@skitterbyte/skitterspec 2.0.0 → 2.0.1
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/package.json +1 -1
- package/src/cli.js +14 -2
- package/src/env/resolve.js +16 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skitterbyte/skitterspec",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
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
|
@@ -17,7 +17,7 @@ const {
|
|
|
17
17
|
freeSlot,
|
|
18
18
|
portOffset,
|
|
19
19
|
} = require('./env/registry.js')
|
|
20
|
-
const { resolveSpec, resolveBaseBranch } = require('./env/resolve.js')
|
|
20
|
+
const { resolveSpec, resolveBaseBranch, repoInfo, expandTokens, splitPrefix } = require('./env/resolve.js')
|
|
21
21
|
const { ensureWorktreeDirTrusted } = require('./env/trust.js')
|
|
22
22
|
const { planUp } = require('./env/provision.js')
|
|
23
23
|
const { planDown } = require('./env/teardown.js')
|
|
@@ -332,7 +332,19 @@ function specEnvIntegrate(dir, config, specArg) {
|
|
|
332
332
|
const commonDir = gitReader(dir)(['rev-parse', '--git-common-dir'])
|
|
333
333
|
const mainRepoPath = commonDir ? path.dirname(path.resolve(dir, commonDir)) : dir
|
|
334
334
|
|
|
335
|
-
|
|
335
|
+
// A spec authored entirely on its branch may not exist in the primary
|
|
336
|
+
// checkout's specs/** (it was never committed to base) — but its worktree
|
|
337
|
+
// does, and the worktree path is derivable from config without the folder.
|
|
338
|
+
// Offer it as a fallback search location so integrate can still find the spec.
|
|
339
|
+
const { slug } = splitPrefix(path.basename(specArg))
|
|
340
|
+
const { repo, repoSlug } = repoInfo(mainRepoPath)
|
|
341
|
+
const wtTokens = { repo, repoSlug, slug }
|
|
342
|
+
const worktreeGuess = path.resolve(
|
|
343
|
+
mainRepoPath,
|
|
344
|
+
expandTokens(config.worktree.root, wtTokens),
|
|
345
|
+
expandTokens(config.worktree.folderPattern, wtTokens),
|
|
346
|
+
)
|
|
347
|
+
const spec = resolveSpec(specArg, mainRepoPath, config, { searchDirs: [worktreeGuess] })
|
|
336
348
|
|
|
337
349
|
if (!fs.existsSync(spec.worktreePath)) {
|
|
338
350
|
process.stdout.write(
|
package/src/env/resolve.js
CHANGED
|
@@ -20,12 +20,17 @@ const BUCKETS = ['backlog', 'in-progress', 'complete', 'cancelled']
|
|
|
20
20
|
|
|
21
21
|
// Find the spec folder under specs/<bucket>/<name>. `specArg` may be a bare
|
|
22
22
|
// folder name or a path — only its basename is matched against the buckets.
|
|
23
|
-
|
|
23
|
+
// Searches `dir` first, then any `extraDirs` in order — so a caller (e.g.
|
|
24
|
+
// `spec-env integrate`) can fall back to a worktree checkout for a spec that
|
|
25
|
+
// was authored on its branch and never committed to the primary checkout.
|
|
26
|
+
function findSpecFolder(specArg, dir, extraDirs = []) {
|
|
24
27
|
const name = path.basename(specArg)
|
|
25
|
-
for (const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
for (const root of [dir, ...extraDirs]) {
|
|
29
|
+
for (const bucket of BUCKETS) {
|
|
30
|
+
const abs = path.join(root, 'specs', bucket, name)
|
|
31
|
+
if (fs.existsSync(abs) && fs.statSync(abs).isDirectory()) {
|
|
32
|
+
return { folder: name, bucket, path: abs }
|
|
33
|
+
}
|
|
29
34
|
}
|
|
30
35
|
}
|
|
31
36
|
return null
|
|
@@ -149,9 +154,13 @@ function resolveBaseBranch(config, git) {
|
|
|
149
154
|
/**
|
|
150
155
|
* Resolve a spec argument to its identity + isolation coordinates.
|
|
151
156
|
* Throws a clear Error when the spec folder can't be found.
|
|
157
|
+
*
|
|
158
|
+
* `opts.searchDirs` adds fallback checkout roots to look under (after `dir`) when
|
|
159
|
+
* locating the spec folder; identity/coordinate tokens still expand against `dir`
|
|
160
|
+
* (the primary checkout), so a worktree-only spec resolves to the right base.
|
|
152
161
|
*/
|
|
153
|
-
function resolveSpec(specArg, dir, config) {
|
|
154
|
-
const found = findSpecFolder(specArg, dir)
|
|
162
|
+
function resolveSpec(specArg, dir, config, opts = {}) {
|
|
163
|
+
const found = findSpecFolder(specArg, dir, opts.searchDirs || [])
|
|
155
164
|
if (!found) {
|
|
156
165
|
throw new Error(`spec not found under specs/**: ${specArg}`)
|
|
157
166
|
}
|