@clawos-dev/clawd 0.2.48-beta.74.b742e0f → 0.2.48-beta.76.f411c83

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -296,8 +296,8 @@ var require_req = __commonJS({
296
296
  if (req.originalUrl) {
297
297
  _req.url = req.originalUrl;
298
298
  } else {
299
- const path26 = req.path;
300
- _req.url = typeof path26 === "string" ? path26 : req.url ? req.url.path || req.url : void 0;
299
+ const path25 = req.path;
300
+ _req.url = typeof path25 === "string" ? path25 : req.url ? req.url.path || req.url : void 0;
301
301
  }
302
302
  if (req.query) {
303
303
  _req.query = req.query;
@@ -462,14 +462,14 @@ var require_redact = __commonJS({
462
462
  }
463
463
  return obj;
464
464
  }
465
- function parsePath(path26) {
465
+ function parsePath(path25) {
466
466
  const parts = [];
467
467
  let current = "";
468
468
  let inBrackets = false;
469
469
  let inQuotes = false;
470
470
  let quoteChar = "";
471
- for (let i = 0; i < path26.length; i++) {
472
- const char = path26[i];
471
+ for (let i = 0; i < path25.length; i++) {
472
+ const char = path25[i];
473
473
  if (!inBrackets && char === ".") {
474
474
  if (current) {
475
475
  parts.push(current);
@@ -600,10 +600,10 @@ var require_redact = __commonJS({
600
600
  return current;
601
601
  }
602
602
  function redactPaths(obj, paths, censor, remove = false) {
603
- for (const path26 of paths) {
604
- const parts = parsePath(path26);
603
+ for (const path25 of paths) {
604
+ const parts = parsePath(path25);
605
605
  if (parts.includes("*")) {
606
- redactWildcardPath(obj, parts, censor, path26, remove);
606
+ redactWildcardPath(obj, parts, censor, path25, remove);
607
607
  } else {
608
608
  if (remove) {
609
609
  removeKey(obj, parts);
@@ -688,8 +688,8 @@ var require_redact = __commonJS({
688
688
  }
689
689
  } else {
690
690
  if (afterWildcard.includes("*")) {
691
- const wrappedCensor = typeof censor === "function" ? (value, path26) => {
692
- const fullPath = [...pathArray.slice(0, pathLength), ...path26];
691
+ const wrappedCensor = typeof censor === "function" ? (value, path25) => {
692
+ const fullPath = [...pathArray.slice(0, pathLength), ...path25];
693
693
  return censor(value, fullPath);
694
694
  } : censor;
695
695
  redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
@@ -724,8 +724,8 @@ var require_redact = __commonJS({
724
724
  return null;
725
725
  }
726
726
  const pathStructure = /* @__PURE__ */ new Map();
727
- for (const path26 of pathsToClone) {
728
- const parts = parsePath(path26);
727
+ for (const path25 of pathsToClone) {
728
+ const parts = parsePath(path25);
729
729
  let current = pathStructure;
730
730
  for (let i = 0; i < parts.length; i++) {
731
731
  const part = parts[i];
@@ -777,24 +777,24 @@ var require_redact = __commonJS({
777
777
  }
778
778
  return cloneSelectively(obj, pathStructure);
779
779
  }
780
- function validatePath(path26) {
781
- if (typeof path26 !== "string") {
780
+ function validatePath(path25) {
781
+ if (typeof path25 !== "string") {
782
782
  throw new Error("Paths must be (non-empty) strings");
783
783
  }
784
- if (path26 === "") {
784
+ if (path25 === "") {
785
785
  throw new Error("Invalid redaction path ()");
786
786
  }
787
- if (path26.includes("..")) {
788
- throw new Error(`Invalid redaction path (${path26})`);
787
+ if (path25.includes("..")) {
788
+ throw new Error(`Invalid redaction path (${path25})`);
789
789
  }
790
- if (path26.includes(",")) {
791
- throw new Error(`Invalid redaction path (${path26})`);
790
+ if (path25.includes(",")) {
791
+ throw new Error(`Invalid redaction path (${path25})`);
792
792
  }
793
793
  let bracketCount = 0;
794
794
  let inQuotes = false;
795
795
  let quoteChar = "";
796
- for (let i = 0; i < path26.length; i++) {
797
- const char = path26[i];
796
+ for (let i = 0; i < path25.length; i++) {
797
+ const char = path25[i];
798
798
  if ((char === '"' || char === "'") && bracketCount > 0) {
799
799
  if (!inQuotes) {
800
800
  inQuotes = true;
@@ -808,20 +808,20 @@ var require_redact = __commonJS({
808
808
  } else if (char === "]" && !inQuotes) {
809
809
  bracketCount--;
810
810
  if (bracketCount < 0) {
811
- throw new Error(`Invalid redaction path (${path26})`);
811
+ throw new Error(`Invalid redaction path (${path25})`);
812
812
  }
813
813
  }
814
814
  }
815
815
  if (bracketCount !== 0) {
816
- throw new Error(`Invalid redaction path (${path26})`);
816
+ throw new Error(`Invalid redaction path (${path25})`);
817
817
  }
818
818
  }
819
819
  function validatePaths(paths) {
820
820
  if (!Array.isArray(paths)) {
821
821
  throw new TypeError("paths must be an array");
822
822
  }
823
- for (const path26 of paths) {
824
- validatePath(path26);
823
+ for (const path25 of paths) {
824
+ validatePath(path25);
825
825
  }
826
826
  }
827
827
  function slowRedact(options = {}) {
@@ -989,8 +989,8 @@ var require_redaction = __commonJS({
989
989
  if (shape[k] === null) {
990
990
  o[k] = (value) => topCensor(value, [k]);
991
991
  } else {
992
- const wrappedCensor = typeof censor === "function" ? (value, path26) => {
993
- return censor(value, [k, ...path26]);
992
+ const wrappedCensor = typeof censor === "function" ? (value, path25) => {
993
+ return censor(value, [k, ...path25]);
994
994
  } : censor;
995
995
  o[k] = Redact({
996
996
  paths: shape[k],
@@ -1211,7 +1211,7 @@ var require_sonic_boom = __commonJS({
1211
1211
  var fs24 = require("fs");
1212
1212
  var EventEmitter = require("events");
1213
1213
  var inherits = require("util").inherits;
1214
- var path26 = require("path");
1214
+ var path25 = require("path");
1215
1215
  var sleep = require_atomic_sleep();
1216
1216
  var assert = require("assert");
1217
1217
  var BUSY_WRITE_TIMEOUT = 100;
@@ -1265,7 +1265,7 @@ var require_sonic_boom = __commonJS({
1265
1265
  const mode = sonic.mode;
1266
1266
  if (sonic.sync) {
1267
1267
  try {
1268
- if (sonic.mkdir) fs24.mkdirSync(path26.dirname(file), { recursive: true });
1268
+ if (sonic.mkdir) fs24.mkdirSync(path25.dirname(file), { recursive: true });
1269
1269
  const fd = fs24.openSync(file, flags, mode);
1270
1270
  fileOpened(null, fd);
1271
1271
  } catch (err) {
@@ -1273,7 +1273,7 @@ var require_sonic_boom = __commonJS({
1273
1273
  throw err;
1274
1274
  }
1275
1275
  } else if (sonic.mkdir) {
1276
- fs24.mkdir(path26.dirname(file), { recursive: true }, (err) => {
1276
+ fs24.mkdir(path25.dirname(file), { recursive: true }, (err) => {
1277
1277
  if (err) return fileOpened(err);
1278
1278
  fs24.open(file, flags, mode, fileOpened);
1279
1279
  });
@@ -4895,8 +4895,8 @@ var init_parseUtil = __esm({
4895
4895
  init_errors2();
4896
4896
  init_en();
4897
4897
  makeIssue = (params) => {
4898
- const { data, path: path26, errorMaps, issueData } = params;
4899
- const fullPath = [...path26, ...issueData.path || []];
4898
+ const { data, path: path25, errorMaps, issueData } = params;
4899
+ const fullPath = [...path25, ...issueData.path || []];
4900
4900
  const fullIssue = {
4901
4901
  ...issueData,
4902
4902
  path: fullPath
@@ -5207,11 +5207,11 @@ var init_types = __esm({
5207
5207
  init_parseUtil();
5208
5208
  init_util();
5209
5209
  ParseInputLazyPath = class {
5210
- constructor(parent, value, path26, key) {
5210
+ constructor(parent, value, path25, key) {
5211
5211
  this._cachedPath = [];
5212
5212
  this.parent = parent;
5213
5213
  this.data = value;
5214
- this._path = path26;
5214
+ this._path = path25;
5215
5215
  this._key = key;
5216
5216
  }
5217
5217
  get path() {
@@ -9823,11 +9823,11 @@ var init_lib = __esm({
9823
9823
  }
9824
9824
  }
9825
9825
  },
9826
- addToPath: function addToPath(path26, added, removed, oldPosInc, options) {
9827
- var last = path26.lastComponent;
9826
+ addToPath: function addToPath(path25, added, removed, oldPosInc, options) {
9827
+ var last = path25.lastComponent;
9828
9828
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
9829
9829
  return {
9830
- oldPos: path26.oldPos + oldPosInc,
9830
+ oldPos: path25.oldPos + oldPosInc,
9831
9831
  lastComponent: {
9832
9832
  count: last.count + 1,
9833
9833
  added,
@@ -9837,7 +9837,7 @@ var init_lib = __esm({
9837
9837
  };
9838
9838
  } else {
9839
9839
  return {
9840
- oldPos: path26.oldPos + oldPosInc,
9840
+ oldPos: path25.oldPos + oldPosInc,
9841
9841
  lastComponent: {
9842
9842
  count: 1,
9843
9843
  added,
@@ -10268,10 +10268,10 @@ function attachmentToHistoryMessage(o, ts) {
10268
10268
  const memories = raw.map((m) => {
10269
10269
  if (!m || typeof m !== "object") return null;
10270
10270
  const rec = m;
10271
- const path26 = typeof rec.path === "string" ? rec.path : null;
10271
+ const path25 = typeof rec.path === "string" ? rec.path : null;
10272
10272
  const content = typeof rec.content === "string" ? rec.content : null;
10273
- if (!path26 || content == null) return null;
10274
- const entry = { path: path26, content };
10273
+ if (!path25 || content == null) return null;
10274
+ const entry = { path: path25, content };
10275
10275
  if (typeof rec.mtimeMs === "number") entry.mtimeMs = rec.mtimeMs;
10276
10276
  return entry;
10277
10277
  }).filter((m) => m !== null);
@@ -10308,7 +10308,7 @@ function readBackupContent(fileHistoryRoot, toolSessionId, backupFileName) {
10308
10308
  if (backupFileName === null) return null;
10309
10309
  try {
10310
10310
  return import_node_fs6.default.readFileSync(
10311
- import_node_path7.default.join(fileHistoryRoot, toolSessionId, backupFileName),
10311
+ import_node_path6.default.join(fileHistoryRoot, toolSessionId, backupFileName),
10312
10312
  "utf8"
10313
10313
  );
10314
10314
  } catch {
@@ -10323,13 +10323,13 @@ function readCurrentContent(filePath) {
10323
10323
  return null;
10324
10324
  }
10325
10325
  }
10326
- var import_node_fs6, import_node_os2, import_node_path7, 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;
10326
+ var import_node_fs6, import_node_os2, import_node_path6, 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;
10327
10327
  var init_claude_history = __esm({
10328
10328
  "src/tools/claude-history.ts"() {
10329
10329
  "use strict";
10330
10330
  import_node_fs6 = __toESM(require("fs"), 1);
10331
10331
  import_node_os2 = __toESM(require("os"), 1);
10332
- import_node_path7 = __toESM(require("path"), 1);
10332
+ import_node_path6 = __toESM(require("path"), 1);
10333
10333
  init_lib();
10334
10334
  init_tool_result_extra();
10335
10335
  TASK_NOTIFICATION_RE = /<task-notification\b[\s\S]*?<\/task-notification>/i;
@@ -10353,9 +10353,9 @@ var init_claude_history = __esm({
10353
10353
  // 每次 user 提交前 trackEdit 拷一份,作为 rewind 回退目标
10354
10354
  fileHistoryRoot;
10355
10355
  constructor(opts = {}) {
10356
- const base = opts.baseDir ?? import_node_path7.default.join(import_node_os2.default.homedir(), ".claude");
10357
- this.projectsRoot = import_node_path7.default.join(base, "projects");
10358
- this.fileHistoryRoot = import_node_path7.default.join(base, "file-history");
10356
+ const base = opts.baseDir ?? import_node_path6.default.join(import_node_os2.default.homedir(), ".claude");
10357
+ this.projectsRoot = import_node_path6.default.join(base, "projects");
10358
+ this.fileHistoryRoot = import_node_path6.default.join(base, "file-history");
10359
10359
  }
10360
10360
  async listProjects() {
10361
10361
  let entries;
@@ -10368,9 +10368,9 @@ var init_claude_history = __esm({
10368
10368
  const out = [];
10369
10369
  for (const ent of entries) {
10370
10370
  if (!ent.isDirectory()) continue;
10371
- const dir = import_node_path7.default.join(this.projectsRoot, ent.name);
10371
+ const dir = import_node_path6.default.join(this.projectsRoot, ent.name);
10372
10372
  const files = import_node_fs6.default.readdirSync(dir).filter((f) => f.endsWith(".jsonl"));
10373
- const updatedAtMs = files.reduce((m, f) => Math.max(m, safeStatMtime(import_node_path7.default.join(dir, f))), 0);
10373
+ const updatedAtMs = files.reduce((m, f) => Math.max(m, safeStatMtime(import_node_path6.default.join(dir, f))), 0);
10374
10374
  out.push({
10375
10375
  projectPath: hashDirToCwd(ent.name),
10376
10376
  hashDir: ent.name,
@@ -10382,7 +10382,7 @@ var init_claude_history = __esm({
10382
10382
  return out;
10383
10383
  }
10384
10384
  async listSessions(args) {
10385
- const dir = import_node_path7.default.join(this.projectsRoot, cwdToHashDir(args.projectPath));
10385
+ const dir = import_node_path6.default.join(this.projectsRoot, cwdToHashDir(args.projectPath));
10386
10386
  let files;
10387
10387
  try {
10388
10388
  files = import_node_fs6.default.readdirSync(dir).filter((f) => f.endsWith(".jsonl"));
@@ -10392,7 +10392,7 @@ var init_claude_history = __esm({
10392
10392
  }
10393
10393
  const out = [];
10394
10394
  for (const f of files) {
10395
- const full = import_node_path7.default.join(dir, f);
10395
+ const full = import_node_path6.default.join(dir, f);
10396
10396
  const toolSessionId = f.slice(0, -".jsonl".length);
10397
10397
  const lines = readJsonlLines(full);
10398
10398
  let summary = "";
@@ -10447,7 +10447,7 @@ var init_claude_history = __esm({
10447
10447
  return out;
10448
10448
  }
10449
10449
  async read(args) {
10450
- const file = import_node_path7.default.join(
10450
+ const file = import_node_path6.default.join(
10451
10451
  this.projectsRoot,
10452
10452
  cwdToHashDir(args.cwd),
10453
10453
  `${args.toolSessionId}.jsonl`
@@ -10480,7 +10480,7 @@ var init_claude_history = __esm({
10480
10480
  // 独立目录路径:<projectsRoot>/<cwdHash>/<toolSessionId>/subagents/*.jsonl
10481
10481
  // 返回 null 表示目录不存在(调用方回退旧实现);返回空数组表示目录存在但无 jsonl
10482
10482
  listSubagentsFromDirectory(cwd, toolSessionId) {
10483
- const dir = import_node_path7.default.join(
10483
+ const dir = import_node_path6.default.join(
10484
10484
  this.projectsRoot,
10485
10485
  cwdToHashDir(cwd),
10486
10486
  toolSessionId,
@@ -10498,7 +10498,7 @@ var init_claude_history = __esm({
10498
10498
  if (!e.isFile()) continue;
10499
10499
  if (!e.name.startsWith("agent-") || !e.name.endsWith(".jsonl")) continue;
10500
10500
  const subagentId = e.name.slice("agent-".length, -".jsonl".length);
10501
- const filePath = import_node_path7.default.join(dir, e.name);
10501
+ const filePath = import_node_path6.default.join(dir, e.name);
10502
10502
  const lines = readJsonlLines(filePath);
10503
10503
  let firstText = "";
10504
10504
  let messageCount = 0;
@@ -10515,7 +10515,7 @@ var init_claude_history = __esm({
10515
10515
  return out;
10516
10516
  }
10517
10517
  listSubagentsFromMainJsonl(cwd, toolSessionId) {
10518
- const file = import_node_path7.default.join(
10518
+ const file = import_node_path6.default.join(
10519
10519
  this.projectsRoot,
10520
10520
  cwdToHashDir(cwd),
10521
10521
  `${toolSessionId}.jsonl`
@@ -10550,7 +10550,7 @@ var init_claude_history = __esm({
10550
10550
  }
10551
10551
  // 独立文件路径:agent-<subagentId>.jsonl;文件不存在返回 null 让调用方回退旧实现
10552
10552
  readSubagentFromFile(cwd, toolSessionId, subagentId) {
10553
- const file = import_node_path7.default.join(
10553
+ const file = import_node_path6.default.join(
10554
10554
  this.projectsRoot,
10555
10555
  cwdToHashDir(cwd),
10556
10556
  toolSessionId,
@@ -10578,7 +10578,7 @@ var init_claude_history = __esm({
10578
10578
  * "那一刻每个 tracked 文件对应的 backup 文件名"
10579
10579
  */
10580
10580
  readFileHistorySnapshots(args) {
10581
- const file = import_node_path7.default.join(
10581
+ const file = import_node_path6.default.join(
10582
10582
  this.projectsRoot,
10583
10583
  cwdToHashDir(args.cwd),
10584
10584
  `${args.toolSessionId}.jsonl`
@@ -10623,7 +10623,7 @@ var init_claude_history = __esm({
10623
10623
  for (const [anchorId, target] of snapshots) {
10624
10624
  let hasAny = false;
10625
10625
  for (const [rawPath, backup] of Object.entries(target)) {
10626
- const absPath = import_node_path7.default.isAbsolute(rawPath) ? rawPath : import_node_path7.default.join(args.cwd, rawPath);
10626
+ const absPath = import_node_path6.default.isAbsolute(rawPath) ? rawPath : import_node_path6.default.join(args.cwd, rawPath);
10627
10627
  const backupContent = readBackupContent(
10628
10628
  this.fileHistoryRoot,
10629
10629
  args.toolSessionId,
@@ -10663,7 +10663,7 @@ var init_claude_history = __esm({
10663
10663
  let totalInsertions = 0;
10664
10664
  let totalDeletions = 0;
10665
10665
  for (const [rawPath, backup] of Object.entries(target)) {
10666
- const absPath = import_node_path7.default.isAbsolute(rawPath) ? rawPath : import_node_path7.default.join(args.cwd, rawPath);
10666
+ const absPath = import_node_path6.default.isAbsolute(rawPath) ? rawPath : import_node_path6.default.join(args.cwd, rawPath);
10667
10667
  const backupContent = readBackupContent(
10668
10668
  this.fileHistoryRoot,
10669
10669
  args.toolSessionId,
@@ -10710,7 +10710,7 @@ var init_claude_history = __esm({
10710
10710
  };
10711
10711
  }
10712
10712
  readSubagentFromMainJsonl(cwd, toolSessionId, subagentId) {
10713
- const file = import_node_path7.default.join(
10713
+ const file = import_node_path6.default.join(
10714
10714
  this.projectsRoot,
10715
10715
  cwdToHashDir(cwd),
10716
10716
  `${toolSessionId}.jsonl`
@@ -10734,7 +10734,7 @@ var init_claude_history = __esm({
10734
10734
  // src/tools/claude.ts
10735
10735
  function macOSDesktopCandidates(home) {
10736
10736
  return [
10737
- import_node_path8.default.join(home, "Applications", "Claude.app", "Contents", "Resources", "app.asar.unpacked", "node_modules", "@anthropic-ai", "claude-code", "cli.js"),
10737
+ import_node_path7.default.join(home, "Applications", "Claude.app", "Contents", "Resources", "app.asar.unpacked", "node_modules", "@anthropic-ai", "claude-code", "cli.js"),
10738
10738
  "/Applications/Claude.app/Contents/Resources/app.asar.unpacked/node_modules/@anthropic-ai/claude-code/cli.js"
10739
10739
  ];
10740
10740
  }
@@ -11075,10 +11075,10 @@ function parseAttachment(obj) {
11075
11075
  const memories = raw.map((m) => {
11076
11076
  if (!m || typeof m !== "object") return null;
11077
11077
  const rec = m;
11078
- const path26 = typeof rec.path === "string" ? rec.path : null;
11078
+ const path25 = typeof rec.path === "string" ? rec.path : null;
11079
11079
  const content = typeof rec.content === "string" ? rec.content : null;
11080
- if (!path26 || content == null) return null;
11081
- const out = { path: path26, content };
11080
+ if (!path25 || content == null) return null;
11081
+ const out = { path: path25, content };
11082
11082
  if (typeof rec.mtimeMs === "number") out.mtimeMs = rec.mtimeMs;
11083
11083
  return out;
11084
11084
  }).filter((m) => m !== null);
@@ -11182,7 +11182,7 @@ function encodeClaudeStdin(text) {
11182
11182
  };
11183
11183
  return JSON.stringify(frame) + "\n";
11184
11184
  }
11185
- var import_node_child_process, import_node_child_process2, import_node_fs7, import_node_os3, import_node_path8, ATTACHMENT_SILENT_SUBTYPES2, unknownTypeHandler, ATTACHMENT_RE, IMAGE_EXT_MIME, CLAUDE_MODELS, CLAUDE_PERMISSION_MODES, CLAUDE_CAPABILITIES, ClaudeAdapter;
11185
+ var import_node_child_process, import_node_child_process2, import_node_fs7, import_node_os3, import_node_path7, ATTACHMENT_SILENT_SUBTYPES2, unknownTypeHandler, ATTACHMENT_RE, IMAGE_EXT_MIME, CLAUDE_MODELS, CLAUDE_PERMISSION_MODES, CLAUDE_CAPABILITIES, ClaudeAdapter;
11186
11186
  var init_claude = __esm({
11187
11187
  "src/tools/claude.ts"() {
11188
11188
  "use strict";
@@ -11190,7 +11190,7 @@ var init_claude = __esm({
11190
11190
  import_node_child_process2 = require("child_process");
11191
11191
  import_node_fs7 = __toESM(require("fs"), 1);
11192
11192
  import_node_os3 = __toESM(require("os"), 1);
11193
- import_node_path8 = __toESM(require("path"), 1);
11193
+ import_node_path7 = __toESM(require("path"), 1);
11194
11194
  init_protocol();
11195
11195
  init_claude_history();
11196
11196
  init_tool_result_extra();
@@ -14945,7 +14945,7 @@ var require_websocket_server = __commonJS({
14945
14945
  // src/run-case/recorder.ts
14946
14946
  function startRunCaseRecorder(opts) {
14947
14947
  const now = opts.now ?? Date.now;
14948
- const dir = import_node_path22.default.dirname(opts.recordPath);
14948
+ const dir = import_node_path21.default.dirname(opts.recordPath);
14949
14949
  let stream = null;
14950
14950
  let closing = false;
14951
14951
  let closedSettled = false;
@@ -14985,12 +14985,12 @@ function startRunCaseRecorder(opts) {
14985
14985
  };
14986
14986
  return { tap, close, closed };
14987
14987
  }
14988
- var import_node_fs21, import_node_path22;
14988
+ var import_node_fs21, import_node_path21;
14989
14989
  var init_recorder = __esm({
14990
14990
  "src/run-case/recorder.ts"() {
14991
14991
  "use strict";
14992
14992
  import_node_fs21 = __toESM(require("fs"), 1);
14993
- import_node_path22 = __toESM(require("path"), 1);
14993
+ import_node_path21 = __toESM(require("path"), 1);
14994
14994
  }
14995
14995
  });
14996
14996
 
@@ -15033,7 +15033,7 @@ var init_wire = __esm({
15033
15033
  // src/run-case/controller.ts
15034
15034
  async function runController(opts) {
15035
15035
  const now = opts.now ?? Date.now;
15036
- const cwd = opts.cwd ?? (0, import_node_fs22.mkdtempSync)(import_node_path23.default.join(import_node_os14.default.tmpdir(), "clawd-runcase-"));
15036
+ const cwd = opts.cwd ?? (0, import_node_fs22.mkdtempSync)(import_node_path22.default.join(import_node_os14.default.tmpdir(), "clawd-runcase-"));
15037
15037
  const ownsCwd = opts.cwd === void 0;
15038
15038
  const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
15039
15039
  const spawnCtx = { cwd };
@@ -15200,13 +15200,13 @@ async function runController(opts) {
15200
15200
  }
15201
15201
  return exitCode ?? 0;
15202
15202
  }
15203
- var import_node_fs22, import_node_os14, import_node_path23;
15203
+ var import_node_fs22, import_node_os14, import_node_path22;
15204
15204
  var init_controller = __esm({
15205
15205
  "src/run-case/controller.ts"() {
15206
15206
  "use strict";
15207
15207
  import_node_fs22 = require("fs");
15208
15208
  import_node_os14 = __toESM(require("os"), 1);
15209
- import_node_path23 = __toESM(require("path"), 1);
15209
+ import_node_path22 = __toESM(require("path"), 1);
15210
15210
  init_claude();
15211
15211
  init_stdout_splitter();
15212
15212
  init_permission_stdio();
@@ -15431,7 +15431,7 @@ Env (advanced):
15431
15431
  `;
15432
15432
 
15433
15433
  // src/index.ts
15434
- var import_node_path21 = __toESM(require("path"), 1);
15434
+ var import_node_path20 = __toESM(require("path"), 1);
15435
15435
  var import_node_fs20 = __toESM(require("fs"), 1);
15436
15436
 
15437
15437
  // src/logger.ts
@@ -15471,30 +15471,9 @@ function createLogger(opts = {}) {
15471
15471
 
15472
15472
  // src/session/store.ts
15473
15473
  var import_node_fs3 = __toESM(require("fs"), 1);
15474
- var import_node_path4 = __toESM(require("path"), 1);
15475
- init_protocol();
15476
-
15477
- // src/session/scope.ts
15478
15474
  var import_node_path3 = __toESM(require("path"), 1);
15479
- function scopeKey(scope) {
15480
- return scope.kind === "default" ? "default" : `persona:${scope.personaId}:${scope.mode}`;
15481
- }
15482
- function scopeSubPath(scope) {
15483
- return scope.kind === "default" ? ["default"] : [scope.personaId, scope.mode];
15484
- }
15485
- function metaFromScope(scope, personaRoot) {
15486
- if (scope.kind === "default") return void 0;
15487
- if (scope.mode === "owner") {
15488
- return { idleKillEnabled: false, personaMode: "owner" };
15489
- }
15490
- return {
15491
- idleKillEnabled: true,
15492
- personaMode: "listener",
15493
- extraSettings: import_node_path3.default.join(personaRoot, scope.personaId, ".clawd", "sandbox-settings.json")
15494
- };
15495
- }
15496
-
15497
- // src/session/store.ts
15475
+ init_protocol();
15476
+ var DEFAULT_AGENT_ID = "default";
15498
15477
  function safeFileName(sessionId) {
15499
15478
  const base = sessionId.replace(/[^a-zA-Z0-9_\-.]/g, "_");
15500
15479
  const cleaned = base.replace(/^\.+/, (dots) => "_".repeat(dots.length));
@@ -15506,15 +15485,20 @@ function safeFileName(sessionId) {
15506
15485
  var SessionStore = class {
15507
15486
  root;
15508
15487
  constructor(opts) {
15509
- const scope = opts.scope ?? { kind: "default" };
15510
- this.root = import_node_path4.default.join(
15511
- opts.dataDir,
15512
- "sessions",
15513
- ...scopeSubPath(scope).map(safeFileName)
15514
- );
15488
+ const agentId = opts.agentId ?? DEFAULT_AGENT_ID;
15489
+ if (agentId !== DEFAULT_AGENT_ID) {
15490
+ if (!opts.personaRoot) {
15491
+ throw new Error(
15492
+ `SessionStore: personaRoot is required for non-default agentId='${agentId}'. Bootstrap must wire personaRoot when constructing SessionStore for persona agents.`
15493
+ );
15494
+ }
15495
+ this.root = import_node_path3.default.join(opts.personaRoot, safeFileName(agentId), ".clawd", "sub-sessions");
15496
+ } else {
15497
+ this.root = import_node_path3.default.join(opts.dataDir, "sessions", agentId);
15498
+ }
15515
15499
  }
15516
15500
  filePath(sessionId) {
15517
- return import_node_path4.default.join(this.root, `${safeFileName(sessionId)}.json`);
15501
+ return import_node_path3.default.join(this.root, `${safeFileName(sessionId)}.json`);
15518
15502
  }
15519
15503
  ensureDir() {
15520
15504
  import_node_fs3.default.mkdirSync(this.root, { recursive: true });
@@ -15562,7 +15546,7 @@ var SessionStore = class {
15562
15546
  for (const name of entries) {
15563
15547
  if (!name.endsWith(".json")) continue;
15564
15548
  if (name.includes(".tmp-")) continue;
15565
- const full = import_node_path4.default.join(this.root, name);
15549
+ const full = import_node_path3.default.join(this.root, name);
15566
15550
  try {
15567
15551
  const raw = import_node_fs3.default.readFileSync(full, "utf8");
15568
15552
  const parsed = JSON.parse(raw);
@@ -15578,7 +15562,7 @@ var SessionStore = class {
15578
15562
 
15579
15563
  // src/session/manager.ts
15580
15564
  var import_node_fs5 = __toESM(require("fs"), 1);
15581
- var import_node_path6 = __toESM(require("path"), 1);
15565
+ var import_node_path5 = __toESM(require("path"), 1);
15582
15566
 
15583
15567
  // ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/stringify.js
15584
15568
  var byteToHex = [];
@@ -16306,7 +16290,7 @@ init_stdout_splitter();
16306
16290
 
16307
16291
  // src/ipc-recorder.ts
16308
16292
  var import_node_fs4 = __toESM(require("fs"), 1);
16309
- var import_node_path5 = __toESM(require("path"), 1);
16293
+ var import_node_path4 = __toESM(require("path"), 1);
16310
16294
  function tsForFilename(ms) {
16311
16295
  return new Date(ms).toISOString().replace(/[:.]/g, "-");
16312
16296
  }
@@ -16317,8 +16301,8 @@ function startRecorder(opts) {
16317
16301
  return null;
16318
16302
  }
16319
16303
  const now = opts.now ?? Date.now;
16320
- const dir = import_node_path5.default.join(opts.dataDir, "ipc-recordings", opts.sessionId);
16321
- const filePath = import_node_path5.default.join(dir, `${tsForFilename(now())}.jsonl`);
16304
+ const dir = import_node_path4.default.join(opts.dataDir, "ipc-recordings", opts.sessionId);
16305
+ const filePath = import_node_path4.default.join(dir, `${tsForFilename(now())}.jsonl`);
16322
16306
  let stream = null;
16323
16307
  let closedResolve;
16324
16308
  const closed = new Promise((resolve2) => {
@@ -16760,6 +16744,7 @@ function makeInitialState(file, subSessionMeta) {
16760
16744
  var SessionManager = class {
16761
16745
  constructor(deps) {
16762
16746
  this.deps = deps;
16747
+ this.storesByAgent.set(DEFAULT_AGENT_ID, deps.store);
16763
16748
  }
16764
16749
  deps;
16765
16750
  // sessionId → SessionRunner;在 send / ensureSession 时按需创建
@@ -16775,28 +16760,33 @@ var SessionManager = class {
16775
16760
  // 由 observer 监听 jsonl user 行后调 recordRealUserUuid 建立映射;rewind 系列 RPC 在
16776
16761
  // 入参 / 出参做转译,保证 UI 看到的 uuid 始终是 events 流里的 synth uuid
16777
16762
  realUuidBySynth = /* @__PURE__ */ new Map();
16778
- // SessionStore scope 派生(root = <dataDir>/sessions/<scopeSubPath>/)。
16779
- // default scope 直接复用 deps.store;persona scope(owner / listener)第一次访问时按需创建并缓存。
16780
- // 取代旧的 storesByAgent —— agentId 概念由 SessionScope 取代,路径即身份,
16781
- // SubSessionMeta scope 派生(metaFromScope),不再需要运行时 cache ownerPersonaId 兜底。
16782
- storesByScope = /* @__PURE__ */ new Map();
16763
+ // persona sub-session 路径:按 agentId 派生 SessionStore(root = dataDir/sessions/<agentId>/)。
16764
+ // 'default' 直接复用 deps.store;其它 agentId 第一次访问时按需创建并缓存
16765
+ storesByAgent = /* @__PURE__ */ new Map();
16766
+ // sub-session 创建时记录的 subSessionMeta;ensureSession / runner 创建时塞入 reducer state。
16767
+ // 不进 SessionFile schema(避免破坏现有 zod parse),仅运行时缓存
16768
+ subSessionMetaBySid = /* @__PURE__ */ new Map();
16783
16769
  // persona-bound transport 订阅器:sessionId → Set<listener>。
16784
16770
  // 透传 owner 路径白名单 EventFrame(routeFromRunner 决定哪些 type 进入),listener 端按
16785
16771
  // `frame.type` narrow 出 'session:event'(ParsedEvent)/ 'session:status'(procAlive 同步)等。
16786
16772
  // 这样 owner / listener 共用同一组事件字面量,新增跨端信号时只需在 fan-out 白名单里加 type。
16787
16773
  eventSubscribers = /* @__PURE__ */ new Map();
16788
- // 按 scope 拿对应的 SessionStore。default scope 复用 deps.store(保证与
16789
- // bootstrap 注入的 store 一致);persona scope 第一次访问时按需创建并缓存。
16790
- storeFor(scope) {
16791
- if (scope.kind === "default") return this.deps.store;
16792
- const key = scopeKey(scope);
16793
- const cached = this.storesByScope.get(key);
16774
+ // 按 agentId 拿对应的 SessionStore;persona-* agentId 使用 personaRoot 路径。
16775
+ // 'default' 直接复用 deps.store;其它 agentId 第一次访问时按需创建并缓存。
16776
+ // personaRoot 必须与 PersonaStore 同源,两者共享相同的 persona 目录层级
16777
+ storeFor(agentId) {
16778
+ const cached = this.storesByAgent.get(agentId);
16794
16779
  if (cached) return cached;
16795
16780
  if (!this.deps.dataDir) {
16796
- throw new Error(`SessionManager: dataDir required to construct SessionStore for scope=${key}`);
16781
+ throw new Error(`SessionManager: dataDir required to route agentId='${agentId}'`);
16782
+ }
16783
+ if (!this.deps.personaRoot) {
16784
+ throw new Error(
16785
+ `SessionManager: personaRoot is required to route agentId='${agentId}'. Bootstrap must wire personaRoot when constructing SessionManager for persona sub-sessions.`
16786
+ );
16797
16787
  }
16798
- const st = new SessionStore({ dataDir: this.deps.dataDir, scope });
16799
- this.storesByScope.set(key, st);
16788
+ const st = new SessionStore({ dataDir: this.deps.dataDir, agentId, personaRoot: this.deps.personaRoot });
16789
+ this.storesByAgent.set(agentId, st);
16800
16790
  return st;
16801
16791
  }
16802
16792
  async getCapabilities(tool) {
@@ -16807,80 +16797,26 @@ var SessionManager = class {
16807
16797
  this.capabilitiesCache.set(tool, caps);
16808
16798
  return caps;
16809
16799
  }
16810
- // SessionFile.ownerPersonaId schema 字段推回写入 scope。
16811
- // ownerPersonaId create({ownerPersonaId}) schema 落盘时记入,永远只反映
16812
- // session 出身(不可变);此函数只用于 SessionStore 的写入路由,不参与运行时行为
16813
- // 决策(personaMode='owner' 等由路径 → scope → metaFromScope 派生)。
16814
- // 仅覆盖 owner + default 两类——listener sub-session 不会从 default RPC 路径进来。
16815
- scopeForFile(file) {
16816
- return file.ownerPersonaId ? { kind: "persona", personaId: file.ownerPersonaId, mode: "owner" } : { kind: "default" };
16817
- }
16818
- // 扫 <dataDir>/sessions/ 列出所有 persona 命名空间(不含 'default')。
16819
- // 用于 findOwnedSession / listAllOwned 跨 scope 查询。
16820
- listPersonaIdsOnDisk() {
16821
- if (!this.deps.dataDir) return [];
16822
- const root = import_node_path6.default.join(this.deps.dataDir, "sessions");
16823
- let entries;
16824
- try {
16825
- entries = import_node_fs5.default.readdirSync(root, { withFileTypes: true });
16826
- } catch (err) {
16827
- const code = err?.code;
16828
- if (code === "ENOENT") return [];
16829
- throw err;
16830
- }
16831
- return entries.filter((e) => e.isDirectory() && e.name !== "default").map((e) => e.name);
16832
- }
16833
- // owner / default 两个分类下按 sessionId 找文件——前端只传 sessionId 不带 scope,
16834
- // SessionManager 在这里扫盘定位(default 直接试,未命中再轮询所有 persona owner 目录)。
16835
- // listener sub-session 不走这条——transport 始终明确传 (personaId, sessionId)。
16836
- findOwnedSession(sessionId) {
16837
- const dflt = this.deps.store.read(sessionId);
16838
- if (dflt) return dflt;
16839
- for (const personaId of this.listPersonaIdsOnDisk()) {
16840
- const ownerStore = this.storeFor({ kind: "persona", personaId, mode: "owner" });
16841
- const file = ownerStore.read(sessionId);
16842
- if (file) return file;
16843
- }
16844
- return null;
16845
- }
16846
- // 合并 default + 所有 persona owner 的 SessionFile —— 桌面 App 主 session 列表入口。
16847
- // 同样不含 listener sub-session(listener 走 persona:listSubSessions RPC 单独入口)。
16848
- listAllOwned() {
16849
- const out = [];
16850
- out.push(...this.deps.store.list());
16851
- for (const personaId of this.listPersonaIdsOnDisk()) {
16852
- const ownerStore = this.storeFor({ kind: "persona", personaId, mode: "owner" });
16853
- out.push(...ownerStore.list());
16854
- }
16855
- return out.sort(
16856
- (a, b) => a.updatedAt > b.updatedAt ? -1 : a.updatedAt < b.updatedAt ? 1 : 0
16857
- );
16858
- }
16859
- // 写回 SessionFile,自动根据 ownerPersonaId 派生写入 scope。
16860
- // 调用方原先都是 `deps.store.write(updated)`,全部走这里收口路由。
16861
- writeOwned(file) {
16862
- return this.storeFor(this.scopeForFile(file)).write(file);
16863
- }
16864
- // 删除 owned SessionFile(default 或 persona/owner),与 findOwnedSession 对称扫盘。
16865
- deleteOwned(sessionId) {
16866
- if (this.deps.store.delete(sessionId)) return true;
16867
- for (const personaId of this.listPersonaIdsOnDisk()) {
16868
- const ownerStore = this.storeFor({ kind: "persona", personaId, mode: "owner" });
16869
- if (ownerStore.delete(sessionId)) return true;
16800
+ // 按优先级解析 SubSessionMeta:subSessionMetaBySid 缓存(内存,首次 create/registerSubSession 写入)
16801
+ // → SessionFile.ownerPersonaId 派生(持久化兜底,daemon 重启后 subSessionMetaBySid 丢失时生效)
16802
+ // undefined(普通 session)
16803
+ resolveSubSessionMeta(file) {
16804
+ const cached = this.subSessionMetaBySid.get(file.sessionId);
16805
+ if (cached) return cached;
16806
+ if (file.ownerPersonaId) {
16807
+ return { idleKillEnabled: false, personaMode: "owner" };
16870
16808
  }
16871
- return false;
16809
+ return void 0;
16872
16810
  }
16873
16811
  // 创建 runner 时包一层 broadcast hook:所有外出 frame 统一走 routeFromRunner,
16874
- // 经过 compressFrameForWire 后决定是 push collector 还是走 deps.broadcastFrame
16875
- // scope 决定两件事:SessionStore 路由 + SubSessionMeta 派生(metaFromScope)。
16876
- // - default 复用 deps.store,无 subSessionMeta(普通 session)
16877
- // - persona/owner <dataDir>/sessions/<personaId>/owner/,meta={idleKillEnabled:false, personaMode:'owner'}
16878
- // - persona/listener <dataDir>/sessions/<personaId>/listener/,meta={idleKillEnabled:true, personaMode:'listener', extraSettings:<sandbox>}
16879
- newRunner(file, scope) {
16812
+ // 经过 compressFrameForWire 后决定是 push collector 还是走 deps.broadcastFrame
16813
+ // store:默认 deps.store;persona sub-session 路径下传该 personaId 对应的 SessionStore
16814
+ // subSessionMeta:listener { idleKillEnabled: true, personaMode: 'listener' };
16815
+ // owner { idleKillEnabled: false, personaMode: 'owner' };普通 session 不传
16816
+ newRunner(file, opts = {}) {
16880
16817
  const adapter = this.deps.getAdapter(file.tool ?? "claude");
16881
- const store = this.storeFor(scope);
16882
- const subSessionMeta = metaFromScope(scope, this.deps.personaRoot ?? "");
16883
- const runner = new SessionRunner(makeInitialState(file, subSessionMeta), {
16818
+ const store = opts.store ?? this.deps.store;
16819
+ const runner = new SessionRunner(makeInitialState(file, opts.subSessionMeta), {
16884
16820
  broadcastFrame: (frame, target) => this.routeFromRunner(frame, target),
16885
16821
  store,
16886
16822
  adapter,
@@ -16941,7 +16877,7 @@ var SessionManager = class {
16941
16877
  if (!this.deps.personaRoot) {
16942
16878
  throw new Error("personaRoot required to derive cwd from ownerPersonaId");
16943
16879
  }
16944
- cwd = import_node_path6.default.join(this.deps.personaRoot, safeFileName(args.ownerPersonaId));
16880
+ cwd = import_node_path5.default.join(this.deps.personaRoot, safeFileName(args.ownerPersonaId));
16945
16881
  }
16946
16882
  if (!cwd) {
16947
16883
  throw new ClawdError(ERROR_CODES.INVALID_CWD, "cwd required when ownerPersonaId is absent");
@@ -16971,8 +16907,13 @@ var SessionManager = class {
16971
16907
  createdAt: iso,
16972
16908
  updatedAt: iso
16973
16909
  };
16974
- const scope = args.ownerPersonaId ? { kind: "persona", personaId: args.ownerPersonaId, mode: "owner" } : { kind: "default" };
16975
- const written = this.storeFor(scope).write(file);
16910
+ const written = this.deps.store.write(file);
16911
+ if (args.ownerPersonaId) {
16912
+ this.subSessionMetaBySid.set(written.sessionId, {
16913
+ idleKillEnabled: false,
16914
+ personaMode: "owner"
16915
+ });
16916
+ }
16976
16917
  return { response: written, broadcast: [] };
16977
16918
  }
16978
16919
  pin(args) {
@@ -16987,13 +16928,13 @@ var SessionManager = class {
16987
16928
  return { response: value, broadcast };
16988
16929
  }
16989
16930
  const updated = { ...existing, pinnedAt };
16990
- this.writeOwned(updated);
16931
+ this.deps.store.write(updated);
16991
16932
  return { response: updated, broadcast: [] };
16992
16933
  }
16993
16934
  // sidebar 拖拽完成 → 整体重写 pinned root 的 pinSortOrder(按 orderedIds 下标 0,1,2...)
16994
16935
  // orderedIds 必须正好覆盖所有当前 pinned root(既不能漏,也不能含 unpinned id)
16995
16936
  reorderPins(args) {
16996
- const all = this.listAllOwned();
16937
+ const all = this.deps.store.list();
16997
16938
  const currentPinnedIds = new Set(
16998
16939
  all.filter((f) => typeof f.pinnedAt === "number").map((f) => f.sessionId)
16999
16940
  );
@@ -17023,14 +16964,14 @@ var SessionManager = class {
17023
16964
  } else {
17024
16965
  const existing = this.getFile(sessionId);
17025
16966
  const updated = { ...existing, pinSortOrder: index };
17026
- this.writeOwned(updated);
16967
+ this.deps.store.write(updated);
17027
16968
  updatedFiles.push(updated);
17028
16969
  }
17029
16970
  });
17030
16971
  return { response: { sessions: updatedFiles }, broadcast };
17031
16972
  }
17032
16973
  list() {
17033
- return { response: { sessions: this.listAllOwned() }, broadcast: [] };
16974
+ return { response: { sessions: this.deps.store.list() }, broadcast: [] };
17034
16975
  }
17035
16976
  get(args) {
17036
16977
  const file = this.getFile(args.sessionId);
@@ -17083,11 +17024,10 @@ var SessionManager = class {
17083
17024
  for (const [synth, real] of map) reverse.set(real, synth);
17084
17025
  return realUuids.map((r) => reverse.get(r) ?? r);
17085
17026
  }
17086
- // 内部帮手:不走 ManagerResult 的 get,直接拿 SessionFile
17087
- // 优先 runner cache(hot path);冷态走 findOwnedSession 跨 default + 所有 persona owner 扫盘。
17027
+ // 内部帮手:不走 ManagerResult 的 get,直接拿 SessionFile
17088
17028
  getFile(sessionId) {
17089
17029
  const runner = this.runners.get(sessionId);
17090
- const existing = runner?.getState().file ?? this.findOwnedSession(sessionId);
17030
+ const existing = runner?.getState().file ?? this.deps.store.read(sessionId);
17091
17031
  if (!existing) throw new ClawdError(ERROR_CODES.SESSION_NOT_FOUND, sessionId);
17092
17032
  return existing;
17093
17033
  }
@@ -17102,11 +17042,11 @@ var SessionManager = class {
17102
17042
  return { response: value, broadcast };
17103
17043
  }
17104
17044
  const updated = { ...existing, ...args.patch, updatedAt: nowIso2(this.deps) };
17105
- this.writeOwned(updated);
17045
+ this.deps.store.write(updated);
17106
17046
  return { response: updated, broadcast: [] };
17107
17047
  }
17108
17048
  delete(args) {
17109
- const existing = this.findOwnedSession(args.sessionId);
17049
+ const existing = this.deps.store.read(args.sessionId);
17110
17050
  if (!existing) throw new ClawdError(ERROR_CODES.SESSION_NOT_FOUND, args.sessionId);
17111
17051
  const runner = this.runners.get(args.sessionId);
17112
17052
  if (runner) {
@@ -17117,7 +17057,7 @@ var SessionManager = class {
17117
17057
  this.realUuidBySynth.delete(args.sessionId);
17118
17058
  return { response: { sessionId: args.sessionId }, broadcast };
17119
17059
  }
17120
- this.deleteOwned(args.sessionId);
17060
+ this.deps.store.delete(args.sessionId);
17121
17061
  return {
17122
17062
  response: { sessionId: args.sessionId },
17123
17063
  broadcast: [
@@ -17129,7 +17069,8 @@ var SessionManager = class {
17129
17069
  const existing = this.getFile(args.sessionId);
17130
17070
  let runner = this.runners.get(args.sessionId);
17131
17071
  if (!runner) {
17132
- runner = this.newRunner(existing, this.scopeForFile(existing));
17072
+ const subSessionMeta = this.resolveSubSessionMeta(existing);
17073
+ runner = this.newRunner(existing, { subSessionMeta });
17133
17074
  this.runners.set(args.sessionId, runner);
17134
17075
  }
17135
17076
  const { broadcast } = this.withCollector(() => {
@@ -17223,7 +17164,8 @@ var SessionManager = class {
17223
17164
  const file = this.getFile(args.sessionId);
17224
17165
  let runner = this.runners.get(args.sessionId);
17225
17166
  if (!runner) {
17226
- runner = this.newRunner(file, this.scopeForFile(file));
17167
+ const subSessionMeta = this.resolveSubSessionMeta(file);
17168
+ runner = this.newRunner(file, { subSessionMeta });
17227
17169
  this.runners.set(args.sessionId, runner);
17228
17170
  }
17229
17171
  if (!runner.getState().procAlive) {
@@ -17274,7 +17216,7 @@ var SessionManager = class {
17274
17216
  });
17275
17217
  return { response: value, broadcast };
17276
17218
  }
17277
- const existing = this.findOwnedSession(args.sessionId);
17219
+ const existing = this.deps.store.read(args.sessionId);
17278
17220
  const {
17279
17221
  toolSessionId: _drop,
17280
17222
  contextUsage: _ctx,
@@ -17289,7 +17231,7 @@ var SessionManager = class {
17289
17231
  void _branch;
17290
17232
  void _model;
17291
17233
  const updated = { ...rest, updatedAt: nowIso2(this.deps) };
17292
- return { response: this.writeOwned(updated), broadcast: [] };
17234
+ return { response: this.deps.store.write(updated), broadcast: [] };
17293
17235
  }
17294
17236
  resume(args) {
17295
17237
  this.getFile(args.sessionId);
@@ -17304,13 +17246,13 @@ var SessionManager = class {
17304
17246
  });
17305
17247
  return { response: value, broadcast };
17306
17248
  }
17307
- const existing = this.findOwnedSession(args.sessionId);
17249
+ const existing = this.deps.store.read(args.sessionId);
17308
17250
  const updated = {
17309
17251
  ...existing,
17310
17252
  toolSessionId: args.toolSessionId,
17311
17253
  updatedAt: nowIso2(this.deps)
17312
17254
  };
17313
- return { response: this.writeOwned(updated), broadcast: [] };
17255
+ return { response: this.deps.store.write(updated), broadcast: [] };
17314
17256
  }
17315
17257
  getEvents(args) {
17316
17258
  const runner = this.runners.get(args.sessionId);
@@ -17378,44 +17320,39 @@ var SessionManager = class {
17378
17320
  if (!runner) return "idle";
17379
17321
  return compressStatus(runner.getState().status);
17380
17322
  }
17381
- // 给 observer 用:保证有 runner 但不 spawn(仅创建 state 容器)。
17382
- // observer 喂事件路径只走 default + owner(普通 + owner persona session)
17383
- // ——listener sub-session 的 observer 路径走 ensureRunnerForScope。
17323
+ // 给 observer 用:保证有 runner 但不 spawn(仅创建 state 容器)
17384
17324
  ensureSession(file) {
17385
17325
  let r = this.runners.get(file.sessionId);
17386
17326
  if (r) return r;
17387
- r = this.newRunner(file, this.scopeForFile(file));
17327
+ const subSessionMeta = this.resolveSubSessionMeta(file);
17328
+ r = this.newRunner(file, { subSessionMeta });
17388
17329
  this.runners.set(file.sessionId, r);
17389
17330
  return r;
17390
17331
  }
17391
- // ---------------- persona / listener sub-session 专用 API ----------------
17332
+ // ---------------- persona / sub-session 专用 API ----------------
17392
17333
  //
17393
- // PersonaManager 是 SessionManager 之上的薄编排层,listener sub-session 的持久化
17394
- // (SessionFile)仍由 SessionManager 持有。区别于普通 / owner session:
17395
- // - SessionFile 落到 <dataDir>/sessions/<personaId>/listener/(拓扑分类)
17334
+ // PersonaManager 是 SessionManager 之上的薄编排层,sub-session 的持久化(SessionFile)
17335
+ // 仍由 SessionManager 持有。区别于普通 session:
17336
+ // - SessionFile 落到 <personaRoot>/<personaId>/.clawd/sub-sessions/ 而非 sessions/default/
17396
17337
  // - reducer state.subSessionMeta.idleKillEnabled = true(turn_end 自动 idle-kill)
17397
17338
  // - sessionId 由 PersonaManager 派生(personaId-<tokenHash>),不走自动 newSessionId
17398
- //
17399
- // 这些 API 接 SessionScope 参数(不再是单参 agentId)—— transport 始终明确传
17400
- // {kind:'persona', personaId, mode:'listener'},与 owner / default 分类隔离。
17401
- /** 按 scope 读取 SessionFile;不存在返回 null */
17402
- readForScope(sessionId, scope) {
17403
- return this.storeFor(scope).read(sessionId);
17339
+ /** 按 agentId 读取 SessionFile;不存在返回 null */
17340
+ readForAgent(sessionId, agentId) {
17341
+ return this.storeFor(agentId).read(sessionId);
17404
17342
  }
17405
17343
  /**
17406
- * 列出指定 persona 在指定 mode 下的所有 SessionFile。
17407
- * persona:listSubSessions RPC 入口(mode='listener');
17408
- * 路径下还未写过任何 session 时 list() 返回空数组(SessionStore.list 内部 ENOENT 处理)
17344
+ * agentId 列出该命名空间下所有 SessionFile(persona:listSubSessions 入口)。
17345
+ * agentId 还未访问过 → storeFor 第一次创建对应 SessionStore(root 不存在则 list 返回 [])
17409
17346
  */
17410
- listPersonaSessions(personaId, mode) {
17411
- return this.storeFor({ kind: "persona", personaId, mode }).list();
17347
+ listForAgent(agentId) {
17348
+ return this.storeFor(agentId).list();
17412
17349
  }
17413
17350
  /**
17414
17351
  * 创建 sub-session 的 SessionFile + 准备 runner(不 spawn)。
17415
- * SubSessionMeta 不进 SessionFile schema,运行时由 scope → metaFromScope 派生。
17416
- * 同一 sessionId 重复调用:抛错(PersonaManager 应先调 readForScope 命中复用)
17352
+ * subSessionMeta 不进 SessionFile schema,仅缓存进 runner state。
17353
+ * 同一 sessionId 重复调用:抛错(PersonaManager 应先调 readForAgent 命中复用)
17417
17354
  */
17418
- createForScope(args) {
17355
+ createForAgent(args) {
17419
17356
  try {
17420
17357
  const stat = import_node_fs5.default.statSync(args.cwd);
17421
17358
  if (!stat.isDirectory()) throw new Error("not dir");
@@ -17424,11 +17361,9 @@ var SessionManager = class {
17424
17361
  }
17425
17362
  const tool = args.tool ?? "claude";
17426
17363
  this.deps.getAdapter(tool);
17427
- const store = this.storeFor(args.scope);
17364
+ const store = this.storeFor(args.agentId);
17428
17365
  if (store.read(args.sessionId)) {
17429
- throw new Error(
17430
- `session already exists for scope ${scopeKey(args.scope)}: ${args.sessionId}`
17431
- );
17366
+ throw new Error(`session already exists for agent ${args.agentId}: ${args.sessionId}`);
17432
17367
  }
17433
17368
  const iso = nowIso2(this.deps);
17434
17369
  const file = {
@@ -17441,7 +17376,11 @@ var SessionManager = class {
17441
17376
  createdAt: iso,
17442
17377
  updatedAt: iso
17443
17378
  };
17444
- return store.write(file);
17379
+ const written = store.write(file);
17380
+ if (args.subSessionMeta) {
17381
+ this.subSessionMetaBySid.set(args.sessionId, args.subSessionMeta);
17382
+ }
17383
+ return written;
17445
17384
  }
17446
17385
  /**
17447
17386
  * persona-bound transport 用:读取 sub-session 的历史 ParsedEvent[]。
@@ -17452,21 +17391,22 @@ var SessionManager = class {
17452
17391
  * 不读 jsonl:
17453
17392
  * 1. observer 路径在 spawn 后会自动接管 jsonl 回灌,进 reducer buffer。
17454
17393
  * 2. 第一次握手时 sub-session 还没 spawn → toolSessionId 为空 → jsonl 不存在。
17455
- * sessionFile 不存在抛 SESSION_NOT_FOUND;上层应先调 createForScope
17394
+ * sessionFile 不存在抛 SESSION_NOT_FOUND;上层应先调 createForAgent
17456
17395
  */
17457
- readHistoryEventsForScope(sessionId, scope) {
17458
- const file = this.storeFor(scope).read(sessionId);
17396
+ readHistoryEvents(sessionId, agentId) {
17397
+ const store = this.storeFor(agentId);
17398
+ const file = store.read(sessionId);
17459
17399
  if (!file) {
17460
17400
  throw new ClawdError(
17461
17401
  ERROR_CODES.SESSION_NOT_FOUND,
17462
- `sub-session not found: ${scopeKey(scope)}/${sessionId}`
17402
+ `sub-session not found: ${agentId}/${sessionId}`
17463
17403
  );
17464
17404
  }
17465
- const runner = this.ensureRunnerForScope(file, scope);
17405
+ const runner = this.ensureRunnerFor(file, agentId);
17466
17406
  return runner.getState().buffer.map((e) => e.event);
17467
17407
  }
17468
17408
  /**
17469
- * persona-bound transport 用:基于 readHistoryEventsForScope 的 buffer 切片视图,支持分页。
17409
+ * persona-bound transport 用:基于 readHistoryEvents 的 buffer 切片视图,支持分页。
17470
17410
  *
17471
17411
  * Why a new method instead of reusing `history:read` RPC handler:
17472
17412
  * - `history:read` 走 HandlerDeps.history.read(),读 CC 写盘的 jsonl 文件
@@ -17474,15 +17414,18 @@ var SessionManager = class {
17474
17414
  * 两条路径数据形态、时序、字段不同,不能共享 helper。persona-bound 客户端必须
17475
17415
  * 走 buffer 路径,才能保证首屏回放和实时帧无 gap、无重复。
17476
17416
  *
17417
+ * Why not 改 readHistoryEvents 加 limit/offset:现有 readHistoryEvents 的语义是
17418
+ * "返回 buffer 全部",被其它路径(rewind uuid 转译等)依赖;保留它不动,新加分页方法。
17419
+ *
17477
17420
  * 切片语义:clip 安全边界,response.offset 保留请求值便于客户端识别越界请求。
17478
17421
  * - offset >= total → events: [], offset: 请求值, total: 当前 buffer 长度
17479
17422
  * - offset + limit > total → 返回 tail [offset, total),长度 = total - offset
17480
17423
  * - 正常 → 返回 [offset, offset + limit)
17481
17424
  *
17482
- * SESSION_NOT_FOUND 行为继承 readHistoryEventsForScope(store.read 返回 null 即抛)。
17425
+ * SESSION_NOT_FOUND 行为继承 readHistoryEvents(store.read 返回 null 即抛)。
17483
17426
  */
17484
- readHistoryPageForScope(sessionId, scope, limit, offset) {
17485
- const all = this.readHistoryEventsForScope(sessionId, scope);
17427
+ readHistoryPage(sessionId, agentId, limit, offset) {
17428
+ const all = this.readHistoryEvents(sessionId, agentId);
17486
17429
  const total = all.length;
17487
17430
  const start = Math.min(offset, total);
17488
17431
  const end = Math.min(start + limit, total);
@@ -17495,34 +17438,36 @@ var SessionManager = class {
17495
17438
  * 返回 unsubscribe;不破坏现有 wire 广播路径——routeFromRunner 同时 fan-out 到
17496
17439
  * eventSubscribers 和 deps.broadcastFrame
17497
17440
  */
17498
- subscribe(sessionId, _scope, listener) {
17499
- let subs = this.eventSubscribers.get(sessionId);
17441
+ subscribe(_sessionId, _agentId, listener) {
17442
+ const sid = _sessionId;
17443
+ let subs = this.eventSubscribers.get(sid);
17500
17444
  if (!subs) {
17501
17445
  subs = /* @__PURE__ */ new Set();
17502
- this.eventSubscribers.set(sessionId, subs);
17446
+ this.eventSubscribers.set(sid, subs);
17503
17447
  }
17504
17448
  subs.add(listener);
17505
17449
  return () => {
17506
- const cur = this.eventSubscribers.get(sessionId);
17450
+ const cur = this.eventSubscribers.get(sid);
17507
17451
  if (!cur) return;
17508
17452
  cur.delete(listener);
17509
- if (cur.size === 0) this.eventSubscribers.delete(sessionId);
17453
+ if (cur.size === 0) this.eventSubscribers.delete(sid);
17510
17454
  };
17511
17455
  }
17512
17456
  /**
17513
- * persona-bound transport 用:sub-session 路径的 send(按 scope 路由 SessionStore)。
17514
- * 区别于 default scope SessionManager.send:transport hello 已知 personaId 和 mode,
17515
- * 显式传 scope 避免跨命名空间 sessionId 撞车。
17457
+ * persona-bound transport 用:sub-session 路径的 send(按 agentId 路由 SessionStore)。
17458
+ * 现状 send(args.sessionId, args.text) 默认 'default' agent;这里按 agentId 拿对应 store
17459
+ * + ensureRunnerFor 保证 runner 用同一个 store 写盘
17516
17460
  */
17517
- sendForScope(args) {
17518
- const file = this.storeFor(args.scope).read(args.sessionId);
17461
+ sendForAgent(args) {
17462
+ const store = this.storeFor(args.agentId);
17463
+ const file = store.read(args.sessionId);
17519
17464
  if (!file) {
17520
17465
  throw new ClawdError(
17521
17466
  ERROR_CODES.SESSION_NOT_FOUND,
17522
- `sub-session not found: ${scopeKey(args.scope)}/${args.sessionId}`
17467
+ `sub-session not found: ${args.agentId}/${args.sessionId}`
17523
17468
  );
17524
17469
  }
17525
- const runner = this.ensureRunnerForScope(file, args.scope);
17470
+ const runner = this.ensureRunnerFor(file, args.agentId);
17526
17471
  const { broadcast } = this.withCollector(() => {
17527
17472
  runner.input({ kind: "command", command: { kind: "send", text: args.text } });
17528
17473
  });
@@ -17532,47 +17477,53 @@ var SessionManager = class {
17532
17477
  * persona-bound transport 用:sub-session reset。
17533
17478
  * 复用 reducer 'new' 命令:清 toolSessionId / buffer / nextSeq / pending* + kill proc + emit
17534
17479
  * session:cleared。语义上等价 alice 端"清空当前会话上下文"。
17535
- * 归档已写盘的 jsonl 不在本路径处理(CC 后续 spawn 会写新的 toolSessionId.jsonl,旧的留盘)。
17480
+ * 归档已写盘的 jsonl 不在本路径处理(CC 后续 spawn 会写新的 toolSessionId.jsonl,旧的留盘);
17481
+ * 物理归档可在后续单独 task 加(spec § 6 待 plan 决定项)。
17536
17482
  */
17537
- resetForScope(args) {
17538
- const file = this.storeFor(args.scope).read(args.sessionId);
17483
+ resetForAgent(args) {
17484
+ const store = this.storeFor(args.agentId);
17485
+ const file = store.read(args.sessionId);
17539
17486
  if (!file) {
17540
17487
  throw new ClawdError(
17541
17488
  ERROR_CODES.SESSION_NOT_FOUND,
17542
- `sub-session not found: ${scopeKey(args.scope)}/${args.sessionId}`
17489
+ `sub-session not found: ${args.agentId}/${args.sessionId}`
17543
17490
  );
17544
17491
  }
17545
- const runner = this.ensureRunnerForScope(file, args.scope);
17492
+ const runner = this.ensureRunnerFor(file, args.agentId);
17546
17493
  const { broadcast } = this.withCollector(() => {
17547
17494
  runner.input({ kind: "command", command: { kind: "new" } });
17548
17495
  });
17549
17496
  return { response: { ok: true }, broadcast };
17550
17497
  }
17551
- /** ensureSession 的 scope-aware 版本:复用现有 runner 或按 scope 创建(含 metaFromScope 派生 meta) */
17552
- ensureRunnerForScope(file, scope) {
17498
+ /** ensureSession 的 agentId-aware 版本:复用现有 runner 或按 agentId 派生 store 创建 */
17499
+ ensureRunnerFor(file, agentId) {
17553
17500
  const existing = this.runners.get(file.sessionId);
17554
17501
  if (existing) return existing;
17555
- const runner = this.newRunner(file, scope);
17502
+ const store = this.storeFor(agentId);
17503
+ const subSessionMeta = this.resolveSubSessionMeta(file);
17504
+ const runner = this.newRunner(file, { store, subSessionMeta });
17556
17505
  this.runners.set(file.sessionId, runner);
17557
17506
  return runner;
17558
17507
  }
17559
17508
  /**
17560
17509
  * 老板插话:把 'inject-owner-text' input 喂给对应 runner,
17561
- * runner 不存在时按 scope 懒创建。
17510
+ * runner 不存在时按 ensureSession 路径懒创建(以 subSessionMeta 缓存为准)。
17562
17511
  * frames 走异步路径(broadcastFrame):调用方一般在 PersonaManager.appendOwnerMessage
17563
17512
  * 内部走 RPC 处理流,没有同步 collector 上下文
17564
17513
  */
17565
17514
  injectOwnerMessage(args) {
17566
- const file = this.storeFor(args.scope).read(args.sessionId);
17515
+ const store = this.storeFor(args.agentId);
17516
+ const file = store.read(args.sessionId);
17567
17517
  if (!file) {
17568
17518
  throw new ClawdError(
17569
17519
  ERROR_CODES.SESSION_NOT_FOUND,
17570
- `sub-session not found: ${scopeKey(args.scope)}/${args.sessionId}`
17520
+ `sub-session not found: ${args.agentId}/${args.sessionId}`
17571
17521
  );
17572
17522
  }
17573
17523
  let runner = this.runners.get(args.sessionId);
17574
17524
  if (!runner) {
17575
- runner = this.newRunner(file, args.scope);
17525
+ const subSessionMeta = this.resolveSubSessionMeta(file);
17526
+ runner = this.newRunner(file, { store, subSessionMeta });
17576
17527
  this.runners.set(args.sessionId, runner);
17577
17528
  }
17578
17529
  runner.input({ kind: "inject-owner-text", text: args.text });
@@ -17668,7 +17619,7 @@ var SessionManager = class {
17668
17619
 
17669
17620
  // src/persona/store.ts
17670
17621
  var fs6 = __toESM(require("fs"), 1);
17671
- var path7 = __toESM(require("path"), 1);
17622
+ var path6 = __toESM(require("path"), 1);
17672
17623
  init_protocol();
17673
17624
  var DEFAULT_SETTINGS = {
17674
17625
  permissions: {
@@ -17697,13 +17648,13 @@ var PersonaStore = class {
17697
17648
  }
17698
17649
  root;
17699
17650
  personaDir(personaId) {
17700
- return path7.join(this.root, safeFileName(personaId));
17651
+ return path6.join(this.root, safeFileName(personaId));
17701
17652
  }
17702
17653
  metaPath(personaId) {
17703
- return path7.join(this.personaDir(personaId), ".clawd", "persona.json");
17654
+ return path6.join(this.personaDir(personaId), ".clawd", "persona.json");
17704
17655
  }
17705
17656
  claudeMdPath(personaId) {
17706
- return path7.join(this.personaDir(personaId), "CLAUDE.md");
17657
+ return path6.join(this.personaDir(personaId), "CLAUDE.md");
17707
17658
  }
17708
17659
  /**
17709
17660
  * Sandbox settings 落盘路径 —— 故意放在 `.clawd/` 而不是 `.claude/`,让 CC 的
@@ -17713,11 +17664,11 @@ var PersonaStore = class {
17713
17664
  * 加载 persona 人格,只有 listener 多一层 OS sandbox。
17714
17665
  */
17715
17666
  sandboxSettingsPath(personaId) {
17716
- return path7.join(this.personaDir(personaId), ".clawd", "sandbox-settings.json");
17667
+ return path6.join(this.personaDir(personaId), ".clawd", "sandbox-settings.json");
17717
17668
  }
17718
17669
  write(persona, personality) {
17719
17670
  const dir = this.personaDir(persona.personaId);
17720
- fs6.mkdirSync(path7.join(dir, ".clawd"), { recursive: true });
17671
+ fs6.mkdirSync(path6.join(dir, ".clawd"), { recursive: true });
17721
17672
  this.atomicWrite(this.claudeMdPath(persona.personaId), personality);
17722
17673
  this.atomicWrite(
17723
17674
  this.sandboxSettingsPath(persona.personaId),
@@ -17748,7 +17699,7 @@ var PersonaStore = class {
17748
17699
  list() {
17749
17700
  if (!fs6.existsSync(this.root)) return [];
17750
17701
  return fs6.readdirSync(this.root).filter((name) => {
17751
- return fs6.existsSync(path7.join(this.root, name, ".clawd", "persona.json"));
17702
+ return fs6.existsSync(path6.join(this.root, name, ".clawd", "persona.json"));
17752
17703
  });
17753
17704
  }
17754
17705
  remove(personaId) {
@@ -17910,20 +17861,27 @@ var PersonaManager = class {
17910
17861
  const persona = this.deps.registry.get(personaId);
17911
17862
  if (!persona) throw new Error(`persona not found: ${personaId}`);
17912
17863
  const subSessionId = this.deriveSubSessionId(personaId, token);
17913
- const scope = { kind: "persona", personaId, mode: "listener" };
17914
- const existing = this.deps.sessionManager.readForScope(subSessionId, scope);
17864
+ const existing = this.deps.sessionManager.readForAgent(subSessionId, personaId);
17915
17865
  if (existing) {
17916
17866
  return { sessionFile: existing, isNew: false };
17917
17867
  }
17918
17868
  const tokenEntry = persona.tokenMap[token];
17919
17869
  const subLabel = tokenEntry?.label ?? "unknown";
17920
- const sessionFile = this.deps.sessionManager.createForScope({
17870
+ const sessionFile = this.deps.sessionManager.createForAgent({
17921
17871
  sessionId: subSessionId,
17922
- scope,
17872
+ agentId: personaId,
17923
17873
  cwd: this.deps.store.personaDirPath(personaId),
17924
17874
  tool: "claude",
17925
17875
  label: subLabel,
17926
- model: persona.model
17876
+ model: persona.model,
17877
+ // listener 走 OS sandbox:sandbox JSON 不在 project 自动发现路径上(PersonaStore 把它
17878
+ // 落在 .clawd/sandbox-settings.json),靠 extraSettings 透传到 spawn 的 `--settings <file>`
17879
+ // 显式拉回。owner 路径不传 extraSettings,天然无 sandbox。
17880
+ subSessionMeta: {
17881
+ idleKillEnabled: true,
17882
+ personaMode: "listener",
17883
+ extraSettings: this.deps.store.sandboxSettingsPath(personaId)
17884
+ }
17927
17885
  });
17928
17886
  return { sessionFile, isNew: true };
17929
17887
  }
@@ -17934,7 +17892,7 @@ var PersonaManager = class {
17934
17892
  appendOwnerMessage(personaId, subSessionId, text) {
17935
17893
  this.deps.sessionManager.injectOwnerMessage({
17936
17894
  sessionId: subSessionId,
17937
- scope: { kind: "persona", personaId, mode: "listener" },
17895
+ agentId: personaId,
17938
17896
  text
17939
17897
  });
17940
17898
  }
@@ -17963,7 +17921,7 @@ var PersonaManager = class {
17963
17921
 
17964
17922
  // src/persona/seed.ts
17965
17923
  var fs7 = __toESM(require("fs"), 1);
17966
- var path8 = __toESM(require("path"), 1);
17924
+ var path7 = __toESM(require("path"), 1);
17967
17925
  var import_node_url = require("url");
17968
17926
  var import_meta = {};
17969
17927
  var DEFAULT_PERSONAS = [
@@ -17980,19 +17938,26 @@ var DEFAULT_PERSONAS = [
17980
17938
  model: "opus",
17981
17939
  iconKey: "reading",
17982
17940
  public: false
17941
+ },
17942
+ {
17943
+ personaId: "persona-clawd-helper",
17944
+ label: "clawd\u4F7F\u7528\u52A9\u624B",
17945
+ model: "opus",
17946
+ iconKey: "assist",
17947
+ public: false
17983
17948
  }
17984
17949
  ];
17985
17950
  function findDefaultsRoot() {
17986
17951
  const candidates = [];
17987
17952
  try {
17988
- const here = path8.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
17989
- candidates.push(path8.resolve(here, "defaults"));
17990
- candidates.push(path8.resolve(here, "persona-defaults"));
17953
+ const here = path7.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
17954
+ candidates.push(path7.resolve(here, "defaults"));
17955
+ candidates.push(path7.resolve(here, "persona-defaults"));
17991
17956
  } catch {
17992
17957
  }
17993
17958
  if (process.argv[1]) {
17994
- const argvDir = path8.dirname(process.argv[1]);
17995
- candidates.push(path8.resolve(argvDir, "persona-defaults"));
17959
+ const argvDir = path7.dirname(process.argv[1]);
17960
+ candidates.push(path7.resolve(argvDir, "persona-defaults"));
17996
17961
  }
17997
17962
  for (const c of candidates) {
17998
17963
  try {
@@ -18009,7 +17974,7 @@ function seedDefaultPersonas(args) {
18009
17974
  args.logger.info("persona.seed.skip", { personaId: entry.personaId, reason: "exists" });
18010
17975
  continue;
18011
17976
  }
18012
- const bundleDir = path8.join(args.defaultsRoot, entry.personaId);
17977
+ const bundleDir = path7.join(args.defaultsRoot, entry.personaId);
18013
17978
  if (!fs7.existsSync(bundleDir)) {
18014
17979
  args.logger.warn("persona.seed.skip", {
18015
17980
  personaId: entry.personaId,
@@ -18018,7 +17983,7 @@ function seedDefaultPersonas(args) {
18018
17983
  });
18019
17984
  continue;
18020
17985
  }
18021
- const claudeMdPath = path8.join(bundleDir, "CLAUDE.md");
17986
+ const claudeMdPath = path7.join(bundleDir, "CLAUDE.md");
18022
17987
  if (!fs7.existsSync(claudeMdPath)) {
18023
17988
  args.logger.warn("persona.seed.skip", {
18024
17989
  personaId: entry.personaId,
@@ -18047,8 +18012,8 @@ function seedDefaultPersonas(args) {
18047
18012
  function copyBundleExtras(srcDir, dstDir) {
18048
18013
  for (const entry of fs7.readdirSync(srcDir, { withFileTypes: true })) {
18049
18014
  if (entry.name === "CLAUDE.md" || entry.name === ".clawd") continue;
18050
- const srcPath = path8.join(srcDir, entry.name);
18051
- const dstPath = path8.join(dstDir, entry.name);
18015
+ const srcPath = path7.join(srcDir, entry.name);
18016
+ const dstPath = path7.join(dstDir, entry.name);
18052
18017
  if (entry.isDirectory()) {
18053
18018
  fs7.cpSync(srcPath, dstPath, { recursive: true, dereference: true });
18054
18019
  } else if (entry.isFile()) {
@@ -18064,14 +18029,14 @@ init_claude_history();
18064
18029
  // src/workspace/browser.ts
18065
18030
  var import_node_fs8 = __toESM(require("fs"), 1);
18066
18031
  var import_node_os4 = __toESM(require("os"), 1);
18067
- var import_node_path9 = __toESM(require("path"), 1);
18032
+ var import_node_path8 = __toESM(require("path"), 1);
18068
18033
  init_protocol();
18069
18034
  var MAX_FILE_BYTES = 2 * 1024 * 1024;
18070
18035
  function resolveInsideCwd(cwd, subpath) {
18071
- const absCwd = import_node_path9.default.resolve(cwd);
18072
- const joined = import_node_path9.default.resolve(absCwd, subpath ?? ".");
18073
- const rel = import_node_path9.default.relative(absCwd, joined);
18074
- if (rel.startsWith("..") || import_node_path9.default.isAbsolute(rel)) {
18036
+ const absCwd = import_node_path8.default.resolve(cwd);
18037
+ const joined = import_node_path8.default.resolve(absCwd, subpath ?? ".");
18038
+ const rel = import_node_path8.default.relative(absCwd, joined);
18039
+ if (rel.startsWith("..") || import_node_path8.default.isAbsolute(rel)) {
18075
18040
  throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
18076
18041
  }
18077
18042
  return joined;
@@ -18102,7 +18067,7 @@ var WorkspaceBrowser = class {
18102
18067
  mtime: ""
18103
18068
  };
18104
18069
  try {
18105
- const st = import_node_fs8.default.statSync(import_node_path9.default.join(full, d.name));
18070
+ const st = import_node_fs8.default.statSync(import_node_path8.default.join(full, d.name));
18106
18071
  entry.mtime = new Date(st.mtimeMs).toISOString();
18107
18072
  if (d.isFile()) entry.size = st.size;
18108
18073
  } catch {
@@ -18149,7 +18114,7 @@ var WorkspaceBrowser = class {
18149
18114
  // src/skills/scanner.ts
18150
18115
  var import_node_fs9 = __toESM(require("fs"), 1);
18151
18116
  var import_node_os5 = __toESM(require("os"), 1);
18152
- var import_node_path10 = __toESM(require("path"), 1);
18117
+ var import_node_path9 = __toESM(require("path"), 1);
18153
18118
 
18154
18119
  // src/skills/frontmatter.ts
18155
18120
  var STRIP_QUOTES = /^["']|["']$/g;
@@ -18271,14 +18236,14 @@ function scanSkillDir(dir, source, seen, out, pluginName) {
18271
18236
  return;
18272
18237
  }
18273
18238
  for (const ent of entries) {
18274
- const entryPath = import_node_path10.default.join(dir, ent.name);
18239
+ const entryPath = import_node_path9.default.join(dir, ent.name);
18275
18240
  if (!ent.isDirectory() && !(ent.isSymbolicLink() && isDirLikeSync(entryPath))) continue;
18276
18241
  let content;
18277
18242
  try {
18278
- content = import_node_fs9.default.readFileSync(import_node_path10.default.join(entryPath, "SKILL.md"), "utf8");
18243
+ content = import_node_fs9.default.readFileSync(import_node_path9.default.join(entryPath, "SKILL.md"), "utf8");
18279
18244
  } catch {
18280
18245
  try {
18281
- content = import_node_fs9.default.readFileSync(import_node_path10.default.join(entryPath, "skill.md"), "utf8");
18246
+ content = import_node_fs9.default.readFileSync(import_node_path9.default.join(entryPath, "skill.md"), "utf8");
18282
18247
  } catch {
18283
18248
  continue;
18284
18249
  }
@@ -18301,7 +18266,7 @@ function scanCommandDir(dir, source, seen, out, pluginName) {
18301
18266
  return;
18302
18267
  }
18303
18268
  for (const ent of entries) {
18304
- const entryPath = import_node_path10.default.join(dir, ent.name);
18269
+ const entryPath = import_node_path9.default.join(dir, ent.name);
18305
18270
  if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync(entryPath)) {
18306
18271
  const ns = ent.name;
18307
18272
  let subEntries;
@@ -18312,7 +18277,7 @@ function scanCommandDir(dir, source, seen, out, pluginName) {
18312
18277
  }
18313
18278
  for (const se of subEntries) {
18314
18279
  if (!se.name.endsWith(".md")) continue;
18315
- const sePath = import_node_path10.default.join(entryPath, se.name);
18280
+ const sePath = import_node_path9.default.join(entryPath, se.name);
18316
18281
  let content;
18317
18282
  try {
18318
18283
  content = import_node_fs9.default.readFileSync(sePath, "utf8");
@@ -18348,7 +18313,7 @@ function scanCommandDir(dir, source, seen, out, pluginName) {
18348
18313
  }
18349
18314
  }
18350
18315
  function readInstalledPlugins(home) {
18351
- const file = import_node_path10.default.join(home, ".claude", "plugins", "installed_plugins.json");
18316
+ const file = import_node_path9.default.join(home, ".claude", "plugins", "installed_plugins.json");
18352
18317
  let raw;
18353
18318
  try {
18354
18319
  raw = import_node_fs9.default.readFileSync(file, "utf8");
@@ -18399,14 +18364,14 @@ var SkillsScanner = class {
18399
18364
  });
18400
18365
  }
18401
18366
  const fsBlock = [];
18402
- scanSkillDir(import_node_path10.default.join(this.home, ".claude", "skills"), "global", seen, fsBlock);
18403
- scanCommandDir(import_node_path10.default.join(this.home, ".claude", "commands"), "global", seen, fsBlock);
18404
- scanSkillDir(import_node_path10.default.join(args.cwd, ".claude", "skills"), "project", seen, fsBlock);
18405
- scanCommandDir(import_node_path10.default.join(args.cwd, ".claude", "commands"), "project", seen, fsBlock);
18367
+ scanSkillDir(import_node_path9.default.join(this.home, ".claude", "skills"), "global", seen, fsBlock);
18368
+ scanCommandDir(import_node_path9.default.join(this.home, ".claude", "commands"), "global", seen, fsBlock);
18369
+ scanSkillDir(import_node_path9.default.join(args.cwd, ".claude", "skills"), "project", seen, fsBlock);
18370
+ scanCommandDir(import_node_path9.default.join(args.cwd, ".claude", "commands"), "project", seen, fsBlock);
18406
18371
  const plugins = [...readInstalledPlugins(this.home), ...this.extraPluginRoots];
18407
18372
  for (const { name, root } of plugins) {
18408
- scanSkillDir(import_node_path10.default.join(root, "skills"), "plugin", seen, fsBlock, name);
18409
- scanCommandDir(import_node_path10.default.join(root, "commands"), "plugin", seen, fsBlock, name);
18373
+ scanSkillDir(import_node_path9.default.join(root, "skills"), "plugin", seen, fsBlock, name);
18374
+ scanCommandDir(import_node_path9.default.join(root, "commands"), "plugin", seen, fsBlock, name);
18410
18375
  }
18411
18376
  fsBlock.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
18412
18377
  return [...builtinBlock, ...fsBlock];
@@ -18416,7 +18381,7 @@ var SkillsScanner = class {
18416
18381
  // src/skills/agents-scanner.ts
18417
18382
  var import_node_fs10 = __toESM(require("fs"), 1);
18418
18383
  var import_node_os6 = __toESM(require("os"), 1);
18419
- var import_node_path11 = __toESM(require("path"), 1);
18384
+ var import_node_path10 = __toESM(require("path"), 1);
18420
18385
  var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
18421
18386
  function isDirLikeSync2(p) {
18422
18387
  try {
@@ -18454,10 +18419,10 @@ function scanAgentsDir(dir, source, seen, out) {
18454
18419
  }
18455
18420
  for (const ent of entries) {
18456
18421
  if (!ent.name.endsWith(".md")) continue;
18457
- if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path11.default.join(dir, ent.name)))) {
18422
+ if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path10.default.join(dir, ent.name)))) {
18458
18423
  continue;
18459
18424
  }
18460
- const filePath = import_node_path11.default.join(dir, ent.name);
18425
+ const filePath = import_node_path10.default.join(dir, ent.name);
18461
18426
  const baseName = ent.name.replace(/\.md$/, "");
18462
18427
  if (seen.has(baseName)) continue;
18463
18428
  seen.add(baseName);
@@ -18480,7 +18445,7 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
18480
18445
  return;
18481
18446
  }
18482
18447
  for (const ent of entries) {
18483
- const childPath = import_node_path11.default.join(dir, ent.name);
18448
+ const childPath = import_node_path10.default.join(dir, ent.name);
18484
18449
  if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
18485
18450
  walk(childPath, [...namespaces, ent.name]);
18486
18451
  continue;
@@ -18505,9 +18470,9 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
18505
18470
  walk(root, []);
18506
18471
  }
18507
18472
  function readInstalledPlugins2(home) {
18508
- const pluginsDir = import_node_path11.default.join(home, ".claude", "plugins");
18509
- const v2 = import_node_path11.default.join(pluginsDir, "installed_plugins_v2.json");
18510
- const v1 = import_node_path11.default.join(pluginsDir, "installed_plugins.json");
18473
+ const pluginsDir = import_node_path10.default.join(home, ".claude", "plugins");
18474
+ const v2 = import_node_path10.default.join(pluginsDir, "installed_plugins_v2.json");
18475
+ const v1 = import_node_path10.default.join(pluginsDir, "installed_plugins.json");
18511
18476
  let raw = null;
18512
18477
  for (const candidate of [v2, v1]) {
18513
18478
  try {
@@ -18536,19 +18501,19 @@ function readInstalledPlugins2(home) {
18536
18501
  return out;
18537
18502
  }
18538
18503
  function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
18539
- let cur = import_node_path11.default.resolve(startCwd);
18540
- const fsRoot = import_node_path11.default.parse(cur).root;
18504
+ let cur = import_node_path10.default.resolve(startCwd);
18505
+ const fsRoot = import_node_path10.default.parse(cur).root;
18541
18506
  while (true) {
18542
- scanAgentsDir(import_node_path11.default.join(cur, ".claude", "agents"), "project", seen, out);
18507
+ scanAgentsDir(import_node_path10.default.join(cur, ".claude", "agents"), "project", seen, out);
18543
18508
  let hasGit = false;
18544
18509
  try {
18545
- hasGit = import_node_fs10.default.existsSync(import_node_path11.default.join(cur, ".git"));
18510
+ hasGit = import_node_fs10.default.existsSync(import_node_path10.default.join(cur, ".git"));
18546
18511
  } catch {
18547
18512
  }
18548
18513
  if (hasGit) return;
18549
18514
  if (cur === home) return;
18550
18515
  if (cur === fsRoot) return;
18551
- const parent = import_node_path11.default.dirname(cur);
18516
+ const parent = import_node_path10.default.dirname(cur);
18552
18517
  if (parent === cur) return;
18553
18518
  cur = parent;
18554
18519
  }
@@ -18583,7 +18548,7 @@ var AgentsScanner = class {
18583
18548
  }
18584
18549
  const fsBlock = [];
18585
18550
  scanAgentsDir(
18586
- import_node_path11.default.join(this.home, ".claude", "agents"),
18551
+ import_node_path10.default.join(this.home, ".claude", "agents"),
18587
18552
  "global",
18588
18553
  seen,
18589
18554
  fsBlock
@@ -18597,7 +18562,7 @@ var AgentsScanner = class {
18597
18562
  ...this.extraPluginRoots
18598
18563
  ];
18599
18564
  for (const { name, root } of plugins) {
18600
- const agentsRoot = import_node_path11.default.join(root, "agents");
18565
+ const agentsRoot = import_node_path10.default.join(root, "agents");
18601
18566
  scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
18602
18567
  }
18603
18568
  return [...builtinBlock, ...fsBlock];
@@ -18607,7 +18572,7 @@ var AgentsScanner = class {
18607
18572
  // src/observer/session-observer.ts
18608
18573
  var import_node_fs11 = __toESM(require("fs"), 1);
18609
18574
  var import_node_os7 = __toESM(require("os"), 1);
18610
- var import_node_path12 = __toESM(require("path"), 1);
18575
+ var import_node_path11 = __toESM(require("path"), 1);
18611
18576
  init_claude_history();
18612
18577
  var SessionObserver = class {
18613
18578
  constructor(opts) {
@@ -18619,7 +18584,7 @@ var SessionObserver = class {
18619
18584
  watches = /* @__PURE__ */ new Map();
18620
18585
  resolveJsonlPath(cwd, toolSessionId, override) {
18621
18586
  if (override) return override;
18622
- return import_node_path12.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
18587
+ return import_node_path11.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
18623
18588
  }
18624
18589
  start(args) {
18625
18590
  this.stop(args.sessionId);
@@ -18639,10 +18604,10 @@ var SessionObserver = class {
18639
18604
  adapter: args.adapter
18640
18605
  };
18641
18606
  try {
18642
- import_node_fs11.default.mkdirSync(import_node_path12.default.dirname(filePath), { recursive: true });
18607
+ import_node_fs11.default.mkdirSync(import_node_path11.default.dirname(filePath), { recursive: true });
18643
18608
  } catch {
18644
18609
  }
18645
- w.watcher = import_node_fs11.default.watch(import_node_path12.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
18610
+ w.watcher = import_node_fs11.default.watch(import_node_path11.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
18646
18611
  if (!changedName || !filePath.endsWith(changedName)) return;
18647
18612
  this.poll(w);
18648
18613
  });
@@ -19158,18 +19123,13 @@ var PersonaBoundHandler = class {
19158
19123
  }
19159
19124
  return true;
19160
19125
  };
19161
- const listenerScope = () => ({
19162
- kind: "persona",
19163
- personaId: scope.personaId,
19164
- mode: "listener"
19165
- });
19166
19126
  switch (type) {
19167
19127
  case "session:subscribe": {
19168
19128
  if (!requireScopedSession()) return;
19169
19129
  if (unsubscribe) unsubscribe();
19170
19130
  unsubscribe = this.deps.sessionManager.subscribe(
19171
19131
  scope.subSessionId,
19172
- listenerScope(),
19132
+ scope.personaId,
19173
19133
  (eventFrame) => send(eventFrame)
19174
19134
  );
19175
19135
  if (requestId)
@@ -19199,9 +19159,9 @@ var PersonaBoundHandler = class {
19199
19159
  return;
19200
19160
  }
19201
19161
  try {
19202
- this.deps.sessionManager.sendForScope({
19162
+ this.deps.sessionManager.sendForAgent({
19203
19163
  sessionId: scope.subSessionId,
19204
- scope: listenerScope(),
19164
+ agentId: scope.personaId,
19205
19165
  text
19206
19166
  });
19207
19167
  if (requestId) send({ type: "session:send", ok: true, requestId });
@@ -19214,9 +19174,9 @@ var PersonaBoundHandler = class {
19214
19174
  case "session:new": {
19215
19175
  if (!requireScopedSession()) return;
19216
19176
  try {
19217
- this.deps.sessionManager.resetForScope({
19177
+ this.deps.sessionManager.resetForAgent({
19218
19178
  sessionId: scope.subSessionId,
19219
- scope: listenerScope()
19179
+ agentId: scope.personaId
19220
19180
  });
19221
19181
  if (requestId) send({ type: "session:info", sessionId: scope.subSessionId, requestId });
19222
19182
  } catch (err) {
@@ -19230,9 +19190,9 @@ var PersonaBoundHandler = class {
19230
19190
  const limit = typeof frame.limit === "number" && frame.limit > 0 ? frame.limit : 50;
19231
19191
  const offset = typeof frame.offset === "number" && frame.offset >= 0 ? frame.offset : 0;
19232
19192
  try {
19233
- const page = this.deps.sessionManager.readHistoryPageForScope(
19193
+ const page = this.deps.sessionManager.readHistoryPage(
19234
19194
  scope.subSessionId,
19235
- listenerScope(),
19195
+ scope.personaId,
19236
19196
  limit,
19237
19197
  offset
19238
19198
  );
@@ -19363,9 +19323,9 @@ function isLocalhost(addr) {
19363
19323
 
19364
19324
  // src/discovery/state-file.ts
19365
19325
  var import_node_fs12 = __toESM(require("fs"), 1);
19366
- var import_node_path13 = __toESM(require("path"), 1);
19326
+ var import_node_path12 = __toESM(require("path"), 1);
19367
19327
  function defaultStateFilePath(dataDir) {
19368
- return import_node_path13.default.join(dataDir, "state.json");
19328
+ return import_node_path12.default.join(dataDir, "state.json");
19369
19329
  }
19370
19330
  function isPidAlive(pid) {
19371
19331
  if (!Number.isFinite(pid) || pid <= 0) return false;
@@ -19401,7 +19361,7 @@ var StateFileManager = class {
19401
19361
  return { status: "stale", existing };
19402
19362
  }
19403
19363
  write(state) {
19404
- import_node_fs12.default.mkdirSync(import_node_path13.default.dirname(this.file), { recursive: true });
19364
+ import_node_fs12.default.mkdirSync(import_node_path12.default.dirname(this.file), { recursive: true });
19405
19365
  const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
19406
19366
  import_node_fs12.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
19407
19367
  import_node_fs12.default.renameSync(tmp, this.file);
@@ -19422,13 +19382,13 @@ var StateFileManager = class {
19422
19382
 
19423
19383
  // src/tunnel/tunnel-manager.ts
19424
19384
  var import_node_fs15 = __toESM(require("fs"), 1);
19425
- var import_node_path16 = __toESM(require("path"), 1);
19385
+ var import_node_path15 = __toESM(require("path"), 1);
19426
19386
  var import_node_crypto4 = __toESM(require("crypto"), 1);
19427
19387
  var import_node_child_process4 = require("child_process");
19428
19388
 
19429
19389
  // src/tunnel/tunnel-store.ts
19430
19390
  var import_node_fs13 = __toESM(require("fs"), 1);
19431
- var import_node_path14 = __toESM(require("path"), 1);
19391
+ var import_node_path13 = __toESM(require("path"), 1);
19432
19392
  var TunnelStore = class {
19433
19393
  constructor(filePath) {
19434
19394
  this.filePath = filePath;
@@ -19447,7 +19407,7 @@ var TunnelStore = class {
19447
19407
  }
19448
19408
  }
19449
19409
  async set(v) {
19450
- const dir = import_node_path14.default.dirname(this.filePath);
19410
+ const dir = import_node_path13.default.dirname(this.filePath);
19451
19411
  await import_node_fs13.default.promises.mkdir(dir, { recursive: true });
19452
19412
  const data = JSON.stringify(v, null, 2);
19453
19413
  const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
@@ -19559,7 +19519,7 @@ function escape(v) {
19559
19519
  // src/tunnel/frpc-binary.ts
19560
19520
  var import_node_fs14 = __toESM(require("fs"), 1);
19561
19521
  var import_node_os8 = __toESM(require("os"), 1);
19562
- var import_node_path15 = __toESM(require("path"), 1);
19522
+ var import_node_path14 = __toESM(require("path"), 1);
19563
19523
  var import_node_child_process3 = require("child_process");
19564
19524
  var import_node_stream = require("stream");
19565
19525
  var import_promises = require("stream/promises");
@@ -19598,13 +19558,13 @@ async function ensureFrpcBinary(opts) {
19598
19558
  }
19599
19559
  const version2 = opts.version ?? FRPC_VERSION;
19600
19560
  const platform = opts.platform ?? detectPlatform();
19601
- const binDir = import_node_path15.default.join(opts.dataDir, "bin");
19561
+ const binDir = import_node_path14.default.join(opts.dataDir, "bin");
19602
19562
  import_node_fs14.default.mkdirSync(binDir, { recursive: true });
19603
19563
  cleanupStaleArtifacts(binDir);
19604
- const stableBin = import_node_path15.default.join(binDir, "frpc");
19564
+ const stableBin = import_node_path14.default.join(binDir, "frpc");
19605
19565
  if (import_node_fs14.default.existsSync(stableBin)) return stableBin;
19606
19566
  const partialBin = `${stableBin}.partial`;
19607
- const tarballPath = import_node_path15.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
19567
+ const tarballPath = import_node_path14.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
19608
19568
  try {
19609
19569
  const url = frpcDownloadUrl(version2, platform);
19610
19570
  await downloadToFile(url, tarballPath, opts.fetchImpl);
@@ -19630,7 +19590,7 @@ function cleanupStaleArtifacts(binDir) {
19630
19590
  }
19631
19591
  for (const name of entries) {
19632
19592
  if (name.endsWith(".partial") || name.startsWith("extract-")) {
19633
- const full = import_node_path15.default.join(binDir, name);
19593
+ const full = import_node_path14.default.join(binDir, name);
19634
19594
  try {
19635
19595
  import_node_fs14.default.rmSync(full, { recursive: true, force: true });
19636
19596
  } catch {
@@ -19656,7 +19616,7 @@ async function downloadToFile(url, dest, fetchImpl) {
19656
19616
  await (0, import_promises.pipeline)(nodeStream, out);
19657
19617
  }
19658
19618
  async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
19659
- const work = import_node_path15.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
19619
+ const work = import_node_path14.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
19660
19620
  import_node_fs14.default.mkdirSync(work, { recursive: true });
19661
19621
  try {
19662
19622
  await new Promise((resolve2, reject) => {
@@ -19665,7 +19625,7 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
19665
19625
  proc.on("exit", (code) => code === 0 ? resolve2() : reject(new Error(`tar exited ${code}`)));
19666
19626
  });
19667
19627
  const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
19668
- const src = import_node_path15.default.join(work, dirName, "frpc");
19628
+ const src = import_node_path14.default.join(work, dirName, "frpc");
19669
19629
  if (!import_node_fs14.default.existsSync(src)) {
19670
19630
  throw new Error(`frpc not found inside tarball at ${src}`);
19671
19631
  }
@@ -19680,7 +19640,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
19680
19640
  var TunnelManager = class {
19681
19641
  constructor(deps) {
19682
19642
  this.deps = deps;
19683
- this.store = deps.store ?? new TunnelStore(import_node_path16.default.join(deps.dataDir, "tunnel.json"));
19643
+ this.store = deps.store ?? new TunnelStore(import_node_path15.default.join(deps.dataDir, "tunnel.json"));
19684
19644
  this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
19685
19645
  this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
19686
19646
  }
@@ -19797,7 +19757,7 @@ var TunnelManager = class {
19797
19757
  dataDir: this.deps.dataDir,
19798
19758
  override: this.deps.frpcBinaryOverride ?? void 0
19799
19759
  });
19800
- const tomlPath = import_node_path16.default.join(this.deps.dataDir, "frpc.toml");
19760
+ const tomlPath = import_node_path15.default.join(this.deps.dataDir, "frpc.toml");
19801
19761
  const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto4.default.randomBytes(3).toString("hex")}`;
19802
19762
  const toml = buildFrpcToml({
19803
19763
  serverAddr: t.frpsHost,
@@ -19812,7 +19772,7 @@ var TunnelManager = class {
19812
19772
  const proc = (this.deps.spawnImpl ?? import_node_child_process4.spawn)(frpcBin, ["-c", tomlPath], {
19813
19773
  stdio: ["ignore", "pipe", "pipe"]
19814
19774
  });
19815
- const logFilePath = import_node_path16.default.join(this.deps.dataDir, "frpc.log");
19775
+ const logFilePath = import_node_path15.default.join(this.deps.dataDir, "frpc.log");
19816
19776
  const logStream = import_node_fs15.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
19817
19777
  logStream.on("error", () => {
19818
19778
  });
@@ -19906,11 +19866,11 @@ function deriveStableDeviceKey(opts = {}) {
19906
19866
 
19907
19867
  // src/auth-store.ts
19908
19868
  var import_node_fs16 = __toESM(require("fs"), 1);
19909
- var import_node_path17 = __toESM(require("path"), 1);
19869
+ var import_node_path16 = __toESM(require("path"), 1);
19910
19870
  var import_node_crypto6 = __toESM(require("crypto"), 1);
19911
19871
  var AUTH_FILE_NAME = "auth.json";
19912
19872
  function authFilePath(dataDir) {
19913
- return import_node_path17.default.join(dataDir, AUTH_FILE_NAME);
19873
+ return import_node_path16.default.join(dataDir, AUTH_FILE_NAME);
19914
19874
  }
19915
19875
  function loadOrCreateAuthToken(opts) {
19916
19876
  const file = authFilePath(opts.dataDir);
@@ -19942,7 +19902,7 @@ function readAuthFile(file) {
19942
19902
  }
19943
19903
  }
19944
19904
  function writeAuthFile(file, content) {
19945
- import_node_fs16.default.mkdirSync(import_node_path17.default.dirname(file), { recursive: true });
19905
+ import_node_fs16.default.mkdirSync(import_node_path16.default.dirname(file), { recursive: true });
19946
19906
  import_node_fs16.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
19947
19907
  try {
19948
19908
  import_node_fs16.default.chmodSync(file, 384);
@@ -19953,11 +19913,11 @@ function writeAuthFile(file, content) {
19953
19913
  // src/owner-profile.ts
19954
19914
  var import_node_fs17 = __toESM(require("fs"), 1);
19955
19915
  var import_node_os10 = __toESM(require("os"), 1);
19956
- var import_node_path18 = __toESM(require("path"), 1);
19916
+ var import_node_path17 = __toESM(require("path"), 1);
19957
19917
  var PROFILE_FILENAME = "profile.json";
19958
19918
  function loadOwnerDisplayName(dataDir) {
19959
19919
  const fallback = import_node_os10.default.userInfo().username;
19960
- const profilePath = import_node_path18.default.join(dataDir, PROFILE_FILENAME);
19920
+ const profilePath = import_node_path17.default.join(dataDir, PROFILE_FILENAME);
19961
19921
  let raw;
19962
19922
  try {
19963
19923
  raw = import_node_fs17.default.readFileSync(profilePath, "utf8");
@@ -19991,7 +19951,7 @@ init_protocol();
19991
19951
  // src/session/fork.ts
19992
19952
  var import_node_fs18 = __toESM(require("fs"), 1);
19993
19953
  var import_node_os11 = __toESM(require("os"), 1);
19994
- var import_node_path19 = __toESM(require("path"), 1);
19954
+ var import_node_path18 = __toESM(require("path"), 1);
19995
19955
  init_claude_history();
19996
19956
  function readJsonlEntries(file) {
19997
19957
  const raw = import_node_fs18.default.readFileSync(file, "utf8");
@@ -20007,9 +19967,9 @@ function readJsonlEntries(file) {
20007
19967
  return out;
20008
19968
  }
20009
19969
  function forkSession(input) {
20010
- const baseDir = input.baseDir ?? import_node_path19.default.join(import_node_os11.default.homedir(), ".claude");
20011
- const projectDir = import_node_path19.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
20012
- const sourceFile = import_node_path19.default.join(projectDir, `${input.toolSessionId}.jsonl`);
19970
+ const baseDir = input.baseDir ?? import_node_path18.default.join(import_node_os11.default.homedir(), ".claude");
19971
+ const projectDir = import_node_path18.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
19972
+ const sourceFile = import_node_path18.default.join(projectDir, `${input.toolSessionId}.jsonl`);
20013
19973
  if (!import_node_fs18.default.existsSync(sourceFile)) {
20014
19974
  throw new Error(`fork: source transcript not found: ${sourceFile}`);
20015
19975
  }
@@ -20040,7 +20000,7 @@ function forkSession(input) {
20040
20000
  }
20041
20001
  forkedLines.push(JSON.stringify(forked));
20042
20002
  }
20043
- const forkedFilePath = import_node_path19.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
20003
+ const forkedFilePath = import_node_path18.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
20044
20004
  import_node_fs18.default.mkdirSync(projectDir, { recursive: true });
20045
20005
  import_node_fs18.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
20046
20006
  return { forkedToolSessionId, forkedFilePath };
@@ -20332,7 +20292,7 @@ init_protocol();
20332
20292
  var import_node_child_process5 = require("child_process");
20333
20293
  var import_node_fs19 = __toESM(require("fs"), 1);
20334
20294
  var import_node_os12 = __toESM(require("os"), 1);
20335
- var import_node_path20 = __toESM(require("path"), 1);
20295
+ var import_node_path19 = __toESM(require("path"), 1);
20336
20296
  var import_node_util = require("util");
20337
20297
  var pexec = (0, import_node_util.promisify)(import_node_child_process5.execFile);
20338
20298
  function formatChildProcessError(err) {
@@ -20347,7 +20307,7 @@ function formatChildProcessError(err) {
20347
20307
  return e.message ?? "unknown error";
20348
20308
  }
20349
20309
  function normalizePath(p) {
20350
- const resolved = import_node_path20.default.resolve(p);
20310
+ const resolved = import_node_path19.default.resolve(p);
20351
20311
  try {
20352
20312
  return import_node_fs19.default.realpathSync(resolved);
20353
20313
  } catch {
@@ -20450,13 +20410,13 @@ function flattenToDirName(branch) {
20450
20410
  }
20451
20411
  function encodeClaudeProjectDir(absPath) {
20452
20412
  if (!absPath || typeof absPath !== "string") return "";
20453
- let canonical = import_node_path20.default.resolve(absPath);
20413
+ let canonical = import_node_path19.default.resolve(absPath);
20454
20414
  try {
20455
20415
  canonical = import_node_fs19.default.realpathSync(canonical);
20456
20416
  } catch {
20457
20417
  try {
20458
- const parent = import_node_fs19.default.realpathSync(import_node_path20.default.dirname(canonical));
20459
- canonical = import_node_path20.default.join(parent, import_node_path20.default.basename(canonical));
20418
+ const parent = import_node_fs19.default.realpathSync(import_node_path19.default.dirname(canonical));
20419
+ canonical = import_node_path19.default.join(parent, import_node_path19.default.basename(canonical));
20460
20420
  } catch {
20461
20421
  }
20462
20422
  }
@@ -20480,11 +20440,11 @@ async function createWorktree(input) {
20480
20440
  if (!isGitRoot) {
20481
20441
  throw new Error(`\u76EE\u5F55 ${cwd} \u4E0D\u662F git repo \u6839`);
20482
20442
  }
20483
- const parent = import_node_path20.default.dirname(import_node_path20.default.resolve(cwd));
20484
- if (parent === "/" || parent === import_node_path20.default.resolve(cwd)) {
20443
+ const parent = import_node_path19.default.dirname(import_node_path19.default.resolve(cwd));
20444
+ if (parent === "/" || parent === import_node_path19.default.resolve(cwd)) {
20485
20445
  throw new Error("repo \u5728\u78C1\u76D8\u6839\u76EE\u5F55\uFF0C\u65E0\u6CD5\u5728\u540C\u7EA7\u521B\u5EFA worktree");
20486
20446
  }
20487
- const worktreeRoot = import_node_path20.default.join(parent, dirName);
20447
+ const worktreeRoot = import_node_path19.default.join(parent, dirName);
20488
20448
  try {
20489
20449
  await pexec("git", ["-C", cwd, "fetch", "origin", baseBranch, "--no-tags"], {
20490
20450
  timeout: 3e4
@@ -20531,8 +20491,8 @@ async function removeWorktree(input) {
20531
20491
  );
20532
20492
  const gitCommonDir = stdout.trim();
20533
20493
  if (!gitCommonDir) throw new Error("empty git-common-dir");
20534
- const absGitCommon = import_node_path20.default.isAbsolute(gitCommonDir) ? gitCommonDir : import_node_path20.default.resolve(worktreeRoot, gitCommonDir);
20535
- repoRoot = import_node_path20.default.dirname(absGitCommon);
20494
+ const absGitCommon = import_node_path19.default.isAbsolute(gitCommonDir) ? gitCommonDir : import_node_path19.default.resolve(worktreeRoot, gitCommonDir);
20495
+ repoRoot = import_node_path19.default.dirname(absGitCommon);
20536
20496
  } catch {
20537
20497
  repoRoot = null;
20538
20498
  }
@@ -20563,9 +20523,9 @@ async function removeWorktree(input) {
20563
20523
  try {
20564
20524
  const encoded = encodeClaudeProjectDir(worktreeRoot);
20565
20525
  if (encoded) {
20566
- const projectsRoot = import_node_path20.default.join(import_node_os12.default.homedir(), ".claude", "projects");
20567
- const target = import_node_path20.default.resolve(projectsRoot, encoded);
20568
- if (target.startsWith(projectsRoot + import_node_path20.default.sep) && target !== projectsRoot) {
20526
+ const projectsRoot = import_node_path19.default.join(import_node_os12.default.homedir(), ".claude", "projects");
20527
+ const target = import_node_path19.default.resolve(projectsRoot, encoded);
20528
+ if (target.startsWith(projectsRoot + import_node_path19.default.sep) && target !== projectsRoot) {
20569
20529
  import_node_fs19.default.rmSync(target, { recursive: true, force: true });
20570
20530
  }
20571
20531
  }
@@ -20734,7 +20694,7 @@ function buildPersonaHandlers(deps) {
20734
20694
  };
20735
20695
  const listSubSessions = async (frame) => {
20736
20696
  const args = PersonaIdArgsSchema.parse(frame);
20737
- const sessions = sessionManager.listPersonaSessions(args.personaId, "listener");
20697
+ const sessions = sessionManager.listForAgent(args.personaId);
20738
20698
  return {
20739
20699
  response: { type: "persona:subSessions", sessions }
20740
20700
  };
@@ -20781,7 +20741,7 @@ function buildMethodHandlers(deps) {
20781
20741
  async function startDaemon(config) {
20782
20742
  const logger = createLogger({
20783
20743
  level: config.logLevel,
20784
- file: import_node_path21.default.join(config.dataDir, "clawd.log")
20744
+ file: import_node_path20.default.join(config.dataDir, "clawd.log")
20785
20745
  });
20786
20746
  logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
20787
20747
  const stateMgr = new StateFileManager({ dataDir: config.dataDir });
@@ -20817,7 +20777,7 @@ async function startDaemon(config) {
20817
20777
  const agents = new AgentsScanner();
20818
20778
  const history = new ClaudeHistoryReader();
20819
20779
  let transport = null;
20820
- const personaStore = new PersonaStore(import_node_path21.default.join(config.dataDir, "personas"));
20780
+ const personaStore = new PersonaStore(import_node_path20.default.join(config.dataDir, "personas"));
20821
20781
  const defaultsRoot = findDefaultsRoot();
20822
20782
  if (defaultsRoot) {
20823
20783
  seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
@@ -20831,7 +20791,7 @@ async function startDaemon(config) {
20831
20791
  getAdapter,
20832
20792
  historyReader: history,
20833
20793
  dataDir: config.dataDir,
20834
- personaRoot: import_node_path21.default.join(config.dataDir, "personas"),
20794
+ personaRoot: import_node_path20.default.join(config.dataDir, "personas"),
20835
20795
  personaStore,
20836
20796
  ownerDisplayName,
20837
20797
  broadcastFrame: (frame, target) => {
@@ -21005,8 +20965,8 @@ async function startDaemon(config) {
21005
20965
  const lines = [
21006
20966
  `Tunnel: ${r.url}`,
21007
20967
  ...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
21008
- `Frpc config: ${import_node_path21.default.join(config.dataDir, "frpc.toml")}`,
21009
- `Frpc log: ${import_node_path21.default.join(config.dataDir, "frpc.log")}`
20968
+ `Frpc config: ${import_node_path20.default.join(config.dataDir, "frpc.toml")}`,
20969
+ `Frpc log: ${import_node_path20.default.join(config.dataDir, "frpc.log")}`
21010
20970
  ];
21011
20971
  const width = Math.max(...lines.map((l) => l.length));
21012
20972
  const bar = "\u2550".repeat(width + 4);
@@ -21019,7 +20979,7 @@ ${bar}
21019
20979
 
21020
20980
  `);
21021
20981
  try {
21022
- const connectPath = import_node_path21.default.join(config.dataDir, "connect.txt");
20982
+ const connectPath = import_node_path20.default.join(config.dataDir, "connect.txt");
21023
20983
  import_node_fs20.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
21024
20984
  } catch {
21025
20985
  }