wize-dev-kit 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/AGENTS.md +21 -0
  2. package/ARCH.md +40 -4
  3. package/CHANGELOG.md +26 -0
  4. package/README.md +3 -1
  5. package/package.json +3 -2
  6. package/src/method-skills/1-analysis/wize-document-project/documentation-requirements.csv +12 -0
  7. package/src/method-skills/1-analysis/wize-document-project/templates/api-contracts-template.md +38 -0
  8. package/src/method-skills/1-analysis/wize-document-project/templates/architecture-template.md +54 -0
  9. package/src/method-skills/1-analysis/wize-document-project/templates/component-inventory-template.md +40 -0
  10. package/src/method-skills/1-analysis/wize-document-project/templates/contribution-guide-template.md +34 -0
  11. package/src/method-skills/1-analysis/wize-document-project/templates/data-models-template.md +36 -0
  12. package/src/method-skills/1-analysis/wize-document-project/templates/deep-dive-template.md +312 -0
  13. package/src/method-skills/1-analysis/wize-document-project/templates/deployment-guide-template.md +42 -0
  14. package/src/method-skills/1-analysis/wize-document-project/templates/development-guide-template.md +61 -0
  15. package/src/method-skills/1-analysis/wize-document-project/templates/index-template.md +185 -0
  16. package/src/method-skills/1-analysis/wize-document-project/templates/project-overview-template.md +110 -0
  17. package/src/method-skills/1-analysis/wize-document-project/templates/project-scan-report-schema.json +159 -0
  18. package/src/method-skills/1-analysis/wize-document-project/templates/source-tree-template.md +142 -0
  19. package/src/method-skills/1-analysis/wize-document-project/workflow.md +23 -0
  20. package/src/tea-skills/wize-tea-risk/workflow.md +11 -0
  21. package/tools/installer/commands/doctor.js +27 -1
  22. package/tools/installer/commands/document-project.js +93 -0
  23. package/tools/installer/document-project/batch-scanner.js +93 -0
  24. package/tools/installer/document-project/classify.js +170 -0
  25. package/tools/installer/document-project/modes/deep-dive.js +196 -0
  26. package/tools/installer/document-project/modes/full-rescan.js +15 -0
  27. package/tools/installer/document-project/modes/initial-scan.js +100 -0
  28. package/tools/installer/document-project/modes/quick.js +211 -0
  29. package/tools/installer/document-project/render-index.js +101 -0
  30. package/tools/installer/document-project/state.js +110 -0
  31. package/tools/installer/wize-cli.js +46 -30
