Skip to content

Commit e3faf1a

Browse files
committed
Merge branch 'daphne/W-22451438-notifications-spike' into daphne/W-22671885-soql-visualforce-notifications
2 parents 8612899 + 8a1f76b commit e3faf1a

31 files changed

Lines changed: 2261 additions & 631 deletions

File tree

.claude/agents/effect-advocate.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ Per finding: file:line, smell, Effect replacement, citation. Severity: `must` (a
3030
- **`if/else` or `switch` on tagged union**`Match.type<T>().pipe(Match.tag(...), Match.exhaustive)` or `Effect.match` / `Option.match`.
3131
- **Hand-rolled retry** (`for`/`while`/recursion + `setTimeout`) → `Effect.retry` + `Schedule.exponential` / `Schedule.recurs` / `Schedule.intersect`.
3232
- **Hand-rolled timeouts** (`Promise.race` + `setTimeout`) → `Effect.timeout` / `Effect.timeoutFail`.
33+
- **Numeric time values** (`TIMEOUT_MS = 30_000`, timeout params as `number`) → `Duration.seconds(30)` / `Duration.millis(30_000)` for constants; `Duration.DurationInput` for param types. Convert with `Duration.toMillis`.
3334
- **AbortController inside Effect**`Effect.interruptible` / fiber interruption / `Effect.race`.
3435
- **Cache** (Map + manual TTL) → `Cache.make` / `Effect.cached` / `Effect.cachedWithTTL`.
3536
- **In-flight dedup** (Map of pending Promises) → `Effect.cachedFunction` / `RequestResolver`.

.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: fast
4+
model: haiku
55
---
66

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

.claude/plans/W-23069757.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# W-23069757 — Fix invalid model `fast` in playwright-e2e-monitor
2+
3+
## Context
4+
5+
- `.claude/agents/playwright-e2e-monitor.md:4``model: fast`
6+
- API rejects: `400 Invalid model name passed in model=fast`
7+
- Agent dies, 0 tool uses
8+
- Valid ids: opus/sonnet/haiku (or omit line → inherit session model)
9+
- Peer agents: gha-rerun.md, doc-maintenance.md = `haiku`; others = `sonnet`
10+
- Task = mechanical CI watch/download → `haiku` (matches gha-rerun)
11+
12+
## Phases
13+
14+
### Phase 1 — Set valid model
15+
- Edit `.claude/agents/playwright-e2e-monitor.md` line 4: `model: fast``model: haiku`
16+
- Files: `.claude/agents/playwright-e2e-monitor.md`
17+
- Commit: `fix(agents): use valid model id in playwright-e2e-monitor frontmatter - W-23069757`
18+
19+
## Skills to apply
20+
- typescript
21+
- concise (md edit)
22+
23+
## Verification
24+
- `grep -n "^model:" .claude/agents/playwright-e2e-monitor.md``haiku`
25+
- no other agent frontmatter uses `model: fast` (grep clean)
26+
- not e2e-covered: agent frontmatter untested; verify via grep

.claude/plans/W-23070551.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# W-23070551 — Improve bug report template + project info (app name)
2+
3+
## Context
4+
5+
- Bug template `.github/ISSUE_TEMPLATE/Bug_report.md` has 4 manual version fields users rarely fill correctly. `SFDX: Generate Project Info` already emits all of them. Replace fields w/ prompt to run command + paste output.
6+
- `projectInfo.ts` `gatherEnvironment` lacks editor app name (`vscode.env.appName` — distinguishes VS Code / Cursor / Code - Insiders). Add to `EnvInfo` + Environment table.
7+
8+
## Phases
9+
10+
### Phase 1 — Bug template
11+
12+
- File: `.github/ISSUE_TEMPLATE/Bug_report.md`
13+
- Remove lines 39-45: Salesforce Extension Version, CLI Version, OS, VS Code version.
14+
- Replace w/ prompt: run `SFDX: Generate Project Info`, paste output (`.sf/project-info.md`).
15+
- Keep "Most recent version of the extensions where this was working" field.
16+
- Commit: `docs: replace manual version fields w/ project-info prompt in bug template - W-23070551`
17+
18+
### Phase 2 — App name in project info
19+
20+
- File: `packages/salesforcedx-vscode-metadata/src/commands/projectInfo.ts`
21+
- `EnvInfo` type (line 37-44): add `appName: string`.
22+
- `gatherEnvironment` return (line 161-168): add `appName: vscode.env.appName`.
23+
- `renderMarkdown` envSection (line 233-246): add `['Editor', envInfo.appName]` row before `['VS Code', ...]`.
24+
- Export `renderMarkdown` (currently only `projectInfoCommand` exported at line 303) so Phase 3 can assert rendered output as a pure unit. Keep `gatherEnvironment` internal; the test passes a hand-built `EnvInfo` to `renderMarkdown`.
25+
26+
### Phase 3 — Mock + unit coverage (REQUIRED, addresses adversary finding)
27+
28+
- root cause: mock omits appName → resolves undefined → renders `| Editor | undefined |`
29+
- e2e only checks `## Environment` heading, not row values → regression ships green without Phase 3
30+
31+
- File: `config/__mocks__/vscode.js`
32+
- In the `env` object (line 117-119), add `appName: 'Visual Studio Code'` alongside `machineId`.
33+
- File: `packages/salesforcedx-vscode-metadata/test/jest/commands/projectInfo.test.ts` (new)
34+
- Import the now-exported `renderMarkdown`.
35+
- Build an `EnvInfo` whose `appName` reads from the mocked `vscode.env.appName` (import the mocked `vscode`), call `renderMarkdown`, and assert the output contains `| Editor | Visual Studio Code |`.
36+
- Add a guard assertion that the rendered output does NOT contain `| Editor | undefined |` — this is what fails if the mock stub is ever removed, catching the gap at CI time.
37+
- Follow existing jest test header/structure (`refreshSObjects.test.ts`).
38+
- Commit (squash w/ Phase 2): `feat(metadata): add editor app name to project info - W-23070551`
39+
40+
## Skills
41+
42+
- concise — md/plan style
43+
- typescript — TS edits
44+
- effect-best-practices — `gatherEnvironment` is an Effect.fn
45+
- verification
46+
47+
## Verification
48+
49+
- `## Environment` section render — e2e-covered (`projectInfo.headless.spec.ts:76`).
50+
- `Editor` row value — jest-covered (Phase 3): asserts `| Editor | Visual Studio Code |` and rejects `| Editor | undefined |`. Run: `npx jest projectInfo` in `packages/salesforcedx-vscode-metadata`.
51+
- `tsc` / build clean: `npx wireit` build for `salesforcedx-vscode-metadata`.
52+
- Lint: `npm run lint` on changed pkg.
53+
- Bug template renders correctly on GitHub (visual, manual).

.claude/plans/W-23072534.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# W-23072534 — TerminalService.simpleExec object param + Duration timeout
2+
3+
## Context
4+
- `simpleExec(command, parse?, timeoutMs?)` → positional. Replace w/ single options object.
5+
- New sig: `simpleExec({ command, parse?, timeout? })`; `timeout: Duration.DurationInput`, default `Duration.millis(30_000)`; internally `Duration.toMillis`.
6+
- Callers: orgDelete.ts (timeout 120s), projectInfo.ts (command-only x2).
7+
- Test: orgDelete.test.ts assertions on positional args (lines 58, 67, 75-79).
8+
- Duration import convention: `import * as Duration from 'effect/Duration'`.
9+
10+
## External-consumers (blast radius)
11+
`TerminalService` is on the public `SalesforceVSCodeServicesApi` surface (index.ts:142, `export type` at index.ts:479). Changing `simpleExec`'s signature is a breaking API change for external callers. Checked:
12+
- monorepo grep `simpleExec`: only callers are orgDelete.ts, projectInfo.ts, orgDelete.test.ts (all in-repo).
13+
- `gh` search `simpleExec org:forcedotcom` + `org:salesforcecli`: only this monorepo + its mirror repos (salesforcedx-vscode-ci-testing, vibes-poc) + `code-analyzer-core` `simpleExecutor` (unrelated class property, not TerminalService).
14+
- No external consumer calls `TerminalService.simpleExec`.
15+
16+
**Decision:** breaking change is safe — no external consumer. No compatibility overload needed. Re-run the external-consumers check at build time (`gh` search may have new hits) before committing; if a new consumer appears, add an object/positional overload or document the break.
17+
18+
## Phases
19+
20+
### Phase 1 — source signature + non-test callers
21+
Change source only; do NOT touch the test yet (so tsc/jest break loudly on the stale positional mock assertions, proving the test catches the new shape).
22+
23+
**Files:**
24+
- `packages/salesforcedx-vscode-services/src/terminal/terminalService.ts`
25+
- sig → `simpleExec: ({ command, parse = s => s, timeout = Duration.millis(30_000) }: { command: string; parse?: (stdout: string) => string; timeout?: Duration.DurationInput })`
26+
- `exec(command, { timeout: Duration.toMillis(timeout) })`
27+
- add `import * as Duration from 'effect/Duration'`; update jsdoc (`timeout` not `timeoutMs`)
28+
- `packages/salesforcedx-vscode-org/src/commands/orgDelete.ts`
29+
- `DELETE_TIMEOUT_MS = 120_000``DELETE_TIMEOUT = Duration.seconds(120)`; update comment (line 140)
30+
- call (line 173) → `simpleExec({ command: \`sf ${deleteSubcommand}${targetOrgFlag} --no-prompt\`, parse: identity, timeout: DELETE_TIMEOUT })`
31+
- add Duration import
32+
- `packages/salesforcedx-vscode-metadata/src/commands/projectInfo.ts`
33+
- `simpleExec({ command: 'sf --version' })`, `simpleExec({ command: 'java --version' })` (lines 149-150)
34+
35+
**Gate:** `tsc` org+services+metadata compile must PASS (source consistent). Run jest orgDelete.test.ts and confirm it FAILS on the stale positional `toHaveBeenCalledWith` — this proves the assertions are load-bearing and not false-green. Note: positional mock-arg assertions are JS-level, not type-checked, so tsc alone won't flag them; the jest run is the guard.
36+
37+
### Phase 2 — test assertions to object shape
38+
**Files:**
39+
- `packages/salesforcedx-vscode-org/test/jest/commands/orgDelete.test.ts`
40+
- 3 `toHaveBeenCalledWith` (lines 58, 67, 75-79) → single object arg: `{ command: '...', parse: expect.any(Function), timeout: Duration.seconds(120) }`
41+
- add `import * as Duration from 'effect/Duration'`
42+
- `Duration.seconds(120)` is a structural value; jest deep-equality matches it. Verify the assertion fails if `timeout` is omitted/wrong (sanity: the Phase-1 red proves lock-step).
43+
44+
**Gate:** jest orgDelete.test.ts now PASSES against new shape.
45+
46+
**Commit (after both phases):** `refactor(services): simpleExec object param w/ Duration timeout - W-23072534`
47+
48+
## Skills
49+
- external-consumers (public API surface — breaking change blast radius)
50+
- effect-best-practices (Duration usage)
51+
- services-extension-consumption (API surface change consumed by org/metadata)
52+
- typescript
53+
- playwright-e2e (projectInfo spec exercises the changed path)
54+
- concise
55+
- verification
56+
57+
## Verification
58+
- `simpleExec` grep: no remaining positional callers
59+
- compile: services, org, metadata packages
60+
- jest: orgDelete.test.ts (object-shape assertions; `Duration.seconds(120)` deep-equality)
61+
- lint changed files
62+
- re-run external-consumers `gh` search before commit (no new external caller)
63+
64+
### E2E
65+
Two existing specs touch the changed packages:
66+
- `packages/salesforcedx-vscode-org/test/playwright/specs/orgDeleteCommandVisibility.desktop.spec.ts` — checks command *visibility* in the palette only; does NOT invoke delete, so does NOT exercise `simpleExec`. The exec call path is jest-covered (orgDelete.test.ts). Not required for this change, but run to confirm no regression in org desktop bundle.
67+
- `packages/salesforcedx-vscode-metadata/test/playwright/specs/projectInfo.headless.spec.ts` — runs "Generate Project Info", which calls `projectInfo.ts``simpleExec({ command: 'sf --version' })` / `simpleExec({ command: 'java --version' })`; the `## Environment` section assertion (spec line 76) depends on those exec results. **DOES exercise the new object-param call path. Required.**
68+
69+
Run before PR (from repo root, no `cd`):
70+
- `npm run test:desktop -w salesforcedx-vscode-metadata -- --retries 0` (projectInfo.headless is desktop-gated via `isDesktop()`)
71+
- `npm run test:desktop -w salesforcedx-vscode-org -- --retries 0` (regression check on visibility spec)
72+
73+
If projectInfo spec cannot run locally (no org/sf/java), document the blocker; the jest+compile gates plus the spec's `## Environment` dependency on simpleExec remain the evidence the path is wired correctly.

.claude/plans/W-23073733.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# W-23073733 — e2e: fix LWC rename input races + folder refresh lag
2+
3+
## Context
4+
5+
- Test: `packages/salesforcedx-vscode-lwc/test/playwright/specs/lwcRename.headless.spec.ts`
6+
- CI run 27492599426 flakes, 2 modes:
7+
- Ubuntu: `ControlOrMeta+a` + `keyboard.type()` truncates name (`enameLwcFinal...`, `meLwcFinal...`) — partial selection before focus settles on quick-input.
8+
- macOS: folder treeitem not visible <10s though child files renamed (debounced watcher). Both visibility asserts (`:79` newFolder, `:102` finalFolder) use identical `toBeVisible({ timeout: 10_000 })` and flake the same way.
9+
- `activeQuickInputTextField` exported from `@salesforce/playwright-vscode-ext` (`src/index.ts:36`); returns `activeQuickInputWidget(page).locator('input.input')`. `.fill()` sets value atomically, no keystroke race.
10+
11+
## Phases
12+
13+
### Phase 1 — fix input races + folder refresh lag (1 commit)
14+
15+
File: `packages/salesforcedx-vscode-lwc/test/playwright/specs/lwcRename.headless.spec.ts`
16+
17+
- Explorer rename: replace `:68``:69` with `await activeQuickInputTextField(page).fill(newName, { force: true })`; keep `:70` (Enter).
18+
- Editor rename: replace `:91``:92` with `await activeQuickInputTextField(page).fill(finalName, { force: true })`; keep `:93` (Enter).
19+
- `.fill(value, { force: true })` is the established package idiom (`commands.ts:101,202`); sets value atomically, eliminating the select-all/type focus race.
20+
- Add `activeQuickInputTextField` to the existing import from `@salesforce/playwright-vscode-ext`.
21+
- `:79` newFolder visibility: wrap in `await expect(async () => { await expect(newFolder).toBeVisible(); }).toPass({ timeout: 20_000 })`.
22+
- `:102` finalFolder visibility: same `toPass({ timeout: 20_000 })` wrap — identical debounced-watcher flake recurs on the post-editor-rename assertion.
23+
24+
Commit: `test(lwc): stabilize lwcRename input fill + folder refresh - W-23073733`
25+
26+
## Skills
27+
28+
- playwright-e2e — locator/quick-input conventions
29+
- typescript — type-correct edits to spec file
30+
- concise — plan + md style
31+
- analyze-e2e / gha-rerun — confirm green CI post-push
32+
33+
## Verification
34+
35+
- Local headless (from repo root): `WIREIT_CACHE=none npm run test:web -w salesforcedx-vscode-lwc -- --retries 0 lwcRename.headless.spec.ts` (confirms `.fill()` resolves in web workbench DOM).
36+
- Local: `npx eslint` on changed file (lint clean).
37+
- CI: lwcRename passes no-retry on ubuntu + macOS (DoD) — via gha-rerun/analyze-e2e after push.

.claude/plans/W-23073734.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# W-23073734 — e2e: fix Apex generate-class template picker Enter race (Windows)
2+
3+
## Context
4+
5+
- Test: `packages/salesforcedx-vscode-apex-log/test/playwright/specs/apexGenerateClassMultiPackageDirs.headless.spec.ts`
6+
- Windows CI only. `:57` `waitForQuickInputFirstOption` waits `attached` only; `:58` `keyboard.press('Enter')` fires ~45ms after options load, before list row gets keyboard focus → swallowed, picker stays open, class-name InputBox never appears.
7+
- Evidence: run 27492599426 windows-latest. t=149340 options attached, t=149385 Enter, t=159681 picker still open.
8+
- Fix: swap `:57-58` for `selectFirstQuickInputOption(page)` — DOM `evaluate()` click on first row (`packages/playwright-vscode-ext/src/utils/helpers.ts:151-175`), bypasses keyboard-focus race.
9+
- Helper already exported (`index.ts:14`); siblings `logRetrieval`, `traceFlagsCrud` already use it.
10+
11+
## Phases
12+
13+
### Phase 1 — swap Enter for selectFirstQuickInputOption
14+
15+
- Edit `apexGenerateClassMultiPackageDirs.headless.spec.ts`:
16+
- import: KEEP `waitForQuickInputFirstOption` (still used at `:72`), ADD `selectFirstQuickInputOption` to the same import block. Both come from `@salesforce/playwright-vscode-ext` (`index.ts:13-14`).
17+
- `:57-58` (template-select step body): replace `waitForQuickInputFirstOption(page)` + `keyboard.press('Enter')` with `selectFirstQuickInputOption(page)`.
18+
- keep `saveScreenshot(page, 'step.template-selected.png')`.
19+
- Why `:72` is left as-is: that call has NO `keyboard.press('Enter')` after it — it only waits for the directory picker to render, then the step asserts on rows (`:78-86`) and presses `Escape`. No commit-via-Enter, so no attached-only race. Do not touch it.
20+
- `selectFirstQuickInputOption` internally calls `waitForQuickInputFirstOption` then does a DOM `evaluate()` click on the first row (`helpers.ts:151-180`), bypassing the keyboard-focus race. Adversarial insurance: it accepts an optional `confirmCommitted` callback that, if the click doesn't land, presses Enter as a fallback. The class-name InputBox step (`:62-65`) is the natural commit signal, but the helper's own post-click verification is sufficient here; call it without options (matching `logRetrieval` / `traceFlagsCrud` siblings).
21+
- Commit: `test(apex-log): fix template picker Enter race on Windows - W-23073734`
22+
23+
## Skills to apply
24+
25+
- playwright-e2e
26+
- concise
27+
- typescript
28+
29+
## Verification
30+
31+
- e2e-covered: picker commit + class-name InputBox appearing (`:62-65`) — the modified spec asserts this. Spec is desktop-only (`:32` skips unless `VSCODE_DESKTOP === '1'`), runs via the `test:desktop` config; the regression repros on windows-latest. Done = passes w/o retries.
32+
- local (required before PR): run the spec by exact file path (immune to title changes), strip inherited VS Code host env so Electron launches:
33+
```
34+
env -u ELECTRON_RUN_AS_NODE -u VSCODE_PID -u VSCODE_CWD -u VSCODE_IPC_HOOK \
35+
WIREIT_CACHE=none npm run test:desktop -w packages/salesforcedx-vscode-apex-log -- \
36+
--retries 0 test/playwright/specs/apexGenerateClassMultiPackageDirs.headless.spec.ts
37+
```
38+
(drop the `env -u …` prefix if not running from inside a VS Code agent shell). Run in background (>30s); check output later. Requires no scratch org (no-org fixture).
39+
- local: lint the spec file — verifies no unused/stale imports after the edit (both helpers must remain referenced).

.claude/plans/W-23076514.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# W-23076514 — Upgrade @rollup/plugin-terser (CVE-2026-34043)
2+
3+
## Context
4+
5+
- Dependabot alert 331: `serialize-javascript@6.0.2` DoS (CVE-2026-34043)
6+
- Path: `salesforcedx-vscode-soql``@rollup/plugin-terser@0.4.4``serialize-javascript@6.0.2`
7+
- Fix: bump `@rollup/plugin-terser` `^0.4.0``^1.0.0`
8+
- v1.0.0 pulls `serialize-javascript@^7.0.3` (CVE fixed in 7.x)
9+
- Compat verified:
10+
- v1 peer `rollup ^4.0.0` matches package `rollup ^4.0.0`
11+
- v1 engines `node>=20`; repo `node>=22.15.1` OK
12+
- usage unchanged: `rollup.config.mjs:16,139``terser({ format:{comments:false}, maxWorkers:1 })`
13+
- devDep only
14+
15+
## Phases
16+
17+
### Phase 1 — bump + relock
18+
- `packages/salesforcedx-vscode-soql/package.json:63` `^0.4.0``^1.0.0`
19+
- root `npm install` to relock
20+
- confirm lockfile drops `serialize-javascript@6.x` on this path (now 3 refs)
21+
- commit: `chore(soql): upgrade @rollup/plugin-terser to ^1.0.0 to fix CVE-2026-34043 - W-23076514`
22+
23+
## Skills to apply
24+
25+
- packageJson — devDep rules
26+
- wireit — build scripts (no change expected)
27+
- typescript
28+
29+
## Verification
30+
31+
- `npm ls serialize-javascript` → no 6.x on soql path
32+
- `npm run build:soql-builder-ui` (rollup/terser) succeeds → v1 API compat
33+
- `npm run vscode:bundle` (soql) succeeds
34+
- e2e: soql builder UI via `test:web`/`test:desktop` Playwright

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ npx effect-language-service diagnostics --project tsconfig.json
4040
| Naming | `FooCommand` for commands, domain names for helpers | `FooEffect` suffix (redundant; TS/Effect.fn already convey type) |
4141
| Logging | `Effect.log` with structured data | `console.log` |
4242
| Config | `Config.*` with validation | `process.env` directly (except build-time vars like `ESBUILD_*`) |
43+
| Time values | `Duration.seconds(30)`, `Duration.millis(5000)`; params as `Duration.DurationInput` | Numeric milliseconds as `number` params or `TIMEOUT_MS = 30_000` constants |
4344
| Options | `Option.match` with both cases | `Option.getOrThrow` |
4445
| Nullability | `Option<T>` in domain types | `null`/`undefined` |
4546
| Atoms | `Atom.make` outside components | Creating atoms inside render |

0 commit comments

Comments
 (0)