create-quiver 0.6.0 → 0.7.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/.github/workflows/ci.yml +7 -30
- package/AGENTS.md.template +41 -0
- package/CHANGELOG.md +5 -0
- package/README.md +37 -13
- package/README_FOR_AI.md +27 -7
- package/ROADMAP.md +78 -0
- package/docs/AI_CONTEXT.md.template +19 -26
- package/docs/AI_ONBOARDING_PROMPT.md.template +12 -0
- package/docs/CONTEXTO.md.template +4 -17
- package/docs/DECISIONS.md.template +18 -0
- package/docs/DEEP.md.template +34 -0
- package/docs/DOCUMENTATION_GUIDE.md.template +9 -7
- package/docs/GITFLOW_PR_GUIDE.md.template +7 -0
- package/docs/INDEX.md.template +9 -0
- package/docs/QUICK.md.template +27 -0
- package/docs/STANDARD.md.template +49 -0
- package/docs/STATUS.md.template +2 -2
- package/docs/SUPPORT_MATRIX.md.template +7 -4
- package/docs/TESTING_GUIDE_FOR_AI.md.template +4 -3
- package/docs/TROUBLESHOOTING.md.template +14 -0
- package/docs/WORKFLOW.md.template +17 -4
- package/package.json +2 -1
- package/package.template.json +11 -0
- package/scripts/cleanup-slice.sh +2 -172
- package/scripts/init-docs.sh +97 -24
- package/scripts/package-quiver.sh +5 -0
- package/scripts/start-slice.sh +3 -425
- package/specs/[project-name]/EVIDENCE_REPORT.md.template +3 -1
- package/specs/[project-name]/slices/slice-template/slice.json +2 -2
- package/specs/quiver-v12-cross-platform-native-runtime/EVIDENCE_REPORT.md +30 -0
- package/specs/quiver-v12-cross-platform-native-runtime/SPEC.md +86 -0
- package/specs/quiver-v12-cross-platform-native-runtime/STATUS.md +29 -0
- package/specs/quiver-v12-cross-platform-native-runtime/slices/slice-01-cross-platform-support-contract/slice.json +69 -0
- package/specs/quiver-v12-cross-platform-native-runtime/slices/slice-02-node-init-docs-runtime/slice.json +76 -0
- package/specs/quiver-v12-cross-platform-native-runtime/slices/slice-03-node-migrate-analyze-doctor-flow/slice.json +74 -0
- package/specs/quiver-v12-cross-platform-native-runtime/slices/slice-04-node-slice-lifecycle-commands/slice.json +81 -0
- package/specs/quiver-v12-cross-platform-native-runtime/slices/slice-05-generated-project-scripts-and-migration/slice.json +78 -0
- package/specs/quiver-v12-cross-platform-native-runtime/slices/slice-06-cross-platform-ci-release-readiness/slice.json +74 -0
- package/specs/quiver-v13-token-efficient-ai-context/EVIDENCE_REPORT.md +28 -0
- package/specs/quiver-v13-token-efficient-ai-context/SPEC.md +68 -0
- package/specs/quiver-v13-token-efficient-ai-context/STATUS.md +26 -0
- package/specs/quiver-v13-token-efficient-ai-context/slices/slice-01-token-efficient-ai-modes-guidance/slice.json +65 -0
- package/specs/quiver-v13-token-efficient-ai-context/slices/slice-02-decision-log-context-checkpoint/slice.json +64 -0
- package/specs/quiver-v13-token-efficient-ai-context/slices/slice-03-project-map-reading-order/slice.json +66 -0
- package/specs/quiver-v14-tiered-context-pack/EVIDENCE_REPORT.md +42 -0
- package/specs/quiver-v14-tiered-context-pack/SPEC.md +116 -0
- package/specs/quiver-v14-tiered-context-pack/STATUS.md +35 -0
- package/specs/quiver-v14-tiered-context-pack/slices/slice-01-tiered-context-pack/slice.json +77 -0
- package/specs/quiver-v14-tiered-context-pack/slices/slice-02-agents-md-router/slice.json +74 -0
- package/specs/quiver-v14-tiered-context-pack/slices/slice-03-active-slice-lifecycle/slice.json +74 -0
- package/specs/quiver-v14-tiered-context-pack/slices/slice-04-dedup-frontmatter/slice.json +83 -0
- package/specs/quiver-v14-tiered-context-pack/slices/slice-05-doctor-smokes-tiered-pack/slice.json +84 -0
- package/src/create-quiver/index.js +299 -123
- package/src/create-quiver/lib/analyze.js +9 -0
- package/src/create-quiver/lib/doctor.js +212 -0
- package/src/create-quiver/lib/git.js +154 -0
- package/src/create-quiver/lib/init-docs.js +616 -0
- package/src/create-quiver/lib/lifecycle.js +478 -0
- package/src/create-quiver/lib/paths.js +19 -0
- package/src/create-quiver/lib/readiness.js +300 -0
- package/src/create-quiver/lib/scope.js +5 -0
- package/src/create-quiver/lib/slice.js +194 -0
- package/src/create-quiver/lib/state.js +89 -0
package/scripts/start-slice.sh
CHANGED
|
@@ -2,428 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
set -euo pipefail
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
bash tools/scripts/start-slice.sh [--allow-draft] <ruta-al-slice.json>
|
|
9
|
-
|
|
10
|
-
Lee la metadata git del slice, valida la rama declarada y crea un worktree
|
|
11
|
-
afuera de la raiz trackeada del repo.
|
|
12
|
-
|
|
13
|
-
Variables opcionales:
|
|
14
|
-
SLICE_WORKTREES_DIR Directorio base para los worktrees.
|
|
15
|
-
Default: <repo-parent>/.worktrees/<repo-name>
|
|
16
|
-
--allow-draft Permite bootstraps intencionales de slices en draft.
|
|
17
|
-
EOF
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
append_unique_line() {
|
|
21
|
-
local file_path="$1"
|
|
22
|
-
local line="$2"
|
|
23
|
-
|
|
24
|
-
mkdir -p "$(dirname "$file_path")"
|
|
25
|
-
touch "$file_path"
|
|
26
|
-
|
|
27
|
-
if ! grep -Fxq "$line" "$file_path"; then
|
|
28
|
-
printf '%s\n' "$line" >> "$file_path"
|
|
29
|
-
fi
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
ensure_local_exclude() {
|
|
33
|
-
local workdir="$1"
|
|
34
|
-
local pattern="$2"
|
|
35
|
-
local exclude_path
|
|
36
|
-
local git_dir
|
|
37
|
-
|
|
38
|
-
git_dir="$(git -C "$workdir" rev-parse --absolute-git-dir)"
|
|
39
|
-
exclude_path="$git_dir/info/exclude"
|
|
40
|
-
append_unique_line "$exclude_path" "$pattern"
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
canonicalize_dir() {
|
|
44
|
-
local dir_path="$1"
|
|
45
|
-
(cd "$dir_path" && pwd -P)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
resolve_base_ref() {
|
|
49
|
-
local base_branch="$1"
|
|
50
|
-
|
|
51
|
-
if git show-ref --verify --quiet "refs/heads/$base_branch"; then
|
|
52
|
-
printf '%s\n' "$base_branch"
|
|
53
|
-
return 0
|
|
54
|
-
fi
|
|
55
|
-
|
|
56
|
-
if git show-ref --verify --quiet "refs/remotes/origin/$base_branch"; then
|
|
57
|
-
printf '%s\n' "origin/$base_branch"
|
|
58
|
-
return 0
|
|
59
|
-
fi
|
|
60
|
-
|
|
61
|
-
if git ls-remote --exit-code --heads origin "$base_branch" >/dev/null 2>&1; then
|
|
62
|
-
if git fetch origin "$base_branch:refs/remotes/origin/$base_branch" >/dev/null 2>&1; then
|
|
63
|
-
printf '%s\n' "origin/$base_branch"
|
|
64
|
-
return 0
|
|
65
|
-
fi
|
|
66
|
-
|
|
67
|
-
echo "Error: origin existe pero no se pudo actualizar '$base_branch'. Revisa conectividad o crea la rama local '$base_branch' antes de correr start-slice.sh." >&2
|
|
68
|
-
return 1
|
|
69
|
-
fi
|
|
70
|
-
|
|
71
|
-
echo "Error: no se encontró '$base_branch' como rama local ni como ref remota 'origin/$base_branch'. Crea la rama base localmente o configura origin antes de correr start-slice.sh." >&2
|
|
72
|
-
return 1
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
slice_alias() {
|
|
76
|
-
node - "$1" <<'NODE'
|
|
77
|
-
const ticket = String(process.argv[2] || '').trim();
|
|
78
|
-
const parts = ticket.split('-').filter(Boolean);
|
|
79
|
-
const prefix = (parts[0] || 'GEN').replace(/[^A-Za-z0-9]/g, '').toUpperCase();
|
|
80
|
-
const suffix = (parts[parts.length - 1] || '00').replace(/[^A-Za-z0-9]/g, '').toUpperCase();
|
|
81
|
-
const short = prefix.length <= 3 ? prefix : prefix.slice(0, 3);
|
|
82
|
-
process.stdout.write(`${short || 'GEN'}-${suffix || '00'}`);
|
|
83
|
-
NODE
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
write_worktree_context() {
|
|
87
|
-
local target_worktree="$1"
|
|
88
|
-
local target_branch="$2"
|
|
89
|
-
|
|
90
|
-
if [[ "$target_worktree" != "$repo_root" ]]; then
|
|
91
|
-
ensure_local_exclude "$target_worktree" "WORKTREE_CONTEXT.md"
|
|
92
|
-
fi
|
|
93
|
-
|
|
94
|
-
node - "$slice_abs" "$target_worktree" "$target_branch" "$spec_family" "$spec_slug" <<'NODE' > "$target_worktree/WORKTREE_CONTEXT.md"
|
|
95
|
-
const fs = require('fs');
|
|
96
|
-
|
|
97
|
-
const [slicePath, worktreePath, branchName, specFamily, specSlug] = process.argv.slice(2);
|
|
98
|
-
const slice = JSON.parse(fs.readFileSync(slicePath, 'utf8'));
|
|
99
|
-
|
|
100
|
-
function toAlias(ticket) {
|
|
101
|
-
const parts = String(ticket || '').split('-').filter(Boolean);
|
|
102
|
-
const prefix = (parts[0] || 'GEN').replace(/[^A-Za-z0-9]/g, '').toUpperCase();
|
|
103
|
-
const suffix = (parts[parts.length - 1] || '00').replace(/[^A-Za-z0-9]/g, '').toUpperCase();
|
|
104
|
-
const short = prefix.length <= 3 ? prefix : prefix.slice(0, 3);
|
|
105
|
-
return `${short || 'GEN'}-${suffix || '00'}`;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function listBlock(items) {
|
|
109
|
-
if (!Array.isArray(items) || items.length === 0) {
|
|
110
|
-
return '- n/a';
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
return items.map((item) => `- ${item}`).join('\n');
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const alias = toAlias(slice.ticket);
|
|
117
|
-
const status = slice.status || 'pending';
|
|
118
|
-
const title = slice.title || slice.slice_id;
|
|
119
|
-
const objective = slice.objective || 'Sin objetivo declarado.';
|
|
120
|
-
|
|
121
|
-
const lines = [
|
|
122
|
-
'# Worktree Context',
|
|
123
|
-
'',
|
|
124
|
-
'> Archivo generado localmente por `tools/scripts/start-slice.sh`.',
|
|
125
|
-
'> No se trackea en git.',
|
|
126
|
-
'',
|
|
127
|
-
`**Alias:** ${alias}`,
|
|
128
|
-
`**Spec:** ${specSlug}`,
|
|
129
|
-
`**Spec family:** ${specFamily}`,
|
|
130
|
-
`**Slice:** ${slice.slice_id}`,
|
|
131
|
-
`**Ticket:** ${slice.ticket}`,
|
|
132
|
-
`**Branch:** ${branchName}`,
|
|
133
|
-
`**Worktree:** ${worktreePath}`,
|
|
134
|
-
`**Status:** ${status}`,
|
|
135
|
-
'',
|
|
136
|
-
'## Title',
|
|
137
|
-
'',
|
|
138
|
-
title,
|
|
139
|
-
'',
|
|
140
|
-
'## Objective',
|
|
141
|
-
'',
|
|
142
|
-
objective,
|
|
143
|
-
'',
|
|
144
|
-
'## Routes',
|
|
145
|
-
'',
|
|
146
|
-
listBlock(slice.ui_scope?.routes),
|
|
147
|
-
'',
|
|
148
|
-
'## Components',
|
|
149
|
-
'',
|
|
150
|
-
listBlock(slice.ui_scope?.components),
|
|
151
|
-
'',
|
|
152
|
-
'## Allowed Files',
|
|
153
|
-
'',
|
|
154
|
-
listBlock(slice.files),
|
|
155
|
-
'',
|
|
156
|
-
'## Constraints',
|
|
157
|
-
'',
|
|
158
|
-
listBlock(slice.not_included),
|
|
159
|
-
'',
|
|
160
|
-
'## Expected Validation',
|
|
161
|
-
'',
|
|
162
|
-
listBlock(slice.acceptance),
|
|
163
|
-
''
|
|
164
|
-
];
|
|
165
|
-
|
|
166
|
-
process.stdout.write(`${lines.join('\n')}\n`);
|
|
167
|
-
NODE
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
refresh_active_slices_board() {
|
|
171
|
-
if [[ -x "$repo_root/tools/scripts/refresh-active-slices.sh" ]]; then
|
|
172
|
-
"$repo_root/tools/scripts/refresh-active-slices.sh" >/dev/null 2>&1 || true
|
|
173
|
-
fi
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
allow_draft="0"
|
|
177
|
-
args=()
|
|
178
|
-
for arg in "$@"; do
|
|
179
|
-
case "$arg" in
|
|
180
|
-
-h|--help)
|
|
181
|
-
usage
|
|
182
|
-
exit 0
|
|
183
|
-
;;
|
|
184
|
-
--allow-draft)
|
|
185
|
-
allow_draft="1"
|
|
186
|
-
;;
|
|
187
|
-
*)
|
|
188
|
-
args+=("$arg")
|
|
189
|
-
;;
|
|
190
|
-
esac
|
|
191
|
-
done
|
|
192
|
-
|
|
193
|
-
[[ "${ALLOW_DRAFT_SLICE:-}" == "1" ]] && allow_draft="1"
|
|
194
|
-
|
|
195
|
-
if [[ ${#args[@]} -ne 1 ]]; then
|
|
196
|
-
usage
|
|
197
|
-
exit 1
|
|
198
|
-
fi
|
|
199
|
-
|
|
200
|
-
if ! command -v git >/dev/null 2>&1; then
|
|
201
|
-
echo "Error: git no esta disponible en PATH." >&2
|
|
202
|
-
exit 1
|
|
203
|
-
fi
|
|
204
|
-
|
|
205
|
-
if ! command -v node >/dev/null 2>&1; then
|
|
206
|
-
echo "Error: node no esta disponible en PATH." >&2
|
|
207
|
-
exit 1
|
|
208
|
-
fi
|
|
209
|
-
|
|
210
|
-
slice_input="${args[0]}"
|
|
211
|
-
repo_root="$(canonicalize_dir "$(git rev-parse --show-toplevel)")"
|
|
212
|
-
|
|
213
|
-
if [[ ! -f "$slice_input" ]]; then
|
|
214
|
-
echo "Error: no existe el slice '$slice_input'." >&2
|
|
215
|
-
exit 1
|
|
216
|
-
fi
|
|
217
|
-
|
|
218
|
-
slice_abs="$(canonicalize_dir "$(dirname "$slice_input")")/$(basename "$slice_input")"
|
|
219
|
-
slice_rel="${slice_abs#$repo_root/}"
|
|
220
|
-
|
|
221
|
-
case "$slice_rel" in
|
|
222
|
-
specs-fix/*/slices/*/slice.json)
|
|
223
|
-
spec_family="specs-fix"
|
|
224
|
-
spec_slug="$(printf '%s\n' "$slice_rel" | cut -d/ -f2)"
|
|
225
|
-
;;
|
|
226
|
-
specs/*/slices/*/slice.json)
|
|
227
|
-
spec_family="specs"
|
|
228
|
-
spec_slug="$(printf '%s\n' "$slice_rel" | cut -d/ -f2)"
|
|
229
|
-
;;
|
|
230
|
-
*)
|
|
231
|
-
echo "Error: el slice debe vivir dentro de specs/ o specs-fix/." >&2
|
|
232
|
-
exit 1
|
|
233
|
-
;;
|
|
234
|
-
esac
|
|
235
|
-
|
|
236
|
-
slice_meta=()
|
|
237
|
-
while IFS= read -r line; do
|
|
238
|
-
slice_meta+=("$line")
|
|
239
|
-
done < <(node - "$slice_abs" <<'NODE'
|
|
240
|
-
const fs = require('fs');
|
|
241
|
-
|
|
242
|
-
const slicePath = process.argv[2];
|
|
243
|
-
|
|
244
|
-
function fail(message) {
|
|
245
|
-
console.error(`Error: ${message}`);
|
|
246
|
-
process.exit(1);
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
let json;
|
|
250
|
-
try {
|
|
251
|
-
json = JSON.parse(fs.readFileSync(slicePath, 'utf8'));
|
|
252
|
-
} catch (error) {
|
|
253
|
-
fail(`No se pudo parsear '${slicePath}' como JSON: ${error.message}`);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
const ticket = typeof json.ticket === 'string' ? json.ticket.trim() : '';
|
|
257
|
-
const git = json.git ?? {};
|
|
258
|
-
const branchType = typeof git.branch_type === 'string' ? git.branch_type.trim() : '';
|
|
259
|
-
const baseBranch = typeof git.base_branch === 'string' ? git.base_branch.trim() : '';
|
|
260
|
-
const branchSlug = typeof git.branch_slug === 'string' ? git.branch_slug.trim() : '';
|
|
261
|
-
const branchName = typeof git.branch_name === 'string' ? git.branch_name.trim() : '';
|
|
262
|
-
const sliceId = typeof json.slice_id === 'string' ? json.slice_id.trim() : '';
|
|
263
|
-
|
|
264
|
-
if (!sliceId) {
|
|
265
|
-
fail('Falta "slice_id" en el slice.');
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
if (!ticket) {
|
|
269
|
-
fail('Falta "ticket" en el slice.');
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
if (!branchType || !baseBranch || !branchSlug || !branchName) {
|
|
273
|
-
fail('El bloque "git" debe incluir "branch_type", "base_branch", "branch_slug" y "branch_name".');
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
const expectedBaseByType = {
|
|
277
|
-
feature: 'develop',
|
|
278
|
-
bugfix: 'develop',
|
|
279
|
-
hotfix: 'main'
|
|
280
|
-
};
|
|
281
|
-
|
|
282
|
-
if (!expectedBaseByType[branchType]) {
|
|
283
|
-
fail(`git.branch_type invalido: "${branchType}". Usa "feature", "bugfix" o "hotfix".`);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
const expectedBaseBranch = expectedBaseByType[branchType];
|
|
287
|
-
if (baseBranch !== expectedBaseBranch) {
|
|
288
|
-
fail(`git.base_branch invalido para ${branchType}. Esperado: "${expectedBaseBranch}".`);
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
const expectedBranchName = `${branchType}/${ticket}-${branchSlug}`;
|
|
292
|
-
if (branchName !== expectedBranchName) {
|
|
293
|
-
fail(`git.branch_name invalido. Esperado: "${expectedBranchName}".`);
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
console.log(sliceId);
|
|
297
|
-
console.log(ticket);
|
|
298
|
-
console.log(branchType);
|
|
299
|
-
console.log(baseBranch);
|
|
300
|
-
console.log(branchSlug);
|
|
301
|
-
console.log(branchName);
|
|
302
|
-
console.log(String(json.status || 'draft'));
|
|
303
|
-
NODE
|
|
304
|
-
)
|
|
305
|
-
|
|
306
|
-
if [[ ${#slice_meta[@]} -ne 7 ]]; then
|
|
307
|
-
echo "Error: no se pudo leer la metadata git del slice." >&2
|
|
308
|
-
exit 1
|
|
309
|
-
fi
|
|
310
|
-
|
|
311
|
-
slice_id="${slice_meta[0]}"
|
|
312
|
-
ticket="${slice_meta[1]}"
|
|
313
|
-
branch_type="${slice_meta[2]}"
|
|
314
|
-
base_branch="${slice_meta[3]}"
|
|
315
|
-
branch_slug="${slice_meta[4]}"
|
|
316
|
-
branch_name="${slice_meta[5]}"
|
|
317
|
-
slice_status="${slice_meta[6]}"
|
|
318
|
-
|
|
319
|
-
if [[ "$slice_status" == "blocked" ]]; then
|
|
320
|
-
echo "Error: el slice esta bloqueado (status=blocked). Resolve el bloqueante antes de iniciar." >&2
|
|
321
|
-
exit 1
|
|
322
|
-
fi
|
|
323
|
-
|
|
324
|
-
if [[ "$slice_status" == "cancelled" ]]; then
|
|
325
|
-
echo "Error: el slice esta cancelado (status=cancelled)." >&2
|
|
326
|
-
exit 1
|
|
327
|
-
fi
|
|
328
|
-
|
|
329
|
-
if [[ "$slice_status" == "completed" ]]; then
|
|
330
|
-
echo "WARN: el slice ya figura como completed. Si realmente corresponde reejecutarlo, cambia el status a in_progress."
|
|
331
|
-
fi
|
|
332
|
-
|
|
333
|
-
if [[ "$slice_status" == "draft" && "$allow_draft" != "1" ]]; then
|
|
334
|
-
echo "Error: el slice esta en estado 'draft'. Marca el slice como 'ready' o usa --allow-draft para un bootstrap intencional." >&2
|
|
335
|
-
exit 1
|
|
336
|
-
fi
|
|
337
|
-
|
|
338
|
-
if [[ "$slice_status" == "draft" ]]; then
|
|
339
|
-
echo "WARN: bootstrap intencional para un slice en draft."
|
|
340
|
-
fi
|
|
341
|
-
|
|
342
|
-
repo_name="$(basename "$repo_root")"
|
|
343
|
-
repo_parent="$(dirname "$repo_root")"
|
|
344
|
-
worktrees_root="${SLICE_WORKTREES_DIR:-$repo_parent/.worktrees/$repo_name}"
|
|
345
|
-
safe_branch_name="$(printf '%s' "$branch_name" | sed 's#[^A-Za-z0-9._-]#-#g')"
|
|
346
|
-
worktree_path="$worktrees_root/$safe_branch_name"
|
|
347
|
-
|
|
348
|
-
git worktree prune >/dev/null 2>&1 || true
|
|
349
|
-
|
|
350
|
-
existing_worktree_path="$(
|
|
351
|
-
node - "$branch_name" <<'NODE'
|
|
352
|
-
const cp = require('child_process');
|
|
353
|
-
|
|
354
|
-
const branchRef = `refs/heads/${process.argv[2]}`;
|
|
355
|
-
const text = cp.execSync('git worktree list --porcelain', {
|
|
356
|
-
encoding: 'utf8',
|
|
357
|
-
stdio: ['ignore', 'pipe', 'pipe']
|
|
358
|
-
});
|
|
359
|
-
|
|
360
|
-
let currentPath = '';
|
|
361
|
-
for (const line of text.trim().split('\n')) {
|
|
362
|
-
if (line.startsWith('worktree ')) {
|
|
363
|
-
currentPath = line.slice('worktree '.length);
|
|
364
|
-
continue;
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
if (line === `branch ${branchRef}`) {
|
|
368
|
-
process.stdout.write(currentPath);
|
|
369
|
-
break;
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
NODE
|
|
373
|
-
)"
|
|
374
|
-
|
|
375
|
-
if [[ -n "$existing_worktree_path" && ! -d "$existing_worktree_path" ]]; then
|
|
376
|
-
existing_worktree_path=""
|
|
377
|
-
fi
|
|
378
|
-
|
|
379
|
-
if [[ -n "$existing_worktree_path" ]]; then
|
|
380
|
-
write_worktree_context "$existing_worktree_path" "$branch_name"
|
|
381
|
-
refresh_active_slices_board
|
|
382
|
-
cat <<EOF
|
|
383
|
-
La rama ya tiene un worktree asociado.
|
|
384
|
-
Alias: $(slice_alias "$ticket")
|
|
385
|
-
Spec: $spec_slug
|
|
386
|
-
Slice: $slice_id
|
|
387
|
-
Ticket: $ticket
|
|
388
|
-
Rama: $branch_name
|
|
389
|
-
Base: $base_branch
|
|
390
|
-
Worktree: $existing_worktree_path
|
|
391
|
-
EOF
|
|
392
|
-
exit 0
|
|
393
|
-
fi
|
|
394
|
-
|
|
395
|
-
if [[ -e "$worktree_path" && ! -f "$worktree_path/.git" && ! -d "$worktree_path/.git" ]]; then
|
|
396
|
-
echo "Error: la ruta '$worktree_path' ya existe y no parece un worktree git." >&2
|
|
397
|
-
exit 1
|
|
398
|
-
fi
|
|
399
|
-
|
|
400
|
-
mkdir -p "$worktrees_root"
|
|
401
|
-
|
|
402
|
-
git fetch origin --prune >/dev/null 2>&1 || true
|
|
403
|
-
|
|
404
|
-
if git show-ref --verify --quiet "refs/heads/$branch_name"; then
|
|
405
|
-
git worktree add "$worktree_path" "$branch_name"
|
|
406
|
-
elif git ls-remote --exit-code --heads origin "$branch_name" >/dev/null 2>&1; then
|
|
407
|
-
git fetch origin "$branch_name:$branch_name" >/dev/null 2>&1
|
|
408
|
-
git worktree add "$worktree_path" "$branch_name"
|
|
409
|
-
else
|
|
410
|
-
base_ref="$(resolve_base_ref "$base_branch")"
|
|
411
|
-
git worktree add -b "$branch_name" "$worktree_path" "$base_ref"
|
|
412
|
-
fi
|
|
413
|
-
|
|
414
|
-
write_worktree_context "$worktree_path" "$branch_name"
|
|
415
|
-
refresh_active_slices_board
|
|
416
|
-
|
|
417
|
-
cat <<EOF
|
|
418
|
-
Slice listo para trabajar.
|
|
419
|
-
Alias: $(slice_alias "$ticket")
|
|
420
|
-
Spec: $spec_slug
|
|
421
|
-
Slice: $slice_id
|
|
422
|
-
Ticket: $ticket
|
|
423
|
-
Tipo de rama: $branch_type
|
|
424
|
-
Base: $base_branch
|
|
425
|
-
Slug: $branch_slug
|
|
426
|
-
Rama: $branch_name
|
|
427
|
-
Worktree: $worktree_path
|
|
428
|
-
Contexto: $worktree_path/WORKTREE_CONTEXT.md
|
|
429
|
-
EOF
|
|
5
|
+
repo_root="$(git rev-parse --show-toplevel)"
|
|
6
|
+
cd "$repo_root"
|
|
7
|
+
exec npx create-quiver start-slice "$@"
|
|
@@ -12,4 +12,6 @@
|
|
|
12
12
|
|
|
13
13
|
## Evidence by Slice
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
- Prefer summarized command evidence over pasted long logs.
|
|
16
|
+
- For each command, record: command, exit code, first relevant error or success signal, and log path if one exists.
|
|
17
|
+
- Keep full logs in files or artifacts when they are too long to fit comfortably here.
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
"git": {
|
|
9
9
|
"branch_type": "feature",
|
|
10
10
|
"base_branch": "develop",
|
|
11
|
-
"branch_slug": "
|
|
12
|
-
"branch_name": "feature/ABC-123-
|
|
11
|
+
"branch_slug": "slice-template",
|
|
12
|
+
"branch_name": "feature/ABC-123-slice-template"
|
|
13
13
|
},
|
|
14
14
|
"ui_scope": {
|
|
15
15
|
"routes": [
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Quiver v0.12 Evidence Report
|
|
2
|
+
|
|
3
|
+
**Spec:** quiver-v12-cross-platform-native-runtime
|
|
4
|
+
**Date:** 2026-04-22
|
|
5
|
+
**Status:** Completed
|
|
6
|
+
|
|
7
|
+
## Summary
|
|
8
|
+
|
|
9
|
+
This spec will make Quiver native across macOS, Linux, and Windows by moving user-facing workflow commands from Bash scripts to Node.js CLI commands.
|
|
10
|
+
|
|
11
|
+
## Slice Evidence
|
|
12
|
+
|
|
13
|
+
| Slice | Status | Evidence |
|
|
14
|
+
|-------|--------|----------|
|
|
15
|
+
| slice-01 | Completed | Updated README, README_FOR_AI, support matrix template, troubleshooting template, and init-docs README generation; validated with `bash scripts/ci/smoke-init-docs.sh`, `bash scripts/ci/smoke-create-quiver.sh`, and `git diff --check` |
|
|
16
|
+
| slice-02 | Completed | Ported `init` to the Node runtime via `src/create-quiver/lib/init-docs.js`; `src/create-quiver/index.js` now calls it directly; `scripts/ci/smoke-init-docs.sh` now validates the real CLI path. Verified with `node -c src/create-quiver/index.js`, `node -c src/create-quiver/lib/init-docs.js`, `bash -n scripts/init-docs.sh scripts/ci/smoke-init-docs.sh scripts/ci/smoke-create-quiver.sh scripts/package-quiver.sh`, `bash scripts/ci/smoke-init-docs.sh`, `bash scripts/ci/smoke-create-quiver.sh`, and `bash scripts/package-quiver.sh` |
|
|
17
|
+
| slice-03 | Completed | Ported `migrate` off Bash by calling the Node init runtime with `migrateMode: true`; added shared path and state helpers in `src/create-quiver/lib/paths.js` and `src/create-quiver/lib/state.js`; updated doctor/init output to use Node-native commands; added smoke coverage for spaces and Windows-style paths in `scripts/ci/smoke-create-quiver.sh`. Verified with `node -c src/create-quiver/index.js`, `node -c src/create-quiver/lib/init-docs.js`, `node -c src/create-quiver/lib/paths.js`, `node -c src/create-quiver/lib/state.js`, `node -c src/create-quiver/lib/analyze.js`, `node -c src/create-quiver/lib/doctor.js`, `bash -n scripts/init-docs.sh scripts/ci/smoke-init-docs.sh scripts/ci/smoke-create-quiver.sh scripts/package-quiver.sh`, `bash scripts/ci/smoke-init-docs.sh`, `bash scripts/ci/smoke-create-quiver.sh`, `bash scripts/package-quiver.sh`, and `git diff --check` |
|
|
18
|
+
| slice-04 | Completed | Ported slice lifecycle and readiness gates to Node CLI commands in `src/create-quiver/lib/lifecycle.js`, `src/create-quiver/lib/readiness.js`, `src/create-quiver/lib/scope.js`, `src/create-quiver/lib/git.js`, and `src/create-quiver/lib/slice.js`; updated `src/create-quiver/index.js` to route `start-slice`, `check-slice`, `check-pr`, `cleanup-slice`, `check-scope`, and `refresh-active-slices`; updated `scripts/ci/smoke-workflow-gates.sh` to exercise the CLI directly. Verified with `node -c src/create-quiver/index.js`, `node -c src/create-quiver/lib/git.js`, `node -c src/create-quiver/lib/slice.js`, `node -c src/create-quiver/lib/lifecycle.js`, `node -c src/create-quiver/lib/readiness.js`, `node -c src/create-quiver/lib/scope.js`, `bash -n scripts/ci/smoke-workflow-gates.sh scripts/ci/smoke-create-quiver.sh scripts/ci/smoke-init-docs.sh scripts/package-quiver.sh`, `bash scripts/ci/smoke-workflow-gates.sh`, `bash scripts/ci/smoke-create-quiver.sh`, `bash scripts/package-quiver.sh`, and `git diff --check` |
|
|
19
|
+
| slice-05 | Completed | Added `quiver:*` npm scripts to generated and migrated projects, kept legacy Bash aliases for compatibility, taught `doctor` to flag projects that still need script migration, and updated smoke coverage to verify additive migration and user script preservation. Verified with `node -c src/create-quiver/index.js`, `node -c src/create-quiver/lib/init-docs.js`, `bash -n scripts/init-docs.sh scripts/ci/smoke-init-docs.sh scripts/ci/smoke-create-quiver.sh scripts/package-quiver.sh`, `bash scripts/ci/smoke-init-docs.sh`, `bash scripts/ci/smoke-create-quiver.sh`, `bash scripts/package-quiver.sh`, and `git diff --check` |
|
|
20
|
+
| slice-06 | Completed | Added a cross-platform Node smoke script at `scripts/ci/smoke-cross-platform.js` and switched `.github/workflows/ci.yml` to a Linux/macOS/Windows matrix that runs the Node smoke without Bash as the required path. Verified with `node -c src/create-quiver/index.js`, `node -c src/create-quiver/lib/init-docs.js`, `node -c scripts/ci/smoke-cross-platform.js`, `bash -n scripts/init-docs.sh scripts/ci/smoke-init-docs.sh scripts/ci/smoke-create-quiver.sh scripts/package-quiver.sh`, `bash scripts/ci/smoke-init-docs.sh`, `node scripts/ci/smoke-cross-platform.js`, `bash scripts/package-quiver.sh`, and `git diff --check` |
|
|
21
|
+
|
|
22
|
+
## Required Final Evidence
|
|
23
|
+
|
|
24
|
+
- Node syntax checks for all new runtime modules
|
|
25
|
+
- Unit or smoke coverage for path handling on Windows-style and POSIX-style paths
|
|
26
|
+
- Generated project smoke on Linux
|
|
27
|
+
- Generated project smoke on macOS
|
|
28
|
+
- Generated project smoke on Windows
|
|
29
|
+
- Package smoke proving npm wrappers invoke CLI commands correctly
|
|
30
|
+
- Documentation check proving Bash is no longer documented as the primary path
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Quiver v0.12 - Cross-Platform Native Runtime
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-04-22
|
|
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 Quiver run natively on macOS, Linux, and Windows by moving the framework runtime from Bash scripts to Node.js CLI commands.
|
|
11
|
+
|
|
12
|
+
## Scope
|
|
13
|
+
|
|
14
|
+
### Included
|
|
15
|
+
|
|
16
|
+
- Define the official cross-platform support contract for macOS, Linux, Windows PowerShell, and Windows CMD
|
|
17
|
+
- Remove Bash as a required runtime dependency for user-facing Quiver commands
|
|
18
|
+
- Port generated project initialization and migration from shell scripts to Node.js
|
|
19
|
+
- Add Node-native commands for slice lifecycle and readiness gates
|
|
20
|
+
- Update generated `package.json` scripts to call `create-quiver` directly
|
|
21
|
+
- Keep existing `.sh` scripts as legacy Unix wrappers where useful
|
|
22
|
+
- Add cross-platform CI coverage for Linux, macOS, and Windows
|
|
23
|
+
- Update docs, support matrix, troubleshooting, and generated project guidance
|
|
24
|
+
|
|
25
|
+
### Excluded
|
|
26
|
+
|
|
27
|
+
- Auto-installing Bash, Git Bash, MSYS2, or WSL
|
|
28
|
+
- Removing existing Bash wrappers in this spec
|
|
29
|
+
- Changing the one slice = one commit or one spec = one PR workflow
|
|
30
|
+
- Integrating AI provider execution into the CLI
|
|
31
|
+
- Publishing a release as part of this spec
|
|
32
|
+
|
|
33
|
+
## Target Native Flow
|
|
34
|
+
|
|
35
|
+
From any supported OS, inside the target project root:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npx create-quiver migrate
|
|
39
|
+
npx create-quiver analyze
|
|
40
|
+
npx create-quiver doctor
|
|
41
|
+
npx create-quiver start-slice specs/app/slices/slice-01/slice.json
|
|
42
|
+
npx create-quiver check-slice specs/app/slices/slice-01/slice.json
|
|
43
|
+
npx create-quiver check-pr specs/app/slices/slice-01/slice.json
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`--dir` remains available for explicit out-of-project targeting, but it is not the primary developer path.
|
|
47
|
+
|
|
48
|
+
## Support Contract
|
|
49
|
+
|
|
50
|
+
Quiver should support:
|
|
51
|
+
|
|
52
|
+
- macOS with Terminal shells
|
|
53
|
+
- Linux with standard shell environments
|
|
54
|
+
- Windows with PowerShell
|
|
55
|
+
- Windows with CMD
|
|
56
|
+
- Node.js LTS and npm
|
|
57
|
+
- Git with `worktree` support
|
|
58
|
+
|
|
59
|
+
Quiver should not require:
|
|
60
|
+
|
|
61
|
+
- Bash on Windows
|
|
62
|
+
- WSL for normal Windows usage
|
|
63
|
+
- executable bits for user-facing commands
|
|
64
|
+
- POSIX-only path behavior in generated project workflows
|
|
65
|
+
|
|
66
|
+
## Slices
|
|
67
|
+
|
|
68
|
+
| Slice | Title | Status | Spec |
|
|
69
|
+
|-------|-------|--------|------|
|
|
70
|
+
| 01 | Cross-Platform Support Contract | Completed | [slice-01](./slices/slice-01-cross-platform-support-contract/slice.json) |
|
|
71
|
+
| 02 | Node Init Docs Runtime | Completed | [slice-02](./slices/slice-02-node-init-docs-runtime/slice.json) |
|
|
72
|
+
| 03 | Node Migrate, Analyze, and Doctor Flow | Completed | [slice-03](./slices/slice-03-node-migrate-analyze-doctor-flow/slice.json) |
|
|
73
|
+
| 04 | Node Slice Lifecycle Commands | Completed | [slice-04](./slices/slice-04-node-slice-lifecycle-commands/slice.json) |
|
|
74
|
+
| 05 | Generated Project Scripts and Migration | Completed | [slice-05](./slices/slice-05-generated-project-scripts-and-migration/slice.json) |
|
|
75
|
+
| 06 | Cross-Platform CI and Release Readiness | Completed | [slice-06](./slices/slice-06-cross-platform-ci-release-readiness/slice.json) |
|
|
76
|
+
|
|
77
|
+
## Definition of Done
|
|
78
|
+
|
|
79
|
+
- New Quiver projects can be initialized without invoking Bash
|
|
80
|
+
- Existing Quiver projects can migrate without invoking Bash
|
|
81
|
+
- Analyzer and doctor work from PowerShell, CMD, macOS, and Linux
|
|
82
|
+
- Slice lifecycle commands have Node-native CLI entrypoints
|
|
83
|
+
- Generated `package.json` scripts use `create-quiver` commands instead of `bash tools/scripts/*.sh`
|
|
84
|
+
- Existing Unix wrappers still work or clearly point to the new CLI commands
|
|
85
|
+
- CI validates core workflows on `ubuntu-latest`, `macos-latest`, and `windows-latest`
|
|
86
|
+
- README and generated docs describe Windows native support accurately
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Quiver v0.12 Spec Status
|
|
2
|
+
|
|
3
|
+
**Spec:** quiver-v12-cross-platform-native-runtime
|
|
4
|
+
**Last updated:** 2026-04-22
|
|
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 | Cross-Platform Support Contract | Completed | - | 3 | 3 |
|
|
13
|
+
| slice-02 | Node Init Docs Runtime | Completed | - | 8 | 4 |
|
|
14
|
+
| slice-03 | Node Migrate, Analyze, and Doctor Flow | Completed | - | 5 | 5 |
|
|
15
|
+
| slice-04 | Node Slice Lifecycle Commands | Completed | - | 10 | 10 |
|
|
16
|
+
| slice-05 | Generated Project Scripts and Migration | Completed | - | 5 | 5 |
|
|
17
|
+
| slice-06 | Cross-Platform CI and Release Readiness | Completed | - | 5 | 5 |
|
|
18
|
+
|
|
19
|
+
## Progress
|
|
20
|
+
|
|
21
|
+
- Completed slices: 6 / 6
|
|
22
|
+
- Estimated hours: 36
|
|
23
|
+
- Actual hours: 32
|
|
24
|
+
|
|
25
|
+
## Blockers
|
|
26
|
+
|
|
27
|
+
| Slice | Blocker | Since | Action needed |
|
|
28
|
+
|-------|---------|-------|---------------|
|
|
29
|
+
| - | - | - | - |
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"slice_id": "slice-01-cross-platform-support-contract",
|
|
3
|
+
"ticket": "QUIVER-01",
|
|
4
|
+
"type": "documentation",
|
|
5
|
+
"title": "Cross-Platform Support Contract",
|
|
6
|
+
"objective": "Define the official macOS, Linux, and Windows support contract before runtime code is ported.",
|
|
7
|
+
"description": "Quiver currently documents macOS and Linux as the supported environments. This slice updates the support contract, README, generated docs, and troubleshooting language so the project has a precise target for native Windows support.",
|
|
8
|
+
"git": {
|
|
9
|
+
"branch_type": "docs",
|
|
10
|
+
"base_branch": "main",
|
|
11
|
+
"branch_slug": "cross-platform-support-contract",
|
|
12
|
+
"branch_name": "docs/QUIVER-01-cross-platform-support-contract"
|
|
13
|
+
},
|
|
14
|
+
"must": [
|
|
15
|
+
"Document macOS, Linux, Windows PowerShell, and Windows CMD as the target support matrix for the cross-platform work",
|
|
16
|
+
"State that Bash remains a legacy compatibility path, not the future required runtime",
|
|
17
|
+
"Define common requirements: Node.js LTS, npm, Git, and Git worktree support",
|
|
18
|
+
"Document that Quiver should not auto-install Bash, Git Bash, MSYS2, or WSL",
|
|
19
|
+
"Update generated support matrix and troubleshooting templates",
|
|
20
|
+
"Keep Windows marked as target support until CI proves native behavior"
|
|
21
|
+
],
|
|
22
|
+
"not_included": [
|
|
23
|
+
"Porting Bash scripts to Node",
|
|
24
|
+
"Changing generated package scripts",
|
|
25
|
+
"Adding Windows CI",
|
|
26
|
+
"Publishing a release"
|
|
27
|
+
],
|
|
28
|
+
"acceptance": [
|
|
29
|
+
"README explains the target native Windows support approach",
|
|
30
|
+
"Support matrix template includes macOS, Linux, PowerShell, and CMD expectations",
|
|
31
|
+
"Troubleshooting explains when to use WSL or Git Bash as a fallback during transition",
|
|
32
|
+
"No doc claims Windows is fully supported before runtime and CI slices are complete"
|
|
33
|
+
],
|
|
34
|
+
"files": [
|
|
35
|
+
"README.md",
|
|
36
|
+
"README_FOR_AI.md",
|
|
37
|
+
"docs/SUPPORT_MATRIX.md.template",
|
|
38
|
+
"docs/TROUBLESHOOTING.md.template",
|
|
39
|
+
"scripts/init-docs.sh",
|
|
40
|
+
"specs/quiver-v12-cross-platform-native-runtime/SPEC.md",
|
|
41
|
+
"specs/quiver-v12-cross-platform-native-runtime/STATUS.md",
|
|
42
|
+
"specs/quiver-v12-cross-platform-native-runtime/EVIDENCE_REPORT.md",
|
|
43
|
+
"specs/quiver-v12-cross-platform-native-runtime/slices/slice-01-cross-platform-support-contract/slice.json"
|
|
44
|
+
],
|
|
45
|
+
"tests": [
|
|
46
|
+
"bash scripts/ci/smoke-init-docs.sh",
|
|
47
|
+
"git diff --check"
|
|
48
|
+
],
|
|
49
|
+
"documentation": [
|
|
50
|
+
"specs/quiver-v12-cross-platform-native-runtime/SPEC.md",
|
|
51
|
+
"specs/quiver-v12-cross-platform-native-runtime/STATUS.md",
|
|
52
|
+
"specs/quiver-v12-cross-platform-native-runtime/EVIDENCE_REPORT.md"
|
|
53
|
+
],
|
|
54
|
+
"dependencies": [
|
|
55
|
+
"quiver-v11-existing-project-migration",
|
|
56
|
+
"docs/root-first-docs-flow"
|
|
57
|
+
],
|
|
58
|
+
"assumptions": [
|
|
59
|
+
"The support contract should lead implementation but avoid overstating current Windows readiness",
|
|
60
|
+
"Bash wrappers can remain documented as legacy Unix compatibility"
|
|
61
|
+
],
|
|
62
|
+
"estimated_hours": 3,
|
|
63
|
+
"actual_hours": null,
|
|
64
|
+
"status": "draft",
|
|
65
|
+
"blocked_reason": null,
|
|
66
|
+
"ready_at": null,
|
|
67
|
+
"started_at": null,
|
|
68
|
+
"completed_at": null
|
|
69
|
+
}
|