@@ -0,0 +1,101 @@
1
+ // Master index renderer for `wize-dev-kit document-project`.
2
+ //
3
+ // Generates `.wize/knowledge/document-project/index.md` linking all docs.
4
+
5
+ 'use strict';
6
+
7
+ const fs = require('node:fs');
8
+ const path = require('node:path');
9
+
10
+ function link(name, file) {
11
+ return `- [${name}](./${file})`;
12
+ }
13
+
14
+ function linkWithMarker(name, file, exists) {
15
+ const base = link(name, file);
16
+ return exists ? base : `${base} _(To be generated)_`;
17
+ }
18
+
19
+ function renderIndex(projectRoot, { projectTypes = [], parts = [], generated = [], existing = [], deepDiveFiles = [] } = {}) {
20
+ const dir = path.join(projectRoot, '.wize', 'knowledge', 'document-project');
21
+ fs.mkdirSync(dir, { recursive: true });
22
+
23
+ const generatedSet = new Set(generated.map(g => path.basename(g)));
24
+ const existingSet = new Set(existing.map(e => path.basename(e)));
25
+ const has = name => generatedSet.has(name) || existingSet.has(name);
26
+
27
+ const isMultiPart = parts.length >= 2;
28
+ const primaryType = projectTypes[0] || 'unknown';
29
+
30
+ const lines = [
31
+ '---',
32
+ 'status: baseline',
33
+ 'owner: Pepper Potts + Peggy Carter',
34
+ `created: ${new Date().toISOString().slice(0, 10)}`,
35
+ `last_refreshed: ${new Date().toISOString().slice(0, 10)}`,
36
+ '---',
37
+ '',
38
+ '# Project Documentation Index',
39
+ '',
40
+ `**Type:** ${isMultiPart ? 'multi-part' : primaryType}`,
41
+ `**Primary project type(s):** ${projectTypes.join(', ') || 'unknown'}`,
42
+ '',
43
+ '## Generated Documentation',
44
+ '',
45
+ link('Project Overview', 'project-overview.md'),
46
+ linkWithMarker('Source Tree Analysis', 'source-tree-analysis.md', has('source-tree-analysis.md')),
47
+ ];
48
+
49
+ if (isMultiPart) {
50
+ for (const part of parts) {
51
+ const suffix = part.part_id === 'root' ? '' : `-${part.part_id}`;
52
+ lines.push(linkWithMarker(`Architecture — ${part.part_id || 'root'}`, `architecture${suffix}.md`, has(`architecture${suffix}.md`)));
53
+ lines.push(linkWithMarker(`Development Guide — ${part.part_id || 'root'}`, `development-guide${suffix}.md`, has(`development-guide${suffix}.md`)));
54
+ lines.push(linkWithMarker(`Component Inventory — ${part.part_id || 'root'}`, `component-inventory${suffix}.md`, has(`component-inventory${suffix}.md`)));
55
+ lines.push(linkWithMarker(`API Contracts — ${part.part_id || 'root'}`, `api-contracts${suffix}.md`, has(`api-contracts${suffix}.md`)));
56
+ lines.push(linkWithMarker(`Data Models — ${part.part_id || 'root'}`, `data-models${suffix}.md`, has(`data-models${suffix}.md`)));
57
+ }
58
+ lines.push(linkWithMarker('Integration Architecture', 'integration-architecture.md', has('integration-architecture.md')));
59
+ } else {
60
+ lines.push(linkWithMarker('Architecture', 'architecture.md', has('architecture.md')));
61
+ lines.push(linkWithMarker('Development Guide', 'development-guide.md', has('development-guide.md')));
62
+ lines.push(linkWithMarker('Component Inventory', 'component-inventory.md', has('component-inventory.md')));
63
+ lines.push(linkWithMarker('API Contracts', 'api-contracts.md', has('api-contracts.md')));
64
+ lines.push(linkWithMarker('Data Models', 'data-models.md', has('data-models.md')));
65
+ }
66
+
67
+ lines.push(linkWithMarker('Deployment Guide', 'deployment-guide.md', has('deployment-guide.md')));
68
+ lines.push(linkWithMarker('Contribution Guide', 'contribution-guide.md', has('contribution-guide.md')));
69
+ if (deepDiveFiles.length) {
70
+ lines.push('', '## Deep-Dive Docs', '');
71
+ for (const f of deepDiveFiles) {
72
+ lines.push(link(f.replace(/^deep-dive-/, '').replace(/\.md$/, ''), f));
73
+ }
74
+ } else {
75
+ lines.push(linkWithMarker('Deep-Dive Docs', 'deep-dive/', false)); // directory marker
76
+ }
77
+
78
+ if (existing.length) {
79
+ lines.push('', '## Existing Documentation', '');
80
+ for (const doc of existing) {
81
+ const rel = path.relative(dir, doc);
82
+ lines.push(`- [${path.basename(doc)}](./${rel})`);
83
+ }
84
+ }
85
+
86
+ lines.push('', '## Brownfield Baseline', '');
87
+ lines.push(link('Overview', 'overview.md'));
88
+ lines.push(link('Architecture Snapshot', 'architecture-snapshot.md'));
89
+ lines.push(link('Conventions', 'conventions.md'));
90
+ lines.push(link('Dependencies', 'dependencies.md'));
91
+ lines.push(link('Risk Spots', 'risk-spots.md'));
92
+ lines.push(link('Open Questions', 'open-questions.md'));
93
+
94
+ lines.push('', '---', '', '_Generated by `wize-document-project`._', '');
95
+
96
+ const file = path.join(dir, 'index.md');
97
+ fs.writeFileSync(file, lines.join('\n'), 'utf-8');
98
+ return { changed: true, written: ['index.md'] };
99
+ }
100
+
101
+ module.exports = { renderIndex, link, linkWithMarker };
@@ -0,0 +1,110 @@
1
+ // State file management for `wize-dev-kit document-project`.
2
+ //
3
+ // Tracks scan progress so long-running deep/exhaustive scans can resume.
4
+
5
+ 'use strict';
6
+
7
+ const fs = require('node:fs');
8
+ const path = require('node:path');
9
+
10
+ const WORKFLOW_VERSION = '0.3.1';
11
+ const STATE_FILE = 'project-scan-report.json';
12
+ const ARCHIVE_DIR = '_archive';
13
+
14
+ function nowIso() {
15
+ return new Date().toISOString();
16
+ }
17
+
18
+ function statePath(projectRoot) {
19
+ return path.join(projectRoot, '.wize', 'knowledge', 'document-project', STATE_FILE);
20
+ }
21
+
22
+ function archivePath(projectRoot, timestamp) {
23
+ const dir = path.join(projectRoot, '.wize', 'knowledge', 'document-project', ARCHIVE_DIR);
24
+ fs.mkdirSync(dir, { recursive: true });
25
+ const safe = timestamp.replace(/[:.]/g, '-');
26
+ return path.join(dir, `project-scan-report-${safe}.json`);
27
+ }
28
+
29
+ function initState(projectRoot, mode, scanLevel) {
30
+ const state = {
31
+ workflow_version: WORKFLOW_VERSION,
32
+ timestamps: { started: nowIso(), last_updated: nowIso() },
33
+ mode,
34
+ scan_level: scanLevel,
35
+ project_root: projectRoot,
36
+ project_knowledge: path.join(projectRoot, '.wize', 'knowledge', 'document-project'),
37
+ completed_steps: [],
38
+ current_step: 'step_1',
39
+ findings: {},
40
+ outputs_generated: [STATE_FILE],
41
+ resume_instructions: `Starting ${mode} (${scanLevel}) from step_1`
42
+ };
43
+ writeState(projectRoot, state);
44
+ return state;
45
+ }
46
+
47
+ function loadState(projectRoot) {
48
+ const p = statePath(projectRoot);
49
+ if (!fs.existsSync(p)) return null;
50
+ try {
51
+ const content = fs.readFileSync(p, 'utf-8');
52
+ const state = JSON.parse(content);
53
+ if (!state.workflow_version || !state.timestamps || !state.mode || !state.scan_level) {
54
+ return null;
55
+ }
56
+ return state;
57
+ } catch {
58
+ return null;
59
+ }
60
+ }
61
+
62
+ function writeState(projectRoot, state) {
63
+ const p = statePath(projectRoot);
64
+ fs.mkdirSync(path.dirname(p), { recursive: true });
65
+ state.timestamps.last_updated = nowIso();
66
+ fs.writeFileSync(p, JSON.stringify(state, null, 2), 'utf-8');
67
+ }
68
+
69
+ function updateState(projectRoot, patch) {
70
+ const state = loadState(projectRoot) || initState(projectRoot, 'quick', 'quick');
71
+ for (const key of Object.keys(patch)) {
72
+ const val = patch[key];
73
+ if (Array.isArray(val) && Array.isArray(state[key])) {
74
+ state[key].push(...val);
75
+ } else if (typeof val === 'object' && val !== null && !Array.isArray(val)) {
76
+ state[key] = { ...(state[key] || {}), ...val };
77
+ } else {
78
+ state[key] = val;
79
+ }
80
+ }
81
+ writeState(projectRoot, state);
82
+ return state;
83
+ }
84
+
85
+ function archiveOldState(projectRoot) {
86
+ const p = statePath(projectRoot);
87
+ if (!fs.existsSync(p)) return false;
88
+ const content = fs.readFileSync(p, 'utf-8');
89
+ const archived = archivePath(projectRoot, nowIso());
90
+ fs.writeFileSync(archived, content, 'utf-8');
91
+ fs.rmSync(p);
92
+ return true;
93
+ }
94
+
95
+ function stateAgeDays(state) {
96
+ if (!state || !state.timestamps || !state.timestamps.last_updated) return null;
97
+ const then = Date.parse(state.timestamps.last_updated);
98
+ if (Number.isNaN(then)) return null;
99
+ return Math.floor((Date.now() - then) / (24 * 3600 * 1000));
100
+ }
101
+
102
+ module.exports = {
103
+ statePath,
104
+ initState,
105
+ loadState,
106
+ updateState,
107
+ archiveOldState,
108
+ stateAgeDays,
109
+ WORKFLOW_VERSION
110
+ };
@@ -16,11 +16,11 @@ 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
19
  const { printUpdateHintIfAny } = require('./version-check.js');
