@clawos-dev/clawd 0.2.321 → 0.2.322

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -450,8 +450,8 @@ var init_parseUtil = __esm({
450
450
  init_errors();
451
451
  init_en();
452
452
  makeIssue = (params) => {
453
- const { data, path: path79, errorMaps, issueData } = params;
454
- const fullPath = [...path79, ...issueData.path || []];
453
+ const { data, path: path81, errorMaps, issueData } = params;
454
+ const fullPath = [...path81, ...issueData.path || []];
455
455
  const fullIssue = {
456
456
  ...issueData,
457
457
  path: fullPath
@@ -762,11 +762,11 @@ var init_types = __esm({
762
762
  init_parseUtil();
763
763
  init_util();
764
764
  ParseInputLazyPath = class {
765
- constructor(parent, value, path79, key) {
765
+ constructor(parent, value, path81, key) {
766
766
  this._cachedPath = [];
767
767
  this.parent = parent;
768
768
  this.data = value;
769
- this._path = path79;
769
+ this._path = path81;
770
770
  this._key = key;
771
771
  }
772
772
  get path() {
@@ -6072,7 +6072,9 @@ var init_feishu_auth = __esm({
6072
6072
  "peerSession:remove",
6073
6073
  // 设备目录 + 连接(决策 #15:daemon 代理中心 server,需要 owner 的 ttcJwt)
6074
6074
  "device:list",
6075
- "device:connect"
6075
+ "device:connect",
6076
+ // iOS TestFlight 意向登记(需要 owner unionId 上报中心 server)
6077
+ "onboarding:iosInterest"
6076
6078
  ];
6077
6079
  DeviceEntrySchema = external_exports.object({
6078
6080
  /**
@@ -6659,6 +6661,49 @@ var init_lark_bot_schemas = __esm({
6659
6661
  }
6660
6662
  });
6661
6663
 
6664
+ // ../protocol/src/onboarding-schemas.ts
6665
+ var OnboardingCompleteArgs, OnboardingCompleteResultSchema, ToolsProbeArgs, ToolsProbeResultSchema, SessionExternalScanArgs, ExternalSessionCandidateSchema, SessionExternalScanResultSchema, OnboardingIosInterestArgs, OnboardingIosInterestResultSchema;
6666
+ var init_onboarding_schemas = __esm({
6667
+ "../protocol/src/onboarding-schemas.ts"() {
6668
+ "use strict";
6669
+ init_zod();
6670
+ OnboardingCompleteArgs = external_exports.object({});
6671
+ OnboardingCompleteResultSchema = external_exports.object({
6672
+ /** 毫秒时间戳;重复调用幂等返回首次值(对齐 personaScanDoneAt 先例) */
6673
+ onboardingCompletedAt: external_exports.number()
6674
+ });
6675
+ ToolsProbeArgs = external_exports.object({});
6676
+ ToolsProbeResultSchema = external_exports.object({
6677
+ tools: external_exports.array(
6678
+ external_exports.object({
6679
+ id: external_exports.enum(["claude", "codex"]),
6680
+ available: external_exports.boolean(),
6681
+ version: external_exports.string().optional(),
6682
+ path: external_exports.string().optional()
6683
+ })
6684
+ )
6685
+ });
6686
+ SessionExternalScanArgs = external_exports.object({});
6687
+ ExternalSessionCandidateSchema = external_exports.object({
6688
+ tool: external_exports.enum(["claude", "codex"]),
6689
+ cwd: external_exports.string(),
6690
+ toolSessionId: external_exports.string(),
6691
+ label: external_exports.string().optional(),
6692
+ /** ISO datetime(直接回填给 session:importExternal) */
6693
+ createdAt: external_exports.string(),
6694
+ updatedAt: external_exports.string(),
6695
+ turns: external_exports.number()
6696
+ });
6697
+ SessionExternalScanResultSchema = external_exports.object({
6698
+ candidates: external_exports.array(ExternalSessionCandidateSchema)
6699
+ });
6700
+ OnboardingIosInterestArgs = external_exports.object({});
6701
+ OnboardingIosInterestResultSchema = external_exports.object({
6702
+ registered: external_exports.boolean()
6703
+ });
6704
+ }
6705
+ });
6706
+
6662
6707
  // ../protocol/src/persona-schemas.ts
6663
6708
  var PersonaFileSchema, PersonaSkillSummarySchema, PersonaPluginSummarySchema, PersonaSandboxSettingsSchema, PersonaInfoResponseSchema, PersonaCreateArgsSchema, PersonaIdArgsSchema, PersonaUpdateArgsSchema, CodexSandboxSettingsSchema;
6664
6709
  var init_persona_schemas = __esm({
@@ -7906,6 +7951,7 @@ var init_methods = __esm({
7906
7951
  init_shift_internal();
7907
7952
  init_github();
7908
7953
  init_lark_bot_schemas();
7954
+ init_onboarding_schemas();
7909
7955
  init_persona_schemas();
7910
7956
  init_schemas();
7911
7957
  NO_ARGS = external_exports.object({});
@@ -7920,6 +7966,10 @@ var init_methods = __esm({
7920
7966
  anyOf: [{ required: ["cwd"] }, { required: ["ownerPersonaId"] }]
7921
7967
  }
7922
7968
  },
7969
+ "session:externalScan": {
7970
+ summary: "\u626B\u63CF\u672C\u673A Claude Code / Codex \u5386\u53F2\u4F1A\u8BDD\uFF0C\u8FD4\u56DE\u53EF\u5BFC\u5165\u5019\u9009\u6E05\u5355\uFF08cwd/toolSessionId/\u65F6\u95F4\u6233/\u8F6E\u6570\uFF09\uFF1B\u6458\u8981\u7EDF\u8BA1\u4E0E\u65F6\u95F4\u7A97\u8FC7\u6EE4\u7531 UI \u6D3E\u751F\uFF0Cskip \u89C4\u5219\u4E0E clawd-session-import skill \u4E00\u81F4\uFF1Bowner-only",
7971
+ args: SessionExternalScanArgs
7972
+ },
7923
7973
  "session:importExternal": {
7924
7974
  summary: "\u628A Claude Code / Codex \u65E2\u6709\u5386\u53F2\u4F1A\u8BDD\u5BFC\u5165\u4E3A clawd \u5F15\u7528\uFF1A\u53EA\u5199 SessionFile\uFF0C\u4E0D\u62C9\u8D77 runner\uFF0C\u4E0D\u6539\u539F\u59CB transcript\uFF1B\u6309 toolSessionId \u8DE8 owned scope \u53BB\u91CD\uFF0C\u65B0\u5BFC\u5165\u4F1A\u5E7F\u64AD session:info",
7925
7975
  args: SessionImportExternalArgs
@@ -8140,6 +8190,18 @@ var init_methods = __esm({
8140
8190
  summary: "\u67E5 persona \u7684\u98DE\u4E66 bot \u72B6\u6001\uFF08unbound/bound/broken + \u670D\u52A1\u4E2D\u7FA4\u6E05\u5355\uFF09\uFF1Bowner-only",
8141
8191
  args: LarkBotStatusArgs
8142
8192
  },
8193
+ "onboarding:complete": {
8194
+ summary: "\u6807\u8BB0\u9996\u542F onboarding \u5B8C\u6210\uFF1A\u5F80 <dataDir>/profile.json \u5199 onboardingCompletedAt\uFF08\u6BEB\u79D2\u65F6\u95F4\u6233\uFF0C\u4FDD\u7559\u5176\u5B83\u5B57\u6BB5\uFF0C\u91CD\u590D\u8C03\u7528\u5E42\u7B49\uFF09\uFF1Binfo ready \u5E27\u643A\u5E26\u8BE5\u5B57\u6BB5\u4F9B UI \u5224\u5B9A\u662F\u5426\u8FDB wizard",
8195
+ args: OnboardingCompleteArgs
8196
+ },
8197
+ "tools:probe": {
8198
+ summary: "\u63A2\u6D4B\u672C\u673A claude / codex CLI \u771F\u5B9E\u53EF\u7528\u6027\u4E0E\u7248\u672C\uFF08which + <bin> --version\uFF0C\u8FDB\u7A0B\u7EA7\u7F13\u5B58\uFF09\uFF1Binfo \u5E27 tools[].available \u662F\u6CE8\u518C\u5360\u4F4D\u4E0D\u53CD\u6620\u5B89\u88C5\u72B6\u6001\uFF0Cwizard \u73AF\u5883\u68C0\u67E5\u7528\u672C\u65B9\u6CD5",
8199
+ args: ToolsProbeArgs
8200
+ },
8201
+ "onboarding:iosInterest": {
8202
+ summary: "\u767B\u8BB0 owner \u60F3\u8981 iOS TestFlight\uFF1Adaemon \u8F6C\u53D1\u4E2D\u5FC3 API\uFF08\u643A\u5E26 unionId/\u98DE\u4E66\u540D\uFF09\uFF0Cserver \u843D\u8868\u53BB\u91CD\u5E76\u7528\u5B98\u65B9 bot \u901A\u77E5 David \u8D70\u98DE\u4E66\u8054\u7CFB\uFF1B\u9700\u98DE\u4E66\u5DF2\u767B\u5F55\uFF08FEISHU_GATED\uFF09",
8203
+ args: OnboardingIosInterestArgs
8204
+ },
8143
8205
  "skills:list": {
8144
8206
  summary: "\u626B\u63CF\u5E76\u5217\u51FA\u8BE5\u76EE\u5F55\u53EF\u7528\u7684 skill",
8145
8207
  args: SkillsListArgs
@@ -8592,6 +8654,7 @@ var init_runtime = __esm({
8592
8654
  init_shift_internal();
8593
8655
  init_lark_bot_schemas();
8594
8656
  init_lark_bot_format();
8657
+ init_onboarding_schemas();
8595
8658
  }
8596
8659
  });
8597
8660
 
@@ -8866,8 +8929,8 @@ var require_req = __commonJS({
8866
8929
  if (req.originalUrl) {
8867
8930
  _req.url = req.originalUrl;
8868
8931
  } else {
8869
- const path79 = req.path;
8870
- _req.url = typeof path79 === "string" ? path79 : req.url ? req.url.path || req.url : void 0;
8932
+ const path81 = req.path;
8933
+ _req.url = typeof path81 === "string" ? path81 : req.url ? req.url.path || req.url : void 0;
8871
8934
  }
8872
8935
  if (req.query) {
8873
8936
  _req.query = req.query;
@@ -9032,14 +9095,14 @@ var require_redact = __commonJS({
9032
9095
  }
9033
9096
  return obj;
9034
9097
  }
9035
- function parsePath(path79) {
9098
+ function parsePath(path81) {
9036
9099
  const parts = [];
9037
9100
  let current = "";
9038
9101
  let inBrackets = false;
9039
9102
  let inQuotes = false;
9040
9103
  let quoteChar = "";
9041
- for (let i = 0; i < path79.length; i++) {
9042
- const char = path79[i];
9104
+ for (let i = 0; i < path81.length; i++) {
9105
+ const char = path81[i];
9043
9106
  if (!inBrackets && char === ".") {
9044
9107
  if (current) {
9045
9108
  parts.push(current);
@@ -9170,10 +9233,10 @@ var require_redact = __commonJS({
9170
9233
  return current;
9171
9234
  }
9172
9235
  function redactPaths(obj, paths, censor, remove = false) {
9173
- for (const path79 of paths) {
9174
- const parts = parsePath(path79);
9236
+ for (const path81 of paths) {
9237
+ const parts = parsePath(path81);
9175
9238
  if (parts.includes("*")) {
9176
- redactWildcardPath(obj, parts, censor, path79, remove);
9239
+ redactWildcardPath(obj, parts, censor, path81, remove);
9177
9240
  } else {
9178
9241
  if (remove) {
9179
9242
  removeKey(obj, parts);
@@ -9258,8 +9321,8 @@ var require_redact = __commonJS({
9258
9321
  }
9259
9322
  } else {
9260
9323
  if (afterWildcard.includes("*")) {
9261
- const wrappedCensor = typeof censor === "function" ? (value, path79) => {
9262
- const fullPath = [...pathArray.slice(0, pathLength), ...path79];
9324
+ const wrappedCensor = typeof censor === "function" ? (value, path81) => {
9325
+ const fullPath = [...pathArray.slice(0, pathLength), ...path81];
9263
9326
  return censor(value, fullPath);
9264
9327
  } : censor;
9265
9328
  redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
@@ -9294,8 +9357,8 @@ var require_redact = __commonJS({
9294
9357
  return null;
9295
9358
  }
9296
9359
  const pathStructure = /* @__PURE__ */ new Map();
9297
- for (const path79 of pathsToClone) {
9298
- const parts = parsePath(path79);
9360
+ for (const path81 of pathsToClone) {
9361
+ const parts = parsePath(path81);
9299
9362
  let current = pathStructure;
9300
9363
  for (let i = 0; i < parts.length; i++) {
9301
9364
  const part = parts[i];
@@ -9347,24 +9410,24 @@ var require_redact = __commonJS({
9347
9410
  }
9348
9411
  return cloneSelectively(obj, pathStructure);
9349
9412
  }
9350
- function validatePath(path79) {
9351
- if (typeof path79 !== "string") {
9413
+ function validatePath(path81) {
9414
+ if (typeof path81 !== "string") {
9352
9415
  throw new Error("Paths must be (non-empty) strings");
9353
9416
  }
9354
- if (path79 === "") {
9417
+ if (path81 === "") {
9355
9418
  throw new Error("Invalid redaction path ()");
9356
9419
  }
9357
- if (path79.includes("..")) {
9358
- throw new Error(`Invalid redaction path (${path79})`);
9420
+ if (path81.includes("..")) {
9421
+ throw new Error(`Invalid redaction path (${path81})`);
9359
9422
  }
9360
- if (path79.includes(",")) {
9361
- throw new Error(`Invalid redaction path (${path79})`);
9423
+ if (path81.includes(",")) {
9424
+ throw new Error(`Invalid redaction path (${path81})`);
9362
9425
  }
9363
9426
  let bracketCount = 0;
9364
9427
  let inQuotes = false;
9365
9428
  let quoteChar = "";
9366
- for (let i = 0; i < path79.length; i++) {
9367
- const char = path79[i];
9429
+ for (let i = 0; i < path81.length; i++) {
9430
+ const char = path81[i];
9368
9431
  if ((char === '"' || char === "'") && bracketCount > 0) {
9369
9432
  if (!inQuotes) {
9370
9433
  inQuotes = true;
@@ -9378,20 +9441,20 @@ var require_redact = __commonJS({
9378
9441
  } else if (char === "]" && !inQuotes) {
9379
9442
  bracketCount--;
9380
9443
  if (bracketCount < 0) {
9381
- throw new Error(`Invalid redaction path (${path79})`);
9444
+ throw new Error(`Invalid redaction path (${path81})`);
9382
9445
  }
9383
9446
  }
9384
9447
  }
9385
9448
  if (bracketCount !== 0) {
9386
- throw new Error(`Invalid redaction path (${path79})`);
9449
+ throw new Error(`Invalid redaction path (${path81})`);
9387
9450
  }
9388
9451
  }
9389
9452
  function validatePaths(paths) {
9390
9453
  if (!Array.isArray(paths)) {
9391
9454
  throw new TypeError("paths must be an array");
9392
9455
  }
9393
- for (const path79 of paths) {
9394
- validatePath(path79);
9456
+ for (const path81 of paths) {
9457
+ validatePath(path81);
9395
9458
  }
9396
9459
  }
9397
9460
  function slowRedact(options = {}) {
@@ -9559,8 +9622,8 @@ var require_redaction = __commonJS({
9559
9622
  if (shape[k2] === null) {
9560
9623
  o[k2] = (value) => topCensor(value, [k2]);
9561
9624
  } else {
9562
- const wrappedCensor = typeof censor === "function" ? (value, path79) => {
9563
- return censor(value, [k2, ...path79]);
9625
+ const wrappedCensor = typeof censor === "function" ? (value, path81) => {
9626
+ return censor(value, [k2, ...path81]);
9564
9627
  } : censor;
9565
9628
  o[k2] = Redact({
9566
9629
  paths: shape[k2],
@@ -9778,10 +9841,10 @@ var require_atomic_sleep = __commonJS({
9778
9841
  var require_sonic_boom = __commonJS({
9779
9842
  "../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
9780
9843
  "use strict";
9781
- var fs69 = require("fs");
9844
+ var fs71 = require("fs");
9782
9845
  var EventEmitter3 = require("events");
9783
9846
  var inherits = require("util").inherits;
9784
- var path79 = require("path");
9847
+ var path81 = require("path");
9785
9848
  var sleep2 = require_atomic_sleep();
9786
9849
  var assert = require("assert");
9787
9850
  var BUSY_WRITE_TIMEOUT = 100;
@@ -9835,20 +9898,20 @@ var require_sonic_boom = __commonJS({
9835
9898
  const mode = sonic.mode;
9836
9899
  if (sonic.sync) {
9837
9900
  try {
9838
- if (sonic.mkdir) fs69.mkdirSync(path79.dirname(file), { recursive: true });
9839
- const fd = fs69.openSync(file, flags, mode);
9901
+ if (sonic.mkdir) fs71.mkdirSync(path81.dirname(file), { recursive: true });
9902
+ const fd = fs71.openSync(file, flags, mode);
9840
9903
  fileOpened(null, fd);
9841
9904
  } catch (err) {
9842
9905
  fileOpened(err);
9843
9906
  throw err;
9844
9907
  }
9845
9908
  } else if (sonic.mkdir) {
9846
- fs69.mkdir(path79.dirname(file), { recursive: true }, (err) => {
9909
+ fs71.mkdir(path81.dirname(file), { recursive: true }, (err) => {
9847
9910
  if (err) return fileOpened(err);
9848
- fs69.open(file, flags, mode, fileOpened);
9911
+ fs71.open(file, flags, mode, fileOpened);
9849
9912
  });
9850
9913
  } else {
9851
- fs69.open(file, flags, mode, fileOpened);
9914
+ fs71.open(file, flags, mode, fileOpened);
9852
9915
  }
9853
9916
  }
9854
9917
  function SonicBoom(opts) {
@@ -9889,8 +9952,8 @@ var require_sonic_boom = __commonJS({
9889
9952
  this.flush = flushBuffer;
9890
9953
  this.flushSync = flushBufferSync;
9891
9954
  this._actualWrite = actualWriteBuffer;
9892
- fsWriteSync = () => fs69.writeSync(this.fd, this._writingBuf);
9893
- fsWrite = () => fs69.write(this.fd, this._writingBuf, this.release);
9955
+ fsWriteSync = () => fs71.writeSync(this.fd, this._writingBuf);
9956
+ fsWrite = () => fs71.write(this.fd, this._writingBuf, this.release);
9894
9957
  } else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
9895
9958
  this._writingBuf = "";
9896
9959
  this.write = write;
@@ -9899,15 +9962,15 @@ var require_sonic_boom = __commonJS({
9899
9962
  this._actualWrite = actualWrite;
9900
9963
  fsWriteSync = () => {
9901
9964
  if (Buffer.isBuffer(this._writingBuf)) {
9902
- return fs69.writeSync(this.fd, this._writingBuf);
9965
+ return fs71.writeSync(this.fd, this._writingBuf);
9903
9966
  }
9904
- return fs69.writeSync(this.fd, this._writingBuf, "utf8");
9967
+ return fs71.writeSync(this.fd, this._writingBuf, "utf8");
9905
9968
  };
9906
9969
  fsWrite = () => {
9907
9970
  if (Buffer.isBuffer(this._writingBuf)) {
9908
- return fs69.write(this.fd, this._writingBuf, this.release);
9971
+ return fs71.write(this.fd, this._writingBuf, this.release);
9909
9972
  }
9910
- return fs69.write(this.fd, this._writingBuf, "utf8", this.release);
9973
+ return fs71.write(this.fd, this._writingBuf, "utf8", this.release);
9911
9974
  };
9912
9975
  } else {
9913
9976
  throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
@@ -9964,7 +10027,7 @@ var require_sonic_boom = __commonJS({
9964
10027
  }
9965
10028
  }
9966
10029
  if (this._fsync) {
9967
- fs69.fsyncSync(this.fd);
10030
+ fs71.fsyncSync(this.fd);
9968
10031
  }
9969
10032
  const len = this._len;
9970
10033
  if (this._reopening) {
@@ -10078,7 +10141,7 @@ var require_sonic_boom = __commonJS({
10078
10141
  const onDrain = () => {
10079
10142
  if (!this._fsync) {
10080
10143
  try {
10081
- fs69.fsync(this.fd, (err) => {
10144
+ fs71.fsync(this.fd, (err) => {
10082
10145
  this._flushPending = false;
10083
10146
  cb(err);
10084
10147
  });
@@ -10180,7 +10243,7 @@ var require_sonic_boom = __commonJS({
10180
10243
  const fd = this.fd;
10181
10244
  this.once("ready", () => {
10182
10245
  if (fd !== this.fd) {
10183
- fs69.close(fd, (err) => {
10246
+ fs71.close(fd, (err) => {
10184
10247
  if (err) {
10185
10248
  return this.emit("error", err);
10186
10249
  }
@@ -10229,7 +10292,7 @@ var require_sonic_boom = __commonJS({
10229
10292
  buf = this._bufs[0];
10230
10293
  }
10231
10294
  try {
10232
- const n = Buffer.isBuffer(buf) ? fs69.writeSync(this.fd, buf) : fs69.writeSync(this.fd, buf, "utf8");
10295
+ const n = Buffer.isBuffer(buf) ? fs71.writeSync(this.fd, buf) : fs71.writeSync(this.fd, buf, "utf8");
10233
10296
  const releasedBufObj = releaseWritingBuf(buf, this._len, n);
10234
10297
  buf = releasedBufObj.writingBuf;
10235
10298
  this._len = releasedBufObj.len;
@@ -10245,7 +10308,7 @@ var require_sonic_boom = __commonJS({
10245
10308
  }
10246
10309
  }
10247
10310
  try {
10248
- fs69.fsyncSync(this.fd);
10311
+ fs71.fsyncSync(this.fd);
10249
10312
  } catch {
10250
10313
  }
10251
10314
  }
@@ -10266,7 +10329,7 @@ var require_sonic_boom = __commonJS({
10266
10329
  buf = mergeBuf(this._bufs[0], this._lens[0]);
10267
10330
  }
10268
10331
  try {
10269
- const n = fs69.writeSync(this.fd, buf);
10332
+ const n = fs71.writeSync(this.fd, buf);
10270
10333
  buf = buf.subarray(n);
10271
10334
  this._len = Math.max(this._len - n, 0);
10272
10335
  if (buf.length <= 0) {
@@ -10294,13 +10357,13 @@ var require_sonic_boom = __commonJS({
10294
10357
  this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
10295
10358
  if (this.sync) {
10296
10359
  try {
10297
- const written = Buffer.isBuffer(this._writingBuf) ? fs69.writeSync(this.fd, this._writingBuf) : fs69.writeSync(this.fd, this._writingBuf, "utf8");
10360
+ const written = Buffer.isBuffer(this._writingBuf) ? fs71.writeSync(this.fd, this._writingBuf) : fs71.writeSync(this.fd, this._writingBuf, "utf8");
10298
10361
  release(null, written);
10299
10362
  } catch (err) {
10300
10363
  release(err);
10301
10364
  }
10302
10365
  } else {
10303
- fs69.write(this.fd, this._writingBuf, release);
10366
+ fs71.write(this.fd, this._writingBuf, release);
10304
10367
  }
10305
10368
  }
10306
10369
  function actualWriteBuffer() {
@@ -10309,7 +10372,7 @@ var require_sonic_boom = __commonJS({
10309
10372
  this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
10310
10373
  if (this.sync) {
10311
10374
  try {
10312
- const written = fs69.writeSync(this.fd, this._writingBuf);
10375
+ const written = fs71.writeSync(this.fd, this._writingBuf);
10313
10376
  release(null, written);
10314
10377
  } catch (err) {
10315
10378
  release(err);
@@ -10318,7 +10381,7 @@ var require_sonic_boom = __commonJS({
10318
10381
  if (kCopyBuffer) {
10319
10382
  this._writingBuf = Buffer.from(this._writingBuf);
10320
10383
  }
10321
- fs69.write(this.fd, this._writingBuf, release);
10384
+ fs71.write(this.fd, this._writingBuf, release);
10322
10385
  }
10323
10386
  }
10324
10387
  function actualClose(sonic) {
@@ -10334,12 +10397,12 @@ var require_sonic_boom = __commonJS({
10334
10397
  sonic._lens = [];
10335
10398
  assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
10336
10399
  try {
10337
- fs69.fsync(sonic.fd, closeWrapped);
10400
+ fs71.fsync(sonic.fd, closeWrapped);
10338
10401
  } catch {
10339
10402
  }
10340
10403
  function closeWrapped() {
10341
10404
  if (sonic.fd !== 1 && sonic.fd !== 2) {
10342
- fs69.close(sonic.fd, done);
10405
+ fs71.close(sonic.fd, done);
10343
10406
  } else {
10344
10407
  done();
10345
10408
  }
@@ -11016,7 +11079,7 @@ var require_thread_stream = __commonJS({
11016
11079
  var require_transport = __commonJS({
11017
11080
  "../node_modules/.pnpm/pino@9.14.0/node_modules/pino/lib/transport.js"(exports2, module2) {
11018
11081
  "use strict";
11019
- var { createRequire } = require("module");
11082
+ var { createRequire: createRequire2 } = require("module");
11020
11083
  var getCallers = require_caller();
11021
11084
  var { join: join16, isAbsolute: isAbsolute2, sep: sep3 } = require("path");
11022
11085
  var sleep2 = require_atomic_sleep();
@@ -11127,7 +11190,7 @@ var require_transport = __commonJS({
11127
11190
  for (const filePath of callers) {
11128
11191
  try {
11129
11192
  const context = filePath === "node:repl" ? process.cwd() + sep3 : filePath;
11130
- fixTarget2 = createRequire(context).resolve(origin);
11193
+ fixTarget2 = createRequire2(context).resolve(origin);
11131
11194
  break;
11132
11195
  } catch (err) {
11133
11196
  continue;
@@ -11549,12 +11612,12 @@ var require_levels = __commonJS({
11549
11612
  function genLsCache(instance) {
11550
11613
  const formatter = instance[formattersSym].level;
11551
11614
  const { labels } = instance.levels;
11552
- const cache = {};
11615
+ const cache2 = {};
11553
11616
  for (const label in labels) {
11554
11617
  const level = formatter(labels[label], Number(label));
11555
- cache[label] = JSON.stringify(level).slice(0, -1);
11618
+ cache2[label] = JSON.stringify(level).slice(0, -1);
11556
11619
  }
11557
- instance[lsCacheSym] = cache;
11620
+ instance[lsCacheSym] = cache2;
11558
11621
  return instance;
11559
11622
  }
11560
11623
  function isStandardLevel(level, useOnlyCustomLevels) {
@@ -12703,7 +12766,7 @@ var require_multistream = __commonJS({
12703
12766
  var require_pino = __commonJS({
12704
12767
  "../node_modules/.pnpm/pino@9.14.0/node_modules/pino/pino.js"(exports2, module2) {
12705
12768
  "use strict";
12706
- var os24 = require("os");
12769
+ var os25 = require("os");
12707
12770
  var stdSerializers = require_pino_std_serializers();
12708
12771
  var caller = require_caller();
12709
12772
  var redaction = require_redaction();
@@ -12750,7 +12813,7 @@ var require_pino = __commonJS({
12750
12813
  } = symbols;
12751
12814
  var { epochTime, nullTime } = time;
12752
12815
  var { pid } = process;
12753
- var hostname = os24.hostname();
12816
+ var hostname = os25.hostname();
12754
12817
  var defaultErrorSerializer = stdSerializers.err;
12755
12818
  var defaultOptions2 = {
12756
12819
  level: "info",
@@ -13474,11 +13537,11 @@ var init_lib = __esm({
13474
13537
  }
13475
13538
  }
13476
13539
  },
13477
- addToPath: function addToPath(path79, added, removed, oldPosInc, options) {
13478
- var last = path79.lastComponent;
13540
+ addToPath: function addToPath(path81, added, removed, oldPosInc, options) {
13541
+ var last = path81.lastComponent;
13479
13542
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
13480
13543
  return {
13481
- oldPos: path79.oldPos + oldPosInc,
13544
+ oldPos: path81.oldPos + oldPosInc,
13482
13545
  lastComponent: {
13483
13546
  count: last.count + 1,
13484
13547
  added,
@@ -13488,7 +13551,7 @@ var init_lib = __esm({
13488
13551
  };
13489
13552
  } else {
13490
13553
  return {
13491
- oldPos: path79.oldPos + oldPosInc,
13554
+ oldPos: path81.oldPos + oldPosInc,
13492
13555
  lastComponent: {
13493
13556
  count: 1,
13494
13557
  added,
@@ -13997,10 +14060,10 @@ function attachmentToHistoryMessage(o, ts) {
13997
14060
  const memories = raw.map((m2) => {
13998
14061
  if (!m2 || typeof m2 !== "object") return null;
13999
14062
  const rec3 = m2;
14000
- const path79 = typeof rec3.path === "string" ? rec3.path : null;
14063
+ const path81 = typeof rec3.path === "string" ? rec3.path : null;
14001
14064
  const content = typeof rec3.content === "string" ? rec3.content : null;
14002
- if (!path79 || content == null) return null;
14003
- const entry = { path: path79, content };
14065
+ if (!path81 || content == null) return null;
14066
+ const entry = { path: path81, content };
14004
14067
  if (typeof rec3.mtimeMs === "number") entry.mtimeMs = rec3.mtimeMs;
14005
14068
  return entry;
14006
14069
  }).filter((m2) => m2 !== null);
@@ -14817,10 +14880,10 @@ function parseAttachment(obj) {
14817
14880
  const memories = raw.map((m2) => {
14818
14881
  if (!m2 || typeof m2 !== "object") return null;
14819
14882
  const rec3 = m2;
14820
- const path79 = typeof rec3.path === "string" ? rec3.path : null;
14883
+ const path81 = typeof rec3.path === "string" ? rec3.path : null;
14821
14884
  const content = typeof rec3.content === "string" ? rec3.content : null;
14822
- if (!path79 || content == null) return null;
14823
- const out = { path: path79, content };
14885
+ if (!path81 || content == null) return null;
14886
+ const out = { path: path81, content };
14824
14887
  if (typeof rec3.mtimeMs === "number") out.mtimeMs = rec3.mtimeMs;
14825
14888
  return out;
14826
14889
  }).filter((m2) => m2 !== null);
@@ -35789,8 +35852,8 @@ var require_utils = __commonJS({
35789
35852
  var result = transform[inputType][outputType](input);
35790
35853
  return result;
35791
35854
  };
35792
- exports2.resolve = function(path79) {
35793
- var parts = path79.split("/");
35855
+ exports2.resolve = function(path81) {
35856
+ var parts = path81.split("/");
35794
35857
  var result = [];
35795
35858
  for (var index = 0; index < parts.length; index++) {
35796
35859
  var part = parts[index];
@@ -41217,10 +41280,10 @@ var require_ZipFileWorker = __commonJS({
41217
41280
  }
41218
41281
  return hex;
41219
41282
  };
41220
- var generateUnixExternalFileAttr = function(unixPermissions, isDir2) {
41283
+ var generateUnixExternalFileAttr = function(unixPermissions, isDir3) {
41221
41284
  var result = unixPermissions;
41222
41285
  if (!unixPermissions) {
41223
- result = isDir2 ? 16893 : 33204;
41286
+ result = isDir3 ? 16893 : 33204;
41224
41287
  }
41225
41288
  return (result & 65535) << 16;
41226
41289
  };
@@ -41643,18 +41706,18 @@ var require_object = __commonJS({
41643
41706
  var object = new ZipObject(name, zipObjectContent, o);
41644
41707
  this.files[name] = object;
41645
41708
  };
41646
- var parentFolder = function(path79) {
41647
- if (path79.slice(-1) === "/") {
41648
- path79 = path79.substring(0, path79.length - 1);
41709
+ var parentFolder = function(path81) {
41710
+ if (path81.slice(-1) === "/") {
41711
+ path81 = path81.substring(0, path81.length - 1);
41649
41712
  }
41650
- var lastSlash = path79.lastIndexOf("/");
41651
- return lastSlash > 0 ? path79.substring(0, lastSlash) : "";
41713
+ var lastSlash = path81.lastIndexOf("/");
41714
+ return lastSlash > 0 ? path81.substring(0, lastSlash) : "";
41652
41715
  };
41653
- var forceTrailingSlash = function(path79) {
41654
- if (path79.slice(-1) !== "/") {
41655
- path79 += "/";
41716
+ var forceTrailingSlash = function(path81) {
41717
+ if (path81.slice(-1) !== "/") {
41718
+ path81 += "/";
41656
41719
  }
41657
- return path79;
41720
+ return path81;
41658
41721
  };
41659
41722
  var folderAdd = function(name, createFolders) {
41660
41723
  createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
@@ -42656,7 +42719,7 @@ var require_lib3 = __commonJS({
42656
42719
  // src/run-case/recorder.ts
42657
42720
  function startRunCaseRecorder(opts) {
42658
42721
  const now = opts.now ?? Date.now;
42659
- const dir = import_node_path66.default.dirname(opts.recordPath);
42722
+ const dir = import_node_path68.default.dirname(opts.recordPath);
42660
42723
  let stream = null;
42661
42724
  let closing = false;
42662
42725
  let closedSettled = false;
@@ -42670,8 +42733,8 @@ function startRunCaseRecorder(opts) {
42670
42733
  });
42671
42734
  const ensureStream = () => {
42672
42735
  if (stream) return stream;
42673
- import_node_fs50.default.mkdirSync(dir, { recursive: true });
42674
- stream = import_node_fs50.default.createWriteStream(opts.recordPath, { flags: "a" });
42736
+ import_node_fs52.default.mkdirSync(dir, { recursive: true });
42737
+ stream = import_node_fs52.default.createWriteStream(opts.recordPath, { flags: "a" });
42675
42738
  stream.on("close", () => closedResolve());
42676
42739
  return stream;
42677
42740
  };
@@ -42696,12 +42759,12 @@ function startRunCaseRecorder(opts) {
42696
42759
  };
42697
42760
  return { tap, close, closed };
42698
42761
  }
42699
- var import_node_fs50, import_node_path66;
42762
+ var import_node_fs52, import_node_path68;
42700
42763
  var init_recorder = __esm({
42701
42764
  "src/run-case/recorder.ts"() {
42702
42765
  "use strict";
42703
- import_node_fs50 = __toESM(require("fs"), 1);
42704
- import_node_path66 = __toESM(require("path"), 1);
42766
+ import_node_fs52 = __toESM(require("fs"), 1);
42767
+ import_node_path68 = __toESM(require("path"), 1);
42705
42768
  }
42706
42769
  });
42707
42770
 
@@ -42744,7 +42807,7 @@ var init_wire = __esm({
42744
42807
  // src/run-case/controller.ts
42745
42808
  async function runController(opts) {
42746
42809
  const now = opts.now ?? Date.now;
42747
- const cwd = opts.cwd ?? (0, import_node_fs51.mkdtempSync)(import_node_path67.default.join(import_node_os23.default.tmpdir(), "clawd-runcase-"));
42810
+ const cwd = opts.cwd ?? (0, import_node_fs53.mkdtempSync)(import_node_path69.default.join(import_node_os24.default.tmpdir(), "clawd-runcase-"));
42748
42811
  const ownsCwd = opts.cwd === void 0;
42749
42812
  const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
42750
42813
  const spawnCtx = { cwd };
@@ -42905,19 +42968,19 @@ async function runController(opts) {
42905
42968
  if (sigintHandler) process.off("SIGINT", sigintHandler);
42906
42969
  if (ownsCwd) {
42907
42970
  try {
42908
- (0, import_node_fs51.rmSync)(cwd, { recursive: true, force: true });
42971
+ (0, import_node_fs53.rmSync)(cwd, { recursive: true, force: true });
42909
42972
  } catch {
42910
42973
  }
42911
42974
  }
42912
42975
  return exitCode ?? 0;
42913
42976
  }
42914
- var import_node_fs51, import_node_os23, import_node_path67;
42977
+ var import_node_fs53, import_node_os24, import_node_path69;
42915
42978
  var init_controller = __esm({
42916
42979
  "src/run-case/controller.ts"() {
42917
42980
  "use strict";
42918
- import_node_fs51 = require("fs");
42919
- import_node_os23 = __toESM(require("os"), 1);
42920
- import_node_path67 = __toESM(require("path"), 1);
42981
+ import_node_fs53 = require("fs");
42982
+ import_node_os24 = __toESM(require("os"), 1);
42983
+ import_node_path69 = __toESM(require("path"), 1);
42921
42984
  init_claude();
42922
42985
  init_stdout_splitter();
42923
42986
  init_permission_stdio();
@@ -43192,9 +43255,9 @@ Env (advanced):
43192
43255
  `;
43193
43256
 
43194
43257
  // src/index.ts
43195
- var import_node_path65 = __toESM(require("path"), 1);
43196
- var import_node_fs49 = __toESM(require("fs"), 1);
43197
- var import_node_os22 = __toESM(require("os"), 1);
43258
+ var import_node_path67 = __toESM(require("path"), 1);
43259
+ var import_node_fs51 = __toESM(require("fs"), 1);
43260
+ var import_node_os23 = __toESM(require("os"), 1);
43198
43261
 
43199
43262
  // ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/stringify.js
43200
43263
  var byteToHex = [];
@@ -49444,8 +49507,8 @@ function turnStartInput(text) {
49444
49507
  const items = [];
49445
49508
  let leftover = text;
49446
49509
  for (const m2 of text.matchAll(SKILL_RE)) {
49447
- const [marker, name, path79] = m2;
49448
- items.push({ type: "skill", name, path: path79 });
49510
+ const [marker, name, path81] = m2;
49511
+ items.push({ type: "skill", name, path: path81 });
49449
49512
  leftover = leftover.replace(marker, "");
49450
49513
  }
49451
49514
  for (const m2 of text.matchAll(ATTACHMENT_RE2)) {
@@ -53394,13 +53457,13 @@ function mapSkillsListResponse(res) {
53394
53457
  const r = s ?? {};
53395
53458
  const name = str3(r.name);
53396
53459
  if (!name) continue;
53397
- const path79 = str3(r.path);
53460
+ const path81 = str3(r.path);
53398
53461
  const description = str3(r.description);
53399
53462
  const isPlugin = name.includes(":");
53400
53463
  out.push({
53401
53464
  name,
53402
53465
  source: isPlugin ? "plugin" : "project",
53403
- ...path79 ? { path: path79 } : {},
53466
+ ...path81 ? { path: path81 } : {},
53404
53467
  ...description ? { description } : {},
53405
53468
  ...isPlugin ? { plugin: name.split(":")[0] } : {}
53406
53469
  });
@@ -57215,24 +57278,34 @@ var import_node_fs42 = __toESM(require("fs"), 1);
57215
57278
  var import_node_os15 = __toESM(require("os"), 1);
57216
57279
  var import_node_path47 = __toESM(require("path"), 1);
57217
57280
  var PROFILE_FILENAME = "profile.json";
57218
- function loadOwnerDisplayName(dataDir) {
57219
- const fallback = import_node_os15.default.userInfo().username;
57220
- const profilePath = import_node_path47.default.join(dataDir, PROFILE_FILENAME);
57281
+ function profilePath(dataDir) {
57282
+ return import_node_path47.default.join(dataDir, PROFILE_FILENAME);
57283
+ }
57284
+ function loadOwnerProfile(dataDir) {
57221
57285
  let raw;
57222
57286
  try {
57223
- raw = import_node_fs42.default.readFileSync(profilePath, "utf8");
57287
+ raw = import_node_fs42.default.readFileSync(profilePath(dataDir), "utf8");
57224
57288
  } catch {
57225
- return fallback;
57289
+ return {};
57226
57290
  }
57227
- let parsed;
57228
57291
  try {
57229
- parsed = JSON.parse(raw);
57292
+ const parsed = JSON.parse(raw);
57293
+ if (parsed != null && typeof parsed === "object" && !Array.isArray(parsed)) {
57294
+ return parsed;
57295
+ }
57230
57296
  } catch (err) {
57231
- console.warn(`[owner-profile] ${PROFILE_FILENAME} parse failed, falling back to OS username:`, err);
57232
- return fallback;
57297
+ console.warn(`[owner-profile] ${PROFILE_FILENAME} parse failed, treating as empty:`, err);
57233
57298
  }
57234
- if (!parsed || typeof parsed !== "object") return fallback;
57235
- const displayName = parsed.displayName;
57299
+ return {};
57300
+ }
57301
+ function patchOwnerProfile(dataDir, patch) {
57302
+ const merged = { ...loadOwnerProfile(dataDir), ...patch };
57303
+ import_node_fs42.default.writeFileSync(profilePath(dataDir), JSON.stringify(merged, null, 2), { encoding: "utf8", mode: 384 });
57304
+ return merged;
57305
+ }
57306
+ function loadOwnerDisplayName(dataDir) {
57307
+ const fallback = import_node_os15.default.userInfo().username;
57308
+ const displayName = loadOwnerProfile(dataDir).displayName;
57236
57309
  if (typeof displayName !== "string" || displayName.length === 0) {
57237
57310
  if (displayName !== void 0) {
57238
57311
  console.warn(`[owner-profile] displayName must be non-empty string, falling back to OS username`);
@@ -57428,9 +57501,9 @@ var CentralClientError = class extends Error {
57428
57501
  code;
57429
57502
  cause;
57430
57503
  };
57431
- async function centralRequest(opts, path79, init) {
57504
+ async function centralRequest(opts, path81, init) {
57432
57505
  const f = opts.fetchImpl ?? globalThis.fetch;
57433
- const url = `${opts.api.replace(/\/+$/, "")}${path79}`;
57506
+ const url = `${opts.api.replace(/\/+$/, "")}${path81}`;
57434
57507
  const ctrl = new AbortController();
57435
57508
  const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
57436
57509
  let res;
@@ -57737,6 +57810,321 @@ function forkSession(input) {
57737
57810
  return { forkedToolSessionId, forkedFilePath };
57738
57811
  }
57739
57812
 
57813
+ // src/session/external-scan.ts
57814
+ var import_node_fs45 = __toESM(require("fs"), 1);
57815
+ var import_promises6 = __toESM(require("fs/promises"), 1);
57816
+ var import_node_os17 = __toESM(require("os"), 1);
57817
+ var import_node_path50 = __toESM(require("path"), 1);
57818
+ var import_node_module = require("module");
57819
+ var import_node_child_process11 = require("child_process");
57820
+ var import_meta4 = {};
57821
+ function defaultRoots() {
57822
+ const home = import_node_os17.default.homedir();
57823
+ return {
57824
+ claudeProjectsDir: import_node_path50.default.join(home, ".claude", "projects"),
57825
+ codexDir: import_node_path50.default.join(home, ".codex"),
57826
+ clawdDir: import_node_path50.default.join(home, ".clawd")
57827
+ };
57828
+ }
57829
+ function width(s) {
57830
+ let w2 = 0;
57831
+ for (const ch of s) w2 += /[ᄀ-ᅟ⺀-꓏가-힣豈-﫿︰-﹏＀-⦆¢-₩]/.test(ch) ? 2 : 1;
57832
+ return w2;
57833
+ }
57834
+ function clipW(text, n) {
57835
+ const s = String(text ?? "").split(/\s+/).filter(Boolean).join(" ");
57836
+ if (width(s) <= n) return s;
57837
+ let out = "";
57838
+ let w2 = 0;
57839
+ for (const ch of s) {
57840
+ const cw = width(ch);
57841
+ if (w2 + cw > n - 1) break;
57842
+ out += ch;
57843
+ w2 += cw;
57844
+ }
57845
+ return out + "\u2026";
57846
+ }
57847
+ function toMs(v2) {
57848
+ const n = Number(v2 || 0);
57849
+ return n > 1e11 ? Math.round(n) : Math.round(n * 1e3);
57850
+ }
57851
+ function listFiles(dir, depth = 0, maxDepth = 8, out = []) {
57852
+ let entries;
57853
+ try {
57854
+ entries = import_node_fs45.default.readdirSync(dir, { withFileTypes: true });
57855
+ } catch {
57856
+ return out;
57857
+ }
57858
+ for (const e of entries) {
57859
+ const full = import_node_path50.default.join(dir, e.name);
57860
+ if (e.isDirectory()) {
57861
+ if (depth < maxDepth) listFiles(full, depth + 1, maxDepth, out);
57862
+ } else if (e.isFile()) {
57863
+ out.push(full);
57864
+ }
57865
+ }
57866
+ return out;
57867
+ }
57868
+ async function* jsonLines(file) {
57869
+ let raw;
57870
+ try {
57871
+ raw = await import_promises6.default.readFile(file, "utf8");
57872
+ } catch {
57873
+ return;
57874
+ }
57875
+ for (const line of raw.split("\n")) {
57876
+ const t = line.trim();
57877
+ if (!t) continue;
57878
+ try {
57879
+ yield JSON.parse(t);
57880
+ } catch {
57881
+ }
57882
+ }
57883
+ }
57884
+ function userText(msg) {
57885
+ const content = msg && typeof msg === "object" ? msg.content : null;
57886
+ if (typeof content === "string") return content;
57887
+ if (Array.isArray(content)) {
57888
+ return content.map((b2) => b2 && b2.type === "text" ? String(b2.text ?? "") : "").join("");
57889
+ }
57890
+ return "";
57891
+ }
57892
+ function isDir2(p2) {
57893
+ try {
57894
+ return import_node_fs45.default.statSync(p2).isDirectory();
57895
+ } catch {
57896
+ return false;
57897
+ }
57898
+ }
57899
+ async function scanClaude(roots) {
57900
+ const out = [];
57901
+ let dirs;
57902
+ try {
57903
+ dirs = import_node_fs45.default.readdirSync(roots.claudeProjectsDir, { withFileTypes: true });
57904
+ } catch {
57905
+ return out;
57906
+ }
57907
+ for (const d of dirs) {
57908
+ if (!d.isDirectory()) continue;
57909
+ let files;
57910
+ try {
57911
+ files = import_node_fs45.default.readdirSync(import_node_path50.default.join(roots.claudeProjectsDir, d.name));
57912
+ } catch {
57913
+ continue;
57914
+ }
57915
+ for (const name of files) {
57916
+ if (!name.endsWith(".jsonl")) continue;
57917
+ const file = import_node_path50.default.join(roots.claudeProjectsDir, d.name, name);
57918
+ let st;
57919
+ try {
57920
+ st = import_node_fs45.default.statSync(file);
57921
+ } catch {
57922
+ continue;
57923
+ }
57924
+ let cwd = "";
57925
+ let title = "";
57926
+ let firstUser = "";
57927
+ let turns = 0;
57928
+ let firstTs = 0;
57929
+ let lastTs = 0;
57930
+ let hasMainLine = false;
57931
+ for await (const rec3 of jsonLines(file)) {
57932
+ if (!cwd && typeof rec3.cwd === "string") cwd = rec3.cwd;
57933
+ if (typeof rec3.timestamp === "string") {
57934
+ const t = Date.parse(rec3.timestamp);
57935
+ if (Number.isFinite(t)) {
57936
+ firstTs ||= t;
57937
+ lastTs = t;
57938
+ }
57939
+ }
57940
+ if (rec3.type === "ai-title" && rec3.aiTitle) {
57941
+ title = String(rec3.aiTitle);
57942
+ continue;
57943
+ }
57944
+ if (rec3.type !== "user" && rec3.type !== "assistant") continue;
57945
+ if (!rec3.isSidechain) hasMainLine = true;
57946
+ if (rec3.type !== "user" || rec3.isSidechain || rec3.isMeta) continue;
57947
+ const text = userText(rec3.message || {});
57948
+ if (!text.trim() || text.trimStart().startsWith("<")) continue;
57949
+ turns += 1;
57950
+ firstUser ||= text;
57951
+ }
57952
+ const cand = {
57953
+ tool: "claude",
57954
+ toolSessionId: name.slice(0, -".jsonl".length),
57955
+ cwd,
57956
+ label: clipW(title || firstUser, 56),
57957
+ turns,
57958
+ createdMs: firstTs || st.mtimeMs,
57959
+ updatedMs: lastTs || st.mtimeMs,
57960
+ skip: ""
57961
+ };
57962
+ if (!hasMainLine) cand.skip = "subagent \u652F\u7EBF";
57963
+ else if (!cwd) cand.skip = "\u65E0 cwd";
57964
+ out.push(cand);
57965
+ }
57966
+ }
57967
+ return out;
57968
+ }
57969
+ async function countCodexTurns(rolloutPath) {
57970
+ if (!rolloutPath || !import_node_fs45.default.existsSync(rolloutPath)) return { turns: 0, first: "" };
57971
+ let turns = 0;
57972
+ let first = "";
57973
+ for await (const rec3 of jsonLines(rolloutPath)) {
57974
+ const p2 = rec3.payload || {};
57975
+ if (p2.type !== "message" || p2.role !== "user") continue;
57976
+ const text = (p2.content || []).map((b2) => String(b2 && b2.text || "")).join("");
57977
+ if (!text.trim() || text.trimStart().startsWith("<")) continue;
57978
+ turns += 1;
57979
+ first ||= text;
57980
+ }
57981
+ return { turns, first };
57982
+ }
57983
+ function readCodexThreads(db) {
57984
+ const COLS = ["id", "cwd", "created_at", "updated_at", "name", "title", "preview", "first_user_message", "archived", "rollout_path"];
57985
+ try {
57986
+ const { DatabaseSync } = (0, import_node_module.createRequire)(import_meta4.url)("node:sqlite");
57987
+ const conn = new DatabaseSync(db, { readOnly: true });
57988
+ try {
57989
+ const have = new Set(
57990
+ conn.prepare("PRAGMA table_info(threads)").all().map((r) => r.name)
57991
+ );
57992
+ if (!["id", "cwd", "updated_at"].every((c) => have.has(c))) return null;
57993
+ const sel = COLS.map((c) => have.has(c) ? c : `NULL AS ${c}`).join(", ");
57994
+ return conn.prepare(`SELECT ${sel} FROM threads`).all();
57995
+ } finally {
57996
+ conn.close();
57997
+ }
57998
+ } catch {
57999
+ }
58000
+ try {
58001
+ const info = (0, import_node_child_process11.spawnSync)("sqlite3", [db, "PRAGMA table_info(threads);"], { encoding: "utf8" });
58002
+ if (info.status !== 0) return null;
58003
+ const have = new Set(
58004
+ info.stdout.split("\n").map((l) => l.split("|")[1]).filter(Boolean)
58005
+ );
58006
+ if (!["id", "cwd", "updated_at"].every((c) => have.has(c))) return null;
58007
+ const sel = COLS.map((c) => have.has(c) ? c : `NULL AS ${c}`).join(", ");
58008
+ const res = (0, import_node_child_process11.spawnSync)("sqlite3", ["-json", db, `SELECT ${sel} FROM threads;`], {
58009
+ encoding: "utf8",
58010
+ maxBuffer: 64 * 1024 * 1024
58011
+ });
58012
+ if (res.status !== 0 || !res.stdout.trim()) return null;
58013
+ return JSON.parse(res.stdout);
58014
+ } catch {
58015
+ return null;
58016
+ }
58017
+ }
58018
+ async function codexFromRows(rows) {
58019
+ const out = [];
58020
+ for (const r of rows) {
58021
+ const updatedMs = toMs(r.updated_at);
58022
+ const { turns, first } = await countCodexTurns(String(r.rollout_path || ""));
58023
+ const label = clipW(r.name || r.title || r.preview || r.first_user_message || first, 56);
58024
+ const cand = {
58025
+ tool: "codex",
58026
+ toolSessionId: String(r.id),
58027
+ cwd: String(r.cwd || ""),
58028
+ label,
58029
+ turns,
58030
+ createdMs: toMs(r.created_at) || updatedMs,
58031
+ updatedMs,
58032
+ skip: ""
58033
+ };
58034
+ if (r.archived) cand.skip = "\u5DF2\u5F52\u6863";
58035
+ else if (!label) cand.skip = "\u7A7A\u4F1A\u8BDD";
58036
+ out.push(cand);
58037
+ }
58038
+ return out;
58039
+ }
58040
+ async function scanCodexRollouts(roots) {
58041
+ const out = [];
58042
+ for (const file of listFiles(import_node_path50.default.join(roots.codexDir, "sessions"))) {
58043
+ if (!file.endsWith(".jsonl")) continue;
58044
+ let st;
58045
+ try {
58046
+ st = import_node_fs45.default.statSync(file);
58047
+ } catch {
58048
+ continue;
58049
+ }
58050
+ let meta = null;
58051
+ for await (const rec3 of jsonLines(file)) {
58052
+ if (rec3.type === "session_meta") {
58053
+ meta = rec3.payload || {};
58054
+ break;
58055
+ }
58056
+ }
58057
+ const tid = meta && (meta.session_id || meta.id);
58058
+ if (!tid) continue;
58059
+ const { turns, first } = await countCodexTurns(file);
58060
+ const cand = {
58061
+ tool: "codex",
58062
+ toolSessionId: String(tid),
58063
+ cwd: String(meta?.cwd || ""),
58064
+ label: clipW(first, 56),
58065
+ turns,
58066
+ createdMs: st.mtimeMs,
58067
+ updatedMs: st.mtimeMs,
58068
+ skip: ""
58069
+ };
58070
+ if (!cand.cwd) cand.skip = "\u65E0 cwd";
58071
+ out.push(cand);
58072
+ }
58073
+ return out;
58074
+ }
58075
+ async function scanCodex(roots) {
58076
+ let dbs = [];
58077
+ try {
58078
+ dbs = import_node_fs45.default.readdirSync(roots.codexDir).filter((n) => /^state_.*\.sqlite$/.test(n)).sort().map((n) => import_node_path50.default.join(roots.codexDir, n));
58079
+ } catch {
58080
+ }
58081
+ if (dbs.length) {
58082
+ const rows = readCodexThreads(dbs[dbs.length - 1]);
58083
+ if (rows) return codexFromRows(rows);
58084
+ }
58085
+ return scanCodexRollouts(roots);
58086
+ }
58087
+ async function scanExternalSessions(rootsIn) {
58088
+ const roots = { ...defaultRoots(), ...rootsIn };
58089
+ const personaRoot = import_node_path50.default.join(roots.clawdDir, "personas");
58090
+ const all = [...await scanClaude(roots), ...await scanCodex(roots)];
58091
+ const out = [];
58092
+ for (const c of all) {
58093
+ if (c.skip) continue;
58094
+ if (c.turns < 1) continue;
58095
+ if (!c.cwd || !isDir2(c.cwd)) continue;
58096
+ if (c.cwd === roots.clawdDir || c.cwd === personaRoot || c.cwd.startsWith(personaRoot + import_node_path50.default.sep) || c.cwd.startsWith(roots.clawdDir + import_node_path50.default.sep)) {
58097
+ continue;
58098
+ }
58099
+ out.push({
58100
+ tool: c.tool,
58101
+ cwd: c.cwd,
58102
+ toolSessionId: c.toolSessionId,
58103
+ ...c.label ? { label: c.label } : {},
58104
+ createdAt: new Date(c.createdMs).toISOString(),
58105
+ updatedAt: new Date(c.updatedMs).toISOString(),
58106
+ turns: c.turns
58107
+ });
58108
+ }
58109
+ return out;
58110
+ }
58111
+
58112
+ // src/session/import-ledger.ts
58113
+ var import_node_fs46 = __toESM(require("fs"), 1);
58114
+ var import_node_path51 = __toESM(require("path"), 1);
58115
+ var LEDGER_FILENAME = "session-import-ledger.json";
58116
+ function appendImportLedger(dataDir, entry) {
58117
+ const file = import_node_path51.default.join(dataDir, LEDGER_FILENAME);
58118
+ let entries = [];
58119
+ try {
58120
+ const parsed = JSON.parse(import_node_fs46.default.readFileSync(file, "utf8"));
58121
+ if (Array.isArray(parsed)) entries = parsed;
58122
+ } catch {
58123
+ }
58124
+ entries.push(entry);
58125
+ import_node_fs46.default.writeFileSync(file, JSON.stringify(entries, null, 2), { encoding: "utf8", mode: 384 });
58126
+ }
58127
+
57740
58128
  // src/handlers/session.ts
57741
58129
  init_protocol();
57742
58130
  function buildSessionHandlers(deps) {
@@ -57809,8 +58197,30 @@ function buildSessionHandlers(deps) {
57809
58197
  creatorDisplayName,
57810
58198
  creatorFeishuUnionId
57811
58199
  );
58200
+ if (deps.dataDir && !("alreadyLinked" in response)) {
58201
+ appendImportLedger(deps.dataDir, {
58202
+ sessionId: String(response.sessionId),
58203
+ tool: args.tool,
58204
+ ...args.label ? { label: args.label } : {},
58205
+ toolSessionId: args.toolSessionId,
58206
+ ...args.ownerPersonaId ? { ownerPersonaId: args.ownerPersonaId } : {}
58207
+ });
58208
+ }
57812
58209
  return { response: { type: "session:info", ...response }, broadcast };
57813
58210
  };
58211
+ const externalScan = async (frame, _client, ctx) => {
58212
+ if (ctx && ctx.principal.kind !== "owner") {
58213
+ throw new ClawdError(
58214
+ ERROR_CODES.UNAUTHORIZED,
58215
+ `principal ${ctx.principal.kind}:${ctx.principal.id} cannot session:externalScan`
58216
+ );
58217
+ }
58218
+ parseArgs2(SessionExternalScanArgs, frame, "session:externalScan args");
58219
+ const owned = manager.list().response.sessions;
58220
+ const linked = new Set(owned.map((f) => f.toolSessionId).filter(Boolean));
58221
+ const candidates = (await scanExternalSessions()).filter((c) => !linked.has(c.toolSessionId));
58222
+ return { response: { candidates } };
58223
+ };
57814
58224
  const list = async (frame, _client, ctx) => {
57815
58225
  const args = SessionListArgs.parse(frame ?? {});
57816
58226
  const narrow = (sessions) => {
@@ -58151,6 +58561,7 @@ function buildSessionHandlers(deps) {
58151
58561
  };
58152
58562
  return {
58153
58563
  "session:create": create,
58564
+ "session:externalScan": externalScan,
58154
58565
  "session:importExternal": importExternal,
58155
58566
  "session:list": list,
58156
58567
  "session:get": get,
@@ -58199,7 +58610,7 @@ function buildPermissionHandlers(deps) {
58199
58610
  }
58200
58611
 
58201
58612
  // src/handlers/history.ts
58202
- var path60 = __toESM(require("path"), 1);
58613
+ var path62 = __toESM(require("path"), 1);
58203
58614
  init_protocol();
58204
58615
 
58205
58616
  // src/session/recent-dirs.ts
@@ -58217,7 +58628,7 @@ function listRecentDirs(store, limit = 50) {
58217
58628
  }
58218
58629
 
58219
58630
  // src/permission/persona-paths.ts
58220
- var path59 = __toESM(require("path"), 1);
58631
+ var path61 = __toESM(require("path"), 1);
58221
58632
  function getAllowedPersonaIds(grants, action) {
58222
58633
  const ids = /* @__PURE__ */ new Set();
58223
58634
  for (const g2 of grants) {
@@ -58230,42 +58641,42 @@ function getAllowedPersonaIds(grants, action) {
58230
58641
  return ids;
58231
58642
  }
58232
58643
  function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
58233
- const target = path59.resolve(absPath);
58644
+ const target = path61.resolve(absPath);
58234
58645
  if (userWorkDir) {
58235
- const u = path59.resolve(userWorkDir);
58236
- const usep = u.endsWith(path59.sep) ? "" : path59.sep;
58646
+ const u = path61.resolve(userWorkDir);
58647
+ const usep = u.endsWith(path61.sep) ? "" : path61.sep;
58237
58648
  if (target === u || target.startsWith(u + usep)) return true;
58238
58649
  }
58239
- const root = path59.resolve(personaRoot);
58240
- const sep3 = root.endsWith(path59.sep) ? "" : path59.sep;
58650
+ const root = path61.resolve(personaRoot);
58651
+ const sep3 = root.endsWith(path61.sep) ? "" : path61.sep;
58241
58652
  if (!target.startsWith(root + sep3)) return false;
58242
- const rel = path59.relative(root, target);
58653
+ const rel = path61.relative(root, target);
58243
58654
  if (!rel || rel.startsWith("..")) return false;
58244
- const personaId2 = rel.split(path59.sep)[0];
58655
+ const personaId2 = rel.split(path61.sep)[0];
58245
58656
  if (!personaId2) return false;
58246
58657
  const allowed = getAllowedPersonaIds(grants, action);
58247
58658
  if (allowed === "*") return true;
58248
58659
  return allowed.has(personaId2);
58249
58660
  }
58250
58661
  function personaIdFromPath(absPath, personaRoot) {
58251
- const root = path59.resolve(personaRoot);
58252
- const target = path59.resolve(absPath);
58253
- const sep3 = root.endsWith(path59.sep) ? "" : path59.sep;
58662
+ const root = path61.resolve(personaRoot);
58663
+ const target = path61.resolve(absPath);
58664
+ const sep3 = root.endsWith(path61.sep) ? "" : path61.sep;
58254
58665
  if (!target.startsWith(root + sep3)) return null;
58255
- const rel = path59.relative(root, target);
58666
+ const rel = path61.relative(root, target);
58256
58667
  if (!rel || rel.startsWith("..")) return null;
58257
- const id = rel.split(path59.sep)[0];
58668
+ const id = rel.split(path61.sep)[0];
58258
58669
  return id || null;
58259
58670
  }
58260
58671
  function isPathWithin(dir, absPath) {
58261
- const d = path59.resolve(dir);
58262
- const t = path59.resolve(absPath);
58263
- const sep3 = d.endsWith(path59.sep) ? "" : path59.sep;
58672
+ const d = path61.resolve(dir);
58673
+ const t = path61.resolve(absPath);
58674
+ const sep3 = d.endsWith(path61.sep) ? "" : path61.sep;
58264
58675
  return t === d || t.startsWith(d + sep3);
58265
58676
  }
58266
58677
  function isPathInGuestBoundary(personaRoot, personaId2, userWorkDir, absPath) {
58267
58678
  if (userWorkDir && isPathWithin(userWorkDir, absPath)) return true;
58268
- return personaIdFromPath(path59.resolve(absPath), personaRoot) === personaId2;
58679
+ return personaIdFromPath(path61.resolve(absPath), personaRoot) === personaId2;
58269
58680
  }
58270
58681
 
58271
58682
  // src/handlers/history.ts
@@ -58317,7 +58728,7 @@ function buildHistoryHandlers(deps) {
58317
58728
  if (!pid) return false;
58318
58729
  return isGuestPathAllowed(
58319
58730
  ctx.grants,
58320
- path60.join(personaRoot, pid),
58731
+ path62.join(personaRoot, pid),
58321
58732
  personaRoot,
58322
58733
  "read",
58323
58734
  userWorkDir
@@ -58329,7 +58740,7 @@ function buildHistoryHandlers(deps) {
58329
58740
  };
58330
58741
  const list = async (frame, _client, ctx) => {
58331
58742
  const args = HistoryListArgs.parse(frame);
58332
- assertGuestPath(ctx, path60.resolve(args.projectPath), personaRoot, "history:list", usersRoot);
58743
+ assertGuestPath(ctx, path62.resolve(args.projectPath), personaRoot, "history:list", usersRoot);
58333
58744
  const sessions = await history.listSessions(args);
58334
58745
  return { response: { type: "history:list", sessions } };
58335
58746
  };
@@ -58373,14 +58784,14 @@ function buildHistoryHandlers(deps) {
58373
58784
  };
58374
58785
  const subagents = async (frame, _client, ctx) => {
58375
58786
  const args = HistorySubagentsArgs.parse(frame);
58376
- assertGuestPath(ctx, path60.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
58787
+ assertGuestPath(ctx, path62.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
58377
58788
  assertGuestOwnsToolSession(ctx, args.toolSessionId, "history:subagents");
58378
58789
  const subs = await history.listSubagents(args);
58379
58790
  return { response: { type: "history:subagents", subagents: subs } };
58380
58791
  };
58381
58792
  const subagentRead = async (frame, _client, ctx) => {
58382
58793
  const args = HistorySubagentReadArgs.parse(frame);
58383
- assertGuestPath(ctx, path60.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
58794
+ assertGuestPath(ctx, path62.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
58384
58795
  assertGuestOwnsToolSession(ctx, args.toolSessionId, "history:subagent-read");
58385
58796
  const res = await history.readSubagent(args);
58386
58797
  return { response: { type: "history:subagent-read", ...res } };
@@ -58390,7 +58801,7 @@ function buildHistoryHandlers(deps) {
58390
58801
  if (ctx?.principal.kind === "guest" && personaRoot) {
58391
58802
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
58392
58803
  const filtered = dirs.filter(
58393
- (d) => isGuestPathAllowed(ctx.grants, path60.resolve(d.cwd), personaRoot, "read", userWorkDir)
58804
+ (d) => isGuestPathAllowed(ctx.grants, path62.resolve(d.cwd), personaRoot, "read", userWorkDir)
58394
58805
  );
58395
58806
  return { response: { type: "history:recentDirs", dirs: filtered } };
58396
58807
  }
@@ -58407,8 +58818,8 @@ function buildHistoryHandlers(deps) {
58407
58818
  }
58408
58819
 
58409
58820
  // src/handlers/workspace.ts
58410
- var path61 = __toESM(require("path"), 1);
58411
- var os16 = __toESM(require("os"), 1);
58821
+ var path63 = __toESM(require("path"), 1);
58822
+ var os17 = __toESM(require("os"), 1);
58412
58823
  init_protocol();
58413
58824
  init_protocol();
58414
58825
  function buildEnabledPluginNames(personaManager, personaId2) {
@@ -58448,23 +58859,23 @@ function buildWorkspaceHandlers(deps) {
58448
58859
  const list = async (frame, _client, ctx) => {
58449
58860
  const args = WorkspaceListArgs.parse(frame);
58450
58861
  const isGuest = ctx?.principal.kind === "guest";
58451
- const fallbackCwd = isGuest && personaRoot ? personaRoot : os16.homedir();
58452
- const resolvedCwd = path61.resolve(args.cwd ?? fallbackCwd);
58453
- const target = args.path ? path61.resolve(resolvedCwd, args.path) : resolvedCwd;
58862
+ const fallbackCwd = isGuest && personaRoot ? personaRoot : os17.homedir();
58863
+ const resolvedCwd = path63.resolve(args.cwd ?? fallbackCwd);
58864
+ const target = args.path ? path63.resolve(resolvedCwd, args.path) : resolvedCwd;
58454
58865
  assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
58455
58866
  const res = workspace.list({ ...args, cwd: resolvedCwd });
58456
58867
  return { response: { type: "workspace:list", ...res } };
58457
58868
  };
58458
58869
  const read = async (frame, _client, ctx) => {
58459
58870
  const args = WorkspaceReadArgs.parse(frame);
58460
- const target = path61.isAbsolute(args.path) ? path61.resolve(args.path) : path61.resolve(args.cwd, args.path);
58871
+ const target = path63.isAbsolute(args.path) ? path63.resolve(args.path) : path63.resolve(args.cwd, args.path);
58461
58872
  assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
58462
58873
  const res = workspace.read(args);
58463
58874
  return { response: { type: "workspace:read", ...res } };
58464
58875
  };
58465
58876
  const skillsList = async (frame, _client, ctx) => {
58466
58877
  const args = SkillsListArgs.parse(frame);
58467
- const cwdAbs = path61.resolve(args.cwd);
58878
+ const cwdAbs = path63.resolve(args.cwd);
58468
58879
  assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
58469
58880
  const list2 = await getSkillsForTool(args.tool ?? "claude", cwdAbs);
58470
58881
  if (ctx?.principal.kind === "guest" && personaRoot) {
@@ -58476,7 +58887,7 @@ function buildWorkspaceHandlers(deps) {
58476
58887
  };
58477
58888
  const agentsList = async (frame, _client, ctx) => {
58478
58889
  const args = AgentsListArgs.parse(frame);
58479
- const cwdAbs = path61.resolve(args.cwd);
58890
+ const cwdAbs = path63.resolve(args.cwd);
58480
58891
  assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
58481
58892
  if (args.tool === "codex") {
58482
58893
  return { response: { type: "agents:list", agents: [] } };
@@ -58498,20 +58909,20 @@ function buildWorkspaceHandlers(deps) {
58498
58909
  }
58499
58910
 
58500
58911
  // src/handlers/git.ts
58501
- var path63 = __toESM(require("path"), 1);
58912
+ var path65 = __toESM(require("path"), 1);
58502
58913
  init_protocol();
58503
58914
  init_protocol();
58504
58915
 
58505
58916
  // src/workspace/git.ts
58506
- var import_node_child_process11 = require("child_process");
58507
- var import_node_fs45 = __toESM(require("fs"), 1);
58508
- var import_node_path50 = __toESM(require("path"), 1);
58917
+ var import_node_child_process12 = require("child_process");
58918
+ var import_node_fs47 = __toESM(require("fs"), 1);
58919
+ var import_node_path52 = __toESM(require("path"), 1);
58509
58920
  var import_node_util = require("util");
58510
- var pexec = (0, import_node_util.promisify)(import_node_child_process11.execFile);
58921
+ var pexec = (0, import_node_util.promisify)(import_node_child_process12.execFile);
58511
58922
  function normalizePath(p2) {
58512
- const resolved = import_node_path50.default.resolve(p2);
58923
+ const resolved = import_node_path52.default.resolve(p2);
58513
58924
  try {
58514
- return import_node_fs45.default.realpathSync(resolved);
58925
+ return import_node_fs47.default.realpathSync(resolved);
58515
58926
  } catch {
58516
58927
  return resolved;
58517
58928
  }
@@ -58585,7 +58996,7 @@ async function listGitBranches(cwd) {
58585
58996
  function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
58586
58997
  if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
58587
58998
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
58588
- if (!isGuestPathAllowed(ctx.grants, path63.resolve(cwd), personaRoot, "read", userWorkDir)) {
58999
+ if (!isGuestPathAllowed(ctx.grants, path65.resolve(cwd), personaRoot, "read", userWorkDir)) {
58589
59000
  throw new ClawdError(
58590
59001
  ERROR_CODES.UNAUTHORIZED,
58591
59002
  `guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
@@ -59207,7 +59618,7 @@ function buildDeviceHandlers(deps) {
59207
59618
  }
59208
59619
 
59209
59620
  // src/handlers/meta.ts
59210
- var import_node_os17 = __toESM(require("os"), 1);
59621
+ var import_node_os18 = __toESM(require("os"), 1);
59211
59622
  init_protocol();
59212
59623
 
59213
59624
  // src/handlers/method-grants.ts
@@ -59331,6 +59742,11 @@ var METHOD_GRANT_MAP = {
59331
59742
  "larkBot:bindManual": ADMIN_ANY,
59332
59743
  "larkBot:unbind": ADMIN_ANY,
59333
59744
  "larkBot:status": ADMIN_ANY,
59745
+ // ---- onboarding:* / tools:probe / session:externalScan(首启 wizard,owner-only)----
59746
+ "onboarding:complete": ADMIN_ANY,
59747
+ "onboarding:iosInterest": ADMIN_ANY,
59748
+ "tools:probe": ADMIN_ANY,
59749
+ "session:externalScan": ADMIN_ANY,
59334
59750
  "inbox:sendDm": ADMIN_ANY,
59335
59751
  "personaDispatch:complete": ADMIN_ANY,
59336
59752
  "personaDispatch:list": ADMIN_ANY,
@@ -59462,21 +59878,21 @@ function computeMethodAccess(args) {
59462
59878
  }
59463
59879
 
59464
59880
  // src/version.ts
59465
- var version = "0.2.321".length > 0 ? "0.2.321" : "dev";
59881
+ var version = "0.2.322".length > 0 ? "0.2.322" : "dev";
59466
59882
 
59467
59883
  // src/cli-probe/probe.ts
59468
- var fs56 = __toESM(require("fs"), 1);
59469
- var path64 = __toESM(require("path"), 1);
59884
+ var fs58 = __toESM(require("fs"), 1);
59885
+ var path66 = __toESM(require("path"), 1);
59470
59886
  var PKG_NAME = "@clawos-dev/clawd";
59471
59887
  var BIN_NAME = "clawd";
59472
59888
  var MAX_PARENT_HOPS = 5;
59473
59889
  function probeGlobalCli(pathEnv) {
59474
59890
  if (!pathEnv) return null;
59475
- for (const dir of pathEnv.split(path64.delimiter)) {
59891
+ for (const dir of pathEnv.split(path66.delimiter)) {
59476
59892
  if (!dir) continue;
59477
59893
  let real;
59478
59894
  try {
59479
- real = fs56.realpathSync(path64.join(dir, BIN_NAME));
59895
+ real = fs58.realpathSync(path66.join(dir, BIN_NAME));
59480
59896
  } catch {
59481
59897
  continue;
59482
59898
  }
@@ -59486,15 +59902,15 @@ function probeGlobalCli(pathEnv) {
59486
59902
  return null;
59487
59903
  }
59488
59904
  function readOwnPackageVersion(entryPath) {
59489
- let dir = path64.dirname(entryPath);
59905
+ let dir = path66.dirname(entryPath);
59490
59906
  for (let i = 0; i < MAX_PARENT_HOPS; i++) {
59491
59907
  try {
59492
- const raw = fs56.readFileSync(path64.join(dir, "package.json"), "utf8");
59908
+ const raw = fs58.readFileSync(path66.join(dir, "package.json"), "utf8");
59493
59909
  const pkg = JSON.parse(raw);
59494
59910
  if (pkg.name !== PKG_NAME) return null;
59495
59911
  return typeof pkg.version === "string" && pkg.version ? pkg.version : null;
59496
59912
  } catch {
59497
- const parent = path64.dirname(dir);
59913
+ const parent = path66.dirname(dir);
59498
59914
  if (parent === dir) return null;
59499
59915
  dir = parent;
59500
59916
  }
@@ -59526,10 +59942,11 @@ function buildReadyFrame(deps, client) {
59526
59942
  const daemonSource = process.env.CLAWD_DAEMON_SOURCE === "ota" ? "ota" : "packaged";
59527
59943
  const globalCliVersion = probeGlobalCli(process.env.PATH);
59528
59944
  const logShipping = deps.getLogShipping ? deps.getLogShipping() : null;
59945
+ const onboardingCompletedAt = deps.dataDir && client?.principalKind !== "guest" ? loadOwnerProfile(deps.dataDir).onboardingCompletedAt ?? null : void 0;
59529
59946
  return {
59530
59947
  version,
59531
59948
  protocolVersion: PROTOCOL_VERSION,
59532
- hostname: import_node_os17.default.hostname(),
59949
+ hostname: import_node_os18.default.hostname(),
59533
59950
  os: process.platform,
59534
59951
  tools,
59535
59952
  runningSessions: info.runningSessions,
@@ -59538,7 +59955,8 @@ function buildReadyFrame(deps, client) {
59538
59955
  daemonSource,
59539
59956
  globalCliVersion,
59540
59957
  ...fileSharing,
59541
- ...logShipping ? { logShipping } : {}
59958
+ ...logShipping ? { logShipping } : {},
59959
+ ...onboardingCompletedAt !== void 0 ? { onboardingCompletedAt } : {}
59542
59960
  };
59543
59961
  }
59544
59962
  function buildMetaHandlers(deps) {
@@ -59652,7 +60070,7 @@ function buildPersonaHandlers(deps) {
59652
60070
  }
59653
60071
 
59654
60072
  // src/handlers/attachment.ts
59655
- var import_node_path51 = __toESM(require("path"), 1);
60073
+ var import_node_path53 = __toESM(require("path"), 1);
59656
60074
  init_protocol();
59657
60075
  init_protocol();
59658
60076
  var DEFAULT_TTL_SECONDS = 24 * 3600;
@@ -59732,12 +60150,12 @@ function buildAttachmentHandlers(deps) {
59732
60150
  `session ${args.sessionId} scope unresolved`
59733
60151
  );
59734
60152
  }
59735
- const cwdAbs = import_node_path51.default.resolve(sessionFile.cwd);
59736
- const candidateAbs = import_node_path51.default.isAbsolute(args.relPath) ? import_node_path51.default.resolve(args.relPath) : import_node_path51.default.resolve(cwdAbs, args.relPath);
60153
+ const cwdAbs = import_node_path53.default.resolve(sessionFile.cwd);
60154
+ const candidateAbs = import_node_path53.default.isAbsolute(args.relPath) ? import_node_path53.default.resolve(args.relPath) : import_node_path53.default.resolve(cwdAbs, args.relPath);
59737
60155
  guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.signUrl", "group-acl");
59738
60156
  const entries = deps.groupFileStore.list(scope, args.sessionId);
59739
60157
  const entry = entries.find((e) => {
59740
- const storedAbs = import_node_path51.default.isAbsolute(e.relPath) ? import_node_path51.default.resolve(e.relPath) : import_node_path51.default.resolve(cwdAbs, e.relPath);
60158
+ const storedAbs = import_node_path53.default.isAbsolute(e.relPath) ? import_node_path53.default.resolve(e.relPath) : import_node_path53.default.resolve(cwdAbs, e.relPath);
59741
60159
  return storedAbs === candidateAbs && !e.stale;
59742
60160
  });
59743
60161
  if (!entry) {
@@ -59762,7 +60180,7 @@ function buildAttachmentHandlers(deps) {
59762
60180
  if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
59763
60181
  const f = deps.sessionStore.read(sessionId);
59764
60182
  if (!f) return;
59765
- assertGuestAttachmentPath(ctx, import_node_path51.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
60183
+ assertGuestAttachmentPath(ctx, import_node_path53.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
59766
60184
  }
59767
60185
  const groupAdd = async (frame, _client, ctx) => {
59768
60186
  if (!deps.groupFileStore || !deps.getSessionScope) {
@@ -59777,8 +60195,8 @@ function buildAttachmentHandlers(deps) {
59777
60195
  if (!scope) {
59778
60196
  throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, `session ${args.sessionId} not found`);
59779
60197
  }
59780
- const cwdAbs = import_node_path51.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
59781
- const candidateAbs = import_node_path51.default.isAbsolute(args.relPath) ? import_node_path51.default.resolve(args.relPath) : import_node_path51.default.resolve(cwdAbs, args.relPath);
60198
+ const cwdAbs = import_node_path53.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
60199
+ const candidateAbs = import_node_path53.default.isAbsolute(args.relPath) ? import_node_path53.default.resolve(args.relPath) : import_node_path53.default.resolve(cwdAbs, args.relPath);
59782
60200
  guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.groupAdd", "cwd-subtree");
59783
60201
  const from = args.origin === "agent" ? "agent" : ctx?.principal.kind === "owner" ? "owner" : "agent";
59784
60202
  const size = 0;
@@ -59836,21 +60254,21 @@ function buildAttachmentHandlers(deps) {
59836
60254
  }
59837
60255
 
59838
60256
  // src/handlers/extension.ts
59839
- var import_promises9 = __toESM(require("fs/promises"), 1);
59840
- var import_node_path56 = __toESM(require("path"), 1);
60257
+ var import_promises10 = __toESM(require("fs/promises"), 1);
60258
+ var import_node_path58 = __toESM(require("path"), 1);
59841
60259
  init_protocol();
59842
60260
 
59843
60261
  // src/extension/bundle-zip.ts
59844
- var import_promises6 = __toESM(require("fs/promises"), 1);
59845
- var import_node_path52 = __toESM(require("path"), 1);
60262
+ var import_promises7 = __toESM(require("fs/promises"), 1);
60263
+ var import_node_path54 = __toESM(require("path"), 1);
59846
60264
  var import_node_crypto14 = __toESM(require("crypto"), 1);
59847
60265
  var import_jszip2 = __toESM(require_lib3(), 1);
59848
60266
  async function bundleExtensionDir(dir) {
59849
60267
  const entries = await listFilesSorted(dir);
59850
60268
  const zip = new import_jszip2.default();
59851
60269
  for (const rel of entries) {
59852
- const abs = import_node_path52.default.join(dir, rel);
59853
- const content = await import_promises6.default.readFile(abs);
60270
+ const abs = import_node_path54.default.join(dir, rel);
60271
+ const content = await import_promises7.default.readFile(abs);
59854
60272
  zip.file(rel, content, { date: FIXED_DATE });
59855
60273
  }
59856
60274
  const buffer = await zip.generateAsync({
@@ -59870,8 +60288,8 @@ async function listFilesSorted(rootDir) {
59870
60288
  return out;
59871
60289
  }
59872
60290
  async function walk(absRoot, relPrefix, out) {
59873
- const dirAbs = import_node_path52.default.join(absRoot, relPrefix);
59874
- const entries = await import_promises6.default.readdir(dirAbs, { withFileTypes: true });
60291
+ const dirAbs = import_node_path54.default.join(absRoot, relPrefix);
60292
+ const entries = await import_promises7.default.readdir(dirAbs, { withFileTypes: true });
59875
60293
  for (const e of entries) {
59876
60294
  if (IGNORE_BASENAMES.has(e.name)) continue;
59877
60295
  const rel = relPrefix ? `${relPrefix}/${e.name}` : e.name;
@@ -59923,26 +60341,26 @@ function computePublishCheck(args) {
59923
60341
  }
59924
60342
 
59925
60343
  // src/extension/install-flow.ts
59926
- var import_promises7 = __toESM(require("fs/promises"), 1);
59927
- var import_node_path54 = __toESM(require("path"), 1);
59928
- var import_node_os19 = __toESM(require("os"), 1);
60344
+ var import_promises8 = __toESM(require("fs/promises"), 1);
60345
+ var import_node_path56 = __toESM(require("path"), 1);
60346
+ var import_node_os20 = __toESM(require("os"), 1);
59929
60347
  var import_node_crypto15 = __toESM(require("crypto"), 1);
59930
60348
  var import_jszip3 = __toESM(require_lib3(), 1);
59931
60349
 
59932
60350
  // src/extension/paths.ts
59933
- var import_node_os18 = __toESM(require("os"), 1);
59934
- var import_node_path53 = __toESM(require("path"), 1);
60351
+ var import_node_os19 = __toESM(require("os"), 1);
60352
+ var import_node_path55 = __toESM(require("path"), 1);
59935
60353
  function clawdHomeRoot(override) {
59936
- return override ?? process.env.CLAWD_HOME ?? import_node_path53.default.join(import_node_os18.default.homedir(), ".clawd");
60354
+ return override ?? process.env.CLAWD_HOME ?? import_node_path55.default.join(import_node_os19.default.homedir(), ".clawd");
59937
60355
  }
59938
60356
  function extensionsRoot(override) {
59939
- return import_node_path53.default.join(clawdHomeRoot(override), "extensions");
60357
+ return import_node_path55.default.join(clawdHomeRoot(override), "extensions");
59940
60358
  }
59941
60359
  function publishedChannelsFile(override) {
59942
- return import_node_path53.default.join(clawdHomeRoot(override), "extensions-published.json");
60360
+ return import_node_path55.default.join(clawdHomeRoot(override), "extensions-published.json");
59943
60361
  }
59944
60362
  function bundleCacheRoot(override) {
59945
- return import_node_path53.default.join(clawdHomeRoot(override), "extension-bundles");
60363
+ return import_node_path55.default.join(clawdHomeRoot(override), "extension-bundles");
59946
60364
  }
59947
60365
 
59948
60366
  // src/extension/install-flow.ts
@@ -59969,7 +60387,7 @@ async function installFromChannel(args, deps) {
59969
60387
  throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
59970
60388
  }
59971
60389
  for (const name of Object.keys(zip.files)) {
59972
- if (name.includes("..") || name.startsWith("/") || import_node_path54.default.isAbsolute(name)) {
60390
+ if (name.includes("..") || name.startsWith("/") || import_node_path56.default.isAbsolute(name)) {
59973
60391
  throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
59974
60392
  }
59975
60393
  }
@@ -60001,10 +60419,10 @@ async function installFromChannel(args, deps) {
60001
60419
  );
60002
60420
  }
60003
60421
  const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
60004
- const destDir = import_node_path54.default.join(deps.extensionsRoot, localExtId);
60422
+ const destDir = import_node_path56.default.join(deps.extensionsRoot, localExtId);
60005
60423
  let destExists = false;
60006
60424
  try {
60007
- await import_promises7.default.access(destDir);
60425
+ await import_promises8.default.access(destDir);
60008
60426
  destExists = true;
60009
60427
  } catch {
60010
60428
  }
@@ -60014,28 +60432,28 @@ async function installFromChannel(args, deps) {
60014
60432
  `extension ${localExtId} already installed locally (from owner ${channelRef.ownerPrincipalId})`
60015
60433
  );
60016
60434
  }
60017
- const stage = await import_promises7.default.mkdtemp(
60018
- import_node_path54.default.join(import_node_os19.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
60435
+ const stage = await import_promises8.default.mkdtemp(
60436
+ import_node_path56.default.join(import_node_os20.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
60019
60437
  );
60020
60438
  try {
60021
60439
  for (const [name, entry] of Object.entries(zip.files)) {
60022
- const dest = import_node_path54.default.join(stage, name);
60440
+ const dest = import_node_path56.default.join(stage, name);
60023
60441
  if (entry.dir) {
60024
- await import_promises7.default.mkdir(dest, { recursive: true });
60442
+ await import_promises8.default.mkdir(dest, { recursive: true });
60025
60443
  continue;
60026
60444
  }
60027
- await import_promises7.default.mkdir(import_node_path54.default.dirname(dest), { recursive: true });
60445
+ await import_promises8.default.mkdir(import_node_path56.default.dirname(dest), { recursive: true });
60028
60446
  if (name === "manifest.json") {
60029
60447
  const rewritten = { ...parsed.data, id: localExtId };
60030
- await import_promises7.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
60448
+ await import_promises8.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
60031
60449
  } else {
60032
- await import_promises7.default.writeFile(dest, await entry.async("nodebuffer"));
60450
+ await import_promises8.default.writeFile(dest, await entry.async("nodebuffer"));
60033
60451
  }
60034
60452
  }
60035
- await import_promises7.default.mkdir(deps.extensionsRoot, { recursive: true });
60036
- await import_promises7.default.rename(stage, destDir);
60453
+ await import_promises8.default.mkdir(deps.extensionsRoot, { recursive: true });
60454
+ await import_promises8.default.rename(stage, destDir);
60037
60455
  } catch (e) {
60038
- await import_promises7.default.rm(stage, { recursive: true, force: true }).catch(() => {
60456
+ await import_promises8.default.rm(stage, { recursive: true, force: true }).catch(() => {
60039
60457
  });
60040
60458
  throw e;
60041
60459
  }
@@ -60044,9 +60462,9 @@ async function installFromChannel(args, deps) {
60044
60462
  }
60045
60463
 
60046
60464
  // src/extension/update-flow.ts
60047
- var import_promises8 = __toESM(require("fs/promises"), 1);
60048
- var import_node_path55 = __toESM(require("path"), 1);
60049
- var import_node_os20 = __toESM(require("os"), 1);
60465
+ var import_promises9 = __toESM(require("fs/promises"), 1);
60466
+ var import_node_path57 = __toESM(require("path"), 1);
60467
+ var import_node_os21 = __toESM(require("os"), 1);
60050
60468
  var import_node_crypto16 = __toESM(require("crypto"), 1);
60051
60469
  var import_jszip4 = __toESM(require_lib3(), 1);
60052
60470
  var UpdateError = class extends Error {
@@ -60062,11 +60480,11 @@ async function updateFromChannel(args, deps) {
60062
60480
  channelRef.extId,
60063
60481
  channelRef.ownerPrincipalId
60064
60482
  );
60065
- const liveDir = import_node_path55.default.join(deps.extensionsRoot, localExtId);
60483
+ const liveDir = import_node_path57.default.join(deps.extensionsRoot, localExtId);
60066
60484
  const prevDir = `${liveDir}.prev`;
60067
60485
  let existingVersion;
60068
60486
  try {
60069
- const raw = await import_promises8.default.readFile(import_node_path55.default.join(liveDir, "manifest.json"), "utf8");
60487
+ const raw = await import_promises9.default.readFile(import_node_path57.default.join(liveDir, "manifest.json"), "utf8");
60070
60488
  const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
60071
60489
  if (!parsed2.success) {
60072
60490
  throw new UpdateError(
@@ -60099,7 +60517,7 @@ async function updateFromChannel(args, deps) {
60099
60517
  throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
60100
60518
  }
60101
60519
  for (const name of Object.keys(zip.files)) {
60102
- if (name.includes("..") || name.startsWith("/") || import_node_path55.default.isAbsolute(name)) {
60520
+ if (name.includes("..") || name.startsWith("/") || import_node_path57.default.isAbsolute(name)) {
60103
60521
  throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
60104
60522
  }
60105
60523
  }
@@ -60131,31 +60549,31 @@ async function updateFromChannel(args, deps) {
60131
60549
  );
60132
60550
  }
60133
60551
  await deps.runtime.close(localExtId);
60134
- await import_promises8.default.rm(prevDir, { recursive: true, force: true });
60135
- await import_promises8.default.rename(liveDir, prevDir);
60136
- const stage = await import_promises8.default.mkdtemp(
60137
- import_node_path55.default.join(import_node_os20.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
60552
+ await import_promises9.default.rm(prevDir, { recursive: true, force: true });
60553
+ await import_promises9.default.rename(liveDir, prevDir);
60554
+ const stage = await import_promises9.default.mkdtemp(
60555
+ import_node_path57.default.join(import_node_os21.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
60138
60556
  );
60139
60557
  try {
60140
60558
  for (const [name, entry] of Object.entries(zip.files)) {
60141
- const dest = import_node_path55.default.join(stage, name);
60559
+ const dest = import_node_path57.default.join(stage, name);
60142
60560
  if (entry.dir) {
60143
- await import_promises8.default.mkdir(dest, { recursive: true });
60561
+ await import_promises9.default.mkdir(dest, { recursive: true });
60144
60562
  continue;
60145
60563
  }
60146
- await import_promises8.default.mkdir(import_node_path55.default.dirname(dest), { recursive: true });
60564
+ await import_promises9.default.mkdir(import_node_path57.default.dirname(dest), { recursive: true });
60147
60565
  if (name === "manifest.json") {
60148
60566
  const rewritten = { ...parsed.data, id: localExtId };
60149
- await import_promises8.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
60567
+ await import_promises9.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
60150
60568
  } else {
60151
- await import_promises8.default.writeFile(dest, await entry.async("nodebuffer"));
60569
+ await import_promises9.default.writeFile(dest, await entry.async("nodebuffer"));
60152
60570
  }
60153
60571
  }
60154
- await import_promises8.default.rename(stage, liveDir);
60572
+ await import_promises9.default.rename(stage, liveDir);
60155
60573
  } catch (e) {
60156
- await import_promises8.default.rm(stage, { recursive: true, force: true }).catch(() => {
60574
+ await import_promises9.default.rm(stage, { recursive: true, force: true }).catch(() => {
60157
60575
  });
60158
- await import_promises8.default.rename(prevDir, liveDir).catch(() => {
60576
+ await import_promises9.default.rename(prevDir, liveDir).catch(() => {
60159
60577
  });
60160
60578
  await deps.runtime.open(localExtId).catch(() => {
60161
60579
  });
@@ -60177,7 +60595,7 @@ async function updateFromChannel(args, deps) {
60177
60595
  reason: e.message
60178
60596
  };
60179
60597
  }
60180
- await import_promises8.default.rm(prevDir, { recursive: true, force: true });
60598
+ await import_promises9.default.rm(prevDir, { recursive: true, force: true });
60181
60599
  return {
60182
60600
  kind: "updated",
60183
60601
  extId: localExtId,
@@ -60185,9 +60603,9 @@ async function updateFromChannel(args, deps) {
60185
60603
  };
60186
60604
  }
60187
60605
  async function rollback(deps, localExtId, liveDir, prevDir) {
60188
- await import_promises8.default.rm(liveDir, { recursive: true, force: true }).catch(() => {
60606
+ await import_promises9.default.rm(liveDir, { recursive: true, force: true }).catch(() => {
60189
60607
  });
60190
- await import_promises8.default.rename(prevDir, liveDir).catch(() => {
60608
+ await import_promises9.default.rename(prevDir, liveDir).catch(() => {
60191
60609
  });
60192
60610
  await deps.runtime.open(localExtId).catch(() => {
60193
60611
  });
@@ -60210,18 +60628,18 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
60210
60628
  );
60211
60629
  }
60212
60630
  }
60213
- const manifestPath = import_node_path56.default.join(root, extId, "manifest.json");
60631
+ const manifestPath = import_node_path58.default.join(root, extId, "manifest.json");
60214
60632
  const manifest = await readManifest(root, extId);
60215
60633
  const next = { ...manifest, version: newVersion };
60216
60634
  const tmp = `${manifestPath}.tmp`;
60217
- await import_promises9.default.writeFile(tmp, JSON.stringify(next, null, 2));
60218
- await import_promises9.default.rename(tmp, manifestPath);
60635
+ await import_promises10.default.writeFile(tmp, JSON.stringify(next, null, 2));
60636
+ await import_promises10.default.rename(tmp, manifestPath);
60219
60637
  }
60220
60638
  async function readManifest(root, extId) {
60221
- const file = import_node_path56.default.join(root, extId, "manifest.json");
60639
+ const file = import_node_path58.default.join(root, extId, "manifest.json");
60222
60640
  let raw;
60223
60641
  try {
60224
- raw = await import_promises9.default.readFile(file, "utf8");
60642
+ raw = await import_promises10.default.readFile(file, "utf8");
60225
60643
  } catch (e) {
60226
60644
  if (e.code === "ENOENT") {
60227
60645
  throw new ClawdError(ERROR_CODES.INVALID_PARAM, `extension ${extId} not installed`);
@@ -60302,7 +60720,7 @@ function buildExtensionHandlers(deps) {
60302
60720
  };
60303
60721
  async function buildSnapshotMeta(extId) {
60304
60722
  const manifest = await readManifest(deps.root, extId);
60305
- const { sha256, buffer } = await bundleExtensionDir(import_node_path56.default.join(deps.root, extId));
60723
+ const { sha256, buffer } = await bundleExtensionDir(import_node_path58.default.join(deps.root, extId));
60306
60724
  return { manifest, contentHash: sha256, buffer };
60307
60725
  }
60308
60726
  const publish = async (frame, _client, ctx) => {
@@ -60477,9 +60895,9 @@ function buildExtensionHandlers(deps) {
60477
60895
  }
60478
60896
 
60479
60897
  // src/app-builder/project-store.ts
60480
- var import_node_fs46 = require("fs");
60481
- var import_node_child_process12 = require("child_process");
60482
- var import_node_path57 = require("path");
60898
+ var import_node_fs48 = require("fs");
60899
+ var import_node_child_process13 = require("child_process");
60900
+ var import_node_path59 = require("path");
60483
60901
  init_protocol();
60484
60902
  var PROJECTS_DIR = "projects";
60485
60903
  var META_FILE = ".clawd-project.json";
@@ -60493,19 +60911,19 @@ var ProjectStore = class {
60493
60911
  root;
60494
60912
  /** projects/<name>/.clawd-project.json 路径 */
60495
60913
  metaPath(name) {
60496
- return (0, import_node_path57.join)(this.projectsRoot(), name, META_FILE);
60914
+ return (0, import_node_path59.join)(this.projectsRoot(), name, META_FILE);
60497
60915
  }
60498
60916
  /** projects/<name>/ 目录路径(cwd 用) */
60499
60917
  projectDir(name) {
60500
- return (0, import_node_path57.join)(this.projectsRoot(), name);
60918
+ return (0, import_node_path59.join)(this.projectsRoot(), name);
60501
60919
  }
60502
60920
  projectsRoot() {
60503
- return (0, import_node_path57.join)(this.root, PROJECTS_DIR);
60921
+ return (0, import_node_path59.join)(this.root, PROJECTS_DIR);
60504
60922
  }
60505
60923
  async list() {
60506
60924
  let entries;
60507
60925
  try {
60508
- entries = await import_node_fs46.promises.readdir(this.projectsRoot());
60926
+ entries = await import_node_fs48.promises.readdir(this.projectsRoot());
60509
60927
  } catch (err) {
60510
60928
  if (err.code === "ENOENT") return [];
60511
60929
  throw err;
@@ -60513,7 +60931,7 @@ var ProjectStore = class {
60513
60931
  const out = [];
60514
60932
  for (const name of entries) {
60515
60933
  try {
60516
- const raw = await import_node_fs46.promises.readFile(this.metaPath(name), "utf8");
60934
+ const raw = await import_node_fs48.promises.readFile(this.metaPath(name), "utf8");
60517
60935
  const json = JSON.parse(raw);
60518
60936
  let migrated = false;
60519
60937
  if (typeof json.devCommand !== "string" || json.devCommand.length === 0) {
@@ -60524,7 +60942,7 @@ var ProjectStore = class {
60524
60942
  if (parsed.success) {
60525
60943
  out.push(parsed.data);
60526
60944
  if (migrated) {
60527
- void import_node_fs46.promises.writeFile(this.metaPath(name), JSON.stringify(parsed.data, null, 2) + "\n", "utf8").catch(() => {
60945
+ void import_node_fs48.promises.writeFile(this.metaPath(name), JSON.stringify(parsed.data, null, 2) + "\n", "utf8").catch(() => {
60528
60946
  });
60529
60947
  }
60530
60948
  }
@@ -60568,8 +60986,8 @@ var ProjectStore = class {
60568
60986
  throw new Error(`invalid name "${name}": ${validated.error.message}`);
60569
60987
  }
60570
60988
  const dir = this.projectDir(name);
60571
- await import_node_fs46.promises.mkdir(dir, { recursive: true });
60572
- await import_node_fs46.promises.writeFile(this.metaPath(name), JSON.stringify(meta, null, 2) + "\n", "utf8");
60989
+ await import_node_fs48.promises.mkdir(dir, { recursive: true });
60990
+ await import_node_fs48.promises.writeFile(this.metaPath(name), JSON.stringify(meta, null, 2) + "\n", "utf8");
60573
60991
  return meta;
60574
60992
  }
60575
60993
  /**
@@ -60583,7 +61001,7 @@ var ProjectStore = class {
60583
61001
  async scaffold(name, templateSrcDir, scaffoldScriptPath) {
60584
61002
  const destDir = this.projectDir(name);
60585
61003
  return await new Promise((resolve6, reject) => {
60586
- const child = (0, import_node_child_process12.spawn)("bash", [scaffoldScriptPath, name, templateSrcDir, destDir], {
61004
+ const child = (0, import_node_child_process13.spawn)("bash", [scaffoldScriptPath, name, templateSrcDir, destDir], {
60587
61005
  env: { ...process.env, PATH: process.env.PATH ?? "" },
60588
61006
  stdio: ["ignore", "pipe", "pipe"]
60589
61007
  });
@@ -60612,7 +61030,7 @@ var ProjectStore = class {
60612
61030
  }
60613
61031
  async delete(name) {
60614
61032
  const dir = this.projectDir(name);
60615
- await import_node_fs46.promises.rm(dir, { recursive: true, force: true });
61033
+ await import_node_fs48.promises.rm(dir, { recursive: true, force: true });
60616
61034
  }
60617
61035
  async updatePort(name, newPort) {
60618
61036
  if (newPort < PROJECT_PORT_MIN || newPort > PROJECT_PORT_MAX) {
@@ -60628,7 +61046,7 @@ var ProjectStore = class {
60628
61046
  throw new Error(`port ${newPort} already used / \u5DF2\u88AB project "${conflict.name}" \u5360\u7528`);
60629
61047
  }
60630
61048
  const updated = { ...target, port: newPort };
60631
- await import_node_fs46.promises.writeFile(this.metaPath(name), JSON.stringify(updated, null, 2) + "\n", "utf8");
61049
+ await import_node_fs48.promises.writeFile(this.metaPath(name), JSON.stringify(updated, null, 2) + "\n", "utf8");
60632
61050
  return updated;
60633
61051
  }
60634
61052
  /**
@@ -60645,7 +61063,7 @@ var ProjectStore = class {
60645
61063
  if (!validated.success) {
60646
61064
  throw new Error(`invalid prodUrl "${url}": ${validated.error.message}`);
60647
61065
  }
60648
- await import_node_fs46.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
61066
+ await import_node_fs48.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
60649
61067
  return validated.data;
60650
61068
  }
60651
61069
  /**
@@ -60666,7 +61084,7 @@ var ProjectStore = class {
60666
61084
  if (!validated.success) {
60667
61085
  throw new Error(`invalid publishJob: ${validated.error.message}`);
60668
61086
  }
60669
- await import_node_fs46.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
61087
+ await import_node_fs48.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
60670
61088
  return validated.data;
60671
61089
  }
60672
61090
  /** 清掉 .clawd-project.json.publishJob 字段。其他字段保持原样。 */
@@ -60681,13 +61099,13 @@ var ProjectStore = class {
60681
61099
  if (!validated.success) {
60682
61100
  throw new Error(`failed to clear publishJob: ${validated.error.message}`);
60683
61101
  }
60684
- await import_node_fs46.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
61102
+ await import_node_fs48.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
60685
61103
  return validated.data;
60686
61104
  }
60687
61105
  };
60688
61106
 
60689
61107
  // src/app-builder/kill-port.ts
60690
- var import_node_child_process13 = require("child_process");
61108
+ var import_node_child_process14 = require("child_process");
60691
61109
  async function killPortOccupants(port, ownedPids, logger) {
60692
61110
  let pids;
60693
61111
  try {
@@ -60729,7 +61147,7 @@ async function killPortOccupants(port, ownedPids, logger) {
60729
61147
  }
60730
61148
  function listPidsOnPort(port) {
60731
61149
  return new Promise((resolve6, reject) => {
60732
- (0, import_node_child_process13.execFile)(
61150
+ (0, import_node_child_process14.execFile)(
60733
61151
  "lsof",
60734
61152
  ["-ti", `:${port}`],
60735
61153
  { timeout: 3e3 },
@@ -60801,9 +61219,9 @@ var PublishJobRegistry = class {
60801
61219
  };
60802
61220
 
60803
61221
  // src/app-builder/publish-job-runner.ts
60804
- var import_node_child_process14 = require("child_process");
60805
- var import_node_fs47 = require("fs");
60806
- var import_node_path58 = require("path");
61222
+ var import_node_child_process15 = require("child_process");
61223
+ var import_node_fs49 = require("fs");
61224
+ var import_node_path60 = require("path");
60807
61225
 
60808
61226
  // src/app-builder/publish-stage-parser.ts
60809
61227
  var STAGE_RE = /^\s*::stage::(build|deploy|verify)\s*$/;
@@ -60830,15 +61248,15 @@ function tailStderrLines(buf, n) {
60830
61248
  // src/app-builder/publish-job-runner.ts
60831
61249
  async function startPublishJob(deps, args) {
60832
61250
  const { registry: registry2, projectDir } = deps;
60833
- const spawn12 = deps.spawnImpl ?? import_node_child_process14.spawn;
61251
+ const spawn12 = deps.spawnImpl ?? import_node_child_process15.spawn;
60834
61252
  if (registry2.has(args.name)) {
60835
61253
  return { jobId: registry2.get(args.name).jobId, status: "already-publishing" };
60836
61254
  }
60837
61255
  const projDir = projectDir(args.name);
60838
- const logPath = (0, import_node_path58.join)(projDir, ".publish.log");
61256
+ const logPath = (0, import_node_path60.join)(projDir, ".publish.log");
60839
61257
  let logStream = null;
60840
61258
  try {
60841
- logStream = (0, import_node_fs47.createWriteStream)(logPath, { flags: "w" });
61259
+ logStream = (0, import_node_fs49.createWriteStream)(logPath, { flags: "w" });
60842
61260
  } catch {
60843
61261
  logStream = null;
60844
61262
  }
@@ -61095,8 +61513,8 @@ async function recoverInterruptedJobs(deps) {
61095
61513
 
61096
61514
  // src/handlers/app-builder.ts
61097
61515
  init_protocol();
61098
- var import_node_path59 = require("path");
61099
- var import_node_fs48 = require("fs");
61516
+ var import_node_path61 = require("path");
61517
+ var import_node_fs50 = require("fs");
61100
61518
  var APP_BUILDER_PERSONAS = ["persona-app-builder", "persona-dataclaw-builder"];
61101
61519
  var DEV_SERVER_READY_TIMEOUT_MS = 3e4;
61102
61520
  async function recoverInterruptedPublishJobs(store, logger) {
@@ -61177,7 +61595,7 @@ function buildAppBuilderHandlers(deps) {
61177
61595
  async function listAllUsersProjects() {
61178
61596
  if (!deps.usersRoot || !deps.getStore) return [];
61179
61597
  const getStore = deps.getStore;
61180
- const userIds = await import_node_fs48.promises.readdir(deps.usersRoot).catch(() => []);
61598
+ const userIds = await import_node_fs50.promises.readdir(deps.usersRoot).catch(() => []);
61181
61599
  const perUser = await Promise.all(
61182
61600
  userIds.map((uid) => getStore(uid).list().catch(() => []))
61183
61601
  );
@@ -61246,8 +61664,8 @@ function buildAppBuilderHandlers(deps) {
61246
61664
  const project = await userStore.create(f.name, reservedPorts);
61247
61665
  try {
61248
61666
  const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(session.ownerPersonaId ?? "") : deps.personaRoot;
61249
- const templateSrcDir = (0, import_node_path59.join)(personaRoot, "extension-kit", "examples", DEFAULT_TEMPLATE);
61250
- const scaffoldScript = (0, import_node_path59.join)(deps.deployKitRoot, "scripts", "new-extension.sh");
61667
+ const templateSrcDir = (0, import_node_path61.join)(personaRoot, "extension-kit", "examples", DEFAULT_TEMPLATE);
61668
+ const scaffoldScript = (0, import_node_path61.join)(deps.deployKitRoot, "scripts", "new-extension.sh");
61251
61669
  const scaffoldResult = await userStore.scaffold(project.name, templateSrcDir, scaffoldScript);
61252
61670
  deps.logger?.info("app-builder.scaffold.done", {
61253
61671
  name: project.name,
@@ -61451,7 +61869,7 @@ function buildAppBuilderHandlers(deps) {
61451
61869
  await userStore.clearPublishJob(args.name);
61452
61870
  }
61453
61871
  const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(boundSession.ownerPersonaId ?? "") : deps.personaRoot;
61454
- const scriptPath = (0, import_node_path59.join)(deps.deployKitRoot, "scripts", "publish.sh");
61872
+ const scriptPath = (0, import_node_path61.join)(deps.deployKitRoot, "scripts", "publish.sh");
61455
61873
  deps.logger?.info("app-builder.publish.start", {
61456
61874
  name: args.name,
61457
61875
  sessionId: boundSession.sessionId,
@@ -61870,12 +62288,12 @@ function buildVisitorHandlers(deps) {
61870
62288
  }
61871
62289
 
61872
62290
  // src/extension/registry.ts
61873
- var import_promises10 = __toESM(require("fs/promises"), 1);
61874
- var import_node_path60 = __toESM(require("path"), 1);
62291
+ var import_promises11 = __toESM(require("fs/promises"), 1);
62292
+ var import_node_path62 = __toESM(require("path"), 1);
61875
62293
  async function loadAll(root) {
61876
62294
  let entries;
61877
62295
  try {
61878
- entries = await import_promises10.default.readdir(root, { withFileTypes: true });
62296
+ entries = await import_promises11.default.readdir(root, { withFileTypes: true });
61879
62297
  } catch (e) {
61880
62298
  if (e.code === "ENOENT") return [];
61881
62299
  throw e;
@@ -61884,16 +62302,16 @@ async function loadAll(root) {
61884
62302
  for (const ent of entries) {
61885
62303
  if (!ent.isDirectory()) continue;
61886
62304
  if (ent.name.startsWith(".")) continue;
61887
- records.push(await loadOne(import_node_path60.default.join(root, ent.name), ent.name));
62305
+ records.push(await loadOne(import_node_path62.default.join(root, ent.name), ent.name));
61888
62306
  }
61889
62307
  records.sort((a, b2) => a.extId < b2.extId ? -1 : a.extId > b2.extId ? 1 : 0);
61890
62308
  return records;
61891
62309
  }
61892
62310
  async function loadOne(dir, dirName) {
61893
- const manifestPath = import_node_path60.default.join(dir, "manifest.json");
62311
+ const manifestPath = import_node_path62.default.join(dir, "manifest.json");
61894
62312
  let raw;
61895
62313
  try {
61896
- raw = await import_promises10.default.readFile(manifestPath, "utf8");
62314
+ raw = await import_promises11.default.readFile(manifestPath, "utf8");
61897
62315
  } catch {
61898
62316
  return {
61899
62317
  extId: dirName,
@@ -61934,8 +62352,8 @@ async function loadOne(dir, dirName) {
61934
62352
  }
61935
62353
 
61936
62354
  // src/extension/uninstall.ts
61937
- var import_promises11 = __toESM(require("fs/promises"), 1);
61938
- var import_node_path61 = __toESM(require("path"), 1);
62355
+ var import_promises12 = __toESM(require("fs/promises"), 1);
62356
+ var import_node_path63 = __toESM(require("path"), 1);
61939
62357
  var UninstallError = class extends Error {
61940
62358
  constructor(code, message) {
61941
62359
  super(message);
@@ -61944,14 +62362,14 @@ var UninstallError = class extends Error {
61944
62362
  code;
61945
62363
  };
61946
62364
  async function uninstall(deps) {
61947
- const dir = import_node_path61.default.join(deps.root, deps.extId);
62365
+ const dir = import_node_path63.default.join(deps.root, deps.extId);
61948
62366
  try {
61949
- await import_promises11.default.access(dir);
62367
+ await import_promises12.default.access(dir);
61950
62368
  } catch {
61951
62369
  throw new UninstallError("NOT_FOUND", `extension ${deps.extId} not installed`);
61952
62370
  }
61953
62371
  await deps.runtime.close(deps.extId);
61954
- await import_promises11.default.rm(dir, { recursive: true, force: true });
62372
+ await import_promises12.default.rm(dir, { recursive: true, force: true });
61955
62373
  }
61956
62374
 
61957
62375
  // src/handlers/index.ts
@@ -61961,15 +62379,15 @@ var import_node_crypto18 = require("crypto");
61961
62379
  init_protocol();
61962
62380
 
61963
62381
  // src/peer-ops/run-command.ts
61964
- var import_node_child_process15 = require("child_process");
61965
- var import_node_os21 = __toESM(require("os"), 1);
62382
+ var import_node_child_process16 = require("child_process");
62383
+ var import_node_os22 = __toESM(require("os"), 1);
61966
62384
  var DEFAULT_TIMEOUT_MS4 = 3e4;
61967
62385
  var MAX_TIMEOUT_MS = 3e5;
61968
62386
  var MAX_OUTPUT_BYTES = 1048576;
61969
62387
  function runCommand(command, opts = {}) {
61970
62388
  const timeoutMs = Math.min(opts.timeoutMs ?? DEFAULT_TIMEOUT_MS4, MAX_TIMEOUT_MS);
61971
62389
  return new Promise((resolve6) => {
61972
- const child = (0, import_node_child_process15.spawn)("bash", ["-c", command], { cwd: import_node_os21.default.homedir() });
62390
+ const child = (0, import_node_child_process16.spawn)("bash", ["-c", command], { cwd: import_node_os22.default.homedir() });
61973
62391
  const out = [];
61974
62392
  const err = [];
61975
62393
  let outBytes = 0;
@@ -62184,8 +62602,129 @@ function buildMethodHandlers(deps) {
62184
62602
  return handlers;
62185
62603
  }
62186
62604
 
62605
+ // src/handlers/onboarding.ts
62606
+ init_protocol();
62607
+
62608
+ // src/tools/version-probe.ts
62609
+ var import_node_child_process17 = require("child_process");
62610
+ init_claude();
62611
+ function parseVersionOutput(out) {
62612
+ return /(\d+\.\d+\.\d+)/.exec(out)?.[1];
62613
+ }
62614
+ function execVersion(bin) {
62615
+ return new Promise((resolve6, reject) => {
62616
+ (0, import_node_child_process17.execFile)(bin, ["--version"], { timeout: 5e3 }, (err, stdout) => {
62617
+ if (err) reject(err);
62618
+ else resolve6(String(stdout));
62619
+ });
62620
+ });
62621
+ }
62622
+ var cache = null;
62623
+ async function probeToolVersions(opts = {}) {
62624
+ if (cache) return cache;
62625
+ const probes = opts.probes ?? { claude: () => probeClaude(), codex: () => probeCodex() };
62626
+ const runVersion = opts.runVersion ?? execVersion;
62627
+ const out = [];
62628
+ for (const id of ["claude", "codex"]) {
62629
+ const p2 = await probes[id]();
62630
+ if (!p2.available) {
62631
+ out.push({ id, available: false });
62632
+ continue;
62633
+ }
62634
+ let version2;
62635
+ try {
62636
+ version2 = parseVersionOutput(await runVersion(p2.path ?? id));
62637
+ } catch {
62638
+ version2 = void 0;
62639
+ }
62640
+ out.push({ id, available: true, ...version2 ? { version: version2 } : {}, ...p2.path ? { path: p2.path } : {} });
62641
+ }
62642
+ if (out.some((t) => t.available)) cache = out;
62643
+ return out;
62644
+ }
62645
+
62646
+ // src/feishu-auth/ios-interest-client.ts
62647
+ var IosInterestClientError = class extends Error {
62648
+ constructor(code, message, cause) {
62649
+ super(message);
62650
+ this.code = code;
62651
+ this.cause = cause;
62652
+ this.name = "IosInterestClientError";
62653
+ }
62654
+ code;
62655
+ cause;
62656
+ };
62657
+ var DEFAULT_TIMEOUT_MS5 = 8e3;
62658
+ async function submitIosInterest(opts) {
62659
+ const doFetch = opts.fetchImpl ?? fetch;
62660
+ const ac = new AbortController();
62661
+ const timer = setTimeout(() => ac.abort(), opts.timeoutMs ?? DEFAULT_TIMEOUT_MS5);
62662
+ let res;
62663
+ try {
62664
+ res = await doFetch(`${opts.apiUrl}/api/ios-interest`, {
62665
+ method: "POST",
62666
+ signal: ac.signal,
62667
+ headers: {
62668
+ authorization: `Bearer ${opts.apiKey}`,
62669
+ "x-did": encodeURIComponent(opts.deviceId),
62670
+ "x-name": encodeURIComponent(opts.displayName),
62671
+ "x-scene": "daemon",
62672
+ "content-type": "application/json"
62673
+ },
62674
+ body: JSON.stringify({ unionId: opts.unionId, displayName: opts.displayName })
62675
+ });
62676
+ } catch (err) {
62677
+ clearTimeout(timer);
62678
+ throw new IosInterestClientError("NETWORK", `network error: ${err.message}`, err);
62679
+ } finally {
62680
+ clearTimeout(timer);
62681
+ }
62682
+ if (!res.ok) {
62683
+ let detail = "";
62684
+ try {
62685
+ detail = JSON.stringify(await res.json());
62686
+ } catch {
62687
+ }
62688
+ throw new IosInterestClientError("API_ERROR", `HTTP ${res.status}: ${detail}`);
62689
+ }
62690
+ }
62691
+
62692
+ // src/handlers/onboarding.ts
62693
+ function buildOnboardingHandlers(deps) {
62694
+ const complete = async (frame) => {
62695
+ parseArgs2(OnboardingCompleteArgs, frame, "onboarding:complete args");
62696
+ const existing = loadOwnerProfile(deps.dataDir).onboardingCompletedAt;
62697
+ const ts = typeof existing === "number" ? existing : Date.now();
62698
+ if (typeof existing !== "number") {
62699
+ patchOwnerProfile(deps.dataDir, { onboardingCompletedAt: ts });
62700
+ }
62701
+ return { response: { onboardingCompletedAt: ts } };
62702
+ };
62703
+ const toolsProbe = async (frame) => {
62704
+ parseArgs2(ToolsProbeArgs, frame, "tools:probe args");
62705
+ return { response: { tools: await probeToolVersions() } };
62706
+ };
62707
+ const iosInterest = async (frame) => {
62708
+ parseArgs2(OnboardingIosInterestArgs, frame, "onboarding:iosInterest args");
62709
+ const identity = deps.getOwnerIdentity();
62710
+ if (!identity) {
62711
+ throw new ClawdError(ERROR_CODES.FEISHU_LOGIN_REQUIRED, "onboarding:iosInterest \u9700\u8981\u98DE\u4E66\u767B\u5F55");
62712
+ }
62713
+ await submitIosInterest({
62714
+ apiUrl: deps.apiUrl,
62715
+ apiKey: deps.apiKey,
62716
+ deviceId: deps.deviceId,
62717
+ unionId: identity.unionId,
62718
+ displayName: identity.displayName,
62719
+ ...deps.fetchImpl ? { fetchImpl: deps.fetchImpl } : {}
62720
+ });
62721
+ return { response: { registered: true } };
62722
+ };
62723
+ return { "onboarding:complete": complete, "tools:probe": toolsProbe, "onboarding:iosInterest": iosInterest };
62724
+ }
62725
+
62187
62726
  // src/app-builder/dev-server-supervisor.ts
62188
- var import_node_child_process16 = require("child_process");
62727
+ var import_node_child_process18 = require("child_process");
62189
62728
  var import_node_events2 = require("events");
62190
62729
  var DEFAULT_READY_PATTERN = /Local:\s+https?:\/\/|Nest application successfully started|server listening on/i;
62191
62730
  var DevServerSupervisor = class extends import_node_events2.EventEmitter {
@@ -62222,7 +62761,7 @@ var DevServerSupervisor = class extends import_node_events2.EventEmitter {
62222
62761
  tunnelHost: args.tunnelHost,
62223
62762
  devCommand: cmd
62224
62763
  });
62225
- const child = (0, import_node_child_process16.spawn)("sh", ["-c", cmd], {
62764
+ const child = (0, import_node_child_process18.spawn)("sh", ["-c", cmd], {
62226
62765
  cwd: args.cwd,
62227
62766
  env,
62228
62767
  stdio: "pipe",
@@ -62474,9 +63013,9 @@ async function dispatchRpc(method, frame, client, ctx, deps) {
62474
63013
  }
62475
63014
 
62476
63015
  // src/extension/runtime.ts
62477
- var import_node_child_process17 = require("child_process");
62478
- var import_node_path62 = __toESM(require("path"), 1);
62479
- var import_promises12 = require("timers/promises");
63016
+ var import_node_child_process19 = require("child_process");
63017
+ var import_node_path64 = __toESM(require("path"), 1);
63018
+ var import_promises13 = require("timers/promises");
62480
63019
 
62481
63020
  // src/extension/port-allocator.ts
62482
63021
  var import_node_net2 = __toESM(require("net"), 1);
@@ -62576,13 +63115,13 @@ var Runtime = class {
62576
63115
  /\$CLAWOS_EXT_PORT/g,
62577
63116
  String(port)
62578
63117
  );
62579
- const dir = import_node_path62.default.join(this.root, extId);
63118
+ const dir = import_node_path64.default.join(this.root, extId);
62580
63119
  const env = {
62581
63120
  ...process.env,
62582
63121
  CLAWOS_EXT_PORT: String(port),
62583
63122
  CLAWOS_EXT_ID: extId
62584
63123
  };
62585
- const child = (0, import_node_child_process17.spawn)("sh", ["-c", cmd], {
63124
+ const child = (0, import_node_child_process19.spawn)("sh", ["-c", cmd], {
62586
63125
  cwd: dir,
62587
63126
  env,
62588
63127
  stdio: ["ignore", "pipe", "pipe"],
@@ -62652,7 +63191,7 @@ ${handle.stderrTail}`
62652
63191
  if (res.ok) return;
62653
63192
  } catch {
62654
63193
  }
62655
- await (0, import_promises12.setTimeout)(this.healthzIntervalMs);
63194
+ await (0, import_promises13.setTimeout)(this.healthzIntervalMs);
62656
63195
  }
62657
63196
  throw new RuntimeError(
62658
63197
  "HEALTHZ_FAILED",
@@ -62677,7 +63216,7 @@ ${handle.stderrTail}`
62677
63216
  };
62678
63217
  killGroup("SIGTERM");
62679
63218
  const exited = new Promise((resolve6) => child.once("exit", () => resolve6()));
62680
- const timed = (0, import_promises12.setTimeout)(5e3).then(() => "timeout");
63219
+ const timed = (0, import_promises13.setTimeout)(5e3).then(() => "timeout");
62681
63220
  const winner = await Promise.race([exited.then(() => "exited"), timed]);
62682
63221
  if (winner === "timeout" && child.exitCode === null) {
62683
63222
  killGroup("SIGKILL");
@@ -62687,8 +63226,8 @@ ${handle.stderrTail}`
62687
63226
  };
62688
63227
 
62689
63228
  // src/extension/published-channels.ts
62690
- var import_promises13 = __toESM(require("fs/promises"), 1);
62691
- var import_node_path63 = __toESM(require("path"), 1);
63229
+ var import_promises14 = __toESM(require("fs/promises"), 1);
63230
+ var import_node_path65 = __toESM(require("path"), 1);
62692
63231
  init_zod();
62693
63232
  var PublishedChannelsError = class extends Error {
62694
63233
  constructor(code, message) {
@@ -62718,7 +63257,7 @@ var PublishedChannelStore = class {
62718
63257
  this.channels.clear();
62719
63258
  let raw;
62720
63259
  try {
62721
- raw = await import_promises13.default.readFile(this.filePath, "utf8");
63260
+ raw = await import_promises14.default.readFile(this.filePath, "utf8");
62722
63261
  } catch (e) {
62723
63262
  if (e.code === "ENOENT") {
62724
63263
  this.loaded = true;
@@ -62787,15 +63326,15 @@ var PublishedChannelStore = class {
62787
63326
  )
62788
63327
  };
62789
63328
  const tmp = `${this.filePath}.tmp`;
62790
- await import_promises13.default.mkdir(import_node_path63.default.dirname(this.filePath), { recursive: true });
62791
- await import_promises13.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
62792
- await import_promises13.default.rename(tmp, this.filePath);
63329
+ await import_promises14.default.mkdir(import_node_path65.default.dirname(this.filePath), { recursive: true });
63330
+ await import_promises14.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
63331
+ await import_promises14.default.rename(tmp, this.filePath);
62793
63332
  }
62794
63333
  };
62795
63334
 
62796
63335
  // src/extension/bundle-cache.ts
62797
- var import_promises14 = __toESM(require("fs/promises"), 1);
62798
- var import_node_path64 = __toESM(require("path"), 1);
63336
+ var import_promises15 = __toESM(require("fs/promises"), 1);
63337
+ var import_node_path66 = __toESM(require("path"), 1);
62799
63338
  var BundleCache = class {
62800
63339
  constructor(rootDir) {
62801
63340
  this.rootDir = rootDir;
@@ -62803,17 +63342,17 @@ var BundleCache = class {
62803
63342
  rootDir;
62804
63343
  /** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
62805
63344
  async write(snapshotHash, buffer) {
62806
- await import_promises14.default.mkdir(this.rootDir, { recursive: true });
62807
- const file = import_node_path64.default.join(this.rootDir, `${snapshotHash}.zip`);
63345
+ await import_promises15.default.mkdir(this.rootDir, { recursive: true });
63346
+ const file = import_node_path66.default.join(this.rootDir, `${snapshotHash}.zip`);
62808
63347
  const tmp = `${file}.tmp`;
62809
- await import_promises14.default.writeFile(tmp, buffer, { mode: 384 });
62810
- await import_promises14.default.rename(tmp, file);
63348
+ await import_promises15.default.writeFile(tmp, buffer, { mode: 384 });
63349
+ await import_promises15.default.rename(tmp, file);
62811
63350
  }
62812
63351
  /** Returns the bundle bytes, or null when the file doesn't exist. */
62813
63352
  async read(snapshotHash) {
62814
- const file = import_node_path64.default.join(this.rootDir, `${snapshotHash}.zip`);
63353
+ const file = import_node_path66.default.join(this.rootDir, `${snapshotHash}.zip`);
62815
63354
  try {
62816
- return await import_promises14.default.readFile(file);
63355
+ return await import_promises15.default.readFile(file);
62817
63356
  } catch (e) {
62818
63357
  if (e.code === "ENOENT") return null;
62819
63358
  throw e;
@@ -62821,13 +63360,13 @@ var BundleCache = class {
62821
63360
  }
62822
63361
  /** Idempotent — missing file is not an error. */
62823
63362
  async delete(snapshotHash) {
62824
- const file = import_node_path64.default.join(this.rootDir, `${snapshotHash}.zip`);
62825
- await import_promises14.default.rm(file, { force: true });
63363
+ const file = import_node_path66.default.join(this.rootDir, `${snapshotHash}.zip`);
63364
+ await import_promises15.default.rm(file, { force: true });
62826
63365
  }
62827
63366
  };
62828
63367
 
62829
63368
  // src/index.ts
62830
- var import_meta6 = {};
63369
+ var import_meta7 = {};
62831
63370
  async function startDaemon(config) {
62832
63371
  const authFile = loadOrCreateAuthFile({ dataDir: config.dataDir });
62833
63372
  const logShippingCfg = config.logShipping ?? { endpoint: null, sampling: {}, mode: "off" };
@@ -62842,26 +63381,26 @@ async function startDaemon(config) {
62842
63381
  },
62843
63382
  source: "daemon",
62844
63383
  sampling: logShippingCfg.sampling,
62845
- homeDir: import_node_os22.default.homedir()
63384
+ homeDir: import_node_os23.default.homedir()
62846
63385
  });
62847
- const logDir = import_node_path65.default.join(config.dataDir, "log");
62848
- import_node_fs49.default.mkdirSync(logDir, { recursive: true });
63386
+ const logDir = import_node_path67.default.join(config.dataDir, "log");
63387
+ import_node_fs51.default.mkdirSync(logDir, { recursive: true });
62849
63388
  const logger = createLogger({
62850
63389
  level: config.logLevel,
62851
- file: import_node_path65.default.join(logDir, "clawd.log"),
63390
+ file: import_node_path67.default.join(logDir, "clawd.log"),
62852
63391
  logClient
62853
63392
  });
62854
63393
  logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
62855
63394
  const screenIdleProbeLogger = createFileOnlyLogger({
62856
- file: import_node_path65.default.join(logDir, "screen-idle-probe.log"),
63395
+ file: import_node_path67.default.join(logDir, "screen-idle-probe.log"),
62857
63396
  level: "debug"
62858
63397
  });
62859
63398
  logger.info("screen-idle probe logger enabled", {
62860
- file: import_node_path65.default.join(logDir, "screen-idle-probe.log")
63399
+ file: import_node_path67.default.join(logDir, "screen-idle-probe.log")
62861
63400
  });
62862
63401
  const CAP_TARGETS = [
62863
- import_node_path65.default.join(logDir, "clawd.log"),
62864
- import_node_path65.default.join(logDir, "screen-idle-probe.log")
63402
+ import_node_path67.default.join(logDir, "clawd.log"),
63403
+ import_node_path67.default.join(logDir, "screen-idle-probe.log")
62865
63404
  ];
62866
63405
  const LOG_CAP_MAX_BYTES = 10 * 1024 * 1024;
62867
63406
  const LOG_CAP_KEEP_BYTES = 5 * 1024 * 1024;
@@ -62957,8 +63496,8 @@ async function startDaemon(config) {
62957
63496
  const agents = new AgentsScanner();
62958
63497
  const history = new ClaudeHistoryReader();
62959
63498
  let transport = null;
62960
- const personaStore = new PersonaStore(import_node_path65.default.join(config.dataDir, "personas"));
62961
- const usersRoot = import_node_path65.default.join(config.dataDir, "users");
63499
+ const personaStore = new PersonaStore(import_node_path67.default.join(config.dataDir, "personas"));
63500
+ const usersRoot = import_node_path67.default.join(config.dataDir, "users");
62962
63501
  const defaultsRoot = findDefaultsRoot(logger);
62963
63502
  if (defaultsRoot) {
62964
63503
  seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
@@ -62980,7 +63519,7 @@ async function startDaemon(config) {
62980
63519
  retirePersonaBuilder({ store: personaStore, logger });
62981
63520
  const groupFileStore = new GroupFileStore({ dataDir: config.dataDir, logger });
62982
63521
  const dispatchStore = createDispatchStore({
62983
- filePath: import_node_path65.default.join(config.dataDir, "dispatch.json"),
63522
+ filePath: import_node_path67.default.join(config.dataDir, "dispatch.json"),
62984
63523
  now: () => Date.now(),
62985
63524
  onFlushError: (err) => logger.error("dispatch store flush failed", {
62986
63525
  reason: err instanceof Error ? err.message : String(err)
@@ -62995,18 +63534,18 @@ async function startDaemon(config) {
62995
63534
  now: () => Date.now(),
62996
63535
  onCompleted: (sid) => deliverPendingRef?.(sid)
62997
63536
  });
62998
- const here = typeof __dirname === "string" ? __dirname : import_node_path65.default.dirname((0, import_node_url4.fileURLToPath)(import_meta6.url));
63537
+ const here = typeof __dirname === "string" ? __dirname : import_node_path67.default.dirname((0, import_node_url4.fileURLToPath)(import_meta7.url));
62999
63538
  const mcpConfigs = [];
63000
63539
  const mcpDaemonUrl = `http://127.0.0.1:${config.port}`;
63001
63540
  const dispatchServerCandidates = [
63002
- import_node_path65.default.join(here, "dispatch", "mcp-server.cjs"),
63541
+ import_node_path67.default.join(here, "dispatch", "mcp-server.cjs"),
63003
63542
  // 生产 dist/index → dist/dispatch/mcp-server.cjs
63004
- import_node_path65.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
63543
+ import_node_path67.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
63005
63544
  // dev tsx src/index → ../dist/dispatch/mcp-server.cjs
63006
63545
  ];
63007
- const dispatchServerScriptPath = dispatchServerCandidates.find((p2) => import_node_fs49.default.existsSync(p2));
63546
+ const dispatchServerScriptPath = dispatchServerCandidates.find((p2) => import_node_fs51.default.existsSync(p2));
63008
63547
  if (dispatchServerScriptPath) {
63009
- const dispatchLogPath = import_node_path65.default.join(logDir, "dispatch-mcp-server.log");
63548
+ const dispatchLogPath = import_node_path67.default.join(logDir, "dispatch-mcp-server.log");
63010
63549
  const dispatchCfgPath = writeDispatchMcpConfig({
63011
63550
  dataDir: config.dataDir,
63012
63551
  serverScriptPath: dispatchServerScriptPath,
@@ -63026,12 +63565,12 @@ async function startDaemon(config) {
63026
63565
  });
63027
63566
  }
63028
63567
  const ticketServerCandidates = [
63029
- import_node_path65.default.join(here, "ticket", "mcp-server.cjs"),
63030
- import_node_path65.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
63568
+ import_node_path67.default.join(here, "ticket", "mcp-server.cjs"),
63569
+ import_node_path67.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
63031
63570
  ];
63032
- const ticketServerScriptPath = ticketServerCandidates.find((p2) => import_node_fs49.default.existsSync(p2));
63571
+ const ticketServerScriptPath = ticketServerCandidates.find((p2) => import_node_fs51.default.existsSync(p2));
63033
63572
  if (ticketServerScriptPath) {
63034
- const ticketLogPath = import_node_path65.default.join(logDir, "ticket-mcp-server.log");
63573
+ const ticketLogPath = import_node_path67.default.join(logDir, "ticket-mcp-server.log");
63035
63574
  const ticketCfgPath = writeTicketMcpConfig({
63036
63575
  dataDir: config.dataDir,
63037
63576
  serverScriptPath: ticketServerScriptPath,
@@ -63053,12 +63592,12 @@ async function startDaemon(config) {
63053
63592
  });
63054
63593
  }
63055
63594
  const shiftServerCandidates = [
63056
- import_node_path65.default.join(here, "shift", "mcp-server.cjs"),
63057
- import_node_path65.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
63595
+ import_node_path67.default.join(here, "shift", "mcp-server.cjs"),
63596
+ import_node_path67.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
63058
63597
  ];
63059
- const shiftServerScriptPath = shiftServerCandidates.find((p2) => import_node_fs49.default.existsSync(p2));
63598
+ const shiftServerScriptPath = shiftServerCandidates.find((p2) => import_node_fs51.default.existsSync(p2));
63060
63599
  if (shiftServerScriptPath) {
63061
- const shiftLogPath = import_node_path65.default.join(logDir, "shift-mcp-server.log");
63600
+ const shiftLogPath = import_node_path67.default.join(logDir, "shift-mcp-server.log");
63062
63601
  const shiftCfgPath = await writeShiftMcpConfig({
63063
63602
  dataDir: config.dataDir,
63064
63603
  serverScriptPath: shiftServerScriptPath,
@@ -63079,12 +63618,12 @@ async function startDaemon(config) {
63079
63618
  );
63080
63619
  }
63081
63620
  const inboxServerCandidates = [
63082
- import_node_path65.default.join(here, "inbox", "mcp-server.cjs"),
63083
- import_node_path65.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
63621
+ import_node_path67.default.join(here, "inbox", "mcp-server.cjs"),
63622
+ import_node_path67.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
63084
63623
  ];
63085
- const inboxServerScriptPath = inboxServerCandidates.find((p2) => import_node_fs49.default.existsSync(p2));
63624
+ const inboxServerScriptPath = inboxServerCandidates.find((p2) => import_node_fs51.default.existsSync(p2));
63086
63625
  if (inboxServerScriptPath) {
63087
- const inboxLogPath = import_node_path65.default.join(logDir, "inbox-mcp-server.log");
63626
+ const inboxLogPath = import_node_path67.default.join(logDir, "inbox-mcp-server.log");
63088
63627
  const inboxCfgPath = await writeInboxMcpConfig({
63089
63628
  dataDir: config.dataDir,
63090
63629
  serverScriptPath: inboxServerScriptPath,
@@ -63105,10 +63644,10 @@ async function startDaemon(config) {
63105
63644
  );
63106
63645
  }
63107
63646
  const peerOpsServerCandidates = [
63108
- import_node_path65.default.join(here, "peer-ops", "mcp-server.cjs"),
63109
- import_node_path65.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
63647
+ import_node_path67.default.join(here, "peer-ops", "mcp-server.cjs"),
63648
+ import_node_path67.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
63110
63649
  ];
63111
- const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) => import_node_fs49.default.existsSync(p2));
63650
+ const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) => import_node_fs51.default.existsSync(p2));
63112
63651
  if (peerOpsServerScriptPath) {
63113
63652
  const peerOpsCfgPath = writePeerOpsMcpConfig({
63114
63653
  dataDir: config.dataDir,
@@ -63128,12 +63667,12 @@ async function startDaemon(config) {
63128
63667
  );
63129
63668
  }
63130
63669
  const rpcToolServerCandidates = [
63131
- import_node_path65.default.join(here, "rpc-tool", "mcp-server.cjs"),
63132
- import_node_path65.default.join(here, "..", "dist", "rpc-tool", "mcp-server.cjs")
63670
+ import_node_path67.default.join(here, "rpc-tool", "mcp-server.cjs"),
63671
+ import_node_path67.default.join(here, "..", "dist", "rpc-tool", "mcp-server.cjs")
63133
63672
  ];
63134
- const rpcToolServerScriptPath = rpcToolServerCandidates.find((p2) => import_node_fs49.default.existsSync(p2));
63673
+ const rpcToolServerScriptPath = rpcToolServerCandidates.find((p2) => import_node_fs51.default.existsSync(p2));
63135
63674
  if (rpcToolServerScriptPath) {
63136
- const rpcToolLogPath = import_node_path65.default.join(logDir, "rpc-tool-mcp-server.log");
63675
+ const rpcToolLogPath = import_node_path67.default.join(logDir, "rpc-tool-mcp-server.log");
63137
63676
  const rpcToolCfgPath = writeRpcToolMcpConfig({
63138
63677
  dataDir: config.dataDir,
63139
63678
  serverScriptPath: rpcToolServerScriptPath,
@@ -63154,7 +63693,7 @@ async function startDaemon(config) {
63154
63693
  );
63155
63694
  }
63156
63695
  const shiftStore = createShiftStore({
63157
- filePath: import_node_path65.default.join(config.dataDir, "shift.json"),
63696
+ filePath: import_node_path67.default.join(config.dataDir, "shift.json"),
63158
63697
  ownerIdProvider: () => ownerPrincipalId,
63159
63698
  now: () => Date.now()
63160
63699
  });
@@ -63176,7 +63715,7 @@ async function startDaemon(config) {
63176
63715
  getAdapter,
63177
63716
  historyReader: history,
63178
63717
  dataDir: config.dataDir,
63179
- personaRoot: import_node_path65.default.join(config.dataDir, "personas"),
63718
+ personaRoot: import_node_path67.default.join(config.dataDir, "personas"),
63180
63719
  // dispatch / shift 自动化 spawn 按 persona 绑定 tool 起 B session(codex persona 用 codex)。
63181
63720
  // personaRegistry 声明在 manager 之后(同作用域 const,调用时机在启动完成后,无 TDZ 风险)。
63182
63721
  getPersonaTool: (personaId2) => personaRegistry.get(personaId2)?.tool,
@@ -63227,10 +63766,10 @@ async function startDaemon(config) {
63227
63766
  // 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
63228
63767
  attachmentGroup: {
63229
63768
  onFileEdit: (input) => {
63230
- const absPath = import_node_path65.default.isAbsolute(input.relPath) ? input.relPath : import_node_path65.default.join(input.cwd, input.relPath);
63769
+ const absPath = import_node_path67.default.isAbsolute(input.relPath) ? input.relPath : import_node_path67.default.join(input.cwd, input.relPath);
63231
63770
  let size = 0;
63232
63771
  try {
63233
- size = import_node_fs49.default.statSync(absPath).size;
63772
+ size = import_node_fs51.default.statSync(absPath).size;
63234
63773
  } catch (err) {
63235
63774
  logger.warn("attachment.onFileEdit stat failed", {
63236
63775
  sessionId: input.sessionId,
@@ -63436,6 +63975,8 @@ async function startDaemon(config) {
63436
63975
  // dispatch / shift-internal 两组,只看 buildMethodHandlers 内部表会误报死方法)
63437
63976
  feishuActive: () => feishuActive,
63438
63977
  getAllHandlers: () => handlers,
63978
+ // onboarding 判定(info 帧字段)+ importExternal 台账落点
63979
+ dataDir: config.dataDir,
63439
63980
  manager,
63440
63981
  workspace,
63441
63982
  skills,
@@ -63477,11 +64018,11 @@ async function startDaemon(config) {
63477
64018
  // 'persona/<pid>/owner',default 走 'default'。
63478
64019
  getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
63479
64020
  // guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
63480
- personaRoot: import_node_path65.default.join(config.dataDir, "personas"),
64021
+ personaRoot: import_node_path67.default.join(config.dataDir, "personas"),
63481
64022
  usersRoot
63482
64023
  },
63483
64024
  // workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
63484
- personaRoot: import_node_path65.default.join(config.dataDir, "personas"),
64025
+ personaRoot: import_node_path67.default.join(config.dataDir, "personas"),
63485
64026
  // v2 多人 persona 隔离:handler 派生 guest user-dir 放行
63486
64027
  usersRoot,
63487
64028
  // v2 Phase 6: whoami handler 装在 owner principal.displayName + persona 解析
@@ -63607,11 +64148,11 @@ async function startDaemon(config) {
63607
64148
  // 发布上线脚手架化 (spec 2026-06-03 §5.2):
63608
64149
  // appBuilderPersonaRoot 用于拼 publish.sh 绝对路径(persona-app-builder 安装在
63609
64150
  // dataDir/personas/persona-app-builder 之下,extension-kit/scripts/publish.sh 是相对路径)。
63610
- appBuilderPersonaRoot: import_node_path65.default.join(config.dataDir, "personas", "persona-app-builder"),
64151
+ appBuilderPersonaRoot: import_node_path67.default.join(config.dataDir, "personas", "persona-app-builder"),
63611
64152
  // 共享 deploy-kit 根:scaffold/publish 脚本骨架 + 阿里云凭证单一真源。
63612
- deployKitRoot: import_node_path65.default.join(config.dataDir, "deploy-kit"),
64153
+ deployKitRoot: import_node_path67.default.join(config.dataDir, "deploy-kit"),
63613
64154
  // scaffold/publish 按当前 session 的 persona 解析其安装根,让每个 persona 用自己的模板/注入配置。
63614
- resolvePersonaRoot: (personaId2) => import_node_path65.default.join(config.dataDir, "personas", personaId2),
64155
+ resolvePersonaRoot: (personaId2) => import_node_path67.default.join(config.dataDir, "personas", personaId2),
63615
64156
  // 发布上线脚手架化 (spec 2026-06-03 §5.2.2):
63616
64157
  // 复用 SessionManagerDeps.broadcastFrame 同款 dispatch 逻辑 —— runner 调 manager.send
63617
64158
  // 取回 broadcast 帧后逐帧 push 到 transport,跟 manager 自身的 deps 一致。
@@ -63654,7 +64195,7 @@ async function startDaemon(config) {
63654
64195
  sourceSessionId: args.sourceSessionId
63655
64196
  });
63656
64197
  const sourceFile = manager.findOwnedSession(args.sourceSessionId);
63657
- const sourceJsonlPath = resolveSourceJsonlPath(sourceFile, import_node_os22.default.homedir());
64198
+ const sourceJsonlPath = resolveSourceJsonlPath(sourceFile, import_node_os23.default.homedir());
63658
64199
  logger.info("dispatch.spawnB.source-resolved", {
63659
64200
  dispatchId: args.dispatchId,
63660
64201
  sourceJsonlPath,
@@ -63716,7 +64257,7 @@ async function startDaemon(config) {
63716
64257
  });
63717
64258
  shiftScheduler.start();
63718
64259
  logger.info("shift scheduler started", { shiftCount: shiftStore.list().length });
63719
- const larkBotStore = createLarkBotBindingStore(import_node_path65.default.join(config.dataDir, "personas"));
64260
+ const larkBotStore = createLarkBotBindingStore(import_node_path67.default.join(config.dataDir, "personas"));
63720
64261
  const larkBotCloud = createLarkBotCloudClient({
63721
64262
  api: config.clawosApi ?? DEFAULT_CLAWOS_API,
63722
64263
  apiKey: resolveClawdTicketsApiKey(),
@@ -63730,7 +64271,7 @@ async function startDaemon(config) {
63730
64271
  store: larkBotStore,
63731
64272
  fetchResource: (appId, messageId, fileKey, maxBytes, type) => larkBotCloud.fetchResource(appId, messageId, fileKey, maxBytes, type),
63732
64273
  // 图片落 guest userWorkDir 下(capId = lark-<chat_id>):CC 经 --add-dir + allowRead carve 可 Read
63733
- mediaRootFor: (chatId) => import_node_path65.default.join(deriveUserWorkDir(`lark-${chatId}`, usersRoot), "lark-media"),
64274
+ mediaRootFor: (chatId) => import_node_path67.default.join(deriveUserWorkDir(`lark-${chatId}`, usersRoot), "lark-media"),
63734
64275
  isShuttingDown: () => larkDraining,
63735
64276
  logger: {
63736
64277
  warn: (msg) => logger.warn(msg),
@@ -63756,6 +64297,24 @@ async function startDaemon(config) {
63756
64297
  logger: { warn: (msg) => logger.warn(msg) }
63757
64298
  };
63758
64299
  Object.assign(handlers, buildLarkBotHandlers(larkBotDeps));
64300
+ Object.assign(
64301
+ handlers,
64302
+ buildOnboardingHandlers({
64303
+ dataDir: config.dataDir,
64304
+ // 现读(登录/登出热切换);unionId 缺失时回落 ownerId(老登录记录无 unionId)
64305
+ getOwnerIdentity: () => {
64306
+ const rec3 = ownerIdentityStore.read();
64307
+ if (!rec3) return null;
64308
+ return {
64309
+ unionId: rec3.identity.unionId ?? rec3.identity.ownerId,
64310
+ displayName: rec3.identity.displayName
64311
+ };
64312
+ },
64313
+ apiUrl: config.clawosApi ?? DEFAULT_CLAWOS_API,
64314
+ apiKey: resolveClawdTicketsApiKey(),
64315
+ deviceId: authFile.deviceId
64316
+ })
64317
+ );
63759
64318
  const authResolver = new AuthContextResolver({
63760
64319
  ownerToken: resolvedAuthToken
63761
64320
  });
@@ -63874,6 +64433,8 @@ async function startDaemon(config) {
63874
64433
  {
63875
64434
  manager,
63876
64435
  getAdapter,
64436
+ // onboarding 判定:ready 帧携带 profile.json 的 onboardingCompletedAt
64437
+ dataDir: config.dataDir,
63877
64438
  getTunnelUrl: () => currentTunnelUrl,
63878
64439
  getLogShipping: () => config.logShipping ? {
63879
64440
  endpoint: config.logShipping.endpoint,
@@ -64014,11 +64575,11 @@ async function startDaemon(config) {
64014
64575
  const lines = [
64015
64576
  `Tunnel: ${r.url}`,
64016
64577
  ...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
64017
- `Frpc config: ${import_node_path65.default.join(config.dataDir, "frpc.toml")}`,
64018
- `Frpc log: ${import_node_path65.default.join(logDir, "frpc.log")}`
64578
+ `Frpc config: ${import_node_path67.default.join(config.dataDir, "frpc.toml")}`,
64579
+ `Frpc log: ${import_node_path67.default.join(logDir, "frpc.log")}`
64019
64580
  ];
64020
- const width = Math.max(...lines.map((l) => l.length));
64021
- const bar = "\u2550".repeat(width + 4);
64581
+ const width2 = Math.max(...lines.map((l) => l.length));
64582
+ const bar = "\u2550".repeat(width2 + 4);
64022
64583
  process.stdout.write(`
64023
64584
  ${bar}
64024
64585
  `);
@@ -64028,8 +64589,8 @@ ${bar}
64028
64589
 
64029
64590
  `);
64030
64591
  try {
64031
- const connectPath = import_node_path65.default.join(config.dataDir, "connect.txt");
64032
- import_node_fs49.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
64592
+ const connectPath = import_node_path67.default.join(config.dataDir, "connect.txt");
64593
+ import_node_fs51.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
64033
64594
  } catch {
64034
64595
  }
64035
64596
  } catch (err) {
@@ -64104,9 +64665,9 @@ ${bar}
64104
64665
  };
64105
64666
  }
64106
64667
  function migrateDropPersonsDir(dataDir) {
64107
- const dir = import_node_path65.default.join(dataDir, "persons");
64668
+ const dir = import_node_path67.default.join(dataDir, "persons");
64108
64669
  try {
64109
- import_node_fs49.default.rmSync(dir, { recursive: true, force: true });
64670
+ import_node_fs51.default.rmSync(dir, { recursive: true, force: true });
64110
64671
  } catch {
64111
64672
  }
64112
64673
  }