create-quiver 0.4.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 (71) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +15 -0
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +15 -0
  3. package/.github/pull_request_template.md +4 -0
  4. package/.github/workflows/ci.yml +74 -0
  5. package/CHANGELOG.md +24 -0
  6. package/CODE_OF_CONDUCT.md +12 -0
  7. package/CONTRIBUTING.md +15 -0
  8. package/LICENSE +21 -0
  9. package/README.md +118 -0
  10. package/README_FOR_AI.md +90 -0
  11. package/ROADMAP.md +20 -0
  12. package/SECURITY.md +12 -0
  13. package/TEMPLATE.md +108 -0
  14. package/bin/create-quiver.js +8 -0
  15. package/docs/CONTEXTO.md.template +45 -0
  16. package/docs/DOCUMENTATION_GUIDE.md.template +34 -0
  17. package/docs/GITFLOW_PR_GUIDE.md.template +52 -0
  18. package/docs/INDEX.md.template +41 -0
  19. package/docs/MOCK_DATA_GUIDE.md.template +31 -0
  20. package/docs/MULTI_AGENT_WORKFLOW.md.template +31 -0
  21. package/docs/STATUS.md.template +26 -0
  22. package/docs/SUPPORT_MATRIX.md.template +31 -0
  23. package/docs/TESTING_GUIDE_FOR_AI.md.template +42 -0
  24. package/docs/TROUBLESHOOTING.md.template +70 -0
  25. package/docs/UI_STANDARDS.md.template +31 -0
  26. package/docs/WORKFLOW.md.template +56 -0
  27. package/docs/ai/LESSONS.md.template +24 -0
  28. package/docs/ai/PRINCIPLES.md +25 -0
  29. package/docs/ai/RULES.yaml +33 -0
  30. package/i18n/es/README.md +15 -0
  31. package/i18n/es/README_FOR_AI.md +6 -0
  32. package/i18n/es/TEMPLATE.md +18 -0
  33. package/i18n/es/docs/CONTEXTO.md.template +9 -0
  34. package/i18n/es/docs/DOCUMENTATION_GUIDE.md.template +4 -0
  35. package/i18n/es/docs/GITFLOW_PR_GUIDE.md.template +4 -0
  36. package/i18n/es/docs/INDEX.md.template +10 -0
  37. package/i18n/es/docs/MOCK_DATA_GUIDE.md.template +4 -0
  38. package/i18n/es/docs/MULTI_AGENT_WORKFLOW.md.template +4 -0
  39. package/i18n/es/docs/STATUS.md.template +9 -0
  40. package/i18n/es/docs/TESTING_GUIDE_FOR_AI.md.template +7 -0
  41. package/i18n/es/docs/UI_STANDARDS.md.template +4 -0
  42. package/i18n/es/docs/WORKFLOW.md.template +6 -0
  43. package/i18n/es/docs/ai/LESSONS.md.template +3 -0
  44. package/i18n/es/docs/ai/PRINCIPLES.md +7 -0
  45. package/i18n/es/docs/ai/RULES.yaml +7 -0
  46. package/package.json +19 -0
  47. package/package.template.json +10 -0
  48. package/scripts/check-pr-readiness.sh +138 -0
  49. package/scripts/check-scope.sh +150 -0
  50. package/scripts/check-slice-readiness.sh +319 -0
  51. package/scripts/cleanup-slice.sh +177 -0
  52. package/scripts/init-docs.sh +368 -0
  53. package/scripts/migrate-project.sh +218 -0
  54. package/scripts/package-quiver.sh +124 -0
  55. package/scripts/refresh-active-slices.sh +232 -0
  56. package/scripts/release-quiver.sh +77 -0
  57. package/scripts/start-slice.sh +429 -0
  58. package/specs/[project-name]/EVIDENCE_REPORT.md.template +15 -0
  59. package/specs/[project-name]/SPEC.md.template +39 -0
  60. package/specs/[project-name]/STATUS.md.template +22 -0
  61. package/specs/[project-name]/slices/pr.md.template +97 -0
  62. package/specs/[project-name]/slices/slice-template/slice.json +69 -0
  63. package/specs/quiver-v05-readme-adoption-contract/EVIDENCE_REPORT.md +21 -0
  64. package/specs/quiver-v05-readme-adoption-contract/SPEC.md +40 -0
  65. package/specs/quiver-v05-readme-adoption-contract/STATUS.md +24 -0
  66. package/specs/quiver-v05-readme-adoption-contract/slices/slice-01-readme-adoption-contract/slice.json +68 -0
  67. package/specs/quiver-v06-release-readiness/EVIDENCE_REPORT.md +23 -0
  68. package/specs/quiver-v06-release-readiness/SPEC.md +40 -0
  69. package/specs/quiver-v06-release-readiness/STATUS.md +24 -0
  70. package/specs/quiver-v06-release-readiness/slices/slice-01-first-npm-release-readiness/slice.json +71 -0
  71. package/src/create-quiver/index.js +329 -0
