create-quiver 0.9.0 → 0.10.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.
Files changed (111) hide show
  1. package/README.md +312 -124
  2. package/README_FOR_AI.md +59 -45
  3. package/ROADMAP.md +12 -11
  4. package/docs/AI_ONBOARDING_PROMPT.md.template +120 -52
  5. package/docs/COMMANDS.md.template +41 -6
  6. package/docs/GITFLOW_PR_GUIDE.md.template +11 -0
  7. package/docs/STANDARD.md.template +1 -1
  8. package/docs/SUPPORT_MATRIX.md.template +4 -0
  9. package/docs/TROUBLESHOOTING.md.template +29 -1
  10. package/docs/WORKFLOW.md.template +1 -1
  11. package/package.json +6 -1
  12. package/package.template.json +11 -6
  13. package/scripts/check-pr-readiness.sh +1 -1
  14. package/scripts/check-scope.sh +0 -1
  15. package/scripts/check-slice-readiness.sh +3 -4
  16. package/scripts/init-docs.sh +55 -9
  17. package/specs/quiver-v19-self-install-dev-dep/EVIDENCE_REPORT.md +2 -2
  18. package/specs/quiver-v19-self-install-dev-dep/STATUS.md +4 -4
  19. package/specs/quiver-v19-self-install-dev-dep/slices/slice-01-auto-install-dev-dep/slice.json +4 -4
  20. package/specs/quiver-v20-ai-cli-orchestration/EVIDENCE_REPORT.md +23 -0
  21. package/specs/quiver-v20-ai-cli-orchestration/EXECUTION_PLAN.md +57 -0
  22. package/specs/quiver-v20-ai-cli-orchestration/SPEC.md +202 -0
  23. package/specs/quiver-v20-ai-cli-orchestration/STATUS.md +35 -0
  24. package/specs/quiver-v20-ai-cli-orchestration/pr.md +100 -0
  25. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-00-spec-foundation/CLOSURE_BRIEF.md +30 -0
  26. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-00-spec-foundation/EXECUTION_BRIEF.md +61 -0
  27. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-00-spec-foundation/slice.json +54 -0
  28. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-01-ai-provider-runner/CLOSURE_BRIEF.md +39 -0
  29. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-01-ai-provider-runner/EXECUTION_BRIEF.md +63 -0
  30. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-01-ai-provider-runner/slice.json +55 -0
  31. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-02-context-packs-token-budget/CLOSURE_BRIEF.md +40 -0
  32. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-02-context-packs-token-budget/EXECUTION_BRIEF.md +60 -0
  33. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-02-context-packs-token-budget/slice.json +54 -0
  34. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-03-ai-phase-gated-planner/CLOSURE_BRIEF.md +43 -0
  35. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-03-ai-phase-gated-planner/EXECUTION_BRIEF.md +62 -0
  36. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-03-ai-phase-gated-planner/slice.json +62 -0
  37. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-04-spec-slice-handoff-pr-generation/CLOSURE_BRIEF.md +36 -0
  38. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-04-spec-slice-handoff-pr-generation/EXECUTION_BRIEF.md +63 -0
  39. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-04-spec-slice-handoff-pr-generation/slice.json +59 -0
  40. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-05-execution-plan-parallel-worktrees/CLOSURE_BRIEF.md +32 -0
  41. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-05-execution-plan-parallel-worktrees/EXECUTION_BRIEF.md +61 -0
  42. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-05-execution-plan-parallel-worktrees/slice.json +59 -0
  43. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-06-ai-execute-slice-scope-enforcement/CLOSURE_BRIEF.md +36 -0
  44. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-06-ai-execute-slice-scope-enforcement/EXECUTION_BRIEF.md +64 -0
  45. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-06-ai-execute-slice-scope-enforcement/slice.json +65 -0
  46. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-07-github-pr-preflight/CLOSURE_BRIEF.md +36 -0
  47. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-07-github-pr-preflight/EXECUTION_BRIEF.md +66 -0
  48. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-07-github-pr-preflight/slice.json +63 -0
  49. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-08-docs-smokes-release-readiness/CLOSURE_BRIEF.md +35 -0
  50. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-08-docs-smokes-release-readiness/EXECUTION_BRIEF.md +64 -0
  51. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-08-docs-smokes-release-readiness/slice.json +77 -0
  52. package/specs/quiver-v21-ai-first-layout/EVIDENCE_REPORT.md +31 -0
  53. package/specs/quiver-v21-ai-first-layout/EXECUTION_PLAN.md +185 -0
  54. package/specs/quiver-v21-ai-first-layout/SPEC.md +212 -0
  55. package/specs/quiver-v21-ai-first-layout/STATUS.md +37 -0
  56. package/specs/quiver-v21-ai-first-layout/pr.md +110 -0
  57. package/specs/quiver-v21-ai-first-layout/slices/slice-00-spec-foundation/CLOSURE_BRIEF.md +30 -0
  58. package/specs/quiver-v21-ai-first-layout/slices/slice-00-spec-foundation/EXECUTION_BRIEF.md +63 -0
  59. package/specs/quiver-v21-ai-first-layout/slices/slice-00-spec-foundation/slice.json +45 -0
  60. package/specs/quiver-v21-ai-first-layout/slices/slice-01-init-profiles-dry-run/CLOSURE_BRIEF.md +31 -0
  61. package/specs/quiver-v21-ai-first-layout/slices/slice-01-init-profiles-dry-run/EXECUTION_BRIEF.md +59 -0
  62. package/specs/quiver-v21-ai-first-layout/slices/slice-01-init-profiles-dry-run/slice.json +57 -0
  63. package/specs/quiver-v21-ai-first-layout/slices/slice-02-internal-layout-template-resolver/CLOSURE_BRIEF.md +32 -0
  64. package/specs/quiver-v21-ai-first-layout/slices/slice-02-internal-layout-template-resolver/EXECUTION_BRIEF.md +60 -0
  65. package/specs/quiver-v21-ai-first-layout/slices/slice-02-internal-layout-template-resolver/slice.json +58 -0
  66. package/specs/quiver-v21-ai-first-layout/slices/slice-03-generation-profiles-visible-contract/CLOSURE_BRIEF.md +34 -0
  67. package/specs/quiver-v21-ai-first-layout/slices/slice-03-generation-profiles-visible-contract/EXECUTION_BRIEF.md +61 -0
  68. package/specs/quiver-v21-ai-first-layout/slices/slice-03-generation-profiles-visible-contract/slice.json +64 -0
  69. package/specs/quiver-v21-ai-first-layout/slices/slice-04-analyze-scan-relocation/CLOSURE_BRIEF.md +32 -0
  70. package/specs/quiver-v21-ai-first-layout/slices/slice-04-analyze-scan-relocation/EXECUTION_BRIEF.md +58 -0
  71. package/specs/quiver-v21-ai-first-layout/slices/slice-04-analyze-scan-relocation/slice.json +64 -0
  72. package/specs/quiver-v21-ai-first-layout/slices/slice-05-empty-specs-layout-doctor/CLOSURE_BRIEF.md +32 -0
  73. package/specs/quiver-v21-ai-first-layout/slices/slice-05-empty-specs-layout-doctor/EXECUTION_BRIEF.md +60 -0
  74. package/specs/quiver-v21-ai-first-layout/slices/slice-05-empty-specs-layout-doctor/slice.json +65 -0
  75. package/specs/quiver-v21-ai-first-layout/slices/slice-06-legacy-migration-optional-assets/CLOSURE_BRIEF.md +31 -0
  76. package/specs/quiver-v21-ai-first-layout/slices/slice-06-legacy-migration-optional-assets/EXECUTION_BRIEF.md +62 -0
  77. package/specs/quiver-v21-ai-first-layout/slices/slice-06-legacy-migration-optional-assets/slice.json +66 -0
  78. package/specs/quiver-v21-ai-first-layout/slices/slice-07-docs-guidance-alignment/CLOSURE_BRIEF.md +33 -0
  79. package/specs/quiver-v21-ai-first-layout/slices/slice-07-docs-guidance-alignment/EXECUTION_BRIEF.md +61 -0
  80. package/specs/quiver-v21-ai-first-layout/slices/slice-07-docs-guidance-alignment/slice.json +67 -0
  81. package/specs/quiver-v21-ai-first-layout/slices/slice-08-smokes-release-readiness/CLOSURE_BRIEF.md +35 -0
  82. package/specs/quiver-v21-ai-first-layout/slices/slice-08-smokes-release-readiness/EXECUTION_BRIEF.md +66 -0
  83. package/specs/quiver-v21-ai-first-layout/slices/slice-08-smokes-release-readiness/slice.json +62 -0
  84. package/src/create-quiver/commands/ai.js +442 -0
  85. package/src/create-quiver/index.js +421 -84
  86. package/src/create-quiver/lib/ai/context-packs.js +158 -0
  87. package/src/create-quiver/lib/ai/execution-plan.js +254 -0
  88. package/src/create-quiver/lib/ai/executor.js +323 -0
  89. package/src/create-quiver/lib/ai/github.js +329 -0
  90. package/src/create-quiver/lib/ai/phase-gates.js +72 -0
  91. package/src/create-quiver/lib/ai/preflight.js +58 -0
  92. package/src/create-quiver/lib/ai/prompt-transport.js +81 -0
  93. package/src/create-quiver/lib/ai/prompts.js +39 -0
  94. package/src/create-quiver/lib/ai/providers.js +314 -0
  95. package/src/create-quiver/lib/ai/safety.js +151 -0
  96. package/src/create-quiver/lib/ai/spec-generator.js +314 -0
  97. package/src/create-quiver/lib/ai/spec-templates.js +715 -0
  98. package/src/create-quiver/lib/doctor.js +114 -0
  99. package/src/create-quiver/lib/git.js +21 -0
  100. package/src/create-quiver/lib/init-docs.js +286 -25
  101. package/src/create-quiver/lib/init-layout.js +426 -0
  102. package/src/create-quiver/lib/lifecycle.js +2 -2
  103. package/src/create-quiver/lib/paths.js +63 -2
  104. package/src/create-quiver/lib/project-scan.js +66 -0
  105. package/src/create-quiver/lib/readiness.js +4 -2
  106. package/src/create-quiver/lib/scope.js +125 -0
  107. package/src/create-quiver/lib/slice-graph.js +6 -0
  108. package/src/create-quiver/lib/slice.js +51 -8
  109. package/src/create-quiver/lib/state.js +18 -1
  110. package/src/create-quiver/lib/template-resolver.js +74 -0
  111. package/.claude/settings.local.json +0 -52
