@clawos-dev/clawd 0.2.67 → 0.2.69-beta.120.2a41cd5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.cjs +102 -153
  2. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -605,8 +605,8 @@ var init_parseUtil = __esm({
605
605
  init_errors2();
606
606
  init_en();
607
607
  makeIssue = (params) => {
608
- const { data, path: path32, errorMaps, issueData } = params;
609
- const fullPath = [...path32, ...issueData.path || []];
608
+ const { data, path: path31, errorMaps, issueData } = params;
609
+ const fullPath = [...path31, ...issueData.path || []];
610
610
  const fullIssue = {
611
611
  ...issueData,
612
612
  path: fullPath
@@ -917,11 +917,11 @@ var init_types = __esm({
917
917
  init_parseUtil();
918
918
  init_util();
919
919
  ParseInputLazyPath = class {
920
- constructor(parent, value, path32, key) {
920
+ constructor(parent, value, path31, key) {
921
921
  this._cachedPath = [];
922
922
  this.parent = parent;
923
923
  this.data = value;
924
- this._path = path32;
924
+ this._path = path31;
925
925
  this._key = key;
926
926
  }
927
927
  get path() {
@@ -4331,11 +4331,9 @@ var init_attachment_schemas = __esm({
4331
4331
  stale: external_exports.boolean().optional()
4332
4332
  });
4333
4333
  AttachmentSignUrlArgs = external_exports.object({
4334
- /** 群文件所属的 session */
4335
- sessionId: external_exports.string().min(1),
4336
- /** 相对 session.cwd 的路径;允许传绝对路径,daemon 端会归一化(必须在 cwd 内) */
4337
- relPath: external_exports.string().min(1),
4338
- /** TTL 秒数;缺省 24h;null 走永久 URL(不带 exp 字段) */
4334
+ /** 要分享的绝对路径;签名只关心 absPath,不区分 persona/session */
4335
+ absPath: external_exports.string().min(1),
4336
+ /** TTL 秒数;缺省 24h;'never' null 不带 exp 字段(永久有效) */
4339
4337
  ttlSeconds: external_exports.number().int().positive().nullable().optional()
4340
4338
  });
4341
4339
  AttachmentSignUrlResponseSchema = external_exports.object({
@@ -4470,7 +4468,7 @@ var init_persona_schemas = __esm({
4470
4468
  });
4471
4469
 
4472
4470
  // ../protocol/src/schemas.ts
4473
- var SessionStatusSchema, UsageSchema, ContextUsageSchema, sessionMetaShape, SessionMetaSchema, ModelInfoSchema, ModeInfoSchema, ConfigFieldSchemaSchema, CapabilitiesGetArgs, CapabilitiesResponseSchema, AllowRuleSchema, SessionFileSchema, ParsedEventBase, HistoryUserMetaSchema, SubagentToolStatsSchema, StructuredPatchHunkSchema, ToolResultExtraSchema, MemoryEntrySchema, AskQuestionOptionSchema, AskQuestionItemSchema, ParsedEventSchema, SessionCreateArgs, SessionIdArgs, SessionUpdateArgs, SessionSendArgs, SessionRewindArgs, SessionRewindResponseSchema, SessionRewindDiffArgs, RewindDiffHunkSchema, RewindDiffFileSchema, SessionRewindDiffResponseSchema, SessionRewindableMessageIdsArgs, SessionRewindableMessageIdsResponseSchema, SessionResumeArgs, SessionForkArgs, SessionForkResponseSchema, SessionObserveArgs, SessionEventsArgs, PermissionRespondArgs, HistoryListArgs, HistoryReadArgs, HistorySubagentsArgs, HistorySubagentReadArgs, WorkspaceListArgs, WorkspaceReadArgs, SkillsListArgs, SkillEntrySchema, AgentEntrySchema, AgentsListArgs, AgentsListResponseSchema, SessionSubscribeArgs, SessionPinArgs, SessionReorderPinsArgs, GitRootArgs, GitRootResponseSchema, GitBranchArgs, GitBranchResponseSchema, GitBranchesArgs, GitBranchesResponseSchema, HistoryRecentDirsArgs, RecentDirEntrySchema, HistoryRecentDirsResponseSchema, SessionQuestionFrameSchema, SessionQuestionClearedFrameSchema, AnswerQuestionArgs, AnswerQuestionResponseSchema, CancelQuestionArgs, CancelQuestionResponseSchema, AuthRequestFrameSchema, AuthOkFrameSchema, TunnelExitedEventSchema, InfoRunningSessionSchema, InfoResponseSchema;
4471
+ var SessionStatusSchema, UsageSchema, ContextUsageSchema, sessionMetaShape, SessionMetaSchema, ModelInfoSchema, ModeInfoSchema, ConfigFieldSchemaSchema, CapabilitiesGetArgs, CapabilitiesResponseSchema, AllowRuleSchema, SessionFileSchema, ParsedEventBase, HistoryUserMetaSchema, SubagentToolStatsSchema, StructuredPatchHunkSchema, ToolResultExtraSchema, MemoryEntrySchema, AskQuestionOptionSchema, AskQuestionItemSchema, ParsedEventSchema, SessionCreateArgs, SessionIdArgs, SessionUpdateArgs, SessionSendArgs, SessionRewindArgs, SessionRewindResponseSchema, SessionRewindDiffArgs, RewindDiffHunkSchema, RewindDiffFileSchema, SessionRewindDiffResponseSchema, SessionRewindableMessageIdsArgs, SessionRewindableMessageIdsResponseSchema, SessionResumeArgs, SessionForkArgs, SessionForkResponseSchema, SessionObserveArgs, SessionEventsArgs, PermissionRespondArgs, HistoryListArgs, HistoryReadArgs, HistorySubagentsArgs, HistorySubagentReadArgs, WorkspaceListArgs, WorkspaceReadArgs, SkillsListArgs, SkillEntrySchema, AgentEntrySchema, AgentsListArgs, AgentsListResponseSchema, SessionSubscribeArgs, SessionPinArgs, SessionReorderPinsArgs, GitRootArgs, GitRootResponseSchema, GitBranchArgs, GitBranchResponseSchema, GitBranchesArgs, GitBranchesResponseSchema, HistoryRecentDirsArgs, RecentDirEntrySchema, HistoryRecentDirsResponseSchema, SessionQuestionFrameSchema, SessionQuestionClearedFrameSchema, AnswerQuestionArgs, AnswerQuestionResponseSchema, CancelQuestionArgs, CancelQuestionResponseSchema, AuthRequestFrameSchema, AuthOkFrameSchema, TunnelExitedEventSchema, TunnelUnavailableEventSchema, InfoRunningSessionSchema, InfoResponseSchema;
4474
4472
  var init_schemas = __esm({
4475
4473
  "../protocol/src/schemas.ts"() {
4476
4474
  "use strict";
@@ -4994,6 +4992,11 @@ var init_schemas = __esm({
4994
4992
  subdomain: external_exports.string().nullable(),
4995
4993
  url: external_exports.string().nullable()
4996
4994
  });
4995
+ TunnelUnavailableEventSchema = external_exports.object({
4996
+ type: external_exports.literal("tunnel:unavailable"),
4997
+ reason: external_exports.string().min(1),
4998
+ failedAt: external_exports.string().min(1)
4999
+ });
4997
5000
  InfoRunningSessionSchema = external_exports.object({
4998
5001
  sessionId: external_exports.string().min(1),
4999
5002
  status: SessionStatusSchema,
@@ -5330,8 +5333,8 @@ var require_req = __commonJS({
5330
5333
  if (req.originalUrl) {
5331
5334
  _req.url = req.originalUrl;
5332
5335
  } else {
5333
- const path32 = req.path;
5334
- _req.url = typeof path32 === "string" ? path32 : req.url ? req.url.path || req.url : void 0;
5336
+ const path31 = req.path;
5337
+ _req.url = typeof path31 === "string" ? path31 : req.url ? req.url.path || req.url : void 0;
5335
5338
  }
5336
5339
  if (req.query) {
5337
5340
  _req.query = req.query;
@@ -5496,14 +5499,14 @@ var require_redact = __commonJS({
5496
5499
  }
5497
5500
  return obj;
5498
5501
  }
5499
- function parsePath(path32) {
5502
+ function parsePath(path31) {
5500
5503
  const parts = [];
5501
5504
  let current = "";
5502
5505
  let inBrackets = false;
5503
5506
  let inQuotes = false;
5504
5507
  let quoteChar = "";
5505
- for (let i = 0; i < path32.length; i++) {
5506
- const char = path32[i];
5508
+ for (let i = 0; i < path31.length; i++) {
5509
+ const char = path31[i];
5507
5510
  if (!inBrackets && char === ".") {
5508
5511
  if (current) {
5509
5512
  parts.push(current);
@@ -5634,10 +5637,10 @@ var require_redact = __commonJS({
5634
5637
  return current;
5635
5638
  }
5636
5639
  function redactPaths(obj, paths, censor, remove = false) {
5637
- for (const path32 of paths) {
5638
- const parts = parsePath(path32);
5640
+ for (const path31 of paths) {
5641
+ const parts = parsePath(path31);
5639
5642
  if (parts.includes("*")) {
5640
- redactWildcardPath(obj, parts, censor, path32, remove);
5643
+ redactWildcardPath(obj, parts, censor, path31, remove);
5641
5644
  } else {
5642
5645
  if (remove) {
5643
5646
  removeKey(obj, parts);
@@ -5722,8 +5725,8 @@ var require_redact = __commonJS({
5722
5725
  }
5723
5726
  } else {
5724
5727
  if (afterWildcard.includes("*")) {
5725
- const wrappedCensor = typeof censor === "function" ? (value, path32) => {
5726
- const fullPath = [...pathArray.slice(0, pathLength), ...path32];
5728
+ const wrappedCensor = typeof censor === "function" ? (value, path31) => {
5729
+ const fullPath = [...pathArray.slice(0, pathLength), ...path31];
5727
5730
  return censor(value, fullPath);
5728
5731
  } : censor;
5729
5732
  redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
@@ -5758,8 +5761,8 @@ var require_redact = __commonJS({
5758
5761
  return null;
5759
5762
  }
5760
5763
  const pathStructure = /* @__PURE__ */ new Map();
5761
- for (const path32 of pathsToClone) {
5762
- const parts = parsePath(path32);
5764
+ for (const path31 of pathsToClone) {
5765
+ const parts = parsePath(path31);
5763
5766
  let current = pathStructure;
5764
5767
  for (let i = 0; i < parts.length; i++) {
5765
5768
  const part = parts[i];
@@ -5811,24 +5814,24 @@ var require_redact = __commonJS({
5811
5814
  }
5812
5815
  return cloneSelectively(obj, pathStructure);
5813
5816
  }
5814
- function validatePath(path32) {
5815
- if (typeof path32 !== "string") {
5817
+ function validatePath(path31) {
5818
+ if (typeof path31 !== "string") {
5816
5819
  throw new Error("Paths must be (non-empty) strings");
5817
5820
  }
5818
- if (path32 === "") {
5821
+ if (path31 === "") {
5819
5822
  throw new Error("Invalid redaction path ()");
5820
5823
  }
5821
- if (path32.includes("..")) {
5822
- throw new Error(`Invalid redaction path (${path32})`);
5824
+ if (path31.includes("..")) {
5825
+ throw new Error(`Invalid redaction path (${path31})`);
5823
5826
  }
5824
- if (path32.includes(",")) {
5825
- throw new Error(`Invalid redaction path (${path32})`);
5827
+ if (path31.includes(",")) {
5828
+ throw new Error(`Invalid redaction path (${path31})`);
5826
5829
  }
5827
5830
  let bracketCount = 0;
5828
5831
  let inQuotes = false;
5829
5832
  let quoteChar = "";
5830
- for (let i = 0; i < path32.length; i++) {
5831
- const char = path32[i];
5833
+ for (let i = 0; i < path31.length; i++) {
5834
+ const char = path31[i];
5832
5835
  if ((char === '"' || char === "'") && bracketCount > 0) {
5833
5836
  if (!inQuotes) {
5834
5837
  inQuotes = true;
@@ -5842,20 +5845,20 @@ var require_redact = __commonJS({
5842
5845
  } else if (char === "]" && !inQuotes) {
5843
5846
  bracketCount--;
5844
5847
  if (bracketCount < 0) {
5845
- throw new Error(`Invalid redaction path (${path32})`);
5848
+ throw new Error(`Invalid redaction path (${path31})`);
5846
5849
  }
5847
5850
  }
5848
5851
  }
5849
5852
  if (bracketCount !== 0) {
5850
- throw new Error(`Invalid redaction path (${path32})`);
5853
+ throw new Error(`Invalid redaction path (${path31})`);
5851
5854
  }
5852
5855
  }
5853
5856
  function validatePaths(paths) {
5854
5857
  if (!Array.isArray(paths)) {
5855
5858
  throw new TypeError("paths must be an array");
5856
5859
  }
5857
- for (const path32 of paths) {
5858
- validatePath(path32);
5860
+ for (const path31 of paths) {
5861
+ validatePath(path31);
5859
5862
  }
5860
5863
  }
5861
5864
  function slowRedact(options = {}) {
@@ -6023,8 +6026,8 @@ var require_redaction = __commonJS({
6023
6026
  if (shape[k2] === null) {
6024
6027
  o[k2] = (value) => topCensor(value, [k2]);
6025
6028
  } else {
6026
- const wrappedCensor = typeof censor === "function" ? (value, path32) => {
6027
- return censor(value, [k2, ...path32]);
6029
+ const wrappedCensor = typeof censor === "function" ? (value, path31) => {
6030
+ return censor(value, [k2, ...path31]);
6028
6031
  } : censor;
6029
6032
  o[k2] = Redact({
6030
6033
  paths: shape[k2],
@@ -6245,7 +6248,7 @@ var require_sonic_boom = __commonJS({
6245
6248
  var fs28 = require("fs");
6246
6249
  var EventEmitter2 = require("events");
6247
6250
  var inherits = require("util").inherits;
6248
- var path32 = require("path");
6251
+ var path31 = require("path");
6249
6252
  var sleep = require_atomic_sleep();
6250
6253
  var assert = require("assert");
6251
6254
  var BUSY_WRITE_TIMEOUT = 100;
@@ -6299,7 +6302,7 @@ var require_sonic_boom = __commonJS({
6299
6302
  const mode = sonic.mode;
6300
6303
  if (sonic.sync) {
6301
6304
  try {
6302
- if (sonic.mkdir) fs28.mkdirSync(path32.dirname(file), { recursive: true });
6305
+ if (sonic.mkdir) fs28.mkdirSync(path31.dirname(file), { recursive: true });
6303
6306
  const fd = fs28.openSync(file, flags, mode);
6304
6307
  fileOpened(null, fd);
6305
6308
  } catch (err) {
@@ -6307,7 +6310,7 @@ var require_sonic_boom = __commonJS({
6307
6310
  throw err;
6308
6311
  }
6309
6312
  } else if (sonic.mkdir) {
6310
- fs28.mkdir(path32.dirname(file), { recursive: true }, (err) => {
6313
+ fs28.mkdir(path31.dirname(file), { recursive: true }, (err) => {
6311
6314
  if (err) return fileOpened(err);
6312
6315
  fs28.open(file, flags, mode, fileOpened);
6313
6316
  });
@@ -9938,11 +9941,11 @@ var init_lib = __esm({
9938
9941
  }
9939
9942
  }
9940
9943
  },
9941
- addToPath: function addToPath(path32, added, removed, oldPosInc, options) {
9942
- var last = path32.lastComponent;
9944
+ addToPath: function addToPath(path31, added, removed, oldPosInc, options) {
9945
+ var last = path31.lastComponent;
9943
9946
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
9944
9947
  return {
9945
- oldPos: path32.oldPos + oldPosInc,
9948
+ oldPos: path31.oldPos + oldPosInc,
9946
9949
  lastComponent: {
9947
9950
  count: last.count + 1,
9948
9951
  added,
@@ -9952,7 +9955,7 @@ var init_lib = __esm({
9952
9955
  };
9953
9956
  } else {
9954
9957
  return {
9955
- oldPos: path32.oldPos + oldPosInc,
9958
+ oldPos: path31.oldPos + oldPosInc,
9956
9959
  lastComponent: {
9957
9960
  count: 1,
9958
9961
  added,
@@ -10383,10 +10386,10 @@ function attachmentToHistoryMessage(o, ts) {
10383
10386
  const memories = raw.map((m2) => {
10384
10387
  if (!m2 || typeof m2 !== "object") return null;
10385
10388
  const rec = m2;
10386
- const path32 = typeof rec.path === "string" ? rec.path : null;
10389
+ const path31 = typeof rec.path === "string" ? rec.path : null;
10387
10390
  const content = typeof rec.content === "string" ? rec.content : null;
10388
- if (!path32 || content == null) return null;
10389
- const entry = { path: path32, content };
10391
+ if (!path31 || content == null) return null;
10392
+ const entry = { path: path31, content };
10390
10393
  if (typeof rec.mtimeMs === "number") entry.mtimeMs = rec.mtimeMs;
10391
10394
  return entry;
10392
10395
  }).filter((m2) => m2 !== null);
@@ -11190,10 +11193,10 @@ function parseAttachment(obj) {
11190
11193
  const memories = raw.map((m2) => {
11191
11194
  if (!m2 || typeof m2 !== "object") return null;
11192
11195
  const rec = m2;
11193
- const path32 = typeof rec.path === "string" ? rec.path : null;
11196
+ const path31 = typeof rec.path === "string" ? rec.path : null;
11194
11197
  const content = typeof rec.content === "string" ? rec.content : null;
11195
- if (!path32 || content == null) return null;
11196
- const out = { path: path32, content };
11198
+ if (!path31 || content == null) return null;
11199
+ const out = { path: path31, content };
11197
11200
  if (typeof rec.mtimeMs === "number") out.mtimeMs = rec.mtimeMs;
11198
11201
  return out;
11199
11202
  }).filter((m2) => m2 !== null);
@@ -20107,7 +20110,7 @@ var require_websocket_server = __commonJS({
20107
20110
  // src/run-case/recorder.ts
20108
20111
  function startRunCaseRecorder(opts) {
20109
20112
  const now = opts.now ?? Date.now;
20110
- const dir = import_node_path28.default.dirname(opts.recordPath);
20113
+ const dir = import_node_path27.default.dirname(opts.recordPath);
20111
20114
  let stream = null;
20112
20115
  let closing = false;
20113
20116
  let closedSettled = false;
@@ -20147,12 +20150,12 @@ function startRunCaseRecorder(opts) {
20147
20150
  };
20148
20151
  return { tap, close, closed };
20149
20152
  }
20150
- var import_node_fs25, import_node_path28;
20153
+ var import_node_fs25, import_node_path27;
20151
20154
  var init_recorder = __esm({
20152
20155
  "src/run-case/recorder.ts"() {
20153
20156
  "use strict";
20154
20157
  import_node_fs25 = __toESM(require("fs"), 1);
20155
- import_node_path28 = __toESM(require("path"), 1);
20158
+ import_node_path27 = __toESM(require("path"), 1);
20156
20159
  }
20157
20160
  });
20158
20161
 
@@ -20195,7 +20198,7 @@ var init_wire = __esm({
20195
20198
  // src/run-case/controller.ts
20196
20199
  async function runController(opts) {
20197
20200
  const now = opts.now ?? Date.now;
20198
- const cwd = opts.cwd ?? (0, import_node_fs26.mkdtempSync)(import_node_path29.default.join(import_node_os14.default.tmpdir(), "clawd-runcase-"));
20201
+ const cwd = opts.cwd ?? (0, import_node_fs26.mkdtempSync)(import_node_path28.default.join(import_node_os14.default.tmpdir(), "clawd-runcase-"));
20199
20202
  const ownsCwd = opts.cwd === void 0;
20200
20203
  const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
20201
20204
  const spawnCtx = { cwd };
@@ -20362,13 +20365,13 @@ async function runController(opts) {
20362
20365
  }
20363
20366
  return exitCode ?? 0;
20364
20367
  }
20365
- var import_node_fs26, import_node_os14, import_node_path29;
20368
+ var import_node_fs26, import_node_os14, import_node_path28;
20366
20369
  var init_controller = __esm({
20367
20370
  "src/run-case/controller.ts"() {
20368
20371
  "use strict";
20369
20372
  import_node_fs26 = require("fs");
20370
20373
  import_node_os14 = __toESM(require("os"), 1);
20371
- import_node_path29 = __toESM(require("path"), 1);
20374
+ import_node_path28 = __toESM(require("path"), 1);
20372
20375
  init_claude();
20373
20376
  init_stdout_splitter();
20374
20377
  init_permission_stdio();
@@ -20600,7 +20603,7 @@ Env (advanced):
20600
20603
  `;
20601
20604
 
20602
20605
  // src/index.ts
20603
- var import_node_path27 = __toESM(require("path"), 1);
20606
+ var import_node_path26 = __toESM(require("path"), 1);
20604
20607
  var import_node_fs24 = __toESM(require("fs"), 1);
20605
20608
 
20606
20609
  // src/logger.ts
@@ -26847,24 +26850,14 @@ var AUTH_FILE_NAME = "auth.json";
26847
26850
  function authFilePath(dataDir) {
26848
26851
  return import_node_path22.default.join(dataDir, AUTH_FILE_NAME);
26849
26852
  }
26850
- function loadOrCreateAuthFile(opts) {
26853
+ function loadOrCreateAuthToken(opts) {
26851
26854
  const file = authFilePath(opts.dataDir);
26852
- const generate = opts.generate ?? defaultGenerate;
26853
- const now = opts.now ?? (() => /* @__PURE__ */ new Date());
26854
26855
  const existing = readAuthFile(file);
26855
- if (existing && existing.token && existing.signSecret) {
26856
- return {
26857
- token: existing.token,
26858
- signSecret: existing.signSecret,
26859
- createdAt: existing.createdAt ?? (/* @__PURE__ */ new Date(0)).toISOString()
26860
- };
26861
- }
26862
- const token = existing?.token || generate();
26863
- const signSecret = existing?.signSecret || generate();
26864
- const createdAt = existing?.createdAt || now().toISOString();
26865
- const next = { token, signSecret, createdAt };
26866
- writeAuthFile(file, next);
26867
- return next;
26856
+ if (existing && existing.token) return existing.token;
26857
+ const token = (opts.generate ?? defaultGenerate)();
26858
+ const now = (opts.now ?? (() => /* @__PURE__ */ new Date()))();
26859
+ writeAuthFile(file, { token, createdAt: now.toISOString() });
26860
+ return token;
26868
26861
  }
26869
26862
  function defaultGenerate() {
26870
26863
  return import_node_crypto8.default.randomBytes(32).toString("base64url");
@@ -26873,14 +26866,13 @@ function readAuthFile(file) {
26873
26866
  try {
26874
26867
  const raw = import_node_fs20.default.readFileSync(file, "utf8");
26875
26868
  const parsed = JSON.parse(raw);
26876
- if (typeof parsed?.token !== "string" || parsed.token.length === 0) {
26877
- return null;
26869
+ if (typeof parsed?.token === "string" && parsed.token.length > 0) {
26870
+ return {
26871
+ token: parsed.token,
26872
+ createdAt: typeof parsed.createdAt === "string" ? parsed.createdAt : (/* @__PURE__ */ new Date(0)).toISOString()
26873
+ };
26878
26874
  }
26879
- return {
26880
- token: parsed.token,
26881
- signSecret: typeof parsed.signSecret === "string" && parsed.signSecret.length > 0 ? parsed.signSecret : void 0,
26882
- createdAt: typeof parsed.createdAt === "string" ? parsed.createdAt : void 0
26883
- };
26875
+ return null;
26884
26876
  } catch (err) {
26885
26877
  const code = err?.code;
26886
26878
  if (code === "ENOENT") return null;
@@ -27549,7 +27541,6 @@ function buildPersonaHandlers(deps) {
27549
27541
  }
27550
27542
 
27551
27543
  // src/handlers/attachment.ts
27552
- var import_node_path26 = __toESM(require("path"), 1);
27553
27544
  init_protocol();
27554
27545
  init_protocol();
27555
27546
  var DEFAULT_TTL_SECONDS = 24 * 3600;
@@ -27574,51 +27565,8 @@ function buildAttachmentHandlers(deps) {
27574
27565
  "httpBaseUrl unavailable (daemon HTTP not ready)"
27575
27566
  );
27576
27567
  }
27577
- if (!deps.sessionStore || !deps.getSessionScope || !deps.groupFileStore) {
27578
- throw new ClawdError(
27579
- ERROR_CODES.METHOD_NOT_IMPLEMENTED,
27580
- "signUrl requires session/group stores"
27581
- );
27582
- }
27583
- const sessionFile = deps.sessionStore.read(args.sessionId);
27584
- if (!sessionFile) {
27585
- throw new ClawdError(
27586
- ERROR_CODES.VALIDATION_ERROR,
27587
- `session ${args.sessionId} not found`
27588
- );
27589
- }
27590
- const scope = deps.getSessionScope(args.sessionId);
27591
- if (!scope) {
27592
- throw new ClawdError(
27593
- ERROR_CODES.VALIDATION_ERROR,
27594
- `session ${args.sessionId} scope unresolved`
27595
- );
27596
- }
27597
- const cwdAbs = import_node_path26.default.resolve(sessionFile.cwd);
27598
- const candidateAbs = import_node_path26.default.isAbsolute(args.relPath) ? import_node_path26.default.resolve(args.relPath) : import_node_path26.default.resolve(cwdAbs, args.relPath);
27599
- if (!isContainedIn2(candidateAbs, cwdAbs)) {
27600
- throw new ClawdError(
27601
- ERROR_CODES.VALIDATION_ERROR,
27602
- "relPath escapes session cwd"
27603
- );
27604
- }
27605
- const relPath = import_node_path26.default.relative(cwdAbs, candidateAbs);
27606
- if (relPath === "" || relPath.startsWith("..")) {
27607
- throw new ClawdError(
27608
- ERROR_CODES.VALIDATION_ERROR,
27609
- "relPath escapes session cwd"
27610
- );
27611
- }
27612
- const entries = deps.groupFileStore.list(scope, args.sessionId);
27613
- const entry = entries.find((e) => e.relPath === relPath && !e.stale);
27614
- if (!entry) {
27615
- throw new ClawdError(
27616
- ERROR_CODES.VALIDATION_ERROR,
27617
- `relPath not in session group files or stale: ${relPath}`
27618
- );
27619
- }
27620
27568
  const ttl = args.ttlSeconds === null ? null : args.ttlSeconds ?? DEFAULT_TTL_SECONDS;
27621
- const parts = signUrlParts(secret, candidateAbs, ttl);
27569
+ const parts = signUrlParts(secret, args.absPath, ttl);
27622
27570
  const url = buildSignedFileUrl(httpBaseUrl, parts);
27623
27571
  return {
27624
27572
  response: {
@@ -27704,12 +27652,6 @@ function buildAttachmentHandlers(deps) {
27704
27652
  "attachment.groupListPersona": groupListPersona
27705
27653
  };
27706
27654
  }
27707
- function isContainedIn2(abs, root) {
27708
- const normalized = import_node_path26.default.resolve(abs);
27709
- const normalizedRoot = import_node_path26.default.resolve(root);
27710
- if (normalized === normalizedRoot) return true;
27711
- return normalized.startsWith(normalizedRoot + import_node_path26.default.sep);
27712
- }
27713
27655
 
27714
27656
  // src/handlers/index.ts
27715
27657
  function buildMethodHandlers(deps) {
@@ -27733,7 +27675,7 @@ function buildMethodHandlers(deps) {
27733
27675
  async function startDaemon(config) {
27734
27676
  const logger = createLogger({
27735
27677
  level: config.logLevel,
27736
- file: import_node_path27.default.join(config.dataDir, "clawd.log")
27678
+ file: import_node_path26.default.join(config.dataDir, "clawd.log")
27737
27679
  });
27738
27680
  logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
27739
27681
  const stateMgr = new StateFileManager({ dataDir: config.dataDir });
@@ -27745,12 +27687,10 @@ async function startDaemon(config) {
27745
27687
  logger.warn("stale state file detected, overwriting", { pid: pre.existing.pid });
27746
27688
  }
27747
27689
  let resolvedAuthToken = null;
27748
- let authFile = null;
27749
27690
  if (config.authToken && config.authToken.trim()) {
27750
27691
  resolvedAuthToken = config.authToken.trim();
27751
27692
  } else if (config.tunnel) {
27752
- authFile = loadOrCreateAuthFile({ dataDir: config.dataDir });
27753
- resolvedAuthToken = authFile.token;
27693
+ resolvedAuthToken = loadOrCreateAuthToken({ dataDir: config.dataDir });
27754
27694
  }
27755
27695
  const authMode = resolvedAuthToken == null ? "none" : "first-message";
27756
27696
  let wsServer = null;
@@ -27767,7 +27707,7 @@ async function startDaemon(config) {
27767
27707
  const agents = new AgentsScanner();
27768
27708
  const history = new ClaudeHistoryReader();
27769
27709
  let transport = null;
27770
- const personaStore = new PersonaStore(import_node_path27.default.join(config.dataDir, "personas"));
27710
+ const personaStore = new PersonaStore(import_node_path26.default.join(config.dataDir, "personas"));
27771
27711
  const defaultsRoot = findDefaultsRoot();
27772
27712
  if (defaultsRoot) {
27773
27713
  seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
@@ -27782,7 +27722,7 @@ async function startDaemon(config) {
27782
27722
  getAdapter,
27783
27723
  historyReader: history,
27784
27724
  dataDir: config.dataDir,
27785
- personaRoot: import_node_path27.default.join(config.dataDir, "personas"),
27725
+ personaRoot: import_node_path26.default.join(config.dataDir, "personas"),
27786
27726
  personaStore,
27787
27727
  ownerDisplayName,
27788
27728
  mode: config.mode,
@@ -27805,7 +27745,7 @@ async function startDaemon(config) {
27805
27745
  // 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
27806
27746
  attachmentGroup: {
27807
27747
  onFileEdit: (input) => {
27808
- const absPath = import_node_path27.default.isAbsolute(input.relPath) ? input.relPath : import_node_path27.default.join(input.cwd, input.relPath);
27748
+ const absPath = import_node_path26.default.isAbsolute(input.relPath) ? input.relPath : import_node_path26.default.join(input.cwd, input.relPath);
27809
27749
  let size = 0;
27810
27750
  try {
27811
27751
  size = import_node_fs24.default.statSync(absPath).size;
@@ -27906,12 +27846,11 @@ async function startDaemon(config) {
27906
27846
  // 根据 sessionId 反查 scope 写盘。
27907
27847
  attachment: {
27908
27848
  groupFileStore,
27909
- sessionStore: store,
27910
27849
  getHttpBaseUrl,
27911
- // HMAC sign secret:~/.clawd/auth.json signSecret 字段(与 WS Bearer token 独立)。
27912
- // --auth-token CLI 模式 / noAuth 模式 authFile 为 null → handler 自己返 NOT_IMPLEMENTED。
27913
- getSignSecret: () => authFile?.signSecret ?? "",
27914
- // group RPC + sign 都用:根据 sessionId 反查 scope;owner-mode persona session 走
27850
+ // HMAC sign secret:复用 ~/.clawd/auth.json owner token(持久跨重启)。
27851
+ // noAuth 模式 resolvedAuthToken 为 null → handler 自己返 NOT_IMPLEMENTED。
27852
+ getSignSecret: () => resolvedAuthToken ?? "",
27853
+ // group RPC:根据 sessionId 反查 scope;owner-mode persona session 走
27915
27854
  // 'persona/<pid>/owner',default 走 'default'。
27916
27855
  getSessionScope: (sessionId) => {
27917
27856
  const file = store.read(sessionId);
@@ -27934,9 +27873,8 @@ async function startDaemon(config) {
27934
27873
  personaStore,
27935
27874
  groupFileStore,
27936
27875
  sessionStore: store,
27937
- // /files HMAC verify auth.json signSecret 字段(与 attachment.signUrl 同源)。
27938
- // --auth-token CLI 模式没 signSecret → 路由返 501,sign URL 功能整体禁用。
27939
- getSignSecret: () => authFile?.signSecret ?? null
27876
+ // /files HMAC verify 用同一份 owner token secret(与 attachment.signUrl 同源)
27877
+ getSignSecret: () => resolvedAuthToken ?? null
27940
27878
  });
27941
27879
  wsServer = new LocalWsServer({
27942
27880
  host: config.host,
@@ -28067,15 +28005,15 @@ async function startDaemon(config) {
28067
28005
  });
28068
28006
  try {
28069
28007
  const r = await tunnelMgr.start({ localPort: config.port });
28070
- stateSnapshot = { ...stateSnapshot, tunnelUrl: r.url };
28008
+ stateSnapshot = { ...stateSnapshot, tunnelUrl: r.url, tunnelError: void 0 };
28071
28009
  stateMgr.write(stateSnapshot);
28072
28010
  currentTunnelUrl = r.url;
28073
28011
  const connectUrl = resolvedAuthToken ? `${r.url}#token=${resolvedAuthToken}` : r.url;
28074
28012
  const lines = [
28075
28013
  `Tunnel: ${r.url}`,
28076
28014
  ...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
28077
- `Frpc config: ${import_node_path27.default.join(config.dataDir, "frpc.toml")}`,
28078
- `Frpc log: ${import_node_path27.default.join(config.dataDir, "frpc.log")}`
28015
+ `Frpc config: ${import_node_path26.default.join(config.dataDir, "frpc.toml")}`,
28016
+ `Frpc log: ${import_node_path26.default.join(config.dataDir, "frpc.log")}`
28079
28017
  ];
28080
28018
  const width = Math.max(...lines.map((l) => l.length));
28081
28019
  const bar = "\u2550".repeat(width + 4);
@@ -28088,19 +28026,30 @@ ${bar}
28088
28026
 
28089
28027
  `);
28090
28028
  try {
28091
- const connectPath = import_node_path27.default.join(config.dataDir, "connect.txt");
28029
+ const connectPath = import_node_path26.default.join(config.dataDir, "connect.txt");
28092
28030
  import_node_fs24.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
28093
28031
  } catch {
28094
28032
  }
28095
28033
  } catch (err) {
28034
+ const tunnelError = err?.message ?? String(err);
28096
28035
  try {
28097
28036
  await tunnelMgr.stop();
28098
28037
  } catch {
28099
28038
  }
28100
28039
  tunnelMgr = null;
28101
- stateMgr.delete();
28102
- await wss.stop();
28103
- throw err;
28040
+ stateSnapshot = { ...stateSnapshot, tunnelUrl: void 0, tunnelError };
28041
+ try {
28042
+ stateMgr.write(stateSnapshot);
28043
+ } catch {
28044
+ }
28045
+ wss.broadcastAll({
28046
+ type: "tunnel:unavailable",
28047
+ reason: tunnelError,
28048
+ failedAt: (/* @__PURE__ */ new Date()).toISOString()
28049
+ });
28050
+ process.stdout.write(`Tunnel: unavailable (local mode) \u2014 ${tunnelError}
28051
+ `);
28052
+ logger.warn("tunnel unavailable, degraded to local mode", { reason: tunnelError });
28104
28053
  }
28105
28054
  }
28106
28055
  const shutdown = async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawos-dev/clawd",
3
- "version": "0.2.67",
3
+ "version": "0.2.69-beta.120.2a41cd5",
4
4
  "description": "Standalone clawd daemon — Claude Code (and future Codex) session server over WebSocket",
5
5
  "type": "module",
6
6
  "license": "MIT",