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,5 +1,130 @@
1
+ const { statusPorcelain } = require('./git');
2
+ const { normalizeContextPath } = require('./ai/safety');
1
3
  const { checkScope } = require('./readiness');
2
4
 
5
+ class ScopeValidationError extends Error {
6
+ constructor(code, message, details = {}) {
7
+ super(message);
8
+ this.name = 'ScopeValidationError';
9
+ this.code = code;
10
+ this.details = details;
11
+ }
12
+ }
13
+
14
+ function formatError(message) {
15
+ return `create-quiver: ${message}`;
16
+ }
17
+
18
+ function normalizeScopePath(filePath) {
19
+ return normalizeContextPath(filePath);
20
+ }
21
+
22
+ function parseStatusPorcelain(text) {
23
+ if (!text) {
24
+ return [];
25
+ }
26
+
27
+ return String(text)
28
+ .split('\n')
29
+ .map((line) => line.trimEnd())
30
+ .filter(Boolean)
31
+ .map((line) => {
32
+ if (line.startsWith('?? ')) {
33
+ return normalizeScopePath(line.slice(3));
34
+ }
35
+
36
+ const entry = (line[2] === ' ' ? line.slice(3) : line[1] === ' ' ? line.slice(2) : line.slice(3)).trim();
37
+ if (!entry) {
38
+ return '';
39
+ }
40
+
41
+ const renamedTarget = entry.includes(' -> ') ? entry.split(' -> ').pop() : entry;
42
+ return normalizeScopePath(renamedTarget);
43
+ })
44
+ .filter(Boolean);
45
+ }
46
+
47
+ function captureWorktreeSnapshot(repoRoot, options = {}) {
48
+ const raw = typeof options.rawStatus === 'string' ? options.rawStatus : statusPorcelain(repoRoot);
49
+ const files = parseStatusPorcelain(raw);
50
+
51
+ return {
52
+ repoRoot,
53
+ raw,
54
+ files,
55
+ };
56
+ }
57
+
58
+ function diffWorktreeSnapshots(beforeSnapshot, afterSnapshot) {
59
+ const beforeFiles = new Set((beforeSnapshot && Array.isArray(beforeSnapshot.files) ? beforeSnapshot.files : []).map(normalizeScopePath));
60
+ const seen = new Set();
61
+ const changedFiles = [];
62
+
63
+ for (const file of afterSnapshot && Array.isArray(afterSnapshot.files) ? afterSnapshot.files : []) {
64
+ const normalized = normalizeScopePath(file);
65
+ if (!normalized || beforeFiles.has(normalized) || seen.has(normalized)) {
66
+ continue;
67
+ }
68
+
69
+ seen.add(normalized);
70
+ changedFiles.push(normalized);
71
+ }
72
+
73
+ return changedFiles;
74
+ }
75
+
76
+ function validateScopeSnapshot({ allowedFiles = [], beforeSnapshot, afterSnapshot, strict = true } = {}) {
77
+ const normalizedAllowedFiles = new Set(
78
+ Array.isArray(allowedFiles)
79
+ ? allowedFiles.map(normalizeScopePath).filter(Boolean)
80
+ : [],
81
+ );
82
+ const changedFiles = diffWorktreeSnapshots(beforeSnapshot, afterSnapshot);
83
+ const outOfScopeFiles = changedFiles.filter((file) => !normalizedAllowedFiles.has(file));
84
+
85
+ if (outOfScopeFiles.length === 0) {
86
+ return {
87
+ ok: true,
88
+ changedFiles,
89
+ outOfScopeFiles,
90
+ allowedFiles: Array.from(normalizedAllowedFiles),
91
+ beforeSnapshot,
92
+ afterSnapshot,
93
+ };
94
+ }
95
+
96
+ const message = formatError(
97
+ `scope violation detected: changed files outside slice.json.files: ${outOfScopeFiles.join(', ')}`,
98
+ );
99
+ const error = new ScopeValidationError('SCOPE_VIOLATION', message, {
100
+ allowedFiles: Array.from(normalizedAllowedFiles),
101
+ beforeSnapshot,
102
+ afterSnapshot,
103
+ changedFiles,
104
+ outOfScopeFiles,
105
+ });
106
+
107
+ if (strict) {
108
+ throw error;
109
+ }
110
+
111
+ return {
112
+ ok: false,
113
+ changedFiles,
114
+ outOfScopeFiles,
115
+ allowedFiles: Array.from(normalizedAllowedFiles),
116
+ beforeSnapshot,
117
+ afterSnapshot,
118
+ error,
119
+ };
120
+ }
121
+
3
122
  module.exports = {
123
+ ScopeValidationError,
124
+ captureWorktreeSnapshot,
125
+ diffWorktreeSnapshots,
4
126
  checkScope,
127
+ normalizeScopePath,
128
+ parseStatusPorcelain,
129
+ validateScopeSnapshot,
5
130
  };
