wize-dev-kit 0.2.5 → 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 +62 -1
- package/README.md +4 -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 +319 -0
- 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 +49 -30
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
// Quick baseline mode for `wize-dev-kit document-project`.
|
|
2
|
+
//
|
|
3
|
+
// Produces the 6 lightweight baseline files. Does not read source files.
|
|
4
|
+
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const fs = require('node:fs');
|
|
8
|
+
const path = require('node:path');
|
|
9
|
+
|
|
10
|
+
const BASELINE_FILES = {
|
|
11
|
+
'overview.md': overviewMarkdown,
|
|
12
|
+
'architecture-snapshot.md': architectureMarkdown,
|
|
13
|
+
'conventions.md': conventionsMarkdown,
|
|
14
|
+
'dependencies.md': dependenciesMarkdown,
|
|
15
|
+
'risk-spots.md': riskMarkdown,
|
|
16
|
+
'open-questions.md': questionsMarkdown
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
function now() {
|
|
20
|
+
return new Date().toISOString().slice(0, 10);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function readPackage(root) {
|
|
24
|
+
try {
|
|
25
|
+
return JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf-8'));
|
|
26
|
+
} catch {
|
|
27
|
+
return {};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function countLines(root) {
|
|
32
|
+
let total = 0;
|
|
33
|
+
const dirs = ['src', 'tools', 'adapters', 'schemas', 'test'];
|
|
34
|
+
for (const dir of dirs) {
|
|
35
|
+
const full = path.join(root, dir);
|
|
36
|
+
if (!fs.existsSync(full)) continue;
|
|
37
|
+
total += walkLines(full);
|
|
38
|
+
}
|
|
39
|
+
return total;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function walkLines(dir) {
|
|
43
|
+
let total = 0;
|
|
44
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
45
|
+
for (const e of entries) {
|
|
46
|
+
const full = path.join(dir, e.name);
|
|
47
|
+
if (e.isDirectory()) total += walkLines(full);
|
|
48
|
+
else if (e.isFile() && /\.(js|md|yaml|json)$/.test(e.name)) {
|
|
49
|
+
const content = fs.readFileSync(full, 'utf-8');
|
|
50
|
+
total += content.split('\n').length;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return total;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function recentCommitCount(root) {
|
|
57
|
+
// Avoid shelling out; return 0 if not a git repo or git unavailable.
|
|
58
|
+
// Caller can overlay a real count from CLI.
|
|
59
|
+
return 0;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function overviewMarkdown(root, pkg) {
|
|
63
|
+
return `---
|
|
64
|
+
status: baseline
|
|
65
|
+
owner: Pepper Potts + Peggy Carter
|
|
66
|
+
created: ${now()}
|
|
67
|
+
last_refreshed: ${now()}
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
# Overview
|
|
71
|
+
|
|
72
|
+
**Project:** ${pkg.name || path.basename(root)}
|
|
73
|
+
**What it is:** ${pkg.description || 'Project documented by Wize Dev Kit.'}
|
|
74
|
+
**Current version:** ${pkg.version || 'unknown'}
|
|
75
|
+
|
|
76
|
+
## Size
|
|
77
|
+
|
|
78
|
+
- Source lines of code: ~${countLines(root)} LOC.
|
|
79
|
+
- Runtime dependencies: ${Object.keys(pkg.dependencies || {}).length}.
|
|
80
|
+
- Dev dependencies: ${Object.keys(pkg.devDependencies || {}).length}.
|
|
81
|
+
|
|
82
|
+
## What it ships
|
|
83
|
+
|
|
84
|
+
- See architecture-snapshot.md for components and entry points.
|
|
85
|
+
- See conventions.md for coding patterns.
|
|
86
|
+
- See dependencies.md for runtime and dev dependency roles.
|
|
87
|
+
`;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function architectureMarkdown() {
|
|
91
|
+
return `---
|
|
92
|
+
status: baseline
|
|
93
|
+
owner: Pepper Potts + Tony Stark
|
|
94
|
+
created: ${now()}
|
|
95
|
+
last_refreshed: ${now()}
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
# Architecture Snapshot
|
|
99
|
+
|
|
100
|
+
## Entry points
|
|
101
|
+
|
|
102
|
+
- Documented after a deeper scan (initial_scan mode).
|
|
103
|
+
|
|
104
|
+
## Components
|
|
105
|
+
|
|
106
|
+
- Run \`wize-dev-kit document-project initial_scan deep\` for component-level detail.
|
|
107
|
+
|
|
108
|
+
## Integration surface
|
|
109
|
+
|
|
110
|
+
- See dependencies.md for external integrations.
|
|
111
|
+
`;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function conventionsMarkdown() {
|
|
115
|
+
return `---
|
|
116
|
+
status: baseline
|
|
117
|
+
owner: Peggy Carter
|
|
118
|
+
created: ${now()}
|
|
119
|
+
last_refreshed: ${now()}
|
|
120
|
+
sampled: "pending deeper scan"
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
# Conventions (observed, not prescribed)
|
|
124
|
+
|
|
125
|
+
## Quick notes
|
|
126
|
+
|
|
127
|
+
- Run \`wize-dev-kit document-project initial_scan deep\` to sample files and fill this doc.
|
|
128
|
+
`;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function dependenciesMarkdown(root, pkg) {
|
|
132
|
+
const runtime = Object.entries(pkg.dependencies || {})
|
|
133
|
+
.map(([name, version]) => `| ${name} | ${version} | | |`).join('\n');
|
|
134
|
+
const dev = Object.entries(pkg.devDependencies || {})
|
|
135
|
+
.map(([name, version]) => `| ${name} | ${version} | | |`).join('\n');
|
|
136
|
+
|
|
137
|
+
return `---
|
|
138
|
+
status: baseline
|
|
139
|
+
owner: Pepper Potts
|
|
140
|
+
created: ${now()}
|
|
141
|
+
last_refreshed: ${now()}
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
# Dependencies
|
|
145
|
+
|
|
146
|
+
## Runtime
|
|
147
|
+
|
|
148
|
+
| Name | Version | Role in this repo | Load-bearing? |
|
|
149
|
+
|---|---|---|---|
|
|
150
|
+
${runtime || '| — | — | — | — |'}
|
|
151
|
+
|
|
152
|
+
## Dev / bundled
|
|
153
|
+
|
|
154
|
+
| Name | Version | Role in this repo | Load-bearing? |
|
|
155
|
+
|---|---|---|---|
|
|
156
|
+
${dev || '| — | — | — | — |'}
|
|
157
|
+
`;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function riskMarkdown() {
|
|
161
|
+
return `---
|
|
162
|
+
status: baseline
|
|
163
|
+
owner: Pepper Potts + Tony Stark
|
|
164
|
+
created: ${now()}
|
|
165
|
+
last_refreshed: ${now()}
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
# Risk Spots
|
|
169
|
+
|
|
170
|
+
| Area | Symptom | Likely cause | Confidence |
|
|
171
|
+
|---|---|---|---|
|
|
172
|
+
| | | | |
|
|
173
|
+
|
|
174
|
+
Run \`wize-dev-kit document-project initial_scan deep\` to populate risk spots.
|
|
175
|
+
`;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function questionsMarkdown() {
|
|
179
|
+
return `---
|
|
180
|
+
status: baseline
|
|
181
|
+
owner: Pepper Potts + Peggy Carter
|
|
182
|
+
created: ${now()}
|
|
183
|
+
last_refreshed: ${now()}
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
# Open Questions
|
|
187
|
+
|
|
188
|
+
| Question | Why it matters | Owner to ask |
|
|
189
|
+
|---|---|---|
|
|
190
|
+
| | | |
|
|
191
|
+
`;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function runQuick(projectRoot, opts = {}) {
|
|
195
|
+
const pkg = readPackage(projectRoot);
|
|
196
|
+
const dir = path.join(projectRoot, '.wize', 'knowledge', 'document-project');
|
|
197
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
198
|
+
|
|
199
|
+
const written = [];
|
|
200
|
+
for (const [name, factory] of Object.entries(BASELINE_FILES)) {
|
|
201
|
+
const file = path.join(dir, name);
|
|
202
|
+
const content = factory(projectRoot, pkg);
|
|
203
|
+
fs.writeFileSync(file, content, 'utf-8');
|
|
204
|
+
written.push(name);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (opts.log) opts.log(`Quick baseline written to ${dir}`);
|
|
208
|
+
return { changed: true, mode: 'quick', written };
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
module.exports = { runQuick, BASELINE_FILES, countLines };
|
|
@@ -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,10 +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');
|
|
22
|
+
const { cmdDoctor } = require('./commands/doctor.js');
|
|
23
|
+
const { cmdDocumentProject } = require('./commands/document-project.js');
|
|
23
24
|
|
|
24
25
|
const INTERACTIVE = process.stdout.isTTY && process.stdin.isTTY;
|
|
25
26
|
|
|
@@ -72,6 +73,8 @@ Commands:
|
|
|
72
73
|
agent <create|list> Manage agents (built-in or custom).
|
|
73
74
|
workflow <create|list> Manage workflows.
|
|
74
75
|
validate Run schema + lint + dry-run validators.
|
|
76
|
+
doctor Diagnose the kit + project state, suggest fixes.
|
|
77
|
+
document-project Document the current repo (quick | initial_scan | full_rescan | deep_dive).
|
|
75
78
|
help Show this message.
|
|
76
79
|
|
|
77
80
|
Documentation:
|
|
@@ -135,6 +138,23 @@ async function confirm(question, defaultYes = true) {
|
|
|
135
138
|
return ans.startsWith('y');
|
|
136
139
|
}
|
|
137
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
|
+
|
|
138
158
|
async function selectLanguage(label, defaultCode = 'en') {
|
|
139
159
|
if (INTERACTIVE) {
|
|
140
160
|
const choices = LANGUAGES.map(l => ({
|
|
@@ -417,35 +437,26 @@ async function cmdInstall(args) {
|
|
|
417
437
|
}
|
|
418
438
|
|
|
419
439
|
if (detection.brownfield) {
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
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 } });
|
|
429
458
|
} else {
|
|
430
|
-
|
|
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
|
-
}
|
|
459
|
+
console.log('\nSkipped documentation. Run `wize-dev-kit document-project` later.');
|
|
449
460
|
}
|
|
450
461
|
}
|
|
451
462
|
}
|
|
@@ -540,7 +551,7 @@ function cmdValidate() {
|
|
|
540
551
|
// for `update` (already updating), `install` (already setting up), `uninstall`
|
|
541
552
|
// (already leaving), `validate` (developer-tool), and `version` (the user is
|
|
542
553
|
// already asking about versions).
|
|
543
|
-
const HINT_COMMANDS = new Set(['list', 'sync', 'agent', 'workflow', 'help']);
|
|
554
|
+
const HINT_COMMANDS = new Set(['list', 'sync', 'agent', 'workflow', 'help', 'doctor', 'document-project']);
|
|
544
555
|
|
|
545
556
|
async function main() {
|
|
546
557
|
const [cmd, ...rest] = process.argv.slice(2);
|
|
@@ -561,6 +572,14 @@ async function main() {
|
|
|
561
572
|
case 'agent': return cmdAgent(rest);
|
|
562
573
|
case 'workflow': return cmdWorkflow(rest);
|
|
563
574
|
case 'validate': return cmdValidate();
|
|
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
|
+
});
|
|
564
583
|
case 'version':
|
|
565
584
|
case '--version':
|
|
566
585
|
case '-v':
|