tracerkit 1.3.13 → 1.4.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/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:** `prds/<slug>.md`
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:** `plans/<slug>.md`
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 `archive/<slug>/`.
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 `plans/<slug>.md` — on PASS: `archive/<slug>/prd.md` + `archive/<slug>/plan.md`
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 `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.
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 archive/dark-mode-support/
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 archive/dark-mode-support/
153
+ PASS — archived to .tracerkit/archives/dark-mode-support/
154
154
  ```
155
155
 
156
156
  </details>
@@ -186,6 +186,25 @@ 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
+ <details>
190
+ <summary>Configuration</summary>
191
+
192
+ Artifacts are stored under `.tracerkit/` by default. To customize paths, create `.tracerkit/config.json`:
193
+
194
+ ```json
195
+ {
196
+ "paths": {
197
+ "prds": ".tracerkit/prds",
198
+ "plans": ".tracerkit/plans",
199
+ "archives": ".tracerkit/archives"
200
+ }
201
+ }
202
+ ```
203
+
204
+ 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.
205
+
206
+ </details>
207
+
189
208
  <details>
190
209
  <summary>Metadata Lifecycle</summary>
191
210
 
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-vX1WH11F.js";
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 prds/ and plans/",
12
+ " uninstall [path] Remove TracerKit skill directories, keep .tracerkit/ artifacts",
13
13
  "",
14
14
  "Options:",
15
15
  " --force Overwrite modified files during update",
@@ -24,13 +24,13 @@ 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.3.13"];
27
+ if (r.includes("--version") || r.includes("-v")) return ["tracerkit/1.4.0"];
28
28
  let i = r[0], s = r.slice(1);
29
29
  switch (i) {
30
30
  case "init": return t(o(s));
31
31
  case "update": {
32
32
  let t = s.includes("--force"), n = e(o(s.filter((e) => e !== "--force")), { force: t });
33
- return n.push("", "Updated to tracerkit/1.3.13"), n.push("If using Claude Code, restart your session to load changes."), n;
33
+ return n.push("", "Updated to the latest TracerKit."), n.push("If using Claude Code, restart your session to load changes."), n;
34
34
  }
35
35
  case "uninstall": return n(o(s));
36
36
  default: return a;
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-vX1WH11F.js";
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,6 +1,6 @@
1
1
  {
2
2
  "name": "tracerkit",
3
- "version": "1.3.13",
3
+ "version": "1.4.0",
4
4
  "description": "Spec-driven workflow for Claude Code: replace ad-hoc prompts with PRD → plan → verify.",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -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 `archive/<slug>/` directory (and `archive/` if missing)
96
- 2. Move `prds/<slug>.md` → `archive/<slug>/prd.md`
97
- 3. Move `plans/<slug>.md` → `archive/<slug>/plan.md`
98
- 4. Append closing timestamp to `archive/<slug>/plan.md`:
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 `archive/<slug>/`, one-line summary of the feature.
109
+ 5. Tell the user: archived to `{{paths.archives}}/<slug>/`, one-line summary of the feature.
110
110
 
111
- If `archive/<slug>/` already exists, warn and ask whether to overwrite.
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
- - `archive/<slug>/` already exists — warn and ask whether to overwrite
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 };