tracerkit 1.19.0 → 1.19.2

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
@@ -142,50 +142,28 @@ AI: | Feature | Status | Age | Progress | Next
142
142
 
143
143
  See [Examples](docs/examples.md) for full walkthroughs.
144
144
 
145
- <details>
146
- <summary>GitHub Issues as storage backend</summary>
147
-
148
- Same skills, same workflow. Storage is configured per-project:
149
-
150
- ```bash
151
- tracerkit config storage github # set current project to use GitHub
152
- ```
153
-
154
- PRDs and plans become GitHub Issues with `tk:prd` and `tk:plan` labels. On `/tk:check` pass, issues are closed with `completed` reason and any related PRs are linked automatically. Each project can use a different backend; local is the default. See [Configuration](docs/configuration.md) for details.
155
-
156
- To migrate existing artifacts between backends:
157
-
158
- ```bash
159
- tracerkit migrate-storage # local→github or github→local (auto-detected)
160
- ```
161
-
162
- Direction is inferred from the current `storage` config. All artifacts are migrated, existing duplicates are skipped, and the config is flipped to the target backend. Source artifacts are left intact as backup.
163
-
164
- </details>
165
-
166
145
  ## Skills
167
146
 
168
- | Skill | What it does | Output |
169
- | ------------------ | ------------------------------------------------------ | ----------------------------------------------------------------------------------------------- |
170
- | `/tk:prd <idea>` | Interview → codebase scan → structured PRD | `.tracerkit/prds/<slug>.md` or GitHub Issue |
171
- | `/tk:plan <slug>` | PRD → phased vertical slices, each demoable on its own | `.tracerkit/plans/<slug>.md` or GitHub Issue |
172
- | `/tk:build <slug>` | Implement next incomplete phase, run feedback loops | Code changes + checked items in plan |
173
- | `/tk:brief` | Feature dashboard with progress and suggested focus | Terminal only, no files |
174
- | `/tk:check [slug]` | Verify done-when checkboxes against codebase and tests | Verdict block in plan. On `done`: status updated (local) or issues closed + PRs linked (GitHub) |
147
+ | Skill | What it does | Output |
148
+ | ------------------ | ------------------------------------------------------ | --------------------------------------------------- |
149
+ | `/tk:prd <idea>` | Interview → codebase scan → structured PRD | `.tracerkit/prds/<slug>.md` |
150
+ | `/tk:plan <slug>` | PRD → phased vertical slices, each demoable on its own | `.tracerkit/plans/<slug>.md` |
151
+ | `/tk:build <slug>` | Implement next incomplete phase, run feedback loops | Code changes + checked items in plan |
152
+ | `/tk:brief` | Feature dashboard with progress and suggested focus | Terminal only, no files |
153
+ | `/tk:check [slug]` | Verify done-when checkboxes against codebase and tests | Verdict block in plan, status updated when all pass |
175
154
 
176
155
  ## Docs
177
156
 
178
- | Document | Description |
179
- | ------------------------------------------------ | ---------------------------------------------------------- |
180
- | [Examples](docs/examples.md) | Walk through end-to-end usage scenarios |
181
- | [CLI Reference](docs/cli-reference.md) | Commands: init, update, config, migrate-storage, uninstall |
182
- | [Configuration](docs/configuration.md) | Storage backends, GitHub options, custom paths |
183
- | [Metadata Lifecycle](docs/metadata-lifecycle.md) | Understand YAML frontmatter states and transitions |
184
- | [Comparison](docs/comparison.md) | Compare TracerKit to Spec Kit, Kiro, and OpenSpec |
185
- | [Cursor Setup](docs/cursor-setup.md) | Use TracerKit skills in Cursor |
186
- | [Gemini CLI Setup](docs/gemini-cli-setup.md) | Use TracerKit skills in Gemini CLI |
187
- | [Copilot Setup](docs/copilot-setup.md) | Use TracerKit skills in GitHub Copilot |
188
- | [OpenCode Setup](docs/opencode-setup.md) | Use TracerKit skills in OpenCode |
157
+ | Document | Description |
158
+ | ------------------------------------------------ | -------------------------------------------------- |
159
+ | [Examples](docs/examples.md) | Walk through end-to-end usage scenarios |
160
+ | [CLI Reference](docs/cli-reference.md) | Commands: init, update, uninstall |
161
+ | [Metadata Lifecycle](docs/metadata-lifecycle.md) | Understand YAML frontmatter states and transitions |
162
+ | [Comparison](docs/comparison.md) | Compare TracerKit to Spec Kit, Kiro, and OpenSpec |
163
+ | [Cursor Setup](docs/cursor-setup.md) | Use TracerKit skills in Cursor |
164
+ | [Gemini CLI Setup](docs/gemini-cli-setup.md) | Use TracerKit skills in Gemini CLI |
165
+ | [Copilot Setup](docs/copilot-setup.md) | Use TracerKit skills in GitHub Copilot |
166
+ | [OpenCode Setup](docs/opencode-setup.md) | Use TracerKit skills in OpenCode |
189
167
 
190
168
  ## Contributing
191
169
 
package/dist/bin.js CHANGED
@@ -1,99 +1,44 @@
1
1
  #!/usr/bin/env node
2
- import { a as e, f as t, i as n, l as r, n as i, o as a, p as o, r as s, s as c, t as l, u } from "./uninstall-CNGQ7MEU.js";
3
- import { existsSync as d, readFileSync as f, statSync as p } from "node:fs";
4
- import { dirname as m, join as h, resolve as g } from "node:path";
5
- import { fileURLToPath as _ } from "node:url";
6
- import { homedir as v } from "node:os";
7
- //#region src/commands/config.ts
8
- function y(e, t) {
9
- let [n, r] = t;
10
- return n ? r ? S(e, n, r) : x(e, n) : b(e);
11
- }
12
- function b(e) {
13
- let n = t(e), r = n.storage === "local" ? {
14
- storage: n.storage,
15
- paths: n.paths
16
- } : n;
17
- return JSON.stringify(r, null, 2).split("\n");
18
- }
19
- function x(e, n) {
20
- let r = w(t(e), n);
21
- return r === void 0 ? [`Unknown key: ${n}`] : typeof r == "object" ? [JSON.stringify(r, null, 2)] : [String(r)];
22
- }
23
- function S(e, t, n) {
24
- o(e, T(t, n));
25
- let r = [`✓ Set ${t} = ${n}`];
26
- return C(e, r), r;
27
- }
28
- function C(n, r) {
29
- u.some((e) => d(h(n, ".claude", "skills", e))) && (e(n, t(n)), r.push("✓ Skills re-rendered"));
30
- }
31
- function w(e, t) {
32
- let n = t.split("."), r = e;
33
- for (let e of n) {
34
- if (typeof r != "object" || !r) return;
35
- r = r[e];
36
- }
37
- return r;
38
- }
39
- function T(e, t) {
40
- let n = e.split("."), r = {}, i = r;
41
- for (let e = 0; e < n.length - 1; e++) {
42
- let t = {};
43
- i[n[e]] = t, i = t;
44
- }
45
- return i[n[n.length - 1]] = t, r;
46
- }
47
- //#endregion
2
+ import { a as e, i as t, n, r, s as i, t as a } from "./uninstall-4Qp75twq.js";
3
+ import { readFileSync as o } from "node:fs";
4
+ import { dirname as s, resolve as c } from "node:path";
5
+ import { fileURLToPath as l } from "node:url";
6
+ import { homedir as u } from "node:os";
48
7
  //#region src/cli.ts
