@clawos-dev/clawd 0.2.364 → 0.2.366

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/cli.cjs CHANGED
@@ -14498,19 +14498,19 @@ var init_claude_history = __esm({
14498
14498
  const backups = snapshot?.trackedFileBackups;
14499
14499
  const anchorId = snapshot?.messageId;
14500
14500
  if (typeof anchorId !== "string" || !backups || typeof backups !== "object") continue;
14501
- const record = {};
14501
+ const record3 = {};
14502
14502
  for (const [filePath, raw] of Object.entries(backups)) {
14503
14503
  if (!raw || typeof raw !== "object") continue;
14504
14504
  const b2 = raw;
14505
14505
  const name = b2.backupFileName;
14506
14506
  const version2 = b2.version;
14507
14507
  if (typeof version2 !== "number") continue;
14508
- record[filePath] = {
14508
+ record3[filePath] = {
14509
14509
  backupFileName: typeof name === "string" ? name : null,
14510
14510
  version: version2
14511
14511
  };
14512
14512
  }
14513
- out.set(anchorId, record);
14513
+ out.set(anchorId, record3);
14514
14514
  }
14515
14515
  return out;
14516
14516
  }
@@ -41569,9 +41569,9 @@ var require_ZipFileWorker = __commonJS({
41569
41569
  this.currentFile = streamInfo["file"].name;
41570
41570
  var streamedContent = this.streamFiles && !streamInfo["file"].dir;
41571
41571
  if (streamedContent) {
41572
- var record = generateZipParts(streamInfo, streamedContent, false, this.currentSourceOffset, this.zipPlatform, this.encodeFileName);
41572
+ var record3 = generateZipParts(streamInfo, streamedContent, false, this.currentSourceOffset, this.zipPlatform, this.encodeFileName);
41573
41573
  this.push({
41574
- data: record.fileRecord,
41574
+ data: record3.fileRecord,
41575
41575
  meta: { percent: 0 }
41576
41576
  });
41577
41577
  } else {
@@ -41581,8 +41581,8 @@ var require_ZipFileWorker = __commonJS({
41581
41581
  ZipFileWorker.prototype.closedSource = function(streamInfo) {
41582
41582
  this.accumulate = false;
41583
41583
  var streamedContent = this.streamFiles && !streamInfo["file"].dir;
41584
- var record = generateZipParts(streamInfo, streamedContent, true, this.currentSourceOffset, this.zipPlatform, this.encodeFileName);
41585
- this.dirRecords.push(record.dirRecord);
41584
+ var record3 = generateZipParts(streamInfo, streamedContent, true, this.currentSourceOffset, this.zipPlatform, this.encodeFileName);
41585
+ this.dirRecords.push(record3.dirRecord);
41586
41586
  if (streamedContent) {
41587
41587
  this.push({
41588
41588
  data: generateDataDescriptors(streamInfo),
@@ -41590,7 +41590,7 @@ var require_ZipFileWorker = __commonJS({
41590
41590
  });
41591
41591
  } else {
41592
41592
  this.push({
41593
- data: record.fileRecord,
41593
+ data: record3.fileRecord,
41594
41594
  meta: { percent: 0 }
41595
41595
  });
41596
41596
  while (this.contentBuffer.length) {
@@ -43630,14 +43630,14 @@ var Batcher = class {
43630
43630
  timer = null;
43631
43631
  disposed = false;
43632
43632
  pendingSends = [];
43633
- enqueue(record) {
43633
+ enqueue(record3) {
43634
43634
  if (this.disposed) return;
43635
- const sz = approxSize(record);
43635
+ const sz = approxSize(record3);
43636
43636
  while (this.queue.length >= this.deps.bufferCap) {
43637
43637
  this.queue.shift();
43638
43638
  this.droppedSinceFlush++;
43639
43639
  }
43640
- this.queue.push(record);
43640
+ this.queue.push(record3);
43641
43641
  this.bytes += sz;
43642
43642
  if (!this.identityReady) return;
43643
43643
  this.maybeTrigger();
@@ -43699,8 +43699,8 @@ var Batcher = class {
43699
43699
  });
43700
43700
  }
43701
43701
  };
43702
- function approxSize(record) {
43703
- return (record.msg?.length ?? 0) + (record.meta_json?.length ?? 0) + 200;
43702
+ function approxSize(record3) {
43703
+ return (record3.msg?.length ?? 0) + (record3.meta_json?.length ?? 0) + 200;
43704
43704
  }
43705
43705
  var BACKOFF_MS = [1e3, 2e3, 4e3];
43706
43706
  async function sendBatch(deps, batch) {
@@ -43788,8 +43788,8 @@ function createLogClient(opts) {
43788
43788
  stats.dropped++;
43789
43789
  return;
43790
43790
  }
43791
- const record = buildRecord(input, identity, opts.source, homeDir, now);
43792
- batcher.enqueue(record);
43791
+ const record3 = buildRecord(input, identity, opts.source, homeDir, now);
43792
+ batcher.enqueue(record3);
43793
43793
  } catch {
43794
43794
  }
43795
43795
  },
@@ -44786,6 +44786,7 @@ function pushEventToBufferInPlace(next, event, deps) {
44786
44786
  if (newBuffer.length === 1) next.bufferStartSeq = seq;
44787
44787
  const isTurnEnd = withSeq.kind === "turn_end";
44788
44788
  const isUserText = withSeq.kind === "user_text";
44789
+ const isBackgroundEvent = withSeq.kind === "subagent_progress";
44789
44790
  if (isTurnEnd && next.turnOpen && isLateTurnEnd(withSeq, next.turnStartedAt, deps.now())) {
44790
44791
  return [emitSessionEvent(next.file.sessionId, withSeq)];
44791
44792
  }
@@ -44796,7 +44797,7 @@ function pushEventToBufferInPlace(next, event, deps) {
44796
44797
  }
44797
44798
  next.turnOpen = false;
44798
44799
  next.turnStartedAt = null;
44799
- } else if (!next.turnOpen) {
44800
+ } else if (!isBackgroundEvent && !next.turnOpen) {
44800
44801
  next.turnOpen = true;
44801
44802
  next.turnStartedAt = deps.now();
44802
44803
  }
@@ -49855,6 +49856,195 @@ function num(v2) {
49855
49856
  return typeof v2 === "number" ? v2 : void 0;
49856
49857
  }
49857
49858
 
49859
+ // src/tools/codex-subagent-tracker.ts
49860
+ var CodexSubagentTracker = class {
49861
+ agents = /* @__PURE__ */ new Map();
49862
+ handleParentNotification(method, params) {
49863
+ if (method !== "item/started" && method !== "item/completed") return [];
49864
+ const item = record(record(params)?.item);
49865
+ if (!item) return [];
49866
+ if (item.type === "subAgentActivity") return this.handleActivity(item);
49867
+ if (item.type === "collabAgentToolCall") return this.handleCollabToolCall(item);
49868
+ return [];
49869
+ }
49870
+ handleChildNotification(threadId, method, params) {
49871
+ const state = this.state(threadId);
49872
+ const p2 = record(params);
49873
+ if (method === "item/started") {
49874
+ const itemType = stringValue(record(p2?.item)?.type);
49875
+ return this.updateStatus(state, "running", itemType ? { lastToolName: itemType } : {});
49876
+ }
49877
+ if (method === "turn/completed") {
49878
+ const turnStatus = stringValue(record(p2?.turn)?.status);
49879
+ if (turnStatus === "completed") return this.updateStatus(state, "completed");
49880
+ if (turnStatus === "failed" || turnStatus === "interrupted") {
49881
+ return this.updateStatus(state, "failed");
49882
+ }
49883
+ return [];
49884
+ }
49885
+ if (method === "error") {
49886
+ if (p2?.willRetry === true) return [];
49887
+ return this.updateStatus(state, "failed");
49888
+ }
49889
+ if (method === "thread/status/changed") {
49890
+ const rawStatus = p2?.status;
49891
+ const statusType = stringValue(record(rawStatus)?.type) ?? stringValue(rawStatus);
49892
+ if (statusType === "systemError") return this.updateStatus(state, "failed");
49893
+ }
49894
+ return [];
49895
+ }
49896
+ handleActivity(item) {
49897
+ const agentId = stringValue(item.agentThreadId);
49898
+ if (!agentId) return [];
49899
+ const state = this.state(agentId);
49900
+ const agentPath = stringValue(item.agentPath);
49901
+ if (agentPath) {
49902
+ state.agentPath = agentPath;
49903
+ state.description = agentPathLabel(agentPath);
49904
+ }
49905
+ const events = [];
49906
+ const toolUseId = stringValue(item.id);
49907
+ const kind = stringValue(item.kind);
49908
+ if (toolUseId && (kind === "started" || kind === "interacted" || kind === "interrupted")) {
49909
+ events.push(...this.bind(state, toolUseId));
49910
+ }
49911
+ if (kind === "interacted") events.push(...this.updateStatus(state, "running"));
49912
+ if (kind === "interrupted") events.push(...this.updateStatus(state, "failed"));
49913
+ return events;
49914
+ }
49915
+ handleCollabToolCall(item) {
49916
+ const prompt = stringValue(item.prompt);
49917
+ const agentStates = record(item.agentsStates);
49918
+ const agentIds = /* @__PURE__ */ new Set();
49919
+ if (Array.isArray(item.receiverThreadIds)) {
49920
+ for (const value of item.receiverThreadIds) {
49921
+ const id = stringValue(value);
49922
+ if (id) agentIds.add(id);
49923
+ }
49924
+ }
49925
+ if (agentStates) {
49926
+ for (const id of Object.keys(agentStates)) agentIds.add(id);
49927
+ }
49928
+ const events = [];
49929
+ for (const agentId of agentIds) {
49930
+ const state = this.state(agentId);
49931
+ const codexStatus = stringValue(record(agentStates?.[agentId])?.status);
49932
+ const status = collabStatus(codexStatus);
49933
+ if (status) {
49934
+ events.push(...this.updateStatus(state, status, prompt ? { prompt } : {}));
49935
+ } else if (!state.terminal && prompt) {
49936
+ state.prompt = prompt;
49937
+ }
49938
+ if (!codexStatus && item.status === "failed") {
49939
+ events.push(...this.updateStatus(state, "failed", prompt ? { prompt } : {}));
49940
+ }
49941
+ }
49942
+ return events;
49943
+ }
49944
+ state(agentId) {
49945
+ let state = this.agents.get(agentId);
49946
+ if (!state) {
49947
+ state = {
49948
+ agentId,
49949
+ toolCallEmitted: false,
49950
+ startedEmitted: false,
49951
+ terminalEmitted: false
49952
+ };
49953
+ this.agents.set(agentId, state);
49954
+ }
49955
+ return state;
49956
+ }
49957
+ bind(state, toolUseId) {
49958
+ if (!state.toolUseId) state.toolUseId = toolUseId;
49959
+ if (state.toolUseId !== toolUseId) return [];
49960
+ const pendingStatus = state.status;
49961
+ const events = [];
49962
+ if (!state.toolCallEmitted) {
49963
+ state.toolCallEmitted = true;
49964
+ const input = { agentId: state.agentId };
49965
+ if (state.description) input.description = state.description;
49966
+ if (state.agentPath) input.agentPath = state.agentPath;
49967
+ if (state.prompt) input.prompt = state.prompt;
49968
+ events.push({
49969
+ kind: "tool_call",
49970
+ toolUseId,
49971
+ tool: "Agent",
49972
+ toolKind: "codex",
49973
+ input
49974
+ });
49975
+ }
49976
+ events.push(...this.emitProgress(state, "started"));
49977
+ if (pendingStatus && pendingStatus !== "started") {
49978
+ events.push(...this.emitProgress(state, pendingStatus));
49979
+ } else if (!state.status) {
49980
+ state.status = "started";
49981
+ }
49982
+ return events;
49983
+ }
49984
+ updateStatus(state, status, patch = {}) {
49985
+ if (state.terminal) return [];
49986
+ if (patch.prompt) state.prompt = patch.prompt;
49987
+ if (patch.lastToolName) state.lastToolName = patch.lastToolName;
49988
+ if (status === "started") {
49989
+ if (!state.status) state.status = status;
49990
+ } else {
49991
+ state.status = status;
49992
+ }
49993
+ if (status === "completed" || status === "failed") state.terminal = status;
49994
+ return this.emitProgress(state, status);
49995
+ }
49996
+ emitProgress(state, status) {
49997
+ if (!state.toolUseId) return [];
49998
+ if (status === "started") {
49999
+ if (state.startedEmitted) return [];
50000
+ state.startedEmitted = true;
50001
+ } else if (status === "running") {
50002
+ const signature = JSON.stringify([state.description, state.lastToolName, state.prompt]);
50003
+ if (state.lastRunningSignature === signature) return [];
50004
+ state.lastRunningSignature = signature;
50005
+ } else {
50006
+ if (state.terminalEmitted) return [];
50007
+ state.terminalEmitted = true;
50008
+ }
50009
+ const event = {
50010
+ kind: "subagent_progress",
50011
+ toolUseId: state.toolUseId,
50012
+ agentId: state.agentId,
50013
+ status
50014
+ };
50015
+ if (state.description) event.description = state.description;
50016
+ if (state.prompt) event.prompt = state.prompt;
50017
+ if (status !== "started" && state.lastToolName) event.lastToolName = state.lastToolName;
50018
+ return [event];
50019
+ }
50020
+ };
50021
+ function notificationThreadId(method, params) {
50022
+ const p2 = record(params);
50023
+ const direct = stringValue(p2?.threadId);
50024
+ if (direct) return direct;
50025
+ if (method === "thread/started") return stringValue(record(p2?.thread)?.id);
50026
+ return void 0;
50027
+ }
50028
+ function collabStatus(value) {
50029
+ if (value === "pendingInit") return "started";
50030
+ if (value === "running") return "running";
50031
+ if (value === "completed") return "completed";
50032
+ if (value === "errored" || value === "interrupted" || value === "shutdown" || value === "notFound") {
50033
+ return "failed";
50034
+ }
50035
+ return void 0;
50036
+ }
50037
+ function agentPathLabel(agentPath) {
50038
+ const segments = agentPath.split("/").filter(Boolean);
50039
+ return segments[segments.length - 1];
50040
+ }
50041
+ function record(value) {
50042
+ return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
50043
+ }
50044
+ function stringValue(value) {
50045
+ return typeof value === "string" && value.length > 0 ? value : void 0;
50046
+ }
50047
+
49858
50048
  // src/tools/codex-app-server-params.ts
49859
50049
  function resolveApprovalPolicy(ctx) {
49860
50050
  if (ctx.personaMode === "owner" || ctx.personaMode === "guest") return "never";
@@ -50076,6 +50266,7 @@ function createCodexSession(ctx, sink, deps = {}) {
50076
50266
  let threadId = ctx.toolSessionId;
50077
50267
  let turnId;
50078
50268
  const approvalIds = /* @__PURE__ */ new Map();
50269
+ const subagents = new CodexSubagentTracker();
50079
50270
  const effort = ctx.effort;
50080
50271
  let exited = false;
50081
50272
  const finish = (code) => {
@@ -50085,11 +50276,26 @@ function createCodexSession(ctx, sink, deps = {}) {
50085
50276
  };
50086
50277
  const client = new CodexAppServerClient(proc, {
50087
50278
  onNotification: (method, params) => {
50088
- if (method === "turn/started") {
50279
+ const ownerThreadId = notificationThreadId(method, params);
50280
+ const route = threadId && ownerThreadId === threadId ? "foreground" : threadId && ownerThreadId ? "subagent" : !threadId && method === "thread/started" && ownerThreadId ? "foreground" : "ignored";
50281
+ const p2 = record2(params);
50282
+ const item = record2(p2?.item);
50283
+ deps.logger?.debug("codex notification routed", {
50284
+ method,
50285
+ rootThreadId: threadId,
50286
+ threadId: ownerThreadId,
50287
+ turnId: stringValue2(p2?.turnId) ?? stringValue2(record2(p2?.turn)?.id),
50288
+ itemType: stringValue2(item?.type),
50289
+ route
50290
+ });
50291
+ if (threadId !== void 0 && ownerThreadId === threadId && method === "turn/started") {
50089
50292
  const id = params?.turn?.id;
50090
50293
  if (id) turnId = id;
50091
50294
  }
50092
- const events = translateNotification(method, params);
50295
+ const events = route === "subagent" && ownerThreadId ? subagents.handleChildNotification(ownerThreadId, method, params) : route === "foreground" ? [
50296
+ ...subagents.handleParentNotification(method, params),
50297
+ ...translateNotification(method, params)
50298
+ ] : [];
50093
50299
  if (events.length) sink.pushEvents(events);
50094
50300
  },
50095
50301
  onServerRequest: (id, method, params) => {
@@ -50174,6 +50380,12 @@ function createCodexSession(ctx, sink, deps = {}) {
50174
50380
  }
50175
50381
  };
50176
50382
  }
50383
+ function record2(value) {
50384
+ return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
50385
+ }
50386
+ function stringValue2(value) {
50387
+ return typeof value === "string" && value.length > 0 ? value : void 0;
50388
+ }
50177
50389
 
50178
50390
  // src/tools/codex-app-server-query.ts
50179
50391
  var import_node_child_process5 = require("child_process");
@@ -50285,9 +50497,9 @@ var CODEX_CAPABILITIES_BASE = {
50285
50497
  tool: "codex",
50286
50498
  toolSessionIdLabel: "Codex Thread ID",
50287
50499
  permissionModes: CODEX_APPROVAL_PRESETS,
50288
- // codex 不支持这些 clawd 功能(rewind file-snapshot / 无子 agent / 无 TUI pty /
50289
- // 无 observe 推送 / 无文件分享 / fork 是 claude jsonl 专用);UI 据此 gate 入口。
50290
- features: { rewind: false, subagents: false, tui: false, observe: false, fileSharing: false, fork: false },
50500
+ // Codex 原生 child thread 已经映射到现有 Agent + history drawer;其余功能仍不支持
50501
+ //(rewindfile-snapshot / 无 TUI pty / 无 observe 推送 / 无文件分享 / fork 是 claude jsonl 专用)。
50502
+ features: { rewind: false, subagents: true, tui: false, observe: false, fileSharing: false, fork: false },
50291
50503
  configSchema: [
50292
50504
  {
50293
50505
  name: "model",
@@ -53753,6 +53965,34 @@ function str2(v2) {
53753
53965
  function num2(v2) {
53754
53966
  return typeof v2 === "number" && Number.isFinite(v2) ? v2 : void 0;
53755
53967
  }
53968
+ function nativeSubagentStart(item) {
53969
+ if (item.type !== "subAgentActivity" || item.kind !== "started") return void 0;
53970
+ const toolUseId = str2(item.id);
53971
+ const agentId = str2(item.agentThreadId);
53972
+ const agentPath = str2(item.agentPath);
53973
+ if (!toolUseId || !agentId || !agentPath) return void 0;
53974
+ const segments = agentPath.split("/").filter(Boolean);
53975
+ return {
53976
+ toolUseId,
53977
+ agentId,
53978
+ agentPath,
53979
+ description: segments[segments.length - 1] ?? agentId
53980
+ };
53981
+ }
53982
+ function threadItems(thread) {
53983
+ const turns = thread && Array.isArray(thread.turns) ? thread.turns : [];
53984
+ const items = [];
53985
+ for (const turn of turns) {
53986
+ const value = rec2(turn);
53987
+ if (value && Array.isArray(value.items)) items.push(...value.items);
53988
+ }
53989
+ return items;
53990
+ }
53991
+ function threadMessages(thread) {
53992
+ const messages = [];
53993
+ for (const item of threadItems(thread)) messages.push(...threadItemToHistoryMessages(item));
53994
+ return messages;
53995
+ }
53756
53996
  function userInputText(content) {
53757
53997
  if (!Array.isArray(content)) return "";
53758
53998
  return content.map((c) => {
@@ -53763,6 +54003,22 @@ function userInputText(content) {
53763
54003
  function threadItemToHistoryMessages(item) {
53764
54004
  const it = rec2(item);
53765
54005
  if (!it) return [];
54006
+ const subagent = nativeSubagentStart(it);
54007
+ if (subagent) {
54008
+ return [
54009
+ {
54010
+ kind: "tool_call",
54011
+ tool: "Agent",
54012
+ toolUseId: subagent.toolUseId,
54013
+ input: {
54014
+ agentId: subagent.agentId,
54015
+ description: subagent.description,
54016
+ agentPath: subagent.agentPath
54017
+ },
54018
+ raw: item
54019
+ }
54020
+ ];
54021
+ }
53766
54022
  switch (it.type) {
53767
54023
  case "userMessage": {
53768
54024
  const text = userInputText(it.content);
@@ -53846,33 +54102,41 @@ var CodexHistoryReader = class {
53846
54102
  return out;
53847
54103
  }
53848
54104
  async read(args) {
53849
- const res = rec2(
53850
- await queryCodexAppServer(
53851
- args.cwd,
53852
- "thread/read",
53853
- { threadId: args.toolSessionId, includeTurns: true },
53854
- this.deps
53855
- )
53856
- );
53857
- const thread = res && rec2(res.thread);
53858
- const turns = thread && Array.isArray(thread.turns) ? thread.turns : [];
53859
- const messages = [];
53860
- for (const turn of turns) {
53861
- const t = rec2(turn);
53862
- const items = t && Array.isArray(t.items) ? t.items : [];
53863
- for (const item of items) messages.push(...threadItemToHistoryMessages(item));
53864
- }
54105
+ const thread = await this.readThread(args.cwd, args.toolSessionId);
54106
+ const messages = threadMessages(thread);
53865
54107
  const total = messages.length;
53866
54108
  const limit = args.limit ?? total;
53867
54109
  const offset = typeof args.offset === "number" ? Math.min(Math.max(0, args.offset), total) : Math.max(0, total - limit);
53868
54110
  return { messages: messages.slice(offset, offset + limit), total, offset };
53869
54111
  }
53870
- // codex 无 sidechain 子 agent / file-history-snapshot → 全 stub 空(对齐 claude-history 同方法空返回)
53871
- async listSubagents() {
53872
- return [];
54112
+ async listSubagents(args) {
54113
+ const thread = await this.readThread(args.cwd, args.toolSessionId);
54114
+ const seen = /* @__PURE__ */ new Set();
54115
+ const subagents = [];
54116
+ for (const item of threadItems(thread)) {
54117
+ const value = rec2(item);
54118
+ const started = value && nativeSubagentStart(value);
54119
+ if (!started || seen.has(started.agentId)) continue;
54120
+ seen.add(started.agentId);
54121
+ subagents.push({
54122
+ subagentId: started.agentId,
54123
+ summary: started.description,
54124
+ // 列表只读 parent 一次,避免为每个 child 再开 app-server 做 N+1 查询。
54125
+ messageCount: 0
54126
+ });
54127
+ }
54128
+ return subagents;
53873
54129
  }
53874
- async readSubagent() {
53875
- return { messages: [] };
54130
+ async readSubagent(args) {
54131
+ const thread = await this.readThread(args.cwd, args.subagentId);
54132
+ const actualId = str2(thread.id);
54133
+ const parentThreadId = str2(thread.parentThreadId);
54134
+ if (actualId !== args.subagentId || parentThreadId !== args.toolSessionId) {
54135
+ throw new Error(
54136
+ `Codex subagent thread ${args.subagentId} does not belong to parent thread ${args.toolSessionId}`
54137
+ );
54138
+ }
54139
+ return { messages: threadMessages(thread) };
53876
54140
  }
53877
54141
  computeRewindDiff() {
53878
54142
  return { canRewind: false, files: [], totalInsertions: 0, totalDeletions: 0 };
@@ -53880,6 +54144,19 @@ var CodexHistoryReader = class {
53880
54144
  listRewindableUserMessageIds() {
53881
54145
  return [];
53882
54146
  }
54147
+ async readThread(cwd, threadId) {
54148
+ const res = rec2(
54149
+ await queryCodexAppServer(
54150
+ cwd,
54151
+ "thread/read",
54152
+ { threadId, includeTurns: true },
54153
+ this.deps
54154
+ )
54155
+ );
54156
+ const thread = res && rec2(res.thread);
54157
+ if (!thread) throw new Error(`Codex thread/read returned no thread for ${threadId}`);
54158
+ return thread;
54159
+ }
53883
54160
  };
53884
54161
 
53885
54162
  // src/tools/codex-skills.ts
@@ -55226,9 +55503,9 @@ var LocalWsServer = class {
55226
55503
  Promise.resolve(this.frameHandler(client, frame)).catch((err) => {
55227
55504
  const e = err;
55228
55505
  const requestId = typeof frame.requestId === "string" ? frame.requestId : void 0;
55229
- const record = this.clients.get(client.id);
55230
- if (!record) return;
55231
- this.safeSend(record.ws, {
55506
+ const record3 = this.clients.get(client.id);
55507
+ if (!record3) return;
55508
+ this.safeSend(record3.ws, {
55232
55509
  type: "error",
55233
55510
  requestId,
55234
55511
  code: e.code ?? "INTERNAL",
@@ -58016,9 +58293,9 @@ var OwnerIdentityStore = class {
58016
58293
  loginAt: typeof r.loginAt === "string" ? r.loginAt : (/* @__PURE__ */ new Date(0)).toISOString()
58017
58294
  };
58018
58295
  }
58019
- write(record) {
58296
+ write(record3) {
58020
58297
  import_node_fs44.default.mkdirSync(import_node_path49.default.dirname(this.file), { recursive: true });
58021
- import_node_fs44.default.writeFileSync(this.file, JSON.stringify(record, null, 2), { mode: 384 });
58298
+ import_node_fs44.default.writeFileSync(this.file, JSON.stringify(record3, null, 2), { mode: 384 });
58022
58299
  try {
58023
58300
  import_node_fs44.default.chmodSync(this.file, 384);
58024
58301
  } catch {
@@ -59465,18 +59742,22 @@ function buildHistoryHandlers(deps) {
59465
59742
  );
59466
59743
  }
59467
59744
  };
59745
+ const historyReaderForToolSession = (toolSessionId) => {
59746
+ const file = store.list().find((session) => session.toolSessionId === toolSessionId);
59747
+ return file ? getHistoryReader(file.tool ?? "claude") : history;
59748
+ };
59468
59749
  const subagents = async (frame, _client, ctx) => {
59469
59750
  const args = HistorySubagentsArgs.parse(frame);
59470
59751
  assertGuestPath(ctx, path64.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
59471
59752
  assertGuestOwnsToolSession(ctx, args.toolSessionId, "history:subagents");
59472
- const subs = await history.listSubagents(args);
59753
+ const subs = await historyReaderForToolSession(args.toolSessionId).listSubagents(args);
59473
59754
  return { response: { type: "history:subagents", subagents: subs } };
59474
59755
  };
59475
59756
  const subagentRead = async (frame, _client, ctx) => {
59476
59757
  const args = HistorySubagentReadArgs.parse(frame);
59477
59758
  assertGuestPath(ctx, path64.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
59478
59759
  assertGuestOwnsToolSession(ctx, args.toolSessionId, "history:subagent-read");
59479
- const res = await history.readSubagent(args);
59760
+ const res = await historyReaderForToolSession(args.toolSessionId).readSubagent(args);
59480
59761
  return { response: { type: "history:subagent-read", ...res } };
59481
59762
  };
59482
59763
  const recentDirs = async (_frame, _client, ctx) => {
@@ -60196,15 +60477,15 @@ function buildFeishuAuthHandlers(deps) {
60196
60477
  };
60197
60478
  };
60198
60479
  const getIdentity = async () => {
60199
- const record = deps.ownerIdentityStore.read();
60480
+ const record3 = deps.ownerIdentityStore.read();
60200
60481
  return {
60201
60482
  response: {
60202
60483
  type: "auth:getIdentity:ok",
60203
- identity: record ? record.identity : null,
60484
+ identity: record3 ? record3.identity : null,
60204
60485
  // 决策 #15:设备属性,与登录态无关——UI"分享我的 Hub 标识"用
60205
60486
  deviceId: deps.deviceId,
60206
60487
  // 过期时间戳(仅时间戳,token 本体永不出 ws)——UI 派生 过期/临期 提示
60207
- ttcTokenExpiresAt: record ? record.ttcTokenExpiresAt : null
60488
+ ttcTokenExpiresAt: record3 ? record3.ttcTokenExpiresAt : null
60208
60489
  }
60209
60490
  };
60210
60491
  };
@@ -60613,7 +60894,7 @@ function computeMethodAccess(args) {
60613
60894
  }
60614
60895
 
60615
60896
  // src/version.ts
60616
- var version = "0.2.364".length > 0 ? "0.2.364" : "dev";
60897
+ var version = "0.2.366".length > 0 ? "0.2.366" : "dev";
60617
60898
 
60618
60899
  // src/cli-probe/probe.ts
60619
60900
  var fs62 = __toESM(require("fs"), 1);
@@ -64631,13 +64912,13 @@ async function startDaemon(config) {
64631
64912
  };
64632
64913
  const reportDevice = async () => {
64633
64914
  if (!feishuActive) return;
64634
- const record = ownerIdentityStore.read();
64635
- if (!record) return;
64915
+ const record3 = ownerIdentityStore.read();
64916
+ if (!record3) return;
64636
64917
  try {
64637
64918
  await centralUpsertDevice({
64638
64919
  api: config.clawosApi ?? DEFAULT_CLAWOS_API,
64639
- ttcJwt: record.ttcToken,
64640
- provider: record.identity.provider,
64920
+ ttcJwt: record3.ttcToken,
64921
+ provider: record3.identity.provider,
64641
64922
  deviceId: authFile.deviceId,
64642
64923
  url: currentTunnelUrl ?? void 0,
64643
64924
  name: ownerDisplayName
@@ -64812,13 +65093,13 @@ async function startDaemon(config) {
64812
65093
  // 契约(ContactHandlerDeps.exchangeToken):null = 本机登录问题(未登录 / JWT 过期),
64813
65094
  // 其他失败原样抛给 handler——两种都会让握手硬失败,只是给对端的错误文案不同。
64814
65095
  exchangeToken: async (targetDeviceId) => {
64815
- const record = ownerIdentityStore.read();
64816
- if (!record) return null;
65096
+ const record3 = ownerIdentityStore.read();
65097
+ if (!record3) return null;
64817
65098
  try {
64818
65099
  const r = await centralExchange({
64819
65100
  api: config.clawosApi ?? DEFAULT_CLAWOS_API,
64820
- jwt: record.ttcToken,
64821
- provider: record.identity.provider,
65101
+ jwt: record3.ttcToken,
65102
+ provider: record3.identity.provider,
64822
65103
  deviceId: targetDeviceId,
64823
65104
  selfDeviceId: authFile.deviceId,
64824
65105
  // 换票在握手关键路径上(硬失败),对端 connect-remote RPC_TIMEOUT_MS=5s:
@@ -64873,27 +65154,27 @@ async function startDaemon(config) {
64873
65154
  feishuDevice: {
64874
65155
  store: contactStore,
64875
65156
  exchange: async (deviceId) => {
64876
- const record = ownerIdentityStore.read();
64877
- if (!record) {
65157
+ const record3 = ownerIdentityStore.read();
65158
+ if (!record3) {
64878
65159
  throw new ClawdError(ERROR_CODES.FEISHU_LOGIN_REQUIRED, "device:connect requires feishu login");
64879
65160
  }
64880
65161
  return centralExchange({
64881
65162
  api: config.clawosApi ?? DEFAULT_CLAWOS_API,
64882
- jwt: record.ttcToken,
64883
- provider: record.identity.provider,
65163
+ jwt: record3.ttcToken,
65164
+ provider: record3.identity.provider,
64884
65165
  deviceId,
64885
65166
  selfDeviceId: authFile.deviceId
64886
65167
  });
64887
65168
  },
64888
65169
  listDevices: async () => {
64889
- const record = ownerIdentityStore.read();
64890
- if (!record) {
65170
+ const record3 = ownerIdentityStore.read();
65171
+ if (!record3) {
64891
65172
  throw new ClawdError(ERROR_CODES.FEISHU_LOGIN_REQUIRED, "device:list requires feishu login");
64892
65173
  }
64893
65174
  return centralListDevices({
64894
65175
  api: config.clawosApi ?? DEFAULT_CLAWOS_API,
64895
- ttcJwt: record.ttcToken,
64896
- provider: record.identity.provider
65176
+ ttcJwt: record3.ttcToken,
65177
+ provider: record3.identity.provider
64897
65178
  });
64898
65179
  },
64899
65180
  connectRemote,