Skip to content

Commit cefc043

Browse files
committed
Merge remote-tracking branch 'origin/develop' into wt-7565
2 parents 62d543a + b2b23d7 commit cefc043

37 files changed

Lines changed: 1467 additions & 168 deletions

File tree

.claude/plans/W-23094925.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# W-23094925 — enable unicorn/prefer-promise-with-resolvers
2+
3+
## Context
4+
- enable `unicorn/prefer-promise-with-resolvers` (error) in `eslint.config.mjs`
5+
- rule: prefer `Promise.withResolvers()` over extracting `resolve`/`reject` from `new Promise()` executor
6+
- depends: W-23094922 (must be merged first)
7+
- 2 violations across repo (verified by adding rule + lint run); rule meta `fixable: 'code'` but autofix declines both (executor has extra statements), so manual rewrite
8+
- prereq: build `packages/eslint-local-rules` (`npm run compile` there) before lint runs, else config import fails
9+
10+
## Phases
11+
12+
### Phase 1 — fix violations
13+
- `streamingClient.ts:137-191` `subscribe()`: replace `let subscribeAccept/subscribeReject` + `new Promise<void>(...)` (lines 138-143) with `const { promise: returnPromise, resolve: subscribeAccept, reject: subscribeReject } = Promise.withResolvers<void>();`. drop executor body. resolver usages (148,164,171) + `return returnPromise` (190) unchanged
14+
- `determineReporters.test.ts:159-165`: replace `let resolveInit` + `new Promise<void>(res => { resolveInit = res; })` with `const { promise, resolve: resolveInit } = Promise.withResolvers<void>();` returned from mock impl; `resolveInit()` at 169
15+
- files:
16+
- `packages/salesforcedx-apex-debugger/src/core/streamingClient.ts`
17+
- `packages/salesforcedx-utils-vscode/test/jest/telemetry/reporters/determineReporters.test.ts`
18+
- commit: `refactor: use Promise.withResolvers - W-23094925`
19+
20+
### Phase 2 — enable rule
21+
- add `'unicorn/prefer-promise-with-resolvers': 'error'` to unicorn block in `eslint.config.mjs` (alpha order, after `prefer-optional-catch-binding`)
22+
- files: `eslint.config.mjs`
23+
- commit: `build: enable unicorn/prefer-promise-with-resolvers - W-23094925`
24+
25+
## Skills
26+
- typescript
27+
- verification
28+
29+
## Verification
30+
- `npm run compile` in `packages/eslint-local-rules` (prereq for lint)
31+
- `npx eslint packages` — 0 `prefer-promise-with-resolvers` errors
32+
- typecheck/build `salesforcedx-apex-debugger``returnPromise` typed `Promise<void>`
33+
- jest `determineReporters.test.ts` "in-progress initialization" test passes (concurrent-init behavior)
34+
- streamingClient `subscribe()`: no direct unit test coverage (test file at `packages/salesforcedx-apex-debugger/test/unit/core/streamingClient.test.ts` only covers setReplayId/getReplayId + headers; subscribe() relies on integration/manual testing). run `npm test -w @salesforce/salesforcedx-apex-debugger` (package exposes `test`, not `test:unit`) — passes. refactor is mechanical/semantically identical; typecheck confirms `returnPromise` typed `Promise<void>`