@@ -0,0 +1,40 @@
1
+ # Quiver v0.5 - README Adoption Contract
2
+
3
+ **Date:** 2026-04-21
4
+ **Status:** Completed
5
+
6
+ Slice numbering resets here: this spec starts at `slice-01` and does not continue any previous spec's numbering.
7
+
8
+ ## Objective
9
+
10
+ Make the root README the adoption contract for Quiver: a new user should understand what Quiver is, install it with the canonical CLI, validate the scaffold, and start the first slice without reading historical implementation notes.
11
+
12
+ ## Scope
13
+
14
+ ### Included
15
+
16
+ - Reposition the README around `create-quiver` as the primary install path
17
+ - Keep manual `docs-template/` usage as a local development fallback
18
+ - Document the first slice workflow at a high level
19
+ - Separate user adoption guidance from maintainer release guidance
20
+ - Reduce long file inventories and link to the relevant generated docs instead
21
+
22
+ ### Excluded
23
+
24
+ - CLI behavior changes
25
+ - Generated template content changes
26
+ - Hosted documentation
27
+ - Release automation changes
28
+
29
+ ## Slices
30
+
31
+ | Slice | Title | Status |
32
+ |-------|-------|--------|
33
+ | 01 | README Adoption Contract | Completed |
34
+
35
+ ## Definition of Done
36
+
37
+ - The first install command in the README uses `npx create-quiver`
38
+ - The README explains install, doctor validation, first slice workflow, manual fallback, and maintainer commands
39
+ - Commands shown in the README match the current CLI and package scripts
40
+ - The README no longer presents manual template copying as the primary path
@@ -0,0 +1,24 @@
1
+ # Quiver v0.5 Spec Status
2
+
3
+ **Spec:** quiver-v05-readme-adoption-contract
4
+ **Last updated:** 2026-04-21
5
+
6
+ Slice numbering is local to this spec. The first slice is `slice-01`.
7
+
8
+ ## Status
9
+
10
+ | Slice | Title | Status | PR | Estimated hours | Actual hours |
11
+ |-------|-------|--------|----|-----------------|--------------|
12
+ | slice-01 | README Adoption Contract | Completed | - | 2 | 2 |
13
+
14
+ ## Progress
15
+
16
+ - Completed slices: 1 / 1
17
+ - Estimated hours: 2
18
+ - Actual hours: 2
19
+
20
+ ## Blockers
21
+
22
+ | Slice | Blocker | Since | Action needed |
23
+ |-------|---------|-------|---------------|
24
+ | - | - | - | - |
@@ -0,0 +1,68 @@
1
+ {
2
+ "slice_id": "slice-01-readme-adoption-contract",
3
+ "ticket": "QUIVER-01",
4
+ "type": "docs",
5
+ "title": "README Adoption Contract",
6
+ "objective": "Rewrite the root README so it presents Quiver as a CLI-first adoption workflow rather than a manual docs-template copy.",
7
+ "description": "The existing README mixes the historical manual template flow with the newer create-quiver installer. This slice makes the README a concise adoption contract for users and maintainers without changing runtime behavior.",
8
+ "git": {
9
+ "branch_type": "docs",
10
+ "base_branch": "develop",
11
+ "branch_slug": "readme-adoption-contract",
12
+ "branch_name": "docs/QUIVER-01-readme-adoption-contract"
13
+ },
14
+ "must": [
15
+ "Make `npx create-quiver` the primary quick-start path",
16
+ "Document `create-quiver doctor` immediately after installation",
17
+ "Explain the first slice workflow at a high level",
18
+ "Move release guidance into a maintainer-focused section",
19
+ "Keep manual `docs-template/` use as a fallback or local development path",
20
+ "Avoid long duplicated file inventories in the root README"
21
+ ],
22
+ "not_included": [
23
+ "Changes to CLI behavior",
24
+ "Changes to generated project templates",
25
+ "Hosted docs or website work"
26
+ ],
27
+ "acceptance": [
28
+ "A new reader can install, validate, and begin slice work from the README alone",
29
+ "The README's commands match the current CLI help and package scripts",
30
+ "Manual copy instructions no longer appear before the CLI quick start",
31
+ "Maintainer release instructions are separated from user onboarding",
32
+ "The README links to AI, support, and troubleshooting docs instead of duplicating their full contents",
33
+ "The change is limited to README and spec traceability files"
34
+ ],
35
+ "files": [
36
+ "README.md",
37
+ "specs/quiver-v05-readme-adoption-contract/SPEC.md",
38
+ "specs/quiver-v05-readme-adoption-contract/STATUS.md",
39
+ "specs/quiver-v05-readme-adoption-contract/EVIDENCE_REPORT.md",
40
+ "specs/quiver-v05-readme-adoption-contract/slices/slice-01-readme-adoption-contract/slice.json"
41
+ ],
42
+ "tests": [
43
+ "CLI help command check",
44
+ "release helper help command check",
45
+ "package.json script existence check",
46
+ "README target link existence check",
47
+ "git diff whitespace check"
48
+ ],
49
+ "documentation": [
50
+ "specs/quiver-v05-readme-adoption-contract/SPEC.md",
51
+ "specs/quiver-v05-readme-adoption-contract/STATUS.md",
52
+ "specs/quiver-v05-readme-adoption-contract/EVIDENCE_REPORT.md"
53
+ ],
54
+ "dependencies": [
55
+ "quiver-v04-zero-friction-installation"
56
+ ],
57
+ "assumptions": [
58
+ "The README should stay concise and point to detailed generated docs",
59
+ "The canonical install path is the npm CLI entrypoint"
60
+ ],
61
+ "estimated_hours": 2,
62
+ "actual_hours": 2,
63
+ "status": "completed",
64
+ "blocked_reason": null,
65
+ "ready_at": "2026-04-21T00:00:00Z",
66
+ "started_at": "2026-04-21T00:00:00Z",
67
+ "completed_at": "2026-04-21T00:00:00Z"
68
+ }
@@ -0,0 +1,23 @@
1
+ # Quiver v0.6 Evidence Report
2
+
3
+ **Spec:** quiver-v06-release-readiness
4
+ **Last updated:** 2026-04-21
5
+ **Status:** Completed
6
+
7
+ ## Summary
8
+
9
+ | Slice | Acceptance criteria | Status | Evidence |
10
+ |-------|---------------------|--------|----------|
11
+ | slice-01 | 6 | Completed | Release helper now supports `--publish-current`, changelog has `0.4.0`, and README documents the exact preflight and publish steps |
12
+
13
+ ## Evidence by Slice
14
+
15
+ - `bash -n scripts/release-quiver.sh`
16
+ - `git diff --check`
17
+ - `node -e "const fs=require('fs'); JSON.parse(fs.readFileSync('specs/quiver-v06-release-readiness/slices/slice-01-first-npm-release-readiness/slice.json','utf8'))"`
18
+
19
+ ## Preflight Notes
20
+
21
+ - `npm whoami` failed with `ENEEDAUTH`; npm login is required before publish.
22
+ - `npm view create-quiver version` failed with DNS/network resolution against `registry.npmjs.org`; registry reachability must be verified before publish.
23
+ - Current package metadata is `create-quiver@0.4.0`.
@@ -0,0 +1,40 @@
1
+ # Quiver v0.6 - Release Readiness
2
+
3
+ **Date:** 2026-04-21
4
+ **Status:** Completed
5
+
6
+ Slice numbering resets here: this spec starts at `slice-01` and does not continue any previous spec's numbering.
7
+
8
+ ## Objective
9
+
10
+ Prepare Quiver for its first public npm release without accidentally bumping past the intended initial version.
11
+
12
+ ## Scope
13
+
14
+ ### Included
15
+
16
+ - Align the release helper with first-release needs
17
+ - Update the changelog from `Unreleased` to the intended release version
18
+ - Validate the local package, installer smoke, release dry run, and npm prereqs
19
+ - Document the publish steps and post-release verification
20
+
21
+ ### Excluded
22
+
23
+ - Publishing the package during spec preparation
24
+ - Changing CLI behavior
25
+ - Changing generated project templates
26
+ - Hosted documentation or marketing work
27
+
28
+ ## Slices
29
+
30
+ | Slice | Title | Status |
31
+ |-------|-------|--------|
32
+ | 01 | First npm Release Readiness | Completed |
33
+
34
+ ## Definition of Done
35
+
36
+ - The release helper can validate and publish the current package version without forcing an unintended patch bump
37
+ - `CHANGELOG.md` has a `0.4.0` release entry dated 2026-04-21 and a fresh `Unreleased` section
38
+ - npm auth and package-name availability are checked before publish
39
+ - Local package, installer, and release dry-run validations pass
40
+ - The publish command is explicit and not run as part of this slice unless requested separately
@@ -0,0 +1,24 @@
1
+ # Quiver v0.6 Spec Status
2
+
3
+ **Spec:** quiver-v06-release-readiness
4
+ **Last updated:** 2026-04-21
5
+
6
+ Slice numbering is local to this spec. The first slice is `slice-01`.
7
+
8
+ ## Status
9
+
10
+ | Slice | Title | Status | PR | Estimated hours | Actual hours |
11
+ |-------|-------|--------|----|-----------------|--------------|
12
+ | slice-01 | First npm Release Readiness | Completed | - | 2 | 2 |
13
+
14
+ ## Progress
15
+
16
+ - Completed slices: 1 / 1
17
+ - Estimated hours: 2
18
+ - Actual hours: 2
19
+
20
+ ## Blockers
21
+
22
+ | Slice | Blocker | Since | Action needed |
23
+ |-------|---------|-------|---------------|
24
+ | - | - | - | - |
@@ -0,0 +1,71 @@
1
+ {
2
+ "slice_id": "slice-01-first-npm-release-readiness",
3
+ "ticket": "QUIVER-01",
4
+ "type": "release",
5
+ "title": "First npm Release Readiness",
6
+ "objective": "Prepare the repository for publishing the first public `create-quiver` npm package at the intended current version.",
7
+ "description": "The package is functionally ready, but the current release helper always runs `npm version patch` when publishing. That would publish `0.4.1` as the first public release instead of the current `0.4.0`. This slice updates the release contract, changelog, and validation path so publishing is explicit and version-safe.",
8
+ "git": {
9
+ "branch_type": "release",
10
+ "base_branch": "develop",
11
+ "branch_slug": "first-npm-release-readiness",
12
+ "branch_name": "release/QUIVER-01-first-npm-release-readiness"
13
+ },
14
+ "must": [
15
+ "Update `scripts/release-quiver.sh` so maintainers can publish the current version intentionally without forcing a patch bump",
16
+ "Update `CHANGELOG.md` so the current release notes move from `Unreleased` to `0.4.0 - 2026-04-21`",
17
+ "Keep `Unreleased` available for future changes",
18
+ "Document the exact preflight checks for npm auth, package-name availability, package smoke, installer smoke, and release dry run",
19
+ "Run local validations but do not publish unless a separate explicit release request is made"
20
+ ],
21
+ "not_included": [
22
+ "Publishing to npm",
23
+ "Changing package name or CLI behavior",
24
+ "Creating hosted docs or release marketing",
25
+ "Changing generated project templates"
26
+ ],
27
+ "acceptance": [
28
+ "Maintainers can publish `create-quiver@0.4.0` without an unintended version bump",
29
+ "`CHANGELOG.md` has a dated `0.4.0` section and a fresh `Unreleased` section",
30
+ "Release dry run still validates installer and package smoke checks",
31
+ "The spec records npm auth and registry reachability as required preflight gates",
32
+ "The publish step remains explicit and separate from this preparation work",
33
+ "No npm publish command is executed during this slice"
34
+ ],
35
+ "files": [
36
+ "scripts/release-quiver.sh",
37
+ "CHANGELOG.md",
38
+ "README.md",
39
+ "specs/quiver-v06-release-readiness/SPEC.md",
40
+ "specs/quiver-v06-release-readiness/STATUS.md",
41
+ "specs/quiver-v06-release-readiness/EVIDENCE_REPORT.md",
42
+ "specs/quiver-v06-release-readiness/slices/slice-01-first-npm-release-readiness/slice.json"
43
+ ],
44
+ "tests": [
45
+ "npm auth and package-name preflight are documented in the README",
46
+ "package smoke",
47
+ "installer smoke",
48
+ "release dry run",
49
+ "git diff whitespace check"
50
+ ],
51
+ "documentation": [
52
+ "specs/quiver-v06-release-readiness/SPEC.md",
53
+ "specs/quiver-v06-release-readiness/STATUS.md",
54
+ "specs/quiver-v06-release-readiness/EVIDENCE_REPORT.md"
55
+ ],
56
+ "dependencies": [
57
+ "quiver-v05-readme-adoption-contract"
58
+ ],
59
+ "assumptions": [
60
+ "The first public release should use the current package version `0.4.0`",
61
+ "The package name remains `create-quiver` unless npm availability proves otherwise",
62
+ "Publishing requires separate explicit approval after this readiness slice is merged"
63
+ ],
64
+ "estimated_hours": 2,
65
+ "actual_hours": 2,
66
+ "status": "completed",
67
+ "blocked_reason": null,
68
+ "ready_at": "2026-04-21T00:00:00Z",
69
+ "started_at": "2026-04-21T00:00:00Z",
70
+ "completed_at": "2026-04-21T00:00:00Z"
71
+ }
@@ -0,0 +1,329 @@
1
+ const fs = require('fs');
2
+ const os = require('os');
3
+ const path = require('path');
4
+ const { execFileSync } = require('child_process');
5
+
6
+ function formatError(message) {
7
+ return `create-quiver: ${message}`;
8
+ }
9
+
10
+ function printUsage() {
11
+ console.log(`Usage:
12
+ npx create-quiver [options]
13
+ npx create-quiver doctor [options]
14
+
15
+ Options:
16
+ -n, --name <project-name> Project name to generate
17
+ -d, --dir <target-dir> Target directory to scaffold into or inspect
18
+ -y, --yes Skip prompts and use the provided inputs
19
+ -h, --help Show this help message
20
+
21
+ Examples:
22
+ npx create-quiver --name "My Project"
23
+ npx create-quiver --name "My Project" --dir ./my-project
24
+ npx create-quiver doctor --dir ./my-project
25
+ node bin/create-quiver.js doctor --dir ./my-project
26
+ `);
27
+ }
28
+
29
+ function parseArgs(argv) {
30
+ const result = {
31
+ help: false,
32
+ force: false,
33
+ mode: 'init',
34
+ projectName: '',
35
+ targetDir: '.',
36
+ };
37
+
38
+ const args = [...argv];
39
+ if (args[0] === 'doctor') {
40
+ result.mode = 'doctor';
41
+ args.shift();
42
+ }
43
+
44
+ const positional = [];
45
+
46
+ for (let index = 0; index < args.length; index += 1) {
47
+ const arg = args[index];
48
+
49
+ if (arg === '-h' || arg === '--help') {
50
+ result.help = true;
51
+ continue;
52
+ }
53
+
54
+ if (arg === '-y' || arg === '--yes') {
55
+ result.force = true;
56
+ continue;
57
+ }
58
+
59
+ if (arg === '--doctor') {
60
+ result.mode = 'doctor';
61
+ continue;
62
+ }
63
+
64
+ if (arg === '-n' || arg === '--name' || arg === '--project-name') {
65
+ const value = args[++index];
66
+ if (!value) {
67
+ throw new Error(formatError('missing value for --name'));
68
+ }
69
+ result.projectName = value;
70
+ continue;
71
+ }
72
+
73
+ if (arg === '-d' || arg === '--dir' || arg === '--target') {
74
+ const value = args[++index];
75
+ if (!value) {
76
+ throw new Error(formatError('missing value for --dir'));
77
+ }
78
+ result.targetDir = value;
79
+ continue;
80
+ }
81
+
82
+ if (arg.startsWith('-')) {
83
+ throw new Error(formatError(`unknown flag: ${arg}`));
84
+ }
85
+
86
+ positional.push(arg);
87
+ }
88
+
89
+ if (result.mode === 'init') {
90
+ if (!result.projectName && positional.length > 0) {
91
+ result.projectName = positional.shift();
92
+ }
93
+
94
+ if (positional.length > 0) {
95
+ result.targetDir = positional.shift();
96
+ }
97
+ } else {
98
+ if (positional.length > 0) {
99
+ result.targetDir = positional.shift();
100
+ }
101
+ }
102
+
103
+ if (positional.length > 0) {
104
+ throw new Error(formatError('too many positional arguments'));
105
+ }
106
+
107
+ return result;
108
+ }
109
+
110
+ function toProjectSlug(projectName) {
111
+ return projectName
112
+ .normalize('NFKD')
113
+ .replace(/[\u0300-\u036f]/g, '')
114
+ .toLowerCase()
115
+ .replace(/[^a-z0-9]+/g, '-')
116
+ .replace(/^-+|-+$/g, '') || 'quiver-project';
117
+ }
118
+
119
+ function runCommand(command, args, options = {}) {
120
+ return execFileSync(command, args, {
121
+ encoding: 'utf8',
122
+ stdio: ['ignore', 'pipe', 'inherit'],
123
+ ...options,
124
+ });
125
+ }
126
+
127
+ function packTemplate(packageRoot, tempRoot) {
128
+ const packDir = path.join(tempRoot, 'pack');
129
+ const extractDir = path.join(tempRoot, 'extract');
130
+ const npmCache = path.join(tempRoot, 'npm-cache');
131
+
132
+ fs.mkdirSync(packDir, { recursive: true });
133
+ fs.mkdirSync(extractDir, { recursive: true });
134
+ fs.mkdirSync(npmCache, { recursive: true });
135
+
136
+ const packOutput = runCommand('npm', ['pack', '--json', '--pack-destination', packDir], {
137
+ cwd: packageRoot,
138
+ env: {
139
+ ...process.env,
140
+ npm_config_cache: npmCache,
141
+ },
142
+ });
143
+
144
+ const packInfo = JSON.parse(packOutput.trim());
145
+ const tarballPath = path.join(packDir, packInfo[0].filename);
146
+
147
+ if (!fs.existsSync(tarballPath)) {
148
+ throw new Error(formatError(`pack output not found at ${tarballPath}`));
149
+ }
150
+
151
+ runCommand('tar', ['-xzf', tarballPath, '-C', extractDir]);
152
+
153
+ return path.join(extractDir, 'package');
154
+ }
155
+
156
+ function ensureDir(dirPath) {
157
+ fs.mkdirSync(dirPath, { recursive: true });
158
+ }
159
+
160
+ function copyTemplate(templateRoot, targetDir) {
161
+ const docsTemplateDir = path.join(targetDir, 'docs-template');
162
+
163
+ if (fs.existsSync(docsTemplateDir)) {
164
+ throw new Error(formatError(`docs-template already exists at ${docsTemplateDir}`));
165
+ }
166
+
167
+ fs.cpSync(templateRoot, docsTemplateDir, { recursive: true });
168
+
169
+ return docsTemplateDir;
170
+ }
171
+
172
+ function runInitDocs(repoRoot, projectName) {
173
+ runCommand('bash', ['docs-template/scripts/init-docs.sh', projectName], {
174
+ cwd: repoRoot,
175
+ });
176
+ }
177
+
178
+ function listGeneratedSpecDirs(projectRoot) {
179
+ const specsDir = path.join(projectRoot, 'specs');
180
+
181
+ if (!fs.existsSync(specsDir)) {
182
+ return [];
183
+ }
184
+
185
+ return fs.readdirSync(specsDir, { withFileTypes: true })
186
+ .filter((entry) => entry.isDirectory())
187
+ .map((entry) => entry.name)
188
+ .filter((entry) => entry !== '[project-name]' && !entry.startsWith('quiver-'));
189
+ }
190
+
191
+ function assertFilesExist(root, relativePaths) {
192
+ return relativePaths.filter((relativePath) => !fs.existsSync(path.join(root, relativePath)));
193
+ }
194
+
195
+ function assertExecutablesExist(root, relativePaths) {
196
+ return relativePaths.filter((relativePath) => {
197
+ const absolutePath = path.join(root, relativePath);
198
+
199
+ if (!fs.existsSync(absolutePath)) {
200
+ return true;
201
+ }
202
+
203
+ const mode = fs.statSync(absolutePath).mode;
204
+ return (mode & 0o111) === 0;
205
+ });
206
+ }
207
+
208
+ function loadPackageJson(projectRoot) {
209
+ const packageJsonPath = path.join(projectRoot, 'package.json');
210
+
211
+ if (!fs.existsSync(packageJsonPath)) {
212
+ throw new Error(formatError(`missing package.json in ${projectRoot}`));
213
+ }
214
+
215
+ return JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
216
+ }
217
+
218
+ function runDoctor(targetDir) {
219
+ const projectRoot = path.resolve(process.cwd(), targetDir);
220
+
221
+ if (!fs.existsSync(projectRoot)) {
222
+ throw new Error(formatError(`target directory does not exist: ${projectRoot}`));
223
+ }
224
+
225
+ const generatedSpecs = listGeneratedSpecDirs(projectRoot);
226
+ if (generatedSpecs.length !== 1) {
227
+ throw new Error(formatError(`expected exactly one generated spec directory, found ${generatedSpecs.length || 0}`));
228
+ }
229
+
230
+ const projectSlug = generatedSpecs[0];
231
+ const requiredFiles = [
232
+ 'README.md',
233
+ 'docs/INDEX.md',
234
+ 'docs/CONTEXTO.md',
235
+ 'docs/WORKFLOW.md',
236
+ 'docs/SUPPORT_MATRIX.md',
237
+ 'docs/TROUBLESHOOTING.md',
238
+ 'docs/TESTING_GUIDE_FOR_AI.md',
239
+ 'docs/ai/PRINCIPLES.md',
240
+ 'docs/ai/RULES.yaml',
241
+ 'docs/ai/LESSONS.md',
242
+ `specs/${projectSlug}/SPEC.md`,
243
+ `specs/${projectSlug}/STATUS.md`,
244
+ `specs/${projectSlug}/EVIDENCE_REPORT.md`,
245
+ 'package.json',
246
+ '.github/pull_request_template.md',
247
+ '.github/ISSUE_TEMPLATE/bug_report.md',
248
+ '.github/ISSUE_TEMPLATE/feature_request.md',
249
+ '.github/workflows/ci.yml',
250
+ ];
251
+
252
+ const requiredExecutables = [
253
+ 'tools/scripts/start-slice.sh',
254
+ 'tools/scripts/check-slice-readiness.sh',
255
+ 'tools/scripts/check-pr-readiness.sh',
256
+ 'tools/scripts/cleanup-slice.sh',
257
+ 'tools/scripts/check-scope.sh',
258
+ ];
259
+
260
+ const missingFiles = assertFilesExist(projectRoot, requiredFiles);
261
+ const nonExecutableScripts = assertExecutablesExist(projectRoot, requiredExecutables);
262
+ const pkg = loadPackageJson(projectRoot);
263
+ const requiredScripts = ['check:slice', 'check:pr', 'start:slice', 'cleanup:slice'];
264
+ const missingScripts = requiredScripts.filter((name) => typeof pkg.scripts?.[name] !== 'string');
265
+
266
+ const problems = [
267
+ ...missingFiles.map((file) => `missing file: ${file}`),
268
+ ...nonExecutableScripts.map((file) => `missing executable bit: ${file}`),
269
+ ...missingScripts.map((name) => `missing package.json script: ${name}`),
270
+ ];
271
+
272
+ if (problems.length > 0) {
273
+ throw new Error(formatError(`doctor failed:\n- ${problems.join('\n- ')}`));
274
+ }
275
+
276
+ console.log(`Quiver doctor passed for ${projectRoot}`);
277
+ console.log(`Generated project slug: ${projectSlug}`);
278
+ console.log('Next steps:');
279
+ console.log(`- Run ${path.join(projectRoot, 'tools', 'scripts', 'start-slice.sh')} ${path.join(projectRoot, 'specs', projectSlug, 'slices', 'slice-template', 'slice.json')}`);
280
+ console.log(`- Validate a slice with ${path.join(projectRoot, 'tools', 'scripts', 'check-slice-readiness.sh')}`);
281
+ console.log(`- Validate the PR gate with ${path.join(projectRoot, 'tools', 'scripts', 'check-pr-readiness.sh')}`);
282
+ }
283
+
284
+ function printInitNextSteps(targetDir, projectName) {
285
+ const projectSlug = toProjectSlug(projectName);
286
+
287
+ console.log('');
288
+ console.log('Next steps:');
289
+ console.log(`- Review ${path.join(targetDir, 'docs', 'INDEX.md')}`);
290
+ console.log(`- Review ${path.join(targetDir, 'docs', 'WORKFLOW.md')}`);
291
+ console.log(`- Create your first slice from ${path.join(targetDir, 'specs', projectSlug, 'slices', 'slice-template', 'slice.json')}`);
292
+ console.log(`- Launch slice work with ${path.join(targetDir, 'tools', 'scripts', 'start-slice.sh')}`);
293
+ }
294
+
295
+ async function run(argv) {
296
+ const args = parseArgs(argv);
297
+
298
+ if (args.help) {
299
+ printUsage();
300
+ return;
301
+ }
302
+
303
+ if (args.mode === 'doctor') {
304
+ runDoctor(args.targetDir);
305
+ return;
306
+ }
307
+
308
+ const packageRoot = path.resolve(__dirname, '../..');
309
+ const targetDir = path.resolve(process.cwd(), args.targetDir);
310
+ const projectName = args.projectName || path.basename(targetDir) || 'Quiver Project';
311
+ const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'quiver-create-'));
312
+
313
+ try {
314
+ ensureDir(targetDir);
315
+
316
+ const templateRoot = packTemplate(packageRoot, tempRoot);
317
+ copyTemplate(templateRoot, targetDir);
318
+ runInitDocs(targetDir, projectName);
319
+
320
+ console.log(`Installed Quiver into ${targetDir}`);
321
+ printInitNextSteps(targetDir, projectName);
322
+ } finally {
323
+ fs.rmSync(tempRoot, { recursive: true, force: true });
324
+ }
325
+ }
326
+
327
+ module.exports = {
328
+ run,
329
+ };