worclaude 2.7.0 → 2.7.1

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 CHANGED
@@ -4,6 +4,24 @@ All notable changes to worclaude are documented in this file. Format loosely fol
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [2.7.1] — 2026-04-24
8
+
9
+ 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.
10
+
11
+ ### Fixed
12
+
13
+ - **`/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 `?`.
14
+ - **`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.
15
+
16
+ ### Changed
17
+
18
+ - **`/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.
19
+
20
+ ### Docs
21
+
22
+ - **`docs/spec/SPEC.md` `/setup` section** (this /sync) — reflects the `help`-keyword-only trigger and the CONFIRM_MEDIUM ≤4-option AskUserQuestion path.
23
+ - **`docs/spec/PROGRESS.md`** (this /sync) — new v2.7.1 release entry; Stats refreshed (782 → 788 tests).
24
+
7
25
  ## [2.7.0] — 2026-04-23
8
26
 
9
27
  `/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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "worclaude",
3
- "version": "2.7.0",
3
+ "version": "2.7.1",
4
4
  "description": "The Workflow Layer for Claude Code — scaffold agents, commands, skills, hooks, and memory into any project",
5
5
  "type": "module",
6
6
  "bin": {
@@ -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: 'confirm',
80
+ type: 'list',
81
81
  name: 'generatePluginJson',
82
82
  message: 'Generate .claude-plugin/plugin.json for marketplace compatibility?',
83
- default: selections.generatePluginJson || false,
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: 'confirm',
90
+ type: 'list',
87
91
  name: 'scaffoldGtdMemory',
88
92
  message: 'Scaffold structured memory files (decisions.md, preferences.md)?',
89
- default: selections.scaffoldGtdMemory || false,
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 };
@@ -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` (INTERVIEW states only, per the
69
- Interaction mode contract `selectable` / `multi-selectable`
70
- questions). Not permitted at CONFIRM_HIGH / CONFIRM_MEDIUM:
71
- those render VERBATIM per rule #7 so the text-parser contract
72
- stays stable.
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 prompt format
96
- with `[x] 1. ...` syntax or other structured output, render it
97
- EXACTLY as specified AND wrap it in a triple-backtick fenced code
98
- block so Markdown rendering does not reformat checkboxes or
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 "?" for help.
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
- - `?` | `help` → render the **Field-help** block for EACH displayed
261
- field (description + target + example) without advancing state. Then
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 `?` for help. To cancel, type
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, render ONE
284
- prompt VERBATIM in a fenced code block. The prompt shape depends on
285
- `item.candidates`:
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
- **Shape A — `candidates === null`** (emitted by `readme`):
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
- **Shape B — `candidates` is a non-empty array** (emitted by
300
- `package-manager` when multiple lockfile groups disagree):
353
+ 1. <renderValue(item)>
354
+ Will be saved as: <target>
355
+ 2. Other (I'll type my own)
301
356
 
302
- ```
303
- <formatField(field)> (detected from <source>):
304
- → Will be saved as: <target>
357
+ Reply with the number of your choice (default: 1), or type `help`:
358
+ ```
305
359
 
306
- 1. <candidates[0]>
307
- 2. <candidates[1]>
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
- Reply with the number of your choice (default: 1), or `?` for help:
313
- ```
364
+ ```
365
+ <formatField(field)> (detected from <source>):
366
+ → Will be saved as: <target>
314
367
 
315
- `<target>` comes from the **Field-help table** below. Render it
316
- verbatim per the table.
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
- `candidates[0]` equals `item.value` default-1 accepts the detected
319
- value.
374
+ Reply with the number of your choice (default: 1), or type `help`:
375
+ ```
320
376
 
321
- **Storage rule:** `mediumResolved[field]` MUST be a string. Store the
322
- exact `renderValue(item)` that was shown to the user on option 1, or
323
- the user's trimmed free-text on "Other", or `candidates[k-1]` (shape
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 (per item):
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 above.
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
- - `?` | `help` → render the **Field-help** block for this field
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 `?` for help. To cancel, type
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 `?` / `help` command (CONFIRM_HIGH, CONFIRM_MEDIUM, and
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 `?` at a CONFIRM or INTERVIEW
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
  ```