create-quiver 0.8.0 → 0.9.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/.claude/settings.local.json +8 -1
- package/CHANGELOG.md +7 -0
- package/package.json +1 -1
- package/specs/quiver-v19-self-install-dev-dep/EVIDENCE_REPORT.md +19 -0
- package/specs/quiver-v19-self-install-dev-dep/SPEC.md +51 -0
- package/specs/quiver-v19-self-install-dev-dep/STATUS.md +20 -0
- package/specs/quiver-v19-self-install-dev-dep/slices/slice-01-auto-install-dev-dep/CLOSURE_BRIEF.md +29 -0
- package/specs/quiver-v19-self-install-dev-dep/slices/slice-01-auto-install-dev-dep/EXECUTION_BRIEF.md +287 -0
- package/specs/quiver-v19-self-install-dev-dep/slices/slice-01-auto-install-dev-dep/slice.json +56 -0
- package/src/create-quiver/index.js +24 -1
- package/src/create-quiver/lib/init-docs.js +37 -0
|
@@ -39,7 +39,14 @@
|
|
|
39
39
|
"Bash(NPM_TOKEN=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 npm publish --access public)",
|
|
40
40
|
"Bash(NPM_TOKEN=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 npm publish --access public)",
|
|
41
41
|
"Bash(npm info *)",
|
|
42
|
-
"Bash(npm publish *)"
|
|
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 *)"
|
|
43
50
|
]
|
|
44
51
|
}
|
|
45
52
|
}
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.9.0] - 2026-05-14
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Auto-install `create-quiver` as a dev dependency after `init` and `migrate` — detects yarn/pnpm/bun/npm via lockfiles and runs the appropriate install command
|
|
12
|
+
- `--skip-install` flag to suppress the dev dependency install step (useful for CI environments)
|
|
13
|
+
|
|
7
14
|
## [0.8.0] - 2026-05-13
|
|
8
15
|
|
|
9
16
|
### Added
|
package/package.json
CHANGED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Quiver v19 — Evidence Report
|
|
2
|
+
|
|
3
|
+
**Spec:** quiver-v19-self-install-dev-dep
|
|
4
|
+
**Date:** 2026-05-14
|
|
5
|
+
**Status:** In Progress
|
|
6
|
+
|
|
7
|
+
## Slice Evidence
|
|
8
|
+
|
|
9
|
+
| Slice | Status | Evidence |
|
|
10
|
+
|-------|--------|----------|
|
|
11
|
+
| slice-01 | Ready | — |
|
|
12
|
+
|
|
13
|
+
## Required Final Evidence
|
|
14
|
+
|
|
15
|
+
- `npx create-quiver --name "test-project" --dir /tmp/test-project` → `cat /tmp/test-project/package.json | grep create-quiver` returns a devDependency entry
|
|
16
|
+
- `ls /tmp/test-project/node_modules/create-quiver` → directory exists
|
|
17
|
+
- `npx create-quiver plan` inside `/tmp/test-project` → exits 0 without `@version`
|
|
18
|
+
- `npx create-quiver --skip-install --name "ci-project" --dir /tmp/ci-project` → no `node_modules/create-quiver`
|
|
19
|
+
- `node --test tests/**/*.test.js` → all pass
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Quiver v19 — Self-Install as Dev Dependency
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-05-14
|
|
4
|
+
**Status:** Active
|
|
5
|
+
|
|
6
|
+
Slice numbering resets here. This spec starts at `slice-01`.
|
|
7
|
+
|
|
8
|
+
## Problem
|
|
9
|
+
|
|
10
|
+
`npx create-quiver` uses the global npx cache. After init, commands like `quiver:plan`, `quiver:graph`, and `quiver:next` in the target project may silently run the cached version instead of the latest — or fail entirely if the version in cache predates those commands. The user has no `create-quiver` in their `node_modules` unless they install it manually.
|
|
11
|
+
|
|
12
|
+
## Objective
|
|
13
|
+
|
|
14
|
+
After `npx create-quiver --name "foo"` (init) or `npx create-quiver migrate`, the target project's `package.json` has `create-quiver` in `devDependencies` and it is installed in `node_modules`. Subsequent `npx create-quiver` invocations in that project resolve to the local version — no cache issues, reproducible across machines.
|
|
15
|
+
|
|
16
|
+
## Scope
|
|
17
|
+
|
|
18
|
+
### Included
|
|
19
|
+
|
|
20
|
+
- Detect the package manager in use (yarn, pnpm, bun, npm) by checking lockfiles
|
|
21
|
+
- Run the appropriate install command (`npm install -D`, `yarn add -D`, `pnpm add -D`, `bun add -d`) with the exact running version
|
|
22
|
+
- Skip if `create-quiver` is already present in `devDependencies`
|
|
23
|
+
- Skip gracefully if no `package.json` exists in the target project
|
|
24
|
+
- Add `--skip-install` flag to the CLI for CI environments
|
|
25
|
+
- Apply to both `init` and `migrate` flows
|
|
26
|
+
- Tests for `detectPackageManager` and `installSelfAsDevDep`
|
|
27
|
+
|
|
28
|
+
### Excluded
|
|
29
|
+
|
|
30
|
+
- Changing any other part of the init/migrate scaffold output
|
|
31
|
+
- Supporting non-standard registries or private npm configurations
|
|
32
|
+
- Auto-updating an existing create-quiver devDependency to a newer version
|
|
33
|
+
|
|
34
|
+
## Acceptance Criteria
|
|
35
|
+
|
|
36
|
+
1. After init, `cat package.json | jq .devDependencies` shows `"create-quiver": "^X.Y.Z"`
|
|
37
|
+
2. `node_modules/create-quiver` exists in the target project after init
|
|
38
|
+
3. `npx create-quiver plan` (no `@version`) works immediately after init
|
|
39
|
+
4. If target project has no `package.json` → no crash, warning printed, init continues
|
|
40
|
+
5. If `create-quiver` already in `devDependencies` → step skipped, no duplicate install
|
|
41
|
+
6. `npx create-quiver --skip-install --name "foo"` → installs Quiver docs but skips npm install
|
|
42
|
+
7. `npx create-quiver migrate --skip-install` → same skip behavior
|
|
43
|
+
8. yarn/pnpm/bun projects get the right install command
|
|
44
|
+
9. If install fails (no network, etc.) → warning printed, init completes without crashing
|
|
45
|
+
10. `node --test tests/**/*.test.js` passes
|
|
46
|
+
|
|
47
|
+
## Slices
|
|
48
|
+
|
|
49
|
+
| Slice | Title | Status |
|
|
50
|
+
|-------|-------|--------|
|
|
51
|
+
| slice-01 | Auto-install create-quiver as dev dependency | Ready |
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Quiver v19 — Status
|
|
2
|
+
|
|
3
|
+
**Spec:** quiver-v19-self-install-dev-dep
|
|
4
|
+
**Last updated:** 2026-05-14
|
|
5
|
+
|
|
6
|
+
## Status
|
|
7
|
+
|
|
8
|
+
| Slice | Title | Status | PR | Estimated hours | Actual hours |
|
|
9
|
+
|-------|-------|--------|----|-----------------|--------------|
|
|
10
|
+
| slice-01 | Auto-install create-quiver as dev dependency | Ready | — | 1.5 | — |
|
|
11
|
+
|
|
12
|
+
## Progress
|
|
13
|
+
|
|
14
|
+
- Completed slices: 0 / 1
|
|
15
|
+
- Estimated hours: 1.5
|
|
16
|
+
- Actual hours: —
|
|
17
|
+
|
|
18
|
+
## Blockers
|
|
19
|
+
|
|
20
|
+
None.
|
package/specs/quiver-v19-self-install-dev-dep/slices/slice-01-auto-install-dev-dep/CLOSURE_BRIEF.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# CLOSURE BRIEF — slice-01: Auto-install create-quiver as dev dependency
|
|
2
|
+
|
|
3
|
+
**Spec:** quiver-v19-self-install-dev-dep
|
|
4
|
+
**Slice:** slice-01-auto-install-dev-dep
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Checklist antes de abrir el PR
|
|
9
|
+
|
|
10
|
+
- [ ] `node --test tests/**/*.test.js` → exit 0, todos los tests pasan incluyendo los 7 nuevos en `init-docs.test.js`
|
|
11
|
+
- [ ] Smoke con `--skip-install` → `node_modules/create-quiver` NO existe en el proyecto destino
|
|
12
|
+
- [ ] Smoke sin `--skip-install` → `node_modules/create-quiver` SÍ existe y `npx create-quiver plan` funciona sin `@version`
|
|
13
|
+
- [ ] Smoke con `devDependencies` preexistente → el step se saltea, no hay doble install
|
|
14
|
+
- [ ] `git diff --stat HEAD` muestra exactamente 3 archivos: `src/create-quiver/lib/init-docs.js`, `src/create-quiver/index.js`, `tests/lib/init-docs.test.js`
|
|
15
|
+
|
|
16
|
+
## Checklist del PR
|
|
17
|
+
|
|
18
|
+
- [ ] Branch: `feature/QUIVER-01-auto-install-dev-dep` → `main`
|
|
19
|
+
- [ ] Título: `feat(QUIVER-01): auto-install create-quiver as dev dependency after init`
|
|
20
|
+
- [ ] Body sigue las secciones del `docs/GITFLOW_PR_GUIDE.md.template`
|
|
21
|
+
- [ ] En "Evidence": output del smoke test mostrando `node_modules/create-quiver` creado y `npx create-quiver plan` funcionando
|
|
22
|
+
- [ ] En "Risks / Notes": mencionar que en entornos sin red el install falla silenciosamente (expected behavior) y documentar el `--skip-install` flag
|
|
23
|
+
|
|
24
|
+
## Post-merge
|
|
25
|
+
|
|
26
|
+
- [ ] Actualizar `specs/quiver-v19-self-install-dev-dep/STATUS.md`: slice-01 → `Completed`, agregar PR y `actual_hours`
|
|
27
|
+
- [ ] Actualizar `specs/quiver-v19-self-install-dev-dep/EVIDENCE_REPORT.md`: registrar evidencia
|
|
28
|
+
- [ ] Actualizar `slice.json`: `status: completed`, `actual_hours`, timestamps
|
|
29
|
+
- [ ] Evaluar si se publica `0.9.0` o si se acumula con otros cambios
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
# EXECUTION BRIEF — slice-01: Auto-install create-quiver as dev dependency
|
|
2
|
+
|
|
3
|
+
**Spec:** quiver-v19-self-install-dev-dep
|
|
4
|
+
**Slice:** slice-01-auto-install-dev-dep
|
|
5
|
+
**Branch:** `feature/QUIVER-01-auto-install-dev-dep` from `main`
|
|
6
|
+
**Estimated time:** 1.5h
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Contexto
|
|
11
|
+
|
|
12
|
+
`npx create-quiver` no instala el paquete en `node_modules` del proyecto destino. Después del init, comandos como `quiver:plan` fallan o usan la versión cacheada globalmente. La solución es correr el package manager del proyecto destino para instalar `create-quiver` como dev dependency inmediatamente después del init/migrate.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Archivos a modificar
|
|
17
|
+
|
|
18
|
+
1. `src/create-quiver/lib/init-docs.js` — agregar `detectPackageManager` e `installSelfAsDevDep`
|
|
19
|
+
2. `src/create-quiver/index.js` — agregar `--skip-install` al parser, llamar a `installSelfAsDevDep` en init y migrate
|
|
20
|
+
3. `tests/lib/init-docs.test.js` — nuevo archivo de tests
|
|
21
|
+
|
|
22
|
+
No toques ningún otro archivo.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Parte A — `src/create-quiver/lib/init-docs.js`
|
|
27
|
+
|
|
28
|
+
### Paso 1: Agregar import de `execSync`
|
|
29
|
+
|
|
30
|
+
Al inicio del archivo, después de los requires existentes (`fs`, `path`, `writeState`), agregar:
|
|
31
|
+
|
|
32
|
+
```js
|
|
33
|
+
const { execSync } = require('child_process');
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Paso 2: Agregar las dos funciones nuevas
|
|
37
|
+
|
|
38
|
+
Agregar antes del `module.exports` al final del archivo:
|
|
39
|
+
|
|
40
|
+
```js
|
|
41
|
+
function detectPackageManager(projectRoot) {
|
|
42
|
+
if (fs.existsSync(path.join(projectRoot, 'bun.lockb'))) return 'bun';
|
|
43
|
+
if (fs.existsSync(path.join(projectRoot, 'pnpm-lock.yaml'))) return 'pnpm';
|
|
44
|
+
if (fs.existsSync(path.join(projectRoot, 'yarn.lock'))) return 'yarn';
|
|
45
|
+
return 'npm';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function installSelfAsDevDep(projectRoot, version) {
|
|
49
|
+
const packageJsonPath = path.join(projectRoot, 'package.json');
|
|
50
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
51
|
+
return 'skipped-no-package-json';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
55
|
+
if (pkg.devDependencies && pkg.devDependencies['create-quiver']) {
|
|
56
|
+
return 'skipped-already-present';
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const pm = detectPackageManager(projectRoot);
|
|
60
|
+
const commands = {
|
|
61
|
+
npm: `npm install -D create-quiver@${version}`,
|
|
62
|
+
yarn: `yarn add -D create-quiver@${version}`,
|
|
63
|
+
pnpm: `pnpm add -D create-quiver@${version}`,
|
|
64
|
+
bun: `bun add -d create-quiver@${version}`,
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
execSync(commands[pm], { cwd: projectRoot, stdio: 'inherit' });
|
|
69
|
+
return 'installed';
|
|
70
|
+
} catch {
|
|
71
|
+
return 'failed';
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Paso 3: Exportar las funciones nuevas
|
|
77
|
+
|
|
78
|
+
Encontrá el `module.exports` actual y agregá las dos funciones nuevas:
|
|
79
|
+
|
|
80
|
+
```js
|
|
81
|
+
module.exports = {
|
|
82
|
+
// ... exports existentes ...
|
|
83
|
+
detectPackageManager,
|
|
84
|
+
installSelfAsDevDep,
|
|
85
|
+
};
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Parte B — `src/create-quiver/index.js`
|
|
91
|
+
|
|
92
|
+
### Paso 1: Importar `installSelfAsDevDep`
|
|
93
|
+
|
|
94
|
+
En la línea 10 donde se importa `runInitDocs`, extender el destructuring para incluir la función nueva:
|
|
95
|
+
|
|
96
|
+
```js
|
|
97
|
+
// Antes (aproximado):
|
|
98
|
+
const { runInitDocs } = require('./lib/init-docs');
|
|
99
|
+
|
|
100
|
+
// Después:
|
|
101
|
+
const { runInitDocs, installSelfAsDevDep } = require('./lib/init-docs');
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Paso 2: Agregar `--skip-install` al parser de args
|
|
105
|
+
|
|
106
|
+
Dentro de la función `parseArgs`, en el bloque donde se manejan los flags (el loop que analiza `arg`), agregar el caso nuevo junto a los otros flags booleanos (`--yes`, etc.):
|
|
107
|
+
|
|
108
|
+
```js
|
|
109
|
+
if (arg === '--skip-install') {
|
|
110
|
+
result.skipInstall = true;
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Paso 3: Llamar a `installSelfAsDevDep` en el flujo de init
|
|
116
|
+
|
|
117
|
+
El flujo init en index.js (cerca de la línea 1416) actualmente es:
|
|
118
|
+
|
|
119
|
+
```js
|
|
120
|
+
runInitDocs(targetDir, projectName);
|
|
121
|
+
console.log(`Installed Quiver into ${targetDir}`);
|
|
122
|
+
printInitNextSteps(targetDir, projectName);
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Reemplazarlo por:
|
|
126
|
+
|
|
127
|
+
```js
|
|
128
|
+
runInitDocs(targetDir, projectName);
|
|
129
|
+
|
|
130
|
+
if (!args.skipInstall) {
|
|
131
|
+
const installResult = installSelfAsDevDep(targetDir, CLI_VERSION);
|
|
132
|
+
if (installResult === 'installed') {
|
|
133
|
+
console.log(`Added create-quiver@${CLI_VERSION} as dev dependency`);
|
|
134
|
+
} else if (installResult === 'failed') {
|
|
135
|
+
console.warn(`Warning: could not install create-quiver automatically. Run: npm install -D create-quiver@${CLI_VERSION}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
console.log(`Installed Quiver into ${targetDir}`);
|
|
140
|
+
printInitNextSteps(targetDir, projectName);
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Nota: `CLI_VERSION` ya existe en `index.js` — no lo reimportes.
|
|
144
|
+
|
|
145
|
+
### Paso 4: Llamar a `installSelfAsDevDep` en el flujo de migrate
|
|
146
|
+
|
|
147
|
+
Buscá el flujo de migrate en index.js (buscar `runInitDocs` con `migrateMode: true` o similar). Aplicar el mismo patrón después del call de init/migrate.
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## Parte C — `tests/lib/init-docs.test.js` (archivo nuevo)
|
|
152
|
+
|
|
153
|
+
Crear este archivo con el patrón del repo (`node:test`, `node:assert/strict`):
|
|
154
|
+
|
|
155
|
+
```js
|
|
156
|
+
const assert = require('node:assert/strict');
|
|
157
|
+
const fs = require('node:fs');
|
|
158
|
+
const os = require('node:os');
|
|
159
|
+
const path = require('node:path');
|
|
160
|
+
const test = require('node:test');
|
|
161
|
+
|
|
162
|
+
const { detectPackageManager, installSelfAsDevDep } = require('../../src/create-quiver/lib/init-docs');
|
|
163
|
+
|
|
164
|
+
function makeTmpDir() {
|
|
165
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'quiver-init-test-'));
|
|
166
|
+
return { dir, cleanup: () => fs.rmSync(dir, { recursive: true, force: true }) };
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
test('detectPackageManager returns npm when no lockfile exists', () => {
|
|
170
|
+
const { dir, cleanup } = makeTmpDir();
|
|
171
|
+
try {
|
|
172
|
+
assert.equal(detectPackageManager(dir), 'npm');
|
|
173
|
+
} finally {
|
|
174
|
+
cleanup();
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test('detectPackageManager returns yarn when yarn.lock exists', () => {
|
|
179
|
+
const { dir, cleanup } = makeTmpDir();
|
|
180
|
+
try {
|
|
181
|
+
fs.writeFileSync(path.join(dir, 'yarn.lock'), '');
|
|
182
|
+
assert.equal(detectPackageManager(dir), 'yarn');
|
|
183
|
+
} finally {
|
|
184
|
+
cleanup();
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
test('detectPackageManager returns pnpm when pnpm-lock.yaml exists', () => {
|
|
189
|
+
const { dir, cleanup } = makeTmpDir();
|
|
190
|
+
try {
|
|
191
|
+
fs.writeFileSync(path.join(dir, 'pnpm-lock.yaml'), '');
|
|
192
|
+
assert.equal(detectPackageManager(dir), 'pnpm');
|
|
193
|
+
} finally {
|
|
194
|
+
cleanup();
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
test('detectPackageManager returns bun when bun.lockb exists', () => {
|
|
199
|
+
const { dir, cleanup } = makeTmpDir();
|
|
200
|
+
try {
|
|
201
|
+
fs.writeFileSync(path.join(dir, 'bun.lockb'), '');
|
|
202
|
+
assert.equal(detectPackageManager(dir), 'bun');
|
|
203
|
+
} finally {
|
|
204
|
+
cleanup();
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
test('installSelfAsDevDep returns skipped-no-package-json when no package.json', () => {
|
|
209
|
+
const { dir, cleanup } = makeTmpDir();
|
|
210
|
+
try {
|
|
211
|
+
const result = installSelfAsDevDep(dir, '0.8.0');
|
|
212
|
+
assert.equal(result, 'skipped-no-package-json');
|
|
213
|
+
} finally {
|
|
214
|
+
cleanup();
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
test('installSelfAsDevDep returns skipped-already-present when create-quiver in devDeps', () => {
|
|
219
|
+
const { dir, cleanup } = makeTmpDir();
|
|
220
|
+
try {
|
|
221
|
+
fs.writeFileSync(path.join(dir, 'package.json'), JSON.stringify({
|
|
222
|
+
name: 'test',
|
|
223
|
+
devDependencies: { 'create-quiver': '^0.7.0' },
|
|
224
|
+
}));
|
|
225
|
+
const result = installSelfAsDevDep(dir, '0.8.0');
|
|
226
|
+
assert.equal(result, 'skipped-already-present');
|
|
227
|
+
} finally {
|
|
228
|
+
cleanup();
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
test('installSelfAsDevDep returns failed when install command fails', () => {
|
|
233
|
+
const { dir, cleanup } = makeTmpDir();
|
|
234
|
+
try {
|
|
235
|
+
fs.writeFileSync(path.join(dir, 'package.json'), JSON.stringify({ name: 'test' }));
|
|
236
|
+
// Force failure: set PATH to empty so no package manager can be found
|
|
237
|
+
const original = process.env.PATH;
|
|
238
|
+
process.env.PATH = '';
|
|
239
|
+
const result = installSelfAsDevDep(dir, '0.8.0');
|
|
240
|
+
process.env.PATH = original;
|
|
241
|
+
assert.equal(result, 'failed');
|
|
242
|
+
} finally {
|
|
243
|
+
cleanup();
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## Verificaciones
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
# Tests
|
|
254
|
+
node --test tests/**/*.test.js
|
|
255
|
+
|
|
256
|
+
# Smoke: --skip-install no instala
|
|
257
|
+
mkdir -p /tmp/quiver-skip-test && echo '{"name":"test","scripts":{}}' > /tmp/quiver-skip-test/package.json
|
|
258
|
+
node bin/create-quiver.js --skip-install --name test --dir /tmp/quiver-skip-test
|
|
259
|
+
ls /tmp/quiver-skip-test/node_modules/create-quiver 2>/dev/null && echo "FAIL: se instaló igual" || echo "OK: no instaló"
|
|
260
|
+
|
|
261
|
+
# Smoke: sin --skip-install sí instala (requiere red)
|
|
262
|
+
mkdir -p /tmp/quiver-install-test && echo '{"name":"test","scripts":{}}' > /tmp/quiver-install-test/package.json
|
|
263
|
+
node bin/create-quiver.js --name test --dir /tmp/quiver-install-test
|
|
264
|
+
ls /tmp/quiver-install-test/node_modules/create-quiver && echo "OK: instalado" || echo "FAIL"
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## Restricciones
|
|
270
|
+
|
|
271
|
+
- No toques `mergePackageJson` — la lógica de install va en `installSelfAsDevDep`, no en el merge de package.json
|
|
272
|
+
- No hagas `npm install` general — solo `npm install -D create-quiver@VERSION`
|
|
273
|
+
- No elimines ni renombres ningún export existente de `init-docs.js`
|
|
274
|
+
- No agregues dependencias externas — solo `child_process` (built-in de Node)
|
|
275
|
+
- Un solo commit con los tres archivos
|
|
276
|
+
|
|
277
|
+
## Mensaje de commit sugerido
|
|
278
|
+
|
|
279
|
+
```
|
|
280
|
+
feat(QUIVER-01): auto-install create-quiver as dev dependency after init
|
|
281
|
+
|
|
282
|
+
After init or migrate, detect the target project's package manager
|
|
283
|
+
(yarn/pnpm/bun/npm) and install create-quiver as a dev dependency.
|
|
284
|
+
Skippable with --skip-install for CI environments.
|
|
285
|
+
Resolves the npx cache issue: subsequent quiver commands in the project
|
|
286
|
+
resolve to the local version without requiring @version suffix.
|
|
287
|
+
```
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"slice_id": "slice-01-auto-install-dev-dep",
|
|
3
|
+
"ticket": "QUIVER-01",
|
|
4
|
+
"type": "feature",
|
|
5
|
+
"title": "Auto-install create-quiver as dev dependency after init/migrate",
|
|
6
|
+
"objective": "After `npx create-quiver` init or migrate, the target project has create-quiver in devDependencies and installed in node_modules. Uses the correct package manager. Skippable via --skip-install.",
|
|
7
|
+
"description": "Add two functions to init-docs.js: detectPackageManager (checks lockfiles) and installSelfAsDevDep (runs the appropriate install command). Call installSelfAsDevDep from the init and migrate flows in index.js after runInitDocs. Add --skip-install flag to the CLI arg parser.",
|
|
8
|
+
"git": {
|
|
9
|
+
"branch_type": "feature",
|
|
10
|
+
"base_branch": "main",
|
|
11
|
+
"branch_slug": "auto-install-dev-dep",
|
|
12
|
+
"branch_name": "feature/QUIVER-01-auto-install-dev-dep"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"src/create-quiver/lib/init-docs.js",
|
|
16
|
+
"src/create-quiver/index.js",
|
|
17
|
+
"tests/lib/init-docs.test.js"
|
|
18
|
+
],
|
|
19
|
+
"depends_on": [],
|
|
20
|
+
"must": [
|
|
21
|
+
"detectPackageManager(projectRoot) returns 'bun'|'pnpm'|'yarn'|'npm' based on lockfile presence",
|
|
22
|
+
"installSelfAsDevDep(projectRoot, version) runs the correct install command for the detected pm",
|
|
23
|
+
"installSelfAsDevDep skips if no package.json exists (returns 'skipped-no-package-json')",
|
|
24
|
+
"installSelfAsDevDep skips if create-quiver already in devDependencies (returns 'skipped-already-present')",
|
|
25
|
+
"installSelfAsDevDep catches install errors and returns 'failed' without throwing",
|
|
26
|
+
"--skip-install flag parsed in index.js and passed through to suppress the install step",
|
|
27
|
+
"Both init and migrate flows call installSelfAsDevDep unless --skip-install is set",
|
|
28
|
+
"Init output prints 'Added create-quiver@X.Y.Z as dev dependency' on success or a warning on skip/fail",
|
|
29
|
+
"node --test tests/**/*.test.js passes"
|
|
30
|
+
],
|
|
31
|
+
"not_included": [
|
|
32
|
+
"Auto-updating an existing create-quiver version in devDependencies",
|
|
33
|
+
"Supporting private registries or custom npm configs",
|
|
34
|
+
"Changing the scaffold output beyond the install step message"
|
|
35
|
+
],
|
|
36
|
+
"acceptance": [
|
|
37
|
+
"After init: package.json has create-quiver in devDependencies",
|
|
38
|
+
"After init: node_modules/create-quiver exists",
|
|
39
|
+
"npx create-quiver plan works without @version in a freshly initialized project",
|
|
40
|
+
"--skip-install suppresses the install in both init and migrate",
|
|
41
|
+
"yarn/pnpm/bun projects use the right install command",
|
|
42
|
+
"Install failure prints a warning but does not crash the init",
|
|
43
|
+
"node --test tests/**/*.test.js exits 0"
|
|
44
|
+
],
|
|
45
|
+
"tests": [
|
|
46
|
+
"node --test tests/**/*.test.js",
|
|
47
|
+
"npx create-quiver --skip-install --name test --dir /tmp/quiver-test-skip && ls /tmp/quiver-test-skip/node_modules/create-quiver 2>/dev/null && echo FAIL || echo OK"
|
|
48
|
+
],
|
|
49
|
+
"estimated_hours": 1.5,
|
|
50
|
+
"actual_hours": null,
|
|
51
|
+
"status": "ready",
|
|
52
|
+
"blocked_reason": null,
|
|
53
|
+
"ready_at": "2026-05-14T00:00:00Z",
|
|
54
|
+
"started_at": null,
|
|
55
|
+
"completed_at": null
|
|
56
|
+
}
|
|
@@ -7,7 +7,7 @@ const { collectDoctorWarnings } = require('./lib/doctor');
|
|
|
7
7
|
const { runGraph } = require('./commands/graph');
|
|
8
8
|
const { runNext } = require('./commands/next');
|
|
9
9
|
const { runPlan } = require('./commands/plan');
|
|
10
|
-
const { initializeProjectDocs } = require('./lib/init-docs');
|
|
10
|
+
const { initializeProjectDocs, installSelfAsDevDep } = require('./lib/init-docs');
|
|
11
11
|
const { checkPrReadiness, checkScope, checkSliceReadiness } = require('./lib/readiness');
|
|
12
12
|
const { cleanupSlice, refreshActiveSlicesBoard, startSlice } = require('./lib/lifecycle');
|
|
13
13
|
const { relativePosixPath, resolveTargetRoot } = require('./lib/paths');
|
|
@@ -144,6 +144,11 @@ function parseArgs(argv) {
|
|
|
144
144
|
continue;
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
+
if (arg === '--skip-install') {
|
|
148
|
+
result.skipInstall = true;
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
|
|
147
152
|
if (arg === '--doctor') {
|
|
148
153
|
result.mode = 'doctor';
|
|
149
154
|
continue;
|
|
@@ -1160,6 +1165,15 @@ function runMigrate(targetDir) {
|
|
|
1160
1165
|
});
|
|
1161
1166
|
updateStateForMigrate(projectRoot, projectName, CLI_VERSION);
|
|
1162
1167
|
|
|
1168
|
+
if (!args.skipInstall) {
|
|
1169
|
+
const installResult = installSelfAsDevDep(projectRoot, CLI_VERSION);
|
|
1170
|
+
if (installResult === 'installed') {
|
|
1171
|
+
console.log(`Added create-quiver@${CLI_VERSION} as dev dependency`);
|
|
1172
|
+
} else if (installResult === 'failed') {
|
|
1173
|
+
console.warn(`Warning: could not install create-quiver automatically. Run: npm install -D create-quiver@${CLI_VERSION}`);
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1163
1177
|
console.log(`Quiver migration completed for ${projectRoot}`);
|
|
1164
1178
|
console.log('Missing workflow files were restored without overwriting existing project files.');
|
|
1165
1179
|
} finally {
|
|
@@ -1415,6 +1429,15 @@ async function run(argv) {
|
|
|
1415
1429
|
copyTemplate(templateRoot, targetDir);
|
|
1416
1430
|
runInitDocs(targetDir, projectName);
|
|
1417
1431
|
|
|
1432
|
+
if (!args.skipInstall) {
|
|
1433
|
+
const installResult = installSelfAsDevDep(targetDir, CLI_VERSION);
|
|
1434
|
+
if (installResult === 'installed') {
|
|
1435
|
+
console.log(`Added create-quiver@${CLI_VERSION} as dev dependency`);
|
|
1436
|
+
} else if (installResult === 'failed') {
|
|
1437
|
+
console.warn(`Warning: could not install create-quiver automatically. Run: npm install -D create-quiver@${CLI_VERSION}`);
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1418
1441
|
console.log(`Installed Quiver into ${targetDir}`);
|
|
1419
1442
|
printInitNextSteps(targetDir, projectName);
|
|
1420
1443
|
} finally {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
+
const { execSync } = require('child_process');
|
|
3
4
|
const { writeState } = require('./state');
|
|
4
5
|
|
|
5
6
|
function ensureDir(dirPath) {
|
|
@@ -667,8 +668,44 @@ function initializeProjectDocs(options) {
|
|
|
667
668
|
};
|
|
668
669
|
}
|
|
669
670
|
|
|
671
|
+
function detectPackageManager(projectRoot) {
|
|
672
|
+
if (fs.existsSync(path.join(projectRoot, 'bun.lockb'))) return 'bun';
|
|
673
|
+
if (fs.existsSync(path.join(projectRoot, 'pnpm-lock.yaml'))) return 'pnpm';
|
|
674
|
+
if (fs.existsSync(path.join(projectRoot, 'yarn.lock'))) return 'yarn';
|
|
675
|
+
return 'npm';
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
function installSelfAsDevDep(projectRoot, version) {
|
|
679
|
+
const packageJsonPath = path.join(projectRoot, 'package.json');
|
|
680
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
681
|
+
return 'skipped-no-package-json';
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
685
|
+
if (pkg.devDependencies && pkg.devDependencies['create-quiver']) {
|
|
686
|
+
return 'skipped-already-present';
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
const pm = detectPackageManager(projectRoot);
|
|
690
|
+
const commands = {
|
|
691
|
+
npm: `npm install -D create-quiver@${version}`,
|
|
692
|
+
yarn: `yarn add -D create-quiver@${version}`,
|
|
693
|
+
pnpm: `pnpm add -D create-quiver@${version}`,
|
|
694
|
+
bun: `bun add -d create-quiver@${version}`,
|
|
695
|
+
};
|
|
696
|
+
|
|
697
|
+
try {
|
|
698
|
+
execSync(commands[pm], { cwd: projectRoot, stdio: 'inherit' });
|
|
699
|
+
return 'installed';
|
|
700
|
+
} catch {
|
|
701
|
+
return 'failed';
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
670
705
|
module.exports = {
|
|
671
706
|
initializeProjectDocs,
|
|
672
707
|
writeFrontMatter,
|
|
673
708
|
toProjectSlug,
|
|
709
|
+
detectPackageManager,
|
|
710
|
+
installSelfAsDevDep,
|
|
674
711
|
};
|