codedeck 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/README.md +45 -16
  2. package/dist/cli/cli-name.js +20 -0
  3. package/dist/cli/cli-name.js.map +1 -0
  4. package/dist/cli/commands/claims.js +170 -0
  5. package/dist/cli/commands/claims.js.map +1 -0
  6. package/dist/cli/commands/doctor.js +22 -1
  7. package/dist/cli/commands/doctor.js.map +1 -1
  8. package/dist/cli/commands/models.js +3 -3
  9. package/dist/cli/commands/models.js.map +1 -1
  10. package/dist/cli/commands/open.js +148 -315
  11. package/dist/cli/commands/open.js.map +1 -1
  12. package/dist/cli/commands/ps.js +260 -23
  13. package/dist/cli/commands/ps.js.map +1 -1
  14. package/dist/cli/commands/rename.js +29 -0
  15. package/dist/cli/commands/rename.js.map +1 -0
  16. package/dist/cli/commands/run.js +48 -17
  17. package/dist/cli/commands/run.js.map +1 -1
  18. package/dist/cli/commands/setup.js +388 -62
  19. package/dist/cli/commands/setup.js.map +1 -1
  20. package/dist/cli/commands/usage.js +37 -0
  21. package/dist/cli/commands/usage.js.map +1 -0
  22. package/dist/cli/commands/wait.js +3 -2
  23. package/dist/cli/commands/wait.js.map +1 -1
  24. package/dist/cli/index.js +33 -21
  25. package/dist/cli/index.js.map +1 -1
  26. package/dist/cli/picker-state.js +75 -8
  27. package/dist/cli/picker-state.js.map +1 -1
  28. package/dist/cli/picker.js +13 -3
  29. package/dist/cli/picker.js.map +1 -1
  30. package/dist/cli/ui.js +20 -4
  31. package/dist/cli/ui.js.map +1 -1
  32. package/dist/config/config.js +39 -0
  33. package/dist/config/config.js.map +1 -1
  34. package/dist/config/orchestrator-mode.js +72 -0
  35. package/dist/config/orchestrator-mode.js.map +1 -0
  36. package/dist/config/paths.js +8 -0
  37. package/dist/config/paths.js.map +1 -1
  38. package/dist/core/pricing.js +65 -0
  39. package/dist/core/pricing.js.map +1 -0
  40. package/dist/core/roles.js +14 -3
  41. package/dist/core/roles.js.map +1 -1
  42. package/dist/core/run-usage.js +46 -0
  43. package/dist/core/run-usage.js.map +1 -0
  44. package/dist/core/session.js +5 -0
  45. package/dist/core/session.js.map +1 -1
  46. package/dist/daemon/daemon.js +90 -3
  47. package/dist/daemon/daemon.js.map +1 -1
  48. package/dist/daemon/ipc.js +10 -3
  49. package/dist/daemon/ipc.js.map +1 -1
  50. package/dist/drivers/opencode/driver.js +1 -114
  51. package/dist/drivers/opencode/driver.js.map +1 -1
  52. package/dist/drivers/opencode/parser.js +86 -0
  53. package/dist/drivers/opencode/parser.js.map +1 -0
  54. package/dist/drivers/session-runtime.js +1 -0
  55. package/dist/drivers/session-runtime.js.map +1 -1
  56. package/dist/git/worktree.js +1 -1
  57. package/dist/git/worktree.js.map +1 -1
  58. package/dist/open/contract.js +104 -0
  59. package/dist/open/contract.js.map +1 -0
  60. package/dist/open/injection.js +59 -0
  61. package/dist/open/injection.js.map +1 -0
  62. package/dist/open/launchers/claude.js +212 -0
  63. package/dist/open/launchers/claude.js.map +1 -0
  64. package/dist/open/launchers/opencode.js +178 -0
  65. package/dist/open/launchers/opencode.js.map +1 -0
  66. package/dist/open/orchestrator-prose.js +12 -0
  67. package/dist/open/orchestrator-prose.js.map +1 -0
  68. package/dist/open/pty.js +281 -0
  69. package/dist/open/pty.js.map +1 -0
  70. package/dist/open/runtime.js +597 -0
  71. package/dist/open/runtime.js.map +1 -0
  72. package/dist/plugin/agents/auditor.md +7 -1
  73. package/dist/plugin/agents/general.md +12 -1
  74. package/dist/plugin/agents/orchestrator-edit.md +69 -0
  75. package/dist/plugin/agents/orchestrator-read.md +69 -0
  76. package/dist/plugin/agents/orchestrator.md +76 -17
  77. package/dist/plugin/agents/reviewer.md +3 -0
  78. package/dist/plugin/commands/autonomous.md +58 -0
  79. package/dist/plugin/hooks/hooks.json +24 -0
  80. package/dist/plugin/hooks/session-id.sh +23 -0
  81. package/dist/plugin/hooks/session-name-lib.mjs +40 -0
  82. package/dist/plugin/hooks/session-name-worker.mjs +124 -0
  83. package/dist/plugin/hooks/session-name.mjs +66 -0
  84. package/dist/plugin/hooks/session-name.sh +7 -0
  85. package/dist/plugin/pty-shim.mjs +114 -0
  86. package/dist/plugin/statusline.sh +214 -22
  87. package/dist/plugin/themes/codedeck-rage.json +74 -0
  88. package/dist/plugin/themes/codedeck-ultra.json +52 -44
  89. package/dist/store/claims.js +152 -0
  90. package/dist/store/claims.js.map +1 -0
  91. package/dist/store/database.js +14 -0
  92. package/dist/store/database.js.map +1 -1
  93. package/dist/store/sessions.js +17 -3
  94. package/dist/store/sessions.js.map +1 -1
  95. package/package.json +3 -2
  96. package/dist/plugin/settings.json +0 -7
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Roda DENTRO do pty criado pelo `script`, entre ele e o harness.
4
+ *
5
+ * Existe por causa de dois buracos que o processo pai não consegue tapar de
6
+ * fora:
7
+ *
8
+ * - `script` só dimensiona o pty quando o stdin dele é um terminal. No nosso
9
+ * desenho o stdin do `script` é um pipe (é por ali que a injeção do
10
+ * `/rename` entra), então o pty nasce 0x0 e qualquer TUI fullscreen desenha
11
+ * errado.
12
+ * - Node não expõe ioctl, então TIOCSWINSZ só é alcançável por um binário que
13
+ * faça a chamada: `stty`, que herda o slave do pty no fd 0.
14
+ */
15
+ import net from "node:net";
16
+ import os from "node:os";
17
+ import { accessSync, constants } from "node:fs";
18
+ import { spawn, spawnSync } from "node:child_process";
19
+
20
+ // The command comes from `codedeck open`, one argv entry per argument, and is
21
+ // run without a shell. The guard is there so a value that could only have been
22
+ // mangled on the way in — a control character, an empty binary — stops here
23
+ // rather than becoming a process.
24
+ const SAFE_BINARY = /^[^\u0000-\u001f]+$/;
25
+ const target = process.argv.slice(2);
26
+ if (target.length === 0 || !SAFE_BINARY.test(target[0])) {
27
+ process.stderr.write("pty-shim: missing or unusable target command\n");
28
+ process.exit(64);
29
+ }
30
+
31
+ /**
32
+ * Named by absolute path rather than looked up on PATH: this runs with the
33
+ * environment of whoever opened the session, and a PATH entry they can write
34
+ * to would decide what "stty" means.
35
+ */
36
+ const STTY = ["/bin/stty", "/usr/bin/stty"].find((candidate) => {
37
+ try {
38
+ accessSync(candidate, constants.X_OK);
39
+ return true;
40
+ } catch {
41
+ return false;
42
+ }
43
+ });
44
+
45
+ // Applying the size on the slave is also what makes the kernel raise SIGWINCH
46
+ // on the session's foreground group, so the TUI redraws without ever knowing
47
+ // this shim exists.
48
+ function applySize(rows, cols) {
49
+ if (STTY === undefined) return false;
50
+ if (!Number.isInteger(rows) || !Number.isInteger(cols) || rows <= 0 || cols <= 0) return false;
51
+ const done = spawnSync(STTY, ["rows", String(rows), "cols", String(cols)], {
52
+ stdio: ["inherit", "ignore", "ignore"],
53
+ });
54
+ return done.status === 0;
55
+ }
56
+
57
+ applySize(Number(process.env.CODEDECK_PTY_ROWS), Number(process.env.CODEDECK_PTY_COLS));
58
+
59
+ const [binary, ...args] = target;
60
+ const child = spawn(binary, args, { stdio: "inherit", shell: false });
61
+
62
+ // Ctrl+C typed by the user reaches the whole foreground group, this shim
63
+ // included. The harness owns that key (Claude Code draws its own interrupt),
64
+ // so the shim stays alive and lets the child decide when to die.
65
+ process.on("SIGINT", () => {});
66
+ process.on("SIGTERM", () => {});
67
+
68
+ let server;
69
+ const control = process.env.CODEDECK_PTY_CONTROL;
70
+ if (control) {
71
+ server = net.createServer((conn) => {
72
+ let buffer = "";
73
+ conn.setEncoding("utf8");
74
+ conn.on("data", (chunk) => {
75
+ buffer += chunk;
76
+ let index;
77
+ while ((index = buffer.indexOf("\n")) >= 0) {
78
+ const line = buffer.slice(0, index).trim();
79
+ buffer = buffer.slice(index + 1);
80
+ if (line.length === 0) continue;
81
+ let message;
82
+ try {
83
+ message = JSON.parse(line);
84
+ } catch {
85
+ continue;
86
+ }
87
+ if (message?.type === "resize") applySize(Number(message.rows), Number(message.cols));
88
+ }
89
+ });
90
+ conn.on("error", () => {});
91
+ });
92
+ server.on("error", () => {});
93
+ server.listen(control);
94
+ }
95
+
96
+ const closeServer = () => {
97
+ try {
98
+ server?.close();
99
+ } catch {}
100
+ };
101
+
102
+ child.on("error", (error) => {
103
+ closeServer();
104
+ process.stderr.write(`pty-shim: ${error.message}\n`);
105
+ process.exit(126);
106
+ });
107
+
108
+ // The exit status has to survive both layers so `codedeck open` still reports
109
+ // what the harness actually did.
110
+ child.on("exit", (code, signal) => {
111
+ closeServer();
112
+ if (signal) process.exit(128 + (os.constants.signals[signal] ?? 0));
113
+ process.exit(code ?? 0);
114
+ });
@@ -2,11 +2,14 @@
2
2
 
