@clawos-dev/clawd 0.2.89 → 0.2.90-beta.169.a6af395
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 +600 -587
- 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: path47, errorMaps, issueData } = params;
|
|
647
|
+
const fullPath = [...path47, ...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, path47, key) {
|
|
967
959
|
this._cachedPath = [];
|
|
968
960
|
this.parent = parent;
|
|
969
961
|
this.data = value;
|
|
970
|
-
this._path =
|
|
962
|
+
this._path = path47;
|
|
971
963
|
this._key = key;
|
|
972
964
|
}
|
|
973
965
|
get path() {
|
|
@@ -4501,7 +4493,7 @@ var init_persona_schemas = __esm({
|
|
|
4501
4493
|
});
|
|
4502
4494
|
|
|
4503
4495
|
// ../protocol/src/schemas.ts
|
|
4504
|
-
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,
|
|
4496
|
+
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;
|
|
4505
4497
|
var init_schemas = __esm({
|
|
4506
4498
|
"../protocol/src/schemas.ts"() {
|
|
4507
4499
|
"use strict";
|
|
@@ -4629,35 +4621,6 @@ var init_schemas = __esm({
|
|
|
4629
4621
|
* 当前为 caller 自报,daemon 不密码学验证真伪;强身份验签是独立工作(B 方案)。
|
|
4630
4622
|
*/
|
|
4631
4623
|
creatorOwnerPrincipalId: external_exports.string().min(1).optional(),
|
|
4632
|
-
/**
|
|
4633
|
-
* Mirror peer sessions (2026-05-26): mirror 标识。**我在朋友 daemon 上以 guest ctx
|
|
4634
|
-
* 创建的 session**,远端是 source of truth,本机是该 session 的持久化副本,方便
|
|
4635
|
-
* sidebar 跨设备聚合。字段值是远端 daemon 的 ownerPrincipalId(即我接入的那位朋友)。
|
|
4636
|
-
*
|
|
4637
|
-
* 语义关键澄清:mirror **不是朋友创建给我的会话**——它是我自己的会话,只是在朋友
|
|
4638
|
-
* 的机器上跑。sidebar chip 显示 `@<朋友>` 暗示「位置」,不是「来源」。
|
|
4639
|
-
*
|
|
4640
|
-
* - undefined / 缺省 → 本机 native session(在我自己机器上跑)
|
|
4641
|
-
* - 非空 → 我的会话在该 ownerPrincipalId 朋友的 daemon 上跑,本机为持久化副本
|
|
4642
|
-
*
|
|
4643
|
-
* 与 `creatorPrincipalId` / `creatorOwnerPrincipalId` 在四类 session 下取值矩阵:
|
|
4644
|
-
* | 形态 | creatorPrincipalId | creatorOwnerPrincipalId | originOwnerPrincipalId |
|
|
4645
|
-
* |-------------------------------------|--------------------------|-------------------------|------------------------|
|
|
4646
|
-
* | 本机 owner 自创 | 本机 ownerPrincipalId | 本机 ownerPrincipalId | undefined |
|
|
4647
|
-
* | 本机被别人通过 personal token 接入创建 | 远端接入者 cap.id | 远端接入者 ownerPrincipalId | undefined |
|
|
4648
|
-
* | 我在朋友 daemon 上以 guest ctx 创建(mirror 回本机) | 朋友 daemon personal cap.id | 我自己 ownerPrincipalId | 朋友 ownerPrincipalId |
|
|
4649
|
-
*
|
|
4650
|
-
* UI 用法:
|
|
4651
|
-
* - sidebar Active/Pinned/Recents 过滤:`origin 非空 → 一律视作 self`(绕过 #739 隔离)
|
|
4652
|
-
* - 行内显示 `@<朋友>` chip 暗示位置
|
|
4653
|
-
* - 进 ChatPanel 时按 origin 路由到 `pool.ensureRemoteForOwner(origin)` 走远端
|
|
4654
|
-
*
|
|
4655
|
-
* daemon 用法:
|
|
4656
|
-
* - `peerSession:upsert` / `peerSession:remove` 一族 RPC 专管 mirror 写删;
|
|
4657
|
-
* daemon dumb write/delete,**不广播任何 push 帧**,UI 是写入唯一源
|
|
4658
|
-
* - native `session:*` handler 完全不感知 mirror(UI 操作 mirror 不走 native 路径)
|
|
4659
|
-
*/
|
|
4660
|
-
originOwnerPrincipalId: external_exports.string().min(1).optional(),
|
|
4661
4624
|
createdAt: external_exports.string().min(1),
|
|
4662
4625
|
updatedAt: external_exports.string().min(1)
|
|
4663
4626
|
});
|
|
@@ -5013,14 +4976,6 @@ var init_schemas = __esm({
|
|
|
5013
4976
|
sessionId: external_exports.string().min(1),
|
|
5014
4977
|
pinned: external_exports.boolean()
|
|
5015
4978
|
});
|
|
5016
|
-
PeerSessionUpsertArgs = SessionFileSchema;
|
|
5017
|
-
PeerSessionUpsertResponseSchema = external_exports.object({
|
|
5018
|
-
type: external_exports.literal("peerSession:upsert:ok")
|
|
5019
|
-
});
|
|
5020
|
-
PeerSessionRemoveArgs = external_exports.object({ sessionId: external_exports.string().min(1) });
|
|
5021
|
-
PeerSessionRemoveResponseSchema = external_exports.object({
|
|
5022
|
-
type: external_exports.literal("peerSession:remove:ok")
|
|
5023
|
-
});
|
|
5024
4979
|
SessionReorderPinsArgs = external_exports.object({
|
|
5025
4980
|
orderedIds: external_exports.array(external_exports.string().min(1)).min(1)
|
|
5026
4981
|
});
|
|
@@ -5635,8 +5590,8 @@ var require_req = __commonJS({
|
|
|
5635
5590
|
if (req.originalUrl) {
|
|
5636
5591
|
_req.url = req.originalUrl;
|
|
5637
5592
|
} else {
|
|
5638
|
-
const
|
|
5639
|
-
_req.url = typeof
|
|
5593
|
+
const path47 = req.path;
|
|
5594
|
+
_req.url = typeof path47 === "string" ? path47 : req.url ? req.url.path || req.url : void 0;
|
|
5640
5595
|
}
|
|
5641
5596
|
if (req.query) {
|
|
5642
5597
|
_req.query = req.query;
|
|
@@ -5801,14 +5756,14 @@ var require_redact = __commonJS({
|
|
|
5801
5756
|
}
|
|
5802
5757
|
return obj;
|
|
5803
5758
|
}
|
|
5804
|
-
function parsePath(
|
|
5759
|
+
function parsePath(path47) {
|
|
5805
5760
|
const parts = [];
|
|
5806
5761
|
let current = "";
|
|
5807
5762
|
let inBrackets = false;
|
|
5808
5763
|
let inQuotes = false;
|
|
5809
5764
|
let quoteChar = "";
|
|
5810
|
-
for (let i = 0; i <
|
|
5811
|
-
const char =
|
|
5765
|
+
for (let i = 0; i < path47.length; i++) {
|
|
5766
|
+
const char = path47[i];
|
|
5812
5767
|
if (!inBrackets && char === ".") {
|
|
5813
5768
|
if (current) {
|
|
5814
5769
|
parts.push(current);
|
|
@@ -5939,10 +5894,10 @@ var require_redact = __commonJS({
|
|
|
5939
5894
|
return current;
|
|
5940
5895
|
}
|
|
5941
5896
|
function redactPaths(obj, paths, censor, remove = false) {
|
|
5942
|
-
for (const
|
|
5943
|
-
const parts = parsePath(
|
|
5897
|
+
for (const path47 of paths) {
|
|
5898
|
+
const parts = parsePath(path47);
|
|
5944
5899
|
if (parts.includes("*")) {
|
|
5945
|
-
redactWildcardPath(obj, parts, censor,
|
|
5900
|
+
redactWildcardPath(obj, parts, censor, path47, remove);
|
|
5946
5901
|
} else {
|
|
5947
5902
|
if (remove) {
|
|
5948
5903
|
removeKey(obj, parts);
|
|
@@ -6027,8 +5982,8 @@ var require_redact = __commonJS({
|
|
|
6027
5982
|
}
|
|
6028
5983
|
} else {
|
|
6029
5984
|
if (afterWildcard.includes("*")) {
|
|
6030
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
6031
|
-
const fullPath = [...pathArray.slice(0, pathLength), ...
|
|
5985
|
+
const wrappedCensor = typeof censor === "function" ? (value, path47) => {
|
|
5986
|
+
const fullPath = [...pathArray.slice(0, pathLength), ...path47];
|
|
6032
5987
|
return censor(value, fullPath);
|
|
6033
5988
|
} : censor;
|
|
6034
5989
|
redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
|
|
@@ -6063,8 +6018,8 @@ var require_redact = __commonJS({
|
|
|
6063
6018
|
return null;
|
|
6064
6019
|
}
|
|
6065
6020
|
const pathStructure = /* @__PURE__ */ new Map();
|
|
6066
|
-
for (const
|
|
6067
|
-
const parts = parsePath(
|
|
6021
|
+
for (const path47 of pathsToClone) {
|
|
6022
|
+
const parts = parsePath(path47);
|
|
6068
6023
|
let current = pathStructure;
|
|
6069
6024
|
for (let i = 0; i < parts.length; i++) {
|
|
6070
6025
|
const part = parts[i];
|
|
@@ -6116,24 +6071,24 @@ var require_redact = __commonJS({
|
|
|
6116
6071
|
}
|
|
6117
6072
|
return cloneSelectively(obj, pathStructure);
|
|
6118
6073
|
}
|
|
6119
|
-
function validatePath(
|
|
6120
|
-
if (typeof
|
|
6074
|
+
function validatePath(path47) {
|
|
6075
|
+
if (typeof path47 !== "string") {
|
|
6121
6076
|
throw new Error("Paths must be (non-empty) strings");
|
|
6122
6077
|
}
|
|
6123
|
-
if (
|
|
6078
|
+
if (path47 === "") {
|
|
6124
6079
|
throw new Error("Invalid redaction path ()");
|
|
6125
6080
|
}
|
|
6126
|
-
if (
|
|
6127
|
-
throw new Error(`Invalid redaction path (${
|
|
6081
|
+
if (path47.includes("..")) {
|
|
6082
|
+
throw new Error(`Invalid redaction path (${path47})`);
|
|
6128
6083
|
}
|
|
6129
|
-
if (
|
|
6130
|
-
throw new Error(`Invalid redaction path (${
|
|
6084
|
+
if (path47.includes(",")) {
|
|
6085
|
+
throw new Error(`Invalid redaction path (${path47})`);
|
|
6131
6086
|
}
|
|
6132
6087
|
let bracketCount = 0;
|
|
6133
6088
|
let inQuotes = false;
|
|
6134
6089
|
let quoteChar = "";
|
|
6135
|
-
for (let i = 0; i <
|
|
6136
|
-
const char =
|
|
6090
|
+
for (let i = 0; i < path47.length; i++) {
|
|
6091
|
+
const char = path47[i];
|
|
6137
6092
|
if ((char === '"' || char === "'") && bracketCount > 0) {
|
|
6138
6093
|
if (!inQuotes) {
|
|
6139
6094
|
inQuotes = true;
|
|
@@ -6147,20 +6102,20 @@ var require_redact = __commonJS({
|
|
|
6147
6102
|
} else if (char === "]" && !inQuotes) {
|
|
6148
6103
|
bracketCount--;
|
|
6149
6104
|
if (bracketCount < 0) {
|
|
6150
|
-
throw new Error(`Invalid redaction path (${
|
|
6105
|
+
throw new Error(`Invalid redaction path (${path47})`);
|
|
6151
6106
|
}
|
|
6152
6107
|
}
|
|
6153
6108
|
}
|
|
6154
6109
|
if (bracketCount !== 0) {
|
|
6155
|
-
throw new Error(`Invalid redaction path (${
|
|
6110
|
+
throw new Error(`Invalid redaction path (${path47})`);
|
|
6156
6111
|
}
|
|
6157
6112
|
}
|
|
6158
6113
|
function validatePaths(paths) {
|
|
6159
6114
|
if (!Array.isArray(paths)) {
|
|
6160
6115
|
throw new TypeError("paths must be an array");
|
|
6161
6116
|
}
|
|
6162
|
-
for (const
|
|
6163
|
-
validatePath(
|
|
6117
|
+
for (const path47 of paths) {
|
|
6118
|
+
validatePath(path47);
|
|
6164
6119
|
}
|
|
6165
6120
|
}
|
|
6166
6121
|
function slowRedact(options = {}) {
|
|
@@ -6328,8 +6283,8 @@ var require_redaction = __commonJS({
|
|
|
6328
6283
|
if (shape[k2] === null) {
|
|
6329
6284
|
o[k2] = (value) => topCensor(value, [k2]);
|
|
6330
6285
|
} else {
|
|
6331
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
6332
|
-
return censor(value, [k2, ...
|
|
6286
|
+
const wrappedCensor = typeof censor === "function" ? (value, path47) => {
|
|
6287
|
+
return censor(value, [k2, ...path47]);
|
|
6333
6288
|
} : censor;
|
|
6334
6289
|
o[k2] = Redact({
|
|
6335
6290
|
paths: shape[k2],
|
|
@@ -6547,10 +6502,10 @@ var require_atomic_sleep = __commonJS({
|
|
|
6547
6502
|
var require_sonic_boom = __commonJS({
|
|
6548
6503
|
"../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
|
|
6549
6504
|
"use strict";
|
|
6550
|
-
var
|
|
6505
|
+
var fs38 = require("fs");
|
|
6551
6506
|
var EventEmitter2 = require("events");
|
|
6552
6507
|
var inherits = require("util").inherits;
|
|
6553
|
-
var
|
|
6508
|
+
var path47 = require("path");
|
|
6554
6509
|
var sleep = require_atomic_sleep();
|
|
6555
6510
|
var assert = require("assert");
|
|
6556
6511
|
var BUSY_WRITE_TIMEOUT = 100;
|
|
@@ -6604,20 +6559,20 @@ var require_sonic_boom = __commonJS({
|
|
|
6604
6559
|
const mode = sonic.mode;
|
|
6605
6560
|
if (sonic.sync) {
|
|
6606
6561
|
try {
|
|
6607
|
-
if (sonic.mkdir)
|
|
6608
|
-
const fd =
|
|
6562
|
+
if (sonic.mkdir) fs38.mkdirSync(path47.dirname(file), { recursive: true });
|
|
6563
|
+
const fd = fs38.openSync(file, flags, mode);
|
|
6609
6564
|
fileOpened(null, fd);
|
|
6610
6565
|
} catch (err) {
|
|
6611
6566
|
fileOpened(err);
|
|
6612
6567
|
throw err;
|
|
6613
6568
|
}
|
|
6614
6569
|
} else if (sonic.mkdir) {
|
|
6615
|
-
|
|
6570
|
+
fs38.mkdir(path47.dirname(file), { recursive: true }, (err) => {
|
|
6616
6571
|
if (err) return fileOpened(err);
|
|
6617
|
-
|
|
6572
|
+
fs38.open(file, flags, mode, fileOpened);
|
|
6618
6573
|
});
|
|
6619
6574
|
} else {
|
|
6620
|
-
|
|
6575
|
+
fs38.open(file, flags, mode, fileOpened);
|
|
6621
6576
|
}
|
|
6622
6577
|
}
|
|
6623
6578
|
function SonicBoom(opts) {
|
|
@@ -6658,8 +6613,8 @@ var require_sonic_boom = __commonJS({
|
|
|
6658
6613
|
this.flush = flushBuffer;
|
|
6659
6614
|
this.flushSync = flushBufferSync;
|
|
6660
6615
|
this._actualWrite = actualWriteBuffer;
|
|
6661
|
-
fsWriteSync = () =>
|
|
6662
|
-
fsWrite = () =>
|
|
6616
|
+
fsWriteSync = () => fs38.writeSync(this.fd, this._writingBuf);
|
|
6617
|
+
fsWrite = () => fs38.write(this.fd, this._writingBuf, this.release);
|
|
6663
6618
|
} else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
|
|
6664
6619
|
this._writingBuf = "";
|
|
6665
6620
|
this.write = write;
|
|
@@ -6668,15 +6623,15 @@ var require_sonic_boom = __commonJS({
|
|
|
6668
6623
|
this._actualWrite = actualWrite;
|
|
6669
6624
|
fsWriteSync = () => {
|
|
6670
6625
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
6671
|
-
return
|
|
6626
|
+
return fs38.writeSync(this.fd, this._writingBuf);
|
|
6672
6627
|
}
|
|
6673
|
-
return
|
|
6628
|
+
return fs38.writeSync(this.fd, this._writingBuf, "utf8");
|
|
6674
6629
|
};
|
|
6675
6630
|
fsWrite = () => {
|
|
6676
6631
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
6677
|
-
return
|
|
6632
|
+
return fs38.write(this.fd, this._writingBuf, this.release);
|
|
6678
6633
|
}
|
|
6679
|
-
return
|
|
6634
|
+
return fs38.write(this.fd, this._writingBuf, "utf8", this.release);
|
|
6680
6635
|
};
|
|
6681
6636
|
} else {
|
|
6682
6637
|
throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
|
|
@@ -6733,7 +6688,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6733
6688
|
}
|
|
6734
6689
|
}
|
|
6735
6690
|
if (this._fsync) {
|
|
6736
|
-
|
|
6691
|
+
fs38.fsyncSync(this.fd);
|
|
6737
6692
|
}
|
|
6738
6693
|
const len = this._len;
|
|
6739
6694
|
if (this._reopening) {
|
|
@@ -6847,7 +6802,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6847
6802
|
const onDrain = () => {
|
|
6848
6803
|
if (!this._fsync) {
|
|
6849
6804
|
try {
|
|
6850
|
-
|
|
6805
|
+
fs38.fsync(this.fd, (err) => {
|
|
6851
6806
|
this._flushPending = false;
|
|
6852
6807
|
cb(err);
|
|
6853
6808
|
});
|
|
@@ -6949,7 +6904,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6949
6904
|
const fd = this.fd;
|
|
6950
6905
|
this.once("ready", () => {
|
|
6951
6906
|
if (fd !== this.fd) {
|
|
6952
|
-
|
|
6907
|
+
fs38.close(fd, (err) => {
|
|
6953
6908
|
if (err) {
|
|
6954
6909
|
return this.emit("error", err);
|
|
6955
6910
|
}
|
|
@@ -6998,7 +6953,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6998
6953
|
buf = this._bufs[0];
|
|
6999
6954
|
}
|
|
7000
6955
|
try {
|
|
7001
|
-
const n = Buffer.isBuffer(buf) ?
|
|
6956
|
+
const n = Buffer.isBuffer(buf) ? fs38.writeSync(this.fd, buf) : fs38.writeSync(this.fd, buf, "utf8");
|
|
7002
6957
|
const releasedBufObj = releaseWritingBuf(buf, this._len, n);
|
|
7003
6958
|
buf = releasedBufObj.writingBuf;
|
|
7004
6959
|
this._len = releasedBufObj.len;
|
|
@@ -7014,7 +6969,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7014
6969
|
}
|
|
7015
6970
|
}
|
|
7016
6971
|
try {
|
|
7017
|
-
|
|
6972
|
+
fs38.fsyncSync(this.fd);
|
|
7018
6973
|
} catch {
|
|
7019
6974
|
}
|
|
7020
6975
|
}
|
|
@@ -7035,7 +6990,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7035
6990
|
buf = mergeBuf(this._bufs[0], this._lens[0]);
|
|
7036
6991
|
}
|
|
7037
6992
|
try {
|
|
7038
|
-
const n =
|
|
6993
|
+
const n = fs38.writeSync(this.fd, buf);
|
|
7039
6994
|
buf = buf.subarray(n);
|
|
7040
6995
|
this._len = Math.max(this._len - n, 0);
|
|
7041
6996
|
if (buf.length <= 0) {
|
|
@@ -7063,13 +7018,13 @@ var require_sonic_boom = __commonJS({
|
|
|
7063
7018
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
|
|
7064
7019
|
if (this.sync) {
|
|
7065
7020
|
try {
|
|
7066
|
-
const written = Buffer.isBuffer(this._writingBuf) ?
|
|
7021
|
+
const written = Buffer.isBuffer(this._writingBuf) ? fs38.writeSync(this.fd, this._writingBuf) : fs38.writeSync(this.fd, this._writingBuf, "utf8");
|
|
7067
7022
|
release(null, written);
|
|
7068
7023
|
} catch (err) {
|
|
7069
7024
|
release(err);
|
|
7070
7025
|
}
|
|
7071
7026
|
} else {
|
|
7072
|
-
|
|
7027
|
+
fs38.write(this.fd, this._writingBuf, release);
|
|
7073
7028
|
}
|
|
7074
7029
|
}
|
|
7075
7030
|
function actualWriteBuffer() {
|
|
@@ -7078,7 +7033,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7078
7033
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
|
|
7079
7034
|
if (this.sync) {
|
|
7080
7035
|
try {
|
|
7081
|
-
const written =
|
|
7036
|
+
const written = fs38.writeSync(this.fd, this._writingBuf);
|
|
7082
7037
|
release(null, written);
|
|
7083
7038
|
} catch (err) {
|
|
7084
7039
|
release(err);
|
|
@@ -7087,7 +7042,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7087
7042
|
if (kCopyBuffer) {
|
|
7088
7043
|
this._writingBuf = Buffer.from(this._writingBuf);
|
|
7089
7044
|
}
|
|
7090
|
-
|
|
7045
|
+
fs38.write(this.fd, this._writingBuf, release);
|
|
7091
7046
|
}
|
|
7092
7047
|
}
|
|
7093
7048
|
function actualClose(sonic) {
|
|
@@ -7103,12 +7058,12 @@ var require_sonic_boom = __commonJS({
|
|
|
7103
7058
|
sonic._lens = [];
|
|
7104
7059
|
assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
|
|
7105
7060
|
try {
|
|
7106
|
-
|
|
7061
|
+
fs38.fsync(sonic.fd, closeWrapped);
|
|
7107
7062
|
} catch {
|
|
7108
7063
|
}
|
|
7109
7064
|
function closeWrapped() {
|
|
7110
7065
|
if (sonic.fd !== 1 && sonic.fd !== 2) {
|
|
7111
|
-
|
|
7066
|
+
fs38.close(sonic.fd, done);
|
|
7112
7067
|
} else {
|
|
7113
7068
|
done();
|
|
7114
7069
|
}
|
|
@@ -10243,11 +10198,11 @@ var init_lib = __esm({
|
|
|
10243
10198
|
}
|
|
10244
10199
|
}
|
|
10245
10200
|
},
|
|
10246
|
-
addToPath: function addToPath(
|
|
10247
|
-
var last =
|
|
10201
|
+
addToPath: function addToPath(path47, added, removed, oldPosInc, options) {
|
|
10202
|
+
var last = path47.lastComponent;
|
|
10248
10203
|
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
10249
10204
|
return {
|
|
10250
|
-
oldPos:
|
|
10205
|
+
oldPos: path47.oldPos + oldPosInc,
|
|
10251
10206
|
lastComponent: {
|
|
10252
10207
|
count: last.count + 1,
|
|
10253
10208
|
added,
|
|
@@ -10257,7 +10212,7 @@ var init_lib = __esm({
|
|
|
10257
10212
|
};
|
|
10258
10213
|
} else {
|
|
10259
10214
|
return {
|
|
10260
|
-
oldPos:
|
|
10215
|
+
oldPos: path47.oldPos + oldPosInc,
|
|
10261
10216
|
lastComponent: {
|
|
10262
10217
|
count: 1,
|
|
10263
10218
|
added,
|
|
@@ -10503,7 +10458,7 @@ function hashDirToCwd(hash) {
|
|
|
10503
10458
|
}
|
|
10504
10459
|
function safeStatMtime(p2) {
|
|
10505
10460
|
try {
|
|
10506
|
-
return
|
|
10461
|
+
return import_node_fs8.default.statSync(p2).mtimeMs;
|
|
10507
10462
|
} catch {
|
|
10508
10463
|
return 0;
|
|
10509
10464
|
}
|
|
@@ -10511,7 +10466,7 @@ function safeStatMtime(p2) {
|
|
|
10511
10466
|
function readJsonlLines(file) {
|
|
10512
10467
|
let raw;
|
|
10513
10468
|
try {
|
|
10514
|
-
raw =
|
|
10469
|
+
raw = import_node_fs8.default.readFileSync(file, "utf8");
|
|
10515
10470
|
} catch (err) {
|
|
10516
10471
|
if (err.code === "ENOENT") return [];
|
|
10517
10472
|
throw err;
|
|
@@ -10688,10 +10643,10 @@ function attachmentToHistoryMessage(o, ts) {
|
|
|
10688
10643
|
const memories = raw.map((m2) => {
|
|
10689
10644
|
if (!m2 || typeof m2 !== "object") return null;
|
|
10690
10645
|
const rec = m2;
|
|
10691
|
-
const
|
|
10646
|
+
const path47 = typeof rec.path === "string" ? rec.path : null;
|
|
10692
10647
|
const content = typeof rec.content === "string" ? rec.content : null;
|
|
10693
|
-
if (!
|
|
10694
|
-
const entry = { path:
|
|
10648
|
+
if (!path47 || content == null) return null;
|
|
10649
|
+
const entry = { path: path47, content };
|
|
10695
10650
|
if (typeof rec.mtimeMs === "number") entry.mtimeMs = rec.mtimeMs;
|
|
10696
10651
|
return entry;
|
|
10697
10652
|
}).filter((m2) => m2 !== null);
|
|
@@ -10727,8 +10682,8 @@ function attachmentDeferredToolsText(a) {
|
|
|
10727
10682
|
function readBackupContent(fileHistoryRoot, toolSessionId, backupFileName) {
|
|
10728
10683
|
if (backupFileName === null) return null;
|
|
10729
10684
|
try {
|
|
10730
|
-
return
|
|
10731
|
-
|
|
10685
|
+
return import_node_fs8.default.readFileSync(
|
|
10686
|
+
import_node_path9.default.join(fileHistoryRoot, toolSessionId, backupFileName),
|
|
10732
10687
|
"utf8"
|
|
10733
10688
|
);
|
|
10734
10689
|
} catch {
|
|
@@ -10737,19 +10692,19 @@ function readBackupContent(fileHistoryRoot, toolSessionId, backupFileName) {
|
|
|
10737
10692
|
}
|
|
10738
10693
|
function readCurrentContent(filePath) {
|
|
10739
10694
|
try {
|
|
10740
|
-
return
|
|
10695
|
+
return import_node_fs8.default.readFileSync(filePath, "utf8");
|
|
10741
10696
|
} catch (err) {
|
|
10742
10697
|
if (err.code === "ENOENT") return null;
|
|
10743
10698
|
return null;
|
|
10744
10699
|
}
|
|
10745
10700
|
}
|
|
10746
|
-
var
|
|
10701
|
+
var import_node_fs8, import_node_os3, import_node_path9, TASK_NOTIFICATION_RE, TASK_ID_RE, TOOL_USE_ID_RE, SLASH_COMMAND_RE, LOCAL_COMMAND_RE, SYSTEM_REMINDER_RE, OPENSPEC_BLOCK_RE, SKILL_HINT_RE, ATTACHMENT_SILENT_SUBTYPES, ClaudeHistoryReader;
|
|
10747
10702
|
var init_claude_history = __esm({
|
|
10748
10703
|
"src/tools/claude-history.ts"() {
|
|
10749
10704
|
"use strict";
|
|
10750
|
-
|
|
10705
|
+
import_node_fs8 = __toESM(require("fs"), 1);
|
|
10751
10706
|
import_node_os3 = __toESM(require("os"), 1);
|
|
10752
|
-
|
|
10707
|
+
import_node_path9 = __toESM(require("path"), 1);
|
|
10753
10708
|
init_lib();
|
|
10754
10709
|
init_tool_result_extra();
|
|
10755
10710
|
TASK_NOTIFICATION_RE = /<task-notification\b[\s\S]*?<\/task-notification>/i;
|
|
@@ -10773,14 +10728,14 @@ var init_claude_history = __esm({
|
|
|
10773
10728
|
// 每次 user 提交前 trackEdit 拷一份,作为 rewind 回退目标
|
|
10774
10729
|
fileHistoryRoot;
|
|
10775
10730
|
constructor(opts = {}) {
|
|
10776
|
-
const base = opts.baseDir ??
|
|
10777
|
-
this.projectsRoot =
|
|
10778
|
-
this.fileHistoryRoot =
|
|
10731
|
+
const base = opts.baseDir ?? import_node_path9.default.join(import_node_os3.default.homedir(), ".claude");
|
|
10732
|
+
this.projectsRoot = import_node_path9.default.join(base, "projects");
|
|
10733
|
+
this.fileHistoryRoot = import_node_path9.default.join(base, "file-history");
|
|
10779
10734
|
}
|
|
10780
10735
|
async listProjects() {
|
|
10781
10736
|
let entries;
|
|
10782
10737
|
try {
|
|
10783
|
-
entries =
|
|
10738
|
+
entries = import_node_fs8.default.readdirSync(this.projectsRoot, { withFileTypes: true });
|
|
10784
10739
|
} catch (err) {
|
|
10785
10740
|
if (err.code === "ENOENT") return [];
|
|
10786
10741
|
throw err;
|
|
@@ -10788,9 +10743,9 @@ var init_claude_history = __esm({
|
|
|
10788
10743
|
const out = [];
|
|
10789
10744
|
for (const ent of entries) {
|
|
10790
10745
|
if (!ent.isDirectory()) continue;
|
|
10791
|
-
const dir =
|
|
10792
|
-
const files =
|
|
10793
|
-
const updatedAtMs = files.reduce((m2, f) => Math.max(m2, safeStatMtime(
|
|
10746
|
+
const dir = import_node_path9.default.join(this.projectsRoot, ent.name);
|
|
10747
|
+
const files = import_node_fs8.default.readdirSync(dir).filter((f) => f.endsWith(".jsonl"));
|
|
10748
|
+
const updatedAtMs = files.reduce((m2, f) => Math.max(m2, safeStatMtime(import_node_path9.default.join(dir, f))), 0);
|
|
10794
10749
|
out.push({
|
|
10795
10750
|
projectPath: hashDirToCwd(ent.name),
|
|
10796
10751
|
hashDir: ent.name,
|
|
@@ -10802,17 +10757,17 @@ var init_claude_history = __esm({
|
|
|
10802
10757
|
return out;
|
|
10803
10758
|
}
|
|
10804
10759
|
async listSessions(args) {
|
|
10805
|
-
const dir =
|
|
10760
|
+
const dir = import_node_path9.default.join(this.projectsRoot, cwdToHashDir(args.projectPath));
|
|
10806
10761
|
let files;
|
|
10807
10762
|
try {
|
|
10808
|
-
files =
|
|
10763
|
+
files = import_node_fs8.default.readdirSync(dir).filter((f) => f.endsWith(".jsonl"));
|
|
10809
10764
|
} catch (err) {
|
|
10810
10765
|
if (err.code === "ENOENT") return [];
|
|
10811
10766
|
throw err;
|
|
10812
10767
|
}
|
|
10813
10768
|
const out = [];
|
|
10814
10769
|
for (const f of files) {
|
|
10815
|
-
const full =
|
|
10770
|
+
const full = import_node_path9.default.join(dir, f);
|
|
10816
10771
|
const toolSessionId = f.slice(0, -".jsonl".length);
|
|
10817
10772
|
const lines = readJsonlLines(full);
|
|
10818
10773
|
let summary = "";
|
|
@@ -10867,7 +10822,7 @@ var init_claude_history = __esm({
|
|
|
10867
10822
|
return out;
|
|
10868
10823
|
}
|
|
10869
10824
|
async read(args) {
|
|
10870
|
-
const file =
|
|
10825
|
+
const file = import_node_path9.default.join(
|
|
10871
10826
|
this.projectsRoot,
|
|
10872
10827
|
cwdToHashDir(args.cwd),
|
|
10873
10828
|
`${args.toolSessionId}.jsonl`
|
|
@@ -10900,7 +10855,7 @@ var init_claude_history = __esm({
|
|
|
10900
10855
|
// 独立目录路径:<projectsRoot>/<cwdHash>/<toolSessionId>/subagents/*.jsonl
|
|
10901
10856
|
// 返回 null 表示目录不存在(调用方回退旧实现);返回空数组表示目录存在但无 jsonl
|
|
10902
10857
|
listSubagentsFromDirectory(cwd, toolSessionId) {
|
|
10903
|
-
const dir =
|
|
10858
|
+
const dir = import_node_path9.default.join(
|
|
10904
10859
|
this.projectsRoot,
|
|
10905
10860
|
cwdToHashDir(cwd),
|
|
10906
10861
|
toolSessionId,
|
|
@@ -10908,7 +10863,7 @@ var init_claude_history = __esm({
|
|
|
10908
10863
|
);
|
|
10909
10864
|
let entries;
|
|
10910
10865
|
try {
|
|
10911
|
-
entries =
|
|
10866
|
+
entries = import_node_fs8.default.readdirSync(dir, { withFileTypes: true });
|
|
10912
10867
|
} catch (err) {
|
|
10913
10868
|
if (err.code === "ENOENT") return null;
|
|
10914
10869
|
return null;
|
|
@@ -10918,7 +10873,7 @@ var init_claude_history = __esm({
|
|
|
10918
10873
|
if (!e.isFile()) continue;
|
|
10919
10874
|
if (!e.name.startsWith("agent-") || !e.name.endsWith(".jsonl")) continue;
|
|
10920
10875
|
const subagentId = e.name.slice("agent-".length, -".jsonl".length);
|
|
10921
|
-
const filePath =
|
|
10876
|
+
const filePath = import_node_path9.default.join(dir, e.name);
|
|
10922
10877
|
const lines = readJsonlLines(filePath);
|
|
10923
10878
|
let firstText = "";
|
|
10924
10879
|
let messageCount = 0;
|
|
@@ -10935,7 +10890,7 @@ var init_claude_history = __esm({
|
|
|
10935
10890
|
return out;
|
|
10936
10891
|
}
|
|
10937
10892
|
listSubagentsFromMainJsonl(cwd, toolSessionId) {
|
|
10938
|
-
const file =
|
|
10893
|
+
const file = import_node_path9.default.join(
|
|
10939
10894
|
this.projectsRoot,
|
|
10940
10895
|
cwdToHashDir(cwd),
|
|
10941
10896
|
`${toolSessionId}.jsonl`
|
|
@@ -10970,7 +10925,7 @@ var init_claude_history = __esm({
|
|
|
10970
10925
|
}
|
|
10971
10926
|
// 独立文件路径:agent-<subagentId>.jsonl;文件不存在返回 null 让调用方回退旧实现
|
|
10972
10927
|
readSubagentFromFile(cwd, toolSessionId, subagentId) {
|
|
10973
|
-
const file =
|
|
10928
|
+
const file = import_node_path9.default.join(
|
|
10974
10929
|
this.projectsRoot,
|
|
10975
10930
|
cwdToHashDir(cwd),
|
|
10976
10931
|
toolSessionId,
|
|
@@ -10979,7 +10934,7 @@ var init_claude_history = __esm({
|
|
|
10979
10934
|
);
|
|
10980
10935
|
let exists = false;
|
|
10981
10936
|
try {
|
|
10982
|
-
exists =
|
|
10937
|
+
exists = import_node_fs8.default.statSync(file).isFile();
|
|
10983
10938
|
} catch {
|
|
10984
10939
|
return null;
|
|
10985
10940
|
}
|
|
@@ -10998,7 +10953,7 @@ var init_claude_history = __esm({
|
|
|
10998
10953
|
* "那一刻每个 tracked 文件对应的 backup 文件名"
|
|
10999
10954
|
*/
|
|
11000
10955
|
readFileHistorySnapshots(args) {
|
|
11001
|
-
const file =
|
|
10956
|
+
const file = import_node_path9.default.join(
|
|
11002
10957
|
this.projectsRoot,
|
|
11003
10958
|
cwdToHashDir(args.cwd),
|
|
11004
10959
|
`${args.toolSessionId}.jsonl`
|
|
@@ -11043,7 +10998,7 @@ var init_claude_history = __esm({
|
|
|
11043
10998
|
for (const [anchorId, target] of snapshots) {
|
|
11044
10999
|
let hasAny = false;
|
|
11045
11000
|
for (const [rawPath, backup] of Object.entries(target)) {
|
|
11046
|
-
const absPath =
|
|
11001
|
+
const absPath = import_node_path9.default.isAbsolute(rawPath) ? rawPath : import_node_path9.default.join(args.cwd, rawPath);
|
|
11047
11002
|
const backupContent = readBackupContent(
|
|
11048
11003
|
this.fileHistoryRoot,
|
|
11049
11004
|
args.toolSessionId,
|
|
@@ -11083,7 +11038,7 @@ var init_claude_history = __esm({
|
|
|
11083
11038
|
let totalInsertions = 0;
|
|
11084
11039
|
let totalDeletions = 0;
|
|
11085
11040
|
for (const [rawPath, backup] of Object.entries(target)) {
|
|
11086
|
-
const absPath =
|
|
11041
|
+
const absPath = import_node_path9.default.isAbsolute(rawPath) ? rawPath : import_node_path9.default.join(args.cwd, rawPath);
|
|
11087
11042
|
const backupContent = readBackupContent(
|
|
11088
11043
|
this.fileHistoryRoot,
|
|
11089
11044
|
args.toolSessionId,
|
|
@@ -11130,7 +11085,7 @@ var init_claude_history = __esm({
|
|
|
11130
11085
|
};
|
|
11131
11086
|
}
|
|
11132
11087
|
readSubagentFromMainJsonl(cwd, toolSessionId, subagentId) {
|
|
11133
|
-
const file =
|
|
11088
|
+
const file = import_node_path9.default.join(
|
|
11134
11089
|
this.projectsRoot,
|
|
11135
11090
|
cwdToHashDir(cwd),
|
|
11136
11091
|
`${toolSessionId}.jsonl`
|
|
@@ -11154,48 +11109,48 @@ var init_claude_history = __esm({
|
|
|
11154
11109
|
// src/tools/sandbox.ts
|
|
11155
11110
|
function shouldSandbox(cwd, personaRoot) {
|
|
11156
11111
|
if (!personaRoot) return false;
|
|
11157
|
-
const sep3 = personaRoot.endsWith(
|
|
11112
|
+
const sep3 = personaRoot.endsWith(path13.sep) ? "" : path13.sep;
|
|
11158
11113
|
return cwd.startsWith(personaRoot + sep3) && cwd !== personaRoot;
|
|
11159
11114
|
}
|
|
11160
11115
|
function inferSandboxSettingsPath(cwd, personaRoot) {
|
|
11161
11116
|
if (!shouldSandbox(cwd, personaRoot)) return null;
|
|
11162
|
-
const rel =
|
|
11163
|
-
const personaId = rel.split(
|
|
11117
|
+
const rel = path13.relative(personaRoot, cwd);
|
|
11118
|
+
const personaId = rel.split(path13.sep)[0];
|
|
11164
11119
|
if (!personaId) return null;
|
|
11165
|
-
return
|
|
11120
|
+
return path13.join(personaRoot, personaId, ".clawd", "sandbox-settings.json");
|
|
11166
11121
|
}
|
|
11167
|
-
var
|
|
11122
|
+
var path13;
|
|
11168
11123
|
var init_sandbox = __esm({
|
|
11169
11124
|
"src/tools/sandbox.ts"() {
|
|
11170
11125
|
"use strict";
|
|
11171
|
-
|
|
11126
|
+
path13 = __toESM(require("path"), 1);
|
|
11172
11127
|
}
|
|
11173
11128
|
});
|
|
11174
11129
|
|
|
11175
11130
|
// src/tools/claude.ts
|
|
11176
11131
|
function macOSDesktopCandidates(home) {
|
|
11177
11132
|
return [
|
|
11178
|
-
|
|
11133
|
+
import_node_path10.default.join(home, "Applications", "Claude.app", "Contents", "Resources", "app.asar.unpacked", "node_modules", "@anthropic-ai", "claude-code", "cli.js"),
|
|
11179
11134
|
"/Applications/Claude.app/Contents/Resources/app.asar.unpacked/node_modules/@anthropic-ai/claude-code/cli.js"
|
|
11180
11135
|
];
|
|
11181
11136
|
}
|
|
11182
11137
|
function probeViaWhich() {
|
|
11183
11138
|
try {
|
|
11184
11139
|
const out = (0, import_node_child_process2.execFileSync)("which", ["claude"], { encoding: "utf8" }).trim();
|
|
11185
|
-
if (out &&
|
|
11140
|
+
if (out && import_node_fs9.default.existsSync(out)) return out;
|
|
11186
11141
|
} catch {
|
|
11187
11142
|
}
|
|
11188
11143
|
return null;
|
|
11189
11144
|
}
|
|
11190
11145
|
async function probeClaude(env = process.env, home = import_node_os4.default.homedir()) {
|
|
11191
|
-
if (env.CLAUDE_BIN &&
|
|
11146
|
+
if (env.CLAUDE_BIN && import_node_fs9.default.existsSync(env.CLAUDE_BIN)) {
|
|
11192
11147
|
return { available: true, path: env.CLAUDE_BIN };
|
|
11193
11148
|
}
|
|
11194
11149
|
const w2 = probeViaWhich();
|
|
11195
11150
|
if (w2) return { available: true, path: w2 };
|
|
11196
11151
|
if (process.platform === "darwin") {
|
|
11197
11152
|
for (const candidate of macOSDesktopCandidates(home)) {
|
|
11198
|
-
if (
|
|
11153
|
+
if (import_node_fs9.default.existsSync(candidate)) {
|
|
11199
11154
|
return { available: true, path: candidate };
|
|
11200
11155
|
}
|
|
11201
11156
|
}
|
|
@@ -11517,10 +11472,10 @@ function parseAttachment(obj) {
|
|
|
11517
11472
|
const memories = raw.map((m2) => {
|
|
11518
11473
|
if (!m2 || typeof m2 !== "object") return null;
|
|
11519
11474
|
const rec = m2;
|
|
11520
|
-
const
|
|
11475
|
+
const path47 = typeof rec.path === "string" ? rec.path : null;
|
|
11521
11476
|
const content = typeof rec.content === "string" ? rec.content : null;
|
|
11522
|
-
if (!
|
|
11523
|
-
const out = { path:
|
|
11477
|
+
if (!path47 || content == null) return null;
|
|
11478
|
+
const out = { path: path47, content };
|
|
11524
11479
|
if (typeof rec.mtimeMs === "number") out.mtimeMs = rec.mtimeMs;
|
|
11525
11480
|
return out;
|
|
11526
11481
|
}).filter((m2) => m2 !== null);
|
|
@@ -11624,15 +11579,15 @@ function encodeClaudeStdin(text) {
|
|
|
11624
11579
|
};
|
|
11625
11580
|
return JSON.stringify(frame) + "\n";
|
|
11626
11581
|
}
|
|
11627
|
-
var import_node_child_process, import_node_child_process2,
|
|
11582
|
+
var import_node_child_process, import_node_child_process2, import_node_fs9, import_node_os4, import_node_path10, ATTACHMENT_SILENT_SUBTYPES2, unknownTypeHandler, ATTACHMENT_RE, IMAGE_EXT_MIME, CLAUDE_MODELS, CLAUDE_PERMISSION_MODES, CLAUDE_CAPABILITIES, ClaudeAdapter;
|
|
11628
11583
|
var init_claude = __esm({
|
|
11629
11584
|
"src/tools/claude.ts"() {
|
|
11630
11585
|
"use strict";
|
|
11631
11586
|
import_node_child_process = require("child_process");
|
|
11632
11587
|
import_node_child_process2 = require("child_process");
|
|
11633
|
-
|
|
11588
|
+
import_node_fs9 = __toESM(require("fs"), 1);
|
|
11634
11589
|
import_node_os4 = __toESM(require("os"), 1);
|
|
11635
|
-
|
|
11590
|
+
import_node_path10 = __toESM(require("path"), 1);
|
|
11636
11591
|
init_protocol();
|
|
11637
11592
|
init_claude_history();
|
|
11638
11593
|
init_tool_result_extra();
|
|
@@ -20435,7 +20390,7 @@ var require_websocket_server = __commonJS({
|
|
|
20435
20390
|
// src/run-case/recorder.ts
|
|
20436
20391
|
function startRunCaseRecorder(opts) {
|
|
20437
20392
|
const now = opts.now ?? Date.now;
|
|
20438
|
-
const dir =
|
|
20393
|
+
const dir = import_node_path33.default.dirname(opts.recordPath);
|
|
20439
20394
|
let stream = null;
|
|
20440
20395
|
let closing = false;
|
|
20441
20396
|
let closedSettled = false;
|
|
@@ -20449,8 +20404,8 @@ function startRunCaseRecorder(opts) {
|
|
|
20449
20404
|
});
|
|
20450
20405
|
const ensureStream = () => {
|
|
20451
20406
|
if (stream) return stream;
|
|
20452
|
-
|
|
20453
|
-
stream =
|
|
20407
|
+
import_node_fs30.default.mkdirSync(dir, { recursive: true });
|
|
20408
|
+
stream = import_node_fs30.default.createWriteStream(opts.recordPath, { flags: "a" });
|
|
20454
20409
|
stream.on("close", () => closedResolve());
|
|
20455
20410
|
return stream;
|
|
20456
20411
|
};
|
|
@@ -20475,12 +20430,12 @@ function startRunCaseRecorder(opts) {
|
|
|
20475
20430
|
};
|
|
20476
20431
|
return { tap, close, closed };
|
|
20477
20432
|
}
|
|
20478
|
-
var
|
|
20433
|
+
var import_node_fs30, import_node_path33;
|
|
20479
20434
|
var init_recorder = __esm({
|
|
20480
20435
|
"src/run-case/recorder.ts"() {
|
|
20481
20436
|
"use strict";
|
|
20482
|
-
|
|
20483
|
-
|
|
20437
|
+
import_node_fs30 = __toESM(require("fs"), 1);
|
|
20438
|
+
import_node_path33 = __toESM(require("path"), 1);
|
|
20484
20439
|
}
|
|
20485
20440
|
});
|
|
20486
20441
|
|
|
@@ -20523,7 +20478,7 @@ var init_wire = __esm({
|
|
|
20523
20478
|
// src/run-case/controller.ts
|
|
20524
20479
|
async function runController(opts) {
|
|
20525
20480
|
const now = opts.now ?? Date.now;
|
|
20526
|
-
const cwd = opts.cwd ?? (0,
|
|
20481
|
+
const cwd = opts.cwd ?? (0, import_node_fs31.mkdtempSync)(import_node_path34.default.join(import_node_os15.default.tmpdir(), "clawd-runcase-"));
|
|
20527
20482
|
const ownsCwd = opts.cwd === void 0;
|
|
20528
20483
|
const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
|
|
20529
20484
|
const spawnCtx = { cwd };
|
|
@@ -20684,19 +20639,19 @@ async function runController(opts) {
|
|
|
20684
20639
|
if (sigintHandler) process.off("SIGINT", sigintHandler);
|
|
20685
20640
|
if (ownsCwd) {
|
|
20686
20641
|
try {
|
|
20687
|
-
(0,
|
|
20642
|
+
(0, import_node_fs31.rmSync)(cwd, { recursive: true, force: true });
|
|
20688
20643
|
} catch {
|
|
20689
20644
|
}
|
|
20690
20645
|
}
|
|
20691
20646
|
return exitCode ?? 0;
|
|
20692
20647
|
}
|
|
20693
|
-
var
|
|
20648
|
+
var import_node_fs31, import_node_os15, import_node_path34;
|
|
20694
20649
|
var init_controller = __esm({
|
|
20695
20650
|
"src/run-case/controller.ts"() {
|
|
20696
20651
|
"use strict";
|
|
20697
|
-
|
|
20652
|
+
import_node_fs31 = require("fs");
|
|
20698
20653
|
import_node_os15 = __toESM(require("os"), 1);
|
|
20699
|
-
|
|
20654
|
+
import_node_path34 = __toESM(require("path"), 1);
|
|
20700
20655
|
init_claude();
|
|
20701
20656
|
init_stdout_splitter();
|
|
20702
20657
|
init_permission_stdio();
|
|
@@ -20928,8 +20883,8 @@ Env (advanced):
|
|
|
20928
20883
|
`;
|
|
20929
20884
|
|
|
20930
20885
|
// src/index.ts
|
|
20931
|
-
var
|
|
20932
|
-
var
|
|
20886
|
+
var import_node_path32 = __toESM(require("path"), 1);
|
|
20887
|
+
var import_node_fs29 = __toESM(require("fs"), 1);
|
|
20933
20888
|
|
|
20934
20889
|
// src/logger.ts
|
|
20935
20890
|
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
@@ -21153,8 +21108,8 @@ var SessionStoreFactory = class {
|
|
|
21153
21108
|
};
|
|
21154
21109
|
|
|
21155
21110
|
// src/session/manager.ts
|
|
21156
|
-
var
|
|
21157
|
-
var
|
|
21111
|
+
var import_node_fs6 = __toESM(require("fs"), 1);
|
|
21112
|
+
var import_node_path7 = __toESM(require("path"), 1);
|
|
21158
21113
|
|
|
21159
21114
|
// ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/stringify.js
|
|
21160
21115
|
var byteToHex = [];
|
|
@@ -22398,6 +22353,62 @@ function extractEditPath(input) {
|
|
|
22398
22353
|
return candidate || null;
|
|
22399
22354
|
}
|
|
22400
22355
|
|
|
22356
|
+
// src/debug/pty-probe.ts
|
|
22357
|
+
var import_node_fs5 = __toESM(require("fs"), 1);
|
|
22358
|
+
var import_node_path6 = __toESM(require("path"), 1);
|
|
22359
|
+
var PROBE_DIR = "/tmp/clawd-probe";
|
|
22360
|
+
var EVENTS_FILE = import_node_path6.default.join(PROBE_DIR, "events.jsonl");
|
|
22361
|
+
var inited = false;
|
|
22362
|
+
function ensureDir() {
|
|
22363
|
+
if (inited) return true;
|
|
22364
|
+
try {
|
|
22365
|
+
import_node_fs5.default.mkdirSync(PROBE_DIR, { recursive: true });
|
|
22366
|
+
inited = true;
|
|
22367
|
+
return true;
|
|
22368
|
+
} catch {
|
|
22369
|
+
return false;
|
|
22370
|
+
}
|
|
22371
|
+
}
|
|
22372
|
+
function probeEvent(event, data = {}) {
|
|
22373
|
+
try {
|
|
22374
|
+
if (!ensureDir()) return;
|
|
22375
|
+
const line = JSON.stringify({ ts: Date.now(), event, ...data }) + "\n";
|
|
22376
|
+
import_node_fs5.default.appendFileSync(EVENTS_FILE, line);
|
|
22377
|
+
} catch {
|
|
22378
|
+
}
|
|
22379
|
+
}
|
|
22380
|
+
function probeDumpReplay(sessionId, payload) {
|
|
22381
|
+
try {
|
|
22382
|
+
if (!ensureDir()) return "";
|
|
22383
|
+
const file = import_node_path6.default.join(PROBE_DIR, `replay-${sessionId}-${Date.now()}.ans`);
|
|
22384
|
+
import_node_fs5.default.writeFileSync(file, payload, "utf8");
|
|
22385
|
+
return file;
|
|
22386
|
+
} catch {
|
|
22387
|
+
return "";
|
|
22388
|
+
}
|
|
22389
|
+
}
|
|
22390
|
+
var _throttle = /* @__PURE__ */ new Map();
|
|
22391
|
+
function probePtyDataThrottled(tsid, len, tail) {
|
|
22392
|
+
const now = Date.now();
|
|
22393
|
+
let s = _throttle.get(tsid);
|
|
22394
|
+
if (!s) {
|
|
22395
|
+
s = { last: 0, bytes: 0, chunks: 0 };
|
|
22396
|
+
_throttle.set(tsid, s);
|
|
22397
|
+
}
|
|
22398
|
+
s.bytes += len;
|
|
22399
|
+
s.chunks += 1;
|
|
22400
|
+
if (now - s.last >= 1e3) {
|
|
22401
|
+
probeEvent("pty.data", {
|
|
22402
|
+
tsid,
|
|
22403
|
+
chunks: s.chunks,
|
|
22404
|
+
accumBytes: s.bytes,
|
|
22405
|
+
lastChunkLen: len,
|
|
22406
|
+
tailHex: tail.subarray(Math.max(0, tail.length - 32)).toString("hex")
|
|
22407
|
+
});
|
|
22408
|
+
s.last = now;
|
|
22409
|
+
}
|
|
22410
|
+
}
|
|
22411
|
+
|
|
22401
22412
|
// src/session/manager.ts
|
|
22402
22413
|
function compressFrameForWire(frame) {
|
|
22403
22414
|
if (frame.type !== "session:status") return frame;
|
|
@@ -22461,7 +22472,7 @@ function derivePersonaSpawnCwd(file, personaRoot) {
|
|
|
22461
22472
|
`derivePersonaSpawnCwd: personaRoot missing for owner session ${file.sessionId} (ownerPersonaId=${personaId})`
|
|
22462
22473
|
);
|
|
22463
22474
|
}
|
|
22464
|
-
return
|
|
22475
|
+
return import_node_path7.default.join(personaRoot, safeFileName(personaId));
|
|
22465
22476
|
}
|
|
22466
22477
|
function makeInitialState(file, subSessionMeta) {
|
|
22467
22478
|
return {
|
|
@@ -22575,10 +22586,10 @@ var SessionManager = class {
|
|
|
22575
22586
|
// <dataDir>/sessions/ 列子目录 (排除 'default').
|
|
22576
22587
|
listPersonaIdsOnDisk() {
|
|
22577
22588
|
if (!this.deps.dataDir) return [];
|
|
22578
|
-
const root = this.deps.storeFactory ?
|
|
22589
|
+
const root = this.deps.storeFactory ? import_node_path7.default.join(this.deps.dataDir, "personas") : import_node_path7.default.join(this.deps.dataDir, "sessions");
|
|
22579
22590
|
let entries;
|
|
22580
22591
|
try {
|
|
22581
|
-
entries =
|
|
22592
|
+
entries = import_node_fs6.default.readdirSync(root, { withFileTypes: true });
|
|
22582
22593
|
} catch (err) {
|
|
22583
22594
|
const code = err?.code;
|
|
22584
22595
|
if (code === "ENOENT") return [];
|
|
@@ -22591,7 +22602,7 @@ var SessionManager = class {
|
|
|
22591
22602
|
// 只在 storeFactory 注入 (新布局) 下生效, 老布局无 guest 目录.
|
|
22592
22603
|
listGuestCapIdsForPersona(personaId) {
|
|
22593
22604
|
if (!this.deps.dataDir || !this.deps.storeFactory) return [];
|
|
22594
|
-
const root =
|
|
22605
|
+
const root = import_node_path7.default.join(
|
|
22595
22606
|
this.deps.dataDir,
|
|
22596
22607
|
"personas",
|
|
22597
22608
|
personaId,
|
|
@@ -22601,7 +22612,7 @@ var SessionManager = class {
|
|
|
22601
22612
|
);
|
|
22602
22613
|
let entries;
|
|
22603
22614
|
try {
|
|
22604
|
-
entries =
|
|
22615
|
+
entries = import_node_fs6.default.readdirSync(root, { withFileTypes: true });
|
|
22605
22616
|
} catch (err) {
|
|
22606
22617
|
const code = err?.code;
|
|
22607
22618
|
if (code === "ENOENT") return [];
|
|
@@ -22838,7 +22849,7 @@ var SessionManager = class {
|
|
|
22838
22849
|
throw new ClawdError(ERROR_CODES.INVALID_CWD, "cwd required when ownerPersonaId is absent");
|
|
22839
22850
|
}
|
|
22840
22851
|
try {
|
|
22841
|
-
const stat =
|
|
22852
|
+
const stat = import_node_fs6.default.statSync(cwd);
|
|
22842
22853
|
if (!stat.isDirectory()) throw new Error("not dir");
|
|
22843
22854
|
} catch {
|
|
22844
22855
|
throw new ClawdError(ERROR_CODES.INVALID_CWD, `cwd not a directory: ${cwd}`);
|
|
@@ -22929,30 +22940,6 @@ var SessionManager = class {
|
|
|
22929
22940
|
const file = this.getFile(args.sessionId);
|
|
22930
22941
|
return { response: file, broadcast: [] };
|
|
22931
22942
|
}
|
|
22932
|
-
// mirror peer sessions (2026-05-26):把来自朋友 daemon 的 SessionFile(originOwnerPrincipalId
|
|
22933
|
-
// 非空)持久化到本机 default store。dumb write,**不广播 push 帧**——UI 是写入唯一源,
|
|
22934
|
-
// 双写完成后通过 cache.setData 同步 sidebar 本地 state。
|
|
22935
|
-
//
|
|
22936
|
-
// 强制走 deps.store(即 default scope),不走 scopeForFile:mirror 物理落 default 即可。
|
|
22937
|
-
// 远端 creator / origin 字段原值保留(不被本机 ctx 派生覆写)。
|
|
22938
|
-
//
|
|
22939
|
-
// strip 远端 personaId:mirror SessionFile 上的 ownerPersonaId 是朋友 daemon 的 persona
|
|
22940
|
-
// 目录 id,本机不持有对应 persona。留着会让按 ownerPersonaId 反查的本机消费者
|
|
22941
|
-
// (MyPersonasSection 等)把 mirror 误聚到同 id persona 下。写入前清掉。
|
|
22942
|
-
//
|
|
22943
|
-
// 与 manager.create / manager.update 区别:
|
|
22944
|
-
// - 不走 newRunner / attachObserver / cwd 校验(mirror 是纯 metadata 层)
|
|
22945
|
-
// - 不发 session:info 帧(manager.create / .update 通过 reducer/wireCollector 发 push)
|
|
22946
|
-
mirrorUpsert(file) {
|
|
22947
|
-
const { ownerPersonaId: _stripped, ...rest } = file;
|
|
22948
|
-
return this.deps.store.write(rest);
|
|
22949
|
-
}
|
|
22950
|
-
// mirror peer sessions:删本机 mirror SessionFile。mirror 一律落 default(mirrorUpsert
|
|
22951
|
-
// 强制走 deps.store + strip ownerPersonaId),删也只删 default。idempotent:找不到
|
|
22952
|
-
// 不 throw(store.delete 内部 ENOENT 兜底返 false 不 throw)。**不广播 session:deleted**。
|
|
22953
|
-
mirrorRemove(sessionId) {
|
|
22954
|
-
this.deps.store.delete(sessionId);
|
|
22955
|
-
}
|
|
22956
22943
|
// observer 上报"jsonl 写入了一条 user 行"时调用:在 buffer 里找到与之对应的、
|
|
22957
22944
|
// 还没建立映射的最早一条 synth user_text,记下 synth → real 映射。
|
|
22958
22945
|
// 找不到匹配的 synth(runner 不存在 / buffer 已被 /clear 清空 / 真 uuid 来自纯 history
|
|
@@ -23374,7 +23361,7 @@ var SessionManager = class {
|
|
|
23374
23361
|
*/
|
|
23375
23362
|
createForScope(args) {
|
|
23376
23363
|
try {
|
|
23377
|
-
const stat =
|
|
23364
|
+
const stat = import_node_fs6.default.statSync(args.cwd);
|
|
23378
23365
|
if (!stat.isDirectory()) throw new Error("not dir");
|
|
23379
23366
|
} catch {
|
|
23380
23367
|
throw new ClawdError(ERROR_CODES.INVALID_CWD, `cwd not a directory: ${args.cwd}`);
|
|
@@ -23709,15 +23696,27 @@ var SessionManager = class {
|
|
|
23709
23696
|
}
|
|
23710
23697
|
/** spawn 进程 exit 时调用,清理映射防止后续 input 写到已死 pty + 释放 replay 闭包 */
|
|
23711
23698
|
unregisterPty(toolSessionId) {
|
|
23699
|
+
const hadReplay = this.ptyReplaysByToolSid.has(toolSessionId);
|
|
23712
23700
|
this.ptyTransports.delete(toolSessionId);
|
|
23713
23701
|
this.ptyReplaysByToolSid.delete(toolSessionId);
|
|
23702
|
+
probeEvent("pty.unregister", {
|
|
23703
|
+
tsid: toolSessionId,
|
|
23704
|
+
hadReplay,
|
|
23705
|
+
replayMapKeys: Array.from(this.ptyReplaysByToolSid.keys())
|
|
23706
|
+
});
|
|
23714
23707
|
}
|
|
23715
23708
|
/**
|
|
23716
23709
|
* ClaudeTuiAdapter.spawn 创建 detector 后调用,注册当前屏幕快照闭包。
|
|
23717
23710
|
* 同一 toolSessionId 重 spawn 会覆盖;unregisterPty 时一并删除。
|
|
23718
23711
|
*/
|
|
23719
23712
|
registerPtyReplay(toolSessionId, replay) {
|
|
23713
|
+
const overwrite = this.ptyReplaysByToolSid.has(toolSessionId);
|
|
23720
23714
|
this.ptyReplaysByToolSid.set(toolSessionId, replay);
|
|
23715
|
+
probeEvent("pty.register", {
|
|
23716
|
+
tsid: toolSessionId,
|
|
23717
|
+
overwrite,
|
|
23718
|
+
replayMapKeys: Array.from(this.ptyReplaysByToolSid.keys())
|
|
23719
|
+
});
|
|
23721
23720
|
}
|
|
23722
23721
|
/**
|
|
23723
23722
|
* 新 client subscribe 时拉当前屏幕快照。返回 null 表示无可重放数据:
|
|
@@ -23726,14 +23725,47 @@ var SessionManager = class {
|
|
|
23726
23725
|
* 调用方(onSubscribe hook)按返回值非空时构造 session:pty + session:control 帧定向回放
|
|
23727
23726
|
*/
|
|
23728
23727
|
getPtyReplay(sessionId) {
|
|
23729
|
-
if (this.deps.mode !== "tui")
|
|
23728
|
+
if (this.deps.mode !== "tui") {
|
|
23729
|
+
probeEvent("replay.request", { sid: sessionId, result: "not-tui-mode" });
|
|
23730
|
+
return null;
|
|
23731
|
+
}
|
|
23730
23732
|
const runner = this.runners.get(sessionId);
|
|
23731
|
-
if (!runner)
|
|
23733
|
+
if (!runner) {
|
|
23734
|
+
probeEvent("replay.request", {
|
|
23735
|
+
sid: sessionId,
|
|
23736
|
+
result: "no-runner",
|
|
23737
|
+
runnerKeys: Array.from(this.runners.keys())
|
|
23738
|
+
});
|
|
23739
|
+
return null;
|
|
23740
|
+
}
|
|
23732
23741
|
const tsid = runner.getState().file.toolSessionId;
|
|
23733
|
-
if (!tsid)
|
|
23742
|
+
if (!tsid) {
|
|
23743
|
+
probeEvent("replay.request", { sid: sessionId, result: "no-tsid" });
|
|
23744
|
+
return null;
|
|
23745
|
+
}
|
|
23734
23746
|
const replay = this.ptyReplaysByToolSid.get(tsid);
|
|
23735
|
-
if (!replay)
|
|
23736
|
-
|
|
23747
|
+
if (!replay) {
|
|
23748
|
+
probeEvent("replay.request", {
|
|
23749
|
+
sid: sessionId,
|
|
23750
|
+
tsid,
|
|
23751
|
+
result: "no-replay-closure",
|
|
23752
|
+
replayMapKeys: Array.from(this.ptyReplaysByToolSid.keys())
|
|
23753
|
+
});
|
|
23754
|
+
return null;
|
|
23755
|
+
}
|
|
23756
|
+
const snap = replay();
|
|
23757
|
+
const dumpFile = probeDumpReplay(sessionId, snap.data);
|
|
23758
|
+
probeEvent("replay.dump", {
|
|
23759
|
+
sid: sessionId,
|
|
23760
|
+
tsid,
|
|
23761
|
+
bytes: snap.data.length,
|
|
23762
|
+
popupKind: snap.popupKind,
|
|
23763
|
+
headHex: Buffer.from(snap.data, "utf8").subarray(0, 32).toString("hex"),
|
|
23764
|
+
dumpFile,
|
|
23765
|
+
runnerKeys: Array.from(this.runners.keys()),
|
|
23766
|
+
replayMapKeys: Array.from(this.ptyReplaysByToolSid.keys())
|
|
23767
|
+
});
|
|
23768
|
+
return snap;
|
|
23737
23769
|
}
|
|
23738
23770
|
/**
|
|
23739
23771
|
* handler tui:pty:input / tui:pty:resize 入口:传 wire 层 sessionId(16 字符),
|
|
@@ -23796,8 +23828,8 @@ var SessionManager = class {
|
|
|
23796
23828
|
};
|
|
23797
23829
|
|
|
23798
23830
|
// src/persona/store.ts
|
|
23799
|
-
var
|
|
23800
|
-
var
|
|
23831
|
+
var fs7 = __toESM(require("fs"), 1);
|
|
23832
|
+
var path9 = __toESM(require("path"), 1);
|
|
23801
23833
|
init_protocol();
|
|
23802
23834
|
var DEFAULT_SETTINGS = {
|
|
23803
23835
|
permissions: {
|
|
@@ -23822,17 +23854,17 @@ var DEFAULT_SETTINGS = {
|
|
|
23822
23854
|
var PersonaStore = class {
|
|
23823
23855
|
constructor(root) {
|
|
23824
23856
|
this.root = root;
|
|
23825
|
-
|
|
23857
|
+
fs7.mkdirSync(root, { recursive: true });
|
|
23826
23858
|
}
|
|
23827
23859
|
root;
|
|
23828
23860
|
personaDir(personaId) {
|
|
23829
|
-
return
|
|
23861
|
+
return path9.join(this.root, safeFileName(personaId));
|
|
23830
23862
|
}
|
|
23831
23863
|
metaPath(personaId) {
|
|
23832
|
-
return
|
|
23864
|
+
return path9.join(this.personaDir(personaId), ".clawd", "persona.json");
|
|
23833
23865
|
}
|
|
23834
23866
|
claudeMdPath(personaId) {
|
|
23835
|
-
return
|
|
23867
|
+
return path9.join(this.personaDir(personaId), "CLAUDE.md");
|
|
23836
23868
|
}
|
|
23837
23869
|
/**
|
|
23838
23870
|
* Sandbox settings 落盘路径 —— 故意放在 `.clawd/` 而不是 `.claude/`,让 CC 的
|
|
@@ -23842,11 +23874,11 @@ var PersonaStore = class {
|
|
|
23842
23874
|
* 加载 persona 人格,只有 listener 多一层 OS sandbox。
|
|
23843
23875
|
*/
|
|
23844
23876
|
sandboxSettingsPath(personaId) {
|
|
23845
|
-
return
|
|
23877
|
+
return path9.join(this.personaDir(personaId), ".clawd", "sandbox-settings.json");
|
|
23846
23878
|
}
|
|
23847
23879
|
write(persona, personality) {
|
|
23848
23880
|
const dir = this.personaDir(persona.personaId);
|
|
23849
|
-
|
|
23881
|
+
fs7.mkdirSync(path9.join(dir, ".clawd"), { recursive: true });
|
|
23850
23882
|
this.atomicWrite(this.claudeMdPath(persona.personaId), personality);
|
|
23851
23883
|
this.atomicWrite(
|
|
23852
23884
|
this.sandboxSettingsPath(persona.personaId),
|
|
@@ -23862,8 +23894,8 @@ var PersonaStore = class {
|
|
|
23862
23894
|
}
|
|
23863
23895
|
read(personaId) {
|
|
23864
23896
|
const p2 = this.metaPath(personaId);
|
|
23865
|
-
if (!
|
|
23866
|
-
const raw = JSON.parse(
|
|
23897
|
+
if (!fs7.existsSync(p2)) return null;
|
|
23898
|
+
const raw = JSON.parse(fs7.readFileSync(p2, "utf8"));
|
|
23867
23899
|
if (raw && typeof raw === "object" && "tokenMap" in raw) {
|
|
23868
23900
|
delete raw.tokenMap;
|
|
23869
23901
|
this.atomicWrite(p2, JSON.stringify(raw, null, 2));
|
|
@@ -23871,12 +23903,12 @@ var PersonaStore = class {
|
|
|
23871
23903
|
return PersonaFileSchema.parse(raw);
|
|
23872
23904
|
}
|
|
23873
23905
|
has(personaId) {
|
|
23874
|
-
return
|
|
23906
|
+
return fs7.existsSync(this.metaPath(personaId));
|
|
23875
23907
|
}
|
|
23876
23908
|
readPersonality(personaId) {
|
|
23877
23909
|
const p2 = this.claudeMdPath(personaId);
|
|
23878
|
-
if (!
|
|
23879
|
-
return
|
|
23910
|
+
if (!fs7.existsSync(p2)) return null;
|
|
23911
|
+
return fs7.readFileSync(p2, "utf8");
|
|
23880
23912
|
}
|
|
23881
23913
|
/**
|
|
23882
23914
|
* 读 sandbox-settings.json 当前内容;文件不存在 / JSON 解析失败均返回 null。
|
|
@@ -23884,23 +23916,23 @@ var PersonaStore = class {
|
|
|
23884
23916
|
*/
|
|
23885
23917
|
readSandboxSettings(personaId) {
|
|
23886
23918
|
const p2 = this.sandboxSettingsPath(personaId);
|
|
23887
|
-
if (!
|
|
23919
|
+
if (!fs7.existsSync(p2)) return null;
|
|
23888
23920
|
try {
|
|
23889
|
-
return JSON.parse(
|
|
23921
|
+
return JSON.parse(fs7.readFileSync(p2, "utf8"));
|
|
23890
23922
|
} catch {
|
|
23891
23923
|
return null;
|
|
23892
23924
|
}
|
|
23893
23925
|
}
|
|
23894
23926
|
/** Persona 私有 skills 目录路径:<personaDir>/.claude/skills */
|
|
23895
23927
|
skillsDir(personaId) {
|
|
23896
|
-
return
|
|
23928
|
+
return path9.join(this.personaDir(personaId), ".claude", "skills");
|
|
23897
23929
|
}
|
|
23898
23930
|
/**
|
|
23899
23931
|
* Claude Code 项目级 settings 路径:`<personaDir>/.claude/settings.json`。
|
|
23900
23932
|
* 这里只读 `enabledPlugins` 字段,由 owner 通过 CC `/plugin` 之类命令维护,daemon 不写。
|
|
23901
23933
|
*/
|
|
23902
23934
|
claudeSettingsPath(personaId) {
|
|
23903
|
-
return
|
|
23935
|
+
return path9.join(this.personaDir(personaId), ".claude", "settings.json");
|
|
23904
23936
|
}
|
|
23905
23937
|
/**
|
|
23906
23938
|
* 读取 persona 的 `.claude/settings.json` 中 `enabledPlugins` map,把 value === true
|
|
@@ -23915,10 +23947,10 @@ var PersonaStore = class {
|
|
|
23915
23947
|
*/
|
|
23916
23948
|
readEnabledPlugins(personaId) {
|
|
23917
23949
|
const p2 = this.claudeSettingsPath(personaId);
|
|
23918
|
-
if (!
|
|
23950
|
+
if (!fs7.existsSync(p2)) return [];
|
|
23919
23951
|
let raw;
|
|
23920
23952
|
try {
|
|
23921
|
-
raw = JSON.parse(
|
|
23953
|
+
raw = JSON.parse(fs7.readFileSync(p2, "utf8"));
|
|
23922
23954
|
} catch {
|
|
23923
23955
|
return [];
|
|
23924
23956
|
}
|
|
@@ -23932,22 +23964,22 @@ var PersonaStore = class {
|
|
|
23932
23964
|
return out;
|
|
23933
23965
|
}
|
|
23934
23966
|
list() {
|
|
23935
|
-
if (!
|
|
23936
|
-
return
|
|
23937
|
-
return
|
|
23967
|
+
if (!fs7.existsSync(this.root)) return [];
|
|
23968
|
+
return fs7.readdirSync(this.root).filter((name) => {
|
|
23969
|
+
return fs7.existsSync(path9.join(this.root, name, ".clawd", "persona.json"));
|
|
23938
23970
|
});
|
|
23939
23971
|
}
|
|
23940
23972
|
remove(personaId) {
|
|
23941
23973
|
const dir = this.personaDir(personaId);
|
|
23942
|
-
if (
|
|
23974
|
+
if (fs7.existsSync(dir)) fs7.rmSync(dir, { recursive: true, force: true });
|
|
23943
23975
|
}
|
|
23944
23976
|
personaDirPath(personaId) {
|
|
23945
23977
|
return this.personaDir(personaId);
|
|
23946
23978
|
}
|
|
23947
23979
|
atomicWrite(file, content) {
|
|
23948
23980
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
23949
|
-
|
|
23950
|
-
|
|
23981
|
+
fs7.writeFileSync(tmp, content, { mode: 384 });
|
|
23982
|
+
fs7.renameSync(tmp, file);
|
|
23951
23983
|
}
|
|
23952
23984
|
};
|
|
23953
23985
|
|
|
@@ -23993,9 +24025,9 @@ var PersonaRegistry = class {
|
|
|
23993
24025
|
var import_node_crypto3 = __toESM(require("crypto"), 1);
|
|
23994
24026
|
|
|
23995
24027
|
// src/skills/scanner.ts
|
|
23996
|
-
var
|
|
24028
|
+
var import_node_fs7 = __toESM(require("fs"), 1);
|
|
23997
24029
|
var import_node_os2 = __toESM(require("os"), 1);
|
|
23998
|
-
var
|
|
24030
|
+
var import_node_path8 = __toESM(require("path"), 1);
|
|
23999
24031
|
|
|
24000
24032
|
// src/skills/frontmatter.ts
|
|
24001
24033
|
var STRIP_QUOTES = /^["']|["']$/g;
|
|
@@ -24104,7 +24136,7 @@ function parseDescription(content) {
|
|
|
24104
24136
|
}
|
|
24105
24137
|
function isDirLikeSync(p2) {
|
|
24106
24138
|
try {
|
|
24107
|
-
return
|
|
24139
|
+
return import_node_fs7.default.statSync(p2).isDirectory();
|
|
24108
24140
|
} catch {
|
|
24109
24141
|
return false;
|
|
24110
24142
|
}
|
|
@@ -24112,19 +24144,19 @@ function isDirLikeSync(p2) {
|
|
|
24112
24144
|
function scanSkillDir(dir, source, seen, out, pluginName) {
|
|
24113
24145
|
let entries;
|
|
24114
24146
|
try {
|
|
24115
|
-
entries =
|
|
24147
|
+
entries = import_node_fs7.default.readdirSync(dir, { withFileTypes: true });
|
|
24116
24148
|
} catch {
|
|
24117
24149
|
return;
|
|
24118
24150
|
}
|
|
24119
24151
|
for (const ent of entries) {
|
|
24120
|
-
const entryPath =
|
|
24152
|
+
const entryPath = import_node_path8.default.join(dir, ent.name);
|
|
24121
24153
|
if (!ent.isDirectory() && !(ent.isSymbolicLink() && isDirLikeSync(entryPath))) continue;
|
|
24122
24154
|
let content;
|
|
24123
24155
|
try {
|
|
24124
|
-
content =
|
|
24156
|
+
content = import_node_fs7.default.readFileSync(import_node_path8.default.join(entryPath, "SKILL.md"), "utf8");
|
|
24125
24157
|
} catch {
|
|
24126
24158
|
try {
|
|
24127
|
-
content =
|
|
24159
|
+
content = import_node_fs7.default.readFileSync(import_node_path8.default.join(entryPath, "skill.md"), "utf8");
|
|
24128
24160
|
} catch {
|
|
24129
24161
|
continue;
|
|
24130
24162
|
}
|
|
@@ -24148,26 +24180,26 @@ function listSkillsForDir(dir, source) {
|
|
|
24148
24180
|
function scanCommandDir(dir, source, seen, out, pluginName) {
|
|
24149
24181
|
let entries;
|
|
24150
24182
|
try {
|
|
24151
|
-
entries =
|
|
24183
|
+
entries = import_node_fs7.default.readdirSync(dir, { withFileTypes: true });
|
|
24152
24184
|
} catch {
|
|
24153
24185
|
return;
|
|
24154
24186
|
}
|
|
24155
24187
|
for (const ent of entries) {
|
|
24156
|
-
const entryPath =
|
|
24188
|
+
const entryPath = import_node_path8.default.join(dir, ent.name);
|
|
24157
24189
|
if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync(entryPath)) {
|
|
24158
24190
|
const ns = ent.name;
|
|
24159
24191
|
let subEntries;
|
|
24160
24192
|
try {
|
|
24161
|
-
subEntries =
|
|
24193
|
+
subEntries = import_node_fs7.default.readdirSync(entryPath, { withFileTypes: true });
|
|
24162
24194
|
} catch {
|
|
24163
24195
|
continue;
|
|
24164
24196
|
}
|
|
24165
24197
|
for (const se of subEntries) {
|
|
24166
24198
|
if (!se.name.endsWith(".md")) continue;
|
|
24167
|
-
const sePath =
|
|
24199
|
+
const sePath = import_node_path8.default.join(entryPath, se.name);
|
|
24168
24200
|
let content;
|
|
24169
24201
|
try {
|
|
24170
|
-
content =
|
|
24202
|
+
content = import_node_fs7.default.readFileSync(sePath, "utf8");
|
|
24171
24203
|
} catch {
|
|
24172
24204
|
continue;
|
|
24173
24205
|
}
|
|
@@ -24184,7 +24216,7 @@ function scanCommandDir(dir, source, seen, out, pluginName) {
|
|
|
24184
24216
|
} else if (ent.name.endsWith(".md")) {
|
|
24185
24217
|
let content;
|
|
24186
24218
|
try {
|
|
24187
|
-
content =
|
|
24219
|
+
content = import_node_fs7.default.readFileSync(entryPath, "utf8");
|
|
24188
24220
|
} catch {
|
|
24189
24221
|
continue;
|
|
24190
24222
|
}
|
|
@@ -24200,10 +24232,10 @@ function scanCommandDir(dir, source, seen, out, pluginName) {
|
|
|
24200
24232
|
}
|
|
24201
24233
|
}
|
|
24202
24234
|
function readInstalledPlugins(home) {
|
|
24203
|
-
const file =
|
|
24235
|
+
const file = import_node_path8.default.join(home, ".claude", "plugins", "installed_plugins.json");
|
|
24204
24236
|
let raw;
|
|
24205
24237
|
try {
|
|
24206
|
-
raw =
|
|
24238
|
+
raw = import_node_fs7.default.readFileSync(file, "utf8");
|
|
24207
24239
|
} catch {
|
|
24208
24240
|
return [];
|
|
24209
24241
|
}
|
|
@@ -24251,14 +24283,14 @@ var SkillsScanner = class {
|
|
|
24251
24283
|
});
|
|
24252
24284
|
}
|
|
24253
24285
|
const fsBlock = [];
|
|
24254
|
-
scanSkillDir(
|
|
24255
|
-
scanCommandDir(
|
|
24256
|
-
scanSkillDir(
|
|
24257
|
-
scanCommandDir(
|
|
24286
|
+
scanSkillDir(import_node_path8.default.join(this.home, ".claude", "skills"), "global", seen, fsBlock);
|
|
24287
|
+
scanCommandDir(import_node_path8.default.join(this.home, ".claude", "commands"), "global", seen, fsBlock);
|
|
24288
|
+
scanSkillDir(import_node_path8.default.join(args.cwd, ".claude", "skills"), "project", seen, fsBlock);
|
|
24289
|
+
scanCommandDir(import_node_path8.default.join(args.cwd, ".claude", "commands"), "project", seen, fsBlock);
|
|
24258
24290
|
const plugins = [...readInstalledPlugins(this.home), ...this.extraPluginRoots];
|
|
24259
24291
|
for (const { name, root } of plugins) {
|
|
24260
|
-
scanSkillDir(
|
|
24261
|
-
scanCommandDir(
|
|
24292
|
+
scanSkillDir(import_node_path8.default.join(root, "skills"), "plugin", seen, fsBlock, name);
|
|
24293
|
+
scanCommandDir(import_node_path8.default.join(root, "commands"), "plugin", seen, fsBlock, name);
|
|
24262
24294
|
}
|
|
24263
24295
|
fsBlock.sort((a, b2) => a.name < b2.name ? -1 : a.name > b2.name ? 1 : 0);
|
|
24264
24296
|
return [...builtinBlock, ...fsBlock];
|
|
@@ -24363,8 +24395,8 @@ var PersonaManager = class {
|
|
|
24363
24395
|
};
|
|
24364
24396
|
|
|
24365
24397
|
// src/persona/seed.ts
|
|
24366
|
-
var
|
|
24367
|
-
var
|
|
24398
|
+
var fs9 = __toESM(require("fs"), 1);
|
|
24399
|
+
var path11 = __toESM(require("path"), 1);
|
|
24368
24400
|
var import_node_url = require("url");
|
|
24369
24401
|
var import_meta = {};
|
|
24370
24402
|
var DEFAULT_PERSONAS = [
|
|
@@ -24400,18 +24432,18 @@ var DEFAULT_PERSONAS = [
|
|
|
24400
24432
|
function findDefaultsRoot() {
|
|
24401
24433
|
const candidates = [];
|
|
24402
24434
|
try {
|
|
24403
|
-
const here =
|
|
24404
|
-
candidates.push(
|
|
24405
|
-
candidates.push(
|
|
24435
|
+
const here = path11.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
|
|
24436
|
+
candidates.push(path11.resolve(here, "defaults"));
|
|
24437
|
+
candidates.push(path11.resolve(here, "persona-defaults"));
|
|
24406
24438
|
} catch {
|
|
24407
24439
|
}
|
|
24408
24440
|
if (process.argv[1]) {
|
|
24409
|
-
const argvDir =
|
|
24410
|
-
candidates.push(
|
|
24441
|
+
const argvDir = path11.dirname(process.argv[1]);
|
|
24442
|
+
candidates.push(path11.resolve(argvDir, "persona-defaults"));
|
|
24411
24443
|
}
|
|
24412
24444
|
for (const c of candidates) {
|
|
24413
24445
|
try {
|
|
24414
|
-
if (
|
|
24446
|
+
if (fs9.statSync(c).isDirectory()) return c;
|
|
24415
24447
|
} catch {
|
|
24416
24448
|
}
|
|
24417
24449
|
}
|
|
@@ -24424,8 +24456,8 @@ function seedDefaultPersonas(args) {
|
|
|
24424
24456
|
args.logger.info("persona.seed.skip", { personaId: entry.personaId, reason: "exists" });
|
|
24425
24457
|
continue;
|
|
24426
24458
|
}
|
|
24427
|
-
const bundleDir =
|
|
24428
|
-
if (!
|
|
24459
|
+
const bundleDir = path11.join(args.defaultsRoot, entry.personaId);
|
|
24460
|
+
if (!fs9.existsSync(bundleDir)) {
|
|
24429
24461
|
args.logger.warn("persona.seed.skip", {
|
|
24430
24462
|
personaId: entry.personaId,
|
|
24431
24463
|
reason: "bundle-missing",
|
|
@@ -24433,8 +24465,8 @@ function seedDefaultPersonas(args) {
|
|
|
24433
24465
|
});
|
|
24434
24466
|
continue;
|
|
24435
24467
|
}
|
|
24436
|
-
const claudeMdPath =
|
|
24437
|
-
if (!
|
|
24468
|
+
const claudeMdPath = path11.join(bundleDir, "CLAUDE.md");
|
|
24469
|
+
if (!fs9.existsSync(claudeMdPath)) {
|
|
24438
24470
|
args.logger.warn("persona.seed.skip", {
|
|
24439
24471
|
personaId: entry.personaId,
|
|
24440
24472
|
reason: "no-CLAUDE.md",
|
|
@@ -24442,7 +24474,7 @@ function seedDefaultPersonas(args) {
|
|
|
24442
24474
|
});
|
|
24443
24475
|
continue;
|
|
24444
24476
|
}
|
|
24445
|
-
const personality =
|
|
24477
|
+
const personality = fs9.readFileSync(claudeMdPath, "utf8");
|
|
24446
24478
|
const now = Date.now();
|
|
24447
24479
|
const persona = {
|
|
24448
24480
|
personaId: entry.personaId,
|
|
@@ -24459,14 +24491,14 @@ function seedDefaultPersonas(args) {
|
|
|
24459
24491
|
}
|
|
24460
24492
|
}
|
|
24461
24493
|
function copyBundleExtras(srcDir, dstDir) {
|
|
24462
|
-
for (const entry of
|
|
24494
|
+
for (const entry of fs9.readdirSync(srcDir, { withFileTypes: true })) {
|
|
24463
24495
|
if (entry.name === "CLAUDE.md" || entry.name === ".clawd") continue;
|
|
24464
|
-
const srcPath =
|
|
24465
|
-
const dstPath =
|
|
24496
|
+
const srcPath = path11.join(srcDir, entry.name);
|
|
24497
|
+
const dstPath = path11.join(dstDir, entry.name);
|
|
24466
24498
|
if (entry.isDirectory()) {
|
|
24467
|
-
|
|
24499
|
+
fs9.cpSync(srcPath, dstPath, { recursive: true, dereference: true });
|
|
24468
24500
|
} else if (entry.isFile()) {
|
|
24469
|
-
|
|
24501
|
+
fs9.copyFileSync(srcPath, dstPath);
|
|
24470
24502
|
}
|
|
24471
24503
|
}
|
|
24472
24504
|
}
|
|
@@ -24475,9 +24507,9 @@ function copyBundleExtras(srcDir, dstDir) {
|
|
|
24475
24507
|
init_claude();
|
|
24476
24508
|
|
|
24477
24509
|
// src/tools/claude-tui.ts
|
|
24478
|
-
var
|
|
24510
|
+
var import_node_fs10 = __toESM(require("fs"), 1);
|
|
24479
24511
|
var import_node_os5 = __toESM(require("os"), 1);
|
|
24480
|
-
var
|
|
24512
|
+
var import_node_path11 = __toESM(require("path"), 1);
|
|
24481
24513
|
var import_headless = __toESM(require_xterm_headless(), 1);
|
|
24482
24514
|
|
|
24483
24515
|
// ../node_modules/.pnpm/@xterm+addon-serialize@0.14.0/node_modules/@xterm/addon-serialize/lib/addon-serialize.mjs
|
|
@@ -25197,6 +25229,11 @@ var ClaudeTuiAdapter = class extends ClaudeAdapter {
|
|
|
25197
25229
|
cwd: ctx.cwd,
|
|
25198
25230
|
toolSessionId: ctx.toolSessionId
|
|
25199
25231
|
});
|
|
25232
|
+
probeEvent("pty.spawn", {
|
|
25233
|
+
tsid: ctx.toolSessionId,
|
|
25234
|
+
isResume: jsonlExistsForCtx(ctx),
|
|
25235
|
+
cwd: ctx.cwd
|
|
25236
|
+
});
|
|
25200
25237
|
const pty = spawnPty({
|
|
25201
25238
|
command: cmd,
|
|
25202
25239
|
args,
|
|
@@ -25238,8 +25275,12 @@ var ClaudeTuiAdapter = class extends ClaudeAdapter {
|
|
|
25238
25275
|
this.tuiOpts.onPtyData(ctx.toolSessionId, data.toString("base64"));
|
|
25239
25276
|
}
|
|
25240
25277
|
void detector.writeBytes(data.toString("utf8"));
|
|
25278
|
+
if (ctx.toolSessionId) {
|
|
25279
|
+
probePtyDataThrottled(ctx.toolSessionId, data.length, data);
|
|
25280
|
+
}
|
|
25241
25281
|
});
|
|
25242
25282
|
ptyChild.on("exit", () => {
|
|
25283
|
+
probeEvent("pty.exit", { tsid: ctx.toolSessionId });
|
|
25243
25284
|
if (ctx.toolSessionId && this.tuiOpts.onPtyUnregister) {
|
|
25244
25285
|
this.tuiOpts.onPtyUnregister(ctx.toolSessionId);
|
|
25245
25286
|
}
|
|
@@ -25312,9 +25353,9 @@ function buildTuiSpawnArgs(ctx, isResume = false) {
|
|
|
25312
25353
|
function jsonlExistsForCtx(ctx) {
|
|
25313
25354
|
if (!ctx.toolSessionId) return false;
|
|
25314
25355
|
const home = import_node_os5.default.homedir();
|
|
25315
|
-
const file =
|
|
25356
|
+
const file = import_node_path11.default.join(home, ".claude", "projects", cwdToHashDir(ctx.cwd), `${ctx.toolSessionId}.jsonl`);
|
|
25316
25357
|
try {
|
|
25317
|
-
return
|
|
25358
|
+
return import_node_fs10.default.statSync(file).isFile();
|
|
25318
25359
|
} catch {
|
|
25319
25360
|
return false;
|
|
25320
25361
|
}
|
|
@@ -25324,23 +25365,23 @@ function jsonlExistsForCtx(ctx) {
|
|
|
25324
25365
|
init_claude_history();
|
|
25325
25366
|
|
|
25326
25367
|
// src/workspace/browser.ts
|
|
25327
|
-
var
|
|
25368
|
+
var import_node_fs11 = __toESM(require("fs"), 1);
|
|
25328
25369
|
var import_node_os6 = __toESM(require("os"), 1);
|
|
25329
|
-
var
|
|
25370
|
+
var import_node_path12 = __toESM(require("path"), 1);
|
|
25330
25371
|
init_protocol();
|
|
25331
25372
|
var MAX_FILE_BYTES = 2 * 1024 * 1024;
|
|
25332
25373
|
function resolveInsideCwd(cwd, subpath) {
|
|
25333
|
-
const absCwd =
|
|
25334
|
-
const joined =
|
|
25335
|
-
const rel =
|
|
25336
|
-
if (rel.startsWith("..") ||
|
|
25374
|
+
const absCwd = import_node_path12.default.resolve(cwd);
|
|
25375
|
+
const joined = import_node_path12.default.resolve(absCwd, subpath ?? ".");
|
|
25376
|
+
const rel = import_node_path12.default.relative(absCwd, joined);
|
|
25377
|
+
if (rel.startsWith("..") || import_node_path12.default.isAbsolute(rel)) {
|
|
25337
25378
|
throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
|
|
25338
25379
|
}
|
|
25339
25380
|
return joined;
|
|
25340
25381
|
}
|
|
25341
25382
|
function ensureCwd(cwd) {
|
|
25342
25383
|
try {
|
|
25343
|
-
const stat =
|
|
25384
|
+
const stat = import_node_fs11.default.statSync(cwd);
|
|
25344
25385
|
if (!stat.isDirectory()) {
|
|
25345
25386
|
throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${cwd}`);
|
|
25346
25387
|
}
|
|
@@ -25354,7 +25395,7 @@ var WorkspaceBrowser = class {
|
|
|
25354
25395
|
const cwd = args.cwd && args.cwd.length > 0 ? args.cwd : import_node_os6.default.homedir();
|
|
25355
25396
|
ensureCwd(cwd);
|
|
25356
25397
|
const full = resolveInsideCwd(cwd, args.path);
|
|
25357
|
-
const dirents =
|
|
25398
|
+
const dirents = import_node_fs11.default.readdirSync(full, { withFileTypes: true });
|
|
25358
25399
|
const entries = [];
|
|
25359
25400
|
for (const d of dirents) {
|
|
25360
25401
|
if (!args.showHidden && d.name.startsWith(".")) continue;
|
|
@@ -25364,7 +25405,7 @@ var WorkspaceBrowser = class {
|
|
|
25364
25405
|
mtime: ""
|
|
25365
25406
|
};
|
|
25366
25407
|
try {
|
|
25367
|
-
const st =
|
|
25408
|
+
const st = import_node_fs11.default.statSync(import_node_path12.default.join(full, d.name));
|
|
25368
25409
|
entry.mtime = new Date(st.mtimeMs).toISOString();
|
|
25369
25410
|
if (d.isFile()) entry.size = st.size;
|
|
25370
25411
|
} catch {
|
|
@@ -25380,14 +25421,14 @@ var WorkspaceBrowser = class {
|
|
|
25380
25421
|
read(args) {
|
|
25381
25422
|
ensureCwd(args.cwd);
|
|
25382
25423
|
const full = resolveInsideCwd(args.cwd, args.path);
|
|
25383
|
-
const st =
|
|
25424
|
+
const st = import_node_fs11.default.statSync(full);
|
|
25384
25425
|
if (!st.isFile()) {
|
|
25385
25426
|
throw new ClawdError(ERROR_CODES.INVALID_PATH, `not a file: ${args.path}`);
|
|
25386
25427
|
}
|
|
25387
25428
|
if (st.size > MAX_FILE_BYTES) {
|
|
25388
25429
|
throw new ClawdError(ERROR_CODES.FILE_TOO_LARGE, `file > ${MAX_FILE_BYTES} bytes`);
|
|
25389
25430
|
}
|
|
25390
|
-
const buf =
|
|
25431
|
+
const buf = import_node_fs11.default.readFileSync(full);
|
|
25391
25432
|
const isBinary = buf.includes(0);
|
|
25392
25433
|
if (isBinary) {
|
|
25393
25434
|
return {
|
|
@@ -25409,20 +25450,20 @@ var WorkspaceBrowser = class {
|
|
|
25409
25450
|
};
|
|
25410
25451
|
|
|
25411
25452
|
// src/skills/agents-scanner.ts
|
|
25412
|
-
var
|
|
25453
|
+
var import_node_fs12 = __toESM(require("fs"), 1);
|
|
25413
25454
|
var import_node_os7 = __toESM(require("os"), 1);
|
|
25414
|
-
var
|
|
25455
|
+
var import_node_path13 = __toESM(require("path"), 1);
|
|
25415
25456
|
var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
|
|
25416
25457
|
function isDirLikeSync2(p2) {
|
|
25417
25458
|
try {
|
|
25418
|
-
return
|
|
25459
|
+
return import_node_fs12.default.statSync(p2).isDirectory();
|
|
25419
25460
|
} catch {
|
|
25420
25461
|
return false;
|
|
25421
25462
|
}
|
|
25422
25463
|
}
|
|
25423
25464
|
function fileExistsSync(p2) {
|
|
25424
25465
|
try {
|
|
25425
|
-
return
|
|
25466
|
+
return import_node_fs12.default.statSync(p2).isFile();
|
|
25426
25467
|
} catch {
|
|
25427
25468
|
return false;
|
|
25428
25469
|
}
|
|
@@ -25430,7 +25471,7 @@ function fileExistsSync(p2) {
|
|
|
25430
25471
|
function parseAgentFile(filePath) {
|
|
25431
25472
|
let content;
|
|
25432
25473
|
try {
|
|
25433
|
-
content =
|
|
25474
|
+
content = import_node_fs12.default.readFileSync(filePath, "utf8");
|
|
25434
25475
|
} catch {
|
|
25435
25476
|
return {};
|
|
25436
25477
|
}
|
|
@@ -25443,16 +25484,16 @@ function parseAgentFile(filePath) {
|
|
|
25443
25484
|
function scanAgentsDir(dir, source, seen, out) {
|
|
25444
25485
|
let entries;
|
|
25445
25486
|
try {
|
|
25446
|
-
entries =
|
|
25487
|
+
entries = import_node_fs12.default.readdirSync(dir, { withFileTypes: true });
|
|
25447
25488
|
} catch {
|
|
25448
25489
|
return;
|
|
25449
25490
|
}
|
|
25450
25491
|
for (const ent of entries) {
|
|
25451
25492
|
if (!ent.name.endsWith(".md")) continue;
|
|
25452
|
-
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(
|
|
25493
|
+
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path13.default.join(dir, ent.name)))) {
|
|
25453
25494
|
continue;
|
|
25454
25495
|
}
|
|
25455
|
-
const filePath =
|
|
25496
|
+
const filePath = import_node_path13.default.join(dir, ent.name);
|
|
25456
25497
|
const baseName = ent.name.replace(/\.md$/, "");
|
|
25457
25498
|
if (seen.has(baseName)) continue;
|
|
25458
25499
|
seen.add(baseName);
|
|
@@ -25470,12 +25511,12 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
25470
25511
|
function walk(dir, namespaces) {
|
|
25471
25512
|
let entries;
|
|
25472
25513
|
try {
|
|
25473
|
-
entries =
|
|
25514
|
+
entries = import_node_fs12.default.readdirSync(dir, { withFileTypes: true });
|
|
25474
25515
|
} catch {
|
|
25475
25516
|
return;
|
|
25476
25517
|
}
|
|
25477
25518
|
for (const ent of entries) {
|
|
25478
|
-
const childPath =
|
|
25519
|
+
const childPath = import_node_path13.default.join(dir, ent.name);
|
|
25479
25520
|
if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
|
|
25480
25521
|
walk(childPath, [...namespaces, ent.name]);
|
|
25481
25522
|
continue;
|
|
@@ -25500,13 +25541,13 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
25500
25541
|
walk(root, []);
|
|
25501
25542
|
}
|
|
25502
25543
|
function readInstalledPlugins2(home) {
|
|
25503
|
-
const pluginsDir =
|
|
25504
|
-
const v2 =
|
|
25505
|
-
const v1 =
|
|
25544
|
+
const pluginsDir = import_node_path13.default.join(home, ".claude", "plugins");
|
|
25545
|
+
const v2 = import_node_path13.default.join(pluginsDir, "installed_plugins_v2.json");
|
|
25546
|
+
const v1 = import_node_path13.default.join(pluginsDir, "installed_plugins.json");
|
|
25506
25547
|
let raw = null;
|
|
25507
25548
|
for (const candidate of [v2, v1]) {
|
|
25508
25549
|
try {
|
|
25509
|
-
raw =
|
|
25550
|
+
raw = import_node_fs12.default.readFileSync(candidate, "utf8");
|
|
25510
25551
|
break;
|
|
25511
25552
|
} catch {
|
|
25512
25553
|
}
|
|
@@ -25531,19 +25572,19 @@ function readInstalledPlugins2(home) {
|
|
|
25531
25572
|
return out;
|
|
25532
25573
|
}
|
|
25533
25574
|
function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
|
|
25534
|
-
let cur =
|
|
25535
|
-
const fsRoot =
|
|
25575
|
+
let cur = import_node_path13.default.resolve(startCwd);
|
|
25576
|
+
const fsRoot = import_node_path13.default.parse(cur).root;
|
|
25536
25577
|
while (true) {
|
|
25537
|
-
scanAgentsDir(
|
|
25578
|
+
scanAgentsDir(import_node_path13.default.join(cur, ".claude", "agents"), "project", seen, out);
|
|
25538
25579
|
let hasGit = false;
|
|
25539
25580
|
try {
|
|
25540
|
-
hasGit =
|
|
25581
|
+
hasGit = import_node_fs12.default.existsSync(import_node_path13.default.join(cur, ".git"));
|
|
25541
25582
|
} catch {
|
|
25542
25583
|
}
|
|
25543
25584
|
if (hasGit) return;
|
|
25544
25585
|
if (cur === home) return;
|
|
25545
25586
|
if (cur === fsRoot) return;
|
|
25546
|
-
const parent =
|
|
25587
|
+
const parent = import_node_path13.default.dirname(cur);
|
|
25547
25588
|
if (parent === cur) return;
|
|
25548
25589
|
cur = parent;
|
|
25549
25590
|
}
|
|
@@ -25578,7 +25619,7 @@ var AgentsScanner = class {
|
|
|
25578
25619
|
}
|
|
25579
25620
|
const fsBlock = [];
|
|
25580
25621
|
scanAgentsDir(
|
|
25581
|
-
|
|
25622
|
+
import_node_path13.default.join(this.home, ".claude", "agents"),
|
|
25582
25623
|
"global",
|
|
25583
25624
|
seen,
|
|
25584
25625
|
fsBlock
|
|
@@ -25592,7 +25633,7 @@ var AgentsScanner = class {
|
|
|
25592
25633
|
...this.extraPluginRoots
|
|
25593
25634
|
];
|
|
25594
25635
|
for (const { name, root } of plugins) {
|
|
25595
|
-
const agentsRoot =
|
|
25636
|
+
const agentsRoot = import_node_path13.default.join(root, "agents");
|
|
25596
25637
|
scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
|
|
25597
25638
|
}
|
|
25598
25639
|
return [...builtinBlock, ...fsBlock];
|
|
@@ -25600,15 +25641,15 @@ var AgentsScanner = class {
|
|
|
25600
25641
|
};
|
|
25601
25642
|
|
|
25602
25643
|
// src/observer/session-observer.ts
|
|
25603
|
-
var
|
|
25644
|
+
var import_node_fs14 = __toESM(require("fs"), 1);
|
|
25604
25645
|
var import_node_os9 = __toESM(require("os"), 1);
|
|
25605
|
-
var
|
|
25646
|
+
var import_node_path15 = __toESM(require("path"), 1);
|
|
25606
25647
|
init_claude_history();
|
|
25607
25648
|
|
|
25608
25649
|
// src/observer/subagent-meta-observer.ts
|
|
25609
|
-
var
|
|
25650
|
+
var import_node_fs13 = __toESM(require("fs"), 1);
|
|
25610
25651
|
var import_node_os8 = __toESM(require("os"), 1);
|
|
25611
|
-
var
|
|
25652
|
+
var import_node_path14 = __toESM(require("path"), 1);
|
|
25612
25653
|
init_claude_history();
|
|
25613
25654
|
var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
|
|
25614
25655
|
var SubagentMetaObserver = class {
|
|
@@ -25621,7 +25662,7 @@ var SubagentMetaObserver = class {
|
|
|
25621
25662
|
watches = /* @__PURE__ */ new Map();
|
|
25622
25663
|
// public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
|
|
25623
25664
|
resolveSubagentDir(cwd, toolSessionId) {
|
|
25624
|
-
return
|
|
25665
|
+
return import_node_path14.default.join(
|
|
25625
25666
|
this.home,
|
|
25626
25667
|
".claude",
|
|
25627
25668
|
"projects",
|
|
@@ -25651,7 +25692,7 @@ var SubagentMetaObserver = class {
|
|
|
25651
25692
|
attachWatcher(w2) {
|
|
25652
25693
|
if (w2.watcher) return;
|
|
25653
25694
|
try {
|
|
25654
|
-
w2.watcher =
|
|
25695
|
+
w2.watcher = import_node_fs13.default.watch(w2.dirPath, { persistent: false }, (_evt, name) => {
|
|
25655
25696
|
if (!name) return;
|
|
25656
25697
|
const m2 = META_RE.exec(String(name));
|
|
25657
25698
|
if (!m2) return;
|
|
@@ -25663,7 +25704,7 @@ var SubagentMetaObserver = class {
|
|
|
25663
25704
|
scan(w2) {
|
|
25664
25705
|
let entries;
|
|
25665
25706
|
try {
|
|
25666
|
-
entries =
|
|
25707
|
+
entries = import_node_fs13.default.readdirSync(w2.dirPath);
|
|
25667
25708
|
} catch {
|
|
25668
25709
|
return;
|
|
25669
25710
|
}
|
|
@@ -25677,10 +25718,10 @@ var SubagentMetaObserver = class {
|
|
|
25677
25718
|
if (!m2) return;
|
|
25678
25719
|
const agentId = m2[1];
|
|
25679
25720
|
if (w2.emitted.has(agentId)) return;
|
|
25680
|
-
const file =
|
|
25721
|
+
const file = import_node_path14.default.join(w2.dirPath, name);
|
|
25681
25722
|
let raw;
|
|
25682
25723
|
try {
|
|
25683
|
-
raw =
|
|
25724
|
+
raw = import_node_fs13.default.readFileSync(file, "utf8");
|
|
25684
25725
|
} catch {
|
|
25685
25726
|
return;
|
|
25686
25727
|
}
|
|
@@ -25737,14 +25778,14 @@ var SessionObserver = class {
|
|
|
25737
25778
|
metaObserver;
|
|
25738
25779
|
resolveJsonlPath(cwd, toolSessionId, override) {
|
|
25739
25780
|
if (override) return override;
|
|
25740
|
-
return
|
|
25781
|
+
return import_node_path15.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
|
|
25741
25782
|
}
|
|
25742
25783
|
start(args) {
|
|
25743
25784
|
this.stop(args.sessionId);
|
|
25744
25785
|
const filePath = this.resolveJsonlPath(args.cwd, args.toolSessionId, args.jsonlPath);
|
|
25745
25786
|
let size = 0;
|
|
25746
25787
|
try {
|
|
25747
|
-
size =
|
|
25788
|
+
size = import_node_fs14.default.statSync(filePath).size;
|
|
25748
25789
|
} catch {
|
|
25749
25790
|
}
|
|
25750
25791
|
const w2 = {
|
|
@@ -25757,10 +25798,10 @@ var SessionObserver = class {
|
|
|
25757
25798
|
adapter: args.adapter
|
|
25758
25799
|
};
|
|
25759
25800
|
try {
|
|
25760
|
-
|
|
25801
|
+
import_node_fs14.default.mkdirSync(import_node_path15.default.dirname(filePath), { recursive: true });
|
|
25761
25802
|
} catch {
|
|
25762
25803
|
}
|
|
25763
|
-
w2.watcher =
|
|
25804
|
+
w2.watcher = import_node_fs14.default.watch(import_node_path15.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
|
|
25764
25805
|
if (!changedName || !filePath.endsWith(changedName)) return;
|
|
25765
25806
|
this.poll(w2);
|
|
25766
25807
|
});
|
|
@@ -25783,7 +25824,7 @@ var SessionObserver = class {
|
|
|
25783
25824
|
// 异常静默吞,不阻塞 watcher 启动
|
|
25784
25825
|
hydrateMetaTail(w2, maxLines = 200) {
|
|
25785
25826
|
try {
|
|
25786
|
-
const raw =
|
|
25827
|
+
const raw = import_node_fs14.default.readFileSync(w2.filePath, "utf8");
|
|
25787
25828
|
if (!raw) return;
|
|
25788
25829
|
const allLines = raw.split("\n").filter((l) => l.trim().length > 0);
|
|
25789
25830
|
if (allLines.length === 0) return;
|
|
@@ -25807,7 +25848,7 @@ var SessionObserver = class {
|
|
|
25807
25848
|
poll(w2) {
|
|
25808
25849
|
let size = 0;
|
|
25809
25850
|
try {
|
|
25810
|
-
size =
|
|
25851
|
+
size = import_node_fs14.default.statSync(w2.filePath).size;
|
|
25811
25852
|
} catch {
|
|
25812
25853
|
return;
|
|
25813
25854
|
}
|
|
@@ -25816,11 +25857,11 @@ var SessionObserver = class {
|
|
|
25816
25857
|
w2.buf = "";
|
|
25817
25858
|
}
|
|
25818
25859
|
if (size === w2.lastSize) return;
|
|
25819
|
-
const fd =
|
|
25860
|
+
const fd = import_node_fs14.default.openSync(w2.filePath, "r");
|
|
25820
25861
|
try {
|
|
25821
25862
|
const len = size - w2.lastSize;
|
|
25822
25863
|
const buf = Buffer.alloc(len);
|
|
25823
|
-
|
|
25864
|
+
import_node_fs14.default.readSync(fd, buf, 0, len, w2.lastSize);
|
|
25824
25865
|
w2.lastSize = size;
|
|
25825
25866
|
w2.buf += buf.toString("utf8");
|
|
25826
25867
|
let newlineIndex;
|
|
@@ -25834,7 +25875,7 @@ var SessionObserver = class {
|
|
|
25834
25875
|
}
|
|
25835
25876
|
}
|
|
25836
25877
|
} finally {
|
|
25837
|
-
|
|
25878
|
+
import_node_fs14.default.closeSync(fd);
|
|
25838
25879
|
}
|
|
25839
25880
|
}
|
|
25840
25881
|
// 解析 JSONL 单行:仅当是主链 user 文本行(非 sidechain / 非 sub-agent / message.role='user'
|
|
@@ -26494,14 +26535,14 @@ function authenticate(token, deps) {
|
|
|
26494
26535
|
}
|
|
26495
26536
|
|
|
26496
26537
|
// src/permission/capability-store.ts
|
|
26497
|
-
var
|
|
26498
|
-
var
|
|
26538
|
+
var fs17 = __toESM(require("fs"), 1);
|
|
26539
|
+
var path20 = __toESM(require("path"), 1);
|
|
26499
26540
|
var CAPABILITIES_FILE_NAME = "capabilities.json";
|
|
26500
26541
|
var FILE_VERSION = 1;
|
|
26501
26542
|
var CapabilityStore = class {
|
|
26502
26543
|
constructor(dataDir) {
|
|
26503
26544
|
this.dataDir = dataDir;
|
|
26504
|
-
|
|
26545
|
+
fs17.mkdirSync(dataDir, { recursive: true });
|
|
26505
26546
|
this.cache = this.readFromDisk();
|
|
26506
26547
|
}
|
|
26507
26548
|
dataDir;
|
|
@@ -26525,13 +26566,13 @@ var CapabilityStore = class {
|
|
|
26525
26566
|
this.flush();
|
|
26526
26567
|
}
|
|
26527
26568
|
filePath() {
|
|
26528
|
-
return
|
|
26569
|
+
return path20.join(this.dataDir, CAPABILITIES_FILE_NAME);
|
|
26529
26570
|
}
|
|
26530
26571
|
readFromDisk() {
|
|
26531
26572
|
const file = this.filePath();
|
|
26532
26573
|
let raw;
|
|
26533
26574
|
try {
|
|
26534
|
-
raw =
|
|
26575
|
+
raw = fs17.readFileSync(file, "utf8");
|
|
26535
26576
|
} catch (err) {
|
|
26536
26577
|
if (err?.code === "ENOENT") return [];
|
|
26537
26578
|
return [];
|
|
@@ -26559,10 +26600,10 @@ var CapabilityStore = class {
|
|
|
26559
26600
|
}
|
|
26560
26601
|
atomicWrite(file, content) {
|
|
26561
26602
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
26562
|
-
|
|
26563
|
-
|
|
26603
|
+
fs17.writeFileSync(tmp, content, { mode: 384 });
|
|
26604
|
+
fs17.renameSync(tmp, file);
|
|
26564
26605
|
try {
|
|
26565
|
-
|
|
26606
|
+
fs17.chmodSync(file, 384);
|
|
26566
26607
|
} catch {
|
|
26567
26608
|
}
|
|
26568
26609
|
}
|
|
@@ -26655,14 +26696,14 @@ var CapabilityManager = class {
|
|
|
26655
26696
|
};
|
|
26656
26697
|
|
|
26657
26698
|
// src/permission/cleanup.ts
|
|
26658
|
-
var
|
|
26699
|
+
var fs18 = __toESM(require("fs"), 1);
|
|
26659
26700
|
function cleanupGuestSessionsForCapability(cap, factory) {
|
|
26660
26701
|
const removed = [];
|
|
26661
26702
|
for (const g2 of cap.grants) {
|
|
26662
26703
|
if (g2.resource.type !== "persona") continue;
|
|
26663
26704
|
const dir = factory.vmGuestRoot(g2.resource.id, cap.id);
|
|
26664
26705
|
try {
|
|
26665
|
-
|
|
26706
|
+
fs18.rmSync(dir, { recursive: true, force: true });
|
|
26666
26707
|
removed.push(dir);
|
|
26667
26708
|
} catch {
|
|
26668
26709
|
}
|
|
@@ -26671,13 +26712,13 @@ function cleanupGuestSessionsForCapability(cap, factory) {
|
|
|
26671
26712
|
}
|
|
26672
26713
|
|
|
26673
26714
|
// src/permission/personal-capability.ts
|
|
26674
|
-
var
|
|
26675
|
-
var
|
|
26715
|
+
var import_node_fs15 = __toESM(require("fs"), 1);
|
|
26716
|
+
var import_node_path16 = __toESM(require("path"), 1);
|
|
26676
26717
|
var import_node_crypto4 = __toESM(require("crypto"), 1);
|
|
26677
26718
|
var PERSONAL_CAP_FILE_NAME = "personal-capability.json";
|
|
26678
26719
|
var PERSONAL_CAP_DISPLAY_NAME = "personal";
|
|
26679
26720
|
function personalCapFilePath(dataDir) {
|
|
26680
|
-
return
|
|
26721
|
+
return import_node_path16.default.join(dataDir, PERSONAL_CAP_FILE_NAME);
|
|
26681
26722
|
}
|
|
26682
26723
|
function loadOrCreatePersonalCapability(opts) {
|
|
26683
26724
|
const file = personalCapFilePath(opts.dataDir);
|
|
@@ -26707,7 +26748,7 @@ function loadOrCreatePersonalCapability(opts) {
|
|
|
26707
26748
|
function readFile(file) {
|
|
26708
26749
|
let raw;
|
|
26709
26750
|
try {
|
|
26710
|
-
raw =
|
|
26751
|
+
raw = import_node_fs15.default.readFileSync(file, "utf8");
|
|
26711
26752
|
} catch (err) {
|
|
26712
26753
|
const code = err?.code;
|
|
26713
26754
|
if (code === "ENOENT") return null;
|
|
@@ -26728,10 +26769,10 @@ function readFile(file) {
|
|
|
26728
26769
|
return { token: obj.token, capability: capParsed.data };
|
|
26729
26770
|
}
|
|
26730
26771
|
function writeFile(file, content) {
|
|
26731
|
-
|
|
26732
|
-
|
|
26772
|
+
import_node_fs15.default.mkdirSync(import_node_path16.default.dirname(file), { recursive: true });
|
|
26773
|
+
import_node_fs15.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
|
|
26733
26774
|
try {
|
|
26734
|
-
|
|
26775
|
+
import_node_fs15.default.chmodSync(file, 384);
|
|
26735
26776
|
} catch {
|
|
26736
26777
|
}
|
|
26737
26778
|
}
|
|
@@ -26746,13 +26787,13 @@ function sha256Hex2(s) {
|
|
|
26746
26787
|
}
|
|
26747
26788
|
|
|
26748
26789
|
// src/inbox/inbox-store.ts
|
|
26749
|
-
var
|
|
26750
|
-
var
|
|
26790
|
+
var fs20 = __toESM(require("fs"), 1);
|
|
26791
|
+
var path22 = __toESM(require("path"), 1);
|
|
26751
26792
|
var INBOX_SUBDIR = "inbox";
|
|
26752
26793
|
var InboxStore = class {
|
|
26753
26794
|
constructor(dataDir) {
|
|
26754
26795
|
this.dataDir = dataDir;
|
|
26755
|
-
|
|
26796
|
+
fs20.mkdirSync(this.dirPath(), { recursive: true });
|
|
26756
26797
|
}
|
|
26757
26798
|
dataDir;
|
|
26758
26799
|
/**
|
|
@@ -26764,7 +26805,7 @@ var InboxStore = class {
|
|
|
26764
26805
|
const file = this.filePath(peerOwnerId);
|
|
26765
26806
|
let raw;
|
|
26766
26807
|
try {
|
|
26767
|
-
raw =
|
|
26808
|
+
raw = fs20.readFileSync(file, "utf8");
|
|
26768
26809
|
} catch (err) {
|
|
26769
26810
|
if (err?.code === "ENOENT") return [];
|
|
26770
26811
|
return [];
|
|
@@ -26780,7 +26821,7 @@ var InboxStore = class {
|
|
|
26780
26821
|
const dir = this.dirPath();
|
|
26781
26822
|
let entries;
|
|
26782
26823
|
try {
|
|
26783
|
-
entries =
|
|
26824
|
+
entries = fs20.readdirSync(dir);
|
|
26784
26825
|
} catch (err) {
|
|
26785
26826
|
if (err?.code === "ENOENT") return [];
|
|
26786
26827
|
return [];
|
|
@@ -26796,9 +26837,9 @@ var InboxStore = class {
|
|
|
26796
26837
|
if (existing.some((m2) => m2.id === message.id)) return;
|
|
26797
26838
|
const file = this.filePath(message.peerOwnerId);
|
|
26798
26839
|
const line = JSON.stringify(message) + "\n";
|
|
26799
|
-
|
|
26840
|
+
fs20.appendFileSync(file, line, { mode: 384 });
|
|
26800
26841
|
try {
|
|
26801
|
-
|
|
26842
|
+
fs20.chmodSync(file, 384);
|
|
26802
26843
|
} catch {
|
|
26803
26844
|
}
|
|
26804
26845
|
}
|
|
@@ -26828,7 +26869,7 @@ var InboxStore = class {
|
|
|
26828
26869
|
removeByPeerOwnerId(peerOwnerId) {
|
|
26829
26870
|
const file = this.filePath(peerOwnerId);
|
|
26830
26871
|
try {
|
|
26831
|
-
|
|
26872
|
+
fs20.unlinkSync(file);
|
|
26832
26873
|
} catch (err) {
|
|
26833
26874
|
if (err?.code === "ENOENT") return;
|
|
26834
26875
|
}
|
|
@@ -26837,18 +26878,18 @@ var InboxStore = class {
|
|
|
26837
26878
|
const file = this.filePath(peerOwnerId);
|
|
26838
26879
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
26839
26880
|
const content = messages.map((m2) => JSON.stringify(m2)).join("\n") + (messages.length > 0 ? "\n" : "");
|
|
26840
|
-
|
|
26841
|
-
|
|
26881
|
+
fs20.writeFileSync(tmp, content, { mode: 384 });
|
|
26882
|
+
fs20.renameSync(tmp, file);
|
|
26842
26883
|
try {
|
|
26843
|
-
|
|
26884
|
+
fs20.chmodSync(file, 384);
|
|
26844
26885
|
} catch {
|
|
26845
26886
|
}
|
|
26846
26887
|
}
|
|
26847
26888
|
dirPath() {
|
|
26848
|
-
return
|
|
26889
|
+
return path22.join(this.dataDir, INBOX_SUBDIR);
|
|
26849
26890
|
}
|
|
26850
26891
|
filePath(peerOwnerId) {
|
|
26851
|
-
return
|
|
26892
|
+
return path22.join(this.dirPath(), `${peerOwnerId}.jsonl`);
|
|
26852
26893
|
}
|
|
26853
26894
|
};
|
|
26854
26895
|
function parseAllLines(raw) {
|
|
@@ -26935,8 +26976,8 @@ var InboxManager = class {
|
|
|
26935
26976
|
};
|
|
26936
26977
|
|
|
26937
26978
|
// src/state/received-capability-store.ts
|
|
26938
|
-
var
|
|
26939
|
-
var
|
|
26979
|
+
var fs21 = __toESM(require("fs"), 1);
|
|
26980
|
+
var path23 = __toESM(require("path"), 1);
|
|
26940
26981
|
var FILE_NAME = "received-capabilities.json";
|
|
26941
26982
|
var ReceivedCapabilityStore = class {
|
|
26942
26983
|
constructor(dataDir) {
|
|
@@ -26946,10 +26987,10 @@ var ReceivedCapabilityStore = class {
|
|
|
26946
26987
|
caps = /* @__PURE__ */ new Map();
|
|
26947
26988
|
load() {
|
|
26948
26989
|
this.caps.clear();
|
|
26949
|
-
const file =
|
|
26990
|
+
const file = path23.join(this.dataDir, FILE_NAME);
|
|
26950
26991
|
let raw;
|
|
26951
26992
|
try {
|
|
26952
|
-
raw =
|
|
26993
|
+
raw = fs21.readFileSync(file, "utf8");
|
|
26953
26994
|
} catch (err) {
|
|
26954
26995
|
if (err?.code !== "ENOENT") this.renameBak(file);
|
|
26955
26996
|
return;
|
|
@@ -26986,20 +27027,20 @@ var ReceivedCapabilityStore = class {
|
|
|
26986
27027
|
this.flush();
|
|
26987
27028
|
}
|
|
26988
27029
|
flush() {
|
|
26989
|
-
const file =
|
|
27030
|
+
const file = path23.join(this.dataDir, FILE_NAME);
|
|
26990
27031
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
26991
27032
|
const content = JSON.stringify(
|
|
26992
27033
|
{ receivedCaps: Array.from(this.caps.values()) },
|
|
26993
27034
|
null,
|
|
26994
27035
|
2
|
|
26995
27036
|
);
|
|
26996
|
-
|
|
26997
|
-
|
|
26998
|
-
|
|
27037
|
+
fs21.mkdirSync(this.dataDir, { recursive: true });
|
|
27038
|
+
fs21.writeFileSync(tmp, content, { mode: 384 });
|
|
27039
|
+
fs21.renameSync(tmp, file);
|
|
26999
27040
|
}
|
|
27000
27041
|
renameBak(file) {
|
|
27001
27042
|
try {
|
|
27002
|
-
|
|
27043
|
+
fs21.renameSync(file, `${file}.bak`);
|
|
27003
27044
|
} catch {
|
|
27004
27045
|
}
|
|
27005
27046
|
}
|
|
@@ -27097,61 +27138,61 @@ async function connectRemote(args) {
|
|
|
27097
27138
|
}
|
|
27098
27139
|
|
|
27099
27140
|
// src/migrations/2026-05-20-flatten-sessions.ts
|
|
27100
|
-
var
|
|
27101
|
-
var
|
|
27141
|
+
var fs22 = __toESM(require("fs"), 1);
|
|
27142
|
+
var path24 = __toESM(require("path"), 1);
|
|
27102
27143
|
var MIGRATION_FLAG_NAME = ".migration.v1.done";
|
|
27103
27144
|
function migrateFlattenSessions(opts) {
|
|
27104
27145
|
const dataDir = opts.dataDir;
|
|
27105
27146
|
const now = opts.now ?? Date.now;
|
|
27106
|
-
const sessionsDir =
|
|
27107
|
-
const flagPath =
|
|
27147
|
+
const sessionsDir = path24.join(dataDir, "sessions");
|
|
27148
|
+
const flagPath = path24.join(sessionsDir, MIGRATION_FLAG_NAME);
|
|
27108
27149
|
if (existsSync3(flagPath)) {
|
|
27109
27150
|
return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
|
|
27110
27151
|
}
|
|
27111
27152
|
let movedBare = 0;
|
|
27112
27153
|
let movedVmOwner = 0;
|
|
27113
27154
|
let archivedListener = 0;
|
|
27114
|
-
const defaultDir =
|
|
27155
|
+
const defaultDir = path24.join(sessionsDir, "default");
|
|
27115
27156
|
if (existsSync3(defaultDir)) {
|
|
27116
27157
|
for (const entry of readdirSafe(defaultDir)) {
|
|
27117
27158
|
if (!entry.endsWith(".json")) continue;
|
|
27118
|
-
const src =
|
|
27119
|
-
const dst =
|
|
27120
|
-
|
|
27159
|
+
const src = path24.join(defaultDir, entry);
|
|
27160
|
+
const dst = path24.join(sessionsDir, entry);
|
|
27161
|
+
fs22.renameSync(src, dst);
|
|
27121
27162
|
movedBare += 1;
|
|
27122
27163
|
}
|
|
27123
27164
|
rmdirIfEmpty(defaultDir);
|
|
27124
27165
|
}
|
|
27125
27166
|
for (const pid of readdirSafe(sessionsDir)) {
|
|
27126
|
-
const personaDir =
|
|
27167
|
+
const personaDir = path24.join(sessionsDir, pid);
|
|
27127
27168
|
if (!isDir(personaDir)) continue;
|
|
27128
27169
|
if (pid === "default") continue;
|
|
27129
|
-
const ownerSrc =
|
|
27170
|
+
const ownerSrc = path24.join(personaDir, "owner");
|
|
27130
27171
|
if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
|
|
27131
|
-
const ownerDst =
|
|
27132
|
-
|
|
27172
|
+
const ownerDst = path24.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
|
|
27173
|
+
fs22.mkdirSync(ownerDst, { recursive: true });
|
|
27133
27174
|
for (const file of readdirSafe(ownerSrc)) {
|
|
27134
27175
|
if (!file.endsWith(".json")) continue;
|
|
27135
|
-
|
|
27176
|
+
fs22.renameSync(path24.join(ownerSrc, file), path24.join(ownerDst, file));
|
|
27136
27177
|
movedVmOwner += 1;
|
|
27137
27178
|
}
|
|
27138
27179
|
rmdirIfEmpty(ownerSrc);
|
|
27139
27180
|
}
|
|
27140
|
-
const listenerSrc =
|
|
27181
|
+
const listenerSrc = path24.join(personaDir, "listener");
|
|
27141
27182
|
if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
|
|
27142
|
-
const archiveDst =
|
|
27143
|
-
|
|
27183
|
+
const archiveDst = path24.join(dataDir, ".legacy", `listener-${pid}`);
|
|
27184
|
+
fs22.mkdirSync(archiveDst, { recursive: true });
|
|
27144
27185
|
for (const file of readdirSafe(listenerSrc)) {
|
|
27145
27186
|
if (!file.endsWith(".json")) continue;
|
|
27146
|
-
|
|
27187
|
+
fs22.renameSync(path24.join(listenerSrc, file), path24.join(archiveDst, file));
|
|
27147
27188
|
archivedListener += 1;
|
|
27148
27189
|
}
|
|
27149
27190
|
rmdirIfEmpty(listenerSrc);
|
|
27150
27191
|
}
|
|
27151
27192
|
rmdirIfEmpty(personaDir);
|
|
27152
27193
|
}
|
|
27153
|
-
|
|
27154
|
-
|
|
27194
|
+
fs22.mkdirSync(sessionsDir, { recursive: true });
|
|
27195
|
+
fs22.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
|
|
27155
27196
|
return {
|
|
27156
27197
|
skipped: false,
|
|
27157
27198
|
flagWritten: true,
|
|
@@ -27162,7 +27203,7 @@ function migrateFlattenSessions(opts) {
|
|
|
27162
27203
|
}
|
|
27163
27204
|
function existsSync3(p2) {
|
|
27164
27205
|
try {
|
|
27165
|
-
|
|
27206
|
+
fs22.statSync(p2);
|
|
27166
27207
|
return true;
|
|
27167
27208
|
} catch {
|
|
27168
27209
|
return false;
|
|
@@ -27170,31 +27211,31 @@ function existsSync3(p2) {
|
|
|
27170
27211
|
}
|
|
27171
27212
|
function isDir(p2) {
|
|
27172
27213
|
try {
|
|
27173
|
-
return
|
|
27214
|
+
return fs22.statSync(p2).isDirectory();
|
|
27174
27215
|
} catch {
|
|
27175
27216
|
return false;
|
|
27176
27217
|
}
|
|
27177
27218
|
}
|
|
27178
27219
|
function readdirSafe(p2) {
|
|
27179
27220
|
try {
|
|
27180
|
-
return
|
|
27221
|
+
return fs22.readdirSync(p2);
|
|
27181
27222
|
} catch {
|
|
27182
27223
|
return [];
|
|
27183
27224
|
}
|
|
27184
27225
|
}
|
|
27185
27226
|
function rmdirIfEmpty(p2) {
|
|
27186
27227
|
try {
|
|
27187
|
-
|
|
27228
|
+
fs22.rmdirSync(p2);
|
|
27188
27229
|
} catch {
|
|
27189
27230
|
}
|
|
27190
27231
|
}
|
|
27191
27232
|
|
|
27192
27233
|
// src/transport/http-router.ts
|
|
27193
|
-
var
|
|
27194
|
-
var
|
|
27234
|
+
var import_node_fs17 = __toESM(require("fs"), 1);
|
|
27235
|
+
var import_node_path19 = __toESM(require("path"), 1);
|
|
27195
27236
|
|
|
27196
27237
|
// src/attachment/mime.ts
|
|
27197
|
-
var
|
|
27238
|
+
var import_node_path17 = __toESM(require("path"), 1);
|
|
27198
27239
|
var TEXT_PLAIN = "text/plain; charset=utf-8";
|
|
27199
27240
|
var EXT_TO_NATIVE_MIME = {
|
|
27200
27241
|
// 图片
|
|
@@ -27301,7 +27342,7 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
27301
27342
|
".mk"
|
|
27302
27343
|
]);
|
|
27303
27344
|
function lookupMime(filePathOrName) {
|
|
27304
|
-
const ext =
|
|
27345
|
+
const ext = import_node_path17.default.extname(filePathOrName).toLowerCase();
|
|
27305
27346
|
if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
|
|
27306
27347
|
if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
|
|
27307
27348
|
return "application/octet-stream";
|
|
@@ -27370,8 +27411,8 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
|
|
|
27370
27411
|
}
|
|
27371
27412
|
|
|
27372
27413
|
// src/attachment/upload.ts
|
|
27373
|
-
var
|
|
27374
|
-
var
|
|
27414
|
+
var import_node_fs16 = __toESM(require("fs"), 1);
|
|
27415
|
+
var import_node_path18 = __toESM(require("path"), 1);
|
|
27375
27416
|
var import_node_crypto6 = __toESM(require("crypto"), 1);
|
|
27376
27417
|
var import_promises = require("stream/promises");
|
|
27377
27418
|
var UploadError = class extends Error {
|
|
@@ -27383,22 +27424,22 @@ var UploadError = class extends Error {
|
|
|
27383
27424
|
code;
|
|
27384
27425
|
};
|
|
27385
27426
|
function assertValidFileName(fileName) {
|
|
27386
|
-
if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !==
|
|
27427
|
+
if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path18.default.basename(fileName)) {
|
|
27387
27428
|
throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
|
|
27388
27429
|
}
|
|
27389
27430
|
}
|
|
27390
27431
|
var HASH_PREFIX_LEN = 16;
|
|
27391
27432
|
async function writeUploadedAttachment(args) {
|
|
27392
27433
|
assertValidFileName(args.fileName);
|
|
27393
|
-
const attachmentsRoot =
|
|
27434
|
+
const attachmentsRoot = import_node_path18.default.join(args.sessionDir, ".attachments");
|
|
27394
27435
|
try {
|
|
27395
|
-
|
|
27436
|
+
import_node_fs16.default.mkdirSync(attachmentsRoot, { recursive: true });
|
|
27396
27437
|
} catch (err) {
|
|
27397
27438
|
throw new UploadError("STORAGE_ERROR", `mkdir failed: ${err.message}`);
|
|
27398
27439
|
}
|
|
27399
27440
|
const hasher = import_node_crypto6.default.createHash("sha256");
|
|
27400
27441
|
let actualSize = 0;
|
|
27401
|
-
const tmpPath =
|
|
27442
|
+
const tmpPath = import_node_path18.default.join(
|
|
27402
27443
|
attachmentsRoot,
|
|
27403
27444
|
`.upload-${process.pid}-${Date.now()}-${import_node_crypto6.default.randomBytes(4).toString("hex")}`
|
|
27404
27445
|
);
|
|
@@ -27413,18 +27454,18 @@ async function writeUploadedAttachment(args) {
|
|
|
27413
27454
|
yield buf;
|
|
27414
27455
|
}
|
|
27415
27456
|
},
|
|
27416
|
-
|
|
27457
|
+
import_node_fs16.default.createWriteStream(tmpPath, { mode: 384 })
|
|
27417
27458
|
);
|
|
27418
27459
|
} catch (err) {
|
|
27419
27460
|
try {
|
|
27420
|
-
|
|
27461
|
+
import_node_fs16.default.unlinkSync(tmpPath);
|
|
27421
27462
|
} catch {
|
|
27422
27463
|
}
|
|
27423
27464
|
throw new UploadError("STORAGE_ERROR", `write failed: ${err.message}`);
|
|
27424
27465
|
}
|
|
27425
27466
|
if (actualSize !== args.contentLength) {
|
|
27426
27467
|
try {
|
|
27427
|
-
|
|
27468
|
+
import_node_fs16.default.unlinkSync(tmpPath);
|
|
27428
27469
|
} catch {
|
|
27429
27470
|
}
|
|
27430
27471
|
throw new UploadError(
|
|
@@ -27433,35 +27474,35 @@ async function writeUploadedAttachment(args) {
|
|
|
27433
27474
|
);
|
|
27434
27475
|
}
|
|
27435
27476
|
const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
|
|
27436
|
-
const hashDir =
|
|
27477
|
+
const hashDir = import_node_path18.default.join(attachmentsRoot, attachmentId);
|
|
27437
27478
|
let finalFileName;
|
|
27438
27479
|
let hashDirExists = false;
|
|
27439
27480
|
try {
|
|
27440
|
-
hashDirExists =
|
|
27481
|
+
hashDirExists = import_node_fs16.default.statSync(hashDir).isDirectory();
|
|
27441
27482
|
} catch {
|
|
27442
27483
|
}
|
|
27443
27484
|
if (hashDirExists) {
|
|
27444
|
-
const existing =
|
|
27485
|
+
const existing = import_node_fs16.default.readdirSync(hashDir).filter((n) => !n.startsWith("."));
|
|
27445
27486
|
finalFileName = existing[0] ?? args.fileName;
|
|
27446
27487
|
try {
|
|
27447
|
-
|
|
27488
|
+
import_node_fs16.default.unlinkSync(tmpPath);
|
|
27448
27489
|
} catch {
|
|
27449
27490
|
}
|
|
27450
27491
|
} else {
|
|
27451
27492
|
try {
|
|
27452
|
-
|
|
27493
|
+
import_node_fs16.default.mkdirSync(hashDir, { recursive: true });
|
|
27453
27494
|
finalFileName = args.fileName;
|
|
27454
|
-
|
|
27495
|
+
import_node_fs16.default.renameSync(tmpPath, import_node_path18.default.join(hashDir, finalFileName));
|
|
27455
27496
|
} catch (err) {
|
|
27456
27497
|
try {
|
|
27457
|
-
|
|
27498
|
+
import_node_fs16.default.unlinkSync(tmpPath);
|
|
27458
27499
|
} catch {
|
|
27459
27500
|
}
|
|
27460
27501
|
throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
|
|
27461
27502
|
}
|
|
27462
27503
|
}
|
|
27463
|
-
const absPath =
|
|
27464
|
-
const relPath =
|
|
27504
|
+
const absPath = import_node_path18.default.join(hashDir, finalFileName);
|
|
27505
|
+
const relPath = import_node_path18.default.relative(args.sessionDir, absPath);
|
|
27465
27506
|
args.groupFileStore.upsert(args.scope, args.sessionId, {
|
|
27466
27507
|
relPath: absPath,
|
|
27467
27508
|
// 存绝对路径,与现有 agent 入清单的形态一致(attachment.ts:144 双形态兼容)
|
|
@@ -27498,7 +27539,7 @@ function isValidUploadFileName(fileName) {
|
|
|
27498
27539
|
if (fileName === "." || fileName === "..") return false;
|
|
27499
27540
|
if (fileName.startsWith(".")) return false;
|
|
27500
27541
|
if (fileName.includes("/") || fileName.includes("\\")) return false;
|
|
27501
|
-
return fileName ===
|
|
27542
|
+
return fileName === import_node_path19.default.basename(fileName);
|
|
27502
27543
|
}
|
|
27503
27544
|
function createHttpRouter(deps) {
|
|
27504
27545
|
return async (req, res) => {
|
|
@@ -27668,7 +27709,7 @@ function createHttpRouter(deps) {
|
|
|
27668
27709
|
return true;
|
|
27669
27710
|
}
|
|
27670
27711
|
let absPath;
|
|
27671
|
-
if (
|
|
27712
|
+
if (import_node_path19.default.isAbsolute(pathParam)) {
|
|
27672
27713
|
absPath = pathParam;
|
|
27673
27714
|
} else if (deps.sessionStore) {
|
|
27674
27715
|
const file = deps.sessionStore.read(sid);
|
|
@@ -27676,7 +27717,7 @@ function createHttpRouter(deps) {
|
|
|
27676
27717
|
sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
|
|
27677
27718
|
return true;
|
|
27678
27719
|
}
|
|
27679
|
-
absPath =
|
|
27720
|
+
absPath = import_node_path19.default.join(file.cwd, pathParam);
|
|
27680
27721
|
} else {
|
|
27681
27722
|
sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
|
|
27682
27723
|
return true;
|
|
@@ -27709,7 +27750,7 @@ function withCtx(ctx, body) {
|
|
|
27709
27750
|
function streamFile(res, absPath, logger) {
|
|
27710
27751
|
let stat;
|
|
27711
27752
|
try {
|
|
27712
|
-
stat =
|
|
27753
|
+
stat = import_node_fs17.default.statSync(absPath);
|
|
27713
27754
|
} catch (err) {
|
|
27714
27755
|
const code = err?.code;
|
|
27715
27756
|
if (code === "ENOENT") {
|
|
@@ -27724,7 +27765,7 @@ function streamFile(res, absPath, logger) {
|
|
|
27724
27765
|
return;
|
|
27725
27766
|
}
|
|
27726
27767
|
const mime = lookupMime(absPath);
|
|
27727
|
-
const basename =
|
|
27768
|
+
const basename = import_node_path19.default.basename(absPath);
|
|
27728
27769
|
res.writeHead(200, {
|
|
27729
27770
|
"Content-Type": mime,
|
|
27730
27771
|
"Content-Length": String(stat.size),
|
|
@@ -27732,7 +27773,7 @@ function streamFile(res, absPath, logger) {
|
|
|
27732
27773
|
// 防止浏览器把任意 mime 当 html 渲染
|
|
27733
27774
|
"X-Content-Type-Options": "nosniff"
|
|
27734
27775
|
});
|
|
27735
|
-
const stream =
|
|
27776
|
+
const stream = import_node_fs17.default.createReadStream(absPath);
|
|
27736
27777
|
stream.on("error", (err) => {
|
|
27737
27778
|
logger?.warn("streamFile read error", { absPath, err: err.message });
|
|
27738
27779
|
res.destroy();
|
|
@@ -27741,8 +27782,8 @@ function streamFile(res, absPath, logger) {
|
|
|
27741
27782
|
}
|
|
27742
27783
|
|
|
27743
27784
|
// src/attachment/gc.ts
|
|
27744
|
-
var
|
|
27745
|
-
var
|
|
27785
|
+
var import_node_fs18 = __toESM(require("fs"), 1);
|
|
27786
|
+
var import_node_path20 = __toESM(require("path"), 1);
|
|
27746
27787
|
var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
|
|
27747
27788
|
function runAttachmentGc(args) {
|
|
27748
27789
|
const now = (args.now ?? Date.now)();
|
|
@@ -27751,38 +27792,38 @@ function runAttachmentGc(args) {
|
|
|
27751
27792
|
for (const { scope, sessionId } of args.sessionScopes) {
|
|
27752
27793
|
for (const entry of args.groupFileStore.list(scope, sessionId)) {
|
|
27753
27794
|
if (entry.stale) continue;
|
|
27754
|
-
if (
|
|
27795
|
+
if (import_node_path20.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
|
|
27755
27796
|
}
|
|
27756
27797
|
}
|
|
27757
27798
|
for (const { scope, sessionId } of args.sessionScopes) {
|
|
27758
|
-
const sessionDir = args.getSessionCwd?.(sessionId) ??
|
|
27799
|
+
const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path20.default.join(
|
|
27759
27800
|
args.dataDir,
|
|
27760
27801
|
"sessions",
|
|
27761
27802
|
...scopeSubPath(scope).map(safeFileName),
|
|
27762
27803
|
safeFileName(sessionId)
|
|
27763
27804
|
);
|
|
27764
|
-
const attRoot =
|
|
27805
|
+
const attRoot = import_node_path20.default.join(sessionDir, ".attachments");
|
|
27765
27806
|
let hashDirs;
|
|
27766
27807
|
try {
|
|
27767
|
-
hashDirs =
|
|
27808
|
+
hashDirs = import_node_fs18.default.readdirSync(attRoot);
|
|
27768
27809
|
} catch (err) {
|
|
27769
27810
|
if (err.code === "ENOENT") continue;
|
|
27770
27811
|
args.logger?.warn("attachment gc: readdir failed", { attRoot, err: err.message });
|
|
27771
27812
|
continue;
|
|
27772
27813
|
}
|
|
27773
27814
|
for (const hashDir of hashDirs) {
|
|
27774
|
-
const hashDirAbs =
|
|
27815
|
+
const hashDirAbs = import_node_path20.default.join(attRoot, hashDir);
|
|
27775
27816
|
let files;
|
|
27776
27817
|
try {
|
|
27777
|
-
files =
|
|
27818
|
+
files = import_node_fs18.default.readdirSync(hashDirAbs);
|
|
27778
27819
|
} catch {
|
|
27779
27820
|
continue;
|
|
27780
27821
|
}
|
|
27781
27822
|
for (const name of files) {
|
|
27782
|
-
const file =
|
|
27823
|
+
const file = import_node_path20.default.join(hashDirAbs, name);
|
|
27783
27824
|
let stat;
|
|
27784
27825
|
try {
|
|
27785
|
-
stat =
|
|
27826
|
+
stat = import_node_fs18.default.statSync(file);
|
|
27786
27827
|
} catch {
|
|
27787
27828
|
continue;
|
|
27788
27829
|
}
|
|
@@ -27791,26 +27832,26 @@ function runAttachmentGc(args) {
|
|
|
27791
27832
|
if (age < ttlMs) continue;
|
|
27792
27833
|
if (liveAbs.has(file)) continue;
|
|
27793
27834
|
try {
|
|
27794
|
-
|
|
27835
|
+
import_node_fs18.default.unlinkSync(file);
|
|
27795
27836
|
} catch (err) {
|
|
27796
27837
|
args.logger?.warn("attachment gc: unlink failed", { file, err: err.message });
|
|
27797
27838
|
}
|
|
27798
27839
|
}
|
|
27799
27840
|
try {
|
|
27800
|
-
if (
|
|
27841
|
+
if (import_node_fs18.default.readdirSync(hashDirAbs).length === 0) import_node_fs18.default.rmdirSync(hashDirAbs);
|
|
27801
27842
|
} catch {
|
|
27802
27843
|
}
|
|
27803
27844
|
}
|
|
27804
27845
|
try {
|
|
27805
|
-
if (
|
|
27846
|
+
if (import_node_fs18.default.readdirSync(attRoot).length === 0) import_node_fs18.default.rmdirSync(attRoot);
|
|
27806
27847
|
} catch {
|
|
27807
27848
|
}
|
|
27808
27849
|
}
|
|
27809
27850
|
}
|
|
27810
27851
|
|
|
27811
27852
|
// src/attachment/group.ts
|
|
27812
|
-
var
|
|
27813
|
-
var
|
|
27853
|
+
var import_node_fs19 = __toESM(require("fs"), 1);
|
|
27854
|
+
var import_node_path21 = __toESM(require("path"), 1);
|
|
27814
27855
|
var import_node_crypto7 = __toESM(require("crypto"), 1);
|
|
27815
27856
|
init_protocol();
|
|
27816
27857
|
var GroupFileStore = class {
|
|
@@ -27822,11 +27863,11 @@ var GroupFileStore = class {
|
|
|
27822
27863
|
this.logger = opts.logger;
|
|
27823
27864
|
}
|
|
27824
27865
|
rootForScope(scope) {
|
|
27825
|
-
return
|
|
27866
|
+
return import_node_path21.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
|
|
27826
27867
|
}
|
|
27827
27868
|
/** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
|
|
27828
27869
|
filePath(scope, sessionId) {
|
|
27829
|
-
return
|
|
27870
|
+
return import_node_path21.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
|
|
27830
27871
|
}
|
|
27831
27872
|
cacheKey(scope, sessionId) {
|
|
27832
27873
|
return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
|
|
@@ -27835,7 +27876,7 @@ var GroupFileStore = class {
|
|
|
27835
27876
|
readFile(scope, sessionId) {
|
|
27836
27877
|
const file = this.filePath(scope, sessionId);
|
|
27837
27878
|
try {
|
|
27838
|
-
const raw =
|
|
27879
|
+
const raw = import_node_fs19.default.readFileSync(file, "utf8");
|
|
27839
27880
|
const parsed = JSON.parse(raw);
|
|
27840
27881
|
if (!Array.isArray(parsed)) {
|
|
27841
27882
|
this.logger?.warn("GroupFileStore.readFile: not an array; resetting session entries", {
|
|
@@ -27861,10 +27902,10 @@ var GroupFileStore = class {
|
|
|
27861
27902
|
}
|
|
27862
27903
|
writeFile(scope, sessionId, entries) {
|
|
27863
27904
|
const file = this.filePath(scope, sessionId);
|
|
27864
|
-
|
|
27905
|
+
import_node_fs19.default.mkdirSync(import_node_path21.default.dirname(file), { recursive: true });
|
|
27865
27906
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
27866
|
-
|
|
27867
|
-
|
|
27907
|
+
import_node_fs19.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
|
|
27908
|
+
import_node_fs19.default.renameSync(tmp, file);
|
|
27868
27909
|
}
|
|
27869
27910
|
/** 拉一份当前 session 的清单。读盘 → cache;之后调用复用 cache */
|
|
27870
27911
|
list(scope, sessionId) {
|
|
@@ -27950,10 +27991,10 @@ var GroupFileStore = class {
|
|
|
27950
27991
|
};
|
|
27951
27992
|
|
|
27952
27993
|
// src/discovery/state-file.ts
|
|
27953
|
-
var
|
|
27954
|
-
var
|
|
27994
|
+
var import_node_fs20 = __toESM(require("fs"), 1);
|
|
27995
|
+
var import_node_path22 = __toESM(require("path"), 1);
|
|
27955
27996
|
function defaultStateFilePath(dataDir) {
|
|
27956
|
-
return
|
|
27997
|
+
return import_node_path22.default.join(dataDir, "state.json");
|
|
27957
27998
|
}
|
|
27958
27999
|
function isPidAlive(pid) {
|
|
27959
28000
|
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
@@ -27975,7 +28016,7 @@ var StateFileManager = class {
|
|
|
27975
28016
|
}
|
|
27976
28017
|
read() {
|
|
27977
28018
|
try {
|
|
27978
|
-
const raw =
|
|
28019
|
+
const raw = import_node_fs20.default.readFileSync(this.file, "utf8");
|
|
27979
28020
|
const parsed = JSON.parse(raw);
|
|
27980
28021
|
return parsed;
|
|
27981
28022
|
} catch {
|
|
@@ -27989,34 +28030,34 @@ var StateFileManager = class {
|
|
|
27989
28030
|
return { status: "stale", existing };
|
|
27990
28031
|
}
|
|
27991
28032
|
write(state) {
|
|
27992
|
-
|
|
28033
|
+
import_node_fs20.default.mkdirSync(import_node_path22.default.dirname(this.file), { recursive: true });
|
|
27993
28034
|
const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
|
|
27994
|
-
|
|
27995
|
-
|
|
28035
|
+
import_node_fs20.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
|
|
28036
|
+
import_node_fs20.default.renameSync(tmp, this.file);
|
|
27996
28037
|
if (process.platform !== "win32") {
|
|
27997
28038
|
try {
|
|
27998
|
-
|
|
28039
|
+
import_node_fs20.default.chmodSync(this.file, 384);
|
|
27999
28040
|
} catch {
|
|
28000
28041
|
}
|
|
28001
28042
|
}
|
|
28002
28043
|
}
|
|
28003
28044
|
delete() {
|
|
28004
28045
|
try {
|
|
28005
|
-
|
|
28046
|
+
import_node_fs20.default.unlinkSync(this.file);
|
|
28006
28047
|
} catch {
|
|
28007
28048
|
}
|
|
28008
28049
|
}
|
|
28009
28050
|
};
|
|
28010
28051
|
|
|
28011
28052
|
// src/tunnel/tunnel-manager.ts
|
|
28012
|
-
var
|
|
28013
|
-
var
|
|
28053
|
+
var import_node_fs24 = __toESM(require("fs"), 1);
|
|
28054
|
+
var import_node_path26 = __toESM(require("path"), 1);
|
|
28014
28055
|
var import_node_crypto8 = __toESM(require("crypto"), 1);
|
|
28015
28056
|
var import_node_child_process5 = require("child_process");
|
|
28016
28057
|
|
|
28017
28058
|
// src/tunnel/tunnel-store.ts
|
|
28018
|
-
var
|
|
28019
|
-
var
|
|
28059
|
+
var import_node_fs21 = __toESM(require("fs"), 1);
|
|
28060
|
+
var import_node_path23 = __toESM(require("path"), 1);
|
|
28020
28061
|
var TunnelStore = class {
|
|
28021
28062
|
constructor(filePath) {
|
|
28022
28063
|
this.filePath = filePath;
|
|
@@ -28024,7 +28065,7 @@ var TunnelStore = class {
|
|
|
28024
28065
|
filePath;
|
|
28025
28066
|
async get() {
|
|
28026
28067
|
try {
|
|
28027
|
-
const raw = await
|
|
28068
|
+
const raw = await import_node_fs21.default.promises.readFile(this.filePath, "utf8");
|
|
28028
28069
|
const obj = JSON.parse(raw);
|
|
28029
28070
|
if (!isPersistedTunnel(obj)) return null;
|
|
28030
28071
|
return obj;
|
|
@@ -28035,22 +28076,22 @@ var TunnelStore = class {
|
|
|
28035
28076
|
}
|
|
28036
28077
|
}
|
|
28037
28078
|
async set(v2) {
|
|
28038
|
-
const dir =
|
|
28039
|
-
await
|
|
28079
|
+
const dir = import_node_path23.default.dirname(this.filePath);
|
|
28080
|
+
await import_node_fs21.default.promises.mkdir(dir, { recursive: true });
|
|
28040
28081
|
const data = JSON.stringify(v2, null, 2);
|
|
28041
28082
|
const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
|
|
28042
|
-
await
|
|
28083
|
+
await import_node_fs21.default.promises.writeFile(tmp, data, { mode: 384 });
|
|
28043
28084
|
if (process.platform !== "win32") {
|
|
28044
28085
|
try {
|
|
28045
|
-
await
|
|
28086
|
+
await import_node_fs21.default.promises.chmod(tmp, 384);
|
|
28046
28087
|
} catch {
|
|
28047
28088
|
}
|
|
28048
28089
|
}
|
|
28049
|
-
await
|
|
28090
|
+
await import_node_fs21.default.promises.rename(tmp, this.filePath);
|
|
28050
28091
|
}
|
|
28051
28092
|
async clear() {
|
|
28052
28093
|
try {
|
|
28053
|
-
await
|
|
28094
|
+
await import_node_fs21.default.promises.unlink(this.filePath);
|
|
28054
28095
|
} catch (err) {
|
|
28055
28096
|
const code = err?.code;
|
|
28056
28097
|
if (code !== "ENOENT") throw err;
|
|
@@ -28145,9 +28186,9 @@ function escape(v2) {
|
|
|
28145
28186
|
}
|
|
28146
28187
|
|
|
28147
28188
|
// src/tunnel/frpc-binary.ts
|
|
28148
|
-
var
|
|
28189
|
+
var import_node_fs22 = __toESM(require("fs"), 1);
|
|
28149
28190
|
var import_node_os10 = __toESM(require("os"), 1);
|
|
28150
|
-
var
|
|
28191
|
+
var import_node_path24 = __toESM(require("path"), 1);
|
|
28151
28192
|
var import_node_child_process3 = require("child_process");
|
|
28152
28193
|
var import_node_stream2 = require("stream");
|
|
28153
28194
|
var import_promises2 = require("stream/promises");
|
|
@@ -28179,20 +28220,20 @@ function frpcDownloadUrl(version2, p2) {
|
|
|
28179
28220
|
}
|
|
28180
28221
|
async function ensureFrpcBinary(opts) {
|
|
28181
28222
|
if (opts.override) {
|
|
28182
|
-
if (!
|
|
28223
|
+
if (!import_node_fs22.default.existsSync(opts.override)) {
|
|
28183
28224
|
throw new Error(`frpc binary not found at override path: ${opts.override}`);
|
|
28184
28225
|
}
|
|
28185
28226
|
return opts.override;
|
|
28186
28227
|
}
|
|
28187
28228
|
const version2 = opts.version ?? FRPC_VERSION;
|
|
28188
28229
|
const platform = opts.platform ?? detectPlatform();
|
|
28189
|
-
const binDir =
|
|
28190
|
-
|
|
28230
|
+
const binDir = import_node_path24.default.join(opts.dataDir, "bin");
|
|
28231
|
+
import_node_fs22.default.mkdirSync(binDir, { recursive: true });
|
|
28191
28232
|
cleanupStaleArtifacts(binDir);
|
|
28192
|
-
const stableBin =
|
|
28193
|
-
if (
|
|
28233
|
+
const stableBin = import_node_path24.default.join(binDir, "frpc");
|
|
28234
|
+
if (import_node_fs22.default.existsSync(stableBin)) return stableBin;
|
|
28194
28235
|
const partialBin = `${stableBin}.partial`;
|
|
28195
|
-
const tarballPath =
|
|
28236
|
+
const tarballPath = import_node_path24.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
|
|
28196
28237
|
try {
|
|
28197
28238
|
const url = frpcDownloadUrl(version2, platform);
|
|
28198
28239
|
await downloadToFile(url, tarballPath, opts.fetchImpl);
|
|
@@ -28201,8 +28242,8 @@ async function ensureFrpcBinary(opts) {
|
|
|
28201
28242
|
} else {
|
|
28202
28243
|
await extractFrpcFromTarball(tarballPath, binDir, version2, platform, partialBin);
|
|
28203
28244
|
}
|
|
28204
|
-
|
|
28205
|
-
|
|
28245
|
+
import_node_fs22.default.chmodSync(partialBin, 493);
|
|
28246
|
+
import_node_fs22.default.renameSync(partialBin, stableBin);
|
|
28206
28247
|
} finally {
|
|
28207
28248
|
safeUnlink(tarballPath);
|
|
28208
28249
|
safeUnlink(partialBin);
|
|
@@ -28212,15 +28253,15 @@ async function ensureFrpcBinary(opts) {
|
|
|
28212
28253
|
function cleanupStaleArtifacts(binDir) {
|
|
28213
28254
|
let entries;
|
|
28214
28255
|
try {
|
|
28215
|
-
entries =
|
|
28256
|
+
entries = import_node_fs22.default.readdirSync(binDir);
|
|
28216
28257
|
} catch {
|
|
28217
28258
|
return;
|
|
28218
28259
|
}
|
|
28219
28260
|
for (const name of entries) {
|
|
28220
28261
|
if (name.endsWith(".partial") || name.startsWith("extract-")) {
|
|
28221
|
-
const full =
|
|
28262
|
+
const full = import_node_path24.default.join(binDir, name);
|
|
28222
28263
|
try {
|
|
28223
|
-
|
|
28264
|
+
import_node_fs22.default.rmSync(full, { recursive: true, force: true });
|
|
28224
28265
|
} catch {
|
|
28225
28266
|
}
|
|
28226
28267
|
}
|
|
@@ -28228,7 +28269,7 @@ function cleanupStaleArtifacts(binDir) {
|
|
|
28228
28269
|
}
|
|
28229
28270
|
function safeUnlink(p2) {
|
|
28230
28271
|
try {
|
|
28231
|
-
|
|
28272
|
+
import_node_fs22.default.unlinkSync(p2);
|
|
28232
28273
|
} catch {
|
|
28233
28274
|
}
|
|
28234
28275
|
}
|
|
@@ -28239,13 +28280,13 @@ async function downloadToFile(url, dest, fetchImpl) {
|
|
|
28239
28280
|
if (!res.ok || !res.body) {
|
|
28240
28281
|
throw new Error(`download failed: ${res.status} ${res.statusText}`);
|
|
28241
28282
|
}
|
|
28242
|
-
const out =
|
|
28283
|
+
const out = import_node_fs22.default.createWriteStream(dest);
|
|
28243
28284
|
const nodeStream = import_node_stream2.Readable.fromWeb(res.body);
|
|
28244
28285
|
await (0, import_promises2.pipeline)(nodeStream, out);
|
|
28245
28286
|
}
|
|
28246
28287
|
async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
|
|
28247
|
-
const work =
|
|
28248
|
-
|
|
28288
|
+
const work = import_node_path24.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
|
|
28289
|
+
import_node_fs22.default.mkdirSync(work, { recursive: true });
|
|
28249
28290
|
try {
|
|
28250
28291
|
await new Promise((resolve6, reject) => {
|
|
28251
28292
|
const proc = (0, import_node_child_process3.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
|
|
@@ -28253,32 +28294,32 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
|
|
|
28253
28294
|
proc.on("exit", (code) => code === 0 ? resolve6() : reject(new Error(`tar exited ${code}`)));
|
|
28254
28295
|
});
|
|
28255
28296
|
const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
|
|
28256
|
-
const src =
|
|
28257
|
-
if (!
|
|
28297
|
+
const src = import_node_path24.default.join(work, dirName, "frpc");
|
|
28298
|
+
if (!import_node_fs22.default.existsSync(src)) {
|
|
28258
28299
|
throw new Error(`frpc not found inside tarball at ${src}`);
|
|
28259
28300
|
}
|
|
28260
|
-
|
|
28301
|
+
import_node_fs22.default.copyFileSync(src, destBin);
|
|
28261
28302
|
} finally {
|
|
28262
|
-
|
|
28303
|
+
import_node_fs22.default.rmSync(work, { recursive: true, force: true });
|
|
28263
28304
|
}
|
|
28264
28305
|
}
|
|
28265
28306
|
|
|
28266
28307
|
// src/tunnel/frpc-process.ts
|
|
28267
|
-
var
|
|
28268
|
-
var
|
|
28308
|
+
var import_node_fs23 = __toESM(require("fs"), 1);
|
|
28309
|
+
var import_node_path25 = __toESM(require("path"), 1);
|
|
28269
28310
|
var import_node_child_process4 = require("child_process");
|
|
28270
28311
|
function frpcPidFilePath(dataDir) {
|
|
28271
|
-
return
|
|
28312
|
+
return import_node_path25.default.join(dataDir, "frpc.pid");
|
|
28272
28313
|
}
|
|
28273
28314
|
function writeFrpcPid(dataDir, pid) {
|
|
28274
28315
|
try {
|
|
28275
|
-
|
|
28316
|
+
import_node_fs23.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
|
|
28276
28317
|
} catch {
|
|
28277
28318
|
}
|
|
28278
28319
|
}
|
|
28279
28320
|
function clearFrpcPid(dataDir) {
|
|
28280
28321
|
try {
|
|
28281
|
-
|
|
28322
|
+
import_node_fs23.default.unlinkSync(frpcPidFilePath(dataDir));
|
|
28282
28323
|
} catch {
|
|
28283
28324
|
}
|
|
28284
28325
|
}
|
|
@@ -28294,7 +28335,7 @@ function defaultIsPidAlive(pid) {
|
|
|
28294
28335
|
}
|
|
28295
28336
|
function defaultReadPidFile(file) {
|
|
28296
28337
|
try {
|
|
28297
|
-
return
|
|
28338
|
+
return import_node_fs23.default.readFileSync(file, "utf8");
|
|
28298
28339
|
} catch {
|
|
28299
28340
|
return null;
|
|
28300
28341
|
}
|
|
@@ -28310,7 +28351,7 @@ function defaultSleep(ms) {
|
|
|
28310
28351
|
}
|
|
28311
28352
|
async function killStaleFrpc(deps) {
|
|
28312
28353
|
const pidFile = frpcPidFilePath(deps.dataDir);
|
|
28313
|
-
const tomlPath =
|
|
28354
|
+
const tomlPath = import_node_path25.default.join(deps.dataDir, "frpc.toml");
|
|
28314
28355
|
const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
|
|
28315
28356
|
const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
|
|
28316
28357
|
const killPid = deps.killPidImpl ?? defaultKillPid;
|
|
@@ -28334,7 +28375,7 @@ async function killStaleFrpc(deps) {
|
|
|
28334
28375
|
}
|
|
28335
28376
|
if (victims.size === 0) {
|
|
28336
28377
|
try {
|
|
28337
|
-
|
|
28378
|
+
import_node_fs23.default.unlinkSync(pidFile);
|
|
28338
28379
|
} catch {
|
|
28339
28380
|
}
|
|
28340
28381
|
return;
|
|
@@ -28345,7 +28386,7 @@ async function killStaleFrpc(deps) {
|
|
|
28345
28386
|
}
|
|
28346
28387
|
await sleep(deps.reapWaitMs ?? 300);
|
|
28347
28388
|
try {
|
|
28348
|
-
|
|
28389
|
+
import_node_fs23.default.unlinkSync(pidFile);
|
|
28349
28390
|
} catch {
|
|
28350
28391
|
}
|
|
28351
28392
|
}
|
|
@@ -28382,7 +28423,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
|
28382
28423
|
var TunnelManager = class {
|
|
28383
28424
|
constructor(deps) {
|
|
28384
28425
|
this.deps = deps;
|
|
28385
|
-
this.store = deps.store ?? new TunnelStore(
|
|
28426
|
+
this.store = deps.store ?? new TunnelStore(import_node_path26.default.join(deps.dataDir, "tunnel.json"));
|
|
28386
28427
|
this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
|
|
28387
28428
|
this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
|
|
28388
28429
|
}
|
|
@@ -28509,7 +28550,7 @@ var TunnelManager = class {
|
|
|
28509
28550
|
dataDir: this.deps.dataDir,
|
|
28510
28551
|
override: this.deps.frpcBinaryOverride ?? void 0
|
|
28511
28552
|
});
|
|
28512
|
-
const tomlPath =
|
|
28553
|
+
const tomlPath = import_node_path26.default.join(this.deps.dataDir, "frpc.toml");
|
|
28513
28554
|
const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto8.default.randomBytes(3).toString("hex")}`;
|
|
28514
28555
|
const toml = buildFrpcToml({
|
|
28515
28556
|
serverAddr: t.frpsHost,
|
|
@@ -28520,12 +28561,12 @@ var TunnelManager = class {
|
|
|
28520
28561
|
localPort,
|
|
28521
28562
|
logLevel: "info"
|
|
28522
28563
|
});
|
|
28523
|
-
await
|
|
28564
|
+
await import_node_fs24.default.promises.writeFile(tomlPath, toml, { mode: 384 });
|
|
28524
28565
|
const proc = (this.deps.spawnImpl ?? import_node_child_process5.spawn)(frpcBin, ["-c", tomlPath], {
|
|
28525
28566
|
stdio: ["ignore", "pipe", "pipe"]
|
|
28526
28567
|
});
|
|
28527
|
-
const logFilePath =
|
|
28528
|
-
const logStream =
|
|
28568
|
+
const logFilePath = import_node_path26.default.join(this.deps.dataDir, "frpc.log");
|
|
28569
|
+
const logStream = import_node_fs24.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
|
|
28529
28570
|
logStream.on("error", () => {
|
|
28530
28571
|
});
|
|
28531
28572
|
const tee = (chunk) => {
|
|
@@ -28618,12 +28659,12 @@ function deriveStableDeviceKey(opts = {}) {
|
|
|
28618
28659
|
}
|
|
28619
28660
|
|
|
28620
28661
|
// src/auth-store.ts
|
|
28621
|
-
var
|
|
28622
|
-
var
|
|
28662
|
+
var import_node_fs25 = __toESM(require("fs"), 1);
|
|
28663
|
+
var import_node_path27 = __toESM(require("path"), 1);
|
|
28623
28664
|
var import_node_crypto10 = __toESM(require("crypto"), 1);
|
|
28624
28665
|
var AUTH_FILE_NAME = "auth.json";
|
|
28625
28666
|
function authFilePath(dataDir) {
|
|
28626
|
-
return
|
|
28667
|
+
return import_node_path27.default.join(dataDir, AUTH_FILE_NAME);
|
|
28627
28668
|
}
|
|
28628
28669
|
function loadOrCreateAuthFile(opts) {
|
|
28629
28670
|
const file = authFilePath(opts.dataDir);
|
|
@@ -28655,7 +28696,7 @@ function defaultGenerateOwnerPrincipalId() {
|
|
|
28655
28696
|
}
|
|
28656
28697
|
function readAuthFile(file) {
|
|
28657
28698
|
try {
|
|
28658
|
-
const raw =
|
|
28699
|
+
const raw = import_node_fs25.default.readFileSync(file, "utf8");
|
|
28659
28700
|
const parsed = JSON.parse(raw);
|
|
28660
28701
|
if (typeof parsed?.token !== "string" || parsed.token.length === 0) {
|
|
28661
28702
|
return null;
|
|
@@ -28673,25 +28714,25 @@ function readAuthFile(file) {
|
|
|
28673
28714
|
}
|
|
28674
28715
|
}
|
|
28675
28716
|
function writeAuthFile(file, content) {
|
|
28676
|
-
|
|
28677
|
-
|
|
28717
|
+
import_node_fs25.default.mkdirSync(import_node_path27.default.dirname(file), { recursive: true });
|
|
28718
|
+
import_node_fs25.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
|
|
28678
28719
|
try {
|
|
28679
|
-
|
|
28720
|
+
import_node_fs25.default.chmodSync(file, 384);
|
|
28680
28721
|
} catch {
|
|
28681
28722
|
}
|
|
28682
28723
|
}
|
|
28683
28724
|
|
|
28684
28725
|
// src/owner-profile.ts
|
|
28685
|
-
var
|
|
28726
|
+
var import_node_fs26 = __toESM(require("fs"), 1);
|
|
28686
28727
|
var import_node_os12 = __toESM(require("os"), 1);
|
|
28687
|
-
var
|
|
28728
|
+
var import_node_path28 = __toESM(require("path"), 1);
|
|
28688
28729
|
var PROFILE_FILENAME = "profile.json";
|
|
28689
28730
|
function loadOwnerDisplayName(dataDir) {
|
|
28690
28731
|
const fallback = import_node_os12.default.userInfo().username;
|
|
28691
|
-
const profilePath =
|
|
28732
|
+
const profilePath = import_node_path28.default.join(dataDir, PROFILE_FILENAME);
|
|
28692
28733
|
let raw;
|
|
28693
28734
|
try {
|
|
28694
|
-
raw =
|
|
28735
|
+
raw = import_node_fs26.default.readFileSync(profilePath, "utf8");
|
|
28695
28736
|
} catch {
|
|
28696
28737
|
return fallback;
|
|
28697
28738
|
}
|
|
@@ -28720,12 +28761,12 @@ init_protocol();
|
|
|
28720
28761
|
init_protocol();
|
|
28721
28762
|
|
|
28722
28763
|
// src/session/fork.ts
|
|
28723
|
-
var
|
|
28764
|
+
var import_node_fs27 = __toESM(require("fs"), 1);
|
|
28724
28765
|
var import_node_os13 = __toESM(require("os"), 1);
|
|
28725
|
-
var
|
|
28766
|
+
var import_node_path29 = __toESM(require("path"), 1);
|
|
28726
28767
|
init_claude_history();
|
|
28727
28768
|
function readJsonlEntries(file) {
|
|
28728
|
-
const raw =
|
|
28769
|
+
const raw = import_node_fs27.default.readFileSync(file, "utf8");
|
|
28729
28770
|
const out = [];
|
|
28730
28771
|
for (const line of raw.split("\n")) {
|
|
28731
28772
|
const t = line.trim();
|
|
@@ -28738,10 +28779,10 @@ function readJsonlEntries(file) {
|
|
|
28738
28779
|
return out;
|
|
28739
28780
|
}
|
|
28740
28781
|
function forkSession(input) {
|
|
28741
|
-
const baseDir = input.baseDir ??
|
|
28742
|
-
const projectDir =
|
|
28743
|
-
const sourceFile =
|
|
28744
|
-
if (!
|
|
28782
|
+
const baseDir = input.baseDir ?? import_node_path29.default.join(import_node_os13.default.homedir(), ".claude");
|
|
28783
|
+
const projectDir = import_node_path29.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
|
|
28784
|
+
const sourceFile = import_node_path29.default.join(projectDir, `${input.toolSessionId}.jsonl`);
|
|
28785
|
+
if (!import_node_fs27.default.existsSync(sourceFile)) {
|
|
28745
28786
|
throw new Error(`fork: source transcript not found: ${sourceFile}`);
|
|
28746
28787
|
}
|
|
28747
28788
|
const entries = readJsonlEntries(sourceFile);
|
|
@@ -28771,9 +28812,9 @@ function forkSession(input) {
|
|
|
28771
28812
|
}
|
|
28772
28813
|
forkedLines.push(JSON.stringify(forked));
|
|
28773
28814
|
}
|
|
28774
|
-
const forkedFilePath =
|
|
28775
|
-
|
|
28776
|
-
|
|
28815
|
+
const forkedFilePath = import_node_path29.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
|
|
28816
|
+
import_node_fs27.default.mkdirSync(projectDir, { recursive: true });
|
|
28817
|
+
import_node_fs27.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
|
|
28777
28818
|
return { forkedToolSessionId, forkedFilePath };
|
|
28778
28819
|
}
|
|
28779
28820
|
|
|
@@ -29061,28 +29102,6 @@ function buildSessionHandlers(deps) {
|
|
|
29061
29102
|
}
|
|
29062
29103
|
};
|
|
29063
29104
|
};
|
|
29064
|
-
const peerSessionUpsert = async (frame, _client, ctx) => {
|
|
29065
|
-
if (ctx && ctx.principal.kind !== "owner") {
|
|
29066
|
-
throw new ClawdError(
|
|
29067
|
-
ERROR_CODES.UNAUTHORIZED,
|
|
29068
|
-
`principal ${ctx.principal.kind}:${ctx.principal.id} cannot peerSession:upsert`
|
|
29069
|
-
);
|
|
29070
|
-
}
|
|
29071
|
-
const file = PeerSessionUpsertArgs.parse(frame);
|
|
29072
|
-
manager.mirrorUpsert(file);
|
|
29073
|
-
return { response: { type: "peerSession:upsert:ok" }, broadcast: [] };
|
|
29074
|
-
};
|
|
29075
|
-
const peerSessionRemove = async (frame, _client, ctx) => {
|
|
29076
|
-
if (ctx && ctx.principal.kind !== "owner") {
|
|
29077
|
-
throw new ClawdError(
|
|
29078
|
-
ERROR_CODES.UNAUTHORIZED,
|
|
29079
|
-
`principal ${ctx.principal.kind}:${ctx.principal.id} cannot peerSession:remove`
|
|
29080
|
-
);
|
|
29081
|
-
}
|
|
29082
|
-
const args = PeerSessionRemoveArgs.parse(frame);
|
|
29083
|
-
manager.mirrorRemove(args.sessionId);
|
|
29084
|
-
return { response: { type: "peerSession:remove:ok" }, broadcast: [] };
|
|
29085
|
-
};
|
|
29086
29105
|
return {
|
|
29087
29106
|
"session:create": create,
|
|
29088
29107
|
"session:list": list,
|
|
@@ -29108,9 +29127,7 @@ function buildSessionHandlers(deps) {
|
|
|
29108
29127
|
"session:cancelQuestion": cancelQuestion,
|
|
29109
29128
|
"session:pty:input": ptyInput,
|
|
29110
29129
|
"session:pty:resize": ptyResize,
|
|
29111
|
-
"session:pty:snapshot": ptySnapshot
|
|
29112
|
-
"peerSession:upsert": peerSessionUpsert,
|
|
29113
|
-
"peerSession:remove": peerSessionRemove
|
|
29130
|
+
"session:pty:snapshot": ptySnapshot
|
|
29114
29131
|
};
|
|
29115
29132
|
}
|
|
29116
29133
|
|
|
@@ -29129,7 +29146,7 @@ function buildPermissionHandlers(deps) {
|
|
|
29129
29146
|
}
|
|
29130
29147
|
|
|
29131
29148
|
// src/handlers/history.ts
|
|
29132
|
-
var
|
|
29149
|
+
var path39 = __toESM(require("path"), 1);
|
|
29133
29150
|
init_protocol();
|
|
29134
29151
|
|
|
29135
29152
|
// src/session/recent-dirs.ts
|
|
@@ -29147,7 +29164,7 @@ function listRecentDirs(store, limit = 50) {
|
|
|
29147
29164
|
}
|
|
29148
29165
|
|
|
29149
29166
|
// src/permission/persona-paths.ts
|
|
29150
|
-
var
|
|
29167
|
+
var path38 = __toESM(require("path"), 1);
|
|
29151
29168
|
function getAllowedPersonaIds(grants, action) {
|
|
29152
29169
|
const ids = /* @__PURE__ */ new Set();
|
|
29153
29170
|
for (const g2 of grants) {
|
|
@@ -29160,26 +29177,26 @@ function getAllowedPersonaIds(grants, action) {
|
|
|
29160
29177
|
return ids;
|
|
29161
29178
|
}
|
|
29162
29179
|
function isGuestPathAllowed(grants, absPath, personaRoot, action = "read") {
|
|
29163
|
-
const root =
|
|
29164
|
-
const target =
|
|
29165
|
-
const sep3 = root.endsWith(
|
|
29180
|
+
const root = path38.resolve(personaRoot);
|
|
29181
|
+
const target = path38.resolve(absPath);
|
|
29182
|
+
const sep3 = root.endsWith(path38.sep) ? "" : path38.sep;
|
|
29166
29183
|
if (!target.startsWith(root + sep3)) return false;
|
|
29167
|
-
const rel =
|
|
29184
|
+
const rel = path38.relative(root, target);
|
|
29168
29185
|
if (!rel || rel.startsWith("..")) return false;
|
|
29169
|
-
const personaId = rel.split(
|
|
29186
|
+
const personaId = rel.split(path38.sep)[0];
|
|
29170
29187
|
if (!personaId) return false;
|
|
29171
29188
|
const allowed = getAllowedPersonaIds(grants, action);
|
|
29172
29189
|
if (allowed === "*") return true;
|
|
29173
29190
|
return allowed.has(personaId);
|
|
29174
29191
|
}
|
|
29175
29192
|
function personaIdFromPath(absPath, personaRoot) {
|
|
29176
|
-
const root =
|
|
29177
|
-
const target =
|
|
29178
|
-
const sep3 = root.endsWith(
|
|
29193
|
+
const root = path38.resolve(personaRoot);
|
|
29194
|
+
const target = path38.resolve(absPath);
|
|
29195
|
+
const sep3 = root.endsWith(path38.sep) ? "" : path38.sep;
|
|
29179
29196
|
if (!target.startsWith(root + sep3)) return null;
|
|
29180
|
-
const rel =
|
|
29197
|
+
const rel = path38.relative(root, target);
|
|
29181
29198
|
if (!rel || rel.startsWith("..")) return null;
|
|
29182
|
-
const id = rel.split(
|
|
29199
|
+
const id = rel.split(path38.sep)[0];
|
|
29183
29200
|
return id || null;
|
|
29184
29201
|
}
|
|
29185
29202
|
|
|
@@ -29204,7 +29221,7 @@ function buildHistoryHandlers(deps) {
|
|
|
29204
29221
|
if (!pid) return false;
|
|
29205
29222
|
return isGuestPathAllowed(
|
|
29206
29223
|
ctx.grants,
|
|
29207
|
-
|
|
29224
|
+
path39.join(personaRoot, pid),
|
|
29208
29225
|
personaRoot,
|
|
29209
29226
|
"read"
|
|
29210
29227
|
);
|
|
@@ -29215,7 +29232,7 @@ function buildHistoryHandlers(deps) {
|
|
|
29215
29232
|
};
|
|
29216
29233
|
const list = async (frame, _client, ctx) => {
|
|
29217
29234
|
const args = HistoryListArgs.parse(frame);
|
|
29218
|
-
assertGuestPath(ctx,
|
|
29235
|
+
assertGuestPath(ctx, path39.resolve(args.projectPath), personaRoot, "history:list");
|
|
29219
29236
|
const sessions = await history.listSessions(args);
|
|
29220
29237
|
return { response: { type: "history:list", sessions } };
|
|
29221
29238
|
};
|
|
@@ -29247,13 +29264,13 @@ function buildHistoryHandlers(deps) {
|
|
|
29247
29264
|
};
|
|
29248
29265
|
const subagents = async (frame, _client, ctx) => {
|
|
29249
29266
|
const args = HistorySubagentsArgs.parse(frame);
|
|
29250
|
-
assertGuestPath(ctx,
|
|
29267
|
+
assertGuestPath(ctx, path39.resolve(args.cwd), personaRoot, "history:subagents");
|
|
29251
29268
|
const subs = await history.listSubagents(args);
|
|
29252
29269
|
return { response: { type: "history:subagents", subagents: subs } };
|
|
29253
29270
|
};
|
|
29254
29271
|
const subagentRead = async (frame, _client, ctx) => {
|
|
29255
29272
|
const args = HistorySubagentReadArgs.parse(frame);
|
|
29256
|
-
assertGuestPath(ctx,
|
|
29273
|
+
assertGuestPath(ctx, path39.resolve(args.cwd), personaRoot, "history:subagent-read");
|
|
29257
29274
|
const res = await history.readSubagent(args);
|
|
29258
29275
|
return { response: { type: "history:subagent-read", ...res } };
|
|
29259
29276
|
};
|
|
@@ -29261,7 +29278,7 @@ function buildHistoryHandlers(deps) {
|
|
|
29261
29278
|
const dirs = listRecentDirs(store);
|
|
29262
29279
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
29263
29280
|
const filtered = dirs.filter(
|
|
29264
|
-
(d) => isGuestPathAllowed(ctx.grants,
|
|
29281
|
+
(d) => isGuestPathAllowed(ctx.grants, path39.resolve(d.cwd), personaRoot, "read")
|
|
29265
29282
|
);
|
|
29266
29283
|
return { response: { type: "history:recentDirs", dirs: filtered } };
|
|
29267
29284
|
}
|
|
@@ -29278,7 +29295,7 @@ function buildHistoryHandlers(deps) {
|
|
|
29278
29295
|
}
|
|
29279
29296
|
|
|
29280
29297
|
// src/handlers/workspace.ts
|
|
29281
|
-
var
|
|
29298
|
+
var path40 = __toESM(require("path"), 1);
|
|
29282
29299
|
var os14 = __toESM(require("os"), 1);
|
|
29283
29300
|
init_protocol();
|
|
29284
29301
|
init_protocol();
|
|
@@ -29319,22 +29336,22 @@ function buildWorkspaceHandlers(deps) {
|
|
|
29319
29336
|
const args = WorkspaceListArgs.parse(frame);
|
|
29320
29337
|
const isGuest = ctx?.principal.kind === "guest";
|
|
29321
29338
|
const fallbackCwd = isGuest && personaRoot ? personaRoot : os14.homedir();
|
|
29322
|
-
const resolvedCwd =
|
|
29323
|
-
const target = args.path ?
|
|
29339
|
+
const resolvedCwd = path40.resolve(args.cwd ?? fallbackCwd);
|
|
29340
|
+
const target = args.path ? path40.resolve(resolvedCwd, args.path) : resolvedCwd;
|
|
29324
29341
|
assertGuestPath2(ctx, target, personaRoot, "workspace:list");
|
|
29325
29342
|
const res = workspace.list({ ...args, cwd: resolvedCwd });
|
|
29326
29343
|
return { response: { type: "workspace:list", ...res } };
|
|
29327
29344
|
};
|
|
29328
29345
|
const read = async (frame, _client, ctx) => {
|
|
29329
29346
|
const args = WorkspaceReadArgs.parse(frame);
|
|
29330
|
-
const target =
|
|
29347
|
+
const target = path40.isAbsolute(args.path) ? path40.resolve(args.path) : path40.resolve(args.cwd, args.path);
|
|
29331
29348
|
assertGuestPath2(ctx, target, personaRoot, "workspace:read");
|
|
29332
29349
|
const res = workspace.read(args);
|
|
29333
29350
|
return { response: { type: "workspace:read", ...res } };
|
|
29334
29351
|
};
|
|
29335
29352
|
const skillsList = async (frame, _client, ctx) => {
|
|
29336
29353
|
const args = SkillsListArgs.parse(frame);
|
|
29337
|
-
const cwdAbs =
|
|
29354
|
+
const cwdAbs = path40.resolve(args.cwd);
|
|
29338
29355
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list");
|
|
29339
29356
|
const list2 = skills.list(args);
|
|
29340
29357
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
@@ -29346,7 +29363,7 @@ function buildWorkspaceHandlers(deps) {
|
|
|
29346
29363
|
};
|
|
29347
29364
|
const agentsList = async (frame, _client, ctx) => {
|
|
29348
29365
|
const args = AgentsListArgs.parse(frame);
|
|
29349
|
-
const cwdAbs =
|
|
29366
|
+
const cwdAbs = path40.resolve(args.cwd);
|
|
29350
29367
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list");
|
|
29351
29368
|
const list2 = agents.list(args);
|
|
29352
29369
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
@@ -29365,20 +29382,20 @@ function buildWorkspaceHandlers(deps) {
|
|
|
29365
29382
|
}
|
|
29366
29383
|
|
|
29367
29384
|
// src/handlers/git.ts
|
|
29368
|
-
var
|
|
29385
|
+
var path42 = __toESM(require("path"), 1);
|
|
29369
29386
|
init_protocol();
|
|
29370
29387
|
init_protocol();
|
|
29371
29388
|
|
|
29372
29389
|
// src/workspace/git.ts
|
|
29373
29390
|
var import_node_child_process6 = require("child_process");
|
|
29374
|
-
var
|
|
29375
|
-
var
|
|
29391
|
+
var import_node_fs28 = __toESM(require("fs"), 1);
|
|
29392
|
+
var import_node_path30 = __toESM(require("path"), 1);
|
|
29376
29393
|
var import_node_util = require("util");
|
|
29377
29394
|
var pexec = (0, import_node_util.promisify)(import_node_child_process6.execFile);
|
|
29378
29395
|
function normalizePath(p2) {
|
|
29379
|
-
const resolved =
|
|
29396
|
+
const resolved = import_node_path30.default.resolve(p2);
|
|
29380
29397
|
try {
|
|
29381
|
-
return
|
|
29398
|
+
return import_node_fs28.default.realpathSync(resolved);
|
|
29382
29399
|
} catch {
|
|
29383
29400
|
return resolved;
|
|
29384
29401
|
}
|
|
@@ -29451,7 +29468,7 @@ async function listGitBranches(cwd) {
|
|
|
29451
29468
|
// src/handlers/git.ts
|
|
29452
29469
|
function assertGuestCwd(ctx, cwd, personaRoot, method) {
|
|
29453
29470
|
if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
|
|
29454
|
-
if (!isGuestPathAllowed(ctx.grants,
|
|
29471
|
+
if (!isGuestPathAllowed(ctx.grants, path42.resolve(cwd), personaRoot, "read")) {
|
|
29455
29472
|
throw new ClawdError(
|
|
29456
29473
|
ERROR_CODES.UNAUTHORIZED,
|
|
29457
29474
|
`guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
|
|
@@ -29938,7 +29955,7 @@ function buildPersonaHandlers(deps) {
|
|
|
29938
29955
|
}
|
|
29939
29956
|
|
|
29940
29957
|
// src/handlers/attachment.ts
|
|
29941
|
-
var
|
|
29958
|
+
var import_node_path31 = __toESM(require("path"), 1);
|
|
29942
29959
|
init_protocol();
|
|
29943
29960
|
init_protocol();
|
|
29944
29961
|
var DEFAULT_TTL_SECONDS = 24 * 3600;
|
|
@@ -29992,12 +30009,12 @@ function buildAttachmentHandlers(deps) {
|
|
|
29992
30009
|
`session ${args.sessionId} scope unresolved`
|
|
29993
30010
|
);
|
|
29994
30011
|
}
|
|
29995
|
-
const cwdAbs =
|
|
29996
|
-
const candidateAbs =
|
|
30012
|
+
const cwdAbs = import_node_path31.default.resolve(sessionFile.cwd);
|
|
30013
|
+
const candidateAbs = import_node_path31.default.isAbsolute(args.relPath) ? import_node_path31.default.resolve(args.relPath) : import_node_path31.default.resolve(cwdAbs, args.relPath);
|
|
29997
30014
|
assertGuestAttachmentPath(ctx, candidateAbs, deps.personaRoot, "attachment.signUrl");
|
|
29998
30015
|
const entries = deps.groupFileStore.list(scope, args.sessionId);
|
|
29999
30016
|
const entry = entries.find((e) => {
|
|
30000
|
-
const storedAbs =
|
|
30017
|
+
const storedAbs = import_node_path31.default.isAbsolute(e.relPath) ? import_node_path31.default.resolve(e.relPath) : import_node_path31.default.resolve(cwdAbs, e.relPath);
|
|
30001
30018
|
return storedAbs === candidateAbs && !e.stale;
|
|
30002
30019
|
});
|
|
30003
30020
|
if (!entry) {
|
|
@@ -30021,7 +30038,7 @@ function buildAttachmentHandlers(deps) {
|
|
|
30021
30038
|
if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
|
|
30022
30039
|
const f = deps.sessionStore.read(sessionId);
|
|
30023
30040
|
if (!f) return;
|
|
30024
|
-
assertGuestAttachmentPath(ctx,
|
|
30041
|
+
assertGuestAttachmentPath(ctx, import_node_path31.default.resolve(f.cwd), deps.personaRoot, method);
|
|
30025
30042
|
}
|
|
30026
30043
|
const groupAdd = async (frame, _client, ctx) => {
|
|
30027
30044
|
if (!deps.groupFileStore || !deps.getSessionScope) {
|
|
@@ -30188,11 +30205,6 @@ var METHOD_GRANT_MAP = {
|
|
|
30188
30205
|
"session:pin": CAPABILITY_SCOPED,
|
|
30189
30206
|
"session:reorderPins": ADMIN_ANY,
|
|
30190
30207
|
// owner 全局操作,无 personaId 维度
|
|
30191
|
-
// mirror peer sessions (2026-05-26):owner-only — guest 不应能写/删本机 mirror SessionFile
|
|
30192
|
-
// (会绕过 #739 隔离规则把伪造身份的 SessionFile 写进 default store)。handler 端内部 ctx
|
|
30193
|
-
// 校验,dispatcher 层一刀切 admin 也兜底。
|
|
30194
|
-
"peerSession:upsert": ADMIN_ANY,
|
|
30195
|
-
"peerSession:remove": ADMIN_ANY,
|
|
30196
30208
|
"permission:respond": CAPABILITY_SCOPED,
|
|
30197
30209
|
"session:answerQuestion": CAPABILITY_SCOPED,
|
|
30198
30210
|
"session:cancelQuestion": CAPABILITY_SCOPED,
|
|
@@ -30263,7 +30275,7 @@ function computeGrantForFrame(method, frame) {
|
|
|
30263
30275
|
async function startDaemon(config) {
|
|
30264
30276
|
const logger = createLogger({
|
|
30265
30277
|
level: config.logLevel,
|
|
30266
|
-
file:
|
|
30278
|
+
file: import_node_path32.default.join(config.dataDir, "clawd.log")
|
|
30267
30279
|
});
|
|
30268
30280
|
logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
|
|
30269
30281
|
const stateMgr = new StateFileManager({ dataDir: config.dataDir });
|
|
@@ -30350,7 +30362,7 @@ async function startDaemon(config) {
|
|
|
30350
30362
|
const agents = new AgentsScanner();
|
|
30351
30363
|
const history = new ClaudeHistoryReader();
|
|
30352
30364
|
let transport = null;
|
|
30353
|
-
const personaStore = new PersonaStore(
|
|
30365
|
+
const personaStore = new PersonaStore(import_node_path32.default.join(config.dataDir, "personas"));
|
|
30354
30366
|
const defaultsRoot = findDefaultsRoot();
|
|
30355
30367
|
if (defaultsRoot) {
|
|
30356
30368
|
seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
|
|
@@ -30367,7 +30379,7 @@ async function startDaemon(config) {
|
|
|
30367
30379
|
getAdapter,
|
|
30368
30380
|
historyReader: history,
|
|
30369
30381
|
dataDir: config.dataDir,
|
|
30370
|
-
personaRoot:
|
|
30382
|
+
personaRoot: import_node_path32.default.join(config.dataDir, "personas"),
|
|
30371
30383
|
personaStore,
|
|
30372
30384
|
ownerDisplayName,
|
|
30373
30385
|
ownerPrincipalId,
|
|
@@ -30391,10 +30403,10 @@ async function startDaemon(config) {
|
|
|
30391
30403
|
// 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
|
|
30392
30404
|
attachmentGroup: {
|
|
30393
30405
|
onFileEdit: (input) => {
|
|
30394
|
-
const absPath =
|
|
30406
|
+
const absPath = import_node_path32.default.isAbsolute(input.relPath) ? input.relPath : import_node_path32.default.join(input.cwd, input.relPath);
|
|
30395
30407
|
let size = 0;
|
|
30396
30408
|
try {
|
|
30397
|
-
size =
|
|
30409
|
+
size = import_node_fs29.default.statSync(absPath).size;
|
|
30398
30410
|
} catch (err) {
|
|
30399
30411
|
logger.warn("attachment.onFileEdit stat failed", {
|
|
30400
30412
|
sessionId: input.sessionId,
|
|
@@ -30512,10 +30524,10 @@ async function startDaemon(config) {
|
|
|
30512
30524
|
// 'persona/<pid>/owner',default 走 'default'。
|
|
30513
30525
|
getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
|
|
30514
30526
|
// guest path guard:candidate 必须在 personaRoot 子树下
|
|
30515
|
-
personaRoot:
|
|
30527
|
+
personaRoot: import_node_path32.default.join(config.dataDir, "personas")
|
|
30516
30528
|
},
|
|
30517
30529
|
// workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
|
|
30518
|
-
personaRoot:
|
|
30530
|
+
personaRoot: import_node_path32.default.join(config.dataDir, "personas"),
|
|
30519
30531
|
// capability:list / delete handler 依赖
|
|
30520
30532
|
capabilityManager,
|
|
30521
30533
|
// personal-cap:get 返回的 shareBaseUrl 用此 base URL:
|
|
@@ -30608,6 +30620,7 @@ async function startDaemon(config) {
|
|
|
30608
30620
|
// 形状与 reducer permission_request 分支构造的 session:question 帧一致;UI 不区分
|
|
30609
30621
|
// 首播 vs 重放(last-write-wins,详见 protocol/events.ts JSDoc)。
|
|
30610
30622
|
onSubscribe: (client, sessionId) => {
|
|
30623
|
+
probeEvent("subscribe", { sid: sessionId });
|
|
30611
30624
|
const runner = manager.getActive(sessionId);
|
|
30612
30625
|
if (!runner) return;
|
|
30613
30626
|
const pendingQuestions = runner.getState().pendingQuestions ?? {};
|
|
@@ -30728,8 +30741,8 @@ async function startDaemon(config) {
|
|
|
30728
30741
|
const lines = [
|
|
30729
30742
|
`Tunnel: ${r.url}`,
|
|
30730
30743
|
...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
|
|
30731
|
-
`Frpc config: ${
|
|
30732
|
-
`Frpc log: ${
|
|
30744
|
+
`Frpc config: ${import_node_path32.default.join(config.dataDir, "frpc.toml")}`,
|
|
30745
|
+
`Frpc log: ${import_node_path32.default.join(config.dataDir, "frpc.log")}`
|
|
30733
30746
|
];
|
|
30734
30747
|
const width = Math.max(...lines.map((l) => l.length));
|
|
30735
30748
|
const bar = "\u2550".repeat(width + 4);
|
|
@@ -30742,8 +30755,8 @@ ${bar}
|
|
|
30742
30755
|
|
|
30743
30756
|
`);
|
|
30744
30757
|
try {
|
|
30745
|
-
const connectPath =
|
|
30746
|
-
|
|
30758
|
+
const connectPath = import_node_path32.default.join(config.dataDir, "connect.txt");
|
|
30759
|
+
import_node_fs29.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
|
|
30747
30760
|
} catch {
|
|
30748
30761
|
}
|
|
30749
30762
|
} catch (err) {
|
|
@@ -30808,9 +30821,9 @@ ${bar}
|
|
|
30808
30821
|
};
|
|
30809
30822
|
}
|
|
30810
30823
|
function migrateDropPersonsDir(dataDir) {
|
|
30811
|
-
const dir =
|
|
30824
|
+
const dir = import_node_path32.default.join(dataDir, "persons");
|
|
30812
30825
|
try {
|
|
30813
|
-
|
|
30826
|
+
import_node_fs29.default.rmSync(dir, { recursive: true, force: true });
|
|
30814
30827
|
} catch {
|
|
30815
30828
|
}
|
|
30816
30829
|
}
|