@skitterbyte/skitterspec 14.0.3 → 15.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/README.md +1 -1
- package/assets/rules/spec-planning.md +9 -7
- package/assets/skills/spec/SKILL.md +2 -2
- package/assets/skills/spec-go/SKILL.md +4 -5
- package/package.json +1 -1
- package/src/init.js +25 -0
package/README.md
CHANGED
|
@@ -29,7 +29,7 @@ Ticketing sync is a **separate superset you install instead of this one**:
|
|
|
29
29
|
| Install | You get |
|
|
30
30
|
|---------|---------|
|
|
31
31
|
| `@skitterbyte/skitterspec` | The base filesystem workflow. No tracker. |
|
|
32
|
-
| `@skitterbyte/skitterspec-linear` | Everything here **plus** Linear
|
|
32
|
+
| `@skitterbyte/skitterspec-linear` | Everything here **plus** one-way Linear sync (`/spec-status` · `/spec-push`, the `spec-sync` CLI) — repo canonical, Linear a generated mirror. |
|
|
33
33
|
|
|
34
34
|
Install exactly one — the superset is a strict superset of this package.
|
|
35
35
|
|
|
@@ -68,13 +68,15 @@ Beneath it, `skitterspec spec-env live <take|release|abort|status>` is the engin
|
|
|
68
68
|
tracker-free: it knows nothing about any specific ticketing system. A
|
|
69
69
|
ticketing provider is installed as its own distribution that plugs into two named
|
|
70
70
|
**seams** in the shared skills (`/spec` Phase E, `/spec-go` step 3b) and fulfils a
|
|
71
|
-
skill-name + CLI contract
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
71
|
+
skill-name + CLI contract. Sync is **one-way**: the repo is the source of truth
|
|
72
|
+
and the tracker is a **generated mirror**. It ships `/spec-push` (repo→tracker;
|
|
73
|
+
computes a create/update plan against a committed last-pushed snapshot and applies
|
|
74
|
+
it) and `/spec-status` (read-only drift report — what would push, and whether the
|
|
75
|
+
tracker's workflow-state drifted), backed by a `spec-sync` CLI. There is no
|
|
76
|
+
content pull — the tracker is never read back or merged. When a provider is
|
|
77
|
+
present, `/spec` also links the spec to the tracker. With no provider installed
|
|
78
|
+
the seams are empty and every skill behaves as a plain filesystem workflow. See
|
|
79
|
+
the provider package's own docs for its config and field reference.
|
|
78
80
|
|
|
79
81
|
## Project conventions (fill this in)
|
|
80
82
|
|
|
@@ -217,11 +217,11 @@ finish as above.
|
|
|
217
217
|
## Phase E — link to a ticketing provider (only if one is installed)
|
|
218
218
|
|
|
219
219
|
**Only when a ticketing provider is installed and configured** (it ships the
|
|
220
|
-
`/spec-push` · `/spec-
|
|
220
|
+
`/spec-push` · `/spec-status` skills and a provider config under
|
|
221
221
|
`specs/.core/`). If none is present, skip this phase entirely — the spec stays
|
|
222
222
|
local-only and `/spec` behaves exactly as above. When a provider is present, link
|
|
223
223
|
the spec to the tracker after writing it, so status and discussion live there
|
|
224
|
-
while the repo stays the
|
|
224
|
+
while the repo stays the source of truth — follow the provider's link steps
|
|
225
225
|
below (nothing to do here without one).
|
|
226
226
|
|
|
227
227
|
|
|
@@ -129,12 +129,11 @@ Before writing any code for this phase, get the workspace clean:
|
|
|
129
129
|
next phase on top of an uncommitted one. (Skip if this is the first phase —
|
|
130
130
|
there's nothing prior to commit.)
|
|
131
131
|
|
|
132
|
-
## 3b.
|
|
132
|
+
## 3b. Sync with the tracker (only if a provider is installed)
|
|
133
133
|
|
|
134
|
-
**Only when a ticketing provider
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
here without one).
|
|
134
|
+
**Only when a ticketing provider is installed** and the spec is linked to the
|
|
135
|
+
tracker. Otherwise skip this step — no provider means zero change to the flow
|
|
136
|
+
below. Follow the provider's steps below (nothing to do here without one).
|
|
138
137
|
|
|
139
138
|
|
|
140
139
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skitterbyte/skitterspec",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "15.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/init.js
CHANGED
|
@@ -259,6 +259,30 @@ function removeRetiredFiles(dir) {
|
|
|
259
259
|
}
|
|
260
260
|
}
|
|
261
261
|
|
|
262
|
+
// Prune a file the manifest records as managed but the current package no longer
|
|
263
|
+
// ships — a retired skill (e.g. `spec-pull` after the one-way switch), rule, or
|
|
264
|
+
// template. Without this, upgrading leaves a live, model-visible skill on disk
|
|
265
|
+
// whose instructions invoke a command that no longer exists. Delete it only when
|
|
266
|
+
// PRISTINE (still matches the hash we last wrote) so a user edit is never lost; a
|
|
267
|
+
// customized retired file is kept with a warning. An emptied skill folder is
|
|
268
|
+
// removed. Takes the pre-flush manifest (which still holds the retired entries).
|
|
269
|
+
function pruneRetiredManaged(dir, manifest) {
|
|
270
|
+
const managedRel = new Set(managedTargets(dir).map((t) => t.relPath))
|
|
271
|
+
for (const relPath of Object.keys(manifest.files || {})) {
|
|
272
|
+
if (managedRel.has(relPath)) continue // still shipped by this version
|
|
273
|
+
const abs = path.join(dir, relPath)
|
|
274
|
+
if (!fs.existsSync(abs)) continue // already gone
|
|
275
|
+
if (managedState(dir, relPath, manifest) === 'customized') {
|
|
276
|
+
report.warnings.push(`retired but kept (you edited it): ${relPath} — delete manually if unused`)
|
|
277
|
+
continue
|
|
278
|
+
}
|
|
279
|
+
fs.unlinkSync(abs)
|
|
280
|
+
report.removed.push(rel(dir, abs))
|
|
281
|
+
const folder = path.dirname(abs)
|
|
282
|
+
if (fs.existsSync(folder) && !fs.readdirSync(folder).length) fs.rmdirSync(folder)
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
262
286
|
// Scaffold the opt-in isolation templates into specs/.core/ (the example config
|
|
263
287
|
// + its field docs). Copied, not activated: the feature stays off until the
|
|
264
288
|
// consumer copies env.config.json.example → env.config.json.
|
|
@@ -409,6 +433,7 @@ function resync(dir, { force = false, claudeMd = true } = {}) {
|
|
|
409
433
|
for (const t of managedTargets(dir)) resyncManagedFile(dir, t, manifest, force)
|
|
410
434
|
installFolders(dir)
|
|
411
435
|
removeRetiredFiles(dir)
|
|
436
|
+
pruneRetiredManaged(dir, manifest)
|
|
412
437
|
if (claudeMd) installClaudeMd(dir, { mode: 'update' })
|
|
413
438
|
flushManifest(dir)
|
|
414
439
|
printReport(dir, 'resync')
|