@clawos-dev/clawd 0.2.64-beta.106.42f5a70 → 0.2.65-beta.107.ac81439
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +409 -657
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -110,17 +110,12 @@ var init_methods = __esm({
|
|
|
110
110
|
// 触发频率低(仅 window resize),response 也是 ack。
|
|
111
111
|
"session:pty:input",
|
|
112
112
|
"session:pty:resize",
|
|
113
|
-
// ---- attachment.* file-sharing
|
|
113
|
+
// ---- attachment.* file-sharing(详见 attachment-schemas.ts) ----
|
|
114
114
|
// 命名警告:这里的 `attachment.*` RPC 与 CC v2.x 上行 `type:"attachment"` 系统行
|
|
115
115
|
// (attachment-skills / attachment-deferred-tools / attachment_memories)是不同概念。
|
|
116
116
|
// 全部管理类 RPC handler 入口 requireOwner(personal token 调任意一个都 403);
|
|
117
|
-
// 实际文件传输走 HTTP 路由(GET/
|
|
118
|
-
"attachment.
|
|
119
|
-
"attachment.outboxRevoke",
|
|
120
|
-
"attachment.outboxList",
|
|
121
|
-
"attachment.mountAdd",
|
|
122
|
-
"attachment.mountRemove",
|
|
123
|
-
"attachment.mountList",
|
|
117
|
+
// 实际文件传输走 HTTP 路由(GET /files?p=&e=&s=,签名验证),不在白名单内。
|
|
118
|
+
"attachment.signUrl",
|
|
124
119
|
"attachment.groupAdd",
|
|
125
120
|
"attachment.groupRemove",
|
|
126
121
|
"attachment.groupList",
|
|
@@ -617,8 +612,8 @@ var init_parseUtil = __esm({
|
|
|
617
612
|
init_errors2();
|
|
618
613
|
init_en();
|
|
619
614
|
makeIssue = (params) => {
|
|
620
|
-
const { data, path:
|
|
621
|
-
const fullPath = [...
|
|
615
|
+
const { data, path: path31, errorMaps, issueData } = params;
|
|
616
|
+
const fullPath = [...path31, ...issueData.path || []];
|
|
622
617
|
const fullIssue = {
|
|
623
618
|
...issueData,
|
|
624
619
|
path: fullPath
|
|
@@ -929,11 +924,11 @@ var init_types = __esm({
|
|
|
929
924
|
init_parseUtil();
|
|
930
925
|
init_util();
|
|
931
926
|
ParseInputLazyPath = class {
|
|
932
|
-
constructor(parent, value,
|
|
927
|
+
constructor(parent, value, path31, key) {
|
|
933
928
|
this._cachedPath = [];
|
|
934
929
|
this.parent = parent;
|
|
935
930
|
this.data = value;
|
|
936
|
-
this._path =
|
|
931
|
+
this._path = path31;
|
|
937
932
|
this._key = key;
|
|
938
933
|
}
|
|
939
934
|
get path() {
|
|
@@ -4317,116 +4312,47 @@ var init_zod = __esm({
|
|
|
4317
4312
|
});
|
|
4318
4313
|
|
|
4319
4314
|
// ../protocol/src/attachment-schemas.ts
|
|
4320
|
-
var TOKEN_ROLES, GROUP_FILE_SOURCES,
|
|
4315
|
+
var TOKEN_ROLES, GROUP_FILE_SOURCES, GroupFileEntrySchema, AttachmentSignUrlArgs, AttachmentSignUrlResponseSchema, AttachmentGroupAddArgs, AttachmentGroupAddResponseSchema, AttachmentGroupRemoveArgs, AttachmentGroupRemoveResponseSchema, AttachmentGroupListArgs, AttachmentGroupListResponseSchema, AttachmentGroupListPersonaArgs, AttachmentGroupListPersonaResponseSchema;
|
|
4321
4316
|
var init_attachment_schemas = __esm({
|
|
4322
4317
|
"../protocol/src/attachment-schemas.ts"() {
|
|
4323
4318
|
"use strict";
|
|
4324
4319
|
init_zod();
|
|
4325
4320
|
TOKEN_ROLES = ["owner", "personal"];
|
|
4326
4321
|
GROUP_FILE_SOURCES = ["agent", "owner"];
|
|
4327
|
-
MOUNT_MODES = ["link", "copy"];
|
|
4328
4322
|
GroupFileEntrySchema = external_exports.object({
|
|
4329
4323
|
/** daemon 派发的稳定 id(用于 RPC remove / UI key) */
|
|
4330
4324
|
id: external_exports.string().min(1),
|
|
4331
4325
|
/** 相对 personaDir / sessionCwd 的路径 */
|
|
4332
4326
|
relPath: external_exports.string().min(1),
|
|
4333
4327
|
from: external_exports.enum(GROUP_FILE_SOURCES),
|
|
4334
|
-
/** owner
|
|
4328
|
+
/** owner 手动加入时的可选备注 */
|
|
4335
4329
|
label: external_exports.string().optional(),
|
|
4336
4330
|
/** 文件字节数(stat 时拍) */
|
|
4337
4331
|
size: external_exports.number().int().nonnegative(),
|
|
4338
4332
|
mime: external_exports.string().min(1),
|
|
4339
|
-
/**
|
|
4333
|
+
/** 加入清单时间戳(ms) */
|
|
4340
4334
|
addedAt: external_exports.number().int().nonnegative(),
|
|
4341
4335
|
/** 最近一次 agent Write/Edit 时间戳(agent 反复改同 path 时更新) */
|
|
4342
4336
|
lastEditedAt: external_exports.number().int().nonnegative().optional(),
|
|
4343
4337
|
/** agent rm / 文件不见了时打标;UI 灰显,不能再 share */
|
|
4344
4338
|
stale: external_exports.boolean().optional()
|
|
4345
4339
|
});
|
|
4346
|
-
|
|
4347
|
-
/**
|
|
4348
|
-
basename: external_exports.string().min(1),
|
|
4349
|
-
/** 原始绝对路径(link 模式下 realpath 后用于 sandbox.allowRead 派生) */
|
|
4340
|
+
AttachmentSignUrlArgs = external_exports.object({
|
|
4341
|
+
/** 要分享的绝对路径;签名只关心 absPath,不区分 persona/session */
|
|
4350
4342
|
absPath: external_exports.string().min(1),
|
|
4351
|
-
|
|
4343
|
+
/** TTL 秒数;缺省 24h;'never' 走 null 不带 exp 字段(永久有效) */
|
|
4344
|
+
ttlSeconds: external_exports.number().int().positive().nullable().optional()
|
|
4352
4345
|
});
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
external_exports.object({ kind: external_exports.literal("personal"), personalId: external_exports.string().min(1) })
|
|
4356
|
-
]);
|
|
4357
|
-
OutboxCapEntrySchema = external_exports.object({
|
|
4358
|
-
capToken: external_exports.string().min(1),
|
|
4359
|
-
/** 归属:persona 域 cap 带 personaId;direct 会话 cap 带 sessionId */
|
|
4360
|
-
scopeRef: external_exports.union([
|
|
4361
|
-
external_exports.object({ kind: external_exports.literal("persona"), personaId: external_exports.string().min(1) }),
|
|
4362
|
-
external_exports.object({ kind: external_exports.literal("session"), sessionId: external_exports.string().min(1) })
|
|
4363
|
-
]),
|
|
4364
|
-
absPath: external_exports.string().min(1),
|
|
4365
|
-
/** display name(UI 列表显示 + Share dialog 标题),通常等于 basename */
|
|
4366
|
-
name: external_exports.string().min(1),
|
|
4367
|
-
expiresAt: external_exports.number().int().nonnegative().nullable(),
|
|
4368
|
-
oneShot: external_exports.boolean(),
|
|
4369
|
-
scope: OutboxScopeSchema,
|
|
4370
|
-
hits: external_exports.number().int().nonnegative(),
|
|
4371
|
-
revoked: external_exports.boolean().optional(),
|
|
4372
|
-
createdAt: external_exports.number().int().nonnegative()
|
|
4373
|
-
});
|
|
4374
|
-
AttachmentOutboxCreateArgs = external_exports.object({
|
|
4375
|
-
/** persona 域:传 personaId;direct 会话:传 sessionId(二选一) */
|
|
4376
|
-
personaId: external_exports.string().min(1).optional(),
|
|
4377
|
-
sessionId: external_exports.string().min(1).optional(),
|
|
4378
|
-
absPath: external_exports.string().min(1),
|
|
4379
|
-
/** TTL 秒数;缺省 24h;'never' 走 null */
|
|
4380
|
-
ttlSeconds: external_exports.number().int().positive().nullable().optional(),
|
|
4381
|
-
oneShot: external_exports.boolean().optional(),
|
|
4382
|
-
scope: OutboxScopeSchema.optional()
|
|
4383
|
-
});
|
|
4384
|
-
AttachmentOutboxCreateResponseSchema = external_exports.object({
|
|
4385
|
-
capToken: external_exports.string().min(1),
|
|
4386
|
-
/** 完整 URL(含 httpBaseUrl 前缀),UI 直接复制到剪贴板 */
|
|
4346
|
+
AttachmentSignUrlResponseSchema = external_exports.object({
|
|
4347
|
+
/** 完整 URL(含 httpBaseUrl 前缀),UI 直接 window.open / 复制到剪贴板 */
|
|
4387
4348
|
url: external_exports.string().min(1),
|
|
4349
|
+
/** 失效时间戳(ms);null = 永久 */
|
|
4388
4350
|
expiresAt: external_exports.number().int().nonnegative().nullable()
|
|
4389
4351
|
});
|
|
4390
|
-
AttachmentOutboxRevokeArgs = external_exports.object({
|
|
4391
|
-
capToken: external_exports.string().min(1)
|
|
4392
|
-
});
|
|
4393
|
-
AttachmentOutboxRevokeResponseSchema = external_exports.object({
|
|
4394
|
-
revoked: external_exports.literal(true)
|
|
4395
|
-
});
|
|
4396
|
-
AttachmentOutboxListArgs = external_exports.object({
|
|
4397
|
-
/** 缺省 = 全部(含 direct 会话);传 personaId 过滤到该 persona */
|
|
4398
|
-
personaId: external_exports.string().min(1).optional()
|
|
4399
|
-
});
|
|
4400
|
-
AttachmentOutboxListResponseSchema = external_exports.object({
|
|
4401
|
-
entries: external_exports.array(OutboxCapEntrySchema)
|
|
4402
|
-
});
|
|
4403
|
-
AttachmentMountAddArgs = external_exports.object({
|
|
4404
|
-
personaId: external_exports.string().min(1),
|
|
4405
|
-
absPath: external_exports.string().min(1),
|
|
4406
|
-
mode: external_exports.enum(MOUNT_MODES)
|
|
4407
|
-
});
|
|
4408
|
-
AttachmentMountAddResponseSchema = external_exports.object({
|
|
4409
|
-
entry: MountEntrySchema,
|
|
4410
|
-
/** sandbox.allowRead 派生后是否需要重启 session 才能让 CC 子进程跟 symlink */
|
|
4411
|
-
sandboxRestartNeeded: external_exports.boolean()
|
|
4412
|
-
});
|
|
4413
|
-
AttachmentMountRemoveArgs = external_exports.object({
|
|
4414
|
-
personaId: external_exports.string().min(1),
|
|
4415
|
-
basename: external_exports.string().min(1)
|
|
4416
|
-
});
|
|
4417
|
-
AttachmentMountRemoveResponseSchema = external_exports.object({
|
|
4418
|
-
removed: external_exports.literal(true)
|
|
4419
|
-
});
|
|
4420
|
-
AttachmentMountListArgs = external_exports.object({
|
|
4421
|
-
personaId: external_exports.string().min(1)
|
|
4422
|
-
});
|
|
4423
|
-
AttachmentMountListResponseSchema = external_exports.object({
|
|
4424
|
-
entries: external_exports.array(MountEntrySchema)
|
|
4425
|
-
});
|
|
4426
4352
|
AttachmentGroupAddArgs = external_exports.object({
|
|
4427
4353
|
sessionId: external_exports.string().min(1),
|
|
4428
4354
|
relPath: external_exports.string().min(1),
|
|
4429
|
-
/** owner
|
|
4355
|
+
/** owner 手动加入时可选备注;agent 自动入清单不走此 RPC */
|
|
4430
4356
|
label: external_exports.string().optional()
|
|
4431
4357
|
});
|
|
4432
4358
|
AttachmentGroupAddResponseSchema = external_exports.object({
|
|
@@ -5543,8 +5469,8 @@ var require_req = __commonJS({
|
|
|
5543
5469
|
if (req.originalUrl) {
|
|
5544
5470
|
_req.url = req.originalUrl;
|
|
5545
5471
|
} else {
|
|
5546
|
-
const
|
|
5547
|
-
_req.url = typeof
|
|
5472
|
+
const path31 = req.path;
|
|
5473
|
+
_req.url = typeof path31 === "string" ? path31 : req.url ? req.url.path || req.url : void 0;
|
|
5548
5474
|
}
|
|
5549
5475
|
if (req.query) {
|
|
5550
5476
|
_req.query = req.query;
|
|
@@ -5709,14 +5635,14 @@ var require_redact = __commonJS({
|
|
|
5709
5635
|
}
|
|
5710
5636
|
return obj;
|
|
5711
5637
|
}
|
|
5712
|
-
function parsePath(
|
|
5638
|
+
function parsePath(path31) {
|
|
5713
5639
|
const parts = [];
|
|
5714
5640
|
let current = "";
|
|
5715
5641
|
let inBrackets = false;
|
|
5716
5642
|
let inQuotes = false;
|
|
5717
5643
|
let quoteChar = "";
|
|
5718
|
-
for (let i = 0; i <
|
|
5719
|
-
const char =
|
|
5644
|
+
for (let i = 0; i < path31.length; i++) {
|
|
5645
|
+
const char = path31[i];
|
|
5720
5646
|
if (!inBrackets && char === ".") {
|
|
5721
5647
|
if (current) {
|
|
5722
5648
|
parts.push(current);
|
|
@@ -5847,10 +5773,10 @@ var require_redact = __commonJS({
|
|
|
5847
5773
|
return current;
|
|
5848
5774
|
}
|
|
5849
5775
|
function redactPaths(obj, paths, censor, remove = false) {
|
|
5850
|
-
for (const
|
|
5851
|
-
const parts = parsePath(
|
|
5776
|
+
for (const path31 of paths) {
|
|
5777
|
+
const parts = parsePath(path31);
|
|
5852
5778
|
if (parts.includes("*")) {
|
|
5853
|
-
redactWildcardPath(obj, parts, censor,
|
|
5779
|
+
redactWildcardPath(obj, parts, censor, path31, remove);
|
|
5854
5780
|
} else {
|
|
5855
5781
|
if (remove) {
|
|
5856
5782
|
removeKey(obj, parts);
|
|
@@ -5935,8 +5861,8 @@ var require_redact = __commonJS({
|
|
|
5935
5861
|
}
|
|
5936
5862
|
} else {
|
|
5937
5863
|
if (afterWildcard.includes("*")) {
|
|
5938
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
5939
|
-
const fullPath = [...pathArray.slice(0, pathLength), ...
|
|
5864
|
+
const wrappedCensor = typeof censor === "function" ? (value, path31) => {
|
|
5865
|
+
const fullPath = [...pathArray.slice(0, pathLength), ...path31];
|
|
5940
5866
|
return censor(value, fullPath);
|
|
5941
5867
|
} : censor;
|
|
5942
5868
|
redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
|
|
@@ -5971,8 +5897,8 @@ var require_redact = __commonJS({
|
|
|
5971
5897
|
return null;
|
|
5972
5898
|
}
|
|
5973
5899
|
const pathStructure = /* @__PURE__ */ new Map();
|
|
5974
|
-
for (const
|
|
5975
|
-
const parts = parsePath(
|
|
5900
|
+
for (const path31 of pathsToClone) {
|
|
5901
|
+
const parts = parsePath(path31);
|
|
5976
5902
|
let current = pathStructure;
|
|
5977
5903
|
for (let i = 0; i < parts.length; i++) {
|
|
5978
5904
|
const part = parts[i];
|
|
@@ -6024,24 +5950,24 @@ var require_redact = __commonJS({
|
|
|
6024
5950
|
}
|
|
6025
5951
|
return cloneSelectively(obj, pathStructure);
|
|
6026
5952
|
}
|
|
6027
|
-
function validatePath(
|
|
6028
|
-
if (typeof
|
|
5953
|
+
function validatePath(path31) {
|
|
5954
|
+
if (typeof path31 !== "string") {
|
|
6029
5955
|
throw new Error("Paths must be (non-empty) strings");
|
|
6030
5956
|
}
|
|
6031
|
-
if (
|
|
5957
|
+
if (path31 === "") {
|
|
6032
5958
|
throw new Error("Invalid redaction path ()");
|
|
6033
5959
|
}
|
|
6034
|
-
if (
|
|
6035
|
-
throw new Error(`Invalid redaction path (${
|
|
5960
|
+
if (path31.includes("..")) {
|
|
5961
|
+
throw new Error(`Invalid redaction path (${path31})`);
|
|
6036
5962
|
}
|
|
6037
|
-
if (
|
|
6038
|
-
throw new Error(`Invalid redaction path (${
|
|
5963
|
+
if (path31.includes(",")) {
|
|
5964
|
+
throw new Error(`Invalid redaction path (${path31})`);
|
|
6039
5965
|
}
|
|
6040
5966
|
let bracketCount = 0;
|
|
6041
5967
|
let inQuotes = false;
|
|
6042
5968
|
let quoteChar = "";
|
|
6043
|
-
for (let i = 0; i <
|
|
6044
|
-
const char =
|
|
5969
|
+
for (let i = 0; i < path31.length; i++) {
|
|
5970
|
+
const char = path31[i];
|
|
6045
5971
|
if ((char === '"' || char === "'") && bracketCount > 0) {
|
|
6046
5972
|
if (!inQuotes) {
|
|
6047
5973
|
inQuotes = true;
|
|
@@ -6055,20 +5981,20 @@ var require_redact = __commonJS({
|
|
|
6055
5981
|
} else if (char === "]" && !inQuotes) {
|
|
6056
5982
|
bracketCount--;
|
|
6057
5983
|
if (bracketCount < 0) {
|
|
6058
|
-
throw new Error(`Invalid redaction path (${
|
|
5984
|
+
throw new Error(`Invalid redaction path (${path31})`);
|
|
6059
5985
|
}
|
|
6060
5986
|
}
|
|
6061
5987
|
}
|
|
6062
5988
|
if (bracketCount !== 0) {
|
|
6063
|
-
throw new Error(`Invalid redaction path (${
|
|
5989
|
+
throw new Error(`Invalid redaction path (${path31})`);
|
|
6064
5990
|
}
|
|
6065
5991
|
}
|
|
6066
5992
|
function validatePaths(paths) {
|
|
6067
5993
|
if (!Array.isArray(paths)) {
|
|
6068
5994
|
throw new TypeError("paths must be an array");
|
|
6069
5995
|
}
|
|
6070
|
-
for (const
|
|
6071
|
-
validatePath(
|
|
5996
|
+
for (const path31 of paths) {
|
|
5997
|
+
validatePath(path31);
|
|
6072
5998
|
}
|
|
6073
5999
|
}
|
|
6074
6000
|
function slowRedact(options = {}) {
|
|
@@ -6236,8 +6162,8 @@ var require_redaction = __commonJS({
|
|
|
6236
6162
|
if (shape[k2] === null) {
|
|
6237
6163
|
o[k2] = (value) => topCensor(value, [k2]);
|
|
6238
6164
|
} else {
|
|
6239
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
6240
|
-
return censor(value, [k2, ...
|
|
6165
|
+
const wrappedCensor = typeof censor === "function" ? (value, path31) => {
|
|
6166
|
+
return censor(value, [k2, ...path31]);
|
|
6241
6167
|
} : censor;
|
|
6242
6168
|
o[k2] = Redact({
|
|
6243
6169
|
paths: shape[k2],
|
|
@@ -6455,10 +6381,10 @@ var require_atomic_sleep = __commonJS({
|
|
|
6455
6381
|
var require_sonic_boom = __commonJS({
|
|
6456
6382
|
"../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
|
|
6457
6383
|
"use strict";
|
|
6458
|
-
var
|
|
6384
|
+
var fs28 = require("fs");
|
|
6459
6385
|
var EventEmitter2 = require("events");
|
|
6460
6386
|
var inherits = require("util").inherits;
|
|
6461
|
-
var
|
|
6387
|
+
var path31 = require("path");
|
|
6462
6388
|
var sleep = require_atomic_sleep();
|
|
6463
6389
|
var assert = require("assert");
|
|
6464
6390
|
var BUSY_WRITE_TIMEOUT = 100;
|
|
@@ -6512,20 +6438,20 @@ var require_sonic_boom = __commonJS({
|
|
|
6512
6438
|
const mode = sonic.mode;
|
|
6513
6439
|
if (sonic.sync) {
|
|
6514
6440
|
try {
|
|
6515
|
-
if (sonic.mkdir)
|
|
6516
|
-
const fd =
|
|
6441
|
+
if (sonic.mkdir) fs28.mkdirSync(path31.dirname(file), { recursive: true });
|
|
6442
|
+
const fd = fs28.openSync(file, flags, mode);
|
|
6517
6443
|
fileOpened(null, fd);
|
|
6518
6444
|
} catch (err) {
|
|
6519
6445
|
fileOpened(err);
|
|
6520
6446
|
throw err;
|
|
6521
6447
|
}
|
|
6522
6448
|
} else if (sonic.mkdir) {
|
|
6523
|
-
|
|
6449
|
+
fs28.mkdir(path31.dirname(file), { recursive: true }, (err) => {
|
|
6524
6450
|
if (err) return fileOpened(err);
|
|
6525
|
-
|
|
6451
|
+
fs28.open(file, flags, mode, fileOpened);
|
|
6526
6452
|
});
|
|
6527
6453
|
} else {
|
|
6528
|
-
|
|
6454
|
+
fs28.open(file, flags, mode, fileOpened);
|
|
6529
6455
|
}
|
|
6530
6456
|
}
|
|
6531
6457
|
function SonicBoom(opts) {
|
|
@@ -6566,8 +6492,8 @@ var require_sonic_boom = __commonJS({
|
|
|
6566
6492
|
this.flush = flushBuffer;
|
|
6567
6493
|
this.flushSync = flushBufferSync;
|
|
6568
6494
|
this._actualWrite = actualWriteBuffer;
|
|
6569
|
-
fsWriteSync = () =>
|
|
6570
|
-
fsWrite = () =>
|
|
6495
|
+
fsWriteSync = () => fs28.writeSync(this.fd, this._writingBuf);
|
|
6496
|
+
fsWrite = () => fs28.write(this.fd, this._writingBuf, this.release);
|
|
6571
6497
|
} else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
|
|
6572
6498
|
this._writingBuf = "";
|
|
6573
6499
|
this.write = write;
|
|
@@ -6576,15 +6502,15 @@ var require_sonic_boom = __commonJS({
|
|
|
6576
6502
|
this._actualWrite = actualWrite;
|
|
6577
6503
|
fsWriteSync = () => {
|
|
6578
6504
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
6579
|
-
return
|
|
6505
|
+
return fs28.writeSync(this.fd, this._writingBuf);
|
|
6580
6506
|
}
|
|
6581
|
-
return
|
|
6507
|
+
return fs28.writeSync(this.fd, this._writingBuf, "utf8");
|
|
6582
6508
|
};
|
|
6583
6509
|
fsWrite = () => {
|
|
6584
6510
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
6585
|
-
return
|
|
6511
|
+
return fs28.write(this.fd, this._writingBuf, this.release);
|
|
6586
6512
|
}
|
|
6587
|
-
return
|
|
6513
|
+
return fs28.write(this.fd, this._writingBuf, "utf8", this.release);
|
|
6588
6514
|
};
|
|
6589
6515
|
} else {
|
|
6590
6516
|
throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
|
|
@@ -6641,7 +6567,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6641
6567
|
}
|
|
6642
6568
|
}
|
|
6643
6569
|
if (this._fsync) {
|
|
6644
|
-
|
|
6570
|
+
fs28.fsyncSync(this.fd);
|
|
6645
6571
|
}
|
|
6646
6572
|
const len = this._len;
|
|
6647
6573
|
if (this._reopening) {
|
|
@@ -6755,7 +6681,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6755
6681
|
const onDrain = () => {
|
|
6756
6682
|
if (!this._fsync) {
|
|
6757
6683
|
try {
|
|
6758
|
-
|
|
6684
|
+
fs28.fsync(this.fd, (err) => {
|
|
6759
6685
|
this._flushPending = false;
|
|
6760
6686
|
cb(err);
|
|
6761
6687
|
});
|
|
@@ -6857,7 +6783,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6857
6783
|
const fd = this.fd;
|
|
6858
6784
|
this.once("ready", () => {
|
|
6859
6785
|
if (fd !== this.fd) {
|
|
6860
|
-
|
|
6786
|
+
fs28.close(fd, (err) => {
|
|
6861
6787
|
if (err) {
|
|
6862
6788
|
return this.emit("error", err);
|
|
6863
6789
|
}
|
|
@@ -6906,7 +6832,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6906
6832
|
buf = this._bufs[0];
|
|
6907
6833
|
}
|
|
6908
6834
|
try {
|
|
6909
|
-
const n = Buffer.isBuffer(buf) ?
|
|
6835
|
+
const n = Buffer.isBuffer(buf) ? fs28.writeSync(this.fd, buf) : fs28.writeSync(this.fd, buf, "utf8");
|
|
6910
6836
|
const releasedBufObj = releaseWritingBuf(buf, this._len, n);
|
|
6911
6837
|
buf = releasedBufObj.writingBuf;
|
|
6912
6838
|
this._len = releasedBufObj.len;
|
|
@@ -6922,7 +6848,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6922
6848
|
}
|
|
6923
6849
|
}
|
|
6924
6850
|
try {
|
|
6925
|
-
|
|
6851
|
+
fs28.fsyncSync(this.fd);
|
|
6926
6852
|
} catch {
|
|
6927
6853
|
}
|
|
6928
6854
|
}
|
|
@@ -6943,7 +6869,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6943
6869
|
buf = mergeBuf(this._bufs[0], this._lens[0]);
|
|
6944
6870
|
}
|
|
6945
6871
|
try {
|
|
6946
|
-
const n =
|
|
6872
|
+
const n = fs28.writeSync(this.fd, buf);
|
|
6947
6873
|
buf = buf.subarray(n);
|
|
6948
6874
|
this._len = Math.max(this._len - n, 0);
|
|
6949
6875
|
if (buf.length <= 0) {
|
|
@@ -6971,13 +6897,13 @@ var require_sonic_boom = __commonJS({
|
|
|
6971
6897
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
|
|
6972
6898
|
if (this.sync) {
|
|
6973
6899
|
try {
|
|
6974
|
-
const written = Buffer.isBuffer(this._writingBuf) ?
|
|
6900
|
+
const written = Buffer.isBuffer(this._writingBuf) ? fs28.writeSync(this.fd, this._writingBuf) : fs28.writeSync(this.fd, this._writingBuf, "utf8");
|
|
6975
6901
|
release(null, written);
|
|
6976
6902
|
} catch (err) {
|
|
6977
6903
|
release(err);
|
|
6978
6904
|
}
|
|
6979
6905
|
} else {
|
|
6980
|
-
|
|
6906
|
+
fs28.write(this.fd, this._writingBuf, release);
|
|
6981
6907
|
}
|
|
6982
6908
|
}
|
|
6983
6909
|
function actualWriteBuffer() {
|
|
@@ -6986,7 +6912,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6986
6912
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
|
|
6987
6913
|
if (this.sync) {
|
|
6988
6914
|
try {
|
|
6989
|
-
const written =
|
|
6915
|
+
const written = fs28.writeSync(this.fd, this._writingBuf);
|
|
6990
6916
|
release(null, written);
|
|
6991
6917
|
} catch (err) {
|
|
6992
6918
|
release(err);
|
|
@@ -6995,7 +6921,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6995
6921
|
if (kCopyBuffer) {
|
|
6996
6922
|
this._writingBuf = Buffer.from(this._writingBuf);
|
|
6997
6923
|
}
|
|
6998
|
-
|
|
6924
|
+
fs28.write(this.fd, this._writingBuf, release);
|
|
6999
6925
|
}
|
|
7000
6926
|
}
|
|
7001
6927
|
function actualClose(sonic) {
|
|
@@ -7011,12 +6937,12 @@ var require_sonic_boom = __commonJS({
|
|
|
7011
6937
|
sonic._lens = [];
|
|
7012
6938
|
assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
|
|
7013
6939
|
try {
|
|
7014
|
-
|
|
6940
|
+
fs28.fsync(sonic.fd, closeWrapped);
|
|
7015
6941
|
} catch {
|
|
7016
6942
|
}
|
|
7017
6943
|
function closeWrapped() {
|
|
7018
6944
|
if (sonic.fd !== 1 && sonic.fd !== 2) {
|
|
7019
|
-
|
|
6945
|
+
fs28.close(sonic.fd, done);
|
|
7020
6946
|
} else {
|
|
7021
6947
|
done();
|
|
7022
6948
|
}
|
|
@@ -10151,11 +10077,11 @@ var init_lib = __esm({
|
|
|
10151
10077
|
}
|
|
10152
10078
|
}
|
|
10153
10079
|
},
|
|
10154
|
-
addToPath: function addToPath(
|
|
10155
|
-
var last =
|
|
10080
|
+
addToPath: function addToPath(path31, added, removed, oldPosInc, options) {
|
|
10081
|
+
var last = path31.lastComponent;
|
|
10156
10082
|
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
10157
10083
|
return {
|
|
10158
|
-
oldPos:
|
|
10084
|
+
oldPos: path31.oldPos + oldPosInc,
|
|
10159
10085
|
lastComponent: {
|
|
10160
10086
|
count: last.count + 1,
|
|
10161
10087
|
added,
|
|
@@ -10165,7 +10091,7 @@ var init_lib = __esm({
|
|
|
10165
10091
|
};
|
|
10166
10092
|
} else {
|
|
10167
10093
|
return {
|
|
10168
|
-
oldPos:
|
|
10094
|
+
oldPos: path31.oldPos + oldPosInc,
|
|
10169
10095
|
lastComponent: {
|
|
10170
10096
|
count: 1,
|
|
10171
10097
|
added,
|
|
@@ -10596,10 +10522,10 @@ function attachmentToHistoryMessage(o, ts) {
|
|
|
10596
10522
|
const memories = raw.map((m2) => {
|
|
10597
10523
|
if (!m2 || typeof m2 !== "object") return null;
|
|
10598
10524
|
const rec = m2;
|
|
10599
|
-
const
|
|
10525
|
+
const path31 = typeof rec.path === "string" ? rec.path : null;
|
|
10600
10526
|
const content = typeof rec.content === "string" ? rec.content : null;
|
|
10601
|
-
if (!
|
|
10602
|
-
const entry = { path:
|
|
10527
|
+
if (!path31 || content == null) return null;
|
|
10528
|
+
const entry = { path: path31, content };
|
|
10603
10529
|
if (typeof rec.mtimeMs === "number") entry.mtimeMs = rec.mtimeMs;
|
|
10604
10530
|
return entry;
|
|
10605
10531
|
}).filter((m2) => m2 !== null);
|
|
@@ -11403,10 +11329,10 @@ function parseAttachment(obj) {
|
|
|
11403
11329
|
const memories = raw.map((m2) => {
|
|
11404
11330
|
if (!m2 || typeof m2 !== "object") return null;
|
|
11405
11331
|
const rec = m2;
|
|
11406
|
-
const
|
|
11332
|
+
const path31 = typeof rec.path === "string" ? rec.path : null;
|
|
11407
11333
|
const content = typeof rec.content === "string" ? rec.content : null;
|
|
11408
|
-
if (!
|
|
11409
|
-
const out = { path:
|
|
11334
|
+
if (!path31 || content == null) return null;
|
|
11335
|
+
const out = { path: path31, content };
|
|
11410
11336
|
if (typeof rec.mtimeMs === "number") out.mtimeMs = rec.mtimeMs;
|
|
11411
11337
|
return out;
|
|
11412
11338
|
}).filter((m2) => m2 !== null);
|
|
@@ -20320,7 +20246,7 @@ var require_websocket_server = __commonJS({
|
|
|
20320
20246
|
// src/run-case/recorder.ts
|
|
20321
20247
|
function startRunCaseRecorder(opts) {
|
|
20322
20248
|
const now = opts.now ?? Date.now;
|
|
20323
|
-
const dir =
|
|
20249
|
+
const dir = import_node_path27.default.dirname(opts.recordPath);
|
|
20324
20250
|
let stream = null;
|
|
20325
20251
|
let closing = false;
|
|
20326
20252
|
let closedSettled = false;
|
|
@@ -20334,8 +20260,8 @@ function startRunCaseRecorder(opts) {
|
|
|
20334
20260
|
});
|
|
20335
20261
|
const ensureStream = () => {
|
|
20336
20262
|
if (stream) return stream;
|
|
20337
|
-
|
|
20338
|
-
stream =
|
|
20263
|
+
import_node_fs25.default.mkdirSync(dir, { recursive: true });
|
|
20264
|
+
stream = import_node_fs25.default.createWriteStream(opts.recordPath, { flags: "a" });
|
|
20339
20265
|
stream.on("close", () => closedResolve());
|
|
20340
20266
|
return stream;
|
|
20341
20267
|
};
|
|
@@ -20360,12 +20286,12 @@ function startRunCaseRecorder(opts) {
|
|
|
20360
20286
|
};
|
|
20361
20287
|
return { tap, close, closed };
|
|
20362
20288
|
}
|
|
20363
|
-
var
|
|
20289
|
+
var import_node_fs25, import_node_path27;
|
|
20364
20290
|
var init_recorder = __esm({
|
|
20365
20291
|
"src/run-case/recorder.ts"() {
|
|
20366
20292
|
"use strict";
|
|
20367
|
-
|
|
20368
|
-
|
|
20293
|
+
import_node_fs25 = __toESM(require("fs"), 1);
|
|
20294
|
+
import_node_path27 = __toESM(require("path"), 1);
|
|
20369
20295
|
}
|
|
20370
20296
|
});
|
|
20371
20297
|
|
|
@@ -20408,7 +20334,7 @@ var init_wire = __esm({
|
|
|
20408
20334
|
// src/run-case/controller.ts
|
|
20409
20335
|
async function runController(opts) {
|
|
20410
20336
|
const now = opts.now ?? Date.now;
|
|
20411
|
-
const cwd = opts.cwd ?? (0,
|
|
20337
|
+
const cwd = opts.cwd ?? (0, import_node_fs26.mkdtempSync)(import_node_path28.default.join(import_node_os15.default.tmpdir(), "clawd-runcase-"));
|
|
20412
20338
|
const ownsCwd = opts.cwd === void 0;
|
|
20413
20339
|
const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
|
|
20414
20340
|
const spawnCtx = { cwd };
|
|
@@ -20569,19 +20495,19 @@ async function runController(opts) {
|
|
|
20569
20495
|
if (sigintHandler) process.off("SIGINT", sigintHandler);
|
|
20570
20496
|
if (ownsCwd) {
|
|
20571
20497
|
try {
|
|
20572
|
-
(0,
|
|
20498
|
+
(0, import_node_fs26.rmSync)(cwd, { recursive: true, force: true });
|
|
20573
20499
|
} catch {
|
|
20574
20500
|
}
|
|
20575
20501
|
}
|
|
20576
20502
|
return exitCode ?? 0;
|
|
20577
20503
|
}
|
|
20578
|
-
var
|
|
20504
|
+
var import_node_fs26, import_node_os15, import_node_path28;
|
|
20579
20505
|
var init_controller = __esm({
|
|
20580
20506
|
"src/run-case/controller.ts"() {
|
|
20581
20507
|
"use strict";
|
|
20582
|
-
|
|
20508
|
+
import_node_fs26 = require("fs");
|
|
20583
20509
|
import_node_os15 = __toESM(require("os"), 1);
|
|
20584
|
-
|
|
20510
|
+
import_node_path28 = __toESM(require("path"), 1);
|
|
20585
20511
|
init_claude();
|
|
20586
20512
|
init_stdout_splitter();
|
|
20587
20513
|
init_permission_stdio();
|
|
@@ -20813,8 +20739,8 @@ Env (advanced):
|
|
|
20813
20739
|
`;
|
|
20814
20740
|
|
|
20815
20741
|
// src/index.ts
|
|
20816
|
-
var
|
|
20817
|
-
var
|
|
20742
|
+
var import_node_path26 = __toESM(require("path"), 1);
|
|
20743
|
+
var import_node_fs24 = __toESM(require("fs"), 1);
|
|
20818
20744
|
|
|
20819
20745
|
// src/logger.ts
|
|
20820
20746
|
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
@@ -26540,40 +26466,178 @@ function safeRealpath(p2) {
|
|
|
26540
26466
|
|
|
26541
26467
|
// src/attachment/mime.ts
|
|
26542
26468
|
var import_node_path15 = __toESM(require("path"), 1);
|
|
26543
|
-
var
|
|
26544
|
-
|
|
26545
|
-
|
|
26546
|
-
".txt": "text/plain",
|
|
26547
|
-
".log": "text/plain",
|
|
26548
|
-
".json": "application/json",
|
|
26549
|
-
".html": "text/html",
|
|
26550
|
-
".htm": "text/html",
|
|
26551
|
-
".css": "text/css",
|
|
26552
|
-
".js": "application/javascript",
|
|
26553
|
-
".ts": "application/typescript",
|
|
26554
|
-
".tsx": "application/typescript",
|
|
26469
|
+
var TEXT_PLAIN = "text/plain; charset=utf-8";
|
|
26470
|
+
var EXT_TO_NATIVE_MIME = {
|
|
26471
|
+
// 图片
|
|
26555
26472
|
".png": "image/png",
|
|
26556
26473
|
".jpg": "image/jpeg",
|
|
26557
26474
|
".jpeg": "image/jpeg",
|
|
26558
26475
|
".gif": "image/gif",
|
|
26559
26476
|
".webp": "image/webp",
|
|
26560
26477
|
".svg": "image/svg+xml",
|
|
26478
|
+
".bmp": "image/bmp",
|
|
26479
|
+
".ico": "image/x-icon",
|
|
26480
|
+
".avif": "image/avif",
|
|
26481
|
+
// 文档 / 富文本
|
|
26561
26482
|
".pdf": "application/pdf",
|
|
26483
|
+
".html": "text/html; charset=utf-8",
|
|
26484
|
+
".htm": "text/html; charset=utf-8",
|
|
26485
|
+
// 视频 / 音频
|
|
26562
26486
|
".mp4": "video/mp4",
|
|
26563
26487
|
".webm": "video/webm",
|
|
26488
|
+
".mov": "video/quicktime",
|
|
26564
26489
|
".mp3": "audio/mpeg",
|
|
26565
26490
|
".wav": "audio/wav",
|
|
26491
|
+
".ogg": "audio/ogg",
|
|
26492
|
+
".flac": "audio/flac",
|
|
26493
|
+
// 真二进制(让浏览器下载而不是错把它当文本明文)
|
|
26566
26494
|
".zip": "application/zip",
|
|
26567
26495
|
".gz": "application/gzip",
|
|
26568
26496
|
".tar": "application/x-tar",
|
|
26569
|
-
".
|
|
26570
|
-
".
|
|
26571
|
-
".yaml": "application/yaml",
|
|
26572
|
-
".yml": "application/yaml"
|
|
26497
|
+
".7z": "application/x-7z-compressed",
|
|
26498
|
+
".rar": "application/x-rar-compressed"
|
|
26573
26499
|
};
|
|
26500
|
+
var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
26501
|
+
// 文档
|
|
26502
|
+
".md",
|
|
26503
|
+
".markdown",
|
|
26504
|
+
".rst",
|
|
26505
|
+
".adoc",
|
|
26506
|
+
".txt",
|
|
26507
|
+
".log",
|
|
26508
|
+
// 通用结构化
|
|
26509
|
+
".json",
|
|
26510
|
+
".jsonc",
|
|
26511
|
+
".json5",
|
|
26512
|
+
".yaml",
|
|
26513
|
+
".yml",
|
|
26514
|
+
".toml",
|
|
26515
|
+
".xml",
|
|
26516
|
+
".csv",
|
|
26517
|
+
".tsv",
|
|
26518
|
+
".ini",
|
|
26519
|
+
".conf",
|
|
26520
|
+
".cfg",
|
|
26521
|
+
".env",
|
|
26522
|
+
// 前端
|
|
26523
|
+
".js",
|
|
26524
|
+
".jsx",
|
|
26525
|
+
".mjs",
|
|
26526
|
+
".cjs",
|
|
26527
|
+
".ts",
|
|
26528
|
+
".tsx",
|
|
26529
|
+
".css",
|
|
26530
|
+
".scss",
|
|
26531
|
+
".sass",
|
|
26532
|
+
".less",
|
|
26533
|
+
".vue",
|
|
26534
|
+
".svelte",
|
|
26535
|
+
".graphql",
|
|
26536
|
+
".gql",
|
|
26537
|
+
// 后端 / 各语言
|
|
26538
|
+
".py",
|
|
26539
|
+
".rb",
|
|
26540
|
+
".go",
|
|
26541
|
+
".rs",
|
|
26542
|
+
".java",
|
|
26543
|
+
".kt",
|
|
26544
|
+
".kts",
|
|
26545
|
+
".scala",
|
|
26546
|
+
".c",
|
|
26547
|
+
".h",
|
|
26548
|
+
".cpp",
|
|
26549
|
+
".hpp",
|
|
26550
|
+
".cc",
|
|
26551
|
+
".hh",
|
|
26552
|
+
".cs",
|
|
26553
|
+
".php",
|
|
26554
|
+
".swift",
|
|
26555
|
+
".m",
|
|
26556
|
+
".mm",
|
|
26557
|
+
".dart",
|
|
26558
|
+
".lua",
|
|
26559
|
+
".pl",
|
|
26560
|
+
".r",
|
|
26561
|
+
".sh",
|
|
26562
|
+
".bash",
|
|
26563
|
+
".zsh",
|
|
26564
|
+
".fish",
|
|
26565
|
+
// 其他
|
|
26566
|
+
".sql",
|
|
26567
|
+
".proto",
|
|
26568
|
+
".dockerfile",
|
|
26569
|
+
".diff",
|
|
26570
|
+
".patch",
|
|
26571
|
+
".makefile",
|
|
26572
|
+
".mk"
|
|
26573
|
+
]);
|
|
26574
26574
|
function lookupMime(filePathOrName) {
|
|
26575
26575
|
const ext = import_node_path15.default.extname(filePathOrName).toLowerCase();
|
|
26576
|
-
|
|
26576
|
+
if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
|
|
26577
|
+
if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
|
|
26578
|
+
return "application/octet-stream";
|
|
26579
|
+
}
|
|
26580
|
+
|
|
26581
|
+
// src/attachment/sign-url.ts
|
|
26582
|
+
var import_node_crypto5 = __toESM(require("crypto"), 1);
|
|
26583
|
+
var HMAC_ALGO = "sha256";
|
|
26584
|
+
function base64urlEncode(buf) {
|
|
26585
|
+
const b2 = typeof buf === "string" ? Buffer.from(buf, "utf8") : buf;
|
|
26586
|
+
return b2.toString("base64url");
|
|
26587
|
+
}
|
|
26588
|
+
function base64urlDecodeBuf(s) {
|
|
26589
|
+
return Buffer.from(s, "base64url");
|
|
26590
|
+
}
|
|
26591
|
+
function encodeAbsPathForUrl(absPath) {
|
|
26592
|
+
return absPath.split("/").map(encodeURIComponent).join("/");
|
|
26593
|
+
}
|
|
26594
|
+
function decodeAbsPathFromUrl(encoded) {
|
|
26595
|
+
return encoded.split("/").map(decodeURIComponent).join("/");
|
|
26596
|
+
}
|
|
26597
|
+
function computeSig(secret, absPath, e) {
|
|
26598
|
+
const msg = e === null ? absPath : `${absPath}|${e}`;
|
|
26599
|
+
return import_node_crypto5.default.createHmac(HMAC_ALGO, secret).update(msg).digest();
|
|
26600
|
+
}
|
|
26601
|
+
function signUrlParts(secret, absPath, ttlSeconds, now = Date.now) {
|
|
26602
|
+
const e = ttlSeconds === null ? null : Math.floor(now() / 1e3) + ttlSeconds;
|
|
26603
|
+
const s = base64urlEncode(computeSig(secret, absPath, e));
|
|
26604
|
+
return { absPath, e, s };
|
|
26605
|
+
}
|
|
26606
|
+
function buildSignedFileUrl(httpBaseUrl, parts) {
|
|
26607
|
+
const encodedPath = encodeAbsPathForUrl(parts.absPath);
|
|
26608
|
+
const query = parts.e === null ? `s=${encodeURIComponent(parts.s)}` : `e=${parts.e}&s=${encodeURIComponent(parts.s)}`;
|
|
26609
|
+
const base = httpBaseUrl.endsWith("/") ? httpBaseUrl.slice(0, -1) : httpBaseUrl;
|
|
26610
|
+
return `${base}/files${encodedPath}?${query}`;
|
|
26611
|
+
}
|
|
26612
|
+
function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
|
|
26613
|
+
let e;
|
|
26614
|
+
if (eRaw === null || eRaw === void 0 || eRaw === "") {
|
|
26615
|
+
e = null;
|
|
26616
|
+
} else {
|
|
26617
|
+
const parsed = Number.parseInt(eRaw, 10);
|
|
26618
|
+
if (!Number.isFinite(parsed) || parsed < 0) {
|
|
26619
|
+
return { ok: false, code: "MALFORMED" };
|
|
26620
|
+
}
|
|
26621
|
+
e = parsed;
|
|
26622
|
+
}
|
|
26623
|
+
if (!absPath || !s) return { ok: false, code: "MALFORMED" };
|
|
26624
|
+
const expected = computeSig(secret, absPath, e);
|
|
26625
|
+
let provided;
|
|
26626
|
+
try {
|
|
26627
|
+
provided = base64urlDecodeBuf(s);
|
|
26628
|
+
} catch {
|
|
26629
|
+
return { ok: false, code: "MALFORMED" };
|
|
26630
|
+
}
|
|
26631
|
+
if (provided.length !== expected.length) {
|
|
26632
|
+
return { ok: false, code: "BAD_SIG" };
|
|
26633
|
+
}
|
|
26634
|
+
if (!import_node_crypto5.default.timingSafeEqual(provided, expected)) {
|
|
26635
|
+
return { ok: false, code: "BAD_SIG" };
|
|
26636
|
+
}
|
|
26637
|
+
if (e !== null && now() / 1e3 > e) {
|
|
26638
|
+
return { ok: false, code: "EXPIRED" };
|
|
26639
|
+
}
|
|
26640
|
+
return { ok: true, absPath };
|
|
26577
26641
|
}
|
|
26578
26642
|
|
|
26579
26643
|
// src/transport/http-router.ts
|
|
@@ -26588,43 +26652,37 @@ function createHttpRouter(deps) {
|
|
|
26588
26652
|
sendJson(res, 200, { ok: true, version: deps.daemonVersion });
|
|
26589
26653
|
return true;
|
|
26590
26654
|
}
|
|
26591
|
-
if (!url.pathname.startsWith("/persona/") && !url.pathname.startsWith("/session/") &&
|
|
26655
|
+
if (!url.pathname.startsWith("/persona/") && !url.pathname.startsWith("/session/") && !url.pathname.startsWith("/files/")) {
|
|
26592
26656
|
return false;
|
|
26593
26657
|
}
|
|
26594
|
-
{
|
|
26595
|
-
const
|
|
26596
|
-
|
|
26597
|
-
|
|
26598
|
-
|
|
26599
|
-
|
|
26600
|
-
|
|
26601
|
-
|
|
26602
|
-
|
|
26603
|
-
|
|
26604
|
-
|
|
26605
|
-
|
|
26606
|
-
|
|
26607
|
-
|
|
26608
|
-
|
|
26609
|
-
|
|
26610
|
-
|
|
26611
|
-
|
|
26612
|
-
|
|
26613
|
-
|
|
26614
|
-
|
|
26615
|
-
|
|
26616
|
-
|
|
26617
|
-
|
|
26618
|
-
);
|
|
26619
|
-
if (!ctx2 || ctx2.role !== "personal" || ctx2.personaId !== entry.scope.personalId) {
|
|
26620
|
-
sendJson(res, 403, { code: "FORBIDDEN", message: "personal-scoped cap requires matching token" });
|
|
26621
|
-
return true;
|
|
26622
|
-
}
|
|
26623
|
-
}
|
|
26624
|
-
const outboxStore = deps.outboxStore;
|
|
26625
|
-
streamFile(res, entry.absPath, deps.logger, () => outboxStore.consume(capToken));
|
|
26658
|
+
if (url.pathname.startsWith("/files/") && req.method === "GET") {
|
|
26659
|
+
const secret = deps.getSignSecret?.();
|
|
26660
|
+
if (!secret) {
|
|
26661
|
+
sendJson(res, 501, { code: "NOT_IMPLEMENTED", message: "signed URL secret unavailable (noAuth?)" });
|
|
26662
|
+
return true;
|
|
26663
|
+
}
|
|
26664
|
+
const encodedPath = url.pathname.slice("/files".length);
|
|
26665
|
+
let absPath;
|
|
26666
|
+
try {
|
|
26667
|
+
absPath = decodeAbsPathFromUrl(encodedPath);
|
|
26668
|
+
} catch {
|
|
26669
|
+
sendJson(res, 400, { code: "MALFORMED", message: "invalid path encoding" });
|
|
26670
|
+
return true;
|
|
26671
|
+
}
|
|
26672
|
+
const e = url.searchParams.get("e");
|
|
26673
|
+
const s = url.searchParams.get("s") ?? "";
|
|
26674
|
+
const r = verifySignedUrl(secret, absPath, e, s);
|
|
26675
|
+
if (!r.ok) {
|
|
26676
|
+
const statusByCode = {
|
|
26677
|
+
BAD_SIG: 403,
|
|
26678
|
+
EXPIRED: 410,
|
|
26679
|
+
MALFORMED: 400
|
|
26680
|
+
};
|
|
26681
|
+
sendJson(res, statusByCode[r.code], { code: r.code, message: "signed URL invalid" });
|
|
26626
26682
|
return true;
|
|
26627
26683
|
}
|
|
26684
|
+
streamFile(res, r.absPath, deps.logger);
|
|
26685
|
+
return true;
|
|
26628
26686
|
}
|
|
26629
26687
|
const ctx = deps.authResolver.resolveFromHeader(
|
|
26630
26688
|
req.headers.authorization,
|
|
@@ -26694,10 +26752,6 @@ function createHttpRouter(deps) {
|
|
|
26694
26752
|
streamFile(res, absPath, deps.logger);
|
|
26695
26753
|
return true;
|
|
26696
26754
|
}
|
|
26697
|
-
if (/^\/persona\/[^/]+\/attachment-meta$/.test(url.pathname) && req.method === "GET") {
|
|
26698
|
-
sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "attachment-meta \u2014 PR 6" }));
|
|
26699
|
-
return true;
|
|
26700
|
-
}
|
|
26701
26755
|
sendJson(res, 404, { code: "NOT_FOUND", message: `no route for ${req.method} ${url.pathname}` });
|
|
26702
26756
|
return true;
|
|
26703
26757
|
};
|
|
@@ -26723,7 +26777,7 @@ function isContainedIn(abs, root) {
|
|
|
26723
26777
|
if (normalized === normalizedRoot) return true;
|
|
26724
26778
|
return normalized.startsWith(normalizedRoot + import_node_path16.default.sep);
|
|
26725
26779
|
}
|
|
26726
|
-
function streamFile(res, absPath, logger
|
|
26780
|
+
function streamFile(res, absPath, logger) {
|
|
26727
26781
|
let stat;
|
|
26728
26782
|
try {
|
|
26729
26783
|
stat = import_node_fs14.default.statSync(absPath);
|
|
@@ -26741,10 +26795,12 @@ function streamFile(res, absPath, logger, onComplete) {
|
|
|
26741
26795
|
return;
|
|
26742
26796
|
}
|
|
26743
26797
|
const mime = lookupMime(absPath);
|
|
26798
|
+
const basename = import_node_path16.default.basename(absPath);
|
|
26744
26799
|
res.writeHead(200, {
|
|
26745
26800
|
"Content-Type": mime,
|
|
26746
26801
|
"Content-Length": String(stat.size),
|
|
26747
|
-
|
|
26802
|
+
"Content-Disposition": `inline; filename*=UTF-8''${encodeURIComponent(basename)}`,
|
|
26803
|
+
// 防止浏览器把任意 mime 当 html 渲染
|
|
26748
26804
|
"X-Content-Type-Options": "nosniff"
|
|
26749
26805
|
});
|
|
26750
26806
|
const stream = import_node_fs14.default.createReadStream(absPath);
|
|
@@ -26752,228 +26808,14 @@ function streamFile(res, absPath, logger, onComplete) {
|
|
|
26752
26808
|
logger?.warn("streamFile read error", { absPath, err: err.message });
|
|
26753
26809
|
res.destroy();
|
|
26754
26810
|
});
|
|
26755
|
-
if (onComplete) {
|
|
26756
|
-
res.once("finish", onComplete);
|
|
26757
|
-
}
|
|
26758
26811
|
stream.pipe(res);
|
|
26759
26812
|
}
|
|
26760
26813
|
|
|
26761
|
-
// src/
|
|
26814
|
+
// src/discovery/state-file.ts
|
|
26762
26815
|
var import_node_fs15 = __toESM(require("fs"), 1);
|
|
26763
26816
|
var import_node_path17 = __toESM(require("path"), 1);
|
|
26764
|
-
var import_node_crypto5 = __toESM(require("crypto"), 1);
|
|
26765
|
-
init_protocol();
|
|
26766
|
-
var FILE_NAME = "outbox-caps.json";
|
|
26767
|
-
var OutboxStore = class {
|
|
26768
|
-
file;
|
|
26769
|
-
now;
|
|
26770
|
-
logger;
|
|
26771
|
-
cache = [];
|
|
26772
|
-
constructor(opts) {
|
|
26773
|
-
this.file = import_node_path17.default.join(opts.dataDir, FILE_NAME);
|
|
26774
|
-
this.now = opts.now ?? Date.now;
|
|
26775
|
-
this.logger = opts.logger;
|
|
26776
|
-
this.reload();
|
|
26777
|
-
}
|
|
26778
|
-
reload() {
|
|
26779
|
-
try {
|
|
26780
|
-
const raw = import_node_fs15.default.readFileSync(this.file, "utf8");
|
|
26781
|
-
const parsed = JSON.parse(raw);
|
|
26782
|
-
if (!Array.isArray(parsed)) {
|
|
26783
|
-
this.logger?.warn("OutboxStore.reload: outbox-caps.json is not an array; resetting", {
|
|
26784
|
-
file: this.file
|
|
26785
|
-
});
|
|
26786
|
-
this.cache = [];
|
|
26787
|
-
return;
|
|
26788
|
-
}
|
|
26789
|
-
const out = [];
|
|
26790
|
-
for (const item of parsed) {
|
|
26791
|
-
const r = OutboxCapEntrySchema.safeParse(item);
|
|
26792
|
-
if (r.success) out.push(r.data);
|
|
26793
|
-
}
|
|
26794
|
-
this.cache = out;
|
|
26795
|
-
} catch (err) {
|
|
26796
|
-
const code = err?.code;
|
|
26797
|
-
if (code !== "ENOENT") {
|
|
26798
|
-
this.logger?.warn("OutboxStore.reload failed; outbox-caps.json may be corrupt", {
|
|
26799
|
-
file: this.file,
|
|
26800
|
-
err: err.message
|
|
26801
|
-
});
|
|
26802
|
-
}
|
|
26803
|
-
this.cache = [];
|
|
26804
|
-
}
|
|
26805
|
-
}
|
|
26806
|
-
persist() {
|
|
26807
|
-
import_node_fs15.default.mkdirSync(import_node_path17.default.dirname(this.file), { recursive: true });
|
|
26808
|
-
const tmp = `${this.file}.tmp-${process.pid}-${Date.now()}`;
|
|
26809
|
-
import_node_fs15.default.writeFileSync(tmp, JSON.stringify(this.cache, null, 2), { mode: 384 });
|
|
26810
|
-
import_node_fs15.default.renameSync(tmp, this.file);
|
|
26811
|
-
}
|
|
26812
|
-
/** 列出当前缓存(含 revoked / 过期,UI Drawer 显灰;过滤靠调用方) */
|
|
26813
|
-
list() {
|
|
26814
|
-
return this.cache.slice();
|
|
26815
|
-
}
|
|
26816
|
-
/** 按 personaId / sessionId 过滤;为 outbox Drawer 服务 */
|
|
26817
|
-
listByPersona(personaId) {
|
|
26818
|
-
return this.cache.filter(
|
|
26819
|
-
(c) => c.scopeRef.kind === "persona" && c.scopeRef.personaId === personaId
|
|
26820
|
-
);
|
|
26821
|
-
}
|
|
26822
|
-
/**
|
|
26823
|
-
* Mint a new cap. capToken = 32B 随机 base64url(256-bit entropy),spec §11 #8 防剪贴板/微信
|
|
26824
|
-
* 截图泄露通过短码的暴力面。返回完整 entry 让 caller 拼 URL。
|
|
26825
|
-
*
|
|
26826
|
-
* @param ttlSeconds null = 永久;undefined = 默认 24h(spec §12)
|
|
26827
|
-
*/
|
|
26828
|
-
mint(input) {
|
|
26829
|
-
const ts = this.now();
|
|
26830
|
-
const ttl = input.ttlSeconds === null ? null : input.ttlSeconds ?? 24 * 3600;
|
|
26831
|
-
const entry = {
|
|
26832
|
-
capToken: import_node_crypto5.default.randomBytes(32).toString("base64url"),
|
|
26833
|
-
scopeRef: input.scopeRef,
|
|
26834
|
-
absPath: input.absPath,
|
|
26835
|
-
name: input.name,
|
|
26836
|
-
expiresAt: ttl === null ? null : ts + ttl * 1e3,
|
|
26837
|
-
oneShot: input.oneShot ?? false,
|
|
26838
|
-
scope: input.scope ?? { kind: "public" },
|
|
26839
|
-
hits: 0,
|
|
26840
|
-
createdAt: ts
|
|
26841
|
-
};
|
|
26842
|
-
this.cache.push(entry);
|
|
26843
|
-
this.persist();
|
|
26844
|
-
return entry;
|
|
26845
|
-
}
|
|
26846
|
-
/** Mark revoked;不删除条目(便于审计),上层 lookup 后返回 410 */
|
|
26847
|
-
revoke(capToken) {
|
|
26848
|
-
const idx = this.cache.findIndex((c) => c.capToken === capToken);
|
|
26849
|
-
if (idx < 0) return false;
|
|
26850
|
-
if (this.cache[idx].revoked) return false;
|
|
26851
|
-
this.cache[idx] = { ...this.cache[idx], revoked: true };
|
|
26852
|
-
this.persist();
|
|
26853
|
-
return true;
|
|
26854
|
-
}
|
|
26855
|
-
/**
|
|
26856
|
-
* HTTP 层用:根据 capToken 找到 entry 并判定能不能用。
|
|
26857
|
-
* 三种结果:
|
|
26858
|
-
* - { ok: true, entry } 可用,调用方流文件
|
|
26859
|
-
* - { ok: false, code: 'EXPIRED' | 'REVOKED' | 'NOT_FOUND' }
|
|
26860
|
-
*
|
|
26861
|
-
* 命中 + oneShot=true 时由调用方调 consume() 把 cache 中 hits 自增并立即 revoke
|
|
26862
|
-
* (consume 应当在 response 'finish' 后才触发,避免中途断流误算消费)。
|
|
26863
|
-
*/
|
|
26864
|
-
lookup(capToken) {
|
|
26865
|
-
const entry = this.cache.find((c) => c.capToken === capToken);
|
|
26866
|
-
if (!entry) return { ok: false, code: "NOT_FOUND" };
|
|
26867
|
-
if (entry.revoked) return { ok: false, code: "REVOKED" };
|
|
26868
|
-
if (entry.expiresAt !== null && this.now() > entry.expiresAt) {
|
|
26869
|
-
return { ok: false, code: "EXPIRED" };
|
|
26870
|
-
}
|
|
26871
|
-
return { ok: true, entry };
|
|
26872
|
-
}
|
|
26873
|
-
/** 命中后真正"消费"一次:hits++ + oneShot 时 revoke。daemon HTTP 层 stream 成功后再调 */
|
|
26874
|
-
consume(capToken) {
|
|
26875
|
-
const idx = this.cache.findIndex((c) => c.capToken === capToken);
|
|
26876
|
-
if (idx < 0) return;
|
|
26877
|
-
const prev = this.cache[idx];
|
|
26878
|
-
this.cache[idx] = {
|
|
26879
|
-
...prev,
|
|
26880
|
-
hits: prev.hits + 1,
|
|
26881
|
-
revoked: prev.oneShot ? true : prev.revoked
|
|
26882
|
-
};
|
|
26883
|
-
this.persist();
|
|
26884
|
-
}
|
|
26885
|
-
};
|
|
26886
|
-
|
|
26887
|
-
// src/attachment/mount.ts
|
|
26888
|
-
var import_node_fs16 = __toESM(require("fs"), 1);
|
|
26889
|
-
var import_node_path18 = __toESM(require("path"), 1);
|
|
26890
|
-
init_protocol();
|
|
26891
|
-
var MountStore = class {
|
|
26892
|
-
constructor(opts) {
|
|
26893
|
-
this.opts = opts;
|
|
26894
|
-
}
|
|
26895
|
-
opts;
|
|
26896
|
-
filePath(personaId) {
|
|
26897
|
-
return import_node_path18.default.join(this.opts.personaDirPath(personaId), ".clawd", "shared-files.json");
|
|
26898
|
-
}
|
|
26899
|
-
list(personaId) {
|
|
26900
|
-
try {
|
|
26901
|
-
const raw = import_node_fs16.default.readFileSync(this.filePath(personaId), "utf8");
|
|
26902
|
-
const parsed = JSON.parse(raw);
|
|
26903
|
-
if (!Array.isArray(parsed)) return [];
|
|
26904
|
-
const out = [];
|
|
26905
|
-
for (const item of parsed) {
|
|
26906
|
-
const r = MountEntrySchema.safeParse(item);
|
|
26907
|
-
if (r.success) out.push(r.data);
|
|
26908
|
-
}
|
|
26909
|
-
return out;
|
|
26910
|
-
} catch {
|
|
26911
|
-
return [];
|
|
26912
|
-
}
|
|
26913
|
-
}
|
|
26914
|
-
/**
|
|
26915
|
-
* Add a mount。在 personaDir 创建 link/copy + 写 manifest。冲突 basename 抛错(caller
|
|
26916
|
-
* 决定是覆盖还是改名)。
|
|
26917
|
-
*/
|
|
26918
|
-
add(personaId, input) {
|
|
26919
|
-
const personaDir = this.opts.personaDirPath(personaId);
|
|
26920
|
-
if (!import_node_fs16.default.existsSync(personaDir)) {
|
|
26921
|
-
throw new Error(`personaDir not found: ${personaDir}`);
|
|
26922
|
-
}
|
|
26923
|
-
const source = import_node_path18.default.resolve(input.absPath);
|
|
26924
|
-
if (!import_node_fs16.default.existsSync(source)) {
|
|
26925
|
-
throw new Error(`source path not found: ${source}`);
|
|
26926
|
-
}
|
|
26927
|
-
const basename = import_node_path18.default.basename(source);
|
|
26928
|
-
const dest = import_node_path18.default.join(personaDir, basename);
|
|
26929
|
-
if (import_node_fs16.default.existsSync(dest)) {
|
|
26930
|
-
throw new Error(`destination already exists: ${dest}`);
|
|
26931
|
-
}
|
|
26932
|
-
if (input.mode === "link") {
|
|
26933
|
-
import_node_fs16.default.symlinkSync(source, dest);
|
|
26934
|
-
} else {
|
|
26935
|
-
import_node_fs16.default.copyFileSync(source, dest);
|
|
26936
|
-
}
|
|
26937
|
-
const entry = {
|
|
26938
|
-
basename,
|
|
26939
|
-
absPath: source,
|
|
26940
|
-
mode: input.mode
|
|
26941
|
-
};
|
|
26942
|
-
const next = this.list(personaId).concat([entry]);
|
|
26943
|
-
this.writeManifest(personaId, next);
|
|
26944
|
-
return entry;
|
|
26945
|
-
}
|
|
26946
|
-
remove(personaId, basename) {
|
|
26947
|
-
const entries = this.list(personaId);
|
|
26948
|
-
const idx = entries.findIndex((e) => e.basename === basename);
|
|
26949
|
-
if (idx < 0) return false;
|
|
26950
|
-
const entry = entries[idx];
|
|
26951
|
-
const personaDir = this.opts.personaDirPath(personaId);
|
|
26952
|
-
const dest = import_node_path18.default.join(personaDir, basename);
|
|
26953
|
-
try {
|
|
26954
|
-
import_node_fs16.default.unlinkSync(dest);
|
|
26955
|
-
} catch {
|
|
26956
|
-
}
|
|
26957
|
-
const next = entries.slice();
|
|
26958
|
-
next.splice(idx, 1);
|
|
26959
|
-
this.writeManifest(personaId, next);
|
|
26960
|
-
void entry;
|
|
26961
|
-
return true;
|
|
26962
|
-
}
|
|
26963
|
-
writeManifest(personaId, entries) {
|
|
26964
|
-
const file = this.filePath(personaId);
|
|
26965
|
-
import_node_fs16.default.mkdirSync(import_node_path18.default.dirname(file), { recursive: true });
|
|
26966
|
-
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
26967
|
-
import_node_fs16.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
|
|
26968
|
-
import_node_fs16.default.renameSync(tmp, file);
|
|
26969
|
-
}
|
|
26970
|
-
};
|
|
26971
|
-
|
|
26972
|
-
// src/discovery/state-file.ts
|
|
26973
|
-
var import_node_fs17 = __toESM(require("fs"), 1);
|
|
26974
|
-
var import_node_path19 = __toESM(require("path"), 1);
|
|
26975
26817
|
function defaultStateFilePath(dataDir) {
|
|
26976
|
-
return
|
|
26818
|
+
return import_node_path17.default.join(dataDir, "state.json");
|
|
26977
26819
|
}
|
|
26978
26820
|
function isPidAlive(pid) {
|
|
26979
26821
|
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
@@ -26995,7 +26837,7 @@ var StateFileManager = class {
|
|
|
26995
26837
|
}
|
|
26996
26838
|
read() {
|
|
26997
26839
|
try {
|
|
26998
|
-
const raw =
|
|
26840
|
+
const raw = import_node_fs15.default.readFileSync(this.file, "utf8");
|
|
26999
26841
|
const parsed = JSON.parse(raw);
|
|
27000
26842
|
return parsed;
|
|
27001
26843
|
} catch {
|
|
@@ -27009,34 +26851,34 @@ var StateFileManager = class {
|
|
|
27009
26851
|
return { status: "stale", existing };
|
|
27010
26852
|
}
|
|
27011
26853
|
write(state) {
|
|
27012
|
-
|
|
26854
|
+
import_node_fs15.default.mkdirSync(import_node_path17.default.dirname(this.file), { recursive: true });
|
|
27013
26855
|
const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
|
|
27014
|
-
|
|
27015
|
-
|
|
26856
|
+
import_node_fs15.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
|
|
26857
|
+
import_node_fs15.default.renameSync(tmp, this.file);
|
|
27016
26858
|
if (process.platform !== "win32") {
|
|
27017
26859
|
try {
|
|
27018
|
-
|
|
26860
|
+
import_node_fs15.default.chmodSync(this.file, 384);
|
|
27019
26861
|
} catch {
|
|
27020
26862
|
}
|
|
27021
26863
|
}
|
|
27022
26864
|
}
|
|
27023
26865
|
delete() {
|
|
27024
26866
|
try {
|
|
27025
|
-
|
|
26867
|
+
import_node_fs15.default.unlinkSync(this.file);
|
|
27026
26868
|
} catch {
|
|
27027
26869
|
}
|
|
27028
26870
|
}
|
|
27029
26871
|
};
|
|
27030
26872
|
|
|
27031
26873
|
// src/tunnel/tunnel-manager.ts
|
|
27032
|
-
var
|
|
27033
|
-
var
|
|
26874
|
+
var import_node_fs19 = __toESM(require("fs"), 1);
|
|
26875
|
+
var import_node_path21 = __toESM(require("path"), 1);
|
|
27034
26876
|
var import_node_crypto6 = __toESM(require("crypto"), 1);
|
|
27035
26877
|
var import_node_child_process5 = require("child_process");
|
|
27036
26878
|
|
|
27037
26879
|
// src/tunnel/tunnel-store.ts
|
|
27038
|
-
var
|
|
27039
|
-
var
|
|
26880
|
+
var import_node_fs16 = __toESM(require("fs"), 1);
|
|
26881
|
+
var import_node_path18 = __toESM(require("path"), 1);
|
|
27040
26882
|
var TunnelStore = class {
|
|
27041
26883
|
constructor(filePath) {
|
|
27042
26884
|
this.filePath = filePath;
|
|
@@ -27044,7 +26886,7 @@ var TunnelStore = class {
|
|
|
27044
26886
|
filePath;
|
|
27045
26887
|
async get() {
|
|
27046
26888
|
try {
|
|
27047
|
-
const raw = await
|
|
26889
|
+
const raw = await import_node_fs16.default.promises.readFile(this.filePath, "utf8");
|
|
27048
26890
|
const obj = JSON.parse(raw);
|
|
27049
26891
|
if (!isPersistedTunnel(obj)) return null;
|
|
27050
26892
|
return obj;
|
|
@@ -27055,22 +26897,22 @@ var TunnelStore = class {
|
|
|
27055
26897
|
}
|
|
27056
26898
|
}
|
|
27057
26899
|
async set(v2) {
|
|
27058
|
-
const dir =
|
|
27059
|
-
await
|
|
26900
|
+
const dir = import_node_path18.default.dirname(this.filePath);
|
|
26901
|
+
await import_node_fs16.default.promises.mkdir(dir, { recursive: true });
|
|
27060
26902
|
const data = JSON.stringify(v2, null, 2);
|
|
27061
26903
|
const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
|
|
27062
|
-
await
|
|
26904
|
+
await import_node_fs16.default.promises.writeFile(tmp, data, { mode: 384 });
|
|
27063
26905
|
if (process.platform !== "win32") {
|
|
27064
26906
|
try {
|
|
27065
|
-
await
|
|
26907
|
+
await import_node_fs16.default.promises.chmod(tmp, 384);
|
|
27066
26908
|
} catch {
|
|
27067
26909
|
}
|
|
27068
26910
|
}
|
|
27069
|
-
await
|
|
26911
|
+
await import_node_fs16.default.promises.rename(tmp, this.filePath);
|
|
27070
26912
|
}
|
|
27071
26913
|
async clear() {
|
|
27072
26914
|
try {
|
|
27073
|
-
await
|
|
26915
|
+
await import_node_fs16.default.promises.unlink(this.filePath);
|
|
27074
26916
|
} catch (err) {
|
|
27075
26917
|
const code = err?.code;
|
|
27076
26918
|
if (code !== "ENOENT") throw err;
|
|
@@ -27165,9 +27007,9 @@ function escape(v2) {
|
|
|
27165
27007
|
}
|
|
27166
27008
|
|
|
27167
27009
|
// src/tunnel/frpc-binary.ts
|
|
27168
|
-
var
|
|
27010
|
+
var import_node_fs17 = __toESM(require("fs"), 1);
|
|
27169
27011
|
var import_node_os9 = __toESM(require("os"), 1);
|
|
27170
|
-
var
|
|
27012
|
+
var import_node_path19 = __toESM(require("path"), 1);
|
|
27171
27013
|
var import_node_child_process3 = require("child_process");
|
|
27172
27014
|
var import_node_stream2 = require("stream");
|
|
27173
27015
|
var import_promises = require("stream/promises");
|
|
@@ -27199,20 +27041,20 @@ function frpcDownloadUrl(version2, p2) {
|
|
|
27199
27041
|
}
|
|
27200
27042
|
async function ensureFrpcBinary(opts) {
|
|
27201
27043
|
if (opts.override) {
|
|
27202
|
-
if (!
|
|
27044
|
+
if (!import_node_fs17.default.existsSync(opts.override)) {
|
|
27203
27045
|
throw new Error(`frpc binary not found at override path: ${opts.override}`);
|
|
27204
27046
|
}
|
|
27205
27047
|
return opts.override;
|
|
27206
27048
|
}
|
|
27207
27049
|
const version2 = opts.version ?? FRPC_VERSION;
|
|
27208
27050
|
const platform = opts.platform ?? detectPlatform();
|
|
27209
|
-
const binDir =
|
|
27210
|
-
|
|
27051
|
+
const binDir = import_node_path19.default.join(opts.dataDir, "bin");
|
|
27052
|
+
import_node_fs17.default.mkdirSync(binDir, { recursive: true });
|
|
27211
27053
|
cleanupStaleArtifacts(binDir);
|
|
27212
|
-
const stableBin =
|
|
27213
|
-
if (
|
|
27054
|
+
const stableBin = import_node_path19.default.join(binDir, "frpc");
|
|
27055
|
+
if (import_node_fs17.default.existsSync(stableBin)) return stableBin;
|
|
27214
27056
|
const partialBin = `${stableBin}.partial`;
|
|
27215
|
-
const tarballPath =
|
|
27057
|
+
const tarballPath = import_node_path19.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
|
|
27216
27058
|
try {
|
|
27217
27059
|
const url = frpcDownloadUrl(version2, platform);
|
|
27218
27060
|
await downloadToFile(url, tarballPath, opts.fetchImpl);
|
|
@@ -27221,8 +27063,8 @@ async function ensureFrpcBinary(opts) {
|
|
|
27221
27063
|
} else {
|
|
27222
27064
|
await extractFrpcFromTarball(tarballPath, binDir, version2, platform, partialBin);
|
|
27223
27065
|
}
|
|
27224
|
-
|
|
27225
|
-
|
|
27066
|
+
import_node_fs17.default.chmodSync(partialBin, 493);
|
|
27067
|
+
import_node_fs17.default.renameSync(partialBin, stableBin);
|
|
27226
27068
|
} finally {
|
|
27227
27069
|
safeUnlink(tarballPath);
|
|
27228
27070
|
safeUnlink(partialBin);
|
|
@@ -27232,15 +27074,15 @@ async function ensureFrpcBinary(opts) {
|
|
|
27232
27074
|
function cleanupStaleArtifacts(binDir) {
|
|
27233
27075
|
let entries;
|
|
27234
27076
|
try {
|
|
27235
|
-
entries =
|
|
27077
|
+
entries = import_node_fs17.default.readdirSync(binDir);
|
|
27236
27078
|
} catch {
|
|
27237
27079
|
return;
|
|
27238
27080
|
}
|
|
27239
27081
|
for (const name of entries) {
|
|
27240
27082
|
if (name.endsWith(".partial") || name.startsWith("extract-")) {
|
|
27241
|
-
const full =
|
|
27083
|
+
const full = import_node_path19.default.join(binDir, name);
|
|
27242
27084
|
try {
|
|
27243
|
-
|
|
27085
|
+
import_node_fs17.default.rmSync(full, { recursive: true, force: true });
|
|
27244
27086
|
} catch {
|
|
27245
27087
|
}
|
|
27246
27088
|
}
|
|
@@ -27248,7 +27090,7 @@ function cleanupStaleArtifacts(binDir) {
|
|
|
27248
27090
|
}
|
|
27249
27091
|
function safeUnlink(p2) {
|
|
27250
27092
|
try {
|
|
27251
|
-
|
|
27093
|
+
import_node_fs17.default.unlinkSync(p2);
|
|
27252
27094
|
} catch {
|
|
27253
27095
|
}
|
|
27254
27096
|
}
|
|
@@ -27259,13 +27101,13 @@ async function downloadToFile(url, dest, fetchImpl) {
|
|
|
27259
27101
|
if (!res.ok || !res.body) {
|
|
27260
27102
|
throw new Error(`download failed: ${res.status} ${res.statusText}`);
|
|
27261
27103
|
}
|
|
27262
|
-
const out =
|
|
27104
|
+
const out = import_node_fs17.default.createWriteStream(dest);
|
|
27263
27105
|
const nodeStream = import_node_stream2.Readable.fromWeb(res.body);
|
|
27264
27106
|
await (0, import_promises.pipeline)(nodeStream, out);
|
|
27265
27107
|
}
|
|
27266
27108
|
async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
|
|
27267
|
-
const work =
|
|
27268
|
-
|
|
27109
|
+
const work = import_node_path19.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
|
|
27110
|
+
import_node_fs17.default.mkdirSync(work, { recursive: true });
|
|
27269
27111
|
try {
|
|
27270
27112
|
await new Promise((resolve2, reject) => {
|
|
27271
27113
|
const proc = (0, import_node_child_process3.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
|
|
@@ -27273,32 +27115,32 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
|
|
|
27273
27115
|
proc.on("exit", (code) => code === 0 ? resolve2() : reject(new Error(`tar exited ${code}`)));
|
|
27274
27116
|
});
|
|
27275
27117
|
const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
|
|
27276
|
-
const src =
|
|
27277
|
-
if (!
|
|
27118
|
+
const src = import_node_path19.default.join(work, dirName, "frpc");
|
|
27119
|
+
if (!import_node_fs17.default.existsSync(src)) {
|
|
27278
27120
|
throw new Error(`frpc not found inside tarball at ${src}`);
|
|
27279
27121
|
}
|
|
27280
|
-
|
|
27122
|
+
import_node_fs17.default.copyFileSync(src, destBin);
|
|
27281
27123
|
} finally {
|
|
27282
|
-
|
|
27124
|
+
import_node_fs17.default.rmSync(work, { recursive: true, force: true });
|
|
27283
27125
|
}
|
|
27284
27126
|
}
|
|
27285
27127
|
|
|
27286
27128
|
// src/tunnel/frpc-process.ts
|
|
27287
|
-
var
|
|
27288
|
-
var
|
|
27129
|
+
var import_node_fs18 = __toESM(require("fs"), 1);
|
|
27130
|
+
var import_node_path20 = __toESM(require("path"), 1);
|
|
27289
27131
|
var import_node_child_process4 = require("child_process");
|
|
27290
27132
|
function frpcPidFilePath(dataDir) {
|
|
27291
|
-
return
|
|
27133
|
+
return import_node_path20.default.join(dataDir, "frpc.pid");
|
|
27292
27134
|
}
|
|
27293
27135
|
function writeFrpcPid(dataDir, pid) {
|
|
27294
27136
|
try {
|
|
27295
|
-
|
|
27137
|
+
import_node_fs18.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
|
|
27296
27138
|
} catch {
|
|
27297
27139
|
}
|
|
27298
27140
|
}
|
|
27299
27141
|
function clearFrpcPid(dataDir) {
|
|
27300
27142
|
try {
|
|
27301
|
-
|
|
27143
|
+
import_node_fs18.default.unlinkSync(frpcPidFilePath(dataDir));
|
|
27302
27144
|
} catch {
|
|
27303
27145
|
}
|
|
27304
27146
|
}
|
|
@@ -27314,7 +27156,7 @@ function defaultIsPidAlive(pid) {
|
|
|
27314
27156
|
}
|
|
27315
27157
|
function defaultReadPidFile(file) {
|
|
27316
27158
|
try {
|
|
27317
|
-
return
|
|
27159
|
+
return import_node_fs18.default.readFileSync(file, "utf8");
|
|
27318
27160
|
} catch {
|
|
27319
27161
|
return null;
|
|
27320
27162
|
}
|
|
@@ -27330,7 +27172,7 @@ function defaultSleep(ms) {
|
|
|
27330
27172
|
}
|
|
27331
27173
|
async function killStaleFrpc(deps) {
|
|
27332
27174
|
const pidFile = frpcPidFilePath(deps.dataDir);
|
|
27333
|
-
const tomlPath =
|
|
27175
|
+
const tomlPath = import_node_path20.default.join(deps.dataDir, "frpc.toml");
|
|
27334
27176
|
const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
|
|
27335
27177
|
const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
|
|
27336
27178
|
const killPid = deps.killPidImpl ?? defaultKillPid;
|
|
@@ -27354,7 +27196,7 @@ async function killStaleFrpc(deps) {
|
|
|
27354
27196
|
}
|
|
27355
27197
|
if (victims.size === 0) {
|
|
27356
27198
|
try {
|
|
27357
|
-
|
|
27199
|
+
import_node_fs18.default.unlinkSync(pidFile);
|
|
27358
27200
|
} catch {
|
|
27359
27201
|
}
|
|
27360
27202
|
return;
|
|
@@ -27365,7 +27207,7 @@ async function killStaleFrpc(deps) {
|
|
|
27365
27207
|
}
|
|
27366
27208
|
await sleep(deps.reapWaitMs ?? 300);
|
|
27367
27209
|
try {
|
|
27368
|
-
|
|
27210
|
+
import_node_fs18.default.unlinkSync(pidFile);
|
|
27369
27211
|
} catch {
|
|
27370
27212
|
}
|
|
27371
27213
|
}
|
|
@@ -27402,7 +27244,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
|
27402
27244
|
var TunnelManager = class {
|
|
27403
27245
|
constructor(deps) {
|
|
27404
27246
|
this.deps = deps;
|
|
27405
|
-
this.store = deps.store ?? new TunnelStore(
|
|
27247
|
+
this.store = deps.store ?? new TunnelStore(import_node_path21.default.join(deps.dataDir, "tunnel.json"));
|
|
27406
27248
|
this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
|
|
27407
27249
|
this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
|
|
27408
27250
|
}
|
|
@@ -27529,7 +27371,7 @@ var TunnelManager = class {
|
|
|
27529
27371
|
dataDir: this.deps.dataDir,
|
|
27530
27372
|
override: this.deps.frpcBinaryOverride ?? void 0
|
|
27531
27373
|
});
|
|
27532
|
-
const tomlPath =
|
|
27374
|
+
const tomlPath = import_node_path21.default.join(this.deps.dataDir, "frpc.toml");
|
|
27533
27375
|
const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto6.default.randomBytes(3).toString("hex")}`;
|
|
27534
27376
|
const toml = buildFrpcToml({
|
|
27535
27377
|
serverAddr: t.frpsHost,
|
|
@@ -27540,12 +27382,12 @@ var TunnelManager = class {
|
|
|
27540
27382
|
localPort,
|
|
27541
27383
|
logLevel: "info"
|
|
27542
27384
|
});
|
|
27543
|
-
await
|
|
27385
|
+
await import_node_fs19.default.promises.writeFile(tomlPath, toml, { mode: 384 });
|
|
27544
27386
|
const proc = (this.deps.spawnImpl ?? import_node_child_process5.spawn)(frpcBin, ["-c", tomlPath], {
|
|
27545
27387
|
stdio: ["ignore", "pipe", "pipe"]
|
|
27546
27388
|
});
|
|
27547
|
-
const logFilePath =
|
|
27548
|
-
const logStream =
|
|
27389
|
+
const logFilePath = import_node_path21.default.join(this.deps.dataDir, "frpc.log");
|
|
27390
|
+
const logStream = import_node_fs19.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
|
|
27549
27391
|
logStream.on("error", () => {
|
|
27550
27392
|
});
|
|
27551
27393
|
const tee = (chunk) => {
|
|
@@ -27638,12 +27480,12 @@ function deriveStableDeviceKey(opts = {}) {
|
|
|
27638
27480
|
}
|
|
27639
27481
|
|
|
27640
27482
|
// src/auth-store.ts
|
|
27641
|
-
var
|
|
27642
|
-
var
|
|
27483
|
+
var import_node_fs20 = __toESM(require("fs"), 1);
|
|
27484
|
+
var import_node_path22 = __toESM(require("path"), 1);
|
|
27643
27485
|
var import_node_crypto8 = __toESM(require("crypto"), 1);
|
|
27644
27486
|
var AUTH_FILE_NAME = "auth.json";
|
|
27645
27487
|
function authFilePath(dataDir) {
|
|
27646
|
-
return
|
|
27488
|
+
return import_node_path22.default.join(dataDir, AUTH_FILE_NAME);
|
|
27647
27489
|
}
|
|
27648
27490
|
function loadOrCreateAuthToken(opts) {
|
|
27649
27491
|
const file = authFilePath(opts.dataDir);
|
|
@@ -27659,7 +27501,7 @@ function defaultGenerate() {
|
|
|
27659
27501
|
}
|
|
27660
27502
|
function readAuthFile(file) {
|
|
27661
27503
|
try {
|
|
27662
|
-
const raw =
|
|
27504
|
+
const raw = import_node_fs20.default.readFileSync(file, "utf8");
|
|
27663
27505
|
const parsed = JSON.parse(raw);
|
|
27664
27506
|
if (typeof parsed?.token === "string" && parsed.token.length > 0) {
|
|
27665
27507
|
return {
|
|
@@ -27675,25 +27517,25 @@ function readAuthFile(file) {
|
|
|
27675
27517
|
}
|
|
27676
27518
|
}
|
|
27677
27519
|
function writeAuthFile(file, content) {
|
|
27678
|
-
|
|
27679
|
-
|
|
27520
|
+
import_node_fs20.default.mkdirSync(import_node_path22.default.dirname(file), { recursive: true });
|
|
27521
|
+
import_node_fs20.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
|
|
27680
27522
|
try {
|
|
27681
|
-
|
|
27523
|
+
import_node_fs20.default.chmodSync(file, 384);
|
|
27682
27524
|
} catch {
|
|
27683
27525
|
}
|
|
27684
27526
|
}
|
|
27685
27527
|
|
|
27686
27528
|
// src/owner-profile.ts
|
|
27687
|
-
var
|
|
27529
|
+
var import_node_fs21 = __toESM(require("fs"), 1);
|
|
27688
27530
|
var import_node_os11 = __toESM(require("os"), 1);
|
|
27689
|
-
var
|
|
27531
|
+
var import_node_path23 = __toESM(require("path"), 1);
|
|
27690
27532
|
var PROFILE_FILENAME = "profile.json";
|
|
27691
27533
|
function loadOwnerDisplayName(dataDir) {
|
|
27692
27534
|
const fallback = import_node_os11.default.userInfo().username;
|
|
27693
|
-
const profilePath =
|
|
27535
|
+
const profilePath = import_node_path23.default.join(dataDir, PROFILE_FILENAME);
|
|
27694
27536
|
let raw;
|
|
27695
27537
|
try {
|
|
27696
|
-
raw =
|
|
27538
|
+
raw = import_node_fs21.default.readFileSync(profilePath, "utf8");
|
|
27697
27539
|
} catch {
|
|
27698
27540
|
return fallback;
|
|
27699
27541
|
}
|
|
@@ -27722,12 +27564,12 @@ init_protocol();
|
|
|
27722
27564
|
init_protocol();
|
|
27723
27565
|
|
|
27724
27566
|
// src/session/fork.ts
|
|
27725
|
-
var
|
|
27567
|
+
var import_node_fs22 = __toESM(require("fs"), 1);
|
|
27726
27568
|
var import_node_os12 = __toESM(require("os"), 1);
|
|
27727
|
-
var
|
|
27569
|
+
var import_node_path24 = __toESM(require("path"), 1);
|
|
27728
27570
|
init_claude_history();
|
|
27729
27571
|
function readJsonlEntries(file) {
|
|
27730
|
-
const raw =
|
|
27572
|
+
const raw = import_node_fs22.default.readFileSync(file, "utf8");
|
|
27731
27573
|
const out = [];
|
|
27732
27574
|
for (const line of raw.split("\n")) {
|
|
27733
27575
|
const t = line.trim();
|
|
@@ -27740,10 +27582,10 @@ function readJsonlEntries(file) {
|
|
|
27740
27582
|
return out;
|
|
27741
27583
|
}
|
|
27742
27584
|
function forkSession(input) {
|
|
27743
|
-
const baseDir = input.baseDir ??
|
|
27744
|
-
const projectDir =
|
|
27745
|
-
const sourceFile =
|
|
27746
|
-
if (!
|
|
27585
|
+
const baseDir = input.baseDir ?? import_node_path24.default.join(import_node_os12.default.homedir(), ".claude");
|
|
27586
|
+
const projectDir = import_node_path24.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
|
|
27587
|
+
const sourceFile = import_node_path24.default.join(projectDir, `${input.toolSessionId}.jsonl`);
|
|
27588
|
+
if (!import_node_fs22.default.existsSync(sourceFile)) {
|
|
27747
27589
|
throw new Error(`fork: source transcript not found: ${sourceFile}`);
|
|
27748
27590
|
}
|
|
27749
27591
|
const entries = readJsonlEntries(sourceFile);
|
|
@@ -27773,9 +27615,9 @@ function forkSession(input) {
|
|
|
27773
27615
|
}
|
|
27774
27616
|
forkedLines.push(JSON.stringify(forked));
|
|
27775
27617
|
}
|
|
27776
|
-
const forkedFilePath =
|
|
27777
|
-
|
|
27778
|
-
|
|
27618
|
+
const forkedFilePath = import_node_path24.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
|
|
27619
|
+
import_node_fs22.default.mkdirSync(projectDir, { recursive: true });
|
|
27620
|
+
import_node_fs22.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
|
|
27779
27621
|
return { forkedToolSessionId, forkedFilePath };
|
|
27780
27622
|
}
|
|
27781
27623
|
|
|
@@ -28096,9 +27938,9 @@ init_protocol();
|
|
|
28096
27938
|
|
|
28097
27939
|
// src/workspace/git.ts
|
|
28098
27940
|
var import_node_child_process6 = require("child_process");
|
|
28099
|
-
var
|
|
27941
|
+
var import_node_fs23 = __toESM(require("fs"), 1);
|
|
28100
27942
|
var import_node_os13 = __toESM(require("os"), 1);
|
|
28101
|
-
var
|
|
27943
|
+
var import_node_path25 = __toESM(require("path"), 1);
|
|
28102
27944
|
var import_node_util = require("util");
|
|
28103
27945
|
var pexec = (0, import_node_util.promisify)(import_node_child_process6.execFile);
|
|
28104
27946
|
function formatChildProcessError(err) {
|
|
@@ -28113,9 +27955,9 @@ function formatChildProcessError(err) {
|
|
|
28113
27955
|
return e.message ?? "unknown error";
|
|
28114
27956
|
}
|
|
28115
27957
|
function normalizePath(p2) {
|
|
28116
|
-
const resolved =
|
|
27958
|
+
const resolved = import_node_path25.default.resolve(p2);
|
|
28117
27959
|
try {
|
|
28118
|
-
return
|
|
27960
|
+
return import_node_fs23.default.realpathSync(resolved);
|
|
28119
27961
|
} catch {
|
|
28120
27962
|
return resolved;
|
|
28121
27963
|
}
|
|
@@ -28216,13 +28058,13 @@ function flattenToDirName(branch) {
|
|
|
28216
28058
|
}
|
|
28217
28059
|
function encodeClaudeProjectDir(absPath) {
|
|
28218
28060
|
if (!absPath || typeof absPath !== "string") return "";
|
|
28219
|
-
let canonical =
|
|
28061
|
+
let canonical = import_node_path25.default.resolve(absPath);
|
|
28220
28062
|
try {
|
|
28221
|
-
canonical =
|
|
28063
|
+
canonical = import_node_fs23.default.realpathSync(canonical);
|
|
28222
28064
|
} catch {
|
|
28223
28065
|
try {
|
|
28224
|
-
const parent =
|
|
28225
|
-
canonical =
|
|
28066
|
+
const parent = import_node_fs23.default.realpathSync(import_node_path25.default.dirname(canonical));
|
|
28067
|
+
canonical = import_node_path25.default.join(parent, import_node_path25.default.basename(canonical));
|
|
28226
28068
|
} catch {
|
|
28227
28069
|
}
|
|
28228
28070
|
}
|
|
@@ -28246,11 +28088,11 @@ async function createWorktree(input) {
|
|
|
28246
28088
|
if (!isGitRoot) {
|
|
28247
28089
|
throw new Error(`\u76EE\u5F55 ${cwd} \u4E0D\u662F git repo \u6839`);
|
|
28248
28090
|
}
|
|
28249
|
-
const parent =
|
|
28250
|
-
if (parent === "/" || parent ===
|
|
28091
|
+
const parent = import_node_path25.default.dirname(import_node_path25.default.resolve(cwd));
|
|
28092
|
+
if (parent === "/" || parent === import_node_path25.default.resolve(cwd)) {
|
|
28251
28093
|
throw new Error("repo \u5728\u78C1\u76D8\u6839\u76EE\u5F55\uFF0C\u65E0\u6CD5\u5728\u540C\u7EA7\u521B\u5EFA worktree");
|
|
28252
28094
|
}
|
|
28253
|
-
const worktreeRoot =
|
|
28095
|
+
const worktreeRoot = import_node_path25.default.join(parent, dirName);
|
|
28254
28096
|
try {
|
|
28255
28097
|
await pexec("git", ["-C", cwd, "fetch", "origin", baseBranch, "--no-tags"], {
|
|
28256
28098
|
timeout: 3e4
|
|
@@ -28269,7 +28111,7 @@ async function createWorktree(input) {
|
|
|
28269
28111
|
const msg = err.message;
|
|
28270
28112
|
if (msg.startsWith("\u5206\u652F ")) throw err;
|
|
28271
28113
|
}
|
|
28272
|
-
if (
|
|
28114
|
+
if (import_node_fs23.default.existsSync(worktreeRoot)) {
|
|
28273
28115
|
throw new Error(`\u76EE\u5F55 ${worktreeRoot} \u5DF2\u5B58\u5728\uFF0C\u8BF7\u6362\u4E00\u4E2A label \u6216\u6E05\u7406\u540E\u91CD\u8BD5`);
|
|
28274
28116
|
}
|
|
28275
28117
|
try {
|
|
@@ -28297,8 +28139,8 @@ async function removeWorktree(input) {
|
|
|
28297
28139
|
);
|
|
28298
28140
|
const gitCommonDir = stdout.trim();
|
|
28299
28141
|
if (!gitCommonDir) throw new Error("empty git-common-dir");
|
|
28300
|
-
const absGitCommon =
|
|
28301
|
-
repoRoot =
|
|
28142
|
+
const absGitCommon = import_node_path25.default.isAbsolute(gitCommonDir) ? gitCommonDir : import_node_path25.default.resolve(worktreeRoot, gitCommonDir);
|
|
28143
|
+
repoRoot = import_node_path25.default.dirname(absGitCommon);
|
|
28302
28144
|
} catch {
|
|
28303
28145
|
repoRoot = null;
|
|
28304
28146
|
}
|
|
@@ -28310,7 +28152,7 @@ async function removeWorktree(input) {
|
|
|
28310
28152
|
} catch (err) {
|
|
28311
28153
|
const stderr = err.stderr ?? "";
|
|
28312
28154
|
const lower = stderr.toLowerCase();
|
|
28313
|
-
const vanished = lower.includes("not a working tree") || lower.includes("is not a working tree") || !
|
|
28155
|
+
const vanished = lower.includes("not a working tree") || lower.includes("is not a working tree") || !import_node_fs23.default.existsSync(worktreeRoot);
|
|
28314
28156
|
if (!vanished) {
|
|
28315
28157
|
throw new Error(`\u6E05\u7406 worktree \u5931\u8D25\uFF1A${formatChildProcessError(err)}`);
|
|
28316
28158
|
}
|
|
@@ -28329,10 +28171,10 @@ async function removeWorktree(input) {
|
|
|
28329
28171
|
try {
|
|
28330
28172
|
const encoded = encodeClaudeProjectDir(worktreeRoot);
|
|
28331
28173
|
if (encoded) {
|
|
28332
|
-
const projectsRoot =
|
|
28333
|
-
const target =
|
|
28334
|
-
if (target.startsWith(projectsRoot +
|
|
28335
|
-
|
|
28174
|
+
const projectsRoot = import_node_path25.default.join(import_node_os13.default.homedir(), ".claude", "projects");
|
|
28175
|
+
const target = import_node_path25.default.resolve(projectsRoot, encoded);
|
|
28176
|
+
if (target.startsWith(projectsRoot + import_node_path25.default.sep) && target !== projectsRoot) {
|
|
28177
|
+
import_node_fs23.default.rmSync(target, { recursive: true, force: true });
|
|
28336
28178
|
}
|
|
28337
28179
|
}
|
|
28338
28180
|
} catch {
|
|
@@ -28554,115 +28396,39 @@ function buildPersonaHandlers(deps) {
|
|
|
28554
28396
|
// src/handlers/attachment.ts
|
|
28555
28397
|
init_protocol();
|
|
28556
28398
|
init_protocol();
|
|
28399
|
+
var DEFAULT_TTL_SECONDS = 24 * 3600;
|
|
28557
28400
|
function buildAttachmentHandlers(deps) {
|
|
28558
|
-
const
|
|
28559
|
-
const parsed =
|
|
28401
|
+
const signUrl = async (frame) => {
|
|
28402
|
+
const parsed = AttachmentSignUrlArgs.safeParse(frame);
|
|
28560
28403
|
if (!parsed.success) {
|
|
28561
28404
|
throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, parsed.error.message);
|
|
28562
28405
|
}
|
|
28563
28406
|
const args = parsed.data;
|
|
28564
|
-
|
|
28407
|
+
const secret = deps.getSignSecret();
|
|
28408
|
+
if (!secret) {
|
|
28565
28409
|
throw new ClawdError(
|
|
28566
|
-
ERROR_CODES.
|
|
28567
|
-
"
|
|
28410
|
+
ERROR_CODES.METHOD_NOT_IMPLEMENTED,
|
|
28411
|
+
"signUrl requires an owner token (daemon noAuth mode disables share URLs)"
|
|
28568
28412
|
);
|
|
28569
28413
|
}
|
|
28570
|
-
const scopeRef = deps.getPersonaScopeForRequest(args);
|
|
28571
|
-
if (!scopeRef) {
|
|
28572
|
-
throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, "invalid scope");
|
|
28573
|
-
}
|
|
28574
|
-
const name = args.absPath.split("/").pop() || args.absPath;
|
|
28575
|
-
const entry = deps.outboxStore.mint({
|
|
28576
|
-
scopeRef,
|
|
28577
|
-
absPath: args.absPath,
|
|
28578
|
-
name,
|
|
28579
|
-
ttlSeconds: args.ttlSeconds,
|
|
28580
|
-
oneShot: args.oneShot,
|
|
28581
|
-
scope: args.scope
|
|
28582
|
-
});
|
|
28583
28414
|
const httpBaseUrl = deps.getHttpBaseUrl();
|
|
28584
|
-
|
|
28585
|
-
|
|
28415
|
+
if (!httpBaseUrl) {
|
|
28416
|
+
throw new ClawdError(
|
|
28417
|
+
ERROR_CODES.METHOD_NOT_IMPLEMENTED,
|
|
28418
|
+
"httpBaseUrl unavailable (daemon HTTP not ready)"
|
|
28419
|
+
);
|
|
28420
|
+
}
|
|
28421
|
+
const ttl = args.ttlSeconds === null ? null : args.ttlSeconds ?? DEFAULT_TTL_SECONDS;
|
|
28422
|
+
const parts = signUrlParts(secret, args.absPath, ttl);
|
|
28423
|
+
const url = buildSignedFileUrl(httpBaseUrl, parts);
|
|
28586
28424
|
return {
|
|
28587
28425
|
response: {
|
|
28588
|
-
type: "attachment.
|
|
28589
|
-
capToken: entry.capToken,
|
|
28426
|
+
type: "attachment.signUrl",
|
|
28590
28427
|
url,
|
|
28591
|
-
expiresAt:
|
|
28428
|
+
expiresAt: parts.e === null ? null : parts.e * 1e3
|
|
28592
28429
|
}
|
|
28593
28430
|
};
|
|
28594
28431
|
};
|
|
28595
|
-
const outboxRevoke = async (frame) => {
|
|
28596
|
-
const parsed = AttachmentOutboxRevokeArgs.safeParse(frame);
|
|
28597
|
-
if (!parsed.success) {
|
|
28598
|
-
throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, parsed.error.message);
|
|
28599
|
-
}
|
|
28600
|
-
const ok = deps.outboxStore.revoke(parsed.data.capToken);
|
|
28601
|
-
if (!ok) {
|
|
28602
|
-
throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, `capToken not found / already revoked`);
|
|
28603
|
-
}
|
|
28604
|
-
return { response: { type: "attachment.outboxRevoke", revoked: true } };
|
|
28605
|
-
};
|
|
28606
|
-
const outboxList = async (frame) => {
|
|
28607
|
-
const parsed = AttachmentOutboxListArgs.safeParse(frame);
|
|
28608
|
-
if (!parsed.success) {
|
|
28609
|
-
throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, parsed.error.message);
|
|
28610
|
-
}
|
|
28611
|
-
const entries = parsed.data.personaId ? deps.outboxStore.listByPersona(parsed.data.personaId) : deps.outboxStore.list();
|
|
28612
|
-
return {
|
|
28613
|
-
response: { type: "attachment.outboxList", entries }
|
|
28614
|
-
};
|
|
28615
|
-
};
|
|
28616
|
-
const mountAdd = async (frame) => {
|
|
28617
|
-
if (!deps.mountStore) {
|
|
28618
|
-
throw new ClawdError(ERROR_CODES.METHOD_NOT_IMPLEMENTED, "mountStore not wired");
|
|
28619
|
-
}
|
|
28620
|
-
const parsed = AttachmentMountAddArgs.safeParse(frame);
|
|
28621
|
-
if (!parsed.success) {
|
|
28622
|
-
throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, parsed.error.message);
|
|
28623
|
-
}
|
|
28624
|
-
const args = parsed.data;
|
|
28625
|
-
try {
|
|
28626
|
-
const entry = deps.mountStore.add(args.personaId, {
|
|
28627
|
-
absPath: args.absPath,
|
|
28628
|
-
mode: args.mode
|
|
28629
|
-
});
|
|
28630
|
-
return {
|
|
28631
|
-
response: {
|
|
28632
|
-
type: "attachment.mountAdd",
|
|
28633
|
-
entry,
|
|
28634
|
-
sandboxRestartNeeded: true
|
|
28635
|
-
}
|
|
28636
|
-
};
|
|
28637
|
-
} catch (err) {
|
|
28638
|
-
throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, err.message);
|
|
28639
|
-
}
|
|
28640
|
-
};
|
|
28641
|
-
const mountRemove = async (frame) => {
|
|
28642
|
-
if (!deps.mountStore) {
|
|
28643
|
-
throw new ClawdError(ERROR_CODES.METHOD_NOT_IMPLEMENTED, "mountStore not wired");
|
|
28644
|
-
}
|
|
28645
|
-
const parsed = AttachmentMountRemoveArgs.safeParse(frame);
|
|
28646
|
-
if (!parsed.success) {
|
|
28647
|
-
throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, parsed.error.message);
|
|
28648
|
-
}
|
|
28649
|
-
const ok = deps.mountStore.remove(parsed.data.personaId, parsed.data.basename);
|
|
28650
|
-
if (!ok) {
|
|
28651
|
-
throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, "mount not found");
|
|
28652
|
-
}
|
|
28653
|
-
return { response: { type: "attachment.mountRemove", removed: true } };
|
|
28654
|
-
};
|
|
28655
|
-
const mountList = async (frame) => {
|
|
28656
|
-
if (!deps.mountStore) {
|
|
28657
|
-
throw new ClawdError(ERROR_CODES.METHOD_NOT_IMPLEMENTED, "mountStore not wired");
|
|
28658
|
-
}
|
|
28659
|
-
const parsed = AttachmentMountListArgs.safeParse(frame);
|
|
28660
|
-
if (!parsed.success) {
|
|
28661
|
-
throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, parsed.error.message);
|
|
28662
|
-
}
|
|
28663
|
-
const entries = deps.mountStore.list(parsed.data.personaId);
|
|
28664
|
-
return { response: { type: "attachment.mountList", entries } };
|
|
28665
|
-
};
|
|
28666
28432
|
const groupAdd = async (frame) => {
|
|
28667
28433
|
if (!deps.groupFileStore || !deps.getSessionScope) {
|
|
28668
28434
|
throw new ClawdError(ERROR_CODES.METHOD_NOT_IMPLEMENTED, "groupFileStore not wired");
|
|
@@ -28732,12 +28498,7 @@ function buildAttachmentHandlers(deps) {
|
|
|
28732
28498
|
return { response: { type: "attachment.groupListPersona", perSession } };
|
|
28733
28499
|
};
|
|
28734
28500
|
return {
|
|
28735
|
-
"attachment.
|
|
28736
|
-
"attachment.outboxRevoke": outboxRevoke,
|
|
28737
|
-
"attachment.outboxList": outboxList,
|
|
28738
|
-
"attachment.mountAdd": mountAdd,
|
|
28739
|
-
"attachment.mountRemove": mountRemove,
|
|
28740
|
-
"attachment.mountList": mountList,
|
|
28501
|
+
"attachment.signUrl": signUrl,
|
|
28741
28502
|
"attachment.groupAdd": groupAdd,
|
|
28742
28503
|
"attachment.groupRemove": groupRemove,
|
|
28743
28504
|
"attachment.groupList": groupList,
|
|
@@ -28769,7 +28530,7 @@ function buildMethodHandlers(deps) {
|
|
|
28769
28530
|
async function startDaemon(config) {
|
|
28770
28531
|
const logger = createLogger({
|
|
28771
28532
|
level: config.logLevel,
|
|
28772
|
-
file:
|
|
28533
|
+
file: import_node_path26.default.join(config.dataDir, "clawd.log")
|
|
28773
28534
|
});
|
|
28774
28535
|
logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
|
|
28775
28536
|
const stateMgr = new StateFileManager({ dataDir: config.dataDir });
|
|
@@ -28801,7 +28562,7 @@ async function startDaemon(config) {
|
|
|
28801
28562
|
const agents = new AgentsScanner();
|
|
28802
28563
|
const history = new ClaudeHistoryReader();
|
|
28803
28564
|
let transport = null;
|
|
28804
|
-
const personaStore = new PersonaStore(
|
|
28565
|
+
const personaStore = new PersonaStore(import_node_path26.default.join(config.dataDir, "personas"));
|
|
28805
28566
|
const defaultsRoot = findDefaultsRoot();
|
|
28806
28567
|
if (defaultsRoot) {
|
|
28807
28568
|
seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
|
|
@@ -28810,17 +28571,13 @@ async function startDaemon(config) {
|
|
|
28810
28571
|
}
|
|
28811
28572
|
const ownerDisplayName = loadOwnerDisplayName(config.dataDir);
|
|
28812
28573
|
const groupFileStore = new GroupFileStore({ dataDir: config.dataDir, logger });
|
|
28813
|
-
const outboxStore = new OutboxStore({ dataDir: config.dataDir, logger });
|
|
28814
|
-
const mountStore = new MountStore({
|
|
28815
|
-
personaDirPath: (pid) => personaStore.personaDirPath(pid)
|
|
28816
|
-
});
|
|
28817
28574
|
const manager = new SessionManager({
|
|
28818
28575
|
store,
|
|
28819
28576
|
logger,
|
|
28820
28577
|
getAdapter,
|
|
28821
28578
|
historyReader: history,
|
|
28822
28579
|
dataDir: config.dataDir,
|
|
28823
|
-
personaRoot:
|
|
28580
|
+
personaRoot: import_node_path26.default.join(config.dataDir, "personas"),
|
|
28824
28581
|
personaStore,
|
|
28825
28582
|
ownerDisplayName,
|
|
28826
28583
|
mode: config.mode,
|
|
@@ -28843,10 +28600,10 @@ async function startDaemon(config) {
|
|
|
28843
28600
|
// 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
|
|
28844
28601
|
attachmentGroup: {
|
|
28845
28602
|
onFileEdit: (input) => {
|
|
28846
|
-
const absPath =
|
|
28603
|
+
const absPath = import_node_path26.default.isAbsolute(input.relPath) ? input.relPath : import_node_path26.default.join(input.cwd, input.relPath);
|
|
28847
28604
|
let size = 0;
|
|
28848
28605
|
try {
|
|
28849
|
-
size =
|
|
28606
|
+
size = import_node_fs24.default.statSync(absPath).size;
|
|
28850
28607
|
} catch (err) {
|
|
28851
28608
|
logger.warn("attachment.onFileEdit stat failed", {
|
|
28852
28609
|
sessionId: input.sessionId,
|
|
@@ -28951,22 +28708,16 @@ async function startDaemon(config) {
|
|
|
28951
28708
|
// 时禁用文件 GET/POST,保持 1.0 行为兼容)。
|
|
28952
28709
|
getHttpBaseUrl,
|
|
28953
28710
|
httpToken: resolvedAuthToken,
|
|
28954
|
-
// file-sharing attachment.* RPC
|
|
28955
|
-
//
|
|
28956
|
-
// 后续 PR 复用同一份装配。
|
|
28711
|
+
// file-sharing attachment.* RPC。signUrl 用 owner token 做 HMAC secret;group RPC
|
|
28712
|
+
// 根据 sessionId 反查 scope 写盘。
|
|
28957
28713
|
attachment: {
|
|
28958
|
-
outboxStore,
|
|
28959
|
-
mountStore,
|
|
28960
28714
|
groupFileStore,
|
|
28961
|
-
personaDirPath: (pid) => personaStore.personaDirPath(pid),
|
|
28962
28715
|
getHttpBaseUrl,
|
|
28963
|
-
|
|
28964
|
-
|
|
28965
|
-
|
|
28966
|
-
return null;
|
|
28967
|
-
},
|
|
28716
|
+
// HMAC sign secret:复用 ~/.clawd/auth.json owner token(持久跨重启)。
|
|
28717
|
+
// noAuth 模式 resolvedAuthToken 为 null → handler 自己返 NOT_IMPLEMENTED。
|
|
28718
|
+
getSignSecret: () => resolvedAuthToken ?? "",
|
|
28968
28719
|
// group RPC:根据 sessionId 反查 scope;owner-mode persona session 走
|
|
28969
|
-
// 'persona/<pid>/owner',default 走 'default'。
|
|
28720
|
+
// 'persona/<pid>/owner',default 走 'default'。
|
|
28970
28721
|
getSessionScope: (sessionId) => {
|
|
28971
28722
|
const file = store.read(sessionId);
|
|
28972
28723
|
if (!file) return null;
|
|
@@ -28988,7 +28739,8 @@ async function startDaemon(config) {
|
|
|
28988
28739
|
personaStore,
|
|
28989
28740
|
groupFileStore,
|
|
28990
28741
|
sessionStore: store,
|
|
28991
|
-
|
|
28742
|
+
// /files HMAC verify 用同一份 owner token 做 secret(与 attachment.signUrl 同源)
|
|
28743
|
+
getSignSecret: () => resolvedAuthToken ?? null
|
|
28992
28744
|
});
|
|
28993
28745
|
wsServer = new LocalWsServer({
|
|
28994
28746
|
host: config.host,
|
|
@@ -29127,8 +28879,8 @@ async function startDaemon(config) {
|
|
|
29127
28879
|
const lines = [
|
|
29128
28880
|
`Tunnel: ${r.url}`,
|
|
29129
28881
|
...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
|
|
29130
|
-
`Frpc config: ${
|
|
29131
|
-
`Frpc log: ${
|
|
28882
|
+
`Frpc config: ${import_node_path26.default.join(config.dataDir, "frpc.toml")}`,
|
|
28883
|
+
`Frpc log: ${import_node_path26.default.join(config.dataDir, "frpc.log")}`
|
|
29132
28884
|
];
|
|
29133
28885
|
const width = Math.max(...lines.map((l) => l.length));
|
|
29134
28886
|
const bar = "\u2550".repeat(width + 4);
|
|
@@ -29141,8 +28893,8 @@ ${bar}
|
|
|
29141
28893
|
|
|
29142
28894
|
`);
|
|
29143
28895
|
try {
|
|
29144
|
-
const connectPath =
|
|
29145
|
-
|
|
28896
|
+
const connectPath = import_node_path26.default.join(config.dataDir, "connect.txt");
|
|
28897
|
+
import_node_fs24.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
|
|
29146
28898
|
} catch {
|
|
29147
28899
|
}
|
|
29148
28900
|
} catch (err) {
|