Skip to content

Commit d1660c2

Browse files
committed
Merge remote-tracking branch 'origin/sm/trigger-templates' into sm/conflicts-view-in-metadata
2 parents 8406e36 + 828e0f2 commit d1660c2

317 files changed

Lines changed: 6913 additions & 4081 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/agents/doc-maintenance.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
---
2+
name: doc-maintenance
3+
description: AI-powered doc maintenance. Invoked when code changes may have left docs stale. Fixes docs directly; runs in background.
4+
model: fast
5+
---
6+
7+
Fix docs when code/config/scripts change. Run in background; fix directly; report what was fixed.
8+
9+
## Scope
10+
11+
- **In scope**: .claude/skills/, .claude/agents/, .cursor/rules/, docs/, contributing/, packages/\*\*/README.md
12+
- **Excluded**: **/\*.plan.md, **/plan.md
13+
14+
## Responsibilities (priority order)
15+
16+
1. **Code→doc drift**: Recent changes (git diff, session context) that require doc updates
17+
- Command IDs, API changes, new features, removed exports
18+
- package.json scripts/commands, esbuild config, scripts/
19+
- .vscodeignore, .vscode (launch/tasks/extensions), tsconfig, .esbuild-web-extra-settings.json, .github workflows
20+
2. **Broken links** in docs
21+
3. **Duplication** — replace with cross-links
22+
23+
## Workflow
24+
25+
1. `git diff HEAD` (or session context) to identify recent changes
26+
2. Cross-reference docs: docs/, .claude/skills/, .claude/agents/, .cursor/rules/, contributing/, packages/\*\*/README.md
27+
3. Fix issues directly (edit files)
28+
4. Report what was fixed (for transparency)
29+
30+
## Style
31+
32+
- **.claude/, .cursor/rules/, docs/, contributing/**: Apply concise skill (fragments, remove words). See .claude/skills/concise/SKILL.md.
33+
- **packages/\*\*/README.md**: Customer-facing, marketplace. Use full sentences, original tone. Do NOT apply concise.

.claude/agents/playwright-e2e-monitor.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
name: playwright-e2e-monitor
33
description: Monitor and analyze Playwright E2E test results from GitHub Actions. Use when users ask for playwright analysis on github actions or /analyze-e2e
4-
model: composer-1
4+
model: fast
55
---
66

77
Monitor running e2e playwright tests, download artifacts on failure, provide analysis.

.claude/skills/concise/SKILL.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ description: Writing style for AI-consumed docs. Proactively apply when creating
44
disable-model-invocation: false
55
---
66

7+
**Excluded**: packages/\*\*/README.md — customer-facing, marketplace; use full sentences.
8+
79
# Concise
810

911
Save tokens and preserve context window.

.claude/skills/effect-best-practices/SKILL.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
name: effect-best-practices
33
description: Enforces Effect-TS patterns for services, errors, layers, and atoms. Use when writing code with Effect.Service, Schema.TaggedError, Layer composition, or effect-atom React components.
4-
version: 1.1.0
4+
version: 1.2.0
55
---
66

77
# Effect-TS Best Practices
@@ -31,7 +31,7 @@ npx effect-language-service diagnostics --project tsconfig.json
3131
| Error Specificity | `UserNotFoundError`, `SessionExpiredError` | Generic `NotFoundError`, `BadRequestError` |
3232
| Error Handling | `catchTag`/`catchTags`; catch only when needed | `catchAll`; swallowing; catching "just in case" |
3333
| IDs | `Schema.UUID.pipe(Schema.brand("@App/EntityId"))` | Plain `string` for entity IDs |
34-
| Functions | `Effect.fn("Service.method")` | Anonymous generators |
34+
| Functions | `Effect.fn` over `Effect.gen`; `.gen` only for shared pipes | Anonymous generators; `.gen` for business logic |
3535
| Params vs deps | Params = runtime data; dependencies = yield from context | Passing Ref/PubSub/service as params |
3636
| Naming | `FooCommand` for commands, domain names for helpers | `FooEffect` suffix (redundant; TS/Effect.fn already convey type) |
3737
| Logging | `Effect.log` with structured data | `console.log` |
@@ -266,9 +266,11 @@ export type CreateUserInput = Schema.Schema.Type<typeof CreateUserInput>;
266266

267267
See `references/schema-patterns.md` for transforms and advanced patterns.
268268

