wize-dev-kit 0.16.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (235) hide show
  1. package/AGENTS.md +37 -0
  2. package/ARCH.md +77 -24
  3. package/CHANGELOG.md +14 -0
  4. package/DECISIONS.md +27 -1
  5. package/README.es.md +296 -0
  6. package/README.md +3 -2
  7. package/README.pt-BR.md +294 -0
  8. package/ROSTER.md +11 -3
  9. package/adapters/README.md +9 -7
  10. package/adapters/antigravity/README.md +5 -5
  11. package/adapters/claude-code/README.md +1 -1
  12. package/adapters/codex/README.md +5 -5
  13. package/adapters/codex/adapter.yaml +1 -1
  14. package/adapters/codex/render.js +1 -1
  15. package/adapters/continue/README.md +5 -5
  16. package/adapters/cursor/README.md +2 -2
  17. package/adapters/generic/README.md +1 -1
  18. package/adapters/hermes/README.md +23 -0
  19. package/adapters/hermes/adapter.yaml +8 -0
  20. package/adapters/hermes/render.js +17 -0
  21. package/adapters/kimi-code/README.md +5 -5
  22. package/adapters/kimi-code/render.js +2 -2
  23. package/adapters/kiro/README.md +30 -0
  24. package/adapters/kiro/adapter.yaml +8 -0
  25. package/adapters/kiro/render.js +21 -0
  26. package/adapters/opencode/README.md +3 -3
  27. package/adapters/opencode/render.js +27 -1
  28. package/adapters/windsurf/README.md +3 -3
  29. package/docs/harnesses/antigravity.md +20 -0
  30. package/docs/harnesses/antigravity.pt-BR.md +20 -0
  31. package/docs/harnesses/claude-code.md +23 -0
  32. package/docs/harnesses/claude-code.pt-BR.md +23 -0
  33. package/docs/harnesses/codex.md +21 -0
  34. package/docs/harnesses/codex.pt-BR.md +21 -0
  35. package/docs/harnesses/continue.md +21 -0
  36. package/docs/harnesses/continue.pt-BR.md +21 -0
  37. package/docs/harnesses/cursor.md +22 -0
  38. package/docs/harnesses/cursor.pt-BR.md +22 -0
  39. package/docs/harnesses/generic.md +20 -0
  40. package/docs/harnesses/generic.pt-BR.md +20 -0
  41. package/docs/harnesses/hermes.md +26 -0
  42. package/docs/harnesses/hermes.pt-BR.md +26 -0
  43. package/docs/harnesses/kimi-code.md +19 -0
  44. package/docs/harnesses/kimi-code.pt-BR.md +19 -0
  45. package/docs/harnesses/kiro.md +26 -0
  46. package/docs/harnesses/kiro.pt-BR.md +26 -0
  47. package/docs/harnesses/opencode.md +31 -0
  48. package/docs/harnesses/opencode.pt-BR.md +31 -0
  49. package/docs/harnesses/windsurf.md +22 -0
  50. package/docs/harnesses/windsurf.pt-BR.md +22 -0
  51. package/package.json +1 -1
  52. package/schemas/agent.schema.json +2 -2
  53. package/schemas/workflow.schema.json +1 -1
  54. package/src/app-overlay/wize-app-release-channels/workflow.md +2 -0
  55. package/src/app-overlay/wize-app-scaffold/workflow.md +2 -0
  56. package/src/app-overlay/wize-app-store-listing/workflow.md +2 -0
  57. package/src/builder-skills/wize-create-agent/workflow.md +2 -0
  58. package/src/builder-skills/wize-create-skill/workflow.md +2 -0
  59. package/src/builder-skills/wize-create-workflow/workflow.md +2 -0
  60. package/src/core-skills/wize-advanced-elicitation/skill.md +2 -0
  61. package/src/core-skills/wize-brainstorming/skill.md +2 -0
  62. package/src/core-skills/wize-customize/skill.md +116 -0
  63. package/src/core-skills/wize-editorial-review-prose/skill.md +94 -0
  64. package/src/core-skills/wize-editorial-review-structure/skill.md +99 -0
  65. package/src/core-skills/wize-grill/skill.md +77 -0
  66. package/src/core-skills/wize-index-docs/skill.md +119 -0
  67. package/src/core-skills/wize-pre-pr-check/skill.md +134 -0
  68. package/src/core-skills/wize-review-adversarial/skill.md +3 -0
  69. package/src/core-skills/wize-review-edge-case-hunter/skill.md +115 -0
  70. package/src/core-skills/wize-shard-doc/skill.md +2 -0
  71. package/src/core-skills/wize-spec/assets/headless-schemas.md +39 -0
  72. package/src/core-skills/wize-spec/assets/spec-template.md +40 -0
  73. package/src/core-skills/wize-spec/customize.toml +20 -0
  74. package/src/core-skills/wize-spec/skill.md +112 -0
  75. package/src/method-skills/1-analysis/wize-agent-analyst/agent.yaml +3 -0
  76. package/src/method-skills/1-analysis/wize-document-project/documentation-requirements.csv +12 -0
  77. package/src/method-skills/1-analysis/wize-document-project/templates/api-contracts-template.md +38 -0
  78. package/src/method-skills/1-analysis/wize-document-project/templates/architecture-template.md +54 -0
  79. package/src/method-skills/1-analysis/wize-document-project/templates/component-inventory-template.md +40 -0
  80. package/src/method-skills/1-analysis/wize-document-project/templates/contribution-guide-template.md +34 -0
  81. package/src/method-skills/1-analysis/wize-document-project/templates/data-models-template.md +36 -0
  82. package/src/method-skills/1-analysis/wize-document-project/templates/deep-dive-template.md +312 -0
  83. package/src/method-skills/1-analysis/wize-document-project/templates/deployment-guide-template.md +42 -0
  84. package/src/method-skills/1-analysis/wize-document-project/templates/development-guide-template.md +61 -0
  85. package/src/method-skills/1-analysis/wize-document-project/templates/index-template.md +185 -0
  86. package/src/method-skills/1-analysis/wize-document-project/templates/project-overview-template.md +110 -0
  87. package/src/method-skills/1-analysis/wize-document-project/templates/project-scan-report-schema.json +159 -0
  88. package/src/method-skills/1-analysis/wize-document-project/templates/source-tree-template.md +142 -0
  89. package/src/method-skills/1-analysis/wize-document-project/workflow.md +213 -20
  90. package/src/method-skills/1-analysis/wize-domain-research/customize.toml +14 -0
  91. package/src/method-skills/1-analysis/wize-domain-research/domain-steps/step-01-init.md +49 -0
  92. package/src/method-skills/1-analysis/wize-domain-research/domain-steps/step-02-domain-analysis.md +39 -0
  93. package/src/method-skills/1-analysis/wize-domain-research/domain-steps/step-03-competitive-landscape.md +39 -0
  94. package/src/method-skills/1-analysis/wize-domain-research/domain-steps/step-04-regulatory-focus.md +39 -0
  95. package/src/method-skills/1-analysis/wize-domain-research/domain-steps/step-05-technical-trends.md +39 -0
  96. package/src/method-skills/1-analysis/wize-domain-research/domain-steps/step-06-research-synthesis.md +43 -0
  97. package/src/method-skills/1-analysis/wize-domain-research/research.template.md +31 -0
  98. package/src/method-skills/1-analysis/wize-domain-research/workflow.md +58 -0
  99. package/src/method-skills/1-analysis/wize-market-research/customize.toml +14 -0
  100. package/src/method-skills/1-analysis/wize-market-research/research.template.md +31 -0
  101. package/src/method-skills/1-analysis/wize-market-research/steps/step-01-init.md +57 -0
  102. package/src/method-skills/1-analysis/wize-market-research/steps/step-02-customer-behavior.md +39 -0
  103. package/src/method-skills/1-analysis/wize-market-research/steps/step-03-customer-pain-points.md +37 -0
  104. package/src/method-skills/1-analysis/wize-market-research/steps/step-04-customer-decisions.md +39 -0
  105. package/src/method-skills/1-analysis/wize-market-research/steps/step-05-competitive-analysis.md +37 -0
  106. package/src/method-skills/1-analysis/wize-market-research/steps/step-06-research-completion.md +47 -0
  107. package/src/method-skills/1-analysis/wize-market-research/workflow.md +66 -0
  108. package/src/method-skills/1-analysis/wize-prfaq/workflow.md +152 -11
  109. package/src/method-skills/1-analysis/wize-product-brief/workflow.md +92 -19
  110. package/src/method-skills/1-analysis/wize-refresh-knowledge/workflow.md +129 -0
  111. package/src/method-skills/1-analysis/wize-research/workflow.md +39 -12
  112. package/src/method-skills/1-analysis/wize-technical-research/customize.toml +14 -0
  113. package/src/method-skills/1-analysis/wize-technical-research/research.template.md +31 -0
  114. package/src/method-skills/1-analysis/wize-technical-research/technical-steps/step-01-init.md +49 -0
  115. package/src/method-skills/1-analysis/wize-technical-research/technical-steps/step-02-technical-overview.md +45 -0
  116. package/src/method-skills/1-analysis/wize-technical-research/technical-steps/step-03-integration-patterns.md +39 -0
  117. package/src/method-skills/1-analysis/wize-technical-research/technical-steps/step-04-architectural-patterns.md +39 -0
  118. package/src/method-skills/1-analysis/wize-technical-research/technical-steps/step-05-implementation-research.md +42 -0
  119. package/src/method-skills/1-analysis/wize-technical-research/technical-steps/step-06-research-synthesis.md +46 -0
  120. package/src/method-skills/1-analysis/wize-technical-research/workflow.md +60 -0
  121. package/src/method-skills/1-analysis/wize-trigger-map/workflow.md +82 -16
  122. package/src/method-skills/2-plan-workflows/wize-create-prd/workflow.md +135 -23
  123. package/src/method-skills/2-plan-workflows/wize-edit-prd/workflow.md +110 -0
  124. package/src/method-skills/2-plan-workflows/wize-ux-design/workflow.md +134 -28
  125. package/src/method-skills/2-plan-workflows/wize-ux-scenarios/workflow.md +93 -15
  126. package/src/method-skills/2-plan-workflows/wize-validate-prd/workflow.md +108 -12
  127. package/src/method-skills/3-solutioning/wize-check-implementation-readiness/workflow.md +103 -11
  128. package/src/method-skills/3-solutioning/wize-create-architecture/architecture-decision-template.md +41 -0
  129. package/src/method-skills/3-solutioning/wize-create-architecture/customize.toml +20 -0
  130. package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-01-init.md +95 -0
  131. package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-01b-continue.md +32 -0
  132. package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-02-context.md +126 -0
  133. package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-03-starter.md +110 -0
  134. package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-04-decisions.md +129 -0
  135. package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-05-patterns.md +109 -0
  136. package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-06-structure.md +97 -0
  137. package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-07-validation.md +124 -0
  138. package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-08-complete.md +59 -0
  139. package/src/method-skills/3-solutioning/wize-create-architecture/workflow.md +55 -48
  140. package/src/method-skills/3-solutioning/wize-create-epics-and-stories/workflow.md +154 -15
  141. package/src/method-skills/3-solutioning/wize-design-system/workflow.md +184 -22
  142. package/src/method-skills/3-solutioning/wize-nfr-principles/workflow.md +145 -17
  143. package/src/method-skills/3-solutioning/wize-project-context/workflow.md +120 -0
  144. package/src/method-skills/3-solutioning/wize-tech-vision/workflow.md +130 -22
  145. package/src/method-skills/4-implementation/wize-agent-dev/persona.md +12 -0
  146. package/src/method-skills/4-implementation/wize-changelog/workflow.md +184 -0
  147. package/src/method-skills/4-implementation/wize-checkpoint-preview/workflow.md +117 -0
  148. package/src/method-skills/4-implementation/wize-code-review/customize.toml +21 -0
  149. package/src/method-skills/4-implementation/wize-code-review/steps/step-01-gather-context.md +64 -0
  150. package/src/method-skills/4-implementation/wize-code-review/steps/step-02-review.md +40 -0
  151. package/src/method-skills/4-implementation/wize-code-review/steps/step-03-triage.md +43 -0
  152. package/src/method-skills/4-implementation/wize-code-review/steps/step-04-present.md +100 -0
  153. package/src/method-skills/4-implementation/wize-code-review/workflow.md +54 -12
  154. package/src/method-skills/4-implementation/wize-correct-course/workflow.md +93 -0
  155. package/src/method-skills/4-implementation/wize-create-story/workflow.md +154 -10
  156. package/src/method-skills/4-implementation/wize-dev-story/workflow.md +185 -17
  157. package/src/method-skills/4-implementation/wize-investigate/workflow.md +123 -0
  158. package/src/method-skills/4-implementation/wize-quick-dev/workflow.md +136 -18
  159. package/src/method-skills/4-implementation/wize-release/workflow.md +162 -0
  160. package/src/method-skills/4-implementation/wize-retrospective/workflow.md +114 -10
  161. package/src/method-skills/4-implementation/wize-sprint-planning/workflow.md +78 -11
  162. package/src/method-skills/4-implementation/wize-sprint-status/workflow.md +45 -11
  163. package/src/method-skills/module.yaml +28 -0
  164. package/src/orchestrator-skills/module.yaml +7 -1
  165. package/src/orchestrator-skills/wize/skill.md +164 -0
  166. package/src/orchestrator-skills/wize-check/skill.md +98 -0
  167. package/src/orchestrator-skills/wize-help/skill.md +227 -67
  168. package/src/orchestrator-skills/wize-onboarding/workflow.md +78 -14
  169. package/src/orchestrator-skills/wize-orchestrator/agent.yaml +2 -0
  170. package/src/orchestrator-skills/wize-orchestrator/persona.md +44 -3
  171. package/src/orchestrator-skills/wize-party-mode/workflow.md +2 -0
  172. package/src/security-overlay/_shared/allowlist.js +154 -0
  173. package/src/security-overlay/_shared/backlog.js +169 -0
  174. package/src/security-overlay/_shared/cli-runner.js +87 -0
  175. package/src/security-overlay/_shared/cvss.js +108 -0
  176. package/src/security-overlay/_shared/detect.js +125 -0
  177. package/src/security-overlay/_shared/install-script.js +205 -0
  178. package/src/security-overlay/_shared/invoke-phase.js +86 -0
  179. package/src/security-overlay/_shared/owasp.js +56 -0
  180. package/src/security-overlay/_shared/partial.js +225 -0
  181. package/src/security-overlay/_shared/preflight.js +175 -0
  182. package/src/security-overlay/_shared/scope-gate.js +172 -0
  183. package/src/security-overlay/_shared/scope-parser.js +147 -0
  184. package/src/security-overlay/agents/red-teamer/agent.yaml +54 -0
  185. package/src/security-overlay/agents/red-teamer/persona.md +49 -0
  186. package/src/security-overlay/data/common.txt +115 -0
  187. package/src/security-overlay/data/owasp-top10.json +15 -0
  188. package/src/security-overlay/data/tool-allowlist.json +31 -0
  189. package/src/security-overlay/skills/wize-sec-enumerate/scripts/run-enumerate.js +180 -0
  190. package/src/security-overlay/skills/wize-sec-enumerate/skill.md +34 -0
  191. package/src/security-overlay/skills/wize-sec-exploit/data/common.txt +117 -0
  192. package/src/security-overlay/skills/wize-sec-exploit/scripts/run-ffuf.js +147 -0
  193. package/src/security-overlay/skills/wize-sec-exploit/scripts/run-nikto.js +145 -0
  194. package/src/security-overlay/skills/wize-sec-exploit/scripts/run-nuclei.js +176 -0
  195. package/src/security-overlay/skills/wize-sec-exploit/scripts/run-sqlmap.js +139 -0
  196. package/src/security-overlay/skills/wize-sec-pentest/scripts/run-pipeline.js +184 -0
  197. package/src/security-overlay/skills/wize-sec-pentest/skill.md +54 -0
  198. package/src/security-overlay/skills/wize-sec-recon/scripts/run-gitleaks.js +139 -0
  199. package/src/security-overlay/skills/wize-sec-recon/scripts/run-osv.js +227 -0
  200. package/src/security-overlay/skills/wize-sec-recon/scripts/run-recon.js +162 -0
  201. package/src/security-overlay/skills/wize-sec-recon/skill.md +37 -0
  202. package/src/security-overlay/skills/wize-sec-report/scripts/render-report.js +1033 -0
  203. package/src/security-overlay/skills/wize-sec-scope/scripts/generate-scope.js +106 -0
  204. package/src/security-overlay/skills/wize-sec-scope/skill.md +52 -0
  205. package/src/tea-skills/wize-qa-generate-e2e-tests/workflow.md +121 -0
  206. package/src/tea-skills/wize-tea-design/workflow.md +107 -13
  207. package/src/tea-skills/wize-tea-gate/workflow.md +118 -25
  208. package/src/tea-skills/wize-tea-nfr/workflow.md +107 -14
  209. package/src/tea-skills/wize-tea-review/workflow.md +123 -13
  210. package/src/tea-skills/wize-tea-risk/workflow.md +113 -10
  211. package/src/tea-skills/wize-tea-trace/workflow.md +86 -12
  212. package/src/web-overlay/wize-web-deploy/workflow.md +2 -0
  213. package/src/web-overlay/wize-web-scaffold/workflow.md +2 -0
  214. package/src/web-overlay/wize-web-seo-audit/workflow.md +2 -0
  215. package/tools/check-eli5-all-adapters.js +3 -2
  216. package/tools/installer/baseline.js +138 -0
  217. package/tools/installer/commands/agent.js +197 -0
  218. package/tools/installer/commands/doctor.js +321 -0
  219. package/tools/installer/commands/document-project.js +93 -0
  220. package/tools/installer/commands/sync.js +45 -0
  221. package/tools/installer/commands/update.js +172 -0
  222. package/tools/installer/document-project/batch-scanner.js +93 -0
  223. package/tools/installer/document-project/classify.js +170 -0
  224. package/tools/installer/document-project/modes/deep-dive.js +196 -0
  225. package/tools/installer/document-project/modes/full-rescan.js +15 -0
  226. package/tools/installer/document-project/modes/initial-scan.js +100 -0
  227. package/tools/installer/document-project/modes/quick.js +211 -0
  228. package/tools/installer/document-project/render-index.js +101 -0
  229. package/tools/installer/document-project/state.js +110 -0
  230. package/tools/installer/onboarding.js +14 -20
  231. package/tools/installer/render-shared.js +159 -15
  232. package/tools/installer/setup-helpers.js +2 -0
  233. package/tools/installer/validators/run-all.js +3 -2
  234. package/tools/installer/version-check.js +117 -0
  235. package/tools/installer/wize-cli.js +501 -70
