@clawos-dev/clawd 0.2.136-beta.287.97b0d33 → 0.2.136

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/cli.cjs +385 -314
  2. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -720,8 +720,8 @@ var init_parseUtil = __esm({
720
720
  init_errors2();
721
721
  init_en();
722
722
  makeIssue = (params) => {
723
- const { data, path: path58, errorMaps, issueData } = params;
724
- const fullPath = [...path58, ...issueData.path || []];
723
+ const { data, path: path59, errorMaps, issueData } = params;
724
+ const fullPath = [...path59, ...issueData.path || []];
725
725
  const fullIssue = {
726
726
  ...issueData,
727
727
  path: fullPath
@@ -1032,11 +1032,11 @@ var init_types = __esm({
1032
1032
  init_parseUtil();
1033
1033
  init_util();
1034
1034
  ParseInputLazyPath = class {
1035
- constructor(parent, value, path58, key) {
1035
+ constructor(parent, value, path59, key) {
1036
1036
  this._cachedPath = [];
1037
1037
  this.parent = parent;
1038
1038
  this.data = value;
1039
- this._path = path58;
1039
+ this._path = path59;
1040
1040
  this._key = key;
1041
1041
  }
1042
1042
  get path() {
@@ -6218,8 +6218,8 @@ var require_req = __commonJS({
6218
6218
  if (req.originalUrl) {
6219
6219
  _req.url = req.originalUrl;
6220
6220
  } else {
6221
- const path58 = req.path;
6222
- _req.url = typeof path58 === "string" ? path58 : req.url ? req.url.path || req.url : void 0;
6221
+ const path59 = req.path;
6222
+ _req.url = typeof path59 === "string" ? path59 : req.url ? req.url.path || req.url : void 0;
6223
6223
  }
6224
6224
  if (req.query) {
6225
6225
  _req.query = req.query;
@@ -6384,14 +6384,14 @@ var require_redact = __commonJS({
6384
6384
  }
6385
6385
  return obj;
6386
6386
  }
6387
- function parsePath(path58) {
6387
+ function parsePath(path59) {
6388
6388
  const parts = [];
6389
6389
  let current = "";
6390
6390
  let inBrackets = false;
6391
6391
  let inQuotes = false;
6392
6392
  let quoteChar = "";
6393
- for (let i = 0; i < path58.length; i++) {
6394
- const char = path58[i];
6393
+ for (let i = 0; i < path59.length; i++) {
6394
+ const char = path59[i];
6395
6395
  if (!inBrackets && char === ".") {
6396
6396
  if (current) {
6397
6397
  parts.push(current);
@@ -6522,10 +6522,10 @@ var require_redact = __commonJS({
6522
6522
  return current;
6523
6523
  }
6524
6524
  function redactPaths(obj, paths, censor, remove = false) {
6525
- for (const path58 of paths) {
6526
- const parts = parsePath(path58);
6525
+ for (const path59 of paths) {
6526
+ const parts = parsePath(path59);
6527
6527
  if (parts.includes("*")) {
6528
- redactWildcardPath(obj, parts, censor, path58, remove);
6528
+ redactWildcardPath(obj, parts, censor, path59, remove);
6529
6529
  } else {
6530
6530
  if (remove) {
6531
6531
  removeKey(obj, parts);
@@ -6610,8 +6610,8 @@ var require_redact = __commonJS({
6610
6610
  }
6611
6611
  } else {
6612
6612
  if (afterWildcard.includes("*")) {
6613
- const wrappedCensor = typeof censor === "function" ? (value, path58) => {
6614
- const fullPath = [...pathArray.slice(0, pathLength), ...path58];
6613
+ const wrappedCensor = typeof censor === "function" ? (value, path59) => {
6614
+ const fullPath = [...pathArray.slice(0, pathLength), ...path59];
6615
6615
  return censor(value, fullPath);
6616
6616
  } : censor;
6617
6617
  redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
@@ -6646,8 +6646,8 @@ var require_redact = __commonJS({
6646
6646
  return null;
6647
6647
  }
6648
6648
  const pathStructure = /* @__PURE__ */ new Map();
6649
- for (const path58 of pathsToClone) {
6650
- const parts = parsePath(path58);
6649
+ for (const path59 of pathsToClone) {
6650
+ const parts = parsePath(path59);
6651
6651
  let current = pathStructure;
6652
6652
  for (let i = 0; i < parts.length; i++) {
6653
6653
  const part = parts[i];
@@ -6699,24 +6699,24 @@ var require_redact = __commonJS({
6699
6699
  }
6700
6700
  return cloneSelectively(obj, pathStructure);
6701
6701
  }
6702
- function validatePath(path58) {
6703
- if (typeof path58 !== "string") {
6702
+ function validatePath(path59) {
6703
+ if (typeof path59 !== "string") {
6704
6704
  throw new Error("Paths must be (non-empty) strings");
6705
6705
  }
6706
- if (path58 === "") {
6706
+ if (path59 === "") {
6707
6707
  throw new Error("Invalid redaction path ()");
6708
6708
  }
6709
- if (path58.includes("..")) {
6710
- throw new Error(`Invalid redaction path (${path58})`);
6709
+ if (path59.includes("..")) {
6710
+ throw new Error(`Invalid redaction path (${path59})`);
6711
6711
  }
6712
- if (path58.includes(",")) {
6713
- throw new Error(`Invalid redaction path (${path58})`);
6712
+ if (path59.includes(",")) {
6713
+ throw new Error(`Invalid redaction path (${path59})`);
6714
6714
  }
6715
6715
  let bracketCount = 0;
6716
6716
  let inQuotes = false;
6717
6717
  let quoteChar = "";
6718
- for (let i = 0; i < path58.length; i++) {
6719
- const char = path58[i];
6718
+ for (let i = 0; i < path59.length; i++) {
6719
+ const char = path59[i];
6720
6720
  if ((char === '"' || char === "'") && bracketCount > 0) {
6721
6721
  if (!inQuotes) {
6722
6722
  inQuotes = true;
@@ -6730,20 +6730,20 @@ var require_redact = __commonJS({
6730
6730
  } else if (char === "]" && !inQuotes) {
6731
6731
  bracketCount--;
6732
6732
  if (bracketCount < 0) {
6733
- throw new Error(`Invalid redaction path (${path58})`);
6733
+ throw new Error(`Invalid redaction path (${path59})`);
6734
6734
  }
6735
6735
  }
6736
6736
  }
6737
6737
  if (bracketCount !== 0) {
6738
- throw new Error(`Invalid redaction path (${path58})`);
6738
+ throw new Error(`Invalid redaction path (${path59})`);
6739
6739
  }
6740
6740
  }
6741
6741
  function validatePaths(paths) {
6742
6742
  if (!Array.isArray(paths)) {
6743
6743
  throw new TypeError("paths must be an array");
6744
6744
  }
6745
- for (const path58 of paths) {
6746
- validatePath(path58);
6745
+ for (const path59 of paths) {
6746
+ validatePath(path59);
6747
6747
  }
6748
6748
  }
6749
6749
  function slowRedact(options = {}) {
@@ -6911,8 +6911,8 @@ var require_redaction = __commonJS({
6911
6911
  if (shape[k2] === null) {
6912
6912
  o[k2] = (value) => topCensor(value, [k2]);
6913
6913
  } else {
6914
- const wrappedCensor = typeof censor === "function" ? (value, path58) => {
6915
- return censor(value, [k2, ...path58]);
6914
+ const wrappedCensor = typeof censor === "function" ? (value, path59) => {
6915
+ return censor(value, [k2, ...path59]);
6916
6916
  } : censor;
6917
6917
  o[k2] = Redact({
6918
6918
  paths: shape[k2],
@@ -7133,7 +7133,7 @@ var require_sonic_boom = __commonJS({
7133
7133
  var fs51 = require("fs");
7134
7134
  var EventEmitter3 = require("events");
7135
7135
  var inherits = require("util").inherits;
7136
- var path58 = require("path");
7136
+ var path59 = require("path");
7137
7137
  var sleep = require_atomic_sleep();
7138
7138
  var assert = require("assert");
7139
7139
  var BUSY_WRITE_TIMEOUT = 100;
@@ -7187,7 +7187,7 @@ var require_sonic_boom = __commonJS({
7187
7187
  const mode = sonic.mode;
7188
7188
  if (sonic.sync) {
7189
7189
  try {
7190
- if (sonic.mkdir) fs51.mkdirSync(path58.dirname(file), { recursive: true });
7190
+ if (sonic.mkdir) fs51.mkdirSync(path59.dirname(file), { recursive: true });
7191
7191
  const fd = fs51.openSync(file, flags, mode);
7192
7192
  fileOpened(null, fd);
7193
7193
  } catch (err) {
@@ -7195,7 +7195,7 @@ var require_sonic_boom = __commonJS({
7195
7195
  throw err;
7196
7196
  }
7197
7197
  } else if (sonic.mkdir) {
7198
- fs51.mkdir(path58.dirname(file), { recursive: true }, (err) => {
7198
+ fs51.mkdir(path59.dirname(file), { recursive: true }, (err) => {
7199
7199
  if (err) return fileOpened(err);
7200
7200
  fs51.open(file, flags, mode, fileOpened);
7201
7201
  });
@@ -10055,7 +10055,7 @@ var require_multistream = __commonJS({
10055
10055
  var require_pino = __commonJS({
10056
10056
  "../node_modules/.pnpm/pino@9.14.0/node_modules/pino/pino.js"(exports2, module2) {
10057
10057
  "use strict";
10058
- var os21 = require("os");
10058
+ var os22 = require("os");
10059
10059
  var stdSerializers = require_pino_std_serializers();
10060
10060
  var caller = require_caller();
10061
10061
  var redaction = require_redaction();
@@ -10102,7 +10102,7 @@ var require_pino = __commonJS({
10102
10102
  } = symbols;
10103
10103
  var { epochTime, nullTime } = time;
10104
10104
  var { pid } = process;
10105
- var hostname = os21.hostname();
10105
+ var hostname = os22.hostname();
10106
10106
  var defaultErrorSerializer = stdSerializers.err;
10107
10107
  var defaultOptions = {
10108
10108
  level: "info",
@@ -10826,11 +10826,11 @@ var init_lib = __esm({
10826
10826
  }
10827
10827
  }
10828
10828
  },
10829
- addToPath: function addToPath(path58, added, removed, oldPosInc, options) {
10830
- var last = path58.lastComponent;
10829
+ addToPath: function addToPath(path59, added, removed, oldPosInc, options) {
10830
+ var last = path59.lastComponent;
10831
10831
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
10832
10832
  return {
10833
- oldPos: path58.oldPos + oldPosInc,
10833
+ oldPos: path59.oldPos + oldPosInc,
10834
10834
  lastComponent: {
10835
10835
  count: last.count + 1,
10836
10836
  added,
@@ -10840,7 +10840,7 @@ var init_lib = __esm({
10840
10840
  };
10841
10841
  } else {
10842
10842
  return {
10843
- oldPos: path58.oldPos + oldPosInc,
10843
+ oldPos: path59.oldPos + oldPosInc,
10844
10844
  lastComponent: {
10845
10845
  count: 1,
10846
10846
  added,
@@ -11286,10 +11286,10 @@ function attachmentToHistoryMessage(o, ts) {
11286
11286
  const memories = raw.map((m2) => {
11287
11287
  if (!m2 || typeof m2 !== "object") return null;
11288
11288
  const rec3 = m2;
11289
- const path58 = typeof rec3.path === "string" ? rec3.path : null;
11289
+ const path59 = typeof rec3.path === "string" ? rec3.path : null;
11290
11290
  const content = typeof rec3.content === "string" ? rec3.content : null;
11291
- if (!path58 || content == null) return null;
11292
- const entry = { path: path58, content };
11291
+ if (!path59 || content == null) return null;
11292
+ const entry = { path: path59, content };
11293
11293
  if (typeof rec3.mtimeMs === "number") entry.mtimeMs = rec3.mtimeMs;
11294
11294
  return entry;
11295
11295
  }).filter((m2) => m2 !== null);
@@ -11754,6 +11754,12 @@ var init_claude_history = __esm({
11754
11754
  });
11755
11755
 
11756
11756
  // src/tools/claude.ts
11757
+ function macOSDesktopCandidates(home) {
11758
+ return [
11759
+ import_node_path9.default.join(home, "Applications", "Claude.app", "Contents", "Resources", "app.asar.unpacked", "node_modules", "@anthropic-ai", "claude-code", "cli.js"),
11760
+ "/Applications/Claude.app/Contents/Resources/app.asar.unpacked/node_modules/@anthropic-ai/claude-code/cli.js"
11761
+ ];
11762
+ }
11757
11763
  function probeViaWhich() {
11758
11764
  try {
11759
11765
  const out = (0, import_node_child_process2.execFileSync)("which", ["claude"], { encoding: "utf8" }).trim();
@@ -11762,12 +11768,19 @@ function probeViaWhich() {
11762
11768
  }
11763
11769
  return null;
11764
11770
  }
11765
- async function probeClaude(env = process.env) {
11771
+ async function probeClaude(env = process.env, home = import_node_os5.default.homedir()) {
11766
11772
  if (env.CLAUDE_BIN && import_node_fs9.default.existsSync(env.CLAUDE_BIN)) {
11767
11773
  return { available: true, path: env.CLAUDE_BIN };
11768
11774
  }
11769
11775
  const w2 = probeViaWhich();
11770
11776
  if (w2) return { available: true, path: w2 };
11777
+ if (process.platform === "darwin") {
11778
+ for (const candidate of macOSDesktopCandidates(home)) {
11779
+ if (import_node_fs9.default.existsSync(candidate)) {
11780
+ return { available: true, path: candidate };
11781
+ }
11782
+ }
11783
+ }
11771
11784
  return { available: false };
11772
11785
  }
11773
11786
  function buildSpawnArgs(ctx) {
@@ -12088,10 +12101,10 @@ function parseAttachment(obj) {
12088
12101
  const memories = raw.map((m2) => {
12089
12102
  if (!m2 || typeof m2 !== "object") return null;
12090
12103
  const rec3 = m2;
12091
- const path58 = typeof rec3.path === "string" ? rec3.path : null;
12104
+ const path59 = typeof rec3.path === "string" ? rec3.path : null;
12092
12105
  const content = typeof rec3.content === "string" ? rec3.content : null;
12093
- if (!path58 || content == null) return null;
12094
- const out = { path: path58, content };
12106
+ if (!path59 || content == null) return null;
12107
+ const out = { path: path59, content };
12095
12108
  if (typeof rec3.mtimeMs === "number") out.mtimeMs = rec3.mtimeMs;
12096
12109
  return out;
12097
12110
  }).filter((m2) => m2 !== null);
@@ -12195,13 +12208,15 @@ function encodeClaudeStdin(text) {
12195
12208
  };
12196
12209
  return JSON.stringify(frame) + "\n";
12197
12210
  }
12198
- var import_node_child_process, import_node_child_process2, import_node_fs9, ATTACHMENT_SILENT_SUBTYPES2, unknownTypeHandler, ATTACHMENT_RE, IMAGE_EXT_MIME, CLAUDE_MODELS, CLAUDE_PERMISSION_MODES, CLAUDE_CAPABILITIES, ClaudeAdapter;
12211
+ var import_node_child_process, import_node_child_process2, import_node_fs9, import_node_os5, import_node_path9, ATTACHMENT_SILENT_SUBTYPES2, unknownTypeHandler, ATTACHMENT_RE, IMAGE_EXT_MIME, CLAUDE_MODELS, CLAUDE_PERMISSION_MODES, CLAUDE_CAPABILITIES, ClaudeAdapter;
12199
12212
  var init_claude = __esm({
12200
12213
  "src/tools/claude.ts"() {
12201
12214
  "use strict";
12202
12215
  import_node_child_process = require("child_process");
12203
12216
  import_node_child_process2 = require("child_process");
12204
12217
  import_node_fs9 = __toESM(require("fs"), 1);
12218
+ import_node_os5 = __toESM(require("os"), 1);
12219
+ import_node_path9 = __toESM(require("path"), 1);
12205
12220
  init_protocol();
12206
12221
  init_claude_history();
12207
12222
  init_tool_result_extra();
@@ -23878,8 +23893,8 @@ var require_utils = __commonJS({
23878
23893
  var result = transform[inputType][outputType](input);
23879
23894
  return result;
23880
23895
  };
23881
- exports2.resolve = function(path58) {
23882
- var parts = path58.split("/");
23896
+ exports2.resolve = function(path59) {
23897
+ var parts = path59.split("/");
23883
23898
  var result = [];
23884
23899
  for (var index = 0; index < parts.length; index++) {
23885
23900
  var part = parts[index];
@@ -29732,18 +29747,18 @@ var require_object = __commonJS({
29732
29747
  var object = new ZipObject(name, zipObjectContent, o);
29733
29748
  this.files[name] = object;
29734
29749
  };
29735
- var parentFolder = function(path58) {
29736
- if (path58.slice(-1) === "/") {
29737
- path58 = path58.substring(0, path58.length - 1);
29750
+ var parentFolder = function(path59) {
29751
+ if (path59.slice(-1) === "/") {
29752
+ path59 = path59.substring(0, path59.length - 1);
29738
29753
  }
29739
- var lastSlash = path58.lastIndexOf("/");
29740
- return lastSlash > 0 ? path58.substring(0, lastSlash) : "";
29754
+ var lastSlash = path59.lastIndexOf("/");
29755
+ return lastSlash > 0 ? path59.substring(0, lastSlash) : "";
29741
29756
  };
29742
- var forceTrailingSlash = function(path58) {
29743
- if (path58.slice(-1) !== "/") {
29744
- path58 += "/";
29757
+ var forceTrailingSlash = function(path59) {
29758
+ if (path59.slice(-1) !== "/") {
29759
+ path59 += "/";
29745
29760
  }
29746
- return path58;
29761
+ return path59;
29747
29762
  };
29748
29763
  var folderAdd = function(name, createFolders) {
29749
29764
  createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
@@ -30745,7 +30760,7 @@ var require_lib3 = __commonJS({
30745
30760
  // src/run-case/recorder.ts
30746
30761
  function startRunCaseRecorder(opts) {
30747
30762
  const now = opts.now ?? Date.now;
30748
- const dir = import_node_path46.default.dirname(opts.recordPath);
30763
+ const dir = import_node_path47.default.dirname(opts.recordPath);
30749
30764
  let stream = null;
30750
30765
  let closing = false;
30751
30766
  let closedSettled = false;
@@ -30785,12 +30800,12 @@ function startRunCaseRecorder(opts) {
30785
30800
  };
30786
30801
  return { tap, close, closed };
30787
30802
  }
30788
- var import_node_fs34, import_node_path46;
30803
+ var import_node_fs34, import_node_path47;
30789
30804
  var init_recorder = __esm({
30790
30805
  "src/run-case/recorder.ts"() {
30791
30806
  "use strict";
30792
30807
  import_node_fs34 = __toESM(require("fs"), 1);
30793
- import_node_path46 = __toESM(require("path"), 1);
30808
+ import_node_path47 = __toESM(require("path"), 1);
30794
30809
  }
30795
30810
  });
30796
30811
 
@@ -30833,7 +30848,7 @@ var init_wire = __esm({
30833
30848
  // src/run-case/controller.ts
30834
30849
  async function runController(opts) {
30835
30850
  const now = opts.now ?? Date.now;
30836
- const cwd = opts.cwd ?? (0, import_node_fs35.mkdtempSync)(import_node_path47.default.join(import_node_os19.default.tmpdir(), "clawd-runcase-"));
30851
+ const cwd = opts.cwd ?? (0, import_node_fs35.mkdtempSync)(import_node_path48.default.join(import_node_os20.default.tmpdir(), "clawd-runcase-"));
30837
30852
  const ownsCwd = opts.cwd === void 0;
30838
30853
  const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
30839
30854
  const spawnCtx = { cwd };
@@ -31000,13 +31015,13 @@ async function runController(opts) {
31000
31015
  }
31001
31016
  return exitCode ?? 0;
31002
31017
  }
31003
- var import_node_fs35, import_node_os19, import_node_path47;
31018
+ var import_node_fs35, import_node_os20, import_node_path48;
31004
31019
  var init_controller = __esm({
31005
31020
  "src/run-case/controller.ts"() {
31006
31021
  "use strict";
31007
31022
  import_node_fs35 = require("fs");
31008
- import_node_os19 = __toESM(require("os"), 1);
31009
- import_node_path47 = __toESM(require("path"), 1);
31023
+ import_node_os20 = __toESM(require("os"), 1);
31024
+ import_node_path48 = __toESM(require("path"), 1);
31010
31025
  init_claude();
31011
31026
  init_stdout_splitter();
31012
31027
  init_permission_stdio();
@@ -31241,7 +31256,7 @@ Env (advanced):
31241
31256
  `;
31242
31257
 
31243
31258
  // src/index.ts
31244
- var import_node_path45 = __toESM(require("path"), 1);
31259
+ var import_node_path46 = __toESM(require("path"), 1);
31245
31260
  var import_node_fs33 = __toESM(require("fs"), 1);
31246
31261
 
31247
31262
  // src/logger.ts
@@ -32586,7 +32601,7 @@ var SessionRunner = class {
32586
32601
  this.input({ kind: "inject-events", events });
32587
32602
  }
32588
32603
  // session:interrupt 的 SDK 通道分流:codex → AgentSession.interrupt();claude → control_request('interrupt')。
32589
- // TUI(pty) 路径在 manager.interrupt() 里先走 stop() SIGKILL,不进这里。
32604
+ // TUI(pty) 路径在 manager.dispatchInterrupt 里先于此处理,不进这里。
32590
32605
  async interrupt() {
32591
32606
  if (this.session) {
32592
32607
  this.session.interrupt();
@@ -33064,6 +33079,11 @@ var SessionManager = class {
33064
33079
  // manager.resizePty 用此映射把 UI 的 session:pty:resize 同步到 surface 内部 buffer,
33065
33080
  // 保证 snapshot serialize 时 cursor positioning 与 UI xterm 实际尺寸一致。
33066
33081
  surfacesByToolSid = /* @__PURE__ */ new Map();
33082
+ // TUI 模式:sessionId → UI 最近一次上报的 xterm 尺寸。resizePty 入口无条件记录(含 pty
33083
+ // 尚未 spawn / runner 尚未创建的早到 resize),registerPty / registerSurface 时回放——
33084
+ // 修「mount resize 早于 lazy spawn 被丢」与「respawn 回到 120×40 后无人补发」的尺寸错配。
33085
+ // 键用 sessionId 而非 toolSessionId:/clear 会 reassign tsid,sessionId 跨 respawn 稳定
33086
+ lastUiSizeBySessionId = /* @__PURE__ */ new Map();
33067
33087
  // 仅 mode='tui' 需要:index.ts 装配阶段在 observer 构造后注入。
33068
33088
  // observer.onEvent 要回灌 manager.feedObserverEvents,所以 observer 必须晚于 manager
33069
33089
  // 构造;反过来 manager 又要在 mode='tui' 下 spawn session 时 attach observer。setter 解循环
@@ -33600,6 +33620,7 @@ var SessionManager = class {
33600
33620
  });
33601
33621
  this.runners.delete(args.sessionId);
33602
33622
  this.realUuidBySynth.delete(args.sessionId);
33623
+ this.lastUiSizeBySessionId.delete(args.sessionId);
33603
33624
  return { response: { sessionId: args.sessionId }, broadcast };
33604
33625
  }
33605
33626
  this.deleteOwned(args.sessionId);
@@ -33657,12 +33678,50 @@ var SessionManager = class {
33657
33678
  return this.stop({ sessionId: args.sessionId });
33658
33679
  }
33659
33680
  try {
33660
- await runner.interrupt();
33681
+ await this.dispatchInterrupt(runner);
33661
33682
  } catch (err) {
33662
33683
  throw new ClawdError(ERROR_CODES.INTERNAL, err.message);
33663
33684
  }
33664
33685
  return { response: { ok: true }, broadcast: [] };
33665
33686
  }
33687
+ // 同时被 interrupt / cancelQuestion 调用:按模式选 interrupt 通道。TUI 优先 pty,
33688
+ // 否则 fallback 到 SDK 的 control_request(包括 mode='tui' 但 pty 未 register 的边角场景)。
33689
+ async dispatchInterrupt(runner) {
33690
+ const sid = runner.getState().file.sessionId;
33691
+ const tsid = runner.getState().file.toolSessionId;
33692
+ const pty = tsid ? this.ptyTransports.get(tsid) : void 0;
33693
+ const stateBefore = runner.getState();
33694
+ this.deps.logger?.info("[BUG-HUNT-INTERRUPT] dispatchInterrupt enter", {
33695
+ sessionId: sid,
33696
+ tsid,
33697
+ ptyHit: Boolean(pty),
33698
+ mode: this.deps.mode,
33699
+ turnOpenBefore: stateBefore.turnOpen,
33700
+ procAlive: stateBefore.procAlive,
33701
+ bufferLen: stateBefore.buffer.length
33702
+ });
33703
+ if (pty) {
33704
+ pty.write("\x1B");
33705
+ this.deps.logger?.info("[BUG-HUNT-INTERRUPT] pty.write ESC done", { sessionId: sid });
33706
+ runner.input({ kind: "inject-events", events: [{ kind: "turn_end" }] });
33707
+ const stateAfter = runner.getState();
33708
+ const lastEvent = stateAfter.buffer[stateAfter.buffer.length - 1];
33709
+ this.deps.logger?.info("[BUG-HUNT-INTERRUPT] after inject turn_end", {
33710
+ sessionId: sid,
33711
+ turnOpenAfter: stateAfter.turnOpen,
33712
+ bufferLen: stateAfter.buffer.length,
33713
+ lastEventKind: lastEvent?.event?.kind,
33714
+ lastEventSeq: lastEvent?.seq
33715
+ });
33716
+ return;
33717
+ }
33718
+ this.deps.logger?.warn("[BUG-HUNT-INTERRUPT] SDK fallback path (pty not registered)", {
33719
+ sessionId: sid,
33720
+ tsid,
33721
+ mode: this.deps.mode
33722
+ });
33723
+ await runner.interrupt();
33724
+ }
33666
33725
  // 批量版本:UI 打开 session 时一次性拿到"磁盘和快照有差异"的 user message id 集合,
33667
33726
  // 用来在消息流里精准控制 rewind 按钮的显示。session 没 toolSessionId 时返回空
33668
33727
  rewindableMessageIds(args) {
@@ -34077,6 +34136,7 @@ var SessionManager = class {
34077
34136
  });
34078
34137
  this.runners.delete(args.sessionId);
34079
34138
  this.realUuidBySynth.delete(args.sessionId);
34139
+ this.lastUiSizeBySessionId.delete(args.sessionId);
34080
34140
  return { response: { sessionId: args.sessionId }, broadcast };
34081
34141
  }
34082
34142
  this.storeFor(args.scope).delete(args.sessionId);
@@ -34207,7 +34267,7 @@ var SessionManager = class {
34207
34267
  runner.input({ kind: "cancel-question", toolUseId: args.toolUseId });
34208
34268
  });
34209
34269
  if (runner.getState().procAlive) {
34210
- void runner.interrupt().catch(() => {
34270
+ void this.dispatchInterrupt(runner).catch(() => {
34211
34271
  });
34212
34272
  }
34213
34273
  return { response: { ok: true }, broadcast };
@@ -34242,6 +34302,14 @@ var SessionManager = class {
34242
34302
  /** ClaudeTuiAdapter.spawn 后调用,让 manager 持有 pty handle 供 handler input/resize 路由 */
34243
34303
  registerPty(toolSessionId, pty) {
34244
34304
  this.ptyTransports.set(toolSessionId, pty);
34305
+ const sid = this.sessionIdByToolSid(toolSessionId);
34306
+ const size = sid ? this.lastUiSizeBySessionId.get(sid) : void 0;
34307
+ if (size) {
34308
+ try {
34309
+ pty.resize(size.cols, size.rows);
34310
+ } catch {
34311
+ }
34312
+ }
34245
34313
  }
34246
34314
  /** spawn 进程 exit 时调用,清理映射防止后续 input 写到已死 pty + 释放 replay 闭包 */
34247
34315
  unregisterPty(toolSessionId) {
@@ -34331,6 +34399,9 @@ var SessionManager = class {
34331
34399
  /** ClaudeTuiAdapter spawn 时注册 surface ref;同一 tsid 重 spawn 会覆盖 */
34332
34400
  registerSurface(toolSessionId, surface) {
34333
34401
  this.surfacesByToolSid.set(toolSessionId, surface);
34402
+ const sid = this.sessionIdByToolSid(toolSessionId);
34403
+ const size = sid ? this.lastUiSizeBySessionId.get(sid) : void 0;
34404
+ if (size) surface.resize(size.cols, size.rows);
34334
34405
  }
34335
34406
  /** spawn 进程 exit 时清理 */
34336
34407
  unregisterSurface(toolSessionId) {
@@ -34343,6 +34414,7 @@ var SessionManager = class {
34343
34414
  * 找不到 runner / toolSessionId / pty 任一缺失 → 返 false,handler 静默给 UI 报 ok=false 不抛错。
34344
34415
  */
34345
34416
  resizePty(sessionId, cols, rows) {
34417
+ this.lastUiSizeBySessionId.set(sessionId, { cols, rows });
34346
34418
  const runner = this.runners.get(sessionId);
34347
34419
  if (!runner) return false;
34348
34420
  const tsid = runner.getState().file.toolSessionId;
@@ -35516,8 +35588,8 @@ function turnStartInput(text) {
35516
35588
  const items = [];
35517
35589
  let leftover = text;
35518
35590
  for (const m2 of text.matchAll(SKILL_RE)) {
35519
- const [marker, name, path58] = m2;
35520
- items.push({ type: "skill", name, path: path58 });
35591
+ const [marker, name, path59] = m2;
35592
+ items.push({ type: "skill", name, path: path59 });
35521
35593
  leftover = leftover.replace(marker, "");
35522
35594
  }
35523
35595
  for (const m2 of text.matchAll(ATTACHMENT_RE2)) {
@@ -35576,7 +35648,6 @@ function createCodexSession(ctx, sink, deps = {}) {
35576
35648
  ]);
35577
35649
  return;
35578
35650
  }
35579
- deps.logger?.warn("codex unknown server-request auto-cancelled", { method });
35580
35651
  client.respond(id, "cancel");
35581
35652
  },
35582
35653
  onClose: () => finish(proc.exitCode)
@@ -35750,8 +35821,8 @@ var CodexAdapter = class {
35750
35821
 
35751
35822
  // src/tools/claude-tui.ts
35752
35823
  var import_node_fs11 = __toESM(require("fs"), 1);
35753
- var import_node_os5 = __toESM(require("os"), 1);
35754
- var import_node_path9 = __toESM(require("path"), 1);
35824
+ var import_node_os6 = __toESM(require("os"), 1);
35825
+ var import_node_path10 = __toESM(require("path"), 1);
35755
35826
  var import_headless = __toESM(require_xterm_headless(), 1);
35756
35827
 
35757
35828
  // ../node_modules/.pnpm/@xterm+addon-serialize@0.14.0/node_modules/@xterm/addon-serialize/lib/addon-serialize.mjs
@@ -36730,8 +36801,8 @@ function buildTuiSpawnArgs(ctx, isResume = false) {
36730
36801
  }
36731
36802
  function jsonlExistsForCtx(ctx) {
36732
36803
  if (!ctx.toolSessionId) return false;
36733
- const home = import_node_os5.default.homedir();
36734
- const file = import_node_path9.default.join(home, ".claude", "projects", cwdToHashDir(ctx.cwd), `${ctx.toolSessionId}.jsonl`);
36804
+ const home = import_node_os6.default.homedir();
36805
+ const file = import_node_path10.default.join(home, ".claude", "projects", cwdToHashDir(ctx.cwd), `${ctx.toolSessionId}.jsonl`);
36735
36806
  try {
36736
36807
  return import_node_fs11.default.statSync(file).isFile();
36737
36808
  } catch {
@@ -36928,13 +36999,13 @@ function mapSkillsListResponse(res) {
36928
36999
  const r = s ?? {};
36929
37000
  const name = str3(r.name);
36930
37001
  if (!name) continue;
36931
- const path58 = str3(r.path);
37002
+ const path59 = str3(r.path);
36932
37003
  const description = str3(r.description);
36933
37004
  const isPlugin = name.includes(":");
36934
37005
  out.push({
36935
37006
  name,
36936
37007
  source: isPlugin ? "plugin" : "project",
36937
- ...path58 ? { path: path58 } : {},
37008
+ ...path59 ? { path: path59 } : {},
36938
37009
  ...description ? { description } : {},
36939
37010
  ...isPlugin ? { plugin: name.split(":")[0] } : {}
36940
37011
  });
@@ -36974,15 +37045,15 @@ async function listCodexSkills(cwd, deps = {}) {
36974
37045
 
36975
37046
  // src/workspace/browser.ts
36976
37047
  var import_node_fs12 = __toESM(require("fs"), 1);
36977
- var import_node_os6 = __toESM(require("os"), 1);
36978
- var import_node_path10 = __toESM(require("path"), 1);
37048
+ var import_node_os7 = __toESM(require("os"), 1);
37049
+ var import_node_path11 = __toESM(require("path"), 1);
36979
37050
  init_protocol();
36980
37051
  var MAX_FILE_BYTES = 2 * 1024 * 1024;
36981
37052
  function resolveInsideCwd(cwd, subpath) {
36982
- const absCwd = import_node_path10.default.resolve(cwd);
36983
- const joined = import_node_path10.default.resolve(absCwd, subpath ?? ".");
36984
- const rel = import_node_path10.default.relative(absCwd, joined);
36985
- if (rel.startsWith("..") || import_node_path10.default.isAbsolute(rel)) {
37053
+ const absCwd = import_node_path11.default.resolve(cwd);
37054
+ const joined = import_node_path11.default.resolve(absCwd, subpath ?? ".");
37055
+ const rel = import_node_path11.default.relative(absCwd, joined);
37056
+ if (rel.startsWith("..") || import_node_path11.default.isAbsolute(rel)) {
36986
37057
  throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
36987
37058
  }
36988
37059
  return joined;
@@ -37000,7 +37071,7 @@ function ensureCwd(cwd) {
37000
37071
  }
37001
37072
  var WorkspaceBrowser = class {
37002
37073
  list(args) {
37003
- const cwd = args.cwd && args.cwd.length > 0 ? args.cwd : import_node_os6.default.homedir();
37074
+ const cwd = args.cwd && args.cwd.length > 0 ? args.cwd : import_node_os7.default.homedir();
37004
37075
  ensureCwd(cwd);
37005
37076
  const full = resolveInsideCwd(cwd, args.path);
37006
37077
  const dirents = import_node_fs12.default.readdirSync(full, { withFileTypes: true });
@@ -37013,7 +37084,7 @@ var WorkspaceBrowser = class {
37013
37084
  mtime: ""
37014
37085
  };
37015
37086
  try {
37016
- const st = import_node_fs12.default.statSync(import_node_path10.default.join(full, d.name));
37087
+ const st = import_node_fs12.default.statSync(import_node_path11.default.join(full, d.name));
37017
37088
  entry.mtime = new Date(st.mtimeMs).toISOString();
37018
37089
  if (d.isFile()) entry.size = st.size;
37019
37090
  } catch {
@@ -37059,8 +37130,8 @@ var WorkspaceBrowser = class {
37059
37130
 
37060
37131
  // src/skills/agents-scanner.ts
37061
37132
  var import_node_fs13 = __toESM(require("fs"), 1);
37062
- var import_node_os7 = __toESM(require("os"), 1);
37063
- var import_node_path11 = __toESM(require("path"), 1);
37133
+ var import_node_os8 = __toESM(require("os"), 1);
37134
+ var import_node_path12 = __toESM(require("path"), 1);
37064
37135
  var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
37065
37136
  function isDirLikeSync2(p2) {
37066
37137
  try {
@@ -37098,10 +37169,10 @@ function scanAgentsDir(dir, source, seen, out) {
37098
37169
  }
37099
37170
  for (const ent of entries) {
37100
37171
  if (!ent.name.endsWith(".md")) continue;
37101
- if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path11.default.join(dir, ent.name)))) {
37172
+ if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path12.default.join(dir, ent.name)))) {
37102
37173
  continue;
37103
37174
  }
37104
- const filePath = import_node_path11.default.join(dir, ent.name);
37175
+ const filePath = import_node_path12.default.join(dir, ent.name);
37105
37176
  const baseName = ent.name.replace(/\.md$/, "");
37106
37177
  if (seen.has(baseName)) continue;
37107
37178
  seen.add(baseName);
@@ -37124,7 +37195,7 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
37124
37195
  return;
37125
37196
  }
37126
37197
  for (const ent of entries) {
37127
- const childPath = import_node_path11.default.join(dir, ent.name);
37198
+ const childPath = import_node_path12.default.join(dir, ent.name);
37128
37199
  if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
37129
37200
  walk2(childPath, [...namespaces, ent.name]);
37130
37201
  continue;
@@ -37149,9 +37220,9 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
37149
37220
  walk2(root, []);
37150
37221
  }
37151
37222
  function readInstalledPlugins2(home) {
37152
- const pluginsDir = import_node_path11.default.join(home, ".claude", "plugins");
37153
- const v2 = import_node_path11.default.join(pluginsDir, "installed_plugins_v2.json");
37154
- const v1 = import_node_path11.default.join(pluginsDir, "installed_plugins.json");
37223
+ const pluginsDir = import_node_path12.default.join(home, ".claude", "plugins");
37224
+ const v2 = import_node_path12.default.join(pluginsDir, "installed_plugins_v2.json");
37225
+ const v1 = import_node_path12.default.join(pluginsDir, "installed_plugins.json");
37155
37226
  let raw = null;
37156
37227
  for (const candidate of [v2, v1]) {
37157
37228
  try {
@@ -37180,19 +37251,19 @@ function readInstalledPlugins2(home) {
37180
37251
  return out;
37181
37252
  }
37182
37253
  function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
37183
- let cur = import_node_path11.default.resolve(startCwd);
37184
- const fsRoot = import_node_path11.default.parse(cur).root;
37254
+ let cur = import_node_path12.default.resolve(startCwd);
37255
+ const fsRoot = import_node_path12.default.parse(cur).root;
37185
37256
  while (true) {
37186
- scanAgentsDir(import_node_path11.default.join(cur, ".claude", "agents"), "project", seen, out);
37257
+ scanAgentsDir(import_node_path12.default.join(cur, ".claude", "agents"), "project", seen, out);
37187
37258
  let hasGit = false;
37188
37259
  try {
37189
- hasGit = import_node_fs13.default.existsSync(import_node_path11.default.join(cur, ".git"));
37260
+ hasGit = import_node_fs13.default.existsSync(import_node_path12.default.join(cur, ".git"));
37190
37261
  } catch {
37191
37262
  }
37192
37263
  if (hasGit) return;
37193
37264
  if (cur === home) return;
37194
37265
  if (cur === fsRoot) return;
37195
- const parent = import_node_path11.default.dirname(cur);
37266
+ const parent = import_node_path12.default.dirname(cur);
37196
37267
  if (parent === cur) return;
37197
37268
  cur = parent;
37198
37269
  }
@@ -37202,7 +37273,7 @@ var AgentsScanner = class {
37202
37273
  extraPluginRoots;
37203
37274
  policyDir;
37204
37275
  constructor(opts = {}) {
37205
- this.home = opts.home ?? process.env.CLAUDE_CONFIG_DIR ?? import_node_os7.default.homedir();
37276
+ this.home = opts.home ?? process.env.CLAUDE_CONFIG_DIR ?? import_node_os8.default.homedir();
37206
37277
  this.extraPluginRoots = opts.extraPluginRoots ?? [];
37207
37278
  if (opts.policyDir !== void 0) {
37208
37279
  this.policyDir = opts.policyDir;
@@ -37227,7 +37298,7 @@ var AgentsScanner = class {
37227
37298
  }
37228
37299
  const fsBlock = [];
37229
37300
  scanAgentsDir(
37230
- import_node_path11.default.join(this.home, ".claude", "agents"),
37301
+ import_node_path12.default.join(this.home, ".claude", "agents"),
37231
37302
  "global",
37232
37303
  seen,
37233
37304
  fsBlock
@@ -37241,7 +37312,7 @@ var AgentsScanner = class {
37241
37312
  ...this.extraPluginRoots
37242
37313
  ];
37243
37314
  for (const { name, root } of plugins) {
37244
- const agentsRoot = import_node_path11.default.join(root, "agents");
37315
+ const agentsRoot = import_node_path12.default.join(root, "agents");
37245
37316
  scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
37246
37317
  }
37247
37318
  return [...builtinBlock, ...fsBlock];
@@ -37250,27 +37321,27 @@ var AgentsScanner = class {
37250
37321
 
37251
37322
  // src/observer/session-observer.ts
37252
37323
  var import_node_fs15 = __toESM(require("fs"), 1);
37253
- var import_node_os9 = __toESM(require("os"), 1);
37254
- var import_node_path13 = __toESM(require("path"), 1);
37324
+ var import_node_os10 = __toESM(require("os"), 1);
37325
+ var import_node_path14 = __toESM(require("path"), 1);
37255
37326
  init_claude_history();
37256
37327
 
37257
37328
  // src/observer/subagent-meta-observer.ts
37258
37329
  var import_node_fs14 = __toESM(require("fs"), 1);
37259
- var import_node_os8 = __toESM(require("os"), 1);
37260
- var import_node_path12 = __toESM(require("path"), 1);
37330
+ var import_node_os9 = __toESM(require("os"), 1);
37331
+ var import_node_path13 = __toESM(require("path"), 1);
37261
37332
  init_claude_history();
37262
37333
  var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
37263
37334
  var SubagentMetaObserver = class {
37264
37335
  constructor(opts) {
37265
37336
  this.opts = opts;
37266
- this.home = opts.home ?? import_node_os8.default.homedir();
37337
+ this.home = opts.home ?? import_node_os9.default.homedir();
37267
37338
  }
37268
37339
  opts;
37269
37340
  home;
37270
37341
  watches = /* @__PURE__ */ new Map();
37271
37342
  // public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
37272
37343
  resolveSubagentDir(cwd, toolSessionId) {
37273
- return import_node_path12.default.join(
37344
+ return import_node_path13.default.join(
37274
37345
  this.home,
37275
37346
  ".claude",
37276
37347
  "projects",
@@ -37326,7 +37397,7 @@ var SubagentMetaObserver = class {
37326
37397
  if (!m2) return;
37327
37398
  const agentId = m2[1];
37328
37399
  if (w2.emitted.has(agentId)) return;
37329
- const file = import_node_path12.default.join(w2.dirPath, name);
37400
+ const file = import_node_path13.default.join(w2.dirPath, name);
37330
37401
  let raw;
37331
37402
  try {
37332
37403
  raw = import_node_fs14.default.readFileSync(file, "utf8");
@@ -37374,7 +37445,7 @@ var SubagentMetaObserver = class {
37374
37445
  var SessionObserver = class {
37375
37446
  constructor(opts) {
37376
37447
  this.opts = opts;
37377
- this.home = opts.home ?? import_node_os9.default.homedir();
37448
+ this.home = opts.home ?? import_node_os10.default.homedir();
37378
37449
  this.metaObserver = opts.enableSubagentMetaObserver ? new SubagentMetaObserver({ home: this.home, onEvent: opts.onEvent }) : null;
37379
37450
  }
37380
37451
  opts;
@@ -37386,7 +37457,7 @@ var SessionObserver = class {
37386
37457
  metaObserver;
37387
37458
  resolveJsonlPath(cwd, toolSessionId, override) {
37388
37459
  if (override) return override;
37389
- return import_node_path13.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
37460
+ return import_node_path14.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
37390
37461
  }
37391
37462
  start(args) {
37392
37463
  this.stop(args.sessionId);
@@ -37407,10 +37478,10 @@ var SessionObserver = class {
37407
37478
  prevIsRejectSentinel: false
37408
37479
  };
37409
37480
  try {
37410
- import_node_fs15.default.mkdirSync(import_node_path13.default.dirname(filePath), { recursive: true });
37481
+ import_node_fs15.default.mkdirSync(import_node_path14.default.dirname(filePath), { recursive: true });
37411
37482
  } catch {
37412
37483
  }
37413
- w2.watcher = import_node_fs15.default.watch(import_node_path13.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
37484
+ w2.watcher = import_node_fs15.default.watch(import_node_path14.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
37414
37485
  if (!changedName || !filePath.endsWith(changedName)) return;
37415
37486
  this.poll(w2);
37416
37487
  });
@@ -38217,7 +38288,7 @@ async function authenticate(token, deps) {
38217
38288
 
38218
38289
  // src/permission/capability-store.ts
38219
38290
  var fs18 = __toESM(require("fs"), 1);
38220
- var path18 = __toESM(require("path"), 1);
38291
+ var path19 = __toESM(require("path"), 1);
38221
38292
  var CAPABILITIES_FILE_NAME = "capabilities.json";
38222
38293
  var FILE_VERSION = 1;
38223
38294
  var CapabilityStore = class {
@@ -38247,7 +38318,7 @@ var CapabilityStore = class {
38247
38318
  this.flush();
38248
38319
  }
38249
38320
  filePath() {
38250
- return path18.join(this.dataDir, CAPABILITIES_FILE_NAME);
38321
+ return path19.join(this.dataDir, CAPABILITIES_FILE_NAME);
38251
38322
  }
38252
38323
  readFromDisk() {
38253
38324
  const file = this.filePath();
@@ -38394,7 +38465,7 @@ function cleanupGuestSessionsForCapability(cap, factory) {
38394
38465
 
38395
38466
  // src/inbox/inbox-store.ts
38396
38467
  var fs20 = __toESM(require("fs"), 1);
38397
- var path19 = __toESM(require("path"), 1);
38468
+ var path20 = __toESM(require("path"), 1);
38398
38469
  var INBOX_SUBDIR = "inbox";
38399
38470
  var InboxStore = class {
38400
38471
  constructor(dataDir) {
@@ -38492,10 +38563,10 @@ var InboxStore = class {
38492
38563
  }
38493
38564
  }
38494
38565
  dirPath() {
38495
- return path19.join(this.dataDir, INBOX_SUBDIR);
38566
+ return path20.join(this.dataDir, INBOX_SUBDIR);
38496
38567
  }
38497
38568
  filePath(peerDeviceId) {
38498
- return path19.join(this.dirPath(), `${peerDeviceId}.jsonl`);
38569
+ return path20.join(this.dirPath(), `${peerDeviceId}.jsonl`);
38499
38570
  }
38500
38571
  };
38501
38572
  function parseAllLines(raw) {
@@ -38583,7 +38654,7 @@ var InboxManager = class {
38583
38654
 
38584
38655
  // src/state/contact-store.ts
38585
38656
  var fs21 = __toESM(require("fs"), 1);
38586
- var path20 = __toESM(require("path"), 1);
38657
+ var path21 = __toESM(require("path"), 1);
38587
38658
  var FILE_NAME = "contacts.json";
38588
38659
  var ContactStore = class {
38589
38660
  constructor(dataDir) {
@@ -38593,7 +38664,7 @@ var ContactStore = class {
38593
38664
  contacts = /* @__PURE__ */ new Map();
38594
38665
  load() {
38595
38666
  this.contacts.clear();
38596
- const file = path20.join(this.dataDir, FILE_NAME);
38667
+ const file = path21.join(this.dataDir, FILE_NAME);
38597
38668
  let raw;
38598
38669
  try {
38599
38670
  raw = fs21.readFileSync(file, "utf8");
@@ -38639,7 +38710,7 @@ var ContactStore = class {
38639
38710
  return existed;
38640
38711
  }
38641
38712
  flush() {
38642
- const file = path20.join(this.dataDir, FILE_NAME);
38713
+ const file = path21.join(this.dataDir, FILE_NAME);
38643
38714
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
38644
38715
  const content = JSON.stringify(
38645
38716
  { contacts: Array.from(this.contacts.values()) },
@@ -38803,52 +38874,52 @@ async function autoReverseContact(args) {
38803
38874
 
38804
38875
  // src/migrations/2026-05-20-flatten-sessions.ts
38805
38876
  var fs22 = __toESM(require("fs"), 1);
38806
- var path21 = __toESM(require("path"), 1);
38877
+ var path22 = __toESM(require("path"), 1);
38807
38878
  var MIGRATION_FLAG_NAME = ".migration.v1.done";
38808
38879
  function migrateFlattenSessions(opts) {
38809
38880
  const dataDir = opts.dataDir;
38810
38881
  const now = opts.now ?? Date.now;
38811
- const sessionsDir = path21.join(dataDir, "sessions");
38812
- const flagPath = path21.join(sessionsDir, MIGRATION_FLAG_NAME);
38882
+ const sessionsDir = path22.join(dataDir, "sessions");
38883
+ const flagPath = path22.join(sessionsDir, MIGRATION_FLAG_NAME);
38813
38884
  if (existsSync3(flagPath)) {
38814
38885
  return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
38815
38886
  }
38816
38887
  let movedBare = 0;
38817
38888
  let movedVmOwner = 0;
38818
38889
  let archivedListener = 0;
38819
- const defaultDir = path21.join(sessionsDir, "default");
38890
+ const defaultDir = path22.join(sessionsDir, "default");
38820
38891
  if (existsSync3(defaultDir)) {
38821
38892
  for (const entry of readdirSafe(defaultDir)) {
38822
38893
  if (!entry.endsWith(".json")) continue;
38823
- const src = path21.join(defaultDir, entry);
38824
- const dst = path21.join(sessionsDir, entry);
38894
+ const src = path22.join(defaultDir, entry);
38895
+ const dst = path22.join(sessionsDir, entry);
38825
38896
  fs22.renameSync(src, dst);
38826
38897
  movedBare += 1;
38827
38898
  }
38828
38899
  rmdirIfEmpty(defaultDir);
38829
38900
  }
38830
38901
  for (const pid of readdirSafe(sessionsDir)) {
38831
- const personaDir = path21.join(sessionsDir, pid);
38902
+ const personaDir = path22.join(sessionsDir, pid);
38832
38903
  if (!isDir(personaDir)) continue;
38833
38904
  if (pid === "default") continue;
38834
- const ownerSrc = path21.join(personaDir, "owner");
38905
+ const ownerSrc = path22.join(personaDir, "owner");
38835
38906
  if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
38836
- const ownerDst = path21.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
38907
+ const ownerDst = path22.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
38837
38908
  fs22.mkdirSync(ownerDst, { recursive: true });
38838
38909
  for (const file of readdirSafe(ownerSrc)) {
38839
38910
  if (!file.endsWith(".json")) continue;
38840
- fs22.renameSync(path21.join(ownerSrc, file), path21.join(ownerDst, file));
38911
+ fs22.renameSync(path22.join(ownerSrc, file), path22.join(ownerDst, file));
38841
38912
  movedVmOwner += 1;
38842
38913
  }
38843
38914
  rmdirIfEmpty(ownerSrc);
38844
38915
  }
38845
- const listenerSrc = path21.join(personaDir, "listener");
38916
+ const listenerSrc = path22.join(personaDir, "listener");
38846
38917
  if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
38847
- const archiveDst = path21.join(dataDir, ".legacy", `listener-${pid}`);
38918
+ const archiveDst = path22.join(dataDir, ".legacy", `listener-${pid}`);
38848
38919
  fs22.mkdirSync(archiveDst, { recursive: true });
38849
38920
  for (const file of readdirSafe(listenerSrc)) {
38850
38921
  if (!file.endsWith(".json")) continue;
38851
- fs22.renameSync(path21.join(listenerSrc, file), path21.join(archiveDst, file));
38922
+ fs22.renameSync(path22.join(listenerSrc, file), path22.join(archiveDst, file));
38852
38923
  archivedListener += 1;
38853
38924
  }
38854
38925
  rmdirIfEmpty(listenerSrc);
@@ -38896,10 +38967,10 @@ function rmdirIfEmpty(p2) {
38896
38967
 
38897
38968
  // src/transport/http-router.ts
38898
38969
  var import_node_fs17 = __toESM(require("fs"), 1);
38899
- var import_node_path17 = __toESM(require("path"), 1);
38970
+ var import_node_path18 = __toESM(require("path"), 1);
38900
38971
 
38901
38972
  // src/attachment/mime.ts
38902
- var import_node_path14 = __toESM(require("path"), 1);
38973
+ var import_node_path15 = __toESM(require("path"), 1);
38903
38974
  var TEXT_PLAIN = "text/plain; charset=utf-8";
38904
38975
  var EXT_TO_NATIVE_MIME = {
38905
38976
  // 图片
@@ -39006,7 +39077,7 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
39006
39077
  ".mk"
39007
39078
  ]);
39008
39079
  function lookupMime(filePathOrName) {
39009
- const ext = import_node_path14.default.extname(filePathOrName).toLowerCase();
39080
+ const ext = import_node_path15.default.extname(filePathOrName).toLowerCase();
39010
39081
  if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
39011
39082
  if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
39012
39083
  return "application/octet-stream";
@@ -39076,7 +39147,7 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
39076
39147
 
39077
39148
  // src/attachment/upload.ts
39078
39149
  var import_node_fs16 = __toESM(require("fs"), 1);
39079
- var import_node_path15 = __toESM(require("path"), 1);
39150
+ var import_node_path16 = __toESM(require("path"), 1);
39080
39151
  var import_node_crypto5 = __toESM(require("crypto"), 1);
39081
39152
  var import_promises = require("stream/promises");
39082
39153
  var UploadError = class extends Error {
@@ -39088,14 +39159,14 @@ var UploadError = class extends Error {
39088
39159
  code;
39089
39160
  };
39090
39161
  function assertValidFileName(fileName) {
39091
- if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path15.default.basename(fileName)) {
39162
+ if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path16.default.basename(fileName)) {
39092
39163
  throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
39093
39164
  }
39094
39165
  }
39095
39166
  var HASH_PREFIX_LEN = 16;
39096
39167
  async function writeUploadedAttachment(args) {
39097
39168
  assertValidFileName(args.fileName);
39098
- const attachmentsRoot = import_node_path15.default.join(args.sessionDir, ".attachments");
39169
+ const attachmentsRoot = import_node_path16.default.join(args.sessionDir, ".attachments");
39099
39170
  try {
39100
39171
  import_node_fs16.default.mkdirSync(attachmentsRoot, { recursive: true });
39101
39172
  } catch (err) {
@@ -39103,7 +39174,7 @@ async function writeUploadedAttachment(args) {
39103
39174
  }
39104
39175
  const hasher = import_node_crypto5.default.createHash("sha256");
39105
39176
  let actualSize = 0;
39106
- const tmpPath = import_node_path15.default.join(
39177
+ const tmpPath = import_node_path16.default.join(
39107
39178
  attachmentsRoot,
39108
39179
  `.upload-${process.pid}-${Date.now()}-${import_node_crypto5.default.randomBytes(4).toString("hex")}`
39109
39180
  );
@@ -39138,7 +39209,7 @@ async function writeUploadedAttachment(args) {
39138
39209
  );
39139
39210
  }
39140
39211
  const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
39141
- const hashDir = import_node_path15.default.join(attachmentsRoot, attachmentId);
39212
+ const hashDir = import_node_path16.default.join(attachmentsRoot, attachmentId);
39142
39213
  let finalFileName;
39143
39214
  let hashDirExists = false;
39144
39215
  try {
@@ -39156,7 +39227,7 @@ async function writeUploadedAttachment(args) {
39156
39227
  try {
39157
39228
  import_node_fs16.default.mkdirSync(hashDir, { recursive: true });
39158
39229
  finalFileName = args.fileName;
39159
- import_node_fs16.default.renameSync(tmpPath, import_node_path15.default.join(hashDir, finalFileName));
39230
+ import_node_fs16.default.renameSync(tmpPath, import_node_path16.default.join(hashDir, finalFileName));
39160
39231
  } catch (err) {
39161
39232
  try {
39162
39233
  import_node_fs16.default.unlinkSync(tmpPath);
@@ -39165,8 +39236,8 @@ async function writeUploadedAttachment(args) {
39165
39236
  throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
39166
39237
  }
39167
39238
  }
39168
- const absPath = import_node_path15.default.join(hashDir, finalFileName);
39169
- const relPath = import_node_path15.default.relative(args.sessionDir, absPath);
39239
+ const absPath = import_node_path16.default.join(hashDir, finalFileName);
39240
+ const relPath = import_node_path16.default.relative(args.sessionDir, absPath);
39170
39241
  args.groupFileStore.upsert(args.scope, args.sessionId, {
39171
39242
  relPath: absPath,
39172
39243
  // 存绝对路径,与现有 agent 入清单的形态一致(attachment.ts:144 双形态兼容)
@@ -39180,8 +39251,8 @@ async function writeUploadedAttachment(args) {
39180
39251
 
39181
39252
  // src/extension/import.ts
39182
39253
  var import_promises2 = __toESM(require("fs/promises"), 1);
39183
- var import_node_path16 = __toESM(require("path"), 1);
39184
- var import_node_os10 = __toESM(require("os"), 1);
39254
+ var import_node_path17 = __toESM(require("path"), 1);
39255
+ var import_node_os11 = __toESM(require("os"), 1);
39185
39256
  var import_jszip = __toESM(require_lib3(), 1);
39186
39257
  var ImportError = class extends Error {
39187
39258
  constructor(code, message) {
@@ -39198,7 +39269,7 @@ async function importZip(buf, root) {
39198
39269
  throw new ImportError("ZIP_INVALID", `failed to load zip: ${e.message}`);
39199
39270
  }
39200
39271
  for (const name of Object.keys(zip.files)) {
39201
- if (name.includes("..") || name.startsWith("/") || import_node_path16.default.isAbsolute(name)) {
39272
+ if (name.includes("..") || name.startsWith("/") || import_node_path17.default.isAbsolute(name)) {
39202
39273
  throw new ImportError("ZIP_INVALID", `unsafe zip entry path: ${name}`);
39203
39274
  }
39204
39275
  }
@@ -39231,7 +39302,7 @@ async function importZip(buf, root) {
39231
39302
  );
39232
39303
  }
39233
39304
  }
39234
- const destDir = import_node_path16.default.join(root, manifest.id);
39305
+ const destDir = import_node_path17.default.join(root, manifest.id);
39235
39306
  let destExists = false;
39236
39307
  try {
39237
39308
  await import_promises2.default.access(destDir);
@@ -39241,15 +39312,15 @@ async function importZip(buf, root) {
39241
39312
  if (destExists) {
39242
39313
  throw new ImportError("ALREADY_EXISTS", `extension ${manifest.id} already installed`);
39243
39314
  }
39244
- const stage = await import_promises2.default.mkdtemp(import_node_path16.default.join(import_node_os10.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
39315
+ const stage = await import_promises2.default.mkdtemp(import_node_path17.default.join(import_node_os11.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
39245
39316
  try {
39246
39317
  for (const [name, entry] of Object.entries(zip.files)) {
39247
- const dest = import_node_path16.default.join(stage, name);
39318
+ const dest = import_node_path17.default.join(stage, name);
39248
39319
  if (entry.dir) {
39249
39320
  await import_promises2.default.mkdir(dest, { recursive: true });
39250
39321
  continue;
39251
39322
  }
39252
- await import_promises2.default.mkdir(import_node_path16.default.dirname(dest), { recursive: true });
39323
+ await import_promises2.default.mkdir(import_node_path17.default.dirname(dest), { recursive: true });
39253
39324
  const content = await entry.async("nodebuffer");
39254
39325
  await import_promises2.default.writeFile(dest, content);
39255
39326
  }
@@ -39363,7 +39434,7 @@ function isValidUploadFileName(fileName) {
39363
39434
  if (fileName === "." || fileName === "..") return false;
39364
39435
  if (fileName.startsWith(".")) return false;
39365
39436
  if (fileName.includes("/") || fileName.includes("\\")) return false;
39366
- return fileName === import_node_path17.default.basename(fileName);
39437
+ return fileName === import_node_path18.default.basename(fileName);
39367
39438
  }
39368
39439
  function createHttpRouter(deps) {
39369
39440
  return async (req, res) => {
@@ -39592,7 +39663,7 @@ function createHttpRouter(deps) {
39592
39663
  return true;
39593
39664
  }
39594
39665
  let absPath;
39595
- if (import_node_path17.default.isAbsolute(pathParam)) {
39666
+ if (import_node_path18.default.isAbsolute(pathParam)) {
39596
39667
  absPath = pathParam;
39597
39668
  } else if (deps.sessionStore) {
39598
39669
  const file = deps.sessionStore.read(sid);
@@ -39600,7 +39671,7 @@ function createHttpRouter(deps) {
39600
39671
  sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
39601
39672
  return true;
39602
39673
  }
39603
- absPath = import_node_path17.default.join(file.cwd, pathParam);
39674
+ absPath = import_node_path18.default.join(file.cwd, pathParam);
39604
39675
  } else {
39605
39676
  sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
39606
39677
  return true;
@@ -39698,7 +39769,7 @@ function streamFile(res, absPath, logger) {
39698
39769
  return;
39699
39770
  }
39700
39771
  const mime = lookupMime(absPath);
39701
- const basename = import_node_path17.default.basename(absPath);
39772
+ const basename = import_node_path18.default.basename(absPath);
39702
39773
  res.writeHead(200, {
39703
39774
  "Content-Type": mime,
39704
39775
  "Content-Length": String(stat.size),
@@ -39716,7 +39787,7 @@ function streamFile(res, absPath, logger) {
39716
39787
 
39717
39788
  // src/attachment/gc.ts
39718
39789
  var import_node_fs18 = __toESM(require("fs"), 1);
39719
- var import_node_path18 = __toESM(require("path"), 1);
39790
+ var import_node_path19 = __toESM(require("path"), 1);
39720
39791
  var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
39721
39792
  function runAttachmentGc(args) {
39722
39793
  const now = (args.now ?? Date.now)();
@@ -39725,17 +39796,17 @@ function runAttachmentGc(args) {
39725
39796
  for (const { scope, sessionId } of args.sessionScopes) {
39726
39797
  for (const entry of args.groupFileStore.list(scope, sessionId)) {
39727
39798
  if (entry.stale) continue;
39728
- if (import_node_path18.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
39799
+ if (import_node_path19.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
39729
39800
  }
39730
39801
  }
39731
39802
  for (const { scope, sessionId } of args.sessionScopes) {
39732
- const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path18.default.join(
39803
+ const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path19.default.join(
39733
39804
  args.dataDir,
39734
39805
  "sessions",
39735
39806
  ...scopeSubPath(scope).map(safeFileName),
39736
39807
  safeFileName(sessionId)
39737
39808
  );
39738
- const attRoot = import_node_path18.default.join(sessionDir, ".attachments");
39809
+ const attRoot = import_node_path19.default.join(sessionDir, ".attachments");
39739
39810
  let hashDirs;
39740
39811
  try {
39741
39812
  hashDirs = import_node_fs18.default.readdirSync(attRoot);
@@ -39745,7 +39816,7 @@ function runAttachmentGc(args) {
39745
39816
  continue;
39746
39817
  }
39747
39818
  for (const hashDir of hashDirs) {
39748
- const hashDirAbs = import_node_path18.default.join(attRoot, hashDir);
39819
+ const hashDirAbs = import_node_path19.default.join(attRoot, hashDir);
39749
39820
  let files;
39750
39821
  try {
39751
39822
  files = import_node_fs18.default.readdirSync(hashDirAbs);
@@ -39753,7 +39824,7 @@ function runAttachmentGc(args) {
39753
39824
  continue;
39754
39825
  }
39755
39826
  for (const name of files) {
39756
- const file = import_node_path18.default.join(hashDirAbs, name);
39827
+ const file = import_node_path19.default.join(hashDirAbs, name);
39757
39828
  let stat;
39758
39829
  try {
39759
39830
  stat = import_node_fs18.default.statSync(file);
@@ -39784,7 +39855,7 @@ function runAttachmentGc(args) {
39784
39855
 
39785
39856
  // src/attachment/group.ts
39786
39857
  var import_node_fs19 = __toESM(require("fs"), 1);
39787
- var import_node_path19 = __toESM(require("path"), 1);
39858
+ var import_node_path20 = __toESM(require("path"), 1);
39788
39859
  var import_node_crypto6 = __toESM(require("crypto"), 1);
39789
39860
  init_protocol();
39790
39861
  var GroupFileStore = class {
@@ -39796,11 +39867,11 @@ var GroupFileStore = class {
39796
39867
  this.logger = opts.logger;
39797
39868
  }
39798
39869
  rootForScope(scope) {
39799
- return import_node_path19.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
39870
+ return import_node_path20.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
39800
39871
  }
39801
39872
  /** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
39802
39873
  filePath(scope, sessionId) {
39803
- return import_node_path19.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
39874
+ return import_node_path20.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
39804
39875
  }
39805
39876
  cacheKey(scope, sessionId) {
39806
39877
  return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
@@ -39835,7 +39906,7 @@ var GroupFileStore = class {
39835
39906
  }
39836
39907
  writeFile(scope, sessionId, entries) {
39837
39908
  const file = this.filePath(scope, sessionId);
39838
- import_node_fs19.default.mkdirSync(import_node_path19.default.dirname(file), { recursive: true });
39909
+ import_node_fs19.default.mkdirSync(import_node_path20.default.dirname(file), { recursive: true });
39839
39910
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
39840
39911
  import_node_fs19.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
39841
39912
  import_node_fs19.default.renameSync(tmp, file);
@@ -39925,9 +39996,9 @@ var GroupFileStore = class {
39925
39996
 
39926
39997
  // src/discovery/state-file.ts
39927
39998
  var import_node_fs20 = __toESM(require("fs"), 1);
39928
- var import_node_path20 = __toESM(require("path"), 1);
39999
+ var import_node_path21 = __toESM(require("path"), 1);
39929
40000
  function defaultStateFilePath(dataDir) {
39930
- return import_node_path20.default.join(dataDir, "state.json");
40001
+ return import_node_path21.default.join(dataDir, "state.json");
39931
40002
  }
39932
40003
  function isPidAlive(pid) {
39933
40004
  if (!Number.isFinite(pid) || pid <= 0) return false;
@@ -39963,7 +40034,7 @@ var StateFileManager = class {
39963
40034
  return { status: "stale", existing };
39964
40035
  }
39965
40036
  write(state) {
39966
- import_node_fs20.default.mkdirSync(import_node_path20.default.dirname(this.file), { recursive: true });
40037
+ import_node_fs20.default.mkdirSync(import_node_path21.default.dirname(this.file), { recursive: true });
39967
40038
  const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
39968
40039
  import_node_fs20.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
39969
40040
  import_node_fs20.default.renameSync(tmp, this.file);
@@ -39992,13 +40063,13 @@ function readDaemonSourceFromEnv(env = process.env) {
39992
40063
 
39993
40064
  // src/tunnel/tunnel-manager.ts
39994
40065
  var import_node_fs24 = __toESM(require("fs"), 1);
39995
- var import_node_path24 = __toESM(require("path"), 1);
40066
+ var import_node_path25 = __toESM(require("path"), 1);
39996
40067
  var import_node_crypto7 = __toESM(require("crypto"), 1);
39997
40068
  var import_node_child_process9 = require("child_process");
39998
40069
 
39999
40070
  // src/tunnel/tunnel-store.ts
40000
40071
  var import_node_fs21 = __toESM(require("fs"), 1);
40001
- var import_node_path21 = __toESM(require("path"), 1);
40072
+ var import_node_path22 = __toESM(require("path"), 1);
40002
40073
  var TunnelStore = class {
40003
40074
  constructor(filePath) {
40004
40075
  this.filePath = filePath;
@@ -40017,7 +40088,7 @@ var TunnelStore = class {
40017
40088
  }
40018
40089
  }
40019
40090
  async set(v2) {
40020
- const dir = import_node_path21.default.dirname(this.filePath);
40091
+ const dir = import_node_path22.default.dirname(this.filePath);
40021
40092
  await import_node_fs21.default.promises.mkdir(dir, { recursive: true });
40022
40093
  const data = JSON.stringify(v2, null, 2);
40023
40094
  const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
@@ -40128,8 +40199,8 @@ function escape(v2) {
40128
40199
 
40129
40200
  // src/tunnel/frpc-binary.ts
40130
40201
  var import_node_fs22 = __toESM(require("fs"), 1);
40131
- var import_node_os11 = __toESM(require("os"), 1);
40132
- var import_node_path22 = __toESM(require("path"), 1);
40202
+ var import_node_os12 = __toESM(require("os"), 1);
40203
+ var import_node_path23 = __toESM(require("path"), 1);
40133
40204
  var import_node_child_process7 = require("child_process");
40134
40205
  var import_node_stream2 = require("stream");
40135
40206
  var import_promises3 = require("stream/promises");
@@ -40168,13 +40239,13 @@ async function ensureFrpcBinary(opts) {
40168
40239
  }
40169
40240
  const version2 = opts.version ?? FRPC_VERSION;
40170
40241
  const platform = opts.platform ?? detectPlatform();
40171
- const binDir = import_node_path22.default.join(opts.dataDir, "bin");
40242
+ const binDir = import_node_path23.default.join(opts.dataDir, "bin");
40172
40243
  import_node_fs22.default.mkdirSync(binDir, { recursive: true });
40173
40244
  cleanupStaleArtifacts(binDir);
40174
- const stableBin = import_node_path22.default.join(binDir, "frpc");
40245
+ const stableBin = import_node_path23.default.join(binDir, "frpc");
40175
40246
  if (import_node_fs22.default.existsSync(stableBin)) return stableBin;
40176
40247
  const partialBin = `${stableBin}.partial`;
40177
- const tarballPath = import_node_path22.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
40248
+ const tarballPath = import_node_path23.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
40178
40249
  try {
40179
40250
  const url = frpcDownloadUrl(version2, platform);
40180
40251
  await downloadToFile(url, tarballPath, opts.fetchImpl);
@@ -40200,7 +40271,7 @@ function cleanupStaleArtifacts(binDir) {
40200
40271
  }
40201
40272
  for (const name of entries) {
40202
40273
  if (name.endsWith(".partial") || name.startsWith("extract-")) {
40203
- const full = import_node_path22.default.join(binDir, name);
40274
+ const full = import_node_path23.default.join(binDir, name);
40204
40275
  try {
40205
40276
  import_node_fs22.default.rmSync(full, { recursive: true, force: true });
40206
40277
  } catch {
@@ -40226,7 +40297,7 @@ async function downloadToFile(url, dest, fetchImpl) {
40226
40297
  await (0, import_promises3.pipeline)(nodeStream, out);
40227
40298
  }
40228
40299
  async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
40229
- const work = import_node_path22.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
40300
+ const work = import_node_path23.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
40230
40301
  import_node_fs22.default.mkdirSync(work, { recursive: true });
40231
40302
  try {
40232
40303
  await new Promise((resolve6, reject) => {
@@ -40235,7 +40306,7 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
40235
40306
  proc.on("exit", (code) => code === 0 ? resolve6() : reject(new Error(`tar exited ${code}`)));
40236
40307
  });
40237
40308
  const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
40238
- const src = import_node_path22.default.join(work, dirName, "frpc");
40309
+ const src = import_node_path23.default.join(work, dirName, "frpc");
40239
40310
  if (!import_node_fs22.default.existsSync(src)) {
40240
40311
  throw new Error(`frpc not found inside tarball at ${src}`);
40241
40312
  }
@@ -40247,10 +40318,10 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
40247
40318
 
40248
40319
  // src/tunnel/frpc-process.ts
40249
40320
  var import_node_fs23 = __toESM(require("fs"), 1);
40250
- var import_node_path23 = __toESM(require("path"), 1);
40321
+ var import_node_path24 = __toESM(require("path"), 1);
40251
40322
  var import_node_child_process8 = require("child_process");
40252
40323
  function frpcPidFilePath(dataDir) {
40253
- return import_node_path23.default.join(dataDir, "frpc.pid");
40324
+ return import_node_path24.default.join(dataDir, "frpc.pid");
40254
40325
  }
40255
40326
  function writeFrpcPid(dataDir, pid) {
40256
40327
  try {
@@ -40292,7 +40363,7 @@ function defaultSleep(ms) {
40292
40363
  }
40293
40364
  async function killStaleFrpc(deps) {
40294
40365
  const pidFile = frpcPidFilePath(deps.dataDir);
40295
- const tomlPath = import_node_path23.default.join(deps.dataDir, "frpc.toml");
40366
+ const tomlPath = import_node_path24.default.join(deps.dataDir, "frpc.toml");
40296
40367
  const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
40297
40368
  const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
40298
40369
  const killPid = deps.killPidImpl ?? defaultKillPid;
@@ -40364,7 +40435,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
40364
40435
  var TunnelManager = class {
40365
40436
  constructor(deps) {
40366
40437
  this.deps = deps;
40367
- this.store = deps.store ?? new TunnelStore(import_node_path24.default.join(deps.dataDir, "tunnel.json"));
40438
+ this.store = deps.store ?? new TunnelStore(import_node_path25.default.join(deps.dataDir, "tunnel.json"));
40368
40439
  this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
40369
40440
  this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
40370
40441
  }
@@ -40491,7 +40562,7 @@ var TunnelManager = class {
40491
40562
  dataDir: this.deps.dataDir,
40492
40563
  override: this.deps.frpcBinaryOverride ?? void 0
40493
40564
  });
40494
- const tomlPath = import_node_path24.default.join(this.deps.dataDir, "frpc.toml");
40565
+ const tomlPath = import_node_path25.default.join(this.deps.dataDir, "frpc.toml");
40495
40566
  const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto7.default.randomBytes(3).toString("hex")}`;
40496
40567
  const toml = buildFrpcToml({
40497
40568
  serverAddr: t.frpsHost,
@@ -40506,7 +40577,7 @@ var TunnelManager = class {
40506
40577
  const proc = (this.deps.spawnImpl ?? import_node_child_process9.spawn)(frpcBin, ["-c", tomlPath], {
40507
40578
  stdio: ["ignore", "pipe", "pipe"]
40508
40579
  });
40509
- const logFilePath = import_node_path24.default.join(this.deps.dataDir, "frpc.log");
40580
+ const logFilePath = import_node_path25.default.join(this.deps.dataDir, "frpc.log");
40510
40581
  const logStream = import_node_fs24.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
40511
40582
  logStream.on("error", () => {
40512
40583
  });
@@ -40589,16 +40660,16 @@ async function waitForFrpcReady(proc, timeoutMs) {
40589
40660
  }
40590
40661
 
40591
40662
  // src/tunnel/device-key.ts
40592
- var import_node_os12 = __toESM(require("os"), 1);
40593
- var import_node_path25 = __toESM(require("path"), 1);
40663
+ var import_node_os13 = __toESM(require("os"), 1);
40664
+ var import_node_path26 = __toESM(require("path"), 1);
40594
40665
  var import_node_crypto8 = __toESM(require("crypto"), 1);
40595
40666
  var DERIVE_SALT = "clawd-tunnel-device-v1";
40596
40667
  function deriveStableDeviceKey(opts = {}) {
40597
- const hostname = opts.hostname ?? import_node_os12.default.hostname();
40598
- const uid = opts.uid ?? (typeof import_node_os12.default.userInfo === "function" ? import_node_os12.default.userInfo().uid : 0);
40599
- const home = opts.home ?? import_node_os12.default.homedir();
40600
- const defaultDataDir = import_node_path25.default.resolve(import_node_path25.default.join(home, ".clawd"));
40601
- const normalizedDataDir = opts.dataDir ? import_node_path25.default.resolve(opts.dataDir) : null;
40668
+ const hostname = opts.hostname ?? import_node_os13.default.hostname();
40669
+ const uid = opts.uid ?? (typeof import_node_os13.default.userInfo === "function" ? import_node_os13.default.userInfo().uid : 0);
40670
+ const home = opts.home ?? import_node_os13.default.homedir();
40671
+ const defaultDataDir = import_node_path26.default.resolve(import_node_path26.default.join(home, ".clawd"));
40672
+ const normalizedDataDir = opts.dataDir ? import_node_path26.default.resolve(opts.dataDir) : null;
40602
40673
  const isDefaultDir = normalizedDataDir == null || normalizedDataDir === defaultDataDir;
40603
40674
  const input = isDefaultDir ? `${hostname}::${uid}` : `${hostname}::${uid}::${normalizedDataDir}`;
40604
40675
  return import_node_crypto8.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
@@ -40606,11 +40677,11 @@ function deriveStableDeviceKey(opts = {}) {
40606
40677
 
40607
40678
  // src/auth-store.ts
40608
40679
  var import_node_fs25 = __toESM(require("fs"), 1);
40609
- var import_node_path26 = __toESM(require("path"), 1);
40680
+ var import_node_path27 = __toESM(require("path"), 1);
40610
40681
  var import_node_crypto9 = __toESM(require("crypto"), 1);
40611
40682
  var AUTH_FILE_NAME = "auth.json";
40612
40683
  function authFilePath(dataDir) {
40613
- return import_node_path26.default.join(dataDir, AUTH_FILE_NAME);
40684
+ return import_node_path27.default.join(dataDir, AUTH_FILE_NAME);
40614
40685
  }
40615
40686
  function loadOrCreateAuthFile(opts) {
40616
40687
  const file = authFilePath(opts.dataDir);
@@ -40663,7 +40734,7 @@ function readAuthFile(file) {
40663
40734
  }
40664
40735
  }
40665
40736
  function writeAuthFile(file, content) {
40666
- import_node_fs25.default.mkdirSync(import_node_path26.default.dirname(file), { recursive: true });
40737
+ import_node_fs25.default.mkdirSync(import_node_path27.default.dirname(file), { recursive: true });
40667
40738
  import_node_fs25.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
40668
40739
  try {
40669
40740
  import_node_fs25.default.chmodSync(file, 384);
@@ -40673,12 +40744,12 @@ function writeAuthFile(file, content) {
40673
40744
 
40674
40745
  // src/owner-profile.ts
40675
40746
  var import_node_fs26 = __toESM(require("fs"), 1);
40676
- var import_node_os13 = __toESM(require("os"), 1);
40677
- var import_node_path27 = __toESM(require("path"), 1);
40747
+ var import_node_os14 = __toESM(require("os"), 1);
40748
+ var import_node_path28 = __toESM(require("path"), 1);
40678
40749
  var PROFILE_FILENAME = "profile.json";
40679
40750
  function loadOwnerDisplayName(dataDir) {
40680
- const fallback = import_node_os13.default.userInfo().username;
40681
- const profilePath = import_node_path27.default.join(dataDir, PROFILE_FILENAME);
40751
+ const fallback = import_node_os14.default.userInfo().username;
40752
+ const profilePath = import_node_path28.default.join(dataDir, PROFILE_FILENAME);
40682
40753
  let raw;
40683
40754
  try {
40684
40755
  raw = import_node_fs26.default.readFileSync(profilePath, "utf8");
@@ -40705,12 +40776,12 @@ function loadOwnerDisplayName(dataDir) {
40705
40776
 
40706
40777
  // src/feishu-auth/owner-identity-store.ts
40707
40778
  var import_node_fs27 = __toESM(require("fs"), 1);
40708
- var import_node_path28 = __toESM(require("path"), 1);
40779
+ var import_node_path29 = __toESM(require("path"), 1);
40709
40780
  var OWNER_IDENTITY_FILE_NAME = "owner-identity.json";
40710
40781
  var OwnerIdentityStore = class {
40711
40782
  file;
40712
40783
  constructor(dataDir) {
40713
- this.file = import_node_path28.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
40784
+ this.file = import_node_path29.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
40714
40785
  }
40715
40786
  read() {
40716
40787
  let raw;
@@ -40742,7 +40813,7 @@ var OwnerIdentityStore = class {
40742
40813
  };
40743
40814
  }
40744
40815
  write(record) {
40745
- import_node_fs27.default.mkdirSync(import_node_path28.default.dirname(this.file), { recursive: true });
40816
+ import_node_fs27.default.mkdirSync(import_node_path29.default.dirname(this.file), { recursive: true });
40746
40817
  import_node_fs27.default.writeFileSync(this.file, JSON.stringify(record, null, 2), { mode: 384 });
40747
40818
  try {
40748
40819
  import_node_fs27.default.chmodSync(this.file, 384);
@@ -40870,9 +40941,9 @@ var CentralClientError = class extends Error {
40870
40941
  code;
40871
40942
  cause;
40872
40943
  };
40873
- async function centralRequest(opts, path58, init) {
40944
+ async function centralRequest(opts, path59, init) {
40874
40945
  const f = opts.fetchImpl ?? globalThis.fetch;
40875
- const url = `${opts.api.replace(/\/+$/, "")}${path58}`;
40946
+ const url = `${opts.api.replace(/\/+$/, "")}${path59}`;
40876
40947
  const ctrl = new AbortController();
40877
40948
  const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
40878
40949
  let res;
@@ -41015,7 +41086,7 @@ function verifyConnectToken(args) {
41015
41086
 
41016
41087
  // src/feishu-auth/server-key.ts
41017
41088
  var fs36 = __toESM(require("fs"), 1);
41018
- var path37 = __toESM(require("path"), 1);
41089
+ var path38 = __toESM(require("path"), 1);
41019
41090
  var FILE_NAME2 = "server-signing-key.json";
41020
41091
  var ServerKeyStore = class {
41021
41092
  constructor(dataDir) {
@@ -41023,7 +41094,7 @@ var ServerKeyStore = class {
41023
41094
  }
41024
41095
  dataDir;
41025
41096
  filePath() {
41026
- return path37.join(this.dataDir, FILE_NAME2);
41097
+ return path38.join(this.dataDir, FILE_NAME2);
41027
41098
  }
41028
41099
  /** 读缓存的公钥;无缓存 / 损坏 → null(调用方决定是否触发拉取) */
41029
41100
  read() {
@@ -41062,8 +41133,8 @@ init_protocol();
41062
41133
 
41063
41134
  // src/session/fork.ts
41064
41135
  var import_node_fs28 = __toESM(require("fs"), 1);
41065
- var import_node_os14 = __toESM(require("os"), 1);
41066
- var import_node_path29 = __toESM(require("path"), 1);
41136
+ var import_node_os15 = __toESM(require("os"), 1);
41137
+ var import_node_path30 = __toESM(require("path"), 1);
41067
41138
  init_claude_history();
41068
41139
  function readJsonlEntries(file) {
41069
41140
  const raw = import_node_fs28.default.readFileSync(file, "utf8");
@@ -41079,9 +41150,9 @@ function readJsonlEntries(file) {
41079
41150
  return out;
41080
41151
  }
41081
41152
  function forkSession(input) {
41082
- const baseDir = input.baseDir ?? import_node_path29.default.join(import_node_os14.default.homedir(), ".claude");
41083
- const projectDir = import_node_path29.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
41084
- const sourceFile = import_node_path29.default.join(projectDir, `${input.toolSessionId}.jsonl`);
41153
+ const baseDir = input.baseDir ?? import_node_path30.default.join(import_node_os15.default.homedir(), ".claude");
41154
+ const projectDir = import_node_path30.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
41155
+ const sourceFile = import_node_path30.default.join(projectDir, `${input.toolSessionId}.jsonl`);
41085
41156
  if (!import_node_fs28.default.existsSync(sourceFile)) {
41086
41157
  throw new Error(`fork: source transcript not found: ${sourceFile}`);
41087
41158
  }
@@ -41112,7 +41183,7 @@ function forkSession(input) {
41112
41183
  }
41113
41184
  forkedLines.push(JSON.stringify(forked));
41114
41185
  }
41115
- const forkedFilePath = import_node_path29.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
41186
+ const forkedFilePath = import_node_path30.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
41116
41187
  import_node_fs28.default.mkdirSync(projectDir, { recursive: true });
41117
41188
  import_node_fs28.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
41118
41189
  return { forkedToolSessionId, forkedFilePath };
@@ -41490,7 +41561,7 @@ function buildPermissionHandlers(deps) {
41490
41561
  }
41491
41562
 
41492
41563
  // src/handlers/history.ts
41493
- var path40 = __toESM(require("path"), 1);
41564
+ var path41 = __toESM(require("path"), 1);
41494
41565
  init_protocol();
41495
41566
 
41496
41567
  // src/session/recent-dirs.ts
@@ -41508,7 +41579,7 @@ function listRecentDirs(store, limit = 50) {
41508
41579
  }
41509
41580
 
41510
41581
  // src/permission/persona-paths.ts
41511
- var path39 = __toESM(require("path"), 1);
41582
+ var path40 = __toESM(require("path"), 1);
41512
41583
  function getAllowedPersonaIds(grants, action) {
41513
41584
  const ids = /* @__PURE__ */ new Set();
41514
41585
  for (const g2 of grants) {
@@ -41521,31 +41592,31 @@ function getAllowedPersonaIds(grants, action) {
41521
41592
  return ids;
41522
41593
  }
41523
41594
  function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
41524
- const target = path39.resolve(absPath);
41595
+ const target = path40.resolve(absPath);
41525
41596
  if (userWorkDir) {
41526
- const u = path39.resolve(userWorkDir);
41527
- const usep = u.endsWith(path39.sep) ? "" : path39.sep;
41597
+ const u = path40.resolve(userWorkDir);
41598
+ const usep = u.endsWith(path40.sep) ? "" : path40.sep;
41528
41599
  if (target === u || target.startsWith(u + usep)) return true;
41529
41600
  }
41530
- const root = path39.resolve(personaRoot);
41531
- const sep2 = root.endsWith(path39.sep) ? "" : path39.sep;
41601
+ const root = path40.resolve(personaRoot);
41602
+ const sep2 = root.endsWith(path40.sep) ? "" : path40.sep;
41532
41603
  if (!target.startsWith(root + sep2)) return false;
41533
- const rel = path39.relative(root, target);
41604
+ const rel = path40.relative(root, target);
41534
41605
  if (!rel || rel.startsWith("..")) return false;
41535
- const personaId = rel.split(path39.sep)[0];
41606
+ const personaId = rel.split(path40.sep)[0];
41536
41607
  if (!personaId) return false;
41537
41608
  const allowed = getAllowedPersonaIds(grants, action);
41538
41609
  if (allowed === "*") return true;
41539
41610
  return allowed.has(personaId);
41540
41611
  }
41541
41612
  function personaIdFromPath(absPath, personaRoot) {
41542
- const root = path39.resolve(personaRoot);
41543
- const target = path39.resolve(absPath);
41544
- const sep2 = root.endsWith(path39.sep) ? "" : path39.sep;
41613
+ const root = path40.resolve(personaRoot);
41614
+ const target = path40.resolve(absPath);
41615
+ const sep2 = root.endsWith(path40.sep) ? "" : path40.sep;
41545
41616
  if (!target.startsWith(root + sep2)) return null;
41546
- const rel = path39.relative(root, target);
41617
+ const rel = path40.relative(root, target);
41547
41618
  if (!rel || rel.startsWith("..")) return null;
41548
- const id = rel.split(path39.sep)[0];
41619
+ const id = rel.split(path40.sep)[0];
41549
41620
  return id || null;
41550
41621
  }
41551
41622
 
@@ -41572,7 +41643,7 @@ function buildHistoryHandlers(deps) {
41572
41643
  if (!pid) return false;
41573
41644
  return isGuestPathAllowed(
41574
41645
  ctx.grants,
41575
- path40.join(personaRoot, pid),
41646
+ path41.join(personaRoot, pid),
41576
41647
  personaRoot,
41577
41648
  "read",
41578
41649
  userWorkDir
@@ -41584,7 +41655,7 @@ function buildHistoryHandlers(deps) {
41584
41655
  };
41585
41656
  const list = async (frame, _client, ctx) => {
41586
41657
  const args = HistoryListArgs.parse(frame);
41587
- assertGuestPath(ctx, path40.resolve(args.projectPath), personaRoot, "history:list");
41658
+ assertGuestPath(ctx, path41.resolve(args.projectPath), personaRoot, "history:list");
41588
41659
  const sessions = await history.listSessions(args);
41589
41660
  return { response: { type: "history:list", sessions } };
41590
41661
  };
@@ -41616,13 +41687,13 @@ function buildHistoryHandlers(deps) {
41616
41687
  };
41617
41688
  const subagents = async (frame, _client, ctx) => {
41618
41689
  const args = HistorySubagentsArgs.parse(frame);
41619
- assertGuestPath(ctx, path40.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
41690
+ assertGuestPath(ctx, path41.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
41620
41691
  const subs = await history.listSubagents(args);
41621
41692
  return { response: { type: "history:subagents", subagents: subs } };
41622
41693
  };
41623
41694
  const subagentRead = async (frame, _client, ctx) => {
41624
41695
  const args = HistorySubagentReadArgs.parse(frame);
41625
- assertGuestPath(ctx, path40.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
41696
+ assertGuestPath(ctx, path41.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
41626
41697
  const res = await history.readSubagent(args);
41627
41698
  return { response: { type: "history:subagent-read", ...res } };
41628
41699
  };
@@ -41631,7 +41702,7 @@ function buildHistoryHandlers(deps) {
41631
41702
  if (ctx?.principal.kind === "guest" && personaRoot) {
41632
41703
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
41633
41704
  const filtered = dirs.filter(
41634
- (d) => isGuestPathAllowed(ctx.grants, path40.resolve(d.cwd), personaRoot, "read", userWorkDir)
41705
+ (d) => isGuestPathAllowed(ctx.grants, path41.resolve(d.cwd), personaRoot, "read", userWorkDir)
41635
41706
  );
41636
41707
  return { response: { type: "history:recentDirs", dirs: filtered } };
41637
41708
  }
@@ -41648,8 +41719,8 @@ function buildHistoryHandlers(deps) {
41648
41719
  }
41649
41720
 
41650
41721
  // src/handlers/workspace.ts
41651
- var path41 = __toESM(require("path"), 1);
41652
- var os15 = __toESM(require("os"), 1);
41722
+ var path42 = __toESM(require("path"), 1);
41723
+ var os16 = __toESM(require("os"), 1);
41653
41724
  init_protocol();
41654
41725
  init_protocol();
41655
41726
  function buildEnabledPluginNames(personaManager, personaId) {
@@ -41689,23 +41760,23 @@ function buildWorkspaceHandlers(deps) {
41689
41760
  const list = async (frame, _client, ctx) => {
41690
41761
  const args = WorkspaceListArgs.parse(frame);
41691
41762
  const isGuest = ctx?.principal.kind === "guest";
41692
- const fallbackCwd = isGuest && personaRoot ? personaRoot : os15.homedir();
41693
- const resolvedCwd = path41.resolve(args.cwd ?? fallbackCwd);
41694
- const target = args.path ? path41.resolve(resolvedCwd, args.path) : resolvedCwd;
41763
+ const fallbackCwd = isGuest && personaRoot ? personaRoot : os16.homedir();
41764
+ const resolvedCwd = path42.resolve(args.cwd ?? fallbackCwd);
41765
+ const target = args.path ? path42.resolve(resolvedCwd, args.path) : resolvedCwd;
41695
41766
  assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
41696
41767
  const res = workspace.list({ ...args, cwd: resolvedCwd });
41697
41768
  return { response: { type: "workspace:list", ...res } };
41698
41769
  };
41699
41770
  const read = async (frame, _client, ctx) => {
41700
41771
  const args = WorkspaceReadArgs.parse(frame);
41701
- const target = path41.isAbsolute(args.path) ? path41.resolve(args.path) : path41.resolve(args.cwd, args.path);
41772
+ const target = path42.isAbsolute(args.path) ? path42.resolve(args.path) : path42.resolve(args.cwd, args.path);
41702
41773
  assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
41703
41774
  const res = workspace.read(args);
41704
41775
  return { response: { type: "workspace:read", ...res } };
41705
41776
  };
41706
41777
  const skillsList = async (frame, _client, ctx) => {
41707
41778
  const args = SkillsListArgs.parse(frame);
41708
- const cwdAbs = path41.resolve(args.cwd);
41779
+ const cwdAbs = path42.resolve(args.cwd);
41709
41780
  assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
41710
41781
  const list2 = await getSkillsForTool(args.tool ?? "claude", cwdAbs);
41711
41782
  if (ctx?.principal.kind === "guest" && personaRoot) {
@@ -41717,7 +41788,7 @@ function buildWorkspaceHandlers(deps) {
41717
41788
  };
41718
41789
  const agentsList = async (frame, _client, ctx) => {
41719
41790
  const args = AgentsListArgs.parse(frame);
41720
- const cwdAbs = path41.resolve(args.cwd);
41791
+ const cwdAbs = path42.resolve(args.cwd);
41721
41792
  assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
41722
41793
  if (args.tool === "codex") {
41723
41794
  return { response: { type: "agents:list", agents: [] } };
@@ -41739,18 +41810,18 @@ function buildWorkspaceHandlers(deps) {
41739
41810
  }
41740
41811
 
41741
41812
  // src/handlers/git.ts
41742
- var path43 = __toESM(require("path"), 1);
41813
+ var path44 = __toESM(require("path"), 1);
41743
41814
  init_protocol();
41744
41815
  init_protocol();
41745
41816
 
41746
41817
  // src/workspace/git.ts
41747
41818
  var import_node_child_process10 = require("child_process");
41748
41819
  var import_node_fs29 = __toESM(require("fs"), 1);
41749
- var import_node_path30 = __toESM(require("path"), 1);
41820
+ var import_node_path31 = __toESM(require("path"), 1);
41750
41821
  var import_node_util = require("util");
41751
41822
  var pexec = (0, import_node_util.promisify)(import_node_child_process10.execFile);
41752
41823
  function normalizePath(p2) {
41753
- const resolved = import_node_path30.default.resolve(p2);
41824
+ const resolved = import_node_path31.default.resolve(p2);
41754
41825
  try {
41755
41826
  return import_node_fs29.default.realpathSync(resolved);
41756
41827
  } catch {
@@ -41826,7 +41897,7 @@ async function listGitBranches(cwd) {
41826
41897
  function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
41827
41898
  if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
41828
41899
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
41829
- if (!isGuestPathAllowed(ctx.grants, path43.resolve(cwd), personaRoot, "read", userWorkDir)) {
41900
+ if (!isGuestPathAllowed(ctx.grants, path44.resolve(cwd), personaRoot, "read", userWorkDir)) {
41830
41901
  throw new ClawdError(
41831
41902
  ERROR_CODES.UNAUTHORIZED,
41832
41903
  `guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
@@ -42214,7 +42285,7 @@ function buildDeviceHandlers(deps) {
42214
42285
  }
42215
42286
 
42216
42287
  // src/handlers/meta.ts
42217
- var import_node_os15 = __toESM(require("os"), 1);
42288
+ var import_node_os16 = __toESM(require("os"), 1);
42218
42289
  init_protocol();
42219
42290
 
42220
42291
  // src/version.ts
@@ -42245,7 +42316,7 @@ function buildReadyFrame(deps, client) {
42245
42316
  return {
42246
42317
  version,
42247
42318
  protocolVersion: PROTOCOL_VERSION,
42248
- hostname: import_node_os15.default.hostname(),
42319
+ hostname: import_node_os16.default.hostname(),
42249
42320
  os: process.platform,
42250
42321
  tools,
42251
42322
  runningSessions: info.runningSessions,
@@ -42340,7 +42411,7 @@ function buildPersonaHandlers(deps) {
42340
42411
  }
42341
42412
 
42342
42413
  // src/handlers/attachment.ts
42343
- var import_node_path31 = __toESM(require("path"), 1);
42414
+ var import_node_path32 = __toESM(require("path"), 1);
42344
42415
  init_protocol();
42345
42416
  init_protocol();
42346
42417
  var DEFAULT_TTL_SECONDS = 24 * 3600;
@@ -42395,12 +42466,12 @@ function buildAttachmentHandlers(deps) {
42395
42466
  `session ${args.sessionId} scope unresolved`
42396
42467
  );
42397
42468
  }
42398
- const cwdAbs = import_node_path31.default.resolve(sessionFile.cwd);
42399
- const candidateAbs = import_node_path31.default.isAbsolute(args.relPath) ? import_node_path31.default.resolve(args.relPath) : import_node_path31.default.resolve(cwdAbs, args.relPath);
42469
+ const cwdAbs = import_node_path32.default.resolve(sessionFile.cwd);
42470
+ const candidateAbs = import_node_path32.default.isAbsolute(args.relPath) ? import_node_path32.default.resolve(args.relPath) : import_node_path32.default.resolve(cwdAbs, args.relPath);
42400
42471
  assertGuestAttachmentPath(ctx, candidateAbs, deps.personaRoot, "attachment.signUrl", deps.usersRoot);
42401
42472
  const entries = deps.groupFileStore.list(scope, args.sessionId);
42402
42473
  const entry = entries.find((e) => {
42403
- const storedAbs = import_node_path31.default.isAbsolute(e.relPath) ? import_node_path31.default.resolve(e.relPath) : import_node_path31.default.resolve(cwdAbs, e.relPath);
42474
+ const storedAbs = import_node_path32.default.isAbsolute(e.relPath) ? import_node_path32.default.resolve(e.relPath) : import_node_path32.default.resolve(cwdAbs, e.relPath);
42404
42475
  return storedAbs === candidateAbs && !e.stale;
42405
42476
  });
42406
42477
  if (!entry) {
@@ -42424,7 +42495,7 @@ function buildAttachmentHandlers(deps) {
42424
42495
  if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
42425
42496
  const f = deps.sessionStore.read(sessionId);
42426
42497
  if (!f) return;
42427
- assertGuestAttachmentPath(ctx, import_node_path31.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
42498
+ assertGuestAttachmentPath(ctx, import_node_path32.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
42428
42499
  }
42429
42500
  const groupAdd = async (frame, _client, ctx) => {
42430
42501
  if (!deps.groupFileStore || !deps.getSessionScope) {
@@ -42496,19 +42567,19 @@ function buildAttachmentHandlers(deps) {
42496
42567
 
42497
42568
  // src/handlers/extension.ts
42498
42569
  var import_promises7 = __toESM(require("fs/promises"), 1);
42499
- var import_node_path36 = __toESM(require("path"), 1);
42570
+ var import_node_path37 = __toESM(require("path"), 1);
42500
42571
  init_protocol();
42501
42572
 
42502
42573
  // src/extension/bundle-zip.ts
42503
42574
  var import_promises4 = __toESM(require("fs/promises"), 1);
42504
- var import_node_path32 = __toESM(require("path"), 1);
42575
+ var import_node_path33 = __toESM(require("path"), 1);
42505
42576
  var import_node_crypto11 = __toESM(require("crypto"), 1);
42506
42577
  var import_jszip2 = __toESM(require_lib3(), 1);
42507
42578
  async function bundleExtensionDir(dir) {
42508
42579
  const entries = await listFilesSorted(dir);
42509
42580
  const zip = new import_jszip2.default();
42510
42581
  for (const rel of entries) {
42511
- const abs = import_node_path32.default.join(dir, rel);
42582
+ const abs = import_node_path33.default.join(dir, rel);
42512
42583
  const content = await import_promises4.default.readFile(abs);
42513
42584
  zip.file(rel, content, { date: FIXED_DATE });
42514
42585
  }
@@ -42529,7 +42600,7 @@ async function listFilesSorted(rootDir) {
42529
42600
  return out;
42530
42601
  }
42531
42602
  async function walk(absRoot, relPrefix, out) {
42532
- const dirAbs = import_node_path32.default.join(absRoot, relPrefix);
42603
+ const dirAbs = import_node_path33.default.join(absRoot, relPrefix);
42533
42604
  const entries = await import_promises4.default.readdir(dirAbs, { withFileTypes: true });
42534
42605
  for (const e of entries) {
42535
42606
  if (IGNORE_BASENAMES.has(e.name)) continue;
@@ -42583,25 +42654,25 @@ function computePublishCheck(args) {
42583
42654
 
42584
42655
  // src/extension/install-flow.ts
42585
42656
  var import_promises5 = __toESM(require("fs/promises"), 1);
42586
- var import_node_path34 = __toESM(require("path"), 1);
42587
- var import_node_os17 = __toESM(require("os"), 1);
42657
+ var import_node_path35 = __toESM(require("path"), 1);
42658
+ var import_node_os18 = __toESM(require("os"), 1);
42588
42659
  var import_node_crypto12 = __toESM(require("crypto"), 1);
42589
42660
  var import_jszip3 = __toESM(require_lib3(), 1);
42590
42661
 
42591
42662
  // src/extension/paths.ts
42592
- var import_node_os16 = __toESM(require("os"), 1);
42593
- var import_node_path33 = __toESM(require("path"), 1);
42663
+ var import_node_os17 = __toESM(require("os"), 1);
42664
+ var import_node_path34 = __toESM(require("path"), 1);
42594
42665
  function clawdHomeRoot(override) {
42595
- return override ?? process.env.CLAWD_HOME ?? import_node_path33.default.join(import_node_os16.default.homedir(), ".clawd");
42666
+ return override ?? process.env.CLAWD_HOME ?? import_node_path34.default.join(import_node_os17.default.homedir(), ".clawd");
42596
42667
  }
42597
42668
  function extensionsRoot(override) {
42598
- return import_node_path33.default.join(clawdHomeRoot(override), "extensions");
42669
+ return import_node_path34.default.join(clawdHomeRoot(override), "extensions");
42599
42670
  }
42600
42671
  function publishedChannelsFile(override) {
42601
- return import_node_path33.default.join(clawdHomeRoot(override), "extensions-published.json");
42672
+ return import_node_path34.default.join(clawdHomeRoot(override), "extensions-published.json");
42602
42673
  }
42603
42674
  function bundleCacheRoot(override) {
42604
- return import_node_path33.default.join(clawdHomeRoot(override), "extension-bundles");
42675
+ return import_node_path34.default.join(clawdHomeRoot(override), "extension-bundles");
42605
42676
  }
42606
42677
 
42607
42678
  // src/extension/install-flow.ts
@@ -42628,7 +42699,7 @@ async function installFromChannel(args, deps) {
42628
42699
  throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
42629
42700
  }
42630
42701
  for (const name of Object.keys(zip.files)) {
42631
- if (name.includes("..") || name.startsWith("/") || import_node_path34.default.isAbsolute(name)) {
42702
+ if (name.includes("..") || name.startsWith("/") || import_node_path35.default.isAbsolute(name)) {
42632
42703
  throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
42633
42704
  }
42634
42705
  }
@@ -42660,7 +42731,7 @@ async function installFromChannel(args, deps) {
42660
42731
  );
42661
42732
  }
42662
42733
  const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
42663
- const destDir = import_node_path34.default.join(deps.extensionsRoot, localExtId);
42734
+ const destDir = import_node_path35.default.join(deps.extensionsRoot, localExtId);
42664
42735
  let destExists = false;
42665
42736
  try {
42666
42737
  await import_promises5.default.access(destDir);
@@ -42674,16 +42745,16 @@ async function installFromChannel(args, deps) {
42674
42745
  );
42675
42746
  }
42676
42747
  const stage = await import_promises5.default.mkdtemp(
42677
- import_node_path34.default.join(import_node_os17.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
42748
+ import_node_path35.default.join(import_node_os18.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
42678
42749
  );
42679
42750
  try {
42680
42751
  for (const [name, entry] of Object.entries(zip.files)) {
42681
- const dest = import_node_path34.default.join(stage, name);
42752
+ const dest = import_node_path35.default.join(stage, name);
42682
42753
  if (entry.dir) {
42683
42754
  await import_promises5.default.mkdir(dest, { recursive: true });
42684
42755
  continue;
42685
42756
  }
42686
- await import_promises5.default.mkdir(import_node_path34.default.dirname(dest), { recursive: true });
42757
+ await import_promises5.default.mkdir(import_node_path35.default.dirname(dest), { recursive: true });
42687
42758
  if (name === "manifest.json") {
42688
42759
  const rewritten = { ...parsed.data, id: localExtId };
42689
42760
  await import_promises5.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
@@ -42704,8 +42775,8 @@ async function installFromChannel(args, deps) {
42704
42775
 
42705
42776
  // src/extension/update-flow.ts
42706
42777
  var import_promises6 = __toESM(require("fs/promises"), 1);
42707
- var import_node_path35 = __toESM(require("path"), 1);
42708
- var import_node_os18 = __toESM(require("os"), 1);
42778
+ var import_node_path36 = __toESM(require("path"), 1);
42779
+ var import_node_os19 = __toESM(require("os"), 1);
42709
42780
  var import_node_crypto13 = __toESM(require("crypto"), 1);
42710
42781
  var import_jszip4 = __toESM(require_lib3(), 1);
42711
42782
  var UpdateError = class extends Error {
@@ -42721,11 +42792,11 @@ async function updateFromChannel(args, deps) {
42721
42792
  channelRef.extId,
42722
42793
  channelRef.ownerPrincipalId
42723
42794
  );
42724
- const liveDir = import_node_path35.default.join(deps.extensionsRoot, localExtId);
42795
+ const liveDir = import_node_path36.default.join(deps.extensionsRoot, localExtId);
42725
42796
  const prevDir = `${liveDir}.prev`;
42726
42797
  let existingVersion;
42727
42798
  try {
42728
- const raw = await import_promises6.default.readFile(import_node_path35.default.join(liveDir, "manifest.json"), "utf8");
42799
+ const raw = await import_promises6.default.readFile(import_node_path36.default.join(liveDir, "manifest.json"), "utf8");
42729
42800
  const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
42730
42801
  if (!parsed2.success) {
42731
42802
  throw new UpdateError(
@@ -42758,7 +42829,7 @@ async function updateFromChannel(args, deps) {
42758
42829
  throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
42759
42830
  }
42760
42831
  for (const name of Object.keys(zip.files)) {
42761
- if (name.includes("..") || name.startsWith("/") || import_node_path35.default.isAbsolute(name)) {
42832
+ if (name.includes("..") || name.startsWith("/") || import_node_path36.default.isAbsolute(name)) {
42762
42833
  throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
42763
42834
  }
42764
42835
  }
@@ -42793,16 +42864,16 @@ async function updateFromChannel(args, deps) {
42793
42864
  await import_promises6.default.rm(prevDir, { recursive: true, force: true });
42794
42865
  await import_promises6.default.rename(liveDir, prevDir);
42795
42866
  const stage = await import_promises6.default.mkdtemp(
42796
- import_node_path35.default.join(import_node_os18.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
42867
+ import_node_path36.default.join(import_node_os19.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
42797
42868
  );
42798
42869
  try {
42799
42870
  for (const [name, entry] of Object.entries(zip.files)) {
42800
- const dest = import_node_path35.default.join(stage, name);
42871
+ const dest = import_node_path36.default.join(stage, name);
42801
42872
  if (entry.dir) {
42802
42873
  await import_promises6.default.mkdir(dest, { recursive: true });
42803
42874
  continue;
42804
42875
  }
42805
- await import_promises6.default.mkdir(import_node_path35.default.dirname(dest), { recursive: true });
42876
+ await import_promises6.default.mkdir(import_node_path36.default.dirname(dest), { recursive: true });
42806
42877
  if (name === "manifest.json") {
42807
42878
  const rewritten = { ...parsed.data, id: localExtId };
42808
42879
  await import_promises6.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
@@ -42895,7 +42966,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
42895
42966
  );
42896
42967
  }
42897
42968
  }
42898
- const manifestPath = import_node_path36.default.join(root, extId, "manifest.json");
42969
+ const manifestPath = import_node_path37.default.join(root, extId, "manifest.json");
42899
42970
  const manifest = await readManifest(root, extId);
42900
42971
  const next = { ...manifest, version: newVersion };
42901
42972
  const tmp = `${manifestPath}.tmp`;
@@ -42903,7 +42974,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
42903
42974
  await import_promises7.default.rename(tmp, manifestPath);
42904
42975
  }
42905
42976
  async function readManifest(root, extId) {
42906
- const file = import_node_path36.default.join(root, extId, "manifest.json");
42977
+ const file = import_node_path37.default.join(root, extId, "manifest.json");
42907
42978
  let raw;
42908
42979
  try {
42909
42980
  raw = await import_promises7.default.readFile(file, "utf8");
@@ -42994,7 +43065,7 @@ function buildExtensionHandlers(deps) {
42994
43065
  };
42995
43066
  async function buildSnapshotMeta(extId) {
42996
43067
  const manifest = await readManifest(deps.root, extId);
42997
- const { sha256, buffer } = await bundleExtensionDir(import_node_path36.default.join(deps.root, extId));
43068
+ const { sha256, buffer } = await bundleExtensionDir(import_node_path37.default.join(deps.root, extId));
42998
43069
  return { manifest, contentHash: sha256, buffer };
42999
43070
  }
43000
43071
  const publish = async (frame, _client, ctx) => {
@@ -43291,7 +43362,7 @@ var PublishJobRegistry = class {
43291
43362
  // src/app-builder/publish-job-runner.ts
43292
43363
  var import_node_child_process12 = require("child_process");
43293
43364
  var import_node_fs30 = require("fs");
43294
- var import_node_path37 = require("path");
43365
+ var import_node_path38 = require("path");
43295
43366
 
43296
43367
  // src/app-builder/publish-stage-parser.ts
43297
43368
  var STAGE_RE = /^\s*::stage::(build|deploy|verify)\s*$/;
@@ -43323,7 +43394,7 @@ async function startPublishJob(deps, args) {
43323
43394
  return { jobId: registry2.get(args.name).jobId, status: "already-publishing" };
43324
43395
  }
43325
43396
  const projDir = projectDir(args.name);
43326
- const logPath = (0, import_node_path37.join)(projDir, ".publish.log");
43397
+ const logPath = (0, import_node_path38.join)(projDir, ".publish.log");
43327
43398
  let logStream = null;
43328
43399
  try {
43329
43400
  logStream = (0, import_node_fs30.createWriteStream)(logPath, { flags: "w" });
@@ -43583,7 +43654,7 @@ async function recoverInterruptedJobs(deps) {
43583
43654
 
43584
43655
  // src/handlers/app-builder.ts
43585
43656
  init_protocol();
43586
- var import_node_path38 = require("path");
43657
+ var import_node_path39 = require("path");
43587
43658
  var import_node_fs31 = require("fs");
43588
43659
  var APP_BUILDER_PERSONAS = ["persona-app-builder"];
43589
43660
  var PUBLISH_SCRIPT_REL = "extension-kit/scripts/publish.sh";
@@ -43960,7 +44031,7 @@ function buildAppBuilderHandlers(deps) {
43960
44031
  });
43961
44032
  await userStore.clearPublishJob(args.name);
43962
44033
  }
43963
- const scriptPath = (0, import_node_path38.join)(deps.personaRoot, PUBLISH_SCRIPT_REL);
44034
+ const scriptPath = (0, import_node_path39.join)(deps.personaRoot, PUBLISH_SCRIPT_REL);
43964
44035
  deps.logger?.info("app-builder.publish.start", {
43965
44036
  name: args.name,
43966
44037
  sessionId: boundSession.sessionId,
@@ -44054,7 +44125,7 @@ function buildAppBuilderHandlers(deps) {
44054
44125
 
44055
44126
  // src/extension/registry.ts
44056
44127
  var import_promises8 = __toESM(require("fs/promises"), 1);
44057
- var import_node_path39 = __toESM(require("path"), 1);
44128
+ var import_node_path40 = __toESM(require("path"), 1);
44058
44129
  async function loadAll(root) {
44059
44130
  let entries;
44060
44131
  try {
@@ -44067,13 +44138,13 @@ async function loadAll(root) {
44067
44138
  for (const ent of entries) {
44068
44139
  if (!ent.isDirectory()) continue;
44069
44140
  if (ent.name.startsWith(".")) continue;
44070
- records.push(await loadOne(import_node_path39.default.join(root, ent.name), ent.name));
44141
+ records.push(await loadOne(import_node_path40.default.join(root, ent.name), ent.name));
44071
44142
  }
44072
44143
  records.sort((a, b2) => a.extId < b2.extId ? -1 : a.extId > b2.extId ? 1 : 0);
44073
44144
  return records;
44074
44145
  }
44075
44146
  async function loadOne(dir, dirName) {
44076
- const manifestPath = import_node_path39.default.join(dir, "manifest.json");
44147
+ const manifestPath = import_node_path40.default.join(dir, "manifest.json");
44077
44148
  let raw;
44078
44149
  try {
44079
44150
  raw = await import_promises8.default.readFile(manifestPath, "utf8");
@@ -44118,7 +44189,7 @@ async function loadOne(dir, dirName) {
44118
44189
 
44119
44190
  // src/extension/uninstall.ts
44120
44191
  var import_promises9 = __toESM(require("fs/promises"), 1);
44121
- var import_node_path40 = __toESM(require("path"), 1);
44192
+ var import_node_path41 = __toESM(require("path"), 1);
44122
44193
  var UninstallError = class extends Error {
44123
44194
  constructor(code, message) {
44124
44195
  super(message);
@@ -44127,7 +44198,7 @@ var UninstallError = class extends Error {
44127
44198
  code;
44128
44199
  };
44129
44200
  async function uninstall(deps) {
44130
- const dir = import_node_path40.default.join(deps.root, deps.extId);
44201
+ const dir = import_node_path41.default.join(deps.root, deps.extId);
44131
44202
  try {
44132
44203
  await import_promises9.default.access(dir);
44133
44204
  } catch {
@@ -44208,7 +44279,7 @@ function buildMethodHandlers(deps) {
44208
44279
  // src/app-builder/project-store.ts
44209
44280
  var import_node_fs32 = require("fs");
44210
44281
  var import_node_child_process13 = require("child_process");
44211
- var import_node_path41 = require("path");
44282
+ var import_node_path42 = require("path");
44212
44283
  init_protocol();
44213
44284
  var PROJECTS_DIR = "projects";
44214
44285
  var META_FILE = ".clawd-project.json";
@@ -44223,14 +44294,14 @@ var ProjectStore = class {
44223
44294
  root;
44224
44295
  /** projects/<name>/.clawd-project.json 路径 */
44225
44296
  metaPath(name) {
44226
- return (0, import_node_path41.join)(this.projectsRoot(), name, META_FILE);
44297
+ return (0, import_node_path42.join)(this.projectsRoot(), name, META_FILE);
44227
44298
  }
44228
44299
  /** projects/<name>/ 目录路径(cwd 用) */
44229
44300
  projectDir(name) {
44230
- return (0, import_node_path41.join)(this.projectsRoot(), name);
44301
+ return (0, import_node_path42.join)(this.projectsRoot(), name);
44231
44302
  }
44232
44303
  projectsRoot() {
44233
- return (0, import_node_path41.join)(this.root, PROJECTS_DIR);
44304
+ return (0, import_node_path42.join)(this.root, PROJECTS_DIR);
44234
44305
  }
44235
44306
  async list() {
44236
44307
  let entries;
@@ -44311,7 +44382,7 @@ var ProjectStore = class {
44311
44382
  * 代码再参考"。assistant 进 project 时目录已是完整模板,直接 pnpm install 即可。
44312
44383
  */
44313
44384
  async scaffold(name, template = DEFAULT_TEMPLATE, personaRoot = this.root) {
44314
- const scriptPath = (0, import_node_path41.join)(personaRoot, SCAFFOLD_SCRIPT_REL);
44385
+ const scriptPath = (0, import_node_path42.join)(personaRoot, SCAFFOLD_SCRIPT_REL);
44315
44386
  const destDir = this.projectDir(name);
44316
44387
  return await new Promise((resolve6, reject) => {
44317
44388
  const child = (0, import_node_child_process13.spawn)("bash", [scriptPath, name, template, destDir], {
@@ -44849,7 +44920,7 @@ function computeGrantForFrame(method, frame) {
44849
44920
 
44850
44921
  // src/extension/runtime.ts
44851
44922
  var import_node_child_process15 = require("child_process");
44852
- var import_node_path42 = __toESM(require("path"), 1);
44923
+ var import_node_path43 = __toESM(require("path"), 1);
44853
44924
  var import_promises10 = require("timers/promises");
44854
44925
 
44855
44926
  // src/extension/port-allocator.ts
@@ -44950,7 +45021,7 @@ var Runtime = class {
44950
45021
  /\$CLAWOS_EXT_PORT/g,
44951
45022
  String(port)
44952
45023
  );
44953
- const dir = import_node_path42.default.join(this.root, extId);
45024
+ const dir = import_node_path43.default.join(this.root, extId);
44954
45025
  const env = {
44955
45026
  ...process.env,
44956
45027
  CLAWOS_EXT_PORT: String(port),
@@ -45062,7 +45133,7 @@ ${handle.stderrTail}`
45062
45133
 
45063
45134
  // src/extension/published-channels.ts
45064
45135
  var import_promises11 = __toESM(require("fs/promises"), 1);
45065
- var import_node_path43 = __toESM(require("path"), 1);
45136
+ var import_node_path44 = __toESM(require("path"), 1);
45066
45137
  init_zod();
45067
45138
  var PublishedChannelsError = class extends Error {
45068
45139
  constructor(code, message) {
@@ -45161,7 +45232,7 @@ var PublishedChannelStore = class {
45161
45232
  )
45162
45233
  };
45163
45234
  const tmp = `${this.filePath}.tmp`;
45164
- await import_promises11.default.mkdir(import_node_path43.default.dirname(this.filePath), { recursive: true });
45235
+ await import_promises11.default.mkdir(import_node_path44.default.dirname(this.filePath), { recursive: true });
45165
45236
  await import_promises11.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
45166
45237
  await import_promises11.default.rename(tmp, this.filePath);
45167
45238
  }
@@ -45169,7 +45240,7 @@ var PublishedChannelStore = class {
45169
45240
 
45170
45241
  // src/extension/bundle-cache.ts
45171
45242
  var import_promises12 = __toESM(require("fs/promises"), 1);
45172
- var import_node_path44 = __toESM(require("path"), 1);
45243
+ var import_node_path45 = __toESM(require("path"), 1);
45173
45244
  var BundleCache = class {
45174
45245
  constructor(rootDir) {
45175
45246
  this.rootDir = rootDir;
@@ -45178,14 +45249,14 @@ var BundleCache = class {
45178
45249
  /** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
45179
45250
  async write(snapshotHash, buffer) {
45180
45251
  await import_promises12.default.mkdir(this.rootDir, { recursive: true });
45181
- const file = import_node_path44.default.join(this.rootDir, `${snapshotHash}.zip`);
45252
+ const file = import_node_path45.default.join(this.rootDir, `${snapshotHash}.zip`);
45182
45253
  const tmp = `${file}.tmp`;
45183
45254
  await import_promises12.default.writeFile(tmp, buffer, { mode: 384 });
45184
45255
  await import_promises12.default.rename(tmp, file);
45185
45256
  }
45186
45257
  /** Returns the bundle bytes, or null when the file doesn't exist. */
45187
45258
  async read(snapshotHash) {
45188
- const file = import_node_path44.default.join(this.rootDir, `${snapshotHash}.zip`);
45259
+ const file = import_node_path45.default.join(this.rootDir, `${snapshotHash}.zip`);
45189
45260
  try {
45190
45261
  return await import_promises12.default.readFile(file);
45191
45262
  } catch (e) {
@@ -45195,7 +45266,7 @@ var BundleCache = class {
45195
45266
  }
45196
45267
  /** Idempotent — missing file is not an error. */
45197
45268
  async delete(snapshotHash) {
45198
- const file = import_node_path44.default.join(this.rootDir, `${snapshotHash}.zip`);
45269
+ const file = import_node_path45.default.join(this.rootDir, `${snapshotHash}.zip`);
45199
45270
  await import_promises12.default.rm(file, { force: true });
45200
45271
  }
45201
45272
  };
@@ -45204,7 +45275,7 @@ var BundleCache = class {
45204
45275
  async function startDaemon(config) {
45205
45276
  const logger = createLogger({
45206
45277
  level: config.logLevel,
45207
- file: import_node_path45.default.join(config.dataDir, "clawd.log")
45278
+ file: import_node_path46.default.join(config.dataDir, "clawd.log")
45208
45279
  });
45209
45280
  logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
45210
45281
  const stateMgr = new StateFileManager({ dataDir: config.dataDir });
@@ -45340,8 +45411,8 @@ async function startDaemon(config) {
45340
45411
  const agents = new AgentsScanner();
45341
45412
  const history = new ClaudeHistoryReader();
45342
45413
  let transport = null;
45343
- const personaStore = new PersonaStore(import_node_path45.default.join(config.dataDir, "personas"));
45344
- const usersRoot = import_node_path45.default.join(config.dataDir, "users");
45414
+ const personaStore = new PersonaStore(import_node_path46.default.join(config.dataDir, "personas"));
45415
+ const usersRoot = import_node_path46.default.join(config.dataDir, "users");
45345
45416
  const defaultsRoot = findDefaultsRoot();
45346
45417
  if (defaultsRoot) {
45347
45418
  seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
@@ -45361,7 +45432,7 @@ async function startDaemon(config) {
45361
45432
  getAdapter,
45362
45433
  historyReader: history,
45363
45434
  dataDir: config.dataDir,
45364
- personaRoot: import_node_path45.default.join(config.dataDir, "personas"),
45435
+ personaRoot: import_node_path46.default.join(config.dataDir, "personas"),
45365
45436
  usersRoot,
45366
45437
  personaStore,
45367
45438
  ownerDisplayName,
@@ -45391,7 +45462,7 @@ async function startDaemon(config) {
45391
45462
  // 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
45392
45463
  attachmentGroup: {
45393
45464
  onFileEdit: (input) => {
45394
- const absPath = import_node_path45.default.isAbsolute(input.relPath) ? input.relPath : import_node_path45.default.join(input.cwd, input.relPath);
45465
+ const absPath = import_node_path46.default.isAbsolute(input.relPath) ? input.relPath : import_node_path46.default.join(input.cwd, input.relPath);
45395
45466
  let size = 0;
45396
45467
  try {
45397
45468
  size = import_node_fs33.default.statSync(absPath).size;
@@ -45580,11 +45651,11 @@ async function startDaemon(config) {
45580
45651
  // 'persona/<pid>/owner',default 走 'default'。
45581
45652
  getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
45582
45653
  // guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
45583
- personaRoot: import_node_path45.default.join(config.dataDir, "personas"),
45654
+ personaRoot: import_node_path46.default.join(config.dataDir, "personas"),
45584
45655
  usersRoot
45585
45656
  },
45586
45657
  // workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
45587
- personaRoot: import_node_path45.default.join(config.dataDir, "personas"),
45658
+ personaRoot: import_node_path46.default.join(config.dataDir, "personas"),
45588
45659
  // v2 多人 persona 隔离:handler 派生 guest user-dir 放行
45589
45660
  usersRoot,
45590
45661
  // capability:list / delete handler 依赖
@@ -45673,7 +45744,7 @@ async function startDaemon(config) {
45673
45744
  // 发布上线脚手架化 (spec 2026-06-03 §5.2):
45674
45745
  // appBuilderPersonaRoot 用于拼 publish.sh 绝对路径(persona-app-builder 安装在
45675
45746
  // dataDir/personas/persona-app-builder 之下,extension-kit/scripts/publish.sh 是相对路径)。
45676
- appBuilderPersonaRoot: import_node_path45.default.join(config.dataDir, "personas", "persona-app-builder"),
45747
+ appBuilderPersonaRoot: import_node_path46.default.join(config.dataDir, "personas", "persona-app-builder"),
45677
45748
  // 发布上线脚手架化 (spec 2026-06-03 §5.2.2):
45678
45749
  // 复用 SessionManagerDeps.broadcastFrame 同款 dispatch 逻辑 —— runner 调 manager.send
45679
45750
  // 取回 broadcast 帧后逐帧 push 到 transport,跟 manager 自身的 deps 一致。
@@ -45922,8 +45993,8 @@ async function startDaemon(config) {
45922
45993
  const lines = [
45923
45994
  `Tunnel: ${r.url}`,
45924
45995
  ...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
45925
- `Frpc config: ${import_node_path45.default.join(config.dataDir, "frpc.toml")}`,
45926
- `Frpc log: ${import_node_path45.default.join(config.dataDir, "frpc.log")}`
45996
+ `Frpc config: ${import_node_path46.default.join(config.dataDir, "frpc.toml")}`,
45997
+ `Frpc log: ${import_node_path46.default.join(config.dataDir, "frpc.log")}`
45927
45998
  ];
45928
45999
  const width = Math.max(...lines.map((l) => l.length));
45929
46000
  const bar = "\u2550".repeat(width + 4);
@@ -45936,7 +46007,7 @@ ${bar}
45936
46007
 
45937
46008
  `);
45938
46009
  try {
45939
- const connectPath = import_node_path45.default.join(config.dataDir, "connect.txt");
46010
+ const connectPath = import_node_path46.default.join(config.dataDir, "connect.txt");
45940
46011
  import_node_fs33.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
45941
46012
  } catch {
45942
46013
  }
@@ -46008,7 +46079,7 @@ ${bar}
46008
46079
  };
46009
46080
  }
46010
46081
  function migrateDropPersonsDir(dataDir) {
46011
- const dir = import_node_path45.default.join(dataDir, "persons");
46082
+ const dir = import_node_path46.default.join(dataDir, "persons");
46012
46083
  try {
46013
46084
  import_node_fs33.default.rmSync(dir, { recursive: true, force: true });
46014
46085
  } catch {