@standardagents/code 0.11.6 → 0.11.7

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/dist/index.js CHANGED
@@ -135,6 +135,36 @@ function parseSharedMessagingSnapshot(value) {
135
135
  }
136
136
  };
137
137
  }
138
+ function parseComposerDraft(value) {
139
+ const draft = record(value);
140
+ if (!draft || draft.version !== 1 || typeof draft.content !== "string") {
141
+ throw new TypeError("unsupported or malformed shared draft");
142
+ }
143
+ return {
144
+ version: 1,
145
+ revision: finiteNumber(draft.revision, "draft revision"),
146
+ content: draft.content,
147
+ attachments: attachments(draft.attachments),
148
+ updatedAt: finiteNumber(draft.updatedAt, "draft updatedAt"),
149
+ ...origin(draft)
150
+ };
151
+ }
152
+ function parseMessagingChangedEvent(value) {
153
+ const event = record(value);
154
+ if (!event || event.version !== 1) return null;
155
+ try {
156
+ return {
157
+ version: 1,
158
+ pendingRevision: finiteNumber(event.pendingRevision, "event pending revision"),
159
+ draftRevision: finiteNumber(event.draftRevision, "event draft revision"),
160
+ ...event.draft !== void 0 ? { draft: parseComposerDraft(event.draft) } : {},
161
+ ...event.draftOmitted === true ? { draftOmitted: true } : {},
162
+ ...origin(event)
163
+ };
164
+ } catch {
165
+ return null;
166
+ }
167
+ }
138
168
 
139
169
  // src/api.ts
140
170
  var ApiHttpError = class extends Error {
@@ -2690,7 +2720,7 @@ var McpManager = class {
2690
2720
  }
2691
2721
  }
2692
2722
  closeAll() {
2693
- for (const [, c5] of this.clients) c5.close();
2723
+ for (const [, c6] of this.clients) c6.close();
2694
2724
  this.clients.clear();
2695
2725
  }
