@clawos-dev/clawd 0.2.612 → 0.2.613
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/app-builder-plugin/mcp-server.cjs +6 -0
- package/dist/cli.cjs +1139 -731
- package/dist/cloud-persona-conversations.html +5 -5
- package/dist/dispatch/mcp-server.cjs +6 -0
- package/dist/persona-defaults/persona-app-builder/mcp/clawd-app-builder/mcp-server.cjs +6 -0
- package/dist/persona-defaults/persona-dataclaw-builder/mcp/clawd-app-builder/mcp-server.cjs +6 -0
- package/dist/share-ui/assets/{guest-DU3dcVMc.js → guest-BXOhTM3E.js} +128 -128
- package/dist/share-ui/guest.html +1 -1
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -450,8 +450,8 @@ var init_parseUtil = __esm({
|
|
|
450
450
|
init_errors();
|
|
451
451
|
init_en();
|
|
452
452
|
makeIssue = (params) => {
|
|
453
|
-
const { data, path:
|
|
454
|
-
const fullPath = [...
|
|
453
|
+
const { data, path: path107, errorMaps, issueData } = params;
|
|
454
|
+
const fullPath = [...path107, ...issueData.path || []];
|
|
455
455
|
const fullIssue = {
|
|
456
456
|
...issueData,
|
|
457
457
|
path: fullPath
|
|
@@ -762,11 +762,11 @@ var init_types = __esm({
|
|
|
762
762
|
init_parseUtil();
|
|
763
763
|
init_util();
|
|
764
764
|
ParseInputLazyPath = class {
|
|
765
|
-
constructor(parent, value,
|
|
765
|
+
constructor(parent, value, path107, key) {
|
|
766
766
|
this._cachedPath = [];
|
|
767
767
|
this.parent = parent;
|
|
768
768
|
this.data = value;
|
|
769
|
-
this._path =
|
|
769
|
+
this._path = path107;
|
|
770
770
|
this._key = key;
|
|
771
771
|
}
|
|
772
772
|
get path() {
|
|
@@ -7968,11 +7968,12 @@ var init_persona_schemas = __esm({
|
|
|
7968
7968
|
});
|
|
7969
7969
|
|
|
7970
7970
|
// ../protocol/src/events.ts
|
|
7971
|
-
var DAEMON_MODE_VALUES, SESSION_STATUS_VALUES, HISTORY_USER_META_VALUES, SKILL_SOURCE_VALUES, AGENT_SOURCE_VALUES, ASK_USER_QUESTION_TOOL_NAME;
|
|
7971
|
+
var DAEMON_MODE_VALUES, CLOUD_HISTORY_REFRESH_KIND, SESSION_STATUS_VALUES, HISTORY_USER_META_VALUES, SKILL_SOURCE_VALUES, AGENT_SOURCE_VALUES, ASK_USER_QUESTION_TOOL_NAME;
|
|
7972
7972
|
var init_events = __esm({
|
|
7973
7973
|
"../protocol/src/events.ts"() {
|
|
7974
7974
|
"use strict";
|
|
7975
7975
|
DAEMON_MODE_VALUES = ["sdk", "tui"];
|
|
7976
|
+
CLOUD_HISTORY_REFRESH_KIND = "cloud_history_refresh";
|
|
7976
7977
|
SESSION_STATUS_VALUES = [
|
|
7977
7978
|
"idle",
|
|
7978
7979
|
"running",
|
|
@@ -8165,6 +8166,12 @@ var init_schemas = __esm({
|
|
|
8165
8166
|
});
|
|
8166
8167
|
SessionFileSchema = external_exports.object({
|
|
8167
8168
|
sessionId: external_exports.string().min(1),
|
|
8169
|
+
/** New gateway execution identity after session:new; defaults to sessionId for the first execution. */
|
|
8170
|
+
cloudExecutionId: external_exports.string().min(1).optional(),
|
|
8171
|
+
/** Owner gateway session observed in ready; proves the remote Pod was opened. */
|
|
8172
|
+
cloudGatewaySessionId: external_exports.string().min(1).optional(),
|
|
8173
|
+
/** Persisted before sending so daemon restart can retry the same gateway command ID. */
|
|
8174
|
+
cloudPendingCommand: external_exports.object({ id: external_exports.string().min(1), text: external_exports.string(), prepared: external_exports.boolean().optional() }).optional(),
|
|
8168
8175
|
cwd: external_exports.string().min(1),
|
|
8169
8176
|
tool: external_exports.literal("claude").or(external_exports.string().min(1)).default("claude"),
|
|
8170
8177
|
// 归一化 tool 侧 session id(CC = claude session uuid,Codex = codex 自己的 id)
|
|
@@ -10345,8 +10352,8 @@ var require_req = __commonJS({
|
|
|
10345
10352
|
if (req.originalUrl) {
|
|
10346
10353
|
_req.url = req.originalUrl;
|
|
10347
10354
|
} else {
|
|
10348
|
-
const
|
|
10349
|
-
_req.url = typeof
|
|
10355
|
+
const path107 = req.path;
|
|
10356
|
+
_req.url = typeof path107 === "string" ? path107 : req.url ? req.url.path || req.url : void 0;
|
|
10350
10357
|
}
|
|
10351
10358
|
if (req.query) {
|
|
10352
10359
|
_req.query = req.query;
|
|
@@ -10511,14 +10518,14 @@ var require_redact = __commonJS({
|
|
|
10511
10518
|
}
|
|
10512
10519
|
return obj;
|
|
10513
10520
|
}
|
|
10514
|
-
function parsePath(
|
|
10521
|
+
function parsePath(path107) {
|
|
10515
10522
|
const parts = [];
|
|
10516
10523
|
let current = "";
|
|
10517
10524
|
let inBrackets = false;
|
|
10518
10525
|
let inQuotes = false;
|
|
10519
10526
|
let quoteChar = "";
|
|
10520
|
-
for (let i2 = 0; i2 <
|
|
10521
|
-
const char =
|
|
10527
|
+
for (let i2 = 0; i2 < path107.length; i2++) {
|
|
10528
|
+
const char = path107[i2];
|
|
10522
10529
|
if (!inBrackets && char === ".") {
|
|
10523
10530
|
if (current) {
|
|
10524
10531
|
parts.push(current);
|
|
@@ -10649,10 +10656,10 @@ var require_redact = __commonJS({
|
|
|
10649
10656
|
return current;
|
|
10650
10657
|
}
|
|
10651
10658
|
function redactPaths(obj, paths, censor, remove = false) {
|
|
10652
|
-
for (const
|
|
10653
|
-
const parts = parsePath(
|
|
10659
|
+
for (const path107 of paths) {
|
|
10660
|
+
const parts = parsePath(path107);
|
|
10654
10661
|
if (parts.includes("*")) {
|
|
10655
|
-
redactWildcardPath(obj, parts, censor,
|
|
10662
|
+
redactWildcardPath(obj, parts, censor, path107, remove);
|
|
10656
10663
|
} else {
|
|
10657
10664
|
if (remove) {
|
|
10658
10665
|
removeKey(obj, parts);
|
|
@@ -10737,8 +10744,8 @@ var require_redact = __commonJS({
|
|
|
10737
10744
|
}
|
|
10738
10745
|
} else {
|
|
10739
10746
|
if (afterWildcard.includes("*")) {
|
|
10740
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
10741
|
-
const fullPath = [...pathArray.slice(0, pathLength), ...
|
|
10747
|
+
const wrappedCensor = typeof censor === "function" ? (value, path107) => {
|
|
10748
|
+
const fullPath = [...pathArray.slice(0, pathLength), ...path107];
|
|
10742
10749
|
return censor(value, fullPath);
|
|
10743
10750
|
} : censor;
|
|
10744
10751
|
redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
|
|
@@ -10773,8 +10780,8 @@ var require_redact = __commonJS({
|
|
|
10773
10780
|
return null;
|
|
10774
10781
|
}
|
|
10775
10782
|
const pathStructure = /* @__PURE__ */ new Map();
|
|
10776
|
-
for (const
|
|
10777
|
-
const parts = parsePath(
|
|
10783
|
+
for (const path107 of pathsToClone) {
|
|
10784
|
+
const parts = parsePath(path107);
|
|
10778
10785
|
let current = pathStructure;
|
|
10779
10786
|
for (let i2 = 0; i2 < parts.length; i2++) {
|
|
10780
10787
|
const part = parts[i2];
|
|
@@ -10826,24 +10833,24 @@ var require_redact = __commonJS({
|
|
|
10826
10833
|
}
|
|
10827
10834
|
return cloneSelectively(obj, pathStructure);
|
|
10828
10835
|
}
|
|
10829
|
-
function validatePath(
|
|
10830
|
-
if (typeof
|
|
10836
|
+
function validatePath(path107) {
|
|
10837
|
+
if (typeof path107 !== "string") {
|
|
10831
10838
|
throw new Error("Paths must be (non-empty) strings");
|
|
10832
10839
|
}
|
|
10833
|
-
if (
|
|
10840
|
+
if (path107 === "") {
|
|
10834
10841
|
throw new Error("Invalid redaction path ()");
|
|
10835
10842
|
}
|
|
10836
|
-
if (
|
|
10837
|
-
throw new Error(`Invalid redaction path (${
|
|
10843
|
+
if (path107.includes("..")) {
|
|
10844
|
+
throw new Error(`Invalid redaction path (${path107})`);
|
|
10838
10845
|
}
|
|
10839
|
-
if (
|
|
10840
|
-
throw new Error(`Invalid redaction path (${
|
|
10846
|
+
if (path107.includes(",")) {
|
|
10847
|
+
throw new Error(`Invalid redaction path (${path107})`);
|
|
10841
10848
|
}
|
|
10842
10849
|
let bracketCount = 0;
|
|
10843
10850
|
let inQuotes = false;
|
|
10844
10851
|
let quoteChar = "";
|
|
10845
|
-
for (let i2 = 0; i2 <
|
|
10846
|
-
const char =
|
|
10852
|
+
for (let i2 = 0; i2 < path107.length; i2++) {
|
|
10853
|
+
const char = path107[i2];
|
|
10847
10854
|
if ((char === '"' || char === "'") && bracketCount > 0) {
|
|
10848
10855
|
if (!inQuotes) {
|
|
10849
10856
|
inQuotes = true;
|
|
@@ -10857,20 +10864,20 @@ var require_redact = __commonJS({
|
|
|
10857
10864
|
} else if (char === "]" && !inQuotes) {
|
|
10858
10865
|
bracketCount--;
|
|
10859
10866
|
if (bracketCount < 0) {
|
|
10860
|
-
throw new Error(`Invalid redaction path (${
|
|
10867
|
+
throw new Error(`Invalid redaction path (${path107})`);
|
|
10861
10868
|
}
|
|
10862
10869
|
}
|
|
10863
10870
|
}
|
|
10864
10871
|
if (bracketCount !== 0) {
|
|
10865
|
-
throw new Error(`Invalid redaction path (${
|
|
10872
|
+
throw new Error(`Invalid redaction path (${path107})`);
|
|
10866
10873
|
}
|
|
10867
10874
|
}
|
|
10868
10875
|
function validatePaths(paths) {
|
|
10869
10876
|
if (!Array.isArray(paths)) {
|
|
10870
10877
|
throw new TypeError("paths must be an array");
|
|
10871
10878
|
}
|
|
10872
|
-
for (const
|
|
10873
|
-
validatePath(
|
|
10879
|
+
for (const path107 of paths) {
|
|
10880
|
+
validatePath(path107);
|
|
10874
10881
|
}
|
|
10875
10882
|
}
|
|
10876
10883
|
function slowRedact(options = {}) {
|
|
@@ -11038,8 +11045,8 @@ var require_redaction = __commonJS({
|
|
|
11038
11045
|
if (shape[k3] === null) {
|
|
11039
11046
|
o2[k3] = (value) => topCensor(value, [k3]);
|
|
11040
11047
|
} else {
|
|
11041
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
11042
|
-
return censor(value, [k3, ...
|
|
11048
|
+
const wrappedCensor = typeof censor === "function" ? (value, path107) => {
|
|
11049
|
+
return censor(value, [k3, ...path107]);
|
|
11043
11050
|
} : censor;
|
|
11044
11051
|
o2[k3] = Redact({
|
|
11045
11052
|
paths: shape[k3],
|
|
@@ -11257,10 +11264,10 @@ var require_atomic_sleep = __commonJS({
|
|
|
11257
11264
|
var require_sonic_boom = __commonJS({
|
|
11258
11265
|
"../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
|
|
11259
11266
|
"use strict";
|
|
11260
|
-
var
|
|
11267
|
+
var fs96 = require("fs");
|
|
11261
11268
|
var EventEmitter2 = require("events");
|
|
11262
11269
|
var inherits = require("util").inherits;
|
|
11263
|
-
var
|
|
11270
|
+
var path107 = require("path");
|
|
11264
11271
|
var sleep2 = require_atomic_sleep();
|
|
11265
11272
|
var assert = require("assert");
|
|
11266
11273
|
var BUSY_WRITE_TIMEOUT = 100;
|
|
@@ -11314,20 +11321,20 @@ var require_sonic_boom = __commonJS({
|
|
|
11314
11321
|
const mode = sonic.mode;
|
|
11315
11322
|
if (sonic.sync) {
|
|
11316
11323
|
try {
|
|
11317
|
-
if (sonic.mkdir)
|
|
11318
|
-
const fd =
|
|
11324
|
+
if (sonic.mkdir) fs96.mkdirSync(path107.dirname(file), { recursive: true });
|
|
11325
|
+
const fd = fs96.openSync(file, flags, mode);
|
|
11319
11326
|
fileOpened(null, fd);
|
|
11320
11327
|
} catch (err) {
|
|
11321
11328
|
fileOpened(err);
|
|
11322
11329
|
throw err;
|
|
11323
11330
|
}
|
|
11324
11331
|
} else if (sonic.mkdir) {
|
|
11325
|
-
|
|
11332
|
+
fs96.mkdir(path107.dirname(file), { recursive: true }, (err) => {
|
|
11326
11333
|
if (err) return fileOpened(err);
|
|
11327
|
-
|
|
11334
|
+
fs96.open(file, flags, mode, fileOpened);
|
|
11328
11335
|
});
|
|
11329
11336
|
} else {
|
|
11330
|
-
|
|
11337
|
+
fs96.open(file, flags, mode, fileOpened);
|
|
11331
11338
|
}
|
|
11332
11339
|
}
|
|
11333
11340
|
function SonicBoom(opts) {
|
|
@@ -11368,8 +11375,8 @@ var require_sonic_boom = __commonJS({
|
|
|
11368
11375
|
this.flush = flushBuffer;
|
|
11369
11376
|
this.flushSync = flushBufferSync;
|
|
11370
11377
|
this._actualWrite = actualWriteBuffer;
|
|
11371
|
-
fsWriteSync = () =>
|
|
11372
|
-
fsWrite = () =>
|
|
11378
|
+
fsWriteSync = () => fs96.writeSync(this.fd, this._writingBuf);
|
|
11379
|
+
fsWrite = () => fs96.write(this.fd, this._writingBuf, this.release);
|
|
11373
11380
|
} else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
|
|
11374
11381
|
this._writingBuf = "";
|
|
11375
11382
|
this.write = write;
|
|
@@ -11378,15 +11385,15 @@ var require_sonic_boom = __commonJS({
|
|
|
11378
11385
|
this._actualWrite = actualWrite;
|
|
11379
11386
|
fsWriteSync = () => {
|
|
11380
11387
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
11381
|
-
return
|
|
11388
|
+
return fs96.writeSync(this.fd, this._writingBuf);
|
|
11382
11389
|
}
|
|
11383
|
-
return
|
|
11390
|
+
return fs96.writeSync(this.fd, this._writingBuf, "utf8");
|
|
11384
11391
|
};
|
|
11385
11392
|
fsWrite = () => {
|
|
11386
11393
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
11387
|
-
return
|
|
11394
|
+
return fs96.write(this.fd, this._writingBuf, this.release);
|
|
11388
11395
|
}
|
|
11389
|
-
return
|
|
11396
|
+
return fs96.write(this.fd, this._writingBuf, "utf8", this.release);
|
|
11390
11397
|
};
|
|
11391
11398
|
} else {
|
|
11392
11399
|
throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
|
|
@@ -11443,7 +11450,7 @@ var require_sonic_boom = __commonJS({
|
|
|
11443
11450
|
}
|
|
11444
11451
|
}
|
|
11445
11452
|
if (this._fsync) {
|
|
11446
|
-
|
|
11453
|
+
fs96.fsyncSync(this.fd);
|
|
11447
11454
|
}
|
|
11448
11455
|
const len = this._len;
|
|
11449
11456
|
if (this._reopening) {
|
|
@@ -11557,7 +11564,7 @@ var require_sonic_boom = __commonJS({
|
|
|
11557
11564
|
const onDrain = () => {
|
|
11558
11565
|
if (!this._fsync) {
|
|
11559
11566
|
try {
|
|
11560
|
-
|
|
11567
|
+
fs96.fsync(this.fd, (err) => {
|
|
11561
11568
|
this._flushPending = false;
|
|
11562
11569
|
cb(err);
|
|
11563
11570
|
});
|
|
@@ -11659,7 +11666,7 @@ var require_sonic_boom = __commonJS({
|
|
|
11659
11666
|
const fd = this.fd;
|
|
11660
11667
|
this.once("ready", () => {
|
|
11661
11668
|
if (fd !== this.fd) {
|
|
11662
|
-
|
|
11669
|
+
fs96.close(fd, (err) => {
|
|
11663
11670
|
if (err) {
|
|
11664
11671
|
return this.emit("error", err);
|
|
11665
11672
|
}
|
|
@@ -11708,7 +11715,7 @@ var require_sonic_boom = __commonJS({
|
|
|
11708
11715
|
buf = this._bufs[0];
|
|
11709
11716
|
}
|
|
11710
11717
|
try {
|
|
11711
|
-
const n2 = Buffer.isBuffer(buf) ?
|
|
11718
|
+
const n2 = Buffer.isBuffer(buf) ? fs96.writeSync(this.fd, buf) : fs96.writeSync(this.fd, buf, "utf8");
|
|
11712
11719
|
const releasedBufObj = releaseWritingBuf(buf, this._len, n2);
|
|
11713
11720
|
buf = releasedBufObj.writingBuf;
|
|
11714
11721
|
this._len = releasedBufObj.len;
|
|
@@ -11724,7 +11731,7 @@ var require_sonic_boom = __commonJS({
|
|
|
11724
11731
|
}
|
|
11725
11732
|
}
|
|
11726
11733
|
try {
|
|
11727
|
-
|
|
11734
|
+
fs96.fsyncSync(this.fd);
|
|
11728
11735
|
} catch {
|
|
11729
11736
|
}
|
|
11730
11737
|
}
|
|
@@ -11745,7 +11752,7 @@ var require_sonic_boom = __commonJS({
|
|
|
11745
11752
|
buf = mergeBuf(this._bufs[0], this._lens[0]);
|
|
11746
11753
|
}
|
|
11747
11754
|
try {
|
|
11748
|
-
const n2 =
|
|
11755
|
+
const n2 = fs96.writeSync(this.fd, buf);
|
|
11749
11756
|
buf = buf.subarray(n2);
|
|
11750
11757
|
this._len = Math.max(this._len - n2, 0);
|
|
11751
11758
|
if (buf.length <= 0) {
|
|
@@ -11773,13 +11780,13 @@ var require_sonic_boom = __commonJS({
|
|
|
11773
11780
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
|
|
11774
11781
|
if (this.sync) {
|
|
11775
11782
|
try {
|
|
11776
|
-
const written = Buffer.isBuffer(this._writingBuf) ?
|
|
11783
|
+
const written = Buffer.isBuffer(this._writingBuf) ? fs96.writeSync(this.fd, this._writingBuf) : fs96.writeSync(this.fd, this._writingBuf, "utf8");
|
|
11777
11784
|
release2(null, written);
|
|
11778
11785
|
} catch (err) {
|
|
11779
11786
|
release2(err);
|
|
11780
11787
|
}
|
|
11781
11788
|
} else {
|
|
11782
|
-
|
|
11789
|
+
fs96.write(this.fd, this._writingBuf, release2);
|
|
11783
11790
|
}
|
|
11784
11791
|
}
|
|
11785
11792
|
function actualWriteBuffer() {
|
|
@@ -11788,7 +11795,7 @@ var require_sonic_boom = __commonJS({
|
|
|
11788
11795
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
|
|
11789
11796
|
if (this.sync) {
|
|
11790
11797
|
try {
|
|
11791
|
-
const written =
|
|
11798
|
+
const written = fs96.writeSync(this.fd, this._writingBuf);
|
|
11792
11799
|
release2(null, written);
|
|
11793
11800
|
} catch (err) {
|
|
11794
11801
|
release2(err);
|
|
@@ -11797,7 +11804,7 @@ var require_sonic_boom = __commonJS({
|
|
|
11797
11804
|
if (kCopyBuffer) {
|
|
11798
11805
|
this._writingBuf = Buffer.from(this._writingBuf);
|
|
11799
11806
|
}
|
|
11800
|
-
|
|
11807
|
+
fs96.write(this.fd, this._writingBuf, release2);
|
|
11801
11808
|
}
|
|
11802
11809
|
}
|
|
11803
11810
|
function actualClose(sonic) {
|
|
@@ -11813,12 +11820,12 @@ var require_sonic_boom = __commonJS({
|
|
|
11813
11820
|
sonic._lens = [];
|
|
11814
11821
|
assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
|
|
11815
11822
|
try {
|
|
11816
|
-
|
|
11823
|
+
fs96.fsync(sonic.fd, closeWrapped);
|
|
11817
11824
|
} catch {
|
|
11818
11825
|
}
|
|
11819
11826
|
function closeWrapped() {
|
|
11820
11827
|
if (sonic.fd !== 1 && sonic.fd !== 2) {
|
|
11821
|
-
|
|
11828
|
+
fs96.close(sonic.fd, done);
|
|
11822
11829
|
} else {
|
|
11823
11830
|
done();
|
|
11824
11831
|
}
|
|
@@ -14953,11 +14960,11 @@ var init_lib = __esm({
|
|
|
14953
14960
|
}
|
|
14954
14961
|
}
|
|
14955
14962
|
},
|
|
14956
|
-
addToPath: function addToPath(
|
|
14957
|
-
var last =
|
|
14963
|
+
addToPath: function addToPath(path107, added, removed, oldPosInc, options) {
|
|
14964
|
+
var last = path107.lastComponent;
|
|
14958
14965
|
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
14959
14966
|
return {
|
|
14960
|
-
oldPos:
|
|
14967
|
+
oldPos: path107.oldPos + oldPosInc,
|
|
14961
14968
|
lastComponent: {
|
|
14962
14969
|
count: last.count + 1,
|
|
14963
14970
|
added,
|
|
@@ -14967,7 +14974,7 @@ var init_lib = __esm({
|
|
|
14967
14974
|
};
|
|
14968
14975
|
} else {
|
|
14969
14976
|
return {
|
|
14970
|
-
oldPos:
|
|
14977
|
+
oldPos: path107.oldPos + oldPosInc,
|
|
14971
14978
|
lastComponent: {
|
|
14972
14979
|
count: 1,
|
|
14973
14980
|
added,
|
|
@@ -15549,10 +15556,10 @@ function attachmentToHistoryMessage(o2, ts) {
|
|
|
15549
15556
|
const memories = raw.map((m3) => {
|
|
15550
15557
|
if (!m3 || typeof m3 !== "object") return null;
|
|
15551
15558
|
const rec6 = m3;
|
|
15552
|
-
const
|
|
15559
|
+
const path107 = typeof rec6.path === "string" ? rec6.path : null;
|
|
15553
15560
|
const content = typeof rec6.content === "string" ? rec6.content : null;
|
|
15554
|
-
if (!
|
|
15555
|
-
const entry = { path:
|
|
15561
|
+
if (!path107 || content == null) return null;
|
|
15562
|
+
const entry = { path: path107, content };
|
|
15556
15563
|
if (typeof rec6.mtimeMs === "number") entry.mtimeMs = rec6.mtimeMs;
|
|
15557
15564
|
return entry;
|
|
15558
15565
|
}).filter((m3) => m3 !== null);
|
|
@@ -16418,10 +16425,10 @@ function parseAttachment(obj) {
|
|
|
16418
16425
|
const memories = raw.map((m3) => {
|
|
16419
16426
|
if (!m3 || typeof m3 !== "object") return null;
|
|
16420
16427
|
const rec6 = m3;
|
|
16421
|
-
const
|
|
16428
|
+
const path107 = typeof rec6.path === "string" ? rec6.path : null;
|
|
16422
16429
|
const content = typeof rec6.content === "string" ? rec6.content : null;
|
|
16423
|
-
if (!
|
|
16424
|
-
const out = { path:
|
|
16430
|
+
if (!path107 || content == null) return null;
|
|
16431
|
+
const out = { path: path107, content };
|
|
16425
16432
|
if (typeof rec6.mtimeMs === "number") out.mtimeMs = rec6.mtimeMs;
|
|
16426
16433
|
return out;
|
|
16427
16434
|
}).filter((m3) => m3 !== null);
|
|
@@ -37395,8 +37402,8 @@ var require_utils = __commonJS({
|
|
|
37395
37402
|
var result = transform[inputType][outputType](input);
|
|
37396
37403
|
return result;
|
|
37397
37404
|
};
|
|
37398
|
-
exports2.resolve = function(
|
|
37399
|
-
var parts =
|
|
37405
|
+
exports2.resolve = function(path107) {
|
|
37406
|
+
var parts = path107.split("/");
|
|
37400
37407
|
var result = [];
|
|
37401
37408
|
for (var index = 0; index < parts.length; index++) {
|
|
37402
37409
|
var part = parts[index];
|
|
@@ -43249,18 +43256,18 @@ var require_object = __commonJS({
|
|
|
43249
43256
|
var object = new ZipObject(name, zipObjectContent, o2);
|
|
43250
43257
|
this.files[name] = object;
|
|
43251
43258
|
};
|
|
43252
|
-
var parentFolder = function(
|
|
43253
|
-
if (
|
|
43254
|
-
|
|
43259
|
+
var parentFolder = function(path107) {
|
|
43260
|
+
if (path107.slice(-1) === "/") {
|
|
43261
|
+
path107 = path107.substring(0, path107.length - 1);
|
|
43255
43262
|
}
|
|
43256
|
-
var lastSlash =
|
|
43257
|
-
return lastSlash > 0 ?
|
|
43263
|
+
var lastSlash = path107.lastIndexOf("/");
|
|
43264
|
+
return lastSlash > 0 ? path107.substring(0, lastSlash) : "";
|
|
43258
43265
|
};
|
|
43259
|
-
var forceTrailingSlash = function(
|
|
43260
|
-
if (
|
|
43261
|
-
|
|
43266
|
+
var forceTrailingSlash = function(path107) {
|
|
43267
|
+
if (path107.slice(-1) !== "/") {
|
|
43268
|
+
path107 += "/";
|
|
43262
43269
|
}
|
|
43263
|
-
return
|
|
43270
|
+
return path107;
|
|
43264
43271
|
};
|
|
43265
43272
|
var folderAdd = function(name, createFolders) {
|
|
43266
43273
|
createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
|
|
@@ -44262,7 +44269,7 @@ var require_lib3 = __commonJS({
|
|
|
44262
44269
|
// src/run-case/recorder.ts
|
|
44263
44270
|
function startRunCaseRecorder(opts) {
|
|
44264
44271
|
const now = opts.now ?? Date.now;
|
|
44265
|
-
const dir =
|
|
44272
|
+
const dir = import_node_path86.default.dirname(opts.recordPath);
|
|
44266
44273
|
let stream = null;
|
|
44267
44274
|
let closing = false;
|
|
44268
44275
|
let closedSettled = false;
|
|
@@ -44276,8 +44283,8 @@ function startRunCaseRecorder(opts) {
|
|
|
44276
44283
|
});
|
|
44277
44284
|
const ensureStream = () => {
|
|
44278
44285
|
if (stream) return stream;
|
|
44279
|
-
|
|
44280
|
-
stream =
|
|
44286
|
+
import_node_fs67.default.mkdirSync(dir, { recursive: true });
|
|
44287
|
+
stream = import_node_fs67.default.createWriteStream(opts.recordPath, { flags: "a" });
|
|
44281
44288
|
stream.on("close", () => closedResolve());
|
|
44282
44289
|
return stream;
|
|
44283
44290
|
};
|
|
@@ -44302,12 +44309,12 @@ function startRunCaseRecorder(opts) {
|
|
|
44302
44309
|
};
|
|
44303
44310
|
return { tap, close, closed };
|
|
44304
44311
|
}
|
|
44305
|
-
var
|
|
44312
|
+
var import_node_fs67, import_node_path86;
|
|
44306
44313
|
var init_recorder = __esm({
|
|
44307
44314
|
"src/run-case/recorder.ts"() {
|
|
44308
44315
|
"use strict";
|
|
44309
|
-
|
|
44310
|
-
|
|
44316
|
+
import_node_fs67 = __toESM(require("fs"), 1);
|
|
44317
|
+
import_node_path86 = __toESM(require("path"), 1);
|
|
44311
44318
|
}
|
|
44312
44319
|
});
|
|
44313
44320
|
|
|
@@ -44350,7 +44357,7 @@ var init_wire = __esm({
|
|
|
44350
44357
|
// src/run-case/controller.ts
|
|
44351
44358
|
async function runController(opts) {
|
|
44352
44359
|
const now = opts.now ?? Date.now;
|
|
44353
|
-
const cwd = opts.cwd ?? (0,
|
|
44360
|
+
const cwd = opts.cwd ?? (0, import_node_fs68.mkdtempSync)(import_node_path87.default.join(import_node_os32.default.tmpdir(), "clawd-runcase-"));
|
|
44354
44361
|
const ownsCwd = opts.cwd === void 0;
|
|
44355
44362
|
const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
|
|
44356
44363
|
const spawnCtx = { cwd };
|
|
@@ -44511,19 +44518,19 @@ async function runController(opts) {
|
|
|
44511
44518
|
if (sigintHandler) process.off("SIGINT", sigintHandler);
|
|
44512
44519
|
if (ownsCwd) {
|
|
44513
44520
|
try {
|
|
44514
|
-
(0,
|
|
44521
|
+
(0, import_node_fs68.rmSync)(cwd, { recursive: true, force: true });
|
|
44515
44522
|
} catch {
|
|
44516
44523
|
}
|
|
44517
44524
|
}
|
|
44518
44525
|
return exitCode ?? 0;
|
|
44519
44526
|
}
|
|
44520
|
-
var
|
|
44527
|
+
var import_node_fs68, import_node_os32, import_node_path87;
|
|
44521
44528
|
var init_controller = __esm({
|
|
44522
44529
|
"src/run-case/controller.ts"() {
|
|
44523
44530
|
"use strict";
|
|
44524
|
-
|
|
44531
|
+
import_node_fs68 = require("fs");
|
|
44525
44532
|
import_node_os32 = __toESM(require("os"), 1);
|
|
44526
|
-
|
|
44533
|
+
import_node_path87 = __toESM(require("path"), 1);
|
|
44527
44534
|
init_claude();
|
|
44528
44535
|
init_stdout_splitter();
|
|
44529
44536
|
init_permission_stdio();
|
|
@@ -44795,10 +44802,10 @@ Env (advanced):
|
|
|
44795
44802
|
`;
|
|
44796
44803
|
|
|
44797
44804
|
// src/index.ts
|
|
44798
|
-
var
|
|
44799
|
-
var
|
|
44805
|
+
var import_node_path85 = __toESM(require("path"), 1);
|
|
44806
|
+
var import_node_fs66 = __toESM(require("fs"), 1);
|
|
44800
44807
|
var import_node_os31 = __toESM(require("os"), 1);
|
|
44801
|
-
var
|
|
44808
|
+
var import_node_crypto28 = require("crypto");
|
|
44802
44809
|
var import_node_url6 = require("url");
|
|
44803
44810
|
|
|
44804
44811
|
// src/logger.ts
|
|
@@ -45951,9 +45958,8 @@ function cloneState(s2) {
|
|
|
45951
45958
|
currentTurnSender: s2.currentTurnSender
|
|
45952
45959
|
};
|
|
45953
45960
|
}
|
|
45954
|
-
var CLOUD_IDLE_KILL_DELAY_MS = 5 * 6e4;
|
|
45955
45961
|
function idleKillDelayOf(state) {
|
|
45956
|
-
if (isCloudTool(state.file.tool)) return
|
|
45962
|
+
if (isCloudTool(state.file.tool)) return void 0;
|
|
45957
45963
|
const ms = state.subSessionMeta?.idleKillDelayMs;
|
|
45958
45964
|
return ms !== void 0 && ms > 0 ? ms : void 0;
|
|
45959
45965
|
}
|
|
@@ -46113,6 +46119,8 @@ function buildSpawnContext(state, deps) {
|
|
|
46113
46119
|
const mcpConfigs = deps.getMcpConfigs?.() ?? [];
|
|
46114
46120
|
const ctx = {
|
|
46115
46121
|
cwd: file.cwd,
|
|
46122
|
+
cloudExecutionId: file.cloudExecutionId,
|
|
46123
|
+
cloudGatewaySessionId: file.cloudGatewaySessionId,
|
|
46116
46124
|
toolSessionId: file.toolSessionId,
|
|
46117
46125
|
model: file.model,
|
|
46118
46126
|
permissionMode: file.permissionMode,
|
|
@@ -46367,7 +46375,11 @@ function pushEventToBufferInPlace(next, event, deps) {
|
|
|
46367
46375
|
}
|
|
46368
46376
|
}
|
|
46369
46377
|
if (isUserText || isTurnEnd) {
|
|
46370
|
-
next.file = {
|
|
46378
|
+
next.file = {
|
|
46379
|
+
...next.file,
|
|
46380
|
+
updatedAt: nowIso(deps),
|
|
46381
|
+
...isCloudTool(next.file.tool) && next.status !== "error" && !(withSeq.kind === "turn_end" && withSeq.reason === "interrupted") ? { cloudPendingCommand: withSeq.kind === "user_text" ? { id: withSeq.uuid ?? `${next.file.sessionId}-${seq}`, text: withSeq.text } : void 0 } : {}
|
|
46382
|
+
};
|
|
46371
46383
|
effects.push({ kind: "persist-file", file: next.file });
|
|
46372
46384
|
effects.push(sessionInfoFrame(next.file));
|
|
46373
46385
|
}
|
|
@@ -46483,6 +46495,10 @@ function applyCommand(state, command, deps) {
|
|
|
46483
46495
|
return { state: next, effects };
|
|
46484
46496
|
}
|
|
46485
46497
|
case "stop": {
|
|
46498
|
+
if (isCloudTool(next.file.tool) && next.file.cloudPendingCommand) {
|
|
46499
|
+
next.file = { ...next.file, cloudPendingCommand: void 0 };
|
|
46500
|
+
effects.push({ kind: "persist-file", file: next.file }, sessionInfoFrame(next.file));
|
|
46501
|
+
}
|
|
46486
46502
|
for (const toolUseId of Object.keys(state.pendingQuestions ?? {})) {
|
|
46487
46503
|
effects.push({
|
|
46488
46504
|
kind: "emit-frame",
|
|
@@ -46616,6 +46632,8 @@ function applyCommand(state, command, deps) {
|
|
|
46616
46632
|
case "new": {
|
|
46617
46633
|
const {
|
|
46618
46634
|
toolSessionId: _drop,
|
|
46635
|
+
cloudPendingCommand: _cloudPendingCommand,
|
|
46636
|
+
cloudGatewaySessionId: _cloudGatewaySessionId,
|
|
46619
46637
|
contextUsage: _ctx,
|
|
46620
46638
|
contextWindowSize: _win,
|
|
46621
46639
|
gitBranch: _branch,
|
|
@@ -46626,6 +46644,8 @@ function applyCommand(state, command, deps) {
|
|
|
46626
46644
|
...rest
|
|
46627
46645
|
} = next.file;
|
|
46628
46646
|
void _drop;
|
|
46647
|
+
void _cloudPendingCommand;
|
|
46648
|
+
void _cloudGatewaySessionId;
|
|
46629
46649
|
void _ctx;
|
|
46630
46650
|
void _win;
|
|
46631
46651
|
void _branch;
|
|
@@ -46634,6 +46654,7 @@ function applyCommand(state, command, deps) {
|
|
|
46634
46654
|
void _titleGeneratedAt;
|
|
46635
46655
|
const nextFile = {
|
|
46636
46656
|
...rest,
|
|
46657
|
+
...command.nextCloudExecutionId ? { cloudExecutionId: command.nextCloudExecutionId } : {},
|
|
46637
46658
|
...command.nextToolSessionId ? { toolSessionId: command.nextToolSessionId } : {},
|
|
46638
46659
|
updatedAt: nowIso(deps)
|
|
46639
46660
|
};
|
|
@@ -46696,9 +46717,31 @@ function reduceSessionInner(state, input, deps) {
|
|
|
46696
46717
|
case "inject-events": {
|
|
46697
46718
|
return applyEventBatch(state, input.events, deps);
|
|
46698
46719
|
}
|
|
46720
|
+
case "cloud-recovery-absent": {
|
|
46721
|
+
if (!state.file.cloudPendingCommand) return { state, effects: [] };
|
|
46722
|
+
const next = cloneState(state);
|
|
46723
|
+
next.file = { ...next.file, cloudPendingCommand: void 0, cloudGatewaySessionId: void 0 };
|
|
46724
|
+
return { state: next, effects: [{ kind: "persist-file", file: next.file }, sessionInfoFrame(next.file)] };
|
|
46725
|
+
}
|
|
46726
|
+
case "cloud-gateway-ready": {
|
|
46727
|
+
if (state.file.cloudGatewaySessionId === input.gatewaySessionId) return { state, effects: [] };
|
|
46728
|
+
const next = cloneState(state);
|
|
46729
|
+
next.file = { ...next.file, cloudGatewaySessionId: input.gatewaySessionId };
|
|
46730
|
+
return { state: next, effects: [{ kind: "persist-file", file: next.file }] };
|
|
46731
|
+
}
|
|
46732
|
+
case "cloud-command-prepared": {
|
|
46733
|
+
const pending = state.file.cloudPendingCommand;
|
|
46734
|
+
if (!pending || pending.id !== input.commandId) return { state, effects: [] };
|
|
46735
|
+
const next = cloneState(state);
|
|
46736
|
+
next.file = { ...next.file, cloudPendingCommand: { id: pending.id, text: input.text, prepared: true } };
|
|
46737
|
+
return { state: next, effects: [{ kind: "persist-file", file: next.file }] };
|
|
46738
|
+
}
|
|
46699
46739
|
case "proc-exit": {
|
|
46700
46740
|
const next = cloneState(state);
|
|
46701
46741
|
next.procAlive = false;
|
|
46742
|
+
if (isCloudTool(next.file.tool) && !next.file.cloudPendingCommand && next.file.cloudGatewaySessionId) {
|
|
46743
|
+
next.file = { ...next.file, cloudGatewaySessionId: void 0 };
|
|
46744
|
+
}
|
|
46702
46745
|
next.status = "stopped";
|
|
46703
46746
|
next.stdinClosed = false;
|
|
46704
46747
|
next.pendingBgTasks = [];
|
|
@@ -46721,6 +46764,7 @@ function reduceSessionInner(state, input, deps) {
|
|
|
46721
46764
|
return {
|
|
46722
46765
|
state: next,
|
|
46723
46766
|
effects: [
|
|
46767
|
+
...isCloudTool(state.file.tool) && state.file.cloudGatewaySessionId && !next.file.cloudGatewaySessionId ? [{ kind: "persist-file", file: next.file }] : [],
|
|
46724
46768
|
...interruptEffects,
|
|
46725
46769
|
{
|
|
46726
46770
|
kind: "emit-frame",
|
|
@@ -46867,6 +46911,7 @@ function reduceSessionInner(state, input, deps) {
|
|
|
46867
46911
|
};
|
|
46868
46912
|
}
|
|
46869
46913
|
case "idle-kill-fired": {
|
|
46914
|
+
if (isCloudTool(state.file.tool)) return { state, effects: [] };
|
|
46870
46915
|
if (state.status !== "running-idle") {
|
|
46871
46916
|
return { state, effects: [] };
|
|
46872
46917
|
}
|
|
@@ -46939,6 +46984,7 @@ function reduceSessionInner(state, input, deps) {
|
|
|
46939
46984
|
// src/session/runner.ts
|
|
46940
46985
|
init_stdout_splitter();
|
|
46941
46986
|
init_permission_stdio();
|
|
46987
|
+
init_protocol();
|
|
46942
46988
|
init_claude_history();
|
|
46943
46989
|
|
|
46944
46990
|
// src/tools/spawn-error.ts
|
|
@@ -47116,6 +47162,7 @@ var SessionRunner = class {
|
|
|
47116
47162
|
this.state = initial;
|
|
47117
47163
|
}
|
|
47118
47164
|
hooks;
|
|
47165
|
+
recoveringCloud = false;
|
|
47119
47166
|
state;
|
|
47120
47167
|
proc = null;
|
|
47121
47168
|
// JSON-RPC 类 agent(codex app-server) 的 per-session 驱动器;非 null 时 runner 不用 spawn()/ChildProcess,
|
|
@@ -47189,6 +47236,17 @@ var SessionRunner = class {
|
|
|
47189
47236
|
for (const w3 of waiters) w3();
|
|
47190
47237
|
}
|
|
47191
47238
|
}
|
|
47239
|
+
recoverCloud() {
|
|
47240
|
+
if (this.state.procAlive) return;
|
|
47241
|
+
this.recoveringCloud = true;
|
|
47242
|
+
try {
|
|
47243
|
+
this.input({ kind: "command", command: { kind: "spawn-if-needed" } });
|
|
47244
|
+
const pending = this.state.file.cloudPendingCommand;
|
|
47245
|
+
if (pending) this.session?.startTurn(pending.text, pending.id, pending.prepared === true);
|
|
47246
|
+
} finally {
|
|
47247
|
+
this.recoveringCloud = false;
|
|
47248
|
+
}
|
|
47249
|
+
}
|
|
47192
47250
|
// 等子进程退出(procAlive=false)。manager.stop 在发完 SIGTERM 后调它确保
|
|
47193
47251
|
// 真停下来再 ack 给前端,从而避免"删 worktree 时 CC 还活着持有文件锁"的 race。
|
|
47194
47252
|
// 已经停止则立即 resolve;超时(默认 3000ms)抛错由上层透传成 RPC error
|
|
@@ -47239,6 +47297,15 @@ var SessionRunner = class {
|
|
|
47239
47297
|
}
|
|
47240
47298
|
await this.sendControlRequest("interrupt");
|
|
47241
47299
|
}
|
|
47300
|
+
/** Daemon shutdown releases only the local cloud subscription. */
|
|
47301
|
+
detachCloud() {
|
|
47302
|
+
this.session?.detach?.();
|
|
47303
|
+
}
|
|
47304
|
+
/** Explicit cancellation has been acknowledged; close the local runner state. */
|
|
47305
|
+
confirmCloudCancelled() {
|
|
47306
|
+
this.detachCloud();
|
|
47307
|
+
if (this.state.procAlive) this.input({ kind: "proc-exit", code: null });
|
|
47308
|
+
}
|
|
47242
47309
|
/**
|
|
47243
47310
|
* file-sharing tool_use ↔ tool_result 配对(spec §6 PR 3)。
|
|
47244
47311
|
*
|
|
@@ -47359,7 +47426,7 @@ var SessionRunner = class {
|
|
|
47359
47426
|
applyEffect(effect) {
|
|
47360
47427
|
switch (effect.kind) {
|
|
47361
47428
|
case "spawn":
|
|
47362
|
-
this.doSpawn(effect.ctx);
|
|
47429
|
+
this.doSpawn(this.recoveringCloud && effect.ctx.cloudGatewaySessionId ? { ...effect.ctx, cloudAttachOnly: true } : effect.ctx);
|
|
47363
47430
|
break;
|
|
47364
47431
|
case "kill":
|
|
47365
47432
|
if (this.session) {
|
|
@@ -47373,7 +47440,7 @@ var SessionRunner = class {
|
|
|
47373
47440
|
break;
|
|
47374
47441
|
case "write-stdin":
|
|
47375
47442
|
if (this.session) {
|
|
47376
|
-
this.session.startTurn(effect.payload);
|
|
47443
|
+
this.session.startTurn(effect.payload, this.state.file.cloudPendingCommand?.id);
|
|
47377
47444
|
break;
|
|
47378
47445
|
}
|
|
47379
47446
|
this.hooks.logger?.debug("[RG] write-stdin", {
|
|
@@ -47501,7 +47568,31 @@ var SessionRunner = class {
|
|
|
47501
47568
|
this.clearIdleKillTimers();
|
|
47502
47569
|
this.input({ kind: "proc-exit", code });
|
|
47503
47570
|
},
|
|
47504
|
-
onError: (message) => this.input({ kind: "proc-error", message })
|
|
47571
|
+
onError: (message) => this.input({ kind: "proc-error", message }),
|
|
47572
|
+
onHistoryGap: (synchronized) => this.hooks.broadcastFrame({
|
|
47573
|
+
type: "session:control",
|
|
47574
|
+
sessionId: this.state.file.sessionId,
|
|
47575
|
+
kind: CLOUD_HISTORY_REFRESH_KIND,
|
|
47576
|
+
synchronized
|
|
47577
|
+
}, "broadcast"),
|
|
47578
|
+
onRecoveryAbsent: () => {
|
|
47579
|
+
this.input({ kind: "cloud-recovery-absent" });
|
|
47580
|
+
this.hooks.broadcastFrame({ type: "session:control", sessionId: this.state.file.sessionId, kind: CLOUD_HISTORY_REFRESH_KIND, synchronized: true }, "broadcast");
|
|
47581
|
+
},
|
|
47582
|
+
onGatewayReady: (gatewaySessionId) => {
|
|
47583
|
+
if (this.state.file.cloudGatewaySessionId === gatewaySessionId) return;
|
|
47584
|
+
this.hooks.store.write({ ...this.state.file, cloudGatewaySessionId: gatewaySessionId });
|
|
47585
|
+
this.input({ kind: "cloud-gateway-ready", gatewaySessionId });
|
|
47586
|
+
},
|
|
47587
|
+
onCommandPrepared: (commandId, text, prepared) => {
|
|
47588
|
+
const pending = this.state.file.cloudPendingCommand;
|
|
47589
|
+
if (!pending || pending.id !== commandId || prepared && pending.text !== text) return false;
|
|
47590
|
+
if (!prepared) {
|
|
47591
|
+
this.hooks.store.write({ ...this.state.file, cloudPendingCommand: { id: commandId, text, prepared: true } });
|
|
47592
|
+
this.input({ kind: "cloud-command-prepared", commandId, text });
|
|
47593
|
+
}
|
|
47594
|
+
return true;
|
|
47595
|
+
}
|
|
47505
47596
|
});
|
|
47506
47597
|
return;
|
|
47507
47598
|
}
|
|
@@ -47695,6 +47786,10 @@ var SessionManager = class {
|
|
|
47695
47786
|
this.deps = deps;
|
|
47696
47787
|
}
|
|
47697
47788
|
deps;
|
|
47789
|
+
cloudCancel = null;
|
|
47790
|
+
setCloudCanceller(cancel) {
|
|
47791
|
+
this.cloudCancel = cancel;
|
|
47792
|
+
}
|
|
47698
47793
|
// sessionId → SessionRunner;在 send / ensureSession 时按需创建
|
|
47699
47794
|
runners = /* @__PURE__ */ new Map();
|
|
47700
47795
|
// 标题生成 in-flight 防重(进程内);跨重启防重靠 SessionFile.aiLabelGeneratedAt
|
|
@@ -48562,6 +48657,19 @@ var SessionManager = class {
|
|
|
48562
48657
|
]
|
|
48563
48658
|
};
|
|
48564
48659
|
}
|
|
48660
|
+
async deleteWithCloudCancel(args) {
|
|
48661
|
+
const file = this.findOwnedSession(args.sessionId);
|
|
48662
|
+
if (!file) throw new ClawdError(ERROR_CODES.SESSION_NOT_FOUND, args.sessionId);
|
|
48663
|
+
const runner = this.runners.get(args.sessionId) ?? null;
|
|
48664
|
+
if (isCloudTool(file.tool)) {
|
|
48665
|
+
if (!file.cloudGatewaySessionId) runner?.confirmCloudCancelled();
|
|
48666
|
+
else if (file.cloudPendingCommand || runner?.getState().procAlive) {
|
|
48667
|
+
if (!this.cloudCancel) throw new Error("cloud canceller is not configured");
|
|
48668
|
+
await this.cloudCancel(file, runner);
|
|
48669
|
+
}
|
|
48670
|
+
}
|
|
48671
|
+
return this.delete(args);
|
|
48672
|
+
}
|
|
48565
48673
|
send(args, senderPrincipal) {
|
|
48566
48674
|
const existing = this.getFile(args.sessionId);
|
|
48567
48675
|
let runner = this.runners.get(args.sessionId);
|
|
@@ -48725,8 +48833,19 @@ var SessionManager = class {
|
|
|
48725
48833
|
// 极端 OS 异常时才会用上。这样修掉了"前端 sessionStop 还没等 CC 退就去删 worktree
|
|
48726
48834
|
// 撞文件锁"的 race,同时也覆盖 CC streaming hang / 幽灵进程这类 SIGTERM 杀不动的 case
|
|
48727
48835
|
async stop(args) {
|
|
48836
|
+
const file = this.findOwnedSession(args.sessionId);
|
|
48728
48837
|
const runner = this.runners.get(args.sessionId);
|
|
48729
|
-
if (
|
|
48838
|
+
if (file && isCloudTool(file.tool)) {
|
|
48839
|
+
if (!file.cloudGatewaySessionId) runner?.confirmCloudCancelled();
|
|
48840
|
+
else if (file.cloudPendingCommand || runner?.getState().procAlive) {
|
|
48841
|
+
if (!this.cloudCancel) throw new Error("cloud canceller is not configured");
|
|
48842
|
+
await this.cloudCancel(file, runner ?? null);
|
|
48843
|
+
}
|
|
48844
|
+
}
|
|
48845
|
+
if (!runner) {
|
|
48846
|
+
if (file && isCloudTool(file.tool) && file.cloudPendingCommand) this.writeOwned({ ...file, cloudPendingCommand: void 0 });
|
|
48847
|
+
return { response: { ok: true }, broadcast: [] };
|
|
48848
|
+
}
|
|
48730
48849
|
this.clearPendingTurnEnd(args.sessionId);
|
|
48731
48850
|
const { broadcast } = this.withCollector(() => {
|
|
48732
48851
|
runner.input({ kind: "command", command: { kind: "stop" } });
|
|
@@ -48868,7 +48987,7 @@ var SessionManager = class {
|
|
|
48868
48987
|
}
|
|
48869
48988
|
return { response: normalized, broadcast };
|
|
48870
48989
|
}
|
|
48871
|
-
newSession(args) {
|
|
48990
|
+
newSession(args, nextCloudExecutionId) {
|
|
48872
48991
|
const existingFile = this.getFile(args.sessionId);
|
|
48873
48992
|
this.titleGenPending.get(args.sessionId)?.abort();
|
|
48874
48993
|
this.titleGenPending.delete(args.sessionId);
|
|
@@ -48879,7 +48998,7 @@ var SessionManager = class {
|
|
|
48879
48998
|
const { value, broadcast } = this.withCollector(() => {
|
|
48880
48999
|
runner.input({
|
|
48881
49000
|
kind: "command",
|
|
48882
|
-
command: { kind: "new", ...nextToolSessionId ? { nextToolSessionId } : {} }
|
|
49001
|
+
command: { kind: "new", ...nextToolSessionId ? { nextToolSessionId } : {}, ...nextCloudExecutionId ? { nextCloudExecutionId } : {} }
|
|
48883
49002
|
});
|
|
48884
49003
|
return runner.getState().file;
|
|
48885
49004
|
});
|
|
@@ -48888,6 +49007,8 @@ var SessionManager = class {
|
|
|
48888
49007
|
const existing = this.findOwnedSession(args.sessionId);
|
|
48889
49008
|
const {
|
|
48890
49009
|
toolSessionId: _drop,
|
|
49010
|
+
cloudPendingCommand: _cloudPendingCommand,
|
|
49011
|
+
cloudGatewaySessionId: _cloudGatewaySessionId,
|
|
48891
49012
|
contextUsage: _ctx,
|
|
48892
49013
|
contextWindowSize: _win,
|
|
48893
49014
|
gitBranch: _branch,
|
|
@@ -48897,6 +49018,8 @@ var SessionManager = class {
|
|
|
48897
49018
|
...rest
|
|
48898
49019
|
} = existing;
|
|
48899
49020
|
void _drop;
|
|
49021
|
+
void _cloudPendingCommand;
|
|
49022
|
+
void _cloudGatewaySessionId;
|
|
48900
49023
|
void _ctx;
|
|
48901
49024
|
void _win;
|
|
48902
49025
|
void _branch;
|
|
@@ -48905,11 +49028,25 @@ var SessionManager = class {
|
|
|
48905
49028
|
void _titleGeneratedAt;
|
|
48906
49029
|
const updated = {
|
|
48907
49030
|
...rest,
|
|
49031
|
+
...nextCloudExecutionId ? { cloudExecutionId: nextCloudExecutionId } : {},
|
|
48908
49032
|
...nextToolSessionId ? { toolSessionId: nextToolSessionId } : {},
|
|
48909
49033
|
updatedAt: nowIso2(this.deps)
|
|
48910
49034
|
};
|
|
48911
49035
|
return { response: this.writeOwned(updated), broadcast: [] };
|
|
48912
49036
|
}
|
|
49037
|
+
async newSessionWithCloudCancel(args) {
|
|
49038
|
+
const file = this.getFile(args.sessionId);
|
|
49039
|
+
if (isCloudTool(file.tool)) {
|
|
49040
|
+
const runner = this.runners.get(args.sessionId) ?? null;
|
|
49041
|
+
if (!file.cloudGatewaySessionId) runner?.confirmCloudCancelled();
|
|
49042
|
+
else if (file.cloudPendingCommand || runner?.getState().procAlive) {
|
|
49043
|
+
if (!this.cloudCancel) throw new Error("cloud canceller is not configured");
|
|
49044
|
+
await this.cloudCancel(file, runner);
|
|
49045
|
+
}
|
|
49046
|
+
return this.newSession(args, (0, import_node_crypto3.randomUUID)());
|
|
49047
|
+
}
|
|
49048
|
+
return this.newSession(args);
|
|
49049
|
+
}
|
|
48913
49050
|
resume(args) {
|
|
48914
49051
|
this.getFile(args.sessionId);
|
|
48915
49052
|
const runner = this.runners.get(args.sessionId);
|
|
@@ -48974,11 +49111,20 @@ var SessionManager = class {
|
|
|
48974
49111
|
}
|
|
48975
49112
|
return { runningSessions: running };
|
|
48976
49113
|
}
|
|
49114
|
+
/** Reattach only to executions whose last turn lacks a durable end marker. */
|
|
49115
|
+
recoverCloudSessions() {
|
|
49116
|
+
for (const file of this.listAllOwned()) {
|
|
49117
|
+
if (!isCloudTool(file.tool) || !file.cloudPendingCommand) continue;
|
|
49118
|
+
const runner = this.ensureSession(file);
|
|
49119
|
+
runner.recoverCloud();
|
|
49120
|
+
}
|
|
49121
|
+
}
|
|
48977
49122
|
stopAll() {
|
|
48978
49123
|
for (const controller of this.titleGenPending.values()) controller.abort();
|
|
48979
49124
|
this.titleGenPending.clear();
|
|
48980
49125
|
for (const r2 of this.runners.values()) {
|
|
48981
|
-
r2.
|
|
49126
|
+
if (isCloudTool(r2.getState().file.tool)) r2.detachCloud();
|
|
49127
|
+
else r2.input({ kind: "command", command: { kind: "stop" } });
|
|
48982
49128
|
}
|
|
48983
49129
|
this.pendingTurnDurationSignals.clear();
|
|
48984
49130
|
}
|
|
@@ -52752,9 +52898,9 @@ var CentralClientError = class extends Error {
|
|
|
52752
52898
|
cause;
|
|
52753
52899
|
status;
|
|
52754
52900
|
};
|
|
52755
|
-
async function centralRequest(opts,
|
|
52901
|
+
async function centralRequest(opts, path107, init) {
|
|
52756
52902
|
const f2 = opts.fetchImpl ?? globalThis.fetch;
|
|
52757
|
-
const url = `${opts.api.replace(/\/+$/, "")}${
|
|
52903
|
+
const url = `${opts.api.replace(/\/+$/, "")}${path107}`;
|
|
52758
52904
|
const ctrl = new AbortController();
|
|
52759
52905
|
const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
|
|
52760
52906
|
let res;
|
|
@@ -53790,8 +53936,8 @@ function turnStartInput(text, resolveImage) {
|
|
|
53790
53936
|
const items = [];
|
|
53791
53937
|
let leftover = text;
|
|
53792
53938
|
for (const m3 of text.matchAll(SKILL_RE)) {
|
|
53793
|
-
const [marker, name,
|
|
53794
|
-
items.push({ type: "skill", name, path:
|
|
53939
|
+
const [marker, name, path107] = m3;
|
|
53940
|
+
items.push({ type: "skill", name, path: path107 });
|
|
53795
53941
|
leftover = leftover.replace(marker, "");
|
|
53796
53942
|
}
|
|
53797
53943
|
for (const m3 of text.matchAll(ATTACHMENT_RE2)) {
|
|
@@ -61166,10 +61312,10 @@ function createGithubApi(args) {
|
|
|
61166
61312
|
const doFetch = args.fetch ?? fetch;
|
|
61167
61313
|
const seal = args.seal ?? sealWithSodium;
|
|
61168
61314
|
const timeoutMs = args.timeoutMs ?? TIMEOUT_MS;
|
|
61169
|
-
async function request(method,
|
|
61315
|
+
async function request(method, path107, body) {
|
|
61170
61316
|
let res;
|
|
61171
61317
|
try {
|
|
61172
|
-
res = await doFetch(`${API}${
|
|
61318
|
+
res = await doFetch(`${API}${path107}`, {
|
|
61173
61319
|
method,
|
|
61174
61320
|
headers: {
|
|
61175
61321
|
Authorization: `Bearer ${args.token}`,
|
|
@@ -61194,8 +61340,8 @@ function createGithubApi(args) {
|
|
|
61194
61340
|
}
|
|
61195
61341
|
return { status: res.status, json };
|
|
61196
61342
|
}
|
|
61197
|
-
async function must(method,
|
|
61198
|
-
const r2 = await request(method,
|
|
61343
|
+
async function must(method, path107, what, body) {
|
|
61344
|
+
const r2 = await request(method, path107, body);
|
|
61199
61345
|
if (r2.status < 200 || r2.status >= 300) throw new GithubApiError(r2.status, explain(r2.status, what, r2.json));
|
|
61200
61346
|
return r2.json;
|
|
61201
61347
|
}
|
|
@@ -61240,9 +61386,9 @@ function createGithubApi(args) {
|
|
|
61240
61386
|
return { env: x2.name, ...Number.isFinite(at3) ? { setAt: at3 } : {} };
|
|
61241
61387
|
});
|
|
61242
61388
|
},
|
|
61243
|
-
async getJson(
|
|
61389
|
+
async getJson(path107) {
|
|
61244
61390
|
try {
|
|
61245
|
-
const r2 = await request("GET",
|
|
61391
|
+
const r2 = await request("GET", path107);
|
|
61246
61392
|
return r2.status >= 200 && r2.status < 300 ? r2.json : void 0;
|
|
61247
61393
|
} catch {
|
|
61248
61394
|
return void 0;
|
|
@@ -62794,8 +62940,8 @@ function refreshPathFromLoginShell() {
|
|
|
62794
62940
|
timeout: 3e3,
|
|
62795
62941
|
stdio: ["ignore", "pipe", "ignore"]
|
|
62796
62942
|
});
|
|
62797
|
-
const
|
|
62798
|
-
if (
|
|
62943
|
+
const path107 = out.trim();
|
|
62944
|
+
if (path107) process.env.PATH = path107;
|
|
62799
62945
|
} catch {
|
|
62800
62946
|
}
|
|
62801
62947
|
}
|
|
@@ -63597,10 +63743,10 @@ function createCloudPersonaBotClient(opts) {
|
|
|
63597
63743
|
const f2 = opts.fetchImpl ?? fetch;
|
|
63598
63744
|
const base = opts.api.replace(/\/+$/, "");
|
|
63599
63745
|
const route = (personaId2) => `/api/lark-bot/cloud/${encodeURIComponent(personaId2)}`;
|
|
63600
|
-
async function request(method,
|
|
63746
|
+
async function request(method, path107, body) {
|
|
63601
63747
|
const pass = opts.getLoginPass();
|
|
63602
63748
|
if (!pass) throw new LarkBotCloudError("\u98DE\u4E66\u767B\u5F55\u540E\u624D\u80FD\u7BA1\u7406\u4E91 Persona \u7684 Bot", 401);
|
|
63603
|
-
const response = await f2(base +
|
|
63749
|
+
const response = await f2(base + path107, {
|
|
63604
63750
|
method,
|
|
63605
63751
|
headers: { authorization: `Bearer ${pass}`, "content-type": "application/json" },
|
|
63606
63752
|
...body ? { body: JSON.stringify(body) } : {},
|
|
@@ -63609,7 +63755,7 @@ function createCloudPersonaBotClient(opts) {
|
|
|
63609
63755
|
const json = await response.json().catch(() => ({}));
|
|
63610
63756
|
if (!response.ok) {
|
|
63611
63757
|
const detail = typeof json.message === "string" ? json.message : `HTTP ${response.status}`;
|
|
63612
|
-
throw new LarkBotCloudError(`cloud bot ${method} ${
|
|
63758
|
+
throw new LarkBotCloudError(`cloud bot ${method} ${path107}: ${detail}`, response.status);
|
|
63613
63759
|
}
|
|
63614
63760
|
return json;
|
|
63615
63761
|
}
|
|
@@ -64603,6 +64749,7 @@ var GATEWAY_ROUTES = {
|
|
|
64603
64749
|
sessionSend: (personaId2, sessionId) => `/p/${encodeURIComponent(personaId2)}/session/${encodeURIComponent(sessionId)}`,
|
|
64604
64750
|
sessionMirror: (personaId2, sessionId) => `/p/${encodeURIComponent(personaId2)}/session/${encodeURIComponent(sessionId)}/mirror`,
|
|
64605
64751
|
eventSession: (personaId2) => `/p/${encodeURIComponent(personaId2)}/session/events`,
|
|
64752
|
+
eventCancel: (personaId2) => `/p/${encodeURIComponent(personaId2)}/session/events:cancel`,
|
|
64606
64753
|
eventSend: (personaId2, sessionId) => `/p/${encodeURIComponent(personaId2)}/session/events/${encodeURIComponent(sessionId)}`,
|
|
64607
64754
|
// 调用方自己那块盘的用量(design 2026-09-19-cloud-volume-usage §3.3):同样按人、不挂 persona
|
|
64608
64755
|
volume: () => "/me/volume",
|
|
@@ -64726,20 +64873,42 @@ var CloudGatewayClient = class {
|
|
|
64726
64873
|
}
|
|
64727
64874
|
async openEventSession(personaId2, opts) {
|
|
64728
64875
|
const { apiKey, gatewayUrl } = await this.credentials();
|
|
64876
|
+
const health = await this.fetchImpl(gatewayUrl + GATEWAY_ROUTES.healthz());
|
|
64877
|
+
if (!health.ok || (await health.json()).sessionProtocolVersion !== 2) throw new Error("\u4E91 gateway \u7684\u4F1A\u8BDD\u534F\u8BAE\u7248\u672C\u4E0D\u5339\u914D\uFF0C\u8BF7\u5148\u5347\u7EA7 gateway");
|
|
64729
64878
|
return openHttpEventSession({
|
|
64730
64879
|
fetchImpl: this.fetchImpl,
|
|
64731
64880
|
gatewayUrl,
|
|
64732
64881
|
apiKey,
|
|
64733
64882
|
personaId: personaId2,
|
|
64883
|
+
clientSessionId: opts.clientSessionId,
|
|
64884
|
+
gatewaySessionId: opts.gatewaySessionId,
|
|
64734
64885
|
engineSessionId: opts.toolSessionId,
|
|
64735
64886
|
instructions: opts.instructions,
|
|
64736
64887
|
purpose: opts.purpose,
|
|
64737
64888
|
expectedEngine: opts.expectedEngine,
|
|
64738
64889
|
effort: opts.effort,
|
|
64739
64890
|
personaMode: opts.personaMode,
|
|
64891
|
+
attachOnly: opts.attachOnly,
|
|
64740
64892
|
logger: this.deps.logger
|
|
64741
64893
|
});
|
|
64742
64894
|
}
|
|
64895
|
+
async cancelEventSession(personaId2, clientSessionId, gatewaySessionId) {
|
|
64896
|
+
const { apiKey, gatewayUrl } = await this.credentials();
|
|
64897
|
+
const res = await this.fetchImpl(gatewayUrl + GATEWAY_ROUTES.eventCancel(personaId2), {
|
|
64898
|
+
method: "POST",
|
|
64899
|
+
headers: { authorization: `Bearer ${apiKey}`, "content-type": "application/json" },
|
|
64900
|
+
body: JSON.stringify({ protocolVersion: 2, clientSessionId, gatewaySessionId })
|
|
64901
|
+
});
|
|
64902
|
+
if (!res.ok) {
|
|
64903
|
+
let message = `gateway \u56DE ${res.status}`;
|
|
64904
|
+
try {
|
|
64905
|
+
const body = await res.json();
|
|
64906
|
+
if (typeof body.message === "string") message = body.message;
|
|
64907
|
+
} catch {
|
|
64908
|
+
}
|
|
64909
|
+
throw new Error(message);
|
|
64910
|
+
}
|
|
64911
|
+
}
|
|
64743
64912
|
/**
|
|
64744
64913
|
* 看板数据(design 2026-09-23-cloud-persona-metrics §3.8):GET /metrics/<persona>?window&entry,**原样回**状态码与 body——
|
|
64745
64914
|
* 形状真源在 gateway 的 cloud-persona-metrics,daemon 只是替浏览器拿本机 api key 转一跳。拿不到 key / 连不上 / 超时 → 抛(路由折成 502)。
|
|
@@ -64796,9 +64965,9 @@ var CloudGatewayClient = class {
|
|
|
64796
64965
|
}
|
|
64797
64966
|
};
|
|
64798
64967
|
function openHttpEventSession(opts) {
|
|
64799
|
-
const { fetchImpl, gatewayUrl, apiKey, personaId: personaId2, engineSessionId, instructions, purpose, effort, personaMode, expectedEngine, logger } = opts;
|
|
64968
|
+
const { fetchImpl, gatewayUrl, apiKey, personaId: personaId2, clientSessionId, gatewaySessionId, engineSessionId, instructions, purpose, effort, personaMode, attachOnly, expectedEngine, logger } = opts;
|
|
64800
64969
|
const headers = { authorization: `Bearer ${apiKey}`, "content-type": "application/json" };
|
|
64801
|
-
|
|
64970
|
+
let abort = new AbortController();
|
|
64802
64971
|
const eventCbs = [];
|
|
64803
64972
|
const controlCbs = [];
|
|
64804
64973
|
const closeCbs = [];
|
|
@@ -64807,7 +64976,11 @@ function openHttpEventSession(opts) {
|
|
|
64807
64976
|
let closed = false;
|
|
64808
64977
|
let readyControl = null;
|
|
64809
64978
|
let errorControl = null;
|
|
64810
|
-
let sessionId = null;
|
|
64979
|
+
let sessionId = gatewaySessionId ?? null;
|
|
64980
|
+
let lastSeq = 0;
|
|
64981
|
+
let everReady = false;
|
|
64982
|
+
let connected = false;
|
|
64983
|
+
const attachWaiters = [];
|
|
64811
64984
|
let resolveReady;
|
|
64812
64985
|
let rejectReady;
|
|
64813
64986
|
const ready = new Promise((resolve9, reject) => {
|
|
@@ -64829,87 +65002,146 @@ function openHttpEventSession(opts) {
|
|
|
64829
65002
|
closed = true;
|
|
64830
65003
|
rejectReady(new Error(message ?? "event session closed"));
|
|
64831
65004
|
abort.abort();
|
|
65005
|
+
for (const resolve9 of attachWaiters.splice(0)) resolve9();
|
|
64832
65006
|
for (const cb of closeCbs) cb();
|
|
64833
65007
|
};
|
|
65008
|
+
const waitForAttach = () => connected ? Promise.resolve() : new Promise((resolve9) => {
|
|
65009
|
+
attachWaiters.push(resolve9);
|
|
65010
|
+
});
|
|
65011
|
+
const retryWait = () => new Promise((resolve9) => {
|
|
65012
|
+
const timer = setTimeout(resolve9, 250);
|
|
65013
|
+
timer.unref?.();
|
|
65014
|
+
abort.signal.addEventListener("abort", () => {
|
|
65015
|
+
clearTimeout(timer);
|
|
65016
|
+
resolve9();
|
|
65017
|
+
}, { once: true });
|
|
65018
|
+
});
|
|
64834
65019
|
void (async () => {
|
|
64835
|
-
|
|
64836
|
-
|
|
64837
|
-
|
|
64838
|
-
|
|
64839
|
-
|
|
64840
|
-
|
|
64841
|
-
|
|
64842
|
-
|
|
64843
|
-
|
|
64844
|
-
|
|
64845
|
-
|
|
64846
|
-
|
|
64847
|
-
|
|
64848
|
-
|
|
64849
|
-
|
|
64850
|
-
|
|
64851
|
-
|
|
64852
|
-
|
|
64853
|
-
|
|
64854
|
-
const decoder = new TextDecoder();
|
|
64855
|
-
let pending = "";
|
|
64856
|
-
for (; ; ) {
|
|
64857
|
-
const { value, done } = await reader.read();
|
|
64858
|
-
if (done) break;
|
|
64859
|
-
pending += decoder.decode(value, { stream: true });
|
|
64860
|
-
const lines = pending.split("\n");
|
|
64861
|
-
pending = lines.pop() ?? "";
|
|
64862
|
-
for (const line of lines) {
|
|
64863
|
-
if (!line.trim()) continue;
|
|
64864
|
-
const data = JSON.parse(line);
|
|
64865
|
-
if (data.clawd === "events") {
|
|
64866
|
-
const events = ParsedEventSchema.array().parse(data.events);
|
|
64867
|
-
if (!eventCbs.length) earlyEvents.push(events);
|
|
64868
|
-
for (const cb of eventCbs) cb(events);
|
|
64869
|
-
continue;
|
|
65020
|
+
while (!closed) {
|
|
65021
|
+
abort = new AbortController();
|
|
65022
|
+
let fatal = false;
|
|
65023
|
+
try {
|
|
65024
|
+
const res = await fetchImpl(gatewayUrl + GATEWAY_ROUTES.eventSession(personaId2), {
|
|
65025
|
+
method: "POST",
|
|
65026
|
+
headers,
|
|
65027
|
+
body: JSON.stringify({ protocolVersion: 2, clientSessionId, afterSeq: lastSeq, ...sessionId ? { gatewaySessionId: sessionId } : {}, expectedEngine, ...engineSessionId ? { engineSessionId } : {}, ...instructions ? { instructions } : {}, ...purpose ? { purpose } : {}, ...effort ? { effort } : {}, ...personaMode ? { personaMode } : {}, ...attachOnly ? { attachOnly: true } : {} }),
|
|
65028
|
+
signal: abort.signal
|
|
65029
|
+
});
|
|
65030
|
+
if (!res.ok || !res.body) {
|
|
65031
|
+
let message = `gateway \u56DE ${res.status}`;
|
|
65032
|
+
let code;
|
|
65033
|
+
try {
|
|
65034
|
+
const body = await res.json();
|
|
65035
|
+
if (typeof body.message === "string") message = body.message;
|
|
65036
|
+
code = body.error;
|
|
65037
|
+
if (body.error === "SESSION_VERSION_EXPIRED" && !message.includes("SESSION_VERSION_EXPIRED")) message = `SESSION_VERSION_EXPIRED: ${message}`;
|
|
65038
|
+
} catch {
|
|
64870
65039
|
}
|
|
64871
|
-
|
|
64872
|
-
|
|
64873
|
-
|
|
64874
|
-
|
|
64875
|
-
|
|
64876
|
-
|
|
65040
|
+
if ((attachOnly || sessionId) && res.status === 404 && code === "SESSION_NOT_FOUND") {
|
|
65041
|
+
emitControl({ kind: "closed", reason: "not-found" });
|
|
65042
|
+
finish();
|
|
65043
|
+
return;
|
|
65044
|
+
}
|
|
65045
|
+
if (res.status === 426 || res.status === 400 || res.status === 401 || res.status === 403 || res.status === 409 || res.status === 410 || code === "CLIENT_UPGRADE_REQUIRED") {
|
|
65046
|
+
fatal = true;
|
|
65047
|
+
finish(message);
|
|
65048
|
+
return;
|
|
65049
|
+
}
|
|
65050
|
+
throw new Error(message);
|
|
65051
|
+
}
|
|
65052
|
+
connected = true;
|
|
65053
|
+
for (const resolve9 of attachWaiters.splice(0)) resolve9();
|
|
65054
|
+
const reader = res.body.getReader();
|
|
65055
|
+
const decoder = new TextDecoder();
|
|
65056
|
+
let pending = "";
|
|
65057
|
+
for (; ; ) {
|
|
65058
|
+
const { value, done } = await reader.read();
|
|
65059
|
+
if (done) break;
|
|
65060
|
+
pending += decoder.decode(value, { stream: true });
|
|
65061
|
+
const lines = pending.split("\n");
|
|
65062
|
+
pending = lines.pop() ?? "";
|
|
65063
|
+
for (const line of lines) {
|
|
65064
|
+
if (!line.trim()) continue;
|
|
65065
|
+
const data = JSON.parse(line);
|
|
65066
|
+
if (data.clawd === "events") {
|
|
65067
|
+
if (typeof data.seq === "number") {
|
|
65068
|
+
if (data.seq <= lastSeq) continue;
|
|
65069
|
+
lastSeq = data.seq;
|
|
65070
|
+
}
|
|
65071
|
+
const events = ParsedEventSchema.array().parse(data.events);
|
|
65072
|
+
if (!eventCbs.length) earlyEvents.push(events);
|
|
65073
|
+
for (const cb of eventCbs) cb(events);
|
|
65074
|
+
continue;
|
|
65075
|
+
}
|
|
65076
|
+
const control = parseControlLine(line);
|
|
65077
|
+
if (!control) throw new Error("gateway event stream contains an unknown line");
|
|
65078
|
+
if (control.kind === "ready") {
|
|
65079
|
+
if (!control.session) throw new Error("gateway ready line has no session id");
|
|
65080
|
+
if (control.engine !== expectedEngine) {
|
|
65081
|
+
finish(control.engine ? `SESSION_VERSION_EXPIRED: \u5F53\u524D Pod \u662F ${control.engine}\uFF0C\u8FD9\u6761\u4F1A\u8BDD\u9700\u8981 ${expectedEngine}` : "gateway \u7684 ready \u63A7\u5236\u884C\u6CA1\u5E26 engine\uFF0Cgateway \u592A\u8001\uFF0C\u5148\u5347 gateway");
|
|
65082
|
+
return;
|
|
65083
|
+
}
|
|
65084
|
+
sessionId = control.session;
|
|
65085
|
+
everReady = true;
|
|
65086
|
+
resolveReady();
|
|
65087
|
+
}
|
|
65088
|
+
emitControl(control);
|
|
65089
|
+
if (control.kind === "error") {
|
|
65090
|
+
finish();
|
|
65091
|
+
return;
|
|
65092
|
+
}
|
|
65093
|
+
if (control.kind === "closed") {
|
|
65094
|
+
finish();
|
|
64877
65095
|
return;
|
|
64878
65096
|
}
|
|
64879
|
-
sessionId = control.session;
|
|
64880
|
-
resolveReady();
|
|
64881
65097
|
}
|
|
64882
|
-
|
|
64883
|
-
|
|
64884
|
-
|
|
65098
|
+
}
|
|
65099
|
+
connected = false;
|
|
65100
|
+
} catch (e) {
|
|
65101
|
+
if (!closed) {
|
|
65102
|
+
if (e instanceof SyntaxError || e.name === "ZodError") {
|
|
65103
|
+
finish("gateway event stream contains invalid data");
|
|
64885
65104
|
return;
|
|
64886
65105
|
}
|
|
65106
|
+
connected = false;
|
|
65107
|
+
logger?.warn("cloud event stream failed; reconnecting", { code: e.code, name: e.name, ready: everReady });
|
|
64887
65108
|
}
|
|
64888
65109
|
}
|
|
64889
|
-
|
|
64890
|
-
} catch (e) {
|
|
64891
|
-
if (!closed) {
|
|
64892
|
-
logger?.warn("cloud event stream failed", { message: e.message });
|
|
64893
|
-
finish(`\u4E91\u4E0A\u4E8B\u4EF6\u901A\u9053\u51FA\u9519\uFF1A${e.message}`);
|
|
64894
|
-
}
|
|
65110
|
+
if (!closed && !fatal) await retryWait();
|
|
64895
65111
|
}
|
|
64896
65112
|
})();
|
|
64897
65113
|
return {
|
|
64898
65114
|
send(command) {
|
|
64899
65115
|
const next = sendChain.then(async () => {
|
|
64900
65116
|
await ready;
|
|
64901
|
-
|
|
64902
|
-
|
|
64903
|
-
|
|
65117
|
+
while (!closed) {
|
|
65118
|
+
await waitForAttach();
|
|
65119
|
+
if (!sessionId) continue;
|
|
65120
|
+
let res;
|
|
65121
|
+
try {
|
|
65122
|
+
res = await fetchImpl(gatewayUrl + GATEWAY_ROUTES.eventSend(personaId2, sessionId), { method: "POST", headers, body: JSON.stringify(command) });
|
|
65123
|
+
} catch {
|
|
65124
|
+
connected = false;
|
|
65125
|
+
abort.abort();
|
|
65126
|
+
await retryWait();
|
|
65127
|
+
continue;
|
|
65128
|
+
}
|
|
65129
|
+
if (res.ok) return;
|
|
65130
|
+
if (res.status === 404 || res.status >= 500) {
|
|
65131
|
+
connected = false;
|
|
65132
|
+
abort.abort();
|
|
65133
|
+
await retryWait();
|
|
65134
|
+
continue;
|
|
65135
|
+
}
|
|
64904
65136
|
let message = `gateway \u56DE ${res.status}`;
|
|
64905
65137
|
try {
|
|
64906
65138
|
const body = await res.json();
|
|
64907
65139
|
if (typeof body.message === "string") message = body.message;
|
|
64908
65140
|
} catch {
|
|
64909
65141
|
}
|
|
64910
|
-
finish(message);
|
|
64911
65142
|
throw new Error(message);
|
|
64912
65143
|
}
|
|
65144
|
+
throw new Error("event session closed");
|
|
64913
65145
|
});
|
|
64914
65146
|
sendChain = next.catch(() => {
|
|
64915
65147
|
});
|
|
@@ -64957,10 +65189,17 @@ function parseControlLine(line) {
|
|
|
64957
65189
|
personaDir: typeof r2.personaDir === "string" ? r2.personaDir : "",
|
|
64958
65190
|
workDir: typeof r2.workDir === "string" ? r2.workDir : "",
|
|
64959
65191
|
...typeof r2.model === "string" ? { model: r2.model } : {},
|
|
64960
|
-
...typeof r2.engine === "string" ? { engine: r2.engine } : {}
|
|
65192
|
+
...typeof r2.engine === "string" ? { engine: r2.engine } : {},
|
|
65193
|
+
...typeof r2.replayGap === "boolean" ? { replayGap: r2.replayGap } : {},
|
|
65194
|
+
...typeof r2.historySynchronized === "boolean" ? { historySynchronized: r2.historySynchronized } : {},
|
|
65195
|
+
...typeof r2.activeTurn === "boolean" ? { activeTurn: r2.activeTurn } : {}
|
|
64961
65196
|
};
|
|
64962
65197
|
case "error":
|
|
64963
65198
|
return { kind: "error", message: typeof r2.message === "string" ? r2.message : "gateway error" };
|
|
65199
|
+
case "closed":
|
|
65200
|
+
return { kind: "closed", reason: typeof r2.reason === "string" ? r2.reason : "unknown" };
|
|
65201
|
+
case "history":
|
|
65202
|
+
return { kind: "history", synchronized: r2.synchronized === true };
|
|
64964
65203
|
default:
|
|
64965
65204
|
return { kind: "ping" };
|
|
64966
65205
|
}
|
|
@@ -65153,11 +65392,97 @@ function openHttpLineStream(opts) {
|
|
|
65153
65392
|
};
|
|
65154
65393
|
}
|
|
65155
65394
|
|
|
65395
|
+
// src/cloud/cancel-outbox.ts
|
|
65396
|
+
var import_node_fs39 = __toESM(require("fs"), 1);
|
|
65397
|
+
var import_node_path44 = __toESM(require("path"), 1);
|
|
65398
|
+
var CloudCancelOutbox = class {
|
|
65399
|
+
constructor(dir, send2, logger) {
|
|
65400
|
+
this.dir = dir;
|
|
65401
|
+
this.send = send2;
|
|
65402
|
+
this.logger = logger;
|
|
65403
|
+
}
|
|
65404
|
+
dir;
|
|
65405
|
+
send;
|
|
65406
|
+
logger;
|
|
65407
|
+
timer = null;
|
|
65408
|
+
inFlight = /* @__PURE__ */ new Set();
|
|
65409
|
+
record(clientSessionId, personaId2, gatewaySessionId) {
|
|
65410
|
+
if (!clientSessionId || !personaId2 || !gatewaySessionId) throw new Error("cloud cancel requires client, gateway and persona IDs");
|
|
65411
|
+
import_node_fs39.default.mkdirSync(this.dir, { recursive: true, mode: 448 });
|
|
65412
|
+
const target = this.pathFor(clientSessionId);
|
|
65413
|
+
const temporary = `${target}.tmp-${process.pid}-${Date.now()}`;
|
|
65414
|
+
import_node_fs39.default.writeFileSync(temporary, JSON.stringify({ clientSessionId, personaId: personaId2, gatewaySessionId }), { mode: 384 });
|
|
65415
|
+
import_node_fs39.default.renameSync(temporary, target);
|
|
65416
|
+
this.inFlight.add(clientSessionId);
|
|
65417
|
+
}
|
|
65418
|
+
confirm(clientSessionId) {
|
|
65419
|
+
import_node_fs39.default.rmSync(this.pathFor(clientSessionId), { force: true });
|
|
65420
|
+
this.inFlight.delete(clientSessionId);
|
|
65421
|
+
}
|
|
65422
|
+
release(clientSessionId) {
|
|
65423
|
+
this.inFlight.delete(clientSessionId);
|
|
65424
|
+
}
|
|
65425
|
+
async request(clientSessionId, personaId2, gatewaySessionId) {
|
|
65426
|
+
this.record(clientSessionId, personaId2, gatewaySessionId);
|
|
65427
|
+
try {
|
|
65428
|
+
await this.send(personaId2, clientSessionId, gatewaySessionId);
|
|
65429
|
+
this.confirm(clientSessionId);
|
|
65430
|
+
} catch (e) {
|
|
65431
|
+
this.release(clientSessionId);
|
|
65432
|
+
throw e;
|
|
65433
|
+
}
|
|
65434
|
+
}
|
|
65435
|
+
async flush() {
|
|
65436
|
+
let names;
|
|
65437
|
+
try {
|
|
65438
|
+
names = import_node_fs39.default.readdirSync(this.dir).filter((name) => name.endsWith(".json"));
|
|
65439
|
+
} catch (e) {
|
|
65440
|
+
if (e.code === "ENOENT") return;
|
|
65441
|
+
throw e;
|
|
65442
|
+
}
|
|
65443
|
+
for (const name of names) {
|
|
65444
|
+
const target = import_node_path44.default.join(this.dir, name);
|
|
65445
|
+
let pending;
|
|
65446
|
+
try {
|
|
65447
|
+
pending = JSON.parse(import_node_fs39.default.readFileSync(target, "utf8"));
|
|
65448
|
+
} catch {
|
|
65449
|
+
continue;
|
|
65450
|
+
}
|
|
65451
|
+
if (!pending.clientSessionId || !pending.personaId || !pending.gatewaySessionId || this.pathFor(pending.clientSessionId) !== target) continue;
|
|
65452
|
+
if (this.inFlight.has(pending.clientSessionId)) continue;
|
|
65453
|
+
this.inFlight.add(pending.clientSessionId);
|
|
65454
|
+
try {
|
|
65455
|
+
await this.send(pending.personaId, pending.clientSessionId, pending.gatewaySessionId);
|
|
65456
|
+
import_node_fs39.default.rmSync(target, { force: true });
|
|
65457
|
+
} catch (e) {
|
|
65458
|
+
this.logger?.warn("cloud cancel pending", { sessionId: pending.clientSessionId, error: e.message });
|
|
65459
|
+
} finally {
|
|
65460
|
+
this.inFlight.delete(pending.clientSessionId);
|
|
65461
|
+
}
|
|
65462
|
+
}
|
|
65463
|
+
}
|
|
65464
|
+
start() {
|
|
65465
|
+
if (this.timer) return;
|
|
65466
|
+
const retry = () => void this.flush().catch((e) => this.logger?.warn("cloud cancel outbox flush failed", { error: e.message }));
|
|
65467
|
+
retry();
|
|
65468
|
+
this.timer = setInterval(retry, 3e4);
|
|
65469
|
+
this.timer.unref?.();
|
|
65470
|
+
}
|
|
65471
|
+
stop() {
|
|
65472
|
+
if (this.timer) clearInterval(this.timer);
|
|
65473
|
+
this.timer = null;
|
|
65474
|
+
}
|
|
65475
|
+
pathFor(clientSessionId) {
|
|
65476
|
+
return import_node_path44.default.join(this.dir, `${safeFileName(clientSessionId)}.json`);
|
|
65477
|
+
}
|
|
65478
|
+
};
|
|
65479
|
+
|
|
65156
65480
|
// src/tools/codex-cloud.ts
|
|
65157
65481
|
init_protocol();
|
|
65158
65482
|
|
|
65159
65483
|
// src/tools/codex-cloud-session.ts
|
|
65160
|
-
var
|
|
65484
|
+
var import_node_fs40 = __toESM(require("fs"), 1);
|
|
65485
|
+
var import_node_crypto13 = require("crypto");
|
|
65161
65486
|
|
|
65162
65487
|
// src/tools/cloud-portable-input.ts
|
|
65163
65488
|
async function portableCloudInput(text, resolvers) {
|
|
@@ -65186,7 +65511,7 @@ function cloudImageInput(deps) {
|
|
|
65186
65511
|
const mime = lookupMime(p3);
|
|
65187
65512
|
if (!mime.startsWith("image/")) return null;
|
|
65188
65513
|
try {
|
|
65189
|
-
const bytes = (deps.readFile ??
|
|
65514
|
+
const bytes = (deps.readFile ?? import_node_fs40.default.readFileSync)(p3);
|
|
65190
65515
|
return { type: "image", url: `data:${mime};base64,${bytes.toString("base64")}` };
|
|
65191
65516
|
} catch (e) {
|
|
65192
65517
|
deps.logger?.warn("cloud image attachment unreadable", { path: p3, message: e.message });
|
|
@@ -65196,18 +65521,22 @@ function cloudImageInput(deps) {
|
|
|
65196
65521
|
}
|
|
65197
65522
|
function createCloudCodexSession(ctx, sink, deps) {
|
|
65198
65523
|
const personaId2 = personaIdFromCloudCwd(ctx.cwd);
|
|
65524
|
+
const clientSessionId = ctx.titleOnly ? (0, import_node_crypto13.randomUUID)() : ctx.cloudExecutionId ?? ctx.env?.CLAWD_SESSION_ID;
|
|
65199
65525
|
let channel = null;
|
|
65200
65526
|
let closed = false;
|
|
65527
|
+
let detached = false;
|
|
65528
|
+
let stopping = null;
|
|
65201
65529
|
let exited = false;
|
|
65530
|
+
let ready = false;
|
|
65202
65531
|
const exit = () => {
|
|
65203
65532
|
if (!exited) {
|
|
65204
65533
|
exited = true;
|
|
65205
65534
|
sink.onExit(null);
|
|
65206
65535
|
}
|
|
65207
65536
|
};
|
|
65208
|
-
if (!personaId2) {
|
|
65537
|
+
if (!personaId2 || !clientSessionId) {
|
|
65209
65538
|
queueMicrotask(() => {
|
|
65210
|
-
sink.onError(`cloud session
|
|
65539
|
+
sink.onError(`cloud session is missing ${personaId2 ? "CLAWD_SESSION_ID" : "persona id"}`);
|
|
65211
65540
|
exit();
|
|
65212
65541
|
});
|
|
65213
65542
|
return { startTurn() {
|
|
@@ -65218,23 +65547,36 @@ function createCloudCodexSession(ctx, sink, deps) {
|
|
|
65218
65547
|
}
|
|
65219
65548
|
const opened = deps.client.openEventSession(personaId2, {
|
|
65220
65549
|
expectedEngine: "codex",
|
|
65550
|
+
clientSessionId,
|
|
65551
|
+
...ctx.cloudGatewaySessionId ? { gatewaySessionId: ctx.cloudGatewaySessionId } : {},
|
|
65221
65552
|
...ctx.toolSessionId ? { toolSessionId: ctx.toolSessionId } : {},
|
|
65222
65553
|
...ctx.extraSystemPrompt ? { instructions: ctx.extraSystemPrompt } : {},
|
|
65223
65554
|
...ctx.effort ? { effort: ctx.effort } : {},
|
|
65224
65555
|
...ctx.personaMode ? { personaMode: ctx.personaMode } : {},
|
|
65225
|
-
...ctx.titleOnly ? { purpose: "title" } : {}
|
|
65556
|
+
...ctx.titleOnly ? { purpose: "title" } : {},
|
|
65557
|
+
...ctx.cloudAttachOnly ? { attachOnly: true } : {}
|
|
65226
65558
|
}).then(
|
|
65227
65559
|
(opened2) => {
|
|
65228
65560
|
channel = opened2;
|
|
65229
65561
|
channel.onEvents((events) => sink.pushEvents(events));
|
|
65230
65562
|
channel.onControl((c2) => {
|
|
65231
|
-
if (c2.kind === "
|
|
65563
|
+
if (c2.kind === "ready") {
|
|
65564
|
+
ready = true;
|
|
65565
|
+
sink.onGatewayReady?.(c2.session);
|
|
65566
|
+
if (c2.replayGap || c2.historySynchronized === false) sink.onHistoryGap?.(c2.historySynchronized === true);
|
|
65567
|
+
} else if (c2.kind === "queued") {
|
|
65232
65568
|
sink.pushEvents([{ kind: "meta-text", text: `\u4E91\u4E0A\u673A\u5668\u6709 ${c2.running} \u4E2A\u4EFB\u52A1\u5728\u8DD1\uFF0C\u7B49\u4E00\u4E2A\u7ED3\u675F\u5C31\u8F6E\u5230\u4F60` }]);
|
|
65569
|
+
} else if (c2.kind === "history") {
|
|
65570
|
+
sink.onHistoryGap?.(c2.synchronized);
|
|
65233
65571
|
} else if (c2.kind === "error") {
|
|
65234
|
-
sink.onError(
|
|
65572
|
+
sink.onError(`${ready ? "\u4E91\u4E0A\u6267\u884C\u5931\u8D25" : "\u4E91\u4E0A persona \u8D77\u4E0D\u6765"}\uFF1A${c2.message}`);
|
|
65573
|
+
} else if (c2.kind === "closed" && c2.reason === "not-found") {
|
|
65574
|
+
sink.onRecoveryAbsent?.();
|
|
65235
65575
|
}
|
|
65236
65576
|
});
|
|
65237
|
-
channel.onClose(
|
|
65577
|
+
channel.onClose(() => {
|
|
65578
|
+
if (!detached) exit();
|
|
65579
|
+
});
|
|
65238
65580
|
if (closed) channel.close();
|
|
65239
65581
|
return channel;
|
|
65240
65582
|
},
|
|
@@ -65253,12 +65595,13 @@ function createCloudCodexSession(ctx, sink, deps) {
|
|
|
65253
65595
|
});
|
|
65254
65596
|
};
|
|
65255
65597
|
return {
|
|
65256
|
-
startTurn(text) {
|
|
65598
|
+
startTurn(text, commandId = (0, import_node_crypto13.randomUUID)(), prepared = false) {
|
|
65257
65599
|
send2(async () => {
|
|
65258
65600
|
const ch = await opened;
|
|
65259
65601
|
if (closed) return;
|
|
65260
|
-
const portable = await portableCloudInput(text, { resolveCodexImage: cloudImageInput(deps) });
|
|
65261
|
-
|
|
65602
|
+
const portable = prepared ? text : await portableCloudInput(text, { resolveCodexImage: cloudImageInput(deps) });
|
|
65603
|
+
if (sink.onCommandPrepared?.(commandId, portable, prepared) === false) return;
|
|
65604
|
+
await ch.send({ command: "turn", text: portable, commandId });
|
|
65262
65605
|
});
|
|
65263
65606
|
},
|
|
65264
65607
|
respondPermission(requestId, allow) {
|
|
@@ -65267,11 +65610,23 @@ function createCloudCodexSession(ctx, sink, deps) {
|
|
|
65267
65610
|
interrupt() {
|
|
65268
65611
|
send2(async () => (await opened).send({ command: "interrupt" }));
|
|
65269
65612
|
},
|
|
65270
|
-
|
|
65613
|
+
detach() {
|
|
65614
|
+
detached = true;
|
|
65271
65615
|
closed = true;
|
|
65272
|
-
|
|
65273
|
-
|
|
65274
|
-
|
|
65616
|
+
channel?.close();
|
|
65617
|
+
},
|
|
65618
|
+
stop() {
|
|
65619
|
+
if (stopping) return stopping;
|
|
65620
|
+
closed = true;
|
|
65621
|
+
stopping = (async () => {
|
|
65622
|
+
const ch = await opened.catch(() => null);
|
|
65623
|
+
if (ch) {
|
|
65624
|
+
await ch.send({ command: "cancel" });
|
|
65625
|
+
ch.close();
|
|
65626
|
+
}
|
|
65627
|
+
exit();
|
|
65628
|
+
})();
|
|
65629
|
+
return stopping;
|
|
65275
65630
|
}
|
|
65276
65631
|
};
|
|
65277
65632
|
}
|
|
@@ -65344,7 +65699,7 @@ init_protocol();
|
|
|
65344
65699
|
|
|
65345
65700
|
// src/tools/pi.ts
|
|
65346
65701
|
var import_node_child_process12 = require("child_process");
|
|
65347
|
-
var
|
|
65702
|
+
var import_node_fs42 = __toESM(require("fs"), 1);
|
|
65348
65703
|
init_protocol();
|
|
65349
65704
|
|
|
65350
65705
|
// src/tools/pi-rpc-client.ts
|
|
@@ -65444,9 +65799,9 @@ var PiRpcClient = class {
|
|
|
65444
65799
|
|
|
65445
65800
|
// src/tools/pi-session.ts
|
|
65446
65801
|
var import_node_child_process11 = require("child_process");
|
|
65447
|
-
var
|
|
65448
|
-
var
|
|
65449
|
-
var
|
|
65802
|
+
var import_node_crypto14 = require("crypto");
|
|
65803
|
+
var import_node_fs41 = __toESM(require("fs"), 1);
|
|
65804
|
+
var import_node_path45 = __toESM(require("path"), 1);
|
|
65450
65805
|
|
|
65451
65806
|
// src/tools/pi-events.ts
|
|
65452
65807
|
init_protocol();
|
|
@@ -65717,9 +66072,9 @@ ${dirs.map((d2) => `- ${d2}`).join("\n")}`;
|
|
|
65717
66072
|
}
|
|
65718
66073
|
function createPiSession(ctx, sink, deps = {}) {
|
|
65719
66074
|
const cmd = process.env.PI_BIN ?? "pi";
|
|
65720
|
-
const sessionId = ctx.toolSessionId ?? (0,
|
|
65721
|
-
const skillsDir =
|
|
65722
|
-
const exists = deps.skillsDirExists ?? ((d2) =>
|
|
66075
|
+
const sessionId = ctx.toolSessionId ?? (0, import_node_crypto14.randomUUID)();
|
|
66076
|
+
const skillsDir = import_node_path45.default.join(ctx.cwd, ".claude", "skills");
|
|
66077
|
+
const exists = deps.skillsDirExists ?? ((d2) => import_node_fs41.default.existsSync(d2));
|
|
65723
66078
|
const args = buildPiArgs(ctx, {
|
|
65724
66079
|
sessionId,
|
|
65725
66080
|
skillsDir: exists(skillsDir) ? skillsDir : void 0,
|
|
@@ -65781,10 +66136,10 @@ var PI_DEFAULT_MODEL_ENTRY = {
|
|
|
65781
66136
|
};
|
|
65782
66137
|
var PI_FULL_ACCESS = { id: "never", label: "Full Access", description: "pi \u65E0\u5BA1\u6279\uFF1A\u4ECE\u4E0D\u8BE2\u95EE\uFF0C\u81EA\u4E3B\u6267\u884C" };
|
|
65783
66138
|
async function probePi(env = process.env) {
|
|
65784
|
-
if (env.PI_BIN &&
|
|
66139
|
+
if (env.PI_BIN && import_node_fs42.default.existsSync(env.PI_BIN)) return { available: true, path: env.PI_BIN };
|
|
65785
66140
|
try {
|
|
65786
66141
|
const out = (0, import_node_child_process12.execFileSync)("which", ["pi"], { encoding: "utf8" }).trim();
|
|
65787
|
-
if (out &&
|
|
66142
|
+
if (out && import_node_fs42.default.existsSync(out)) return { available: true, path: out };
|
|
65788
66143
|
} catch {
|
|
65789
66144
|
}
|
|
65790
66145
|
return { available: false };
|
|
@@ -65954,25 +66309,29 @@ var PiAdapter = class {
|
|
|
65954
66309
|
};
|
|
65955
66310
|
|
|
65956
66311
|
// src/tools/pi-cloud-session.ts
|
|
65957
|
-
var
|
|
66312
|
+
var import_node_crypto15 = require("crypto");
|
|
65958
66313
|
function cloudPiInstructions(ctx) {
|
|
65959
66314
|
return [ctx.extraSystemPrompt, workDirPrompt(CLOUD_WORKSPACE_SLOT, ctx.personaMode ?? "owner")].filter((x2) => Boolean(x2)).join("\n\n");
|
|
65960
66315
|
}
|
|
65961
66316
|
function createCloudPiSession(ctx, sink, deps) {
|
|
65962
66317
|
const personaId2 = personaIdFromCloudCwd(ctx.cwd);
|
|
65963
|
-
const
|
|
66318
|
+
const clientSessionId = ctx.titleOnly ? (0, import_node_crypto15.randomUUID)() : ctx.cloudExecutionId ?? ctx.env?.CLAWD_SESSION_ID;
|
|
66319
|
+
const sessionId = ctx.toolSessionId ?? (0, import_node_crypto15.randomUUID)();
|
|
65964
66320
|
let channel = null;
|
|
65965
66321
|
let closed = false;
|
|
66322
|
+
let detached = false;
|
|
66323
|
+
let stopping = null;
|
|
65966
66324
|
let exited = false;
|
|
66325
|
+
let ready = false;
|
|
65967
66326
|
const exit = () => {
|
|
65968
66327
|
if (!exited) {
|
|
65969
66328
|
exited = true;
|
|
65970
66329
|
sink.onExit(null);
|
|
65971
66330
|
}
|
|
65972
66331
|
};
|
|
65973
|
-
if (!personaId2) {
|
|
66332
|
+
if (!personaId2 || !clientSessionId) {
|
|
65974
66333
|
queueMicrotask(() => {
|
|
65975
|
-
sink.onError(`cloud session
|
|
66334
|
+
sink.onError(`cloud session is missing ${personaId2 ? "CLAWD_SESSION_ID" : "persona id"}`);
|
|
65976
66335
|
exit();
|
|
65977
66336
|
});
|
|
65978
66337
|
return { startTurn() {
|
|
@@ -65981,18 +66340,28 @@ function createCloudPiSession(ctx, sink, deps) {
|
|
|
65981
66340
|
}, async stop() {
|
|
65982
66341
|
} };
|
|
65983
66342
|
}
|
|
65984
|
-
const opened = deps.client.openEventSession(personaId2, { expectedEngine: "pi", toolSessionId: sessionId, instructions: ctx.titleOnly ? "" : cloudPiInstructions(ctx), ...ctx.titleOnly ? { purpose: "title" } : {} }).then(
|
|
66343
|
+
const opened = deps.client.openEventSession(personaId2, { expectedEngine: "pi", clientSessionId, ...ctx.cloudGatewaySessionId ? { gatewaySessionId: ctx.cloudGatewaySessionId } : {}, toolSessionId: sessionId, instructions: ctx.titleOnly ? "" : cloudPiInstructions(ctx), ...ctx.titleOnly ? { purpose: "title" } : {}, ...ctx.cloudAttachOnly ? { attachOnly: true } : {} }).then(
|
|
65985
66344
|
(opened2) => {
|
|
65986
66345
|
channel = opened2;
|
|
65987
66346
|
channel.onEvents((events) => sink.pushEvents(events));
|
|
65988
66347
|
channel.onControl((c2) => {
|
|
65989
|
-
if (c2.kind === "
|
|
66348
|
+
if (c2.kind === "ready") {
|
|
66349
|
+
ready = true;
|
|
66350
|
+
sink.onGatewayReady?.(c2.session);
|
|
66351
|
+
if (c2.replayGap || c2.historySynchronized === false) sink.onHistoryGap?.(c2.historySynchronized === true);
|
|
66352
|
+
} else if (c2.kind === "queued") {
|
|
65990
66353
|
sink.pushEvents([{ kind: "meta-text", text: `\u4E91\u4E0A\u673A\u5668\u6709 ${c2.running} \u4E2A\u4EFB\u52A1\u5728\u8DD1\uFF0C\u7B49\u4E00\u4E2A\u7ED3\u675F\u5C31\u8F6E\u5230\u4F60` }]);
|
|
66354
|
+
} else if (c2.kind === "history") {
|
|
66355
|
+
sink.onHistoryGap?.(c2.synchronized);
|
|
65991
66356
|
} else if (c2.kind === "error") {
|
|
65992
|
-
sink.onError(
|
|
66357
|
+
sink.onError(`${ready ? "\u4E91\u4E0A\u6267\u884C\u5931\u8D25" : "\u4E91\u4E0A persona \u8D77\u4E0D\u6765"}\uFF1A${c2.message}`);
|
|
66358
|
+
} else if (c2.kind === "closed" && c2.reason === "not-found") {
|
|
66359
|
+
sink.onRecoveryAbsent?.();
|
|
65993
66360
|
}
|
|
65994
66361
|
});
|
|
65995
|
-
channel.onClose(
|
|
66362
|
+
channel.onClose(() => {
|
|
66363
|
+
if (!detached) exit();
|
|
66364
|
+
});
|
|
65996
66365
|
if (closed) channel.close();
|
|
65997
66366
|
return channel;
|
|
65998
66367
|
},
|
|
@@ -66011,12 +66380,13 @@ function createCloudPiSession(ctx, sink, deps) {
|
|
|
66011
66380
|
});
|
|
66012
66381
|
};
|
|
66013
66382
|
return {
|
|
66014
|
-
startTurn(text) {
|
|
66383
|
+
startTurn(text, commandId = (0, import_node_crypto15.randomUUID)(), prepared = false) {
|
|
66015
66384
|
send2(async () => {
|
|
66016
66385
|
const ch = await opened;
|
|
66017
66386
|
if (closed) return;
|
|
66018
|
-
const portable = await portableCloudInput(text, { fetchPiImage: deps.fetchImage ?? makeImageFetcher() });
|
|
66019
|
-
|
|
66387
|
+
const portable = prepared ? text : await portableCloudInput(text, { fetchPiImage: deps.fetchImage ?? makeImageFetcher() });
|
|
66388
|
+
if (sink.onCommandPrepared?.(commandId, portable, prepared) === false) return;
|
|
66389
|
+
await ch.send({ command: "turn", text: portable, commandId });
|
|
66020
66390
|
});
|
|
66021
66391
|
},
|
|
66022
66392
|
respondPermission(requestId, allow) {
|
|
@@ -66025,11 +66395,23 @@ function createCloudPiSession(ctx, sink, deps) {
|
|
|
66025
66395
|
interrupt() {
|
|
66026
66396
|
send2(async () => (await opened).send({ command: "interrupt" }));
|
|
66027
66397
|
},
|
|
66028
|
-
|
|
66398
|
+
detach() {
|
|
66399
|
+
detached = true;
|
|
66029
66400
|
closed = true;
|
|
66030
|
-
|
|
66031
|
-
|
|
66032
|
-
|
|
66401
|
+
channel?.close();
|
|
66402
|
+
},
|
|
66403
|
+
stop() {
|
|
66404
|
+
if (stopping) return stopping;
|
|
66405
|
+
closed = true;
|
|
66406
|
+
stopping = (async () => {
|
|
66407
|
+
const ch = await opened.catch(() => null);
|
|
66408
|
+
if (ch) {
|
|
66409
|
+
await ch.send({ command: "cancel" });
|
|
66410
|
+
ch.close();
|
|
66411
|
+
}
|
|
66412
|
+
exit();
|
|
66413
|
+
})();
|
|
66414
|
+
return stopping;
|
|
66033
66415
|
}
|
|
66034
66416
|
};
|
|
66035
66417
|
}
|
|
@@ -66101,7 +66483,7 @@ var CloudPiAdapter = class {
|
|
|
66101
66483
|
init_protocol();
|
|
66102
66484
|
|
|
66103
66485
|
// src/tools/codex-skills.ts
|
|
66104
|
-
var
|
|
66486
|
+
var import_node_path46 = __toESM(require("path"), 1);
|
|
66105
66487
|
function str4(v3) {
|
|
66106
66488
|
return typeof v3 === "string" ? v3 : void 0;
|
|
66107
66489
|
}
|
|
@@ -66116,13 +66498,13 @@ function mapSkillsListResponse(res) {
|
|
|
66116
66498
|
const r2 = s2 ?? {};
|
|
66117
66499
|
const name = str4(r2.name);
|
|
66118
66500
|
if (!name) continue;
|
|
66119
|
-
const
|
|
66501
|
+
const path107 = str4(r2.path);
|
|
66120
66502
|
const description = str4(r2.description);
|
|
66121
66503
|
const isPlugin = name.includes(":");
|
|
66122
66504
|
out.push({
|
|
66123
66505
|
name,
|
|
66124
66506
|
source: isPlugin ? "plugin" : "project",
|
|
66125
|
-
...
|
|
66507
|
+
...path107 ? { path: path107 } : {},
|
|
66126
66508
|
...description ? { description } : {},
|
|
66127
66509
|
...isPlugin ? { plugin: name.split(":")[0] } : {}
|
|
66128
66510
|
});
|
|
@@ -66138,7 +66520,7 @@ async function listCodexSkills(cwd, deps = {}) {
|
|
|
66138
66520
|
// 先写 extraRoots 再写 list(stdio 按写入顺序处理,fire-and-forget 不 await 回包;
|
|
66139
66521
|
// codex-session.ts ready 序列同款,两处保持一致)。失败不阻塞 list。
|
|
66140
66522
|
beforeRequest: (client) => {
|
|
66141
|
-
void client.request("skills/extraRoots/set", { extraRoots: [
|
|
66523
|
+
void client.request("skills/extraRoots/set", { extraRoots: [import_node_path46.default.join(cwd, ".claude", "skills")] }).catch(() => void 0);
|
|
66142
66524
|
}
|
|
66143
66525
|
});
|
|
66144
66526
|
return mapSkillsListResponse(res);
|
|
@@ -66212,23 +66594,23 @@ function rec4(v3) {
|
|
|
66212
66594
|
}
|
|
66213
66595
|
|
|
66214
66596
|
// src/workspace/browser.ts
|
|
66215
|
-
var
|
|
66597
|
+
var import_node_fs43 = __toESM(require("fs"), 1);
|
|
66216
66598
|
var import_node_os15 = __toESM(require("os"), 1);
|
|
66217
|
-
var
|
|
66599
|
+
var import_node_path47 = __toESM(require("path"), 1);
|
|
66218
66600
|
init_protocol();
|
|
66219
66601
|
var MAX_FILE_BYTES2 = 2 * 1024 * 1024;
|
|
66220
66602
|
function resolveInsideCwd(cwd, subpath) {
|
|
66221
|
-
const absCwd =
|
|
66222
|
-
const joined =
|
|
66223
|
-
const rel =
|
|
66224
|
-
if (rel.startsWith("..") ||
|
|
66603
|
+
const absCwd = import_node_path47.default.resolve(cwd);
|
|
66604
|
+
const joined = import_node_path47.default.resolve(absCwd, subpath ?? ".");
|
|
66605
|
+
const rel = import_node_path47.default.relative(absCwd, joined);
|
|
66606
|
+
if (rel.startsWith("..") || import_node_path47.default.isAbsolute(rel)) {
|
|
66225
66607
|
throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
|
|
66226
66608
|
}
|
|
66227
66609
|
return joined;
|
|
66228
66610
|
}
|
|
66229
66611
|
function ensureCwd(cwd) {
|
|
66230
66612
|
try {
|
|
66231
|
-
const stat =
|
|
66613
|
+
const stat = import_node_fs43.default.statSync(cwd);
|
|
66232
66614
|
if (!stat.isDirectory()) {
|
|
66233
66615
|
throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${cwd}`);
|
|
66234
66616
|
}
|
|
@@ -66242,7 +66624,7 @@ var WorkspaceBrowser = class {
|
|
|
66242
66624
|
const cwd = args.cwd && args.cwd.length > 0 ? args.cwd : import_node_os15.default.homedir();
|
|
66243
66625
|
ensureCwd(cwd);
|
|
66244
66626
|
const full = resolveInsideCwd(cwd, args.path);
|
|
66245
|
-
const dirents =
|
|
66627
|
+
const dirents = import_node_fs43.default.readdirSync(full, { withFileTypes: true });
|
|
66246
66628
|
const entries = [];
|
|
66247
66629
|
for (const d2 of dirents) {
|
|
66248
66630
|
if (!args.showHidden && d2.name.startsWith(".")) continue;
|
|
@@ -66252,7 +66634,7 @@ var WorkspaceBrowser = class {
|
|
|
66252
66634
|
mtime: ""
|
|
66253
66635
|
};
|
|
66254
66636
|
try {
|
|
66255
|
-
const st2 =
|
|
66637
|
+
const st2 = import_node_fs43.default.statSync(import_node_path47.default.join(full, d2.name));
|
|
66256
66638
|
entry.mtime = new Date(st2.mtimeMs).toISOString();
|
|
66257
66639
|
if (d2.isFile()) entry.size = st2.size;
|
|
66258
66640
|
} catch {
|
|
@@ -66268,14 +66650,14 @@ var WorkspaceBrowser = class {
|
|
|
66268
66650
|
read(args) {
|
|
66269
66651
|
ensureCwd(args.cwd);
|
|
66270
66652
|
const full = resolveInsideCwd(args.cwd, args.path);
|
|
66271
|
-
const st2 =
|
|
66653
|
+
const st2 = import_node_fs43.default.statSync(full);
|
|
66272
66654
|
if (!st2.isFile()) {
|
|
66273
66655
|
throw new ClawdError(ERROR_CODES.INVALID_PATH, `not a file: ${args.path}`);
|
|
66274
66656
|
}
|
|
66275
66657
|
if (st2.size > MAX_FILE_BYTES2) {
|
|
66276
66658
|
throw new ClawdError(ERROR_CODES.FILE_TOO_LARGE, `file > ${MAX_FILE_BYTES2} bytes`);
|
|
66277
66659
|
}
|
|
66278
|
-
const buf =
|
|
66660
|
+
const buf = import_node_fs43.default.readFileSync(full);
|
|
66279
66661
|
const isBinary = buf.includes(0);
|
|
66280
66662
|
if (isBinary) {
|
|
66281
66663
|
return {
|
|
@@ -66297,20 +66679,20 @@ var WorkspaceBrowser = class {
|
|
|
66297
66679
|
};
|
|
66298
66680
|
|
|
66299
66681
|
// src/skills/agents-scanner.ts
|
|
66300
|
-
var
|
|
66682
|
+
var import_node_fs44 = __toESM(require("fs"), 1);
|
|
66301
66683
|
var import_node_os16 = __toESM(require("os"), 1);
|
|
66302
|
-
var
|
|
66684
|
+
var import_node_path48 = __toESM(require("path"), 1);
|
|
66303
66685
|
var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
|
|
66304
66686
|
function isDirLikeSync2(p3) {
|
|
66305
66687
|
try {
|
|
66306
|
-
return
|
|
66688
|
+
return import_node_fs44.default.statSync(p3).isDirectory();
|
|
66307
66689
|
} catch {
|
|
66308
66690
|
return false;
|
|
66309
66691
|
}
|
|
66310
66692
|
}
|
|
66311
66693
|
function fileExistsSync(p3) {
|
|
66312
66694
|
try {
|
|
66313
|
-
return
|
|
66695
|
+
return import_node_fs44.default.statSync(p3).isFile();
|
|
66314
66696
|
} catch {
|
|
66315
66697
|
return false;
|
|
66316
66698
|
}
|
|
@@ -66318,7 +66700,7 @@ function fileExistsSync(p3) {
|
|
|
66318
66700
|
function parseAgentFile(filePath) {
|
|
66319
66701
|
let content;
|
|
66320
66702
|
try {
|
|
66321
|
-
content =
|
|
66703
|
+
content = import_node_fs44.default.readFileSync(filePath, "utf8");
|
|
66322
66704
|
} catch {
|
|
66323
66705
|
return {};
|
|
66324
66706
|
}
|
|
@@ -66331,16 +66713,16 @@ function parseAgentFile(filePath) {
|
|
|
66331
66713
|
function scanAgentsDir(dir, source, seen, out) {
|
|
66332
66714
|
let entries;
|
|
66333
66715
|
try {
|
|
66334
|
-
entries =
|
|
66716
|
+
entries = import_node_fs44.default.readdirSync(dir, { withFileTypes: true });
|
|
66335
66717
|
} catch {
|
|
66336
66718
|
return;
|
|
66337
66719
|
}
|
|
66338
66720
|
for (const ent of entries) {
|
|
66339
66721
|
if (!ent.name.endsWith(".md")) continue;
|
|
66340
|
-
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(
|
|
66722
|
+
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path48.default.join(dir, ent.name)))) {
|
|
66341
66723
|
continue;
|
|
66342
66724
|
}
|
|
66343
|
-
const filePath =
|
|
66725
|
+
const filePath = import_node_path48.default.join(dir, ent.name);
|
|
66344
66726
|
const baseName = ent.name.replace(/\.md$/, "");
|
|
66345
66727
|
if (seen.has(baseName)) continue;
|
|
66346
66728
|
seen.add(baseName);
|
|
@@ -66358,12 +66740,12 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
66358
66740
|
function walk2(dir, namespaces) {
|
|
66359
66741
|
let entries;
|
|
66360
66742
|
try {
|
|
66361
|
-
entries =
|
|
66743
|
+
entries = import_node_fs44.default.readdirSync(dir, { withFileTypes: true });
|
|
66362
66744
|
} catch {
|
|
66363
66745
|
return;
|
|
66364
66746
|
}
|
|
66365
66747
|
for (const ent of entries) {
|
|
66366
|
-
const childPath =
|
|
66748
|
+
const childPath = import_node_path48.default.join(dir, ent.name);
|
|
66367
66749
|
if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
|
|
66368
66750
|
walk2(childPath, [...namespaces, ent.name]);
|
|
66369
66751
|
continue;
|
|
@@ -66388,13 +66770,13 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
66388
66770
|
walk2(root, []);
|
|
66389
66771
|
}
|
|
66390
66772
|
function readInstalledPlugins2(home) {
|
|
66391
|
-
const pluginsDir =
|
|
66392
|
-
const v22 =
|
|
66393
|
-
const v1 =
|
|
66773
|
+
const pluginsDir = import_node_path48.default.join(home, ".claude", "plugins");
|
|
66774
|
+
const v22 = import_node_path48.default.join(pluginsDir, "installed_plugins_v2.json");
|
|
66775
|
+
const v1 = import_node_path48.default.join(pluginsDir, "installed_plugins.json");
|
|
66394
66776
|
let raw = null;
|
|
66395
66777
|
for (const candidate of [v22, v1]) {
|
|
66396
66778
|
try {
|
|
66397
|
-
raw =
|
|
66779
|
+
raw = import_node_fs44.default.readFileSync(candidate, "utf8");
|
|
66398
66780
|
break;
|
|
66399
66781
|
} catch {
|
|
66400
66782
|
}
|
|
@@ -66419,19 +66801,19 @@ function readInstalledPlugins2(home) {
|
|
|
66419
66801
|
return out;
|
|
66420
66802
|
}
|
|
66421
66803
|
function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
|
|
66422
|
-
let cur =
|
|
66423
|
-
const fsRoot =
|
|
66804
|
+
let cur = import_node_path48.default.resolve(startCwd);
|
|
66805
|
+
const fsRoot = import_node_path48.default.parse(cur).root;
|
|
66424
66806
|
while (true) {
|
|
66425
|
-
scanAgentsDir(
|
|
66807
|
+
scanAgentsDir(import_node_path48.default.join(cur, ".claude", "agents"), "project", seen, out);
|
|
66426
66808
|
let hasGit = false;
|
|
66427
66809
|
try {
|
|
66428
|
-
hasGit =
|
|
66810
|
+
hasGit = import_node_fs44.default.existsSync(import_node_path48.default.join(cur, ".git"));
|
|
66429
66811
|
} catch {
|
|
66430
66812
|
}
|
|
66431
66813
|
if (hasGit) return;
|
|
66432
66814
|
if (cur === home) return;
|
|
66433
66815
|
if (cur === fsRoot) return;
|
|
66434
|
-
const parent =
|
|
66816
|
+
const parent = import_node_path48.default.dirname(cur);
|
|
66435
66817
|
if (parent === cur) return;
|
|
66436
66818
|
cur = parent;
|
|
66437
66819
|
}
|
|
@@ -66466,7 +66848,7 @@ var AgentsScanner = class {
|
|
|
66466
66848
|
}
|
|
66467
66849
|
const fsBlock = [];
|
|
66468
66850
|
scanAgentsDir(
|
|
66469
|
-
|
|
66851
|
+
import_node_path48.default.join(this.home, ".claude", "agents"),
|
|
66470
66852
|
"global",
|
|
66471
66853
|
seen,
|
|
66472
66854
|
fsBlock
|
|
@@ -66480,7 +66862,7 @@ var AgentsScanner = class {
|
|
|
66480
66862
|
...this.extraPluginRoots
|
|
66481
66863
|
];
|
|
66482
66864
|
for (const { name, root } of plugins) {
|
|
66483
|
-
const agentsRoot =
|
|
66865
|
+
const agentsRoot = import_node_path48.default.join(root, "agents");
|
|
66484
66866
|
scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
|
|
66485
66867
|
}
|
|
66486
66868
|
return [...builtinBlock, ...fsBlock];
|
|
@@ -66488,15 +66870,15 @@ var AgentsScanner = class {
|
|
|
66488
66870
|
};
|
|
66489
66871
|
|
|
66490
66872
|
// src/observer/session-observer.ts
|
|
66491
|
-
var
|
|
66873
|
+
var import_node_fs46 = __toESM(require("fs"), 1);
|
|
66492
66874
|
var import_node_os18 = __toESM(require("os"), 1);
|
|
66493
|
-
var
|
|
66875
|
+
var import_node_path50 = __toESM(require("path"), 1);
|
|
66494
66876
|
init_claude_history();
|
|
66495
66877
|
|
|
66496
66878
|
// src/observer/subagent-meta-observer.ts
|
|
66497
|
-
var
|
|
66879
|
+
var import_node_fs45 = __toESM(require("fs"), 1);
|
|
66498
66880
|
var import_node_os17 = __toESM(require("os"), 1);
|
|
66499
|
-
var
|
|
66881
|
+
var import_node_path49 = __toESM(require("path"), 1);
|
|
66500
66882
|
init_claude_history();
|
|
66501
66883
|
var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
|
|
66502
66884
|
var SubagentMetaObserver = class {
|
|
@@ -66509,7 +66891,7 @@ var SubagentMetaObserver = class {
|
|
|
66509
66891
|
watches = /* @__PURE__ */ new Map();
|
|
66510
66892
|
// public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
|
|
66511
66893
|
resolveSubagentDir(cwd, toolSessionId) {
|
|
66512
|
-
return
|
|
66894
|
+
return import_node_path49.default.join(
|
|
66513
66895
|
this.home,
|
|
66514
66896
|
".claude",
|
|
66515
66897
|
"projects",
|
|
@@ -66539,7 +66921,7 @@ var SubagentMetaObserver = class {
|
|
|
66539
66921
|
attachWatcher(w3) {
|
|
66540
66922
|
if (w3.watcher) return;
|
|
66541
66923
|
try {
|
|
66542
|
-
w3.watcher =
|
|
66924
|
+
w3.watcher = import_node_fs45.default.watch(w3.dirPath, { persistent: false }, (_evt, name) => {
|
|
66543
66925
|
if (!name) return;
|
|
66544
66926
|
const m3 = META_RE.exec(String(name));
|
|
66545
66927
|
if (!m3) return;
|
|
@@ -66551,7 +66933,7 @@ var SubagentMetaObserver = class {
|
|
|
66551
66933
|
scan(w3) {
|
|
66552
66934
|
let entries;
|
|
66553
66935
|
try {
|
|
66554
|
-
entries =
|
|
66936
|
+
entries = import_node_fs45.default.readdirSync(w3.dirPath);
|
|
66555
66937
|
} catch {
|
|
66556
66938
|
return;
|
|
66557
66939
|
}
|
|
@@ -66565,10 +66947,10 @@ var SubagentMetaObserver = class {
|
|
|
66565
66947
|
if (!m3) return;
|
|
66566
66948
|
const agentId = m3[1];
|
|
66567
66949
|
if (w3.emitted.has(agentId)) return;
|
|
66568
|
-
const file =
|
|
66950
|
+
const file = import_node_path49.default.join(w3.dirPath, name);
|
|
66569
66951
|
let raw;
|
|
66570
66952
|
try {
|
|
66571
|
-
raw =
|
|
66953
|
+
raw = import_node_fs45.default.readFileSync(file, "utf8");
|
|
66572
66954
|
} catch {
|
|
66573
66955
|
return;
|
|
66574
66956
|
}
|
|
@@ -66625,14 +67007,14 @@ var SessionObserver = class {
|
|
|
66625
67007
|
metaObserver;
|
|
66626
67008
|
resolveJsonlPath(cwd, toolSessionId, override) {
|
|
66627
67009
|
if (override) return override;
|
|
66628
|
-
return
|
|
67010
|
+
return import_node_path50.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
|
|
66629
67011
|
}
|
|
66630
67012
|
start(args) {
|
|
66631
67013
|
this.stop(args.sessionId);
|
|
66632
67014
|
const filePath = this.resolveJsonlPath(args.cwd, args.toolSessionId, args.jsonlPath);
|
|
66633
67015
|
let size = 0;
|
|
66634
67016
|
try {
|
|
66635
|
-
size =
|
|
67017
|
+
size = import_node_fs46.default.statSync(filePath).size;
|
|
66636
67018
|
} catch {
|
|
66637
67019
|
}
|
|
66638
67020
|
const w3 = {
|
|
@@ -66645,16 +67027,16 @@ var SessionObserver = class {
|
|
|
66645
67027
|
adapter: args.adapter,
|
|
66646
67028
|
prevIsRejectSentinel: false,
|
|
66647
67029
|
toolSessionId: args.toolSessionId,
|
|
66648
|
-
sawFile:
|
|
67030
|
+
sawFile: import_node_fs46.default.existsSync(filePath),
|
|
66649
67031
|
lastRelocateScanMs: 0,
|
|
66650
67032
|
pendingCwdDerive: false,
|
|
66651
67033
|
lastDeriveMs: 0
|
|
66652
67034
|
};
|
|
66653
67035
|
try {
|
|
66654
|
-
|
|
67036
|
+
import_node_fs46.default.mkdirSync(import_node_path50.default.dirname(filePath), { recursive: true });
|
|
66655
67037
|
} catch {
|
|
66656
67038
|
}
|
|
66657
|
-
w3.watcher =
|
|
67039
|
+
w3.watcher = import_node_fs46.default.watch(import_node_path50.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
|
|
66658
67040
|
if (!changedName || !w3.filePath.endsWith(changedName)) return;
|
|
66659
67041
|
this.poll(w3);
|
|
66660
67042
|
});
|
|
@@ -66677,7 +67059,7 @@ var SessionObserver = class {
|
|
|
66677
67059
|
// 异常静默吞,不阻塞 watcher 启动
|
|
66678
67060
|
hydrateMetaTail(w3, maxLines = 200) {
|
|
66679
67061
|
try {
|
|
66680
|
-
const raw =
|
|
67062
|
+
const raw = import_node_fs46.default.readFileSync(w3.filePath, "utf8");
|
|
66681
67063
|
if (!raw) return;
|
|
66682
67064
|
const allLines = raw.split("\n").filter((l2) => l2.trim().length > 0);
|
|
66683
67065
|
if (allLines.length === 0) return;
|
|
@@ -66701,7 +67083,7 @@ var SessionObserver = class {
|
|
|
66701
67083
|
poll(w3) {
|
|
66702
67084
|
let size = 0;
|
|
66703
67085
|
try {
|
|
66704
|
-
size =
|
|
67086
|
+
size = import_node_fs46.default.statSync(w3.filePath).size;
|
|
66705
67087
|
} catch {
|
|
66706
67088
|
if (w3.sawFile) this.maybeRelocate(w3);
|
|
66707
67089
|
return;
|
|
@@ -66712,11 +67094,11 @@ var SessionObserver = class {
|
|
|
66712
67094
|
w3.buf = "";
|
|
66713
67095
|
}
|
|
66714
67096
|
if (size === w3.lastSize) return;
|
|
66715
|
-
const fd =
|
|
67097
|
+
const fd = import_node_fs46.default.openSync(w3.filePath, "r");
|
|
66716
67098
|
try {
|
|
66717
67099
|
const len = size - w3.lastSize;
|
|
66718
67100
|
const buf = Buffer.alloc(len);
|
|
66719
|
-
|
|
67101
|
+
import_node_fs46.default.readSync(fd, buf, 0, len, w3.lastSize);
|
|
66720
67102
|
w3.lastSize = size;
|
|
66721
67103
|
w3.buf += buf.toString("utf8");
|
|
66722
67104
|
let newlineIndex;
|
|
@@ -66739,7 +67121,7 @@ var SessionObserver = class {
|
|
|
66739
67121
|
}
|
|
66740
67122
|
}
|
|
66741
67123
|
} finally {
|
|
66742
|
-
|
|
67124
|
+
import_node_fs46.default.closeSync(fd);
|
|
66743
67125
|
}
|
|
66744
67126
|
if (w3.pendingCwdDerive) this.maybeDeriveCwd(w3);
|
|
66745
67127
|
}
|
|
@@ -66751,7 +67133,7 @@ var SessionObserver = class {
|
|
|
66751
67133
|
const now = Date.now();
|
|
66752
67134
|
if (now - w3.lastRelocateScanMs < 1e3) return;
|
|
66753
67135
|
w3.lastRelocateScanMs = now;
|
|
66754
|
-
const projectsRoot =
|
|
67136
|
+
const projectsRoot = import_node_path50.default.join(this.home, ".claude", "projects");
|
|
66755
67137
|
const found = findTranscriptByToolSessionId(projectsRoot, w3.toolSessionId);
|
|
66756
67138
|
if (!found || found === w3.filePath) return;
|
|
66757
67139
|
try {
|
|
@@ -66760,7 +67142,7 @@ var SessionObserver = class {
|
|
|
66760
67142
|
}
|
|
66761
67143
|
w3.filePath = found;
|
|
66762
67144
|
try {
|
|
66763
|
-
w3.watcher =
|
|
67145
|
+
w3.watcher = import_node_fs46.default.watch(import_node_path50.default.dirname(found), { persistent: false }, (_event, changedName) => {
|
|
66764
67146
|
if (!changedName || !w3.filePath.endsWith(changedName)) return;
|
|
66765
67147
|
this.poll(w3);
|
|
66766
67148
|
});
|
|
@@ -66882,9 +67264,9 @@ function listRegistered() {
|
|
|
66882
67264
|
// src/tools/title-generator.ts
|
|
66883
67265
|
var import_node_child_process13 = require("child_process");
|
|
66884
67266
|
init_protocol();
|
|
66885
|
-
var
|
|
67267
|
+
var import_node_fs47 = __toESM(require("fs"), 1);
|
|
66886
67268
|
var import_node_os19 = __toESM(require("os"), 1);
|
|
66887
|
-
var
|
|
67269
|
+
var import_node_path51 = __toESM(require("path"), 1);
|
|
66888
67270
|
var TITLE_GEN_DIR_PREFIX = "clawd-title-";
|
|
66889
67271
|
var TITLE_INPUT_MAX_CHARS = 400;
|
|
66890
67272
|
var DEFAULT_TITLE_GEN_TIMEOUT_MS = 45e3;
|
|
@@ -66975,21 +67357,21 @@ async function generateSessionTitle(file, firstMessage, deps = {}) {
|
|
|
66975
67357
|
}
|
|
66976
67358
|
let workDir;
|
|
66977
67359
|
try {
|
|
66978
|
-
workDir =
|
|
67360
|
+
workDir = import_node_fs47.default.mkdtempSync(import_node_path51.default.join(import_node_os19.default.tmpdir(), TITLE_GEN_DIR_PREFIX));
|
|
66979
67361
|
} catch {
|
|
66980
67362
|
return null;
|
|
66981
67363
|
}
|
|
66982
67364
|
const cleanupWorkDir = () => {
|
|
66983
67365
|
try {
|
|
66984
|
-
|
|
67366
|
+
import_node_fs47.default.rmSync(workDir, { recursive: true, force: true });
|
|
66985
67367
|
} catch {
|
|
66986
67368
|
}
|
|
66987
67369
|
};
|
|
66988
|
-
const outFile =
|
|
66989
|
-
const schemaFile =
|
|
67370
|
+
const outFile = import_node_path51.default.join(workDir, `codex-title-${process.pid}-${++outFileSeq}-${Date.now()}.txt`);
|
|
67371
|
+
const schemaFile = import_node_path51.default.join(workDir, "title-schema.json");
|
|
66990
67372
|
if (tool === "codex") {
|
|
66991
67373
|
try {
|
|
66992
|
-
|
|
67374
|
+
import_node_fs47.default.writeFileSync(schemaFile, CODEX_TITLE_SCHEMA);
|
|
66993
67375
|
} catch {
|
|
66994
67376
|
cleanupWorkDir();
|
|
66995
67377
|
return null;
|
|
@@ -67044,7 +67426,7 @@ async function generateSessionTitle(file, firstMessage, deps = {}) {
|
|
|
67044
67426
|
if (tool === "claude" || tool === "pi") return finish(parseTitleJson(stdout));
|
|
67045
67427
|
let fileText = "";
|
|
67046
67428
|
try {
|
|
67047
|
-
fileText =
|
|
67429
|
+
fileText = import_node_fs47.default.readFileSync(outFile, "utf8");
|
|
67048
67430
|
} catch {
|
|
67049
67431
|
return finish(null);
|
|
67050
67432
|
}
|
|
@@ -67117,7 +67499,7 @@ var wrapper_default = import_websocket.default;
|
|
|
67117
67499
|
|
|
67118
67500
|
// src/transport/local-ws-server.ts
|
|
67119
67501
|
var import_node_http = __toESM(require("http"), 1);
|
|
67120
|
-
var
|
|
67502
|
+
var import_node_crypto16 = require("crypto");
|
|
67121
67503
|
var LocalWsServer = class {
|
|
67122
67504
|
constructor(opts) {
|
|
67123
67505
|
this.opts = opts;
|
|
@@ -67334,7 +67716,7 @@ var LocalWsServer = class {
|
|
|
67334
67716
|
}
|
|
67335
67717
|
}
|
|
67336
67718
|
onConnection(socket, remoteAddress) {
|
|
67337
|
-
const id = (0,
|
|
67719
|
+
const id = (0, import_node_crypto16.randomUUID)();
|
|
67338
67720
|
const subscribedSessions = /* @__PURE__ */ new Map();
|
|
67339
67721
|
const handle = {
|
|
67340
67722
|
id,
|
|
@@ -67740,8 +68122,8 @@ async function authenticate(token, deps) {
|
|
|
67740
68122
|
}
|
|
67741
68123
|
|
|
67742
68124
|
// src/legacy-cleanup.ts
|
|
67743
|
-
var
|
|
67744
|
-
var
|
|
68125
|
+
var fs58 = __toESM(require("fs/promises"), 1);
|
|
68126
|
+
var path59 = __toESM(require("path"), 1);
|
|
67745
68127
|
var LEGACY_FILES = [
|
|
67746
68128
|
"personal-capability.json",
|
|
67747
68129
|
"received-capabilities.json",
|
|
@@ -67750,9 +68132,9 @@ var LEGACY_FILES = [
|
|
|
67750
68132
|
async function cleanupLegacyCapabilityFiles(dataDir, logger) {
|
|
67751
68133
|
const removed = [];
|
|
67752
68134
|
for (const name of LEGACY_FILES) {
|
|
67753
|
-
const p3 =
|
|
68135
|
+
const p3 = path59.join(dataDir, name);
|
|
67754
68136
|
try {
|
|
67755
|
-
await
|
|
68137
|
+
await fs58.unlink(p3);
|
|
67756
68138
|
removed.push(name);
|
|
67757
68139
|
logger.debug("legacy capability file removed", { file: name });
|
|
67758
68140
|
} catch (err) {
|
|
@@ -67764,13 +68146,13 @@ async function cleanupLegacyCapabilityFiles(dataDir, logger) {
|
|
|
67764
68146
|
}
|
|
67765
68147
|
|
|
67766
68148
|
// src/inbox/inbox-store.ts
|
|
67767
|
-
var
|
|
67768
|
-
var
|
|
68149
|
+
var fs59 = __toESM(require("fs"), 1);
|
|
68150
|
+
var path60 = __toESM(require("path"), 1);
|
|
67769
68151
|
var INBOX_SUBDIR = "inbox";
|
|
67770
68152
|
var InboxStore = class {
|
|
67771
68153
|
constructor(dataDir) {
|
|
67772
68154
|
this.dataDir = dataDir;
|
|
67773
|
-
|
|
68155
|
+
fs59.mkdirSync(this.dirPath(), { recursive: true });
|
|
67774
68156
|
}
|
|
67775
68157
|
dataDir;
|
|
67776
68158
|
/**
|
|
@@ -67782,7 +68164,7 @@ var InboxStore = class {
|
|
|
67782
68164
|
const file = this.filePath(peerDeviceId);
|
|
67783
68165
|
let raw;
|
|
67784
68166
|
try {
|
|
67785
|
-
raw =
|
|
68167
|
+
raw = fs59.readFileSync(file, "utf8");
|
|
67786
68168
|
} catch (err) {
|
|
67787
68169
|
if (err?.code === "ENOENT") return [];
|
|
67788
68170
|
return [];
|
|
@@ -67798,7 +68180,7 @@ var InboxStore = class {
|
|
|
67798
68180
|
const dir = this.dirPath();
|
|
67799
68181
|
let entries;
|
|
67800
68182
|
try {
|
|
67801
|
-
entries =
|
|
68183
|
+
entries = fs59.readdirSync(dir);
|
|
67802
68184
|
} catch (err) {
|
|
67803
68185
|
if (err?.code === "ENOENT") return [];
|
|
67804
68186
|
return [];
|
|
@@ -67814,9 +68196,9 @@ var InboxStore = class {
|
|
|
67814
68196
|
if (existing.some((m3) => m3.id === message.id)) return;
|
|
67815
68197
|
const file = this.filePath(message.peerDeviceId);
|
|
67816
68198
|
const line = JSON.stringify(message) + "\n";
|
|
67817
|
-
|
|
68199
|
+
fs59.appendFileSync(file, line, { mode: 384 });
|
|
67818
68200
|
try {
|
|
67819
|
-
|
|
68201
|
+
fs59.chmodSync(file, 384);
|
|
67820
68202
|
} catch {
|
|
67821
68203
|
}
|
|
67822
68204
|
}
|
|
@@ -67846,7 +68228,7 @@ var InboxStore = class {
|
|
|
67846
68228
|
removeByPeerDeviceId(peerDeviceId) {
|
|
67847
68229
|
const file = this.filePath(peerDeviceId);
|
|
67848
68230
|
try {
|
|
67849
|
-
|
|
68231
|
+
fs59.unlinkSync(file);
|
|
67850
68232
|
} catch (err) {
|
|
67851
68233
|
if (err?.code === "ENOENT") return;
|
|
67852
68234
|
}
|
|
@@ -67855,18 +68237,18 @@ var InboxStore = class {
|
|
|
67855
68237
|
const file = this.filePath(peerDeviceId);
|
|
67856
68238
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
67857
68239
|
const content = messages.map((m3) => JSON.stringify(m3)).join("\n") + (messages.length > 0 ? "\n" : "");
|
|
67858
|
-
|
|
67859
|
-
|
|
68240
|
+
fs59.writeFileSync(tmp, content, { mode: 384 });
|
|
68241
|
+
fs59.renameSync(tmp, file);
|
|
67860
68242
|
try {
|
|
67861
|
-
|
|
68243
|
+
fs59.chmodSync(file, 384);
|
|
67862
68244
|
} catch {
|
|
67863
68245
|
}
|
|
67864
68246
|
}
|
|
67865
68247
|
dirPath() {
|
|
67866
|
-
return
|
|
68248
|
+
return path60.join(this.dataDir, INBOX_SUBDIR);
|
|
67867
68249
|
}
|
|
67868
68250
|
filePath(peerDeviceId) {
|
|
67869
|
-
return
|
|
68251
|
+
return path60.join(this.dirPath(), `${peerDeviceId}.jsonl`);
|
|
67870
68252
|
}
|
|
67871
68253
|
};
|
|
67872
68254
|
function parseAllLines(raw) {
|
|
@@ -67954,8 +68336,8 @@ var InboxManager = class {
|
|
|
67954
68336
|
};
|
|
67955
68337
|
|
|
67956
68338
|
// src/state/contact-store.ts
|
|
67957
|
-
var
|
|
67958
|
-
var
|
|
68339
|
+
var fs60 = __toESM(require("fs"), 1);
|
|
68340
|
+
var path61 = __toESM(require("path"), 1);
|
|
67959
68341
|
var FILE_NAME = "contacts.json";
|
|
67960
68342
|
var ContactStore = class {
|
|
67961
68343
|
constructor(dataDir) {
|
|
@@ -67965,10 +68347,10 @@ var ContactStore = class {
|
|
|
67965
68347
|
contacts = /* @__PURE__ */ new Map();
|
|
67966
68348
|
load() {
|
|
67967
68349
|
this.contacts.clear();
|
|
67968
|
-
const file =
|
|
68350
|
+
const file = path61.join(this.dataDir, FILE_NAME);
|
|
67969
68351
|
let raw;
|
|
67970
68352
|
try {
|
|
67971
|
-
raw =
|
|
68353
|
+
raw = fs60.readFileSync(file, "utf8");
|
|
67972
68354
|
} catch (err) {
|
|
67973
68355
|
if (err?.code !== "ENOENT") this.renameBak(file);
|
|
67974
68356
|
return;
|
|
@@ -68049,20 +68431,20 @@ var ContactStore = class {
|
|
|
68049
68431
|
return true;
|
|
68050
68432
|
}
|
|
68051
68433
|
flush() {
|
|
68052
|
-
const file =
|
|
68434
|
+
const file = path61.join(this.dataDir, FILE_NAME);
|
|
68053
68435
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
68054
68436
|
const content = JSON.stringify(
|
|
68055
68437
|
{ contacts: Array.from(this.contacts.values()) },
|
|
68056
68438
|
null,
|
|
68057
68439
|
2
|
|
68058
68440
|
);
|
|
68059
|
-
|
|
68060
|
-
|
|
68061
|
-
|
|
68441
|
+
fs60.mkdirSync(this.dataDir, { recursive: true });
|
|
68442
|
+
fs60.writeFileSync(tmp, content, { mode: 384 });
|
|
68443
|
+
fs60.renameSync(tmp, file);
|
|
68062
68444
|
}
|
|
68063
68445
|
renameBak(file) {
|
|
68064
68446
|
try {
|
|
68065
|
-
|
|
68447
|
+
fs60.renameSync(file, `${file}.bak`);
|
|
68066
68448
|
} catch {
|
|
68067
68449
|
}
|
|
68068
68450
|
}
|
|
@@ -68170,61 +68552,61 @@ async function connectRemote(args) {
|
|
|
68170
68552
|
}
|
|
68171
68553
|
|
|
68172
68554
|
// src/migrations/2026-05-20-flatten-sessions.ts
|
|
68173
|
-
var
|
|
68174
|
-
var
|
|
68555
|
+
var fs61 = __toESM(require("fs"), 1);
|
|
68556
|
+
var path62 = __toESM(require("path"), 1);
|
|
68175
68557
|
var MIGRATION_FLAG_NAME = ".migration.v1.done";
|
|
68176
68558
|
function migrateFlattenSessions(opts) {
|
|
68177
68559
|
const dataDir = opts.dataDir;
|
|
68178
68560
|
const now = opts.now ?? Date.now;
|
|
68179
|
-
const sessionsDir =
|
|
68180
|
-
const flagPath =
|
|
68561
|
+
const sessionsDir = path62.join(dataDir, "sessions");
|
|
68562
|
+
const flagPath = path62.join(sessionsDir, MIGRATION_FLAG_NAME);
|
|
68181
68563
|
if (existsSync3(flagPath)) {
|
|
68182
68564
|
return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
|
|
68183
68565
|
}
|
|
68184
68566
|
let movedBare = 0;
|
|
68185
68567
|
let movedVmOwner = 0;
|
|
68186
68568
|
let archivedListener = 0;
|
|
68187
|
-
const defaultDir =
|
|
68569
|
+
const defaultDir = path62.join(sessionsDir, "default");
|
|
68188
68570
|
if (existsSync3(defaultDir)) {
|
|
68189
68571
|
for (const entry of readdirSafe(defaultDir)) {
|
|
68190
68572
|
if (!entry.endsWith(".json")) continue;
|
|
68191
|
-
const src =
|
|
68192
|
-
const dst =
|
|
68193
|
-
|
|
68573
|
+
const src = path62.join(defaultDir, entry);
|
|
68574
|
+
const dst = path62.join(sessionsDir, entry);
|
|
68575
|
+
fs61.renameSync(src, dst);
|
|
68194
68576
|
movedBare += 1;
|
|
68195
68577
|
}
|
|
68196
68578
|
rmdirIfEmpty(defaultDir);
|
|
68197
68579
|
}
|
|
68198
68580
|
for (const pid of readdirSafe(sessionsDir)) {
|
|
68199
|
-
const personaDir =
|
|
68581
|
+
const personaDir = path62.join(sessionsDir, pid);
|
|
68200
68582
|
if (!isDir(personaDir)) continue;
|
|
68201
68583
|
if (pid === "default") continue;
|
|
68202
|
-
const ownerSrc =
|
|
68584
|
+
const ownerSrc = path62.join(personaDir, "owner");
|
|
68203
68585
|
if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
|
|
68204
|
-
const ownerDst =
|
|
68205
|
-
|
|
68586
|
+
const ownerDst = path62.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
|
|
68587
|
+
fs61.mkdirSync(ownerDst, { recursive: true });
|
|
68206
68588
|
for (const file of readdirSafe(ownerSrc)) {
|
|
68207
68589
|
if (!file.endsWith(".json")) continue;
|
|
68208
|
-
|
|
68590
|
+
fs61.renameSync(path62.join(ownerSrc, file), path62.join(ownerDst, file));
|
|
68209
68591
|
movedVmOwner += 1;
|
|
68210
68592
|
}
|
|
68211
68593
|
rmdirIfEmpty(ownerSrc);
|
|
68212
68594
|
}
|
|
68213
|
-
const listenerSrc =
|
|
68595
|
+
const listenerSrc = path62.join(personaDir, "listener");
|
|
68214
68596
|
if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
|
|
68215
|
-
const archiveDst =
|
|
68216
|
-
|
|
68597
|
+
const archiveDst = path62.join(dataDir, ".legacy", `listener-${pid}`);
|
|
68598
|
+
fs61.mkdirSync(archiveDst, { recursive: true });
|
|
68217
68599
|
for (const file of readdirSafe(listenerSrc)) {
|
|
68218
68600
|
if (!file.endsWith(".json")) continue;
|
|
68219
|
-
|
|
68601
|
+
fs61.renameSync(path62.join(listenerSrc, file), path62.join(archiveDst, file));
|
|
68220
68602
|
archivedListener += 1;
|
|
68221
68603
|
}
|
|
68222
68604
|
rmdirIfEmpty(listenerSrc);
|
|
68223
68605
|
}
|
|
68224
68606
|
rmdirIfEmpty(personaDir);
|
|
68225
68607
|
}
|
|
68226
|
-
|
|
68227
|
-
|
|
68608
|
+
fs61.mkdirSync(sessionsDir, { recursive: true });
|
|
68609
|
+
fs61.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
|
|
68228
68610
|
return {
|
|
68229
68611
|
skipped: false,
|
|
68230
68612
|
flagWritten: true,
|
|
@@ -68235,7 +68617,7 @@ function migrateFlattenSessions(opts) {
|
|
|
68235
68617
|
}
|
|
68236
68618
|
function existsSync3(p3) {
|
|
68237
68619
|
try {
|
|
68238
|
-
|
|
68620
|
+
fs61.statSync(p3);
|
|
68239
68621
|
return true;
|
|
68240
68622
|
} catch {
|
|
68241
68623
|
return false;
|
|
@@ -68243,63 +68625,63 @@ function existsSync3(p3) {
|
|
|
68243
68625
|
}
|
|
68244
68626
|
function isDir(p3) {
|
|
68245
68627
|
try {
|
|
68246
|
-
return
|
|
68628
|
+
return fs61.statSync(p3).isDirectory();
|
|
68247
68629
|
} catch {
|
|
68248
68630
|
return false;
|
|
68249
68631
|
}
|
|
68250
68632
|
}
|
|
68251
68633
|
function readdirSafe(p3) {
|
|
68252
68634
|
try {
|
|
68253
|
-
return
|
|
68635
|
+
return fs61.readdirSync(p3);
|
|
68254
68636
|
} catch {
|
|
68255
68637
|
return [];
|
|
68256
68638
|
}
|
|
68257
68639
|
}
|
|
68258
68640
|
function rmdirIfEmpty(p3) {
|
|
68259
68641
|
try {
|
|
68260
|
-
|
|
68642
|
+
fs61.rmdirSync(p3);
|
|
68261
68643
|
} catch {
|
|
68262
68644
|
}
|
|
68263
68645
|
}
|
|
68264
68646
|
|
|
68265
68647
|
// src/migrations/2026-08-18-drop-seeded-projects.ts
|
|
68266
|
-
var
|
|
68267
|
-
var
|
|
68648
|
+
var fs62 = __toESM(require("fs"), 1);
|
|
68649
|
+
var path63 = __toESM(require("path"), 1);
|
|
68268
68650
|
var DROP_SEEDED_PROJECTS_FLAG = ".projects-seed-dropped.v1.done";
|
|
68269
68651
|
function dropSeededProjects(opts) {
|
|
68270
|
-
|
|
68271
|
-
const flag =
|
|
68272
|
-
if (
|
|
68273
|
-
const file =
|
|
68652
|
+
fs62.mkdirSync(opts.dataDir, { recursive: true });
|
|
68653
|
+
const flag = path63.join(opts.dataDir, DROP_SEEDED_PROJECTS_FLAG);
|
|
68654
|
+
if (fs62.existsSync(flag)) return { skipped: true, dropped: 0, backup: null };
|
|
68655
|
+
const file = path63.join(opts.dataDir, "projects.json");
|
|
68274
68656
|
let raw = null;
|
|
68275
68657
|
let dropped = 0;
|
|
68276
68658
|
try {
|
|
68277
|
-
raw =
|
|
68659
|
+
raw = fs62.readFileSync(file, "utf8");
|
|
68278
68660
|
dropped = JSON.parse(raw).projects?.length ?? 0;
|
|
68279
68661
|
} catch {
|
|
68280
68662
|
}
|
|
68281
68663
|
let backup = null;
|
|
68282
68664
|
if (raw != null && dropped > 0) {
|
|
68283
|
-
const dir =
|
|
68284
|
-
|
|
68285
|
-
backup =
|
|
68286
|
-
|
|
68665
|
+
const dir = path63.join(opts.dataDir, "backups");
|
|
68666
|
+
fs62.mkdirSync(dir, { recursive: true });
|
|
68667
|
+
backup = path63.join(dir, `projects.seed-dropped.${(opts.now ?? Date.now)()}.json`);
|
|
68668
|
+
fs62.writeFileSync(backup, raw);
|
|
68287
68669
|
}
|
|
68288
68670
|
if (raw != null || dropped > 0) {
|
|
68289
|
-
|
|
68671
|
+
fs62.writeFileSync(file, JSON.stringify({ projects: [] }, null, 2));
|
|
68290
68672
|
}
|
|
68291
|
-
|
|
68673
|
+
fs62.writeFileSync(flag, (/* @__PURE__ */ new Date()).toISOString());
|
|
68292
68674
|
return { skipped: false, dropped, backup };
|
|
68293
68675
|
}
|
|
68294
68676
|
|
|
68295
68677
|
// src/transport/http-router.ts
|
|
68296
|
-
var
|
|
68297
|
-
var
|
|
68678
|
+
var import_node_fs49 = __toESM(require("fs"), 1);
|
|
68679
|
+
var import_node_path54 = __toESM(require("path"), 1);
|
|
68298
68680
|
|
|
68299
68681
|
// src/attachment/upload.ts
|
|
68300
|
-
var
|
|
68301
|
-
var
|
|
68302
|
-
var
|
|
68682
|
+
var import_node_fs48 = __toESM(require("fs"), 1);
|
|
68683
|
+
var import_node_path52 = __toESM(require("path"), 1);
|
|
68684
|
+
var import_node_crypto17 = __toESM(require("crypto"), 1);
|
|
68303
68685
|
var import_promises8 = require("stream/promises");
|
|
68304
68686
|
var UploadError = class extends Error {
|
|
68305
68687
|
constructor(code, message) {
|
|
@@ -68310,24 +68692,24 @@ var UploadError = class extends Error {
|
|
|
68310
68692
|
code;
|
|
68311
68693
|
};
|
|
68312
68694
|
function assertValidFileName(fileName) {
|
|
68313
|
-
if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !==
|
|
68695
|
+
if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path52.default.basename(fileName)) {
|
|
68314
68696
|
throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
|
|
68315
68697
|
}
|
|
68316
68698
|
}
|
|
68317
68699
|
var HASH_PREFIX_LEN = 16;
|
|
68318
68700
|
async function writeUploadedAttachment(args) {
|
|
68319
68701
|
assertValidFileName(args.fileName);
|
|
68320
|
-
const attachmentsRoot =
|
|
68702
|
+
const attachmentsRoot = import_node_path52.default.join(args.baseDir, ".attachments");
|
|
68321
68703
|
try {
|
|
68322
|
-
|
|
68704
|
+
import_node_fs48.default.mkdirSync(attachmentsRoot, { recursive: true });
|
|
68323
68705
|
} catch (err) {
|
|
68324
68706
|
throw new UploadError("STORAGE_ERROR", `mkdir failed: ${err.message}`);
|
|
68325
68707
|
}
|
|
68326
|
-
const hasher =
|
|
68708
|
+
const hasher = import_node_crypto17.default.createHash("sha256");
|
|
68327
68709
|
let actualSize = 0;
|
|
68328
|
-
const tmpPath =
|
|
68710
|
+
const tmpPath = import_node_path52.default.join(
|
|
68329
68711
|
attachmentsRoot,
|
|
68330
|
-
`.upload-${process.pid}-${Date.now()}-${
|
|
68712
|
+
`.upload-${process.pid}-${Date.now()}-${import_node_crypto17.default.randomBytes(4).toString("hex")}`
|
|
68331
68713
|
);
|
|
68332
68714
|
try {
|
|
68333
68715
|
await (0, import_promises8.pipeline)(
|
|
@@ -68340,18 +68722,18 @@ async function writeUploadedAttachment(args) {
|
|
|
68340
68722
|
yield buf;
|
|
68341
68723
|
}
|
|
68342
68724
|
},
|
|
68343
|
-
|
|
68725
|
+
import_node_fs48.default.createWriteStream(tmpPath, { mode: 384 })
|
|
68344
68726
|
);
|
|
68345
68727
|
} catch (err) {
|
|
68346
68728
|
try {
|
|
68347
|
-
|
|
68729
|
+
import_node_fs48.default.unlinkSync(tmpPath);
|
|
68348
68730
|
} catch {
|
|
68349
68731
|
}
|
|
68350
68732
|
throw new UploadError("STORAGE_ERROR", `write failed: ${err.message}`);
|
|
68351
68733
|
}
|
|
68352
68734
|
if (actualSize !== args.contentLength) {
|
|
68353
68735
|
try {
|
|
68354
|
-
|
|
68736
|
+
import_node_fs48.default.unlinkSync(tmpPath);
|
|
68355
68737
|
} catch {
|
|
68356
68738
|
}
|
|
68357
68739
|
throw new UploadError(
|
|
@@ -68360,34 +68742,34 @@ async function writeUploadedAttachment(args) {
|
|
|
68360
68742
|
);
|
|
68361
68743
|
}
|
|
68362
68744
|
const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
|
|
68363
|
-
const hashDir =
|
|
68745
|
+
const hashDir = import_node_path52.default.join(attachmentsRoot, attachmentId);
|
|
68364
68746
|
let finalFileName;
|
|
68365
68747
|
let hashDirExists = false;
|
|
68366
68748
|
try {
|
|
68367
|
-
hashDirExists =
|
|
68749
|
+
hashDirExists = import_node_fs48.default.statSync(hashDir).isDirectory();
|
|
68368
68750
|
} catch {
|
|
68369
68751
|
}
|
|
68370
68752
|
if (hashDirExists) {
|
|
68371
|
-
const existing =
|
|
68753
|
+
const existing = import_node_fs48.default.readdirSync(hashDir).filter((n2) => !n2.startsWith("."));
|
|
68372
68754
|
finalFileName = existing[0] ?? args.fileName;
|
|
68373
68755
|
try {
|
|
68374
|
-
|
|
68756
|
+
import_node_fs48.default.unlinkSync(tmpPath);
|
|
68375
68757
|
} catch {
|
|
68376
68758
|
}
|
|
68377
68759
|
} else {
|
|
68378
68760
|
try {
|
|
68379
|
-
|
|
68761
|
+
import_node_fs48.default.mkdirSync(hashDir, { recursive: true });
|
|
68380
68762
|
finalFileName = args.fileName;
|
|
68381
|
-
|
|
68763
|
+
import_node_fs48.default.renameSync(tmpPath, import_node_path52.default.join(hashDir, finalFileName));
|
|
68382
68764
|
} catch (err) {
|
|
68383
68765
|
try {
|
|
68384
|
-
|
|
68766
|
+
import_node_fs48.default.unlinkSync(tmpPath);
|
|
68385
68767
|
} catch {
|
|
68386
68768
|
}
|
|
68387
68769
|
throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
|
|
68388
68770
|
}
|
|
68389
68771
|
}
|
|
68390
|
-
const absPath =
|
|
68772
|
+
const absPath = import_node_path52.default.join(hashDir, finalFileName);
|
|
68391
68773
|
const relPath = absPath;
|
|
68392
68774
|
args.groupFileStore.upsert(args.scope, args.sessionId, {
|
|
68393
68775
|
relPath: absPath,
|
|
@@ -68402,7 +68784,7 @@ async function writeUploadedAttachment(args) {
|
|
|
68402
68784
|
|
|
68403
68785
|
// src/extension/import.ts
|
|
68404
68786
|
var import_promises9 = __toESM(require("fs/promises"), 1);
|
|
68405
|
-
var
|
|
68787
|
+
var import_node_path53 = __toESM(require("path"), 1);
|
|
68406
68788
|
var import_node_os20 = __toESM(require("os"), 1);
|
|
68407
68789
|
var import_jszip = __toESM(require_lib3(), 1);
|
|
68408
68790
|
var ImportError = class extends Error {
|
|
@@ -68420,7 +68802,7 @@ async function importZip(buf, root) {
|
|
|
68420
68802
|
throw new ImportError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
68421
68803
|
}
|
|
68422
68804
|
for (const name of Object.keys(zip.files)) {
|
|
68423
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
68805
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path53.default.isAbsolute(name)) {
|
|
68424
68806
|
throw new ImportError("ZIP_INVALID", `unsafe zip entry path: ${name}`);
|
|
68425
68807
|
}
|
|
68426
68808
|
}
|
|
@@ -68453,7 +68835,7 @@ async function importZip(buf, root) {
|
|
|
68453
68835
|
);
|
|
68454
68836
|
}
|
|
68455
68837
|
}
|
|
68456
|
-
const destDir =
|
|
68838
|
+
const destDir = import_node_path53.default.join(root, manifest.id);
|
|
68457
68839
|
let destExists = false;
|
|
68458
68840
|
try {
|
|
68459
68841
|
await import_promises9.default.access(destDir);
|
|
@@ -68463,15 +68845,15 @@ async function importZip(buf, root) {
|
|
|
68463
68845
|
if (destExists) {
|
|
68464
68846
|
throw new ImportError("ALREADY_EXISTS", `extension ${manifest.id} already installed`);
|
|
68465
68847
|
}
|
|
68466
|
-
const stage = await import_promises9.default.mkdtemp(
|
|
68848
|
+
const stage = await import_promises9.default.mkdtemp(import_node_path53.default.join(import_node_os20.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
|
|
68467
68849
|
try {
|
|
68468
68850
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
68469
|
-
const dest =
|
|
68851
|
+
const dest = import_node_path53.default.join(stage, name);
|
|
68470
68852
|
if (entry.dir) {
|
|
68471
68853
|
await import_promises9.default.mkdir(dest, { recursive: true });
|
|
68472
68854
|
continue;
|
|
68473
68855
|
}
|
|
68474
|
-
await import_promises9.default.mkdir(
|
|
68856
|
+
await import_promises9.default.mkdir(import_node_path53.default.dirname(dest), { recursive: true });
|
|
68475
68857
|
const content = await entry.async("nodebuffer");
|
|
68476
68858
|
await import_promises9.default.writeFile(dest, content);
|
|
68477
68859
|
}
|
|
@@ -68525,7 +68907,7 @@ var SHARE_UI_ASSET_MIME = {
|
|
|
68525
68907
|
".wasm": "application/wasm"
|
|
68526
68908
|
};
|
|
68527
68909
|
function shareUiAssetMime(filePath) {
|
|
68528
|
-
const ext =
|
|
68910
|
+
const ext = import_node_path54.default.extname(filePath).toLowerCase();
|
|
68529
68911
|
return SHARE_UI_ASSET_MIME[ext] ?? lookupMime(filePath);
|
|
68530
68912
|
}
|
|
68531
68913
|
var AUTHED_RPC_ROUTE_PREFIX = "/rpc/";
|
|
@@ -68624,7 +69006,7 @@ function isValidUploadFileName(fileName) {
|
|
|
68624
69006
|
if (fileName === "." || fileName === "..") return false;
|
|
68625
69007
|
if (fileName.startsWith(".")) return false;
|
|
68626
69008
|
if (fileName.includes("/") || fileName.includes("\\")) return false;
|
|
68627
|
-
return fileName ===
|
|
69009
|
+
return fileName === import_node_path54.default.basename(fileName);
|
|
68628
69010
|
}
|
|
68629
69011
|
function createHttpRouter(deps) {
|
|
68630
69012
|
return async (req, res) => {
|
|
@@ -68708,7 +69090,7 @@ function createHttpRouter(deps) {
|
|
|
68708
69090
|
}
|
|
68709
69091
|
let buf;
|
|
68710
69092
|
try {
|
|
68711
|
-
buf = await
|
|
69093
|
+
buf = await import_node_fs49.default.promises.readFile(abs);
|
|
68712
69094
|
} catch {
|
|
68713
69095
|
sendJson2(res, 404, { code: "NOT_FOUND", message: "asset not found" });
|
|
68714
69096
|
return true;
|
|
@@ -68854,7 +69236,7 @@ function createHttpRouter(deps) {
|
|
|
68854
69236
|
sendHtml(res, statusByCode[r2.code], loader.renderErrorHtml(r2.code, msgByCode[r2.code]));
|
|
68855
69237
|
return true;
|
|
68856
69238
|
}
|
|
68857
|
-
sendHtml(res, 200, loader.renderViewerHtml(
|
|
69239
|
+
sendHtml(res, 200, loader.renderViewerHtml(import_node_path54.default.basename(r2.absPath)));
|
|
68858
69240
|
return true;
|
|
68859
69241
|
}
|
|
68860
69242
|
const ctx = deps.authResolver.resolveFromHeader(
|
|
@@ -68975,7 +69357,7 @@ function createHttpRouter(deps) {
|
|
|
68975
69357
|
return true;
|
|
68976
69358
|
}
|
|
68977
69359
|
let absPath;
|
|
68978
|
-
if (
|
|
69360
|
+
if (import_node_path54.default.isAbsolute(pathParam)) {
|
|
68979
69361
|
absPath = pathParam;
|
|
68980
69362
|
} else if (deps.sessionStore) {
|
|
68981
69363
|
const file = deps.sessionStore.read(sid);
|
|
@@ -68983,7 +69365,7 @@ function createHttpRouter(deps) {
|
|
|
68983
69365
|
sendJson2(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
|
|
68984
69366
|
return true;
|
|
68985
69367
|
}
|
|
68986
|
-
absPath =
|
|
69368
|
+
absPath = import_node_path54.default.join(file.cwd, pathParam);
|
|
68987
69369
|
} else {
|
|
68988
69370
|
sendJson2(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
|
|
68989
69371
|
return true;
|
|
@@ -69067,7 +69449,7 @@ function withCtx(ctx, body) {
|
|
|
69067
69449
|
function streamFile(res, absPath, logger) {
|
|
69068
69450
|
let stat;
|
|
69069
69451
|
try {
|
|
69070
|
-
stat =
|
|
69452
|
+
stat = import_node_fs49.default.statSync(absPath);
|
|
69071
69453
|
} catch (err) {
|
|
69072
69454
|
const code = err?.code;
|
|
69073
69455
|
if (code === "ENOENT") {
|
|
@@ -69082,7 +69464,7 @@ function streamFile(res, absPath, logger) {
|
|
|
69082
69464
|
return;
|
|
69083
69465
|
}
|
|
69084
69466
|
const mime = lookupMime(absPath);
|
|
69085
|
-
const basename2 =
|
|
69467
|
+
const basename2 = import_node_path54.default.basename(absPath);
|
|
69086
69468
|
res.writeHead(200, {
|
|
69087
69469
|
"Content-Type": mime,
|
|
69088
69470
|
"Content-Length": String(stat.size),
|
|
@@ -69090,7 +69472,7 @@ function streamFile(res, absPath, logger) {
|
|
|
69090
69472
|
// 防止浏览器把任意 mime 当 html 渲染
|
|
69091
69473
|
"X-Content-Type-Options": "nosniff"
|
|
69092
69474
|
});
|
|
69093
|
-
const stream =
|
|
69475
|
+
const stream = import_node_fs49.default.createReadStream(absPath);
|
|
69094
69476
|
stream.on("error", (err) => {
|
|
69095
69477
|
logger?.warn("streamFile read error", { absPath, err: err.message });
|
|
69096
69478
|
res.destroy();
|
|
@@ -69099,8 +69481,8 @@ function streamFile(res, absPath, logger) {
|
|
|
69099
69481
|
}
|
|
69100
69482
|
|
|
69101
69483
|
// src/attachment/gc.ts
|
|
69102
|
-
var
|
|
69103
|
-
var
|
|
69484
|
+
var import_node_fs50 = __toESM(require("fs"), 1);
|
|
69485
|
+
var import_node_path55 = __toESM(require("path"), 1);
|
|
69104
69486
|
var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
|
|
69105
69487
|
function runAttachmentGc(args) {
|
|
69106
69488
|
const now = (args.now ?? Date.now)();
|
|
@@ -69109,12 +69491,12 @@ function runAttachmentGc(args) {
|
|
|
69109
69491
|
for (const { scope, sessionId } of args.sessionScopes) {
|
|
69110
69492
|
for (const entry of args.groupFileStore.list(scope, sessionId)) {
|
|
69111
69493
|
if (entry.stale) continue;
|
|
69112
|
-
if (
|
|
69494
|
+
if (import_node_path55.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
|
|
69113
69495
|
}
|
|
69114
69496
|
}
|
|
69115
69497
|
const visited = /* @__PURE__ */ new Set();
|
|
69116
69498
|
for (const { scope, sessionId } of args.sessionScopes) {
|
|
69117
|
-
const legacyDir = args.getSessionCwd?.(sessionId) ??
|
|
69499
|
+
const legacyDir = args.getSessionCwd?.(sessionId) ?? import_node_path55.default.join(
|
|
69118
69500
|
args.dataDir,
|
|
69119
69501
|
"sessions",
|
|
69120
69502
|
...scopeSubPath(scope).map(safeFileName),
|
|
@@ -69127,28 +69509,28 @@ function runAttachmentGc(args) {
|
|
|
69127
69509
|
return true;
|
|
69128
69510
|
});
|
|
69129
69511
|
for (const rootDir of roots) {
|
|
69130
|
-
const attRoot =
|
|
69512
|
+
const attRoot = import_node_path55.default.join(rootDir, ".attachments");
|
|
69131
69513
|
let hashDirs;
|
|
69132
69514
|
try {
|
|
69133
|
-
hashDirs =
|
|
69515
|
+
hashDirs = import_node_fs50.default.readdirSync(attRoot);
|
|
69134
69516
|
} catch (err) {
|
|
69135
69517
|
if (err.code === "ENOENT") continue;
|
|
69136
69518
|
args.logger?.warn("attachment gc: readdir failed", { attRoot, err: err.message });
|
|
69137
69519
|
continue;
|
|
69138
69520
|
}
|
|
69139
69521
|
for (const hashDir of hashDirs) {
|
|
69140
|
-
const hashDirAbs =
|
|
69522
|
+
const hashDirAbs = import_node_path55.default.join(attRoot, hashDir);
|
|
69141
69523
|
let files;
|
|
69142
69524
|
try {
|
|
69143
|
-
files =
|
|
69525
|
+
files = import_node_fs50.default.readdirSync(hashDirAbs);
|
|
69144
69526
|
} catch {
|
|
69145
69527
|
continue;
|
|
69146
69528
|
}
|
|
69147
69529
|
for (const name of files) {
|
|
69148
|
-
const file =
|
|
69530
|
+
const file = import_node_path55.default.join(hashDirAbs, name);
|
|
69149
69531
|
let stat;
|
|
69150
69532
|
try {
|
|
69151
|
-
stat =
|
|
69533
|
+
stat = import_node_fs50.default.statSync(file);
|
|
69152
69534
|
} catch {
|
|
69153
69535
|
continue;
|
|
69154
69536
|
}
|
|
@@ -69157,18 +69539,18 @@ function runAttachmentGc(args) {
|
|
|
69157
69539
|
if (age < ttlMs) continue;
|
|
69158
69540
|
if (liveAbs.has(file)) continue;
|
|
69159
69541
|
try {
|
|
69160
|
-
|
|
69542
|
+
import_node_fs50.default.unlinkSync(file);
|
|
69161
69543
|
} catch (err) {
|
|
69162
69544
|
args.logger?.warn("attachment gc: unlink failed", { file, err: err.message });
|
|
69163
69545
|
}
|
|
69164
69546
|
}
|
|
69165
69547
|
try {
|
|
69166
|
-
if (
|
|
69548
|
+
if (import_node_fs50.default.readdirSync(hashDirAbs).length === 0) import_node_fs50.default.rmdirSync(hashDirAbs);
|
|
69167
69549
|
} catch {
|
|
69168
69550
|
}
|
|
69169
69551
|
}
|
|
69170
69552
|
try {
|
|
69171
|
-
if (
|
|
69553
|
+
if (import_node_fs50.default.readdirSync(attRoot).length === 0) import_node_fs50.default.rmdirSync(attRoot);
|
|
69172
69554
|
} catch {
|
|
69173
69555
|
}
|
|
69174
69556
|
}
|
|
@@ -69176,9 +69558,9 @@ function runAttachmentGc(args) {
|
|
|
69176
69558
|
}
|
|
69177
69559
|
|
|
69178
69560
|
// src/attachment/group.ts
|
|
69179
|
-
var
|
|
69180
|
-
var
|
|
69181
|
-
var
|
|
69561
|
+
var import_node_fs51 = __toESM(require("fs"), 1);
|
|
69562
|
+
var import_node_path56 = __toESM(require("path"), 1);
|
|
69563
|
+
var import_node_crypto18 = __toESM(require("crypto"), 1);
|
|
69182
69564
|
init_protocol();
|
|
69183
69565
|
var GroupFileStore = class {
|
|
69184
69566
|
dataDir;
|
|
@@ -69189,11 +69571,11 @@ var GroupFileStore = class {
|
|
|
69189
69571
|
this.logger = opts.logger;
|
|
69190
69572
|
}
|
|
69191
69573
|
rootForScope(scope) {
|
|
69192
|
-
return
|
|
69574
|
+
return import_node_path56.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
|
|
69193
69575
|
}
|
|
69194
69576
|
/** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
|
|
69195
69577
|
filePath(scope, sessionId) {
|
|
69196
|
-
return
|
|
69578
|
+
return import_node_path56.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
|
|
69197
69579
|
}
|
|
69198
69580
|
cacheKey(scope, sessionId) {
|
|
69199
69581
|
return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
|
|
@@ -69202,7 +69584,7 @@ var GroupFileStore = class {
|
|
|
69202
69584
|
readFile(scope, sessionId) {
|
|
69203
69585
|
const file = this.filePath(scope, sessionId);
|
|
69204
69586
|
try {
|
|
69205
|
-
const raw =
|
|
69587
|
+
const raw = import_node_fs51.default.readFileSync(file, "utf8");
|
|
69206
69588
|
const parsed = JSON.parse(raw);
|
|
69207
69589
|
if (!Array.isArray(parsed)) {
|
|
69208
69590
|
this.logger?.warn("GroupFileStore.readFile: not an array; resetting session entries", {
|
|
@@ -69228,10 +69610,10 @@ var GroupFileStore = class {
|
|
|
69228
69610
|
}
|
|
69229
69611
|
writeFile(scope, sessionId, entries) {
|
|
69230
69612
|
const file = this.filePath(scope, sessionId);
|
|
69231
|
-
|
|
69613
|
+
import_node_fs51.default.mkdirSync(import_node_path56.default.dirname(file), { recursive: true });
|
|
69232
69614
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
69233
|
-
|
|
69234
|
-
|
|
69615
|
+
import_node_fs51.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
|
|
69616
|
+
import_node_fs51.default.renameSync(tmp, file);
|
|
69235
69617
|
}
|
|
69236
69618
|
/** 拉一份当前 session 的清单。读盘 → cache;之后调用复用 cache */
|
|
69237
69619
|
list(scope, sessionId) {
|
|
@@ -69267,7 +69649,7 @@ var GroupFileStore = class {
|
|
|
69267
69649
|
entries[idx] = next;
|
|
69268
69650
|
} else {
|
|
69269
69651
|
next = {
|
|
69270
|
-
id: `gf-${
|
|
69652
|
+
id: `gf-${import_node_crypto18.default.randomBytes(6).toString("base64url")}`,
|
|
69271
69653
|
relPath: input.relPath,
|
|
69272
69654
|
from: input.from,
|
|
69273
69655
|
label: input.label,
|
|
@@ -69323,7 +69705,7 @@ var GroupFileStore = class {
|
|
|
69323
69705
|
*/
|
|
69324
69706
|
deleteSession(scope, sessionId) {
|
|
69325
69707
|
try {
|
|
69326
|
-
|
|
69708
|
+
import_node_fs51.default.unlinkSync(this.filePath(scope, sessionId));
|
|
69327
69709
|
} catch (err) {
|
|
69328
69710
|
if (err?.code !== "ENOENT") throw err;
|
|
69329
69711
|
}
|
|
@@ -69336,7 +69718,7 @@ var GroupFileStore = class {
|
|
|
69336
69718
|
* 不在 persona 目录里(见文件头的路径约定)。没树的 persona 是 noop。
|
|
69337
69719
|
*/
|
|
69338
69720
|
deletePersona(personaId2) {
|
|
69339
|
-
|
|
69721
|
+
import_node_fs51.default.rmSync(import_node_path56.default.join(this.dataDir, "sessions", safeFileName(personaId2)), { recursive: true, force: true });
|
|
69340
69722
|
const prefix = `persona:${personaId2}:`;
|
|
69341
69723
|
for (const key of this.cache.keys()) {
|
|
69342
69724
|
if (key.startsWith(prefix)) this.cache.delete(key);
|
|
@@ -69345,10 +69727,10 @@ var GroupFileStore = class {
|
|
|
69345
69727
|
};
|
|
69346
69728
|
|
|
69347
69729
|
// src/discovery/state-file.ts
|
|
69348
|
-
var
|
|
69349
|
-
var
|
|
69730
|
+
var import_node_fs52 = __toESM(require("fs"), 1);
|
|
69731
|
+
var import_node_path57 = __toESM(require("path"), 1);
|
|
69350
69732
|
function defaultStateFilePath(dataDir) {
|
|
69351
|
-
return
|
|
69733
|
+
return import_node_path57.default.join(dataDir, "state.json");
|
|
69352
69734
|
}
|
|
69353
69735
|
function isPidAlive(pid) {
|
|
69354
69736
|
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
@@ -69370,7 +69752,7 @@ var StateFileManager = class {
|
|
|
69370
69752
|
}
|
|
69371
69753
|
read() {
|
|
69372
69754
|
try {
|
|
69373
|
-
const raw =
|
|
69755
|
+
const raw = import_node_fs52.default.readFileSync(this.file, "utf8");
|
|
69374
69756
|
const parsed = JSON.parse(raw);
|
|
69375
69757
|
return parsed;
|
|
69376
69758
|
} catch {
|
|
@@ -69384,20 +69766,20 @@ var StateFileManager = class {
|
|
|
69384
69766
|
return { status: "stale", existing };
|
|
69385
69767
|
}
|
|
69386
69768
|
write(state) {
|
|
69387
|
-
|
|
69769
|
+
import_node_fs52.default.mkdirSync(import_node_path57.default.dirname(this.file), { recursive: true });
|
|
69388
69770
|
const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
|
|
69389
|
-
|
|
69390
|
-
|
|
69771
|
+
import_node_fs52.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
|
|
69772
|
+
import_node_fs52.default.renameSync(tmp, this.file);
|
|
69391
69773
|
if (process.platform !== "win32") {
|
|
69392
69774
|
try {
|
|
69393
|
-
|
|
69775
|
+
import_node_fs52.default.chmodSync(this.file, 384);
|
|
69394
69776
|
} catch {
|
|
69395
69777
|
}
|
|
69396
69778
|
}
|
|
69397
69779
|
}
|
|
69398
69780
|
delete() {
|
|
69399
69781
|
try {
|
|
69400
|
-
|
|
69782
|
+
import_node_fs52.default.unlinkSync(this.file);
|
|
69401
69783
|
} catch {
|
|
69402
69784
|
}
|
|
69403
69785
|
}
|
|
@@ -69411,14 +69793,14 @@ function readSpawnedByDesktopFromEnv(env = process.env) {
|
|
|
69411
69793
|
}
|
|
69412
69794
|
|
|
69413
69795
|
// src/tunnel/tunnel-manager.ts
|
|
69414
|
-
var
|
|
69415
|
-
var
|
|
69416
|
-
var
|
|
69796
|
+
var import_node_fs56 = __toESM(require("fs"), 1);
|
|
69797
|
+
var import_node_path61 = __toESM(require("path"), 1);
|
|
69798
|
+
var import_node_crypto19 = __toESM(require("crypto"), 1);
|
|
69417
69799
|
var import_node_child_process16 = require("child_process");
|
|
69418
69800
|
|
|
69419
69801
|
// src/tunnel/tunnel-store.ts
|
|
69420
|
-
var
|
|
69421
|
-
var
|
|
69802
|
+
var import_node_fs53 = __toESM(require("fs"), 1);
|
|
69803
|
+
var import_node_path58 = __toESM(require("path"), 1);
|
|
69422
69804
|
var TunnelStore = class {
|
|
69423
69805
|
constructor(filePath) {
|
|
69424
69806
|
this.filePath = filePath;
|
|
@@ -69426,7 +69808,7 @@ var TunnelStore = class {
|
|
|
69426
69808
|
filePath;
|
|
69427
69809
|
async get() {
|
|
69428
69810
|
try {
|
|
69429
|
-
const raw = await
|
|
69811
|
+
const raw = await import_node_fs53.default.promises.readFile(this.filePath, "utf8");
|
|
69430
69812
|
const obj = JSON.parse(raw);
|
|
69431
69813
|
if (!isPersistedTunnel(obj)) return null;
|
|
69432
69814
|
return obj;
|
|
@@ -69437,22 +69819,22 @@ var TunnelStore = class {
|
|
|
69437
69819
|
}
|
|
69438
69820
|
}
|
|
69439
69821
|
async set(v3) {
|
|
69440
|
-
const dir =
|
|
69441
|
-
await
|
|
69822
|
+
const dir = import_node_path58.default.dirname(this.filePath);
|
|
69823
|
+
await import_node_fs53.default.promises.mkdir(dir, { recursive: true });
|
|
69442
69824
|
const data = JSON.stringify(v3, null, 2);
|
|
69443
69825
|
const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
|
|
69444
|
-
await
|
|
69826
|
+
await import_node_fs53.default.promises.writeFile(tmp, data, { mode: 384 });
|
|
69445
69827
|
if (process.platform !== "win32") {
|
|
69446
69828
|
try {
|
|
69447
|
-
await
|
|
69829
|
+
await import_node_fs53.default.promises.chmod(tmp, 384);
|
|
69448
69830
|
} catch {
|
|
69449
69831
|
}
|
|
69450
69832
|
}
|
|
69451
|
-
await
|
|
69833
|
+
await import_node_fs53.default.promises.rename(tmp, this.filePath);
|
|
69452
69834
|
}
|
|
69453
69835
|
async clear() {
|
|
69454
69836
|
try {
|
|
69455
|
-
await
|
|
69837
|
+
await import_node_fs53.default.promises.unlink(this.filePath);
|
|
69456
69838
|
} catch (err) {
|
|
69457
69839
|
const code = err?.code;
|
|
69458
69840
|
if (code !== "ENOENT") throw err;
|
|
@@ -69547,9 +69929,9 @@ function escape2(v3) {
|
|
|
69547
69929
|
}
|
|
69548
69930
|
|
|
69549
69931
|
// src/tunnel/frpc-binary.ts
|
|
69550
|
-
var
|
|
69932
|
+
var import_node_fs54 = __toESM(require("fs"), 1);
|
|
69551
69933
|
var import_node_os21 = __toESM(require("os"), 1);
|
|
69552
|
-
var
|
|
69934
|
+
var import_node_path59 = __toESM(require("path"), 1);
|
|
69553
69935
|
var import_node_child_process14 = require("child_process");
|
|
69554
69936
|
var import_node_stream4 = require("stream");
|
|
69555
69937
|
var import_promises10 = require("stream/promises");
|
|
@@ -69581,20 +69963,20 @@ function frpcDownloadUrl(version2, p3) {
|
|
|
69581
69963
|
}
|
|
69582
69964
|
async function ensureFrpcBinary(opts) {
|
|
69583
69965
|
if (opts.override) {
|
|
69584
|
-
if (!
|
|
69966
|
+
if (!import_node_fs54.default.existsSync(opts.override)) {
|
|
69585
69967
|
throw new Error(`frpc binary not found at override path: ${opts.override}`);
|
|
69586
69968
|
}
|
|
69587
69969
|
return opts.override;
|
|
69588
69970
|
}
|
|
69589
69971
|
const version2 = opts.version ?? FRPC_VERSION;
|
|
69590
69972
|
const platform = opts.platform ?? detectPlatform();
|
|
69591
|
-
const binDir =
|
|
69592
|
-
|
|
69973
|
+
const binDir = import_node_path59.default.join(opts.dataDir, "bin");
|
|
69974
|
+
import_node_fs54.default.mkdirSync(binDir, { recursive: true });
|
|
69593
69975
|
cleanupStaleArtifacts(binDir);
|
|
69594
|
-
const stableBin =
|
|
69595
|
-
if (
|
|
69976
|
+
const stableBin = import_node_path59.default.join(binDir, "frpc");
|
|
69977
|
+
if (import_node_fs54.default.existsSync(stableBin)) return stableBin;
|
|
69596
69978
|
const partialBin = `${stableBin}.partial`;
|
|
69597
|
-
const tarballPath =
|
|
69979
|
+
const tarballPath = import_node_path59.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
|
|
69598
69980
|
try {
|
|
69599
69981
|
const url = frpcDownloadUrl(version2, platform);
|
|
69600
69982
|
await downloadToFile(url, tarballPath, opts.fetchImpl);
|
|
@@ -69603,8 +69985,8 @@ async function ensureFrpcBinary(opts) {
|
|
|
69603
69985
|
} else {
|
|
69604
69986
|
await extractFrpcFromTarball(tarballPath, binDir, version2, platform, partialBin);
|
|
69605
69987
|
}
|
|
69606
|
-
|
|
69607
|
-
|
|
69988
|
+
import_node_fs54.default.chmodSync(partialBin, 493);
|
|
69989
|
+
import_node_fs54.default.renameSync(partialBin, stableBin);
|
|
69608
69990
|
} finally {
|
|
69609
69991
|
safeUnlink(tarballPath);
|
|
69610
69992
|
safeUnlink(partialBin);
|
|
@@ -69614,15 +69996,15 @@ async function ensureFrpcBinary(opts) {
|
|
|
69614
69996
|
function cleanupStaleArtifacts(binDir) {
|
|
69615
69997
|
let entries;
|
|
69616
69998
|
try {
|
|
69617
|
-
entries =
|
|
69999
|
+
entries = import_node_fs54.default.readdirSync(binDir);
|
|
69618
70000
|
} catch {
|
|
69619
70001
|
return;
|
|
69620
70002
|
}
|
|
69621
70003
|
for (const name of entries) {
|
|
69622
70004
|
if (name.endsWith(".partial") || name.startsWith("extract-")) {
|
|
69623
|
-
const full =
|
|
70005
|
+
const full = import_node_path59.default.join(binDir, name);
|
|
69624
70006
|
try {
|
|
69625
|
-
|
|
70007
|
+
import_node_fs54.default.rmSync(full, { recursive: true, force: true });
|
|
69626
70008
|
} catch {
|
|
69627
70009
|
}
|
|
69628
70010
|
}
|
|
@@ -69630,7 +70012,7 @@ function cleanupStaleArtifacts(binDir) {
|
|
|
69630
70012
|
}
|
|
69631
70013
|
function safeUnlink(p3) {
|
|
69632
70014
|
try {
|
|
69633
|
-
|
|
70015
|
+
import_node_fs54.default.unlinkSync(p3);
|
|
69634
70016
|
} catch {
|
|
69635
70017
|
}
|
|
69636
70018
|
}
|
|
@@ -69641,13 +70023,13 @@ async function downloadToFile(url, dest, fetchImpl) {
|
|
|
69641
70023
|
if (!res.ok || !res.body) {
|
|
69642
70024
|
throw new Error(`download failed: ${res.status} ${res.statusText}`);
|
|
69643
70025
|
}
|
|
69644
|
-
const out =
|
|
70026
|
+
const out = import_node_fs54.default.createWriteStream(dest);
|
|
69645
70027
|
const nodeStream = import_node_stream4.Readable.fromWeb(res.body);
|
|
69646
70028
|
await (0, import_promises10.pipeline)(nodeStream, out);
|
|
69647
70029
|
}
|
|
69648
70030
|
async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
|
|
69649
|
-
const work =
|
|
69650
|
-
|
|
70031
|
+
const work = import_node_path59.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
|
|
70032
|
+
import_node_fs54.default.mkdirSync(work, { recursive: true });
|
|
69651
70033
|
try {
|
|
69652
70034
|
await new Promise((resolve9, reject) => {
|
|
69653
70035
|
const proc = (0, import_node_child_process14.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
|
|
@@ -69655,32 +70037,32 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
|
|
|
69655
70037
|
proc.on("exit", (code) => code === 0 ? resolve9() : reject(new Error(`tar exited ${code}`)));
|
|
69656
70038
|
});
|
|
69657
70039
|
const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
|
|
69658
|
-
const src =
|
|
69659
|
-
if (!
|
|
70040
|
+
const src = import_node_path59.default.join(work, dirName, "frpc");
|
|
70041
|
+
if (!import_node_fs54.default.existsSync(src)) {
|
|
69660
70042
|
throw new Error(`frpc not found inside tarball at ${src}`);
|
|
69661
70043
|
}
|
|
69662
|
-
|
|
70044
|
+
import_node_fs54.default.copyFileSync(src, destBin);
|
|
69663
70045
|
} finally {
|
|
69664
|
-
|
|
70046
|
+
import_node_fs54.default.rmSync(work, { recursive: true, force: true });
|
|
69665
70047
|
}
|
|
69666
70048
|
}
|
|
69667
70049
|
|
|
69668
70050
|
// src/tunnel/frpc-process.ts
|
|
69669
|
-
var
|
|
69670
|
-
var
|
|
70051
|
+
var import_node_fs55 = __toESM(require("fs"), 1);
|
|
70052
|
+
var import_node_path60 = __toESM(require("path"), 1);
|
|
69671
70053
|
var import_node_child_process15 = require("child_process");
|
|
69672
70054
|
function frpcPidFilePath(dataDir) {
|
|
69673
|
-
return
|
|
70055
|
+
return import_node_path60.default.join(dataDir, "frpc.pid");
|
|
69674
70056
|
}
|
|
69675
70057
|
function writeFrpcPid(dataDir, pid) {
|
|
69676
70058
|
try {
|
|
69677
|
-
|
|
70059
|
+
import_node_fs55.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
|
|
69678
70060
|
} catch {
|
|
69679
70061
|
}
|
|
69680
70062
|
}
|
|
69681
70063
|
function clearFrpcPid(dataDir) {
|
|
69682
70064
|
try {
|
|
69683
|
-
|
|
70065
|
+
import_node_fs55.default.unlinkSync(frpcPidFilePath(dataDir));
|
|
69684
70066
|
} catch {
|
|
69685
70067
|
}
|
|
69686
70068
|
}
|
|
@@ -69696,7 +70078,7 @@ function defaultIsPidAlive(pid) {
|
|
|
69696
70078
|
}
|
|
69697
70079
|
function defaultReadPidFile(file) {
|
|
69698
70080
|
try {
|
|
69699
|
-
return
|
|
70081
|
+
return import_node_fs55.default.readFileSync(file, "utf8");
|
|
69700
70082
|
} catch {
|
|
69701
70083
|
return null;
|
|
69702
70084
|
}
|
|
@@ -69712,7 +70094,7 @@ function defaultSleep2(ms) {
|
|
|
69712
70094
|
}
|
|
69713
70095
|
async function killStaleFrpc(deps) {
|
|
69714
70096
|
const pidFile = frpcPidFilePath(deps.dataDir);
|
|
69715
|
-
const tomlPath =
|
|
70097
|
+
const tomlPath = import_node_path60.default.join(deps.dataDir, "frpc.toml");
|
|
69716
70098
|
const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
|
|
69717
70099
|
const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
|
|
69718
70100
|
const killPid = deps.killPidImpl ?? defaultKillPid;
|
|
@@ -69736,7 +70118,7 @@ async function killStaleFrpc(deps) {
|
|
|
69736
70118
|
}
|
|
69737
70119
|
if (victims.size === 0) {
|
|
69738
70120
|
try {
|
|
69739
|
-
|
|
70121
|
+
import_node_fs55.default.unlinkSync(pidFile);
|
|
69740
70122
|
} catch {
|
|
69741
70123
|
}
|
|
69742
70124
|
return;
|
|
@@ -69747,7 +70129,7 @@ async function killStaleFrpc(deps) {
|
|
|
69747
70129
|
}
|
|
69748
70130
|
await sleep2(deps.reapWaitMs ?? 300);
|
|
69749
70131
|
try {
|
|
69750
|
-
|
|
70132
|
+
import_node_fs55.default.unlinkSync(pidFile);
|
|
69751
70133
|
} catch {
|
|
69752
70134
|
}
|
|
69753
70135
|
}
|
|
@@ -69784,7 +70166,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
|
69784
70166
|
var TunnelManager = class {
|
|
69785
70167
|
constructor(deps) {
|
|
69786
70168
|
this.deps = deps;
|
|
69787
|
-
this.store = deps.store ?? new TunnelStore(
|
|
70169
|
+
this.store = deps.store ?? new TunnelStore(import_node_path61.default.join(deps.dataDir, "tunnel.json"));
|
|
69788
70170
|
this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
|
|
69789
70171
|
this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
|
|
69790
70172
|
}
|
|
@@ -69911,8 +70293,8 @@ var TunnelManager = class {
|
|
|
69911
70293
|
dataDir: this.deps.dataDir,
|
|
69912
70294
|
override: this.deps.frpcBinaryOverride ?? void 0
|
|
69913
70295
|
});
|
|
69914
|
-
const tomlPath =
|
|
69915
|
-
const proxyName = `clawd-${t2.subdomain}-${localPort}-${
|
|
70296
|
+
const tomlPath = import_node_path61.default.join(this.deps.dataDir, "frpc.toml");
|
|
70297
|
+
const proxyName = `clawd-${t2.subdomain}-${localPort}-${import_node_crypto19.default.randomBytes(3).toString("hex")}`;
|
|
69916
70298
|
const toml = buildFrpcToml({
|
|
69917
70299
|
serverAddr: t2.frpsHost,
|
|
69918
70300
|
serverPort: t2.frpsPort,
|
|
@@ -69922,14 +70304,14 @@ var TunnelManager = class {
|
|
|
69922
70304
|
localPort,
|
|
69923
70305
|
logLevel: "info"
|
|
69924
70306
|
});
|
|
69925
|
-
await
|
|
70307
|
+
await import_node_fs56.default.promises.writeFile(tomlPath, toml, { mode: 384 });
|
|
69926
70308
|
const proc = (this.deps.spawnImpl ?? import_node_child_process16.spawn)(frpcBin, ["-c", tomlPath], {
|
|
69927
70309
|
stdio: ["ignore", "pipe", "pipe"]
|
|
69928
70310
|
});
|
|
69929
|
-
const logDir =
|
|
69930
|
-
|
|
69931
|
-
const logFilePath =
|
|
69932
|
-
const logStream =
|
|
70311
|
+
const logDir = import_node_path61.default.join(this.deps.dataDir, "log");
|
|
70312
|
+
import_node_fs56.default.mkdirSync(logDir, { recursive: true });
|
|
70313
|
+
const logFilePath = import_node_path61.default.join(logDir, "frpc.log");
|
|
70314
|
+
const logStream = import_node_fs56.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
|
|
69933
70315
|
logStream.on("error", () => {
|
|
69934
70316
|
});
|
|
69935
70317
|
const tee = (chunk) => {
|
|
@@ -70012,27 +70394,27 @@ async function waitForFrpcReady(proc, timeoutMs) {
|
|
|
70012
70394
|
|
|
70013
70395
|
// src/tunnel/device-key.ts
|
|
70014
70396
|
var import_node_os22 = __toESM(require("os"), 1);
|
|
70015
|
-
var
|
|
70016
|
-
var
|
|
70397
|
+
var import_node_path62 = __toESM(require("path"), 1);
|
|
70398
|
+
var import_node_crypto20 = __toESM(require("crypto"), 1);
|
|
70017
70399
|
var DERIVE_SALT = "clawd-tunnel-device-v1";
|
|
70018
70400
|
function deriveStableDeviceKey(opts = {}) {
|
|
70019
70401
|
const hostname = opts.hostname ?? import_node_os22.default.hostname();
|
|
70020
70402
|
const uid = opts.uid ?? (typeof import_node_os22.default.userInfo === "function" ? import_node_os22.default.userInfo().uid : 0);
|
|
70021
70403
|
const home = opts.home ?? import_node_os22.default.homedir();
|
|
70022
|
-
const defaultDataDir =
|
|
70023
|
-
const normalizedDataDir = opts.dataDir ?
|
|
70404
|
+
const defaultDataDir = import_node_path62.default.resolve(import_node_path62.default.join(home, ".clawd"));
|
|
70405
|
+
const normalizedDataDir = opts.dataDir ? import_node_path62.default.resolve(opts.dataDir) : null;
|
|
70024
70406
|
const isDefaultDir = normalizedDataDir == null || normalizedDataDir === defaultDataDir;
|
|
70025
70407
|
const input = isDefaultDir ? `${hostname}::${uid}` : `${hostname}::${uid}::${normalizedDataDir}`;
|
|
70026
|
-
return
|
|
70408
|
+
return import_node_crypto20.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
|
|
70027
70409
|
}
|
|
70028
70410
|
|
|
70029
70411
|
// src/auth-store.ts
|
|
70030
|
-
var
|
|
70031
|
-
var
|
|
70032
|
-
var
|
|
70412
|
+
var import_node_fs57 = __toESM(require("fs"), 1);
|
|
70413
|
+
var import_node_path63 = __toESM(require("path"), 1);
|
|
70414
|
+
var import_node_crypto21 = __toESM(require("crypto"), 1);
|
|
70033
70415
|
var AUTH_FILE_NAME = "auth.json";
|
|
70034
70416
|
function authFilePath(dataDir) {
|
|
70035
|
-
return
|
|
70417
|
+
return import_node_path63.default.join(dataDir, AUTH_FILE_NAME);
|
|
70036
70418
|
}
|
|
70037
70419
|
function loadOrCreateAuthFile(opts) {
|
|
70038
70420
|
const file = authFilePath(opts.dataDir);
|
|
@@ -70066,14 +70448,14 @@ function loadOrCreateTunnelDeviceKey(opts) {
|
|
|
70066
70448
|
return tunnelDeviceKey;
|
|
70067
70449
|
}
|
|
70068
70450
|
function defaultGenerateToken() {
|
|
70069
|
-
return
|
|
70451
|
+
return import_node_crypto21.default.randomBytes(32).toString("base64url");
|
|
70070
70452
|
}
|
|
70071
70453
|
function defaultGenerateOwnerPrincipalId() {
|
|
70072
|
-
return `owner-${
|
|
70454
|
+
return `owner-${import_node_crypto21.default.randomUUID()}`;
|
|
70073
70455
|
}
|
|
70074
70456
|
function readAuthFile(file) {
|
|
70075
70457
|
try {
|
|
70076
|
-
const raw =
|
|
70458
|
+
const raw = import_node_fs57.default.readFileSync(file, "utf8");
|
|
70077
70459
|
const parsed = JSON.parse(raw);
|
|
70078
70460
|
if (typeof parsed?.token !== "string" || parsed.token.length === 0) {
|
|
70079
70461
|
return null;
|
|
@@ -70094,26 +70476,26 @@ function readAuthFile(file) {
|
|
|
70094
70476
|
}
|
|
70095
70477
|
}
|
|
70096
70478
|
function writeAuthFile(file, content) {
|
|
70097
|
-
|
|
70098
|
-
|
|
70479
|
+
import_node_fs57.default.mkdirSync(import_node_path63.default.dirname(file), { recursive: true });
|
|
70480
|
+
import_node_fs57.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
|
|
70099
70481
|
try {
|
|
70100
|
-
|
|
70482
|
+
import_node_fs57.default.chmodSync(file, 384);
|
|
70101
70483
|
} catch {
|
|
70102
70484
|
}
|
|
70103
70485
|
}
|
|
70104
70486
|
|
|
70105
70487
|
// src/owner-profile.ts
|
|
70106
|
-
var
|
|
70488
|
+
var import_node_fs58 = __toESM(require("fs"), 1);
|
|
70107
70489
|
var import_node_os23 = __toESM(require("os"), 1);
|
|
70108
|
-
var
|
|
70490
|
+
var import_node_path64 = __toESM(require("path"), 1);
|
|
70109
70491
|
var PROFILE_FILENAME = "profile.json";
|
|
70110
70492
|
function profilePath(dataDir) {
|
|
70111
|
-
return
|
|
70493
|
+
return import_node_path64.default.join(dataDir, PROFILE_FILENAME);
|
|
70112
70494
|
}
|
|
70113
70495
|
function loadOwnerProfile(dataDir) {
|
|
70114
70496
|
let raw;
|
|
70115
70497
|
try {
|
|
70116
|
-
raw =
|
|
70498
|
+
raw = import_node_fs58.default.readFileSync(profilePath(dataDir), "utf8");
|
|
70117
70499
|
} catch {
|
|
70118
70500
|
return {};
|
|
70119
70501
|
}
|
|
@@ -70129,7 +70511,7 @@ function loadOwnerProfile(dataDir) {
|
|
|
70129
70511
|
}
|
|
70130
70512
|
function patchOwnerProfile(dataDir, patch) {
|
|
70131
70513
|
const merged = { ...loadOwnerProfile(dataDir), ...patch };
|
|
70132
|
-
|
|
70514
|
+
import_node_fs58.default.writeFileSync(profilePath(dataDir), JSON.stringify(merged, null, 2), { encoding: "utf8", mode: 384 });
|
|
70133
70515
|
return merged;
|
|
70134
70516
|
}
|
|
70135
70517
|
function loadOwnerDisplayName(dataDir) {
|
|
@@ -70145,18 +70527,18 @@ function loadOwnerDisplayName(dataDir) {
|
|
|
70145
70527
|
}
|
|
70146
70528
|
|
|
70147
70529
|
// src/feishu-auth/owner-identity-store.ts
|
|
70148
|
-
var
|
|
70149
|
-
var
|
|
70530
|
+
var import_node_fs59 = __toESM(require("fs"), 1);
|
|
70531
|
+
var import_node_path65 = __toESM(require("path"), 1);
|
|
70150
70532
|
var OWNER_IDENTITY_FILE_NAME = "owner-identity.json";
|
|
70151
70533
|
var OwnerIdentityStore = class {
|
|
70152
70534
|
file;
|
|
70153
70535
|
constructor(dataDir) {
|
|
70154
|
-
this.file =
|
|
70536
|
+
this.file = import_node_path65.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
|
|
70155
70537
|
}
|
|
70156
70538
|
read() {
|
|
70157
70539
|
let raw;
|
|
70158
70540
|
try {
|
|
70159
|
-
raw =
|
|
70541
|
+
raw = import_node_fs59.default.readFileSync(this.file, "utf8");
|
|
70160
70542
|
} catch {
|
|
70161
70543
|
return null;
|
|
70162
70544
|
}
|
|
@@ -70183,16 +70565,16 @@ var OwnerIdentityStore = class {
|
|
|
70183
70565
|
};
|
|
70184
70566
|
}
|
|
70185
70567
|
write(record4) {
|
|
70186
|
-
|
|
70187
|
-
|
|
70568
|
+
import_node_fs59.default.mkdirSync(import_node_path65.default.dirname(this.file), { recursive: true });
|
|
70569
|
+
import_node_fs59.default.writeFileSync(this.file, JSON.stringify(record4, null, 2), { mode: 384 });
|
|
70188
70570
|
try {
|
|
70189
|
-
|
|
70571
|
+
import_node_fs59.default.chmodSync(this.file, 384);
|
|
70190
70572
|
} catch {
|
|
70191
70573
|
}
|
|
70192
70574
|
}
|
|
70193
70575
|
clear() {
|
|
70194
70576
|
try {
|
|
70195
|
-
|
|
70577
|
+
import_node_fs59.default.unlinkSync(this.file);
|
|
70196
70578
|
} catch (err) {
|
|
70197
70579
|
const code = err?.code;
|
|
70198
70580
|
if (code !== "ENOENT") throw err;
|
|
@@ -70201,7 +70583,7 @@ var OwnerIdentityStore = class {
|
|
|
70201
70583
|
};
|
|
70202
70584
|
|
|
70203
70585
|
// src/feishu-auth/login-flow.ts
|
|
70204
|
-
var
|
|
70586
|
+
var import_node_crypto22 = __toESM(require("crypto"), 1);
|
|
70205
70587
|
var STATE_TTL_MS = 5 * 60 * 1e3;
|
|
70206
70588
|
var LoginFlow = class {
|
|
70207
70589
|
constructor(deps) {
|
|
@@ -70210,7 +70592,7 @@ var LoginFlow = class {
|
|
|
70210
70592
|
deps;
|
|
70211
70593
|
pendingStates = /* @__PURE__ */ new Map();
|
|
70212
70594
|
start() {
|
|
70213
|
-
const state =
|
|
70595
|
+
const state = import_node_crypto22.default.randomBytes(16).toString("base64url");
|
|
70214
70596
|
const now = (this.deps.now ?? Date.now)();
|
|
70215
70597
|
this.pendingStates.set(state, now);
|
|
70216
70598
|
this.gcExpired(now);
|
|
@@ -70688,8 +71070,8 @@ function verifyConnectToken(args) {
|
|
|
70688
71070
|
}
|
|
70689
71071
|
|
|
70690
71072
|
// src/feishu-auth/server-key.ts
|
|
70691
|
-
var
|
|
70692
|
-
var
|
|
71073
|
+
var fs76 = __toESM(require("fs"), 1);
|
|
71074
|
+
var path78 = __toESM(require("path"), 1);
|
|
70693
71075
|
var FILE_NAME2 = "server-signing-key.json";
|
|
70694
71076
|
var ServerKeyStore = class {
|
|
70695
71077
|
constructor(dataDir) {
|
|
@@ -70697,12 +71079,12 @@ var ServerKeyStore = class {
|
|
|
70697
71079
|
}
|
|
70698
71080
|
dataDir;
|
|
70699
71081
|
filePath() {
|
|
70700
|
-
return
|
|
71082
|
+
return path78.join(this.dataDir, FILE_NAME2);
|
|
70701
71083
|
}
|
|
70702
71084
|
/** 读缓存的公钥;无缓存 / 损坏 → null(调用方决定是否触发拉取) */
|
|
70703
71085
|
read() {
|
|
70704
71086
|
try {
|
|
70705
|
-
const raw =
|
|
71087
|
+
const raw = fs76.readFileSync(this.filePath(), "utf8");
|
|
70706
71088
|
const parsed = JSON.parse(raw);
|
|
70707
71089
|
if (typeof parsed.publicKeyPem === "string" && parsed.publicKeyPem.includes("PUBLIC KEY")) {
|
|
70708
71090
|
return parsed.publicKeyPem;
|
|
@@ -70717,12 +71099,12 @@ var ServerKeyStore = class {
|
|
|
70717
71099
|
publicKeyPem,
|
|
70718
71100
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
70719
71101
|
};
|
|
70720
|
-
|
|
70721
|
-
|
|
71102
|
+
fs76.mkdirSync(this.dataDir, { recursive: true });
|
|
71103
|
+
fs76.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
|
|
70722
71104
|
}
|
|
70723
71105
|
clear() {
|
|
70724
71106
|
try {
|
|
70725
|
-
|
|
71107
|
+
fs76.unlinkSync(this.filePath());
|
|
70726
71108
|
} catch {
|
|
70727
71109
|
}
|
|
70728
71110
|
}
|
|
@@ -70732,19 +71114,19 @@ var ServerKeyStore = class {
|
|
|
70732
71114
|
init_protocol();
|
|
70733
71115
|
|
|
70734
71116
|
// src/handlers/index.ts
|
|
70735
|
-
var
|
|
71117
|
+
var import_node_path81 = __toESM(require("path"), 1);
|
|
70736
71118
|
|
|
70737
71119
|
// src/handlers/session.ts
|
|
70738
71120
|
init_protocol();
|
|
70739
71121
|
|
|
70740
71122
|
// src/session/fork.ts
|
|
70741
|
-
var
|
|
71123
|
+
var import_node_fs60 = __toESM(require("fs"), 1);
|
|
70742
71124
|
var import_node_os24 = __toESM(require("os"), 1);
|
|
70743
|
-
var
|
|
70744
|
-
var
|
|
71125
|
+
var import_node_path66 = __toESM(require("path"), 1);
|
|
71126
|
+
var import_node_crypto23 = require("crypto");
|
|
70745
71127
|
init_claude_history();
|
|
70746
71128
|
function readJsonlEntries(file) {
|
|
70747
|
-
const raw =
|
|
71129
|
+
const raw = import_node_fs60.default.readFileSync(file, "utf8");
|
|
70748
71130
|
const out = [];
|
|
70749
71131
|
for (const line of raw.split("\n")) {
|
|
70750
71132
|
const t2 = line.trim();
|
|
@@ -70757,19 +71139,19 @@ function readJsonlEntries(file) {
|
|
|
70757
71139
|
return out;
|
|
70758
71140
|
}
|
|
70759
71141
|
function forkSession(input) {
|
|
70760
|
-
const baseDir = input.baseDir ??
|
|
70761
|
-
let projectDir =
|
|
70762
|
-
let sourceFile =
|
|
70763
|
-
if (!
|
|
71142
|
+
const baseDir = input.baseDir ?? import_node_path66.default.join(import_node_os24.default.homedir(), ".claude");
|
|
71143
|
+
let projectDir = import_node_path66.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
|
|
71144
|
+
let sourceFile = import_node_path66.default.join(projectDir, `${input.toolSessionId}.jsonl`);
|
|
71145
|
+
if (!import_node_fs60.default.existsSync(sourceFile)) {
|
|
70764
71146
|
const found = findTranscriptByToolSessionId(
|
|
70765
|
-
|
|
71147
|
+
import_node_path66.default.join(baseDir, "projects"),
|
|
70766
71148
|
input.toolSessionId
|
|
70767
71149
|
);
|
|
70768
71150
|
if (!found) {
|
|
70769
71151
|
throw new Error(`fork: source transcript not found: ${sourceFile}`);
|
|
70770
71152
|
}
|
|
70771
71153
|
sourceFile = found;
|
|
70772
|
-
projectDir =
|
|
71154
|
+
projectDir = import_node_path66.default.dirname(found);
|
|
70773
71155
|
}
|
|
70774
71156
|
const entries = readJsonlEntries(sourceFile);
|
|
70775
71157
|
const mainEntries = entries.filter((e) => e.isSidechain !== true);
|
|
@@ -70778,7 +71160,7 @@ function forkSession(input) {
|
|
|
70778
71160
|
throw new Error(`fork: messageUuid not found in transcript: ${input.messageUuid}`);
|
|
70779
71161
|
}
|
|
70780
71162
|
const sliced = mainEntries.slice(0, targetIdx + 1);
|
|
70781
|
-
const forkedToolSessionId = (0,
|
|
71163
|
+
const forkedToolSessionId = (0, import_node_crypto23.randomUUID)();
|
|
70782
71164
|
let parentUuid = null;
|
|
70783
71165
|
const forkedLines = [];
|
|
70784
71166
|
for (const entry of sliced) {
|
|
@@ -70798,17 +71180,17 @@ function forkSession(input) {
|
|
|
70798
71180
|
}
|
|
70799
71181
|
forkedLines.push(JSON.stringify(forked));
|
|
70800
71182
|
}
|
|
70801
|
-
const outDir = input.targetCwd ?
|
|
70802
|
-
const forkedFilePath =
|
|
70803
|
-
|
|
70804
|
-
|
|
71183
|
+
const outDir = input.targetCwd ? import_node_path66.default.join(baseDir, "projects", cwdToHashDir(input.targetCwd)) : projectDir;
|
|
71184
|
+
const forkedFilePath = import_node_path66.default.join(outDir, `${forkedToolSessionId}.jsonl`);
|
|
71185
|
+
import_node_fs60.default.mkdirSync(outDir, { recursive: true });
|
|
71186
|
+
import_node_fs60.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
|
|
70805
71187
|
return { forkedToolSessionId, forkedFilePath };
|
|
70806
71188
|
}
|
|
70807
71189
|
|
|
70808
71190
|
// src/tools/codex-fork.ts
|
|
70809
71191
|
var import_node_child_process17 = require("child_process");
|
|
70810
|
-
var
|
|
70811
|
-
var
|
|
71192
|
+
var import_node_fs61 = __toESM(require("fs"), 1);
|
|
71193
|
+
var import_node_path67 = __toESM(require("path"), 1);
|
|
70812
71194
|
function openCodexAppServer(home, cwd) {
|
|
70813
71195
|
const proc = (0, import_node_child_process17.spawn)(process.env.CODEX_BIN ?? "codex", ["app-server", "--listen", "stdio://"], {
|
|
70814
71196
|
cwd,
|
|
@@ -70828,7 +71210,7 @@ function openCodexAppServer(home, cwd) {
|
|
|
70828
71210
|
async function forkCodexThread(input, deps = {}) {
|
|
70829
71211
|
const source = locateCodexThread(input.roots, input.sourceThreadId);
|
|
70830
71212
|
if (!source) throw new Error(`codex fork: source thread not found: ${input.sourceThreadId}`);
|
|
70831
|
-
const rollout = parseCodexRollout(
|
|
71213
|
+
const rollout = parseCodexRollout(import_node_fs61.default.readFileSync(source.file, "utf8"));
|
|
70832
71214
|
if (rollout.meta?.threadId.toLowerCase() !== input.sourceThreadId.toLowerCase()) {
|
|
70833
71215
|
throw new Error(`codex fork: source thread metadata does not match ${input.sourceThreadId}`);
|
|
70834
71216
|
}
|
|
@@ -70858,7 +71240,7 @@ async function forkCodexThread(input, deps = {}) {
|
|
|
70858
71240
|
if (typeof forkedToolSessionId !== "string" || !forkedToolSessionId) {
|
|
70859
71241
|
throw new Error("codex fork: app-server returned no thread id");
|
|
70860
71242
|
}
|
|
70861
|
-
const forked = locateCodexThread([
|
|
71243
|
+
const forked = locateCodexThread([import_node_path67.default.join(source.home, "sessions")], forkedToolSessionId);
|
|
70862
71244
|
if (!forked) throw new Error(`codex fork: rollout not found for forked thread ${forkedToolSessionId}`);
|
|
70863
71245
|
return { forkedToolSessionId, forkedFilePath: forked.file };
|
|
70864
71246
|
})()]);
|
|
@@ -70869,19 +71251,19 @@ async function forkCodexThread(input, deps = {}) {
|
|
|
70869
71251
|
}
|
|
70870
71252
|
|
|
70871
71253
|
// src/session/external-scan.ts
|
|
70872
|
-
var
|
|
71254
|
+
var import_node_fs62 = __toESM(require("fs"), 1);
|
|
70873
71255
|
var import_promises11 = __toESM(require("fs/promises"), 1);
|
|
70874
71256
|
var import_node_os25 = __toESM(require("os"), 1);
|
|
70875
|
-
var
|
|
71257
|
+
var import_node_path68 = __toESM(require("path"), 1);
|
|
70876
71258
|
var import_node_module = require("module");
|
|
70877
71259
|
var import_node_child_process18 = require("child_process");
|
|
70878
71260
|
var import_meta7 = {};
|
|
70879
71261
|
function defaultRoots() {
|
|
70880
71262
|
const home = import_node_os25.default.homedir();
|
|
70881
71263
|
return {
|
|
70882
|
-
claudeProjectsDir:
|
|
70883
|
-
codexDir:
|
|
70884
|
-
clawdDir:
|
|
71264
|
+
claudeProjectsDir: import_node_path68.default.join(home, ".claude", "projects"),
|
|
71265
|
+
codexDir: import_node_path68.default.join(home, ".codex"),
|
|
71266
|
+
clawdDir: import_node_path68.default.join(home, ".clawd")
|
|
70885
71267
|
};
|
|
70886
71268
|
}
|
|
70887
71269
|
function width(s2) {
|
|
@@ -70932,7 +71314,7 @@ function userText(msg) {
|
|
|
70932
71314
|
}
|
|
70933
71315
|
function isDir2(p3) {
|
|
70934
71316
|
try {
|
|
70935
|
-
return
|
|
71317
|
+
return import_node_fs62.default.statSync(p3).isDirectory();
|
|
70936
71318
|
} catch {
|
|
70937
71319
|
return false;
|
|
70938
71320
|
}
|
|
@@ -70941,7 +71323,7 @@ async function scanClaude(roots) {
|
|
|
70941
71323
|
const out = [];
|
|
70942
71324
|
let dirs;
|
|
70943
71325
|
try {
|
|
70944
|
-
dirs =
|
|
71326
|
+
dirs = import_node_fs62.default.readdirSync(roots.claudeProjectsDir, { withFileTypes: true });
|
|
70945
71327
|
} catch {
|
|
70946
71328
|
return out;
|
|
70947
71329
|
}
|
|
@@ -70949,16 +71331,16 @@ async function scanClaude(roots) {
|
|
|
70949
71331
|
if (!d2.isDirectory()) continue;
|
|
70950
71332
|
let files;
|
|
70951
71333
|
try {
|
|
70952
|
-
files =
|
|
71334
|
+
files = import_node_fs62.default.readdirSync(import_node_path68.default.join(roots.claudeProjectsDir, d2.name));
|
|
70953
71335
|
} catch {
|
|
70954
71336
|
continue;
|
|
70955
71337
|
}
|
|
70956
71338
|
for (const name of files) {
|
|
70957
71339
|
if (!name.endsWith(".jsonl")) continue;
|
|
70958
|
-
const file =
|
|
71340
|
+
const file = import_node_path68.default.join(roots.claudeProjectsDir, d2.name, name);
|
|
70959
71341
|
let st2;
|
|
70960
71342
|
try {
|
|
70961
|
-
st2 =
|
|
71343
|
+
st2 = import_node_fs62.default.statSync(file);
|
|
70962
71344
|
} catch {
|
|
70963
71345
|
continue;
|
|
70964
71346
|
}
|
|
@@ -71011,7 +71393,7 @@ async function scanClaude(roots) {
|
|
|
71011
71393
|
return out;
|
|
71012
71394
|
}
|
|
71013
71395
|
async function countCodexTurns(rolloutPath) {
|
|
71014
|
-
if (!rolloutPath || !
|
|
71396
|
+
if (!rolloutPath || !import_node_fs62.default.existsSync(rolloutPath)) return { turns: 0, first: "" };
|
|
71015
71397
|
let turns = 0;
|
|
71016
71398
|
let first = "";
|
|
71017
71399
|
for await (const rec6 of jsonLines(rolloutPath)) {
|
|
@@ -71085,7 +71467,7 @@ async function codexFromRows(rows) {
|
|
|
71085
71467
|
async function scanCodex(roots) {
|
|
71086
71468
|
let dbs = [];
|
|
71087
71469
|
try {
|
|
71088
|
-
dbs =
|
|
71470
|
+
dbs = import_node_fs62.default.readdirSync(roots.codexDir).filter((n2) => /^state_.*\.sqlite$/.test(n2)).sort().map((n2) => import_node_path68.default.join(roots.codexDir, n2));
|
|
71089
71471
|
} catch {
|
|
71090
71472
|
}
|
|
71091
71473
|
if (!dbs.length) return [];
|
|
@@ -71094,14 +71476,14 @@ async function scanCodex(roots) {
|
|
|
71094
71476
|
}
|
|
71095
71477
|
async function scanExternalSessions(rootsIn) {
|
|
71096
71478
|
const roots = { ...defaultRoots(), ...rootsIn };
|
|
71097
|
-
const personaRoot =
|
|
71479
|
+
const personaRoot = import_node_path68.default.join(roots.clawdDir, "personas");
|
|
71098
71480
|
const all = [...await scanClaude(roots), ...await scanCodex(roots)];
|
|
71099
71481
|
const out = [];
|
|
71100
71482
|
for (const c2 of all) {
|
|
71101
71483
|
if (c2.skip) continue;
|
|
71102
71484
|
if (c2.turns < 1) continue;
|
|
71103
71485
|
if (!c2.cwd || !isDir2(c2.cwd)) continue;
|
|
71104
|
-
if (c2.cwd === roots.clawdDir || c2.cwd === personaRoot || c2.cwd.startsWith(personaRoot +
|
|
71486
|
+
if (c2.cwd === roots.clawdDir || c2.cwd === personaRoot || c2.cwd.startsWith(personaRoot + import_node_path68.default.sep) || c2.cwd.startsWith(roots.clawdDir + import_node_path68.default.sep)) {
|
|
71105
71487
|
continue;
|
|
71106
71488
|
}
|
|
71107
71489
|
out.push({
|
|
@@ -71118,13 +71500,13 @@ async function scanExternalSessions(rootsIn) {
|
|
|
71118
71500
|
}
|
|
71119
71501
|
|
|
71120
71502
|
// src/session/import-ledger.ts
|
|
71121
|
-
var
|
|
71122
|
-
var
|
|
71503
|
+
var import_node_fs63 = __toESM(require("fs"), 1);
|
|
71504
|
+
var import_node_path69 = __toESM(require("path"), 1);
|
|
71123
71505
|
var LEDGER_FILENAME = "session-import-ledger.json";
|
|
71124
71506
|
function readImportLedger(dataDir) {
|
|
71125
71507
|
try {
|
|
71126
71508
|
const parsed = JSON.parse(
|
|
71127
|
-
|
|
71509
|
+
import_node_fs63.default.readFileSync(import_node_path69.default.join(dataDir, LEDGER_FILENAME), "utf8")
|
|
71128
71510
|
);
|
|
71129
71511
|
return Array.isArray(parsed) ? parsed : [];
|
|
71130
71512
|
} catch {
|
|
@@ -71132,15 +71514,15 @@ function readImportLedger(dataDir) {
|
|
|
71132
71514
|
}
|
|
71133
71515
|
}
|
|
71134
71516
|
function appendImportLedger(dataDir, entry) {
|
|
71135
|
-
const file =
|
|
71517
|
+
const file = import_node_path69.default.join(dataDir, LEDGER_FILENAME);
|
|
71136
71518
|
const entries = readImportLedger(dataDir);
|
|
71137
71519
|
entries.push(entry);
|
|
71138
|
-
|
|
71520
|
+
import_node_fs63.default.writeFileSync(file, JSON.stringify(entries, null, 2), { encoding: "utf8", mode: 384 });
|
|
71139
71521
|
}
|
|
71140
71522
|
|
|
71141
71523
|
// src/handlers/session.ts
|
|
71142
71524
|
init_protocol();
|
|
71143
|
-
var
|
|
71525
|
+
var import_node_path70 = __toESM(require("path"), 1);
|
|
71144
71526
|
function canReadSearchHit(ctx, file) {
|
|
71145
71527
|
if (!ctx || ctx.principal.kind === "owner") return true;
|
|
71146
71528
|
return canAccessPersona(ctx.grants, file.ownerPersonaId, "read") && file.creatorPrincipalId === ctx.principal.id;
|
|
@@ -71316,7 +71698,7 @@ function buildSessionHandlers(deps) {
|
|
|
71316
71698
|
const del = async (frame, _client, ctx) => {
|
|
71317
71699
|
const args = SessionIdArgs.parse(frame);
|
|
71318
71700
|
ensureSessionAccess(ctx, args.sessionId, "send");
|
|
71319
|
-
const { broadcast } = manager.
|
|
71701
|
+
const { broadcast } = await manager.deleteWithCloudCancel(args);
|
|
71320
71702
|
return {
|
|
71321
71703
|
response: { type: "session:deleted", sessionId: args.sessionId },
|
|
71322
71704
|
broadcast
|
|
@@ -71421,7 +71803,7 @@ ${attribution}` } : args;
|
|
|
71421
71803
|
`principal guest:${ctx.principal.id} cannot fork tool session ${args.toolSessionId}`
|
|
71422
71804
|
);
|
|
71423
71805
|
}
|
|
71424
|
-
if (source?.tool === "codex" && args.targetCwd &&
|
|
71806
|
+
if (source?.tool === "codex" && args.targetCwd && import_node_path70.default.resolve(args.targetCwd) !== import_node_path70.default.resolve(source.cwd)) {
|
|
71425
71807
|
throw new ClawdError(ERROR_CODES.FORBIDDEN, "fork: guest targetCwd must match source cwd");
|
|
71426
71808
|
}
|
|
71427
71809
|
}
|
|
@@ -71460,7 +71842,7 @@ ${attribution}` } : args;
|
|
|
71460
71842
|
const args = SessionIdArgs.parse(frame);
|
|
71461
71843
|
ensureSessionAccess(ctx, args.sessionId, "send");
|
|
71462
71844
|
observer.stop(args.sessionId);
|
|
71463
|
-
const { response, broadcast } = manager.
|
|
71845
|
+
const { response, broadcast } = await manager.newSessionWithCloudCancel(args);
|
|
71464
71846
|
return { response: { type: "session:info", ...response }, broadcast };
|
|
71465
71847
|
};
|
|
71466
71848
|
const resume = async (frame, _client, ctx) => {
|
|
@@ -71698,7 +72080,7 @@ function buildPermissionHandlers(deps) {
|
|
|
71698
72080
|
}
|
|
71699
72081
|
|
|
71700
72082
|
// src/handlers/history.ts
|
|
71701
|
-
var
|
|
72083
|
+
var path85 = __toESM(require("path"), 1);
|
|
71702
72084
|
init_protocol();
|
|
71703
72085
|
|
|
71704
72086
|
// src/session/recent-dirs.ts
|
|
@@ -71716,7 +72098,7 @@ function listRecentDirs(store, limit = 50) {
|
|
|
71716
72098
|
}
|
|
71717
72099
|
|
|
71718
72100
|
// src/permission/persona-paths.ts
|
|
71719
|
-
var
|
|
72101
|
+
var path84 = __toESM(require("path"), 1);
|
|
71720
72102
|
function getAllowedPersonaIds(grants, action) {
|
|
71721
72103
|
const ids = /* @__PURE__ */ new Set();
|
|
71722
72104
|
for (const g3 of grants) {
|
|
@@ -71729,42 +72111,42 @@ function getAllowedPersonaIds(grants, action) {
|
|
|
71729
72111
|
return ids;
|
|
71730
72112
|
}
|
|
71731
72113
|
function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
|
|
71732
|
-
const target =
|
|
72114
|
+
const target = path84.resolve(absPath);
|
|
71733
72115
|
if (userWorkDir) {
|
|
71734
|
-
const u2 =
|
|
71735
|
-
const usep = u2.endsWith(
|
|
72116
|
+
const u2 = path84.resolve(userWorkDir);
|
|
72117
|
+
const usep = u2.endsWith(path84.sep) ? "" : path84.sep;
|
|
71736
72118
|
if (target === u2 || target.startsWith(u2 + usep)) return true;
|
|
71737
72119
|
}
|
|
71738
|
-
const root =
|
|
71739
|
-
const sep4 = root.endsWith(
|
|
72120
|
+
const root = path84.resolve(personaRoot);
|
|
72121
|
+
const sep4 = root.endsWith(path84.sep) ? "" : path84.sep;
|
|
71740
72122
|
if (!target.startsWith(root + sep4)) return false;
|
|
71741
|
-
const rel =
|
|
72123
|
+
const rel = path84.relative(root, target);
|
|
71742
72124
|
if (!rel || rel.startsWith("..")) return false;
|
|
71743
|
-
const personaId2 = rel.split(
|
|
72125
|
+
const personaId2 = rel.split(path84.sep)[0];
|
|
71744
72126
|
if (!personaId2) return false;
|
|
71745
72127
|
const allowed = getAllowedPersonaIds(grants, action);
|
|
71746
72128
|
if (allowed === "*") return true;
|
|
71747
72129
|
return allowed.has(personaId2);
|
|
71748
72130
|
}
|
|
71749
72131
|
function personaIdFromPath(absPath, personaRoot) {
|
|
71750
|
-
const root =
|
|
71751
|
-
const target =
|
|
71752
|
-
const sep4 = root.endsWith(
|
|
72132
|
+
const root = path84.resolve(personaRoot);
|
|
72133
|
+
const target = path84.resolve(absPath);
|
|
72134
|
+
const sep4 = root.endsWith(path84.sep) ? "" : path84.sep;
|
|
71753
72135
|
if (!target.startsWith(root + sep4)) return null;
|
|
71754
|
-
const rel =
|
|
72136
|
+
const rel = path84.relative(root, target);
|
|
71755
72137
|
if (!rel || rel.startsWith("..")) return null;
|
|
71756
|
-
const id = rel.split(
|
|
72138
|
+
const id = rel.split(path84.sep)[0];
|
|
71757
72139
|
return id || null;
|
|
71758
72140
|
}
|
|
71759
72141
|
function isPathWithin(dir, absPath) {
|
|
71760
|
-
const d2 =
|
|
71761
|
-
const t2 =
|
|
71762
|
-
const sep4 = d2.endsWith(
|
|
72142
|
+
const d2 = path84.resolve(dir);
|
|
72143
|
+
const t2 = path84.resolve(absPath);
|
|
72144
|
+
const sep4 = d2.endsWith(path84.sep) ? "" : path84.sep;
|
|
71763
72145
|
return t2 === d2 || t2.startsWith(d2 + sep4);
|
|
71764
72146
|
}
|
|
71765
72147
|
function isPathInGuestBoundary(personaRoot, personaId2, userWorkDir, absPath) {
|
|
71766
72148
|
if (userWorkDir && isPathWithin(userWorkDir, absPath)) return true;
|
|
71767
|
-
return personaIdFromPath(
|
|
72149
|
+
return personaIdFromPath(path84.resolve(absPath), personaRoot) === personaId2;
|
|
71768
72150
|
}
|
|
71769
72151
|
|
|
71770
72152
|
// src/handlers/history.ts
|
|
@@ -71818,7 +72200,7 @@ function buildHistoryHandlers(deps) {
|
|
|
71818
72200
|
if (!pid) return false;
|
|
71819
72201
|
return isGuestPathAllowed(
|
|
71820
72202
|
ctx.grants,
|
|
71821
|
-
|
|
72203
|
+
path85.join(personaRoot, pid),
|
|
71822
72204
|
personaRoot,
|
|
71823
72205
|
"read",
|
|
71824
72206
|
userWorkDir
|
|
@@ -71830,7 +72212,7 @@ function buildHistoryHandlers(deps) {
|
|
|
71830
72212
|
};
|
|
71831
72213
|
const list = async (frame, _client, ctx) => {
|
|
71832
72214
|
const args = HistoryListArgs.parse(frame);
|
|
71833
|
-
assertGuestPath(ctx,
|
|
72215
|
+
assertGuestPath(ctx, path85.resolve(args.projectPath), personaRoot, "history:list", usersRoot);
|
|
71834
72216
|
const sessions = await history.listSessions(args);
|
|
71835
72217
|
return { response: { type: "history:list", sessions } };
|
|
71836
72218
|
};
|
|
@@ -71905,14 +72287,14 @@ function buildHistoryHandlers(deps) {
|
|
|
71905
72287
|
};
|
|
71906
72288
|
const subagents = async (frame, _client, ctx) => {
|
|
71907
72289
|
const args = HistorySubagentsArgs.parse(frame);
|
|
71908
|
-
assertGuestPath(ctx,
|
|
72290
|
+
assertGuestPath(ctx, path85.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
|
|
71909
72291
|
assertGuestOwnsToolSession(ctx, args.toolSessionId, "history:subagents");
|
|
71910
72292
|
const subs = await historyReaderForToolSession(args.toolSessionId).listSubagents(args);
|
|
71911
72293
|
return { response: { type: "history:subagents", subagents: subs } };
|
|
71912
72294
|
};
|
|
71913
72295
|
const subagentRead = async (frame, _client, ctx) => {
|
|
71914
72296
|
const args = HistorySubagentReadArgs.parse(frame);
|
|
71915
|
-
assertGuestPath(ctx,
|
|
72297
|
+
assertGuestPath(ctx, path85.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
|
|
71916
72298
|
assertGuestOwnsToolSession(ctx, args.toolSessionId, "history:subagent-read");
|
|
71917
72299
|
const res = await historyReaderForToolSession(args.toolSessionId).readSubagent(args);
|
|
71918
72300
|
return { response: { type: "history:subagent-read", ...res } };
|
|
@@ -71922,7 +72304,7 @@ function buildHistoryHandlers(deps) {
|
|
|
71922
72304
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
71923
72305
|
const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
|
|
71924
72306
|
const filtered = dirs.filter(
|
|
71925
|
-
(d2) => isGuestPathAllowed(ctx.grants,
|
|
72307
|
+
(d2) => isGuestPathAllowed(ctx.grants, path85.resolve(d2.cwd), personaRoot, "read", userWorkDir)
|
|
71926
72308
|
);
|
|
71927
72309
|
return { response: { type: "history:recentDirs", dirs: filtered } };
|
|
71928
72310
|
}
|
|
@@ -71939,17 +72321,17 @@ function buildHistoryHandlers(deps) {
|
|
|
71939
72321
|
}
|
|
71940
72322
|
|
|
71941
72323
|
// src/handlers/projects.ts
|
|
71942
|
-
var
|
|
72324
|
+
var fs81 = __toESM(require("fs"), 1);
|
|
71943
72325
|
var os27 = __toESM(require("os"), 1);
|
|
71944
|
-
var
|
|
72326
|
+
var path86 = __toESM(require("path"), 1);
|
|
71945
72327
|
var import_node_child_process19 = require("child_process");
|
|
71946
72328
|
init_protocol();
|
|
71947
|
-
var DEFAULT_PROJECTS_ROOT =
|
|
72329
|
+
var DEFAULT_PROJECTS_ROOT = path86.join(os27.homedir(), "Documents", "ChatGPT");
|
|
71948
72330
|
function allocateDir(root, name) {
|
|
71949
|
-
let candidate =
|
|
72331
|
+
let candidate = path86.join(root, name);
|
|
71950
72332
|
let n2 = 2;
|
|
71951
|
-
while (
|
|
71952
|
-
candidate =
|
|
72333
|
+
while (fs81.existsSync(candidate)) {
|
|
72334
|
+
candidate = path86.join(root, `${name} ${n2}`);
|
|
71953
72335
|
n2 += 1;
|
|
71954
72336
|
}
|
|
71955
72337
|
return candidate;
|
|
@@ -71977,7 +72359,7 @@ function buildProjectHandlers(deps) {
|
|
|
71977
72359
|
throw new ClawdError(ERROR_CODES.INVALID_CWD, "project:reveal \u4EC5\u652F\u6301 macOS");
|
|
71978
72360
|
}
|
|
71979
72361
|
try {
|
|
71980
|
-
if (!
|
|
72362
|
+
if (!fs81.statSync(args.path).isDirectory()) throw new Error("not dir");
|
|
71981
72363
|
} catch {
|
|
71982
72364
|
throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${args.path}`);
|
|
71983
72365
|
}
|
|
@@ -71993,7 +72375,7 @@ function buildProjectHandlers(deps) {
|
|
|
71993
72375
|
let target;
|
|
71994
72376
|
if (args.path) {
|
|
71995
72377
|
try {
|
|
71996
|
-
if (!
|
|
72378
|
+
if (!fs81.statSync(args.path).isDirectory()) throw new Error("not dir");
|
|
71997
72379
|
} catch {
|
|
71998
72380
|
throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${args.path}`);
|
|
71999
72381
|
}
|
|
@@ -72001,15 +72383,15 @@ function buildProjectHandlers(deps) {
|
|
|
72001
72383
|
} else {
|
|
72002
72384
|
const name = args.name;
|
|
72003
72385
|
try {
|
|
72004
|
-
|
|
72386
|
+
fs81.mkdirSync(root, { recursive: true });
|
|
72005
72387
|
target = allocateDir(root, name);
|
|
72006
|
-
|
|
72388
|
+
fs81.mkdirSync(target);
|
|
72007
72389
|
} catch (err) {
|
|
72008
72390
|
throw new ClawdError(ERROR_CODES.INVALID_CWD, `\u521B\u5EFA\u9879\u76EE\u76EE\u5F55\u5931\u8D25: ${String(err)}`);
|
|
72009
72391
|
}
|
|
72010
72392
|
const git2 = (0, import_node_child_process19.spawnSync)("git", ["init"], { cwd: target, stdio: "ignore" });
|
|
72011
72393
|
if (git2.status !== 0) {
|
|
72012
|
-
|
|
72394
|
+
fs81.rmSync(target, { recursive: true, force: true });
|
|
72013
72395
|
throw new ClawdError(
|
|
72014
72396
|
ERROR_CODES.INVALID_CWD,
|
|
72015
72397
|
`git init \u5931\u8D25\uFF08${git2.error ? String(git2.error) : `exit ${git2.status}`}\uFF09: ${target}`
|
|
@@ -72034,7 +72416,7 @@ function buildProjectHandlers(deps) {
|
|
|
72034
72416
|
}
|
|
72035
72417
|
|
|
72036
72418
|
// src/handlers/workspace.ts
|
|
72037
|
-
var
|
|
72419
|
+
var path87 = __toESM(require("path"), 1);
|
|
72038
72420
|
init_protocol();
|
|
72039
72421
|
var os28 = __toESM(require("os"), 1);
|
|
72040
72422
|
init_protocol();
|
|
@@ -72077,22 +72459,22 @@ function buildWorkspaceHandlers(deps) {
|
|
|
72077
72459
|
const args = WorkspaceListArgs.parse(frame);
|
|
72078
72460
|
const isGuest = ctx?.principal.kind === "guest";
|
|
72079
72461
|
const fallbackCwd = isGuest && personaRoot ? personaRoot : os28.homedir();
|
|
72080
|
-
const resolvedCwd =
|
|
72081
|
-
const target = args.path ?
|
|
72462
|
+
const resolvedCwd = path87.resolve(args.cwd ?? fallbackCwd);
|
|
72463
|
+
const target = args.path ? path87.resolve(resolvedCwd, args.path) : resolvedCwd;
|
|
72082
72464
|
assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
|
|
72083
72465
|
const res = workspace.list({ ...args, cwd: resolvedCwd });
|
|
72084
72466
|
return { response: { type: "workspace:list", ...res } };
|
|
72085
72467
|
};
|
|
72086
72468
|
const read = async (frame, _client, ctx) => {
|
|
72087
72469
|
const args = WorkspaceReadArgs.parse(frame);
|
|
72088
|
-
const target =
|
|
72470
|
+
const target = path87.isAbsolute(args.path) ? path87.resolve(args.path) : path87.resolve(args.cwd, args.path);
|
|
72089
72471
|
assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
|
|
72090
72472
|
const res = workspace.read(args);
|
|
72091
72473
|
return { response: { type: "workspace:read", ...res } };
|
|
72092
72474
|
};
|
|
72093
72475
|
const skillsList = async (frame, _client, ctx) => {
|
|
72094
72476
|
const args = SkillsListArgs.parse(frame);
|
|
72095
|
-
const cwdAbs =
|
|
72477
|
+
const cwdAbs = path87.resolve(args.cwd);
|
|
72096
72478
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
|
|
72097
72479
|
const list2 = await getSkillsForTool(args.tool ?? "claude", cwdAbs);
|
|
72098
72480
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
@@ -72104,7 +72486,7 @@ function buildWorkspaceHandlers(deps) {
|
|
|
72104
72486
|
};
|
|
72105
72487
|
const agentsList = async (frame, _client, ctx) => {
|
|
72106
72488
|
const args = AgentsListArgs.parse(frame);
|
|
72107
|
-
const cwdAbs =
|
|
72489
|
+
const cwdAbs = path87.resolve(args.cwd);
|
|
72108
72490
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
|
|
72109
72491
|
if (isCodexFamily(args.tool) || isPiFamily(args.tool)) {
|
|
72110
72492
|
return { response: { type: "agents:list", agents: [] } };
|
|
@@ -72126,20 +72508,20 @@ function buildWorkspaceHandlers(deps) {
|
|
|
72126
72508
|
}
|
|
72127
72509
|
|
|
72128
72510
|
// src/handlers/git.ts
|
|
72129
|
-
var
|
|
72511
|
+
var path89 = __toESM(require("path"), 1);
|
|
72130
72512
|
init_protocol();
|
|
72131
72513
|
init_protocol();
|
|
72132
72514
|
|
|
72133
72515
|
// src/workspace/git.ts
|
|
72134
72516
|
var import_node_child_process20 = require("child_process");
|
|
72135
|
-
var
|
|
72136
|
-
var
|
|
72517
|
+
var import_node_fs64 = __toESM(require("fs"), 1);
|
|
72518
|
+
var import_node_path71 = __toESM(require("path"), 1);
|
|
72137
72519
|
var import_node_util2 = require("util");
|
|
72138
72520
|
var pexec = (0, import_node_util2.promisify)(import_node_child_process20.execFile);
|
|
72139
72521
|
function normalizePath(p3) {
|
|
72140
|
-
const resolved =
|
|
72522
|
+
const resolved = import_node_path71.default.resolve(p3);
|
|
72141
72523
|
try {
|
|
72142
|
-
return
|
|
72524
|
+
return import_node_fs64.default.realpathSync(resolved);
|
|
72143
72525
|
} catch {
|
|
72144
72526
|
return resolved;
|
|
72145
72527
|
}
|
|
@@ -72213,7 +72595,7 @@ async function listGitBranches(cwd) {
|
|
|
72213
72595
|
function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
|
|
72214
72596
|
if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
|
|
72215
72597
|
const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
|
|
72216
|
-
if (!isGuestPathAllowed(ctx.grants,
|
|
72598
|
+
if (!isGuestPathAllowed(ctx.grants, path89.resolve(cwd), personaRoot, "read", userWorkDir)) {
|
|
72217
72599
|
throw new ClawdError(
|
|
72218
72600
|
ERROR_CODES.UNAUTHORIZED,
|
|
72219
72601
|
`guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
|
|
@@ -72470,12 +72852,12 @@ async function queryCodexAccount(deps = {}) {
|
|
|
72470
72852
|
}
|
|
72471
72853
|
|
|
72472
72854
|
// src/tools/pi-account.ts
|
|
72473
|
-
var
|
|
72474
|
-
var
|
|
72855
|
+
var import_node_fs65 = __toESM(require("fs"), 1);
|
|
72856
|
+
var import_node_path72 = __toESM(require("path"), 1);
|
|
72475
72857
|
function readPiCredentials(agentDir) {
|
|
72476
72858
|
let raw;
|
|
72477
72859
|
try {
|
|
72478
|
-
raw = JSON.parse(
|
|
72860
|
+
raw = JSON.parse(import_node_fs65.default.readFileSync(import_node_path72.default.join(agentDir, "auth.json"), "utf8"));
|
|
72479
72861
|
} catch {
|
|
72480
72862
|
return {};
|
|
72481
72863
|
}
|
|
@@ -73566,21 +73948,21 @@ function computeMethodAccess(args) {
|
|
|
73566
73948
|
}
|
|
73567
73949
|
|
|
73568
73950
|
// src/version.ts
|
|
73569
|
-
var version = "0.2.
|
|
73951
|
+
var version = "0.2.613".length > 0 ? "0.2.613" : "dev";
|
|
73570
73952
|
|
|
73571
73953
|
// src/cli-probe/probe.ts
|
|
73572
|
-
var
|
|
73573
|
-
var
|
|
73954
|
+
var fs84 = __toESM(require("fs"), 1);
|
|
73955
|
+
var path91 = __toESM(require("path"), 1);
|
|
73574
73956
|
var PKG_NAME = "@clawos-dev/clawd";
|
|
73575
73957
|
var BIN_NAME = "clawd";
|
|
73576
73958
|
var MAX_PARENT_HOPS = 5;
|
|
73577
73959
|
function probeGlobalCli(pathEnv) {
|
|
73578
73960
|
if (!pathEnv) return null;
|
|
73579
|
-
for (const dir of pathEnv.split(
|
|
73961
|
+
for (const dir of pathEnv.split(path91.delimiter)) {
|
|
73580
73962
|
if (!dir) continue;
|
|
73581
73963
|
let real;
|
|
73582
73964
|
try {
|
|
73583
|
-
real =
|
|
73965
|
+
real = fs84.realpathSync(path91.join(dir, BIN_NAME));
|
|
73584
73966
|
} catch {
|
|
73585
73967
|
continue;
|
|
73586
73968
|
}
|
|
@@ -73590,15 +73972,15 @@ function probeGlobalCli(pathEnv) {
|
|
|
73590
73972
|
return null;
|
|
73591
73973
|
}
|
|
73592
73974
|
function readOwnPackageVersion(entryPath) {
|
|
73593
|
-
let dir =
|
|
73975
|
+
let dir = path91.dirname(entryPath);
|
|
73594
73976
|
for (let i2 = 0; i2 < MAX_PARENT_HOPS; i2++) {
|
|
73595
73977
|
try {
|
|
73596
|
-
const raw =
|
|
73978
|
+
const raw = fs84.readFileSync(path91.join(dir, "package.json"), "utf8");
|
|
73597
73979
|
const pkg = JSON.parse(raw);
|
|
73598
73980
|
if (pkg.name !== PKG_NAME) return null;
|
|
73599
73981
|
return typeof pkg.version === "string" && pkg.version ? pkg.version : null;
|
|
73600
73982
|
} catch {
|
|
73601
|
-
const parent =
|
|
73983
|
+
const parent = path91.dirname(dir);
|
|
73602
73984
|
if (parent === dir) return null;
|
|
73603
73985
|
dir = parent;
|
|
73604
73986
|
}
|
|
@@ -73774,7 +74156,7 @@ function buildPersonaHandlers(deps) {
|
|
|
73774
74156
|
}
|
|
73775
74157
|
|
|
73776
74158
|
// src/handlers/attachment.ts
|
|
73777
|
-
var
|
|
74159
|
+
var import_node_path73 = __toESM(require("path"), 1);
|
|
73778
74160
|
init_protocol();
|
|
73779
74161
|
init_protocol();
|
|
73780
74162
|
function assertGuestAttachmentPath(ctx, absPath, personaRoot, method, usersRoot) {
|
|
@@ -73853,12 +74235,12 @@ function buildAttachmentHandlers(deps) {
|
|
|
73853
74235
|
`session ${args.sessionId} scope unresolved`
|
|
73854
74236
|
);
|
|
73855
74237
|
}
|
|
73856
|
-
const cwdAbs =
|
|
73857
|
-
const candidateAbs =
|
|
74238
|
+
const cwdAbs = import_node_path73.default.resolve(sessionFile.cwd);
|
|
74239
|
+
const candidateAbs = import_node_path73.default.isAbsolute(args.relPath) ? import_node_path73.default.resolve(args.relPath) : import_node_path73.default.resolve(cwdAbs, args.relPath);
|
|
73858
74240
|
guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.signUrl", "group-acl");
|
|
73859
74241
|
const entries = deps.groupFileStore.list(scope, args.sessionId);
|
|
73860
74242
|
const entry = entries.find((e) => {
|
|
73861
|
-
const storedAbs =
|
|
74243
|
+
const storedAbs = import_node_path73.default.isAbsolute(e.relPath) ? import_node_path73.default.resolve(e.relPath) : import_node_path73.default.resolve(cwdAbs, e.relPath);
|
|
73862
74244
|
return storedAbs === candidateAbs && !e.stale;
|
|
73863
74245
|
});
|
|
73864
74246
|
if (!entry) {
|
|
@@ -73882,7 +74264,7 @@ function buildAttachmentHandlers(deps) {
|
|
|
73882
74264
|
if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
|
|
73883
74265
|
const f2 = deps.sessionStore.read(sessionId);
|
|
73884
74266
|
if (!f2) return;
|
|
73885
|
-
assertGuestAttachmentPath(ctx,
|
|
74267
|
+
assertGuestAttachmentPath(ctx, import_node_path73.default.resolve(f2.cwd), deps.personaRoot, method, deps.usersRoot);
|
|
73886
74268
|
}
|
|
73887
74269
|
const groupAdd = async (frame, _client, ctx) => {
|
|
73888
74270
|
if (!deps.groupFileStore || !deps.getSessionScope) {
|
|
@@ -73897,8 +74279,8 @@ function buildAttachmentHandlers(deps) {
|
|
|
73897
74279
|
if (!scope) {
|
|
73898
74280
|
throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, `session ${args.sessionId} not found`);
|
|
73899
74281
|
}
|
|
73900
|
-
const cwdAbs =
|
|
73901
|
-
const candidateAbs =
|
|
74282
|
+
const cwdAbs = import_node_path73.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
|
|
74283
|
+
const candidateAbs = import_node_path73.default.isAbsolute(args.relPath) ? import_node_path73.default.resolve(args.relPath) : import_node_path73.default.resolve(cwdAbs, args.relPath);
|
|
73902
74284
|
guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.groupAdd", "cwd-subtree");
|
|
73903
74285
|
const from = args.origin === "agent" ? "agent" : ctx?.principal.kind === "owner" ? "owner" : "agent";
|
|
73904
74286
|
const size = 0;
|
|
@@ -73957,19 +74339,19 @@ function buildAttachmentHandlers(deps) {
|
|
|
73957
74339
|
|
|
73958
74340
|
// src/handlers/extension.ts
|
|
73959
74341
|
var import_promises15 = __toESM(require("fs/promises"), 1);
|
|
73960
|
-
var
|
|
74342
|
+
var import_node_path78 = __toESM(require("path"), 1);
|
|
73961
74343
|
init_protocol();
|
|
73962
74344
|
|
|
73963
74345
|
// src/extension/bundle-zip.ts
|
|
73964
74346
|
var import_promises12 = __toESM(require("fs/promises"), 1);
|
|
73965
|
-
var
|
|
73966
|
-
var
|
|
74347
|
+
var import_node_path74 = __toESM(require("path"), 1);
|
|
74348
|
+
var import_node_crypto24 = __toESM(require("crypto"), 1);
|
|
73967
74349
|
var import_jszip2 = __toESM(require_lib3(), 1);
|
|
73968
74350
|
async function bundleExtensionDir(dir) {
|
|
73969
74351
|
const entries = await listFilesSorted(dir);
|
|
73970
74352
|
const zip = new import_jszip2.default();
|
|
73971
74353
|
for (const rel of entries) {
|
|
73972
|
-
const abs =
|
|
74354
|
+
const abs = import_node_path74.default.join(dir, rel);
|
|
73973
74355
|
const content = await import_promises12.default.readFile(abs);
|
|
73974
74356
|
zip.file(rel, content, { date: FIXED_DATE });
|
|
73975
74357
|
}
|
|
@@ -73978,7 +74360,7 @@ async function bundleExtensionDir(dir) {
|
|
|
73978
74360
|
compression: "DEFLATE",
|
|
73979
74361
|
compressionOptions: { level: 6 }
|
|
73980
74362
|
});
|
|
73981
|
-
const sha256 =
|
|
74363
|
+
const sha256 = import_node_crypto24.default.createHash("sha256").update(buffer).digest("hex");
|
|
73982
74364
|
return { buffer, sha256 };
|
|
73983
74365
|
}
|
|
73984
74366
|
var FIXED_DATE = /* @__PURE__ */ new Date("2020-01-01T00:00:00.000Z");
|
|
@@ -73990,7 +74372,7 @@ async function listFilesSorted(rootDir) {
|
|
|
73990
74372
|
return out;
|
|
73991
74373
|
}
|
|
73992
74374
|
async function walk(absRoot, relPrefix, out) {
|
|
73993
|
-
const dirAbs =
|
|
74375
|
+
const dirAbs = import_node_path74.default.join(absRoot, relPrefix);
|
|
73994
74376
|
const entries = await import_promises12.default.readdir(dirAbs, { withFileTypes: true });
|
|
73995
74377
|
for (const e of entries) {
|
|
73996
74378
|
if (IGNORE_BASENAMES.has(e.name)) continue;
|
|
@@ -74044,25 +74426,25 @@ function computePublishCheck(args) {
|
|
|
74044
74426
|
|
|
74045
74427
|
// src/extension/install-flow.ts
|
|
74046
74428
|
var import_promises13 = __toESM(require("fs/promises"), 1);
|
|
74047
|
-
var
|
|
74429
|
+
var import_node_path76 = __toESM(require("path"), 1);
|
|
74048
74430
|
var import_node_os28 = __toESM(require("os"), 1);
|
|
74049
|
-
var
|
|
74431
|
+
var import_node_crypto25 = __toESM(require("crypto"), 1);
|
|
74050
74432
|
var import_jszip3 = __toESM(require_lib3(), 1);
|
|
74051
74433
|
|
|
74052
74434
|
// src/extension/paths.ts
|
|
74053
74435
|
var import_node_os27 = __toESM(require("os"), 1);
|
|
74054
|
-
var
|
|
74436
|
+
var import_node_path75 = __toESM(require("path"), 1);
|
|
74055
74437
|
function clawdHomeRoot(override) {
|
|
74056
|
-
return override ?? process.env.CLAWD_HOME ??
|
|
74438
|
+
return override ?? process.env.CLAWD_HOME ?? import_node_path75.default.join(import_node_os27.default.homedir(), ".clawd");
|
|
74057
74439
|
}
|
|
74058
74440
|
function extensionsRoot(override) {
|
|
74059
|
-
return
|
|
74441
|
+
return import_node_path75.default.join(clawdHomeRoot(override), "extensions");
|
|
74060
74442
|
}
|
|
74061
74443
|
function publishedChannelsFile(override) {
|
|
74062
|
-
return
|
|
74444
|
+
return import_node_path75.default.join(clawdHomeRoot(override), "extensions-published.json");
|
|
74063
74445
|
}
|
|
74064
74446
|
function bundleCacheRoot(override) {
|
|
74065
|
-
return
|
|
74447
|
+
return import_node_path75.default.join(clawdHomeRoot(override), "extension-bundles");
|
|
74066
74448
|
}
|
|
74067
74449
|
|
|
74068
74450
|
// src/extension/install-flow.ts
|
|
@@ -74075,7 +74457,7 @@ var InstallError = class extends Error {
|
|
|
74075
74457
|
};
|
|
74076
74458
|
async function installFromChannel(args, deps) {
|
|
74077
74459
|
const { channelRef, snapshotHash, bundleZip } = args;
|
|
74078
|
-
const computed =
|
|
74460
|
+
const computed = import_node_crypto25.default.createHash("sha256").update(bundleZip).digest("hex");
|
|
74079
74461
|
if (computed !== snapshotHash) {
|
|
74080
74462
|
throw new InstallError(
|
|
74081
74463
|
"HASH_MISMATCH",
|
|
@@ -74089,7 +74471,7 @@ async function installFromChannel(args, deps) {
|
|
|
74089
74471
|
throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
74090
74472
|
}
|
|
74091
74473
|
for (const name of Object.keys(zip.files)) {
|
|
74092
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
74474
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path76.default.isAbsolute(name)) {
|
|
74093
74475
|
throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
|
|
74094
74476
|
}
|
|
74095
74477
|
}
|
|
@@ -74121,7 +74503,7 @@ async function installFromChannel(args, deps) {
|
|
|
74121
74503
|
);
|
|
74122
74504
|
}
|
|
74123
74505
|
const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
|
|
74124
|
-
const destDir =
|
|
74506
|
+
const destDir = import_node_path76.default.join(deps.extensionsRoot, localExtId);
|
|
74125
74507
|
let destExists = false;
|
|
74126
74508
|
try {
|
|
74127
74509
|
await import_promises13.default.access(destDir);
|
|
@@ -74135,16 +74517,16 @@ async function installFromChannel(args, deps) {
|
|
|
74135
74517
|
);
|
|
74136
74518
|
}
|
|
74137
74519
|
const stage = await import_promises13.default.mkdtemp(
|
|
74138
|
-
|
|
74520
|
+
import_node_path76.default.join(import_node_os28.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
|
|
74139
74521
|
);
|
|
74140
74522
|
try {
|
|
74141
74523
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
74142
|
-
const dest =
|
|
74524
|
+
const dest = import_node_path76.default.join(stage, name);
|
|
74143
74525
|
if (entry.dir) {
|
|
74144
74526
|
await import_promises13.default.mkdir(dest, { recursive: true });
|
|
74145
74527
|
continue;
|
|
74146
74528
|
}
|
|
74147
|
-
await import_promises13.default.mkdir(
|
|
74529
|
+
await import_promises13.default.mkdir(import_node_path76.default.dirname(dest), { recursive: true });
|
|
74148
74530
|
if (name === "manifest.json") {
|
|
74149
74531
|
const rewritten = { ...parsed.data, id: localExtId };
|
|
74150
74532
|
await import_promises13.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
|
|
@@ -74165,9 +74547,9 @@ async function installFromChannel(args, deps) {
|
|
|
74165
74547
|
|
|
74166
74548
|
// src/extension/update-flow.ts
|
|
74167
74549
|
var import_promises14 = __toESM(require("fs/promises"), 1);
|
|
74168
|
-
var
|
|
74550
|
+
var import_node_path77 = __toESM(require("path"), 1);
|
|
74169
74551
|
var import_node_os29 = __toESM(require("os"), 1);
|
|
74170
|
-
var
|
|
74552
|
+
var import_node_crypto26 = __toESM(require("crypto"), 1);
|
|
74171
74553
|
var import_jszip4 = __toESM(require_lib3(), 1);
|
|
74172
74554
|
var UpdateError = class extends Error {
|
|
74173
74555
|
constructor(code, message) {
|
|
@@ -74182,11 +74564,11 @@ async function updateFromChannel(args, deps) {
|
|
|
74182
74564
|
channelRef.extId,
|
|
74183
74565
|
channelRef.ownerPrincipalId
|
|
74184
74566
|
);
|
|
74185
|
-
const liveDir =
|
|
74567
|
+
const liveDir = import_node_path77.default.join(deps.extensionsRoot, localExtId);
|
|
74186
74568
|
const prevDir = `${liveDir}.prev`;
|
|
74187
74569
|
let existingVersion;
|
|
74188
74570
|
try {
|
|
74189
|
-
const raw = await import_promises14.default.readFile(
|
|
74571
|
+
const raw = await import_promises14.default.readFile(import_node_path77.default.join(liveDir, "manifest.json"), "utf8");
|
|
74190
74572
|
const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
|
|
74191
74573
|
if (!parsed2.success) {
|
|
74192
74574
|
throw new UpdateError(
|
|
@@ -74205,7 +74587,7 @@ async function updateFromChannel(args, deps) {
|
|
|
74205
74587
|
if (e instanceof UpdateError) throw e;
|
|
74206
74588
|
throw e;
|
|
74207
74589
|
}
|
|
74208
|
-
const computed =
|
|
74590
|
+
const computed = import_node_crypto26.default.createHash("sha256").update(bundleZip).digest("hex");
|
|
74209
74591
|
if (computed !== snapshotHash) {
|
|
74210
74592
|
throw new UpdateError(
|
|
74211
74593
|
"HASH_MISMATCH",
|
|
@@ -74219,7 +74601,7 @@ async function updateFromChannel(args, deps) {
|
|
|
74219
74601
|
throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
74220
74602
|
}
|
|
74221
74603
|
for (const name of Object.keys(zip.files)) {
|
|
74222
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
74604
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path77.default.isAbsolute(name)) {
|
|
74223
74605
|
throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
|
|
74224
74606
|
}
|
|
74225
74607
|
}
|
|
@@ -74254,16 +74636,16 @@ async function updateFromChannel(args, deps) {
|
|
|
74254
74636
|
await import_promises14.default.rm(prevDir, { recursive: true, force: true });
|
|
74255
74637
|
await import_promises14.default.rename(liveDir, prevDir);
|
|
74256
74638
|
const stage = await import_promises14.default.mkdtemp(
|
|
74257
|
-
|
|
74639
|
+
import_node_path77.default.join(import_node_os29.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
|
|
74258
74640
|
);
|
|
74259
74641
|
try {
|
|
74260
74642
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
74261
|
-
const dest =
|
|
74643
|
+
const dest = import_node_path77.default.join(stage, name);
|
|
74262
74644
|
if (entry.dir) {
|
|
74263
74645
|
await import_promises14.default.mkdir(dest, { recursive: true });
|
|
74264
74646
|
continue;
|
|
74265
74647
|
}
|
|
74266
|
-
await import_promises14.default.mkdir(
|
|
74648
|
+
await import_promises14.default.mkdir(import_node_path77.default.dirname(dest), { recursive: true });
|
|
74267
74649
|
if (name === "manifest.json") {
|
|
74268
74650
|
const rewritten = { ...parsed.data, id: localExtId };
|
|
74269
74651
|
await import_promises14.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
|
|
@@ -74330,7 +74712,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
|
|
|
74330
74712
|
);
|
|
74331
74713
|
}
|
|
74332
74714
|
}
|
|
74333
|
-
const manifestPath =
|
|
74715
|
+
const manifestPath = import_node_path78.default.join(root, extId, "manifest.json");
|
|
74334
74716
|
const manifest = await readManifest(root, extId);
|
|
74335
74717
|
const next = { ...manifest, version: newVersion };
|
|
74336
74718
|
const tmp = `${manifestPath}.tmp`;
|
|
@@ -74338,7 +74720,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
|
|
|
74338
74720
|
await import_promises15.default.rename(tmp, manifestPath);
|
|
74339
74721
|
}
|
|
74340
74722
|
async function readManifest(root, extId) {
|
|
74341
|
-
const file =
|
|
74723
|
+
const file = import_node_path78.default.join(root, extId, "manifest.json");
|
|
74342
74724
|
let raw;
|
|
74343
74725
|
try {
|
|
74344
74726
|
raw = await import_promises15.default.readFile(file, "utf8");
|
|
@@ -74422,7 +74804,7 @@ function buildExtensionHandlers(deps) {
|
|
|
74422
74804
|
};
|
|
74423
74805
|
async function buildSnapshotMeta(extId) {
|
|
74424
74806
|
const manifest = await readManifest(deps.root, extId);
|
|
74425
|
-
const { sha256, buffer } = await bundleExtensionDir(
|
|
74807
|
+
const { sha256, buffer } = await bundleExtensionDir(import_node_path78.default.join(deps.root, extId));
|
|
74426
74808
|
return { manifest, contentHash: sha256, buffer };
|
|
74427
74809
|
}
|
|
74428
74810
|
const publish = async (frame, _client, ctx) => {
|
|
@@ -74893,12 +75275,12 @@ function buildTopicHandlers(deps) {
|
|
|
74893
75275
|
"topic:delete": async (frame) => {
|
|
74894
75276
|
const { topicId } = TopicDeleteArgsSchema.parse(frame);
|
|
74895
75277
|
const topic = mustGet(topicId);
|
|
74896
|
-
const { removed, broadcast } = deps.deleteSession(topic.masterSessionId);
|
|
75278
|
+
const { removed, broadcast } = await deps.deleteSession(topic.masterSessionId);
|
|
74897
75279
|
const removedWorkerSessionIds = [];
|
|
74898
75280
|
const allBroadcast = [...broadcast];
|
|
74899
75281
|
for (const sessionId of workerSessionIdsOf(topic.masterSessionId)) {
|
|
74900
75282
|
try {
|
|
74901
|
-
const w3 = deps.deleteSession(sessionId);
|
|
75283
|
+
const w3 = await deps.deleteSession(sessionId);
|
|
74902
75284
|
allBroadcast.push(...w3.broadcast);
|
|
74903
75285
|
if (w3.removed) removedWorkerSessionIds.push(sessionId);
|
|
74904
75286
|
} catch (err) {
|
|
@@ -75250,7 +75632,7 @@ function buildVisitorHandlers(deps) {
|
|
|
75250
75632
|
|
|
75251
75633
|
// src/extension/registry.ts
|
|
75252
75634
|
var import_promises17 = __toESM(require("fs/promises"), 1);
|
|
75253
|
-
var
|
|
75635
|
+
var import_node_path79 = __toESM(require("path"), 1);
|
|
75254
75636
|
async function loadAll(root) {
|
|
75255
75637
|
let entries;
|
|
75256
75638
|
try {
|
|
@@ -75263,13 +75645,13 @@ async function loadAll(root) {
|
|
|
75263
75645
|
for (const ent of entries) {
|
|
75264
75646
|
if (!ent.isDirectory()) continue;
|
|
75265
75647
|
if (ent.name.startsWith(".")) continue;
|
|
75266
|
-
records.push(await loadOne(
|
|
75648
|
+
records.push(await loadOne(import_node_path79.default.join(root, ent.name), ent.name));
|
|
75267
75649
|
}
|
|
75268
75650
|
records.sort((a2, b3) => a2.extId < b3.extId ? -1 : a2.extId > b3.extId ? 1 : 0);
|
|
75269
75651
|
return records;
|
|
75270
75652
|
}
|
|
75271
75653
|
async function loadOne(dir, dirName) {
|
|
75272
|
-
const manifestPath =
|
|
75654
|
+
const manifestPath = import_node_path79.default.join(dir, "manifest.json");
|
|
75273
75655
|
let raw;
|
|
75274
75656
|
try {
|
|
75275
75657
|
raw = await import_promises17.default.readFile(manifestPath, "utf8");
|
|
@@ -75314,7 +75696,7 @@ async function loadOne(dir, dirName) {
|
|
|
75314
75696
|
|
|
75315
75697
|
// src/extension/uninstall.ts
|
|
75316
75698
|
var import_promises18 = __toESM(require("fs/promises"), 1);
|
|
75317
|
-
var
|
|
75699
|
+
var import_node_path80 = __toESM(require("path"), 1);
|
|
75318
75700
|
var UninstallError = class extends Error {
|
|
75319
75701
|
constructor(code, message) {
|
|
75320
75702
|
super(message);
|
|
@@ -75323,7 +75705,7 @@ var UninstallError = class extends Error {
|
|
|
75323
75705
|
code;
|
|
75324
75706
|
};
|
|
75325
75707
|
async function uninstall(deps) {
|
|
75326
|
-
const dir =
|
|
75708
|
+
const dir = import_node_path80.default.join(deps.root, deps.extId);
|
|
75327
75709
|
try {
|
|
75328
75710
|
await import_promises18.default.access(dir);
|
|
75329
75711
|
} catch {
|
|
@@ -75334,7 +75716,7 @@ async function uninstall(deps) {
|
|
|
75334
75716
|
}
|
|
75335
75717
|
|
|
75336
75718
|
// src/handlers/index.ts
|
|
75337
|
-
var
|
|
75719
|
+
var import_node_crypto27 = require("crypto");
|
|
75338
75720
|
|
|
75339
75721
|
// src/handlers/peer-exec.ts
|
|
75340
75722
|
init_protocol();
|
|
@@ -75491,7 +75873,7 @@ function buildMethodHandlers(deps) {
|
|
|
75491
75873
|
const c2 = deps.contactStore.get(deviceId);
|
|
75492
75874
|
return c2 ? { deviceId: c2.deviceId, remoteUrl: c2.remoteUrl, connectToken: c2.connectToken } : null;
|
|
75493
75875
|
},
|
|
75494
|
-
genId: () => (0,
|
|
75876
|
+
genId: () => (0, import_node_crypto27.randomUUID)(),
|
|
75495
75877
|
now: () => Date.now(),
|
|
75496
75878
|
forwardInboxPostToPeer,
|
|
75497
75879
|
logger: deps.logger
|
|
@@ -75541,7 +75923,7 @@ function buildMethodHandlers(deps) {
|
|
|
75541
75923
|
broadcast: deps.broadcastToOwners
|
|
75542
75924
|
}),
|
|
75543
75925
|
...buildMasterHandlers({
|
|
75544
|
-
authorityTablePath:
|
|
75926
|
+
authorityTablePath: import_node_path81.default.join(deps.masterDataDir, "master-authority.json")
|
|
75545
75927
|
}),
|
|
75546
75928
|
...buildTopicHandlers({
|
|
75547
75929
|
topicStore: deps.topicStore,
|
|
@@ -75684,7 +76066,7 @@ async function dispatchRpc(method, frame, client, ctx, deps) {
|
|
|
75684
76066
|
|
|
75685
76067
|
// src/extension/runtime.ts
|
|
75686
76068
|
var import_node_child_process25 = require("child_process");
|
|
75687
|
-
var
|
|
76069
|
+
var import_node_path82 = __toESM(require("path"), 1);
|
|
75688
76070
|
var import_promises19 = require("timers/promises");
|
|
75689
76071
|
|
|
75690
76072
|
// src/extension/port-allocator.ts
|
|
@@ -75785,7 +76167,7 @@ var Runtime = class {
|
|
|
75785
76167
|
/\$CLAWOS_EXT_PORT/g,
|
|
75786
76168
|
String(port)
|
|
75787
76169
|
);
|
|
75788
|
-
const dir =
|
|
76170
|
+
const dir = import_node_path82.default.join(this.root, extId);
|
|
75789
76171
|
const env = {
|
|
75790
76172
|
...process.env,
|
|
75791
76173
|
CLAWOS_EXT_PORT: String(port),
|
|
@@ -75897,7 +76279,7 @@ ${handle.stderrTail}`
|
|
|
75897
76279
|
|
|
75898
76280
|
// src/extension/published-channels.ts
|
|
75899
76281
|
var import_promises20 = __toESM(require("fs/promises"), 1);
|
|
75900
|
-
var
|
|
76282
|
+
var import_node_path83 = __toESM(require("path"), 1);
|
|
75901
76283
|
init_zod();
|
|
75902
76284
|
var PublishedChannelsError = class extends Error {
|
|
75903
76285
|
constructor(code, message) {
|
|
@@ -75996,7 +76378,7 @@ var PublishedChannelStore = class {
|
|
|
75996
76378
|
)
|
|
75997
76379
|
};
|
|
75998
76380
|
const tmp = `${this.filePath}.tmp`;
|
|
75999
|
-
await import_promises20.default.mkdir(
|
|
76381
|
+
await import_promises20.default.mkdir(import_node_path83.default.dirname(this.filePath), { recursive: true });
|
|
76000
76382
|
await import_promises20.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
|
|
76001
76383
|
await import_promises20.default.rename(tmp, this.filePath);
|
|
76002
76384
|
}
|
|
@@ -76004,7 +76386,7 @@ var PublishedChannelStore = class {
|
|
|
76004
76386
|
|
|
76005
76387
|
// src/extension/bundle-cache.ts
|
|
76006
76388
|
var import_promises21 = __toESM(require("fs/promises"), 1);
|
|
76007
|
-
var
|
|
76389
|
+
var import_node_path84 = __toESM(require("path"), 1);
|
|
76008
76390
|
var BundleCache = class {
|
|
76009
76391
|
constructor(rootDir) {
|
|
76010
76392
|
this.rootDir = rootDir;
|
|
@@ -76013,14 +76395,14 @@ var BundleCache = class {
|
|
|
76013
76395
|
/** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
|
|
76014
76396
|
async write(snapshotHash, buffer) {
|
|
76015
76397
|
await import_promises21.default.mkdir(this.rootDir, { recursive: true });
|
|
76016
|
-
const file =
|
|
76398
|
+
const file = import_node_path84.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
76017
76399
|
const tmp = `${file}.tmp`;
|
|
76018
76400
|
await import_promises21.default.writeFile(tmp, buffer, { mode: 384 });
|
|
76019
76401
|
await import_promises21.default.rename(tmp, file);
|
|
76020
76402
|
}
|
|
76021
76403
|
/** Returns the bundle bytes, or null when the file doesn't exist. */
|
|
76022
76404
|
async read(snapshotHash) {
|
|
76023
|
-
const file =
|
|
76405
|
+
const file = import_node_path84.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
76024
76406
|
try {
|
|
76025
76407
|
return await import_promises21.default.readFile(file);
|
|
76026
76408
|
} catch (e) {
|
|
@@ -76030,7 +76412,7 @@ var BundleCache = class {
|
|
|
76030
76412
|
}
|
|
76031
76413
|
/** Idempotent — missing file is not an error. */
|
|
76032
76414
|
async delete(snapshotHash) {
|
|
76033
|
-
const file =
|
|
76415
|
+
const file = import_node_path84.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
76034
76416
|
await import_promises21.default.rm(file, { force: true });
|
|
76035
76417
|
}
|
|
76036
76418
|
};
|
|
@@ -76053,24 +76435,24 @@ async function startDaemon(config) {
|
|
|
76053
76435
|
sampling: logShippingCfg.sampling,
|
|
76054
76436
|
homeDir: import_node_os31.default.homedir()
|
|
76055
76437
|
});
|
|
76056
|
-
const logDir =
|
|
76057
|
-
|
|
76438
|
+
const logDir = import_node_path85.default.join(config.dataDir, "log");
|
|
76439
|
+
import_node_fs66.default.mkdirSync(logDir, { recursive: true });
|
|
76058
76440
|
const logger = createLogger({
|
|
76059
76441
|
level: config.logLevel,
|
|
76060
|
-
file:
|
|
76442
|
+
file: import_node_path85.default.join(logDir, "clawd.log"),
|
|
76061
76443
|
logClient
|
|
76062
76444
|
});
|
|
76063
76445
|
logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
|
|
76064
76446
|
const screenIdleProbeLogger = createFileOnlyLogger({
|
|
76065
|
-
file:
|
|
76447
|
+
file: import_node_path85.default.join(logDir, "screen-idle-probe.log"),
|
|
76066
76448
|
level: "debug"
|
|
76067
76449
|
});
|
|
76068
76450
|
logger.info("screen-idle probe logger enabled", {
|
|
76069
|
-
file:
|
|
76451
|
+
file: import_node_path85.default.join(logDir, "screen-idle-probe.log")
|
|
76070
76452
|
});
|
|
76071
76453
|
const CAP_TARGETS = [
|
|
76072
|
-
|
|
76073
|
-
|
|
76454
|
+
import_node_path85.default.join(logDir, "clawd.log"),
|
|
76455
|
+
import_node_path85.default.join(logDir, "screen-idle-probe.log")
|
|
76074
76456
|
];
|
|
76075
76457
|
const LOG_CAP_MAX_BYTES = 10 * 1024 * 1024;
|
|
76076
76458
|
const LOG_CAP_KEEP_BYTES = 5 * 1024 * 1024;
|
|
@@ -76192,11 +76574,11 @@ async function startDaemon(config) {
|
|
|
76192
76574
|
const agents = new AgentsScanner();
|
|
76193
76575
|
const history = new ClaudeHistoryReader();
|
|
76194
76576
|
let transport = null;
|
|
76195
|
-
const personaStore = new PersonaStore(
|
|
76577
|
+
const personaStore = new PersonaStore(import_node_path85.default.join(config.dataDir, "personas"));
|
|
76196
76578
|
const subscriptionChannelStore = new SubscriptionChannelStore({ dataDir: config.dataDir });
|
|
76197
76579
|
const activeSubscriptionChannel = subscriptionChannelStore.getActive();
|
|
76198
76580
|
if (activeSubscriptionChannel) applyPiSubscriptionChannel({ channel: activeSubscriptionChannel });
|
|
76199
|
-
const usersRoot =
|
|
76581
|
+
const usersRoot = import_node_path85.default.join(config.dataDir, "users");
|
|
76200
76582
|
const defaultsRoot = findDefaultsRoot(logger);
|
|
76201
76583
|
if (defaultsRoot) {
|
|
76202
76584
|
seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
|
|
@@ -76213,7 +76595,7 @@ async function startDaemon(config) {
|
|
|
76213
76595
|
retirePersonaBuilder({ store: personaStore, logger });
|
|
76214
76596
|
const groupFileStore = new GroupFileStore({ dataDir: config.dataDir, logger });
|
|
76215
76597
|
const dispatchStore = createDispatchStore({
|
|
76216
|
-
filePath:
|
|
76598
|
+
filePath: import_node_path85.default.join(config.dataDir, "dispatch.json"),
|
|
76217
76599
|
now: () => Date.now(),
|
|
76218
76600
|
onFlushError: (err) => logger.error("dispatch store flush failed", {
|
|
76219
76601
|
reason: err instanceof Error ? err.message : String(err)
|
|
@@ -76222,18 +76604,18 @@ async function startDaemon(config) {
|
|
|
76222
76604
|
await dispatchStore.load();
|
|
76223
76605
|
dispatchStore.markInterruptedAsFailed((/* @__PURE__ */ new Date()).toISOString());
|
|
76224
76606
|
const channelStore = createChannelStore({
|
|
76225
|
-
filePath:
|
|
76607
|
+
filePath: import_node_path85.default.join(config.dataDir, "channels.json"),
|
|
76226
76608
|
now: () => Date.now(),
|
|
76227
|
-
genId: () => `ch-${(0,
|
|
76609
|
+
genId: () => `ch-${(0, import_node_crypto28.randomUUID)().slice(0, 8)}`,
|
|
76228
76610
|
onFlushError: (err) => logger.error("channel store flush failed", {
|
|
76229
76611
|
reason: err instanceof Error ? err.message : String(err)
|
|
76230
76612
|
})
|
|
76231
76613
|
});
|
|
76232
76614
|
await channelStore.load();
|
|
76233
76615
|
const topicStore = createTopicStore({
|
|
76234
|
-
filePath:
|
|
76616
|
+
filePath: import_node_path85.default.join(config.dataDir, "topics.json"),
|
|
76235
76617
|
now: () => Date.now(),
|
|
76236
|
-
genId: () => `tp-${(0,
|
|
76618
|
+
genId: () => `tp-${(0, import_node_crypto28.randomUUID)().slice(0, 8)}`,
|
|
76237
76619
|
onFlushError: (err) => logger.error("topic store flush failed", {
|
|
76238
76620
|
reason: err instanceof Error ? err.message : String(err)
|
|
76239
76621
|
})
|
|
@@ -76241,7 +76623,7 @@ async function startDaemon(config) {
|
|
|
76241
76623
|
await topicStore.load();
|
|
76242
76624
|
let deliverPendingRef;
|
|
76243
76625
|
const personaDispatchManager = new PersonaDispatchManager({
|
|
76244
|
-
genId: () => (0,
|
|
76626
|
+
genId: () => (0, import_node_crypto28.randomUUID)(),
|
|
76245
76627
|
store: dispatchStore,
|
|
76246
76628
|
now: () => Date.now(),
|
|
76247
76629
|
onCompleted: (sid) => deliverPendingRef?.(sid),
|
|
@@ -76258,12 +76640,12 @@ async function startDaemon(config) {
|
|
|
76258
76640
|
});
|
|
76259
76641
|
}
|
|
76260
76642
|
});
|
|
76261
|
-
const here = typeof __dirname === "string" ? __dirname :
|
|
76643
|
+
const here = typeof __dirname === "string" ? __dirname : import_node_path85.default.dirname((0, import_node_url6.fileURLToPath)(import_meta10.url));
|
|
76262
76644
|
const mcpConfigs = [];
|
|
76263
76645
|
const secretsBundleRoot = findSecretsBundleRoot(logger);
|
|
76264
|
-
const localSecretsDir =
|
|
76646
|
+
const localSecretsDir = import_node_path85.default.join(config.dataDir, LOCAL_SECRETS_DIRNAME);
|
|
76265
76647
|
const readSecrets = () => readSecretTable({ bundleRoot: secretsBundleRoot, overrideDir: localSecretsDir, logger });
|
|
76266
|
-
const githubTokenFile =
|
|
76648
|
+
const githubTokenFile = import_node_path85.default.join(localSecretsDir, GITHUB_TOKEN_FILE);
|
|
76267
76649
|
const githubIdentity = createGithubIdentity({
|
|
76268
76650
|
resolve: () => resolveGithubAuth({ exec: runCommand, fileToken: () => readEnvFileVar(githubTokenFile, GITHUB_TOKEN_VAR) }),
|
|
76269
76651
|
store: (token) => storeGithubAuth({
|
|
@@ -76301,22 +76683,22 @@ async function startDaemon(config) {
|
|
|
76301
76683
|
void githubIdentity.refresh();
|
|
76302
76684
|
return renderPersonaMcpSecrets({
|
|
76303
76685
|
personaId: personaId2,
|
|
76304
|
-
personaDir:
|
|
76686
|
+
personaDir: import_node_path85.default.join(config.dataDir, "personas", personaId2),
|
|
76305
76687
|
secrets,
|
|
76306
|
-
outDir:
|
|
76688
|
+
outDir: import_node_path85.default.join(config.dataDir, "persona-mcp"),
|
|
76307
76689
|
logger
|
|
76308
76690
|
});
|
|
76309
76691
|
};
|
|
76310
76692
|
const mcpDaemonUrl = `http://127.0.0.1:${config.port}`;
|
|
76311
76693
|
const dispatchServerCandidates = [
|
|
76312
|
-
|
|
76694
|
+
import_node_path85.default.join(here, "dispatch", "mcp-server.cjs"),
|
|
76313
76695
|
// 生产 dist/index → dist/dispatch/mcp-server.cjs
|
|
76314
|
-
|
|
76696
|
+
import_node_path85.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
|
|
76315
76697
|
// dev tsx src/index → ../dist/dispatch/mcp-server.cjs
|
|
76316
76698
|
];
|
|
76317
|
-
const dispatchServerScriptPath = dispatchServerCandidates.find((p3) =>
|
|
76699
|
+
const dispatchServerScriptPath = dispatchServerCandidates.find((p3) => import_node_fs66.default.existsSync(p3));
|
|
76318
76700
|
if (dispatchServerScriptPath) {
|
|
76319
|
-
const dispatchLogPath =
|
|
76701
|
+
const dispatchLogPath = import_node_path85.default.join(logDir, "dispatch-mcp-server.log");
|
|
76320
76702
|
const dispatchCfgPath = writeDispatchMcpConfig({
|
|
76321
76703
|
dataDir: config.dataDir,
|
|
76322
76704
|
serverScriptPath: dispatchServerScriptPath,
|
|
@@ -76336,12 +76718,12 @@ async function startDaemon(config) {
|
|
|
76336
76718
|
});
|
|
76337
76719
|
}
|
|
76338
76720
|
const ticketServerCandidates = [
|
|
76339
|
-
|
|
76340
|
-
|
|
76721
|
+
import_node_path85.default.join(here, "ticket", "mcp-server.cjs"),
|
|
76722
|
+
import_node_path85.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
|
|
76341
76723
|
];
|
|
76342
|
-
const ticketServerScriptPath = ticketServerCandidates.find((p3) =>
|
|
76724
|
+
const ticketServerScriptPath = ticketServerCandidates.find((p3) => import_node_fs66.default.existsSync(p3));
|
|
76343
76725
|
if (ticketServerScriptPath) {
|
|
76344
|
-
const ticketLogPath =
|
|
76726
|
+
const ticketLogPath = import_node_path85.default.join(logDir, "ticket-mcp-server.log");
|
|
76345
76727
|
const ticketCfgPath = writeTicketMcpConfig({
|
|
76346
76728
|
dataDir: config.dataDir,
|
|
76347
76729
|
serverScriptPath: ticketServerScriptPath,
|
|
@@ -76363,12 +76745,12 @@ async function startDaemon(config) {
|
|
|
76363
76745
|
});
|
|
76364
76746
|
}
|
|
76365
76747
|
const shiftServerCandidates = [
|
|
76366
|
-
|
|
76367
|
-
|
|
76748
|
+
import_node_path85.default.join(here, "shift", "mcp-server.cjs"),
|
|
76749
|
+
import_node_path85.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
|
|
76368
76750
|
];
|
|
76369
|
-
const shiftServerScriptPath = shiftServerCandidates.find((p3) =>
|
|
76751
|
+
const shiftServerScriptPath = shiftServerCandidates.find((p3) => import_node_fs66.default.existsSync(p3));
|
|
76370
76752
|
if (shiftServerScriptPath) {
|
|
76371
|
-
const shiftLogPath =
|
|
76753
|
+
const shiftLogPath = import_node_path85.default.join(logDir, "shift-mcp-server.log");
|
|
76372
76754
|
const shiftCfgPath = await writeShiftMcpConfig({
|
|
76373
76755
|
dataDir: config.dataDir,
|
|
76374
76756
|
serverScriptPath: shiftServerScriptPath,
|
|
@@ -76389,12 +76771,12 @@ async function startDaemon(config) {
|
|
|
76389
76771
|
);
|
|
76390
76772
|
}
|
|
76391
76773
|
const inboxServerCandidates = [
|
|
76392
|
-
|
|
76393
|
-
|
|
76774
|
+
import_node_path85.default.join(here, "inbox", "mcp-server.cjs"),
|
|
76775
|
+
import_node_path85.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
|
|
76394
76776
|
];
|
|
76395
|
-
const inboxServerScriptPath = inboxServerCandidates.find((p3) =>
|
|
76777
|
+
const inboxServerScriptPath = inboxServerCandidates.find((p3) => import_node_fs66.default.existsSync(p3));
|
|
76396
76778
|
if (inboxServerScriptPath) {
|
|
76397
|
-
const inboxLogPath =
|
|
76779
|
+
const inboxLogPath = import_node_path85.default.join(logDir, "inbox-mcp-server.log");
|
|
76398
76780
|
const inboxCfgPath = await writeInboxMcpConfig({
|
|
76399
76781
|
dataDir: config.dataDir,
|
|
76400
76782
|
serverScriptPath: inboxServerScriptPath,
|
|
@@ -76415,10 +76797,10 @@ async function startDaemon(config) {
|
|
|
76415
76797
|
);
|
|
76416
76798
|
}
|
|
76417
76799
|
const peerOpsServerCandidates = [
|
|
76418
|
-
|
|
76419
|
-
|
|
76800
|
+
import_node_path85.default.join(here, "peer-ops", "mcp-server.cjs"),
|
|
76801
|
+
import_node_path85.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
|
|
76420
76802
|
];
|
|
76421
|
-
const peerOpsServerScriptPath = peerOpsServerCandidates.find((p3) =>
|
|
76803
|
+
const peerOpsServerScriptPath = peerOpsServerCandidates.find((p3) => import_node_fs66.default.existsSync(p3));
|
|
76422
76804
|
if (peerOpsServerScriptPath) {
|
|
76423
76805
|
const peerOpsCfgPath = writePeerOpsMcpConfig({
|
|
76424
76806
|
dataDir: config.dataDir,
|
|
@@ -76438,12 +76820,12 @@ async function startDaemon(config) {
|
|
|
76438
76820
|
);
|
|
76439
76821
|
}
|
|
76440
76822
|
const rpcToolServerCandidates = [
|
|
76441
|
-
|
|
76442
|
-
|
|
76823
|
+
import_node_path85.default.join(here, "rpc-tool", "mcp-server.cjs"),
|
|
76824
|
+
import_node_path85.default.join(here, "..", "dist", "rpc-tool", "mcp-server.cjs")
|
|
76443
76825
|
];
|
|
76444
|
-
const rpcToolServerScriptPath = rpcToolServerCandidates.find((p3) =>
|
|
76826
|
+
const rpcToolServerScriptPath = rpcToolServerCandidates.find((p3) => import_node_fs66.default.existsSync(p3));
|
|
76445
76827
|
if (rpcToolServerScriptPath) {
|
|
76446
|
-
const rpcToolLogPath =
|
|
76828
|
+
const rpcToolLogPath = import_node_path85.default.join(logDir, "rpc-tool-mcp-server.log");
|
|
76447
76829
|
const rpcToolCfgPath = writeRpcToolMcpConfig({
|
|
76448
76830
|
dataDir: config.dataDir,
|
|
76449
76831
|
serverScriptPath: rpcToolServerScriptPath,
|
|
@@ -76464,7 +76846,7 @@ async function startDaemon(config) {
|
|
|
76464
76846
|
);
|
|
76465
76847
|
}
|
|
76466
76848
|
const shiftStore = createShiftStore({
|
|
76467
|
-
filePath:
|
|
76849
|
+
filePath: import_node_path85.default.join(config.dataDir, "shift.json"),
|
|
76468
76850
|
ownerIdProvider: () => ownerPrincipalId,
|
|
76469
76851
|
now: () => Date.now()
|
|
76470
76852
|
});
|
|
@@ -76486,7 +76868,7 @@ async function startDaemon(config) {
|
|
|
76486
76868
|
getAdapter,
|
|
76487
76869
|
historyReader: history,
|
|
76488
76870
|
dataDir: config.dataDir,
|
|
76489
|
-
personaRoot:
|
|
76871
|
+
personaRoot: import_node_path85.default.join(config.dataDir, "personas"),
|
|
76490
76872
|
// dispatch / shift 自动化 spawn 按 persona 绑定 tool 起 B session(codex persona 用 codex)。
|
|
76491
76873
|
// personaRegistry 声明在 manager 之后(同作用域 const,调用时机在启动完成后,无 TDZ 风险)。
|
|
76492
76874
|
getPersonaDefaults: (personaId2) => personaRegistry.get(personaId2),
|
|
@@ -76547,10 +76929,10 @@ async function startDaemon(config) {
|
|
|
76547
76929
|
// 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
|
|
76548
76930
|
attachmentGroup: {
|
|
76549
76931
|
onFileEdit: (input) => {
|
|
76550
|
-
const absPath =
|
|
76932
|
+
const absPath = import_node_path85.default.isAbsolute(input.relPath) ? input.relPath : import_node_path85.default.join(input.cwd, input.relPath);
|
|
76551
76933
|
let size = 0;
|
|
76552
76934
|
try {
|
|
76553
|
-
size =
|
|
76935
|
+
size = import_node_fs66.default.statSync(absPath).size;
|
|
76554
76936
|
} catch (err) {
|
|
76555
76937
|
logger.warn("attachment.onFileEdit stat failed", {
|
|
76556
76938
|
sessionId: input.sessionId,
|
|
@@ -76591,9 +76973,9 @@ async function startDaemon(config) {
|
|
|
76591
76973
|
logger.info("projects.seed-dropped", { dropped: droppedSeed.dropped, backup: droppedSeed.backup });
|
|
76592
76974
|
}
|
|
76593
76975
|
const projectsStore = new ProjectsStore({
|
|
76594
|
-
file:
|
|
76976
|
+
file: import_node_path85.default.join(config.dataDir, "projects.json"),
|
|
76595
76977
|
clawdDir: config.dataDir,
|
|
76596
|
-
codexStateFile:
|
|
76978
|
+
codexStateFile: import_node_path85.default.join(import_node_os31.default.homedir(), ".codex", ".codex-global-state.json"),
|
|
76597
76979
|
logger
|
|
76598
76980
|
});
|
|
76599
76981
|
const observer = new SessionObserver({
|
|
@@ -76657,14 +77039,35 @@ async function startDaemon(config) {
|
|
|
76657
77039
|
centralApi: config.clawosApi ?? DEFAULT_CLAWOS_API,
|
|
76658
77040
|
logger
|
|
76659
77041
|
});
|
|
77042
|
+
const cloudCancelOutbox = new CloudCancelOutbox(
|
|
77043
|
+
import_node_path85.default.join(config.dataDir, "cloud-cancel-outbox"),
|
|
77044
|
+
(personaId2, clientSessionId, gatewaySessionId) => cloudGateway.cancelEventSession(personaId2, clientSessionId, gatewaySessionId),
|
|
77045
|
+
logger
|
|
77046
|
+
);
|
|
77047
|
+
manager.setCloudCanceller(async (file, runner) => {
|
|
77048
|
+
const personaId2 = personaIdFromCloudCwd(file.cwd);
|
|
77049
|
+
if (!personaId2) throw new Error(`\u4E91\u4F1A\u8BDD ${file.sessionId} \u7F3A\u5C11 gateway persona ID`);
|
|
77050
|
+
const executionId = file.cloudExecutionId ?? file.sessionId;
|
|
77051
|
+
if (!file.cloudGatewaySessionId) throw new Error(`\u4E91\u4F1A\u8BDD ${file.sessionId} \u5C1A\u672A\u6536\u5230 gateway ready`);
|
|
77052
|
+
cloudCancelOutbox.record(executionId, personaId2, file.cloudGatewaySessionId);
|
|
77053
|
+
try {
|
|
77054
|
+
await cloudGateway.cancelEventSession(personaId2, executionId, file.cloudGatewaySessionId);
|
|
77055
|
+
cloudCancelOutbox.confirm(executionId);
|
|
77056
|
+
runner?.confirmCloudCancelled();
|
|
77057
|
+
} catch (e) {
|
|
77058
|
+
cloudCancelOutbox.release(executionId);
|
|
77059
|
+
throw e;
|
|
77060
|
+
}
|
|
77061
|
+
});
|
|
77062
|
+
cloudCancelOutbox.start();
|
|
76660
77063
|
registerAdapter("claude", claudeAdapter);
|
|
76661
|
-
const codexIsolatedHome =
|
|
77064
|
+
const codexIsolatedHome = import_node_path85.default.join(config.dataDir, "codex-home");
|
|
76662
77065
|
try {
|
|
76663
|
-
|
|
77066
|
+
import_node_fs66.default.mkdirSync(codexIsolatedHome, { recursive: true });
|
|
76664
77067
|
for (const f2 of ["auth.json", "config.toml"]) {
|
|
76665
|
-
const link =
|
|
76666
|
-
const target =
|
|
76667
|
-
if (!
|
|
77068
|
+
const link = import_node_path85.default.join(codexIsolatedHome, f2);
|
|
77069
|
+
const target = import_node_path85.default.join(import_node_os31.default.homedir(), ".codex", f2);
|
|
77070
|
+
if (!import_node_fs66.default.existsSync(link) && import_node_fs66.default.existsSync(target)) import_node_fs66.default.symlinkSync(target, link);
|
|
76668
77071
|
}
|
|
76669
77072
|
} catch (err) {
|
|
76670
77073
|
logger.warn("codex isolated home setup failed", { err: String(err) });
|
|
@@ -76675,17 +77078,17 @@ async function startDaemon(config) {
|
|
|
76675
77078
|
logger,
|
|
76676
77079
|
historyReader: new CodexHistoryReader({
|
|
76677
77080
|
roots: codexRolloutRoots(config.dataDir),
|
|
76678
|
-
sharedHome:
|
|
77081
|
+
sharedHome: import_node_path85.default.join(import_node_os31.default.homedir(), ".codex"),
|
|
76679
77082
|
logger
|
|
76680
77083
|
}),
|
|
76681
77084
|
// projectPaths 每次调用现取 —— 用户新建 project 后立即生效,不用重启 daemon
|
|
76682
77085
|
codexHomeFor: (cwd) => resolveCodexHome({
|
|
76683
77086
|
cwd,
|
|
76684
|
-
personaRoot:
|
|
77087
|
+
personaRoot: import_node_path85.default.join(config.dataDir, "personas"),
|
|
76685
77088
|
// 必须用 listMerged(Codex registry ∪ 叠加层):只用本地 list() 的话,用户在
|
|
76686
77089
|
// Codex 里建的 project 不在表里,在它下面开的会话会被误判成隔离 → Codex 侧看不到
|
|
76687
77090
|
projectPaths: projectsStore.listMerged().map((x2) => x2.path),
|
|
76688
|
-
sharedHome:
|
|
77091
|
+
sharedHome: import_node_path85.default.join(import_node_os31.default.homedir(), ".codex"),
|
|
76689
77092
|
isolatedHome: codexIsolatedHome
|
|
76690
77093
|
}),
|
|
76691
77094
|
codexHomeForThread: (threadId) => locateCodexThread(codexRolloutRoots(config.dataDir), threadId)?.home,
|
|
@@ -76711,10 +77114,10 @@ async function startDaemon(config) {
|
|
|
76711
77114
|
);
|
|
76712
77115
|
registerAdapter(PI_CLOUD_TOOL_ID, new CloudPiAdapter({ client: cloudGateway, history: cloudHistorySource, logger }));
|
|
76713
77116
|
const piMcpBridgeCandidates = [
|
|
76714
|
-
|
|
76715
|
-
|
|
77117
|
+
import_node_path85.default.join(here, "pi-mcp-bridge", "extension.cjs"),
|
|
77118
|
+
import_node_path85.default.join(here, "..", "dist", "pi-mcp-bridge", "extension.cjs")
|
|
76716
77119
|
];
|
|
76717
|
-
const piMcpBridgePath = piMcpBridgeCandidates.find((p3) =>
|
|
77120
|
+
const piMcpBridgePath = piMcpBridgeCandidates.find((p3) => import_node_fs66.default.existsSync(p3));
|
|
76718
77121
|
if (piMcpBridgePath) {
|
|
76719
77122
|
logger.info("pi-mcp-bridge extension resolved", { path: piMcpBridgePath });
|
|
76720
77123
|
} else {
|
|
@@ -76959,9 +77362,9 @@ async function startDaemon(config) {
|
|
|
76959
77362
|
// 删话题连带删这个话题名下的全部会话(Master + 它派出去的 worker),逐条走这里。
|
|
76960
77363
|
// 会话已经不在本机了不算失败——话题仍要删得掉,所以 SESSION_NOT_FOUND 吞掉并回
|
|
76961
77364
|
// removed:false,其余错误照抛(别把真故障说成成功)。
|
|
76962
|
-
deleteSession: (sessionId) => {
|
|
77365
|
+
deleteSession: async (sessionId) => {
|
|
76963
77366
|
try {
|
|
76964
|
-
const { broadcast } = manager.
|
|
77367
|
+
const { broadcast } = await manager.deleteWithCloudCancel({ sessionId });
|
|
76965
77368
|
return { removed: true, broadcast };
|
|
76966
77369
|
} catch (err) {
|
|
76967
77370
|
if (err instanceof ClawdError && err.code === ERROR_CODES.SESSION_NOT_FOUND) {
|
|
@@ -77020,11 +77423,11 @@ async function startDaemon(config) {
|
|
|
77020
77423
|
// 'persona/<pid>/owner',default 走 'default'。
|
|
77021
77424
|
getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
|
|
77022
77425
|
// guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
|
|
77023
|
-
personaRoot:
|
|
77426
|
+
personaRoot: import_node_path85.default.join(config.dataDir, "personas"),
|
|
77024
77427
|
usersRoot
|
|
77025
77428
|
},
|
|
77026
77429
|
// workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
|
|
77027
|
-
personaRoot:
|
|
77430
|
+
personaRoot: import_node_path85.default.join(config.dataDir, "personas"),
|
|
77028
77431
|
// v2 多人 persona 隔离:handler 派生 guest user-dir 放行
|
|
77029
77432
|
usersRoot,
|
|
77030
77433
|
// v2 Phase 6: whoami handler 装在 owner principal.displayName + persona 解析
|
|
@@ -77330,7 +77733,7 @@ async function startDaemon(config) {
|
|
|
77330
77733
|
});
|
|
77331
77734
|
shiftScheduler.start();
|
|
77332
77735
|
logger.info("shift scheduler started", { shiftCount: shiftStore.list().length });
|
|
77333
|
-
const larkBotStore = createLarkBotBindingStore(
|
|
77736
|
+
const larkBotStore = createLarkBotBindingStore(import_node_path85.default.join(config.dataDir, "personas"));
|
|
77334
77737
|
const larkBotCloud = createLarkBotCloudClient({
|
|
77335
77738
|
api: config.clawosApi ?? DEFAULT_CLAWOS_API,
|
|
77336
77739
|
getLoginPass: () => ownerIdentityStore.read()?.loginPass ?? null
|
|
@@ -77342,7 +77745,7 @@ async function startDaemon(config) {
|
|
|
77342
77745
|
store: larkBotStore,
|
|
77343
77746
|
fetchResource: (appId, messageId, fileKey, maxBytes, type) => larkBotCloud.fetchResource(appId, messageId, fileKey, maxBytes, type),
|
|
77344
77747
|
// 图片落 guest userWorkDir 下(capId = lark-<chat_id>):CC 经 --add-dir + allowRead carve 可 Read
|
|
77345
|
-
mediaRootFor: (chatId) =>
|
|
77748
|
+
mediaRootFor: (chatId) => import_node_path85.default.join(deriveUserWorkDir(`lark-${chatId}`, usersRoot), "lark-media"),
|
|
77346
77749
|
isShuttingDown: () => larkDraining,
|
|
77347
77750
|
logger: {
|
|
77348
77751
|
warn: (msg) => logger.warn(msg),
|
|
@@ -77599,6 +78002,9 @@ async function startDaemon(config) {
|
|
|
77599
78002
|
fanOutBroadcast(result.broadcast);
|
|
77600
78003
|
});
|
|
77601
78004
|
manager.sweepEphemeralOnStartup();
|
|
78005
|
+
manager.recoverCloudSessions();
|
|
78006
|
+
const cloudRecoveryInterval = setInterval(() => manager.recoverCloudSessions(), 3e4);
|
|
78007
|
+
cloudRecoveryInterval.unref();
|
|
77602
78008
|
await wss.start();
|
|
77603
78009
|
const url = `ws://${config.host}:${config.port}`;
|
|
77604
78010
|
let stateSnapshot = {
|
|
@@ -77652,8 +78058,8 @@ async function startDaemon(config) {
|
|
|
77652
78058
|
const lines = [
|
|
77653
78059
|
`Tunnel: ${r2.url}`,
|
|
77654
78060
|
...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
|
|
77655
|
-
`Frpc config: ${
|
|
77656
|
-
`Frpc log: ${
|
|
78061
|
+
`Frpc config: ${import_node_path85.default.join(config.dataDir, "frpc.toml")}`,
|
|
78062
|
+
`Frpc log: ${import_node_path85.default.join(logDir, "frpc.log")}`
|
|
77657
78063
|
];
|
|
77658
78064
|
const width2 = Math.max(...lines.map((l2) => l2.length));
|
|
77659
78065
|
const bar = "\u2550".repeat(width2 + 4);
|
|
@@ -77666,8 +78072,8 @@ ${bar}
|
|
|
77666
78072
|
|
|
77667
78073
|
`);
|
|
77668
78074
|
try {
|
|
77669
|
-
const connectPath =
|
|
77670
|
-
|
|
78075
|
+
const connectPath = import_node_path85.default.join(config.dataDir, "connect.txt");
|
|
78076
|
+
import_node_fs66.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
|
|
77671
78077
|
} catch {
|
|
77672
78078
|
}
|
|
77673
78079
|
} catch (err) {
|
|
@@ -77735,6 +78141,8 @@ ${bar}
|
|
|
77735
78141
|
logger.info("stopping clawd");
|
|
77736
78142
|
larkDraining = true;
|
|
77737
78143
|
clearInterval(attachmentGcInterval);
|
|
78144
|
+
clearInterval(cloudRecoveryInterval);
|
|
78145
|
+
cloudCancelOutbox.stop();
|
|
77738
78146
|
observer.stopAll();
|
|
77739
78147
|
manager.stopAll();
|
|
77740
78148
|
await extensionRuntime.stopAll();
|
|
@@ -77765,9 +78173,9 @@ ${bar}
|
|
|
77765
78173
|
};
|
|
77766
78174
|
}
|
|
77767
78175
|
function migrateDropPersonsDir(dataDir) {
|
|
77768
|
-
const dir =
|
|
78176
|
+
const dir = import_node_path85.default.join(dataDir, "persons");
|
|
77769
78177
|
try {
|
|
77770
|
-
|
|
78178
|
+
import_node_fs66.default.rmSync(dir, { recursive: true, force: true });
|
|
77771
78179
|
} catch {
|
|
77772
78180
|
}
|
|
77773
78181
|
}
|