token-pilot 0.41.0 → 0.42.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.
@@ -6,14 +6,14 @@
6
6
  },
7
7
  "metadata": {
8
8
  "description": "Token Pilot \u2014 save 60-90% tokens when AI reads code",
9
- "version": "0.41.0"
9
+ "version": "0.42.1"
10
10
  },
11
11
  "plugins": [
12
12
  {
13
13
  "name": "token-pilot",
14
14
  "source": "./",
15
15
  "description": "Reduces token consumption by 60-90% via AST-aware lazy file reading, structural symbol navigation, and cross-session tool-usage analytics. 22 MCP tools + 19 subagents + budget watchdog hooks.",
16
- "version": "0.41.0",
16
+ "version": "0.42.1",
17
17
  "author": {
18
18
  "name": "Digital-Threads"
19
19
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "token-pilot",
3
- "version": "0.41.0",
3
+ "version": "0.42.1",
4
4
  "description": "Saves 60-90% tokens on AI code reading. AST-aware lazy reads, symbol navigation, find_usages, structural git diff/log, edit-safety guard, Task-routing matcher, cross-session telemetry (errors + diagnostics), 25 tp-* subagents tiered to haiku/sonnet/opus with budget watchdog.",
5
5
  "author": {
6
6
  "name": "Digital-Threads",
@@ -9,7 +9,7 @@ tools:
9
9
  - mcp__token-pilot__read_symbol
10
10
  - Bash
11
11
  model: haiku
12
- token_pilot_version: "0.41.0"
12
+ token_pilot_version: "0.42.1"
13
13
  token_pilot_body_hash: dd184501203fa7f3c73f419c4ffbe33c4be75400cb64a7a51733a3fe23f6e085
14
14
  requiredMcpServers:
15
15
  - "token-pilot"
@@ -11,7 +11,7 @@ tools:
11
11
  - Grep
12
12
  - Read
13
13
  model: sonnet
14
- token_pilot_version: "0.41.0"
14
+ token_pilot_version: "0.42.1"
15
15
  token_pilot_body_hash: d172f600bf32277ea6eb4cbbee4542ddd698a986dcd96997d33930561964569b
16
16
  requiredMcpServers:
17
17
  - "token-pilot"
@@ -8,7 +8,7 @@ tools:
8
8
  - mcp__token-pilot__test_summary
9
9
  - mcp__token-pilot__outline
10
10
  - Bash
11
- token_pilot_version: "0.41.0"
11
+ token_pilot_version: "0.42.1"
12
12
  token_pilot_body_hash: de64a406b5176de19f7422619c7de7949b1f28865f225402c9cea9255f377428
13
13
  requiredMcpServers:
14
14
  - "token-pilot"
@@ -13,7 +13,7 @@ tools:
13
13
  - Edit
14
14
  - Glob
15
15
  model: sonnet
16
- token_pilot_version: "0.41.0"
16
+ token_pilot_version: "0.42.1"
17
17
  token_pilot_body_hash: 68b32af2dacd82ebe52c4eec93edb903d452688274c3065218270627c564d8b0
18
18
  requiredMcpServers:
19
19
  - "token-pilot"
@@ -11,7 +11,7 @@ tools:
11
11
  - Grep
12
12
  - Read
13
13
  model: sonnet
14
- token_pilot_version: "0.41.0"
14
+ token_pilot_version: "0.42.1"
15
15
  token_pilot_body_hash: d9b7f5b7ae6f4ae21305c775361bcab097cc774370a6d976c093571d46d55021
16
16
  requiredMcpServers:
17
17
  - "token-pilot"
@@ -12,7 +12,7 @@ tools:
12
12
  - Read
13
13
  - Bash
14
14
  model: sonnet
15
- token_pilot_version: "0.41.0"
15
+ token_pilot_version: "0.42.1"
16
16
  token_pilot_body_hash: 052413de8d92377edcde6ae5c823f5378db304baccfa29e8866467f42553a500
17
17
  requiredMcpServers:
18
18
  - "token-pilot"
@@ -9,7 +9,7 @@ tools:
9
9
  - Bash
10
10
  - Read
11
11
  model: haiku
12
- token_pilot_version: "0.41.0"
12
+ token_pilot_version: "0.42.1"
13
13
  token_pilot_body_hash: e14dc57493d816f8c2e017963e2ef5f66bea50fd0b805a80e8a0d97c968427e7
14
14
  requiredMcpServers:
15
15
  - "token-pilot"
@@ -13,7 +13,7 @@ tools:
13
13
  - Edit
14
14
  - Glob
15
15
  model: haiku
16
- token_pilot_version: "0.41.0"
16
+ token_pilot_version: "0.42.1"
17
17
  token_pilot_body_hash: 57d741794ab40e31a7ac49c68ea39a9088f5827cdef866ce81bfca1b7c9180cf
18
18
  requiredMcpServers:
19
19
  - "token-pilot"
@@ -10,7 +10,7 @@ tools:
10
10
  - Bash
11
11
  - Read
12
12
  model: haiku
13
- token_pilot_version: "0.41.0"
13
+ token_pilot_version: "0.42.1"
14
14
  token_pilot_body_hash: 7b70fa76a60e3c58a1de4f56c32c0f166424137e203a0cf1c8654e7c9235d904
15
15
  requiredMcpServers:
16
16
  - "token-pilot"
@@ -12,7 +12,7 @@ tools:
12
12
  - mcp__token-pilot__read_symbols
13
13
  - Read
14
14
  model: sonnet
15
- token_pilot_version: "0.41.0"
15
+ token_pilot_version: "0.42.1"
16
16
  token_pilot_body_hash: 351a987e11eba63852f5431a16d8eb53104f4f689f82fdcc5a2bf4db948ba92f
17
17
  requiredMcpServers:
18
18
  - "token-pilot"
@@ -8,7 +8,7 @@ tools:
8
8
  - mcp__token-pilot__read_symbol
9
9
  - Bash
10
10
  model: inherit
11
- token_pilot_version: "0.41.0"
11
+ token_pilot_version: "0.42.1"
12
12
  token_pilot_body_hash: de5722bfea374eaab096c1ae635c37879e7a91370ee3cd0532f4240be03c91eb
13
13
  requiredMcpServers:
14
14
  - "token-pilot"
@@ -13,7 +13,7 @@ tools:
13
13
  - Edit
14
14
  - Bash
15
15
  model: sonnet
16
- token_pilot_version: "0.41.0"
16
+ token_pilot_version: "0.42.1"
17
17
  token_pilot_body_hash: 375a824d0d847bb5453ec594c7a62ad566ee7e4d92717b0473f771f1a0477c60
18
18
  requiredMcpServers:
19
19
  - "token-pilot"
@@ -11,7 +11,7 @@ tools:
11
11
  - Grep
12
12
  - Glob
13
13
  model: sonnet
14
- token_pilot_version: "0.41.0"
14
+ token_pilot_version: "0.42.1"
15
15
  token_pilot_body_hash: 0334de1bf99b431b65359637d125cda7c44c6f780eb92c57cc538715b1939536
16
16
  requiredMcpServers:
17
17
  - "token-pilot"
@@ -10,7 +10,7 @@ tools:
10
10
  - mcp__token-pilot__smart_read
11
11
  - mcp__token-pilot__smart_read_many
12
12
  - mcp__token-pilot__read_section
13
- token_pilot_version: "0.41.0"
13
+ token_pilot_version: "0.42.1"
14
14
  token_pilot_body_hash: 832e95633fbc8e9b0c10f3e540a327d4be062fb4b3f17a6cce6be13f414e2927
15
15
  requiredMcpServers:
16
16
  - "token-pilot"
@@ -11,7 +11,7 @@ tools:
11
11
  - Bash
12
12
  - Read
13
13
  model: sonnet
14
- token_pilot_version: "0.41.0"
14
+ token_pilot_version: "0.42.1"
15
15
  token_pilot_body_hash: b61f06380d80798fa2e49d37bcba0653495bee04dd6bdbc1feff9a75607b0508
16
16
  requiredMcpServers:
17
17
  - "token-pilot"
@@ -11,7 +11,7 @@ tools:
11
11
  - mcp__token-pilot__read_for_edit
12
12
  - Read
13
13
  model: sonnet
14
- token_pilot_version: "0.41.0"
14
+ token_pilot_version: "0.42.1"
15
15
  token_pilot_body_hash: f83f50d05b4f70285ae7afed2b1a406fc436df56e61a0aedbfb31edc7f2b6e66
16
16
  requiredMcpServers:
17
17
  - "token-pilot"
@@ -8,7 +8,7 @@ tools:
8
8
  - mcp__token-pilot__outline
9
9
  - mcp__token-pilot__read_symbol
10
10
  model: sonnet
11
- token_pilot_version: "0.41.0"
11
+ token_pilot_version: "0.42.1"
12
12
  token_pilot_body_hash: c5f6fc122c89e16e5cf774045f92169ee3468555320b898171ba13eca5323550
13
13
  requiredMcpServers:
14
14
  - "token-pilot"
@@ -9,7 +9,7 @@ tools:
9
9
  - mcp__token-pilot__module_info
10
10
  - Bash
11
11
  model: sonnet
12
- token_pilot_version: "0.41.0"
12
+ token_pilot_version: "0.42.1"
13
13
  token_pilot_body_hash: 8ef3c3341cbfed4eb8dd130126a9683edc57e378c92ff0ca764d584fd941c55c
14
14
  requiredMcpServers:
15
15
  - "token-pilot"
package/agents/tp-run.md CHANGED
@@ -16,7 +16,7 @@ tools:
16
16
  - Glob
17
17
  - Bash
18
18
  model: haiku
19
- token_pilot_version: "0.41.0"
19
+ token_pilot_version: "0.42.1"
20
20
  token_pilot_body_hash: 2b08618d34a61f00aafccbda9fed6d83243296dedb83440edbd2d5c28bb6dbc4
21
21
  requiredMcpServers:
22
22
  - "token-pilot"
@@ -9,7 +9,7 @@ tools:
9
9
  - mcp__token-pilot__session_budget
10
10
  - Bash
11
11
  - Read
12
- token_pilot_version: "0.41.0"
12
+ token_pilot_version: "0.42.1"
13
13
  token_pilot_body_hash: 529374ed728f5eed5b758b3be3da65624783c0bf0c1a253d7d661a843eb5f767
14
14
  requiredMcpServers:
15
15
  - "token-pilot"
@@ -11,7 +11,7 @@ tools:
11
11
  - Read
12
12
  - Grep
13
13
  model: sonnet
14
- token_pilot_version: "0.41.0"
14
+ token_pilot_version: "0.42.1"
15
15
  token_pilot_body_hash: a60f6ae110eb3138064bce074e8ba26fa0ce5f4659df1624a9d9d3646803391b
16
16
  requiredMcpServers:
17
17
  - "token-pilot"
@@ -9,7 +9,7 @@ tools:
9
9
  - Read
10
10
  - Write
11
11
  model: sonnet
12
- token_pilot_version: "0.41.0"
12
+ token_pilot_version: "0.42.1"
13
13
  token_pilot_body_hash: c7a4e8b39228fd5158528f389c924c5ff2d98c4b9b05ee0106d54a26c5dc1350
14
14
  requiredMcpServers:
15
15
  - "token-pilot"
@@ -10,7 +10,7 @@ tools:
10
10
  - mcp__token-pilot__test_summary
11
11
  - Glob
12
12
  - Grep
13
- token_pilot_version: "0.41.0"
13
+ token_pilot_version: "0.42.1"
14
14
  token_pilot_body_hash: be81eed53a3720d146cf89e4a14a7a56577633f7c84c234c412ab70d64c05b11
15
15
  requiredMcpServers:
16
16
  - "token-pilot"
@@ -8,7 +8,7 @@ tools:
8
8
  - mcp__token-pilot__find_usages
9
9
  - mcp__token-pilot__read_symbol
10
10
  model: sonnet
11
- token_pilot_version: "0.41.0"
11
+ token_pilot_version: "0.42.1"
12
12
  token_pilot_body_hash: 362ecf4cb03b059421ea26933473700900073dc38b3a7fe271208dfb1ae14f90
13
13
  requiredMcpServers:
14
14
  - "token-pilot"
@@ -13,7 +13,7 @@ tools:
13
13
  - Edit
14
14
  - Bash
15
15
  model: sonnet
16
- token_pilot_version: "0.41.0"
16
+ token_pilot_version: "0.42.1"
17
17
  token_pilot_body_hash: 269f2fe22ff4517c277d3f56ca67d8a5527b93290ab21079a83ba7af22c1b5a9
18
18
  requiredMcpServers:
19
19
  - "token-pilot"
@@ -225,18 +225,10 @@ export function formatStatuslineHint(result, ecosystemStatuses) {
225
225
  case "unknown":
226
226
  return null;
227
227
  case "not-configured": {
228
- lines.push(` ○ no statusline badge configured — add one to see token-pilot`);
229
- lines.push(` state (enforcement mode + cumulative saved tokens) in`);
230
- lines.push(` Claude Code's status bar.`);
231
- lines.push("");
232
- const command = pluginRoot
233
- ? `bash "${pluginRoot}/hooks/statusline-chain.sh"`
234
- : `bash "$(ls -t ~/.claude/plugins/cache/token-pilot/token-pilot/*/hooks/statusline-chain.sh 2>/dev/null | head -1)"`;
235
- lines.push(` Add to ${result.configPath}:`);
236
- lines.push(` "statusLine": {`);
237
- lines.push(` "type": "command",`);
238
- lines.push(` "command": "${command.replace(/"/g, '\\"')}"`);
239
- lines.push(` }`);
228
+ lines.push(` ○ no statusline badge configured — see token-pilot's live`);
229
+ lines.push(` saved-token count + enforcement mode in your status bar.`);
230
+ lines.push(` one command (non-destructive — never clobbers an existing one):`);
231
+ lines.push(` token-pilot install-statusline`);
240
232
  return lines.join("\n");
241
233
  }
242
234
  }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * v0.42.0 — `token-pilot install-statusline`.
3
+ *
4
+ * Convenience installer for the statusline badge. v0.41.1 removed the
5
+ * intrusive sessionTitle overwrite and pointed users at the additive
6
+ * statusline (hooks/statusline-chain.sh) — the caveman-style channel
7
+ * that sits ALONGSIDE the session name and live-updates on every render.
8
+ * This command wires it into `~/.claude/settings.json` without making
9
+ * the user hand-edit JSON.
10
+ *
11
+ * Non-destructive by design (the sessionTitle lesson): we NEVER clobber
12
+ * a third-party statusLine. Decision per current state:
13
+ *
14
+ * not-configured → write our chain command
15
+ * configured-caveman-only → upgrade to chain (shows BOTH badges)
16
+ * configured-tp-only → upgrade to chain (so caveman shows too if present)
17
+ * configured-chain → already ideal, no-op
18
+ * configured-other → leave alone; print how to switch manually
19
+ * unknown → settings.json unreadable; print guidance
20
+ *
21
+ * `--force` overrides the configured-other guard for users who really
22
+ * want to replace a custom statusLine.
23
+ */
24
+ import type { StatuslineStatus } from "./ecosystem-check.js";
25
+ /** The version-agnostic chain command (auto-picks the newest plugin dir). */
26
+ export declare const CHAIN_COMMAND = "bash \"$(ls -t ~/.claude/plugins/cache/token-pilot/token-pilot/*/hooks/statusline-chain.sh 2>/dev/null | head -1)\"";
27
+ export interface InstallStatuslineResult {
28
+ action: "installed" | "upgraded" | "noop" | "skipped";
29
+ message: string;
30
+ }
31
+ /**
32
+ * Pure decision: given the current statusline status, what should the
33
+ * installer do? Separated from I/O for unit tests.
34
+ */
35
+ export declare function decideStatuslineAction(status: StatuslineStatus, force: boolean): {
36
+ write: boolean;
37
+ result: InstallStatuslineResult;
38
+ };
39
+ /**
40
+ * Classify the statusLine state of a settings.json at `settingsPath`.
41
+ * Async, path-injectable (so tests point at a tmp file). Mirrors
42
+ * ecosystem-check.checkStatusline but works on any path. Never throws.
43
+ */
44
+ export declare function classifyStatuslineAt(settingsPath: string): Promise<StatuslineStatus>;
45
+ /**
46
+ * CLI entry. Returns an exit code.
47
+ */
48
+ export declare function handleInstallStatusline(argv: string[], opts?: {
49
+ settingsPath?: string;
50
+ }): Promise<number>;
51
+ //# sourceMappingURL=install-statusline.d.ts.map
@@ -0,0 +1,160 @@
1
+ /**
2
+ * v0.42.0 — `token-pilot install-statusline`.
3
+ *
4
+ * Convenience installer for the statusline badge. v0.41.1 removed the
5
+ * intrusive sessionTitle overwrite and pointed users at the additive
6
+ * statusline (hooks/statusline-chain.sh) — the caveman-style channel
7
+ * that sits ALONGSIDE the session name and live-updates on every render.
8
+ * This command wires it into `~/.claude/settings.json` without making
9
+ * the user hand-edit JSON.
10
+ *
11
+ * Non-destructive by design (the sessionTitle lesson): we NEVER clobber
12
+ * a third-party statusLine. Decision per current state:
13
+ *
14
+ * not-configured → write our chain command
15
+ * configured-caveman-only → upgrade to chain (shows BOTH badges)
16
+ * configured-tp-only → upgrade to chain (so caveman shows too if present)
17
+ * configured-chain → already ideal, no-op
18
+ * configured-other → leave alone; print how to switch manually
19
+ * unknown → settings.json unreadable; print guidance
20
+ *
21
+ * `--force` overrides the configured-other guard for users who really
22
+ * want to replace a custom statusLine.
23
+ */
24
+ import { readFile, writeFile, mkdir, access } from "node:fs/promises";
25
+ import { homedir } from "node:os";
26
+ import { dirname, join } from "node:path";
27
+ /** The version-agnostic chain command (auto-picks the newest plugin dir). */
28
+ export const CHAIN_COMMAND = 'bash "$(ls -t ~/.claude/plugins/cache/token-pilot/token-pilot/*/hooks/statusline-chain.sh 2>/dev/null | head -1)"';
29
+ /**
30
+ * Pure decision: given the current statusline status, what should the
31
+ * installer do? Separated from I/O for unit tests.
32
+ */
33
+ export function decideStatuslineAction(status, force) {
34
+ switch (status) {
35
+ case "not-configured":
36
+ return {
37
+ write: true,
38
+ result: {
39
+ action: "installed",
40
+ message: "statusLine configured — the [TP] badge will show in your status bar (restart Claude Code).",
41
+ },
42
+ };
43
+ case "configured-caveman-only":
44
+ case "configured-tp-only":
45
+ return {
46
+ write: true,
47
+ result: {
48
+ action: "upgraded",
49
+ message: "statusLine upgraded to the chain wrapper — both caveman and [TP] badges now render side by side.",
50
+ },
51
+ };
52
+ case "configured-chain":
53
+ return {
54
+ write: false,
55
+ result: {
56
+ action: "noop",
57
+ message: "statusLine already uses the token-pilot chain wrapper. Nothing to do.",
58
+ },
59
+ };
60
+ case "configured-other":
61
+ if (force) {
62
+ return {
63
+ write: true,
64
+ result: {
65
+ action: "installed",
66
+ message: "Replaced your custom statusLine with the token-pilot chain wrapper (--force).",
67
+ },
68
+ };
69
+ }
70
+ return {
71
+ write: false,
72
+ result: {
73
+ action: "skipped",
74
+ message: "You already have a custom statusLine — left untouched. " +
75
+ "To show the [TP] badge too, set statusLine.command to:\n " +
76
+ CHAIN_COMMAND +
77
+ "\nor re-run with --force to replace it.",
78
+ },
79
+ };
80
+ case "unknown":
81
+ default:
82
+ return {
83
+ write: false,
84
+ result: {
85
+ action: "skipped",
86
+ message: "Could not read ~/.claude/settings.json as JSON — not modifying it. " +
87
+ "Add this manually under \"statusLine\":\n " +
88
+ CHAIN_COMMAND,
89
+ },
90
+ };
91
+ }
92
+ }
93
+ /**
94
+ * Classify the statusLine state of a settings.json at `settingsPath`.
95
+ * Async, path-injectable (so tests point at a tmp file). Mirrors
96
+ * ecosystem-check.checkStatusline but works on any path. Never throws.
97
+ */
98
+ export async function classifyStatuslineAt(settingsPath) {
99
+ try {
100
+ await access(settingsPath);
101
+ }
102
+ catch {
103
+ return "not-configured";
104
+ }
105
+ let parsed;
106
+ try {
107
+ parsed = JSON.parse(await readFile(settingsPath, "utf-8"));
108
+ }
109
+ catch {
110
+ return "unknown";
111
+ }
112
+ const cmd = parsed
113
+ ?.statusLine?.command;
114
+ if (typeof cmd !== "string")
115
+ return "not-configured";
116
+ if (cmd.includes("statusline-chain.sh"))
117
+ return "configured-chain";
118
+ if (cmd.includes("tp-statusline.sh"))
119
+ return "configured-tp-only";
120
+ if (cmd.includes("caveman-statusline.sh"))
121
+ return "configured-caveman-only";
122
+ return "configured-other";
123
+ }
124
+ /**
125
+ * CLI entry. Returns an exit code.
126
+ */
127
+ export async function handleInstallStatusline(argv, opts) {
128
+ const force = argv.includes("--force");
129
+ const settingsPath = opts?.settingsPath ?? join(homedir(), ".claude", "settings.json");
130
+ const status = await classifyStatuslineAt(settingsPath);
131
+ const { write, result } = decideStatuslineAction(status, force);
132
+ if (!write) {
133
+ process.stdout.write(`[token-pilot] ${result.message}\n`);
134
+ return 0;
135
+ }
136
+ // Merge the statusLine field into existing settings (preserve the rest).
137
+ let settings = {};
138
+ try {
139
+ const raw = await readFile(settingsPath, "utf-8");
140
+ const parsed = JSON.parse(raw);
141
+ if (parsed && typeof parsed === "object") {
142
+ settings = parsed;
143
+ }
144
+ }
145
+ catch {
146
+ /* fresh file — start clean (only reached when status was safe) */
147
+ }
148
+ settings.statusLine = { type: "command", command: CHAIN_COMMAND };
149
+ try {
150
+ await mkdir(dirname(settingsPath), { recursive: true });
151
+ await writeFile(settingsPath, JSON.stringify(settings, null, 2) + "\n");
152
+ }
153
+ catch (err) {
154
+ process.stderr.write(`[token-pilot] failed to write ${settingsPath}: ${err instanceof Error ? err.message : String(err)}\n`);
155
+ return 1;
156
+ }
157
+ process.stdout.write(`[token-pilot] ${result.message}\n`);
158
+ return 0;
159
+ }
160
+ //# sourceMappingURL=install-statusline.js.map
@@ -17,7 +17,7 @@
17
17
  * Everything else passes through untouched — a real project root like
18
18
  * `/home/user/my-project` or `./subdir` goes to startServer as before.
19
19
  */
20
- export declare const KNOWN_COMMANDS: readonly ["hook-read", "hook-edit", "hook-pre-bash", "hook-pre-grep", "hook-pre-task", "hook-post-bash", "hook-post-task", "hook-session-start", "hook-bootstrap", "hook-subagent-stop", "install-hook", "uninstall-hook", "install-ast-index", "doctor", "bless-agents", "unbless-agents", "install-agents", "uninstall-agents", "stats", "tool-audit", "save-doc", "list-docs", "init", "migrate-hooks", "errors", "workflow", "--version", "-v", "--help", "-h"];
20
+ export declare const KNOWN_COMMANDS: readonly ["hook-read", "hook-edit", "hook-pre-bash", "hook-pre-grep", "hook-pre-task", "hook-post-bash", "hook-post-task", "hook-session-start", "hook-bootstrap", "hook-subagent-stop", "install-statusline", "install-hook", "uninstall-hook", "install-ast-index", "doctor", "bless-agents", "unbless-agents", "install-agents", "uninstall-agents", "stats", "tool-audit", "save-doc", "list-docs", "init", "migrate-hooks", "errors", "workflow", "--version", "-v", "--help", "-h"];
21
21
  export interface TypoGuardResult {
22
22
  kind: "pass-through" | "typo";
23
23
  suggestion?: string;
@@ -37,6 +37,8 @@ export const KNOWN_COMMANDS = [
37
37
  "hook-bootstrap",
38
38
  // v0.40.0 — canonical subagent-completion capture
39
39
  "hook-subagent-stop",
40
+ // v0.42.0 — one-command statusline badge installer
41
+ "install-statusline",
40
42
  "install-hook",
41
43
  "uninstall-hook",
42
44
  "install-ast-index",
@@ -274,72 +274,20 @@ export async function handleSessionStart(opts) {
274
274
  ".token-pilot/snapshots/latest.md",
275
275
  ".token-pilot/hook-events.jsonl",
276
276
  ];
277
- // v0.36.0 — sessionTitle was added in Claude Code 2.1.152. We surface
278
- // the cumulative saved-token count for this project so users see the
279
- // payoff at a glance in their window/tab title. Best-effort — if the
280
- // savings file is unreadable we fall back to a neutral title.
281
- let sessionTitle;
282
- try {
283
- const { loadSessionStats } = await import("../core/session-savings.js");
284
- // Sum savings across all sessions in this project, not just one.
285
- const stats = loadSessionStats(opts.projectRoot, "");
286
- // sessionId="" makes loadSessionStats short-circuit; use a tiny
287
- // dedicated reader instead.
288
- const { readFileSync } = await import("node:fs");
289
- const { join } = await import("node:path");
290
- let total = 0;
291
- try {
292
- const raw = readFileSync(join(opts.projectRoot, ".token-pilot", "hook-events.jsonl"), "utf-8");
293
- for (const line of raw.split("\n")) {
294
- if (!line)
295
- continue;
296
- try {
297
- const ev = JSON.parse(line);
298
- if (typeof ev.savedTokens === "number")
299
- total += ev.savedTokens;
300
- }
301
- catch {
302
- /* skip malformed line */
303
- }
304
- }
305
- }
306
- catch {
307
- /* no log file yet */
308
- }
309
- // Use the larger of "single-session" (loadSessionStats fallback)
310
- // and the all-sessions sum so an empty single-session number
311
- // doesn't override the meaningful project-wide total.
312
- const surfaced = Math.max(total, stats.savedTokens);
313
- if (surfaced > 0) {
314
- const human = surfaced >= 1_000_000
315
- ? `${(surfaced / 1_000_000).toFixed(1)}M`
316
- : surfaced >= 1000
317
- ? `${Math.round(surfaced / 1000)}k`
318
- : `${surfaced}`;
319
- sessionTitle = `[TP] ${human} saved`;
320
- }
321
- // v0.38.0 — when a fleet workflow is active, prefer a
322
- // workflow-progress title so a long fan-out run shows live
323
- // task count + budget in the window title.
324
- const { activeWorkflowId, workflowStatus } = await import("../core/workflow.js");
325
- const wfId = activeWorkflowId();
326
- if (wfId) {
327
- const st = await workflowStatus(opts.projectRoot, wfId);
328
- if (st) {
329
- const pct = st.pct != null ? ` · ${st.pct}%` : "";
330
- sessionTitle = `[TP] wf · ${st.task_count} tasks${pct}`;
331
- }
332
- }
333
- }
334
- catch {
335
- /* sessionTitle is best-effort decoration; never block startup */
336
- }
277
+ // v0.41.1 — sessionTitle removed. v0.36.0 set the window/tab title
278
+ // to `[TP] Nk saved`, but `sessionTitle` OVERWRITES Claude Code's
279
+ // own session name an intrusive clobber users (rightly) disliked.
280
+ // The cumulative-savings display belongs in the additive statusline
281
+ // badge (hooks/tp-statusline.sh), the same non-intrusive channel
282
+ // caveman uses — it sits alongside the session name instead of
283
+ // replacing it. Workflow progress, likewise, can ride the
284
+ // statusline (tp-statusline.sh reads the active workflow) rather
285
+ // than hijacking the title.
337
286
  const output = {
338
287
  hookSpecificOutput: {
339
288
  hookEventName: "SessionStart",
340
289
  additionalContext: message,
341
290
  watchPaths,
342
- ...(sessionTitle ? { sessionTitle } : {}),
343
291
  },
344
292
  };
345
293
  return JSON.stringify(output);
package/dist/index.js CHANGED
@@ -425,6 +425,16 @@ export async function main(cliArgs = process.argv.slice(2)) {
425
425
  process.exit(code);
426
426
  return;
427
427
  }
428
+ case "install-statusline": {
429
+ // v0.42.0 — wire the additive statusline badge into
430
+ // ~/.claude/settings.json so users don't hand-edit JSON. Never
431
+ // clobbers a third-party statusLine (the sessionTitle lesson);
432
+ // upgrades caveman-only / tp-only to the chain wrapper.
433
+ const { handleInstallStatusline } = await import("./cli/install-statusline.js");
434
+ const code = await handleInstallStatusline(cliArgs.slice(1));
435
+ process.exit(code);
436
+ return;
437
+ }
428
438
  case "migrate-hooks": {
429
439
  // v0.33.0 — clean stale npx-cache / pinned-version token-pilot
430
440
  // hook entries from user-level + project-level settings.json so
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "token-pilot",
3
- "version": "0.41.0",
3
+ "version": "0.42.1",
4
4
  "description": "Save up to 80% tokens when AI reads code — MCP server for token-efficient code navigation, AST-aware structural reading instead of dumping full files into context window",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",