269-
## Function Pattern with Effect.fn
269+
## Function Pattern: Prefer Effect.fn over Effect.gen
270270

271-
**Always use `Effect.fn`** for service methods. This provides automatic tracing with proper span names. Span name is required; enforced by `local/require-effect-fn-span-name`.
271+
**Prefer `Effect.fn`** for effectful code. Provides automatic tracing with proper span names. Span name required; enforced by `local/require-effect-fn-span-name`.
272+
273+
**Use `Effect.gen` only when** you need a shared effect with common `.pipe` attached so multiple consumers don't each pipe the same things — e.g. provided dependencies, common error handlers, retries. (Less common with Runtimes.) Service definition bodies are a valid use (shared wiring).
272274

273275
```typescript
274276
// CORRECT - Effect.fn with descriptive name
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
name: feature-branch
3+
description: Create feature branches for all work. Use when creating branches, checking out, or pushing. Prevents accidental push to develop.
4+
---
5+
6+
# Feature Branch
7+
8+
All work must be on feature branches. Never commit directly to develop or main.
9+
10+
## Do
11+
12+
```bash
13+
git fetch origin develop
14+
git checkout develop
15+
git pull
16+
git checkout -b feature/W-XXXXX
17+
# ... work, commit ...
18+
git push -u origin feature/W-XXXXX
19+
```
20+
21+
Or, branch from remote without tracking it:
22+
23+
```bash
24+
git fetch origin develop
25+
git checkout -b feature/W-XXXXX origin/develop --no-track
26+
```
27+
28+
## Don't
29+
30+
**Never** `git checkout -b feature/W-XXXXX origin/develop` without `--no-track`.
31+
32+
That sets the new branch to track `origin/develop`. A bare `git push` would then push to develop instead of creating a remote feature branch.
33+
34+
## Summary
35+
36+
- All work on feature branches
37+
- Use `--no-track` when branching from `origin/<base>`, or branch from local `<base>` after pull
38+
- Always push with explicit branch: `git push -u origin feature/W-XXXXX`

.claude/skills/playwright-e2e/SKILL.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,17 @@ Guidelines for writing and iterating on Playwright tests for VS Code extensions.
1515
- `references/local-setup.md` - Scratch org setup (Dreamhouse, minimal, non-tracking)
1616
- `references/iterating-playwright-tests.md` - Iterating on tests ("Things to ignore" for failure analysis)
1717
- `references/analyze-e2e.md` - Analyzing E2E test results from CI
18-
- `references/local-setup.md` - Local scratch org setup for E2E tests
1918

2019
# Use playwright-vscode-ext
2120

2221
Shared code (helpers, locators, configuration) for tests.
2322

23+
**Desktop workspace shapes (pick one per test):**
24+
25+
- **No folder open** — fixture opens a Salesforce project, then call `prepareNoFolderOpenForPaletteTests(page)` (runs `Workspaces: Close Workspace` + workbench wait). Or use `closeWorkspaceToEmptyWindow` if UI is already prepared.
26+
- **Folder open, no `sfdx-project.json`**`createDesktopTest({ emptyWorkspace: true })`; workspace path comes from `createEmptyTestWorkspace()` (also exported from the package).
27+
- **Default org in workspace** — pass `orgAlias: '…'` (e.g. `MINIMAL_ORG_ALIAS` / `DREAMHOUSE_ORG_ALIAS`) so `.sfdx/config.json` gets `target-org`. Omit `orgAlias` or use `undefined` for **no** `config.json` (no org).
28+
2429
## Span files (when debugging traces)
2530

2631
Local only — span export disabled in CI/GHA.

.claude/skills/playwright-e2e/references/iterating-playwright-tests.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,12 @@ Scratch org setup: see `references/local-setup.md`.
1111
1. run `web` locally (use `--retries 0`, follow debugging tips)
1212
2. run `desktop` locally (use `--retries 0`)
1313

14-
**Passing args:** Use `--` to forward params to the underlying command, e.g. `npm run test:web -w <package> -- --retries 0` or `npm run test:desktop -w <package> -- --retries 0`
15-
3. edit github workflows if needed
16-
4. CI (windows, gha) - see `analyze-e2e.md` for monitoring and analyzing results
14+
**Passing args:** Use `--` to forward params to the underlying command, e.g. `npm run test:web -w <package> -- --retries 0` or `npm run test:desktop -w <package> -- --retries 0` 3. edit github workflows if needed 4. CI (windows, gha) - see `analyze-e2e.md` for monitoring and analyzing results
1715

1816
After passing, clean up while keeping tests passing:
1917

2018
1. remove fallbacks, waits, "try another way"
21-
2. align with `coding-playwright-tests.mdc` rules
19+
2. align with `coding-playwright-tests.md` rules
2220
3. consolidate locators, increase DRY/reuse
2321
4. ensure playwright-ext exports are used by other extensions
2422
5. verify compile/lint pass (`@.claude/skills/verification/`)

.claude/skills/playwright-e2e/references/local-setup.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Prereq: authenticated Dev Hub (`sf org login web --set-default-dev-hub` or simil
2424
```bash
2525
mkdir -p /tmp/minimal-project/force-app
2626
echo '{"packageDirectories":[{"path":"force-app","default":true}],"namespace":"","sfdcLoginUrl":"https://login.salesforce.com","sourceApiVersion":"64.0"}' > /tmp/minimal-project/sfdx-project.json
27-
cd /tmp/minimal-project && sf org create scratch -d -w 10 -a minimalTestOrg --wait 30 --json
27+
cd /tmp/minimal-project && sf org create scratch -d -w 10 -a minimalTestOrg --edition developer --json
2828
```
2929

3030
## Non-tracking
@@ -36,7 +36,7 @@ cd /tmp/minimal-project && sf org create scratch -d -w 10 -a minimalTestOrg --wa
3636
```bash
3737
mkdir -p /tmp/non-tracking-project/force-app
3838
echo '{"packageDirectories":[{"path":"force-app","default":true}],"namespace":"","sfdcLoginUrl":"https://login.salesforce.com","sourceApiVersion":"64.0"}' > /tmp/non-tracking-project/sfdx-project.json
39-
cd /tmp/non-tracking-project && sf org create scratch -d -w 10 -a nonTrackingTestOrg --wait 30 --no-track-source --json
39+
cd /tmp/non-tracking-project && sf org create scratch -d -w 10 -a nonTrackingTestOrg --edition developer --no-track-source --json
4040
```
4141

4242
**Note:** Non-tracking test skips on web locally — requires Dev Hub aliased as `hub`. Desktop and CI work.

.claude/skills/pr-draft/SKILL.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Draft PR titles and bodies per salesforcedx-vscode conventions. Requires a Gus w
1616
1. If branch name contains `W-XXXXX`, confirm it exists in GUS, resembles the work done on the branch, and use that
1717
2. Else ask: "Do you have a Gus work item (W-XXXXX) for this PR?"
1818
3. If yes → try to find it using [gus-cli/SKILL.md](../gus-cli/SKILL.md). Confirm with the user that you got it right, or ask them to choose if several could be right.
19-
4. If no → offer to create via Gus. Follow [gus-cli/SKILL.md](../gus-cli/SKILL.md). **Before creating:** show user Subject, Epic, Details, assignee. Ask: "Create this work item?" Do not run `sf data create record` until user says yes.
19+
4. If no → offer to create via Gus. Follow [gus-cli/SKILL.md](../gus-cli/SKILL.md). **Before creating:** show user Subject, Epic, Details, assignee. Ask: "Create this work item?" Do not run `sf data create record` until user says yes. If user declines creation and still wants to proceed with the PR, include `[skip-validate-pr]` in the PR body.
2020
5. Before creating PR: push current branch to remote if it doesn't already exist (`git push -u origin $(git branch --show-current)` or equivalent). Never push to `develop`/`main`
2121
6. After PR created: update work item `Details__c` with PR link. Query current `Details__c`, append `"\nPR: <url>"` (or prepend if empty). **Before updating:** show user the new Details\_\_c. Ask: "Update work item with PR link?" Do not run `sf data update record` until user says yes.
2222
7. After PR created: offer Ready for Review. Ask: "Put WI in Ready for Review? Who should review?" Choices:
@@ -40,9 +40,12 @@ Draft PR titles and bodies per salesforcedx-vscode conventions. Requires a Gus w
4040

4141
## Body format
4242

43-
- Write body content per [concise/SKILL.md](../concise/SKILL.md)
43+
- Base body on branch commits only
44+
- Ignore plans/conversation history (may be stale)
45+
- Write content per [concise/SKILL.md](../concise/SKILL.md)
4446
- Include `@W-XXXXX@` in "What issues does this PR fix or reference?" per [.github/PULL_REQUEST_TEMPLATE.md](../../../.github/PULL_REQUEST_TEMPLATE.md):
45-
- Delete the before/after section if you have nothing to say there
47+
- Delete before/after section if empty
48+
- **User declined WI:** If user explicitly declines WI but wants PR, include `[skip-validate-pr]` in body (e.g. at end)
4649

4750
```
4851
### What issues does this PR fix or reference?