21
20
  const { cmdSync: cmdSyncReal } = require('./commands/sync.js');
22
21
  const { cmdAgentList, cmdAgentCreate, cmdAgentEdit } = require('./commands/agent.js');
23
22
  const { cmdDoctor } = require('./commands/doctor.js');
23
+ const { cmdDocumentProject } = require('./commands/document-project.js');
24
24
 
25
25
  const INTERACTIVE = process.stdout.isTTY && process.stdin.isTTY;
26
26
 
@@ -74,6 +74,7 @@ Commands:
74
74
  workflow <create|list> Manage workflows.
75
75
  validate Run schema + lint + dry-run validators.
76
76
  doctor Diagnose the kit + project state, suggest fixes.
77
+ document-project Document the current repo (quick | initial_scan | full_rescan | deep_dive).
77
78
  help Show this message.
78
79
 
79
80
  Documentation:
@@ -137,6 +138,23 @@ async function confirm(question, defaultYes = true) {
137
138
  return ans.startsWith('y');
138
139
  }
139
140
 
141
+ async function select(label, choices, defaultValue) {
142
+ if (INTERACTIVE) {
143
+ const initial = choices.findIndex(c => c.value === defaultValue);
144
+ const { picked } = await prompts({
145
+ type: 'select',
146
+ name: 'picked',
147
+ message: label,
148
+ choices: choices.map(c => ({ title: c.title, value: c.value, description: c.description })),
149
+ initial: initial === -1 ? 0 : initial
150
+ });
151
+ if (picked === undefined) process.exit(130);
152
+ return picked;
153
+ }
154
+ // Non-TTY fallback: return default.
155
+ return defaultValue;
156
+ }
157
+
140
158
  async function selectLanguage(label, defaultCode = 'en') {
141
159
  if (INTERACTIVE) {
142
160
  const choices = LANGUAGES.map(l => ({
@@ -419,35 +437,26 @@ async function cmdInstall(args) {
419
437
  }
420
438
 
421
439
  if (detection.brownfield) {
422
- const baseline = await confirm('\nRun `wize-document-project` to baseline the existing repo now?', true);
423
- if (baseline) {
424
- const preferIde = targets.map(t => t.code);
425
- const harnesses = detectHarnessCli({ preferIde });
426
- if (process.env.WIZE_SKIP_BASELINE === '1') {
427
- console.log('\nWIZE_SKIP_BASELINE=1 not running the baseline.');
428
- console.log(manualInstructions(harnesses[0]));
429
- } else if (harnesses.length === 0) {
430
- console.log(manualInstructions(null));
440
+ if (process.env.WIZE_SKIP_BASELINE === '1') {
441
+ console.log('\nWIZE_SKIP_BASELINE=1 — not running the baseline.');
442
+ } else if (!INTERACTIVE) {
443
+ console.log('\nNon-interactive install detected; running quick baseline...');
444
+ cmdDocumentProject({ kitRoot: KIT_ROOT, projectRoot: cwd, args: ['quick'], opts: { log: console.log } });
445
+ } else {
446
+ const mode = await select(
447
+ 'Document the existing repo now?',
448
+ [
449
+ { title: 'Quick baseline (default, 6 files)', value: 'quick' },
450
+ { title: 'Initial scan (pattern + conditional docs)', value: 'initial_scan' },
451
+ { title: 'Full rescan (archive old state, re-run)', value: 'full_rescan' },
452
+ { title: 'Skip documentation for now', value: 'skip' }
453
+ ],
454
+ 'quick'
455
+ );
456
+ if (mode !== 'skip') {
457
+ cmdDocumentProject({ kitRoot: KIT_ROOT, projectRoot: cwd, args: [mode], opts: { log: console.log } });
431
458
  } else {
432
- const chosen = harnesses[0];
433
- console.log(`\nDetected harness: ${chosen.binary} (${chosen.path}).`);
434
- const confirmRun = await confirm(
435
- `Run /wize-document-project via ${chosen.binary} now?`,
436
- true
437
- );
438
- if (confirmRun) {
439
- const r = runHeadlessBaseline({
440
- harness: chosen,
441
- projectRoot: cwd,
442
- prompt: defaultPrompt()
443
- });
444
- if (!r.ok && !r.skipped) {
445
- console.log(`\n${chosen.binary} exited with code ${r.exitCode}. You can re-run later with:`);
446
- console.log(manualInstructions(chosen));
447
- }
448
- } else {
449
- console.log(manualInstructions(chosen));
450
- }
459
+ console.log('\nSkipped documentation. Run `wize-dev-kit document-project` later.');
451
460
  }
452
461
  }
453
462
  }
@@ -542,7 +551,7 @@ function cmdValidate() {
542
551
  // for `update` (already updating), `install` (already setting up), `uninstall`
543
552
  // (already leaving), `validate` (developer-tool), and `version` (the user is
544
553
  // already asking about versions).
545
- const HINT_COMMANDS = new Set(['list', 'sync', 'agent', 'workflow', 'help', 'doctor']);
554
+ const HINT_COMMANDS = new Set(['list', 'sync', 'agent', 'workflow', 'help', 'doctor', 'document-project']);
546
555
 
547
556
  async function main() {
548
557
  const [cmd, ...rest] = process.argv.slice(2);
@@ -564,6 +573,13 @@ async function main() {
564
573
  case 'workflow': return cmdWorkflow(rest);
565
574
  case 'validate': return cmdValidate();
566
575
  case 'doctor': return cmdDoctor({ kitRoot: KIT_ROOT, projectRoot: process.cwd() });
576
+ case 'document-project':
577
+ return cmdDocumentProject({
578
+ kitRoot: KIT_ROOT,
579
+ projectRoot: process.cwd(),
580
+ args: rest,
581
+ opts: { log: console.log }
582
+ });
567
583
  case 'version':
568
584
  case '--version':
569
585
  case '-v':