worclaude 2.7.0 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -0
- package/package.json +1 -1
- package/src/commands/doctor.js +68 -0
- package/src/commands/init.js +12 -4
- package/templates/agents/optional/quality/bug-fixer.md +12 -0
- package/templates/agents/universal/test-writer.md +12 -0
- package/templates/agents/universal/verify-app.md +12 -0
- package/templates/commands/setup.md +123 -60
- package/templates/skills/universal/subagent-usage.md +14 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,42 @@ All notable changes to worclaude are documented in this file. Format loosely fol
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [2.8.0] — 2026-04-24
|
|
8
|
+
|
|
9
|
+
Fixes a long-standing agent worktree correctness bug. Both `claude --worktree` and the `Agent` tool's `isolation: "worktree"` option create their isolated checkout from `origin/HEAD` — which on most worclaude-convention repos resolves to `origin/main`. When the working branch (typically `develop`) is ahead of main (the normal state mid-release-cycle), agent worktrees get a stale checkout that misses recent commits, producing "missing develop files" symptoms easy to misattribute to tooling flakiness. This release ships two complementary fixes: a new `worclaude doctor` check that detects and warns on the at-risk configuration with a local, reversible remedy (`git remote set-head origin <branch>`), and a freshness preamble on the three bundled worktree agents (`bug-fixer`, `verify-app`, `test-writer`) that resets the worktree to match the parent's current branch regardless of `origin/HEAD`. Documentation in `subagent-usage` now correctly describes the harness behavior instead of the previous "creates a worktree from your current branch" claim.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **`worclaude doctor` Git Integration / `origin/HEAD` divergence check** (PR #121) — warns when the current branch is ahead of `origin/HEAD`'s target, naming the branch and commit count. Suggests `git remote set-head origin <branch>` (local-only, reversible via `--auto` or `main`) as the fix. Skips silently outside a git repo or when `origin/HEAD` is unset. Shared `runGit(cwd, args)` helper added alongside for future checks to reuse the same spawn pattern.
|
|
14
|
+
- **Worktree freshness preamble on `bug-fixer`, `verify-app`, `test-writer` agent templates** (PR #121) — on worktree start the agent runs `git fetch origin`, identifies the parent's current branch from `git worktree list --porcelain` (filtering out auto-named `worktree-agent-*` branches), then `git reset --hard "origin/${PARENT_BRANCH}"`. Protects correctness even when the user hasn't run `set-head`. LLM-driven parsing (no `awk`/`sed` pipelines) for cross-platform portability.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- **`subagent-usage` skill (both `.claude/skills/subagent-usage/SKILL.md` and `templates/skills/universal/subagent-usage.md`)** (PR #121) — "How it works" item 1 corrected from "creates a worktree from your current branch" to "creates a worktree based on `origin/HEAD` (see gotcha below)". New "Base-branch gotcha" subsection cross-links to `worclaude doctor` and the `git remote set-head` remedy, and notes that the three bundled agents include a freshness preamble while other worktree agents do not.
|
|
19
|
+
|
|
20
|
+
### Docs
|
|
21
|
+
|
|
22
|
+
- **`docs/spec/SPEC.md` doctor section** (this /sync) — adds a `### Git Integration` subsection documenting both the gitignore coverage check and the new origin/HEAD divergence check.
|
|
23
|
+
- **`docs/spec/PROGRESS.md`** (this /sync) — new v2.8.0 release entry; Stats refreshed (788 → 804 tests, 57 → 58 files).
|
|
24
|
+
|
|
25
|
+
## [2.7.1] — 2026-04-24
|
|
26
|
+
|
|
27
|
+
Three `/setup` UX follow-ups from v2.7.0 confirmation testing, shipped as a single patch PR. The `?` / `help` trigger introduced in v2.7.0 turned out to collide with Claude Code's built-in keyboard-shortcut overlay (pressing `?` opens the shortcut panel before /setup's parser sees the keystroke); switched to the `help` keyword only. `worclaude init`'s `runOptionalExtras` was the only place in the init flow still using `inquirer type: 'confirm'` (rendered as `(y/N)`) — converted to `type: 'list'` arrow-key menus so every yes/no in init behaves consistently. CONFIRM_MEDIUM now invokes `AskUserQuestion` directly when the per-item option count fits the tool's `maxItems: 4` schema cap, with the consequence info ("Will be saved as") carried inside each option's `description` field; falls back to the verbatim text prompt (using `help` instead of `?`) when the count exceeds 4. CONFIRM_HIGH stays text-parse — detection lists routinely exceed 4 items. No consumer-visible schema or CLI surface additions.
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
|
|
31
|
+
- **`/setup` `?` help trigger → `help` keyword** (PR #119) — 9 occurrences across CONFIRM_HIGH + CONFIRM_MEDIUM prompt templates, response-parsing bullets, error restates, and the Field-help table intro. Explanatory notes added so future maintainers don't re-add `?`.
|
|
32
|
+
- **`worclaude init` prompt-type consistency** (PR #119) — `runOptionalExtras` (src/commands/init.js:77-93) converted the plugin.json and gtd-memory prompts from `type: 'confirm'` (the only `(y/N)` text inputs in init) to `type: 'list'` with boolean-valued Yes/No choices. Regression test inspects `inquirer.prompt.mock.calls` directly.
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
|
|
36
|
+
- **`/setup` CONFIRM_MEDIUM (≤4 options) uses `AskUserQuestion`** (PR #119) — State 3 split into Path 1 (AskUserQuestion path) and Path 2 (verbatim text fallback, >4 options). Rule #5 widens the AskUserQuestion permit to include CONFIRM_MEDIUM. Rule #7 picks up an explicit EXCEPTION paragraph. Storage rule from v2.6.5 (`mediumResolved[field]` must be a string) applies uniformly across both paths.
|
|
37
|
+
|
|
38
|
+
### Docs
|
|
39
|
+
|
|
40
|
+
- **`docs/spec/SPEC.md` `/setup` section** (this /sync) — reflects the `help`-keyword-only trigger and the CONFIRM_MEDIUM ≤4-option AskUserQuestion path.
|
|
41
|
+
- **`docs/spec/PROGRESS.md`** (this /sync) — new v2.7.1 release entry; Stats refreshed (782 → 788 tests).
|
|
42
|
+
|
|
7
43
|
## [2.7.0] — 2026-04-23
|
|
8
44
|
|
|
9
45
|
`/setup` hardening + UX revamp release. PR #115 closes 8 backend bug clusters surfaced by the v2.6.3 manual test matrix (upgrade-flow correctness, downgrade guard, doctor ghost detection, scaffolder exec bits, Commander routing). PR #116 fixes four `/setup` template failure modes — missing `schemaVersion` in SCAN state, `readme` object-shape mismatch in CONFIRM_MEDIUM, all-22-questions-asked despite detection, accept-off-topic-as-answer — and adds a `--from-file` flag to `worclaude setup-state save` plus `Bash(worclaude:*)` permissions so `/setup` runs without approval-prompt interruption. PR #117 adopts Claude Code's `AskUserQuestion` tool for 10 enumerable interview questions (arrow-key selection instead of free-text), redesigns CONFIRM prompts with a "Will be saved as" consequence sub-line and `?` / `help` command, and drops the 80-char readme truncation so users can read the full description before accepting. Dogfood-relevant: `.claude/commands/setup.md` auto-updates on `worclaude upgrade` to pick up the new template.
|
package/package.json
CHANGED
package/src/commands/doctor.js
CHANGED
|
@@ -838,6 +838,73 @@ async function checkGitignore(projectRoot) {
|
|
|
838
838
|
return results;
|
|
839
839
|
}
|
|
840
840
|
|
|
841
|
+
function runGit(projectRoot, args) {
|
|
842
|
+
try {
|
|
843
|
+
const r = spawnSync('git', args, { cwd: projectRoot, encoding: 'utf8' });
|
|
844
|
+
if (r.error) return { status: -1, stdout: '', stderr: String(r.error) };
|
|
845
|
+
return {
|
|
846
|
+
status: r.status,
|
|
847
|
+
stdout: (r.stdout || '').trim(),
|
|
848
|
+
stderr: (r.stderr || '').trim(),
|
|
849
|
+
};
|
|
850
|
+
} catch (err) {
|
|
851
|
+
return { status: -1, stdout: '', stderr: String(err) };
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
async function checkOriginHead(projectRoot) {
|
|
856
|
+
const skipped = result(PASS, 'origin/HEAD check skipped', null);
|
|
857
|
+
|
|
858
|
+
const headRef = runGit(projectRoot, ['symbolic-ref', 'refs/remotes/origin/HEAD']);
|
|
859
|
+
if (headRef.status === 128) return skipped;
|
|
860
|
+
if (headRef.status !== 0) {
|
|
861
|
+
return result(
|
|
862
|
+
WARN,
|
|
863
|
+
'origin/HEAD not set',
|
|
864
|
+
'Run `git remote set-head origin --auto` (or `git remote set-head origin <branch>`) so worktree agents have a defined base'
|
|
865
|
+
);
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
const defaultBranch = headRef.stdout.replace(/^refs\/remotes\/origin\//, '');
|
|
869
|
+
if (!defaultBranch) {
|
|
870
|
+
return result(WARN, 'origin/HEAD malformed', `Unexpected ref: ${headRef.stdout}`);
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
const currentRef = runGit(projectRoot, ['branch', '--show-current']);
|
|
874
|
+
if (currentRef.status !== 0) return skipped;
|
|
875
|
+
|
|
876
|
+
const currentBranch = currentRef.stdout;
|
|
877
|
+
if (!currentBranch) {
|
|
878
|
+
return result(PASS, `origin/HEAD → ${defaultBranch} (detached HEAD, skipped)`, null);
|
|
879
|
+
}
|
|
880
|
+
if (currentBranch === defaultBranch) {
|
|
881
|
+
return result(PASS, `origin/HEAD → ${defaultBranch} (matches current branch)`, null);
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
const ahead = runGit(projectRoot, [
|
|
885
|
+
'rev-list',
|
|
886
|
+
'--count',
|
|
887
|
+
`origin/${defaultBranch}..${currentBranch}`,
|
|
888
|
+
]);
|
|
889
|
+
if (ahead.status !== 0) {
|
|
890
|
+
return result(PASS, `origin/HEAD → ${defaultBranch}`, null);
|
|
891
|
+
}
|
|
892
|
+
const aheadCount = Number.parseInt(ahead.stdout, 10) || 0;
|
|
893
|
+
if (aheadCount === 0) {
|
|
894
|
+
return result(
|
|
895
|
+
PASS,
|
|
896
|
+
`origin/HEAD → ${defaultBranch}, current '${currentBranch}' not ahead`,
|
|
897
|
+
null
|
|
898
|
+
);
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
return result(
|
|
902
|
+
WARN,
|
|
903
|
+
`Current branch '${currentBranch}' is ${aheadCount} commit(s) ahead of origin/${defaultBranch}`,
|
|
904
|
+
`Worktree agents (claude --worktree, Agent isolation:worktree) base off origin/${defaultBranch} and will miss those commits. Fix: \`git remote set-head origin ${currentBranch}\` (local-only, reversible with \`--auto\` or \`main\`)`
|
|
905
|
+
);
|
|
906
|
+
}
|
|
907
|
+
|
|
841
908
|
async function checkPendingReviewFiles(projectRoot) {
|
|
842
909
|
const pending = [];
|
|
843
910
|
try {
|
|
@@ -943,6 +1010,7 @@ export async function doctorCommand(options = {}) {
|
|
|
943
1010
|
// Git Integration
|
|
944
1011
|
section('Git Integration');
|
|
945
1012
|
record('git', await checkGitignore(projectRoot));
|
|
1013
|
+
record('git', await checkOriginHead(projectRoot));
|
|
946
1014
|
spacer();
|
|
947
1015
|
|
|
948
1016
|
// Integrity
|
package/src/commands/init.js
CHANGED
|
@@ -77,16 +77,24 @@ async function runAgents(selections) {
|
|
|
77
77
|
async function runOptionalExtras(selections) {
|
|
78
78
|
const { generatePluginJson, scaffoldGtdMemory } = await inquirer.prompt([
|
|
79
79
|
{
|
|
80
|
-
type: '
|
|
80
|
+
type: 'list',
|
|
81
81
|
name: 'generatePluginJson',
|
|
82
82
|
message: 'Generate .claude-plugin/plugin.json for marketplace compatibility?',
|
|
83
|
-
|
|
83
|
+
choices: [
|
|
84
|
+
{ name: 'Yes', value: true },
|
|
85
|
+
{ name: 'No', value: false },
|
|
86
|
+
],
|
|
87
|
+
default: selections.generatePluginJson === true ? 0 : 1,
|
|
84
88
|
},
|
|
85
89
|
{
|
|
86
|
-
type: '
|
|
90
|
+
type: 'list',
|
|
87
91
|
name: 'scaffoldGtdMemory',
|
|
88
92
|
message: 'Scaffold structured memory files (decisions.md, preferences.md)?',
|
|
89
|
-
|
|
93
|
+
choices: [
|
|
94
|
+
{ name: 'Yes', value: true },
|
|
95
|
+
{ name: 'No', value: false },
|
|
96
|
+
],
|
|
97
|
+
default: selections.scaffoldGtdMemory === true ? 0 : 1,
|
|
90
98
|
},
|
|
91
99
|
]);
|
|
92
100
|
return { ...selections, generatePluginJson, scaffoldGtdMemory };
|
|
@@ -6,6 +6,18 @@ isolation: worktree
|
|
|
6
6
|
maxTurns: 50
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
+
## Worktree freshness preamble
|
|
10
|
+
|
|
11
|
+
Before making any code changes, synchronize this worktree to the parent checkout's committed state. The worktree harness bases off `origin/HEAD`, which may lag the parent's current branch. Follow these steps and report the result:
|
|
12
|
+
|
|
13
|
+
1. Run `git fetch origin`.
|
|
14
|
+
2. Run `git worktree list --porcelain`. Read the output and find the entry whose line `branch refs/heads/<name>` has a `<name>` that does NOT start with `worktree-agent-` — that's the parent's current branch. Strip the `refs/heads/` prefix and use it as `PARENT_BRANCH`.
|
|
15
|
+
3. Run `git reset --hard "origin/${PARENT_BRANCH}"`.
|
|
16
|
+
|
|
17
|
+
If step 2 yields no match, or step 3 fails, stop and report the issue — do not make changes against an unsynchronized worktree.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
9
21
|
You are a senior developer who specializes in diagnosing and fixing
|
|
10
22
|
bugs. You follow a disciplined approach: understand the bug, find the
|
|
11
23
|
root cause, make a minimal fix, and verify it with a regression test.
|
|
@@ -9,6 +9,18 @@ skills:
|
|
|
9
9
|
- testing
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
+
## Worktree freshness preamble
|
|
13
|
+
|
|
14
|
+
Before writing tests, synchronize this worktree to the parent checkout's committed state. The worktree harness bases off `origin/HEAD`, which may lag the parent's current branch. Follow these steps and report the result:
|
|
15
|
+
|
|
16
|
+
1. Run `git fetch origin`.
|
|
17
|
+
2. Run `git worktree list --porcelain`. Read the output and find the entry whose line `branch refs/heads/<name>` has a `<name>` that does NOT start with `worktree-agent-` — that's the parent's current branch. Strip the `refs/heads/` prefix and use it as `PARENT_BRANCH`.
|
|
18
|
+
3. Run `git reset --hard "origin/${PARENT_BRANCH}"`.
|
|
19
|
+
|
|
20
|
+
If step 2 yields no match, or step 3 fails, stop and report the issue — tests written against a stale worktree will not cover the code you were asked about.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
12
24
|
You are a test specialist. You write comprehensive, meaningful tests
|
|
13
25
|
for recently changed code. You focus on testing behavior (what the code
|
|
14
26
|
does) not implementation (how it does it). You work in a worktree to
|
|
@@ -9,6 +9,18 @@ initialPrompt: "/start"
|
|
|
9
9
|
criticalSystemReminder: "CRITICAL: You are verification-only. Do NOT edit or fix code. Report findings with exact reproduction steps."
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
+
## Worktree freshness preamble
|
|
13
|
+
|
|
14
|
+
Before running any verification, synchronize this worktree to the parent checkout's committed state. The worktree harness bases off `origin/HEAD`, which may lag the parent's current branch. Follow these steps and report the result:
|
|
15
|
+
|
|
16
|
+
1. Run `git fetch origin`.
|
|
17
|
+
2. Run `git worktree list --porcelain`. Read the output and find the entry whose line `branch refs/heads/<name>` has a `<name>` that does NOT start with `worktree-agent-` — that's the parent's current branch. Strip the `refs/heads/` prefix and use it as `PARENT_BRANCH`.
|
|
18
|
+
3. Run `git reset --hard "origin/${PARENT_BRANCH}"`.
|
|
19
|
+
|
|
20
|
+
If step 2 yields no match, or step 3 fails, stop and report the issue — verification against a stale worktree is meaningless.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
12
24
|
You are a verification specialist. You test the actual running
|
|
13
25
|
application to confirm that implemented features work correctly
|
|
14
26
|
end-to-end. Unit tests passing is not enough — you verify the real
|
|
@@ -65,11 +65,16 @@ normally apply.
|
|
|
65
65
|
- Read: `.claude/cache/setup-state.json`
|
|
66
66
|
- Write: `.claude/cache/setup-state.draft.json` (state-save staging
|
|
67
67
|
only — overwritten each save).
|
|
68
|
-
- Tool: `AskUserQuestion`
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
68
|
+
- Tool: `AskUserQuestion` permitted at:
|
|
69
|
+
- INTERVIEW states, per the Interaction mode contract
|
|
70
|
+
(`selectable` / `multi-selectable` / `hybrid` questions).
|
|
71
|
+
- CONFIRM_MEDIUM when the per-item option count (candidates + 1
|
|
72
|
+
for "Other") is ≤ 4 — AskUserQuestion's own `maxItems: 4`
|
|
73
|
+
schema cap. When the count exceeds 4, fall back to the verbatim
|
|
74
|
+
text-parse rendering defined in State 3 below.
|
|
75
|
+
Not permitted at CONFIRM_HIGH: the detection list routinely has
|
|
76
|
+
12+ items in real projects, which exceeds the 4-option schema cap.
|
|
77
|
+
CONFIRM_HIGH renders VERBATIM per rule #7.
|
|
73
78
|
|
|
74
79
|
At WRITE state the whitelist RELAXES to additionally permit:
|
|
75
80
|
|
|
@@ -92,15 +97,23 @@ normally apply.
|
|
|
92
97
|
project only. Only use information the user provides during THIS
|
|
93
98
|
interview and the detection report for THIS project.
|
|
94
99
|
|
|
95
|
-
7. **RENDER PROMPTS VERBATIM.** Where a state specifies a
|
|
96
|
-
with `[x] 1. ...` syntax or other structured output,
|
|
97
|
-
EXACTLY as specified AND wrap it in a triple-backtick
|
|
98
|
-
block so Markdown rendering does not reformat checkboxes
|
|
99
|
-
renumber lines. The format is part of the contract with the
|
|
100
|
+
7. **RENDER PROMPTS VERBATIM.** Where a state specifies a text-parse
|
|
101
|
+
prompt format with `[x] 1. ...` syntax or other structured output,
|
|
102
|
+
render it EXACTLY as specified AND wrap it in a triple-backtick
|
|
103
|
+
fenced code block so Markdown rendering does not reformat checkboxes
|
|
104
|
+
or renumber lines. The format is part of the contract with the
|
|
100
105
|
user-response parser — paraphrasing or reformatting breaks parsing.
|
|
101
106
|
You MAY add a brief conversational sentence before or after a
|
|
102
107
|
verbatim prompt, but NOT within it.
|
|
103
108
|
|
|
109
|
+
EXCEPTION — CONFIRM_MEDIUM via AskUserQuestion: when the per-item
|
|
110
|
+
option count is ≤ 4 (candidates + "Other"), State 3 uses the
|
|
111
|
+
`AskUserQuestion` tool path instead of the verbatim text prompt
|
|
112
|
+
(see rule #5 and State 3). The verbatim-rendering requirement does
|
|
113
|
+
not apply to tool invocations. When the count exceeds 4, the text
|
|
114
|
+
fallback kicks in and this rule applies as written. CONFIRM_HIGH
|
|
115
|
+
never uses AskUserQuestion (detection lists routinely exceed 4).
|
|
116
|
+
|
|
104
117
|
KNOWN FAILURE MODES: reformatting `[x] 1. X: Y` as `- [x] X: Y`
|
|
105
118
|
(loses numbering); paraphrasing labels; collapsing items onto one
|
|
106
119
|
line; rendering outside a fenced block (Markdown may convert `[x]`
|
|
@@ -235,7 +248,7 @@ ENTRY:
|
|
|
235
248
|
```
|
|
236
249
|
I scanned your project. Please confirm the high-confidence
|
|
237
250
|
detections below. Reply with the numbers of any items that are
|
|
238
|
-
WRONG (e.g., "2, 5"), or reply "ok" to accept all, or "
|
|
251
|
+
WRONG (e.g., "2, 5"), or reply "ok" to accept all, or type "help".
|
|
239
252
|
|
|
240
253
|
[x] 1. <formatField(item1.field)>: <renderValue(item1)> (from <item1.source>)
|
|
241
254
|
→ Will be saved as: <target1>
|
|
@@ -257,13 +270,15 @@ Response parsing (case-insensitive, whitespace trimmed):
|
|
|
257
270
|
- One or more integers (comma or space separated) in range 1..N →
|
|
258
271
|
those items are rejected; split fields into accepted/rejected
|
|
259
272
|
accordingly (in rendered order).
|
|
260
|
-
-
|
|
261
|
-
|
|
273
|
+
- `help` → render the **Field-help** block for EACH displayed field
|
|
274
|
+
(description + target + example) without advancing state. Then
|
|
262
275
|
restate the prompt above (same text, same items). Do NOT persist a
|
|
263
|
-
mutation for the help render.
|
|
276
|
+
mutation for the help render. (`?` is intentionally NOT a trigger —
|
|
277
|
+
Claude Code binds it to a keyboard-shortcut overlay that intercepts
|
|
278
|
+
the keystroke before /setup sees it.)
|
|
264
279
|
- Anything else (including integers out of range) → rule #3 fires:
|
|
265
280
|
restate with "I need either 'ok', numbers from 1 to `<N>` matching
|
|
266
|
-
the items above (e.g., '2, 5'), or
|
|
281
|
+
the items above (e.g., '2, 5'), or type `help`. To cancel, type
|
|
267
282
|
`cancel setup`."
|
|
268
283
|
|
|
269
284
|
State file mutation: persist the updated arrays via
|
|
@@ -280,69 +295,117 @@ ENTRY:
|
|
|
280
295
|
report.
|
|
281
296
|
- If there are zero medium-confidence items: persist
|
|
282
297
|
`mediumResolved: {}`, transition to INTERVIEW_STORY.
|
|
283
|
-
- Otherwise iterate in report order. For each medium item,
|
|
284
|
-
|
|
285
|
-
`
|
|
298
|
+
- Otherwise iterate in report order. For each medium item, compute the
|
|
299
|
+
total option count:
|
|
300
|
+
- Shape A (`candidates === null`, emitted by `readme`):
|
|
301
|
+
`1 + 1` = 2 (detected value + "Other").
|
|
302
|
+
- Shape B (`candidates` is a non-empty array): `candidates.length + 1`.
|
|
303
|
+
If the total is ≤ 4, use the **AskUserQuestion path** (Path 1).
|
|
304
|
+
Otherwise fall back to the **verbatim text-parse path** (Path 2).
|
|
305
|
+
The threshold is the `maxItems: 4` schema cap of AskUserQuestion.
|
|
306
|
+
|
|
307
|
+
#### Path 1 — AskUserQuestion (option count ≤ 4)
|
|
308
|
+
|
|
309
|
+
Invoke the `AskUserQuestion` tool once per medium item with exactly
|
|
310
|
+
this shape:
|
|
311
|
+
|
|
312
|
+
- `question`: `<formatField(field)> — detected from <source>. Which
|
|
313
|
+
should I use?`
|
|
314
|
+
- `header`: short label for the sidebar (≤ 12 chars) — typically
|
|
315
|
+
`formatField(field)` truncated.
|
|
316
|
+
- `multiSelect`: `false`
|
|
317
|
+
- `options`: built from the Shape above:
|
|
318
|
+
- Shape A: `[{ label: <renderValue(item)>, description: "Will be
|
|
319
|
+
saved as <target>. Accept the detected value." },
|
|
320
|
+
{ label: "Other (I'll type my own)", description: "Supply a
|
|
321
|
+
custom value via free-text follow-up." }]`
|
|
322
|
+
- Shape B: one option per `candidates[k]` with
|
|
323
|
+
`description: "Will be saved as <target>."`; append
|
|
324
|
+
`{ label: "Other (I'll type my own)", description: "Supply a
|
|
325
|
+
custom value via free-text follow-up." }` as the final option.
|
|
326
|
+
|
|
327
|
+
`<target>` comes from the **Field-help table** below. Render it
|
|
328
|
+
verbatim per the table.
|
|
329
|
+
|
|
330
|
+
On response:
|
|
331
|
+
- User selects a candidate label → store that label string in
|
|
332
|
+
`mediumResolved[field]` (Storage rule applies).
|
|
333
|
+
- User selects "Other (I'll type my own)" → follow up with a free-text
|
|
334
|
+
prompt: "Go ahead — what's the value you'd like to use?". Store the
|
|
335
|
+
trimmed reply.
|
|
336
|
+
|
|
337
|
+
`AskUserQuestion` does not expose a `help` trigger; the per-option
|
|
338
|
+
`description` text carries the equivalent content inline. The text
|
|
339
|
+
fallback's `help` keyword is scoped to Path 2 only.
|
|
340
|
+
|
|
341
|
+
#### Path 2 — Verbatim text prompt (option count > 4)
|
|
342
|
+
|
|
343
|
+
Render ONE prompt VERBATIM in a fenced code block. The prompt shape
|
|
344
|
+
depends on `item.candidates`:
|
|
345
|
+
|
|
346
|
+
**Shape A — `candidates === null`** (rare in this path — only 2
|
|
347
|
+
options, typically handled by Path 1 above; included here for
|
|
348
|
+
completeness in case AskUserQuestion is unavailable):
|
|
286
349
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
```
|
|
290
|
-
<formatField(field)> (detected from <source>):
|
|
291
|
-
|
|
292
|
-
1. <renderValue(item)>
|
|
293
|
-
→ Will be saved as: <target>
|
|
294
|
-
2. Other (I'll type my own)
|
|
295
|
-
|
|
296
|
-
Reply with the number of your choice (default: 1), or `?` for help:
|
|
297
|
-
```
|
|
350
|
+
```
|
|
351
|
+
<formatField(field)> (detected from <source>):
|
|
298
352
|
|
|
299
|
-
|
|
300
|
-
|
|
353
|
+
1. <renderValue(item)>
|
|
354
|
+
→ Will be saved as: <target>
|
|
355
|
+
2. Other (I'll type my own)
|
|
301
356
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
→ Will be saved as: <target>
|
|
357
|
+
Reply with the number of your choice (default: 1), or type `help`:
|
|
358
|
+
```
|
|
305
359
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
N. <candidates[N-1]>
|
|
310
|
-
N+1. Other (I'll type my own)
|
|
360
|
+
**Shape B — `candidates` is a non-empty array** (e.g.,
|
|
361
|
+
`package-manager` when multiple lockfile groups disagree and produce
|
|
362
|
+
4+ candidates):
|
|
311
363
|
|
|
312
|
-
|
|
313
|
-
|
|
364
|
+
```
|
|
365
|
+
<formatField(field)> (detected from <source>):
|
|
366
|
+
→ Will be saved as: <target>
|
|
314
367
|
|
|
315
|
-
|
|
316
|
-
|
|
368
|
+
1. <candidates[0]>
|
|
369
|
+
2. <candidates[1]>
|
|
370
|
+
...
|
|
371
|
+
N. <candidates[N-1]>
|
|
372
|
+
N+1. Other (I'll type my own)
|
|
317
373
|
|
|
318
|
-
|
|
319
|
-
|
|
374
|
+
Reply with the number of your choice (default: 1), or type `help`:
|
|
375
|
+
```
|
|
320
376
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
B) for a numbered pick. **NEVER store the raw `item.value` object** —
|
|
325
|
-
for fields like `readme` whose detected value is an object
|
|
326
|
-
(`{projectDescription, setupInstructions, fullPath}`) the validator
|
|
327
|
-
will reject the mutation with `state.mediumResolved.<field> must be a
|
|
328
|
-
string`.
|
|
377
|
+
`<target>` comes from the **Field-help table** below. Render it
|
|
378
|
+
verbatim per the table. `candidates[0]` equals `item.value` —
|
|
379
|
+
default-1 accepts the detected value.
|
|
329
380
|
|
|
330
|
-
Response parsing (
|
|
381
|
+
Response parsing (Path 2 only):
|
|
331
382
|
|
|
332
383
|
- `""` | `1` | `default` → accept item 1; store `renderValue(item)`
|
|
333
|
-
as a string per the Storage rule
|
|
384
|
+
as a string per the Storage rule.
|
|
334
385
|
- The final "Other" number (`2` in shape A, `N+1` in shape B) →
|
|
335
386
|
follow-up free-text prompt: "Go ahead — what's the value you'd like
|
|
336
387
|
to use?". Store the trimmed reply.
|
|
337
388
|
- Integer in range `2..N` (shape B only) → store `candidates[k-1]`.
|
|
338
|
-
-
|
|
389
|
+
- `help` → render the **Field-help** block for this field
|
|
339
390
|
(description + target + example) without advancing state. Then
|
|
340
391
|
restate the prompt above. Do NOT persist a mutation for the help
|
|
341
|
-
render.
|
|
392
|
+
render. (`?` is intentionally NOT a trigger — Claude Code binds it
|
|
393
|
+
to a keyboard-shortcut overlay that intercepts the keystroke.)
|
|
342
394
|
- Anything else → restate with "I need a number from 1 to `<max>`,
|
|
343
|
-
empty for the default, or
|
|
395
|
+
empty for the default, or type `help`. To cancel, type
|
|
344
396
|
`cancel setup`."
|
|
345
397
|
|
|
398
|
+
#### Storage rule (both paths)
|
|
399
|
+
|
|
400
|
+
`mediumResolved[field]` MUST be a string. Store the exact label that
|
|
401
|
+
was shown to the user (Path 1: `AskUserQuestion` `label`; Path 2:
|
|
402
|
+
`renderValue(item)` or `candidates[k-1]`), or the user's trimmed
|
|
403
|
+
free-text on "Other". **NEVER store the raw `item.value` object** —
|
|
404
|
+
for fields like `readme` whose detected value is an object
|
|
405
|
+
(`{projectDescription, setupInstructions, fullPath}`) the validator
|
|
406
|
+
will reject the mutation with `state.mediumResolved.<field> must be a
|
|
407
|
+
string`.
|
|
408
|
+
|
|
346
409
|
State file mutation: after EACH item is resolved (not batched),
|
|
347
410
|
append to `mediumResolved` and persist.
|
|
348
411
|
|
|
@@ -635,7 +698,7 @@ knowledge the detector has no access to).
|
|
|
635
698
|
|
|
636
699
|
### Field-help table
|
|
637
700
|
|
|
638
|
-
Drives the
|
|
701
|
+
Drives the `help` command (CONFIRM_HIGH, CONFIRM_MEDIUM, and
|
|
639
702
|
INTERVIEW states) AND the "→ Will be saved as: `<target>`" line on
|
|
640
703
|
every CONFIRM prompt. Keep the `<target>` column stable — parsers
|
|
641
704
|
downstream don't match on it, but users read it for orientation.
|
|
@@ -686,7 +749,7 @@ Interview questions (used at INTERVIEW states):
|
|
|
686
749
|
| `verification.staging` | Whether there's a staging / preview env | `## Verification` of `docs/spec/SPEC.md` | `yes — Vercel preview per PR` |
|
|
687
750
|
| `verification.required_checks` | CI required checks gating merge | `## Verification` of `docs/spec/SPEC.md` | `tests, lint, type-check` |
|
|
688
751
|
|
|
689
|
-
Help-render format when the user types
|
|
752
|
+
Help-render format when the user types `help` at a CONFIRM or INTERVIEW
|
|
690
753
|
prompt — render in a fenced code block:
|
|
691
754
|
|
|
692
755
|
```
|
|
@@ -67,7 +67,7 @@ coordination overhead grows.
|
|
|
67
67
|
Some agents use `git worktree` to make changes without affecting your working tree:
|
|
68
68
|
|
|
69
69
|
How it works:
|
|
70
|
-
1. Agent creates a worktree
|
|
70
|
+
1. Agent creates a worktree based on `origin/HEAD` (see gotcha below)
|
|
71
71
|
2. Makes changes in the worktree (isolated from your files)
|
|
72
72
|
3. Commits changes
|
|
73
73
|
4. You merge or cherry-pick the results
|
|
@@ -75,6 +75,19 @@ How it works:
|
|
|
75
75
|
Agents with worktree isolation: code-simplifier, test-writer, verify-app, ci-fixer,
|
|
76
76
|
bug-fixer, refactorer, doc-writer.
|
|
77
77
|
|
|
78
|
+
### Base-branch gotcha
|
|
79
|
+
|
|
80
|
+
Both `claude --worktree` and the Agent `isolation: "worktree"` option create the
|
|
81
|
+
worktree from `origin/HEAD`, **not** your current branch. If your working branch is
|
|
82
|
+
ahead of whatever `origin/HEAD` points to (typically `origin/main`), the worktree
|
|
83
|
+
will miss those commits.
|
|
84
|
+
|
|
85
|
+
Run `worclaude doctor` to diagnose. Fix locally with `git remote set-head origin
|
|
86
|
+
<your-branch>` (reversible via `--auto` or `main`). The bundled `bug-fixer`,
|
|
87
|
+
`verify-app`, and `test-writer` agents include a freshness preamble that resets
|
|
88
|
+
their worktree to match the parent's current branch automatically; other worktree
|
|
89
|
+
agents do not.
|
|
90
|
+
|
|
78
91
|
Benefits:
|
|
79
92
|
- Agent's changes don't conflict with your uncommitted work
|
|
80
93
|
- You can review agent changes before merging
|