.claude/skills/services-extension-consumption/SKILL.md

Lines changed: 63 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
name: services-extension-consumption
3-
description: Guidelines for consuming salesforcedx-vscode-services extension API. Use when working with extensions that have extensionDependency on salesforcedx-vscode-services, registering commands, using Workspace/Connection/Project/Settings/FS/Channel/Media services, or implementing file/config watchers.
3+
description: Guidelines for consuming salesforcedx-vscode-services extension API. Use when working with extensions that have extensionDependency on salesforcedx-vscode-services, registering commands, using Workspace/Connection/Project/Settings/FS/Channel/Media services, quickpick/quickInput, or implementing file/config watchers.
44
---
55

66
# Consuming salesforcedx-vscode-services
@@ -33,13 +33,13 @@ Shares singleton instances (caches, watchers) across extensions; avoids re-build
3333

3434
Per-extension layers (must build yourself):
3535

36-
| Layer | Why |
37-
|---|---|
38-
| `ChannelServiceLayer(displayName)` | Own output channel |
39-
| `ErrorHandlerService.Default` | Depends on own ChannelService |
40-
| `ExtensionContextServiceLayer(context)` | Own `ExtensionContext` |
41-
| `SdkLayerFor(context)` | Own tracer (extension name/version in resource attributes) |
42-
| `ExtensionProviderServiceLive` | Local singleton |
36+
| Layer | Why |
37+
| --------------------------------------- | ---------------------------------------------------------- |
38+
| `ChannelServiceLayer(displayName)` | Own output channel |
39+
| `ErrorHandlerService.Default` | Depends on own ChannelService |
40+
| `ExtensionContextServiceLayer(context)` | Own `ExtensionContext` |
41+
| `SdkLayerFor(context)` | Own tracer (extension name/version in resource attributes) |
42+
| `ExtensionProviderServiceLive` | Local singleton |
4343

