@clawos-dev/clawd 0.2.227 → 0.2.229

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.
@@ -3227,8 +3227,8 @@ var require_utils = __commonJS({
3227
3227
  }
3228
3228
  return ind;
3229
3229
  }
3230
- function removeDotSegments(path) {
3231
- let input = path;
3230
+ function removeDotSegments(path2) {
3231
+ let input = path2;
3232
3232
  const output = [];
3233
3233
  let nextSlash = -1;
3234
3234
  let len = 0;
@@ -3480,8 +3480,8 @@ var require_schemes = __commonJS({
3480
3480
  wsComponent.secure = void 0;
3481
3481
  }
3482
3482
  if (wsComponent.resourceName) {
3483
- const [path, query] = wsComponent.resourceName.split("?");
3484
- wsComponent.path = path && path !== "/" ? path : void 0;
3483
+ const [path2, query] = wsComponent.resourceName.split("?");
3484
+ wsComponent.path = path2 && path2 !== "/" ? path2 : void 0;
3485
3485
  wsComponent.query = query;
3486
3486
  wsComponent.resourceName = void 0;
3487
3487
  }
@@ -6874,12 +6874,12 @@ var require_dist = __commonJS({
6874
6874
  throw new Error(`Unknown format "${name}"`);
6875
6875
  return f;
6876
6876
  };
6877
- function addFormats(ajv, list, fs2, exportName) {
6877
+ function addFormats(ajv, list, fs4, exportName) {
6878
6878
  var _a;
6879
6879
  var _b;
6880
6880
  (_a = (_b = ajv.opts.code).formats) !== null && _a !== void 0 ? _a : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
6881
6881
  for (const f of list)
6882
- ajv.addFormat(f, fs2[f]);
6882
+ ajv.addFormat(f, fs4[f]);
6883
6883
  }
6884
6884
  module2.exports = exports2 = formatsPlugin;
6885
6885
  Object.defineProperty(exports2, "__esModule", { value: true });
@@ -7690,14 +7690,14 @@ var require_util2 = __commonJS({
7690
7690
  }
7691
7691
  const port = url.port != null ? url.port : url.protocol === "https:" ? 443 : 80;
7692
7692
  let origin = url.origin != null ? url.origin : `${url.protocol || ""}//${url.hostname || ""}:${port}`;
7693
- let path = url.path != null ? url.path : `${url.pathname || ""}${url.search || ""}`;
7693
+ let path2 = url.path != null ? url.path : `${url.pathname || ""}${url.search || ""}`;
7694
7694
  if (origin[origin.length - 1] === "/") {
7695
7695
  origin = origin.slice(0, origin.length - 1);
7696
7696
  }
7697
- if (path && path[0] !== "/") {
7698
- path = `/${path}`;
7697
+ if (path2 && path2[0] !== "/") {
7698
+ path2 = `/${path2}`;
7699
7699
  }
7700
- return new URL(`${origin}${path}`);
7700
+ return new URL(`${origin}${path2}`);
7701
7701
  }
7702
7702
  if (!isHttpOrHttpsPrefixed(url.origin || url.protocol)) {
7703
7703
  throw new InvalidArgumentError("Invalid URL protocol: the URL must start with `http:` or `https:`.");
@@ -8148,39 +8148,39 @@ var require_diagnostics = __commonJS({
8148
8148
  });
8149
8149
  diagnosticsChannel.channel("undici:client:sendHeaders").subscribe((evt) => {
8150
8150
  const {
8151
- request: { method, path, origin }
8151
+ request: { method, path: path2, origin }
8152
8152
  } = evt;
8153
- debuglog("sending request to %s %s/%s", method, origin, path);
8153
+ debuglog("sending request to %s %s/%s", method, origin, path2);
8154
8154
  });
8155
8155
  diagnosticsChannel.channel("undici:request:headers").subscribe((evt) => {
8156
8156
  const {
8157
- request: { method, path, origin },
8157
+ request: { method, path: path2, origin },
8158
8158
  response: { statusCode }
8159
8159
  } = evt;
8160
8160
  debuglog(
8161
8161
  "received response to %s %s/%s - HTTP %d",
8162
8162
  method,
8163
8163
  origin,
8164
- path,
8164
+ path2,
8165
8165
  statusCode
8166
8166
  );
8167
8167
  });
8168
8168
  diagnosticsChannel.channel("undici:request:trailers").subscribe((evt) => {
8169
8169
  const {
8170
- request: { method, path, origin }
8170
+ request: { method, path: path2, origin }
8171
8171
  } = evt;
8172
- debuglog("trailers received from %s %s/%s", method, origin, path);
8172
+ debuglog("trailers received from %s %s/%s", method, origin, path2);
8173
8173
  });
8174
8174
  diagnosticsChannel.channel("undici:request:error").subscribe((evt) => {
8175
8175
  const {
8176
- request: { method, path, origin },
8176
+ request: { method, path: path2, origin },
8177
8177
  error: error2
8178
8178
  } = evt;
8179
8179
  debuglog(
8180
8180
  "request to %s %s/%s errored - %s",
8181
8181
  method,
8182
8182
  origin,
8183
- path,
8183
+ path2,
8184
8184
  error2.message
8185
8185
  );
8186
8186
  });
@@ -8229,9 +8229,9 @@ var require_diagnostics = __commonJS({
8229
8229
  });
8230
8230
  diagnosticsChannel.channel("undici:client:sendHeaders").subscribe((evt) => {
8231
8231
  const {
8232
- request: { method, path, origin }
8232
+ request: { method, path: path2, origin }
8233
8233
  } = evt;
8234
- debuglog("sending request to %s %s/%s", method, origin, path);
8234
+ debuglog("sending request to %s %s/%s", method, origin, path2);
8235
8235
  });
8236
8236
  }
8237
8237
  diagnosticsChannel.channel("undici:websocket:open").subscribe((evt) => {
@@ -8294,7 +8294,7 @@ var require_request = __commonJS({
8294
8294
  var kHandler = /* @__PURE__ */ Symbol("handler");
8295
8295
  var Request = class {
8296
8296
  constructor(origin, {
8297
- path,
8297
+ path: path2,
8298
8298
  method,
8299
8299
  body,
8300
8300
  headers,
@@ -8309,11 +8309,11 @@ var require_request = __commonJS({
8309
8309
  expectContinue,
8310
8310
  servername
8311
8311
  }, handler) {
8312
- if (typeof path !== "string") {
8312
+ if (typeof path2 !== "string") {
8313
8313
  throw new InvalidArgumentError("path must be a string");
8314
- } else if (path[0] !== "/" && !(path.startsWith("http://") || path.startsWith("https://")) && method !== "CONNECT") {
8314
+ } else if (path2[0] !== "/" && !(path2.startsWith("http://") || path2.startsWith("https://")) && method !== "CONNECT") {
8315
8315
  throw new InvalidArgumentError("path must be an absolute URL or start with a slash");
8316
- } else if (invalidPathRegex.test(path)) {
8316
+ } else if (invalidPathRegex.test(path2)) {
8317
8317
  throw new InvalidArgumentError("invalid request path");
8318
8318
  }
8319
8319
  if (typeof method !== "string") {
@@ -8379,7 +8379,7 @@ var require_request = __commonJS({
8379
8379
  this.completed = false;
8380
8380
  this.aborted = false;
8381
8381
  this.upgrade = upgrade || null;
8382
- this.path = query ? buildURL(path, query) : path;
8382
+ this.path = query ? buildURL(path2, query) : path2;
8383
8383
  this.origin = origin;
8384
8384
  this.idempotent = idempotent == null ? method === "HEAD" || method === "GET" : idempotent;
8385
8385
  this.blocking = blocking == null ? false : blocking;
@@ -12943,7 +12943,7 @@ var require_client_h1 = __commonJS({
12943
12943
  return method !== "GET" && method !== "HEAD" && method !== "OPTIONS" && method !== "TRACE" && method !== "CONNECT";
12944
12944
  }
12945
12945
  function writeH1(client, request) {
12946
- const { method, path, host, upgrade, blocking, reset } = request;
12946
+ const { method, path: path2, host, upgrade, blocking, reset } = request;
12947
12947
  let { body, headers, contentLength } = request;
12948
12948
  const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH" || method === "QUERY" || method === "PROPFIND" || method === "PROPPATCH";
12949
12949
  if (util2.isFormDataLike(body)) {
@@ -13009,7 +13009,7 @@ var require_client_h1 = __commonJS({
13009
13009
  if (blocking) {
13010
13010
  socket[kBlocking] = true;
13011
13011
  }
13012
- let header = `${method} ${path} HTTP/1.1\r
13012
+ let header = `${method} ${path2} HTTP/1.1\r
13013
13013
  `;
13014
13014
  if (typeof host === "string") {
13015
13015
  header += `host: ${host}\r
@@ -13535,7 +13535,7 @@ var require_client_h2 = __commonJS({
13535
13535
  }
13536
13536
  function writeH2(client, request) {
13537
13537
  const session = client[kHTTP2Session];
13538
- const { method, path, host, upgrade, expectContinue, signal, headers: reqHeaders } = request;
13538
+ const { method, path: path2, host, upgrade, expectContinue, signal, headers: reqHeaders } = request;
13539
13539
  let { body } = request;
13540
13540
  if (upgrade) {
13541
13541
  util2.errorRequest(client, request, new Error("Upgrade not supported for H2"));
@@ -13602,7 +13602,7 @@ var require_client_h2 = __commonJS({
13602
13602
  });
13603
13603
  return true;
13604
13604
  }
13605
- headers[HTTP2_HEADER_PATH] = path;
13605
+ headers[HTTP2_HEADER_PATH] = path2;
13606
13606
  headers[HTTP2_HEADER_SCHEME] = "https";
13607
13607
  const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH";
13608
13608
  if (body && typeof body.read === "function") {
@@ -13955,9 +13955,9 @@ var require_redirect_handler = __commonJS({
13955
13955
  return this.handler.onHeaders(statusCode, headers, resume, statusText);
13956
13956
  }
13957
13957
  const { origin, pathname, search } = util2.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin)));
13958
- const path = search ? `${pathname}${search}` : pathname;
13958
+ const path2 = search ? `${pathname}${search}` : pathname;
13959
13959
  this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin);
13960
- this.opts.path = path;
13960
+ this.opts.path = path2;
13961
13961
  this.opts.origin = origin;
13962
13962
  this.opts.maxRedirections = 0;
13963
13963
  this.opts.query = null;
@@ -15193,10 +15193,10 @@ var require_proxy_agent = __commonJS({
15193
15193
  };
15194
15194
  const {
15195
15195
  origin,
15196
- path = "/",
15196
+ path: path2 = "/",
15197
15197
  headers = {}
15198
15198
  } = opts;
15199
- opts.path = origin + path;
15199
+ opts.path = origin + path2;
15200
15200
  if (!("host" in headers) && !("Host" in headers)) {
15201
15201
  const { host } = new URL2(origin);
15202
15202
  headers.host = host;
@@ -17119,20 +17119,20 @@ var require_mock_utils = __commonJS({
17119
17119
  }
17120
17120
  return true;
17121
17121
  }
17122
- function safeUrl(path) {
17123
- if (typeof path !== "string") {
17124
- return path;
17122
+ function safeUrl(path2) {
17123
+ if (typeof path2 !== "string") {
17124
+ return path2;
17125
17125
  }
17126
- const pathSegments = path.split("?");
17126
+ const pathSegments = path2.split("?");
17127
17127
  if (pathSegments.length !== 2) {
17128
- return path;
17128
+ return path2;
17129
17129
  }
17130
17130
  const qp = new URLSearchParams(pathSegments.pop());
17131
17131
  qp.sort();
17132
17132
  return [...pathSegments, qp.toString()].join("?");
17133
17133
  }
17134
- function matchKey(mockDispatch2, { path, method, body, headers }) {
17135
- const pathMatch = matchValue(mockDispatch2.path, path);
17134
+ function matchKey(mockDispatch2, { path: path2, method, body, headers }) {
17135
+ const pathMatch = matchValue(mockDispatch2.path, path2);
17136
17136
  const methodMatch = matchValue(mockDispatch2.method, method);
17137
17137
  const bodyMatch = typeof mockDispatch2.body !== "undefined" ? matchValue(mockDispatch2.body, body) : true;
17138
17138
  const headersMatch = matchHeaders(mockDispatch2, headers);
@@ -17154,7 +17154,7 @@ var require_mock_utils = __commonJS({
17154
17154
  function getMockDispatch(mockDispatches, key) {
17155
17155
  const basePath = key.query ? buildURL(key.path, key.query) : key.path;
17156
17156
  const resolvedPath = typeof basePath === "string" ? safeUrl(basePath) : basePath;
17157
- let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path }) => matchValue(safeUrl(path), resolvedPath));
17157
+ let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path2 }) => matchValue(safeUrl(path2), resolvedPath));
17158
17158
  if (matchedMockDispatches.length === 0) {
17159
17159
  throw new MockNotMatchedError(`Mock dispatch not matched for path '${resolvedPath}'`);
17160
17160
  }
@@ -17192,9 +17192,9 @@ var require_mock_utils = __commonJS({
17192
17192
  }
17193
17193
  }
17194
17194
  function buildKey(opts) {
17195
- const { path, method, body, headers, query } = opts;
17195
+ const { path: path2, method, body, headers, query } = opts;
17196
17196
  return {
17197
- path,
17197
+ path: path2,
17198
17198
  method,
17199
17199
  body,
17200
17200
  headers,
@@ -17657,10 +17657,10 @@ var require_pending_interceptors_formatter = __commonJS({
17657
17657
  }
17658
17658
  format(pendingInterceptors) {
17659
17659
  const withPrettyHeaders = pendingInterceptors.map(
17660
- ({ method, path, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
17660
+ ({ method, path: path2, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
17661
17661
  Method: method,
17662
17662
  Origin: origin,
17663
- Path: path,
17663
+ Path: path2,
17664
17664
  "Status code": statusCode,
17665
17665
  Persistent: persist ? PERSISTENT : NOT_PERSISTENT,
17666
17666
  Invocations: timesInvoked,
@@ -22541,9 +22541,9 @@ var require_util7 = __commonJS({
22541
22541
  }
22542
22542
  }
22543
22543
  }
22544
- function validateCookiePath(path) {
22545
- for (let i = 0; i < path.length; ++i) {
22546
- const code = path.charCodeAt(i);
22544
+ function validateCookiePath(path2) {
22545
+ for (let i = 0; i < path2.length; ++i) {
22546
+ const code = path2.charCodeAt(i);
22547
22547
  if (code < 32 || // exclude CTLs (0-31)
22548
22548
  code === 127 || // DEL
22549
22549
  code === 59) {
@@ -25220,11 +25220,11 @@ var require_undici = __commonJS({
25220
25220
  if (typeof opts.path !== "string") {
25221
25221
  throw new InvalidArgumentError("invalid opts.path");
25222
25222
  }
25223
- let path = opts.path;
25223
+ let path2 = opts.path;
25224
25224
  if (!opts.path.startsWith("/")) {
25225
- path = `/${path}`;
25225
+ path2 = `/${path2}`;
25226
25226
  }
25227
- url = new URL(util2.parseOrigin(url).origin + path);
25227
+ url = new URL(util2.parseOrigin(url).origin + path2);
25228
25228
  } else {
25229
25229
  if (!opts) {
25230
25230
  opts = typeof url === "object" ? url : {};
@@ -25304,7 +25304,7 @@ __export(mcp_server_exports, {
25304
25304
  handlePersonaDispatchToolCall: () => handlePersonaDispatchToolCall
25305
25305
  });
25306
25306
  module.exports = __toCommonJS(mcp_server_exports);
25307
- var import_node_fs = __toESM(require("fs"), 1);
25307
+ var import_node_fs3 = __toESM(require("fs"), 1);
25308
25308
 
25309
25309
  // ../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.js
25310
25310
  var external_exports = {};
@@ -25784,8 +25784,8 @@ function getErrorMap() {
25784
25784
 
25785
25785
  // ../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
25786
25786
  var makeIssue = (params) => {
25787
- const { data, path, errorMaps, issueData } = params;
25788
- const fullPath = [...path, ...issueData.path || []];
25787
+ const { data, path: path2, errorMaps, issueData } = params;
25788
+ const fullPath = [...path2, ...issueData.path || []];
25789
25789
  const fullIssue = {
25790
25790
  ...issueData,
25791
25791
  path: fullPath
@@ -25901,11 +25901,11 @@ var errorUtil;
25901
25901
 
25902
25902
  // ../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js
25903
25903
  var ParseInputLazyPath = class {
25904
- constructor(parent, value, path, key) {
25904
+ constructor(parent, value, path2, key) {
25905
25905
  this._cachedPath = [];
25906
25906
  this.parent = parent;
25907
25907
  this.data = value;
25908
- this._path = path;
25908
+ this._path = path2;
25909
25909
  this._key = key;
25910
25910
  }
25911
25911
  get path() {
@@ -29542,10 +29542,10 @@ function assignProp(target, prop, value) {
29542
29542
  configurable: true
29543
29543
  });
29544
29544
  }
29545
- function getElementAtPath(obj, path) {
29546
- if (!path)
29545
+ function getElementAtPath(obj, path2) {
29546
+ if (!path2)
29547
29547
  return obj;
29548
- return path.reduce((acc, key) => acc?.[key], obj);
29548
+ return path2.reduce((acc, key) => acc?.[key], obj);
29549
29549
  }
29550
29550
  function promiseAllObject(promisesObj) {
29551
29551
  const keys = Object.keys(promisesObj);
@@ -29865,11 +29865,11 @@ function aborted(x, startIndex = 0) {
29865
29865
  }
29866
29866
  return false;
29867
29867
  }
29868
- function prefixIssues(path, issues) {
29868
+ function prefixIssues(path2, issues) {
29869
29869
  return issues.map((iss) => {
29870
29870
  var _a;
29871
29871
  (_a = iss).path ?? (_a.path = []);
29872
- iss.path.unshift(path);
29872
+ iss.path.unshift(path2);
29873
29873
  return iss;
29874
29874
  });
29875
29875
  }
@@ -39520,6 +39520,2210 @@ var StdioServerTransport = class {
39520
39520
 
39521
39521
  // src/dispatch/mcp-server.ts
39522
39522
  var import_undici = __toESM(require_undici(), 1);
39523
+
39524
+ // src/tools/claude.ts
39525
+ var import_node_child_process = require("child_process");
39526
+ var import_node_child_process2 = require("child_process");
39527
+ var import_node_fs2 = __toESM(require("fs"), 1);
39528
+
39529
+ // ../protocol/src/events.ts
39530
+ var SESSION_STATUS_VALUES = [
39531
+ "idle",
39532
+ "running",
39533
+ "running-idle",
39534
+ "stopped",
39535
+ "error",
39536
+ "observing"
39537
+ ];
39538
+ var HISTORY_USER_META_VALUES = [
39539
+ "task-notification",
39540
+ "slash-command",
39541
+ "local-command",
39542
+ "system-reminder",
39543
+ "skill-hint",
39544
+ "meta-text",
39545
+ "attachment-skills",
39546
+ "attachment-deferred-tools"
39547
+ ];
39548
+ var SKILL_SOURCE_VALUES = ["builtin", "global", "project", "plugin"];
39549
+ var AGENT_SOURCE_VALUES = [
39550
+ "builtin",
39551
+ "global",
39552
+ "project",
39553
+ "policy",
39554
+ "plugin"
39555
+ ];
39556
+
39557
+ // ../protocol/src/attachment-schemas.ts
39558
+ var TOKEN_ROLES = ["owner"];
39559
+ var GROUP_FILE_SOURCES = ["agent", "owner", "user-upload"];
39560
+ var GroupFileEntrySchema = external_exports.object({
39561
+ /** daemon 派发的稳定 id(用于 RPC remove / UI key) */
39562
+ id: external_exports.string().min(1),
39563
+ /** 相对 personaDir / sessionCwd 的路径 */
39564
+ relPath: external_exports.string().min(1),
39565
+ from: external_exports.enum(GROUP_FILE_SOURCES),
39566
+ /** owner 手动加入时的可选备注 */
39567
+ label: external_exports.string().optional(),
39568
+ /** 文件字节数(stat 时拍) */
39569
+ size: external_exports.number().int().nonnegative(),
39570
+ mime: external_exports.string().min(1),
39571
+ /** 加入清单时间戳(ms) */
39572
+ addedAt: external_exports.number().int().nonnegative(),
39573
+ /** 最近一次 agent Write/Edit 时间戳(agent 反复改同 path 时更新) */
39574
+ lastEditedAt: external_exports.number().int().nonnegative().optional(),
39575
+ /** agent rm / 文件不见了时打标;UI 灰显,不能再 share */
39576
+ stale: external_exports.boolean().optional()
39577
+ });
39578
+ var AttachmentSignUrlArgs = external_exports.object({
39579
+ /** 群文件所属的 session */
39580
+ sessionId: external_exports.string().min(1),
39581
+ /** 相对 session.cwd 的路径;允许传绝对路径,daemon 端会归一化(必须在 cwd 内) */
39582
+ relPath: external_exports.string().min(1),
39583
+ /** TTL 秒数;缺省 24h;null 走永久 URL(不带 exp 字段) */
39584
+ ttlSeconds: external_exports.number().int().positive().nullable().optional(),
39585
+ /** 视图模式:缺省 'raw' 返 /files/... 裸文件 URL;'md-rendered' 返
39586
+ * /share/md/... viewer URL(同一签名,daemon 端换前缀),外人浏览器打开就是
39587
+ * drawer 同款 ReactMarkdown 渲染。FilesDrawer 等不关心渲染的 caller 不传。 */
39588
+ view: external_exports.enum(["raw", "md-rendered"]).optional()
39589
+ });
39590
+ var AttachmentSignUrlResponseSchema = external_exports.object({
39591
+ /** 完整 URL(含 httpBaseUrl 前缀),UI 直接 window.open / 复制到剪贴板 */
39592
+ url: external_exports.string().min(1),
39593
+ /** 失效时间戳(ms);null = 永久 */
39594
+ expiresAt: external_exports.number().int().nonnegative().nullable()
39595
+ });
39596
+ var AttachmentGroupAddArgs = external_exports.object({
39597
+ sessionId: external_exports.string().min(1),
39598
+ relPath: external_exports.string().min(1),
39599
+ /** owner 手动加入时可选备注;agent 自动入清单不走此 RPC */
39600
+ label: external_exports.string().optional()
39601
+ });
39602
+ var AttachmentGroupAddResponseSchema = external_exports.object({
39603
+ entry: GroupFileEntrySchema
39604
+ });
39605
+ var AttachmentGroupRemoveArgs = external_exports.object({
39606
+ sessionId: external_exports.string().min(1),
39607
+ relPath: external_exports.string().min(1)
39608
+ });
39609
+ var AttachmentGroupRemoveResponseSchema = external_exports.object({
39610
+ removed: external_exports.literal(true)
39611
+ });
39612
+ var AttachmentGroupListArgs = external_exports.object({
39613
+ sessionId: external_exports.string().min(1)
39614
+ });
39615
+ var AttachmentGroupListResponseSchema = external_exports.object({
39616
+ entries: external_exports.array(GroupFileEntrySchema)
39617
+ });
39618
+ var AttachmentUploadResponseSchema = external_exports.object({
39619
+ /** sha256(bytes) 前 16 位,前端持有的稳定 ref */
39620
+ attachmentId: external_exports.string().min(1),
39621
+ /** 完整 tunnel signed URL,前端拼 marker / 直接送 Anthropic 都用它 */
39622
+ url: external_exports.string().min(1),
39623
+ /** 落在 session 目录下的相对路径(后续 group RPC / drawer 展示用) */
39624
+ relPath: external_exports.string().min(1),
39625
+ sizeBytes: external_exports.number().int().nonnegative(),
39626
+ mimeType: external_exports.string().min(1)
39627
+ });
39628
+
39629
+ // ../protocol/src/principal.ts
39630
+ var PrincipalKindSchema = external_exports.enum(["owner", "guest"]);
39631
+ var PrincipalSchema = external_exports.object({
39632
+ id: external_exports.string().min(1),
39633
+ kind: PrincipalKindSchema,
39634
+ displayName: external_exports.string(),
39635
+ /**
39636
+ * 飞书 union_id。owner: 本机 daemon 已飞书登录时透传自 owner-identity.json;未登录 undefined。
39637
+ * guest: v1 保持 undefined(connect token 当前不携带 unionId;未来若签名 payload 加字段可透传)。
39638
+ * 消费方(如 ticket MCP / 未来别的飞书身份挂钩场景)按 undefined 决定是否降级;本层不做 fallback。
39639
+ */
39640
+ feishuUnionId: external_exports.string().optional()
39641
+ }).strict();
39642
+ var SenderInfoSchema = external_exports.object({
39643
+ /** = principal.id = deviceId(决策 #16)。稳定路由 id */
39644
+ did: external_exports.string().min(1),
39645
+ displayName: external_exports.string(),
39646
+ /** owner 未登录 / guest 无飞书身份时缺省。消费方各自决定是否降级 */
39647
+ feishuUnionId: external_exports.string().optional(),
39648
+ principal: PrincipalKindSchema
39649
+ }).strict();
39650
+
39651
+ // ../protocol/src/persona-schemas.ts
39652
+ var PersonaFileSchema = external_exports.object({
39653
+ personaId: external_exports.string(),
39654
+ label: external_exports.string(),
39655
+ model: external_exports.string().optional(),
39656
+ public: external_exports.boolean(),
39657
+ // 8-key set defined UI-side in `lib/session-icons.ts`; protocol stays plain string
39658
+ // for forward compatibility, consumer fallbacks to default when key not found.
39659
+ iconKey: external_exports.string().optional(),
39660
+ // 绑定的 agent tool('claude' / 'codex');缺省消费侧按 'claude' 兜底。
39661
+ // 与 model 平行:persona 新建 session 的默认 tool,可平滑切换。
39662
+ tool: external_exports.string().optional(),
39663
+ createdAt: external_exports.number(),
39664
+ updatedAt: external_exports.number()
39665
+ }).strict();
39666
+ var PersonaSkillSummarySchema = external_exports.object({
39667
+ // 目录名作为 skill name(对齐 CC:frontmatter `name:` 仅作 displayName 用)
39668
+ name: external_exports.string().min(1),
39669
+ // SKILL.md frontmatter `description:`;缺省时省略字段
39670
+ description: external_exports.string().optional()
39671
+ });
39672
+ var PersonaPluginSummarySchema = external_exports.object({
39673
+ // settings.json 中 enabledPlugins 的 key,例如 'superpowers@claude-plugins-official'
39674
+ id: external_exports.string().min(1)
39675
+ });
39676
+ var PersonaSandboxSettingsSchema = external_exports.object({
39677
+ permissions: external_exports.object({
39678
+ defaultMode: external_exports.string().optional(),
39679
+ // CC 工具 allowlist('Bash'/'Read'/...)。per-persona profile 在最严格 base 上追加放开。
39680
+ allow: external_exports.array(external_exports.string()).optional(),
39681
+ // deny 优先级最高;强制底座(persona 私密区)由 daemon compose 强制 union,owner 删不掉。
39682
+ deny: external_exports.array(external_exports.string()).optional()
39683
+ }).optional(),
39684
+ sandbox: external_exports.object({
39685
+ enabled: external_exports.boolean().optional(),
39686
+ autoAllowBashIfSandboxed: external_exports.boolean().optional(),
39687
+ allowUnsandboxedCommands: external_exports.boolean().optional(),
39688
+ // 命令前缀白名单(CC `sandbox.excludedCommands`):匹配的命令在沙箱外运行,
39689
+ // 用于需逃出沙箱的工具(如 'docker *' / 'aliyun *' 要访问宿主 socket / 凭证)。
39690
+ excludedCommands: external_exports.array(external_exports.string()).optional(),
39691
+ filesystem: external_exports.object({
39692
+ denyRead: external_exports.array(external_exports.string()).optional(),
39693
+ allowRead: external_exports.array(external_exports.string()).optional(),
39694
+ denyWrite: external_exports.array(external_exports.string()).optional(),
39695
+ allowWrite: external_exports.array(external_exports.string()).optional()
39696
+ }).optional(),
39697
+ // 出站网络 + 本机端口。base 不放(空),profile 按需追加域名(app-builder = ['*'])。
39698
+ network: external_exports.object({
39699
+ allowedDomains: external_exports.array(external_exports.string()).optional(),
39700
+ allowLocalBinding: external_exports.boolean().optional()
39701
+ }).optional()
39702
+ }).optional()
39703
+ });
39704
+ var PersonaInfoResponseSchema = PersonaFileSchema.extend({
39705
+ personality: external_exports.string().optional(),
39706
+ // 仅 'persona:get' 携带;null = 文件不存在 / parse 失败;undefined = 不在该响应类型上
39707
+ skills: external_exports.array(PersonaSkillSummarySchema).optional(),
39708
+ // 仅 'persona:get' 携带;空数组 = 没启用任何插件 / settings.json 不存在;undefined = 不在该响应类型上
39709
+ plugins: external_exports.array(PersonaPluginSummarySchema).optional(),
39710
+ sandboxSettings: PersonaSandboxSettingsSchema.nullable().optional()
39711
+ });
39712
+ var PersonaCreateArgsSchema = external_exports.object({
39713
+ label: external_exports.string().min(1),
39714
+ personality: external_exports.string(),
39715
+ model: external_exports.string().optional(),
39716
+ tool: external_exports.string().optional(),
39717
+ public: external_exports.boolean().optional(),
39718
+ iconKey: external_exports.string().optional()
39719
+ }).strict();
39720
+ var PersonaIdArgsSchema = external_exports.object({
39721
+ personaId: external_exports.string().min(1)
39722
+ });
39723
+ var PersonaUpdateArgsSchema = external_exports.object({
39724
+ personaId: external_exports.string().min(1),
39725
+ patch: external_exports.object({
39726
+ label: external_exports.string().min(1).optional(),
39727
+ model: external_exports.string().optional(),
39728
+ tool: external_exports.string().optional(),
39729
+ personality: external_exports.string().optional(),
39730
+ public: external_exports.boolean().optional(),
39731
+ // pass `null` to clear; daemon strips the field from PersonaFile on null
39732
+ iconKey: external_exports.string().nullable().optional()
39733
+ }).strict()
39734
+ }).strict();
39735
+ var CodexSandboxSettingsSchema = external_exports.object({
39736
+ // 额外可写的绝对路径或 ~ 路径(pnpm 工具链等);workspace(cwd) 和 userWorkDir 由 daemon 自动加,不用列。
39737
+ writableRoots: external_exports.array(external_exports.string()).optional(),
39738
+ // 禁读 glob(相对 workspace root 或绝对),如 ".secrets/**"、"**/*.env"。
39739
+ denyRead: external_exports.array(external_exports.string()).optional(),
39740
+ // true → 网络全放(*);缺省/false → 断网。
39741
+ network: external_exports.boolean().optional()
39742
+ }).strict();
39743
+
39744
+ // ../protocol/src/schemas.ts
39745
+ var SessionStatusSchema = external_exports.enum(SESSION_STATUS_VALUES);
39746
+ var UsageSchema = external_exports.object({
39747
+ input_tokens: external_exports.number().int().nonnegative().optional(),
39748
+ cache_read_input_tokens: external_exports.number().int().nonnegative().optional(),
39749
+ cache_creation_input_tokens: external_exports.number().int().nonnegative().optional(),
39750
+ output_tokens: external_exports.number().int().nonnegative().optional()
39751
+ });
39752
+ var ContextUsageSchema = external_exports.object({
39753
+ inputTokens: external_exports.number().int().nonnegative(),
39754
+ outputTokens: external_exports.number().int().nonnegative(),
39755
+ cacheReadTokens: external_exports.number().int().nonnegative().optional(),
39756
+ cacheCreateTokens: external_exports.number().int().nonnegative().optional()
39757
+ });
39758
+ var sessionMetaShape = {
39759
+ gitBranch: external_exports.string().optional(),
39760
+ resolvedModel: external_exports.string().optional(),
39761
+ contextUsage: ContextUsageSchema.optional(),
39762
+ contextWindowSize: external_exports.number().int().positive().optional()
39763
+ };
39764
+ var SessionMetaSchema = external_exports.object(sessionMetaShape);
39765
+ var ModelInfoSchema = external_exports.object({
39766
+ id: external_exports.string().min(1),
39767
+ label: external_exports.string().min(1),
39768
+ description: external_exports.string().optional(),
39769
+ contextWindowSize: external_exports.number().int().positive(),
39770
+ default: external_exports.boolean().optional()
39771
+ });
39772
+ var ModeInfoSchema = external_exports.object({
39773
+ id: external_exports.string().min(1),
39774
+ label: external_exports.string().min(1),
39775
+ description: external_exports.string().optional()
39776
+ });
39777
+ var ConfigFieldSchemaSchema = external_exports.object({
39778
+ name: external_exports.string().min(1),
39779
+ type: external_exports.enum(["string", "select", "toggle"]),
39780
+ label: external_exports.string().min(1),
39781
+ description: external_exports.string().optional(),
39782
+ options: external_exports.array(
39783
+ external_exports.object({
39784
+ value: external_exports.string(),
39785
+ label: external_exports.string(),
39786
+ description: external_exports.string().optional()
39787
+ })
39788
+ ).optional(),
39789
+ default: external_exports.unknown().optional(),
39790
+ scope: external_exports.enum(["core", "tool-specific"])
39791
+ });
39792
+ var CapabilitiesGetArgs = external_exports.object({
39793
+ tool: external_exports.string().min(1)
39794
+ });
39795
+ var ToolFeaturesSchema = external_exports.object({
39796
+ rewind: external_exports.boolean(),
39797
+ subagents: external_exports.boolean(),
39798
+ tui: external_exports.boolean(),
39799
+ observe: external_exports.boolean(),
39800
+ fileSharing: external_exports.boolean(),
39801
+ // fork:session:fork 走 forkSession(claude jsonl 专用,派生新 jsonl)。codex 无 claude jsonl
39802
+ // → fork 不可用。UI 据此 gate assistant 消息上的 fork 按钮(codex 一轮多条消息会刷出一堆按钮且点了报错)。
39803
+ fork: external_exports.boolean()
39804
+ });
39805
+ var CapabilitiesResponseSchema = external_exports.object({
39806
+ tool: external_exports.string().min(1),
39807
+ toolSessionIdLabel: external_exports.string().optional(),
39808
+ models: external_exports.array(ModelInfoSchema),
39809
+ permissionModes: external_exports.array(ModeInfoSchema),
39810
+ configSchema: external_exports.array(ConfigFieldSchemaSchema),
39811
+ features: ToolFeaturesSchema
39812
+ });
39813
+ var AllowRuleSchema = external_exports.object({
39814
+ tool: external_exports.string().min(1),
39815
+ pattern: external_exports.string().min(1),
39816
+ createdAt: external_exports.string().min(1).optional()
39817
+ });
39818
+ var SessionFileSchema = external_exports.object({
39819
+ sessionId: external_exports.string().min(1),
39820
+ cwd: external_exports.string().min(1),
39821
+ tool: external_exports.literal("claude").or(external_exports.string().min(1)).default("claude"),
39822
+ // 归一化 tool 侧 session id(CC = claude session uuid,Codex = codex 自己的 id)
39823
+ toolSessionId: external_exports.string().optional(),
39824
+ label: external_exports.string().optional(),
39825
+ model: external_exports.string().optional(),
39826
+ permissionMode: external_exports.string().optional(),
39827
+ effort: external_exports.string().optional(),
39828
+ // 归一化运行时观测字段(daemon 独立计算,session:update 不接受;meta_update 事件投递)
39829
+ ...sessionMetaShape,
39830
+ permissionRules: external_exports.array(AllowRuleSchema).optional(),
39831
+ // Sidebar 置顶时间戳;null/undefined 表示未置顶
39832
+ pinnedAt: external_exports.number().int().nonnegative().nullable().optional(),
39833
+ // pinned 行手动拖拽顺序;越小越靠前。session:reorderPins 整体重写所有 pinned 的此字段。
39834
+ // 缺失时 view-state 排序回退到 pinnedAt desc(旧数据兼容)
39835
+ pinSortOrder: external_exports.number().int().nullable().optional(),
39836
+ // 用户在 NewSessionDialog 或 Edit modal 选择的 icon 标识;UI 端做 enum 兜底
39837
+ iconKey: external_exports.string().optional(),
39838
+ // 由 session:fork 派生的 session 在 create 时记录源 session 的 sessionId(稳定 key,
39839
+ // 不受 parent clear / re-spawn 影响);sidebar 据此挂 fork 图标。非 fork session 该字段缺省。
39840
+ // 旧字段 forkedFromToolSessionId 已弃用,daemon 启动时一次性迁移老数据
39841
+ forkedFromSessionId: external_exports.string().min(1).optional(),
39842
+ // 快速问答临时会话标记(spec 2026-06-23-fork-quick-ask):true = 关闭抽屉即删、
39843
+ // 不进 sidebar 树、daemon 启动清扫孤儿。普通会话缺省。
39844
+ ephemeral: external_exports.boolean().optional(),
39845
+ // owner-mode persona session 身份标识;UI 用它在 SessionList 过滤 + jump,
39846
+ // daemon 用它做 idempotent dedupe + spawn 时派生 ctx.personaMode='owner'
39847
+ ownerPersonaId: external_exports.string().min(1).optional(),
39848
+ // app-builder Project 反向索引(spec: superpowers/specs/2026-06-01-app-builder-project-picker-design.md)。
39849
+ // 当此 session 绑定到某个 build 中的 project 时填写;name 与 projects/<name>/ 子目录同名,
39850
+ // 受 projectNameSchema regex 约束。daemon session:resume 时校验该目录存在,不存在则拒。
39851
+ appBuilderProject: external_exports.string().regex(/^[a-z][a-z0-9-]{0,39}$/).optional(),
39852
+ // listener-mode sub-session 的原始 chatId(owner-mode 不写;listener-scope 强制写入)。
39853
+ // 派生 sessionId 是单向 hash `${personaId}-${tokenHash12}-${chatHash8}`,必须保留原始 chatId
39854
+ // 才能让 alice 重连同一 sub-session(持久化在 alice localStorage 之外,由 daemon push 同步)。
39855
+ // optional 是因为 owner-mode session 不带;只要写入就是 listener-mode 必填三元组。
39856
+ chatId: external_exports.string().min(1).optional(),
39857
+ /**
39858
+ * 创建该 session 的设备 id(决策 #16:从 ctx.principal.id 派生 = deviceId)。
39859
+ * UI 端 self 判定收敛为单一比较 `!creatorPrincipalId || creatorPrincipalId === 本机 deviceId`
39860
+ * → 「我自己创建」vs「别的设备接入创建」。MyPersonas 二级分组按 creatorPrincipalId(设备)
39861
+ * 分桶、按 contact(deviceId→ownerName) 反查显示名。
39862
+ *
39863
+ * 命名保留 creatorPrincipalId(命名债,语义已是 creatorDeviceId);值由 connect token
39864
+ * subDevice 背书(guest ctx)或本机 deviceId(owner ctx)。optional 兼容老 session。
39865
+ *
39866
+ * 决策 #16 删除了 creatorOwnerPrincipalId(personal token #735 遗留)——当年 guest 的
39867
+ * principal.id 都是同张 cap.id 区分不了人才加它;现在 principal.id = 设备 deviceId、
39868
+ * 归属人由 contact(deviceId→ownerId) 反查,该字段理由消失。
39869
+ */
39870
+ creatorPrincipalId: external_exports.string().min(1).optional(),
39871
+ /**
39872
+ * 创建该 session 的连接者飞书 displayName(一次性 stamp)。session:create handler
39873
+ * 从 ctx.principal.displayName 传入;newRunner 时读这个字段派生 SubSessionMeta.callerDisplayName,
39874
+ * 注入到 cc system prompt 引导自我介绍(见 connection-prompt.ts)。
39875
+ * Optional 兼容老 SessionFile——newRunner 读不到时 fallback ContactStore 反查(guest)
39876
+ * 或 deps.ownerDisplayName(owner)。
39877
+ */
39878
+ creatorDisplayName: external_exports.string().min(1).optional(),
39879
+ /**
39880
+ * Mirror peer sessions (2026-05-26): mirror 标识。**我在朋友 daemon 上创建的 session**,
39881
+ * 远端是 source of truth,本机是持久化副本,方便 sidebar 跨设备聚合。
39882
+ * 字段值 = 远端 daemon 的 deviceId(决策 #16:朋友设备标识,即我接入的那台机器)。
39883
+ *
39884
+ * 语义关键澄清:mirror **不是朋友创建给我的会话**——它是我自己的会话,只是在朋友
39885
+ * 的机器上跑。sidebar chip 显示 `@<朋友>` 暗示「位置」,不是「来源」。
39886
+ *
39887
+ * - undefined / 缺省 → 本机 native session(在我自己机器上跑)
39888
+ * - 非空 → 我的会话在该 deviceId 朋友的 daemon 上跑,本机为持久化副本
39889
+ *
39890
+ * 四类 session 取值矩阵(决策 #16 deviceId 版,creatorOwnerPrincipalId 列已删):
39891
+ * | 形态 | creatorPrincipalId(=设备) | originOwnerPrincipalId(=朋友设备) |
39892
+ * |-------------------------------------|--------------------------|----------------------------------|
39893
+ * | 本机 owner 自创 | 本机 deviceId | undefined |
39894
+ * | 本机被别的设备接入创建 | 接入者 deviceId(token 背书) | undefined |
39895
+ * | 我在朋友 daemon 上创建(mirror 回本机) | 我的 deviceId | 朋友 deviceId |
39896
+ *
39897
+ * UI 用法:
39898
+ * - sidebar Active/Pinned/Recents 过滤:`origin 非空 → 一律视作 self`(绕过 #739 隔离)
39899
+ * - 行内显示 `@<朋友>` chip 暗示位置
39900
+ * - 进 ChatPanel 时按 origin 路由到 `pool.ensureRemoteForOwner(origin)` 走远端(按 deviceId)
39901
+ *
39902
+ * daemon 用法:
39903
+ * - `peerSession:upsert` / `peerSession:remove` 一族 RPC 专管 mirror 写删;
39904
+ * daemon dumb write/delete,**不广播任何 push 帧**,UI 是写入唯一源
39905
+ * - native `session:*` handler 完全不感知 mirror(UI 操作 mirror 不走 native 路径)
39906
+ */
39907
+ originOwnerPrincipalId: external_exports.string().min(1).optional(),
39908
+ /**
39909
+ * Dispatch 派生的 session 在 create 时记录源 session 的 sessionId(稳定 key);
39910
+ * sidebar 据此把 dispatch 出来的 sub-session 折叠在源 session 下。非 dispatch session 缺省。
39911
+ * mirror SessionFile 上必须 strip(朋友 daemon 上的 sessionId 在本机无意义,会让本机
39912
+ * 反查路径走错;按 #750 一族防线处理,跟 ownerPersonaId 同地点 strip)。
39913
+ */
39914
+ dispatchedFromSessionId: external_exports.string().min(1).optional(),
39915
+ /**
39916
+ * Shift fire 派生的 session 记录调 addShift 的 source cc session id(稳定 key);
39917
+ * sidebar 据此把 fire 出的 session 折叠在 source session 下,跟 dispatchedFromSessionId
39918
+ * 平行但渲染不同 icon(AlarmClock 区别于 dispatch 的 CornerDownRight),让 owner 一眼
39919
+ * 分清"派生于人为委派"还是"派生于定时唤起"。非 shift fire session 缺省。
39920
+ * 跟 dispatchedFromSessionId / forkedFromSessionId 三者互斥(同一 session 不会兼任)。
39921
+ * mirror SessionFile 同 dispatchedFromSessionId 处理(shift fire 本地概念,理论上不会
39922
+ * mirror,留 strip 防御)。
39923
+ */
39924
+ shiftFiredFromSessionId: external_exports.string().min(1).optional(),
39925
+ createdAt: external_exports.string().min(1),
39926
+ updatedAt: external_exports.string().min(1)
39927
+ });
39928
+ var ParsedEventBase = {
39929
+ seq: external_exports.number().int().nonnegative().optional(),
39930
+ ts: external_exports.string().optional(),
39931
+ // CC top-level uuid:同一逻辑帧从 stream-json stdout 和 JSONL 落地时携带相同值,
39932
+ // reducer 用它做跨路径去重(managed stdout 和 observer JSONL 双写)。对齐 cc-direct cc-event-store
39933
+ uuid: external_exports.string().optional()
39934
+ };
39935
+ var HistoryUserMetaSchema = external_exports.enum(HISTORY_USER_META_VALUES);
39936
+ var SubagentToolStatsSchema = external_exports.object({
39937
+ readCount: external_exports.number().int().nonnegative().optional(),
39938
+ searchCount: external_exports.number().int().nonnegative().optional(),
39939
+ bashCount: external_exports.number().int().nonnegative().optional(),
39940
+ editFileCount: external_exports.number().int().nonnegative().optional(),
39941
+ linesAdded: external_exports.number().int().nonnegative().optional(),
39942
+ linesRemoved: external_exports.number().int().nonnegative().optional(),
39943
+ otherToolCount: external_exports.number().int().nonnegative().optional()
39944
+ });
39945
+ var StructuredPatchHunkSchema = external_exports.object({
39946
+ oldStart: external_exports.number().int().nonnegative(),
39947
+ oldLines: external_exports.number().int().nonnegative(),
39948
+ newStart: external_exports.number().int().nonnegative(),
39949
+ newLines: external_exports.number().int().nonnegative(),
39950
+ // 每行以 '+' / '-' / ' ' 开头(diff npm 包的标准 hunk lines)
39951
+ lines: external_exports.array(external_exports.string())
39952
+ });
39953
+ var ToolResultExtraSchema = external_exports.object({
39954
+ agentId: external_exports.string().optional(),
39955
+ agentType: external_exports.string().optional(),
39956
+ status: external_exports.string().optional(),
39957
+ prompt: external_exports.string().optional(),
39958
+ // CC File*Tool 结果里的 filePath / structuredPatch:UI rewind 预览据此本地渲染 diff。
39959
+ // 两者同时存在才有意义;缺任一则 UI 降级为仅显示"受影响文件"摘要
39960
+ filePath: external_exports.string().optional(),
39961
+ structuredPatch: external_exports.array(StructuredPatchHunkSchema).optional(),
39962
+ stats: external_exports.object({
39963
+ durationMs: external_exports.number().int().nonnegative().optional(),
39964
+ tokens: external_exports.number().int().nonnegative().optional(),
39965
+ toolUseCount: external_exports.number().int().nonnegative().optional(),
39966
+ toolStats: SubagentToolStatsSchema.optional(),
39967
+ usage: UsageSchema.optional()
39968
+ }).optional()
39969
+ });
39970
+ var MemoryEntrySchema = external_exports.object({
39971
+ path: external_exports.string(),
39972
+ content: external_exports.string(),
39973
+ mtimeMs: external_exports.number().optional()
39974
+ });
39975
+ var AskQuestionOptionSchema = external_exports.object({
39976
+ label: external_exports.string().min(1),
39977
+ description: external_exports.string().optional()
39978
+ });
39979
+ var AskQuestionItemSchema = external_exports.object({
39980
+ question: external_exports.string().min(1),
39981
+ // multiSelect 必填(boolean 不给默认值):daemon emit 时必须显式传,避免 UI 端漂移
39982
+ multiSelect: external_exports.boolean(),
39983
+ options: external_exports.array(AskQuestionOptionSchema).min(1)
39984
+ });
39985
+ var ParsedEventSchema = external_exports.discriminatedUnion("kind", [
39986
+ // session_init 仅携带 session 标识;resolvedModel 等元信息走 meta_update
39987
+ external_exports.object({
39988
+ ...ParsedEventBase,
39989
+ kind: external_exports.literal("session_init"),
39990
+ toolSessionId: external_exports.string().optional()
39991
+ }),
39992
+ external_exports.object({
39993
+ ...ParsedEventBase,
39994
+ kind: external_exports.literal("thinking"),
39995
+ text: external_exports.string(),
39996
+ // 同一思考块的多次 stream_event 增量带相同 partialId(= `${sessionId}-${blockIndex}`);
39997
+ // 不带表示是 assistant 帧的整段快照。UI 用 partialId 累积 / 用快照覆盖。
39998
+ partialId: external_exports.string().optional()
39999
+ }),
40000
+ external_exports.object({
40001
+ ...ParsedEventBase,
40002
+ kind: external_exports.literal("text"),
40003
+ text: external_exports.string(),
40004
+ // 同一文本块的多次 stream_event 增量带相同 partialId;语义同 thinking
40005
+ partialId: external_exports.string().optional()
40006
+ }),
40007
+ // 真实用户输入:daemon 通过 --replay-user-messages 拿到 stdin 回显,区分于 assistant text。
40008
+ // meta 非空表示是 CC 注入的系统消息(task-notification / slash-command / system-reminder 等),
40009
+ // UI 据此走低视觉权重渲染或子 agent 通知卡。
40010
+ //
40011
+ // sender(2026-07-08 spec §4.1):daemon 'send' 命令 synth 的 user_text 携带发起人 SenderInfo;
40012
+ // observer 回灌路径(cc jsonl)永远不带 —— cc 自己写盘不知道 daemon 层身份。
40013
+ // UI 端 sender 缺省 → 不渲染 displayName label;有 → 气泡下方渲染。
40014
+ external_exports.object({
40015
+ ...ParsedEventBase,
40016
+ kind: external_exports.literal("user_text"),
40017
+ text: external_exports.string(),
40018
+ meta: HistoryUserMetaSchema.optional(),
40019
+ taskId: external_exports.string().optional(),
40020
+ parentToolUseId: external_exports.string().optional(),
40021
+ sender: SenderInfoSchema.optional()
40022
+ }),
40023
+ external_exports.object({
40024
+ ...ParsedEventBase,
40025
+ kind: external_exports.literal("tool_call"),
40026
+ toolUseId: external_exports.string(),
40027
+ tool: external_exports.string(),
40028
+ // 等于 session.tool;UI 按 {toolKind, tool} 分派渲染。additive 可选,旧 adapter 不填也能解析
40029
+ toolKind: external_exports.string().optional(),
40030
+ input: external_exports.unknown()
40031
+ }),
40032
+ external_exports.object({
40033
+ ...ParsedEventBase,
40034
+ kind: external_exports.literal("tool_result"),
40035
+ toolUseId: external_exports.string(),
40036
+ output: external_exports.unknown().optional(),
40037
+ error: external_exports.string().optional(),
40038
+ // CC Agent / Task tool 完成后在 JSONL 顶层挂的 toolUseResult 元信息(非 content 字段)
40039
+ // 老 CC 走 <task-notification> user 消息携带统计,新 CC 直接挂在这里——兼容期两者可能并存
40040
+ toolResultExtra: ToolResultExtraSchema.optional(),
40041
+ // 精确指向发起 tool 的 assistant 消息顶层 uuid;toolUseId 已够 UI 聚合,这个仅作调试辅助
40042
+ sourceToolAssistantUUID: external_exports.string().optional(),
40043
+ // AskUserQuestion 实时回放(plan: clawd-ask-user-question 任务 B 修复):
40044
+ // CC 用户答完后把 answers 写在 user 帧顶层 toolUseResult.answers,daemon parser
40045
+ // 抽到这里。UI eventsToLines 用 toolUseId 配对到 question-card line,把卡片转为
40046
+ // 只读态显示用户的答案。仅 AskUserQuestion 配对的 tool_result 行携带;普通工具不带。
40047
+ // 等价于 HistoryMessage.askQuestionAnswers(历史回放路径),两端字段名对齐。
40048
+ askQuestionAnswers: external_exports.record(external_exports.string(), external_exports.string()).optional()
40049
+ }),
40050
+ // CC 命中项目记忆(`type:"attachment"`,`attachment.type:"memories"`)的独立事件;
40051
+ // 其它 attachment 子类型(skills / hook_context / deferred_tools / hook_success / unknown)
40052
+ // 视觉权重低,daemon 直接走 user_text + HistoryUserMeta 折叠,不另开 kind
40053
+ external_exports.object({
40054
+ ...ParsedEventBase,
40055
+ kind: external_exports.literal("attachment_memories"),
40056
+ memories: external_exports.array(MemoryEntrySchema)
40057
+ }),
40058
+ external_exports.object({
40059
+ ...ParsedEventBase,
40060
+ kind: external_exports.literal("permission_request"),
40061
+ requestId: external_exports.string(),
40062
+ tool: external_exports.string(),
40063
+ input: external_exports.unknown(),
40064
+ // CC `control_request.request.tool_use_id` 对应的 tool_use id;UI 用它把队列项与
40065
+ // 后续 tool_result.toolUseId 关联做跨客户端 dequeue(plan permission-multi-pending-queue.md
40066
+ // 选项 ii)。老 daemon / legacy CC 不发该字段时保持向后兼容(optional)。
40067
+ toolUseId: external_exports.string().optional()
40068
+ }),
40069
+ // AskUserQuestion 工具调用的内联锚点(plan: clawd-ask-user-question 问题 1 修复):
40070
+ // daemon parser 把 assistant tool_use AskUserQuestion 翻译成本 kind(不是 permission_request、
40071
+ // 也不是 tool_call),让 UI 在事件流自然位置渲染问答卡(紧跟 assistant 消息 / 在后续消息之前),
40072
+ // 而不是被强行挂在末尾。permission_request 帧仍正常下发驱动 pendingQuestions 状态机,
40073
+ // 但只走 wire 帧不入 ring buffer——状态由 daemon pendingQuestions 持有,
40074
+ // 渲染锚点由本 kind 的 ParsedEvent 提供。
40075
+ // 历史回放:history-to-lines.ts 在 jsonl tool_use AskUserQuestion 处插入对应 'question-card' line,
40076
+ // 配对的 tool_result 携带 toolUseResult.answers,已答完的展示只读态。
40077
+ external_exports.object({
40078
+ ...ParsedEventBase,
40079
+ kind: external_exports.literal("ask_user_question"),
40080
+ toolUseId: external_exports.string(),
40081
+ questions: external_exports.array(AskQuestionItemSchema)
40082
+ }),
40083
+ // turn_end —— 一轮 AI 响应结束。消费者:reducer pushEventToBuffer 翻 turnOpen=false;
40084
+ // UI useChatPanelState 收 "Claude is working" spinner(lastEventKind===turn_end)。
40085
+ // 三个产生来源:
40086
+ // ① SDK 模式 stream-json `result` 帧(claude.ts)—— stdout 最后一帧,可靠
40087
+ // ② TUI 模式 observer 读 JSONL `system/turn_duration` 行(claude-tui.ts parseLine)
40088
+ // ⚠️ CC 写此行早于该轮尾段正文落盘,可能被尾随 text 覆盖 lastEventKind(③ 存在的原因)
40089
+ // ③ TUI 模式屏幕静止 AND observer 静止(observeScreenIdle + manager.observerIdleWaitMs 复合闸 →
40090
+ // dispatchTurnIdle inject)—— 兜 ② 的覆盖;等尾随 text 全部 poll 落盘后补,排在 buffer 末条
40091
+ external_exports.object({
40092
+ ...ParsedEventBase,
40093
+ kind: external_exports.literal("turn_end")
40094
+ }),
40095
+ // SDK system 帧 task_started / task_progress / task_notification 的归一化产物:
40096
+ // 子 agent 执行过程中实时上报 agentId / lastToolName / stats,UI pending 期就能开抽屉、看进度。
40097
+ // toolUseId 对齐父 Agent 工具的 tool_use_id;status 由 SDK subtype 派生。
40098
+ external_exports.object({
40099
+ ...ParsedEventBase,
40100
+ kind: external_exports.literal("subagent_progress"),
40101
+ toolUseId: external_exports.string(),
40102
+ agentId: external_exports.string(),
40103
+ status: external_exports.enum(["started", "running", "completed", "failed"]),
40104
+ description: external_exports.string().optional(),
40105
+ lastToolName: external_exports.string().optional(),
40106
+ prompt: external_exports.string().optional(),
40107
+ stats: external_exports.object({
40108
+ durationMs: external_exports.number().int().nonnegative().optional(),
40109
+ tokens: external_exports.number().int().nonnegative().optional(),
40110
+ toolUseCount: external_exports.number().int().nonnegative().optional()
40111
+ }).optional()
40112
+ }),
40113
+ external_exports.object({
40114
+ ...ParsedEventBase,
40115
+ kind: external_exports.literal("error"),
40116
+ message: external_exports.string()
40117
+ }),
40118
+ // 元信息投递:daemon adapter 从任意来源(stream-json / JSONL)抽出的 SessionMeta 子集
40119
+ // reducer 做 patch merge + diff + persist + 广播 session:info;不入 ring buffer
40120
+ external_exports.object({
40121
+ ...ParsedEventBase,
40122
+ kind: external_exports.literal("meta_update"),
40123
+ patch: SessionMetaSchema
40124
+ }),
40125
+ // 系统消息(CC 自家系统提示 / 老板插话补充);persona 场景下区分两类:
40126
+ // metaSource='cc' → CC 注入的系统消息(默认低视觉权重渲染)
40127
+ // metaSource='owner' → 老板通过 persona:appendOwnerMessage 插入的话(蓝色气泡)
40128
+ // 缺省视为 'cc';现有非 persona 场景保持兼容(不需要 owner 时不下发该字段)
40129
+ external_exports.object({
40130
+ ...ParsedEventBase,
40131
+ kind: external_exports.literal("meta-text"),
40132
+ text: external_exports.string(),
40133
+ metaSource: external_exports.enum(["cc", "owner"]).optional()
40134
+ })
40135
+ ]);
40136
+ var SessionCreateArgs = external_exports.object({
40137
+ // 当 ownerPersonaId 存在时 cwd 由 daemon 派生,UI 可不传
40138
+ cwd: external_exports.string().min(1).optional(),
40139
+ tool: external_exports.string().optional(),
40140
+ label: external_exports.string().optional(),
40141
+ model: external_exports.string().optional(),
40142
+ permissionMode: external_exports.string().optional(),
40143
+ effort: external_exports.string().optional(),
40144
+ // 用户在 NewSessionDialog 选择的 icon 标识;UI 端做 enum 兜底
40145
+ iconKey: external_exports.string().optional(),
40146
+ // session:fork 派生 session 时由 UI 传入源 sessionId,daemon 写到 SessionFile.forkedFromSessionId
40147
+ forkedFromSessionId: external_exports.string().min(1).optional(),
40148
+ // 快速问答:创建时打 ephemeral 标记,daemon 写到 SessionFile.ephemeral
40149
+ ephemeral: external_exports.boolean().optional(),
40150
+ // owner-mode persona session:传此字段时 daemon 自行派生 cwd 和启动参数,
40151
+ // 且按 ownerPersonaId 做 idempotent dedupe(每 persona 永远只有一个 owner session)
40152
+ ownerPersonaId: external_exports.string().min(1).optional()
40153
+ // 单栏默认 refactor (spec 2026-06-02):appBuilderProject 字段已从 SessionCreateArgs 砍掉。
40154
+ // 绑定路径收敛到 appBuilder:createProject —— 先创建空 session(仅传 ownerPersonaId=persona-app-builder),
40155
+ // 后通过 createProject RPC 创建 project 并 daemon 内部 mutate 写入 appBuilderProject。
40156
+ // SessionFile schema 仍保留该字段供 daemon 内部 mutate(manager.update 内部调用通道)。
40157
+ }).refine((args) => args.cwd != null || args.ownerPersonaId != null, {
40158
+ message: "cwd \u4E0E ownerPersonaId \u81F3\u5C11\u4F20\u4E00\u4E2A"
40159
+ });
40160
+ var SessionIdArgs = external_exports.object({ sessionId: external_exports.string().min(1) });
40161
+ var SessionUpdateArgs = external_exports.object({
40162
+ sessionId: external_exports.string().min(1),
40163
+ patch: external_exports.object({
40164
+ label: external_exports.string().optional(),
40165
+ model: external_exports.string().optional(),
40166
+ permissionMode: external_exports.string().optional(),
40167
+ effort: external_exports.string().optional(),
40168
+ cwd: external_exports.string().optional(),
40169
+ // 用户在 Edit modal 选择的 icon 标识;UI 端做 enum 兜底
40170
+ iconKey: external_exports.string().optional()
40171
+ // 注意:appBuilderProject 字段已从 patch 中砍掉(spec 2026-06-02-app-builder-single-pane-default-design)。
40172
+ // 绑定单向不可变 —— 由 appBuilder:createProject 在 daemon 内部一次写入;UI / assistant 不再
40173
+ // 通过 sessionUpdate 修改这个字段。SessionFile 仍保留 appBuilderProject 字段供 daemon 内部 mutate。
40174
+ })
40175
+ });
40176
+ var SessionSendArgs = external_exports.object({
40177
+ sessionId: external_exports.string().min(1),
40178
+ text: external_exports.string()
40179
+ });
40180
+ var SessionRewindArgs = external_exports.object({
40181
+ sessionId: external_exports.string().min(1),
40182
+ userMessageId: external_exports.string().min(1),
40183
+ dryRun: external_exports.boolean().optional()
40184
+ });
40185
+ var SessionRewindResponseSchema = external_exports.object({
40186
+ canRewind: external_exports.boolean(),
40187
+ error: external_exports.string().optional(),
40188
+ filesChanged: external_exports.array(external_exports.string()).optional(),
40189
+ insertions: external_exports.number().int().nonnegative().optional(),
40190
+ deletions: external_exports.number().int().nonnegative().optional()
40191
+ });
40192
+ var SessionRewindDiffArgs = external_exports.object({
40193
+ sessionId: external_exports.string().min(1),
40194
+ userMessageId: external_exports.string().min(1)
40195
+ });
40196
+ var RewindDiffHunkSchema = external_exports.object({
40197
+ oldStart: external_exports.number().int().nonnegative(),
40198
+ oldLines: external_exports.number().int().nonnegative(),
40199
+ newStart: external_exports.number().int().nonnegative(),
40200
+ newLines: external_exports.number().int().nonnegative(),
40201
+ lines: external_exports.array(external_exports.string())
40202
+ });
40203
+ var RewindDiffFileSchema = external_exports.object({
40204
+ filePath: external_exports.string().min(1),
40205
+ hunks: external_exports.array(RewindDiffHunkSchema),
40206
+ insertions: external_exports.number().int().nonnegative(),
40207
+ deletions: external_exports.number().int().nonnegative(),
40208
+ status: external_exports.enum(["modified", "added", "deleted"]).optional()
40209
+ });
40210
+ var SessionRewindDiffResponseSchema = external_exports.object({
40211
+ canRewind: external_exports.boolean(),
40212
+ error: external_exports.string().optional(),
40213
+ files: external_exports.array(RewindDiffFileSchema),
40214
+ totalInsertions: external_exports.number().int().nonnegative(),
40215
+ totalDeletions: external_exports.number().int().nonnegative()
40216
+ });
40217
+ var SessionRewindableMessageIdsResponseSchema = external_exports.object({
40218
+ userMessageIds: external_exports.array(external_exports.string())
40219
+ });
40220
+ var SessionResumeArgs = external_exports.object({
40221
+ sessionId: external_exports.string().min(1),
40222
+ toolSessionId: external_exports.string().min(1)
40223
+ });
40224
+ var SessionForkArgs = external_exports.object({
40225
+ cwd: external_exports.string().min(1),
40226
+ toolSessionId: external_exports.string().min(1),
40227
+ messageUuid: external_exports.string().min(1)
40228
+ });
40229
+ var SessionForkResponseSchema = external_exports.object({
40230
+ forkedToolSessionId: external_exports.string().min(1),
40231
+ forkedFilePath: external_exports.string().min(1)
40232
+ });
40233
+ var SessionObserveArgs = external_exports.object({
40234
+ sessionId: external_exports.string().min(1),
40235
+ toolSessionId: external_exports.string().min(1),
40236
+ jsonlPath: external_exports.string().optional()
40237
+ });
40238
+ var SessionEventsArgs = external_exports.object({
40239
+ sessionId: external_exports.string().min(1),
40240
+ // -1 表示"从头拉全量"(尚未见过任何事件);seq 从 0 起,所以合法下界是 -1
40241
+ afterSeq: external_exports.number().int().min(-1)
40242
+ });
40243
+ var PermissionRespondArgs = external_exports.object({
40244
+ sessionId: external_exports.string().min(1),
40245
+ // 权限请求 id 用 `permissionRequestId`,**不能**叫 `requestId`:WS 传输层用帧顶层的
40246
+ // `requestId` 做 RPC 请求/响应关联(daemon-client 发帧时 `{...args, type, requestId}`,
40247
+ // 传输 id 在最后会覆盖 args 同名字段)。若沿用 `requestId`,权限 id 会被传输 id(如 "r61")
40248
+ // 覆盖,daemon 查 pendingPermissions 永远 miss → 点了允许一直卡住。
40249
+ permissionRequestId: external_exports.string().min(1),
40250
+ allow: external_exports.boolean(),
40251
+ permanent: external_exports.boolean().optional(),
40252
+ pattern: external_exports.string().optional()
40253
+ });
40254
+ var HistoryListArgs = external_exports.object({ projectPath: external_exports.string().min(1) });
40255
+ var HistoryReadArgs = external_exports.object({
40256
+ sessionId: external_exports.string().min(1),
40257
+ limit: external_exports.number().int().positive().max(5e3).optional(),
40258
+ /** 不传时走 tail 语义:daemon 返回最后 limit 条(offset = max(0, total - limit)) */
40259
+ offset: external_exports.number().int().nonnegative().optional()
40260
+ });
40261
+ var HistorySubagentsArgs = external_exports.object({
40262
+ cwd: external_exports.string().min(1),
40263
+ toolSessionId: external_exports.string().min(1)
40264
+ });
40265
+ var HistorySubagentReadArgs = external_exports.object({
40266
+ cwd: external_exports.string().min(1),
40267
+ toolSessionId: external_exports.string().min(1),
40268
+ subagentId: external_exports.string().min(1)
40269
+ });
40270
+ var WorkspaceListArgs = external_exports.object({
40271
+ // cwd 缺省则 daemon 兜底 os.homedir();UI 的 DirBrowser 首次浏览就走这条路径
40272
+ cwd: external_exports.string().min(1).optional(),
40273
+ path: external_exports.string().optional(),
40274
+ showHidden: external_exports.boolean().optional()
40275
+ });
40276
+ var WorkspaceReadArgs = external_exports.object({
40277
+ cwd: external_exports.string().min(1),
40278
+ path: external_exports.string().min(1)
40279
+ });
40280
+ var SkillsListArgs = external_exports.object({ cwd: external_exports.string().min(1), tool: external_exports.string().optional() });
40281
+ var SkillEntrySchema = external_exports.object({
40282
+ name: external_exports.string().min(1),
40283
+ source: external_exports.enum(SKILL_SOURCE_VALUES),
40284
+ path: external_exports.string().optional(),
40285
+ description: external_exports.string().optional(),
40286
+ plugin: external_exports.string().optional()
40287
+ });
40288
+ var AgentEntrySchema = external_exports.object({
40289
+ name: external_exports.string().min(1),
40290
+ source: external_exports.enum(AGENT_SOURCE_VALUES),
40291
+ path: external_exports.string().optional(),
40292
+ description: external_exports.string().optional(),
40293
+ whenToUse: external_exports.string().optional(),
40294
+ plugin: external_exports.string().optional()
40295
+ });
40296
+ var AgentsListArgs = external_exports.object({ cwd: external_exports.string().min(1), tool: external_exports.string().optional() });
40297
+ var AgentsListResponseSchema = external_exports.object({
40298
+ agents: external_exports.array(AgentEntrySchema)
40299
+ });
40300
+ var SessionSubscribeArgs = external_exports.object({ sessionId: external_exports.string().min(1) });
40301
+ var SessionPinArgs = external_exports.object({
40302
+ sessionId: external_exports.string().min(1),
40303
+ pinned: external_exports.boolean()
40304
+ });
40305
+ var PeerSessionUpsertResponseSchema = external_exports.object({
40306
+ type: external_exports.literal("peerSession:upsert:ok")
40307
+ });
40308
+ var PeerSessionRemoveArgs = external_exports.object({ sessionId: external_exports.string().min(1) });
40309
+ var PeerSessionRemoveResponseSchema = external_exports.object({
40310
+ type: external_exports.literal("peerSession:remove:ok")
40311
+ });
40312
+ var SessionReorderPinsArgs = external_exports.object({
40313
+ orderedIds: external_exports.array(external_exports.string().min(1)).min(1)
40314
+ });
40315
+ var GitRootArgs = external_exports.object({ cwd: external_exports.string().min(1) });
40316
+ var GitRootResponseSchema = external_exports.object({
40317
+ isGitRoot: external_exports.boolean(),
40318
+ gitRoot: external_exports.string().nullable()
40319
+ });
40320
+ var GitBranchArgs = external_exports.object({ cwd: external_exports.string().min(1) });
40321
+ var GitBranchResponseSchema = external_exports.object({
40322
+ branch: external_exports.string().nullable()
40323
+ });
40324
+ var GitBranchesArgs = external_exports.object({ cwd: external_exports.string().min(1) });
40325
+ var GitBranchesResponseSchema = external_exports.object({
40326
+ branches: external_exports.array(external_exports.string()),
40327
+ head: external_exports.string().nullable()
40328
+ });
40329
+ var HistoryRecentDirsArgs = external_exports.object({}).optional();
40330
+ var RecentDirEntrySchema = external_exports.object({
40331
+ cwd: external_exports.string().min(1),
40332
+ updatedAt: external_exports.string().min(1)
40333
+ });
40334
+ var HistoryRecentDirsResponseSchema = external_exports.object({
40335
+ dirs: external_exports.array(RecentDirEntrySchema)
40336
+ });
40337
+ var SessionQuestionFrameSchema = external_exports.object({
40338
+ type: external_exports.literal("session:question"),
40339
+ sessionId: external_exports.string().min(1),
40340
+ toolUseId: external_exports.string().min(1),
40341
+ requestId: external_exports.string().min(1),
40342
+ // UI 单卡承载多 question;空数组语义无效,schema 必拒
40343
+ questions: external_exports.array(AskQuestionItemSchema).min(1)
40344
+ });
40345
+ var SessionQuestionClearedFrameSchema = external_exports.object({
40346
+ type: external_exports.literal("session:question:cleared"),
40347
+ sessionId: external_exports.string().min(1),
40348
+ toolUseId: external_exports.string().min(1),
40349
+ // record<string,string>:与 AnswerQuestionArgs.answers 同形状(question text → label)
40350
+ answers: external_exports.record(external_exports.string(), external_exports.string()).optional()
40351
+ });
40352
+ var AnswerQuestionArgs = external_exports.object({
40353
+ sessionId: external_exports.string().min(1),
40354
+ toolUseId: external_exports.string().min(1),
40355
+ answers: external_exports.record(external_exports.string(), external_exports.string())
40356
+ });
40357
+ var AnswerQuestionResponseSchema = external_exports.object({ ok: external_exports.literal(true) });
40358
+ var CancelQuestionArgs = external_exports.object({
40359
+ sessionId: external_exports.string().min(1),
40360
+ toolUseId: external_exports.string().min(1)
40361
+ });
40362
+ var CancelQuestionResponseSchema = external_exports.object({ ok: external_exports.literal(true) });
40363
+ var AuthRequestFrameSchema = external_exports.object({
40364
+ type: external_exports.literal("auth"),
40365
+ token: external_exports.string().min(1),
40366
+ scheme: external_exports.literal("bearer").optional(),
40367
+ /**
40368
+ * 决策 #16:自报身份字段(selfPrincipalId / selfDisplayName / selfDeviceId)全部删除——
40369
+ * guest 的设备 id / 人 id / 来源全部由 connect token 的 subDevice/subOwner/provider 签名背书
40370
+ * (server 签、目标设备本地验签,不可伪造),不再接受任何自报身份。
40371
+ *
40372
+ * selfUrl 保留:它只是"可达地址"(auto-reverse 反向连接用),不是身份——填错只影响
40373
+ * 反向连通性,不构成伪造风险,且 url 不在 token 里(token 只签身份不签地址)。
40374
+ */
40375
+ selfUrl: external_exports.string().min(1).optional()
40376
+ });
40377
+ var AuthOkFrameSchema = external_exports.object({
40378
+ type: external_exports.literal("auth:ok"),
40379
+ version: external_exports.string().min(1).optional(),
40380
+ protocolVersion: external_exports.number().int().nonnegative().optional()
40381
+ });
40382
+ var TunnelReadyEventSchema = external_exports.object({
40383
+ type: external_exports.literal("tunnel:ready"),
40384
+ url: external_exports.string().min(1),
40385
+ subdomain: external_exports.string().min(1)
40386
+ });
40387
+ var TunnelExitedEventSchema = external_exports.object({
40388
+ type: external_exports.literal("tunnel:exited"),
40389
+ code: external_exports.number().int().nullable(),
40390
+ subdomain: external_exports.string().nullable(),
40391
+ url: external_exports.string().nullable()
40392
+ });
40393
+ var TunnelUnavailableEventSchema = external_exports.object({
40394
+ type: external_exports.literal("tunnel:unavailable"),
40395
+ reason: external_exports.string().min(1),
40396
+ failedAt: external_exports.string().min(1)
40397
+ });
40398
+ var InfoRunningSessionSchema = external_exports.object({
40399
+ sessionId: external_exports.string().min(1),
40400
+ status: SessionStatusSchema,
40401
+ freshSpawn: external_exports.boolean(),
40402
+ pendingPermissionRequestIds: external_exports.array(external_exports.string().min(1)),
40403
+ pendingQuestionToolUseIds: external_exports.array(external_exports.string().min(1))
40404
+ });
40405
+ var InfoResponseSchema = external_exports.object({
40406
+ type: external_exports.literal("info"),
40407
+ version: external_exports.string(),
40408
+ protocolVersion: external_exports.number(),
40409
+ hostname: external_exports.string(),
40410
+ os: external_exports.string(),
40411
+ tools: external_exports.array(external_exports.object({ id: external_exports.string(), available: external_exports.boolean() })),
40412
+ runningSessions: external_exports.array(InfoRunningSessionSchema),
40413
+ // ── file-sharing 会话身份回执(spec: superpowers/specs/2026-05-19-clawd-file-sharing-design.md §8) ──
40414
+ // PR 1 阶段标 optional(daemon 还没下发,旧 daemon info 响应不带这五个字段);
40415
+ // PR 2 daemon 实现 single HTTP server + auth-context 后,daemon 必返这五个字段,
40416
+ // 届时可考虑改成 required。spec §11 第 3 条:"tokenRole 是协议字段,daemon 查 token
40417
+ // 表后显式下发,UI 不自行推导"——所以 UI 一律读这里,禁止本地推导。
40418
+ /** 'owner' = 拿到 owner-token 的连接(不限来源 IP)。来源 TOKEN_ROLES(spec §11 #1 中央真理源)。
40419
+ * 历史 'personal' role(persona file-sharing token)在 2026-05-21 删除;tokenPersonaId 一同移除。 */
40420
+ tokenRole: external_exports.enum(TOKEN_ROLES).optional(),
40421
+ /** socket.remoteAddress 是否落在 127.0.0.1 / ::1;本期无 RPC 消费,保留协议槽位给未来 "Reveal in Finder" 等本机动作 */
40422
+ isLoopback: external_exports.boolean().optional(),
40423
+ /** UI 拼 file-sharing HTTP 路由的前缀(http(s)://host:port),不含尾斜杠;frpc 反代时返反代地址 */
40424
+ httpBaseUrl: external_exports.string().optional(),
40425
+ /** file-sharing HTTP 路由的 Authorization: Bearer token;与 WS token 解耦,HTTP 401 仅触发 ReAuth 不强踢 WS(spec §11 第 4 条) */
40426
+ httpToken: external_exports.string().optional()
40427
+ });
40428
+ var PROJECT_PORT_MIN = 6173;
40429
+ var PROJECT_PORT_MAX = 6272;
40430
+ var projectNameRegex = /^[a-z][a-z0-9-]{0,39}$/;
40431
+ var ProjectMetadataSchema = external_exports.object({
40432
+ name: external_exports.string().regex(projectNameRegex, {
40433
+ message: "kebab-case, \u5C0F\u5199\u5B57\u6BCD\u5F00\u5934\uFF0C\u53EA\u5141\u8BB8\u5C0F\u5199\u5B57\u6BCD / \u6570\u5B57 / -\uFF0C\u6700\u957F 40 \u5B57\u7B26"
40434
+ }),
40435
+ port: external_exports.number().int().min(PROJECT_PORT_MIN).max(PROJECT_PORT_MAX),
40436
+ createdAt: external_exports.string().datetime(),
40437
+ /** dev server 启动命令(shell 字符串);占位符 $CLAWD_PREVIEW_PORT 替换 + env 注入 */
40438
+ devCommand: external_exports.string().min(1),
40439
+ /**
40440
+ * 发布上线后的公网 URL(spec 2026-06-02-app-builder-single-pane-default-design §5.6.1)。
40441
+ * assistant 跑完 publish.sh 后调 appBuilder:setProdUrl 写入;UI 读这个字段切预览栏到线上 URL,
40442
+ * 取代旧 `<builder-preview url=... label="prod" />` marker 机制。
40443
+ * 老 project 元数据无此字段(optional 兼容)。
40444
+ */
40445
+ prodUrl: external_exports.string().url().optional(),
40446
+ /**
40447
+ * dev server 就绪 stdout regex(spec 2026-06-02-app-builder-explicit-dev-server-control §2)。
40448
+ * supervisor spawn 后会监听子进程 stdout,命中此 regex 视为 dev server 真 ready;
40449
+ * 仅当 await ready 后才把 stage 切到 'running',避免 cold start race 导致 iframe 502。
40450
+ * optional:缺省时 supervisor 用默认 /Local:\s+https?:\/\//(vite "Local: http://..." 输出)。
40451
+ * 老板换非 vite 技术栈(Next.js "Ready in"、webpack "Compiled" 等)时自定义这个字段。
40452
+ */
40453
+ readyPattern: external_exports.string().optional(),
40454
+ /**
40455
+ * 发布上线脚手架化 (spec 2026-06-03-app-builder-publish-scaffold-design §5.1.4):
40456
+ * in-flight 发布 job 的元数据。仅承载"in-flight"或"中断残骸"两种状态:
40457
+ * - daemon spawn publish.sh + 收到第一个 ::stage::build marker 时写入
40458
+ * - 每次 stage 切换更新 stage 字段
40459
+ * - 成功 / 正常失败 / 用户 dismiss 时立即清掉
40460
+ * - 只有 daemon 崩才会留残骸(子进程随 daemon 一起死)
40461
+ * status 字段在 ProjectWithStatus 派生而不在这里 —— 本 schema 是落盘形态,
40462
+ * "in-flight vs interrupted" 区分由 daemon 响应时实时拼 registry 状态得出。
40463
+ */
40464
+ publishJob: external_exports.object({
40465
+ jobId: external_exports.string().min(1),
40466
+ stage: external_exports.enum(["build", "deploy", "verify"]),
40467
+ startedAt: external_exports.number().int().nonnegative()
40468
+ }).optional()
40469
+ });
40470
+ var PROJECT_STAGE_VALUES = [
40471
+ "install-pending",
40472
+ // createProject 刚返回,scaffold 已完成(daemon 同步内联跑),等 assistant pnpm install
40473
+ "installing",
40474
+ // assistant pnpm install 中
40475
+ "starting-dev-server",
40476
+ // startDevServer 已调,supervisor spawn 子进程中(await ready 期间也在此 stage)
40477
+ "running",
40478
+ // dev server 跑起来了(supervisor stdout 命中 readyPattern + 端口已监听)
40479
+ "stopped",
40480
+ // 用户显式点"收起预览"停掉 / daemon 重启后默认;UI 渲染折叠条 + "展开预览"按钮
40481
+ "failed"
40482
+ // 某个阶段失败(stageReason 字段携带原因,含 dev server cold start timeout)
40483
+ ];
40484
+ var ProjectStageSchema = external_exports.enum(PROJECT_STAGE_VALUES);
40485
+ var ProjectWithStatusSchema = ProjectMetadataSchema.extend({
40486
+ isRunning: external_exports.boolean(),
40487
+ boundSessionId: external_exports.string().nullable(),
40488
+ /**
40489
+ * 单栏 refactor stage fix (spec 2026-06-02 §5.6.2):daemon 内存维护的当前 stage。
40490
+ * UI 据此切 PreviewPane spinner / iframe / error。
40491
+ * optional 兼容启动后 daemon 还没有 stage 记录的 fresh project(按 isRunning 推断兜底)。
40492
+ */
40493
+ stage: ProjectStageSchema.optional(),
40494
+ /** stage='failed' 时携带失败原因 */
40495
+ stageReason: external_exports.string().optional(),
40496
+ /**
40497
+ * 发布上线脚手架化 (spec 2026-06-03-app-builder-publish-scaffold-design §5.1.3):
40498
+ * ProjectMetadata.publishJob 的 status 派生版。daemon 响应时按以下规则实时拼装:
40499
+ * - 落盘字段存在 + PublishJobRegistry 有匹配 jobId → 'in-flight'
40500
+ * - 落盘字段存在 + Registry 无匹配(jobId 对不上或 entry 缺失)→ 'interrupted'(daemon 崩残骸)
40501
+ * - 落盘字段不存在 → undefined(字段省略)
40502
+ * UI 用 status 决定 PreviewPane 渲染分支(in-flight 三段 checklist / interrupted 恢复条)。
40503
+ */
40504
+ publishJob: external_exports.object({
40505
+ jobId: external_exports.string().min(1),
40506
+ stage: external_exports.enum(["build", "deploy", "verify"]),
40507
+ startedAt: external_exports.number().int().nonnegative(),
40508
+ status: external_exports.enum(["in-flight", "interrupted"])
40509
+ }).optional()
40510
+ });
40511
+ var ListProjectsArgsSchema = external_exports.object({}).strict();
40512
+ var ListProjectsResultSchema = external_exports.object({
40513
+ projects: external_exports.array(ProjectWithStatusSchema)
40514
+ }).strict();
40515
+ var GetProjectArgsSchema = external_exports.object({
40516
+ sessionId: external_exports.string().min(1)
40517
+ }).strict();
40518
+ var GetProjectResultSchema = external_exports.object({
40519
+ /** session 未绑 project / project 不存在时为 null(UI 走单栏 / 折叠) */
40520
+ project: ProjectWithStatusSchema.nullable()
40521
+ }).strict();
40522
+ var CreateProjectArgsSchema = external_exports.object({
40523
+ /** 必填:caller session,daemon 自动绑过去(spec 2026-06-02 §3 invariant 1 Session ↔ 1 Project) */
40524
+ sessionId: external_exports.string().min(1),
40525
+ name: external_exports.string()
40526
+ }).strict();
40527
+ var CreateProjectResultSchema = external_exports.object({
40528
+ project: ProjectMetadataSchema
40529
+ }).strict();
40530
+ var DeleteProjectArgsSchema = external_exports.object({
40531
+ name: external_exports.string()
40532
+ }).strict();
40533
+ var DeleteProjectResultSchema = external_exports.object({}).strict();
40534
+ var UpdateProjectPortArgsSchema = external_exports.object({
40535
+ name: external_exports.string(),
40536
+ newPort: external_exports.number().int()
40537
+ }).strict();
40538
+ var UpdateProjectPortResultSchema = external_exports.object({
40539
+ project: ProjectMetadataSchema
40540
+ }).strict();
40541
+ var SetProdUrlArgsSchema = external_exports.object({
40542
+ name: external_exports.string().regex(projectNameRegex),
40543
+ url: external_exports.string().url()
40544
+ }).strict();
40545
+ var SetProdUrlResultSchema = external_exports.object({
40546
+ project: ProjectMetadataSchema
40547
+ }).strict();
40548
+ var StartDevServerArgsSchema = external_exports.object({
40549
+ sessionId: external_exports.string().min(1),
40550
+ force: external_exports.boolean().optional()
40551
+ }).strict();
40552
+ var StartDevServerResultSchema = external_exports.object({
40553
+ project: ProjectMetadataSchema
40554
+ }).strict();
40555
+ var ASSISTANT_REPORTABLE_STAGES = [
40556
+ "installing",
40557
+ "failed"
40558
+ ];
40559
+ var ReportStageArgsSchema = external_exports.object({
40560
+ sessionId: external_exports.string().min(1),
40561
+ stage: external_exports.enum(ASSISTANT_REPORTABLE_STAGES),
40562
+ /** stage='failed' 时必填的原因(一句话),其它 stage optional */
40563
+ reason: external_exports.string().optional()
40564
+ }).strict();
40565
+ var ReportStageResultSchema = external_exports.object({
40566
+ ok: external_exports.literal(true)
40567
+ }).strict();
40568
+ var StopDevServerArgsSchema = external_exports.object({
40569
+ sessionId: external_exports.string().min(1)
40570
+ }).strict();
40571
+ var StopDevServerResultSchema = external_exports.object({
40572
+ ok: external_exports.literal(true)
40573
+ }).strict();
40574
+ var AppBuilderProjectUpdatedEventSchema = external_exports.object({
40575
+ type: external_exports.literal("appBuilder:project-updated"),
40576
+ project: ProjectWithStatusSchema,
40577
+ stage: ProjectStageSchema,
40578
+ /** stage='failed' 时的失败原因 */
40579
+ stageReason: external_exports.string().optional()
40580
+ }).strict();
40581
+ var PublishArgsSchema = external_exports.object({
40582
+ name: external_exports.string().regex(projectNameRegex)
40583
+ });
40584
+ var PublishResultSchema = external_exports.object({
40585
+ jobId: external_exports.string().min(1),
40586
+ status: external_exports.enum(["started", "already-publishing"])
40587
+ }).strict();
40588
+ var DismissPublishJobArgsSchema = external_exports.object({
40589
+ name: external_exports.string().regex(projectNameRegex)
40590
+ });
40591
+ var DismissPublishJobResultSchema = external_exports.object({
40592
+ ok: external_exports.literal(true)
40593
+ }).strict();
40594
+ var AppBuilderPublishProgressEventSchema = external_exports.object({
40595
+ type: external_exports.literal("appBuilder:publish-progress"),
40596
+ name: external_exports.string().regex(projectNameRegex),
40597
+ jobId: external_exports.string().min(1),
40598
+ stage: external_exports.enum(["build", "deploy", "verify"]),
40599
+ status: external_exports.enum(["started", "completed"])
40600
+ }).strict();
40601
+ var AppBuilderPublishFailedEventSchema = external_exports.object({
40602
+ type: external_exports.literal("appBuilder:publish-failed"),
40603
+ name: external_exports.string().regex(projectNameRegex),
40604
+ jobId: external_exports.string().min(1),
40605
+ stage: external_exports.enum(["build", "deploy", "verify", "unknown"]),
40606
+ errorSummary: external_exports.string()
40607
+ }).strict();
40608
+
40609
+ // ../protocol/src/capability.ts
40610
+ var ResourceSchema2 = external_exports.discriminatedUnion("type", [
40611
+ external_exports.object({ type: external_exports.literal("persona"), id: external_exports.string().min(1) }).strict(),
40612
+ external_exports.object({ type: external_exports.literal("chat"), id: external_exports.string().min(1) }).strict(),
40613
+ external_exports.object({ type: external_exports.literal("*") }).strict()
40614
+ ]);
40615
+ var ActionSchema = external_exports.enum(["read", "send", "admin"]);
40616
+ var GrantSchema = external_exports.object({
40617
+ resource: ResourceSchema2,
40618
+ actions: external_exports.array(ActionSchema).min(1)
40619
+ }).strict();
40620
+ var CapabilitySchema = external_exports.object({
40621
+ id: external_exports.string().min(1),
40622
+ // sha256(token) hex 64
40623
+ secretHash: external_exports.string().regex(/^[a-f0-9]{64}$/),
40624
+ displayName: external_exports.string(),
40625
+ // 空数组合法 = 纯访客(只能 DM)
40626
+ grants: external_exports.array(GrantSchema),
40627
+ issuedAt: external_exports.number().int().nonnegative(),
40628
+ expiresAt: external_exports.number().int().positive().optional(),
40629
+ maxUses: external_exports.number().int().positive().optional(),
40630
+ usedCount: external_exports.number().int().nonnegative(),
40631
+ /**
40632
+ * guest 在 auth 帧捎带 selfPrincipalId 时由 AuthGate.authenticate 回写;
40633
+ * 未被消费的 cap 此字段缺失。
40634
+ */
40635
+ peerOwnerId: external_exports.string().min(1).optional(),
40636
+ /** 首次 client hello 时间戳(与 peerOwnerId 同步写入) */
40637
+ firstUsedByPeerAt: external_exports.number().int().positive().optional(),
40638
+ /**
40639
+ * 对方 daemon owner 的 displayName,guest auth 帧 selfDisplayName 触发
40640
+ * recordPeerHello 时同步回写。视角 B (2026-05-23) UI 派生联系人列表用此字段
40641
+ * 显示对方名字(避免 fallback 到我颁 cap 时填的 displayName)。
40642
+ */
40643
+ peerDisplayName: external_exports.string().optional()
40644
+ }).strict();
40645
+ var CapabilityWireSchema = CapabilitySchema.omit({ secretHash: true });
40646
+ var CapabilityErrorCodeSchema = external_exports.enum([
40647
+ "TOKEN_INVALID",
40648
+ "TOKEN_REVOKED",
40649
+ "TOKEN_EXPIRED",
40650
+ "TOKEN_EXHAUSTED"
40651
+ ]);
40652
+ var WhoamiResponseSchema = external_exports.object({
40653
+ type: external_exports.literal("whoami:ok"),
40654
+ owner: external_exports.object({
40655
+ id: external_exports.string(),
40656
+ kind: external_exports.enum(["owner", "guest"]),
40657
+ displayName: external_exports.string(),
40658
+ /** 归属人 id(决策 #16:TTC unique_id 等,落 contact.ownerId) */
40659
+ ownerId: external_exports.string(),
40660
+ /** 身份来源(决策 #16:'ttc'/'google',落 contact.provider) */
40661
+ provider: external_exports.string()
40662
+ }).strict(),
40663
+ capability: CapabilityWireSchema,
40664
+ grantedPersonas: external_exports.array(
40665
+ external_exports.object({
40666
+ id: external_exports.string().min(1),
40667
+ displayName: external_exports.string()
40668
+ }).strict()
40669
+ )
40670
+ }).strict();
40671
+ var PERSONAL_CAP_GRANTS = Object.freeze([
40672
+ Object.freeze({
40673
+ resource: Object.freeze({ type: "persona", id: "*" }),
40674
+ actions: Object.freeze(["read", "send"])
40675
+ })
40676
+ ]);
40677
+
40678
+ // ../protocol/src/inbox.ts
40679
+ var InboxMessageSchema = external_exports.object({
40680
+ id: external_exports.string().min(1),
40681
+ peerDeviceId: external_exports.string().min(1),
40682
+ senderDeviceId: external_exports.string().min(1),
40683
+ text: external_exports.string().min(1),
40684
+ createdAt: external_exports.number().int().nonnegative(),
40685
+ readBy: external_exports.record(external_exports.string().min(1), external_exports.number().int().positive()).default({}),
40686
+ // persona 代发署名(B 版设计):非空 = 该消息由某 persona 代发,非真人手打。
40687
+ // 缺省 = 真人。routing 身份仍看 senderDeviceId;origin 只用于末端 UI 渲染来源。
40688
+ origin: external_exports.object({ kind: external_exports.literal("persona"), personaId: external_exports.string().min(1) }).optional()
40689
+ }).strict();
40690
+ var InboxPostMessageArgsSchema = external_exports.object({
40691
+ peerDeviceId: external_exports.string().min(1).optional(),
40692
+ id: external_exports.string().min(1),
40693
+ text: external_exports.string().min(1),
40694
+ createdAt: external_exports.number().int().nonnegative(),
40695
+ // persona 代发署名(跨 daemon forward 时随远程腿透传;真人发缺省)。
40696
+ origin: external_exports.object({ kind: external_exports.literal("persona"), personaId: external_exports.string().min(1) }).optional()
40697
+ }).strict();
40698
+ var InboxListArgsSchema = external_exports.object({
40699
+ peerDeviceId: external_exports.string().min(1),
40700
+ sinceCreatedAt: external_exports.number().int().nonnegative().optional()
40701
+ }).strict();
40702
+ var InboxMarkReadArgsSchema = external_exports.object({
40703
+ peerDeviceId: external_exports.string().min(1),
40704
+ upToCreatedAt: external_exports.number().int().nonnegative()
40705
+ }).strict();
40706
+ var InboxSendDmArgsSchema = external_exports.object({
40707
+ peerDeviceId: external_exports.string().min(1).optional(),
40708
+ text: external_exports.string().min(1)
40709
+ });
40710
+
40711
+ // ../protocol/src/contact.ts
40712
+ var ContactSchema = external_exports.object({
40713
+ /**
40714
+ * 对方设备标识(主键):对方 daemon 自己生成并持久化的标识(auth.json deviceId,
40715
+ * 如 dev-<uuid>),provider 无关。同 deviceId 重复 upsert 覆盖。
40716
+ */
40717
+ deviceId: external_exports.string().min(1),
40718
+ /**
40719
+ * 归属人 id(决策 #16):TTC unique_id 等,由 connect token subOwner 签名背书。
40720
+ * 与 provider 一起唯一标识一个人。DM 不再按它路由(路由用 deviceId),仅显示/分组用。
40721
+ */
40722
+ ownerId: external_exports.string().min(1),
40723
+ /** 身份来源(决策 #16):'ttc'(飞书/手机/邮箱登入 TTC)| 'google' | ...,token 背书 */
40724
+ provider: external_exports.string().min(1),
40725
+ /** 联系人显示名 */
40726
+ displayName: external_exports.string(),
40727
+ /** 该设备可达的 ws/tunnel 地址 */
40728
+ remoteUrl: external_exports.string().min(1),
40729
+ // 自动反向建立联系人(spec 决策 #11):被连接方本地验票成功后自动落 A 为
40730
+ // 联系人,但它不持有 A 颁发的 token(A 从未给它换票)→ connectToken 为空串。
40731
+ // device:connect 出站路径仍存中心 server 签发的真实 connect token(断线重连复用)。
40732
+ // 不用 .min(1):自动反向路径合法地存空串,禁止填假 token 占位(不造假数据)。
40733
+ connectToken: external_exports.string(),
40734
+ grants: external_exports.array(GrantSchema),
40735
+ addedAt: external_exports.number().int().nonnegative(),
40736
+ /**
40737
+ * pin 时间戳(ms,Date.now() 语义);null = 未 pin。sidebar 顶部固定区渲染由此驱动。
40738
+ * 老 contacts.json 缺此字段 → zod default 补 null(无破坏性升级;不 orphan)。
40739
+ * 对齐 SessionFile.pinnedAt 语义(daemon 侧持久化,contact:pin RPC 更新 → contact:pinned push)。
40740
+ */
40741
+ pinnedAt: external_exports.number().int().nullable().default(null),
40742
+ /**
40743
+ * SSH 反向访问授权(PR: contact-ssh-sandbox)。owner 视角:允许该 contact 通过 daemon
40744
+ * 专用 sshd 反向 SSH 进本机。default=false 保证老 contacts.json 兼容(zod default 补齐)。
40745
+ * 授权粒度 per-people (per-contact):借用别人 persona 本来就带信任对方本人的前提;
40746
+ * 极端场景(区别对方多个 persona)留 per-persona override 演进空间。
40747
+ */
40748
+ sshAllowed: external_exports.boolean().default(false),
40749
+ /**
40750
+ * 授权访问的目录白名单(绝对路径)。空数组 + sshAllowed=true 意味 SSH 通道能拨到但无处可读,
40751
+ * jail 会拒绝 shell 启动。由 clawd-ssh-jail 运行时读,生成 sbpl / bwrap policy 白名单。
40752
+ */
40753
+ exposedDirs: external_exports.array(external_exports.string()).default([])
40754
+ }).strict();
40755
+ var ContactWireSchema = ContactSchema;
40756
+ var ContactRemoveArgsSchema = external_exports.object({
40757
+ deviceId: external_exports.string().min(1)
40758
+ }).strict();
40759
+ var ContactRemoveOkSchema = external_exports.object({
40760
+ type: external_exports.literal("contact:remove:ok"),
40761
+ deviceId: external_exports.string().min(1)
40762
+ }).strict();
40763
+ var ContactListOkSchema = external_exports.object({
40764
+ type: external_exports.literal("contact:list:ok"),
40765
+ contacts: external_exports.array(ContactWireSchema)
40766
+ }).strict();
40767
+ var ContactAddedFrameSchema = external_exports.object({
40768
+ type: external_exports.literal("contact:added"),
40769
+ contact: ContactWireSchema
40770
+ }).strict();
40771
+ var ContactRemovedFrameSchema = external_exports.object({
40772
+ type: external_exports.literal("contact:removed"),
40773
+ deviceId: external_exports.string().min(1)
40774
+ }).strict();
40775
+ var ContactPinArgsSchema = external_exports.object({
40776
+ deviceId: external_exports.string().min(1),
40777
+ pinned: external_exports.boolean()
40778
+ }).strict();
40779
+ var ContactPinOkSchema = external_exports.object({
40780
+ type: external_exports.literal("contact:pin:ok"),
40781
+ deviceId: external_exports.string().min(1),
40782
+ pinnedAt: external_exports.number().int().nullable()
40783
+ }).strict();
40784
+ var ContactPinnedFrameSchema = external_exports.object({
40785
+ type: external_exports.literal("contact:pinned"),
40786
+ deviceId: external_exports.string().min(1),
40787
+ pinnedAt: external_exports.number().int().nullable()
40788
+ }).strict();
40789
+
40790
+ // ../protocol/src/contact-ssh.ts
40791
+ var ContactSetSshAccessArgsSchema = external_exports.object({
40792
+ deviceId: external_exports.string().min(1),
40793
+ sshAllowed: external_exports.boolean(),
40794
+ exposedDirs: external_exports.array(external_exports.string())
40795
+ }).strict();
40796
+ var ContactSetSshAccessOkSchema = external_exports.object({
40797
+ type: external_exports.literal("contact:setSshAccess:ok"),
40798
+ deviceId: external_exports.string().min(1),
40799
+ sshAllowed: external_exports.boolean(),
40800
+ exposedDirs: external_exports.array(external_exports.string())
40801
+ }).strict();
40802
+ var ContactSshKeyIssueArgsSchema = external_exports.object({
40803
+ deviceId: external_exports.string().min(1)
40804
+ }).strict();
40805
+ var ContactSshKeyIssueOkSchema = external_exports.object({
40806
+ type: external_exports.literal("contact:sshKey:issue:ok"),
40807
+ privateKeyPem: external_exports.string().min(1),
40808
+ publicKeyLine: external_exports.string().min(1)
40809
+ }).strict();
40810
+ var ContactSshAccessUpdatedFrameSchema = external_exports.object({
40811
+ type: external_exports.literal("contact:ssh-access-updated"),
40812
+ deviceId: external_exports.string().min(1),
40813
+ sshAllowed: external_exports.boolean(),
40814
+ exposedDirs: external_exports.array(external_exports.string())
40815
+ }).strict();
40816
+
40817
+ // ../protocol/src/extension.ts
40818
+ var EXT_ID_REGEX = /^[a-z0-9][a-z0-9-]*$/;
40819
+ var ExtensionStateSchema = external_exports.enum([
40820
+ "stopped",
40821
+ "starting",
40822
+ "running",
40823
+ "crashed",
40824
+ "invalid"
40825
+ ]);
40826
+ var LOCALHOST_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1"]);
40827
+ function isAllowedHostedUrl(raw) {
40828
+ let u;
40829
+ try {
40830
+ u = new URL(raw);
40831
+ } catch {
40832
+ return false;
40833
+ }
40834
+ if (u.protocol === "https:") return true;
40835
+ if (u.protocol === "http:" && LOCALHOST_HOSTS.has(u.hostname)) return true;
40836
+ return false;
40837
+ }
40838
+ var ExtensionManifestSchema = external_exports.object({
40839
+ id: external_exports.string().regex(EXT_ID_REGEX),
40840
+ name: external_exports.string().min(1),
40841
+ version: external_exports.string().min(1),
40842
+ apiVersion: external_exports.literal("1"),
40843
+ runtime: external_exports.object({ startCommand: external_exports.string().min(1) }).passthrough().optional(),
40844
+ entry: external_exports.object({
40845
+ url: external_exports.string().url().refine(isAllowedHostedUrl, {
40846
+ message: "INVALID_URL_SCHEME: only https or http://localhost is allowed"
40847
+ })
40848
+ }).strict().optional()
40849
+ }).passthrough().superRefine((m, ctx) => {
40850
+ const hasRuntime = !!m.runtime;
40851
+ const hasUrl = !!m.entry?.url;
40852
+ if (hasRuntime && hasUrl) {
40853
+ ctx.addIssue({
40854
+ code: external_exports.ZodIssueCode.custom,
40855
+ message: "INVALID_MANIFEST: entry.url and runtime cannot coexist"
40856
+ });
40857
+ }
40858
+ if (!hasRuntime && !hasUrl) {
40859
+ ctx.addIssue({
40860
+ code: external_exports.ZodIssueCode.custom,
40861
+ message: "INVALID_MANIFEST: must have either entry.url or runtime"
40862
+ });
40863
+ }
40864
+ });
40865
+ var ExtensionTargetSchema = external_exports.discriminatedUnion("kind", [
40866
+ external_exports.object({ kind: external_exports.literal("local"), port: external_exports.number().int().min(1).max(65535) }),
40867
+ external_exports.object({ kind: external_exports.literal("hosted"), url: external_exports.string().url() })
40868
+ ]);
40869
+ var ExtensionRecordSchema = external_exports.discriminatedUnion("state", [
40870
+ external_exports.object({
40871
+ extId: external_exports.string(),
40872
+ manifest: ExtensionManifestSchema,
40873
+ state: external_exports.literal("stopped")
40874
+ }),
40875
+ external_exports.object({
40876
+ extId: external_exports.string(),
40877
+ manifest: ExtensionManifestSchema,
40878
+ state: external_exports.literal("starting")
40879
+ }),
40880
+ external_exports.object({
40881
+ extId: external_exports.string(),
40882
+ manifest: ExtensionManifestSchema,
40883
+ state: external_exports.literal("running"),
40884
+ target: ExtensionTargetSchema
40885
+ }),
40886
+ external_exports.object({
40887
+ extId: external_exports.string(),
40888
+ manifest: ExtensionManifestSchema,
40889
+ state: external_exports.literal("crashed")
40890
+ }),
40891
+ external_exports.object({
40892
+ extId: external_exports.string(),
40893
+ manifest: external_exports.unknown().nullable(),
40894
+ state: external_exports.literal("invalid"),
40895
+ invalidReason: external_exports.string().min(1)
40896
+ })
40897
+ ]);
40898
+ var PublishedSnapshotSchema = external_exports.object({
40899
+ snapshotHash: external_exports.string().min(1),
40900
+ version: external_exports.string().min(1),
40901
+ publishedAt: external_exports.number()
40902
+ });
40903
+ var ChannelRefSchema = external_exports.discriminatedUnion("kind", [
40904
+ external_exports.object({
40905
+ kind: external_exports.literal("p2p-tunnel"),
40906
+ ownerPrincipalId: external_exports.string().min(1),
40907
+ extId: external_exports.string().min(1)
40908
+ })
40909
+ ]);
40910
+ var SourceRefSchema = external_exports.discriminatedUnion("kind", [
40911
+ external_exports.object({
40912
+ kind: external_exports.literal("p2p-tunnel"),
40913
+ ownerPrincipalId: external_exports.string().min(1),
40914
+ extId: external_exports.string().min(1),
40915
+ snapshotHash: external_exports.string().min(1)
40916
+ })
40917
+ ]);
40918
+ var PublishedExtensionRecordSchema = external_exports.object({
40919
+ extId: external_exports.string().min(1),
40920
+ name: external_exports.string().min(1),
40921
+ version: external_exports.string().min(1),
40922
+ contentHash: external_exports.string().min(1),
40923
+ publishedAt: external_exports.number()
40924
+ });
40925
+ var PublishCheckSchema = external_exports.discriminatedUnion("kind", [
40926
+ external_exports.object({ kind: external_exports.literal("clean") }),
40927
+ external_exports.object({
40928
+ kind: external_exports.literal("ready-new-version"),
40929
+ fromVersion: external_exports.string().min(1),
40930
+ toVersion: external_exports.string().min(1)
40931
+ }),
40932
+ external_exports.object({
40933
+ kind: external_exports.literal("error-same-hash"),
40934
+ version: external_exports.string().min(1)
40935
+ }),
40936
+ external_exports.object({
40937
+ kind: external_exports.literal("error-version-not-bumped"),
40938
+ localVersion: external_exports.string().min(1),
40939
+ publishedVersion: external_exports.string().min(1)
40940
+ }),
40941
+ external_exports.object({
40942
+ kind: external_exports.literal("error-version-regression"),
40943
+ localVersion: external_exports.string().min(1),
40944
+ publishedVersion: external_exports.string().min(1)
40945
+ })
40946
+ ]);
40947
+ var PublishStatusResultSchema = external_exports.object({
40948
+ localManifest: external_exports.object({
40949
+ name: external_exports.string().min(1),
40950
+ version: external_exports.string().min(1),
40951
+ contentHash: external_exports.string().min(1)
40952
+ }),
40953
+ publishState: external_exports.discriminatedUnion("kind", [
40954
+ external_exports.object({ kind: external_exports.literal("unpublished") }),
40955
+ external_exports.object({
40956
+ kind: external_exports.literal("published"),
40957
+ version: external_exports.string().min(1),
40958
+ contentHash: external_exports.string().min(1),
40959
+ publishedAt: external_exports.number()
40960
+ })
40961
+ ]),
40962
+ check: PublishCheckSchema
40963
+ });
40964
+
40965
+ // ../protocol/src/feishu-auth.ts
40966
+ var DeviceEntrySchema = external_exports.object({
40967
+ /**
40968
+ * 设备标识(决策 #15:daemon 本地生成的 dev-<uuid>,与人的身份 unionId 无关)。
40969
+ * 中心 server clawd_devices 注册表仅作服务发现(url 下发 + 目录),不在安全路径上。
40970
+ */
40971
+ deviceId: external_exports.string().min(1),
40972
+ /** 显示名 */
40973
+ name: external_exports.string().min(1),
40974
+ /** ws/tunnel 地址 */
40975
+ url: external_exports.string().min(1)
40976
+ });
40977
+ var DeviceListResponseSchema = external_exports.object({
40978
+ type: external_exports.literal("device:list:ok"),
40979
+ devices: external_exports.array(DeviceEntrySchema)
40980
+ });
40981
+ var DeviceConnectArgsSchema = external_exports.object({
40982
+ /** 目标设备的 deviceId(对方 daemon 生成的 dev-<uuid>) */
40983
+ deviceId: external_exports.string().min(1),
40984
+ /**
40985
+ * 目标设备的 ws/tunnel 地址(可选):
40986
+ * - 公开目录点击:带 url(device:list 已下发,省一次 server 查询)
40987
+ * - 凭 deviceId 连接:缺省 url → daemon exchange 时由中心 server 下发该设备上报的 url
40988
+ * - 注册表不在安全路径上:知道对方 url 时显式传入即可连接(不依赖中心 server 服务发现)
40989
+ */
40990
+ url: external_exports.string().min(1).optional(),
40991
+ /** 显示名(公共设备来自目录;缺省时连上后用 whoami 回填) */
40992
+ name: external_exports.string().optional()
40993
+ });
40994
+ var DeviceConnectResponseSchema = external_exports.object({
40995
+ type: external_exports.literal("device:connect:ok"),
40996
+ /** 连接的目标设备标识(= 请求 args.deviceId) */
40997
+ deviceId: external_exports.string(),
40998
+ name: external_exports.string(),
40999
+ url: external_exports.string()
41000
+ });
41001
+ var FeishuIdentitySchema = external_exports.object({
41002
+ /** 归属人 id(决策 #16:TTC unique_id,取代飞书 union_id;跨登录方式稳定) */
41003
+ ownerId: external_exports.string().min(1),
41004
+ /** 身份来源:'ttc'(飞书/手机/邮箱登入 TTC)| 'google' | ...(决策 #16,拓展用) */
41005
+ provider: external_exports.string().min(1),
41006
+ /** 显示名。TTC user_info 接口 data.name */
41007
+ displayName: external_exports.string().min(1),
41008
+ /** TTC user_info 接口 data.avatar_url,可缺省 */
41009
+ avatarUrl: external_exports.string().optional(),
41010
+ /** TTC user_info 接口 data.union_id(飞书 union_id;dataclaw 可信入口 X-User-UnionId 用),可缺省 */
41011
+ unionId: external_exports.string().optional()
41012
+ });
41013
+ var AuthLoginStartResponseSchema = external_exports.object({
41014
+ type: external_exports.literal("auth:login:start:ok"),
41015
+ /** 完整 TTC 授权页 URL(含 callback_url + state + auto=1),UI 直接 window.open */
41016
+ authUrl: external_exports.string().min(1),
41017
+ /** 防 CSRF 的一次性 nonce;回调时 daemon 校验 */
41018
+ state: external_exports.string().min(1)
41019
+ });
41020
+ var AuthGetIdentityResponseSchema = external_exports.object({
41021
+ type: external_exports.literal("auth:getIdentity:ok"),
41022
+ /** null = 未登录 */
41023
+ identity: FeishuIdentitySchema.nullable(),
41024
+ /**
41025
+ * 本机设备标识(决策 #15:daemon 生成并持久化在 auth.json,如 dev-<uuid>)。
41026
+ * 设备属性,与登录态无关、登录登出不变。UI"我的设备标识"用它拼
41027
+ * clawos://device/<deviceId>(替代旧的 unionId——不再向外暴露人的身份标识)。
41028
+ */
41029
+ deviceId: external_exports.string().min(1)
41030
+ });
41031
+ var AuthLogoutResponseSchema = external_exports.object({
41032
+ type: external_exports.literal("auth:logout:ok")
41033
+ });
41034
+ var AuthLoginDoneEventSchema = external_exports.object({
41035
+ type: external_exports.literal("auth:login:done"),
41036
+ identity: FeishuIdentitySchema
41037
+ });
41038
+ var AuthLoginFailedEventSchema = external_exports.object({
41039
+ type: external_exports.literal("auth:login:failed"),
41040
+ reason: external_exports.string()
41041
+ });
41042
+
41043
+ // ../protocol/src/dispatch.ts
41044
+ var DispatchOutcomeSchema = external_exports.discriminatedUnion("kind", [
41045
+ external_exports.object({
41046
+ kind: external_exports.literal("success"),
41047
+ text: external_exports.string(),
41048
+ filePaths: external_exports.array(external_exports.string()).optional()
41049
+ }),
41050
+ external_exports.object({
41051
+ kind: external_exports.literal("failure"),
41052
+ reason: external_exports.string()
41053
+ })
41054
+ ]);
41055
+ var DispatchRunArgsSchema = external_exports.object({
41056
+ targetPersona: external_exports.string().min(1),
41057
+ prompt: external_exports.string(),
41058
+ // 跨设备 dispatch:非空 = A 角色,转发到该 contact deviceId 的 peer daemon;
41059
+ // 省略 = 本地 dispatch / B 角色本地执行。A 转发给 B 时 body 不带此字段。
41060
+ targetDeviceId: external_exports.string().min(1).optional(),
41061
+ // 可选:override B session 使用的 claude 模型。缺省 = 用 persona 默认。
41062
+ // 合法值集与 claude adapter capabilities.models[].id 一致(见 daemon
41063
+ // tools/claude.ts CLAUDE_MODEL_IDS);handler 层做二次校验,非法值 fail-fast。
41064
+ // protocol 层保持 string 便于未来跨 tool 扩展(届时 union 收合法字面量)。
41065
+ model: external_exports.string().min(1).optional()
41066
+ });
41067
+ var DispatchCompleteArgsSchema = external_exports.object({
41068
+ dispatchId: external_exports.string().min(1),
41069
+ outcome: DispatchOutcomeSchema
41070
+ });
41071
+
41072
+ // ../protocol/src/log.ts
41073
+ var LOG_SOURCES = ["daemon", "main", "renderer"];
41074
+ var LogSourceSchema = external_exports.enum(LOG_SOURCES);
41075
+ var LOG_LEVELS = ["debug", "info", "warn", "error"];
41076
+ var LogLevelSchema = external_exports.enum(LOG_LEVELS);
41077
+ var LogRecordSchema = external_exports.object({
41078
+ ts: external_exports.number().int(),
41079
+ source: LogSourceSchema,
41080
+ level: LogLevelSchema,
41081
+ msg: external_exports.string(),
41082
+ ownerPrincipalId: external_exports.string(),
41083
+ deviceId: external_exports.string(),
41084
+ appVersion: external_exports.string(),
41085
+ daemonVersion: external_exports.string().optional(),
41086
+ os: external_exports.string(),
41087
+ meta_json: external_exports.string().optional(),
41088
+ sessionId: external_exports.string().optional()
41089
+ });
41090
+
41091
+ // ../protocol/src/visitor-schemas.ts
41092
+ var VisitorTokenPayloadSchema = external_exports.object({
41093
+ v: external_exports.literal(1),
41094
+ visitorId: external_exports.string().min(1),
41095
+ displayName: external_exports.string(),
41096
+ provider: external_exports.string(),
41097
+ iat: external_exports.number(),
41098
+ exp: external_exports.number()
41099
+ });
41100
+ var VisitorRecordSchema = external_exports.object({
41101
+ visitorId: external_exports.string(),
41102
+ displayName: external_exports.string(),
41103
+ avatarUrl: external_exports.string().optional(),
41104
+ provider: external_exports.string(),
41105
+ firstSeen: external_exports.number(),
41106
+ lastSeen: external_exports.number()
41107
+ });
41108
+ var VisitorListResultSchema = external_exports.object({ visitors: external_exports.array(VisitorRecordSchema) });
41109
+
41110
+ // src/tools/claude-history.ts
41111
+ var import_node_fs = __toESM(require("fs"), 1);
41112
+ var import_node_os = __toESM(require("os"), 1);
41113
+ var import_node_path = __toESM(require("path"), 1);
41114
+
41115
+ // ../node_modules/.pnpm/diff@7.0.0/node_modules/diff/lib/index.mjs
41116
+ function Diff() {
41117
+ }
41118
+ Diff.prototype = {
41119
+ diff: function diff(oldString, newString) {
41120
+ var _options$timeout;
41121
+ var options = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : {};
41122
+ var callback = options.callback;
41123
+ if (typeof options === "function") {
41124
+ callback = options;
41125
+ options = {};
41126
+ }
41127
+ var self = this;
41128
+ function done(value) {
41129
+ value = self.postProcess(value, options);
41130
+ if (callback) {
41131
+ setTimeout(function() {
41132
+ callback(value);
41133
+ }, 0);
41134
+ return true;
41135
+ } else {
41136
+ return value;
41137
+ }
41138
+ }
41139
+ oldString = this.castInput(oldString, options);
41140
+ newString = this.castInput(newString, options);
41141
+ oldString = this.removeEmpty(this.tokenize(oldString, options));
41142
+ newString = this.removeEmpty(this.tokenize(newString, options));
41143
+ var newLen = newString.length, oldLen = oldString.length;
41144
+ var editLength = 1;
41145
+ var maxEditLength = newLen + oldLen;
41146
+ if (options.maxEditLength != null) {
41147
+ maxEditLength = Math.min(maxEditLength, options.maxEditLength);
41148
+ }
41149
+ var maxExecutionTime = (_options$timeout = options.timeout) !== null && _options$timeout !== void 0 ? _options$timeout : Infinity;
41150
+ var abortAfterTimestamp = Date.now() + maxExecutionTime;
41151
+ var bestPath = [{
41152
+ oldPos: -1,
41153
+ lastComponent: void 0
41154
+ }];
41155
+ var newPos = this.extractCommon(bestPath[0], newString, oldString, 0, options);
41156
+ if (bestPath[0].oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
41157
+ return done(buildValues(self, bestPath[0].lastComponent, newString, oldString, self.useLongestToken));
41158
+ }
41159
+ var minDiagonalToConsider = -Infinity, maxDiagonalToConsider = Infinity;
41160
+ function execEditLength() {
41161
+ for (var diagonalPath = Math.max(minDiagonalToConsider, -editLength); diagonalPath <= Math.min(maxDiagonalToConsider, editLength); diagonalPath += 2) {
41162
+ var basePath = void 0;
41163
+ var removePath = bestPath[diagonalPath - 1], addPath = bestPath[diagonalPath + 1];
41164
+ if (removePath) {
41165
+ bestPath[diagonalPath - 1] = void 0;
41166
+ }
41167
+ var canAdd = false;
41168
+ if (addPath) {
41169
+ var addPathNewPos = addPath.oldPos - diagonalPath;
41170
+ canAdd = addPath && 0 <= addPathNewPos && addPathNewPos < newLen;
41171
+ }
41172
+ var canRemove = removePath && removePath.oldPos + 1 < oldLen;
41173
+ if (!canAdd && !canRemove) {
41174
+ bestPath[diagonalPath] = void 0;
41175
+ continue;
41176
+ }
41177
+ if (!canRemove || canAdd && removePath.oldPos < addPath.oldPos) {
41178
+ basePath = self.addToPath(addPath, true, false, 0, options);
41179
+ } else {
41180
+ basePath = self.addToPath(removePath, false, true, 1, options);
41181
+ }
41182
+ newPos = self.extractCommon(basePath, newString, oldString, diagonalPath, options);
41183
+ if (basePath.oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
41184
+ return done(buildValues(self, basePath.lastComponent, newString, oldString, self.useLongestToken));
41185
+ } else {
41186
+ bestPath[diagonalPath] = basePath;
41187
+ if (basePath.oldPos + 1 >= oldLen) {
41188
+ maxDiagonalToConsider = Math.min(maxDiagonalToConsider, diagonalPath - 1);
41189
+ }
41190
+ if (newPos + 1 >= newLen) {
41191
+ minDiagonalToConsider = Math.max(minDiagonalToConsider, diagonalPath + 1);
41192
+ }
41193
+ }
41194
+ }
41195
+ editLength++;
41196
+ }
41197
+ if (callback) {
41198
+ (function exec() {
41199
+ setTimeout(function() {
41200
+ if (editLength > maxEditLength || Date.now() > abortAfterTimestamp) {
41201
+ return callback();
41202
+ }
41203
+ if (!execEditLength()) {
41204
+ exec();
41205
+ }
41206
+ }, 0);
41207
+ })();
41208
+ } else {
41209
+ while (editLength <= maxEditLength && Date.now() <= abortAfterTimestamp) {
41210
+ var ret = execEditLength();
41211
+ if (ret) {
41212
+ return ret;
41213
+ }
41214
+ }
41215
+ }
41216
+ },
41217
+ addToPath: function addToPath(path2, added, removed, oldPosInc, options) {
41218
+ var last = path2.lastComponent;
41219
+ if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
41220
+ return {
41221
+ oldPos: path2.oldPos + oldPosInc,
41222
+ lastComponent: {
41223
+ count: last.count + 1,
41224
+ added,
41225
+ removed,
41226
+ previousComponent: last.previousComponent
41227
+ }
41228
+ };
41229
+ } else {
41230
+ return {
41231
+ oldPos: path2.oldPos + oldPosInc,
41232
+ lastComponent: {
41233
+ count: 1,
41234
+ added,
41235
+ removed,
41236
+ previousComponent: last
41237
+ }
41238
+ };
41239
+ }
41240
+ },
41241
+ extractCommon: function extractCommon(basePath, newString, oldString, diagonalPath, options) {
41242
+ var newLen = newString.length, oldLen = oldString.length, oldPos = basePath.oldPos, newPos = oldPos - diagonalPath, commonCount = 0;
41243
+ while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(oldString[oldPos + 1], newString[newPos + 1], options)) {
41244
+ newPos++;
41245
+ oldPos++;
41246
+ commonCount++;
41247
+ if (options.oneChangePerToken) {
41248
+ basePath.lastComponent = {
41249
+ count: 1,
41250
+ previousComponent: basePath.lastComponent,
41251
+ added: false,
41252
+ removed: false
41253
+ };
41254
+ }
41255
+ }
41256
+ if (commonCount && !options.oneChangePerToken) {
41257
+ basePath.lastComponent = {
41258
+ count: commonCount,
41259
+ previousComponent: basePath.lastComponent,
41260
+ added: false,
41261
+ removed: false
41262
+ };
41263
+ }
41264
+ basePath.oldPos = oldPos;
41265
+ return newPos;
41266
+ },
41267
+ equals: function equals(left, right, options) {
41268
+ if (options.comparator) {
41269
+ return options.comparator(left, right);
41270
+ } else {
41271
+ return left === right || options.ignoreCase && left.toLowerCase() === right.toLowerCase();
41272
+ }
41273
+ },
41274
+ removeEmpty: function removeEmpty(array2) {
41275
+ var ret = [];
41276
+ for (var i = 0; i < array2.length; i++) {
41277
+ if (array2[i]) {
41278
+ ret.push(array2[i]);
41279
+ }
41280
+ }
41281
+ return ret;
41282
+ },
41283
+ castInput: function castInput(value) {
41284
+ return value;
41285
+ },
41286
+ tokenize: function tokenize(value) {
41287
+ return Array.from(value);
41288
+ },
41289
+ join: function join(chars) {
41290
+ return chars.join("");
41291
+ },
41292
+ postProcess: function postProcess(changeObjects) {
41293
+ return changeObjects;
41294
+ }
41295
+ };
41296
+ function buildValues(diff2, lastComponent, newString, oldString, useLongestToken) {
41297
+ var components = [];
41298
+ var nextComponent;
41299
+ while (lastComponent) {
41300
+ components.push(lastComponent);
41301
+ nextComponent = lastComponent.previousComponent;
41302
+ delete lastComponent.previousComponent;
41303
+ lastComponent = nextComponent;
41304
+ }
41305
+ components.reverse();
41306
+ var componentPos = 0, componentLen = components.length, newPos = 0, oldPos = 0;
41307
+ for (; componentPos < componentLen; componentPos++) {
41308
+ var component = components[componentPos];
41309
+ if (!component.removed) {
41310
+ if (!component.added && useLongestToken) {
41311
+ var value = newString.slice(newPos, newPos + component.count);
41312
+ value = value.map(function(value2, i) {
41313
+ var oldValue = oldString[oldPos + i];
41314
+ return oldValue.length > value2.length ? oldValue : value2;
41315
+ });
41316
+ component.value = diff2.join(value);
41317
+ } else {
41318
+ component.value = diff2.join(newString.slice(newPos, newPos + component.count));
41319
+ }
41320
+ newPos += component.count;
41321
+ if (!component.added) {
41322
+ oldPos += component.count;
41323
+ }
41324
+ } else {
41325
+ component.value = diff2.join(oldString.slice(oldPos, oldPos + component.count));
41326
+ oldPos += component.count;
41327
+ }
41328
+ }
41329
+ return components;
41330
+ }
41331
+ var characterDiff = new Diff();
41332
+ function longestCommonPrefix(str1, str2) {
41333
+ var i;
41334
+ for (i = 0; i < str1.length && i < str2.length; i++) {
41335
+ if (str1[i] != str2[i]) {
41336
+ return str1.slice(0, i);
41337
+ }
41338
+ }
41339
+ return str1.slice(0, i);
41340
+ }
41341
+ function longestCommonSuffix(str1, str2) {
41342
+ var i;
41343
+ if (!str1 || !str2 || str1[str1.length - 1] != str2[str2.length - 1]) {
41344
+ return "";
41345
+ }
41346
+ for (i = 0; i < str1.length && i < str2.length; i++) {
41347
+ if (str1[str1.length - (i + 1)] != str2[str2.length - (i + 1)]) {
41348
+ return str1.slice(-i);
41349
+ }
41350
+ }
41351
+ return str1.slice(-i);
41352
+ }
41353
+ function replacePrefix(string3, oldPrefix, newPrefix) {
41354
+ if (string3.slice(0, oldPrefix.length) != oldPrefix) {
41355
+ throw Error("string ".concat(JSON.stringify(string3), " doesn't start with prefix ").concat(JSON.stringify(oldPrefix), "; this is a bug"));
41356
+ }
41357
+ return newPrefix + string3.slice(oldPrefix.length);
41358
+ }
41359
+ function replaceSuffix(string3, oldSuffix, newSuffix) {
41360
+ if (!oldSuffix) {
41361
+ return string3 + newSuffix;
41362
+ }
41363
+ if (string3.slice(-oldSuffix.length) != oldSuffix) {
41364
+ throw Error("string ".concat(JSON.stringify(string3), " doesn't end with suffix ").concat(JSON.stringify(oldSuffix), "; this is a bug"));
41365
+ }
41366
+ return string3.slice(0, -oldSuffix.length) + newSuffix;
41367
+ }
41368
+ function removePrefix(string3, oldPrefix) {
41369
+ return replacePrefix(string3, oldPrefix, "");
41370
+ }
41371
+ function removeSuffix(string3, oldSuffix) {
41372
+ return replaceSuffix(string3, oldSuffix, "");
41373
+ }
41374
+ function maximumOverlap(string1, string22) {
41375
+ return string22.slice(0, overlapCount(string1, string22));
41376
+ }
41377
+ function overlapCount(a, b) {
41378
+ var startA = 0;
41379
+ if (a.length > b.length) {
41380
+ startA = a.length - b.length;
41381
+ }
41382
+ var endB = b.length;
41383
+ if (a.length < b.length) {
41384
+ endB = a.length;
41385
+ }
41386
+ var map = Array(endB);
41387
+ var k = 0;
41388
+ map[0] = 0;
41389
+ for (var j = 1; j < endB; j++) {
41390
+ if (b[j] == b[k]) {
41391
+ map[j] = map[k];
41392
+ } else {
41393
+ map[j] = k;
41394
+ }
41395
+ while (k > 0 && b[j] != b[k]) {
41396
+ k = map[k];
41397
+ }
41398
+ if (b[j] == b[k]) {
41399
+ k++;
41400
+ }
41401
+ }
41402
+ k = 0;
41403
+ for (var i = startA; i < a.length; i++) {
41404
+ while (k > 0 && a[i] != b[k]) {
41405
+ k = map[k];
41406
+ }
41407
+ if (a[i] == b[k]) {
41408
+ k++;
41409
+ }
41410
+ }
41411
+ return k;
41412
+ }
41413
+ var extendedWordChars = "a-zA-Z0-9_\\u{C0}-\\u{FF}\\u{D8}-\\u{F6}\\u{F8}-\\u{2C6}\\u{2C8}-\\u{2D7}\\u{2DE}-\\u{2FF}\\u{1E00}-\\u{1EFF}";
41414
+ var tokenizeIncludingWhitespace = new RegExp("[".concat(extendedWordChars, "]+|\\s+|[^").concat(extendedWordChars, "]"), "ug");
41415
+ var wordDiff = new Diff();
41416
+ wordDiff.equals = function(left, right, options) {
41417
+ if (options.ignoreCase) {
41418
+ left = left.toLowerCase();
41419
+ right = right.toLowerCase();
41420
+ }
41421
+ return left.trim() === right.trim();
41422
+ };
41423
+ wordDiff.tokenize = function(value) {
41424
+ var options = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
41425
+ var parts;
41426
+ if (options.intlSegmenter) {
41427
+ if (options.intlSegmenter.resolvedOptions().granularity != "word") {
41428
+ throw new Error('The segmenter passed must have a granularity of "word"');
41429
+ }
41430
+ parts = Array.from(options.intlSegmenter.segment(value), function(segment) {
41431
+ return segment.segment;
41432
+ });
41433
+ } else {
41434
+ parts = value.match(tokenizeIncludingWhitespace) || [];
41435
+ }
41436
+ var tokens = [];
41437
+ var prevPart = null;
41438
+ parts.forEach(function(part) {
41439
+ if (/\s/.test(part)) {
41440
+ if (prevPart == null) {
41441
+ tokens.push(part);
41442
+ } else {
41443
+ tokens.push(tokens.pop() + part);
41444
+ }
41445
+ } else if (/\s/.test(prevPart)) {
41446
+ if (tokens[tokens.length - 1] == prevPart) {
41447
+ tokens.push(tokens.pop() + part);
41448
+ } else {
41449
+ tokens.push(prevPart + part);
41450
+ }
41451
+ } else {
41452
+ tokens.push(part);
41453
+ }
41454
+ prevPart = part;
41455
+ });
41456
+ return tokens;
41457
+ };
41458
+ wordDiff.join = function(tokens) {
41459
+ return tokens.map(function(token, i) {
41460
+ if (i == 0) {
41461
+ return token;
41462
+ } else {
41463
+ return token.replace(/^\s+/, "");
41464
+ }
41465
+ }).join("");
41466
+ };
41467
+ wordDiff.postProcess = function(changes, options) {
41468
+ if (!changes || options.oneChangePerToken) {
41469
+ return changes;
41470
+ }
41471
+ var lastKeep = null;
41472
+ var insertion = null;
41473
+ var deletion = null;
41474
+ changes.forEach(function(change) {
41475
+ if (change.added) {
41476
+ insertion = change;
41477
+ } else if (change.removed) {
41478
+ deletion = change;
41479
+ } else {
41480
+ if (insertion || deletion) {
41481
+ dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, change);
41482
+ }
41483
+ lastKeep = change;
41484
+ insertion = null;
41485
+ deletion = null;
41486
+ }
41487
+ });
41488
+ if (insertion || deletion) {
41489
+ dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, null);
41490
+ }
41491
+ return changes;
41492
+ };
41493
+ function dedupeWhitespaceInChangeObjects(startKeep, deletion, insertion, endKeep) {
41494
+ if (deletion && insertion) {
41495
+ var oldWsPrefix = deletion.value.match(/^\s*/)[0];
41496
+ var oldWsSuffix = deletion.value.match(/\s*$/)[0];
41497
+ var newWsPrefix = insertion.value.match(/^\s*/)[0];
41498
+ var newWsSuffix = insertion.value.match(/\s*$/)[0];
41499
+ if (startKeep) {
41500
+ var commonWsPrefix = longestCommonPrefix(oldWsPrefix, newWsPrefix);
41501
+ startKeep.value = replaceSuffix(startKeep.value, newWsPrefix, commonWsPrefix);
41502
+ deletion.value = removePrefix(deletion.value, commonWsPrefix);
41503
+ insertion.value = removePrefix(insertion.value, commonWsPrefix);
41504
+ }
41505
+ if (endKeep) {
41506
+ var commonWsSuffix = longestCommonSuffix(oldWsSuffix, newWsSuffix);
41507
+ endKeep.value = replacePrefix(endKeep.value, newWsSuffix, commonWsSuffix);
41508
+ deletion.value = removeSuffix(deletion.value, commonWsSuffix);
41509
+ insertion.value = removeSuffix(insertion.value, commonWsSuffix);
41510
+ }
41511
+ } else if (insertion) {
41512
+ if (startKeep) {
41513
+ insertion.value = insertion.value.replace(/^\s*/, "");
41514
+ }
41515
+ if (endKeep) {
41516
+ endKeep.value = endKeep.value.replace(/^\s*/, "");
41517
+ }
41518
+ } else if (startKeep && endKeep) {
41519
+ var newWsFull = endKeep.value.match(/^\s*/)[0], delWsStart = deletion.value.match(/^\s*/)[0], delWsEnd = deletion.value.match(/\s*$/)[0];
41520
+ var newWsStart = longestCommonPrefix(newWsFull, delWsStart);
41521
+ deletion.value = removePrefix(deletion.value, newWsStart);
41522
+ var newWsEnd = longestCommonSuffix(removePrefix(newWsFull, newWsStart), delWsEnd);
41523
+ deletion.value = removeSuffix(deletion.value, newWsEnd);
41524
+ endKeep.value = replacePrefix(endKeep.value, newWsFull, newWsEnd);
41525
+ startKeep.value = replaceSuffix(startKeep.value, newWsFull, newWsFull.slice(0, newWsFull.length - newWsEnd.length));
41526
+ } else if (endKeep) {
41527
+ var endKeepWsPrefix = endKeep.value.match(/^\s*/)[0];
41528
+ var deletionWsSuffix = deletion.value.match(/\s*$/)[0];
41529
+ var overlap = maximumOverlap(deletionWsSuffix, endKeepWsPrefix);
41530
+ deletion.value = removeSuffix(deletion.value, overlap);
41531
+ } else if (startKeep) {
41532
+ var startKeepWsSuffix = startKeep.value.match(/\s*$/)[0];
41533
+ var deletionWsPrefix = deletion.value.match(/^\s*/)[0];
41534
+ var _overlap = maximumOverlap(startKeepWsSuffix, deletionWsPrefix);
41535
+ deletion.value = removePrefix(deletion.value, _overlap);
41536
+ }
41537
+ }
41538
+ var wordWithSpaceDiff = new Diff();
41539
+ wordWithSpaceDiff.tokenize = function(value) {
41540
+ var regex = new RegExp("(\\r?\\n)|[".concat(extendedWordChars, "]+|[^\\S\\n\\r]+|[^").concat(extendedWordChars, "]"), "ug");
41541
+ return value.match(regex) || [];
41542
+ };
41543
+ var lineDiff = new Diff();
41544
+ lineDiff.tokenize = function(value, options) {
41545
+ if (options.stripTrailingCr) {
41546
+ value = value.replace(/\r\n/g, "\n");
41547
+ }
41548
+ var retLines = [], linesAndNewlines = value.split(/(\n|\r\n)/);
41549
+ if (!linesAndNewlines[linesAndNewlines.length - 1]) {
41550
+ linesAndNewlines.pop();
41551
+ }
41552
+ for (var i = 0; i < linesAndNewlines.length; i++) {
41553
+ var line = linesAndNewlines[i];
41554
+ if (i % 2 && !options.newlineIsToken) {
41555
+ retLines[retLines.length - 1] += line;
41556
+ } else {
41557
+ retLines.push(line);
41558
+ }
41559
+ }
41560
+ return retLines;
41561
+ };
41562
+ lineDiff.equals = function(left, right, options) {
41563
+ if (options.ignoreWhitespace) {
41564
+ if (!options.newlineIsToken || !left.includes("\n")) {
41565
+ left = left.trim();
41566
+ }
41567
+ if (!options.newlineIsToken || !right.includes("\n")) {
41568
+ right = right.trim();
41569
+ }
41570
+ } else if (options.ignoreNewlineAtEof && !options.newlineIsToken) {
41571
+ if (left.endsWith("\n")) {
41572
+ left = left.slice(0, -1);
41573
+ }
41574
+ if (right.endsWith("\n")) {
41575
+ right = right.slice(0, -1);
41576
+ }
41577
+ }
41578
+ return Diff.prototype.equals.call(this, left, right, options);
41579
+ };
41580
+ var sentenceDiff = new Diff();
41581
+ sentenceDiff.tokenize = function(value) {
41582
+ return value.split(/(\S.+?[.!?])(?=\s+|$)/);
41583
+ };
41584
+ var cssDiff = new Diff();
41585
+ cssDiff.tokenize = function(value) {
41586
+ return value.split(/([{}:;,]|\s+)/);
41587
+ };
41588
+ function _typeof(o) {
41589
+ "@babel/helpers - typeof";
41590
+ return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o2) {
41591
+ return typeof o2;
41592
+ } : function(o2) {
41593
+ return o2 && "function" == typeof Symbol && o2.constructor === Symbol && o2 !== Symbol.prototype ? "symbol" : typeof o2;
41594
+ }, _typeof(o);
41595
+ }
41596
+ var jsonDiff = new Diff();
41597
+ jsonDiff.useLongestToken = true;
41598
+ jsonDiff.tokenize = lineDiff.tokenize;
41599
+ jsonDiff.castInput = function(value, options) {
41600
+ var undefinedReplacement = options.undefinedReplacement, _options$stringifyRep = options.stringifyReplacer, stringifyReplacer = _options$stringifyRep === void 0 ? function(k, v) {
41601
+ return typeof v === "undefined" ? undefinedReplacement : v;
41602
+ } : _options$stringifyRep;
41603
+ return typeof value === "string" ? value : JSON.stringify(canonicalize(value, null, null, stringifyReplacer), stringifyReplacer, " ");
41604
+ };
41605
+ jsonDiff.equals = function(left, right, options) {
41606
+ return Diff.prototype.equals.call(jsonDiff, left.replace(/,([\r\n])/g, "$1"), right.replace(/,([\r\n])/g, "$1"), options);
41607
+ };
41608
+ function canonicalize(obj, stack, replacementStack, replacer, key) {
41609
+ stack = stack || [];
41610
+ replacementStack = replacementStack || [];
41611
+ if (replacer) {
41612
+ obj = replacer(key, obj);
41613
+ }
41614
+ var i;
41615
+ for (i = 0; i < stack.length; i += 1) {
41616
+ if (stack[i] === obj) {
41617
+ return replacementStack[i];
41618
+ }
41619
+ }
41620
+ var canonicalizedObj;
41621
+ if ("[object Array]" === Object.prototype.toString.call(obj)) {
41622
+ stack.push(obj);
41623
+ canonicalizedObj = new Array(obj.length);
41624
+ replacementStack.push(canonicalizedObj);
41625
+ for (i = 0; i < obj.length; i += 1) {
41626
+ canonicalizedObj[i] = canonicalize(obj[i], stack, replacementStack, replacer, key);
41627
+ }
41628
+ stack.pop();
41629
+ replacementStack.pop();
41630
+ return canonicalizedObj;
41631
+ }
41632
+ if (obj && obj.toJSON) {
41633
+ obj = obj.toJSON();
41634
+ }
41635
+ if (_typeof(obj) === "object" && obj !== null) {
41636
+ stack.push(obj);
41637
+ canonicalizedObj = {};
41638
+ replacementStack.push(canonicalizedObj);
41639
+ var sortedKeys = [], _key;
41640
+ for (_key in obj) {
41641
+ if (Object.prototype.hasOwnProperty.call(obj, _key)) {
41642
+ sortedKeys.push(_key);
41643
+ }
41644
+ }
41645
+ sortedKeys.sort();
41646
+ for (i = 0; i < sortedKeys.length; i += 1) {
41647
+ _key = sortedKeys[i];
41648
+ canonicalizedObj[_key] = canonicalize(obj[_key], stack, replacementStack, replacer, _key);
41649
+ }
41650
+ stack.pop();
41651
+ replacementStack.pop();
41652
+ } else {
41653
+ canonicalizedObj = obj;
41654
+ }
41655
+ return canonicalizedObj;
41656
+ }
41657
+ var arrayDiff = new Diff();
41658
+ arrayDiff.tokenize = function(value) {
41659
+ return value.slice();
41660
+ };
41661
+ arrayDiff.join = arrayDiff.removeEmpty = function(value) {
41662
+ return value;
41663
+ };
41664
+
41665
+ // src/tools/claude.ts
41666
+ var CLAUDE_MODEL_IDS = ["opus", "fable", "sonnet", "haiku"];
41667
+ var CLAUDE_MODELS = [
41668
+ { id: "", label: "Default", description: "CLI default model", contextWindowSize: 1e6, default: true },
41669
+ { id: "opus", label: "Opus", description: "Most capable", contextWindowSize: 1e6 },
41670
+ { id: "fable", label: "Fable", contextWindowSize: 1e6 },
41671
+ { id: "sonnet", label: "Sonnet", description: "Fast, balanced", contextWindowSize: 1e6 },
41672
+ { id: "haiku", label: "Haiku", description: "Fastest, lightest", contextWindowSize: 1e6 }
41673
+ ];
41674
+ var _assertModelIdsAligned = CLAUDE_MODELS.filter(
41675
+ (m) => m.id !== ""
41676
+ ).map((m) => m.id);
41677
+ var CLAUDE_PERMISSION_MODES = [
41678
+ { id: "", label: "Default", description: "Ask for every tool call" },
41679
+ { id: "plan", label: "Plan", description: "Read-only, no code changes" },
41680
+ { id: "bypassPermissions", label: "YOLO", description: "Skip all permission checks" }
41681
+ ];
41682
+ var CLAUDE_CAPABILITIES = {
41683
+ tool: "claude",
41684
+ toolSessionIdLabel: "Claude Session ID",
41685
+ models: CLAUDE_MODELS,
41686
+ permissionModes: CLAUDE_PERMISSION_MODES,
41687
+ features: { rewind: true, subagents: true, tui: true, observe: true, fileSharing: true, fork: true },
41688
+ configSchema: [
41689
+ {
41690
+ name: "model",
41691
+ type: "select",
41692
+ label: "Model",
41693
+ scope: "core",
41694
+ options: CLAUDE_MODELS.map((m) => ({ value: m.id, label: m.label, description: m.description })),
41695
+ default: ""
41696
+ },
41697
+ {
41698
+ name: "permissionMode",
41699
+ type: "select",
41700
+ label: "Permission Mode",
41701
+ scope: "core",
41702
+ options: CLAUDE_PERMISSION_MODES.map((m) => ({ value: m.id, label: m.label, description: m.description })),
41703
+ default: ""
41704
+ },
41705
+ {
41706
+ name: "effort",
41707
+ type: "select",
41708
+ label: "Effort",
41709
+ description: "Reasoning effort level",
41710
+ scope: "tool-specific",
41711
+ // CC `--effort` 值域(claude --help, 2.1.187):low / medium / high / xhigh / max。
41712
+ // '' = 不传 --effort,用 CLI 默认。
41713
+ options: [
41714
+ { value: "", label: "Default" },
41715
+ { value: "low", label: "Low" },
41716
+ { value: "medium", label: "Medium" },
41717
+ { value: "high", label: "High" },
41718
+ { value: "xhigh", label: "Extra high" },
41719
+ { value: "max", label: "Max" }
41720
+ ],
41721
+ default: ""
41722
+ }
41723
+ ]
41724
+ };
41725
+
41726
+ // src/dispatch/mcp-server.ts
39523
41727
  var LONG_WAIT_AGENT_OPTIONS = {
39524
41728
  headersTimeout: 0,
39525
41729
  bodyTimeout: 0,
@@ -39534,7 +41738,7 @@ function log(msg, info) {
39534
41738
  `;
39535
41739
  if (DISPATCH_LOG) {
39536
41740
  try {
39537
- import_node_fs.default.appendFileSync(DISPATCH_LOG, line);
41741
+ import_node_fs3.default.appendFileSync(DISPATCH_LOG, line);
39538
41742
  return;
39539
41743
  } catch {
39540
41744
  }
@@ -39578,7 +41782,10 @@ async function handlePersonaDispatchToolCall(input, ctx) {
39578
41782
  targetPersona: input.targetPersona,
39579
41783
  prompt: input.prompt,
39580
41784
  // 跨设备:非空时透传,daemon run handler 据此走 A 角色转发分支。
39581
- ...input.targetDeviceId ? { targetDeviceId: input.targetDeviceId } : {}
41785
+ ...input.targetDeviceId ? { targetDeviceId: input.targetDeviceId } : {},
41786
+ // T-20: 可选 override B session 使用的 claude 模型;MCP tool 层已 enum 校验,
41787
+ // daemon handler 层还会再校验一次(fail-fast)。
41788
+ ...input.model ? { model: input.model } : {}
39582
41789
  })
39583
41790
  });
39584
41791
  } catch (err) {
@@ -39713,6 +41920,11 @@ async function main() {
39713
41920
  ),
39714
41921
  targetDeviceId: external_exports.string().optional().describe(
39715
41922
  "contact deviceId of the remote device when delegating cross-device (omit for a local persona)"
41923
+ ),
41924
+ // T-20: dispatch model override. Enum 走 MCP tool JSON schema 硬约束,
41925
+ // caller LLM 只能从可选值挑,避免瞎填历史模型名。
41926
+ model: external_exports.enum(CLAUDE_MODEL_IDS).optional().describe(
41927
+ "override the target persona's default claude model. Omit to use the persona default. Allowed: " + CLAUDE_MODEL_IDS.join(" / ") + "."
39716
41928
  )
39717
41929
  }
39718
41930
  },