clawborrator-cli 0.0.23 → 0.0.25

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 (2) hide show
  1. package/dist-bundled/claw.cjs +154 -47
  2. package/package.json +1 -1
@@ -6844,7 +6844,7 @@ var whoamiCmd = new Command("whoami").description("show the currently authentica
6844
6844
  });
6845
6845
 
6846
6846
  // src/commands/session-attach.ts
6847
- var import_node_readline = require("node:readline");
6847
+ var import_node_readline2 = require("node:readline");
6848
6848
 
6849
6849
  // ../node_modules/ws/wrapper.mjs
6850
6850
  var import_stream = __toESM(require_stream(), 1);
@@ -6857,18 +6857,70 @@ var import_websocket = __toESM(require_websocket(), 1);
6857
6857
  var import_websocket_server = __toESM(require_websocket_server(), 1);
6858
6858
  var wrapper_default = import_websocket.default;
6859
6859
 
6860
- // src/commands/session-attach.ts
6860
+ // src/util/disambiguate.ts
6861
+ var import_node_readline = require("node:readline");
6861
6862
  var RESET = "\x1B[0m";
6862
6863
  var DIM = "\x1B[2m";
6864
+ var BOLD = "\x1B[1m";
6865
+ var AmbiguousError = class extends Error {
6866
+ constructor(candidates, input) {
6867
+ super(`ambiguous reference '${input}' \u2014 multiple online sessions match`);
6868
+ this.candidates = candidates;
6869
+ this.input = input;
6870
+ }
6871
+ code = "CLW_AMBIGUOUS";
6872
+ };
6873
+ async function pickCandidate(input, candidates) {
6874
+ if (candidates.length === 1) return candidates[0];
6875
+ const live = candidates.filter((c) => c.connected);
6876
+ if (live.length <= 1) {
6877
+ return live[0] ?? candidates[0];
6878
+ }
6879
+ if (!process.stdin.isTTY || !process.stderr.isTTY) {
6880
+ throw new AmbiguousError(live, input);
6881
+ }
6882
+ process.stderr.write(`${BOLD}'${input}' is ambiguous \u2014 pick a session:${RESET}
6883
+ `);
6884
+ for (let i = 0; i < live.length; i++) {
6885
+ const c = live[i];
6886
+ const qualified = c.routingName ? `@${c.startedByLogin}/${c.routingName.replace(/^@/, "")}` : `(no routing name)`;
6887
+ const cwd = c.cwd ? ` ${DIM}${c.cwd}${RESET}` : "";
6888
+ const host = c.host ? ` ${DIM}${c.host}${RESET}` : "";
6889
+ process.stderr.write(` ${BOLD}${i + 1}${RESET}. ${qualified}${host}${cwd}
6890
+ `);
6891
+ process.stderr.write(` ${DIM}id ${c.id}${RESET}
6892
+ `);
6893
+ }
6894
+ process.stderr.write(` ${BOLD}q${RESET}. cancel
6895
+ `);
6896
+ const rl = (0, import_node_readline.createInterface)({ input: process.stdin, output: process.stderr });
6897
+ const answer = await new Promise((resolve3) => {
6898
+ rl.question(`pick [1-${live.length}]: `, resolve3);
6899
+ });
6900
+ rl.close();
6901
+ const trimmed = answer.trim().toLowerCase();
6902
+ if (trimmed === "q" || trimmed === "quit" || trimmed === "") {
6903
+ throw new Error("cancelled");
6904
+ }
6905
+ const idx = parseInt(trimmed, 10);
6906
+ if (!Number.isInteger(idx) || idx < 1 || idx > live.length) {
6907
+ throw new Error(`invalid selection '${answer}'`);
6908
+ }
6909
+ return live[idx - 1];
6910
+ }
6911
+
6912
+ // src/commands/session-attach.ts
6913
+ var RESET2 = "\x1B[0m";
6914
+ var DIM2 = "\x1B[2m";
6863
6915
  var AMBER = "\x1B[33m";
6864
6916
  var BLUE = "\x1B[36m";
6865
6917
  var RED = "\x1B[31m";
6866
- var BOLD = "\x1B[1m";
6918
+ var BOLD2 = "\x1B[1m";
6867
6919
  var GREEN = "\x1B[32m";