@@ -34,6 +34,10 @@ function naturalNumberFromSliceId(sliceId) {
34
34
  return match ? Number.parseInt(match[1], 10) : Number.POSITIVE_INFINITY;
35
35
  }
36
36
 
37
+ function isFoundationSliceId(sliceId) {
38
+ return naturalNumberFromSliceId(sliceId) === 0;
39
+ }
40
+
37
41
  function compareSliceRefs(a, b) {
38
42
  const left = String(a || '');
39
43
  const right = String(b || '');
@@ -448,6 +452,8 @@ module.exports = {
448
452
  computeLevels,
449
453
  detectFileConflicts,
450
454
  inferDependencies,
455
+ isFoundationSliceId,
451
456
  readAllSlices,
457
+ naturalNumberFromSliceId,
452
458
  topoSort,
453
459
  };
@@ -1,17 +1,18 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
3
  const { parseJsonWithComments } = require('./json');
4
- const { resolveTargetRoot, toPosixPath } = require('./paths');
4
+ const { normalizeGitBashDrivePath, relativePosixPath, resolveTargetRoot, specRelativePathFromPath, toPosixPath } = require('./paths');
5
5
 
6
6
  function readJson(filePath) {
7
7
  return JSON.parse(fs.readFileSync(filePath, 'utf8'));
8
8
  }
9
9
 
10
10
  function canonicalizePath(dirPath) {
11
+ const normalizedPath = normalizeGitBashDrivePath(dirPath);
11
12
  try {
12
- return fs.realpathSync(dirPath);
13
+ return normalizeGitBashDrivePath(fs.realpathSync(normalizedPath));
13
14
  } catch {
14
- return path.resolve(dirPath);
15
+ return path.resolve(normalizedPath);
15
16
  }
16
17
  }
17
18
 
@@ -94,19 +95,61 @@ function validateSliceMetaForStart(slice) {
94
95
  }
95
96
  }
96
97
 