4444
## ExtensionContext Setup
4545

@@ -74,20 +74,32 @@ In `activate`:
7474
export const activate = async (context: vscode.ExtensionContext): Promise<void> => {
7575
const extensionScope = Effect.runSync(getExtensionScope());
7676
setAllServicesLayer(buildAllServicesLayer(context));
77-
await Effect.runPromise(activateEffect(context).pipe(Effect.provide(AllServicesLayer), Scope.extend(extensionScope)));
77+
await getRuntime().runPromise(activateEffect(context).pipe(Scope.extend(extensionScope)));
7878
};
7979
```
8080

81+
## Runtime vs provide
82+
83+
- **Do**: Build `ManagedRuntime.make(AllServicesLayer)` and export `getRuntime()`.
84+
- **Do**: Use `getRuntime().runPromise(effect)` / `runFork(effect)` for ad-hoc execution.
85+
- **Don't**: Use `Effect.provide(AllServicesLayer)` at call sites — use the runtime instead.
86+
- **Exception**: `registerCommandWithLayer(AllServicesLayer)` — keep passing the Layer; it internally uses provide.
87+
8188
## Registering Commands
8289

83-
Use `registerCommandWithLayer` pre-loaded with AllServicesLayer:
90+
Use `registerCommandWithLayer` (for layers) or `registerCommandWithRuntime` (for runtimes):
8491

8592
```typescript
8693
import { myCommandEffect } from './commands/myCommand';
8794

8895
const api = yield * (yield * ExtensionProviderService).getServicesApi;
96+
97+
// Using Layer
8998
const registerCommand = api.services.registerCommandWithLayer(AllServicesLayer);
99+
yield * registerCommand('sf.my.command', myCommandEffect);
90100

