wize-dev-kit 0.2.0 → 0.2.5

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
@@ -5,6 +5,91 @@ Format inspired by [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [0.2.5] — 2026-06-12
9
+
10
+ Fixes a real install-time bug that bit non-TTY users (CI smoke + anyone piping input into `wize-dev-kit install`).
11
+
12
+ ### Fixed
13
+
14
+ - **Non-TTY prompt stall.** The CLI's `prompt()` helper created a new `readline.createInterface` per call and used `rl.question()`. Both choices misbehave in pipe mode: per-call interfaces close stdin on the first `rl.close()`, and even with a shared interface `readline.question` stalls when it has to read an empty line in non-TTY mode (Node 24 behavior). After step 1 of `install` (project name), every subsequent prompt would hang silently. Replaced with an event-based line reader: subscribe once to `line`, push waiters in order, propagate empty lines as `""`, treat EOF as "remaining waiters resolve empty". `printf '...\n\n\n\n\nName\n\n' | wize-dev-kit install` now runs cleanly to completion.
15
+
16
+ ### Notes
17
+
18
+ This was the actual cause behind the CI smoke E2E loop. The 0.2.4 fix to the smoke script (using `npm install <tarball>` instead of `npx <tarball>`) was correct, but the underlying CLI couldn't accept piped input either, so the smoke kept failing at the second prompt. With both fixed, the smoke runs end-to-end.
19
+
20
+ ## [0.2.4] — 2026-06-12
21
+
22
+ CI-only hotfix to actually unblock the publish pipeline. Surface area of wize-dev-kit unchanged.
23
+
24
+ ### Fixed
25
+
26
+ - Smoke E2E step used `npx --yes "$tarball" install`. On the GitHub Actions runner that path is interpreted as a shell command, which tries to **execute the tarball directly** before npx ever extracts it — exit code 126, `Permission denied`. Rewrote the step to: install the tarball into a throwaway project via `npm install <tarball>`, then invoke `$NODE_MODULES/.bin/wize-dev-kit` directly. `npm install` extracts the archive properly and sets the bin executable bit, so the rest of the smoke (`install` → assertions → `update` → `agent list`) runs cleanly. Same coverage, named-per-check error messages, and now also sets `WIZE_DISABLE_UPDATE_CHECK=1` so the registry isn't probed mid-smoke.
27
+
28
+ ## [0.2.3] — 2026-06-11
29
+
30
+ Hotfix: 0.2.1 and 0.2.2 publish workflows hung because `test/version-check.test.js` had a sync/async bug in its test scaffolding. CI's smoke E2E never started for those releases. This release fixes the test and re-runs the same smoke for 0.2.2 + 0.2.3.
31
+
32
+ ### Fixed
33
+
34
+ - `withTempCacheHome` helper in `test/version-check.test.js` was synchronous (`return fn(dir)`), so its `finally` block restored the env var before the async callback's `writeCache` resolved. The cache lookup inside the callback then landed in the real `~/.cache/wize-dev-kit/`, contaminating subsequent test runs and intermittently failing the `getLatestVersion returns the cached value when fresh` assertion. Fix: make the helper `async` and `return await fn(dir)`. Confirmed locally + ensures CI doesn't get a stuck cache file across tags.
35
+
36
+ ### Notes
37
+
38
+ No surface area changed; behavior of `wize-dev-kit` itself is identical to 0.2.2. The bump exists only so the publish workflow re-runs cleanly.
39
+
40
+ ## [0.2.2] — 2026-06-11
41
+
42
+ Closes the "documentation always stale" gap: inline knowledge captures per story, Hawkeye enforces, sprint-end refresh consolidates. Plus auto-update nudges on the CLI and Wizer.
43
+
44
+ ### Added — knowledge stays current
45
+
46
+ - **`wize-dev-story` step 8 — Knowledge update (inline).** After commits and before pre-PR check, Shuri checks whether the story touched any of the 5 baseline axes (architecture / conventions / risk-spots / dependencies / overview) and, if yes, adds 1–3 dated bullets to the matching `.wize/knowledge/document-project/*.md` file — same PR. ~60 seconds when applicable; skipped otherwise.
47
+ - **`wize-quick-dev` step 5 — Knowledge update (only if applicable).** Quick-dev rarely touches axes; when it does (dep bump that shifts API, rename that breaks a contract), one line lands in the relevant doc.
48
+ - **`wize-tea-review` step 5 — Knowledge update check.** Hawkeye walks the diff. Touched-but-not-updated stories get a `KN-NN` finding. `tea-review` frontmatter now carries `knowledge_axes_touched` + `knowledge_axes_updated`.
49
+ - **`wize-tea-gate` decision rule extended.** When `knowledge_axes_touched ≠ knowledge_axes_updated`, recommendation flips to `CONCERNS` (advisory) or `FAIL` (enforcing). Example `KN-NN` finding shape documented in the canonical YAML.
50
+ - **`wize-refresh-knowledge` (new workflow).** Sprint-end consolidation: Pepper + Peggy roll the dated bullets accumulated through the sprint into the narrative prose of each axis file, demote stale claims to a `Deprecated` section, freeze a snapshot at `.wize/knowledge/document-project/_history/{YYYY-Qn}/sprint-{N}.md`, and stamp `last_refreshed` in each file. Triggered when `wize-help next` detects the sprint emptied.
51
+ - **`wize-document-project` — Update mode section.** Documents the two-cadence loop (inline-per-story + sprint-refresh) and the file frontmatter convention (`last_refreshed`).
52
+
53
+ ### Added — proactive nudges
54
+
55
+ - **`wize-help` skill — version-skew detection.** Wizer now reads `kit_version` from `.wize/config/project.toml`, compares with the installed package version and (via Bash tool when available) the registry, and proactively suggests `npx wize-dev-kit@latest update` when behind. Worded as a single short line, never as a banner.
56
+ - **`wize-help` skill — sprint-end detection.** Heuristic refined: when sprint-status shows all stories gated and no `ready-for-dev` left, the next-step recommendation is `wize-retrospective` + `wize-refresh-knowledge`, not just retro.
57
+ - **CLI version check (camera 1).** `wize-dev-kit list / sync / agent / workflow / help` now print a one-line `↑ Update available: X → Y` at the top when a newer version sits in the npm registry. Cached for 1 hour, 1.5s network timeout, silent on offline / non-TTY / `WIZE_DISABLE_UPDATE_CHECK=1`. Never blocks. New module `tools/installer/version-check.js`.
58
+
59
+ ### Tests
60
+
61
+ - Total: **104 passing** (was 94 in 0.2.1).
62
+ - 10 new tests in `test/version-check.test.js` covering semver compare, cache freshness, fetch fallback (offline + non-2xx), TTY guard, env disable.
63
+
64
+ ### Files
65
+
66
+ - `src/method-skills/1-analysis/wize-refresh-knowledge/workflow.md` (new).
67
+ - `tools/installer/version-check.js` (new).
68
+ - Edits to `wize-dev-story`, `wize-quick-dev`, `wize-tea-review`, `wize-tea-gate`, `wize-help` skill, `wize-document-project`, `tools/installer/wize-cli.js`.
69
+
70
+ ## [0.2.1] — 2026-06-11
71
+
72
+ Focused polish: brownfield baseline finally runs end-to-end through a detected harness CLI, CI publishes without the deprecated-config warning, and every release is now smoke-tested before going up.
73
+
74
+ ### Added
75
+
76
+ - **Brownfield baseline runs real now.** When the installer detects existing code and you accept the `Run wize-document-project?` prompt, it now scans your PATH for an AI harness CLI (Claude Code, then Codex, then OpenCode), prioritizes whichever you selected as an IDE target, asks you to confirm the headless invocation, and spawns it with the right flags (`claude -p`, `codex exec`, `opencode run`). If no harness CLI is on PATH, the installer prints the exact command you can run later in your IDE. Set `WIZE_SKIP_BASELINE=1` to disable the headless run entirely (used by CI and unattended setups).
77
+ - `tools/installer/baseline.js` — exports `detectHarnessCli`, `runHeadlessBaseline`, `manualInstructions`, `defaultPrompt`. Self-contained, no extra deps; uses a manual PATH walk for hermetic, cross-platform detection.
78
+ - 7 new unit tests covering detection priority, PATH isolation, the skip-baseline env, and instruction strings.
79
+
80
+ ### Fixed
81
+
82
+ - CI publish workflow now strips the deprecated `always-auth=false` line from the runner's `.npmrc` before installing. Removes the `npm warn Unknown user config "always-auth"` noise that appeared in every 0.2.0 publish log. See actions/setup-node#1129.
83
+
84
+ ### Added — CI
85
+
86
+ - **Smoke E2E before publish.** The workflow now packs the tarball, installs it in a temp git repo via `npx`, and asserts that `.wize/`, the Claude adapter SKILL.md, generic AGENTS-equivalent, `kit_version` in `project.toml`, `update`, and `agent list` all work — exactly like a user would experience. Fails the release if anything is off, so we never publish a broken tarball again.
87
+ - Sets `WIZE_SKIP_BASELINE=1` in the smoke step so the harness-run prompt doesn't try to spawn `claude` inside GitHub's runner.
88
+
89
+ ### Tests
90
+
91
+ - Total now **94 passing** (was 87 in 0.2.0).
92
+
8
93
  ## [0.2.0] — 2026-06-11
9
94
 
10
95
  First release that delivers the lifecycle end-to-end. Workflows have real bodies; CLI commands work for real; the team has a Walkthrough to follow.
@@ -177,7 +262,12 @@ Ignore (handled by the suggested block): `.wize/config/user.toml`, `.wize/scratc
177
262
  - Inspired by [BMAD Method v6.8.0](https://github.com/bmad-code-org/BMAD-METHOD).
178
263
  - WDS module inspired by [bmad-method-wds-expansion](https://github.com/bmad-code-org/bmad-method-wds-expansion).
179
264
 
180
- [Unreleased]: https://github.com/qwize-br/wize-development-kit/compare/v0.2.0...HEAD
265
+ [Unreleased]: https://github.com/qwize-br/wize-development-kit/compare/v0.2.5...HEAD
266
+ [0.2.5]: https://github.com/qwize-br/wize-development-kit/compare/v0.2.4...v0.2.5
267
+ [0.2.4]: https://github.com/qwize-br/wize-development-kit/compare/v0.2.3...v0.2.4
268
+ [0.2.3]: https://github.com/qwize-br/wize-development-kit/compare/v0.2.2...v0.2.3
269
+ [0.2.2]: https://github.com/qwize-br/wize-development-kit/compare/v0.2.1...v0.2.2
270
+ [0.2.1]: https://github.com/qwize-br/wize-development-kit/compare/v0.2.0...v0.2.1
181
271
  [0.2.0]: https://github.com/qwize-br/wize-development-kit/compare/v0.1.5...v0.2.0
182
272
  [0.1.5]: https://github.com/qwize-br/wize-development-kit/compare/v0.1.4...v0.1.5
183
273
  [0.1.4]: https://github.com/qwize-br/wize-development-kit/compare/v0.1.3...v0.1.4
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "wize-dev-kit",
4
- "version": "0.2.0",
4
+ "version": "0.2.5",
5
5
  "description": "Full-lifecycle AI-assisted development kit with Test Architect and Whiteport Design Studio embedded. Inspired by BMAD Method and WDS.",
6
6
  "keywords": [
7
7
  "ai",
@@ -150,6 +150,46 @@ Co-located with the file under test. `.spec.ts` for unit; `.e2e.ts` for end-to-e
150
150
  - Some files use `_test.ts` suffix instead of `.spec.ts` — older code.
151
151
  ```
152
152
 
153
+ ## Update mode (how the baseline stays alive)
154
+
155
+ The first run of this workflow produces the **baseline**. Two complementary mechanisms keep it current after:
156
+
157
+ ### 1. Inline updates per story (the daily cadence)
158
+
159
+ Every `wize-dev-story` ends with a Knowledge Update step (step 8). If the story touched any of the 5 axes (architecture, conventions, risk-spots, dependencies, overview), Shuri appends 1–3 dated bullets to the matching `document-project/*.md` file **in the same PR**. Hawkeye verifies in `tea-review`; a touched-but-not-updated story gets a `KN-NN` finding at gate.
160
+
161
+ `wize-quick-dev` has a lighter version: only when a dep bump or a public rename actually shifts the baseline.
162
+
163
+ This produces dated bullets like:
164
+
165
+ ```markdown
166
+ ## 2026-06-12 — E01-S03
167
+ - Conventions: `data-testid="invite-*"` published as public contract.
168
+ - Risk: R-1 (mailer) mitigation confirmed.
169
+ ```
170
+
171
+ ### 2. Sprint-end refresh (the narrative cadence)
172
+
173
+ `wize-refresh-knowledge` runs at sprint end (triggered by `wize-help next` when it detects the sprint emptied). Pepper + Peggy consolidate the inline bullets into the narrative prose of each axis file, demote stale claims to a "Deprecated" section, freeze a sprint snapshot in `_history/{YYYY-Qn}/sprint-{N}.md`, and stamp `last_refreshed` in each file.
174
+
175
+ Result: the baseline reads like a single coherent document, not a chronological log. New devs can read it linearly and form a mental model. Forensics readers (six months later, asking "when did X change?") consult `_history/`.
176
+
177
+ ### File frontmatter convention
178
+
179
+ Each `document-project/*.md` file ships with:
180
+
181
+ ```yaml
182
+ ---
183
+ status: baseline
184
+ owner: Pepper Potts + Peggy Carter
185
+ created: 2026-04-02
186
+ last_refreshed: 2026-06-25
187
+ sampled: "wkly + sprint refresh"
188
+ ---
189
+ ```
190
+
191
+ `last_refreshed` tells the reader how much to trust the file vs the inline bullets accumulating since.
192
+
153
193
  ## Anti-patterns Pepper rejects
154
194
 
155
195
  - "TODO: document later." The baseline IS the documentation pass; later doesn't come.
@@ -157,6 +197,7 @@ Co-located with the file under test. `.spec.ts` for unit; `.e2e.ts` for end-to-e
157
197
  - Architecture diagrams that show what the team *wishes* exists. Diagram the real state.
158
198
  - Risk-spot table with no confidence label. Without confidence, readers can't act.
159
199
  - Open questions with no owner. They never get answered.
200
+ - Treating the baseline as one-shot. The mode + refresh exist precisely because point-in-time docs lie within weeks.
160
201
 
161
202
  ## Hand-off
162
203
 
@@ -0,0 +1,127 @@
1
+ ---
2
+ code: wize-refresh-knowledge
3
+ name: Refresh Project Knowledge
4
+ phase: 1-analysis
5
+ owner: wize-agent-analyst # Pepper (drives), with Peggy on prose
6
+ status: ready
7
+ ---
8
+
9
+ # Refresh Project Knowledge
10
+
11
+ **Goal.** Consolidate the dated bullets added to `document-project/*.md` over the sprint (via `wize-dev-story` step 8 and `wize-quick-dev` step 5) into a coherent, narrated, current-state baseline. Keep what's still true; demote what's outdated; archive what's no longer relevant.
12
+
13
+ This is the workflow that **keeps `document-project` honest over months**, instead of letting it stale within a sprint.
14
+
15
+ Pepper drives the consolidation. Peggy edits prose. Tony reviews architecture-snapshot changes. Hawkeye reviews risk-spots changes.
16
+
17
+ ## When to run
18
+
19
+ - **End of sprint** (default cadence). `wize-help next` suggests it when it detects the sprint ended.
20
+ - **After a major epic ships.** Architecture often shifts visibly; this is the moment to consolidate.
21
+ - **Before onboarding a new engineer.** The baseline is the first thing they read; keep it fresh.
22
+ - **Before an audit / external review.** Same.
23
+
24
+ Don't run after every story — that's why each story already does its own inline update. This is the *periodic narration pass*.
25
+
26
+ ## Inputs
27
+
28
+ - `.wize/knowledge/document-project/{overview,architecture-snapshot,conventions,dependencies,risk-spots,open-questions}.md`
29
+ - `.wize/implementation/tea/**/gate.md` from this sprint (look for `KN-NN` findings — they flag where the baseline got out of sync).
30
+ - Git log of the sprint window (`git log --since="<sprint-start>" --until="<sprint-end>"`).
31
+ - `.wize/implementation/sprint-status.md` (latest sprint block).
32
+
33
+ ## Outputs
34
+
35
+ - Updated `.wize/knowledge/document-project/*.md` (in place).
36
+ - `.wize/knowledge/document-project/_history/{YYYY-Qn}/{sprint-N}.md` — sprint-scoped snapshot (frozen).
37
+ - Optional new entries appended to `open-questions.md`.
38
+
39
+ ## Steps
40
+
41
+ ### 1. Collect the inline notes
42
+
43
+ For each of the 5 axes, list every dated bullet added since the previous refresh (or since the baseline was created). They look like:
44
+
45
+ ```
46
+ ## 2026-06-12 — E01-S03
47
+ - Conventions: `data-testid="invite-*"` published as public contract.
48
+ - Risk: R-1 (mailer) mitigation confirmed.
49
+ ```
50
+
51
+ Pepper extracts them by axis.
52
+
53
+ ### 2. Narrate, don't list
54
+
55
+ For each axis, write a short paragraph that **integrates** the new bullets into the surrounding context. The bullets disappear; the prose grows. Each axis remains a single coherent file — not a chronological log.
56
+
57
+ Example for `conventions.md` before refresh:
58
+
59
+ ```markdown
60
+ ## Tests
61
+ Co-located with the file under test. `.spec.ts` for unit; `.e2e.ts` for end-to-end.
62
+ ```
63
+
64
+ After refresh integrating an inline note "data-testid='invite-*' is a public contract":
65
+
66
+ ```markdown
67
+ ## Tests
68
+ Co-located with the file under test. `.spec.ts` for unit; `.e2e.ts` for end-to-end. Test IDs follow the `data-testid="{feature}-{element}"` convention and are treated as a **public contract** — renaming one is a breaking change for end-to-end tests; ping Hawkeye before changing.
69
+ ```
70
+
71
+ ### 3. Demote what's outdated
72
+
73
+ If a previous claim no longer holds (a service was retired, a convention was replaced), don't delete silently. Move it to a "Deprecated" section at the bottom of the file with the date it was replaced and the new pattern. Future readers need the breadcrumb.
74
+
75
+ ### 4. Archive a sprint snapshot
76
+
77
+ Freeze the *current* state into `_history/{YYYY-Qn}/sprint-{N}.md`. This file is read-only after creation. Six months from now, when someone asks "when did we change the test-id convention?", the answer is in `_history/`.
78
+
79
+ ### 5. Open questions sweep
80
+
81
+ Pull any `KN-NN` findings that weren't resolved (the gap was acknowledged but the doc still wasn't updated) and copy them as `open-questions.md` entries with owners.
82
+
83
+ ### 6. Diff narrative
84
+
85
+ Append a one-paragraph summary to the bottom of each updated file:
86
+
87
+ ```markdown
88
+ ## Last refresh: 2026-06-25 (Sprint 7)
89
+ - Architecture: 2 new components documented (`<InviteForm>`, `<TeamList>`); ADR-008 anchored in the auth section.
90
+ - Conventions: test-id public contract documented; eslint plugin added (commit 7a3d2f).
91
+ - Risk-spots: R-1 (mailer) closed; R-7 (rate limiter) added.
92
+ - Dependencies: bumped zod, drizzle, expo (notes in dependencies.md).
93
+ - Overview: unchanged; no new top-level feature in this sprint.
94
+ ```
95
+
96
+ ### 7. Hand off
97
+
98
+ - All updated docs flip frontmatter `last_refreshed: YYYY-MM-DD`.
99
+ - Wizer announces in `sprint-status.md`: *"Knowledge refresh done; baseline current."*
100
+ - Maria Hill carries this into the retrospective: was the refresh smooth, or did the team accumulate too many KN findings?
101
+
102
+ ## Frontmatter convention for `document-project/*.md`
103
+
104
+ Each baseline file ships with:
105
+
106
+ ```yaml
107
+ ---
108
+ status: baseline
109
+ owner: Pepper + Peggy
110
+ created: 2026-04-02
111
+ last_refreshed: 2026-06-25
112
+ sampled: "wkly + sprint refresh"
113
+ ---
114
+ ```
115
+
116
+ `last_refreshed` tells the next reader how much to trust the file vs read the more recent inline notes from `_history/`.
117
+
118
+ ## Anti-patterns Pepper rejects
119
+
120
+ - **Refreshing into a chronological log.** That defeats narration; if a new dev opens `conventions.md` and sees 47 dated bullets, they can't form a mental model. Narrate.
121
+ - **Refresh without reading the gate findings.** `KN-NN` findings are exactly the gaps you should be patching here; ignoring them recreates the original problem.
122
+ - **Refresh every sprint regardless of activity.** If the sprint touched zero axes (rare but possible — a sprint of pure UI polish), say so in the diff narrative and skip the bulk of the work.
123
+ - **Demotion without breadcrumb.** Future readers need the trail.
124
+
125
+ ## Hand-off
126
+
127
+ > Knowledge refresh for Sprint 7 done. Baseline current; 1 historical snapshot frozen at `_history/2026-Q2/sprint-7.md`. KN-01 closed, KN-03 still open (deferred to S8 — assigned to Aaliyah).
@@ -81,7 +81,31 @@ feat(invite): validate email per AC-02-1 / AC-02-2
81
81
 
