@clawos-dev/clawd 0.2.104 → 0.2.105-beta.199.6386646

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.cjs +283 -312
  2. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -672,8 +672,8 @@ var init_parseUtil = __esm({
672
672
  init_errors2();
673
673
  init_en();
674
674
  makeIssue = (params) => {
675
- const { data, path: path58, errorMaps, issueData } = params;
676
- const fullPath = [...path58, ...issueData.path || []];
675
+ const { data, path: path59, errorMaps, issueData } = params;
676
+ const fullPath = [...path59, ...issueData.path || []];
677
677
  const fullIssue = {
678
678
  ...issueData,
679
679
  path: fullPath
@@ -984,11 +984,11 @@ var init_types = __esm({
984
984
  init_parseUtil();
985
985
  init_util();
986
986
  ParseInputLazyPath = class {
987
- constructor(parent, value, path58, key) {
987
+ constructor(parent, value, path59, key) {
988
988
  this._cachedPath = [];
989
989
  this.parent = parent;
990
990
  this.data = value;
991
- this._path = path58;
991
+ this._path = path59;
992
992
  this._key = key;
993
993
  }
994
994
  get path() {
@@ -5367,20 +5367,6 @@ var init_received_capability = __esm({
5367
5367
  });
5368
5368
 
5369
5369
  // ../protocol/src/extension.ts
5370
- function isAllowedHostedUrl(raw) {
5371
- let u;
5372
- try {
5373
- u = new URL(raw);
5374
- } catch {
5375
- return false;
5376
- }
5377
- if (u.protocol === "https:") return true;
5378
- if (u.protocol === "http:" && LOCALHOST_HOSTS.has(u.hostname)) return true;
5379
- return false;
5380
- }
5381
- function manifestMode(m2) {
5382
- return m2.entry?.url ? "hosted" : "local";
5383
- }
5384
5370
  function ownerNamespace(ownerPrincipalId) {
5385
5371
  let h = 2166136261;
5386
5372
  for (let i = 0; i < ownerPrincipalId.length; i++) {
@@ -5422,7 +5408,7 @@ function parseOrThrow(v2) {
5422
5408
  const [a, b2, c] = v2.split(".").map((p2) => parseInt(p2, 10));
5423
5409
  return [a, b2, c];
5424
5410
  }
5425
- var EXT_ID_REGEX, ExtensionStateSchema, LOCALHOST_HOSTS, ExtensionManifestSchema, ExtensionTargetSchema, ExtensionRecordSchema, PublishedSnapshotSchema, ChannelRefSchema, SourceRefSchema, PublishedExtensionRecordSchema, PublishCheckSchema, PublishStatusResultSchema;
5411
+ var EXT_ID_REGEX, ExtensionStateSchema, ExtensionManifestSchema, ExtensionRecordSchema, PublishedSnapshotSchema, ChannelRefSchema, SourceRefSchema, PublishedExtensionRecordSchema, PublishCheckSchema, PublishStatusResultSchema;
5426
5412
  var init_extension = __esm({
5427
5413
  "../protocol/src/extension.ts"() {
5428
5414
  "use strict";
@@ -5435,38 +5421,18 @@ var init_extension = __esm({
5435
5421
  "crashed",
5436
5422
  "invalid"
5437
5423
  ]);
5438
- LOCALHOST_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1"]);
5439
5424
  ExtensionManifestSchema = external_exports.object({
5440
5425
  id: external_exports.string().regex(EXT_ID_REGEX),
5441
5426
  name: external_exports.string().min(1),
5442
5427
  version: external_exports.string().min(1),
5443
5428
  apiVersion: external_exports.literal("1"),
5444
- runtime: external_exports.object({ startCommand: external_exports.string().min(1) }).passthrough().optional(),
5445
5429
  entry: external_exports.object({
5446
- url: external_exports.string().url().refine(isAllowedHostedUrl, {
5447
- message: "INVALID_URL_SCHEME: only https or http://localhost is allowed"
5448
- })
5449
- }).strict().optional()
5450
- }).passthrough().superRefine((m2, ctx) => {
5451
- const hasRuntime = !!m2.runtime;
5452
- const hasUrl = !!m2.entry?.url;
5453
- if (hasRuntime && hasUrl) {
5454
- ctx.addIssue({
5455
- code: external_exports.ZodIssueCode.custom,
5456
- message: "INVALID_MANIFEST: entry.url and runtime cannot coexist"
5457
- });
5458
- }
5459
- if (!hasRuntime && !hasUrl) {
5460
- ctx.addIssue({
5461
- code: external_exports.ZodIssueCode.custom,
5462
- message: "INVALID_MANIFEST: must have either entry.url or runtime"
5463
- });
5464
- }
5465
- });
5466
- ExtensionTargetSchema = external_exports.discriminatedUnion("kind", [
5467
- external_exports.object({ kind: external_exports.literal("local"), port: external_exports.number().int().min(1).max(65535) }),
5468
- external_exports.object({ kind: external_exports.literal("hosted"), url: external_exports.string().url() })
5469
- ]);
5430
+ ui: external_exports.string().min(1).optional()
5431
+ }).strict().optional(),
5432
+ runtime: external_exports.object({
5433
+ startCommand: external_exports.string().min(1)
5434
+ }).passthrough()
5435
+ }).passthrough();
5470
5436
  ExtensionRecordSchema = external_exports.discriminatedUnion("state", [
5471
5437
  external_exports.object({
5472
5438
  extId: external_exports.string(),
@@ -5482,7 +5448,7 @@ var init_extension = __esm({
5482
5448
  extId: external_exports.string(),
5483
5449
  manifest: ExtensionManifestSchema,
5484
5450
  state: external_exports.literal("running"),
5485
- target: ExtensionTargetSchema
5451
+ port: external_exports.number().int().min(1).max(65535)
5486
5452
  }),
5487
5453
  external_exports.object({
5488
5454
  extId: external_exports.string(),
@@ -5856,8 +5822,8 @@ var require_req = __commonJS({
5856
5822
  if (req.originalUrl) {
5857
5823
  _req.url = req.originalUrl;
5858
5824
  } else {
5859
- const path58 = req.path;
5860
- _req.url = typeof path58 === "string" ? path58 : req.url ? req.url.path || req.url : void 0;
5825
+ const path59 = req.path;
5826
+ _req.url = typeof path59 === "string" ? path59 : req.url ? req.url.path || req.url : void 0;
5861
5827
  }
5862
5828
  if (req.query) {
5863
5829
  _req.query = req.query;
@@ -6022,14 +5988,14 @@ var require_redact = __commonJS({
6022
5988
  }
6023
5989
  return obj;
6024
5990
  }
6025
- function parsePath(path58) {
5991
+ function parsePath(path59) {
6026
5992
  const parts = [];
6027
5993
  let current = "";
6028
5994
  let inBrackets = false;
6029
5995
  let inQuotes = false;
6030
5996
  let quoteChar = "";
6031
- for (let i = 0; i < path58.length; i++) {
6032
- const char = path58[i];
5997
+ for (let i = 0; i < path59.length; i++) {
5998
+ const char = path59[i];
6033
5999
  if (!inBrackets && char === ".") {
6034
6000
  if (current) {
6035
6001
  parts.push(current);
@@ -6160,10 +6126,10 @@ var require_redact = __commonJS({
6160
6126
  return current;
6161
6127
  }
6162
6128
  function redactPaths(obj, paths, censor, remove = false) {
6163
- for (const path58 of paths) {
6164
- const parts = parsePath(path58);
6129
+ for (const path59 of paths) {
6130
+ const parts = parsePath(path59);
6165
6131
  if (parts.includes("*")) {
6166
- redactWildcardPath(obj, parts, censor, path58, remove);
6132
+ redactWildcardPath(obj, parts, censor, path59, remove);
6167
6133
  } else {
6168
6134
  if (remove) {
6169
6135
  removeKey(obj, parts);
@@ -6248,8 +6214,8 @@ var require_redact = __commonJS({
6248
6214
  }
6249
6215
  } else {
6250
6216
  if (afterWildcard.includes("*")) {
6251
- const wrappedCensor = typeof censor === "function" ? (value, path58) => {
6252
- const fullPath = [...pathArray.slice(0, pathLength), ...path58];
6217
+ const wrappedCensor = typeof censor === "function" ? (value, path59) => {
6218
+ const fullPath = [...pathArray.slice(0, pathLength), ...path59];
6253
6219
  return censor(value, fullPath);
6254
6220
  } : censor;
6255
6221
  redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
@@ -6284,8 +6250,8 @@ var require_redact = __commonJS({
6284
6250
  return null;
6285
6251
  }
6286
6252
  const pathStructure = /* @__PURE__ */ new Map();
6287
- for (const path58 of pathsToClone) {
6288
- const parts = parsePath(path58);
6253
+ for (const path59 of pathsToClone) {
6254
+ const parts = parsePath(path59);
6289
6255
  let current = pathStructure;
6290
6256
  for (let i = 0; i < parts.length; i++) {
6291
6257
  const part = parts[i];
@@ -6337,24 +6303,24 @@ var require_redact = __commonJS({
6337
6303
  }
6338
6304
  return cloneSelectively(obj, pathStructure);
6339
6305
  }
6340
- function validatePath(path58) {
6341
- if (typeof path58 !== "string") {
6306
+ function validatePath(path59) {
6307
+ if (typeof path59 !== "string") {
6342
6308
  throw new Error("Paths must be (non-empty) strings");
6343
6309
  }
6344
- if (path58 === "") {
6310
+ if (path59 === "") {
6345
6311
  throw new Error("Invalid redaction path ()");
6346
6312
  }
6347
- if (path58.includes("..")) {
6348
- throw new Error(`Invalid redaction path (${path58})`);
6313
+ if (path59.includes("..")) {
6314
+ throw new Error(`Invalid redaction path (${path59})`);
6349
6315
  }
6350
- if (path58.includes(",")) {
6351
- throw new Error(`Invalid redaction path (${path58})`);
6316
+ if (path59.includes(",")) {
6317
+ throw new Error(`Invalid redaction path (${path59})`);
6352
6318
  }
6353
6319
  let bracketCount = 0;
6354
6320
  let inQuotes = false;
6355
6321
  let quoteChar = "";
6356
- for (let i = 0; i < path58.length; i++) {
6357
- const char = path58[i];
6322
+ for (let i = 0; i < path59.length; i++) {
6323
+ const char = path59[i];
6358
6324
  if ((char === '"' || char === "'") && bracketCount > 0) {
6359
6325
  if (!inQuotes) {
6360
6326
  inQuotes = true;
@@ -6368,20 +6334,20 @@ var require_redact = __commonJS({
6368
6334
  } else if (char === "]" && !inQuotes) {
6369
6335
  bracketCount--;
6370
6336
  if (bracketCount < 0) {
6371
- throw new Error(`Invalid redaction path (${path58})`);
6337
+ throw new Error(`Invalid redaction path (${path59})`);
6372
6338
  }
6373
6339
  }
6374
6340
  }
6375
6341
  if (bracketCount !== 0) {
6376
- throw new Error(`Invalid redaction path (${path58})`);
6342
+ throw new Error(`Invalid redaction path (${path59})`);
6377
6343
  }
6378
6344
  }
6379
6345
  function validatePaths(paths) {
6380
6346
  if (!Array.isArray(paths)) {
6381
6347
  throw new TypeError("paths must be an array");
6382
6348
  }
6383
- for (const path58 of paths) {
6384
- validatePath(path58);
6349
+ for (const path59 of paths) {
6350
+ validatePath(path59);
6385
6351
  }
6386
6352
  }
6387
6353
  function slowRedact(options = {}) {
@@ -6549,8 +6515,8 @@ var require_redaction = __commonJS({
6549
6515
  if (shape[k2] === null) {
6550
6516
  o[k2] = (value) => topCensor(value, [k2]);
6551
6517
  } else {
6552
- const wrappedCensor = typeof censor === "function" ? (value, path58) => {
6553
- return censor(value, [k2, ...path58]);
6518
+ const wrappedCensor = typeof censor === "function" ? (value, path59) => {
6519
+ return censor(value, [k2, ...path59]);
6554
6520
  } : censor;
6555
6521
  o[k2] = Redact({
6556
6522
  paths: shape[k2],
@@ -6768,10 +6734,10 @@ var require_atomic_sleep = __commonJS({
6768
6734
  var require_sonic_boom = __commonJS({
6769
6735
  "../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
6770
6736
  "use strict";
6771
- var fs46 = require("fs");
6737
+ var fs47 = require("fs");
6772
6738
  var EventEmitter2 = require("events");
6773
6739
  var inherits = require("util").inherits;
6774
- var path58 = require("path");
6740
+ var path59 = require("path");
6775
6741
  var sleep = require_atomic_sleep();
6776
6742
  var assert = require("assert");
6777
6743
  var BUSY_WRITE_TIMEOUT = 100;
@@ -6825,20 +6791,20 @@ var require_sonic_boom = __commonJS({
6825
6791
  const mode = sonic.mode;
6826
6792
  if (sonic.sync) {
6827
6793
  try {
6828
- if (sonic.mkdir) fs46.mkdirSync(path58.dirname(file), { recursive: true });
6829
- const fd = fs46.openSync(file, flags, mode);
6794
+ if (sonic.mkdir) fs47.mkdirSync(path59.dirname(file), { recursive: true });
6795
+ const fd = fs47.openSync(file, flags, mode);
6830
6796
  fileOpened(null, fd);
6831
6797
  } catch (err) {
6832
6798
  fileOpened(err);
6833
6799
  throw err;
6834
6800
  }
6835
6801
  } else if (sonic.mkdir) {
6836
- fs46.mkdir(path58.dirname(file), { recursive: true }, (err) => {
6802
+ fs47.mkdir(path59.dirname(file), { recursive: true }, (err) => {
6837
6803
  if (err) return fileOpened(err);
6838
- fs46.open(file, flags, mode, fileOpened);
6804
+ fs47.open(file, flags, mode, fileOpened);
6839
6805
  });
6840
6806
  } else {
6841
- fs46.open(file, flags, mode, fileOpened);
6807
+ fs47.open(file, flags, mode, fileOpened);
6842
6808
  }
6843
6809
  }
6844
6810
  function SonicBoom(opts) {
@@ -6879,8 +6845,8 @@ var require_sonic_boom = __commonJS({
6879
6845
  this.flush = flushBuffer;
6880
6846
  this.flushSync = flushBufferSync;
6881
6847
  this._actualWrite = actualWriteBuffer;
6882
- fsWriteSync = () => fs46.writeSync(this.fd, this._writingBuf);
6883
- fsWrite = () => fs46.write(this.fd, this._writingBuf, this.release);
6848
+ fsWriteSync = () => fs47.writeSync(this.fd, this._writingBuf);
6849
+ fsWrite = () => fs47.write(this.fd, this._writingBuf, this.release);
6884
6850
  } else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
6885
6851
  this._writingBuf = "";
6886
6852
  this.write = write;
@@ -6889,15 +6855,15 @@ var require_sonic_boom = __commonJS({
6889
6855
  this._actualWrite = actualWrite;
6890
6856
  fsWriteSync = () => {
6891
6857
  if (Buffer.isBuffer(this._writingBuf)) {
6892
- return fs46.writeSync(this.fd, this._writingBuf);
6858
+ return fs47.writeSync(this.fd, this._writingBuf);
6893
6859
  }
6894
- return fs46.writeSync(this.fd, this._writingBuf, "utf8");
6860
+ return fs47.writeSync(this.fd, this._writingBuf, "utf8");
6895
6861
  };
6896
6862
  fsWrite = () => {
6897
6863
  if (Buffer.isBuffer(this._writingBuf)) {
6898
- return fs46.write(this.fd, this._writingBuf, this.release);
6864
+ return fs47.write(this.fd, this._writingBuf, this.release);
6899
6865
  }
6900
- return fs46.write(this.fd, this._writingBuf, "utf8", this.release);
6866
+ return fs47.write(this.fd, this._writingBuf, "utf8", this.release);
6901
6867
  };
6902
6868
  } else {
6903
6869
  throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
@@ -6954,7 +6920,7 @@ var require_sonic_boom = __commonJS({
6954
6920
  }
6955
6921
  }
6956
6922
  if (this._fsync) {
6957
- fs46.fsyncSync(this.fd);
6923
+ fs47.fsyncSync(this.fd);
6958
6924
  }
6959
6925
  const len = this._len;
6960
6926
  if (this._reopening) {
@@ -7068,7 +7034,7 @@ var require_sonic_boom = __commonJS({
7068
7034
  const onDrain = () => {
7069
7035
  if (!this._fsync) {
7070
7036
  try {
7071
- fs46.fsync(this.fd, (err) => {
7037
+ fs47.fsync(this.fd, (err) => {
7072
7038
  this._flushPending = false;
7073
7039
  cb(err);
7074
7040
  });
@@ -7170,7 +7136,7 @@ var require_sonic_boom = __commonJS({
7170
7136
  const fd = this.fd;
7171
7137
  this.once("ready", () => {
7172
7138
  if (fd !== this.fd) {
7173
- fs46.close(fd, (err) => {
7139
+ fs47.close(fd, (err) => {
7174
7140
  if (err) {
7175
7141
  return this.emit("error", err);
7176
7142
  }
@@ -7219,7 +7185,7 @@ var require_sonic_boom = __commonJS({
7219
7185
  buf = this._bufs[0];
7220
7186
  }
7221
7187
  try {
7222
- const n = Buffer.isBuffer(buf) ? fs46.writeSync(this.fd, buf) : fs46.writeSync(this.fd, buf, "utf8");
7188
+ const n = Buffer.isBuffer(buf) ? fs47.writeSync(this.fd, buf) : fs47.writeSync(this.fd, buf, "utf8");
7223
7189
  const releasedBufObj = releaseWritingBuf(buf, this._len, n);
7224
7190
  buf = releasedBufObj.writingBuf;
7225
7191
  this._len = releasedBufObj.len;
@@ -7235,7 +7201,7 @@ var require_sonic_boom = __commonJS({
7235
7201
  }
7236
7202
  }
7237
7203
  try {
7238
- fs46.fsyncSync(this.fd);
7204
+ fs47.fsyncSync(this.fd);
7239
7205
  } catch {
7240
7206
  }
7241
7207
  }
@@ -7256,7 +7222,7 @@ var require_sonic_boom = __commonJS({
7256
7222
  buf = mergeBuf(this._bufs[0], this._lens[0]);
7257
7223
  }
7258
7224
  try {
7259
- const n = fs46.writeSync(this.fd, buf);
7225
+ const n = fs47.writeSync(this.fd, buf);
7260
7226
  buf = buf.subarray(n);
7261
7227
  this._len = Math.max(this._len - n, 0);
7262
7228
  if (buf.length <= 0) {
@@ -7284,13 +7250,13 @@ var require_sonic_boom = __commonJS({
7284
7250
  this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
7285
7251
  if (this.sync) {
7286
7252
  try {
7287
- const written = Buffer.isBuffer(this._writingBuf) ? fs46.writeSync(this.fd, this._writingBuf) : fs46.writeSync(this.fd, this._writingBuf, "utf8");
7253
+ const written = Buffer.isBuffer(this._writingBuf) ? fs47.writeSync(this.fd, this._writingBuf) : fs47.writeSync(this.fd, this._writingBuf, "utf8");
7288
7254
  release(null, written);
7289
7255
  } catch (err) {
7290
7256
  release(err);
7291
7257
  }
7292
7258
  } else {
7293
- fs46.write(this.fd, this._writingBuf, release);
7259
+ fs47.write(this.fd, this._writingBuf, release);
7294
7260
  }
7295
7261
  }
7296
7262
  function actualWriteBuffer() {
@@ -7299,7 +7265,7 @@ var require_sonic_boom = __commonJS({
7299
7265
  this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
7300
7266
  if (this.sync) {
7301
7267
  try {
7302
- const written = fs46.writeSync(this.fd, this._writingBuf);
7268
+ const written = fs47.writeSync(this.fd, this._writingBuf);
7303
7269
  release(null, written);
7304
7270
  } catch (err) {
7305
7271
  release(err);
@@ -7308,7 +7274,7 @@ var require_sonic_boom = __commonJS({
7308
7274
  if (kCopyBuffer) {
7309
7275
  this._writingBuf = Buffer.from(this._writingBuf);
7310
7276
  }
7311
- fs46.write(this.fd, this._writingBuf, release);
7277
+ fs47.write(this.fd, this._writingBuf, release);
7312
7278
  }
7313
7279
  }
7314
7280
  function actualClose(sonic) {
@@ -7324,12 +7290,12 @@ var require_sonic_boom = __commonJS({
7324
7290
  sonic._lens = [];
7325
7291
  assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
7326
7292
  try {
7327
- fs46.fsync(sonic.fd, closeWrapped);
7293
+ fs47.fsync(sonic.fd, closeWrapped);
7328
7294
  } catch {
7329
7295
  }
7330
7296
  function closeWrapped() {
7331
7297
  if (sonic.fd !== 1 && sonic.fd !== 2) {
7332
- fs46.close(sonic.fd, done);
7298
+ fs47.close(sonic.fd, done);
7333
7299
  } else {
7334
7300
  done();
7335
7301
  }
@@ -10464,11 +10430,11 @@ var init_lib = __esm({
10464
10430
  }
10465
10431
  }
10466
10432
  },
10467
- addToPath: function addToPath(path58, added, removed, oldPosInc, options) {
10468
- var last = path58.lastComponent;
10433
+ addToPath: function addToPath(path59, added, removed, oldPosInc, options) {
10434
+ var last = path59.lastComponent;
10469
10435
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
10470
10436
  return {
10471
- oldPos: path58.oldPos + oldPosInc,
10437
+ oldPos: path59.oldPos + oldPosInc,
10472
10438
  lastComponent: {
10473
10439
  count: last.count + 1,
10474
10440
  added,
@@ -10478,7 +10444,7 @@ var init_lib = __esm({
10478
10444
  };
10479
10445
  } else {
10480
10446
  return {
10481
- oldPos: path58.oldPos + oldPosInc,
10447
+ oldPos: path59.oldPos + oldPosInc,
10482
10448
  lastComponent: {
10483
10449
  count: 1,
10484
10450
  added,
@@ -10924,10 +10890,10 @@ function attachmentToHistoryMessage(o, ts) {
10924
10890
  const memories = raw.map((m2) => {
10925
10891
  if (!m2 || typeof m2 !== "object") return null;
10926
10892
  const rec = m2;
10927
- const path58 = typeof rec.path === "string" ? rec.path : null;
10893
+ const path59 = typeof rec.path === "string" ? rec.path : null;
10928
10894
  const content = typeof rec.content === "string" ? rec.content : null;
10929
- if (!path58 || content == null) return null;
10930
- const entry = { path: path58, content };
10895
+ if (!path59 || content == null) return null;
10896
+ const entry = { path: path59, content };
10931
10897
  if (typeof rec.mtimeMs === "number") entry.mtimeMs = rec.mtimeMs;
10932
10898
  return entry;
10933
10899
  }).filter((m2) => m2 !== null);
@@ -11758,10 +11724,10 @@ function parseAttachment(obj) {
11758
11724
  const memories = raw.map((m2) => {
11759
11725
  if (!m2 || typeof m2 !== "object") return null;
11760
11726
  const rec = m2;
11761
- const path58 = typeof rec.path === "string" ? rec.path : null;
11727
+ const path59 = typeof rec.path === "string" ? rec.path : null;
11762
11728
  const content = typeof rec.content === "string" ? rec.content : null;
11763
- if (!path58 || content == null) return null;
11764
- const out = { path: path58, content };
11729
+ if (!path59 || content == null) return null;
11730
+ const out = { path: path59, content };
11765
11731
  if (typeof rec.mtimeMs === "number") out.mtimeMs = rec.mtimeMs;
11766
11732
  return out;
11767
11733
  }).filter((m2) => m2 !== null);
@@ -23550,8 +23516,8 @@ var require_utils = __commonJS({
23550
23516
  var result = transform[inputType][outputType](input);
23551
23517
  return result;
23552
23518
  };
23553
- exports2.resolve = function(path58) {
23554
- var parts = path58.split("/");
23519
+ exports2.resolve = function(path59) {
23520
+ var parts = path59.split("/");
23555
23521
  var result = [];
23556
23522
  for (var index = 0; index < parts.length; index++) {
23557
23523
  var part = parts[index];
@@ -29404,18 +29370,18 @@ var require_object = __commonJS({
29404
29370
  var object = new ZipObject(name, zipObjectContent, o);
29405
29371
  this.files[name] = object;
29406
29372
  };
29407
- var parentFolder = function(path58) {
29408
- if (path58.slice(-1) === "/") {
29409
- path58 = path58.substring(0, path58.length - 1);
29373
+ var parentFolder = function(path59) {
29374
+ if (path59.slice(-1) === "/") {
29375
+ path59 = path59.substring(0, path59.length - 1);
29410
29376
  }
29411
- var lastSlash = path58.lastIndexOf("/");
29412
- return lastSlash > 0 ? path58.substring(0, lastSlash) : "";
29377
+ var lastSlash = path59.lastIndexOf("/");
29378
+ return lastSlash > 0 ? path59.substring(0, lastSlash) : "";
29413
29379
  };
29414
- var forceTrailingSlash = function(path58) {
29415
- if (path58.slice(-1) !== "/") {
29416
- path58 += "/";
29380
+ var forceTrailingSlash = function(path59) {
29381
+ if (path59.slice(-1) !== "/") {
29382
+ path59 += "/";
29417
29383
  }
29418
- return path58;
29384
+ return path59;
29419
29385
  };
29420
29386
  var folderAdd = function(name, createFolders) {
29421
29387
  createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
@@ -30417,7 +30383,7 @@ var require_lib3 = __commonJS({
30417
30383
  // src/run-case/recorder.ts
30418
30384
  function startRunCaseRecorder(opts) {
30419
30385
  const now = opts.now ?? Date.now;
30420
- const dir = import_node_path44.default.dirname(opts.recordPath);
30386
+ const dir = import_node_path45.default.dirname(opts.recordPath);
30421
30387
  let stream = null;
30422
30388
  let closing = false;
30423
30389
  let closedSettled = false;
@@ -30457,12 +30423,12 @@ function startRunCaseRecorder(opts) {
30457
30423
  };
30458
30424
  return { tap, close, closed };
30459
30425
  }
30460
- var import_node_fs30, import_node_path44;
30426
+ var import_node_fs30, import_node_path45;
30461
30427
  var init_recorder = __esm({
30462
30428
  "src/run-case/recorder.ts"() {
30463
30429
  "use strict";
30464
30430
  import_node_fs30 = __toESM(require("fs"), 1);
30465
- import_node_path44 = __toESM(require("path"), 1);
30431
+ import_node_path45 = __toESM(require("path"), 1);
30466
30432
  }
30467
30433
  });
30468
30434
 
@@ -30505,7 +30471,7 @@ var init_wire = __esm({
30505
30471
  // src/run-case/controller.ts
30506
30472
  async function runController(opts) {
30507
30473
  const now = opts.now ?? Date.now;
30508
- const cwd = opts.cwd ?? (0, import_node_fs31.mkdtempSync)(import_node_path45.default.join(import_node_os19.default.tmpdir(), "clawd-runcase-"));
30474
+ const cwd = opts.cwd ?? (0, import_node_fs31.mkdtempSync)(import_node_path46.default.join(import_node_os19.default.tmpdir(), "clawd-runcase-"));
30509
30475
  const ownsCwd = opts.cwd === void 0;
30510
30476
  const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
30511
30477
  const spawnCtx = { cwd };
@@ -30672,13 +30638,13 @@ async function runController(opts) {
30672
30638
  }
30673
30639
  return exitCode ?? 0;
30674
30640
  }
30675
- var import_node_fs31, import_node_os19, import_node_path45;
30641
+ var import_node_fs31, import_node_os19, import_node_path46;
30676
30642
  var init_controller = __esm({
30677
30643
  "src/run-case/controller.ts"() {
30678
30644
  "use strict";
30679
30645
  import_node_fs31 = require("fs");
30680
30646
  import_node_os19 = __toESM(require("os"), 1);
30681
- import_node_path45 = __toESM(require("path"), 1);
30647
+ import_node_path46 = __toESM(require("path"), 1);
30682
30648
  init_claude();
30683
30649
  init_stdout_splitter();
30684
30650
  init_permission_stdio();
@@ -30910,7 +30876,7 @@ Env (advanced):
30910
30876
  `;
30911
30877
 
30912
30878
  // src/index.ts
30913
- var import_node_path43 = __toESM(require("path"), 1);
30879
+ var import_node_path44 = __toESM(require("path"), 1);
30914
30880
  var import_node_fs29 = __toESM(require("fs"), 1);
30915
30881
 
30916
30882
  // src/logger.ts
@@ -32580,12 +32546,11 @@ var SessionManager = class {
32580
32546
  // 新 client 通过 session:subscribe 接入时由 onSubscribe hook 取 getPtyReplay(sessionId)
32581
32547
  // 把屏幕快照定向 emit,解决"刷新页面 / 第二个 tab 接入时 xterm 白屏"
32582
32548
  ptyReplaysByToolSid = /* @__PURE__ */ new Map();
32583
- // TUI 模式:toolSessionId → @xterm/headless TerminalSurface(单一虚拟终端,popup / ready
32584
- // observer 都从这一份 buffer 派生状态)。ClaudeTuiAdapter spawn 时通过 onSurfaceRegister
32585
- // callback 写入;exit onSurfaceUnregister 清理。
32586
- // manager.resizePty 用此映射把 UI 的 session:pty:resize 同步到 surface 内部 buffer,
32549
+ // TUI 模式:toolSessionId → @xterm/headless PopupDetector。
32550
+ // ClaudeTuiAdapter spawn 时通过 onDetectorRegister callback 写入;exit 时 onDetectorUnregister 清理。
32551
+ // manager.resizePty 用此映射把 UI session:pty:resize 同步到 detector 内部 buffer,
32587
32552
  // 保证 snapshot serialize 时 cursor positioning 与 UI xterm 实际尺寸一致。
32588
- surfacesByToolSid = /* @__PURE__ */ new Map();
32553
+ detectorsByToolSid = /* @__PURE__ */ new Map();
32589
32554
  // 仅 mode='tui' 需要:index.ts 装配阶段在 observer 构造后注入。
32590
32555
  // observer.onEvent 要回灌 manager.feedObserverEvents,所以 observer 必须晚于 manager
32591
32556
  // 构造;反过来 manager 又要在 mode='tui' 下 spawn session 时 attach observer。setter 解循环
@@ -33859,18 +33824,18 @@ var SessionManager = class {
33859
33824
  if (!tsid) return void 0;
33860
33825
  return this.ptyTransports.get(tsid);
33861
33826
  }
33862
- /** ClaudeTuiAdapter spawn 时注册 surface ref;同一 tsid 重 spawn 会覆盖 */
33863
- registerSurface(toolSessionId, surface) {
33864
- this.surfacesByToolSid.set(toolSessionId, surface);
33827
+ /** ClaudeTuiAdapter spawn 时注册 detector ref;同一 tsid 重 spawn 会覆盖 */
33828
+ registerDetector(toolSessionId, detector) {
33829
+ this.detectorsByToolSid.set(toolSessionId, detector);
33865
33830
  }
33866
33831
  /** spawn 进程 exit 时清理 */
33867
- unregisterSurface(toolSessionId) {
33868
- this.surfacesByToolSid.delete(toolSessionId);
33832
+ unregisterDetector(toolSessionId) {
33833
+ this.detectorsByToolSid.delete(toolSessionId);
33869
33834
  }
33870
33835
  /**
33871
- * 同时 resize pty 子进程和 surface buffer:UI session:pty:resize 入口走这个。
33872
- * 顺序:pty.resize 在前,surface.resize 在后 —— pty 是真正的 CC 子进程视图,必须先成功;
33873
- * surface 只是 daemon 端镜像,任一步失败都返 false。
33836
+ * 同时 resize pty 子进程和 detector buffer:UI session:pty:resize 入口走这个。
33837
+ * 顺序:pty.resize 在前,detector.resize 在后 —— pty 是真正的 CC 子进程视图,必须先成功;
33838
+ * detector 只是 daemon 端镜像,任一步失败都返 false。
33874
33839
  * 找不到 runner / toolSessionId / pty 任一缺失 → 返 false,handler 静默给 UI 报 ok=false 不抛错。
33875
33840
  */
33876
33841
  resizePty(sessionId, cols, rows) {
@@ -33885,8 +33850,8 @@ var SessionManager = class {
33885
33850
  } catch {
33886
33851
  return false;
33887
33852
  }
33888
- const surface = this.surfacesByToolSid.get(tsid);
33889
- if (surface) surface.resize(cols, rows);
33853
+ const detector = this.detectorsByToolSid.get(tsid);
33854
+ if (detector) detector.resize(cols, rows);
33890
33855
  return true;
33891
33856
  }
33892
33857
  /**
@@ -35184,30 +35149,59 @@ var POPUP_FOOTER_PATTERNS = [
35184
35149
  { kind: "permission", regex: /Tab to amend|Do you want to proceed/i },
35185
35150
  { kind: "question", regex: /Enter to select|↑\/↓ to navigate/i }
35186
35151
  ];
35187
- function createTerminalSurface(opts) {
35152
+ function createPopupDetector(opts) {
35188
35153
  const term = new Terminal({
35189
- cols: opts?.cols ?? 120,
35190
- rows: opts?.rows ?? 40,
35191
- scrollback: opts?.scrollback ?? 1e3,
35154
+ cols: opts.cols ?? 120,
35155
+ rows: opts.rows ?? 40,
35156
+ scrollback: 1e3,
35192
35157
  allowProposedApi: true
35193
35158
  });
35194
35159
  const serializeAddon = new D();
35195
35160
  term.loadAddon(serializeAddon);
35161
+ let visible = null;
35162
+ let pendingClear = null;
35196
35163
  let parseSeq = 0;
35197
35164
  let pendingParse = 0;
35198
35165
  let drainWaiters = [];
35199
35166
  let disposed = false;
35200
- const observers = [];
35201
- const collectLines = () => {
35167
+ const scanFooter = () => {
35202
35168
  const buf = term.buffer.active;
35203
- const lines = new Array(buf.length);
35204
35169
  for (let i = 0; i < buf.length; i++) {
35205
35170
  const line = buf.getLine(i);
35206
- lines[i] = line ? line.translateToString(true) : "";
35171
+ if (!line) continue;
35172
+ const text = line.translateToString(true);
35173
+ if (!text) continue;
35174
+ for (const p2 of POPUP_FOOTER_PATTERNS) {
35175
+ if (p2.regex.test(text)) return p2.kind;
35176
+ }
35177
+ }
35178
+ return null;
35179
+ };
35180
+ const tick = () => {
35181
+ const matched = scanFooter();
35182
+ if (matched && visible === null) {
35183
+ visible = matched;
35184
+ opts.onTransition(matched, true);
35185
+ } else if (matched && visible !== null) {
35186
+ if (pendingClear) {
35187
+ clearTimeout(pendingClear);
35188
+ pendingClear = null;
35189
+ }
35190
+ } else if (!matched && visible !== null && !pendingClear) {
35191
+ const toClear = visible;
35192
+ pendingClear = setTimeout(() => {
35193
+ pendingClear = null;
35194
+ if (visible === toClear) {
35195
+ visible = null;
35196
+ opts.onTransition(toClear, false);
35197
+ }
35198
+ }, opts.clearQuietMs);
35207
35199
  }
35208
- return lines;
35209
35200
  };
35210
35201
  return {
35202
+ get visibleKind() {
35203
+ return visible;
35204
+ },
35211
35205
  get parseSeq() {
35212
35206
  return parseSeq;
35213
35207
  },
@@ -35221,10 +35215,7 @@ function createTerminalSurface(opts) {
35221
35215
  }
35222
35216
  if (typeof seq === "number" && seq > parseSeq) parseSeq = seq;
35223
35217
  pendingParse--;
35224
- if (observers.length > 0) {
35225
- const lines = collectLines();
35226
- for (const cb of [...observers]) cb(lines);
35227
- }
35218
+ tick();
35228
35219
  if (pendingParse === 0 && drainWaiters.length > 0) {
35229
35220
  const waiters = drainWaiters;
35230
35221
  drainWaiters = [];
@@ -35246,93 +35237,42 @@ function createTerminalSurface(opts) {
35246
35237
  } catch {
35247
35238
  }
35248
35239
  },
35249
- serialize() {
35250
- return serializeAddon.serialize({ scrollback: 1e3 });
35251
- },
35252
35240
  dispose() {
35253
35241
  disposed = true;
35254
- pendingParse = 0;
35242
+ if (pendingClear) {
35243
+ clearTimeout(pendingClear);
35244
+ pendingClear = null;
35245
+ }
35255
35246
  const waiters = drainWaiters;
35256
35247
  drainWaiters = [];
35257
35248
  for (const w2 of waiters) w2();
35258
- observers.length = 0;
35259
35249
  serializeAddon.dispose();
35260
35250
  term.dispose();
35261
35251
  },
35262
- onTick(cb) {
35263
- observers.push(cb);
35264
- return () => {
35265
- const i = observers.indexOf(cb);
35266
- if (i >= 0) observers.splice(i, 1);
35267
- };
35252
+ serialize() {
35253
+ return serializeAddon.serialize({ scrollback: 1e3 });
35268
35254
  }
35269
35255
  };
35270
35256
  }
35271
- function observePopup(surface, opts) {
35272
- let visible = null;
35273
- let pendingClear = null;
35274
- const scanFooter = (lines) => {
35275
- for (const text of lines) {
35276
- if (!text) continue;
35277
- for (const p2 of POPUP_FOOTER_PATTERNS) {
35278
- if (p2.regex.test(text)) return p2.kind;
35279
- }
35280
- }
35281
- return null;
35282
- };
35283
- const unsubscribe = surface.onTick((lines) => {
35284
- const matched = scanFooter(lines);
35285
- const inputFrameVisible = opts.getInputFrameVisible();
35286
- if (visible === null) {
35287
- if (matched && !inputFrameVisible) {
35288
- visible = matched;
35289
- opts.onTransition(matched, true);
35290
- }
35291
- return;
35292
- }
35293
- if (!inputFrameVisible) {
35294
- if (pendingClear) {
35295
- clearTimeout(pendingClear);
35296
- pendingClear = null;
35297
- }
35298
- return;
35299
- }
35300
- if (!pendingClear) {
35301
- const toClear = visible;
35302
- pendingClear = setTimeout(() => {
35303
- pendingClear = null;
35304
- if (visible === toClear) {
35305
- visible = null;
35306
- opts.onTransition(toClear, false);
35307
- }
35308
- }, opts.clearQuietMs);
35309
- }
35257
+ function createReadyDetector(opts) {
35258
+ const term = new Terminal({
35259
+ cols: opts.cols ?? 120,
35260
+ rows: opts.rows ?? 40,
35261
+ scrollback: 200,
35262
+ allowProposedApi: true
35310
35263
  });
35311
- return {
35312
- get visibleKind() {
35313
- return visible;
35314
- },
35315
- dispose() {
35316
- unsubscribe();
35317
- if (pendingClear) {
35318
- clearTimeout(pendingClear);
35319
- pendingClear = null;
35320
- }
35321
- }
35322
- };
35323
- }
35324
- function observeReady(surface, opts) {
35325
- let prevReady = false;
35326
35264
  let quietTimer = null;
35327
- let unsubscribed = false;
35328
- let latestLines = [];
35329
- const scanReadyFrame = (lines) => {
35265
+ let disposed = false;
35266
+ const scanReadyFrame = () => {
35267
+ const buf = term.buffer.active;
35330
35268
  let prevHasDivider = false;
35331
- for (const text of lines) {
35332
- if (!text) {
35269
+ for (let i = 0; i < buf.length; i++) {
35270
+ const line = buf.getLine(i);
35271
+ if (!line) {
35333
35272
  prevHasDivider = false;
35334
35273
  continue;
35335
35274
  }
35275
+ const text = line.translateToString(true);
35336
35276
  const hasPrompt = /^❯/.test(text);
35337
35277
  const hasDivider = /─{20,}/.test(text);
35338
35278
  if (hasPrompt && prevHasDivider) return true;
@@ -35355,18 +35295,18 @@ function observeReady(surface, opts) {
35355
35295
  };
35356
35296
  const quietFire = () => {
35357
35297
  quietTimer = null;
35358
- if (unsubscribed) return;
35359
- if (!scanReadyFrame(latestLines)) {
35298
+ if (disposed) return;
35299
+ if (!scanReadyFrame()) {
35360
35300
  dbg({ event: "quiet-fire-but-not-ready-anymore" });
35361
35301
  return;
35362
35302
  }
35363
35303
  dbg({ event: "quiet-fire \u2192 onReady" });
35364
35304
  opts.onReady();
35365
35305
  };
35366
- const unsubscribe = surface.onTick((lines) => {
35367
- if (unsubscribed) return;
35368
- latestLines = lines;
35369
- const ready = scanReadyFrame(lines);
35306
+ let prevReady = false;
35307
+ const tick = () => {
35308
+ if (disposed) return;
35309
+ const ready = scanReadyFrame();
35370
35310
  if (!ready) {
35371
35311
  clearQuiet();
35372
35312
  if (prevReady) {
@@ -35381,15 +35321,19 @@ function observeReady(surface, opts) {
35381
35321
  }
35382
35322
  clearQuiet();
35383
35323
  quietTimer = setTimeout(quietFire, opts.quietMs);
35384
- });
35324
+ };
35385
35325
  return {
35386
- get inputFrameVisible() {
35387
- return prevReady;
35326
+ writeBytes(data) {
35327
+ if (disposed) return;
35328
+ term.write(data, () => {
35329
+ if (disposed) return;
35330
+ tick();
35331
+ });
35388
35332
  },
35389
35333
  dispose() {
35390
- unsubscribed = true;
35391
- unsubscribe();
35334
+ disposed = true;
35392
35335
  clearQuiet();
35336
+ term.dispose();
35393
35337
  }
35394
35338
  };
35395
35339
  }
@@ -35471,18 +35415,7 @@ var ClaudeTuiAdapter = class extends ClaudeAdapter {
35471
35415
  tag: ctx.toolSessionId ?? "no-tsid"
35472
35416
  });
35473
35417
  const bootGate = createBootGate(pty, this.tuiLogger);
35474
- const surface = createTerminalSurface();
35475
- const readyObserver = observeReady(surface, {
35476
- quietMs: 500,
35477
- onReady: () => {
35478
- if (!ctx.toolSessionId || !this.tuiOpts.onReady) return;
35479
- this.tuiLogger?.debug("ready-detected", { toolSessionId: ctx.toolSessionId });
35480
- this.tuiOpts.onReady(ctx.toolSessionId);
35481
- },
35482
- // [RG-DBG] 排查 ReadyGate 偶现卡输入用;定位完跟所有 [RG] 日志一起删
35483
- logger: this.tuiLogger
35484
- });
35485
- const popupObserver = observePopup(surface, {
35418
+ const detector = createPopupDetector({
35486
35419
  clearQuietMs: 200,
35487
35420
  onTransition: (kind, visible) => {
35488
35421
  if (!ctx.toolSessionId || !this.tuiOpts.onPopupTransition) return;
@@ -35492,21 +35425,29 @@ var ClaudeTuiAdapter = class extends ClaudeAdapter {
35492
35425
  visible
35493
35426
  });
35494
35427
  this.tuiOpts.onPopupTransition(ctx.toolSessionId, kind, visible);
35428
+ }
35429
+ });
35430
+ const readyDetector = createReadyDetector({
35431
+ quietMs: 500,
35432
+ onReady: () => {
35433
+ if (!ctx.toolSessionId || !this.tuiOpts.onReady) return;
35434
+ this.tuiLogger?.debug("ready-detected", { toolSessionId: ctx.toolSessionId });
35435
+ this.tuiOpts.onReady(ctx.toolSessionId);
35495
35436
  },
35496
- // popup_close 信号源:ready observer 扫到 + ─{20,} 输入框结构 → 输入框可见 → popup 已关
35497
- getInputFrameVisible: () => readyObserver.inputFrameVisible
35437
+ // [RG-DBG] 排查 ReadyGate 偶现卡输入用;定位完跟所有 [RG] 日志一起删
35438
+ logger: this.tuiLogger
35498
35439
  });
35499
- if (ctx.toolSessionId && this.tuiOpts.onSurfaceRegister) {
35500
- this.tuiOpts.onSurfaceRegister(ctx.toolSessionId, surface);
35440
+ if (ctx.toolSessionId && this.tuiOpts.onDetectorRegister) {
35441
+ this.tuiOpts.onDetectorRegister(ctx.toolSessionId, detector);
35501
35442
  }
35502
35443
  let chunkSeq = 0;
35503
35444
  if (ctx.toolSessionId && this.tuiOpts.onPtyReplayRegister) {
35504
35445
  this.tuiOpts.onPtyReplayRegister(ctx.toolSessionId, async () => {
35505
- await surface.drain();
35446
+ await detector.drain();
35506
35447
  return {
35507
- data: surface.serialize(),
35508
- popupKind: popupObserver.visibleKind,
35509
- atSeq: surface.parseSeq
35448
+ data: detector.serialize(),
35449
+ popupKind: detector.visibleKind,
35450
+ atSeq: detector.parseSeq
35510
35451
  };
35511
35452
  });
35512
35453
  }
@@ -35523,7 +35464,8 @@ var ClaudeTuiAdapter = class extends ClaudeAdapter {
35523
35464
  this.tuiOpts.onPtyData(ctx.toolSessionId, merged.toString("base64"), seq);
35524
35465
  }
35525
35466
  bootGate.feedBytes(merged);
35526
- void surface.writeBytes(merged.toString("utf8"), seq);
35467
+ void detector.writeBytes(merged.toString("utf8"), seq);
35468
+ readyDetector.writeBytes(merged.toString("utf8"));
35527
35469
  if (ctx.toolSessionId) {
35528
35470
  probePtyDataThrottled(ctx.toolSessionId, merged.length, merged);
35529
35471
  }
@@ -35541,15 +35483,14 @@ var ClaudeTuiAdapter = class extends ClaudeAdapter {
35541
35483
  flushCoalesced();
35542
35484
  }
35543
35485
  bootGate.dispose();
35544
- readyObserver.dispose();
35545
- popupObserver.dispose();
35546
- if (ctx.toolSessionId && this.tuiOpts.onSurfaceUnregister) {
35547
- this.tuiOpts.onSurfaceUnregister(ctx.toolSessionId);
35486
+ readyDetector.dispose();
35487
+ if (ctx.toolSessionId && this.tuiOpts.onDetectorUnregister) {
35488
+ this.tuiOpts.onDetectorUnregister(ctx.toolSessionId);
35548
35489
  }
35549
35490
  if (ctx.toolSessionId && this.tuiOpts.onPtyUnregister) {
35550
35491
  this.tuiOpts.onPtyUnregister(ctx.toolSessionId);
35551
35492
  }
35552
- surface.dispose();
35493
+ detector.dispose();
35553
35494
  });
35554
35495
  return ptyChild;
35555
35496
  }
@@ -37825,6 +37766,12 @@ async function importZip(buf, root) {
37825
37766
  } catch (e) {
37826
37767
  throw new ImportError("INVALID_MANIFEST", `manifest.json: ${e.message}`);
37827
37768
  }
37769
+ if (manifestJson && typeof manifestJson === "object" && "entry" in manifestJson && manifestJson.entry?.url !== void 0) {
37770
+ throw new ImportError(
37771
+ "REMOTE_NOT_SUPPORTED",
37772
+ "entry.url (remote mode) is not supported in v1"
37773
+ );
37774
+ }
37828
37775
  const result = ExtensionManifestSchema.safeParse(manifestJson);
37829
37776
  if (!result.success) {
37830
37777
  throw new ImportError(
@@ -37833,16 +37780,6 @@ async function importZip(buf, root) {
37833
37780
  );
37834
37781
  }
37835
37782
  const manifest = result.data;
37836
- if (manifestMode(manifest) === "hosted") {
37837
- const filenames = Object.keys(zip.files).filter((n) => !zip.files[n].dir);
37838
- const extras = filenames.filter((n) => n !== "manifest.json");
37839
- if (extras.length > 0) {
37840
- throw new ImportError(
37841
- "HOSTED_ZIP_EXTRA_FILES",
37842
- `hosted extension may only contain manifest.json (extra: ${extras.join(", ")})`
37843
- );
37844
- }
37845
- }
37846
37783
  const destDir = import_node_path19.default.join(root, manifest.id);
37847
37784
  let destExists = false;
37848
37785
  try {
@@ -40303,7 +40240,6 @@ function buildReadyFrame(deps, client) {
40303
40240
  fileSharing.httpBaseUrl = httpBaseUrl;
40304
40241
  if (deps.httpToken) fileSharing.httpToken = deps.httpToken;
40305
40242
  }
40306
- const daemonSource = process.env.CLAWD_DAEMON_SOURCE === "ota" ? "ota" : "packaged";
40307
40243
  return {
40308
40244
  version,
40309
40245
  protocolVersion: PROTOCOL_VERSION,
@@ -40313,7 +40249,6 @@ function buildReadyFrame(deps, client) {
40313
40249
  runningSessions: info.runningSessions,
40314
40250
  tunnelUrl,
40315
40251
  mode: deps.mode,
40316
- daemonSource,
40317
40252
  ...fileSharing
40318
40253
  };
40319
40254
  }
@@ -40661,6 +40596,9 @@ function extensionsRoot(override) {
40661
40596
  function publishedChannelsFile(override) {
40662
40597
  return import_node_path35.default.join(clawdHomeRoot(override), "extensions-published.json");
40663
40598
  }
40599
+ function bundleCacheRoot(override) {
40600
+ return import_node_path35.default.join(clawdHomeRoot(override), "extension-bundles");
40601
+ }
40664
40602
 
40665
40603
  // src/extension/install-flow.ts
40666
40604
  var InstallError = class extends Error {
@@ -41003,17 +40941,10 @@ function pickExtId(frame) {
41003
40941
  }
41004
40942
  function composeState(rec, running, crashed, getPort) {
41005
40943
  if (rec.state === "invalid") return rec;
41006
- if (manifestMode(rec.manifest) === "hosted") {
41007
- return {
41008
- ...rec,
41009
- state: "running",
41010
- target: { kind: "hosted", url: rec.manifest.entry.url }
41011
- };
41012
- }
41013
40944
  if (running.has(rec.extId)) {
41014
40945
  const port = getPort(rec.extId);
41015
40946
  if (port == null) return rec;
41016
- return { ...rec, state: "running", target: { kind: "local", port } };
40947
+ return { ...rec, state: "running", port };
41017
40948
  }
41018
40949
  if (crashed.has(rec.extId)) return { ...rec, state: "crashed" };
41019
40950
  return rec;
@@ -41035,8 +40966,8 @@ function buildExtensionHandlers(deps) {
41035
40966
  const open = async (frame, _client, ctx) => {
41036
40967
  assertOwner(ctx);
41037
40968
  const extId = pickExtId(frame);
41038
- const target = await deps.runtime.open(extId);
41039
- return { response: target };
40969
+ const { port } = await deps.runtime.open(extId);
40970
+ return { response: { port } };
41040
40971
  };
41041
40972
  const close = async (frame, _client, ctx) => {
41042
40973
  assertOwner(ctx);
@@ -41052,8 +40983,8 @@ function buildExtensionHandlers(deps) {
41052
40983
  };
41053
40984
  async function buildSnapshotMeta(extId) {
41054
40985
  const manifest = await readManifest(deps.root, extId);
41055
- const { sha256 } = await bundleExtensionDir(import_node_path38.default.join(deps.root, extId));
41056
- return { manifest, contentHash: sha256 };
40986
+ const { sha256, buffer } = await bundleExtensionDir(import_node_path38.default.join(deps.root, extId));
40987
+ return { manifest, contentHash: sha256, buffer };
41057
40988
  }
41058
40989
  const publish = async (frame, _client, ctx) => {
41059
40990
  assertOwner(ctx);
@@ -41062,7 +40993,7 @@ function buildExtensionHandlers(deps) {
41062
40993
  if (newVersion !== null) {
41063
40994
  await rewriteManifestVersion(deps.root, extId, newVersion, deps.publishedChannelStore.get(extId)?.version);
41064
40995
  }
41065
- const { manifest, contentHash } = await buildSnapshotMeta(extId);
40996
+ const { manifest, contentHash, buffer } = await buildSnapshotMeta(extId);
41066
40997
  const head = deps.publishedChannelStore.get(extId);
41067
40998
  const check = computePublishCheck({
41068
40999
  localHash: contentHash,
@@ -41087,6 +41018,10 @@ function buildExtensionHandlers(deps) {
41087
41018
  `VERSION_REGRESSION: manifest.version (${check.localVersion}) is lower than published version (${check.publishedVersion})`
41088
41019
  );
41089
41020
  }
41021
+ await deps.bundleCache.write(contentHash, buffer);
41022
+ if (head && head.snapshotHash !== contentHash) {
41023
+ await deps.bundleCache.delete(head.snapshotHash);
41024
+ }
41090
41025
  const snapshot = {
41091
41026
  snapshotHash: contentHash,
41092
41027
  version: manifest.version,
@@ -41100,7 +41035,11 @@ function buildExtensionHandlers(deps) {
41100
41035
  const unpublish = async (frame, _client, ctx) => {
41101
41036
  assertOwner(ctx);
41102
41037
  const extId = pickExtId(frame);
41038
+ const head = deps.publishedChannelStore.get(extId);
41103
41039
  await deps.publishedChannelStore.delete(extId);
41040
+ if (head) {
41041
+ await deps.bundleCache.delete(head.snapshotHash);
41042
+ }
41104
41043
  return { response: {} };
41105
41044
  };
41106
41045
  const publishStatus = async (frame, _client, ctx) => {
@@ -41154,16 +41093,16 @@ function buildExtensionHandlers(deps) {
41154
41093
  if (!ctx || ctx.principal.kind !== "guest") {
41155
41094
  throw new ClawdError(ERROR_CODES.FORBIDDEN, "guest only");
41156
41095
  }
41157
- const extId = pickExtId(frame);
41096
+ pickExtId(frame);
41158
41097
  const expectedHash = pickStringField(frame, "snapshotHash");
41159
- const { buffer, sha256 } = await bundleExtensionDir(import_node_path38.default.join(deps.root, extId));
41160
- if (sha256 !== expectedHash) {
41098
+ const cached = await deps.bundleCache.read(expectedHash);
41099
+ if (cached === null) {
41161
41100
  throw new ClawdError(
41162
41101
  ERROR_CODES.VALIDATION_ERROR,
41163
- `HASH_MISMATCH: bundle hash ${sha256.slice(0, 8)}\u2026 \u2260 requested ${expectedHash.slice(0, 8)}\u2026`
41102
+ `SNAPSHOT_NOT_AVAILABLE: bundle for ${expectedHash.slice(0, 8)}\u2026 no longer cached (owner likely republished); guest should reconcile and retry`
41164
41103
  );
41165
41104
  }
41166
- return { response: { zipBase64: buffer.toString("base64") } };
41105
+ return { response: { zipBase64: cached.toString("base64") } };
41167
41106
  };
41168
41107
  const installFromChannelHandler = async (frame, _client, ctx) => {
41169
41108
  assertOwner(ctx);
@@ -41351,7 +41290,8 @@ function buildMethodHandlers(deps) {
41351
41290
  runtime: deps.extensionRuntime,
41352
41291
  uninstall,
41353
41292
  root: extensionsRoot(),
41354
- publishedChannelStore: deps.publishedChannelStore
41293
+ publishedChannelStore: deps.publishedChannelStore,
41294
+ bundleCache: deps.bundleCache
41355
41295
  })
41356
41296
  };
41357
41297
  }
@@ -41586,20 +41526,16 @@ var Runtime = class {
41586
41526
  }
41587
41527
  async open(extId) {
41588
41528
  const existing = this.handles.get(extId);
41589
- if (existing) return { kind: "local", port: existing.port };
41529
+ if (existing) return { port: existing.port };
41590
41530
  const records = await loadAll(this.root);
41591
41531
  const rec = records.find((r) => r.extId === extId);
41592
41532
  if (!rec) throw new RuntimeError("NOT_FOUND", `extension ${extId} not installed`);
41593
41533
  if (rec.state === "invalid")
41594
41534
  throw new RuntimeError("INVALID_MANIFEST", rec.invalidReason);
41595
- if (manifestMode(rec.manifest) === "hosted") {
41596
- return { kind: "hosted", url: rec.manifest.entry.url };
41597
- }
41598
41535
  const port = await this.allocator.allocate().catch(() => {
41599
41536
  throw new RuntimeError("PORT_EXHAUSTED", "no free port in configured range");
41600
41537
  });
41601
- const startCommand = rec.manifest.runtime.startCommand;
41602
- const cmd = startCommand.replace(
41538
+ const cmd = rec.manifest.runtime.startCommand.replace(
41603
41539
  /\$CLAWOS_EXT_PORT/g,
41604
41540
  String(port)
41605
41541
  );
@@ -41637,7 +41573,7 @@ var Runtime = class {
41637
41573
  try {
41638
41574
  await this.waitForHealthz(port, () => earlyExit, handle);
41639
41575
  this.crashed.delete(extId);
41640
- return { kind: "local", port };
41576
+ return { port };
41641
41577
  } catch (e) {
41642
41578
  if (this.handles.get(extId) === handle) {
41643
41579
  this.handles.delete(extId);
@@ -41820,11 +41756,44 @@ var PublishedChannelStore = class {
41820
41756
  }
41821
41757
  };
41822
41758
 
41759
+ // src/extension/bundle-cache.ts
41760
+ var import_promises12 = __toESM(require("fs/promises"), 1);
41761
+ var import_node_path43 = __toESM(require("path"), 1);
41762
+ var BundleCache = class {
41763
+ constructor(rootDir) {
41764
+ this.rootDir = rootDir;
41765
+ }
41766
+ rootDir;
41767
+ /** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
41768
+ async write(snapshotHash, buffer) {
41769
+ await import_promises12.default.mkdir(this.rootDir, { recursive: true });
41770
+ const file = import_node_path43.default.join(this.rootDir, `${snapshotHash}.zip`);
41771
+ const tmp = `${file}.tmp`;
41772
+ await import_promises12.default.writeFile(tmp, buffer, { mode: 384 });
41773
+ await import_promises12.default.rename(tmp, file);
41774
+ }
41775
+ /** Returns the bundle bytes, or null when the file doesn't exist. */
41776
+ async read(snapshotHash) {
41777
+ const file = import_node_path43.default.join(this.rootDir, `${snapshotHash}.zip`);
41778
+ try {
41779
+ return await import_promises12.default.readFile(file);
41780
+ } catch (e) {
41781
+ if (e.code === "ENOENT") return null;
41782
+ throw e;
41783
+ }
41784
+ }
41785
+ /** Idempotent — missing file is not an error. */
41786
+ async delete(snapshotHash) {
41787
+ const file = import_node_path43.default.join(this.rootDir, `${snapshotHash}.zip`);
41788
+ await import_promises12.default.rm(file, { force: true });
41789
+ }
41790
+ };
41791
+
41823
41792
  // src/index.ts
41824
41793
  async function startDaemon(config) {
41825
41794
  const logger = createLogger({
41826
41795
  level: config.logLevel,
41827
- file: import_node_path43.default.join(config.dataDir, "clawd.log")
41796
+ file: import_node_path44.default.join(config.dataDir, "clawd.log")
41828
41797
  });
41829
41798
  logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
41830
41799
  const stateMgr = new StateFileManager({ dataDir: config.dataDir });
@@ -41911,7 +41880,7 @@ async function startDaemon(config) {
41911
41880
  const agents = new AgentsScanner();
41912
41881
  const history = new ClaudeHistoryReader();
41913
41882
  let transport = null;
41914
- const personaStore = new PersonaStore(import_node_path43.default.join(config.dataDir, "personas"));
41883
+ const personaStore = new PersonaStore(import_node_path44.default.join(config.dataDir, "personas"));
41915
41884
  const defaultsRoot = findDefaultsRoot();
41916
41885
  if (defaultsRoot) {
41917
41886
  seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
@@ -41928,7 +41897,7 @@ async function startDaemon(config) {
41928
41897
  getAdapter,
41929
41898
  historyReader: history,
41930
41899
  dataDir: config.dataDir,
41931
- personaRoot: import_node_path43.default.join(config.dataDir, "personas"),
41900
+ personaRoot: import_node_path44.default.join(config.dataDir, "personas"),
41932
41901
  personaStore,
41933
41902
  ownerDisplayName,
41934
41903
  ownerPrincipalId,
@@ -41952,7 +41921,7 @@ async function startDaemon(config) {
41952
41921
  // 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
41953
41922
  attachmentGroup: {
41954
41923
  onFileEdit: (input) => {
41955
- const absPath = import_node_path43.default.isAbsolute(input.relPath) ? input.relPath : import_node_path43.default.join(input.cwd, input.relPath);
41924
+ const absPath = import_node_path44.default.isAbsolute(input.relPath) ? input.relPath : import_node_path44.default.join(input.cwd, input.relPath);
41956
41925
  let size = 0;
41957
41926
  try {
41958
41927
  size = import_node_fs29.default.statSync(absPath).size;
@@ -42019,8 +41988,8 @@ async function startDaemon(config) {
42019
41988
  onPtyData: (tsid, b64, seq) => manager.emitPtyChunk(tsid, b64, seq),
42020
41989
  onPopupTransition: (tsid, kind, visible) => manager.emitPopupTransition(tsid, kind, visible),
42021
41990
  onPtyReplayRegister: (tsid, replay) => manager.registerPtyReplay(tsid, replay),
42022
- onSurfaceRegister: (tsid, surface) => manager.registerSurface(tsid, surface),
42023
- onSurfaceUnregister: (tsid) => manager.unregisterSurface(tsid),
41991
+ onDetectorRegister: (tsid, detector) => manager.registerDetector(tsid, detector),
41992
+ onDetectorUnregister: (tsid) => manager.unregisterDetector(tsid),
42024
41993
  // ReadyGate v2:ReadyDetector emit ready 时投递 reducer 'ready-detected' input
42025
41994
  onReady: (tsid) => manager.dispatchReadyDetected(tsid)
42026
41995
  }) : new ClaudeAdapter({ logger, historyReader: new ClaudeHistoryReader() });
@@ -42041,6 +42010,7 @@ async function startDaemon(config) {
42041
42010
  const extensionRuntime = new Runtime({ root: extensionsRoot() });
42042
42011
  const publishedChannelStore = new PublishedChannelStore(publishedChannelsFile());
42043
42012
  await publishedChannelStore.load();
42013
+ const bundleCache = new BundleCache(bundleCacheRoot());
42044
42014
  const handlers = buildMethodHandlers({
42045
42015
  manager,
42046
42016
  workspace,
@@ -42080,10 +42050,10 @@ async function startDaemon(config) {
42080
42050
  // 'persona/<pid>/owner',default 走 'default'。
42081
42051
  getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
42082
42052
  // guest path guard:candidate 必须在 personaRoot 子树下
42083
- personaRoot: import_node_path43.default.join(config.dataDir, "personas")
42053
+ personaRoot: import_node_path44.default.join(config.dataDir, "personas")
42084
42054
  },
42085
42055
  // workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
42086
- personaRoot: import_node_path43.default.join(config.dataDir, "personas"),
42056
+ personaRoot: import_node_path44.default.join(config.dataDir, "personas"),
42087
42057
  // capability:list / delete handler 依赖
42088
42058
  capabilityManager,
42089
42059
  // personal-cap:get 返回的 shareBaseUrl 用此 base URL:
@@ -42112,7 +42082,8 @@ async function startDaemon(config) {
42112
42082
  // level so stopAll() runs in the shutdown hook below.
42113
42083
  extensionRuntime,
42114
42084
  // extension sharing v1 — owner-side published-channels store.
42115
- publishedChannelStore
42085
+ publishedChannelStore,
42086
+ bundleCache
42116
42087
  });
42117
42088
  const authResolver = new AuthContextResolver({
42118
42089
  ownerToken: resolvedAuthToken
@@ -42297,8 +42268,8 @@ async function startDaemon(config) {
42297
42268
  const lines = [
42298
42269
  `Tunnel: ${r.url}`,
42299
42270
  ...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
42300
- `Frpc config: ${import_node_path43.default.join(config.dataDir, "frpc.toml")}`,
42301
- `Frpc log: ${import_node_path43.default.join(config.dataDir, "frpc.log")}`
42271
+ `Frpc config: ${import_node_path44.default.join(config.dataDir, "frpc.toml")}`,
42272
+ `Frpc log: ${import_node_path44.default.join(config.dataDir, "frpc.log")}`
42302
42273
  ];
42303
42274
  const width = Math.max(...lines.map((l) => l.length));
42304
42275
  const bar = "\u2550".repeat(width + 4);
@@ -42311,7 +42282,7 @@ ${bar}
42311
42282
 
42312
42283
  `);
42313
42284
  try {
42314
- const connectPath = import_node_path43.default.join(config.dataDir, "connect.txt");
42285
+ const connectPath = import_node_path44.default.join(config.dataDir, "connect.txt");
42315
42286
  import_node_fs29.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
42316
42287
  } catch {
42317
42288
  }
@@ -42378,7 +42349,7 @@ ${bar}
42378
42349
  };
42379
42350
  }
42380
42351
  function migrateDropPersonsDir(dataDir) {
42381
- const dir = import_node_path43.default.join(dataDir, "persons");
42352
+ const dir = import_node_path44.default.join(dataDir, "persons");
42382
42353
  try {
42383
42354
  import_node_fs29.default.rmSync(dir, { recursive: true, force: true });
42384
42355
  } catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawos-dev/clawd",
3
- "version": "0.2.104",
3
+ "version": "0.2.105-beta.199.6386646",
4
4
  "description": "Standalone clawd daemon — Claude Code (and future Codex) session server over WebSocket",
5
5
  "type": "module",
6
6
  "license": "MIT",