6868
6920
  function ts() {
6869
6921
  return (/* @__PURE__ */ new Date()).toLocaleTimeString();
6870
6922
  }
6871
- var sessionAttach = new Command("attach").description("open a TUI on a session \u2014 see the chat stream, post op-messages").argument("<ref>", "session UUID or @routingName (e.g. @driver)").action(async (ref) => {
6923
+ var sessionAttach = new Command("attach").description("open a TUI on a session \u2014 see the chat stream, post op-messages").argument("<ref>", "session UUID or @routingName (e.g. @driver)").option("--limit <n>", 'history items to load before the live stream begins. 0 = none. "all" = up to 5000. default 50.', "50").option("--no-op-messages", "exclude op-messages from the history backlog (live ones still arrive once attached)").action(async (ref, opts) => {
6872
6924
  const cfg = loadConfig();
6873
6925
  if (!cfg.pat) {
6874
6926
  console.error("error: not logged in. run `claw login`.");
@@ -6906,7 +6958,41 @@ var sessionAttach = new Command("attach").description("open a TUI on a session \
6906
6958
  console.error(`error: no session with routing name ${label} (run \`claw session list\` to see what's available)`);
6907
6959
  process.exit(2);
6908
6960
  }
6909
- sessionId = candidates[0].id;
6961
+ try {
6962
+ const picked = await pickCandidate(ref, candidates);
6963
+ sessionId = picked.id;
6964
+ } catch (e) {
6965
+ if (e instanceof AmbiguousError) {
6966
+ console.error(`error: '${ref}' is ambiguous \u2014 multiple online sessions match. Re-run with a UUID or qualified form (e.g. @owner/slug). Candidates:`);
6967
+ for (const c of e.candidates) {
6968
+ console.error(` ${c.id} @${c.startedByLogin}/${(c.routingName ?? "").replace(/^@/, "")} ${c.cwd ?? ""}`);
6969
+ }
6970
+ process.exit(2);
6971
+ }
6972
+ console.error(`error: ${e?.message ?? String(e)}`);
6973
+ process.exit(2);
6974
+ }
6975
+ }
6976
+ const limitArg = String(opts.limit ?? "50").toLowerCase();
6977
+ const historyLimit = limitArg === "all" ? 5e3 : limitArg === "0" ? 0 : Math.max(0, parseInt(limitArg, 10) || 0);
6978
+ if (historyLimit > 0) {
6979
+ const kindsParam = opts.opMessages === false ? "&kinds=event" : "";
6980
+ try {
6981
+ const tl = await api.get(`/api/v1/sessions/${encodeURIComponent(sessionId)}/timeline?limit=${historyLimit}${kindsParam}`);
6982
+ if (tl.items.length > 0) {
6983
+ console.log(`${DIM2}\u2500\u2500\u2500 history (${tl.items.length} item${tl.items.length === 1 ? "" : "s"}) \u2500\u2500\u2500${RESET2}`);
6984
+ for (const item of tl.items) {
6985
+ if (item.kind === "event") {
6986
+ renderEvent(item.event, myLogin);
6987
+ } else {
6988
+ console.log(`${DIM2}[${shortTs(item.ts)}]${RESET2} ${GREEN}@${item.authorLogin}${RESET2} ${item.text}`);
6989
+ }
6990
+ }
6991
+ console.log(`${DIM2}\u2500\u2500\u2500 live \u2500\u2500\u2500${RESET2}`);
6992
+ }
6993
+ } catch (e) {
6994
+ console.error(`${DIM2}(history fetch failed: ${e?.message ?? String(e)} \u2014 continuing live)${RESET2}`);
6995
+ }
6910
6996
  }
6911
6997
  const wsUrl = cfg.hubUrl.replace(/^http/i, "ws") + "/cli";
6912
6998
  const ws = new wrapper_default(wsUrl, {
@@ -6915,7 +7001,7 @@ var sessionAttach = new Command("attach").description("open a TUI on a session \
6915
7001
  let mySubscription = false;
6916
7002
  const pendingPerms = [];
6917
7003
  ws.on("open", () => {
6918
- console.log(`${DIM}[${ts()}]${RESET} connected to ${cfg.hubUrl}`);
7004
+ console.log(`${DIM2}[${ts()}]${RESET2} connected to ${cfg.hubUrl}`);
6919
7005
  const sub = { type: "subscribe", sessionId };
6920
7006
  ws.send(JSON.stringify(sub));
6921
7007
  });
@@ -6935,22 +7021,22 @@ var sessionAttach = new Command("attach").description("open a TUI on a session \
6935
7021
  printInbound(msg, myLogin);
6936
7022
  if (msg.type === "subscribed") {
6937
7023
  mySubscription = true;
6938
- console.log(`${DIM}attached as ${BOLD}${msg.role}${RESET}${DIM}. type for prompt \xB7 @other <text> to route \xB7 /m <text> for op-msg \xB7 /y /n on permissions \xB7 /q to quit${RESET}`);
7024
+ console.log(`${DIM2}attached as ${BOLD2}${msg.role}${RESET2}${DIM2}. type for prompt \xB7 @other <text> to route \xB7 /m <text> for op-msg \xB7 /y /n on permissions \xB7 /q to quit${RESET2}`);
6939
7025
  }
6940
7026
  });
6941
7027
  ws.on("close", (code, reason) => {
6942
- console.log(`${DIM}[${ts()}] disconnected (${code}${reason ? ": " + reason.toString() : ""})${RESET}`);
7028
+ console.log(`${DIM2}[${ts()}] disconnected (${code}${reason ? ": " + reason.toString() : ""})${RESET2}`);
6943
7029
  process.exit(0);
6944
7030
  });
6945
7031
  ws.on("error", (err) => {
6946
- console.error(`${RED}ws error: ${err.message}${RESET}`);
7032
+ console.error(`${RED}ws error: ${err.message}${RESET2}`);
6947
7033
  });
6948
- const rl = (0, import_node_readline.createInterface)({ input: process.stdin, terminal: false });
7034
+ const rl = (0, import_node_readline2.createInterface)({ input: process.stdin, terminal: false });
6949
7035
  rl.on("line", (raw) => {
6950
7036
  const text = raw.trim();
6951
7037
  if (!text) return;
6952
7038
  if (!mySubscription) {
6953
- console.log(`${DIM}(not subscribed yet \u2014 waiting...)${RESET}`);
7039
+ console.log(`${DIM2}(not subscribed yet \u2014 waiting...)${RESET2}`);
6954
7040
  return;
6955
7041
  }
6956
7042
  if (text === "/q" || text === "/quit") {
@@ -6960,7 +7046,7 @@ var sessionAttach = new Command("attach").description("open a TUI on a session \
6960
7046
  if (text === "/y" || text === "/yes" || text === "/n" || text === "/no") {
6961
7047
  const pending = pendingPerms[pendingPerms.length - 1];
6962
7048
  if (!pending) {
6963
- console.log(`${DIM}(no pending permission to act on)${RESET}`);
7049
+ console.log(`${DIM2}(no pending permission to act on)${RESET2}`);
6964
7050
  return;
6965
7051
  }
6966
7052
  const decision = text === "/y" || text === "/yes" ? "allow" : "deny";
@@ -6977,7 +7063,7 @@ var sessionAttach = new Command("attach").description("open a TUI on a session \
6977
7063
  if (text === "/m" || text.startsWith("/m ")) {
6978
7064
  const opText = text.slice(2).trim();
6979
7065
  if (!opText) {
6980
- console.log(`${DIM}usage: /m <text> (sends as op-message; bare text is a prompt)${RESET}`);
7066
+ console.log(`${DIM2}usage: /m <text> (sends as op-message; bare text is a prompt)${RESET2}`);
6981
7067
  return;
6982
7068
  }
6983
7069
  const out2 = { type: "op_message", sessionId, text: opText };
@@ -6987,16 +7073,16 @@ var sessionAttach = new Command("attach").description("open a TUI on a session \
6987
7073
  if (text === "/p" || text.startsWith("/p ")) {
6988
7074
  const promptText = text.slice(2).trim();
6989
7075
  if (!promptText) {
6990
- console.log(`${DIM}usage: /p <text> (or just type \u2014 bare text is a prompt now)${RESET}`);
7076
+ console.log(`${DIM2}usage: /p <text> (or just type \u2014 bare text is a prompt now)${RESET2}`);
6991
7077
  return;
6992
7078
  }
6993
7079
  const out2 = { type: "prompt", sessionId, text: promptText };
6994
7080
  ws.send(JSON.stringify(out2));
6995
- console.log(`${DIM}[${ts()}]${RESET} ${AMBER}\u2192 prompt sent${RESET} ${promptText}`);
7081
+ console.log(`${DIM2}[${ts()}]${RESET2} ${AMBER}\u2192 prompt sent${RESET2} ${promptText}`);
6996
7082
  return;
6997
7083
  }
6998
7084
  if (text.startsWith("/")) {
6999
- console.log(`${DIM}unknown slash-command: ${text} (try /m /y /n /q)${RESET}`);
7085
+ console.log(`${DIM2}unknown slash-command: ${text} (try /m /y /n /q)${RESET2}`);
7000
7086
  return;
7001
7087
  }
7002
7088
  const xMatch = /^(@[A-Za-z0-9._\-/]+)\s+([\s\S]+)$/.exec(text);
@@ -7004,7 +7090,7 @@ var sessionAttach = new Command("attach").description("open a TUI on a session \
7004
7090
  const targetRef = xMatch[1];
7005
7091
  const promptText = xMatch[2].trim();
7006
7092
  if (!promptText) {
7007
- console.log(`${DIM}usage: ${targetRef} <prompt>${RESET}`);
7093
+ console.log(`${DIM2}usage: ${targetRef} <prompt>${RESET2}`);
7008
7094
  return;
7009
7095
  }
7010
7096
  (async () => {
@@ -7028,7 +7114,15 @@ var sessionAttach = new Command("attach").description("open a TUI on a session \
7028
7114
  if (mine.length > 0) candidates = mine;
7029
7115
  }
7030
7116
  if (candidates.length === 0) {
7031
- console.error(`${RED}error: no session ${targetRef} (try \`claw session list\` in another terminal)${RESET}`);
7117
+ console.error(`${RED}error: no session ${targetRef} (try \`claw session list\` in another terminal)${RESET2}`);
7118
+ return;
7119
+ }
7120
+ const liveMatches = candidates.filter((c) => c.connected);
7121
+ if (liveMatches.length > 1) {
7122
+ console.error(`${RED}error: '${targetRef}' is ambiguous \u2014 multiple online matches. Use the qualified form:${RESET2}`);
7123
+ for (const c of liveMatches) {
7124
+ console.error(` ${DIM2}${c.id.slice(0, 8)}\u2026${RESET2} @${c.startedByLogin}/${(c.routingName ?? "").replace(/^@/, "")} ${DIM2}${c.cwd ?? ""}${RESET2}`);
7125
+ }
7032
7126
  return;
7033
7127
  }
7034
7128
  const match = candidates[0];
@@ -7043,16 +7137,16 @@ var sessionAttach = new Command("attach").description("open a TUI on a session \
7043
7137
  sourceSessionId: sessionId
7044
7138
  };
7045
7139
  ws.send(JSON.stringify(out2));
7046
- console.log(`${DIM}[${ts()}]${RESET} ${AMBER}\u2192 prompt \u2192 ${targetRef}${RESET} ${promptText}`);
7140
+ console.log(`${DIM2}[${ts()}]${RESET2} ${AMBER}\u2192 prompt \u2192 ${targetRef}${RESET2} ${promptText}`);
7047
7141
  } catch (e) {
7048
- console.error(`${RED}error: ${e?.message ?? String(e)}${RESET}`);
7142
+ console.error(`${RED}error: ${e?.message ?? String(e)}${RESET2}`);
7049
7143
  }
7050
7144
  })();
7051
7145
  return;
7052
7146
  }
7053
7147
  const out = { type: "prompt", sessionId, text };
7054
7148
  ws.send(JSON.stringify(out));
7055
- console.log(`${DIM}[${ts()}]${RESET} ${AMBER}\u2192 prompt${RESET} ${text}`);
7149
+ console.log(`${DIM2}[${ts()}]${RESET2} ${AMBER}\u2192 prompt${RESET2} ${text}`);
7056
7150
  });
7057
7151
  process.on("SIGINT", () => {
7058
7152
  ws.close(1e3, "sigint");
@@ -7067,26 +7161,26 @@ function printInbound(msg, myLogin) {
7067
7161
  break;
7068
7162
  }
7069
7163
  case "op_message": {
7070
- console.log(`${DIM}[${shortTs(msg.ts)}]${RESET} ${GREEN}@${msg.authorLogin}${RESET} ${msg.text}`);
7164
+ console.log(`${DIM2}[${shortTs(msg.ts)}]${RESET2} ${GREEN}@${msg.authorLogin}${RESET2} ${msg.text}`);
7071
7165
  break;
7072
7166
  }
7073
7167
  case "permission_request": {
7074
- console.log(`${RED}[!] ${shortTs(msg.ts)}${RESET} approval needed: ${BOLD}${msg.tool}${RESET} \u2014 ${msg.inputPreview}`);
7168
+ console.log(`${RED}[!] ${shortTs(msg.ts)}${RESET2} approval needed: ${BOLD2}${msg.tool}${RESET2} \u2014 ${msg.inputPreview}`);
7075
7169
  break;
7076
7170
  }
7077
7171
  case "permission_resolved": {
7078
- const dec = msg.decision === "allow" ? `${GREEN}allowed${RESET}` : msg.decision === "deny" ? `${RED}denied${RESET}` : `${DIM}expired${RESET}`;
7079
- console.log(`${DIM}[${ts()}]${RESET} permission ${msg.requestId} ${dec} by @${msg.resolverLogin ?? "?"}`);
7172
+ const dec = msg.decision === "allow" ? `${GREEN}allowed${RESET2}` : msg.decision === "deny" ? `${RED}denied${RESET2}` : `${DIM2}expired${RESET2}`;
7173
+ console.log(`${DIM2}[${ts()}]${RESET2} permission ${msg.requestId} ${dec} by @${msg.resolverLogin ?? "?"}`);
7080
7174
  break;
7081
7175
  }
7082
7176
  case "presence": {
7083
- console.log(`${DIM}[${ts()}] presence: ${msg.attached.map((l) => "@" + l).join(", ") || "(empty)"}${RESET}`);
7177
+ console.log(`${DIM2}[${ts()}] presence: ${msg.attached.map((l) => "@" + l).join(", ") || "(empty)"}${RESET2}`);
7084
7178
  break;
7085
7179
  }
7086
7180
  case "ack":
7087
7181
  break;
7088
7182
  case "error":
7089
- console.error(`${RED}error (${msg.code}): ${msg.message}${RESET}`);
7183
+ console.error(`${RED}error (${msg.code}): ${msg.message}${RESET2}`);
7090
7184
  break;
7091
7185
  }
7092
7186
  }
@@ -7109,58 +7203,58 @@ function renderEvent(ev, myLogin) {
7109
7203
  const text = String(p.text ?? p.prompt ?? "").trim() || JSON.stringify(p).slice(0, 200);
7110
7204
  const source = String(p.source ?? "cli");
7111
7205
  if (source === "operator" && myLogin && p.authorLogin === myLogin) return;
7112
- const label = source === "operator" ? `${BOLD}@${String(p.authorLogin ?? "remote")} \u203A${RESET}` : `${BOLD}(cli) \u203A${RESET}`;
7113
- console.log(`${DIM}[${ts2}]${RESET} ${label} ${text}`);
7206
+ const label = source === "operator" ? `${BOLD2}@${String(p.authorLogin ?? "remote")} \u203A${RESET2}` : `${BOLD2}(cli) \u203A${RESET2}`;
7207
+ console.log(`${DIM2}[${ts2}]${RESET2} ${label} ${text}`);
7114
7208
  return;
7115
7209
  }
7116
7210
  if (ev.type === "assistant_text") {
7117
7211
  const text = String(p.text ?? "").trim();
7118
7212
  const isPlaceholder = !!p.placeholder;
7119
- const tag = isPlaceholder ? `${DIM}claude \xB7 thinking${RESET}` : `${AMBER}claude${RESET}`;
7120
- console.log(`${DIM}[${ts2}]${RESET} ${tag} ${isPlaceholder ? DIM + text + RESET : text}`);
7213
+ const tag = isPlaceholder ? `${DIM2}claude \xB7 thinking${RESET2}` : `${AMBER}claude${RESET2}`;
7214
+ console.log(`${DIM2}[${ts2}]${RESET2} ${tag} ${isPlaceholder ? DIM2 + text + RESET2 : text}`);
7121
7215
  return;
7122
7216
  }
7123
7217
  if (ev.type === "reply") {
7124
7218
  const text = String(p.text ?? "").trim();
7125
7219
  if (p.source === "peer-reply" && p.peerLogin) {
7126
- console.log(`${DIM}[${ts2}]${RESET} ${AMBER}${String(p.peerLogin)} answered${RESET} ${text}`);
7220
+ console.log(`${DIM2}[${ts2}]${RESET2} ${AMBER}${String(p.peerLogin)} answered${RESET2} ${text}`);
7127
7221
  return;
7128
7222
  }
7129
- const tag = p.chatId ? `${AMBER}claude${RESET} ${DIM}(reply to ${String(p.chatId).slice(0, 8)})${RESET}` : `${AMBER}claude${RESET}`;
7130
- console.log(`${DIM}[${ts2}]${RESET} ${tag} ${text}`);
7223
+ const tag = p.chatId ? `${AMBER}claude${RESET2} ${DIM2}(reply to ${String(p.chatId).slice(0, 8)})${RESET2}` : `${AMBER}claude${RESET2}`;
7224
+ console.log(`${DIM2}[${ts2}]${RESET2} ${tag} ${text}`);
7131
7225
  return;
7132
7226
  }
7133
- console.log(`${DIM}[${ts2}]${RESET} ${AMBER}[chat:${ev.type}]${RESET} ${previewPayload(p)}`);
7227
+ console.log(`${DIM2}[${ts2}]${RESET2} ${AMBER}[chat:${ev.type}]${RESET2} ${previewPayload(p)}`);
7134
7228
  return;
7135
7229
  }
7136
7230
  switch (ev.type) {
7137
7231
  case "PreToolUse": {
7138
7232
  const tool = String(p.tool_name ?? p.toolName ?? p.tool ?? "?");
7139
7233
  const input = renderToolInput(p);
7140
- console.log(`${DIM}[${ts2}]${RESET} ${BLUE}\u2192 ${tool}${RESET} ${DIM}${input}${RESET}`);
7234
+ console.log(`${DIM2}[${ts2}]${RESET2} ${BLUE}\u2192 ${tool}${RESET2} ${DIM2}${input}${RESET2}`);
7141
7235
  return;
7142
7236
  }
7143
7237
  case "PostToolUse": {
7144
7238
  const tool = String(p.tool_name ?? p.toolName ?? p.tool ?? "?");
7145
7239
  const out = stringifyToolResponse(p.tool_response ?? p.toolResponse ?? p.outputPreview ?? p.output);
7146
- const ok = p.ok === false ? `${RED}\u2717${RESET}` : `${BLUE}\u2713${RESET}`;
7147
- console.log(`${DIM}[${ts2}]${RESET} ${ok} ${tool}${out ? " " + DIM + truncate(out, 200) + RESET : ""}`);
7240
+ const ok = p.ok === false ? `${RED}\u2717${RESET2}` : `${BLUE}\u2713${RESET2}`;
7241
+ console.log(`${DIM2}[${ts2}]${RESET2} ${ok} ${tool}${out ? " " + DIM2 + truncate(out, 200) + RESET2 : ""}`);
7148
7242
  return;
7149
7243
  }
7150
7244
  case "PostToolUseFailure": {
7151
7245
  const tool = String(p.tool_name ?? p.toolName ?? p.tool ?? "?");
7152
7246
  const err = stringifyToolResponse(p.error ?? p.message ?? p.tool_response);
7153
- console.log(`${DIM}[${ts2}]${RESET} ${RED}\u2717 ${tool}${RESET} ${RED}${truncate(err, 200)}${RESET}`);
7247
+ console.log(`${DIM2}[${ts2}]${RESET2} ${RED}\u2717 ${tool}${RESET2} ${RED}${truncate(err, 200)}${RESET2}`);
7154
7248
  return;
7155
7249
  }
7156
7250
  case "Stop":
7157
- console.log(`${DIM}[${ts2}] \u2014 turn end \u2014${RESET}`);
7251
+ console.log(`${DIM2}[${ts2}] \u2014 turn end \u2014${RESET2}`);
7158
7252
  return;
7159
7253
  case "SessionStart":
7160
- console.log(`${DIM}[${ts2}] \u25B8 session start${RESET}`);
7254
+ console.log(`${DIM2}[${ts2}] \u25B8 session start${RESET2}`);
7161
7255
  return;
7162
7256
  case "SessionEnd":
7163
- console.log(`${DIM}[${ts2}] \u25C2 session end${RESET}`);
7257
+ console.log(`${DIM2}[${ts2}] \u25C2 session end${RESET2}`);
7164
7258
  return;
7165
7259
  case "TaskCreated":
7166
7260
  case "SubagentStart":
@@ -7168,16 +7262,16 @@ function renderEvent(ev, myLogin) {
7168
7262
  case "TaskCompleted": {
7169
7263
  const which = ev.type;
7170
7264
  const desc = String(p.description ?? p.agentType ?? "");
7171
- console.log(`${DIM}[${ts2}] ${BLUE}\u21AA ${which}${RESET}${desc ? " " + desc : ""}`);
7265
+ console.log(`${DIM2}[${ts2}] ${BLUE}\u21AA ${which}${RESET2}${desc ? " " + desc : ""}`);
7172
7266
  return;
7173
7267
  }
7174
7268
  case "Notification": {
7175
7269
  const msg = String(p.message ?? p.text ?? "").trim();
7176
- console.log(`${DIM}[${ts2}]${RESET} ${BOLD}\u{1F514}${RESET} ${msg || JSON.stringify(p).slice(0, 200)}`);
7270
+ console.log(`${DIM2}[${ts2}]${RESET2} ${BOLD2}\u{1F514}${RESET2} ${msg || JSON.stringify(p).slice(0, 200)}`);
7177
7271
  return;
7178
7272
  }
7179
7273
  default:
7180
- console.log(`${DIM}[${ts2}]${RESET} ${BLUE}[${ev.type}]${RESET} ${previewPayload(p)}`);
7274
+ console.log(`${DIM2}[${ts2}]${RESET2} ${BLUE}[${ev.type}]${RESET2} ${previewPayload(p)}`);
7181
7275
  }
7182
7276
  }
7183
7277
  function stringifyToolResponse(v) {
@@ -7258,7 +7352,20 @@ async function resolveSessionId(idOrName) {
7258
7352
  err.code = "CLW_NO_ROUTING_MATCH";
7259
7353
  throw err;
7260
7354
  }
7261
- return candidates[0].id;
7355
+ try {
7356
+ const picked = await pickCandidate(idOrName, candidates);
7357
+ return picked.id;
7358
+ } catch (e) {
7359
+ if (e instanceof AmbiguousError) {
7360
+ const err = new Error(
7361
+ `ambiguous reference '${idOrName}' \u2014 multiple online sessions match. Re-run with a UUID or qualified form. Candidates:
7362
+ ` + e.candidates.map((c) => ` ${c.id} @${c.startedByLogin}/${(c.routingName ?? "").replace(/^@/, "")} ${c.cwd ?? ""}`).join("\n")
7363
+ );
7364
+ err.code = "CLW_AMBIGUOUS";
7365
+ throw err;
7366
+ }
7367
+ throw e;
7368
+ }
7262
7369
  }
7263
7370
  var sessionList = new Command("list").alias("ls").description("list sessions you can see").option("--connected", "only sessions whose channel WS is currently open").option("--all", "include archived sessions").action(async (opts) => {
7264
7371
  const qs = new URLSearchParams();
@@ -7677,7 +7784,7 @@ var webhookCmd = new Command("webhook").description("manage webhook subscription
7677
7784
 
7678
7785
  // src/index.ts
7679
7786
  var program2 = new Command();
7680
- program2.name("claw").description("clawborrator CLI \u2014 control your Claude Code sessions from the terminal").version("0.0.23");
7787
+ program2.name("claw").description("clawborrator CLI \u2014 control your Claude Code sessions from the terminal").version("0.0.25");
7681
7788
  program2.addCommand(loginCmd);
7682
7789
  program2.addCommand(logoutCmd);
7683
7790
  program2.addCommand(whoamiCmd);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clawborrator-cli",
3
- "version": "0.0.23",
3
+ "version": "0.0.25",
4
4
  "type": "module",
5
5
  "description": "claw — command-line client for clawborrator hub_v1. Manages PATs, channel tokens, sessions, cross-session routing, and webhooks; ships an inline TUI for live multi-operator session attach.",
6
6
  "license": "MIT",