@@ -0,0 +1,138 @@
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 > hermes > kiro-cli (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
+ code: 'hermes',
41
+ binary: 'hermes',
42
+ buildCmd: (prompt) => ({ cmd: 'hermes', args: ['-z', prompt] })
43
+ },
44
+ {
45
+ code: 'kiro',
46
+ binary: 'kiro-cli',
47
+ buildCmd: (prompt) => ({ cmd: 'kiro-cli', args: ['chat', '--no-interactive', '--trust-all-tools', prompt] })
48
+ }
49
+ ];
50
+
51
+ function whichSync(bin) {
52
+ // Manual PATH walk — more predictable than shelling out to `which`/`where`,
53
+ // honors PATH overrides set by callers (and our tests), and stays portable.
54
+ const PATH = process.env.PATH || '';
55
+ const sep = process.platform === 'win32' ? ';' : ':';
56
+ const exts = process.platform === 'win32'
57
+ ? (process.env.PATHEXT || '.EXE;.CMD;.BAT').split(';')
58
+ : [''];
59
+ for (const dir of PATH.split(sep).filter(Boolean)) {
60
+ for (const ext of exts) {
61
+ const candidate = path.join(dir, bin + ext);
62
+ try {
63
+ const st = fs.statSync(candidate);
64
+ if (st.isFile() && (process.platform === 'win32' || (st.mode & 0o111))) {
65
+ return candidate;
66
+ }
67
+ } catch (_) { /* not here, keep looking */ }
68
+ }
69
+ }
70
+ return null;
71
+ }
72
+
73
+ // Returns an ordered list of harnesses present on PATH. When `preferIde`
74
+ // includes a harness's `code`, it floats to the top of the result.
75
+ function detectHarnessCli({ preferIde = [] } = {}) {
76
+ const found = [];
77
+ for (const h of HARNESSES) {
78
+ const p = whichSync(h.binary);
79
+ if (p) found.push({ ...h, path: p });
80
+ }
81
+ // Float preferred IDE targets to the top, keep relative order otherwise.
82
+ return found.sort((a, b) => {
83
+ const ai = preferIde.indexOf(a.code);
84
+ const bi = preferIde.indexOf(b.code);
85
+ if (ai === -1 && bi === -1) return 0;
86
+ if (ai === -1) return 1;
87
+ if (bi === -1) return -1;
88
+ return ai - bi;
89
+ });
90
+ }
91
+
92
+ // Run the harness headless with the document-project prompt. Returns
93
+ // { ok: boolean, exitCode, stdout, stderr }.
94
+ function runHeadlessBaseline({ harness, projectRoot, prompt, log = console.log }) {
95
+ if (process.env.WIZE_SKIP_BASELINE === '1') {
96
+ log('WIZE_SKIP_BASELINE=1 — not running the baseline; you can do it later in your IDE.');
97
+ return { ok: false, skipped: true };
98
+ }
99
+ const { cmd, args } = harness.buildCmd(prompt);
100
+ log(`Running ${cmd} ${args.map(a => /\s/.test(a) ? '"' + a + '"' : a).join(' ')}\n`);
101
+ const r = spawnSync(cmd, args, { cwd: projectRoot, stdio: 'inherit' });
102
+ return { ok: r.status === 0, exitCode: r.status, signal: r.signal };
103
+ }
104
+
105
+ function manualInstructions(harness) {
106
+ if (!harness) {
107
+ return [
108
+ '',
109
+ 'No AI harness CLI was detected on PATH (claude / codex / opencode / hermes / kiro-cli).',
110
+ 'Open your IDE in this repo and run:',
111
+ ' /wize-document-project',
112
+ ''
113
+ ].join('\n');
114
+ }
115
+ const { cmd, args } = harness.buildCmd('/wize-document-project');
116
+ const shown = `${cmd} ${args.map(a => /\s/.test(a) ? '"' + a + '"' : a).join(' ')}`;
117
+ return [
118
+ '',
119
+ `Skipping the headless run. When you're ready, run from this folder:`,
120
+ ` ${shown}`,
121
+ '',
122
+ `Or open your IDE and type: /wize-document-project`,
123
+ ''
124
+ ].join('\n');
125
+ }
126
+
127
+ function defaultPrompt() {
128
+ 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/.';
129
+ }
130
+
131
+ module.exports = {
132
+ HARNESSES,
133
+ whichSync,
134
+ detectHarnessCli,
135
+ runHeadlessBaseline,
136
+ manualInstructions,
137
+ defaultPrompt
138
+ };
@@ -0,0 +1,197 @@
1
+ // `wize-dev-kit agent <subcommand>` — manage built-in and custom agents.
2
+ //
3
+ // list - show every agent the active install resolves (built-in + custom)
4
+ // create - scaffold a brand-new custom agent in .wize/custom/agents/{code}/
5
+ // edit <code> - override an existing built-in via .wize/custom/agents/{code}/customize.toml
6
+ //
7
+ // All write operations validate the result against schemas/agent.schema.json
8
+ // (lite parser — no dependency on Ajv yet) and do a smoke dry-run before
9
+ // persisting, matching the contract `wize-create-agent` describes.
10
+
11
+ 'use strict';
12
+
13
+ const fs = require('node:fs');
14
+ const path = require('node:path');
15
+ const prompts = require('prompts');
16
+ const { collectAssets } = require('../render-shared.js');
17
+
18
+ const VALID_CODE = /^wize-(agent|orchestrator)(?:-[a-z0-9-]+)?$/;
19
+ const VALID_MODULES = ['orchestrator', 'method', 'tea', 'builder', 'core', 'web-overlay', 'app-overlay', 'custom'];
20
+
21
+ function ensureDir(p) { fs.mkdirSync(p, { recursive: true }); }
22
+
23
+ function listAgents(kitRoot, projectRoot) {
24
+ const builtIn = collectAssets(kitRoot, { profiles: ['core', 'web-overlay', 'app-overlay'] })
25
+ .filter(a => a.kind === 'agent')
26
+ .map(a => ({ code: a.code, name: a.name, title: a.title, source: 'built-in' }));
27
+ const customDir = path.join(projectRoot, '.wize/custom/agents');
28
+ const custom = [];
29
+ if (fs.existsSync(customDir)) {
30
+ for (const entry of fs.readdirSync(customDir, { withFileTypes: true })) {
31
+ if (!entry.isDirectory()) continue;
32
+ const yamlPath = path.join(customDir, entry.name, 'agent.yaml');
33
+ const customizePath = path.join(customDir, entry.name, 'customize.toml');
34
+ if (fs.existsSync(yamlPath)) {
35
+ const yaml = fs.readFileSync(yamlPath, 'utf-8');
36
+ const name = (yaml.match(/^name:\s*(.+)$/m) || [])[1] || entry.name;
37
+ const title = (yaml.match(/^title:\s*(.+)$/m) || [])[1] || '';
38
+ custom.push({ code: entry.name, name: name.trim(), title: title.trim(), source: 'custom' });
39
+ } else if (fs.existsSync(customizePath)) {
40
+ custom.push({ code: entry.name, name: '(override)', title: '', source: 'override' });
41
+ }
42
+ }
43
+ }
44
+ return { builtIn, custom };
45
+ }
46
+
47
+ function cmdAgentList({ kitRoot, projectRoot, log = console.log } = {}) {
48
+ const { builtIn, custom } = listAgents(kitRoot, projectRoot);
49
+ log('Built-in agents:');
50
+ for (const a of builtIn) log(` ${a.code.padEnd(36)} ${a.name}${a.title ? ' — ' + a.title : ''}`);
51
+ if (custom.length) {
52
+ log('\nCustom / override agents (from .wize/custom/agents/):');
53
+ for (const a of custom) log(` ${a.code.padEnd(36)} ${a.name}${a.title ? ' — ' + a.title : ''} [${a.source}]`);
54
+ } else {
55
+ log('\nCustom / override agents: (none yet — use `wize-dev-kit agent create`)');
56
+ }
57
+ return { builtIn, custom };
58
+ }
59
+
60
+ function validateAgent(spec, kitRoot) {
61
+ const errs = [];
62
+ if (!spec.code) errs.push('code is required');
63
+ else if (!VALID_CODE.test(spec.code)) errs.push(`code "${spec.code}" must match wize-(agent|orchestrator)[-name]`);
64
+ if (!spec.name) errs.push('name is required');
65
+ if (!spec.title) errs.push('title is required');
66
+ if (!VALID_MODULES.includes(spec.module)) errs.push(`module must be one of: ${VALID_MODULES.join(', ')}`);
67
+ if (!spec.description || spec.description.length < 10) errs.push('description must be ≥ 10 characters');
68
+ // Collide check against built-ins when not overriding.
69
+ const builtinCodes = collectAssets(kitRoot, { profiles: ['core', 'web-overlay', 'app-overlay'] })
70
+ .filter(a => a.kind === 'agent').map(a => a.code);
71
+ if (builtinCodes.includes(spec.code) && !spec.allowOverride) {
72
+ errs.push(`code "${spec.code}" already exists as a built-in. Use \`wize-dev-kit agent edit ${spec.code}\` to override.`);
73
+ }
74
+ return errs;
75
+ }
76
+
77
+ function renderAgentYaml(spec) {
78
+ return [
79
+ `code: ${spec.code}`,
80
+ `name: ${spec.name}`,
81
+ `title: ${spec.title}`,
82
+ `icon: "${spec.icon || '🔧'}"`,
83
+ `team: ${spec.team || 'software-development'}`,
84
+ `module: ${spec.module}`,
85
+ '',
86
+ 'description: |',
87
+ ...spec.description.split('\n').map(l => ' ' + l),
88
+ ''
89
+ ].join('\n');
90
+ }
91
+
92
+ function renderPersonaMd(spec) {
93
+ const body = (spec.persona || `I am **${spec.name}**. ${spec.description}`).trim();
94
+ return [
95
+ `# ${spec.name} — ${spec.title}`,
96
+ '',
97
+ body,
98
+ ''
99
+ ].join('\n');
100
+ }
101
+
102
+ // Smoke dry-run: write to temp dir, re-read, assert frontmatter parses.
103
+ function dryRunPersist(spec) {
104
+ const tmp = path.join(require('node:os').tmpdir(), `wize-agent-${spec.code}-${Date.now()}`);
105
+ ensureDir(tmp);
106
+ try {
107
+ fs.writeFileSync(path.join(tmp, 'agent.yaml'), renderAgentYaml(spec), 'utf-8');
108
+ fs.writeFileSync(path.join(tmp, 'persona.md'), renderPersonaMd(spec), 'utf-8');
109
+ const reread = fs.readFileSync(path.join(tmp, 'agent.yaml'), 'utf-8');
110
+ if (!/^code:\s+/m.test(reread)) throw new Error('emitted agent.yaml has no "code:" line');
111
+ if (!/^name:\s+/m.test(reread)) throw new Error('emitted agent.yaml has no "name:" line');
112
+ return { ok: true };
113
+ } finally {
114
+ try { fs.rmSync(tmp, { recursive: true, force: true }); } catch (_) {}
115
+ }
116
+ }
117
+
118
+ async function cmdAgentCreate({ kitRoot, projectRoot, opts = {} } = {}) {
119
+ const interactive = process.stdout.isTTY && process.stdin.isTTY && !opts.fromSpec;
120
+ let spec = opts.fromSpec || {};
121
+
122
+ if (interactive) {
123
+ const a = await prompts([
124
+ { type: 'text', name: 'code', message: 'Agent code (e.g. wize-agent-runbooks)',
125
+ validate: v => VALID_CODE.test(v) || 'must match wize-(agent|orchestrator)[-name]' },
126
+ { type: 'text', name: 'name', message: 'Display name (e.g. Riri Williams)', validate: v => !!v.trim() || 'required' },
127
+ { type: 'text', name: 'title', message: 'Role / title (e.g. Reliability Engineer)', validate: v => !!v.trim() || 'required' },
128
+ { type: 'text', name: 'icon', message: 'Icon emoji (optional)', initial: '🔧' },
129
+ { type: 'text', name: 'team', message: 'Team', initial: 'software-development' },
130
+ { type: 'select', name: 'module', message: 'Module', choices: VALID_MODULES.map(v => ({ title: v, value: v })), initial: VALID_MODULES.indexOf('custom') },
131
+ { type: 'text', name: 'description', message: 'One-paragraph description (≥ 10 chars)', validate: v => v.length >= 10 || 'must be ≥ 10 characters' },
132
+ { type: 'text', name: 'persona', message: 'Persona body (optional — defaults to description)', initial: '' }
133
+ ], { onCancel: () => process.exit(130) });
134
+ spec = { ...spec, ...a };
135
+ }
136
+
137
+ const errs = validateAgent(spec, kitRoot);
138
+ if (errs.length) {
139
+ console.error('✖ Validation failed:');
140
+ for (const e of errs) console.error(' - ' + e);
141
+ process.exit(2);
142
+ }
143
+
144
+ const dry = dryRunPersist(spec);
145
+ if (!dry.ok) {
146
+ console.error('✖ Dry-run failed; aborting.');
147
+ process.exit(3);
148
+ }
149
+
150
+ const target = path.join(projectRoot, '.wize/custom/agents', spec.code);
151
+ ensureDir(target);
152
+ fs.writeFileSync(path.join(target, 'agent.yaml'), renderAgentYaml(spec), 'utf-8');
153
+ fs.writeFileSync(path.join(target, 'persona.md'), renderPersonaMd(spec), 'utf-8');
154
+
155
+ console.log(`✓ Created ${path.relative(projectRoot, target)}/`);
156
+ console.log(' Run `wize-dev-kit sync` to refresh IDE adapter outputs with the new agent.');
157
+ return { code: spec.code, path: target };
158
+ }
159
+
160
+ async function cmdAgentEdit({ kitRoot, projectRoot, code, opts = {} } = {}) {
161
+ if (!code) {
162
+ console.error('Usage: wize-dev-kit agent edit <code>');
163
+ process.exit(1);
164
+ }
165
+ const builtinCodes = collectAssets(kitRoot, { profiles: ['core', 'web-overlay', 'app-overlay'] })
166
+ .filter(a => a.kind === 'agent').map(a => a.code);
167
+ if (!builtinCodes.includes(code)) {
168
+ console.error(`✖ "${code}" is not a built-in agent. Use \`wize-dev-kit agent create\` for new agents.`);
169
+ process.exit(2);
170
+ }
171
+
172
+ const target = path.join(projectRoot, '.wize/custom/agents', code);
173
+ ensureDir(target);
174
+ const customize = path.join(target, 'customize.toml');
175
+ if (fs.existsSync(customize) && !opts.force) {
176
+ console.log(`= ${path.relative(projectRoot, customize)} already exists. Edit it directly.`);
177
+ return { code, path: customize };
178
+ }
179
+ fs.writeFileSync(customize, `# Wize Dev Kit — overrides for the built-in agent "${code}".
180
+ # This file is loaded on top of the built-in agent's persona.md / agent.yaml
181
+ # at IDE adapter render time. Only the fields you set here are overridden.
182
+
183
+ [persona]
184
+ # motto = "your custom motto"
185
+ # voice = "succinct and irreverent"
186
+ # style = "show with code, not prose"
187
+
188
+ [behavior]
189
+ # defer_to = [] # e.g. ["wize-agent-pm"] to lower priority on certain decisions
190
+ # tools_deny = [] # tool codes the override removes from the agent
191
+ `, 'utf-8');
192
+ console.log(`✓ Created ${path.relative(projectRoot, customize)}`);
193
+ console.log(' Edit the file, then run `wize-dev-kit sync` to apply.');
194
+ return { code, path: customize };
195
+ }
196
+
197
+ module.exports = { cmdAgentList, cmdAgentCreate, cmdAgentEdit, listAgents, validateAgent };
@@ -0,0 +1,321 @@
1
+ // `wize-dev-kit doctor` — single-command diagnose.
2
+ //
3
+ // Prints a structured snapshot of the kit + the project + the surrounding
4
+ // environment, plus a list of actionable suggestions ranked by severity.
5
+ // Designed to be the *first* command a new dev runs in an unfamiliar
6
+ // wize-enabled repo, and the *go-to* command when something looks off.
7
+ //
8
+ // Output is plain text (no colors by default) so it's grep-friendly and pipe-
9
+ // friendly. Sections are stable so editors / dashboards can parse them.
10
+
11
+ 'use strict';
12
+
13
+ const fs = require('node:fs');
14
+ const path = require('node:path');
15
+ const { loadProjectConfig, loadInstalledKitVersion } = require('./update.js');
16
+ const { detectHarnessCli } = require('../baseline.js');
17
+ const { getLatestVersion, semverGreater } = require('../version-check.js');
18
+
19
+ function fileExists(p) { try { return fs.statSync(p).isFile(); } catch { return false; } }
20
+ function dirExists(p) { try { return fs.statSync(p).isDirectory(); } catch { return false; } }
21
+ function readSafe(p) { try { return fs.readFileSync(p, 'utf-8'); } catch { return ''; } }
22
+
23
+ function listFilesUnder(root, pattern) {
24
+ if (!dirExists(root)) return [];
25
+ const out = [];
26
+ const stack = [root];
27
+ while (stack.length) {
28
+ const dir = stack.pop();
29
+ let entries; try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch { continue; }
30
+ for (const e of entries) {
31
+ const full = path.join(dir, e.name);
32
+ if (e.isDirectory()) stack.push(full);
33
+ else if (e.isFile() && pattern.test(e.name)) out.push(full);
34
+ }
35
+ }
36
+ return out;
37
+ }
38
+
39
+ function parseGateStatus(content) {
40
+ // Find a `status: PASS|CONCERNS|FAIL|WAIVED` line in YAML frontmatter.
41
+ const m = content.match(/^status:\s*(PASS|CONCERNS|FAIL|WAIVED)\s*$/m);
42
+ return m ? m[1] : null;
43
+ }
44
+
45
+ function parseLastRefreshed(content) {
46
+ const m = content.match(/^last_refreshed:\s*([\d-]+)/m);
47
+ return m ? m[1] : null;
48
+ }
49
+
50
+ function daysAgo(dateStr) {
51
+ const t = Date.parse(dateStr);
52
+ if (Number.isNaN(t)) return null;
53
+ return Math.floor((Date.now() - t) / (24 * 3600 * 1000));
54
+ }
55
+
56
+ function adapterTargetPath(targetCode, projectRoot) {
57
+ // Mirror of the adapter render conventions documented in adapters/README.md.
58
+ switch (targetCode) {
59
+ case 'claude-code': return path.join(projectRoot, '.claude/skills');
60
+ case 'antigravity': return path.join(projectRoot, '.agent/skills');
61
+ case 'codex': return path.join(projectRoot, '.agents/skills');
62
+ case 'kimi-code': return path.join(projectRoot, '.kimi/skills');
63
+ case 'hermes': return path.join(projectRoot, '.hermes/skills');
64
+ case 'kiro': return path.join(projectRoot, '.kiro/skills');
65
+ case 'cursor': return path.join(projectRoot, '.cursor/rules');
66
+ case 'windsurf': return path.join(projectRoot, '.windsurf/rules');
67
+ case 'continue': return path.join(projectRoot, '.continue/prompts');
68
+ case 'opencode': return path.join(projectRoot, '.opencode/agents');
69
+ case 'generic': return path.join(projectRoot, '.wize/agents');
70
+ default: return null;
71
+ }
72
+ }
73
+
74
+ function countAdapterFiles(targetCode, projectRoot) {
75
+ const dir = adapterTargetPath(targetCode, projectRoot);
76
+ if (!dir || !dirExists(dir)) return 0;
77
+ // Be permissive on file extension; .mdc, .md, .prompt, and SKILL.md dirs all count.
78
+ let count = 0;
79
+ const stack = [dir];
80
+ while (stack.length) {
81
+ const d = stack.pop();
82
+ let entries; try { entries = fs.readdirSync(d, { withFileTypes: true }); } catch { continue; }
83
+ for (const e of entries) {
84
+ const full = path.join(d, e.name);
85
+ if (e.isDirectory()) stack.push(full);
86
+ else if (e.isFile()) count++;
87
+ }
88
+ }
89
+ return count;
90
+ }
91
+
92
+ function detectPhase(projectRoot) {
93
+ const has = (p) => fileExists(path.join(projectRoot, p)) || dirExists(path.join(projectRoot, p));
94
+ if (!dirExists(path.join(projectRoot, '.wize'))) return 'no-install';
95
+ if (!has('.wize/planning/brief.md')) return '1-analysis (brief pending)';
96
+ if (!has('.wize/planning/ux/trigger-map.md')) return '1-analysis (trigger map pending)';
97
+ if (!has('.wize/planning/prd.md')) return '2-plan (PRD pending)';
98
+ if (!has('.wize/planning/ux/ux-scenarios.md')) return '2-plan (UX scenarios pending)';
99
+ if (!has('.wize/planning/tech-vision.md')) return '2→3 boundary (Fury pending)';
100
+ if (!has('.wize/solutioning/architecture.md')) return '3-solutioning (architecture pending)';
101
+ if (!dirExists(path.join(projectRoot, '.wize/solutioning/stories')) ||
102
+ listFilesUnder(path.join(projectRoot, '.wize/solutioning/stories'), /\.md$/).length === 0)
103
+ return '3-solutioning (stories pending)';
104
+ if (!has('.wize/implementation/tea/risk-profile.md')) return '3-closeout (risk profile pending)';
105
+ if (!has('.wize/implementation/sprint-status.md')) return '4-implementation (sprint planning pending)';
106
+ return '4-implementation';
107
+ }
108
+
109
+ function gateStats(projectRoot) {
110
+ const root = path.join(projectRoot, '.wize/implementation/tea');
111
+ const files = listFilesUnder(root, /^gate\.md$/);
112
+ const stats = { PASS: 0, CONCERNS: 0, FAIL: 0, WAIVED: 0, total: files.length };
113
+ for (const f of files) {
114
+ const s = parseGateStatus(readSafe(f));
115
+ if (s && stats[s] !== undefined) stats[s]++;
116
+ }
117
+ return stats;
118
+ }
119
+
120
+ function knowledgeStatus(projectRoot) {
121
+ const root = path.join(projectRoot, '.wize/knowledge/document-project');
122
+ const exists = dirExists(root);
123
+ if (!exists) return { exists: false };
124
+ const files = ['overview.md', 'architecture-snapshot.md', 'conventions.md', 'dependencies.md', 'risk-spots.md']
125
+ .map(name => path.join(root, name))
126
+ .filter(fileExists);
127
+ const refreshed = files.map(f => ({
128
+ name: path.basename(f),
129
+ days: daysAgo(parseLastRefreshed(readSafe(f)))
130
+ }));
131
+ const pendingFile = path.join(root, '_pending.md');
132
+ const pendingLines = fileExists(pendingFile)
133
+ ? readSafe(pendingFile).split('\n').filter(l => l.trim() && !l.startsWith('#')).length
134
+ : 0;
135
+
136
+ const indexPath = path.join(root, 'index.md');
137
+ const indexContent = fileExists(indexPath) ? readSafe(indexPath) : '';
138
+ const toBeGeneratedMarkers = (indexContent.match(/_\(To be generated\)_/g) || []).length;
139
+
140
+ const statePath = path.join(root, 'project-scan-report.json');
141
+ const stateExists = fileExists(statePath);
142
+ const stateContent = stateExists ? readSafe(statePath) : '';
143
+ let stateAgeDays = null;
144
+ try {
145
+ const state = JSON.parse(stateContent);
146
+ stateAgeDays = daysAgo(state.timestamps && state.timestamps.last_updated);
147
+ } catch (_) {}
148
+
149
+ return { exists: true, files: refreshed, pendingLines, toBeGeneratedMarkers, stateExists, stateAgeDays };
150
+ }
151
+
152
+ function gitInfo(projectRoot) {
153
+ const dotGit = path.join(projectRoot, '.git');
154
+ if (!dirExists(dotGit)) return { isRepo: false };
155
+ let branch = '?'; let head = '?';
156
+ try {
157
+ const HEAD = readSafe(path.join(dotGit, 'HEAD')).trim();
158
+ if (HEAD.startsWith('ref: ')) {
159
+ branch = HEAD.slice(5).replace('refs/heads/', '');
160
+ } else {
161
+ head = HEAD.slice(0, 7);
162
+ }
163
+ } catch (_) {}
164
+ return { isRepo: true, branch, head };
165
+ }
166
+
167
+ function severityIcon(level) {
168
+ return level === 'error' ? '✖' : level === 'warn' ? '⚠' : 'ℹ';
169
+ }
170
+
171
+ async function cmdDoctor({ kitRoot, projectRoot, opts = {} } = {}) {
172
+ const log = opts.log || console.log;
173
+ const cwd = projectRoot;
174
+ const cfg = loadProjectConfig(cwd);
175
+ const installed = loadInstalledKitVersion(kitRoot);
176
+ const phase = detectPhase(cwd);
177
+ const gates = gateStats(cwd);
178
+ const knowledge = knowledgeStatus(cwd);
179
+ const git = gitInfo(cwd);
180
+ const targets = (cfg.install && cfg.install.ide_targets) || [];
181
+ const profiles = (cfg.install && cfg.install.profiles) || [];
182
+ const harnesses = detectHarnessCli({ preferIde: targets });
183
+
184
+ // Try registry — best-effort, never blocks.
185
+ let registryLatest = null;
186
+ try { registryLatest = await getLatestVersion(); } catch (_) {}
187
+
188
+ const suggestions = [];
189
+
190
+ // -- Section: Kit --
191
+ log('');
192
+ log('Wize Dev Kit — Doctor');
193
+ log('─────────────────────');
194
+ log(`Kit version (installed): ${installed || '?'}`);
195
+ log(`Kit version (project): ${cfg.project && cfg.project.kit_version || '— (no install)'}`);
196
+ log(`Kit version (registry): ${registryLatest || '(offline or skipped)'}`);
197
+ if (installed && cfg.project && cfg.project.kit_version && installed !== cfg.project.kit_version) {
198
+ suggestions.push({ level: 'warn', text: `Project pinned to ${cfg.project.kit_version} but ${installed} is installed. Run \`npx wize-dev-kit update\` to refresh adapters.` });
199
+ }
200
+ if (registryLatest && installed && semverGreater(registryLatest, installed)) {
201
+ suggestions.push({ level: 'info', text: `Registry has ${registryLatest}; you're on ${installed}. Run \`npx wize-dev-kit@latest update\` to pick it up.` });
202
+ }
203
+
204
+ // -- Section: Project --
205
+ log('');
206
+ log('Project');
207
+ log('───────');
208
+ if (!cfg.project) {
209
+ log('No .wize/config/project.toml — kit is not installed here.');
210
+ suggestions.push({ level: 'error', text: 'Run `npx wize-dev-kit install` to set the kit up in this repo.' });
211
+ } else {
212
+ log(`Name: ${cfg.project.name || '?'}`);
213
+ log(`Profiles: ${profiles.join(', ') || '(none)'}`);
214
+ log(`IDE targets: ${targets.join(', ') || '(none)'}`);
215
+ log(`Communication lang: ${cfg.language && cfg.language.communication || '?'}`);
216
+ log(`Document lang: ${cfg.language && cfg.language.document_output || '?'}`);
217
+ log(`Current phase: ${phase}`);
218
+ }
219
+
220
+ // -- Section: Adapters --
221
+ if (cfg.install) {
222
+ log('');
223
+ log('IDE Adapters');
224
+ log('────────────');
225
+ for (const t of targets) {
226
+ const dir = adapterTargetPath(t, cwd);
227
+ const count = countAdapterFiles(t, cwd);
228
+ const status = count > 0 ? `✓ ${count} files` : '✖ none';
229
+ log(` ${t.padEnd(14)} ${status.padEnd(15)} ${dir ? path.relative(cwd, dir) : '(no path)'}`);
230
+ if (count === 0) suggestions.push({ level: 'warn', text: `Adapter "${t}" has no rendered files. Run \`npx wize-dev-kit sync\`.` });
231
+ }
232
+ }
233
+
234
+ // -- Section: TEA gates --
235
+ if (gates.total > 0) {
236
+ log('');
237
+ log('TEA gates');
238
+ log('─────────');
239
+ log(`Total gate.md files: ${gates.total}`);
240
+ log(`PASS: ${gates.PASS}`);
241
+ log(`CONCERNS: ${gates.CONCERNS}`);
242
+ log(`FAIL: ${gates.FAIL}`);
243
+ log(`WAIVED: ${gates.WAIVED}`);
244
+ if (gates.FAIL > 0) suggestions.push({ level: 'error', text: `${gates.FAIL} story gate(s) at FAIL. Stories must not merge until resolved (advisory mode) or are blocking (enforcing mode).` });
245
+ if (gates.CONCERNS > 0) suggestions.push({ level: 'warn', text: `${gates.CONCERNS} story gate(s) at CONCERNS. Review findings before next sprint.` });
246
+ }
247
+
248
+ // -- Section: Knowledge --
249
+ if (knowledge.exists) {
250
+ log('');
251
+ log('Knowledge baseline (`document-project/`)');
252
+ log('────────────────────────────────────────');
253
+ for (const f of knowledge.files) {
254
+ const age = f.days == null ? 'no last_refreshed' : `${f.days}d ago`;
255
+ log(` ${f.name.padEnd(28)} ${age}`);
256
+ if (f.days != null && f.days > 60) {
257
+ suggestions.push({ level: 'warn', text: `\`${f.name}\` last refreshed ${f.days}d ago. Run \`/wize-refresh-knowledge\` after current sprint.` });
258
+ }
259
+ }
260
+ if (knowledge.pendingLines > 0) {
261
+ log(` _pending.md: ${knowledge.pendingLines} inline note(s) waiting consolidation`);
262
+ if (knowledge.pendingLines >= 5) {
263
+ suggestions.push({ level: 'info', text: `${knowledge.pendingLines} notes piled up in _pending.md. Time to run \`/wize-refresh-knowledge\`.` });
264
+ }
265
+ }
266
+ const markerText = knowledge.toBeGeneratedMarkers > 0 ? `${knowledge.toBeGeneratedMarkers} marker(s)` : 'none';
267
+ log(` To be generated markers: ${markerText}`);
268
+ if (knowledge.toBeGeneratedMarkers >= 5) {
269
+ suggestions.push({ level: 'warn', text: `${knowledge.toBeGeneratedMarkers} docs marked "To be generated" in index.md. Run \`wize-dev-kit document-project initial_scan deep\` to fill them.` });
270
+ }
271
+ const stateText = knowledge.stateExists
272
+ ? (knowledge.stateAgeDays == null ? 'project-scan-report.json exists (age unknown)' : `project-scan-report.json ${knowledge.stateAgeDays}d old`)
273
+ : 'no project-scan-report.json';
274
+ log(` Scan state: ${stateText}`);
275
+ if (!knowledge.stateExists) {
276
+ suggestions.push({ level: 'info', text: 'No scan state file found. Run `wize-dev-kit document-project quick` to create a baseline + state.' });
277
+ }
278
+ }
279
+
280
+ // -- Section: Harness CLIs --
281
+ log('');
282
+ log('AI Harness CLIs on PATH');
283
+ log('───────────────────────');
284
+ if (harnesses.length === 0) {
285
+ log(' (none detected)');
286
+ suggestions.push({ level: 'info', text: 'No harness CLI detected. Brownfield baseline + auto-run features only work in your IDE; the headless flow is unavailable.' });
287
+ } else {
288
+ for (const h of harnesses) log(` ${h.binary.padEnd(10)} ${h.path}`);
289
+ }
290
+
291
+ // -- Section: Git --
292
+ log('');
293
+ log('Git');
294
+ log('───');
295
+ if (!git.isRepo) {
296
+ log(' (not a git repo)');
297
+ suggestions.push({ level: 'warn', text: 'Not a git repository. Run `git init` before installing the kit so version history is recorded.' });
298
+ } else {
299
+ log(` branch: ${git.branch}`);
300
+ log(` head: ${git.head}`);
301
+ }
302
+
303
+ // -- Section: Suggestions --
304
+ log('');
305
+ log('Suggestions');
306
+ log('───────────');
307
+ if (suggestions.length === 0) {
308
+ log(' ✓ Everything looks good.');
309
+ } else {
310
+ for (const s of suggestions) log(` ${severityIcon(s.level)} ${s.text}`);
311
+ }
312
+ log('');
313
+
314
+ return { suggestions, phase, gates, knowledge, targets, profiles, installed, registryLatest };
315
+ }
316
+
317
+ module.exports = {
318
+ cmdDoctor,
319
+ // exported for tests:
320
+ detectPhase, gateStats, knowledgeStatus, gitInfo, adapterTargetPath, countAdapterFiles
321
+ };