@clawos-dev/clawd 0.2.602 → 0.2.604
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +781 -607
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -62563,6 +62563,81 @@ var SubscriptionChannelStore = class {
|
|
|
62563
62563
|
}
|
|
62564
62564
|
};
|
|
62565
62565
|
|
|
62566
|
+
// src/tools/subscription-channels-apply.ts
|
|
62567
|
+
var import_node_fs36 = __toESM(require("fs"), 1);
|
|
62568
|
+
var import_node_os13 = __toESM(require("os"), 1);
|
|
62569
|
+
var import_node_path41 = __toESM(require("path"), 1);
|
|
62570
|
+
var TABLE_HEADER = /^\s*\[\[?\s*([A-Za-z0-9_.-]+)\s*\]\]?\s*(?:#.*)?$/;
|
|
62571
|
+
var KEY_LINE = /^\s*([A-Za-z0-9_.-]+)\s*=/;
|
|
62572
|
+
function stripCodexProvider(text) {
|
|
62573
|
+
const out = [];
|
|
62574
|
+
let inProviderSection = false;
|
|
62575
|
+
for (const line of text.split("\n")) {
|
|
62576
|
+
const headerMatch = TABLE_HEADER.exec(line);
|
|
62577
|
+
if (headerMatch) {
|
|
62578
|
+
const section = headerMatch[1].trim();
|
|
62579
|
+
inProviderSection = section === "model_providers" || section.startsWith("model_providers.");
|
|
62580
|
+
if (inProviderSection) continue;
|
|
62581
|
+
out.push(line);
|
|
62582
|
+
continue;
|
|
62583
|
+
}
|
|
62584
|
+
if (inProviderSection) continue;
|
|
62585
|
+
const keyMatch = KEY_LINE.exec(line);
|
|
62586
|
+
if (keyMatch) {
|
|
62587
|
+
const key = keyMatch[1].trim();
|
|
62588
|
+
if (key === "model_provider" || key.startsWith("model_providers.")) {
|
|
62589
|
+
continue;
|
|
62590
|
+
}
|
|
62591
|
+
}
|
|
62592
|
+
out.push(line);
|
|
62593
|
+
}
|
|
62594
|
+
return out.join("\n").trim();
|
|
62595
|
+
}
|
|
62596
|
+
function applyCodexSubscriptionChannel(opts) {
|
|
62597
|
+
const codexHome = opts.codexHome || process.env.CODEX_HOME || import_node_path41.default.join(import_node_os13.default.homedir(), ".codex");
|
|
62598
|
+
import_node_fs36.default.mkdirSync(codexHome, { recursive: true });
|
|
62599
|
+
const configFile = import_node_path41.default.join(codexHome, "config.toml");
|
|
62600
|
+
const original = import_node_fs36.default.existsSync(configFile) ? import_node_fs36.default.readFileSync(configFile, "utf8") : "";
|
|
62601
|
+
const rest = stripCodexProvider(original);
|
|
62602
|
+
let content;
|
|
62603
|
+
if (opts.channel) {
|
|
62604
|
+
const ch = opts.channel;
|
|
62605
|
+
content = [
|
|
62606
|
+
'model_provider = "cliproxyapi"',
|
|
62607
|
+
...rest ? ["", rest] : [],
|
|
62608
|
+
"",
|
|
62609
|
+
"[model_providers.cliproxyapi]",
|
|
62610
|
+
'name = "cliproxyapi"',
|
|
62611
|
+
`base_url = ${JSON.stringify(ch.baseUrl)}`,
|
|
62612
|
+
'wire_api = "responses"',
|
|
62613
|
+
`auth = { command = "echo", args = [${JSON.stringify(ch.apiKey)}] }`,
|
|
62614
|
+
""
|
|
62615
|
+
].join("\n");
|
|
62616
|
+
} else {
|
|
62617
|
+
content = [
|
|
62618
|
+
'model_provider = "openai"',
|
|
62619
|
+
...rest ? ["", rest] : [],
|
|
62620
|
+
""
|
|
62621
|
+
].join("\n");
|
|
62622
|
+
}
|
|
62623
|
+
const tmpFile = `${configFile}.tmp.${Date.now()}`;
|
|
62624
|
+
import_node_fs36.default.writeFileSync(tmpFile, content, { mode: 384 });
|
|
62625
|
+
import_node_fs36.default.renameSync(tmpFile, configFile);
|
|
62626
|
+
}
|
|
62627
|
+
function applyPiSubscriptionChannel(opts) {
|
|
62628
|
+
const agentDir = opts.agentDir || process.env.PI_CODING_AGENT_DIR || import_node_path41.default.join(import_node_os13.default.homedir(), ".pi", "agent");
|
|
62629
|
+
if (!import_node_fs36.default.existsSync(agentDir)) return false;
|
|
62630
|
+
const configFile = import_node_path41.default.join(agentDir, "cliproxyapi.json");
|
|
62631
|
+
if (opts.channel) {
|
|
62632
|
+
const data = { baseUrl: opts.channel.baseUrl, apiKey: opts.channel.apiKey };
|
|
62633
|
+
const tmp = `${configFile}.tmp.${Date.now()}`;
|
|
62634
|
+
import_node_fs36.default.writeFileSync(tmp, JSON.stringify(data, null, 2) + "\n", { mode: 384 });
|
|
62635
|
+
import_node_fs36.default.renameSync(tmp, configFile);
|
|
62636
|
+
return true;
|
|
62637
|
+
}
|
|
62638
|
+
return false;
|
|
62639
|
+
}
|
|
62640
|
+
|
|
62566
62641
|
// src/deploy/local-probe.ts
|
|
62567
62642
|
function pickVersion(s2) {
|
|
62568
62643
|
return /(\d+)\.(\d+)(?:\.(\d+))?/.exec(s2)?.[0];
|
|
@@ -62611,10 +62686,10 @@ async function probeLocalVersion(exec, pkg) {
|
|
|
62611
62686
|
|
|
62612
62687
|
// src/tools/shell-path.ts
|
|
62613
62688
|
var import_node_child_process10 = require("child_process");
|
|
62614
|
-
var
|
|
62689
|
+
var import_node_os14 = __toESM(require("os"), 1);
|
|
62615
62690
|
function refreshPathFromLoginShell() {
|
|
62616
62691
|
if (process.platform === "win32") return;
|
|
62617
|
-
const shell = process.env.SHELL ??
|
|
62692
|
+
const shell = process.env.SHELL ?? import_node_os14.default.userInfo().shell ?? "/bin/zsh";
|
|
62618
62693
|
try {
|
|
62619
62694
|
const out = (0, import_node_child_process10.execFileSync)(shell, ["-ilc", 'command echo -n "$PATH"'], {
|
|
62620
62695
|
encoding: "utf8",
|
|
@@ -63160,15 +63235,15 @@ async function refreshTunnelUrlOnStartup(deps) {
|
|
|
63160
63235
|
}
|
|
63161
63236
|
|
|
63162
63237
|
// src/lark-bot-connector/binding-store.ts
|
|
63163
|
-
var
|
|
63164
|
-
var
|
|
63238
|
+
var import_node_fs37 = __toESM(require("fs"), 1);
|
|
63239
|
+
var import_node_path42 = __toESM(require("path"), 1);
|
|
63165
63240
|
function createLarkBotBindingStore(personaRoot) {
|
|
63166
|
-
const filePath = (personaId2) =>
|
|
63241
|
+
const filePath = (personaId2) => import_node_path42.default.join(personaRoot, safeFileName(personaId2), ".clawd", "lark-bot.json");
|
|
63167
63242
|
const read = (personaId2) => {
|
|
63168
63243
|
const file = filePath(personaId2);
|
|
63169
|
-
if (!
|
|
63244
|
+
if (!import_node_fs37.default.existsSync(file)) return null;
|
|
63170
63245
|
try {
|
|
63171
|
-
const raw = JSON.parse(
|
|
63246
|
+
const raw = JSON.parse(import_node_fs37.default.readFileSync(file, "utf8"));
|
|
63172
63247
|
if (typeof raw?.appId !== "string" || raw.appId.length === 0) return null;
|
|
63173
63248
|
return raw;
|
|
63174
63249
|
} catch {
|
|
@@ -63177,16 +63252,16 @@ function createLarkBotBindingStore(personaRoot) {
|
|
|
63177
63252
|
};
|
|
63178
63253
|
const write = (personaId2, meta) => {
|
|
63179
63254
|
const file = filePath(personaId2);
|
|
63180
|
-
|
|
63255
|
+
import_node_fs37.default.mkdirSync(import_node_path42.default.dirname(file), { recursive: true });
|
|
63181
63256
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
63182
|
-
|
|
63183
|
-
|
|
63257
|
+
import_node_fs37.default.writeFileSync(tmp, JSON.stringify(meta, null, 2), { mode: 384 });
|
|
63258
|
+
import_node_fs37.default.renameSync(tmp, file);
|
|
63184
63259
|
};
|
|
63185
63260
|
return {
|
|
63186
63261
|
read,
|
|
63187
63262
|
write,
|
|
63188
63263
|
remove(personaId2) {
|
|
63189
|
-
|
|
63264
|
+
import_node_fs37.default.rmSync(filePath(personaId2), { force: true });
|
|
63190
63265
|
},
|
|
63191
63266
|
addRemovedChat(personaId2, chatId) {
|
|
63192
63267
|
const meta = read(personaId2);
|
|
@@ -63338,8 +63413,8 @@ function createLarkBotCloudClient(opts) {
|
|
|
63338
63413
|
}
|
|
63339
63414
|
|
|
63340
63415
|
// src/lark-bot-connector/chat-router.ts
|
|
63341
|
-
var
|
|
63342
|
-
var
|
|
63416
|
+
var import_node_fs38 = __toESM(require("fs"), 1);
|
|
63417
|
+
var import_node_path43 = __toESM(require("path"), 1);
|
|
63343
63418
|
init_protocol();
|
|
63344
63419
|
var ERROR_REPLY_TEXT = "\u5904\u7406\u51FA\u9519\u4E86\uFF0C\u8BF7\u91CD\u8BD5";
|
|
63345
63420
|
var LOCAL_TURN_RETRIES = 2;
|
|
@@ -63417,9 +63492,9 @@ function createLarkChatRouter(deps) {
|
|
|
63417
63492
|
continue;
|
|
63418
63493
|
}
|
|
63419
63494
|
const dir = deps.mediaRootFor(env.chatId);
|
|
63420
|
-
|
|
63421
|
-
const p3 =
|
|
63422
|
-
|
|
63495
|
+
import_node_fs38.default.mkdirSync(dir, { recursive: true });
|
|
63496
|
+
const p3 = import_node_path43.default.join(dir, `${safeMediaName(ownerMessageId)}-${i2}.${ext}`);
|
|
63497
|
+
import_node_fs38.default.writeFileSync(p3, r2.data);
|
|
63423
63498
|
lines.push(`[\u56FE\u7247: ${p3}]\uFF08\u7528 Read \u5DE5\u5177\u67E5\u770B\uFF09`);
|
|
63424
63499
|
} catch (err) {
|
|
63425
63500
|
deps.logger?.warn(`larkBot image fetch failed ${key}: ${err.message}`);
|
|
@@ -63440,9 +63515,9 @@ function createLarkChatRouter(deps) {
|
|
|
63440
63515
|
continue;
|
|
63441
63516
|
}
|
|
63442
63517
|
const dir = deps.mediaRootFor(env.chatId);
|
|
63443
|
-
|
|
63444
|
-
const p3 =
|
|
63445
|
-
|
|
63518
|
+
import_node_fs38.default.mkdirSync(dir, { recursive: true });
|
|
63519
|
+
const p3 = import_node_path43.default.join(dir, `${safeMediaName(ownerMessageId)}-${i2}-${safeAttachmentName(f2.name)}`);
|
|
63520
|
+
import_node_fs38.default.writeFileSync(p3, r2.data);
|
|
63446
63521
|
lines.push(`[\u6587\u4EF6: ${p3}]\uFF08\u7528 Read \u5DE5\u5177\u67E5\u770B\uFF09`);
|
|
63447
63522
|
} catch (err) {
|
|
63448
63523
|
deps.logger?.warn(`larkBot file fetch failed ${f2.key}: ${err.message}`);
|
|
@@ -64276,6 +64351,8 @@ var GATEWAY_ROUTES = {
|
|
|
64276
64351
|
session: (personaId2) => `/p/${encodeURIComponent(personaId2)}/session`,
|
|
64277
64352
|
sessionSend: (personaId2, sessionId) => `/p/${encodeURIComponent(personaId2)}/session/${encodeURIComponent(sessionId)}`,
|
|
64278
64353
|
sessionMirror: (personaId2, sessionId) => `/p/${encodeURIComponent(personaId2)}/session/${encodeURIComponent(sessionId)}/mirror`,
|
|
64354
|
+
eventSession: (personaId2) => `/p/${encodeURIComponent(personaId2)}/session/events`,
|
|
64355
|
+
eventSend: (personaId2, sessionId) => `/p/${encodeURIComponent(personaId2)}/session/events/${encodeURIComponent(sessionId)}`,
|
|
64279
64356
|
// 调用方自己那块盘的用量(design 2026-09-19-cloud-volume-usage §3.3):同样按人、不挂 persona
|
|
64280
64357
|
volume: () => "/me/volume",
|
|
64281
64358
|
// 云 persona 运行看板的数据(design 2026-09-23-cloud-persona-metrics §3.6):只给发布者与管理员(gateway 问中心,design 2026-09-24-cloud-persona-conversations §3.2)
|
|
@@ -64396,6 +64473,22 @@ var CloudGatewayClient = class {
|
|
|
64396
64473
|
logger: this.deps.logger
|
|
64397
64474
|
});
|
|
64398
64475
|
}
|
|
64476
|
+
async openEventSession(personaId2, opts) {
|
|
64477
|
+
const { apiKey, gatewayUrl } = await this.credentials();
|
|
64478
|
+
return openHttpEventSession({
|
|
64479
|
+
fetchImpl: this.fetchImpl,
|
|
64480
|
+
gatewayUrl,
|
|
64481
|
+
apiKey,
|
|
64482
|
+
personaId: personaId2,
|
|
64483
|
+
engineSessionId: opts.toolSessionId,
|
|
64484
|
+
instructions: opts.instructions,
|
|
64485
|
+
purpose: opts.purpose,
|
|
64486
|
+
expectedEngine: opts.expectedEngine,
|
|
64487
|
+
effort: opts.effort,
|
|
64488
|
+
personaMode: opts.personaMode,
|
|
64489
|
+
logger: this.deps.logger
|
|
64490
|
+
});
|
|
64491
|
+
}
|
|
64399
64492
|
/**
|
|
64400
64493
|
* 看板数据(design 2026-09-23-cloud-persona-metrics §3.8):GET /metrics/<persona>?window&entry,**原样回**状态码与 body——
|
|
64401
64494
|
* 形状真源在 gateway 的 cloud-persona-metrics,daemon 只是替浏览器拿本机 api key 转一跳。拿不到 key / 连不上 / 超时 → 抛(路由折成 502)。
|
|
@@ -64433,6 +64526,149 @@ var CloudGatewayClient = class {
|
|
|
64433
64526
|
return CloudVolumeUsageSchema.parse(body.volume);
|
|
64434
64527
|
}
|
|
64435
64528
|
};
|
|
64529
|
+
function openHttpEventSession(opts) {
|
|
64530
|
+
const { fetchImpl, gatewayUrl, apiKey, personaId: personaId2, engineSessionId, instructions, purpose, effort, personaMode, expectedEngine, logger } = opts;
|
|
64531
|
+
const headers = { authorization: `Bearer ${apiKey}`, "content-type": "application/json" };
|
|
64532
|
+
const abort = new AbortController();
|
|
64533
|
+
const eventCbs = [];
|
|
64534
|
+
const controlCbs = [];
|
|
64535
|
+
const closeCbs = [];
|
|
64536
|
+
const earlyEvents = [];
|
|
64537
|
+
const earlyControls = [];
|
|
64538
|
+
let closed = false;
|
|
64539
|
+
let readyControl = null;
|
|
64540
|
+
let errorControl = null;
|
|
64541
|
+
let sessionId = null;
|
|
64542
|
+
let resolveReady;
|
|
64543
|
+
let rejectReady;
|
|
64544
|
+
const ready = new Promise((resolve9, reject) => {
|
|
64545
|
+
resolveReady = resolve9;
|
|
64546
|
+
rejectReady = reject;
|
|
64547
|
+
});
|
|
64548
|
+
void ready.catch(() => {
|
|
64549
|
+
});
|
|
64550
|
+
let sendChain = Promise.resolve();
|
|
64551
|
+
const emitControl = (control) => {
|
|
64552
|
+
if (control.kind === "ready") readyControl = control;
|
|
64553
|
+
if (control.kind === "error") errorControl = control;
|
|
64554
|
+
if (!controlCbs.length) earlyControls.push(control);
|
|
64555
|
+
for (const cb of controlCbs) cb(control);
|
|
64556
|
+
};
|
|
64557
|
+
const finish = (message) => {
|
|
64558
|
+
if (closed) return;
|
|
64559
|
+
if (message) emitControl({ kind: "error", message });
|
|
64560
|
+
closed = true;
|
|
64561
|
+
rejectReady(new Error(message ?? "event session closed"));
|
|
64562
|
+
abort.abort();
|
|
64563
|
+
for (const cb of closeCbs) cb();
|
|
64564
|
+
};
|
|
64565
|
+
void (async () => {
|
|
64566
|
+
try {
|
|
64567
|
+
const res = await fetchImpl(gatewayUrl + GATEWAY_ROUTES.eventSession(personaId2), {
|
|
64568
|
+
method: "POST",
|
|
64569
|
+
headers,
|
|
64570
|
+
body: JSON.stringify({ expectedEngine, ...engineSessionId ? { engineSessionId } : {}, ...instructions ? { instructions } : {}, ...purpose ? { purpose } : {}, ...effort ? { effort } : {}, ...personaMode ? { personaMode } : {} }),
|
|
64571
|
+
signal: abort.signal
|
|
64572
|
+
});
|
|
64573
|
+
if (!res.ok || !res.body) {
|
|
64574
|
+
let message = `gateway \u56DE ${res.status}`;
|
|
64575
|
+
try {
|
|
64576
|
+
const body = await res.json();
|
|
64577
|
+
if (typeof body.message === "string") message = body.message;
|
|
64578
|
+
if (body.error === "SESSION_VERSION_EXPIRED" && !message.includes("SESSION_VERSION_EXPIRED")) message = `SESSION_VERSION_EXPIRED: ${message}`;
|
|
64579
|
+
} catch {
|
|
64580
|
+
}
|
|
64581
|
+
finish(message);
|
|
64582
|
+
return;
|
|
64583
|
+
}
|
|
64584
|
+
const reader = res.body.getReader();
|
|
64585
|
+
const decoder = new TextDecoder();
|
|
64586
|
+
let pending = "";
|
|
64587
|
+
for (; ; ) {
|
|
64588
|
+
const { value, done } = await reader.read();
|
|
64589
|
+
if (done) break;
|
|
64590
|
+
pending += decoder.decode(value, { stream: true });
|
|
64591
|
+
const lines = pending.split("\n");
|
|
64592
|
+
pending = lines.pop() ?? "";
|
|
64593
|
+
for (const line of lines) {
|
|
64594
|
+
if (!line.trim()) continue;
|
|
64595
|
+
const data = JSON.parse(line);
|
|
64596
|
+
if (data.clawd === "events") {
|
|
64597
|
+
const events = ParsedEventSchema.array().parse(data.events);
|
|
64598
|
+
if (!eventCbs.length) earlyEvents.push(events);
|
|
64599
|
+
for (const cb of eventCbs) cb(events);
|
|
64600
|
+
continue;
|
|
64601
|
+
}
|
|
64602
|
+
const control = parseControlLine(line);
|
|
64603
|
+
if (!control) throw new Error("gateway event stream contains an unknown line");
|
|
64604
|
+
if (control.kind === "ready") {
|
|
64605
|
+
if (!control.session) throw new Error("gateway ready line has no session id");
|
|
64606
|
+
if (control.engine !== expectedEngine) {
|
|
64607
|
+
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");
|
|
64608
|
+
return;
|
|
64609
|
+
}
|
|
64610
|
+
sessionId = control.session;
|
|
64611
|
+
resolveReady();
|
|
64612
|
+
}
|
|
64613
|
+
emitControl(control);
|
|
64614
|
+
if (control.kind === "error") {
|
|
64615
|
+
finish();
|
|
64616
|
+
return;
|
|
64617
|
+
}
|
|
64618
|
+
}
|
|
64619
|
+
}
|
|
64620
|
+
finish();
|
|
64621
|
+
} catch (e) {
|
|
64622
|
+
if (!closed) {
|
|
64623
|
+
logger?.warn("cloud event stream failed", { message: e.message });
|
|
64624
|
+
finish(`\u4E91\u4E0A\u4E8B\u4EF6\u901A\u9053\u51FA\u9519\uFF1A${e.message}`);
|
|
64625
|
+
}
|
|
64626
|
+
}
|
|
64627
|
+
})();
|
|
64628
|
+
return {
|
|
64629
|
+
send(command) {
|
|
64630
|
+
const next = sendChain.then(async () => {
|
|
64631
|
+
await ready;
|
|
64632
|
+
if (closed || !sessionId) throw new Error("event session closed");
|
|
64633
|
+
const res = await fetchImpl(gatewayUrl + GATEWAY_ROUTES.eventSend(personaId2, sessionId), { method: "POST", headers, body: JSON.stringify(command) });
|
|
64634
|
+
if (!res.ok) {
|
|
64635
|
+
let message = `gateway \u56DE ${res.status}`;
|
|
64636
|
+
try {
|
|
64637
|
+
const body = await res.json();
|
|
64638
|
+
if (typeof body.message === "string") message = body.message;
|
|
64639
|
+
} catch {
|
|
64640
|
+
}
|
|
64641
|
+
finish(message);
|
|
64642
|
+
throw new Error(message);
|
|
64643
|
+
}
|
|
64644
|
+
});
|
|
64645
|
+
sendChain = next.catch(() => {
|
|
64646
|
+
});
|
|
64647
|
+
return next;
|
|
64648
|
+
},
|
|
64649
|
+
onEvents(cb) {
|
|
64650
|
+
const first = !eventCbs.length;
|
|
64651
|
+
eventCbs.push(cb);
|
|
64652
|
+
if (first) for (const events of earlyEvents.splice(0)) cb(events);
|
|
64653
|
+
},
|
|
64654
|
+
onControl(cb) {
|
|
64655
|
+
const first = !controlCbs.length;
|
|
64656
|
+
controlCbs.push(cb);
|
|
64657
|
+
if (first) for (const control of earlyControls.splice(0)) cb(control);
|
|
64658
|
+
else {
|
|
64659
|
+
if (readyControl) cb(readyControl);
|
|
64660
|
+
if (errorControl) cb(errorControl);
|
|
64661
|
+
}
|
|
64662
|
+
},
|
|
64663
|
+
onClose(cb) {
|
|
64664
|
+
closeCbs.push(cb);
|
|
64665
|
+
if (closed) cb();
|
|
64666
|
+
},
|
|
64667
|
+
close() {
|
|
64668
|
+
finish();
|
|
64669
|
+
}
|
|
64670
|
+
};
|
|
64671
|
+
}
|
|
64436
64672
|
function parseControlLine(line) {
|
|
64437
64673
|
let o2;
|
|
64438
64674
|
try {
|
|
@@ -64652,55 +64888,27 @@ function openHttpLineStream(opts) {
|
|
|
64652
64888
|
init_protocol();
|
|
64653
64889
|
|
|
64654
64890
|
// src/tools/codex-cloud-session.ts
|
|
64655
|
-
var
|
|
64656
|
-
|
|
64657
|
-
|
|
64658
|
-
|
|
64659
|
-
|
|
64660
|
-
|
|
64661
|
-
|
|
64662
|
-
|
|
64663
|
-
|
|
64664
|
-
|
|
64665
|
-
|
|
64666
|
-
|
|
64667
|
-
|
|
64668
|
-
|
|
64669
|
-
|
|
64670
|
-
|
|
64671
|
-
}
|
|
64672
|
-
return
|
|
64673
|
-
attach(t2) {
|
|
64674
|
-
if (closed) {
|
|
64675
|
-
t2.close();
|
|
64676
|
-
return;
|
|
64677
|
-
}
|
|
64678
|
-
target = t2;
|
|
64679
|
-
t2.onLine((l2) => {
|
|
64680
|
-
for (const cb of lineCbs) cb(l2);
|
|
64681
|
-
});
|
|
64682
|
-
t2.onClose(finish);
|
|
64683
|
-
for (const line of pending.splice(0)) t2.write(line);
|
|
64684
|
-
},
|
|
64685
|
-
write(line) {
|
|
64686
|
-
if (closed) return;
|
|
64687
|
-
if (target) target.write(line);
|
|
64688
|
-
else pending.push(line);
|
|
64689
|
-
},
|
|
64690
|
-
onLine(cb) {
|
|
64691
|
-
lineCbs.push(cb);
|
|
64692
|
-
},
|
|
64693
|
-
onClose(cb) {
|
|
64694
|
-
closeCbs.push(cb);
|
|
64695
|
-
if (closed) cb();
|
|
64696
|
-
},
|
|
64697
|
-
close() {
|
|
64698
|
-
if (closed) return;
|
|
64699
|
-
target?.close();
|
|
64700
|
-
finish();
|
|
64701
|
-
}
|
|
64702
|
-
};
|
|
64891
|
+
var import_node_fs39 = __toESM(require("fs"), 1);
|
|
64892
|
+
|
|
64893
|
+
// src/tools/cloud-portable-input.ts
|
|
64894
|
+
async function portableCloudInput(text, resolvers) {
|
|
64895
|
+
const markers = [...text.matchAll(/\[attachment:image:(https?:\/\/[^\]]+)\]/g)];
|
|
64896
|
+
let result = text;
|
|
64897
|
+
for (const match of markers) {
|
|
64898
|
+
const url = match[1];
|
|
64899
|
+
let dataUrl;
|
|
64900
|
+
const codex = resolvers.resolveCodexImage?.(url);
|
|
64901
|
+
if (codex?.type === "image" && codex.url.startsWith("data:")) dataUrl = codex.url;
|
|
64902
|
+
if (!dataUrl && resolvers.fetchPiImage) {
|
|
64903
|
+
const pi = await resolvers.fetchPiImage(url).catch(() => null);
|
|
64904
|
+
if (pi) dataUrl = `data:${pi.mimeType};base64,${pi.data}`;
|
|
64905
|
+
}
|
|
64906
|
+
if (dataUrl) result = result.replace(match[0], `[attachment:image:${dataUrl}]`);
|
|
64907
|
+
}
|
|
64908
|
+
return result;
|
|
64703
64909
|
}
|
|
64910
|
+
|
|
64911
|
+
// src/tools/codex-cloud-session.ts
|
|
64704
64912
|
function cloudImageInput(deps) {
|
|
64705
64913
|
return (url) => {
|
|
64706
64914
|
const secret = deps.getSignSecret?.();
|
|
@@ -64709,7 +64917,7 @@ function cloudImageInput(deps) {
|
|
|
64709
64917
|
const mime = lookupMime(p3);
|
|
64710
64918
|
if (!mime.startsWith("image/")) return null;
|
|
64711
64919
|
try {
|
|
64712
|
-
const bytes = (deps.readFile ??
|
|
64920
|
+
const bytes = (deps.readFile ?? import_node_fs39.default.readFileSync)(p3);
|
|
64713
64921
|
return { type: "image", url: `data:${mime};base64,${bytes.toString("base64")}` };
|
|
64714
64922
|
} catch (e) {
|
|
64715
64923
|
deps.logger?.warn("cloud image attachment unreadable", { path: p3, message: e.message });
|
|
@@ -64719,73 +64927,84 @@ function cloudImageInput(deps) {
|
|
|
64719
64927
|
}
|
|
64720
64928
|
function createCloudCodexSession(ctx, sink, deps) {
|
|
64721
64929
|
const personaId2 = personaIdFromCloudCwd(ctx.cwd);
|
|
64722
|
-
const stream = deferredLineStream();
|
|
64723
|
-
let resolvePaths;
|
|
64724
|
-
let rejectPaths;
|
|
64725
|
-
const paths = new Promise((resolve9, reject) => {
|
|
64726
|
-
resolvePaths = resolve9;
|
|
64727
|
-
rejectPaths = reject;
|
|
64728
|
-
});
|
|
64729
|
-
paths.catch(() => {
|
|
64730
|
-
});
|
|
64731
|
-
stream.onClose(() => rejectPaths(new Error("\u4E91\u4E0A\u901A\u9053\u5728 ready \u4E4B\u524D\u5173\u4E86\uFF0C\u62FF\u4E0D\u5230 Pod \u8DEF\u5F84")));
|
|
64732
64930
|
let channel = null;
|
|
64733
|
-
|
|
64734
|
-
|
|
64735
|
-
|
|
64736
|
-
|
|
64737
|
-
|
|
64738
|
-
|
|
64739
|
-
|
|
64740
|
-
|
|
64741
|
-
if (!ctx.toolSessionId || p3.model) return params;
|
|
64742
|
-
const config = await client.request("config/read", {});
|
|
64743
|
-
if (config?.config?.model) return { ...params, model: config.config.model };
|
|
64744
|
-
const list = await client.request("model/list", {});
|
|
64745
|
-
const selected = list?.data?.find((m3) => m3.isDefault);
|
|
64746
|
-
const current = selected?.id || selected?.model;
|
|
64747
|
-
if (!current) throw new Error("\u65E0\u6CD5\u786E\u5B9A\u5F53\u524D Codex \u9ED8\u8BA4\u6A21\u578B\uFF0C\u62D2\u7EDD\u6CBF\u7528\u65E7\u4F1A\u8BDD\u6A21\u578B");
|
|
64748
|
-
return { ...params, model: current };
|
|
64749
|
-
},
|
|
64750
|
-
imageInput: cloudImageInput(deps),
|
|
64751
|
-
// skills 在 Pod 里由 persona 目录自带,本机路径对它没意义
|
|
64752
|
-
// 「让对端走人」= 断开下行流,gateway 收到就删 Job;信号对 Pod 没有意义
|
|
64753
|
-
kill: () => stream.close(),
|
|
64754
|
-
// 云 persona 运行看板(design 2026-09-23-cloud-persona-metrics §3.7):提问那一行带「一轮开始」头,轮末镜像顺带报这一轮的结果
|
|
64755
|
-
onTurnStarting: () => channel?.markNextLineTurnStart(),
|
|
64756
|
-
// 轮末镜像带上这一轮的结果与首字节(design 2026-09-23-cloud-persona-metrics §3.7)
|
|
64757
|
-
onTurnCompleted: (outcome, afterFirstByteMs) => {
|
|
64758
|
-
if (!ctx.titleOnly) void channel?.mirror({ outcome, ...afterFirstByteMs !== void 0 ? { afterFirstByteMs } : {} });
|
|
64759
|
-
},
|
|
64760
|
-
now: deps.now
|
|
64761
|
-
});
|
|
64931
|
+
let closed = false;
|
|
64932
|
+
let exited = false;
|
|
64933
|
+
const exit = () => {
|
|
64934
|
+
if (!exited) {
|
|
64935
|
+
exited = true;
|
|
64936
|
+
sink.onExit(null);
|
|
64937
|
+
}
|
|
64938
|
+
};
|
|
64762
64939
|
if (!personaId2) {
|
|
64763
64940
|
queueMicrotask(() => {
|
|
64764
64941
|
sink.onError(`cloud session has no persona id (cwd=${ctx.cwd})`);
|
|
64765
|
-
|
|
64942
|
+
exit();
|
|
64766
64943
|
});
|
|
64767
|
-
return
|
|
64768
|
-
|
|
64769
|
-
|
|
64770
|
-
(
|
|
64771
|
-
|
|
64944
|
+
return { startTurn() {
|
|
64945
|
+
}, respondPermission() {
|
|
64946
|
+
}, interrupt() {
|
|
64947
|
+
}, async stop() {
|
|
64948
|
+
} };
|
|
64949
|
+
}
|
|
64950
|
+
const opened = deps.client.openEventSession(personaId2, {
|
|
64951
|
+
expectedEngine: "codex",
|
|
64952
|
+
...ctx.toolSessionId ? { toolSessionId: ctx.toolSessionId } : {},
|
|
64953
|
+
...ctx.extraSystemPrompt ? { instructions: ctx.extraSystemPrompt } : {},
|
|
64954
|
+
...ctx.effort ? { effort: ctx.effort } : {},
|
|
64955
|
+
...ctx.personaMode ? { personaMode: ctx.personaMode } : {},
|
|
64956
|
+
...ctx.titleOnly ? { purpose: "title" } : {}
|
|
64957
|
+
}).then(
|
|
64958
|
+
(opened2) => {
|
|
64959
|
+
channel = opened2;
|
|
64960
|
+
channel.onEvents((events) => sink.pushEvents(events));
|
|
64772
64961
|
channel.onControl((c2) => {
|
|
64773
|
-
if (c2.kind === "
|
|
64774
|
-
resolvePaths({ personaDir: c2.personaDir, workDir: c2.workDir, model: c2.model });
|
|
64775
|
-
} else if (c2.kind === "queued") {
|
|
64962
|
+
if (c2.kind === "queued") {
|
|
64776
64963
|
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` }]);
|
|
64777
64964
|
} else if (c2.kind === "error") {
|
|
64778
64965
|
sink.onError(`\u4E91\u4E0A persona \u8D77\u4E0D\u6765\uFF1A${c2.message}`);
|
|
64779
64966
|
}
|
|
64780
64967
|
});
|
|
64781
|
-
|
|
64968
|
+
channel.onClose(exit);
|
|
64969
|
+
if (closed) channel.close();
|
|
64970
|
+
return channel;
|
|
64782
64971
|
},
|
|
64783
64972
|
(e) => {
|
|
64784
64973
|
sink.onError(e instanceof CloudApiKeyRequiredError ? e.message : `\u8FDE\u4E0D\u4E0A\u4E91 gateway\uFF1A${e.message}`);
|
|
64785
|
-
|
|
64974
|
+
exit();
|
|
64975
|
+
throw e;
|
|
64786
64976
|
}
|
|
64787
64977
|
);
|
|
64788
|
-
|
|
64978
|
+
void opened.catch(() => {
|
|
64979
|
+
});
|
|
64980
|
+
let sendChain = Promise.resolve();
|
|
64981
|
+
const send2 = (command) => {
|
|
64982
|
+
sendChain = sendChain.then(command).catch((e) => {
|
|
64983
|
+
if (!closed && !exited) sink.onError(`\u4E91\u4E0A\u4F1A\u8BDD\u4E0A\u884C\u5931\u8D25\uFF1A${e.message}`);
|
|
64984
|
+
});
|
|
64985
|
+
};
|
|
64986
|
+
return {
|
|
64987
|
+
startTurn(text) {
|
|
64988
|
+
send2(async () => {
|
|
64989
|
+
const ch = await opened;
|
|
64990
|
+
if (closed) return;
|
|
64991
|
+
const portable = await portableCloudInput(text, { resolveCodexImage: cloudImageInput(deps) });
|
|
64992
|
+
await ch.send({ command: "turn", text: portable });
|
|
64993
|
+
});
|
|
64994
|
+
},
|
|
64995
|
+
respondPermission(requestId, allow) {
|
|
64996
|
+
send2(async () => (await opened).send({ command: "permission", requestId, allow }));
|
|
64997
|
+
},
|
|
64998
|
+
interrupt() {
|
|
64999
|
+
send2(async () => (await opened).send({ command: "interrupt" }));
|
|
65000
|
+
},
|
|
65001
|
+
async stop() {
|
|
65002
|
+
closed = true;
|
|
65003
|
+
const ch = await opened.catch(() => null);
|
|
65004
|
+
ch?.close();
|
|
65005
|
+
exit();
|
|
65006
|
+
}
|
|
65007
|
+
};
|
|
64789
65008
|
}
|
|
64790
65009
|
|
|
64791
65010
|
// src/tools/codex-cloud.ts
|
|
@@ -64856,7 +65075,7 @@ init_protocol();
|
|
|
64856
65075
|
|
|
64857
65076
|
// src/tools/pi.ts
|
|
64858
65077
|
var import_node_child_process12 = require("child_process");
|
|
64859
|
-
var
|
|
65078
|
+
var import_node_fs41 = __toESM(require("fs"), 1);
|
|
64860
65079
|
init_protocol();
|
|
64861
65080
|
|
|
64862
65081
|
// src/tools/pi-rpc-client.ts
|
|
@@ -64957,8 +65176,8 @@ var PiRpcClient = class {
|
|
|
64957
65176
|
// src/tools/pi-session.ts
|
|
64958
65177
|
var import_node_child_process11 = require("child_process");
|
|
64959
65178
|
var import_node_crypto12 = require("crypto");
|
|
64960
|
-
var
|
|
64961
|
-
var
|
|
65179
|
+
var import_node_fs40 = __toESM(require("fs"), 1);
|
|
65180
|
+
var import_node_path44 = __toESM(require("path"), 1);
|
|
64962
65181
|
|
|
64963
65182
|
// src/tools/pi-events.ts
|
|
64964
65183
|
init_protocol();
|
|
@@ -65230,8 +65449,8 @@ ${dirs.map((d2) => `- ${d2}`).join("\n")}`;
|
|
|
65230
65449
|
function createPiSession(ctx, sink, deps = {}) {
|
|
65231
65450
|
const cmd = process.env.PI_BIN ?? "pi";
|
|
65232
65451
|
const sessionId = ctx.toolSessionId ?? (0, import_node_crypto12.randomUUID)();
|
|
65233
|
-
const skillsDir =
|
|
65234
|
-
const exists = deps.skillsDirExists ?? ((d2) =>
|
|
65452
|
+
const skillsDir = import_node_path44.default.join(ctx.cwd, ".claude", "skills");
|
|
65453
|
+
const exists = deps.skillsDirExists ?? ((d2) => import_node_fs40.default.existsSync(d2));
|
|
65235
65454
|
const args = buildPiArgs(ctx, {
|
|
65236
65455
|
sessionId,
|
|
65237
65456
|
skillsDir: exists(skillsDir) ? skillsDir : void 0,
|
|
@@ -65293,10 +65512,10 @@ var PI_DEFAULT_MODEL_ENTRY = {
|
|
|
65293
65512
|
};
|
|
65294
65513
|
var PI_FULL_ACCESS = { id: "never", label: "Full Access", description: "pi \u65E0\u5BA1\u6279\uFF1A\u4ECE\u4E0D\u8BE2\u95EE\uFF0C\u81EA\u4E3B\u6267\u884C" };
|
|
65295
65514
|
async function probePi(env = process.env) {
|
|
65296
|
-
if (env.PI_BIN &&
|
|
65515
|
+
if (env.PI_BIN && import_node_fs41.default.existsSync(env.PI_BIN)) return { available: true, path: env.PI_BIN };
|
|
65297
65516
|
try {
|
|
65298
65517
|
const out = (0, import_node_child_process12.execFileSync)("which", ["pi"], { encoding: "utf8" }).trim();
|
|
65299
|
-
if (out &&
|
|
65518
|
+
if (out && import_node_fs41.default.existsSync(out)) return { available: true, path: out };
|
|
65300
65519
|
} catch {
|
|
65301
65520
|
}
|
|
65302
65521
|
return { available: false };
|
|
@@ -65473,34 +65692,30 @@ function cloudPiInstructions(ctx) {
|
|
|
65473
65692
|
function createCloudPiSession(ctx, sink, deps) {
|
|
65474
65693
|
const personaId2 = personaIdFromCloudCwd(ctx.cwd);
|
|
65475
65694
|
const sessionId = ctx.toolSessionId ?? (0, import_node_crypto13.randomUUID)();
|
|
65476
|
-
const stream = deferredLineStream();
|
|
65477
65695
|
let channel = null;
|
|
65478
|
-
|
|
65479
|
-
|
|
65480
|
-
|
|
65481
|
-
|
|
65482
|
-
|
|
65483
|
-
|
|
65484
|
-
|
|
65485
|
-
|
|
65486
|
-
// 云 persona 运行看板(design 2026-09-23-cloud-persona-metrics §3.7):提问那一行带「一轮开始」头,轮末镜像顺带报这一轮的结果
|
|
65487
|
-
onTurnStarting: () => channel?.markNextLineTurnStart(),
|
|
65488
|
-
// 轮末镜像带上这一轮的结果与首字节(design 2026-09-23-cloud-persona-metrics §3.7)
|
|
65489
|
-
onTurnCompleted: (outcome, afterFirstByteMs) => {
|
|
65490
|
-
if (!ctx.titleOnly) void channel?.mirror({ outcome, ...afterFirstByteMs !== void 0 ? { afterFirstByteMs } : {} });
|
|
65491
|
-
},
|
|
65492
|
-
now: deps.now
|
|
65493
|
-
});
|
|
65696
|
+
let closed = false;
|
|
65697
|
+
let exited = false;
|
|
65698
|
+
const exit = () => {
|
|
65699
|
+
if (!exited) {
|
|
65700
|
+
exited = true;
|
|
65701
|
+
sink.onExit(null);
|
|
65702
|
+
}
|
|
65703
|
+
};
|
|
65494
65704
|
if (!personaId2) {
|
|
65495
65705
|
queueMicrotask(() => {
|
|
65496
65706
|
sink.onError(`cloud session has no persona id (cwd=${ctx.cwd})`);
|
|
65497
|
-
|
|
65707
|
+
exit();
|
|
65498
65708
|
});
|
|
65499
|
-
return
|
|
65500
|
-
|
|
65501
|
-
|
|
65502
|
-
(
|
|
65503
|
-
|
|
65709
|
+
return { startTurn() {
|
|
65710
|
+
}, respondPermission() {
|
|
65711
|
+
}, interrupt() {
|
|
65712
|
+
}, async stop() {
|
|
65713
|
+
} };
|
|
65714
|
+
}
|
|
65715
|
+
const opened = deps.client.openEventSession(personaId2, { expectedEngine: "pi", toolSessionId: sessionId, instructions: ctx.titleOnly ? "" : cloudPiInstructions(ctx), ...ctx.titleOnly ? { purpose: "title" } : {} }).then(
|
|
65716
|
+
(opened2) => {
|
|
65717
|
+
channel = opened2;
|
|
65718
|
+
channel.onEvents((events) => sink.pushEvents(events));
|
|
65504
65719
|
channel.onControl((c2) => {
|
|
65505
65720
|
if (c2.kind === "queued") {
|
|
65506
65721
|
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` }]);
|
|
@@ -65508,14 +65723,46 @@ function createCloudPiSession(ctx, sink, deps) {
|
|
|
65508
65723
|
sink.onError(`\u4E91\u4E0A persona \u8D77\u4E0D\u6765\uFF1A${c2.message}`);
|
|
65509
65724
|
}
|
|
65510
65725
|
});
|
|
65511
|
-
|
|
65726
|
+
channel.onClose(exit);
|
|
65727
|
+
if (closed) channel.close();
|
|
65728
|
+
return channel;
|
|
65512
65729
|
},
|
|
65513
65730
|
(e) => {
|
|
65514
65731
|
sink.onError(e instanceof CloudApiKeyRequiredError ? e.message : `\u8FDE\u4E0D\u4E0A\u4E91 gateway\uFF1A${e.message}`);
|
|
65515
|
-
|
|
65732
|
+
exit();
|
|
65733
|
+
throw e;
|
|
65516
65734
|
}
|
|
65517
65735
|
);
|
|
65518
|
-
|
|
65736
|
+
void opened.catch(() => {
|
|
65737
|
+
});
|
|
65738
|
+
let sendChain = Promise.resolve();
|
|
65739
|
+
const send2 = (command) => {
|
|
65740
|
+
sendChain = sendChain.then(command).catch((e) => {
|
|
65741
|
+
if (!closed && !exited) sink.onError(`\u4E91\u4E0A\u4F1A\u8BDD\u4E0A\u884C\u5931\u8D25\uFF1A${e.message}`);
|
|
65742
|
+
});
|
|
65743
|
+
};
|
|
65744
|
+
return {
|
|
65745
|
+
startTurn(text) {
|
|
65746
|
+
send2(async () => {
|
|
65747
|
+
const ch = await opened;
|
|
65748
|
+
if (closed) return;
|
|
65749
|
+
const portable = await portableCloudInput(text, { fetchPiImage: deps.fetchImage ?? makeImageFetcher() });
|
|
65750
|
+
await ch.send({ command: "turn", text: portable });
|
|
65751
|
+
});
|
|
65752
|
+
},
|
|
65753
|
+
respondPermission(requestId, allow) {
|
|
65754
|
+
send2(async () => (await opened).send({ command: "permission", requestId, allow }));
|
|
65755
|
+
},
|
|
65756
|
+
interrupt() {
|
|
65757
|
+
send2(async () => (await opened).send({ command: "interrupt" }));
|
|
65758
|
+
},
|
|
65759
|
+
async stop() {
|
|
65760
|
+
closed = true;
|
|
65761
|
+
const ch = await opened.catch(() => null);
|
|
65762
|
+
ch?.close();
|
|
65763
|
+
exit();
|
|
65764
|
+
}
|
|
65765
|
+
};
|
|
65519
65766
|
}
|
|
65520
65767
|
|
|
65521
65768
|
// src/tools/pi-cloud.ts
|
|
@@ -65585,7 +65832,7 @@ var CloudPiAdapter = class {
|
|
|
65585
65832
|
init_protocol();
|
|
65586
65833
|
|
|
65587
65834
|
// src/tools/codex-skills.ts
|
|
65588
|
-
var
|
|
65835
|
+
var import_node_path45 = __toESM(require("path"), 1);
|
|
65589
65836
|
function str4(v3) {
|
|
65590
65837
|
return typeof v3 === "string" ? v3 : void 0;
|
|
65591
65838
|
}
|
|
@@ -65622,7 +65869,7 @@ async function listCodexSkills(cwd, deps = {}) {
|
|
|
65622
65869
|
// 先写 extraRoots 再写 list(stdio 按写入顺序处理,fire-and-forget 不 await 回包;
|
|
65623
65870
|
// codex-session.ts ready 序列同款,两处保持一致)。失败不阻塞 list。
|
|
65624
65871
|
beforeRequest: (client) => {
|
|
65625
|
-
void client.request("skills/extraRoots/set", { extraRoots: [
|
|
65872
|
+
void client.request("skills/extraRoots/set", { extraRoots: [import_node_path45.default.join(cwd, ".claude", "skills")] }).catch(() => void 0);
|
|
65626
65873
|
}
|
|
65627
65874
|
});
|
|
65628
65875
|
return mapSkillsListResponse(res);
|
|
@@ -65696,23 +65943,23 @@ function rec4(v3) {
|
|
|
65696
65943
|
}
|
|
65697
65944
|
|
|
65698
65945
|
// src/workspace/browser.ts
|
|
65699
|
-
var
|
|
65700
|
-
var
|
|
65701
|
-
var
|
|
65946
|
+
var import_node_fs42 = __toESM(require("fs"), 1);
|
|
65947
|
+
var import_node_os15 = __toESM(require("os"), 1);
|
|
65948
|
+
var import_node_path46 = __toESM(require("path"), 1);
|
|
65702
65949
|
init_protocol();
|
|
65703
65950
|
var MAX_FILE_BYTES2 = 2 * 1024 * 1024;
|
|
65704
65951
|
function resolveInsideCwd(cwd, subpath) {
|
|
65705
|
-
const absCwd =
|
|
65706
|
-
const joined =
|
|
65707
|
-
const rel =
|
|
65708
|
-
if (rel.startsWith("..") ||
|
|
65952
|
+
const absCwd = import_node_path46.default.resolve(cwd);
|
|
65953
|
+
const joined = import_node_path46.default.resolve(absCwd, subpath ?? ".");
|
|
65954
|
+
const rel = import_node_path46.default.relative(absCwd, joined);
|
|
65955
|
+
if (rel.startsWith("..") || import_node_path46.default.isAbsolute(rel)) {
|
|
65709
65956
|
throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
|
|
65710
65957
|
}
|
|
65711
65958
|
return joined;
|
|
65712
65959
|
}
|
|
65713
65960
|
function ensureCwd(cwd) {
|
|
65714
65961
|
try {
|
|
65715
|
-
const stat =
|
|
65962
|
+
const stat = import_node_fs42.default.statSync(cwd);
|
|
65716
65963
|
if (!stat.isDirectory()) {
|
|
65717
65964
|
throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${cwd}`);
|
|
65718
65965
|
}
|
|
@@ -65723,10 +65970,10 @@ function ensureCwd(cwd) {
|
|
|
65723
65970
|
}
|
|
65724
65971
|
var WorkspaceBrowser = class {
|
|
65725
65972
|
list(args) {
|
|
65726
|
-
const cwd = args.cwd && args.cwd.length > 0 ? args.cwd :
|
|
65973
|
+
const cwd = args.cwd && args.cwd.length > 0 ? args.cwd : import_node_os15.default.homedir();
|
|
65727
65974
|
ensureCwd(cwd);
|
|
65728
65975
|
const full = resolveInsideCwd(cwd, args.path);
|
|
65729
|
-
const dirents =
|
|
65976
|
+
const dirents = import_node_fs42.default.readdirSync(full, { withFileTypes: true });
|
|
65730
65977
|
const entries = [];
|
|
65731
65978
|
for (const d2 of dirents) {
|
|
65732
65979
|
if (!args.showHidden && d2.name.startsWith(".")) continue;
|
|
@@ -65736,7 +65983,7 @@ var WorkspaceBrowser = class {
|
|
|
65736
65983
|
mtime: ""
|
|
65737
65984
|
};
|
|
65738
65985
|
try {
|
|
65739
|
-
const st2 =
|
|
65986
|
+
const st2 = import_node_fs42.default.statSync(import_node_path46.default.join(full, d2.name));
|
|
65740
65987
|
entry.mtime = new Date(st2.mtimeMs).toISOString();
|
|
65741
65988
|
if (d2.isFile()) entry.size = st2.size;
|
|
65742
65989
|
} catch {
|
|
@@ -65752,14 +65999,14 @@ var WorkspaceBrowser = class {
|
|
|
65752
65999
|
read(args) {
|
|
65753
66000
|
ensureCwd(args.cwd);
|
|
65754
66001
|
const full = resolveInsideCwd(args.cwd, args.path);
|
|
65755
|
-
const st2 =
|
|
66002
|
+
const st2 = import_node_fs42.default.statSync(full);
|
|
65756
66003
|
if (!st2.isFile()) {
|
|
65757
66004
|
throw new ClawdError(ERROR_CODES.INVALID_PATH, `not a file: ${args.path}`);
|
|
65758
66005
|
}
|
|
65759
66006
|
if (st2.size > MAX_FILE_BYTES2) {
|
|
65760
66007
|
throw new ClawdError(ERROR_CODES.FILE_TOO_LARGE, `file > ${MAX_FILE_BYTES2} bytes`);
|
|
65761
66008
|
}
|
|
65762
|
-
const buf =
|
|
66009
|
+
const buf = import_node_fs42.default.readFileSync(full);
|
|
65763
66010
|
const isBinary = buf.includes(0);
|
|
65764
66011
|
if (isBinary) {
|
|
65765
66012
|
return {
|
|
@@ -65781,20 +66028,20 @@ var WorkspaceBrowser = class {
|
|
|
65781
66028
|
};
|
|
65782
66029
|
|
|
65783
66030
|
// src/skills/agents-scanner.ts
|
|
65784
|
-
var
|
|
65785
|
-
var
|
|
65786
|
-
var
|
|
66031
|
+
var import_node_fs43 = __toESM(require("fs"), 1);
|
|
66032
|
+
var import_node_os16 = __toESM(require("os"), 1);
|
|
66033
|
+
var import_node_path47 = __toESM(require("path"), 1);
|
|
65787
66034
|
var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
|
|
65788
66035
|
function isDirLikeSync2(p3) {
|
|
65789
66036
|
try {
|
|
65790
|
-
return
|
|
66037
|
+
return import_node_fs43.default.statSync(p3).isDirectory();
|
|
65791
66038
|
} catch {
|
|
65792
66039
|
return false;
|
|
65793
66040
|
}
|
|
65794
66041
|
}
|
|
65795
66042
|
function fileExistsSync(p3) {
|
|
65796
66043
|
try {
|
|
65797
|
-
return
|
|
66044
|
+
return import_node_fs43.default.statSync(p3).isFile();
|
|
65798
66045
|
} catch {
|
|
65799
66046
|
return false;
|
|
65800
66047
|
}
|
|
@@ -65802,7 +66049,7 @@ function fileExistsSync(p3) {
|
|
|
65802
66049
|
function parseAgentFile(filePath) {
|
|
65803
66050
|
let content;
|
|
65804
66051
|
try {
|
|
65805
|
-
content =
|
|
66052
|
+
content = import_node_fs43.default.readFileSync(filePath, "utf8");
|
|
65806
66053
|
} catch {
|
|
65807
66054
|
return {};
|
|
65808
66055
|
}
|
|
@@ -65815,16 +66062,16 @@ function parseAgentFile(filePath) {
|
|
|
65815
66062
|
function scanAgentsDir(dir, source, seen, out) {
|
|
65816
66063
|
let entries;
|
|
65817
66064
|
try {
|
|
65818
|
-
entries =
|
|
66065
|
+
entries = import_node_fs43.default.readdirSync(dir, { withFileTypes: true });
|
|
65819
66066
|
} catch {
|
|
65820
66067
|
return;
|
|
65821
66068
|
}
|
|
65822
66069
|
for (const ent of entries) {
|
|
65823
66070
|
if (!ent.name.endsWith(".md")) continue;
|
|
65824
|
-
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(
|
|
66071
|
+
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path47.default.join(dir, ent.name)))) {
|
|
65825
66072
|
continue;
|
|
65826
66073
|
}
|
|
65827
|
-
const filePath =
|
|
66074
|
+
const filePath = import_node_path47.default.join(dir, ent.name);
|
|
65828
66075
|
const baseName = ent.name.replace(/\.md$/, "");
|
|
65829
66076
|
if (seen.has(baseName)) continue;
|
|
65830
66077
|
seen.add(baseName);
|
|
@@ -65842,12 +66089,12 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
65842
66089
|
function walk2(dir, namespaces) {
|
|
65843
66090
|
let entries;
|
|
65844
66091
|
try {
|
|
65845
|
-
entries =
|
|
66092
|
+
entries = import_node_fs43.default.readdirSync(dir, { withFileTypes: true });
|
|
65846
66093
|
} catch {
|
|
65847
66094
|
return;
|
|
65848
66095
|
}
|
|
65849
66096
|
for (const ent of entries) {
|
|
65850
|
-
const childPath =
|
|
66097
|
+
const childPath = import_node_path47.default.join(dir, ent.name);
|
|
65851
66098
|
if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
|
|
65852
66099
|
walk2(childPath, [...namespaces, ent.name]);
|
|
65853
66100
|
continue;
|
|
@@ -65872,13 +66119,13 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
65872
66119
|
walk2(root, []);
|
|
65873
66120
|
}
|
|
65874
66121
|
function readInstalledPlugins2(home) {
|
|
65875
|
-
const pluginsDir =
|
|
65876
|
-
const v22 =
|
|
65877
|
-
const v1 =
|
|
66122
|
+
const pluginsDir = import_node_path47.default.join(home, ".claude", "plugins");
|
|
66123
|
+
const v22 = import_node_path47.default.join(pluginsDir, "installed_plugins_v2.json");
|
|
66124
|
+
const v1 = import_node_path47.default.join(pluginsDir, "installed_plugins.json");
|
|
65878
66125
|
let raw = null;
|
|
65879
66126
|
for (const candidate of [v22, v1]) {
|
|
65880
66127
|
try {
|
|
65881
|
-
raw =
|
|
66128
|
+
raw = import_node_fs43.default.readFileSync(candidate, "utf8");
|
|
65882
66129
|
break;
|
|
65883
66130
|
} catch {
|
|
65884
66131
|
}
|
|
@@ -65903,19 +66150,19 @@ function readInstalledPlugins2(home) {
|
|
|
65903
66150
|
return out;
|
|
65904
66151
|
}
|
|
65905
66152
|
function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
|
|
65906
|
-
let cur =
|
|
65907
|
-
const fsRoot =
|
|
66153
|
+
let cur = import_node_path47.default.resolve(startCwd);
|
|
66154
|
+
const fsRoot = import_node_path47.default.parse(cur).root;
|
|
65908
66155
|
while (true) {
|
|
65909
|
-
scanAgentsDir(
|
|
66156
|
+
scanAgentsDir(import_node_path47.default.join(cur, ".claude", "agents"), "project", seen, out);
|
|
65910
66157
|
let hasGit = false;
|
|
65911
66158
|
try {
|
|
65912
|
-
hasGit =
|
|
66159
|
+
hasGit = import_node_fs43.default.existsSync(import_node_path47.default.join(cur, ".git"));
|
|
65913
66160
|
} catch {
|
|
65914
66161
|
}
|
|
65915
66162
|
if (hasGit) return;
|
|
65916
66163
|
if (cur === home) return;
|
|
65917
66164
|
if (cur === fsRoot) return;
|
|
65918
|
-
const parent =
|
|
66165
|
+
const parent = import_node_path47.default.dirname(cur);
|
|
65919
66166
|
if (parent === cur) return;
|
|
65920
66167
|
cur = parent;
|
|
65921
66168
|
}
|
|
@@ -65925,7 +66172,7 @@ var AgentsScanner = class {
|
|
|
65925
66172
|
extraPluginRoots;
|
|
65926
66173
|
policyDir;
|
|
65927
66174
|
constructor(opts = {}) {
|
|
65928
|
-
this.home = opts.home ?? process.env.CLAUDE_CONFIG_DIR ??
|
|
66175
|
+
this.home = opts.home ?? process.env.CLAUDE_CONFIG_DIR ?? import_node_os16.default.homedir();
|
|
65929
66176
|
this.extraPluginRoots = opts.extraPluginRoots ?? [];
|
|
65930
66177
|
if (opts.policyDir !== void 0) {
|
|
65931
66178
|
this.policyDir = opts.policyDir;
|
|
@@ -65950,7 +66197,7 @@ var AgentsScanner = class {
|
|
|
65950
66197
|
}
|
|
65951
66198
|
const fsBlock = [];
|
|
65952
66199
|
scanAgentsDir(
|
|
65953
|
-
|
|
66200
|
+
import_node_path47.default.join(this.home, ".claude", "agents"),
|
|
65954
66201
|
"global",
|
|
65955
66202
|
seen,
|
|
65956
66203
|
fsBlock
|
|
@@ -65964,7 +66211,7 @@ var AgentsScanner = class {
|
|
|
65964
66211
|
...this.extraPluginRoots
|
|
65965
66212
|
];
|
|
65966
66213
|
for (const { name, root } of plugins) {
|
|
65967
|
-
const agentsRoot =
|
|
66214
|
+
const agentsRoot = import_node_path47.default.join(root, "agents");
|
|
65968
66215
|
scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
|
|
65969
66216
|
}
|
|
65970
66217
|
return [...builtinBlock, ...fsBlock];
|
|
@@ -65972,28 +66219,28 @@ var AgentsScanner = class {
|
|
|
65972
66219
|
};
|
|
65973
66220
|
|
|
65974
66221
|
// src/observer/session-observer.ts
|
|
65975
|
-
var
|
|
65976
|
-
var
|
|
65977
|
-
var
|
|
66222
|
+
var import_node_fs45 = __toESM(require("fs"), 1);
|
|
66223
|
+
var import_node_os18 = __toESM(require("os"), 1);
|
|
66224
|
+
var import_node_path49 = __toESM(require("path"), 1);
|
|
65978
66225
|
init_claude_history();
|
|
65979
66226
|
|
|
65980
66227
|
// src/observer/subagent-meta-observer.ts
|
|
65981
|
-
var
|
|
65982
|
-
var
|
|
65983
|
-
var
|
|
66228
|
+
var import_node_fs44 = __toESM(require("fs"), 1);
|
|
66229
|
+
var import_node_os17 = __toESM(require("os"), 1);
|
|
66230
|
+
var import_node_path48 = __toESM(require("path"), 1);
|
|
65984
66231
|
init_claude_history();
|
|
65985
66232
|
var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
|
|
65986
66233
|
var SubagentMetaObserver = class {
|
|
65987
66234
|
constructor(opts) {
|
|
65988
66235
|
this.opts = opts;
|
|
65989
|
-
this.home = opts.home ??
|
|
66236
|
+
this.home = opts.home ?? import_node_os17.default.homedir();
|
|
65990
66237
|
}
|
|
65991
66238
|
opts;
|
|
65992
66239
|
home;
|
|
65993
66240
|
watches = /* @__PURE__ */ new Map();
|
|
65994
66241
|
// public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
|
|
65995
66242
|
resolveSubagentDir(cwd, toolSessionId) {
|
|
65996
|
-
return
|
|
66243
|
+
return import_node_path48.default.join(
|
|
65997
66244
|
this.home,
|
|
65998
66245
|
".claude",
|
|
65999
66246
|
"projects",
|
|
@@ -66023,7 +66270,7 @@ var SubagentMetaObserver = class {
|
|
|
66023
66270
|
attachWatcher(w3) {
|
|
66024
66271
|
if (w3.watcher) return;
|
|
66025
66272
|
try {
|
|
66026
|
-
w3.watcher =
|
|
66273
|
+
w3.watcher = import_node_fs44.default.watch(w3.dirPath, { persistent: false }, (_evt, name) => {
|
|
66027
66274
|
if (!name) return;
|
|
66028
66275
|
const m3 = META_RE.exec(String(name));
|
|
66029
66276
|
if (!m3) return;
|
|
@@ -66035,7 +66282,7 @@ var SubagentMetaObserver = class {
|
|
|
66035
66282
|
scan(w3) {
|
|
66036
66283
|
let entries;
|
|
66037
66284
|
try {
|
|
66038
|
-
entries =
|
|
66285
|
+
entries = import_node_fs44.default.readdirSync(w3.dirPath);
|
|
66039
66286
|
} catch {
|
|
66040
66287
|
return;
|
|
66041
66288
|
}
|
|
@@ -66049,10 +66296,10 @@ var SubagentMetaObserver = class {
|
|
|
66049
66296
|
if (!m3) return;
|
|
66050
66297
|
const agentId = m3[1];
|
|
66051
66298
|
if (w3.emitted.has(agentId)) return;
|
|
66052
|
-
const file =
|
|
66299
|
+
const file = import_node_path48.default.join(w3.dirPath, name);
|
|
66053
66300
|
let raw;
|
|
66054
66301
|
try {
|
|
66055
|
-
raw =
|
|
66302
|
+
raw = import_node_fs44.default.readFileSync(file, "utf8");
|
|
66056
66303
|
} catch {
|
|
66057
66304
|
return;
|
|
66058
66305
|
}
|
|
@@ -66097,7 +66344,7 @@ var SubagentMetaObserver = class {
|
|
|
66097
66344
|
var SessionObserver = class {
|
|
66098
66345
|
constructor(opts) {
|
|
66099
66346
|
this.opts = opts;
|
|
66100
|
-
this.home = opts.home ??
|
|
66347
|
+
this.home = opts.home ?? import_node_os18.default.homedir();
|
|
66101
66348
|
this.metaObserver = opts.enableSubagentMetaObserver ? new SubagentMetaObserver({ home: this.home, onEvent: opts.onEvent }) : null;
|
|
66102
66349
|
}
|
|
66103
66350
|
opts;
|
|
@@ -66109,14 +66356,14 @@ var SessionObserver = class {
|
|
|
66109
66356
|
metaObserver;
|
|
66110
66357
|
resolveJsonlPath(cwd, toolSessionId, override) {
|
|
66111
66358
|
if (override) return override;
|
|
66112
|
-
return
|
|
66359
|
+
return import_node_path49.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
|
|
66113
66360
|
}
|
|
66114
66361
|
start(args) {
|
|
66115
66362
|
this.stop(args.sessionId);
|
|
66116
66363
|
const filePath = this.resolveJsonlPath(args.cwd, args.toolSessionId, args.jsonlPath);
|
|
66117
66364
|
let size = 0;
|
|
66118
66365
|
try {
|
|
66119
|
-
size =
|
|
66366
|
+
size = import_node_fs45.default.statSync(filePath).size;
|
|
66120
66367
|
} catch {
|
|
66121
66368
|
}
|
|
66122
66369
|
const w3 = {
|
|
@@ -66129,16 +66376,16 @@ var SessionObserver = class {
|
|
|
66129
66376
|
adapter: args.adapter,
|
|
66130
66377
|
prevIsRejectSentinel: false,
|
|
66131
66378
|
toolSessionId: args.toolSessionId,
|
|
66132
|
-
sawFile:
|
|
66379
|
+
sawFile: import_node_fs45.default.existsSync(filePath),
|
|
66133
66380
|
lastRelocateScanMs: 0,
|
|
66134
66381
|
pendingCwdDerive: false,
|
|
66135
66382
|
lastDeriveMs: 0
|
|
66136
66383
|
};
|
|
66137
66384
|
try {
|
|
66138
|
-
|
|
66385
|
+
import_node_fs45.default.mkdirSync(import_node_path49.default.dirname(filePath), { recursive: true });
|
|
66139
66386
|
} catch {
|
|
66140
66387
|
}
|
|
66141
|
-
w3.watcher =
|
|
66388
|
+
w3.watcher = import_node_fs45.default.watch(import_node_path49.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
|
|
66142
66389
|
if (!changedName || !w3.filePath.endsWith(changedName)) return;
|
|
66143
66390
|
this.poll(w3);
|
|
66144
66391
|
});
|
|
@@ -66161,7 +66408,7 @@ var SessionObserver = class {
|
|
|
66161
66408
|
// 异常静默吞,不阻塞 watcher 启动
|
|
66162
66409
|
hydrateMetaTail(w3, maxLines = 200) {
|
|
66163
66410
|
try {
|
|
66164
|
-
const raw =
|
|
66411
|
+
const raw = import_node_fs45.default.readFileSync(w3.filePath, "utf8");
|
|
66165
66412
|
if (!raw) return;
|
|
66166
66413
|
const allLines = raw.split("\n").filter((l2) => l2.trim().length > 0);
|
|
66167
66414
|
if (allLines.length === 0) return;
|
|
@@ -66185,7 +66432,7 @@ var SessionObserver = class {
|
|
|
66185
66432
|
poll(w3) {
|
|
66186
66433
|
let size = 0;
|
|
66187
66434
|
try {
|
|
66188
|
-
size =
|
|
66435
|
+
size = import_node_fs45.default.statSync(w3.filePath).size;
|
|
66189
66436
|
} catch {
|
|
66190
66437
|
if (w3.sawFile) this.maybeRelocate(w3);
|
|
66191
66438
|
return;
|
|
@@ -66196,11 +66443,11 @@ var SessionObserver = class {
|
|
|
66196
66443
|
w3.buf = "";
|
|
66197
66444
|
}
|
|
66198
66445
|
if (size === w3.lastSize) return;
|
|
66199
|
-
const fd =
|
|
66446
|
+
const fd = import_node_fs45.default.openSync(w3.filePath, "r");
|
|
66200
66447
|
try {
|
|
66201
66448
|
const len = size - w3.lastSize;
|
|
66202
66449
|
const buf = Buffer.alloc(len);
|
|
66203
|
-
|
|
66450
|
+
import_node_fs45.default.readSync(fd, buf, 0, len, w3.lastSize);
|
|
66204
66451
|
w3.lastSize = size;
|
|
66205
66452
|
w3.buf += buf.toString("utf8");
|
|
66206
66453
|
let newlineIndex;
|
|
@@ -66223,7 +66470,7 @@ var SessionObserver = class {
|
|
|
66223
66470
|
}
|
|
66224
66471
|
}
|
|
66225
66472
|
} finally {
|
|
66226
|
-
|
|
66473
|
+
import_node_fs45.default.closeSync(fd);
|
|
66227
66474
|
}
|
|
66228
66475
|
if (w3.pendingCwdDerive) this.maybeDeriveCwd(w3);
|
|
66229
66476
|
}
|
|
@@ -66235,7 +66482,7 @@ var SessionObserver = class {
|
|
|
66235
66482
|
const now = Date.now();
|
|
66236
66483
|
if (now - w3.lastRelocateScanMs < 1e3) return;
|
|
66237
66484
|
w3.lastRelocateScanMs = now;
|
|
66238
|
-
const projectsRoot =
|
|
66485
|
+
const projectsRoot = import_node_path49.default.join(this.home, ".claude", "projects");
|
|
66239
66486
|
const found = findTranscriptByToolSessionId(projectsRoot, w3.toolSessionId);
|
|
66240
66487
|
if (!found || found === w3.filePath) return;
|
|
66241
66488
|
try {
|
|
@@ -66244,7 +66491,7 @@ var SessionObserver = class {
|
|
|
66244
66491
|
}
|
|
66245
66492
|
w3.filePath = found;
|
|
66246
66493
|
try {
|
|
66247
|
-
w3.watcher =
|
|
66494
|
+
w3.watcher = import_node_fs45.default.watch(import_node_path49.default.dirname(found), { persistent: false }, (_event, changedName) => {
|
|
66248
66495
|
if (!changedName || !w3.filePath.endsWith(changedName)) return;
|
|
66249
66496
|
this.poll(w3);
|
|
66250
66497
|
});
|
|
@@ -66366,9 +66613,9 @@ function listRegistered() {
|
|
|
66366
66613
|
// src/tools/title-generator.ts
|
|
66367
66614
|
var import_node_child_process13 = require("child_process");
|
|
66368
66615
|
init_protocol();
|
|
66369
|
-
var
|
|
66370
|
-
var
|
|
66371
|
-
var
|
|
66616
|
+
var import_node_fs46 = __toESM(require("fs"), 1);
|
|
66617
|
+
var import_node_os19 = __toESM(require("os"), 1);
|
|
66618
|
+
var import_node_path50 = __toESM(require("path"), 1);
|
|
66372
66619
|
var TITLE_GEN_DIR_PREFIX = "clawd-title-";
|
|
66373
66620
|
var TITLE_INPUT_MAX_CHARS = 400;
|
|
66374
66621
|
var DEFAULT_TITLE_GEN_TIMEOUT_MS = 45e3;
|
|
@@ -66459,21 +66706,21 @@ async function generateSessionTitle(file, firstMessage, deps = {}) {
|
|
|
66459
66706
|
}
|
|
66460
66707
|
let workDir;
|
|
66461
66708
|
try {
|
|
66462
|
-
workDir =
|
|
66709
|
+
workDir = import_node_fs46.default.mkdtempSync(import_node_path50.default.join(import_node_os19.default.tmpdir(), TITLE_GEN_DIR_PREFIX));
|
|
66463
66710
|
} catch {
|
|
66464
66711
|
return null;
|
|
66465
66712
|
}
|
|
66466
66713
|
const cleanupWorkDir = () => {
|
|
66467
66714
|
try {
|
|
66468
|
-
|
|
66715
|
+
import_node_fs46.default.rmSync(workDir, { recursive: true, force: true });
|
|
66469
66716
|
} catch {
|
|
66470
66717
|
}
|
|
66471
66718
|
};
|
|
66472
|
-
const outFile =
|
|
66473
|
-
const schemaFile =
|
|
66719
|
+
const outFile = import_node_path50.default.join(workDir, `codex-title-${process.pid}-${++outFileSeq}-${Date.now()}.txt`);
|
|
66720
|
+
const schemaFile = import_node_path50.default.join(workDir, "title-schema.json");
|
|
66474
66721
|
if (tool === "codex") {
|
|
66475
66722
|
try {
|
|
66476
|
-
|
|
66723
|
+
import_node_fs46.default.writeFileSync(schemaFile, CODEX_TITLE_SCHEMA);
|
|
66477
66724
|
} catch {
|
|
66478
66725
|
cleanupWorkDir();
|
|
66479
66726
|
return null;
|
|
@@ -66528,7 +66775,7 @@ async function generateSessionTitle(file, firstMessage, deps = {}) {
|
|
|
66528
66775
|
if (tool === "claude" || tool === "pi") return finish(parseTitleJson(stdout));
|
|
66529
66776
|
let fileText = "";
|
|
66530
66777
|
try {
|
|
66531
|
-
fileText =
|
|
66778
|
+
fileText = import_node_fs46.default.readFileSync(outFile, "utf8");
|
|
66532
66779
|
} catch {
|
|
66533
66780
|
return finish(null);
|
|
66534
66781
|
}
|
|
@@ -67224,8 +67471,8 @@ async function authenticate(token, deps) {
|
|
|
67224
67471
|
}
|
|
67225
67472
|
|
|
67226
67473
|
// src/legacy-cleanup.ts
|
|
67227
|
-
var
|
|
67228
|
-
var
|
|
67474
|
+
var fs57 = __toESM(require("fs/promises"), 1);
|
|
67475
|
+
var path58 = __toESM(require("path"), 1);
|
|
67229
67476
|
var LEGACY_FILES = [
|
|
67230
67477
|
"personal-capability.json",
|
|
67231
67478
|
"received-capabilities.json",
|
|
@@ -67234,9 +67481,9 @@ var LEGACY_FILES = [
|
|
|
67234
67481
|
async function cleanupLegacyCapabilityFiles(dataDir, logger) {
|
|
67235
67482
|
const removed = [];
|
|
67236
67483
|
for (const name of LEGACY_FILES) {
|
|
67237
|
-
const p3 =
|
|
67484
|
+
const p3 = path58.join(dataDir, name);
|
|
67238
67485
|
try {
|
|
67239
|
-
await
|
|
67486
|
+
await fs57.unlink(p3);
|
|
67240
67487
|
removed.push(name);
|
|
67241
67488
|
logger.debug("legacy capability file removed", { file: name });
|
|
67242
67489
|
} catch (err) {
|
|
@@ -67248,13 +67495,13 @@ async function cleanupLegacyCapabilityFiles(dataDir, logger) {
|
|
|
67248
67495
|
}
|
|
67249
67496
|
|
|
67250
67497
|
// src/inbox/inbox-store.ts
|
|
67251
|
-
var
|
|
67252
|
-
var
|
|
67498
|
+
var fs58 = __toESM(require("fs"), 1);
|
|
67499
|
+
var path59 = __toESM(require("path"), 1);
|
|
67253
67500
|
var INBOX_SUBDIR = "inbox";
|
|
67254
67501
|
var InboxStore = class {
|
|
67255
67502
|
constructor(dataDir) {
|
|
67256
67503
|
this.dataDir = dataDir;
|
|
67257
|
-
|
|
67504
|
+
fs58.mkdirSync(this.dirPath(), { recursive: true });
|
|
67258
67505
|
}
|
|
67259
67506
|
dataDir;
|
|
67260
67507
|
/**
|
|
@@ -67266,7 +67513,7 @@ var InboxStore = class {
|
|
|
67266
67513
|
const file = this.filePath(peerDeviceId);
|
|
67267
67514
|
let raw;
|
|
67268
67515
|
try {
|
|
67269
|
-
raw =
|
|
67516
|
+
raw = fs58.readFileSync(file, "utf8");
|
|
67270
67517
|
} catch (err) {
|
|
67271
67518
|
if (err?.code === "ENOENT") return [];
|
|
67272
67519
|
return [];
|
|
@@ -67282,7 +67529,7 @@ var InboxStore = class {
|
|
|
67282
67529
|
const dir = this.dirPath();
|
|
67283
67530
|
let entries;
|
|
67284
67531
|
try {
|
|
67285
|
-
entries =
|
|
67532
|
+
entries = fs58.readdirSync(dir);
|
|
67286
67533
|
} catch (err) {
|
|
67287
67534
|
if (err?.code === "ENOENT") return [];
|
|
67288
67535
|
return [];
|
|
@@ -67298,9 +67545,9 @@ var InboxStore = class {
|
|
|
67298
67545
|
if (existing.some((m3) => m3.id === message.id)) return;
|
|
67299
67546
|
const file = this.filePath(message.peerDeviceId);
|
|
67300
67547
|
const line = JSON.stringify(message) + "\n";
|
|
67301
|
-
|
|
67548
|
+
fs58.appendFileSync(file, line, { mode: 384 });
|
|
67302
67549
|
try {
|
|
67303
|
-
|
|
67550
|
+
fs58.chmodSync(file, 384);
|
|
67304
67551
|
} catch {
|
|
67305
67552
|
}
|
|
67306
67553
|
}
|
|
@@ -67330,7 +67577,7 @@ var InboxStore = class {
|
|
|
67330
67577
|
removeByPeerDeviceId(peerDeviceId) {
|
|
67331
67578
|
const file = this.filePath(peerDeviceId);
|
|
67332
67579
|
try {
|
|
67333
|
-
|
|
67580
|
+
fs58.unlinkSync(file);
|
|
67334
67581
|
} catch (err) {
|
|
67335
67582
|
if (err?.code === "ENOENT") return;
|
|
67336
67583
|
}
|
|
@@ -67339,18 +67586,18 @@ var InboxStore = class {
|
|
|
67339
67586
|
const file = this.filePath(peerDeviceId);
|
|
67340
67587
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
67341
67588
|
const content = messages.map((m3) => JSON.stringify(m3)).join("\n") + (messages.length > 0 ? "\n" : "");
|
|
67342
|
-
|
|
67343
|
-
|
|
67589
|
+
fs58.writeFileSync(tmp, content, { mode: 384 });
|
|
67590
|
+
fs58.renameSync(tmp, file);
|
|
67344
67591
|
try {
|
|
67345
|
-
|
|
67592
|
+
fs58.chmodSync(file, 384);
|
|
67346
67593
|
} catch {
|
|
67347
67594
|
}
|
|
67348
67595
|
}
|
|
67349
67596
|
dirPath() {
|
|
67350
|
-
return
|
|
67597
|
+
return path59.join(this.dataDir, INBOX_SUBDIR);
|
|
67351
67598
|
}
|
|
67352
67599
|
filePath(peerDeviceId) {
|
|
67353
|
-
return
|
|
67600
|
+
return path59.join(this.dirPath(), `${peerDeviceId}.jsonl`);
|
|
67354
67601
|
}
|
|
67355
67602
|
};
|
|
67356
67603
|
function parseAllLines(raw) {
|
|
@@ -67438,8 +67685,8 @@ var InboxManager = class {
|
|
|
67438
67685
|
};
|
|
67439
67686
|
|
|
67440
67687
|
// src/state/contact-store.ts
|
|
67441
|
-
var
|
|
67442
|
-
var
|
|
67688
|
+
var fs59 = __toESM(require("fs"), 1);
|
|
67689
|
+
var path60 = __toESM(require("path"), 1);
|
|
67443
67690
|
var FILE_NAME = "contacts.json";
|
|
67444
67691
|
var ContactStore = class {
|
|
67445
67692
|
constructor(dataDir) {
|
|
@@ -67449,10 +67696,10 @@ var ContactStore = class {
|
|
|
67449
67696
|
contacts = /* @__PURE__ */ new Map();
|
|
67450
67697
|
load() {
|
|
67451
67698
|
this.contacts.clear();
|
|
67452
|
-
const file =
|
|
67699
|
+
const file = path60.join(this.dataDir, FILE_NAME);
|
|
67453
67700
|
let raw;
|
|
67454
67701
|
try {
|
|
67455
|
-
raw =
|
|
67702
|
+
raw = fs59.readFileSync(file, "utf8");
|
|
67456
67703
|
} catch (err) {
|
|
67457
67704
|
if (err?.code !== "ENOENT") this.renameBak(file);
|
|
67458
67705
|
return;
|
|
@@ -67533,20 +67780,20 @@ var ContactStore = class {
|
|
|
67533
67780
|
return true;
|
|
67534
67781
|
}
|
|
67535
67782
|
flush() {
|
|
67536
|
-
const file =
|
|
67783
|
+
const file = path60.join(this.dataDir, FILE_NAME);
|
|
67537
67784
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
67538
67785
|
const content = JSON.stringify(
|
|
67539
67786
|
{ contacts: Array.from(this.contacts.values()) },
|
|
67540
67787
|
null,
|
|
67541
67788
|
2
|
|
67542
67789
|
);
|
|
67543
|
-
|
|
67544
|
-
|
|
67545
|
-
|
|
67790
|
+
fs59.mkdirSync(this.dataDir, { recursive: true });
|
|
67791
|
+
fs59.writeFileSync(tmp, content, { mode: 384 });
|
|
67792
|
+
fs59.renameSync(tmp, file);
|
|
67546
67793
|
}
|
|
67547
67794
|
renameBak(file) {
|
|
67548
67795
|
try {
|
|
67549
|
-
|
|
67796
|
+
fs59.renameSync(file, `${file}.bak`);
|
|
67550
67797
|
} catch {
|
|
67551
67798
|
}
|
|
67552
67799
|
}
|
|
@@ -67654,61 +67901,61 @@ async function connectRemote(args) {
|
|
|
67654
67901
|
}
|
|
67655
67902
|
|
|
67656
67903
|
// src/migrations/2026-05-20-flatten-sessions.ts
|
|
67657
|
-
var
|
|
67658
|
-
var
|
|
67904
|
+
var fs60 = __toESM(require("fs"), 1);
|
|
67905
|
+
var path61 = __toESM(require("path"), 1);
|
|
67659
67906
|
var MIGRATION_FLAG_NAME = ".migration.v1.done";
|
|
67660
67907
|
function migrateFlattenSessions(opts) {
|
|
67661
67908
|
const dataDir = opts.dataDir;
|
|
67662
67909
|
const now = opts.now ?? Date.now;
|
|
67663
|
-
const sessionsDir =
|
|
67664
|
-
const flagPath =
|
|
67910
|
+
const sessionsDir = path61.join(dataDir, "sessions");
|
|
67911
|
+
const flagPath = path61.join(sessionsDir, MIGRATION_FLAG_NAME);
|
|
67665
67912
|
if (existsSync3(flagPath)) {
|
|
67666
67913
|
return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
|
|
67667
67914
|
}
|
|
67668
67915
|
let movedBare = 0;
|
|
67669
67916
|
let movedVmOwner = 0;
|
|
67670
67917
|
let archivedListener = 0;
|
|
67671
|
-
const defaultDir =
|
|
67918
|
+
const defaultDir = path61.join(sessionsDir, "default");
|
|
67672
67919
|
if (existsSync3(defaultDir)) {
|
|
67673
67920
|
for (const entry of readdirSafe(defaultDir)) {
|
|
67674
67921
|
if (!entry.endsWith(".json")) continue;
|
|
67675
|
-
const src =
|
|
67676
|
-
const dst =
|
|
67677
|
-
|
|
67922
|
+
const src = path61.join(defaultDir, entry);
|
|
67923
|
+
const dst = path61.join(sessionsDir, entry);
|
|
67924
|
+
fs60.renameSync(src, dst);
|
|
67678
67925
|
movedBare += 1;
|
|
67679
67926
|
}
|
|
67680
67927
|
rmdirIfEmpty(defaultDir);
|
|
67681
67928
|
}
|
|
67682
67929
|
for (const pid of readdirSafe(sessionsDir)) {
|
|
67683
|
-
const personaDir =
|
|
67930
|
+
const personaDir = path61.join(sessionsDir, pid);
|
|
67684
67931
|
if (!isDir(personaDir)) continue;
|
|
67685
67932
|
if (pid === "default") continue;
|
|
67686
|
-
const ownerSrc =
|
|
67933
|
+
const ownerSrc = path61.join(personaDir, "owner");
|
|
67687
67934
|
if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
|
|
67688
|
-
const ownerDst =
|
|
67689
|
-
|
|
67935
|
+
const ownerDst = path61.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
|
|
67936
|
+
fs60.mkdirSync(ownerDst, { recursive: true });
|
|
67690
67937
|
for (const file of readdirSafe(ownerSrc)) {
|
|
67691
67938
|
if (!file.endsWith(".json")) continue;
|
|
67692
|
-
|
|
67939
|
+
fs60.renameSync(path61.join(ownerSrc, file), path61.join(ownerDst, file));
|
|
67693
67940
|
movedVmOwner += 1;
|
|
67694
67941
|
}
|
|
67695
67942
|
rmdirIfEmpty(ownerSrc);
|
|
67696
67943
|
}
|
|
67697
|
-
const listenerSrc =
|
|
67944
|
+
const listenerSrc = path61.join(personaDir, "listener");
|
|
67698
67945
|
if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
|
|
67699
|
-
const archiveDst =
|
|
67700
|
-
|
|
67946
|
+
const archiveDst = path61.join(dataDir, ".legacy", `listener-${pid}`);
|
|
67947
|
+
fs60.mkdirSync(archiveDst, { recursive: true });
|
|
67701
67948
|
for (const file of readdirSafe(listenerSrc)) {
|
|
67702
67949
|
if (!file.endsWith(".json")) continue;
|
|
67703
|
-
|
|
67950
|
+
fs60.renameSync(path61.join(listenerSrc, file), path61.join(archiveDst, file));
|
|
67704
67951
|
archivedListener += 1;
|
|
67705
67952
|
}
|
|
67706
67953
|
rmdirIfEmpty(listenerSrc);
|
|
67707
67954
|
}
|
|
67708
67955
|
rmdirIfEmpty(personaDir);
|
|
67709
67956
|
}
|
|
67710
|
-
|
|
67711
|
-
|
|
67957
|
+
fs60.mkdirSync(sessionsDir, { recursive: true });
|
|
67958
|
+
fs60.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
|
|
67712
67959
|
return {
|
|
67713
67960
|
skipped: false,
|
|
67714
67961
|
flagWritten: true,
|
|
@@ -67719,7 +67966,7 @@ function migrateFlattenSessions(opts) {
|
|
|
67719
67966
|
}
|
|
67720
67967
|
function existsSync3(p3) {
|
|
67721
67968
|
try {
|
|
67722
|
-
|
|
67969
|
+
fs60.statSync(p3);
|
|
67723
67970
|
return true;
|
|
67724
67971
|
} catch {
|
|
67725
67972
|
return false;
|
|
@@ -67727,62 +67974,62 @@ function existsSync3(p3) {
|
|
|
67727
67974
|
}
|
|
67728
67975
|
function isDir(p3) {
|
|
67729
67976
|
try {
|
|
67730
|
-
return
|
|
67977
|
+
return fs60.statSync(p3).isDirectory();
|
|
67731
67978
|
} catch {
|
|
67732
67979
|
return false;
|
|
67733
67980
|
}
|
|
67734
67981
|
}
|
|
67735
67982
|
function readdirSafe(p3) {
|
|
67736
67983
|
try {
|
|
67737
|
-
return
|
|
67984
|
+
return fs60.readdirSync(p3);
|
|
67738
67985
|
} catch {
|
|
67739
67986
|
return [];
|
|
67740
67987
|
}
|
|
67741
67988
|
}
|
|
67742
67989
|
function rmdirIfEmpty(p3) {
|
|
67743
67990
|
try {
|
|
67744
|
-
|
|
67991
|
+
fs60.rmdirSync(p3);
|
|
67745
67992
|
} catch {
|
|
67746
67993
|
}
|
|
67747
67994
|
}
|
|
67748
67995
|
|
|
67749
67996
|
// src/migrations/2026-08-18-drop-seeded-projects.ts
|
|
67750
|
-
var
|
|
67751
|
-
var
|
|
67997
|
+
var fs61 = __toESM(require("fs"), 1);
|
|
67998
|
+
var path62 = __toESM(require("path"), 1);
|
|
67752
67999
|
var DROP_SEEDED_PROJECTS_FLAG = ".projects-seed-dropped.v1.done";
|
|
67753
68000
|
function dropSeededProjects(opts) {
|
|
67754
|
-
|
|
67755
|
-
const flag =
|
|
67756
|
-
if (
|
|
67757
|
-
const file =
|
|
68001
|
+
fs61.mkdirSync(opts.dataDir, { recursive: true });
|
|
68002
|
+
const flag = path62.join(opts.dataDir, DROP_SEEDED_PROJECTS_FLAG);
|
|
68003
|
+
if (fs61.existsSync(flag)) return { skipped: true, dropped: 0, backup: null };
|
|
68004
|
+
const file = path62.join(opts.dataDir, "projects.json");
|
|
67758
68005
|
let raw = null;
|
|
67759
68006
|
let dropped = 0;
|
|
67760
68007
|
try {
|
|
67761
|
-
raw =
|
|
68008
|
+
raw = fs61.readFileSync(file, "utf8");
|
|
67762
68009
|
dropped = JSON.parse(raw).projects?.length ?? 0;
|
|
67763
68010
|
} catch {
|
|
67764
68011
|
}
|
|
67765
68012
|
let backup = null;
|
|
67766
68013
|
if (raw != null && dropped > 0) {
|
|
67767
|
-
const dir =
|
|
67768
|
-
|
|
67769
|
-
backup =
|
|
67770
|
-
|
|
68014
|
+
const dir = path62.join(opts.dataDir, "backups");
|
|
68015
|
+
fs61.mkdirSync(dir, { recursive: true });
|
|
68016
|
+
backup = path62.join(dir, `projects.seed-dropped.${(opts.now ?? Date.now)()}.json`);
|
|
68017
|
+
fs61.writeFileSync(backup, raw);
|
|
67771
68018
|
}
|
|
67772
68019
|
if (raw != null || dropped > 0) {
|
|
67773
|
-
|
|
68020
|
+
fs61.writeFileSync(file, JSON.stringify({ projects: [] }, null, 2));
|
|
67774
68021
|
}
|
|
67775
|
-
|
|
68022
|
+
fs61.writeFileSync(flag, (/* @__PURE__ */ new Date()).toISOString());
|
|
67776
68023
|
return { skipped: false, dropped, backup };
|
|
67777
68024
|
}
|
|
67778
68025
|
|
|
67779
68026
|
// src/transport/http-router.ts
|
|
67780
|
-
var
|
|
67781
|
-
var
|
|
68027
|
+
var import_node_fs48 = __toESM(require("fs"), 1);
|
|
68028
|
+
var import_node_path53 = __toESM(require("path"), 1);
|
|
67782
68029
|
|
|
67783
68030
|
// src/attachment/upload.ts
|
|
67784
|
-
var
|
|
67785
|
-
var
|
|
68031
|
+
var import_node_fs47 = __toESM(require("fs"), 1);
|
|
68032
|
+
var import_node_path51 = __toESM(require("path"), 1);
|
|
67786
68033
|
var import_node_crypto15 = __toESM(require("crypto"), 1);
|
|
67787
68034
|
var import_promises8 = require("stream/promises");
|
|
67788
68035
|
var UploadError = class extends Error {
|
|
@@ -67794,22 +68041,22 @@ var UploadError = class extends Error {
|
|
|
67794
68041
|
code;
|
|
67795
68042
|
};
|
|
67796
68043
|
function assertValidFileName(fileName) {
|
|
67797
|
-
if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !==
|
|
68044
|
+
if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path51.default.basename(fileName)) {
|
|
67798
68045
|
throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
|
|
67799
68046
|
}
|
|
67800
68047
|
}
|
|
67801
68048
|
var HASH_PREFIX_LEN = 16;
|
|
67802
68049
|
async function writeUploadedAttachment(args) {
|
|
67803
68050
|
assertValidFileName(args.fileName);
|
|
67804
|
-
const attachmentsRoot =
|
|
68051
|
+
const attachmentsRoot = import_node_path51.default.join(args.baseDir, ".attachments");
|
|
67805
68052
|
try {
|
|
67806
|
-
|
|
68053
|
+
import_node_fs47.default.mkdirSync(attachmentsRoot, { recursive: true });
|
|
67807
68054
|
} catch (err) {
|
|
67808
68055
|
throw new UploadError("STORAGE_ERROR", `mkdir failed: ${err.message}`);
|
|
67809
68056
|
}
|
|
67810
68057
|
const hasher = import_node_crypto15.default.createHash("sha256");
|
|
67811
68058
|
let actualSize = 0;
|
|
67812
|
-
const tmpPath =
|
|
68059
|
+
const tmpPath = import_node_path51.default.join(
|
|
67813
68060
|
attachmentsRoot,
|
|
67814
68061
|
`.upload-${process.pid}-${Date.now()}-${import_node_crypto15.default.randomBytes(4).toString("hex")}`
|
|
67815
68062
|
);
|
|
@@ -67824,18 +68071,18 @@ async function writeUploadedAttachment(args) {
|
|
|
67824
68071
|
yield buf;
|
|
67825
68072
|
}
|
|
67826
68073
|
},
|
|
67827
|
-
|
|
68074
|
+
import_node_fs47.default.createWriteStream(tmpPath, { mode: 384 })
|
|
67828
68075
|
);
|
|
67829
68076
|
} catch (err) {
|
|
67830
68077
|
try {
|
|
67831
|
-
|
|
68078
|
+
import_node_fs47.default.unlinkSync(tmpPath);
|
|
67832
68079
|
} catch {
|
|
67833
68080
|
}
|
|
67834
68081
|
throw new UploadError("STORAGE_ERROR", `write failed: ${err.message}`);
|
|
67835
68082
|
}
|
|
67836
68083
|
if (actualSize !== args.contentLength) {
|
|
67837
68084
|
try {
|
|
67838
|
-
|
|
68085
|
+
import_node_fs47.default.unlinkSync(tmpPath);
|
|
67839
68086
|
} catch {
|
|
67840
68087
|
}
|
|
67841
68088
|
throw new UploadError(
|
|
@@ -67844,34 +68091,34 @@ async function writeUploadedAttachment(args) {
|
|
|
67844
68091
|
);
|
|
67845
68092
|
}
|
|
67846
68093
|
const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
|
|
67847
|
-
const hashDir =
|
|
68094
|
+
const hashDir = import_node_path51.default.join(attachmentsRoot, attachmentId);
|
|
67848
68095
|
let finalFileName;
|
|
67849
68096
|
let hashDirExists = false;
|
|
67850
68097
|
try {
|
|
67851
|
-
hashDirExists =
|
|
68098
|
+
hashDirExists = import_node_fs47.default.statSync(hashDir).isDirectory();
|
|
67852
68099
|
} catch {
|
|
67853
68100
|
}
|
|
67854
68101
|
if (hashDirExists) {
|
|
67855
|
-
const existing =
|
|
68102
|
+
const existing = import_node_fs47.default.readdirSync(hashDir).filter((n2) => !n2.startsWith("."));
|
|
67856
68103
|
finalFileName = existing[0] ?? args.fileName;
|
|
67857
68104
|
try {
|
|
67858
|
-
|
|
68105
|
+
import_node_fs47.default.unlinkSync(tmpPath);
|
|
67859
68106
|
} catch {
|
|
67860
68107
|
}
|
|
67861
68108
|
} else {
|
|
67862
68109
|
try {
|
|
67863
|
-
|
|
68110
|
+
import_node_fs47.default.mkdirSync(hashDir, { recursive: true });
|
|
67864
68111
|
finalFileName = args.fileName;
|
|
67865
|
-
|
|
68112
|
+
import_node_fs47.default.renameSync(tmpPath, import_node_path51.default.join(hashDir, finalFileName));
|
|
67866
68113
|
} catch (err) {
|
|
67867
68114
|
try {
|
|
67868
|
-
|
|
68115
|
+
import_node_fs47.default.unlinkSync(tmpPath);
|
|
67869
68116
|
} catch {
|
|
67870
68117
|
}
|
|
67871
68118
|
throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
|
|
67872
68119
|
}
|
|
67873
68120
|
}
|
|
67874
|
-
const absPath =
|
|
68121
|
+
const absPath = import_node_path51.default.join(hashDir, finalFileName);
|
|
67875
68122
|
const relPath = absPath;
|
|
67876
68123
|
args.groupFileStore.upsert(args.scope, args.sessionId, {
|
|
67877
68124
|
relPath: absPath,
|
|
@@ -67886,8 +68133,8 @@ async function writeUploadedAttachment(args) {
|
|
|
67886
68133
|
|
|
67887
68134
|
// src/extension/import.ts
|
|
67888
68135
|
var import_promises9 = __toESM(require("fs/promises"), 1);
|
|
67889
|
-
var
|
|
67890
|
-
var
|
|
68136
|
+
var import_node_path52 = __toESM(require("path"), 1);
|
|
68137
|
+
var import_node_os20 = __toESM(require("os"), 1);
|
|
67891
68138
|
var import_jszip = __toESM(require_lib3(), 1);
|
|
67892
68139
|
var ImportError = class extends Error {
|
|
67893
68140
|
constructor(code, message) {
|
|
@@ -67904,7 +68151,7 @@ async function importZip(buf, root) {
|
|
|
67904
68151
|
throw new ImportError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
67905
68152
|
}
|
|
67906
68153
|
for (const name of Object.keys(zip.files)) {
|
|
67907
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
68154
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path52.default.isAbsolute(name)) {
|
|
67908
68155
|
throw new ImportError("ZIP_INVALID", `unsafe zip entry path: ${name}`);
|
|
67909
68156
|
}
|
|
67910
68157
|
}
|
|
@@ -67937,7 +68184,7 @@ async function importZip(buf, root) {
|
|
|
67937
68184
|
);
|
|
67938
68185
|
}
|
|
67939
68186
|
}
|
|
67940
|
-
const destDir =
|
|
68187
|
+
const destDir = import_node_path52.default.join(root, manifest.id);
|
|
67941
68188
|
let destExists = false;
|
|
67942
68189
|
try {
|
|
67943
68190
|
await import_promises9.default.access(destDir);
|
|
@@ -67947,15 +68194,15 @@ async function importZip(buf, root) {
|
|
|
67947
68194
|
if (destExists) {
|
|
67948
68195
|
throw new ImportError("ALREADY_EXISTS", `extension ${manifest.id} already installed`);
|
|
67949
68196
|
}
|
|
67950
|
-
const stage = await import_promises9.default.mkdtemp(
|
|
68197
|
+
const stage = await import_promises9.default.mkdtemp(import_node_path52.default.join(import_node_os20.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
|
|
67951
68198
|
try {
|
|
67952
68199
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
67953
|
-
const dest =
|
|
68200
|
+
const dest = import_node_path52.default.join(stage, name);
|
|
67954
68201
|
if (entry.dir) {
|
|
67955
68202
|
await import_promises9.default.mkdir(dest, { recursive: true });
|
|
67956
68203
|
continue;
|
|
67957
68204
|
}
|
|
67958
|
-
await import_promises9.default.mkdir(
|
|
68205
|
+
await import_promises9.default.mkdir(import_node_path52.default.dirname(dest), { recursive: true });
|
|
67959
68206
|
const content = await entry.async("nodebuffer");
|
|
67960
68207
|
await import_promises9.default.writeFile(dest, content);
|
|
67961
68208
|
}
|
|
@@ -68009,7 +68256,7 @@ var SHARE_UI_ASSET_MIME = {
|
|
|
68009
68256
|
".wasm": "application/wasm"
|
|
68010
68257
|
};
|
|
68011
68258
|
function shareUiAssetMime(filePath) {
|
|
68012
|
-
const ext =
|
|
68259
|
+
const ext = import_node_path53.default.extname(filePath).toLowerCase();
|
|
68013
68260
|
return SHARE_UI_ASSET_MIME[ext] ?? lookupMime(filePath);
|
|
68014
68261
|
}
|
|
68015
68262
|
var AUTHED_RPC_ROUTE_PREFIX = "/rpc/";
|
|
@@ -68108,7 +68355,7 @@ function isValidUploadFileName(fileName) {
|
|
|
68108
68355
|
if (fileName === "." || fileName === "..") return false;
|
|
68109
68356
|
if (fileName.startsWith(".")) return false;
|
|
68110
68357
|
if (fileName.includes("/") || fileName.includes("\\")) return false;
|
|
68111
|
-
return fileName ===
|
|
68358
|
+
return fileName === import_node_path53.default.basename(fileName);
|
|
68112
68359
|
}
|
|
68113
68360
|
function createHttpRouter(deps) {
|
|
68114
68361
|
return async (req, res) => {
|
|
@@ -68192,7 +68439,7 @@ function createHttpRouter(deps) {
|
|
|
68192
68439
|
}
|
|
68193
68440
|
let buf;
|
|
68194
68441
|
try {
|
|
68195
|
-
buf = await
|
|
68442
|
+
buf = await import_node_fs48.default.promises.readFile(abs);
|
|
68196
68443
|
} catch {
|
|
68197
68444
|
sendJson2(res, 404, { code: "NOT_FOUND", message: "asset not found" });
|
|
68198
68445
|
return true;
|
|
@@ -68338,7 +68585,7 @@ function createHttpRouter(deps) {
|
|
|
68338
68585
|
sendHtml(res, statusByCode[r2.code], loader.renderErrorHtml(r2.code, msgByCode[r2.code]));
|
|
68339
68586
|
return true;
|
|
68340
68587
|
}
|
|
68341
|
-
sendHtml(res, 200, loader.renderViewerHtml(
|
|
68588
|
+
sendHtml(res, 200, loader.renderViewerHtml(import_node_path53.default.basename(r2.absPath)));
|
|
68342
68589
|
return true;
|
|
68343
68590
|
}
|
|
68344
68591
|
const ctx = deps.authResolver.resolveFromHeader(
|
|
@@ -68459,7 +68706,7 @@ function createHttpRouter(deps) {
|
|
|
68459
68706
|
return true;
|
|
68460
68707
|
}
|
|
68461
68708
|
let absPath;
|
|
68462
|
-
if (
|
|
68709
|
+
if (import_node_path53.default.isAbsolute(pathParam)) {
|
|
68463
68710
|
absPath = pathParam;
|
|
68464
68711
|
} else if (deps.sessionStore) {
|
|
68465
68712
|
const file = deps.sessionStore.read(sid);
|
|
@@ -68467,7 +68714,7 @@ function createHttpRouter(deps) {
|
|
|
68467
68714
|
sendJson2(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
|
|
68468
68715
|
return true;
|
|
68469
68716
|
}
|
|
68470
|
-
absPath =
|
|
68717
|
+
absPath = import_node_path53.default.join(file.cwd, pathParam);
|
|
68471
68718
|
} else {
|
|
68472
68719
|
sendJson2(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
|
|
68473
68720
|
return true;
|
|
@@ -68551,7 +68798,7 @@ function withCtx(ctx, body) {
|
|
|
68551
68798
|
function streamFile(res, absPath, logger) {
|
|
68552
68799
|
let stat;
|
|
68553
68800
|
try {
|
|
68554
|
-
stat =
|
|
68801
|
+
stat = import_node_fs48.default.statSync(absPath);
|
|
68555
68802
|
} catch (err) {
|
|
68556
68803
|
const code = err?.code;
|
|
68557
68804
|
if (code === "ENOENT") {
|
|
@@ -68566,7 +68813,7 @@ function streamFile(res, absPath, logger) {
|
|
|
68566
68813
|
return;
|
|
68567
68814
|
}
|
|
68568
68815
|
const mime = lookupMime(absPath);
|
|
68569
|
-
const basename2 =
|
|
68816
|
+
const basename2 = import_node_path53.default.basename(absPath);
|
|
68570
68817
|
res.writeHead(200, {
|
|
68571
68818
|
"Content-Type": mime,
|
|
68572
68819
|
"Content-Length": String(stat.size),
|
|
@@ -68574,7 +68821,7 @@ function streamFile(res, absPath, logger) {
|
|
|
68574
68821
|
// 防止浏览器把任意 mime 当 html 渲染
|
|
68575
68822
|
"X-Content-Type-Options": "nosniff"
|
|
68576
68823
|
});
|
|
68577
|
-
const stream =
|
|
68824
|
+
const stream = import_node_fs48.default.createReadStream(absPath);
|
|
68578
68825
|
stream.on("error", (err) => {
|
|
68579
68826
|
logger?.warn("streamFile read error", { absPath, err: err.message });
|
|
68580
68827
|
res.destroy();
|
|
@@ -68583,8 +68830,8 @@ function streamFile(res, absPath, logger) {
|
|
|
68583
68830
|
}
|
|
68584
68831
|
|
|
68585
68832
|
// src/attachment/gc.ts
|
|
68586
|
-
var
|
|
68587
|
-
var
|
|
68833
|
+
var import_node_fs49 = __toESM(require("fs"), 1);
|
|
68834
|
+
var import_node_path54 = __toESM(require("path"), 1);
|
|
68588
68835
|
var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
|
|
68589
68836
|
function runAttachmentGc(args) {
|
|
68590
68837
|
const now = (args.now ?? Date.now)();
|
|
@@ -68593,12 +68840,12 @@ function runAttachmentGc(args) {
|
|
|
68593
68840
|
for (const { scope, sessionId } of args.sessionScopes) {
|
|
68594
68841
|
for (const entry of args.groupFileStore.list(scope, sessionId)) {
|
|
68595
68842
|
if (entry.stale) continue;
|
|
68596
|
-
if (
|
|
68843
|
+
if (import_node_path54.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
|
|
68597
68844
|
}
|
|
68598
68845
|
}
|
|
68599
68846
|
const visited = /* @__PURE__ */ new Set();
|
|
68600
68847
|
for (const { scope, sessionId } of args.sessionScopes) {
|
|
68601
|
-
const legacyDir = args.getSessionCwd?.(sessionId) ??
|
|
68848
|
+
const legacyDir = args.getSessionCwd?.(sessionId) ?? import_node_path54.default.join(
|
|
68602
68849
|
args.dataDir,
|
|
68603
68850
|
"sessions",
|
|
68604
68851
|
...scopeSubPath(scope).map(safeFileName),
|
|
@@ -68611,28 +68858,28 @@ function runAttachmentGc(args) {
|
|
|
68611
68858
|
return true;
|
|
68612
68859
|
});
|
|
68613
68860
|
for (const rootDir of roots) {
|
|
68614
|
-
const attRoot =
|
|
68861
|
+
const attRoot = import_node_path54.default.join(rootDir, ".attachments");
|
|
68615
68862
|
let hashDirs;
|
|
68616
68863
|
try {
|
|
68617
|
-
hashDirs =
|
|
68864
|
+
hashDirs = import_node_fs49.default.readdirSync(attRoot);
|
|
68618
68865
|
} catch (err) {
|
|
68619
68866
|
if (err.code === "ENOENT") continue;
|
|
68620
68867
|
args.logger?.warn("attachment gc: readdir failed", { attRoot, err: err.message });
|
|
68621
68868
|
continue;
|
|
68622
68869
|
}
|
|
68623
68870
|
for (const hashDir of hashDirs) {
|
|
68624
|
-
const hashDirAbs =
|
|
68871
|
+
const hashDirAbs = import_node_path54.default.join(attRoot, hashDir);
|
|
68625
68872
|
let files;
|
|
68626
68873
|
try {
|
|
68627
|
-
files =
|
|
68874
|
+
files = import_node_fs49.default.readdirSync(hashDirAbs);
|
|
68628
68875
|
} catch {
|
|
68629
68876
|
continue;
|
|
68630
68877
|
}
|
|
68631
68878
|
for (const name of files) {
|
|
68632
|
-
const file =
|
|
68879
|
+
const file = import_node_path54.default.join(hashDirAbs, name);
|
|
68633
68880
|
let stat;
|
|
68634
68881
|
try {
|
|
68635
|
-
stat =
|
|
68882
|
+
stat = import_node_fs49.default.statSync(file);
|
|
68636
68883
|
} catch {
|
|
68637
68884
|
continue;
|
|
68638
68885
|
}
|
|
@@ -68641,18 +68888,18 @@ function runAttachmentGc(args) {
|
|
|
68641
68888
|
if (age < ttlMs) continue;
|
|
68642
68889
|
if (liveAbs.has(file)) continue;
|
|
68643
68890
|
try {
|
|
68644
|
-
|
|
68891
|
+
import_node_fs49.default.unlinkSync(file);
|
|
68645
68892
|
} catch (err) {
|
|
68646
68893
|
args.logger?.warn("attachment gc: unlink failed", { file, err: err.message });
|
|
68647
68894
|
}
|
|
68648
68895
|
}
|
|
68649
68896
|
try {
|
|
68650
|
-
if (
|
|
68897
|
+
if (import_node_fs49.default.readdirSync(hashDirAbs).length === 0) import_node_fs49.default.rmdirSync(hashDirAbs);
|
|
68651
68898
|
} catch {
|
|
68652
68899
|
}
|
|
68653
68900
|
}
|
|
68654
68901
|
try {
|
|
68655
|
-
if (
|
|
68902
|
+
if (import_node_fs49.default.readdirSync(attRoot).length === 0) import_node_fs49.default.rmdirSync(attRoot);
|
|
68656
68903
|
} catch {
|
|
68657
68904
|
}
|
|
68658
68905
|
}
|
|
@@ -68660,8 +68907,8 @@ function runAttachmentGc(args) {
|
|
|
68660
68907
|
}
|
|
68661
68908
|
|
|
68662
68909
|
// src/attachment/group.ts
|
|
68663
|
-
var
|
|
68664
|
-
var
|
|
68910
|
+
var import_node_fs50 = __toESM(require("fs"), 1);
|
|
68911
|
+
var import_node_path55 = __toESM(require("path"), 1);
|
|
68665
68912
|
var import_node_crypto16 = __toESM(require("crypto"), 1);
|
|
68666
68913
|
init_protocol();
|
|
68667
68914
|
var GroupFileStore = class {
|
|
@@ -68673,11 +68920,11 @@ var GroupFileStore = class {
|
|
|
68673
68920
|
this.logger = opts.logger;
|
|
68674
68921
|
}
|
|
68675
68922
|
rootForScope(scope) {
|
|
68676
|
-
return
|
|
68923
|
+
return import_node_path55.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
|
|
68677
68924
|
}
|
|
68678
68925
|
/** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
|
|
68679
68926
|
filePath(scope, sessionId) {
|
|
68680
|
-
return
|
|
68927
|
+
return import_node_path55.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
|
|
68681
68928
|
}
|
|
68682
68929
|
cacheKey(scope, sessionId) {
|
|
68683
68930
|
return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
|
|
@@ -68686,7 +68933,7 @@ var GroupFileStore = class {
|
|
|
68686
68933
|
readFile(scope, sessionId) {
|
|
68687
68934
|
const file = this.filePath(scope, sessionId);
|
|
68688
68935
|
try {
|
|
68689
|
-
const raw =
|
|
68936
|
+
const raw = import_node_fs50.default.readFileSync(file, "utf8");
|
|
68690
68937
|
const parsed = JSON.parse(raw);
|
|
68691
68938
|
if (!Array.isArray(parsed)) {
|
|
68692
68939
|
this.logger?.warn("GroupFileStore.readFile: not an array; resetting session entries", {
|
|
@@ -68712,10 +68959,10 @@ var GroupFileStore = class {
|
|
|
68712
68959
|
}
|
|
68713
68960
|
writeFile(scope, sessionId, entries) {
|
|
68714
68961
|
const file = this.filePath(scope, sessionId);
|
|
68715
|
-
|
|
68962
|
+
import_node_fs50.default.mkdirSync(import_node_path55.default.dirname(file), { recursive: true });
|
|
68716
68963
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
68717
|
-
|
|
68718
|
-
|
|
68964
|
+
import_node_fs50.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
|
|
68965
|
+
import_node_fs50.default.renameSync(tmp, file);
|
|
68719
68966
|
}
|
|
68720
68967
|
/** 拉一份当前 session 的清单。读盘 → cache;之后调用复用 cache */
|
|
68721
68968
|
list(scope, sessionId) {
|
|
@@ -68807,7 +69054,7 @@ var GroupFileStore = class {
|
|
|
68807
69054
|
*/
|
|
68808
69055
|
deleteSession(scope, sessionId) {
|
|
68809
69056
|
try {
|
|
68810
|
-
|
|
69057
|
+
import_node_fs50.default.unlinkSync(this.filePath(scope, sessionId));
|
|
68811
69058
|
} catch (err) {
|
|
68812
69059
|
if (err?.code !== "ENOENT") throw err;
|
|
68813
69060
|
}
|
|
@@ -68820,7 +69067,7 @@ var GroupFileStore = class {
|
|
|
68820
69067
|
* 不在 persona 目录里(见文件头的路径约定)。没树的 persona 是 noop。
|
|
68821
69068
|
*/
|
|
68822
69069
|
deletePersona(personaId2) {
|
|
68823
|
-
|
|
69070
|
+
import_node_fs50.default.rmSync(import_node_path55.default.join(this.dataDir, "sessions", safeFileName(personaId2)), { recursive: true, force: true });
|
|
68824
69071
|
const prefix = `persona:${personaId2}:`;
|
|
68825
69072
|
for (const key of this.cache.keys()) {
|
|
68826
69073
|
if (key.startsWith(prefix)) this.cache.delete(key);
|
|
@@ -68829,10 +69076,10 @@ var GroupFileStore = class {
|
|
|
68829
69076
|
};
|
|
68830
69077
|
|
|
68831
69078
|
// src/discovery/state-file.ts
|
|
68832
|
-
var
|
|
68833
|
-
var
|
|
69079
|
+
var import_node_fs51 = __toESM(require("fs"), 1);
|
|
69080
|
+
var import_node_path56 = __toESM(require("path"), 1);
|
|
68834
69081
|
function defaultStateFilePath(dataDir) {
|
|
68835
|
-
return
|
|
69082
|
+
return import_node_path56.default.join(dataDir, "state.json");
|
|
68836
69083
|
}
|
|
68837
69084
|
function isPidAlive(pid) {
|
|
68838
69085
|
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
@@ -68854,7 +69101,7 @@ var StateFileManager = class {
|
|
|
68854
69101
|
}
|
|
68855
69102
|
read() {
|
|
68856
69103
|
try {
|
|
68857
|
-
const raw =
|
|
69104
|
+
const raw = import_node_fs51.default.readFileSync(this.file, "utf8");
|
|
68858
69105
|
const parsed = JSON.parse(raw);
|
|
68859
69106
|
return parsed;
|
|
68860
69107
|
} catch {
|
|
@@ -68868,20 +69115,20 @@ var StateFileManager = class {
|
|
|
68868
69115
|
return { status: "stale", existing };
|
|
68869
69116
|
}
|
|
68870
69117
|
write(state) {
|
|
68871
|
-
|
|
69118
|
+
import_node_fs51.default.mkdirSync(import_node_path56.default.dirname(this.file), { recursive: true });
|
|
68872
69119
|
const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
|
|
68873
|
-
|
|
68874
|
-
|
|
69120
|
+
import_node_fs51.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
|
|
69121
|
+
import_node_fs51.default.renameSync(tmp, this.file);
|
|
68875
69122
|
if (process.platform !== "win32") {
|
|
68876
69123
|
try {
|
|
68877
|
-
|
|
69124
|
+
import_node_fs51.default.chmodSync(this.file, 384);
|
|
68878
69125
|
} catch {
|
|
68879
69126
|
}
|
|
68880
69127
|
}
|
|
68881
69128
|
}
|
|
68882
69129
|
delete() {
|
|
68883
69130
|
try {
|
|
68884
|
-
|
|
69131
|
+
import_node_fs51.default.unlinkSync(this.file);
|
|
68885
69132
|
} catch {
|
|
68886
69133
|
}
|
|
68887
69134
|
}
|
|
@@ -68895,14 +69142,14 @@ function readSpawnedByDesktopFromEnv(env = process.env) {
|
|
|
68895
69142
|
}
|
|
68896
69143
|
|
|
68897
69144
|
// src/tunnel/tunnel-manager.ts
|
|
68898
|
-
var
|
|
68899
|
-
var
|
|
69145
|
+
var import_node_fs55 = __toESM(require("fs"), 1);
|
|
69146
|
+
var import_node_path60 = __toESM(require("path"), 1);
|
|
68900
69147
|
var import_node_crypto17 = __toESM(require("crypto"), 1);
|
|
68901
69148
|
var import_node_child_process16 = require("child_process");
|
|
68902
69149
|
|
|
68903
69150
|
// src/tunnel/tunnel-store.ts
|
|
68904
|
-
var
|
|
68905
|
-
var
|
|
69151
|
+
var import_node_fs52 = __toESM(require("fs"), 1);
|
|
69152
|
+
var import_node_path57 = __toESM(require("path"), 1);
|
|
68906
69153
|
var TunnelStore = class {
|
|
68907
69154
|
constructor(filePath) {
|
|
68908
69155
|
this.filePath = filePath;
|
|
@@ -68910,7 +69157,7 @@ var TunnelStore = class {
|
|
|
68910
69157
|
filePath;
|
|
68911
69158
|
async get() {
|
|
68912
69159
|
try {
|
|
68913
|
-
const raw = await
|
|
69160
|
+
const raw = await import_node_fs52.default.promises.readFile(this.filePath, "utf8");
|
|
68914
69161
|
const obj = JSON.parse(raw);
|
|
68915
69162
|
if (!isPersistedTunnel(obj)) return null;
|
|
68916
69163
|
return obj;
|
|
@@ -68921,22 +69168,22 @@ var TunnelStore = class {
|
|
|
68921
69168
|
}
|
|
68922
69169
|
}
|
|
68923
69170
|
async set(v3) {
|
|
68924
|
-
const dir =
|
|
68925
|
-
await
|
|
69171
|
+
const dir = import_node_path57.default.dirname(this.filePath);
|
|
69172
|
+
await import_node_fs52.default.promises.mkdir(dir, { recursive: true });
|
|
68926
69173
|
const data = JSON.stringify(v3, null, 2);
|
|
68927
69174
|
const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
|
|
68928
|
-
await
|
|
69175
|
+
await import_node_fs52.default.promises.writeFile(tmp, data, { mode: 384 });
|
|
68929
69176
|
if (process.platform !== "win32") {
|
|
68930
69177
|
try {
|
|
68931
|
-
await
|
|
69178
|
+
await import_node_fs52.default.promises.chmod(tmp, 384);
|
|
68932
69179
|
} catch {
|
|
68933
69180
|
}
|
|
68934
69181
|
}
|
|
68935
|
-
await
|
|
69182
|
+
await import_node_fs52.default.promises.rename(tmp, this.filePath);
|
|
68936
69183
|
}
|
|
68937
69184
|
async clear() {
|
|
68938
69185
|
try {
|
|
68939
|
-
await
|
|
69186
|
+
await import_node_fs52.default.promises.unlink(this.filePath);
|
|
68940
69187
|
} catch (err) {
|
|
68941
69188
|
const code = err?.code;
|
|
68942
69189
|
if (code !== "ENOENT") throw err;
|
|
@@ -69031,9 +69278,9 @@ function escape2(v3) {
|
|
|
69031
69278
|
}
|
|
69032
69279
|
|
|
69033
69280
|
// src/tunnel/frpc-binary.ts
|
|
69034
|
-
var
|
|
69035
|
-
var
|
|
69036
|
-
var
|
|
69281
|
+
var import_node_fs53 = __toESM(require("fs"), 1);
|
|
69282
|
+
var import_node_os21 = __toESM(require("os"), 1);
|
|
69283
|
+
var import_node_path58 = __toESM(require("path"), 1);
|
|
69037
69284
|
var import_node_child_process14 = require("child_process");
|
|
69038
69285
|
var import_node_stream4 = require("stream");
|
|
69039
69286
|
var import_promises10 = require("stream/promises");
|
|
@@ -69065,20 +69312,20 @@ function frpcDownloadUrl(version2, p3) {
|
|
|
69065
69312
|
}
|
|
69066
69313
|
async function ensureFrpcBinary(opts) {
|
|
69067
69314
|
if (opts.override) {
|
|
69068
|
-
if (!
|
|
69315
|
+
if (!import_node_fs53.default.existsSync(opts.override)) {
|
|
69069
69316
|
throw new Error(`frpc binary not found at override path: ${opts.override}`);
|
|
69070
69317
|
}
|
|
69071
69318
|
return opts.override;
|
|
69072
69319
|
}
|
|
69073
69320
|
const version2 = opts.version ?? FRPC_VERSION;
|
|
69074
69321
|
const platform = opts.platform ?? detectPlatform();
|
|
69075
|
-
const binDir =
|
|
69076
|
-
|
|
69322
|
+
const binDir = import_node_path58.default.join(opts.dataDir, "bin");
|
|
69323
|
+
import_node_fs53.default.mkdirSync(binDir, { recursive: true });
|
|
69077
69324
|
cleanupStaleArtifacts(binDir);
|
|
69078
|
-
const stableBin =
|
|
69079
|
-
if (
|
|
69325
|
+
const stableBin = import_node_path58.default.join(binDir, "frpc");
|
|
69326
|
+
if (import_node_fs53.default.existsSync(stableBin)) return stableBin;
|
|
69080
69327
|
const partialBin = `${stableBin}.partial`;
|
|
69081
|
-
const tarballPath =
|
|
69328
|
+
const tarballPath = import_node_path58.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
|
|
69082
69329
|
try {
|
|
69083
69330
|
const url = frpcDownloadUrl(version2, platform);
|
|
69084
69331
|
await downloadToFile(url, tarballPath, opts.fetchImpl);
|
|
@@ -69087,8 +69334,8 @@ async function ensureFrpcBinary(opts) {
|
|
|
69087
69334
|
} else {
|
|
69088
69335
|
await extractFrpcFromTarball(tarballPath, binDir, version2, platform, partialBin);
|
|
69089
69336
|
}
|
|
69090
|
-
|
|
69091
|
-
|
|
69337
|
+
import_node_fs53.default.chmodSync(partialBin, 493);
|
|
69338
|
+
import_node_fs53.default.renameSync(partialBin, stableBin);
|
|
69092
69339
|
} finally {
|
|
69093
69340
|
safeUnlink(tarballPath);
|
|
69094
69341
|
safeUnlink(partialBin);
|
|
@@ -69098,15 +69345,15 @@ async function ensureFrpcBinary(opts) {
|
|
|
69098
69345
|
function cleanupStaleArtifacts(binDir) {
|
|
69099
69346
|
let entries;
|
|
69100
69347
|
try {
|
|
69101
|
-
entries =
|
|
69348
|
+
entries = import_node_fs53.default.readdirSync(binDir);
|
|
69102
69349
|
} catch {
|
|
69103
69350
|
return;
|
|
69104
69351
|
}
|
|
69105
69352
|
for (const name of entries) {
|
|
69106
69353
|
if (name.endsWith(".partial") || name.startsWith("extract-")) {
|
|
69107
|
-
const full =
|
|
69354
|
+
const full = import_node_path58.default.join(binDir, name);
|
|
69108
69355
|
try {
|
|
69109
|
-
|
|
69356
|
+
import_node_fs53.default.rmSync(full, { recursive: true, force: true });
|
|
69110
69357
|
} catch {
|
|
69111
69358
|
}
|
|
69112
69359
|
}
|
|
@@ -69114,7 +69361,7 @@ function cleanupStaleArtifacts(binDir) {
|
|
|
69114
69361
|
}
|
|
69115
69362
|
function safeUnlink(p3) {
|
|
69116
69363
|
try {
|
|
69117
|
-
|
|
69364
|
+
import_node_fs53.default.unlinkSync(p3);
|
|
69118
69365
|
} catch {
|
|
69119
69366
|
}
|
|
69120
69367
|
}
|
|
@@ -69125,13 +69372,13 @@ async function downloadToFile(url, dest, fetchImpl) {
|
|
|
69125
69372
|
if (!res.ok || !res.body) {
|
|
69126
69373
|
throw new Error(`download failed: ${res.status} ${res.statusText}`);
|
|
69127
69374
|
}
|
|
69128
|
-
const out =
|
|
69375
|
+
const out = import_node_fs53.default.createWriteStream(dest);
|
|
69129
69376
|
const nodeStream = import_node_stream4.Readable.fromWeb(res.body);
|
|
69130
69377
|
await (0, import_promises10.pipeline)(nodeStream, out);
|
|
69131
69378
|
}
|
|
69132
69379
|
async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
|
|
69133
|
-
const work =
|
|
69134
|
-
|
|
69380
|
+
const work = import_node_path58.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
|
|
69381
|
+
import_node_fs53.default.mkdirSync(work, { recursive: true });
|
|
69135
69382
|
try {
|
|
69136
69383
|
await new Promise((resolve9, reject) => {
|
|
69137
69384
|
const proc = (0, import_node_child_process14.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
|
|
@@ -69139,32 +69386,32 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
|
|
|
69139
69386
|
proc.on("exit", (code) => code === 0 ? resolve9() : reject(new Error(`tar exited ${code}`)));
|
|
69140
69387
|
});
|
|
69141
69388
|
const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
|
|
69142
|
-
const src =
|
|
69143
|
-
if (!
|
|
69389
|
+
const src = import_node_path58.default.join(work, dirName, "frpc");
|
|
69390
|
+
if (!import_node_fs53.default.existsSync(src)) {
|
|
69144
69391
|
throw new Error(`frpc not found inside tarball at ${src}`);
|
|
69145
69392
|
}
|
|
69146
|
-
|
|
69393
|
+
import_node_fs53.default.copyFileSync(src, destBin);
|
|
69147
69394
|
} finally {
|
|
69148
|
-
|
|
69395
|
+
import_node_fs53.default.rmSync(work, { recursive: true, force: true });
|
|
69149
69396
|
}
|
|
69150
69397
|
}
|
|
69151
69398
|
|
|
69152
69399
|
// src/tunnel/frpc-process.ts
|
|
69153
|
-
var
|
|
69154
|
-
var
|
|
69400
|
+
var import_node_fs54 = __toESM(require("fs"), 1);
|
|
69401
|
+
var import_node_path59 = __toESM(require("path"), 1);
|
|
69155
69402
|
var import_node_child_process15 = require("child_process");
|
|
69156
69403
|
function frpcPidFilePath(dataDir) {
|
|
69157
|
-
return
|
|
69404
|
+
return import_node_path59.default.join(dataDir, "frpc.pid");
|
|
69158
69405
|
}
|
|
69159
69406
|
function writeFrpcPid(dataDir, pid) {
|
|
69160
69407
|
try {
|
|
69161
|
-
|
|
69408
|
+
import_node_fs54.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
|
|
69162
69409
|
} catch {
|
|
69163
69410
|
}
|
|
69164
69411
|
}
|
|
69165
69412
|
function clearFrpcPid(dataDir) {
|
|
69166
69413
|
try {
|
|
69167
|
-
|
|
69414
|
+
import_node_fs54.default.unlinkSync(frpcPidFilePath(dataDir));
|
|
69168
69415
|
} catch {
|
|
69169
69416
|
}
|
|
69170
69417
|
}
|
|
@@ -69180,7 +69427,7 @@ function defaultIsPidAlive(pid) {
|
|
|
69180
69427
|
}
|
|
69181
69428
|
function defaultReadPidFile(file) {
|
|
69182
69429
|
try {
|
|
69183
|
-
return
|
|
69430
|
+
return import_node_fs54.default.readFileSync(file, "utf8");
|
|
69184
69431
|
} catch {
|
|
69185
69432
|
return null;
|
|
69186
69433
|
}
|
|
@@ -69196,7 +69443,7 @@ function defaultSleep2(ms) {
|
|
|
69196
69443
|
}
|
|
69197
69444
|
async function killStaleFrpc(deps) {
|
|
69198
69445
|
const pidFile = frpcPidFilePath(deps.dataDir);
|
|
69199
|
-
const tomlPath =
|
|
69446
|
+
const tomlPath = import_node_path59.default.join(deps.dataDir, "frpc.toml");
|
|
69200
69447
|
const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
|
|
69201
69448
|
const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
|
|
69202
69449
|
const killPid = deps.killPidImpl ?? defaultKillPid;
|
|
@@ -69220,7 +69467,7 @@ async function killStaleFrpc(deps) {
|
|
|
69220
69467
|
}
|
|
69221
69468
|
if (victims.size === 0) {
|
|
69222
69469
|
try {
|
|
69223
|
-
|
|
69470
|
+
import_node_fs54.default.unlinkSync(pidFile);
|
|
69224
69471
|
} catch {
|
|
69225
69472
|
}
|
|
69226
69473
|
return;
|
|
@@ -69231,7 +69478,7 @@ async function killStaleFrpc(deps) {
|
|
|
69231
69478
|
}
|
|
69232
69479
|
await sleep2(deps.reapWaitMs ?? 300);
|
|
69233
69480
|
try {
|
|
69234
|
-
|
|
69481
|
+
import_node_fs54.default.unlinkSync(pidFile);
|
|
69235
69482
|
} catch {
|
|
69236
69483
|
}
|
|
69237
69484
|
}
|
|
@@ -69268,7 +69515,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
|
69268
69515
|
var TunnelManager = class {
|
|
69269
69516
|
constructor(deps) {
|
|
69270
69517
|
this.deps = deps;
|
|
69271
|
-
this.store = deps.store ?? new TunnelStore(
|
|
69518
|
+
this.store = deps.store ?? new TunnelStore(import_node_path60.default.join(deps.dataDir, "tunnel.json"));
|
|
69272
69519
|
this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
|
|
69273
69520
|
this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
|
|
69274
69521
|
}
|
|
@@ -69395,7 +69642,7 @@ var TunnelManager = class {
|
|
|
69395
69642
|
dataDir: this.deps.dataDir,
|
|
69396
69643
|
override: this.deps.frpcBinaryOverride ?? void 0
|
|
69397
69644
|
});
|
|
69398
|
-
const tomlPath =
|
|
69645
|
+
const tomlPath = import_node_path60.default.join(this.deps.dataDir, "frpc.toml");
|
|
69399
69646
|
const proxyName = `clawd-${t2.subdomain}-${localPort}-${import_node_crypto17.default.randomBytes(3).toString("hex")}`;
|
|
69400
69647
|
const toml = buildFrpcToml({
|
|
69401
69648
|
serverAddr: t2.frpsHost,
|
|
@@ -69406,14 +69653,14 @@ var TunnelManager = class {
|
|
|
69406
69653
|
localPort,
|
|
69407
69654
|
logLevel: "info"
|
|
69408
69655
|
});
|
|
69409
|
-
await
|
|
69656
|
+
await import_node_fs55.default.promises.writeFile(tomlPath, toml, { mode: 384 });
|
|
69410
69657
|
const proc = (this.deps.spawnImpl ?? import_node_child_process16.spawn)(frpcBin, ["-c", tomlPath], {
|
|
69411
69658
|
stdio: ["ignore", "pipe", "pipe"]
|
|
69412
69659
|
});
|
|
69413
|
-
const logDir =
|
|
69414
|
-
|
|
69415
|
-
const logFilePath =
|
|
69416
|
-
const logStream =
|
|
69660
|
+
const logDir = import_node_path60.default.join(this.deps.dataDir, "log");
|
|
69661
|
+
import_node_fs55.default.mkdirSync(logDir, { recursive: true });
|
|
69662
|
+
const logFilePath = import_node_path60.default.join(logDir, "frpc.log");
|
|
69663
|
+
const logStream = import_node_fs55.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
|
|
69417
69664
|
logStream.on("error", () => {
|
|
69418
69665
|
});
|
|
69419
69666
|
const tee = (chunk) => {
|
|
@@ -69495,28 +69742,28 @@ async function waitForFrpcReady(proc, timeoutMs) {
|
|
|
69495
69742
|
}
|
|
69496
69743
|
|
|
69497
69744
|
// src/tunnel/device-key.ts
|
|
69498
|
-
var
|
|
69499
|
-
var
|
|
69745
|
+
var import_node_os22 = __toESM(require("os"), 1);
|
|
69746
|
+
var import_node_path61 = __toESM(require("path"), 1);
|
|
69500
69747
|
var import_node_crypto18 = __toESM(require("crypto"), 1);
|
|
69501
69748
|
var DERIVE_SALT = "clawd-tunnel-device-v1";
|
|
69502
69749
|
function deriveStableDeviceKey(opts = {}) {
|
|
69503
|
-
const hostname = opts.hostname ??
|
|
69504
|
-
const uid = opts.uid ?? (typeof
|
|
69505
|
-
const home = opts.home ??
|
|
69506
|
-
const defaultDataDir =
|
|
69507
|
-
const normalizedDataDir = opts.dataDir ?
|
|
69750
|
+
const hostname = opts.hostname ?? import_node_os22.default.hostname();
|
|
69751
|
+
const uid = opts.uid ?? (typeof import_node_os22.default.userInfo === "function" ? import_node_os22.default.userInfo().uid : 0);
|
|
69752
|
+
const home = opts.home ?? import_node_os22.default.homedir();
|
|
69753
|
+
const defaultDataDir = import_node_path61.default.resolve(import_node_path61.default.join(home, ".clawd"));
|
|
69754
|
+
const normalizedDataDir = opts.dataDir ? import_node_path61.default.resolve(opts.dataDir) : null;
|
|
69508
69755
|
const isDefaultDir = normalizedDataDir == null || normalizedDataDir === defaultDataDir;
|
|
69509
69756
|
const input = isDefaultDir ? `${hostname}::${uid}` : `${hostname}::${uid}::${normalizedDataDir}`;
|
|
69510
69757
|
return import_node_crypto18.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
|
|
69511
69758
|
}
|
|
69512
69759
|
|
|
69513
69760
|
// src/auth-store.ts
|
|
69514
|
-
var
|
|
69515
|
-
var
|
|
69761
|
+
var import_node_fs56 = __toESM(require("fs"), 1);
|
|
69762
|
+
var import_node_path62 = __toESM(require("path"), 1);
|
|
69516
69763
|
var import_node_crypto19 = __toESM(require("crypto"), 1);
|
|
69517
69764
|
var AUTH_FILE_NAME = "auth.json";
|
|
69518
69765
|
function authFilePath(dataDir) {
|
|
69519
|
-
return
|
|
69766
|
+
return import_node_path62.default.join(dataDir, AUTH_FILE_NAME);
|
|
69520
69767
|
}
|
|
69521
69768
|
function loadOrCreateAuthFile(opts) {
|
|
69522
69769
|
const file = authFilePath(opts.dataDir);
|
|
@@ -69557,7 +69804,7 @@ function defaultGenerateOwnerPrincipalId() {
|
|
|
69557
69804
|
}
|
|
69558
69805
|
function readAuthFile(file) {
|
|
69559
69806
|
try {
|
|
69560
|
-
const raw =
|
|
69807
|
+
const raw = import_node_fs56.default.readFileSync(file, "utf8");
|
|
69561
69808
|
const parsed = JSON.parse(raw);
|
|
69562
69809
|
if (typeof parsed?.token !== "string" || parsed.token.length === 0) {
|
|
69563
69810
|
return null;
|
|
@@ -69578,26 +69825,26 @@ function readAuthFile(file) {
|
|
|
69578
69825
|
}
|
|
69579
69826
|
}
|
|
69580
69827
|
function writeAuthFile(file, content) {
|
|
69581
|
-
|
|
69582
|
-
|
|
69828
|
+
import_node_fs56.default.mkdirSync(import_node_path62.default.dirname(file), { recursive: true });
|
|
69829
|
+
import_node_fs56.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
|
|
69583
69830
|
try {
|
|
69584
|
-
|
|
69831
|
+
import_node_fs56.default.chmodSync(file, 384);
|
|
69585
69832
|
} catch {
|
|
69586
69833
|
}
|
|
69587
69834
|
}
|
|
69588
69835
|
|
|
69589
69836
|
// src/owner-profile.ts
|
|
69590
|
-
var
|
|
69591
|
-
var
|
|
69592
|
-
var
|
|
69837
|
+
var import_node_fs57 = __toESM(require("fs"), 1);
|
|
69838
|
+
var import_node_os23 = __toESM(require("os"), 1);
|
|
69839
|
+
var import_node_path63 = __toESM(require("path"), 1);
|
|
69593
69840
|
var PROFILE_FILENAME = "profile.json";
|
|
69594
69841
|
function profilePath(dataDir) {
|
|
69595
|
-
return
|
|
69842
|
+
return import_node_path63.default.join(dataDir, PROFILE_FILENAME);
|
|
69596
69843
|
}
|
|
69597
69844
|
function loadOwnerProfile(dataDir) {
|
|
69598
69845
|
let raw;
|
|
69599
69846
|
try {
|
|
69600
|
-
raw =
|
|
69847
|
+
raw = import_node_fs57.default.readFileSync(profilePath(dataDir), "utf8");
|
|
69601
69848
|
} catch {
|
|
69602
69849
|
return {};
|
|
69603
69850
|
}
|
|
@@ -69613,11 +69860,11 @@ function loadOwnerProfile(dataDir) {
|
|
|
69613
69860
|
}
|
|
69614
69861
|
function patchOwnerProfile(dataDir, patch) {
|
|
69615
69862
|
const merged = { ...loadOwnerProfile(dataDir), ...patch };
|
|
69616
|
-
|
|
69863
|
+
import_node_fs57.default.writeFileSync(profilePath(dataDir), JSON.stringify(merged, null, 2), { encoding: "utf8", mode: 384 });
|
|
69617
69864
|
return merged;
|
|
69618
69865
|
}
|
|
69619
69866
|
function loadOwnerDisplayName(dataDir) {
|
|
69620
|
-
const fallback =
|
|
69867
|
+
const fallback = import_node_os23.default.userInfo().username;
|
|
69621
69868
|
const displayName = loadOwnerProfile(dataDir).displayName;
|
|
69622
69869
|
if (typeof displayName !== "string" || displayName.length === 0) {
|
|
69623
69870
|
if (displayName !== void 0) {
|
|
@@ -69629,18 +69876,18 @@ function loadOwnerDisplayName(dataDir) {
|
|
|
69629
69876
|
}
|
|
69630
69877
|
|
|
69631
69878
|
// src/feishu-auth/owner-identity-store.ts
|
|
69632
|
-
var
|
|
69633
|
-
var
|
|
69879
|
+
var import_node_fs58 = __toESM(require("fs"), 1);
|
|
69880
|
+
var import_node_path64 = __toESM(require("path"), 1);
|
|
69634
69881
|
var OWNER_IDENTITY_FILE_NAME = "owner-identity.json";
|
|
69635
69882
|
var OwnerIdentityStore = class {
|
|
69636
69883
|
file;
|
|
69637
69884
|
constructor(dataDir) {
|
|
69638
|
-
this.file =
|
|
69885
|
+
this.file = import_node_path64.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
|
|
69639
69886
|
}
|
|
69640
69887
|
read() {
|
|
69641
69888
|
let raw;
|
|
69642
69889
|
try {
|
|
69643
|
-
raw =
|
|
69890
|
+
raw = import_node_fs58.default.readFileSync(this.file, "utf8");
|
|
69644
69891
|
} catch {
|
|
69645
69892
|
return null;
|
|
69646
69893
|
}
|
|
@@ -69667,16 +69914,16 @@ var OwnerIdentityStore = class {
|
|
|
69667
69914
|
};
|
|
69668
69915
|
}
|
|
69669
69916
|
write(record4) {
|
|
69670
|
-
|
|
69671
|
-
|
|
69917
|
+
import_node_fs58.default.mkdirSync(import_node_path64.default.dirname(this.file), { recursive: true });
|
|
69918
|
+
import_node_fs58.default.writeFileSync(this.file, JSON.stringify(record4, null, 2), { mode: 384 });
|
|
69672
69919
|
try {
|
|
69673
|
-
|
|
69920
|
+
import_node_fs58.default.chmodSync(this.file, 384);
|
|
69674
69921
|
} catch {
|
|
69675
69922
|
}
|
|
69676
69923
|
}
|
|
69677
69924
|
clear() {
|
|
69678
69925
|
try {
|
|
69679
|
-
|
|
69926
|
+
import_node_fs58.default.unlinkSync(this.file);
|
|
69680
69927
|
} catch (err) {
|
|
69681
69928
|
const code = err?.code;
|
|
69682
69929
|
if (code !== "ENOENT") throw err;
|
|
@@ -70172,8 +70419,8 @@ function verifyConnectToken(args) {
|
|
|
70172
70419
|
}
|
|
70173
70420
|
|
|
70174
70421
|
// src/feishu-auth/server-key.ts
|
|
70175
|
-
var
|
|
70176
|
-
var
|
|
70422
|
+
var fs75 = __toESM(require("fs"), 1);
|
|
70423
|
+
var path77 = __toESM(require("path"), 1);
|
|
70177
70424
|
var FILE_NAME2 = "server-signing-key.json";
|
|
70178
70425
|
var ServerKeyStore = class {
|
|
70179
70426
|
constructor(dataDir) {
|
|
@@ -70181,12 +70428,12 @@ var ServerKeyStore = class {
|
|
|
70181
70428
|
}
|
|
70182
70429
|
dataDir;
|
|
70183
70430
|
filePath() {
|
|
70184
|
-
return
|
|
70431
|
+
return path77.join(this.dataDir, FILE_NAME2);
|
|
70185
70432
|
}
|
|
70186
70433
|
/** 读缓存的公钥;无缓存 / 损坏 → null(调用方决定是否触发拉取) */
|
|
70187
70434
|
read() {
|
|
70188
70435
|
try {
|
|
70189
|
-
const raw =
|
|
70436
|
+
const raw = fs75.readFileSync(this.filePath(), "utf8");
|
|
70190
70437
|
const parsed = JSON.parse(raw);
|
|
70191
70438
|
if (typeof parsed.publicKeyPem === "string" && parsed.publicKeyPem.includes("PUBLIC KEY")) {
|
|
70192
70439
|
return parsed.publicKeyPem;
|
|
@@ -70201,12 +70448,12 @@ var ServerKeyStore = class {
|
|
|
70201
70448
|
publicKeyPem,
|
|
70202
70449
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
70203
70450
|
};
|
|
70204
|
-
|
|
70205
|
-
|
|
70451
|
+
fs75.mkdirSync(this.dataDir, { recursive: true });
|
|
70452
|
+
fs75.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
|
|
70206
70453
|
}
|
|
70207
70454
|
clear() {
|
|
70208
70455
|
try {
|
|
70209
|
-
|
|
70456
|
+
fs75.unlinkSync(this.filePath());
|
|
70210
70457
|
} catch {
|
|
70211
70458
|
}
|
|
70212
70459
|
}
|
|
@@ -70222,13 +70469,13 @@ var import_node_path80 = __toESM(require("path"), 1);
|
|
|
70222
70469
|
init_protocol();
|
|
70223
70470
|
|
|
70224
70471
|
// src/session/fork.ts
|
|
70225
|
-
var
|
|
70226
|
-
var
|
|
70227
|
-
var
|
|
70472
|
+
var import_node_fs59 = __toESM(require("fs"), 1);
|
|
70473
|
+
var import_node_os24 = __toESM(require("os"), 1);
|
|
70474
|
+
var import_node_path65 = __toESM(require("path"), 1);
|
|
70228
70475
|
var import_node_crypto21 = require("crypto");
|
|
70229
70476
|
init_claude_history();
|
|
70230
70477
|
function readJsonlEntries(file) {
|
|
70231
|
-
const raw =
|
|
70478
|
+
const raw = import_node_fs59.default.readFileSync(file, "utf8");
|
|
70232
70479
|
const out = [];
|
|
70233
70480
|
for (const line of raw.split("\n")) {
|
|
70234
70481
|
const t2 = line.trim();
|
|
@@ -70241,19 +70488,19 @@ function readJsonlEntries(file) {
|
|
|
70241
70488
|
return out;
|
|
70242
70489
|
}
|
|
70243
70490
|
function forkSession(input) {
|
|
70244
|
-
const baseDir = input.baseDir ??
|
|
70245
|
-
let projectDir =
|
|
70246
|
-
let sourceFile =
|
|
70247
|
-
if (!
|
|
70491
|
+
const baseDir = input.baseDir ?? import_node_path65.default.join(import_node_os24.default.homedir(), ".claude");
|
|
70492
|
+
let projectDir = import_node_path65.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
|
|
70493
|
+
let sourceFile = import_node_path65.default.join(projectDir, `${input.toolSessionId}.jsonl`);
|
|
70494
|
+
if (!import_node_fs59.default.existsSync(sourceFile)) {
|
|
70248
70495
|
const found = findTranscriptByToolSessionId(
|
|
70249
|
-
|
|
70496
|
+
import_node_path65.default.join(baseDir, "projects"),
|
|
70250
70497
|
input.toolSessionId
|
|
70251
70498
|
);
|
|
70252
70499
|
if (!found) {
|
|
70253
70500
|
throw new Error(`fork: source transcript not found: ${sourceFile}`);
|
|
70254
70501
|
}
|
|
70255
70502
|
sourceFile = found;
|
|
70256
|
-
projectDir =
|
|
70503
|
+
projectDir = import_node_path65.default.dirname(found);
|
|
70257
70504
|
}
|
|
70258
70505
|
const entries = readJsonlEntries(sourceFile);
|
|
70259
70506
|
const mainEntries = entries.filter((e) => e.isSidechain !== true);
|
|
@@ -70282,17 +70529,17 @@ function forkSession(input) {
|
|
|
70282
70529
|
}
|
|
70283
70530
|
forkedLines.push(JSON.stringify(forked));
|
|
70284
70531
|
}
|
|
70285
|
-
const outDir = input.targetCwd ?
|
|
70286
|
-
const forkedFilePath =
|
|
70287
|
-
|
|
70288
|
-
|
|
70532
|
+
const outDir = input.targetCwd ? import_node_path65.default.join(baseDir, "projects", cwdToHashDir(input.targetCwd)) : projectDir;
|
|
70533
|
+
const forkedFilePath = import_node_path65.default.join(outDir, `${forkedToolSessionId}.jsonl`);
|
|
70534
|
+
import_node_fs59.default.mkdirSync(outDir, { recursive: true });
|
|
70535
|
+
import_node_fs59.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
|
|
70289
70536
|
return { forkedToolSessionId, forkedFilePath };
|
|
70290
70537
|
}
|
|
70291
70538
|
|
|
70292
70539
|
// src/tools/codex-fork.ts
|
|
70293
70540
|
var import_node_child_process17 = require("child_process");
|
|
70294
|
-
var
|
|
70295
|
-
var
|
|
70541
|
+
var import_node_fs60 = __toESM(require("fs"), 1);
|
|
70542
|
+
var import_node_path66 = __toESM(require("path"), 1);
|
|
70296
70543
|
function openCodexAppServer(home, cwd) {
|
|
70297
70544
|
const proc = (0, import_node_child_process17.spawn)(process.env.CODEX_BIN ?? "codex", ["app-server", "--listen", "stdio://"], {
|
|
70298
70545
|
cwd,
|
|
@@ -70312,7 +70559,7 @@ function openCodexAppServer(home, cwd) {
|
|
|
70312
70559
|
async function forkCodexThread(input, deps = {}) {
|
|
70313
70560
|
const source = locateCodexThread(input.roots, input.sourceThreadId);
|
|
70314
70561
|
if (!source) throw new Error(`codex fork: source thread not found: ${input.sourceThreadId}`);
|
|
70315
|
-
const rollout = parseCodexRollout(
|
|
70562
|
+
const rollout = parseCodexRollout(import_node_fs60.default.readFileSync(source.file, "utf8"));
|
|
70316
70563
|
if (rollout.meta?.threadId.toLowerCase() !== input.sourceThreadId.toLowerCase()) {
|
|
70317
70564
|
throw new Error(`codex fork: source thread metadata does not match ${input.sourceThreadId}`);
|
|
70318
70565
|
}
|
|
@@ -70342,7 +70589,7 @@ async function forkCodexThread(input, deps = {}) {
|
|
|
70342
70589
|
if (typeof forkedToolSessionId !== "string" || !forkedToolSessionId) {
|
|
70343
70590
|
throw new Error("codex fork: app-server returned no thread id");
|
|
70344
70591
|
}
|
|
70345
|
-
const forked = locateCodexThread([
|
|
70592
|
+
const forked = locateCodexThread([import_node_path66.default.join(source.home, "sessions")], forkedToolSessionId);
|
|
70346
70593
|
if (!forked) throw new Error(`codex fork: rollout not found for forked thread ${forkedToolSessionId}`);
|
|
70347
70594
|
return { forkedToolSessionId, forkedFilePath: forked.file };
|
|
70348
70595
|
})()]);
|
|
@@ -70353,19 +70600,19 @@ async function forkCodexThread(input, deps = {}) {
|
|
|
70353
70600
|
}
|
|
70354
70601
|
|
|
70355
70602
|
// src/session/external-scan.ts
|
|
70356
|
-
var
|
|
70603
|
+
var import_node_fs61 = __toESM(require("fs"), 1);
|
|
70357
70604
|
var import_promises11 = __toESM(require("fs/promises"), 1);
|
|
70358
|
-
var
|
|
70359
|
-
var
|
|
70605
|
+
var import_node_os25 = __toESM(require("os"), 1);
|
|
70606
|
+
var import_node_path67 = __toESM(require("path"), 1);
|
|
70360
70607
|
var import_node_module = require("module");
|
|
70361
70608
|
var import_node_child_process18 = require("child_process");
|
|
70362
70609
|
var import_meta7 = {};
|
|
70363
70610
|
function defaultRoots() {
|
|
70364
|
-
const home =
|
|
70611
|
+
const home = import_node_os25.default.homedir();
|
|
70365
70612
|
return {
|
|
70366
|
-
claudeProjectsDir:
|
|
70367
|
-
codexDir:
|
|
70368
|
-
clawdDir:
|
|
70613
|
+
claudeProjectsDir: import_node_path67.default.join(home, ".claude", "projects"),
|
|
70614
|
+
codexDir: import_node_path67.default.join(home, ".codex"),
|
|
70615
|
+
clawdDir: import_node_path67.default.join(home, ".clawd")
|
|
70369
70616
|
};
|
|
70370
70617
|
}
|
|
70371
70618
|
function width(s2) {
|
|
@@ -70416,7 +70663,7 @@ function userText(msg) {
|
|
|
70416
70663
|
}
|
|
70417
70664
|
function isDir2(p3) {
|
|
70418
70665
|
try {
|
|
70419
|
-
return
|
|
70666
|
+
return import_node_fs61.default.statSync(p3).isDirectory();
|
|
70420
70667
|
} catch {
|
|
70421
70668
|
return false;
|
|
70422
70669
|
}
|
|
@@ -70425,7 +70672,7 @@ async function scanClaude(roots) {
|
|
|
70425
70672
|
const out = [];
|
|
70426
70673
|
let dirs;
|
|
70427
70674
|
try {
|
|
70428
|
-
dirs =
|
|
70675
|
+
dirs = import_node_fs61.default.readdirSync(roots.claudeProjectsDir, { withFileTypes: true });
|
|
70429
70676
|
} catch {
|
|
70430
70677
|
return out;
|
|
70431
70678
|
}
|
|
@@ -70433,16 +70680,16 @@ async function scanClaude(roots) {
|
|
|
70433
70680
|
if (!d2.isDirectory()) continue;
|
|
70434
70681
|
let files;
|
|
70435
70682
|
try {
|
|
70436
|
-
files =
|
|
70683
|
+
files = import_node_fs61.default.readdirSync(import_node_path67.default.join(roots.claudeProjectsDir, d2.name));
|
|
70437
70684
|
} catch {
|
|
70438
70685
|
continue;
|
|
70439
70686
|
}
|
|
70440
70687
|
for (const name of files) {
|
|
70441
70688
|
if (!name.endsWith(".jsonl")) continue;
|
|
70442
|
-
const file =
|
|
70689
|
+
const file = import_node_path67.default.join(roots.claudeProjectsDir, d2.name, name);
|
|
70443
70690
|
let st2;
|
|
70444
70691
|
try {
|
|
70445
|
-
st2 =
|
|
70692
|
+
st2 = import_node_fs61.default.statSync(file);
|
|
70446
70693
|
} catch {
|
|
70447
70694
|
continue;
|
|
70448
70695
|
}
|
|
@@ -70495,7 +70742,7 @@ async function scanClaude(roots) {
|
|
|
70495
70742
|
return out;
|
|
70496
70743
|
}
|
|
70497
70744
|
async function countCodexTurns(rolloutPath) {
|
|
70498
|
-
if (!rolloutPath || !
|
|
70745
|
+
if (!rolloutPath || !import_node_fs61.default.existsSync(rolloutPath)) return { turns: 0, first: "" };
|
|
70499
70746
|
let turns = 0;
|
|
70500
70747
|
let first = "";
|
|
70501
70748
|
for await (const rec6 of jsonLines(rolloutPath)) {
|
|
@@ -70569,7 +70816,7 @@ async function codexFromRows(rows) {
|
|
|
70569
70816
|
async function scanCodex(roots) {
|
|
70570
70817
|
let dbs = [];
|
|
70571
70818
|
try {
|
|
70572
|
-
dbs =
|
|
70819
|
+
dbs = import_node_fs61.default.readdirSync(roots.codexDir).filter((n2) => /^state_.*\.sqlite$/.test(n2)).sort().map((n2) => import_node_path67.default.join(roots.codexDir, n2));
|
|
70573
70820
|
} catch {
|
|
70574
70821
|
}
|
|
70575
70822
|
if (!dbs.length) return [];
|
|
@@ -70578,14 +70825,14 @@ async function scanCodex(roots) {
|
|
|
70578
70825
|
}
|
|
70579
70826
|
async function scanExternalSessions(rootsIn) {
|
|
70580
70827
|
const roots = { ...defaultRoots(), ...rootsIn };
|
|
70581
|
-
const personaRoot =
|
|
70828
|
+
const personaRoot = import_node_path67.default.join(roots.clawdDir, "personas");
|
|
70582
70829
|
const all = [...await scanClaude(roots), ...await scanCodex(roots)];
|
|
70583
70830
|
const out = [];
|
|
70584
70831
|
for (const c2 of all) {
|
|
70585
70832
|
if (c2.skip) continue;
|
|
70586
70833
|
if (c2.turns < 1) continue;
|
|
70587
70834
|
if (!c2.cwd || !isDir2(c2.cwd)) continue;
|
|
70588
|
-
if (c2.cwd === roots.clawdDir || c2.cwd === personaRoot || c2.cwd.startsWith(personaRoot +
|
|
70835
|
+
if (c2.cwd === roots.clawdDir || c2.cwd === personaRoot || c2.cwd.startsWith(personaRoot + import_node_path67.default.sep) || c2.cwd.startsWith(roots.clawdDir + import_node_path67.default.sep)) {
|
|
70589
70836
|
continue;
|
|
70590
70837
|
}
|
|
70591
70838
|
out.push({
|
|
@@ -70602,13 +70849,13 @@ async function scanExternalSessions(rootsIn) {
|
|
|
70602
70849
|
}
|
|
70603
70850
|
|
|
70604
70851
|
// src/session/import-ledger.ts
|
|
70605
|
-
var
|
|
70606
|
-
var
|
|
70852
|
+
var import_node_fs62 = __toESM(require("fs"), 1);
|
|
70853
|
+
var import_node_path68 = __toESM(require("path"), 1);
|
|
70607
70854
|
var LEDGER_FILENAME = "session-import-ledger.json";
|
|
70608
70855
|
function readImportLedger(dataDir) {
|
|
70609
70856
|
try {
|
|
70610
70857
|
const parsed = JSON.parse(
|
|
70611
|
-
|
|
70858
|
+
import_node_fs62.default.readFileSync(import_node_path68.default.join(dataDir, LEDGER_FILENAME), "utf8")
|
|
70612
70859
|
);
|
|
70613
70860
|
return Array.isArray(parsed) ? parsed : [];
|
|
70614
70861
|
} catch {
|
|
@@ -70616,15 +70863,15 @@ function readImportLedger(dataDir) {
|
|
|
70616
70863
|
}
|
|
70617
70864
|
}
|
|
70618
70865
|
function appendImportLedger(dataDir, entry) {
|
|
70619
|
-
const file =
|
|
70866
|
+
const file = import_node_path68.default.join(dataDir, LEDGER_FILENAME);
|
|
70620
70867
|
const entries = readImportLedger(dataDir);
|
|
70621
70868
|
entries.push(entry);
|
|
70622
|
-
|
|
70869
|
+
import_node_fs62.default.writeFileSync(file, JSON.stringify(entries, null, 2), { encoding: "utf8", mode: 384 });
|
|
70623
70870
|
}
|
|
70624
70871
|
|
|
70625
70872
|
// src/handlers/session.ts
|
|
70626
70873
|
init_protocol();
|
|
70627
|
-
var
|
|
70874
|
+
var import_node_path69 = __toESM(require("path"), 1);
|
|
70628
70875
|
function canReadSearchHit(ctx, file) {
|
|
70629
70876
|
if (!ctx || ctx.principal.kind === "owner") return true;
|
|
70630
70877
|
return canAccessPersona(ctx.grants, file.ownerPersonaId, "read") && file.creatorPrincipalId === ctx.principal.id;
|
|
@@ -70905,7 +71152,7 @@ ${attribution}` } : args;
|
|
|
70905
71152
|
`principal guest:${ctx.principal.id} cannot fork tool session ${args.toolSessionId}`
|
|
70906
71153
|
);
|
|
70907
71154
|
}
|
|
70908
|
-
if (source?.tool === "codex" && args.targetCwd &&
|
|
71155
|
+
if (source?.tool === "codex" && args.targetCwd && import_node_path69.default.resolve(args.targetCwd) !== import_node_path69.default.resolve(source.cwd)) {
|
|
70909
71156
|
throw new ClawdError(ERROR_CODES.FORBIDDEN, "fork: guest targetCwd must match source cwd");
|
|
70910
71157
|
}
|
|
70911
71158
|
}
|
|
@@ -71182,7 +71429,7 @@ function buildPermissionHandlers(deps) {
|
|
|
71182
71429
|
}
|
|
71183
71430
|
|
|
71184
71431
|
// src/handlers/history.ts
|
|
71185
|
-
var
|
|
71432
|
+
var path84 = __toESM(require("path"), 1);
|
|
71186
71433
|
init_protocol();
|
|
71187
71434
|
|
|
71188
71435
|
// src/session/recent-dirs.ts
|
|
@@ -71200,7 +71447,7 @@ function listRecentDirs(store, limit = 50) {
|
|
|
71200
71447
|
}
|
|
71201
71448
|
|
|
71202
71449
|
// src/permission/persona-paths.ts
|
|
71203
|
-
var
|
|
71450
|
+
var path83 = __toESM(require("path"), 1);
|
|
71204
71451
|
function getAllowedPersonaIds(grants, action) {
|
|
71205
71452
|
const ids = /* @__PURE__ */ new Set();
|
|
71206
71453
|
for (const g3 of grants) {
|
|
@@ -71213,42 +71460,42 @@ function getAllowedPersonaIds(grants, action) {
|
|
|
71213
71460
|
return ids;
|
|
71214
71461
|
}
|
|
71215
71462
|
function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
|
|
71216
|
-
const target =
|
|
71463
|
+
const target = path83.resolve(absPath);
|
|
71217
71464
|
if (userWorkDir) {
|
|
71218
|
-
const u2 =
|
|
71219
|
-
const usep = u2.endsWith(
|
|
71465
|
+
const u2 = path83.resolve(userWorkDir);
|
|
71466
|
+
const usep = u2.endsWith(path83.sep) ? "" : path83.sep;
|
|
71220
71467
|
if (target === u2 || target.startsWith(u2 + usep)) return true;
|
|
71221
71468
|
}
|
|
71222
|
-
const root =
|
|
71223
|
-
const sep4 = root.endsWith(
|
|
71469
|
+
const root = path83.resolve(personaRoot);
|
|
71470
|
+
const sep4 = root.endsWith(path83.sep) ? "" : path83.sep;
|
|
71224
71471
|
if (!target.startsWith(root + sep4)) return false;
|
|
71225
|
-
const rel =
|
|
71472
|
+
const rel = path83.relative(root, target);
|
|
71226
71473
|
if (!rel || rel.startsWith("..")) return false;
|
|
71227
|
-
const personaId2 = rel.split(
|
|
71474
|
+
const personaId2 = rel.split(path83.sep)[0];
|
|
71228
71475
|
if (!personaId2) return false;
|
|
71229
71476
|
const allowed = getAllowedPersonaIds(grants, action);
|
|
71230
71477
|
if (allowed === "*") return true;
|
|
71231
71478
|
return allowed.has(personaId2);
|
|
71232
71479
|
}
|
|
71233
71480
|
function personaIdFromPath(absPath, personaRoot) {
|
|
71234
|
-
const root =
|
|
71235
|
-
const target =
|
|
71236
|
-
const sep4 = root.endsWith(
|
|
71481
|
+
const root = path83.resolve(personaRoot);
|
|
71482
|
+
const target = path83.resolve(absPath);
|
|
71483
|
+
const sep4 = root.endsWith(path83.sep) ? "" : path83.sep;
|
|
71237
71484
|
if (!target.startsWith(root + sep4)) return null;
|
|
71238
|
-
const rel =
|
|
71485
|
+
const rel = path83.relative(root, target);
|
|
71239
71486
|
if (!rel || rel.startsWith("..")) return null;
|
|
71240
|
-
const id = rel.split(
|
|
71487
|
+
const id = rel.split(path83.sep)[0];
|
|
71241
71488
|
return id || null;
|
|
71242
71489
|
}
|
|
71243
71490
|
function isPathWithin(dir, absPath) {
|
|
71244
|
-
const d2 =
|
|
71245
|
-
const t2 =
|
|
71246
|
-
const sep4 = d2.endsWith(
|
|
71491
|
+
const d2 = path83.resolve(dir);
|
|
71492
|
+
const t2 = path83.resolve(absPath);
|
|
71493
|
+
const sep4 = d2.endsWith(path83.sep) ? "" : path83.sep;
|
|
71247
71494
|
return t2 === d2 || t2.startsWith(d2 + sep4);
|
|
71248
71495
|
}
|
|
71249
71496
|
function isPathInGuestBoundary(personaRoot, personaId2, userWorkDir, absPath) {
|
|
71250
71497
|
if (userWorkDir && isPathWithin(userWorkDir, absPath)) return true;
|
|
71251
|
-
return personaIdFromPath(
|
|
71498
|
+
return personaIdFromPath(path83.resolve(absPath), personaRoot) === personaId2;
|
|
71252
71499
|
}
|
|
71253
71500
|
|
|
71254
71501
|
// src/handlers/history.ts
|
|
@@ -71302,7 +71549,7 @@ function buildHistoryHandlers(deps) {
|
|
|
71302
71549
|
if (!pid) return false;
|
|
71303
71550
|
return isGuestPathAllowed(
|
|
71304
71551
|
ctx.grants,
|
|
71305
|
-
|
|
71552
|
+
path84.join(personaRoot, pid),
|
|
71306
71553
|
personaRoot,
|
|
71307
71554
|
"read",
|
|
71308
71555
|
userWorkDir
|
|
@@ -71314,7 +71561,7 @@ function buildHistoryHandlers(deps) {
|
|
|
71314
71561
|
};
|
|
71315
71562
|
const list = async (frame, _client, ctx) => {
|
|
71316
71563
|
const args = HistoryListArgs.parse(frame);
|
|
71317
|
-
assertGuestPath(ctx,
|
|
71564
|
+
assertGuestPath(ctx, path84.resolve(args.projectPath), personaRoot, "history:list", usersRoot);
|
|
71318
71565
|
const sessions = await history.listSessions(args);
|
|
71319
71566
|
return { response: { type: "history:list", sessions } };
|
|
71320
71567
|
};
|
|
@@ -71362,14 +71609,14 @@ function buildHistoryHandlers(deps) {
|
|
|
71362
71609
|
};
|
|
71363
71610
|
const subagents = async (frame, _client, ctx) => {
|
|
71364
71611
|
const args = HistorySubagentsArgs.parse(frame);
|
|
71365
|
-
assertGuestPath(ctx,
|
|
71612
|
+
assertGuestPath(ctx, path84.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
|
|
71366
71613
|
assertGuestOwnsToolSession(ctx, args.toolSessionId, "history:subagents");
|
|
71367
71614
|
const subs = await historyReaderForToolSession(args.toolSessionId).listSubagents(args);
|
|
71368
71615
|
return { response: { type: "history:subagents", subagents: subs } };
|
|
71369
71616
|
};
|
|
71370
71617
|
const subagentRead = async (frame, _client, ctx) => {
|
|
71371
71618
|
const args = HistorySubagentReadArgs.parse(frame);
|
|
71372
|
-
assertGuestPath(ctx,
|
|
71619
|
+
assertGuestPath(ctx, path84.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
|
|
71373
71620
|
assertGuestOwnsToolSession(ctx, args.toolSessionId, "history:subagent-read");
|
|
71374
71621
|
const res = await historyReaderForToolSession(args.toolSessionId).readSubagent(args);
|
|
71375
71622
|
return { response: { type: "history:subagent-read", ...res } };
|
|
@@ -71379,7 +71626,7 @@ function buildHistoryHandlers(deps) {
|
|
|
71379
71626
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
71380
71627
|
const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
|
|
71381
71628
|
const filtered = dirs.filter(
|
|
71382
|
-
(d2) => isGuestPathAllowed(ctx.grants,
|
|
71629
|
+
(d2) => isGuestPathAllowed(ctx.grants, path84.resolve(d2.cwd), personaRoot, "read", userWorkDir)
|
|
71383
71630
|
);
|
|
71384
71631
|
return { response: { type: "history:recentDirs", dirs: filtered } };
|
|
71385
71632
|
}
|
|
@@ -71396,17 +71643,17 @@ function buildHistoryHandlers(deps) {
|
|
|
71396
71643
|
}
|
|
71397
71644
|
|
|
71398
71645
|
// src/handlers/projects.ts
|
|
71399
|
-
var
|
|
71400
|
-
var
|
|
71401
|
-
var
|
|
71646
|
+
var fs80 = __toESM(require("fs"), 1);
|
|
71647
|
+
var os27 = __toESM(require("os"), 1);
|
|
71648
|
+
var path85 = __toESM(require("path"), 1);
|
|
71402
71649
|
var import_node_child_process19 = require("child_process");
|
|
71403
71650
|
init_protocol();
|
|
71404
|
-
var DEFAULT_PROJECTS_ROOT =
|
|
71651
|
+
var DEFAULT_PROJECTS_ROOT = path85.join(os27.homedir(), "Documents", "ChatGPT");
|
|
71405
71652
|
function allocateDir(root, name) {
|
|
71406
|
-
let candidate =
|
|
71653
|
+
let candidate = path85.join(root, name);
|
|
71407
71654
|
let n2 = 2;
|
|
71408
|
-
while (
|
|
71409
|
-
candidate =
|
|
71655
|
+
while (fs80.existsSync(candidate)) {
|
|
71656
|
+
candidate = path85.join(root, `${name} ${n2}`);
|
|
71410
71657
|
n2 += 1;
|
|
71411
71658
|
}
|
|
71412
71659
|
return candidate;
|
|
@@ -71434,7 +71681,7 @@ function buildProjectHandlers(deps) {
|
|
|
71434
71681
|
throw new ClawdError(ERROR_CODES.INVALID_CWD, "project:reveal \u4EC5\u652F\u6301 macOS");
|
|
71435
71682
|
}
|
|
71436
71683
|
try {
|
|
71437
|
-
if (!
|
|
71684
|
+
if (!fs80.statSync(args.path).isDirectory()) throw new Error("not dir");
|
|
71438
71685
|
} catch {
|
|
71439
71686
|
throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${args.path}`);
|
|
71440
71687
|
}
|
|
@@ -71450,7 +71697,7 @@ function buildProjectHandlers(deps) {
|
|
|
71450
71697
|
let target;
|
|
71451
71698
|
if (args.path) {
|
|
71452
71699
|
try {
|
|
71453
|
-
if (!
|
|
71700
|
+
if (!fs80.statSync(args.path).isDirectory()) throw new Error("not dir");
|
|
71454
71701
|
} catch {
|
|
71455
71702
|
throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${args.path}`);
|
|
71456
71703
|
}
|
|
@@ -71458,15 +71705,15 @@ function buildProjectHandlers(deps) {
|
|
|
71458
71705
|
} else {
|
|
71459
71706
|
const name = args.name;
|
|
71460
71707
|
try {
|
|
71461
|
-
|
|
71708
|
+
fs80.mkdirSync(root, { recursive: true });
|
|
71462
71709
|
target = allocateDir(root, name);
|
|
71463
|
-
|
|
71710
|
+
fs80.mkdirSync(target);
|
|
71464
71711
|
} catch (err) {
|
|
71465
71712
|
throw new ClawdError(ERROR_CODES.INVALID_CWD, `\u521B\u5EFA\u9879\u76EE\u76EE\u5F55\u5931\u8D25: ${String(err)}`);
|
|
71466
71713
|
}
|
|
71467
71714
|
const git2 = (0, import_node_child_process19.spawnSync)("git", ["init"], { cwd: target, stdio: "ignore" });
|
|
71468
71715
|
if (git2.status !== 0) {
|
|
71469
|
-
|
|
71716
|
+
fs80.rmSync(target, { recursive: true, force: true });
|
|
71470
71717
|
throw new ClawdError(
|
|
71471
71718
|
ERROR_CODES.INVALID_CWD,
|
|
71472
71719
|
`git init \u5931\u8D25\uFF08${git2.error ? String(git2.error) : `exit ${git2.status}`}\uFF09: ${target}`
|
|
@@ -71491,9 +71738,9 @@ function buildProjectHandlers(deps) {
|
|
|
71491
71738
|
}
|
|
71492
71739
|
|
|
71493
71740
|
// src/handlers/workspace.ts
|
|
71494
|
-
var
|
|
71741
|
+
var path86 = __toESM(require("path"), 1);
|
|
71495
71742
|
init_protocol();
|
|
71496
|
-
var
|
|
71743
|
+
var os28 = __toESM(require("os"), 1);
|
|
71497
71744
|
init_protocol();
|
|
71498
71745
|
init_protocol();
|
|
71499
71746
|
function buildEnabledPluginNames(personaManager, personaId2) {
|
|
@@ -71533,23 +71780,23 @@ function buildWorkspaceHandlers(deps) {
|
|
|
71533
71780
|
const list = async (frame, _client, ctx) => {
|
|
71534
71781
|
const args = WorkspaceListArgs.parse(frame);
|
|
71535
71782
|
const isGuest = ctx?.principal.kind === "guest";
|
|
71536
|
-
const fallbackCwd = isGuest && personaRoot ? personaRoot :
|
|
71537
|
-
const resolvedCwd =
|
|
71538
|
-
const target = args.path ?
|
|
71783
|
+
const fallbackCwd = isGuest && personaRoot ? personaRoot : os28.homedir();
|
|
71784
|
+
const resolvedCwd = path86.resolve(args.cwd ?? fallbackCwd);
|
|
71785
|
+
const target = args.path ? path86.resolve(resolvedCwd, args.path) : resolvedCwd;
|
|
71539
71786
|
assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
|
|
71540
71787
|
const res = workspace.list({ ...args, cwd: resolvedCwd });
|
|
71541
71788
|
return { response: { type: "workspace:list", ...res } };
|
|
71542
71789
|
};
|
|
71543
71790
|
const read = async (frame, _client, ctx) => {
|
|
71544
71791
|
const args = WorkspaceReadArgs.parse(frame);
|
|
71545
|
-
const target =
|
|
71792
|
+
const target = path86.isAbsolute(args.path) ? path86.resolve(args.path) : path86.resolve(args.cwd, args.path);
|
|
71546
71793
|
assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
|
|
71547
71794
|
const res = workspace.read(args);
|
|
71548
71795
|
return { response: { type: "workspace:read", ...res } };
|
|
71549
71796
|
};
|
|
71550
71797
|
const skillsList = async (frame, _client, ctx) => {
|
|
71551
71798
|
const args = SkillsListArgs.parse(frame);
|
|
71552
|
-
const cwdAbs =
|
|
71799
|
+
const cwdAbs = path86.resolve(args.cwd);
|
|
71553
71800
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
|
|
71554
71801
|
const list2 = await getSkillsForTool(args.tool ?? "claude", cwdAbs);
|
|
71555
71802
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
@@ -71561,7 +71808,7 @@ function buildWorkspaceHandlers(deps) {
|
|
|
71561
71808
|
};
|
|
71562
71809
|
const agentsList = async (frame, _client, ctx) => {
|
|
71563
71810
|
const args = AgentsListArgs.parse(frame);
|
|
71564
|
-
const cwdAbs =
|
|
71811
|
+
const cwdAbs = path86.resolve(args.cwd);
|
|
71565
71812
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
|
|
71566
71813
|
if (isCodexFamily(args.tool) || isPiFamily(args.tool)) {
|
|
71567
71814
|
return { response: { type: "agents:list", agents: [] } };
|
|
@@ -71583,20 +71830,20 @@ function buildWorkspaceHandlers(deps) {
|
|
|
71583
71830
|
}
|
|
71584
71831
|
|
|
71585
71832
|
// src/handlers/git.ts
|
|
71586
|
-
var
|
|
71833
|
+
var path88 = __toESM(require("path"), 1);
|
|
71587
71834
|
init_protocol();
|
|
71588
71835
|
init_protocol();
|
|
71589
71836
|
|
|
71590
71837
|
// src/workspace/git.ts
|
|
71591
71838
|
var import_node_child_process20 = require("child_process");
|
|
71592
|
-
var
|
|
71593
|
-
var
|
|
71839
|
+
var import_node_fs63 = __toESM(require("fs"), 1);
|
|
71840
|
+
var import_node_path70 = __toESM(require("path"), 1);
|
|
71594
71841
|
var import_node_util2 = require("util");
|
|
71595
71842
|
var pexec = (0, import_node_util2.promisify)(import_node_child_process20.execFile);
|
|
71596
71843
|
function normalizePath(p3) {
|
|
71597
|
-
const resolved =
|
|
71844
|
+
const resolved = import_node_path70.default.resolve(p3);
|
|
71598
71845
|
try {
|
|
71599
|
-
return
|
|
71846
|
+
return import_node_fs63.default.realpathSync(resolved);
|
|
71600
71847
|
} catch {
|
|
71601
71848
|
return resolved;
|
|
71602
71849
|
}
|
|
@@ -71670,7 +71917,7 @@ async function listGitBranches(cwd) {
|
|
|
71670
71917
|
function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
|
|
71671
71918
|
if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
|
|
71672
71919
|
const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
|
|
71673
|
-
if (!isGuestPathAllowed(ctx.grants,
|
|
71920
|
+
if (!isGuestPathAllowed(ctx.grants, path88.resolve(cwd), personaRoot, "read", userWorkDir)) {
|
|
71674
71921
|
throw new ClawdError(
|
|
71675
71922
|
ERROR_CODES.UNAUTHORIZED,
|
|
71676
71923
|
`guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
|
|
@@ -71927,12 +72174,12 @@ async function queryCodexAccount(deps = {}) {
|
|
|
71927
72174
|
}
|
|
71928
72175
|
|
|
71929
72176
|
// src/tools/pi-account.ts
|
|
71930
|
-
var
|
|
71931
|
-
var
|
|
72177
|
+
var import_node_fs64 = __toESM(require("fs"), 1);
|
|
72178
|
+
var import_node_path71 = __toESM(require("path"), 1);
|
|
71932
72179
|
function readPiCredentials(agentDir) {
|
|
71933
72180
|
let raw;
|
|
71934
72181
|
try {
|
|
71935
|
-
raw = JSON.parse(
|
|
72182
|
+
raw = JSON.parse(import_node_fs64.default.readFileSync(import_node_path71.default.join(agentDir, "auth.json"), "utf8"));
|
|
71936
72183
|
} catch {
|
|
71937
72184
|
return {};
|
|
71938
72185
|
}
|
|
@@ -72015,81 +72262,6 @@ function buildEngineHandlers(deps, overrides = {}) {
|
|
|
72015
72262
|
return { "engine:status": status, "engine:connectPool": connectPool };
|
|
72016
72263
|
}
|
|
72017
72264
|
|
|
72018
|
-
// src/tools/subscription-channels-apply.ts
|
|
72019
|
-
var import_node_fs64 = __toESM(require("fs"), 1);
|
|
72020
|
-
var import_node_os25 = __toESM(require("os"), 1);
|
|
72021
|
-
var import_node_path71 = __toESM(require("path"), 1);
|
|
72022
|
-
var TABLE_HEADER = /^\s*\[\[?\s*([A-Za-z0-9_.-]+)\s*\]\]?\s*(?:#.*)?$/;
|
|
72023
|
-
var KEY_LINE = /^\s*([A-Za-z0-9_.-]+)\s*=/;
|
|
72024
|
-
function stripCodexProvider(text) {
|
|
72025
|
-
const out = [];
|
|
72026
|
-
let inProviderSection = false;
|
|
72027
|
-
for (const line of text.split("\n")) {
|
|
72028
|
-
const headerMatch = TABLE_HEADER.exec(line);
|
|
72029
|
-
if (headerMatch) {
|
|
72030
|
-
const section = headerMatch[1].trim();
|
|
72031
|
-
inProviderSection = section === "model_providers" || section.startsWith("model_providers.");
|
|
72032
|
-
if (inProviderSection) continue;
|
|
72033
|
-
out.push(line);
|
|
72034
|
-
continue;
|
|
72035
|
-
}
|
|
72036
|
-
if (inProviderSection) continue;
|
|
72037
|
-
const keyMatch = KEY_LINE.exec(line);
|
|
72038
|
-
if (keyMatch) {
|
|
72039
|
-
const key = keyMatch[1].trim();
|
|
72040
|
-
if (key === "model_provider" || key.startsWith("model_providers.")) {
|
|
72041
|
-
continue;
|
|
72042
|
-
}
|
|
72043
|
-
}
|
|
72044
|
-
out.push(line);
|
|
72045
|
-
}
|
|
72046
|
-
return out.join("\n").trim();
|
|
72047
|
-
}
|
|
72048
|
-
function applyCodexSubscriptionChannel(opts) {
|
|
72049
|
-
const codexHome = opts.codexHome || process.env.CODEX_HOME || import_node_path71.default.join(import_node_os25.default.homedir(), ".codex");
|
|
72050
|
-
import_node_fs64.default.mkdirSync(codexHome, { recursive: true });
|
|
72051
|
-
const configFile = import_node_path71.default.join(codexHome, "config.toml");
|
|
72052
|
-
const original = import_node_fs64.default.existsSync(configFile) ? import_node_fs64.default.readFileSync(configFile, "utf8") : "";
|
|
72053
|
-
const rest = stripCodexProvider(original);
|
|
72054
|
-
let content;
|
|
72055
|
-
if (opts.channel) {
|
|
72056
|
-
const ch = opts.channel;
|
|
72057
|
-
content = [
|
|
72058
|
-
'model_provider = "cliproxyapi"',
|
|
72059
|
-
...rest ? ["", rest] : [],
|
|
72060
|
-
"",
|
|
72061
|
-
"[model_providers.cliproxyapi]",
|
|
72062
|
-
'name = "cliproxyapi"',
|
|
72063
|
-
`base_url = ${JSON.stringify(ch.baseUrl)}`,
|
|
72064
|
-
'wire_api = "responses"',
|
|
72065
|
-
`auth = { command = "echo", args = [${JSON.stringify(ch.apiKey)}] }`,
|
|
72066
|
-
""
|
|
72067
|
-
].join("\n");
|
|
72068
|
-
} else {
|
|
72069
|
-
content = [
|
|
72070
|
-
'model_provider = "openai"',
|
|
72071
|
-
...rest ? ["", rest] : [],
|
|
72072
|
-
""
|
|
72073
|
-
].join("\n");
|
|
72074
|
-
}
|
|
72075
|
-
const tmpFile = `${configFile}.tmp.${Date.now()}`;
|
|
72076
|
-
import_node_fs64.default.writeFileSync(tmpFile, content, { mode: 384 });
|
|
72077
|
-
import_node_fs64.default.renameSync(tmpFile, configFile);
|
|
72078
|
-
}
|
|
72079
|
-
function applyPiSubscriptionChannel(opts) {
|
|
72080
|
-
const agentDir = opts.agentDir || process.env.PI_CODING_AGENT_DIR || import_node_path71.default.join(import_node_os25.default.homedir(), ".pi", "agent");
|
|
72081
|
-
if (!import_node_fs64.default.existsSync(agentDir)) return false;
|
|
72082
|
-
const configFile = import_node_path71.default.join(agentDir, "cliproxyapi.json");
|
|
72083
|
-
if (opts.channel) {
|
|
72084
|
-
const data = { baseUrl: opts.channel.baseUrl, apiKey: opts.channel.apiKey };
|
|
72085
|
-
const tmp = `${configFile}.tmp.${Date.now()}`;
|
|
72086
|
-
import_node_fs64.default.writeFileSync(tmp, JSON.stringify(data, null, 2) + "\n", { mode: 384 });
|
|
72087
|
-
import_node_fs64.default.renameSync(tmp, configFile);
|
|
72088
|
-
return true;
|
|
72089
|
-
}
|
|
72090
|
-
return false;
|
|
72091
|
-
}
|
|
72092
|
-
|
|
72093
72265
|
// src/handlers/channels.ts
|
|
72094
72266
|
function buildChannelsHandlers(deps) {
|
|
72095
72267
|
const get = async () => {
|
|
@@ -73092,7 +73264,7 @@ function computeMethodAccess(args) {
|
|
|
73092
73264
|
}
|
|
73093
73265
|
|
|
73094
73266
|
// src/version.ts
|
|
73095
|
-
var version = "0.2.
|
|
73267
|
+
var version = "0.2.604".length > 0 ? "0.2.604" : "dev";
|
|
73096
73268
|
|
|
73097
73269
|
// src/cli-probe/probe.ts
|
|
73098
73270
|
var fs83 = __toESM(require("fs"), 1);
|
|
@@ -75720,6 +75892,8 @@ async function startDaemon(config) {
|
|
|
75720
75892
|
let transport = null;
|
|
75721
75893
|
const personaStore = new PersonaStore(import_node_path84.default.join(config.dataDir, "personas"));
|
|
75722
75894
|
const subscriptionChannelStore = new SubscriptionChannelStore({ dataDir: config.dataDir });
|
|
75895
|
+
const activeSubscriptionChannel = subscriptionChannelStore.getActive();
|
|
75896
|
+
if (activeSubscriptionChannel) applyPiSubscriptionChannel({ channel: activeSubscriptionChannel });
|
|
75723
75897
|
const usersRoot = import_node_path84.default.join(config.dataDir, "users");
|
|
75724
75898
|
const defaultsRoot = findDefaultsRoot(logger);
|
|
75725
75899
|
if (defaultsRoot) {
|