82
82
  Until every AC has at least one test + minimum code that makes it pass.
83
83
 
84
- ### 8. Pre-PR self-check
84
+ ### 8. Knowledge update (inline, ~60s)
85
+
86
+ Before opening the PR, ask: **did this story touch any of the 5 baseline axes** documented in `.wize/knowledge/document-project/`?
87
+
88
+ | Axis | Touched when… | File to update |
89
+ |---|---|---|
90
+ | **Architecture** | new component, new sequence, changed data flow | `architecture-snapshot.md` |
91
+ | **Conventions** | new naming/folder/test pattern published as public contract (incl. `testid`) | `conventions.md` |
92
+ | **Risk-spots** | introduced a complexity hot spot OR resolved one | `risk-spots.md` |
93
+ | **Dependencies** | added / removed / upgraded a runtime dep | `dependencies.md` |
94
+ | **Overview** | new user-visible feature a new dev should know about | `overview.md` |
95
+
96
+ If yes for any axis: open the file and add **1–3 lines** under a new dated bullet — in the same PR.
97
+
98
+ ```markdown
99
+ ## 2026-06-12 — E01-S03
100
+ - Conventions: `data-testid="invite-*"` published as public contract; Hawkeye E2E depends on these.
101
+ - Risk: R-1 (mailer) mitigation now confirmed (integration test covers retry policy).
102
+ ```
103
+
104
+ If no axis was touched, you skip this step entirely — quick-dev-style changes don't need it. Hawkeye will check whether the call was correct in `tea-review`. A story that touched an axis but skipped the update gets a `KN-NN` finding in the gate (recommendation `CONCERNS` advisory, or `FAIL` enforcing).
105
+
106
+ This is how the brownfield baseline stays alive instead of going stale 6 months in.
107
+
108
+ ### 9. Pre-PR self-check
85
109
 