@@ -3,16 +3,27 @@ const os = require('os');
3
3
  const path = require('path');
4
4
  const { execFileSync } = require('child_process');
5
5
  const { checkHandoff, scaffoldHandoff } = require('./lib/handoff');
6
- const { collectDoctorWarnings } = require('./lib/doctor');
6
+ const { collectDoctorReport } = require('./lib/doctor');
7
+ const { runDoctor: runAiDoctor, runExecuteSlice: runAiExecuteSlice, runOnboard, runPlan: runAiPlan, runPr: runAiPr } = require('./commands/ai');
7
8
  const { runGraph } = require('./commands/graph');
8
9
  const { runNext } = require('./commands/next');
9
10
  const { runPlan } = require('./commands/plan');
11
+ const { buildInitLayout, formatInitLayoutPlan } = require('./lib/init-layout');
10
12
  const { initializeProjectDocs, installSelfAsDevDep } = require('./lib/init-docs');
11
13
  const { checkPrReadiness, checkScope, checkSliceReadiness } = require('./lib/readiness');
12
14
  const { cleanupSlice, refreshActiveSlicesBoard, startSlice } = require('./lib/lifecycle');
13
15
  const { relativePosixPath, resolveTargetRoot } = require('./lib/paths');
16
+ const {
17
+ CURRENT_SCAN_RELATIVE_PATH,
18
+ PROJECT_MAP_RELATIVE_PATH,
19
+ hasProjectScanArtifact,
20
+ projectScanPaths,
21
+ writeProjectScanJson,
22
+ } = require('./lib/project-scan');
23
+ const { resolveTemplateRoot } = require('./lib/template-resolver');
14
24
  const {
15
25
  hasQuiverInitializationEvidence,
26
+ inspectLegacyMigrationLayout,
16
27
  readState,
17
28
  updateStateForAnalyze,
18
29
  updateStateForMigrate,
@@ -27,8 +38,10 @@ function formatError(message) {
27
38
  function printUsage() {
28
39
  console.log(`Usage:
29
40
  npx create-quiver [options]
41
+ npx create-quiver init [options]
30
42
  npx create-quiver analyze [options]
31
43
  npx create-quiver plan [options]
44
+ npx create-quiver ai <task> [options]
32
45
  npx create-quiver graph [options]
33
46
  npx create-quiver next [options]
34
47
  npx create-quiver migrate [options]
@@ -54,14 +67,26 @@ Options:
54
67
  --all-ready List every ready slice returned by next
55
68
  --auto-start Prompt for confirmation and run start-slice on next
56
69
  --unicode Prefer Unicode output when supported
70
+ --minimal Plan or run the minimal init profile
71
+ --full Plan or run the full compatibility init profile
72
+ --legacy-scripts Include legacy Bash wrappers in init profile
73
+ --include-templates Export packaged templates in init profile
74
+ --dry-run Preview init or AI work without executing writes/providers
57
75
  -y, --yes Skip prompts and use the provided inputs
58
76
  -h, --help Show this help message
59
77
 
60
78
  Examples:
79
+ npx create-quiver init --name "My Project"
80
+ npx create-quiver init --name "My Project" --dry-run
61
81
  npx create-quiver --name "My Project"
62
82
  npx create-quiver --name "My Project" --dir ./my-project
63
83
  cd ./my-project && npx create-quiver analyze
64
84
  cd ./my-project && npx create-quiver plan --json
85
+ cd ./my-project && npx create-quiver ai onboard --dry-run
86
+ cd ./my-project && npx create-quiver ai plan --phase acceptance --input requirements.md --dry-run
87
+ cd ./my-project && npx create-quiver ai execute-slice --slice specs/my-project/slices/slice-01/slice.json --dry-run
88
+ cd ./my-project && npx create-quiver ai doctor --dry-run --ssh-host-alias github-work --identity-file ~/.ssh/github-work
89
+ cd ./my-project && npx create-quiver ai pr --dry-run --ssh-host-alias github-work --identity-file ~/.ssh/github-work
65
90
  cd ./my-project && npx create-quiver graph --show-conflicts
66
91
  cd ./my-project && npx create-quiver graph --format mermaid
67
92
  cd ./my-project && npx create-quiver graph --format dot
@@ -86,6 +111,7 @@ function parseArgs(argv) {
86
111
  const result = {
87
112
  help: false,
88
113
  force: false,
114
+ explicitInit: false,
89
115
  mode: 'init',
90
116
  allowDraft: false,
91
117
  closeBaseline: false,
@@ -105,12 +131,28 @@ function parseArgs(argv) {
105
131
  showConflicts: false,
106
132
  level: null,
107
133
  unicode: false,
134
+ aiCommand: '',
135
+ aiPhase: 'acceptance',
136
+ aiProvider: 'codex',
137
+ aiRole: '',
138
+ aiContext: '',
139
+ aiInput: '',
140
+ aiSlice: '',
141
+ aiTimeout: null,
142
+ aiSshHostAlias: '',
143
+ aiIdentityFile: '',
144
+ aiRemote: 'origin',
145
+ initFull: false,
146
+ initIncludeTemplates: false,
147
+ initLegacyScripts: false,
148
+ initMinimal: false,
108
149
  };
109
150
 
110
151
  const args = [...argv];
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']);
152
+ const commandModes = new Set(['init', 'plan', 'graph', 'next', 'doctor', 'analyze', 'migrate', 'start-slice', 'check-slice', 'check-pr', 'check-handoff', 'new-handoff', 'cleanup-slice', 'check-scope', 'refresh-active-slices', 'ai']);
112
153
  if (commandModes.has(args[0])) {
113
154
  result.mode = args[0];
155
+ result.explicitInit = args[0] === 'init';
114
156
  args.shift();
115
157
  } else if (args[0] === '--analyze') {
116
158
  result.mode = 'analyze';
@@ -189,6 +231,26 @@ function parseArgs(argv) {
189
231
  continue;
190
232
  }
191
233
 
234
+ if (arg === '--minimal') {
235
+ result.initMinimal = true;
236
+ continue;
237
+ }
238
+
239
+ if (arg === '--full') {
240
+ result.initFull = true;
241
+ continue;
242
+ }
243
+
244
+ if (arg === '--legacy-scripts') {
245
+ result.initLegacyScripts = true;
246
+ continue;
247
+ }
248
+
249
+ if (arg === '--include-templates') {
250
+ result.initIncludeTemplates = true;
251
+ continue;
252
+ }
253
+
192
254
  if (arg === '--strict') {
193
255
  result.strict = true;
194
256
  continue;
@@ -251,6 +313,100 @@ function parseArgs(argv) {
251
313
  continue;
252
314
  }
253
315
 
316
+ if (arg === '--provider') {
317
+ const value = args[++index];
318
+ if (!value) {
319
+ throw new Error(formatError('missing value for --provider'));
320
+ }
321
+ result.aiProvider = value;
322
+ continue;
323
+ }
324
+
325
+ if (arg === '--role') {
326
+ const value = args[++index];
327
+ if (!value) {
328
+ throw new Error(formatError('missing value for --role'));
329
+ }
330
+ result.aiRole = value;
331
+ continue;
332
+ }
333
+
334
+ if (arg === '--context') {
335
+ const value = args[++index];
336
+ if (!value) {
337
+ throw new Error(formatError('missing value for --context'));
338
+ }
339
+ result.aiContext = value;
340
+ continue;
341
+ }
342
+
343
+ if (arg === '--input') {
344
+ const value = args[++index];
345
+ if (!value) {
346
+ throw new Error(formatError('missing value for --input'));
347
+ }
348
+ result.aiInput = value;
349
+ continue;
350
+ }
351
+
352
+ if (arg === '--slice') {
353
+ const value = args[++index];
354
+ if (!value) {
355
+ throw new Error(formatError('missing value for --slice'));
356
+ }
357
+ result.aiSlice = value;
358
+ continue;
359
+ }
360
+
361
+ if (arg === '--timeout') {
362
+ const value = args[++index];
363
+ if (typeof value === 'undefined') {
364
+ throw new Error(formatError('missing value for --timeout'));
365
+ }
366
+ const parsed = Number.parseInt(value, 10);
367
+ if (!Number.isInteger(parsed) || parsed <= 0) {
368
+ throw new Error(formatError('invalid value for --timeout'));
369
+ }
370
+ result.aiTimeout = parsed;
371
+ continue;
372
+ }
373
+
374
+ if (arg === '--ssh-host-alias') {
375
+ const value = args[++index];
376
+ if (!value) {
377
+ throw new Error(formatError('missing value for --ssh-host-alias'));
378
+ }
379
+ result.aiSshHostAlias = value;
380
+ continue;
381
+ }
382
+
383
+ if (arg === '--identity-file') {
384
+ const value = args[++index];
385
+ if (!value) {
386
+ throw new Error(formatError('missing value for --identity-file'));
387
+ }
388
+ result.aiIdentityFile = value;
389
+ continue;
390
+ }
391
+
392
+ if (arg === '--remote') {
393
+ const value = args[++index];
394
+ if (!value) {
395
+ throw new Error(formatError('missing value for --remote'));
396
+ }
397
+ result.aiRemote = value;
398
+ continue;
399
+ }
400
+
401
+ if (arg === '--phase') {
402
+ const value = args[++index];
403
+ if (!value) {
404
+ throw new Error(formatError('missing value for --phase'));
405
+ }
406
+ result.aiPhase = value;
407
+ continue;
408
+ }
409
+
254
410
  if (arg === '--spec') {
255
411
  const value = args[++index];
256
412
  if (!value) {
@@ -306,6 +462,13 @@ function parseArgs(argv) {
306
462
  if (positional.length > 0) {
307
463
  throw new Error(formatError('plan does not accept positional arguments; use --spec <slug>'));
308
464
  }
465
+ } else if (result.mode === 'ai') {
466
+ if (!result.aiCommand && positional.length > 0) {
467
+ result.aiCommand = positional.shift();
468
+ }
469
+ if (positional.length > 0) {
470
+ throw new Error(formatError('ai does not accept extra positional arguments'));
471
+ }
309
472
  } else if (result.mode === 'refresh-active-slices') {
310
473
  if (positional.length > 0) {
311
474
  throw new Error(formatError('refresh-active-slices does not accept positional arguments'));
@@ -340,6 +503,43 @@ function runCommand(command, args, options = {}) {
340
503
  });
341
504
  }
342
505
 
506
+ function copyPackageFallback(packageRoot, tempRoot) {
507
+ const fallbackDir = path.join(tempRoot, 'package-fallback');
508
+ const ignoredRoots = new Set([
509
+ '.git',
510
+ '.worktrees',
511
+ 'examples',
512
+ 'package-lock.json',
513
+ 'tests',
514
+ ]);
515
+ const ignoredPrefixes = [
516
+ 'scripts/ci',
517
+ 'specs/quiver-v01',
518
+ 'specs/quiver-v02-bootstrap-hardening',
519
+ 'specs/quiver-v03-adoption-verification',
520
+ 'specs/quiver-v04-zero-friction-installation',
521
+ ];
522
+
523
+ fs.cpSync(packageRoot, fallbackDir, {
524
+ recursive: true,
525
+ filter: (sourcePath) => {
526
+ const relativePath = relativePosixPath(packageRoot, sourcePath);
527
+ if (!relativePath || relativePath === '.') {
528
+ return true;
529
+ }
530
+
531
+ const firstSegment = relativePath.split('/')[0];
532
+ if (ignoredRoots.has(firstSegment) || ignoredRoots.has(relativePath)) {
533
+ return false;
534
+ }
535
+
536
+ return !ignoredPrefixes.some((prefix) => relativePath === prefix || relativePath.startsWith(`${prefix}/`));
537
+ },
538
+ });
539
+
540
+ return fallbackDir;
541
+ }
542
+
343
543
  function packTemplate(packageRoot, tempRoot) {
344
544
  const packDir = path.join(tempRoot, 'pack');
345
545
  const extractDir = path.join(tempRoot, 'extract');
@@ -349,24 +549,32 @@ function packTemplate(packageRoot, tempRoot) {
349
549
  fs.mkdirSync(extractDir, { recursive: true });
350
550
  fs.mkdirSync(npmCache, { recursive: true });
351
551
 
352
- const packOutput = runCommand('npm', ['pack', '--json', '--pack-destination', packDir], {
353
- cwd: packageRoot,
354
- env: {
355
- ...process.env,
356
- npm_config_cache: npmCache,
357
- },
358
- });
552
+ try {
553
+ const packOutput = runCommand('npm', ['pack', '--json', '--pack-destination', packDir], {
554
+ cwd: packageRoot,
555
+ env: {
556
+ ...process.env,
557
+ npm_config_cache: npmCache,
558
+ },
559
+ });
359
560
 
360
- const packInfo = JSON.parse(packOutput.trim());
361
- const tarballPath = path.join(packDir, packInfo[0].filename);
561
+ const packInfo = JSON.parse(packOutput.trim());
562
+ const tarballPath = path.join(packDir, packInfo[0].filename);
362
563
 
363
- if (!fs.existsSync(tarballPath)) {
364
- throw new Error(formatError(`pack output not found at ${tarballPath}`));
365
- }
564
+ if (!fs.existsSync(tarballPath)) {
565
+ throw new Error(formatError(`pack output not found at ${tarballPath}`));
566
+ }
567
+
568
+ runCommand('tar', ['-xzf', tarballPath, '-C', extractDir]);
366
569
 
367
- runCommand('tar', ['-xzf', tarballPath, '-C', extractDir]);
570
+ return path.join(extractDir, 'package');
571
+ } catch (error) {
572
+ if (error && error.code === 'ENOENT') {
573
+ return copyPackageFallback(packageRoot, tempRoot);
574
+ }
368
575
 
369
- return path.join(extractDir, 'package');
576
+ throw error;
577
+ }
370
578
  }
371
579
 
372
580
  function ensureDir(dirPath) {
@@ -385,6 +593,10 @@ function copyTemplate(templateRoot, targetDir) {
385
593
  return docsTemplateDir;
386
594
  }
387
595
 
596
+ function exportTemplatesToLegacyRoot(templateRoot, targetDir) {
597
+ return copyTemplate(templateRoot, targetDir);
598
+ }
599
+
388
600
  function mergeDirectoryTree(sourceDir, targetDir) {
389
601
  if (!fs.existsSync(sourceDir)) {
390
602
  return;
@@ -399,12 +611,22 @@ function mergeDirectoryTree(sourceDir, targetDir) {
399
611
  });
400
612
  }
401
613
 
402
- function runInitDocs(repoRoot, projectName) {
614
+ function runInitDocs(repoRoot, projectName, options = {}) {
615
+ const templateRoot = options.templateRoot
616
+ ? { path: options.templateRoot }
617
+ : resolveTemplateRoot(repoRoot, {
618
+ packageRoot: path.resolve(__dirname, '../..'),
619
+ });
620
+
403
621
  initializeProjectDocs({
404
622
  projectRoot: repoRoot,
405
623
  projectName,
406
624
  cliVersion: CLI_VERSION,
625
+ includeTemplates: options.includeTemplates === true,
626
+ legacyScripts: options.legacyScripts === true,
407
627
  migrateMode: false,
628
+ profile: options.profile || 'default',
629
+ templateRoot: templateRoot.path,
408
630
  });
409
631
  }
410
632
 
@@ -426,6 +648,10 @@ function assertFilesExist(root, relativePaths) {
426
648
  }
427
649
 
428
650
  function assertExecutablesExist(root, relativePaths) {
651
+ if (process.platform === 'win32') {
652
+ return [];
653
+ }
654
+
429
655
  return relativePaths.filter((relativePath) => {
430
656
  const absolutePath = path.join(root, relativePath);
431
657
 
@@ -931,8 +1157,8 @@ function renderProjectMap(scan) {
931
1157
  'docs/INDEX.md',
932
1158
  'docs/AI_CONTEXT.md',
933
1159
  'docs/DECISIONS.md',
934
- 'docs/PROJECT_SCAN.json',
935
- 'docs/PROJECT_MAP.md',
1160
+ CURRENT_SCAN_RELATIVE_PATH,
1161
+ PROJECT_MAP_RELATIVE_PATH,
936
1162
  'docs/AI_ONBOARDING_PROMPT.md',
937
1163
  'docs/CONTEXTO.md',
938
1164
  'docs/WORKFLOW.md',
@@ -952,8 +1178,7 @@ function renderProjectMap(scan) {
952
1178
  'README.md',
953
1179
  'docs/INDEX.md',
954
1180
  'docs/AI_CONTEXT.md',
955
- 'docs/PROJECT_SCAN.json',
956
- 'docs/PROJECT_MAP.md',
1181
+ PROJECT_MAP_RELATIVE_PATH,
957
1182
  hasDecisionLog ? 'docs/DECISIONS.md' : 'docs/DECISIONS.md (create with migrate if missing)',
958
1183
  'docs/CONTEXTO.md',
959
1184
  'docs/WORKFLOW.md',
@@ -993,7 +1218,7 @@ function renderProjectMap(scan) {
993
1218
  lines.push('## Entry Points');
994
1219
  lines.push(`- Project overview: ${scan.docs.has_readme ? 'README.md' : 'docs/CONTEXTO.md'}`);
995
1220
  lines.push(`- AI context: ${hasDecisionLog ? 'docs/AI_CONTEXT.md + docs/DECISIONS.md' : 'docs/AI_CONTEXT.md'}`);
996
- lines.push('- Analysis outputs: docs/PROJECT_SCAN.json, docs/PROJECT_MAP.md');
1221
+ lines.push(`- Analysis outputs: ${CURRENT_SCAN_RELATIVE_PATH}, ${PROJECT_MAP_RELATIVE_PATH}`);
997
1222
  lines.push(`- Workflow contract: docs/WORKFLOW.md`);
998
1223
  lines.push(`- Spec contract: specs/${projectSlug}/SPEC.md`);
999
1224
  if (sourceDirs.length > 0) {
@@ -1108,16 +1333,13 @@ function renderProjectMap(scan) {
1108
1333
  }
1109
1334
 
1110
1335
  function writeProjectScanArtifacts(projectRoot, scan) {
1111
- const docsDir = path.join(projectRoot, 'docs');
1112
- ensureDir(docsDir);
1113
-
1114
- const jsonPath = path.join(docsDir, 'PROJECT_SCAN.json');
1115
- const mdPath = path.join(docsDir, 'PROJECT_MAP.md');
1336
+ const scanPaths = projectScanPaths(projectRoot);
1337
+ ensureDir(path.dirname(scanPaths.projectMapPath));
1116
1338
 
1117
- fs.writeFileSync(jsonPath, `${JSON.stringify(scan, null, 2)}\n`);
1118
- fs.writeFileSync(mdPath, `${renderProjectMap(scan)}\n`);
1339
+ const jsonPath = writeProjectScanJson(projectRoot, scan);
1340
+ fs.writeFileSync(scanPaths.projectMapPath, `${renderProjectMap(scan)}\n`);
1119
1341
 
1120
- return { jsonPath, mdPath };
1342
+ return { jsonPath, mdPath: scanPaths.projectMapPath };
1121
1343
  }
1122
1344
 
1123
1345
  function runAnalyze(targetDir) {
@@ -1138,7 +1360,7 @@ function runAnalyze(targetDir) {
1138
1360
  console.log(`Detected package manager: ${scan.project.package_manager}`);
1139
1361
  }
1140
1362
 
1141
- function runMigrate(targetDir) {
1363
+ function runMigrate(targetDir, options = {}) {
1142
1364
  const projectRoot = resolveTargetRoot(process.cwd(), targetDir);
1143
1365
 
1144
1366
  if (!fs.existsSync(projectRoot)) {
@@ -1153,6 +1375,7 @@ function runMigrate(targetDir) {
1153
1375
  const projectName = packageJson.name || path.basename(projectRoot) || 'Quiver Project';
1154
1376
  const packageRoot = path.resolve(__dirname, '../..');
1155
1377
  const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'quiver-migrate-'));
1378
+ const legacyLayout = inspectLegacyMigrationLayout(projectRoot);
1156
1379
 
1157
1380
  try {
1158
1381
  const templateRoot = packTemplate(packageRoot, tempRoot);
@@ -1161,11 +1384,14 @@ function runMigrate(targetDir) {
1161
1384
  projectRoot,
1162
1385
  projectName,
1163
1386
  cliVersion: CLI_VERSION,
1387
+ legacyScripts: true,
1164
1388
  migrateMode: true,
1389
+ profile: 'full',
1390
+ templateRoot,
1165
1391
  });
1166
1392
  updateStateForMigrate(projectRoot, projectName, CLI_VERSION);
1167
1393
 
1168
- if (!args.skipInstall) {
1394
+ if (!options.skipInstall) {
1169
1395
  const installResult = installSelfAsDevDep(projectRoot, CLI_VERSION);
1170
1396
  if (installResult === 'installed') {
1171
1397
  console.log(`Added create-quiver@${CLI_VERSION} as dev dependency`);
@@ -1176,6 +1402,9 @@ function runMigrate(targetDir) {
1176
1402
 
1177
1403
  console.log(`Quiver migration completed for ${projectRoot}`);
1178
1404
  console.log('Missing workflow files were restored without overwriting existing project files.');
1405
+ if (legacyLayout.hasLegacyLayout) {
1406
+ console.log(`Legacy layout detected and preserved: ${legacyLayout.legacyPaths.join(', ')}`);
1407
+ }
1179
1408
  } finally {
1180
1409
  fs.rmSync(tempRoot, { recursive: true, force: true });
1181
1410
  }
@@ -1192,47 +1421,42 @@ function runDoctor(targetDir) {
1192
1421
  throw new Error(formatError('doctor requires a project previously initialized by Quiver.\nRun init first: npx create-quiver --name "Project Name"'));
1193
1422
  }
1194
1423
 
1195
- const generatedSpecs = listGeneratedSpecDirs(projectRoot);
1196
- if (generatedSpecs.length !== 1) {
1197
- throw new Error(formatError(`expected exactly one generated spec directory, found ${generatedSpecs.length || 0}`));
1198
- }
1199
-
1200
- const projectSlug = generatedSpecs[0];
1201
- const requiredFiles = [
1424
+ const doctorReport = collectDoctorReport(projectRoot);
1425
+ const specSlugs = doctorReport.specSlugs;
1426
+ const specRequiredFiles = specSlugs.flatMap((projectSlug) => [
1427
+ `specs/${projectSlug}/SPEC.md`,
1428
+ `specs/${projectSlug}/STATUS.md`,
1429
+ `specs/${projectSlug}/EVIDENCE_REPORT.md`,
1430
+ ]);
1431
+ const newLayoutRequiredFiles = [
1202
1432
  'AGENTS.md',
1203
1433
  'README.md',
1204
- 'docs/INDEX.md',
1205
1434
  'docs/AI_CONTEXT.md',
1206
1435
  'docs/AI_ONBOARDING_PROMPT.md',
1207
- 'docs/CONTEXTO.md',
1436
+ 'docs/COMMANDS.md',
1208
1437
  'docs/WORKFLOW.md',
1209
- 'docs/SUPPORT_MATRIX.md',
1210
- 'docs/TROUBLESHOOTING.md',
1211
- 'docs/TESTING_GUIDE_FOR_AI.md',
1212
- 'docs/ai/PRINCIPLES.md',
1213
- 'docs/ai/RULES.yaml',
1214
- 'docs/ai/LESSONS.md',
1215
- `specs/${projectSlug}/SPEC.md`,
1216
- `specs/${projectSlug}/STATUS.md`,
1217
- `specs/${projectSlug}/EVIDENCE_REPORT.md`,
1218
1438
  'package.json',
1219
- '.github/pull_request_template.md',
1220
- '.github/ISSUE_TEMPLATE/bug_report.md',
1221
- '.github/ISSUE_TEMPLATE/feature_request.md',
1222
- '.github/workflows/ci.yml',
1439
+ '.quiver/state.json',
1440
+ '.quiver/config.json',
1441
+ '.quiver/.gitignore',
1442
+ ...specRequiredFiles,
1223
1443
  ];
1224
-
1225
- const requiredExecutables = [
1226
- 'tools/scripts/start-slice.sh',
1227
- 'tools/scripts/check-slice-readiness.sh',
1228
- 'tools/scripts/check-pr-readiness.sh',
1229
- 'tools/scripts/cleanup-slice.sh',
1230
- 'tools/scripts/check-scope.sh',
1231
- ];
1232
-
1444
+ const requiredFiles = doctorReport.layout === 'legacy'
1445
+ ? ['package.json', ...specRequiredFiles]
1446
+ : newLayoutRequiredFiles;
1447
+ const legacyScriptsDir = path.join(projectRoot, 'tools', 'scripts');
1448
+ const requiredExecutables = fs.existsSync(legacyScriptsDir)
1449
+ ? [
1450
+ 'tools/scripts/start-slice.sh',
1451
+ 'tools/scripts/check-slice-readiness.sh',
1452
+ 'tools/scripts/check-pr-readiness.sh',
1453
+ 'tools/scripts/cleanup-slice.sh',
1454
+ 'tools/scripts/check-scope.sh',
1455
+ ]
1456
+ : [];
1233
1457
  const missingFiles = assertFilesExist(projectRoot, requiredFiles);
1234
1458
  const nonExecutableScripts = assertExecutablesExist(projectRoot, requiredExecutables);
1235
- const pkg = loadPackageJson(projectRoot);
1459
+ const pkg = fs.existsSync(path.join(projectRoot, 'package.json')) ? loadPackageJson(projectRoot) : {};
1236
1460
  const workflowScriptGroups = [
1237
1461
  { label: 'migrate', node: 'quiver:migrate', legacy: 'migrate' },
1238
1462
  { label: 'start-slice', node: 'quiver:start-slice', legacy: 'start:slice' },
@@ -1250,8 +1474,15 @@ function runDoctor(targetDir) {
1250
1474
  .map((group) => group.label);
1251
1475
  const missingNodeNativeScripts = ['quiver:migrate', 'quiver:analyze', 'quiver:doctor']
1252
1476
  .filter((name) => typeof pkg.scripts?.[name] !== 'string');
1253
- const hasScanArtifacts = fs.existsSync(path.join(projectRoot, 'docs', 'PROJECT_SCAN.json'))
1254
- && fs.existsSync(path.join(projectRoot, 'docs', 'PROJECT_MAP.md'));
1477
+ const missingAiScripts = [
1478
+ 'quiver:ai:onboard',
1479
+ 'quiver:ai:plan',
1480
+ 'quiver:ai:execute-slice',
1481
+ 'quiver:ai:pr',
1482
+ 'quiver:ai:doctor',
1483
+ ].filter((name) => typeof pkg.scripts?.[name] !== 'string');
1484
+ const hasScanArtifacts = hasProjectScanArtifact(projectRoot)
1485
+ && fs.existsSync(path.join(projectRoot, PROJECT_MAP_RELATIVE_PATH));
1255
1486
  const quiverState = readState(projectRoot);
1256
1487
  const hasQuiverState = Boolean(quiverState);
1257
1488
  const stateWarnings = hasQuiverState ? [] : ['missing Quiver state metadata: .quiver/state.json'];
@@ -1260,21 +1491,35 @@ function runDoctor(targetDir) {
1260
1491
  ...nonExecutableScripts.map((file) => `missing executable bit: ${file}`),
1261
1492
  ...missingScripts.map((name) => `missing package.json script: ${name}`),
1262
1493
  ];
1263
- const softWarnings = collectDoctorWarnings(projectRoot);
1494
+ const softWarnings = doctorReport.warnings;
1264
1495
 
1265
1496
  if (migrationProblems.length > 0) {
1266
1497
  throw new Error(formatError(`doctor failed:\n- ${migrationProblems.join('\n- ')}\n- Run migration first: npx create-quiver migrate`));
1267
1498
  }
1268
1499
 
1269
1500
  console.log(`Quiver doctor passed for ${projectRoot}`);
1270
- console.log(`Generated project slug: ${projectSlug}`);
1501
+ console.log(`Layout: ${doctorReport.layout}`);
1502
+ if (specSlugs.length > 0) {
1503
+ console.log(`Specs: ${specSlugs.join(', ')}`);
1504
+ } else {
1505
+ console.log('Specs: none yet');
1506
+ }
1507
+ if (doctorReport.legacySignals.length > 0) {
1508
+ console.log(`Legacy signals: ${doctorReport.legacySignals.join(', ')}`);
1509
+ }
1271
1510
  console.log('Next steps:');
1511
+ for (const recommendation of doctorReport.recommendations) {
1512
+ console.log(`- ${recommendation}`);
1513
+ }
1272
1514
  for (const warning of stateWarnings) {
1273
1515
  console.log(`- Warning: ${warning}`);
1274
1516
  }
1275
1517
  for (const scriptName of missingNodeNativeScripts) {
1276
1518
  console.log(`- Warning: missing Node-native script: ${scriptName}`);
1277
1519
  }
1520
+ for (const scriptName of missingAiScripts) {
1521
+ console.log(`- Warning: missing AI orchestration script: ${scriptName}`);
1522
+ }
1278
1523
  if (legacyOnlyScripts.length > 0) {
1279
1524
  console.log(`- Warning: legacy Bash workflow scripts detected for ${legacyOnlyScripts.join(', ')}. Run npx create-quiver migrate to add quiver:* npm scripts.`);
1280
1525
  }
@@ -1289,20 +1534,23 @@ function runDoctor(targetDir) {
1289
1534
  console.log('- Ask your AI agent: Read AGENTS.md, then docs/AI_ONBOARDING_PROMPT.md and execute it.');
1290
1535
  }
1291
1536
  console.log('- Check the next ready slice: npx create-quiver next');
1292
- console.log(`- Start a slice: npx create-quiver start-slice specs/${projectSlug}/slices/slice-template/slice.json`);
1293
- console.log(`- Validate a slice: npx create-quiver check-slice specs/${projectSlug}/slices/slice-template/slice.json`);
1294
- console.log(`- Validate the PR gate: npx create-quiver check-pr specs/${projectSlug}/slices/slice-template/slice.json`);
1537
+ if (specSlugs.length > 0) {
1538
+ const projectSlug = specSlugs[0];
1539
+ console.log(`- Start a slice: npx create-quiver start-slice specs/${projectSlug}/slices/<slice-id>/slice.json`);
1540
+ console.log(`- Validate a slice: npx create-quiver check-slice specs/${projectSlug}/slices/<slice-id>/slice.json`);
1541
+ console.log(`- Validate the PR gate: npx create-quiver check-pr specs/${projectSlug}/slices/<slice-id>/slice.json`);
1542
+ } else {
1543
+ console.log('- Create real specs and slices only after acceptance criteria and the technical plan are approved.');
1544
+ }
1295
1545
  }
1296
1546
 
1297
1547
  function printInitNextSteps(targetDir, projectName) {
1298
- const projectSlug = toProjectSlug(projectName);
1299
-
1300
1548
  console.log('');
1301
1549
  console.log('Next steps:');
1302
- console.log(`- Review AGENTS.md, then ${path.join(targetDir, 'docs', 'INDEX.md')}`);
1550
+ console.log(`- Review AGENTS.md, then ${path.join(targetDir, 'docs', 'AI_ONBOARDING_PROMPT.md')}`);
1303
1551
  console.log(`- Review ${path.join(targetDir, 'docs', 'WORKFLOW.md')}`);
1304
- console.log(`- Create your first slice from ${path.join(targetDir, 'specs', projectSlug, 'slices', 'slice-template', 'slice.json')}`);
1305
- console.log(`- Launch slice work with npx create-quiver start-slice specs/${projectSlug}/slices/slice-template/slice.json`);
1552
+ console.log('- Analyze the project with npx create-quiver analyze');
1553
+ console.log('- Create real specs and slices after acceptance criteria and the technical plan are approved.');
1306
1554
  }
1307
1555
 
1308
1556
  async function run(argv) {
@@ -1328,6 +1576,72 @@ async function run(argv) {
1328
1576
  return;
1329
1577
  }
1330
1578
 
1579
+ if (args.mode === 'ai') {
1580
+ if (!args.aiCommand) {
1581
+ throw new Error(formatError('missing ai subcommand. Use: npx create-quiver ai onboard | plan | execute-slice | doctor | pr'));
1582
+ }
1583
+
1584
+ if (args.aiCommand === 'onboard') {
1585
+ await runOnboard(process.cwd(), {
1586
+ context: args.aiContext || undefined,
1587
+ dryRun: args.dryRun,
1588
+ input: args.aiInput || undefined,
1589
+ provider: args.aiProvider,
1590
+ role: args.aiRole,
1591
+ timeout: args.aiTimeout,
1592
+ });
1593
+ return;
1594
+ }
1595
+
1596
+ if (args.aiCommand === 'plan') {
1597
+ await runAiPlan(process.cwd(), {
1598
+ context: args.aiContext || undefined,
1599
+ dryRun: args.dryRun,
1600
+ input: args.aiInput || undefined,
1601
+ phase: args.aiPhase,
1602
+ provider: args.aiProvider,
1603
+ role: args.aiRole,
1604
+ specSlug: args.specSlug || undefined,
1605
+ timeout: args.aiTimeout,
1606
+ });
1607
+ return;
1608
+ }
1609
+
1610
+ if (args.aiCommand === 'execute-slice') {
1611
+ await runAiExecuteSlice(process.cwd(), {
1612
+ context: args.aiContext || undefined,
1613
+ dryRun: args.dryRun,
1614
+ provider: args.aiProvider,
1615
+ role: args.aiRole,
1616
+ slice: args.aiSlice || undefined,
1617
+ timeout: args.aiTimeout,
1618
+ });
1619
+ return;
1620
+ }
1621
+
1622
+ if (args.aiCommand === 'doctor') {
1623
+ await runAiDoctor(process.cwd(), {
1624
+ dryRun: args.dryRun,
1625
+ remote: args.aiRemote || undefined,
1626
+ sshHostAlias: args.aiSshHostAlias || undefined,
1627
+ identityFile: args.aiIdentityFile || undefined,
1628
+ });
1629
+ return;
1630
+ }
1631
+
1632
+ if (args.aiCommand === 'pr') {
1633
+ await runAiPr(process.cwd(), {
1634
+ dryRun: args.dryRun,
1635
+ remote: args.aiRemote || undefined,
1636
+ sshHostAlias: args.aiSshHostAlias || undefined,
1637
+ identityFile: args.aiIdentityFile || undefined,
1638
+ });
1639
+ return;
1640
+ }
1641
+
1642
+ throw new Error(formatError(`unsupported ai subcommand: ${args.aiCommand}. Supported tasks: onboard, plan, execute-slice, doctor, pr`));
1643
+ }
1644
+
1331
1645
  if (args.mode === 'graph') {
1332
1646
  runGraph(process.cwd(), {
1333
1647
  format: args.format,
@@ -1350,7 +1664,7 @@ async function run(argv) {
1350
1664
  }
1351
1665
 
1352
1666
  if (args.mode === 'migrate') {
1353
- runMigrate(args.targetDir);
1667
+ runMigrate(args.targetDir, { skipInstall: args.skipInstall });
1354
1668
  return;
1355
1669
  }
1356
1670
 
@@ -1360,12 +1674,12 @@ async function run(argv) {
1360
1674
  }
1361
1675
 
1362
1676
  if (args.mode === 'start-slice') {
1363
- startSlice(path.resolve(process.cwd(), args.targetDir), { allowDraft: args.allowDraft });
1677
+ startSlice(args.targetDir, { allowDraft: args.allowDraft });
1364
1678
  return;
1365
1679
  }
1366
1680
 
1367
1681
  if (args.mode === 'check-slice') {
1368
- checkSliceReadiness(path.resolve(process.cwd(), args.targetDir), {
1682
+ checkSliceReadiness(args.targetDir, {
1369
1683
  gate: args.gate,
1370
1684
  strictOverlap: args.strictOverlap,
1371
1685
  });
@@ -1373,7 +1687,7 @@ async function run(argv) {
1373
1687
  }
1374
1688
 
1375
1689
  if (args.mode === 'check-pr') {
1376
- checkPrReadiness(path.resolve(process.cwd(), args.targetDir));
1690
+ checkPrReadiness(args.targetDir);
1377
1691
  return;
1378
1692
  }
1379
1693
 
@@ -1397,7 +1711,7 @@ async function run(argv) {
1397
1711
  }
1398
1712
 
1399
1713
  if (args.mode === 'cleanup-slice') {
1400
- cleanupSlice(path.resolve(process.cwd(), args.targetDir), {
1714
+ cleanupSlice(args.targetDir, {
1401
1715
  closeBaseline: args.closeBaseline,
1402
1716
  discard: args.discard,
1403
1717
  dryRun: args.dryRun,
@@ -1407,7 +1721,7 @@ async function run(argv) {
1407
1721
  }
1408
1722
 
1409
1723
  if (args.mode === 'check-scope') {
1410
- checkScope(path.resolve(process.cwd(), args.targetDir), { strict: args.strict });
1724
+ checkScope(args.targetDir, { strict: args.strict });
1411
1725
  return;
1412
1726
  }
1413
1727
 
@@ -1420,14 +1734,37 @@ async function run(argv) {
1420
1734
  const packageRoot = path.resolve(__dirname, '../..');
1421
1735
  const targetDir = resolveTargetRoot(process.cwd(), args.targetDir);
1422
1736
  const projectName = args.projectName || path.basename(targetDir) || 'Quiver Project';
1737
+ const initLayout = buildInitLayout(targetDir, {
1738
+ compatibilityAlias: !args.explicitInit,
1739
+ dryRun: args.dryRun,
1740
+ full: args.initFull,
1741
+ includeTemplates: args.initIncludeTemplates,
1742
+ legacyScripts: args.initLegacyScripts,
1743
+ minimal: args.initMinimal,
1744
+ projectName,
1745
+ skipInstall: args.skipInstall,
1746
+ });
1747
+
1748
+ if (args.dryRun) {
1749
+ console.log(formatInitLayoutPlan(initLayout));
1750
+ return;
1751
+ }
1752
+
1423
1753
  const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'quiver-create-'));
1424
1754
 
1425
1755
  try {
1426
1756
  ensureDir(targetDir);
1427
1757
 
1428
1758
  const templateRoot = packTemplate(packageRoot, tempRoot);
1429
- copyTemplate(templateRoot, targetDir);
1430
- runInitDocs(targetDir, projectName);
1759
+ if (initLayout.profile === 'full') {
1760
+ exportTemplatesToLegacyRoot(templateRoot, targetDir);
1761
+ }
1762
+ runInitDocs(targetDir, projectName, {
1763
+ includeTemplates: args.initIncludeTemplates,
1764
+ legacyScripts: args.initLegacyScripts,
1765
+ profile: initLayout.profile,
1766
+ templateRoot,
1767
+ });
1431
1768
 
1432
1769
  if (!args.skipInstall) {
1433
1770
  const installResult = installSelfAsDevDep(targetDir, CLI_VERSION);