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 +91 -1
- package/package.json +1 -1
- package/src/method-skills/1-analysis/wize-document-project/workflow.md +41 -0
- package/src/method-skills/1-analysis/wize-refresh-knowledge/workflow.md +127 -0
- package/src/method-skills/4-implementation/wize-dev-story/workflow.md +28 -3
- package/src/method-skills/4-implementation/wize-quick-dev/workflow.md +13 -1
- package/src/orchestrator-skills/wize-help/skill.md +25 -1
- package/src/tea-skills/wize-tea-gate/workflow.md +7 -0
- package/src/tea-skills/wize-tea-review/workflow.md +15 -2
- package/tools/installer/baseline.js +128 -0
- package/tools/installer/version-check.js +117 -0
- package/tools/installer/wize-cli.js +74 -3
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.
|
|
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.
|
|
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.
|
|
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
|
-
###
|
|
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
|
-
###
|
|
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.
|
|
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`** +
|
|
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.
|
|
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
|
-
###
|
|
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
|
-
|
|
94
|
-
|
|
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
|
-
|
|
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() });
|