claude-code-extensions 0.1.0 → 0.1.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.
Files changed (115) hide show
  1. package/dist/ast.d.ts +43 -0
  2. package/dist/ast.js +308 -0
  3. package/dist/ast.js.map +1 -0
  4. package/dist/cli-setup.d.ts +14 -0
  5. package/dist/cli-setup.js +110 -0
  6. package/dist/cli-setup.js.map +1 -0
  7. package/dist/cli.d.ts +18 -0
  8. package/dist/cli.js +218 -0
  9. package/dist/cli.js.map +1 -0
  10. package/dist/patch-worker.d.ts +6 -0
  11. package/dist/patch-worker.js +27 -0
  12. package/dist/patch-worker.js.map +1 -0
  13. package/dist/patches/always-show-context.d.ts +23 -0
  14. package/dist/patches/always-show-context.js +97 -0
  15. package/dist/patches/always-show-context.js.map +1 -0
  16. package/dist/patches/always-show-thinking.d.ts +18 -0
  17. package/dist/patches/always-show-thinking.js +55 -0
  18. package/dist/patches/always-show-thinking.js.map +1 -0
  19. package/dist/patches/banner.d.ts +10 -0
  20. package/dist/patches/banner.js +60 -0
  21. package/dist/patches/banner.js.map +1 -0
  22. package/dist/patches/cd-command.d.ts +16 -0
  23. package/dist/patches/cd-command.js +89 -0
  24. package/dist/patches/cd-command.js.map +1 -0
  25. package/dist/patches/cx-badge.d.ts +10 -0
  26. package/dist/patches/cx-badge.js +115 -0
  27. package/dist/patches/cx-badge.js.map +1 -0
  28. package/dist/patches/cx-resume-commands.d.ts +14 -0
  29. package/dist/patches/cx-resume-commands.js +53 -0
  30. package/dist/patches/cx-resume-commands.js.map +1 -0
  31. package/dist/patches/disable-paste-collapse.d.ts +16 -0
  32. package/dist/patches/disable-paste-collapse.js +49 -0
  33. package/dist/patches/disable-paste-collapse.js.map +1 -0
  34. package/dist/patches/disable-telemetry.d.ts +13 -0
  35. package/dist/patches/disable-telemetry.js +76 -0
  36. package/dist/patches/disable-telemetry.js.map +1 -0
  37. package/{patches/index.js → dist/patches/index.d.ts} +4 -0
  38. package/dist/patches/index.js +22 -0
  39. package/dist/patches/index.js.map +1 -0
  40. package/dist/patches/no-attribution.d.ts +15 -0
  41. package/dist/patches/no-attribution.js +42 -0
  42. package/dist/patches/no-attribution.js.map +1 -0
  43. package/dist/patches/no-feedback.d.ts +12 -0
  44. package/dist/patches/no-feedback.js +31 -0
  45. package/dist/patches/no-feedback.js.map +1 -0
  46. package/dist/patches/no-npm-warning.d.ts +9 -0
  47. package/dist/patches/no-npm-warning.js +31 -0
  48. package/dist/patches/no-npm-warning.js.map +1 -0
  49. package/dist/patches/no-tips.d.ts +10 -0
  50. package/dist/patches/no-tips.js +26 -0
  51. package/dist/patches/no-tips.js.map +1 -0
  52. package/dist/patches/persist-max-effort.d.ts +15 -0
  53. package/dist/patches/persist-max-effort.js +75 -0
  54. package/dist/patches/persist-max-effort.js.map +1 -0
  55. package/dist/patches/queue.d.ts +10 -0
  56. package/dist/patches/queue.js +202 -0
  57. package/dist/patches/queue.js.map +1 -0
  58. package/dist/patches/random-clawd.d.ts +9 -0
  59. package/dist/patches/random-clawd.js +49 -0
  60. package/dist/patches/random-clawd.js.map +1 -0
  61. package/dist/patches/reload.d.ts +10 -0
  62. package/dist/patches/reload.js +50 -0
  63. package/dist/patches/reload.js.map +1 -0
  64. package/dist/patches/session-export.d.ts +16 -0
  65. package/dist/patches/session-export.js +93 -0
  66. package/dist/patches/session-export.js.map +1 -0
  67. package/dist/patches/session-timer.d.ts +18 -0
  68. package/dist/patches/session-timer.js +217 -0
  69. package/dist/patches/session-timer.js.map +1 -0
  70. package/dist/patches/show-file-in-collapsed-read.d.ts +17 -0
  71. package/dist/patches/show-file-in-collapsed-read.js +151 -0
  72. package/dist/patches/show-file-in-collapsed-read.js.map +1 -0
  73. package/dist/patches/simple-spinner.d.ts +12 -0
  74. package/dist/patches/simple-spinner.js +30 -0
  75. package/dist/patches/simple-spinner.js.map +1 -0
  76. package/dist/patches/swap-enter-submit.d.ts +26 -0
  77. package/dist/patches/swap-enter-submit.js +155 -0
  78. package/dist/patches/swap-enter-submit.js.map +1 -0
  79. package/dist/setup.d.ts +11 -0
  80. package/dist/setup.js +268 -0
  81. package/dist/setup.js.map +1 -0
  82. package/dist/transform-worker.d.ts +10 -0
  83. package/dist/transform-worker.js +35 -0
  84. package/dist/transform-worker.js.map +1 -0
  85. package/dist/transform.d.ts +12 -0
  86. package/dist/transform.js +83 -0
  87. package/dist/transform.js.map +1 -0
  88. package/dist/types.d.ts +105 -0
  89. package/dist/types.js +8 -0
  90. package/dist/types.js.map +1 -0
  91. package/package.json +16 -11
  92. package/ast.js +0 -276
  93. package/cx +0 -228
  94. package/cx-setup +0 -101
  95. package/patch-worker.js +0 -31
  96. package/patches/always-show-context.js +0 -123
  97. package/patches/always-show-thinking.js +0 -65
  98. package/patches/banner.js +0 -58
  99. package/patches/cd-command.js +0 -104
  100. package/patches/cx-badge.js +0 -112
  101. package/patches/cx-resume-commands.js +0 -58
  102. package/patches/disable-paste-collapse.js +0 -52
  103. package/patches/disable-telemetry.js +0 -84
  104. package/patches/no-attribution.js +0 -55
  105. package/patches/no-npm-warning.js +0 -32
  106. package/patches/no-tips.js +0 -29
  107. package/patches/persist-max-effort.js +0 -70
  108. package/patches/queue.js +0 -215
  109. package/patches/random-clawd.js +0 -52
  110. package/patches/reload.js +0 -68
  111. package/patches/show-file-in-collapsed-read.js +0 -178
  112. package/patches/swap-enter-submit.js +0 -188
  113. package/setup.js +0 -222
  114. package/transform-worker.js +0 -38
  115. package/transform.js +0 -99