101+
// Using Runtime
102+
const registerCommand = api.services.registerCommandWithRuntime(getRuntime());
91103
yield * registerCommand('sf.my.command', myCommandEffect);
92104
```
93105

@@ -96,6 +108,7 @@ Commands auto:
96108
- Register with ExtensionContext subscriptions
97109
- Wrap with error handling
98110
- Trace with observability spans
111+
- Handle Cancellation
99112

100113
## Basic Services
101114

@@ -109,21 +122,29 @@ Accessor pattern: call methods directly, don't assign to variable first.
109122
- [SettingsService](references/settings-service.md) - Settings read/write
110123
- [FsService](references/fs-service.md) - File ops (web-compatible) and uri/path conversion
111124
- [EditorService](references/editor-service.md) - Active editor changes and current URI
125+
- [Prompts](references/prompts.md) - QuickPick, InputBox, and UserCancellationError handling
112126

113127
## Watchers
114128

115129
### File Watching
116130

117-
Watch file changes:
131+
FileWatcherService exposes a PubSub of all workspace file changes (`**/*`). Subscribe and filter:
118132

119133
```typescript
120-
const watcher = yield * api.services.FileWatcherService.watchFiles(pattern, options);
134+
import * as PubSub from 'effect/PubSub';
135+
import * as Stream from 'effect/Stream';
136+
137+
const fileWatcher = yield * api.services.FileWatcherService;
138+
const dequeue = yield * PubSub.subscribe(fileWatcher.pubsub);
121139

122140
yield *
123-
Stream.runForEach(watcher, event =>
124-
Effect.sync(() => {
125-
// Handle file change
126-
})
141+
Stream.fromQueue(dequeue).pipe(
142+
Stream.filter(event => /* match event.uri to your pattern */),
143+
Stream.runForEach(event =>
144+
Effect.sync(() => {
145+
// Handle event: { type: 'create'|'change'|'delete', uri }
146+
})
147+
)
127148
);
128149
```
129150

@@ -160,29 +181,29 @@ yield *
160181

161182
### Target Org Changes
162183

163-
Watch org changes via `TargetOrgRef`:
184+
Watch org changes via `TargetOrgRef` (SubscriptionRef):
164185

165186
```typescript
166-
const targetOrgRef = yield * api.services.TargetOrgRef();
187+
const ref = yield * api.services.TargetOrgRef();
167188
yield *
168-
Effect.forkDaemon(
169-
targetOrgRef.changes.pipe(
170-
Stream.map(org => org.orgId),
171-
Stream.changes,
172-
Stream.tap(orgId => {
173-
// Handle org change
174-
}),
175-
Stream.runForEach(() => {
176-
// Refresh UI, invalidate caches, etc.
177-
})
178-
)
189+
ref.changes.pipe(
190+
Stream.map(org => org.orgId),
191+
Stream.changes,
192+
Stream.tap(orgId => {
193+
// Handle org change
194+
}),
195+
Stream.runForEach(() => {
196+
// Refresh UI, invalidate caches, etc.
197+
})
179198
);
180199
```
181200

182201
## Complete Example Pattern
183202

184203
```typescript
185204
// extensionProvider.ts
205+
import * as ManagedRuntime from 'effect/ManagedRuntime';
206+
186207
export const buildAllServicesLayer = (context: ExtensionContext) =>
187208
Layer.unwrapEffect(
188209
Effect.gen(function* () {
@@ -204,6 +225,18 @@ export const buildAllServicesLayer = (context: ExtensionContext) =>
204225
}).pipe(Effect.provide(ExtensionProviderServiceLive))
205226
);
206227

228+
export let AllServicesLayer: ReturnType<typeof buildAllServicesLayer>;
229+
export const setAllServicesLayer = (layer: ReturnType<typeof buildAllServicesLayer>) => {
230+
AllServicesLayer = layer;
231+
};
232+
233+
const createRuntime = () => ManagedRuntime.make(AllServicesLayer);
234+
let _runtime: ReturnType<typeof createRuntime> | undefined;
235+
export const getRuntime = () => {
236+
_runtime ??= createRuntime();
237+
return _runtime;
238+
};
239+
207240
// index.ts
208241
import { myCommandEffect } from './commands/myCommand';
209242

@@ -228,3 +261,4 @@ export const activateEffect = Effect.fn(`activation:${EXTENSION_NAME}`)(function
228261
- Pass `context` to `SdkLayerFor` (extracts name/version from ExtensionContext)
229262
- `Effect.forkIn(..., yield* getExtensionScope())` for watcher cleanup on deactivation
230263
- `registerCommandWithLayer` for all commands (tracing + error handling)
264+
- Use `getRuntime().runPromise` / `runFork` instead of `Effect.provide(AllServicesLayer)` for execution

0 commit comments

Comments
 (0)