@clawos-dev/clawd 0.2.142 → 0.2.143-beta.301.814d293

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/dist/cli.cjs +920 -1562
  2. package/dist/deploy-kit/.secrets/aliyun.env.example +4 -0
  3. package/dist/deploy-kit/scripts/new-extension.sh +22 -0
  4. package/dist/deploy-kit/scripts/publish.sh +100 -0
  5. package/dist/deploy-kit/scripts/publish.spec.ts +69 -0
  6. package/dist/{persona-defaults/persona-app-builder/extension-kit → deploy-kit}/scripts/remove-extension.sh +15 -26
  7. package/dist/persona-defaults/persona-app-builder/CLAUDE.md +13 -16
  8. package/dist/persona-defaults/persona-app-builder/extension-kit/README.md +24 -18
  9. package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/ext.conf +5 -0
  10. package/dist/persona-defaults/persona-bug-fixer/CLAUDE.md +0 -2
  11. package/dist/persona-defaults/persona-dataclaw-builder/.mcp.json +4 -0
  12. package/dist/persona-defaults/persona-dataclaw-builder/.secrets/dataclaw.env.example +3 -0
  13. package/dist/persona-defaults/persona-dataclaw-builder/CLAUDE.md +66 -0
  14. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/README.md +99 -0
  15. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/config.env +20 -0
  16. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/contract/s.yaml.tmpl +59 -0
  17. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/ext.conf +5 -0
  18. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/server/.env.example +15 -0
  19. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/server/.fcignore +7 -0
  20. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/server/nest-cli.json +8 -0
  21. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/server/package.json +29 -0
  22. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/server/src/app.module.ts +13 -0
  23. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/server/src/auth/gate.ts +70 -0
  24. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/server/src/auth/session.ts +52 -0
  25. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/server/src/auth/ttc-user-info.ts +23 -0
  26. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/server/src/dataclaw/dataclaw.client.ts +83 -0
  27. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/server/src/dataclaw/dataclaw.config.ts +18 -0
  28. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/server/src/dataclaw/dataclaw.controller.ts +30 -0
  29. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/server/src/dataclaw/dataclaw.module.ts +9 -0
  30. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/server/src/main.ts +116 -0
  31. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/server/src/polyfill.ts +6 -0
  32. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/server/tsconfig.json +14 -0
  33. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/web/index.html +12 -0
  34. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/web/package.json +18 -0
  35. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/web/src/App.jsx +9 -0
  36. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/web/src/api.js +19 -0
  37. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/web/src/auth.js +7 -0
  38. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/web/src/components/BarChart.jsx +38 -0
  39. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/web/src/components/FilterRow.jsx +79 -0
  40. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/web/src/components/ResultCards.jsx +17 -0
  41. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/web/src/components/ResultTable.jsx +21 -0
  42. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/web/src/components/SchemaFilters.jsx +93 -0
  43. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/web/src/enums.js +22 -0
  44. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/web/src/main.jsx +6 -0
  45. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/web/src/pages/PerformanceQueryPage.jsx +102 -0
  46. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/web/src/styles.css +83 -0
  47. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/web/vite.config.js +30 -0
  48. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/hooks/pre-deploy.sh +25 -0
  49. package/dist/persona-defaults/persona-developer/CLAUDE.md +0 -2
  50. package/package.json +2 -5
  51. package/dist/dispatch/mcp-server.cjs +0 -39756
  52. package/dist/persona-defaults/persona-app-builder/extension-kit/scripts/new-extension.sh +0 -66
  53. package/dist/persona-defaults/persona-app-builder/extension-kit/scripts/publish.sh +0 -110
  54. /package/dist/{persona-defaults/persona-app-builder → deploy-kit}/.secrets/aliyun.env +0 -0
  55. /package/dist/{persona-defaults/persona-app-builder/extension-kit → deploy-kit}/contract/bootstrap +0 -0
  56. /package/dist/{persona-defaults/persona-app-builder/extension-kit → deploy-kit}/scripts/ensure-toolchain.sh +0 -0
  57. /package/dist/{persona-defaults/persona-app-builder/extension-kit → deploy-kit}/scripts/verify.sh +0 -0