49
- var { version: E } = JSON.parse(f(g(m(_(import.meta.url)), "..", "package.json"), "utf8")), D = Math.max(...a.map((e) => `${e.name} ${e.args}`.length)), O = [
8
+ var { version: d } = JSON.parse(o(c(s(l(import.meta.url)), "..", "package.json"), "utf8")), f = Math.max(...t.map((e) => `${e.name} ${e.args}`.length)), p = [
50
9
  "Usage: tracerkit <command> [path]",
51
10
  "",
52
11
  "Commands:",
53
- ...a.map((e) => ` ${`${e.name} ${e.args}`.padEnd(D + 2)}${e.desc}`),
12
+ ...t.map((e) => ` ${`${e.name} ${e.args}`.padEnd(f + 2)}${e.desc}`),
54
13
  "",
55
14
  "Options:",
56
15
  " --force Overwrite modified files during update",
57
16
  " --help, -h Show this help message",
58
17
  " --version, -v Print version",
59
18
  "",
60
- "init/update/uninstall default to the home directory when no path is given.",
61
- "config defaults to the current working directory."
19
+ "Defaults to the home directory when no path is given."
62
20
  ];
63
- function k(e) {
64
- if (!e) return !1;
65
- try {
66
- return p(g(e)).isDirectory();
67
- } catch {
68
- return !1;
69
- }
70
- }
71
- function A(e, t = v()) {
21
+ function m(e, t = u()) {
72
22
  let n = e.find((e) => !e.startsWith("-"));
73
- return n ? g(n) : t;
74
- }
75
- function j(e) {
76
- if (e.includes(r.help) || e.includes("-h")) return O;
77
- if (e.includes(r.version) || e.includes("-v")) return [`tracerkit/${E}`];
78
- let t = e[0], a = e.slice(1);
79
- if (c.includes(t)) return [`"${t}" has been removed — skills handle this now.`, "Run `tracerkit update` to get the latest skills."];
80
- switch (t) {
81
- case "init": return s(A(a));
23
+ return n ? c(n) : t;
24
+ }
25
+ function h(t) {
26
+ if (t.includes(i.help) || t.includes("-h")) return p;
27
+ if (t.includes(i.version) || t.includes("-v")) return [`tracerkit/${d}`];
28
+ let o = t[0], s = t.slice(1);
29
+ if (e.includes(o)) return [`"${o}" has been removed — skills handle this now.`, "Run `tracerkit update` to get the latest skills."];
30
+ switch (o) {
31
+ case "init": return n(m(s));
82
32
  case "update": {
83
- let e = a.includes(r.force), t = n(A(a.filter((e) => e !== r.force)), { force: e });
33
+ let e = s.includes(i.force), t = r(m(s.filter((e) => e !== i.force)), { force: e });
84
34
  return t.push("", "Updated to the latest TracerKit."), t.push("If using Claude Code, restart your session to load changes."), t;
85
35
  }
86
- case "config": {
87
- let e = k(a[0]);
88
- return y(e ? g(a[0]) : process.cwd(), e ? a.slice(1) : a);
89
- }
90
- case "uninstall": return l(A(a));
91
- case "migrate-storage": return i(k(a[0]) ? g(a[0]) : process.cwd());
92
- default: return O;
36
+ case "uninstall": return a(m(s));
37
+ default: return p;
93
38
  }
94
39
  }
95
40
  //#endregion
96
41
  //#region src/bin.ts
97
- var M = j(process.argv.slice(2));
98
- for (let e of M) console.log(e);
42
+ var g = h(process.argv.slice(2));
43
+ for (let e of g) console.log(e);
99
44
  //#endregion
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import { c as e, i as t, n, o as r, r as i, t as a, u as o } from "./uninstall-CNGQ7MEU.js";
2
- export { r as COMMANDS, e as DEPRECATED_SKILLS, o as SKILL_NAMES, i as init, n as migrateStorage, a as uninstall, t as update };
1
+ import { c as e, i as t, n, o as r, r as i, t as a } from "./uninstall-4Qp75twq.js";
2
+ export { t as COMMANDS, r as DEPRECATED_SKILLS, e as SKILL_NAMES, n as init, a as uninstall, i as update };
@@ -0,0 +1,130 @@
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
+ var u = [
6
+ "tk:brief",
7
+ "tk:prd",
8
+ "tk:plan",
9
+ "tk:build",
10
+ "tk:check"
11
+ ], d = ["tk:verify"], f = {
12
+ force: "--force",
13
+ help: "--help",
14
+ version: "--version"
15
+ }, p = [
16
+ "brief",
17
+ "progress",
18
+ "archive",
19
+ "config",
20
+ "migrate-storage"
21
+ ], m = [
22
+ {
23
+ name: "init",
24
+ args: "[path]",
25
+ desc: "Install skills to ~/.claude/skills/ (or [path] if given)"
26
+ },
27
+ {
28
+ name: "update",
29
+ args: "[path]",
30
+ desc: "Refresh unchanged files from latest version, skip modified"
31
+ },
32
+ {
33
+ name: "uninstall",
34
+ args: "[path]",
35
+ desc: "Remove TracerKit skill directories, keep .tracerkit/ artifacts"
36
+ }
37
+ ], h = s(o(l(import.meta.url)), "..", "skills");
38
+ function g(e, t = "") {
39
+ let n = r(e, { withFileTypes: !0 }), i = [];
40
+ for (let r of n) {
41
+ let n = t ? `${t}/${r.name}` : r.name;
42
+ r.isDirectory() ? i.push(...g(s(e, r.name), n)) : i.push(n);
43
+ }
44
+ return i.sort();
45
+ }
46
+ function _(e) {
47
+ return `.claude/skills/tk:${e}`;
48
+ }
49
+ function v(e) {
50
+ return e.slice(18);
51
+ }
52
+ function y(e, r) {
53
+ let i = r ?? g(h).map(_);
54
+ for (let r of i) {
55
+ let i = s(h, v(r)), c = s(e, r);
56
+ t(o(c), { recursive: !0 }), a(c, n(i, "utf8"));
57
+ }
58
+ return { copied: i };
59
+ }
60
+ function b(e) {
61
+ return c("sha256").update(e).digest("hex");
62
+ }
63
+ function x(t) {
64
+ let r = g(h).map(_), i = [], a = [], o = [];
65
+ for (let c of r) {
66
+ let r = s(t, c);
67
+ if (!e(r)) o.push(c);
68
+ else {
69
+ let e = n(s(h, v(c)), "utf8");
70
+ b(Buffer.from(e)) === b(n(r)) ? i.push(c) : a.push(c);
71
+ }
72
+ }
73
+ return {
74
+ unchanged: i,
75
+ modified: a,
76
+ missing: o
77
+ };
78
+ }
79
+ //#endregion
80
+ //#region src/commands/update.ts
81
+ function S(t, n) {
82
+ if (!u.some((n) => e(s(t, ".claude", "skills", n)))) throw Error("TracerKit not initialized — run `tracerkit init` first");
83
+ let { unchanged: r, modified: a, missing: o } = x(t), c = [];
84
+ for (let n of d) {
85
+ let r = s(t, ".claude", "skills", n);
86
+ e(r) && (i(r, {
87
+ recursive: !0,
88
+ force: !0
89
+ }), c.push(`✗ .claude/skills/${n}/ removed (deprecated)`));
90
+ }
91
+ let l = n?.force ?? !1, f = [
92
+ ...r,
93
+ ...o,
94
+ ...l ? a : []
95
+ ];
96
+ if (f.length > 0) {
97
+ y(t, f);
98
+ for (let e of r) c.push(`✓ ${e}`);
99
+ for (let e of o) c.push(`✓ ${e} (added)`);
100
+ if (l) for (let e of a) c.push(`✓ ${e} (replaced)`);
101
+ }
102
+ if (!l && a.length > 0) {
103
+ for (let e of a) c.push(`⚠ ${e} (skipped — modified)`);
104
+ c.push("", "Run `tracerkit update --force` to replace modified files with latest versions.");
105
+ }
106
+ return c;
107
+ }
108
+ //#endregion
109
+ //#region src/commands/init.ts
110
+ function C(t) {
111
+ if (u.some((n) => e(s(t, ".claude", "skills", n)))) return S(t, { force: !1 });
112
+ let { copied: n } = y(t);
113
+ return n.map((e) => `✓ ${e}`);
114
+ }
115
+ //#endregion
116
+ //#region src/commands/uninstall.ts
117
+ function w(t) {
118
+ if (!u.some((n) => e(s(t, ".claude", "skills", n)))) throw Error("TracerKit not initialized — nothing to uninstall");
119
+ let n = [];
120
+ for (let r of u) {
121
+ let a = s(t, ".claude", "skills", r);
122
+ e(a) && (i(a, {
123
+ recursive: !0,
124
+ force: !0
125
+ }), n.push(`✗ .claude/skills/${r}/ removed`));
126
+ }
127
+ return n;
128
+ }
129
+ //#endregion
130
+ export { p as a, u as c, m as i, C as n, d as o, S as r, f as s, w as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tracerkit",
3
- "version": "1.19.0",
3
+ "version": "1.19.2",
4
4
  "description": "Spec-driven workflow for AI coding agents — PRD → plan → build → verify. Pure Markdown skills, zero runtime deps.",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -2,59 +2,26 @@
2
2
  description: Session briefing — shows active features, progress, and suggested focus. Use at the start of a session, when asking what to work on, or when checking active features.
3
3
  ---
4
4
 
5
- **Config**: read `.tracerkit/config.json` (default: `local`). Follow matching `<!-- if:local/github -->` blocks.
6
-
7
5
  # Session Briefing
8
6
 
9
7
  Overview of active features, progress, and suggested focus.
10
8
 
11
9
  ## Pre-loaded context
12
10
 
13
- <!-- if:local -->
14
-
15
11
  - Available PRDs: !`ls .tracerkit/prds/*.md 2>/dev/null || echo "(none)"`
16
- <!-- end:local -->
17
- <!-- if:github -->
18
- - Available PRDs: list open GitHub Issues with label `{{github.labels.prd}}`
19
- <!-- end:github -->
20
12
 
21
13
  ## Algorithm
22
14
 
23
15
  ### 1. Discover features
24
16
 
25
- <!-- if:local -->
26
-
27
17
  For each `.md` file in `.tracerkit/prds/`: parse frontmatter, extract `status` and `created`. Skip `status: done`. Slug = filename without `.md`.
28
18
 
29
- <!-- end:local -->
30
- <!-- if:github -->
31
-
32
- List open GitHub Issues with label `{{github.labels.prd}}`:
33
-
34
- 1. For each issue, parse the `<!-- tk:metadata -->` comment in the body
35
- 2. Extract `status` and `created` fields from the metadata
36
- 3. Also check labels: `tk:created`, `tk:in-progress`
37
- 4. Skip issues with `tk:done` label
38
- 5. The slug is extracted from the title: `[{{github.labels.prd}}] <slug>: ...`
39
- <!-- end:github -->
40
-
41
19
  ### 2. Count progress from plans
42
20
 
43
- <!-- if:local -->
44
-
45
21
  For each slug with a plan at `.tracerkit/plans/<slug>.md`:
46
22
 
47
23
  Count `- [x]` and `- [ ]` lines under each `## Phase N` heading. Sum → `checked/total`. First unchecked item → "Next" (strip trailing `[tag]`). No plan → `—`.
48
24
 
49
- <!-- end:local -->
50
- <!-- if:github -->
51
-
52
- For each slug, find plan issue with label `{{github.labels.plan}}` and matching title. If found:
53
-
54
- Count `- [x]` and `- [ ]` lines under each `## Phase N` heading. Sum → `checked/total`. First unchecked item → "Next" (strip trailing `[tag]`). No plan → `—`.
55
-
56
- <!-- end:github -->
57
-
58
25
  ### 3. Build the table
59
26
 
60
27
  Sort by `created` ascending (no-date last). Age from `created`:
@@ -89,13 +56,8 @@ Append below the table:
89
56
 
90
57
  ### 5. Offer next steps
91
58
 
92
- <!-- if:local -->
93
-
94
- Options: continue focused feature (read plan at `.tracerkit/plans/<slug>.md`), `/tk:prd` for new feature, `/tk:check <slug>` for progress.
95
-
96
- <!-- end:local -->
97
- <!-- if:github -->
98
-
99
- Options: continue focused feature (read plan issue), `/tk:prd` for new feature, `/tk:check <slug>` for progress.
59
+ Present options and wait for the user's choice:
100
60
 
101
- <!-- end:github -->
61
+ 1. Continue focused feature — read plan at `.tracerkit/plans/<slug>.md` (Recommended)
62
+ 2. Start new feature — `/tk:prd`
63
+ 3. Check progress — `/tk:check <slug>`
@@ -3,8 +3,6 @@ description: Implement one phase of a plan. Reads plan, finds next incomplete ph
3
3
  argument-hint: '[slug]'
4
4
  ---
5
5
 
6
- **Config**: read `.tracerkit/config.json` (default: `local`). Follow matching `<!-- if:local/github -->` blocks.
7
-
8
6
  # Build Phase
9
7
 
10
8
  Implement the next incomplete phase of a plan — one phase per invocation.
@@ -15,19 +13,13 @@ Implement the next incomplete phase of a plan — one phase per invocation.
15
13
 
16
14
  ## Pre-loaded context
17
15
 
18
- <!-- if:local -->
19
-
20
16
  - Available plans: !`ls .tracerkit/plans/*.md 2>/dev/null || echo "(none)"`
21
- <!-- end:local -->
22
- <!-- if:github -->
23
- - Available plans: list open GitHub Issues with label `{{github.labels.plan}}`
24
- <!-- end:github -->
25
17
 
26
18
  ## Input
27
19
 
28
20
  The argument (if provided) is: $ARGUMENTS
29
21
 
30
- Use argument as `<slug>`. If empty, list available plans and ask the user to select one.
22
+ Use argument as `<slug>`. If empty, list plans as numbered options and wait for the user's choice.
31
23
 
32
24
  Accepts slug or `@file` reference:
33
25
 
@@ -42,16 +34,7 @@ If argument starts with `@`, treat it as a file path — read that file directly
42
34
 
43
35
  ### 1. Load the plan
44
36
 
45
- <!-- if:local -->
46
-
47
- Read `.tracerkit/plans/<slug>.md`. If missing, list plans and ask the user to select one.
48
-
49
- <!-- end:local -->
50
- <!-- if:github -->
51
-
52
- Find plan issue: open issue with label `{{github.labels.plan}}`, title matching `[{{github.labels.plan}}] <slug>:`. If missing, list plans and ask the user to select one.
53
-
54
- <!-- end:github -->
37
+ Read `.tracerkit/plans/<slug>.md`. If missing, list plans as numbered options and wait for the user's choice.
55
38
 
56
39
  ### 2. Find the next incomplete phase
57
40
 
@@ -134,18 +117,7 @@ Wait for the user's response before continuing.
134
117
 
135
118
  ### 7. Mark checkboxes
136
119
 
137
- After all feedback loops pass, update checkboxes in the plan file:
138
-
139
- <!-- if:local -->
140
-
141
- For each completed item, change `- [ ]` → `- [x]` in `.tracerkit/plans/<slug>.md`.
142
-
143
- <!-- end:local -->
144
- <!-- if:github -->
145
-
146
- For each completed item, change `- [ ]` → `- [x]` in the plan issue body using `gh issue edit`.
147
-
148
- <!-- end:github -->
120
+ After all feedback loops pass, for each completed item change `- [ ]` → `- [x]` in `.tracerkit/plans/<slug>.md`.
149
121
 
150
122
  ### 8. Offer commit
151
123
 
@@ -3,8 +3,6 @@ description: Verify implementation against plan. Shows progress, finds blockers,
3
3
  argument-hint: '[slug]'
4
4
  ---
5
5
 
6
- **Config**: read `.tracerkit/config.json` (default: `local`). Follow matching `<!-- if:local/github -->` blocks.
7
-
8
6
  # Check Implementation
9
7
 
10
8
  Check implementation against a plan. Update checks, stamp findings, transition status, and mark complete when done.
@@ -13,13 +11,7 @@ Check implementation against a plan. Update checks, stamp findings, transition s
13
11
 
14
12
  ## Pre-loaded context
15
13
 
16
- <!-- if:local -->
17
-
18
14
  - Available plans: !`ls .tracerkit/plans/*.md 2>/dev/null || echo "(none)"`
19
- <!-- end:local -->
20
- <!-- if:github -->
21
- - Available plans: list open GitHub Issues with label `{{github.labels.plan}}`
22
- <!-- end:github -->
23
15
 
24
16
  ## Input
25
17
 
@@ -35,24 +27,13 @@ If no argument is provided, build a summary table before asking which one to che
35
27
  | <slug> | ... | 3/7 |
36
28
  ```
37
29
 
38
- <!-- if:local -->
39
-
40
30
  For each `.md` file in `.tracerkit/prds/`:
41
31
 
42
32
  1. Read the file, parse YAML frontmatter (block between `---` fences)
43
33
  2. Extract `status` — use `unknown` if missing
44
34
  3. If `.tracerkit/plans/<slug>.md` exists, count progress (see Progress Algorithm below). Show `—` if no plan.
45
- <!-- end:local -->
46
- <!-- if:github -->
47
-
48
- List open GitHub Issues with label `{{github.labels.prd}}`:
49
35
 
50
- 4. For each PRD issue, extract `status` from labels (`tk:created`, `tk:in-progress`)
51
- 5. Find matching plan issue with label `{{github.labels.plan}}` and same slug in title
52
- 6. If plan issue exists, count progress from checkboxes in its body (see Progress Algorithm below). Show `—` if no plan.
53
- <!-- end:github -->
54
-
55
- Present each feature as an option and let the user pick which to verify.
36
+ Present each feature as a numbered option and wait for the user's choice.
56
37
 
57
38
  ## Progress Algorithm
58
39
 
@@ -62,30 +43,12 @@ Count `- [x]` and `- [ ]` lines under each `## Phase N` heading. Per-phase: `Pha
62
43
 
63
44
  ### 1. Load the plan
64
45
 
65
- <!-- if:local -->
66
-
67
- Read `.tracerkit/plans/<slug>.md`. If missing, list plans and ask the user to select one.
68
-
69
- <!-- end:local -->
70
- <!-- if:github -->
71
-
72
- Find plan issue: open issue with label `{{github.labels.plan}}`, title matching `[{{github.labels.plan}}] <slug>:`. If missing, list plans and ask the user to select one.
73
-
74
- <!-- end:github -->
46
+ Read `.tracerkit/plans/<slug>.md`. If missing, list plans as numbered options and wait for the user's choice.
75
47
 
76
48
  ### 2. Load the PRD
77
49
 
78
- <!-- if:local -->
79
-
80
50
  Read source PRD referenced in plan header (`> Source PRD: ...`).
81
51
 
82
- <!-- end:local -->
83
- <!-- if:github -->
84
-
85
- Read source PRD issue referenced in plan body (`> Source PRD: #<number>`).
86
-
87
- <!-- end:github -->
88
-
89
52
  ### 3. Fast-path: check if implementation exists
90
53
 
91
54
  If primary module file(s) from Phase 1 don't exist, skip subagent — report `0/N — not yet started`, list Phase 1 done-when items, jump to Step 5.
@@ -108,17 +71,8 @@ Collect findings into two categories:
108
71
 
109
72
  ### 3c. Update checkboxes
110
73
 
111
- <!-- if:local -->
112
-
113
74
  Using the subagent's report, update each checkbox in `.tracerkit/plans/<slug>.md` to `[x]` or `[ ]`.
114
75
 
115
- <!-- end:local -->
116
- <!-- if:github -->
117
-
118
- Using the subagent's report, update each checkbox in the plan issue body to `[x]` or `[ ]` by editing the issue.
119
-
120
- <!-- end:github -->
121
-
122
76
  ### 4. Determine outcome
123
77
 
124
78
  Based on checks and findings, decide the status transition:
@@ -153,17 +107,8 @@ Total: checked/total
153
107
 
154
108
  ### 6. Stamp the plan
155
109
 
156
- <!-- if:local -->
157
-
158
110
  Append a verdict block at the bottom of `.tracerkit/plans/<slug>.md`:
159
111
 
160
- <!-- end:local -->
161
- <!-- if:github -->
162
-
163
- Append a verdict block at the bottom of the plan issue body by editing the issue:
164
-
165
- <!-- end:github -->
166
-
167
112
  ```markdown
168
113
  ---
169
114
 
@@ -181,24 +126,9 @@ If a previous verdict block exists, replace it with the new one.
181
126
 
182
127
  If all checks pass and zero BLOCKERS:
183
128
 
184
- <!-- if:local -->
185
-
186
129
  1. Update PRD frontmatter: `status: done`, add `completed: <UTC ISO 8601>`
187
130
  2. Update plan frontmatter: `status: done`, add `completed: <UTC ISO 8601>`
188
131
 
189
- <!-- end:local -->
190
- <!-- if:github -->
191
-
192
- 1. If on a feature branch with commits ahead of default:
193
- a. Push branch if not pushed
194
- b. Open PR with `Closes #<prd-number>, Closes #<plan-number>` (or update existing PR body)
195
- 2. Search merged PRs matching slug: `gh pr list --search <slug> --state merged` — add comment on PRD issue linking found PRs
196
- 3. PRD issue: add `tk:done`, remove `tk:in-progress`, update metadata `status: done` + `completed` timestamp
197
- 4. Close PRD issue (reason: `completed`)
198
- 5. Close plan issue (reason: `completed`)
199
-
200
- <!-- end:github -->
201
-
202
132
  ### 8. On `in_progress` (no blockers)
203
133
 
204
134
  Show progress summary (checked/total per phase), list the next unchecked items to implement. Keep going.
@@ -3,71 +3,39 @@ description: Turn a PRD into a multi-phase implementation plan using tracer-bull
3
3
  argument-hint: '[slug]'
4
4
  ---
5
5
 
6
- **Config**: read `.tracerkit/config.json` (default: `local`). Follow matching `<!-- if:local/github -->` blocks.
7
-
8
6
  # PRD to Plan
9
7
 
10
8
  Break a PRD into phased vertical slices (tracer bullets).
11
9
 
12
10
  **Interactive prompts**: present options as a numbered list and wait for the user's choice.
13
11
 
14
- <!-- if:local -->
15
-
16
12
  Output: `.tracerkit/plans/<slug>.md`.
17
13
 
18
- <!-- end:local -->
19
- <!-- if:github -->
20
-
21
- Output: a GitHub Issue with label `{{github.labels.plan}}`.
22
-
23
- <!-- end:github -->
24
-
25
14
  ## Pre-loaded context
26
15
 
27
- <!-- if:local -->
28
-
29
16
  - Available PRDs: !`ls .tracerkit/prds/*.md 2>/dev/null || echo "(none)"`
30
- <!-- end:local -->
31
- <!-- if:github -->
32
- - Available PRDs: list open GitHub Issues with label `{{github.labels.prd}}`
33
- <!-- end:github -->
34
17
 
35
18
  ## Input
36
19
 
37
20
  The argument (if provided) is: $ARGUMENTS
38
21
 
39
- Use argument as `<slug>`. If empty, list available PRDs and ask the user to select one.
22
+ Use argument as `<slug>`. If empty, list PRDs as numbered options and wait for the user's choice.
40
23
 
41
24
  ## Workflow
42
25
 
43
26
  ### 1. Read the PRD
44
27
 
45
- <!-- if:local -->
46
-
47
- Read `.tracerkit/prds/<slug>.md`. If missing, list PRDs and ask the user to select one. If `.tracerkit/plans/<slug>.md` exists, ask: "Overwrite existing" / "Pick a new name".
28
+ Read `.tracerkit/prds/<slug>.md`. If missing, list PRDs as numbered options and wait for the user's choice.
48
29
 
49
- <!-- end:local -->
50
- <!-- if:github -->
30
+ If `.tracerkit/plans/<slug>.md` exists, present options and wait:
51
31
 
52
- Find PRD issue: open issue with label `{{github.labels.prd}}`, title matching `[{{github.labels.prd}}] <slug>:`. If missing, list PRDs and ask the user to select one. If plan issue with label `{{github.labels.plan}}` and matching title exists, ask: "Update existing plan" / "Use a new name".
53
-
54
- <!-- end:github -->
32
+ 1. Overwrite existing (Recommended)
33
+ 2. Pick a new name
55
34
 
56
35
  ### 1b. Update PRD status
57
36
 
58
- <!-- if:local -->
59
-
60
37
  Set `status: in_progress` in `.tracerkit/prds/<slug>.md` frontmatter. Change only `status`.
61
38
 
62
- <!-- end:local -->
63
- <!-- if:github -->
64
-
65
- Update the PRD issue:
66
-
67
- - Remove `tk:created` label, add `tk:in-progress` label
68
- - Update the `<!-- tk:metadata -->` comment in the issue body to `status: in_progress`
69
- <!-- end:github -->
70
-
71
39
  ### 2. Explore the codebase
72
40
 
73
41
  Map architecture, patterns, integration points. Skip if codebase context exists from prior step.
@@ -112,7 +80,9 @@ Each phase: thin vertical slice through all layers (schema → service → API
112
80
 
113
81
  - 1 module touched → 2–3 phases max
114
82
  - 2–3 modules touched → 3–5 phases max
115
- - 4+ modules or 6+ phases → stop and ask: "PRD touches 4+ modules. Split before planning?" with options: "Split the PRD" (Recommended) / "Continue anyway".
83
+ - 4+ modules or 6+ phases → stop and present options:
84
+ 1. Split the PRD (Recommended)
85
+ 2. Continue anyway
116
86
 
117
87
  Count "modules touched" by scanning the PRD's New Modules and Schema Changes sections.
118
88
 
@@ -124,11 +94,15 @@ Assign an agent tag to tasks where appropriate:
124
94
 
125
95
  ### 5. Quiz the user
126
96
 
127
- Present breakdown (title, user stories covered, done-when per phase). Ask: "How's the granularity?" with options: "Looks good, proceed" (Recommended) / "Merge some phases" / "Split a phase". Iterate until approved.
97
+ Present breakdown (title, user stories covered, done-when per phase). Present options and wait:
128
98
 
129
- ### 6. Save plan
99
+ 1. Looks good, proceed (Recommended)
100
+ 2. Merge some phases
101
+ 3. Split a phase
130
102
 
131
- <!-- if:local -->
103
+ Iterate until approved.
104
+
105
+ ### 6. Save plan
132
106
 
133
107
  Save to `.tracerkit/plans/<slug>.md` (create dir if missing).
134
108
 
@@ -144,41 +118,7 @@ status: in_progress
144
118
  > Source PRD: `.tracerkit/prds/<slug>.md`
145
119
  ```
146
120
 
147
- Then update PRD frontmatter: add `plan: .tracerkit/plans/<slug>.md` field.
148
-
149
- <!-- end:local -->
150
- <!-- if:github -->
151
-
152
- Ensure labels exist: `gh label create {{github.labels.plan}} --force`, `gh label create tk:in-progress --force`.
153
-
154
- Create GitHub Issue — title: `[{{github.labels.plan}}] <slug>: Plan: <Feature Title>`, labels: `{{github.labels.plan}}`, `tk:in-progress`.
155
-
156
- ```markdown
157
- <!-- tk:metadata
158
- source_prd: #<PRD issue number>
159
- slug: <slug>
160
- status: in_progress
161
- -->
162
-
163
- # Plan: <Feature Name>
164
-
165
- > Source PRD: #<PRD issue number>
166
- ```
167
-
168
- <!-- end:github -->
169
-
170
- ### 6b. Backlink PRD
171
-
172
- <!-- if:local -->
173
-
174
- Already linked via PRD frontmatter `plan:` field (set in step 6).
175
-
176
- <!-- end:local -->
177
- <!-- if:github -->
178
-
179
- Add comment on PRD issue: "Plan: #<plan-issue-number>" (creates cross-reference).
180
-
181
- <!-- end:github -->
121
+ Then update PRD frontmatter: add `plan: .tracerkit/plans/<slug>.md` field (creates backlink).
182
122
 
183
123
  Use this structure for the plan body:
184
124
 
@@ -217,7 +157,11 @@ Carried forward from PRD verbatim.
217
157
  Gaps found in the PRD needing resolution. Blank if none.
218
158
  ```
219
159
 
220
- Print one line per phase: `Phase N — <title> (<condition summary>)`. Then ask: "What's next?" with options: "Run `/tk:build <slug>`" (Recommended) / "Run `/tk:check <slug>`" / "Done for now".
160
+ Print one line per phase: `Phase N — <title> (<condition summary>)`. Present options and wait:
161
+
162
+ 1. Run `/tk:build <slug>` (Recommended)
163
+ 2. Run `/tk:check <slug>`
164
+ 3. Done for now
221
165
 
222
166
  ## Execution guidance
223
167
 
@@ -229,10 +173,5 @@ To implement this plan phase by phase, run `/tk:build <slug>`. It handles branch
229
173
  - Each phase must be demoable end-to-end on its own
230
174
  - "Done when" must be a checkbox list of testable conditions, not prose
231
175
  - **Safety valve**: if a phase has >5 "Done when" items, stop and split it into smaller phases before continuing
232
- <!-- if:local -->
233
176
  - Never modify the source PRD content — only update frontmatter status fields
234
- <!-- end:local -->
235
- <!-- if:github -->
236
- - Never modify the source PRD content — only update metadata and labels
237
- <!-- end:github -->
238
177
  - Carry PRD's Out of Scope forward verbatim
@@ -3,8 +3,6 @@ description: Create a PRD through user interview, codebase exploration, and modu
3
3
  argument-hint: <idea>
4
4
  ---
5
5
 
6
- **Config**: read `.tracerkit/config.json` (default: `local`). Follow matching `<!-- if:local/github -->` blocks.
7
-
8
6
  # PRD Writing
9
7
 
10
8
  Skip satisfied steps. If argument provided, skip to Step 2.
@@ -13,13 +11,7 @@ Skip satisfied steps. If argument provided, skip to Step 2.
13
11
 
14
12
  ## Pre-loaded context
15
13
 
16
- <!-- if:local -->
17
-
18
14
  - Existing PRDs: !`ls .tracerkit/prds/*.md 2>/dev/null || echo "(none)"`
19
- <!-- end:local -->
20
- <!-- if:github -->
21
- - Existing PRDs: list open GitHub Issues with label `{{github.labels.prd}}`
22
- <!-- end:github -->
23
15
 
24
16
  ## Input
25
17
 
@@ -34,16 +26,10 @@ If empty, go to Step 1; derive slug after gathering the idea. If provided, deriv
34
26
  5. Take the first 4 remaining words (or fewer if less exist)
35
27
  6. Join with hyphens → `<slug>`
36
28
 
37
- <!-- if:local -->
38
-
39
- Output: `.tracerkit/prds/<slug>.md`. If exists, ask: "Overwrite existing" / "Pick a new name".
40
-
41
- <!-- end:local -->
42
- <!-- if:github -->
43
-
44
- Output: GitHub Issue with label `{{github.labels.prd}}`, title `[{{github.labels.prd}}] <slug>: <Feature Title>`. If matching issue exists, ask: "Update existing issue" / "Use a new slug".
29
+ Output: `.tracerkit/prds/<slug>.md`. If file exists, present options and wait:
45
30
 
46
- <!-- end:github -->
31
+ 1. Overwrite existing (Recommended)
32
+ 2. Pick a new name
47
33
 
48
34
  ## Workflow
49
35
 
@@ -85,8 +71,6 @@ Present modules. Confirm which need tests.
85
71
 
86
72
  ### 5. Write PRD
87
73
 
88
- <!-- if:local -->
89
-
90
74
  Save to `.tracerkit/prds/<slug>.md` (create dir if missing).
91
75
 
92
76
  ```markdown
@@ -98,26 +82,7 @@ status: created
98
82
  # Feature Name
99
83
  ```
100
84
 
101
- <!-- end:local -->
102
- <!-- if:github -->
103
-
104
- Ensure labels exist: `gh label create {{github.labels.prd}} --force`, `gh label create tk:created --force`.
105
-
106
- Create GitHub Issue — title: `[{{github.labels.prd}}] <slug>: <Feature Title>`, labels: `{{github.labels.prd}}`, `tk:created`.
107
-
108
- ```markdown
109
- <!-- tk:metadata
110
- slug: <slug>
111
- created: <UTC ISO 8601>
112
- status: created
113
- -->
114
-
115
- # Feature Name
116
- ```
117
-
118
- <!-- end:github -->
119
-
120
- PRD body structure (same for local file and issue body). Omit empty sections. No file paths or code snippets.
85
+ PRD body structure. Omit empty sections. No file paths or code snippets.
121
86
 
122
87
  ```
123
88
  ## Problem Statement
@@ -136,4 +101,7 @@ PRD body structure (same for local file and issue body). Omit empty sections. No
136
101
 
137
102
  ---
138
103
 
139
- Then ask: "What's next?" with options: "Run `/tk:plan <slug>`" (Recommended) / "Done for now".
104
+ Present options and wait for the user's choice:
105
+
106
+ 1. Run `/tk:plan <slug>` (Recommended)
107
+ 2. Done for now
@@ -1,468 +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 { basename as o, dirname as s, join as c } from "node:path";
3
- import { createHash as l } from "node:crypto";
4
- import { fileURLToPath as u } from "node:url";
5
- import { execSync as d } from "node:child_process";
6
- //#region src/config.ts
7
- var f = "local", p = "github", m = [f, p], h = {
8
- prds: ".tracerkit/prds",
9
- plans: ".tracerkit/plans"
10
- }, g = { labels: {
11
- prd: "tk:prd",
12
- plan: "tk:plan"
13
- } };
14
- function _(t) {
15
- let r = c(t, ".tracerkit", "config.json");
16
- if (!e(r)) return {
17
- storage: f,
18
- paths: { ...h },
19
- github: { ...g }
20
- };
21
- let i;
22
- try {
23
- i = JSON.parse(n(r, "utf8"));
24
- } catch {
25
- throw Error("Invalid .tracerkit/config.json — expected valid JSON");
26
- }
27
- return {
28
- storage: ee(i.storage),
29
- paths: v(i.paths),
30
- github: y(i.github)
31
- };
32
- }
33
- function ee(e) {
34
- return typeof e == "string" && m.includes(e) ? e : f;
35
- }
36
- function v(e) {
37
- let t = S(e) ? e : {};
38
- return {
39
- prds: typeof t.prds == "string" ? t.prds : h.prds,
40
- plans: typeof t.plans == "string" ? t.plans : h.plans
41
- };
42
- }
43
- function y(e) {
44
- let t = S(e) ? e : {}, n = S(t.labels) ? t.labels : {};
45
- return { labels: {
46
- prd: typeof n.prd == "string" ? n.prd : g.labels.prd,
47
- plan: typeof n.plan == "string" ? n.plan : g.labels.plan
48
- } };
49
- }
50
- function b(r, i) {
51
- let o = c(r, ".tracerkit", "config.json");
52
- t(s(o), { recursive: !0 });
53
- let l = {};
54
- if (e(o)) try {
55
- l = JSON.parse(n(o, "utf8"));
56
- } catch {
57
- l = {};
58
- }
59
- let u = x(l, i);
60
- a(o, JSON.stringify(u, null, 2) + "\n");
61
- }
62
- function x(e, t) {
63
- let n = { ...e };
64
- for (let e of Object.keys(t)) S(n[e]) && S(t[e]) ? n[e] = x(n[e], t[e]) : n[e] = t[e];
65
- return n;
66
- }
67
- function S(e) {
68
- return typeof e == "object" && !!e && !Array.isArray(e);
69
- }
70
- var C = [
71
- "tk:brief",
72
- "tk:prd",
73
- "tk:plan",
74
- "tk:build",
75
- "tk:check"
76
- ], w = ["tk:verify"], T = {
77
- force: "--force",
78
- help: "--help",
79
- version: "--version"
80
- }, E = [
81
- "brief",
82
- "progress",
83
- "archive"
84
- ], D = [
85
- {
86
- name: "init",
87
- args: "[path]",
88
- desc: "Install skills to ~/.claude/skills/ (or [path] if given)"
89
- },
90
- {
91
- name: "update",
92
- args: "[path]",
93
- desc: "Refresh unchanged files from latest version, skip modified"
94
- },
95
- {
96
- name: "config",
97
- args: "[path] [key] [value]",
98
- desc: "Get or set TracerKit configuration"
99
- },
100
- {
101
- name: "uninstall",
102
- args: "[path]",
103
- desc: "Remove TracerKit skill directories, keep .tracerkit/ artifacts"
104
- },
105
- {
106
- name: "migrate-storage",
107
- args: "[path]",
108
- desc: "Migrate artifacts between local and GitHub storage backends"
109
- }
110
- ], O = c(s(u(import.meta.url)), "..", "skills");
111
- function k(e, t = "") {
112
- let n = r(e, { withFileTypes: !0 }), i = [];
113
- for (let r of n) {
114
- let n = t ? `${t}/${r.name}` : r.name;
115
- r.isDirectory() ? i.push(...k(c(e, r.name), n)) : i.push(n);
116
- }
117
- return i.sort();
118
- }
119
- function A(e) {
120
- return `.claude/skills/tk:${e}`;
121
- }
122
- function j(e) {
123
- return e.slice(18);
124
- }
125
- function M(e, t) {
126
- let n = e;
127
- return t.paths.prds !== h.prds && (n = n.replaceAll(h.prds, t.paths.prds)), t.paths.plans !== h.plans && (n = n.replaceAll(h.plans, t.paths.plans)), t.github?.labels?.prd && (n = n.replaceAll("{{github.labels.prd}}", t.github.labels.prd)), t.github?.labels?.plan && (n = n.replaceAll("{{github.labels.plan}}", t.github.labels.plan)), n;
128
- }
129
- function N(e, r, i) {
130
- let o = i ?? k(O).map(A);
131
- for (let i of o) {
132
- let o = c(O, j(i)), l = c(e, i);
133
- t(s(l), { recursive: !0 }), a(l, M(n(o, "utf8"), r));
134
- }
135
- return { copied: o };
136
- }
137
- function P(e) {
138
- return l("sha256").update(e).digest("hex");
139
- }
140
- function F(t, r) {
141
- let i = k(O).map(A), a = [], o = [], s = [];
142
- for (let l of i) {
143
- let i = c(t, l);
144
- if (!e(i)) s.push(l);
145
- else {
146
- let e = M(n(c(O, j(l)), "utf8"), r);
147
- P(Buffer.from(e)) === P(n(i)) ? a.push(l) : o.push(l);
148
- }
149
- }
150
- return {
151
- unchanged: a,
152
- modified: o,
153
- missing: s
154
- };
155
- }
156
- //#endregion
157
- //#region src/commands/update.ts
158
- function I(t, n) {
159
- if (!C.some((n) => e(c(t, ".claude", "skills", n)))) throw Error("TracerKit not initialized — run `tracerkit init` first");
160
- let r = _(t), { unchanged: a, modified: o, missing: s } = F(t, r), l = [];
161
- for (let n of w) {
162
- let r = c(t, ".claude", "skills", n);
163
- e(r) && (i(r, {
164
- recursive: !0,
165
- force: !0
166
- }), l.push(`✗ .claude/skills/${n}/ removed (deprecated)`));
167
- }
168
- let u = n?.force ?? !1, d = [
169
- ...a,
170
- ...s,
171
- ...u ? o : []
172
- ];
173
- if (d.length > 0) {
174
- N(t, r, d);
175
- for (let e of a) l.push(`✓ ${e}`);
176
- for (let e of s) l.push(`✓ ${e} (added)`);
177
- if (u) for (let e of o) l.push(`✓ ${e} (replaced)`);
178
- }
179
- if (!u && o.length > 0) {
180
- for (let e of o) l.push(`⚠ ${e} (skipped — modified)`);
181
- l.push("", "Run `tracerkit update --force` to replace modified files with latest versions.");
182
- }
183
- return l;
184
- }
185
- //#endregion
186
- //#region src/commands/init.ts
187
- function te(t) {
188
- if (C.some((n) => e(c(t, ".claude", "skills", n)))) return I(t, { force: !1 });
189
- let { copied: n } = N(t, _(t));
190
- return n.map((e) => `✓ ${e}`);
191
- }
192
- //#endregion
193
- //#region src/commands/migrate-storage.ts
194
- var L = {
195
- created: "tk:created",
196
- in_progress: "tk:in-progress",
197
- done: "tk:done"
198
- }, R = {
199
- "tk:created": "created",
200
- "tk:in-progress": "in_progress",
201
- "tk:done": "done"
202
- };
203
- function z(e) {
204
- let t = e.match(/^---\n([\s\S]*?)---\n([\s\S]*)$/);
205
- if (!t) return {
206
- metadata: {},
207
- body: e
208
- };
209
- let n = {};
210
- for (let e of t[1].split("\n")) {
211
- let t = e.indexOf(":");
212
- if (t === -1) continue;
213
- let r = e.slice(0, t).trim(), i = e.slice(t + 1).trim();
214
- r && (n[r] = i);
215
- }
216
- return {
217
- metadata: n,
218
- body: t[2]
219
- };
220
- }
221
- function B(e) {
222
- let t = Object.entries(e);
223
- return t.length === 0 ? "<!-- tk:metadata\n-->" : `<!-- tk:metadata\n${t.map(([e, t]) => `${e}: ${t}`).join("\n")}\n-->`;
224
- }
225
- function V(e) {
226
- return L[e] ?? "tk:created";
227
- }
228
- function H(e) {
229
- let t = e.match(/<!--\s*tk:metadata\n([\s\S]*?)-->\n*([\s\S]*)$/);
230
- if (!t) return {
231
- metadata: {},
232
- body: e
233
- };
234
- let n = {};
235
- for (let e of t[1].split("\n")) {
236
- let t = e.indexOf(":");
237
- if (t === -1) continue;
238
- let r = e.slice(0, t).trim(), i = e.slice(t + 1).trim();
239
- r && (n[r] = i);
240
- }
241
- return {
242
- metadata: n,
243
- body: t[2]
244
- };
245
- }
246
- function U(e) {
247
- let t = Object.entries(e);
248
- return t.length === 0 ? "---\n---\n" : `---\n${t.map(([e, t]) => `${e}: ${t}`).join("\n")}\n---\n`;
249
- }
250
- function W(e) {
251
- let t = e.match(/\[[^\]]+\]\s+([^:]+):/);
252
- return t ? t[1].trim() : null;
253
- }
254
- function G(e) {
255
- let t = e.match(/^#\s+(.+)$/m);
256
- return t ? t[1].trim() : "Untitled";
257
- }
258
- function K(t, i) {
259
- let a = [], s = c(t, i.paths.prds);
260
- if (e(s)) for (let e of r(s)) {
261
- if (!e.endsWith(".md")) continue;
262
- let t = o(e, ".md"), { metadata: r, body: i } = z(n(c(s, e), "utf8"));
263
- a.push({
264
- slug: t,
265
- type: "prd",
266
- metadata: r,
267
- body: i,
268
- title: G(i)
269
- });
270
- }
271
- let l = c(t, i.paths.plans);
272
- if (e(l)) for (let e of r(l)) {
273
- if (!e.endsWith(".md")) continue;
274
- let t = o(e, ".md"), r = n(c(l, e), "utf8"), { metadata: i, body: s } = z(r);
275
- a.push({
276
- slug: t,
277
- type: "plan",
278
- metadata: i,
279
- body: s,
280
- title: G(s || r)
281
- });
282
- }
283
- return a;
284
- }
285
- function q(e) {
286
- let t = e;
287
- if (t.code === "ENOENT") return /* @__PURE__ */ Error("gh CLI not found — install it: https://cli.github.com");
288
- let n = (t.stderr ?? t.message ?? "").toLowerCase();
289
- return n.includes("not logged in") || n.includes("authentication") ? /* @__PURE__ */ Error("Not authenticated with GitHub. Run: gh auth login") : n.includes("rate limit") || n.includes("403") ? /* @__PURE__ */ Error("GitHub rate limit exceeded. Wait and retry.") : n.includes("not found") || n.includes("404") ? /* @__PURE__ */ Error("Repository not found. Check your git remote configuration.") : e instanceof Error ? e : Error(String(e));
290
- }
291
- function J(e) {
292
- try {
293
- return d(`gh ${e.map((e) => `'${e.replace(/'/g, "'\\''")}'`).join(" ")}`, {
294
- encoding: "utf8",
295
- stdio: [
296
- "pipe",
297
- "pipe",
298
- "pipe"
299
- ]
300
- }).trim();
301
- } catch (e) {
302
- throw q(e);
303
- }
304
- }
305
- function Y(e, t) {
306
- let n = t([
307
- "issue",
308
- "list",
309
- "--label",
310
- e,
311
- "--state",
312
- "all",
313
- "--json",
314
- "number,title,body,labels,state",
315
- "--limit",
316
- "1000"
317
- ]);
318
- return JSON.parse(n || "[]");
319
- }
320
- function X(e, t) {
321
- return t.some((t) => {
322
- if (t.body) {
323
- let { metadata: n } = H(t.body);
324
- if (n.slug) return n.slug === e;
325
- }
326
- return W(t.title) === e;
327
- });
328
- }
329
- function Z(e, t) {
330
- for (let n of e) t([
331
- "label",
332
- "create",
333
- n,
334
- "--force"
335
- ]);
336
- }
337
- function ne(e, t) {
338
- let n = [
339
- "issue",
340
- "create",
341
- "--title",
342
- e.title,
343
- "--body",
344
- e.body
345
- ];
346
- for (let t of e.labels) n.push("--label", t);
347
- let r = t(n).match(/\/(\d+)\s*$/);
348
- return r ? parseInt(r[1], 10) : 0;
349
- }
350
- function re(e, t) {
351
- t([
352
- "issue",
353
- "close",
354
- String(e)
355
- ]);
356
- }
357
- function ie(e, t) {
358
- let n = t([
359
- "pr",
360
- "list",
361
- "--search",
362
- e,
363
- "--state",
364
- "merged",
365
- "--json",
366
- "number,title",
367
- "--limit",
368
- "5"
369
- ]);
370
- return JSON.parse(n || "[]");
371
- }
372
- function ae(e, t, n) {
373
- n([
374
- "issue",
375
- "comment",
376
- String(e),
377
- "--body",
378
- t
379
- ]);
380
- }
381
- function oe(e) {
382
- for (let t of e) {
383
- let e = R[t];
384
- if (e) return e;
385
- }
386
- return "created";
387
- }
388
- function Q(e, n) {
389
- t(s(e), { recursive: !0 }), a(e, n);
390
- }
391
- function $(e, t) {
392
- let n = t?.runGh ?? J, r = _(e);
393
- return r.storage === "local" ? se(e, r, n) : le(e, r, n);
394
- }
395
- function se(e, t, n) {
396
- let r = [], i = K(e, t);
397
- if (i.length === 0) return b(e, { storage: p }), r.push("No artifacts found — nothing to migrate."), r.push(`✓ Storage switched to "${p}".`), r;
398
- let a = t.github.labels?.prd ?? "tk:prd", o = t.github.labels?.plan ?? "tk:plan";
399
- Z([
400
- a,
401
- o,
402
- ...[...new Set(i.map((e) => V(e.metadata.status ?? "created")))]
403
- ], n);
404
- let s = Y(a, n), c = Y(o, n);
405
- for (let e of i) {
406
- let t = e.type === "prd" ? a : o, i = e.type === "prd" ? s : c;
407
- if (X(e.slug, i)) {
408
- r.push(`⚠ skip ${e.type} "${e.slug}" — already exists on GitHub`);
409
- continue;
410
- }
411
- let l = e.metadata.status ?? "created", u = V(l), d = `${B(e.metadata)}\n\n${e.body.replace(/^\n/, "")}`, f = ne({
412
- title: `[${t}] ${e.slug}: ${e.title}`,
413
- body: d,
414
- labels: [t, u]
415
- }, n);
416
- l === "done" ? (re(f, n), ce(e.slug, f, n), r.push(`✓ ${e.type} "${e.slug}" → issue #${f} (closed)`)) : r.push(`✓ ${e.type} "${e.slug}" → issue #${f}`);
417
- }
418
- return b(e, { storage: p }), r.push(`✓ Storage switched to "${p}".`), r;
419
- }
420
- function ce(e, t, n) {
421
- let r = ie(e, n);
422
- r.length !== 0 && ae(t, `Linked PR: ${r.map((e) => `#${e.number}`).join(", ")}`, n);
423
- }
424
- function le(t, n, r) {
425
- let i = [], a = n.github.labels?.prd ?? "tk:prd", o = n.github.labels?.plan ?? "tk:plan", s = Y(a, r), l = Y(o, r), u = [...s.map((e) => ({
426
- ...e,
427
- type: "prd"
428
- })), ...l.map((e) => ({
429
- ...e,
430
- type: "plan"
431
- }))];
432
- if (u.length === 0) return b(t, { storage: f }), i.push("No GitHub issues found — nothing to migrate."), i.push(`✓ Storage switched to "${f}".`), i;
433
- for (let r of u) {
434
- let { metadata: a, body: o } = H(r.body ?? ""), s = a.slug ?? W(r.title);
435
- if (!s) continue;
436
- let l = r.labels.map((e) => e.name), u = a.status ?? oe(l), d = c(t, r.type === "prd" ? n.paths.prds : n.paths.plans, `${s}.md`);
437
- if (e(d)) {
438
- i.push(`⚠ skip ${r.type} "${s}" — local file already exists`);
439
- continue;
440
- }
441
- if (r.type === "prd") Q(d, `${U({
442
- ...a,
443
- status: u
444
- })}\n${o}`);
445
- else {
446
- let e = {};
447
- a.source_prd && (e.source_prd = a.source_prd), (a.slug || s) && (e.slug = a.slug ?? s), u && (e.status = u), a.completed && (e.completed = a.completed), Q(d, `${U(e)}\n${o}`);
448
- }
449
- i.push(`✓ ${r.type} "${s}" → ${d}`);
450
- }
451
- return b(t, { storage: f }), i.push(`✓ Storage switched to "${f}".`), i;
452
- }
453
- //#endregion
454
- //#region src/commands/uninstall.ts
455
- function ue(t) {
456
- if (!C.some((n) => e(c(t, ".claude", "skills", n)))) throw Error("TracerKit not initialized — nothing to uninstall");
457
- let n = [];
458
- for (let r of C) {
459
- let a = c(t, ".claude", "skills", r);
460
- e(a) && (i(a, {
461
- recursive: !0,
462
- force: !0
463
- }), n.push(`✗ .claude/skills/${r}/ removed`));
464
- }
465
- return n;
466
- }
467
- //#endregion
468
- export { N as a, w as c, f as d, _ as f, I as i, T as l, $ as n, D as o, b as p, te as r, E as s, ue as t, C as u };