86
110
  - All Hawkeye-declared tests exist + pass.
87
111
  - No `test.skip` / `.only` left.
@@ -91,15 +115,16 @@ Until every AC has at least one test + minimum code that makes it pass.
91
115
  - Story file frontmatter → `status: ready-for-review`.
92
116
  - Self-walk the screen (web) or smoke a tab on simulator (app).
93
117
 
94
- ### 9. Open PR
118
+ ### 10. Open PR
95
119
 
96
120
  PR description includes:
97
121
  - Story link.
98
122
  - AC list with the test names that cover them.
99
123
  - Screenshots / recordings of happy + failure paths.
124
+ - Knowledge update line (`Touched axis: <none|architecture|conventions|risk-spots|dependencies|overview>`).
100
125
  - TEA expected next: design → trace → review → gate.
101
126
 
102
- ### 10. Address gate findings
127
+ ### 11. Address gate findings
103
128
 
104
129
  If `tea-review` flags issues, fix them in the same PR or open a follow-up if the story has shipped a separate value-bearing slice.
105
130
 
@@ -80,7 +80,19 @@ Append one line to `.wize/implementation/quick-dev-log.md`:
80
80
  2026-06-11 | shuri | rename UserService → AccountService | smoke PASS | PR #420
81
81
  ```
82
82
 
83
- ### 5. Commit + open PR
83
+ ### 5. Knowledge update (only if applicable)
84
+
85
+ Most quick-dev changes don't touch the baseline axes (copy edit, small refactor, dep bump in a stable lib). When they do — typically a **dependency bump** or a **rename that breaks a public contract** — add **one line** to the matching `document-project/*.md` file:
86
+
87
+ ```markdown
88
+ ## 2026-06-11
89
+ - Dependencies: bump zod 3.22 → 3.23. No API changes; validateInviteEmail unaffected.
90
+ - Conventions: `AccountService` replaces `UserService` (rename); imports updated repo-wide.
91
+ ```
92
+
93
+ Heuristic: *"would a new dev hitting `document-project/*.md` next week be misled if I don't add this?"* Yes → write. No → skip.
94
+
95
+ ### 6. Commit + open PR
84
96
 
85
97
  Conventional commit. PR description: the paragraph from step 1.
86
98
 
@@ -58,10 +58,34 @@ Apply this heuristic, top-down. Stop at the first match.
58
58
  12. **Has active sprint, oldest in-flight story has no `tea/.../design.md`.** → Next: **Hawkeye / `wize-tea-design`** for that story.
59
59
  13. **In-flight story exists, no implementation commits.** → Next: **Shuri / `wize-dev-story`** on that story.
60
60
  14. **In-flight story exists with code, no `gate.md`.** → Next: **Hawkeye / `wize-tea-trace` → `wize-tea-review` → `wize-tea-gate`** for that story.
61
- 15. **All stories gated.** → Next: **Wizer / `wize-retrospective`** + plan next epic.
61
+ 15. **All sprint stories gated `PASS`/`CONCERNS`, backlog has no `ready-for-dev` left.** → Sprint ended. Next: **Wizer / `wize-retrospective`** + **Pepper+Peggy / `wize-refresh-knowledge`** (the inline knowledge notes pile up over the sprint; the refresh consolidates them into the baseline docs).
62
+ 16. **All stories gated and no new epic pulled.** → Plan next epic with Tony + Hill, or run a roadmap session.
62
63
 
63
64
  For brownfield repos where `.wize/knowledge/document-project/` is missing, prepend: "Run `wize-document-project` first to baseline the codebase."
64
65
 
66
+ ## Step 2.5 — version-skew detection (proactive)
67
+
68
+ Before routing, compare:
69
+ - `kit_version` in `.wize/config/project.toml`
70
+ - The version of the installed kit (from `node_modules/wize-dev-kit/package.json` — *or* the version baked into the activated skills if you don't have a node-side check)
71
+
72
+ If you have access to the user's terminal (Claude Code Bash tool, Codex exec, OpenCode), additionally check the npm registry with a 2-second timeout:
73
+
74
+ ```bash
75
+ npm view wize-dev-kit version 2>/dev/null
76
+ ```
77
+
78
+ Cases:
79
+ - **Installed version > project.toml's `kit_version`** → suggest `npx wize-dev-kit update` (no `@latest` needed; the installed version is already newer).
80
+ - **Registry > installed version** → suggest `npx wize-dev-kit@latest update` to pick up the newer release.
81
+ - **All three match** → no message; carry on.
82
+
83
+ Phrase it as one short line, not a banner. Example:
84
+
85
+ > *"Heads up: registry has 0.2.3, you're on 0.2.2. Want me to run `npx wize-dev-kit@latest update`? (it preserves your `user.toml` and re-renders adapters)"*
86
+
87
+ If the user says yes and you can execute Bash, run it in the project root and stream output. Otherwise, print the command for them to run.
88
+
65
89
  ## Step 3 — respond
66
90
 
67
91
  Default response shape (3 lines). When `user.toml` provides a `[user] name`, include it in the greeting:
@@ -34,6 +34,7 @@ Hawkeye drives. The four inputs (`design`, `trace`, `review`, plus `nfr` at epic
34
34
  | Any AC `partial` | **CONCERNS** |
35
35
  | Any AC `not-met` | **FAIL** |
36
36
  | NFR `FAIL` on the epic (last story) | **FAIL** |
37
+ | `tea-review` flagged `knowledge_axes_touched` ≠ `knowledge_axes_updated` (any axis touched without update) | **CONCERNS** (advisory mode) / **FAIL** (enforcing mode) — adds finding `KN-NN` |
37
38
  | Failing AC OR non-neg NFR with documented business rationale + senior signoff | **WAIVED** |
38
39
 
39
40
  Score (0–100): heuristic. `100 - (10 × high) - (5 × medium) - (2 × low)`. Floor 0.
@@ -82,6 +83,12 @@ findings:
82
83
  severity: low
83
84
  summary: "Empty-state copy slightly differs from Mantis' spec."
84
85
  recommendation: "Update `<EmptyTeamPanel>` heading in a follow-up."
86
+ - id: KN-01
87
+ severity: medium
88
+ summary: "Story added a new component (`<InviteForm>`) but architecture-snapshot.md was not updated."
89
+ recommendation: "Add 2 lines to `.wize/knowledge/document-project/architecture-snapshot.md` under a dated bullet referencing the new component + its public testid contract."
90
+ owner: shuri
91
+ blocking: false # advisory mode; would be true under enforcing
85
92
  waived_by: null
86
93
  waived_reason: null
87
94
  created_at: 2026-06-11T20:30:00Z
@@ -47,11 +47,22 @@ If the story touches any `R-x` from the risk profile, walk the mitigation contra
47
47
 
48
48
  Did the story stay within its declared scope? Any out-of-scope item that crept in is flagged in the review (and either moved to a new story or backed out).
49
49
 
50
- ### 5. Findings
50
+ ### 5. Knowledge update check
51
+
52
+ Did this story touch any of the 5 `document-project` axes (architecture / conventions / risk-spots / dependencies / overview)? If yes, walk the PR diff and confirm the corresponding `.wize/knowledge/document-project/*.md` got 1–3 new lines this commit.
53
+
54
+ Decision:
55
+ - **Touched + updated** → record as PASS, no finding.
56
+ - **Touched + NOT updated** → record finding `KN-NN` (severity `medium`); recommendation: `gate CONCERNS` (advisory mode) or `gate FAIL` (enforcing).
57
+ - **Not touched** → write `knowledge: n/a` in the body, move on.
58
+
59
+ This is what keeps the brownfield baseline alive instead of stale. Without it, `document-project` is honest in week 1 and obsolete in week 24.
60
+
61
+ ### 6. Findings
51
62
 
52
63
  For each issue, write: severity (`low / medium / high`), what, why it matters, what to do.
53
64
 
54
- ### 6. Recommend gate outcome
65
+ ### 7. Recommend gate outcome
55
66
 
56
67
  Review doesn't *make* the gate decision (that's `tea-gate`); it recommends. Possible recommendations:
57
68
  - `gate PASS`
@@ -73,6 +84,8 @@ ac_check:
73
84
  - id: AC-02-2
74
85
  met: true
75
86
  evidence: "InviteForm.spec.tsx::error region announces"
87
+ knowledge_axes_touched: [conventions, risk-spots]
88
+ knowledge_axes_updated: [conventions, risk-spots] # leave empty array if axes touched but no update happened
76
89
  findings:
77
90
  - id: REV-01
78
91
  severity: low
@@ -0,0 +1,128 @@
1
+ // Brownfield baseline runner — detects AI harness CLIs available on PATH and,
2
+ // when authorized, executes `/wize-document-project` headlessly to populate
3
+ // .wize/knowledge/document-project/. Falls back to printed instructions when
4
+ // no harness is present or the user opts out.
5
+ //
6
+ // Harness priority is:
7
+ // 1. user's selected IDE targets (from .wize/config/project.toml), highest first
8
+ // 2. claude > codex > opencode (universal fallback)
9
+ //
10
+ // Set WIZE_SKIP_BASELINE=1 in the environment to disable any execution (the
11
+ // install still suggests the next step). Useful for CI and unattended setups.
12
+
13
+ 'use strict';
14
+
15
+ const fs = require('node:fs');
16
+ const path = require('node:path');
17
+ const { spawnSync } = require('node:child_process');
18
+
19
+ // Harness registry — for each supported CLI we know:
20
+ // binary : the executable name to find on PATH
21
+ // ideCode : the matching `ide_targets` code in project.toml (so we can prioritize)
22
+ // buildCmd: returns the spawnSync args (binary + arg list) for a headless run
23
+ const HARNESSES = [
24
+ {
25
+ code: 'claude-code',
26
+ binary: 'claude',
27
+ buildCmd: (prompt) => ({ cmd: 'claude', args: ['-p', prompt] })
28
+ },
29
+ {
30
+ code: 'codex',
31
+ binary: 'codex',
32
+ buildCmd: (prompt) => ({ cmd: 'codex', args: ['exec', '--', prompt] })
33
+ },
34
+ {
35
+ code: 'opencode',
36
+ binary: 'opencode',
37
+ buildCmd: (prompt) => ({ cmd: 'opencode', args: ['run', prompt] })
38
+ }
39
+ ];
40
+
41
+ function whichSync(bin) {
42
+ // Manual PATH walk — more predictable than shelling out to `which`/`where`,
43
+ // honors PATH overrides set by callers (and our tests), and stays portable.
44
+ const PATH = process.env.PATH || '';
45
+ const sep = process.platform === 'win32' ? ';' : ':';
46
+ const exts = process.platform === 'win32'
47
+ ? (process.env.PATHEXT || '.EXE;.CMD;.BAT').split(';')
48
+ : [''];
49
+ for (const dir of PATH.split(sep).filter(Boolean)) {
50
+ for (const ext of exts) {
51
+ const candidate = path.join(dir, bin + ext);
52
+ try {
53
+ const st = fs.statSync(candidate);
54
+ if (st.isFile() && (process.platform === 'win32' || (st.mode & 0o111))) {
55
+ return candidate;
56
+ }
57
+ } catch (_) { /* not here, keep looking */ }
58
+ }
59
+ }
60
+ return null;
61
+ }
62
+
63
+ // Returns an ordered list of harnesses present on PATH. When `preferIde`
64
+ // includes a harness's `code`, it floats to the top of the result.
65
+ function detectHarnessCli({ preferIde = [] } = {}) {
66
+ const found = [];
67
+ for (const h of HARNESSES) {
68
+ const p = whichSync(h.binary);
69
+ if (p) found.push({ ...h, path: p });
70
+ }
71
+ // Float preferred IDE targets to the top, keep relative order otherwise.
72
+ return found.sort((a, b) => {
73
+ const ai = preferIde.indexOf(a.code);
74
+ const bi = preferIde.indexOf(b.code);
75
+ if (ai === -1 && bi === -1) return 0;
76
+ if (ai === -1) return 1;
77
+ if (bi === -1) return -1;
78
+ return ai - bi;
79
+ });
80
+ }
81
+
82
+ // Run the harness headless with the document-project prompt. Returns
83
+ // { ok: boolean, exitCode, stdout, stderr }.
84
+ function runHeadlessBaseline({ harness, projectRoot, prompt, log = console.log }) {
85
+ if (process.env.WIZE_SKIP_BASELINE === '1') {
86
+ log('WIZE_SKIP_BASELINE=1 — not running the baseline; you can do it later in your IDE.');
87
+ return { ok: false, skipped: true };
88
+ }
89
+ const { cmd, args } = harness.buildCmd(prompt);
90
+ log(`Running ${cmd} ${args.map(a => /\s/.test(a) ? '"' + a + '"' : a).join(' ')}\n`);
91
+ const r = spawnSync(cmd, args, { cwd: projectRoot, stdio: 'inherit' });
92
+ return { ok: r.status === 0, exitCode: r.status, signal: r.signal };
93
+ }
94
+
95
+ function manualInstructions(harness) {
96
+ if (!harness) {
97
+ return [
98
+ '',
99
+ 'No AI harness CLI was detected on PATH (claude / codex / opencode).',
100
+ 'Open your IDE in this repo and run:',
101
+ ' /wize-document-project',
102
+ ''
103
+ ].join('\n');
104
+ }
105
+ const { cmd, args } = harness.buildCmd('/wize-document-project');
106
+ const shown = `${cmd} ${args.map(a => /\s/.test(a) ? '"' + a + '"' : a).join(' ')}`;
107
+ return [
108
+ '',
109
+ `Skipping the headless run. When you're ready, run from this folder:`,
110
+ ` ${shown}`,
111
+ '',
112
+ `Or open your IDE and type: /wize-document-project`,
113
+ ''
114
+ ].join('\n');
115
+ }
116
+
117
+ function defaultPrompt() {
118
+ return 'Activate the wize-document-project skill and execute it on this repository. Follow the steps in .claude/skills/wize-document-project/SKILL.md (or the equivalent path for your IDE). Output the baseline docs under .wize/knowledge/document-project/.';
119
+ }
120
+
121
+ module.exports = {
122
+ HARNESSES,
123
+ whichSync,
124
+ detectHarnessCli,
125
+ runHeadlessBaseline,
126
+ manualInstructions,
127
+ defaultPrompt
128
+ };
@@ -0,0 +1,117 @@
1
+ // Best-effort, non-blocking npm registry check for "is there a newer wize-dev-kit
2
+ // version than the one I'm running?". Designed so the CLI can call it from
3
+ // `list` / `agent list` / `help` and print a single hint at the top, without
4
+ // ever blocking the command if the network is slow, the user is offline, or
5
+ // the registry is misbehaving.
6
+ //
7
+ // Strategy:
8
+ // - Cache the registry answer in $XDG_CACHE_HOME (or ~/.cache) for 1 hour.
9
+ // - Resolve via fetch with a 1.5s timeout. Failure is silent.
10
+ // - Compare with the kit version baked into the running CLI.
11
+ // - Expose a `printUpdateHintIfAny(currentVersion)` helper for the CLI.
12
+
13
+ 'use strict';
14
+
15
+ const fs = require('node:fs');
16
+ const os = require('node:os');
17
+ const path = require('node:path');
18
+
19
+ const CACHE_TTL_MS = 60 * 60 * 1000; // 1h
20
+ const NETWORK_TIMEOUT_MS = 1500;
21
+
22
+ function cacheFile() {
23
+ const base = process.env.XDG_CACHE_HOME || path.join(os.homedir(), '.cache');
24
+ return path.join(base, 'wize-dev-kit', 'registry-version.json');
25
+ }
26
+
27
+ function readCache() {
28
+ const f = cacheFile();
29
+ try {
30
+ const stat = fs.statSync(f);
31
+ if (Date.now() - stat.mtimeMs > CACHE_TTL_MS) return null;
32
+ return JSON.parse(fs.readFileSync(f, 'utf-8'));
33
+ } catch (_) {
34
+ return null;
35
+ }
36
+ }
37
+
38
+ function writeCache(payload) {
39
+ const f = cacheFile();
40
+ try {
41
+ fs.mkdirSync(path.dirname(f), { recursive: true });
42
+ fs.writeFileSync(f, JSON.stringify(payload), 'utf-8');
43
+ } catch (_) { /* cache failure is harmless */ }
44
+ }
45
+
46
+ async function fetchLatestFromRegistry() {
47
+ const ctrl = new AbortController();
48
+ const timer = setTimeout(() => ctrl.abort(), NETWORK_TIMEOUT_MS);
49
+ try {
50
+ const res = await fetch('https://registry.npmjs.org/wize-dev-kit', {
51
+ signal: ctrl.signal,
52
+ headers: { Accept: 'application/vnd.npm.install-v1+json' }
53
+ });
54
+ if (!res.ok) return null;
55
+ const body = await res.json();
56
+ const latest = body && body['dist-tags'] && body['dist-tags'].latest;
57
+ return typeof latest === 'string' ? latest : null;
58
+ } catch (_) {
59
+ return null; // any error → silent fallback
60
+ } finally {
61
+ clearTimeout(timer);
62
+ }
63
+ }
64
+
65
+ // Returns the registry-latest version, hitting the cache first. Never throws,
66
+ // never blocks meaningfully (network call is capped + abortable).
67
+ async function getLatestVersion({ skipCache = false } = {}) {
68
+ if (!skipCache) {
69
+ const c = readCache();
70
+ if (c && c.version) return c.version;
71
+ }
72
+ const fresh = await fetchLatestFromRegistry();
73
+ if (fresh) writeCache({ version: fresh, fetched_at: Date.now() });
74
+ return fresh;
75
+ }
76
+
77
+ function semverGreater(a, b) {
78
+ const pa = String(a).split('.').map(n => parseInt(n, 10) || 0);
79
+ const pb = String(b).split('.').map(n => parseInt(n, 10) || 0);
80
+ for (let i = 0; i < 3; i++) {
81
+ if ((pa[i] || 0) > (pb[i] || 0)) return true;
82
+ if ((pa[i] || 0) < (pb[i] || 0)) return false;
83
+ }
84
+ return false;
85
+ }
86
+
87
+ // Prints a one-line hint when a newer version is available. Silent otherwise.
88
+ // Designed to be awaited near the top of a CLI command; if anything is slow
89
+ // or off, it just returns.
90
+ async function printUpdateHintIfAny(currentVersion, { log = console.log, isTTY = process.stdout.isTTY } = {}) {
91
+ if (process.env.WIZE_DISABLE_UPDATE_CHECK === '1') return;
92
+ if (!isTTY) return; // don't spam pipes
93
+ try {
94
+ const latest = await getLatestVersion();
95
+ if (!latest) return;
96
+ if (semverGreater(latest, currentVersion)) {
97
+ log('');
98
+ log(` ↑ Update available: wize-dev-kit ${currentVersion} → ${latest}`);
99
+ log(` Run \`npx wize-dev-kit@latest update\` in your project to refresh adapters.`);
100
+ log('');
101
+ }
102
+ } catch (_) {
103
+ /* total fallback — never block the command */
104
+ }
105
+ }
106
+
107
+ module.exports = {
108
+ CACHE_TTL_MS,
109
+ NETWORK_TIMEOUT_MS,
110
+ cacheFile,
111
+ readCache,
112
+ writeCache,
113
+ fetchLatestFromRegistry,
114
+ getLatestVersion,
115
+ semverGreater,
116
+ printUpdateHintIfAny
117
+ };
@@ -16,6 +16,8 @@ const readline = require('node:readline');
16
16
  const prompts = require('prompts');
