create-quiver 0.7.0 → 0.9.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 +52 -0
- package/.github/workflows/ci.yml +2 -2
- package/BACKLOG.md +139 -0
- package/CHANGELOG.md +20 -1
- package/README.md +31 -1
- package/README_FOR_AI.md +25 -13
- package/ROADMAP.md +28 -6
- package/docs/AI_ONBOARDING_PROMPT.md.template +4 -0
- package/docs/COMMANDS.md.template +25 -0
- package/docs/INDEX.md.template +2 -0
- package/docs/SUPPORT_MATRIX.md.template +9 -0
- package/docs/WORKFLOW.md.template +4 -0
- 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 +5 -2
- package/package.template.json +8 -3
- package/scripts/check-slice-readiness.sh +6 -4
- package/scripts/init-docs.sh +57 -9
- package/specs/[project-name]/HANDOFF.md.template +37 -0
- package/specs/[project-name]/slices/slice-template/slice.json +5 -0
- 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/slices/slice-01-cross-platform-support-contract/slice.json +1 -1
- package/specs/quiver-v12-cross-platform-native-runtime/slices/slice-02-node-init-docs-runtime/slice.json +1 -1
- package/specs/quiver-v12-cross-platform-native-runtime/slices/slice-03-node-migrate-analyze-doctor-flow/slice.json +1 -1
- package/specs/quiver-v12-cross-platform-native-runtime/slices/slice-04-node-slice-lifecycle-commands/slice.json +1 -1
- package/specs/quiver-v12-cross-platform-native-runtime/slices/slice-05-generated-project-scripts-and-migration/slice.json +1 -1
- package/specs/quiver-v13-token-efficient-ai-context/EVIDENCE_REPORT.md +1 -1
- package/specs/quiver-v13-token-efficient-ai-context/SPEC.md +1 -1
- 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/specs/quiver-v19-self-install-dev-dep/EVIDENCE_REPORT.md +19 -0
- package/specs/quiver-v19-self-install-dev-dep/SPEC.md +51 -0
- package/specs/quiver-v19-self-install-dev-dep/STATUS.md +20 -0
- package/specs/quiver-v19-self-install-dev-dep/slices/slice-01-auto-install-dev-dep/CLOSURE_BRIEF.md +29 -0
- package/specs/quiver-v19-self-install-dev-dep/slices/slice-01-auto-install-dev-dep/EXECUTION_BRIEF.md +287 -0
- package/specs/quiver-v19-self-install-dev-dep/slices/slice-01-auto-install-dev-dep/slice.json +56 -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 +203 -3
- package/src/create-quiver/lib/handoff.js +104 -0
- package/src/create-quiver/lib/init-docs.js +108 -13
- package/src/create-quiver/lib/json.js +14 -0
- package/src/create-quiver/lib/lifecycle.js +3 -2
- package/src/create-quiver/lib/readiness.js +55 -1
- 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/slice-graph.js +453 -0
- package/src/create-quiver/lib/slice.js +2 -1
- package/src/create-quiver/lib/state.js +50 -0
|
@@ -2,12 +2,17 @@ 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');
|
|
5
6
|
const { collectDoctorWarnings } = require('./lib/doctor');
|
|
6
|
-
const {
|
|
7
|
+
const { runGraph } = require('./commands/graph');
|
|
8
|
+
const { runNext } = require('./commands/next');
|
|
9
|
+
const { runPlan } = require('./commands/plan');
|
|
10
|
+
const { initializeProjectDocs, installSelfAsDevDep } = require('./lib/init-docs');
|
|
7
11
|
const { checkPrReadiness, checkScope, checkSliceReadiness } = require('./lib/readiness');
|
|
8
12
|
const { cleanupSlice, refreshActiveSlicesBoard, startSlice } = require('./lib/lifecycle');
|
|
9
13
|
const { relativePosixPath, resolveTargetRoot } = require('./lib/paths');
|
|
10
14
|
const {
|
|
15
|
+
hasQuiverInitializationEvidence,
|
|
11
16
|
readState,
|
|
12
17
|
updateStateForAnalyze,
|
|
13
18
|
updateStateForMigrate,
|
|
@@ -23,11 +28,16 @@ function printUsage() {
|
|
|
23
28
|
console.log(`Usage:
|
|
24
29
|
npx create-quiver [options]
|
|
25
30
|
npx create-quiver analyze [options]
|
|
31
|
+
npx create-quiver plan [options]
|
|
32
|
+
npx create-quiver graph [options]
|
|
33
|
+
npx create-quiver next [options]
|
|
26
34
|
npx create-quiver migrate [options]
|
|
27
35
|
npx create-quiver doctor [options]
|
|
28
36
|
npx create-quiver start-slice [options] <slice.json>
|
|
29
37
|
npx create-quiver check-slice [options] <slice.json>
|
|
30
38
|
npx create-quiver check-pr <slice.json>
|
|
39
|
+
npx create-quiver check-handoff <handoff.md>
|
|
40
|
+
npx create-quiver new-handoff <spec-slug>
|
|
31
41
|
npx create-quiver cleanup-slice [options] <slice.json>
|
|
32
42
|
npx create-quiver check-scope [options] <slice.json>
|
|
33
43
|
npx create-quiver refresh-active-slices
|
|
@@ -35,6 +45,15 @@ function printUsage() {
|
|
|
35
45
|
Options:
|
|
36
46
|
-n, --name <project-name> Project name to generate
|
|
37
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
|
|
38
57
|
-y, --yes Skip prompts and use the provided inputs
|
|
39
58
|
-h, --help Show this help message
|
|
40
59
|
|
|
@@ -42,11 +61,20 @@ Examples:
|
|
|
42
61
|
npx create-quiver --name "My Project"
|
|
43
62
|
npx create-quiver --name "My Project" --dir ./my-project
|
|
44
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
|
|
45
71
|
cd ./my-project && npx create-quiver migrate
|
|
46
72
|
cd ./my-project && npx create-quiver doctor
|
|
47
73
|
cd ./my-project && npx create-quiver start-slice specs/my-project/slices/slice-01/slice.json
|
|
48
74
|
cd ./my-project && npx create-quiver check-slice specs/my-project/slices/slice-01/slice.json
|
|
49
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
|
|
50
78
|
cd ./my-project && npx create-quiver cleanup-slice specs/my-project/slices/slice-01/slice.json
|
|
51
79
|
cd ./my-project && npx create-quiver check-scope specs/my-project/slices/slice-01/slice.json
|
|
52
80
|
cd ./my-project && npx create-quiver refresh-active-slices
|
|
@@ -68,10 +96,19 @@ function parseArgs(argv) {
|
|
|
68
96
|
targetDir: '.',
|
|
69
97
|
strict: false,
|
|
70
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,
|
|
71
108
|
};
|
|
72
109
|
|
|
73
110
|
const args = [...argv];
|
|
74
|
-
const commandModes = new Set(['doctor', 'analyze', 'migrate', 'start-slice', 'check-slice', 'check-pr', 'cleanup-slice', 'check-scope', 'refresh-active-slices']);
|
|
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']);
|
|
75
112
|
if (commandModes.has(args[0])) {
|
|
76
113
|
result.mode = args[0];
|
|
77
114
|
args.shift();
|
|
@@ -84,6 +121,12 @@ function parseArgs(argv) {
|
|
|
84
121
|
} else if (args[0] === '--doctor') {
|
|
85
122
|
result.mode = 'doctor';
|
|
86
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();
|
|
87
130
|
}
|
|
88
131
|
|
|
89
132
|
const positional = [];
|
|
@@ -101,6 +144,11 @@ function parseArgs(argv) {
|
|
|
101
144
|
continue;
|
|
102
145
|
}
|
|
103
146
|
|
|
147
|
+
if (arg === '--skip-install') {
|
|
148
|
+
result.skipInstall = true;
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
|
|
104
152
|
if (arg === '--doctor') {
|
|
105
153
|
result.mode = 'doctor';
|
|
106
154
|
continue;
|
|
@@ -111,6 +159,16 @@ function parseArgs(argv) {
|
|
|
111
159
|
continue;
|
|
112
160
|
}
|
|
113
161
|
|
|
162
|
+
if (arg === '--check-handoff') {
|
|
163
|
+
result.mode = 'check-handoff';
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (arg === '--new-handoff') {
|
|
168
|
+
result.mode = 'new-handoff';
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
|
|
114
172
|
if (arg === '--allow-draft') {
|
|
115
173
|
result.allowDraft = true;
|
|
116
174
|
continue;
|
|
@@ -141,6 +199,67 @@ function parseArgs(argv) {
|
|
|
141
199
|
continue;
|
|
142
200
|
}
|
|
143
201
|
|
|
202
|
+
if (arg === '--json') {
|
|
203
|
+
result.json = true;
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (arg === '--show-conflicts') {
|
|
208
|
+
result.showConflicts = true;
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (arg === '--format') {
|
|
213
|
+
const value = args[++index];
|
|
214
|
+
if (!value) {
|
|
215
|
+
throw new Error(formatError('missing value for --format'));
|
|
216
|
+
}
|
|
217
|
+
result.format = value;
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (arg === '--level') {
|
|
222
|
+
const value = args[++index];
|
|
223
|
+
if (typeof value === 'undefined') {
|
|
224
|
+
throw new Error(formatError('missing value for --level'));
|
|
225
|
+
}
|
|
226
|
+
const parsed = Number.parseInt(value, 10);
|
|
227
|
+
if (!Number.isInteger(parsed) || parsed < 0) {
|
|
228
|
+
throw new Error(formatError('invalid value for --level'));
|
|
229
|
+
}
|
|
230
|
+
result.level = parsed;
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (arg === '--only-ready') {
|
|
235
|
+
result.onlyReady = true;
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (arg === '--all-ready') {
|
|
240
|
+
result.allReady = true;
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (arg === '--auto-start') {
|
|
245
|
+
result.autoStart = true;
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (arg === '--unicode') {
|
|
250
|
+
result.unicode = true;
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (arg === '--spec') {
|
|
255
|
+
const value = args[++index];
|
|
256
|
+
if (!value) {
|
|
257
|
+
throw new Error(formatError('missing value for --spec'));
|
|
258
|
+
}
|
|
259
|
+
result.specSlug = value;
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
|
|
144
263
|
if (arg === '--gate') {
|
|
145
264
|
const value = args[++index];
|
|
146
265
|
if (!value) {
|
|
@@ -183,6 +302,10 @@ function parseArgs(argv) {
|
|
|
183
302
|
if (positional.length > 0) {
|
|
184
303
|
result.targetDir = positional.shift();
|
|
185
304
|
}
|
|
305
|
+
} else if (result.mode === 'plan') {
|
|
306
|
+
if (positional.length > 0) {
|
|
307
|
+
throw new Error(formatError('plan does not accept positional arguments; use --spec <slug>'));
|
|
308
|
+
}
|
|
186
309
|
} else if (result.mode === 'refresh-active-slices') {
|
|
187
310
|
if (positional.length > 0) {
|
|
188
311
|
throw new Error(formatError('refresh-active-slices does not accept positional arguments'));
|
|
@@ -1022,6 +1145,10 @@ function runMigrate(targetDir) {
|
|
|
1022
1145
|
throw new Error(formatError(`target directory does not exist: ${projectRoot}`));
|
|
1023
1146
|
}
|
|
1024
1147
|
|
|
1148
|
+
if (!hasQuiverInitializationEvidence(projectRoot)) {
|
|
1149
|
+
throw new Error(formatError('migrate requires a project previously initialized by Quiver.\nRun: npx create-quiver --name "Project Name"'));
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1025
1152
|
const packageJson = loadPackageJson(projectRoot);
|
|
1026
1153
|
const projectName = packageJson.name || path.basename(projectRoot) || 'Quiver Project';
|
|
1027
1154
|
const packageRoot = path.resolve(__dirname, '../..');
|
|
@@ -1038,6 +1165,15 @@ function runMigrate(targetDir) {
|
|
|
1038
1165
|
});
|
|
1039
1166
|
updateStateForMigrate(projectRoot, projectName, CLI_VERSION);
|
|
1040
1167
|
|
|
1168
|
+
if (!args.skipInstall) {
|
|
1169
|
+
const installResult = installSelfAsDevDep(projectRoot, CLI_VERSION);
|
|
1170
|
+
if (installResult === 'installed') {
|
|
1171
|
+
console.log(`Added create-quiver@${CLI_VERSION} as dev dependency`);
|
|
1172
|
+
} else if (installResult === 'failed') {
|
|
1173
|
+
console.warn(`Warning: could not install create-quiver automatically. Run: npm install -D create-quiver@${CLI_VERSION}`);
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1041
1177
|
console.log(`Quiver migration completed for ${projectRoot}`);
|
|
1042
1178
|
console.log('Missing workflow files were restored without overwriting existing project files.');
|
|
1043
1179
|
} finally {
|
|
@@ -1052,6 +1188,10 @@ function runDoctor(targetDir) {
|
|
|
1052
1188
|
throw new Error(formatError(`target directory does not exist: ${projectRoot}`));
|
|
1053
1189
|
}
|
|
1054
1190
|
|
|
1191
|
+
if (!hasQuiverInitializationEvidence(projectRoot)) {
|
|
1192
|
+
throw new Error(formatError('doctor requires a project previously initialized by Quiver.\nRun init first: npx create-quiver --name "Project Name"'));
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1055
1195
|
const generatedSpecs = listGeneratedSpecDirs(projectRoot);
|
|
1056
1196
|
if (generatedSpecs.length !== 1) {
|
|
1057
1197
|
throw new Error(formatError(`expected exactly one generated spec directory, found ${generatedSpecs.length || 0}`));
|
|
@@ -1144,10 +1284,11 @@ function runDoctor(targetDir) {
|
|
|
1144
1284
|
if (!hasQuiverState) {
|
|
1145
1285
|
console.log('- Run migration first: npx create-quiver migrate');
|
|
1146
1286
|
} else if (!hasScanArtifacts) {
|
|
1147
|
-
|
|
1287
|
+
console.log('- Analyze the project first: npx create-quiver analyze');
|
|
1148
1288
|
} else {
|
|
1149
1289
|
console.log('- Ask your AI agent: Read AGENTS.md, then docs/AI_ONBOARDING_PROMPT.md and execute it.');
|
|
1150
1290
|
}
|
|
1291
|
+
console.log('- Check the next ready slice: npx create-quiver next');
|
|
1151
1292
|
console.log(`- Start a slice: npx create-quiver start-slice specs/${projectSlug}/slices/slice-template/slice.json`);
|
|
1152
1293
|
console.log(`- Validate a slice: npx create-quiver check-slice specs/${projectSlug}/slices/slice-template/slice.json`);
|
|
1153
1294
|
console.log(`- Validate the PR gate: npx create-quiver check-pr specs/${projectSlug}/slices/slice-template/slice.json`);
|
|
@@ -1177,6 +1318,37 @@ async function run(argv) {
|
|
|
1177
1318
|
return;
|
|
1178
1319
|
}
|
|
1179
1320
|
|
|
1321
|
+
if (args.mode === 'plan') {
|
|
1322
|
+
runPlan(process.cwd(), {
|
|
1323
|
+
json: args.json,
|
|
1324
|
+
onlyReady: args.onlyReady,
|
|
1325
|
+
specSlug: args.specSlug,
|
|
1326
|
+
unicode: args.unicode,
|
|
1327
|
+
});
|
|
1328
|
+
return;
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
if (args.mode === 'graph') {
|
|
1332
|
+
runGraph(process.cwd(), {
|
|
1333
|
+
format: args.format,
|
|
1334
|
+
json: args.json,
|
|
1335
|
+
level: args.level,
|
|
1336
|
+
showConflicts: args.showConflicts,
|
|
1337
|
+
unicode: args.unicode,
|
|
1338
|
+
});
|
|
1339
|
+
return;
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
if (args.mode === 'next') {
|
|
1343
|
+
await runNext(process.cwd(), {
|
|
1344
|
+
allReady: args.allReady,
|
|
1345
|
+
autoStart: args.autoStart,
|
|
1346
|
+
json: args.json,
|
|
1347
|
+
specSlug: args.specSlug,
|
|
1348
|
+
});
|
|
1349
|
+
return;
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1180
1352
|
if (args.mode === 'migrate') {
|
|
1181
1353
|
runMigrate(args.targetDir);
|
|
1182
1354
|
return;
|
|
@@ -1205,6 +1377,25 @@ async function run(argv) {
|
|
|
1205
1377
|
return;
|
|
1206
1378
|
}
|
|
1207
1379
|
|
|
1380
|
+
if (args.mode === 'check-handoff') {
|
|
1381
|
+
const repoRoot = process.cwd();
|
|
1382
|
+
const handoffInput = args.targetDir;
|
|
1383
|
+
if (!handoffInput || handoffInput === '.') {
|
|
1384
|
+
throw new Error(formatError('missing handoff path. Use: npx create-quiver check-handoff specs/<spec-slug>/HANDOFF.md'));
|
|
1385
|
+
}
|
|
1386
|
+
const resolved = checkHandoff(handoffInput, repoRoot);
|
|
1387
|
+
console.log(`PASS: Handoff validated at ${resolved.relativePath}`);
|
|
1388
|
+
return;
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
if (args.mode === 'new-handoff') {
|
|
1392
|
+
const repoRoot = process.cwd();
|
|
1393
|
+
const handoffSlug = args.targetDir;
|
|
1394
|
+
const resolved = scaffoldHandoff(handoffSlug, repoRoot);
|
|
1395
|
+
console.log(`PASS: Handoff scaffolded at ${resolved.relativePath}`);
|
|
1396
|
+
return;
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1208
1399
|
if (args.mode === 'cleanup-slice') {
|
|
1209
1400
|
cleanupSlice(path.resolve(process.cwd(), args.targetDir), {
|
|
1210
1401
|
closeBaseline: args.closeBaseline,
|
|
@@ -1238,6 +1429,15 @@ async function run(argv) {
|
|
|
1238
1429
|
copyTemplate(templateRoot, targetDir);
|
|
1239
1430
|
runInitDocs(targetDir, projectName);
|
|
1240
1431
|
|
|
1432
|
+
if (!args.skipInstall) {
|
|
1433
|
+
const installResult = installSelfAsDevDep(targetDir, CLI_VERSION);
|
|
1434
|
+
if (installResult === 'installed') {
|
|
1435
|
+
console.log(`Added create-quiver@${CLI_VERSION} as dev dependency`);
|
|
1436
|
+
} else if (installResult === 'failed') {
|
|
1437
|
+
console.warn(`Warning: could not install create-quiver automatically. Run: npm install -D create-quiver@${CLI_VERSION}`);
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1241
1441
|
console.log(`Installed Quiver into ${targetDir}`);
|
|
1242
1442
|
printInitNextSteps(targetDir, projectName);
|
|
1243
1443
|
} finally {
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
const REQUIRED_HEADINGS = [
|
|
5
|
+
'## Background',
|
|
6
|
+
'## What you will change',
|
|
7
|
+
'## Validation checklist',
|
|
8
|
+
'## Out of scope',
|
|
9
|
+
'## Expected deliverable',
|
|
10
|
+
'## Constraints',
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
const HANDOFF_TEMPLATE_PATH = path.resolve(__dirname, '..', '..', '..', 'specs', '[project-name]', 'HANDOFF.md.template');
|
|
14
|
+
|
|
15
|
+
function normalizePosixPath(filePath, pathLib = path) {
|
|
16
|
+
return filePath.split(pathLib.sep).join('/');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function resolveHandoffPath(repoRoot, handoffInput, pathLib = path) {
|
|
20
|
+
const absolutePath = pathLib.resolve(repoRoot, handoffInput);
|
|
21
|
+
const relativePath = normalizePosixPath(pathLib.relative(repoRoot, absolutePath), pathLib);
|
|
22
|
+
|
|
23
|
+
if (relativePath.startsWith('..') || pathLib.isAbsolute(relativePath)) {
|
|
24
|
+
throw new Error(`create-quiver: handoff must live at specs/<spec-slug>/HANDOFF.md (got ${normalizePosixPath(handoffInput, pathLib)})`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const match = relativePath.match(/^specs\/([^/]+)\/HANDOFF\.md$/);
|
|
28
|
+
if (!match) {
|
|
29
|
+
throw new Error(`create-quiver: handoff must live at specs/<spec-slug>/HANDOFF.md (got ${relativePath})`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
absolutePath,
|
|
34
|
+
relativePath,
|
|
35
|
+
specSlug: match[1],
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function readHandoffSections(text) {
|
|
40
|
+
return String(text || '')
|
|
41
|
+
.split(/\r?\n/)
|
|
42
|
+
.map((line) => line.trim())
|
|
43
|
+
.filter((line) => line.startsWith('## '))
|
|
44
|
+
.map((line) => line.replace(/\s+$/, ''));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function validateHandoffSections(text) {
|
|
48
|
+
const sections = new Set(readHandoffSections(text));
|
|
49
|
+
return REQUIRED_HEADINGS.filter((heading) => !sections.has(heading));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function checkHandoff(handoffInput, repoRoot = process.cwd()) {
|
|
53
|
+
const resolved = resolveHandoffPath(repoRoot, handoffInput);
|
|
54
|
+
|
|
55
|
+
if (!fs.existsSync(resolved.absolutePath)) {
|
|
56
|
+
throw new Error(`create-quiver: missing handoff file: ${resolved.relativePath}`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const text = fs.readFileSync(resolved.absolutePath, 'utf8');
|
|
60
|
+
const missingSections = validateHandoffSections(text);
|
|
61
|
+
if (missingSections.length > 0) {
|
|
62
|
+
throw new Error(`create-quiver: handoff is missing required sections: ${missingSections.join(', ')}`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return resolved;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function scaffoldHandoff(specSlug, repoRoot = process.cwd()) {
|
|
69
|
+
const trimmedSlug = String(specSlug || '').trim();
|
|
70
|
+
if (!trimmedSlug) {
|
|
71
|
+
throw new Error('create-quiver: missing handoff slug. Use: npx create-quiver new-handoff <spec-slug>');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (!fs.existsSync(HANDOFF_TEMPLATE_PATH)) {
|
|
75
|
+
throw new Error('create-quiver: missing handoff template at specs/[project-name]/HANDOFF.md.template');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const resolved = resolveHandoffPath(repoRoot, path.join('specs', trimmedSlug, 'HANDOFF.md'));
|
|
79
|
+
if (fs.existsSync(resolved.absolutePath)) {
|
|
80
|
+
throw new Error(`create-quiver: handoff already exists at ${resolved.relativePath}`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const templateText = fs.readFileSync(HANDOFF_TEMPLATE_PATH, 'utf8');
|
|
84
|
+
const projectName = trimmedSlug.replace(/-/g, ' ');
|
|
85
|
+
const currentDate = new Date().toISOString().slice(0, 10);
|
|
86
|
+
const renderedText = templateText
|
|
87
|
+
.replace(/{{PROJECT_NAME}}/g, projectName)
|
|
88
|
+
.replace(/{{PROJECT_SLUG}}/g, trimmedSlug)
|
|
89
|
+
.replace(/{{FECHA}}/g, currentDate);
|
|
90
|
+
|
|
91
|
+
fs.mkdirSync(path.dirname(resolved.absolutePath), { recursive: true });
|
|
92
|
+
fs.writeFileSync(resolved.absolutePath, renderedText);
|
|
93
|
+
|
|
94
|
+
return checkHandoff(resolved.relativePath, repoRoot);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
module.exports = {
|
|
98
|
+
REQUIRED_HEADINGS,
|
|
99
|
+
checkHandoff,
|
|
100
|
+
readHandoffSections,
|
|
101
|
+
scaffoldHandoff,
|
|
102
|
+
resolveHandoffPath,
|
|
103
|
+
validateHandoffSections,
|
|
104
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
+
const { execSync } = require('child_process');
|
|
3
4
|
const { writeState } = require('./state');
|
|
4
5
|
|
|
5
6
|
function ensureDir(dirPath) {
|
|
@@ -61,6 +62,9 @@ function renderTemplate(text, replacements) {
|
|
|
61
62
|
.replace(/{{PRIMARY_DEV}}/g, replacements.primaryDev || 'not defined')
|
|
62
63
|
.replace(/{{PRIMARY_TEST}}/g, replacements.primaryTest || 'not defined')
|
|
63
64
|
.replace(/{{ANALYZE_COMMAND}}/g, replacements.analyzeCommand || 'npx create-quiver analyze')
|
|
65
|
+
.replace(/{{PLAN_COMMAND}}/g, replacements.planCommand || 'npx create-quiver plan')
|
|
66
|
+
.replace(/{{GRAPH_COMMAND}}/g, replacements.graphCommand || 'npx create-quiver graph')
|
|
67
|
+
.replace(/{{NEXT_COMMAND}}/g, replacements.nextCommand || 'npx create-quiver next')
|
|
64
68
|
.replace(/{{DOCTOR_COMMAND}}/g, replacements.doctorCommand || 'npx create-quiver doctor')
|
|
65
69
|
.replace(/{{START_SLICE_COMMAND}}/g, replacements.startSliceCommand || 'npx create-quiver start-slice <slice.json>')
|
|
66
70
|
.replace(/{{CHECK_SLICE_COMMAND}}/g, replacements.checkSliceCommand || 'npx create-quiver check-slice <slice.json>')
|
|
@@ -227,12 +231,22 @@ function buildReadme(projectName, projectSlug) {
|
|
|
227
231
|
|
|
228
232
|
## Quick Start
|
|
229
233
|
|
|
230
|
-
Run Quiver from this project root. Do not install it globally.
|
|
234
|
+
Run Quiver from this project root. Do not install it globally.
|
|
231
235
|
|
|
232
236
|
\`\`\`bash
|
|
233
237
|
npm install
|
|
234
|
-
|
|
235
|
-
|
|
238
|
+
{{ANALYZE_COMMAND}}
|
|
239
|
+
{{PLAN_COMMAND}}
|
|
240
|
+
{{GRAPH_COMMAND}}
|
|
241
|
+
{{DOCTOR_COMMAND}}
|
|
242
|
+
{{NEXT_COMMAND}}
|
|
243
|
+
\`\`\`
|
|
244
|
+
|
|
245
|
+
Exportable graph formats are available when you need a PR-ready Mermaid block or Graphviz source:
|
|
246
|
+
|
|
247
|
+
\`\`\`bash
|
|
248
|
+
{{GRAPH_COMMAND}} --format mermaid
|
|
249
|
+
{{GRAPH_COMMAND}} --format dot
|
|
236
250
|
\`\`\`
|
|
237
251
|
|
|
238
252
|
If this project needs a pinned Quiver version, install it as a devDependency:
|
|
@@ -251,17 +265,28 @@ The generated project includes \`quiver:*\` npm scripts that call the Node CLI a
|
|
|
251
265
|
|
|
252
266
|
\`\`\`bash
|
|
253
267
|
npm run quiver:analyze
|
|
268
|
+
npm run quiver:plan
|
|
269
|
+
npm run quiver:graph
|
|
270
|
+
npm run quiver:next
|
|
254
271
|
npm run quiver:doctor
|
|
255
272
|
npm run quiver:migrate
|
|
256
273
|
npm run quiver:start-slice -- specs/${projectSlug}/slices/slice-01/slice.json
|
|
257
274
|
npm run quiver:check-slice -- specs/${projectSlug}/slices/slice-01/slice.json
|
|
258
275
|
npm run quiver:check-pr -- specs/${projectSlug}/slices/slice-01/slice.json
|
|
276
|
+
npm run quiver:check-handoff -- specs/${projectSlug}/HANDOFF.md
|
|
259
277
|
npm run quiver:cleanup-slice -- specs/${projectSlug}/slices/slice-01/slice.json
|
|
260
278
|
npm run quiver:check-scope -- specs/${projectSlug}/slices/slice-01/slice.json
|
|
261
279
|
npm run quiver:refresh-active-slices
|
|
262
280
|
\`\`\`
|
|
263
281
|
|
|
282
|
+
The \`quiver:graph\` script prints the tree view by default; use \`npx create-quiver graph --format mermaid\` for PR-ready Markdown and \`--format dot\` when you want Graphviz source.
|
|
283
|
+
The \`quiver:next\` script points to the next ready slice and can auto-start it behind a confirmation prompt.
|
|
284
|
+
Use \`npx create-quiver next --all-ready\` when you want the full ready level instead of a single suggestion.
|
|
264
285
|
The legacy Bash wrappers remain in \`tools/scripts/\` for compatibility, but new project-level automation should prefer the \`quiver:*\` scripts and the direct \`npx create-quiver ...\` commands below.
|
|
286
|
+
\`npm run quiver:migrate\` is only for projects that were already initialized by Quiver.
|
|
287
|
+
\`npm run check-handoff -- specs/${projectSlug}/HANDOFF.md\` is available as a legacy-friendly alias for the handoff validator.
|
|
288
|
+
If a new bounded transfer is needed, scaffold \`specs/${projectSlug}/HANDOFF.md\` with \`npx create-quiver new-handoff ${projectSlug}\` and validate it with \`npx create-quiver check-handoff specs/${projectSlug}/HANDOFF.md\`.
|
|
289
|
+
For exceptional context transfers between agents or phases, a dedicated \`HANDOFF.md\` can live alongside the usual spec and docs files.
|
|
265
290
|
|
|
266
291
|
## Cross-Platform Support
|
|
267
292
|
|
|
@@ -274,8 +299,19 @@ If the project already existed before this Quiver version, upgrade it from the p
|
|
|
274
299
|
\`\`\`bash
|
|
275
300
|
cd /path/to/your-project
|
|
276
301
|
npx create-quiver migrate
|
|
277
|
-
|
|
278
|
-
|
|
302
|
+
{{ANALYZE_COMMAND}}
|
|
303
|
+
{{PLAN_COMMAND}}
|
|
304
|
+
{{GRAPH_COMMAND}}
|
|
305
|
+
{{NEXT_COMMAND}}
|
|
306
|
+
{{DOCTOR_COMMAND}}
|
|
307
|
+
\`\`\`
|
|
308
|
+
|
|
309
|
+
Use \`{{GRAPH_COMMAND}} --format mermaid\` for GitHub-friendly graph embeds or \`{{GRAPH_COMMAND}} --format dot\` for Graphviz pipelines.
|
|
310
|
+
|
|
311
|
+
If the project never ran Quiver initialization before, do not use \`migrate\` as bootstrap. Run:
|
|
312
|
+
|
|
313
|
+
\`\`\`bash
|
|
314
|
+
npx create-quiver --name "Project Name"
|
|
279
315
|
\`\`\`
|
|
280
316
|
|
|
281
317
|
If your team prefers a pinned local dependency, update the package first and then run the same flow:
|
|
@@ -283,10 +319,15 @@ If your team prefers a pinned local dependency, update the package first and the
|
|
|
283
319
|
\`\`\`bash
|
|
284
320
|
npm install --save-dev create-quiver@latest
|
|
285
321
|
npx create-quiver migrate
|
|
286
|
-
|
|
287
|
-
|
|
322
|
+
{{ANALYZE_COMMAND}}
|
|
323
|
+
{{PLAN_COMMAND}}
|
|
324
|
+
{{GRAPH_COMMAND}}
|
|
325
|
+
{{NEXT_COMMAND}}
|
|
326
|
+
{{DOCTOR_COMMAND}}
|
|
288
327
|
\`\`\`
|
|
289
328
|
|
|
329
|
+
The tree output remains the default, but Mermaid and DOT are available on demand for exported docs and slide decks.
|
|
330
|
+
|
|
290
331
|
## AI Context Onboarding
|
|
291
332
|
|
|
292
333
|
Read \`AGENTS.md\` first, then open \`docs/AI_ONBOARDING_PROMPT.md\` after analysis.
|
|
@@ -300,6 +341,7 @@ Prepare the project context docs and report assumptions, risks, and files change
|
|
|
300
341
|
\`\`\`
|
|
301
342
|
|
|
302
343
|
Review the AI changes to docs/AI_CONTEXT.md, docs/CONTEXTO.md, docs/STATUS.md, and specs/${projectSlug}/SPEC.md before starting implementation work. Use \`docs/PROJECT_MAP.md\` for stack and command details.
|
|
344
|
+
If the work was explicitly transferred through a handoff artifact, read \`specs/${projectSlug}/HANDOFF.md\` before implementation.
|
|
303
345
|
|
|
304
346
|
## Decision Log
|
|
305
347
|
|
|
@@ -309,15 +351,21 @@ Record durable decisions in \`docs/DECISIONS.md\` so future AI agents do not re-
|
|
|
309
351
|
|
|
310
352
|
1. Review or refine specs/${projectSlug}/SPEC.md.
|
|
311
353
|
2. Create the first slice from specs/${projectSlug}/slices/slice-template/slice.json.
|
|
312
|
-
3.
|
|
313
|
-
4.
|
|
314
|
-
5.
|
|
354
|
+
3. Review the plan with \`{{PLAN_COMMAND}}\` or \`npm run quiver:plan\`.
|
|
355
|
+
4. Inspect parallel lots with \`{{GRAPH_COMMAND}}\` or \`npm run quiver:graph\`.
|
|
356
|
+
5. Check the next ready slice with \`{{NEXT_COMMAND}}\` or \`npm run quiver:next\`.
|
|
357
|
+
6. Start work with \`{{START_SLICE_COMMAND}}\` or \`npm run quiver:start-slice -- <slice.json>\`.
|
|
358
|
+
7. Make one commit per slice.
|
|
359
|
+
8. Open one PR per spec.
|
|
315
360
|
|
|
316
361
|
## Verification Checklist
|
|
317
362
|
|
|
318
363
|
- [ ] npm install completes
|
|
319
|
-
- [ ]
|
|
320
|
-
- [ ]
|
|
364
|
+
- [ ] {{ANALYZE_COMMAND}} completes
|
|
365
|
+
- [ ] {{PLAN_COMMAND}} completes
|
|
366
|
+
- [ ] {{GRAPH_COMMAND}} completes
|
|
367
|
+
- [ ] {{NEXT_COMMAND}} completes
|
|
368
|
+
- [ ] {{DOCTOR_COMMAND}} completes
|
|
321
369
|
- [ ] AI agent executed docs/AI_ONBOARDING_PROMPT.md
|
|
322
370
|
- [ ] Context docs were reviewed before the first slice
|
|
323
371
|
|
|
@@ -326,6 +374,9 @@ Record durable decisions in \`docs/DECISIONS.md\` so future AI agents do not re-
|
|
|
326
374
|
- [AI Context](./docs/AI_CONTEXT.md) - Contexto resumido para IA
|
|
327
375
|
- [Decision Log](./docs/DECISIONS.md) - Decisiones durables del proyecto
|
|
328
376
|
- [AI Onboarding Prompt](./docs/AI_ONBOARDING_PROMPT.md) - Handoff exacto para agentes después del análisis
|
|
377
|
+
- [Handoff](./specs/${projectSlug}/HANDOFF.md) - Transferencia excepcional entre agentes o fases
|
|
378
|
+
- [Check Handoff](./docs/WORKFLOW.md) - Valida el handoff con \`npx create-quiver check-handoff\`
|
|
379
|
+
- [Commands](./docs/COMMANDS.md) - Tabla canónica de comandos de orquestación
|
|
329
380
|
- [Contexto](./docs/CONTEXTO.md) - Qué es ${projectName}
|
|
330
381
|
- [Workflow](./docs/WORKFLOW.md) - Cómo implementar
|
|
331
382
|
- [Support Matrix](./docs/SUPPORT_MATRIX.md) - Qué entornos están soportados
|
|
@@ -382,6 +433,7 @@ function initializeProjectDocs(options) {
|
|
|
382
433
|
});
|
|
383
434
|
const templateCopies = [
|
|
384
435
|
['docs/INDEX.md.template', 'docs/INDEX.md'],
|
|
436
|
+
['docs/COMMANDS.md.template', 'docs/COMMANDS.md'],
|
|
385
437
|
['docs/DECISIONS.md.template', 'docs/DECISIONS.md'],
|
|
386
438
|
['docs/AI_CONTEXT.md.template', 'docs/AI_CONTEXT.md', frontMatterFor('Agent-facing project context pack', 'onboarding, implementation, review')],
|
|
387
439
|
['docs/AI_ONBOARDING_PROMPT.md.template', 'docs/AI_ONBOARDING_PROMPT.md', frontMatterFor('AI onboarding handoff prompt', 'onboarding after analysis')],
|
|
@@ -398,6 +450,7 @@ function initializeProjectDocs(options) {
|
|
|
398
450
|
['docs/TESTING_GUIDE_FOR_AI.md.template', 'docs/TESTING_GUIDE_FOR_AI.md'],
|
|
399
451
|
['docs/ai/LESSONS.md.template', 'docs/ai/LESSONS.md', frontMatterFor('Slice learnings log', 'after slice completion')],
|
|
400
452
|
['specs/[project-name]/SPEC.md.template', `specs/${replacements.projectSlug}/SPEC.md`],
|
|
453
|
+
['specs/[project-name]/HANDOFF.md.template', `specs/${replacements.projectSlug}/HANDOFF.md`],
|
|
401
454
|
['specs/[project-name]/STATUS.md.template', `specs/${replacements.projectSlug}/STATUS.md`],
|
|
402
455
|
['specs/[project-name]/EVIDENCE_REPORT.md.template', `specs/${replacements.projectSlug}/EVIDENCE_REPORT.md`],
|
|
403
456
|
['specs/[project-name]/slices/slice-template/slice.json', `specs/${replacements.projectSlug}/slices/slice-template/slice.json`],
|
|
@@ -479,6 +532,9 @@ function initializeProjectDocs(options) {
|
|
|
479
532
|
primaryDev: packageScripts.dev || packageScripts.start || 'not defined',
|
|
480
533
|
primaryTest: packageScripts.test || 'not defined',
|
|
481
534
|
analyzeCommand: 'npx create-quiver analyze',
|
|
535
|
+
planCommand: 'npx create-quiver plan',
|
|
536
|
+
graphCommand: 'npx create-quiver graph',
|
|
537
|
+
nextCommand: 'npx create-quiver next',
|
|
482
538
|
doctorCommand: 'npx create-quiver doctor',
|
|
483
539
|
startSliceCommand: 'npx create-quiver start-slice <slice.json>',
|
|
484
540
|
checkSliceCommand: 'npx create-quiver check-slice <slice.json>',
|
|
@@ -492,6 +548,9 @@ function initializeProjectDocs(options) {
|
|
|
492
548
|
['docs/QUICK.md.template', 'docs/ai/QUICK.md'],
|
|
493
549
|
['docs/STANDARD.md.template', 'docs/ai/STANDARD.md'],
|
|
494
550
|
['docs/DEEP.md.template', 'docs/ai/DEEP.md'],
|
|
551
|
+
['docs/examples/plan.md.template', 'docs/examples/plan.md'],
|
|
552
|
+
['docs/examples/graph.md.template', 'docs/examples/graph.md'],
|
|
553
|
+
['docs/examples/next.md.template', 'docs/examples/next.md'],
|
|
495
554
|
];
|
|
496
555
|
|
|
497
556
|
for (const [source, destination] of tierCopies) {
|
|
@@ -597,7 +656,7 @@ function initializeProjectDocs(options) {
|
|
|
597
656
|
|
|
598
657
|
const readmePath = path.join(projectRoot, 'README.md');
|
|
599
658
|
if (!fs.existsSync(readmePath)) {
|
|
600
|
-
fs.writeFileSync(readmePath, `${buildReadme(projectName, replacements.projectSlug)}\n`);
|
|
659
|
+
fs.writeFileSync(readmePath, `${renderTemplate(buildReadme(projectName, replacements.projectSlug), replacements)}\n`);
|
|
601
660
|
operations.push({ source: 'README.md template', destination: 'README.md', result: 'created' });
|
|
602
661
|
} else {
|
|
603
662
|
operations.push({ source: 'README.md template', destination: 'README.md', result: 'skipped' });
|
|
@@ -609,8 +668,44 @@ function initializeProjectDocs(options) {
|
|
|
609
668
|
};
|
|
610
669
|
}
|
|
611
670
|
|
|
671
|
+
function detectPackageManager(projectRoot) {
|
|
672
|
+
if (fs.existsSync(path.join(projectRoot, 'bun.lockb'))) return 'bun';
|
|
673
|
+
if (fs.existsSync(path.join(projectRoot, 'pnpm-lock.yaml'))) return 'pnpm';
|
|
674
|
+
if (fs.existsSync(path.join(projectRoot, 'yarn.lock'))) return 'yarn';
|
|
675
|
+
return 'npm';
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
function installSelfAsDevDep(projectRoot, version) {
|
|
679
|
+
const packageJsonPath = path.join(projectRoot, 'package.json');
|
|
680
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
681
|
+
return 'skipped-no-package-json';
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
685
|
+
if (pkg.devDependencies && pkg.devDependencies['create-quiver']) {
|
|
686
|
+
return 'skipped-already-present';
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
const pm = detectPackageManager(projectRoot);
|
|
690
|
+
const commands = {
|
|
691
|
+
npm: `npm install -D create-quiver@${version}`,
|
|
692
|
+
yarn: `yarn add -D create-quiver@${version}`,
|
|
693
|
+
pnpm: `pnpm add -D create-quiver@${version}`,
|
|
694
|
+
bun: `bun add -d create-quiver@${version}`,
|
|
695
|
+
};
|
|
696
|
+
|
|
697
|
+
try {
|
|
698
|
+
execSync(commands[pm], { cwd: projectRoot, stdio: 'inherit' });
|
|
699
|
+
return 'installed';
|
|
700
|
+
} catch {
|
|
701
|
+
return 'failed';
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
612
705
|
module.exports = {
|
|
613
706
|
initializeProjectDocs,
|
|
614
707
|
writeFrontMatter,
|
|
615
708
|
toProjectSlug,
|
|
709
|
+
detectPackageManager,
|
|
710
|
+
installSelfAsDevDep,
|
|
616
711
|
};
|