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
@@ -1,7 +1,31 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
+ const { readAllSlices } = require('./slice-graph');
4
+ const { hasGeneratedProjectSpec, hasInitializedStateMetadata, readState } = require('./state');
3
5
  const { worktreeList } = require('./git');
4
6
 
7
+ const NEW_LAYOUT_REQUIRED_PATHS = [
8
+ 'README.md',
9
+ 'AGENTS.md',
10
+ 'package.json',
11
+ 'docs/AI_CONTEXT.md',
12
+ 'docs/AI_ONBOARDING_PROMPT.md',
13
+ 'docs/COMMANDS.md',
14
+ 'docs/WORKFLOW.md',
15
+ '.quiver/state.json',
16
+ '.quiver/config.json',
17
+ '.quiver/.gitignore',
18
+ ];
19
+
20
+ const LEGACY_LAYOUT_PROBES = [
21
+ 'docs-template/',
22
+ 'tools/scripts/start-slice.sh',
23
+ 'tools/scripts/check-slice-readiness.sh',
24
+ 'tools/scripts/check-pr-readiness.sh',
25
+ '.github/pull_request_template.md',
26
+ 'docs/PROJECT_SCAN.json',
27
+ ];
28
+
5
29
  function readTextIfExists(filePath) {
6
30
  if (!fs.existsSync(filePath)) {
7
31
  return null;
@@ -30,6 +54,18 @@ function normalizeRelativePath(root, absolutePath) {
30
54
  return path.relative(root, absolutePath).split(path.sep).join('/');
31
55
  }
32
56
 
57
+ function hasPath(projectRoot, relativePath) {
58
+ return fs.existsSync(path.join(projectRoot, relativePath));
59
+ }
60
+
61
+ function collectPresentPaths(projectRoot, relativePaths) {
62
+ return relativePaths.filter((relativePath) => hasPath(projectRoot, relativePath));
63
+ }
64
+
65
+ function collectMissingPaths(projectRoot, relativePaths) {
66
+ return relativePaths.filter((relativePath) => !hasPath(projectRoot, relativePath));
67
+ }
68
+
33
69
  function collectAiMarkdownFiles(projectRoot) {
34
70
  const aiDir = path.join(projectRoot, 'docs', 'ai');
35
71
  if (!fs.existsSync(aiDir)) {
@@ -174,6 +210,82 @@ function countStackInfoLeaks(projectRoot) {
174
210
  return leaks;
175
211
  }
176
212
 
213
+ function collectLayoutReport(projectRoot) {
214
+ const hasStateMetadata = hasInitializedStateMetadata(readState(projectRoot));
215
+ const realSlices = readAllSlices(projectRoot);
216
+ const specSlugs = Array.from(new Set(realSlices.map((slice) => slice.specSlug))).sort((left, right) => left.localeCompare(right));
217
+ const newLayoutFiles = collectPresentPaths(projectRoot, NEW_LAYOUT_REQUIRED_PATHS);
218
+ const missingNewLayoutFiles = collectMissingPaths(projectRoot, NEW_LAYOUT_REQUIRED_PATHS);
219
+ const legacySignals = collectPresentPaths(projectRoot, LEGACY_LAYOUT_PROBES);
220
+ const hasLegacyProjectSpec = hasGeneratedProjectSpec(projectRoot);
221
+
222
+ if (hasLegacyProjectSpec) {
223
+ legacySignals.push('specs/<project-slug>/SPEC.md');
224
+ }
225
+
226
+ const hasNewLayout = missingNewLayoutFiles.length === 0;
227
+ const hasLegacyLayout = legacySignals.length > 0;
228
+
229
+ let layout = 'incomplete';
230
+ if (hasNewLayout && hasLegacyLayout) {
231
+ layout = 'hybrid';
232
+ } else if (hasNewLayout) {
233
+ layout = 'new';
234
+ } else if (hasLegacyLayout) {
235
+ layout = 'legacy';
236
+ }
237
+
238
+ const recommendations = [];
239
+
240
+ if (layout === 'new') {
241
+ if (specSlugs.length === 0) {
242
+ recommendations.push('No specs yet. That is valid after the AI-first init flow.');
243
+ } else {
244
+ recommendations.push(`Specs found: ${specSlugs.join(', ')}.`);
245
+ }
246
+
247
+ if (!hasPath(projectRoot, 'docs/PROJECT_MAP.md')) {
248
+ recommendations.push('Run `npx create-quiver analyze` to generate docs/PROJECT_MAP.md when you want the visible project map.');
249
+ }
250
+ } else if (layout === 'legacy') {
251
+ recommendations.push('Legacy layout detected. Run `npx create-quiver migrate` to add the modern .quiver/ contract and AI-first docs.');
252
+ } else if (layout === 'hybrid') {
253
+ recommendations.push('Hybrid layout detected. Keep the new .quiver/ contract as the source of truth and plan cleanup of legacy roots.');
254
+ recommendations.push('Review any remaining docs-template/, tools/scripts/, or docs/PROJECT_SCAN.json paths and migrate them only if they are still needed.');
255
+ } else {
256
+ recommendations.push('Incomplete layout detected. Restore the missing AI-first contract files before relying on this project for onboarding.');
257
+ if (missingNewLayoutFiles.length > 0) {
258
+ recommendations.push(`Missing files: ${missingNewLayoutFiles.join(', ')}.`);
259
+ }
260
+ if (!hasStateMetadata && !hasLegacyLayout) {
261
+ recommendations.push('Run `npx create-quiver --name "Project Name"` or `npx create-quiver init` to create the Quiver contract first.');
262
+ }
263
+ }
264
+
265
+ return {
266
+ hasLegacyLayout,
267
+ hasNewLayout,
268
+ hasStateMetadata,
269
+ layout,
270
+ legacySignals,
271
+ missingNewLayoutFiles,
272
+ newLayoutFiles,
273
+ recommendations,
274
+ realSlices,
275
+ specSlugs,
276
+ };
277
+ }
278
+
279
+ function collectDoctorReport(projectRoot) {
280
+ const layout = collectLayoutReport(projectRoot);
281
+ const warnings = collectDoctorWarnings(projectRoot);
282
+
283
+ return {
284
+ ...layout,
285
+ warnings,
286
+ };
287
+ }
288
+
177
289
  function collectDoctorWarnings(projectRoot) {
178
290
  const warnings = [];
179
291
 
@@ -208,5 +320,7 @@ function collectDoctorWarnings(projectRoot) {
208
320
  }
209
321
 
210
322
  module.exports = {
323
+ collectDoctorReport,
211
324
  collectDoctorWarnings,
325
+ collectLayoutReport,
212
326
  };
@@ -101,6 +101,23 @@ function statusPorcelain(repoRoot) {
101
101
  return tryGit(['status', '--porcelain'], repoRoot);
102
102
  }
103
103
 
104
+ function remoteList(repoRoot) {
105
+ const output = tryGit(['remote'], repoRoot);
106
+ return output ? output.split('\n').map((line) => line.trim()).filter(Boolean) : [];
107
+ }
108
+
109
+ function hasRemote(repoRoot, remoteName = 'origin') {
110
+ return remoteList(repoRoot).includes(remoteName);
111
+ }
112
+
113
+ function isCleanWorktree(repoRoot) {
114
+ return statusPorcelain(repoRoot) === '';
115
+ }
116
+
117
+ function isDetachedHead(repoRoot) {
118
+ return currentBranch(repoRoot) === '';
119
+ }
120
+
104
121
  function revListCount(repoRoot, range) {
105
122
  const output = tryGit(['rev-list', '--count', range], repoRoot);
106
123
  return Number(output || '0');
@@ -143,7 +160,11 @@ module.exports = {
143
160
  hasRemoteBranch,
144
161
  lsRemoteHeads,
145
162
  mergeBaseIsAncestor,
163
+ hasRemote,
164
+ isCleanWorktree,
165
+ isDetachedHead,
146
166
  revListCount,
167
+ remoteList,
147
168
  runGit,
148
169
  statusPorcelain,
149
170
  tryGit,
@@ -1,6 +1,12 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
3
  const { execSync } = require('child_process');
4
+ const {
5
+ buildQuiverConfig,
6
+ buildQuiverInternalGitignore,
7
+ quiverInternalPaths,
8
+ resolveInitPackageScripts,
9
+ } = require('./init-layout');
4
10
  const { writeState } = require('./state');
5
11
 
6
12
  function ensureDir(dirPath) {
@@ -199,7 +205,7 @@ function writeFrontMatter(filePath, fields) {
199
205
  return nextContent;
200
206
  }
201
207
 
202
- function mergePackageJson(projectRoot, templateRoot, skipIfExists) {
208
+ function mergePackageJson(projectRoot, templateRoot, options = {}) {
203
209
  const packageTemplate = path.join(templateRoot, 'package.template.json');
204
210
  const packageJsonPath = path.join(projectRoot, 'package.json');
205
211
 
@@ -207,8 +213,13 @@ function mergePackageJson(projectRoot, templateRoot, skipIfExists) {
207
213
  return 'missing';
208
214
  }
209
215
 
216
+ const profile = options.profile || 'default';
217
+ const scripts = resolveInitPackageScripts(profile, { legacyScripts: options.legacyScripts === true });
218
+
210
219
  if (!fs.existsSync(packageJsonPath)) {
211
- fs.copyFileSync(packageTemplate, packageJsonPath);
220
+ const template = JSON.parse(fs.readFileSync(packageTemplate, 'utf8'));
221
+ template.scripts = scripts;
222
+ fs.writeFileSync(packageJsonPath, `${JSON.stringify(template, null, 2)}\n`);
212
223
  return 'created';
213
224
  }
214
225
 
@@ -217,14 +228,125 @@ function mergePackageJson(projectRoot, templateRoot, skipIfExists) {
217
228
 
218
229
  existing.scripts = {
219
230
  ...(existing.scripts || {}),
220
- ...(template.scripts || {}),
231
+ ...scripts,
221
232
  };
222
233
 
223
234
  fs.writeFileSync(packageJsonPath, `${JSON.stringify(existing, null, 2)}\n`);
224
- return skipIfExists ? 'merged' : 'updated';
235
+ return options.migrateMode ? 'merged' : 'updated';
225
236
  }
226
237
 
227
- function buildReadme(projectName, projectSlug) {
238
+ function buildReadme(projectName, projectSlug, profile = 'default') {
239
+ if (profile === 'minimal') {
240
+ return `# ${projectName}
241
+
242
+ [Descripción breve del proyecto]
243
+
244
+ ## Quick Start
245
+
246
+ Run Quiver from this project root. Do not install it globally.
247
+
248
+ \`\`\`bash
249
+ npm install
250
+ npx create-quiver analyze
251
+ npx create-quiver plan
252
+ npx create-quiver graph
253
+ npx create-quiver doctor
254
+ npx create-quiver next
255
+ \`\`\`
256
+
257
+ ## AI Workflow
258
+
259
+ Use \`AGENTS.md\` first, then \`docs/AI_CONTEXT.md\` and \`docs/AI_ONBOARDING_PROMPT.md\` for the working contract.
260
+
261
+ \`\`\`bash
262
+ npm run quiver:ai:onboard -- --dry-run
263
+ npm run quiver:ai:plan -- --phase acceptance --input requirements.md --dry-run
264
+ npm run quiver:ai:plan -- --phase technical-plan --input acceptance-approved.md --dry-run
265
+ npm run quiver:ai:plan -- --phase spec --input technical-plan-approved.md --dry-run
266
+ \`\`\`
267
+
268
+ When a real spec exists, execute one approved slice at a time:
269
+
270
+ \`\`\`bash
271
+ npm run quiver:ai:execute-slice -- --slice specs/<spec-slug>/slices/<slice-id>/slice.json --dry-run
272
+ \`\`\`
273
+
274
+ ## Documentation
275
+
276
+ - [AI Context](./docs/AI_CONTEXT.md)
277
+ - [AI Onboarding Prompt](./docs/AI_ONBOARDING_PROMPT.md)
278
+ - [Commands](./docs/COMMANDS.md)
279
+ - [Workflow](./docs/WORKFLOW.md)
280
+ `;
281
+ }
282
+
283
+ if (profile !== 'full') {
284
+ return `# ${projectName}
285
+
286
+ [Descripción breve del proyecto]
287
+
288
+ ## Quick Start
289
+
290
+ Run Quiver from this project root. Do not install it globally.
291
+
292
+ \`\`\`bash
293
+ npm install
294
+ npx create-quiver analyze
295
+ npx create-quiver plan
296
+ npx create-quiver graph
297
+ npx create-quiver doctor
298
+ npx create-quiver next
299
+ \`\`\`
300
+
301
+ After \`analyze\`, use \`docs/PROJECT_MAP.md\` for the detected stack, package manager, and command surface.
302
+
303
+ ## AI-First Workflow
304
+
305
+ Quiver keeps the visible contract small: start with \`README.md\`, \`AGENTS.md\`, and \`docs/\`. Specs and slices should be created only after a real requirement and an approved technical plan.
306
+
307
+ Use dry-runs before spending model tokens:
308
+
309
+ \`\`\`bash
310
+ npm run quiver:ai:onboard -- --dry-run
311
+ npm run quiver:ai:plan -- --phase acceptance --input requirements.md --dry-run
312
+ npm run quiver:ai:plan -- --phase technical-plan --input acceptance-approved.md --dry-run
313
+ npm run quiver:ai:plan -- --phase spec --input technical-plan-approved.md --dry-run
314
+ \`\`\`
315
+
316
+ When a real spec exists, execute one approved slice at a time:
317
+
318
+ \`\`\`bash
319
+ npm run quiver:ai:execute-slice -- --slice specs/<spec-slug>/slices/<slice-id>/slice.json --dry-run
320
+ \`\`\`
321
+
322
+ ## Project NPM Scripts
323
+
324
+ The generated project includes \`quiver:*\` npm scripts that call the Node CLI:
325
+
326
+ \`\`\`bash
327
+ npm run quiver:analyze
328
+ npm run quiver:plan
329
+ npm run quiver:graph
330
+ npm run quiver:next
331
+ npm run quiver:doctor
332
+ npm run quiver:ai:onboard -- --dry-run
333
+ npm run quiver:ai:plan -- --phase acceptance --input requirements.md --dry-run
334
+ npm run quiver:ai:execute-slice -- --slice specs/<spec-slug>/slices/<slice-id>/slice.json --dry-run
335
+ \`\`\`
336
+
337
+ ## Documentation
338
+
339
+ - [Agents](./AGENTS.md)
340
+ - [AI Context](./docs/AI_CONTEXT.md)
341
+ - [AI Onboarding Prompt](./docs/AI_ONBOARDING_PROMPT.md)
342
+ - [Commands](./docs/COMMANDS.md)
343
+ - [Workflow](./docs/WORKFLOW.md)
344
+ - [GitFlow PR Guide](./docs/GITFLOW_PR_GUIDE.md)
345
+ - [Support Matrix](./docs/SUPPORT_MATRIX.md)
346
+ - [Troubleshooting](./docs/TROUBLESHOOTING.md)
347
+ `;
348
+ }
349
+
228
350
  return `# ${projectName}
229
351
 
230
352
  [Descripción breve del proyecto]
@@ -259,6 +381,23 @@ If you need to target another directory from outside the project, pass \`--dir\`
259
381
 
260
382
  After you run \`analyze\`, open \`docs/PROJECT_MAP.md\` for the detected stack, package manager, and command surface.
261
383
 
384
+ ## AI-First Workflow
385
+
386
+ Quiver is designed for an AI-first workflow: a planner agent reads the project context and prepares acceptance criteria, technical plans, specs, slices, and PR notes; executor agents then work one approved slice at a time with minimal context.
387
+
388
+ Start with dry-runs so you can inspect the provider, role, context pack, and invocation before spending model tokens:
389
+
390
+ \`\`\`bash
391
+ npm run quiver:ai:onboard -- --dry-run
392
+ npm run quiver:ai:plan -- --phase acceptance --input requirements.md --dry-run
393
+ npm run quiver:ai:plan -- --phase technical-plan --input acceptance-approved.md --dry-run
394
+ npm run quiver:ai:plan -- --phase spec --input technical-plan-approved.md --dry-run
395
+ npm run quiver:ai:execute-slice -- --slice specs/${projectSlug}/slices/slice-01/slice.json --dry-run
396
+ npm run quiver:ai:pr -- --dry-run --ssh-host-alias github-work --identity-file ~/.ssh/github-work
397
+ \`\`\`
398
+
399
+ Remove \`--dry-run\` only after the phase output is approved and the local provider CLI is ready.
400
+
262
401
  ## Project NPM Scripts
263
402
 
264
403
  The generated project includes \`quiver:*\` npm scripts that call the Node CLI and are the preferred repeatable workflow:
@@ -269,6 +408,11 @@ npm run quiver:plan
269
408
  npm run quiver:graph
270
409
  npm run quiver:next
271
410
  npm run quiver:doctor
411
+ npm run quiver:ai:onboard -- --dry-run
412
+ npm run quiver:ai:plan -- --phase acceptance --input requirements.md --dry-run
413
+ npm run quiver:ai:execute-slice -- --slice specs/${projectSlug}/slices/slice-01/slice.json --dry-run
414
+ npm run quiver:ai:doctor -- --dry-run --ssh-host-alias github-work --identity-file ~/.ssh/github-work
415
+ npm run quiver:ai:pr -- --dry-run --ssh-host-alias github-work --identity-file ~/.ssh/github-work
272
416
  npm run quiver:migrate
273
417
  npm run quiver:start-slice -- specs/${projectSlug}/slices/slice-01/slice.json
274
418
  npm run quiver:check-slice -- specs/${projectSlug}/slices/slice-01/slice.json
@@ -281,6 +425,7 @@ npm run quiver:refresh-active-slices
281
425
 
282
426
  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
427
  The \`quiver:next\` script points to the next ready slice and can auto-start it behind a confirmation prompt.
428
+ The \`quiver:ai:*\` scripts standardize planner/executor AI flows. Use dry-run first: onboarding and planning dry-runs do not require provider auth, while \`quiver:ai:pr -- --dry-run\` validates \`gh\`, GitFlow docs, branch/worktree state, and SSH inputs without creating a PR.
284
429
  Use \`npx create-quiver next --all-ready\` when you want the full ready level instead of a single suggestion.
285
430
  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
431
  \`npm run quiver:migrate\` is only for projects that were already initialized by Quiver.
@@ -311,7 +456,7 @@ Use \`{{GRAPH_COMMAND}} --format mermaid\` for GitHub-friendly graph embeds or \
311
456
  If the project never ran Quiver initialization before, do not use \`migrate\` as bootstrap. Run:
312
457
 
313
458
  \`\`\`bash
314
- npx create-quiver --name "Project Name"
459
+ npx create-quiver init --name "Project Name"
315
460
  \`\`\`
316
461
 
317
462
  If your team prefers a pinned local dependency, update the package first and then run the same flow:
@@ -335,9 +480,17 @@ Read \`AGENTS.md\` first, then open \`docs/AI_ONBOARDING_PROMPT.md\` after analy
335
480
  After analysis and doctor validation, open your AI agent in this project and run:
336
481
 
337
482
  \`\`\`text
338
- Read docs/AI_ONBOARDING_PROMPT.md and execute it.
339
- Do not modify product code unless I explicitly authorize it.
340
- Prepare the project context docs and report assumptions, risks, and files changed.
483
+ Lee \`docs/AI_ONBOARDING_PROMPT.md\` y ejecútalo como fuente principal de verdad para incorporarte a este repositorio.
484
+
485
+ Actúa como asistente de onboarding de IA. Prepara el contexto del proyecto para trabajar de forma segura con el workflow documentado, specs y slices.
486
+
487
+ Usa el rol planner para onboarding, criterios de aceptación, plan técnico y generación de specs/slices. Usa el rol executor solo cuando exista un slice aprobado y debas ejecutar su handoff con contexto mínimo.
488
+
489
+ No modifiques código de producto salvo autorización explícita. Puedes crear o actualizar documentación de contexto si el onboarding lo requiere.
490
+
491
+ Usa solo la documentación del repositorio como fuente de verdad. Si encuentras información faltante, ambigua o contradictoria, documenta el supuesto, el riesgo y continúa por el camino más seguro.
492
+
493
+ Responde en español y finaliza con un reporte breve de archivos leídos, archivos modificados, estado del código de producto, supuestos, riesgos y próximos pasos.
341
494
  \`\`\`
342
495
 
343
496
  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.
@@ -349,6 +502,8 @@ Record durable decisions in \`docs/DECISIONS.md\` so future AI agents do not re-
349
502
 
350
503
  ## First Slice Workflow
351
504
 
505
+ Use this section only for projects generated with the full compatibility layout. In the default AI-first layout, create real specs and slices with \`npx create-quiver ai plan --phase spec\` after acceptance criteria and the technical plan are approved.
506
+
352
507
  1. Review or refine specs/${projectSlug}/SPEC.md.
353
508
  2. Create the first slice from specs/${projectSlug}/slices/slice-template/slice.json.
354
509
  3. Review the plan with \`{{PLAN_COMMAND}}\` or \`npm run quiver:plan\`.
@@ -391,10 +546,15 @@ function initializeProjectDocs(options) {
391
546
  projectRoot,
392
547
  projectName,
393
548
  cliVersion,
549
+ includeTemplates = false,
550
+ legacyScripts = false,
394
551
  migrateMode = false,
552
+ profile = 'default',
553
+ templateRoot: providedTemplateRoot = '',
395
554
  } = options;
396
555
 
397
- const templateRoot = path.join(projectRoot, 'docs-template');
556
+ const templateRoot = providedTemplateRoot || path.join(projectRoot, 'docs-template');
557
+ const internalPaths = quiverInternalPaths(projectRoot);
398
558
  const replacements = {
399
559
  projectName,
400
560
  projectSlug: toProjectSlug(projectName),
@@ -407,17 +567,48 @@ function initializeProjectDocs(options) {
407
567
  const dirs = [
408
568
  'docs',
409
569
  'docs/ai',
410
- 'docs/tools',
411
- 'docs/archive',
412
- `specs/${replacements.projectSlug}/slices/slice-template`,
413
- 'tools/scripts',
570
+ '.quiver',
571
+ '.quiver/scans',
414
572
  ];
415
573
 
574
+ if (profile === 'full') {
575
+ dirs.push(
576
+ 'docs/archive',
577
+ 'docs/examples',
578
+ 'docs/tools',
579
+ `specs/${replacements.projectSlug}/slices/slice-template`,
580
+ 'tools/scripts',
581
+ );
582
+ } else if (legacyScripts) {
583
+ dirs.push('tools/scripts');
584
+ }
585
+
416
586
  for (const dir of dirs) {
417
587
  ensureDir(path.join(projectRoot, dir));
418
588
  }
419
589
 
420
590
  const operations = [];
591
+ if (!fs.existsSync(internalPaths.configPath)) {
592
+ fs.writeFileSync(internalPaths.configPath, `${JSON.stringify(buildQuiverConfig(), null, 2)}\n`);
593
+ operations.push({ source: 'Quiver config', destination: '.quiver/config.json', result: 'created' });
594
+ } else {
595
+ operations.push({ source: 'Quiver config', destination: '.quiver/config.json', result: 'skipped' });
596
+ }
597
+
598
+ fs.writeFileSync(internalPaths.gitignorePath, buildQuiverInternalGitignore());
599
+ operations.push({ source: 'Quiver internal gitignore', destination: '.quiver/.gitignore', result: 'updated' });
600
+
601
+ if (includeTemplates) {
602
+ fs.mkdirSync(internalPaths.templatesDir, { recursive: true });
603
+ fs.cpSync(templateRoot, internalPaths.templatesDir, {
604
+ recursive: true,
605
+ force: false,
606
+ errorOnExist: false,
607
+ preserveTimestamps: true,
608
+ });
609
+ operations.push({ source: 'packaged templates', destination: '.quiver/templates', result: 'merged' });
610
+ }
611
+
421
612
  const agentsSourcePath = path.join(templateRoot, 'AGENTS.md.template');
422
613
  if (fs.existsSync(agentsSourcePath)) {
423
614
  const agentsDestinationPath = path.join(projectRoot, 'AGENTS.md');
@@ -457,13 +648,45 @@ function initializeProjectDocs(options) {
457
648
  ['specs/[project-name]/slices/pr.md.template', `specs/${replacements.projectSlug}/slices/slice-template/pr.md.template`],
458
649
  ];
459
650
 
651
+ const minimalTemplateDestinations = new Set([
652
+ 'docs/AI_CONTEXT.md',
653
+ 'docs/AI_ONBOARDING_PROMPT.md',
654
+ 'docs/COMMANDS.md',
655
+ 'docs/WORKFLOW.md',
656
+ ]);
657
+ const defaultTemplateDestinations = new Set([
658
+ ...minimalTemplateDestinations,
659
+ 'docs/CONTEXTO.md',
660
+ 'docs/DECISIONS.md',
661
+ 'docs/GITFLOW_PR_GUIDE.md',
662
+ 'docs/INDEX.md',
663
+ 'docs/STATUS.md',
664
+ 'docs/SUPPORT_MATRIX.md',
665
+ 'docs/TESTING_GUIDE_FOR_AI.md',
666
+ 'docs/TROUBLESHOOTING.md',
667
+ 'docs/ai/LESSONS.md',
668
+ ]);
669
+
460
670
  for (const [source, destination, frontMatterFactory] of templateCopies) {
671
+ if (profile === 'minimal' && !minimalTemplateDestinations.has(destination)) {
672
+ continue;
673
+ }
674
+
675
+ if (profile === 'default' && !defaultTemplateDestinations.has(destination)) {
676
+ continue;
677
+ }
678
+
461
679
  const sourcePath = path.join(templateRoot, source);
462
680
  if (!fs.existsSync(sourcePath)) {
463
681
  continue;
464
682
  }
465
683
 
466
684
  const destinationPath = path.join(projectRoot, destination);
685
+ if (!migrateMode && fs.existsSync(destinationPath)) {
686
+ operations.push({ source, destination, result: 'skipped' });
687
+ continue;
688
+ }
689
+
467
690
  const result = copyRenderedFile(sourcePath, destinationPath, replacements, migrateMode, frontMatterFactory);
468
691
  operations.push({ source, destination, result });
469
692
  }
@@ -491,31 +714,58 @@ function initializeProjectDocs(options) {
491
714
  ['scripts/migrate-project.sh', 'tools/scripts/migrate-project.sh'],
492
715
  ];
493
716
 
717
+ const alwaysBinaryDestinations = new Set([
718
+ 'docs/ai/RULES.yaml',
719
+ ]);
720
+ const legacyScriptDestinations = new Set([
721
+ 'tools/scripts/start-slice.sh',
722
+ 'tools/scripts/refresh-active-slices.sh',
723
+ 'tools/scripts/check-slice-readiness.sh',
724
+ 'tools/scripts/check-pr-readiness.sh',
725
+ 'tools/scripts/cleanup-slice.sh',
726
+ 'tools/scripts/check-scope.sh',
727
+ 'tools/scripts/migrate-project.sh',
728
+ ]);
729
+
494
730
  for (const [source, destination] of binaryCopies) {
731
+ if (
732
+ profile !== 'full'
733
+ && !alwaysBinaryDestinations.has(destination)
734
+ && !(legacyScripts && legacyScriptDestinations.has(destination))
735
+ ) {
736
+ continue;
737
+ }
738
+
495
739
  const sourcePath = path.join(templateRoot, source);
496
740
  const destinationPath = path.join(projectRoot, destination);
497
741
  if (!fs.existsSync(sourcePath)) {
498
742
  continue;
499
743
  }
500
744
 
501
- const result = copyIfSourceExists(sourcePath, destinationPath, migrateMode);
745
+ const result = copyIfSourceExists(sourcePath, destinationPath, true);
502
746
  operations.push({ source, destination, result });
503
747
  }
504
748
 
505
749
  const aiPrinciplesSource = path.join(templateRoot, 'docs/ai/PRINCIPLES.md');
506
750
  if (fs.existsSync(aiPrinciplesSource)) {
507
751
  const aiPrinciplesDestination = path.join(projectRoot, 'docs/ai/PRINCIPLES.md');
508
- const result = copyRenderedFile(
509
- aiPrinciplesSource,
510
- aiPrinciplesDestination,
511
- replacements,
512
- migrateMode,
513
- frontMatterFor('AI operating principles', 'all AI work'),
514
- );
752
+ const result = !migrateMode && fs.existsSync(aiPrinciplesDestination)
753
+ ? 'skipped'
754
+ : copyRenderedFile(
755
+ aiPrinciplesSource,
756
+ aiPrinciplesDestination,
757
+ replacements,
758
+ migrateMode,
759
+ frontMatterFor('AI operating principles', 'all AI work'),
760
+ );
515
761
  operations.push({ source: 'docs/ai/PRINCIPLES.md', destination: 'docs/ai/PRINCIPLES.md', result });
516
762
  }
517
763
 
518
- const packageResult = mergePackageJson(projectRoot, templateRoot, migrateMode);
764
+ const packageResult = mergePackageJson(projectRoot, templateRoot, {
765
+ legacyScripts,
766
+ migrateMode,
767
+ profile,
768
+ });
519
769
  operations.push({ source: 'package.template.json', destination: 'package.json', result: packageResult });
520
770
 
521
771
  const mergedPackageJsonPath = path.join(projectRoot, 'package.json');
@@ -554,12 +804,21 @@ function initializeProjectDocs(options) {
554
804
  ];
555
805
 
556
806
  for (const [source, destination] of tierCopies) {
807
+ if (profile !== 'full') {
808
+ continue;
809
+ }
810
+
557
811
  const sourcePath = path.join(templateRoot, source);
558
812
  if (!fs.existsSync(sourcePath)) {
559
813
  continue;
560
814
  }
561
815
 
562
816
  const destinationPath = path.join(projectRoot, destination);
817
+ if (!migrateMode && fs.existsSync(destinationPath)) {
818
+ operations.push({ source, destination, result: 'skipped' });
819
+ continue;
820
+ }
821
+
563
822
  const result = copyRenderedFile(sourcePath, destinationPath, tierReplacements, migrateMode, ({
564
823
  body,
565
824
  }) => buildFrontMatterFields({
@@ -607,7 +866,9 @@ function initializeProjectDocs(options) {
607
866
  writeState(projectRoot, nextState);
608
867
 
609
868
  const searchPath = path.join(projectRoot, 'docs', 'SEARCH.md');
610
- if (!(migrateMode && fs.existsSync(searchPath))) {
869
+ if (profile !== 'full') {
870
+ operations.push({ source: 'docs/SEARCH.md', destination: 'docs/SEARCH.md', result: 'skipped-profile' });
871
+ } else if (!fs.existsSync(searchPath)) {
611
872
  const searchContent = `# Búsqueda por Tema
612
873
 
613
874
  **Última actualización:** ${replacements.currentDate}
@@ -656,7 +917,7 @@ function initializeProjectDocs(options) {
656
917
 
657
918
  const readmePath = path.join(projectRoot, 'README.md');
658
919
  if (!fs.existsSync(readmePath)) {
659
- fs.writeFileSync(readmePath, `${renderTemplate(buildReadme(projectName, replacements.projectSlug), replacements)}\n`);
920
+ fs.writeFileSync(readmePath, `${renderTemplate(buildReadme(projectName, replacements.projectSlug, profile), replacements)}\n`);
660
921
  operations.push({ source: 'README.md template', destination: 'README.md', result: 'created' });
661
922
  } else {
662
923
  operations.push({ source: 'README.md template', destination: 'README.md', result: 'skipped' });