17
17
  const { applyGitignore, generateUserToml } = require('./setup-helpers.js');
18
18
  const { cmdUpdate } = require('./commands/update.js');
19
+ const { detectHarnessCli, runHeadlessBaseline, manualInstructions, defaultPrompt } = require('./baseline.js');
20
+ const { printUpdateHintIfAny } = require('./version-check.js');
19
21
  const { cmdSync: cmdSyncReal } = require('./commands/sync.js');
20
22
  const { cmdAgentList, cmdAgentCreate, cmdAgentEdit } = require('./commands/agent.js');
21
23
 
@@ -89,9 +91,41 @@ function logo() {
89
91
  ].join('\n');
90
92
  }
91
93
 
94
+ // Pipe-safe line reader.
95
+ //
96
+ // `readline.question()` has two bugs that bite us when stdin is a pipe (e.g.
97
+ // `printf ... | wize-dev-kit install` or our CI smoke test):
98
+ // 1. Opening a new createInterface per call closes stdin on .close().
99
+ // 2. Even with a shared interface, the second `question` after a single
100
+ // empty line ("\n") never resolves — readline's question machinery
101
+ // stalls in non-TTY mode.
102
+ //
103
+ // We replace it with an event-based queue: subscribe to `line` once, push
104
+ // resolved promises in order. Empty lines are propagated as `""`. EOF is
105
+ // treated as end of the queue (remaining waiters resolve with `""`).
106
+ let _rl = null;
107
+ let _queue = [];
108
+ let _waiters = [];
109
+
110
+ function getRl() {
111
+ if (_rl) return _rl;
112
+ _rl = readline.createInterface({ input: process.stdin, terminal: false });
113
+ _rl.on('line', (line) => {
114
+ if (_waiters.length) _waiters.shift()(line);
115
+ else _queue.push(line);
116
+ });
117
+ _rl.on('close', () => {
118
+ while (_waiters.length) _waiters.shift()('');
119
+ });
120
+ process.on('exit', () => { if (_rl) { _rl.close(); _rl = null; } });
121
+ return _rl;
122
+ }
123
+
92
124
  function prompt(question) {
93
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
94
- return new Promise(resolve => rl.question(question, ans => { rl.close(); resolve(ans.trim()); }));
125
+ process.stdout.write(question);
126
+ getRl();
127
+ if (_queue.length) return Promise.resolve(_queue.shift().trim());
128
+ return new Promise(resolve => _waiters.push((line) => resolve(line.trim())));
95
129
  }