2696
2726
  get(name) {
@@ -2701,13 +2731,13 @@ var McpManager = class {
2701
2731
  }
2702
2732
  toolCount() {
2703
2733
  let n = 0;
2704
- for (const [, c5] of this.clients) n += c5.tools.length;
2734
+ for (const [, c6] of this.clients) n += c6.tools.length;
2705
2735
  return n;
2706
2736
  }
2707
2737
  /** A JSON-serializable catalog of every connected server for the KV/context. */
2708
2738
  catalog() {
2709
2739
  return {
2710
- servers: Array.from(this.clients.values()).map((c5) => c5.catalogEntry()),
2740
+ servers: Array.from(this.clients.values()).map((c6) => c6.catalogEntry()),
2711
2741
  generatedAt: Date.now()
2712
2742
  };
2713
2743
  }
@@ -2797,9 +2827,9 @@ function flattenContent(content, structured) {
2797
2827
  }
2798
2828
  function flattenResourceContents(contents) {
2799
2829
  const parts = [];
2800
- for (const c5 of contents || []) {
2801
- if (typeof c5.text === "string") parts.push(c5.text);
2802
- else if (typeof c5.blob === "string") parts.push(`[binary resource ${String(c5.uri ?? "")} (${c5.blob.length} b64 chars)]`);
2830
+ for (const c6 of contents || []) {
2831
+ if (typeof c6.text === "string") parts.push(c6.text);
2832
+ else if (typeof c6.blob === "string") parts.push(`[binary resource ${String(c6.uri ?? "")} (${c6.blob.length} b64 chars)]`);
2803
2833
  }
2804
2834
  return parts.join("\n").trim();
2805
2835
  }
@@ -3849,17 +3879,17 @@ function wrapBlock(out, cols2, leadFirst, leadRest, leadWidth, text) {
3849
3879
  function renderTable(rows) {
3850
3880
  const cols2 = Math.max(...rows.map((r) => r.length));
3851
3881
  const widths = [];
3852
- for (let c5 = 0; c5 < cols2; c5++) {
3853
- widths[c5] = Math.max(...rows.map((r) => visibleWidth(inline(r[c5] ?? ""))));
3882
+ for (let c6 = 0; c6 < cols2; c6++) {
3883
+ widths[c6] = Math.max(...rows.map((r) => visibleWidth(inline(r[c6] ?? ""))));
3854
3884
  }
3855
3885
  const sep = `${GRAY} \u2502 ${R}`;
3856
3886
  const out = [];
3857
3887
  rows.forEach((r, ri) => {
3858
3888
  const cells = [];
3859
- for (let c5 = 0; c5 < cols2; c5++) {
3860
- const raw = r[c5] ?? "";
3889
+ for (let c6 = 0; c6 < cols2; c6++) {
3890
+ const raw = r[c6] ?? "";
3861
3891
  const styled = ri === 0 ? `${BOLD}${inline(raw)}${R}` : inline(raw);
3862
- cells.push(padEndVisible(styled, widths[c5]));
3892
+ cells.push(padEndVisible(styled, widths[c6]));
3863
3893
  }
3864
3894
  out.push((" " + cells.join(sep)).replace(/\s+$/, ""));
3865
3895
  if (ri === 0) {
@@ -4331,7 +4361,7 @@ function buildInputBoxRows(opts) {
4331
4361
  let di = 0;
4332
4362
  for (let ci = 0; ci < plainChars.length; ci++) {
4333
4363
  const ch = plainChars[ci];
4334
- const c5 = colorAt(perimeterIndex("top", xi++, W, bodyH));
4364
+ const c6 = colorAt(perimeterIndex("top", xi++, W, bodyH));
4335
4365
  if (ci >= agentSpanStart && ci < agentSpanEnd) {
4336
4366
  top += `\x1B[2m${themeGray}${ch}\x1B[0m`;
4337
4367
  continue;
@@ -4340,9 +4370,9 @@ function buildInputBoxRows(opts) {
4340
4370
  const levelN = Math.max(1, Math.min(5, level));
4341
4371
  const filled = di < levelN;
4342
4372
  di++;
4343
- top += (filled ? levelColor || c5 : "\x1B[38;5;240m") + (filled ? "\u25CF" : "\u25CB") + reset;
4373
+ top += (filled ? levelColor || c6 : "\x1B[38;5;240m") + (filled ? "\u25CF" : "\u25CB") + reset;
4344
4374
  } else {
4345
- top += c5 + ch + reset;
4375
+ top += c6 + ch + reset;
4346
4376
  }
4347
4377
  }
4348
4378
  }
@@ -4363,10 +4393,10 @@ function buildInputBoxRows(opts) {
4363
4393
  let bottom = "";
4364
4394
  for (let x = 0; x < W; x++) {
4365
4395
  const idx = perimeterIndex("bottom", W - 1 - x, W, bodyH);
4366
- const c5 = colorAt(idx);
4367
- if (x === 0) bottom += c5 + "\u2570" + reset;
4368
- else if (x === W - 1) bottom += c5 + "\u256F" + reset;
4369
- else bottom += c5 + "\u2500" + reset;
4396
+ const c6 = colorAt(idx);
4397
+ if (x === 0) bottom += c6 + "\u2570" + reset;
4398
+ else if (x === W - 1) bottom += c6 + "\u256F" + reset;
4399
+ else bottom += c6 + "\u2500" + reset;
4370
4400
  }
4371
4401
  return [pad + top, ...bodyRows, pad + bottom];
4372
4402
  }
@@ -5101,7 +5131,7 @@ var Tui = class _Tui {
5101
5131
  const q = this.inputBuffer.slice(1).trim().toLowerCase();
5102
5132
  if (q === "") return this.commands;
5103
5133
  return this.commands.filter(
5104
- (c5) => c5.name.startsWith(q) || c5.name.includes(q) || c5.label.toLowerCase().includes(q)
5134
+ (c6) => c6.name.startsWith(q) || c6.name.includes(q) || c6.label.toLowerCase().includes(q)
5105
5135
  );
5106
5136
  }
5107
5137
  runCommand(cmd) {
@@ -6460,7 +6490,7 @@ function readVersion() {
6460
6490
  if (typeof pkg.version === "string" && pkg.version) return pkg.version;
6461
6491
  } catch {
6462
6492
  }
6463
- return "0.11.6" ;
6493
+ return "0.11.7" ;
6464
6494
  }
6465
6495
  function isLocalHost(host) {
6466
6496
  return host === "localhost" || host === "127.0.0.1" || host === "::1" || host.endsWith(".local") || host.endsWith(".localhost") || /^10\./.test(host) || /^192\.168\./.test(host) || /^172\.(1[6-9]|2\d|3[01])\./.test(host);
@@ -6819,7 +6849,7 @@ async function clearDaemon(api, identity) {
6819
6849
  function parseCommands(value) {
6820
6850
  if (!Array.isArray(value)) return [];
6821
6851
  return value.filter(
6822
- (c5) => !!c5 && typeof c5 === "object" && typeof c5.id === "string" && typeof c5.kind === "string"
6852
+ (c6) => !!c6 && typeof c6 === "object" && typeof c6.id === "string" && typeof c6.kind === "string"
6823
6853
  );
6824
6854
  }
6825
6855
  async function enqueueMachineCommand(api, machineId, kind, args) {
@@ -6842,7 +6872,7 @@ async function clearMachineCommands(api, machineId, appliedIds) {
6842
6872
  if (appliedIds.length === 0) return;
6843
6873
  const key = commandKey(machineId);
6844
6874
  const remaining = parseCommands(await api.userKvGet(key)).filter(
6845
- (c5) => !appliedIds.includes(c5.id)
6875
+ (c6) => !appliedIds.includes(c6.id)
6846
6876
  );
6847
6877
  await api.userKvSet(key, remaining.length ? remaining : null);
6848
6878
  }
@@ -7228,7 +7258,7 @@ var HubSocket = class {
7228
7258
  }
7229
7259
  openSocket() {
7230
7260
  if (this.closed) return;
7231
- let url = `${this.api.wsEndpoint}/api/users/me/hub?token=${encodeURIComponent(this.api.bearer)}&client_id=${encodeURIComponent(this.clientId)}&client_kind=daemon`;
7261
+ let url = `${this.api.wsEndpoint}/api/users/me/stream?token=${encodeURIComponent(this.api.bearer)}&client_id=${encodeURIComponent(this.clientId)}&client_kind=daemon`;
7232
7262
  if (this.clientName) url += `&client_name=${encodeURIComponent(this.clientName)}`;
7233
7263
  let ws;
7234
7264
  try {
@@ -7257,8 +7287,15 @@ var HubSocket = class {
7257
7287
  } catch {
7258
7288
  return;
7259
7289
  }
7260
- if (msg && typeof msg === "object" && msg.type === "wake" && typeof msg.threadId === "string") {
7261
- this.hooks.onWake(msg.threadId);
7290
+ if (!msg || typeof msg !== "object") return;
7291
+ const frame = msg;
7292
+ if (frame.event === "standardagents.wake") {
7293
+ const threadId = frame.data?.thread_id;
7294
+ if (typeof threadId === "string") this.hooks.onWake(threadId);
7295
+ return;
7296
+ }
7297
+ if (frame.type === "wake" && typeof frame.threadId === "string") {
7298
+ this.hooks.onWake(frame.threadId);
7262
7299
  }
7263
7300
  }
7264
7301
  handleDrop(ws) {
@@ -8303,8 +8340,127 @@ async function runDaemonCommand(argv) {
8303
8340
  }
8304
8341
  }
8305
8342
 
8306
- // src/index.ts
8343
+ // src/auth-cli.ts
8307
8344
  var c4 = {
8345
+ reset: "\x1B[0m",
8346
+ dim: "\x1B[2m",
8347
+ bold: "\x1B[1m",
8348
+ green: "\x1B[32m",
8349
+ red: "\x1B[31m",
8350
+ teal: "\x1B[38;5;43m"
8351
+ };
8352
+ function parseAuthArgs(argv) {
8353
+ let endpoint = null;
8354
+ let token = null;
8355
+ for (let i = 0; i < argv.length; i += 1) {
8356
+ const arg = argv[i];
8357
+ if (arg === "--endpoint" || arg === "-e") {
8358
+ endpoint = argv[++i] ?? "";
8359
+ if (!endpoint) throw new Error("--endpoint requires a URL");
8360
+ } else if (arg.startsWith("--endpoint=")) {
8361
+ endpoint = arg.slice("--endpoint=".length);
8362
+ } else if (arg === "--token") {
8363
+ token = argv[++i] ?? "";
8364
+ if (!token) throw new Error("--token requires a value");
8365
+ } else if (arg.startsWith("--token=")) {
8366
+ token = arg.slice("--token=".length);
8367
+ } else {
8368
+ throw new Error(`Unknown option for login/logout: ${arg}`);
8369
+ }
8370
+ }
8371
+ const endpointExplicit = endpoint !== null;
8372
+ const resolved = normalizeEndpoint(endpoint ?? defaultEndpoint() ?? PRODUCTION_ENDPOINT);
8373
+ return { endpoint: resolved, endpointExplicit, token };
8374
+ }
8375
+ function hostLabel(endpoint) {
8376
+ return endpoint.replace(/^https?:\/\//, "").replace(/\/$/, "");
8377
+ }
8378
+ async function signedInLabel(endpoint, token) {
8379
+ try {
8380
+ const res = await fetch(`${endpoint}/api/auth/me`, {
8381
+ headers: { Authorization: `Bearer ${token}` },
8382
+ signal: AbortSignal.timeout(1e4)
8383
+ });
8384
+ if (!res.ok) return null;
8385
+ const body = await res.json();
8386
+ return body.user?.email || body.user?.username || null;
8387
+ } catch {
8388
+ return null;
8389
+ }
8390
+ }
8391
+ async function runAuthCommand(command, argv) {
8392
+ let args;
8393
+ try {
8394
+ args = parseAuthArgs(argv);
8395
+ } catch (error) {
8396
+ process.stdout.write(`${c4.red}error:${c4.reset} ${error instanceof Error ? error.message : String(error)}
8397
+ `);
8398
+ process.stdout.write(`${c4.dim}usage: standardcode ${command} [--endpoint <url>]${command === "login" ? " [--token <key>]" : ""}${c4.reset}
8399
+ `);
8400
+ process.exitCode = 1;
8401
+ return;
8402
+ }
8403
+ const host = hostLabel(args.endpoint);
8404
+ relaxTlsForLocalEndpoint(args.endpoint);
8405
+ const existing = getCredential(args.endpoint);
8406
+ if (command === "logout") {
8407
+ if (!existing) {
8408
+ process.stdout.write(`You're not signed in to ${c4.teal}${host}${c4.reset} \u2014 nothing to do.
8409
+ `);
8410
+ return;
8411
+ }
8412
+ deleteCredential(args.endpoint);
8413
+ process.stdout.write(`${c4.green}\u2713${c4.reset} Signed out of ${c4.teal}${host}${c4.reset}.
8414
+ `);
8415
+ process.stdout.write(`${c4.dim}Run \`standardcode login\` to sign in again \u2014 with any account.${c4.reset}
8416
+ `);
8417
+ return;
8418
+ }
8419
+ if (existing) {
8420
+ const who2 = await signedInLabel(args.endpoint, existing.access_token);
8421
+ process.stdout.write(
8422
+ `${c4.dim}Currently signed in to ${host}${who2 ? ` as ${who2}` : ""} \u2014 replacing that sign-in.${c4.reset}
8423
+ `
8424
+ );
8425
+ }
8426
+ let token = args.token;
8427
+ if (!token) {
8428
+ process.stdout.write(`${c4.bold}Sign in to Standard Code${c4.reset}
8429
+ `);
8430
+ if (`https://${host}` !== PRODUCTION_ENDPOINT && `http://${host}` !== PRODUCTION_ENDPOINT) {
8431
+ process.stdout.write(`${c4.dim}Connecting to${c4.reset} ${c4.teal}${host}${c4.reset}
8432
+ `);
8433
+ }
8434
+ try {
8435
+ token = await deviceLogin(args.endpoint);
8436
+ } catch (error) {
8437
+ process.stdout.write(`${c4.red}\u2717${c4.reset} ${error instanceof Error ? error.message : String(error)}
8438
+ `);
8439
+ process.exitCode = 1;
8440
+ return;
8441
+ }
8442
+ }
8443
+ const api = new ApiClient(args.endpoint, token);
8444
+ const check = await api.verifyDetailed();
8445
+ if (!check.ok) {
8446
+ process.stdout.write(`${c4.red}\u2717${c4.reset} Sign-in didn't verify: ${check.reason}
8447
+ `);
8448
+ if (check.hint) process.stdout.write(` ${c4.dim}${check.hint}${c4.reset}
8449
+ `);
8450
+ process.exitCode = 1;
8451
+ return;
8452
+ }
8453
+ saveCredential(
8454
+ { endpoint: args.endpoint, access_token: token, token_type: "Bearer", saved_at: Date.now() },
8455
+ { updateDefault: !args.endpointExplicit }
8456
+ );
8457
+ const who = await signedInLabel(args.endpoint, token);
8458
+ process.stdout.write(`${c4.green}\u2713${c4.reset} Signed in to ${c4.teal}${host}${c4.reset}${who ? ` as ${c4.bold}${who}${c4.reset}` : ""}.
8459
+ `);
8460
+ }
8461
+
8462
+ // src/index.ts
8463
+ var c5 = {
8308
8464
  reset: "\x1B[0m",
8309
8465
  dim: "\x1B[2m",
8310
8466
  bold: "\x1B[1m",
@@ -8333,10 +8489,16 @@ function printUsage() {
8333
8489
  stdout.write(
8334
8490
  [
8335
8491
  "",
8336
- `${c4.bold}Usage${c4.reset}`,
8492
+ `${c5.bold}Usage${c5.reset}`,
8337
8493
  " standardcode [options] [dir]",
8494
+ " standardcode login [--endpoint <url>] [--token <key>]",
8495
+ " Sign in (or switch accounts \u2014 always re-runs the flow).",
8496
+ " standardcode logout [--endpoint <url>]",
8497
+ " Sign out of the saved endpoint.",
8498
+ " standardcode daemon <install|run|status|uninstall>",
8499
+ " Manage this machine's headless execution daemon.",
8338
8500
  "",
8339
- `${c4.bold}Options${c4.reset}`,
8501
+ `${c5.bold}Options${c5.reset}`,
8340
8502
  " -v, --version Print the Standard Code version and exit.",
8341
8503
  " -e, --endpoint [url] Use a different Standard Agents instance for this run",
8342
8504
  " (default: https://api.standardcode.ai).",
@@ -8405,15 +8567,15 @@ function parseArgs2(args) {
8405
8567
  }
8406
8568
  function printCommandBlock(tui, command, output4, ok, where) {
8407
8569
  tui.print("");
8408
- const note = where ? ` ${c4.dim}(ran on ${where})${c4.reset}` : "";
8409
- tui.print(`${c4.magenta}!${c4.reset} ${c4.bold}${command}${c4.reset}${note}`);
8570
+ const note = where ? ` ${c5.dim}(ran on ${where})${c5.reset}` : "";
8571
+ tui.print(`${c5.magenta}!${c5.reset} ${c5.bold}${command}${c5.reset}${note}`);
8410
8572
  const body = (output4 ?? "").replace(/\s+$/, "");
8411
8573
  if (body) {
8412
8574
  for (const line of body.split("\n")) {
8413
- tui.print(` ${ok ? c4.dim : c4.red}${line}${c4.reset}`);
8575
+ tui.print(` ${ok ? c5.dim : c5.red}${line}${c5.reset}`);
8414
8576
  }
8415
8577
  } else {
8416
- tui.print(` ${c4.dim}(no output)${c4.reset}`);
8578
+ tui.print(` ${c5.dim}(no output)${c5.reset}`);
8417
8579
  }
8418
8580
  tui.print("");
8419
8581
  }
@@ -8424,7 +8586,7 @@ function printAssistant(tui, text) {
8424
8586
  let dotted = false;
8425
8587
  for (const line of renderStreamingMarkdown(text, cols2)) {
8426
8588
  if (!dotted && line.trim()) {
8427
- tui.print(`${c4.gray}\u2022${c4.reset} ${line}`);
8589
+ tui.print(`${c5.gray}\u2022${c5.reset} ${line}`);
8428
8590
  dotted = true;
8429
8591
  } else {
8430
8592
  tui.print(` ${line}`);
@@ -8439,7 +8601,7 @@ function startLoader(label) {
8439
8601
  const draw = () => {
8440
8602
  const now = Date.now();
8441
8603
  const f = frames[Math.floor(now / 70) % frames.length];
8442
- stdout.write(`\r\x1B[K${pad}${brandCycleColor(now)}${f}${c4.reset} ${c4.dim}${label}\u2026${c4.reset}`);
8604
+ stdout.write(`\r\x1B[K${pad}${brandCycleColor(now)}${f}${c5.reset} ${c5.dim}${label}\u2026${c5.reset}`);
8443
8605
  };
8444
8606
  draw();
8445
8607
  const timer = setInterval(draw, 70);
@@ -8455,12 +8617,12 @@ function farewell(stoppedProcs = 0) {
8455
8617
  if (stoppedProcs > 0) {
8456
8618
  stdout.write(
8457
8619
  `
8458
- ${c4.cyan}\u2699${c4.reset} Stopped ${stoppedProcs} background process${stoppedProcs === 1 ? "" : "es"}.
8620
+ ${c5.cyan}\u2699${c5.reset} Stopped ${stoppedProcs} background process${stoppedProcs === 1 ? "" : "es"}.
8459
8621
  `
8460
8622
  );
8461
8623
  }
8462
8624
  stdout.write(`
8463
- ${c4.teal}\u25C7${c4.reset} ${c4.dim}Standard Code \u2014 see you soon.${c4.reset}
8625
+ ${c5.teal}\u25C7${c5.reset} ${c5.dim}Standard Code \u2014 see you soon.${c5.reset}
8464
8626
  `);
8465
8627
  }
8466
8628
  function printWelcome(endpoint, projectDir) {
@@ -8474,10 +8636,10 @@ function printWelcome(endpoint, projectDir) {
8474
8636
  const metaWidth = Math.max(1, terminalColumns - pad.length - markWidth - 3 - 1);
8475
8637
  const displayDir = truncateMiddle(dir2, metaWidth);
8476
8638
  const meta = [
8477
- `${c4.bold}${gradientText("Standard Code")}${c4.reset}${version ? ` ${c4.dim}v${version}${c4.reset}` : ""}`,
8478
- `${c4.dim}terminal coding agent${c4.reset}`,
8479
- ...endpoint === PRODUCTION_ENDPOINT ? [] : [`${c4.teal}${host}${c4.reset}`],
8480
- `${c4.dim}${displayDir}${c4.reset}`
8639
+ `${c5.bold}${gradientText("Standard Code")}${c5.reset}${version ? ` ${c5.dim}v${version}${c5.reset}` : ""}`,
8640
+ `${c5.dim}terminal coding agent${c5.reset}`,
8641
+ ...endpoint === PRODUCTION_ENDPOINT ? [] : [`${c5.teal}${host}${c5.reset}`],
8642
+ `${c5.dim}${displayDir}${c5.reset}`
8481
8643
  ];
8482
8644
  const metaTop = Math.floor((LOGO_MARK.length - meta.length) / 2);
8483
8645
  stdout.write("\n");
@@ -8491,11 +8653,11 @@ function printWelcome(endpoint, projectDir) {
8491
8653
  }
8492
8654
  function colorActivity(line) {
8493
8655
  const m = line.match(/^(\s*)([✓✗⛔])\s?([\s\S]*)$/);
8494
- if (!m) return `${c4.dim}${line}${c4.reset}`;
8656
+ if (!m) return `${c5.dim}${line}${c5.reset}`;
8495
8657
  const [, indent, glyph, rest] = m;
8496
8658
  if (glyph === "\u2713") {
8497
- const body = rest.replace(/\s(\([^()]*\))\s*$/, ` ${c4.dim}$1${c4.reset}`);
8498
- return `${indent}${c4.green}\u2713${c4.reset} ${body}`;
8659
+ const body = rest.replace(/\s(\([^()]*\))\s*$/, ` ${c5.dim}$1${c5.reset}`);
8660
+ return `${indent}${c5.green}\u2713${c5.reset} ${body}`;
8499
8661
  }
8500
8662
  if (glyph === "\u2717") {
8501
8663
  const ERR_MAX_LINES = 7;
@@ -8503,15 +8665,15 @@ function colorActivity(line) {
8503
8665
  const shown = lines.slice(0, ERR_MAX_LINES);
8504
8666
  const hidden = lines.length - shown.length;
8505
8667
  const body = shown.map(
8506
- (l, i) => i === 0 ? `${indent}${c4.red}\u2717 ${l}${c4.reset}` : `${indent}${c4.red}${c4.dim}${l}${c4.reset}`
8668
+ (l, i) => i === 0 ? `${indent}${c5.red}\u2717 ${l}${c5.reset}` : `${indent}${c5.red}${c5.dim}${l}${c5.reset}`
8507
8669
  ).join("\n");
8508
8670
  if (hidden > 0) {
8509
8671
  return `${body}
8510
- ${indent}${c4.dim}\u2026 +${hidden} more line${hidden === 1 ? "" : "s"}${c4.reset}`;
8672
+ ${indent}${c5.dim}\u2026 +${hidden} more line${hidden === 1 ? "" : "s"}${c5.reset}`;
8511
8673
  }
8512
8674
  return body;
8513
8675
  }
8514
- return `${indent}${c4.yellow}\u26D4 ${rest}${c4.reset}`;
8676
+ return `${indent}${c5.yellow}\u26D4 ${rest}${c5.reset}`;
8515
8677
  }
8516
8678
  async function main() {
8517
8679
  if (process.argv.slice(2).some((arg) => arg === "-v" || arg === "--version")) {
@@ -8523,11 +8685,15 @@ async function main() {
8523
8685
  await runDaemonCommand(process.argv.slice(3));
8524
8686
  return;
8525
8687
  }
8688
+ if (process.argv[2] === "login" || process.argv[2] === "logout") {
8689
+ await runAuthCommand(process.argv[2], process.argv.slice(3));
8690
+ return;
8691
+ }
8526
8692
  let cliArgs;
8527
8693
  try {
8528
8694
  cliArgs = parseArgs2(process.argv.slice(2));
8529
8695
  } catch (error) {
8530
- stdout.write(`${c4.red}error:${c4.reset} ${error instanceof Error ? error.message : String(error)}
8696
+ stdout.write(`${c5.red}error:${c5.reset} ${error instanceof Error ? error.message : String(error)}
8531
8697
  `);
8532
8698
  printUsage();
8533
8699
  process.exit(1);
@@ -8554,7 +8720,7 @@ async function main() {
8554
8720
  }
8555
8721
  preflightArmed = true;
8556
8722
  stdout.write(`
8557
- ${c4.dim}Press Control-C again to exit${c4.reset}
8723
+ ${c5.dim}Press Control-C again to exit${c5.reset}
8558
8724
  `);
8559
8725
  preflightTimer = setTimeout(() => {
8560
8726
  preflightArmed = false;
@@ -8576,10 +8742,10 @@ ${c4.dim}Press Control-C again to exit${c4.reset}
8576
8742
  const askEndpoint = async () => {
8577
8743
  for (; ; ) {
8578
8744
  const answer = (await ask(
8579
- `${c4.cyan}Standard Agents instance URL${c4.reset} (e.g. http://localhost:5178): `
8745
+ `${c5.cyan}Standard Agents instance URL${c5.reset} (e.g. http://localhost:5178): `
8580
8746
  )).trim();
8581
8747
  if (answer) return answer;
8582
- stdout.write(`${c4.dim}An endpoint URL is required.${c4.reset}
8748
+ stdout.write(`${c5.dim}An endpoint URL is required.${c5.reset}
8583
8749
  `);
8584
8750
  }
8585
8751
  };
@@ -8594,7 +8760,7 @@ ${c4.dim}Press Control-C again to exit${c4.reset}
8594
8760
  const tlsRelaxed = relaxTlsForLocalEndpoint(endpoint);
8595
8761
  printWelcome(endpoint, projectDir);
8596
8762
  if (tlsRelaxed) {
8597
- stdout.write(`${c4.dim} TLS verification relaxed for local endpoint.${c4.reset}
8763
+ stdout.write(`${c5.dim} TLS verification relaxed for local endpoint.${c5.reset}
8598
8764
 
8599
8765
  `);
8600
8766
  }
@@ -8606,7 +8772,7 @@ ${c4.dim}Press Control-C again to exit${c4.reset}
8606
8772
  loading.stop();
8607
8773
  const applied = consumeAppliedUpdate(version);
8608
8774
  if (applied) {
8609
- stdout.write(` ${c4.green}\u2713${c4.reset} ${c4.dim}Standard Code updated to v${version}.${c4.reset}
8775
+ stdout.write(` ${c5.green}\u2713${c5.reset} ${c5.dim}Standard Code updated to v${version}.${c5.reset}
8610
8776
 
8611
8777
  `);
8612
8778
  }
@@ -8615,21 +8781,21 @@ ${c4.dim}Press Control-C again to exit${c4.reset}
8615
8781
  const decision = decideAutoUpdate(updateAvailable, { state: readAutoUpdateState(), pm });
8616
8782
  if (decision === "start" && pm && startBackgroundUpdate(updateAvailable.latest, pm)) {
8617
8783
  stdout.write(
8618
- ` ${c4.teal}\u27F3${c4.reset} ${c4.dim}Standard Code ${c4.reset}${c4.bold}v${updateAvailable.latest}${c4.reset}${c4.dim} is installing in the background \u2014 it applies on your next launch.${c4.reset}
8784
+ ` ${c5.teal}\u27F3${c5.reset} ${c5.dim}Standard Code ${c5.reset}${c5.bold}v${updateAvailable.latest}${c5.reset}${c5.dim} is installing in the background \u2014 it applies on your next launch.${c5.reset}
8619
8785
 
8620
8786
  `
8621
8787
  );
8622
8788
  } else if (decision === "in_flight") {
8623
8789
  stdout.write(
8624
- ` ${c4.teal}\u27F3${c4.reset} ${c4.dim}Standard Code v${updateAvailable.latest} is still installing in the background.${c4.reset}
8790
+ ` ${c5.teal}\u27F3${c5.reset} ${c5.dim}Standard Code v${updateAvailable.latest} is still installing in the background.${c5.reset}
8625
8791
 
8626
8792
  `
8627
8793
  );
8628
8794
  } else {
8629
8795
  const display = updateCommand(pm ?? "npm").display;
8630
8796
  stdout.write(
8631
- ` ${c4.teal}\u25C7${c4.reset} ${c4.dim}Update available:${c4.reset} ${c4.dim}v${updateAvailable.current}${c4.reset} \u2192 ${c4.bold}v${updateAvailable.latest}${c4.reset}
8632
- ${c4.dim}Run ${c4.reset}${c4.bold}${display}${c4.reset}${c4.dim} to update${c4.reset}
8797
+ ` ${c5.teal}\u25C7${c5.reset} ${c5.dim}Update available:${c5.reset} ${c5.dim}v${updateAvailable.current}${c5.reset} \u2192 ${c5.bold}v${updateAvailable.latest}${c5.reset}
8798
+ ${c5.dim}Run ${c5.reset}${c5.bold}${display}${c5.reset}${c5.dim} to update${c5.reset}
8633
8799
 
8634
8800
  `
8635
8801
  );
@@ -8647,39 +8813,39 @@ ${c4.dim}Press Control-C again to exit${c4.reset}
8647
8813
  if (!api || !storedCheck?.ok) {
8648
8814
  const host = endpoint.replace(/^https?:\/\//, "").replace(/\/$/, "");
8649
8815
  if (storedCheck && !storedCheck.ok) {
8650
- stdout.write(`${c4.red}\u2717${c4.reset} ${c4.dim}Saved sign-in for this endpoint failed:${c4.reset} ${storedCheck.reason}
8816
+ stdout.write(`${c5.red}\u2717${c5.reset} ${c5.dim}Saved sign-in for this endpoint failed:${c5.reset} ${storedCheck.reason}
8651
8817
  `);
8652
- if (storedCheck.hint) stdout.write(` ${c4.dim}${storedCheck.hint}${c4.reset}
8818
+ if (storedCheck.hint) stdout.write(` ${c5.dim}${storedCheck.hint}${c5.reset}
8653
8819
  `);
8654
8820
  stdout.write("\n");
8655
8821
  }
8656
8822
  const explainFailure = (result, prefix) => {
8657
- stdout.write(`${c4.red}\u2717${c4.reset} ${prefix}${result.reason}
8823
+ stdout.write(`${c5.red}\u2717${c5.reset} ${prefix}${result.reason}
8658
8824
  `);
8659
- if (result.hint) stdout.write(` ${c4.dim}${result.hint}${c4.reset}
8825
+ if (result.hint) stdout.write(` ${c5.dim}${result.hint}${c5.reset}
8660
8826
  `);
8661
8827
  };
8662
- stdout.write(`${c4.bold}Sign in to ${gradientText("Standard Code")}${c4.reset}
8828
+ stdout.write(`${c5.bold}Sign in to ${gradientText("Standard Code")}${c5.reset}
8663
8829
  `);
8664
8830
  if (`https://${host}` !== PRODUCTION_ENDPOINT) {
8665
- stdout.write(`${c4.dim}Connecting to${c4.reset} ${c4.teal}${host}${c4.reset}
8831
+ stdout.write(`${c5.dim}Connecting to${c5.reset} ${c5.teal}${host}${c5.reset}
8666
8832
  `);
8667
8833
  }
8668
8834
  stdout.write(
8669
- `${c4.dim}You'll only need to do this once on this machine.${c4.reset}
8835
+ `${c5.dim}You'll only need to do this once on this machine.${c5.reset}
8670
8836
 
8671
8837
  `
8672
8838
  );
8673
8839
  stdout.write(
8674
- `${c4.white}Press ${c4.bold}Enter${c4.reset}${c4.white} to open your browser and sign in.${c4.reset} ${c4.dim}(or paste an API token)${c4.reset}
8840
+ `${c5.white}Press ${c5.bold}Enter${c5.reset}${c5.white} to open your browser and sign in.${c5.reset} ${c5.dim}(or paste an API token)${c5.reset}
8675
8841
 
8676
8842
  `
8677
8843
  );
8678
8844
  for (; ; ) {
8679
- const token = (await ask(`${c4.teal}\u276F${c4.reset} `)).trim();
8845
+ const token = (await ask(`${c5.teal}\u276F${c5.reset} `)).trim();
8680
8846
  if (!token) {
8681
8847
  const got = await deviceLogin(endpoint).catch((e) => {
8682
- stdout.write(`${c4.red}\u2717${c4.reset} ${c4.dim}${e instanceof Error ? e.message : String(e)}${c4.reset}
8848
+ stdout.write(`${c5.red}\u2717${c5.reset} ${c5.dim}${e instanceof Error ? e.message : String(e)}${c5.reset}
8683
8849
  `);
8684
8850
  return null;
8685
8851
  });
@@ -8693,7 +8859,7 @@ ${c4.dim}Press Control-C again to exit${c4.reset}
8693
8859
  { endpoint, access_token: got, token_type: "Bearer", saved_at: Date.now() },
8694
8860
  { updateDefault: !endpointOverride }
8695
8861
  );
8696
- stdout.write(`${c4.green}\u2713${c4.reset} Connected to ${c4.teal}${host}${c4.reset}
8862
+ stdout.write(`${c5.green}\u2713${c5.reset} Connected to ${c5.teal}${host}${c5.reset}
8697
8863
  `);
8698
8864
  break;
8699
8865
  }
@@ -8709,7 +8875,7 @@ ${c4.dim}Press Control-C again to exit${c4.reset}
8709
8875
  { endpoint, access_token: token, token_type: "Bearer", saved_at: Date.now() },
8710
8876
  { updateDefault: !endpointOverride }
8711
8877
  );
8712
- stdout.write(`${c4.green}\u2713${c4.reset} Connected to ${c4.teal}${host}${c4.reset}
8878
+ stdout.write(`${c5.green}\u2713${c5.reset} Connected to ${c5.teal}${host}${c5.reset}
8713
8879
  `);
8714
8880
  break;
8715
8881
  }
@@ -8733,7 +8899,7 @@ ${c4.dim}Press Control-C again to exit${c4.reset}
8733
8899
  } else if (["unlimited", "standard", "unlimited_one", AGENT_ID].includes(wanted)) {
8734
8900
  agentOverride = AGENT_ID;
8735
8901
  } else {
8736
- stdout.write(`${c4.red}error:${c4.reset} Unknown agent "${cliArgs.agent}". Use unlimited or sama.
8902
+ stdout.write(`${c5.red}error:${c5.reset} Unknown agent "${cliArgs.agent}". Use unlimited or sama.
8737
8903
  `);
8738
8904
  process.exit(1);
8739
8905
  }
@@ -8771,7 +8937,7 @@ ${c4.dim}Press Control-C again to exit${c4.reset}
8771
8937
  flow: for (; ; ) {
8772
8938
  if (step === "machine") {
8773
8939
  const picked = await tui.select(
8774
- `${c4.bold}Where should this session run?${c4.reset} ${c4.dim}\u2191\u2193 \xB7 enter \xB7 esc${c4.reset}`,
8940
+ `${c5.bold}Where should this session run?${c5.reset} ${c5.dim}\u2191\u2193 \xB7 enter \xB7 esc${c5.reset}`,
8775
8941
  [
8776
8942
  {
8777
8943
  label: `This machine \u2014 ${self ? machineDisplayName(self) : machine}`,
@@ -8855,7 +9021,7 @@ ${c4.dim}Press Control-C again to exit${c4.reset}
8855
9021
  items.push({ label: "\uFF0B Start a new session", value: null });
8856
9022
  const whereLabel = session.mode === "remote" && session.runner ? `${session.runner.name}:${shortenPath(session.remotePath ?? "")}` : shortDir;
8857
9023
  const picked = await tui.select(
8858
- `${c4.bold}Resume a session${c4.reset} ${c4.gray}${whereLabel}${c4.reset} ${c4.dim}\u2191\u2193 \xB7 enter \xB7 esc${c4.reset}`,
9024
+ `${c5.bold}Resume a session${c5.reset} ${c5.gray}${whereLabel}${c5.reset} ${c5.dim}\u2191\u2193 \xB7 enter \xB7 esc${c5.reset}`,
8859
9025
  items
8860
9026
  );
8861
9027
  if (picked === void 0) {
@@ -8881,7 +9047,7 @@ ${c4.dim}Press Control-C again to exit${c4.reset}
8881
9047
  } else {
8882
9048
  if (!agentOverride) {
8883
9049
  const picked = await tui.select(
8884
- `${c4.bold}Which agent?${c4.reset} ${c4.dim}\u2191\u2193 \xB7 enter \xB7 esc${c4.reset}`,
9050
+ `${c5.bold}Which agent?${c5.reset} ${c5.dim}\u2191\u2193 \xB7 enter \xB7 esc${c5.reset}`,
8885
9051
  AGENT_CHOICES.map((choice) => ({
8886
9052
  label: choice.title,
8887
9053
  hint: choice.description,
@@ -8931,7 +9097,7 @@ async function ensureSamaAuth(tui, api) {
8931
9097
  checking.stop();
8932
9098
  if (already) return true;
8933
9099
  const picked = await tui.select(
8934
- `${c4.bold}Authenticate with ChatGPT${c4.reset} ${c4.dim}Sama One runs on OpenAI using your own ChatGPT Pro account${c4.reset}`,
9100
+ `${c5.bold}Authenticate with ChatGPT${c5.reset} ${c5.dim}Sama One runs on OpenAI using your own ChatGPT Pro account${c5.reset}`,
8935
9101
  [
8936
9102
  {
8937
9103
  label: "Continue with ChatGPT",
@@ -8944,7 +9110,7 @@ async function ensureSamaAuth(tui, api) {
8944
9110
  if (picked !== "continue") return false;
8945
9111
  openUrl("https://standardcode.ai/app?connect=sama");
8946
9112
  tui.print(
8947
- `${c4.dim}Finish connecting ChatGPT in the browser \u2014 waiting here for the authorization to land on your account\u2026${c4.reset}`
9113
+ `${c5.dim}Finish connecting ChatGPT in the browser \u2014 waiting here for the authorization to land on your account\u2026${c5.reset}`
8948
9114
  );
8949
9115
  const waiting = startLoader("Waiting for your ChatGPT authorization");
8950
9116
  const deadline = Date.now() + 5 * 60 * 1e3;
@@ -8953,20 +9119,20 @@ async function ensureSamaAuth(tui, api) {
8953
9119
  if (await api.openSamaStatus().catch(() => false)) {
8954
9120
  waiting.stop();
8955
9121
  tui.print(
8956
- `${c4.green}\u2713${c4.reset} ChatGPT connected \u2014 Sama One is now unlocked on your account (terminal, web, and macOS app).`
9122
+ `${c5.green}\u2713${c5.reset} ChatGPT connected \u2014 Sama One is now unlocked on your account (terminal, web, and macOS app).`
8957
9123
  );
8958
9124
  return true;
8959
9125
  }
8960
9126
  }
8961
9127
  waiting.stop();
8962
9128
  tui.print(
8963
- `${c4.yellow}Still not connected.${c4.reset} Finish the flow at ${c4.teal}standardcode.ai/app${c4.reset} and pick Sama One again.`
9129
+ `${c5.yellow}Still not connected.${c5.reset} Finish the flow at ${c5.teal}standardcode.ai/app${c5.reset} and pick Sama One again.`
8964
9130
  );
8965
9131
  return false;
8966
9132
  }
8967
9133
  async function runAgentSwitchMenu(tui, api, threadId) {
8968
9134
  const picked = await tui.select(
8969
- `${c4.bold}Switch agent${c4.reset} ${c4.dim}takes effect on the next message${c4.reset}`,
9135
+ `${c5.bold}Switch agent${c5.reset} ${c5.dim}takes effect on the next message${c5.reset}`,
8970
9136
  AGENT_CHOICES.map((choice) => ({
8971
9137
  label: choice.title,
8972
9138
  hint: choice.description,
@@ -8983,10 +9149,10 @@ async function runAgentSwitchMenu(tui, api, threadId) {
8983
9149
  try {
8984
9150
  await api.setThreadAgent(threadId, picked);
8985
9151
  tui.setAgentLabel(title);
8986
- tui.print(`${c4.green}\u2713${c4.reset} Session handed to ${c4.bold}${title}${c4.reset} \u2014 applies from your next message.`);
9152
+ tui.print(`${c5.green}\u2713${c5.reset} Session handed to ${c5.bold}${title}${c5.reset} \u2014 applies from your next message.`);
8987
9153
  } catch (e) {
8988
9154
  tui.print(
8989
- `${c4.red}\u2717 couldn't switch agent:${c4.reset} ${c4.gray}${e instanceof Error ? e.message : String(e)}${c4.reset}`
9155
+ `${c5.red}\u2717 couldn't switch agent:${c5.reset} ${c5.gray}${e instanceof Error ? e.message : String(e)}${c5.reset}`
8990
9156
  );
8991
9157
  }
8992
9158
  }
@@ -9011,7 +9177,7 @@ async function pickLocalProject(tui, api, self, cwd, machineName) {
9011
9177
  { label: "\uFF0B New project", hint: "browse or create a directory", value: NEW }
9012
9178
  ];
9013
9179
  const picked = await tui.select(
9014
- `${c4.bold}Project on ${label}${c4.reset} ${c4.dim}\u2191\u2193 \xB7 enter \xB7 esc${c4.reset}`,
9180
+ `${c5.bold}Project on ${label}${c5.reset} ${c5.dim}\u2191\u2193 \xB7 enter \xB7 esc${c5.reset}`,
9015
9181
  items,
9016
9182
  { spaced: true }
9017
9183
  );
@@ -9035,7 +9201,7 @@ async function pickRemoteProject(tui, api, runner) {
9035
9201
  );
9036
9202
  items.push({ label: "\uFF0B New project", hint: "browse or create a directory", value: ENTER_PATH });
9037
9203
  const picked = await tui.select(
9038
- `${c4.bold}Project on ${runner.name}${c4.reset} ${c4.dim}\u2191\u2193 \xB7 enter \xB7 esc${c4.reset}`,
9204
+ `${c5.bold}Project on ${runner.name}${c5.reset} ${c5.dim}\u2191\u2193 \xB7 enter \xB7 esc${c5.reset}`,
9039
9205
  items,
9040
9206
  { spaced: true }
9041
9207
  );
@@ -9068,7 +9234,7 @@ async function summarizeThreads(api, threads) {
9068
9234
  }
9069
9235
  function subagentLabel(s, titles) {
9070
9236
  const agentName = (s.agent_name || "").trim();
9071
- const title = (s.title || "").trim() || titles.get(agentName) || (agentName ? agentName.replace(/[_-]+/g, " ").replace(/\b\w/g, (c5) => c5.toUpperCase()) : "Subagent");
9237
+ const title = (s.title || "").trim() || titles.get(agentName) || (agentName ? agentName.replace(/[_-]+/g, " ").replace(/\b\w/g, (c6) => c6.toUpperCase()) : "Subagent");
9072
9238
  const tagged = (s.threadName || "").trim();
9073
9239
  return tagged ? `${title} \xB7 ${tagged}` : title;
9074
9240
  }
@@ -9091,8 +9257,8 @@ async function printHistory(api, threadId, tui) {
9091
9257
  ).sort((a, b) => (a.created_at ?? 0) - (b.created_at ?? 0));
9092
9258
  if (!convo.length) return;
9093
9259
  const shown = convo.slice(-24);
9094
- tui.print(`${c4.dim}\u2500\u2500 resuming session \xB7 ${convo.length} message${convo.length === 1 ? "" : "s"} \u2500\u2500${c4.reset}`);
9095
- if (shown.length < convo.length) tui.print(`${c4.dim} \u2026 earlier messages omitted${c4.reset}`);
9260
+ tui.print(`${c5.dim}\u2500\u2500 resuming session \xB7 ${convo.length} message${convo.length === 1 ? "" : "s"} \u2500\u2500${c5.reset}`);
9261
+ if (shown.length < convo.length) tui.print(`${c5.dim} \u2026 earlier messages omitted${c5.reset}`);
9096
9262
  for (const m of shown) {
9097
9263
  if (m.metadata?.user_command) {
9098
9264
  printCommandBlock(
@@ -9153,6 +9319,7 @@ async function runInteractive(tui, api, threadId, projectDir, machine, resumed,
9153
9319
  let editingPendingId = null;
9154
9320
  let reconcileSharedMessaging = async () => {
9155
9321
  };
9322
+ let applySharedMessagingEvent = () => false;
9156
9323
  let refreshSessionProjection = async () => {
9157
9324
  };
9158
9325
  const shownIds = /* @__PURE__ */ new Set();
@@ -9210,21 +9377,21 @@ async function runInteractive(tui, api, threadId, projectDir, machine, resumed,
9210
9377
  if (isOwner) {
9211
9378
  bridge?.setClaim("takeover");
9212
9379
  exec?.writeSessionInfo();
9213
- if (wasKnown && moved) tui.print(`${c4.dim}Tool execution moved to this terminal.${c4.reset}`);
9380
+ if (wasKnown && moved) tui.print(`${c5.dim}Tool execution moved to this terminal.${c5.reset}`);
9214
9381
  } else if (wasKnown && moved) {
9215
- tui.print(`${c4.dim}Tool execution moved to ${describeExecOwner(owner2)}.${c4.reset}`);
9382
+ tui.print(`${c5.dim}Tool execution moved to ${describeExecOwner(owner2)}.${c5.reset}`);
9216
9383
  }
9217
9384
  },
9218
9385
  onClaimRefused: (reason) => {
9219
9386
  if (reason === "in_flight") {
9220
9387
  tui.print(
9221
- `${c4.dim}The session's current client is mid-operation \u2014 execution stays there until it finishes.${c4.reset}`
9388
+ `${c5.dim}The session's current client is mid-operation \u2014 execution stays there until it finishes.${c5.reset}`
9222
9389
  );
9223
9390
  }
9224
9391
  },
9225
9392
  onSuperseded: () => {
9226
9393
  tui.print(
9227
- `${c4.yellow}\u26A0 Another Standard Code process on this machine took over this session \u2014 this terminal is watching.${c4.reset}`
9394
+ `${c5.yellow}\u26A0 Another Standard Code process on this machine took over this session \u2014 this terminal is watching.${c5.reset}`
9228
9395
  );
9229
9396
  },
9230
9397
  onStatus: (id, summary) => {
@@ -9286,7 +9453,7 @@ why: ${req.requestPermission}` : ""}`,
9286
9453
  } else if (eventType === "goal_updated" && data) {
9287
9454
  tui.setGoal(data);
9288
9455
  } else if (eventType === SHARED_MESSAGING_EVENT) {
9289
- void reconcileSharedMessaging(true);
9456
+ if (!applySharedMessagingEvent(data)) void reconcileSharedMessaging(true);
9290
9457
  }
9291
9458
  },
9292
9459
  // A failed turn whose message is the lease service's at-limit denial → offer
@@ -9382,7 +9549,7 @@ why: ${req.requestPermission}` : ""}`,
9382
9549
  const logout = async () => {
9383
9550
  deleteCredential(api.origin);
9384
9551
  const instanceHost = api.origin.replace(/^https?:\/\//, "");
9385
- tui.print(`${c4.gray}Signed out \u2014 removed the saved token for ${c4.teal}${instanceHost}${c4.reset}${c4.gray}. Run standardcode to sign in again.${c4.reset}`);
9552
+ tui.print(`${c5.gray}Signed out \u2014 removed the saved token for ${c5.teal}${instanceHost}${c5.reset}${c5.gray}. Run standardcode to sign in again.${c5.reset}`);
9386
9553
  await quit();
9387
9554
  };
9388
9555
  const bgMgr = {
@@ -9390,7 +9557,7 @@ why: ${req.requestPermission}` : ""}`,
9390
9557
  stop: async (id) => {
9391
9558
  if (!host) {
9392
9559
  tui.print(
9393
- `${c4.gray}That process runs on ${runnerName} \u2014 ask the agent to stop it (it manages processes there).${c4.reset}`
9560
+ `${c5.gray}That process runs on ${runnerName} \u2014 ask the agent to stop it (it manages processes there).${c5.reset}`
9394
9561
  );
9395
9562
  return;
9396
9563
  }
@@ -9471,17 +9638,25 @@ why: ${req.requestPermission}` : ""}`,
9471
9638
  } catch (error) {
9472
9639
  if (!sharedMessagingReady && !sharedMessagingUnavailableShown) {
9473
9640
  sharedMessagingUnavailableShown = true;
9474
- tui.print(`${c4.dim}shared messaging unavailable: ${error instanceof Error ? error.message : String(error)}${c4.reset}`);
9641
+ tui.print(`${c5.dim}shared messaging unavailable: ${error instanceof Error ? error.message : String(error)}${c5.reset}`);
9475
9642
  }
9476
9643
  }
9477
9644
  };
9645
+ applySharedMessagingEvent = (data) => {
9646
+ if (!sharedMessagingReady) return false;
9647
+ const event = parseMessagingChangedEvent(data);
9648
+ if (!event || !event.draft || event.draftOmitted) return false;
9649
+ if (event.pendingRevision > sharedMessaging.pending.revision) return false;
9650
+ applySharedMessaging({ version: 1, pending: sharedMessaging.pending, draft: event.draft }, true);
9651
+ return true;
9652
+ };
9478
9653
  const onTerminalResume = () => void reconcileSharedMessaging(true);
9479
9654
  process.on("SIGCONT", onTerminalResume);
9480
9655
  const applySharedMutation = (promise) => promise.then((snapshot) => {
9481
9656
  applySharedMessaging(snapshot, false);
9482
9657
  return true;
9483
9658
  }).catch((error) => {
9484
- tui.print(`${c4.dim}shared messaging failed: ${error instanceof Error ? error.message : String(error)}${c4.reset}`);
9659
+ tui.print(`${c5.dim}shared messaging failed: ${error instanceof Error ? error.message : String(error)}${c5.reset}`);
9485
9660
  return false;
9486
9661
  });
9487
9662
  const appendSharedPending = (text, images, refs = []) => applySharedMutation(api.appendPendingInput(threadId, {
@@ -9530,7 +9705,7 @@ why: ${req.requestPermission}` : ""}`,
9530
9705
  busy = false;
9531
9706
  optimisticBusyUntil = 0;
9532
9707
  tui.setWorking(false);
9533
- tui.print(`${c4.dim}failed to send: ${e instanceof Error ? e.message : String(e)}${c4.reset}`);
9708
+ tui.print(`${c5.dim}failed to send: ${e instanceof Error ? e.message : String(e)}${c5.reset}`);
9534
9709
  return false;
9535
9710
  }
9536
9711
  return true;
@@ -9539,11 +9714,11 @@ why: ${req.requestPermission}` : ""}`,
9539
9714
  let bangRunning = false;
9540
9715
  const runBangCommand = async (command) => {
9541
9716
  if (bangRunning) {
9542
- tui.print(`${c4.dim}a command is already running \u2014 one at a time.${c4.reset}`);
9717
+ tui.print(`${c5.dim}a command is already running \u2014 one at a time.${c5.reset}`);
9543
9718
  return;
9544
9719
  }
9545
9720
  bangRunning = true;
9546
- tui.print(`${c4.magenta}!${c4.reset} ${c4.dim}running on ${whereLabel}\u2026${c4.reset}`);
9721
+ tui.print(`${c5.magenta}!${c5.reset} ${c5.dim}running on ${whereLabel}\u2026${c5.reset}`);
9547
9722
  try {
9548
9723
  const res = await api.runCommand(threadId, command);
9549
9724
  if (res.messageId) shownIds.add(res.messageId);
@@ -9557,7 +9732,7 @@ why: ${req.requestPermission}` : ""}`,
9557
9732
  const openPendingMenu = async () => {
9558
9733
  const items = sharedMessaging.pending.items;
9559
9734
  if (!items.length) {
9560
- tui.print(`${c4.dim}No pending messages.${c4.reset}`);
9735
+ tui.print(`${c5.dim}No pending messages.${c5.reset}`);
9561
9736
  return;
9562
9737
  }
9563
9738
  const picked = await tui.select("Pending messages", items.map((item, index) => ({
@@ -9587,16 +9762,16 @@ why: ${req.requestPermission}` : ""}`,
9587
9762
  try {
9588
9763
  await api.compact(threadId);
9589
9764
  } catch (err) {
9590
- tui.print(`${c4.red}\u2717${c4.reset} couldn't start compaction: ${err.message}`);
9765
+ tui.print(`${c5.red}\u2717${c5.reset} couldn't start compaction: ${err.message}`);
9591
9766
  }
9592
9767
  };
9593
9768
  const runAccountCommand = async () => {
9594
- tui.print(`${c4.gray}Opening your account\u2026${c4.reset}`);
9769
+ tui.print(`${c5.gray}Opening your account\u2026${c5.reset}`);
9595
9770
  const link = await api.accountLink(threadId).catch(() => null);
9596
9771
  const target = link?.url ?? "https://standardcode.ai/account";
9597
9772
  openUrl(target);
9598
9773
  tui.print(
9599
- link?.preauthed ? `${c4.gray}\u2192 account dashboard opened in your browser (signed in)${c4.reset}` : `${c4.gray}\u2192 opened ${target} \u2014 sign in with your account email${c4.reset}`
9774
+ link?.preauthed ? `${c5.gray}\u2192 account dashboard opened in your browser (signed in)${c5.reset}` : `${c5.gray}\u2192 opened ${target} \u2014 sign in with your account email${c5.reset}`
9600
9775
  );
9601
9776
  };
9602
9777
  const ordinal = (n) => {
@@ -9607,24 +9782,24 @@ why: ${req.requestPermission}` : ""}`,
9607
9782
  const renderUpgradePanel = (q) => {
9608
9783
  const dots = [];
9609
9784
  for (let i = 0; i < q.max; i++) {
9610
- if (i < q.current) dots.push(`${c4.teal}\u25CF${c4.reset}`);
9611
- else if (i === q.current) dots.push(`${c4.bold}${gradientText("\uFF0B")}${c4.reset}`);
9612
- else dots.push(`${c4.dim}\xB7${c4.reset}`);
9785
+ if (i < q.current) dots.push(`${c5.teal}\u25CF${c5.reset}`);
9786
+ else if (i === q.current) dots.push(`${c5.bold}${gradientText("\uFF0B")}${c5.reset}`);
9787
+ else dots.push(`${c5.dim}\xB7${c5.reset}`);
9613
9788
  }
9614
9789
  const cost = fmtCost(q);
9615
9790
  const lines = [
9616
9791
  "",
9617
- `${c4.bold}\u2726 Add a parallel session${c4.reset}`,
9792
+ `${c5.bold}\u2726 Add a parallel session${c5.reset}`,
9618
9793
  "",
9619
- `${dots.join(" ")} ${c4.dim}${q.current} of ${q.current} session${q.current === 1 ? "" : "s"} in use${c4.reset}`
9794
+ `${dots.join(" ")} ${c5.dim}${q.current} of ${q.current} session${q.current === 1 ? "" : "s"} in use${c5.reset}`
9620
9795
  ];
9621
9796
  if (q.ends_trial) {
9622
9797
  lines.push(
9623
- `${c4.yellow}Your $5 trial covers 1 session. Adding a ${ordinal(q.sessions)} ends the trial${c4.reset}`,
9624
- `${c4.yellow}and starts your $49/mo plan now${cost ? ` \u2014 ${c4.bold}${cost} charged today${c4.reset}${c4.yellow}` : ""}.${c4.reset}`
9798
+ `${c5.yellow}Your $5 trial covers 1 session. Adding a ${ordinal(q.sessions)} ends the trial${c5.reset}`,
9799
+ `${c5.yellow}and starts your $49/mo plan now${cost ? ` \u2014 ${c5.bold}${cost} charged today${c5.reset}${c5.yellow}` : ""}.${c5.reset}`
9625
9800
  );
9626
9801
  } else if (cost) {
9627
- lines.push(`Add a ${ordinal(q.sessions)} session at $49/mo \u2014 ${c4.bold}${cost} charged now${c4.reset}.`);
9802
+ lines.push(`Add a ${ordinal(q.sessions)} session at $49/mo \u2014 ${c5.bold}${cost} charged now${c5.reset}.`);
9628
9803
  } else {
9629
9804
  lines.push(`Add a ${ordinal(q.sessions)} session at $49/mo \u2014 prorated on your next invoice.`);
9630
9805
  }
@@ -9637,7 +9812,7 @@ why: ${req.requestPermission}` : ""}`,
9637
9812
  try {
9638
9813
  if (opts.auto) {
9639
9814
  tui.print(
9640
- `${c4.yellow}You're out of simultaneous sessions \u2014 another Standard Code session is using your slot.${c4.reset}`
9815
+ `${c5.yellow}You're out of simultaneous sessions \u2014 another Standard Code session is using your slot.${c5.reset}`
9641
9816
  );
9642
9817
  }
9643
9818
  const quote = await api.sessionsQuote(threadId);
@@ -9645,16 +9820,16 @@ why: ${req.requestPermission}` : ""}`,
9645
9820
  const link = await api.accountLink(threadId).catch(() => null);
9646
9821
  const target = link?.url ?? "https://standardcode.ai/account";
9647
9822
  tui.print(
9648
- `${c4.gray}Close the other session (its slot frees within ~90s) \u2014 or add another simultaneous session to your plan, then resend your message.${c4.reset}`
9823
+ `${c5.gray}Close the other session (its slot frees within ~90s) \u2014 or add another simultaneous session to your plan, then resend your message.${c5.reset}`
9649
9824
  );
9650
9825
  openUrl(target);
9651
- tui.print(`${c4.gray}\u2192 opened ${target} to manage your plan${c4.reset}`);
9826
+ tui.print(`${c5.gray}\u2192 opened ${target} to manage your plan${c5.reset}`);
9652
9827
  return;
9653
9828
  }
9654
9829
  if (quote.current >= quote.max) {
9655
9830
  tui.print(
9656
- `${c4.yellow}You're at the maximum of ${quote.max} parallel session${quote.max === 1 ? "" : "s"}.${c4.reset}
9657
- ${c4.gray}Close another session (its slot frees within ~90s), then resend your message.${c4.reset}`
9831
+ `${c5.yellow}You're at the maximum of ${quote.max} parallel session${quote.max === 1 ? "" : "s"}.${c5.reset}
9832
+ ${c5.gray}Close another session (its slot frees within ~90s), then resend your message.${c5.reset}`
9658
9833
  );
9659
9834
  return;
9660
9835
  }
@@ -9666,25 +9841,25 @@ ${c4.gray}Close another session (its slot frees within ~90s), then resend your m
9666
9841
  { label: "Not now", value: "no" }
9667
9842
  ]);
9668
9843
  if (choice !== "go") {
9669
- tui.print(`${c4.gray}No change made \u2014 you can upgrade anytime with /upgrade.${c4.reset}`);
9844
+ tui.print(`${c5.gray}No change made \u2014 you can upgrade anytime with /upgrade.${c5.reset}`);
9670
9845
  return;
9671
9846
  }
9672
- tui.print(`${c4.gray}Applying\u2026${c4.reset}`);
9847
+ tui.print(`${c5.gray}Applying\u2026${c5.reset}`);
9673
9848
  let applied;
9674
9849
  try {
9675
9850
  applied = await api.sessionsUpgrade(threadId, quote.sessions);
9676
9851
  } catch (e) {
9677
- tui.print(`${c4.red}\u2717${c4.reset} Upgrade failed: ${e instanceof Error ? e.message : String(e)}`);
9852
+ tui.print(`${c5.red}\u2717${c5.reset} Upgrade failed: ${e instanceof Error ? e.message : String(e)}`);
9678
9853
  return;
9679
9854
  }
9680
9855
  if (!applied?.ok) {
9681
- tui.print(`${c4.red}\u2717${c4.reset} Upgrade failed: ${applied?.error ?? "unknown error"}`);
9856
+ tui.print(`${c5.red}\u2717${c5.reset} Upgrade failed: ${applied?.error ?? "unknown error"}`);
9682
9857
  return;
9683
9858
  }
9684
9859
  const n = applied.sessions ?? quote.sessions;
9685
- tui.print(`${c4.green}\u2713${c4.reset} ${c4.bold}${gradientText(`You now have ${n} parallel session${n === 1 ? "" : "s"}.`)}${c4.reset}`);
9860
+ tui.print(`${c5.green}\u2713${c5.reset} ${c5.bold}${gradientText(`You now have ${n} parallel session${n === 1 ? "" : "s"}.`)}${c5.reset}`);
9686
9861
  if (opts.auto && lastSent) {
9687
- tui.print(`${c4.gray}Continuing\u2026${c4.reset}`);
9862
+ tui.print(`${c5.gray}Continuing\u2026${c5.reset}`);
9688
9863
  await sendNow(lastSent.text, lastSent.images, lastSent.refs);
9689
9864
  }
9690
9865
  } finally {
@@ -9795,38 +9970,50 @@ ${c4.gray}Close another session (its slot frees within ~90s), then resend your m
9795
9970
  const history = await loadHistory(api, threadId, historySeedThreadId);
9796
9971
  tui.setHistory(history);
9797
9972
  await reconcileSharedMessaging(true);
9798
- let draftTimer;
9799
- const clearComposerDraft = () => {
9800
- if (draftTimer) clearTimeout(draftTimer);
9801
- draftTimer = void 0;
9802
- mirroredDraftRefs = [];
9803
- tui.setExternalAttachmentNames([]);
9804
- if (sharedMessagingReady) void applySharedMutation(api.clearSharedDraft(threadId, messagingOrigin));
9805
- };
9806
- tui.onDraftChange = (textVal, images) => {
9807
- if (draftTimer) clearTimeout(draftTimer);
9808
- draftTimer = setTimeout(() => {
9809
- draftTimer = void 0;
9810
- if (sharedMessagingReady) {
9811
- const hasDraft = !!textVal.trim() || images.length > 0 || mirroredDraftRefs.length > 0;
9973
+ let latestDraftPayload = null;
9974
+ let draftDirty = false;
9975
+ let draftInFlight = false;
9976
+ const pumpComposerDraft = async () => {
9977
+ if (draftInFlight) return;
9978
+ draftInFlight = true;
9979
+ try {
9980
+ while (draftDirty) {
9981
+ draftDirty = false;
9982
+ const payload = latestDraftPayload;
9983
+ if (!payload || !sharedMessagingReady) continue;
9984
+ const hasDraft = !!payload.text.trim() || payload.images.length > 0 || mirroredDraftRefs.length > 0;
9812
9985
  const mutation = {
9813
- content: textVal,
9986
+ content: payload.text,
9814
9987
  attachments: [
9815
9988
  ...hasDraft ? mirroredDraftRefs : [],
9816
- ...toSharedAttachments(images)
9989
+ ...toSharedAttachments(payload.images)
9817
9990
  ],
9818
9991
  ...messagingOrigin
9819
9992
  };
9820
- void applySharedMutation(
9993
+ await applySharedMutation(
9821
9994
  hasDraft ? api.putSharedDraft(threadId, mutation) : api.clearSharedDraft(threadId, messagingOrigin)
9822
9995
  );
9823
9996
  }
9824
- }, 150);
9997
+ } finally {
9998
+ draftInFlight = false;
9999
+ }
10000
+ };
10001
+ const clearComposerDraft = () => {
10002
+ mirroredDraftRefs = [];
10003
+ tui.setExternalAttachmentNames([]);
10004
+ latestDraftPayload = { text: "", images: [] };
10005
+ draftDirty = true;
10006
+ void pumpComposerDraft();
10007
+ };
10008
+ tui.onDraftChange = (textVal, images) => {
10009
+ latestDraftPayload = { text: textVal, images };
10010
+ draftDirty = true;
10011
+ void pumpComposerDraft();
9825
10012
  };
9826
10013
  const submitComposer = async (text, images, steer) => {
9827
10014
  const draftRefs = mirroredDraftRefs;
9828
10015
  if (!sharedMessagingReady && (busy || steer || editingPendingId !== null)) {
9829
- tui.print(`${c4.dim}Restoring shared message state \u2014 try again in a moment.${c4.reset}`);
10016
+ tui.print(`${c5.dim}Restoring shared message state \u2014 try again in a moment.${c5.reset}`);
9830
10017
  tui.setExternalAttachmentNames(draftRefs.map((attachment) => attachment.name));
9831
10018
  tui.setInput(text, images);
9832
10019
  return;
@@ -9849,7 +10036,7 @@ ${c4.gray}Close another session (its slot frees within ~90s), then resend your m
9849
10036
  const item = sharedMessaging.pending.items.find((candidate) => candidate.id === pendingId);
9850
10037
  editingPendingId = null;
9851
10038
  if (!item) {
9852
- tui.print(`${c4.dim}That pending message was already dispatched or dismissed.${c4.reset}`);
10039
+ tui.print(`${c5.dim}That pending message was already dispatched or dismissed.${c5.reset}`);
9853
10040
  return;
9854
10041
  }
9855
10042
  const updated = await editSharedPending(item, text, images, draftRefs);
@@ -9862,7 +10049,7 @@ ${c4.gray}Close another session (its slot frees within ~90s), then resend your m
9862
10049
  return;
9863
10050
  }
9864
10051
  if (steer) {
9865
- tui.print(`${c4.yellow}\u21AA steering now \u2014 stopping the current step${c4.reset}`);
10052
+ tui.print(`${c5.yellow}\u21AA steering now \u2014 stopping the current step${c5.reset}`);
9866
10053
  await Promise.all([
9867
10054
  api.stopThread(threadId).catch(() => {
9868
10055
  }),
@@ -9899,18 +10086,18 @@ ${c4.gray}Close another session (its slot frees within ~90s), then resend your m
9899
10086
  tui.onInterrupt = () => {
9900
10087
  const firstPending = sharedMessaging.pending.items[0];
9901
10088
  if (!busy && firstPending) {
9902
- tui.print(`${c4.yellow}\u21AA steering the first pending message\u2026${c4.reset}`);
10089
+ tui.print(`${c5.yellow}\u21AA steering the first pending message\u2026${c5.reset}`);
9903
10090
  void promoteSharedPending(firstPending);
9904
10091
  return;
9905
10092
  }
9906
10093
  if (busy) {
9907
10094
  const head = sharedMessaging.pending.items[0];
9908
10095
  if (head) {
9909
- tui.print(`${c4.yellow}\u21AA steering \u2014 stopping the current step to run the queued message${c4.reset}`);
10096
+ tui.print(`${c5.yellow}\u21AA steering \u2014 stopping the current step to run the queued message${c5.reset}`);
9910
10097
  void promoteSharedPending(head);
9911
10098
  return;
9912
10099
  }
9913
- tui.print(`${c4.yellow}\u25A0 stopping now${c4.reset}`);
10100
+ tui.print(`${c5.yellow}\u25A0 stopping now${c5.reset}`);
9914
10101
  const stops = [api.stopThread(threadId).catch(() => {
9915
10102
  })];
9916
10103
  for (const childId of activeSubagents.keys()) {
@@ -9940,7 +10127,7 @@ ${c4.gray}Close another session (its slot frees within ~90s), then resend your m
9940
10127
  void api.getGoal(threadId).then((g) => tui.setGoal(g)).catch(() => {
9941
10128
  });
9942
10129
  attaching.stop();
9943
- const header = `${c4.bold}${c4.magenta}Standard Code${c4.reset} ${c4.dim}\u2014 ${agentTitle}${c4.reset}`;
10130
+ const header = `${c5.bold}${c5.magenta}Standard Code${c5.reset} ${c5.dim}\u2014 ${agentTitle}${c5.reset}`;
9944
10131
  const remoteDaemonV = session.runner?.daemon?.version;
9945
10132
  const owner = currentOwner;
9946
10133
  let localOwnerDesc = ownsExecution ? "this terminal" : describeExecOwner(owner);
@@ -9948,24 +10135,24 @@ ${c4.gray}Close another session (its slot frees within ~90s), then resend your m
9948
10135
  const selfRec = await loadMachine(api, session.identity.machine_id).catch(() => null);
9949
10136
  if (selfRec?.daemon?.version) localOwnerDesc = `the daemon on this machine (v${selfRec.daemon.version})`;
9950
10137
  }
9951
- const execLine = remote ? `${c4.gray}tool execution:${c4.reset} daemon${remoteDaemonV ? ` v${remoteDaemonV}` : ""} on ${runnerName}` : `${c4.gray}tool execution:${c4.reset} ${localOwnerDesc}`;
10138
+ const execLine = remote ? `${c5.gray}tool execution:${c5.reset} daemon${remoteDaemonV ? ` v${remoteDaemonV}` : ""} on ${runnerName}` : `${c5.gray}tool execution:${c5.reset} ${localOwnerDesc}`;
9952
10139
  tui.setAgentLabel(agentTitle);
9953
10140
  tui.banner(
9954
10141
  remote ? [
9955
10142
  header,
9956
- `${c4.gray}project:${c4.reset} ${session.remotePath ?? "?"} ${c4.teal}on ${runnerName}${c4.reset}`,
9957
- `${c4.gray}machine:${c4.reset} ${runnerName} ${c4.gray}thread:${c4.reset} ${threadId.slice(0, 8)}`,
10143
+ `${c5.gray}project:${c5.reset} ${session.remotePath ?? "?"} ${c5.teal}on ${runnerName}${c5.reset}`,
10144
+ `${c5.gray}machine:${c5.reset} ${runnerName} ${c5.gray}thread:${c5.reset} ${threadId.slice(0, 8)}`,
9958
10145
  execLine
9959
10146
  ] : [
9960
10147
  header,
9961
- `${c4.gray}project:${c4.reset} ${projectDir}`,
9962
- `${c4.gray}machine:${c4.reset} ${machine} ${c4.gray}thread:${c4.reset} ${threadId.slice(0, 8)}`,
10148
+ `${c5.gray}project:${c5.reset} ${projectDir}`,
10149
+ `${c5.gray}machine:${c5.reset} ${machine} ${c5.gray}thread:${c5.reset} ${threadId.slice(0, 8)}`,
9963
10150
  execLine
9964
10151
  ]
9965
10152
  );
9966
10153
  if (!remote && session.suggestDaemonInstall && process.platform !== "win32" && !serviceStatus().installed) {
9967
10154
  tui.print(
9968
- `${c4.dim}Tip: install the always-on daemon (${c4.reset}standardcode daemon install${c4.dim}) to start sessions on this machine from anywhere.${c4.reset}`
10155
+ `${c5.dim}Tip: install the always-on daemon (${c5.reset}standardcode daemon install${c5.dim}) to start sessions on this machine from anywhere.${c5.reset}`
9969
10156
  );
9970
10157
  }
9971
10158
  if (resumed) await printHistory(api, threadId, tui);
@@ -9976,17 +10163,17 @@ ${c4.gray}Close another session (its slot frees within ~90s), then resend your m
9976
10163
  const runningProcs = (await registry.list()).filter((p) => p.status === "running");
9977
10164
  if (runningProcs.length) {
9978
10165
  tui.print(
9979
- `${c4.cyan}\u2699 ${runningProcs.length} background process${runningProcs.length === 1 ? "" : "es"} running:${c4.reset}`
10166
+ `${c5.cyan}\u2699 ${runningProcs.length} background process${runningProcs.length === 1 ? "" : "es"} running:${c5.reset}`
9980
10167
  );
9981
- for (const p of runningProcs) tui.print(`${c4.gray} ${p.id} ${p.description || p.command}${c4.reset}`);
10168
+ for (const p of runningProcs) tui.print(`${c5.gray} ${p.id} ${p.description || p.command}${c5.reset}`);
9982
10169
  }
9983
10170
  refreshBgCount();
9984
10171
  if (exec && ownsExecution) {
9985
10172
  for (const res of await exec.connectEnabledMcpServers()) {
9986
10173
  if (res.ok) {
9987
- tui.print(`${c4.cyan}\u26A1 MCP "${res.name}" connected${c4.reset} ${c4.gray}(${res.tools} tool${res.tools === 1 ? "" : "s"})${c4.reset}`);
10174
+ tui.print(`${c5.cyan}\u26A1 MCP "${res.name}" connected${c5.reset} ${c5.gray}(${res.tools} tool${res.tools === 1 ? "" : "s"})${c5.reset}`);
9988
10175
  } else {
9989
- tui.print(`${c4.red}\u26A0 MCP "${res.name}" failed:${c4.reset} ${c4.gray}${res.error}${c4.reset}`);
10176
+ tui.print(`${c5.red}\u26A0 MCP "${res.name}" failed:${c5.reset} ${c5.gray}${res.error}${c5.reset}`);
9990
10177
  }
9991
10178
  }
9992
10179
  }
@@ -10002,8 +10189,8 @@ ${c4.gray}Close another session (its slot frees within ~90s), then resend your m
10002
10189
  try {
10003
10190
  const { choice, reason } = await tui.approval(
10004
10191
  `${request.summary}${request.permission ? `
10005
- ${c4.bold}why: ${request.permission}${c4.reset}` : ""}
10006
- ${c4.dim}runs on ${request.machine || runnerName}${c4.reset}`,
10192
+ ${c5.bold}why: ${request.permission}${c5.reset}` : ""}
10193
+ ${c5.dim}runs on ${request.machine || runnerName}${c5.reset}`,
10007
10194
  request.risk
10008
10195
  );
10009
10196
  answeredApprovals.add(request.tool_call_id);
@@ -10030,7 +10217,7 @@ ${c4.dim}runs on ${request.machine || runnerName}${c4.reset}`,
10030
10217
  if (snapshot.stalled && !stalledNoticeShown) {
10031
10218
  stalledNoticeShown = true;
10032
10219
  tui.print(
10033
- `${c4.yellow}\u26A0 session interrupted${c4.reset} ${c4.dim}\u2014 the last operation never finished (the runtime is attempting recovery). Send a message to continue.${c4.reset}`
10220
+ `${c5.yellow}\u26A0 session interrupted${c5.reset} ${c5.dim}\u2014 the last operation never finished (the runtime is attempting recovery). Send a message to continue.${c5.reset}`
10034
10221
  );
10035
10222
  } else if (!snapshot.stalled && stalledNoticeShown && snapshot.busy) {
10036
10223
  stalledNoticeShown = false;
@@ -10063,7 +10250,7 @@ ${c4.dim}runs on ${request.machine || runnerName}${c4.reset}`,
10063
10250
  continue;
10064
10251
  }
10065
10252
  if (m.role === "assistant" && text) printAssistant(tui, text);
10066
- else if (m.role === "system" && text) tui.print(`${c4.dim}${text}${c4.reset}`);
10253
+ else if (m.role === "system" && text) tui.print(`${c5.dim}${text}${c5.reset}`);
10067
10254
  else if (m.role === "user" && text) {
10068
10255
  const pending = pendingSent.get(text) ?? 0;
10069
10256
  if (pending > 0) {
@@ -10157,16 +10344,16 @@ ${c4.dim}runs on ${request.machine || runnerName}${c4.reset}`,
10157
10344
  tui.setStep(null, 0);
10158
10345
  tui.setBackgroundCount(0);
10159
10346
  if (killed > 0) {
10160
- tui.print(`${c4.cyan}\u2699${c4.reset} Stopped ${killed} background process${killed === 1 ? "" : "es"}.`);
10347
+ tui.print(`${c5.cyan}\u2699${c5.reset} Stopped ${killed} background process${killed === 1 ? "" : "es"}.`);
10161
10348
  }
10162
- tui.print(`${c4.dim}\u2500\u2500 conversation cleared \u2014 starting a fresh session \u2500\u2500${c4.reset}`);
10349
+ tui.print(`${c5.dim}\u2500\u2500 conversation cleared \u2014 starting a fresh session \u2500\u2500${c5.reset}`);
10163
10350
  }
10164
10351
  async function runSkillsMenu(tui, skills) {
10165
10352
  let list;
10166
10353
  try {
10167
10354
  list = await skills.list();
10168
10355
  } catch (e) {
10169
- tui.print(`${c4.red}\u2717 couldn't load skills:${c4.reset} ${c4.gray}${e instanceof Error ? e.message : String(e)}${c4.reset}`);
10356
+ tui.print(`${c5.red}\u2717 couldn't load skills:${c5.reset} ${c5.gray}${e instanceof Error ? e.message : String(e)}${c5.reset}`);
10170
10357
  return;
10171
10358
  }
10172
10359
  const INSTALL = "__install__";
@@ -10177,7 +10364,7 @@ async function runSkillsMenu(tui, skills) {
10177
10364
  }));
10178
10365
  items.push({ label: "\uFF0B Install a skill\u2026", hint: "find & install", value: INSTALL });
10179
10366
  const picked = await tui.select(
10180
- `${c4.bold}Agent skills${c4.reset} ${c4.dim}(\u2191/\u2193 \xB7 enter \xB7 esc to close)${c4.reset}`,
10367
+ `${c5.bold}Agent skills${c5.reset} ${c5.dim}(\u2191/\u2193 \xB7 enter \xB7 esc to close)${c5.reset}`,
10181
10368
  items
10182
10369
  );
10183
10370
  if (!picked) return;
@@ -10190,8 +10377,8 @@ async function runSkillsMenu(tui, skills) {
10190
10377
  return;
10191
10378
  }
10192
10379
  const skill = list.find((s) => s.name === picked);
10193
- tui.print(`${c4.cyan}${skill.name}${c4.reset}${skill.version ? ` ${c4.dim}v${skill.version}${c4.reset}` : ""} ${c4.gray}\u2014 ${skill.description}${c4.reset}`);
10194
- const action = await tui.select(`${c4.bold}${picked}${c4.reset}`, [
10380
+ tui.print(`${c5.cyan}${skill.name}${c5.reset}${skill.version ? ` ${c5.dim}v${skill.version}${c5.reset}` : ""} ${c5.gray}\u2014 ${skill.description}${c5.reset}`);
10381
+ const action = await tui.select(`${c5.bold}${picked}${c5.reset}`, [
10195
10382
  skill.enabled ? { label: "Disable (hide from the agent)", value: "disable" } : { label: "Enable", value: "enable" },
10196
10383
  { label: "View files", value: "files" },
10197
10384
  { label: "Remove this skill", value: "remove" },
@@ -10200,20 +10387,20 @@ async function runSkillsMenu(tui, skills) {
10200
10387
  try {
10201
10388
  if (action === "enable" || action === "disable") {
10202
10389
  await skills.setEnabled(picked, action === "enable");
10203
- tui.print(`${c4.gray}${action}d ${picked}${c4.reset}`);
10390
+ tui.print(`${c5.gray}${action}d ${picked}${c5.reset}`);
10204
10391
  } else if (action === "files") {
10205
- for (const f of skill.files) tui.print(` ${c4.gray}${f}${c4.reset}`);
10392
+ for (const f of skill.files) tui.print(` ${c5.gray}${f}${c5.reset}`);
10206
10393
  } else if (action === "remove") {
10207
10394
  await skills.remove(picked);
10208
- tui.print(`${c4.gray}removed ${picked}${c4.reset}`);
10395
+ tui.print(`${c5.gray}removed ${picked}${c5.reset}`);
10209
10396
  }
10210
10397
  } catch (e) {
10211
- tui.print(`${c4.red}\u2717 ${e instanceof Error ? e.message : String(e)}${c4.reset}`);
10398
+ tui.print(`${c5.red}\u2717 ${e instanceof Error ? e.message : String(e)}${c5.reset}`);
10212
10399
  }
10213
10400
  }
10214
10401
  async function runLevelMenu(tui, perm) {
10215
10402
  const picked = await tui.select(
10216
- `${c4.bold}Auto-accept level${c4.reset} ${c4.dim}(\u2191/\u2193 \xB7 enter \xB7 shift-tab cycles)${c4.reset}`,
10403
+ `${c5.bold}Auto-accept level${c5.reset} ${c5.dim}(\u2191/\u2193 \xB7 enter \xB7 shift-tab cycles)${c5.reset}`,
10217
10404
  LEVELS.map((l) => ({
10218
10405
  label: levelLabel(l),
10219
10406
  hint: l === tui.level ? "current" : "",
@@ -10230,16 +10417,16 @@ async function runMachinesMenu(tui, api, self) {
10230
10417
  try {
10231
10418
  machines = await loadMachines(api);
10232
10419
  } catch (e) {
10233
- tui.print(`${c4.red}\u2717 couldn't load machines:${c4.reset} ${c4.gray}${e instanceof Error ? e.message : String(e)}${c4.reset}`);
10420
+ tui.print(`${c5.red}\u2717 couldn't load machines:${c5.reset} ${c5.gray}${e instanceof Error ? e.message : String(e)}${c5.reset}`);
10234
10421
  return;
10235
10422
  }
10236
10423
  if (!machines.length) {
10237
- tui.print(`${c4.gray}No machines registered yet. Run standardcode on a machine (or install its daemon) to register it.${c4.reset}`);
10424
+ tui.print(`${c5.gray}No machines registered yet. Run standardcode on a machine (or install its daemon) to register it.${c5.reset}`);
10238
10425
  return;
10239
10426
  }
10240
10427
  machines.sort((a, b) => (b.updated_at ?? 0) - (a.updated_at ?? 0));
10241
10428
  const picked = await tui.select(
10242
- `${c4.bold}Your machines${c4.reset} ${c4.dim}(\u2191/\u2193 \xB7 enter \xB7 esc)${c4.reset}`,
10429
+ `${c5.bold}Your machines${c5.reset} ${c5.dim}(\u2191/\u2193 \xB7 enter \xB7 esc)${c5.reset}`,
10243
10430
  machines.map((m) => {
10244
10431
  const isSelf = m.id === self.machine_id;
10245
10432
  const online = daemonOnline(m);
@@ -10273,26 +10460,26 @@ async function manageMachine(tui, api, self, machine) {
10273
10460
  options.push({ label: "Back", value: "back" });
10274
10461
  if (!isSelf && !machine.daemon) {
10275
10462
  tui.print(
10276
- `${c4.dim}${machine.name} has no daemon \u2014 you can rename it here; update and project changes need its daemon installed.${c4.reset}`
10463
+ `${c5.dim}${machine.name} has no daemon \u2014 you can rename it here; update and project changes need its daemon installed.${c5.reset}`
10277
10464
  );
10278
10465
  } else if (!isSelf && machine.daemon && !online) {
10279
10466
  tui.print(
10280
- `${c4.dim}${machine.name}'s daemon is offline \u2014 queued changes apply when it next comes online.${c4.reset}`
10467
+ `${c5.dim}${machine.name}'s daemon is offline \u2014 queued changes apply when it next comes online.${c5.reset}`
10281
10468
  );
10282
10469
  }
10283
- const action = await tui.select(`${c4.bold}${machineIcon(machine)} ${machine.name}${c4.reset}`, options);
10470
+ const action = await tui.select(`${c5.bold}${machineIcon(machine)} ${machine.name}${c5.reset}`, options);
10284
10471
  if (!action || action === "back") return;
10285
10472
  if (action === "icon") {
10286
10473
  const current = machine.icon ?? "";
10287
10474
  const emoji = await tui.prompt(
10288
- `${c4.bold}Icon for ${machine.name}${c4.reset} ${c4.dim}(paste an emoji, blank to reset)${c4.reset}`,
10475
+ `${c5.bold}Icon for ${machine.name}${c5.reset} ${c5.dim}(paste an emoji, blank to reset)${c5.reset}`,
10289
10476
  current
10290
10477
  );
10291
10478
  if (emoji !== null) {
10292
10479
  const trimmed = emoji.trim();
10293
10480
  await setMachineIcon(api, machine.id, trimmed);
10294
10481
  machine.icon = trimmed || void 0;
10295
- tui.print(`${c4.green}\u2713${c4.reset} icon ${trimmed ? `set to ${trimmed}` : "reset"} for ${machine.name}`);
10482
+ tui.print(`${c5.green}\u2713${c5.reset} icon ${trimmed ? `set to ${trimmed}` : "reset"} for ${machine.name}`);
10296
10483
  }
10297
10484
  return manageMachine(tui, api, self, machine);
10298
10485
  }
@@ -10308,7 +10495,7 @@ async function manageMachine(tui, api, self, machine) {
10308
10495
  const name = await tui.prompt(`New name for ${machine.name}`, machine.name);
10309
10496
  if (name === null || !name.trim()) return;
10310
10497
  await setMachineName(api, machine.id, name.trim());
10311
- tui.print(`${c4.green}\u2713${c4.reset} Renamed ${c4.bold}${machine.name}${c4.reset} \u2192 ${c4.bold}${name.trim()}${c4.reset}.`);
10498
+ tui.print(`${c5.green}\u2713${c5.reset} Renamed ${c5.bold}${machine.name}${c5.reset} \u2192 ${c5.bold}${name.trim()}${c5.reset}.`);
10312
10499
  } else if (action === "update") {
10313
10500
  if (isSelf) {
10314
10501
  await runUpdateCommand(tui);
@@ -10319,7 +10506,7 @@ async function manageMachine(tui, api, self, machine) {
10319
10506
  ]);
10320
10507
  if (go !== "yes") return;
10321
10508
  await dispatch("update");
10322
- tui.print(`${c4.green}\u2713${c4.reset} Update ${c4.gray}${applyNote} (its daemon updates and restarts on the new version).${c4.reset}`);
10509
+ tui.print(`${c5.green}\u2713${c5.reset} Update ${c5.gray}${applyNote} (its daemon updates and restarts on the new version).${c5.reset}`);
10323
10510
  }
10324
10511
  } else if (action === "projects") {
10325
10512
  await manageMachineProjects(tui, api, self, machine, dispatch, applyNote);
@@ -10330,7 +10517,7 @@ async function manageMachineProjects(tui, api, self, machine, dispatch, applyNot
10330
10517
  const paths = Object.keys(machine.projects).sort();
10331
10518
  const projLabels = projectDisplayLabels(machine.projects);
10332
10519
  const picked = await tui.select(
10333
- `${c4.bold}Projects on ${machine.name}${c4.reset} ${c4.dim}(\u2191\u2193 \xB7 enter \xB7 esc)${c4.reset}`,
10520
+ `${c5.bold}Projects on ${machine.name}${c5.reset} ${c5.dim}(\u2191\u2193 \xB7 enter \xB7 esc)${c5.reset}`,
10334
10521
  [
10335
10522
  ...paths.map((p) => ({
10336
10523
  label: projLabels.get(p) ?? projectDisplayName(p, machine.projects[p]),
@@ -10351,12 +10538,12 @@ async function manageMachineProjects(tui, api, self, machine, dispatch, applyNot
10351
10538
  });
10352
10539
  if (!chosen) return;
10353
10540
  await dispatch("add_project", { path: chosen });
10354
- tui.print(`${c4.green}\u2713${c4.reset} Add ${chosen} ${c4.gray}${applyNote}.${c4.reset}`);
10541
+ tui.print(`${c5.green}\u2713${c5.reset} Add ${chosen} ${c5.gray}${applyNote}.${c5.reset}`);
10355
10542
  return;
10356
10543
  }
10357
10544
  const project = machine.projects[picked];
10358
10545
  const displayName = projectDisplayName(picked, project);
10359
- const action = await tui.select(`${c4.bold}${displayName}${c4.reset} ${c4.dim}${shortenPath(picked, 48)}${c4.reset}`, [
10546
+ const action = await tui.select(`${c5.bold}${displayName}${c5.reset} ${c5.dim}${shortenPath(picked, 48)}${c5.reset}`, [
10360
10547
  { label: "Rename", hint: "display name only \u2014 the directory is untouched", value: "rename" },
10361
10548
  { label: "Remove from this machine's projects", hint: "doesn't delete the directory", value: "remove" },
10362
10549
  { label: "Back", value: "back" }
@@ -10371,60 +10558,60 @@ async function manageMachineProjects(tui, api, self, machine, dispatch, applyNot
10371
10558
  await setProjectName(api, machine.id, picked, name);
10372
10559
  const now = name.trim() || projectDisplayName(picked, null);
10373
10560
  if (project) project.name = now;
10374
- tui.print(`${c4.green}\u2713${c4.reset} Renamed ${c4.bold}${displayName}${c4.reset} \u2192 ${c4.bold}${now}${c4.reset}.`);
10561
+ tui.print(`${c5.green}\u2713${c5.reset} Renamed ${c5.bold}${displayName}${c5.reset} \u2192 ${c5.bold}${now}${c5.reset}.`);
10375
10562
  } else {
10376
10563
  await dispatch("remove_project", { path: picked });
10377
- tui.print(`${c4.green}\u2713${c4.reset} Remove ${picked} ${c4.gray}${applyNote}.${c4.reset}`);
10564
+ tui.print(`${c5.green}\u2713${c5.reset} Remove ${picked} ${c5.gray}${applyNote}.${c5.reset}`);
10378
10565
  }
10379
10566
  }
10380
10567
  function showDaemonInfo(tui, session) {
10381
10568
  if (session.mode === "remote" && session.runner) {
10382
10569
  tui.print(
10383
- `${c4.gray}This session runs on${c4.reset} ${c4.bold}${session.runner.name}${c4.reset} ${c4.gray}(${session.runner.hostname}) \u2014 its daemon executes the tools.${c4.reset}`
10570
+ `${c5.gray}This session runs on${c5.reset} ${c5.bold}${session.runner.name}${c5.reset} ${c5.gray}(${session.runner.hostname}) \u2014 its daemon executes the tools.${c5.reset}`
10384
10571
  );
10385
10572
  } else {
10386
- tui.print(`${c4.gray}This session runs on this machine.${c4.reset}`);
10573
+ tui.print(`${c5.gray}This session runs on this machine.${c5.reset}`);
10387
10574
  }
10388
10575
  const status = serviceStatus();
10389
10576
  tui.print(
10390
- `${c4.gray}Daemon on this machine:${c4.reset} ${status.installed ? status.detail : "not installed"}`
10577
+ `${c5.gray}Daemon on this machine:${c5.reset} ${status.installed ? status.detail : "not installed"}`
10391
10578
  );
10392
10579
  if (!status.installed) {
10393
10580
  tui.print(
10394
- `${c4.gray}Install it to start sessions on this machine from anywhere:${c4.reset} ${c4.bold}standardcode daemon install${c4.reset}`
10581
+ `${c5.gray}Install it to start sessions on this machine from anywhere:${c5.reset} ${c5.bold}standardcode daemon install${c5.reset}`
10395
10582
  );
10396
10583
  tui.print(
10397
- `${c4.dim}The daemon keeps running after you close the terminal \u2014 it self-restarts, self-updates, and executes sessions you start from other machines.${c4.reset}`
10584
+ `${c5.dim}The daemon keeps running after you close the terminal \u2014 it self-restarts, self-updates, and executes sessions you start from other machines.${c5.reset}`
10398
10585
  );
10399
10586
  } else {
10400
- tui.print(`${c4.dim}Manage it with standardcode daemon status | uninstall | add-project <path>.${c4.reset}`);
10587
+ tui.print(`${c5.dim}Manage it with standardcode daemon status | uninstall | add-project <path>.${c5.reset}`);
10401
10588
  }
10402
10589
  }
10403
10590
  function showKeybindings(tui) {
10404
- tui.print(`${c4.gray}shortcuts:${c4.reset}`);
10405
- tui.print(`${c4.gray} shift-tab${c4.reset} cycle auto-accept level (1\u20135)`);
10406
- tui.print(`${c4.gray} shift-\u23CE${c4.reset} insert a newline (multiline input)`);
10407
- tui.print(`${c4.gray} option-\u23CE${c4.reset} steer now \u2014 stops the current step and plays your message`);
10408
- tui.print(`${c4.gray} /${c4.reset} open the command palette (type to filter)`);
10409
- tui.print(`${c4.gray} !cmd${c4.reset} run a shell command on the session's machine (e.g. !ls); !! to send a literal !`);
10410
- tui.print(`${c4.gray} ctrl-v${c4.reset} paste an image from the clipboard ([#Image 1])`);
10411
- tui.print(`${c4.gray} \u2191 / \u2193${c4.reset} cycle past messages (on the input's top line)`);
10412
- tui.print(`${c4.gray} \u2190${c4.reset} from the start of the input: select the [\u2699 n bg] badge (enter opens it)`);
10413
- tui.print(`${c4.gray} ctrl-c${c4.reset} quit`);
10591
+ tui.print(`${c5.gray}shortcuts:${c5.reset}`);
10592
+ tui.print(`${c5.gray} shift-tab${c5.reset} cycle auto-accept level (1\u20135)`);
10593
+ tui.print(`${c5.gray} shift-\u23CE${c5.reset} insert a newline (multiline input)`);
10594
+ tui.print(`${c5.gray} option-\u23CE${c5.reset} steer now \u2014 stops the current step and plays your message`);
10595
+ tui.print(`${c5.gray} /${c5.reset} open the command palette (type to filter)`);
10596
+ tui.print(`${c5.gray} !cmd${c5.reset} run a shell command on the session's machine (e.g. !ls); !! to send a literal !`);
10597
+ tui.print(`${c5.gray} ctrl-v${c5.reset} paste an image from the clipboard ([#Image 1])`);
10598
+ tui.print(`${c5.gray} \u2191 / \u2193${c5.reset} cycle past messages (on the input's top line)`);
10599
+ tui.print(`${c5.gray} \u2190${c5.reset} from the start of the input: select the [\u2699 n bg] badge (enter opens it)`);
10600
+ tui.print(`${c5.gray} ctrl-c${c5.reset} quit`);
10414
10601
  }
10415
10602
  async function runUpdateCommand(tui) {
10416
10603
  const version = readVersion();
10417
10604
  const result = await forceCheckForUpdate(version);
10418
10605
  if (!result) {
10419
- tui.print(`${c4.green}\u2713${c4.reset} ${c4.gray}@standardagents/code${c4.reset} is up to date (v${version})`);
10606
+ tui.print(`${c5.green}\u2713${c5.reset} ${c5.gray}@standardagents/code${c5.reset} is up to date (v${version})`);
10420
10607
  return;
10421
10608
  }
10422
10609
  const { latest } = result;
10423
10610
  tui.print(`
10424
- ${c4.yellow}\u27F3${c4.reset} Update available: ${c4.gray}v${version}${c4.reset} \u2192 ${c4.green}v${latest}${c4.reset}`);
10611
+ ${c5.yellow}\u27F3${c5.reset} Update available: ${c5.gray}v${version}${c5.reset} \u2192 ${c5.green}v${latest}${c5.reset}`);
10425
10612
  const pm = detectPackageManager();
10426
10613
  if (!pm) {
10427
- tui.print(` ${c4.gray}This is a source checkout \u2014 pull the repo to update.${c4.reset}`);
10614
+ tui.print(` ${c5.gray}This is a source checkout \u2014 pull the repo to update.${c5.reset}`);
10428
10615
  return;
10429
10616
  }
10430
10617
  const { display } = updateCommand(pm);
@@ -10433,28 +10620,28 @@ async function runUpdateCommand(tui) {
10433
10620
  { label: "No, skip", value: "no" }
10434
10621
  ]);
10435
10622
  if (choice === "yes") {
10436
- tui.print(` ${c4.gray}Running ${display}\u2026${c4.reset}`);
10623
+ tui.print(` ${c5.gray}Running ${display}\u2026${c5.reset}`);
10437
10624
  const { ok, output: pmOutput } = await runUpdate(pm);
10438
10625
  if (ok) {
10439
- tui.print(` ${c4.green}\u2713${c4.reset} Updated to v${latest}. Restart to use the new version.`);
10626
+ tui.print(` ${c5.green}\u2713${c5.reset} Updated to v${latest}. Restart to use the new version.`);
10440
10627
  } else {
10441
- tui.print(` ${c4.red}\u2717${c4.reset} Update failed:`);
10628
+ tui.print(` ${c5.red}\u2717${c5.reset} Update failed:`);
10442
10629
  for (const line of pmOutput.trim().split("\n").slice(-6)) {
10443
- tui.print(` ${c4.dim}${line}${c4.reset}`);
10630
+ tui.print(` ${c5.dim}${line}${c5.reset}`);
10444
10631
  }
10445
10632
  }
10446
10633
  } else {
10447
- tui.print(` ${c4.gray}Skipped. Run /update later.${c4.reset}`);
10634
+ tui.print(` ${c5.gray}Skipped. Run /update later.${c5.reset}`);
10448
10635
  }
10449
10636
  }
10450
10637
  async function runProcessMenu(tui, bg) {
10451
10638
  const procs = await bg.list();
10452
10639
  if (!procs.length) {
10453
- tui.print(`${c4.gray}No background processes for this session.${c4.reset}`);
10640
+ tui.print(`${c5.gray}No background processes for this session.${c5.reset}`);
10454
10641
  return;
10455
10642
  }
10456
10643
  const items = procs.map((p) => {
10457
- const status = p.status === "running" ? `${c4.green}running${c4.reset}` : `${c4.gray}${p.status}${typeof p.exitCode === "number" ? ` (exit ${p.exitCode})` : ""}${c4.reset}`;
10644
+ const status = p.status === "running" ? `${c5.green}running${c5.reset}` : `${c5.gray}${p.status}${typeof p.exitCode === "number" ? ` (exit ${p.exitCode})` : ""}${c5.reset}`;
10458
10645
  return {
10459
10646
  label: `${p.description || p.command}`,
10460
10647
  hint: `${p.id} \xB7 ${status}`,
@@ -10462,22 +10649,22 @@ async function runProcessMenu(tui, bg) {
10462
10649
  };
10463
10650
  });
10464
10651
  const picked = await tui.select(
10465
- `${c4.bold}Background processes${c4.reset} ${c4.dim}(\u2191/\u2193 \xB7 enter to manage \xB7 esc to close)${c4.reset}`,
10652
+ `${c5.bold}Background processes${c5.reset} ${c5.dim}(\u2191/\u2193 \xB7 enter to manage \xB7 esc to close)${c5.reset}`,
10466
10653
  items
10467
10654
  );
10468
10655
  if (!picked) return;
10469
10656
  const proc = procs.find((p) => p.id === picked);
10470
10657
  if (!proc || proc.status !== "running") {
10471
- tui.print(`${c4.gray}${picked} is not running.${c4.reset}`);
10658
+ tui.print(`${c5.gray}${picked} is not running.${c5.reset}`);
10472
10659
  return;
10473
10660
  }
10474
- const action = await tui.select(`${c4.bold}${proc.description || proc.command}${c4.reset}`, [
10661
+ const action = await tui.select(`${c5.bold}${proc.description || proc.command}${c5.reset}`, [
10475
10662
  { label: "Stop this process", value: "stop" },
10476
10663
  { label: "Leave it running", value: "leave" }
10477
10664
  ]);
10478
10665
  if (action === "stop") {
10479
10666
  await bg.stop(picked);
10480
- tui.print(`${c4.gray}stopped ${picked}${c4.reset}`);
10667
+ tui.print(`${c5.gray}stopped ${picked}${c5.reset}`);
10481
10668
  }
10482
10669
  }
10483
10670
  async function runApprovalsMenu(tui, perm, save) {
@@ -10485,7 +10672,7 @@ async function runApprovalsMenu(tui, perm, save) {
10485
10672
  const risks = Array.from(perm.allowRisk).sort((a, b) => a - b);
10486
10673
  if (!tools.length && !risks.length) {
10487
10674
  tui.print(
10488
- `${c4.gray}No pre-approved commands. At a permission prompt, choose "Always allow this tool" or "Allow all level N" to add some.${c4.reset}`
10675
+ `${c5.gray}No pre-approved commands. At a permission prompt, choose "Always allow this tool" or "Allow all level N" to add some.${c5.reset}`
10489
10676
  );
10490
10677
  return;
10491
10678
  }
@@ -10495,22 +10682,22 @@ async function runApprovalsMenu(tui, perm, save) {
10495
10682
  { label: "Clear all approvals", hint: "", value: "clear" }
10496
10683
  ];
10497
10684
  const picked = await tui.select(
10498
- `${c4.bold}Approved commands${c4.reset} ${c4.dim}(enter to revoke \xB7 esc to close)${c4.reset}`,
10685
+ `${c5.bold}Approved commands${c5.reset} ${c5.dim}(enter to revoke \xB7 esc to close)${c5.reset}`,
10499
10686
  items
10500
10687
  );
10501
10688
  if (!picked) return;
10502
10689
  if (picked === "clear") {
10503
10690
  perm.alwaysAllow.clear();
10504
10691
  perm.allowRisk.clear();
10505
- tui.print(`${c4.gray}cleared all approvals${c4.reset}`);
10692
+ tui.print(`${c5.gray}cleared all approvals${c5.reset}`);
10506
10693
  } else if (picked.startsWith("tool:")) {
10507
10694
  const t = picked.slice(5);
10508
10695
  perm.alwaysAllow.delete(t);
10509
- tui.print(`${c4.gray}revoked tool ${t}${c4.reset}`);
10696
+ tui.print(`${c5.gray}revoked tool ${t}${c5.reset}`);
10510
10697
  } else if (picked.startsWith("risk:")) {
10511
10698
  const r = Number(picked.slice(5));
10512
10699
  perm.allowRisk.delete(r);
10513
- tui.print(`${c4.gray}revoked level ${r}${c4.reset}`);
10700
+ tui.print(`${c5.gray}revoked level ${r}${c5.reset}`);
10514
10701
  }
10515
10702
  save();
10516
10703
  }
@@ -10528,7 +10715,7 @@ async function runMcpMenu(tui, mcp) {
10528
10715
  items.push({ label: "\uFF0B Install a new MCP server\u2026", hint: "find & install", value: INSTALL });
10529
10716
  items.push({ label: "Add manually (name: command)\u2026", hint: "advanced", value: ADD_MANUAL });
10530
10717
  const picked = await tui.select(
10531
- `${c4.bold}MCP servers${c4.reset} ${c4.dim}(\u2191/\u2193 \xB7 enter \xB7 esc to close)${c4.reset}`,
10718
+ `${c5.bold}MCP servers${c5.reset} ${c5.dim}(\u2191/\u2193 \xB7 enter \xB7 esc to close)${c5.reset}`,
10532
10719
  items
10533
10720
  );
10534
10721
  if (!picked) return;
@@ -10542,7 +10729,7 @@ async function runMcpMenu(tui, mcp) {
10542
10729
  }
10543
10730
  const server = configured.find((s) => s.name === picked);
10544
10731
  const isConnected = connected.has(picked);
10545
- const action = await tui.select(`${c4.bold}${picked}${c4.reset}`, [
10732
+ const action = await tui.select(`${c5.bold}${picked}${c5.reset}`, [
10546
10733
  { label: "View tools", value: "tools" },
10547
10734
  isConnected ? { label: "Disconnect", value: "disconnect" } : { label: "Connect", value: "connect" },
10548
10735
  server.enabled ? { label: "Disable (don't auto-connect)", value: "disable" } : { label: "Enable (auto-connect on start)", value: "enable" },
@@ -10552,29 +10739,29 @@ async function runMcpMenu(tui, mcp) {
10552
10739
  if (action === "tools") {
10553
10740
  const entry = mcp.catalog().servers.find((e) => e.name === picked);
10554
10741
  if (!entry || entry.status !== "connected") {
10555
- tui.print(`${c4.gray}${picked} is not connected \u2014 connect it to list tools.${c4.reset}`);
10742
+ tui.print(`${c5.gray}${picked} is not connected \u2014 connect it to list tools.${c5.reset}`);
10556
10743
  return;
10557
10744
  }
10558
- if (!entry.tools.length) tui.print(`${c4.gray}${picked} exposes no tools.${c4.reset}`);
10559
- for (const t of entry.tools) tui.print(` ${c4.cyan}${t.name}${c4.reset}${t.description ? ` ${c4.gray}\u2014 ${t.description}${c4.reset}` : ""}`);
10560
- if (entry.resources.length) tui.print(` ${c4.gray}${entry.resources.length} resource(s)${c4.reset}`);
10745
+ if (!entry.tools.length) tui.print(`${c5.gray}${picked} exposes no tools.${c5.reset}`);
10746
+ for (const t of entry.tools) tui.print(` ${c5.cyan}${t.name}${c5.reset}${t.description ? ` ${c5.gray}\u2014 ${t.description}${c5.reset}` : ""}`);
10747
+ if (entry.resources.length) tui.print(` ${c5.gray}${entry.resources.length} resource(s)${c5.reset}`);
10561
10748
  } else if (action === "connect") {
10562
10749
  const res = await mcp.connect(server);
10563
- tui.print(res.ok ? `${c4.cyan}\u26A1 connected (${res.tools} tools)${c4.reset}` : `${c4.red}\u26A0 ${res.error}${c4.reset}`);
10750
+ tui.print(res.ok ? `${c5.cyan}\u26A1 connected (${res.tools} tools)${c5.reset}` : `${c5.red}\u26A0 ${res.error}${c5.reset}`);
10564
10751
  } else if (action === "disconnect") {
10565
10752
  mcp.disconnect(picked);
10566
- tui.print(`${c4.gray}disconnected ${picked}${c4.reset}`);
10753
+ tui.print(`${c5.gray}disconnected ${picked}${c5.reset}`);
10567
10754
  } else if (action === "enable") {
10568
10755
  mcp.setEnabled(picked, true);
10569
10756
  const res = await mcp.connect(server);
10570
- tui.print(res.ok ? `${c4.cyan}\u26A1 enabled + connected (${res.tools} tools)${c4.reset}` : `${c4.red}\u26A0 enabled but failed: ${res.error}${c4.reset}`);
10757
+ tui.print(res.ok ? `${c5.cyan}\u26A1 enabled + connected (${res.tools} tools)${c5.reset}` : `${c5.red}\u26A0 enabled but failed: ${res.error}${c5.reset}`);
10571
10758
  } else if (action === "disable") {
10572
10759
  mcp.setEnabled(picked, false);
10573
10760
  mcp.disconnect(picked);
10574
- tui.print(`${c4.gray}disabled + disconnected ${picked}${c4.reset}`);
10761
+ tui.print(`${c5.gray}disabled + disconnected ${picked}${c5.reset}`);
10575
10762
  } else if (action === "remove") {
10576
10763
  mcp.remove(picked);
10577
- tui.print(`${c4.gray}removed ${picked}${c4.reset}`);
10764
+ tui.print(`${c5.gray}removed ${picked}${c5.reset}`);
10578
10765
  }
10579
10766
  }
10580
10767
  async function addMcpServer(tui, mcp) {
@@ -10585,13 +10772,13 @@ async function addMcpServer(tui, mcp) {
10585
10772
  if (!spec) return;
10586
10773
  const cfg = parseServerSpec(spec);
10587
10774
  if (!cfg) {
10588
- tui.print(`${c4.yellow}couldn't parse that. Use name: command [args]${c4.reset}`);
10775
+ tui.print(`${c5.yellow}couldn't parse that. Use name: command [args]${c5.reset}`);
10589
10776
  return;
10590
10777
  }
10591
- tui.print(`${c4.gray}connecting MCP "${cfg.name}" (${cfg.command} ${cfg.args.join(" ")})\u2026${c4.reset}`);
10778
+ tui.print(`${c5.gray}connecting MCP "${cfg.name}" (${cfg.command} ${cfg.args.join(" ")})\u2026${c5.reset}`);
10592
10779
  const res = await mcp.add(cfg);
10593
- if (res.ok) tui.print(`${c4.cyan}\u26A1 MCP "${cfg.name}" connected${c4.reset} ${c4.gray}(${res.tools} tool${res.tools === 1 ? "" : "s"})${c4.reset}`);
10594
- else tui.print(`${c4.red}\u26A0 MCP "${cfg.name}" failed:${c4.reset} ${c4.gray}${res.error}${c4.reset} ${c4.dim}(saved; retry from the MCP menu)${c4.reset}`);
10780
+ if (res.ok) tui.print(`${c5.cyan}\u26A1 MCP "${cfg.name}" connected${c5.reset} ${c5.gray}(${res.tools} tool${res.tools === 1 ? "" : "s"})${c5.reset}`);
10781
+ else tui.print(`${c5.red}\u26A0 MCP "${cfg.name}" failed:${c5.reset} ${c5.gray}${res.error}${c5.reset} ${c5.dim}(saved; retry from the MCP menu)${c5.reset}`);
10595
10782
  }
10596
10783
  async function installMcpServerFlow(tui, mcp) {
10597
10784
  const query = await tui.prompt(