tracerkit 1.3.14 → 1.4.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 +30 -20
- package/dist/bin.js +3 -3
- package/dist/index.js +1 -1
- package/dist/uninstall-C6vhDv_T.js +116 -0
- package/package.json +1 -1
- package/templates/.claude/skills/tk:plan/SKILL.md +9 -9
- package/templates/.claude/skills/tk:prd/SKILL.md +5 -5
- package/templates/.claude/skills/tk:status/SKILL.md +3 -3
- package/templates/.claude/skills/tk:verify/SKILL.md +12 -12
- package/dist/uninstall-vX1WH11F.js +0 -86
package/README.md
CHANGED
|
@@ -63,19 +63,19 @@ The three-step workflow that takes a feature from idea to verified archive.
|
|
|
63
63
|
|
|
64
64
|
Interactive interview to define a feature. Explores the codebase, asks scoping questions one at a time, designs deep modules, and writes a structured PRD.
|
|
65
65
|
|
|
66
|
-
**Output:**
|
|
66
|
+
**Output:** `.tracerkit/prds/<slug>.md`
|
|
67
67
|
|
|
68
68
|
#### `/tk:plan <slug>` — Create an implementation plan
|
|
69
69
|
|
|
70
70
|
Reads a PRD and breaks it into phased **tracer-bullet vertical slices** — each phase is a thin but complete path through every layer (schema, service, API, UI, tests), demoable on its own.
|
|
71
71
|
|
|
72
|
-
**Output:**
|
|
72
|
+
**Output:** `.tracerkit/plans/<slug>.md`
|
|
73
73
|
|
|
74
74
|
#### `/tk:verify <slug>` — Verify and archive
|
|
75
75
|
|
|
76
|
-
Read-only review that compares the codebase against the plan's done-when conditions. Runs tests, checks user stories, and stamps a **PASS** or **NEEDS_WORK** verdict. On PASS, automatically archives the PRD and plan to
|
|
76
|
+
Read-only review that compares the codebase against the plan's done-when conditions. Runs tests, checks user stories, and stamps a **PASS** or **NEEDS_WORK** verdict. On PASS, automatically archives the PRD and plan to `.tracerkit/archives/<slug>/`.
|
|
77
77
|
|
|
78
|
-
**Output:** Verdict block in
|
|
78
|
+
**Output:** Verdict block in `.tracerkit/plans/<slug>.md` — on PASS: `.tracerkit/archives/<slug>/prd.md` + `.tracerkit/archives/<slug>/plan.md`
|
|
79
79
|
|
|
80
80
|
### Helper skills
|
|
81
81
|
|
|
@@ -83,7 +83,7 @@ Useful but optional — this category will grow over time.
|
|
|
83
83
|
|
|
84
84
|
#### `/tk:status` — Workflow dashboard
|
|
85
85
|
|
|
86
|
-
Scans
|
|
86
|
+
Scans `.tracerkit/prds/` and prints a table of all features grouped by status (`in_progress`, `created`, `done`), with age, latest verdict, and blocker/suggestion counts. Read-only — no files are modified.
|
|
87
87
|
|
|
88
88
|
## Examples
|
|
89
89
|
|
|
@@ -97,14 +97,14 @@ AI: Starting PRD interview...
|
|
|
97
97
|
? Should it detect system preference or manual toggle only?
|
|
98
98
|
? Which components need theming?
|
|
99
99
|
...
|
|
100
|
-
✓ Written prds/dark-mode-support.md
|
|
100
|
+
✓ Written .tracerkit/prds/dark-mode-support.md
|
|
101
101
|
|
|
102
102
|
You: /tk:plan dark-mode-support
|
|
103
103
|
AI: Reading PRD...
|
|
104
104
|
✓ Phase 1 — CSS variables + ThemeProvider (schema → context → tests)
|
|
105
105
|
✓ Phase 2 — Toggle component + localStorage (UI → persistence → tests)
|
|
106
106
|
✓ Phase 3 — System preference detection (media query → sync → tests)
|
|
107
|
-
Written plans/dark-mode-support.md
|
|
107
|
+
Written .tracerkit/plans/dark-mode-support.md
|
|
108
108
|
|
|
109
109
|
You: # implement each phase with Claude...
|
|
110
110
|
|
|
@@ -112,7 +112,7 @@ You: /tk:verify dark-mode-support
|
|
|
112
112
|
AI: Verifying against plan...
|
|
113
113
|
✓ All done-when conditions met
|
|
114
114
|
✓ Tests passing
|
|
115
|
-
PASS — archived to
|
|
115
|
+
PASS — archived to .tracerkit/archives/dark-mode-support/
|
|
116
116
|
```
|
|
117
117
|
|
|
118
118
|
</details>
|
|
@@ -122,14 +122,14 @@ AI: Verifying against plan...
|
|
|
122
122
|
|
|
123
123
|
```
|
|
124
124
|
You: /tk:prd update dark mode to detect system preference
|
|
125
|
-
AI: Found existing prds/dark-mode-support.md
|
|
125
|
+
AI: Found existing .tracerkit/prds/dark-mode-support.md
|
|
126
126
|
? Start fresh or revise the existing PRD?
|
|
127
127
|
...
|
|
128
|
-
✓ Updated prds/dark-mode-support.md
|
|
128
|
+
✓ Updated .tracerkit/prds/dark-mode-support.md
|
|
129
129
|
|
|
130
130
|
You: /tk:plan dark-mode-support
|
|
131
131
|
AI: Reading updated PRD...
|
|
132
|
-
✓ Regenerated plans/dark-mode-support.md with new scope
|
|
132
|
+
✓ Regenerated .tracerkit/plans/dark-mode-support.md with new scope
|
|
133
133
|
```
|
|
134
134
|
|
|
135
135
|
</details>
|
|
@@ -150,7 +150,7 @@ You: /tk:verify dark-mode-support
|
|
|
150
150
|
AI: Verifying against plan...
|
|
151
151
|
✓ All done-when conditions met
|
|
152
152
|
✓ Tests passing
|
|
153
|
-
PASS — archived to
|
|
153
|
+
PASS — archived to .tracerkit/archives/dark-mode-support/
|
|
154
154
|
```
|
|
155
155
|
|
|
156
156
|
</details>
|
|
@@ -186,8 +186,23 @@ AI: Feature Status Dashboard
|
|
|
186
186
|
|
|
187
187
|
All commands default to the home directory. Pass a path to target a specific project.
|
|
188
188
|
|
|
189
|
-
|
|
190
|
-
|
|
189
|
+
## Configuration
|
|
190
|
+
|
|
191
|
+
Artifacts are stored under `.tracerkit/` by default. To customize paths, create `.tracerkit/config.json`:
|
|
192
|
+
|
|
193
|
+
```json
|
|
194
|
+
{
|
|
195
|
+
"paths": {
|
|
196
|
+
"prds": ".tracerkit/prds",
|
|
197
|
+
"plans": ".tracerkit/plans",
|
|
198
|
+
"archives": ".tracerkit/archives"
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Any missing key falls back to its default. The file is optional — without it, all defaults apply. After changing config, run `tracerkit update` to regenerate skills with the new paths.
|
|
204
|
+
|
|
205
|
+
## Metadata Lifecycle
|
|
191
206
|
|
|
192
207
|
Each PRD carries YAML frontmatter that tracks its position in the workflow. The skills update it automatically — you never need to edit it by hand.
|
|
193
208
|
|
|
@@ -238,10 +253,7 @@ completed: 2025-06-20T09:00:00Z
|
|
|
238
253
|
|
|
239
254
|
</details>
|
|
240
255
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
<details>
|
|
244
|
-
<summary>Compared to</summary>
|
|
256
|
+
## Compared to
|
|
245
257
|
|
|
246
258
|
**vs. [Spec Kit](https://github.com/github/spec-kit)** (GitHub) — Thorough but heavyweight. 5 phases, Python setup, rigid phase gates. TracerKit is 3 phases, zero deps, automated verification.
|
|
247
259
|
|
|
@@ -266,8 +278,6 @@ completed: 2025-06-20T09:00:00Z
|
|
|
266
278
|
|
|
267
279
|
</details>
|
|
268
280
|
|
|
269
|
-
</details>
|
|
270
|
-
|
|
271
281
|
## Contributing
|
|
272
282
|
|
|
273
283
|
1. Fork the repo and create a feature branch
|
package/dist/bin.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { n as e, r as t, t as n } from "./uninstall-
|
|
2
|
+
import { n as e, r as t, t as n } from "./uninstall-C6vhDv_T.js";
|
|
3
3
|
import { resolve as r } from "node:path";
|
|
4
4
|
import { homedir as i } from "node:os";
|
|
5
5
|
//#region src/cli.ts
|
|
@@ -9,7 +9,7 @@ var a = [
|
|
|
9
9
|
"Commands:",
|
|
10
10
|
" init [path] Install skills to ~/.claude/skills/ (or [path] if given)",
|
|
11
11
|
" update [path] Refresh unchanged files from latest version, skip modified",
|
|
12
|
-
" uninstall [path] Remove TracerKit skill directories, keep
|
|
12
|
+
" uninstall [path] Remove TracerKit skill directories, keep .tracerkit/ artifacts",
|
|
13
13
|
"",
|
|
14
14
|
"Options:",
|
|
15
15
|
" --force Overwrite modified files during update",
|
|
@@ -24,7 +24,7 @@ function o(e) {
|
|
|
24
24
|
}
|
|
25
25
|
function s(r) {
|
|
26
26
|
if (r.includes("--help") || r.includes("-h")) return a;
|
|
27
|
-
if (r.includes("--version") || r.includes("-v")) return ["tracerkit/1.
|
|
27
|
+
if (r.includes("--version") || r.includes("-v")) return ["tracerkit/1.4.1"];
|
|
28
28
|
let i = r[0], s = r.slice(1);
|
|
29
29
|
switch (i) {
|
|
30
30
|
case "init": return t(o(s));
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as e, n as t, r as n, t as r } from "./uninstall-
|
|
1
|
+
import { i as e, n as t, r as n, t as r } from "./uninstall-C6vhDv_T.js";
|
|
2
2
|
export { e as SKILL_NAMES, n as init, r as uninstall, t as update };
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { existsSync as e, mkdirSync as t, readFileSync as n, readdirSync as r, rmSync as i, writeFileSync as a } from "node:fs";
|
|
2
|
+
import { dirname as o, join as s } from "node:path";
|
|
3
|
+
import { createHash as c } from "node:crypto";
|
|
4
|
+
import { fileURLToPath as l } from "node:url";
|
|
5
|
+
//#region src/config.ts
|
|
6
|
+
var u = {
|
|
7
|
+
prds: ".tracerkit/prds",
|
|
8
|
+
plans: ".tracerkit/plans",
|
|
9
|
+
archives: ".tracerkit/archives"
|
|
10
|
+
};
|
|
11
|
+
function d(t) {
|
|
12
|
+
let r = s(t, ".tracerkit", "config.json");
|
|
13
|
+
if (!e(r)) return { paths: { ...u } };
|
|
14
|
+
let i, a;
|
|
15
|
+
try {
|
|
16
|
+
i = n(r, "utf8"), a = JSON.parse(i);
|
|
17
|
+
} catch {
|
|
18
|
+
throw Error("Invalid .tracerkit/config.json — expected valid JSON");
|
|
19
|
+
}
|
|
20
|
+
let o = typeof a.paths == "object" && a.paths !== null ? a.paths : {};
|
|
21
|
+
return { paths: {
|
|
22
|
+
prds: typeof o.prds == "string" ? o.prds : u.prds,
|
|
23
|
+
plans: typeof o.plans == "string" ? o.plans : u.plans,
|
|
24
|
+
archives: typeof o.archives == "string" ? o.archives : u.archives
|
|
25
|
+
} };
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region src/templates.ts
|
|
29
|
+
var f = [
|
|
30
|
+
"tk:prd",
|
|
31
|
+
"tk:plan",
|
|
32
|
+
"tk:verify",
|
|
33
|
+
"tk:status"
|
|
34
|
+
], p = s(o(l(import.meta.url)), "..", "templates");
|
|
35
|
+
function m(e, t = "") {
|
|
36
|
+
let n = r(e, { withFileTypes: !0 }), i = [];
|
|
37
|
+
for (let r of n) {
|
|
38
|
+
let n = t ? `${t}/${r.name}` : r.name;
|
|
39
|
+
r.isDirectory() ? i.push(...m(s(e, r.name), n)) : i.push(n);
|
|
40
|
+
}
|
|
41
|
+
return i.sort();
|
|
42
|
+
}
|
|
43
|
+
function h(e, t) {
|
|
44
|
+
return e.replaceAll("{{paths.prds}}", t.paths.prds).replaceAll("{{paths.plans}}", t.paths.plans).replaceAll("{{paths.archives}}", t.paths.archives);
|
|
45
|
+
}
|
|
46
|
+
function g(e, r, i) {
|
|
47
|
+
let c = i ?? m(p);
|
|
48
|
+
for (let i of c) {
|
|
49
|
+
let c = s(p, i), l = s(e, i);
|
|
50
|
+
t(o(l), { recursive: !0 }), a(l, h(n(c, "utf8"), r));
|
|
51
|
+
}
|
|
52
|
+
return { copied: c };
|
|
53
|
+
}
|
|
54
|
+
function _(e) {
|
|
55
|
+
return c("sha256").update(e).digest("hex");
|
|
56
|
+
}
|
|
57
|
+
function v(t, r) {
|
|
58
|
+
let i = m(p), a = [], o = [], c = [];
|
|
59
|
+
for (let l of i) {
|
|
60
|
+
let i = s(t, l);
|
|
61
|
+
if (!e(i)) c.push(l);
|
|
62
|
+
else {
|
|
63
|
+
let e = h(n(s(p, l), "utf8"), r);
|
|
64
|
+
_(Buffer.from(e)) === _(n(i)) ? a.push(l) : o.push(l);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
unchanged: a,
|
|
69
|
+
modified: o,
|
|
70
|
+
missing: c
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
//#endregion
|
|
74
|
+
//#region src/commands/init.ts
|
|
75
|
+
function y(t) {
|
|
76
|
+
for (let n of f) if (e(s(t, ".claude", "skills", n))) throw Error(`.claude/skills/${n}/ already exists — aborting`);
|
|
77
|
+
let { copied: n } = g(t, d(t));
|
|
78
|
+
return n.map((e) => `✓ ${e}`);
|
|
79
|
+
}
|
|
80
|
+
//#endregion
|
|
81
|
+
//#region src/commands/update.ts
|
|
82
|
+
function b(t, n) {
|
|
83
|
+
if (!f.some((n) => e(s(t, ".claude", "skills", n)))) throw Error("TracerKit not initialized — run `tracerkit init` first");
|
|
84
|
+
let r = d(t), { unchanged: i, modified: a, missing: o } = v(t, r), c = [], l = n?.force ?? !1, u = [
|
|
85
|
+
...i,
|
|
86
|
+
...o,
|
|
87
|
+
...l ? a : []
|
|
88
|
+
];
|
|
89
|
+
if (u.length > 0) {
|
|
90
|
+
g(t, r, u);
|
|
91
|
+
for (let e of i) c.push(`✓ ${e}`);
|
|
92
|
+
for (let e of o) c.push(`✓ ${e} (added)`);
|
|
93
|
+
if (l) for (let e of a) c.push(`✓ ${e} (replaced)`);
|
|
94
|
+
}
|
|
95
|
+
if (!l && a.length > 0) {
|
|
96
|
+
for (let e of a) c.push(`⚠ ${e} (skipped — modified)`);
|
|
97
|
+
c.push("", "Run `tracerkit update --force` to replace modified files with latest versions.");
|
|
98
|
+
}
|
|
99
|
+
return c;
|
|
100
|
+
}
|
|
101
|
+
//#endregion
|
|
102
|
+
//#region src/commands/uninstall.ts
|
|
103
|
+
function x(t) {
|
|
104
|
+
if (!f.some((n) => e(s(t, ".claude", "skills", n)))) throw Error("TracerKit not initialized — nothing to uninstall");
|
|
105
|
+
let n = [];
|
|
106
|
+
for (let r of f) {
|
|
107
|
+
let a = s(t, ".claude", "skills", r);
|
|
108
|
+
e(a) && (i(a, {
|
|
109
|
+
recursive: !0,
|
|
110
|
+
force: !0
|
|
111
|
+
}), n.push(`✗ .claude/skills/${r}/ removed`));
|
|
112
|
+
}
|
|
113
|
+
return n;
|
|
114
|
+
}
|
|
115
|
+
//#endregion
|
|
116
|
+
export { f as i, b as n, y as r, x as t };
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Turn a PRD into a multi-phase implementation plan using tracer-bullet vertical slices, saved to plans/. Use after /tk:prd.
|
|
2
|
+
description: Turn a PRD into a multi-phase implementation plan using tracer-bullet vertical slices, saved to {{paths.plans}}/. Use after /tk:prd.
|
|
3
3
|
argument-hint: '[slug]'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# PRD to Plan
|
|
7
7
|
|
|
8
|
-
Break a PRD into phased vertical slices (tracer bullets). Output: `plans/<slug>.md`.
|
|
8
|
+
Break a PRD into phased vertical slices (tracer bullets). Output: `{{paths.plans}}/<slug>.md`.
|
|
9
9
|
|
|
10
10
|
## Pre-loaded context
|
|
11
11
|
|
|
12
|
-
- Available PRDs: !`ls prds/ 2>/dev/null || echo "no prds/ directory found"`
|
|
12
|
+
- Available PRDs: !`ls {{paths.prds}}/ 2>/dev/null || echo "no {{paths.prds}}/ directory found"`
|
|
13
13
|
|
|
14
14
|
## Input
|
|
15
15
|
|
|
@@ -21,13 +21,13 @@ Use the argument as `<slug>` if given. If no argument is provided, list availabl
|
|
|
21
21
|
|
|
22
22
|
### 1. Read the PRD
|
|
23
23
|
|
|
24
|
-
Read `prds/<slug>.md`. If it does not exist, list available PRDs and ask.
|
|
24
|
+
Read `{{paths.prds}}/<slug>.md`. If it does not exist, list available PRDs and ask.
|
|
25
25
|
|
|
26
|
-
If `plans/<slug>.md` already exists, tell the user and ask whether to overwrite or pick a new name.
|
|
26
|
+
If `{{paths.plans}}/<slug>.md` already exists, tell the user and ask whether to overwrite or pick a new name.
|
|
27
27
|
|
|
28
28
|
### 1b. Update PRD status
|
|
29
29
|
|
|
30
|
-
Update the YAML frontmatter in `prds/<slug>.md` to `status: in_progress`. Change only the `status` field — do not touch any other frontmatter fields or the markdown content below the closing `---`.
|
|
30
|
+
Update the YAML frontmatter in `{{paths.prds}}/<slug>.md` to `status: in_progress`. Change only the `status` field — do not touch any other frontmatter fields or the markdown content below the closing `---`.
|
|
31
31
|
|
|
32
32
|
If the PRD has no frontmatter, skip this step silently.
|
|
33
33
|
|
|
@@ -87,12 +87,12 @@ Ask: Does the granularity feel right? Should any phases merge or split? Iterate
|
|
|
87
87
|
|
|
88
88
|
### 6. Save plan
|
|
89
89
|
|
|
90
|
-
Save to `plans/<slug>.md` (create `plans/` if missing).
|
|
90
|
+
Save to `{{paths.plans}}/<slug>.md` (create `{{paths.plans}}/` if missing).
|
|
91
91
|
|
|
92
92
|
```markdown
|
|
93
93
|
# Plan: <Feature Name>
|
|
94
94
|
|
|
95
|
-
> Source PRD: `prds/<slug>.md`
|
|
95
|
+
> Source PRD: `{{paths.prds}}/<slug>.md`
|
|
96
96
|
|
|
97
97
|
## Architectural Decisions
|
|
98
98
|
|
|
@@ -141,4 +141,4 @@ Print saved path and one line per phase: `Phase N — <title> (<condition summar
|
|
|
141
141
|
|
|
142
142
|
- PRD not found — list available PRDs and ask
|
|
143
143
|
- PRD missing sections — note gaps inline and continue
|
|
144
|
-
- `plans/` missing — create it
|
|
144
|
+
- `{{paths.plans}}/` missing — create it
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Create a PRD through user interview, codebase exploration, and module design, saved to prds/. Use when starting a new feature or change.
|
|
2
|
+
description: Create a PRD through user interview, codebase exploration, and module design, saved to {{paths.prds}}/. Use when starting a new feature or change.
|
|
3
3
|
argument-hint: <idea>
|
|
4
4
|
---
|
|
5
5
|
|
|
@@ -13,9 +13,9 @@ The argument is: $ARGUMENTS
|
|
|
13
13
|
|
|
14
14
|
If the argument is empty, go straight to Step 1 (gather problem description). After gathering the idea, derive the slug from the idea.
|
|
15
15
|
|
|
16
|
-
If the argument is provided, convert it to a kebab-case slug (lowercase, spaces and underscores replaced with hyphens). This is `<slug>`. The output file is `prds/<slug>.md`.
|
|
16
|
+
If the argument is provided, convert it to a kebab-case slug (lowercase, spaces and underscores replaced with hyphens). This is `<slug>`. The output file is `{{paths.prds}}/<slug>.md`.
|
|
17
17
|
|
|
18
|
-
If `prds/<slug>.md` already exists, tell the user and ask whether to overwrite or pick a new name.
|
|
18
|
+
If `{{paths.prds}}/<slug>.md` already exists, tell the user and ask whether to overwrite or pick a new name.
|
|
19
19
|
|
|
20
20
|
## Workflow
|
|
21
21
|
|
|
@@ -51,7 +51,7 @@ Present modules to user. Confirm which need tests.
|
|
|
51
51
|
|
|
52
52
|
### 5. Write PRD
|
|
53
53
|
|
|
54
|
-
Save to `prds/<slug>.md` (create `prds/` if missing).
|
|
54
|
+
Save to `{{paths.prds}}/<slug>.md` (create `{{paths.prds}}/` if missing).
|
|
55
55
|
|
|
56
56
|
```markdown
|
|
57
57
|
---
|
|
@@ -118,5 +118,5 @@ Tell the user: file created, one-line summary, next step is `/tk:plan <slug>`.
|
|
|
118
118
|
|
|
119
119
|
## Error Handling
|
|
120
120
|
|
|
121
|
-
- `prds/` missing — create it
|
|
121
|
+
- `{{paths.prds}}/` missing — create it
|
|
122
122
|
- Scope larger than expected — surface and re-scope with user before continuing
|
|
@@ -10,11 +10,11 @@ Scan all PRDs and display a status overview of every feature in the workflow.
|
|
|
10
10
|
|
|
11
11
|
### 1. Scan PRDs
|
|
12
12
|
|
|
13
|
-
List all `.md` files in `prds/`. If the directory is missing or empty, print "No features found — run `/tk:prd` to start one." and stop.
|
|
13
|
+
List all `.md` files in `{{paths.prds}}/`. If the directory is missing or empty, print "No features found — run `/tk:prd` to start one." and stop.
|
|
14
14
|
|
|
15
15
|
### 2. Parse each PRD
|
|
16
16
|
|
|
17
|
-
For each file `prds/<slug>.md`:
|
|
17
|
+
For each file `{{paths.prds}}/<slug>.md`:
|
|
18
18
|
|
|
19
19
|
1. Read YAML frontmatter (between opening and closing `---` delimiters)
|
|
20
20
|
2. Extract fields: `created`, `status`, `completed`
|
|
@@ -22,7 +22,7 @@ For each file `prds/<slug>.md`:
|
|
|
22
22
|
|
|
23
23
|
### 3. Read verdict data
|
|
24
24
|
|
|
25
|
-
For each slug, check if `plans/<slug>.md` exists. If it does, find the last `## Verdict` block and extract:
|
|
25
|
+
For each slug, check if `{{paths.plans}}/<slug>.md` exists. If it does, find the last `## Verdict` block and extract:
|
|
26
26
|
|
|
27
27
|
- **Result**: PASS or NEEDS_WORK
|
|
28
28
|
- **BLOCKERS**: count
|
|
@@ -9,7 +9,7 @@ Compare current implementation against a plan, stamp a verdict, and archive on P
|
|
|
9
9
|
|
|
10
10
|
## Pre-loaded context
|
|
11
11
|
|
|
12
|
-
- Available plans: !`ls plans/ 2>/dev/null || echo "no plans/ directory found"`
|
|
12
|
+
- Available plans: !`ls {{paths.plans}}/ 2>/dev/null || echo "no {{paths.plans}}/ directory found"`
|
|
13
13
|
|
|
14
14
|
## Input
|
|
15
15
|
|
|
@@ -21,7 +21,7 @@ Use the argument as `<slug>` if given. If no argument is provided, list availabl
|
|
|
21
21
|
|
|
22
22
|
### 1. Load the plan
|
|
23
23
|
|
|
24
|
-
Read `plans/<slug>.md`. If it does not exist, list available plans and ask.
|
|
24
|
+
Read `{{paths.plans}}/<slug>.md`. If it does not exist, list available plans and ask.
|
|
25
25
|
|
|
26
26
|
### 2. Load the PRD
|
|
27
27
|
|
|
@@ -64,7 +64,7 @@ Print the verdict report:
|
|
|
64
64
|
|
|
65
65
|
### 6. Stamp the plan
|
|
66
66
|
|
|
67
|
-
Append a verdict block at the bottom of `plans/<slug>.md`:
|
|
67
|
+
Append a verdict block at the bottom of `{{paths.plans}}/<slug>.md`:
|
|
68
68
|
|
|
69
69
|
```markdown
|
|
70
70
|
---
|
|
@@ -83,7 +83,7 @@ If a previous verdict block exists, replace it with the new one.
|
|
|
83
83
|
|
|
84
84
|
If the verdict is **PASS**:
|
|
85
85
|
|
|
86
|
-
**First**, update the YAML frontmatter in `prds/<slug>.md`:
|
|
86
|
+
**First**, update the YAML frontmatter in `{{paths.prds}}/<slug>.md`:
|
|
87
87
|
|
|
88
88
|
- Set `status: done`
|
|
89
89
|
- Add `completed: <current UTC timestamp, ISO 8601, e.g. 2025-06-15T14:30:00Z>`
|
|
@@ -92,10 +92,10 @@ If the verdict is **PASS**:
|
|
|
92
92
|
|
|
93
93
|
**Then**, automatically archive:
|
|
94
94
|
|
|
95
|
-
1. Create `
|
|
96
|
-
2. Move `prds/<slug>.md` → `
|
|
97
|
-
3. Move `plans/<slug>.md` → `
|
|
98
|
-
4. Append closing timestamp to `
|
|
95
|
+
1. Create `{{paths.archives}}/<slug>/` directory (and `{{paths.archives}}/` if missing)
|
|
96
|
+
2. Move `{{paths.prds}}/<slug>.md` → `{{paths.archives}}/<slug>/prd.md`
|
|
97
|
+
3. Move `{{paths.plans}}/<slug>.md` → `{{paths.archives}}/<slug>/plan.md`
|
|
98
|
+
4. Append closing timestamp to `{{paths.archives}}/<slug>/plan.md`:
|
|
99
99
|
|
|
100
100
|
```markdown
|
|
101
101
|
---
|
|
@@ -106,9 +106,9 @@ If the verdict is **PASS**:
|
|
|
106
106
|
- **Closed**: YYYY-MM-DD HH:MM (UTC)
|
|
107
107
|
```
|
|
108
108
|
|
|
109
|
-
5. Tell the user: archived to `
|
|
109
|
+
5. Tell the user: archived to `{{paths.archives}}/<slug>/`, one-line summary of the feature.
|
|
110
110
|
|
|
111
|
-
If `
|
|
111
|
+
If `{{paths.archives}}/<slug>/` already exists, warn and ask whether to overwrite.
|
|
112
112
|
|
|
113
113
|
### 8. On NEEDS_WORK
|
|
114
114
|
|
|
@@ -126,5 +126,5 @@ Tell the user: fix the listed blockers, then re-run `/tk:verify <slug>`.
|
|
|
126
126
|
|
|
127
127
|
- Plan not found — list available plans and ask
|
|
128
128
|
- PRD referenced in plan not found — warn and continue with plan only
|
|
129
|
-
- `plans/` missing — tell user to run `/tk:plan` first
|
|
130
|
-
- `
|
|
129
|
+
- `{{paths.plans}}/` missing — tell user to run `/tk:plan` first
|
|
130
|
+
- `{{paths.archives}}/<slug>/` already exists — warn and ask whether to overwrite
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import { existsSync as e, mkdirSync as t, readFileSync as n, readdirSync as r, rmSync as i, writeFileSync as a } from "node:fs";
|
|
2
|
-
import { dirname as o, join as s } from "node:path";
|
|
3
|
-
import { createHash as c } from "node:crypto";
|
|
4
|
-
import { fileURLToPath as l } from "node:url";
|
|
5
|
-
//#region src/templates.ts
|
|
6
|
-
var u = [
|
|
7
|
-
"tk:prd",
|
|
8
|
-
"tk:plan",
|
|
9
|
-
"tk:verify",
|
|
10
|
-
"tk:status"
|
|
11
|
-
], d = s(o(l(import.meta.url)), "..", "templates");
|
|
12
|
-
function f(e, t = "") {
|
|
13
|
-
let n = r(e, { withFileTypes: !0 }), i = [];
|
|
14
|
-
for (let r of n) {
|
|
15
|
-
let n = t ? `${t}/${r.name}` : r.name;
|
|
16
|
-
r.isDirectory() ? i.push(...f(s(e, r.name), n)) : i.push(n);
|
|
17
|
-
}
|
|
18
|
-
return i.sort();
|
|
19
|
-
}
|
|
20
|
-
function p(e, r) {
|
|
21
|
-
let i = r ?? f(d);
|
|
22
|
-
for (let r of i) {
|
|
23
|
-
let i = s(d, r), c = s(e, r);
|
|
24
|
-
t(o(c), { recursive: !0 }), a(c, n(i));
|
|
25
|
-
}
|
|
26
|
-
return { copied: i };
|
|
27
|
-
}
|
|
28
|
-
function m(e) {
|
|
29
|
-
return c("sha256").update(e).digest("hex");
|
|
30
|
-
}
|
|
31
|
-
function h(t) {
|
|
32
|
-
let r = f(d), i = [], a = [], o = [];
|
|
33
|
-
for (let c of r) {
|
|
34
|
-
let r = s(t, c);
|
|
35
|
-
e(r) ? m(n(s(d, c))) === m(n(r)) ? i.push(c) : a.push(c) : o.push(c);
|
|
36
|
-
}
|
|
37
|
-
return {
|
|
38
|
-
unchanged: i,
|
|
39
|
-
modified: a,
|
|
40
|
-
missing: o
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
//#endregion
|
|
44
|
-
//#region src/commands/init.ts
|
|
45
|
-
function g(t) {
|
|
46
|
-
for (let n of u) if (e(s(t, ".claude", "skills", n))) throw Error(`.claude/skills/${n}/ already exists — aborting`);
|
|
47
|
-
let { copied: n } = p(t);
|
|
48
|
-
return n.map((e) => `✓ ${e}`);
|
|
49
|
-
}
|
|
50
|
-
//#endregion
|
|
51
|
-
//#region src/commands/update.ts
|
|
52
|
-
function _(t, n) {
|
|
53
|
-
if (!u.some((n) => e(s(t, ".claude", "skills", n)))) throw Error("TracerKit not initialized — run `tracerkit init` first");
|
|
54
|
-
let { unchanged: r, modified: i, missing: a } = h(t), o = [], c = n?.force ?? !1, l = [
|
|
55
|
-
...r,
|
|
56
|
-
...a,
|
|
57
|
-
...c ? i : []
|
|
58
|
-
];
|
|
59
|
-
if (l.length > 0) {
|
|
60
|
-
p(t, l);
|
|
61
|
-
for (let e of r) o.push(`✓ ${e}`);
|
|
62
|
-
for (let e of a) o.push(`✓ ${e} (added)`);
|
|
63
|
-
if (c) for (let e of i) o.push(`✓ ${e} (replaced)`);
|
|
64
|
-
}
|
|
65
|
-
if (!c && i.length > 0) {
|
|
66
|
-
for (let e of i) o.push(`⚠ ${e} (skipped — modified)`);
|
|
67
|
-
o.push("", "Run `tracerkit update --force` to replace modified files with latest versions.");
|
|
68
|
-
}
|
|
69
|
-
return o;
|
|
70
|
-
}
|
|
71
|
-
//#endregion
|
|
72
|
-
//#region src/commands/uninstall.ts
|
|
73
|
-
function v(t) {
|
|
74
|
-
if (!u.some((n) => e(s(t, ".claude", "skills", n)))) throw Error("TracerKit not initialized — nothing to uninstall");
|
|
75
|
-
let n = [];
|
|
76
|
-
for (let r of u) {
|
|
77
|
-
let a = s(t, ".claude", "skills", r);
|
|
78
|
-
e(a) && (i(a, {
|
|
79
|
-
recursive: !0,
|
|
80
|
-
force: !0
|
|
81
|
-
}), n.push(`✗ .claude/skills/${r}/ removed`));
|
|
82
|
-
}
|
|
83
|
-
return n;
|
|
84
|
-
}
|
|
85
|
-
//#endregion
|
|
86
|
-
export { u as i, _ as n, g as r, v as t };
|