create-quiver 0.6.0 → 0.8.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.
- package/.claude/settings.local.json +45 -0
- package/.github/workflows/ci.yml +9 -32
- package/AGENTS.md.template +41 -0
- package/BACKLOG.md +139 -0
- package/CHANGELOG.md +17 -0
- package/README.md +68 -14
- package/README_FOR_AI.md +48 -16
- package/ROADMAP.md +100 -0
- package/docs/AI_CONTEXT.md.template +19 -26
- package/docs/AI_ONBOARDING_PROMPT.md.template +16 -0
- package/docs/COMMANDS.md.template +25 -0
- package/docs/CONTEXTO.md.template +4 -17
- package/docs/DECISIONS.md.template +18 -0
- package/docs/DEEP.md.template +34 -0
- package/docs/DOCUMENTATION_GUIDE.md.template +9 -7
- package/docs/GITFLOW_PR_GUIDE.md.template +7 -0
- package/docs/INDEX.md.template +11 -0
- package/docs/QUICK.md.template +27 -0
- package/docs/STANDARD.md.template +49 -0
- package/docs/STATUS.md.template +2 -2
- package/docs/SUPPORT_MATRIX.md.template +16 -4
- package/docs/TESTING_GUIDE_FOR_AI.md.template +4 -3
- package/docs/TROUBLESHOOTING.md.template +14 -0
- package/docs/WORKFLOW.md.template +21 -4
- package/docs/examples/graph.md.template +62 -0
- package/docs/examples/next.md.template +27 -0
- package/docs/examples/plan.md.template +28 -0
- package/package.json +6 -2
- package/package.template.json +16 -0
- package/scripts/check-slice-readiness.sh +6 -4
- package/scripts/cleanup-slice.sh +2 -172
- package/scripts/init-docs.sh +147 -26
- package/scripts/package-quiver.sh +5 -0
- package/scripts/start-slice.sh +3 -425
- package/specs/[project-name]/EVIDENCE_REPORT.md.template +3 -1
- package/specs/[project-name]/HANDOFF.md.template +37 -0
- package/specs/[project-name]/slices/slice-template/slice.json +7 -2
- package/specs/quiver-v08-agent-onboarding-analysis/slices/slice-01-project-scan-command/slice.json +1 -1
- package/specs/quiver-v08-agent-onboarding-analysis/slices/slice-02-ai-onboarding-prompt/slice.json +1 -1
- package/specs/quiver-v08-agent-onboarding-analysis/slices/slice-03-doctor-readme-adoption-flow/slice.json +1 -1
- package/specs/quiver-v12-cross-platform-native-runtime/EVIDENCE_REPORT.md +30 -0
- package/specs/quiver-v12-cross-platform-native-runtime/SPEC.md +86 -0
- package/specs/quiver-v12-cross-platform-native-runtime/STATUS.md +29 -0
- package/specs/quiver-v12-cross-platform-native-runtime/slices/slice-01-cross-platform-support-contract/slice.json +69 -0
- package/specs/quiver-v12-cross-platform-native-runtime/slices/slice-02-node-init-docs-runtime/slice.json +76 -0
- package/specs/quiver-v12-cross-platform-native-runtime/slices/slice-03-node-migrate-analyze-doctor-flow/slice.json +74 -0
- package/specs/quiver-v12-cross-platform-native-runtime/slices/slice-04-node-slice-lifecycle-commands/slice.json +81 -0
- package/specs/quiver-v12-cross-platform-native-runtime/slices/slice-05-generated-project-scripts-and-migration/slice.json +78 -0
- package/specs/quiver-v12-cross-platform-native-runtime/slices/slice-06-cross-platform-ci-release-readiness/slice.json +74 -0
- package/specs/quiver-v13-token-efficient-ai-context/EVIDENCE_REPORT.md +28 -0
- package/specs/quiver-v13-token-efficient-ai-context/SPEC.md +68 -0
- package/specs/quiver-v13-token-efficient-ai-context/STATUS.md +26 -0
- package/specs/quiver-v13-token-efficient-ai-context/slices/slice-01-token-efficient-ai-modes-guidance/slice.json +65 -0
- package/specs/quiver-v13-token-efficient-ai-context/slices/slice-02-decision-log-context-checkpoint/slice.json +64 -0
- package/specs/quiver-v13-token-efficient-ai-context/slices/slice-03-project-map-reading-order/slice.json +66 -0
- package/specs/quiver-v14-tiered-context-pack/EVIDENCE_REPORT.md +42 -0
- package/specs/quiver-v14-tiered-context-pack/SPEC.md +116 -0
- package/specs/quiver-v14-tiered-context-pack/STATUS.md +35 -0
- package/specs/quiver-v14-tiered-context-pack/slices/slice-01-tiered-context-pack/slice.json +77 -0
- package/specs/quiver-v14-tiered-context-pack/slices/slice-02-agents-md-router/slice.json +74 -0
- package/specs/quiver-v14-tiered-context-pack/slices/slice-03-active-slice-lifecycle/slice.json +74 -0
- package/specs/quiver-v14-tiered-context-pack/slices/slice-04-dedup-frontmatter/slice.json +83 -0
- package/specs/quiver-v14-tiered-context-pack/slices/slice-05-doctor-smokes-tiered-pack/slice.json +84 -0
- package/specs/quiver-v15-init-required-before-migrate/EVIDENCE_REPORT.md +26 -0
- package/specs/quiver-v15-init-required-before-migrate/SPEC.md +66 -0
- package/specs/quiver-v15-init-required-before-migrate/STATUS.md +26 -0
- package/specs/quiver-v15-init-required-before-migrate/slices/slice-01-migrate-initialization-precondition/slice.json +65 -0
- package/specs/quiver-v15-init-required-before-migrate/slices/slice-02-doctor-not-initialized-guidance/slice.json +61 -0
- package/specs/quiver-v15-init-required-before-migrate/slices/slice-03-docs-smokes-init-before-migrate/slice.json +64 -0
- package/specs/quiver-v16-handoff-contract/EVIDENCE_REPORT.md +26 -0
- package/specs/quiver-v16-handoff-contract/SPEC.md +68 -0
- package/specs/quiver-v16-handoff-contract/STATUS.md +26 -0
- package/specs/quiver-v16-handoff-contract/slices/slice-01-handoff-template-and-contract/slice.json +66 -0
- package/specs/quiver-v16-handoff-contract/slices/slice-02-check-handoff-command/slice.json +70 -0
- package/specs/quiver-v16-handoff-contract/slices/slice-03-handoff-scaffold-optional/slice.json +67 -0
- package/specs/quiver-v17-orchestration-foundation/EVIDENCE_REPORT.md +32 -0
- package/specs/quiver-v17-orchestration-foundation/SPEC.md +79 -0
- package/specs/quiver-v17-orchestration-foundation/STATUS.md +31 -0
- package/specs/quiver-v17-orchestration-foundation/slices/slice-01-ci-matrix-verified/slice.json +68 -0
- package/specs/quiver-v17-orchestration-foundation/slices/slice-02-slice-graph-library/slice.json +65 -0
- package/specs/quiver-v17-orchestration-foundation/slices/slice-03-depends-on-validation/slice.json +72 -0
- package/specs/quiver-v18-slice-orchestration/EVIDENCE_REPORT.md +38 -0
- package/specs/quiver-v18-slice-orchestration/SPEC.md +91 -0
- package/specs/quiver-v18-slice-orchestration/STATUS.md +33 -0
- package/specs/quiver-v18-slice-orchestration/slices/slice-01-plan-command/slice.json +79 -0
- package/specs/quiver-v18-slice-orchestration/slices/slice-02-graph-mvp-tree/slice.json +75 -0
- package/specs/quiver-v18-slice-orchestration/slices/slice-03-graph-extended-formats/slice.json +70 -0
- package/specs/quiver-v18-slice-orchestration/slices/slice-04-next-command/slice.json +73 -0
- package/specs/quiver-v18-stabilization/EVIDENCE_REPORT.md +26 -0
- package/specs/quiver-v18-stabilization/SPEC.md +62 -0
- package/specs/quiver-v18-stabilization/STATUS.md +30 -0
- package/specs/quiver-v18-stabilization/slices/slice-01-fix-legacy-dependency-resolution/CLOSURE_BRIEF.md +29 -0
- package/specs/quiver-v18-stabilization/slices/slice-01-fix-legacy-dependency-resolution/EXECUTION_BRIEF.md +134 -0
- package/specs/quiver-v18-stabilization/slices/slice-01-fix-legacy-dependency-resolution/slice.json +56 -0
- package/specs/quiver-v18-stabilization/slices/slice-02-roadmap-and-branch-cleanup/CLOSURE_BRIEF.md +29 -0
- package/specs/quiver-v18-stabilization/slices/slice-02-roadmap-and-branch-cleanup/EXECUTION_BRIEF.md +118 -0
- package/specs/quiver-v18-stabilization/slices/slice-02-roadmap-and-branch-cleanup/slice.json +57 -0
- package/specs/quiver-v18-stabilization/slices/slice-03-publish-drafts-branch/CLOSURE_BRIEF.md +23 -0
- package/specs/quiver-v18-stabilization/slices/slice-03-publish-drafts-branch/EXECUTION_BRIEF.md +73 -0
- package/specs/quiver-v18-stabilization/slices/slice-03-publish-drafts-branch/slice.json +49 -0
- package/src/create-quiver/commands/graph.js +97 -0
- package/src/create-quiver/commands/next.js +134 -0
- package/src/create-quiver/commands/plan.js +205 -0
- package/src/create-quiver/index.js +476 -123
- package/src/create-quiver/lib/analyze.js +9 -0
- package/src/create-quiver/lib/doctor.js +212 -0
- package/src/create-quiver/lib/git.js +154 -0
- package/src/create-quiver/lib/handoff.js +104 -0
- package/src/create-quiver/lib/init-docs.js +674 -0
- package/src/create-quiver/lib/json.js +14 -0
- package/src/create-quiver/lib/lifecycle.js +479 -0
- package/src/create-quiver/lib/paths.js +19 -0
- package/src/create-quiver/lib/readiness.js +354 -0
- package/src/create-quiver/lib/renderers/dot.js +129 -0
- package/src/create-quiver/lib/renderers/mermaid.js +119 -0
- package/src/create-quiver/lib/renderers/tree.js +116 -0
- package/src/create-quiver/lib/scope.js +5 -0
- package/src/create-quiver/lib/slice-graph.js +453 -0
- package/src/create-quiver/lib/slice.js +195 -0
- package/src/create-quiver/lib/state.js +139 -0
|
@@ -2,6 +2,21 @@ const fs = require('fs');
|
|
|
2
2
|
const os = require('os');
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const { execFileSync } = require('child_process');
|
|
5
|
+
const { checkHandoff, scaffoldHandoff } = require('./lib/handoff');
|
|
6
|
+
const { collectDoctorWarnings } = require('./lib/doctor');
|
|
7
|
+
const { runGraph } = require('./commands/graph');
|
|
8
|
+
const { runNext } = require('./commands/next');
|
|
9
|
+
const { runPlan } = require('./commands/plan');
|
|
10
|
+
const { initializeProjectDocs } = require('./lib/init-docs');
|
|
11
|
+
const { checkPrReadiness, checkScope, checkSliceReadiness } = require('./lib/readiness');
|
|
12
|
+
const { cleanupSlice, refreshActiveSlicesBoard, startSlice } = require('./lib/lifecycle');
|
|
13
|
+
const { relativePosixPath, resolveTargetRoot } = require('./lib/paths');
|
|
14
|
+
const {
|
|
15
|
+
hasQuiverInitializationEvidence,
|
|
16
|
+
readState,
|
|
17
|
+
updateStateForAnalyze,
|
|
18
|
+
updateStateForMigrate,
|
|
19
|
+
} = require('./lib/state');
|
|
5
20
|
const cliPackageJson = JSON.parse(fs.readFileSync(path.resolve(__dirname, '../..', 'package.json'), 'utf8'));
|
|
6
21
|
const CLI_VERSION = cliPackageJson.version || '0.0.0';
|
|
7
22
|
|
|
@@ -13,21 +28,56 @@ function printUsage() {
|
|
|
13
28
|
console.log(`Usage:
|
|
14
29
|
npx create-quiver [options]
|
|
15
30
|
npx create-quiver analyze [options]
|
|
31
|
+
npx create-quiver plan [options]
|
|
32
|
+
npx create-quiver graph [options]
|
|
33
|
+
npx create-quiver next [options]
|
|
16
34
|
npx create-quiver migrate [options]
|
|
17
35
|
npx create-quiver doctor [options]
|
|
36
|
+
npx create-quiver start-slice [options] <slice.json>
|
|
37
|
+
npx create-quiver check-slice [options] <slice.json>
|
|
38
|
+
npx create-quiver check-pr <slice.json>
|
|
39
|
+
npx create-quiver check-handoff <handoff.md>
|
|
40
|
+
npx create-quiver new-handoff <spec-slug>
|
|
41
|
+
npx create-quiver cleanup-slice [options] <slice.json>
|
|
42
|
+
npx create-quiver check-scope [options] <slice.json>
|
|
43
|
+
npx create-quiver refresh-active-slices
|
|
18
44
|
|
|
19
45
|
Options:
|
|
20
46
|
-n, --name <project-name> Project name to generate
|
|
21
47
|
-d, --dir <target-dir> Target directory to scaffold into or inspect
|
|
48
|
+
--spec <slug> Restrict plan output to one spec
|
|
49
|
+
--format <name> Graph output format (tree, mermaid, dot)
|
|
50
|
+
--show-conflicts Show shared file paths in graph output
|
|
51
|
+
--level <n> Restrict graph output to one level
|
|
52
|
+
--json Emit machine-readable JSON
|
|
53
|
+
--only-ready Show only slices with no pending dependencies
|
|
54
|
+
--all-ready List every ready slice returned by next
|
|
55
|
+
--auto-start Prompt for confirmation and run start-slice on next
|
|
56
|
+
--unicode Prefer Unicode output when supported
|
|
22
57
|
-y, --yes Skip prompts and use the provided inputs
|
|
23
58
|
-h, --help Show this help message
|
|
24
59
|
|
|
25
60
|
Examples:
|
|
26
61
|
npx create-quiver --name "My Project"
|
|
27
62
|
npx create-quiver --name "My Project" --dir ./my-project
|
|
28
|
-
npx create-quiver analyze
|
|
29
|
-
npx create-quiver
|
|
30
|
-
npx create-quiver
|
|
63
|
+
cd ./my-project && npx create-quiver analyze
|
|
64
|
+
cd ./my-project && npx create-quiver plan --json
|
|
65
|
+
cd ./my-project && npx create-quiver graph --show-conflicts
|
|
66
|
+
cd ./my-project && npx create-quiver graph --format mermaid
|
|
67
|
+
cd ./my-project && npx create-quiver graph --format dot
|
|
68
|
+
cd ./my-project && npx create-quiver next
|
|
69
|
+
cd ./my-project && npx create-quiver next --all-ready
|
|
70
|
+
cd ./my-project && npx create-quiver next --auto-start
|
|
71
|
+
cd ./my-project && npx create-quiver migrate
|
|
72
|
+
cd ./my-project && npx create-quiver doctor
|
|
73
|
+
cd ./my-project && npx create-quiver start-slice specs/my-project/slices/slice-01/slice.json
|
|
74
|
+
cd ./my-project && npx create-quiver check-slice specs/my-project/slices/slice-01/slice.json
|
|
75
|
+
cd ./my-project && npx create-quiver check-pr specs/my-project/slices/slice-01/slice.json
|
|
76
|
+
cd ./my-project && npx create-quiver check-handoff specs/my-project/HANDOFF.md
|
|
77
|
+
cd ./my-project && npx create-quiver new-handoff my-spec
|
|
78
|
+
cd ./my-project && npx create-quiver cleanup-slice specs/my-project/slices/slice-01/slice.json
|
|
79
|
+
cd ./my-project && npx create-quiver check-scope specs/my-project/slices/slice-01/slice.json
|
|
80
|
+
cd ./my-project && npx create-quiver refresh-active-slices
|
|
31
81
|
node bin/create-quiver.js doctor --dir ./my-project
|
|
32
82
|
`);
|
|
33
83
|
}
|
|
@@ -37,12 +87,29 @@ function parseArgs(argv) {
|
|
|
37
87
|
help: false,
|
|
38
88
|
force: false,
|
|
39
89
|
mode: 'init',
|
|
90
|
+
allowDraft: false,
|
|
91
|
+
closeBaseline: false,
|
|
92
|
+
discard: false,
|
|
93
|
+
dryRun: false,
|
|
94
|
+
gate: 'execution',
|
|
40
95
|
projectName: '',
|
|
41
96
|
targetDir: '.',
|
|
97
|
+
strict: false,
|
|
98
|
+
strictOverlap: false,
|
|
99
|
+
json: false,
|
|
100
|
+
onlyReady: false,
|
|
101
|
+
allReady: false,
|
|
102
|
+
autoStart: false,
|
|
103
|
+
specSlug: '',
|
|
104
|
+
format: 'tree',
|
|
105
|
+
showConflicts: false,
|
|
106
|
+
level: null,
|
|
107
|
+
unicode: false,
|
|
42
108
|
};
|
|
43
109
|
|
|
44
110
|
const args = [...argv];
|
|
45
|
-
|
|
111
|
+
const commandModes = new Set(['plan', 'graph', 'next', 'doctor', 'analyze', 'migrate', 'start-slice', 'check-slice', 'check-pr', 'check-handoff', 'new-handoff', 'cleanup-slice', 'check-scope', 'refresh-active-slices']);
|
|
112
|
+
if (commandModes.has(args[0])) {
|
|
46
113
|
result.mode = args[0];
|
|
47
114
|
args.shift();
|
|
48
115
|
} else if (args[0] === '--analyze') {
|
|
@@ -54,6 +121,12 @@ function parseArgs(argv) {
|
|
|
54
121
|
} else if (args[0] === '--doctor') {
|
|
55
122
|
result.mode = 'doctor';
|
|
56
123
|
args.shift();
|
|
124
|
+
} else if (args[0] === '--check-handoff') {
|
|
125
|
+
result.mode = 'check-handoff';
|
|
126
|
+
args.shift();
|
|
127
|
+
} else if (args[0] === '--new-handoff') {
|
|
128
|
+
result.mode = 'new-handoff';
|
|
129
|
+
args.shift();
|
|
57
130
|
}
|
|
58
131
|
|
|
59
132
|
const positional = [];
|
|
@@ -81,6 +154,116 @@ function parseArgs(argv) {
|
|
|
81
154
|
continue;
|
|
82
155
|
}
|
|
83
156
|
|
|
157
|
+
if (arg === '--check-handoff') {
|
|
158
|
+
result.mode = 'check-handoff';
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (arg === '--new-handoff') {
|
|
163
|
+
result.mode = 'new-handoff';
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (arg === '--allow-draft') {
|
|
168
|
+
result.allowDraft = true;
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (arg === '--close-baseline') {
|
|
173
|
+
result.closeBaseline = true;
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (arg === '--discard') {
|
|
178
|
+
result.discard = true;
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (arg === '--dry-run') {
|
|
183
|
+
result.dryRun = true;
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (arg === '--strict') {
|
|
188
|
+
result.strict = true;
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (arg === '--strict-overlap') {
|
|
193
|
+
result.strictOverlap = true;
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (arg === '--json') {
|
|
198
|
+
result.json = true;
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (arg === '--show-conflicts') {
|
|
203
|
+
result.showConflicts = true;
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (arg === '--format') {
|
|
208
|
+
const value = args[++index];
|
|
209
|
+
if (!value) {
|
|
210
|
+
throw new Error(formatError('missing value for --format'));
|
|
211
|
+
}
|
|
212
|
+
result.format = value;
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (arg === '--level') {
|
|
217
|
+
const value = args[++index];
|
|
218
|
+
if (typeof value === 'undefined') {
|
|
219
|
+
throw new Error(formatError('missing value for --level'));
|
|
220
|
+
}
|
|
221
|
+
const parsed = Number.parseInt(value, 10);
|
|
222
|
+
if (!Number.isInteger(parsed) || parsed < 0) {
|
|
223
|
+
throw new Error(formatError('invalid value for --level'));
|
|
224
|
+
}
|
|
225
|
+
result.level = parsed;
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (arg === '--only-ready') {
|
|
230
|
+
result.onlyReady = true;
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (arg === '--all-ready') {
|
|
235
|
+
result.allReady = true;
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (arg === '--auto-start') {
|
|
240
|
+
result.autoStart = true;
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (arg === '--unicode') {
|
|
245
|
+
result.unicode = true;
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (arg === '--spec') {
|
|
250
|
+
const value = args[++index];
|
|
251
|
+
if (!value) {
|
|
252
|
+
throw new Error(formatError('missing value for --spec'));
|
|
253
|
+
}
|
|
254
|
+
result.specSlug = value;
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (arg === '--gate') {
|
|
259
|
+
const value = args[++index];
|
|
260
|
+
if (!value) {
|
|
261
|
+
throw new Error(formatError('missing value for --gate'));
|
|
262
|
+
}
|
|
263
|
+
result.gate = value;
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
|
|
84
267
|
if (arg === '-n' || arg === '--name' || arg === '--project-name') {
|
|
85
268
|
const value = args[++index];
|
|
86
269
|
if (!value) {
|
|
@@ -114,6 +297,14 @@ function parseArgs(argv) {
|
|
|
114
297
|
if (positional.length > 0) {
|
|
115
298
|
result.targetDir = positional.shift();
|
|
116
299
|
}
|
|
300
|
+
} else if (result.mode === 'plan') {
|
|
301
|
+
if (positional.length > 0) {
|
|
302
|
+
throw new Error(formatError('plan does not accept positional arguments; use --spec <slug>'));
|
|
303
|
+
}
|
|
304
|
+
} else if (result.mode === 'refresh-active-slices') {
|
|
305
|
+
if (positional.length > 0) {
|
|
306
|
+
throw new Error(formatError('refresh-active-slices does not accept positional arguments'));
|
|
307
|
+
}
|
|
117
308
|
} else {
|
|
118
309
|
if (positional.length > 0) {
|
|
119
310
|
result.targetDir = positional.shift();
|
|
@@ -204,84 +395,14 @@ function mergeDirectoryTree(sourceDir, targetDir) {
|
|
|
204
395
|
}
|
|
205
396
|
|
|
206
397
|
function runInitDocs(repoRoot, projectName) {
|
|
207
|
-
|
|
208
|
-
|
|
398
|
+
initializeProjectDocs({
|
|
399
|
+
projectRoot: repoRoot,
|
|
400
|
+
projectName,
|
|
401
|
+
cliVersion: CLI_VERSION,
|
|
402
|
+
migrateMode: false,
|
|
209
403
|
});
|
|
210
404
|
}
|
|
211
405
|
|
|
212
|
-
function runInitDocsWithMode(repoRoot, projectName, mode) {
|
|
213
|
-
return runCommand('bash', ['docs-template/scripts/init-docs.sh', projectName], {
|
|
214
|
-
cwd: repoRoot,
|
|
215
|
-
env: {
|
|
216
|
-
...process.env,
|
|
217
|
-
QUIVER_PROJECT_NAME: projectName,
|
|
218
|
-
QUIVER_MIGRATE: mode === 'migrate' ? '1' : '0',
|
|
219
|
-
QUIVER_VERSION: CLI_VERSION,
|
|
220
|
-
},
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
function writeQuiverState(projectRoot, nextState) {
|
|
225
|
-
const stateDir = path.join(projectRoot, '.quiver');
|
|
226
|
-
const statePath = path.join(stateDir, 'state.json');
|
|
227
|
-
fs.mkdirSync(stateDir, { recursive: true });
|
|
228
|
-
fs.writeFileSync(statePath, `${JSON.stringify(nextState, null, 2)}\n`);
|
|
229
|
-
return statePath;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
function readQuiverState(projectRoot) {
|
|
233
|
-
return readJsonIfExists(path.join(projectRoot, '.quiver', 'state.json'));
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
function createInitialQuiverState(projectName) {
|
|
237
|
-
const now = new Date().toISOString();
|
|
238
|
-
|
|
239
|
-
return {
|
|
240
|
-
project_name: projectName,
|
|
241
|
-
quiver_version: CLI_VERSION,
|
|
242
|
-
initialized_version: CLI_VERSION,
|
|
243
|
-
migrated_version: null,
|
|
244
|
-
last_initialized_at: now,
|
|
245
|
-
last_migration_at: null,
|
|
246
|
-
last_analysis_at: null,
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
function updateQuiverStateForAnalyze(projectRoot) {
|
|
251
|
-
const currentState = readQuiverState(projectRoot);
|
|
252
|
-
|
|
253
|
-
if (!currentState) {
|
|
254
|
-
return null;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
const nextState = {
|
|
258
|
-
...currentState,
|
|
259
|
-
quiver_version: CLI_VERSION,
|
|
260
|
-
last_analysis_at: new Date().toISOString(),
|
|
261
|
-
};
|
|
262
|
-
|
|
263
|
-
writeQuiverState(projectRoot, nextState);
|
|
264
|
-
return nextState;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
function updateQuiverStateForMigrate(projectRoot, projectName) {
|
|
268
|
-
const currentState = readQuiverState(projectRoot);
|
|
269
|
-
const now = new Date().toISOString();
|
|
270
|
-
const nextState = {
|
|
271
|
-
...(currentState || {}),
|
|
272
|
-
project_name: projectName,
|
|
273
|
-
quiver_version: CLI_VERSION,
|
|
274
|
-
initialized_version: currentState?.initialized_version ?? null,
|
|
275
|
-
migrated_version: CLI_VERSION,
|
|
276
|
-
last_initialized_at: currentState?.last_initialized_at ?? null,
|
|
277
|
-
last_migration_at: now,
|
|
278
|
-
last_analysis_at: currentState?.last_analysis_at ?? null,
|
|
279
|
-
};
|
|
280
|
-
|
|
281
|
-
writeQuiverState(projectRoot, nextState);
|
|
282
|
-
return nextState;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
406
|
function listGeneratedSpecDirs(projectRoot) {
|
|
286
407
|
const specsDir = path.join(projectRoot, 'specs');
|
|
287
408
|
|
|
@@ -791,6 +912,49 @@ function buildProjectScan(projectRoot) {
|
|
|
791
912
|
|
|
792
913
|
function renderProjectMap(scan) {
|
|
793
914
|
const lines = [];
|
|
915
|
+
const projectSlug = scan.project.name
|
|
916
|
+
.toLowerCase()
|
|
917
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
918
|
+
.replace(/^-+|-+$/g, '') || 'project';
|
|
919
|
+
const docsFiles = new Set(scan.docs.files);
|
|
920
|
+
const hasDecisionLog = docsFiles.has('docs/DECISIONS.md');
|
|
921
|
+
const hasAiPrompt = docsFiles.has('docs/AI_ONBOARDING_PROMPT.md');
|
|
922
|
+
const sourceDirs = scan.structure.source_directories.length > 0 ? scan.structure.source_directories : [];
|
|
923
|
+
const configFiles = scan.structure.config_files.length > 0 ? scan.structure.config_files : [];
|
|
924
|
+
const highSignalFiles = [
|
|
925
|
+
'README.md',
|
|
926
|
+
'docs/INDEX.md',
|
|
927
|
+
'docs/AI_CONTEXT.md',
|
|
928
|
+
'docs/DECISIONS.md',
|
|
929
|
+
'docs/PROJECT_SCAN.json',
|
|
930
|
+
'docs/PROJECT_MAP.md',
|
|
931
|
+
'docs/AI_ONBOARDING_PROMPT.md',
|
|
932
|
+
'docs/CONTEXTO.md',
|
|
933
|
+
'docs/WORKFLOW.md',
|
|
934
|
+
'docs/SUPPORT_MATRIX.md',
|
|
935
|
+
'docs/TROUBLESHOOTING.md',
|
|
936
|
+
'package.json',
|
|
937
|
+
...configFiles,
|
|
938
|
+
].filter((value, index, array) => array.indexOf(value) === index);
|
|
939
|
+
const likelyTestCommands = [
|
|
940
|
+
['Install', scan.commands.install || 'npm install'],
|
|
941
|
+
['dev', scan.commands.common.dev || 'not defined'],
|
|
942
|
+
['build', scan.commands.common.build || 'not defined'],
|
|
943
|
+
['test', scan.commands.common.test || 'not defined'],
|
|
944
|
+
['lint', scan.commands.common.lint || 'not defined'],
|
|
945
|
+
];
|
|
946
|
+
const readingOrder = [
|
|
947
|
+
'README.md',
|
|
948
|
+
'docs/INDEX.md',
|
|
949
|
+
'docs/AI_CONTEXT.md',
|
|
950
|
+
'docs/PROJECT_SCAN.json',
|
|
951
|
+
'docs/PROJECT_MAP.md',
|
|
952
|
+
hasDecisionLog ? 'docs/DECISIONS.md' : 'docs/DECISIONS.md (create with migrate if missing)',
|
|
953
|
+
'docs/CONTEXTO.md',
|
|
954
|
+
'docs/WORKFLOW.md',
|
|
955
|
+
'docs/SUPPORT_MATRIX.md',
|
|
956
|
+
'docs/TROUBLESHOOTING.md',
|
|
957
|
+
];
|
|
794
958
|
|
|
795
959
|
lines.push('# Project Map');
|
|
796
960
|
lines.push('');
|
|
@@ -804,37 +968,83 @@ function renderProjectMap(scan) {
|
|
|
804
968
|
}
|
|
805
969
|
|
|
806
970
|
lines.push('');
|
|
807
|
-
lines.push('##
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
971
|
+
lines.push('## Suggested Reading Order');
|
|
972
|
+
for (const item of readingOrder) {
|
|
973
|
+
lines.push(`- ${item}`);
|
|
974
|
+
}
|
|
811
975
|
|
|
812
|
-
if (
|
|
813
|
-
lines.push('');
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
976
|
+
if (hasAiPrompt) {
|
|
977
|
+
lines.push('- docs/AI_ONBOARDING_PROMPT.md');
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
lines.push(`- specs/${projectSlug}/SPEC.md`);
|
|
981
|
+
if (sourceDirs.length > 0) {
|
|
982
|
+
for (const sourceDir of sourceDirs) {
|
|
983
|
+
lines.push(`- ${sourceDir}/...`);
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
lines.push('');
|
|
988
|
+
lines.push('## Entry Points');
|
|
989
|
+
lines.push(`- Project overview: ${scan.docs.has_readme ? 'README.md' : 'docs/CONTEXTO.md'}`);
|
|
990
|
+
lines.push(`- AI context: ${hasDecisionLog ? 'docs/AI_CONTEXT.md + docs/DECISIONS.md' : 'docs/AI_CONTEXT.md'}`);
|
|
991
|
+
lines.push('- Analysis outputs: docs/PROJECT_SCAN.json, docs/PROJECT_MAP.md');
|
|
992
|
+
lines.push(`- Workflow contract: docs/WORKFLOW.md`);
|
|
993
|
+
lines.push(`- Spec contract: specs/${projectSlug}/SPEC.md`);
|
|
994
|
+
if (sourceDirs.length > 0) {
|
|
995
|
+
lines.push(`- Source roots: ${sourceDirs.join(', ')}`);
|
|
996
|
+
} else {
|
|
997
|
+
lines.push('- Source roots: none detected');
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
lines.push('');
|
|
1001
|
+
lines.push('## Primary Config Files');
|
|
1002
|
+
if (configFiles.length > 0) {
|
|
1003
|
+
for (const configFile of configFiles) {
|
|
1004
|
+
lines.push(`- ${configFile}`);
|
|
817
1005
|
}
|
|
1006
|
+
} else {
|
|
1007
|
+
lines.push('- none detected');
|
|
818
1008
|
}
|
|
819
1009
|
|
|
820
1010
|
lines.push('');
|
|
821
1011
|
lines.push('## Commands');
|
|
1012
|
+
lines.push('See **Likely Test Commands** for the current read-friendly command summary.');
|
|
1013
|
+
|
|
1014
|
+
lines.push('');
|
|
1015
|
+
lines.push('## Likely Test Commands');
|
|
822
1016
|
lines.push('| Command | Value |');
|
|
823
1017
|
lines.push('|---------|-------|');
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
1018
|
+
for (const [name, value] of likelyTestCommands) {
|
|
1019
|
+
lines.push(`| ${name} | ${escapeMarkdownCell(value)} |`);
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
const relevantScripts = Object.entries(scan.commands.scripts)
|
|
1023
|
+
.filter(([name]) => /(^|:)(analyze|doctor|migrate|test|build|lint|dev|start|check)(:|$)|analyze|doctor|migrate|test|build|lint|dev|start|check/i.test(name))
|
|
1024
|
+
.slice(0, 12);
|
|
829
1025
|
|
|
830
|
-
if (
|
|
1026
|
+
if (relevantScripts.length > 0) {
|
|
831
1027
|
lines.push('');
|
|
832
1028
|
lines.push('### package.json scripts');
|
|
833
|
-
for (const [name, command] of
|
|
1029
|
+
for (const [name, command] of relevantScripts) {
|
|
834
1030
|
lines.push(`- ${name}: \`${command}\``);
|
|
835
1031
|
}
|
|
836
1032
|
}
|
|
837
1033
|
|
|
1034
|
+
lines.push('');
|
|
1035
|
+
lines.push('## Stack');
|
|
1036
|
+
lines.push(`- Primary: ${scan.stack.primary}`);
|
|
1037
|
+
lines.push(`- Frameworks: ${scan.stack.frameworks.length > 0 ? scan.stack.frameworks.join(', ') : 'none detected'}`);
|
|
1038
|
+
lines.push(`- Languages: ${scan.stack.languages.length > 0 ? scan.stack.languages.join(', ') : 'none detected'}`);
|
|
1039
|
+
|
|
1040
|
+
if (scan.stack.evidence.length > 0) {
|
|
1041
|
+
lines.push('');
|
|
1042
|
+
lines.push('### Evidence');
|
|
1043
|
+
for (const item of scan.stack.evidence) {
|
|
1044
|
+
lines.push(`- ${item.framework}: ${item.signals.join(', ')}`);
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
|
|
838
1048
|
lines.push('');
|
|
839
1049
|
lines.push('## Structure');
|
|
840
1050
|
lines.push(`- Top-level directories: ${scan.structure.top_level_directories.length > 0 ? scan.structure.top_level_directories.join(', ') : 'none detected'}`);
|
|
@@ -849,6 +1059,14 @@ function renderProjectMap(scan) {
|
|
|
849
1059
|
lines.push('## Docs');
|
|
850
1060
|
lines.push(`- README present: ${scan.docs.has_readme ? 'yes' : 'no'}`);
|
|
851
1061
|
lines.push(`- Docs files: ${scan.docs.files.length > 0 ? scan.docs.files.join(', ') : 'none detected'}`);
|
|
1062
|
+
lines.push(`- Decision log: ${hasDecisionLog ? 'present' : 'missing'}`);
|
|
1063
|
+
lines.push(`- AI onboarding prompt: ${hasAiPrompt ? 'present' : 'missing'}`);
|
|
1064
|
+
|
|
1065
|
+
lines.push('');
|
|
1066
|
+
lines.push('## High-Signal Files');
|
|
1067
|
+
for (const file of highSignalFiles) {
|
|
1068
|
+
lines.push(`- ${file}`);
|
|
1069
|
+
}
|
|
852
1070
|
|
|
853
1071
|
lines.push('');
|
|
854
1072
|
lines.push('## Risks');
|
|
@@ -870,6 +1088,16 @@ function renderProjectMap(scan) {
|
|
|
870
1088
|
lines.push('- None');
|
|
871
1089
|
}
|
|
872
1090
|
|
|
1091
|
+
lines.push('');
|
|
1092
|
+
lines.push('## Do Not Read First');
|
|
1093
|
+
if (scan.skipped_paths.length > 0) {
|
|
1094
|
+
for (const skippedPath of scan.skipped_paths) {
|
|
1095
|
+
lines.push(`- ${skippedPath}`);
|
|
1096
|
+
}
|
|
1097
|
+
} else {
|
|
1098
|
+
lines.push('- None detected, but still prioritize docs and config files before source trees.');
|
|
1099
|
+
}
|
|
1100
|
+
|
|
873
1101
|
lines.push('');
|
|
874
1102
|
return lines.join('\n');
|
|
875
1103
|
}
|
|
@@ -888,7 +1116,7 @@ function writeProjectScanArtifacts(projectRoot, scan) {
|
|
|
888
1116
|
}
|
|
889
1117
|
|
|
890
1118
|
function runAnalyze(targetDir) {
|
|
891
|
-
const projectRoot =
|
|
1119
|
+
const projectRoot = resolveTargetRoot(process.cwd(), targetDir);
|
|
892
1120
|
|
|
893
1121
|
if (!fs.existsSync(projectRoot)) {
|
|
894
1122
|
throw new Error(formatError(`target directory does not exist: ${projectRoot}`));
|
|
@@ -896,22 +1124,26 @@ function runAnalyze(targetDir) {
|
|
|
896
1124
|
|
|
897
1125
|
const scan = buildProjectScan(projectRoot);
|
|
898
1126
|
const artifacts = writeProjectScanArtifacts(projectRoot, scan);
|
|
899
|
-
|
|
1127
|
+
updateStateForAnalyze(projectRoot, CLI_VERSION);
|
|
900
1128
|
|
|
901
1129
|
console.log(`Project analysis completed for ${projectRoot}`);
|
|
902
|
-
console.log(`Wrote ${
|
|
903
|
-
console.log(`Wrote ${
|
|
1130
|
+
console.log(`Wrote ${relativePosixPath(projectRoot, artifacts.jsonPath)}`);
|
|
1131
|
+
console.log(`Wrote ${relativePosixPath(projectRoot, artifacts.mdPath)}`);
|
|
904
1132
|
console.log(`Detected primary stack: ${scan.stack.primary}`);
|
|
905
1133
|
console.log(`Detected package manager: ${scan.project.package_manager}`);
|
|
906
1134
|
}
|
|
907
1135
|
|
|
908
1136
|
function runMigrate(targetDir) {
|
|
909
|
-
const projectRoot =
|
|
1137
|
+
const projectRoot = resolveTargetRoot(process.cwd(), targetDir);
|
|
910
1138
|
|
|
911
1139
|
if (!fs.existsSync(projectRoot)) {
|
|
912
1140
|
throw new Error(formatError(`target directory does not exist: ${projectRoot}`));
|
|
913
1141
|
}
|
|
914
1142
|
|
|
1143
|
+
if (!hasQuiverInitializationEvidence(projectRoot)) {
|
|
1144
|
+
throw new Error(formatError('migrate requires a project previously initialized by Quiver.\nRun: npx create-quiver --name "Project Name"'));
|
|
1145
|
+
}
|
|
1146
|
+
|
|
915
1147
|
const packageJson = loadPackageJson(projectRoot);
|
|
916
1148
|
const projectName = packageJson.name || path.basename(projectRoot) || 'Quiver Project';
|
|
917
1149
|
const packageRoot = path.resolve(__dirname, '../..');
|
|
@@ -920,15 +1152,13 @@ function runMigrate(targetDir) {
|
|
|
920
1152
|
try {
|
|
921
1153
|
const templateRoot = packTemplate(packageRoot, tempRoot);
|
|
922
1154
|
mergeDirectoryTree(templateRoot, path.join(projectRoot, 'docs-template'));
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
}
|
|
931
|
-
}
|
|
1155
|
+
initializeProjectDocs({
|
|
1156
|
+
projectRoot,
|
|
1157
|
+
projectName,
|
|
1158
|
+
cliVersion: CLI_VERSION,
|
|
1159
|
+
migrateMode: true,
|
|
1160
|
+
});
|
|
1161
|
+
updateStateForMigrate(projectRoot, projectName, CLI_VERSION);
|
|
932
1162
|
|
|
933
1163
|
console.log(`Quiver migration completed for ${projectRoot}`);
|
|
934
1164
|
console.log('Missing workflow files were restored without overwriting existing project files.');
|
|
@@ -938,12 +1168,16 @@ function runMigrate(targetDir) {
|
|
|
938
1168
|
}
|
|
939
1169
|
|
|
940
1170
|
function runDoctor(targetDir) {
|
|
941
|
-
const projectRoot =
|
|
1171
|
+
const projectRoot = resolveTargetRoot(process.cwd(), targetDir);
|
|
942
1172
|
|
|
943
1173
|
if (!fs.existsSync(projectRoot)) {
|
|
944
1174
|
throw new Error(formatError(`target directory does not exist: ${projectRoot}`));
|
|
945
1175
|
}
|
|
946
1176
|
|
|
1177
|
+
if (!hasQuiverInitializationEvidence(projectRoot)) {
|
|
1178
|
+
throw new Error(formatError('doctor requires a project previously initialized by Quiver.\nRun init first: npx create-quiver --name "Project Name"'));
|
|
1179
|
+
}
|
|
1180
|
+
|
|
947
1181
|
const generatedSpecs = listGeneratedSpecDirs(projectRoot);
|
|
948
1182
|
if (generatedSpecs.length !== 1) {
|
|
949
1183
|
throw new Error(formatError(`expected exactly one generated spec directory, found ${generatedSpecs.length || 0}`));
|
|
@@ -951,6 +1185,7 @@ function runDoctor(targetDir) {
|
|
|
951
1185
|
|
|
952
1186
|
const projectSlug = generatedSpecs[0];
|
|
953
1187
|
const requiredFiles = [
|
|
1188
|
+
'AGENTS.md',
|
|
954
1189
|
'README.md',
|
|
955
1190
|
'docs/INDEX.md',
|
|
956
1191
|
'docs/AI_CONTEXT.md',
|
|
@@ -984,11 +1219,26 @@ function runDoctor(targetDir) {
|
|
|
984
1219
|
const missingFiles = assertFilesExist(projectRoot, requiredFiles);
|
|
985
1220
|
const nonExecutableScripts = assertExecutablesExist(projectRoot, requiredExecutables);
|
|
986
1221
|
const pkg = loadPackageJson(projectRoot);
|
|
987
|
-
const
|
|
988
|
-
|
|
1222
|
+
const workflowScriptGroups = [
|
|
1223
|
+
{ label: 'migrate', node: 'quiver:migrate', legacy: 'migrate' },
|
|
1224
|
+
{ label: 'start-slice', node: 'quiver:start-slice', legacy: 'start:slice' },
|
|
1225
|
+
{ label: 'check-slice', node: 'quiver:check-slice', legacy: 'check:slice' },
|
|
1226
|
+
{ label: 'check-pr', node: 'quiver:check-pr', legacy: 'check:pr' },
|
|
1227
|
+
{ label: 'cleanup-slice', node: 'quiver:cleanup-slice', legacy: 'cleanup:slice' },
|
|
1228
|
+
{ label: 'check-scope', node: 'quiver:check-scope', legacy: 'check:scope' },
|
|
1229
|
+
{ label: 'refresh-active-slices', node: 'quiver:refresh-active-slices', legacy: 'refresh:active-slices' },
|
|
1230
|
+
];
|
|
1231
|
+
const missingScripts = workflowScriptGroups
|
|
1232
|
+
.filter((group) => typeof pkg.scripts?.[group.node] !== 'string' && typeof pkg.scripts?.[group.legacy] !== 'string')
|
|
1233
|
+
.map((group) => `${group.node} (or legacy ${group.legacy})`);
|
|
1234
|
+
const legacyOnlyScripts = workflowScriptGroups
|
|
1235
|
+
.filter((group) => typeof pkg.scripts?.[group.node] !== 'string' && typeof pkg.scripts?.[group.legacy] === 'string')
|
|
1236
|
+
.map((group) => group.label);
|
|
1237
|
+
const missingNodeNativeScripts = ['quiver:migrate', 'quiver:analyze', 'quiver:doctor']
|
|
1238
|
+
.filter((name) => typeof pkg.scripts?.[name] !== 'string');
|
|
989
1239
|
const hasScanArtifacts = fs.existsSync(path.join(projectRoot, 'docs', 'PROJECT_SCAN.json'))
|
|
990
1240
|
&& fs.existsSync(path.join(projectRoot, 'docs', 'PROJECT_MAP.md'));
|
|
991
|
-
const quiverState =
|
|
1241
|
+
const quiverState = readState(projectRoot);
|
|
992
1242
|
const hasQuiverState = Boolean(quiverState);
|
|
993
1243
|
const stateWarnings = hasQuiverState ? [] : ['missing Quiver state metadata: .quiver/state.json'];
|
|
994
1244
|
const migrationProblems = [
|
|
@@ -996,9 +1246,10 @@ function runDoctor(targetDir) {
|
|
|
996
1246
|
...nonExecutableScripts.map((file) => `missing executable bit: ${file}`),
|
|
997
1247
|
...missingScripts.map((name) => `missing package.json script: ${name}`),
|
|
998
1248
|
];
|
|
1249
|
+
const softWarnings = collectDoctorWarnings(projectRoot);
|
|
999
1250
|
|
|
1000
1251
|
if (migrationProblems.length > 0) {
|
|
1001
|
-
throw new Error(formatError(`doctor failed:\n- ${migrationProblems.join('\n- ')}\n- Run migration first: npx create-quiver migrate
|
|
1252
|
+
throw new Error(formatError(`doctor failed:\n- ${migrationProblems.join('\n- ')}\n- Run migration first: npx create-quiver migrate`));
|
|
1002
1253
|
}
|
|
1003
1254
|
|
|
1004
1255
|
console.log(`Quiver doctor passed for ${projectRoot}`);
|
|
@@ -1007,16 +1258,26 @@ function runDoctor(targetDir) {
|
|
|
1007
1258
|
for (const warning of stateWarnings) {
|
|
1008
1259
|
console.log(`- Warning: ${warning}`);
|
|
1009
1260
|
}
|
|
1261
|
+
for (const scriptName of missingNodeNativeScripts) {
|
|
1262
|
+
console.log(`- Warning: missing Node-native script: ${scriptName}`);
|
|
1263
|
+
}
|
|
1264
|
+
if (legacyOnlyScripts.length > 0) {
|
|
1265
|
+
console.log(`- Warning: legacy Bash workflow scripts detected for ${legacyOnlyScripts.join(', ')}. Run npx create-quiver migrate to add quiver:* npm scripts.`);
|
|
1266
|
+
}
|
|
1267
|
+
for (const warning of softWarnings) {
|
|
1268
|
+
console.log(`- Warning: ${warning}`);
|
|
1269
|
+
}
|
|
1010
1270
|
if (!hasQuiverState) {
|
|
1011
|
-
console.log('- Run migration first: npx create-quiver migrate
|
|
1271
|
+
console.log('- Run migration first: npx create-quiver migrate');
|
|
1012
1272
|
} else if (!hasScanArtifacts) {
|
|
1013
|
-
|
|
1273
|
+
console.log('- Analyze the project first: npx create-quiver analyze');
|
|
1014
1274
|
} else {
|
|
1015
|
-
console.log('- Ask your AI agent: Read docs/AI_ONBOARDING_PROMPT.md and execute it.');
|
|
1275
|
+
console.log('- Ask your AI agent: Read AGENTS.md, then docs/AI_ONBOARDING_PROMPT.md and execute it.');
|
|
1016
1276
|
}
|
|
1017
|
-
console.log(
|
|
1018
|
-
console.log(
|
|
1019
|
-
console.log(
|
|
1277
|
+
console.log('- Check the next ready slice: npx create-quiver next');
|
|
1278
|
+
console.log(`- Start a slice: npx create-quiver start-slice specs/${projectSlug}/slices/slice-template/slice.json`);
|
|
1279
|
+
console.log(`- Validate a slice: npx create-quiver check-slice specs/${projectSlug}/slices/slice-template/slice.json`);
|
|
1280
|
+
console.log(`- Validate the PR gate: npx create-quiver check-pr specs/${projectSlug}/slices/slice-template/slice.json`);
|
|
1020
1281
|
}
|
|
1021
1282
|
|
|
1022
1283
|
function printInitNextSteps(targetDir, projectName) {
|
|
@@ -1024,10 +1285,10 @@ function printInitNextSteps(targetDir, projectName) {
|
|
|
1024
1285
|
|
|
1025
1286
|
console.log('');
|
|
1026
1287
|
console.log('Next steps:');
|
|
1027
|
-
console.log(`- Review ${path.join(targetDir, 'docs', 'INDEX.md')}`);
|
|
1288
|
+
console.log(`- Review AGENTS.md, then ${path.join(targetDir, 'docs', 'INDEX.md')}`);
|
|
1028
1289
|
console.log(`- Review ${path.join(targetDir, 'docs', 'WORKFLOW.md')}`);
|
|
1029
1290
|
console.log(`- Create your first slice from ${path.join(targetDir, 'specs', projectSlug, 'slices', 'slice-template', 'slice.json')}`);
|
|
1030
|
-
console.log(`- Launch slice work with
|
|
1291
|
+
console.log(`- Launch slice work with npx create-quiver start-slice specs/${projectSlug}/slices/slice-template/slice.json`);
|
|
1031
1292
|
}
|
|
1032
1293
|
|
|
1033
1294
|
async function run(argv) {
|
|
@@ -1043,6 +1304,37 @@ async function run(argv) {
|
|
|
1043
1304
|
return;
|
|
1044
1305
|
}
|
|
1045
1306
|
|
|
1307
|
+
if (args.mode === 'plan') {
|
|
1308
|
+
runPlan(process.cwd(), {
|
|
1309
|
+
json: args.json,
|
|
1310
|
+
onlyReady: args.onlyReady,
|
|
1311
|
+
specSlug: args.specSlug,
|
|
1312
|
+
unicode: args.unicode,
|
|
1313
|
+
});
|
|
1314
|
+
return;
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
if (args.mode === 'graph') {
|
|
1318
|
+
runGraph(process.cwd(), {
|
|
1319
|
+
format: args.format,
|
|
1320
|
+
json: args.json,
|
|
1321
|
+
level: args.level,
|
|
1322
|
+
showConflicts: args.showConflicts,
|
|
1323
|
+
unicode: args.unicode,
|
|
1324
|
+
});
|
|
1325
|
+
return;
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
if (args.mode === 'next') {
|
|
1329
|
+
await runNext(process.cwd(), {
|
|
1330
|
+
allReady: args.allReady,
|
|
1331
|
+
autoStart: args.autoStart,
|
|
1332
|
+
json: args.json,
|
|
1333
|
+
specSlug: args.specSlug,
|
|
1334
|
+
});
|
|
1335
|
+
return;
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1046
1338
|
if (args.mode === 'migrate') {
|
|
1047
1339
|
runMigrate(args.targetDir);
|
|
1048
1340
|
return;
|
|
@@ -1053,8 +1345,66 @@ async function run(argv) {
|
|
|
1053
1345
|
return;
|
|
1054
1346
|
}
|
|
1055
1347
|
|
|
1348
|
+
if (args.mode === 'start-slice') {
|
|
1349
|
+
startSlice(path.resolve(process.cwd(), args.targetDir), { allowDraft: args.allowDraft });
|
|
1350
|
+
return;
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
if (args.mode === 'check-slice') {
|
|
1354
|
+
checkSliceReadiness(path.resolve(process.cwd(), args.targetDir), {
|
|
1355
|
+
gate: args.gate,
|
|
1356
|
+
strictOverlap: args.strictOverlap,
|
|
1357
|
+
});
|
|
1358
|
+
return;
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
if (args.mode === 'check-pr') {
|
|
1362
|
+
checkPrReadiness(path.resolve(process.cwd(), args.targetDir));
|
|
1363
|
+
return;
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
if (args.mode === 'check-handoff') {
|
|
1367
|
+
const repoRoot = process.cwd();
|
|
1368
|
+
const handoffInput = args.targetDir;
|
|
1369
|
+
if (!handoffInput || handoffInput === '.') {
|
|
1370
|
+
throw new Error(formatError('missing handoff path. Use: npx create-quiver check-handoff specs/<spec-slug>/HANDOFF.md'));
|
|
1371
|
+
}
|
|
1372
|
+
const resolved = checkHandoff(handoffInput, repoRoot);
|
|
1373
|
+
console.log(`PASS: Handoff validated at ${resolved.relativePath}`);
|
|
1374
|
+
return;
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
if (args.mode === 'new-handoff') {
|
|
1378
|
+
const repoRoot = process.cwd();
|
|
1379
|
+
const handoffSlug = args.targetDir;
|
|
1380
|
+
const resolved = scaffoldHandoff(handoffSlug, repoRoot);
|
|
1381
|
+
console.log(`PASS: Handoff scaffolded at ${resolved.relativePath}`);
|
|
1382
|
+
return;
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
if (args.mode === 'cleanup-slice') {
|
|
1386
|
+
cleanupSlice(path.resolve(process.cwd(), args.targetDir), {
|
|
1387
|
+
closeBaseline: args.closeBaseline,
|
|
1388
|
+
discard: args.discard,
|
|
1389
|
+
dryRun: args.dryRun,
|
|
1390
|
+
force: args.force,
|
|
1391
|
+
});
|
|
1392
|
+
return;
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
if (args.mode === 'check-scope') {
|
|
1396
|
+
checkScope(path.resolve(process.cwd(), args.targetDir), { strict: args.strict });
|
|
1397
|
+
return;
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
if (args.mode === 'refresh-active-slices') {
|
|
1401
|
+
const outputPath = refreshActiveSlicesBoard(path.resolve(process.cwd(), '.'));
|
|
1402
|
+
console.log(`Active slices refreshed: ${outputPath}`);
|
|
1403
|
+
return;
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1056
1406
|
const packageRoot = path.resolve(__dirname, '../..');
|
|
1057
|
-
const targetDir =
|
|
1407
|
+
const targetDir = resolveTargetRoot(process.cwd(), args.targetDir);
|
|
1058
1408
|
const projectName = args.projectName || path.basename(targetDir) || 'Quiver Project';
|
|
1059
1409
|
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'quiver-create-'));
|
|
1060
1410
|
|
|
@@ -1073,5 +1423,8 @@ async function run(argv) {
|
|
|
1073
1423
|
}
|
|
1074
1424
|
|
|
1075
1425
|
module.exports = {
|
|
1426
|
+
runAnalyze,
|
|
1427
|
+
runDoctor,
|
|
1428
|
+
runMigrate,
|
|
1076
1429
|
run,
|
|
1077
1430
|
};
|