@skitterbyte/skitterspec 3.0.0 → 7.0.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.
|
@@ -52,6 +52,16 @@ no live `env.config.json` was found.
|
|
|
52
52
|
// empty = no backup, volumes dropped directly.
|
|
53
53
|
},
|
|
54
54
|
|
|
55
|
+
// Bootstrap commands `spec-env up <spec>` runs IN the worktree, right after
|
|
56
|
+
// `git worktree add` (before Docker/dev), on every provision including
|
|
57
|
+
// re-attach — so a fresh worktree's dependencies exist and git hooks,
|
|
58
|
+
// typechecks, builds and tests work immediately instead of failing on a
|
|
59
|
+
// missing node_modules. An array, run in order; [] = none. Each string is a
|
|
60
|
+
// shell command; {slug}/{branch}/{worktreePath}/{projectName}/{portOffset}
|
|
61
|
+
// expand (the cwd is already the worktree, so {worktreePath} is usually
|
|
62
|
+
// redundant). Example: ["pnpm install --frozen-lockfile"].
|
|
63
|
+
"setup": [],
|
|
64
|
+
|
|
55
65
|
// Host dev servers `spec-env dev up <spec>` starts on the spec's port block
|
|
56
66
|
// (for apps that run via `pnpm dev` on the host, not inside the Docker stack).
|
|
57
67
|
// An array so UI + API (or more) are supervised independently; [] = none.
|
|
@@ -30,6 +30,13 @@ housekeeping below lands on the spec's branch and never on `main`:
|
|
|
30
30
|
worktree on a branch forked from `main`, and — only when the spec's
|
|
31
31
|
`> **Stack:**` header is `worktree + docker` — also brings up its Docker stack.
|
|
32
32
|
Print the worktree path and the opener command it emits.
|
|
33
|
+
- **Bootstrap the worktree's dependencies.** A fresh worktree has an empty
|
|
34
|
+
working tree — no installed dependencies — so git hooks, typechecks, builds and
|
|
35
|
+
tests fail until they're installed. `spec-env up` prints the project's
|
|
36
|
+
configured **`in the worktree, run:`** commands (from `env.config.json` →
|
|
37
|
+
`setup`, e.g. an install command) — run them in the worktree before doing
|
|
38
|
+
anything else. With no `setup` configured there's nothing to run; set one up if
|
|
39
|
+
agents keep stalling on missing dependencies.
|
|
33
40
|
- **Trust the worktree for this session.** The engine wrote the printed
|
|
34
41
|
`trusted:` root into `.claude/settings.local.json` (gitignored) so future
|
|
35
42
|
sessions trust it automatically — but that file likely won't hot-reload now,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skitterbyte/skitterspec",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0",
|
|
4
4
|
"description": "Spec-driven development for Claude Code — a tracker-free filesystem workflow: lifecycle skills and per-spec isolation. For Linear sync, install @skitterbyte/skitterspec-linear instead.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude",
|
package/src/cli.js
CHANGED
|
@@ -205,6 +205,11 @@ function specEnvUp(dir, config, specArg) {
|
|
|
205
205
|
out.push(' run these:')
|
|
206
206
|
for (const cmd of plan.commands) out.push(` ${cmd}`)
|
|
207
207
|
if (plan.openCommand) out.push(` ${plan.openCommand}`)
|
|
208
|
+
if (plan.setupCommands.length) {
|
|
209
|
+
out.push('')
|
|
210
|
+
out.push(' in the worktree, run:')
|
|
211
|
+
for (const cmd of plan.setupCommands) out.push(` ${cmd}`)
|
|
212
|
+
}
|
|
208
213
|
if (plan.envContents) {
|
|
209
214
|
out.push('')
|
|
210
215
|
out.push(` write ${config.docker.envFile} in the worktree:`)
|
package/src/env/config.js
CHANGED
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
* worktree: { root, folderPattern },
|
|
17
17
|
* docker: { enabled, composeFile, projectNamePattern, portBase,
|
|
18
18
|
* portsPerSpec, envFile, backupCommand },
|
|
19
|
+
* setup: [ "cmd", ... ], // bootstrap commands run in the worktree right
|
|
20
|
+
* // after `git worktree add` (e.g. install deps); empty = none
|
|
19
21
|
* dev: [ { name, command, portVar, health?, frontPort? } ], // host dev
|
|
20
22
|
* // servers started on the spec's port block (empty = none)
|
|
21
23
|
* proxy: { enabled, host }, // bundled front-door proxy (spec-env connect)
|
|
@@ -43,6 +45,10 @@ const DEFAULT_CONFIG = Object.freeze({
|
|
|
43
45
|
envFile: '.env',
|
|
44
46
|
backupCommand: '',
|
|
45
47
|
}),
|
|
48
|
+
// Bootstrap commands run in the worktree by `spec-env up`, right after
|
|
49
|
+
// `git worktree add` (before Docker/dev), on every provision. Array of shell
|
|
50
|
+
// strings (e.g. "pnpm install"); {slug}/{branch}/… expand. Default: none.
|
|
51
|
+
setup: Object.freeze([]),
|
|
46
52
|
// Host dev servers started on the spec's port block by `spec-env dev up`.
|
|
47
53
|
// Each: { name, command, portVar, health?, frontPort? }. Default: none.
|
|
48
54
|
dev: Object.freeze([]),
|
|
@@ -70,6 +76,7 @@ function defaults() {
|
|
|
70
76
|
return {
|
|
71
77
|
worktree: { ...DEFAULT_CONFIG.worktree },
|
|
72
78
|
docker: { ...DEFAULT_CONFIG.docker },
|
|
79
|
+
setup: [],
|
|
73
80
|
dev: [],
|
|
74
81
|
proxy: { ...DEFAULT_CONFIG.proxy },
|
|
75
82
|
open: { ...DEFAULT_CONFIG.open },
|
|
@@ -120,6 +127,21 @@ function normalizeDev(parsed) {
|
|
|
120
127
|
return out
|
|
121
128
|
}
|
|
122
129
|
|
|
130
|
+
/**
|
|
131
|
+
* Normalise a parsed `setup` array into bootstrap commands: keep only trimmed,
|
|
132
|
+
* non-empty strings, drop everything else (lenient, like `normalizeDev`) so a
|
|
133
|
+
* stray entry can't crash provisioning.
|
|
134
|
+
*/
|
|
135
|
+
function normalizeSetup(parsed) {
|
|
136
|
+
const out = []
|
|
137
|
+
for (const raw of parsed) {
|
|
138
|
+
if (typeof raw !== 'string') continue
|
|
139
|
+
const cmd = raw.trim()
|
|
140
|
+
if (cmd) out.push(cmd)
|
|
141
|
+
}
|
|
142
|
+
return out
|
|
143
|
+
}
|
|
144
|
+
|
|
123
145
|
/**
|
|
124
146
|
* Merge a parsed config over the defaults. Only known keys are copied (unknown
|
|
125
147
|
* keys ignored for forward-compat). Nested objects are merged field-by-field.
|
|
@@ -142,6 +164,10 @@ function mergeConfig(base, parsed) {
|
|
|
142
164
|
assign(base.docker, parsed.docker, 'backupCommand', 'string?')
|
|
143
165
|
}
|
|
144
166
|
|
|
167
|
+
if (Array.isArray(parsed.setup)) {
|
|
168
|
+
base.setup = normalizeSetup(parsed.setup)
|
|
169
|
+
}
|
|
170
|
+
|
|
145
171
|
if (Array.isArray(parsed.dev)) {
|
|
146
172
|
base.dev = normalizeDev(parsed.dev)
|
|
147
173
|
}
|
package/src/env/provision.js
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
const { portOffset } = require('./registry.js')
|
|
15
15
|
const { renderEnvFile, expandOpenCommand } = require('./render.js')
|
|
16
|
+
const { expandTokens } = require('./resolve.js')
|
|
16
17
|
|
|
17
18
|
/**
|
|
18
19
|
* Plan a provisioning run.
|
|
@@ -23,7 +24,8 @@ const { renderEnvFile, expandOpenCommand } = require('./render.js')
|
|
|
23
24
|
* existed in the registry (re-run → attach, don't clobber).
|
|
24
25
|
* @param {object} config normalised env config.
|
|
25
26
|
* @returns {object} { worktreePath, branch, projectName, slot, portOffset,
|
|
26
|
-
* envContents, openCommand, commands,
|
|
27
|
+
* envContents, openCommand, commands, setupCommands,
|
|
28
|
+
* attached }
|
|
27
29
|
*/
|
|
28
30
|
function planUp(spec, alloc, config) {
|
|
29
31
|
const { slot, attached } = alloc
|
|
@@ -41,13 +43,21 @@ function planUp(spec, alloc, config) {
|
|
|
41
43
|
? renderEnvFile({ projectName: spec.projectName, portOffset: offset })
|
|
42
44
|
: null
|
|
43
45
|
|
|
44
|
-
const
|
|
46
|
+
const tokens = {
|
|
45
47
|
worktreePath: spec.worktreePath,
|
|
46
48
|
slug: spec.slug,
|
|
47
49
|
branch: spec.branch,
|
|
48
50
|
projectName: spec.projectName,
|
|
49
51
|
portOffset: offset === null ? '' : String(offset),
|
|
50
|
-
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const openCommand = expandOpenCommand(config.open.command, tokens)
|
|
55
|
+
|
|
56
|
+
// Bootstrap commands run *in the worktree* after `git worktree add` (before
|
|
57
|
+
// Docker/dev), on every provision including re-attach — deps must exist for
|
|
58
|
+
// the worktree to be usable. Kept separate from `commands` (run from the
|
|
59
|
+
// primary checkout root); the CLI prints them under an "in the worktree" head.
|
|
60
|
+
const setupCommands = (config.setup || []).map((cmd) => expandTokens(cmd, tokens))
|
|
51
61
|
|
|
52
62
|
const commands = []
|
|
53
63
|
// Fresh branch → -b; attach an existing branch/slot → plain form (never clobber).
|
|
@@ -69,6 +79,7 @@ function planUp(spec, alloc, config) {
|
|
|
69
79
|
envContents,
|
|
70
80
|
openCommand,
|
|
71
81
|
commands,
|
|
82
|
+
setupCommands,
|
|
72
83
|
attached,
|
|
73
84
|
}
|
|
74
85
|
}
|