@clawos-dev/clawd 0.2.128-beta.255.69495b2 → 0.2.129-beta.256.7cc795b

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 +485 -387
  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: path60, errorMaps, issueData } = params;
724
- const fullPath = [...path60, ...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, path60, key) {
1035
+ constructor(parent, value, path59, key) {
1036
1036
  this._cachedPath = [];
1037
1037
  this.parent = parent;
1038
1038
  this.data = value;
1039
- this._path = path60;
1039
+ this._path = path59;
1040
1040
  this._key = key;
1041
1041
  }
1042
1042
  get path() {
@@ -4523,7 +4523,11 @@ var init_persona_schemas = __esm({
4523
4523
  });
4524
4524
  PersonaSandboxSettingsSchema = external_exports.object({
4525
4525
  permissions: external_exports.object({
4526
- defaultMode: external_exports.string().optional()
4526
+ defaultMode: external_exports.string().optional(),
4527
+ // CC 工具 allowlist('Bash'/'Read'/...)。per-persona profile 在最严格 base 上追加放开。
4528
+ allow: external_exports.array(external_exports.string()).optional(),
4529
+ // deny 优先级最高;强制底座(persona 私密区)由 daemon compose 强制 union,owner 删不掉。
4530
+ deny: external_exports.array(external_exports.string()).optional()
4527
4531
  }).optional(),
4528
4532
  sandbox: external_exports.object({
4529
4533
  enabled: external_exports.boolean().optional(),
@@ -4534,6 +4538,11 @@ var init_persona_schemas = __esm({
4534
4538
  allowRead: external_exports.array(external_exports.string()).optional(),
4535
4539
  denyWrite: external_exports.array(external_exports.string()).optional(),
4536
4540
  allowWrite: external_exports.array(external_exports.string()).optional()
4541
+ }).optional(),
4542
+ // 出站网络 + 本机端口。base 不放(空),profile 按需追加域名(app-builder = ['*'])。
4543
+ network: external_exports.object({
4544
+ allowedDomains: external_exports.array(external_exports.string()).optional(),
4545
+ allowLocalBinding: external_exports.boolean().optional()
4537
4546
  }).optional()
4538
4547
  }).optional()
4539
4548
  });
@@ -6181,8 +6190,8 @@ var require_req = __commonJS({
6181
6190
  if (req.originalUrl) {
6182
6191
  _req.url = req.originalUrl;
6183
6192
  } else {
6184
- const path60 = req.path;
6185
- _req.url = typeof path60 === "string" ? path60 : req.url ? req.url.path || req.url : void 0;
6193
+ const path59 = req.path;
6194
+ _req.url = typeof path59 === "string" ? path59 : req.url ? req.url.path || req.url : void 0;
6186
6195
  }
6187
6196
  if (req.query) {
6188
6197
  _req.query = req.query;
@@ -6347,14 +6356,14 @@ var require_redact = __commonJS({
6347
6356
  }
6348
6357
  return obj;
6349
6358
  }
6350
- function parsePath(path60) {
6359
+ function parsePath(path59) {
6351
6360
  const parts = [];
6352
6361
  let current = "";
6353
6362
  let inBrackets = false;
6354
6363
  let inQuotes = false;
6355
6364
  let quoteChar = "";
6356
- for (let i = 0; i < path60.length; i++) {
6357
- const char = path60[i];
6365
+ for (let i = 0; i < path59.length; i++) {
6366
+ const char = path59[i];
6358
6367
  if (!inBrackets && char === ".") {
6359
6368
  if (current) {
6360
6369
  parts.push(current);
@@ -6485,10 +6494,10 @@ var require_redact = __commonJS({
6485
6494
  return current;
6486
6495
  }
6487
6496
  function redactPaths(obj, paths, censor, remove = false) {
6488
- for (const path60 of paths) {
6489
- const parts = parsePath(path60);
6497
+ for (const path59 of paths) {
6498
+ const parts = parsePath(path59);
6490
6499
  if (parts.includes("*")) {
6491
- redactWildcardPath(obj, parts, censor, path60, remove);
6500
+ redactWildcardPath(obj, parts, censor, path59, remove);
6492
6501
  } else {
6493
6502
  if (remove) {
6494
6503
  removeKey(obj, parts);
@@ -6573,8 +6582,8 @@ var require_redact = __commonJS({
6573
6582
  }
6574
6583
  } else {
6575
6584
  if (afterWildcard.includes("*")) {
6576
- const wrappedCensor = typeof censor === "function" ? (value, path60) => {
6577
- const fullPath = [...pathArray.slice(0, pathLength), ...path60];
6585
+ const wrappedCensor = typeof censor === "function" ? (value, path59) => {
6586
+ const fullPath = [...pathArray.slice(0, pathLength), ...path59];
6578
6587
  return censor(value, fullPath);
6579
6588
  } : censor;
6580
6589
  redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
@@ -6609,8 +6618,8 @@ var require_redact = __commonJS({
6609
6618
  return null;
6610
6619
  }
6611
6620
  const pathStructure = /* @__PURE__ */ new Map();
6612
- for (const path60 of pathsToClone) {
6613
- const parts = parsePath(path60);
6621
+ for (const path59 of pathsToClone) {
6622
+ const parts = parsePath(path59);
6614
6623
  let current = pathStructure;
6615
6624
  for (let i = 0; i < parts.length; i++) {
6616
6625
  const part = parts[i];
@@ -6662,24 +6671,24 @@ var require_redact = __commonJS({
6662
6671
  }
6663
6672
  return cloneSelectively(obj, pathStructure);
6664
6673
  }
6665
- function validatePath(path60) {
6666
- if (typeof path60 !== "string") {
6674
+ function validatePath(path59) {
6675
+ if (typeof path59 !== "string") {
6667
6676
  throw new Error("Paths must be (non-empty) strings");
6668
6677
  }
6669
- if (path60 === "") {
6678
+ if (path59 === "") {
6670
6679
  throw new Error("Invalid redaction path ()");
6671
6680
  }
6672
- if (path60.includes("..")) {
6673
- throw new Error(`Invalid redaction path (${path60})`);
6681
+ if (path59.includes("..")) {
6682
+ throw new Error(`Invalid redaction path (${path59})`);
6674
6683
  }
6675
- if (path60.includes(",")) {
6676
- throw new Error(`Invalid redaction path (${path60})`);
6684
+ if (path59.includes(",")) {
6685
+ throw new Error(`Invalid redaction path (${path59})`);
6677
6686
  }
6678
6687
  let bracketCount = 0;
6679
6688
  let inQuotes = false;
6680
6689
  let quoteChar = "";
6681
- for (let i = 0; i < path60.length; i++) {
6682
- const char = path60[i];
6690
+ for (let i = 0; i < path59.length; i++) {
6691
+ const char = path59[i];
6683
6692
  if ((char === '"' || char === "'") && bracketCount > 0) {
6684
6693
  if (!inQuotes) {
6685
6694
  inQuotes = true;
@@ -6693,20 +6702,20 @@ var require_redact = __commonJS({
6693
6702
  } else if (char === "]" && !inQuotes) {
6694
6703
  bracketCount--;
6695
6704
  if (bracketCount < 0) {
6696
- throw new Error(`Invalid redaction path (${path60})`);
6705
+ throw new Error(`Invalid redaction path (${path59})`);
6697
6706
  }
6698
6707
  }
6699
6708
  }
6700
6709
  if (bracketCount !== 0) {
6701
- throw new Error(`Invalid redaction path (${path60})`);
6710
+ throw new Error(`Invalid redaction path (${path59})`);
6702
6711
  }
6703
6712
  }
6704
6713
  function validatePaths(paths) {
6705
6714
  if (!Array.isArray(paths)) {
6706
6715
  throw new TypeError("paths must be an array");
6707
6716
  }
6708
- for (const path60 of paths) {
6709
- validatePath(path60);
6717
+ for (const path59 of paths) {
6718
+ validatePath(path59);
6710
6719
  }
6711
6720
  }
6712
6721
  function slowRedact(options = {}) {
@@ -6874,8 +6883,8 @@ var require_redaction = __commonJS({
6874
6883
  if (shape[k2] === null) {
6875
6884
  o[k2] = (value) => topCensor(value, [k2]);
6876
6885
  } else {
6877
- const wrappedCensor = typeof censor === "function" ? (value, path60) => {
6878
- return censor(value, [k2, ...path60]);
6886
+ const wrappedCensor = typeof censor === "function" ? (value, path59) => {
6887
+ return censor(value, [k2, ...path59]);
6879
6888
  } : censor;
6880
6889
  o[k2] = Redact({
6881
6890
  paths: shape[k2],
@@ -7096,7 +7105,7 @@ var require_sonic_boom = __commonJS({
7096
7105
  var fs50 = require("fs");
7097
7106
  var EventEmitter3 = require("events");
7098
7107
  var inherits = require("util").inherits;
7099
- var path60 = require("path");
7108
+ var path59 = require("path");
7100
7109
  var sleep = require_atomic_sleep();
7101
7110
  var assert = require("assert");
7102
7111
  var BUSY_WRITE_TIMEOUT = 100;
@@ -7150,7 +7159,7 @@ var require_sonic_boom = __commonJS({
7150
7159
  const mode = sonic.mode;
7151
7160
  if (sonic.sync) {
7152
7161
  try {
7153
- if (sonic.mkdir) fs50.mkdirSync(path60.dirname(file), { recursive: true });
7162
+ if (sonic.mkdir) fs50.mkdirSync(path59.dirname(file), { recursive: true });
7154
7163
  const fd = fs50.openSync(file, flags, mode);
7155
7164
  fileOpened(null, fd);
7156
7165
  } catch (err) {
@@ -7158,7 +7167,7 @@ var require_sonic_boom = __commonJS({
7158
7167
  throw err;
7159
7168
  }
7160
7169
  } else if (sonic.mkdir) {
7161
- fs50.mkdir(path60.dirname(file), { recursive: true }, (err) => {
7170
+ fs50.mkdir(path59.dirname(file), { recursive: true }, (err) => {
7162
7171
  if (err) return fileOpened(err);
7163
7172
  fs50.open(file, flags, mode, fileOpened);
7164
7173
  });
@@ -10789,11 +10798,11 @@ var init_lib = __esm({
10789
10798
  }
10790
10799
  }
10791
10800
  },
10792
- addToPath: function addToPath(path60, added, removed, oldPosInc, options) {
10793
- var last = path60.lastComponent;
10801
+ addToPath: function addToPath(path59, added, removed, oldPosInc, options) {
10802
+ var last = path59.lastComponent;
10794
10803
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
10795
10804
  return {
10796
- oldPos: path60.oldPos + oldPosInc,
10805
+ oldPos: path59.oldPos + oldPosInc,
10797
10806
  lastComponent: {
10798
10807
  count: last.count + 1,
10799
10808
  added,
@@ -10803,7 +10812,7 @@ var init_lib = __esm({
10803
10812
  };
10804
10813
  } else {
10805
10814
  return {
10806
- oldPos: path60.oldPos + oldPosInc,
10815
+ oldPos: path59.oldPos + oldPosInc,
10807
10816
  lastComponent: {
10808
10817
  count: 1,
10809
10818
  added,
@@ -11249,10 +11258,10 @@ function attachmentToHistoryMessage(o, ts) {
11249
11258
  const memories = raw.map((m2) => {
11250
11259
  if (!m2 || typeof m2 !== "object") return null;
11251
11260
  const rec = m2;
11252
- const path60 = typeof rec.path === "string" ? rec.path : null;
11261
+ const path59 = typeof rec.path === "string" ? rec.path : null;
11253
11262
  const content = typeof rec.content === "string" ? rec.content : null;
11254
- if (!path60 || content == null) return null;
11255
- const entry = { path: path60, content };
11263
+ if (!path59 || content == null) return null;
11264
+ const entry = { path: path59, content };
11256
11265
  if (typeof rec.mtimeMs === "number") entry.mtimeMs = rec.mtimeMs;
11257
11266
  return entry;
11258
11267
  }).filter((m2) => m2 !== null);
@@ -11289,7 +11298,7 @@ function readBackupContent(fileHistoryRoot, toolSessionId, backupFileName) {
11289
11298
  if (backupFileName === null) return null;
11290
11299
  try {
11291
11300
  return import_node_fs8.default.readFileSync(
11292
- import_node_path9.default.join(fileHistoryRoot, toolSessionId, backupFileName),
11301
+ import_node_path8.default.join(fileHistoryRoot, toolSessionId, backupFileName),
11293
11302
  "utf8"
11294
11303
  );
11295
11304
  } catch {
@@ -11304,13 +11313,13 @@ function readCurrentContent(filePath) {
11304
11313
  return null;
11305
11314
  }
11306
11315
  }
11307
- var import_node_fs8, import_node_os3, import_node_path9, TASK_NOTIFICATION_RE, TASK_ID_RE, TOOL_USE_ID_RE, SLASH_COMMAND_RE, LOCAL_COMMAND_RE, SYSTEM_REMINDER_RE, OPENSPEC_BLOCK_RE, SKILL_HINT_RE, ATTACHMENT_SILENT_SUBTYPES, ClaudeHistoryReader;
11316
+ var import_node_fs8, import_node_os3, import_node_path8, TASK_NOTIFICATION_RE, TASK_ID_RE, TOOL_USE_ID_RE, SLASH_COMMAND_RE, LOCAL_COMMAND_RE, SYSTEM_REMINDER_RE, OPENSPEC_BLOCK_RE, SKILL_HINT_RE, ATTACHMENT_SILENT_SUBTYPES, ClaudeHistoryReader;
11308
11317
  var init_claude_history = __esm({
11309
11318
  "src/tools/claude-history.ts"() {
11310
11319
  "use strict";
11311
11320
  import_node_fs8 = __toESM(require("fs"), 1);
11312
11321
  import_node_os3 = __toESM(require("os"), 1);
11313
- import_node_path9 = __toESM(require("path"), 1);
11322
+ import_node_path8 = __toESM(require("path"), 1);
11314
11323
  init_lib();
11315
11324
  init_tool_result_extra();
11316
11325
  TASK_NOTIFICATION_RE = /<task-notification\b[\s\S]*?<\/task-notification>/i;
@@ -11334,9 +11343,9 @@ var init_claude_history = __esm({
11334
11343
  // 每次 user 提交前 trackEdit 拷一份,作为 rewind 回退目标
11335
11344
  fileHistoryRoot;
11336
11345
  constructor(opts = {}) {
11337
- const base = opts.baseDir ?? import_node_path9.default.join(import_node_os3.default.homedir(), ".claude");
11338
- this.projectsRoot = import_node_path9.default.join(base, "projects");
11339
- this.fileHistoryRoot = import_node_path9.default.join(base, "file-history");
11346
+ const base = opts.baseDir ?? import_node_path8.default.join(import_node_os3.default.homedir(), ".claude");
11347
+ this.projectsRoot = import_node_path8.default.join(base, "projects");
11348
+ this.fileHistoryRoot = import_node_path8.default.join(base, "file-history");
11340
11349
  }
11341
11350
  async listProjects() {
11342
11351
  let entries;
@@ -11349,9 +11358,9 @@ var init_claude_history = __esm({
11349
11358
  const out = [];
11350
11359
  for (const ent of entries) {
11351
11360
  if (!ent.isDirectory()) continue;
11352
- const dir = import_node_path9.default.join(this.projectsRoot, ent.name);
11361
+ const dir = import_node_path8.default.join(this.projectsRoot, ent.name);
11353
11362
  const files = import_node_fs8.default.readdirSync(dir).filter((f) => f.endsWith(".jsonl"));
11354
- const updatedAtMs = files.reduce((m2, f) => Math.max(m2, safeStatMtime(import_node_path9.default.join(dir, f))), 0);
11363
+ const updatedAtMs = files.reduce((m2, f) => Math.max(m2, safeStatMtime(import_node_path8.default.join(dir, f))), 0);
11355
11364
  out.push({
11356
11365
  projectPath: hashDirToCwd(ent.name),
11357
11366
  hashDir: ent.name,
@@ -11363,7 +11372,7 @@ var init_claude_history = __esm({
11363
11372
  return out;
11364
11373
  }
11365
11374
  async listSessions(args) {
11366
- const dir = import_node_path9.default.join(this.projectsRoot, cwdToHashDir(args.projectPath));
11375
+ const dir = import_node_path8.default.join(this.projectsRoot, cwdToHashDir(args.projectPath));
11367
11376
  let files;
11368
11377
  try {
11369
11378
  files = import_node_fs8.default.readdirSync(dir).filter((f) => f.endsWith(".jsonl"));
@@ -11373,7 +11382,7 @@ var init_claude_history = __esm({
11373
11382
  }
11374
11383
  const out = [];
11375
11384
  for (const f of files) {
11376
- const full = import_node_path9.default.join(dir, f);
11385
+ const full = import_node_path8.default.join(dir, f);
11377
11386
  const toolSessionId = f.slice(0, -".jsonl".length);
11378
11387
  const lines = readJsonlLines(full);
11379
11388
  let summary = "";
@@ -11428,7 +11437,7 @@ var init_claude_history = __esm({
11428
11437
  return out;
11429
11438
  }
11430
11439
  async read(args) {
11431
- const file = import_node_path9.default.join(
11440
+ const file = import_node_path8.default.join(
11432
11441
  this.projectsRoot,
11433
11442
  cwdToHashDir(args.cwd),
11434
11443
  `${args.toolSessionId}.jsonl`
@@ -11465,7 +11474,7 @@ var init_claude_history = __esm({
11465
11474
  // 独立目录路径:<projectsRoot>/<cwdHash>/<toolSessionId>/subagents/*.jsonl
11466
11475
  // 返回 null 表示目录不存在(调用方回退旧实现);返回空数组表示目录存在但无 jsonl
11467
11476
  listSubagentsFromDirectory(cwd, toolSessionId) {
11468
- const dir = import_node_path9.default.join(
11477
+ const dir = import_node_path8.default.join(
11469
11478
  this.projectsRoot,
11470
11479
  cwdToHashDir(cwd),
11471
11480
  toolSessionId,
@@ -11483,7 +11492,7 @@ var init_claude_history = __esm({
11483
11492
  if (!e.isFile()) continue;
11484
11493
  if (!e.name.startsWith("agent-") || !e.name.endsWith(".jsonl")) continue;
11485
11494
  const subagentId = e.name.slice("agent-".length, -".jsonl".length);
11486
- const filePath = import_node_path9.default.join(dir, e.name);
11495
+ const filePath = import_node_path8.default.join(dir, e.name);
11487
11496
  const lines = readJsonlLines(filePath);
11488
11497
  let firstText = "";
11489
11498
  let messageCount = 0;
@@ -11500,7 +11509,7 @@ var init_claude_history = __esm({
11500
11509
  return out;
11501
11510
  }
11502
11511
  listSubagentsFromMainJsonl(cwd, toolSessionId) {
11503
- const file = import_node_path9.default.join(
11512
+ const file = import_node_path8.default.join(
11504
11513
  this.projectsRoot,
11505
11514
  cwdToHashDir(cwd),
11506
11515
  `${toolSessionId}.jsonl`
@@ -11535,7 +11544,7 @@ var init_claude_history = __esm({
11535
11544
  }
11536
11545
  // 独立文件路径:agent-<subagentId>.jsonl;文件不存在返回 null 让调用方回退旧实现
11537
11546
  readSubagentFromFile(cwd, toolSessionId, subagentId) {
11538
- const file = import_node_path9.default.join(
11547
+ const file = import_node_path8.default.join(
11539
11548
  this.projectsRoot,
11540
11549
  cwdToHashDir(cwd),
11541
11550
  toolSessionId,
@@ -11563,7 +11572,7 @@ var init_claude_history = __esm({
11563
11572
  * "那一刻每个 tracked 文件对应的 backup 文件名"
11564
11573
  */
11565
11574
  readFileHistorySnapshots(args) {
11566
- const file = import_node_path9.default.join(
11575
+ const file = import_node_path8.default.join(
11567
11576
  this.projectsRoot,
11568
11577
  cwdToHashDir(args.cwd),
11569
11578
  `${args.toolSessionId}.jsonl`
@@ -11608,7 +11617,7 @@ var init_claude_history = __esm({
11608
11617
  for (const [anchorId, target] of snapshots) {
11609
11618
  let hasAny = false;
11610
11619
  for (const [rawPath, backup] of Object.entries(target)) {
11611
- const absPath = import_node_path9.default.isAbsolute(rawPath) ? rawPath : import_node_path9.default.join(args.cwd, rawPath);
11620
+ const absPath = import_node_path8.default.isAbsolute(rawPath) ? rawPath : import_node_path8.default.join(args.cwd, rawPath);
11612
11621
  const backupContent = readBackupContent(
11613
11622
  this.fileHistoryRoot,
11614
11623
  args.toolSessionId,
@@ -11648,7 +11657,7 @@ var init_claude_history = __esm({
11648
11657
  let totalInsertions = 0;
11649
11658
  let totalDeletions = 0;
11650
11659
  for (const [rawPath, backup] of Object.entries(target)) {
11651
- const absPath = import_node_path9.default.isAbsolute(rawPath) ? rawPath : import_node_path9.default.join(args.cwd, rawPath);
11660
+ const absPath = import_node_path8.default.isAbsolute(rawPath) ? rawPath : import_node_path8.default.join(args.cwd, rawPath);
11652
11661
  const backupContent = readBackupContent(
11653
11662
  this.fileHistoryRoot,
11654
11663
  args.toolSessionId,
@@ -11695,7 +11704,7 @@ var init_claude_history = __esm({
11695
11704
  };
11696
11705
  }
11697
11706
  readSubagentFromMainJsonl(cwd, toolSessionId, subagentId) {
11698
- const file = import_node_path9.default.join(
11707
+ const file = import_node_path8.default.join(
11699
11708
  this.projectsRoot,
11700
11709
  cwdToHashDir(cwd),
11701
11710
  `${toolSessionId}.jsonl`
@@ -11719,7 +11728,7 @@ var init_claude_history = __esm({
11719
11728
  // src/tools/claude.ts
11720
11729
  function macOSDesktopCandidates(home) {
11721
11730
  return [
11722
- import_node_path10.default.join(home, "Applications", "Claude.app", "Contents", "Resources", "app.asar.unpacked", "node_modules", "@anthropic-ai", "claude-code", "cli.js"),
11731
+ import_node_path9.default.join(home, "Applications", "Claude.app", "Contents", "Resources", "app.asar.unpacked", "node_modules", "@anthropic-ai", "claude-code", "cli.js"),
11723
11732
  "/Applications/Claude.app/Contents/Resources/app.asar.unpacked/node_modules/@anthropic-ai/claude-code/cli.js"
11724
11733
  ];
11725
11734
  }
@@ -12064,10 +12073,10 @@ function parseAttachment(obj) {
12064
12073
  const memories = raw.map((m2) => {
12065
12074
  if (!m2 || typeof m2 !== "object") return null;
12066
12075
  const rec = m2;
12067
- const path60 = typeof rec.path === "string" ? rec.path : null;
12076
+ const path59 = typeof rec.path === "string" ? rec.path : null;
12068
12077
  const content = typeof rec.content === "string" ? rec.content : null;
12069
- if (!path60 || content == null) return null;
12070
- const out = { path: path60, content };
12078
+ if (!path59 || content == null) return null;
12079
+ const out = { path: path59, content };
12071
12080
  if (typeof rec.mtimeMs === "number") out.mtimeMs = rec.mtimeMs;
12072
12081
  return out;
12073
12082
  }).filter((m2) => m2 !== null);
@@ -12171,7 +12180,7 @@ function encodeClaudeStdin(text) {
12171
12180
  };
12172
12181
  return JSON.stringify(frame) + "\n";
12173
12182
  }
12174
- var import_node_child_process, import_node_child_process2, import_node_fs9, import_node_os4, import_node_path10, ATTACHMENT_SILENT_SUBTYPES2, unknownTypeHandler, ATTACHMENT_RE, IMAGE_EXT_MIME, CLAUDE_MODELS, CLAUDE_PERMISSION_MODES, CLAUDE_CAPABILITIES, ClaudeAdapter;
12183
+ var import_node_child_process, import_node_child_process2, import_node_fs9, import_node_os4, import_node_path9, ATTACHMENT_SILENT_SUBTYPES2, unknownTypeHandler, ATTACHMENT_RE, IMAGE_EXT_MIME, CLAUDE_MODELS, CLAUDE_PERMISSION_MODES, CLAUDE_CAPABILITIES, ClaudeAdapter;
12175
12184
  var init_claude = __esm({
12176
12185
  "src/tools/claude.ts"() {
12177
12186
  "use strict";
@@ -12179,7 +12188,7 @@ var init_claude = __esm({
12179
12188
  import_node_child_process2 = require("child_process");
12180
12189
  import_node_fs9 = __toESM(require("fs"), 1);
12181
12190
  import_node_os4 = __toESM(require("os"), 1);
12182
- import_node_path10 = __toESM(require("path"), 1);
12191
+ import_node_path9 = __toESM(require("path"), 1);
12183
12192
  init_protocol();
12184
12193
  init_claude_history();
12185
12194
  init_tool_result_extra();
@@ -23855,8 +23864,8 @@ var require_utils = __commonJS({
23855
23864
  var result = transform[inputType][outputType](input);
23856
23865
  return result;
23857
23866
  };
23858
- exports2.resolve = function(path60) {
23859
- var parts = path60.split("/");
23867
+ exports2.resolve = function(path59) {
23868
+ var parts = path59.split("/");
23860
23869
  var result = [];
23861
23870
  for (var index = 0; index < parts.length; index++) {
23862
23871
  var part = parts[index];
@@ -29709,18 +29718,18 @@ var require_object = __commonJS({
29709
29718
  var object = new ZipObject(name, zipObjectContent, o);
29710
29719
  this.files[name] = object;
29711
29720
  };
29712
- var parentFolder = function(path60) {
29713
- if (path60.slice(-1) === "/") {
29714
- path60 = path60.substring(0, path60.length - 1);
29721
+ var parentFolder = function(path59) {
29722
+ if (path59.slice(-1) === "/") {
29723
+ path59 = path59.substring(0, path59.length - 1);
29715
29724
  }
29716
- var lastSlash = path60.lastIndexOf("/");
29717
- return lastSlash > 0 ? path60.substring(0, lastSlash) : "";
29725
+ var lastSlash = path59.lastIndexOf("/");
29726
+ return lastSlash > 0 ? path59.substring(0, lastSlash) : "";
29718
29727
  };
29719
- var forceTrailingSlash = function(path60) {
29720
- if (path60.slice(-1) !== "/") {
29721
- path60 += "/";
29728
+ var forceTrailingSlash = function(path59) {
29729
+ if (path59.slice(-1) !== "/") {
29730
+ path59 += "/";
29722
29731
  }
29723
- return path60;
29732
+ return path59;
29724
29733
  };
29725
29734
  var folderAdd = function(name, createFolders) {
29726
29735
  createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
@@ -30722,7 +30731,7 @@ var require_lib3 = __commonJS({
30722
30731
  // src/run-case/recorder.ts
30723
30732
  function startRunCaseRecorder(opts) {
30724
30733
  const now = opts.now ?? Date.now;
30725
- const dir = import_node_path48.default.dirname(opts.recordPath);
30734
+ const dir = import_node_path47.default.dirname(opts.recordPath);
30726
30735
  let stream = null;
30727
30736
  let closing = false;
30728
30737
  let closedSettled = false;
@@ -30762,12 +30771,12 @@ function startRunCaseRecorder(opts) {
30762
30771
  };
30763
30772
  return { tap, close, closed };
30764
30773
  }
30765
- var import_node_fs33, import_node_path48;
30774
+ var import_node_fs33, import_node_path47;
30766
30775
  var init_recorder = __esm({
30767
30776
  "src/run-case/recorder.ts"() {
30768
30777
  "use strict";
30769
30778
  import_node_fs33 = __toESM(require("fs"), 1);
30770
- import_node_path48 = __toESM(require("path"), 1);
30779
+ import_node_path47 = __toESM(require("path"), 1);
30771
30780
  }
30772
30781
  });
30773
30782
 
@@ -30810,7 +30819,7 @@ var init_wire = __esm({
30810
30819
  // src/run-case/controller.ts
30811
30820
  async function runController(opts) {
30812
30821
  const now = opts.now ?? Date.now;
30813
- const cwd = opts.cwd ?? (0, import_node_fs34.mkdtempSync)(import_node_path49.default.join(import_node_os19.default.tmpdir(), "clawd-runcase-"));
30822
+ const cwd = opts.cwd ?? (0, import_node_fs34.mkdtempSync)(import_node_path48.default.join(import_node_os19.default.tmpdir(), "clawd-runcase-"));
30814
30823
  const ownsCwd = opts.cwd === void 0;
30815
30824
  const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
30816
30825
  const spawnCtx = { cwd };
@@ -30977,13 +30986,13 @@ async function runController(opts) {
30977
30986
  }
30978
30987
  return exitCode ?? 0;
30979
30988
  }
30980
- var import_node_fs34, import_node_os19, import_node_path49;
30989
+ var import_node_fs34, import_node_os19, import_node_path48;
30981
30990
  var init_controller = __esm({
30982
30991
  "src/run-case/controller.ts"() {
30983
30992
  "use strict";
30984
30993
  import_node_fs34 = require("fs");
30985
30994
  import_node_os19 = __toESM(require("os"), 1);
30986
- import_node_path49 = __toESM(require("path"), 1);
30995
+ import_node_path48 = __toESM(require("path"), 1);
30987
30996
  init_claude();
30988
30997
  init_stdout_splitter();
30989
30998
  init_permission_stdio();
@@ -31218,7 +31227,7 @@ Env (advanced):
31218
31227
  `;
31219
31228
 
31220
31229
  // src/index.ts
31221
- var import_node_path47 = __toESM(require("path"), 1);
31230
+ var import_node_path46 = __toESM(require("path"), 1);
31222
31231
  var import_node_fs32 = __toESM(require("fs"), 1);
31223
31232
 
31224
31233
  // src/logger.ts
@@ -31257,15 +31266,12 @@ function createLogger(opts = {}) {
31257
31266
  }
31258
31267
 
31259
31268
  // src/session/store-factory.ts
31260
- var path6 = __toESM(require("path"), 1);
31269
+ var path5 = __toESM(require("path"), 1);
31261
31270
 
31262
31271
  // src/session/store.ts
31263
31272
  var import_node_fs3 = __toESM(require("fs"), 1);
31264
- var import_node_path4 = __toESM(require("path"), 1);
31265
- init_protocol();
31266
-
31267
- // src/session/scope.ts
31268
31273
  var import_node_path3 = __toESM(require("path"), 1);
31274
+ init_protocol();
31269
31275
 
31270
31276
  // src/session/user-workdir.ts
31271
31277
  var path3 = __toESM(require("path"), 1);
@@ -31301,7 +31307,6 @@ function metaFromScope(scope, personaRoot, usersRoot) {
31301
31307
  return {
31302
31308
  idleKillEnabled: true,
31303
31309
  personaMode: "guest",
31304
- extraSettings: import_node_path3.default.join(personaRoot, scope.personaId, ".clawd", "sandbox-settings.json"),
31305
31310
  userWorkDir,
31306
31311
  addDirs: [userWorkDir]
31307
31312
  };
@@ -31331,7 +31336,7 @@ var SessionStore = class {
31331
31336
  this.root = opts.root;
31332
31337
  } else {
31333
31338
  const scope = opts.scope ?? { kind: "default" };
31334
- this.root = import_node_path4.default.join(
31339
+ this.root = import_node_path3.default.join(
31335
31340
  opts.dataDir,
31336
31341
  "sessions",
31337
31342
  ...scopeSubPath(scope).map(safeFileName)
@@ -31339,7 +31344,7 @@ var SessionStore = class {
31339
31344
  }
31340
31345
  }
31341
31346
  filePath(sessionId) {
31342
- return import_node_path4.default.join(this.root, `${safeFileName(sessionId)}.json`);
31347
+ return import_node_path3.default.join(this.root, `${safeFileName(sessionId)}.json`);
31343
31348
  }
31344
31349
  ensureDir() {
31345
31350
  import_node_fs3.default.mkdirSync(this.root, { recursive: true });
@@ -31387,7 +31392,7 @@ var SessionStore = class {
31387
31392
  for (const name of entries) {
31388
31393
  if (!name.endsWith(".json")) continue;
31389
31394
  if (name.includes(".tmp-")) continue;
31390
- const full = import_node_path4.default.join(this.root, name);
31395
+ const full = import_node_path3.default.join(this.root, name);
31391
31396
  try {
31392
31397
  const raw = import_node_fs3.default.readFileSync(full, "utf8");
31393
31398
  const parsed = JSON.parse(raw);
@@ -31413,10 +31418,10 @@ var SessionStoreFactory = class {
31413
31418
  }
31414
31419
  // ---- root path 派生(暴露给 migration / revoke cascade 等外部消费方) ----
31415
31420
  bareRoot() {
31416
- return path6.join(this.dataDir, "sessions");
31421
+ return path5.join(this.dataDir, "sessions");
31417
31422
  }
31418
31423
  vmOwnerRoot(personaId) {
31419
- return path6.join(
31424
+ return path5.join(
31420
31425
  this.dataDir,
31421
31426
  "personas",
31422
31427
  safeFileName(personaId),
@@ -31426,7 +31431,7 @@ var SessionStoreFactory = class {
31426
31431
  );
31427
31432
  }
31428
31433
  vmGuestRoot(personaId, capId) {
31429
- return path6.join(
31434
+ return path5.join(
31430
31435
  this.dataDir,
31431
31436
  "personas",
31432
31437
  safeFileName(personaId),
@@ -31463,7 +31468,7 @@ var SessionStoreFactory = class {
31463
31468
 
31464
31469
  // src/session/manager.ts
31465
31470
  var import_node_fs6 = __toESM(require("fs"), 1);
31466
- var import_node_path7 = __toESM(require("path"), 1);
31471
+ var import_node_path6 = __toESM(require("path"), 1);
31467
31472
 
31468
31473
  // ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/stringify.js
31469
31474
  var byteToHex = [];
@@ -31515,6 +31520,78 @@ var v4_default = v4;
31515
31520
  // src/session/manager.ts
31516
31521
  init_protocol();
31517
31522
 
31523
+ // src/tools/guest-settings.ts
31524
+ var FORCED_DENY_READ = ["~/"];
31525
+ var FORCED_TOOL_DENY = ["Edit(./**)"];
31526
+ function unionArr(a, b2) {
31527
+ const out = [...a ?? []];
31528
+ for (const x of b2) if (!out.includes(x)) out.push(x);
31529
+ return out;
31530
+ }
31531
+ function isGuestSettingsLike(v2) {
31532
+ if (!v2 || typeof v2 !== "object") return false;
31533
+ const sb = v2.sandbox;
31534
+ return !!sb && typeof sb === "object";
31535
+ }
31536
+ function buildGuestSettingsV1() {
31537
+ return {
31538
+ permissions: {
31539
+ defaultMode: "dontAsk",
31540
+ deny: [...FORCED_TOOL_DENY]
31541
+ // 保留 persona 限制:挡 CC 工具改/读 persona(cwd=persona)
31542
+ },
31543
+ sandbox: {
31544
+ enabled: true,
31545
+ autoAllowBashIfSandboxed: true,
31546
+ // Bash 自动过沙箱;文件工具 dontAsk 自动拒(最严格只 Bash)
31547
+ allowUnsandboxedCommands: false,
31548
+ // 关 dangerouslyDisableSandbox 逃逸口
31549
+ filesystem: {
31550
+ denyRead: ["~/"],
31551
+ denyWrite: [],
31552
+ // **不放 '~/'**(写是白名单制,home 自动不可写);persona(cwd) 由 compose 强制 deny
31553
+ allowRead: [],
31554
+ // 不放 cwd(persona);userWorkDir 由 compose 注入,profile 加工具链精确路径
31555
+ allowWrite: []
31556
+ }
31557
+ }
31558
+ };
31559
+ }
31560
+ function applyProfile(base, profile) {
31561
+ if (profile.permissions?.defaultMode) base.permissions.defaultMode = profile.permissions.defaultMode;
31562
+ if (profile.permissions?.allow) base.permissions.allow = unionArr(base.permissions.allow, profile.permissions.allow);
31563
+ if (profile.permissions?.deny) base.permissions.deny = unionArr(base.permissions.deny, profile.permissions.deny);
31564
+ const pf = profile.sandbox?.filesystem;
31565
+ if (pf) {
31566
+ const f = base.sandbox.filesystem ?? (base.sandbox.filesystem = {});
31567
+ if (pf.allowRead) f.allowRead = unionArr(f.allowRead, pf.allowRead);
31568
+ if (pf.allowWrite) f.allowWrite = unionArr(f.allowWrite, pf.allowWrite);
31569
+ if (pf.denyRead) f.denyRead = unionArr(f.denyRead, pf.denyRead);
31570
+ if (pf.denyWrite) f.denyWrite = unionArr(f.denyWrite, pf.denyWrite);
31571
+ }
31572
+ const pn = profile.sandbox?.network;
31573
+ if (pn) {
31574
+ const n = base.sandbox.network ?? (base.sandbox.network = {});
31575
+ if (pn.allowedDomains) n.allowedDomains = unionArr(n.allowedDomains, pn.allowedDomains);
31576
+ if (pn.allowLocalBinding !== void 0) n.allowLocalBinding = pn.allowLocalBinding;
31577
+ }
31578
+ return base;
31579
+ }
31580
+ function composeGuestSandbox(base, userWorkDir, spawnCwd) {
31581
+ const s = isGuestSettingsLike(base) ? base : buildGuestSettingsV1();
31582
+ s.permissions = s.permissions ?? { defaultMode: "dontAsk" };
31583
+ const fsv = s.sandbox.filesystem ?? (s.sandbox.filesystem = {});
31584
+ s.sandbox.enabled = true;
31585
+ s.sandbox.autoAllowBashIfSandboxed = true;
31586
+ s.sandbox.allowUnsandboxedCommands = false;
31587
+ fsv.denyRead = unionArr(fsv.denyRead, FORCED_DENY_READ);
31588
+ fsv.denyWrite = unionArr((fsv.denyWrite ?? []).filter((p2) => p2 !== "~/"), [spawnCwd]);
31589
+ s.permissions.deny = unionArr(s.permissions.deny, FORCED_TOOL_DENY);
31590
+ fsv.allowRead = unionArr(fsv.allowRead, [userWorkDir]);
31591
+ fsv.allowWrite = unionArr(fsv.allowWrite, [userWorkDir]);
31592
+ return s;
31593
+ }
31594
+
31518
31595
  // src/session/reducer.ts
31519
31596
  init_runtime();
31520
31597
 
@@ -32282,7 +32359,7 @@ init_stdout_splitter();
32282
32359
 
32283
32360
  // src/ipc-recorder.ts
32284
32361
  var import_node_fs4 = __toESM(require("fs"), 1);
32285
- var import_node_path5 = __toESM(require("path"), 1);
32362
+ var import_node_path4 = __toESM(require("path"), 1);
32286
32363
  function tsForFilename(ms) {
32287
32364
  return new Date(ms).toISOString().replace(/[:.]/g, "-");
32288
32365
  }
@@ -32293,8 +32370,8 @@ function startRecorder(opts) {
32293
32370
  return null;
32294
32371
  }
32295
32372
  const now = opts.now ?? Date.now;
32296
- const dir = import_node_path5.default.join(opts.dataDir, "ipc-recordings", opts.sessionId);
32297
- const filePath = import_node_path5.default.join(dir, `${tsForFilename(now())}.jsonl`);
32373
+ const dir = import_node_path4.default.join(opts.dataDir, "ipc-recordings", opts.sessionId);
32374
+ const filePath = import_node_path4.default.join(dir, `${tsForFilename(now())}.jsonl`);
32298
32375
  let stream = null;
32299
32376
  let closedResolve;
32300
32377
  const closed = new Promise((resolve6) => {
@@ -32746,9 +32823,9 @@ function extractEditPath(input) {
32746
32823
 
32747
32824
  // src/debug/pty-probe.ts
32748
32825
  var import_node_fs5 = __toESM(require("fs"), 1);
32749
- var import_node_path6 = __toESM(require("path"), 1);
32826
+ var import_node_path5 = __toESM(require("path"), 1);
32750
32827
  var PROBE_DIR = "/tmp/clawd-probe";
32751
- var EVENTS_FILE = import_node_path6.default.join(PROBE_DIR, "events.jsonl");
32828
+ var EVENTS_FILE = import_node_path5.default.join(PROBE_DIR, "events.jsonl");
32752
32829
  var inited = false;
32753
32830
  function ensureDir() {
32754
32831
  if (inited) return true;
@@ -32771,7 +32848,7 @@ function probeEvent(event, data = {}) {
32771
32848
  function probeDumpReplay(sessionId, payload) {
32772
32849
  try {
32773
32850
  if (!ensureDir()) return "";
32774
- const file = import_node_path6.default.join(PROBE_DIR, `replay-${sessionId}-${Date.now()}.ans`);
32851
+ const file = import_node_path5.default.join(PROBE_DIR, `replay-${sessionId}-${Date.now()}.ans`);
32775
32852
  import_node_fs5.default.writeFileSync(file, payload, "utf8");
32776
32853
  return file;
32777
32854
  } catch {
@@ -32863,7 +32940,7 @@ function derivePersonaSpawnCwd(file, personaRoot) {
32863
32940
  `derivePersonaSpawnCwd: personaRoot missing for owner session ${file.sessionId} (ownerPersonaId=${personaId})`
32864
32941
  );
32865
32942
  }
32866
- return import_node_path7.default.join(personaRoot, safeFileName(personaId));
32943
+ return import_node_path6.default.join(personaRoot, safeFileName(personaId));
32867
32944
  }
32868
32945
  function makeInitialState(file, subSessionMeta) {
32869
32946
  return {
@@ -32980,7 +33057,7 @@ var SessionManager = class {
32980
33057
  // <dataDir>/sessions/ 列子目录 (排除 'default').
32981
33058
  listPersonaIdsOnDisk() {
32982
33059
  if (!this.deps.dataDir) return [];
32983
- const root = this.deps.storeFactory ? import_node_path7.default.join(this.deps.dataDir, "personas") : import_node_path7.default.join(this.deps.dataDir, "sessions");
33060
+ const root = this.deps.storeFactory ? import_node_path6.default.join(this.deps.dataDir, "personas") : import_node_path6.default.join(this.deps.dataDir, "sessions");
32984
33061
  let entries;
32985
33062
  try {
32986
33063
  entries = import_node_fs6.default.readdirSync(root, { withFileTypes: true });
@@ -32996,7 +33073,7 @@ var SessionManager = class {
32996
33073
  // 只在 storeFactory 注入 (新布局) 下生效, 老布局无 guest 目录.
32997
33074
  listGuestCapIdsForPersona(personaId) {
32998
33075
  if (!this.deps.dataDir || !this.deps.storeFactory) return [];
32999
- const root = import_node_path7.default.join(
33076
+ const root = import_node_path6.default.join(
33000
33077
  this.deps.dataDir,
33001
33078
  "personas",
33002
33079
  personaId,
@@ -33117,6 +33194,16 @@ var SessionManager = class {
33117
33194
  const adapter = this.deps.getAdapter(file.tool ?? "claude");
33118
33195
  const store = this.storeFor(scope);
33119
33196
  const subSessionMeta = metaFromScope(scope, this.deps.personaRoot ?? "", this.deps.usersRoot ?? "");
33197
+ if (scope.kind === "persona" && scope.mode === "guest") {
33198
+ if (!this.deps.personaRoot || !subSessionMeta?.userWorkDir) {
33199
+ throw new Error(
33200
+ `newRunner: guest session ${file.sessionId} \u7F3A personaRoot/userWorkDir\uFF0C\u65E0\u6CD5\u7269\u5316 OS \u6C99\u7BB1\uFF08\u62D2\u7EDD\u521B\u5EFA\u65E0\u6C99\u7BB1 guest\uFF09`
33201
+ );
33202
+ }
33203
+ const base = this.deps.personaStore?.readSandboxSettings(scope.personaId) ?? null;
33204
+ const settings = composeGuestSandbox(base, subSessionMeta.userWorkDir, file.cwd);
33205
+ subSessionMeta.extraSettings = JSON.stringify(settings);
33206
+ }
33120
33207
  const attachmentGroup = this.deps.attachmentGroup;
33121
33208
  const runner = new SessionRunner(makeInitialState(file, subSessionMeta), {
33122
33209
  broadcastFrame: (frame, target) => this.routeFromRunner(frame, target),
@@ -34313,24 +34400,8 @@ var SessionManager = class {
34313
34400
 
34314
34401
  // src/persona/store.ts
34315
34402
  var fs7 = __toESM(require("fs"), 1);
34316
- var path10 = __toESM(require("path"), 1);
34403
+ var path9 = __toESM(require("path"), 1);
34317
34404
  init_protocol();
34318
-
34319
- // src/tools/guest-settings.ts
34320
- function buildGuestSettingsV1(paths) {
34321
- const p2 = (dir) => dir.replace(/^\//, "");
34322
- return {
34323
- permissions: {
34324
- defaultMode: "dontAsk",
34325
- allow: ["Bash"],
34326
- deny: [`Edit(//${p2(paths.personaDir)}/**)`, `Read(//${p2(paths.personaDir)}/.clawd/**)`]
34327
- },
34328
- // 先不加 OS 沙箱(见文件头说明);目录隔离靠 user-dir 分配 + --add-dir + RPC 守卫。
34329
- sandbox: { enabled: false }
34330
- };
34331
- }
34332
-
34333
- // src/persona/store.ts
34334
34405
  var PersonaStore = class {
34335
34406
  constructor(root) {
34336
34407
  this.root = root;
@@ -34338,31 +34409,30 @@ var PersonaStore = class {
34338
34409
  }
34339
34410
  root;
34340
34411
  personaDir(personaId) {
34341
- return path10.join(this.root, safeFileName(personaId));
34412
+ return path9.join(this.root, safeFileName(personaId));
34342
34413
  }
34343
34414
  metaPath(personaId) {
34344
- return path10.join(this.personaDir(personaId), ".clawd", "persona.json");
34415
+ return path9.join(this.personaDir(personaId), ".clawd", "persona.json");
34345
34416
  }
34346
34417
  claudeMdPath(personaId) {
34347
- return path10.join(this.personaDir(personaId), "CLAUDE.md");
34418
+ return path9.join(this.personaDir(personaId), "CLAUDE.md");
34348
34419
  }
34349
34420
  /**
34350
- * Sandbox settings 落盘路径 —— 故意放在 `.clawd/` 而不是 `.claude/`,让 CC 的
34351
- * project source 自动发现机制扫不到。owner 模式 spawn 时不会被 `--setting-sources
34352
- * user,project,local` 顺手带进来;listener 模式靠 `--settings <这个路径>` 显式拉回。
34353
- * sandbox persona CLAUDE.md(仍在 `<persona>/CLAUDE.md`)解耦后,两种模式都能
34354
- * 加载 persona 人格,只有 listener 多一层 OS sandbox。
34421
+ * persona sandbox 模板落盘路径 —— 故意放 `.clawd/` 而非 `.claude/`,让 CC 的 project
34422
+ * source 自动发现扫不到(owner `--setting-sources user,project,local` 不会顺手带进来)。
34423
+ * 这份是 **UI 展示用模板**(readSandboxSettings);guest 真正加载的沙箱文件由 manager
34424
+ * spawn per-guest 动态拼到各自 session 目录(含本 guest userWorkDir carve),不是这份。
34355
34425
  */
34356
34426
  sandboxSettingsPath(personaId) {
34357
- return path10.join(this.personaDir(personaId), ".clawd", "sandbox-settings.json");
34427
+ return path9.join(this.personaDir(personaId), ".clawd", "sandbox-settings.json");
34358
34428
  }
34359
34429
  write(persona, personality) {
34360
34430
  const dir = this.personaDir(persona.personaId);
34361
- fs7.mkdirSync(path10.join(dir, ".clawd"), { recursive: true });
34431
+ fs7.mkdirSync(path9.join(dir, ".clawd"), { recursive: true });
34362
34432
  this.atomicWrite(this.claudeMdPath(persona.personaId), personality);
34363
34433
  this.atomicWrite(
34364
34434
  this.sandboxSettingsPath(persona.personaId),
34365
- JSON.stringify(buildGuestSettingsV1({ personaDir: dir }), null, 2)
34435
+ JSON.stringify(buildGuestSettingsV1(), null, 2)
34366
34436
  );
34367
34437
  this.atomicWrite(this.metaPath(persona.personaId), JSON.stringify(persona, null, 2));
34368
34438
  }
@@ -34370,10 +34440,9 @@ var PersonaStore = class {
34370
34440
  this.atomicWrite(this.claudeMdPath(personaId), personality);
34371
34441
  }
34372
34442
  /**
34373
- * 覆盖式写 sandbox-settings.json。preinstalled persona seed 时按需调用(如
34374
- * persona-app-builder 默认关 sandbox:FC 部署 / pnpm install / curl daemon RPC 都要 freedom,
34375
- * 默认 enabled=true 会拦住老板正常工作流)。已存在 persona 不主动覆盖 —— 老板手改了的不打扰;
34376
- * 想同步默认值,老板手动 cat 写一次即可。
34443
+ * 覆盖式写 persona 级 sandbox 配置(seed 给有 profile 的 persona base⊕profile;owner 之后可手编)。
34444
+ * 这份是 guest 沙箱的 **base 真源**:manager spawn composeGuestSandbox 读它 + 叠强制底座
34445
+ * enabled/denyRead/persona-deny owner 削弱不了)+ 注入本 guest userWorkDir → 写 per-guest 文件给 CC。
34377
34446
  */
34378
34447
  writeSandboxSettings(personaId, settings) {
34379
34448
  this.atomicWrite(
@@ -34417,14 +34486,14 @@ var PersonaStore = class {
34417
34486
  }
34418
34487
  /** Persona 私有 skills 目录路径:<personaDir>/.claude/skills */
34419
34488
  skillsDir(personaId) {
34420
- return path10.join(this.personaDir(personaId), ".claude", "skills");
34489
+ return path9.join(this.personaDir(personaId), ".claude", "skills");
34421
34490
  }
34422
34491
  /**
34423
34492
  * Claude Code 项目级 settings 路径:`<personaDir>/.claude/settings.json`。
34424
34493
  * 这里只读 `enabledPlugins` 字段,由 owner 通过 CC `/plugin` 之类命令维护,daemon 不写。
34425
34494
  */
34426
34495
  claudeSettingsPath(personaId) {
34427
- return path10.join(this.personaDir(personaId), ".claude", "settings.json");
34496
+ return path9.join(this.personaDir(personaId), ".claude", "settings.json");
34428
34497
  }
34429
34498
  /**
34430
34499
  * 读取 persona 的 `.claude/settings.json` 中 `enabledPlugins` map,把 value === true
@@ -34458,7 +34527,7 @@ var PersonaStore = class {
34458
34527
  list() {
34459
34528
  if (!fs7.existsSync(this.root)) return [];
34460
34529
  return fs7.readdirSync(this.root).filter((name) => {
34461
- return fs7.existsSync(path10.join(this.root, name, ".clawd", "persona.json"));
34530
+ return fs7.existsSync(path9.join(this.root, name, ".clawd", "persona.json"));
34462
34531
  });
34463
34532
  }
34464
34533
  remove(personaId) {
@@ -34519,7 +34588,7 @@ var import_node_crypto3 = __toESM(require("crypto"), 1);
34519
34588
  // src/skills/scanner.ts
34520
34589
  var import_node_fs7 = __toESM(require("fs"), 1);
34521
34590
  var import_node_os2 = __toESM(require("os"), 1);
34522
- var import_node_path8 = __toESM(require("path"), 1);
34591
+ var import_node_path7 = __toESM(require("path"), 1);
34523
34592
 
34524
34593
  // src/skills/frontmatter.ts
34525
34594
  var STRIP_QUOTES = /^["']|["']$/g;
@@ -34641,14 +34710,14 @@ function scanSkillDir(dir, source, seen, out, pluginName) {
34641
34710
  return;
34642
34711
  }
34643
34712
  for (const ent of entries) {
34644
- const entryPath = import_node_path8.default.join(dir, ent.name);
34713
+ const entryPath = import_node_path7.default.join(dir, ent.name);
34645
34714
  if (!ent.isDirectory() && !(ent.isSymbolicLink() && isDirLikeSync(entryPath))) continue;
34646
34715
  let content;
34647
34716
  try {
34648
- content = import_node_fs7.default.readFileSync(import_node_path8.default.join(entryPath, "SKILL.md"), "utf8");
34717
+ content = import_node_fs7.default.readFileSync(import_node_path7.default.join(entryPath, "SKILL.md"), "utf8");
34649
34718
  } catch {
34650
34719
  try {
34651
- content = import_node_fs7.default.readFileSync(import_node_path8.default.join(entryPath, "skill.md"), "utf8");
34720
+ content = import_node_fs7.default.readFileSync(import_node_path7.default.join(entryPath, "skill.md"), "utf8");
34652
34721
  } catch {
34653
34722
  continue;
34654
34723
  }
@@ -34677,7 +34746,7 @@ function scanCommandDir(dir, source, seen, out, pluginName) {
34677
34746
  return;
34678
34747
  }
34679
34748
  for (const ent of entries) {
34680
- const entryPath = import_node_path8.default.join(dir, ent.name);
34749
+ const entryPath = import_node_path7.default.join(dir, ent.name);
34681
34750
  if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync(entryPath)) {
34682
34751
  const ns = ent.name;
34683
34752
  let subEntries;
@@ -34688,7 +34757,7 @@ function scanCommandDir(dir, source, seen, out, pluginName) {
34688
34757
  }
34689
34758
  for (const se of subEntries) {
34690
34759
  if (!se.name.endsWith(".md")) continue;
34691
- const sePath = import_node_path8.default.join(entryPath, se.name);
34760
+ const sePath = import_node_path7.default.join(entryPath, se.name);
34692
34761
  let content;
34693
34762
  try {
34694
34763
  content = import_node_fs7.default.readFileSync(sePath, "utf8");
@@ -34724,7 +34793,7 @@ function scanCommandDir(dir, source, seen, out, pluginName) {
34724
34793
  }
34725
34794
  }
34726
34795
  function readInstalledPlugins(home) {
34727
- const file = import_node_path8.default.join(home, ".claude", "plugins", "installed_plugins.json");
34796
+ const file = import_node_path7.default.join(home, ".claude", "plugins", "installed_plugins.json");
34728
34797
  let raw;
34729
34798
  try {
34730
34799
  raw = import_node_fs7.default.readFileSync(file, "utf8");
@@ -34775,14 +34844,14 @@ var SkillsScanner = class {
34775
34844
  });
34776
34845
  }
34777
34846
  const fsBlock = [];
34778
- scanSkillDir(import_node_path8.default.join(this.home, ".claude", "skills"), "global", seen, fsBlock);
34779
- scanCommandDir(import_node_path8.default.join(this.home, ".claude", "commands"), "global", seen, fsBlock);
34780
- scanSkillDir(import_node_path8.default.join(args.cwd, ".claude", "skills"), "project", seen, fsBlock);
34781
- scanCommandDir(import_node_path8.default.join(args.cwd, ".claude", "commands"), "project", seen, fsBlock);
34847
+ scanSkillDir(import_node_path7.default.join(this.home, ".claude", "skills"), "global", seen, fsBlock);
34848
+ scanCommandDir(import_node_path7.default.join(this.home, ".claude", "commands"), "global", seen, fsBlock);
34849
+ scanSkillDir(import_node_path7.default.join(args.cwd, ".claude", "skills"), "project", seen, fsBlock);
34850
+ scanCommandDir(import_node_path7.default.join(args.cwd, ".claude", "commands"), "project", seen, fsBlock);
34782
34851
  const plugins = [...readInstalledPlugins(this.home), ...this.extraPluginRoots];
34783
34852
  for (const { name, root } of plugins) {
34784
- scanSkillDir(import_node_path8.default.join(root, "skills"), "plugin", seen, fsBlock, name);
34785
- scanCommandDir(import_node_path8.default.join(root, "commands"), "plugin", seen, fsBlock, name);
34853
+ scanSkillDir(import_node_path7.default.join(root, "skills"), "plugin", seen, fsBlock, name);
34854
+ scanCommandDir(import_node_path7.default.join(root, "commands"), "plugin", seen, fsBlock, name);
34786
34855
  }
34787
34856
  fsBlock.sort((a, b2) => a.name < b2.name ? -1 : a.name > b2.name ? 1 : 0);
34788
34857
  return [...builtinBlock, ...fsBlock];
@@ -34888,7 +34957,7 @@ var PersonaManager = class {
34888
34957
 
34889
34958
  // src/persona/seed.ts
34890
34959
  var fs9 = __toESM(require("fs"), 1);
34891
- var path12 = __toESM(require("path"), 1);
34960
+ var path11 = __toESM(require("path"), 1);
34892
34961
  var import_node_url = require("url");
34893
34962
  var import_meta = {};
34894
34963
  var DEFAULT_PERSONAS = [
@@ -34928,9 +34997,37 @@ var DEFAULT_PERSONAS = [
34928
34997
  label: "App Builder",
34929
34998
  model: "opus",
34930
34999
  iconKey: "assist",
34931
- public: false
34932
- // 不设 sandboxOverride:owner 不注入 sandbox(天然不沙箱,部署/pnpm/curl 都 freedom),
34933
- // guest sandbox-settings.json guest 沙箱配置(store.write 默认生成)。
35000
+ public: false,
35001
+ // 开发型 profile:在最严格 base(已含 Bash+文件工具)上追加 web 工具 + node/pnpm 工具链精确路径
35002
+ // + 出站全放。工具链只列精确目录(~/.nvm / pnpm store / ~/.npm),**不放宽 dot 目录**(~/.config 含
35003
+ // gh/gcloud 凭证、~/.local/bin 在 PATH 可被植入),避免 secrets 暴露 + 提权。mac/linux 两套 pnpm store 都列。
35004
+ sandboxProfile: {
35005
+ // base 只 Bash,开发型在此放开文件工具 + web 工具(OS 沙箱 carve 兜底文件边界)。
35006
+ // .secrets 只 app-builder 有 → 这里加 deny(其余 persona base 不默认带 .secrets)。
35007
+ // defaultMode bypassPermissions:开发流频繁用工具,免逐次审批;deny 规则仍生效、OS 沙箱照管(已验证)。
35008
+ permissions: {
35009
+ defaultMode: "bypassPermissions",
35010
+ allow: ["Read", "Edit", "Write", "Glob", "Grep", "WebFetch", "WebSearch"],
35011
+ deny: ["Read(./.secrets/**)"]
35012
+ },
35013
+ sandbox: {
35014
+ filesystem: {
35015
+ // ~/.npmrc:registry 认证配置(私有源 token),不读会 pnpm install 403;单文件精确放行。
35016
+ // ~/Library/Preferences/pnpm:mac 上 pnpm 全局 rc 目录(env-paths config),不读会 WARN EPERM。
35017
+ allowRead: ["~/.npmrc", "~/Library/Preferences/pnpm", "~/.nvm", "~/Library/pnpm", "~/.local/share/pnpm", "~/.local/state/pnpm", "~/.npm", "~/.pnpm-store"],
35018
+ allowWrite: ["~/Library/pnpm", "~/.local/share/pnpm", "~/.local/state/pnpm", "~/.npm", "~/.pnpm-store"]
35019
+ },
35020
+ // 网络:CC 沙箱出站强制走它自管的 MITM proxy 按 allowedDomains 过滤,**没有全开档**——'*' 或空白名单
35021
+ // 都被全拦(matcher JL8:plain 域名只精确匹配,'*.xxx' 是 host.endsWith('.xxx'),且对裸 IP 返回 false)。
35022
+ // 用一组常见顶级域通配近似"全放行",几乎零维护即可覆盖 npm/pnpm/git 全生态(registry.npmjs.org→*.org、
35023
+ // npm.jsr.io→*.io、github/githubusercontent→*.com…)。代价:仍挡掉直连 IP 外联(正常包安装都走域名,
35024
+ // 反而是一道防裸 IP 外泄的兜底)。需要别的 TLD 往这里加。allowLocalBinding 控本机 bind,与出站正交。
35025
+ network: {
35026
+ allowedDomains: ["*.com", "*.org", "*.io", "*.net", "*.dev", "*.app", "*.cn", "*.co", "*.chat", "*.ai"],
35027
+ allowLocalBinding: true
35028
+ }
35029
+ }
35030
+ }
34934
35031
  },
34935
35032
  {
34936
35033
  personaId: "persona-developer",
@@ -34950,14 +35047,14 @@ var DEFAULT_PERSONAS = [
34950
35047
  function findDefaultsRoot() {
34951
35048
  const candidates = [];
34952
35049
  try {
34953
- const here = path12.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
34954
- candidates.push(path12.resolve(here, "defaults"));
34955
- candidates.push(path12.resolve(here, "persona-defaults"));
35050
+ const here = path11.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
35051
+ candidates.push(path11.resolve(here, "defaults"));
35052
+ candidates.push(path11.resolve(here, "persona-defaults"));
34956
35053
  } catch {
34957
35054
  }
34958
35055
  if (process.argv[1]) {
34959
- const argvDir = path12.dirname(process.argv[1]);
34960
- candidates.push(path12.resolve(argvDir, "persona-defaults"));
35056
+ const argvDir = path11.dirname(process.argv[1]);
35057
+ candidates.push(path11.resolve(argvDir, "persona-defaults"));
34961
35058
  }
34962
35059
  for (const c of candidates) {
34963
35060
  try {
@@ -34974,7 +35071,7 @@ function seedDefaultPersonas(args) {
34974
35071
  args.logger.info("persona.seed.skip", { personaId: entry.personaId, reason: "exists" });
34975
35072
  continue;
34976
35073
  }
34977
- const bundleDir = path12.join(args.defaultsRoot, entry.personaId);
35074
+ const bundleDir = path11.join(args.defaultsRoot, entry.personaId);
34978
35075
  if (!fs9.existsSync(bundleDir)) {
34979
35076
  args.logger.warn("persona.seed.skip", {
34980
35077
  personaId: entry.personaId,
@@ -34983,7 +35080,7 @@ function seedDefaultPersonas(args) {
34983
35080
  });
34984
35081
  continue;
34985
35082
  }
34986
- const claudeMdPath = path12.join(bundleDir, "CLAUDE.md");
35083
+ const claudeMdPath = path11.join(bundleDir, "CLAUDE.md");
34987
35084
  if (!fs9.existsSync(claudeMdPath)) {
34988
35085
  args.logger.warn("persona.seed.skip", {
34989
35086
  personaId: entry.personaId,
@@ -35004,9 +35101,10 @@ function seedDefaultPersonas(args) {
35004
35101
  updatedAt: now
35005
35102
  };
35006
35103
  args.store.write(persona, personality);
35007
- if (entry.sandboxOverride) {
35008
- args.store.writeSandboxSettings(entry.personaId, entry.sandboxOverride);
35009
- args.logger.info("persona.seed.sandbox-override", { personaId: entry.personaId });
35104
+ if (entry.sandboxProfile) {
35105
+ const settings = applyProfile(buildGuestSettingsV1(), entry.sandboxProfile);
35106
+ args.store.writeSandboxSettings(entry.personaId, settings);
35107
+ args.logger.info("persona.seed.sandbox-profile", { personaId: entry.personaId });
35010
35108
  }
35011
35109
  copyBundleExtras(bundleDir, args.store.personaDirPath(entry.personaId));
35012
35110
  args.logger.info("persona.seed.created", { personaId: entry.personaId });
@@ -35015,8 +35113,8 @@ function seedDefaultPersonas(args) {
35015
35113
  function copyBundleExtras(srcDir, dstDir) {
35016
35114
  for (const entry of fs9.readdirSync(srcDir, { withFileTypes: true })) {
35017
35115
  if (entry.name === "CLAUDE.md" || entry.name === ".clawd") continue;
35018
- const srcPath = path12.join(srcDir, entry.name);
35019
- const dstPath = path12.join(dstDir, entry.name);
35116
+ const srcPath = path11.join(srcDir, entry.name);
35117
+ const dstPath = path11.join(dstDir, entry.name);
35020
35118
  if (entry.isDirectory()) {
35021
35119
  fs9.cpSync(srcPath, dstPath, { recursive: true, dereference: true });
35022
35120
  } else if (entry.isFile()) {
@@ -35028,14 +35126,14 @@ var DAEMON_MANAGED_PATHS = ["extension-kit", "CLAUDE.md", ".mcp.json"];
35028
35126
  function refreshDaemonManagedDirs(args) {
35029
35127
  const entries = args.entries ?? DEFAULT_PERSONAS;
35030
35128
  for (const entry of entries) {
35031
- const bundleDir = path12.join(args.defaultsRoot, entry.personaId);
35129
+ const bundleDir = path11.join(args.defaultsRoot, entry.personaId);
35032
35130
  if (!fs9.existsSync(bundleDir)) continue;
35033
35131
  const personaDir = args.store.personaDirPath(entry.personaId);
35034
35132
  if (!fs9.existsSync(personaDir)) continue;
35035
35133
  for (const relPath of DAEMON_MANAGED_PATHS) {
35036
- const srcPath = path12.join(bundleDir, relPath);
35134
+ const srcPath = path11.join(bundleDir, relPath);
35037
35135
  if (!fs9.existsSync(srcPath)) continue;
35038
- const dstPath = path12.join(personaDir, relPath);
35136
+ const dstPath = path11.join(personaDir, relPath);
35039
35137
  try {
35040
35138
  fs9.cpSync(srcPath, dstPath, { recursive: true, force: true, dereference: true });
35041
35139
  args.logger.info("persona.refresh.synced", {
@@ -35059,7 +35157,7 @@ init_claude();
35059
35157
  // src/tools/claude-tui.ts
35060
35158
  var import_node_fs10 = __toESM(require("fs"), 1);
35061
35159
  var import_node_os5 = __toESM(require("os"), 1);
35062
- var import_node_path11 = __toESM(require("path"), 1);
35160
+ var import_node_path10 = __toESM(require("path"), 1);
35063
35161
  var import_headless = __toESM(require_xterm_headless(), 1);
35064
35162
 
35065
35163
  // ../node_modules/.pnpm/@xterm+addon-serialize@0.14.0/node_modules/@xterm/addon-serialize/lib/addon-serialize.mjs
@@ -36039,7 +36137,7 @@ function buildTuiSpawnArgs(ctx, isResume = false) {
36039
36137
  function jsonlExistsForCtx(ctx) {
36040
36138
  if (!ctx.toolSessionId) return false;
36041
36139
  const home = import_node_os5.default.homedir();
36042
- const file = import_node_path11.default.join(home, ".claude", "projects", cwdToHashDir(ctx.cwd), `${ctx.toolSessionId}.jsonl`);
36140
+ const file = import_node_path10.default.join(home, ".claude", "projects", cwdToHashDir(ctx.cwd), `${ctx.toolSessionId}.jsonl`);
36043
36141
  try {
36044
36142
  return import_node_fs10.default.statSync(file).isFile();
36045
36143
  } catch {
@@ -36053,14 +36151,14 @@ init_claude_history();
36053
36151
  // src/workspace/browser.ts
36054
36152
  var import_node_fs11 = __toESM(require("fs"), 1);
36055
36153
  var import_node_os6 = __toESM(require("os"), 1);
36056
- var import_node_path12 = __toESM(require("path"), 1);
36154
+ var import_node_path11 = __toESM(require("path"), 1);
36057
36155
  init_protocol();
36058
36156
  var MAX_FILE_BYTES = 2 * 1024 * 1024;
36059
36157
  function resolveInsideCwd(cwd, subpath) {
36060
- const absCwd = import_node_path12.default.resolve(cwd);
36061
- const joined = import_node_path12.default.resolve(absCwd, subpath ?? ".");
36062
- const rel = import_node_path12.default.relative(absCwd, joined);
36063
- if (rel.startsWith("..") || import_node_path12.default.isAbsolute(rel)) {
36158
+ const absCwd = import_node_path11.default.resolve(cwd);
36159
+ const joined = import_node_path11.default.resolve(absCwd, subpath ?? ".");
36160
+ const rel = import_node_path11.default.relative(absCwd, joined);
36161
+ if (rel.startsWith("..") || import_node_path11.default.isAbsolute(rel)) {
36064
36162
  throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
36065
36163
  }
36066
36164
  return joined;
@@ -36091,7 +36189,7 @@ var WorkspaceBrowser = class {
36091
36189
  mtime: ""
36092
36190
  };
36093
36191
  try {
36094
- const st = import_node_fs11.default.statSync(import_node_path12.default.join(full, d.name));
36192
+ const st = import_node_fs11.default.statSync(import_node_path11.default.join(full, d.name));
36095
36193
  entry.mtime = new Date(st.mtimeMs).toISOString();
36096
36194
  if (d.isFile()) entry.size = st.size;
36097
36195
  } catch {
@@ -36138,7 +36236,7 @@ var WorkspaceBrowser = class {
36138
36236
  // src/skills/agents-scanner.ts
36139
36237
  var import_node_fs12 = __toESM(require("fs"), 1);
36140
36238
  var import_node_os7 = __toESM(require("os"), 1);
36141
- var import_node_path13 = __toESM(require("path"), 1);
36239
+ var import_node_path12 = __toESM(require("path"), 1);
36142
36240
  var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
36143
36241
  function isDirLikeSync2(p2) {
36144
36242
  try {
@@ -36176,10 +36274,10 @@ function scanAgentsDir(dir, source, seen, out) {
36176
36274
  }
36177
36275
  for (const ent of entries) {
36178
36276
  if (!ent.name.endsWith(".md")) continue;
36179
- if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path13.default.join(dir, ent.name)))) {
36277
+ if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path12.default.join(dir, ent.name)))) {
36180
36278
  continue;
36181
36279
  }
36182
- const filePath = import_node_path13.default.join(dir, ent.name);
36280
+ const filePath = import_node_path12.default.join(dir, ent.name);
36183
36281
  const baseName = ent.name.replace(/\.md$/, "");
36184
36282
  if (seen.has(baseName)) continue;
36185
36283
  seen.add(baseName);
@@ -36202,7 +36300,7 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
36202
36300
  return;
36203
36301
  }
36204
36302
  for (const ent of entries) {
36205
- const childPath = import_node_path13.default.join(dir, ent.name);
36303
+ const childPath = import_node_path12.default.join(dir, ent.name);
36206
36304
  if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
36207
36305
  walk2(childPath, [...namespaces, ent.name]);
36208
36306
  continue;
@@ -36227,9 +36325,9 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
36227
36325
  walk2(root, []);
36228
36326
  }
36229
36327
  function readInstalledPlugins2(home) {
36230
- const pluginsDir = import_node_path13.default.join(home, ".claude", "plugins");
36231
- const v2 = import_node_path13.default.join(pluginsDir, "installed_plugins_v2.json");
36232
- const v1 = import_node_path13.default.join(pluginsDir, "installed_plugins.json");
36328
+ const pluginsDir = import_node_path12.default.join(home, ".claude", "plugins");
36329
+ const v2 = import_node_path12.default.join(pluginsDir, "installed_plugins_v2.json");
36330
+ const v1 = import_node_path12.default.join(pluginsDir, "installed_plugins.json");
36233
36331
  let raw = null;
36234
36332
  for (const candidate of [v2, v1]) {
36235
36333
  try {
@@ -36258,19 +36356,19 @@ function readInstalledPlugins2(home) {
36258
36356
  return out;
36259
36357
  }
36260
36358
  function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
36261
- let cur = import_node_path13.default.resolve(startCwd);
36262
- const fsRoot = import_node_path13.default.parse(cur).root;
36359
+ let cur = import_node_path12.default.resolve(startCwd);
36360
+ const fsRoot = import_node_path12.default.parse(cur).root;
36263
36361
  while (true) {
36264
- scanAgentsDir(import_node_path13.default.join(cur, ".claude", "agents"), "project", seen, out);
36362
+ scanAgentsDir(import_node_path12.default.join(cur, ".claude", "agents"), "project", seen, out);
36265
36363
  let hasGit = false;
36266
36364
  try {
36267
- hasGit = import_node_fs12.default.existsSync(import_node_path13.default.join(cur, ".git"));
36365
+ hasGit = import_node_fs12.default.existsSync(import_node_path12.default.join(cur, ".git"));
36268
36366
  } catch {
36269
36367
  }
36270
36368
  if (hasGit) return;
36271
36369
  if (cur === home) return;
36272
36370
  if (cur === fsRoot) return;
36273
- const parent = import_node_path13.default.dirname(cur);
36371
+ const parent = import_node_path12.default.dirname(cur);
36274
36372
  if (parent === cur) return;
36275
36373
  cur = parent;
36276
36374
  }
@@ -36305,7 +36403,7 @@ var AgentsScanner = class {
36305
36403
  }
36306
36404
  const fsBlock = [];
36307
36405
  scanAgentsDir(
36308
- import_node_path13.default.join(this.home, ".claude", "agents"),
36406
+ import_node_path12.default.join(this.home, ".claude", "agents"),
36309
36407
  "global",
36310
36408
  seen,
36311
36409
  fsBlock
@@ -36319,7 +36417,7 @@ var AgentsScanner = class {
36319
36417
  ...this.extraPluginRoots
36320
36418
  ];
36321
36419
  for (const { name, root } of plugins) {
36322
- const agentsRoot = import_node_path13.default.join(root, "agents");
36420
+ const agentsRoot = import_node_path12.default.join(root, "agents");
36323
36421
  scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
36324
36422
  }
36325
36423
  return [...builtinBlock, ...fsBlock];
@@ -36329,13 +36427,13 @@ var AgentsScanner = class {
36329
36427
  // src/observer/session-observer.ts
36330
36428
  var import_node_fs14 = __toESM(require("fs"), 1);
36331
36429
  var import_node_os9 = __toESM(require("os"), 1);
36332
- var import_node_path15 = __toESM(require("path"), 1);
36430
+ var import_node_path14 = __toESM(require("path"), 1);
36333
36431
  init_claude_history();
36334
36432
 
36335
36433
  // src/observer/subagent-meta-observer.ts
36336
36434
  var import_node_fs13 = __toESM(require("fs"), 1);
36337
36435
  var import_node_os8 = __toESM(require("os"), 1);
36338
- var import_node_path14 = __toESM(require("path"), 1);
36436
+ var import_node_path13 = __toESM(require("path"), 1);
36339
36437
  init_claude_history();
36340
36438
  var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
36341
36439
  var SubagentMetaObserver = class {
@@ -36348,7 +36446,7 @@ var SubagentMetaObserver = class {
36348
36446
  watches = /* @__PURE__ */ new Map();
36349
36447
  // public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
36350
36448
  resolveSubagentDir(cwd, toolSessionId) {
36351
- return import_node_path14.default.join(
36449
+ return import_node_path13.default.join(
36352
36450
  this.home,
36353
36451
  ".claude",
36354
36452
  "projects",
@@ -36404,7 +36502,7 @@ var SubagentMetaObserver = class {
36404
36502
  if (!m2) return;
36405
36503
  const agentId = m2[1];
36406
36504
  if (w2.emitted.has(agentId)) return;
36407
- const file = import_node_path14.default.join(w2.dirPath, name);
36505
+ const file = import_node_path13.default.join(w2.dirPath, name);
36408
36506
  let raw;
36409
36507
  try {
36410
36508
  raw = import_node_fs13.default.readFileSync(file, "utf8");
@@ -36464,7 +36562,7 @@ var SessionObserver = class {
36464
36562
  metaObserver;
36465
36563
  resolveJsonlPath(cwd, toolSessionId, override) {
36466
36564
  if (override) return override;
36467
- return import_node_path15.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
36565
+ return import_node_path14.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
36468
36566
  }
36469
36567
  start(args) {
36470
36568
  this.stop(args.sessionId);
@@ -36485,10 +36583,10 @@ var SessionObserver = class {
36485
36583
  prevIsRejectSentinel: false
36486
36584
  };
36487
36585
  try {
36488
- import_node_fs14.default.mkdirSync(import_node_path15.default.dirname(filePath), { recursive: true });
36586
+ import_node_fs14.default.mkdirSync(import_node_path14.default.dirname(filePath), { recursive: true });
36489
36587
  } catch {
36490
36588
  }
36491
- w2.watcher = import_node_fs14.default.watch(import_node_path15.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
36589
+ w2.watcher = import_node_fs14.default.watch(import_node_path14.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
36492
36590
  if (!changedName || !filePath.endsWith(changedName)) return;
36493
36591
  this.poll(w2);
36494
36592
  });
@@ -37295,7 +37393,7 @@ async function authenticate(token, deps) {
37295
37393
 
37296
37394
  // src/permission/capability-store.ts
37297
37395
  var fs17 = __toESM(require("fs"), 1);
37298
- var path20 = __toESM(require("path"), 1);
37396
+ var path19 = __toESM(require("path"), 1);
37299
37397
  var CAPABILITIES_FILE_NAME = "capabilities.json";
37300
37398
  var FILE_VERSION = 1;
37301
37399
  var CapabilityStore = class {
@@ -37325,7 +37423,7 @@ var CapabilityStore = class {
37325
37423
  this.flush();
37326
37424
  }
37327
37425
  filePath() {
37328
- return path20.join(this.dataDir, CAPABILITIES_FILE_NAME);
37426
+ return path19.join(this.dataDir, CAPABILITIES_FILE_NAME);
37329
37427
  }
37330
37428
  readFromDisk() {
37331
37429
  const file = this.filePath();
@@ -37472,7 +37570,7 @@ function cleanupGuestSessionsForCapability(cap, factory) {
37472
37570
 
37473
37571
  // src/inbox/inbox-store.ts
37474
37572
  var fs19 = __toESM(require("fs"), 1);
37475
- var path21 = __toESM(require("path"), 1);
37573
+ var path20 = __toESM(require("path"), 1);
37476
37574
  var INBOX_SUBDIR = "inbox";
37477
37575
  var InboxStore = class {
37478
37576
  constructor(dataDir) {
@@ -37570,10 +37668,10 @@ var InboxStore = class {
37570
37668
  }
37571
37669
  }
37572
37670
  dirPath() {
37573
- return path21.join(this.dataDir, INBOX_SUBDIR);
37671
+ return path20.join(this.dataDir, INBOX_SUBDIR);
37574
37672
  }
37575
37673
  filePath(peerDeviceId) {
37576
- return path21.join(this.dirPath(), `${peerDeviceId}.jsonl`);
37674
+ return path20.join(this.dirPath(), `${peerDeviceId}.jsonl`);
37577
37675
  }
37578
37676
  };
37579
37677
  function parseAllLines(raw) {
@@ -37661,7 +37759,7 @@ var InboxManager = class {
37661
37759
 
37662
37760
  // src/state/contact-store.ts
37663
37761
  var fs20 = __toESM(require("fs"), 1);
37664
- var path22 = __toESM(require("path"), 1);
37762
+ var path21 = __toESM(require("path"), 1);
37665
37763
  var FILE_NAME = "contacts.json";
37666
37764
  var ContactStore = class {
37667
37765
  constructor(dataDir) {
@@ -37671,7 +37769,7 @@ var ContactStore = class {
37671
37769
  contacts = /* @__PURE__ */ new Map();
37672
37770
  load() {
37673
37771
  this.contacts.clear();
37674
- const file = path22.join(this.dataDir, FILE_NAME);
37772
+ const file = path21.join(this.dataDir, FILE_NAME);
37675
37773
  let raw;
37676
37774
  try {
37677
37775
  raw = fs20.readFileSync(file, "utf8");
@@ -37717,7 +37815,7 @@ var ContactStore = class {
37717
37815
  return existed;
37718
37816
  }
37719
37817
  flush() {
37720
- const file = path22.join(this.dataDir, FILE_NAME);
37818
+ const file = path21.join(this.dataDir, FILE_NAME);
37721
37819
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
37722
37820
  const content = JSON.stringify(
37723
37821
  { contacts: Array.from(this.contacts.values()) },
@@ -37866,52 +37964,52 @@ async function autoReverseContact(args) {
37866
37964
 
37867
37965
  // src/migrations/2026-05-20-flatten-sessions.ts
37868
37966
  var fs21 = __toESM(require("fs"), 1);
37869
- var path23 = __toESM(require("path"), 1);
37967
+ var path22 = __toESM(require("path"), 1);
37870
37968
  var MIGRATION_FLAG_NAME = ".migration.v1.done";
37871
37969
  function migrateFlattenSessions(opts) {
37872
37970
  const dataDir = opts.dataDir;
37873
37971
  const now = opts.now ?? Date.now;
37874
- const sessionsDir = path23.join(dataDir, "sessions");
37875
- const flagPath = path23.join(sessionsDir, MIGRATION_FLAG_NAME);
37972
+ const sessionsDir = path22.join(dataDir, "sessions");
37973
+ const flagPath = path22.join(sessionsDir, MIGRATION_FLAG_NAME);
37876
37974
  if (existsSync3(flagPath)) {
37877
37975
  return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
37878
37976
  }
37879
37977
  let movedBare = 0;
37880
37978
  let movedVmOwner = 0;
37881
37979
  let archivedListener = 0;
37882
- const defaultDir = path23.join(sessionsDir, "default");
37980
+ const defaultDir = path22.join(sessionsDir, "default");
37883
37981
  if (existsSync3(defaultDir)) {
37884
37982
  for (const entry of readdirSafe(defaultDir)) {
37885
37983
  if (!entry.endsWith(".json")) continue;
37886
- const src = path23.join(defaultDir, entry);
37887
- const dst = path23.join(sessionsDir, entry);
37984
+ const src = path22.join(defaultDir, entry);
37985
+ const dst = path22.join(sessionsDir, entry);
37888
37986
  fs21.renameSync(src, dst);
37889
37987
  movedBare += 1;
37890
37988
  }
37891
37989
  rmdirIfEmpty(defaultDir);
37892
37990
  }
37893
37991
  for (const pid of readdirSafe(sessionsDir)) {
37894
- const personaDir = path23.join(sessionsDir, pid);
37992
+ const personaDir = path22.join(sessionsDir, pid);
37895
37993
  if (!isDir(personaDir)) continue;
37896
37994
  if (pid === "default") continue;
37897
- const ownerSrc = path23.join(personaDir, "owner");
37995
+ const ownerSrc = path22.join(personaDir, "owner");
37898
37996
  if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
37899
- const ownerDst = path23.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
37997
+ const ownerDst = path22.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
37900
37998
  fs21.mkdirSync(ownerDst, { recursive: true });
37901
37999
  for (const file of readdirSafe(ownerSrc)) {
37902
38000
  if (!file.endsWith(".json")) continue;
37903
- fs21.renameSync(path23.join(ownerSrc, file), path23.join(ownerDst, file));
38001
+ fs21.renameSync(path22.join(ownerSrc, file), path22.join(ownerDst, file));
37904
38002
  movedVmOwner += 1;
37905
38003
  }
37906
38004
  rmdirIfEmpty(ownerSrc);
37907
38005
  }
37908
- const listenerSrc = path23.join(personaDir, "listener");
38006
+ const listenerSrc = path22.join(personaDir, "listener");
37909
38007
  if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
37910
- const archiveDst = path23.join(dataDir, ".legacy", `listener-${pid}`);
38008
+ const archiveDst = path22.join(dataDir, ".legacy", `listener-${pid}`);
37911
38009
  fs21.mkdirSync(archiveDst, { recursive: true });
37912
38010
  for (const file of readdirSafe(listenerSrc)) {
37913
38011
  if (!file.endsWith(".json")) continue;
37914
- fs21.renameSync(path23.join(listenerSrc, file), path23.join(archiveDst, file));
38012
+ fs21.renameSync(path22.join(listenerSrc, file), path22.join(archiveDst, file));
37915
38013
  archivedListener += 1;
37916
38014
  }
37917
38015
  rmdirIfEmpty(listenerSrc);
@@ -37959,10 +38057,10 @@ function rmdirIfEmpty(p2) {
37959
38057
 
37960
38058
  // src/transport/http-router.ts
37961
38059
  var import_node_fs16 = __toESM(require("fs"), 1);
37962
- var import_node_path19 = __toESM(require("path"), 1);
38060
+ var import_node_path18 = __toESM(require("path"), 1);
37963
38061
 
37964
38062
  // src/attachment/mime.ts
37965
- var import_node_path16 = __toESM(require("path"), 1);
38063
+ var import_node_path15 = __toESM(require("path"), 1);
37966
38064
  var TEXT_PLAIN = "text/plain; charset=utf-8";
37967
38065
  var EXT_TO_NATIVE_MIME = {
37968
38066
  // 图片
@@ -38069,7 +38167,7 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
38069
38167
  ".mk"
38070
38168
  ]);
38071
38169
  function lookupMime(filePathOrName) {
38072
- const ext = import_node_path16.default.extname(filePathOrName).toLowerCase();
38170
+ const ext = import_node_path15.default.extname(filePathOrName).toLowerCase();
38073
38171
  if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
38074
38172
  if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
38075
38173
  return "application/octet-stream";
@@ -38139,7 +38237,7 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
38139
38237
 
38140
38238
  // src/attachment/upload.ts
38141
38239
  var import_node_fs15 = __toESM(require("fs"), 1);
38142
- var import_node_path17 = __toESM(require("path"), 1);
38240
+ var import_node_path16 = __toESM(require("path"), 1);
38143
38241
  var import_node_crypto5 = __toESM(require("crypto"), 1);
38144
38242
  var import_promises = require("stream/promises");
38145
38243
  var UploadError = class extends Error {
@@ -38151,14 +38249,14 @@ var UploadError = class extends Error {
38151
38249
  code;
38152
38250
  };
38153
38251
  function assertValidFileName(fileName) {
38154
- if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path17.default.basename(fileName)) {
38252
+ if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path16.default.basename(fileName)) {
38155
38253
  throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
38156
38254
  }
38157
38255
  }
38158
38256
  var HASH_PREFIX_LEN = 16;
38159
38257
  async function writeUploadedAttachment(args) {
38160
38258
  assertValidFileName(args.fileName);
38161
- const attachmentsRoot = import_node_path17.default.join(args.sessionDir, ".attachments");
38259
+ const attachmentsRoot = import_node_path16.default.join(args.sessionDir, ".attachments");
38162
38260
  try {
38163
38261
  import_node_fs15.default.mkdirSync(attachmentsRoot, { recursive: true });
38164
38262
  } catch (err) {
@@ -38166,7 +38264,7 @@ async function writeUploadedAttachment(args) {
38166
38264
  }
38167
38265
  const hasher = import_node_crypto5.default.createHash("sha256");
38168
38266
  let actualSize = 0;
38169
- const tmpPath = import_node_path17.default.join(
38267
+ const tmpPath = import_node_path16.default.join(
38170
38268
  attachmentsRoot,
38171
38269
  `.upload-${process.pid}-${Date.now()}-${import_node_crypto5.default.randomBytes(4).toString("hex")}`
38172
38270
  );
@@ -38201,7 +38299,7 @@ async function writeUploadedAttachment(args) {
38201
38299
  );
38202
38300
  }
38203
38301
  const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
38204
- const hashDir = import_node_path17.default.join(attachmentsRoot, attachmentId);
38302
+ const hashDir = import_node_path16.default.join(attachmentsRoot, attachmentId);
38205
38303
  let finalFileName;
38206
38304
  let hashDirExists = false;
38207
38305
  try {
@@ -38219,7 +38317,7 @@ async function writeUploadedAttachment(args) {
38219
38317
  try {
38220
38318
  import_node_fs15.default.mkdirSync(hashDir, { recursive: true });
38221
38319
  finalFileName = args.fileName;
38222
- import_node_fs15.default.renameSync(tmpPath, import_node_path17.default.join(hashDir, finalFileName));
38320
+ import_node_fs15.default.renameSync(tmpPath, import_node_path16.default.join(hashDir, finalFileName));
38223
38321
  } catch (err) {
38224
38322
  try {
38225
38323
  import_node_fs15.default.unlinkSync(tmpPath);
@@ -38228,8 +38326,8 @@ async function writeUploadedAttachment(args) {
38228
38326
  throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
38229
38327
  }
38230
38328
  }
38231
- const absPath = import_node_path17.default.join(hashDir, finalFileName);
38232
- const relPath = import_node_path17.default.relative(args.sessionDir, absPath);
38329
+ const absPath = import_node_path16.default.join(hashDir, finalFileName);
38330
+ const relPath = import_node_path16.default.relative(args.sessionDir, absPath);
38233
38331
  args.groupFileStore.upsert(args.scope, args.sessionId, {
38234
38332
  relPath: absPath,
38235
38333
  // 存绝对路径,与现有 agent 入清单的形态一致(attachment.ts:144 双形态兼容)
@@ -38243,7 +38341,7 @@ async function writeUploadedAttachment(args) {
38243
38341
 
38244
38342
  // src/extension/import.ts
38245
38343
  var import_promises2 = __toESM(require("fs/promises"), 1);
38246
- var import_node_path18 = __toESM(require("path"), 1);
38344
+ var import_node_path17 = __toESM(require("path"), 1);
38247
38345
  var import_node_os10 = __toESM(require("os"), 1);
38248
38346
  var import_jszip = __toESM(require_lib3(), 1);
38249
38347
  var ImportError = class extends Error {
@@ -38261,7 +38359,7 @@ async function importZip(buf, root) {
38261
38359
  throw new ImportError("ZIP_INVALID", `failed to load zip: ${e.message}`);
38262
38360
  }
38263
38361
  for (const name of Object.keys(zip.files)) {
38264
- if (name.includes("..") || name.startsWith("/") || import_node_path18.default.isAbsolute(name)) {
38362
+ if (name.includes("..") || name.startsWith("/") || import_node_path17.default.isAbsolute(name)) {
38265
38363
  throw new ImportError("ZIP_INVALID", `unsafe zip entry path: ${name}`);
38266
38364
  }
38267
38365
  }
@@ -38294,7 +38392,7 @@ async function importZip(buf, root) {
38294
38392
  );
38295
38393
  }
38296
38394
  }
38297
- const destDir = import_node_path18.default.join(root, manifest.id);
38395
+ const destDir = import_node_path17.default.join(root, manifest.id);
38298
38396
  let destExists = false;
38299
38397
  try {
38300
38398
  await import_promises2.default.access(destDir);
@@ -38304,15 +38402,15 @@ async function importZip(buf, root) {
38304
38402
  if (destExists) {
38305
38403
  throw new ImportError("ALREADY_EXISTS", `extension ${manifest.id} already installed`);
38306
38404
  }
38307
- const stage = await import_promises2.default.mkdtemp(import_node_path18.default.join(import_node_os10.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
38405
+ const stage = await import_promises2.default.mkdtemp(import_node_path17.default.join(import_node_os10.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
38308
38406
  try {
38309
38407
  for (const [name, entry] of Object.entries(zip.files)) {
38310
- const dest = import_node_path18.default.join(stage, name);
38408
+ const dest = import_node_path17.default.join(stage, name);
38311
38409
  if (entry.dir) {
38312
38410
  await import_promises2.default.mkdir(dest, { recursive: true });
38313
38411
  continue;
38314
38412
  }
38315
- await import_promises2.default.mkdir(import_node_path18.default.dirname(dest), { recursive: true });
38413
+ await import_promises2.default.mkdir(import_node_path17.default.dirname(dest), { recursive: true });
38316
38414
  const content = await entry.async("nodebuffer");
38317
38415
  await import_promises2.default.writeFile(dest, content);
38318
38416
  }
@@ -38426,7 +38524,7 @@ function isValidUploadFileName(fileName) {
38426
38524
  if (fileName === "." || fileName === "..") return false;
38427
38525
  if (fileName.startsWith(".")) return false;
38428
38526
  if (fileName.includes("/") || fileName.includes("\\")) return false;
38429
- return fileName === import_node_path19.default.basename(fileName);
38527
+ return fileName === import_node_path18.default.basename(fileName);
38430
38528
  }
38431
38529
  function createHttpRouter(deps) {
38432
38530
  return async (req, res) => {
@@ -38655,7 +38753,7 @@ function createHttpRouter(deps) {
38655
38753
  return true;
38656
38754
  }
38657
38755
  let absPath;
38658
- if (import_node_path19.default.isAbsolute(pathParam)) {
38756
+ if (import_node_path18.default.isAbsolute(pathParam)) {
38659
38757
  absPath = pathParam;
38660
38758
  } else if (deps.sessionStore) {
38661
38759
  const file = deps.sessionStore.read(sid);
@@ -38663,7 +38761,7 @@ function createHttpRouter(deps) {
38663
38761
  sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
38664
38762
  return true;
38665
38763
  }
38666
- absPath = import_node_path19.default.join(file.cwd, pathParam);
38764
+ absPath = import_node_path18.default.join(file.cwd, pathParam);
38667
38765
  } else {
38668
38766
  sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
38669
38767
  return true;
@@ -38761,7 +38859,7 @@ function streamFile(res, absPath, logger) {
38761
38859
  return;
38762
38860
  }
38763
38861
  const mime = lookupMime(absPath);
38764
- const basename = import_node_path19.default.basename(absPath);
38862
+ const basename = import_node_path18.default.basename(absPath);
38765
38863
  res.writeHead(200, {
38766
38864
  "Content-Type": mime,
38767
38865
  "Content-Length": String(stat.size),
@@ -38779,7 +38877,7 @@ function streamFile(res, absPath, logger) {
38779
38877
 
38780
38878
  // src/attachment/gc.ts
38781
38879
  var import_node_fs17 = __toESM(require("fs"), 1);
38782
- var import_node_path20 = __toESM(require("path"), 1);
38880
+ var import_node_path19 = __toESM(require("path"), 1);
38783
38881
  var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
38784
38882
  function runAttachmentGc(args) {
38785
38883
  const now = (args.now ?? Date.now)();
@@ -38788,17 +38886,17 @@ function runAttachmentGc(args) {
38788
38886
  for (const { scope, sessionId } of args.sessionScopes) {
38789
38887
  for (const entry of args.groupFileStore.list(scope, sessionId)) {
38790
38888
  if (entry.stale) continue;
38791
- if (import_node_path20.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
38889
+ if (import_node_path19.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
38792
38890
  }
38793
38891
  }
38794
38892
  for (const { scope, sessionId } of args.sessionScopes) {
38795
- const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path20.default.join(
38893
+ const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path19.default.join(
38796
38894
  args.dataDir,
38797
38895
  "sessions",
38798
38896
  ...scopeSubPath(scope).map(safeFileName),
38799
38897
  safeFileName(sessionId)
38800
38898
  );
38801
- const attRoot = import_node_path20.default.join(sessionDir, ".attachments");
38899
+ const attRoot = import_node_path19.default.join(sessionDir, ".attachments");
38802
38900
  let hashDirs;
38803
38901
  try {
38804
38902
  hashDirs = import_node_fs17.default.readdirSync(attRoot);
@@ -38808,7 +38906,7 @@ function runAttachmentGc(args) {
38808
38906
  continue;
38809
38907
  }
38810
38908
  for (const hashDir of hashDirs) {
38811
- const hashDirAbs = import_node_path20.default.join(attRoot, hashDir);
38909
+ const hashDirAbs = import_node_path19.default.join(attRoot, hashDir);
38812
38910
  let files;
38813
38911
  try {
38814
38912
  files = import_node_fs17.default.readdirSync(hashDirAbs);
@@ -38816,7 +38914,7 @@ function runAttachmentGc(args) {
38816
38914
  continue;
38817
38915
  }
38818
38916
  for (const name of files) {
38819
- const file = import_node_path20.default.join(hashDirAbs, name);
38917
+ const file = import_node_path19.default.join(hashDirAbs, name);
38820
38918
  let stat;
38821
38919
  try {
38822
38920
  stat = import_node_fs17.default.statSync(file);
@@ -38847,7 +38945,7 @@ function runAttachmentGc(args) {
38847
38945
 
38848
38946
  // src/attachment/group.ts
38849
38947
  var import_node_fs18 = __toESM(require("fs"), 1);
38850
- var import_node_path21 = __toESM(require("path"), 1);
38948
+ var import_node_path20 = __toESM(require("path"), 1);
38851
38949
  var import_node_crypto6 = __toESM(require("crypto"), 1);
38852
38950
  init_protocol();
38853
38951
  var GroupFileStore = class {
@@ -38859,11 +38957,11 @@ var GroupFileStore = class {
38859
38957
  this.logger = opts.logger;
38860
38958
  }
38861
38959
  rootForScope(scope) {
38862
- return import_node_path21.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
38960
+ return import_node_path20.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
38863
38961
  }
38864
38962
  /** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
38865
38963
  filePath(scope, sessionId) {
38866
- return import_node_path21.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
38964
+ return import_node_path20.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
38867
38965
  }
38868
38966
  cacheKey(scope, sessionId) {
38869
38967
  return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
@@ -38898,7 +38996,7 @@ var GroupFileStore = class {
38898
38996
  }
38899
38997
  writeFile(scope, sessionId, entries) {
38900
38998
  const file = this.filePath(scope, sessionId);
38901
- import_node_fs18.default.mkdirSync(import_node_path21.default.dirname(file), { recursive: true });
38999
+ import_node_fs18.default.mkdirSync(import_node_path20.default.dirname(file), { recursive: true });
38902
39000
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
38903
39001
  import_node_fs18.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
38904
39002
  import_node_fs18.default.renameSync(tmp, file);
@@ -38988,9 +39086,9 @@ var GroupFileStore = class {
38988
39086
 
38989
39087
  // src/discovery/state-file.ts
38990
39088
  var import_node_fs19 = __toESM(require("fs"), 1);
38991
- var import_node_path22 = __toESM(require("path"), 1);
39089
+ var import_node_path21 = __toESM(require("path"), 1);
38992
39090
  function defaultStateFilePath(dataDir) {
38993
- return import_node_path22.default.join(dataDir, "state.json");
39091
+ return import_node_path21.default.join(dataDir, "state.json");
38994
39092
  }
38995
39093
  function isPidAlive(pid) {
38996
39094
  if (!Number.isFinite(pid) || pid <= 0) return false;
@@ -39026,7 +39124,7 @@ var StateFileManager = class {
39026
39124
  return { status: "stale", existing };
39027
39125
  }
39028
39126
  write(state) {
39029
- import_node_fs19.default.mkdirSync(import_node_path22.default.dirname(this.file), { recursive: true });
39127
+ import_node_fs19.default.mkdirSync(import_node_path21.default.dirname(this.file), { recursive: true });
39030
39128
  const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
39031
39129
  import_node_fs19.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
39032
39130
  import_node_fs19.default.renameSync(tmp, this.file);
@@ -39047,13 +39145,13 @@ var StateFileManager = class {
39047
39145
 
39048
39146
  // src/tunnel/tunnel-manager.ts
39049
39147
  var import_node_fs23 = __toESM(require("fs"), 1);
39050
- var import_node_path26 = __toESM(require("path"), 1);
39148
+ var import_node_path25 = __toESM(require("path"), 1);
39051
39149
  var import_node_crypto7 = __toESM(require("crypto"), 1);
39052
39150
  var import_node_child_process5 = require("child_process");
39053
39151
 
39054
39152
  // src/tunnel/tunnel-store.ts
39055
39153
  var import_node_fs20 = __toESM(require("fs"), 1);
39056
- var import_node_path23 = __toESM(require("path"), 1);
39154
+ var import_node_path22 = __toESM(require("path"), 1);
39057
39155
  var TunnelStore = class {
39058
39156
  constructor(filePath) {
39059
39157
  this.filePath = filePath;
@@ -39072,7 +39170,7 @@ var TunnelStore = class {
39072
39170
  }
39073
39171
  }
39074
39172
  async set(v2) {
39075
- const dir = import_node_path23.default.dirname(this.filePath);
39173
+ const dir = import_node_path22.default.dirname(this.filePath);
39076
39174
  await import_node_fs20.default.promises.mkdir(dir, { recursive: true });
39077
39175
  const data = JSON.stringify(v2, null, 2);
39078
39176
  const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
@@ -39184,7 +39282,7 @@ function escape(v2) {
39184
39282
  // src/tunnel/frpc-binary.ts
39185
39283
  var import_node_fs21 = __toESM(require("fs"), 1);
39186
39284
  var import_node_os11 = __toESM(require("os"), 1);
39187
- var import_node_path24 = __toESM(require("path"), 1);
39285
+ var import_node_path23 = __toESM(require("path"), 1);
39188
39286
  var import_node_child_process3 = require("child_process");
39189
39287
  var import_node_stream2 = require("stream");
39190
39288
  var import_promises3 = require("stream/promises");
@@ -39223,13 +39321,13 @@ async function ensureFrpcBinary(opts) {
39223
39321
  }
39224
39322
  const version2 = opts.version ?? FRPC_VERSION;
39225
39323
  const platform = opts.platform ?? detectPlatform();
39226
- const binDir = import_node_path24.default.join(opts.dataDir, "bin");
39324
+ const binDir = import_node_path23.default.join(opts.dataDir, "bin");
39227
39325
  import_node_fs21.default.mkdirSync(binDir, { recursive: true });
39228
39326
  cleanupStaleArtifacts(binDir);
39229
- const stableBin = import_node_path24.default.join(binDir, "frpc");
39327
+ const stableBin = import_node_path23.default.join(binDir, "frpc");
39230
39328
  if (import_node_fs21.default.existsSync(stableBin)) return stableBin;
39231
39329
  const partialBin = `${stableBin}.partial`;
39232
- const tarballPath = import_node_path24.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
39330
+ const tarballPath = import_node_path23.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
39233
39331
  try {
39234
39332
  const url = frpcDownloadUrl(version2, platform);
39235
39333
  await downloadToFile(url, tarballPath, opts.fetchImpl);
@@ -39255,7 +39353,7 @@ function cleanupStaleArtifacts(binDir) {
39255
39353
  }
39256
39354
  for (const name of entries) {
39257
39355
  if (name.endsWith(".partial") || name.startsWith("extract-")) {
39258
- const full = import_node_path24.default.join(binDir, name);
39356
+ const full = import_node_path23.default.join(binDir, name);
39259
39357
  try {
39260
39358
  import_node_fs21.default.rmSync(full, { recursive: true, force: true });
39261
39359
  } catch {
@@ -39281,7 +39379,7 @@ async function downloadToFile(url, dest, fetchImpl) {
39281
39379
  await (0, import_promises3.pipeline)(nodeStream, out);
39282
39380
  }
39283
39381
  async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
39284
- const work = import_node_path24.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
39382
+ const work = import_node_path23.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
39285
39383
  import_node_fs21.default.mkdirSync(work, { recursive: true });
39286
39384
  try {
39287
39385
  await new Promise((resolve6, reject) => {
@@ -39290,7 +39388,7 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
39290
39388
  proc.on("exit", (code) => code === 0 ? resolve6() : reject(new Error(`tar exited ${code}`)));
39291
39389
  });
39292
39390
  const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
39293
- const src = import_node_path24.default.join(work, dirName, "frpc");
39391
+ const src = import_node_path23.default.join(work, dirName, "frpc");
39294
39392
  if (!import_node_fs21.default.existsSync(src)) {
39295
39393
  throw new Error(`frpc not found inside tarball at ${src}`);
39296
39394
  }
@@ -39302,10 +39400,10 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
39302
39400
 
39303
39401
  // src/tunnel/frpc-process.ts
39304
39402
  var import_node_fs22 = __toESM(require("fs"), 1);
39305
- var import_node_path25 = __toESM(require("path"), 1);
39403
+ var import_node_path24 = __toESM(require("path"), 1);
39306
39404
  var import_node_child_process4 = require("child_process");
39307
39405
  function frpcPidFilePath(dataDir) {
39308
- return import_node_path25.default.join(dataDir, "frpc.pid");
39406
+ return import_node_path24.default.join(dataDir, "frpc.pid");
39309
39407
  }
39310
39408
  function writeFrpcPid(dataDir, pid) {
39311
39409
  try {
@@ -39347,7 +39445,7 @@ function defaultSleep(ms) {
39347
39445
  }
39348
39446
  async function killStaleFrpc(deps) {
39349
39447
  const pidFile = frpcPidFilePath(deps.dataDir);
39350
- const tomlPath = import_node_path25.default.join(deps.dataDir, "frpc.toml");
39448
+ const tomlPath = import_node_path24.default.join(deps.dataDir, "frpc.toml");
39351
39449
  const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
39352
39450
  const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
39353
39451
  const killPid = deps.killPidImpl ?? defaultKillPid;
@@ -39419,7 +39517,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
39419
39517
  var TunnelManager = class {
39420
39518
  constructor(deps) {
39421
39519
  this.deps = deps;
39422
- this.store = deps.store ?? new TunnelStore(import_node_path26.default.join(deps.dataDir, "tunnel.json"));
39520
+ this.store = deps.store ?? new TunnelStore(import_node_path25.default.join(deps.dataDir, "tunnel.json"));
39423
39521
  this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
39424
39522
  this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
39425
39523
  }
@@ -39546,7 +39644,7 @@ var TunnelManager = class {
39546
39644
  dataDir: this.deps.dataDir,
39547
39645
  override: this.deps.frpcBinaryOverride ?? void 0
39548
39646
  });
39549
- const tomlPath = import_node_path26.default.join(this.deps.dataDir, "frpc.toml");
39647
+ const tomlPath = import_node_path25.default.join(this.deps.dataDir, "frpc.toml");
39550
39648
  const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto7.default.randomBytes(3).toString("hex")}`;
39551
39649
  const toml = buildFrpcToml({
39552
39650
  serverAddr: t.frpsHost,
@@ -39561,7 +39659,7 @@ var TunnelManager = class {
39561
39659
  const proc = (this.deps.spawnImpl ?? import_node_child_process5.spawn)(frpcBin, ["-c", tomlPath], {
39562
39660
  stdio: ["ignore", "pipe", "pipe"]
39563
39661
  });
39564
- const logFilePath = import_node_path26.default.join(this.deps.dataDir, "frpc.log");
39662
+ const logFilePath = import_node_path25.default.join(this.deps.dataDir, "frpc.log");
39565
39663
  const logStream = import_node_fs23.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
39566
39664
  logStream.on("error", () => {
39567
39665
  });
@@ -39645,15 +39743,15 @@ async function waitForFrpcReady(proc, timeoutMs) {
39645
39743
 
39646
39744
  // src/tunnel/device-key.ts
39647
39745
  var import_node_os12 = __toESM(require("os"), 1);
39648
- var import_node_path27 = __toESM(require("path"), 1);
39746
+ var import_node_path26 = __toESM(require("path"), 1);
39649
39747
  var import_node_crypto8 = __toESM(require("crypto"), 1);
39650
39748
  var DERIVE_SALT = "clawd-tunnel-device-v1";
39651
39749
  function deriveStableDeviceKey(opts = {}) {
39652
39750
  const hostname = opts.hostname ?? import_node_os12.default.hostname();
39653
39751
  const uid = opts.uid ?? (typeof import_node_os12.default.userInfo === "function" ? import_node_os12.default.userInfo().uid : 0);
39654
39752
  const home = opts.home ?? import_node_os12.default.homedir();
39655
- const defaultDataDir = import_node_path27.default.resolve(import_node_path27.default.join(home, ".clawd"));
39656
- const normalizedDataDir = opts.dataDir ? import_node_path27.default.resolve(opts.dataDir) : null;
39753
+ const defaultDataDir = import_node_path26.default.resolve(import_node_path26.default.join(home, ".clawd"));
39754
+ const normalizedDataDir = opts.dataDir ? import_node_path26.default.resolve(opts.dataDir) : null;
39657
39755
  const isDefaultDir = normalizedDataDir == null || normalizedDataDir === defaultDataDir;
39658
39756
  const input = isDefaultDir ? `${hostname}::${uid}` : `${hostname}::${uid}::${normalizedDataDir}`;
39659
39757
  return import_node_crypto8.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
@@ -39661,11 +39759,11 @@ function deriveStableDeviceKey(opts = {}) {
39661
39759
 
39662
39760
  // src/auth-store.ts
39663
39761
  var import_node_fs24 = __toESM(require("fs"), 1);
39664
- var import_node_path28 = __toESM(require("path"), 1);
39762
+ var import_node_path27 = __toESM(require("path"), 1);
39665
39763
  var import_node_crypto9 = __toESM(require("crypto"), 1);
39666
39764
  var AUTH_FILE_NAME = "auth.json";
39667
39765
  function authFilePath(dataDir) {
39668
- return import_node_path28.default.join(dataDir, AUTH_FILE_NAME);
39766
+ return import_node_path27.default.join(dataDir, AUTH_FILE_NAME);
39669
39767
  }
39670
39768
  function loadOrCreateAuthFile(opts) {
39671
39769
  const file = authFilePath(opts.dataDir);
@@ -39718,7 +39816,7 @@ function readAuthFile(file) {
39718
39816
  }
39719
39817
  }
39720
39818
  function writeAuthFile(file, content) {
39721
- import_node_fs24.default.mkdirSync(import_node_path28.default.dirname(file), { recursive: true });
39819
+ import_node_fs24.default.mkdirSync(import_node_path27.default.dirname(file), { recursive: true });
39722
39820
  import_node_fs24.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
39723
39821
  try {
39724
39822
  import_node_fs24.default.chmodSync(file, 384);
@@ -39729,11 +39827,11 @@ function writeAuthFile(file, content) {
39729
39827
  // src/owner-profile.ts
39730
39828
  var import_node_fs25 = __toESM(require("fs"), 1);
39731
39829
  var import_node_os13 = __toESM(require("os"), 1);
39732
- var import_node_path29 = __toESM(require("path"), 1);
39830
+ var import_node_path28 = __toESM(require("path"), 1);
39733
39831
  var PROFILE_FILENAME = "profile.json";
39734
39832
  function loadOwnerDisplayName(dataDir) {
39735
39833
  const fallback = import_node_os13.default.userInfo().username;
39736
- const profilePath = import_node_path29.default.join(dataDir, PROFILE_FILENAME);
39834
+ const profilePath = import_node_path28.default.join(dataDir, PROFILE_FILENAME);
39737
39835
  let raw;
39738
39836
  try {
39739
39837
  raw = import_node_fs25.default.readFileSync(profilePath, "utf8");
@@ -39760,12 +39858,12 @@ function loadOwnerDisplayName(dataDir) {
39760
39858
 
39761
39859
  // src/feishu-auth/owner-identity-store.ts
39762
39860
  var import_node_fs26 = __toESM(require("fs"), 1);
39763
- var import_node_path30 = __toESM(require("path"), 1);
39861
+ var import_node_path29 = __toESM(require("path"), 1);
39764
39862
  var OWNER_IDENTITY_FILE_NAME = "owner-identity.json";
39765
39863
  var OwnerIdentityStore = class {
39766
39864
  file;
39767
39865
  constructor(dataDir) {
39768
- this.file = import_node_path30.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
39866
+ this.file = import_node_path29.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
39769
39867
  }
39770
39868
  read() {
39771
39869
  let raw;
@@ -39797,7 +39895,7 @@ var OwnerIdentityStore = class {
39797
39895
  };
39798
39896
  }
39799
39897
  write(record) {
39800
- import_node_fs26.default.mkdirSync(import_node_path30.default.dirname(this.file), { recursive: true });
39898
+ import_node_fs26.default.mkdirSync(import_node_path29.default.dirname(this.file), { recursive: true });
39801
39899
  import_node_fs26.default.writeFileSync(this.file, JSON.stringify(record, null, 2), { mode: 384 });
39802
39900
  try {
39803
39901
  import_node_fs26.default.chmodSync(this.file, 384);
@@ -39925,9 +40023,9 @@ var CentralClientError = class extends Error {
39925
40023
  code;
39926
40024
  cause;
39927
40025
  };
39928
- async function centralRequest(opts, path60, init) {
40026
+ async function centralRequest(opts, path59, init) {
39929
40027
  const f = opts.fetchImpl ?? globalThis.fetch;
39930
- const url = `${opts.api.replace(/\/+$/, "")}${path60}`;
40028
+ const url = `${opts.api.replace(/\/+$/, "")}${path59}`;
39931
40029
  const ctrl = new AbortController();
39932
40030
  const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
39933
40031
  let res;
@@ -40070,7 +40168,7 @@ function verifyConnectToken(args) {
40070
40168
 
40071
40169
  // src/feishu-auth/server-key.ts
40072
40170
  var fs35 = __toESM(require("fs"), 1);
40073
- var path39 = __toESM(require("path"), 1);
40171
+ var path38 = __toESM(require("path"), 1);
40074
40172
  var FILE_NAME2 = "server-signing-key.json";
40075
40173
  var ServerKeyStore = class {
40076
40174
  constructor(dataDir) {
@@ -40078,7 +40176,7 @@ var ServerKeyStore = class {
40078
40176
  }
40079
40177
  dataDir;
40080
40178
  filePath() {
40081
- return path39.join(this.dataDir, FILE_NAME2);
40179
+ return path38.join(this.dataDir, FILE_NAME2);
40082
40180
  }
40083
40181
  /** 读缓存的公钥;无缓存 / 损坏 → null(调用方决定是否触发拉取) */
40084
40182
  read() {
@@ -40118,7 +40216,7 @@ init_protocol();
40118
40216
  // src/session/fork.ts
40119
40217
  var import_node_fs27 = __toESM(require("fs"), 1);
40120
40218
  var import_node_os14 = __toESM(require("os"), 1);
40121
- var import_node_path31 = __toESM(require("path"), 1);
40219
+ var import_node_path30 = __toESM(require("path"), 1);
40122
40220
  init_claude_history();
40123
40221
  function readJsonlEntries(file) {
40124
40222
  const raw = import_node_fs27.default.readFileSync(file, "utf8");
@@ -40134,9 +40232,9 @@ function readJsonlEntries(file) {
40134
40232
  return out;
40135
40233
  }
40136
40234
  function forkSession(input) {
40137
- const baseDir = input.baseDir ?? import_node_path31.default.join(import_node_os14.default.homedir(), ".claude");
40138
- const projectDir = import_node_path31.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
40139
- const sourceFile = import_node_path31.default.join(projectDir, `${input.toolSessionId}.jsonl`);
40235
+ const baseDir = input.baseDir ?? import_node_path30.default.join(import_node_os14.default.homedir(), ".claude");
40236
+ const projectDir = import_node_path30.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
40237
+ const sourceFile = import_node_path30.default.join(projectDir, `${input.toolSessionId}.jsonl`);
40140
40238
  if (!import_node_fs27.default.existsSync(sourceFile)) {
40141
40239
  throw new Error(`fork: source transcript not found: ${sourceFile}`);
40142
40240
  }
@@ -40167,7 +40265,7 @@ function forkSession(input) {
40167
40265
  }
40168
40266
  forkedLines.push(JSON.stringify(forked));
40169
40267
  }
40170
- const forkedFilePath = import_node_path31.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
40268
+ const forkedFilePath = import_node_path30.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
40171
40269
  import_node_fs27.default.mkdirSync(projectDir, { recursive: true });
40172
40270
  import_node_fs27.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
40173
40271
  return { forkedToolSessionId, forkedFilePath };
@@ -40536,7 +40634,7 @@ function buildPermissionHandlers(deps) {
40536
40634
  }
40537
40635
 
40538
40636
  // src/handlers/history.ts
40539
- var path42 = __toESM(require("path"), 1);
40637
+ var path41 = __toESM(require("path"), 1);
40540
40638
  init_protocol();
40541
40639
 
40542
40640
  // src/session/recent-dirs.ts
@@ -40554,7 +40652,7 @@ function listRecentDirs(store, limit = 50) {
40554
40652
  }
40555
40653
 
40556
40654
  // src/permission/persona-paths.ts
40557
- var path41 = __toESM(require("path"), 1);
40655
+ var path40 = __toESM(require("path"), 1);
40558
40656
  function getAllowedPersonaIds(grants, action) {
40559
40657
  const ids = /* @__PURE__ */ new Set();
40560
40658
  for (const g2 of grants) {
@@ -40567,31 +40665,31 @@ function getAllowedPersonaIds(grants, action) {
40567
40665
  return ids;
40568
40666
  }
40569
40667
  function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
40570
- const target = path41.resolve(absPath);
40668
+ const target = path40.resolve(absPath);
40571
40669
  if (userWorkDir) {
40572
- const u = path41.resolve(userWorkDir);
40573
- const usep = u.endsWith(path41.sep) ? "" : path41.sep;
40670
+ const u = path40.resolve(userWorkDir);
40671
+ const usep = u.endsWith(path40.sep) ? "" : path40.sep;
40574
40672
  if (target === u || target.startsWith(u + usep)) return true;
40575
40673
  }
40576
- const root = path41.resolve(personaRoot);
40577
- const sep2 = root.endsWith(path41.sep) ? "" : path41.sep;
40674
+ const root = path40.resolve(personaRoot);
40675
+ const sep2 = root.endsWith(path40.sep) ? "" : path40.sep;
40578
40676
  if (!target.startsWith(root + sep2)) return false;
40579
- const rel = path41.relative(root, target);
40677
+ const rel = path40.relative(root, target);
40580
40678
  if (!rel || rel.startsWith("..")) return false;
40581
- const personaId = rel.split(path41.sep)[0];
40679
+ const personaId = rel.split(path40.sep)[0];
40582
40680
  if (!personaId) return false;
40583
40681
  const allowed = getAllowedPersonaIds(grants, action);
40584
40682
  if (allowed === "*") return true;
40585
40683
  return allowed.has(personaId);
40586
40684
  }
40587
40685
  function personaIdFromPath(absPath, personaRoot) {
40588
- const root = path41.resolve(personaRoot);
40589
- const target = path41.resolve(absPath);
40590
- const sep2 = root.endsWith(path41.sep) ? "" : path41.sep;
40686
+ const root = path40.resolve(personaRoot);
40687
+ const target = path40.resolve(absPath);
40688
+ const sep2 = root.endsWith(path40.sep) ? "" : path40.sep;
40591
40689
  if (!target.startsWith(root + sep2)) return null;
40592
- const rel = path41.relative(root, target);
40690
+ const rel = path40.relative(root, target);
40593
40691
  if (!rel || rel.startsWith("..")) return null;
40594
- const id = rel.split(path41.sep)[0];
40692
+ const id = rel.split(path40.sep)[0];
40595
40693
  return id || null;
40596
40694
  }
40597
40695
 
@@ -40618,7 +40716,7 @@ function buildHistoryHandlers(deps) {
40618
40716
  if (!pid) return false;
40619
40717
  return isGuestPathAllowed(
40620
40718
  ctx.grants,
40621
- path42.join(personaRoot, pid),
40719
+ path41.join(personaRoot, pid),
40622
40720
  personaRoot,
40623
40721
  "read",
40624
40722
  userWorkDir
@@ -40630,7 +40728,7 @@ function buildHistoryHandlers(deps) {
40630
40728
  };
40631
40729
  const list = async (frame, _client, ctx) => {
40632
40730
  const args = HistoryListArgs.parse(frame);
40633
- assertGuestPath(ctx, path42.resolve(args.projectPath), personaRoot, "history:list");
40731
+ assertGuestPath(ctx, path41.resolve(args.projectPath), personaRoot, "history:list");
40634
40732
  const sessions = await history.listSessions(args);
40635
40733
  return { response: { type: "history:list", sessions } };
40636
40734
  };
@@ -40662,13 +40760,13 @@ function buildHistoryHandlers(deps) {
40662
40760
  };
40663
40761
  const subagents = async (frame, _client, ctx) => {
40664
40762
  const args = HistorySubagentsArgs.parse(frame);
40665
- assertGuestPath(ctx, path42.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
40763
+ assertGuestPath(ctx, path41.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
40666
40764
  const subs = await history.listSubagents(args);
40667
40765
  return { response: { type: "history:subagents", subagents: subs } };
40668
40766
  };
40669
40767
  const subagentRead = async (frame, _client, ctx) => {
40670
40768
  const args = HistorySubagentReadArgs.parse(frame);
40671
- assertGuestPath(ctx, path42.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
40769
+ assertGuestPath(ctx, path41.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
40672
40770
  const res = await history.readSubagent(args);
40673
40771
  return { response: { type: "history:subagent-read", ...res } };
40674
40772
  };
@@ -40677,7 +40775,7 @@ function buildHistoryHandlers(deps) {
40677
40775
  if (ctx?.principal.kind === "guest" && personaRoot) {
40678
40776
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
40679
40777
  const filtered = dirs.filter(
40680
- (d) => isGuestPathAllowed(ctx.grants, path42.resolve(d.cwd), personaRoot, "read", userWorkDir)
40778
+ (d) => isGuestPathAllowed(ctx.grants, path41.resolve(d.cwd), personaRoot, "read", userWorkDir)
40681
40779
  );
40682
40780
  return { response: { type: "history:recentDirs", dirs: filtered } };
40683
40781
  }
@@ -40694,7 +40792,7 @@ function buildHistoryHandlers(deps) {
40694
40792
  }
40695
40793
 
40696
40794
  // src/handlers/workspace.ts
40697
- var path43 = __toESM(require("path"), 1);
40795
+ var path42 = __toESM(require("path"), 1);
40698
40796
  var os15 = __toESM(require("os"), 1);
40699
40797
  init_protocol();
40700
40798
  init_protocol();
@@ -40736,22 +40834,22 @@ function buildWorkspaceHandlers(deps) {
40736
40834
  const args = WorkspaceListArgs.parse(frame);
40737
40835
  const isGuest = ctx?.principal.kind === "guest";
40738
40836
  const fallbackCwd = isGuest && personaRoot ? personaRoot : os15.homedir();
40739
- const resolvedCwd = path43.resolve(args.cwd ?? fallbackCwd);
40740
- const target = args.path ? path43.resolve(resolvedCwd, args.path) : resolvedCwd;
40837
+ const resolvedCwd = path42.resolve(args.cwd ?? fallbackCwd);
40838
+ const target = args.path ? path42.resolve(resolvedCwd, args.path) : resolvedCwd;
40741
40839
  assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
40742
40840
  const res = workspace.list({ ...args, cwd: resolvedCwd });
40743
40841
  return { response: { type: "workspace:list", ...res } };
40744
40842
  };
40745
40843
  const read = async (frame, _client, ctx) => {
40746
40844
  const args = WorkspaceReadArgs.parse(frame);
40747
- const target = path43.isAbsolute(args.path) ? path43.resolve(args.path) : path43.resolve(args.cwd, args.path);
40845
+ const target = path42.isAbsolute(args.path) ? path42.resolve(args.path) : path42.resolve(args.cwd, args.path);
40748
40846
  assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
40749
40847
  const res = workspace.read(args);
40750
40848
  return { response: { type: "workspace:read", ...res } };
40751
40849
  };
40752
40850
  const skillsList = async (frame, _client, ctx) => {
40753
40851
  const args = SkillsListArgs.parse(frame);
40754
- const cwdAbs = path43.resolve(args.cwd);
40852
+ const cwdAbs = path42.resolve(args.cwd);
40755
40853
  assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
40756
40854
  const list2 = skills.list(args);
40757
40855
  if (ctx?.principal.kind === "guest" && personaRoot) {
@@ -40763,7 +40861,7 @@ function buildWorkspaceHandlers(deps) {
40763
40861
  };
40764
40862
  const agentsList = async (frame, _client, ctx) => {
40765
40863
  const args = AgentsListArgs.parse(frame);
40766
- const cwdAbs = path43.resolve(args.cwd);
40864
+ const cwdAbs = path42.resolve(args.cwd);
40767
40865
  assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
40768
40866
  const list2 = agents.list(args);
40769
40867
  if (ctx?.principal.kind === "guest" && personaRoot) {
@@ -40782,18 +40880,18 @@ function buildWorkspaceHandlers(deps) {
40782
40880
  }
40783
40881
 
40784
40882
  // src/handlers/git.ts
40785
- var path45 = __toESM(require("path"), 1);
40883
+ var path44 = __toESM(require("path"), 1);
40786
40884
  init_protocol();
40787
40885
  init_protocol();
40788
40886
 
40789
40887
  // src/workspace/git.ts
40790
40888
  var import_node_child_process6 = require("child_process");
40791
40889
  var import_node_fs28 = __toESM(require("fs"), 1);
40792
- var import_node_path32 = __toESM(require("path"), 1);
40890
+ var import_node_path31 = __toESM(require("path"), 1);
40793
40891
  var import_node_util = require("util");
40794
40892
  var pexec = (0, import_node_util.promisify)(import_node_child_process6.execFile);
40795
40893
  function normalizePath(p2) {
40796
- const resolved = import_node_path32.default.resolve(p2);
40894
+ const resolved = import_node_path31.default.resolve(p2);
40797
40895
  try {
40798
40896
  return import_node_fs28.default.realpathSync(resolved);
40799
40897
  } catch {
@@ -40869,7 +40967,7 @@ async function listGitBranches(cwd) {
40869
40967
  function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
40870
40968
  if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
40871
40969
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
40872
- if (!isGuestPathAllowed(ctx.grants, path45.resolve(cwd), personaRoot, "read", userWorkDir)) {
40970
+ if (!isGuestPathAllowed(ctx.grants, path44.resolve(cwd), personaRoot, "read", userWorkDir)) {
40873
40971
  throw new ClawdError(
40874
40972
  ERROR_CODES.UNAUTHORIZED,
40875
40973
  `guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
@@ -41382,7 +41480,7 @@ function buildPersonaHandlers(deps) {
41382
41480
  }
41383
41481
 
41384
41482
  // src/handlers/attachment.ts
41385
- var import_node_path33 = __toESM(require("path"), 1);
41483
+ var import_node_path32 = __toESM(require("path"), 1);
41386
41484
  init_protocol();
41387
41485
  init_protocol();
41388
41486
  var DEFAULT_TTL_SECONDS = 24 * 3600;
@@ -41437,12 +41535,12 @@ function buildAttachmentHandlers(deps) {
41437
41535
  `session ${args.sessionId} scope unresolved`
41438
41536
  );
41439
41537
  }
41440
- const cwdAbs = import_node_path33.default.resolve(sessionFile.cwd);
41441
- const candidateAbs = import_node_path33.default.isAbsolute(args.relPath) ? import_node_path33.default.resolve(args.relPath) : import_node_path33.default.resolve(cwdAbs, args.relPath);
41538
+ const cwdAbs = import_node_path32.default.resolve(sessionFile.cwd);
41539
+ const candidateAbs = import_node_path32.default.isAbsolute(args.relPath) ? import_node_path32.default.resolve(args.relPath) : import_node_path32.default.resolve(cwdAbs, args.relPath);
41442
41540
  assertGuestAttachmentPath(ctx, candidateAbs, deps.personaRoot, "attachment.signUrl", deps.usersRoot);
41443
41541
  const entries = deps.groupFileStore.list(scope, args.sessionId);
41444
41542
  const entry = entries.find((e) => {
41445
- const storedAbs = import_node_path33.default.isAbsolute(e.relPath) ? import_node_path33.default.resolve(e.relPath) : import_node_path33.default.resolve(cwdAbs, e.relPath);
41543
+ const storedAbs = import_node_path32.default.isAbsolute(e.relPath) ? import_node_path32.default.resolve(e.relPath) : import_node_path32.default.resolve(cwdAbs, e.relPath);
41446
41544
  return storedAbs === candidateAbs && !e.stale;
41447
41545
  });
41448
41546
  if (!entry) {
@@ -41466,7 +41564,7 @@ function buildAttachmentHandlers(deps) {
41466
41564
  if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
41467
41565
  const f = deps.sessionStore.read(sessionId);
41468
41566
  if (!f) return;
41469
- assertGuestAttachmentPath(ctx, import_node_path33.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
41567
+ assertGuestAttachmentPath(ctx, import_node_path32.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
41470
41568
  }
41471
41569
  const groupAdd = async (frame, _client, ctx) => {
41472
41570
  if (!deps.groupFileStore || !deps.getSessionScope) {
@@ -41538,19 +41636,19 @@ function buildAttachmentHandlers(deps) {
41538
41636
 
41539
41637
  // src/handlers/extension.ts
41540
41638
  var import_promises7 = __toESM(require("fs/promises"), 1);
41541
- var import_node_path38 = __toESM(require("path"), 1);
41639
+ var import_node_path37 = __toESM(require("path"), 1);
41542
41640
  init_protocol();
41543
41641
 
41544
41642
  // src/extension/bundle-zip.ts
41545
41643
  var import_promises4 = __toESM(require("fs/promises"), 1);
41546
- var import_node_path34 = __toESM(require("path"), 1);
41644
+ var import_node_path33 = __toESM(require("path"), 1);
41547
41645
  var import_node_crypto11 = __toESM(require("crypto"), 1);
41548
41646
  var import_jszip2 = __toESM(require_lib3(), 1);
41549
41647
  async function bundleExtensionDir(dir) {
41550
41648
  const entries = await listFilesSorted(dir);
41551
41649
  const zip = new import_jszip2.default();
41552
41650
  for (const rel of entries) {
41553
- const abs = import_node_path34.default.join(dir, rel);
41651
+ const abs = import_node_path33.default.join(dir, rel);
41554
41652
  const content = await import_promises4.default.readFile(abs);
41555
41653
  zip.file(rel, content, { date: FIXED_DATE });
41556
41654
  }
@@ -41571,7 +41669,7 @@ async function listFilesSorted(rootDir) {
41571
41669
  return out;
41572
41670
  }
41573
41671
  async function walk(absRoot, relPrefix, out) {
41574
- const dirAbs = import_node_path34.default.join(absRoot, relPrefix);
41672
+ const dirAbs = import_node_path33.default.join(absRoot, relPrefix);
41575
41673
  const entries = await import_promises4.default.readdir(dirAbs, { withFileTypes: true });
41576
41674
  for (const e of entries) {
41577
41675
  if (IGNORE_BASENAMES.has(e.name)) continue;
@@ -41625,25 +41723,25 @@ function computePublishCheck(args) {
41625
41723
 
41626
41724
  // src/extension/install-flow.ts
41627
41725
  var import_promises5 = __toESM(require("fs/promises"), 1);
41628
- var import_node_path36 = __toESM(require("path"), 1);
41726
+ var import_node_path35 = __toESM(require("path"), 1);
41629
41727
  var import_node_os17 = __toESM(require("os"), 1);
41630
41728
  var import_node_crypto12 = __toESM(require("crypto"), 1);
41631
41729
  var import_jszip3 = __toESM(require_lib3(), 1);
41632
41730
 
41633
41731
  // src/extension/paths.ts
41634
41732
  var import_node_os16 = __toESM(require("os"), 1);
41635
- var import_node_path35 = __toESM(require("path"), 1);
41733
+ var import_node_path34 = __toESM(require("path"), 1);
41636
41734
  function clawdHomeRoot(override) {
41637
- return override ?? process.env.CLAWD_HOME ?? import_node_path35.default.join(import_node_os16.default.homedir(), ".clawd");
41735
+ return override ?? process.env.CLAWD_HOME ?? import_node_path34.default.join(import_node_os16.default.homedir(), ".clawd");
41638
41736
  }
41639
41737
  function extensionsRoot(override) {
41640
- return import_node_path35.default.join(clawdHomeRoot(override), "extensions");
41738
+ return import_node_path34.default.join(clawdHomeRoot(override), "extensions");
41641
41739
  }
41642
41740
  function publishedChannelsFile(override) {
41643
- return import_node_path35.default.join(clawdHomeRoot(override), "extensions-published.json");
41741
+ return import_node_path34.default.join(clawdHomeRoot(override), "extensions-published.json");
41644
41742
  }
41645
41743
  function bundleCacheRoot(override) {
41646
- return import_node_path35.default.join(clawdHomeRoot(override), "extension-bundles");
41744
+ return import_node_path34.default.join(clawdHomeRoot(override), "extension-bundles");
41647
41745
  }
41648
41746
 
41649
41747
  // src/extension/install-flow.ts
@@ -41670,7 +41768,7 @@ async function installFromChannel(args, deps) {
41670
41768
  throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
41671
41769
  }
41672
41770
  for (const name of Object.keys(zip.files)) {
41673
- if (name.includes("..") || name.startsWith("/") || import_node_path36.default.isAbsolute(name)) {
41771
+ if (name.includes("..") || name.startsWith("/") || import_node_path35.default.isAbsolute(name)) {
41674
41772
  throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
41675
41773
  }
41676
41774
  }
@@ -41702,7 +41800,7 @@ async function installFromChannel(args, deps) {
41702
41800
  );
41703
41801
  }
41704
41802
  const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
41705
- const destDir = import_node_path36.default.join(deps.extensionsRoot, localExtId);
41803
+ const destDir = import_node_path35.default.join(deps.extensionsRoot, localExtId);
41706
41804
  let destExists = false;
41707
41805
  try {
41708
41806
  await import_promises5.default.access(destDir);
@@ -41716,16 +41814,16 @@ async function installFromChannel(args, deps) {
41716
41814
  );
41717
41815
  }
41718
41816
  const stage = await import_promises5.default.mkdtemp(
41719
- import_node_path36.default.join(import_node_os17.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
41817
+ import_node_path35.default.join(import_node_os17.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
41720
41818
  );
41721
41819
  try {
41722
41820
  for (const [name, entry] of Object.entries(zip.files)) {
41723
- const dest = import_node_path36.default.join(stage, name);
41821
+ const dest = import_node_path35.default.join(stage, name);
41724
41822
  if (entry.dir) {
41725
41823
  await import_promises5.default.mkdir(dest, { recursive: true });
41726
41824
  continue;
41727
41825
  }
41728
- await import_promises5.default.mkdir(import_node_path36.default.dirname(dest), { recursive: true });
41826
+ await import_promises5.default.mkdir(import_node_path35.default.dirname(dest), { recursive: true });
41729
41827
  if (name === "manifest.json") {
41730
41828
  const rewritten = { ...parsed.data, id: localExtId };
41731
41829
  await import_promises5.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
@@ -41746,7 +41844,7 @@ async function installFromChannel(args, deps) {
41746
41844
 
41747
41845
  // src/extension/update-flow.ts
41748
41846
  var import_promises6 = __toESM(require("fs/promises"), 1);
41749
- var import_node_path37 = __toESM(require("path"), 1);
41847
+ var import_node_path36 = __toESM(require("path"), 1);
41750
41848
  var import_node_os18 = __toESM(require("os"), 1);
41751
41849
  var import_node_crypto13 = __toESM(require("crypto"), 1);
41752
41850
  var import_jszip4 = __toESM(require_lib3(), 1);
@@ -41763,11 +41861,11 @@ async function updateFromChannel(args, deps) {
41763
41861
  channelRef.extId,
41764
41862
  channelRef.ownerPrincipalId
41765
41863
  );
41766
- const liveDir = import_node_path37.default.join(deps.extensionsRoot, localExtId);
41864
+ const liveDir = import_node_path36.default.join(deps.extensionsRoot, localExtId);
41767
41865
  const prevDir = `${liveDir}.prev`;
41768
41866
  let existingVersion;
41769
41867
  try {
41770
- const raw = await import_promises6.default.readFile(import_node_path37.default.join(liveDir, "manifest.json"), "utf8");
41868
+ const raw = await import_promises6.default.readFile(import_node_path36.default.join(liveDir, "manifest.json"), "utf8");
41771
41869
  const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
41772
41870
  if (!parsed2.success) {
41773
41871
  throw new UpdateError(
@@ -41800,7 +41898,7 @@ async function updateFromChannel(args, deps) {
41800
41898
  throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
41801
41899
  }
41802
41900
  for (const name of Object.keys(zip.files)) {
41803
- if (name.includes("..") || name.startsWith("/") || import_node_path37.default.isAbsolute(name)) {
41901
+ if (name.includes("..") || name.startsWith("/") || import_node_path36.default.isAbsolute(name)) {
41804
41902
  throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
41805
41903
  }
41806
41904
  }
@@ -41835,16 +41933,16 @@ async function updateFromChannel(args, deps) {
41835
41933
  await import_promises6.default.rm(prevDir, { recursive: true, force: true });
41836
41934
  await import_promises6.default.rename(liveDir, prevDir);
41837
41935
  const stage = await import_promises6.default.mkdtemp(
41838
- import_node_path37.default.join(import_node_os18.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
41936
+ import_node_path36.default.join(import_node_os18.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
41839
41937
  );
41840
41938
  try {
41841
41939
  for (const [name, entry] of Object.entries(zip.files)) {
41842
- const dest = import_node_path37.default.join(stage, name);
41940
+ const dest = import_node_path36.default.join(stage, name);
41843
41941
  if (entry.dir) {
41844
41942
  await import_promises6.default.mkdir(dest, { recursive: true });
41845
41943
  continue;
41846
41944
  }
41847
- await import_promises6.default.mkdir(import_node_path37.default.dirname(dest), { recursive: true });
41945
+ await import_promises6.default.mkdir(import_node_path36.default.dirname(dest), { recursive: true });
41848
41946
  if (name === "manifest.json") {
41849
41947
  const rewritten = { ...parsed.data, id: localExtId };
41850
41948
  await import_promises6.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
@@ -41937,7 +42035,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
41937
42035
  );
41938
42036
  }
41939
42037
  }
41940
- const manifestPath = import_node_path38.default.join(root, extId, "manifest.json");
42038
+ const manifestPath = import_node_path37.default.join(root, extId, "manifest.json");
41941
42039
  const manifest = await readManifest(root, extId);
41942
42040
  const next = { ...manifest, version: newVersion };
41943
42041
  const tmp = `${manifestPath}.tmp`;
@@ -41945,7 +42043,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
41945
42043
  await import_promises7.default.rename(tmp, manifestPath);
41946
42044
  }
41947
42045
  async function readManifest(root, extId) {
41948
- const file = import_node_path38.default.join(root, extId, "manifest.json");
42046
+ const file = import_node_path37.default.join(root, extId, "manifest.json");
41949
42047
  let raw;
41950
42048
  try {
41951
42049
  raw = await import_promises7.default.readFile(file, "utf8");
@@ -42036,7 +42134,7 @@ function buildExtensionHandlers(deps) {
42036
42134
  };
42037
42135
  async function buildSnapshotMeta(extId) {
42038
42136
  const manifest = await readManifest(deps.root, extId);
42039
- const { sha256, buffer } = await bundleExtensionDir(import_node_path38.default.join(deps.root, extId));
42137
+ const { sha256, buffer } = await bundleExtensionDir(import_node_path37.default.join(deps.root, extId));
42040
42138
  return { manifest, contentHash: sha256, buffer };
42041
42139
  }
42042
42140
  const publish = async (frame, _client, ctx) => {
@@ -42333,7 +42431,7 @@ var PublishJobRegistry = class {
42333
42431
  // src/app-builder/publish-job-runner.ts
42334
42432
  var import_node_child_process8 = require("child_process");
42335
42433
  var import_node_fs29 = require("fs");
42336
- var import_node_path39 = require("path");
42434
+ var import_node_path38 = require("path");
42337
42435
 
42338
42436
  // src/app-builder/publish-stage-parser.ts
42339
42437
  var STAGE_RE = /^\s*::stage::(build|deploy|verify)\s*$/;
@@ -42365,7 +42463,7 @@ async function startPublishJob(deps, args) {
42365
42463
  return { jobId: registry2.get(args.name).jobId, status: "already-publishing" };
42366
42464
  }
42367
42465
  const projDir = projectDir(args.name);
42368
- const logPath = (0, import_node_path39.join)(projDir, ".publish.log");
42466
+ const logPath = (0, import_node_path38.join)(projDir, ".publish.log");
42369
42467
  let logStream = null;
42370
42468
  try {
42371
42469
  logStream = (0, import_node_fs29.createWriteStream)(logPath, { flags: "w" });
@@ -42625,7 +42723,7 @@ async function recoverInterruptedJobs(deps) {
42625
42723
 
42626
42724
  // src/handlers/app-builder.ts
42627
42725
  init_protocol();
42628
- var import_node_path40 = require("path");
42726
+ var import_node_path39 = require("path");
42629
42727
  var import_node_fs30 = require("fs");
42630
42728
  var APP_BUILDER_PERSONAS = ["persona-app-builder"];
42631
42729
  var PUBLISH_SCRIPT_REL = "extension-kit/scripts/publish.sh";
@@ -43000,7 +43098,7 @@ function buildAppBuilderHandlers(deps) {
43000
43098
  });
43001
43099
  await userStore.clearPublishJob(args.name);
43002
43100
  }
43003
- const scriptPath = (0, import_node_path40.join)(deps.personaRoot, PUBLISH_SCRIPT_REL);
43101
+ const scriptPath = (0, import_node_path39.join)(deps.personaRoot, PUBLISH_SCRIPT_REL);
43004
43102
  deps.logger?.info("app-builder.publish.start", {
43005
43103
  name: args.name,
43006
43104
  sessionId: boundSession.sessionId,
@@ -43094,7 +43192,7 @@ function buildAppBuilderHandlers(deps) {
43094
43192
 
43095
43193
  // src/extension/registry.ts
43096
43194
  var import_promises8 = __toESM(require("fs/promises"), 1);
43097
- var import_node_path41 = __toESM(require("path"), 1);
43195
+ var import_node_path40 = __toESM(require("path"), 1);
43098
43196
  async function loadAll(root) {
43099
43197
  let entries;
43100
43198
  try {
@@ -43107,13 +43205,13 @@ async function loadAll(root) {
43107
43205
  for (const ent of entries) {
43108
43206
  if (!ent.isDirectory()) continue;
43109
43207
  if (ent.name.startsWith(".")) continue;
43110
- records.push(await loadOne(import_node_path41.default.join(root, ent.name), ent.name));
43208
+ records.push(await loadOne(import_node_path40.default.join(root, ent.name), ent.name));
43111
43209
  }
43112
43210
  records.sort((a, b2) => a.extId < b2.extId ? -1 : a.extId > b2.extId ? 1 : 0);
43113
43211
  return records;
43114
43212
  }
43115
43213
  async function loadOne(dir, dirName) {
43116
- const manifestPath = import_node_path41.default.join(dir, "manifest.json");
43214
+ const manifestPath = import_node_path40.default.join(dir, "manifest.json");
43117
43215
  let raw;
43118
43216
  try {
43119
43217
  raw = await import_promises8.default.readFile(manifestPath, "utf8");
@@ -43158,7 +43256,7 @@ async function loadOne(dir, dirName) {
43158
43256
 
43159
43257
  // src/extension/uninstall.ts
43160
43258
  var import_promises9 = __toESM(require("fs/promises"), 1);
43161
- var import_node_path42 = __toESM(require("path"), 1);
43259
+ var import_node_path41 = __toESM(require("path"), 1);
43162
43260
  var UninstallError = class extends Error {
43163
43261
  constructor(code, message) {
43164
43262
  super(message);
@@ -43167,7 +43265,7 @@ var UninstallError = class extends Error {
43167
43265
  code;
43168
43266
  };
43169
43267
  async function uninstall(deps) {
43170
- const dir = import_node_path42.default.join(deps.root, deps.extId);
43268
+ const dir = import_node_path41.default.join(deps.root, deps.extId);
43171
43269
  try {
43172
43270
  await import_promises9.default.access(dir);
43173
43271
  } catch {
@@ -43248,7 +43346,7 @@ function buildMethodHandlers(deps) {
43248
43346
  // src/app-builder/project-store.ts
43249
43347
  var import_node_fs31 = require("fs");
43250
43348
  var import_node_child_process9 = require("child_process");
43251
- var import_node_path43 = require("path");
43349
+ var import_node_path42 = require("path");
43252
43350
  init_protocol();
43253
43351
  var PROJECTS_DIR = "projects";
43254
43352
  var META_FILE = ".clawd-project.json";
@@ -43263,14 +43361,14 @@ var ProjectStore = class {
43263
43361
  root;
43264
43362
  /** projects/<name>/.clawd-project.json 路径 */
43265
43363
  metaPath(name) {
43266
- return (0, import_node_path43.join)(this.projectsRoot(), name, META_FILE);
43364
+ return (0, import_node_path42.join)(this.projectsRoot(), name, META_FILE);
43267
43365
  }
43268
43366
  /** projects/<name>/ 目录路径(cwd 用) */
43269
43367
  projectDir(name) {
43270
- return (0, import_node_path43.join)(this.projectsRoot(), name);
43368
+ return (0, import_node_path42.join)(this.projectsRoot(), name);
43271
43369
  }
43272
43370
  projectsRoot() {
43273
- return (0, import_node_path43.join)(this.root, PROJECTS_DIR);
43371
+ return (0, import_node_path42.join)(this.root, PROJECTS_DIR);
43274
43372
  }
43275
43373
  async list() {
43276
43374
  let entries;
@@ -43351,7 +43449,7 @@ var ProjectStore = class {
43351
43449
  * 代码再参考"。assistant 进 project 时目录已是完整模板,直接 pnpm install 即可。
43352
43450
  */
43353
43451
  async scaffold(name, template = DEFAULT_TEMPLATE, personaRoot = this.root) {
43354
- const scriptPath = (0, import_node_path43.join)(personaRoot, SCAFFOLD_SCRIPT_REL);
43452
+ const scriptPath = (0, import_node_path42.join)(personaRoot, SCAFFOLD_SCRIPT_REL);
43355
43453
  const destDir = this.projectDir(name);
43356
43454
  return await new Promise((resolve6, reject) => {
43357
43455
  const child = (0, import_node_child_process9.spawn)("bash", [scriptPath, name, template, destDir], {
@@ -43889,7 +43987,7 @@ function computeGrantForFrame(method, frame) {
43889
43987
 
43890
43988
  // src/extension/runtime.ts
43891
43989
  var import_node_child_process11 = require("child_process");
43892
- var import_node_path44 = __toESM(require("path"), 1);
43990
+ var import_node_path43 = __toESM(require("path"), 1);
43893
43991
  var import_promises10 = require("timers/promises");
43894
43992
 
43895
43993
  // src/extension/port-allocator.ts
@@ -43990,7 +44088,7 @@ var Runtime = class {
43990
44088
  /\$CLAWOS_EXT_PORT/g,
43991
44089
  String(port)
43992
44090
  );
43993
- const dir = import_node_path44.default.join(this.root, extId);
44091
+ const dir = import_node_path43.default.join(this.root, extId);
43994
44092
  const env = {
43995
44093
  ...process.env,
43996
44094
  CLAWOS_EXT_PORT: String(port),
@@ -44102,7 +44200,7 @@ ${handle.stderrTail}`
44102
44200
 
44103
44201
  // src/extension/published-channels.ts
44104
44202
  var import_promises11 = __toESM(require("fs/promises"), 1);
44105
- var import_node_path45 = __toESM(require("path"), 1);
44203
+ var import_node_path44 = __toESM(require("path"), 1);
44106
44204
  init_zod();
44107
44205
  var PublishedChannelsError = class extends Error {
44108
44206
  constructor(code, message) {
@@ -44201,7 +44299,7 @@ var PublishedChannelStore = class {
44201
44299
  )
44202
44300
  };
44203
44301
  const tmp = `${this.filePath}.tmp`;
44204
- await import_promises11.default.mkdir(import_node_path45.default.dirname(this.filePath), { recursive: true });
44302
+ await import_promises11.default.mkdir(import_node_path44.default.dirname(this.filePath), { recursive: true });
44205
44303
  await import_promises11.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
44206
44304
  await import_promises11.default.rename(tmp, this.filePath);
44207
44305
  }
@@ -44209,7 +44307,7 @@ var PublishedChannelStore = class {
44209
44307
 
44210
44308
  // src/extension/bundle-cache.ts
44211
44309
  var import_promises12 = __toESM(require("fs/promises"), 1);
44212
- var import_node_path46 = __toESM(require("path"), 1);
44310
+ var import_node_path45 = __toESM(require("path"), 1);
44213
44311
  var BundleCache = class {
44214
44312
  constructor(rootDir) {
44215
44313
  this.rootDir = rootDir;
@@ -44218,14 +44316,14 @@ var BundleCache = class {
44218
44316
  /** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
44219
44317
  async write(snapshotHash, buffer) {
44220
44318
  await import_promises12.default.mkdir(this.rootDir, { recursive: true });
44221
- const file = import_node_path46.default.join(this.rootDir, `${snapshotHash}.zip`);
44319
+ const file = import_node_path45.default.join(this.rootDir, `${snapshotHash}.zip`);
44222
44320
  const tmp = `${file}.tmp`;
44223
44321
  await import_promises12.default.writeFile(tmp, buffer, { mode: 384 });
44224
44322
  await import_promises12.default.rename(tmp, file);
44225
44323
  }
44226
44324
  /** Returns the bundle bytes, or null when the file doesn't exist. */
44227
44325
  async read(snapshotHash) {
44228
- const file = import_node_path46.default.join(this.rootDir, `${snapshotHash}.zip`);
44326
+ const file = import_node_path45.default.join(this.rootDir, `${snapshotHash}.zip`);
44229
44327
  try {
44230
44328
  return await import_promises12.default.readFile(file);
44231
44329
  } catch (e) {
@@ -44235,7 +44333,7 @@ var BundleCache = class {
44235
44333
  }
44236
44334
  /** Idempotent — missing file is not an error. */
44237
44335
  async delete(snapshotHash) {
44238
- const file = import_node_path46.default.join(this.rootDir, `${snapshotHash}.zip`);
44336
+ const file = import_node_path45.default.join(this.rootDir, `${snapshotHash}.zip`);
44239
44337
  await import_promises12.default.rm(file, { force: true });
44240
44338
  }
44241
44339
  };
@@ -44244,7 +44342,7 @@ var BundleCache = class {
44244
44342
  async function startDaemon(config) {
44245
44343
  const logger = createLogger({
44246
44344
  level: config.logLevel,
44247
- file: import_node_path47.default.join(config.dataDir, "clawd.log")
44345
+ file: import_node_path46.default.join(config.dataDir, "clawd.log")
44248
44346
  });
44249
44347
  logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
44250
44348
  const stateMgr = new StateFileManager({ dataDir: config.dataDir });
@@ -44380,8 +44478,8 @@ async function startDaemon(config) {
44380
44478
  const agents = new AgentsScanner();
44381
44479
  const history = new ClaudeHistoryReader();
44382
44480
  let transport = null;
44383
- const personaStore = new PersonaStore(import_node_path47.default.join(config.dataDir, "personas"));
44384
- const usersRoot = import_node_path47.default.join(config.dataDir, "users");
44481
+ const personaStore = new PersonaStore(import_node_path46.default.join(config.dataDir, "personas"));
44482
+ const usersRoot = import_node_path46.default.join(config.dataDir, "users");
44385
44483
  const defaultsRoot = findDefaultsRoot();
44386
44484
  if (defaultsRoot) {
44387
44485
  seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
@@ -44399,7 +44497,7 @@ async function startDaemon(config) {
44399
44497
  getAdapter,
44400
44498
  historyReader: history,
44401
44499
  dataDir: config.dataDir,
44402
- personaRoot: import_node_path47.default.join(config.dataDir, "personas"),
44500
+ personaRoot: import_node_path46.default.join(config.dataDir, "personas"),
44403
44501
  usersRoot,
44404
44502
  personaStore,
44405
44503
  ownerDisplayName,
@@ -44429,7 +44527,7 @@ async function startDaemon(config) {
44429
44527
  // 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
44430
44528
  attachmentGroup: {
44431
44529
  onFileEdit: (input) => {
44432
- const absPath = import_node_path47.default.isAbsolute(input.relPath) ? input.relPath : import_node_path47.default.join(input.cwd, input.relPath);
44530
+ const absPath = import_node_path46.default.isAbsolute(input.relPath) ? input.relPath : import_node_path46.default.join(input.cwd, input.relPath);
44433
44531
  let size = 0;
44434
44532
  try {
44435
44533
  size = import_node_fs32.default.statSync(absPath).size;
@@ -44614,11 +44712,11 @@ async function startDaemon(config) {
44614
44712
  // 'persona/<pid>/owner',default 走 'default'。
44615
44713
  getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
44616
44714
  // guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
44617
- personaRoot: import_node_path47.default.join(config.dataDir, "personas"),
44715
+ personaRoot: import_node_path46.default.join(config.dataDir, "personas"),
44618
44716
  usersRoot
44619
44717
  },
44620
44718
  // workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
44621
- personaRoot: import_node_path47.default.join(config.dataDir, "personas"),
44719
+ personaRoot: import_node_path46.default.join(config.dataDir, "personas"),
44622
44720
  // v2 多人 persona 隔离:handler 派生 guest user-dir 放行
44623
44721
  usersRoot,
44624
44722
  // capability:list / delete handler 依赖
@@ -44707,7 +44805,7 @@ async function startDaemon(config) {
44707
44805
  // 发布上线脚手架化 (spec 2026-06-03 §5.2):
44708
44806
  // appBuilderPersonaRoot 用于拼 publish.sh 绝对路径(persona-app-builder 安装在
44709
44807
  // dataDir/personas/persona-app-builder 之下,extension-kit/scripts/publish.sh 是相对路径)。
44710
- appBuilderPersonaRoot: import_node_path47.default.join(config.dataDir, "personas", "persona-app-builder"),
44808
+ appBuilderPersonaRoot: import_node_path46.default.join(config.dataDir, "personas", "persona-app-builder"),
44711
44809
  // 发布上线脚手架化 (spec 2026-06-03 §5.2.2):
44712
44810
  // 复用 SessionManagerDeps.broadcastFrame 同款 dispatch 逻辑 —— runner 调 manager.send
44713
44811
  // 取回 broadcast 帧后逐帧 push 到 transport,跟 manager 自身的 deps 一致。
@@ -44955,8 +45053,8 @@ async function startDaemon(config) {
44955
45053
  const lines = [
44956
45054
  `Tunnel: ${r.url}`,
44957
45055
  ...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
44958
- `Frpc config: ${import_node_path47.default.join(config.dataDir, "frpc.toml")}`,
44959
- `Frpc log: ${import_node_path47.default.join(config.dataDir, "frpc.log")}`
45056
+ `Frpc config: ${import_node_path46.default.join(config.dataDir, "frpc.toml")}`,
45057
+ `Frpc log: ${import_node_path46.default.join(config.dataDir, "frpc.log")}`
44960
45058
  ];
44961
45059
  const width = Math.max(...lines.map((l) => l.length));
44962
45060
  const bar = "\u2550".repeat(width + 4);
@@ -44969,7 +45067,7 @@ ${bar}
44969
45067
 
44970
45068
  `);
44971
45069
  try {
44972
- const connectPath = import_node_path47.default.join(config.dataDir, "connect.txt");
45070
+ const connectPath = import_node_path46.default.join(config.dataDir, "connect.txt");
44973
45071
  import_node_fs32.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
44974
45072
  } catch {
44975
45073
  }
@@ -45041,7 +45139,7 @@ ${bar}
45041
45139
  };
45042
45140
  }
45043
45141
  function migrateDropPersonsDir(dataDir) {
45044
- const dir = import_node_path47.default.join(dataDir, "persons");
45142
+ const dir = import_node_path46.default.join(dataDir, "persons");
45045
45143
  try {
45046
45144
  import_node_fs32.default.rmSync(dir, { recursive: true, force: true });
45047
45145
  } catch {