96
130
 
97
131
  async function confirm(question, defaultYes = true) {
@@ -385,7 +419,34 @@ async function cmdInstall(args) {
385
419
  if (detection.brownfield) {
386
420
  const baseline = await confirm('\nRun `wize-document-project` to baseline the existing repo now?', true);
387
421
  if (baseline) {
388
- console.log('(stub) Pepper + Peggy would now produce the baseline docs in .wize/knowledge/document-project/.');
422
+ const preferIde = targets.map(t => t.code);
423
+ const harnesses = detectHarnessCli({ preferIde });
424
+ if (process.env.WIZE_SKIP_BASELINE === '1') {
425
+ console.log('\nWIZE_SKIP_BASELINE=1 — not running the baseline.');
426
+ console.log(manualInstructions(harnesses[0]));
427
+ } else if (harnesses.length === 0) {
428
+ console.log(manualInstructions(null));
429
+ } else {
430
+ const chosen = harnesses[0];
431
+ console.log(`\nDetected harness: ${chosen.binary} (${chosen.path}).`);
432
+ const confirmRun = await confirm(
433
+ `Run /wize-document-project via ${chosen.binary} now?`,
434
+ true
435
+ );
436
+ if (confirmRun) {
437
+ const r = runHeadlessBaseline({
438
+ harness: chosen,
439
+ projectRoot: cwd,
440
+ prompt: defaultPrompt()
441
+ });
442
+ if (!r.ok && !r.skipped) {
443
+ console.log(`\n${chosen.binary} exited with code ${r.exitCode}. You can re-run later with:`);
444
+ console.log(manualInstructions(chosen));
445
+ }
446
+ } else {
447
+ console.log(manualInstructions(chosen));
448
+ }
449
+ }
389
450
  }
390
451
  }
391
452
 
@@ -475,12 +536,22 @@ function cmdValidate() {
475
536
  require('./validators/run-all.js')(KIT_ROOT);
476
537
  }
477
538
 
539
+ // Commands worth nudging the user about when a newer version exists. Skipped
540
+ // for `update` (already updating), `install` (already setting up), `uninstall`
541
+ // (already leaving), `validate` (developer-tool), and `version` (the user is
542
+ // already asking about versions).
543
+ const HINT_COMMANDS = new Set(['list', 'sync', 'agent', 'workflow', 'help']);
544
+
478
545
  async function main() {
479
546
  const [cmd, ...rest] = process.argv.slice(2);
480
547
  if (!cmd || cmd === 'help' || cmd === '--help' || cmd === '-h') {
548
+ await printUpdateHintIfAny(KIT_VERSION);
481
549
  console.log(HELP);
482
550
  return;
483
551
  }
552
+ if (HINT_COMMANDS.has(cmd)) {
553
+ await printUpdateHintIfAny(KIT_VERSION);
554
+ }
484
555
  switch (cmd) {
485
556
  case 'install': return cmdInstall(rest);
486
557
  case 'update': return cmdUpdate({ kitRoot: KIT_ROOT, projectRoot: process.cwd() });