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.
- package/AGENTS.md +21 -0
- package/ARCH.md +40 -4
- package/CHANGELOG.md +26 -0
- package/README.md +3 -1
- package/package.json +3 -2
- package/src/method-skills/1-analysis/wize-document-project/documentation-requirements.csv +12 -0
- package/src/method-skills/1-analysis/wize-document-project/templates/api-contracts-template.md +38 -0
- package/src/method-skills/1-analysis/wize-document-project/templates/architecture-template.md +54 -0
- package/src/method-skills/1-analysis/wize-document-project/templates/component-inventory-template.md +40 -0
- package/src/method-skills/1-analysis/wize-document-project/templates/contribution-guide-template.md +34 -0
- package/src/method-skills/1-analysis/wize-document-project/templates/data-models-template.md +36 -0
- package/src/method-skills/1-analysis/wize-document-project/templates/deep-dive-template.md +312 -0
- package/src/method-skills/1-analysis/wize-document-project/templates/deployment-guide-template.md +42 -0
- package/src/method-skills/1-analysis/wize-document-project/templates/development-guide-template.md +61 -0
- package/src/method-skills/1-analysis/wize-document-project/templates/index-template.md +185 -0
- package/src/method-skills/1-analysis/wize-document-project/templates/project-overview-template.md +110 -0
- package/src/method-skills/1-analysis/wize-document-project/templates/project-scan-report-schema.json +159 -0
- package/src/method-skills/1-analysis/wize-document-project/templates/source-tree-template.md +142 -0
- package/src/method-skills/1-analysis/wize-document-project/workflow.md +23 -0
- package/src/tea-skills/wize-tea-risk/workflow.md +11 -0
- package/tools/installer/commands/doctor.js +27 -1
- package/tools/installer/commands/document-project.js +93 -0
- package/tools/installer/document-project/batch-scanner.js +93 -0
- package/tools/installer/document-project/classify.js +170 -0
- package/tools/installer/document-project/modes/deep-dive.js +196 -0
- package/tools/installer/document-project/modes/full-rescan.js +15 -0
- package/tools/installer/document-project/modes/initial-scan.js +100 -0
- package/tools/installer/document-project/modes/quick.js +211 -0
- package/tools/installer/document-project/render-index.js +101 -0
- package/tools/installer/document-project/state.js +110 -0
- 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
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
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
|
-
|
|
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':
|