@clawos-dev/clawd 0.2.85-beta.158.934b6ca → 0.2.85-beta.160.958069f
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 +442 -400
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -65,14 +65,6 @@ var init_methods = __esm({
|
|
|
65
65
|
"session:unsubscribe",
|
|
66
66
|
"session:pin",
|
|
67
67
|
"session:reorderPins",
|
|
68
|
-
// mirror peer sessions (2026-05-26): owner-only RPC,写/删本机 mirror SessionFile —
|
|
69
|
-
// mirror 是「**我**在朋友 daemon 上自己创建的 session」的本机持久化副本(不是朋友的会话),
|
|
70
|
-
// 方便 sidebar 跨设备聚合。daemon dumb 写删,**不广播任何 push 帧** (不发 session:info /
|
|
71
|
-
// session:deleted);UI 是写入唯一源,双写完成后通过 cache.setData('sessions', ...) 同步
|
|
72
|
-
// 本地 sidebar state。native session:* handler 完全不感知 mirror (UI 操作 mirror 不复用
|
|
73
|
-
// native 路径)。
|
|
74
|
-
"peerSession:upsert",
|
|
75
|
-
"peerSession:remove",
|
|
76
68
|
"permission:respond",
|
|
77
69
|
// AskUserQuestion 表单回写:UI 答完所有 question 后调用,daemon 把答案合并进 updated_input
|
|
78
70
|
// 写一条 control_response 到 CC stdin(详见 events.ts session:question JSDoc)
|
|
@@ -651,8 +643,8 @@ var init_parseUtil = __esm({
|
|
|
651
643
|
init_errors2();
|
|
652
644
|
init_en();
|
|
653
645
|
makeIssue = (params) => {
|
|
654
|
-
const { data, path:
|
|
655
|
-
const fullPath = [...
|
|
646
|
+
const { data, path: path44, errorMaps, issueData } = params;
|
|
647
|
+
const fullPath = [...path44, ...issueData.path || []];
|
|
656
648
|
const fullIssue = {
|
|
657
649
|
...issueData,
|
|
658
650
|
path: fullPath
|
|
@@ -963,11 +955,11 @@ var init_types = __esm({
|
|
|
963
955
|
init_parseUtil();
|
|
964
956
|
init_util();
|
|
965
957
|
ParseInputLazyPath = class {
|
|
966
|
-
constructor(parent, value,
|
|
958
|
+
constructor(parent, value, path44, key) {
|
|
967
959
|
this._cachedPath = [];
|
|
968
960
|
this.parent = parent;
|
|
969
961
|
this.data = value;
|
|
970
|
-
this._path =
|
|
962
|
+
this._path = path44;
|
|
971
963
|
this._key = key;
|
|
972
964
|
}
|
|
973
965
|
get path() {
|
|
@@ -4491,7 +4483,7 @@ var init_persona_schemas = __esm({
|
|
|
4491
4483
|
});
|
|
4492
4484
|
|
|
4493
4485
|
// ../protocol/src/schemas.ts
|
|
4494
|
-
var SessionStatusSchema, UsageSchema, ContextUsageSchema, sessionMetaShape, SessionMetaSchema, ModelInfoSchema, ModeInfoSchema, ConfigFieldSchemaSchema, CapabilitiesGetArgs, CapabilitiesResponseSchema, AllowRuleSchema, SessionFileSchema, ParsedEventBase, HistoryUserMetaSchema, SubagentToolStatsSchema, StructuredPatchHunkSchema, ToolResultExtraSchema, MemoryEntrySchema, AskQuestionOptionSchema, AskQuestionItemSchema, ParsedEventSchema, SessionCreateArgs, SessionIdArgs, SessionUpdateArgs, SessionSendArgs, SessionRewindArgs, SessionRewindResponseSchema, SessionRewindDiffArgs, RewindDiffHunkSchema, RewindDiffFileSchema, SessionRewindDiffResponseSchema, SessionRewindableMessageIdsArgs, SessionRewindableMessageIdsResponseSchema, SessionResumeArgs, SessionForkArgs, SessionForkResponseSchema, SessionObserveArgs, SessionEventsArgs, PermissionRespondArgs, HistoryListArgs, HistoryReadArgs, HistorySubagentsArgs, HistorySubagentReadArgs, WorkspaceListArgs, WorkspaceReadArgs, SkillsListArgs, SkillEntrySchema, AgentEntrySchema, AgentsListArgs, AgentsListResponseSchema, SessionSubscribeArgs, SessionPinArgs,
|
|
4486
|
+
var SessionStatusSchema, UsageSchema, ContextUsageSchema, sessionMetaShape, SessionMetaSchema, ModelInfoSchema, ModeInfoSchema, ConfigFieldSchemaSchema, CapabilitiesGetArgs, CapabilitiesResponseSchema, AllowRuleSchema, SessionFileSchema, ParsedEventBase, HistoryUserMetaSchema, SubagentToolStatsSchema, StructuredPatchHunkSchema, ToolResultExtraSchema, MemoryEntrySchema, AskQuestionOptionSchema, AskQuestionItemSchema, ParsedEventSchema, SessionCreateArgs, SessionIdArgs, SessionUpdateArgs, SessionSendArgs, SessionRewindArgs, SessionRewindResponseSchema, SessionRewindDiffArgs, RewindDiffHunkSchema, RewindDiffFileSchema, SessionRewindDiffResponseSchema, SessionRewindableMessageIdsArgs, SessionRewindableMessageIdsResponseSchema, SessionResumeArgs, SessionForkArgs, SessionForkResponseSchema, SessionObserveArgs, SessionEventsArgs, PermissionRespondArgs, HistoryListArgs, HistoryReadArgs, HistorySubagentsArgs, HistorySubagentReadArgs, WorkspaceListArgs, WorkspaceReadArgs, SkillsListArgs, SkillEntrySchema, AgentEntrySchema, AgentsListArgs, AgentsListResponseSchema, SessionSubscribeArgs, SessionPinArgs, SessionReorderPinsArgs, GitRootArgs, GitRootResponseSchema, GitBranchArgs, GitBranchResponseSchema, GitBranchesArgs, GitBranchesResponseSchema, HistoryRecentDirsArgs, RecentDirEntrySchema, HistoryRecentDirsResponseSchema, SessionQuestionFrameSchema, SessionQuestionClearedFrameSchema, AnswerQuestionArgs, AnswerQuestionResponseSchema, CancelQuestionArgs, CancelQuestionResponseSchema, AuthRequestFrameSchema, AuthOkFrameSchema, TunnelExitedEventSchema, TunnelUnavailableEventSchema, InfoRunningSessionSchema, InfoResponseSchema;
|
|
4495
4487
|
var init_schemas = __esm({
|
|
4496
4488
|
"../protocol/src/schemas.ts"() {
|
|
4497
4489
|
"use strict";
|
|
@@ -4619,35 +4611,6 @@ var init_schemas = __esm({
|
|
|
4619
4611
|
* 当前为 caller 自报,daemon 不密码学验证真伪;强身份验签是独立工作(B 方案)。
|
|
4620
4612
|
*/
|
|
4621
4613
|
creatorOwnerPrincipalId: external_exports.string().min(1).optional(),
|
|
4622
|
-
/**
|
|
4623
|
-
* Mirror peer sessions (2026-05-26): mirror 标识。**我在朋友 daemon 上以 guest ctx
|
|
4624
|
-
* 创建的 session**,远端是 source of truth,本机是该 session 的持久化副本,方便
|
|
4625
|
-
* sidebar 跨设备聚合。字段值是远端 daemon 的 ownerPrincipalId(即我接入的那位朋友)。
|
|
4626
|
-
*
|
|
4627
|
-
* 语义关键澄清:mirror **不是朋友创建给我的会话**——它是我自己的会话,只是在朋友
|
|
4628
|
-
* 的机器上跑。sidebar chip 显示 `@<朋友>` 暗示「位置」,不是「来源」。
|
|
4629
|
-
*
|
|
4630
|
-
* - undefined / 缺省 → 本机 native session(在我自己机器上跑)
|
|
4631
|
-
* - 非空 → 我的会话在该 ownerPrincipalId 朋友的 daemon 上跑,本机为持久化副本
|
|
4632
|
-
*
|
|
4633
|
-
* 与 `creatorPrincipalId` / `creatorOwnerPrincipalId` 在四类 session 下取值矩阵:
|
|
4634
|
-
* | 形态 | creatorPrincipalId | creatorOwnerPrincipalId | originOwnerPrincipalId |
|
|
4635
|
-
* |-------------------------------------|--------------------------|-------------------------|------------------------|
|
|
4636
|
-
* | 本机 owner 自创 | 本机 ownerPrincipalId | 本机 ownerPrincipalId | undefined |
|
|
4637
|
-
* | 本机被别人通过 personal token 接入创建 | 远端接入者 cap.id | 远端接入者 ownerPrincipalId | undefined |
|
|
4638
|
-
* | 我在朋友 daemon 上以 guest ctx 创建(mirror 回本机) | 朋友 daemon personal cap.id | 我自己 ownerPrincipalId | 朋友 ownerPrincipalId |
|
|
4639
|
-
*
|
|
4640
|
-
* UI 用法:
|
|
4641
|
-
* - sidebar Active/Pinned/Recents 过滤:`origin 非空 → 一律视作 self`(绕过 #739 隔离)
|
|
4642
|
-
* - 行内显示 `@<朋友>` chip 暗示位置
|
|
4643
|
-
* - 进 ChatPanel 时按 origin 路由到 `pool.ensureRemoteForOwner(origin)` 走远端
|
|
4644
|
-
*
|
|
4645
|
-
* daemon 用法:
|
|
4646
|
-
* - `peerSession:upsert` / `peerSession:remove` 一族 RPC 专管 mirror 写删;
|
|
4647
|
-
* daemon dumb write/delete,**不广播任何 push 帧**,UI 是写入唯一源
|
|
4648
|
-
* - native `session:*` handler 完全不感知 mirror(UI 操作 mirror 不走 native 路径)
|
|
4649
|
-
*/
|
|
4650
|
-
originOwnerPrincipalId: external_exports.string().min(1).optional(),
|
|
4651
4614
|
createdAt: external_exports.string().min(1),
|
|
4652
4615
|
updatedAt: external_exports.string().min(1)
|
|
4653
4616
|
});
|
|
@@ -5003,14 +4966,6 @@ var init_schemas = __esm({
|
|
|
5003
4966
|
sessionId: external_exports.string().min(1),
|
|
5004
4967
|
pinned: external_exports.boolean()
|
|
5005
4968
|
});
|
|
5006
|
-
PeerSessionUpsertArgs = SessionFileSchema;
|
|
5007
|
-
PeerSessionUpsertResponseSchema = external_exports.object({
|
|
5008
|
-
type: external_exports.literal("peerSession:upsert:ok")
|
|
5009
|
-
});
|
|
5010
|
-
PeerSessionRemoveArgs = external_exports.object({ sessionId: external_exports.string().min(1) });
|
|
5011
|
-
PeerSessionRemoveResponseSchema = external_exports.object({
|
|
5012
|
-
type: external_exports.literal("peerSession:remove:ok")
|
|
5013
|
-
});
|
|
5014
4969
|
SessionReorderPinsArgs = external_exports.object({
|
|
5015
4970
|
orderedIds: external_exports.array(external_exports.string().min(1)).min(1)
|
|
5016
4971
|
});
|
|
@@ -5625,8 +5580,8 @@ var require_req = __commonJS({
|
|
|
5625
5580
|
if (req.originalUrl) {
|
|
5626
5581
|
_req.url = req.originalUrl;
|
|
5627
5582
|
} else {
|
|
5628
|
-
const
|
|
5629
|
-
_req.url = typeof
|
|
5583
|
+
const path44 = req.path;
|
|
5584
|
+
_req.url = typeof path44 === "string" ? path44 : req.url ? req.url.path || req.url : void 0;
|
|
5630
5585
|
}
|
|
5631
5586
|
if (req.query) {
|
|
5632
5587
|
_req.query = req.query;
|
|
@@ -5791,14 +5746,14 @@ var require_redact = __commonJS({
|
|
|
5791
5746
|
}
|
|
5792
5747
|
return obj;
|
|
5793
5748
|
}
|
|
5794
|
-
function parsePath(
|
|
5749
|
+
function parsePath(path44) {
|
|
5795
5750
|
const parts = [];
|
|
5796
5751
|
let current = "";
|
|
5797
5752
|
let inBrackets = false;
|
|
5798
5753
|
let inQuotes = false;
|
|
5799
5754
|
let quoteChar = "";
|
|
5800
|
-
for (let i = 0; i <
|
|
5801
|
-
const char =
|
|
5755
|
+
for (let i = 0; i < path44.length; i++) {
|
|
5756
|
+
const char = path44[i];
|
|
5802
5757
|
if (!inBrackets && char === ".") {
|
|
5803
5758
|
if (current) {
|
|
5804
5759
|
parts.push(current);
|
|
@@ -5929,10 +5884,10 @@ var require_redact = __commonJS({
|
|
|
5929
5884
|
return current;
|
|
5930
5885
|
}
|
|
5931
5886
|
function redactPaths(obj, paths, censor, remove = false) {
|
|
5932
|
-
for (const
|
|
5933
|
-
const parts = parsePath(
|
|
5887
|
+
for (const path44 of paths) {
|
|
5888
|
+
const parts = parsePath(path44);
|
|
5934
5889
|
if (parts.includes("*")) {
|
|
5935
|
-
redactWildcardPath(obj, parts, censor,
|
|
5890
|
+
redactWildcardPath(obj, parts, censor, path44, remove);
|
|
5936
5891
|
} else {
|
|
5937
5892
|
if (remove) {
|
|
5938
5893
|
removeKey(obj, parts);
|
|
@@ -6017,8 +5972,8 @@ var require_redact = __commonJS({
|
|
|
6017
5972
|
}
|
|
6018
5973
|
} else {
|
|
6019
5974
|
if (afterWildcard.includes("*")) {
|
|
6020
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
6021
|
-
const fullPath = [...pathArray.slice(0, pathLength), ...
|
|
5975
|
+
const wrappedCensor = typeof censor === "function" ? (value, path44) => {
|
|
5976
|
+
const fullPath = [...pathArray.slice(0, pathLength), ...path44];
|
|
6022
5977
|
return censor(value, fullPath);
|
|
6023
5978
|
} : censor;
|
|
6024
5979
|
redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
|
|
@@ -6053,8 +6008,8 @@ var require_redact = __commonJS({
|
|
|
6053
6008
|
return null;
|
|
6054
6009
|
}
|
|
6055
6010
|
const pathStructure = /* @__PURE__ */ new Map();
|
|
6056
|
-
for (const
|
|
6057
|
-
const parts = parsePath(
|
|
6011
|
+
for (const path44 of pathsToClone) {
|
|
6012
|
+
const parts = parsePath(path44);
|
|
6058
6013
|
let current = pathStructure;
|
|
6059
6014
|
for (let i = 0; i < parts.length; i++) {
|
|
6060
6015
|
const part = parts[i];
|
|
@@ -6106,24 +6061,24 @@ var require_redact = __commonJS({
|
|
|
6106
6061
|
}
|
|
6107
6062
|
return cloneSelectively(obj, pathStructure);
|
|
6108
6063
|
}
|
|
6109
|
-
function validatePath(
|
|
6110
|
-
if (typeof
|
|
6064
|
+
function validatePath(path44) {
|
|
6065
|
+
if (typeof path44 !== "string") {
|
|
6111
6066
|
throw new Error("Paths must be (non-empty) strings");
|
|
6112
6067
|
}
|
|
6113
|
-
if (
|
|
6068
|
+
if (path44 === "") {
|
|
6114
6069
|
throw new Error("Invalid redaction path ()");
|
|
6115
6070
|
}
|
|
6116
|
-
if (
|
|
6117
|
-
throw new Error(`Invalid redaction path (${
|
|
6071
|
+
if (path44.includes("..")) {
|
|
6072
|
+
throw new Error(`Invalid redaction path (${path44})`);
|
|
6118
6073
|
}
|
|
6119
|
-
if (
|
|
6120
|
-
throw new Error(`Invalid redaction path (${
|
|
6074
|
+
if (path44.includes(",")) {
|
|
6075
|
+
throw new Error(`Invalid redaction path (${path44})`);
|
|
6121
6076
|
}
|
|
6122
6077
|
let bracketCount = 0;
|
|
6123
6078
|
let inQuotes = false;
|
|
6124
6079
|
let quoteChar = "";
|
|
6125
|
-
for (let i = 0; i <
|
|
6126
|
-
const char =
|
|
6080
|
+
for (let i = 0; i < path44.length; i++) {
|
|
6081
|
+
const char = path44[i];
|
|
6127
6082
|
if ((char === '"' || char === "'") && bracketCount > 0) {
|
|
6128
6083
|
if (!inQuotes) {
|
|
6129
6084
|
inQuotes = true;
|
|
@@ -6137,20 +6092,20 @@ var require_redact = __commonJS({
|
|
|
6137
6092
|
} else if (char === "]" && !inQuotes) {
|
|
6138
6093
|
bracketCount--;
|
|
6139
6094
|
if (bracketCount < 0) {
|
|
6140
|
-
throw new Error(`Invalid redaction path (${
|
|
6095
|
+
throw new Error(`Invalid redaction path (${path44})`);
|
|
6141
6096
|
}
|
|
6142
6097
|
}
|
|
6143
6098
|
}
|
|
6144
6099
|
if (bracketCount !== 0) {
|
|
6145
|
-
throw new Error(`Invalid redaction path (${
|
|
6100
|
+
throw new Error(`Invalid redaction path (${path44})`);
|
|
6146
6101
|
}
|
|
6147
6102
|
}
|
|
6148
6103
|
function validatePaths(paths) {
|
|
6149
6104
|
if (!Array.isArray(paths)) {
|
|
6150
6105
|
throw new TypeError("paths must be an array");
|
|
6151
6106
|
}
|
|
6152
|
-
for (const
|
|
6153
|
-
validatePath(
|
|
6107
|
+
for (const path44 of paths) {
|
|
6108
|
+
validatePath(path44);
|
|
6154
6109
|
}
|
|
6155
6110
|
}
|
|
6156
6111
|
function slowRedact(options = {}) {
|
|
@@ -6318,8 +6273,8 @@ var require_redaction = __commonJS({
|
|
|
6318
6273
|
if (shape[k2] === null) {
|
|
6319
6274
|
o[k2] = (value) => topCensor(value, [k2]);
|
|
6320
6275
|
} else {
|
|
6321
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
6322
|
-
return censor(value, [k2, ...
|
|
6276
|
+
const wrappedCensor = typeof censor === "function" ? (value, path44) => {
|
|
6277
|
+
return censor(value, [k2, ...path44]);
|
|
6323
6278
|
} : censor;
|
|
6324
6279
|
o[k2] = Redact({
|
|
6325
6280
|
paths: shape[k2],
|
|
@@ -6537,10 +6492,10 @@ var require_atomic_sleep = __commonJS({
|
|
|
6537
6492
|
var require_sonic_boom = __commonJS({
|
|
6538
6493
|
"../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
|
|
6539
6494
|
"use strict";
|
|
6540
|
-
var
|
|
6495
|
+
var fs35 = require("fs");
|
|
6541
6496
|
var EventEmitter2 = require("events");
|
|
6542
6497
|
var inherits = require("util").inherits;
|
|
6543
|
-
var
|
|
6498
|
+
var path44 = require("path");
|
|
6544
6499
|
var sleep = require_atomic_sleep();
|
|
6545
6500
|
var assert = require("assert");
|
|
6546
6501
|
var BUSY_WRITE_TIMEOUT = 100;
|
|
@@ -6594,20 +6549,20 @@ var require_sonic_boom = __commonJS({
|
|
|
6594
6549
|
const mode = sonic.mode;
|
|
6595
6550
|
if (sonic.sync) {
|
|
6596
6551
|
try {
|
|
6597
|
-
if (sonic.mkdir)
|
|
6598
|
-
const fd =
|
|
6552
|
+
if (sonic.mkdir) fs35.mkdirSync(path44.dirname(file), { recursive: true });
|
|
6553
|
+
const fd = fs35.openSync(file, flags, mode);
|
|
6599
6554
|
fileOpened(null, fd);
|
|
6600
6555
|
} catch (err) {
|
|
6601
6556
|
fileOpened(err);
|
|
6602
6557
|
throw err;
|
|
6603
6558
|
}
|
|
6604
6559
|
} else if (sonic.mkdir) {
|
|
6605
|
-
|
|
6560
|
+
fs35.mkdir(path44.dirname(file), { recursive: true }, (err) => {
|
|
6606
6561
|
if (err) return fileOpened(err);
|
|
6607
|
-
|
|
6562
|
+
fs35.open(file, flags, mode, fileOpened);
|
|
6608
6563
|
});
|
|
6609
6564
|
} else {
|
|
6610
|
-
|
|
6565
|
+
fs35.open(file, flags, mode, fileOpened);
|
|
6611
6566
|
}
|
|
6612
6567
|
}
|
|
6613
6568
|
function SonicBoom(opts) {
|
|
@@ -6648,8 +6603,8 @@ var require_sonic_boom = __commonJS({
|
|
|
6648
6603
|
this.flush = flushBuffer;
|
|
6649
6604
|
this.flushSync = flushBufferSync;
|
|
6650
6605
|
this._actualWrite = actualWriteBuffer;
|
|
6651
|
-
fsWriteSync = () =>
|
|
6652
|
-
fsWrite = () =>
|
|
6606
|
+
fsWriteSync = () => fs35.writeSync(this.fd, this._writingBuf);
|
|
6607
|
+
fsWrite = () => fs35.write(this.fd, this._writingBuf, this.release);
|
|
6653
6608
|
} else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
|
|
6654
6609
|
this._writingBuf = "";
|
|
6655
6610
|
this.write = write;
|
|
@@ -6658,15 +6613,15 @@ var require_sonic_boom = __commonJS({
|
|
|
6658
6613
|
this._actualWrite = actualWrite;
|
|
6659
6614
|
fsWriteSync = () => {
|
|
6660
6615
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
6661
|
-
return
|
|
6616
|
+
return fs35.writeSync(this.fd, this._writingBuf);
|
|
6662
6617
|
}
|
|
6663
|
-
return
|
|
6618
|
+
return fs35.writeSync(this.fd, this._writingBuf, "utf8");
|
|
6664
6619
|
};
|
|
6665
6620
|
fsWrite = () => {
|
|
6666
6621
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
6667
|
-
return
|
|
6622
|
+
return fs35.write(this.fd, this._writingBuf, this.release);
|
|
6668
6623
|
}
|
|
6669
|
-
return
|
|
6624
|
+
return fs35.write(this.fd, this._writingBuf, "utf8", this.release);
|
|
6670
6625
|
};
|
|
6671
6626
|
} else {
|
|
6672
6627
|
throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
|
|
@@ -6723,7 +6678,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6723
6678
|
}
|
|
6724
6679
|
}
|
|
6725
6680
|
if (this._fsync) {
|
|
6726
|
-
|
|
6681
|
+
fs35.fsyncSync(this.fd);
|
|
6727
6682
|
}
|
|
6728
6683
|
const len = this._len;
|
|
6729
6684
|
if (this._reopening) {
|
|
@@ -6837,7 +6792,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6837
6792
|
const onDrain = () => {
|
|
6838
6793
|
if (!this._fsync) {
|
|
6839
6794
|
try {
|
|
6840
|
-
|
|
6795
|
+
fs35.fsync(this.fd, (err) => {
|
|
6841
6796
|
this._flushPending = false;
|
|
6842
6797
|
cb(err);
|
|
6843
6798
|
});
|
|
@@ -6939,7 +6894,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6939
6894
|
const fd = this.fd;
|
|
6940
6895
|
this.once("ready", () => {
|
|
6941
6896
|
if (fd !== this.fd) {
|
|
6942
|
-
|
|
6897
|
+
fs35.close(fd, (err) => {
|
|
6943
6898
|
if (err) {
|
|
6944
6899
|
return this.emit("error", err);
|
|
6945
6900
|
}
|
|
@@ -6988,7 +6943,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6988
6943
|
buf = this._bufs[0];
|
|
6989
6944
|
}
|
|
6990
6945
|
try {
|
|
6991
|
-
const n = Buffer.isBuffer(buf) ?
|
|
6946
|
+
const n = Buffer.isBuffer(buf) ? fs35.writeSync(this.fd, buf) : fs35.writeSync(this.fd, buf, "utf8");
|
|
6992
6947
|
const releasedBufObj = releaseWritingBuf(buf, this._len, n);
|
|
6993
6948
|
buf = releasedBufObj.writingBuf;
|
|
6994
6949
|
this._len = releasedBufObj.len;
|
|
@@ -7004,7 +6959,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7004
6959
|
}
|
|
7005
6960
|
}
|
|
7006
6961
|
try {
|
|
7007
|
-
|
|
6962
|
+
fs35.fsyncSync(this.fd);
|
|
7008
6963
|
} catch {
|
|
7009
6964
|
}
|
|
7010
6965
|
}
|
|
@@ -7025,7 +6980,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7025
6980
|
buf = mergeBuf(this._bufs[0], this._lens[0]);
|
|
7026
6981
|
}
|
|
7027
6982
|
try {
|
|
7028
|
-
const n =
|
|
6983
|
+
const n = fs35.writeSync(this.fd, buf);
|
|
7029
6984
|
buf = buf.subarray(n);
|
|
7030
6985
|
this._len = Math.max(this._len - n, 0);
|
|
7031
6986
|
if (buf.length <= 0) {
|
|
@@ -7053,13 +7008,13 @@ var require_sonic_boom = __commonJS({
|
|
|
7053
7008
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
|
|
7054
7009
|
if (this.sync) {
|
|
7055
7010
|
try {
|
|
7056
|
-
const written = Buffer.isBuffer(this._writingBuf) ?
|
|
7011
|
+
const written = Buffer.isBuffer(this._writingBuf) ? fs35.writeSync(this.fd, this._writingBuf) : fs35.writeSync(this.fd, this._writingBuf, "utf8");
|
|
7057
7012
|
release(null, written);
|
|
7058
7013
|
} catch (err) {
|
|
7059
7014
|
release(err);
|
|
7060
7015
|
}
|
|
7061
7016
|
} else {
|
|
7062
|
-
|
|
7017
|
+
fs35.write(this.fd, this._writingBuf, release);
|
|
7063
7018
|
}
|
|
7064
7019
|
}
|
|
7065
7020
|
function actualWriteBuffer() {
|
|
@@ -7068,7 +7023,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7068
7023
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
|
|
7069
7024
|
if (this.sync) {
|
|
7070
7025
|
try {
|
|
7071
|
-
const written =
|
|
7026
|
+
const written = fs35.writeSync(this.fd, this._writingBuf);
|
|
7072
7027
|
release(null, written);
|
|
7073
7028
|
} catch (err) {
|
|
7074
7029
|
release(err);
|
|
@@ -7077,7 +7032,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7077
7032
|
if (kCopyBuffer) {
|
|
7078
7033
|
this._writingBuf = Buffer.from(this._writingBuf);
|
|
7079
7034
|
}
|
|
7080
|
-
|
|
7035
|
+
fs35.write(this.fd, this._writingBuf, release);
|
|
7081
7036
|
}
|
|
7082
7037
|
}
|
|
7083
7038
|
function actualClose(sonic) {
|
|
@@ -7093,12 +7048,12 @@ var require_sonic_boom = __commonJS({
|
|
|
7093
7048
|
sonic._lens = [];
|
|
7094
7049
|
assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
|
|
7095
7050
|
try {
|
|
7096
|
-
|
|
7051
|
+
fs35.fsync(sonic.fd, closeWrapped);
|
|
7097
7052
|
} catch {
|
|
7098
7053
|
}
|
|
7099
7054
|
function closeWrapped() {
|
|
7100
7055
|
if (sonic.fd !== 1 && sonic.fd !== 2) {
|
|
7101
|
-
|
|
7056
|
+
fs35.close(sonic.fd, done);
|
|
7102
7057
|
} else {
|
|
7103
7058
|
done();
|
|
7104
7059
|
}
|
|
@@ -9462,7 +9417,7 @@ var require_multistream = __commonJS({
|
|
|
9462
9417
|
var require_pino = __commonJS({
|
|
9463
9418
|
"../node_modules/.pnpm/pino@9.14.0/node_modules/pino/pino.js"(exports2, module2) {
|
|
9464
9419
|
"use strict";
|
|
9465
|
-
var
|
|
9420
|
+
var os17 = require("os");
|
|
9466
9421
|
var stdSerializers = require_pino_std_serializers();
|
|
9467
9422
|
var caller = require_caller();
|
|
9468
9423
|
var redaction = require_redaction();
|
|
@@ -9509,7 +9464,7 @@ var require_pino = __commonJS({
|
|
|
9509
9464
|
} = symbols;
|
|
9510
9465
|
var { epochTime, nullTime } = time;
|
|
9511
9466
|
var { pid } = process;
|
|
9512
|
-
var hostname =
|
|
9467
|
+
var hostname = os17.hostname();
|
|
9513
9468
|
var defaultErrorSerializer = stdSerializers.err;
|
|
9514
9469
|
var defaultOptions = {
|
|
9515
9470
|
level: "info",
|
|
@@ -10233,11 +10188,11 @@ var init_lib = __esm({
|
|
|
10233
10188
|
}
|
|
10234
10189
|
}
|
|
10235
10190
|
},
|
|
10236
|
-
addToPath: function addToPath(
|
|
10237
|
-
var last =
|
|
10191
|
+
addToPath: function addToPath(path44, added, removed, oldPosInc, options) {
|
|
10192
|
+
var last = path44.lastComponent;
|
|
10238
10193
|
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
10239
10194
|
return {
|
|
10240
|
-
oldPos:
|
|
10195
|
+
oldPos: path44.oldPos + oldPosInc,
|
|
10241
10196
|
lastComponent: {
|
|
10242
10197
|
count: last.count + 1,
|
|
10243
10198
|
added,
|
|
@@ -10247,7 +10202,7 @@ var init_lib = __esm({
|
|
|
10247
10202
|
};
|
|
10248
10203
|
} else {
|
|
10249
10204
|
return {
|
|
10250
|
-
oldPos:
|
|
10205
|
+
oldPos: path44.oldPos + oldPosInc,
|
|
10251
10206
|
lastComponent: {
|
|
10252
10207
|
count: 1,
|
|
10253
10208
|
added,
|
|
@@ -10678,10 +10633,10 @@ function attachmentToHistoryMessage(o, ts) {
|
|
|
10678
10633
|
const memories = raw.map((m2) => {
|
|
10679
10634
|
if (!m2 || typeof m2 !== "object") return null;
|
|
10680
10635
|
const rec = m2;
|
|
10681
|
-
const
|
|
10636
|
+
const path44 = typeof rec.path === "string" ? rec.path : null;
|
|
10682
10637
|
const content = typeof rec.content === "string" ? rec.content : null;
|
|
10683
|
-
if (!
|
|
10684
|
-
const entry = { path:
|
|
10638
|
+
if (!path44 || content == null) return null;
|
|
10639
|
+
const entry = { path: path44, content };
|
|
10685
10640
|
if (typeof rec.mtimeMs === "number") entry.mtimeMs = rec.mtimeMs;
|
|
10686
10641
|
return entry;
|
|
10687
10642
|
}).filter((m2) => m2 !== null);
|
|
@@ -11507,10 +11462,10 @@ function parseAttachment(obj) {
|
|
|
11507
11462
|
const memories = raw.map((m2) => {
|
|
11508
11463
|
if (!m2 || typeof m2 !== "object") return null;
|
|
11509
11464
|
const rec = m2;
|
|
11510
|
-
const
|
|
11465
|
+
const path44 = typeof rec.path === "string" ? rec.path : null;
|
|
11511
11466
|
const content = typeof rec.content === "string" ? rec.content : null;
|
|
11512
|
-
if (!
|
|
11513
|
-
const out = { path:
|
|
11467
|
+
if (!path44 || content == null) return null;
|
|
11468
|
+
const out = { path: path44, content };
|
|
11514
11469
|
if (typeof rec.mtimeMs === "number") out.mtimeMs = rec.mtimeMs;
|
|
11515
11470
|
return out;
|
|
11516
11471
|
}).filter((m2) => m2 !== null);
|
|
@@ -20425,7 +20380,7 @@ var require_websocket_server = __commonJS({
|
|
|
20425
20380
|
// src/run-case/recorder.ts
|
|
20426
20381
|
function startRunCaseRecorder(opts) {
|
|
20427
20382
|
const now = opts.now ?? Date.now;
|
|
20428
|
-
const dir =
|
|
20383
|
+
const dir = import_node_path30.default.dirname(opts.recordPath);
|
|
20429
20384
|
let stream = null;
|
|
20430
20385
|
let closing = false;
|
|
20431
20386
|
let closedSettled = false;
|
|
@@ -20439,8 +20394,8 @@ function startRunCaseRecorder(opts) {
|
|
|
20439
20394
|
});
|
|
20440
20395
|
const ensureStream = () => {
|
|
20441
20396
|
if (stream) return stream;
|
|
20442
|
-
|
|
20443
|
-
stream =
|
|
20397
|
+
import_node_fs27.default.mkdirSync(dir, { recursive: true });
|
|
20398
|
+
stream = import_node_fs27.default.createWriteStream(opts.recordPath, { flags: "a" });
|
|
20444
20399
|
stream.on("close", () => closedResolve());
|
|
20445
20400
|
return stream;
|
|
20446
20401
|
};
|
|
@@ -20465,12 +20420,12 @@ function startRunCaseRecorder(opts) {
|
|
|
20465
20420
|
};
|
|
20466
20421
|
return { tap, close, closed };
|
|
20467
20422
|
}
|
|
20468
|
-
var
|
|
20423
|
+
var import_node_fs27, import_node_path30;
|
|
20469
20424
|
var init_recorder = __esm({
|
|
20470
20425
|
"src/run-case/recorder.ts"() {
|
|
20471
20426
|
"use strict";
|
|
20472
|
-
|
|
20473
|
-
|
|
20427
|
+
import_node_fs27 = __toESM(require("fs"), 1);
|
|
20428
|
+
import_node_path30 = __toESM(require("path"), 1);
|
|
20474
20429
|
}
|
|
20475
20430
|
});
|
|
20476
20431
|
|
|
@@ -20513,7 +20468,7 @@ var init_wire = __esm({
|
|
|
20513
20468
|
// src/run-case/controller.ts
|
|
20514
20469
|
async function runController(opts) {
|
|
20515
20470
|
const now = opts.now ?? Date.now;
|
|
20516
|
-
const cwd = opts.cwd ?? (0,
|
|
20471
|
+
const cwd = opts.cwd ?? (0, import_node_fs28.mkdtempSync)(import_node_path31.default.join(import_node_os15.default.tmpdir(), "clawd-runcase-"));
|
|
20517
20472
|
const ownsCwd = opts.cwd === void 0;
|
|
20518
20473
|
const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
|
|
20519
20474
|
const spawnCtx = { cwd };
|
|
@@ -20674,19 +20629,19 @@ async function runController(opts) {
|
|
|
20674
20629
|
if (sigintHandler) process.off("SIGINT", sigintHandler);
|
|
20675
20630
|
if (ownsCwd) {
|
|
20676
20631
|
try {
|
|
20677
|
-
(0,
|
|
20632
|
+
(0, import_node_fs28.rmSync)(cwd, { recursive: true, force: true });
|
|
20678
20633
|
} catch {
|
|
20679
20634
|
}
|
|
20680
20635
|
}
|
|
20681
20636
|
return exitCode ?? 0;
|
|
20682
20637
|
}
|
|
20683
|
-
var
|
|
20638
|
+
var import_node_fs28, import_node_os15, import_node_path31;
|
|
20684
20639
|
var init_controller = __esm({
|
|
20685
20640
|
"src/run-case/controller.ts"() {
|
|
20686
20641
|
"use strict";
|
|
20687
|
-
|
|
20688
|
-
|
|
20689
|
-
|
|
20642
|
+
import_node_fs28 = require("fs");
|
|
20643
|
+
import_node_os15 = __toESM(require("os"), 1);
|
|
20644
|
+
import_node_path31 = __toESM(require("path"), 1);
|
|
20690
20645
|
init_claude();
|
|
20691
20646
|
init_stdout_splitter();
|
|
20692
20647
|
init_permission_stdio();
|
|
@@ -20918,8 +20873,8 @@ Env (advanced):
|
|
|
20918
20873
|
`;
|
|
20919
20874
|
|
|
20920
20875
|
// src/index.ts
|
|
20921
|
-
var
|
|
20922
|
-
var
|
|
20876
|
+
var import_node_path29 = __toESM(require("path"), 1);
|
|
20877
|
+
var import_node_fs26 = __toESM(require("fs"), 1);
|
|
20923
20878
|
|
|
20924
20879
|
// src/logger.ts
|
|
20925
20880
|
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
@@ -22907,25 +22862,6 @@ var SessionManager = class {
|
|
|
22907
22862
|
const file = this.getFile(args.sessionId);
|
|
22908
22863
|
return { response: file, broadcast: [] };
|
|
22909
22864
|
}
|
|
22910
|
-
// mirror peer sessions (2026-05-26):把来自朋友 daemon 的 SessionFile(originOwnerPrincipalId
|
|
22911
|
-
// 非空)持久化到本机 default store。dumb write,**不广播 push 帧**——UI 是写入唯一源,
|
|
22912
|
-
// 双写完成后通过 cache.setData 同步 sidebar 本地 state。
|
|
22913
|
-
//
|
|
22914
|
-
// 强制走 deps.store(即 default scope),不走 scopeForFile:即使 mirror SessionFile 带
|
|
22915
|
-
// 远端 ownerPersonaId(远端 persona session),本机也落 default,不创建本机 persona 目录。
|
|
22916
|
-
// 远端 creator / origin 字段原值保留(不被本机 ctx 派生覆写)。
|
|
22917
|
-
//
|
|
22918
|
-
// 与 manager.create / manager.update 区别:
|
|
22919
|
-
// - 不走 newRunner / attachObserver / cwd 校验(mirror 是纯 metadata 层)
|
|
22920
|
-
// - 不发 session:info 帧(manager.create / .update 通过 reducer/wireCollector 发 push)
|
|
22921
|
-
mirrorUpsert(file) {
|
|
22922
|
-
return this.deps.store.write(file);
|
|
22923
|
-
}
|
|
22924
|
-
// mirror peer sessions:删本机 mirror SessionFile。强制 default store。
|
|
22925
|
-
// idempotent:找不到不 throw(UI 反复点删容错)。**不广播 session:deleted**。
|
|
22926
|
-
mirrorRemove(sessionId) {
|
|
22927
|
-
this.deps.store.delete(sessionId);
|
|
22928
|
-
}
|
|
22929
22865
|
// observer 上报"jsonl 写入了一条 user 行"时调用:在 buffer 里找到与之对应的、
|
|
22930
22866
|
// 还没建立映射的最早一条 synth user_text,记下 synth → real 映射。
|
|
22931
22867
|
// 找不到匹配的 synth(runner 不存在 / buffer 已被 /clear 清空 / 真 uuid 来自纯 history
|
|
@@ -25573,11 +25509,18 @@ var AgentsScanner = class {
|
|
|
25573
25509
|
};
|
|
25574
25510
|
|
|
25575
25511
|
// src/observer/session-observer.ts
|
|
25512
|
+
var import_node_fs13 = __toESM(require("fs"), 1);
|
|
25513
|
+
var import_node_os9 = __toESM(require("os"), 1);
|
|
25514
|
+
var import_node_path14 = __toESM(require("path"), 1);
|
|
25515
|
+
init_claude_history();
|
|
25516
|
+
|
|
25517
|
+
// src/observer/subagent-meta-observer.ts
|
|
25576
25518
|
var import_node_fs12 = __toESM(require("fs"), 1);
|
|
25577
25519
|
var import_node_os8 = __toESM(require("os"), 1);
|
|
25578
25520
|
var import_node_path13 = __toESM(require("path"), 1);
|
|
25579
25521
|
init_claude_history();
|
|
25580
|
-
var
|
|
25522
|
+
var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
|
|
25523
|
+
var SubagentMetaObserver = class {
|
|
25581
25524
|
constructor(opts) {
|
|
25582
25525
|
this.opts = opts;
|
|
25583
25526
|
this.home = opts.home ?? import_node_os8.default.homedir();
|
|
@@ -25585,16 +25528,132 @@ var SessionObserver = class {
|
|
|
25585
25528
|
opts;
|
|
25586
25529
|
home;
|
|
25587
25530
|
watches = /* @__PURE__ */ new Map();
|
|
25531
|
+
// public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
|
|
25532
|
+
resolveSubagentDir(cwd, toolSessionId) {
|
|
25533
|
+
return import_node_path13.default.join(
|
|
25534
|
+
this.home,
|
|
25535
|
+
".claude",
|
|
25536
|
+
"projects",
|
|
25537
|
+
cwdToHashDir(cwd),
|
|
25538
|
+
toolSessionId,
|
|
25539
|
+
"subagents"
|
|
25540
|
+
);
|
|
25541
|
+
}
|
|
25542
|
+
start(args) {
|
|
25543
|
+
this.stop(args.sessionId);
|
|
25544
|
+
const dirPath = this.resolveSubagentDir(args.cwd, args.toolSessionId);
|
|
25545
|
+
const w2 = {
|
|
25546
|
+
sessionId: args.sessionId,
|
|
25547
|
+
dirPath,
|
|
25548
|
+
watcher: null,
|
|
25549
|
+
pollTimer: null,
|
|
25550
|
+
emitted: /* @__PURE__ */ new Set()
|
|
25551
|
+
};
|
|
25552
|
+
this.watches.set(args.sessionId, w2);
|
|
25553
|
+
this.scan(w2);
|
|
25554
|
+
this.attachWatcher(w2);
|
|
25555
|
+
w2.pollTimer = setInterval(() => this.scan(w2), 200);
|
|
25556
|
+
return { dirPath };
|
|
25557
|
+
}
|
|
25558
|
+
// fs.watch 必须在目录存在后调用;首次启动时 subagents/ 通常不存在 —— attachWatcher
|
|
25559
|
+
// 失败就交给 pollTimer 200ms 兜底,目录一出现就被下次 poll 捡起来,那时也尝试 attach
|
|
25560
|
+
attachWatcher(w2) {
|
|
25561
|
+
if (w2.watcher) return;
|
|
25562
|
+
try {
|
|
25563
|
+
w2.watcher = import_node_fs12.default.watch(w2.dirPath, { persistent: false }, (_evt, name) => {
|
|
25564
|
+
if (!name) return;
|
|
25565
|
+
const m2 = META_RE.exec(String(name));
|
|
25566
|
+
if (!m2) return;
|
|
25567
|
+
this.scanOne(w2, String(name));
|
|
25568
|
+
});
|
|
25569
|
+
} catch {
|
|
25570
|
+
}
|
|
25571
|
+
}
|
|
25572
|
+
scan(w2) {
|
|
25573
|
+
let entries;
|
|
25574
|
+
try {
|
|
25575
|
+
entries = import_node_fs12.default.readdirSync(w2.dirPath);
|
|
25576
|
+
} catch {
|
|
25577
|
+
return;
|
|
25578
|
+
}
|
|
25579
|
+
if (!w2.watcher) this.attachWatcher(w2);
|
|
25580
|
+
for (const name of entries) {
|
|
25581
|
+
this.scanOne(w2, name);
|
|
25582
|
+
}
|
|
25583
|
+
}
|
|
25584
|
+
scanOne(w2, name) {
|
|
25585
|
+
const m2 = META_RE.exec(name);
|
|
25586
|
+
if (!m2) return;
|
|
25587
|
+
const agentId = m2[1];
|
|
25588
|
+
if (w2.emitted.has(agentId)) return;
|
|
25589
|
+
const file = import_node_path13.default.join(w2.dirPath, name);
|
|
25590
|
+
let raw;
|
|
25591
|
+
try {
|
|
25592
|
+
raw = import_node_fs12.default.readFileSync(file, "utf8");
|
|
25593
|
+
} catch {
|
|
25594
|
+
return;
|
|
25595
|
+
}
|
|
25596
|
+
let obj;
|
|
25597
|
+
try {
|
|
25598
|
+
obj = JSON.parse(raw);
|
|
25599
|
+
} catch {
|
|
25600
|
+
return;
|
|
25601
|
+
}
|
|
25602
|
+
const toolUseId = typeof obj.toolUseId === "string" ? obj.toolUseId : "";
|
|
25603
|
+
if (!toolUseId) return;
|
|
25604
|
+
w2.emitted.add(agentId);
|
|
25605
|
+
const ev = {
|
|
25606
|
+
kind: "subagent_progress",
|
|
25607
|
+
toolUseId,
|
|
25608
|
+
agentId,
|
|
25609
|
+
status: "started"
|
|
25610
|
+
};
|
|
25611
|
+
if (typeof obj.description === "string" && obj.description) ev.description = obj.description;
|
|
25612
|
+
this.opts.onEvent({ sessionId: w2.sessionId, events: [ev] });
|
|
25613
|
+
}
|
|
25614
|
+
isObserving(sessionId) {
|
|
25615
|
+
return this.watches.has(sessionId);
|
|
25616
|
+
}
|
|
25617
|
+
stop(sessionId) {
|
|
25618
|
+
const w2 = this.watches.get(sessionId);
|
|
25619
|
+
if (!w2) return false;
|
|
25620
|
+
try {
|
|
25621
|
+
w2.watcher?.close();
|
|
25622
|
+
} catch {
|
|
25623
|
+
}
|
|
25624
|
+
if (w2.pollTimer) clearInterval(w2.pollTimer);
|
|
25625
|
+
this.watches.delete(sessionId);
|
|
25626
|
+
return true;
|
|
25627
|
+
}
|
|
25628
|
+
stopAll() {
|
|
25629
|
+
for (const id of [...this.watches.keys()]) this.stop(id);
|
|
25630
|
+
}
|
|
25631
|
+
};
|
|
25632
|
+
|
|
25633
|
+
// src/observer/session-observer.ts
|
|
25634
|
+
var SessionObserver = class {
|
|
25635
|
+
constructor(opts) {
|
|
25636
|
+
this.opts = opts;
|
|
25637
|
+
this.home = opts.home ?? import_node_os9.default.homedir();
|
|
25638
|
+
this.metaObserver = opts.enableSubagentMetaObserver ? new SubagentMetaObserver({ home: this.home, onEvent: opts.onEvent }) : null;
|
|
25639
|
+
}
|
|
25640
|
+
opts;
|
|
25641
|
+
home;
|
|
25642
|
+
watches = /* @__PURE__ */ new Map();
|
|
25643
|
+
// 子 observer:监听 <projectsRoot>/<hashDir>/<toolSessionId>/subagents/ 目录的 meta.json,
|
|
25644
|
+
// 仅 TUI 模式启用——SDK 模式靠 `system.task_started` 帧(claude.ts:466)emit subagent_progress
|
|
25645
|
+
// 已经能解锁 AgentCallLine 抽屉入口,再跑 meta watcher 会让 ring buffer 留双帧
|
|
25646
|
+
metaObserver;
|
|
25588
25647
|
resolveJsonlPath(cwd, toolSessionId, override) {
|
|
25589
25648
|
if (override) return override;
|
|
25590
|
-
return
|
|
25649
|
+
return import_node_path14.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
|
|
25591
25650
|
}
|
|
25592
25651
|
start(args) {
|
|
25593
25652
|
this.stop(args.sessionId);
|
|
25594
25653
|
const filePath = this.resolveJsonlPath(args.cwd, args.toolSessionId, args.jsonlPath);
|
|
25595
25654
|
let size = 0;
|
|
25596
25655
|
try {
|
|
25597
|
-
size =
|
|
25656
|
+
size = import_node_fs13.default.statSync(filePath).size;
|
|
25598
25657
|
} catch {
|
|
25599
25658
|
}
|
|
25600
25659
|
const w2 = {
|
|
@@ -25607,10 +25666,10 @@ var SessionObserver = class {
|
|
|
25607
25666
|
adapter: args.adapter
|
|
25608
25667
|
};
|
|
25609
25668
|
try {
|
|
25610
|
-
|
|
25669
|
+
import_node_fs13.default.mkdirSync(import_node_path14.default.dirname(filePath), { recursive: true });
|
|
25611
25670
|
} catch {
|
|
25612
25671
|
}
|
|
25613
|
-
w2.watcher =
|
|
25672
|
+
w2.watcher = import_node_fs13.default.watch(import_node_path14.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
|
|
25614
25673
|
if (!changedName || !filePath.endsWith(changedName)) return;
|
|
25615
25674
|
this.poll(w2);
|
|
25616
25675
|
});
|
|
@@ -25619,6 +25678,11 @@ var SessionObserver = class {
|
|
|
25619
25678
|
this.opts.onStatus?.(args.sessionId, "observing");
|
|
25620
25679
|
this.hydrateMetaTail(w2);
|
|
25621
25680
|
this.poll(w2);
|
|
25681
|
+
this.metaObserver?.start({
|
|
25682
|
+
sessionId: args.sessionId,
|
|
25683
|
+
cwd: args.cwd,
|
|
25684
|
+
toolSessionId: args.toolSessionId
|
|
25685
|
+
});
|
|
25622
25686
|
return { filePath };
|
|
25623
25687
|
}
|
|
25624
25688
|
// 读 JSONL 文件尾部 N 行,把每行的 meta_update 字段**合并成一个 patch** 喂给 reducer。
|
|
@@ -25628,7 +25692,7 @@ var SessionObserver = class {
|
|
|
25628
25692
|
// 异常静默吞,不阻塞 watcher 启动
|
|
25629
25693
|
hydrateMetaTail(w2, maxLines = 200) {
|
|
25630
25694
|
try {
|
|
25631
|
-
const raw =
|
|
25695
|
+
const raw = import_node_fs13.default.readFileSync(w2.filePath, "utf8");
|
|
25632
25696
|
if (!raw) return;
|
|
25633
25697
|
const allLines = raw.split("\n").filter((l) => l.trim().length > 0);
|
|
25634
25698
|
if (allLines.length === 0) return;
|
|
@@ -25652,7 +25716,7 @@ var SessionObserver = class {
|
|
|
25652
25716
|
poll(w2) {
|
|
25653
25717
|
let size = 0;
|
|
25654
25718
|
try {
|
|
25655
|
-
size =
|
|
25719
|
+
size = import_node_fs13.default.statSync(w2.filePath).size;
|
|
25656
25720
|
} catch {
|
|
25657
25721
|
return;
|
|
25658
25722
|
}
|
|
@@ -25661,11 +25725,11 @@ var SessionObserver = class {
|
|
|
25661
25725
|
w2.buf = "";
|
|
25662
25726
|
}
|
|
25663
25727
|
if (size === w2.lastSize) return;
|
|
25664
|
-
const fd =
|
|
25728
|
+
const fd = import_node_fs13.default.openSync(w2.filePath, "r");
|
|
25665
25729
|
try {
|
|
25666
25730
|
const len = size - w2.lastSize;
|
|
25667
25731
|
const buf = Buffer.alloc(len);
|
|
25668
|
-
|
|
25732
|
+
import_node_fs13.default.readSync(fd, buf, 0, len, w2.lastSize);
|
|
25669
25733
|
w2.lastSize = size;
|
|
25670
25734
|
w2.buf += buf.toString("utf8");
|
|
25671
25735
|
let newlineIndex;
|
|
@@ -25679,7 +25743,7 @@ var SessionObserver = class {
|
|
|
25679
25743
|
}
|
|
25680
25744
|
}
|
|
25681
25745
|
} finally {
|
|
25682
|
-
|
|
25746
|
+
import_node_fs13.default.closeSync(fd);
|
|
25683
25747
|
}
|
|
25684
25748
|
}
|
|
25685
25749
|
// 解析 JSONL 单行:仅当是主链 user 文本行(非 sidechain / 非 sub-agent / message.role='user'
|
|
@@ -25732,11 +25796,13 @@ var SessionObserver = class {
|
|
|
25732
25796
|
}
|
|
25733
25797
|
if (w2.pollTimer) clearInterval(w2.pollTimer);
|
|
25734
25798
|
this.watches.delete(sessionId);
|
|
25799
|
+
this.metaObserver?.stop(sessionId);
|
|
25735
25800
|
this.opts.onStatus?.(sessionId, "stopped");
|
|
25736
25801
|
return true;
|
|
25737
25802
|
}
|
|
25738
25803
|
stopAll() {
|
|
25739
25804
|
for (const id of [...this.watches.keys()]) this.stop(id);
|
|
25805
|
+
this.metaObserver?.stopAll();
|
|
25740
25806
|
}
|
|
25741
25807
|
};
|
|
25742
25808
|
|
|
@@ -26337,14 +26403,14 @@ function authenticate(token, deps) {
|
|
|
26337
26403
|
}
|
|
26338
26404
|
|
|
26339
26405
|
// src/permission/capability-store.ts
|
|
26340
|
-
var
|
|
26341
|
-
var
|
|
26406
|
+
var fs16 = __toESM(require("fs"), 1);
|
|
26407
|
+
var path19 = __toESM(require("path"), 1);
|
|
26342
26408
|
var CAPABILITIES_FILE_NAME = "capabilities.json";
|
|
26343
26409
|
var FILE_VERSION = 1;
|
|
26344
26410
|
var CapabilityStore = class {
|
|
26345
26411
|
constructor(dataDir) {
|
|
26346
26412
|
this.dataDir = dataDir;
|
|
26347
|
-
|
|
26413
|
+
fs16.mkdirSync(dataDir, { recursive: true });
|
|
26348
26414
|
this.cache = this.readFromDisk();
|
|
26349
26415
|
}
|
|
26350
26416
|
dataDir;
|
|
@@ -26368,13 +26434,13 @@ var CapabilityStore = class {
|
|
|
26368
26434
|
this.flush();
|
|
26369
26435
|
}
|
|
26370
26436
|
filePath() {
|
|
26371
|
-
return
|
|
26437
|
+
return path19.join(this.dataDir, CAPABILITIES_FILE_NAME);
|
|
26372
26438
|
}
|
|
26373
26439
|
readFromDisk() {
|
|
26374
26440
|
const file = this.filePath();
|
|
26375
26441
|
let raw;
|
|
26376
26442
|
try {
|
|
26377
|
-
raw =
|
|
26443
|
+
raw = fs16.readFileSync(file, "utf8");
|
|
26378
26444
|
} catch (err) {
|
|
26379
26445
|
if (err?.code === "ENOENT") return [];
|
|
26380
26446
|
return [];
|
|
@@ -26402,10 +26468,10 @@ var CapabilityStore = class {
|
|
|
26402
26468
|
}
|
|
26403
26469
|
atomicWrite(file, content) {
|
|
26404
26470
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
26405
|
-
|
|
26406
|
-
|
|
26471
|
+
fs16.writeFileSync(tmp, content, { mode: 384 });
|
|
26472
|
+
fs16.renameSync(tmp, file);
|
|
26407
26473
|
try {
|
|
26408
|
-
|
|
26474
|
+
fs16.chmodSync(file, 384);
|
|
26409
26475
|
} catch {
|
|
26410
26476
|
}
|
|
26411
26477
|
}
|
|
@@ -26498,14 +26564,14 @@ var CapabilityManager = class {
|
|
|
26498
26564
|
};
|
|
26499
26565
|
|
|
26500
26566
|
// src/permission/cleanup.ts
|
|
26501
|
-
var
|
|
26567
|
+
var fs17 = __toESM(require("fs"), 1);
|
|
26502
26568
|
function cleanupGuestSessionsForCapability(cap, factory) {
|
|
26503
26569
|
const removed = [];
|
|
26504
26570
|
for (const g2 of cap.grants) {
|
|
26505
26571
|
if (g2.resource.type !== "persona") continue;
|
|
26506
26572
|
const dir = factory.vmGuestRoot(g2.resource.id, cap.id);
|
|
26507
26573
|
try {
|
|
26508
|
-
|
|
26574
|
+
fs17.rmSync(dir, { recursive: true, force: true });
|
|
26509
26575
|
removed.push(dir);
|
|
26510
26576
|
} catch {
|
|
26511
26577
|
}
|
|
@@ -26514,13 +26580,13 @@ function cleanupGuestSessionsForCapability(cap, factory) {
|
|
|
26514
26580
|
}
|
|
26515
26581
|
|
|
26516
26582
|
// src/permission/personal-capability.ts
|
|
26517
|
-
var
|
|
26518
|
-
var
|
|
26583
|
+
var import_node_fs14 = __toESM(require("fs"), 1);
|
|
26584
|
+
var import_node_path15 = __toESM(require("path"), 1);
|
|
26519
26585
|
var import_node_crypto4 = __toESM(require("crypto"), 1);
|
|
26520
26586
|
var PERSONAL_CAP_FILE_NAME = "personal-capability.json";
|
|
26521
26587
|
var PERSONAL_CAP_DISPLAY_NAME = "personal";
|
|
26522
26588
|
function personalCapFilePath(dataDir) {
|
|
26523
|
-
return
|
|
26589
|
+
return import_node_path15.default.join(dataDir, PERSONAL_CAP_FILE_NAME);
|
|
26524
26590
|
}
|
|
26525
26591
|
function loadOrCreatePersonalCapability(opts) {
|
|
26526
26592
|
const file = personalCapFilePath(opts.dataDir);
|
|
@@ -26550,7 +26616,7 @@ function loadOrCreatePersonalCapability(opts) {
|
|
|
26550
26616
|
function readFile(file) {
|
|
26551
26617
|
let raw;
|
|
26552
26618
|
try {
|
|
26553
|
-
raw =
|
|
26619
|
+
raw = import_node_fs14.default.readFileSync(file, "utf8");
|
|
26554
26620
|
} catch (err) {
|
|
26555
26621
|
const code = err?.code;
|
|
26556
26622
|
if (code === "ENOENT") return null;
|
|
@@ -26571,10 +26637,10 @@ function readFile(file) {
|
|
|
26571
26637
|
return { token: obj.token, capability: capParsed.data };
|
|
26572
26638
|
}
|
|
26573
26639
|
function writeFile(file, content) {
|
|
26574
|
-
|
|
26575
|
-
|
|
26640
|
+
import_node_fs14.default.mkdirSync(import_node_path15.default.dirname(file), { recursive: true });
|
|
26641
|
+
import_node_fs14.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
|
|
26576
26642
|
try {
|
|
26577
|
-
|
|
26643
|
+
import_node_fs14.default.chmodSync(file, 384);
|
|
26578
26644
|
} catch {
|
|
26579
26645
|
}
|
|
26580
26646
|
}
|
|
@@ -26589,13 +26655,13 @@ function sha256Hex2(s) {
|
|
|
26589
26655
|
}
|
|
26590
26656
|
|
|
26591
26657
|
// src/inbox/inbox-store.ts
|
|
26592
|
-
var
|
|
26593
|
-
var
|
|
26658
|
+
var fs19 = __toESM(require("fs"), 1);
|
|
26659
|
+
var path21 = __toESM(require("path"), 1);
|
|
26594
26660
|
var INBOX_SUBDIR = "inbox";
|
|
26595
26661
|
var InboxStore = class {
|
|
26596
26662
|
constructor(dataDir) {
|
|
26597
26663
|
this.dataDir = dataDir;
|
|
26598
|
-
|
|
26664
|
+
fs19.mkdirSync(this.dirPath(), { recursive: true });
|
|
26599
26665
|
}
|
|
26600
26666
|
dataDir;
|
|
26601
26667
|
/**
|
|
@@ -26607,7 +26673,7 @@ var InboxStore = class {
|
|
|
26607
26673
|
const file = this.filePath(peerOwnerId);
|
|
26608
26674
|
let raw;
|
|
26609
26675
|
try {
|
|
26610
|
-
raw =
|
|
26676
|
+
raw = fs19.readFileSync(file, "utf8");
|
|
26611
26677
|
} catch (err) {
|
|
26612
26678
|
if (err?.code === "ENOENT") return [];
|
|
26613
26679
|
return [];
|
|
@@ -26623,7 +26689,7 @@ var InboxStore = class {
|
|
|
26623
26689
|
const dir = this.dirPath();
|
|
26624
26690
|
let entries;
|
|
26625
26691
|
try {
|
|
26626
|
-
entries =
|
|
26692
|
+
entries = fs19.readdirSync(dir);
|
|
26627
26693
|
} catch (err) {
|
|
26628
26694
|
if (err?.code === "ENOENT") return [];
|
|
26629
26695
|
return [];
|
|
@@ -26639,9 +26705,9 @@ var InboxStore = class {
|
|
|
26639
26705
|
if (existing.some((m2) => m2.id === message.id)) return;
|
|
26640
26706
|
const file = this.filePath(message.peerOwnerId);
|
|
26641
26707
|
const line = JSON.stringify(message) + "\n";
|
|
26642
|
-
|
|
26708
|
+
fs19.appendFileSync(file, line, { mode: 384 });
|
|
26643
26709
|
try {
|
|
26644
|
-
|
|
26710
|
+
fs19.chmodSync(file, 384);
|
|
26645
26711
|
} catch {
|
|
26646
26712
|
}
|
|
26647
26713
|
}
|
|
@@ -26671,7 +26737,7 @@ var InboxStore = class {
|
|
|
26671
26737
|
removeByPeerOwnerId(peerOwnerId) {
|
|
26672
26738
|
const file = this.filePath(peerOwnerId);
|
|
26673
26739
|
try {
|
|
26674
|
-
|
|
26740
|
+
fs19.unlinkSync(file);
|
|
26675
26741
|
} catch (err) {
|
|
26676
26742
|
if (err?.code === "ENOENT") return;
|
|
26677
26743
|
}
|
|
@@ -26680,18 +26746,18 @@ var InboxStore = class {
|
|
|
26680
26746
|
const file = this.filePath(peerOwnerId);
|
|
26681
26747
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
26682
26748
|
const content = messages.map((m2) => JSON.stringify(m2)).join("\n") + (messages.length > 0 ? "\n" : "");
|
|
26683
|
-
|
|
26684
|
-
|
|
26749
|
+
fs19.writeFileSync(tmp, content, { mode: 384 });
|
|
26750
|
+
fs19.renameSync(tmp, file);
|
|
26685
26751
|
try {
|
|
26686
|
-
|
|
26752
|
+
fs19.chmodSync(file, 384);
|
|
26687
26753
|
} catch {
|
|
26688
26754
|
}
|
|
26689
26755
|
}
|
|
26690
26756
|
dirPath() {
|
|
26691
|
-
return
|
|
26757
|
+
return path21.join(this.dataDir, INBOX_SUBDIR);
|
|
26692
26758
|
}
|
|
26693
26759
|
filePath(peerOwnerId) {
|
|
26694
|
-
return
|
|
26760
|
+
return path21.join(this.dirPath(), `${peerOwnerId}.jsonl`);
|
|
26695
26761
|
}
|
|
26696
26762
|
};
|
|
26697
26763
|
function parseAllLines(raw) {
|
|
@@ -26778,8 +26844,8 @@ var InboxManager = class {
|
|
|
26778
26844
|
};
|
|
26779
26845
|
|
|
26780
26846
|
// src/state/received-capability-store.ts
|
|
26781
|
-
var
|
|
26782
|
-
var
|
|
26847
|
+
var fs20 = __toESM(require("fs"), 1);
|
|
26848
|
+
var path22 = __toESM(require("path"), 1);
|
|
26783
26849
|
var FILE_NAME = "received-capabilities.json";
|
|
26784
26850
|
var ReceivedCapabilityStore = class {
|
|
26785
26851
|
constructor(dataDir) {
|
|
@@ -26789,10 +26855,10 @@ var ReceivedCapabilityStore = class {
|
|
|
26789
26855
|
caps = /* @__PURE__ */ new Map();
|
|
26790
26856
|
load() {
|
|
26791
26857
|
this.caps.clear();
|
|
26792
|
-
const file =
|
|
26858
|
+
const file = path22.join(this.dataDir, FILE_NAME);
|
|
26793
26859
|
let raw;
|
|
26794
26860
|
try {
|
|
26795
|
-
raw =
|
|
26861
|
+
raw = fs20.readFileSync(file, "utf8");
|
|
26796
26862
|
} catch (err) {
|
|
26797
26863
|
if (err?.code !== "ENOENT") this.renameBak(file);
|
|
26798
26864
|
return;
|
|
@@ -26829,20 +26895,20 @@ var ReceivedCapabilityStore = class {
|
|
|
26829
26895
|
this.flush();
|
|
26830
26896
|
}
|
|
26831
26897
|
flush() {
|
|
26832
|
-
const file =
|
|
26898
|
+
const file = path22.join(this.dataDir, FILE_NAME);
|
|
26833
26899
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
26834
26900
|
const content = JSON.stringify(
|
|
26835
26901
|
{ receivedCaps: Array.from(this.caps.values()) },
|
|
26836
26902
|
null,
|
|
26837
26903
|
2
|
|
26838
26904
|
);
|
|
26839
|
-
|
|
26840
|
-
|
|
26841
|
-
|
|
26905
|
+
fs20.mkdirSync(this.dataDir, { recursive: true });
|
|
26906
|
+
fs20.writeFileSync(tmp, content, { mode: 384 });
|
|
26907
|
+
fs20.renameSync(tmp, file);
|
|
26842
26908
|
}
|
|
26843
26909
|
renameBak(file) {
|
|
26844
26910
|
try {
|
|
26845
|
-
|
|
26911
|
+
fs20.renameSync(file, `${file}.bak`);
|
|
26846
26912
|
} catch {
|
|
26847
26913
|
}
|
|
26848
26914
|
}
|
|
@@ -26940,61 +27006,61 @@ async function connectRemote(args) {
|
|
|
26940
27006
|
}
|
|
26941
27007
|
|
|
26942
27008
|
// src/migrations/2026-05-20-flatten-sessions.ts
|
|
26943
|
-
var
|
|
26944
|
-
var
|
|
27009
|
+
var fs21 = __toESM(require("fs"), 1);
|
|
27010
|
+
var path23 = __toESM(require("path"), 1);
|
|
26945
27011
|
var MIGRATION_FLAG_NAME = ".migration.v1.done";
|
|
26946
27012
|
function migrateFlattenSessions(opts) {
|
|
26947
27013
|
const dataDir = opts.dataDir;
|
|
26948
27014
|
const now = opts.now ?? Date.now;
|
|
26949
|
-
const sessionsDir =
|
|
26950
|
-
const flagPath =
|
|
27015
|
+
const sessionsDir = path23.join(dataDir, "sessions");
|
|
27016
|
+
const flagPath = path23.join(sessionsDir, MIGRATION_FLAG_NAME);
|
|
26951
27017
|
if (existsSync3(flagPath)) {
|
|
26952
27018
|
return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
|
|
26953
27019
|
}
|
|
26954
27020
|
let movedBare = 0;
|
|
26955
27021
|
let movedVmOwner = 0;
|
|
26956
27022
|
let archivedListener = 0;
|
|
26957
|
-
const defaultDir =
|
|
27023
|
+
const defaultDir = path23.join(sessionsDir, "default");
|
|
26958
27024
|
if (existsSync3(defaultDir)) {
|
|
26959
27025
|
for (const entry of readdirSafe(defaultDir)) {
|
|
26960
27026
|
if (!entry.endsWith(".json")) continue;
|
|
26961
|
-
const src =
|
|
26962
|
-
const dst =
|
|
26963
|
-
|
|
27027
|
+
const src = path23.join(defaultDir, entry);
|
|
27028
|
+
const dst = path23.join(sessionsDir, entry);
|
|
27029
|
+
fs21.renameSync(src, dst);
|
|
26964
27030
|
movedBare += 1;
|
|
26965
27031
|
}
|
|
26966
27032
|
rmdirIfEmpty(defaultDir);
|
|
26967
27033
|
}
|
|
26968
27034
|
for (const pid of readdirSafe(sessionsDir)) {
|
|
26969
|
-
const personaDir =
|
|
27035
|
+
const personaDir = path23.join(sessionsDir, pid);
|
|
26970
27036
|
if (!isDir(personaDir)) continue;
|
|
26971
27037
|
if (pid === "default") continue;
|
|
26972
|
-
const ownerSrc =
|
|
27038
|
+
const ownerSrc = path23.join(personaDir, "owner");
|
|
26973
27039
|
if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
|
|
26974
|
-
const ownerDst =
|
|
26975
|
-
|
|
27040
|
+
const ownerDst = path23.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
|
|
27041
|
+
fs21.mkdirSync(ownerDst, { recursive: true });
|
|
26976
27042
|
for (const file of readdirSafe(ownerSrc)) {
|
|
26977
27043
|
if (!file.endsWith(".json")) continue;
|
|
26978
|
-
|
|
27044
|
+
fs21.renameSync(path23.join(ownerSrc, file), path23.join(ownerDst, file));
|
|
26979
27045
|
movedVmOwner += 1;
|
|
26980
27046
|
}
|
|
26981
27047
|
rmdirIfEmpty(ownerSrc);
|
|
26982
27048
|
}
|
|
26983
|
-
const listenerSrc =
|
|
27049
|
+
const listenerSrc = path23.join(personaDir, "listener");
|
|
26984
27050
|
if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
|
|
26985
|
-
const archiveDst =
|
|
26986
|
-
|
|
27051
|
+
const archiveDst = path23.join(dataDir, ".legacy", `listener-${pid}`);
|
|
27052
|
+
fs21.mkdirSync(archiveDst, { recursive: true });
|
|
26987
27053
|
for (const file of readdirSafe(listenerSrc)) {
|
|
26988
27054
|
if (!file.endsWith(".json")) continue;
|
|
26989
|
-
|
|
27055
|
+
fs21.renameSync(path23.join(listenerSrc, file), path23.join(archiveDst, file));
|
|
26990
27056
|
archivedListener += 1;
|
|
26991
27057
|
}
|
|
26992
27058
|
rmdirIfEmpty(listenerSrc);
|
|
26993
27059
|
}
|
|
26994
27060
|
rmdirIfEmpty(personaDir);
|
|
26995
27061
|
}
|
|
26996
|
-
|
|
26997
|
-
|
|
27062
|
+
fs21.mkdirSync(sessionsDir, { recursive: true });
|
|
27063
|
+
fs21.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
|
|
26998
27064
|
return {
|
|
26999
27065
|
skipped: false,
|
|
27000
27066
|
flagWritten: true,
|
|
@@ -27005,7 +27071,7 @@ function migrateFlattenSessions(opts) {
|
|
|
27005
27071
|
}
|
|
27006
27072
|
function existsSync3(p2) {
|
|
27007
27073
|
try {
|
|
27008
|
-
|
|
27074
|
+
fs21.statSync(p2);
|
|
27009
27075
|
return true;
|
|
27010
27076
|
} catch {
|
|
27011
27077
|
return false;
|
|
@@ -27013,31 +27079,31 @@ function existsSync3(p2) {
|
|
|
27013
27079
|
}
|
|
27014
27080
|
function isDir(p2) {
|
|
27015
27081
|
try {
|
|
27016
|
-
return
|
|
27082
|
+
return fs21.statSync(p2).isDirectory();
|
|
27017
27083
|
} catch {
|
|
27018
27084
|
return false;
|
|
27019
27085
|
}
|
|
27020
27086
|
}
|
|
27021
27087
|
function readdirSafe(p2) {
|
|
27022
27088
|
try {
|
|
27023
|
-
return
|
|
27089
|
+
return fs21.readdirSync(p2);
|
|
27024
27090
|
} catch {
|
|
27025
27091
|
return [];
|
|
27026
27092
|
}
|
|
27027
27093
|
}
|
|
27028
27094
|
function rmdirIfEmpty(p2) {
|
|
27029
27095
|
try {
|
|
27030
|
-
|
|
27096
|
+
fs21.rmdirSync(p2);
|
|
27031
27097
|
} catch {
|
|
27032
27098
|
}
|
|
27033
27099
|
}
|
|
27034
27100
|
|
|
27035
27101
|
// src/transport/http-router.ts
|
|
27036
|
-
var
|
|
27037
|
-
var
|
|
27102
|
+
var import_node_fs15 = __toESM(require("fs"), 1);
|
|
27103
|
+
var import_node_path17 = __toESM(require("path"), 1);
|
|
27038
27104
|
|
|
27039
27105
|
// src/attachment/mime.ts
|
|
27040
|
-
var
|
|
27106
|
+
var import_node_path16 = __toESM(require("path"), 1);
|
|
27041
27107
|
var TEXT_PLAIN = "text/plain; charset=utf-8";
|
|
27042
27108
|
var EXT_TO_NATIVE_MIME = {
|
|
27043
27109
|
// 图片
|
|
@@ -27144,7 +27210,7 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
27144
27210
|
".mk"
|
|
27145
27211
|
]);
|
|
27146
27212
|
function lookupMime(filePathOrName) {
|
|
27147
|
-
const ext =
|
|
27213
|
+
const ext = import_node_path16.default.extname(filePathOrName).toLowerCase();
|
|
27148
27214
|
if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
|
|
27149
27215
|
if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
|
|
27150
27216
|
return "application/octet-stream";
|
|
@@ -27275,7 +27341,7 @@ function createHttpRouter(deps) {
|
|
|
27275
27341
|
return true;
|
|
27276
27342
|
}
|
|
27277
27343
|
let absPath;
|
|
27278
|
-
if (
|
|
27344
|
+
if (import_node_path17.default.isAbsolute(pathParam)) {
|
|
27279
27345
|
absPath = pathParam;
|
|
27280
27346
|
} else if (deps.sessionStore) {
|
|
27281
27347
|
const file = deps.sessionStore.read(sid);
|
|
@@ -27283,7 +27349,7 @@ function createHttpRouter(deps) {
|
|
|
27283
27349
|
sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
|
|
27284
27350
|
return true;
|
|
27285
27351
|
}
|
|
27286
|
-
absPath =
|
|
27352
|
+
absPath = import_node_path17.default.join(file.cwd, pathParam);
|
|
27287
27353
|
} else {
|
|
27288
27354
|
sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
|
|
27289
27355
|
return true;
|
|
@@ -27316,7 +27382,7 @@ function withCtx(ctx, body) {
|
|
|
27316
27382
|
function streamFile(res, absPath, logger) {
|
|
27317
27383
|
let stat;
|
|
27318
27384
|
try {
|
|
27319
|
-
stat =
|
|
27385
|
+
stat = import_node_fs15.default.statSync(absPath);
|
|
27320
27386
|
} catch (err) {
|
|
27321
27387
|
const code = err?.code;
|
|
27322
27388
|
if (code === "ENOENT") {
|
|
@@ -27331,7 +27397,7 @@ function streamFile(res, absPath, logger) {
|
|
|
27331
27397
|
return;
|
|
27332
27398
|
}
|
|
27333
27399
|
const mime = lookupMime(absPath);
|
|
27334
|
-
const basename =
|
|
27400
|
+
const basename = import_node_path17.default.basename(absPath);
|
|
27335
27401
|
res.writeHead(200, {
|
|
27336
27402
|
"Content-Type": mime,
|
|
27337
27403
|
"Content-Length": String(stat.size),
|
|
@@ -27339,7 +27405,7 @@ function streamFile(res, absPath, logger) {
|
|
|
27339
27405
|
// 防止浏览器把任意 mime 当 html 渲染
|
|
27340
27406
|
"X-Content-Type-Options": "nosniff"
|
|
27341
27407
|
});
|
|
27342
|
-
const stream =
|
|
27408
|
+
const stream = import_node_fs15.default.createReadStream(absPath);
|
|
27343
27409
|
stream.on("error", (err) => {
|
|
27344
27410
|
logger?.warn("streamFile read error", { absPath, err: err.message });
|
|
27345
27411
|
res.destroy();
|
|
@@ -27348,8 +27414,8 @@ function streamFile(res, absPath, logger) {
|
|
|
27348
27414
|
}
|
|
27349
27415
|
|
|
27350
27416
|
// src/attachment/group.ts
|
|
27351
|
-
var
|
|
27352
|
-
var
|
|
27417
|
+
var import_node_fs16 = __toESM(require("fs"), 1);
|
|
27418
|
+
var import_node_path18 = __toESM(require("path"), 1);
|
|
27353
27419
|
var import_node_crypto6 = __toESM(require("crypto"), 1);
|
|
27354
27420
|
init_protocol();
|
|
27355
27421
|
var GroupFileStore = class {
|
|
@@ -27361,11 +27427,11 @@ var GroupFileStore = class {
|
|
|
27361
27427
|
this.logger = opts.logger;
|
|
27362
27428
|
}
|
|
27363
27429
|
rootForScope(scope) {
|
|
27364
|
-
return
|
|
27430
|
+
return import_node_path18.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
|
|
27365
27431
|
}
|
|
27366
27432
|
/** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
|
|
27367
27433
|
filePath(scope, sessionId) {
|
|
27368
|
-
return
|
|
27434
|
+
return import_node_path18.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
|
|
27369
27435
|
}
|
|
27370
27436
|
cacheKey(scope, sessionId) {
|
|
27371
27437
|
return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
|
|
@@ -27374,7 +27440,7 @@ var GroupFileStore = class {
|
|
|
27374
27440
|
readFile(scope, sessionId) {
|
|
27375
27441
|
const file = this.filePath(scope, sessionId);
|
|
27376
27442
|
try {
|
|
27377
|
-
const raw =
|
|
27443
|
+
const raw = import_node_fs16.default.readFileSync(file, "utf8");
|
|
27378
27444
|
const parsed = JSON.parse(raw);
|
|
27379
27445
|
if (!Array.isArray(parsed)) {
|
|
27380
27446
|
this.logger?.warn("GroupFileStore.readFile: not an array; resetting session entries", {
|
|
@@ -27400,10 +27466,10 @@ var GroupFileStore = class {
|
|
|
27400
27466
|
}
|
|
27401
27467
|
writeFile(scope, sessionId, entries) {
|
|
27402
27468
|
const file = this.filePath(scope, sessionId);
|
|
27403
|
-
|
|
27469
|
+
import_node_fs16.default.mkdirSync(import_node_path18.default.dirname(file), { recursive: true });
|
|
27404
27470
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
27405
|
-
|
|
27406
|
-
|
|
27471
|
+
import_node_fs16.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
|
|
27472
|
+
import_node_fs16.default.renameSync(tmp, file);
|
|
27407
27473
|
}
|
|
27408
27474
|
/** 拉一份当前 session 的清单。读盘 → cache;之后调用复用 cache */
|
|
27409
27475
|
list(scope, sessionId) {
|
|
@@ -27489,10 +27555,10 @@ var GroupFileStore = class {
|
|
|
27489
27555
|
};
|
|
27490
27556
|
|
|
27491
27557
|
// src/discovery/state-file.ts
|
|
27492
|
-
var
|
|
27493
|
-
var
|
|
27558
|
+
var import_node_fs17 = __toESM(require("fs"), 1);
|
|
27559
|
+
var import_node_path19 = __toESM(require("path"), 1);
|
|
27494
27560
|
function defaultStateFilePath(dataDir) {
|
|
27495
|
-
return
|
|
27561
|
+
return import_node_path19.default.join(dataDir, "state.json");
|
|
27496
27562
|
}
|
|
27497
27563
|
function isPidAlive(pid) {
|
|
27498
27564
|
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
@@ -27514,7 +27580,7 @@ var StateFileManager = class {
|
|
|
27514
27580
|
}
|
|
27515
27581
|
read() {
|
|
27516
27582
|
try {
|
|
27517
|
-
const raw =
|
|
27583
|
+
const raw = import_node_fs17.default.readFileSync(this.file, "utf8");
|
|
27518
27584
|
const parsed = JSON.parse(raw);
|
|
27519
27585
|
return parsed;
|
|
27520
27586
|
} catch {
|
|
@@ -27528,34 +27594,34 @@ var StateFileManager = class {
|
|
|
27528
27594
|
return { status: "stale", existing };
|
|
27529
27595
|
}
|
|
27530
27596
|
write(state) {
|
|
27531
|
-
|
|
27597
|
+
import_node_fs17.default.mkdirSync(import_node_path19.default.dirname(this.file), { recursive: true });
|
|
27532
27598
|
const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
|
|
27533
|
-
|
|
27534
|
-
|
|
27599
|
+
import_node_fs17.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
|
|
27600
|
+
import_node_fs17.default.renameSync(tmp, this.file);
|
|
27535
27601
|
if (process.platform !== "win32") {
|
|
27536
27602
|
try {
|
|
27537
|
-
|
|
27603
|
+
import_node_fs17.default.chmodSync(this.file, 384);
|
|
27538
27604
|
} catch {
|
|
27539
27605
|
}
|
|
27540
27606
|
}
|
|
27541
27607
|
}
|
|
27542
27608
|
delete() {
|
|
27543
27609
|
try {
|
|
27544
|
-
|
|
27610
|
+
import_node_fs17.default.unlinkSync(this.file);
|
|
27545
27611
|
} catch {
|
|
27546
27612
|
}
|
|
27547
27613
|
}
|
|
27548
27614
|
};
|
|
27549
27615
|
|
|
27550
27616
|
// src/tunnel/tunnel-manager.ts
|
|
27551
|
-
var
|
|
27552
|
-
var
|
|
27617
|
+
var import_node_fs21 = __toESM(require("fs"), 1);
|
|
27618
|
+
var import_node_path23 = __toESM(require("path"), 1);
|
|
27553
27619
|
var import_node_crypto7 = __toESM(require("crypto"), 1);
|
|
27554
27620
|
var import_node_child_process5 = require("child_process");
|
|
27555
27621
|
|
|
27556
27622
|
// src/tunnel/tunnel-store.ts
|
|
27557
|
-
var
|
|
27558
|
-
var
|
|
27623
|
+
var import_node_fs18 = __toESM(require("fs"), 1);
|
|
27624
|
+
var import_node_path20 = __toESM(require("path"), 1);
|
|
27559
27625
|
var TunnelStore = class {
|
|
27560
27626
|
constructor(filePath) {
|
|
27561
27627
|
this.filePath = filePath;
|
|
@@ -27563,7 +27629,7 @@ var TunnelStore = class {
|
|
|
27563
27629
|
filePath;
|
|
27564
27630
|
async get() {
|
|
27565
27631
|
try {
|
|
27566
|
-
const raw = await
|
|
27632
|
+
const raw = await import_node_fs18.default.promises.readFile(this.filePath, "utf8");
|
|
27567
27633
|
const obj = JSON.parse(raw);
|
|
27568
27634
|
if (!isPersistedTunnel(obj)) return null;
|
|
27569
27635
|
return obj;
|
|
@@ -27574,22 +27640,22 @@ var TunnelStore = class {
|
|
|
27574
27640
|
}
|
|
27575
27641
|
}
|
|
27576
27642
|
async set(v2) {
|
|
27577
|
-
const dir =
|
|
27578
|
-
await
|
|
27643
|
+
const dir = import_node_path20.default.dirname(this.filePath);
|
|
27644
|
+
await import_node_fs18.default.promises.mkdir(dir, { recursive: true });
|
|
27579
27645
|
const data = JSON.stringify(v2, null, 2);
|
|
27580
27646
|
const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
|
|
27581
|
-
await
|
|
27647
|
+
await import_node_fs18.default.promises.writeFile(tmp, data, { mode: 384 });
|
|
27582
27648
|
if (process.platform !== "win32") {
|
|
27583
27649
|
try {
|
|
27584
|
-
await
|
|
27650
|
+
await import_node_fs18.default.promises.chmod(tmp, 384);
|
|
27585
27651
|
} catch {
|
|
27586
27652
|
}
|
|
27587
27653
|
}
|
|
27588
|
-
await
|
|
27654
|
+
await import_node_fs18.default.promises.rename(tmp, this.filePath);
|
|
27589
27655
|
}
|
|
27590
27656
|
async clear() {
|
|
27591
27657
|
try {
|
|
27592
|
-
await
|
|
27658
|
+
await import_node_fs18.default.promises.unlink(this.filePath);
|
|
27593
27659
|
} catch (err) {
|
|
27594
27660
|
const code = err?.code;
|
|
27595
27661
|
if (code !== "ENOENT") throw err;
|
|
@@ -27684,9 +27750,9 @@ function escape(v2) {
|
|
|
27684
27750
|
}
|
|
27685
27751
|
|
|
27686
27752
|
// src/tunnel/frpc-binary.ts
|
|
27687
|
-
var
|
|
27688
|
-
var
|
|
27689
|
-
var
|
|
27753
|
+
var import_node_fs19 = __toESM(require("fs"), 1);
|
|
27754
|
+
var import_node_os10 = __toESM(require("os"), 1);
|
|
27755
|
+
var import_node_path21 = __toESM(require("path"), 1);
|
|
27690
27756
|
var import_node_child_process3 = require("child_process");
|
|
27691
27757
|
var import_node_stream2 = require("stream");
|
|
27692
27758
|
var import_promises = require("stream/promises");
|
|
@@ -27718,20 +27784,20 @@ function frpcDownloadUrl(version2, p2) {
|
|
|
27718
27784
|
}
|
|
27719
27785
|
async function ensureFrpcBinary(opts) {
|
|
27720
27786
|
if (opts.override) {
|
|
27721
|
-
if (!
|
|
27787
|
+
if (!import_node_fs19.default.existsSync(opts.override)) {
|
|
27722
27788
|
throw new Error(`frpc binary not found at override path: ${opts.override}`);
|
|
27723
27789
|
}
|
|
27724
27790
|
return opts.override;
|
|
27725
27791
|
}
|
|
27726
27792
|
const version2 = opts.version ?? FRPC_VERSION;
|
|
27727
27793
|
const platform = opts.platform ?? detectPlatform();
|
|
27728
|
-
const binDir =
|
|
27729
|
-
|
|
27794
|
+
const binDir = import_node_path21.default.join(opts.dataDir, "bin");
|
|
27795
|
+
import_node_fs19.default.mkdirSync(binDir, { recursive: true });
|
|
27730
27796
|
cleanupStaleArtifacts(binDir);
|
|
27731
|
-
const stableBin =
|
|
27732
|
-
if (
|
|
27797
|
+
const stableBin = import_node_path21.default.join(binDir, "frpc");
|
|
27798
|
+
if (import_node_fs19.default.existsSync(stableBin)) return stableBin;
|
|
27733
27799
|
const partialBin = `${stableBin}.partial`;
|
|
27734
|
-
const tarballPath =
|
|
27800
|
+
const tarballPath = import_node_path21.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
|
|
27735
27801
|
try {
|
|
27736
27802
|
const url = frpcDownloadUrl(version2, platform);
|
|
27737
27803
|
await downloadToFile(url, tarballPath, opts.fetchImpl);
|
|
@@ -27740,8 +27806,8 @@ async function ensureFrpcBinary(opts) {
|
|
|
27740
27806
|
} else {
|
|
27741
27807
|
await extractFrpcFromTarball(tarballPath, binDir, version2, platform, partialBin);
|
|
27742
27808
|
}
|
|
27743
|
-
|
|
27744
|
-
|
|
27809
|
+
import_node_fs19.default.chmodSync(partialBin, 493);
|
|
27810
|
+
import_node_fs19.default.renameSync(partialBin, stableBin);
|
|
27745
27811
|
} finally {
|
|
27746
27812
|
safeUnlink(tarballPath);
|
|
27747
27813
|
safeUnlink(partialBin);
|
|
@@ -27751,15 +27817,15 @@ async function ensureFrpcBinary(opts) {
|
|
|
27751
27817
|
function cleanupStaleArtifacts(binDir) {
|
|
27752
27818
|
let entries;
|
|
27753
27819
|
try {
|
|
27754
|
-
entries =
|
|
27820
|
+
entries = import_node_fs19.default.readdirSync(binDir);
|
|
27755
27821
|
} catch {
|
|
27756
27822
|
return;
|
|
27757
27823
|
}
|
|
27758
27824
|
for (const name of entries) {
|
|
27759
27825
|
if (name.endsWith(".partial") || name.startsWith("extract-")) {
|
|
27760
|
-
const full =
|
|
27826
|
+
const full = import_node_path21.default.join(binDir, name);
|
|
27761
27827
|
try {
|
|
27762
|
-
|
|
27828
|
+
import_node_fs19.default.rmSync(full, { recursive: true, force: true });
|
|
27763
27829
|
} catch {
|
|
27764
27830
|
}
|
|
27765
27831
|
}
|
|
@@ -27767,7 +27833,7 @@ function cleanupStaleArtifacts(binDir) {
|
|
|
27767
27833
|
}
|
|
27768
27834
|
function safeUnlink(p2) {
|
|
27769
27835
|
try {
|
|
27770
|
-
|
|
27836
|
+
import_node_fs19.default.unlinkSync(p2);
|
|
27771
27837
|
} catch {
|
|
27772
27838
|
}
|
|
27773
27839
|
}
|
|
@@ -27778,13 +27844,13 @@ async function downloadToFile(url, dest, fetchImpl) {
|
|
|
27778
27844
|
if (!res.ok || !res.body) {
|
|
27779
27845
|
throw new Error(`download failed: ${res.status} ${res.statusText}`);
|
|
27780
27846
|
}
|
|
27781
|
-
const out =
|
|
27847
|
+
const out = import_node_fs19.default.createWriteStream(dest);
|
|
27782
27848
|
const nodeStream = import_node_stream2.Readable.fromWeb(res.body);
|
|
27783
27849
|
await (0, import_promises.pipeline)(nodeStream, out);
|
|
27784
27850
|
}
|
|
27785
27851
|
async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
|
|
27786
|
-
const work =
|
|
27787
|
-
|
|
27852
|
+
const work = import_node_path21.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
|
|
27853
|
+
import_node_fs19.default.mkdirSync(work, { recursive: true });
|
|
27788
27854
|
try {
|
|
27789
27855
|
await new Promise((resolve6, reject) => {
|
|
27790
27856
|
const proc = (0, import_node_child_process3.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
|
|
@@ -27792,32 +27858,32 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
|
|
|
27792
27858
|
proc.on("exit", (code) => code === 0 ? resolve6() : reject(new Error(`tar exited ${code}`)));
|
|
27793
27859
|
});
|
|
27794
27860
|
const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
|
|
27795
|
-
const src =
|
|
27796
|
-
if (!
|
|
27861
|
+
const src = import_node_path21.default.join(work, dirName, "frpc");
|
|
27862
|
+
if (!import_node_fs19.default.existsSync(src)) {
|
|
27797
27863
|
throw new Error(`frpc not found inside tarball at ${src}`);
|
|
27798
27864
|
}
|
|
27799
|
-
|
|
27865
|
+
import_node_fs19.default.copyFileSync(src, destBin);
|
|
27800
27866
|
} finally {
|
|
27801
|
-
|
|
27867
|
+
import_node_fs19.default.rmSync(work, { recursive: true, force: true });
|
|
27802
27868
|
}
|
|
27803
27869
|
}
|
|
27804
27870
|
|
|
27805
27871
|
// src/tunnel/frpc-process.ts
|
|
27806
|
-
var
|
|
27807
|
-
var
|
|
27872
|
+
var import_node_fs20 = __toESM(require("fs"), 1);
|
|
27873
|
+
var import_node_path22 = __toESM(require("path"), 1);
|
|
27808
27874
|
var import_node_child_process4 = require("child_process");
|
|
27809
27875
|
function frpcPidFilePath(dataDir) {
|
|
27810
|
-
return
|
|
27876
|
+
return import_node_path22.default.join(dataDir, "frpc.pid");
|
|
27811
27877
|
}
|
|
27812
27878
|
function writeFrpcPid(dataDir, pid) {
|
|
27813
27879
|
try {
|
|
27814
|
-
|
|
27880
|
+
import_node_fs20.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
|
|
27815
27881
|
} catch {
|
|
27816
27882
|
}
|
|
27817
27883
|
}
|
|
27818
27884
|
function clearFrpcPid(dataDir) {
|
|
27819
27885
|
try {
|
|
27820
|
-
|
|
27886
|
+
import_node_fs20.default.unlinkSync(frpcPidFilePath(dataDir));
|
|
27821
27887
|
} catch {
|
|
27822
27888
|
}
|
|
27823
27889
|
}
|
|
@@ -27833,7 +27899,7 @@ function defaultIsPidAlive(pid) {
|
|
|
27833
27899
|
}
|
|
27834
27900
|
function defaultReadPidFile(file) {
|
|
27835
27901
|
try {
|
|
27836
|
-
return
|
|
27902
|
+
return import_node_fs20.default.readFileSync(file, "utf8");
|
|
27837
27903
|
} catch {
|
|
27838
27904
|
return null;
|
|
27839
27905
|
}
|
|
@@ -27849,7 +27915,7 @@ function defaultSleep(ms) {
|
|
|
27849
27915
|
}
|
|
27850
27916
|
async function killStaleFrpc(deps) {
|
|
27851
27917
|
const pidFile = frpcPidFilePath(deps.dataDir);
|
|
27852
|
-
const tomlPath =
|
|
27918
|
+
const tomlPath = import_node_path22.default.join(deps.dataDir, "frpc.toml");
|
|
27853
27919
|
const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
|
|
27854
27920
|
const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
|
|
27855
27921
|
const killPid = deps.killPidImpl ?? defaultKillPid;
|
|
@@ -27873,7 +27939,7 @@ async function killStaleFrpc(deps) {
|
|
|
27873
27939
|
}
|
|
27874
27940
|
if (victims.size === 0) {
|
|
27875
27941
|
try {
|
|
27876
|
-
|
|
27942
|
+
import_node_fs20.default.unlinkSync(pidFile);
|
|
27877
27943
|
} catch {
|
|
27878
27944
|
}
|
|
27879
27945
|
return;
|
|
@@ -27884,7 +27950,7 @@ async function killStaleFrpc(deps) {
|
|
|
27884
27950
|
}
|
|
27885
27951
|
await sleep(deps.reapWaitMs ?? 300);
|
|
27886
27952
|
try {
|
|
27887
|
-
|
|
27953
|
+
import_node_fs20.default.unlinkSync(pidFile);
|
|
27888
27954
|
} catch {
|
|
27889
27955
|
}
|
|
27890
27956
|
}
|
|
@@ -27921,7 +27987,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
|
27921
27987
|
var TunnelManager = class {
|
|
27922
27988
|
constructor(deps) {
|
|
27923
27989
|
this.deps = deps;
|
|
27924
|
-
this.store = deps.store ?? new TunnelStore(
|
|
27990
|
+
this.store = deps.store ?? new TunnelStore(import_node_path23.default.join(deps.dataDir, "tunnel.json"));
|
|
27925
27991
|
this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
|
|
27926
27992
|
this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
|
|
27927
27993
|
}
|
|
@@ -28048,7 +28114,7 @@ var TunnelManager = class {
|
|
|
28048
28114
|
dataDir: this.deps.dataDir,
|
|
28049
28115
|
override: this.deps.frpcBinaryOverride ?? void 0
|
|
28050
28116
|
});
|
|
28051
|
-
const tomlPath =
|
|
28117
|
+
const tomlPath = import_node_path23.default.join(this.deps.dataDir, "frpc.toml");
|
|
28052
28118
|
const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto7.default.randomBytes(3).toString("hex")}`;
|
|
28053
28119
|
const toml = buildFrpcToml({
|
|
28054
28120
|
serverAddr: t.frpsHost,
|
|
@@ -28059,12 +28125,12 @@ var TunnelManager = class {
|
|
|
28059
28125
|
localPort,
|
|
28060
28126
|
logLevel: "info"
|
|
28061
28127
|
});
|
|
28062
|
-
await
|
|
28128
|
+
await import_node_fs21.default.promises.writeFile(tomlPath, toml, { mode: 384 });
|
|
28063
28129
|
const proc = (this.deps.spawnImpl ?? import_node_child_process5.spawn)(frpcBin, ["-c", tomlPath], {
|
|
28064
28130
|
stdio: ["ignore", "pipe", "pipe"]
|
|
28065
28131
|
});
|
|
28066
|
-
const logFilePath =
|
|
28067
|
-
const logStream =
|
|
28132
|
+
const logFilePath = import_node_path23.default.join(this.deps.dataDir, "frpc.log");
|
|
28133
|
+
const logStream = import_node_fs21.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
|
|
28068
28134
|
logStream.on("error", () => {
|
|
28069
28135
|
});
|
|
28070
28136
|
const tee = (chunk) => {
|
|
@@ -28146,23 +28212,23 @@ async function waitForFrpcReady(proc, timeoutMs) {
|
|
|
28146
28212
|
}
|
|
28147
28213
|
|
|
28148
28214
|
// src/tunnel/device-key.ts
|
|
28149
|
-
var
|
|
28215
|
+
var import_node_os11 = __toESM(require("os"), 1);
|
|
28150
28216
|
var import_node_crypto8 = __toESM(require("crypto"), 1);
|
|
28151
28217
|
var DERIVE_SALT = "clawd-tunnel-device-v1";
|
|
28152
28218
|
function deriveStableDeviceKey(opts = {}) {
|
|
28153
|
-
const hostname = opts.hostname ??
|
|
28154
|
-
const uid = opts.uid ?? (typeof
|
|
28219
|
+
const hostname = opts.hostname ?? import_node_os11.default.hostname();
|
|
28220
|
+
const uid = opts.uid ?? (typeof import_node_os11.default.userInfo === "function" ? import_node_os11.default.userInfo().uid : 0);
|
|
28155
28221
|
const input = `${hostname}::${uid}`;
|
|
28156
28222
|
return import_node_crypto8.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
|
|
28157
28223
|
}
|
|
28158
28224
|
|
|
28159
28225
|
// src/auth-store.ts
|
|
28160
|
-
var
|
|
28161
|
-
var
|
|
28226
|
+
var import_node_fs22 = __toESM(require("fs"), 1);
|
|
28227
|
+
var import_node_path24 = __toESM(require("path"), 1);
|
|
28162
28228
|
var import_node_crypto9 = __toESM(require("crypto"), 1);
|
|
28163
28229
|
var AUTH_FILE_NAME = "auth.json";
|
|
28164
28230
|
function authFilePath(dataDir) {
|
|
28165
|
-
return
|
|
28231
|
+
return import_node_path24.default.join(dataDir, AUTH_FILE_NAME);
|
|
28166
28232
|
}
|
|
28167
28233
|
function loadOrCreateAuthFile(opts) {
|
|
28168
28234
|
const file = authFilePath(opts.dataDir);
|
|
@@ -28194,7 +28260,7 @@ function defaultGenerateOwnerPrincipalId() {
|
|
|
28194
28260
|
}
|
|
28195
28261
|
function readAuthFile(file) {
|
|
28196
28262
|
try {
|
|
28197
|
-
const raw =
|
|
28263
|
+
const raw = import_node_fs22.default.readFileSync(file, "utf8");
|
|
28198
28264
|
const parsed = JSON.parse(raw);
|
|
28199
28265
|
if (typeof parsed?.token !== "string" || parsed.token.length === 0) {
|
|
28200
28266
|
return null;
|
|
@@ -28212,25 +28278,25 @@ function readAuthFile(file) {
|
|
|
28212
28278
|
}
|
|
28213
28279
|
}
|
|
28214
28280
|
function writeAuthFile(file, content) {
|
|
28215
|
-
|
|
28216
|
-
|
|
28281
|
+
import_node_fs22.default.mkdirSync(import_node_path24.default.dirname(file), { recursive: true });
|
|
28282
|
+
import_node_fs22.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
|
|
28217
28283
|
try {
|
|
28218
|
-
|
|
28284
|
+
import_node_fs22.default.chmodSync(file, 384);
|
|
28219
28285
|
} catch {
|
|
28220
28286
|
}
|
|
28221
28287
|
}
|
|
28222
28288
|
|
|
28223
28289
|
// src/owner-profile.ts
|
|
28224
|
-
var
|
|
28225
|
-
var
|
|
28226
|
-
var
|
|
28290
|
+
var import_node_fs23 = __toESM(require("fs"), 1);
|
|
28291
|
+
var import_node_os12 = __toESM(require("os"), 1);
|
|
28292
|
+
var import_node_path25 = __toESM(require("path"), 1);
|
|
28227
28293
|
var PROFILE_FILENAME = "profile.json";
|
|
28228
28294
|
function loadOwnerDisplayName(dataDir) {
|
|
28229
|
-
const fallback =
|
|
28230
|
-
const profilePath =
|
|
28295
|
+
const fallback = import_node_os12.default.userInfo().username;
|
|
28296
|
+
const profilePath = import_node_path25.default.join(dataDir, PROFILE_FILENAME);
|
|
28231
28297
|
let raw;
|
|
28232
28298
|
try {
|
|
28233
|
-
raw =
|
|
28299
|
+
raw = import_node_fs23.default.readFileSync(profilePath, "utf8");
|
|
28234
28300
|
} catch {
|
|
28235
28301
|
return fallback;
|
|
28236
28302
|
}
|
|
@@ -28259,12 +28325,12 @@ init_protocol();
|
|
|
28259
28325
|
init_protocol();
|
|
28260
28326
|
|
|
28261
28327
|
// src/session/fork.ts
|
|
28262
|
-
var
|
|
28263
|
-
var
|
|
28264
|
-
var
|
|
28328
|
+
var import_node_fs24 = __toESM(require("fs"), 1);
|
|
28329
|
+
var import_node_os13 = __toESM(require("os"), 1);
|
|
28330
|
+
var import_node_path26 = __toESM(require("path"), 1);
|
|
28265
28331
|
init_claude_history();
|
|
28266
28332
|
function readJsonlEntries(file) {
|
|
28267
|
-
const raw =
|
|
28333
|
+
const raw = import_node_fs24.default.readFileSync(file, "utf8");
|
|
28268
28334
|
const out = [];
|
|
28269
28335
|
for (const line of raw.split("\n")) {
|
|
28270
28336
|
const t = line.trim();
|
|
@@ -28277,10 +28343,10 @@ function readJsonlEntries(file) {
|
|
|
28277
28343
|
return out;
|
|
28278
28344
|
}
|
|
28279
28345
|
function forkSession(input) {
|
|
28280
|
-
const baseDir = input.baseDir ??
|
|
28281
|
-
const projectDir =
|
|
28282
|
-
const sourceFile =
|
|
28283
|
-
if (!
|
|
28346
|
+
const baseDir = input.baseDir ?? import_node_path26.default.join(import_node_os13.default.homedir(), ".claude");
|
|
28347
|
+
const projectDir = import_node_path26.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
|
|
28348
|
+
const sourceFile = import_node_path26.default.join(projectDir, `${input.toolSessionId}.jsonl`);
|
|
28349
|
+
if (!import_node_fs24.default.existsSync(sourceFile)) {
|
|
28284
28350
|
throw new Error(`fork: source transcript not found: ${sourceFile}`);
|
|
28285
28351
|
}
|
|
28286
28352
|
const entries = readJsonlEntries(sourceFile);
|
|
@@ -28310,9 +28376,9 @@ function forkSession(input) {
|
|
|
28310
28376
|
}
|
|
28311
28377
|
forkedLines.push(JSON.stringify(forked));
|
|
28312
28378
|
}
|
|
28313
|
-
const forkedFilePath =
|
|
28314
|
-
|
|
28315
|
-
|
|
28379
|
+
const forkedFilePath = import_node_path26.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
|
|
28380
|
+
import_node_fs24.default.mkdirSync(projectDir, { recursive: true });
|
|
28381
|
+
import_node_fs24.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
|
|
28316
28382
|
return { forkedToolSessionId, forkedFilePath };
|
|
28317
28383
|
}
|
|
28318
28384
|
|
|
@@ -28600,28 +28666,6 @@ function buildSessionHandlers(deps) {
|
|
|
28600
28666
|
}
|
|
28601
28667
|
};
|
|
28602
28668
|
};
|
|
28603
|
-
const peerSessionUpsert = async (frame, _client, ctx) => {
|
|
28604
|
-
if (ctx && ctx.principal.kind !== "owner") {
|
|
28605
|
-
throw new ClawdError(
|
|
28606
|
-
ERROR_CODES.UNAUTHORIZED,
|
|
28607
|
-
`principal ${ctx.principal.kind}:${ctx.principal.id} cannot peerSession:upsert`
|
|
28608
|
-
);
|
|
28609
|
-
}
|
|
28610
|
-
const file = PeerSessionUpsertArgs.parse(frame);
|
|
28611
|
-
manager.mirrorUpsert(file);
|
|
28612
|
-
return { response: { type: "peerSession:upsert:ok" }, broadcast: [] };
|
|
28613
|
-
};
|
|
28614
|
-
const peerSessionRemove = async (frame, _client, ctx) => {
|
|
28615
|
-
if (ctx && ctx.principal.kind !== "owner") {
|
|
28616
|
-
throw new ClawdError(
|
|
28617
|
-
ERROR_CODES.UNAUTHORIZED,
|
|
28618
|
-
`principal ${ctx.principal.kind}:${ctx.principal.id} cannot peerSession:remove`
|
|
28619
|
-
);
|
|
28620
|
-
}
|
|
28621
|
-
const args = PeerSessionRemoveArgs.parse(frame);
|
|
28622
|
-
manager.mirrorRemove(args.sessionId);
|
|
28623
|
-
return { response: { type: "peerSession:remove:ok" }, broadcast: [] };
|
|
28624
|
-
};
|
|
28625
28669
|
return {
|
|
28626
28670
|
"session:create": create,
|
|
28627
28671
|
"session:list": list,
|
|
@@ -28647,9 +28691,7 @@ function buildSessionHandlers(deps) {
|
|
|
28647
28691
|
"session:cancelQuestion": cancelQuestion,
|
|
28648
28692
|
"session:pty:input": ptyInput,
|
|
28649
28693
|
"session:pty:resize": ptyResize,
|
|
28650
|
-
"session:pty:snapshot": ptySnapshot
|
|
28651
|
-
"peerSession:upsert": peerSessionUpsert,
|
|
28652
|
-
"peerSession:remove": peerSessionRemove
|
|
28694
|
+
"session:pty:snapshot": ptySnapshot
|
|
28653
28695
|
};
|
|
28654
28696
|
}
|
|
28655
28697
|
|
|
@@ -28668,7 +28710,7 @@ function buildPermissionHandlers(deps) {
|
|
|
28668
28710
|
}
|
|
28669
28711
|
|
|
28670
28712
|
// src/handlers/history.ts
|
|
28671
|
-
var
|
|
28713
|
+
var path36 = __toESM(require("path"), 1);
|
|
28672
28714
|
init_protocol();
|
|
28673
28715
|
|
|
28674
28716
|
// src/session/recent-dirs.ts
|
|
@@ -28686,7 +28728,7 @@ function listRecentDirs(store, limit = 50) {
|
|
|
28686
28728
|
}
|
|
28687
28729
|
|
|
28688
28730
|
// src/permission/persona-paths.ts
|
|
28689
|
-
var
|
|
28731
|
+
var path35 = __toESM(require("path"), 1);
|
|
28690
28732
|
function getAllowedPersonaIds(grants, action) {
|
|
28691
28733
|
const ids = /* @__PURE__ */ new Set();
|
|
28692
28734
|
for (const g2 of grants) {
|
|
@@ -28699,26 +28741,26 @@ function getAllowedPersonaIds(grants, action) {
|
|
|
28699
28741
|
return ids;
|
|
28700
28742
|
}
|
|
28701
28743
|
function isGuestPathAllowed(grants, absPath, personaRoot, action = "read") {
|
|
28702
|
-
const root =
|
|
28703
|
-
const target =
|
|
28704
|
-
const sep3 = root.endsWith(
|
|
28744
|
+
const root = path35.resolve(personaRoot);
|
|
28745
|
+
const target = path35.resolve(absPath);
|
|
28746
|
+
const sep3 = root.endsWith(path35.sep) ? "" : path35.sep;
|
|
28705
28747
|
if (!target.startsWith(root + sep3)) return false;
|
|
28706
|
-
const rel =
|
|
28748
|
+
const rel = path35.relative(root, target);
|
|
28707
28749
|
if (!rel || rel.startsWith("..")) return false;
|
|
28708
|
-
const personaId = rel.split(
|
|
28750
|
+
const personaId = rel.split(path35.sep)[0];
|
|
28709
28751
|
if (!personaId) return false;
|
|
28710
28752
|
const allowed = getAllowedPersonaIds(grants, action);
|
|
28711
28753
|
if (allowed === "*") return true;
|
|
28712
28754
|
return allowed.has(personaId);
|
|
28713
28755
|
}
|
|
28714
28756
|
function personaIdFromPath(absPath, personaRoot) {
|
|
28715
|
-
const root =
|
|
28716
|
-
const target =
|
|
28717
|
-
const sep3 = root.endsWith(
|
|
28757
|
+
const root = path35.resolve(personaRoot);
|
|
28758
|
+
const target = path35.resolve(absPath);
|
|
28759
|
+
const sep3 = root.endsWith(path35.sep) ? "" : path35.sep;
|
|
28718
28760
|
if (!target.startsWith(root + sep3)) return null;
|
|
28719
|
-
const rel =
|
|
28761
|
+
const rel = path35.relative(root, target);
|
|
28720
28762
|
if (!rel || rel.startsWith("..")) return null;
|
|
28721
|
-
const id = rel.split(
|
|
28763
|
+
const id = rel.split(path35.sep)[0];
|
|
28722
28764
|
return id || null;
|
|
28723
28765
|
}
|
|
28724
28766
|
|
|
@@ -28743,7 +28785,7 @@ function buildHistoryHandlers(deps) {
|
|
|
28743
28785
|
if (!pid) return false;
|
|
28744
28786
|
return isGuestPathAllowed(
|
|
28745
28787
|
ctx.grants,
|
|
28746
|
-
|
|
28788
|
+
path36.join(personaRoot, pid),
|
|
28747
28789
|
personaRoot,
|
|
28748
28790
|
"read"
|
|
28749
28791
|
);
|
|
@@ -28754,7 +28796,7 @@ function buildHistoryHandlers(deps) {
|
|
|
28754
28796
|
};
|
|
28755
28797
|
const list = async (frame, _client, ctx) => {
|
|
28756
28798
|
const args = HistoryListArgs.parse(frame);
|
|
28757
|
-
assertGuestPath(ctx,
|
|
28799
|
+
assertGuestPath(ctx, path36.resolve(args.projectPath), personaRoot, "history:list");
|
|
28758
28800
|
const sessions = await history.listSessions(args);
|
|
28759
28801
|
return { response: { type: "history:list", sessions } };
|
|
28760
28802
|
};
|
|
@@ -28786,13 +28828,13 @@ function buildHistoryHandlers(deps) {
|
|
|
28786
28828
|
};
|
|
28787
28829
|
const subagents = async (frame, _client, ctx) => {
|
|
28788
28830
|
const args = HistorySubagentsArgs.parse(frame);
|
|
28789
|
-
assertGuestPath(ctx,
|
|
28831
|
+
assertGuestPath(ctx, path36.resolve(args.cwd), personaRoot, "history:subagents");
|
|
28790
28832
|
const subs = await history.listSubagents(args);
|
|
28791
28833
|
return { response: { type: "history:subagents", subagents: subs } };
|
|
28792
28834
|
};
|
|
28793
28835
|
const subagentRead = async (frame, _client, ctx) => {
|
|
28794
28836
|
const args = HistorySubagentReadArgs.parse(frame);
|
|
28795
|
-
assertGuestPath(ctx,
|
|
28837
|
+
assertGuestPath(ctx, path36.resolve(args.cwd), personaRoot, "history:subagent-read");
|
|
28796
28838
|
const res = await history.readSubagent(args);
|
|
28797
28839
|
return { response: { type: "history:subagent-read", ...res } };
|
|
28798
28840
|
};
|
|
@@ -28800,7 +28842,7 @@ function buildHistoryHandlers(deps) {
|
|
|
28800
28842
|
const dirs = listRecentDirs(store);
|
|
28801
28843
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
28802
28844
|
const filtered = dirs.filter(
|
|
28803
|
-
(d) => isGuestPathAllowed(ctx.grants,
|
|
28845
|
+
(d) => isGuestPathAllowed(ctx.grants, path36.resolve(d.cwd), personaRoot, "read")
|
|
28804
28846
|
);
|
|
28805
28847
|
return { response: { type: "history:recentDirs", dirs: filtered } };
|
|
28806
28848
|
}
|
|
@@ -28817,8 +28859,8 @@ function buildHistoryHandlers(deps) {
|
|
|
28817
28859
|
}
|
|
28818
28860
|
|
|
28819
28861
|
// src/handlers/workspace.ts
|
|
28820
|
-
var
|
|
28821
|
-
var
|
|
28862
|
+
var path37 = __toESM(require("path"), 1);
|
|
28863
|
+
var os14 = __toESM(require("os"), 1);
|
|
28822
28864
|
init_protocol();
|
|
28823
28865
|
init_protocol();
|
|
28824
28866
|
function buildEnabledPluginNames(personaManager, personaId) {
|
|
@@ -28857,23 +28899,23 @@ function buildWorkspaceHandlers(deps) {
|
|
|
28857
28899
|
const list = async (frame, _client, ctx) => {
|
|
28858
28900
|
const args = WorkspaceListArgs.parse(frame);
|
|
28859
28901
|
const isGuest = ctx?.principal.kind === "guest";
|
|
28860
|
-
const fallbackCwd = isGuest && personaRoot ? personaRoot :
|
|
28861
|
-
const resolvedCwd =
|
|
28862
|
-
const target = args.path ?
|
|
28902
|
+
const fallbackCwd = isGuest && personaRoot ? personaRoot : os14.homedir();
|
|
28903
|
+
const resolvedCwd = path37.resolve(args.cwd ?? fallbackCwd);
|
|
28904
|
+
const target = args.path ? path37.resolve(resolvedCwd, args.path) : resolvedCwd;
|
|
28863
28905
|
assertGuestPath2(ctx, target, personaRoot, "workspace:list");
|
|
28864
28906
|
const res = workspace.list({ ...args, cwd: resolvedCwd });
|
|
28865
28907
|
return { response: { type: "workspace:list", ...res } };
|
|
28866
28908
|
};
|
|
28867
28909
|
const read = async (frame, _client, ctx) => {
|
|
28868
28910
|
const args = WorkspaceReadArgs.parse(frame);
|
|
28869
|
-
const target =
|
|
28911
|
+
const target = path37.isAbsolute(args.path) ? path37.resolve(args.path) : path37.resolve(args.cwd, args.path);
|
|
28870
28912
|
assertGuestPath2(ctx, target, personaRoot, "workspace:read");
|
|
28871
28913
|
const res = workspace.read(args);
|
|
28872
28914
|
return { response: { type: "workspace:read", ...res } };
|
|
28873
28915
|
};
|
|
28874
28916
|
const skillsList = async (frame, _client, ctx) => {
|
|
28875
28917
|
const args = SkillsListArgs.parse(frame);
|
|
28876
|
-
const cwdAbs =
|
|
28918
|
+
const cwdAbs = path37.resolve(args.cwd);
|
|
28877
28919
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list");
|
|
28878
28920
|
const list2 = skills.list(args);
|
|
28879
28921
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
@@ -28885,7 +28927,7 @@ function buildWorkspaceHandlers(deps) {
|
|
|
28885
28927
|
};
|
|
28886
28928
|
const agentsList = async (frame, _client, ctx) => {
|
|
28887
28929
|
const args = AgentsListArgs.parse(frame);
|
|
28888
|
-
const cwdAbs =
|
|
28930
|
+
const cwdAbs = path37.resolve(args.cwd);
|
|
28889
28931
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list");
|
|
28890
28932
|
const list2 = agents.list(args);
|
|
28891
28933
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
@@ -28904,20 +28946,20 @@ function buildWorkspaceHandlers(deps) {
|
|
|
28904
28946
|
}
|
|
28905
28947
|
|
|
28906
28948
|
// src/handlers/git.ts
|
|
28907
|
-
var
|
|
28949
|
+
var path39 = __toESM(require("path"), 1);
|
|
28908
28950
|
init_protocol();
|
|
28909
28951
|
init_protocol();
|
|
28910
28952
|
|
|
28911
28953
|
// src/workspace/git.ts
|
|
28912
28954
|
var import_node_child_process6 = require("child_process");
|
|
28913
|
-
var
|
|
28914
|
-
var
|
|
28955
|
+
var import_node_fs25 = __toESM(require("fs"), 1);
|
|
28956
|
+
var import_node_path27 = __toESM(require("path"), 1);
|
|
28915
28957
|
var import_node_util = require("util");
|
|
28916
28958
|
var pexec = (0, import_node_util.promisify)(import_node_child_process6.execFile);
|
|
28917
28959
|
function normalizePath(p2) {
|
|
28918
|
-
const resolved =
|
|
28960
|
+
const resolved = import_node_path27.default.resolve(p2);
|
|
28919
28961
|
try {
|
|
28920
|
-
return
|
|
28962
|
+
return import_node_fs25.default.realpathSync(resolved);
|
|
28921
28963
|
} catch {
|
|
28922
28964
|
return resolved;
|
|
28923
28965
|
}
|
|
@@ -28990,7 +29032,7 @@ async function listGitBranches(cwd) {
|
|
|
28990
29032
|
// src/handlers/git.ts
|
|
28991
29033
|
function assertGuestCwd(ctx, cwd, personaRoot, method) {
|
|
28992
29034
|
if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
|
|
28993
|
-
if (!isGuestPathAllowed(ctx.grants,
|
|
29035
|
+
if (!isGuestPathAllowed(ctx.grants, path39.resolve(cwd), personaRoot, "read")) {
|
|
28994
29036
|
throw new ClawdError(
|
|
28995
29037
|
ERROR_CODES.UNAUTHORIZED,
|
|
28996
29038
|
`guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
|
|
@@ -29353,7 +29395,7 @@ function buildWhoamiHandler(deps) {
|
|
|
29353
29395
|
}
|
|
29354
29396
|
|
|
29355
29397
|
// src/handlers/meta.ts
|
|
29356
|
-
var
|
|
29398
|
+
var import_node_os14 = __toESM(require("os"), 1);
|
|
29357
29399
|
init_protocol();
|
|
29358
29400
|
|
|
29359
29401
|
// src/version.ts
|
|
@@ -29383,7 +29425,7 @@ function buildReadyFrame(deps, client) {
|
|
|
29383
29425
|
return {
|
|
29384
29426
|
version,
|
|
29385
29427
|
protocolVersion: PROTOCOL_VERSION,
|
|
29386
|
-
hostname:
|
|
29428
|
+
hostname: import_node_os14.default.hostname(),
|
|
29387
29429
|
os: process.platform,
|
|
29388
29430
|
tools,
|
|
29389
29431
|
runningSessions: info.runningSessions,
|
|
@@ -29477,7 +29519,7 @@ function buildPersonaHandlers(deps) {
|
|
|
29477
29519
|
}
|
|
29478
29520
|
|
|
29479
29521
|
// src/handlers/attachment.ts
|
|
29480
|
-
var
|
|
29522
|
+
var import_node_path28 = __toESM(require("path"), 1);
|
|
29481
29523
|
init_protocol();
|
|
29482
29524
|
init_protocol();
|
|
29483
29525
|
var DEFAULT_TTL_SECONDS = 24 * 3600;
|
|
@@ -29531,12 +29573,12 @@ function buildAttachmentHandlers(deps) {
|
|
|
29531
29573
|
`session ${args.sessionId} scope unresolved`
|
|
29532
29574
|
);
|
|
29533
29575
|
}
|
|
29534
|
-
const cwdAbs =
|
|
29535
|
-
const candidateAbs =
|
|
29576
|
+
const cwdAbs = import_node_path28.default.resolve(sessionFile.cwd);
|
|
29577
|
+
const candidateAbs = import_node_path28.default.isAbsolute(args.relPath) ? import_node_path28.default.resolve(args.relPath) : import_node_path28.default.resolve(cwdAbs, args.relPath);
|
|
29536
29578
|
assertGuestAttachmentPath(ctx, candidateAbs, deps.personaRoot, "attachment.signUrl");
|
|
29537
29579
|
const entries = deps.groupFileStore.list(scope, args.sessionId);
|
|
29538
29580
|
const entry = entries.find((e) => {
|
|
29539
|
-
const storedAbs =
|
|
29581
|
+
const storedAbs = import_node_path28.default.isAbsolute(e.relPath) ? import_node_path28.default.resolve(e.relPath) : import_node_path28.default.resolve(cwdAbs, e.relPath);
|
|
29540
29582
|
return storedAbs === candidateAbs && !e.stale;
|
|
29541
29583
|
});
|
|
29542
29584
|
if (!entry) {
|
|
@@ -29560,7 +29602,7 @@ function buildAttachmentHandlers(deps) {
|
|
|
29560
29602
|
if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
|
|
29561
29603
|
const f = deps.sessionStore.read(sessionId);
|
|
29562
29604
|
if (!f) return;
|
|
29563
|
-
assertGuestAttachmentPath(ctx,
|
|
29605
|
+
assertGuestAttachmentPath(ctx, import_node_path28.default.resolve(f.cwd), deps.personaRoot, method);
|
|
29564
29606
|
}
|
|
29565
29607
|
const groupAdd = async (frame, _client, ctx) => {
|
|
29566
29608
|
if (!deps.groupFileStore || !deps.getSessionScope) {
|
|
@@ -29727,11 +29769,6 @@ var METHOD_GRANT_MAP = {
|
|
|
29727
29769
|
"session:pin": CAPABILITY_SCOPED,
|
|
29728
29770
|
"session:reorderPins": ADMIN_ANY,
|
|
29729
29771
|
// owner 全局操作,无 personaId 维度
|
|
29730
|
-
// mirror peer sessions (2026-05-26):owner-only — guest 不应能写/删本机 mirror SessionFile
|
|
29731
|
-
// (会绕过 #739 隔离规则把伪造身份的 SessionFile 写进 default store)。handler 端内部 ctx
|
|
29732
|
-
// 校验,dispatcher 层一刀切 admin 也兜底。
|
|
29733
|
-
"peerSession:upsert": ADMIN_ANY,
|
|
29734
|
-
"peerSession:remove": ADMIN_ANY,
|
|
29735
29772
|
"permission:respond": CAPABILITY_SCOPED,
|
|
29736
29773
|
"session:answerQuestion": CAPABILITY_SCOPED,
|
|
29737
29774
|
"session:cancelQuestion": CAPABILITY_SCOPED,
|
|
@@ -29802,7 +29839,7 @@ function computeGrantForFrame(method, frame) {
|
|
|
29802
29839
|
async function startDaemon(config) {
|
|
29803
29840
|
const logger = createLogger({
|
|
29804
29841
|
level: config.logLevel,
|
|
29805
|
-
file:
|
|
29842
|
+
file: import_node_path29.default.join(config.dataDir, "clawd.log")
|
|
29806
29843
|
});
|
|
29807
29844
|
logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
|
|
29808
29845
|
const stateMgr = new StateFileManager({ dataDir: config.dataDir });
|
|
@@ -29889,7 +29926,7 @@ async function startDaemon(config) {
|
|
|
29889
29926
|
const agents = new AgentsScanner();
|
|
29890
29927
|
const history = new ClaudeHistoryReader();
|
|
29891
29928
|
let transport = null;
|
|
29892
|
-
const personaStore = new PersonaStore(
|
|
29929
|
+
const personaStore = new PersonaStore(import_node_path29.default.join(config.dataDir, "personas"));
|
|
29893
29930
|
const defaultsRoot = findDefaultsRoot();
|
|
29894
29931
|
if (defaultsRoot) {
|
|
29895
29932
|
seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
|
|
@@ -29906,7 +29943,7 @@ async function startDaemon(config) {
|
|
|
29906
29943
|
getAdapter,
|
|
29907
29944
|
historyReader: history,
|
|
29908
29945
|
dataDir: config.dataDir,
|
|
29909
|
-
personaRoot:
|
|
29946
|
+
personaRoot: import_node_path29.default.join(config.dataDir, "personas"),
|
|
29910
29947
|
personaStore,
|
|
29911
29948
|
ownerDisplayName,
|
|
29912
29949
|
ownerPrincipalId,
|
|
@@ -29930,10 +29967,10 @@ async function startDaemon(config) {
|
|
|
29930
29967
|
// 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
|
|
29931
29968
|
attachmentGroup: {
|
|
29932
29969
|
onFileEdit: (input) => {
|
|
29933
|
-
const absPath =
|
|
29970
|
+
const absPath = import_node_path29.default.isAbsolute(input.relPath) ? input.relPath : import_node_path29.default.join(input.cwd, input.relPath);
|
|
29934
29971
|
let size = 0;
|
|
29935
29972
|
try {
|
|
29936
|
-
size =
|
|
29973
|
+
size = import_node_fs26.default.statSync(absPath).size;
|
|
29937
29974
|
} catch (err) {
|
|
29938
29975
|
logger.warn("attachment.onFileEdit stat failed", {
|
|
29939
29976
|
sessionId: input.sessionId,
|
|
@@ -29959,6 +29996,11 @@ async function startDaemon(config) {
|
|
|
29959
29996
|
}
|
|
29960
29997
|
});
|
|
29961
29998
|
const observer = new SessionObserver({
|
|
29999
|
+
// TUI 模式 pty 跑 CC 不发 SDK system.task_started 帧 → UI pending 期 progress.agentId
|
|
30000
|
+
// 永远 undefined,子 agent 调用过程没有抽屉入口。开 meta observer 后从 subagents 目录
|
|
30001
|
+
// 新出现的 agent-*.meta.json 派生 subagent_progress(started) 补这块缺口。SDK 模式仍走
|
|
30002
|
+
// task_started 路径,避免双 emit 让 ring buffer 双帧。
|
|
30003
|
+
enableSubagentMetaObserver: config.mode === "tui",
|
|
29962
30004
|
onEvent: ({ sessionId, events }) => {
|
|
29963
30005
|
manager.feedObserverEvents(sessionId, events);
|
|
29964
30006
|
},
|
|
@@ -30046,10 +30088,10 @@ async function startDaemon(config) {
|
|
|
30046
30088
|
// 'persona/<pid>/owner',default 走 'default'。
|
|
30047
30089
|
getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
|
|
30048
30090
|
// guest path guard:candidate 必须在 personaRoot 子树下
|
|
30049
|
-
personaRoot:
|
|
30091
|
+
personaRoot: import_node_path29.default.join(config.dataDir, "personas")
|
|
30050
30092
|
},
|
|
30051
30093
|
// workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
|
|
30052
|
-
personaRoot:
|
|
30094
|
+
personaRoot: import_node_path29.default.join(config.dataDir, "personas"),
|
|
30053
30095
|
// capability:list / delete handler 依赖
|
|
30054
30096
|
capabilityManager,
|
|
30055
30097
|
// personal-cap:get 返回的 shareBaseUrl 用此 base URL:
|
|
@@ -30250,8 +30292,8 @@ async function startDaemon(config) {
|
|
|
30250
30292
|
const lines = [
|
|
30251
30293
|
`Tunnel: ${r.url}`,
|
|
30252
30294
|
...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
|
|
30253
|
-
`Frpc config: ${
|
|
30254
|
-
`Frpc log: ${
|
|
30295
|
+
`Frpc config: ${import_node_path29.default.join(config.dataDir, "frpc.toml")}`,
|
|
30296
|
+
`Frpc log: ${import_node_path29.default.join(config.dataDir, "frpc.log")}`
|
|
30255
30297
|
];
|
|
30256
30298
|
const width = Math.max(...lines.map((l) => l.length));
|
|
30257
30299
|
const bar = "\u2550".repeat(width + 4);
|
|
@@ -30264,8 +30306,8 @@ ${bar}
|
|
|
30264
30306
|
|
|
30265
30307
|
`);
|
|
30266
30308
|
try {
|
|
30267
|
-
const connectPath =
|
|
30268
|
-
|
|
30309
|
+
const connectPath = import_node_path29.default.join(config.dataDir, "connect.txt");
|
|
30310
|
+
import_node_fs26.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
|
|
30269
30311
|
} catch {
|
|
30270
30312
|
}
|
|
30271
30313
|
} catch (err) {
|
|
@@ -30309,9 +30351,9 @@ ${bar}
|
|
|
30309
30351
|
};
|
|
30310
30352
|
}
|
|
30311
30353
|
function migrateDropPersonsDir(dataDir) {
|
|
30312
|
-
const dir =
|
|
30354
|
+
const dir = import_node_path29.default.join(dataDir, "persons");
|
|
30313
30355
|
try {
|
|
30314
|
-
|
|
30356
|
+
import_node_fs26.default.rmSync(dir, { recursive: true, force: true });
|
|
30315
30357
|
} catch {
|
|
30316
30358
|
}
|
|
30317
30359
|
}
|