@clawos-dev/clawd 0.2.143-beta.300.c2a3792 → 0.2.143-beta.302.5df5cc1
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 +1632 -824
- package/dist/deploy-kit/.secrets/aliyun.env.example +4 -0
- package/dist/deploy-kit/scripts/new-extension.sh +22 -0
- package/dist/deploy-kit/scripts/publish.sh +100 -0
- package/dist/deploy-kit/scripts/publish.spec.ts +69 -0
- package/dist/{persona-defaults/persona-app-builder/extension-kit → deploy-kit}/scripts/remove-extension.sh +15 -26
- package/dist/dispatch/mcp-server.cjs +39756 -0
- package/dist/persona-defaults/persona-app-builder/CLAUDE.md +16 -13
- package/dist/persona-defaults/persona-app-builder/extension-kit/README.md +24 -18
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/ext.conf +5 -0
- package/dist/persona-defaults/persona-bug-fixer/CLAUDE.md +2 -0
- package/dist/persona-defaults/persona-dataclaw-builder/CLAUDE.md +48 -2
- package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/README.md +28 -25
- package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/ext.conf +5 -0
- package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/hooks/pre-deploy.sh +25 -0
- package/dist/persona-defaults/persona-developer/CLAUDE.md +2 -0
- package/package.json +5 -2
- package/dist/persona-defaults/persona-app-builder/extension-kit/scripts/new-extension.sh +0 -66
- package/dist/persona-defaults/persona-app-builder/extension-kit/scripts/publish.sh +0 -110
- package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/contract/bootstrap +0 -22
- package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/scripts/ensure-toolchain.sh +0 -62
- package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/scripts/new-extension.sh +0 -66
- package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/scripts/publish.sh +0 -129
- package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/scripts/remove-extension.sh +0 -70
- package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/scripts/verify.sh +0 -38
- /package/dist/{persona-defaults/persona-app-builder → deploy-kit}/.secrets/aliyun.env +0 -0
- /package/dist/{persona-defaults/persona-app-builder/extension-kit → deploy-kit}/contract/bootstrap +0 -0
- /package/dist/{persona-defaults/persona-app-builder/extension-kit → deploy-kit}/scripts/ensure-toolchain.sh +0 -0
- /package/dist/{persona-defaults/persona-app-builder/extension-kit → deploy-kit}/scripts/verify.sh +0 -0
package/dist/cli.cjs
CHANGED
|
@@ -720,8 +720,8 @@ var init_parseUtil = __esm({
|
|
|
720
720
|
init_errors2();
|
|
721
721
|
init_en();
|
|
722
722
|
makeIssue = (params) => {
|
|
723
|
-
const { data, path:
|
|
724
|
-
const fullPath = [...
|
|
723
|
+
const { data, path: path59, errorMaps, issueData } = params;
|
|
724
|
+
const fullPath = [...path59, ...issueData.path || []];
|
|
725
725
|
const fullIssue = {
|
|
726
726
|
...issueData,
|
|
727
727
|
path: fullPath
|
|
@@ -1032,11 +1032,11 @@ var init_types = __esm({
|
|
|
1032
1032
|
init_parseUtil();
|
|
1033
1033
|
init_util();
|
|
1034
1034
|
ParseInputLazyPath = class {
|
|
1035
|
-
constructor(parent, value,
|
|
1035
|
+
constructor(parent, value, path59, key) {
|
|
1036
1036
|
this._cachedPath = [];
|
|
1037
1037
|
this.parent = parent;
|
|
1038
1038
|
this.data = value;
|
|
1039
|
-
this._path =
|
|
1039
|
+
this._path = path59;
|
|
1040
1040
|
this._key = key;
|
|
1041
1041
|
}
|
|
1042
1042
|
get path() {
|
|
@@ -4752,6 +4752,13 @@ var init_schemas = __esm({
|
|
|
4752
4752
|
* - native `session:*` handler 完全不感知 mirror(UI 操作 mirror 不走 native 路径)
|
|
4753
4753
|
*/
|
|
4754
4754
|
originOwnerPrincipalId: external_exports.string().min(1).optional(),
|
|
4755
|
+
/**
|
|
4756
|
+
* Dispatch 派生的 session 在 create 时记录源 session 的 sessionId(稳定 key);
|
|
4757
|
+
* sidebar 据此把 dispatch 出来的 sub-session 折叠在源 session 下。非 dispatch session 缺省。
|
|
4758
|
+
* mirror SessionFile 上必须 strip(朋友 daemon 上的 sessionId 在本机无意义,会让本机
|
|
4759
|
+
* 反查路径走错;按 #750 一族防线处理,跟 ownerPersonaId 同地点 strip)。
|
|
4760
|
+
*/
|
|
4761
|
+
dispatchedFromSessionId: external_exports.string().min(1).optional(),
|
|
4755
4762
|
createdAt: external_exports.string().min(1),
|
|
4756
4763
|
updatedAt: external_exports.string().min(1)
|
|
4757
4764
|
});
|
|
@@ -5928,6 +5935,60 @@ var init_feishu_auth = __esm({
|
|
|
5928
5935
|
}
|
|
5929
5936
|
});
|
|
5930
5937
|
|
|
5938
|
+
// ../protocol/src/dispatch.ts
|
|
5939
|
+
var DispatchOutcomeSchema, DispatchRunArgsSchema, DispatchCompleteArgsSchema;
|
|
5940
|
+
var init_dispatch = __esm({
|
|
5941
|
+
"../protocol/src/dispatch.ts"() {
|
|
5942
|
+
"use strict";
|
|
5943
|
+
init_zod();
|
|
5944
|
+
DispatchOutcomeSchema = external_exports.discriminatedUnion("kind", [
|
|
5945
|
+
external_exports.object({
|
|
5946
|
+
kind: external_exports.literal("success"),
|
|
5947
|
+
text: external_exports.string(),
|
|
5948
|
+
filePaths: external_exports.array(external_exports.string()).optional()
|
|
5949
|
+
}),
|
|
5950
|
+
external_exports.object({
|
|
5951
|
+
kind: external_exports.literal("failure"),
|
|
5952
|
+
reason: external_exports.string()
|
|
5953
|
+
})
|
|
5954
|
+
]);
|
|
5955
|
+
DispatchRunArgsSchema = external_exports.object({
|
|
5956
|
+
targetPersona: external_exports.string().min(1),
|
|
5957
|
+
prompt: external_exports.string()
|
|
5958
|
+
});
|
|
5959
|
+
DispatchCompleteArgsSchema = external_exports.object({
|
|
5960
|
+
dispatchId: external_exports.string().min(1),
|
|
5961
|
+
outcome: DispatchOutcomeSchema
|
|
5962
|
+
});
|
|
5963
|
+
}
|
|
5964
|
+
});
|
|
5965
|
+
|
|
5966
|
+
// ../protocol/src/log.ts
|
|
5967
|
+
var LOG_SOURCES, LogSourceSchema, LOG_LEVELS, LogLevelSchema, LogRecordSchema;
|
|
5968
|
+
var init_log = __esm({
|
|
5969
|
+
"../protocol/src/log.ts"() {
|
|
5970
|
+
"use strict";
|
|
5971
|
+
init_zod();
|
|
5972
|
+
LOG_SOURCES = ["daemon", "main", "renderer"];
|
|
5973
|
+
LogSourceSchema = external_exports.enum(LOG_SOURCES);
|
|
5974
|
+
LOG_LEVELS = ["debug", "info", "warn", "error"];
|
|
5975
|
+
LogLevelSchema = external_exports.enum(LOG_LEVELS);
|
|
5976
|
+
LogRecordSchema = external_exports.object({
|
|
5977
|
+
ts: external_exports.number().int(),
|
|
5978
|
+
source: LogSourceSchema,
|
|
5979
|
+
level: LogLevelSchema,
|
|
5980
|
+
msg: external_exports.string(),
|
|
5981
|
+
ownerPrincipalId: external_exports.string(),
|
|
5982
|
+
deviceId: external_exports.string(),
|
|
5983
|
+
appVersion: external_exports.string(),
|
|
5984
|
+
daemonVersion: external_exports.string().optional(),
|
|
5985
|
+
os: external_exports.string(),
|
|
5986
|
+
meta_json: external_exports.string().optional(),
|
|
5987
|
+
sessionId: external_exports.string().optional()
|
|
5988
|
+
});
|
|
5989
|
+
}
|
|
5990
|
+
});
|
|
5991
|
+
|
|
5931
5992
|
// ../protocol/src/runtime.ts
|
|
5932
5993
|
var init_runtime = __esm({
|
|
5933
5994
|
"../protocol/src/runtime.ts"() {
|
|
@@ -5946,6 +6007,8 @@ var init_runtime = __esm({
|
|
|
5946
6007
|
init_contact();
|
|
5947
6008
|
init_extension();
|
|
5948
6009
|
init_feishu_auth();
|
|
6010
|
+
init_dispatch();
|
|
6011
|
+
init_log();
|
|
5949
6012
|
}
|
|
5950
6013
|
});
|
|
5951
6014
|
|
|
@@ -6220,8 +6283,8 @@ var require_req = __commonJS({
|
|
|
6220
6283
|
if (req.originalUrl) {
|
|
6221
6284
|
_req.url = req.originalUrl;
|
|
6222
6285
|
} else {
|
|
6223
|
-
const
|
|
6224
|
-
_req.url = typeof
|
|
6286
|
+
const path59 = req.path;
|
|
6287
|
+
_req.url = typeof path59 === "string" ? path59 : req.url ? req.url.path || req.url : void 0;
|
|
6225
6288
|
}
|
|
6226
6289
|
if (req.query) {
|
|
6227
6290
|
_req.query = req.query;
|
|
@@ -6386,14 +6449,14 @@ var require_redact = __commonJS({
|
|
|
6386
6449
|
}
|
|
6387
6450
|
return obj;
|
|
6388
6451
|
}
|
|
6389
|
-
function parsePath(
|
|
6452
|
+
function parsePath(path59) {
|
|
6390
6453
|
const parts = [];
|
|
6391
6454
|
let current = "";
|
|
6392
6455
|
let inBrackets = false;
|
|
6393
6456
|
let inQuotes = false;
|
|
6394
6457
|
let quoteChar = "";
|
|
6395
|
-
for (let i = 0; i <
|
|
6396
|
-
const char =
|
|
6458
|
+
for (let i = 0; i < path59.length; i++) {
|
|
6459
|
+
const char = path59[i];
|
|
6397
6460
|
if (!inBrackets && char === ".") {
|
|
6398
6461
|
if (current) {
|
|
6399
6462
|
parts.push(current);
|
|
@@ -6524,10 +6587,10 @@ var require_redact = __commonJS({
|
|
|
6524
6587
|
return current;
|
|
6525
6588
|
}
|
|
6526
6589
|
function redactPaths(obj, paths, censor, remove = false) {
|
|
6527
|
-
for (const
|
|
6528
|
-
const parts = parsePath(
|
|
6590
|
+
for (const path59 of paths) {
|
|
6591
|
+
const parts = parsePath(path59);
|
|
6529
6592
|
if (parts.includes("*")) {
|
|
6530
|
-
redactWildcardPath(obj, parts, censor,
|
|
6593
|
+
redactWildcardPath(obj, parts, censor, path59, remove);
|
|
6531
6594
|
} else {
|
|
6532
6595
|
if (remove) {
|
|
6533
6596
|
removeKey(obj, parts);
|
|
@@ -6612,8 +6675,8 @@ var require_redact = __commonJS({
|
|
|
6612
6675
|
}
|
|
6613
6676
|
} else {
|
|
6614
6677
|
if (afterWildcard.includes("*")) {
|
|
6615
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
6616
|
-
const fullPath = [...pathArray.slice(0, pathLength), ...
|
|
6678
|
+
const wrappedCensor = typeof censor === "function" ? (value, path59) => {
|
|
6679
|
+
const fullPath = [...pathArray.slice(0, pathLength), ...path59];
|
|
6617
6680
|
return censor(value, fullPath);
|
|
6618
6681
|
} : censor;
|
|
6619
6682
|
redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
|
|
@@ -6648,8 +6711,8 @@ var require_redact = __commonJS({
|
|
|
6648
6711
|
return null;
|
|
6649
6712
|
}
|
|
6650
6713
|
const pathStructure = /* @__PURE__ */ new Map();
|
|
6651
|
-
for (const
|
|
6652
|
-
const parts = parsePath(
|
|
6714
|
+
for (const path59 of pathsToClone) {
|
|
6715
|
+
const parts = parsePath(path59);
|
|
6653
6716
|
let current = pathStructure;
|
|
6654
6717
|
for (let i = 0; i < parts.length; i++) {
|
|
6655
6718
|
const part = parts[i];
|
|
@@ -6701,24 +6764,24 @@ var require_redact = __commonJS({
|
|
|
6701
6764
|
}
|
|
6702
6765
|
return cloneSelectively(obj, pathStructure);
|
|
6703
6766
|
}
|
|
6704
|
-
function validatePath(
|
|
6705
|
-
if (typeof
|
|
6767
|
+
function validatePath(path59) {
|
|
6768
|
+
if (typeof path59 !== "string") {
|
|
6706
6769
|
throw new Error("Paths must be (non-empty) strings");
|
|
6707
6770
|
}
|
|
6708
|
-
if (
|
|
6771
|
+
if (path59 === "") {
|
|
6709
6772
|
throw new Error("Invalid redaction path ()");
|
|
6710
6773
|
}
|
|
6711
|
-
if (
|
|
6712
|
-
throw new Error(`Invalid redaction path (${
|
|
6774
|
+
if (path59.includes("..")) {
|
|
6775
|
+
throw new Error(`Invalid redaction path (${path59})`);
|
|
6713
6776
|
}
|
|
6714
|
-
if (
|
|
6715
|
-
throw new Error(`Invalid redaction path (${
|
|
6777
|
+
if (path59.includes(",")) {
|
|
6778
|
+
throw new Error(`Invalid redaction path (${path59})`);
|
|
6716
6779
|
}
|
|
6717
6780
|
let bracketCount = 0;
|
|
6718
6781
|
let inQuotes = false;
|
|
6719
6782
|
let quoteChar = "";
|
|
6720
|
-
for (let i = 0; i <
|
|
6721
|
-
const char =
|
|
6783
|
+
for (let i = 0; i < path59.length; i++) {
|
|
6784
|
+
const char = path59[i];
|
|
6722
6785
|
if ((char === '"' || char === "'") && bracketCount > 0) {
|
|
6723
6786
|
if (!inQuotes) {
|
|
6724
6787
|
inQuotes = true;
|
|
@@ -6732,20 +6795,20 @@ var require_redact = __commonJS({
|
|
|
6732
6795
|
} else if (char === "]" && !inQuotes) {
|
|
6733
6796
|
bracketCount--;
|
|
6734
6797
|
if (bracketCount < 0) {
|
|
6735
|
-
throw new Error(`Invalid redaction path (${
|
|
6798
|
+
throw new Error(`Invalid redaction path (${path59})`);
|
|
6736
6799
|
}
|
|
6737
6800
|
}
|
|
6738
6801
|
}
|
|
6739
6802
|
if (bracketCount !== 0) {
|
|
6740
|
-
throw new Error(`Invalid redaction path (${
|
|
6803
|
+
throw new Error(`Invalid redaction path (${path59})`);
|
|
6741
6804
|
}
|
|
6742
6805
|
}
|
|
6743
6806
|
function validatePaths(paths) {
|
|
6744
6807
|
if (!Array.isArray(paths)) {
|
|
6745
6808
|
throw new TypeError("paths must be an array");
|
|
6746
6809
|
}
|
|
6747
|
-
for (const
|
|
6748
|
-
validatePath(
|
|
6810
|
+
for (const path59 of paths) {
|
|
6811
|
+
validatePath(path59);
|
|
6749
6812
|
}
|
|
6750
6813
|
}
|
|
6751
6814
|
function slowRedact(options = {}) {
|
|
@@ -6913,8 +6976,8 @@ var require_redaction = __commonJS({
|
|
|
6913
6976
|
if (shape[k2] === null) {
|
|
6914
6977
|
o[k2] = (value) => topCensor(value, [k2]);
|
|
6915
6978
|
} else {
|
|
6916
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
6917
|
-
return censor(value, [k2, ...
|
|
6979
|
+
const wrappedCensor = typeof censor === "function" ? (value, path59) => {
|
|
6980
|
+
return censor(value, [k2, ...path59]);
|
|
6918
6981
|
} : censor;
|
|
6919
6982
|
o[k2] = Redact({
|
|
6920
6983
|
paths: shape[k2],
|
|
@@ -7098,7 +7161,7 @@ var require_atomic_sleep = __commonJS({
|
|
|
7098
7161
|
"../node_modules/.pnpm/atomic-sleep@1.0.0/node_modules/atomic-sleep/index.js"(exports2, module2) {
|
|
7099
7162
|
"use strict";
|
|
7100
7163
|
if (typeof SharedArrayBuffer !== "undefined" && typeof Atomics !== "undefined") {
|
|
7101
|
-
let
|
|
7164
|
+
let sleep2 = function(ms) {
|
|
7102
7165
|
const valid = ms > 0 && ms < Infinity;
|
|
7103
7166
|
if (valid === false) {
|
|
7104
7167
|
if (typeof ms !== "number" && typeof ms !== "bigint") {
|
|
@@ -7109,9 +7172,9 @@ var require_atomic_sleep = __commonJS({
|
|
|
7109
7172
|
Atomics.wait(nil, 0, 0, Number(ms));
|
|
7110
7173
|
};
|
|
7111
7174
|
const nil = new Int32Array(new SharedArrayBuffer(4));
|
|
7112
|
-
module2.exports =
|
|
7175
|
+
module2.exports = sleep2;
|
|
7113
7176
|
} else {
|
|
7114
|
-
let
|
|
7177
|
+
let sleep2 = function(ms) {
|
|
7115
7178
|
const valid = ms > 0 && ms < Infinity;
|
|
7116
7179
|
if (valid === false) {
|
|
7117
7180
|
if (typeof ms !== "number" && typeof ms !== "bigint") {
|
|
@@ -7123,7 +7186,7 @@ var require_atomic_sleep = __commonJS({
|
|
|
7123
7186
|
while (target > Date.now()) {
|
|
7124
7187
|
}
|
|
7125
7188
|
};
|
|
7126
|
-
module2.exports =
|
|
7189
|
+
module2.exports = sleep2;
|
|
7127
7190
|
}
|
|
7128
7191
|
}
|
|
7129
7192
|
});
|
|
@@ -7132,11 +7195,11 @@ var require_atomic_sleep = __commonJS({
|
|
|
7132
7195
|
var require_sonic_boom = __commonJS({
|
|
7133
7196
|
"../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
|
|
7134
7197
|
"use strict";
|
|
7135
|
-
var
|
|
7198
|
+
var fs52 = require("fs");
|
|
7136
7199
|
var EventEmitter3 = require("events");
|
|
7137
7200
|
var inherits = require("util").inherits;
|
|
7138
|
-
var
|
|
7139
|
-
var
|
|
7201
|
+
var path59 = require("path");
|
|
7202
|
+
var sleep2 = require_atomic_sleep();
|
|
7140
7203
|
var assert = require("assert");
|
|
7141
7204
|
var BUSY_WRITE_TIMEOUT = 100;
|
|
7142
7205
|
var kEmptyBuffer = Buffer.allocUnsafe(0);
|
|
@@ -7189,20 +7252,20 @@ var require_sonic_boom = __commonJS({
|
|
|
7189
7252
|
const mode = sonic.mode;
|
|
7190
7253
|
if (sonic.sync) {
|
|
7191
7254
|
try {
|
|
7192
|
-
if (sonic.mkdir)
|
|
7193
|
-
const fd =
|
|
7255
|
+
if (sonic.mkdir) fs52.mkdirSync(path59.dirname(file), { recursive: true });
|
|
7256
|
+
const fd = fs52.openSync(file, flags, mode);
|
|
7194
7257
|
fileOpened(null, fd);
|
|
7195
7258
|
} catch (err) {
|
|
7196
7259
|
fileOpened(err);
|
|
7197
7260
|
throw err;
|
|
7198
7261
|
}
|
|
7199
7262
|
} else if (sonic.mkdir) {
|
|
7200
|
-
|
|
7263
|
+
fs52.mkdir(path59.dirname(file), { recursive: true }, (err) => {
|
|
7201
7264
|
if (err) return fileOpened(err);
|
|
7202
|
-
|
|
7265
|
+
fs52.open(file, flags, mode, fileOpened);
|
|
7203
7266
|
});
|
|
7204
7267
|
} else {
|
|
7205
|
-
|
|
7268
|
+
fs52.open(file, flags, mode, fileOpened);
|
|
7206
7269
|
}
|
|
7207
7270
|
}
|
|
7208
7271
|
function SonicBoom(opts) {
|
|
@@ -7243,8 +7306,8 @@ var require_sonic_boom = __commonJS({
|
|
|
7243
7306
|
this.flush = flushBuffer;
|
|
7244
7307
|
this.flushSync = flushBufferSync;
|
|
7245
7308
|
this._actualWrite = actualWriteBuffer;
|
|
7246
|
-
fsWriteSync = () =>
|
|
7247
|
-
fsWrite = () =>
|
|
7309
|
+
fsWriteSync = () => fs52.writeSync(this.fd, this._writingBuf);
|
|
7310
|
+
fsWrite = () => fs52.write(this.fd, this._writingBuf, this.release);
|
|
7248
7311
|
} else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
|
|
7249
7312
|
this._writingBuf = "";
|
|
7250
7313
|
this.write = write;
|
|
@@ -7253,15 +7316,15 @@ var require_sonic_boom = __commonJS({
|
|
|
7253
7316
|
this._actualWrite = actualWrite;
|
|
7254
7317
|
fsWriteSync = () => {
|
|
7255
7318
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
7256
|
-
return
|
|
7319
|
+
return fs52.writeSync(this.fd, this._writingBuf);
|
|
7257
7320
|
}
|
|
7258
|
-
return
|
|
7321
|
+
return fs52.writeSync(this.fd, this._writingBuf, "utf8");
|
|
7259
7322
|
};
|
|
7260
7323
|
fsWrite = () => {
|
|
7261
7324
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
7262
|
-
return
|
|
7325
|
+
return fs52.write(this.fd, this._writingBuf, this.release);
|
|
7263
7326
|
}
|
|
7264
|
-
return
|
|
7327
|
+
return fs52.write(this.fd, this._writingBuf, "utf8", this.release);
|
|
7265
7328
|
};
|
|
7266
7329
|
} else {
|
|
7267
7330
|
throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
|
|
@@ -7282,7 +7345,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7282
7345
|
if ((err.code === "EAGAIN" || err.code === "EBUSY") && this.retryEAGAIN(err, this._writingBuf.length, this._len - this._writingBuf.length)) {
|
|
7283
7346
|
if (this.sync) {
|
|
7284
7347
|
try {
|
|
7285
|
-
|
|
7348
|
+
sleep2(BUSY_WRITE_TIMEOUT);
|
|
7286
7349
|
this.release(void 0, 0);
|
|
7287
7350
|
} catch (err2) {
|
|
7288
7351
|
this.release(err2);
|
|
@@ -7318,7 +7381,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7318
7381
|
}
|
|
7319
7382
|
}
|
|
7320
7383
|
if (this._fsync) {
|
|
7321
|
-
|
|
7384
|
+
fs52.fsyncSync(this.fd);
|
|
7322
7385
|
}
|
|
7323
7386
|
const len = this._len;
|
|
7324
7387
|
if (this._reopening) {
|
|
@@ -7432,7 +7495,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7432
7495
|
const onDrain = () => {
|
|
7433
7496
|
if (!this._fsync) {
|
|
7434
7497
|
try {
|
|
7435
|
-
|
|
7498
|
+
fs52.fsync(this.fd, (err) => {
|
|
7436
7499
|
this._flushPending = false;
|
|
7437
7500
|
cb(err);
|
|
7438
7501
|
});
|
|
@@ -7534,7 +7597,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7534
7597
|
const fd = this.fd;
|
|
7535
7598
|
this.once("ready", () => {
|
|
7536
7599
|
if (fd !== this.fd) {
|
|
7537
|
-
|
|
7600
|
+
fs52.close(fd, (err) => {
|
|
7538
7601
|
if (err) {
|
|
7539
7602
|
return this.emit("error", err);
|
|
7540
7603
|
}
|
|
@@ -7583,7 +7646,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7583
7646
|
buf = this._bufs[0];
|
|
7584
7647
|
}
|
|
7585
7648
|
try {
|
|
7586
|
-
const n = Buffer.isBuffer(buf) ?
|
|
7649
|
+
const n = Buffer.isBuffer(buf) ? fs52.writeSync(this.fd, buf) : fs52.writeSync(this.fd, buf, "utf8");
|
|
7587
7650
|
const releasedBufObj = releaseWritingBuf(buf, this._len, n);
|
|
7588
7651
|
buf = releasedBufObj.writingBuf;
|
|
7589
7652
|
this._len = releasedBufObj.len;
|
|
@@ -7595,11 +7658,11 @@ var require_sonic_boom = __commonJS({
|
|
|
7595
7658
|
if (shouldRetry && !this.retryEAGAIN(err, buf.length, this._len - buf.length)) {
|
|
7596
7659
|
throw err;
|
|
7597
7660
|
}
|
|
7598
|
-
|
|
7661
|
+
sleep2(BUSY_WRITE_TIMEOUT);
|
|
7599
7662
|
}
|
|
7600
7663
|
}
|
|
7601
7664
|
try {
|
|
7602
|
-
|
|
7665
|
+
fs52.fsyncSync(this.fd);
|
|
7603
7666
|
} catch {
|
|
7604
7667
|
}
|
|
7605
7668
|
}
|
|
@@ -7620,7 +7683,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7620
7683
|
buf = mergeBuf(this._bufs[0], this._lens[0]);
|
|
7621
7684
|
}
|
|
7622
7685
|
try {
|
|
7623
|
-
const n =
|
|
7686
|
+
const n = fs52.writeSync(this.fd, buf);
|
|
7624
7687
|
buf = buf.subarray(n);
|
|
7625
7688
|
this._len = Math.max(this._len - n, 0);
|
|
7626
7689
|
if (buf.length <= 0) {
|
|
@@ -7632,7 +7695,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7632
7695
|
if (shouldRetry && !this.retryEAGAIN(err, buf.length, this._len - buf.length)) {
|
|
7633
7696
|
throw err;
|
|
7634
7697
|
}
|
|
7635
|
-
|
|
7698
|
+
sleep2(BUSY_WRITE_TIMEOUT);
|
|
7636
7699
|
}
|
|
7637
7700
|
}
|
|
7638
7701
|
}
|
|
@@ -7648,13 +7711,13 @@ var require_sonic_boom = __commonJS({
|
|
|
7648
7711
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
|
|
7649
7712
|
if (this.sync) {
|
|
7650
7713
|
try {
|
|
7651
|
-
const written = Buffer.isBuffer(this._writingBuf) ?
|
|
7714
|
+
const written = Buffer.isBuffer(this._writingBuf) ? fs52.writeSync(this.fd, this._writingBuf) : fs52.writeSync(this.fd, this._writingBuf, "utf8");
|
|
7652
7715
|
release(null, written);
|
|
7653
7716
|
} catch (err) {
|
|
7654
7717
|
release(err);
|
|
7655
7718
|
}
|
|
7656
7719
|
} else {
|
|
7657
|
-
|
|
7720
|
+
fs52.write(this.fd, this._writingBuf, release);
|
|
7658
7721
|
}
|
|
7659
7722
|
}
|
|
7660
7723
|
function actualWriteBuffer() {
|
|
@@ -7663,7 +7726,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7663
7726
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
|
|
7664
7727
|
if (this.sync) {
|
|
7665
7728
|
try {
|
|
7666
|
-
const written =
|
|
7729
|
+
const written = fs52.writeSync(this.fd, this._writingBuf);
|
|
7667
7730
|
release(null, written);
|
|
7668
7731
|
} catch (err) {
|
|
7669
7732
|
release(err);
|
|
@@ -7672,7 +7735,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7672
7735
|
if (kCopyBuffer) {
|
|
7673
7736
|
this._writingBuf = Buffer.from(this._writingBuf);
|
|
7674
7737
|
}
|
|
7675
|
-
|
|
7738
|
+
fs52.write(this.fd, this._writingBuf, release);
|
|
7676
7739
|
}
|
|
7677
7740
|
}
|
|
7678
7741
|
function actualClose(sonic) {
|
|
@@ -7688,12 +7751,12 @@ var require_sonic_boom = __commonJS({
|
|
|
7688
7751
|
sonic._lens = [];
|
|
7689
7752
|
assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
|
|
7690
7753
|
try {
|
|
7691
|
-
|
|
7754
|
+
fs52.fsync(sonic.fd, closeWrapped);
|
|
7692
7755
|
} catch {
|
|
7693
7756
|
}
|
|
7694
7757
|
function closeWrapped() {
|
|
7695
7758
|
if (sonic.fd !== 1 && sonic.fd !== 2) {
|
|
7696
|
-
|
|
7759
|
+
fs52.close(sonic.fd, done);
|
|
7697
7760
|
} else {
|
|
7698
7761
|
done();
|
|
7699
7762
|
}
|
|
@@ -8373,7 +8436,7 @@ var require_transport = __commonJS({
|
|
|
8373
8436
|
var { createRequire } = require("module");
|
|
8374
8437
|
var getCallers = require_caller();
|
|
8375
8438
|
var { join: join15, isAbsolute: isAbsolute2, sep: sep2 } = require("path");
|
|
8376
|
-
var
|
|
8439
|
+
var sleep2 = require_atomic_sleep();
|
|
8377
8440
|
var onExit = require_on_exit_leak_free();
|
|
8378
8441
|
var ThreadStream = require_thread_stream();
|
|
8379
8442
|
function setupOnExit(stream) {
|
|
@@ -8407,7 +8470,7 @@ var require_transport = __commonJS({
|
|
|
8407
8470
|
return;
|
|
8408
8471
|
}
|
|
8409
8472
|
stream.flushSync();
|
|
8410
|
-
|
|
8473
|
+
sleep2(100);
|
|
8411
8474
|
stream.end();
|
|
8412
8475
|
}
|
|
8413
8476
|
return stream;
|
|
@@ -10057,7 +10120,7 @@ var require_multistream = __commonJS({
|
|
|
10057
10120
|
var require_pino = __commonJS({
|
|
10058
10121
|
"../node_modules/.pnpm/pino@9.14.0/node_modules/pino/pino.js"(exports2, module2) {
|
|
10059
10122
|
"use strict";
|
|
10060
|
-
var
|
|
10123
|
+
var os22 = require("os");
|
|
10061
10124
|
var stdSerializers = require_pino_std_serializers();
|
|
10062
10125
|
var caller = require_caller();
|
|
10063
10126
|
var redaction = require_redaction();
|
|
@@ -10104,7 +10167,7 @@ var require_pino = __commonJS({
|
|
|
10104
10167
|
} = symbols;
|
|
10105
10168
|
var { epochTime, nullTime } = time;
|
|
10106
10169
|
var { pid } = process;
|
|
10107
|
-
var hostname =
|
|
10170
|
+
var hostname = os22.hostname();
|
|
10108
10171
|
var defaultErrorSerializer = stdSerializers.err;
|
|
10109
10172
|
var defaultOptions = {
|
|
10110
10173
|
level: "info",
|
|
@@ -10828,11 +10891,11 @@ var init_lib = __esm({
|
|
|
10828
10891
|
}
|
|
10829
10892
|
}
|
|
10830
10893
|
},
|
|
10831
|
-
addToPath: function addToPath(
|
|
10832
|
-
var last =
|
|
10894
|
+
addToPath: function addToPath(path59, added, removed, oldPosInc, options) {
|
|
10895
|
+
var last = path59.lastComponent;
|
|
10833
10896
|
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
10834
10897
|
return {
|
|
10835
|
-
oldPos:
|
|
10898
|
+
oldPos: path59.oldPos + oldPosInc,
|
|
10836
10899
|
lastComponent: {
|
|
10837
10900
|
count: last.count + 1,
|
|
10838
10901
|
added,
|
|
@@ -10842,7 +10905,7 @@ var init_lib = __esm({
|
|
|
10842
10905
|
};
|
|
10843
10906
|
} else {
|
|
10844
10907
|
return {
|
|
10845
|
-
oldPos:
|
|
10908
|
+
oldPos: path59.oldPos + oldPosInc,
|
|
10846
10909
|
lastComponent: {
|
|
10847
10910
|
count: 1,
|
|
10848
10911
|
added,
|
|
@@ -11288,10 +11351,10 @@ function attachmentToHistoryMessage(o, ts) {
|
|
|
11288
11351
|
const memories = raw.map((m2) => {
|
|
11289
11352
|
if (!m2 || typeof m2 !== "object") return null;
|
|
11290
11353
|
const rec3 = m2;
|
|
11291
|
-
const
|
|
11354
|
+
const path59 = typeof rec3.path === "string" ? rec3.path : null;
|
|
11292
11355
|
const content = typeof rec3.content === "string" ? rec3.content : null;
|
|
11293
|
-
if (!
|
|
11294
|
-
const entry = { path:
|
|
11356
|
+
if (!path59 || content == null) return null;
|
|
11357
|
+
const entry = { path: path59, content };
|
|
11295
11358
|
if (typeof rec3.mtimeMs === "number") entry.mtimeMs = rec3.mtimeMs;
|
|
11296
11359
|
return entry;
|
|
11297
11360
|
}).filter((m2) => m2 !== null);
|
|
@@ -11811,6 +11874,9 @@ function buildSpawnArgs(ctx) {
|
|
|
11811
11874
|
if (ctx.addDirs) {
|
|
11812
11875
|
for (const dir of ctx.addDirs) args.push("--add-dir", dir);
|
|
11813
11876
|
}
|
|
11877
|
+
if (ctx.dispatchMcpConfigPath) {
|
|
11878
|
+
args.push("--mcp-config", ctx.dispatchMcpConfigPath);
|
|
11879
|
+
}
|
|
11814
11880
|
if (ctx.effort) args.push("--effort", ctx.effort);
|
|
11815
11881
|
if (ctx.toolSessionId) args.push("--resume", ctx.toolSessionId);
|
|
11816
11882
|
return args;
|
|
@@ -12090,10 +12156,10 @@ function parseAttachment(obj) {
|
|
|
12090
12156
|
const memories = raw.map((m2) => {
|
|
12091
12157
|
if (!m2 || typeof m2 !== "object") return null;
|
|
12092
12158
|
const rec3 = m2;
|
|
12093
|
-
const
|
|
12159
|
+
const path59 = typeof rec3.path === "string" ? rec3.path : null;
|
|
12094
12160
|
const content = typeof rec3.content === "string" ? rec3.content : null;
|
|
12095
|
-
if (!
|
|
12096
|
-
const out = { path:
|
|
12161
|
+
if (!path59 || content == null) return null;
|
|
12162
|
+
const out = { path: path59, content };
|
|
12097
12163
|
if (typeof rec3.mtimeMs === "number") out.mtimeMs = rec3.mtimeMs;
|
|
12098
12164
|
return out;
|
|
12099
12165
|
}).filter((m2) => m2 !== null);
|
|
@@ -18123,7 +18189,7 @@ var require_validation = __commonJS({
|
|
|
18123
18189
|
var require_receiver = __commonJS({
|
|
18124
18190
|
"../node_modules/.pnpm/ws@8.20.0/node_modules/ws/lib/receiver.js"(exports2, module2) {
|
|
18125
18191
|
"use strict";
|
|
18126
|
-
var { Writable:
|
|
18192
|
+
var { Writable: Writable3 } = require("stream");
|
|
18127
18193
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
18128
18194
|
var {
|
|
18129
18195
|
BINARY_TYPES,
|
|
@@ -18141,7 +18207,7 @@ var require_receiver = __commonJS({
|
|
|
18141
18207
|
var GET_DATA = 4;
|
|
18142
18208
|
var INFLATING = 5;
|
|
18143
18209
|
var DEFER_EVENT = 6;
|
|
18144
|
-
var Receiver2 = class extends
|
|
18210
|
+
var Receiver2 = class extends Writable3 {
|
|
18145
18211
|
/**
|
|
18146
18212
|
* Creates a Receiver instance.
|
|
18147
18213
|
*
|
|
@@ -21404,7 +21470,7 @@ var require_stream_writable = __commonJS({
|
|
|
21404
21470
|
"../node_modules/.pnpm/readable-stream@2.3.8/node_modules/readable-stream/lib/_stream_writable.js"(exports2, module2) {
|
|
21405
21471
|
"use strict";
|
|
21406
21472
|
var pna = require_process_nextick_args();
|
|
21407
|
-
module2.exports =
|
|
21473
|
+
module2.exports = Writable3;
|
|
21408
21474
|
function CorkedRequest(state) {
|
|
21409
21475
|
var _this = this;
|
|
21410
21476
|
this.next = null;
|
|
@@ -21415,7 +21481,7 @@ var require_stream_writable = __commonJS({
|
|
|
21415
21481
|
}
|
|
21416
21482
|
var asyncWrite = !process.browser && ["v0.10", "v0.9."].indexOf(process.version.slice(0, 5)) > -1 ? setImmediate : pna.nextTick;
|
|
21417
21483
|
var Duplex;
|
|
21418
|
-
|
|
21484
|
+
Writable3.WritableState = WritableState;
|
|
21419
21485
|
var util2 = Object.create(require_util());
|
|
21420
21486
|
util2.inherits = require_inherits();
|
|
21421
21487
|
var internalUtil = {
|
|
@@ -21432,7 +21498,7 @@ var require_stream_writable = __commonJS({
|
|
|
21432
21498
|
return Buffer2.isBuffer(obj) || obj instanceof OurUint8Array;
|
|
21433
21499
|
}
|
|
21434
21500
|
var destroyImpl = require_destroy();
|
|
21435
|
-
util2.inherits(
|
|
21501
|
+
util2.inherits(Writable3, Stream);
|
|
21436
21502
|
function nop() {
|
|
21437
21503
|
}
|
|
21438
21504
|
function WritableState(options, stream) {
|
|
@@ -21497,10 +21563,10 @@ var require_stream_writable = __commonJS({
|
|
|
21497
21563
|
var realHasInstance;
|
|
21498
21564
|
if (typeof Symbol === "function" && Symbol.hasInstance && typeof Function.prototype[Symbol.hasInstance] === "function") {
|
|
21499
21565
|
realHasInstance = Function.prototype[Symbol.hasInstance];
|
|
21500
|
-
Object.defineProperty(
|
|
21566
|
+
Object.defineProperty(Writable3, Symbol.hasInstance, {
|
|
21501
21567
|
value: function(object) {
|
|
21502
21568
|
if (realHasInstance.call(this, object)) return true;
|
|
21503
|
-
if (this !==
|
|
21569
|
+
if (this !== Writable3) return false;
|
|
21504
21570
|
return object && object._writableState instanceof WritableState;
|
|
21505
21571
|
}
|
|
21506
21572
|
});
|
|
@@ -21509,10 +21575,10 @@ var require_stream_writable = __commonJS({
|
|
|
21509
21575
|
return object instanceof this;
|
|
21510
21576
|
};
|
|
21511
21577
|
}
|
|
21512
|
-
function
|
|
21578
|
+
function Writable3(options) {
|
|
21513
21579
|
Duplex = Duplex || require_stream_duplex();
|
|
21514
|
-
if (!realHasInstance.call(
|
|
21515
|
-
return new
|
|
21580
|
+
if (!realHasInstance.call(Writable3, this) && !(this instanceof Duplex)) {
|
|
21581
|
+
return new Writable3(options);
|
|
21516
21582
|
}
|
|
21517
21583
|
this._writableState = new WritableState(options, this);
|
|
21518
21584
|
this.writable = true;
|
|
@@ -21524,7 +21590,7 @@ var require_stream_writable = __commonJS({
|
|
|
21524
21590
|
}
|
|
21525
21591
|
Stream.call(this);
|
|
21526
21592
|
}
|
|
21527
|
-
|
|
21593
|
+
Writable3.prototype.pipe = function() {
|
|
21528
21594
|
this.emit("error", new Error("Cannot pipe, not readable"));
|
|
21529
21595
|
};
|
|
21530
21596
|
function writeAfterEnd(stream, cb) {
|
|
@@ -21547,7 +21613,7 @@ var require_stream_writable = __commonJS({
|
|
|
21547
21613
|
}
|
|
21548
21614
|
return valid;
|
|
21549
21615
|
}
|
|
21550
|
-
|
|
21616
|
+
Writable3.prototype.write = function(chunk, encoding, cb) {
|
|
21551
21617
|
var state = this._writableState;
|
|
21552
21618
|
var ret = false;
|
|
21553
21619
|
var isBuf = !state.objectMode && _isUint8Array(chunk);
|
|
@@ -21568,18 +21634,18 @@ var require_stream_writable = __commonJS({
|
|
|
21568
21634
|
}
|
|
21569
21635
|
return ret;
|
|
21570
21636
|
};
|
|
21571
|
-
|
|
21637
|
+
Writable3.prototype.cork = function() {
|
|
21572
21638
|
var state = this._writableState;
|
|
21573
21639
|
state.corked++;
|
|
21574
21640
|
};
|
|
21575
|
-
|
|
21641
|
+
Writable3.prototype.uncork = function() {
|
|
21576
21642
|
var state = this._writableState;
|
|
21577
21643
|
if (state.corked) {
|
|
21578
21644
|
state.corked--;
|
|
21579
21645
|
if (!state.writing && !state.corked && !state.bufferProcessing && state.bufferedRequest) clearBuffer(this, state);
|
|
21580
21646
|
}
|
|
21581
21647
|
};
|
|
21582
|
-
|
|
21648
|
+
Writable3.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) {
|
|
21583
21649
|
if (typeof encoding === "string") encoding = encoding.toLowerCase();
|
|
21584
21650
|
if (!(["hex", "utf8", "utf-8", "ascii", "binary", "base64", "ucs2", "ucs-2", "utf16le", "utf-16le", "raw"].indexOf((encoding + "").toLowerCase()) > -1)) throw new TypeError("Unknown encoding: " + encoding);
|
|
21585
21651
|
this._writableState.defaultEncoding = encoding;
|
|
@@ -21591,7 +21657,7 @@ var require_stream_writable = __commonJS({
|
|
|
21591
21657
|
}
|
|
21592
21658
|
return chunk;
|
|
21593
21659
|
}
|
|
21594
|
-
Object.defineProperty(
|
|
21660
|
+
Object.defineProperty(Writable3.prototype, "writableHighWaterMark", {
|
|
21595
21661
|
// making it explicit this property is not enumerable
|
|
21596
21662
|
// because otherwise some prototype manipulation in
|
|
21597
21663
|
// userland will fail
|
|
@@ -21737,11 +21803,11 @@ var require_stream_writable = __commonJS({
|
|
|
21737
21803
|
state.bufferedRequest = entry;
|
|
21738
21804
|
state.bufferProcessing = false;
|
|
21739
21805
|
}
|
|
21740
|
-
|
|
21806
|
+
Writable3.prototype._write = function(chunk, encoding, cb) {
|
|
21741
21807
|
cb(new Error("_write() is not implemented"));
|
|
21742
21808
|
};
|
|
21743
|
-
|
|
21744
|
-
|
|
21809
|
+
Writable3.prototype._writev = null;
|
|
21810
|
+
Writable3.prototype.end = function(chunk, encoding, cb) {
|
|
21745
21811
|
var state = this._writableState;
|
|
21746
21812
|
if (typeof chunk === "function") {
|
|
21747
21813
|
cb = chunk;
|
|
@@ -21816,7 +21882,7 @@ var require_stream_writable = __commonJS({
|
|
|
21816
21882
|
}
|
|
21817
21883
|
state.corkedRequestsFree.next = corkReq;
|
|
21818
21884
|
}
|
|
21819
|
-
Object.defineProperty(
|
|
21885
|
+
Object.defineProperty(Writable3.prototype, "destroyed", {
|
|
21820
21886
|
get: function() {
|
|
21821
21887
|
if (this._writableState === void 0) {
|
|
21822
21888
|
return false;
|
|
@@ -21830,9 +21896,9 @@ var require_stream_writable = __commonJS({
|
|
|
21830
21896
|
this._writableState.destroyed = value;
|
|
21831
21897
|
}
|
|
21832
21898
|
});
|
|
21833
|
-
|
|
21834
|
-
|
|
21835
|
-
|
|
21899
|
+
Writable3.prototype.destroy = destroyImpl.destroy;
|
|
21900
|
+
Writable3.prototype._undestroy = destroyImpl.undestroy;
|
|
21901
|
+
Writable3.prototype._destroy = function(err, cb) {
|
|
21836
21902
|
this.end();
|
|
21837
21903
|
cb(err);
|
|
21838
21904
|
};
|
|
@@ -21855,13 +21921,13 @@ var require_stream_duplex = __commonJS({
|
|
|
21855
21921
|
var util2 = Object.create(require_util());
|
|
21856
21922
|
util2.inherits = require_inherits();
|
|
21857
21923
|
var Readable3 = require_stream_readable();
|
|
21858
|
-
var
|
|
21924
|
+
var Writable3 = require_stream_writable();
|
|
21859
21925
|
util2.inherits(Duplex, Readable3);
|
|
21860
21926
|
{
|
|
21861
|
-
keys = objectKeys(
|
|
21927
|
+
keys = objectKeys(Writable3.prototype);
|
|
21862
21928
|
for (v2 = 0; v2 < keys.length; v2++) {
|
|
21863
21929
|
method = keys[v2];
|
|
21864
|
-
if (!Duplex.prototype[method]) Duplex.prototype[method] =
|
|
21930
|
+
if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable3.prototype[method];
|
|
21865
21931
|
}
|
|
21866
21932
|
}
|
|
21867
21933
|
var keys;
|
|
@@ -21870,7 +21936,7 @@ var require_stream_duplex = __commonJS({
|
|
|
21870
21936
|
function Duplex(options) {
|
|
21871
21937
|
if (!(this instanceof Duplex)) return new Duplex(options);
|
|
21872
21938
|
Readable3.call(this, options);
|
|
21873
|
-
|
|
21939
|
+
Writable3.call(this, options);
|
|
21874
21940
|
if (options && options.readable === false) this.readable = false;
|
|
21875
21941
|
if (options && options.writable === false) this.writable = false;
|
|
21876
21942
|
this.allowHalfOpen = true;
|
|
@@ -23880,8 +23946,8 @@ var require_utils = __commonJS({
|
|
|
23880
23946
|
var result = transform[inputType][outputType](input);
|
|
23881
23947
|
return result;
|
|
23882
23948
|
};
|
|
23883
|
-
exports2.resolve = function(
|
|
23884
|
-
var parts =
|
|
23949
|
+
exports2.resolve = function(path59) {
|
|
23950
|
+
var parts = path59.split("/");
|
|
23885
23951
|
var result = [];
|
|
23886
23952
|
for (var index = 0; index < parts.length; index++) {
|
|
23887
23953
|
var part = parts[index];
|
|
@@ -29734,18 +29800,18 @@ var require_object = __commonJS({
|
|
|
29734
29800
|
var object = new ZipObject(name, zipObjectContent, o);
|
|
29735
29801
|
this.files[name] = object;
|
|
29736
29802
|
};
|
|
29737
|
-
var parentFolder = function(
|
|
29738
|
-
if (
|
|
29739
|
-
|
|
29803
|
+
var parentFolder = function(path59) {
|
|
29804
|
+
if (path59.slice(-1) === "/") {
|
|
29805
|
+
path59 = path59.substring(0, path59.length - 1);
|
|
29740
29806
|
}
|
|
29741
|
-
var lastSlash =
|
|
29742
|
-
return lastSlash > 0 ?
|
|
29807
|
+
var lastSlash = path59.lastIndexOf("/");
|
|
29808
|
+
return lastSlash > 0 ? path59.substring(0, lastSlash) : "";
|
|
29743
29809
|
};
|
|
29744
|
-
var forceTrailingSlash = function(
|
|
29745
|
-
if (
|
|
29746
|
-
|
|
29810
|
+
var forceTrailingSlash = function(path59) {
|
|
29811
|
+
if (path59.slice(-1) !== "/") {
|
|
29812
|
+
path59 += "/";
|
|
29747
29813
|
}
|
|
29748
|
-
return
|
|
29814
|
+
return path59;
|
|
29749
29815
|
};
|
|
29750
29816
|
var folderAdd = function(name, createFolders) {
|
|
29751
29817
|
createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
|
|
@@ -30747,7 +30813,7 @@ var require_lib3 = __commonJS({
|
|
|
30747
30813
|
// src/run-case/recorder.ts
|
|
30748
30814
|
function startRunCaseRecorder(opts) {
|
|
30749
30815
|
const now = opts.now ?? Date.now;
|
|
30750
|
-
const dir =
|
|
30816
|
+
const dir = import_node_path47.default.dirname(opts.recordPath);
|
|
30751
30817
|
let stream = null;
|
|
30752
30818
|
let closing = false;
|
|
30753
30819
|
let closedSettled = false;
|
|
@@ -30761,8 +30827,8 @@ function startRunCaseRecorder(opts) {
|
|
|
30761
30827
|
});
|
|
30762
30828
|
const ensureStream = () => {
|
|
30763
30829
|
if (stream) return stream;
|
|
30764
|
-
|
|
30765
|
-
stream =
|
|
30830
|
+
import_node_fs35.default.mkdirSync(dir, { recursive: true });
|
|
30831
|
+
stream = import_node_fs35.default.createWriteStream(opts.recordPath, { flags: "a" });
|
|
30766
30832
|
stream.on("close", () => closedResolve());
|
|
30767
30833
|
return stream;
|
|
30768
30834
|
};
|
|
@@ -30787,12 +30853,12 @@ function startRunCaseRecorder(opts) {
|
|
|
30787
30853
|
};
|
|
30788
30854
|
return { tap, close, closed };
|
|
30789
30855
|
}
|
|
30790
|
-
var
|
|
30856
|
+
var import_node_fs35, import_node_path47;
|
|
30791
30857
|
var init_recorder = __esm({
|
|
30792
30858
|
"src/run-case/recorder.ts"() {
|
|
30793
30859
|
"use strict";
|
|
30794
|
-
|
|
30795
|
-
|
|
30860
|
+
import_node_fs35 = __toESM(require("fs"), 1);
|
|
30861
|
+
import_node_path47 = __toESM(require("path"), 1);
|
|
30796
30862
|
}
|
|
30797
30863
|
});
|
|
30798
30864
|
|
|
@@ -30835,7 +30901,7 @@ var init_wire = __esm({
|
|
|
30835
30901
|
// src/run-case/controller.ts
|
|
30836
30902
|
async function runController(opts) {
|
|
30837
30903
|
const now = opts.now ?? Date.now;
|
|
30838
|
-
const cwd = opts.cwd ?? (0,
|
|
30904
|
+
const cwd = opts.cwd ?? (0, import_node_fs36.mkdtempSync)(import_node_path48.default.join(import_node_os20.default.tmpdir(), "clawd-runcase-"));
|
|
30839
30905
|
const ownsCwd = opts.cwd === void 0;
|
|
30840
30906
|
const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
|
|
30841
30907
|
const spawnCtx = { cwd };
|
|
@@ -30996,19 +31062,19 @@ async function runController(opts) {
|
|
|
30996
31062
|
if (sigintHandler) process.off("SIGINT", sigintHandler);
|
|
30997
31063
|
if (ownsCwd) {
|
|
30998
31064
|
try {
|
|
30999
|
-
(0,
|
|
31065
|
+
(0, import_node_fs36.rmSync)(cwd, { recursive: true, force: true });
|
|
31000
31066
|
} catch {
|
|
31001
31067
|
}
|
|
31002
31068
|
}
|
|
31003
31069
|
return exitCode ?? 0;
|
|
31004
31070
|
}
|
|
31005
|
-
var
|
|
31071
|
+
var import_node_fs36, import_node_os20, import_node_path48;
|
|
31006
31072
|
var init_controller = __esm({
|
|
31007
31073
|
"src/run-case/controller.ts"() {
|
|
31008
31074
|
"use strict";
|
|
31009
|
-
|
|
31010
|
-
|
|
31011
|
-
|
|
31075
|
+
import_node_fs36 = require("fs");
|
|
31076
|
+
import_node_os20 = __toESM(require("os"), 1);
|
|
31077
|
+
import_node_path48 = __toESM(require("path"), 1);
|
|
31012
31078
|
init_claude();
|
|
31013
31079
|
init_stdout_splitter();
|
|
31014
31080
|
init_permission_stdio();
|
|
@@ -31112,6 +31178,24 @@ init_protocol();
|
|
|
31112
31178
|
var DEFAULT_PORT = 18790;
|
|
31113
31179
|
var DEFAULT_HOST = "127.0.0.1";
|
|
31114
31180
|
var DEFAULT_CLAWOS_API = "https://api.clawos.chat";
|
|
31181
|
+
var DEFAULT_LOG_ENDPOINT = "https://clawd-prod.cn-hangzhou.log.aliyuncs.com/logstores/app-logs/track";
|
|
31182
|
+
function resolveLogShipping(raw, cliNoShipping) {
|
|
31183
|
+
if (cliNoShipping) {
|
|
31184
|
+
return { mode: "off", endpoint: null, sampling: {} };
|
|
31185
|
+
}
|
|
31186
|
+
const rawMode = raw?.mode;
|
|
31187
|
+
const mode = rawMode === "off" || rawMode === "errors-only" ? rawMode : "on";
|
|
31188
|
+
if (mode === "off") {
|
|
31189
|
+
return { mode, endpoint: null, sampling: {} };
|
|
31190
|
+
}
|
|
31191
|
+
const endpoint = typeof raw?.endpoint === "string" && raw.endpoint ? raw.endpoint : raw?.endpoint === null ? null : DEFAULT_LOG_ENDPOINT;
|
|
31192
|
+
const sampling = mode === "errors-only" ? { debug: 0, info: 0, warn: 1, error: 1 } : isPlainSamplingMap(raw?.sampling) ? raw.sampling : {};
|
|
31193
|
+
return { mode, endpoint, sampling };
|
|
31194
|
+
}
|
|
31195
|
+
function isPlainSamplingMap(v2) {
|
|
31196
|
+
if (!v2 || typeof v2 !== "object") return false;
|
|
31197
|
+
return Object.values(v2).every((n) => typeof n === "number");
|
|
31198
|
+
}
|
|
31115
31199
|
function parseArgs(argv) {
|
|
31116
31200
|
const out = {};
|
|
31117
31201
|
for (let i = 0; i < argv.length; i++) {
|
|
@@ -31157,6 +31241,9 @@ function parseArgs(argv) {
|
|
|
31157
31241
|
case "-v":
|
|
31158
31242
|
out.version = true;
|
|
31159
31243
|
break;
|
|
31244
|
+
case "--no-log-shipping":
|
|
31245
|
+
out.noLogShipping = true;
|
|
31246
|
+
break;
|
|
31160
31247
|
default:
|
|
31161
31248
|
if (a.startsWith("--")) throw new Error(`unknown flag: ${a}`);
|
|
31162
31249
|
break;
|
|
@@ -31202,6 +31289,10 @@ function resolveConfig(opts) {
|
|
|
31202
31289
|
const mode = DAEMON_MODE_VALUES.includes(rawMode ?? "") ? rawMode : "sdk";
|
|
31203
31290
|
const filePreviewPorts = Array.isArray(fileCfg.previewPorts) ? fileCfg.previewPorts.map((n) => Number(n)).filter((n) => Number.isInteger(n) && n > 0) : null;
|
|
31204
31291
|
const previewPorts = env.CLAWD_PREVIEW_PORTS ? env.CLAWD_PREVIEW_PORTS.split(",").map((s) => Number(s.trim())).filter((n) => Number.isInteger(n) && n > 0) : filePreviewPorts && filePreviewPorts.length > 0 ? filePreviewPorts : null;
|
|
31292
|
+
const logShipping = resolveLogShipping(
|
|
31293
|
+
fileCfg.logShipping,
|
|
31294
|
+
args.noLogShipping ?? false
|
|
31295
|
+
);
|
|
31205
31296
|
return {
|
|
31206
31297
|
port,
|
|
31207
31298
|
host,
|
|
@@ -31214,7 +31305,8 @@ function resolveConfig(opts) {
|
|
|
31214
31305
|
noTunnelPersist,
|
|
31215
31306
|
frpcBinary,
|
|
31216
31307
|
mode,
|
|
31217
|
-
previewPorts
|
|
31308
|
+
previewPorts,
|
|
31309
|
+
logShipping
|
|
31218
31310
|
};
|
|
31219
31311
|
}
|
|
31220
31312
|
var HELP_TEXT = `clawd [options]
|
|
@@ -31225,6 +31317,7 @@ var HELP_TEXT = `clawd [options]
|
|
|
31225
31317
|
--tunnel \u542F\u7528 frp tunnel \u628A\u672C\u5730\u7AEF\u53E3\u66B4\u9732\u5230\u516C\u7F51
|
|
31226
31318
|
--clawos-api <url> tunnel register \u63A5\u53E3\u7684 base url\uFF08\u9ED8\u8BA4 https://api.clawos.chat\uFF09
|
|
31227
31319
|
--auth-token <s> \u6307\u5B9A daemon auth token\uFF1B\u7F3A\u7701\u65F6 tunnel \u6A21\u5F0F\u4ECE ~/.clawd/auth.json \u590D\u7528\uFF0C\u6CA1\u6709\u5C31\u751F\u6210
|
|
31320
|
+
--no-log-shipping \u7981\u7528 SLS \u65E5\u5FD7\u4E0A\u884C\uFF08\u8986\u76D6 config.json logShipping.mode=off\uFF09
|
|
31228
31321
|
--help / -h \u663E\u793A\u5E2E\u52A9
|
|
31229
31322
|
--version / -v \u663E\u793A\u7248\u672C
|
|
31230
31323
|
|
|
@@ -31243,12 +31336,64 @@ Env (advanced):
|
|
|
31243
31336
|
`;
|
|
31244
31337
|
|
|
31245
31338
|
// src/index.ts
|
|
31246
|
-
var
|
|
31247
|
-
var
|
|
31339
|
+
var import_node_path46 = __toESM(require("path"), 1);
|
|
31340
|
+
var import_node_fs34 = __toESM(require("fs"), 1);
|
|
31341
|
+
var import_node_os19 = __toESM(require("os"), 1);
|
|
31342
|
+
|
|
31343
|
+
// ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/stringify.js
|
|
31344
|
+
var byteToHex = [];
|
|
31345
|
+
for (let i = 0; i < 256; ++i) {
|
|
31346
|
+
byteToHex.push((i + 256).toString(16).slice(1));
|
|
31347
|
+
}
|
|
31348
|
+
function unsafeStringify(arr, offset = 0) {
|
|
31349
|
+
return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
|
|
31350
|
+
}
|
|
31351
|
+
|
|
31352
|
+
// ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/rng.js
|
|
31353
|
+
var import_node_crypto = __toESM(require("crypto"));
|
|
31354
|
+
var rnds8Pool = new Uint8Array(256);
|
|
31355
|
+
var poolPtr = rnds8Pool.length;
|
|
31356
|
+
function rng() {
|
|
31357
|
+
if (poolPtr > rnds8Pool.length - 16) {
|
|
31358
|
+
import_node_crypto.default.randomFillSync(rnds8Pool);
|
|
31359
|
+
poolPtr = 0;
|
|
31360
|
+
}
|
|
31361
|
+
return rnds8Pool.slice(poolPtr, poolPtr += 16);
|
|
31362
|
+
}
|
|
31363
|
+
|
|
31364
|
+
// ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/native.js
|
|
31365
|
+
var import_node_crypto2 = __toESM(require("crypto"));
|
|
31366
|
+
var native_default = {
|
|
31367
|
+
randomUUID: import_node_crypto2.default.randomUUID
|
|
31368
|
+
};
|
|
31369
|
+
|
|
31370
|
+
// ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/v4.js
|
|
31371
|
+
function v4(options, buf, offset) {
|
|
31372
|
+
if (native_default.randomUUID && !buf && !options) {
|
|
31373
|
+
return native_default.randomUUID();
|
|
31374
|
+
}
|
|
31375
|
+
options = options || {};
|
|
31376
|
+
const rnds = options.random || (options.rng || rng)();
|
|
31377
|
+
rnds[6] = rnds[6] & 15 | 64;
|
|
31378
|
+
rnds[8] = rnds[8] & 63 | 128;
|
|
31379
|
+
if (buf) {
|
|
31380
|
+
offset = offset || 0;
|
|
31381
|
+
for (let i = 0; i < 16; ++i) {
|
|
31382
|
+
buf[offset + i] = rnds[i];
|
|
31383
|
+
}
|
|
31384
|
+
return buf;
|
|
31385
|
+
}
|
|
31386
|
+
return unsafeStringify(rnds);
|
|
31387
|
+
}
|
|
31388
|
+
var v4_default = v4;
|
|
31389
|
+
|
|
31390
|
+
// src/index.ts
|
|
31391
|
+
var import_node_url2 = require("url");
|
|
31248
31392
|
|
|
31249
31393
|
// src/logger.ts
|
|
31250
31394
|
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
31251
31395
|
var import_node_path2 = __toESM(require("path"), 1);
|
|
31396
|
+
var import_node_stream = require("stream");
|
|
31252
31397
|
var import_pino = __toESM(require_pino(), 1);
|
|
31253
31398
|
function wrap(inner) {
|
|
31254
31399
|
return {
|
|
@@ -31274,12 +31419,328 @@ function createLogger(opts = {}) {
|
|
|
31274
31419
|
} catch {
|
|
31275
31420
|
}
|
|
31276
31421
|
}
|
|
31422
|
+
if (opts.logClient) {
|
|
31423
|
+
const client = opts.logClient;
|
|
31424
|
+
const sink = new import_node_stream.Writable({
|
|
31425
|
+
write(chunk, _enc, cb) {
|
|
31426
|
+
try {
|
|
31427
|
+
const line = String(chunk).trim();
|
|
31428
|
+
if (line) {
|
|
31429
|
+
const obj = JSON.parse(line);
|
|
31430
|
+
const lvl = pinoLevelToString(obj.level);
|
|
31431
|
+
if (lvl) {
|
|
31432
|
+
const meta = {};
|
|
31433
|
+
for (const [k2, v2] of Object.entries(obj)) {
|
|
31434
|
+
if (k2 === "level" || k2 === "msg" || k2 === "time" || k2 === "pid" || k2 === "hostname") continue;
|
|
31435
|
+
if (k2 === "sessionId") continue;
|
|
31436
|
+
meta[k2] = v2;
|
|
31437
|
+
}
|
|
31438
|
+
client.push({
|
|
31439
|
+
ts: typeof obj.time === "number" ? obj.time : void 0,
|
|
31440
|
+
level: lvl,
|
|
31441
|
+
msg: typeof obj.msg === "string" ? obj.msg : "",
|
|
31442
|
+
meta: Object.keys(meta).length > 0 ? meta : void 0,
|
|
31443
|
+
sessionId: typeof obj.sessionId === "string" ? obj.sessionId : void 0
|
|
31444
|
+
});
|
|
31445
|
+
}
|
|
31446
|
+
}
|
|
31447
|
+
} catch {
|
|
31448
|
+
}
|
|
31449
|
+
cb();
|
|
31450
|
+
}
|
|
31451
|
+
});
|
|
31452
|
+
streams.push({ stream: sink, level });
|
|
31453
|
+
}
|
|
31277
31454
|
const base = (0, import_pino.default)(
|
|
31278
31455
|
{ level, base: { pid: process.pid } },
|
|
31279
31456
|
import_pino.default.multistream(streams)
|
|
31280
31457
|
);
|
|
31281
31458
|
return wrap(base);
|
|
31282
31459
|
}
|
|
31460
|
+
function pinoLevelToString(n) {
|
|
31461
|
+
if (typeof n !== "number") return null;
|
|
31462
|
+
if (n >= 50) return "error";
|
|
31463
|
+
if (n >= 40) return "warn";
|
|
31464
|
+
if (n >= 30) return "info";
|
|
31465
|
+
if (n >= 20) return "debug";
|
|
31466
|
+
return null;
|
|
31467
|
+
}
|
|
31468
|
+
|
|
31469
|
+
// ../log-client/dist/index.js
|
|
31470
|
+
var DEFAULT_BATCH = {
|
|
31471
|
+
maxRecords: 100,
|
|
31472
|
+
maxBytes: 512 * 1024,
|
|
31473
|
+
maxWaitMs: 5e3
|
|
31474
|
+
};
|
|
31475
|
+
var DEFAULT_BUFFER_CAP = 5e3;
|
|
31476
|
+
var DEFAULT_SAMPLING = {
|
|
31477
|
+
debug: 0,
|
|
31478
|
+
info: 1,
|
|
31479
|
+
warn: 1,
|
|
31480
|
+
error: 1
|
|
31481
|
+
};
|
|
31482
|
+
var MAX_MSG_BYTES = 1024;
|
|
31483
|
+
var MAX_META_JSON_BYTES = 2048;
|
|
31484
|
+
var REDACT_KEY_REGEX = /token|secret|password|auth(?!or)|apikey|signsecret/i;
|
|
31485
|
+
var REDACTED_PLACEHOLDER = "[REDACTED]";
|
|
31486
|
+
var TRUNCATE_SUFFIX = "\u2026[truncated]";
|
|
31487
|
+
function redactMeta(meta, homeDir) {
|
|
31488
|
+
const cleaned = cleanValue(meta, homeDir, 0);
|
|
31489
|
+
const json = safeStringify(cleaned);
|
|
31490
|
+
if (json.length <= MAX_META_JSON_BYTES) return cleaned;
|
|
31491
|
+
const truncated = json.slice(0, MAX_META_JSON_BYTES) + TRUNCATE_SUFFIX;
|
|
31492
|
+
return { __truncated__: truncated };
|
|
31493
|
+
}
|
|
31494
|
+
function cleanValue(v2, homeDir, depth) {
|
|
31495
|
+
if (depth > 10) return "[depth-limit]";
|
|
31496
|
+
if (v2 == null) return v2;
|
|
31497
|
+
if (typeof v2 === "string") {
|
|
31498
|
+
return homeDir ? v2.split(homeDir).join("~") : v2;
|
|
31499
|
+
}
|
|
31500
|
+
if (typeof v2 !== "object") return v2;
|
|
31501
|
+
if (Array.isArray(v2)) return v2.map((x) => cleanValue(x, homeDir, depth + 1));
|
|
31502
|
+
const out = {};
|
|
31503
|
+
for (const [k2, val] of Object.entries(v2)) {
|
|
31504
|
+
if (REDACT_KEY_REGEX.test(k2)) {
|
|
31505
|
+
out[k2] = REDACTED_PLACEHOLDER;
|
|
31506
|
+
} else {
|
|
31507
|
+
out[k2] = cleanValue(val, homeDir, depth + 1);
|
|
31508
|
+
}
|
|
31509
|
+
}
|
|
31510
|
+
return out;
|
|
31511
|
+
}
|
|
31512
|
+
function safeStringify(v2) {
|
|
31513
|
+
try {
|
|
31514
|
+
return JSON.stringify(v2) ?? "";
|
|
31515
|
+
} catch {
|
|
31516
|
+
return '"[serialize-failed]"';
|
|
31517
|
+
}
|
|
31518
|
+
}
|
|
31519
|
+
function truncateMsg(msg) {
|
|
31520
|
+
if (msg.length <= MAX_MSG_BYTES) return msg;
|
|
31521
|
+
return msg.slice(0, MAX_MSG_BYTES) + TRUNCATE_SUFFIX;
|
|
31522
|
+
}
|
|
31523
|
+
function shouldSample(level, config, rng2) {
|
|
31524
|
+
const rate = config[level] ?? DEFAULT_SAMPLING[level];
|
|
31525
|
+
if (rate <= 0) return false;
|
|
31526
|
+
if (rate >= 1) return true;
|
|
31527
|
+
return rng2() < rate;
|
|
31528
|
+
}
|
|
31529
|
+
var Batcher = class {
|
|
31530
|
+
constructor(deps) {
|
|
31531
|
+
this.deps = deps;
|
|
31532
|
+
}
|
|
31533
|
+
deps;
|
|
31534
|
+
queue = [];
|
|
31535
|
+
bytes = 0;
|
|
31536
|
+
droppedSinceFlush = 0;
|
|
31537
|
+
identityReady = false;
|
|
31538
|
+
timer = null;
|
|
31539
|
+
disposed = false;
|
|
31540
|
+
pendingSends = [];
|
|
31541
|
+
enqueue(record) {
|
|
31542
|
+
if (this.disposed) return;
|
|
31543
|
+
const sz = approxSize(record);
|
|
31544
|
+
while (this.queue.length >= this.deps.bufferCap) {
|
|
31545
|
+
this.queue.shift();
|
|
31546
|
+
this.droppedSinceFlush++;
|
|
31547
|
+
}
|
|
31548
|
+
this.queue.push(record);
|
|
31549
|
+
this.bytes += sz;
|
|
31550
|
+
if (!this.identityReady) return;
|
|
31551
|
+
this.maybeTrigger();
|
|
31552
|
+
}
|
|
31553
|
+
setIdentityReady(ready) {
|
|
31554
|
+
this.identityReady = ready;
|
|
31555
|
+
if (ready && this.queue.length > 0) this.maybeTrigger();
|
|
31556
|
+
}
|
|
31557
|
+
async flush() {
|
|
31558
|
+
if (this.queue.length > 0) {
|
|
31559
|
+
this.fire("flush");
|
|
31560
|
+
}
|
|
31561
|
+
await Promise.allSettled(this.pendingSends);
|
|
31562
|
+
}
|
|
31563
|
+
stats() {
|
|
31564
|
+
return { queued: this.queue.length, dropped: this.droppedSinceFlush };
|
|
31565
|
+
}
|
|
31566
|
+
async dispose() {
|
|
31567
|
+
if (this.disposed) return;
|
|
31568
|
+
this.disposed = true;
|
|
31569
|
+
if (this.timer) {
|
|
31570
|
+
clearTimeout(this.timer);
|
|
31571
|
+
this.timer = null;
|
|
31572
|
+
}
|
|
31573
|
+
await this.flush();
|
|
31574
|
+
}
|
|
31575
|
+
maybeTrigger() {
|
|
31576
|
+
const { maxRecords, maxBytes, maxWaitMs } = this.deps.batch;
|
|
31577
|
+
if (this.queue.length >= maxRecords) {
|
|
31578
|
+
this.fire("records");
|
|
31579
|
+
return;
|
|
31580
|
+
}
|
|
31581
|
+
if (this.bytes >= maxBytes) {
|
|
31582
|
+
this.fire("bytes");
|
|
31583
|
+
return;
|
|
31584
|
+
}
|
|
31585
|
+
if (this.timer == null) {
|
|
31586
|
+
this.timer = setTimeout(() => {
|
|
31587
|
+
this.timer = null;
|
|
31588
|
+
if (this.queue.length > 0 && this.identityReady) this.fire("time");
|
|
31589
|
+
}, maxWaitMs);
|
|
31590
|
+
}
|
|
31591
|
+
}
|
|
31592
|
+
fire(reason) {
|
|
31593
|
+
if (this.timer) {
|
|
31594
|
+
clearTimeout(this.timer);
|
|
31595
|
+
this.timer = null;
|
|
31596
|
+
}
|
|
31597
|
+
const records = this.queue;
|
|
31598
|
+
const droppedCarryover = this.droppedSinceFlush;
|
|
31599
|
+
this.queue = [];
|
|
31600
|
+
this.bytes = 0;
|
|
31601
|
+
this.droppedSinceFlush = 0;
|
|
31602
|
+
const p2 = this.deps.onBatch({ reason, records, droppedCarryover }).catch(() => {
|
|
31603
|
+
});
|
|
31604
|
+
this.pendingSends.push(p2);
|
|
31605
|
+
p2.finally(() => {
|
|
31606
|
+
this.pendingSends = this.pendingSends.filter((x) => x !== p2);
|
|
31607
|
+
});
|
|
31608
|
+
}
|
|
31609
|
+
};
|
|
31610
|
+
function approxSize(record) {
|
|
31611
|
+
return (record.msg?.length ?? 0) + (record.meta_json?.length ?? 0) + 200;
|
|
31612
|
+
}
|
|
31613
|
+
var BACKOFF_MS = [1e3, 2e3, 4e3];
|
|
31614
|
+
async function sendBatch(deps, batch) {
|
|
31615
|
+
const logsForSls = batch.records.map(stringifyRecord);
|
|
31616
|
+
const body = JSON.stringify({
|
|
31617
|
+
__topic__: deps.topic ?? "clawd",
|
|
31618
|
+
__source__: deps.source,
|
|
31619
|
+
__logs__: logsForSls,
|
|
31620
|
+
...batch.droppedCarryover > 0 ? { __tags__: { dropped: String(batch.droppedCarryover) } } : {}
|
|
31621
|
+
});
|
|
31622
|
+
for (let attempt = 0; attempt < BACKOFF_MS.length; attempt++) {
|
|
31623
|
+
if (attempt > 0) await sleep(BACKOFF_MS[attempt - 1]);
|
|
31624
|
+
try {
|
|
31625
|
+
const res = await deps.fetchImpl(deps.endpoint, {
|
|
31626
|
+
method: "POST",
|
|
31627
|
+
headers: { "Content-Type": "application/json" },
|
|
31628
|
+
body
|
|
31629
|
+
});
|
|
31630
|
+
if (res.status >= 200 && res.status < 300) {
|
|
31631
|
+
return { sent: batch.records.length, failed: 0 };
|
|
31632
|
+
}
|
|
31633
|
+
if (res.status >= 400 && res.status < 500) {
|
|
31634
|
+
return { sent: 0, failed: batch.records.length };
|
|
31635
|
+
}
|
|
31636
|
+
} catch {
|
|
31637
|
+
}
|
|
31638
|
+
}
|
|
31639
|
+
return { sent: 0, failed: batch.records.length };
|
|
31640
|
+
}
|
|
31641
|
+
function stringifyRecord(rec3) {
|
|
31642
|
+
const out = {};
|
|
31643
|
+
for (const [k2, v2] of Object.entries(rec3)) {
|
|
31644
|
+
if (v2 == null) continue;
|
|
31645
|
+
out[k2] = typeof v2 === "string" ? v2 : String(v2);
|
|
31646
|
+
}
|
|
31647
|
+
return out;
|
|
31648
|
+
}
|
|
31649
|
+
function sleep(ms) {
|
|
31650
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
31651
|
+
}
|
|
31652
|
+
function createLogClient(opts) {
|
|
31653
|
+
const stats = { sent: 0, dropped: 0, queued: 0, failed: 0 };
|
|
31654
|
+
const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
31655
|
+
const now = opts.now ?? Date.now;
|
|
31656
|
+
const sampling = { ...DEFAULT_SAMPLING, ...opts.sampling ?? {} };
|
|
31657
|
+
const homeDir = opts.homeDir === void 0 ? null : opts.homeDir;
|
|
31658
|
+
const batchConfig = { ...DEFAULT_BATCH, ...opts.batch ?? {} };
|
|
31659
|
+
const bufferCap = opts.bufferCap ?? DEFAULT_BUFFER_CAP;
|
|
31660
|
+
let identity = opts.identity;
|
|
31661
|
+
let disposed = false;
|
|
31662
|
+
if (opts.endpoint == null) {
|
|
31663
|
+
return {
|
|
31664
|
+
push: () => {
|
|
31665
|
+
if (disposed) return;
|
|
31666
|
+
stats.dropped++;
|
|
31667
|
+
},
|
|
31668
|
+
flush: async () => {
|
|
31669
|
+
},
|
|
31670
|
+
setIdentity: (next) => {
|
|
31671
|
+
identity = next;
|
|
31672
|
+
},
|
|
31673
|
+
stats: () => ({ ...stats }),
|
|
31674
|
+
dispose: async () => {
|
|
31675
|
+
disposed = true;
|
|
31676
|
+
}
|
|
31677
|
+
};
|
|
31678
|
+
}
|
|
31679
|
+
const endpoint = opts.endpoint;
|
|
31680
|
+
const batcher = new Batcher({
|
|
31681
|
+
batch: batchConfig,
|
|
31682
|
+
bufferCap,
|
|
31683
|
+
now,
|
|
31684
|
+
onBatch: async (b2) => {
|
|
31685
|
+
const res = await sendBatch({ endpoint, source: opts.source, fetchImpl }, b2);
|
|
31686
|
+
stats.sent += res.sent;
|
|
31687
|
+
stats.failed += res.failed;
|
|
31688
|
+
}
|
|
31689
|
+
});
|
|
31690
|
+
batcher.setIdentityReady(identity != null);
|
|
31691
|
+
return {
|
|
31692
|
+
push(input) {
|
|
31693
|
+
if (disposed) return;
|
|
31694
|
+
try {
|
|
31695
|
+
if (!shouldSample(input.level, sampling, Math.random)) {
|
|
31696
|
+
stats.dropped++;
|
|
31697
|
+
return;
|
|
31698
|
+
}
|
|
31699
|
+
const record = buildRecord(input, identity, opts.source, homeDir, now);
|
|
31700
|
+
batcher.enqueue(record);
|
|
31701
|
+
} catch {
|
|
31702
|
+
}
|
|
31703
|
+
},
|
|
31704
|
+
async flush() {
|
|
31705
|
+
try {
|
|
31706
|
+
await batcher.flush();
|
|
31707
|
+
} catch {
|
|
31708
|
+
}
|
|
31709
|
+
},
|
|
31710
|
+
setIdentity(next) {
|
|
31711
|
+
identity = next;
|
|
31712
|
+
batcher.setIdentityReady(next != null);
|
|
31713
|
+
},
|
|
31714
|
+
stats() {
|
|
31715
|
+
const bs = batcher.stats();
|
|
31716
|
+
return { ...stats, queued: bs.queued, dropped: stats.dropped + bs.dropped };
|
|
31717
|
+
},
|
|
31718
|
+
async dispose() {
|
|
31719
|
+
disposed = true;
|
|
31720
|
+
try {
|
|
31721
|
+
await batcher.dispose();
|
|
31722
|
+
} catch {
|
|
31723
|
+
}
|
|
31724
|
+
}
|
|
31725
|
+
};
|
|
31726
|
+
}
|
|
31727
|
+
function buildRecord(input, identity, source, homeDir, now) {
|
|
31728
|
+
const cleanedMeta = input.meta ? redactMeta(input.meta, homeDir) : void 0;
|
|
31729
|
+
const meta_json = cleanedMeta ? JSON.stringify(cleanedMeta) : void 0;
|
|
31730
|
+
return {
|
|
31731
|
+
ts: input.ts ?? now(),
|
|
31732
|
+
source,
|
|
31733
|
+
level: input.level,
|
|
31734
|
+
msg: truncateMsg(input.msg),
|
|
31735
|
+
ownerPrincipalId: identity?.ownerPrincipalId ?? "__pending__",
|
|
31736
|
+
deviceId: identity?.deviceId ?? "__pending__",
|
|
31737
|
+
appVersion: identity?.appVersion ?? "__pending__",
|
|
31738
|
+
daemonVersion: identity?.daemonVersion,
|
|
31739
|
+
os: identity?.os ?? "unknown",
|
|
31740
|
+
meta_json,
|
|
31741
|
+
sessionId: input.sessionId
|
|
31742
|
+
};
|
|
31743
|
+
}
|
|
31283
31744
|
|
|
31284
31745
|
// src/session/store-factory.ts
|
|
31285
31746
|
var path5 = __toESM(require("path"), 1);
|
|
@@ -31486,55 +31947,6 @@ var SessionStoreFactory = class {
|
|
|
31486
31947
|
var import_node_fs6 = __toESM(require("fs"), 1);
|
|
31487
31948
|
var import_node_path6 = __toESM(require("path"), 1);
|
|
31488
31949
|
var import_node_os2 = __toESM(require("os"), 1);
|
|
31489
|
-
|
|
31490
|
-
// ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/stringify.js
|
|
31491
|
-
var byteToHex = [];
|
|
31492
|
-
for (let i = 0; i < 256; ++i) {
|
|
31493
|
-
byteToHex.push((i + 256).toString(16).slice(1));
|
|
31494
|
-
}
|
|
31495
|
-
function unsafeStringify(arr, offset = 0) {
|
|
31496
|
-
return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
|
|
31497
|
-
}
|
|
31498
|
-
|
|
31499
|
-
// ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/rng.js
|
|
31500
|
-
var import_node_crypto = __toESM(require("crypto"));
|
|
31501
|
-
var rnds8Pool = new Uint8Array(256);
|
|
31502
|
-
var poolPtr = rnds8Pool.length;
|
|
31503
|
-
function rng() {
|
|
31504
|
-
if (poolPtr > rnds8Pool.length - 16) {
|
|
31505
|
-
import_node_crypto.default.randomFillSync(rnds8Pool);
|
|
31506
|
-
poolPtr = 0;
|
|
31507
|
-
}
|
|
31508
|
-
return rnds8Pool.slice(poolPtr, poolPtr += 16);
|
|
31509
|
-
}
|
|
31510
|
-
|
|
31511
|
-
// ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/native.js
|
|
31512
|
-
var import_node_crypto2 = __toESM(require("crypto"));
|
|
31513
|
-
var native_default = {
|
|
31514
|
-
randomUUID: import_node_crypto2.default.randomUUID
|
|
31515
|
-
};
|
|
31516
|
-
|
|
31517
|
-
// ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/v4.js
|
|
31518
|
-
function v4(options, buf, offset) {
|
|
31519
|
-
if (native_default.randomUUID && !buf && !options) {
|
|
31520
|
-
return native_default.randomUUID();
|
|
31521
|
-
}
|
|
31522
|
-
options = options || {};
|
|
31523
|
-
const rnds = options.random || (options.rng || rng)();
|
|
31524
|
-
rnds[6] = rnds[6] & 15 | 64;
|
|
31525
|
-
rnds[8] = rnds[8] & 63 | 128;
|
|
31526
|
-
if (buf) {
|
|
31527
|
-
offset = offset || 0;
|
|
31528
|
-
for (let i = 0; i < 16; ++i) {
|
|
31529
|
-
buf[offset + i] = rnds[i];
|
|
31530
|
-
}
|
|
31531
|
-
return buf;
|
|
31532
|
-
}
|
|
31533
|
-
return unsafeStringify(rnds);
|
|
31534
|
-
}
|
|
31535
|
-
var v4_default = v4;
|
|
31536
|
-
|
|
31537
|
-
// src/session/manager.ts
|
|
31538
31950
|
init_protocol();
|
|
31539
31951
|
|
|
31540
31952
|
// src/tools/guest-settings.ts
|
|
@@ -31659,6 +32071,32 @@ function buildConnectionPrompt(args) {
|
|
|
31659
32071
|
return result;
|
|
31660
32072
|
}
|
|
31661
32073
|
|
|
32074
|
+
// src/dispatch/system-prompt.ts
|
|
32075
|
+
var DISPATCH_SYSTEM_PROMPT_HINT = `## \u59D4\u6D3E\u7ED9\u53E6\u4E00\u4E2A persona\uFF08dispatch\uFF09
|
|
32076
|
+
|
|
32077
|
+
\u5F53\u7528\u6237\u6D88\u606F\u91CC\u542B \`@persona/<id>\`\uFF08\u5982 \`@persona/persona-bug-fixer\`\uFF09\u65F6\uFF0C**\u4F60\u5FC5\u987B**\u7ACB\u5373\u8C03 MCP tool \`mcp__clawd-dispatch__personaDispatch\` \u59D4\u6D3E\uFF0C\u4E0D\u8981\u5C1D\u8BD5\u81EA\u5DF1\u6267\u884C\uFF1A
|
|
32078
|
+
|
|
32079
|
+
- \`targetPersona = <id>\`\uFF08@ token \u91CC\u7684 persona id\uFF09
|
|
32080
|
+
- \`prompt = \u53BB\u6389 @persona/<id> token \u7684\u7528\u6237\u539F\u6587\`
|
|
32081
|
+
|
|
32082
|
+
tool \u4F1A\u963B\u585E\u6302\u8D77\u7B49\u5BF9\u65B9\u4EBA\u683C\u5E72\u5B8C\uFF0C\u628A outcome\uFF08\u542B text + \u53EF\u9009 filePaths\uFF09\u4F5C\u4E3A tool_result \u56DE\u7ED9\u4F60\uFF0C\u4F60\u518D\u7EFC\u5408\u56DE\u5E94\u7528\u6237\u3002
|
|
32083
|
+
|
|
32084
|
+
- **\u4E0D\u8981**\u5C1D\u8BD5\u81EA\u5DF1\u6267\u884C\uFF08\u4F60\u4E0D\u662F\u90A3\u4E2A persona\uFF09
|
|
32085
|
+
- **\u4E0D\u8981** in-place \u6A21\u4EFF\u5BF9\u65B9\u4EBA\u683C \u2014\u2014 dispatch \u662F\u771F\u5207\u5230\u53E6\u4E00\u4E2A\u72EC\u7ACB session
|
|
32086
|
+
- \u4E00\u53E5\u8BDD\u91CC\u591A\u4E2A \`@persona/<id>\` \u65F6\u9009\u7B2C\u4E00\u4E2A\uFF08tool \u4E00\u6B21\u53EA\u5904\u7406\u4E00\u4E2A target\uFF09
|
|
32087
|
+
- \u59D4\u6D3E\u5931\u8D25\uFF08tool_result.is_error=true\uFF09\u65F6\u5982\u5B9E\u544A\u8BC9\u7528\u6237\u539F\u56E0\uFF0C**\u4E0D\u8981\u91CD\u8BD5**
|
|
32088
|
+
|
|
32089
|
+
## \u88AB dispatch \u63A5\u5230\u4EFB\u52A1
|
|
32090
|
+
|
|
32091
|
+
\u5982\u679C\u4F60\u7684 session \u7B2C\u4E00\u6761 user message \u662F\u4EE5 \`[Dispatched from owner \u2014 another persona session\u59D4\u6D3E\u7ED9\u4F60\u6267\u884C\u4EFB\u52A1]\` \u8D77\u5934\u7684 plain text \u4EFB\u52A1\u5305\uFF0C\u4F60\u662F\u88AB\u53E6\u4E00\u4E2A persona \u59D4\u6D3E\u6765\u5E72\u6D3B\u7684\uFF08\u4EFB\u52A1\u5305\u4E0D\u7528 \`<system-reminder>\` \u5305\u662F\u4E3A\u4E86 reducer dedup \u5DE5\u4F5C\u6B63\u5E38\uFF0C\u89C1 manager.ts buildDispatchTaskPack \u6CE8\u91CA\uFF09\uFF1A
|
|
32092
|
+
|
|
32093
|
+
- \u4EFB\u52A1\u5728 \`Task:\` \u6BB5
|
|
32094
|
+
- \u539F\u4F1A\u8BDD\u7684\u5BF9\u8BDD\u5386\u53F2\u5728 \`Source conversation\` \u6BB5\u7ED9\u7684 jsonl \u8DEF\u5F84\u4E0B\uFF1B\u6309\u9700 Read \u5B83\u4E86\u89E3\u4E0A\u4E0B\u6587\uFF08\u4E0D\u5FC5\u8BFB\u5B8C\uFF09
|
|
32095
|
+
- \u5E72\u5B8C\u540E**\u5FC5\u987B**\u8C03 \`mcp__clawd-dispatch__personaDispatchComplete\` \u62A5\u544A\u7ED3\u679C\uFF1A
|
|
32096
|
+
- \u6210\u529F\uFF1A\`{ text: "\u603B\u7ED3/\u7ED3\u8BBA", filePaths?: ["\u4F60\u4EA7\u51FA/\u6539\u7684\u6587\u4EF6\u7EDD\u5BF9\u8DEF\u5F84"] }\`
|
|
32097
|
+
- \u5931\u8D25\uFF1A\`{ isFailure: true, reason: "..." }\`
|
|
32098
|
+
- \u62A5\u544A\u5B8C\u540E\u4F60\u7684 session \u5C31\u7ED3\u675F\u4E86\uFF0C\u4E0D\u8981\u7EE7\u7EED\u8F93\u51FA`;
|
|
32099
|
+
|
|
31662
32100
|
// src/session/reducer.ts
|
|
31663
32101
|
function cloneState(s) {
|
|
31664
32102
|
return {
|
|
@@ -31737,6 +32175,9 @@ function buildSpawnContext(state, deps) {
|
|
|
31737
32175
|
env.CLAWD_SESSION_ID = file.sessionId;
|
|
31738
32176
|
const daemonUrl = deps.getDaemonUrl?.() ?? null;
|
|
31739
32177
|
if (daemonUrl) env.CLAWD_DAEMON_URL = daemonUrl;
|
|
32178
|
+
const dispatchId = deps.lookupDispatchByBSessionId?.(file.sessionId);
|
|
32179
|
+
if (dispatchId) env.CLAWD_DISPATCH_ID = dispatchId;
|
|
32180
|
+
const dispatchMcpConfigPath2 = deps.getDispatchMcpConfigPath?.() ?? null;
|
|
31740
32181
|
const ctx = {
|
|
31741
32182
|
cwd: file.cwd,
|
|
31742
32183
|
toolSessionId: file.toolSessionId,
|
|
@@ -31746,7 +32187,10 @@ function buildSpawnContext(state, deps) {
|
|
|
31746
32187
|
env,
|
|
31747
32188
|
// Phase 2 capability platform (plan §3): personaRoot 透传给 buildSpawnArgs;
|
|
31748
32189
|
// 内部 shouldSandbox(cwd, personaRoot) 决定是否注入 --settings sandbox-settings.
|
|
31749
|
-
personaRoot: deps.personaRoot
|
|
32190
|
+
personaRoot: deps.personaRoot,
|
|
32191
|
+
// Persona dispatch:所有 session(A 和 B)都挂同一份 dispatch.mcp.json,让两边的 cc
|
|
32192
|
+
// 都能看到 personaDispatch / personaDispatchComplete tool;按 env 区分实际行为。
|
|
32193
|
+
dispatchMcpConfigPath: dispatchMcpConfigPath2 ?? void 0
|
|
31750
32194
|
};
|
|
31751
32195
|
const meta = state.subSessionMeta;
|
|
31752
32196
|
if (meta?.personaMode) {
|
|
@@ -31757,6 +32201,9 @@ function buildSpawnContext(state, deps) {
|
|
|
31757
32201
|
workDir: meta.userWorkDir
|
|
31758
32202
|
});
|
|
31759
32203
|
}
|
|
32204
|
+
if (dispatchMcpConfigPath2) {
|
|
32205
|
+
ctx.extraSystemPrompt = (ctx.extraSystemPrompt ? ctx.extraSystemPrompt + "\n\n" : "") + DISPATCH_SYSTEM_PROMPT_HINT;
|
|
32206
|
+
}
|
|
31760
32207
|
if (meta?.extraSettings) {
|
|
31761
32208
|
ctx.extraSettings = meta.extraSettings;
|
|
31762
32209
|
}
|
|
@@ -32422,35 +32869,6 @@ function startRecorder(opts) {
|
|
|
32422
32869
|
};
|
|
32423
32870
|
}
|
|
32424
32871
|
|
|
32425
|
-
// src/persona/mention-injection.ts
|
|
32426
|
-
var MENTION_RE = /@persona\/([A-Za-z0-9_-]+)(?=\s|$|[^A-Za-z0-9_-])/g;
|
|
32427
|
-
function injectPersonaMentions(rawText, store) {
|
|
32428
|
-
const resolved = [];
|
|
32429
|
-
const body = rawText.replace(MENTION_RE, (match, id) => {
|
|
32430
|
-
const meta = store.read(id);
|
|
32431
|
-
const personality = store.readPersonality(id);
|
|
32432
|
-
if (meta && personality !== null) {
|
|
32433
|
-
resolved.push({ label: meta.label, personality });
|
|
32434
|
-
return "";
|
|
32435
|
-
}
|
|
32436
|
-
return match;
|
|
32437
|
-
});
|
|
32438
|
-
if (resolved.length === 0) {
|
|
32439
|
-
return { systemReminder: null, userText: rawText };
|
|
32440
|
-
}
|
|
32441
|
-
const blocks = resolved.map((r) => {
|
|
32442
|
-
const safe = r.personality.replace(/<\/system-reminder>/gi, "</ system-reminder>");
|
|
32443
|
-
return `[Acting as persona "${r.label}" for this message]
|
|
32444
|
-
${safe}`;
|
|
32445
|
-
});
|
|
32446
|
-
return {
|
|
32447
|
-
systemReminder: `<system-reminder>
|
|
32448
|
-
${blocks.join("\n\n")}
|
|
32449
|
-
</system-reminder>`,
|
|
32450
|
-
userText: body.trim()
|
|
32451
|
-
};
|
|
32452
|
-
}
|
|
32453
|
-
|
|
32454
32872
|
// src/session/runner.ts
|
|
32455
32873
|
var DEFAULT_CONTROL_REQUEST_TIMEOUT_MS = 1e4;
|
|
32456
32874
|
function encodeAllowWithInputControlResponse(requestId, updatedInput) {
|
|
@@ -32499,7 +32917,6 @@ var SessionRunner = class {
|
|
|
32499
32917
|
}
|
|
32500
32918
|
// 外部推送 input 到 reducer,然后执行产出的 effects
|
|
32501
32919
|
input(inputMsg) {
|
|
32502
|
-
const personaStore = this.hooks.personaStore;
|
|
32503
32920
|
const adapter = this.hooks.adapter;
|
|
32504
32921
|
const deps = {
|
|
32505
32922
|
// file-sharing (spec §6 PR 3):在 stdout-line 解析时同步观察 file-edit 工具事件,
|
|
@@ -32509,20 +32926,10 @@ var SessionRunner = class {
|
|
|
32509
32926
|
if (this.hooks.onFileEdit) this.observeForFileEdit(events);
|
|
32510
32927
|
return events;
|
|
32511
32928
|
},
|
|
32512
|
-
//
|
|
32513
|
-
//
|
|
32514
|
-
//
|
|
32515
|
-
|
|
32516
|
-
// - 第二条正常用户气泡,刷新页面不再暴露 personality 文本。
|
|
32517
|
-
encodeStdin: (t, ctx) => {
|
|
32518
|
-
if (!personaStore) return adapter.encodeStdin(t, ctx) ?? "";
|
|
32519
|
-
const { systemReminder, userText } = injectPersonaMentions(t, personaStore);
|
|
32520
|
-
if (systemReminder === null) return adapter.encodeStdin(userText, ctx) ?? "";
|
|
32521
|
-
const metaFrame = adapter.encodeStdin(systemReminder, ctx) ?? "";
|
|
32522
|
-
if (userText === "") return metaFrame;
|
|
32523
|
-
const userFrame = adapter.encodeStdin(userText, ctx) ?? "";
|
|
32524
|
-
return metaFrame + userFrame;
|
|
32525
|
-
},
|
|
32929
|
+
// Persona dispatch (Task 9):原 in-place `@persona/<id>` 注入路径已删,cc 自己看到字面
|
|
32930
|
+
// token 会调 personaDispatch MCP tool 委派(dispatch.mcp.json 通过 cc --mcp-config 加载,
|
|
32931
|
+
// CLAUDE.md 教 cc 触发条件)。encodeStdin 现在是 adapter 的简单 passthrough。
|
|
32932
|
+
encodeStdin: (t, ctx) => adapter.encodeStdin(t, ctx) ?? "",
|
|
32526
32933
|
bufferCap: this.hooks.bufferCap ?? 500,
|
|
32527
32934
|
now: this.hooks.now ?? Date.now,
|
|
32528
32935
|
resolveContextWindow: this.hooks.resolveContextWindow,
|
|
@@ -32532,6 +32939,10 @@ var SessionRunner = class {
|
|
|
32532
32939
|
// 单栏 refactor (spec 2026-06-02 §5.1): cc 子进程 env 注入 CLAWD_DAEMON_URL,让 assistant
|
|
32533
32940
|
// curl daemon HTTP RPC adapter (/api/rpc/<method>) 触发管理操作。null = HTTP adapter 未启。
|
|
32534
32941
|
getDaemonUrl: this.hooks.getDaemonUrl,
|
|
32942
|
+
// Persona dispatch:透传 dispatch.mcp.json 路径闭包 + B→dispatchId 反查闭包。
|
|
32943
|
+
// 见 reducer.buildSpawnContext 注 CLAWD_DISPATCH_ID env / 派生 SpawnContext.dispatchMcpConfigPath
|
|
32944
|
+
getDispatchMcpConfigPath: this.hooks.getDispatchMcpConfigPath,
|
|
32945
|
+
lookupDispatchByBSessionId: this.hooks.lookupDispatchByBSessionId,
|
|
32535
32946
|
// ReadyGate v2:透传 mode 让 reducer send / ready-detected 分支决定走暂存队列还是直写
|
|
32536
32947
|
mode: this.hooks.mode,
|
|
32537
32948
|
// [RG-DBG] 注入 logger 让 reducer rgDbg 走 pino 进 clawd.log;定位完跟 rgDbg 一起删
|
|
@@ -32991,6 +33402,22 @@ function nowIso2(deps) {
|
|
|
32991
33402
|
function newSessionId() {
|
|
32992
33403
|
return v4_default().replace(/-/g, "").slice(0, 16);
|
|
32993
33404
|
}
|
|
33405
|
+
function buildDispatchTaskPack(args) {
|
|
33406
|
+
return `[Dispatched from owner \u2014 another persona session\u59D4\u6D3E\u7ED9\u4F60\u6267\u884C\u4EFB\u52A1]
|
|
33407
|
+
|
|
33408
|
+
Task:
|
|
33409
|
+
${args.prompt}
|
|
33410
|
+
|
|
33411
|
+
Source conversation (jsonl, CC stream-json format, one message per line):
|
|
33412
|
+
${args.sourceJsonlPath}
|
|
33413
|
+
You may read this file with your Read tool to understand context. You do not have to read it all.
|
|
33414
|
+
|
|
33415
|
+
When done, call the MCP tool \`mcp__clawd-dispatch__personaDispatchComplete\` with your result:
|
|
33416
|
+
- Success: { text: "...", filePaths?: ["abs/path", ...] }
|
|
33417
|
+
- Failure: { isFailure: true, reason: "..." }
|
|
33418
|
+
|
|
33419
|
+
dispatchId for this task: ${args.dispatchId}`;
|
|
33420
|
+
}
|
|
32994
33421
|
function derivePersonaSpawnCwd(file, personaRoot) {
|
|
32995
33422
|
const personaId = file.ownerPersonaId;
|
|
32996
33423
|
if (!personaId) return file.cwd;
|
|
@@ -33288,7 +33715,8 @@ var SessionManager = class {
|
|
|
33288
33715
|
// adapter 自己持有模型表 + 兜底逻辑(contains / opus-1M / [1m] 等),manager 不再 cache 转发
|
|
33289
33716
|
resolveContextWindow: (tool, modelId) => this.deps.getAdapter(tool).resolveContextWindow(modelId),
|
|
33290
33717
|
dataDir: this.deps.dataDir,
|
|
33291
|
-
personaStore
|
|
33718
|
+
// personaStore 不再透给 runner hooks(in-place mention 注入路径已删,runner 不用);
|
|
33719
|
+
// manager 自身的 sandbox 派生仍直接读 this.deps.personaStore。
|
|
33292
33720
|
ownerDisplayName: this.deps.ownerDisplayName,
|
|
33293
33721
|
// Phase 2 capability platform (plan §3): 透传 personaRoot, buildSpawnArgs 据
|
|
33294
33722
|
// cwd 是否在 personaRoot 下自动决定是否注入 --settings sandbox-settings.json.
|
|
@@ -33296,6 +33724,10 @@ var SessionManager = class {
|
|
|
33296
33724
|
// 单栏 refactor (spec 2026-06-02 §5.1): 透传 daemon HTTP RPC base URL 闭包,
|
|
33297
33725
|
// reducer 把它注入 cc 子进程 env CLAWD_DAEMON_URL.
|
|
33298
33726
|
getDaemonUrl: this.deps.getDaemonUrl,
|
|
33727
|
+
// Persona dispatch (Task 7): dispatch.mcp.json 路径 + B sessionId → dispatchId 反查
|
|
33728
|
+
// 闭包透传给 reducer,让 cc spawn 加 --mcp-config flag + B session 注 CLAWD_DISPATCH_ID env.
|
|
33729
|
+
getDispatchMcpConfigPath: this.deps.dispatchMcpConfigPath ? () => this.deps.dispatchMcpConfigPath ?? null : void 0,
|
|
33730
|
+
lookupDispatchByBSessionId: this.deps.personaDispatchManager ? (bSid) => this.deps.personaDispatchManager?.lookupDispatchByBSessionId(bSid) : void 0,
|
|
33299
33731
|
// file-sharing (spec §6 PR 3):闭包 scope + sessionId,runner 只暴露 tool/relPath/cwd
|
|
33300
33732
|
onFileEdit: attachmentGroup ? (input) => attachmentGroup.onFileEdit({
|
|
33301
33733
|
scope,
|
|
@@ -33511,15 +33943,20 @@ var SessionManager = class {
|
|
|
33511
33943
|
// 强制走 deps.store(即 default scope),不走 scopeForFile:mirror 物理落 default 即可。
|
|
33512
33944
|
// 远端 creator / origin 字段原值保留(不被本机 ctx 派生覆写)。
|
|
33513
33945
|
//
|
|
33514
|
-
// strip 远端 personaId:mirror SessionFile
|
|
33515
|
-
//
|
|
33516
|
-
//
|
|
33946
|
+
// strip 远端 personaId / dispatchedFromSessionId:mirror SessionFile 上这两个字段都指向
|
|
33947
|
+
// 朋友 daemon 上的本地 id,本机不持有对应 persona / 源 session。留着会让按这些字段反查的
|
|
33948
|
+
// 本机消费者(MyPersonasSection 按 ownerPersonaId 反查 persona、sidebar 按
|
|
33949
|
+
// dispatchedFromSessionId 折叠 sub-session)走错分支。写入前清掉。#750 一族防线。
|
|
33517
33950
|
//
|
|
33518
33951
|
// 与 manager.create / manager.update 区别:
|
|
33519
33952
|
// - 不走 newRunner / attachObserver / cwd 校验(mirror 是纯 metadata 层)
|
|
33520
33953
|
// - 不发 session:info 帧(manager.create / .update 通过 reducer/wireCollector 发 push)
|
|
33521
33954
|
mirrorUpsert(file) {
|
|
33522
|
-
const {
|
|
33955
|
+
const {
|
|
33956
|
+
ownerPersonaId: _strippedPid,
|
|
33957
|
+
dispatchedFromSessionId: _strippedDsp,
|
|
33958
|
+
...rest
|
|
33959
|
+
} = file;
|
|
33523
33960
|
return this.deps.store.write(rest);
|
|
33524
33961
|
}
|
|
33525
33962
|
// mirror peer sessions:删本机 mirror SessionFile。mirror 一律落 default(mirrorUpsert
|
|
@@ -34104,6 +34541,66 @@ var SessionManager = class {
|
|
|
34104
34541
|
this.runners.set(file.sessionId, runner);
|
|
34105
34542
|
return runner;
|
|
34106
34543
|
}
|
|
34544
|
+
/**
|
|
34545
|
+
* Persona dispatch: 启动 B session 并投递任务包当第一条 user message。
|
|
34546
|
+
*
|
|
34547
|
+
* - 复用 persona-owner 创建路径(cwd=personaDir、scope=persona-owner、不沙箱)
|
|
34548
|
+
* - SessionFile 上写 dispatchedFromSessionId 关联回 A(UI 折叠用;mirror 一侧 strip)
|
|
34549
|
+
* - 跟 PersonaDispatchManager 双向登记 dispatchId ↔ B sessionId,让后续 reducer
|
|
34550
|
+
* buildSpawnContext 能反查到 dispatchId 注 CLAWD_DISPATCH_ID env
|
|
34551
|
+
* - 投 inject-owner-text 任务包;包尾教 B 用 personaDispatchComplete tool 回传
|
|
34552
|
+
*
|
|
34553
|
+
* cwd 派生与 SessionManager.create 的 owner persona 路径一致(derivePersonaSpawnCwd)。
|
|
34554
|
+
*/
|
|
34555
|
+
createDispatchedSession(args) {
|
|
34556
|
+
if (!this.deps.personaRoot) {
|
|
34557
|
+
throw new Error("createDispatchedSession: personaRoot missing in ManagerDeps");
|
|
34558
|
+
}
|
|
34559
|
+
if (!this.deps.personaDispatchManager) {
|
|
34560
|
+
throw new Error("createDispatchedSession: personaDispatchManager missing in ManagerDeps");
|
|
34561
|
+
}
|
|
34562
|
+
const sessionId = newSessionId();
|
|
34563
|
+
const scope = {
|
|
34564
|
+
kind: "persona",
|
|
34565
|
+
personaId: args.targetPersona,
|
|
34566
|
+
mode: "owner"
|
|
34567
|
+
};
|
|
34568
|
+
const cwd = import_node_path6.default.join(this.deps.personaRoot, safeFileName(args.targetPersona));
|
|
34569
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
34570
|
+
const file = {
|
|
34571
|
+
sessionId,
|
|
34572
|
+
cwd,
|
|
34573
|
+
tool: "claude",
|
|
34574
|
+
ownerPersonaId: args.targetPersona,
|
|
34575
|
+
dispatchedFromSessionId: args.sourceSessionId,
|
|
34576
|
+
createdAt: now,
|
|
34577
|
+
updatedAt: now
|
|
34578
|
+
};
|
|
34579
|
+
this.storeFor(scope).write(file);
|
|
34580
|
+
this.deps.personaDispatchManager.registerBSession(args.dispatchId, sessionId);
|
|
34581
|
+
this.deps.logger?.info("dispatch.createDispatchedSession.file-written", {
|
|
34582
|
+
dispatchId: args.dispatchId,
|
|
34583
|
+
bSessionId: sessionId,
|
|
34584
|
+
targetPersona: args.targetPersona,
|
|
34585
|
+
cwd
|
|
34586
|
+
});
|
|
34587
|
+
const runner = this.ensureRunnerForScope(file, scope);
|
|
34588
|
+
this.deps.logger?.info("dispatch.createDispatchedSession.runner-ready", {
|
|
34589
|
+
dispatchId: args.dispatchId,
|
|
34590
|
+
bSessionId: sessionId
|
|
34591
|
+
});
|
|
34592
|
+
const taskPack = buildDispatchTaskPack({
|
|
34593
|
+
prompt: args.prompt,
|
|
34594
|
+
sourceJsonlPath: args.sourceJsonlPath,
|
|
34595
|
+
dispatchId: args.dispatchId
|
|
34596
|
+
});
|
|
34597
|
+
runner.input({ kind: "command", command: { kind: "send", text: taskPack } });
|
|
34598
|
+
this.deps.logger?.info("dispatch.createDispatchedSession.task-pack-sent", {
|
|
34599
|
+
dispatchId: args.dispatchId,
|
|
34600
|
+
bSessionId: sessionId
|
|
34601
|
+
});
|
|
34602
|
+
return { sessionId };
|
|
34603
|
+
}
|
|
34107
34604
|
/**
|
|
34108
34605
|
* 老板插话:把 'inject-owner-text' input 喂给对应 runner,
|
|
34109
34606
|
* runner 不存在时按 scope 懒创建。
|
|
@@ -35316,6 +35813,56 @@ function migrateCodexSandbox(args) {
|
|
|
35316
35813
|
}
|
|
35317
35814
|
if (n > 0) args.logger.info("persona.codex-sandbox.done", { migrated: n });
|
|
35318
35815
|
}
|
|
35816
|
+
function findDeployKitRoot() {
|
|
35817
|
+
const candidates = [];
|
|
35818
|
+
try {
|
|
35819
|
+
const here = path11.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
|
|
35820
|
+
candidates.push(path11.resolve(here, "..", "deploy-kit"));
|
|
35821
|
+
} catch {
|
|
35822
|
+
}
|
|
35823
|
+
if (process.argv[1]) {
|
|
35824
|
+
candidates.push(path11.resolve(path11.dirname(process.argv[1]), "deploy-kit"));
|
|
35825
|
+
}
|
|
35826
|
+
for (const c of candidates) {
|
|
35827
|
+
try {
|
|
35828
|
+
if (fs9.statSync(c).isDirectory()) return c;
|
|
35829
|
+
} catch {
|
|
35830
|
+
}
|
|
35831
|
+
}
|
|
35832
|
+
return null;
|
|
35833
|
+
}
|
|
35834
|
+
function seedDeployKit(args) {
|
|
35835
|
+
const dst = path11.join(args.dataDir, "deploy-kit");
|
|
35836
|
+
fs9.cpSync(args.deployKitBundleRoot, dst, {
|
|
35837
|
+
recursive: true,
|
|
35838
|
+
dereference: true,
|
|
35839
|
+
force: false,
|
|
35840
|
+
errorOnExist: false
|
|
35841
|
+
});
|
|
35842
|
+
args.logger.info("deploy-kit.seed.done", { dst });
|
|
35843
|
+
}
|
|
35844
|
+
function refreshDeployKit(args) {
|
|
35845
|
+
const dst = path11.join(args.dataDir, "deploy-kit");
|
|
35846
|
+
if (!fs9.existsSync(dst)) {
|
|
35847
|
+
seedDeployKit(args);
|
|
35848
|
+
return;
|
|
35849
|
+
}
|
|
35850
|
+
for (const sub of ["scripts", "contract"]) {
|
|
35851
|
+
const s = path11.join(args.deployKitBundleRoot, sub);
|
|
35852
|
+
if (fs9.existsSync(s)) {
|
|
35853
|
+
fs9.cpSync(s, path11.join(dst, sub), { recursive: true, force: true, dereference: true });
|
|
35854
|
+
}
|
|
35855
|
+
}
|
|
35856
|
+
const secretsSrc = path11.join(args.deployKitBundleRoot, ".secrets");
|
|
35857
|
+
if (fs9.existsSync(secretsSrc)) {
|
|
35858
|
+
fs9.mkdirSync(path11.join(dst, ".secrets"), { recursive: true });
|
|
35859
|
+
for (const f of fs9.readdirSync(secretsSrc)) {
|
|
35860
|
+
if (!f.endsWith(".example")) continue;
|
|
35861
|
+
fs9.copyFileSync(path11.join(secretsSrc, f), path11.join(dst, ".secrets", f));
|
|
35862
|
+
}
|
|
35863
|
+
}
|
|
35864
|
+
args.logger.info("deploy-kit.refresh.done", { dst });
|
|
35865
|
+
}
|
|
35319
35866
|
|
|
35320
35867
|
// src/index.ts
|
|
35321
35868
|
init_claude();
|
|
@@ -35570,8 +36117,8 @@ function turnStartInput(text) {
|
|
|
35570
36117
|
const items = [];
|
|
35571
36118
|
let leftover = text;
|
|
35572
36119
|
for (const m2 of text.matchAll(SKILL_RE)) {
|
|
35573
|
-
const [marker, name,
|
|
35574
|
-
items.push({ type: "skill", name, path:
|
|
36120
|
+
const [marker, name, path59] = m2;
|
|
36121
|
+
items.push({ type: "skill", name, path: path59 });
|
|
35575
36122
|
leftover = leftover.replace(marker, "");
|
|
35576
36123
|
}
|
|
35577
36124
|
for (const m2 of text.matchAll(ATTACHMENT_RE2)) {
|
|
@@ -36222,7 +36769,7 @@ init_claude_history();
|
|
|
36222
36769
|
|
|
36223
36770
|
// src/pty/pty-child-process.ts
|
|
36224
36771
|
var import_node_events = require("events");
|
|
36225
|
-
var
|
|
36772
|
+
var import_node_stream2 = require("stream");
|
|
36226
36773
|
var PtyChildProcess = class extends import_node_events.EventEmitter {
|
|
36227
36774
|
constructor(pty, opts = {}) {
|
|
36228
36775
|
super();
|
|
@@ -36251,7 +36798,7 @@ var PtyChildProcess = class extends import_node_events.EventEmitter {
|
|
|
36251
36798
|
pty.write(data);
|
|
36252
36799
|
}
|
|
36253
36800
|
};
|
|
36254
|
-
this.stdin = new
|
|
36801
|
+
this.stdin = new import_node_stream2.Writable({
|
|
36255
36802
|
decodeStrings: false,
|
|
36256
36803
|
write: (chunk, _enc, cb) => {
|
|
36257
36804
|
const s = typeof chunk === "string" ? chunk : chunk.toString("utf8");
|
|
@@ -36270,7 +36817,7 @@ var PtyChildProcess = class extends import_node_events.EventEmitter {
|
|
|
36270
36817
|
}
|
|
36271
36818
|
}
|
|
36272
36819
|
});
|
|
36273
|
-
this.stdout = new
|
|
36820
|
+
this.stdout = new import_node_stream2.Readable({ read() {
|
|
36274
36821
|
} });
|
|
36275
36822
|
pty.onData((data) => {
|
|
36276
36823
|
if (!this.firstDataLogged) {
|
|
@@ -36283,7 +36830,7 @@ var PtyChildProcess = class extends import_node_events.EventEmitter {
|
|
|
36283
36830
|
}
|
|
36284
36831
|
this.stdout.push(Buffer.from(data, "utf8"));
|
|
36285
36832
|
});
|
|
36286
|
-
this.stderr = new
|
|
36833
|
+
this.stderr = new import_node_stream2.Readable({ read() {
|
|
36287
36834
|
} });
|
|
36288
36835
|
pty.onExit(({ exitCode, signal }) => {
|
|
36289
36836
|
this.exitCode = exitCode;
|
|
@@ -36798,6 +37345,9 @@ function buildTuiSpawnArgs(ctx, isResume = false) {
|
|
|
36798
37345
|
if (ctx.addDirs) {
|
|
36799
37346
|
for (const dir of ctx.addDirs) args.push("--add-dir", dir);
|
|
36800
37347
|
}
|
|
37348
|
+
if (ctx.dispatchMcpConfigPath) {
|
|
37349
|
+
args.push("--mcp-config", ctx.dispatchMcpConfigPath);
|
|
37350
|
+
}
|
|
36801
37351
|
if (ctx.effort) args.push("--effort", ctx.effort);
|
|
36802
37352
|
return args;
|
|
36803
37353
|
}
|
|
@@ -36815,6 +37365,155 @@ function jsonlExistsForCtx(ctx) {
|
|
|
36815
37365
|
// src/index.ts
|
|
36816
37366
|
init_claude_history();
|
|
36817
37367
|
|
|
37368
|
+
// src/dispatch/manager.ts
|
|
37369
|
+
function defer() {
|
|
37370
|
+
let resolve6;
|
|
37371
|
+
const promise = new Promise((r) => {
|
|
37372
|
+
resolve6 = r;
|
|
37373
|
+
});
|
|
37374
|
+
return { promise, resolve: resolve6 };
|
|
37375
|
+
}
|
|
37376
|
+
var PersonaDispatchManager = class {
|
|
37377
|
+
constructor(deps) {
|
|
37378
|
+
this.deps = deps;
|
|
37379
|
+
}
|
|
37380
|
+
deps;
|
|
37381
|
+
map = /* @__PURE__ */ new Map();
|
|
37382
|
+
start(args) {
|
|
37383
|
+
const dispatchId = this.deps.genId();
|
|
37384
|
+
this.map.set(dispatchId, {
|
|
37385
|
+
dispatchId,
|
|
37386
|
+
sourceSessionId: args.sourceSessionId,
|
|
37387
|
+
targetPersona: args.targetPersona,
|
|
37388
|
+
waiters: [],
|
|
37389
|
+
outcome: null
|
|
37390
|
+
});
|
|
37391
|
+
return { dispatchId };
|
|
37392
|
+
}
|
|
37393
|
+
get(dispatchId) {
|
|
37394
|
+
return this.map.get(dispatchId);
|
|
37395
|
+
}
|
|
37396
|
+
async wait(dispatchId) {
|
|
37397
|
+
const state = this.map.get(dispatchId);
|
|
37398
|
+
if (!state) throw new Error(`unknown dispatchId: ${dispatchId}`);
|
|
37399
|
+
if (state.outcome) return state.outcome;
|
|
37400
|
+
const d = defer();
|
|
37401
|
+
state.waiters.push(d);
|
|
37402
|
+
return d.promise;
|
|
37403
|
+
}
|
|
37404
|
+
complete(dispatchId, outcome) {
|
|
37405
|
+
const state = this.map.get(dispatchId);
|
|
37406
|
+
if (!state) throw new Error(`unknown dispatchId: ${dispatchId}`);
|
|
37407
|
+
state.outcome = outcome;
|
|
37408
|
+
const waiters = state.waiters;
|
|
37409
|
+
state.waiters = [];
|
|
37410
|
+
for (const w2 of waiters) w2.resolve(outcome);
|
|
37411
|
+
}
|
|
37412
|
+
/** SessionManager 在 createDispatchedSession 时调,建立 dispatchId → B sessionId 映射 */
|
|
37413
|
+
registerBSession(dispatchId, bSessionId) {
|
|
37414
|
+
const state = this.map.get(dispatchId);
|
|
37415
|
+
if (!state) throw new Error(`unknown dispatchId: ${dispatchId}`);
|
|
37416
|
+
state.bSessionId = bSessionId;
|
|
37417
|
+
}
|
|
37418
|
+
/** reducer buildSpawnContext 调,按 B 的 sessionId 反查 dispatchId(用于注 CLAWD_DISPATCH_ID env) */
|
|
37419
|
+
lookupDispatchByBSessionId(bSessionId) {
|
|
37420
|
+
for (const state of this.map.values()) {
|
|
37421
|
+
if (state.bSessionId === bSessionId) return state.dispatchId;
|
|
37422
|
+
}
|
|
37423
|
+
return void 0;
|
|
37424
|
+
}
|
|
37425
|
+
};
|
|
37426
|
+
|
|
37427
|
+
// src/dispatch/mcp-config.ts
|
|
37428
|
+
var import_node_fs12 = __toESM(require("fs"), 1);
|
|
37429
|
+
var import_node_path10 = __toESM(require("path"), 1);
|
|
37430
|
+
function dispatchMcpConfigPath(dataDir) {
|
|
37431
|
+
return import_node_path10.default.join(dataDir, "dispatch.mcp.json");
|
|
37432
|
+
}
|
|
37433
|
+
function writeDispatchMcpConfig(args) {
|
|
37434
|
+
const cfgPath = dispatchMcpConfigPath(args.dataDir);
|
|
37435
|
+
const content = {
|
|
37436
|
+
_comment: "daemon \u542F\u52A8\u65F6\u81EA\u52A8\u751F\u6210\uFF1Bcc spawn \u901A\u8FC7 --mcp-config \u6CE8\u5165\u3002dispatch-mcp-server.cjs \u662F daemon \u81EA\u5E26\u7684 stdio MCP server\u3002env.CLAWD_DISPATCH_LOG \u6307 server \u5199\u65E5\u5FD7\u7684 append \u6587\u4EF6\u8DEF\u5F84\uFF08dispatch \u6D41\u7A0B\u8282\u70B9 + fetch \u9519\u8BEF\u7EC6\u8282\uFF09\u3002",
|
|
37437
|
+
mcpServers: {
|
|
37438
|
+
"clawd-dispatch": {
|
|
37439
|
+
type: "stdio",
|
|
37440
|
+
command: "node",
|
|
37441
|
+
args: [args.serverScriptPath],
|
|
37442
|
+
...args.logPath ? { env: { CLAWD_DISPATCH_LOG: args.logPath } } : {}
|
|
37443
|
+
}
|
|
37444
|
+
}
|
|
37445
|
+
};
|
|
37446
|
+
import_node_fs12.default.mkdirSync(args.dataDir, { recursive: true });
|
|
37447
|
+
import_node_fs12.default.writeFileSync(cfgPath, JSON.stringify(content, null, 2), "utf8");
|
|
37448
|
+
return cfgPath;
|
|
37449
|
+
}
|
|
37450
|
+
|
|
37451
|
+
// src/handlers/persona-dispatch.ts
|
|
37452
|
+
init_protocol();
|
|
37453
|
+
function buildPersonaDispatchHandlers(deps) {
|
|
37454
|
+
const { personaDispatchManager: mgr, spawnB, logger } = deps;
|
|
37455
|
+
const run = async (frame) => {
|
|
37456
|
+
const { type: _t, requestId: _r, ...rest } = frame;
|
|
37457
|
+
const sourceSessionId = typeof rest.sessionId === "string" ? rest.sessionId : void 0;
|
|
37458
|
+
const args = DispatchRunArgsSchema.parse(rest);
|
|
37459
|
+
if (!sourceSessionId) {
|
|
37460
|
+
throw new Error(
|
|
37461
|
+
"personaDispatch:run requires sessionId (caller must pass x-clawd-session-id header)"
|
|
37462
|
+
);
|
|
37463
|
+
}
|
|
37464
|
+
const { dispatchId } = mgr.start({
|
|
37465
|
+
sourceSessionId,
|
|
37466
|
+
targetPersona: args.targetPersona
|
|
37467
|
+
});
|
|
37468
|
+
logger?.info("dispatch.run.received", {
|
|
37469
|
+
dispatchId,
|
|
37470
|
+
sourceSessionId,
|
|
37471
|
+
targetPersona: args.targetPersona,
|
|
37472
|
+
promptLen: args.prompt.length
|
|
37473
|
+
});
|
|
37474
|
+
void spawnB({
|
|
37475
|
+
dispatchId,
|
|
37476
|
+
sourceSessionId,
|
|
37477
|
+
targetPersona: args.targetPersona,
|
|
37478
|
+
prompt: args.prompt
|
|
37479
|
+
}).then(() => {
|
|
37480
|
+
logger?.info("dispatch.spawnB.ok", { dispatchId });
|
|
37481
|
+
}).catch((err) => {
|
|
37482
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
37483
|
+
logger?.warn("dispatch.spawnB.failed", { dispatchId, reason });
|
|
37484
|
+
mgr.complete(dispatchId, {
|
|
37485
|
+
kind: "failure",
|
|
37486
|
+
reason: `failed to spawn B: ${reason}`
|
|
37487
|
+
});
|
|
37488
|
+
});
|
|
37489
|
+
logger?.info("dispatch.run.waiting", { dispatchId });
|
|
37490
|
+
const outcome = await mgr.wait(dispatchId);
|
|
37491
|
+
logger?.info("dispatch.run.resolved", {
|
|
37492
|
+
dispatchId,
|
|
37493
|
+
outcomeKind: outcome.kind
|
|
37494
|
+
});
|
|
37495
|
+
return {
|
|
37496
|
+
response: { type: "personaDispatch:run:ok", outcome }
|
|
37497
|
+
};
|
|
37498
|
+
};
|
|
37499
|
+
const complete = async (frame) => {
|
|
37500
|
+
const { type: _t, requestId: _r, ...rest } = frame;
|
|
37501
|
+
const args = DispatchCompleteArgsSchema.parse(rest);
|
|
37502
|
+
logger?.info("dispatch.complete.received", {
|
|
37503
|
+
dispatchId: args.dispatchId,
|
|
37504
|
+
outcomeKind: args.outcome.kind
|
|
37505
|
+
});
|
|
37506
|
+
mgr.complete(args.dispatchId, args.outcome);
|
|
37507
|
+
return {
|
|
37508
|
+
response: { type: "personaDispatch:complete:ok" }
|
|
37509
|
+
};
|
|
37510
|
+
};
|
|
37511
|
+
return {
|
|
37512
|
+
"personaDispatch:run": run,
|
|
37513
|
+
"personaDispatch:complete": complete
|
|
37514
|
+
};
|
|
37515
|
+
}
|
|
37516
|
+
|
|
36818
37517
|
// src/tools/codex-history.ts
|
|
36819
37518
|
var import_node_child_process5 = require("child_process");
|
|
36820
37519
|
var DEFAULT_TIMEOUT_MS = 8e3;
|
|
@@ -37001,13 +37700,13 @@ function mapSkillsListResponse(res) {
|
|
|
37001
37700
|
const r = s ?? {};
|
|
37002
37701
|
const name = str3(r.name);
|
|
37003
37702
|
if (!name) continue;
|
|
37004
|
-
const
|
|
37703
|
+
const path59 = str3(r.path);
|
|
37005
37704
|
const description = str3(r.description);
|
|
37006
37705
|
const isPlugin = name.includes(":");
|
|
37007
37706
|
out.push({
|
|
37008
37707
|
name,
|
|
37009
37708
|
source: isPlugin ? "plugin" : "project",
|
|
37010
|
-
...
|
|
37709
|
+
...path59 ? { path: path59 } : {},
|
|
37011
37710
|
...description ? { description } : {},
|
|
37012
37711
|
...isPlugin ? { plugin: name.split(":")[0] } : {}
|
|
37013
37712
|
});
|
|
@@ -37046,23 +37745,23 @@ async function listCodexSkills(cwd, deps = {}) {
|
|
|
37046
37745
|
}
|
|
37047
37746
|
|
|
37048
37747
|
// src/workspace/browser.ts
|
|
37049
|
-
var
|
|
37748
|
+
var import_node_fs13 = __toESM(require("fs"), 1);
|
|
37050
37749
|
var import_node_os6 = __toESM(require("os"), 1);
|
|
37051
|
-
var
|
|
37750
|
+
var import_node_path11 = __toESM(require("path"), 1);
|
|
37052
37751
|
init_protocol();
|
|
37053
37752
|
var MAX_FILE_BYTES = 2 * 1024 * 1024;
|
|
37054
37753
|
function resolveInsideCwd(cwd, subpath) {
|
|
37055
|
-
const absCwd =
|
|
37056
|
-
const joined =
|
|
37057
|
-
const rel =
|
|
37058
|
-
if (rel.startsWith("..") ||
|
|
37754
|
+
const absCwd = import_node_path11.default.resolve(cwd);
|
|
37755
|
+
const joined = import_node_path11.default.resolve(absCwd, subpath ?? ".");
|
|
37756
|
+
const rel = import_node_path11.default.relative(absCwd, joined);
|
|
37757
|
+
if (rel.startsWith("..") || import_node_path11.default.isAbsolute(rel)) {
|
|
37059
37758
|
throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
|
|
37060
37759
|
}
|
|
37061
37760
|
return joined;
|
|
37062
37761
|
}
|
|
37063
37762
|
function ensureCwd(cwd) {
|
|
37064
37763
|
try {
|
|
37065
|
-
const stat =
|
|
37764
|
+
const stat = import_node_fs13.default.statSync(cwd);
|
|
37066
37765
|
if (!stat.isDirectory()) {
|
|
37067
37766
|
throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${cwd}`);
|
|
37068
37767
|
}
|
|
@@ -37076,7 +37775,7 @@ var WorkspaceBrowser = class {
|
|
|
37076
37775
|
const cwd = args.cwd && args.cwd.length > 0 ? args.cwd : import_node_os6.default.homedir();
|
|
37077
37776
|
ensureCwd(cwd);
|
|
37078
37777
|
const full = resolveInsideCwd(cwd, args.path);
|
|
37079
|
-
const dirents =
|
|
37778
|
+
const dirents = import_node_fs13.default.readdirSync(full, { withFileTypes: true });
|
|
37080
37779
|
const entries = [];
|
|
37081
37780
|
for (const d of dirents) {
|
|
37082
37781
|
if (!args.showHidden && d.name.startsWith(".")) continue;
|
|
@@ -37086,7 +37785,7 @@ var WorkspaceBrowser = class {
|
|
|
37086
37785
|
mtime: ""
|
|
37087
37786
|
};
|
|
37088
37787
|
try {
|
|
37089
|
-
const st =
|
|
37788
|
+
const st = import_node_fs13.default.statSync(import_node_path11.default.join(full, d.name));
|
|
37090
37789
|
entry.mtime = new Date(st.mtimeMs).toISOString();
|
|
37091
37790
|
if (d.isFile()) entry.size = st.size;
|
|
37092
37791
|
} catch {
|
|
@@ -37102,14 +37801,14 @@ var WorkspaceBrowser = class {
|
|
|
37102
37801
|
read(args) {
|
|
37103
37802
|
ensureCwd(args.cwd);
|
|
37104
37803
|
const full = resolveInsideCwd(args.cwd, args.path);
|
|
37105
|
-
const st =
|
|
37804
|
+
const st = import_node_fs13.default.statSync(full);
|
|
37106
37805
|
if (!st.isFile()) {
|
|
37107
37806
|
throw new ClawdError(ERROR_CODES.INVALID_PATH, `not a file: ${args.path}`);
|
|
37108
37807
|
}
|
|
37109
37808
|
if (st.size > MAX_FILE_BYTES) {
|
|
37110
37809
|
throw new ClawdError(ERROR_CODES.FILE_TOO_LARGE, `file > ${MAX_FILE_BYTES} bytes`);
|
|
37111
37810
|
}
|
|
37112
|
-
const buf =
|
|
37811
|
+
const buf = import_node_fs13.default.readFileSync(full);
|
|
37113
37812
|
const isBinary = buf.includes(0);
|
|
37114
37813
|
if (isBinary) {
|
|
37115
37814
|
return {
|
|
@@ -37131,20 +37830,20 @@ var WorkspaceBrowser = class {
|
|
|
37131
37830
|
};
|
|
37132
37831
|
|
|
37133
37832
|
// src/skills/agents-scanner.ts
|
|
37134
|
-
var
|
|
37833
|
+
var import_node_fs14 = __toESM(require("fs"), 1);
|
|
37135
37834
|
var import_node_os7 = __toESM(require("os"), 1);
|
|
37136
|
-
var
|
|
37835
|
+
var import_node_path12 = __toESM(require("path"), 1);
|
|
37137
37836
|
var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
|
|
37138
37837
|
function isDirLikeSync2(p2) {
|
|
37139
37838
|
try {
|
|
37140
|
-
return
|
|
37839
|
+
return import_node_fs14.default.statSync(p2).isDirectory();
|
|
37141
37840
|
} catch {
|
|
37142
37841
|
return false;
|
|
37143
37842
|
}
|
|
37144
37843
|
}
|
|
37145
37844
|
function fileExistsSync(p2) {
|
|
37146
37845
|
try {
|
|
37147
|
-
return
|
|
37846
|
+
return import_node_fs14.default.statSync(p2).isFile();
|
|
37148
37847
|
} catch {
|
|
37149
37848
|
return false;
|
|
37150
37849
|
}
|
|
@@ -37152,7 +37851,7 @@ function fileExistsSync(p2) {
|
|
|
37152
37851
|
function parseAgentFile(filePath) {
|
|
37153
37852
|
let content;
|
|
37154
37853
|
try {
|
|
37155
|
-
content =
|
|
37854
|
+
content = import_node_fs14.default.readFileSync(filePath, "utf8");
|
|
37156
37855
|
} catch {
|
|
37157
37856
|
return {};
|
|
37158
37857
|
}
|
|
@@ -37165,16 +37864,16 @@ function parseAgentFile(filePath) {
|
|
|
37165
37864
|
function scanAgentsDir(dir, source, seen, out) {
|
|
37166
37865
|
let entries;
|
|
37167
37866
|
try {
|
|
37168
|
-
entries =
|
|
37867
|
+
entries = import_node_fs14.default.readdirSync(dir, { withFileTypes: true });
|
|
37169
37868
|
} catch {
|
|
37170
37869
|
return;
|
|
37171
37870
|
}
|
|
37172
37871
|
for (const ent of entries) {
|
|
37173
37872
|
if (!ent.name.endsWith(".md")) continue;
|
|
37174
|
-
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(
|
|
37873
|
+
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path12.default.join(dir, ent.name)))) {
|
|
37175
37874
|
continue;
|
|
37176
37875
|
}
|
|
37177
|
-
const filePath =
|
|
37876
|
+
const filePath = import_node_path12.default.join(dir, ent.name);
|
|
37178
37877
|
const baseName = ent.name.replace(/\.md$/, "");
|
|
37179
37878
|
if (seen.has(baseName)) continue;
|
|
37180
37879
|
seen.add(baseName);
|
|
@@ -37192,12 +37891,12 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
37192
37891
|
function walk2(dir, namespaces) {
|
|
37193
37892
|
let entries;
|
|
37194
37893
|
try {
|
|
37195
|
-
entries =
|
|
37894
|
+
entries = import_node_fs14.default.readdirSync(dir, { withFileTypes: true });
|
|
37196
37895
|
} catch {
|
|
37197
37896
|
return;
|
|
37198
37897
|
}
|
|
37199
37898
|
for (const ent of entries) {
|
|
37200
|
-
const childPath =
|
|
37899
|
+
const childPath = import_node_path12.default.join(dir, ent.name);
|
|
37201
37900
|
if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
|
|
37202
37901
|
walk2(childPath, [...namespaces, ent.name]);
|
|
37203
37902
|
continue;
|
|
@@ -37222,13 +37921,13 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
37222
37921
|
walk2(root, []);
|
|
37223
37922
|
}
|
|
37224
37923
|
function readInstalledPlugins2(home) {
|
|
37225
|
-
const pluginsDir =
|
|
37226
|
-
const v2 =
|
|
37227
|
-
const v1 =
|
|
37924
|
+
const pluginsDir = import_node_path12.default.join(home, ".claude", "plugins");
|
|
37925
|
+
const v2 = import_node_path12.default.join(pluginsDir, "installed_plugins_v2.json");
|
|
37926
|
+
const v1 = import_node_path12.default.join(pluginsDir, "installed_plugins.json");
|
|
37228
37927
|
let raw = null;
|
|
37229
37928
|
for (const candidate of [v2, v1]) {
|
|
37230
37929
|
try {
|
|
37231
|
-
raw =
|
|
37930
|
+
raw = import_node_fs14.default.readFileSync(candidate, "utf8");
|
|
37232
37931
|
break;
|
|
37233
37932
|
} catch {
|
|
37234
37933
|
}
|
|
@@ -37253,19 +37952,19 @@ function readInstalledPlugins2(home) {
|
|
|
37253
37952
|
return out;
|
|
37254
37953
|
}
|
|
37255
37954
|
function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
|
|
37256
|
-
let cur =
|
|
37257
|
-
const fsRoot =
|
|
37955
|
+
let cur = import_node_path12.default.resolve(startCwd);
|
|
37956
|
+
const fsRoot = import_node_path12.default.parse(cur).root;
|
|
37258
37957
|
while (true) {
|
|
37259
|
-
scanAgentsDir(
|
|
37958
|
+
scanAgentsDir(import_node_path12.default.join(cur, ".claude", "agents"), "project", seen, out);
|
|
37260
37959
|
let hasGit = false;
|
|
37261
37960
|
try {
|
|
37262
|
-
hasGit =
|
|
37961
|
+
hasGit = import_node_fs14.default.existsSync(import_node_path12.default.join(cur, ".git"));
|
|
37263
37962
|
} catch {
|
|
37264
37963
|
}
|
|
37265
37964
|
if (hasGit) return;
|
|
37266
37965
|
if (cur === home) return;
|
|
37267
37966
|
if (cur === fsRoot) return;
|
|
37268
|
-
const parent =
|
|
37967
|
+
const parent = import_node_path12.default.dirname(cur);
|
|
37269
37968
|
if (parent === cur) return;
|
|
37270
37969
|
cur = parent;
|
|
37271
37970
|
}
|
|
@@ -37300,7 +37999,7 @@ var AgentsScanner = class {
|
|
|
37300
37999
|
}
|
|
37301
38000
|
const fsBlock = [];
|
|
37302
38001
|
scanAgentsDir(
|
|
37303
|
-
|
|
38002
|
+
import_node_path12.default.join(this.home, ".claude", "agents"),
|
|
37304
38003
|
"global",
|
|
37305
38004
|
seen,
|
|
37306
38005
|
fsBlock
|
|
@@ -37314,7 +38013,7 @@ var AgentsScanner = class {
|
|
|
37314
38013
|
...this.extraPluginRoots
|
|
37315
38014
|
];
|
|
37316
38015
|
for (const { name, root } of plugins) {
|
|
37317
|
-
const agentsRoot =
|
|
38016
|
+
const agentsRoot = import_node_path12.default.join(root, "agents");
|
|
37318
38017
|
scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
|
|
37319
38018
|
}
|
|
37320
38019
|
return [...builtinBlock, ...fsBlock];
|
|
@@ -37322,15 +38021,15 @@ var AgentsScanner = class {
|
|
|
37322
38021
|
};
|
|
37323
38022
|
|
|
37324
38023
|
// src/observer/session-observer.ts
|
|
37325
|
-
var
|
|
38024
|
+
var import_node_fs16 = __toESM(require("fs"), 1);
|
|
37326
38025
|
var import_node_os9 = __toESM(require("os"), 1);
|
|
37327
|
-
var
|
|
38026
|
+
var import_node_path14 = __toESM(require("path"), 1);
|
|
37328
38027
|
init_claude_history();
|
|
37329
38028
|
|
|
37330
38029
|
// src/observer/subagent-meta-observer.ts
|
|
37331
|
-
var
|
|
38030
|
+
var import_node_fs15 = __toESM(require("fs"), 1);
|
|
37332
38031
|
var import_node_os8 = __toESM(require("os"), 1);
|
|
37333
|
-
var
|
|
38032
|
+
var import_node_path13 = __toESM(require("path"), 1);
|
|
37334
38033
|
init_claude_history();
|
|
37335
38034
|
var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
|
|
37336
38035
|
var SubagentMetaObserver = class {
|
|
@@ -37343,7 +38042,7 @@ var SubagentMetaObserver = class {
|
|
|
37343
38042
|
watches = /* @__PURE__ */ new Map();
|
|
37344
38043
|
// public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
|
|
37345
38044
|
resolveSubagentDir(cwd, toolSessionId) {
|
|
37346
|
-
return
|
|
38045
|
+
return import_node_path13.default.join(
|
|
37347
38046
|
this.home,
|
|
37348
38047
|
".claude",
|
|
37349
38048
|
"projects",
|
|
@@ -37373,7 +38072,7 @@ var SubagentMetaObserver = class {
|
|
|
37373
38072
|
attachWatcher(w2) {
|
|
37374
38073
|
if (w2.watcher) return;
|
|
37375
38074
|
try {
|
|
37376
|
-
w2.watcher =
|
|
38075
|
+
w2.watcher = import_node_fs15.default.watch(w2.dirPath, { persistent: false }, (_evt, name) => {
|
|
37377
38076
|
if (!name) return;
|
|
37378
38077
|
const m2 = META_RE.exec(String(name));
|
|
37379
38078
|
if (!m2) return;
|
|
@@ -37385,7 +38084,7 @@ var SubagentMetaObserver = class {
|
|
|
37385
38084
|
scan(w2) {
|
|
37386
38085
|
let entries;
|
|
37387
38086
|
try {
|
|
37388
|
-
entries =
|
|
38087
|
+
entries = import_node_fs15.default.readdirSync(w2.dirPath);
|
|
37389
38088
|
} catch {
|
|
37390
38089
|
return;
|
|
37391
38090
|
}
|
|
@@ -37399,10 +38098,10 @@ var SubagentMetaObserver = class {
|
|
|
37399
38098
|
if (!m2) return;
|
|
37400
38099
|
const agentId = m2[1];
|
|
37401
38100
|
if (w2.emitted.has(agentId)) return;
|
|
37402
|
-
const file =
|
|
38101
|
+
const file = import_node_path13.default.join(w2.dirPath, name);
|
|
37403
38102
|
let raw;
|
|
37404
38103
|
try {
|
|
37405
|
-
raw =
|
|
38104
|
+
raw = import_node_fs15.default.readFileSync(file, "utf8");
|
|
37406
38105
|
} catch {
|
|
37407
38106
|
return;
|
|
37408
38107
|
}
|
|
@@ -37459,14 +38158,14 @@ var SessionObserver = class {
|
|
|
37459
38158
|
metaObserver;
|
|
37460
38159
|
resolveJsonlPath(cwd, toolSessionId, override) {
|
|
37461
38160
|
if (override) return override;
|
|
37462
|
-
return
|
|
38161
|
+
return import_node_path14.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
|
|
37463
38162
|
}
|
|
37464
38163
|
start(args) {
|
|
37465
38164
|
this.stop(args.sessionId);
|
|
37466
38165
|
const filePath = this.resolveJsonlPath(args.cwd, args.toolSessionId, args.jsonlPath);
|
|
37467
38166
|
let size = 0;
|
|
37468
38167
|
try {
|
|
37469
|
-
size =
|
|
38168
|
+
size = import_node_fs16.default.statSync(filePath).size;
|
|
37470
38169
|
} catch {
|
|
37471
38170
|
}
|
|
37472
38171
|
const w2 = {
|
|
@@ -37480,10 +38179,10 @@ var SessionObserver = class {
|
|
|
37480
38179
|
prevIsRejectSentinel: false
|
|
37481
38180
|
};
|
|
37482
38181
|
try {
|
|
37483
|
-
|
|
38182
|
+
import_node_fs16.default.mkdirSync(import_node_path14.default.dirname(filePath), { recursive: true });
|
|
37484
38183
|
} catch {
|
|
37485
38184
|
}
|
|
37486
|
-
w2.watcher =
|
|
38185
|
+
w2.watcher = import_node_fs16.default.watch(import_node_path14.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
|
|
37487
38186
|
if (!changedName || !filePath.endsWith(changedName)) return;
|
|
37488
38187
|
this.poll(w2);
|
|
37489
38188
|
});
|
|
@@ -37506,7 +38205,7 @@ var SessionObserver = class {
|
|
|
37506
38205
|
// 异常静默吞,不阻塞 watcher 启动
|
|
37507
38206
|
hydrateMetaTail(w2, maxLines = 200) {
|
|
37508
38207
|
try {
|
|
37509
|
-
const raw =
|
|
38208
|
+
const raw = import_node_fs16.default.readFileSync(w2.filePath, "utf8");
|
|
37510
38209
|
if (!raw) return;
|
|
37511
38210
|
const allLines = raw.split("\n").filter((l) => l.trim().length > 0);
|
|
37512
38211
|
if (allLines.length === 0) return;
|
|
@@ -37530,7 +38229,7 @@ var SessionObserver = class {
|
|
|
37530
38229
|
poll(w2) {
|
|
37531
38230
|
let size = 0;
|
|
37532
38231
|
try {
|
|
37533
|
-
size =
|
|
38232
|
+
size = import_node_fs16.default.statSync(w2.filePath).size;
|
|
37534
38233
|
} catch {
|
|
37535
38234
|
return;
|
|
37536
38235
|
}
|
|
@@ -37539,11 +38238,11 @@ var SessionObserver = class {
|
|
|
37539
38238
|
w2.buf = "";
|
|
37540
38239
|
}
|
|
37541
38240
|
if (size === w2.lastSize) return;
|
|
37542
|
-
const fd =
|
|
38241
|
+
const fd = import_node_fs16.default.openSync(w2.filePath, "r");
|
|
37543
38242
|
try {
|
|
37544
38243
|
const len = size - w2.lastSize;
|
|
37545
38244
|
const buf = Buffer.alloc(len);
|
|
37546
|
-
|
|
38245
|
+
import_node_fs16.default.readSync(fd, buf, 0, len, w2.lastSize);
|
|
37547
38246
|
w2.lastSize = size;
|
|
37548
38247
|
w2.buf += buf.toString("utf8");
|
|
37549
38248
|
let newlineIndex;
|
|
@@ -37566,7 +38265,7 @@ var SessionObserver = class {
|
|
|
37566
38265
|
}
|
|
37567
38266
|
}
|
|
37568
38267
|
} finally {
|
|
37569
|
-
|
|
38268
|
+
import_node_fs16.default.closeSync(fd);
|
|
37570
38269
|
}
|
|
37571
38270
|
}
|
|
37572
38271
|
// 解析 JSONL 单行:仅当是主链 user 文本行(非 sidechain / 非 sub-agent / message.role='user'
|
|
@@ -38289,14 +38988,14 @@ async function authenticate(token, deps) {
|
|
|
38289
38988
|
}
|
|
38290
38989
|
|
|
38291
38990
|
// src/permission/capability-store.ts
|
|
38292
|
-
var
|
|
38293
|
-
var
|
|
38991
|
+
var fs19 = __toESM(require("fs"), 1);
|
|
38992
|
+
var path19 = __toESM(require("path"), 1);
|
|
38294
38993
|
var CAPABILITIES_FILE_NAME = "capabilities.json";
|
|
38295
38994
|
var FILE_VERSION = 1;
|
|
38296
38995
|
var CapabilityStore = class {
|
|
38297
38996
|
constructor(dataDir) {
|
|
38298
38997
|
this.dataDir = dataDir;
|
|
38299
|
-
|
|
38998
|
+
fs19.mkdirSync(dataDir, { recursive: true });
|
|
38300
38999
|
this.cache = this.readFromDisk();
|
|
38301
39000
|
}
|
|
38302
39001
|
dataDir;
|
|
@@ -38320,13 +39019,13 @@ var CapabilityStore = class {
|
|
|
38320
39019
|
this.flush();
|
|
38321
39020
|
}
|
|
38322
39021
|
filePath() {
|
|
38323
|
-
return
|
|
39022
|
+
return path19.join(this.dataDir, CAPABILITIES_FILE_NAME);
|
|
38324
39023
|
}
|
|
38325
39024
|
readFromDisk() {
|
|
38326
39025
|
const file = this.filePath();
|
|
38327
39026
|
let raw;
|
|
38328
39027
|
try {
|
|
38329
|
-
raw =
|
|
39028
|
+
raw = fs19.readFileSync(file, "utf8");
|
|
38330
39029
|
} catch (err) {
|
|
38331
39030
|
if (err?.code === "ENOENT") return [];
|
|
38332
39031
|
return [];
|
|
@@ -38354,10 +39053,10 @@ var CapabilityStore = class {
|
|
|
38354
39053
|
}
|
|
38355
39054
|
atomicWrite(file, content) {
|
|
38356
39055
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
38357
|
-
|
|
38358
|
-
|
|
39056
|
+
fs19.writeFileSync(tmp, content, { mode: 384 });
|
|
39057
|
+
fs19.renameSync(tmp, file);
|
|
38359
39058
|
try {
|
|
38360
|
-
|
|
39059
|
+
fs19.chmodSync(file, 384);
|
|
38361
39060
|
} catch {
|
|
38362
39061
|
}
|
|
38363
39062
|
}
|
|
@@ -38450,14 +39149,14 @@ var CapabilityManager = class {
|
|
|
38450
39149
|
};
|
|
38451
39150
|
|
|
38452
39151
|
// src/permission/cleanup.ts
|
|
38453
|
-
var
|
|
39152
|
+
var fs20 = __toESM(require("fs"), 1);
|
|
38454
39153
|
function cleanupGuestSessionsForCapability(cap, factory) {
|
|
38455
39154
|
const removed = [];
|
|
38456
39155
|
for (const g2 of cap.grants) {
|
|
38457
39156
|
if (g2.resource.type !== "persona") continue;
|
|
38458
39157
|
const dir = factory.vmGuestRoot(g2.resource.id, cap.id);
|
|
38459
39158
|
try {
|
|
38460
|
-
|
|
39159
|
+
fs20.rmSync(dir, { recursive: true, force: true });
|
|
38461
39160
|
removed.push(dir);
|
|
38462
39161
|
} catch {
|
|
38463
39162
|
}
|
|
@@ -38466,13 +39165,13 @@ function cleanupGuestSessionsForCapability(cap, factory) {
|
|
|
38466
39165
|
}
|
|
38467
39166
|
|
|
38468
39167
|
// src/inbox/inbox-store.ts
|
|
38469
|
-
var
|
|
38470
|
-
var
|
|
39168
|
+
var fs21 = __toESM(require("fs"), 1);
|
|
39169
|
+
var path20 = __toESM(require("path"), 1);
|
|
38471
39170
|
var INBOX_SUBDIR = "inbox";
|
|
38472
39171
|
var InboxStore = class {
|
|
38473
39172
|
constructor(dataDir) {
|
|
38474
39173
|
this.dataDir = dataDir;
|
|
38475
|
-
|
|
39174
|
+
fs21.mkdirSync(this.dirPath(), { recursive: true });
|
|
38476
39175
|
}
|
|
38477
39176
|
dataDir;
|
|
38478
39177
|
/**
|
|
@@ -38484,7 +39183,7 @@ var InboxStore = class {
|
|
|
38484
39183
|
const file = this.filePath(peerDeviceId);
|
|
38485
39184
|
let raw;
|
|
38486
39185
|
try {
|
|
38487
|
-
raw =
|
|
39186
|
+
raw = fs21.readFileSync(file, "utf8");
|
|
38488
39187
|
} catch (err) {
|
|
38489
39188
|
if (err?.code === "ENOENT") return [];
|
|
38490
39189
|
return [];
|
|
@@ -38500,7 +39199,7 @@ var InboxStore = class {
|
|
|
38500
39199
|
const dir = this.dirPath();
|
|
38501
39200
|
let entries;
|
|
38502
39201
|
try {
|
|
38503
|
-
entries =
|
|
39202
|
+
entries = fs21.readdirSync(dir);
|
|
38504
39203
|
} catch (err) {
|
|
38505
39204
|
if (err?.code === "ENOENT") return [];
|
|
38506
39205
|
return [];
|
|
@@ -38516,9 +39215,9 @@ var InboxStore = class {
|
|
|
38516
39215
|
if (existing.some((m2) => m2.id === message.id)) return;
|
|
38517
39216
|
const file = this.filePath(message.peerDeviceId);
|
|
38518
39217
|
const line = JSON.stringify(message) + "\n";
|
|
38519
|
-
|
|
39218
|
+
fs21.appendFileSync(file, line, { mode: 384 });
|
|
38520
39219
|
try {
|
|
38521
|
-
|
|
39220
|
+
fs21.chmodSync(file, 384);
|
|
38522
39221
|
} catch {
|
|
38523
39222
|
}
|
|
38524
39223
|
}
|
|
@@ -38548,7 +39247,7 @@ var InboxStore = class {
|
|
|
38548
39247
|
removeByPeerDeviceId(peerDeviceId) {
|
|
38549
39248
|
const file = this.filePath(peerDeviceId);
|
|
38550
39249
|
try {
|
|
38551
|
-
|
|
39250
|
+
fs21.unlinkSync(file);
|
|
38552
39251
|
} catch (err) {
|
|
38553
39252
|
if (err?.code === "ENOENT") return;
|
|
38554
39253
|
}
|
|
@@ -38557,18 +39256,18 @@ var InboxStore = class {
|
|
|
38557
39256
|
const file = this.filePath(peerDeviceId);
|
|
38558
39257
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
38559
39258
|
const content = messages.map((m2) => JSON.stringify(m2)).join("\n") + (messages.length > 0 ? "\n" : "");
|
|
38560
|
-
|
|
38561
|
-
|
|
39259
|
+
fs21.writeFileSync(tmp, content, { mode: 384 });
|
|
39260
|
+
fs21.renameSync(tmp, file);
|
|
38562
39261
|
try {
|
|
38563
|
-
|
|
39262
|
+
fs21.chmodSync(file, 384);
|
|
38564
39263
|
} catch {
|
|
38565
39264
|
}
|
|
38566
39265
|
}
|
|
38567
39266
|
dirPath() {
|
|
38568
|
-
return
|
|
39267
|
+
return path20.join(this.dataDir, INBOX_SUBDIR);
|
|
38569
39268
|
}
|
|
38570
39269
|
filePath(peerDeviceId) {
|
|
38571
|
-
return
|
|
39270
|
+
return path20.join(this.dirPath(), `${peerDeviceId}.jsonl`);
|
|
38572
39271
|
}
|
|
38573
39272
|
};
|
|
38574
39273
|
function parseAllLines(raw) {
|
|
@@ -38655,8 +39354,8 @@ var InboxManager = class {
|
|
|
38655
39354
|
};
|
|
38656
39355
|
|
|
38657
39356
|
// src/state/contact-store.ts
|
|
38658
|
-
var
|
|
38659
|
-
var
|
|
39357
|
+
var fs22 = __toESM(require("fs"), 1);
|
|
39358
|
+
var path21 = __toESM(require("path"), 1);
|
|
38660
39359
|
var FILE_NAME = "contacts.json";
|
|
38661
39360
|
var ContactStore = class {
|
|
38662
39361
|
constructor(dataDir) {
|
|
@@ -38666,10 +39365,10 @@ var ContactStore = class {
|
|
|
38666
39365
|
contacts = /* @__PURE__ */ new Map();
|
|
38667
39366
|
load() {
|
|
38668
39367
|
this.contacts.clear();
|
|
38669
|
-
const file =
|
|
39368
|
+
const file = path21.join(this.dataDir, FILE_NAME);
|
|
38670
39369
|
let raw;
|
|
38671
39370
|
try {
|
|
38672
|
-
raw =
|
|
39371
|
+
raw = fs22.readFileSync(file, "utf8");
|
|
38673
39372
|
} catch (err) {
|
|
38674
39373
|
if (err?.code !== "ENOENT") this.renameBak(file);
|
|
38675
39374
|
return;
|
|
@@ -38712,20 +39411,20 @@ var ContactStore = class {
|
|
|
38712
39411
|
return existed;
|
|
38713
39412
|
}
|
|
38714
39413
|
flush() {
|
|
38715
|
-
const file =
|
|
39414
|
+
const file = path21.join(this.dataDir, FILE_NAME);
|
|
38716
39415
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
38717
39416
|
const content = JSON.stringify(
|
|
38718
39417
|
{ contacts: Array.from(this.contacts.values()) },
|
|
38719
39418
|
null,
|
|
38720
39419
|
2
|
|
38721
39420
|
);
|
|
38722
|
-
|
|
38723
|
-
|
|
38724
|
-
|
|
39421
|
+
fs22.mkdirSync(this.dataDir, { recursive: true });
|
|
39422
|
+
fs22.writeFileSync(tmp, content, { mode: 384 });
|
|
39423
|
+
fs22.renameSync(tmp, file);
|
|
38725
39424
|
}
|
|
38726
39425
|
renameBak(file) {
|
|
38727
39426
|
try {
|
|
38728
|
-
|
|
39427
|
+
fs22.renameSync(file, `${file}.bak`);
|
|
38729
39428
|
} catch {
|
|
38730
39429
|
}
|
|
38731
39430
|
}
|
|
@@ -38875,61 +39574,61 @@ async function autoReverseContact(args) {
|
|
|
38875
39574
|
}
|
|
38876
39575
|
|
|
38877
39576
|
// src/migrations/2026-05-20-flatten-sessions.ts
|
|
38878
|
-
var
|
|
38879
|
-
var
|
|
39577
|
+
var fs23 = __toESM(require("fs"), 1);
|
|
39578
|
+
var path22 = __toESM(require("path"), 1);
|
|
38880
39579
|
var MIGRATION_FLAG_NAME = ".migration.v1.done";
|
|
38881
39580
|
function migrateFlattenSessions(opts) {
|
|
38882
39581
|
const dataDir = opts.dataDir;
|
|
38883
39582
|
const now = opts.now ?? Date.now;
|
|
38884
|
-
const sessionsDir =
|
|
38885
|
-
const flagPath =
|
|
39583
|
+
const sessionsDir = path22.join(dataDir, "sessions");
|
|
39584
|
+
const flagPath = path22.join(sessionsDir, MIGRATION_FLAG_NAME);
|
|
38886
39585
|
if (existsSync3(flagPath)) {
|
|
38887
39586
|
return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
|
|
38888
39587
|
}
|
|
38889
39588
|
let movedBare = 0;
|
|
38890
39589
|
let movedVmOwner = 0;
|
|
38891
39590
|
let archivedListener = 0;
|
|
38892
|
-
const defaultDir =
|
|
39591
|
+
const defaultDir = path22.join(sessionsDir, "default");
|
|
38893
39592
|
if (existsSync3(defaultDir)) {
|
|
38894
39593
|
for (const entry of readdirSafe(defaultDir)) {
|
|
38895
39594
|
if (!entry.endsWith(".json")) continue;
|
|
38896
|
-
const src =
|
|
38897
|
-
const dst =
|
|
38898
|
-
|
|
39595
|
+
const src = path22.join(defaultDir, entry);
|
|
39596
|
+
const dst = path22.join(sessionsDir, entry);
|
|
39597
|
+
fs23.renameSync(src, dst);
|
|
38899
39598
|
movedBare += 1;
|
|
38900
39599
|
}
|
|
38901
39600
|
rmdirIfEmpty(defaultDir);
|
|
38902
39601
|
}
|
|
38903
39602
|
for (const pid of readdirSafe(sessionsDir)) {
|
|
38904
|
-
const personaDir =
|
|
39603
|
+
const personaDir = path22.join(sessionsDir, pid);
|
|
38905
39604
|
if (!isDir(personaDir)) continue;
|
|
38906
39605
|
if (pid === "default") continue;
|
|
38907
|
-
const ownerSrc =
|
|
39606
|
+
const ownerSrc = path22.join(personaDir, "owner");
|
|
38908
39607
|
if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
|
|
38909
|
-
const ownerDst =
|
|
38910
|
-
|
|
39608
|
+
const ownerDst = path22.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
|
|
39609
|
+
fs23.mkdirSync(ownerDst, { recursive: true });
|
|
38911
39610
|
for (const file of readdirSafe(ownerSrc)) {
|
|
38912
39611
|
if (!file.endsWith(".json")) continue;
|
|
38913
|
-
|
|
39612
|
+
fs23.renameSync(path22.join(ownerSrc, file), path22.join(ownerDst, file));
|
|
38914
39613
|
movedVmOwner += 1;
|
|
38915
39614
|
}
|
|
38916
39615
|
rmdirIfEmpty(ownerSrc);
|
|
38917
39616
|
}
|
|
38918
|
-
const listenerSrc =
|
|
39617
|
+
const listenerSrc = path22.join(personaDir, "listener");
|
|
38919
39618
|
if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
|
|
38920
|
-
const archiveDst =
|
|
38921
|
-
|
|
39619
|
+
const archiveDst = path22.join(dataDir, ".legacy", `listener-${pid}`);
|
|
39620
|
+
fs23.mkdirSync(archiveDst, { recursive: true });
|
|
38922
39621
|
for (const file of readdirSafe(listenerSrc)) {
|
|
38923
39622
|
if (!file.endsWith(".json")) continue;
|
|
38924
|
-
|
|
39623
|
+
fs23.renameSync(path22.join(listenerSrc, file), path22.join(archiveDst, file));
|
|
38925
39624
|
archivedListener += 1;
|
|
38926
39625
|
}
|
|
38927
39626
|
rmdirIfEmpty(listenerSrc);
|
|
38928
39627
|
}
|
|
38929
39628
|
rmdirIfEmpty(personaDir);
|
|
38930
39629
|
}
|
|
38931
|
-
|
|
38932
|
-
|
|
39630
|
+
fs23.mkdirSync(sessionsDir, { recursive: true });
|
|
39631
|
+
fs23.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
|
|
38933
39632
|
return {
|
|
38934
39633
|
skipped: false,
|
|
38935
39634
|
flagWritten: true,
|
|
@@ -38940,7 +39639,7 @@ function migrateFlattenSessions(opts) {
|
|
|
38940
39639
|
}
|
|
38941
39640
|
function existsSync3(p2) {
|
|
38942
39641
|
try {
|
|
38943
|
-
|
|
39642
|
+
fs23.statSync(p2);
|
|
38944
39643
|
return true;
|
|
38945
39644
|
} catch {
|
|
38946
39645
|
return false;
|
|
@@ -38948,31 +39647,31 @@ function existsSync3(p2) {
|
|
|
38948
39647
|
}
|
|
38949
39648
|
function isDir(p2) {
|
|
38950
39649
|
try {
|
|
38951
|
-
return
|
|
39650
|
+
return fs23.statSync(p2).isDirectory();
|
|
38952
39651
|
} catch {
|
|
38953
39652
|
return false;
|
|
38954
39653
|
}
|
|
38955
39654
|
}
|
|
38956
39655
|
function readdirSafe(p2) {
|
|
38957
39656
|
try {
|
|
38958
|
-
return
|
|
39657
|
+
return fs23.readdirSync(p2);
|
|
38959
39658
|
} catch {
|
|
38960
39659
|
return [];
|
|
38961
39660
|
}
|
|
38962
39661
|
}
|
|
38963
39662
|
function rmdirIfEmpty(p2) {
|
|
38964
39663
|
try {
|
|
38965
|
-
|
|
39664
|
+
fs23.rmdirSync(p2);
|
|
38966
39665
|
} catch {
|
|
38967
39666
|
}
|
|
38968
39667
|
}
|
|
38969
39668
|
|
|
38970
39669
|
// src/transport/http-router.ts
|
|
38971
|
-
var
|
|
38972
|
-
var
|
|
39670
|
+
var import_node_fs18 = __toESM(require("fs"), 1);
|
|
39671
|
+
var import_node_path18 = __toESM(require("path"), 1);
|
|
38973
39672
|
|
|
38974
39673
|
// src/attachment/mime.ts
|
|
38975
|
-
var
|
|
39674
|
+
var import_node_path15 = __toESM(require("path"), 1);
|
|
38976
39675
|
var TEXT_PLAIN = "text/plain; charset=utf-8";
|
|
38977
39676
|
var EXT_TO_NATIVE_MIME = {
|
|
38978
39677
|
// 图片
|
|
@@ -39079,7 +39778,7 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
39079
39778
|
".mk"
|
|
39080
39779
|
]);
|
|
39081
39780
|
function lookupMime(filePathOrName) {
|
|
39082
|
-
const ext =
|
|
39781
|
+
const ext = import_node_path15.default.extname(filePathOrName).toLowerCase();
|
|
39083
39782
|
if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
|
|
39084
39783
|
if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
|
|
39085
39784
|
return "application/octet-stream";
|
|
@@ -39148,8 +39847,8 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
|
|
|
39148
39847
|
}
|
|
39149
39848
|
|
|
39150
39849
|
// src/attachment/upload.ts
|
|
39151
|
-
var
|
|
39152
|
-
var
|
|
39850
|
+
var import_node_fs17 = __toESM(require("fs"), 1);
|
|
39851
|
+
var import_node_path16 = __toESM(require("path"), 1);
|
|
39153
39852
|
var import_node_crypto5 = __toESM(require("crypto"), 1);
|
|
39154
39853
|
var import_promises = require("stream/promises");
|
|
39155
39854
|
var UploadError = class extends Error {
|
|
@@ -39161,22 +39860,22 @@ var UploadError = class extends Error {
|
|
|
39161
39860
|
code;
|
|
39162
39861
|
};
|
|
39163
39862
|
function assertValidFileName(fileName) {
|
|
39164
|
-
if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !==
|
|
39863
|
+
if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path16.default.basename(fileName)) {
|
|
39165
39864
|
throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
|
|
39166
39865
|
}
|
|
39167
39866
|
}
|
|
39168
39867
|
var HASH_PREFIX_LEN = 16;
|
|
39169
39868
|
async function writeUploadedAttachment(args) {
|
|
39170
39869
|
assertValidFileName(args.fileName);
|
|
39171
|
-
const attachmentsRoot =
|
|
39870
|
+
const attachmentsRoot = import_node_path16.default.join(args.sessionDir, ".attachments");
|
|
39172
39871
|
try {
|
|
39173
|
-
|
|
39872
|
+
import_node_fs17.default.mkdirSync(attachmentsRoot, { recursive: true });
|
|
39174
39873
|
} catch (err) {
|
|
39175
39874
|
throw new UploadError("STORAGE_ERROR", `mkdir failed: ${err.message}`);
|
|
39176
39875
|
}
|
|
39177
39876
|
const hasher = import_node_crypto5.default.createHash("sha256");
|
|
39178
39877
|
let actualSize = 0;
|
|
39179
|
-
const tmpPath =
|
|
39878
|
+
const tmpPath = import_node_path16.default.join(
|
|
39180
39879
|
attachmentsRoot,
|
|
39181
39880
|
`.upload-${process.pid}-${Date.now()}-${import_node_crypto5.default.randomBytes(4).toString("hex")}`
|
|
39182
39881
|
);
|
|
@@ -39191,18 +39890,18 @@ async function writeUploadedAttachment(args) {
|
|
|
39191
39890
|
yield buf;
|
|
39192
39891
|
}
|
|
39193
39892
|
},
|
|
39194
|
-
|
|
39893
|
+
import_node_fs17.default.createWriteStream(tmpPath, { mode: 384 })
|
|
39195
39894
|
);
|
|
39196
39895
|
} catch (err) {
|
|
39197
39896
|
try {
|
|
39198
|
-
|
|
39897
|
+
import_node_fs17.default.unlinkSync(tmpPath);
|
|
39199
39898
|
} catch {
|
|
39200
39899
|
}
|
|
39201
39900
|
throw new UploadError("STORAGE_ERROR", `write failed: ${err.message}`);
|
|
39202
39901
|
}
|
|
39203
39902
|
if (actualSize !== args.contentLength) {
|
|
39204
39903
|
try {
|
|
39205
|
-
|
|
39904
|
+
import_node_fs17.default.unlinkSync(tmpPath);
|
|
39206
39905
|
} catch {
|
|
39207
39906
|
}
|
|
39208
39907
|
throw new UploadError(
|
|
@@ -39211,35 +39910,35 @@ async function writeUploadedAttachment(args) {
|
|
|
39211
39910
|
);
|
|
39212
39911
|
}
|
|
39213
39912
|
const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
|
|
39214
|
-
const hashDir =
|
|
39913
|
+
const hashDir = import_node_path16.default.join(attachmentsRoot, attachmentId);
|
|
39215
39914
|
let finalFileName;
|
|
39216
39915
|
let hashDirExists = false;
|
|
39217
39916
|
try {
|
|
39218
|
-
hashDirExists =
|
|
39917
|
+
hashDirExists = import_node_fs17.default.statSync(hashDir).isDirectory();
|
|
39219
39918
|
} catch {
|
|
39220
39919
|
}
|
|
39221
39920
|
if (hashDirExists) {
|
|
39222
|
-
const existing =
|
|
39921
|
+
const existing = import_node_fs17.default.readdirSync(hashDir).filter((n) => !n.startsWith("."));
|
|
39223
39922
|
finalFileName = existing[0] ?? args.fileName;
|
|
39224
39923
|
try {
|
|
39225
|
-
|
|
39924
|
+
import_node_fs17.default.unlinkSync(tmpPath);
|
|
39226
39925
|
} catch {
|
|
39227
39926
|
}
|
|
39228
39927
|
} else {
|
|
39229
39928
|
try {
|
|
39230
|
-
|
|
39929
|
+
import_node_fs17.default.mkdirSync(hashDir, { recursive: true });
|
|
39231
39930
|
finalFileName = args.fileName;
|
|
39232
|
-
|
|
39931
|
+
import_node_fs17.default.renameSync(tmpPath, import_node_path16.default.join(hashDir, finalFileName));
|
|
39233
39932
|
} catch (err) {
|
|
39234
39933
|
try {
|
|
39235
|
-
|
|
39934
|
+
import_node_fs17.default.unlinkSync(tmpPath);
|
|
39236
39935
|
} catch {
|
|
39237
39936
|
}
|
|
39238
39937
|
throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
|
|
39239
39938
|
}
|
|
39240
39939
|
}
|
|
39241
|
-
const absPath =
|
|
39242
|
-
const relPath =
|
|
39940
|
+
const absPath = import_node_path16.default.join(hashDir, finalFileName);
|
|
39941
|
+
const relPath = import_node_path16.default.relative(args.sessionDir, absPath);
|
|
39243
39942
|
args.groupFileStore.upsert(args.scope, args.sessionId, {
|
|
39244
39943
|
relPath: absPath,
|
|
39245
39944
|
// 存绝对路径,与现有 agent 入清单的形态一致(attachment.ts:144 双形态兼容)
|
|
@@ -39253,7 +39952,7 @@ async function writeUploadedAttachment(args) {
|
|
|
39253
39952
|
|
|
39254
39953
|
// src/extension/import.ts
|
|
39255
39954
|
var import_promises2 = __toESM(require("fs/promises"), 1);
|
|
39256
|
-
var
|
|
39955
|
+
var import_node_path17 = __toESM(require("path"), 1);
|
|
39257
39956
|
var import_node_os10 = __toESM(require("os"), 1);
|
|
39258
39957
|
var import_jszip = __toESM(require_lib3(), 1);
|
|
39259
39958
|
var ImportError = class extends Error {
|
|
@@ -39271,7 +39970,7 @@ async function importZip(buf, root) {
|
|
|
39271
39970
|
throw new ImportError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
39272
39971
|
}
|
|
39273
39972
|
for (const name of Object.keys(zip.files)) {
|
|
39274
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
39973
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path17.default.isAbsolute(name)) {
|
|
39275
39974
|
throw new ImportError("ZIP_INVALID", `unsafe zip entry path: ${name}`);
|
|
39276
39975
|
}
|
|
39277
39976
|
}
|
|
@@ -39304,7 +40003,7 @@ async function importZip(buf, root) {
|
|
|
39304
40003
|
);
|
|
39305
40004
|
}
|
|
39306
40005
|
}
|
|
39307
|
-
const destDir =
|
|
40006
|
+
const destDir = import_node_path17.default.join(root, manifest.id);
|
|
39308
40007
|
let destExists = false;
|
|
39309
40008
|
try {
|
|
39310
40009
|
await import_promises2.default.access(destDir);
|
|
@@ -39314,15 +40013,15 @@ async function importZip(buf, root) {
|
|
|
39314
40013
|
if (destExists) {
|
|
39315
40014
|
throw new ImportError("ALREADY_EXISTS", `extension ${manifest.id} already installed`);
|
|
39316
40015
|
}
|
|
39317
|
-
const stage = await import_promises2.default.mkdtemp(
|
|
40016
|
+
const stage = await import_promises2.default.mkdtemp(import_node_path17.default.join(import_node_os10.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
|
|
39318
40017
|
try {
|
|
39319
40018
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
39320
|
-
const dest =
|
|
40019
|
+
const dest = import_node_path17.default.join(stage, name);
|
|
39321
40020
|
if (entry.dir) {
|
|
39322
40021
|
await import_promises2.default.mkdir(dest, { recursive: true });
|
|
39323
40022
|
continue;
|
|
39324
40023
|
}
|
|
39325
|
-
await import_promises2.default.mkdir(
|
|
40024
|
+
await import_promises2.default.mkdir(import_node_path17.default.dirname(dest), { recursive: true });
|
|
39326
40025
|
const content = await entry.async("nodebuffer");
|
|
39327
40026
|
await import_promises2.default.writeFile(dest, content);
|
|
39328
40027
|
}
|
|
@@ -39350,7 +40049,12 @@ var EXPOSED_RPC_METHODS = [
|
|
|
39350
40049
|
"appBuilder.setActiveSession",
|
|
39351
40050
|
// dataclaw-builder:persona 建页时取建页人身份(含 union_id)写进生成 app 的配置。
|
|
39352
40051
|
// 路由到 handlers['auth:getIdentity'],只返 identity、绝不带 ttcToken(见 handlers/feishu-auth.ts)。
|
|
39353
|
-
"auth.getIdentity"
|
|
40052
|
+
"auth.getIdentity",
|
|
40053
|
+
// Persona dispatch (Task 4): A 端 dispatch MCP server 调 run(hold-and-wait 一次);
|
|
40054
|
+
// B 端 dispatch MCP server 调 complete(带 outcome 触发 run 端 resolve)。详见
|
|
40055
|
+
// protocol/src/dispatch.ts。
|
|
40056
|
+
"personaDispatch.run",
|
|
40057
|
+
"personaDispatch.complete"
|
|
39354
40058
|
];
|
|
39355
40059
|
async function handleRpcRequest(input) {
|
|
39356
40060
|
const { method, body, sessionId, dispatcher } = input;
|
|
@@ -39439,7 +40143,7 @@ function isValidUploadFileName(fileName) {
|
|
|
39439
40143
|
if (fileName === "." || fileName === "..") return false;
|
|
39440
40144
|
if (fileName.startsWith(".")) return false;
|
|
39441
40145
|
if (fileName.includes("/") || fileName.includes("\\")) return false;
|
|
39442
|
-
return fileName ===
|
|
40146
|
+
return fileName === import_node_path18.default.basename(fileName);
|
|
39443
40147
|
}
|
|
39444
40148
|
function createHttpRouter(deps) {
|
|
39445
40149
|
return async (req, res) => {
|
|
@@ -39486,6 +40190,8 @@ function createHttpRouter(deps) {
|
|
|
39486
40190
|
sendJson(res, 403, { code: "NOT_LOOPBACK", message: "RPC adapter only accepts loopback connections" });
|
|
39487
40191
|
return true;
|
|
39488
40192
|
}
|
|
40193
|
+
req.socket.setTimeout(0);
|
|
40194
|
+
res.socket?.setTimeout(0);
|
|
39489
40195
|
const method = url.pathname.slice(RPC_ROUTE_PREFIX.length).split("?")[0] ?? "";
|
|
39490
40196
|
const sessionId = req.headers["x-clawd-session-id"] ?? void 0;
|
|
39491
40197
|
let body;
|
|
@@ -39668,7 +40374,7 @@ function createHttpRouter(deps) {
|
|
|
39668
40374
|
return true;
|
|
39669
40375
|
}
|
|
39670
40376
|
let absPath;
|
|
39671
|
-
if (
|
|
40377
|
+
if (import_node_path18.default.isAbsolute(pathParam)) {
|
|
39672
40378
|
absPath = pathParam;
|
|
39673
40379
|
} else if (deps.sessionStore) {
|
|
39674
40380
|
const file = deps.sessionStore.read(sid);
|
|
@@ -39676,7 +40382,7 @@ function createHttpRouter(deps) {
|
|
|
39676
40382
|
sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
|
|
39677
40383
|
return true;
|
|
39678
40384
|
}
|
|
39679
|
-
absPath =
|
|
40385
|
+
absPath = import_node_path18.default.join(file.cwd, pathParam);
|
|
39680
40386
|
} else {
|
|
39681
40387
|
sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
|
|
39682
40388
|
return true;
|
|
@@ -39759,7 +40465,7 @@ function withCtx(ctx, body) {
|
|
|
39759
40465
|
function streamFile(res, absPath, logger) {
|
|
39760
40466
|
let stat;
|
|
39761
40467
|
try {
|
|
39762
|
-
stat =
|
|
40468
|
+
stat = import_node_fs18.default.statSync(absPath);
|
|
39763
40469
|
} catch (err) {
|
|
39764
40470
|
const code = err?.code;
|
|
39765
40471
|
if (code === "ENOENT") {
|
|
@@ -39774,7 +40480,7 @@ function streamFile(res, absPath, logger) {
|
|
|
39774
40480
|
return;
|
|
39775
40481
|
}
|
|
39776
40482
|
const mime = lookupMime(absPath);
|
|
39777
|
-
const basename =
|
|
40483
|
+
const basename = import_node_path18.default.basename(absPath);
|
|
39778
40484
|
res.writeHead(200, {
|
|
39779
40485
|
"Content-Type": mime,
|
|
39780
40486
|
"Content-Length": String(stat.size),
|
|
@@ -39782,7 +40488,7 @@ function streamFile(res, absPath, logger) {
|
|
|
39782
40488
|
// 防止浏览器把任意 mime 当 html 渲染
|
|
39783
40489
|
"X-Content-Type-Options": "nosniff"
|
|
39784
40490
|
});
|
|
39785
|
-
const stream =
|
|
40491
|
+
const stream = import_node_fs18.default.createReadStream(absPath);
|
|
39786
40492
|
stream.on("error", (err) => {
|
|
39787
40493
|
logger?.warn("streamFile read error", { absPath, err: err.message });
|
|
39788
40494
|
res.destroy();
|
|
@@ -39791,8 +40497,8 @@ function streamFile(res, absPath, logger) {
|
|
|
39791
40497
|
}
|
|
39792
40498
|
|
|
39793
40499
|
// src/attachment/gc.ts
|
|
39794
|
-
var
|
|
39795
|
-
var
|
|
40500
|
+
var import_node_fs19 = __toESM(require("fs"), 1);
|
|
40501
|
+
var import_node_path19 = __toESM(require("path"), 1);
|
|
39796
40502
|
var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
|
|
39797
40503
|
function runAttachmentGc(args) {
|
|
39798
40504
|
const now = (args.now ?? Date.now)();
|
|
@@ -39801,38 +40507,38 @@ function runAttachmentGc(args) {
|
|
|
39801
40507
|
for (const { scope, sessionId } of args.sessionScopes) {
|
|
39802
40508
|
for (const entry of args.groupFileStore.list(scope, sessionId)) {
|
|
39803
40509
|
if (entry.stale) continue;
|
|
39804
|
-
if (
|
|
40510
|
+
if (import_node_path19.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
|
|
39805
40511
|
}
|
|
39806
40512
|
}
|
|
39807
40513
|
for (const { scope, sessionId } of args.sessionScopes) {
|
|
39808
|
-
const sessionDir = args.getSessionCwd?.(sessionId) ??
|
|
40514
|
+
const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path19.default.join(
|
|
39809
40515
|
args.dataDir,
|
|
39810
40516
|
"sessions",
|
|
39811
40517
|
...scopeSubPath(scope).map(safeFileName),
|
|
39812
40518
|
safeFileName(sessionId)
|
|
39813
40519
|
);
|
|
39814
|
-
const attRoot =
|
|
40520
|
+
const attRoot = import_node_path19.default.join(sessionDir, ".attachments");
|
|
39815
40521
|
let hashDirs;
|
|
39816
40522
|
try {
|
|
39817
|
-
hashDirs =
|
|
40523
|
+
hashDirs = import_node_fs19.default.readdirSync(attRoot);
|
|
39818
40524
|
} catch (err) {
|
|
39819
40525
|
if (err.code === "ENOENT") continue;
|
|
39820
40526
|
args.logger?.warn("attachment gc: readdir failed", { attRoot, err: err.message });
|
|
39821
40527
|
continue;
|
|
39822
40528
|
}
|
|
39823
40529
|
for (const hashDir of hashDirs) {
|
|
39824
|
-
const hashDirAbs =
|
|
40530
|
+
const hashDirAbs = import_node_path19.default.join(attRoot, hashDir);
|
|
39825
40531
|
let files;
|
|
39826
40532
|
try {
|
|
39827
|
-
files =
|
|
40533
|
+
files = import_node_fs19.default.readdirSync(hashDirAbs);
|
|
39828
40534
|
} catch {
|
|
39829
40535
|
continue;
|
|
39830
40536
|
}
|
|
39831
40537
|
for (const name of files) {
|
|
39832
|
-
const file =
|
|
40538
|
+
const file = import_node_path19.default.join(hashDirAbs, name);
|
|
39833
40539
|
let stat;
|
|
39834
40540
|
try {
|
|
39835
|
-
stat =
|
|
40541
|
+
stat = import_node_fs19.default.statSync(file);
|
|
39836
40542
|
} catch {
|
|
39837
40543
|
continue;
|
|
39838
40544
|
}
|
|
@@ -39841,26 +40547,26 @@ function runAttachmentGc(args) {
|
|
|
39841
40547
|
if (age < ttlMs) continue;
|
|
39842
40548
|
if (liveAbs.has(file)) continue;
|
|
39843
40549
|
try {
|
|
39844
|
-
|
|
40550
|
+
import_node_fs19.default.unlinkSync(file);
|
|
39845
40551
|
} catch (err) {
|
|
39846
40552
|
args.logger?.warn("attachment gc: unlink failed", { file, err: err.message });
|
|
39847
40553
|
}
|
|
39848
40554
|
}
|
|
39849
40555
|
try {
|
|
39850
|
-
if (
|
|
40556
|
+
if (import_node_fs19.default.readdirSync(hashDirAbs).length === 0) import_node_fs19.default.rmdirSync(hashDirAbs);
|
|
39851
40557
|
} catch {
|
|
39852
40558
|
}
|
|
39853
40559
|
}
|
|
39854
40560
|
try {
|
|
39855
|
-
if (
|
|
40561
|
+
if (import_node_fs19.default.readdirSync(attRoot).length === 0) import_node_fs19.default.rmdirSync(attRoot);
|
|
39856
40562
|
} catch {
|
|
39857
40563
|
}
|
|
39858
40564
|
}
|
|
39859
40565
|
}
|
|
39860
40566
|
|
|
39861
40567
|
// src/attachment/group.ts
|
|
39862
|
-
var
|
|
39863
|
-
var
|
|
40568
|
+
var import_node_fs20 = __toESM(require("fs"), 1);
|
|
40569
|
+
var import_node_path20 = __toESM(require("path"), 1);
|
|
39864
40570
|
var import_node_crypto6 = __toESM(require("crypto"), 1);
|
|
39865
40571
|
init_protocol();
|
|
39866
40572
|
var GroupFileStore = class {
|
|
@@ -39872,11 +40578,11 @@ var GroupFileStore = class {
|
|
|
39872
40578
|
this.logger = opts.logger;
|
|
39873
40579
|
}
|
|
39874
40580
|
rootForScope(scope) {
|
|
39875
|
-
return
|
|
40581
|
+
return import_node_path20.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
|
|
39876
40582
|
}
|
|
39877
40583
|
/** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
|
|
39878
40584
|
filePath(scope, sessionId) {
|
|
39879
|
-
return
|
|
40585
|
+
return import_node_path20.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
|
|
39880
40586
|
}
|
|
39881
40587
|
cacheKey(scope, sessionId) {
|
|
39882
40588
|
return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
|
|
@@ -39885,7 +40591,7 @@ var GroupFileStore = class {
|
|
|
39885
40591
|
readFile(scope, sessionId) {
|
|
39886
40592
|
const file = this.filePath(scope, sessionId);
|
|
39887
40593
|
try {
|
|
39888
|
-
const raw =
|
|
40594
|
+
const raw = import_node_fs20.default.readFileSync(file, "utf8");
|
|
39889
40595
|
const parsed = JSON.parse(raw);
|
|
39890
40596
|
if (!Array.isArray(parsed)) {
|
|
39891
40597
|
this.logger?.warn("GroupFileStore.readFile: not an array; resetting session entries", {
|
|
@@ -39911,10 +40617,10 @@ var GroupFileStore = class {
|
|
|
39911
40617
|
}
|
|
39912
40618
|
writeFile(scope, sessionId, entries) {
|
|
39913
40619
|
const file = this.filePath(scope, sessionId);
|
|
39914
|
-
|
|
40620
|
+
import_node_fs20.default.mkdirSync(import_node_path20.default.dirname(file), { recursive: true });
|
|
39915
40621
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
39916
|
-
|
|
39917
|
-
|
|
40622
|
+
import_node_fs20.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
|
|
40623
|
+
import_node_fs20.default.renameSync(tmp, file);
|
|
39918
40624
|
}
|
|
39919
40625
|
/** 拉一份当前 session 的清单。读盘 → cache;之后调用复用 cache */
|
|
39920
40626
|
list(scope, sessionId) {
|
|
@@ -40000,10 +40706,10 @@ var GroupFileStore = class {
|
|
|
40000
40706
|
};
|
|
40001
40707
|
|
|
40002
40708
|
// src/discovery/state-file.ts
|
|
40003
|
-
var
|
|
40004
|
-
var
|
|
40709
|
+
var import_node_fs21 = __toESM(require("fs"), 1);
|
|
40710
|
+
var import_node_path21 = __toESM(require("path"), 1);
|
|
40005
40711
|
function defaultStateFilePath(dataDir) {
|
|
40006
|
-
return
|
|
40712
|
+
return import_node_path21.default.join(dataDir, "state.json");
|
|
40007
40713
|
}
|
|
40008
40714
|
function isPidAlive(pid) {
|
|
40009
40715
|
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
@@ -40025,7 +40731,7 @@ var StateFileManager = class {
|
|
|
40025
40731
|
}
|
|
40026
40732
|
read() {
|
|
40027
40733
|
try {
|
|
40028
|
-
const raw =
|
|
40734
|
+
const raw = import_node_fs21.default.readFileSync(this.file, "utf8");
|
|
40029
40735
|
const parsed = JSON.parse(raw);
|
|
40030
40736
|
return parsed;
|
|
40031
40737
|
} catch {
|
|
@@ -40039,20 +40745,20 @@ var StateFileManager = class {
|
|
|
40039
40745
|
return { status: "stale", existing };
|
|
40040
40746
|
}
|
|
40041
40747
|
write(state) {
|
|
40042
|
-
|
|
40748
|
+
import_node_fs21.default.mkdirSync(import_node_path21.default.dirname(this.file), { recursive: true });
|
|
40043
40749
|
const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
|
|
40044
|
-
|
|
40045
|
-
|
|
40750
|
+
import_node_fs21.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
|
|
40751
|
+
import_node_fs21.default.renameSync(tmp, this.file);
|
|
40046
40752
|
if (process.platform !== "win32") {
|
|
40047
40753
|
try {
|
|
40048
|
-
|
|
40754
|
+
import_node_fs21.default.chmodSync(this.file, 384);
|
|
40049
40755
|
} catch {
|
|
40050
40756
|
}
|
|
40051
40757
|
}
|
|
40052
40758
|
}
|
|
40053
40759
|
delete() {
|
|
40054
40760
|
try {
|
|
40055
|
-
|
|
40761
|
+
import_node_fs21.default.unlinkSync(this.file);
|
|
40056
40762
|
} catch {
|
|
40057
40763
|
}
|
|
40058
40764
|
}
|
|
@@ -40067,14 +40773,14 @@ function readDaemonSourceFromEnv(env = process.env) {
|
|
|
40067
40773
|
}
|
|
40068
40774
|
|
|
40069
40775
|
// src/tunnel/tunnel-manager.ts
|
|
40070
|
-
var
|
|
40071
|
-
var
|
|
40776
|
+
var import_node_fs25 = __toESM(require("fs"), 1);
|
|
40777
|
+
var import_node_path25 = __toESM(require("path"), 1);
|
|
40072
40778
|
var import_node_crypto7 = __toESM(require("crypto"), 1);
|
|
40073
40779
|
var import_node_child_process9 = require("child_process");
|
|
40074
40780
|
|
|
40075
40781
|
// src/tunnel/tunnel-store.ts
|
|
40076
|
-
var
|
|
40077
|
-
var
|
|
40782
|
+
var import_node_fs22 = __toESM(require("fs"), 1);
|
|
40783
|
+
var import_node_path22 = __toESM(require("path"), 1);
|
|
40078
40784
|
var TunnelStore = class {
|
|
40079
40785
|
constructor(filePath) {
|
|
40080
40786
|
this.filePath = filePath;
|
|
@@ -40082,7 +40788,7 @@ var TunnelStore = class {
|
|
|
40082
40788
|
filePath;
|
|
40083
40789
|
async get() {
|
|
40084
40790
|
try {
|
|
40085
|
-
const raw = await
|
|
40791
|
+
const raw = await import_node_fs22.default.promises.readFile(this.filePath, "utf8");
|
|
40086
40792
|
const obj = JSON.parse(raw);
|
|
40087
40793
|
if (!isPersistedTunnel(obj)) return null;
|
|
40088
40794
|
return obj;
|
|
@@ -40093,22 +40799,22 @@ var TunnelStore = class {
|
|
|
40093
40799
|
}
|
|
40094
40800
|
}
|
|
40095
40801
|
async set(v2) {
|
|
40096
|
-
const dir =
|
|
40097
|
-
await
|
|
40802
|
+
const dir = import_node_path22.default.dirname(this.filePath);
|
|
40803
|
+
await import_node_fs22.default.promises.mkdir(dir, { recursive: true });
|
|
40098
40804
|
const data = JSON.stringify(v2, null, 2);
|
|
40099
40805
|
const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
|
|
40100
|
-
await
|
|
40806
|
+
await import_node_fs22.default.promises.writeFile(tmp, data, { mode: 384 });
|
|
40101
40807
|
if (process.platform !== "win32") {
|
|
40102
40808
|
try {
|
|
40103
|
-
await
|
|
40809
|
+
await import_node_fs22.default.promises.chmod(tmp, 384);
|
|
40104
40810
|
} catch {
|
|
40105
40811
|
}
|
|
40106
40812
|
}
|
|
40107
|
-
await
|
|
40813
|
+
await import_node_fs22.default.promises.rename(tmp, this.filePath);
|
|
40108
40814
|
}
|
|
40109
40815
|
async clear() {
|
|
40110
40816
|
try {
|
|
40111
|
-
await
|
|
40817
|
+
await import_node_fs22.default.promises.unlink(this.filePath);
|
|
40112
40818
|
} catch (err) {
|
|
40113
40819
|
const code = err?.code;
|
|
40114
40820
|
if (code !== "ENOENT") throw err;
|
|
@@ -40203,11 +40909,11 @@ function escape(v2) {
|
|
|
40203
40909
|
}
|
|
40204
40910
|
|
|
40205
40911
|
// src/tunnel/frpc-binary.ts
|
|
40206
|
-
var
|
|
40912
|
+
var import_node_fs23 = __toESM(require("fs"), 1);
|
|
40207
40913
|
var import_node_os11 = __toESM(require("os"), 1);
|
|
40208
|
-
var
|
|
40914
|
+
var import_node_path23 = __toESM(require("path"), 1);
|
|
40209
40915
|
var import_node_child_process7 = require("child_process");
|
|
40210
|
-
var
|
|
40916
|
+
var import_node_stream3 = require("stream");
|
|
40211
40917
|
var import_promises3 = require("stream/promises");
|
|
40212
40918
|
var FRPC_VERSION = "0.68.0";
|
|
40213
40919
|
var UnsupportedPlatformError = class extends Error {
|
|
@@ -40237,20 +40943,20 @@ function frpcDownloadUrl(version2, p2) {
|
|
|
40237
40943
|
}
|
|
40238
40944
|
async function ensureFrpcBinary(opts) {
|
|
40239
40945
|
if (opts.override) {
|
|
40240
|
-
if (!
|
|
40946
|
+
if (!import_node_fs23.default.existsSync(opts.override)) {
|
|
40241
40947
|
throw new Error(`frpc binary not found at override path: ${opts.override}`);
|
|
40242
40948
|
}
|
|
40243
40949
|
return opts.override;
|
|
40244
40950
|
}
|
|
40245
40951
|
const version2 = opts.version ?? FRPC_VERSION;
|
|
40246
40952
|
const platform = opts.platform ?? detectPlatform();
|
|
40247
|
-
const binDir =
|
|
40248
|
-
|
|
40953
|
+
const binDir = import_node_path23.default.join(opts.dataDir, "bin");
|
|
40954
|
+
import_node_fs23.default.mkdirSync(binDir, { recursive: true });
|
|
40249
40955
|
cleanupStaleArtifacts(binDir);
|
|
40250
|
-
const stableBin =
|
|
40251
|
-
if (
|
|
40956
|
+
const stableBin = import_node_path23.default.join(binDir, "frpc");
|
|
40957
|
+
if (import_node_fs23.default.existsSync(stableBin)) return stableBin;
|
|
40252
40958
|
const partialBin = `${stableBin}.partial`;
|
|
40253
|
-
const tarballPath =
|
|
40959
|
+
const tarballPath = import_node_path23.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
|
|
40254
40960
|
try {
|
|
40255
40961
|
const url = frpcDownloadUrl(version2, platform);
|
|
40256
40962
|
await downloadToFile(url, tarballPath, opts.fetchImpl);
|
|
@@ -40259,8 +40965,8 @@ async function ensureFrpcBinary(opts) {
|
|
|
40259
40965
|
} else {
|
|
40260
40966
|
await extractFrpcFromTarball(tarballPath, binDir, version2, platform, partialBin);
|
|
40261
40967
|
}
|
|
40262
|
-
|
|
40263
|
-
|
|
40968
|
+
import_node_fs23.default.chmodSync(partialBin, 493);
|
|
40969
|
+
import_node_fs23.default.renameSync(partialBin, stableBin);
|
|
40264
40970
|
} finally {
|
|
40265
40971
|
safeUnlink(tarballPath);
|
|
40266
40972
|
safeUnlink(partialBin);
|
|
@@ -40270,15 +40976,15 @@ async function ensureFrpcBinary(opts) {
|
|
|
40270
40976
|
function cleanupStaleArtifacts(binDir) {
|
|
40271
40977
|
let entries;
|
|
40272
40978
|
try {
|
|
40273
|
-
entries =
|
|
40979
|
+
entries = import_node_fs23.default.readdirSync(binDir);
|
|
40274
40980
|
} catch {
|
|
40275
40981
|
return;
|
|
40276
40982
|
}
|
|
40277
40983
|
for (const name of entries) {
|
|
40278
40984
|
if (name.endsWith(".partial") || name.startsWith("extract-")) {
|
|
40279
|
-
const full =
|
|
40985
|
+
const full = import_node_path23.default.join(binDir, name);
|
|
40280
40986
|
try {
|
|
40281
|
-
|
|
40987
|
+
import_node_fs23.default.rmSync(full, { recursive: true, force: true });
|
|
40282
40988
|
} catch {
|
|
40283
40989
|
}
|
|
40284
40990
|
}
|
|
@@ -40286,7 +40992,7 @@ function cleanupStaleArtifacts(binDir) {
|
|
|
40286
40992
|
}
|
|
40287
40993
|
function safeUnlink(p2) {
|
|
40288
40994
|
try {
|
|
40289
|
-
|
|
40995
|
+
import_node_fs23.default.unlinkSync(p2);
|
|
40290
40996
|
} catch {
|
|
40291
40997
|
}
|
|
40292
40998
|
}
|
|
@@ -40297,13 +41003,13 @@ async function downloadToFile(url, dest, fetchImpl) {
|
|
|
40297
41003
|
if (!res.ok || !res.body) {
|
|
40298
41004
|
throw new Error(`download failed: ${res.status} ${res.statusText}`);
|
|
40299
41005
|
}
|
|
40300
|
-
const out =
|
|
40301
|
-
const nodeStream =
|
|
41006
|
+
const out = import_node_fs23.default.createWriteStream(dest);
|
|
41007
|
+
const nodeStream = import_node_stream3.Readable.fromWeb(res.body);
|
|
40302
41008
|
await (0, import_promises3.pipeline)(nodeStream, out);
|
|
40303
41009
|
}
|
|
40304
41010
|
async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
|
|
40305
|
-
const work =
|
|
40306
|
-
|
|
41011
|
+
const work = import_node_path23.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
|
|
41012
|
+
import_node_fs23.default.mkdirSync(work, { recursive: true });
|
|
40307
41013
|
try {
|
|
40308
41014
|
await new Promise((resolve6, reject) => {
|
|
40309
41015
|
const proc = (0, import_node_child_process7.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
|
|
@@ -40311,32 +41017,32 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
|
|
|
40311
41017
|
proc.on("exit", (code) => code === 0 ? resolve6() : reject(new Error(`tar exited ${code}`)));
|
|
40312
41018
|
});
|
|
40313
41019
|
const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
|
|
40314
|
-
const src =
|
|
40315
|
-
if (!
|
|
41020
|
+
const src = import_node_path23.default.join(work, dirName, "frpc");
|
|
41021
|
+
if (!import_node_fs23.default.existsSync(src)) {
|
|
40316
41022
|
throw new Error(`frpc not found inside tarball at ${src}`);
|
|
40317
41023
|
}
|
|
40318
|
-
|
|
41024
|
+
import_node_fs23.default.copyFileSync(src, destBin);
|
|
40319
41025
|
} finally {
|
|
40320
|
-
|
|
41026
|
+
import_node_fs23.default.rmSync(work, { recursive: true, force: true });
|
|
40321
41027
|
}
|
|
40322
41028
|
}
|
|
40323
41029
|
|
|
40324
41030
|
// src/tunnel/frpc-process.ts
|
|
40325
|
-
var
|
|
40326
|
-
var
|
|
41031
|
+
var import_node_fs24 = __toESM(require("fs"), 1);
|
|
41032
|
+
var import_node_path24 = __toESM(require("path"), 1);
|
|
40327
41033
|
var import_node_child_process8 = require("child_process");
|
|
40328
41034
|
function frpcPidFilePath(dataDir) {
|
|
40329
|
-
return
|
|
41035
|
+
return import_node_path24.default.join(dataDir, "frpc.pid");
|
|
40330
41036
|
}
|
|
40331
41037
|
function writeFrpcPid(dataDir, pid) {
|
|
40332
41038
|
try {
|
|
40333
|
-
|
|
41039
|
+
import_node_fs24.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
|
|
40334
41040
|
} catch {
|
|
40335
41041
|
}
|
|
40336
41042
|
}
|
|
40337
41043
|
function clearFrpcPid(dataDir) {
|
|
40338
41044
|
try {
|
|
40339
|
-
|
|
41045
|
+
import_node_fs24.default.unlinkSync(frpcPidFilePath(dataDir));
|
|
40340
41046
|
} catch {
|
|
40341
41047
|
}
|
|
40342
41048
|
}
|
|
@@ -40352,7 +41058,7 @@ function defaultIsPidAlive(pid) {
|
|
|
40352
41058
|
}
|
|
40353
41059
|
function defaultReadPidFile(file) {
|
|
40354
41060
|
try {
|
|
40355
|
-
return
|
|
41061
|
+
return import_node_fs24.default.readFileSync(file, "utf8");
|
|
40356
41062
|
} catch {
|
|
40357
41063
|
return null;
|
|
40358
41064
|
}
|
|
@@ -40368,12 +41074,12 @@ function defaultSleep(ms) {
|
|
|
40368
41074
|
}
|
|
40369
41075
|
async function killStaleFrpc(deps) {
|
|
40370
41076
|
const pidFile = frpcPidFilePath(deps.dataDir);
|
|
40371
|
-
const tomlPath =
|
|
41077
|
+
const tomlPath = import_node_path24.default.join(deps.dataDir, "frpc.toml");
|
|
40372
41078
|
const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
|
|
40373
41079
|
const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
|
|
40374
41080
|
const killPid = deps.killPidImpl ?? defaultKillPid;
|
|
40375
41081
|
const scanPids = deps.scanFrpcPidsImpl ?? ((tp) => defaultScanFrpcPidsByCmdline(tp, deps.logger));
|
|
40376
|
-
const
|
|
41082
|
+
const sleep2 = deps.sleepImpl ?? defaultSleep;
|
|
40377
41083
|
const victims = /* @__PURE__ */ new Set();
|
|
40378
41084
|
const raw = readPidFile(pidFile);
|
|
40379
41085
|
if (raw) {
|
|
@@ -40392,7 +41098,7 @@ async function killStaleFrpc(deps) {
|
|
|
40392
41098
|
}
|
|
40393
41099
|
if (victims.size === 0) {
|
|
40394
41100
|
try {
|
|
40395
|
-
|
|
41101
|
+
import_node_fs24.default.unlinkSync(pidFile);
|
|
40396
41102
|
} catch {
|
|
40397
41103
|
}
|
|
40398
41104
|
return;
|
|
@@ -40401,9 +41107,9 @@ async function killStaleFrpc(deps) {
|
|
|
40401
41107
|
deps.logger?.warn("tunnel: killing stale frpc before respawn", { pid });
|
|
40402
41108
|
killPid(pid, "SIGKILL");
|
|
40403
41109
|
}
|
|
40404
|
-
await
|
|
41110
|
+
await sleep2(deps.reapWaitMs ?? 300);
|
|
40405
41111
|
try {
|
|
40406
|
-
|
|
41112
|
+
import_node_fs24.default.unlinkSync(pidFile);
|
|
40407
41113
|
} catch {
|
|
40408
41114
|
}
|
|
40409
41115
|
}
|
|
@@ -40440,7 +41146,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
|
40440
41146
|
var TunnelManager = class {
|
|
40441
41147
|
constructor(deps) {
|
|
40442
41148
|
this.deps = deps;
|
|
40443
|
-
this.store = deps.store ?? new TunnelStore(
|
|
41149
|
+
this.store = deps.store ?? new TunnelStore(import_node_path25.default.join(deps.dataDir, "tunnel.json"));
|
|
40444
41150
|
this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
|
|
40445
41151
|
this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
|
|
40446
41152
|
}
|
|
@@ -40567,7 +41273,7 @@ var TunnelManager = class {
|
|
|
40567
41273
|
dataDir: this.deps.dataDir,
|
|
40568
41274
|
override: this.deps.frpcBinaryOverride ?? void 0
|
|
40569
41275
|
});
|
|
40570
|
-
const tomlPath =
|
|
41276
|
+
const tomlPath = import_node_path25.default.join(this.deps.dataDir, "frpc.toml");
|
|
40571
41277
|
const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto7.default.randomBytes(3).toString("hex")}`;
|
|
40572
41278
|
const toml = buildFrpcToml({
|
|
40573
41279
|
serverAddr: t.frpsHost,
|
|
@@ -40578,12 +41284,12 @@ var TunnelManager = class {
|
|
|
40578
41284
|
localPort,
|
|
40579
41285
|
logLevel: "info"
|
|
40580
41286
|
});
|
|
40581
|
-
await
|
|
41287
|
+
await import_node_fs25.default.promises.writeFile(tomlPath, toml, { mode: 384 });
|
|
40582
41288
|
const proc = (this.deps.spawnImpl ?? import_node_child_process9.spawn)(frpcBin, ["-c", tomlPath], {
|
|
40583
41289
|
stdio: ["ignore", "pipe", "pipe"]
|
|
40584
41290
|
});
|
|
40585
|
-
const logFilePath =
|
|
40586
|
-
const logStream =
|
|
41291
|
+
const logFilePath = import_node_path25.default.join(this.deps.dataDir, "frpc.log");
|
|
41292
|
+
const logStream = import_node_fs25.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
|
|
40587
41293
|
logStream.on("error", () => {
|
|
40588
41294
|
});
|
|
40589
41295
|
const tee = (chunk) => {
|
|
@@ -40666,27 +41372,27 @@ async function waitForFrpcReady(proc, timeoutMs) {
|
|
|
40666
41372
|
|
|
40667
41373
|
// src/tunnel/device-key.ts
|
|
40668
41374
|
var import_node_os12 = __toESM(require("os"), 1);
|
|
40669
|
-
var
|
|
41375
|
+
var import_node_path26 = __toESM(require("path"), 1);
|
|
40670
41376
|
var import_node_crypto8 = __toESM(require("crypto"), 1);
|
|
40671
41377
|
var DERIVE_SALT = "clawd-tunnel-device-v1";
|
|
40672
41378
|
function deriveStableDeviceKey(opts = {}) {
|
|
40673
41379
|
const hostname = opts.hostname ?? import_node_os12.default.hostname();
|
|
40674
41380
|
const uid = opts.uid ?? (typeof import_node_os12.default.userInfo === "function" ? import_node_os12.default.userInfo().uid : 0);
|
|
40675
41381
|
const home = opts.home ?? import_node_os12.default.homedir();
|
|
40676
|
-
const defaultDataDir =
|
|
40677
|
-
const normalizedDataDir = opts.dataDir ?
|
|
41382
|
+
const defaultDataDir = import_node_path26.default.resolve(import_node_path26.default.join(home, ".clawd"));
|
|
41383
|
+
const normalizedDataDir = opts.dataDir ? import_node_path26.default.resolve(opts.dataDir) : null;
|
|
40678
41384
|
const isDefaultDir = normalizedDataDir == null || normalizedDataDir === defaultDataDir;
|
|
40679
41385
|
const input = isDefaultDir ? `${hostname}::${uid}` : `${hostname}::${uid}::${normalizedDataDir}`;
|
|
40680
41386
|
return import_node_crypto8.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
|
|
40681
41387
|
}
|
|
40682
41388
|
|
|
40683
41389
|
// src/auth-store.ts
|
|
40684
|
-
var
|
|
40685
|
-
var
|
|
41390
|
+
var import_node_fs26 = __toESM(require("fs"), 1);
|
|
41391
|
+
var import_node_path27 = __toESM(require("path"), 1);
|
|
40686
41392
|
var import_node_crypto9 = __toESM(require("crypto"), 1);
|
|
40687
41393
|
var AUTH_FILE_NAME = "auth.json";
|
|
40688
41394
|
function authFilePath(dataDir) {
|
|
40689
|
-
return
|
|
41395
|
+
return import_node_path27.default.join(dataDir, AUTH_FILE_NAME);
|
|
40690
41396
|
}
|
|
40691
41397
|
function loadOrCreateAuthFile(opts) {
|
|
40692
41398
|
const file = authFilePath(opts.dataDir);
|
|
@@ -40720,7 +41426,7 @@ function defaultGenerateOwnerPrincipalId() {
|
|
|
40720
41426
|
}
|
|
40721
41427
|
function readAuthFile(file) {
|
|
40722
41428
|
try {
|
|
40723
|
-
const raw =
|
|
41429
|
+
const raw = import_node_fs26.default.readFileSync(file, "utf8");
|
|
40724
41430
|
const parsed = JSON.parse(raw);
|
|
40725
41431
|
if (typeof parsed?.token !== "string" || parsed.token.length === 0) {
|
|
40726
41432
|
return null;
|
|
@@ -40739,25 +41445,25 @@ function readAuthFile(file) {
|
|
|
40739
41445
|
}
|
|
40740
41446
|
}
|
|
40741
41447
|
function writeAuthFile(file, content) {
|
|
40742
|
-
|
|
40743
|
-
|
|
41448
|
+
import_node_fs26.default.mkdirSync(import_node_path27.default.dirname(file), { recursive: true });
|
|
41449
|
+
import_node_fs26.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
|
|
40744
41450
|
try {
|
|
40745
|
-
|
|
41451
|
+
import_node_fs26.default.chmodSync(file, 384);
|
|
40746
41452
|
} catch {
|
|
40747
41453
|
}
|
|
40748
41454
|
}
|
|
40749
41455
|
|
|
40750
41456
|
// src/owner-profile.ts
|
|
40751
|
-
var
|
|
41457
|
+
var import_node_fs27 = __toESM(require("fs"), 1);
|
|
40752
41458
|
var import_node_os13 = __toESM(require("os"), 1);
|
|
40753
|
-
var
|
|
41459
|
+
var import_node_path28 = __toESM(require("path"), 1);
|
|
40754
41460
|
var PROFILE_FILENAME = "profile.json";
|
|
40755
41461
|
function loadOwnerDisplayName(dataDir) {
|
|
40756
41462
|
const fallback = import_node_os13.default.userInfo().username;
|
|
40757
|
-
const profilePath =
|
|
41463
|
+
const profilePath = import_node_path28.default.join(dataDir, PROFILE_FILENAME);
|
|
40758
41464
|
let raw;
|
|
40759
41465
|
try {
|
|
40760
|
-
raw =
|
|
41466
|
+
raw = import_node_fs27.default.readFileSync(profilePath, "utf8");
|
|
40761
41467
|
} catch {
|
|
40762
41468
|
return fallback;
|
|
40763
41469
|
}
|
|
@@ -40780,18 +41486,18 @@ function loadOwnerDisplayName(dataDir) {
|
|
|
40780
41486
|
}
|
|
40781
41487
|
|
|
40782
41488
|
// src/feishu-auth/owner-identity-store.ts
|
|
40783
|
-
var
|
|
40784
|
-
var
|
|
41489
|
+
var import_node_fs28 = __toESM(require("fs"), 1);
|
|
41490
|
+
var import_node_path29 = __toESM(require("path"), 1);
|
|
40785
41491
|
var OWNER_IDENTITY_FILE_NAME = "owner-identity.json";
|
|
40786
41492
|
var OwnerIdentityStore = class {
|
|
40787
41493
|
file;
|
|
40788
41494
|
constructor(dataDir) {
|
|
40789
|
-
this.file =
|
|
41495
|
+
this.file = import_node_path29.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
|
|
40790
41496
|
}
|
|
40791
41497
|
read() {
|
|
40792
41498
|
let raw;
|
|
40793
41499
|
try {
|
|
40794
|
-
raw =
|
|
41500
|
+
raw = import_node_fs28.default.readFileSync(this.file, "utf8");
|
|
40795
41501
|
} catch {
|
|
40796
41502
|
return null;
|
|
40797
41503
|
}
|
|
@@ -40819,16 +41525,16 @@ var OwnerIdentityStore = class {
|
|
|
40819
41525
|
};
|
|
40820
41526
|
}
|
|
40821
41527
|
write(record) {
|
|
40822
|
-
|
|
40823
|
-
|
|
41528
|
+
import_node_fs28.default.mkdirSync(import_node_path29.default.dirname(this.file), { recursive: true });
|
|
41529
|
+
import_node_fs28.default.writeFileSync(this.file, JSON.stringify(record, null, 2), { mode: 384 });
|
|
40824
41530
|
try {
|
|
40825
|
-
|
|
41531
|
+
import_node_fs28.default.chmodSync(this.file, 384);
|
|
40826
41532
|
} catch {
|
|
40827
41533
|
}
|
|
40828
41534
|
}
|
|
40829
41535
|
clear() {
|
|
40830
41536
|
try {
|
|
40831
|
-
|
|
41537
|
+
import_node_fs28.default.unlinkSync(this.file);
|
|
40832
41538
|
} catch (err) {
|
|
40833
41539
|
const code = err?.code;
|
|
40834
41540
|
if (code !== "ENOENT") throw err;
|
|
@@ -40949,9 +41655,9 @@ var CentralClientError = class extends Error {
|
|
|
40949
41655
|
code;
|
|
40950
41656
|
cause;
|
|
40951
41657
|
};
|
|
40952
|
-
async function centralRequest(opts,
|
|
41658
|
+
async function centralRequest(opts, path59, init) {
|
|
40953
41659
|
const f = opts.fetchImpl ?? globalThis.fetch;
|
|
40954
|
-
const url = `${opts.api.replace(/\/+$/, "")}${
|
|
41660
|
+
const url = `${opts.api.replace(/\/+$/, "")}${path59}`;
|
|
40955
41661
|
const ctrl = new AbortController();
|
|
40956
41662
|
const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
|
|
40957
41663
|
let res;
|
|
@@ -41093,8 +41799,8 @@ function verifyConnectToken(args) {
|
|
|
41093
41799
|
}
|
|
41094
41800
|
|
|
41095
41801
|
// src/feishu-auth/server-key.ts
|
|
41096
|
-
var
|
|
41097
|
-
var
|
|
41802
|
+
var fs37 = __toESM(require("fs"), 1);
|
|
41803
|
+
var path38 = __toESM(require("path"), 1);
|
|
41098
41804
|
var FILE_NAME2 = "server-signing-key.json";
|
|
41099
41805
|
var ServerKeyStore = class {
|
|
41100
41806
|
constructor(dataDir) {
|
|
@@ -41102,12 +41808,12 @@ var ServerKeyStore = class {
|
|
|
41102
41808
|
}
|
|
41103
41809
|
dataDir;
|
|
41104
41810
|
filePath() {
|
|
41105
|
-
return
|
|
41811
|
+
return path38.join(this.dataDir, FILE_NAME2);
|
|
41106
41812
|
}
|
|
41107
41813
|
/** 读缓存的公钥;无缓存 / 损坏 → null(调用方决定是否触发拉取) */
|
|
41108
41814
|
read() {
|
|
41109
41815
|
try {
|
|
41110
|
-
const raw =
|
|
41816
|
+
const raw = fs37.readFileSync(this.filePath(), "utf8");
|
|
41111
41817
|
const parsed = JSON.parse(raw);
|
|
41112
41818
|
if (typeof parsed.publicKeyPem === "string" && parsed.publicKeyPem.includes("PUBLIC KEY")) {
|
|
41113
41819
|
return parsed.publicKeyPem;
|
|
@@ -41122,12 +41828,12 @@ var ServerKeyStore = class {
|
|
|
41122
41828
|
publicKeyPem,
|
|
41123
41829
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
41124
41830
|
};
|
|
41125
|
-
|
|
41126
|
-
|
|
41831
|
+
fs37.mkdirSync(this.dataDir, { recursive: true });
|
|
41832
|
+
fs37.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
|
|
41127
41833
|
}
|
|
41128
41834
|
clear() {
|
|
41129
41835
|
try {
|
|
41130
|
-
|
|
41836
|
+
fs37.unlinkSync(this.filePath());
|
|
41131
41837
|
} catch {
|
|
41132
41838
|
}
|
|
41133
41839
|
}
|
|
@@ -41140,12 +41846,12 @@ init_protocol();
|
|
|
41140
41846
|
init_protocol();
|
|
41141
41847
|
|
|
41142
41848
|
// src/session/fork.ts
|
|
41143
|
-
var
|
|
41849
|
+
var import_node_fs29 = __toESM(require("fs"), 1);
|
|
41144
41850
|
var import_node_os14 = __toESM(require("os"), 1);
|
|
41145
|
-
var
|
|
41851
|
+
var import_node_path30 = __toESM(require("path"), 1);
|
|
41146
41852
|
init_claude_history();
|
|
41147
41853
|
function readJsonlEntries(file) {
|
|
41148
|
-
const raw =
|
|
41854
|
+
const raw = import_node_fs29.default.readFileSync(file, "utf8");
|
|
41149
41855
|
const out = [];
|
|
41150
41856
|
for (const line of raw.split("\n")) {
|
|
41151
41857
|
const t = line.trim();
|
|
@@ -41158,10 +41864,10 @@ function readJsonlEntries(file) {
|
|
|
41158
41864
|
return out;
|
|
41159
41865
|
}
|
|
41160
41866
|
function forkSession(input) {
|
|
41161
|
-
const baseDir = input.baseDir ??
|
|
41162
|
-
const projectDir =
|
|
41163
|
-
const sourceFile =
|
|
41164
|
-
if (!
|
|
41867
|
+
const baseDir = input.baseDir ?? import_node_path30.default.join(import_node_os14.default.homedir(), ".claude");
|
|
41868
|
+
const projectDir = import_node_path30.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
|
|
41869
|
+
const sourceFile = import_node_path30.default.join(projectDir, `${input.toolSessionId}.jsonl`);
|
|
41870
|
+
if (!import_node_fs29.default.existsSync(sourceFile)) {
|
|
41165
41871
|
throw new Error(`fork: source transcript not found: ${sourceFile}`);
|
|
41166
41872
|
}
|
|
41167
41873
|
const entries = readJsonlEntries(sourceFile);
|
|
@@ -41191,9 +41897,9 @@ function forkSession(input) {
|
|
|
41191
41897
|
}
|
|
41192
41898
|
forkedLines.push(JSON.stringify(forked));
|
|
41193
41899
|
}
|
|
41194
|
-
const forkedFilePath =
|
|
41195
|
-
|
|
41196
|
-
|
|
41900
|
+
const forkedFilePath = import_node_path30.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
|
|
41901
|
+
import_node_fs29.default.mkdirSync(projectDir, { recursive: true });
|
|
41902
|
+
import_node_fs29.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
|
|
41197
41903
|
return { forkedToolSessionId, forkedFilePath };
|
|
41198
41904
|
}
|
|
41199
41905
|
|
|
@@ -41569,7 +42275,7 @@ function buildPermissionHandlers(deps) {
|
|
|
41569
42275
|
}
|
|
41570
42276
|
|
|
41571
42277
|
// src/handlers/history.ts
|
|
41572
|
-
var
|
|
42278
|
+
var path41 = __toESM(require("path"), 1);
|
|
41573
42279
|
init_protocol();
|
|
41574
42280
|
|
|
41575
42281
|
// src/session/recent-dirs.ts
|
|
@@ -41587,7 +42293,7 @@ function listRecentDirs(store, limit = 50) {
|
|
|
41587
42293
|
}
|
|
41588
42294
|
|
|
41589
42295
|
// src/permission/persona-paths.ts
|
|
41590
|
-
var
|
|
42296
|
+
var path40 = __toESM(require("path"), 1);
|
|
41591
42297
|
function getAllowedPersonaIds(grants, action) {
|
|
41592
42298
|
const ids = /* @__PURE__ */ new Set();
|
|
41593
42299
|
for (const g2 of grants) {
|
|
@@ -41600,31 +42306,31 @@ function getAllowedPersonaIds(grants, action) {
|
|
|
41600
42306
|
return ids;
|
|
41601
42307
|
}
|
|
41602
42308
|
function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
|
|
41603
|
-
const target =
|
|
42309
|
+
const target = path40.resolve(absPath);
|
|
41604
42310
|
if (userWorkDir) {
|
|
41605
|
-
const u =
|
|
41606
|
-
const usep = u.endsWith(
|
|
42311
|
+
const u = path40.resolve(userWorkDir);
|
|
42312
|
+
const usep = u.endsWith(path40.sep) ? "" : path40.sep;
|
|
41607
42313
|
if (target === u || target.startsWith(u + usep)) return true;
|
|
41608
42314
|
}
|
|
41609
|
-
const root =
|
|
41610
|
-
const sep2 = root.endsWith(
|
|
42315
|
+
const root = path40.resolve(personaRoot);
|
|
42316
|
+
const sep2 = root.endsWith(path40.sep) ? "" : path40.sep;
|
|
41611
42317
|
if (!target.startsWith(root + sep2)) return false;
|
|
41612
|
-
const rel =
|
|
42318
|
+
const rel = path40.relative(root, target);
|
|
41613
42319
|
if (!rel || rel.startsWith("..")) return false;
|
|
41614
|
-
const personaId = rel.split(
|
|
42320
|
+
const personaId = rel.split(path40.sep)[0];
|
|
41615
42321
|
if (!personaId) return false;
|
|
41616
42322
|
const allowed = getAllowedPersonaIds(grants, action);
|
|
41617
42323
|
if (allowed === "*") return true;
|
|
41618
42324
|
return allowed.has(personaId);
|
|
41619
42325
|
}
|
|
41620
42326
|
function personaIdFromPath(absPath, personaRoot) {
|
|
41621
|
-
const root =
|
|
41622
|
-
const target =
|
|
41623
|
-
const sep2 = root.endsWith(
|
|
42327
|
+
const root = path40.resolve(personaRoot);
|
|
42328
|
+
const target = path40.resolve(absPath);
|
|
42329
|
+
const sep2 = root.endsWith(path40.sep) ? "" : path40.sep;
|
|
41624
42330
|
if (!target.startsWith(root + sep2)) return null;
|
|
41625
|
-
const rel =
|
|
42331
|
+
const rel = path40.relative(root, target);
|
|
41626
42332
|
if (!rel || rel.startsWith("..")) return null;
|
|
41627
|
-
const id = rel.split(
|
|
42333
|
+
const id = rel.split(path40.sep)[0];
|
|
41628
42334
|
return id || null;
|
|
41629
42335
|
}
|
|
41630
42336
|
|
|
@@ -41651,7 +42357,7 @@ function buildHistoryHandlers(deps) {
|
|
|
41651
42357
|
if (!pid) return false;
|
|
41652
42358
|
return isGuestPathAllowed(
|
|
41653
42359
|
ctx.grants,
|
|
41654
|
-
|
|
42360
|
+
path41.join(personaRoot, pid),
|
|
41655
42361
|
personaRoot,
|
|
41656
42362
|
"read",
|
|
41657
42363
|
userWorkDir
|
|
@@ -41663,7 +42369,7 @@ function buildHistoryHandlers(deps) {
|
|
|
41663
42369
|
};
|
|
41664
42370
|
const list = async (frame, _client, ctx) => {
|
|
41665
42371
|
const args = HistoryListArgs.parse(frame);
|
|
41666
|
-
assertGuestPath(ctx,
|
|
42372
|
+
assertGuestPath(ctx, path41.resolve(args.projectPath), personaRoot, "history:list");
|
|
41667
42373
|
const sessions = await history.listSessions(args);
|
|
41668
42374
|
return { response: { type: "history:list", sessions } };
|
|
41669
42375
|
};
|
|
@@ -41695,13 +42401,13 @@ function buildHistoryHandlers(deps) {
|
|
|
41695
42401
|
};
|
|
41696
42402
|
const subagents = async (frame, _client, ctx) => {
|
|
41697
42403
|
const args = HistorySubagentsArgs.parse(frame);
|
|
41698
|
-
assertGuestPath(ctx,
|
|
42404
|
+
assertGuestPath(ctx, path41.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
|
|
41699
42405
|
const subs = await history.listSubagents(args);
|
|
41700
42406
|
return { response: { type: "history:subagents", subagents: subs } };
|
|
41701
42407
|
};
|
|
41702
42408
|
const subagentRead = async (frame, _client, ctx) => {
|
|
41703
42409
|
const args = HistorySubagentReadArgs.parse(frame);
|
|
41704
|
-
assertGuestPath(ctx,
|
|
42410
|
+
assertGuestPath(ctx, path41.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
|
|
41705
42411
|
const res = await history.readSubagent(args);
|
|
41706
42412
|
return { response: { type: "history:subagent-read", ...res } };
|
|
41707
42413
|
};
|
|
@@ -41710,7 +42416,7 @@ function buildHistoryHandlers(deps) {
|
|
|
41710
42416
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
41711
42417
|
const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
|
|
41712
42418
|
const filtered = dirs.filter(
|
|
41713
|
-
(d) => isGuestPathAllowed(ctx.grants,
|
|
42419
|
+
(d) => isGuestPathAllowed(ctx.grants, path41.resolve(d.cwd), personaRoot, "read", userWorkDir)
|
|
41714
42420
|
);
|
|
41715
42421
|
return { response: { type: "history:recentDirs", dirs: filtered } };
|
|
41716
42422
|
}
|
|
@@ -41727,7 +42433,7 @@ function buildHistoryHandlers(deps) {
|
|
|
41727
42433
|
}
|
|
41728
42434
|
|
|
41729
42435
|
// src/handlers/workspace.ts
|
|
41730
|
-
var
|
|
42436
|
+
var path42 = __toESM(require("path"), 1);
|
|
41731
42437
|
var os15 = __toESM(require("os"), 1);
|
|
41732
42438
|
init_protocol();
|
|
41733
42439
|
init_protocol();
|
|
@@ -41769,22 +42475,22 @@ function buildWorkspaceHandlers(deps) {
|
|
|
41769
42475
|
const args = WorkspaceListArgs.parse(frame);
|
|
41770
42476
|
const isGuest = ctx?.principal.kind === "guest";
|
|
41771
42477
|
const fallbackCwd = isGuest && personaRoot ? personaRoot : os15.homedir();
|
|
41772
|
-
const resolvedCwd =
|
|
41773
|
-
const target = args.path ?
|
|
42478
|
+
const resolvedCwd = path42.resolve(args.cwd ?? fallbackCwd);
|
|
42479
|
+
const target = args.path ? path42.resolve(resolvedCwd, args.path) : resolvedCwd;
|
|
41774
42480
|
assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
|
|
41775
42481
|
const res = workspace.list({ ...args, cwd: resolvedCwd });
|
|
41776
42482
|
return { response: { type: "workspace:list", ...res } };
|
|
41777
42483
|
};
|
|
41778
42484
|
const read = async (frame, _client, ctx) => {
|
|
41779
42485
|
const args = WorkspaceReadArgs.parse(frame);
|
|
41780
|
-
const target =
|
|
42486
|
+
const target = path42.isAbsolute(args.path) ? path42.resolve(args.path) : path42.resolve(args.cwd, args.path);
|
|
41781
42487
|
assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
|
|
41782
42488
|
const res = workspace.read(args);
|
|
41783
42489
|
return { response: { type: "workspace:read", ...res } };
|
|
41784
42490
|
};
|
|
41785
42491
|
const skillsList = async (frame, _client, ctx) => {
|
|
41786
42492
|
const args = SkillsListArgs.parse(frame);
|
|
41787
|
-
const cwdAbs =
|
|
42493
|
+
const cwdAbs = path42.resolve(args.cwd);
|
|
41788
42494
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
|
|
41789
42495
|
const list2 = await getSkillsForTool(args.tool ?? "claude", cwdAbs);
|
|
41790
42496
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
@@ -41796,7 +42502,7 @@ function buildWorkspaceHandlers(deps) {
|
|
|
41796
42502
|
};
|
|
41797
42503
|
const agentsList = async (frame, _client, ctx) => {
|
|
41798
42504
|
const args = AgentsListArgs.parse(frame);
|
|
41799
|
-
const cwdAbs =
|
|
42505
|
+
const cwdAbs = path42.resolve(args.cwd);
|
|
41800
42506
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
|
|
41801
42507
|
if (args.tool === "codex") {
|
|
41802
42508
|
return { response: { type: "agents:list", agents: [] } };
|
|
@@ -41818,20 +42524,20 @@ function buildWorkspaceHandlers(deps) {
|
|
|
41818
42524
|
}
|
|
41819
42525
|
|
|
41820
42526
|
// src/handlers/git.ts
|
|
41821
|
-
var
|
|
42527
|
+
var path44 = __toESM(require("path"), 1);
|
|
41822
42528
|
init_protocol();
|
|
41823
42529
|
init_protocol();
|
|
41824
42530
|
|
|
41825
42531
|
// src/workspace/git.ts
|
|
41826
42532
|
var import_node_child_process10 = require("child_process");
|
|
41827
|
-
var
|
|
41828
|
-
var
|
|
42533
|
+
var import_node_fs30 = __toESM(require("fs"), 1);
|
|
42534
|
+
var import_node_path31 = __toESM(require("path"), 1);
|
|
41829
42535
|
var import_node_util = require("util");
|
|
41830
42536
|
var pexec = (0, import_node_util.promisify)(import_node_child_process10.execFile);
|
|
41831
42537
|
function normalizePath(p2) {
|
|
41832
|
-
const resolved =
|
|
42538
|
+
const resolved = import_node_path31.default.resolve(p2);
|
|
41833
42539
|
try {
|
|
41834
|
-
return
|
|
42540
|
+
return import_node_fs30.default.realpathSync(resolved);
|
|
41835
42541
|
} catch {
|
|
41836
42542
|
return resolved;
|
|
41837
42543
|
}
|
|
@@ -41905,7 +42611,7 @@ async function listGitBranches(cwd) {
|
|
|
41905
42611
|
function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
|
|
41906
42612
|
if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
|
|
41907
42613
|
const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
|
|
41908
|
-
if (!isGuestPathAllowed(ctx.grants,
|
|
42614
|
+
if (!isGuestPathAllowed(ctx.grants, path44.resolve(cwd), personaRoot, "read", userWorkDir)) {
|
|
41909
42615
|
throw new ClawdError(
|
|
41910
42616
|
ERROR_CODES.UNAUTHORIZED,
|
|
41911
42617
|
`guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
|
|
@@ -42321,6 +43027,7 @@ function buildReadyFrame(deps, client) {
|
|
|
42321
43027
|
if (deps.httpToken) fileSharing.httpToken = deps.httpToken;
|
|
42322
43028
|
}
|
|
42323
43029
|
const daemonSource = process.env.CLAWD_DAEMON_SOURCE === "ota" ? "ota" : "packaged";
|
|
43030
|
+
const logShipping = deps.getLogShipping ? deps.getLogShipping() : null;
|
|
42324
43031
|
return {
|
|
42325
43032
|
version,
|
|
42326
43033
|
protocolVersion: PROTOCOL_VERSION,
|
|
@@ -42331,7 +43038,8 @@ function buildReadyFrame(deps, client) {
|
|
|
42331
43038
|
tunnelUrl,
|
|
42332
43039
|
mode: deps.mode,
|
|
42333
43040
|
daemonSource,
|
|
42334
|
-
...fileSharing
|
|
43041
|
+
...fileSharing,
|
|
43042
|
+
...logShipping ? { logShipping } : {}
|
|
42335
43043
|
};
|
|
42336
43044
|
}
|
|
42337
43045
|
function buildMetaHandlers(deps) {
|
|
@@ -42419,7 +43127,7 @@ function buildPersonaHandlers(deps) {
|
|
|
42419
43127
|
}
|
|
42420
43128
|
|
|
42421
43129
|
// src/handlers/attachment.ts
|
|
42422
|
-
var
|
|
43130
|
+
var import_node_path32 = __toESM(require("path"), 1);
|
|
42423
43131
|
init_protocol();
|
|
42424
43132
|
init_protocol();
|
|
42425
43133
|
var DEFAULT_TTL_SECONDS = 24 * 3600;
|
|
@@ -42474,12 +43182,12 @@ function buildAttachmentHandlers(deps) {
|
|
|
42474
43182
|
`session ${args.sessionId} scope unresolved`
|
|
42475
43183
|
);
|
|
42476
43184
|
}
|
|
42477
|
-
const cwdAbs =
|
|
42478
|
-
const candidateAbs =
|
|
43185
|
+
const cwdAbs = import_node_path32.default.resolve(sessionFile.cwd);
|
|
43186
|
+
const candidateAbs = import_node_path32.default.isAbsolute(args.relPath) ? import_node_path32.default.resolve(args.relPath) : import_node_path32.default.resolve(cwdAbs, args.relPath);
|
|
42479
43187
|
assertGuestAttachmentPath(ctx, candidateAbs, deps.personaRoot, "attachment.signUrl", deps.usersRoot);
|
|
42480
43188
|
const entries = deps.groupFileStore.list(scope, args.sessionId);
|
|
42481
43189
|
const entry = entries.find((e) => {
|
|
42482
|
-
const storedAbs =
|
|
43190
|
+
const storedAbs = import_node_path32.default.isAbsolute(e.relPath) ? import_node_path32.default.resolve(e.relPath) : import_node_path32.default.resolve(cwdAbs, e.relPath);
|
|
42483
43191
|
return storedAbs === candidateAbs && !e.stale;
|
|
42484
43192
|
});
|
|
42485
43193
|
if (!entry) {
|
|
@@ -42503,7 +43211,7 @@ function buildAttachmentHandlers(deps) {
|
|
|
42503
43211
|
if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
|
|
42504
43212
|
const f = deps.sessionStore.read(sessionId);
|
|
42505
43213
|
if (!f) return;
|
|
42506
|
-
assertGuestAttachmentPath(ctx,
|
|
43214
|
+
assertGuestAttachmentPath(ctx, import_node_path32.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
|
|
42507
43215
|
}
|
|
42508
43216
|
const groupAdd = async (frame, _client, ctx) => {
|
|
42509
43217
|
if (!deps.groupFileStore || !deps.getSessionScope) {
|
|
@@ -42575,19 +43283,19 @@ function buildAttachmentHandlers(deps) {
|
|
|
42575
43283
|
|
|
42576
43284
|
// src/handlers/extension.ts
|
|
42577
43285
|
var import_promises7 = __toESM(require("fs/promises"), 1);
|
|
42578
|
-
var
|
|
43286
|
+
var import_node_path37 = __toESM(require("path"), 1);
|
|
42579
43287
|
init_protocol();
|
|
42580
43288
|
|
|
42581
43289
|
// src/extension/bundle-zip.ts
|
|
42582
43290
|
var import_promises4 = __toESM(require("fs/promises"), 1);
|
|
42583
|
-
var
|
|
43291
|
+
var import_node_path33 = __toESM(require("path"), 1);
|
|
42584
43292
|
var import_node_crypto11 = __toESM(require("crypto"), 1);
|
|
42585
43293
|
var import_jszip2 = __toESM(require_lib3(), 1);
|
|
42586
43294
|
async function bundleExtensionDir(dir) {
|
|
42587
43295
|
const entries = await listFilesSorted(dir);
|
|
42588
43296
|
const zip = new import_jszip2.default();
|
|
42589
43297
|
for (const rel of entries) {
|
|
42590
|
-
const abs =
|
|
43298
|
+
const abs = import_node_path33.default.join(dir, rel);
|
|
42591
43299
|
const content = await import_promises4.default.readFile(abs);
|
|
42592
43300
|
zip.file(rel, content, { date: FIXED_DATE });
|
|
42593
43301
|
}
|
|
@@ -42608,7 +43316,7 @@ async function listFilesSorted(rootDir) {
|
|
|
42608
43316
|
return out;
|
|
42609
43317
|
}
|
|
42610
43318
|
async function walk(absRoot, relPrefix, out) {
|
|
42611
|
-
const dirAbs =
|
|
43319
|
+
const dirAbs = import_node_path33.default.join(absRoot, relPrefix);
|
|
42612
43320
|
const entries = await import_promises4.default.readdir(dirAbs, { withFileTypes: true });
|
|
42613
43321
|
for (const e of entries) {
|
|
42614
43322
|
if (IGNORE_BASENAMES.has(e.name)) continue;
|
|
@@ -42662,25 +43370,25 @@ function computePublishCheck(args) {
|
|
|
42662
43370
|
|
|
42663
43371
|
// src/extension/install-flow.ts
|
|
42664
43372
|
var import_promises5 = __toESM(require("fs/promises"), 1);
|
|
42665
|
-
var
|
|
43373
|
+
var import_node_path35 = __toESM(require("path"), 1);
|
|
42666
43374
|
var import_node_os17 = __toESM(require("os"), 1);
|
|
42667
43375
|
var import_node_crypto12 = __toESM(require("crypto"), 1);
|
|
42668
43376
|
var import_jszip3 = __toESM(require_lib3(), 1);
|
|
42669
43377
|
|
|
42670
43378
|
// src/extension/paths.ts
|
|
42671
43379
|
var import_node_os16 = __toESM(require("os"), 1);
|
|
42672
|
-
var
|
|
43380
|
+
var import_node_path34 = __toESM(require("path"), 1);
|
|
42673
43381
|
function clawdHomeRoot(override) {
|
|
42674
|
-
return override ?? process.env.CLAWD_HOME ??
|
|
43382
|
+
return override ?? process.env.CLAWD_HOME ?? import_node_path34.default.join(import_node_os16.default.homedir(), ".clawd");
|
|
42675
43383
|
}
|
|
42676
43384
|
function extensionsRoot(override) {
|
|
42677
|
-
return
|
|
43385
|
+
return import_node_path34.default.join(clawdHomeRoot(override), "extensions");
|
|
42678
43386
|
}
|
|
42679
43387
|
function publishedChannelsFile(override) {
|
|
42680
|
-
return
|
|
43388
|
+
return import_node_path34.default.join(clawdHomeRoot(override), "extensions-published.json");
|
|
42681
43389
|
}
|
|
42682
43390
|
function bundleCacheRoot(override) {
|
|
42683
|
-
return
|
|
43391
|
+
return import_node_path34.default.join(clawdHomeRoot(override), "extension-bundles");
|
|
42684
43392
|
}
|
|
42685
43393
|
|
|
42686
43394
|
// src/extension/install-flow.ts
|
|
@@ -42707,7 +43415,7 @@ async function installFromChannel(args, deps) {
|
|
|
42707
43415
|
throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
42708
43416
|
}
|
|
42709
43417
|
for (const name of Object.keys(zip.files)) {
|
|
42710
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
43418
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path35.default.isAbsolute(name)) {
|
|
42711
43419
|
throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
|
|
42712
43420
|
}
|
|
42713
43421
|
}
|
|
@@ -42739,7 +43447,7 @@ async function installFromChannel(args, deps) {
|
|
|
42739
43447
|
);
|
|
42740
43448
|
}
|
|
42741
43449
|
const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
|
|
42742
|
-
const destDir =
|
|
43450
|
+
const destDir = import_node_path35.default.join(deps.extensionsRoot, localExtId);
|
|
42743
43451
|
let destExists = false;
|
|
42744
43452
|
try {
|
|
42745
43453
|
await import_promises5.default.access(destDir);
|
|
@@ -42753,16 +43461,16 @@ async function installFromChannel(args, deps) {
|
|
|
42753
43461
|
);
|
|
42754
43462
|
}
|
|
42755
43463
|
const stage = await import_promises5.default.mkdtemp(
|
|
42756
|
-
|
|
43464
|
+
import_node_path35.default.join(import_node_os17.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
|
|
42757
43465
|
);
|
|
42758
43466
|
try {
|
|
42759
43467
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
42760
|
-
const dest =
|
|
43468
|
+
const dest = import_node_path35.default.join(stage, name);
|
|
42761
43469
|
if (entry.dir) {
|
|
42762
43470
|
await import_promises5.default.mkdir(dest, { recursive: true });
|
|
42763
43471
|
continue;
|
|
42764
43472
|
}
|
|
42765
|
-
await import_promises5.default.mkdir(
|
|
43473
|
+
await import_promises5.default.mkdir(import_node_path35.default.dirname(dest), { recursive: true });
|
|
42766
43474
|
if (name === "manifest.json") {
|
|
42767
43475
|
const rewritten = { ...parsed.data, id: localExtId };
|
|
42768
43476
|
await import_promises5.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
|
|
@@ -42783,7 +43491,7 @@ async function installFromChannel(args, deps) {
|
|
|
42783
43491
|
|
|
42784
43492
|
// src/extension/update-flow.ts
|
|
42785
43493
|
var import_promises6 = __toESM(require("fs/promises"), 1);
|
|
42786
|
-
var
|
|
43494
|
+
var import_node_path36 = __toESM(require("path"), 1);
|
|
42787
43495
|
var import_node_os18 = __toESM(require("os"), 1);
|
|
42788
43496
|
var import_node_crypto13 = __toESM(require("crypto"), 1);
|
|
42789
43497
|
var import_jszip4 = __toESM(require_lib3(), 1);
|
|
@@ -42800,11 +43508,11 @@ async function updateFromChannel(args, deps) {
|
|
|
42800
43508
|
channelRef.extId,
|
|
42801
43509
|
channelRef.ownerPrincipalId
|
|
42802
43510
|
);
|
|
42803
|
-
const liveDir =
|
|
43511
|
+
const liveDir = import_node_path36.default.join(deps.extensionsRoot, localExtId);
|
|
42804
43512
|
const prevDir = `${liveDir}.prev`;
|
|
42805
43513
|
let existingVersion;
|
|
42806
43514
|
try {
|
|
42807
|
-
const raw = await import_promises6.default.readFile(
|
|
43515
|
+
const raw = await import_promises6.default.readFile(import_node_path36.default.join(liveDir, "manifest.json"), "utf8");
|
|
42808
43516
|
const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
|
|
42809
43517
|
if (!parsed2.success) {
|
|
42810
43518
|
throw new UpdateError(
|
|
@@ -42837,7 +43545,7 @@ async function updateFromChannel(args, deps) {
|
|
|
42837
43545
|
throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
42838
43546
|
}
|
|
42839
43547
|
for (const name of Object.keys(zip.files)) {
|
|
42840
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
43548
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path36.default.isAbsolute(name)) {
|
|
42841
43549
|
throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
|
|
42842
43550
|
}
|
|
42843
43551
|
}
|
|
@@ -42872,16 +43580,16 @@ async function updateFromChannel(args, deps) {
|
|
|
42872
43580
|
await import_promises6.default.rm(prevDir, { recursive: true, force: true });
|
|
42873
43581
|
await import_promises6.default.rename(liveDir, prevDir);
|
|
42874
43582
|
const stage = await import_promises6.default.mkdtemp(
|
|
42875
|
-
|
|
43583
|
+
import_node_path36.default.join(import_node_os18.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
|
|
42876
43584
|
);
|
|
42877
43585
|
try {
|
|
42878
43586
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
42879
|
-
const dest =
|
|
43587
|
+
const dest = import_node_path36.default.join(stage, name);
|
|
42880
43588
|
if (entry.dir) {
|
|
42881
43589
|
await import_promises6.default.mkdir(dest, { recursive: true });
|
|
42882
43590
|
continue;
|
|
42883
43591
|
}
|
|
42884
|
-
await import_promises6.default.mkdir(
|
|
43592
|
+
await import_promises6.default.mkdir(import_node_path36.default.dirname(dest), { recursive: true });
|
|
42885
43593
|
if (name === "manifest.json") {
|
|
42886
43594
|
const rewritten = { ...parsed.data, id: localExtId };
|
|
42887
43595
|
await import_promises6.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
|
|
@@ -42974,7 +43682,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
|
|
|
42974
43682
|
);
|
|
42975
43683
|
}
|
|
42976
43684
|
}
|
|
42977
|
-
const manifestPath =
|
|
43685
|
+
const manifestPath = import_node_path37.default.join(root, extId, "manifest.json");
|
|
42978
43686
|
const manifest = await readManifest(root, extId);
|
|
42979
43687
|
const next = { ...manifest, version: newVersion };
|
|
42980
43688
|
const tmp = `${manifestPath}.tmp`;
|
|
@@ -42982,7 +43690,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
|
|
|
42982
43690
|
await import_promises7.default.rename(tmp, manifestPath);
|
|
42983
43691
|
}
|
|
42984
43692
|
async function readManifest(root, extId) {
|
|
42985
|
-
const file =
|
|
43693
|
+
const file = import_node_path37.default.join(root, extId, "manifest.json");
|
|
42986
43694
|
let raw;
|
|
42987
43695
|
try {
|
|
42988
43696
|
raw = await import_promises7.default.readFile(file, "utf8");
|
|
@@ -43073,7 +43781,7 @@ function buildExtensionHandlers(deps) {
|
|
|
43073
43781
|
};
|
|
43074
43782
|
async function buildSnapshotMeta(extId) {
|
|
43075
43783
|
const manifest = await readManifest(deps.root, extId);
|
|
43076
|
-
const { sha256, buffer } = await bundleExtensionDir(
|
|
43784
|
+
const { sha256, buffer } = await bundleExtensionDir(import_node_path37.default.join(deps.root, extId));
|
|
43077
43785
|
return { manifest, contentHash: sha256, buffer };
|
|
43078
43786
|
}
|
|
43079
43787
|
const publish = async (frame, _client, ctx) => {
|
|
@@ -43253,8 +43961,218 @@ function buildExtensionHandlers(deps) {
|
|
|
43253
43961
|
};
|
|
43254
43962
|
}
|
|
43255
43963
|
|
|
43256
|
-
// src/app-builder/
|
|
43964
|
+
// src/app-builder/project-store.ts
|
|
43965
|
+
var import_node_fs31 = require("fs");
|
|
43257
43966
|
var import_node_child_process11 = require("child_process");
|
|
43967
|
+
var import_node_path38 = require("path");
|
|
43968
|
+
init_protocol();
|
|
43969
|
+
var PROJECTS_DIR = "projects";
|
|
43970
|
+
var META_FILE = ".clawd-project.json";
|
|
43971
|
+
var DEFAULT_TEMPLATE = "nestjs-react";
|
|
43972
|
+
var SCAFFOLD_TIMEOUT_MS = 3e4;
|
|
43973
|
+
var ProjectStore = class {
|
|
43974
|
+
/** @param root projects 父目录,例如 `~/.clawd/users/<userId>/`(v2 per-user) */
|
|
43975
|
+
constructor(root) {
|
|
43976
|
+
this.root = root;
|
|
43977
|
+
}
|
|
43978
|
+
root;
|
|
43979
|
+
/** projects/<name>/.clawd-project.json 路径 */
|
|
43980
|
+
metaPath(name) {
|
|
43981
|
+
return (0, import_node_path38.join)(this.projectsRoot(), name, META_FILE);
|
|
43982
|
+
}
|
|
43983
|
+
/** projects/<name>/ 目录路径(cwd 用) */
|
|
43984
|
+
projectDir(name) {
|
|
43985
|
+
return (0, import_node_path38.join)(this.projectsRoot(), name);
|
|
43986
|
+
}
|
|
43987
|
+
projectsRoot() {
|
|
43988
|
+
return (0, import_node_path38.join)(this.root, PROJECTS_DIR);
|
|
43989
|
+
}
|
|
43990
|
+
async list() {
|
|
43991
|
+
let entries;
|
|
43992
|
+
try {
|
|
43993
|
+
entries = await import_node_fs31.promises.readdir(this.projectsRoot());
|
|
43994
|
+
} catch (err) {
|
|
43995
|
+
if (err.code === "ENOENT") return [];
|
|
43996
|
+
throw err;
|
|
43997
|
+
}
|
|
43998
|
+
const out = [];
|
|
43999
|
+
for (const name of entries) {
|
|
44000
|
+
try {
|
|
44001
|
+
const raw = await import_node_fs31.promises.readFile(this.metaPath(name), "utf8");
|
|
44002
|
+
const json = JSON.parse(raw);
|
|
44003
|
+
let migrated = false;
|
|
44004
|
+
if (typeof json.devCommand !== "string" || json.devCommand.length === 0) {
|
|
44005
|
+
json.devCommand = DEFAULT_DEV_COMMAND;
|
|
44006
|
+
migrated = true;
|
|
44007
|
+
}
|
|
44008
|
+
const parsed = ProjectMetadataSchema.safeParse(json);
|
|
44009
|
+
if (parsed.success) {
|
|
44010
|
+
out.push(parsed.data);
|
|
44011
|
+
if (migrated) {
|
|
44012
|
+
void import_node_fs31.promises.writeFile(this.metaPath(name), JSON.stringify(parsed.data, null, 2) + "\n", "utf8").catch(() => {
|
|
44013
|
+
});
|
|
44014
|
+
}
|
|
44015
|
+
}
|
|
44016
|
+
} catch {
|
|
44017
|
+
}
|
|
44018
|
+
}
|
|
44019
|
+
return out.sort((a, b2) => a.name.localeCompare(b2.name));
|
|
44020
|
+
}
|
|
44021
|
+
/**
|
|
44022
|
+
* @param reservedPorts 其它 user 已占端口(v2 per-user:端口必须全局唯一,所有 user 的
|
|
44023
|
+
* dev server 同机跑;per-user store 各自只 list 自己,靠 handler 收集全局端口传进来,
|
|
44024
|
+
* 否则不同 user 的首个项目都从 PROJECT_PORT_MIN 起 → 全撞 6173)。
|
|
44025
|
+
*/
|
|
44026
|
+
async create(name, reservedPorts) {
|
|
44027
|
+
const existing = await this.list();
|
|
44028
|
+
if (existing.some((p2) => p2.name === name)) {
|
|
44029
|
+
throw new Error(`project "${name}" already exists / \u5DF2\u5B58\u5728`);
|
|
44030
|
+
}
|
|
44031
|
+
const usedPorts = new Set(existing.map((p2) => p2.port));
|
|
44032
|
+
if (reservedPorts) for (const p2 of reservedPorts) usedPorts.add(p2);
|
|
44033
|
+
let port = -1;
|
|
44034
|
+
for (let p2 = PROJECT_PORT_MIN; p2 <= PROJECT_PORT_MAX; p2++) {
|
|
44035
|
+
if (!usedPorts.has(p2)) {
|
|
44036
|
+
port = p2;
|
|
44037
|
+
break;
|
|
44038
|
+
}
|
|
44039
|
+
}
|
|
44040
|
+
if (port < 0) {
|
|
44041
|
+
throw new Error(
|
|
44042
|
+
`port pool exhausted / \u7AEF\u53E3\u6C60\u5DF2\u6EE1\uFF08${PROJECT_PORT_MIN}-${PROJECT_PORT_MAX}\uFF09\uFF0C\u5148\u5220\u4E00\u4E2A project \u91CA\u653E\u7AEF\u53E3`
|
|
44043
|
+
);
|
|
44044
|
+
}
|
|
44045
|
+
const meta = {
|
|
44046
|
+
name,
|
|
44047
|
+
port,
|
|
44048
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
44049
|
+
devCommand: DEFAULT_DEV_COMMAND
|
|
44050
|
+
};
|
|
44051
|
+
const validated = ProjectMetadataSchema.safeParse(meta);
|
|
44052
|
+
if (!validated.success) {
|
|
44053
|
+
throw new Error(`invalid name "${name}": ${validated.error.message}`);
|
|
44054
|
+
}
|
|
44055
|
+
const dir = this.projectDir(name);
|
|
44056
|
+
await import_node_fs31.promises.mkdir(dir, { recursive: true });
|
|
44057
|
+
await import_node_fs31.promises.writeFile(this.metaPath(name), JSON.stringify(meta, null, 2) + "\n", "utf8");
|
|
44058
|
+
return meta;
|
|
44059
|
+
}
|
|
44060
|
+
/**
|
|
44061
|
+
* 同步内联 scaffold:spawn `extension-kit/scripts/new-extension.sh <name>` 等 exit。
|
|
44062
|
+
* 必须在 `create()` 之后调(脚本期望 projects/<name>/.clawd-project.json 已就位 = picker 模式)。
|
|
44063
|
+
* 失败抛错;上层(handler)应当 catch 后回滚(删 dir + 不 mutate session)。
|
|
44064
|
+
*
|
|
44065
|
+
* spec 2026-06-02 §5.6.3:scaffold 对 assistant 不可见,避免 assistant 被诱导去"读 example
|
|
44066
|
+
* 代码再参考"。assistant 进 project 时目录已是完整模板,直接 pnpm install 即可。
|
|
44067
|
+
*/
|
|
44068
|
+
async scaffold(name, templateSrcDir, scaffoldScriptPath) {
|
|
44069
|
+
const destDir = this.projectDir(name);
|
|
44070
|
+
return await new Promise((resolve6, reject) => {
|
|
44071
|
+
const child = (0, import_node_child_process11.spawn)("bash", [scaffoldScriptPath, name, templateSrcDir, destDir], {
|
|
44072
|
+
env: { ...process.env, PATH: process.env.PATH ?? "" },
|
|
44073
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
44074
|
+
});
|
|
44075
|
+
let stdout = "";
|
|
44076
|
+
let stderr = "";
|
|
44077
|
+
child.stdout.on("data", (d) => {
|
|
44078
|
+
stdout += d.toString("utf8");
|
|
44079
|
+
});
|
|
44080
|
+
child.stderr.on("data", (d) => {
|
|
44081
|
+
stderr += d.toString("utf8");
|
|
44082
|
+
});
|
|
44083
|
+
const timer = setTimeout(() => {
|
|
44084
|
+
child.kill("SIGKILL");
|
|
44085
|
+
reject(new Error(`scaffold timeout (>${SCAFFOLD_TIMEOUT_MS}ms): ${scaffoldScriptPath} ${name}`));
|
|
44086
|
+
}, SCAFFOLD_TIMEOUT_MS);
|
|
44087
|
+
child.on("error", (err) => {
|
|
44088
|
+
clearTimeout(timer);
|
|
44089
|
+
reject(new Error(`scaffold spawn failed: ${err.message}`));
|
|
44090
|
+
});
|
|
44091
|
+
child.on("exit", (code, signal) => {
|
|
44092
|
+
clearTimeout(timer);
|
|
44093
|
+
if (code === 0) resolve6({ stdout, stderr });
|
|
44094
|
+
else reject(new Error(`scaffold exit ${code ?? signal}: ${stderr.slice(0, 500)}`));
|
|
44095
|
+
});
|
|
44096
|
+
});
|
|
44097
|
+
}
|
|
44098
|
+
async delete(name) {
|
|
44099
|
+
const dir = this.projectDir(name);
|
|
44100
|
+
await import_node_fs31.promises.rm(dir, { recursive: true, force: true });
|
|
44101
|
+
}
|
|
44102
|
+
async updatePort(name, newPort) {
|
|
44103
|
+
if (newPort < PROJECT_PORT_MIN || newPort > PROJECT_PORT_MAX) {
|
|
44104
|
+
throw new Error(
|
|
44105
|
+
`port range invalid: must be ${PROJECT_PORT_MIN}-${PROJECT_PORT_MAX}, got ${newPort}`
|
|
44106
|
+
);
|
|
44107
|
+
}
|
|
44108
|
+
const list = await this.list();
|
|
44109
|
+
const target = list.find((p2) => p2.name === name);
|
|
44110
|
+
if (!target) throw new Error(`project "${name}" not found / \u4E0D\u5B58\u5728`);
|
|
44111
|
+
const conflict = list.find((p2) => p2.name !== name && p2.port === newPort);
|
|
44112
|
+
if (conflict) {
|
|
44113
|
+
throw new Error(`port ${newPort} already used / \u5DF2\u88AB project "${conflict.name}" \u5360\u7528`);
|
|
44114
|
+
}
|
|
44115
|
+
const updated = { ...target, port: newPort };
|
|
44116
|
+
await import_node_fs31.promises.writeFile(this.metaPath(name), JSON.stringify(updated, null, 2) + "\n", "utf8");
|
|
44117
|
+
return updated;
|
|
44118
|
+
}
|
|
44119
|
+
/**
|
|
44120
|
+
* 单栏 refactor (spec 2026-06-02 §5.6.1):发布上线后写公网 URL 到 .clawd-project.json.prodUrl。
|
|
44121
|
+
* UI 通过 listProjects 读到 prodUrl 后切预览栏到线上 URL,取代旧 prod marker 机制。
|
|
44122
|
+
* 重复调用幂等(覆盖旧 URL)。url 由 ProjectMetadataSchema 校验 url() 格式。
|
|
44123
|
+
*/
|
|
44124
|
+
async setProdUrl(name, url) {
|
|
44125
|
+
const list = await this.list();
|
|
44126
|
+
const target = list.find((p2) => p2.name === name);
|
|
44127
|
+
if (!target) throw new Error(`project "${name}" not found / \u4E0D\u5B58\u5728`);
|
|
44128
|
+
const updated = { ...target, prodUrl: url };
|
|
44129
|
+
const validated = ProjectMetadataSchema.safeParse(updated);
|
|
44130
|
+
if (!validated.success) {
|
|
44131
|
+
throw new Error(`invalid prodUrl "${url}": ${validated.error.message}`);
|
|
44132
|
+
}
|
|
44133
|
+
await import_node_fs31.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
|
|
44134
|
+
return validated.data;
|
|
44135
|
+
}
|
|
44136
|
+
/**
|
|
44137
|
+
* 发布上线脚手架化 (spec 2026-06-03-app-builder-publish-scaffold-design §5.1.4):
|
|
44138
|
+
* 写 publishJob 字段到 .clawd-project.json。仅承载 in-flight 状态 ——
|
|
44139
|
+
* - daemon 收到第一个 ::stage::build marker 时写入
|
|
44140
|
+
* - 每次 stage 切换更新 stage 字段(jobId / startedAt 不变)
|
|
44141
|
+
* - 成功 / 失败 / dismiss 时调 clearPublishJob 清掉
|
|
44142
|
+
* - 只有 daemon 崩才会留残骸
|
|
44143
|
+
* 写入时保留所有其他字段(prodUrl 等不受影响)。
|
|
44144
|
+
*/
|
|
44145
|
+
async setPublishJob(name, job) {
|
|
44146
|
+
const list = await this.list();
|
|
44147
|
+
const target = list.find((p2) => p2.name === name);
|
|
44148
|
+
if (!target) throw new Error(`project "${name}" not found / \u4E0D\u5B58\u5728`);
|
|
44149
|
+
const updated = { ...target, publishJob: job };
|
|
44150
|
+
const validated = ProjectMetadataSchema.safeParse(updated);
|
|
44151
|
+
if (!validated.success) {
|
|
44152
|
+
throw new Error(`invalid publishJob: ${validated.error.message}`);
|
|
44153
|
+
}
|
|
44154
|
+
await import_node_fs31.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
|
|
44155
|
+
return validated.data;
|
|
44156
|
+
}
|
|
44157
|
+
/** 清掉 .clawd-project.json.publishJob 字段。其他字段保持原样。 */
|
|
44158
|
+
async clearPublishJob(name) {
|
|
44159
|
+
const list = await this.list();
|
|
44160
|
+
const target = list.find((p2) => p2.name === name);
|
|
44161
|
+
if (!target) throw new Error(`project "${name}" not found / \u4E0D\u5B58\u5728`);
|
|
44162
|
+
if (!target.publishJob) return target;
|
|
44163
|
+
const { publishJob: _drop, ...rest } = target;
|
|
44164
|
+
void _drop;
|
|
44165
|
+
const validated = ProjectMetadataSchema.safeParse(rest);
|
|
44166
|
+
if (!validated.success) {
|
|
44167
|
+
throw new Error(`failed to clear publishJob: ${validated.error.message}`);
|
|
44168
|
+
}
|
|
44169
|
+
await import_node_fs31.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
|
|
44170
|
+
return validated.data;
|
|
44171
|
+
}
|
|
44172
|
+
};
|
|
44173
|
+
|
|
44174
|
+
// src/app-builder/kill-port.ts
|
|
44175
|
+
var import_node_child_process12 = require("child_process");
|
|
43258
44176
|
async function killPortOccupants(port, ownedPids, logger) {
|
|
43259
44177
|
let pids;
|
|
43260
44178
|
try {
|
|
@@ -43296,7 +44214,7 @@ async function killPortOccupants(port, ownedPids, logger) {
|
|
|
43296
44214
|
}
|
|
43297
44215
|
function listPidsOnPort(port) {
|
|
43298
44216
|
return new Promise((resolve6, reject) => {
|
|
43299
|
-
(0,
|
|
44217
|
+
(0, import_node_child_process12.execFile)(
|
|
43300
44218
|
"lsof",
|
|
43301
44219
|
["-ti", `:${port}`],
|
|
43302
44220
|
{ timeout: 3e3 },
|
|
@@ -43368,9 +44286,9 @@ var PublishJobRegistry = class {
|
|
|
43368
44286
|
};
|
|
43369
44287
|
|
|
43370
44288
|
// src/app-builder/publish-job-runner.ts
|
|
43371
|
-
var
|
|
43372
|
-
var
|
|
43373
|
-
var
|
|
44289
|
+
var import_node_child_process13 = require("child_process");
|
|
44290
|
+
var import_node_fs32 = require("fs");
|
|
44291
|
+
var import_node_path39 = require("path");
|
|
43374
44292
|
|
|
43375
44293
|
// src/app-builder/publish-stage-parser.ts
|
|
43376
44294
|
var STAGE_RE = /^\s*::stage::(build|deploy|verify)\s*$/;
|
|
@@ -43397,19 +44315,19 @@ function tailStderrLines(buf, n) {
|
|
|
43397
44315
|
// src/app-builder/publish-job-runner.ts
|
|
43398
44316
|
async function startPublishJob(deps, args) {
|
|
43399
44317
|
const { registry: registry2, projectDir } = deps;
|
|
43400
|
-
const spawn12 = deps.spawnImpl ??
|
|
44318
|
+
const spawn12 = deps.spawnImpl ?? import_node_child_process13.spawn;
|
|
43401
44319
|
if (registry2.has(args.name)) {
|
|
43402
44320
|
return { jobId: registry2.get(args.name).jobId, status: "already-publishing" };
|
|
43403
44321
|
}
|
|
43404
44322
|
const projDir = projectDir(args.name);
|
|
43405
|
-
const logPath = (0,
|
|
44323
|
+
const logPath = (0, import_node_path39.join)(projDir, ".publish.log");
|
|
43406
44324
|
let logStream = null;
|
|
43407
44325
|
try {
|
|
43408
|
-
logStream = (0,
|
|
44326
|
+
logStream = (0, import_node_fs32.createWriteStream)(logPath, { flags: "w" });
|
|
43409
44327
|
} catch {
|
|
43410
44328
|
logStream = null;
|
|
43411
44329
|
}
|
|
43412
|
-
const child = spawn12("bash", [args.scriptPath, projDir], {
|
|
44330
|
+
const child = spawn12("bash", [args.scriptPath, projDir, args.personaRoot ?? ""], {
|
|
43413
44331
|
cwd: projDir,
|
|
43414
44332
|
env: process.env,
|
|
43415
44333
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -43662,10 +44580,9 @@ async function recoverInterruptedJobs(deps) {
|
|
|
43662
44580
|
|
|
43663
44581
|
// src/handlers/app-builder.ts
|
|
43664
44582
|
init_protocol();
|
|
43665
|
-
var
|
|
43666
|
-
var
|
|
44583
|
+
var import_node_path40 = require("path");
|
|
44584
|
+
var import_node_fs33 = require("fs");
|
|
43667
44585
|
var APP_BUILDER_PERSONAS = ["persona-app-builder", "persona-dataclaw-builder"];
|
|
43668
|
-
var PUBLISH_SCRIPT_REL = "extension-kit/scripts/publish.sh";
|
|
43669
44586
|
var DEV_SERVER_READY_TIMEOUT_MS = 3e4;
|
|
43670
44587
|
async function recoverInterruptedPublishJobs(store, logger) {
|
|
43671
44588
|
await recoverInterruptedJobs({
|
|
@@ -43745,7 +44662,7 @@ function buildAppBuilderHandlers(deps) {
|
|
|
43745
44662
|
async function listAllUsersProjects() {
|
|
43746
44663
|
if (!deps.usersRoot || !deps.getStore) return [];
|
|
43747
44664
|
const getStore = deps.getStore;
|
|
43748
|
-
const userIds = await
|
|
44665
|
+
const userIds = await import_node_fs33.promises.readdir(deps.usersRoot).catch(() => []);
|
|
43749
44666
|
const perUser = await Promise.all(
|
|
43750
44667
|
userIds.map((uid) => getStore(uid).list().catch(() => []))
|
|
43751
44668
|
);
|
|
@@ -43821,7 +44738,9 @@ function buildAppBuilderHandlers(deps) {
|
|
|
43821
44738
|
const project = await userStore.create(f.name, reservedPorts);
|
|
43822
44739
|
try {
|
|
43823
44740
|
const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(session.ownerPersonaId ?? "") : deps.personaRoot;
|
|
43824
|
-
const
|
|
44741
|
+
const templateSrcDir = (0, import_node_path40.join)(personaRoot, "extension-kit", "examples", DEFAULT_TEMPLATE);
|
|
44742
|
+
const scaffoldScript = (0, import_node_path40.join)(deps.deployKitRoot, "scripts", "new-extension.sh");
|
|
44743
|
+
const scaffoldResult = await userStore.scaffold(project.name, templateSrcDir, scaffoldScript);
|
|
43825
44744
|
deps.logger?.info("app-builder.scaffold.done", {
|
|
43826
44745
|
name: project.name,
|
|
43827
44746
|
stdout: scaffoldResult.stdout.slice(0, 200)
|
|
@@ -44040,11 +44959,13 @@ function buildAppBuilderHandlers(deps) {
|
|
|
44040
44959
|
});
|
|
44041
44960
|
await userStore.clearPublishJob(args.name);
|
|
44042
44961
|
}
|
|
44043
|
-
const
|
|
44962
|
+
const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(boundSession.ownerPersonaId ?? "") : deps.personaRoot;
|
|
44963
|
+
const scriptPath = (0, import_node_path40.join)(deps.deployKitRoot, "scripts", "publish.sh");
|
|
44044
44964
|
deps.logger?.info("app-builder.publish.start", {
|
|
44045
44965
|
name: args.name,
|
|
44046
44966
|
sessionId: boundSession.sessionId,
|
|
44047
|
-
scriptPath
|
|
44967
|
+
scriptPath,
|
|
44968
|
+
personaRoot
|
|
44048
44969
|
});
|
|
44049
44970
|
const result = await startPublishJob(
|
|
44050
44971
|
{
|
|
@@ -44079,7 +45000,8 @@ function buildAppBuilderHandlers(deps) {
|
|
|
44079
45000
|
{
|
|
44080
45001
|
name: args.name,
|
|
44081
45002
|
sessionId: boundSession.sessionId,
|
|
44082
|
-
scriptPath
|
|
45003
|
+
scriptPath,
|
|
45004
|
+
personaRoot
|
|
44083
45005
|
}
|
|
44084
45006
|
);
|
|
44085
45007
|
return { response: { ...result } };
|
|
@@ -44134,7 +45056,7 @@ function buildAppBuilderHandlers(deps) {
|
|
|
44134
45056
|
|
|
44135
45057
|
// src/extension/registry.ts
|
|
44136
45058
|
var import_promises8 = __toESM(require("fs/promises"), 1);
|
|
44137
|
-
var
|
|
45059
|
+
var import_node_path41 = __toESM(require("path"), 1);
|
|
44138
45060
|
async function loadAll(root) {
|
|
44139
45061
|
let entries;
|
|
44140
45062
|
try {
|
|
@@ -44147,13 +45069,13 @@ async function loadAll(root) {
|
|
|
44147
45069
|
for (const ent of entries) {
|
|
44148
45070
|
if (!ent.isDirectory()) continue;
|
|
44149
45071
|
if (ent.name.startsWith(".")) continue;
|
|
44150
|
-
records.push(await loadOne(
|
|
45072
|
+
records.push(await loadOne(import_node_path41.default.join(root, ent.name), ent.name));
|
|
44151
45073
|
}
|
|
44152
45074
|
records.sort((a, b2) => a.extId < b2.extId ? -1 : a.extId > b2.extId ? 1 : 0);
|
|
44153
45075
|
return records;
|
|
44154
45076
|
}
|
|
44155
45077
|
async function loadOne(dir, dirName) {
|
|
44156
|
-
const manifestPath =
|
|
45078
|
+
const manifestPath = import_node_path41.default.join(dir, "manifest.json");
|
|
44157
45079
|
let raw;
|
|
44158
45080
|
try {
|
|
44159
45081
|
raw = await import_promises8.default.readFile(manifestPath, "utf8");
|
|
@@ -44198,7 +45120,7 @@ async function loadOne(dir, dirName) {
|
|
|
44198
45120
|
|
|
44199
45121
|
// src/extension/uninstall.ts
|
|
44200
45122
|
var import_promises9 = __toESM(require("fs/promises"), 1);
|
|
44201
|
-
var
|
|
45123
|
+
var import_node_path42 = __toESM(require("path"), 1);
|
|
44202
45124
|
var UninstallError = class extends Error {
|
|
44203
45125
|
constructor(code, message) {
|
|
44204
45126
|
super(message);
|
|
@@ -44207,7 +45129,7 @@ var UninstallError = class extends Error {
|
|
|
44207
45129
|
code;
|
|
44208
45130
|
};
|
|
44209
45131
|
async function uninstall(deps) {
|
|
44210
|
-
const dir =
|
|
45132
|
+
const dir = import_node_path42.default.join(deps.root, deps.extId);
|
|
44211
45133
|
try {
|
|
44212
45134
|
await import_promises9.default.access(dir);
|
|
44213
45135
|
} catch {
|
|
@@ -44277,228 +45199,16 @@ function buildMethodHandlers(deps) {
|
|
|
44277
45199
|
broadcastProjectUpdated: deps.broadcastProjectUpdated,
|
|
44278
45200
|
logger: deps.logger,
|
|
44279
45201
|
// 发布上线脚手架化 (spec 2026-06-03 §5.2):
|
|
44280
|
-
// personaRoot
|
|
44281
|
-
//
|
|
45202
|
+
// personaRoot 仅作 resolvePersonaRoot 未注入时的兜底;deployKitRoot 为共享脚本根。
|
|
45203
|
+
// broadcastSessionFrame 用于失败回灌路径(runner 调 manager.send 后逐帧 dispatch 到 transport)。
|
|
44282
45204
|
personaRoot: deps.appBuilderPersonaRoot,
|
|
45205
|
+
deployKitRoot: deps.deployKitRoot,
|
|
44283
45206
|
resolvePersonaRoot: deps.resolvePersonaRoot,
|
|
44284
45207
|
broadcastSessionFrame: deps.broadcastSessionFrame
|
|
44285
45208
|
})
|
|
44286
45209
|
};
|
|
44287
45210
|
}
|
|
44288
45211
|
|
|
44289
|
-
// src/app-builder/project-store.ts
|
|
44290
|
-
var import_node_fs32 = require("fs");
|
|
44291
|
-
var import_node_child_process13 = require("child_process");
|
|
44292
|
-
var import_node_path41 = require("path");
|
|
44293
|
-
init_protocol();
|
|
44294
|
-
var PROJECTS_DIR = "projects";
|
|
44295
|
-
var META_FILE = ".clawd-project.json";
|
|
44296
|
-
var SCAFFOLD_SCRIPT_REL = "extension-kit/scripts/new-extension.sh";
|
|
44297
|
-
var DEFAULT_TEMPLATE = "nestjs-react";
|
|
44298
|
-
var SCAFFOLD_TIMEOUT_MS = 3e4;
|
|
44299
|
-
var ProjectStore = class {
|
|
44300
|
-
/** @param root projects 父目录,例如 `~/.clawd/users/<userId>/`(v2 per-user) */
|
|
44301
|
-
constructor(root) {
|
|
44302
|
-
this.root = root;
|
|
44303
|
-
}
|
|
44304
|
-
root;
|
|
44305
|
-
/** projects/<name>/.clawd-project.json 路径 */
|
|
44306
|
-
metaPath(name) {
|
|
44307
|
-
return (0, import_node_path41.join)(this.projectsRoot(), name, META_FILE);
|
|
44308
|
-
}
|
|
44309
|
-
/** projects/<name>/ 目录路径(cwd 用) */
|
|
44310
|
-
projectDir(name) {
|
|
44311
|
-
return (0, import_node_path41.join)(this.projectsRoot(), name);
|
|
44312
|
-
}
|
|
44313
|
-
projectsRoot() {
|
|
44314
|
-
return (0, import_node_path41.join)(this.root, PROJECTS_DIR);
|
|
44315
|
-
}
|
|
44316
|
-
async list() {
|
|
44317
|
-
let entries;
|
|
44318
|
-
try {
|
|
44319
|
-
entries = await import_node_fs32.promises.readdir(this.projectsRoot());
|
|
44320
|
-
} catch (err) {
|
|
44321
|
-
if (err.code === "ENOENT") return [];
|
|
44322
|
-
throw err;
|
|
44323
|
-
}
|
|
44324
|
-
const out = [];
|
|
44325
|
-
for (const name of entries) {
|
|
44326
|
-
try {
|
|
44327
|
-
const raw = await import_node_fs32.promises.readFile(this.metaPath(name), "utf8");
|
|
44328
|
-
const json = JSON.parse(raw);
|
|
44329
|
-
let migrated = false;
|
|
44330
|
-
if (typeof json.devCommand !== "string" || json.devCommand.length === 0) {
|
|
44331
|
-
json.devCommand = DEFAULT_DEV_COMMAND;
|
|
44332
|
-
migrated = true;
|
|
44333
|
-
}
|
|
44334
|
-
const parsed = ProjectMetadataSchema.safeParse(json);
|
|
44335
|
-
if (parsed.success) {
|
|
44336
|
-
out.push(parsed.data);
|
|
44337
|
-
if (migrated) {
|
|
44338
|
-
void import_node_fs32.promises.writeFile(this.metaPath(name), JSON.stringify(parsed.data, null, 2) + "\n", "utf8").catch(() => {
|
|
44339
|
-
});
|
|
44340
|
-
}
|
|
44341
|
-
}
|
|
44342
|
-
} catch {
|
|
44343
|
-
}
|
|
44344
|
-
}
|
|
44345
|
-
return out.sort((a, b2) => a.name.localeCompare(b2.name));
|
|
44346
|
-
}
|
|
44347
|
-
/**
|
|
44348
|
-
* @param reservedPorts 其它 user 已占端口(v2 per-user:端口必须全局唯一,所有 user 的
|
|
44349
|
-
* dev server 同机跑;per-user store 各自只 list 自己,靠 handler 收集全局端口传进来,
|
|
44350
|
-
* 否则不同 user 的首个项目都从 PROJECT_PORT_MIN 起 → 全撞 6173)。
|
|
44351
|
-
*/
|
|
44352
|
-
async create(name, reservedPorts) {
|
|
44353
|
-
const existing = await this.list();
|
|
44354
|
-
if (existing.some((p2) => p2.name === name)) {
|
|
44355
|
-
throw new Error(`project "${name}" already exists / \u5DF2\u5B58\u5728`);
|
|
44356
|
-
}
|
|
44357
|
-
const usedPorts = new Set(existing.map((p2) => p2.port));
|
|
44358
|
-
if (reservedPorts) for (const p2 of reservedPorts) usedPorts.add(p2);
|
|
44359
|
-
let port = -1;
|
|
44360
|
-
for (let p2 = PROJECT_PORT_MIN; p2 <= PROJECT_PORT_MAX; p2++) {
|
|
44361
|
-
if (!usedPorts.has(p2)) {
|
|
44362
|
-
port = p2;
|
|
44363
|
-
break;
|
|
44364
|
-
}
|
|
44365
|
-
}
|
|
44366
|
-
if (port < 0) {
|
|
44367
|
-
throw new Error(
|
|
44368
|
-
`port pool exhausted / \u7AEF\u53E3\u6C60\u5DF2\u6EE1\uFF08${PROJECT_PORT_MIN}-${PROJECT_PORT_MAX}\uFF09\uFF0C\u5148\u5220\u4E00\u4E2A project \u91CA\u653E\u7AEF\u53E3`
|
|
44369
|
-
);
|
|
44370
|
-
}
|
|
44371
|
-
const meta = {
|
|
44372
|
-
name,
|
|
44373
|
-
port,
|
|
44374
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
44375
|
-
devCommand: DEFAULT_DEV_COMMAND
|
|
44376
|
-
};
|
|
44377
|
-
const validated = ProjectMetadataSchema.safeParse(meta);
|
|
44378
|
-
if (!validated.success) {
|
|
44379
|
-
throw new Error(`invalid name "${name}": ${validated.error.message}`);
|
|
44380
|
-
}
|
|
44381
|
-
const dir = this.projectDir(name);
|
|
44382
|
-
await import_node_fs32.promises.mkdir(dir, { recursive: true });
|
|
44383
|
-
await import_node_fs32.promises.writeFile(this.metaPath(name), JSON.stringify(meta, null, 2) + "\n", "utf8");
|
|
44384
|
-
return meta;
|
|
44385
|
-
}
|
|
44386
|
-
/**
|
|
44387
|
-
* 同步内联 scaffold:spawn `extension-kit/scripts/new-extension.sh <name>` 等 exit。
|
|
44388
|
-
* 必须在 `create()` 之后调(脚本期望 projects/<name>/.clawd-project.json 已就位 = picker 模式)。
|
|
44389
|
-
* 失败抛错;上层(handler)应当 catch 后回滚(删 dir + 不 mutate session)。
|
|
44390
|
-
*
|
|
44391
|
-
* spec 2026-06-02 §5.6.3:scaffold 对 assistant 不可见,避免 assistant 被诱导去"读 example
|
|
44392
|
-
* 代码再参考"。assistant 进 project 时目录已是完整模板,直接 pnpm install 即可。
|
|
44393
|
-
*/
|
|
44394
|
-
async scaffold(name, template = DEFAULT_TEMPLATE, personaRoot = this.root) {
|
|
44395
|
-
const scriptPath = (0, import_node_path41.join)(personaRoot, SCAFFOLD_SCRIPT_REL);
|
|
44396
|
-
const destDir = this.projectDir(name);
|
|
44397
|
-
return await new Promise((resolve6, reject) => {
|
|
44398
|
-
const child = (0, import_node_child_process13.spawn)("bash", [scriptPath, name, template, destDir], {
|
|
44399
|
-
cwd: personaRoot,
|
|
44400
|
-
env: { ...process.env, PATH: process.env.PATH ?? "" },
|
|
44401
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
44402
|
-
});
|
|
44403
|
-
let stdout = "";
|
|
44404
|
-
let stderr = "";
|
|
44405
|
-
child.stdout.on("data", (d) => {
|
|
44406
|
-
stdout += d.toString("utf8");
|
|
44407
|
-
});
|
|
44408
|
-
child.stderr.on("data", (d) => {
|
|
44409
|
-
stderr += d.toString("utf8");
|
|
44410
|
-
});
|
|
44411
|
-
const timer = setTimeout(() => {
|
|
44412
|
-
child.kill("SIGKILL");
|
|
44413
|
-
reject(new Error(`scaffold timeout (>${SCAFFOLD_TIMEOUT_MS}ms): ${scriptPath} ${name} ${template}`));
|
|
44414
|
-
}, SCAFFOLD_TIMEOUT_MS);
|
|
44415
|
-
child.on("error", (err) => {
|
|
44416
|
-
clearTimeout(timer);
|
|
44417
|
-
reject(new Error(`scaffold spawn failed: ${err.message}`));
|
|
44418
|
-
});
|
|
44419
|
-
child.on("exit", (code, signal) => {
|
|
44420
|
-
clearTimeout(timer);
|
|
44421
|
-
if (code === 0) resolve6({ stdout, stderr });
|
|
44422
|
-
else reject(new Error(`scaffold exit ${code ?? signal}: ${stderr.slice(0, 500)}`));
|
|
44423
|
-
});
|
|
44424
|
-
});
|
|
44425
|
-
}
|
|
44426
|
-
async delete(name) {
|
|
44427
|
-
const dir = this.projectDir(name);
|
|
44428
|
-
await import_node_fs32.promises.rm(dir, { recursive: true, force: true });
|
|
44429
|
-
}
|
|
44430
|
-
async updatePort(name, newPort) {
|
|
44431
|
-
if (newPort < PROJECT_PORT_MIN || newPort > PROJECT_PORT_MAX) {
|
|
44432
|
-
throw new Error(
|
|
44433
|
-
`port range invalid: must be ${PROJECT_PORT_MIN}-${PROJECT_PORT_MAX}, got ${newPort}`
|
|
44434
|
-
);
|
|
44435
|
-
}
|
|
44436
|
-
const list = await this.list();
|
|
44437
|
-
const target = list.find((p2) => p2.name === name);
|
|
44438
|
-
if (!target) throw new Error(`project "${name}" not found / \u4E0D\u5B58\u5728`);
|
|
44439
|
-
const conflict = list.find((p2) => p2.name !== name && p2.port === newPort);
|
|
44440
|
-
if (conflict) {
|
|
44441
|
-
throw new Error(`port ${newPort} already used / \u5DF2\u88AB project "${conflict.name}" \u5360\u7528`);
|
|
44442
|
-
}
|
|
44443
|
-
const updated = { ...target, port: newPort };
|
|
44444
|
-
await import_node_fs32.promises.writeFile(this.metaPath(name), JSON.stringify(updated, null, 2) + "\n", "utf8");
|
|
44445
|
-
return updated;
|
|
44446
|
-
}
|
|
44447
|
-
/**
|
|
44448
|
-
* 单栏 refactor (spec 2026-06-02 §5.6.1):发布上线后写公网 URL 到 .clawd-project.json.prodUrl。
|
|
44449
|
-
* UI 通过 listProjects 读到 prodUrl 后切预览栏到线上 URL,取代旧 prod marker 机制。
|
|
44450
|
-
* 重复调用幂等(覆盖旧 URL)。url 由 ProjectMetadataSchema 校验 url() 格式。
|
|
44451
|
-
*/
|
|
44452
|
-
async setProdUrl(name, url) {
|
|
44453
|
-
const list = await this.list();
|
|
44454
|
-
const target = list.find((p2) => p2.name === name);
|
|
44455
|
-
if (!target) throw new Error(`project "${name}" not found / \u4E0D\u5B58\u5728`);
|
|
44456
|
-
const updated = { ...target, prodUrl: url };
|
|
44457
|
-
const validated = ProjectMetadataSchema.safeParse(updated);
|
|
44458
|
-
if (!validated.success) {
|
|
44459
|
-
throw new Error(`invalid prodUrl "${url}": ${validated.error.message}`);
|
|
44460
|
-
}
|
|
44461
|
-
await import_node_fs32.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
|
|
44462
|
-
return validated.data;
|
|
44463
|
-
}
|
|
44464
|
-
/**
|
|
44465
|
-
* 发布上线脚手架化 (spec 2026-06-03-app-builder-publish-scaffold-design §5.1.4):
|
|
44466
|
-
* 写 publishJob 字段到 .clawd-project.json。仅承载 in-flight 状态 ——
|
|
44467
|
-
* - daemon 收到第一个 ::stage::build marker 时写入
|
|
44468
|
-
* - 每次 stage 切换更新 stage 字段(jobId / startedAt 不变)
|
|
44469
|
-
* - 成功 / 失败 / dismiss 时调 clearPublishJob 清掉
|
|
44470
|
-
* - 只有 daemon 崩才会留残骸
|
|
44471
|
-
* 写入时保留所有其他字段(prodUrl 等不受影响)。
|
|
44472
|
-
*/
|
|
44473
|
-
async setPublishJob(name, job) {
|
|
44474
|
-
const list = await this.list();
|
|
44475
|
-
const target = list.find((p2) => p2.name === name);
|
|
44476
|
-
if (!target) throw new Error(`project "${name}" not found / \u4E0D\u5B58\u5728`);
|
|
44477
|
-
const updated = { ...target, publishJob: job };
|
|
44478
|
-
const validated = ProjectMetadataSchema.safeParse(updated);
|
|
44479
|
-
if (!validated.success) {
|
|
44480
|
-
throw new Error(`invalid publishJob: ${validated.error.message}`);
|
|
44481
|
-
}
|
|
44482
|
-
await import_node_fs32.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
|
|
44483
|
-
return validated.data;
|
|
44484
|
-
}
|
|
44485
|
-
/** 清掉 .clawd-project.json.publishJob 字段。其他字段保持原样。 */
|
|
44486
|
-
async clearPublishJob(name) {
|
|
44487
|
-
const list = await this.list();
|
|
44488
|
-
const target = list.find((p2) => p2.name === name);
|
|
44489
|
-
if (!target) throw new Error(`project "${name}" not found / \u4E0D\u5B58\u5728`);
|
|
44490
|
-
if (!target.publishJob) return target;
|
|
44491
|
-
const { publishJob: _drop, ...rest } = target;
|
|
44492
|
-
void _drop;
|
|
44493
|
-
const validated = ProjectMetadataSchema.safeParse(rest);
|
|
44494
|
-
if (!validated.success) {
|
|
44495
|
-
throw new Error(`failed to clear publishJob: ${validated.error.message}`);
|
|
44496
|
-
}
|
|
44497
|
-
await import_node_fs32.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
|
|
44498
|
-
return validated.data;
|
|
44499
|
-
}
|
|
44500
|
-
};
|
|
44501
|
-
|
|
44502
45212
|
// src/app-builder/dev-server-supervisor.ts
|
|
44503
45213
|
var import_node_child_process14 = require("child_process");
|
|
44504
45214
|
var import_node_events2 = require("events");
|
|
@@ -44930,7 +45640,7 @@ function computeGrantForFrame(method, frame) {
|
|
|
44930
45640
|
|
|
44931
45641
|
// src/extension/runtime.ts
|
|
44932
45642
|
var import_node_child_process15 = require("child_process");
|
|
44933
|
-
var
|
|
45643
|
+
var import_node_path43 = __toESM(require("path"), 1);
|
|
44934
45644
|
var import_promises10 = require("timers/promises");
|
|
44935
45645
|
|
|
44936
45646
|
// src/extension/port-allocator.ts
|
|
@@ -45031,7 +45741,7 @@ var Runtime = class {
|
|
|
45031
45741
|
/\$CLAWOS_EXT_PORT/g,
|
|
45032
45742
|
String(port)
|
|
45033
45743
|
);
|
|
45034
|
-
const dir =
|
|
45744
|
+
const dir = import_node_path43.default.join(this.root, extId);
|
|
45035
45745
|
const env = {
|
|
45036
45746
|
...process.env,
|
|
45037
45747
|
CLAWOS_EXT_PORT: String(port),
|
|
@@ -45143,7 +45853,7 @@ ${handle.stderrTail}`
|
|
|
45143
45853
|
|
|
45144
45854
|
// src/extension/published-channels.ts
|
|
45145
45855
|
var import_promises11 = __toESM(require("fs/promises"), 1);
|
|
45146
|
-
var
|
|
45856
|
+
var import_node_path44 = __toESM(require("path"), 1);
|
|
45147
45857
|
init_zod();
|
|
45148
45858
|
var PublishedChannelsError = class extends Error {
|
|
45149
45859
|
constructor(code, message) {
|
|
@@ -45242,7 +45952,7 @@ var PublishedChannelStore = class {
|
|
|
45242
45952
|
)
|
|
45243
45953
|
};
|
|
45244
45954
|
const tmp = `${this.filePath}.tmp`;
|
|
45245
|
-
await import_promises11.default.mkdir(
|
|
45955
|
+
await import_promises11.default.mkdir(import_node_path44.default.dirname(this.filePath), { recursive: true });
|
|
45246
45956
|
await import_promises11.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
|
|
45247
45957
|
await import_promises11.default.rename(tmp, this.filePath);
|
|
45248
45958
|
}
|
|
@@ -45250,7 +45960,7 @@ var PublishedChannelStore = class {
|
|
|
45250
45960
|
|
|
45251
45961
|
// src/extension/bundle-cache.ts
|
|
45252
45962
|
var import_promises12 = __toESM(require("fs/promises"), 1);
|
|
45253
|
-
var
|
|
45963
|
+
var import_node_path45 = __toESM(require("path"), 1);
|
|
45254
45964
|
var BundleCache = class {
|
|
45255
45965
|
constructor(rootDir) {
|
|
45256
45966
|
this.rootDir = rootDir;
|
|
@@ -45259,14 +45969,14 @@ var BundleCache = class {
|
|
|
45259
45969
|
/** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
|
|
45260
45970
|
async write(snapshotHash, buffer) {
|
|
45261
45971
|
await import_promises12.default.mkdir(this.rootDir, { recursive: true });
|
|
45262
|
-
const file =
|
|
45972
|
+
const file = import_node_path45.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
45263
45973
|
const tmp = `${file}.tmp`;
|
|
45264
45974
|
await import_promises12.default.writeFile(tmp, buffer, { mode: 384 });
|
|
45265
45975
|
await import_promises12.default.rename(tmp, file);
|
|
45266
45976
|
}
|
|
45267
45977
|
/** Returns the bundle bytes, or null when the file doesn't exist. */
|
|
45268
45978
|
async read(snapshotHash) {
|
|
45269
|
-
const file =
|
|
45979
|
+
const file = import_node_path45.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
45270
45980
|
try {
|
|
45271
45981
|
return await import_promises12.default.readFile(file);
|
|
45272
45982
|
} catch (e) {
|
|
@@ -45276,16 +45986,33 @@ var BundleCache = class {
|
|
|
45276
45986
|
}
|
|
45277
45987
|
/** Idempotent — missing file is not an error. */
|
|
45278
45988
|
async delete(snapshotHash) {
|
|
45279
|
-
const file =
|
|
45989
|
+
const file = import_node_path45.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
45280
45990
|
await import_promises12.default.rm(file, { force: true });
|
|
45281
45991
|
}
|
|
45282
45992
|
};
|
|
45283
45993
|
|
|
45284
45994
|
// src/index.ts
|
|
45995
|
+
var import_meta4 = {};
|
|
45285
45996
|
async function startDaemon(config) {
|
|
45997
|
+
const authFile = loadOrCreateAuthFile({ dataDir: config.dataDir });
|
|
45998
|
+
const logShippingCfg = config.logShipping ?? { endpoint: null, sampling: {}, mode: "off" };
|
|
45999
|
+
const logClient = createLogClient({
|
|
46000
|
+
endpoint: logShippingCfg.endpoint,
|
|
46001
|
+
identity: {
|
|
46002
|
+
ownerPrincipalId: authFile.ownerPrincipalId,
|
|
46003
|
+
deviceId: authFile.deviceId,
|
|
46004
|
+
appVersion: version,
|
|
46005
|
+
daemonVersion: version,
|
|
46006
|
+
os: `${process.platform}-${process.arch}`
|
|
46007
|
+
},
|
|
46008
|
+
source: "daemon",
|
|
46009
|
+
sampling: logShippingCfg.sampling,
|
|
46010
|
+
homeDir: import_node_os19.default.homedir()
|
|
46011
|
+
});
|
|
45286
46012
|
const logger = createLogger({
|
|
45287
46013
|
level: config.logLevel,
|
|
45288
|
-
file:
|
|
46014
|
+
file: import_node_path46.default.join(config.dataDir, "clawd.log"),
|
|
46015
|
+
logClient
|
|
45289
46016
|
});
|
|
45290
46017
|
logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
|
|
45291
46018
|
const stateMgr = new StateFileManager({ dataDir: config.dataDir });
|
|
@@ -45296,7 +46023,6 @@ async function startDaemon(config) {
|
|
|
45296
46023
|
if (pre.status === "stale") {
|
|
45297
46024
|
logger.warn("stale state file detected, overwriting", { pid: pre.existing.pid });
|
|
45298
46025
|
}
|
|
45299
|
-
const authFile = loadOrCreateAuthFile({ dataDir: config.dataDir });
|
|
45300
46026
|
let resolvedAuthToken = null;
|
|
45301
46027
|
if (config.authToken && config.authToken.trim()) {
|
|
45302
46028
|
resolvedAuthToken = config.authToken.trim();
|
|
@@ -45421,8 +46147,8 @@ async function startDaemon(config) {
|
|
|
45421
46147
|
const agents = new AgentsScanner();
|
|
45422
46148
|
const history = new ClaudeHistoryReader();
|
|
45423
46149
|
let transport = null;
|
|
45424
|
-
const personaStore = new PersonaStore(
|
|
45425
|
-
const usersRoot =
|
|
46150
|
+
const personaStore = new PersonaStore(import_node_path46.default.join(config.dataDir, "personas"));
|
|
46151
|
+
const usersRoot = import_node_path46.default.join(config.dataDir, "users");
|
|
45426
46152
|
const defaultsRoot = findDefaultsRoot();
|
|
45427
46153
|
if (defaultsRoot) {
|
|
45428
46154
|
seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
|
|
@@ -45430,9 +46156,43 @@ async function startDaemon(config) {
|
|
|
45430
46156
|
} else {
|
|
45431
46157
|
logger.warn("persona.seed.skip", { reason: "defaults-root-not-found" });
|
|
45432
46158
|
}
|
|
46159
|
+
const deployKitBundleRoot = findDeployKitRoot();
|
|
46160
|
+
if (deployKitBundleRoot) {
|
|
46161
|
+
seedDeployKit({ deployKitBundleRoot, dataDir: config.dataDir, logger });
|
|
46162
|
+
refreshDeployKit({ deployKitBundleRoot, dataDir: config.dataDir, logger });
|
|
46163
|
+
} else {
|
|
46164
|
+
logger.warn("deploy-kit.bundle-missing", {});
|
|
46165
|
+
}
|
|
45433
46166
|
migrateAgentsMirror({ store: personaStore, logger });
|
|
45434
46167
|
migrateCodexSandbox({ store: personaStore, logger });
|
|
45435
46168
|
const groupFileStore = new GroupFileStore({ dataDir: config.dataDir, logger });
|
|
46169
|
+
const personaDispatchManager = new PersonaDispatchManager({ genId: () => v4_default() });
|
|
46170
|
+
const here = typeof __dirname === "string" ? __dirname : import_node_path46.default.dirname((0, import_node_url2.fileURLToPath)(import_meta4.url));
|
|
46171
|
+
const dispatchServerCandidates = [
|
|
46172
|
+
import_node_path46.default.join(here, "dispatch", "mcp-server.cjs"),
|
|
46173
|
+
// 生产 dist/index → dist/dispatch/mcp-server.cjs
|
|
46174
|
+
import_node_path46.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
|
|
46175
|
+
// dev tsx src/index → ../dist/dispatch/mcp-server.cjs
|
|
46176
|
+
];
|
|
46177
|
+
const dispatchServerScriptPath = dispatchServerCandidates.find((p2) => import_node_fs34.default.existsSync(p2));
|
|
46178
|
+
let dispatchMcpConfigPath2;
|
|
46179
|
+
if (dispatchServerScriptPath) {
|
|
46180
|
+
const dispatchLogPath = import_node_path46.default.join(config.dataDir, "dispatch-mcp-server.log");
|
|
46181
|
+
dispatchMcpConfigPath2 = writeDispatchMcpConfig({
|
|
46182
|
+
dataDir: config.dataDir,
|
|
46183
|
+
serverScriptPath: dispatchServerScriptPath,
|
|
46184
|
+
logPath: dispatchLogPath
|
|
46185
|
+
});
|
|
46186
|
+
logger.info("dispatch.mcp.json written", {
|
|
46187
|
+
path: dispatchMcpConfigPath2,
|
|
46188
|
+
server: dispatchServerScriptPath,
|
|
46189
|
+
serverLog: dispatchLogPath
|
|
46190
|
+
});
|
|
46191
|
+
} else {
|
|
46192
|
+
logger.warn("dispatch-mcp-server.cjs not found; persona dispatch disabled (dev tsx \u6A21\u5F0F\u4E0B\u9700\u5148\u8DD1\u8FC7 build)", {
|
|
46193
|
+
tried: dispatchServerCandidates
|
|
46194
|
+
});
|
|
46195
|
+
}
|
|
45436
46196
|
const manager = new SessionManager({
|
|
45437
46197
|
store,
|
|
45438
46198
|
// Phase 2 (capability platform plan §1): factory 注入后 manager.storeFor 走
|
|
@@ -45442,7 +46202,7 @@ async function startDaemon(config) {
|
|
|
45442
46202
|
getAdapter,
|
|
45443
46203
|
historyReader: history,
|
|
45444
46204
|
dataDir: config.dataDir,
|
|
45445
|
-
personaRoot:
|
|
46205
|
+
personaRoot: import_node_path46.default.join(config.dataDir, "personas"),
|
|
45446
46206
|
usersRoot,
|
|
45447
46207
|
personaStore,
|
|
45448
46208
|
ownerDisplayName,
|
|
@@ -45453,6 +46213,12 @@ async function startDaemon(config) {
|
|
|
45453
46213
|
// 127.0.0.1(不是 config.host)—— cc 跑在本机,loopback 最稳;外部访问限制 + http-router
|
|
45454
46214
|
// 的 isLoopback 兜底已确保安全。
|
|
45455
46215
|
getDaemonUrl: () => `http://127.0.0.1:${config.port}`,
|
|
46216
|
+
// Persona dispatch (Task 8): manager 通过这两个 deps 跟 PersonaDispatchManager 协作。
|
|
46217
|
+
// - personaDispatchManager: manager.createDispatchedSession 用它 registerBSession;
|
|
46218
|
+
// reducer 通过闭包反查 dispatchId 注 CLAWD_DISPATCH_ID env。
|
|
46219
|
+
// - dispatchMcpConfigPath: reducer 透传到 SpawnContext,cc spawn 加 --mcp-config flag。
|
|
46220
|
+
personaDispatchManager,
|
|
46221
|
+
dispatchMcpConfigPath: dispatchMcpConfigPath2,
|
|
45456
46222
|
broadcastFrame: (frame, target) => {
|
|
45457
46223
|
if (target === "all") {
|
|
45458
46224
|
transport?.broadcastAll(frame);
|
|
@@ -45472,10 +46238,10 @@ async function startDaemon(config) {
|
|
|
45472
46238
|
// 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
|
|
45473
46239
|
attachmentGroup: {
|
|
45474
46240
|
onFileEdit: (input) => {
|
|
45475
|
-
const absPath =
|
|
46241
|
+
const absPath = import_node_path46.default.isAbsolute(input.relPath) ? input.relPath : import_node_path46.default.join(input.cwd, input.relPath);
|
|
45476
46242
|
let size = 0;
|
|
45477
46243
|
try {
|
|
45478
|
-
size =
|
|
46244
|
+
size = import_node_fs34.default.statSync(absPath).size;
|
|
45479
46245
|
} catch (err) {
|
|
45480
46246
|
logger.warn("attachment.onFileEdit stat failed", {
|
|
45481
46247
|
sessionId: input.sessionId,
|
|
@@ -45661,11 +46427,11 @@ async function startDaemon(config) {
|
|
|
45661
46427
|
// 'persona/<pid>/owner',default 走 'default'。
|
|
45662
46428
|
getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
|
|
45663
46429
|
// guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
|
|
45664
|
-
personaRoot:
|
|
46430
|
+
personaRoot: import_node_path46.default.join(config.dataDir, "personas"),
|
|
45665
46431
|
usersRoot
|
|
45666
46432
|
},
|
|
45667
46433
|
// workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
|
|
45668
|
-
personaRoot:
|
|
46434
|
+
personaRoot: import_node_path46.default.join(config.dataDir, "personas"),
|
|
45669
46435
|
// v2 多人 persona 隔离:handler 派生 guest user-dir 放行
|
|
45670
46436
|
usersRoot,
|
|
45671
46437
|
// capability:list / delete handler 依赖
|
|
@@ -45754,9 +46520,11 @@ async function startDaemon(config) {
|
|
|
45754
46520
|
// 发布上线脚手架化 (spec 2026-06-03 §5.2):
|
|
45755
46521
|
// appBuilderPersonaRoot 用于拼 publish.sh 绝对路径(persona-app-builder 安装在
|
|
45756
46522
|
// dataDir/personas/persona-app-builder 之下,extension-kit/scripts/publish.sh 是相对路径)。
|
|
45757
|
-
appBuilderPersonaRoot:
|
|
45758
|
-
//
|
|
45759
|
-
|
|
46523
|
+
appBuilderPersonaRoot: import_node_path46.default.join(config.dataDir, "personas", "persona-app-builder"),
|
|
46524
|
+
// 共享 deploy-kit 根:scaffold/publish 脚本骨架 + 阿里云凭证单一真源。
|
|
46525
|
+
deployKitRoot: import_node_path46.default.join(config.dataDir, "deploy-kit"),
|
|
46526
|
+
// scaffold/publish 按当前 session 的 persona 解析其安装根,让每个 persona 用自己的模板/注入配置。
|
|
46527
|
+
resolvePersonaRoot: (personaId) => import_node_path46.default.join(config.dataDir, "personas", personaId),
|
|
45760
46528
|
// 发布上线脚手架化 (spec 2026-06-03 §5.2.2):
|
|
45761
46529
|
// 复用 SessionManagerDeps.broadcastFrame 同款 dispatch 逻辑 —— runner 调 manager.send
|
|
45762
46530
|
// 取回 broadcast 帧后逐帧 push 到 transport,跟 manager 自身的 deps 一致。
|
|
@@ -45777,6 +46545,41 @@ async function startDaemon(config) {
|
|
|
45777
46545
|
logger
|
|
45778
46546
|
});
|
|
45779
46547
|
let handlers = makeHandlers();
|
|
46548
|
+
const dispatchHandlers = buildPersonaDispatchHandlers({
|
|
46549
|
+
personaDispatchManager,
|
|
46550
|
+
logger,
|
|
46551
|
+
spawnB: async (args) => {
|
|
46552
|
+
logger.info("dispatch.spawnB.start", {
|
|
46553
|
+
dispatchId: args.dispatchId,
|
|
46554
|
+
targetPersona: args.targetPersona,
|
|
46555
|
+
sourceSessionId: args.sourceSessionId
|
|
46556
|
+
});
|
|
46557
|
+
const sourceFile = manager.findOwnedSession(args.sourceSessionId);
|
|
46558
|
+
if (!sourceFile) {
|
|
46559
|
+
throw new Error(`personaDispatch:run source session not found: ${args.sourceSessionId}`);
|
|
46560
|
+
}
|
|
46561
|
+
const sourceJsonlPath = sourceFile.toolSessionId ? import_node_path46.default.join(
|
|
46562
|
+
import_node_os19.default.homedir(),
|
|
46563
|
+
".claude",
|
|
46564
|
+
"projects",
|
|
46565
|
+
cwdToHashDir(sourceFile.cwd),
|
|
46566
|
+
`${sourceFile.toolSessionId}.jsonl`
|
|
46567
|
+
) : "(no transcript yet \u2014 operate from the task description alone)";
|
|
46568
|
+
logger.info("dispatch.spawnB.source-resolved", {
|
|
46569
|
+
dispatchId: args.dispatchId,
|
|
46570
|
+
sourceJsonlPath,
|
|
46571
|
+
hasToolSessionId: Boolean(sourceFile.toolSessionId)
|
|
46572
|
+
});
|
|
46573
|
+
manager.createDispatchedSession({
|
|
46574
|
+
dispatchId: args.dispatchId,
|
|
46575
|
+
sourceSessionId: args.sourceSessionId,
|
|
46576
|
+
targetPersona: args.targetPersona,
|
|
46577
|
+
prompt: args.prompt,
|
|
46578
|
+
sourceJsonlPath
|
|
46579
|
+
});
|
|
46580
|
+
}
|
|
46581
|
+
});
|
|
46582
|
+
handlers = { ...handlers, ...dispatchHandlers };
|
|
45780
46583
|
const authResolver = new AuthContextResolver({
|
|
45781
46584
|
ownerToken: resolvedAuthToken
|
|
45782
46585
|
});
|
|
@@ -45851,6 +46654,10 @@ async function startDaemon(config) {
|
|
|
45851
46654
|
manager,
|
|
45852
46655
|
getAdapter,
|
|
45853
46656
|
getTunnelUrl: () => currentTunnelUrl,
|
|
46657
|
+
getLogShipping: () => config.logShipping ? {
|
|
46658
|
+
endpoint: config.logShipping.endpoint,
|
|
46659
|
+
sampling: config.logShipping.sampling
|
|
46660
|
+
} : null,
|
|
45854
46661
|
// ready 帧 mode = daemon CC spawn 模式('sdk' | 'tui');UI 用它挂 XtermPanel
|
|
45855
46662
|
mode: config.mode,
|
|
45856
46663
|
// file-sharing 字段:httpBaseUrl 跟 tunnel 状态走;httpToken 复用 owner WS token
|
|
@@ -46005,8 +46812,8 @@ async function startDaemon(config) {
|
|
|
46005
46812
|
const lines = [
|
|
46006
46813
|
`Tunnel: ${r.url}`,
|
|
46007
46814
|
...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
|
|
46008
|
-
`Frpc config: ${
|
|
46009
|
-
`Frpc log: ${
|
|
46815
|
+
`Frpc config: ${import_node_path46.default.join(config.dataDir, "frpc.toml")}`,
|
|
46816
|
+
`Frpc log: ${import_node_path46.default.join(config.dataDir, "frpc.log")}`
|
|
46010
46817
|
];
|
|
46011
46818
|
const width = Math.max(...lines.map((l) => l.length));
|
|
46012
46819
|
const bar = "\u2550".repeat(width + 4);
|
|
@@ -46019,8 +46826,8 @@ ${bar}
|
|
|
46019
46826
|
|
|
46020
46827
|
`);
|
|
46021
46828
|
try {
|
|
46022
|
-
const connectPath =
|
|
46023
|
-
|
|
46829
|
+
const connectPath = import_node_path46.default.join(config.dataDir, "connect.txt");
|
|
46830
|
+
import_node_fs34.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
|
|
46024
46831
|
} catch {
|
|
46025
46832
|
}
|
|
46026
46833
|
} catch (err) {
|
|
@@ -46081,6 +46888,7 @@ ${bar}
|
|
|
46081
46888
|
}
|
|
46082
46889
|
await wss.stop();
|
|
46083
46890
|
stateMgr.delete();
|
|
46891
|
+
if (logClient) await logClient.dispose();
|
|
46084
46892
|
};
|
|
46085
46893
|
return {
|
|
46086
46894
|
stop: shutdown,
|
|
@@ -46091,9 +46899,9 @@ ${bar}
|
|
|
46091
46899
|
};
|
|
46092
46900
|
}
|
|
46093
46901
|
function migrateDropPersonsDir(dataDir) {
|
|
46094
|
-
const dir =
|
|
46902
|
+
const dir = import_node_path46.default.join(dataDir, "persons");
|
|
46095
46903
|
try {
|
|
46096
|
-
|
|
46904
|
+
import_node_fs34.default.rmSync(dir, { recursive: true, force: true });
|
|
46097
46905
|
} catch {
|
|
46098
46906
|
}
|
|
46099
46907
|
}
|