98
+ function isSpecRelativePath(parts) {
99
+ return parts[0] === 'specs' || parts[0] === 'specs-fix';
100
+ }
101
+
102
+ function resolveRepoSlicePath(repoRoot, relSlicePath) {
103
+ const candidate = path.join(repoRoot, relSlicePath);
104
+ if (!fs.existsSync(candidate)) {
105
+ return '';
106
+ }
107
+
108
+ return canonicalizePath(candidate);
109
+ }
110
+
97
111
  function resolveSliceContext(repoRoot, slicePath) {
98
- const absSlicePath = resolveSlicePath(slicePath);
99
- const relSlicePath = toPosixPath(path.relative(repoRoot, absSlicePath));
100
- const parts = relSlicePath.split('/');
112
+ const canonicalRepoRoot = canonicalizePath(repoRoot);
113
+ let absSlicePath = resolveSlicePath(slicePath);
114
+ let relSlicePath = relativePosixPath(canonicalRepoRoot, absSlicePath);
115
+ let parts = relSlicePath.split('/');
116
+
117
+ if (!isSpecRelativePath(parts)) {
118
+ const cwdRelSlicePath = relativePosixPath(canonicalizePath(process.cwd()), absSlicePath);
119
+ const cwdParts = cwdRelSlicePath.split('/');
120
+ if (isSpecRelativePath(cwdParts)) {
121
+ relSlicePath = cwdRelSlicePath;
122
+ parts = cwdParts;
123
+ }
124
+ }
125
+
126
+ if (!isSpecRelativePath(parts) && !path.isAbsolute(slicePath)) {
127
+ const inputRelSlicePath = toPosixPath(slicePath).replace(/^\.\/+/, '');
128
+ const inputParts = inputRelSlicePath.split('/');
129
+ if (isSpecRelativePath(inputParts)) {
130
+ relSlicePath = inputRelSlicePath;
131
+ parts = inputParts;
132
+ }
133
+ }
134
+
135
+ if (!isSpecRelativePath(parts)) {
136
+ const candidateRelSlicePath = specRelativePathFromPath(absSlicePath) || specRelativePathFromPath(slicePath);
137
+ const candidateAbsSlicePath = candidateRelSlicePath ? resolveRepoSlicePath(canonicalRepoRoot, candidateRelSlicePath) : '';
138
+ if (candidateAbsSlicePath) {
139
+ relSlicePath = candidateRelSlicePath;
140
+ parts = relSlicePath.split('/');
141
+ absSlicePath = candidateAbsSlicePath;
142
+ }
143
+ }
101
144
 
102
- if (parts[0] !== 'specs' && parts[0] !== 'specs-fix') {
145
+ if (!isSpecRelativePath(parts)) {
103
146
  throw new Error('create-quiver: el slice debe vivir dentro de specs/ o specs-fix/.');
104
147
  }
105
148
 
106
149
  const specFamily = parts[0];
107
150
  const specSlug = parts[1];
108
151
  const specDirRel = `${specFamily}/${specSlug}`;
109
- const specDirAbs = path.join(repoRoot, specDirRel);
152
+ const specDirAbs = path.join(canonicalRepoRoot, specDirRel);
110
153
  const slice = readSliceMeta(absSlicePath);
111
154
  slice.specFamily = specFamily;
112
155
  slice.specSlug = specSlug;
@@ -1,8 +1,9 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
+ const { quiverInternalPaths } = require('./init-layout');
3
4
 
4
5
  function statePath(projectRoot) {
5
- return path.join(projectRoot, '.quiver', 'state.json');
6
+ return quiverInternalPaths(projectRoot).statePath;
6
7
  }
7
8
 
8
9
  function ensureDir(dirPath) {
@@ -60,6 +61,21 @@ function hasLegacyQuiverInitializationEvidence(projectRoot) {
60
61
  && hasGeneratedProjectSpec(projectRoot);
61
62
  }
62
63
 
64
+ function inspectLegacyMigrationLayout(projectRoot) {
65
+ const candidates = [
66
+ 'docs-template/',
67
+ 'tools/scripts/',
68
+ 'docs/PROJECT_SCAN.json',
69
+ ];
70
+
71
+ const detected = candidates.filter((relativePath) => fs.existsSync(path.join(projectRoot, relativePath)));
72
+
73
+ return {
74
+ hasLegacyLayout: detected.length > 0,
75
+ legacyPaths: detected,
76
+ };
77
+ }
78
+
63
79
  function hasQuiverInitializationEvidence(projectRoot) {
64
80
  const state = readState(projectRoot);
65
81
  return hasInitializedStateMetadata(state) || hasLegacyQuiverInitializationEvidence(projectRoot);
@@ -129,6 +145,7 @@ module.exports = {
129
145
  hasGeneratedProjectSpec,
130
146
  hasInitializedStateMetadata,
131
147
  hasLegacyQuiverInitializationEvidence,
148
+ inspectLegacyMigrationLayout,
132
149
  hasQuiverInitializationEvidence,
133
150
  readState,
134
151
  statePath,
@@ -0,0 +1,74 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ function resolvePackagedTemplateRoot(packageRoot = path.resolve(__dirname, '../../..')) {
5
+ return packageRoot;
6
+ }
7
+
8
+ function resolveExportedTemplateRoot(projectRoot) {
9
+ return path.join(projectRoot, '.quiver', 'templates');
10
+ }
11
+
12
+ function resolveLegacyTemplateRoot(projectRoot) {
13
+ return path.join(projectRoot, 'docs-template');
14
+ }
15
+
16
+ function templateRootExists(templateRoot) {
17
+ return fs.existsSync(path.join(templateRoot, 'docs'))
18
+ && fs.existsSync(path.join(templateRoot, 'specs'))
19
+ && fs.existsSync(path.join(templateRoot, 'package.template.json'));
20
+ }
21
+
22
+ function resolveTemplateRoot(projectRoot, options = {}) {
23
+ const packageRoot = options.packageRoot || resolvePackagedTemplateRoot();
24
+ const candidates = [];
25
+
26
+ if (options.preferExported === true) {
27
+ candidates.push({
28
+ kind: 'exported',
29
+ path: resolveExportedTemplateRoot(projectRoot),
30
+ });
31
+ }
32
+
33
+ candidates.push({
34
+ kind: 'packaged',
35
+ path: resolvePackagedTemplateRoot(packageRoot),
36
+ });
37
+
38
+ candidates.push({
39
+ kind: 'legacy',
40
+ path: resolveLegacyTemplateRoot(projectRoot),
41
+ });
42
+
43
+ for (const candidate of candidates) {
44
+ if (templateRootExists(candidate.path)) {
45
+ return candidate;
46
+ }
47
+ }
48
+
49
+ const searched = candidates.map((candidate) => `${candidate.kind}: ${candidate.path}`).join(', ');
50
+ throw new Error(`create-quiver: missing Quiver templates. Searched ${searched}`);
51
+ }
52
+
53
+ function resolveTemplatePath(projectRoot, relativePath, options = {}) {
54
+ const root = resolveTemplateRoot(projectRoot, options);
55
+ const templatePath = path.join(root.path, relativePath);
56
+
57
+ if (!fs.existsSync(templatePath)) {
58
+ throw new Error(`create-quiver: missing template ${relativePath} in ${root.path}`);
59
+ }
60
+
61
+ return {
62
+ ...root,
63
+ templatePath,
64
+ };
65
+ }
66
+
67
+ module.exports = {
68
+ resolveExportedTemplateRoot,
69
+ resolveLegacyTemplateRoot,
70
+ resolvePackagedTemplateRoot,
71
+ resolveTemplatePath,
72
+ resolveTemplateRoot,
73
+ templateRootExists,
74
+ };
@@ -1,52 +0,0 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Bash(git fetch *)",
5
- "Bash(git checkout *)",
6
- "Bash(git add *)",
7
- "Bash(git commit -m ' *)",
8
- "Bash(git cherry-pick *)",
9
- "Bash(git reset *)",
10
- "Bash(gh pr create --title 'docs: register v17-v22 orchestration plan and park web console idea' --base main --head docs/register-orchestration-plan-park-web-console --body ' *)",
11
- "Bash(gh auth *)",
12
- "Bash(gh pr *)",
13
- "Bash(node -e \"const g=require\\('./src/create-quiver/lib/slice-graph'\\); const slices=g.readAllSlices\\('.'\\); console.log\\('Total slices:', slices.length\\); const graph=g.buildGraph\\(slices\\); const levels=g.computeLevels\\(graph\\); console.log\\('Levels:', levels.length\\);\")",
14
- "Bash(npx . plan)",
15
- "Bash(git pull *)",
16
- "Read(//Users/fabrijk/Documents/Work/Proyectos Personales/nika/frameworks/.worktrees/quiver/bugfix-QUIVER-01-fix-legacy-dependency-resolution/**)",
17
- "Bash(node --test tests/)",
18
- "Bash(node --test tests/**/*.test.js)",
19
- "Bash(node bin/create-quiver.js plan)",
20
- "Bash(echo \"EXIT_$?\")",
21
- "Bash(node bin/create-quiver.js plan --json)",
22
- "Bash(node -e \"const d=JSON.parse\\(require\\('fs'\\).readFileSync\\('/dev/stdin','utf8'\\)\\); console.log\\('plan items:', Array.isArray\\(d.plan\\) ? d.plan.length : 'NOT ARRAY'\\); console.log\\('critical_path:', Array.isArray\\(d.critical_path\\)\\); console.log\\('total_hours:', typeof d.total_hours\\); process.exit\\(Array.isArray\\(d.plan\\) && Array.isArray\\(d.critical_path\\) && typeof d.total_hours === 'number' ? 0 : 1\\)\")",
23
- "Bash(grep -v \"^\\\\-\\\\-$\")",
24
- "Bash(echo \"EXIT:$?\")",
25
- "Bash(node -e \"const d=JSON.parse\\(require\\('fs'\\).readFileSync\\('/tmp/plan_json.txt','utf8'\\)\\); console.log\\('plan:', Array.isArray\\(d.plan\\) ? d.plan.length + ' items' : 'INVALID'\\); console.log\\('critical_path:', Array.isArray\\(d.critical_path\\)\\); console.log\\('total_hours:', typeof d.total_hours\\)\")",
26
- "Bash(xargs git branch -d)",
27
- "Bash(git branch *)",
28
- "Read(//private/tmp/**)",
29
- "Read(//Users/fabrijk/Documents/Work/Proyectos Personales/nika/frameworks/quiver-v18-slice02/**)",
30
- "Bash(git worktree *)",
31
- "Bash(git ls-remote *)",
32
- "Bash(node *)",
33
- "Bash(npm view *)",
34
- "Bash(bash scripts/release-quiver.sh)",
35
- "Bash(git stash *)",
36
- "Bash(npm whoami *)",
37
- "Bash(bash scripts/release-quiver.sh --publish-current)",
38
- "Bash(npm pkg *)",
39
- "Bash(NPM_TOKEN=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 npm publish --access public)",
40
- "Bash(NPM_TOKEN=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 npm publish --access public)",
41
- "Bash(npm info *)",
42
- "Bash(npm publish *)",
43
- "Bash(rm -rf /tmp/quiver-skip-test)",
44
- "Bash(mkdir -p /tmp/quiver-skip-test)",
45
- "Bash(echo '{\"name\":\"test\",\"scripts\":{}}')",
46
- "Bash(ls /tmp/quiver-skip-test/node_modules/create-quiver)",
47
- "Bash(rm -rf /tmp/quiver-install-test)",
48
- "Bash(mkdir -p /tmp/quiver-install-test)",
49
- "Bash(npm config *)"
50
- ]
51
- }
52
- }