package/dist/cli.cjs CHANGED
@@ -720,8 +720,8 @@ var init_parseUtil = __esm({
720
720
  init_errors2();
721
721
  init_en();
722
722
  makeIssue = (params) => {
723
- const { data, path: path59, errorMaps, issueData } = params;
724
- const fullPath = [...path59, ...issueData.path || []];
723
+ const { data, path: path58, errorMaps, issueData } = params;
724
+ const fullPath = [...path58, ...issueData.path || []];
725
725
  const fullIssue = {
726
726
  ...issueData,
727
727
  path: fullPath
@@ -1032,11 +1032,11 @@ var init_types = __esm({
1032
1032
  init_parseUtil();
1033
1033
  init_util();
1034
1034
  ParseInputLazyPath = class {
1035
- constructor(parent, value, path59, key) {
1035
+ constructor(parent, value, path58, key) {
1036
1036
  this._cachedPath = [];
1037
1037
  this.parent = parent;
1038
1038
  this.data = value;
1039
- this._path = path59;
1039
+ this._path = path58;
1040
1040
  this._key = key;
1041
1041
  }
1042
1042
  get path() {
@@ -4752,13 +4752,6 @@ var init_schemas = __esm({
4752
4752
  * - native `session:*` handler 完全不感知 mirror(UI 操作 mirror 不走 native 路径)
4753
4753
  */
4754
4754
  originOwnerPrincipalId: external_exports.string().min(1).optional(),
4755
- /**
4756
- * Dispatch 派生的 session 在 create 时记录源 session 的 sessionId(稳定 key);
4757
- * sidebar 据此把 dispatch 出来的 sub-session 折叠在源 session 下。非 dispatch session 缺省。
4758
- * mirror SessionFile 上必须 strip(朋友 daemon 上的 sessionId 在本机无意义,会让本机
4759
- * 反查路径走错;按 #750 一族防线处理,跟 ownerPersonaId 同地点 strip)。
4760
- */
4761
- dispatchedFromSessionId: external_exports.string().min(1).optional(),
4762
4755
  createdAt: external_exports.string().min(1),
4763
4756
  updatedAt: external_exports.string().min(1)
4764
4757
  });
@@ -5899,7 +5892,9 @@ var init_feishu_auth = __esm({
5899
5892
  /** 显示名。TTC user_info 接口 data.name */
5900
5893
  displayName: external_exports.string().min(1),
5901
5894
  /** TTC user_info 接口 data.avatar_url,可缺省 */
5902
- avatarUrl: external_exports.string().optional()
5895
+ avatarUrl: external_exports.string().optional(),
5896
+ /** TTC user_info 接口 data.union_id(飞书 union_id;dataclaw 可信入口 X-User-UnionId 用),可缺省 */
5897
+ unionId: external_exports.string().optional()
5903
5898
  });
5904
5899
  AuthLoginStartResponseSchema = external_exports.object({
5905
5900
  type: external_exports.literal("auth:login:start:ok"),
@@ -5933,60 +5928,6 @@ var init_feishu_auth = __esm({
5933
5928
  }
5934
5929
  });
5935
5930
 
5936
- // ../protocol/src/dispatch.ts
5937
- var DispatchOutcomeSchema, DispatchRunArgsSchema, DispatchCompleteArgsSchema;
5938
- var init_dispatch = __esm({
5939
- "../protocol/src/dispatch.ts"() {
5940
- "use strict";
5941
- init_zod();
5942
- DispatchOutcomeSchema = external_exports.discriminatedUnion("kind", [
5943
- external_exports.object({
5944
- kind: external_exports.literal("success"),
5945
- text: external_exports.string(),
5946
- filePaths: external_exports.array(external_exports.string()).optional()
5947
- }),
5948
- external_exports.object({
5949
- kind: external_exports.literal("failure"),
5950
- reason: external_exports.string()
5951
- })
5952
- ]);
5953
- DispatchRunArgsSchema = external_exports.object({
5954
- targetPersona: external_exports.string().min(1),
5955
- prompt: external_exports.string()
5956
- });
5957
- DispatchCompleteArgsSchema = external_exports.object({
5958
- dispatchId: external_exports.string().min(1),
5959
- outcome: DispatchOutcomeSchema
5960
- });
5961
- }
5962
- });
5963
-
5964
- // ../protocol/src/log.ts
5965
- var LOG_SOURCES, LogSourceSchema, LOG_LEVELS, LogLevelSchema, LogRecordSchema;
5966
- var init_log = __esm({
5967
- "../protocol/src/log.ts"() {
5968
- "use strict";
5969
- init_zod();
5970
- LOG_SOURCES = ["daemon", "main", "renderer"];
5971
- LogSourceSchema = external_exports.enum(LOG_SOURCES);
5972
- LOG_LEVELS = ["debug", "info", "warn", "error"];
5973
- LogLevelSchema = external_exports.enum(LOG_LEVELS);
5974
- LogRecordSchema = external_exports.object({
5975
- ts: external_exports.number().int(),
5976
- source: LogSourceSchema,
5977
- level: LogLevelSchema,
5978
- msg: external_exports.string(),
5979
- ownerPrincipalId: external_exports.string(),
5980
- deviceId: external_exports.string(),
5981
- appVersion: external_exports.string(),
5982
- daemonVersion: external_exports.string().optional(),
5983
- os: external_exports.string(),
5984
- meta_json: external_exports.string().optional(),
5985
- sessionId: external_exports.string().optional()
5986
- });
5987
- }
5988
- });
5989
-
5990
5931
  // ../protocol/src/runtime.ts
5991
5932
  var init_runtime = __esm({
5992
5933
  "../protocol/src/runtime.ts"() {
@@ -6005,8 +5946,6 @@ var init_runtime = __esm({
6005
5946
  init_contact();
6006
5947
  init_extension();
6007
5948
  init_feishu_auth();
6008
- init_dispatch();
6009
- init_log();
6010
5949
  }
6011
5950
  });
6012
5951
 
@@ -6281,8 +6220,8 @@ var require_req = __commonJS({
6281
6220
  if (req.originalUrl) {
6282
6221
  _req.url = req.originalUrl;
6283
6222
  } else {
6284
- const path59 = req.path;
6285
- _req.url = typeof path59 === "string" ? path59 : req.url ? req.url.path || req.url : void 0;
6223
+ const path58 = req.path;
6224
+ _req.url = typeof path58 === "string" ? path58 : req.url ? req.url.path || req.url : void 0;
6286
6225
  }
6287
6226
  if (req.query) {
6288
6227
  _req.query = req.query;
@@ -6447,14 +6386,14 @@ var require_redact = __commonJS({
6447
6386
  }
6448
6387
  return obj;
6449
6388
  }
6450
- function parsePath(path59) {
6389
+ function parsePath(path58) {
6451
6390
  const parts = [];
6452
6391
  let current = "";
6453
6392
  let inBrackets = false;
6454
6393
  let inQuotes = false;
6455
6394
  let quoteChar = "";
6456
- for (let i = 0; i < path59.length; i++) {
6457
- const char = path59[i];
6395
+ for (let i = 0; i < path58.length; i++) {
6396
+ const char = path58[i];
6458
6397
  if (!inBrackets && char === ".") {
6459
6398
  if (current) {
6460
6399
  parts.push(current);
@@ -6585,10 +6524,10 @@ var require_redact = __commonJS({
6585
6524
  return current;
6586
6525
  }
6587
6526
  function redactPaths(obj, paths, censor, remove = false) {
6588
- for (const path59 of paths) {
6589
- const parts = parsePath(path59);
6527
+ for (const path58 of paths) {
6528
+ const parts = parsePath(path58);
6590
6529
  if (parts.includes("*")) {
6591
- redactWildcardPath(obj, parts, censor, path59, remove);
6530
+ redactWildcardPath(obj, parts, censor, path58, remove);
6592
6531
  } else {
6593
6532
  if (remove) {
6594
6533
  removeKey(obj, parts);
@@ -6673,8 +6612,8 @@ var require_redact = __commonJS({
6673
6612
  }
6674
6613
  } else {
6675
6614
  if (afterWildcard.includes("*")) {
6676
- const wrappedCensor = typeof censor === "function" ? (value, path59) => {
6677
- const fullPath = [...pathArray.slice(0, pathLength), ...path59];
6615
+ const wrappedCensor = typeof censor === "function" ? (value, path58) => {
6616
+ const fullPath = [...pathArray.slice(0, pathLength), ...path58];
6678
6617
  return censor(value, fullPath);
6679
6618
  } : censor;
6680
6619
  redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
@@ -6709,8 +6648,8 @@ var require_redact = __commonJS({
6709
6648
  return null;
6710
6649
  }
6711
6650
  const pathStructure = /* @__PURE__ */ new Map();
6712
- for (const path59 of pathsToClone) {
6713
- const parts = parsePath(path59);
6651
+ for (const path58 of pathsToClone) {
6652
+ const parts = parsePath(path58);
6714
6653
  let current = pathStructure;
6715
6654
  for (let i = 0; i < parts.length; i++) {
6716
6655
  const part = parts[i];
@@ -6762,24 +6701,24 @@ var require_redact = __commonJS({
6762
6701
  }
6763
6702
  return cloneSelectively(obj, pathStructure);
6764
6703
  }
6765
- function validatePath(path59) {
6766
- if (typeof path59 !== "string") {
6704
+ function validatePath(path58) {
6705
+ if (typeof path58 !== "string") {
6767
6706
  throw new Error("Paths must be (non-empty) strings");
6768
6707
  }
6769
- if (path59 === "") {
6708
+ if (path58 === "") {
6770
6709
  throw new Error("Invalid redaction path ()");
6771
6710
  }
6772
- if (path59.includes("..")) {
6773
- throw new Error(`Invalid redaction path (${path59})`);
6711
+ if (path58.includes("..")) {
6712
+ throw new Error(`Invalid redaction path (${path58})`);
6774
6713
  }
6775
- if (path59.includes(",")) {
6776
- throw new Error(`Invalid redaction path (${path59})`);
6714
+ if (path58.includes(",")) {
6715
+ throw new Error(`Invalid redaction path (${path58})`);
6777
6716
  }
6778
6717
  let bracketCount = 0;
6779
6718
  let inQuotes = false;
6780
6719
  let quoteChar = "";
6781
- for (let i = 0; i < path59.length; i++) {
6782
- const char = path59[i];
6720
+ for (let i = 0; i < path58.length; i++) {
6721
+ const char = path58[i];
6783
6722
  if ((char === '"' || char === "'") && bracketCount > 0) {
6784
6723
  if (!inQuotes) {
6785
6724
  inQuotes = true;
@@ -6793,20 +6732,20 @@ var require_redact = __commonJS({
6793
6732
  } else if (char === "]" && !inQuotes) {
6794
6733
  bracketCount--;
6795
6734
  if (bracketCount < 0) {
6796
- throw new Error(`Invalid redaction path (${path59})`);
6735
+ throw new Error(`Invalid redaction path (${path58})`);
6797
6736
  }
6798
6737
  }
6799
6738
  }
6800
6739
  if (bracketCount !== 0) {
6801
- throw new Error(`Invalid redaction path (${path59})`);
6740
+ throw new Error(`Invalid redaction path (${path58})`);
6802
6741
  }
6803
6742
  }
6804
6743
  function validatePaths(paths) {
6805
6744
  if (!Array.isArray(paths)) {
6806
6745
  throw new TypeError("paths must be an array");
6807
6746
  }
6808
- for (const path59 of paths) {
6809
- validatePath(path59);
6747
+ for (const path58 of paths) {
6748
+ validatePath(path58);
6810
6749
  }
6811
6750
  }
6812
6751
  function slowRedact(options = {}) {
@@ -6974,8 +6913,8 @@ var require_redaction = __commonJS({
6974
6913
  if (shape[k2] === null) {
6975
6914
  o[k2] = (value) => topCensor(value, [k2]);
6976
6915
  } else {
6977
- const wrappedCensor = typeof censor === "function" ? (value, path59) => {
6978
- return censor(value, [k2, ...path59]);
6916
+ const wrappedCensor = typeof censor === "function" ? (value, path58) => {
6917
+ return censor(value, [k2, ...path58]);
6979
6918
  } : censor;
6980
6919
  o[k2] = Redact({
6981
6920
  paths: shape[k2],
@@ -7159,7 +7098,7 @@ var require_atomic_sleep = __commonJS({
7159
7098
  "../node_modules/.pnpm/atomic-sleep@1.0.0/node_modules/atomic-sleep/index.js"(exports2, module2) {
7160
7099
  "use strict";
7161
7100
  if (typeof SharedArrayBuffer !== "undefined" && typeof Atomics !== "undefined") {
7162
- let sleep2 = function(ms) {
7101
+ let sleep = function(ms) {
7163
7102
  const valid = ms > 0 && ms < Infinity;
7164
7103
  if (valid === false) {
7165
7104
  if (typeof ms !== "number" && typeof ms !== "bigint") {
@@ -7170,9 +7109,9 @@ var require_atomic_sleep = __commonJS({
7170
7109
  Atomics.wait(nil, 0, 0, Number(ms));
7171
7110
  };
7172
7111
  const nil = new Int32Array(new SharedArrayBuffer(4));
7173
- module2.exports = sleep2;
7112
+ module2.exports = sleep;
7174
7113
  } else {
7175
- let sleep2 = function(ms) {
7114
+ let sleep = function(ms) {
7176
7115
  const valid = ms > 0 && ms < Infinity;
7177
7116
  if (valid === false) {
7178
7117
  if (typeof ms !== "number" && typeof ms !== "bigint") {
@@ -7184,7 +7123,7 @@ var require_atomic_sleep = __commonJS({
7184
7123
  while (target > Date.now()) {
7185
7124
  }
7186
7125
  };
7187
- module2.exports = sleep2;
7126
+ module2.exports = sleep;
7188
7127
  }
7189
7128
  }
7190
7129
  });
@@ -7193,11 +7132,11 @@ var require_atomic_sleep = __commonJS({
7193
7132
  var require_sonic_boom = __commonJS({
7194
7133
  "../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
7195
7134
  "use strict";
7196
- var fs52 = require("fs");
7135
+ var fs51 = require("fs");
7197
7136
  var EventEmitter3 = require("events");
7198
7137
  var inherits = require("util").inherits;
7199
- var path59 = require("path");
7200
- var sleep2 = require_atomic_sleep();
7138
+ var path58 = require("path");
7139
+ var sleep = require_atomic_sleep();
7201
7140
  var assert = require("assert");
7202
7141
  var BUSY_WRITE_TIMEOUT = 100;
7203
7142
  var kEmptyBuffer = Buffer.allocUnsafe(0);
@@ -7250,20 +7189,20 @@ var require_sonic_boom = __commonJS({
7250
7189
  const mode = sonic.mode;
7251
7190
  if (sonic.sync) {
7252
7191
  try {
7253
- if (sonic.mkdir) fs52.mkdirSync(path59.dirname(file), { recursive: true });
7254
- const fd = fs52.openSync(file, flags, mode);
7192
+ if (sonic.mkdir) fs51.mkdirSync(path58.dirname(file), { recursive: true });
7193
+ const fd = fs51.openSync(file, flags, mode);
7255
7194
  fileOpened(null, fd);
7256
7195
  } catch (err) {
7257
7196
  fileOpened(err);
7258
7197
  throw err;
7259
7198
  }
7260
7199
  } else if (sonic.mkdir) {
7261
- fs52.mkdir(path59.dirname(file), { recursive: true }, (err) => {
7200
+ fs51.mkdir(path58.dirname(file), { recursive: true }, (err) => {
7262
7201
  if (err) return fileOpened(err);
7263
- fs52.open(file, flags, mode, fileOpened);
7202
+ fs51.open(file, flags, mode, fileOpened);
7264
7203
  });
7265
7204
  } else {
7266
- fs52.open(file, flags, mode, fileOpened);
7205
+ fs51.open(file, flags, mode, fileOpened);
7267
7206
  }
7268
7207
  }
7269
7208
  function SonicBoom(opts) {
@@ -7304,8 +7243,8 @@ var require_sonic_boom = __commonJS({
7304
7243
  this.flush = flushBuffer;
7305
7244
  this.flushSync = flushBufferSync;
7306
7245
  this._actualWrite = actualWriteBuffer;
7307
- fsWriteSync = () => fs52.writeSync(this.fd, this._writingBuf);
7308
- fsWrite = () => fs52.write(this.fd, this._writingBuf, this.release);
7246
+ fsWriteSync = () => fs51.writeSync(this.fd, this._writingBuf);
7247
+ fsWrite = () => fs51.write(this.fd, this._writingBuf, this.release);
7309
7248
  } else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
7310
7249
  this._writingBuf = "";
7311
7250
  this.write = write;
@@ -7314,15 +7253,15 @@ var require_sonic_boom = __commonJS({
7314
7253
  this._actualWrite = actualWrite;
7315
7254
  fsWriteSync = () => {
7316
7255
  if (Buffer.isBuffer(this._writingBuf)) {
7317
- return fs52.writeSync(this.fd, this._writingBuf);
7256
+ return fs51.writeSync(this.fd, this._writingBuf);
7318
7257
  }
7319
- return fs52.writeSync(this.fd, this._writingBuf, "utf8");
7258
+ return fs51.writeSync(this.fd, this._writingBuf, "utf8");
7320
7259
  };
7321
7260
  fsWrite = () => {
7322
7261
  if (Buffer.isBuffer(this._writingBuf)) {
7323
- return fs52.write(this.fd, this._writingBuf, this.release);
7262
+ return fs51.write(this.fd, this._writingBuf, this.release);
7324
7263
  }
7325
- return fs52.write(this.fd, this._writingBuf, "utf8", this.release);
7264
+ return fs51.write(this.fd, this._writingBuf, "utf8", this.release);
7326
7265
  };
7327
7266
  } else {
7328
7267
  throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
@@ -7343,7 +7282,7 @@ var require_sonic_boom = __commonJS({
7343
7282
  if ((err.code === "EAGAIN" || err.code === "EBUSY") && this.retryEAGAIN(err, this._writingBuf.length, this._len - this._writingBuf.length)) {
7344
7283
  if (this.sync) {
7345
7284
  try {
7346
- sleep2(BUSY_WRITE_TIMEOUT);
7285
+ sleep(BUSY_WRITE_TIMEOUT);
7347
7286
  this.release(void 0, 0);
7348
7287
  } catch (err2) {
7349
7288
  this.release(err2);
@@ -7379,7 +7318,7 @@ var require_sonic_boom = __commonJS({
7379
7318
  }
7380
7319
  }
7381
7320
  if (this._fsync) {
7382
- fs52.fsyncSync(this.fd);
7321
+ fs51.fsyncSync(this.fd);
7383
7322
  }
7384
7323
  const len = this._len;
7385
7324
  if (this._reopening) {
@@ -7493,7 +7432,7 @@ var require_sonic_boom = __commonJS({
7493
7432
  const onDrain = () => {
7494
7433
  if (!this._fsync) {
7495
7434
  try {
7496
- fs52.fsync(this.fd, (err) => {
7435
+ fs51.fsync(this.fd, (err) => {
7497
7436
  this._flushPending = false;
7498
7437
  cb(err);
7499
7438
  });
@@ -7595,7 +7534,7 @@ var require_sonic_boom = __commonJS({
7595
7534
  const fd = this.fd;
7596
7535
  this.once("ready", () => {
7597
7536
  if (fd !== this.fd) {
7598
- fs52.close(fd, (err) => {
7537
+ fs51.close(fd, (err) => {
7599
7538
  if (err) {
7600
7539
  return this.emit("error", err);
7601
7540
  }
@@ -7644,7 +7583,7 @@ var require_sonic_boom = __commonJS({
7644
7583
  buf = this._bufs[0];
7645
7584
  }
7646
7585
  try {
7647
- const n = Buffer.isBuffer(buf) ? fs52.writeSync(this.fd, buf) : fs52.writeSync(this.fd, buf, "utf8");
7586
+ const n = Buffer.isBuffer(buf) ? fs51.writeSync(this.fd, buf) : fs51.writeSync(this.fd, buf, "utf8");
7648
7587
  const releasedBufObj = releaseWritingBuf(buf, this._len, n);
7649
7588
  buf = releasedBufObj.writingBuf;
7650
7589
  this._len = releasedBufObj.len;
@@ -7656,11 +7595,11 @@ var require_sonic_boom = __commonJS({
7656
7595
  if (shouldRetry && !this.retryEAGAIN(err, buf.length, this._len - buf.length)) {
7657
7596
  throw err;
7658
7597
  }
7659
- sleep2(BUSY_WRITE_TIMEOUT);
7598
+ sleep(BUSY_WRITE_TIMEOUT);
7660
7599
  }
7661
7600
  }
7662
7601
  try {
7663
- fs52.fsyncSync(this.fd);
7602
+ fs51.fsyncSync(this.fd);
7664
7603
  } catch {
7665
7604
  }
7666
7605
  }
@@ -7681,7 +7620,7 @@ var require_sonic_boom = __commonJS({
7681
7620
  buf = mergeBuf(this._bufs[0], this._lens[0]);
7682
7621
  }
7683
7622
  try {
7684
- const n = fs52.writeSync(this.fd, buf);
7623
+ const n = fs51.writeSync(this.fd, buf);
7685
7624
  buf = buf.subarray(n);
7686
7625
  this._len = Math.max(this._len - n, 0);
7687
7626
  if (buf.length <= 0) {
@@ -7693,7 +7632,7 @@ var require_sonic_boom = __commonJS({
7693
7632
  if (shouldRetry && !this.retryEAGAIN(err, buf.length, this._len - buf.length)) {
7694
7633
  throw err;
7695
7634
  }
7696
- sleep2(BUSY_WRITE_TIMEOUT);
7635
+ sleep(BUSY_WRITE_TIMEOUT);
7697
7636
  }
7698
7637
  }
7699
7638
  }
@@ -7709,13 +7648,13 @@ var require_sonic_boom = __commonJS({
7709
7648
  this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
7710
7649
  if (this.sync) {
7711
7650
  try {
7712
- const written = Buffer.isBuffer(this._writingBuf) ? fs52.writeSync(this.fd, this._writingBuf) : fs52.writeSync(this.fd, this._writingBuf, "utf8");
7651
+ const written = Buffer.isBuffer(this._writingBuf) ? fs51.writeSync(this.fd, this._writingBuf) : fs51.writeSync(this.fd, this._writingBuf, "utf8");
7713
7652
  release(null, written);
7714
7653
  } catch (err) {
7715
7654
  release(err);
7716
7655
  }
7717
7656
  } else {
7718
- fs52.write(this.fd, this._writingBuf, release);
7657
+ fs51.write(this.fd, this._writingBuf, release);
7719
7658
  }
7720
7659
  }
7721
7660
  function actualWriteBuffer() {
@@ -7724,7 +7663,7 @@ var require_sonic_boom = __commonJS({
7724
7663
  this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
7725
7664
  if (this.sync) {
7726
7665
  try {
7727
- const written = fs52.writeSync(this.fd, this._writingBuf);
7666
+ const written = fs51.writeSync(this.fd, this._writingBuf);
7728
7667
  release(null, written);
7729
7668
  } catch (err) {
7730
7669
  release(err);
@@ -7733,7 +7672,7 @@ var require_sonic_boom = __commonJS({
7733
7672
  if (kCopyBuffer) {
7734
7673
  this._writingBuf = Buffer.from(this._writingBuf);
7735
7674
  }
7736
- fs52.write(this.fd, this._writingBuf, release);
7675
+ fs51.write(this.fd, this._writingBuf, release);
7737
7676
  }
7738
7677
  }
7739
7678
  function actualClose(sonic) {
@@ -7749,12 +7688,12 @@ var require_sonic_boom = __commonJS({
7749
7688
  sonic._lens = [];
7750
7689
  assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
7751
7690
  try {
7752
- fs52.fsync(sonic.fd, closeWrapped);
7691
+ fs51.fsync(sonic.fd, closeWrapped);
7753
7692
  } catch {
7754
7693
  }
7755
7694
  function closeWrapped() {
7756
7695
  if (sonic.fd !== 1 && sonic.fd !== 2) {
7757
- fs52.close(sonic.fd, done);
7696
+ fs51.close(sonic.fd, done);
7758
7697
  } else {
7759
7698
  done();
7760
7699
  }
@@ -8434,7 +8373,7 @@ var require_transport = __commonJS({
8434
8373
  var { createRequire } = require("module");
8435
8374
  var getCallers = require_caller();
8436
8375
  var { join: join15, isAbsolute: isAbsolute2, sep: sep2 } = require("path");
8437
- var sleep2 = require_atomic_sleep();
8376
+ var sleep = require_atomic_sleep();
8438
8377
  var onExit = require_on_exit_leak_free();
8439
8378
  var ThreadStream = require_thread_stream();
8440
8379
  function setupOnExit(stream) {
@@ -8468,7 +8407,7 @@ var require_transport = __commonJS({
8468
8407
  return;
8469
8408
  }
8470
8409
  stream.flushSync();
8471
- sleep2(100);
8410
+ sleep(100);
8472
8411
  stream.end();
8473
8412
  }
8474
8413
  return stream;
@@ -10118,7 +10057,7 @@ var require_multistream = __commonJS({
10118
10057
  var require_pino = __commonJS({
10119
10058
  "../node_modules/.pnpm/pino@9.14.0/node_modules/pino/pino.js"(exports2, module2) {
10120
10059
  "use strict";
10121
- var os22 = require("os");
10060
+ var os21 = require("os");
10122
10061
  var stdSerializers = require_pino_std_serializers();
10123
10062
  var caller = require_caller();
10124
10063
  var redaction = require_redaction();
@@ -10165,7 +10104,7 @@ var require_pino = __commonJS({
10165
10104
  } = symbols;
10166
10105
  var { epochTime, nullTime } = time;
10167
10106
  var { pid } = process;
10168
- var hostname = os22.hostname();
10107
+ var hostname = os21.hostname();
10169
10108
  var defaultErrorSerializer = stdSerializers.err;
10170
10109
  var defaultOptions = {
10171
10110
  level: "info",
@@ -10889,11 +10828,11 @@ var init_lib = __esm({
10889
10828
  }
10890
10829
  }
10891
10830
  },
10892
- addToPath: function addToPath(path59, added, removed, oldPosInc, options) {
10893
- var last = path59.lastComponent;
10831
+ addToPath: function addToPath(path58, added, removed, oldPosInc, options) {
10832
+ var last = path58.lastComponent;
10894
10833
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
10895
10834
  return {
10896
- oldPos: path59.oldPos + oldPosInc,
10835
+ oldPos: path58.oldPos + oldPosInc,
10897
10836
  lastComponent: {
10898
10837
  count: last.count + 1,
10899
10838
  added,
@@ -10903,7 +10842,7 @@ var init_lib = __esm({
10903
10842
  };
10904
10843
  } else {
10905
10844
  return {
10906
- oldPos: path59.oldPos + oldPosInc,
10845
+ oldPos: path58.oldPos + oldPosInc,
10907
10846
  lastComponent: {
10908
10847
  count: 1,
10909
10848
  added,
@@ -11349,10 +11288,10 @@ function attachmentToHistoryMessage(o, ts) {
11349
11288
  const memories = raw.map((m2) => {
11350
11289
  if (!m2 || typeof m2 !== "object") return null;
11351
11290
  const rec3 = m2;
11352
- const path59 = typeof rec3.path === "string" ? rec3.path : null;
11291
+ const path58 = typeof rec3.path === "string" ? rec3.path : null;
11353
11292
  const content = typeof rec3.content === "string" ? rec3.content : null;
11354
- if (!path59 || content == null) return null;
11355
- const entry = { path: path59, content };
11293
+ if (!path58 || content == null) return null;
11294
+ const entry = { path: path58, content };
11356
11295
  if (typeof rec3.mtimeMs === "number") entry.mtimeMs = rec3.mtimeMs;
11357
11296
  return entry;
11358
11297
  }).filter((m2) => m2 !== null);
@@ -11872,9 +11811,6 @@ function buildSpawnArgs(ctx) {
11872
11811
  if (ctx.addDirs) {
11873
11812
  for (const dir of ctx.addDirs) args.push("--add-dir", dir);
11874
11813
  }
11875
- if (ctx.dispatchMcpConfigPath) {
11876
- args.push("--mcp-config", ctx.dispatchMcpConfigPath);
11877
- }
11878
11814
  if (ctx.effort) args.push("--effort", ctx.effort);
11879
11815
  if (ctx.toolSessionId) args.push("--resume", ctx.toolSessionId);
11880
11816
  return args;
@@ -12154,10 +12090,10 @@ function parseAttachment(obj) {
12154
12090
  const memories = raw.map((m2) => {
12155
12091
  if (!m2 || typeof m2 !== "object") return null;
12156
12092
  const rec3 = m2;
12157
- const path59 = typeof rec3.path === "string" ? rec3.path : null;
12093
+ const path58 = typeof rec3.path === "string" ? rec3.path : null;
12158
12094
  const content = typeof rec3.content === "string" ? rec3.content : null;
12159
- if (!path59 || content == null) return null;
12160
- const out = { path: path59, content };
12095
+ if (!path58 || content == null) return null;
12096
+ const out = { path: path58, content };
12161
12097
  if (typeof rec3.mtimeMs === "number") out.mtimeMs = rec3.mtimeMs;
12162
12098
  return out;
12163
12099
  }).filter((m2) => m2 !== null);
@@ -18187,7 +18123,7 @@ var require_validation = __commonJS({
18187
18123
  var require_receiver = __commonJS({
18188
18124
  "../node_modules/.pnpm/ws@8.20.0/node_modules/ws/lib/receiver.js"(exports2, module2) {
18189
18125
  "use strict";
18190
- var { Writable: Writable3 } = require("stream");
18126
+ var { Writable: Writable2 } = require("stream");
18191
18127
  var PerMessageDeflate2 = require_permessage_deflate();
18192
18128
  var {
18193
18129
  BINARY_TYPES,
@@ -18205,7 +18141,7 @@ var require_receiver = __commonJS({
18205
18141
  var GET_DATA = 4;
18206
18142
  var INFLATING = 5;
18207
18143
  var DEFER_EVENT = 6;
18208
- var Receiver2 = class extends Writable3 {
18144
+ var Receiver2 = class extends Writable2 {
18209
18145
  /**
18210
18146
  * Creates a Receiver instance.
18211
18147
  *
@@ -21468,7 +21404,7 @@ var require_stream_writable = __commonJS({
21468
21404
  "../node_modules/.pnpm/readable-stream@2.3.8/node_modules/readable-stream/lib/_stream_writable.js"(exports2, module2) {
21469
21405
  "use strict";
21470
21406
  var pna = require_process_nextick_args();
21471
- module2.exports = Writable3;
21407
+ module2.exports = Writable2;
21472
21408
  function CorkedRequest(state) {
21473
21409
  var _this = this;
21474
21410
  this.next = null;
@@ -21479,7 +21415,7 @@ var require_stream_writable = __commonJS({
21479
21415
  }
21480
21416
  var asyncWrite = !process.browser && ["v0.10", "v0.9."].indexOf(process.version.slice(0, 5)) > -1 ? setImmediate : pna.nextTick;
21481
21417
  var Duplex;
21482
- Writable3.WritableState = WritableState;
21418
+ Writable2.WritableState = WritableState;
21483
21419
  var util2 = Object.create(require_util());
21484
21420
  util2.inherits = require_inherits();
21485
21421
  var internalUtil = {
@@ -21496,7 +21432,7 @@ var require_stream_writable = __commonJS({
21496
21432
  return Buffer2.isBuffer(obj) || obj instanceof OurUint8Array;
21497
21433
  }
21498
21434
  var destroyImpl = require_destroy();
21499
- util2.inherits(Writable3, Stream);
21435
+ util2.inherits(Writable2, Stream);
21500
21436
  function nop() {
21501
21437
  }
21502
21438
  function WritableState(options, stream) {
@@ -21561,10 +21497,10 @@ var require_stream_writable = __commonJS({
21561
21497
  var realHasInstance;
21562
21498
  if (typeof Symbol === "function" && Symbol.hasInstance && typeof Function.prototype[Symbol.hasInstance] === "function") {
21563
21499
  realHasInstance = Function.prototype[Symbol.hasInstance];
21564
- Object.defineProperty(Writable3, Symbol.hasInstance, {
21500
+ Object.defineProperty(Writable2, Symbol.hasInstance, {
21565
21501
  value: function(object) {
21566
21502
  if (realHasInstance.call(this, object)) return true;
21567
- if (this !== Writable3) return false;
21503
+ if (this !== Writable2) return false;
21568
21504
  return object && object._writableState instanceof WritableState;
21569
21505
  }
21570
21506
  });
@@ -21573,10 +21509,10 @@ var require_stream_writable = __commonJS({
21573
21509
  return object instanceof this;
21574
21510
  };
21575
21511
  }
21576
- function Writable3(options) {
21512
+ function Writable2(options) {
21577
21513
  Duplex = Duplex || require_stream_duplex();
21578
- if (!realHasInstance.call(Writable3, this) && !(this instanceof Duplex)) {
21579
- return new Writable3(options);
21514
+ if (!realHasInstance.call(Writable2, this) && !(this instanceof Duplex)) {
21515
+ return new Writable2(options);
21580
21516
  }
21581
21517
  this._writableState = new WritableState(options, this);
21582
21518
  this.writable = true;
@@ -21588,7 +21524,7 @@ var require_stream_writable = __commonJS({
21588
21524
  }
21589
21525
  Stream.call(this);
21590
21526
  }
21591
- Writable3.prototype.pipe = function() {
21527
+ Writable2.prototype.pipe = function() {
21592
21528
  this.emit("error", new Error("Cannot pipe, not readable"));
21593
21529
  };
21594
21530
  function writeAfterEnd(stream, cb) {
@@ -21611,7 +21547,7 @@ var require_stream_writable = __commonJS({
21611
21547
  }
21612
21548
  return valid;
21613
21549
  }
21614
- Writable3.prototype.write = function(chunk, encoding, cb) {
21550
+ Writable2.prototype.write = function(chunk, encoding, cb) {
21615
21551
  var state = this._writableState;
21616
21552
  var ret = false;
21617
21553
  var isBuf = !state.objectMode && _isUint8Array(chunk);
@@ -21632,18 +21568,18 @@ var require_stream_writable = __commonJS({
21632
21568
  }
21633
21569
  return ret;
21634
21570
  };
21635
- Writable3.prototype.cork = function() {
21571
+ Writable2.prototype.cork = function() {
21636
21572
  var state = this._writableState;
21637
21573
  state.corked++;
21638
21574
  };
21639
- Writable3.prototype.uncork = function() {
21575
+ Writable2.prototype.uncork = function() {
21640
21576
  var state = this._writableState;
21641
21577
  if (state.corked) {
21642
21578
  state.corked--;
21643
21579
  if (!state.writing && !state.corked && !state.bufferProcessing && state.bufferedRequest) clearBuffer(this, state);
21644
21580
  }
21645
21581
  };
21646
- Writable3.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) {
21582
+ Writable2.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) {
21647
21583
  if (typeof encoding === "string") encoding = encoding.toLowerCase();
21648
21584
  if (!(["hex", "utf8", "utf-8", "ascii", "binary", "base64", "ucs2", "ucs-2", "utf16le", "utf-16le", "raw"].indexOf((encoding + "").toLowerCase()) > -1)) throw new TypeError("Unknown encoding: " + encoding);
21649
21585
  this._writableState.defaultEncoding = encoding;
@@ -21655,7 +21591,7 @@ var require_stream_writable = __commonJS({
21655
21591
  }
21656
21592
  return chunk;
21657
21593
  }
21658
- Object.defineProperty(Writable3.prototype, "writableHighWaterMark", {
21594
+ Object.defineProperty(Writable2.prototype, "writableHighWaterMark", {
21659
21595
  // making it explicit this property is not enumerable
21660
21596
  // because otherwise some prototype manipulation in
21661
21597
  // userland will fail
@@ -21801,11 +21737,11 @@ var require_stream_writable = __commonJS({
21801
21737
  state.bufferedRequest = entry;
21802
21738
  state.bufferProcessing = false;
21803
21739
  }
21804
- Writable3.prototype._write = function(chunk, encoding, cb) {
21740
+ Writable2.prototype._write = function(chunk, encoding, cb) {
21805
21741
  cb(new Error("_write() is not implemented"));
21806
21742
  };
21807
- Writable3.prototype._writev = null;
21808
- Writable3.prototype.end = function(chunk, encoding, cb) {
21743
+ Writable2.prototype._writev = null;
21744
+ Writable2.prototype.end = function(chunk, encoding, cb) {
21809
21745
  var state = this._writableState;
21810
21746
  if (typeof chunk === "function") {
21811
21747
  cb = chunk;
@@ -21880,7 +21816,7 @@ var require_stream_writable = __commonJS({
21880
21816
  }
21881
21817
  state.corkedRequestsFree.next = corkReq;
21882
21818
  }
21883
- Object.defineProperty(Writable3.prototype, "destroyed", {
21819
+ Object.defineProperty(Writable2.prototype, "destroyed", {
21884
21820
  get: function() {
21885
21821
  if (this._writableState === void 0) {
21886
21822
  return false;
@@ -21894,9 +21830,9 @@ var require_stream_writable = __commonJS({
21894
21830
  this._writableState.destroyed = value;
21895
21831
  }
21896
21832
  });
21897
- Writable3.prototype.destroy = destroyImpl.destroy;
21898
- Writable3.prototype._undestroy = destroyImpl.undestroy;
21899
- Writable3.prototype._destroy = function(err, cb) {
21833
+ Writable2.prototype.destroy = destroyImpl.destroy;
21834
+ Writable2.prototype._undestroy = destroyImpl.undestroy;
21835
+ Writable2.prototype._destroy = function(err, cb) {
21900
21836
  this.end();
21901
21837
  cb(err);
21902
21838
  };
@@ -21919,13 +21855,13 @@ var require_stream_duplex = __commonJS({
21919
21855
  var util2 = Object.create(require_util());
21920
21856
  util2.inherits = require_inherits();
21921
21857
  var Readable3 = require_stream_readable();
21922
- var Writable3 = require_stream_writable();
21858
+ var Writable2 = require_stream_writable();
21923
21859
  util2.inherits(Duplex, Readable3);
21924
21860
  {
21925
- keys = objectKeys(Writable3.prototype);
21861
+ keys = objectKeys(Writable2.prototype);
21926
21862
  for (v2 = 0; v2 < keys.length; v2++) {
21927
21863
  method = keys[v2];
21928
- if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable3.prototype[method];
21864
+ if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable2.prototype[method];
21929
21865
  }
21930
21866
  }
21931
21867
  var keys;
@@ -21934,7 +21870,7 @@ var require_stream_duplex = __commonJS({
21934
21870
  function Duplex(options) {
21935
21871
  if (!(this instanceof Duplex)) return new Duplex(options);
21936
21872
  Readable3.call(this, options);
21937
- Writable3.call(this, options);
21873
+ Writable2.call(this, options);
21938
21874
  if (options && options.readable === false) this.readable = false;
21939
21875
  if (options && options.writable === false) this.writable = false;
21940
21876
  this.allowHalfOpen = true;
@@ -23944,8 +23880,8 @@ var require_utils = __commonJS({
23944
23880
  var result = transform[inputType][outputType](input);
23945
23881
  return result;
23946
23882
  };
23947
- exports2.resolve = function(path59) {
23948
- var parts = path59.split("/");
23883
+ exports2.resolve = function(path58) {
23884
+ var parts = path58.split("/");
23949
23885
  var result = [];
23950
23886
  for (var index = 0; index < parts.length; index++) {
23951
23887
  var part = parts[index];
@@ -29798,18 +29734,18 @@ var require_object = __commonJS({
29798
29734
  var object = new ZipObject(name, zipObjectContent, o);
29799
29735
  this.files[name] = object;
29800
29736
  };
29801
- var parentFolder = function(path59) {
29802
- if (path59.slice(-1) === "/") {
29803
- path59 = path59.substring(0, path59.length - 1);
29737
+ var parentFolder = function(path58) {
29738
+ if (path58.slice(-1) === "/") {
29739
+ path58 = path58.substring(0, path58.length - 1);
29804
29740
  }
29805
- var lastSlash = path59.lastIndexOf("/");
29806
- return lastSlash > 0 ? path59.substring(0, lastSlash) : "";
29741
+ var lastSlash = path58.lastIndexOf("/");
29742
+ return lastSlash > 0 ? path58.substring(0, lastSlash) : "";
29807
29743
  };
29808
- var forceTrailingSlash = function(path59) {
29809
- if (path59.slice(-1) !== "/") {
29810
- path59 += "/";
29744
+ var forceTrailingSlash = function(path58) {
29745
+ if (path58.slice(-1) !== "/") {
29746
+ path58 += "/";
29811
29747
  }
29812
- return path59;
29748
+ return path58;
29813
29749
  };
29814
29750
  var folderAdd = function(name, createFolders) {
29815
29751
  createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
@@ -30811,7 +30747,7 @@ var require_lib3 = __commonJS({
30811
30747
  // src/run-case/recorder.ts
30812
30748
  function startRunCaseRecorder(opts) {
30813
30749
  const now = opts.now ?? Date.now;
30814
- const dir = import_node_path47.default.dirname(opts.recordPath);
30750
+ const dir = import_node_path46.default.dirname(opts.recordPath);
30815
30751
  let stream = null;
30816
30752
  let closing = false;
30817
30753
  let closedSettled = false;
@@ -30825,8 +30761,8 @@ function startRunCaseRecorder(opts) {
30825
30761
  });
30826
30762
  const ensureStream = () => {
30827
30763
  if (stream) return stream;
30828
- import_node_fs35.default.mkdirSync(dir, { recursive: true });
30829
- stream = import_node_fs35.default.createWriteStream(opts.recordPath, { flags: "a" });
30764
+ import_node_fs34.default.mkdirSync(dir, { recursive: true });
30765
+ stream = import_node_fs34.default.createWriteStream(opts.recordPath, { flags: "a" });
30830
30766
  stream.on("close", () => closedResolve());
30831
30767
  return stream;
30832
30768
  };
@@ -30851,12 +30787,12 @@ function startRunCaseRecorder(opts) {
30851
30787
  };
30852
30788
  return { tap, close, closed };
30853
30789
  }
30854
- var import_node_fs35, import_node_path47;
30790
+ var import_node_fs34, import_node_path46;
30855
30791
  var init_recorder = __esm({
30856
30792
  "src/run-case/recorder.ts"() {
30857
30793
  "use strict";
30858
- import_node_fs35 = __toESM(require("fs"), 1);
30859
- import_node_path47 = __toESM(require("path"), 1);
30794
+ import_node_fs34 = __toESM(require("fs"), 1);
30795
+ import_node_path46 = __toESM(require("path"), 1);
30860
30796
  }
30861
30797
  });
30862
30798
 
@@ -30899,7 +30835,7 @@ var init_wire = __esm({
30899
30835
  // src/run-case/controller.ts
30900
30836
  async function runController(opts) {
30901
30837
  const now = opts.now ?? Date.now;
30902
- const cwd = opts.cwd ?? (0, import_node_fs36.mkdtempSync)(import_node_path48.default.join(import_node_os20.default.tmpdir(), "clawd-runcase-"));
30838
+ const cwd = opts.cwd ?? (0, import_node_fs35.mkdtempSync)(import_node_path47.default.join(import_node_os19.default.tmpdir(), "clawd-runcase-"));
30903
30839
  const ownsCwd = opts.cwd === void 0;
30904
30840
  const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
30905
30841
  const spawnCtx = { cwd };
@@ -31060,19 +30996,19 @@ async function runController(opts) {
31060
30996
  if (sigintHandler) process.off("SIGINT", sigintHandler);
31061
30997
  if (ownsCwd) {
31062
30998
  try {
31063
- (0, import_node_fs36.rmSync)(cwd, { recursive: true, force: true });
30999
+ (0, import_node_fs35.rmSync)(cwd, { recursive: true, force: true });
31064
31000
  } catch {
31065
31001
  }
31066
31002
  }
31067
31003
  return exitCode ?? 0;
31068
31004
  }
31069
- var import_node_fs36, import_node_os20, import_node_path48;
31005
+ var import_node_fs35, import_node_os19, import_node_path47;
31070
31006
  var init_controller = __esm({
31071
31007
  "src/run-case/controller.ts"() {
31072
31008
  "use strict";
31073
- import_node_fs36 = require("fs");
31074
- import_node_os20 = __toESM(require("os"), 1);
31075
- import_node_path48 = __toESM(require("path"), 1);
31009
+ import_node_fs35 = require("fs");
31010
+ import_node_os19 = __toESM(require("os"), 1);
31011
+ import_node_path47 = __toESM(require("path"), 1);
31076
31012
  init_claude();
31077
31013
  init_stdout_splitter();
31078
31014
  init_permission_stdio();
@@ -31176,24 +31112,6 @@ init_protocol();
31176
31112
  var DEFAULT_PORT = 18790;
31177
31113
  var DEFAULT_HOST = "127.0.0.1";
31178
31114
  var DEFAULT_CLAWOS_API = "https://api.clawos.chat";
31179
- var DEFAULT_LOG_ENDPOINT = "https://clawd-prod.cn-hangzhou.log.aliyuncs.com/logstores/app-logs/track";
31180
- function resolveLogShipping(raw, cliNoShipping) {
31181
- if (cliNoShipping) {
31182
- return { mode: "off", endpoint: null, sampling: {} };
31183
- }
31184
- const rawMode = raw?.mode;
31185
- const mode = rawMode === "off" || rawMode === "errors-only" ? rawMode : "on";
31186
- if (mode === "off") {
31187
- return { mode, endpoint: null, sampling: {} };
31188
- }
31189
- const endpoint = typeof raw?.endpoint === "string" && raw.endpoint ? raw.endpoint : raw?.endpoint === null ? null : DEFAULT_LOG_ENDPOINT;
31190
- const sampling = mode === "errors-only" ? { debug: 0, info: 0, warn: 1, error: 1 } : isPlainSamplingMap(raw?.sampling) ? raw.sampling : {};
31191
- return { mode, endpoint, sampling };
31192
- }
31193
- function isPlainSamplingMap(v2) {
31194
- if (!v2 || typeof v2 !== "object") return false;
31195
- return Object.values(v2).every((n) => typeof n === "number");
31196
- }
31197
31115
  function parseArgs(argv) {
31198
31116
  const out = {};
31199
31117
  for (let i = 0; i < argv.length; i++) {
@@ -31239,9 +31157,6 @@ function parseArgs(argv) {
31239
31157
  case "-v":
31240
31158
  out.version = true;
31241
31159
  break;
31242
- case "--no-log-shipping":
31243
- out.noLogShipping = true;
31244
- break;
31245
31160
  default:
31246
31161
  if (a.startsWith("--")) throw new Error(`unknown flag: ${a}`);
31247
31162
  break;
@@ -31287,10 +31202,6 @@ function resolveConfig(opts) {
31287
31202
  const mode = DAEMON_MODE_VALUES.includes(rawMode ?? "") ? rawMode : "sdk";
31288
31203
  const filePreviewPorts = Array.isArray(fileCfg.previewPorts) ? fileCfg.previewPorts.map((n) => Number(n)).filter((n) => Number.isInteger(n) && n > 0) : null;
31289
31204
  const previewPorts = env.CLAWD_PREVIEW_PORTS ? env.CLAWD_PREVIEW_PORTS.split(",").map((s) => Number(s.trim())).filter((n) => Number.isInteger(n) && n > 0) : filePreviewPorts && filePreviewPorts.length > 0 ? filePreviewPorts : null;
31290
- const logShipping = resolveLogShipping(
31291
- fileCfg.logShipping,
31292
- args.noLogShipping ?? false
31293
- );
31294
31205
  return {
31295
31206
  port,
31296
31207
  host,
@@ -31303,8 +31214,7 @@ function resolveConfig(opts) {
31303
31214
  noTunnelPersist,
31304
31215
  frpcBinary,
31305
31216
  mode,
31306
- previewPorts,
31307
- logShipping
31217
+ previewPorts
31308
31218
  };
31309
31219
  }
31310
31220
  var HELP_TEXT = `clawd [options]
@@ -31315,7 +31225,6 @@ var HELP_TEXT = `clawd [options]
31315
31225
  --tunnel \u542F\u7528 frp tunnel \u628A\u672C\u5730\u7AEF\u53E3\u66B4\u9732\u5230\u516C\u7F51
31316
31226
  --clawos-api <url> tunnel register \u63A5\u53E3\u7684 base url\uFF08\u9ED8\u8BA4 https://api.clawos.chat\uFF09
31317
31227
  --auth-token <s> \u6307\u5B9A daemon auth token\uFF1B\u7F3A\u7701\u65F6 tunnel \u6A21\u5F0F\u4ECE ~/.clawd/auth.json \u590D\u7528\uFF0C\u6CA1\u6709\u5C31\u751F\u6210
31318
- --no-log-shipping \u7981\u7528 SLS \u65E5\u5FD7\u4E0A\u884C\uFF08\u8986\u76D6 config.json logShipping.mode=off\uFF09
31319
31228
  --help / -h \u663E\u793A\u5E2E\u52A9
31320
31229
  --version / -v \u663E\u793A\u7248\u672C
31321
31230
 
@@ -31334,64 +31243,12 @@ Env (advanced):
31334
31243
  `;
31335
31244
 
31336
31245
  // src/index.ts
31337
- var import_node_path46 = __toESM(require("path"), 1);
31338
- var import_node_fs34 = __toESM(require("fs"), 1);
31339
- var import_node_os19 = __toESM(require("os"), 1);
31340
-
31341
- // ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/stringify.js
31342
- var byteToHex = [];
31343
- for (let i = 0; i < 256; ++i) {
31344
- byteToHex.push((i + 256).toString(16).slice(1));
31345
- }
31346
- function unsafeStringify(arr, offset = 0) {
31347
- return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
31348
- }
31349
-
31350
- // ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/rng.js
31351
- var import_node_crypto = __toESM(require("crypto"));
31352
- var rnds8Pool = new Uint8Array(256);
31353
- var poolPtr = rnds8Pool.length;
31354
- function rng() {
31355
- if (poolPtr > rnds8Pool.length - 16) {
31356
- import_node_crypto.default.randomFillSync(rnds8Pool);
31357
- poolPtr = 0;
31358
- }
31359
- return rnds8Pool.slice(poolPtr, poolPtr += 16);
31360
- }
31361
-
31362
- // ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/native.js
31363
- var import_node_crypto2 = __toESM(require("crypto"));
31364
- var native_default = {
31365
- randomUUID: import_node_crypto2.default.randomUUID
31366
- };
31367
-
31368
- // ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/v4.js
31369
- function v4(options, buf, offset) {
31370
- if (native_default.randomUUID && !buf && !options) {
31371
- return native_default.randomUUID();
31372
- }
31373
- options = options || {};
31374
- const rnds = options.random || (options.rng || rng)();
31375
- rnds[6] = rnds[6] & 15 | 64;
31376
- rnds[8] = rnds[8] & 63 | 128;
31377
- if (buf) {
31378
- offset = offset || 0;
31379
- for (let i = 0; i < 16; ++i) {
31380
- buf[offset + i] = rnds[i];
31381
- }
31382
- return buf;
31383
- }
31384
- return unsafeStringify(rnds);
31385
- }
31386
- var v4_default = v4;
31387
-
31388
- // src/index.ts
31389
- var import_node_url2 = require("url");
31246
+ var import_node_path45 = __toESM(require("path"), 1);
31247
+ var import_node_fs33 = __toESM(require("fs"), 1);
31390
31248
 
31391
31249
  // src/logger.ts
31392
31250
  var import_node_fs2 = __toESM(require("fs"), 1);
31393
31251
  var import_node_path2 = __toESM(require("path"), 1);
31394
- var import_node_stream = require("stream");
31395
31252
  var import_pino = __toESM(require_pino(), 1);
31396
31253
  function wrap(inner) {
31397
31254
  return {
@@ -31417,329 +31274,12 @@ function createLogger(opts = {}) {
31417
31274
  } catch {
31418
31275
  }
31419
31276
  }
31420
- if (opts.logClient) {
31421
- const client = opts.logClient;
31422
- const sink = new import_node_stream.Writable({
31423
- write(chunk, _enc, cb) {
31424
- try {
31425
- const line = String(chunk).trim();
31426
- if (line) {
31427
- const obj = JSON.parse(line);
31428
- const lvl = pinoLevelToString(obj.level);
31429
- if (lvl) {
31430
- const meta = {};
31431
- for (const [k2, v2] of Object.entries(obj)) {
31432
- if (k2 === "level" || k2 === "msg" || k2 === "time" || k2 === "pid" || k2 === "hostname") continue;
31433
- if (k2 === "sessionId") continue;
31434
- meta[k2] = v2;
31435
- }
31436
- client.push({
31437
- ts: typeof obj.time === "number" ? obj.time : void 0,
31438
- level: lvl,
31439
- msg: typeof obj.msg === "string" ? obj.msg : "",
31440
- meta: Object.keys(meta).length > 0 ? meta : void 0,
31441
- sessionId: typeof obj.sessionId === "string" ? obj.sessionId : void 0
31442
- });
31443
- }
31444
- }
31445
- } catch {
31446
- }
31447
- cb();
31448
- }
31449
- });
31450
- streams.push({ stream: sink, level });
31451
- }
31452
31277
  const base = (0, import_pino.default)(
31453
31278
  { level, base: { pid: process.pid } },
31454
31279
  import_pino.default.multistream(streams)
31455
31280
  );
31456
31281
  return wrap(base);
31457
31282
  }
31458
- function pinoLevelToString(n) {
31459
- if (typeof n !== "number") return null;
31460
- if (n >= 50) return "error";
31461
- if (n >= 40) return "warn";
31462
- if (n >= 30) return "info";
31463
- if (n >= 20) return "debug";
31464
- return null;
31465
- }
31466
-
31467
- // ../log-client/src/types.ts
31468
- var DEFAULT_BATCH = {
31469
- maxRecords: 100,
31470
- maxBytes: 512 * 1024,
31471
- maxWaitMs: 5e3
31472
- };
31473
- var DEFAULT_BUFFER_CAP = 5e3;
31474
- var DEFAULT_SAMPLING = {
31475
- debug: 0,
31476
- info: 1,
31477
- warn: 1,
31478
- error: 1
31479
- };
31480
- var MAX_MSG_BYTES = 1024;
31481
- var MAX_META_JSON_BYTES = 2048;
31482
- var REDACT_KEY_REGEX = /token|secret|password|auth(?!or)|apikey|signsecret/i;
31483
- var REDACTED_PLACEHOLDER = "[REDACTED]";
31484
-
31485
- // ../log-client/src/redactor.ts
31486
- var TRUNCATE_SUFFIX = "\u2026[truncated]";
31487
- function redactMeta(meta, homeDir) {
31488
- const cleaned = cleanValue(meta, homeDir, 0);
31489
- const json = safeStringify(cleaned);
31490
- if (json.length <= MAX_META_JSON_BYTES) return cleaned;
31491
- const truncated = json.slice(0, MAX_META_JSON_BYTES) + TRUNCATE_SUFFIX;
31492
- return { __truncated__: truncated };
31493
- }
31494
- function cleanValue(v2, homeDir, depth) {
31495
- if (depth > 10) return "[depth-limit]";
31496
- if (v2 == null) return v2;
31497
- if (typeof v2 === "string") {
31498
- return homeDir ? v2.split(homeDir).join("~") : v2;
31499
- }
31500
- if (typeof v2 !== "object") return v2;
31501
- if (Array.isArray(v2)) return v2.map((x) => cleanValue(x, homeDir, depth + 1));
31502
- const out = {};
31503
- for (const [k2, val] of Object.entries(v2)) {
31504
- if (REDACT_KEY_REGEX.test(k2)) {
31505
- out[k2] = REDACTED_PLACEHOLDER;
31506
- } else {
31507
- out[k2] = cleanValue(val, homeDir, depth + 1);
31508
- }
31509
- }
31510
- return out;
31511
- }
31512
- function safeStringify(v2) {
31513
- try {
31514
- return JSON.stringify(v2) ?? "";
31515
- } catch {
31516
- return '"[serialize-failed]"';
31517
- }
31518
- }
31519
- function truncateMsg(msg) {
31520
- if (msg.length <= MAX_MSG_BYTES) return msg;
31521
- return msg.slice(0, MAX_MSG_BYTES) + TRUNCATE_SUFFIX;
31522
- }
31523
-
31524
- // ../log-client/src/sampling.ts
31525
- function shouldSample(level, config, rng2) {
31526
- const rate = config[level] ?? DEFAULT_SAMPLING[level];
31527
- if (rate <= 0) return false;
31528
- if (rate >= 1) return true;
31529
- return rng2() < rate;
31530
- }
31531
-
31532
- // ../log-client/src/batcher.ts
31533
- var Batcher = class {
31534
- constructor(deps) {
31535
- this.deps = deps;
31536
- }
31537
- deps;
31538
- queue = [];
31539
- bytes = 0;
31540
- droppedSinceFlush = 0;
31541
- identityReady = false;
31542
- timer = null;
31543
- disposed = false;
31544
- pendingSends = [];
31545
- enqueue(record) {
31546
- if (this.disposed) return;
31547
- const sz = approxSize(record);
31548
- while (this.queue.length >= this.deps.bufferCap) {
31549
- this.queue.shift();
31550
- this.droppedSinceFlush++;
31551
- }
31552
- this.queue.push(record);
31553
- this.bytes += sz;
31554
- if (!this.identityReady) return;
31555
- this.maybeTrigger();
31556
- }
31557
- setIdentityReady(ready) {
31558
- this.identityReady = ready;
31559
- if (ready && this.queue.length > 0) this.maybeTrigger();
31560
- }
31561
- async flush() {
31562
- if (this.queue.length > 0) {
31563
- this.fire("flush");
31564
- }
31565
- await Promise.allSettled(this.pendingSends);
31566
- }
31567
- stats() {
31568
- return { queued: this.queue.length, dropped: this.droppedSinceFlush };
31569
- }
31570
- async dispose() {
31571
- if (this.disposed) return;
31572
- this.disposed = true;
31573
- if (this.timer) {
31574
- clearTimeout(this.timer);
31575
- this.timer = null;
31576
- }
31577
- await this.flush();
31578
- }
31579
- maybeTrigger() {
31580
- const { maxRecords, maxBytes, maxWaitMs } = this.deps.batch;
31581
- if (this.queue.length >= maxRecords) {
31582
- this.fire("records");
31583
- return;
31584
- }
31585
- if (this.bytes >= maxBytes) {
31586
- this.fire("bytes");
31587
- return;
31588
- }
31589
- if (this.timer == null) {
31590
- this.timer = setTimeout(() => {
31591
- this.timer = null;
31592
- if (this.queue.length > 0 && this.identityReady) this.fire("time");
31593
- }, maxWaitMs);
31594
- }
31595
- }
31596
- fire(reason) {
31597
- if (this.timer) {
31598
- clearTimeout(this.timer);
31599
- this.timer = null;
31600
- }
31601
- const records = this.queue;
31602
- const droppedCarryover = this.droppedSinceFlush;
31603
- this.queue = [];
31604
- this.bytes = 0;
31605
- this.droppedSinceFlush = 0;
31606
- const p2 = this.deps.onBatch({ reason, records, droppedCarryover }).catch(() => {
31607
- });
31608
- this.pendingSends.push(p2);
31609
- p2.finally(() => {
31610
- this.pendingSends = this.pendingSends.filter((x) => x !== p2);
31611
- });
31612
- }
31613
- };
31614
- function approxSize(record) {
31615
- return (record.msg?.length ?? 0) + (record.meta_json?.length ?? 0) + 200;
31616
- }
31617
-
31618
- // ../log-client/src/sender.ts
31619
- var BACKOFF_MS = [1e3, 2e3, 4e3];
31620
- async function sendBatch(deps, batch) {
31621
- const body = JSON.stringify({
31622
- __topic__: deps.topic ?? "clawd",
31623
- __source__: deps.source,
31624
- __logs__: batch.records,
31625
- __dropped__: batch.droppedCarryover
31626
- });
31627
- for (let attempt = 0; attempt < BACKOFF_MS.length; attempt++) {
31628
- if (attempt > 0) await sleep(BACKOFF_MS[attempt - 1]);
31629
- try {
31630
- const res = await deps.fetchImpl(deps.endpoint, {
31631
- method: "POST",
31632
- headers: { "Content-Type": "application/json" },
31633
- body
31634
- });
31635
- if (res.status >= 200 && res.status < 300) {
31636
- return { sent: batch.records.length, failed: 0 };
31637
- }
31638
- if (res.status >= 400 && res.status < 500) {
31639
- return { sent: 0, failed: batch.records.length };
31640
- }
31641
- } catch {
31642
- }
31643
- }
31644
- return { sent: 0, failed: batch.records.length };
31645
- }
31646
- function sleep(ms) {
31647
- return new Promise((r) => setTimeout(r, ms));
31648
- }
31649
-
31650
- // ../log-client/src/client.ts
31651
- function createLogClient(opts) {
31652
- const stats = { sent: 0, dropped: 0, queued: 0, failed: 0 };
31653
- const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
31654
- const now = opts.now ?? Date.now;
31655
- const sampling = { ...DEFAULT_SAMPLING, ...opts.sampling ?? {} };
31656
- const homeDir = opts.homeDir === void 0 ? null : opts.homeDir;
31657
- const batchConfig = { ...DEFAULT_BATCH, ...opts.batch ?? {} };
31658
- const bufferCap = opts.bufferCap ?? DEFAULT_BUFFER_CAP;
31659
- let identity = opts.identity;
31660
- let disposed = false;
31661
- if (opts.endpoint == null) {
31662
- return {
31663
- push: () => {
31664
- if (disposed) return;
31665
- stats.dropped++;
31666
- },
31667
- flush: async () => {
31668
- },
31669
- setIdentity: (next) => {
31670
- identity = next;
31671
- },
31672
- stats: () => ({ ...stats }),
31673
- dispose: async () => {
31674
- disposed = true;
31675
- }
31676
- };
31677
- }
31678
- const endpoint = opts.endpoint;
31679
- const batcher = new Batcher({
31680
- batch: batchConfig,
31681
- bufferCap,
31682
- now,
31683
- onBatch: async (b2) => {
31684
- const res = await sendBatch({ endpoint, source: opts.source, fetchImpl }, b2);
31685
- stats.sent += res.sent;
31686
- stats.failed += res.failed;
31687
- }
31688
- });
31689
- batcher.setIdentityReady(identity != null);
31690
- return {
31691
- push(input) {
31692
- if (disposed) return;
31693
- try {
31694
- if (!shouldSample(input.level, sampling, Math.random)) {
31695
- stats.dropped++;
31696
- return;
31697
- }
31698
- const record = buildRecord(input, identity, opts.source, homeDir, now);
31699
- batcher.enqueue(record);
31700
- } catch {
31701
- }
31702
- },
31703
- async flush() {
31704
- try {
31705
- await batcher.flush();
31706
- } catch {
31707
- }
31708
- },
31709
- setIdentity(next) {
31710
- identity = next;
31711
- batcher.setIdentityReady(next != null);
31712
- },
31713
- stats() {
31714
- const bs = batcher.stats();
31715
- return { ...stats, queued: bs.queued, dropped: stats.dropped + bs.dropped };
31716
- },
31717
- async dispose() {
31718
- disposed = true;
31719
- try {
31720
- await batcher.dispose();
31721
- } catch {
31722
- }
31723
- }
31724
- };
31725
- }
31726
- function buildRecord(input, identity, source, homeDir, now) {
31727
- const cleanedMeta = input.meta ? redactMeta(input.meta, homeDir) : void 0;
31728
- const meta_json = cleanedMeta ? JSON.stringify(cleanedMeta) : void 0;
31729
- return {
31730
- ts: input.ts ?? now(),
31731
- source,
31732
- level: input.level,
31733
- msg: truncateMsg(input.msg),
31734
- ownerPrincipalId: identity?.ownerPrincipalId ?? "__pending__",
31735
- deviceId: identity?.deviceId ?? "__pending__",
31736
- appVersion: identity?.appVersion ?? "__pending__",
31737
- daemonVersion: identity?.daemonVersion,
31738
- os: identity?.os ?? "unknown",
31739
- meta_json,
31740
- sessionId: input.sessionId
31741
- };
31742
- }
31743
31283
 
31744
31284
  // src/session/store-factory.ts
31745
31285
  var path5 = __toESM(require("path"), 1);
@@ -31946,6 +31486,55 @@ var SessionStoreFactory = class {
31946
31486
  var import_node_fs6 = __toESM(require("fs"), 1);
31947
31487
  var import_node_path6 = __toESM(require("path"), 1);
31948
31488
  var import_node_os2 = __toESM(require("os"), 1);
31489
+
31490
+ // ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/stringify.js
31491
+ var byteToHex = [];
31492
+ for (let i = 0; i < 256; ++i) {
31493
+ byteToHex.push((i + 256).toString(16).slice(1));
31494
+ }
31495
+ function unsafeStringify(arr, offset = 0) {
31496
+ return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
31497
+ }
31498
+
31499
+ // ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/rng.js
31500
+ var import_node_crypto = __toESM(require("crypto"));
31501
+ var rnds8Pool = new Uint8Array(256);
31502
+ var poolPtr = rnds8Pool.length;
31503
+ function rng() {
31504
+ if (poolPtr > rnds8Pool.length - 16) {
31505
+ import_node_crypto.default.randomFillSync(rnds8Pool);
31506
+ poolPtr = 0;
31507
+ }
31508
+ return rnds8Pool.slice(poolPtr, poolPtr += 16);
31509
+ }
31510
+
31511
+ // ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/native.js
31512
+ var import_node_crypto2 = __toESM(require("crypto"));
31513
+ var native_default = {
31514
+ randomUUID: import_node_crypto2.default.randomUUID
31515
+ };
31516
+
31517
+ // ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/v4.js
31518
+ function v4(options, buf, offset) {
31519
+ if (native_default.randomUUID && !buf && !options) {
31520
+ return native_default.randomUUID();
31521
+ }
31522
+ options = options || {};
31523
+ const rnds = options.random || (options.rng || rng)();
31524
+ rnds[6] = rnds[6] & 15 | 64;
31525
+ rnds[8] = rnds[8] & 63 | 128;
31526
+ if (buf) {
31527
+ offset = offset || 0;
31528
+ for (let i = 0; i < 16; ++i) {
31529
+ buf[offset + i] = rnds[i];
31530
+ }
31531
+ return buf;
31532
+ }
31533
+ return unsafeStringify(rnds);
31534
+ }
31535
+ var v4_default = v4;
31536
+
31537
+ // src/session/manager.ts
31949
31538
  init_protocol();
31950
31539
 
31951
31540
  // src/tools/guest-settings.ts
@@ -32070,32 +31659,6 @@ function buildConnectionPrompt(args) {
32070
31659
  return result;
32071
31660
  }
32072
31661
 
32073
- // src/dispatch/system-prompt.ts
32074
- var DISPATCH_SYSTEM_PROMPT_HINT = `## \u59D4\u6D3E\u7ED9\u53E6\u4E00\u4E2A persona\uFF08dispatch\uFF09
32075
-
32076
- \u5F53\u7528\u6237\u6D88\u606F\u91CC\u542B \`@persona/<id>\`\uFF08\u5982 \`@persona/persona-bug-fixer\`\uFF09\u65F6\uFF0C**\u4F60\u5FC5\u987B**\u7ACB\u5373\u8C03 MCP tool \`mcp__clawd-dispatch__personaDispatch\` \u59D4\u6D3E\uFF0C\u4E0D\u8981\u5C1D\u8BD5\u81EA\u5DF1\u6267\u884C\uFF1A
32077
-
32078
- - \`targetPersona = <id>\`\uFF08@ token \u91CC\u7684 persona id\uFF09
32079
- - \`prompt = \u53BB\u6389 @persona/<id> token \u7684\u7528\u6237\u539F\u6587\`
32080
-
32081
- tool \u4F1A\u963B\u585E\u6302\u8D77\u7B49\u5BF9\u65B9\u4EBA\u683C\u5E72\u5B8C\uFF0C\u628A outcome\uFF08\u542B text + \u53EF\u9009 filePaths\uFF09\u4F5C\u4E3A tool_result \u56DE\u7ED9\u4F60\uFF0C\u4F60\u518D\u7EFC\u5408\u56DE\u5E94\u7528\u6237\u3002
32082
-
32083
- - **\u4E0D\u8981**\u5C1D\u8BD5\u81EA\u5DF1\u6267\u884C\uFF08\u4F60\u4E0D\u662F\u90A3\u4E2A persona\uFF09
32084
- - **\u4E0D\u8981** in-place \u6A21\u4EFF\u5BF9\u65B9\u4EBA\u683C \u2014\u2014 dispatch \u662F\u771F\u5207\u5230\u53E6\u4E00\u4E2A\u72EC\u7ACB session
32085
- - \u4E00\u53E5\u8BDD\u91CC\u591A\u4E2A \`@persona/<id>\` \u65F6\u9009\u7B2C\u4E00\u4E2A\uFF08tool \u4E00\u6B21\u53EA\u5904\u7406\u4E00\u4E2A target\uFF09
32086
- - \u59D4\u6D3E\u5931\u8D25\uFF08tool_result.is_error=true\uFF09\u65F6\u5982\u5B9E\u544A\u8BC9\u7528\u6237\u539F\u56E0\uFF0C**\u4E0D\u8981\u91CD\u8BD5**
32087
-
32088
- ## \u88AB dispatch \u63A5\u5230\u4EFB\u52A1
32089
-
32090
- \u5982\u679C\u4F60\u7684 session \u7B2C\u4E00\u6761 user message \u662F\u4EE5 \`[Dispatched from owner \u2014 another persona session\u59D4\u6D3E\u7ED9\u4F60\u6267\u884C\u4EFB\u52A1]\` \u8D77\u5934\u7684 plain text \u4EFB\u52A1\u5305\uFF0C\u4F60\u662F\u88AB\u53E6\u4E00\u4E2A persona \u59D4\u6D3E\u6765\u5E72\u6D3B\u7684\uFF08\u4EFB\u52A1\u5305\u4E0D\u7528 \`<system-reminder>\` \u5305\u662F\u4E3A\u4E86 reducer dedup \u5DE5\u4F5C\u6B63\u5E38\uFF0C\u89C1 manager.ts buildDispatchTaskPack \u6CE8\u91CA\uFF09\uFF1A
32091
-
32092
- - \u4EFB\u52A1\u5728 \`Task:\` \u6BB5
32093
- - \u539F\u4F1A\u8BDD\u7684\u5BF9\u8BDD\u5386\u53F2\u5728 \`Source conversation\` \u6BB5\u7ED9\u7684 jsonl \u8DEF\u5F84\u4E0B\uFF1B\u6309\u9700 Read \u5B83\u4E86\u89E3\u4E0A\u4E0B\u6587\uFF08\u4E0D\u5FC5\u8BFB\u5B8C\uFF09
32094
- - \u5E72\u5B8C\u540E**\u5FC5\u987B**\u8C03 \`mcp__clawd-dispatch__personaDispatchComplete\` \u62A5\u544A\u7ED3\u679C\uFF1A
32095
- - \u6210\u529F\uFF1A\`{ text: "\u603B\u7ED3/\u7ED3\u8BBA", filePaths?: ["\u4F60\u4EA7\u51FA/\u6539\u7684\u6587\u4EF6\u7EDD\u5BF9\u8DEF\u5F84"] }\`
32096
- - \u5931\u8D25\uFF1A\`{ isFailure: true, reason: "..." }\`
32097
- - \u62A5\u544A\u5B8C\u540E\u4F60\u7684 session \u5C31\u7ED3\u675F\u4E86\uFF0C\u4E0D\u8981\u7EE7\u7EED\u8F93\u51FA`;
32098
-
32099
31662
  // src/session/reducer.ts
32100
31663
  function cloneState(s) {
32101
31664
  return {
@@ -32174,9 +31737,6 @@ function buildSpawnContext(state, deps) {
32174
31737
  env.CLAWD_SESSION_ID = file.sessionId;
32175
31738
  const daemonUrl = deps.getDaemonUrl?.() ?? null;
32176
31739
  if (daemonUrl) env.CLAWD_DAEMON_URL = daemonUrl;
32177
- const dispatchId = deps.lookupDispatchByBSessionId?.(file.sessionId);
32178
- if (dispatchId) env.CLAWD_DISPATCH_ID = dispatchId;
32179
- const dispatchMcpConfigPath2 = deps.getDispatchMcpConfigPath?.() ?? null;
32180
31740
  const ctx = {
32181
31741
  cwd: file.cwd,
32182
31742
  toolSessionId: file.toolSessionId,
@@ -32186,10 +31746,7 @@ function buildSpawnContext(state, deps) {
32186
31746
  env,
32187
31747
  // Phase 2 capability platform (plan §3): personaRoot 透传给 buildSpawnArgs;
32188
31748
  // 内部 shouldSandbox(cwd, personaRoot) 决定是否注入 --settings sandbox-settings.
32189
- personaRoot: deps.personaRoot,
32190
- // Persona dispatch:所有 session(A 和 B)都挂同一份 dispatch.mcp.json,让两边的 cc
32191
- // 都能看到 personaDispatch / personaDispatchComplete tool;按 env 区分实际行为。
32192
- dispatchMcpConfigPath: dispatchMcpConfigPath2 ?? void 0
31749
+ personaRoot: deps.personaRoot
32193
31750
  };
32194
31751
  const meta = state.subSessionMeta;
32195
31752
  if (meta?.personaMode) {
@@ -32200,9 +31757,6 @@ function buildSpawnContext(state, deps) {
32200
31757
  workDir: meta.userWorkDir
32201
31758
  });
32202
31759
  }
32203
- if (dispatchMcpConfigPath2) {
32204
- ctx.extraSystemPrompt = (ctx.extraSystemPrompt ? ctx.extraSystemPrompt + "\n\n" : "") + DISPATCH_SYSTEM_PROMPT_HINT;
32205
- }
32206
31760
  if (meta?.extraSettings) {
32207
31761
  ctx.extraSettings = meta.extraSettings;
32208
31762
  }
@@ -32868,6 +32422,35 @@ function startRecorder(opts) {
32868
32422
  };
32869
32423
  }
32870
32424
 
32425
+ // src/persona/mention-injection.ts
32426
+ var MENTION_RE = /@persona\/([A-Za-z0-9_-]+)(?=\s|$|[^A-Za-z0-9_-])/g;
32427
+ function injectPersonaMentions(rawText, store) {
32428
+ const resolved = [];
32429
+ const body = rawText.replace(MENTION_RE, (match, id) => {
32430
+ const meta = store.read(id);
32431
+ const personality = store.readPersonality(id);
32432
+ if (meta && personality !== null) {
32433
+ resolved.push({ label: meta.label, personality });
32434
+ return "";
32435
+ }
32436
+ return match;
32437
+ });
32438
+ if (resolved.length === 0) {
32439
+ return { systemReminder: null, userText: rawText };
32440
+ }
32441
+ const blocks = resolved.map((r) => {
32442
+ const safe = r.personality.replace(/<\/system-reminder>/gi, "</ system-reminder>");
32443
+ return `[Acting as persona "${r.label}" for this message]
32444
+ ${safe}`;
32445
+ });
32446
+ return {
32447
+ systemReminder: `<system-reminder>
32448
+ ${blocks.join("\n\n")}
32449
+ </system-reminder>`,
32450
+ userText: body.trim()
32451
+ };
32452
+ }
32453
+
32871
32454
  // src/session/runner.ts
32872
32455
  var DEFAULT_CONTROL_REQUEST_TIMEOUT_MS = 1e4;
32873
32456
  function encodeAllowWithInputControlResponse(requestId, updatedInput) {
@@ -32916,6 +32499,7 @@ var SessionRunner = class {
32916
32499
  }
32917
32500
  // 外部推送 input 到 reducer,然后执行产出的 effects
32918
32501
  input(inputMsg) {
32502
+ const personaStore = this.hooks.personaStore;
32919
32503
  const adapter = this.hooks.adapter;
32920
32504
  const deps = {
32921
32505
  // file-sharing (spec §6 PR 3):在 stdout-line 解析时同步观察 file-edit 工具事件,
@@ -32925,10 +32509,20 @@ var SessionRunner = class {
32925
32509
  if (this.hooks.onFileEdit) this.observeForFileEdit(events);
32926
32510
  return events;
32927
32511
  },
32928
- // Persona dispatch (Task 9):原 in-place `@persona/<id>` 注入路径已删,cc 自己看到字面
32929
- // token 会调 personaDispatch MCP tool 委派(dispatch.mcp.json 通过 cc --mcp-config 加载,
32930
- // CLAUDE.md cc 触发条件)。encodeStdin 现在是 adapter 的简单 passthrough。
32931
- encodeStdin: (t, ctx) => adapter.encodeStdin(t, ctx) ?? "",
32512
+ // persona mention injection deps 装配处包一层,对 reducer 完全透明。
32513
+ // 命中 mention 时拆成两条 stdin 帧(先 system-reminder 块、后 user 原文):
32514
+ // - CC stream-json 按行处理,落盘是两条独立 user message;
32515
+ // - 第一条文本起头 `<system-reminder>` classifyUserMessage 命中 UI 折叠;
32516
+ // - 第二条正常用户气泡,刷新页面不再暴露 personality 文本。
32517
+ encodeStdin: (t, ctx) => {
32518
+ if (!personaStore) return adapter.encodeStdin(t, ctx) ?? "";
32519
+ const { systemReminder, userText } = injectPersonaMentions(t, personaStore);
32520
+ if (systemReminder === null) return adapter.encodeStdin(userText, ctx) ?? "";
32521
+ const metaFrame = adapter.encodeStdin(systemReminder, ctx) ?? "";
32522
+ if (userText === "") return metaFrame;
32523
+ const userFrame = adapter.encodeStdin(userText, ctx) ?? "";
32524
+ return metaFrame + userFrame;
32525
+ },
32932
32526
  bufferCap: this.hooks.bufferCap ?? 500,
32933
32527
  now: this.hooks.now ?? Date.now,
32934
32528
  resolveContextWindow: this.hooks.resolveContextWindow,
@@ -32938,10 +32532,6 @@ var SessionRunner = class {
32938
32532
  // 单栏 refactor (spec 2026-06-02 §5.1): cc 子进程 env 注入 CLAWD_DAEMON_URL,让 assistant
32939
32533
  // curl daemon HTTP RPC adapter (/api/rpc/<method>) 触发管理操作。null = HTTP adapter 未启。
32940
32534
  getDaemonUrl: this.hooks.getDaemonUrl,
32941
- // Persona dispatch:透传 dispatch.mcp.json 路径闭包 + B→dispatchId 反查闭包。
32942
- // 见 reducer.buildSpawnContext 注 CLAWD_DISPATCH_ID env / 派生 SpawnContext.dispatchMcpConfigPath
32943
- getDispatchMcpConfigPath: this.hooks.getDispatchMcpConfigPath,
32944
- lookupDispatchByBSessionId: this.hooks.lookupDispatchByBSessionId,
32945
32535
  // ReadyGate v2:透传 mode 让 reducer send / ready-detected 分支决定走暂存队列还是直写
32946
32536
  mode: this.hooks.mode,
32947
32537
  // [RG-DBG] 注入 logger 让 reducer rgDbg 走 pino 进 clawd.log;定位完跟 rgDbg 一起删
@@ -33401,22 +32991,6 @@ function nowIso2(deps) {
33401
32991
  function newSessionId() {
33402
32992
  return v4_default().replace(/-/g, "").slice(0, 16);
33403
32993
  }
33404
- function buildDispatchTaskPack(args) {
33405
- return `[Dispatched from owner \u2014 another persona session\u59D4\u6D3E\u7ED9\u4F60\u6267\u884C\u4EFB\u52A1]
33406
-
33407
- Task:
33408
- ${args.prompt}
33409
-
33410
- Source conversation (jsonl, CC stream-json format, one message per line):
33411
- ${args.sourceJsonlPath}
33412
- You may read this file with your Read tool to understand context. You do not have to read it all.
33413
-
33414
- When done, call the MCP tool \`mcp__clawd-dispatch__personaDispatchComplete\` with your result:
33415
- - Success: { text: "...", filePaths?: ["abs/path", ...] }
33416
- - Failure: { isFailure: true, reason: "..." }
33417
-
33418
- dispatchId for this task: ${args.dispatchId}`;
33419
- }
33420
32994
  function derivePersonaSpawnCwd(file, personaRoot) {
33421
32995
  const personaId = file.ownerPersonaId;
33422
32996
  if (!personaId) return file.cwd;
@@ -33714,8 +33288,7 @@ var SessionManager = class {
33714
33288
  // adapter 自己持有模型表 + 兜底逻辑(contains / opus-1M / [1m] 等),manager 不再 cache 转发
33715
33289
  resolveContextWindow: (tool, modelId) => this.deps.getAdapter(tool).resolveContextWindow(modelId),
33716
33290
  dataDir: this.deps.dataDir,
33717
- // personaStore 不再透给 runner hooks(in-place mention 注入路径已删,runner 不用);
33718
- // manager 自身的 sandbox 派生仍直接读 this.deps.personaStore。
33291
+ personaStore: this.deps.personaStore,
33719
33292
  ownerDisplayName: this.deps.ownerDisplayName,
33720
33293
  // Phase 2 capability platform (plan §3): 透传 personaRoot, buildSpawnArgs 据
33721
33294
  // cwd 是否在 personaRoot 下自动决定是否注入 --settings sandbox-settings.json.
@@ -33723,10 +33296,6 @@ var SessionManager = class {
33723
33296
  // 单栏 refactor (spec 2026-06-02 §5.1): 透传 daemon HTTP RPC base URL 闭包,
33724
33297
  // reducer 把它注入 cc 子进程 env CLAWD_DAEMON_URL.
33725
33298
  getDaemonUrl: this.deps.getDaemonUrl,
33726
- // Persona dispatch (Task 7): dispatch.mcp.json 路径 + B sessionId → dispatchId 反查
33727
- // 闭包透传给 reducer,让 cc spawn 加 --mcp-config flag + B session 注 CLAWD_DISPATCH_ID env.
33728
- getDispatchMcpConfigPath: this.deps.dispatchMcpConfigPath ? () => this.deps.dispatchMcpConfigPath ?? null : void 0,
33729
- lookupDispatchByBSessionId: this.deps.personaDispatchManager ? (bSid) => this.deps.personaDispatchManager?.lookupDispatchByBSessionId(bSid) : void 0,
33730
33299
  // file-sharing (spec §6 PR 3):闭包 scope + sessionId,runner 只暴露 tool/relPath/cwd
33731
33300
  onFileEdit: attachmentGroup ? (input) => attachmentGroup.onFileEdit({
33732
33301
  scope,
@@ -33942,20 +33511,15 @@ var SessionManager = class {
33942
33511
  // 强制走 deps.store(即 default scope),不走 scopeForFile:mirror 物理落 default 即可。
33943
33512
  // 远端 creator / origin 字段原值保留(不被本机 ctx 派生覆写)。
33944
33513
  //
33945
- // strip 远端 personaId / dispatchedFromSessionId:mirror SessionFile 上这两个字段都指向
33946
- // 朋友 daemon 上的本地 id,本机不持有对应 persona / 源 session。留着会让按这些字段反查的
33947
- // 本机消费者(MyPersonasSection ownerPersonaId 反查 persona、sidebar
33948
- // dispatchedFromSessionId 折叠 sub-session)走错分支。写入前清掉。#750 一族防线。
33514
+ // strip 远端 personaId:mirror SessionFile 上的 ownerPersonaId 是朋友 daemon 的 persona
33515
+ // 目录 id,本机不持有对应 persona。留着会让按 ownerPersonaId 反查的本机消费者
33516
+ // MyPersonasSection 等)把 mirror 误聚到同 id persona 下。写入前清掉。
33949
33517
  //
33950
33518
  // 与 manager.create / manager.update 区别:
33951
33519
  // - 不走 newRunner / attachObserver / cwd 校验(mirror 是纯 metadata 层)
33952
33520
  // - 不发 session:info 帧(manager.create / .update 通过 reducer/wireCollector 发 push)
33953
33521
  mirrorUpsert(file) {
33954
- const {
33955
- ownerPersonaId: _strippedPid,
33956
- dispatchedFromSessionId: _strippedDsp,
33957
- ...rest
33958
- } = file;
33522
+ const { ownerPersonaId: _stripped, ...rest } = file;
33959
33523
  return this.deps.store.write(rest);
33960
33524
  }
33961
33525
  // mirror peer sessions:删本机 mirror SessionFile。mirror 一律落 default(mirrorUpsert
@@ -34540,66 +34104,6 @@ var SessionManager = class {
34540
34104
  this.runners.set(file.sessionId, runner);
34541
34105
  return runner;
34542
34106
  }
34543
- /**
34544
- * Persona dispatch: 启动 B session 并投递任务包当第一条 user message。
34545
- *
34546
- * - 复用 persona-owner 创建路径(cwd=personaDir、scope=persona-owner、不沙箱)
34547
- * - SessionFile 上写 dispatchedFromSessionId 关联回 A(UI 折叠用;mirror 一侧 strip)
34548
- * - 跟 PersonaDispatchManager 双向登记 dispatchId ↔ B sessionId,让后续 reducer
34549
- * buildSpawnContext 能反查到 dispatchId 注 CLAWD_DISPATCH_ID env
34550
- * - 投 inject-owner-text 任务包;包尾教 B 用 personaDispatchComplete tool 回传
34551
- *
34552
- * cwd 派生与 SessionManager.create 的 owner persona 路径一致(derivePersonaSpawnCwd)。
34553
- */
34554
- createDispatchedSession(args) {
34555
- if (!this.deps.personaRoot) {
34556
- throw new Error("createDispatchedSession: personaRoot missing in ManagerDeps");
34557
- }
34558
- if (!this.deps.personaDispatchManager) {
34559
- throw new Error("createDispatchedSession: personaDispatchManager missing in ManagerDeps");
34560
- }
34561
- const sessionId = newSessionId();
34562
- const scope = {
34563
- kind: "persona",
34564
- personaId: args.targetPersona,
34565
- mode: "owner"
34566
- };
34567
- const cwd = import_node_path6.default.join(this.deps.personaRoot, safeFileName(args.targetPersona));
34568
- const now = (/* @__PURE__ */ new Date()).toISOString();
34569
- const file = {
34570
- sessionId,
34571
- cwd,
34572
- tool: "claude",
34573
- ownerPersonaId: args.targetPersona,
34574
- dispatchedFromSessionId: args.sourceSessionId,
34575
- createdAt: now,
34576
- updatedAt: now
34577
- };
34578
- this.storeFor(scope).write(file);
34579
- this.deps.personaDispatchManager.registerBSession(args.dispatchId, sessionId);
34580
- this.deps.logger?.info("dispatch.createDispatchedSession.file-written", {
34581
- dispatchId: args.dispatchId,
34582
- bSessionId: sessionId,
34583
- targetPersona: args.targetPersona,
34584
- cwd
34585
- });
34586
- const runner = this.ensureRunnerForScope(file, scope);
34587
- this.deps.logger?.info("dispatch.createDispatchedSession.runner-ready", {
34588
- dispatchId: args.dispatchId,
34589
- bSessionId: sessionId
34590
- });
34591
- const taskPack = buildDispatchTaskPack({
34592
- prompt: args.prompt,
34593
- sourceJsonlPath: args.sourceJsonlPath,
34594
- dispatchId: args.dispatchId
34595
- });
34596
- runner.input({ kind: "command", command: { kind: "send", text: taskPack } });
34597
- this.deps.logger?.info("dispatch.createDispatchedSession.task-pack-sent", {
34598
- dispatchId: args.dispatchId,
34599
- bSessionId: sessionId
34600
- });
34601
- return { sessionId };
34602
- }
34603
34107
  /**
34604
34108
  * 老板插话:把 'inject-owner-text' input 喂给对应 runner,
34605
34109
  * runner 不存在时按 scope 懒创建。
@@ -35621,6 +35125,39 @@ var DEFAULT_PERSONAS = [
35621
35125
  network: true
35622
35126
  }
35623
35127
  },
35128
+ {
35129
+ // 数据查询搭建师:复用 app-builder 流水线生成 dataclaw 只读查询页
35130
+ // spec: clawd/superpowers/specs/2026-06-14-dataclaw-builder-design.md
35131
+ personaId: "persona-dataclaw-builder",
35132
+ label: "\u6570\u636E\u67E5\u8BE2\u642D\u5EFA\u5E08",
35133
+ model: "opus",
35134
+ iconKey: "assist",
35135
+ public: false,
35136
+ // 同 app-builder 的开发型 profile(逐字段照抄):web 工具 + node/pnpm 工具链精确路径
35137
+ // + 出站 TLD 通配白名单 + .secrets deny。复用同一条流水线 → 同一套沙箱授权。
35138
+ sandboxProfile: {
35139
+ permissions: {
35140
+ defaultMode: "bypassPermissions",
35141
+ allow: ["Read", "Edit", "Write", "Glob", "Grep", "WebFetch", "WebSearch"],
35142
+ deny: ["Read(./.secrets/**)"]
35143
+ },
35144
+ sandbox: {
35145
+ filesystem: {
35146
+ allowRead: ["~/.npmrc", "~/Library/Preferences/pnpm", "~/.nvm", "~/Library/pnpm", "~/.local/share/pnpm", "~/.local/state/pnpm", "~/.npm", "~/.pnpm-store"],
35147
+ allowWrite: ["~/Library/pnpm", "~/.local/share/pnpm", "~/.local/state/pnpm", "~/.npm", "~/.pnpm-store"]
35148
+ },
35149
+ network: {
35150
+ allowedDomains: ["*.com", "*.org", "*.io", "*.net", "*.dev", "*.app", "*.cn", "*.co", "*.chat", "*.ai"],
35151
+ allowLocalBinding: true
35152
+ }
35153
+ }
35154
+ },
35155
+ codexSandbox: {
35156
+ writableRoots: ["~/Library/pnpm", "~/.local/share/pnpm", "~/.local/state/pnpm", "~/.npm", "~/.pnpm-store"],
35157
+ denyRead: [".secrets/**"],
35158
+ network: true
35159
+ }
35160
+ },
35624
35161
  {
35625
35162
  personaId: "persona-developer",
35626
35163
  label: "\u5F00\u53D1\u8005",
@@ -35779,6 +35316,56 @@ function migrateCodexSandbox(args) {
35779
35316
  }
35780
35317
  if (n > 0) args.logger.info("persona.codex-sandbox.done", { migrated: n });
35781
35318
  }
35319
+ function findDeployKitRoot() {
35320
+ const candidates = [];
35321
+ try {
35322
+ const here = path11.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
35323
+ candidates.push(path11.resolve(here, "..", "deploy-kit"));
35324
+ } catch {
35325
+ }
35326
+ if (process.argv[1]) {
35327
+ candidates.push(path11.resolve(path11.dirname(process.argv[1]), "deploy-kit"));
35328
+ }
35329
+ for (const c of candidates) {
35330
+ try {
35331
+ if (fs9.statSync(c).isDirectory()) return c;
35332
+ } catch {
35333
+ }
35334
+ }
35335
+ return null;
35336
+ }
35337
+ function seedDeployKit(args) {
35338
+ const dst = path11.join(args.dataDir, "deploy-kit");
35339
+ fs9.cpSync(args.deployKitBundleRoot, dst, {
35340
+ recursive: true,
35341
+ dereference: true,
35342
+ force: false,
35343
+ errorOnExist: false
35344
+ });
35345
+ args.logger.info("deploy-kit.seed.done", { dst });
35346
+ }
35347
+ function refreshDeployKit(args) {
35348
+ const dst = path11.join(args.dataDir, "deploy-kit");
35349
+ if (!fs9.existsSync(dst)) {
35350
+ seedDeployKit(args);
35351
+ return;
35352
+ }
35353
+ for (const sub of ["scripts", "contract"]) {
35354
+ const s = path11.join(args.deployKitBundleRoot, sub);
35355
+ if (fs9.existsSync(s)) {
35356
+ fs9.cpSync(s, path11.join(dst, sub), { recursive: true, force: true, dereference: true });
35357
+ }
35358
+ }
35359
+ const secretsSrc = path11.join(args.deployKitBundleRoot, ".secrets");
35360
+ if (fs9.existsSync(secretsSrc)) {
35361
+ fs9.mkdirSync(path11.join(dst, ".secrets"), { recursive: true });
35362
+ for (const f of fs9.readdirSync(secretsSrc)) {
35363
+ if (!f.endsWith(".example")) continue;
35364
+ fs9.copyFileSync(path11.join(secretsSrc, f), path11.join(dst, ".secrets", f));
35365
+ }
35366
+ }
35367
+ args.logger.info("deploy-kit.refresh.done", { dst });
35368
+ }
35782
35369
 
35783
35370
  // src/index.ts
35784
35371
  init_claude();
@@ -36033,8 +35620,8 @@ function turnStartInput(text) {
36033
35620
  const items = [];
36034
35621
  let leftover = text;
36035
35622
  for (const m2 of text.matchAll(SKILL_RE)) {
36036
- const [marker, name, path59] = m2;
36037
- items.push({ type: "skill", name, path: path59 });
35623
+ const [marker, name, path58] = m2;
35624
+ items.push({ type: "skill", name, path: path58 });
36038
35625
  leftover = leftover.replace(marker, "");
36039
35626
  }
36040
35627
  for (const m2 of text.matchAll(ATTACHMENT_RE2)) {
@@ -36685,7 +36272,7 @@ init_claude_history();
36685
36272
 
36686
36273
  // src/pty/pty-child-process.ts
36687
36274
  var import_node_events = require("events");
36688
- var import_node_stream2 = require("stream");
36275
+ var import_node_stream = require("stream");
36689
36276
  var PtyChildProcess = class extends import_node_events.EventEmitter {
36690
36277
  constructor(pty, opts = {}) {
36691
36278
  super();
@@ -36714,7 +36301,7 @@ var PtyChildProcess = class extends import_node_events.EventEmitter {
36714
36301
  pty.write(data);
36715
36302
  }
36716
36303
  };
36717
- this.stdin = new import_node_stream2.Writable({
36304
+ this.stdin = new import_node_stream.Writable({
36718
36305
  decodeStrings: false,
36719
36306
  write: (chunk, _enc, cb) => {
36720
36307
  const s = typeof chunk === "string" ? chunk : chunk.toString("utf8");
@@ -36733,7 +36320,7 @@ var PtyChildProcess = class extends import_node_events.EventEmitter {
36733
36320
  }
36734
36321
  }
36735
36322
  });
36736
- this.stdout = new import_node_stream2.Readable({ read() {
36323
+ this.stdout = new import_node_stream.Readable({ read() {
36737
36324
  } });
36738
36325
  pty.onData((data) => {
36739
36326
  if (!this.firstDataLogged) {
@@ -36746,7 +36333,7 @@ var PtyChildProcess = class extends import_node_events.EventEmitter {
36746
36333
  }
36747
36334
  this.stdout.push(Buffer.from(data, "utf8"));
36748
36335
  });
36749
- this.stderr = new import_node_stream2.Readable({ read() {
36336
+ this.stderr = new import_node_stream.Readable({ read() {
36750
36337
  } });
36751
36338
  pty.onExit(({ exitCode, signal }) => {
36752
36339
  this.exitCode = exitCode;
@@ -37261,9 +36848,6 @@ function buildTuiSpawnArgs(ctx, isResume = false) {
37261
36848
  if (ctx.addDirs) {
37262
36849
  for (const dir of ctx.addDirs) args.push("--add-dir", dir);
37263
36850
  }
37264
- if (ctx.dispatchMcpConfigPath) {
37265
- args.push("--mcp-config", ctx.dispatchMcpConfigPath);
37266
- }
37267
36851
  if (ctx.effort) args.push("--effort", ctx.effort);
37268
36852
  return args;
37269
36853
  }
@@ -37281,155 +36865,6 @@ function jsonlExistsForCtx(ctx) {
37281
36865
  // src/index.ts
37282
36866
  init_claude_history();
37283
36867
 
37284
- // src/dispatch/manager.ts
37285
- function defer() {
37286
- let resolve6;
37287
- const promise = new Promise((r) => {
37288
- resolve6 = r;
37289
- });
37290
- return { promise, resolve: resolve6 };
37291
- }
37292
- var PersonaDispatchManager = class {
37293
- constructor(deps) {
37294
- this.deps = deps;
37295
- }
37296
- deps;
37297
- map = /* @__PURE__ */ new Map();
37298
- start(args) {
37299
- const dispatchId = this.deps.genId();
37300
- this.map.set(dispatchId, {
37301
- dispatchId,
37302
- sourceSessionId: args.sourceSessionId,
37303
- targetPersona: args.targetPersona,
37304
- waiters: [],
37305
- outcome: null
37306
- });
37307
- return { dispatchId };
37308
- }
37309
- get(dispatchId) {
37310
- return this.map.get(dispatchId);
37311
- }
37312
- async wait(dispatchId) {
37313
- const state = this.map.get(dispatchId);
37314
- if (!state) throw new Error(`unknown dispatchId: ${dispatchId}`);
37315
- if (state.outcome) return state.outcome;
37316
- const d = defer();
37317
- state.waiters.push(d);
37318
- return d.promise;
37319
- }
37320
- complete(dispatchId, outcome) {
37321
- const state = this.map.get(dispatchId);
37322
- if (!state) throw new Error(`unknown dispatchId: ${dispatchId}`);
37323
- state.outcome = outcome;
37324
- const waiters = state.waiters;
37325
- state.waiters = [];
37326
- for (const w2 of waiters) w2.resolve(outcome);
37327
- }
37328
- /** SessionManager 在 createDispatchedSession 时调,建立 dispatchId → B sessionId 映射 */
37329
- registerBSession(dispatchId, bSessionId) {
37330
- const state = this.map.get(dispatchId);
37331
- if (!state) throw new Error(`unknown dispatchId: ${dispatchId}`);
37332
- state.bSessionId = bSessionId;
37333
- }
37334
- /** reducer buildSpawnContext 调,按 B 的 sessionId 反查 dispatchId(用于注 CLAWD_DISPATCH_ID env) */
37335
- lookupDispatchByBSessionId(bSessionId) {
37336
- for (const state of this.map.values()) {
37337
- if (state.bSessionId === bSessionId) return state.dispatchId;
37338
- }
37339
- return void 0;
37340
- }
37341
- };
37342
-
37343
- // src/dispatch/mcp-config.ts
37344
- var import_node_fs12 = __toESM(require("fs"), 1);
37345
- var import_node_path10 = __toESM(require("path"), 1);
37346
- function dispatchMcpConfigPath(dataDir) {
37347
- return import_node_path10.default.join(dataDir, "dispatch.mcp.json");
37348
- }
37349
- function writeDispatchMcpConfig(args) {
37350
- const cfgPath = dispatchMcpConfigPath(args.dataDir);
37351
- const content = {
37352
- _comment: "daemon \u542F\u52A8\u65F6\u81EA\u52A8\u751F\u6210\uFF1Bcc spawn \u901A\u8FC7 --mcp-config \u6CE8\u5165\u3002dispatch-mcp-server.cjs \u662F daemon \u81EA\u5E26\u7684 stdio MCP server\u3002env.CLAWD_DISPATCH_LOG \u6307 server \u5199\u65E5\u5FD7\u7684 append \u6587\u4EF6\u8DEF\u5F84\uFF08dispatch \u6D41\u7A0B\u8282\u70B9 + fetch \u9519\u8BEF\u7EC6\u8282\uFF09\u3002",
37353
- mcpServers: {
37354
- "clawd-dispatch": {
37355
- type: "stdio",
37356
- command: "node",
37357
- args: [args.serverScriptPath],
37358
- ...args.logPath ? { env: { CLAWD_DISPATCH_LOG: args.logPath } } : {}
37359
- }
37360
- }
37361
- };
37362
- import_node_fs12.default.mkdirSync(args.dataDir, { recursive: true });
37363
- import_node_fs12.default.writeFileSync(cfgPath, JSON.stringify(content, null, 2), "utf8");
37364
- return cfgPath;
37365
- }
37366
-
37367
- // src/handlers/persona-dispatch.ts
37368
- init_protocol();
37369
- function buildPersonaDispatchHandlers(deps) {
37370
- const { personaDispatchManager: mgr, spawnB, logger } = deps;
37371
- const run = async (frame) => {
37372
- const { type: _t, requestId: _r, ...rest } = frame;
37373
- const sourceSessionId = typeof rest.sessionId === "string" ? rest.sessionId : void 0;
37374
- const args = DispatchRunArgsSchema.parse(rest);
37375
- if (!sourceSessionId) {
37376
- throw new Error(
37377
- "personaDispatch:run requires sessionId (caller must pass x-clawd-session-id header)"
37378
- );
37379
- }
37380
- const { dispatchId } = mgr.start({
37381
- sourceSessionId,
37382
- targetPersona: args.targetPersona
37383
- });
37384
- logger?.info("dispatch.run.received", {
37385
- dispatchId,
37386
- sourceSessionId,
37387
- targetPersona: args.targetPersona,
37388
- promptLen: args.prompt.length
37389
- });
37390
- void spawnB({
37391
- dispatchId,
37392
- sourceSessionId,
37393
- targetPersona: args.targetPersona,
37394
- prompt: args.prompt
37395
- }).then(() => {
37396
- logger?.info("dispatch.spawnB.ok", { dispatchId });
37397
- }).catch((err) => {
37398
- const reason = err instanceof Error ? err.message : String(err);
37399
- logger?.warn("dispatch.spawnB.failed", { dispatchId, reason });
37400
- mgr.complete(dispatchId, {
37401
- kind: "failure",
37402
- reason: `failed to spawn B: ${reason}`
37403
- });
37404
- });
37405
- logger?.info("dispatch.run.waiting", { dispatchId });
37406
- const outcome = await mgr.wait(dispatchId);
37407
- logger?.info("dispatch.run.resolved", {
37408
- dispatchId,
37409
- outcomeKind: outcome.kind
37410
- });
37411
- return {
37412
- response: { type: "personaDispatch:run:ok", outcome }
37413
- };
37414
- };
37415
- const complete = async (frame) => {
37416
- const { type: _t, requestId: _r, ...rest } = frame;
37417
- const args = DispatchCompleteArgsSchema.parse(rest);
37418
- logger?.info("dispatch.complete.received", {
37419
- dispatchId: args.dispatchId,
37420
- outcomeKind: args.outcome.kind
37421
- });
37422
- mgr.complete(args.dispatchId, args.outcome);
37423
- return {
37424
- response: { type: "personaDispatch:complete:ok" }
37425
- };
37426
- };
37427
- return {
37428
- "personaDispatch:run": run,
37429
- "personaDispatch:complete": complete
37430
- };
37431
- }
37432
-
37433
36868
  // src/tools/codex-history.ts
37434
36869
  var import_node_child_process5 = require("child_process");
37435
36870
  var DEFAULT_TIMEOUT_MS = 8e3;
@@ -37616,13 +37051,13 @@ function mapSkillsListResponse(res) {
37616
37051
  const r = s ?? {};
37617
37052
  const name = str3(r.name);
37618
37053
  if (!name) continue;
37619
- const path59 = str3(r.path);
37054
+ const path58 = str3(r.path);
37620
37055
  const description = str3(r.description);
37621
37056
  const isPlugin = name.includes(":");
37622
37057
  out.push({
37623
37058
  name,
37624
37059
  source: isPlugin ? "plugin" : "project",
37625
- ...path59 ? { path: path59 } : {},
37060
+ ...path58 ? { path: path58 } : {},
37626
37061
  ...description ? { description } : {},
37627
37062
  ...isPlugin ? { plugin: name.split(":")[0] } : {}
37628
37063
  });
@@ -37661,23 +37096,23 @@ async function listCodexSkills(cwd, deps = {}) {
37661
37096
  }
37662
37097
 
37663
37098
  // src/workspace/browser.ts
37664
- var import_node_fs13 = __toESM(require("fs"), 1);
37099
+ var import_node_fs12 = __toESM(require("fs"), 1);
37665
37100
  var import_node_os6 = __toESM(require("os"), 1);
37666
- var import_node_path11 = __toESM(require("path"), 1);
37101
+ var import_node_path10 = __toESM(require("path"), 1);
37667
37102
  init_protocol();
37668
37103
  var MAX_FILE_BYTES = 2 * 1024 * 1024;
37669
37104
  function resolveInsideCwd(cwd, subpath) {
37670
- const absCwd = import_node_path11.default.resolve(cwd);
37671
- const joined = import_node_path11.default.resolve(absCwd, subpath ?? ".");
37672
- const rel = import_node_path11.default.relative(absCwd, joined);
37673
- if (rel.startsWith("..") || import_node_path11.default.isAbsolute(rel)) {
37105
+ const absCwd = import_node_path10.default.resolve(cwd);
37106
+ const joined = import_node_path10.default.resolve(absCwd, subpath ?? ".");
37107
+ const rel = import_node_path10.default.relative(absCwd, joined);
37108
+ if (rel.startsWith("..") || import_node_path10.default.isAbsolute(rel)) {
37674
37109
  throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
37675
37110
  }
37676
37111
  return joined;
37677
37112
  }
37678
37113
  function ensureCwd(cwd) {
37679
37114
  try {
37680
- const stat = import_node_fs13.default.statSync(cwd);
37115
+ const stat = import_node_fs12.default.statSync(cwd);
37681
37116
  if (!stat.isDirectory()) {
37682
37117
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${cwd}`);
37683
37118
  }
@@ -37691,7 +37126,7 @@ var WorkspaceBrowser = class {
37691
37126
  const cwd = args.cwd && args.cwd.length > 0 ? args.cwd : import_node_os6.default.homedir();
37692
37127
  ensureCwd(cwd);
37693
37128
  const full = resolveInsideCwd(cwd, args.path);
37694
- const dirents = import_node_fs13.default.readdirSync(full, { withFileTypes: true });
37129
+ const dirents = import_node_fs12.default.readdirSync(full, { withFileTypes: true });
37695
37130
  const entries = [];
37696
37131
  for (const d of dirents) {
37697
37132
  if (!args.showHidden && d.name.startsWith(".")) continue;
@@ -37701,7 +37136,7 @@ var WorkspaceBrowser = class {
37701
37136
  mtime: ""
37702
37137
  };
37703
37138
  try {
37704
- const st = import_node_fs13.default.statSync(import_node_path11.default.join(full, d.name));
37139
+ const st = import_node_fs12.default.statSync(import_node_path10.default.join(full, d.name));
37705
37140
  entry.mtime = new Date(st.mtimeMs).toISOString();
37706
37141
  if (d.isFile()) entry.size = st.size;
37707
37142
  } catch {
@@ -37717,14 +37152,14 @@ var WorkspaceBrowser = class {
37717
37152
  read(args) {
37718
37153
  ensureCwd(args.cwd);
37719
37154
  const full = resolveInsideCwd(args.cwd, args.path);
37720
- const st = import_node_fs13.default.statSync(full);
37155
+ const st = import_node_fs12.default.statSync(full);
37721
37156
  if (!st.isFile()) {
37722
37157
  throw new ClawdError(ERROR_CODES.INVALID_PATH, `not a file: ${args.path}`);
37723
37158
  }
37724
37159
  if (st.size > MAX_FILE_BYTES) {
37725
37160
  throw new ClawdError(ERROR_CODES.FILE_TOO_LARGE, `file > ${MAX_FILE_BYTES} bytes`);
37726
37161
  }
37727
- const buf = import_node_fs13.default.readFileSync(full);
37162
+ const buf = import_node_fs12.default.readFileSync(full);
37728
37163
  const isBinary = buf.includes(0);
37729
37164
  if (isBinary) {
37730
37165
  return {
@@ -37746,20 +37181,20 @@ var WorkspaceBrowser = class {
37746
37181
  };
37747
37182
 
37748
37183
  // src/skills/agents-scanner.ts
37749
- var import_node_fs14 = __toESM(require("fs"), 1);
37184
+ var import_node_fs13 = __toESM(require("fs"), 1);
37750
37185
  var import_node_os7 = __toESM(require("os"), 1);
37751
- var import_node_path12 = __toESM(require("path"), 1);
37186
+ var import_node_path11 = __toESM(require("path"), 1);
37752
37187
  var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
37753
37188
  function isDirLikeSync2(p2) {
37754
37189
  try {
37755
- return import_node_fs14.default.statSync(p2).isDirectory();
37190
+ return import_node_fs13.default.statSync(p2).isDirectory();
37756
37191
  } catch {
37757
37192
  return false;
37758
37193
  }
37759
37194
  }
37760
37195
  function fileExistsSync(p2) {
37761
37196
  try {
37762
- return import_node_fs14.default.statSync(p2).isFile();
37197
+ return import_node_fs13.default.statSync(p2).isFile();
37763
37198
  } catch {
37764
37199
  return false;
37765
37200
  }
@@ -37767,7 +37202,7 @@ function fileExistsSync(p2) {
37767
37202
  function parseAgentFile(filePath) {
37768
37203
  let content;
37769
37204
  try {
37770
- content = import_node_fs14.default.readFileSync(filePath, "utf8");
37205
+ content = import_node_fs13.default.readFileSync(filePath, "utf8");
37771
37206
  } catch {
37772
37207
  return {};
37773
37208
  }
@@ -37780,16 +37215,16 @@ function parseAgentFile(filePath) {
37780
37215
  function scanAgentsDir(dir, source, seen, out) {
37781
37216
  let entries;
37782
37217
  try {
37783
- entries = import_node_fs14.default.readdirSync(dir, { withFileTypes: true });
37218
+ entries = import_node_fs13.default.readdirSync(dir, { withFileTypes: true });
37784
37219
  } catch {
37785
37220
  return;
37786
37221
  }
37787
37222
  for (const ent of entries) {
37788
37223
  if (!ent.name.endsWith(".md")) continue;
37789
- if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path12.default.join(dir, ent.name)))) {
37224
+ if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path11.default.join(dir, ent.name)))) {
37790
37225
  continue;
37791
37226
  }
37792
- const filePath = import_node_path12.default.join(dir, ent.name);
37227
+ const filePath = import_node_path11.default.join(dir, ent.name);
37793
37228
  const baseName = ent.name.replace(/\.md$/, "");
37794
37229
  if (seen.has(baseName)) continue;
37795
37230
  seen.add(baseName);
@@ -37807,12 +37242,12 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
37807
37242
  function walk2(dir, namespaces) {
37808
37243
  let entries;
37809
37244
  try {
37810
- entries = import_node_fs14.default.readdirSync(dir, { withFileTypes: true });
37245
+ entries = import_node_fs13.default.readdirSync(dir, { withFileTypes: true });
37811
37246
  } catch {
37812
37247
  return;
37813
37248
  }
37814
37249
  for (const ent of entries) {
37815
- const childPath = import_node_path12.default.join(dir, ent.name);
37250
+ const childPath = import_node_path11.default.join(dir, ent.name);
37816
37251
  if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
37817
37252
  walk2(childPath, [...namespaces, ent.name]);
37818
37253
  continue;
@@ -37837,13 +37272,13 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
37837
37272
  walk2(root, []);
37838
37273
  }
37839
37274
  function readInstalledPlugins2(home) {
37840
- const pluginsDir = import_node_path12.default.join(home, ".claude", "plugins");
37841
- const v2 = import_node_path12.default.join(pluginsDir, "installed_plugins_v2.json");
37842
- const v1 = import_node_path12.default.join(pluginsDir, "installed_plugins.json");
37275
+ const pluginsDir = import_node_path11.default.join(home, ".claude", "plugins");
37276
+ const v2 = import_node_path11.default.join(pluginsDir, "installed_plugins_v2.json");
37277
+ const v1 = import_node_path11.default.join(pluginsDir, "installed_plugins.json");
37843
37278
  let raw = null;
37844
37279
  for (const candidate of [v2, v1]) {
37845
37280
  try {
37846
- raw = import_node_fs14.default.readFileSync(candidate, "utf8");
37281
+ raw = import_node_fs13.default.readFileSync(candidate, "utf8");
37847
37282
  break;
37848
37283
  } catch {
37849
37284
  }
@@ -37868,19 +37303,19 @@ function readInstalledPlugins2(home) {
37868
37303
  return out;
37869
37304
  }
37870
37305
  function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
37871
- let cur = import_node_path12.default.resolve(startCwd);
37872
- const fsRoot = import_node_path12.default.parse(cur).root;
37306
+ let cur = import_node_path11.default.resolve(startCwd);
37307
+ const fsRoot = import_node_path11.default.parse(cur).root;
37873
37308
  while (true) {
37874
- scanAgentsDir(import_node_path12.default.join(cur, ".claude", "agents"), "project", seen, out);
37309
+ scanAgentsDir(import_node_path11.default.join(cur, ".claude", "agents"), "project", seen, out);
37875
37310
  let hasGit = false;
37876
37311
  try {
37877
- hasGit = import_node_fs14.default.existsSync(import_node_path12.default.join(cur, ".git"));
37312
+ hasGit = import_node_fs13.default.existsSync(import_node_path11.default.join(cur, ".git"));
37878
37313
  } catch {
37879
37314
  }
37880
37315
  if (hasGit) return;
37881
37316
  if (cur === home) return;
37882
37317
  if (cur === fsRoot) return;
37883
- const parent = import_node_path12.default.dirname(cur);
37318
+ const parent = import_node_path11.default.dirname(cur);
37884
37319
  if (parent === cur) return;
37885
37320
  cur = parent;
37886
37321
  }
@@ -37915,7 +37350,7 @@ var AgentsScanner = class {
37915
37350
  }
37916
37351
  const fsBlock = [];
37917
37352
  scanAgentsDir(
37918
- import_node_path12.default.join(this.home, ".claude", "agents"),
37353
+ import_node_path11.default.join(this.home, ".claude", "agents"),
37919
37354
  "global",
37920
37355
  seen,
37921
37356
  fsBlock
@@ -37929,7 +37364,7 @@ var AgentsScanner = class {
37929
37364
  ...this.extraPluginRoots
37930
37365
  ];
37931
37366
  for (const { name, root } of plugins) {
37932
- const agentsRoot = import_node_path12.default.join(root, "agents");
37367
+ const agentsRoot = import_node_path11.default.join(root, "agents");
37933
37368
  scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
37934
37369
  }
37935
37370
  return [...builtinBlock, ...fsBlock];
@@ -37937,15 +37372,15 @@ var AgentsScanner = class {
37937
37372
  };
37938
37373
 
37939
37374
  // src/observer/session-observer.ts
37940
- var import_node_fs16 = __toESM(require("fs"), 1);
37375
+ var import_node_fs15 = __toESM(require("fs"), 1);
37941
37376
  var import_node_os9 = __toESM(require("os"), 1);
37942
- var import_node_path14 = __toESM(require("path"), 1);
37377
+ var import_node_path13 = __toESM(require("path"), 1);
37943
37378
  init_claude_history();
37944
37379
 
37945
37380
  // src/observer/subagent-meta-observer.ts
37946
- var import_node_fs15 = __toESM(require("fs"), 1);
37381
+ var import_node_fs14 = __toESM(require("fs"), 1);
37947
37382
  var import_node_os8 = __toESM(require("os"), 1);
37948
- var import_node_path13 = __toESM(require("path"), 1);
37383
+ var import_node_path12 = __toESM(require("path"), 1);
37949
37384
  init_claude_history();
37950
37385
  var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
37951
37386
  var SubagentMetaObserver = class {
@@ -37958,7 +37393,7 @@ var SubagentMetaObserver = class {
37958
37393
  watches = /* @__PURE__ */ new Map();
37959
37394
  // public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
37960
37395
  resolveSubagentDir(cwd, toolSessionId) {
37961
- return import_node_path13.default.join(
37396
+ return import_node_path12.default.join(
37962
37397
  this.home,
37963
37398
  ".claude",
37964
37399
  "projects",
@@ -37988,7 +37423,7 @@ var SubagentMetaObserver = class {
37988
37423
  attachWatcher(w2) {
37989
37424
  if (w2.watcher) return;
37990
37425
  try {
37991
- w2.watcher = import_node_fs15.default.watch(w2.dirPath, { persistent: false }, (_evt, name) => {
37426
+ w2.watcher = import_node_fs14.default.watch(w2.dirPath, { persistent: false }, (_evt, name) => {
37992
37427
  if (!name) return;
37993
37428
  const m2 = META_RE.exec(String(name));
37994
37429
  if (!m2) return;
@@ -38000,7 +37435,7 @@ var SubagentMetaObserver = class {
38000
37435
  scan(w2) {
38001
37436
  let entries;
38002
37437
  try {
38003
- entries = import_node_fs15.default.readdirSync(w2.dirPath);
37438
+ entries = import_node_fs14.default.readdirSync(w2.dirPath);
38004
37439
  } catch {
38005
37440
  return;
38006
37441
  }
@@ -38014,10 +37449,10 @@ var SubagentMetaObserver = class {
38014
37449
  if (!m2) return;
38015
37450
  const agentId = m2[1];
38016
37451
  if (w2.emitted.has(agentId)) return;
38017
- const file = import_node_path13.default.join(w2.dirPath, name);
37452
+ const file = import_node_path12.default.join(w2.dirPath, name);
38018
37453
  let raw;
38019
37454
  try {
38020
- raw = import_node_fs15.default.readFileSync(file, "utf8");
37455
+ raw = import_node_fs14.default.readFileSync(file, "utf8");
38021
37456
  } catch {
38022
37457
  return;
38023
37458
  }
@@ -38074,14 +37509,14 @@ var SessionObserver = class {
38074
37509
  metaObserver;
38075
37510
  resolveJsonlPath(cwd, toolSessionId, override) {
38076
37511
  if (override) return override;
38077
- return import_node_path14.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
37512
+ return import_node_path13.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
38078
37513
  }
38079
37514
  start(args) {
38080
37515
  this.stop(args.sessionId);
38081
37516
  const filePath = this.resolveJsonlPath(args.cwd, args.toolSessionId, args.jsonlPath);
38082
37517
  let size = 0;
38083
37518
  try {
38084
- size = import_node_fs16.default.statSync(filePath).size;
37519
+ size = import_node_fs15.default.statSync(filePath).size;
38085
37520
  } catch {
38086
37521
  }
38087
37522
  const w2 = {
@@ -38095,10 +37530,10 @@ var SessionObserver = class {
38095
37530
  prevIsRejectSentinel: false
38096
37531
  };
38097
37532
  try {
38098
- import_node_fs16.default.mkdirSync(import_node_path14.default.dirname(filePath), { recursive: true });
37533
+ import_node_fs15.default.mkdirSync(import_node_path13.default.dirname(filePath), { recursive: true });
38099
37534
  } catch {
38100
37535
  }
38101
- w2.watcher = import_node_fs16.default.watch(import_node_path14.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
37536
+ w2.watcher = import_node_fs15.default.watch(import_node_path13.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
38102
37537
  if (!changedName || !filePath.endsWith(changedName)) return;
38103
37538
  this.poll(w2);
38104
37539
  });
@@ -38121,7 +37556,7 @@ var SessionObserver = class {
38121
37556
  // 异常静默吞,不阻塞 watcher 启动
38122
37557
  hydrateMetaTail(w2, maxLines = 200) {
38123
37558
  try {
38124
- const raw = import_node_fs16.default.readFileSync(w2.filePath, "utf8");
37559
+ const raw = import_node_fs15.default.readFileSync(w2.filePath, "utf8");
38125
37560
  if (!raw) return;
38126
37561
  const allLines = raw.split("\n").filter((l) => l.trim().length > 0);
38127
37562
  if (allLines.length === 0) return;
@@ -38145,7 +37580,7 @@ var SessionObserver = class {
38145
37580
  poll(w2) {
38146
37581
  let size = 0;
38147
37582
  try {
38148
- size = import_node_fs16.default.statSync(w2.filePath).size;
37583
+ size = import_node_fs15.default.statSync(w2.filePath).size;
38149
37584
  } catch {
38150
37585
  return;
38151
37586
  }
@@ -38154,11 +37589,11 @@ var SessionObserver = class {
38154
37589
  w2.buf = "";
38155
37590
  }
38156
37591
  if (size === w2.lastSize) return;
38157
- const fd = import_node_fs16.default.openSync(w2.filePath, "r");
37592
+ const fd = import_node_fs15.default.openSync(w2.filePath, "r");
38158
37593
  try {
38159
37594
  const len = size - w2.lastSize;
38160
37595
  const buf = Buffer.alloc(len);
38161
- import_node_fs16.default.readSync(fd, buf, 0, len, w2.lastSize);
37596
+ import_node_fs15.default.readSync(fd, buf, 0, len, w2.lastSize);
38162
37597
  w2.lastSize = size;
38163
37598
  w2.buf += buf.toString("utf8");
38164
37599
  let newlineIndex;
@@ -38181,7 +37616,7 @@ var SessionObserver = class {
38181
37616
  }
38182
37617
  }
38183
37618
  } finally {
38184
- import_node_fs16.default.closeSync(fd);
37619
+ import_node_fs15.default.closeSync(fd);
38185
37620
  }
38186
37621
  }
38187
37622
  // 解析 JSONL 单行:仅当是主链 user 文本行(非 sidechain / 非 sub-agent / message.role='user'
@@ -38276,7 +37711,7 @@ var import_stream = __toESM(require_stream(), 1);
38276
37711
  var import_extension = __toESM(require_extension(), 1);
38277
37712
  var import_permessage_deflate = __toESM(require_permessage_deflate(), 1);
38278
37713
  var import_receiver = __toESM(require_receiver(), 1);
38279
- var import_sender2 = __toESM(require_sender(), 1);
37714
+ var import_sender = __toESM(require_sender(), 1);
38280
37715
  var import_subprotocol = __toESM(require_subprotocol(), 1);
38281
37716
  var import_websocket = __toESM(require_websocket(), 1);
38282
37717
  var import_websocket_server = __toESM(require_websocket_server(), 1);
@@ -38904,14 +38339,14 @@ async function authenticate(token, deps) {
38904
38339
  }
38905
38340
 
38906
38341
  // src/permission/capability-store.ts
38907
- var fs19 = __toESM(require("fs"), 1);
38908
- var path19 = __toESM(require("path"), 1);
38342
+ var fs18 = __toESM(require("fs"), 1);
38343
+ var path18 = __toESM(require("path"), 1);
38909
38344
  var CAPABILITIES_FILE_NAME = "capabilities.json";
38910
38345
  var FILE_VERSION = 1;
38911
38346
  var CapabilityStore = class {
38912
38347
  constructor(dataDir) {
38913
38348
  this.dataDir = dataDir;
38914
- fs19.mkdirSync(dataDir, { recursive: true });
38349
+ fs18.mkdirSync(dataDir, { recursive: true });
38915
38350
  this.cache = this.readFromDisk();
38916
38351
  }
38917
38352
  dataDir;
@@ -38935,13 +38370,13 @@ var CapabilityStore = class {
38935
38370
  this.flush();
38936
38371
  }
38937
38372
  filePath() {
38938
- return path19.join(this.dataDir, CAPABILITIES_FILE_NAME);
38373
+ return path18.join(this.dataDir, CAPABILITIES_FILE_NAME);
38939
38374
  }
38940
38375
  readFromDisk() {
38941
38376
  const file = this.filePath();
38942
38377
  let raw;
38943
38378
  try {
38944
- raw = fs19.readFileSync(file, "utf8");
38379
+ raw = fs18.readFileSync(file, "utf8");
38945
38380
  } catch (err) {
38946
38381
  if (err?.code === "ENOENT") return [];
38947
38382
  return [];
@@ -38969,10 +38404,10 @@ var CapabilityStore = class {
38969
38404
  }
38970
38405
  atomicWrite(file, content) {
38971
38406
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
38972
- fs19.writeFileSync(tmp, content, { mode: 384 });
38973
- fs19.renameSync(tmp, file);
38407
+ fs18.writeFileSync(tmp, content, { mode: 384 });
38408
+ fs18.renameSync(tmp, file);
38974
38409
  try {
38975
- fs19.chmodSync(file, 384);
38410
+ fs18.chmodSync(file, 384);
38976
38411
  } catch {
38977
38412
  }
38978
38413
  }
@@ -39065,14 +38500,14 @@ var CapabilityManager = class {
39065
38500
  };
39066
38501
 
39067
38502
  // src/permission/cleanup.ts
39068
- var fs20 = __toESM(require("fs"), 1);
38503
+ var fs19 = __toESM(require("fs"), 1);
39069
38504
  function cleanupGuestSessionsForCapability(cap, factory) {
39070
38505
  const removed = [];
39071
38506
  for (const g2 of cap.grants) {
39072
38507
  if (g2.resource.type !== "persona") continue;
39073
38508
  const dir = factory.vmGuestRoot(g2.resource.id, cap.id);
39074
38509
  try {
39075
- fs20.rmSync(dir, { recursive: true, force: true });
38510
+ fs19.rmSync(dir, { recursive: true, force: true });
39076
38511
  removed.push(dir);
39077
38512
  } catch {
39078
38513
  }
@@ -39081,13 +38516,13 @@ function cleanupGuestSessionsForCapability(cap, factory) {
39081
38516
  }
39082
38517
 
39083
38518
  // src/inbox/inbox-store.ts
39084
- var fs21 = __toESM(require("fs"), 1);
39085
- var path20 = __toESM(require("path"), 1);
38519
+ var fs20 = __toESM(require("fs"), 1);
38520
+ var path19 = __toESM(require("path"), 1);
39086
38521
  var INBOX_SUBDIR = "inbox";
39087
38522
  var InboxStore = class {
39088
38523
  constructor(dataDir) {
39089
38524
  this.dataDir = dataDir;
39090
- fs21.mkdirSync(this.dirPath(), { recursive: true });
38525
+ fs20.mkdirSync(this.dirPath(), { recursive: true });
39091
38526
  }
39092
38527
  dataDir;
39093
38528
  /**
@@ -39099,7 +38534,7 @@ var InboxStore = class {
39099
38534
  const file = this.filePath(peerDeviceId);
39100
38535
  let raw;
39101
38536
  try {
39102
- raw = fs21.readFileSync(file, "utf8");
38537
+ raw = fs20.readFileSync(file, "utf8");
39103
38538
  } catch (err) {
39104
38539
  if (err?.code === "ENOENT") return [];
39105
38540
  return [];
@@ -39115,7 +38550,7 @@ var InboxStore = class {
39115
38550
  const dir = this.dirPath();
39116
38551
  let entries;
39117
38552
  try {
39118
- entries = fs21.readdirSync(dir);
38553
+ entries = fs20.readdirSync(dir);
39119
38554
  } catch (err) {
39120
38555
  if (err?.code === "ENOENT") return [];
39121
38556
  return [];
@@ -39131,9 +38566,9 @@ var InboxStore = class {
39131
38566
  if (existing.some((m2) => m2.id === message.id)) return;
39132
38567
  const file = this.filePath(message.peerDeviceId);
39133
38568
  const line = JSON.stringify(message) + "\n";
39134
- fs21.appendFileSync(file, line, { mode: 384 });
38569
+ fs20.appendFileSync(file, line, { mode: 384 });
39135
38570
  try {
39136
- fs21.chmodSync(file, 384);
38571
+ fs20.chmodSync(file, 384);
39137
38572
  } catch {
39138
38573
  }
39139
38574
  }
@@ -39163,7 +38598,7 @@ var InboxStore = class {
39163
38598
  removeByPeerDeviceId(peerDeviceId) {
39164
38599
  const file = this.filePath(peerDeviceId);
39165
38600
  try {
39166
- fs21.unlinkSync(file);
38601
+ fs20.unlinkSync(file);
39167
38602
  } catch (err) {
39168
38603
  if (err?.code === "ENOENT") return;
39169
38604
  }
@@ -39172,18 +38607,18 @@ var InboxStore = class {
39172
38607
  const file = this.filePath(peerDeviceId);
39173
38608
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
39174
38609
  const content = messages.map((m2) => JSON.stringify(m2)).join("\n") + (messages.length > 0 ? "\n" : "");
39175
- fs21.writeFileSync(tmp, content, { mode: 384 });
39176
- fs21.renameSync(tmp, file);
38610
+ fs20.writeFileSync(tmp, content, { mode: 384 });
38611
+ fs20.renameSync(tmp, file);
39177
38612
  try {
39178
- fs21.chmodSync(file, 384);
38613
+ fs20.chmodSync(file, 384);
39179
38614
  } catch {
39180
38615
  }
39181
38616
  }
39182
38617
  dirPath() {
39183
- return path20.join(this.dataDir, INBOX_SUBDIR);
38618
+ return path19.join(this.dataDir, INBOX_SUBDIR);
39184
38619
  }
39185
38620
  filePath(peerDeviceId) {
39186
- return path20.join(this.dirPath(), `${peerDeviceId}.jsonl`);
38621
+ return path19.join(this.dirPath(), `${peerDeviceId}.jsonl`);
39187
38622
  }
39188
38623
  };
39189
38624
  function parseAllLines(raw) {
@@ -39270,8 +38705,8 @@ var InboxManager = class {
39270
38705
  };
39271
38706
 
39272
38707
  // src/state/contact-store.ts
39273
- var fs22 = __toESM(require("fs"), 1);
39274
- var path21 = __toESM(require("path"), 1);
38708
+ var fs21 = __toESM(require("fs"), 1);
38709
+ var path20 = __toESM(require("path"), 1);
39275
38710
  var FILE_NAME = "contacts.json";
39276
38711
  var ContactStore = class {
39277
38712
  constructor(dataDir) {
@@ -39281,10 +38716,10 @@ var ContactStore = class {
39281
38716
  contacts = /* @__PURE__ */ new Map();
39282
38717
  load() {
39283
38718
  this.contacts.clear();
39284
- const file = path21.join(this.dataDir, FILE_NAME);
38719
+ const file = path20.join(this.dataDir, FILE_NAME);
39285
38720
  let raw;
39286
38721
  try {
39287
- raw = fs22.readFileSync(file, "utf8");
38722
+ raw = fs21.readFileSync(file, "utf8");
39288
38723
  } catch (err) {
39289
38724
  if (err?.code !== "ENOENT") this.renameBak(file);
39290
38725
  return;
@@ -39327,20 +38762,20 @@ var ContactStore = class {
39327
38762
  return existed;
39328
38763
  }
39329
38764
  flush() {
39330
- const file = path21.join(this.dataDir, FILE_NAME);
38765
+ const file = path20.join(this.dataDir, FILE_NAME);
39331
38766
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
39332
38767
  const content = JSON.stringify(
39333
38768
  { contacts: Array.from(this.contacts.values()) },
39334
38769
  null,
39335
38770
  2
39336
38771
  );
39337
- fs22.mkdirSync(this.dataDir, { recursive: true });
39338
- fs22.writeFileSync(tmp, content, { mode: 384 });
39339
- fs22.renameSync(tmp, file);
38772
+ fs21.mkdirSync(this.dataDir, { recursive: true });
38773
+ fs21.writeFileSync(tmp, content, { mode: 384 });
38774
+ fs21.renameSync(tmp, file);
39340
38775
  }
39341
38776
  renameBak(file) {
39342
38777
  try {
39343
- fs22.renameSync(file, `${file}.bak`);
38778
+ fs21.renameSync(file, `${file}.bak`);
39344
38779
  } catch {
39345
38780
  }
39346
38781
  }
@@ -39490,61 +38925,61 @@ async function autoReverseContact(args) {
39490
38925
  }
39491
38926
 
39492
38927
  // src/migrations/2026-05-20-flatten-sessions.ts
39493
- var fs23 = __toESM(require("fs"), 1);
39494
- var path22 = __toESM(require("path"), 1);
38928
+ var fs22 = __toESM(require("fs"), 1);
38929
+ var path21 = __toESM(require("path"), 1);
39495
38930
  var MIGRATION_FLAG_NAME = ".migration.v1.done";
39496
38931
  function migrateFlattenSessions(opts) {
39497
38932
  const dataDir = opts.dataDir;
39498
38933
  const now = opts.now ?? Date.now;
39499
- const sessionsDir = path22.join(dataDir, "sessions");
39500
- const flagPath = path22.join(sessionsDir, MIGRATION_FLAG_NAME);
38934
+ const sessionsDir = path21.join(dataDir, "sessions");
38935
+ const flagPath = path21.join(sessionsDir, MIGRATION_FLAG_NAME);
39501
38936
  if (existsSync3(flagPath)) {
39502
38937
  return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
39503
38938
  }
39504
38939
  let movedBare = 0;
39505
38940
  let movedVmOwner = 0;
39506
38941
  let archivedListener = 0;
39507
- const defaultDir = path22.join(sessionsDir, "default");
38942
+ const defaultDir = path21.join(sessionsDir, "default");
39508
38943
  if (existsSync3(defaultDir)) {
39509
38944
  for (const entry of readdirSafe(defaultDir)) {
39510
38945
  if (!entry.endsWith(".json")) continue;
39511
- const src = path22.join(defaultDir, entry);
39512
- const dst = path22.join(sessionsDir, entry);
39513
- fs23.renameSync(src, dst);
38946
+ const src = path21.join(defaultDir, entry);
38947
+ const dst = path21.join(sessionsDir, entry);
38948
+ fs22.renameSync(src, dst);
39514
38949
  movedBare += 1;
39515
38950
  }
39516
38951
  rmdirIfEmpty(defaultDir);
39517
38952
  }
39518
38953
  for (const pid of readdirSafe(sessionsDir)) {
39519
- const personaDir = path22.join(sessionsDir, pid);
38954
+ const personaDir = path21.join(sessionsDir, pid);
39520
38955
  if (!isDir(personaDir)) continue;
39521
38956
  if (pid === "default") continue;
39522
- const ownerSrc = path22.join(personaDir, "owner");
38957
+ const ownerSrc = path21.join(personaDir, "owner");
39523
38958
  if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
39524
- const ownerDst = path22.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
39525
- fs23.mkdirSync(ownerDst, { recursive: true });
38959
+ const ownerDst = path21.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
38960
+ fs22.mkdirSync(ownerDst, { recursive: true });
39526
38961
  for (const file of readdirSafe(ownerSrc)) {
39527
38962
  if (!file.endsWith(".json")) continue;
39528
- fs23.renameSync(path22.join(ownerSrc, file), path22.join(ownerDst, file));
38963
+ fs22.renameSync(path21.join(ownerSrc, file), path21.join(ownerDst, file));
39529
38964
  movedVmOwner += 1;
39530
38965
  }
39531
38966
  rmdirIfEmpty(ownerSrc);
39532
38967
  }
39533
- const listenerSrc = path22.join(personaDir, "listener");
38968
+ const listenerSrc = path21.join(personaDir, "listener");
39534
38969
  if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
39535
- const archiveDst = path22.join(dataDir, ".legacy", `listener-${pid}`);
39536
- fs23.mkdirSync(archiveDst, { recursive: true });
38970
+ const archiveDst = path21.join(dataDir, ".legacy", `listener-${pid}`);
38971
+ fs22.mkdirSync(archiveDst, { recursive: true });
39537
38972
  for (const file of readdirSafe(listenerSrc)) {
39538
38973
  if (!file.endsWith(".json")) continue;
39539
- fs23.renameSync(path22.join(listenerSrc, file), path22.join(archiveDst, file));
38974
+ fs22.renameSync(path21.join(listenerSrc, file), path21.join(archiveDst, file));
39540
38975
  archivedListener += 1;
39541
38976
  }
39542
38977
  rmdirIfEmpty(listenerSrc);
39543
38978
  }
39544
38979
  rmdirIfEmpty(personaDir);
39545
38980
  }
39546
- fs23.mkdirSync(sessionsDir, { recursive: true });
39547
- fs23.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
38981
+ fs22.mkdirSync(sessionsDir, { recursive: true });
38982
+ fs22.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
39548
38983
  return {
39549
38984
  skipped: false,
39550
38985
  flagWritten: true,
@@ -39555,7 +38990,7 @@ function migrateFlattenSessions(opts) {
39555
38990
  }
39556
38991
  function existsSync3(p2) {
39557
38992
  try {
39558
- fs23.statSync(p2);
38993
+ fs22.statSync(p2);
39559
38994
  return true;
39560
38995
  } catch {
39561
38996
  return false;
@@ -39563,31 +38998,31 @@ function existsSync3(p2) {
39563
38998
  }
39564
38999
  function isDir(p2) {
39565
39000
  try {
39566
- return fs23.statSync(p2).isDirectory();
39001
+ return fs22.statSync(p2).isDirectory();
39567
39002
  } catch {
39568
39003
  return false;
39569
39004
  }
39570
39005
  }
39571
39006
  function readdirSafe(p2) {
39572
39007
  try {
39573
- return fs23.readdirSync(p2);
39008
+ return fs22.readdirSync(p2);
39574
39009
  } catch {
39575
39010
  return [];
39576
39011
  }
39577
39012
  }
39578
39013
  function rmdirIfEmpty(p2) {
39579
39014
  try {
39580
- fs23.rmdirSync(p2);
39015
+ fs22.rmdirSync(p2);
39581
39016
  } catch {
39582
39017
  }
39583
39018
  }
39584
39019
 
39585
39020
  // src/transport/http-router.ts
39586
- var import_node_fs18 = __toESM(require("fs"), 1);
39587
- var import_node_path18 = __toESM(require("path"), 1);
39021
+ var import_node_fs17 = __toESM(require("fs"), 1);
39022
+ var import_node_path17 = __toESM(require("path"), 1);
39588
39023
 
39589
39024
  // src/attachment/mime.ts
39590
- var import_node_path15 = __toESM(require("path"), 1);
39025
+ var import_node_path14 = __toESM(require("path"), 1);
39591
39026
  var TEXT_PLAIN = "text/plain; charset=utf-8";
39592
39027
  var EXT_TO_NATIVE_MIME = {
39593
39028
  // 图片
@@ -39694,7 +39129,7 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
39694
39129
  ".mk"
39695
39130
  ]);
39696
39131
  function lookupMime(filePathOrName) {
39697
- const ext = import_node_path15.default.extname(filePathOrName).toLowerCase();
39132
+ const ext = import_node_path14.default.extname(filePathOrName).toLowerCase();
39698
39133
  if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
39699
39134
  if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
39700
39135
  return "application/octet-stream";
@@ -39763,8 +39198,8 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
39763
39198
  }
39764
39199
 
39765
39200
  // src/attachment/upload.ts
39766
- var import_node_fs17 = __toESM(require("fs"), 1);
39767
- var import_node_path16 = __toESM(require("path"), 1);
39201
+ var import_node_fs16 = __toESM(require("fs"), 1);
39202
+ var import_node_path15 = __toESM(require("path"), 1);
39768
39203
  var import_node_crypto5 = __toESM(require("crypto"), 1);
39769
39204
  var import_promises = require("stream/promises");
39770
39205
  var UploadError = class extends Error {
@@ -39776,22 +39211,22 @@ var UploadError = class extends Error {
39776
39211
  code;
39777
39212
  };
39778
39213
  function assertValidFileName(fileName) {
39779
- if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path16.default.basename(fileName)) {
39214
+ if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path15.default.basename(fileName)) {
39780
39215
  throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
39781
39216
  }
39782
39217
  }
39783
39218
  var HASH_PREFIX_LEN = 16;
39784
39219
  async function writeUploadedAttachment(args) {
39785
39220
  assertValidFileName(args.fileName);
39786
- const attachmentsRoot = import_node_path16.default.join(args.sessionDir, ".attachments");
39221
+ const attachmentsRoot = import_node_path15.default.join(args.sessionDir, ".attachments");
39787
39222
  try {
39788
- import_node_fs17.default.mkdirSync(attachmentsRoot, { recursive: true });
39223
+ import_node_fs16.default.mkdirSync(attachmentsRoot, { recursive: true });
39789
39224
  } catch (err) {
39790
39225
  throw new UploadError("STORAGE_ERROR", `mkdir failed: ${err.message}`);
39791
39226
  }
39792
39227
  const hasher = import_node_crypto5.default.createHash("sha256");
39793
39228
  let actualSize = 0;
39794
- const tmpPath = import_node_path16.default.join(
39229
+ const tmpPath = import_node_path15.default.join(
39795
39230
  attachmentsRoot,
39796
39231
  `.upload-${process.pid}-${Date.now()}-${import_node_crypto5.default.randomBytes(4).toString("hex")}`
39797
39232
  );
@@ -39806,18 +39241,18 @@ async function writeUploadedAttachment(args) {
39806
39241
  yield buf;
39807
39242
  }
39808
39243
  },
39809
- import_node_fs17.default.createWriteStream(tmpPath, { mode: 384 })
39244
+ import_node_fs16.default.createWriteStream(tmpPath, { mode: 384 })
39810
39245
  );
39811
39246
  } catch (err) {
39812
39247
  try {
39813
- import_node_fs17.default.unlinkSync(tmpPath);
39248
+ import_node_fs16.default.unlinkSync(tmpPath);
39814
39249
  } catch {
39815
39250
  }
39816
39251
  throw new UploadError("STORAGE_ERROR", `write failed: ${err.message}`);
39817
39252
  }
39818
39253
  if (actualSize !== args.contentLength) {
39819
39254
  try {
39820
- import_node_fs17.default.unlinkSync(tmpPath);
39255
+ import_node_fs16.default.unlinkSync(tmpPath);
39821
39256
  } catch {
39822
39257
  }
39823
39258
  throw new UploadError(
@@ -39826,35 +39261,35 @@ async function writeUploadedAttachment(args) {
39826
39261
  );
39827
39262
  }
39828
39263
  const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
39829
- const hashDir = import_node_path16.default.join(attachmentsRoot, attachmentId);
39264
+ const hashDir = import_node_path15.default.join(attachmentsRoot, attachmentId);
39830
39265
  let finalFileName;
39831
39266
  let hashDirExists = false;
39832
39267
  try {
39833
- hashDirExists = import_node_fs17.default.statSync(hashDir).isDirectory();
39268
+ hashDirExists = import_node_fs16.default.statSync(hashDir).isDirectory();
39834
39269
  } catch {
39835
39270
  }
39836
39271
  if (hashDirExists) {
39837
- const existing = import_node_fs17.default.readdirSync(hashDir).filter((n) => !n.startsWith("."));
39272
+ const existing = import_node_fs16.default.readdirSync(hashDir).filter((n) => !n.startsWith("."));
39838
39273
  finalFileName = existing[0] ?? args.fileName;
39839
39274
  try {
39840
- import_node_fs17.default.unlinkSync(tmpPath);
39275
+ import_node_fs16.default.unlinkSync(tmpPath);
39841
39276
  } catch {
39842
39277
  }
39843
39278
  } else {
39844
39279
  try {
39845
- import_node_fs17.default.mkdirSync(hashDir, { recursive: true });
39280
+ import_node_fs16.default.mkdirSync(hashDir, { recursive: true });
39846
39281
  finalFileName = args.fileName;
39847
- import_node_fs17.default.renameSync(tmpPath, import_node_path16.default.join(hashDir, finalFileName));
39282
+ import_node_fs16.default.renameSync(tmpPath, import_node_path15.default.join(hashDir, finalFileName));
39848
39283
  } catch (err) {
39849
39284
  try {
39850
- import_node_fs17.default.unlinkSync(tmpPath);
39285
+ import_node_fs16.default.unlinkSync(tmpPath);
39851
39286
  } catch {
39852
39287
  }
39853
39288
  throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
39854
39289
  }
39855
39290
  }
39856
- const absPath = import_node_path16.default.join(hashDir, finalFileName);
39857
- const relPath = import_node_path16.default.relative(args.sessionDir, absPath);
39291
+ const absPath = import_node_path15.default.join(hashDir, finalFileName);
39292
+ const relPath = import_node_path15.default.relative(args.sessionDir, absPath);
39858
39293
  args.groupFileStore.upsert(args.scope, args.sessionId, {
39859
39294
  relPath: absPath,
39860
39295
  // 存绝对路径,与现有 agent 入清单的形态一致(attachment.ts:144 双形态兼容)
@@ -39868,7 +39303,7 @@ async function writeUploadedAttachment(args) {
39868
39303
 
39869
39304
  // src/extension/import.ts
39870
39305
  var import_promises2 = __toESM(require("fs/promises"), 1);
39871
- var import_node_path17 = __toESM(require("path"), 1);
39306
+ var import_node_path16 = __toESM(require("path"), 1);
39872
39307
  var import_node_os10 = __toESM(require("os"), 1);
39873
39308
  var import_jszip = __toESM(require_lib3(), 1);
39874
39309
  var ImportError = class extends Error {
@@ -39886,7 +39321,7 @@ async function importZip(buf, root) {
39886
39321
  throw new ImportError("ZIP_INVALID", `failed to load zip: ${e.message}`);
39887
39322
  }
39888
39323
  for (const name of Object.keys(zip.files)) {
39889
- if (name.includes("..") || name.startsWith("/") || import_node_path17.default.isAbsolute(name)) {
39324
+ if (name.includes("..") || name.startsWith("/") || import_node_path16.default.isAbsolute(name)) {
39890
39325
  throw new ImportError("ZIP_INVALID", `unsafe zip entry path: ${name}`);
39891
39326
  }
39892
39327
  }
@@ -39919,7 +39354,7 @@ async function importZip(buf, root) {
39919
39354
  );
39920
39355
  }
39921
39356
  }
39922
- const destDir = import_node_path17.default.join(root, manifest.id);
39357
+ const destDir = import_node_path16.default.join(root, manifest.id);
39923
39358
  let destExists = false;
39924
39359
  try {
39925
39360
  await import_promises2.default.access(destDir);
@@ -39929,15 +39364,15 @@ async function importZip(buf, root) {
39929
39364
  if (destExists) {
39930
39365
  throw new ImportError("ALREADY_EXISTS", `extension ${manifest.id} already installed`);
39931
39366
  }
39932
- const stage = await import_promises2.default.mkdtemp(import_node_path17.default.join(import_node_os10.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
39367
+ const stage = await import_promises2.default.mkdtemp(import_node_path16.default.join(import_node_os10.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
39933
39368
  try {
39934
39369
  for (const [name, entry] of Object.entries(zip.files)) {
39935
- const dest = import_node_path17.default.join(stage, name);
39370
+ const dest = import_node_path16.default.join(stage, name);
39936
39371
  if (entry.dir) {
39937
39372
  await import_promises2.default.mkdir(dest, { recursive: true });
39938
39373
  continue;
39939
39374
  }
39940
- await import_promises2.default.mkdir(import_node_path17.default.dirname(dest), { recursive: true });
39375
+ await import_promises2.default.mkdir(import_node_path16.default.dirname(dest), { recursive: true });
39941
39376
  const content = await entry.async("nodebuffer");
39942
39377
  await import_promises2.default.writeFile(dest, content);
39943
39378
  }
@@ -39963,11 +39398,9 @@ var EXPOSED_RPC_METHODS = [
39963
39398
  "appBuilder.reportStage",
39964
39399
  // 单栏 §5.6.5 fix: UI 切 session 时调(assistant 不需要主动调,但暴露白名单避免误猜成 forbidden)
39965
39400
  "appBuilder.setActiveSession",
39966
- // Persona dispatch (Task 4): A 端 dispatch MCP server 调 run(hold-and-wait 一次);
39967
- // B dispatch MCP server 调 complete(带 outcome 触发 run 端 resolve)。详见
39968
- // protocol/src/dispatch.ts。
39969
- "personaDispatch.run",
39970
- "personaDispatch.complete"
39401
+ // dataclaw-builder:persona 建页时取建页人身份(含 union_id)写进生成 app 的配置。
39402
+ // 路由到 handlers['auth:getIdentity'],只返 identity、绝不带 ttcToken(见 handlers/feishu-auth.ts)。
39403
+ "auth.getIdentity"
39971
39404
  ];
39972
39405
  async function handleRpcRequest(input) {
39973
39406
  const { method, body, sessionId, dispatcher } = input;
@@ -40056,7 +39489,7 @@ function isValidUploadFileName(fileName) {
40056
39489
  if (fileName === "." || fileName === "..") return false;
40057
39490
  if (fileName.startsWith(".")) return false;
40058
39491
  if (fileName.includes("/") || fileName.includes("\\")) return false;
40059
- return fileName === import_node_path18.default.basename(fileName);
39492
+ return fileName === import_node_path17.default.basename(fileName);
40060
39493
  }
40061
39494
  function createHttpRouter(deps) {
40062
39495
  return async (req, res) => {
@@ -40103,8 +39536,6 @@ function createHttpRouter(deps) {
40103
39536
  sendJson(res, 403, { code: "NOT_LOOPBACK", message: "RPC adapter only accepts loopback connections" });
40104
39537
  return true;
40105
39538
  }
40106
- req.socket.setTimeout(0);
40107
- res.socket?.setTimeout(0);
40108
39539
  const method = url.pathname.slice(RPC_ROUTE_PREFIX.length).split("?")[0] ?? "";
40109
39540
  const sessionId = req.headers["x-clawd-session-id"] ?? void 0;
40110
39541
  let body;
@@ -40287,7 +39718,7 @@ function createHttpRouter(deps) {
40287
39718
  return true;
40288
39719
  }
40289
39720
  let absPath;
40290
- if (import_node_path18.default.isAbsolute(pathParam)) {
39721
+ if (import_node_path17.default.isAbsolute(pathParam)) {
40291
39722
  absPath = pathParam;
40292
39723
  } else if (deps.sessionStore) {
40293
39724
  const file = deps.sessionStore.read(sid);
@@ -40295,7 +39726,7 @@ function createHttpRouter(deps) {
40295
39726
  sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
40296
39727
  return true;
40297
39728
  }
40298
- absPath = import_node_path18.default.join(file.cwd, pathParam);
39729
+ absPath = import_node_path17.default.join(file.cwd, pathParam);
40299
39730
  } else {
40300
39731
  sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
40301
39732
  return true;
@@ -40378,7 +39809,7 @@ function withCtx(ctx, body) {
40378
39809
  function streamFile(res, absPath, logger) {
40379
39810
  let stat;
40380
39811
  try {
40381
- stat = import_node_fs18.default.statSync(absPath);
39812
+ stat = import_node_fs17.default.statSync(absPath);
40382
39813
  } catch (err) {
40383
39814
  const code = err?.code;
40384
39815
  if (code === "ENOENT") {
@@ -40393,7 +39824,7 @@ function streamFile(res, absPath, logger) {
40393
39824
  return;
40394
39825
  }
40395
39826
  const mime = lookupMime(absPath);
40396
- const basename = import_node_path18.default.basename(absPath);
39827
+ const basename = import_node_path17.default.basename(absPath);
40397
39828
  res.writeHead(200, {
40398
39829
  "Content-Type": mime,
40399
39830
  "Content-Length": String(stat.size),
@@ -40401,7 +39832,7 @@ function streamFile(res, absPath, logger) {
40401
39832
  // 防止浏览器把任意 mime 当 html 渲染
40402
39833
  "X-Content-Type-Options": "nosniff"
40403
39834
  });
40404
- const stream = import_node_fs18.default.createReadStream(absPath);
39835
+ const stream = import_node_fs17.default.createReadStream(absPath);
40405
39836
  stream.on("error", (err) => {
40406
39837
  logger?.warn("streamFile read error", { absPath, err: err.message });
40407
39838
  res.destroy();
@@ -40410,8 +39841,8 @@ function streamFile(res, absPath, logger) {
40410
39841
  }
40411
39842
 
40412
39843
  // src/attachment/gc.ts
40413
- var import_node_fs19 = __toESM(require("fs"), 1);
40414
- var import_node_path19 = __toESM(require("path"), 1);
39844
+ var import_node_fs18 = __toESM(require("fs"), 1);
39845
+ var import_node_path18 = __toESM(require("path"), 1);
40415
39846
  var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
40416
39847
  function runAttachmentGc(args) {
40417
39848
  const now = (args.now ?? Date.now)();
@@ -40420,38 +39851,38 @@ function runAttachmentGc(args) {
40420
39851
  for (const { scope, sessionId } of args.sessionScopes) {
40421
39852
  for (const entry of args.groupFileStore.list(scope, sessionId)) {
40422
39853
  if (entry.stale) continue;
40423
- if (import_node_path19.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
39854
+ if (import_node_path18.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
40424
39855
  }
40425
39856
  }
40426
39857
  for (const { scope, sessionId } of args.sessionScopes) {
40427
- const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path19.default.join(
39858
+ const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path18.default.join(
40428
39859
  args.dataDir,
40429
39860
  "sessions",
40430
39861
  ...scopeSubPath(scope).map(safeFileName),
40431
39862
  safeFileName(sessionId)
40432
39863
  );
40433
- const attRoot = import_node_path19.default.join(sessionDir, ".attachments");
39864
+ const attRoot = import_node_path18.default.join(sessionDir, ".attachments");
40434
39865
  let hashDirs;
40435
39866
  try {
40436
- hashDirs = import_node_fs19.default.readdirSync(attRoot);
39867
+ hashDirs = import_node_fs18.default.readdirSync(attRoot);
40437
39868
  } catch (err) {
40438
39869
  if (err.code === "ENOENT") continue;
40439
39870
  args.logger?.warn("attachment gc: readdir failed", { attRoot, err: err.message });
40440
39871
  continue;
40441
39872
  }
40442
39873
  for (const hashDir of hashDirs) {
40443
- const hashDirAbs = import_node_path19.default.join(attRoot, hashDir);
39874
+ const hashDirAbs = import_node_path18.default.join(attRoot, hashDir);
40444
39875
  let files;
40445
39876
  try {
40446
- files = import_node_fs19.default.readdirSync(hashDirAbs);
39877
+ files = import_node_fs18.default.readdirSync(hashDirAbs);
40447
39878
  } catch {
40448
39879
  continue;
40449
39880
  }
40450
39881
  for (const name of files) {
40451
- const file = import_node_path19.default.join(hashDirAbs, name);
39882
+ const file = import_node_path18.default.join(hashDirAbs, name);
40452
39883
  let stat;
40453
39884
  try {
40454
- stat = import_node_fs19.default.statSync(file);
39885
+ stat = import_node_fs18.default.statSync(file);
40455
39886
  } catch {
40456
39887
  continue;
40457
39888
  }
@@ -40460,26 +39891,26 @@ function runAttachmentGc(args) {
40460
39891
  if (age < ttlMs) continue;
40461
39892
  if (liveAbs.has(file)) continue;
40462
39893
  try {
40463
- import_node_fs19.default.unlinkSync(file);
39894
+ import_node_fs18.default.unlinkSync(file);
40464
39895
  } catch (err) {
40465
39896
  args.logger?.warn("attachment gc: unlink failed", { file, err: err.message });
40466
39897
  }
40467
39898
  }
40468
39899
  try {
40469
- if (import_node_fs19.default.readdirSync(hashDirAbs).length === 0) import_node_fs19.default.rmdirSync(hashDirAbs);
39900
+ if (import_node_fs18.default.readdirSync(hashDirAbs).length === 0) import_node_fs18.default.rmdirSync(hashDirAbs);
40470
39901
  } catch {
40471
39902
  }
40472
39903
  }
40473
39904
  try {
40474
- if (import_node_fs19.default.readdirSync(attRoot).length === 0) import_node_fs19.default.rmdirSync(attRoot);
39905
+ if (import_node_fs18.default.readdirSync(attRoot).length === 0) import_node_fs18.default.rmdirSync(attRoot);
40475
39906
  } catch {
40476
39907
  }
40477
39908
  }
40478
39909
  }
40479
39910
 
40480
39911
  // src/attachment/group.ts
40481
- var import_node_fs20 = __toESM(require("fs"), 1);
40482
- var import_node_path20 = __toESM(require("path"), 1);
39912
+ var import_node_fs19 = __toESM(require("fs"), 1);
39913
+ var import_node_path19 = __toESM(require("path"), 1);
40483
39914
  var import_node_crypto6 = __toESM(require("crypto"), 1);
40484
39915
  init_protocol();
40485
39916
  var GroupFileStore = class {
@@ -40491,11 +39922,11 @@ var GroupFileStore = class {
40491
39922
  this.logger = opts.logger;
40492
39923
  }
40493
39924
  rootForScope(scope) {
40494
- return import_node_path20.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
39925
+ return import_node_path19.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
40495
39926
  }
40496
39927
  /** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
40497
39928
  filePath(scope, sessionId) {
40498
- return import_node_path20.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
39929
+ return import_node_path19.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
40499
39930
  }
40500
39931
  cacheKey(scope, sessionId) {
40501
39932
  return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
@@ -40504,7 +39935,7 @@ var GroupFileStore = class {
40504
39935
  readFile(scope, sessionId) {
40505
39936
  const file = this.filePath(scope, sessionId);
40506
39937
  try {
40507
- const raw = import_node_fs20.default.readFileSync(file, "utf8");
39938
+ const raw = import_node_fs19.default.readFileSync(file, "utf8");
40508
39939
  const parsed = JSON.parse(raw);
40509
39940
  if (!Array.isArray(parsed)) {
40510
39941
  this.logger?.warn("GroupFileStore.readFile: not an array; resetting session entries", {
@@ -40530,10 +39961,10 @@ var GroupFileStore = class {
40530
39961
  }
40531
39962
  writeFile(scope, sessionId, entries) {
40532
39963
  const file = this.filePath(scope, sessionId);
40533
- import_node_fs20.default.mkdirSync(import_node_path20.default.dirname(file), { recursive: true });
39964
+ import_node_fs19.default.mkdirSync(import_node_path19.default.dirname(file), { recursive: true });
40534
39965
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
40535
- import_node_fs20.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
40536
- import_node_fs20.default.renameSync(tmp, file);
39966
+ import_node_fs19.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
39967
+ import_node_fs19.default.renameSync(tmp, file);
40537
39968
  }
40538
39969
  /** 拉一份当前 session 的清单。读盘 → cache;之后调用复用 cache */
40539
39970
  list(scope, sessionId) {
@@ -40619,10 +40050,10 @@ var GroupFileStore = class {
40619
40050
  };
40620
40051
 
40621
40052
  // src/discovery/state-file.ts
40622
- var import_node_fs21 = __toESM(require("fs"), 1);
40623
- var import_node_path21 = __toESM(require("path"), 1);
40053
+ var import_node_fs20 = __toESM(require("fs"), 1);
40054
+ var import_node_path20 = __toESM(require("path"), 1);
40624
40055
  function defaultStateFilePath(dataDir) {
40625
- return import_node_path21.default.join(dataDir, "state.json");
40056
+ return import_node_path20.default.join(dataDir, "state.json");
40626
40057
  }
40627
40058
  function isPidAlive(pid) {
40628
40059
  if (!Number.isFinite(pid) || pid <= 0) return false;
@@ -40644,7 +40075,7 @@ var StateFileManager = class {
40644
40075
  }
40645
40076
  read() {
40646
40077
  try {
40647
- const raw = import_node_fs21.default.readFileSync(this.file, "utf8");
40078
+ const raw = import_node_fs20.default.readFileSync(this.file, "utf8");
40648
40079
  const parsed = JSON.parse(raw);
40649
40080
  return parsed;
40650
40081
  } catch {
@@ -40658,20 +40089,20 @@ var StateFileManager = class {
40658
40089
  return { status: "stale", existing };
40659
40090
  }
40660
40091
  write(state) {
40661
- import_node_fs21.default.mkdirSync(import_node_path21.default.dirname(this.file), { recursive: true });
40092
+ import_node_fs20.default.mkdirSync(import_node_path20.default.dirname(this.file), { recursive: true });
40662
40093
  const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
40663
- import_node_fs21.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
40664
- import_node_fs21.default.renameSync(tmp, this.file);
40094
+ import_node_fs20.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
40095
+ import_node_fs20.default.renameSync(tmp, this.file);
40665
40096
  if (process.platform !== "win32") {
40666
40097
  try {
40667
- import_node_fs21.default.chmodSync(this.file, 384);
40098
+ import_node_fs20.default.chmodSync(this.file, 384);
40668
40099
  } catch {
40669
40100
  }
40670
40101
  }
40671
40102
  }
40672
40103
  delete() {
40673
40104
  try {
40674
- import_node_fs21.default.unlinkSync(this.file);
40105
+ import_node_fs20.default.unlinkSync(this.file);
40675
40106
  } catch {
40676
40107
  }
40677
40108
  }
@@ -40686,14 +40117,14 @@ function readDaemonSourceFromEnv(env = process.env) {
40686
40117
  }
40687
40118
 
40688
40119
  // src/tunnel/tunnel-manager.ts
40689
- var import_node_fs25 = __toESM(require("fs"), 1);
40690
- var import_node_path25 = __toESM(require("path"), 1);
40120
+ var import_node_fs24 = __toESM(require("fs"), 1);
40121
+ var import_node_path24 = __toESM(require("path"), 1);
40691
40122
  var import_node_crypto7 = __toESM(require("crypto"), 1);
40692
40123
  var import_node_child_process9 = require("child_process");
40693
40124
 
40694
40125
  // src/tunnel/tunnel-store.ts
40695
- var import_node_fs22 = __toESM(require("fs"), 1);
40696
- var import_node_path22 = __toESM(require("path"), 1);
40126
+ var import_node_fs21 = __toESM(require("fs"), 1);
40127
+ var import_node_path21 = __toESM(require("path"), 1);
40697
40128
  var TunnelStore = class {
40698
40129
  constructor(filePath) {
40699
40130
  this.filePath = filePath;
@@ -40701,7 +40132,7 @@ var TunnelStore = class {
40701
40132
  filePath;
40702
40133
  async get() {
40703
40134
  try {
40704
- const raw = await import_node_fs22.default.promises.readFile(this.filePath, "utf8");
40135
+ const raw = await import_node_fs21.default.promises.readFile(this.filePath, "utf8");
40705
40136
  const obj = JSON.parse(raw);
40706
40137
  if (!isPersistedTunnel(obj)) return null;
40707
40138
  return obj;
@@ -40712,22 +40143,22 @@ var TunnelStore = class {
40712
40143
  }
40713
40144
  }
40714
40145
  async set(v2) {
40715
- const dir = import_node_path22.default.dirname(this.filePath);
40716
- await import_node_fs22.default.promises.mkdir(dir, { recursive: true });
40146
+ const dir = import_node_path21.default.dirname(this.filePath);
40147
+ await import_node_fs21.default.promises.mkdir(dir, { recursive: true });
40717
40148
  const data = JSON.stringify(v2, null, 2);
40718
40149
  const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
40719
- await import_node_fs22.default.promises.writeFile(tmp, data, { mode: 384 });
40150
+ await import_node_fs21.default.promises.writeFile(tmp, data, { mode: 384 });
40720
40151
  if (process.platform !== "win32") {
40721
40152
  try {
40722
- await import_node_fs22.default.promises.chmod(tmp, 384);
40153
+ await import_node_fs21.default.promises.chmod(tmp, 384);
40723
40154
  } catch {
40724
40155
  }
40725
40156
  }
40726
- await import_node_fs22.default.promises.rename(tmp, this.filePath);
40157
+ await import_node_fs21.default.promises.rename(tmp, this.filePath);
40727
40158
  }
40728
40159
  async clear() {
40729
40160
  try {
40730
- await import_node_fs22.default.promises.unlink(this.filePath);
40161
+ await import_node_fs21.default.promises.unlink(this.filePath);
40731
40162
  } catch (err) {
40732
40163
  const code = err?.code;
40733
40164
  if (code !== "ENOENT") throw err;
@@ -40822,11 +40253,11 @@ function escape(v2) {
40822
40253
  }
40823
40254
 
40824
40255
  // src/tunnel/frpc-binary.ts
40825
- var import_node_fs23 = __toESM(require("fs"), 1);
40256
+ var import_node_fs22 = __toESM(require("fs"), 1);
40826
40257
  var import_node_os11 = __toESM(require("os"), 1);
40827
- var import_node_path23 = __toESM(require("path"), 1);
40258
+ var import_node_path22 = __toESM(require("path"), 1);
40828
40259
  var import_node_child_process7 = require("child_process");
40829
- var import_node_stream3 = require("stream");
40260
+ var import_node_stream2 = require("stream");
40830
40261
  var import_promises3 = require("stream/promises");
40831
40262
  var FRPC_VERSION = "0.68.0";
40832
40263
  var UnsupportedPlatformError = class extends Error {
@@ -40856,20 +40287,20 @@ function frpcDownloadUrl(version2, p2) {
40856
40287
  }
40857
40288
  async function ensureFrpcBinary(opts) {
40858
40289
  if (opts.override) {
40859
- if (!import_node_fs23.default.existsSync(opts.override)) {
40290
+ if (!import_node_fs22.default.existsSync(opts.override)) {
40860
40291
  throw new Error(`frpc binary not found at override path: ${opts.override}`);
40861
40292
  }
40862
40293
  return opts.override;
40863
40294
  }
40864
40295
  const version2 = opts.version ?? FRPC_VERSION;
40865
40296
  const platform = opts.platform ?? detectPlatform();
40866
- const binDir = import_node_path23.default.join(opts.dataDir, "bin");
40867
- import_node_fs23.default.mkdirSync(binDir, { recursive: true });
40297
+ const binDir = import_node_path22.default.join(opts.dataDir, "bin");
40298
+ import_node_fs22.default.mkdirSync(binDir, { recursive: true });
40868
40299
  cleanupStaleArtifacts(binDir);
40869
- const stableBin = import_node_path23.default.join(binDir, "frpc");
40870
- if (import_node_fs23.default.existsSync(stableBin)) return stableBin;
40300
+ const stableBin = import_node_path22.default.join(binDir, "frpc");
40301
+ if (import_node_fs22.default.existsSync(stableBin)) return stableBin;
40871
40302
  const partialBin = `${stableBin}.partial`;
40872
- const tarballPath = import_node_path23.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
40303
+ const tarballPath = import_node_path22.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
40873
40304
  try {
40874
40305
  const url = frpcDownloadUrl(version2, platform);
40875
40306
  await downloadToFile(url, tarballPath, opts.fetchImpl);
@@ -40878,8 +40309,8 @@ async function ensureFrpcBinary(opts) {
40878
40309
  } else {
40879
40310
  await extractFrpcFromTarball(tarballPath, binDir, version2, platform, partialBin);
40880
40311
  }
40881
- import_node_fs23.default.chmodSync(partialBin, 493);
40882
- import_node_fs23.default.renameSync(partialBin, stableBin);
40312
+ import_node_fs22.default.chmodSync(partialBin, 493);
40313
+ import_node_fs22.default.renameSync(partialBin, stableBin);
40883
40314
  } finally {
40884
40315
  safeUnlink(tarballPath);
40885
40316
  safeUnlink(partialBin);
@@ -40889,15 +40320,15 @@ async function ensureFrpcBinary(opts) {
40889
40320
  function cleanupStaleArtifacts(binDir) {
40890
40321
  let entries;
40891
40322
  try {
40892
- entries = import_node_fs23.default.readdirSync(binDir);
40323
+ entries = import_node_fs22.default.readdirSync(binDir);
40893
40324
  } catch {
40894
40325
  return;
40895
40326
  }
40896
40327
  for (const name of entries) {
40897
40328
  if (name.endsWith(".partial") || name.startsWith("extract-")) {
40898
- const full = import_node_path23.default.join(binDir, name);
40329
+ const full = import_node_path22.default.join(binDir, name);
40899
40330
  try {
40900
- import_node_fs23.default.rmSync(full, { recursive: true, force: true });
40331
+ import_node_fs22.default.rmSync(full, { recursive: true, force: true });
40901
40332
  } catch {
40902
40333
  }
40903
40334
  }
@@ -40905,7 +40336,7 @@ function cleanupStaleArtifacts(binDir) {
40905
40336
  }
40906
40337
  function safeUnlink(p2) {
40907
40338
  try {
40908
- import_node_fs23.default.unlinkSync(p2);
40339
+ import_node_fs22.default.unlinkSync(p2);
40909
40340
  } catch {
40910
40341
  }
40911
40342
  }
@@ -40916,13 +40347,13 @@ async function downloadToFile(url, dest, fetchImpl) {
40916
40347
  if (!res.ok || !res.body) {
40917
40348
  throw new Error(`download failed: ${res.status} ${res.statusText}`);
40918
40349
  }
40919
- const out = import_node_fs23.default.createWriteStream(dest);
40920
- const nodeStream = import_node_stream3.Readable.fromWeb(res.body);
40350
+ const out = import_node_fs22.default.createWriteStream(dest);
40351
+ const nodeStream = import_node_stream2.Readable.fromWeb(res.body);
40921
40352
  await (0, import_promises3.pipeline)(nodeStream, out);
40922
40353
  }
40923
40354
  async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
40924
- const work = import_node_path23.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
40925
- import_node_fs23.default.mkdirSync(work, { recursive: true });
40355
+ const work = import_node_path22.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
40356
+ import_node_fs22.default.mkdirSync(work, { recursive: true });
40926
40357
  try {
40927
40358
  await new Promise((resolve6, reject) => {
40928
40359
  const proc = (0, import_node_child_process7.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
@@ -40930,32 +40361,32 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
40930
40361
  proc.on("exit", (code) => code === 0 ? resolve6() : reject(new Error(`tar exited ${code}`)));
40931
40362
  });
40932
40363
  const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
40933
- const src = import_node_path23.default.join(work, dirName, "frpc");
40934
- if (!import_node_fs23.default.existsSync(src)) {
40364
+ const src = import_node_path22.default.join(work, dirName, "frpc");
40365
+ if (!import_node_fs22.default.existsSync(src)) {
40935
40366
  throw new Error(`frpc not found inside tarball at ${src}`);
40936
40367
  }
40937
- import_node_fs23.default.copyFileSync(src, destBin);
40368
+ import_node_fs22.default.copyFileSync(src, destBin);
40938
40369
  } finally {
40939
- import_node_fs23.default.rmSync(work, { recursive: true, force: true });
40370
+ import_node_fs22.default.rmSync(work, { recursive: true, force: true });
40940
40371
  }
40941
40372
  }
40942
40373
 
40943
40374
  // src/tunnel/frpc-process.ts
40944
- var import_node_fs24 = __toESM(require("fs"), 1);
40945
- var import_node_path24 = __toESM(require("path"), 1);
40375
+ var import_node_fs23 = __toESM(require("fs"), 1);
40376
+ var import_node_path23 = __toESM(require("path"), 1);
40946
40377
  var import_node_child_process8 = require("child_process");
40947
40378
  function frpcPidFilePath(dataDir) {
40948
- return import_node_path24.default.join(dataDir, "frpc.pid");
40379
+ return import_node_path23.default.join(dataDir, "frpc.pid");
40949
40380
  }
40950
40381
  function writeFrpcPid(dataDir, pid) {
40951
40382
  try {
40952
- import_node_fs24.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
40383
+ import_node_fs23.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
40953
40384
  } catch {
40954
40385
  }
40955
40386
  }
40956
40387
  function clearFrpcPid(dataDir) {
40957
40388
  try {
40958
- import_node_fs24.default.unlinkSync(frpcPidFilePath(dataDir));
40389
+ import_node_fs23.default.unlinkSync(frpcPidFilePath(dataDir));
40959
40390
  } catch {
40960
40391
  }
40961
40392
  }
@@ -40971,7 +40402,7 @@ function defaultIsPidAlive(pid) {
40971
40402
  }
40972
40403
  function defaultReadPidFile(file) {
40973
40404
  try {
40974
- return import_node_fs24.default.readFileSync(file, "utf8");
40405
+ return import_node_fs23.default.readFileSync(file, "utf8");
40975
40406
  } catch {
40976
40407
  return null;
40977
40408
  }
@@ -40987,12 +40418,12 @@ function defaultSleep(ms) {
40987
40418
  }
40988
40419
  async function killStaleFrpc(deps) {
40989
40420
  const pidFile = frpcPidFilePath(deps.dataDir);
40990
- const tomlPath = import_node_path24.default.join(deps.dataDir, "frpc.toml");
40421
+ const tomlPath = import_node_path23.default.join(deps.dataDir, "frpc.toml");
40991
40422
  const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
40992
40423
  const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
40993
40424
  const killPid = deps.killPidImpl ?? defaultKillPid;
40994
40425
  const scanPids = deps.scanFrpcPidsImpl ?? ((tp) => defaultScanFrpcPidsByCmdline(tp, deps.logger));
40995
- const sleep2 = deps.sleepImpl ?? defaultSleep;
40426
+ const sleep = deps.sleepImpl ?? defaultSleep;
40996
40427
  const victims = /* @__PURE__ */ new Set();
40997
40428
  const raw = readPidFile(pidFile);
40998
40429
  if (raw) {
@@ -41011,7 +40442,7 @@ async function killStaleFrpc(deps) {
41011
40442
  }
41012
40443
  if (victims.size === 0) {
41013
40444
  try {
41014
- import_node_fs24.default.unlinkSync(pidFile);
40445
+ import_node_fs23.default.unlinkSync(pidFile);
41015
40446
  } catch {
41016
40447
  }
41017
40448
  return;
@@ -41020,9 +40451,9 @@ async function killStaleFrpc(deps) {
41020
40451
  deps.logger?.warn("tunnel: killing stale frpc before respawn", { pid });
41021
40452
  killPid(pid, "SIGKILL");
41022
40453
  }
41023
- await sleep2(deps.reapWaitMs ?? 300);
40454
+ await sleep(deps.reapWaitMs ?? 300);
41024
40455
  try {
41025
- import_node_fs24.default.unlinkSync(pidFile);
40456
+ import_node_fs23.default.unlinkSync(pidFile);
41026
40457
  } catch {
41027
40458
  }
41028
40459
  }
@@ -41059,7 +40490,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
41059
40490
  var TunnelManager = class {
41060
40491
  constructor(deps) {
41061
40492
  this.deps = deps;
41062
- this.store = deps.store ?? new TunnelStore(import_node_path25.default.join(deps.dataDir, "tunnel.json"));
40493
+ this.store = deps.store ?? new TunnelStore(import_node_path24.default.join(deps.dataDir, "tunnel.json"));
41063
40494
  this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
41064
40495
  this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
41065
40496
  }
@@ -41186,7 +40617,7 @@ var TunnelManager = class {
41186
40617
  dataDir: this.deps.dataDir,
41187
40618
  override: this.deps.frpcBinaryOverride ?? void 0
41188
40619
  });
41189
- const tomlPath = import_node_path25.default.join(this.deps.dataDir, "frpc.toml");
40620
+ const tomlPath = import_node_path24.default.join(this.deps.dataDir, "frpc.toml");
41190
40621
  const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto7.default.randomBytes(3).toString("hex")}`;
41191
40622
  const toml = buildFrpcToml({
41192
40623
  serverAddr: t.frpsHost,
@@ -41197,12 +40628,12 @@ var TunnelManager = class {
41197
40628
  localPort,
41198
40629
  logLevel: "info"
41199
40630
  });
41200
- await import_node_fs25.default.promises.writeFile(tomlPath, toml, { mode: 384 });
40631
+ await import_node_fs24.default.promises.writeFile(tomlPath, toml, { mode: 384 });
41201
40632
  const proc = (this.deps.spawnImpl ?? import_node_child_process9.spawn)(frpcBin, ["-c", tomlPath], {
41202
40633
  stdio: ["ignore", "pipe", "pipe"]
41203
40634
  });
41204
- const logFilePath = import_node_path25.default.join(this.deps.dataDir, "frpc.log");
41205
- const logStream = import_node_fs25.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
40635
+ const logFilePath = import_node_path24.default.join(this.deps.dataDir, "frpc.log");
40636
+ const logStream = import_node_fs24.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
41206
40637
  logStream.on("error", () => {
41207
40638
  });
41208
40639
  const tee = (chunk) => {
@@ -41285,27 +40716,27 @@ async function waitForFrpcReady(proc, timeoutMs) {
41285
40716
 
41286
40717
  // src/tunnel/device-key.ts
41287
40718
  var import_node_os12 = __toESM(require("os"), 1);
41288
- var import_node_path26 = __toESM(require("path"), 1);
40719
+ var import_node_path25 = __toESM(require("path"), 1);
41289
40720
  var import_node_crypto8 = __toESM(require("crypto"), 1);
41290
40721
  var DERIVE_SALT = "clawd-tunnel-device-v1";
41291
40722
  function deriveStableDeviceKey(opts = {}) {
41292
40723
  const hostname = opts.hostname ?? import_node_os12.default.hostname();
41293
40724
  const uid = opts.uid ?? (typeof import_node_os12.default.userInfo === "function" ? import_node_os12.default.userInfo().uid : 0);
41294
40725
  const home = opts.home ?? import_node_os12.default.homedir();
41295
- const defaultDataDir = import_node_path26.default.resolve(import_node_path26.default.join(home, ".clawd"));
41296
- const normalizedDataDir = opts.dataDir ? import_node_path26.default.resolve(opts.dataDir) : null;
40726
+ const defaultDataDir = import_node_path25.default.resolve(import_node_path25.default.join(home, ".clawd"));
40727
+ const normalizedDataDir = opts.dataDir ? import_node_path25.default.resolve(opts.dataDir) : null;
41297
40728
  const isDefaultDir = normalizedDataDir == null || normalizedDataDir === defaultDataDir;
41298
40729
  const input = isDefaultDir ? `${hostname}::${uid}` : `${hostname}::${uid}::${normalizedDataDir}`;
41299
40730
  return import_node_crypto8.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
41300
40731
  }
41301
40732
 
41302
40733
  // src/auth-store.ts
41303
- var import_node_fs26 = __toESM(require("fs"), 1);
41304
- var import_node_path27 = __toESM(require("path"), 1);
40734
+ var import_node_fs25 = __toESM(require("fs"), 1);
40735
+ var import_node_path26 = __toESM(require("path"), 1);
41305
40736
  var import_node_crypto9 = __toESM(require("crypto"), 1);
41306
40737
  var AUTH_FILE_NAME = "auth.json";
41307
40738
  function authFilePath(dataDir) {
41308
- return import_node_path27.default.join(dataDir, AUTH_FILE_NAME);
40739
+ return import_node_path26.default.join(dataDir, AUTH_FILE_NAME);
41309
40740
  }
41310
40741
  function loadOrCreateAuthFile(opts) {
41311
40742
  const file = authFilePath(opts.dataDir);
@@ -41339,7 +40770,7 @@ function defaultGenerateOwnerPrincipalId() {
41339
40770
  }
41340
40771
  function readAuthFile(file) {
41341
40772
  try {
41342
- const raw = import_node_fs26.default.readFileSync(file, "utf8");
40773
+ const raw = import_node_fs25.default.readFileSync(file, "utf8");
41343
40774
  const parsed = JSON.parse(raw);
41344
40775
  if (typeof parsed?.token !== "string" || parsed.token.length === 0) {
41345
40776
  return null;
@@ -41358,25 +40789,25 @@ function readAuthFile(file) {
41358
40789
  }
41359
40790
  }
41360
40791
  function writeAuthFile(file, content) {
41361
- import_node_fs26.default.mkdirSync(import_node_path27.default.dirname(file), { recursive: true });
41362
- import_node_fs26.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
40792
+ import_node_fs25.default.mkdirSync(import_node_path26.default.dirname(file), { recursive: true });
40793
+ import_node_fs25.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
41363
40794
  try {
41364
- import_node_fs26.default.chmodSync(file, 384);
40795
+ import_node_fs25.default.chmodSync(file, 384);
41365
40796
  } catch {
41366
40797
  }
41367
40798
  }
41368
40799
 
41369
40800
  // src/owner-profile.ts
41370
- var import_node_fs27 = __toESM(require("fs"), 1);
40801
+ var import_node_fs26 = __toESM(require("fs"), 1);
41371
40802
  var import_node_os13 = __toESM(require("os"), 1);
41372
- var import_node_path28 = __toESM(require("path"), 1);
40803
+ var import_node_path27 = __toESM(require("path"), 1);
41373
40804
  var PROFILE_FILENAME = "profile.json";
41374
40805
  function loadOwnerDisplayName(dataDir) {
41375
40806
  const fallback = import_node_os13.default.userInfo().username;
41376
- const profilePath = import_node_path28.default.join(dataDir, PROFILE_FILENAME);
40807
+ const profilePath = import_node_path27.default.join(dataDir, PROFILE_FILENAME);
41377
40808
  let raw;
41378
40809
  try {
41379
- raw = import_node_fs27.default.readFileSync(profilePath, "utf8");
40810
+ raw = import_node_fs26.default.readFileSync(profilePath, "utf8");
41380
40811
  } catch {
41381
40812
  return fallback;
41382
40813
  }
@@ -41399,18 +40830,18 @@ function loadOwnerDisplayName(dataDir) {
41399
40830
  }
41400
40831
 
41401
40832
  // src/feishu-auth/owner-identity-store.ts
41402
- var import_node_fs28 = __toESM(require("fs"), 1);
41403
- var import_node_path29 = __toESM(require("path"), 1);
40833
+ var import_node_fs27 = __toESM(require("fs"), 1);
40834
+ var import_node_path28 = __toESM(require("path"), 1);
41404
40835
  var OWNER_IDENTITY_FILE_NAME = "owner-identity.json";
41405
40836
  var OwnerIdentityStore = class {
41406
40837
  file;
41407
40838
  constructor(dataDir) {
41408
- this.file = import_node_path29.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
40839
+ this.file = import_node_path28.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
41409
40840
  }
41410
40841
  read() {
41411
40842
  let raw;
41412
40843
  try {
41413
- raw = import_node_fs28.default.readFileSync(this.file, "utf8");
40844
+ raw = import_node_fs27.default.readFileSync(this.file, "utf8");
41414
40845
  } catch {
41415
40846
  return null;
41416
40847
  }
@@ -41429,7 +40860,8 @@ var OwnerIdentityStore = class {
41429
40860
  ownerId: r.identity.ownerId,
41430
40861
  provider: r.identity.provider,
41431
40862
  displayName: r.identity.displayName,
41432
- ...typeof r.identity.avatarUrl === "string" ? { avatarUrl: r.identity.avatarUrl } : {}
40863
+ ...typeof r.identity.avatarUrl === "string" ? { avatarUrl: r.identity.avatarUrl } : {},
40864
+ ...typeof r.identity.unionId === "string" ? { unionId: r.identity.unionId } : {}
41433
40865
  },
41434
40866
  ttcToken: r.ttcToken,
41435
40867
  ttcTokenExpiresAt: typeof r.ttcTokenExpiresAt === "number" ? r.ttcTokenExpiresAt : null,
@@ -41437,16 +40869,16 @@ var OwnerIdentityStore = class {
41437
40869
  };
41438
40870
  }
41439
40871
  write(record) {
41440
- import_node_fs28.default.mkdirSync(import_node_path29.default.dirname(this.file), { recursive: true });
41441
- import_node_fs28.default.writeFileSync(this.file, JSON.stringify(record, null, 2), { mode: 384 });
40872
+ import_node_fs27.default.mkdirSync(import_node_path28.default.dirname(this.file), { recursive: true });
40873
+ import_node_fs27.default.writeFileSync(this.file, JSON.stringify(record, null, 2), { mode: 384 });
41442
40874
  try {
41443
- import_node_fs28.default.chmodSync(this.file, 384);
40875
+ import_node_fs27.default.chmodSync(this.file, 384);
41444
40876
  } catch {
41445
40877
  }
41446
40878
  }
41447
40879
  clear() {
41448
40880
  try {
41449
- import_node_fs28.default.unlinkSync(this.file);
40881
+ import_node_fs27.default.unlinkSync(this.file);
41450
40882
  } catch (err) {
41451
40883
  const code = err?.code;
41452
40884
  if (code !== "ENOENT") throw err;
@@ -41550,7 +40982,9 @@ async function fetchTtcUserInfo(opts) {
41550
40982
  ownerId: d.unique_id,
41551
40983
  provider: "ttc",
41552
40984
  displayName: d.name,
41553
- ...typeof d.avatar_url === "string" && d.avatar_url.length > 0 ? { avatarUrl: d.avatar_url } : {}
40985
+ ...typeof d.avatar_url === "string" && d.avatar_url.length > 0 ? { avatarUrl: d.avatar_url } : {},
40986
+ // union_id 捕获:dataclaw 可信入口用 X-User-UnionId(ownerId 仍是 unique_id,跨登录方式稳定)
40987
+ ...typeof d.union_id === "string" && d.union_id.length > 0 ? { unionId: d.union_id } : {}
41554
40988
  };
41555
40989
  }
41556
40990
 
@@ -41565,9 +40999,9 @@ var CentralClientError = class extends Error {
41565
40999
  code;
41566
41000
  cause;
41567
41001
  };
41568
- async function centralRequest(opts, path59, init) {
41002
+ async function centralRequest(opts, path58, init) {
41569
41003
  const f = opts.fetchImpl ?? globalThis.fetch;
41570
- const url = `${opts.api.replace(/\/+$/, "")}${path59}`;
41004
+ const url = `${opts.api.replace(/\/+$/, "")}${path58}`;
41571
41005
  const ctrl = new AbortController();
41572
41006
  const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
41573
41007
  let res;
@@ -41709,8 +41143,8 @@ function verifyConnectToken(args) {
41709
41143
  }
41710
41144
 
41711
41145
  // src/feishu-auth/server-key.ts
41712
- var fs37 = __toESM(require("fs"), 1);
41713
- var path38 = __toESM(require("path"), 1);
41146
+ var fs36 = __toESM(require("fs"), 1);
41147
+ var path37 = __toESM(require("path"), 1);
41714
41148
  var FILE_NAME2 = "server-signing-key.json";
41715
41149
  var ServerKeyStore = class {
41716
41150
  constructor(dataDir) {
@@ -41718,12 +41152,12 @@ var ServerKeyStore = class {
41718
41152
  }
41719
41153
  dataDir;
41720
41154
  filePath() {
41721
- return path38.join(this.dataDir, FILE_NAME2);
41155
+ return path37.join(this.dataDir, FILE_NAME2);
41722
41156
  }
41723
41157
  /** 读缓存的公钥;无缓存 / 损坏 → null(调用方决定是否触发拉取) */
41724
41158
  read() {
41725
41159
  try {
41726
- const raw = fs37.readFileSync(this.filePath(), "utf8");
41160
+ const raw = fs36.readFileSync(this.filePath(), "utf8");
41727
41161
  const parsed = JSON.parse(raw);
41728
41162
  if (typeof parsed.publicKeyPem === "string" && parsed.publicKeyPem.includes("PUBLIC KEY")) {
41729
41163
  return parsed.publicKeyPem;
@@ -41738,12 +41172,12 @@ var ServerKeyStore = class {
41738
41172
  publicKeyPem,
41739
41173
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
41740
41174
  };
41741
- fs37.mkdirSync(this.dataDir, { recursive: true });
41742
- fs37.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
41175
+ fs36.mkdirSync(this.dataDir, { recursive: true });
41176
+ fs36.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
41743
41177
  }
41744
41178
  clear() {
41745
41179
  try {
41746
- fs37.unlinkSync(this.filePath());
41180
+ fs36.unlinkSync(this.filePath());
41747
41181
  } catch {
41748
41182
  }
41749
41183
  }
@@ -41756,12 +41190,12 @@ init_protocol();
41756
41190
  init_protocol();
41757
41191
 
41758
41192
  // src/session/fork.ts
41759
- var import_node_fs29 = __toESM(require("fs"), 1);
41193
+ var import_node_fs28 = __toESM(require("fs"), 1);
41760
41194
  var import_node_os14 = __toESM(require("os"), 1);
41761
- var import_node_path30 = __toESM(require("path"), 1);
41195
+ var import_node_path29 = __toESM(require("path"), 1);
41762
41196
  init_claude_history();
41763
41197
  function readJsonlEntries(file) {
41764
- const raw = import_node_fs29.default.readFileSync(file, "utf8");
41198
+ const raw = import_node_fs28.default.readFileSync(file, "utf8");
41765
41199
  const out = [];
41766
41200
  for (const line of raw.split("\n")) {
41767
41201
  const t = line.trim();
@@ -41774,10 +41208,10 @@ function readJsonlEntries(file) {
41774
41208
  return out;
41775
41209
  }
41776
41210
  function forkSession(input) {
41777
- const baseDir = input.baseDir ?? import_node_path30.default.join(import_node_os14.default.homedir(), ".claude");
41778
- const projectDir = import_node_path30.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
41779
- const sourceFile = import_node_path30.default.join(projectDir, `${input.toolSessionId}.jsonl`);
41780
- if (!import_node_fs29.default.existsSync(sourceFile)) {
41211
+ const baseDir = input.baseDir ?? import_node_path29.default.join(import_node_os14.default.homedir(), ".claude");
41212
+ const projectDir = import_node_path29.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
41213
+ const sourceFile = import_node_path29.default.join(projectDir, `${input.toolSessionId}.jsonl`);
41214
+ if (!import_node_fs28.default.existsSync(sourceFile)) {
41781
41215
  throw new Error(`fork: source transcript not found: ${sourceFile}`);
41782
41216
  }
41783
41217
  const entries = readJsonlEntries(sourceFile);
@@ -41807,9 +41241,9 @@ function forkSession(input) {
41807
41241
  }
41808
41242
  forkedLines.push(JSON.stringify(forked));
41809
41243
  }
41810
- const forkedFilePath = import_node_path30.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
41811
- import_node_fs29.default.mkdirSync(projectDir, { recursive: true });
41812
- import_node_fs29.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
41244
+ const forkedFilePath = import_node_path29.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
41245
+ import_node_fs28.default.mkdirSync(projectDir, { recursive: true });
41246
+ import_node_fs28.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
41813
41247
  return { forkedToolSessionId, forkedFilePath };
41814
41248
  }
41815
41249
 
@@ -42185,7 +41619,7 @@ function buildPermissionHandlers(deps) {
42185
41619
  }
42186
41620
 
42187
41621
  // src/handlers/history.ts
42188
- var path41 = __toESM(require("path"), 1);
41622
+ var path40 = __toESM(require("path"), 1);
42189
41623
  init_protocol();
42190
41624
 
42191
41625
  // src/session/recent-dirs.ts
@@ -42203,7 +41637,7 @@ function listRecentDirs(store, limit = 50) {
42203
41637
  }
42204
41638
 
42205
41639
  // src/permission/persona-paths.ts
42206
- var path40 = __toESM(require("path"), 1);
41640
+ var path39 = __toESM(require("path"), 1);
42207
41641
  function getAllowedPersonaIds(grants, action) {
42208
41642
  const ids = /* @__PURE__ */ new Set();
42209
41643
  for (const g2 of grants) {
@@ -42216,31 +41650,31 @@ function getAllowedPersonaIds(grants, action) {
42216
41650
  return ids;
42217
41651
  }
42218
41652
  function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
42219
- const target = path40.resolve(absPath);
41653
+ const target = path39.resolve(absPath);
42220
41654
  if (userWorkDir) {
42221
- const u = path40.resolve(userWorkDir);
42222
- const usep = u.endsWith(path40.sep) ? "" : path40.sep;
41655
+ const u = path39.resolve(userWorkDir);
41656
+ const usep = u.endsWith(path39.sep) ? "" : path39.sep;
42223
41657
  if (target === u || target.startsWith(u + usep)) return true;
42224
41658
  }
42225
- const root = path40.resolve(personaRoot);
42226
- const sep2 = root.endsWith(path40.sep) ? "" : path40.sep;
41659
+ const root = path39.resolve(personaRoot);
41660
+ const sep2 = root.endsWith(path39.sep) ? "" : path39.sep;
42227
41661
  if (!target.startsWith(root + sep2)) return false;
42228
- const rel = path40.relative(root, target);
41662
+ const rel = path39.relative(root, target);
42229
41663
  if (!rel || rel.startsWith("..")) return false;
42230
- const personaId = rel.split(path40.sep)[0];
41664
+ const personaId = rel.split(path39.sep)[0];
42231
41665
  if (!personaId) return false;
42232
41666
  const allowed = getAllowedPersonaIds(grants, action);
42233
41667
  if (allowed === "*") return true;
42234
41668
  return allowed.has(personaId);
42235
41669
  }
42236
41670
  function personaIdFromPath(absPath, personaRoot) {
42237
- const root = path40.resolve(personaRoot);
42238
- const target = path40.resolve(absPath);
42239
- const sep2 = root.endsWith(path40.sep) ? "" : path40.sep;
41671
+ const root = path39.resolve(personaRoot);
41672
+ const target = path39.resolve(absPath);
41673
+ const sep2 = root.endsWith(path39.sep) ? "" : path39.sep;
42240
41674
  if (!target.startsWith(root + sep2)) return null;
42241
- const rel = path40.relative(root, target);
41675
+ const rel = path39.relative(root, target);
42242
41676
  if (!rel || rel.startsWith("..")) return null;
42243
- const id = rel.split(path40.sep)[0];
41677
+ const id = rel.split(path39.sep)[0];
42244
41678
  return id || null;
42245
41679
  }
42246
41680
 
@@ -42267,7 +41701,7 @@ function buildHistoryHandlers(deps) {
42267
41701
  if (!pid) return false;
42268
41702
  return isGuestPathAllowed(
42269
41703
  ctx.grants,
42270
- path41.join(personaRoot, pid),
41704
+ path40.join(personaRoot, pid),
42271
41705
  personaRoot,
42272
41706
  "read",
42273
41707
  userWorkDir
@@ -42279,7 +41713,7 @@ function buildHistoryHandlers(deps) {
42279
41713
  };
42280
41714
  const list = async (frame, _client, ctx) => {
42281
41715
  const args = HistoryListArgs.parse(frame);
42282
- assertGuestPath(ctx, path41.resolve(args.projectPath), personaRoot, "history:list");
41716
+ assertGuestPath(ctx, path40.resolve(args.projectPath), personaRoot, "history:list");
42283
41717
  const sessions = await history.listSessions(args);
42284
41718
  return { response: { type: "history:list", sessions } };
42285
41719
  };
@@ -42311,13 +41745,13 @@ function buildHistoryHandlers(deps) {
42311
41745
  };
42312
41746
  const subagents = async (frame, _client, ctx) => {
42313
41747
  const args = HistorySubagentsArgs.parse(frame);
42314
- assertGuestPath(ctx, path41.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
41748
+ assertGuestPath(ctx, path40.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
42315
41749
  const subs = await history.listSubagents(args);
42316
41750
  return { response: { type: "history:subagents", subagents: subs } };
42317
41751
  };
42318
41752
  const subagentRead = async (frame, _client, ctx) => {
42319
41753
  const args = HistorySubagentReadArgs.parse(frame);
42320
- assertGuestPath(ctx, path41.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
41754
+ assertGuestPath(ctx, path40.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
42321
41755
  const res = await history.readSubagent(args);
42322
41756
  return { response: { type: "history:subagent-read", ...res } };
42323
41757
  };
@@ -42326,7 +41760,7 @@ function buildHistoryHandlers(deps) {
42326
41760
  if (ctx?.principal.kind === "guest" && personaRoot) {
42327
41761
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
42328
41762
  const filtered = dirs.filter(
42329
- (d) => isGuestPathAllowed(ctx.grants, path41.resolve(d.cwd), personaRoot, "read", userWorkDir)
41763
+ (d) => isGuestPathAllowed(ctx.grants, path40.resolve(d.cwd), personaRoot, "read", userWorkDir)
42330
41764
  );
42331
41765
  return { response: { type: "history:recentDirs", dirs: filtered } };
42332
41766
  }
@@ -42343,7 +41777,7 @@ function buildHistoryHandlers(deps) {
42343
41777
  }
42344
41778
 
42345
41779
  // src/handlers/workspace.ts
42346
- var path42 = __toESM(require("path"), 1);
41780
+ var path41 = __toESM(require("path"), 1);
42347
41781
  var os15 = __toESM(require("os"), 1);
42348
41782
  init_protocol();
42349
41783
  init_protocol();
@@ -42385,22 +41819,22 @@ function buildWorkspaceHandlers(deps) {
42385
41819
  const args = WorkspaceListArgs.parse(frame);
42386
41820
  const isGuest = ctx?.principal.kind === "guest";
42387
41821
  const fallbackCwd = isGuest && personaRoot ? personaRoot : os15.homedir();
42388
- const resolvedCwd = path42.resolve(args.cwd ?? fallbackCwd);
42389
- const target = args.path ? path42.resolve(resolvedCwd, args.path) : resolvedCwd;
41822
+ const resolvedCwd = path41.resolve(args.cwd ?? fallbackCwd);
41823
+ const target = args.path ? path41.resolve(resolvedCwd, args.path) : resolvedCwd;
42390
41824
  assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
42391
41825
  const res = workspace.list({ ...args, cwd: resolvedCwd });
42392
41826
  return { response: { type: "workspace:list", ...res } };
42393
41827
  };
42394
41828
  const read = async (frame, _client, ctx) => {
42395
41829
  const args = WorkspaceReadArgs.parse(frame);
42396
- const target = path42.isAbsolute(args.path) ? path42.resolve(args.path) : path42.resolve(args.cwd, args.path);
41830
+ const target = path41.isAbsolute(args.path) ? path41.resolve(args.path) : path41.resolve(args.cwd, args.path);
42397
41831
  assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
42398
41832
  const res = workspace.read(args);
42399
41833
  return { response: { type: "workspace:read", ...res } };
42400
41834
  };
42401
41835
  const skillsList = async (frame, _client, ctx) => {
42402
41836
  const args = SkillsListArgs.parse(frame);
42403
- const cwdAbs = path42.resolve(args.cwd);
41837
+ const cwdAbs = path41.resolve(args.cwd);
42404
41838
  assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
42405
41839
  const list2 = await getSkillsForTool(args.tool ?? "claude", cwdAbs);
42406
41840
  if (ctx?.principal.kind === "guest" && personaRoot) {
@@ -42412,7 +41846,7 @@ function buildWorkspaceHandlers(deps) {
42412
41846
  };
42413
41847
  const agentsList = async (frame, _client, ctx) => {
42414
41848
  const args = AgentsListArgs.parse(frame);
42415
- const cwdAbs = path42.resolve(args.cwd);
41849
+ const cwdAbs = path41.resolve(args.cwd);
42416
41850
  assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
42417
41851
  if (args.tool === "codex") {
42418
41852
  return { response: { type: "agents:list", agents: [] } };
@@ -42434,20 +41868,20 @@ function buildWorkspaceHandlers(deps) {
42434
41868
  }
42435
41869
 
42436
41870
  // src/handlers/git.ts
42437
- var path44 = __toESM(require("path"), 1);
41871
+ var path43 = __toESM(require("path"), 1);
42438
41872
  init_protocol();
42439
41873
  init_protocol();
42440
41874
 
42441
41875
  // src/workspace/git.ts
42442
41876
  var import_node_child_process10 = require("child_process");
42443
- var import_node_fs30 = __toESM(require("fs"), 1);
42444
- var import_node_path31 = __toESM(require("path"), 1);
41877
+ var import_node_fs29 = __toESM(require("fs"), 1);
41878
+ var import_node_path30 = __toESM(require("path"), 1);
42445
41879
  var import_node_util = require("util");
42446
41880
  var pexec = (0, import_node_util.promisify)(import_node_child_process10.execFile);
42447
41881
  function normalizePath(p2) {
42448
- const resolved = import_node_path31.default.resolve(p2);
41882
+ const resolved = import_node_path30.default.resolve(p2);
42449
41883
  try {
42450
- return import_node_fs30.default.realpathSync(resolved);
41884
+ return import_node_fs29.default.realpathSync(resolved);
42451
41885
  } catch {
42452
41886
  return resolved;
42453
41887
  }
@@ -42521,7 +41955,7 @@ async function listGitBranches(cwd) {
42521
41955
  function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
42522
41956
  if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
42523
41957
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
42524
- if (!isGuestPathAllowed(ctx.grants, path44.resolve(cwd), personaRoot, "read", userWorkDir)) {
41958
+ if (!isGuestPathAllowed(ctx.grants, path43.resolve(cwd), personaRoot, "read", userWorkDir)) {
42525
41959
  throw new ClawdError(
42526
41960
  ERROR_CODES.UNAUTHORIZED,
42527
41961
  `guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
@@ -42937,7 +42371,6 @@ function buildReadyFrame(deps, client) {
42937
42371
  if (deps.httpToken) fileSharing.httpToken = deps.httpToken;
42938
42372
  }
42939
42373
  const daemonSource = process.env.CLAWD_DAEMON_SOURCE === "ota" ? "ota" : "packaged";
42940
- const logShipping = deps.getLogShipping ? deps.getLogShipping() : null;
42941
42374
  return {
42942
42375
  version,
42943
42376
  protocolVersion: PROTOCOL_VERSION,
@@ -42948,8 +42381,7 @@ function buildReadyFrame(deps, client) {
42948
42381
  tunnelUrl,
42949
42382
  mode: deps.mode,
42950
42383
  daemonSource,
42951
- ...fileSharing,
42952
- ...logShipping ? { logShipping } : {}
42384
+ ...fileSharing
42953
42385
  };
42954
42386
  }
42955
42387
  function buildMetaHandlers(deps) {
@@ -43037,7 +42469,7 @@ function buildPersonaHandlers(deps) {
43037
42469
  }
43038
42470
 
43039
42471
  // src/handlers/attachment.ts
43040
- var import_node_path32 = __toESM(require("path"), 1);
42472
+ var import_node_path31 = __toESM(require("path"), 1);
43041
42473
  init_protocol();
43042
42474
  init_protocol();
43043
42475
  var DEFAULT_TTL_SECONDS = 24 * 3600;
@@ -43092,12 +42524,12 @@ function buildAttachmentHandlers(deps) {
43092
42524
  `session ${args.sessionId} scope unresolved`
43093
42525
  );
43094
42526
  }
43095
- const cwdAbs = import_node_path32.default.resolve(sessionFile.cwd);
43096
- const candidateAbs = import_node_path32.default.isAbsolute(args.relPath) ? import_node_path32.default.resolve(args.relPath) : import_node_path32.default.resolve(cwdAbs, args.relPath);
42527
+ const cwdAbs = import_node_path31.default.resolve(sessionFile.cwd);
42528
+ const candidateAbs = import_node_path31.default.isAbsolute(args.relPath) ? import_node_path31.default.resolve(args.relPath) : import_node_path31.default.resolve(cwdAbs, args.relPath);
43097
42529
  assertGuestAttachmentPath(ctx, candidateAbs, deps.personaRoot, "attachment.signUrl", deps.usersRoot);
43098
42530
  const entries = deps.groupFileStore.list(scope, args.sessionId);
43099
42531
  const entry = entries.find((e) => {
43100
- const storedAbs = import_node_path32.default.isAbsolute(e.relPath) ? import_node_path32.default.resolve(e.relPath) : import_node_path32.default.resolve(cwdAbs, e.relPath);
42532
+ const storedAbs = import_node_path31.default.isAbsolute(e.relPath) ? import_node_path31.default.resolve(e.relPath) : import_node_path31.default.resolve(cwdAbs, e.relPath);
43101
42533
  return storedAbs === candidateAbs && !e.stale;
43102
42534
  });
43103
42535
  if (!entry) {
@@ -43121,7 +42553,7 @@ function buildAttachmentHandlers(deps) {
43121
42553
  if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
43122
42554
  const f = deps.sessionStore.read(sessionId);
43123
42555
  if (!f) return;
43124
- assertGuestAttachmentPath(ctx, import_node_path32.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
42556
+ assertGuestAttachmentPath(ctx, import_node_path31.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
43125
42557
  }
43126
42558
  const groupAdd = async (frame, _client, ctx) => {
43127
42559
  if (!deps.groupFileStore || !deps.getSessionScope) {
@@ -43193,19 +42625,19 @@ function buildAttachmentHandlers(deps) {
43193
42625
 
43194
42626
  // src/handlers/extension.ts
43195
42627
  var import_promises7 = __toESM(require("fs/promises"), 1);
43196
- var import_node_path37 = __toESM(require("path"), 1);
42628
+ var import_node_path36 = __toESM(require("path"), 1);
43197
42629
  init_protocol();
43198
42630
 
43199
42631
  // src/extension/bundle-zip.ts
43200
42632
  var import_promises4 = __toESM(require("fs/promises"), 1);
43201
- var import_node_path33 = __toESM(require("path"), 1);
42633
+ var import_node_path32 = __toESM(require("path"), 1);
43202
42634
  var import_node_crypto11 = __toESM(require("crypto"), 1);
43203
42635
  var import_jszip2 = __toESM(require_lib3(), 1);
43204
42636
  async function bundleExtensionDir(dir) {
43205
42637
  const entries = await listFilesSorted(dir);
43206
42638
  const zip = new import_jszip2.default();
43207
42639
  for (const rel of entries) {
43208
- const abs = import_node_path33.default.join(dir, rel);
42640
+ const abs = import_node_path32.default.join(dir, rel);
43209
42641
  const content = await import_promises4.default.readFile(abs);
43210
42642
  zip.file(rel, content, { date: FIXED_DATE });
43211
42643
  }
@@ -43226,7 +42658,7 @@ async function listFilesSorted(rootDir) {
43226
42658
  return out;
43227
42659
  }
43228
42660
  async function walk(absRoot, relPrefix, out) {
43229
- const dirAbs = import_node_path33.default.join(absRoot, relPrefix);
42661
+ const dirAbs = import_node_path32.default.join(absRoot, relPrefix);
43230
42662
  const entries = await import_promises4.default.readdir(dirAbs, { withFileTypes: true });
43231
42663
  for (const e of entries) {
43232
42664
  if (IGNORE_BASENAMES.has(e.name)) continue;
@@ -43280,25 +42712,25 @@ function computePublishCheck(args) {
43280
42712
 
43281
42713
  // src/extension/install-flow.ts
43282
42714
  var import_promises5 = __toESM(require("fs/promises"), 1);
43283
- var import_node_path35 = __toESM(require("path"), 1);
42715
+ var import_node_path34 = __toESM(require("path"), 1);
43284
42716
  var import_node_os17 = __toESM(require("os"), 1);
43285
42717
  var import_node_crypto12 = __toESM(require("crypto"), 1);
43286
42718
  var import_jszip3 = __toESM(require_lib3(), 1);
43287
42719
 
43288
42720
  // src/extension/paths.ts
43289
42721
  var import_node_os16 = __toESM(require("os"), 1);
43290
- var import_node_path34 = __toESM(require("path"), 1);
42722
+ var import_node_path33 = __toESM(require("path"), 1);
43291
42723
  function clawdHomeRoot(override) {
43292
- return override ?? process.env.CLAWD_HOME ?? import_node_path34.default.join(import_node_os16.default.homedir(), ".clawd");
42724
+ return override ?? process.env.CLAWD_HOME ?? import_node_path33.default.join(import_node_os16.default.homedir(), ".clawd");
43293
42725
  }
43294
42726
  function extensionsRoot(override) {
43295
- return import_node_path34.default.join(clawdHomeRoot(override), "extensions");
42727
+ return import_node_path33.default.join(clawdHomeRoot(override), "extensions");
43296
42728
  }
43297
42729
  function publishedChannelsFile(override) {
43298
- return import_node_path34.default.join(clawdHomeRoot(override), "extensions-published.json");
42730
+ return import_node_path33.default.join(clawdHomeRoot(override), "extensions-published.json");
43299
42731
  }
43300
42732
  function bundleCacheRoot(override) {
43301
- return import_node_path34.default.join(clawdHomeRoot(override), "extension-bundles");
42733
+ return import_node_path33.default.join(clawdHomeRoot(override), "extension-bundles");
43302
42734
  }
43303
42735
 
43304
42736
  // src/extension/install-flow.ts
@@ -43325,7 +42757,7 @@ async function installFromChannel(args, deps) {
43325
42757
  throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
43326
42758
  }
43327
42759
  for (const name of Object.keys(zip.files)) {
43328
- if (name.includes("..") || name.startsWith("/") || import_node_path35.default.isAbsolute(name)) {
42760
+ if (name.includes("..") || name.startsWith("/") || import_node_path34.default.isAbsolute(name)) {
43329
42761
  throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
43330
42762
  }
43331
42763
  }
@@ -43357,7 +42789,7 @@ async function installFromChannel(args, deps) {
43357
42789
  );
43358
42790
  }
43359
42791
  const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
43360
- const destDir = import_node_path35.default.join(deps.extensionsRoot, localExtId);
42792
+ const destDir = import_node_path34.default.join(deps.extensionsRoot, localExtId);
43361
42793
  let destExists = false;
43362
42794
  try {
43363
42795
  await import_promises5.default.access(destDir);
@@ -43371,16 +42803,16 @@ async function installFromChannel(args, deps) {
43371
42803
  );
43372
42804
  }
43373
42805
  const stage = await import_promises5.default.mkdtemp(
43374
- import_node_path35.default.join(import_node_os17.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
42806
+ import_node_path34.default.join(import_node_os17.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
43375
42807
  );
43376
42808
  try {
43377
42809
  for (const [name, entry] of Object.entries(zip.files)) {
43378
- const dest = import_node_path35.default.join(stage, name);
42810
+ const dest = import_node_path34.default.join(stage, name);
43379
42811
  if (entry.dir) {
43380
42812
  await import_promises5.default.mkdir(dest, { recursive: true });
43381
42813
  continue;
43382
42814
  }
43383
- await import_promises5.default.mkdir(import_node_path35.default.dirname(dest), { recursive: true });
42815
+ await import_promises5.default.mkdir(import_node_path34.default.dirname(dest), { recursive: true });
43384
42816
  if (name === "manifest.json") {
43385
42817
  const rewritten = { ...parsed.data, id: localExtId };
43386
42818
  await import_promises5.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
@@ -43401,7 +42833,7 @@ async function installFromChannel(args, deps) {
43401
42833
 
43402
42834
  // src/extension/update-flow.ts
43403
42835
  var import_promises6 = __toESM(require("fs/promises"), 1);
43404
- var import_node_path36 = __toESM(require("path"), 1);
42836
+ var import_node_path35 = __toESM(require("path"), 1);
43405
42837
  var import_node_os18 = __toESM(require("os"), 1);
43406
42838
  var import_node_crypto13 = __toESM(require("crypto"), 1);
43407
42839
  var import_jszip4 = __toESM(require_lib3(), 1);
@@ -43418,11 +42850,11 @@ async function updateFromChannel(args, deps) {
43418
42850
  channelRef.extId,
43419
42851
  channelRef.ownerPrincipalId
43420
42852
  );
43421
- const liveDir = import_node_path36.default.join(deps.extensionsRoot, localExtId);
42853
+ const liveDir = import_node_path35.default.join(deps.extensionsRoot, localExtId);
43422
42854
  const prevDir = `${liveDir}.prev`;
43423
42855
  let existingVersion;
43424
42856
  try {
43425
- const raw = await import_promises6.default.readFile(import_node_path36.default.join(liveDir, "manifest.json"), "utf8");
42857
+ const raw = await import_promises6.default.readFile(import_node_path35.default.join(liveDir, "manifest.json"), "utf8");
43426
42858
  const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
43427
42859
  if (!parsed2.success) {
43428
42860
  throw new UpdateError(
@@ -43455,7 +42887,7 @@ async function updateFromChannel(args, deps) {
43455
42887
  throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
43456
42888
  }
43457
42889
  for (const name of Object.keys(zip.files)) {
43458
- if (name.includes("..") || name.startsWith("/") || import_node_path36.default.isAbsolute(name)) {
42890
+ if (name.includes("..") || name.startsWith("/") || import_node_path35.default.isAbsolute(name)) {
43459
42891
  throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
43460
42892
  }
43461
42893
  }
@@ -43490,16 +42922,16 @@ async function updateFromChannel(args, deps) {
43490
42922
  await import_promises6.default.rm(prevDir, { recursive: true, force: true });
43491
42923
  await import_promises6.default.rename(liveDir, prevDir);
43492
42924
  const stage = await import_promises6.default.mkdtemp(
43493
- import_node_path36.default.join(import_node_os18.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
42925
+ import_node_path35.default.join(import_node_os18.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
43494
42926
  );
43495
42927
  try {
43496
42928
  for (const [name, entry] of Object.entries(zip.files)) {
43497
- const dest = import_node_path36.default.join(stage, name);
42929
+ const dest = import_node_path35.default.join(stage, name);
43498
42930
  if (entry.dir) {
43499
42931
  await import_promises6.default.mkdir(dest, { recursive: true });
43500
42932
  continue;
43501
42933
  }
43502
- await import_promises6.default.mkdir(import_node_path36.default.dirname(dest), { recursive: true });
42934
+ await import_promises6.default.mkdir(import_node_path35.default.dirname(dest), { recursive: true });
43503
42935
  if (name === "manifest.json") {
43504
42936
  const rewritten = { ...parsed.data, id: localExtId };
43505
42937
  await import_promises6.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
@@ -43592,7 +43024,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
43592
43024
  );
43593
43025
  }
43594
43026
  }
43595
- const manifestPath = import_node_path37.default.join(root, extId, "manifest.json");
43027
+ const manifestPath = import_node_path36.default.join(root, extId, "manifest.json");
43596
43028
  const manifest = await readManifest(root, extId);
43597
43029
  const next = { ...manifest, version: newVersion };
43598
43030
  const tmp = `${manifestPath}.tmp`;
@@ -43600,7 +43032,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
43600
43032
  await import_promises7.default.rename(tmp, manifestPath);
43601
43033
  }
43602
43034
  async function readManifest(root, extId) {
43603
- const file = import_node_path37.default.join(root, extId, "manifest.json");
43035
+ const file = import_node_path36.default.join(root, extId, "manifest.json");
43604
43036
  let raw;
43605
43037
  try {
43606
43038
  raw = await import_promises7.default.readFile(file, "utf8");
@@ -43691,7 +43123,7 @@ function buildExtensionHandlers(deps) {
43691
43123
  };
43692
43124
  async function buildSnapshotMeta(extId) {
43693
43125
  const manifest = await readManifest(deps.root, extId);
43694
- const { sha256, buffer } = await bundleExtensionDir(import_node_path37.default.join(deps.root, extId));
43126
+ const { sha256, buffer } = await bundleExtensionDir(import_node_path36.default.join(deps.root, extId));
43695
43127
  return { manifest, contentHash: sha256, buffer };
43696
43128
  }
43697
43129
  const publish = async (frame, _client, ctx) => {
@@ -43871,8 +43303,218 @@ function buildExtensionHandlers(deps) {
43871
43303
  };
43872
43304
  }
43873
43305
 
43874
- // src/app-builder/kill-port.ts
43306
+ // src/app-builder/project-store.ts
43307
+ var import_node_fs30 = require("fs");
43875
43308
  var import_node_child_process11 = require("child_process");
43309
+ var import_node_path37 = require("path");
43310
+ init_protocol();
43311
+ var PROJECTS_DIR = "projects";
43312
+ var META_FILE = ".clawd-project.json";
43313
+ var DEFAULT_TEMPLATE = "nestjs-react";
43314
+ var SCAFFOLD_TIMEOUT_MS = 3e4;
43315
+ var ProjectStore = class {
43316
+ /** @param root projects 父目录,例如 `~/.clawd/users/<userId>/`(v2 per-user) */
43317
+ constructor(root) {
43318
+ this.root = root;
43319
+ }
43320
+ root;
43321
+ /** projects/<name>/.clawd-project.json 路径 */
43322
+ metaPath(name) {
43323
+ return (0, import_node_path37.join)(this.projectsRoot(), name, META_FILE);
43324
+ }
43325
+ /** projects/<name>/ 目录路径(cwd 用) */
43326
+ projectDir(name) {
43327
+ return (0, import_node_path37.join)(this.projectsRoot(), name);
43328
+ }
43329
+ projectsRoot() {
43330
+ return (0, import_node_path37.join)(this.root, PROJECTS_DIR);
43331
+ }
43332
+ async list() {
43333
+ let entries;
43334
+ try {
43335
+ entries = await import_node_fs30.promises.readdir(this.projectsRoot());
43336
+ } catch (err) {
43337
+ if (err.code === "ENOENT") return [];
43338
+ throw err;
43339
+ }
43340
+ const out = [];
43341
+ for (const name of entries) {
43342
+ try {
43343
+ const raw = await import_node_fs30.promises.readFile(this.metaPath(name), "utf8");
43344
+ const json = JSON.parse(raw);
43345
+ let migrated = false;
43346
+ if (typeof json.devCommand !== "string" || json.devCommand.length === 0) {
43347
+ json.devCommand = DEFAULT_DEV_COMMAND;
43348
+ migrated = true;
43349
+ }
43350
+ const parsed = ProjectMetadataSchema.safeParse(json);
43351
+ if (parsed.success) {
43352
+ out.push(parsed.data);
43353
+ if (migrated) {
43354
+ void import_node_fs30.promises.writeFile(this.metaPath(name), JSON.stringify(parsed.data, null, 2) + "\n", "utf8").catch(() => {
43355
+ });
43356
+ }
43357
+ }
43358
+ } catch {
43359
+ }
43360
+ }
43361
+ return out.sort((a, b2) => a.name.localeCompare(b2.name));
43362
+ }
43363
+ /**
43364
+ * @param reservedPorts 其它 user 已占端口(v2 per-user:端口必须全局唯一,所有 user 的
43365
+ * dev server 同机跑;per-user store 各自只 list 自己,靠 handler 收集全局端口传进来,
43366
+ * 否则不同 user 的首个项目都从 PROJECT_PORT_MIN 起 → 全撞 6173)。
43367
+ */
43368
+ async create(name, reservedPorts) {
43369
+ const existing = await this.list();
43370
+ if (existing.some((p2) => p2.name === name)) {
43371
+ throw new Error(`project "${name}" already exists / \u5DF2\u5B58\u5728`);
43372
+ }
43373
+ const usedPorts = new Set(existing.map((p2) => p2.port));
43374
+ if (reservedPorts) for (const p2 of reservedPorts) usedPorts.add(p2);
43375
+ let port = -1;
43376
+ for (let p2 = PROJECT_PORT_MIN; p2 <= PROJECT_PORT_MAX; p2++) {
43377
+ if (!usedPorts.has(p2)) {
43378
+ port = p2;
43379
+ break;
43380
+ }
43381
+ }
43382
+ if (port < 0) {
43383
+ throw new Error(
43384
+ `port pool exhausted / \u7AEF\u53E3\u6C60\u5DF2\u6EE1\uFF08${PROJECT_PORT_MIN}-${PROJECT_PORT_MAX}\uFF09\uFF0C\u5148\u5220\u4E00\u4E2A project \u91CA\u653E\u7AEF\u53E3`
43385
+ );
43386
+ }
43387
+ const meta = {
43388
+ name,
43389
+ port,
43390
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
43391
+ devCommand: DEFAULT_DEV_COMMAND
43392
+ };
43393
+ const validated = ProjectMetadataSchema.safeParse(meta);
43394
+ if (!validated.success) {
43395
+ throw new Error(`invalid name "${name}": ${validated.error.message}`);
43396
+ }
43397
+ const dir = this.projectDir(name);
43398
+ await import_node_fs30.promises.mkdir(dir, { recursive: true });
43399
+ await import_node_fs30.promises.writeFile(this.metaPath(name), JSON.stringify(meta, null, 2) + "\n", "utf8");
43400
+ return meta;
43401
+ }
43402
+ /**
43403
+ * 同步内联 scaffold:spawn `extension-kit/scripts/new-extension.sh <name>` 等 exit。
43404
+ * 必须在 `create()` 之后调(脚本期望 projects/<name>/.clawd-project.json 已就位 = picker 模式)。
43405
+ * 失败抛错;上层(handler)应当 catch 后回滚(删 dir + 不 mutate session)。
43406
+ *
43407
+ * spec 2026-06-02 §5.6.3:scaffold 对 assistant 不可见,避免 assistant 被诱导去"读 example
43408
+ * 代码再参考"。assistant 进 project 时目录已是完整模板,直接 pnpm install 即可。
43409
+ */
43410
+ async scaffold(name, templateSrcDir, scaffoldScriptPath) {
43411
+ const destDir = this.projectDir(name);
43412
+ return await new Promise((resolve6, reject) => {
43413
+ const child = (0, import_node_child_process11.spawn)("bash", [scaffoldScriptPath, name, templateSrcDir, destDir], {
43414
+ env: { ...process.env, PATH: process.env.PATH ?? "" },
43415
+ stdio: ["ignore", "pipe", "pipe"]
43416
+ });
43417
+ let stdout = "";
43418
+ let stderr = "";
43419
+ child.stdout.on("data", (d) => {
43420
+ stdout += d.toString("utf8");
43421
+ });
43422
+ child.stderr.on("data", (d) => {
43423
+ stderr += d.toString("utf8");
43424
+ });
43425
+ const timer = setTimeout(() => {
43426
+ child.kill("SIGKILL");
43427
+ reject(new Error(`scaffold timeout (>${SCAFFOLD_TIMEOUT_MS}ms): ${scaffoldScriptPath} ${name}`));
43428
+ }, SCAFFOLD_TIMEOUT_MS);
43429
+ child.on("error", (err) => {
43430
+ clearTimeout(timer);
43431
+ reject(new Error(`scaffold spawn failed: ${err.message}`));
43432
+ });
43433
+ child.on("exit", (code, signal) => {
43434
+ clearTimeout(timer);
43435
+ if (code === 0) resolve6({ stdout, stderr });
43436
+ else reject(new Error(`scaffold exit ${code ?? signal}: ${stderr.slice(0, 500)}`));
43437
+ });
43438
+ });
43439
+ }
43440
+ async delete(name) {
43441
+ const dir = this.projectDir(name);
43442
+ await import_node_fs30.promises.rm(dir, { recursive: true, force: true });
43443
+ }
43444
+ async updatePort(name, newPort) {
43445
+ if (newPort < PROJECT_PORT_MIN || newPort > PROJECT_PORT_MAX) {
43446
+ throw new Error(
43447
+ `port range invalid: must be ${PROJECT_PORT_MIN}-${PROJECT_PORT_MAX}, got ${newPort}`
43448
+ );
43449
+ }
43450
+ const list = await this.list();
43451
+ const target = list.find((p2) => p2.name === name);
43452
+ if (!target) throw new Error(`project "${name}" not found / \u4E0D\u5B58\u5728`);
43453
+ const conflict = list.find((p2) => p2.name !== name && p2.port === newPort);
43454
+ if (conflict) {
43455
+ throw new Error(`port ${newPort} already used / \u5DF2\u88AB project "${conflict.name}" \u5360\u7528`);
43456
+ }
43457
+ const updated = { ...target, port: newPort };
43458
+ await import_node_fs30.promises.writeFile(this.metaPath(name), JSON.stringify(updated, null, 2) + "\n", "utf8");
43459
+ return updated;
43460
+ }
43461
+ /**
43462
+ * 单栏 refactor (spec 2026-06-02 §5.6.1):发布上线后写公网 URL 到 .clawd-project.json.prodUrl。
43463
+ * UI 通过 listProjects 读到 prodUrl 后切预览栏到线上 URL,取代旧 prod marker 机制。
43464
+ * 重复调用幂等(覆盖旧 URL)。url 由 ProjectMetadataSchema 校验 url() 格式。
43465
+ */
43466
+ async setProdUrl(name, url) {
43467
+ const list = await this.list();
43468
+ const target = list.find((p2) => p2.name === name);
43469
+ if (!target) throw new Error(`project "${name}" not found / \u4E0D\u5B58\u5728`);
43470
+ const updated = { ...target, prodUrl: url };
43471
+ const validated = ProjectMetadataSchema.safeParse(updated);
43472
+ if (!validated.success) {
43473
+ throw new Error(`invalid prodUrl "${url}": ${validated.error.message}`);
43474
+ }
43475
+ await import_node_fs30.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
43476
+ return validated.data;
43477
+ }
43478
+ /**
43479
+ * 发布上线脚手架化 (spec 2026-06-03-app-builder-publish-scaffold-design §5.1.4):
43480
+ * 写 publishJob 字段到 .clawd-project.json。仅承载 in-flight 状态 ——
43481
+ * - daemon 收到第一个 ::stage::build marker 时写入
43482
+ * - 每次 stage 切换更新 stage 字段(jobId / startedAt 不变)
43483
+ * - 成功 / 失败 / dismiss 时调 clearPublishJob 清掉
43484
+ * - 只有 daemon 崩才会留残骸
43485
+ * 写入时保留所有其他字段(prodUrl 等不受影响)。
43486
+ */
43487
+ async setPublishJob(name, job) {
43488
+ const list = await this.list();
43489
+ const target = list.find((p2) => p2.name === name);
43490
+ if (!target) throw new Error(`project "${name}" not found / \u4E0D\u5B58\u5728`);
43491
+ const updated = { ...target, publishJob: job };
43492
+ const validated = ProjectMetadataSchema.safeParse(updated);
43493
+ if (!validated.success) {
43494
+ throw new Error(`invalid publishJob: ${validated.error.message}`);
43495
+ }
43496
+ await import_node_fs30.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
43497
+ return validated.data;
43498
+ }
43499
+ /** 清掉 .clawd-project.json.publishJob 字段。其他字段保持原样。 */
43500
+ async clearPublishJob(name) {
43501
+ const list = await this.list();
43502
+ const target = list.find((p2) => p2.name === name);
43503
+ if (!target) throw new Error(`project "${name}" not found / \u4E0D\u5B58\u5728`);
43504
+ if (!target.publishJob) return target;
43505
+ const { publishJob: _drop, ...rest } = target;
43506
+ void _drop;
43507
+ const validated = ProjectMetadataSchema.safeParse(rest);
43508
+ if (!validated.success) {
43509
+ throw new Error(`failed to clear publishJob: ${validated.error.message}`);
43510
+ }
43511
+ await import_node_fs30.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
43512
+ return validated.data;
43513
+ }
43514
+ };
43515
+
43516
+ // src/app-builder/kill-port.ts
43517
+ var import_node_child_process12 = require("child_process");
43876
43518
  async function killPortOccupants(port, ownedPids, logger) {
43877
43519
  let pids;
43878
43520
  try {
@@ -43914,7 +43556,7 @@ async function killPortOccupants(port, ownedPids, logger) {
43914
43556
  }
43915
43557
  function listPidsOnPort(port) {
43916
43558
  return new Promise((resolve6, reject) => {
43917
- (0, import_node_child_process11.execFile)(
43559
+ (0, import_node_child_process12.execFile)(
43918
43560
  "lsof",
43919
43561
  ["-ti", `:${port}`],
43920
43562
  { timeout: 3e3 },
@@ -43986,7 +43628,7 @@ var PublishJobRegistry = class {
43986
43628
  };
43987
43629
 
43988
43630
  // src/app-builder/publish-job-runner.ts
43989
- var import_node_child_process12 = require("child_process");
43631
+ var import_node_child_process13 = require("child_process");
43990
43632
  var import_node_fs31 = require("fs");
43991
43633
  var import_node_path38 = require("path");
43992
43634
 
@@ -44015,7 +43657,7 @@ function tailStderrLines(buf, n) {
44015
43657
  // src/app-builder/publish-job-runner.ts
44016
43658
  async function startPublishJob(deps, args) {
44017
43659
  const { registry: registry2, projectDir } = deps;
44018
- const spawn12 = deps.spawnImpl ?? import_node_child_process12.spawn;
43660
+ const spawn12 = deps.spawnImpl ?? import_node_child_process13.spawn;
44019
43661
  if (registry2.has(args.name)) {
44020
43662
  return { jobId: registry2.get(args.name).jobId, status: "already-publishing" };
44021
43663
  }
@@ -44027,7 +43669,7 @@ async function startPublishJob(deps, args) {
44027
43669
  } catch {
44028
43670
  logStream = null;
44029
43671
  }
44030
- const child = spawn12("bash", [args.scriptPath, projDir], {
43672
+ const child = spawn12("bash", [args.scriptPath, projDir, args.personaRoot ?? ""], {
44031
43673
  cwd: projDir,
44032
43674
  env: process.env,
44033
43675
  stdio: ["ignore", "pipe", "pipe"]
@@ -44282,8 +43924,7 @@ async function recoverInterruptedJobs(deps) {
44282
43924
  init_protocol();
44283
43925
  var import_node_path39 = require("path");
44284
43926
  var import_node_fs32 = require("fs");
44285
- var APP_BUILDER_PERSONAS = ["persona-app-builder"];
44286
- var PUBLISH_SCRIPT_REL = "extension-kit/scripts/publish.sh";
43927
+ var APP_BUILDER_PERSONAS = ["persona-app-builder", "persona-dataclaw-builder"];
44287
43928
  var DEV_SERVER_READY_TIMEOUT_MS = 3e4;
44288
43929
  async function recoverInterruptedPublishJobs(store, logger) {
44289
43930
  await recoverInterruptedJobs({
@@ -44438,7 +44079,10 @@ function buildAppBuilderHandlers(deps) {
44438
44079
  const reservedPorts = new Set((await listAllUsersProjects()).map((p2) => p2.port));
44439
44080
  const project = await userStore.create(f.name, reservedPorts);
44440
44081
  try {
44441
- const scaffoldResult = await userStore.scaffold(project.name, void 0, deps.personaRoot);
44082
+ const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(session.ownerPersonaId ?? "") : deps.personaRoot;
44083
+ const templateSrcDir = (0, import_node_path39.join)(personaRoot, "extension-kit", "examples", DEFAULT_TEMPLATE);
44084
+ const scaffoldScript = (0, import_node_path39.join)(deps.deployKitRoot, "scripts", "new-extension.sh");
44085
+ const scaffoldResult = await userStore.scaffold(project.name, templateSrcDir, scaffoldScript);
44442
44086
  deps.logger?.info("app-builder.scaffold.done", {
44443
44087
  name: project.name,
44444
44088
  stdout: scaffoldResult.stdout.slice(0, 200)
@@ -44657,11 +44301,13 @@ function buildAppBuilderHandlers(deps) {
44657
44301
  });
44658
44302
  await userStore.clearPublishJob(args.name);
44659
44303
  }
44660
- const scriptPath = (0, import_node_path39.join)(deps.personaRoot, PUBLISH_SCRIPT_REL);
44304
+ const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(boundSession.ownerPersonaId ?? "") : deps.personaRoot;
44305
+ const scriptPath = (0, import_node_path39.join)(deps.deployKitRoot, "scripts", "publish.sh");
44661
44306
  deps.logger?.info("app-builder.publish.start", {
44662
44307
  name: args.name,
44663
44308
  sessionId: boundSession.sessionId,
44664
- scriptPath
44309
+ scriptPath,
44310
+ personaRoot
44665
44311
  });
44666
44312
  const result = await startPublishJob(
44667
44313
  {
@@ -44696,7 +44342,8 @@ function buildAppBuilderHandlers(deps) {
44696
44342
  {
44697
44343
  name: args.name,
44698
44344
  sessionId: boundSession.sessionId,
44699
- scriptPath
44345
+ scriptPath,
44346
+ personaRoot
44700
44347
  }
44701
44348
  );
44702
44349
  return { response: { ...result } };
@@ -44894,227 +44541,16 @@ function buildMethodHandlers(deps) {
44894
44541
  broadcastProjectUpdated: deps.broadcastProjectUpdated,
44895
44542
  logger: deps.logger,
44896
44543
  // 发布上线脚手架化 (spec 2026-06-03 §5.2):
44897
- // personaRoot 用于拼 publish.sh 绝对路径;broadcastSessionFrame 用于失败回灌路径
44898
- // runner 调 manager.send 后逐帧 dispatch 到 transport)。
44544
+ // personaRoot 仅作 resolvePersonaRoot 未注入时的兜底;deployKitRoot 为共享脚本根。
44545
+ // broadcastSessionFrame 用于失败回灌路径(runner 调 manager.send 后逐帧 dispatch 到 transport)。
44899
44546
  personaRoot: deps.appBuilderPersonaRoot,
44547
+ deployKitRoot: deps.deployKitRoot,
44548
+ resolvePersonaRoot: deps.resolvePersonaRoot,
44900
44549
  broadcastSessionFrame: deps.broadcastSessionFrame
44901
44550
  })
44902
44551
  };
44903
44552
  }
44904
44553
 
44905
- // src/app-builder/project-store.ts
44906
- var import_node_fs33 = require("fs");
44907
- var import_node_child_process13 = require("child_process");
44908
- var import_node_path42 = require("path");
44909
- init_protocol();
44910
- var PROJECTS_DIR = "projects";
44911
- var META_FILE = ".clawd-project.json";
44912
- var SCAFFOLD_SCRIPT_REL = "extension-kit/scripts/new-extension.sh";
44913
- var DEFAULT_TEMPLATE = "nestjs-react";
44914
- var SCAFFOLD_TIMEOUT_MS = 3e4;
44915
- var ProjectStore = class {
44916
- /** @param root projects 父目录,例如 `~/.clawd/users/<userId>/`(v2 per-user) */
44917
- constructor(root) {
44918
- this.root = root;
44919
- }
44920
- root;
44921
- /** projects/<name>/.clawd-project.json 路径 */
44922
- metaPath(name) {
44923
- return (0, import_node_path42.join)(this.projectsRoot(), name, META_FILE);
44924
- }
44925
- /** projects/<name>/ 目录路径(cwd 用) */
44926
- projectDir(name) {
44927
- return (0, import_node_path42.join)(this.projectsRoot(), name);
44928
- }
44929
- projectsRoot() {
44930
- return (0, import_node_path42.join)(this.root, PROJECTS_DIR);
44931
- }
44932
- async list() {
44933
- let entries;
44934
- try {
44935
- entries = await import_node_fs33.promises.readdir(this.projectsRoot());
44936
- } catch (err) {
44937
- if (err.code === "ENOENT") return [];
44938
- throw err;
44939
- }
44940
- const out = [];
44941
- for (const name of entries) {
44942
- try {
44943
- const raw = await import_node_fs33.promises.readFile(this.metaPath(name), "utf8");
44944
- const json = JSON.parse(raw);
44945
- let migrated = false;
44946
- if (typeof json.devCommand !== "string" || json.devCommand.length === 0) {
44947
- json.devCommand = DEFAULT_DEV_COMMAND;
44948
- migrated = true;
44949
- }
44950
- const parsed = ProjectMetadataSchema.safeParse(json);
44951
- if (parsed.success) {
44952
- out.push(parsed.data);
44953
- if (migrated) {
44954
- void import_node_fs33.promises.writeFile(this.metaPath(name), JSON.stringify(parsed.data, null, 2) + "\n", "utf8").catch(() => {
44955
- });
44956
- }
44957
- }
44958
- } catch {
44959
- }
44960
- }
44961
- return out.sort((a, b2) => a.name.localeCompare(b2.name));
44962
- }
44963
- /**
44964
- * @param reservedPorts 其它 user 已占端口(v2 per-user:端口必须全局唯一,所有 user 的
44965
- * dev server 同机跑;per-user store 各自只 list 自己,靠 handler 收集全局端口传进来,
44966
- * 否则不同 user 的首个项目都从 PROJECT_PORT_MIN 起 → 全撞 6173)。
44967
- */
44968
- async create(name, reservedPorts) {
44969
- const existing = await this.list();
44970
- if (existing.some((p2) => p2.name === name)) {
44971
- throw new Error(`project "${name}" already exists / \u5DF2\u5B58\u5728`);
44972
- }
44973
- const usedPorts = new Set(existing.map((p2) => p2.port));
44974
- if (reservedPorts) for (const p2 of reservedPorts) usedPorts.add(p2);
44975
- let port = -1;
44976
- for (let p2 = PROJECT_PORT_MIN; p2 <= PROJECT_PORT_MAX; p2++) {
44977
- if (!usedPorts.has(p2)) {
44978
- port = p2;
44979
- break;
44980
- }
44981
- }
44982
- if (port < 0) {
44983
- throw new Error(
44984
- `port pool exhausted / \u7AEF\u53E3\u6C60\u5DF2\u6EE1\uFF08${PROJECT_PORT_MIN}-${PROJECT_PORT_MAX}\uFF09\uFF0C\u5148\u5220\u4E00\u4E2A project \u91CA\u653E\u7AEF\u53E3`
44985
- );
44986
- }
44987
- const meta = {
44988
- name,
44989
- port,
44990
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
44991
- devCommand: DEFAULT_DEV_COMMAND
44992
- };
44993
- const validated = ProjectMetadataSchema.safeParse(meta);
44994
- if (!validated.success) {
44995
- throw new Error(`invalid name "${name}": ${validated.error.message}`);
44996
- }
44997
- const dir = this.projectDir(name);
44998
- await import_node_fs33.promises.mkdir(dir, { recursive: true });
44999
- await import_node_fs33.promises.writeFile(this.metaPath(name), JSON.stringify(meta, null, 2) + "\n", "utf8");
45000
- return meta;
45001
- }
45002
- /**
45003
- * 同步内联 scaffold:spawn `extension-kit/scripts/new-extension.sh <name>` 等 exit。
45004
- * 必须在 `create()` 之后调(脚本期望 projects/<name>/.clawd-project.json 已就位 = picker 模式)。
45005
- * 失败抛错;上层(handler)应当 catch 后回滚(删 dir + 不 mutate session)。
45006
- *
45007
- * spec 2026-06-02 §5.6.3:scaffold 对 assistant 不可见,避免 assistant 被诱导去"读 example
45008
- * 代码再参考"。assistant 进 project 时目录已是完整模板,直接 pnpm install 即可。
45009
- */
45010
- async scaffold(name, template = DEFAULT_TEMPLATE, personaRoot = this.root) {
45011
- const scriptPath = (0, import_node_path42.join)(personaRoot, SCAFFOLD_SCRIPT_REL);
45012
- const destDir = this.projectDir(name);
45013
- return await new Promise((resolve6, reject) => {
45014
- const child = (0, import_node_child_process13.spawn)("bash", [scriptPath, name, template, destDir], {
45015
- cwd: personaRoot,
45016
- env: { ...process.env, PATH: process.env.PATH ?? "" },
45017
- stdio: ["ignore", "pipe", "pipe"]
45018
- });
45019
- let stdout = "";
45020
- let stderr = "";
45021
- child.stdout.on("data", (d) => {
45022
- stdout += d.toString("utf8");
45023
- });
45024
- child.stderr.on("data", (d) => {
45025
- stderr += d.toString("utf8");
45026
- });
45027
- const timer = setTimeout(() => {
45028
- child.kill("SIGKILL");
45029
- reject(new Error(`scaffold timeout (>${SCAFFOLD_TIMEOUT_MS}ms): ${scriptPath} ${name} ${template}`));
45030
- }, SCAFFOLD_TIMEOUT_MS);
45031
- child.on("error", (err) => {
45032
- clearTimeout(timer);
45033
- reject(new Error(`scaffold spawn failed: ${err.message}`));
45034
- });
45035
- child.on("exit", (code, signal) => {
45036
- clearTimeout(timer);
45037
- if (code === 0) resolve6({ stdout, stderr });
45038
- else reject(new Error(`scaffold exit ${code ?? signal}: ${stderr.slice(0, 500)}`));
45039
- });
45040
- });
45041
- }
45042
- async delete(name) {
45043
- const dir = this.projectDir(name);
45044
- await import_node_fs33.promises.rm(dir, { recursive: true, force: true });
45045
- }
45046
- async updatePort(name, newPort) {
45047
- if (newPort < PROJECT_PORT_MIN || newPort > PROJECT_PORT_MAX) {
45048
- throw new Error(
45049
- `port range invalid: must be ${PROJECT_PORT_MIN}-${PROJECT_PORT_MAX}, got ${newPort}`
45050
- );
45051
- }
45052
- const list = await this.list();
45053
- const target = list.find((p2) => p2.name === name);
45054
- if (!target) throw new Error(`project "${name}" not found / \u4E0D\u5B58\u5728`);
45055
- const conflict = list.find((p2) => p2.name !== name && p2.port === newPort);
45056
- if (conflict) {
45057
- throw new Error(`port ${newPort} already used / \u5DF2\u88AB project "${conflict.name}" \u5360\u7528`);
45058
- }
45059
- const updated = { ...target, port: newPort };
45060
- await import_node_fs33.promises.writeFile(this.metaPath(name), JSON.stringify(updated, null, 2) + "\n", "utf8");
45061
- return updated;
45062
- }
45063
- /**
45064
- * 单栏 refactor (spec 2026-06-02 §5.6.1):发布上线后写公网 URL 到 .clawd-project.json.prodUrl。
45065
- * UI 通过 listProjects 读到 prodUrl 后切预览栏到线上 URL,取代旧 prod marker 机制。
45066
- * 重复调用幂等(覆盖旧 URL)。url 由 ProjectMetadataSchema 校验 url() 格式。
45067
- */
45068
- async setProdUrl(name, url) {
45069
- const list = await this.list();
45070
- const target = list.find((p2) => p2.name === name);
45071
- if (!target) throw new Error(`project "${name}" not found / \u4E0D\u5B58\u5728`);
45072
- const updated = { ...target, prodUrl: url };
45073
- const validated = ProjectMetadataSchema.safeParse(updated);
45074
- if (!validated.success) {
45075
- throw new Error(`invalid prodUrl "${url}": ${validated.error.message}`);
45076
- }
45077
- await import_node_fs33.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
45078
- return validated.data;
45079
- }
45080
- /**
45081
- * 发布上线脚手架化 (spec 2026-06-03-app-builder-publish-scaffold-design §5.1.4):
45082
- * 写 publishJob 字段到 .clawd-project.json。仅承载 in-flight 状态 ——
45083
- * - daemon 收到第一个 ::stage::build marker 时写入
45084
- * - 每次 stage 切换更新 stage 字段(jobId / startedAt 不变)
45085
- * - 成功 / 失败 / dismiss 时调 clearPublishJob 清掉
45086
- * - 只有 daemon 崩才会留残骸
45087
- * 写入时保留所有其他字段(prodUrl 等不受影响)。
45088
- */
45089
- async setPublishJob(name, job) {
45090
- const list = await this.list();
45091
- const target = list.find((p2) => p2.name === name);
45092
- if (!target) throw new Error(`project "${name}" not found / \u4E0D\u5B58\u5728`);
45093
- const updated = { ...target, publishJob: job };
45094
- const validated = ProjectMetadataSchema.safeParse(updated);
45095
- if (!validated.success) {
45096
- throw new Error(`invalid publishJob: ${validated.error.message}`);
45097
- }
45098
- await import_node_fs33.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
45099
- return validated.data;
45100
- }
45101
- /** 清掉 .clawd-project.json.publishJob 字段。其他字段保持原样。 */
45102
- async clearPublishJob(name) {
45103
- const list = await this.list();
45104
- const target = list.find((p2) => p2.name === name);
45105
- if (!target) throw new Error(`project "${name}" not found / \u4E0D\u5B58\u5728`);
45106
- if (!target.publishJob) return target;
45107
- const { publishJob: _drop, ...rest } = target;
45108
- void _drop;
45109
- const validated = ProjectMetadataSchema.safeParse(rest);
45110
- if (!validated.success) {
45111
- throw new Error(`failed to clear publishJob: ${validated.error.message}`);
45112
- }
45113
- await import_node_fs33.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
45114
- return validated.data;
45115
- }
45116
- };
45117
-
45118
44554
  // src/app-builder/dev-server-supervisor.ts
45119
44555
  var import_node_child_process14 = require("child_process");
45120
44556
  var import_node_events2 = require("events");
@@ -45546,7 +44982,7 @@ function computeGrantForFrame(method, frame) {
45546
44982
 
45547
44983
  // src/extension/runtime.ts
45548
44984
  var import_node_child_process15 = require("child_process");
45549
- var import_node_path43 = __toESM(require("path"), 1);
44985
+ var import_node_path42 = __toESM(require("path"), 1);
45550
44986
  var import_promises10 = require("timers/promises");
45551
44987
 
45552
44988
  // src/extension/port-allocator.ts
@@ -45647,7 +45083,7 @@ var Runtime = class {
45647
45083
  /\$CLAWOS_EXT_PORT/g,
45648
45084
  String(port)
45649
45085
  );
45650
- const dir = import_node_path43.default.join(this.root, extId);
45086
+ const dir = import_node_path42.default.join(this.root, extId);
45651
45087
  const env = {
45652
45088
  ...process.env,
45653
45089
  CLAWOS_EXT_PORT: String(port),
@@ -45759,7 +45195,7 @@ ${handle.stderrTail}`
45759
45195
 
45760
45196
  // src/extension/published-channels.ts
45761
45197
  var import_promises11 = __toESM(require("fs/promises"), 1);
45762
- var import_node_path44 = __toESM(require("path"), 1);
45198
+ var import_node_path43 = __toESM(require("path"), 1);
45763
45199
  init_zod();
45764
45200
  var PublishedChannelsError = class extends Error {
45765
45201
  constructor(code, message) {
@@ -45858,7 +45294,7 @@ var PublishedChannelStore = class {
45858
45294
  )
45859
45295
  };
45860
45296
  const tmp = `${this.filePath}.tmp`;
45861
- await import_promises11.default.mkdir(import_node_path44.default.dirname(this.filePath), { recursive: true });
45297
+ await import_promises11.default.mkdir(import_node_path43.default.dirname(this.filePath), { recursive: true });
45862
45298
  await import_promises11.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
45863
45299
  await import_promises11.default.rename(tmp, this.filePath);
45864
45300
  }
@@ -45866,7 +45302,7 @@ var PublishedChannelStore = class {
45866
45302
 
45867
45303
  // src/extension/bundle-cache.ts
45868
45304
  var import_promises12 = __toESM(require("fs/promises"), 1);
45869
- var import_node_path45 = __toESM(require("path"), 1);
45305
+ var import_node_path44 = __toESM(require("path"), 1);
45870
45306
  var BundleCache = class {
45871
45307
  constructor(rootDir) {
45872
45308
  this.rootDir = rootDir;
@@ -45875,14 +45311,14 @@ var BundleCache = class {
45875
45311
  /** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
45876
45312
  async write(snapshotHash, buffer) {
45877
45313
  await import_promises12.default.mkdir(this.rootDir, { recursive: true });
45878
- const file = import_node_path45.default.join(this.rootDir, `${snapshotHash}.zip`);
45314
+ const file = import_node_path44.default.join(this.rootDir, `${snapshotHash}.zip`);
45879
45315
  const tmp = `${file}.tmp`;
45880
45316
  await import_promises12.default.writeFile(tmp, buffer, { mode: 384 });
45881
45317
  await import_promises12.default.rename(tmp, file);
45882
45318
  }
45883
45319
  /** Returns the bundle bytes, or null when the file doesn't exist. */
45884
45320
  async read(snapshotHash) {
45885
- const file = import_node_path45.default.join(this.rootDir, `${snapshotHash}.zip`);
45321
+ const file = import_node_path44.default.join(this.rootDir, `${snapshotHash}.zip`);
45886
45322
  try {
45887
45323
  return await import_promises12.default.readFile(file);
45888
45324
  } catch (e) {
@@ -45892,33 +45328,16 @@ var BundleCache = class {
45892
45328
  }
45893
45329
  /** Idempotent — missing file is not an error. */
45894
45330
  async delete(snapshotHash) {
45895
- const file = import_node_path45.default.join(this.rootDir, `${snapshotHash}.zip`);
45331
+ const file = import_node_path44.default.join(this.rootDir, `${snapshotHash}.zip`);
45896
45332
  await import_promises12.default.rm(file, { force: true });
45897
45333
  }
45898
45334
  };
45899
45335
 
45900
45336
  // src/index.ts
45901
- var import_meta4 = {};
45902
45337
  async function startDaemon(config) {
45903
- const authFile = loadOrCreateAuthFile({ dataDir: config.dataDir });
45904
- const logShippingCfg = config.logShipping ?? { endpoint: null, sampling: {}, mode: "off" };
45905
- const logClient = createLogClient({
45906
- endpoint: logShippingCfg.endpoint,
45907
- identity: {
45908
- ownerPrincipalId: authFile.ownerPrincipalId,
45909
- deviceId: authFile.deviceId,
45910
- appVersion: version,
45911
- daemonVersion: version,
45912
- os: `${process.platform}-${process.arch}`
45913
- },
45914
- source: "daemon",
45915
- sampling: logShippingCfg.sampling,
45916
- homeDir: import_node_os19.default.homedir()
45917
- });
45918
45338
  const logger = createLogger({
45919
45339
  level: config.logLevel,
45920
- file: import_node_path46.default.join(config.dataDir, "clawd.log"),
45921
- logClient
45340
+ file: import_node_path45.default.join(config.dataDir, "clawd.log")
45922
45341
  });
45923
45342
  logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
45924
45343
  const stateMgr = new StateFileManager({ dataDir: config.dataDir });
@@ -45929,6 +45348,7 @@ async function startDaemon(config) {
45929
45348
  if (pre.status === "stale") {
45930
45349
  logger.warn("stale state file detected, overwriting", { pid: pre.existing.pid });
45931
45350
  }
45351
+ const authFile = loadOrCreateAuthFile({ dataDir: config.dataDir });
45932
45352
  let resolvedAuthToken = null;
45933
45353
  if (config.authToken && config.authToken.trim()) {
45934
45354
  resolvedAuthToken = config.authToken.trim();
@@ -46053,8 +45473,8 @@ async function startDaemon(config) {
46053
45473
  const agents = new AgentsScanner();
46054
45474
  const history = new ClaudeHistoryReader();
46055
45475
  let transport = null;
46056
- const personaStore = new PersonaStore(import_node_path46.default.join(config.dataDir, "personas"));
46057
- const usersRoot = import_node_path46.default.join(config.dataDir, "users");
45476
+ const personaStore = new PersonaStore(import_node_path45.default.join(config.dataDir, "personas"));
45477
+ const usersRoot = import_node_path45.default.join(config.dataDir, "users");
46058
45478
  const defaultsRoot = findDefaultsRoot();
46059
45479
  if (defaultsRoot) {
46060
45480
  seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
@@ -46062,36 +45482,16 @@ async function startDaemon(config) {
46062
45482
  } else {
46063
45483
  logger.warn("persona.seed.skip", { reason: "defaults-root-not-found" });
46064
45484
  }
45485
+ const deployKitBundleRoot = findDeployKitRoot();
45486
+ if (deployKitBundleRoot) {
45487
+ seedDeployKit({ deployKitBundleRoot, dataDir: config.dataDir, logger });
45488
+ refreshDeployKit({ deployKitBundleRoot, dataDir: config.dataDir, logger });
45489
+ } else {
45490
+ logger.warn("deploy-kit.bundle-missing", {});
45491
+ }
46065
45492
  migrateAgentsMirror({ store: personaStore, logger });
46066
45493
  migrateCodexSandbox({ store: personaStore, logger });
46067
45494
  const groupFileStore = new GroupFileStore({ dataDir: config.dataDir, logger });
46068
- const personaDispatchManager = new PersonaDispatchManager({ genId: () => v4_default() });
46069
- const here = typeof __dirname === "string" ? __dirname : import_node_path46.default.dirname((0, import_node_url2.fileURLToPath)(import_meta4.url));
46070
- const dispatchServerCandidates = [
46071
- import_node_path46.default.join(here, "dispatch", "mcp-server.cjs"),
46072
- // 生产 dist/index → dist/dispatch/mcp-server.cjs
46073
- import_node_path46.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
46074
- // dev tsx src/index → ../dist/dispatch/mcp-server.cjs
46075
- ];
46076
- const dispatchServerScriptPath = dispatchServerCandidates.find((p2) => import_node_fs34.default.existsSync(p2));
46077
- let dispatchMcpConfigPath2;
46078
- if (dispatchServerScriptPath) {
46079
- const dispatchLogPath = import_node_path46.default.join(config.dataDir, "dispatch-mcp-server.log");
46080
- dispatchMcpConfigPath2 = writeDispatchMcpConfig({
46081
- dataDir: config.dataDir,
46082
- serverScriptPath: dispatchServerScriptPath,
46083
- logPath: dispatchLogPath
46084
- });
46085
- logger.info("dispatch.mcp.json written", {
46086
- path: dispatchMcpConfigPath2,
46087
- server: dispatchServerScriptPath,
46088
- serverLog: dispatchLogPath
46089
- });
46090
- } else {
46091
- logger.warn("dispatch-mcp-server.cjs not found; persona dispatch disabled (dev tsx \u6A21\u5F0F\u4E0B\u9700\u5148\u8DD1\u8FC7 build)", {
46092
- tried: dispatchServerCandidates
46093
- });
46094
- }
46095
45495
  const manager = new SessionManager({
46096
45496
  store,
46097
45497
  // Phase 2 (capability platform plan §1): factory 注入后 manager.storeFor 走
@@ -46101,7 +45501,7 @@ async function startDaemon(config) {
46101
45501
  getAdapter,
46102
45502
  historyReader: history,
46103
45503
  dataDir: config.dataDir,
46104
- personaRoot: import_node_path46.default.join(config.dataDir, "personas"),
45504
+ personaRoot: import_node_path45.default.join(config.dataDir, "personas"),
46105
45505
  usersRoot,
46106
45506
  personaStore,
46107
45507
  ownerDisplayName,
@@ -46112,12 +45512,6 @@ async function startDaemon(config) {
46112
45512
  // 127.0.0.1(不是 config.host)—— cc 跑在本机,loopback 最稳;外部访问限制 + http-router
46113
45513
  // 的 isLoopback 兜底已确保安全。
46114
45514
  getDaemonUrl: () => `http://127.0.0.1:${config.port}`,
46115
- // Persona dispatch (Task 8): manager 通过这两个 deps 跟 PersonaDispatchManager 协作。
46116
- // - personaDispatchManager: manager.createDispatchedSession 用它 registerBSession;
46117
- // reducer 通过闭包反查 dispatchId 注 CLAWD_DISPATCH_ID env。
46118
- // - dispatchMcpConfigPath: reducer 透传到 SpawnContext,cc spawn 加 --mcp-config flag。
46119
- personaDispatchManager,
46120
- dispatchMcpConfigPath: dispatchMcpConfigPath2,
46121
45515
  broadcastFrame: (frame, target) => {
46122
45516
  if (target === "all") {
46123
45517
  transport?.broadcastAll(frame);
@@ -46137,10 +45531,10 @@ async function startDaemon(config) {
46137
45531
  // 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
46138
45532
  attachmentGroup: {
46139
45533
  onFileEdit: (input) => {
46140
- const absPath = import_node_path46.default.isAbsolute(input.relPath) ? input.relPath : import_node_path46.default.join(input.cwd, input.relPath);
45534
+ const absPath = import_node_path45.default.isAbsolute(input.relPath) ? input.relPath : import_node_path45.default.join(input.cwd, input.relPath);
46141
45535
  let size = 0;
46142
45536
  try {
46143
- size = import_node_fs34.default.statSync(absPath).size;
45537
+ size = import_node_fs33.default.statSync(absPath).size;
46144
45538
  } catch (err) {
46145
45539
  logger.warn("attachment.onFileEdit stat failed", {
46146
45540
  sessionId: input.sessionId,
@@ -46326,11 +45720,11 @@ async function startDaemon(config) {
46326
45720
  // 'persona/<pid>/owner',default 走 'default'。
46327
45721
  getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
46328
45722
  // guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
46329
- personaRoot: import_node_path46.default.join(config.dataDir, "personas"),
45723
+ personaRoot: import_node_path45.default.join(config.dataDir, "personas"),
46330
45724
  usersRoot
46331
45725
  },
46332
45726
  // workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
46333
- personaRoot: import_node_path46.default.join(config.dataDir, "personas"),
45727
+ personaRoot: import_node_path45.default.join(config.dataDir, "personas"),
46334
45728
  // v2 多人 persona 隔离:handler 派生 guest user-dir 放行
46335
45729
  usersRoot,
46336
45730
  // capability:list / delete handler 依赖
@@ -46419,7 +45813,11 @@ async function startDaemon(config) {
46419
45813
  // 发布上线脚手架化 (spec 2026-06-03 §5.2):
46420
45814
  // appBuilderPersonaRoot 用于拼 publish.sh 绝对路径(persona-app-builder 安装在
46421
45815
  // dataDir/personas/persona-app-builder 之下,extension-kit/scripts/publish.sh 是相对路径)。
46422
- appBuilderPersonaRoot: import_node_path46.default.join(config.dataDir, "personas", "persona-app-builder"),
45816
+ appBuilderPersonaRoot: import_node_path45.default.join(config.dataDir, "personas", "persona-app-builder"),
45817
+ // 共享 deploy-kit 根:scaffold/publish 脚本骨架 + 阿里云凭证单一真源。
45818
+ deployKitRoot: import_node_path45.default.join(config.dataDir, "deploy-kit"),
45819
+ // scaffold/publish 按当前 session 的 persona 解析其安装根,让每个 persona 用自己的模板/注入配置。
45820
+ resolvePersonaRoot: (personaId) => import_node_path45.default.join(config.dataDir, "personas", personaId),
46423
45821
  // 发布上线脚手架化 (spec 2026-06-03 §5.2.2):
46424
45822
  // 复用 SessionManagerDeps.broadcastFrame 同款 dispatch 逻辑 —— runner 调 manager.send
46425
45823
  // 取回 broadcast 帧后逐帧 push 到 transport,跟 manager 自身的 deps 一致。
@@ -46440,41 +45838,6 @@ async function startDaemon(config) {
46440
45838
  logger
46441
45839
  });
46442
45840
  let handlers = makeHandlers();
46443
- const dispatchHandlers = buildPersonaDispatchHandlers({
46444
- personaDispatchManager,
46445
- logger,
46446
- spawnB: async (args) => {
46447
- logger.info("dispatch.spawnB.start", {
46448
- dispatchId: args.dispatchId,
46449
- targetPersona: args.targetPersona,
46450
- sourceSessionId: args.sourceSessionId
46451
- });
46452
- const sourceFile = manager.findOwnedSession(args.sourceSessionId);
46453
- if (!sourceFile) {
46454
- throw new Error(`personaDispatch:run source session not found: ${args.sourceSessionId}`);
46455
- }
46456
- const sourceJsonlPath = sourceFile.toolSessionId ? import_node_path46.default.join(
46457
- import_node_os19.default.homedir(),
46458
- ".claude",
46459
- "projects",
46460
- cwdToHashDir(sourceFile.cwd),
46461
- `${sourceFile.toolSessionId}.jsonl`
46462
- ) : "(no transcript yet \u2014 operate from the task description alone)";
46463
- logger.info("dispatch.spawnB.source-resolved", {
46464
- dispatchId: args.dispatchId,
46465
- sourceJsonlPath,
46466
- hasToolSessionId: Boolean(sourceFile.toolSessionId)
46467
- });
46468
- manager.createDispatchedSession({
46469
- dispatchId: args.dispatchId,
46470
- sourceSessionId: args.sourceSessionId,
46471
- targetPersona: args.targetPersona,
46472
- prompt: args.prompt,
46473
- sourceJsonlPath
46474
- });
46475
- }
46476
- });
46477
- handlers = { ...handlers, ...dispatchHandlers };
46478
45841
  const authResolver = new AuthContextResolver({
46479
45842
  ownerToken: resolvedAuthToken
46480
45843
  });
@@ -46549,10 +45912,6 @@ async function startDaemon(config) {
46549
45912
  manager,
46550
45913
  getAdapter,
46551
45914
  getTunnelUrl: () => currentTunnelUrl,
46552
- getLogShipping: () => config.logShipping ? {
46553
- endpoint: config.logShipping.endpoint,
46554
- sampling: config.logShipping.sampling
46555
- } : null,
46556
45915
  // ready 帧 mode = daemon CC spawn 模式('sdk' | 'tui');UI 用它挂 XtermPanel
46557
45916
  mode: config.mode,
46558
45917
  // file-sharing 字段:httpBaseUrl 跟 tunnel 状态走;httpToken 复用 owner WS token
@@ -46707,8 +46066,8 @@ async function startDaemon(config) {
46707
46066
  const lines = [
46708
46067
  `Tunnel: ${r.url}`,
46709
46068
  ...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
46710
- `Frpc config: ${import_node_path46.default.join(config.dataDir, "frpc.toml")}`,
46711
- `Frpc log: ${import_node_path46.default.join(config.dataDir, "frpc.log")}`
46069
+ `Frpc config: ${import_node_path45.default.join(config.dataDir, "frpc.toml")}`,
46070
+ `Frpc log: ${import_node_path45.default.join(config.dataDir, "frpc.log")}`
46712
46071
  ];
46713
46072
  const width = Math.max(...lines.map((l) => l.length));
46714
46073
  const bar = "\u2550".repeat(width + 4);
@@ -46721,8 +46080,8 @@ ${bar}
46721
46080
 
46722
46081
  `);
46723
46082
  try {
46724
- const connectPath = import_node_path46.default.join(config.dataDir, "connect.txt");
46725
- import_node_fs34.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
46083
+ const connectPath = import_node_path45.default.join(config.dataDir, "connect.txt");
46084
+ import_node_fs33.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
46726
46085
  } catch {
46727
46086
  }
46728
46087
  } catch (err) {
@@ -46783,7 +46142,6 @@ ${bar}
46783
46142
  }
46784
46143
  await wss.stop();
46785
46144
  stateMgr.delete();
46786
- if (logClient) await logClient.dispose();
46787
46145
  };
46788
46146
  return {
46789
46147
  stop: shutdown,
@@ -46794,9 +46152,9 @@ ${bar}
46794
46152
  };
46795
46153
  }
46796
46154
  function migrateDropPersonsDir(dataDir) {
46797
- const dir = import_node_path46.default.join(dataDir, "persons");
46155
+ const dir = import_node_path45.default.join(dataDir, "persons");
46798
46156
  try {
46799
- import_node_fs34.default.rmSync(dir, { recursive: true, force: true });
46157
+ import_node_fs33.default.rmSync(dir, { recursive: true, force: true });
46800
46158
  } catch {
46801
46159
  }
46802
46160
  }