create-quiver 0.9.1 → 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.
- package/README.md +289 -335
- package/README_FOR_AI.md +57 -44
- package/docs/AI_ONBOARDING_PROMPT.md.template +13 -3
- package/docs/COMMANDS.md.template +24 -0
- package/docs/GITFLOW_PR_GUIDE.md.template +11 -0
- package/docs/STANDARD.md.template +1 -1
- package/docs/SUPPORT_MATRIX.md.template +4 -0
- package/docs/TROUBLESHOOTING.md.template +29 -1
- package/docs/WORKFLOW.md.template +1 -1
- package/package.json +6 -1
- package/package.template.json +11 -6
- package/scripts/check-pr-readiness.sh +1 -1
- package/scripts/check-scope.sh +0 -1
- package/scripts/check-slice-readiness.sh +3 -4
- package/scripts/init-docs.sh +46 -6
- package/specs/quiver-v20-ai-cli-orchestration/EVIDENCE_REPORT.md +23 -0
- package/specs/quiver-v20-ai-cli-orchestration/EXECUTION_PLAN.md +57 -0
- package/specs/quiver-v20-ai-cli-orchestration/SPEC.md +202 -0
- package/specs/quiver-v20-ai-cli-orchestration/STATUS.md +35 -0
- package/specs/quiver-v20-ai-cli-orchestration/pr.md +100 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-00-spec-foundation/CLOSURE_BRIEF.md +30 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-00-spec-foundation/EXECUTION_BRIEF.md +61 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-00-spec-foundation/slice.json +54 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-01-ai-provider-runner/CLOSURE_BRIEF.md +39 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-01-ai-provider-runner/EXECUTION_BRIEF.md +63 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-01-ai-provider-runner/slice.json +55 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-02-context-packs-token-budget/CLOSURE_BRIEF.md +40 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-02-context-packs-token-budget/EXECUTION_BRIEF.md +60 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-02-context-packs-token-budget/slice.json +54 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-03-ai-phase-gated-planner/CLOSURE_BRIEF.md +43 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-03-ai-phase-gated-planner/EXECUTION_BRIEF.md +62 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-03-ai-phase-gated-planner/slice.json +62 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-04-spec-slice-handoff-pr-generation/CLOSURE_BRIEF.md +36 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-04-spec-slice-handoff-pr-generation/EXECUTION_BRIEF.md +63 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-04-spec-slice-handoff-pr-generation/slice.json +59 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-05-execution-plan-parallel-worktrees/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-05-execution-plan-parallel-worktrees/EXECUTION_BRIEF.md +61 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-05-execution-plan-parallel-worktrees/slice.json +59 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-06-ai-execute-slice-scope-enforcement/CLOSURE_BRIEF.md +36 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-06-ai-execute-slice-scope-enforcement/EXECUTION_BRIEF.md +64 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-06-ai-execute-slice-scope-enforcement/slice.json +65 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-07-github-pr-preflight/CLOSURE_BRIEF.md +36 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-07-github-pr-preflight/EXECUTION_BRIEF.md +66 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-07-github-pr-preflight/slice.json +63 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-08-docs-smokes-release-readiness/CLOSURE_BRIEF.md +35 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-08-docs-smokes-release-readiness/EXECUTION_BRIEF.md +64 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-08-docs-smokes-release-readiness/slice.json +77 -0
- package/specs/quiver-v21-ai-first-layout/EVIDENCE_REPORT.md +31 -0
- package/specs/quiver-v21-ai-first-layout/EXECUTION_PLAN.md +185 -0
- package/specs/quiver-v21-ai-first-layout/SPEC.md +212 -0
- package/specs/quiver-v21-ai-first-layout/STATUS.md +37 -0
- package/specs/quiver-v21-ai-first-layout/pr.md +110 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-00-spec-foundation/CLOSURE_BRIEF.md +30 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-00-spec-foundation/EXECUTION_BRIEF.md +63 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-00-spec-foundation/slice.json +45 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-01-init-profiles-dry-run/CLOSURE_BRIEF.md +31 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-01-init-profiles-dry-run/EXECUTION_BRIEF.md +59 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-01-init-profiles-dry-run/slice.json +57 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-02-internal-layout-template-resolver/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-02-internal-layout-template-resolver/EXECUTION_BRIEF.md +60 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-02-internal-layout-template-resolver/slice.json +58 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-03-generation-profiles-visible-contract/CLOSURE_BRIEF.md +34 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-03-generation-profiles-visible-contract/EXECUTION_BRIEF.md +61 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-03-generation-profiles-visible-contract/slice.json +64 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-04-analyze-scan-relocation/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-04-analyze-scan-relocation/EXECUTION_BRIEF.md +58 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-04-analyze-scan-relocation/slice.json +64 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-05-empty-specs-layout-doctor/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-05-empty-specs-layout-doctor/EXECUTION_BRIEF.md +60 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-05-empty-specs-layout-doctor/slice.json +65 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-06-legacy-migration-optional-assets/CLOSURE_BRIEF.md +31 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-06-legacy-migration-optional-assets/EXECUTION_BRIEF.md +62 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-06-legacy-migration-optional-assets/slice.json +66 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-07-docs-guidance-alignment/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-07-docs-guidance-alignment/EXECUTION_BRIEF.md +61 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-07-docs-guidance-alignment/slice.json +67 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-08-smokes-release-readiness/CLOSURE_BRIEF.md +35 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-08-smokes-release-readiness/EXECUTION_BRIEF.md +66 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-08-smokes-release-readiness/slice.json +62 -0
- package/src/create-quiver/commands/ai.js +442 -0
- package/src/create-quiver/index.js +418 -81
- package/src/create-quiver/lib/ai/context-packs.js +158 -0
- package/src/create-quiver/lib/ai/execution-plan.js +254 -0
- package/src/create-quiver/lib/ai/executor.js +323 -0
- package/src/create-quiver/lib/ai/github.js +329 -0
- package/src/create-quiver/lib/ai/phase-gates.js +72 -0
- package/src/create-quiver/lib/ai/preflight.js +58 -0
- package/src/create-quiver/lib/ai/prompt-transport.js +81 -0
- package/src/create-quiver/lib/ai/prompts.js +39 -0
- package/src/create-quiver/lib/ai/providers.js +314 -0
- package/src/create-quiver/lib/ai/safety.js +151 -0
- package/src/create-quiver/lib/ai/spec-generator.js +314 -0
- package/src/create-quiver/lib/ai/spec-templates.js +715 -0
- package/src/create-quiver/lib/doctor.js +114 -0
- package/src/create-quiver/lib/git.js +21 -0
- package/src/create-quiver/lib/init-docs.js +277 -22
- package/src/create-quiver/lib/init-layout.js +426 -0
- package/src/create-quiver/lib/lifecycle.js +2 -2
- package/src/create-quiver/lib/paths.js +63 -2
- package/src/create-quiver/lib/project-scan.js +66 -0
- package/src/create-quiver/lib/readiness.js +4 -2
- package/src/create-quiver/lib/scope.js +125 -0
- package/src/create-quiver/lib/slice-graph.js +6 -0
- package/src/create-quiver/lib/slice.js +51 -8
- package/src/create-quiver/lib/state.js +18 -1
- package/src/create-quiver/lib/template-resolver.js +74 -0
|
@@ -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,
|
|
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.
|
|
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
|
-
...
|
|
231
|
+
...scripts,
|
|
221
232
|
};
|
|
222
233
|
|
|
223
234
|
fs.writeFileSync(packageJsonPath, `${JSON.stringify(existing, null, 2)}\n`);
|
|
224
|
-
return
|
|
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:
|
|
@@ -339,6 +484,8 @@ Lee \`docs/AI_ONBOARDING_PROMPT.md\` y ejecútalo como fuente principal de verda
|
|
|
339
484
|
|
|
340
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.
|
|
341
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
|
+
|
|
342
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.
|
|
343
490
|
|
|
344
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.
|
|
@@ -355,6 +502,8 @@ Record durable decisions in \`docs/DECISIONS.md\` so future AI agents do not re-
|
|
|
355
502
|
|
|
356
503
|
## First Slice Workflow
|
|
357
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
|
+
|
|
358
507
|
1. Review or refine specs/${projectSlug}/SPEC.md.
|
|
359
508
|
2. Create the first slice from specs/${projectSlug}/slices/slice-template/slice.json.
|
|
360
509
|
3. Review the plan with \`{{PLAN_COMMAND}}\` or \`npm run quiver:plan\`.
|
|
@@ -397,10 +546,15 @@ function initializeProjectDocs(options) {
|
|
|
397
546
|
projectRoot,
|
|
398
547
|
projectName,
|
|
399
548
|
cliVersion,
|
|
549
|
+
includeTemplates = false,
|
|
550
|
+
legacyScripts = false,
|
|
400
551
|
migrateMode = false,
|
|
552
|
+
profile = 'default',
|
|
553
|
+
templateRoot: providedTemplateRoot = '',
|
|
401
554
|
} = options;
|
|
402
555
|
|
|
403
|
-
const templateRoot = path.join(projectRoot, 'docs-template');
|
|
556
|
+
const templateRoot = providedTemplateRoot || path.join(projectRoot, 'docs-template');
|
|
557
|
+
const internalPaths = quiverInternalPaths(projectRoot);
|
|
404
558
|
const replacements = {
|
|
405
559
|
projectName,
|
|
406
560
|
projectSlug: toProjectSlug(projectName),
|
|
@@ -413,17 +567,48 @@ function initializeProjectDocs(options) {
|
|
|
413
567
|
const dirs = [
|
|
414
568
|
'docs',
|
|
415
569
|
'docs/ai',
|
|
416
|
-
'
|
|
417
|
-
'
|
|
418
|
-
`specs/${replacements.projectSlug}/slices/slice-template`,
|
|
419
|
-
'tools/scripts',
|
|
570
|
+
'.quiver',
|
|
571
|
+
'.quiver/scans',
|
|
420
572
|
];
|
|
421
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
|
+
|
|
422
586
|
for (const dir of dirs) {
|
|
423
587
|
ensureDir(path.join(projectRoot, dir));
|
|
424
588
|
}
|
|
425
589
|
|
|
426
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
|
+
|
|
427
612
|
const agentsSourcePath = path.join(templateRoot, 'AGENTS.md.template');
|
|
428
613
|
if (fs.existsSync(agentsSourcePath)) {
|
|
429
614
|
const agentsDestinationPath = path.join(projectRoot, 'AGENTS.md');
|
|
@@ -463,13 +648,45 @@ function initializeProjectDocs(options) {
|
|
|
463
648
|
['specs/[project-name]/slices/pr.md.template', `specs/${replacements.projectSlug}/slices/slice-template/pr.md.template`],
|
|
464
649
|
];
|
|
465
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
|
+
|
|
466
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
|
+
|
|
467
679
|
const sourcePath = path.join(templateRoot, source);
|
|
468
680
|
if (!fs.existsSync(sourcePath)) {
|
|
469
681
|
continue;
|
|
470
682
|
}
|
|
471
683
|
|
|
472
684
|
const destinationPath = path.join(projectRoot, destination);
|
|
685
|
+
if (!migrateMode && fs.existsSync(destinationPath)) {
|
|
686
|
+
operations.push({ source, destination, result: 'skipped' });
|
|
687
|
+
continue;
|
|
688
|
+
}
|
|
689
|
+
|
|
473
690
|
const result = copyRenderedFile(sourcePath, destinationPath, replacements, migrateMode, frontMatterFactory);
|
|
474
691
|
operations.push({ source, destination, result });
|
|
475
692
|
}
|
|
@@ -497,31 +714,58 @@ function initializeProjectDocs(options) {
|
|
|
497
714
|
['scripts/migrate-project.sh', 'tools/scripts/migrate-project.sh'],
|
|
498
715
|
];
|
|
499
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
|
+
|
|
500
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
|
+
|
|
501
739
|
const sourcePath = path.join(templateRoot, source);
|
|
502
740
|
const destinationPath = path.join(projectRoot, destination);
|
|
503
741
|
if (!fs.existsSync(sourcePath)) {
|
|
504
742
|
continue;
|
|
505
743
|
}
|
|
506
744
|
|
|
507
|
-
const result = copyIfSourceExists(sourcePath, destinationPath,
|
|
745
|
+
const result = copyIfSourceExists(sourcePath, destinationPath, true);
|
|
508
746
|
operations.push({ source, destination, result });
|
|
509
747
|
}
|
|
510
748
|
|
|
511
749
|
const aiPrinciplesSource = path.join(templateRoot, 'docs/ai/PRINCIPLES.md');
|
|
512
750
|
if (fs.existsSync(aiPrinciplesSource)) {
|
|
513
751
|
const aiPrinciplesDestination = path.join(projectRoot, 'docs/ai/PRINCIPLES.md');
|
|
514
|
-
const result =
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
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
|
+
);
|
|
521
761
|
operations.push({ source: 'docs/ai/PRINCIPLES.md', destination: 'docs/ai/PRINCIPLES.md', result });
|
|
522
762
|
}
|
|
523
763
|
|
|
524
|
-
const packageResult = mergePackageJson(projectRoot, templateRoot,
|
|
764
|
+
const packageResult = mergePackageJson(projectRoot, templateRoot, {
|
|
765
|
+
legacyScripts,
|
|
766
|
+
migrateMode,
|
|
767
|
+
profile,
|
|
768
|
+
});
|
|
525
769
|
operations.push({ source: 'package.template.json', destination: 'package.json', result: packageResult });
|
|
526
770
|
|
|
527
771
|
const mergedPackageJsonPath = path.join(projectRoot, 'package.json');
|
|
@@ -560,12 +804,21 @@ function initializeProjectDocs(options) {
|
|
|
560
804
|
];
|
|
561
805
|
|
|
562
806
|
for (const [source, destination] of tierCopies) {
|
|
807
|
+
if (profile !== 'full') {
|
|
808
|
+
continue;
|
|
809
|
+
}
|
|
810
|
+
|
|
563
811
|
const sourcePath = path.join(templateRoot, source);
|
|
564
812
|
if (!fs.existsSync(sourcePath)) {
|
|
565
813
|
continue;
|
|
566
814
|
}
|
|
567
815
|
|
|
568
816
|
const destinationPath = path.join(projectRoot, destination);
|
|
817
|
+
if (!migrateMode && fs.existsSync(destinationPath)) {
|
|
818
|
+
operations.push({ source, destination, result: 'skipped' });
|
|
819
|
+
continue;
|
|
820
|
+
}
|
|
821
|
+
|
|
569
822
|
const result = copyRenderedFile(sourcePath, destinationPath, tierReplacements, migrateMode, ({
|
|
570
823
|
body,
|
|
571
824
|
}) => buildFrontMatterFields({
|
|
@@ -613,7 +866,9 @@ function initializeProjectDocs(options) {
|
|
|
613
866
|
writeState(projectRoot, nextState);
|
|
614
867
|
|
|
615
868
|
const searchPath = path.join(projectRoot, 'docs', 'SEARCH.md');
|
|
616
|
-
if (
|
|
869
|
+
if (profile !== 'full') {
|
|
870
|
+
operations.push({ source: 'docs/SEARCH.md', destination: 'docs/SEARCH.md', result: 'skipped-profile' });
|
|
871
|
+
} else if (!fs.existsSync(searchPath)) {
|
|
617
872
|
const searchContent = `# Búsqueda por Tema
|
|
618
873
|
|
|
619
874
|
**Última actualización:** ${replacements.currentDate}
|
|
@@ -662,7 +917,7 @@ function initializeProjectDocs(options) {
|
|
|
662
917
|
|
|
663
918
|
const readmePath = path.join(projectRoot, 'README.md');
|
|
664
919
|
if (!fs.existsSync(readmePath)) {
|
|
665
|
-
fs.writeFileSync(readmePath, `${renderTemplate(buildReadme(projectName, replacements.projectSlug), replacements)}\n`);
|
|
920
|
+
fs.writeFileSync(readmePath, `${renderTemplate(buildReadme(projectName, replacements.projectSlug, profile), replacements)}\n`);
|
|
666
921
|
operations.push({ source: 'README.md template', destination: 'README.md', result: 'created' });
|
|
667
922
|
} else {
|
|
668
923
|
operations.push({ source: 'README.md template', destination: 'README.md', result: 'skipped' });
|