worclaude 2.5.0 → 2.6.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 +65 -0
- package/package.json +4 -2
- package/src/commands/doctor.js +4 -6
- package/src/commands/init.js +9 -6
- package/src/commands/scan.js +126 -0
- package/src/commands/setup-state.js +113 -0
- package/src/commands/status.js +6 -4
- package/src/commands/upgrade.js +32 -20
- package/src/core/drift-checks.js +2 -1
- package/src/core/file-categorizer.js +38 -0
- package/src/core/merger.js +14 -7
- package/src/core/migration.js +77 -1
- package/src/core/project-scanner/detectors/ci.js +51 -0
- package/src/core/project-scanner/detectors/deployment.js +32 -0
- package/src/core/project-scanner/detectors/env-variables.js +78 -0
- package/src/core/project-scanner/detectors/external-apis.js +45 -0
- package/src/core/project-scanner/detectors/frameworks.js +56 -0
- package/src/core/project-scanner/detectors/language.js +131 -0
- package/src/core/project-scanner/detectors/linting.js +58 -0
- package/src/core/project-scanner/detectors/monorepo.js +93 -0
- package/src/core/project-scanner/detectors/orm.js +72 -0
- package/src/core/project-scanner/detectors/package-manager.js +57 -0
- package/src/core/project-scanner/detectors/readme.js +123 -0
- package/src/core/project-scanner/detectors/scripts.js +128 -0
- package/src/core/project-scanner/detectors/spec-docs.js +110 -0
- package/src/core/project-scanner/detectors/testing.js +88 -0
- package/src/core/project-scanner/index.js +126 -0
- package/src/core/project-scanner/manifests.js +120 -0
- package/src/core/remover.js +6 -3
- package/src/core/scaffolder.js +1 -0
- package/src/core/setup-state.js +213 -0
- package/src/index.js +39 -0
- package/templates/commands/setup.md +512 -113
|
@@ -1,121 +1,520 @@
|
|
|
1
1
|
---
|
|
2
|
-
description:
|
|
2
|
+
description: 'Diagnose-first project setup with state machine — scans, confirms, interviews, writes.'
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
-
|
|
58
|
-
|
|
59
|
-
-
|
|
60
|
-
-
|
|
61
|
-
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
-
|
|
73
|
-
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
5
|
+
## CRITICAL EXECUTION RULES — READ FIRST
|
|
6
|
+
|
|
7
|
+
This command is a state machine. Once `/setup` is invoked, your behavior
|
|
8
|
+
is constrained by the following rules. These rules override contextual
|
|
9
|
+
judgment, helpfulness instincts, and any other instructions you would
|
|
10
|
+
normally apply.
|
|
11
|
+
|
|
12
|
+
1. **ADVANCE STATES IN ORDER.** States execute in numeric order 0 through
|
|
13
|
+
11. You MUST NOT skip a state based on your judgment about what seems
|
|
14
|
+
redundant. If a state's work is trivially empty (e.g., no
|
|
15
|
+
medium-confidence items to confirm), enter the state, record the
|
|
16
|
+
empty mutation, and transition immediately — but DO enter it.
|
|
17
|
+
|
|
18
|
+
2. **NO BACKWARD ADVANCE.** Once you leave a state, do not re-enter it
|
|
19
|
+
within this `/setup` invocation. "Invocation" means one continuous
|
|
20
|
+
run from INIT through DONE. Typing `cancel setup` ENDS the current
|
|
21
|
+
invocation; re-running `/setup` later starts a NEW invocation, and
|
|
22
|
+
entering the saved `currentState` is an allowed forward transition
|
|
23
|
+
for the new invocation. If the user wants to correct a prior answer
|
|
24
|
+
mid-run, tell them to finish this run and edit the output files
|
|
25
|
+
afterward.
|
|
26
|
+
|
|
27
|
+
3. **OFF-TOPIC INPUT DOES NOT ADVANCE.** If the user's response to a
|
|
28
|
+
state's prompt is not valid input for that state, you MUST re-render
|
|
29
|
+
the current state's prompt with this prefix:
|
|
30
|
+
|
|
31
|
+
> "I'm in the middle of project setup (state: `<STATE_NAME>`).
|
|
32
|
+
> I'll help with that after setup completes. To cancel setup, type
|
|
33
|
+
> `cancel setup`."
|
|
34
|
+
|
|
35
|
+
You MUST NOT answer the off-topic question. You MUST NOT run any
|
|
36
|
+
tool to investigate the off-topic question.
|
|
37
|
+
|
|
38
|
+
4. **CANCEL PRESERVES STATE.** The cancel trigger is the case-
|
|
39
|
+
insensitive regex `/^(cancel|stop|abort)( setup)?[.!?\s]*$/i`
|
|
40
|
+
applied to the trimmed user reply. Accepts the base verb (optionally
|
|
41
|
+
followed by "setup") plus trailing punctuation or whitespace —
|
|
42
|
+
`cancel`, `Cancel!`, `STOP SETUP.`, `abort ` all match. Text beyond
|
|
43
|
+
the matched prefix means "not a cancel" (`cancel please` is a
|
|
44
|
+
question, not a cancel). On match, acknowledge (the state file is
|
|
45
|
+
already saved after every mutation per rule #6), print:
|
|
46
|
+
|
|
47
|
+
> "Setup paused. Run `/setup` again to resume, or
|
|
48
|
+
> `worclaude setup-state reset` to discard."
|
|
49
|
+
|
|
50
|
+
and exit. You MUST NOT write any output files on cancel.
|
|
51
|
+
|
|
52
|
+
5. **SCOPED TOOL WHITELIST.** Between SCAN ENTRY and WRITE ENTRY you
|
|
53
|
+
may invoke ONLY these tools:
|
|
54
|
+
|
|
55
|
+
- Shell: `worclaude scan --path .` (SCAN only)
|
|
56
|
+
- Shell: `worclaude setup-state show --path .`
|
|
57
|
+
- Shell: `worclaude setup-state save --stdin --path .` (pipe the
|
|
58
|
+
updated state JSON via stdin — the ONLY way state is persisted)
|
|
59
|
+
- Shell: `worclaude setup-state reset --path .`
|
|
60
|
+
- Shell: `worclaude setup-state resume-info --path .`
|
|
61
|
+
- Read: `.claude/cache/detection-report.json`
|
|
62
|
+
- Read: `.claude/cache/setup-state.json`
|
|
63
|
+
|
|
64
|
+
At WRITE state the whitelist RELAXES to additionally permit:
|
|
65
|
+
|
|
66
|
+
- Read: each of the six target output files (`CLAUDE.md`,
|
|
67
|
+
`docs/spec/SPEC.md`, three `SKILL.md` files under
|
|
68
|
+
`.claude/skills/`, `docs/spec/PROGRESS.md`). Reads are ONLY to
|
|
69
|
+
preserve user content that the merge does not overwrite. Missing
|
|
70
|
+
files are treated as empty.
|
|
71
|
+
- Read: `.claude/workflow-meta.json` for template-hash lookup.
|
|
72
|
+
- Write: exactly those six files, with merged content per the
|
|
73
|
+
per-file merge rules in the WRITE state section.
|
|
74
|
+
|
|
75
|
+
NO OTHER tool invocation is permitted — not Grep, not Glob, not
|
|
76
|
+
WebFetch, not arbitrary Bash, not reads of files outside the
|
|
77
|
+
whitelist. If you find yourself wanting another tool, you have
|
|
78
|
+
already drifted; restate the current prompt instead.
|
|
79
|
+
|
|
80
|
+
6. **NO MEMORY PRE-FILL.** Do NOT use information from previous
|
|
81
|
+
conversations, memory, or other projects. This setup is for THIS
|
|
82
|
+
project only. Only use information the user provides during THIS
|
|
83
|
+
interview and the detection report for THIS project.
|
|
84
|
+
|
|
85
|
+
7. **RENDER PROMPTS VERBATIM.** Where a state specifies a prompt format
|
|
86
|
+
with `[x] 1. ...` syntax or other structured output, render it
|
|
87
|
+
EXACTLY as specified AND wrap it in a triple-backtick fenced code
|
|
88
|
+
block so Markdown rendering does not reformat checkboxes or
|
|
89
|
+
renumber lines. The format is part of the contract with the
|
|
90
|
+
user-response parser — paraphrasing or reformatting breaks parsing.
|
|
91
|
+
You MAY add a brief conversational sentence before or after a
|
|
92
|
+
verbatim prompt, but NOT within it.
|
|
93
|
+
|
|
94
|
+
KNOWN FAILURE MODES: reformatting `[x] 1. X: Y` as `- [x] X: Y`
|
|
95
|
+
(loses numbering); paraphrasing labels; collapsing items onto one
|
|
96
|
+
line; rendering outside a fenced block (Markdown may convert `[x]`
|
|
97
|
+
to interactive checkboxes).
|
|
98
|
+
|
|
99
|
+
This rule ALSO applies to state-machine control prose. Render these
|
|
100
|
+
templates with fixed phrasing:
|
|
101
|
+
|
|
102
|
+
- Resume preamble (INTERVIEW\_\* states):
|
|
103
|
+
"Resuming `<STATE_NAME>`. Already have: `<comma-list>`.
|
|
104
|
+
Next: `<next questionId>`."
|
|
105
|
+
- Back rejection (INTERVIEW\_\* states):
|
|
106
|
+
"I can't go back within a single setup run. Finish this run and
|
|
107
|
+
edit the output files afterward."
|
|
108
|
+
- Off-topic restate prefix: exactly the text in rule #3.
|
|
109
|
+
- Cancel acknowledgment: exactly the text in rule #4.
|
|
110
|
+
|
|
111
|
+
If any rule conflicts with contextual judgment, **THE RULE WINS**. This
|
|
112
|
+
command is intentionally rigid — rigidity is the feature.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## State machine reference
|
|
117
|
+
|
|
118
|
+
| # | State | ENTRY action | EXIT condition |
|
|
119
|
+
| --- | ---------------------- | ----------------------------------------------------- | -------------------------------------------- |
|
|
120
|
+
| 0 | INIT | Precondition check, then branch to SCAN or RESUME | State loaded OR state absent/stale |
|
|
121
|
+
| 1 | SCAN | Invoke `worclaude scan --path .`, read cache file | Report loaded successfully |
|
|
122
|
+
| 2 | CONFIRM_HIGH | Render high-confidence checklist; parse response | User responds with "ok" or valid number list |
|
|
123
|
+
| 3 | CONFIRM_MEDIUM | Iterate medium-confidence items; one prompt each | All medium items resolved |
|
|
124
|
+
| 4 | INTERVIEW_STORY | Section 1 residual questions | User answered or skipped |
|
|
125
|
+
| 5 | INTERVIEW_ARCH | Section 2 residual questions | User answered or skipped |
|
|
126
|
+
| 6 | INTERVIEW_FEATURES | Section 4 conversational interview | User answered or skipped |
|
|
127
|
+
| 7 | INTERVIEW_WORKFLOW | Section 5 residual questions | User answered or skipped |
|
|
128
|
+
| 8 | INTERVIEW_CONVENTIONS | Section 6 conversational interview | User answered or skipped |
|
|
129
|
+
| 9 | INTERVIEW_VERIFICATION | Section 7 residual questions | User answered or skipped |
|
|
130
|
+
| 10 | WRITE | Merge-write the six output files from collected data | All files written (failures recorded) |
|
|
131
|
+
| 11 | DONE | Clear state file, summarize to user | — (terminal) |
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Per-state instructions
|
|
136
|
+
|
|
137
|
+
### State 0 — INIT
|
|
138
|
+
|
|
139
|
+
ENTRY:
|
|
140
|
+
|
|
141
|
+
- **Precondition check.** Verify `.claude/workflow-meta.json` exists at
|
|
142
|
+
the project root. If absent, print "This project has not been
|
|
143
|
+
scaffolded by Worclaude yet. Run `worclaude init` first, then re-run
|
|
144
|
+
`/setup`." and exit. `/setup` is a post-init command.
|
|
145
|
+
- Invoke `worclaude setup-state show --path .`.
|
|
146
|
+
- If stdout is `no state` → advance to SCAN.
|
|
147
|
+
- If the command exits non-zero (corrupt state file, unsupported
|
|
148
|
+
schema, unreadable project root): print the stderr verbatim, add
|
|
149
|
+
"The setup state file looks broken. Run
|
|
150
|
+
`worclaude setup-state reset` to discard it, then re-run `/setup`.",
|
|
151
|
+
and exit. Do NOT auto-reset.
|
|
152
|
+
- If stdout is a JSON state object:
|
|
153
|
+
- Invoke `worclaude setup-state resume-info --path .` to get the
|
|
154
|
+
pre-formatted `state: ..., age: ..., staleness: ...` line.
|
|
155
|
+
- If `staleness: stale` → prompt: "Found a setup in progress from
|
|
156
|
+
`<age>`. That's old enough I'd rather start fresh. Discard and run
|
|
157
|
+
a new setup? [yes/no]". `yes` → invoke
|
|
158
|
+
`worclaude setup-state reset`, advance to SCAN. `no` → resume at
|
|
159
|
+
the saved `currentState`.
|
|
160
|
+
- Otherwise (`fresh`) → prompt: "Found a setup in progress (state:
|
|
161
|
+
`<STATE>`, started `<age>` ago). Resume from there, or start over?
|
|
162
|
+
[resume/restart]". `resume` → jump to the saved `currentState`.
|
|
163
|
+
`restart` → invoke reset, advance to SCAN.
|
|
164
|
+
|
|
165
|
+
EXIT: SCAN (fresh/reset) or the saved `currentState` (resume).
|
|
166
|
+
Resuming begins a new invocation (rule #2).
|
|
167
|
+
|
|
168
|
+
### State 1 — SCAN
|
|
169
|
+
|
|
170
|
+
ENTRY:
|
|
171
|
+
|
|
172
|
+
- Invoke `worclaude scan --path .`.
|
|
173
|
+
- Read `.claude/cache/detection-report.json`.
|
|
174
|
+
- If the report has a non-empty `errors` array, render a one-block
|
|
175
|
+
warning verbatim:
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
The scanner ran but reported <N> detector error(s). I'll proceed
|
|
179
|
+
with what was detected; the error'd fields will be asked in the
|
|
180
|
+
interview.
|
|
181
|
+
Errors:
|
|
182
|
+
- <detector>: <kind> — <message>
|
|
183
|
+
- ...
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
- State file mutation: write a fresh state with `currentState: "SCAN"`,
|
|
187
|
+
`startedAt` and `updatedAt` set to now, `detectionReportPath:
|
|
188
|
+
".claude/cache/detection-report.json"`, empty arrays/objects for the
|
|
189
|
+
remaining fields. Persist via `worclaude setup-state save --stdin`.
|
|
190
|
+
|
|
191
|
+
EXIT: advance to CONFIRM_HIGH.
|
|
192
|
+
|
|
193
|
+
### State 2 — CONFIRM_HIGH
|
|
194
|
+
|
|
195
|
+
ENTRY:
|
|
196
|
+
|
|
197
|
+
- Read the detection report. Gather entries with
|
|
198
|
+
`confidence === "high"`.
|
|
199
|
+
- If there are zero high-confidence items: persist the state with
|
|
200
|
+
`currentState: "CONFIRM_HIGH"`, `highConfirmedAccepted: []`,
|
|
201
|
+
`highConfirmedRejected: []`, and transition to CONFIRM_MEDIUM
|
|
202
|
+
(trivial exit per rule #1).
|
|
203
|
+
- Otherwise render VERBATIM (wrapped in a triple-backtick fenced code
|
|
204
|
+
block):
|
|
205
|
+
|
|
206
|
+
```
|
|
207
|
+
I scanned your project. Please confirm the high-confidence
|
|
208
|
+
detections below. Reply with the numbers of any items that are
|
|
209
|
+
WRONG (e.g., "2, 5"), or reply "ok" to accept all.
|
|
210
|
+
|
|
211
|
+
[x] 1. <formatField(item1.field)>: <renderValue(item1)> (from <item1.source>)
|
|
212
|
+
[x] 2. ...
|
|
213
|
+
|
|
214
|
+
Your response:
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
`<formatField>` and `<renderValue>` are defined in the **Field
|
|
218
|
+
rendering table** below.
|
|
219
|
+
|
|
220
|
+
Response parsing (case-insensitive, whitespace trimmed):
|
|
221
|
+
|
|
222
|
+
- `ok` | `yes` | `all good` | `""` → accept all; set
|
|
223
|
+
`highConfirmedAccepted` to all item field names in rendered order;
|
|
224
|
+
`highConfirmedRejected: []`.
|
|
225
|
+
- One or more integers (comma or space separated) in range 1..N →
|
|
226
|
+
those items are rejected; split fields into accepted/rejected
|
|
227
|
+
accordingly (in rendered order).
|
|
228
|
+
- Anything else (including integers out of range) → rule #3 fires:
|
|
229
|
+
restate with "I need either 'ok' or numbers from 1 to `<N>` matching
|
|
230
|
+
the items above (e.g., '2, 5'). To cancel, type `cancel setup`."
|
|
231
|
+
|
|
232
|
+
State file mutation: persist the updated arrays via
|
|
233
|
+
`worclaude setup-state save --stdin`.
|
|
234
|
+
|
|
235
|
+
EXIT: advance to CONFIRM_MEDIUM.
|
|
236
|
+
|
|
237
|
+
### State 3 — CONFIRM_MEDIUM
|
|
238
|
+
|
|
239
|
+
ENTRY:
|
|
240
|
+
|
|
241
|
+
- Gather entries with `confidence === "medium"` from the detection
|
|
242
|
+
report.
|
|
243
|
+
- If there are zero medium-confidence items: persist
|
|
244
|
+
`mediumResolved: {}`, transition to INTERVIEW_STORY.
|
|
245
|
+
- Otherwise iterate in report order. For each medium item, render ONE
|
|
246
|
+
prompt VERBATIM in a fenced code block. The prompt shape depends on
|
|
247
|
+
`item.candidates`:
|
|
248
|
+
|
|
249
|
+
**Shape A — `candidates === null`** (emitted by `readme`):
|
|
250
|
+
|
|
251
|
+
```
|
|
252
|
+
<formatField(field)> (detected from <source>):
|
|
253
|
+
|
|
254
|
+
1. <renderValue(item)>
|
|
255
|
+
2. Other (I'll type my own)
|
|
256
|
+
|
|
257
|
+
Reply with the number of your choice (default: 1):
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
**Shape B — `candidates` is a non-empty array** (emitted by
|
|
261
|
+
`package-manager` when multiple lockfile groups disagree):
|
|
262
|
+
|
|
263
|
+
```
|
|
264
|
+
<formatField(field)> (detected from <source>):
|
|
265
|
+
|
|
266
|
+
1. <candidates[0]>
|
|
267
|
+
2. <candidates[1]>
|
|
268
|
+
...
|
|
269
|
+
N. <candidates[N-1]>
|
|
270
|
+
N+1. Other (I'll type my own)
|
|
271
|
+
|
|
272
|
+
Reply with the number of your choice (default: 1):
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
`candidates[0]` equals `item.value` — default-1 accepts the detected
|
|
276
|
+
value.
|
|
277
|
+
|
|
278
|
+
Response parsing (per item):
|
|
279
|
+
|
|
280
|
+
- `""` | `1` | `default` → accept item 1 (the detected value).
|
|
281
|
+
- The final "Other" number (`2` in shape A, `N+1` in shape B) →
|
|
282
|
+
follow-up free-text prompt: "Go ahead — what's the value you'd like
|
|
283
|
+
to use?". Record the trimmed reply as the answer.
|
|
284
|
+
- Integer in range `2..N` (shape B only) → accept `candidates[k-1]`.
|
|
285
|
+
- Anything else → restate with "I need a number from 1 to `<max>`, or
|
|
286
|
+
empty for the default. To cancel, type `cancel setup`."
|
|
287
|
+
|
|
288
|
+
State file mutation: after EACH item is resolved (not batched),
|
|
289
|
+
append to `mediumResolved` and persist.
|
|
290
|
+
|
|
291
|
+
EXIT: advance to INTERVIEW_STORY.
|
|
292
|
+
|
|
293
|
+
### States 4–9 — INTERVIEW\_\*
|
|
294
|
+
|
|
295
|
+
Shared ENTRY protocol for each INTERVIEW state:
|
|
296
|
+
|
|
297
|
+
- Read the state file. Determine this state's question list from the
|
|
298
|
+
**QuestionId enumeration** below plus any rejected fields routed to
|
|
299
|
+
this state from CONFIRM_HIGH (per the **Rejected-field re-ask
|
|
300
|
+
routing** table).
|
|
301
|
+
- Skip any `questionId` already present in `interviewAnswers`.
|
|
302
|
+
- Resume preamble (only if ANY questionId is already answered AND at
|
|
303
|
+
least one remains): "Resuming `<STATE_NAME>`. Already have:
|
|
304
|
+
`<comma-list>`. Next: `<next questionId>`."
|
|
305
|
+
- If ALL `questionId`s for this state are present, trivially-exit:
|
|
306
|
+
persist a state update (only `currentState` and `updatedAt` change)
|
|
307
|
+
and advance.
|
|
308
|
+
- Ask remaining questions conversationally, in enumeration order.
|
|
309
|
+
- `skip` on a question → record `interviewAnswers[<questionId>] =
|
|
310
|
+
"[skipped]"`, advance to the next question in this state.
|
|
311
|
+
- `skip all` → record every remaining `questionId` as `[skipped]`,
|
|
312
|
+
exit the state.
|
|
313
|
+
- `back` → restate the current question with the prefix "I can't go
|
|
314
|
+
back within a single setup run. Finish this run and edit the output
|
|
315
|
+
files afterward." (rule #2).
|
|
316
|
+
- Rule #3 applies within interview states: off-topic replies trigger
|
|
317
|
+
a restatement of the pending question, not an answer to the
|
|
318
|
+
off-topic question.
|
|
319
|
+
|
|
320
|
+
State file mutation: after EACH question is answered or skipped,
|
|
321
|
+
persist via `worclaude setup-state save --stdin` BEFORE rendering the
|
|
322
|
+
next prompt. Resume granularity is per-question.
|
|
323
|
+
|
|
324
|
+
EXIT: advance to the next state; INTERVIEW_VERIFICATION exits to
|
|
325
|
+
WRITE.
|
|
326
|
+
|
|
327
|
+
### State 10 — WRITE
|
|
328
|
+
|
|
329
|
+
ENTRY:
|
|
330
|
+
|
|
331
|
+
- Per rule #5's WRITE relaxation, read each of the six target files
|
|
332
|
+
(missing → empty) and read `.claude/workflow-meta.json` for template
|
|
333
|
+
hashes.
|
|
334
|
+
- Compose merged contents per the per-file merge rules below.
|
|
335
|
+
- Write each file. Per-file failure is recorded but does not abort
|
|
336
|
+
the remaining writes.
|
|
337
|
+
- State file mutation: record `writeResults: { [file]: "ok" | "error:
|
|
338
|
+
<message>" }` and persist.
|
|
339
|
+
|
|
340
|
+
Per-file merge rules:
|
|
341
|
+
|
|
342
|
+
1. **`CLAUDE.md`** — ATX-heading-scoped replace. Replace ONLY the body
|
|
343
|
+
of `## Tech Stack` and `## Commands` with generated content.
|
|
344
|
+
Preserve every other section verbatim (user additions, critical
|
|
345
|
+
rules, gotchas). If either target section is absent, append it at
|
|
346
|
+
the end.
|
|
347
|
+
2. **`docs/spec/SPEC.md`** — full rewrite if empty or template-only;
|
|
348
|
+
otherwise append a `## Additions from /setup (<ISO-date>)` section
|
|
349
|
+
at the end.
|
|
350
|
+
3. **`.claude/skills/backend-conventions/SKILL.md`** — same rule as
|
|
351
|
+
SPEC.md.
|
|
352
|
+
4. **`.claude/skills/frontend-design-system/SKILL.md`** — same rule.
|
|
353
|
+
5. **`.claude/skills/project-patterns/SKILL.md`** — same rule.
|
|
354
|
+
6. **`docs/spec/PROGRESS.md`** — never overwrite. Append a
|
|
355
|
+
`## Setup notes (<ISO-date>)` section with detected stack summary
|
|
356
|
+
and interview highlights.
|
|
357
|
+
|
|
358
|
+
**Template-hash lookup.** "Template-only" means the file's
|
|
359
|
+
CRLF-normalized SHA-256 matches the hash stored in
|
|
360
|
+
`.claude/workflow-meta.json` for that file. If the meta file is
|
|
361
|
+
missing or lacks the entry, treat the file as authored (safer
|
|
362
|
+
default: append, do not rewrite).
|
|
363
|
+
|
|
364
|
+
EXIT: advance to DONE.
|
|
365
|
+
|
|
366
|
+
### State 11 — DONE
|
|
367
|
+
|
|
368
|
+
ENTRY:
|
|
369
|
+
|
|
370
|
+
- Invoke `worclaude setup-state reset` to clear the state file.
|
|
371
|
+
- Print: "Setup complete. Wrote `<N>`/6 files. [If any errors: list
|
|
372
|
+
them.] Review what I wrote and edit anything that looks off."
|
|
373
|
+
|
|
374
|
+
EXIT: terminal.
|
|
375
|
+
|
|
376
|
+
---
|
|
377
|
+
|
|
378
|
+
## QuestionId enumeration (load-bearing contract)
|
|
379
|
+
|
|
380
|
+
These IDs are the keys for `interviewAnswers`. `saveSetupState`
|
|
381
|
+
rejects keys outside this set (with the `<state>.unchecked.<field>`
|
|
382
|
+
prefix exception — see routing table).
|
|
383
|
+
|
|
384
|
+
**INTERVIEW_STORY** (section 1; residual after README + spec-docs
|
|
385
|
+
detection):
|
|
386
|
+
|
|
387
|
+
- `story.audience` — "Who is it for?"
|
|
388
|
+
- `story.problem` — "What problem does it solve?"
|
|
389
|
+
- `story.analogs` — "Any similar product you're modeling after?"
|
|
390
|
+
|
|
391
|
+
**INTERVIEW_ARCH** (section 2; `monorepo` detector flags presence
|
|
392
|
+
only):
|
|
393
|
+
|
|
394
|
+
- `arch.classification` — monolith / microservices / monorepo /
|
|
395
|
+
serverless
|
|
396
|
+
- `arch.modules` — directory/module purposes. Prompt the user to
|
|
397
|
+
mention in-house libraries and private-registry packages here.
|
|
398
|
+
- `arch.entities` — database entities (detector knows the ORM;
|
|
399
|
+
entities are user knowledge).
|
|
400
|
+
- `arch.external_apis` — external APIs beyond SDK detection.
|
|
401
|
+
- `arch.stack_rationale` — WHY the detected framework/stack choices
|
|
402
|
+
were made.
|
|
403
|
+
|
|
404
|
+
**INTERVIEW_FEATURES** (section 4; detection ~10%):
|
|
405
|
+
|
|
406
|
+
- `features.core` — list of core features.
|
|
407
|
+
- `features.nice_to_have` — nice-to-have features.
|
|
408
|
+
- `features.non_goals` — explicit non-goals.
|
|
409
|
+
|
|
410
|
+
**INTERVIEW_WORKFLOW** (section 5; residual after scripts,
|
|
411
|
+
env-variables, ci detection):
|
|
412
|
+
|
|
413
|
+
- `workflow.new_dev_steps` — setup steps beyond README.
|
|
414
|
+
- `workflow.env_values` — guidance for env variable values (detector
|
|
415
|
+
has names only, not values).
|
|
416
|
+
|
|
417
|
+
**INTERVIEW_CONVENTIONS** (section 6; detection ~21%):
|
|
418
|
+
|
|
419
|
+
- `conventions.patterns` — code patterns the project uses.
|
|
420
|
+
- `conventions.errors` — error handling approach.
|
|
421
|
+
- `conventions.logging` — logging approach.
|
|
422
|
+
- `conventions.api_format` — API response format.
|
|
423
|
+
- `conventions.naming` — naming conventions.
|
|
424
|
+
- `conventions.rules` — never/always rules.
|
|
425
|
+
|
|
426
|
+
**INTERVIEW_VERIFICATION** (section 7; residual after testing + ci
|
|
427
|
+
detection):
|
|
428
|
+
|
|
429
|
+
- `verification.manual` — manual verification steps.
|
|
430
|
+
- `verification.staging` — staging/preview environment.
|
|
431
|
+
- `verification.required_checks` — CI required checks.
|
|
432
|
+
|
|
433
|
+
### Rejected-field re-ask routing
|
|
434
|
+
|
|
435
|
+
Fields in `highConfirmedRejected` are re-asked as one sub-question
|
|
436
|
+
each in the INTERVIEW state that matches the field's natural section.
|
|
437
|
+
|
|
438
|
+
| Rejected field | Re-asked in | Answer key |
|
|
439
|
+
| ------------------------------------ | ---------------------- | -------------------------------- |
|
|
440
|
+
| `readme`, `specDocs` | INTERVIEW_STORY | `story.unchecked.<field>` |
|
|
441
|
+
| `packageManager`, `language` | INTERVIEW_ARCH | `arch.unchecked.<field>` |
|
|
442
|
+
| `frameworks`, `orm`, `monorepo` | INTERVIEW_ARCH | `arch.unchecked.<field>` |
|
|
443
|
+
| `deployment`, `externalApis` | INTERVIEW_ARCH | `arch.unchecked.<field>` |
|
|
444
|
+
| `scripts`, `envVariables`, `linting` | INTERVIEW_WORKFLOW | `workflow.unchecked.<field>` |
|
|
445
|
+
| `ci` | INTERVIEW_WORKFLOW | `workflow.unchecked.<field>` |
|
|
446
|
+
| `testing` | INTERVIEW_VERIFICATION | `verification.unchecked.<field>` |
|
|
447
|
+
|
|
448
|
+
`<state>.unchecked.<field>` keys are the ONLY keys outside the
|
|
449
|
+
enumeration that `saveSetupState` accepts, matched by prefix. The
|
|
450
|
+
`<field>` segment must exactly match a known detector field name AND
|
|
451
|
+
the routing table must map that field to that state prefix.
|
|
452
|
+
|
|
453
|
+
---
|
|
454
|
+
|
|
455
|
+
## Field rendering table
|
|
456
|
+
|
|
457
|
+
Reproduced from the scanner's `summarizeValue` semantics. Used in
|
|
458
|
+
CONFIRM_HIGH and CONFIRM_MEDIUM to render `<renderValue(item)>`.
|
|
459
|
+
|
|
460
|
+
| `field` | `item.value` shape | Rendered as |
|
|
461
|
+
| ---------------- | ---------------------------------------------- | -------------------------------------------------------------------- |
|
|
462
|
+
| `packageManager` | string | `<value>` (shape-B medium → render `candidates` one per line) |
|
|
463
|
+
| `language` | string | `<value>` |
|
|
464
|
+
| `frameworks` | `[{name, version}, ...]` | `Name Version, Name Version` joined by `, ` (missing version → just `Name`) |
|
|
465
|
+
| `testing` | `{framework, configFile, ...}` | `<framework> (<configFile>)` — if `configFile` null: `<framework>` |
|
|
466
|
+
| `linting` | `string[]` | joined by `, ` (empty → omit this item) |
|
|
467
|
+
| `orm` | `{name, schemaFile}` | `<name>` |
|
|
468
|
+
| `deployment` | string | `<value>` |
|
|
469
|
+
| `ci` | `{provider, workflows: string[]}` | `<provider>, <N> workflow(s)` (singular when `N === 1`) |
|
|
470
|
+
| `scripts` | `{dev, test, build, lint, ...}` | `dev=<dev.key> test=<test.key> build=<build.key> lint=<lint.key>` — omit null slots; all null → `(no standard scripts)` |
|
|
471
|
+
| `envVariables` | `{names: string[], inferredServices: [...]}` | `<N> variable(s)` (singular when `N === 1`; 0 → omit) |
|
|
472
|
+
| `externalApis` | `string[]` | joined by `, ` (empty → omit) |
|
|
473
|
+
| `readme` | `{projectDescription, ...}` | `<projectDescription>` truncated to 80 chars with `…` suffix |
|
|
474
|
+
| `specDocs` | `[{path, firstHeading}, ...]` | `<N> doc(s)` (empty → omit) |
|
|
475
|
+
| `monorepo` | `{tool, packagePaths, ...}` | `<tool> (<N> packages)` |
|
|
476
|
+
| fallback scalar | string / number / boolean | `String(value)` |
|
|
477
|
+
|
|
478
|
+
`formatField(field)` inserts a space before each uppercase letter and
|
|
479
|
+
capitalizes the first character — every word ends up Title-Cased:
|
|
480
|
+
`packageManager` → `Package Manager`, `envVariables` →
|
|
481
|
+
`Env Variables`, `externalApis` → `External Apis`, `specDocs` →
|
|
482
|
+
`Spec Docs`. Render exactly what `formatField` produces — do not
|
|
483
|
+
retitle `External Apis` as `External APIs` or similar; the parser
|
|
484
|
+
matches the scanner's output, not natural-language acronym casing.
|
|
485
|
+
|
|
486
|
+
---
|
|
487
|
+
|
|
488
|
+
## WRITE composition (which state data flows to which file)
|
|
489
|
+
|
|
490
|
+
For each target file, compose content from detection + `mediumResolved` +
|
|
491
|
+
`interviewAnswers` per this mapping:
|
|
492
|
+
|
|
493
|
+
- **`CLAUDE.md`** Tech Stack ← `packageManager`, `language`,
|
|
494
|
+
`frameworks`, `orm`, `testing`, `linting`. Commands ← `scripts` +
|
|
495
|
+
`workflow.unchecked.scripts`.
|
|
496
|
+
- **`docs/spec/SPEC.md`** ← Overview (`story.*`); Architecture
|
|
497
|
+
(`arch.*`, `frameworks`, `monorepo`, `deployment`); Features
|
|
498
|
+
(`features.*`); Workflow (`workflow.*`, `scripts`, `ci`,
|
|
499
|
+
`envVariables`); Conventions (`conventions.*`); Verification
|
|
500
|
+
(`verification.*`, `testing`, `ci`).
|
|
501
|
+
- **`backend-conventions/SKILL.md`** ← `conventions.errors`,
|
|
502
|
+
`conventions.logging`, `conventions.api_format`, `orm`,
|
|
503
|
+
`externalApis`.
|
|
504
|
+
- **`frontend-design-system/SKILL.md`** ← detected frontend
|
|
505
|
+
frameworks (`react`, `vue`, `svelte`, `next`, `nuxt` — if present in
|
|
506
|
+
`frameworks`) + design-system residuals from interview answers.
|
|
507
|
+
- **`project-patterns/SKILL.md`** ← `conventions.patterns`,
|
|
508
|
+
`conventions.naming`, `conventions.rules`, `arch.classification`,
|
|
509
|
+
`arch.modules`.
|
|
510
|
+
- **`docs/spec/PROGRESS.md`** ← `## Setup notes (<ISO-date>)`
|
|
511
|
+
appended; detected stack summary + interview highlights.
|
|
512
|
+
|
|
513
|
+
---
|
|
117
514
|
|
|
118
515
|
## Trigger Phrases
|
|
516
|
+
|
|
119
517
|
- "set up the project"
|
|
120
518
|
- "configure this project"
|
|
121
519
|
- "project interview"
|
|
520
|
+
- "run setup"
|