.claude/plans/W-23094927.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# W-23094927 — enable unicorn/prefer-while-loop-condition
2+
3+
## Context
4+
- Enable `unicorn/prefer-while-loop-condition` (`error`) in `eslint.config.mjs`.
5+
- Rule: prefer condition in `while` over infinite loop + immediate `break`.
6+
- Independent of W-23094925 (PR #7556 DRAFT); branch from develop.
7+
- Unicorn v68 (`node_modules/eslint-plugin-unicorn`); rule fixable: `code`.
8+
- Verified zero violations: only `while(true)`/`for(;;)` matches sit in already-ignored paths:
9+
- `salesforcedx-visualforce-markup-language-server/src/**` (eslint.config.mjs:47)
10+
- `salesforcedx-aura-language-server/src/tern/**` (:48)
11+
- `salesforcedx-vscode-lightning/src/resources/**` (:51)
12+
- Pure config flip, no source edits.
13+
14+
## Phases
15+
16+
### Phase 1 — enable rule
17+
- `eslint.config.mjs`: add `'unicorn/prefer-while-loop-condition': 'error'` in unicorn block (after :219 `prefer-simple-condition-first`).
18+
- Files: `eslint.config.mjs`
19+
- Commit: `chore(eslint): enable unicorn/prefer-while-loop-condition - W-23094927`
20+
21+
## Skills
22+
- concise (plan/md)
23+
- packageJson (n/a — no manifest change)
24+
- typescript
25+
- verification
26+
27+
## Verification
28+
- `npx eslint --rule '{"unicorn/prefer-while-loop-condition":"error"}' "packages/**/*.{ts,js}"` → 0 violations (confirmed pre-write).
29+
- `npm run lint` clean.
30+
- Not e2e-covered (lint-config-only change).

.claude/plans/W-23094932.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# W-23094932 — enable unicorn/prefer-single-replace
2+
3+
## Context
4+
5+
- Rule: `unicorn/prefer-single-replace` — chains same-replacement single-char replaces into `replaceAll(/[..]/g, ...)`.
6+
- unicorn v68 installed; rule file `node_modules/eslint-plugin-unicorn/rules/prefer-single-replace.js` exists.
7+
- Config: `eslint.config.mjs` line ~214 `'unicorn/prefer-single-call'`; insert new rule alphabetically (before `prefer-string-replace-all`).
8+
- Trigger criteria (verified in rule src): chained `.replaceAll('x',R)` (string, 1 char) or `.replace(/x/g,R)` (single literal char, only g/m/s flags); ALL links share identical string-literal replacement `R`; `R` must not include any searched char; no `$\`` / `$'`.
9+
- Pattern matches prior WIs (W-23094920/891/898): single config line via `chore(eslint): enable ...` commit.
10+
- Dependency W-23094931: only a plan commit on develop, not merged. Proceeding per task instruction.
11+
12+
## Violations
13+
14+
- Audited via temp rule injection + targeted eslint + grep.
15+
- 17 chained-`.replace` sites in linted src; none qualify:
16+
- `.ts` candidates: multi-char strings, non-`g` regex, or differing replacement values.
17+
- 3 chained `.replaceAll`: `contextMenu.ts` (differing R), `traceFlagJsonSync.ts` (`\W+` multi-char), `newlineUtils.ts` (`\r\n` multi-char) — none trigger.
18+
- resource `.js` (aura/visualforce) ignored by eslint config (verified: "File ignored").
19+
20+
## Phases
21+
22+
### Phase 1 — enable rule
23+
24+
- `eslint.config.mjs`: add `'unicorn/prefer-single-replace': 'error',` after `prefer-single-call`.
25+
- No source refactors (0 violations).
26+
- Commit: `chore(eslint): enable unicorn/prefer-single-replace - W-23094932`
27+
28+
## Skills
29+
30+
- packageJson — n/a
31+
- typescript — eslint config
32+
- verification
33+
34+
## Verification
35+
36+
- `npm run lint` (or per-pkg lint) clean — 0 new errors.
37+
- Build local rules first if `packages/eslint-local-rules/out/index.js` missing (config import fails otherwise).
38+
- Not e2e-covered; lint is the gate.

.claude/plans/W-23141742.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# W-23141742 — Sort replay debugger variables alphabetically
2+
3+
## Context
4+
- Variables panel = log-parse insertion order (random to user)
5+
- Want: alphabetical, case-insensitive, natural numeric (item2 < item10)
6+
- Choke point: `getAllVariables()``packages/salesforcedx-apex-replay-debugger/src/adapter/variableContainer.ts:34`
7+
- covers top-level scope vars + nested object children
8+
- Scopes (Local/Static/Global) stay fixed order — not touched (`apexReplayDebug.ts:287` only calls per-scope `getAllVariables`)
9+
- Ref discussion: github.com/forcedotcom/salesforcedx-vscode/discussions/5457 (PR must link)
10+
- `toSorted` already common in repo; lint `unicorn/no-array-sort` enforced (eslint.config.mjs:172)
11+
12+
## Phases
13+
14+
### Phase 1 — sort + unit test
15+
- edit `getAllVariables()` (variableContainer.ts:34): `.toSorted((a, b) => a.name.localeCompare(b.name, undefined, { sensitivity: 'base', numeric: true }))` on mapped `ApexVariable[]`
16+
- non-mutational; satisfies no-array-sort + no-immediate-mutation
17+
- add unit test: container w/ out-of-order var names → assert sorted output
18+
- case-insensitivity (Zebra/apple) + numeric (item2 < item10)
19+
- file: `packages/salesforcedx-apex-replay-debugger/test/unit/adapter/` (new or extend existing variableContainer coverage)
20+
21+
### Phase 2 — update integration gold files (REQUIRED, not optional)
22+
- Why: integration suite (test/integration/adapter.test.ts) does exact string compare vs gold; gold encodes insertion order → sort breaks it.
23+
- Affected golds (both contain variable blocks in insertion order today):
24+
- `test/integration/config/logs/recursive.gold` — first var block lines 28-89: `this, myClass, mySimpleList, myComplexList, myNestedList, mySimpleMap, myComplexMap, mySimpleSet, myComplexSet` (NOT alphabetical)
25+
- `test/integration/config/logs/statics.gold` — verify + update each variable block
26+
- Approach: run integration suite, capture new sorted output as gold. Verify each block is alphabetical (e.g. recursive block 1 → `myClass, myComplexList, …, this`).
27+
- commit (single, Phase 1+2 together so tree stays green): `feat(apex-replay-debugger): sort variables panel alphabetically - W-23141742`
28+
29+
## Skills
30+
- typescript
31+
- concise
32+
- pr-draft (link discussion 5457)
33+
- verification
34+
35+
## Verification
36+
- `npm test` in salesforcedx-apex-replay-debugger green
37+
- lint clean (no-array-sort / no-immediate-mutation)
38+
- manually inspect regenerated recursive.gold + statics.gold variable blocks: each is alphabetical/numeric ordered (the assertion now encodes the sort contract)
39+
- scope (Local/Static/Global) ordering unchanged — only within-scope variable order changes
40+
- no dedicated e2e on branch; integration gold suite is the behavioral coverage

.claude/plans/W-23150428.md

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# W-23150428 — Include GitHub discussion/issue URLs from WI Details\_\_c in PR body
2+
3+
## Context
4+
5+
- SF strips external hrefs in rich-text `Details__c``<a href="">discussions/5867</a>` loses URL
6+
- Observed: W-23145031 / PR #7560`discussions/5867` link text, empty href
7+
- PRs from auto-build-wi never reference originating discussion/issue
8+
- Files:
9+
- `.claude/workflows/auto-build-wi.js``draftPrPrompt` (L893-932), helpers near `extractPrUrl`/`stripHtml` (L282-329), `chosen.details` available (L351 build, L827 already interpolated into `planPrompt`)
10+
- `.claude/skills/pr-draft/SKILL.md``## GitHub issues & discussions` (L52-61)
11+
- `.claude/skills/gus-cli/SKILL.md``Details__c formatting` (L99-105)
12+
- Workflow file = script, no exports/unit tests → verify via node REPL
13+
14+
## Mechanism (load-bearing — addresses adversary findings)
15+
16+
- `draftPrPrompt(chosen, identity, fixerResult)` = plain template string handed to `agent()`. No function calling — agent cannot call `extractDiscussionUrls` directly. Mechanism: run `extractDiscussionUrls(chosen.details)` in JS scope before prompt built, then string-interpolate output into template (same pattern as `chosen.details` at L827).
17+
- Insertion: `const reconstructedUrls = extractDiscussionUrls(chosen.details)` at top of `draftPrPrompt` body (after `pathsFor` destructure, L894). Interpolate joined list into step-4 `## Summary`/reference area — exact text in Phase 1. Empty → interpolate nothing (no placeholder, no instruction).
18+
- Reconstructed URLs = precomputed strings injected verbatim; agent copies into PR body, does not derive.
19+
20+
## Regex / re-tick safety (load-bearing — addresses adversary findings)
21+
22+
- L924 PR snippet: text=`#NNN`, href=populated URL → never matches empty-href filter; no re-tick ghost. Verify via fixture (see Verification).
23+
- "Empty href" covers all SF storage forms: `href=""`, `href=" "` / whitespace-only, entity-encoded `href=&quot;&quot;`, absent `href`.
24+
- Populated-href anchors (real `href="https://..."`) EXCLUDED even when text matches `discussions/\d+` — user-authored live links; URL already present, reconstructing would risk overwriting correct host/path.
25+
26+
## Phases
27+
28+
### Phase 1 — `extractDiscussionUrls` + interpolate into `draftPrPrompt`
29+
30+
- Add `extractDiscussionUrls(details)` near `extractPrUrl` (L289), arrow `const`, returns `string[]`:
31+
- match `<a ...>TEXT</a>` where TEXT matches `(discussions|issues)\/\d+`
32+
- INCLUDE only if href is empty/missing in ALL stored forms: no `href` attr, `href=""`, `href="<whitespace>"`, or entity-encoded `href=&quot;&quot;`. EXCLUDE any anchor whose href holds a real value (e.g. `href="https://..."`).
33+
- reconstruct `https://github.com/forcedotcom/salesforcedx-vscode/${path}` from the matched `discussions/NNN`|`issues/NNN`
34+
- dedupe (Set); return array (empty when none)
35+
- `draftPrPrompt` (L894): `const reconstructedUrls = extractDiscussionUrls(chosen.details)` as first statement. Interpolate, ONLY when non-empty, into the body — add to step 4's reference area, e.g.:
36+
```
37+
${reconstructedUrls.length ? `\n - ## References — the originating GitHub discussion/issue links (SF stripped their hrefs; reconstructed below). Include each verbatim in the body:\n${reconstructedUrls.map(u => ` ${u}`).join('\n')}` : ''}
38+
```
39+
Agent copies the precomputed strings; it does not derive them. Empty → nothing injected.
40+
- commit: `feat(auto-build-wi): reconstruct stripped discussion/issue URLs for PR body - W-23150428`
41+
- files: `.claude/workflows/auto-build-wi.js`
42+
43+
### Phase 2 — pr-draft SKILL step
44+
45+
- `## GitHub issues & discussions`: add step — scan WI `Details__c` for anchors w/ `discussions/`|`issues/` text whose href is empty/missing in any stored form (`href=""`, `href=&quot;&quot;`, whitespace, absent); EXCLUDE anchors with a populated real href; auto-include reconstructed `https://github.com/forcedotcom/salesforcedx-vscode/<path>` URLs, no user prompt
46+
- concise style
47+
- commit: `docs(pr-draft): auto-include stripped discussion/issue URLs - W-23150428`
48+
- files: `.claude/skills/pr-draft/SKILL.md`
49+
50+
### Phase 3 — gus-cli SKILL href-stripping note
51+
52+
- `Details__c formatting` section: document SF strips external hrefs on save; advise always write full `href` even if stripped (text-preserved path lets auto-build reconstruct)
53+
- concise style
54+
- commit: `docs(gus-cli): note SF href-stripping in rich-text Details__c - W-23150428`
55+
- files: `.claude/skills/gus-cli/SKILL.md`
56+
57+
## Skills to apply
58+
59+
- concise (all `.md` + plan)
60+
- gus-cli, pr-draft (domain conventions)
61+
- typescript (auto-build-wi.js changes)
62+
63+
## Verification
64+
65+
- `node -e` load `extractDiscussionUrls`; assert each href-empty form maps to reconstructed URL and each excluded form is dropped:
66+
- `<a href="">discussions/5867</a>``https://github.com/forcedotcom/salesforcedx-vscode/discussions/5867`
67+
- `<a href=&quot;&quot;>discussions/42</a>` (entity-encoded empty) → reconstructed
68+
- `<a href=" ">issues/123</a>` (whitespace href) → reconstructed
69+
- `<a>issues/9</a>` (absent href) → reconstructed
70+
- `<a href="https://github.com/forcedotcom/salesforcedx-vscode/discussions/77">discussions/77</a>` (populated href) → EXCLUDED
71+
- workflow's own PR snippet `<p><strong>PR:</strong> <a href="https://github.com/forcedotcom/salesforcedx-vscode/pull/7382">#7382</a></p>` → EXCLUDED (text `#7382` not a path; guards re-tick ghost URL)
72+
- non-matching link text → excluded
73+
- duplicate empty-href anchors → single deduped entry
74+
- empty/null details → `[]`
75+
- `node --check .claude/workflows/auto-build-wi.js`
76+
- lint/prettier — CI-covered, skip manual
77+
- no e2e on branch (workflow script + skill docs)

.claude/skills/gus-cli/SKILL.md

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ Objects: `ADM_Work__c`, `ADM_Epic__c` (not ADM_Theme\_\_c).
8282

8383
Closed statuses: see ## Status\_\_c values. Use `LIMIT 50` (or 100) when querying team or epic work.
8484

85+
**Open-WI queries must ALSO exclude the "Bug no-fix" terminals**: `Duplicate`, `Inactive`, `Never`, `Not a bug`, `Not Reproducible`, `Rejected`, `Eng Internal`. Terminal despite no "Closed" prefix — omit them and a `Duplicate` WI wrongly shows as open.
86+
8587
**Create:** Always set `Story_Points__c=2`, `Product_Tag__c=a1aB000000005G3IAI`, `RecordTypeId`. Include `Subject__c`, `Assignee__c`, `Scrum_Team__c=a00B0000000w9xPIAQ`, `Epic__c` (optional), `QA_Engineer__c` (optional), `Details__c` (optional). Leave `Sprint__c` blank; never modify it. **Details\_\_c:** write concisely—fragments/bullets, minimal words, no repetition (see .claude/skills/concise/SKILL.md).
8688

8789
**`Details__c` ≥20 chars required.** `Details__c` (field label "Description") has a User Story validation rule: <20 chars → create fails with `Description must be at least 20 characters to submit a User Story`. Despite docs marking it optional, treat as required on create. Note: `Description__c` is a DIFFERENT field (label "Comment", unvalidated)—don't confuse them; the validated body field is `Details__c`.
@@ -104,6 +106,8 @@ Closed statuses: see ## Status\_\_c values. Use `LIMIT 50` (or 100) when queryin
104106

105107
Constraints: File single-line (flags-dir treats each line as a separate flag invocation). Values in single quotes. HTML: `<p>`, `<strong>`, `<code>`, `<ul><li>`, `<a href="...">`. Escape `"` inside value as `&quot;`.
106108

109+
**SF strips external hrefs on save:** `<a href=&quot;https://github.com/...discussions/5867&quot;>discussions/5867</a>` persists as `<a href="">discussions/5867</a>` — link text survives, href empties. Write full `href` regardless — surviving `discussions/NNN`|`issues/NNN` path text lets auto-build reconstruct the PR URL. Prefer link text that IS the path (`discussions/5867`), not a label.
110+
107111
**After create:** Always provide the work item link. Format: `https://gus.lightning.force.com/lightning/r/ADM_Work__c/<recordId>/view` (replace `<recordId>` with the Id from the create output, e.g. `a07EE00002V3a8YYAR`). Example: [a07EE00002V3a8YYAR](https://gus.lightning.force.com/lightning/r/ADM_Work__c/a07EE00002V3a8YYAR/view).
108112

109113
**CRITICAL:** After creation, you MUST query the `Name` (W-XXXXX) to append to the PR title as ` - W-XXXXX`. The `id` returned by `sf data create` is NOT the `W-XXXXX` name.
@@ -130,6 +134,8 @@ sf data query --query "SELECT Id, Name, Description__c FROM ADM_Epic__c WHERE Te
130134

131135
Closed = `Health__c` in ('Completed', 'Canceled'). Use `Description__c` when populated to match work to epic.
132136

137+
**`Description__c` is not filterable in SOQL**`WHERE`/`LIKE` on it errors `field 'Description__c' can not be filtered in a query call`. To match an epic by text, fetch all open epics and match on `Name`, or post-filter `Description__c` client-side (e.g. with jq). Only `SELECT` it.
138+
133139
## Epic guide: which work items go where
134140

135141
Use to pick the right Epic\_\_c when creating work. Query epics first; match by Name/Description. Key epics:
@@ -161,9 +167,9 @@ When unsure which epic: ask the user.
161167

162168
`[ai-auto]` in `Subject__c` or `Details__c` opts a WI into the [auto-build-wi workflow](../../workflows/auto-build-wi.js) (claim → plan → build → review → draft PR). See [workflows/README.md](../../workflows/README.md).
163169

164-
- Add only on explicit user request; prefer `Subject__c`
170+
- Add only on explicit user request; only `Subject__c` (title), never `Details__c`
165171
- Skip for WIs needing design/coordination
166-
- Query: `(Subject__c LIKE '%[ai-auto]%' OR Details__c LIKE '%[ai-auto]%')`
172+
- Query: `Subject__c LIKE '%[ai-auto]%'`
167173

168174
## Compound workflows
169175

@@ -191,6 +197,8 @@ When unsure which epic: ask the user.
191197
When creating/updating, only use New,In Progress,Ready for Review,QA In Progress,Fixed,Waiting,Closed
192198
When completing a work item, use `Closed`.
193199

200+
To mark a WI as a duplicate: set `Status__c='Duplicate'` + link the original via `Related_Work__c` (label "Duplicate Of"). `Closed - Duplicate` does NOT persist here — a trigger reverts it to `Duplicate` — so use `Duplicate` directly. `Duplicate` is terminal (treat like Closed) for open/unfinished queries.
201+
194202
**Flow:** New → Acknowledged → Triaged → In Progress → Ready for Review → Fixed → QA In Progress → Completed/Closed
195203

196204
**Blocked:** Investigating | More Info Reqd from Support | Waiting On Customer | Waiting On 3rd Party | Waiting | Deferred | Integrate | Pending Release
@@ -201,6 +209,6 @@ When completing a work item, use `Closed`.
201209

202210
## CLI tips
203211

204-
- `--result-format json` for parseable output
205-
- Strip CLI version warning before JSON parse (`tail -1` or parse last object)
212+
- `--json` for parseable output (not `--result-format json`)
213+
- Parse with `jq`, not python
206214
- `sf data create record` / `sf data update record` for single-record writes

0 commit comments

Comments
 (0)