3
3
  # Claude Code sends the status payload on stdin. Keep parsing in Node so this
4
4
  # plugin does not require jq or Python on the host.
5
+ #
6
+ # The JS below is single quoted, so it must not contain a single quote anywhere.
5
7
  set -u
6
8
 
7
9
  node --input-type=module -e '
8
10
  import { execFileSync } from "node:child_process";
9
- import { readFileSync } from "node:fs";
11
+ import { readFileSync, writeSync } from "node:fs";
12
+ import { basename } from "node:path";
10
13
 
11
14
  let payload;
12
15
  try {
@@ -14,6 +17,23 @@ try {
14
17
  } catch {
15
18
  process.exit(0);
16
19
  }
20
+ if (payload === null || typeof payload !== "object") process.exit(0);
21
+
22
+ /**
23
+ * Claude Code dims every status row before printing it, so the palette here is
24
+ * the bright end of the theme on purpose: a mid tone arrives on screen as grey.
25
+ * SGR survives, which is why these are raw escapes and not a library.
26
+ */
27
+ const BLOOD = "\x1b[38;2;225;29;72m";
28
+ const EMBER = "\x1b[38;2;251;146;60m";
29
+ const TEXT = "\x1b[38;2;247;237;238m";
30
+ const MUTED = "\x1b[38;2;163;139;143m";
31
+ const GREEN = "\x1b[38;2;74;222;128m";
32
+ const AMBER = "\x1b[38;2;251;191;36m";
33
+ const RED = "\x1b[38;2;255;77;109m";
34
+ const OFF = "\x1b[0m";
35
+
36
+ const paint = (color, value) => color + value + OFF;
17
37
 
18
38
  const text = (value) => {
19
39
  if (typeof value !== "string") return undefined;
@@ -23,29 +43,55 @@ const text = (value) => {
23
43
 
24
44
  const firstText = (...values) => values.map(text).find(Boolean);
25
45
 
26
- const roleFrom = (value) => {
46
+ /**
47
+ * A row is one line, so anything that could carry a newline is flattened before
48
+ * it reaches the terminal.
49
+ */
50
+ const clean = (value) => value.replace(/[\t\r\n]/g, " ");
51
+
52
+ const tail = (value) => {
27
53
  const candidate = text(value);
28
54
  if (!candidate) return undefined;
29
55
  const parts = candidate.split(/[·:]/).map((part) => part.trim()).filter(Boolean);
30
56
  return parts.at(-1) ?? candidate;
31
57
  };
32
58
 
33
- const role = roleFrom(
34
- payload.agent?.name,
35
- payload.agent?.role,
36
- payload.role,
37
- payload.session_role,
38
- ) ?? roleFrom(
39
- text(payload.session_name)?.match(/CodeDeck\s*·\s*(.+)$/i)?.[1],
40
- );
41
- const model = firstText(payload.model?.display_name, payload.model?.id, payload.model);
59
+ /**
60
+ * `codedeck open` puts the role at the end of session_name, so the tail remains
61
+ * the source for ordinary sessions. agent.name is only a fallback.
62
+ */
63
+ const role =
64
+ tail(text(payload.session_name)?.match(/CodeDeck\s*[·:]\s*(.+)$/i)?.[1]) ??
65
+ tail(payload.agent?.name) ??
66
+ tail(payload.session_name);
67
+
68
+ const taskName = (() => {
69
+ const sessionFile = text(process.env.CODEDECK_SESSION_FILE);
70
+ const sessionId = payload.session_id;
71
+ if (
72
+ !sessionFile ||
73
+ typeof sessionId !== "string" ||
74
+ !/^[0-9a-fA-F-]{8,}$/.test(sessionId)
75
+ ) return undefined;
76
+
77
+ try {
78
+ const value = readFileSync(`${sessionFile}.${sessionId}.name`, "utf8")
79
+ .replace(/\s+/g, " ")
80
+ .trim()
81
+ .slice(0, 30);
82
+ return value || undefined;
83
+ } catch {
84
+ return undefined;
85
+ }
86
+ })();
87
+
42
88
  const cwd = firstText(payload.workspace?.current_dir, payload.cwd) ?? process.cwd();
89
+ const project = text(basename(cwd)) ?? (cwd === "/" ? "/" : undefined);
43
90
 
44
- let branch = firstText(
45
- payload.worktree?.branch,
46
- payload.workspace?.git_worktree,
47
- payload.branch,
48
- );
91
+ /**
92
+ * Claude supplies a branch for its own worktrees. Git fills the ordinary case.
93
+ */
94
+ let branch = text(payload.worktree?.branch);
49
95
  if (!branch) {
50
96
  try {
51
97
  branch = text(execFileSync("git", ["-C", cwd, "branch", "--show-current"], {
@@ -57,12 +103,158 @@ if (!branch) {
57
103
  }
58
104
  }
59
105
 
60
- const clean = (value) => value?.replace(/[\t\r\n]/g, " ");
106
+ /**
107
+ * Context is reported as remaining, not used. Colour keeps the existing bands.
108
+ */
109
+ const contextField = () => {
110
+ const remaining = payload.context_window?.remaining_percentage;
111
+ if (typeof remaining !== "number" || !Number.isFinite(remaining)) return undefined;
112
+ const value = Math.max(0, Math.min(100, Math.round(remaining)));
113
+ const color = value <= 15 ? RED : value <= 35 ? AMBER : GREEN;
114
+ return paint(MUTED, "ctx ") + paint(color, value + "%");
115
+ };
116
+
117
+ const nonNegativeNumber = (value) =>
118
+ typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : undefined;
119
+
120
+ const compactTokens = (value) => {
121
+ const total = Math.max(0, Math.round(value));
122
+ if (total < 1000) return String(total);
123
+ if (total >= 1_000_000) {
124
+ const millions = total / 1_000_000;
125
+ return millions.toFixed(millions < 10 ? 1 : 0).replace(/\.0$/, "") + "M";
126
+ }
127
+ const thousands = total / 1000;
128
+ const roundedThousands = Number(thousands.toFixed(thousands < 100 ? 1 : 0));
129
+ if (roundedThousands >= 1000) return "1M";
130
+ return String(roundedThousands).replace(/\.0$/, "") + "k";
131
+ };
132
+
133
+ /**
134
+ * Since Claude Code 2.1.132, these fields describe the latest context window,
135
+ * not cumulative session totals. The aggregate token field therefore stays
136
+ * worker-only instead of adding a repeated local window to the run total.
137
+ * Degraded mode may show this current local snapshot when it is available.
138
+ */
139
+ const localTokens = () => {
140
+ const context = payload.context_window;
141
+ const totalInput = nonNegativeNumber(context?.total_input_tokens);
142
+ const totalOutput = nonNegativeNumber(context?.total_output_tokens);
143
+ if (totalInput !== undefined && totalOutput !== undefined) return totalInput + totalOutput;
144
+
145
+ const current = context?.current_usage;
146
+ const input = nonNegativeNumber(current?.input_tokens);
147
+ const output = nonNegativeNumber(current?.output_tokens);
148
+ const cacheCreation = nonNegativeNumber(current?.cache_creation_input_tokens);
149
+ const cacheRead = nonNegativeNumber(current?.cache_read_input_tokens);
150
+ if (
151
+ input !== undefined &&
152
+ output !== undefined &&
153
+ cacheCreation !== undefined &&
154
+ cacheRead !== undefined
155
+ ) return input + output + cacheCreation + cacheRead;
156
+ return undefined;
157
+ };
158
+
159
+ const COST_DISPLAY_THRESHOLD = 0.01;
160
+ const COST_TEXT_THRESHOLD = 1;
161
+ const COST_EMBER_THRESHOLD = 5;
162
+ const COST_BLOOD_THRESHOLD = 10;
163
+
164
+ const costColor = (total) =>
165
+ total < COST_TEXT_THRESHOLD ? MUTED :
166
+ total < COST_EMBER_THRESHOLD ? TEXT :
167
+ total < COST_BLOOD_THRESHOLD ? EMBER : BLOOD;
168
+
169
+ const costAmount = (total, incomplete = false) => {
170
+ const value = total >= COST_DISPLAY_THRESHOLD ? "$" + total.toFixed(2) : "$";
171
+ const amount = paint(costColor(total), value);
172
+ return incomplete ? amount + paint(AMBER, "?") : amount;
173
+ };
174
+
175
+ const localCost = () => {
176
+ const total = payload.cost?.total_cost_usd;
177
+ return typeof total === "number" && Number.isFinite(total) ? total : undefined;
178
+ };
179
+
180
+ const getRunUsage = () => {
181
+ const runId = text(process.env.CODEDECK_RUN_ID);
182
+ if (!runId) return undefined;
183
+
184
+ try {
185
+ const output = execFileSync("codedeck", ["usage", runId, "--json"], {
186
+ encoding: "utf8",
187
+ stdio: ["ignore", "pipe", "ignore"],
188
+ timeout: 1000,
189
+ maxBuffer: 1024 * 1024,
190
+ });
191
+ const usage = JSON.parse(output);
192
+ if (
193
+ usage === null ||
194
+ typeof usage !== "object" ||
195
+ usage.runId !== runId ||
196
+ typeof usage.inputTokens !== "number" ||
197
+ !Number.isFinite(usage.inputTokens) ||
198
+ typeof usage.outputTokens !== "number" ||
199
+ !Number.isFinite(usage.outputTokens) ||
200
+ typeof usage.cachedTokens !== "number" ||
201
+ !Number.isFinite(usage.cachedTokens) ||
202
+ typeof usage.costUsd !== "number" ||
203
+ !Number.isFinite(usage.costUsd) ||
204
+ typeof usage.sessionCount !== "number" ||
205
+ !Number.isFinite(usage.sessionCount) ||
206
+ typeof usage.activeSessionCount !== "number" ||
207
+ !Number.isFinite(usage.activeSessionCount) ||
208
+ typeof usage.costComplete !== "boolean" ||
209
+ typeof usage.sessionsWithoutCost !== "number" ||
210
+ !Number.isFinite(usage.sessionsWithoutCost)
211
+ ) return undefined;
212
+ return usage;
213
+ } catch {
214
+ return undefined;
215
+ }
216
+ };
217
+
218
+ const local = localCost();
219
+ const runUsage = getRunUsage();
220
+ const workerTokens = runUsage
221
+ ? runUsage.inputTokens + runUsage.outputTokens + runUsage.cachedTokens
222
+ : undefined;
223
+ const tokenField = () => {
224
+ const total = workerTokens ?? (runUsage ? undefined : localTokens());
225
+ return total === undefined ? undefined : paint(MUTED, compactTokens(total) + " tok");
226
+ };
227
+
228
+ const runField = () => {
229
+ if (!runUsage) return undefined;
230
+ const total = (local ?? 0) + runUsage.costUsd;
231
+ const incomplete = !runUsage.costComplete;
232
+ if (!incomplete && total < COST_DISPLAY_THRESHOLD) return undefined;
233
+ return paint(MUTED, "run ") + costAmount(total, incomplete);
234
+ };
235
+
236
+ const localField = () => {
237
+ if (local === undefined || local < COST_DISPLAY_THRESHOLD) return undefined;
238
+ return costAmount(local);
239
+ };
240
+
241
+ const projectBranch = project && branch
242
+ ? paint(TEXT, clean(project)) + paint(MUTED, "/") + paint(BLOOD, clean(branch))
243
+ : project
244
+ ? paint(TEXT, clean(project))
245
+ : branch
246
+ ? paint(BLOOD, clean(branch))
247
+ : undefined;
248
+
61
249
  const fields = [
62
- role && `role:${clean(role)}`,
63
- model && `model:${clean(model)}`,
64
- `branch:${clean(branch) ?? "(none)"}`,
250
+ taskName && paint(EMBER, clean(taskName)),
251
+ role && paint(EMBER, clean(role)),
252
+ projectBranch,
253
+ contextField(),
254
+ tokenField(),
255
+ runUsage ? runField() : localField(),
256
+ runUsage && paint(TEXT, String(Math.max(0, Math.round(runUsage.activeSessionCount))) + " agents"),
65
257
  ].filter(Boolean);
66
258
 
67
- process.stdout.write(fields.join(" · "));
68
- '
259
+ writeSync(1, fields.join(paint(MUTED, " · ")));
260
+ '
@@ -0,0 +1,74 @@
1
+ {
2
+ "$schema": "https://opencode.ai/theme.json",
3
+ "defs": {
4
+ "blood": "#E11D48",
5
+ "shimmer": "#C026D3",
6
+ "ember": "#FB923C",
7
+ "amber": "#FBBF24",
8
+ "remember": "#FACC15",
9
+ "green": "#4ADE80",
10
+ "red": "#FF4D6D",
11
+ "text": "#F7EDEE",
12
+ "muted": "#A38B8F",
13
+ "ink": "#140406",
14
+ "panel": "#1F0A0E",
15
+ "element": "#2A0710",
16
+ "rose": "#FDA4AF",
17
+ "pink": "#F472B6",
18
+ "blue": "#60A5FA",
19
+ "cyan": "#22D3EE",
20
+ "mint": "#34D399",
21
+ "purple": "#C084FC",
22
+ "deepGreen": "#14532D",
23
+ "deepRed": "#7F1D1D"
24
+ },
25
+ "theme": {
26
+ "primary": { "dark": "blood", "light": "blood" },
27
+ "secondary": { "dark": "rose", "light": "blood" },
28
+ "accent": { "dark": "shimmer", "light": "shimmer" },
29
+ "error": { "dark": "red", "light": "red" },
30
+ "warning": { "dark": "amber", "light": "amber" },
31
+ "success": { "dark": "green", "light": "green" },
32
+ "info": { "dark": "blue", "light": "blue" },
33
+ "text": { "dark": "text", "light": "ink" },
34
+ "textMuted": { "dark": "muted", "light": "muted" },
35
+ "background": { "dark": "ink", "light": "text" },
36
+ "backgroundPanel": { "dark": "panel", "light": "rose" },
37
+ "backgroundElement": { "dark": "element", "light": "rose" },
38
+ "border": { "dark": "blood", "light": "blood" },
39
+ "borderActive": { "dark": "ember", "light": "ember" },
40
+ "borderSubtle": { "dark": "muted", "light": "muted" },
41
+ "diffAdded": { "dark": "green", "light": "deepGreen" },
42
+ "diffRemoved": { "dark": "red", "light": "deepRed" },
43
+ "diffContext": { "dark": "muted", "light": "muted" },
44
+ "diffHunkHeader": { "dark": "cyan", "light": "blue" },
45
+ "diffHighlightAdded": { "dark": "green", "light": "deepGreen" },
46
+ "diffHighlightRemoved": { "dark": "red", "light": "deepRed" },
47
+ "diffAddedBg": { "dark": "deepGreen", "light": "green" },
48
+ "diffRemovedBg": { "dark": "deepRed", "light": "red" },
49
+ "diffContextBg": { "dark": "ink", "light": "text" },
50
+ "diffLineNumber": { "dark": "muted", "light": "muted" },
51
+ "diffAddedLineNumberBg": { "dark": "deepGreen", "light": "green" },
52
+ "diffRemovedLineNumberBg": { "dark": "deepRed", "light": "red" },
53
+ "markdownText": { "dark": "text", "light": "ink" },
54
+ "markdownHeading": { "dark": "blood", "light": "blood" },
55
+ "markdownLink": { "dark": "cyan", "light": "blue" },
56
+ "markdownLinkText": { "dark": "cyan", "light": "blue" },
57
+ "markdownCode": { "dark": "ember", "light": "ember" },
58
+ "markdownBlockQuote": { "dark": "muted", "light": "muted" },
59
+ "markdownEmph": { "dark": "rose", "light": "blood" },
60
+ "markdownStrong": { "dark": "text", "light": "ink" },
61
+ "markdownHorizontalRule": { "dark": "blood", "light": "blood" },
62
+ "markdownListItem": { "dark": "ember", "light": "ember" },
63
+ "markdownCodeBlock": { "dark": "element", "light": "rose" },
64
+ "syntaxComment": { "dark": "muted", "light": "muted" },
65
+ "syntaxKeyword": { "dark": "blood", "light": "blood" },
66
+ "syntaxFunction": { "dark": "blue", "light": "blue" },
67
+ "syntaxVariable": { "dark": "cyan", "light": "blue" },
68
+ "syntaxString": { "dark": "green", "light": "deepGreen" },
69
+ "syntaxNumber": { "dark": "ember", "light": "ember" },
70
+ "syntaxType": { "dark": "purple", "light": "shimmer" },
71
+ "syntaxOperator": { "dark": "pink", "light": "blood" },
72
+ "syntaxPunctuation": { "dark": "muted", "light": "muted" }
73
+ }
74
+ }
@@ -1,47 +1,55 @@
1
1
  {
2
- "name": "CodeDeck Ultra",
2
+ "name": "CodeDeck Rage",
3
3
  "base": "dark",
4
4
  "overrides": {
5
- "claude": "#8BE9FD",
6
- "claudeShimmer": "#C4F1FF",
7
- "text": "#F8FAFC",
8
- "inverseText": "#0B1020",
9
- "inactive": "#94A3B8",
10
- "inactiveShimmer": "#CBD5E1",
11
- "subtle": "#475569",
12
- "suggestion": "#67E8F9",
13
- "permission": "#A78BFA",
14
- "permissionShimmer": "#C4B5FD",
5
+ "claude": "#E11D48",
6
+ "claudeShimmer": "#C026D3",
7
+ "claudeBlue_FOR_SYSTEM_SPINNER": "#E11D48",
8
+ "claudeBlueShimmer_FOR_SYSTEM_SPINNER": "#C026D3",
9
+ "autoAcceptShimmer": "#FCA5A5",
10
+ "clawd_body": "#881337",
11
+ "clawd_background": "#140406",
12
+ "background": "#140406",
13
+ "composerSidebarBackground": "#1F0A0E",
14
+ "professionalBlue": "#F43F5E",
15
+ "text": "#F7EDEE",
16
+ "inverseText": "#140406",
17
+ "inactive": "#A38B8F",
18
+ "inactiveShimmer": "#D6C2C5",
19
+ "subtle": "#EC6A5C",
20
+ "suggestion": "#FCA5A5",
21
+ "permission": "#FB923C",
22
+ "permissionShimmer": "#FED7AA",
15
23
  "remember": "#FACC15",
16
- "success": "#34D399",
17
- "error": "#FB7185",
24
+ "success": "#4ADE80",
25
+ "error": "#FF4D6D",
18
26
  "warning": "#FBBF24",
19
27
  "warningShimmer": "#FDE68A",
20
- "merged": "#C084FC",
21
- "promptBorder": "#22D3EE",
22
- "promptBorderShimmer": "#67E8F9",
23
- "planMode": "#60A5FA",
24
- "autoAccept": "#34D399",
28
+ "merged": "#F43F5E",
29
+ "promptBorder": "#E11D48",
30
+ "promptBorderShimmer": "#C026D3",
31
+ "planMode": "#FDA4AF",
32
+ "autoAccept": "#4ADE80",
25
33
  "bashBorder": "#F59E0B",
26
- "ide": "#C084FC",
27
- "fastMode": "#F472B6",
28
- "fastModeShimmer": "#F9A8D4",
29
- "effortUltra": "#A78BFA",
34
+ "ide": "#F43F5E",
35
+ "fastMode": "#FF4D6D",
36
+ "fastModeShimmer": "#FFD1D8",
37
+ "effortUltra": "#FB7185",
30
38
  "diffAdded": "#14532D",
31
39
  "diffRemoved": "#7F1D1D",
32
40
  "diffAddedDimmed": "#166534",
33
41
  "diffRemovedDimmed": "#991B1B",
34
42
  "diffAddedWord": "#22C55E",
35
43
  "diffRemovedWord": "#EF4444",
36
- "userMessageBackground": "#172554",
37
- "userMessageBackgroundHover": "#1E3A8A",
44
+ "userMessageBackground": "#2A0710",
45
+ "userMessageBackgroundHover": "#4C0D1C",
38
46
  "bashMessageBackgroundColor": "#451A03",
39
- "memoryBackgroundColor": "#27272A",
40
- "selectionBg": "#334155",
41
- "rate_limit_fill": "#22D3EE",
42
- "rate_limit_empty": "#334155",
43
- "briefLabelYou": "#67E8F9",
44
- "briefLabelClaude": "#A78BFA",
47
+ "memoryBackgroundColor": "#291B1D",
48
+ "selectionBg": "#4C1D24",
49
+ "rate_limit_fill": "#E11D48",
50
+ "rate_limit_empty": "#3F1E24",
51
+ "briefLabelYou": "#FCA5A5",
52
+ "briefLabelClaude": "#E11D48",
45
53
  "red_FOR_SUBAGENTS_ONLY": "#FB7185",
46
54
  "blue_FOR_SUBAGENTS_ONLY": "#60A5FA",
47
55
  "green_FOR_SUBAGENTS_ONLY": "#34D399",
@@ -50,19 +58,19 @@
50
58
  "orange_FOR_SUBAGENTS_ONLY": "#FB923C",
51
59
  "pink_FOR_SUBAGENTS_ONLY": "#F472B6",
52
60
  "cyan_FOR_SUBAGENTS_ONLY": "#22D3EE",
53
- "rainbow_red": "#EF4444",
54
- "rainbow_red_shimmer": "#FCA5A5",
55
- "rainbow_orange": "#F97316",
56
- "rainbow_orange_shimmer": "#FDBA74",
57
- "rainbow_yellow": "#EAB308",
58
- "rainbow_yellow_shimmer": "#FDE047",
59
- "rainbow_green": "#22C55E",
60
- "rainbow_green_shimmer": "#86EFAC",
61
- "rainbow_blue": "#3B82F6",
62
- "rainbow_blue_shimmer": "#93C5FD",
63
- "rainbow_indigo": "#6366F1",
64
- "rainbow_indigo_shimmer": "#A5B4FC",
65
- "rainbow_violet": "#8B5CF6",
66
- "rainbow_violet_shimmer": "#C4B5FD"
61
+ "rainbow_red": "#7F1D1D",
62
+ "rainbow_red_shimmer": "#B91C1C",
63
+ "rainbow_orange": "#B91C1C",
64
+ "rainbow_orange_shimmer": "#E11D48",
65
+ "rainbow_yellow": "#E11D48",
66
+ "rainbow_yellow_shimmer": "#F43F5E",
67
+ "rainbow_green": "#F43F5E",
68
+ "rainbow_green_shimmer": "#FB7185",
69
+ "rainbow_blue": "#FB7185",
70
+ "rainbow_blue_shimmer": "#FB923C",
71
+ "rainbow_indigo": "#FB923C",
72
+ "rainbow_indigo_shimmer": "#FBBF24",
73
+ "rainbow_violet": "#FBBF24",
74
+ "rainbow_violet_shimmer": "#FDE68A"
67
75
  }
68
76
  }