package/dist/cli.js ADDED
@@ -0,0 +1,218 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * cx — Claude Code Extensions
4
+ *
5
+ * Drop-in replacement for `claude`. Applies enabled patches at runtime
6
+ * via AST transformation. The original cli.js is never modified.
7
+ * All arguments pass through to claude untouched.
8
+ *
9
+ * Subcommands:
10
+ * cx setup — interactive patch configurator
11
+ * cx list — show patch status
12
+ * cx reload — signal a running cx instance to reload Claude
13
+ * cx [args] — run patched Claude (with auto-reload support)
14
+ *
15
+ * Reload: type `! cx reload` inside Claude to restart the session
16
+ * with fresh patches applied. The conversation resumes via --continue.
17
+ */
18
+ import { existsSync, readFileSync, writeFileSync, statSync, mkdirSync, unlinkSync } from 'fs';
19
+ import { execSync, spawn as nodeSpawn } from 'child_process';
20
+ import { resolve, dirname } from 'path';
21
+ import { fileURLToPath } from 'url';
22
+ import { transformAsync, listPatches } from './transform.js';
23
+ const __dirname = dirname(fileURLToPath(import.meta.url));
24
+ const CONFIG_PATH = resolve(__dirname, '..', '.cx-patches.json');
25
+ const cacheDir = resolve(__dirname, '..', '.cache');
26
+ const cachedCliPath = resolve(cacheDir, 'cli.mjs');
27
+ const metaPath = resolve(cacheDir, 'meta.json');
28
+ const PID_FILE = resolve(__dirname, '..', '.cx-pid');
29
+ const RELOAD_EXIT_CODE = 75;
30
+ // ── Subcommands (fast path, before any heavy work) ───────────────────────
31
+ const sub = process.argv[2];
32
+ if (sub === 'reload') {
33
+ try {
34
+ const pid = parseInt(readFileSync(PID_FILE, 'utf-8').trim(), 10);
35
+ process.kill(pid, 'SIGUSR1');
36
+ process.stderr.write('\x1b[2mcx: reload signal sent\x1b[0m\n');
37
+ }
38
+ catch (e) {
39
+ const msg = e.code === 'ENOENT' ? 'no cx instance running'
40
+ : e.code === 'ESRCH' ? 'cx process not running'
41
+ : e.message;
42
+ process.stderr.write(`cx reload: ${msg}\n`);
43
+ process.exit(1);
44
+ }
45
+ process.exit(0);
46
+ }
47
+ // ── Config ───────────────────────────────────────────────────────────────
48
+ function loadConfig() {
49
+ if (!existsSync(CONFIG_PATH))
50
+ return null;
51
+ try {
52
+ return JSON.parse(readFileSync(CONFIG_PATH, 'utf-8'));
53
+ }
54
+ catch {
55
+ return null;
56
+ }
57
+ }
58
+ function getEnabledPatches() {
59
+ const config = loadConfig();
60
+ const all = listPatches();
61
+ if (!config?.patches)
62
+ return all.map(p => p.id);
63
+ return all.filter((p) => {
64
+ if (p.id in config.patches)
65
+ return config.patches[p.id] !== false;
66
+ return p.defaultEnabled !== false;
67
+ }).map(p => p.id);
68
+ }
69
+ if (sub === 'list') {
70
+ const all = listPatches();
71
+ const enabled = getEnabledPatches();
72
+ for (const p of all) {
73
+ const on = enabled.includes(p.id);
74
+ process.stdout.write(` ${on ? '\x1b[32m✓\x1b[0m' : '\x1b[90m✗\x1b[0m'} ${p.id} — ${p.description ?? p.name}\n`);
75
+ }
76
+ process.exit(0);
77
+ }
78
+ if (sub === 'setup') {
79
+ const { default: setup } = await import('./setup.js');
80
+ await setup();
81
+ process.exit(0);
82
+ }
83
+ // ── First run ────────────────────────────────────────────────────────────
84
+ if (!existsSync(CONFIG_PATH)) {
85
+ if (process.stdin.isTTY) {
86
+ const { default: setup } = await import('./setup.js');
87
+ await setup({ firstRun: true });
88
+ }
89
+ else {
90
+ process.stderr.write('\x1b[2mcx: first run — all patches enabled. run cx setup to configure.\x1b[0m\n');
91
+ }
92
+ }
93
+ // ── Locate cli.js ────────────────────────────────────────────────────────
94
+ let cliPath;
95
+ try {
96
+ const npmRoot = execSync('npm root -g', { encoding: 'utf-8' }).trim();
97
+ cliPath = resolve(npmRoot, '@anthropic-ai/claude-code/cli.js');
98
+ }
99
+ catch { /* fallthrough */ }
100
+ if (!cliPath || !existsSync(cliPath)) {
101
+ console.error('cx: could not find @anthropic-ai/claude-code. Install it:');
102
+ console.error(' npm install -g @anthropic-ai/claude-code');
103
+ process.exit(1);
104
+ }
105
+ // ── Cache ────────────────────────────────────────────────────────────────
106
+ async function ensureCache() {
107
+ const enabled = getEnabledPatches();
108
+ const stat = statSync(cliPath);
109
+ const key = `${stat.size}:${stat.mtimeMs}:${[...enabled].sort().join(',')}`;
110
+ let valid = false;
111
+ if (existsSync(cachedCliPath) && existsSync(metaPath)) {
112
+ try {
113
+ valid = JSON.parse(readFileSync(metaPath, 'utf-8')).key === key;
114
+ }
115
+ catch { }
116
+ }
117
+ if (!valid) {
118
+ const t0 = performance.now();
119
+ const total = enabled.length;
120
+ // Line 0: prepare with elapsed timer, Lines 1..N: patch checklist
121
+ process.stderr.write(`\x1b[2m ◇ preparing (0s)\x1b[0m\n`);
122
+ for (const id of enabled) {
123
+ process.stderr.write(`\x1b[2m ◻ ${id}\x1b[0m\n`);
124
+ }
125
+ const timer = setInterval(() => {
126
+ const elapsed = ((performance.now() - t0) / 1000).toFixed(1);
127
+ const up = total + 1;
128
+ process.stderr.write(`\x1b[${up}A\r\x1b[2m ◇ preparing (${elapsed}s)\x1b[0m\x1b[K\x1b[${up}B\r`);
129
+ }, 100);
130
+ const original = readFileSync(cliPath, 'utf-8');
131
+ const patched = await transformAsync(original, enabled, {
132
+ onReady() {
133
+ clearInterval(timer);
134
+ const up = total + 1;
135
+ const elapsed = ((performance.now() - t0) / 1000).toFixed(1);
136
+ process.stderr.write(`\x1b[${up}A\r\x1b[2m ◇ ready (${elapsed}s)\x1b[0m\x1b[K\x1b[${up}B\r`);
137
+ },
138
+ onDone(id) {
139
+ const idx = enabled.indexOf(id);
140
+ const up = total - idx;
141
+ process.stderr.write(`\x1b[${up}A\r\x1b[32m ✔ ${id}\x1b[0m\x1b[K\x1b[${up}B\r`);
142
+ },
143
+ });
144
+ // Replace prepare line with summary
145
+ const up = total + 1;
146
+ process.stderr.write(`\x1b[${up}A\r\x1b[2m ◆ ${total} patches applied (${((performance.now() - t0) / 1000).toFixed(1)}s)\x1b[0m\x1b[K\x1b[${up}B\r`);
147
+ mkdirSync(cacheDir, { recursive: true });
148
+ writeFileSync(cachedCliPath, patched);
149
+ writeFileSync(metaPath, JSON.stringify({ key, ts: new Date().toISOString() }));
150
+ }
151
+ }
152
+ // ── PID file ─────────────────────────────────────────────────────────────
153
+ writeFileSync(PID_FILE, String(process.pid));
154
+ function cleanPid() { try {
155
+ unlinkSync(PID_FILE);
156
+ }
157
+ catch { } }
158
+ process.on('exit', cleanPid);
159
+ // ── Reload loop ──────────────────────────────────────────────────────────
160
+ let child = null;
161
+ let shouldReload = false;
162
+ process.on('SIGUSR1', () => {
163
+ shouldReload = true;
164
+ if (child)
165
+ child.kill('SIGTERM');
166
+ });
167
+ // Let child handle Ctrl+C — don't let it kill the wrapper
168
+ process.on('SIGINT', () => {
169
+ if (!child) {
170
+ cleanPid();
171
+ process.exit(130);
172
+ }
173
+ });
174
+ process.on('SIGTERM', () => {
175
+ if (child)
176
+ child.kill('SIGTERM');
177
+ cleanPid();
178
+ process.exit(143);
179
+ });
180
+ /**
181
+ * Build args for a reload: strip --continue/--resume, prepend --continue.
182
+ */
183
+ function reloadArgs(original) {
184
+ const skip = new Set(['--continue', '-c', '--resume', '-r']);
185
+ const result = ['--continue'];
186
+ for (let i = 0; i < original.length; i++) {
187
+ if (skip.has(original[i])) {
188
+ // --resume/-r may have an optional value; skip it too
189
+ if ((original[i] === '--resume' || original[i] === '-r') &&
190
+ i + 1 < original.length && !original[i + 1].startsWith('-')) {
191
+ i++;
192
+ }
193
+ continue;
194
+ }
195
+ result.push(original[i]);
196
+ }
197
+ return result;
198
+ }
199
+ const userArgs = process.argv.slice(2);
200
+ let isReload = false;
201
+ while (true) {
202
+ await ensureCache();
203
+ const args = isReload ? reloadArgs(userArgs) : userArgs;
204
+ child = nodeSpawn(process.execPath, [cachedCliPath, ...args], {
205
+ stdio: 'inherit',
206
+ env: process.env,
207
+ });
208
+ const code = await new Promise(r => child.on('close', (c) => r(c)));
209
+ child = null;
210
+ if (shouldReload || code === RELOAD_EXIT_CODE) {
211
+ shouldReload = false;
212
+ isReload = true;
213
+ process.stderr.write('\n\x1b[2mcx: reloading…\x1b[0m\n');
214
+ continue;
215
+ }
216
+ process.exit(code ?? 0);
217
+ }
218
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Worker thread that runs a single patch and returns its edits.
3
+ * Receives: { source, patchId, patchesDir }
4
+ * Returns: { edits: [{pos, deleteCount, text}] } or { error: string }
5
+ */
6
+ export {};
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Worker thread that runs a single patch and returns its edits.
3
+ * Receives: { source, patchId, patchesDir }
4
+ * Returns: { edits: [{pos, deleteCount, text}] } or { error: string }
5
+ */
6
+ import { workerData, parentPort } from 'worker_threads';
7
+ import * as acorn from 'acorn';
8
+ import { ASTIndex, buildContext } from './ast.js';
9
+ const { source, patchId, patchesDir } = workerData;
10
+ try {
11
+ const ast = acorn.parse(source, { ecmaVersion: 'latest', sourceType: 'module', allowHashBang: true });
12
+ const index = new ASTIndex(ast);
13
+ parentPort.postMessage({ type: 'ready' });
14
+ const edits = [];
15
+ const editor = {
16
+ insertAt(pos, text) { edits.push({ pos, deleteCount: 0, text }); },
17
+ replaceRange(start, end, text) { edits.push({ pos: start, deleteCount: end - start, text }); },
18
+ };
19
+ const ctx = buildContext(source, index, editor);
20
+ const patchModule = await import(`${patchesDir}/${patchId}.js`);
21
+ patchModule.default.apply(ctx);
22
+ parentPort.postMessage({ type: 'done', edits });
23
+ }
24
+ catch (err) {
25
+ parentPort.postMessage({ type: 'error', error: err.message });
26
+ }
27
+ //# sourceMappingURL=patch-worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patch-worker.js","sourceRoot":"","sources":["../src/patch-worker.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAGlD,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,UAA6B,CAAC;AAEtE,IAAI,CAAC;IACH,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,CAAuB,CAAC;IAC5H,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC;IAChC,UAAW,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IAE3C,MAAM,KAAK,GAAiB,EAAE,CAAC;IAC/B,MAAM,MAAM,GAAgB;QAC1B,QAAQ,CAAC,GAAW,EAAE,IAAY,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAClF,YAAY,CAAC,KAAa,EAAE,GAAW,EAAE,IAAY,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,GAAG,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;KACvH,CAAC;IAEF,MAAM,GAAG,GAAG,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IAChD,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,GAAG,UAAU,IAAI,OAAO,KAAK,CAAC,CAAC;IAC/D,WAAW,CAAC,OAAiB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAE1C,UAAW,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;AACnD,CAAC;AAAC,OAAO,GAAG,EAAE,CAAC;IACb,UAAW,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAG,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;AAC5E,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Always Show Context
3
+ *
4
+ * Shows context usage percentage at all times, not just when approaching
5
+ * the limit. The built-in TokenWarning only fires within 20k tokens of
6
+ * the threshold — on a 1M context window, that's ~98% full, far too late.
7
+ *
8
+ * Addresses: https://github.com/anthropics/claude-code/issues/18456 (51 thumbs up)
9
+ *
10
+ * Strategy:
11
+ * 1. Find TokenWarning by its unique "Context low" string
12
+ * 2. Remove the isAboveWarningThreshold gate so the indicator always renders
13
+ * 3. Fix the warning color to be neutral when below threshold
14
+ * 4. Soften "Context low" label to "Context" for always-on display
15
+ *
16
+ * For auto-compact users (the default): shows a dim "X% context used"
17
+ * line at all times. For manual-compact users: shows "Context (X% remaining)"
18
+ * in neutral color when below threshold, escalating to warning/error colors
19
+ * as context fills up.
20
+ */
21
+ import type { Patch } from '../types.js';
22
+ declare const patch: Patch;
23
+ export default patch;
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Always Show Context
3
+ *
4
+ * Shows context usage percentage at all times, not just when approaching
5
+ * the limit. The built-in TokenWarning only fires within 20k tokens of
6
+ * the threshold — on a 1M context window, that's ~98% full, far too late.
7
+ *
8
+ * Addresses: https://github.com/anthropics/claude-code/issues/18456 (51 thumbs up)
9
+ *
10
+ * Strategy:
11
+ * 1. Find TokenWarning by its unique "Context low" string
12
+ * 2. Remove the isAboveWarningThreshold gate so the indicator always renders
13
+ * 3. Fix the warning color to be neutral when below threshold
14
+ * 4. Soften "Context low" label to "Context" for always-on display
15
+ *
16
+ * For auto-compact users (the default): shows a dim "X% context used"
17
+ * line at all times. For manual-compact users: shows "Context (X% remaining)"
18
+ * in neutral color when below threshold, escalating to warning/error colors
19
+ * as context fills up.
20
+ */
21
+ const patch = {
22
+ id: 'always-show-context',
23
+ name: 'Always Show Context',
24
+ description: 'Always display context usage percentage, not just when near limit',
25
+ apply(ctx) {
26
+ const { ast, editor, find, index, assert, src } = ctx;
27
+ const { findFirst } = find;
28
+ // Find TokenWarning function via its unique "Context low" marker.
29
+ // Check indexed literals first (string concat), then template elements.
30
+ let marker = null;
31
+ for (const [value, nodes] of index.literalsByValue) {
32
+ if (typeof value === 'string' && value.includes('Context low')) {
33
+ marker = nodes[0];
34
+ break;
35
+ }
36
+ }
37
+ if (!marker) {
38
+ marker = findFirst(ast, (n) => n.type === 'TemplateElement' &&
39
+ n.value?.raw?.includes('Context low'));
40
+ }
41
+ assert(marker, 'Could not find "Context low" marker in bundle');
42
+ const fn = index.enclosingFunction(marker);
43
+ assert(fn, 'Could not find TokenWarning function');
44
+ // Find the early-return gate:
45
+ // if (!isAboveWarningThreshold || suppressWarning) { return null; }
46
+ // Pattern: IfStatement → test: !X || Y, consequent: return null,
47
+ // and it must appear before the "Context low" string.
48
+ const gate = findFirst(fn, (n) => {
49
+ if (n.type !== 'IfStatement' || n.start >= marker.start)
50
+ return false;
51
+ const t = n.test;
52
+ if (t.type !== 'LogicalExpression' || t.operator !== '||')
53
+ return false;
54
+ if (t.left.type !== 'UnaryExpression' || t.left.operator !== '!')
55
+ return false;
56
+ return findFirst(n.consequent, (r) => r.type === 'ReturnStatement' &&
57
+ r.argument?.type === 'Literal' &&
58
+ r.argument.value === null) !== null;
59
+ });
60
+ assert(gate, 'Could not find early-return gate: if(!X||Y){return null}');
61
+ // Save the minified name for isAboveWarningThreshold before editing
62
+ const warnVar = gate.test.left.argument;
63
+ assert(warnVar.type === 'Identifier', 'Expected Identifier for isAboveWarningThreshold');
64
+ // Edit 1: Remove threshold check from gate, keep suppress check.
65
+ // !isAboveWarningThreshold || suppressWarning → suppressWarning
66
+ editor.replaceRange(gate.test.start, gate.test.end, src(gate.test.right));
67
+ // Edit 2: Neutral color when below warning threshold.
68
+ // Find: isAboveErrorThreshold ? "error" : "warning"
69
+ // Replace "warning" with: isAboveWarningThreshold ? "warning" : void 0
70
+ // This makes text render in default color when context usage is low.
71
+ const colorTernary = findFirst(fn, (n) => n.type === 'ConditionalExpression' &&
72
+ n.consequent.type === 'Literal' && n.consequent.value === 'error' &&
73
+ n.alternate.type === 'Literal' && n.alternate.value === 'warning');
74
+ if (colorTernary) {
75
+ editor.replaceRange(colorTernary.alternate.start, colorTernary.alternate.end, `${warnVar.name}?"warning":void 0`);
76
+ }
77
+ // Edit 3: Soften "Context low" → "Context" for neutral always-on display.
78
+ const fnSrc = src(fn);
79
+ const needle = 'Context low';
80
+ let pos = 0;
81
+ while ((pos = fnSrc.indexOf(needle, pos)) !== -1) {
82
+ editor.replaceRange(fn.start + pos, fn.start + pos + needle.length, 'Context');
83
+ pos += needle.length;
84
+ }
85
+ // Edit 4: Change "X% until auto-compact" → "X% context used"
86
+ // The bundle has: reactiveOnlyMode ? `${100-var}% context used` : `${var}% until auto-compact`
87
+ // reactiveOnlyMode is always false, so patch the alternate branch to also show context used.
88
+ const autocompactTpl = findFirst(fn, (n) => n.type === 'TemplateLiteral' &&
89
+ n.quasis.some((q) => q.value?.raw?.includes('% until auto-compact')));
90
+ if (autocompactTpl) {
91
+ const varName = src(autocompactTpl.expressions[0]);
92
+ editor.replaceRange(autocompactTpl.start, autocompactTpl.end, `\`\${100-${varName}}% context used\``);
93
+ }
94
+ },
95
+ };
96
+ export default patch;
97
+ //# sourceMappingURL=always-show-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"always-show-context.js","sourceRoot":"","sources":["../../src/patches/always-show-context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Always Show Thinking Patch
3
+ *
4
+ * Makes Claude's thinking blocks always display expanded instead of
5
+ * collapsed behind "∴ Thinking (ctrl+o to expand)".
6
+ *
7
+ * Addresses: https://github.com/anthropics/claude-code/issues/8477 (195 thumbs up)
8
+ *
9
+ * In AssistantThinkingMessage, the gate is:
10
+ * const shouldShowFullThinking = isTranscriptMode || verbose;
11
+ * if (!shouldShowFullThinking) { return <collapsed view> }
12
+ *
13
+ * We find the function by its unique "∴ Thinking" string and replace
14
+ * the negated OR gate with `false` so the expanded view always renders.
15
+ */
16
+ import type { Patch } from '../types.js';
17
+ declare const patch: Patch;
18
+ export default patch;
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Always Show Thinking Patch
3
+ *
4
+ * Makes Claude's thinking blocks always display expanded instead of
5
+ * collapsed behind "∴ Thinking (ctrl+o to expand)".
6
+ *
7
+ * Addresses: https://github.com/anthropics/claude-code/issues/8477 (195 thumbs up)
8
+ *
9
+ * In AssistantThinkingMessage, the gate is:
10
+ * const shouldShowFullThinking = isTranscriptMode || verbose;
11
+ * if (!shouldShowFullThinking) { return <collapsed view> }
12
+ *
13
+ * We find the function by its unique "∴ Thinking" string and replace
14
+ * the negated OR gate with `false` so the expanded view always renders.
15
+ */
16
+ const patch = {
17
+ id: 'always-show-thinking',
18
+ name: 'Always Show Thinking',
19
+ description: 'Show thinking block content inline instead of collapsed',
20
+ apply(ctx) {
21
+ const { ast, editor, find, index, assert, src } = ctx;
22
+ const { findFirst } = find;
23
+ // Find the AssistantThinkingMessage function by its unique string literal.
24
+ // The "∴" character (U+2234, "therefore") only appears in this component.
25
+ // Use the literal index to find the marker, then walk up to its enclosing function.
26
+ let thinkingMarker = null;
27
+ for (const [value, nodes] of index.literalsByValue) {
28
+ if (typeof value === 'string' && value.includes('\u2234 Thinking')) {
29
+ thinkingMarker = nodes[0];
30
+ break;
31
+ }
32
+ }
33
+ assert(thinkingMarker, 'Could not find "∴ Thinking" literal');
34
+ const thinkingFn = index.enclosingFunction(thinkingMarker);
35
+ assert(thinkingFn, 'Could not find AssistantThinkingMessage function (marker: "∴ Thinking")');
36
+ // Find the gate: if(!(Y||O)) where Y=isTranscriptMode, O=verbose.
37
+ // Structure: IfStatement whose test is UnaryExpression(!) wrapping LogicalExpression(||)
38
+ // This is the FIRST such pattern in the function, appearing before the "∴ Thinking" strings.
39
+ const gate = findFirst(thinkingFn, (n) => n.type === 'IfStatement'
40
+ && n.test.type === 'UnaryExpression'
41
+ && n.test.operator === '!'
42
+ && n.test.argument.type === 'LogicalExpression'
43
+ && n.test.argument.operator === '||');
44
+ assert(gate, 'Could not find thinking display gate: if(!(X||Y))');
45
+ // Verify this is the right gate by checking it appears before the "∴ Thinking" string
46
+ const firstThinkingLiteral = findFirst(thinkingFn, (n) => n.type === 'Literal' && typeof n.value === 'string'
47
+ && n.value.includes('\u2234 Thinking'));
48
+ assert(gate.start < firstThinkingLiteral.start, 'Gate should appear before "∴ Thinking" literal');
49
+ // Replace the test expression with `false` so the collapsed branch is never taken.
50
+ // This makes thinking always display in expanded mode.
51
+ editor.replaceRange(gate.test.start, gate.test.end, 'false');
52
+ },
53
+ };
54
+ export default patch;
55
+ //# sourceMappingURL=always-show-thinking.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"always-show-thinking.js","sourceRoot":"","sources":["../../src/patches/always-show-thinking.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,MAAM,KAAK,GAAU;IACnB,EAAE,EAAE,sBAAsB;IAC1B,IAAI,EAAE,sBAAsB;IAC5B,WAAW,EAAE,yDAAyD;IAEtE,KAAK,CAAC,GAAG;QACP,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC;QACtD,MAAM,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC;QAE3B,2EAA2E;QAC3E,0EAA0E;QAC1E,oFAAoF;QACpF,IAAI,cAAc,GAAG,IAAI,CAAC;QAC1B,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,KAAK,CAAC,eAAe,EAAE,CAAC;YACnD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC;gBACnE,cAAc,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBAC1B,MAAM;YACR,CAAC;QACH,CAAC;QACD,MAAM,CAAC,cAAc,EAAE,qCAAqC,CAAC,CAAC;QAC9D,MAAM,UAAU,GAAG,KAAK,CAAC,iBAAiB,CAAC,cAAc,CAAC,CAAC;QAC3D,MAAM,CAAC,UAAU,EAAE,yEAAyE,CAAC,CAAC;QAE9F,kEAAkE;QAClE,yFAAyF;QACzF,6FAA6F;QAC7F,MAAM,IAAI,GAAG,SAAS,CAAC,UAAU,EAAE,CAAC,CAAM,EAAE,EAAE,CAC5C,CAAC,CAAC,IAAI,KAAK,aAAa;eACrB,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,iBAAiB;eACjC,CAAC,CAAC,IAAI,CAAC,QAAQ,KAAK,GAAG;eACvB,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,mBAAmB;eAC5C,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,KAAK,IAAI,CACrC,CAAC;QACF,MAAM,CAAC,IAAI,EAAE,mDAAmD,CAAC,CAAC;QAElE,sFAAsF;QACtF,MAAM,oBAAoB,GAAG,SAAS,CAAC,UAAU,EAAE,CAAC,CAAM,EAAE,EAAE,CAC5D,CAAC,CAAC,IAAI,KAAK,SAAS,IAAI,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ;eAChD,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC,CAAC;QAC1C,MAAM,CACJ,IAAI,CAAC,KAAK,GAAG,oBAAoB,CAAC,KAAK,EACvC,gDAAgD,CACjD,CAAC;QAEF,mFAAmF;QACnF,uDAAuD;QACvD,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC/D,CAAC;CACF,CAAC;AAEF,eAAe,KAAK,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Attribution Banner Patch
3
+ *
4
+ * Changes "Claude Code" to "Claude Code Extensions (cx) v<version> by @wormcoffee" on the title line.
5
+ * Targets the bold <Text> in the condensed layout and the border title
6
+ * in the boxed layout. No extra elements, no layout changes.
7
+ */
8
+ import type { Patch } from '../types.js';
9
+ declare const patch: Patch;
10
+ export default patch;
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Attribution Banner Patch
3
+ *
4
+ * Changes "Claude Code" to "Claude Code Extensions (cx) v<version> by @wormcoffee" on the title line.
5
+ * Targets the bold <Text> in the condensed layout and the border title
6
+ * in the boxed layout. No extra elements, no layout changes.
7
+ */
8
+ import { readFileSync } from 'fs';
9
+ import { resolve, dirname } from 'path';
10
+ import { fileURLToPath } from 'url';
11
+ const __dirname = dirname(fileURLToPath(import.meta.url));
12
+ const pkg = JSON.parse(readFileSync(resolve(__dirname, '..', '..', 'package.json'), 'utf-8'));
13
+ const version = pkg.version;
14
+ const patch = {
15
+ id: 'banner',
16
+ name: 'Attribution Banner',
17
+ description: 'Show "@wormcoffee" on the Claude Code title line',
18
+ apply(ctx) {
19
+ const { ast, editor, find, index, src, assert } = ctx;
20
+ const { findFirst } = find;
21
+ // ── Condensed layout: createElement(T, {bold:true}, "Claude Code") ──
22
+ // Use literal index to find "Claude Code", then walk up to the createElement call.
23
+ const claudeCodeLiterals = index.literalsByValue.get('Claude Code') || [];
24
+ let boldTextCall = null;
25
+ for (const lit of claudeCodeLiterals) {
26
+ const call = index.ancestor(lit, 'CallExpression');
27
+ if (!call || call.callee.type !== 'MemberExpression' || call.callee.property.name !== 'createElement')
28
+ continue;
29
+ const hasBold = call.arguments.some((a) => a?.type === 'ObjectExpression' &&
30
+ a.properties.some((p) => p.key?.type === 'Identifier' && p.key.name === 'bold'));
31
+ if (hasBold) {
32
+ boldTextCall = call;
33
+ break;
34
+ }
35
+ }
36
+ assert(boldTextCall, 'Could not find createElement(T, {bold}, "Claude Code")');
37
+ const textLiteral = boldTextCall.arguments.find((a) => a.type === 'Literal' && a.value === 'Claude Code');
38
+ editor.replaceRange(textLiteral.start, textLiteral.end, `"Claude Code Extensions (cx) v${version} by x.com/@wormcoffee"`);
39
+ // ── Boxed layout: b7("claude",o)("Claude Code") in the border title ──
40
+ // ── Boxed layout: b7("claude",o)("Claude Code") ──
41
+ // Find "Claude Code" literal whose parent CallExpression's callee is another call with "claude"
42
+ let titleCall = null;
43
+ for (const lit of claudeCodeLiterals) {
44
+ const call = index.parentMap.get(lit);
45
+ if (!call || call.type !== 'CallExpression' || call.arguments.length !== 1)
46
+ continue;
47
+ if (call.callee.type === 'CallExpression' &&
48
+ call.callee.arguments[0]?.type === 'Literal' &&
49
+ call.callee.arguments[0].value === 'claude') {
50
+ titleCall = call;
51
+ break;
52
+ }
53
+ }
54
+ if (titleCall) {
55
+ editor.replaceRange(titleCall.arguments[0].start, titleCall.arguments[0].end, `"Claude Code Extensions (cx) v${version} by x.com/@wormcoffee"`);
56
+ }
57
+ },
58
+ };
59
+ export default patch;
60
+ //# sourceMappingURL=banner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"banner.js","sourceRoot":"","sources":["../../src/patches/banner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * /cd Command Patch
3
+ *
4
+ * Adds a /cd <path> slash command to change the working directory
5
+ * mid-session without losing conversation context.
6
+ *
7
+ * Addresses: https://github.com/anthropics/claude-code/issues/3473 (54 thumbs up)
8
+ *
9
+ * AST strategy: find the bundled setCwd function (via its "tengu_shell_set_cwd"
10
+ * telemetry string) and getCwdState (via its named export mapping), then inject
11
+ * a new LocalCommand into the memoized COMMANDS array. The command calls setCwd
12
+ * and reports the new working directory.
13
+ */
14
+ import type { Patch } from '../types.js';
15
+ declare const patch: Patch;
16
+ export default patch;