@dotobokuri/fleet-console 1.5.5 → 1.6.0
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/AGENTS.md +13 -11
- package/dist/cli-bin.mjs +1566 -495
- package/dist/cli.d.ts +6 -1
- package/dist/cli.mjs +1566 -495
- package/dist/client/assets/{_baseUniq-CpEjig2A.js → _baseUniq-CYDnUUwD.js} +1 -1
- package/dist/client/assets/{arc-BmymS_Kz.js → arc-C2kUi1S_.js} +1 -1
- package/dist/client/assets/{architectureDiagram-Q4EWVU46-D1d0KVz1.js → architectureDiagram-Q4EWVU46-CsfgL2zC.js} +1 -1
- package/dist/client/assets/{blockDiagram-DXYQGD6D-Cwuv0sNk.js → blockDiagram-DXYQGD6D-uqim2Pmo.js} +1 -1
- package/dist/client/assets/{c4Diagram-AHTNJAMY-Bsk-GjC_.js → c4Diagram-AHTNJAMY-CRz88GqP.js} +1 -1
- package/dist/client/assets/channel-BDggAVtM.js +1 -0
- package/dist/client/assets/{chunk-4BX2VUAB-ZM4i9T4D.js → chunk-4BX2VUAB-DNgf85a7.js} +1 -1
- package/dist/client/assets/{chunk-4TB4RGXK-Sw5ODKRj.js → chunk-4TB4RGXK-Ds39jFtV.js} +1 -1
- package/dist/client/assets/{chunk-55IACEB6-DDDLwVg4.js → chunk-55IACEB6-Bv7hCHgD.js} +1 -1
- package/dist/client/assets/{chunk-EDXVE4YY-BNk5Xk1Q.js → chunk-EDXVE4YY-BUjgWLOR.js} +1 -1
- package/dist/client/assets/{chunk-FMBD7UC4-C_CC6grw.js → chunk-FMBD7UC4-WVMeE3Je.js} +1 -1
- package/dist/client/assets/{chunk-OYMX7WX6-DTbaYVUc.js → chunk-OYMX7WX6-Bd5Z4NNL.js} +1 -1
- package/dist/client/assets/{chunk-QZHKN3VN-i7z9jXPR.js → chunk-QZHKN3VN-BfIbGoT4.js} +1 -1
- package/dist/client/assets/{chunk-YZCP3GAM-cTSeZOtz.js → chunk-YZCP3GAM-T_CDhFqg.js} +1 -1
- package/dist/client/assets/classDiagram-6PBFFD2Q-AVod154E.js +1 -0
- package/dist/client/assets/classDiagram-v2-HSJHXN6E-AVod154E.js +1 -0
- package/dist/client/assets/clone-DMJcvMWj.js +1 -0
- package/dist/client/assets/{cose-bilkent-S5V4N54A-uVW4wTRq.js → cose-bilkent-S5V4N54A-M6EvTH7M.js} +1 -1
- package/dist/client/assets/{dagre-KV5264BT-CclQ97X6.js → dagre-KV5264BT-UUCScvPY.js} +1 -1
- package/dist/client/assets/{diagram-5BDNPKRD-eZaXK0Xj.js → diagram-5BDNPKRD-BnmEvwtB.js} +1 -1
- package/dist/client/assets/{diagram-G4DWMVQ6-DIQ8qOFv.js → diagram-G4DWMVQ6-QHdTQz1G.js} +1 -1
- package/dist/client/assets/{diagram-MMDJMWI5-B_EbeR8B.js → diagram-MMDJMWI5-B-4tZ6wC.js} +1 -1
- package/dist/client/assets/{diagram-TYMM5635-DI64qX-Y.js → diagram-TYMM5635-D5KVosUo.js} +1 -1
- package/dist/client/assets/{erDiagram-SMLLAGMA-DLkwbOsk.js → erDiagram-SMLLAGMA-B-FwpOjI.js} +1 -1
- package/dist/client/assets/{flowDiagram-DWJPFMVM-BWvMzejD.js → flowDiagram-DWJPFMVM-CO00mjhm.js} +1 -1
- package/dist/client/assets/fraunces-latin-ext-standard-italic-CGbN9UgK.woff2 +0 -0
- package/dist/client/assets/fraunces-latin-standard-italic-lSdLDfvT.woff2 +0 -0
- package/dist/client/assets/fraunces-vietnamese-standard-italic-DxWqP7Ku.woff2 +0 -0
- package/dist/client/assets/{ganttDiagram-T4ZO3ILL-B4qUxmRl.js → ganttDiagram-T4ZO3ILL-ChcRAmXN.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-UUTBAWPF-CnvcLURP.js → gitGraphDiagram-UUTBAWPF-BWSq2uT3.js} +1 -1
- package/dist/client/assets/{graph-N4oFFLXe.js → graph-mErvxWG_.js} +1 -1
- package/dist/client/assets/index-B4QPttGw.css +1 -0
- package/dist/client/assets/index-GN6Lp6Jj.js +734 -0
- package/dist/client/assets/{infoDiagram-42DDH7IO-3uxP8aX_.js → infoDiagram-42DDH7IO-CchQFIPi.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-UXIWVN3A-DQomHvSO.js → ishikawaDiagram-UXIWVN3A-BAsF6BnZ.js} +1 -1
- package/dist/client/assets/{journeyDiagram-VCZTEJTY-C_Ogwo77.js → journeyDiagram-VCZTEJTY-DE0wiQxC.js} +1 -1
- package/dist/client/assets/{kanban-definition-6JOO6SKY-CGOeur5D.js → kanban-definition-6JOO6SKY-BzPJLpKw.js} +1 -1
- package/dist/client/assets/{layout-DKlBkSB9.js → layout-CO0unZG0.js} +1 -1
- package/dist/client/assets/{linear-2pQUtBdp.js → linear-CkDoVGz5.js} +1 -1
- package/dist/client/assets/{mermaid.core-BrseLPLb.js → mermaid.core-BWqsf-WS.js} +4 -4
- package/dist/client/assets/{min-OFtHLPyF.js → min-BMb-G34C.js} +1 -1
- package/dist/client/assets/{mindmap-definition-QFDTVHPH-DQk9T3wA.js → mindmap-definition-QFDTVHPH-XVxnUTPw.js} +1 -1
- package/dist/client/assets/{pieDiagram-DEJITSTG-Btu4aJWj.js → pieDiagram-DEJITSTG-CKM6Cfhz.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-34T5L4WZ-BHMDVip9.js → quadrantDiagram-34T5L4WZ-Dn_2AZqA.js} +1 -1
- package/dist/client/assets/{requirementDiagram-MS252O5E-CbXi80dX.js → requirementDiagram-MS252O5E-uNgGGE60.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-XADWPNL6-D5c7vUw4.js → sankeyDiagram-XADWPNL6-B75Ahck1.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-FGHM5R23-CGuRanG_.js → sequenceDiagram-FGHM5R23-Cw5UNG2_.js} +1 -1
- package/dist/client/assets/{stateDiagram-FHFEXIEX-CVD3CB69.js → stateDiagram-FHFEXIEX-C6u6py_B.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-BMBsbsoy.js +1 -0
- package/dist/client/assets/{timeline-definition-GMOUNBTQ-DMTeeglq.js → timeline-definition-GMOUNBTQ-Bi50wA17.js} +1 -1
- package/dist/client/assets/{vennDiagram-DHZGUBPP-CQ6TwRhb.js → vennDiagram-DHZGUBPP-CufQGlDN.js} +1 -1
- package/dist/client/assets/{wardley-RL74JXVD-DdgusU4o.js → wardley-RL74JXVD-BQLghHpH.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-NUSXRM2D-BFsWqK49.js → wardleyDiagram-NUSXRM2D-C-_4o-CK.js} +1 -1
- package/dist/client/assets/{xychartDiagram-5P7HB3ND-Hca3jUV6.js → xychartDiagram-5P7HB3ND-e4ekvSc7.js} +1 -1
- package/dist/client/index.html +2 -2
- package/package.json +1 -1
- package/dist/client/assets/channel--qpYuR58.js +0 -1
- package/dist/client/assets/classDiagram-6PBFFD2Q-BAI-fNQ3.js +0 -1
- package/dist/client/assets/classDiagram-v2-HSJHXN6E-BAI-fNQ3.js +0 -1
- package/dist/client/assets/clone-CqNqlAzp.js +0 -1
- package/dist/client/assets/index-DfJLxHX8.js +0 -734
- package/dist/client/assets/index-uNbiLDxs.css +0 -1
- package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-BevvDvg0.js +0 -1
package/dist/cli-bin.mjs
CHANGED
|
@@ -4,14 +4,14 @@ import * as fs5 from 'fs';
|
|
|
4
4
|
import fs5__default, { readFileSync, existsSync, mkdtempSync, writeFileSync, mkdirSync, rmSync, chmodSync, renameSync, readdirSync, constants, openSync, closeSync, lstatSync, unlinkSync, realpathSync, statSync, symlinkSync, fstatSync } from 'fs';
|
|
5
5
|
import * as path93 from 'path';
|
|
6
6
|
import path93__default, { join, resolve, relative, dirname } from 'path';
|
|
7
|
-
import
|
|
7
|
+
import process5 from 'process';
|
|
8
8
|
import { fileURLToPath, pathToFileURL } from 'url';
|
|
9
9
|
import * as os22 from 'os';
|
|
10
10
|
import os22__default from 'os';
|
|
11
11
|
import { EventEmitter } from 'events';
|
|
12
12
|
import { stat, mkdir, readFile, readdir, appendFile, writeFile, rename, access, rm } from 'fs/promises';
|
|
13
13
|
import { Writable, Readable } from 'stream';
|
|
14
|
-
import
|
|
14
|
+
import crypto5, { createHash, randomUUID, timingSafeEqual } from 'crypto';
|
|
15
15
|
import http from 'http';
|
|
16
16
|
import { createRequire } from 'module';
|
|
17
17
|
import net2 from 'net';
|
|
@@ -969,10 +969,10 @@ function mergeDefs(...defs) {
|
|
|
969
969
|
function cloneDef(schema) {
|
|
970
970
|
return mergeDefs(schema._zod.def);
|
|
971
971
|
}
|
|
972
|
-
function getElementAtPath(obj,
|
|
973
|
-
if (!
|
|
972
|
+
function getElementAtPath(obj, path34) {
|
|
973
|
+
if (!path34)
|
|
974
974
|
return obj;
|
|
975
|
-
return
|
|
975
|
+
return path34.reduce((acc, key) => acc?.[key], obj);
|
|
976
976
|
}
|
|
977
977
|
function promiseAllObject(promisesObj) {
|
|
978
978
|
const keys = Object.keys(promisesObj);
|
|
@@ -1381,11 +1381,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
1381
1381
|
}
|
|
1382
1382
|
return false;
|
|
1383
1383
|
}
|
|
1384
|
-
function prefixIssues(
|
|
1384
|
+
function prefixIssues(path34, issues) {
|
|
1385
1385
|
return issues.map((iss) => {
|
|
1386
1386
|
var _a3;
|
|
1387
1387
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
1388
|
-
iss.path.unshift(
|
|
1388
|
+
iss.path.unshift(path34);
|
|
1389
1389
|
return iss;
|
|
1390
1390
|
});
|
|
1391
1391
|
}
|
|
@@ -1532,16 +1532,16 @@ function flattenError(error51, mapper = (issue3) => issue3.message) {
|
|
|
1532
1532
|
}
|
|
1533
1533
|
function formatError(error51, mapper = (issue3) => issue3.message) {
|
|
1534
1534
|
const fieldErrors = { _errors: [] };
|
|
1535
|
-
const processError = (error52,
|
|
1535
|
+
const processError = (error52, path34 = []) => {
|
|
1536
1536
|
for (const issue3 of error52.issues) {
|
|
1537
1537
|
if (issue3.code === "invalid_union" && issue3.errors.length) {
|
|
1538
|
-
issue3.errors.map((issues) => processError({ issues }, [...
|
|
1538
|
+
issue3.errors.map((issues) => processError({ issues }, [...path34, ...issue3.path]));
|
|
1539
1539
|
} else if (issue3.code === "invalid_key") {
|
|
1540
|
-
processError({ issues: issue3.issues }, [...
|
|
1540
|
+
processError({ issues: issue3.issues }, [...path34, ...issue3.path]);
|
|
1541
1541
|
} else if (issue3.code === "invalid_element") {
|
|
1542
|
-
processError({ issues: issue3.issues }, [...
|
|
1542
|
+
processError({ issues: issue3.issues }, [...path34, ...issue3.path]);
|
|
1543
1543
|
} else {
|
|
1544
|
-
const fullpath = [...
|
|
1544
|
+
const fullpath = [...path34, ...issue3.path];
|
|
1545
1545
|
if (fullpath.length === 0) {
|
|
1546
1546
|
fieldErrors._errors.push(mapper(issue3));
|
|
1547
1547
|
} else {
|
|
@@ -1568,17 +1568,17 @@ function formatError(error51, mapper = (issue3) => issue3.message) {
|
|
|
1568
1568
|
}
|
|
1569
1569
|
function treeifyError(error51, mapper = (issue3) => issue3.message) {
|
|
1570
1570
|
const result = { errors: [] };
|
|
1571
|
-
const processError = (error52,
|
|
1571
|
+
const processError = (error52, path34 = []) => {
|
|
1572
1572
|
var _a3, _b;
|
|
1573
1573
|
for (const issue3 of error52.issues) {
|
|
1574
1574
|
if (issue3.code === "invalid_union" && issue3.errors.length) {
|
|
1575
|
-
issue3.errors.map((issues) => processError({ issues }, [...
|
|
1575
|
+
issue3.errors.map((issues) => processError({ issues }, [...path34, ...issue3.path]));
|
|
1576
1576
|
} else if (issue3.code === "invalid_key") {
|
|
1577
|
-
processError({ issues: issue3.issues }, [...
|
|
1577
|
+
processError({ issues: issue3.issues }, [...path34, ...issue3.path]);
|
|
1578
1578
|
} else if (issue3.code === "invalid_element") {
|
|
1579
|
-
processError({ issues: issue3.issues }, [...
|
|
1579
|
+
processError({ issues: issue3.issues }, [...path34, ...issue3.path]);
|
|
1580
1580
|
} else {
|
|
1581
|
-
const fullpath = [...
|
|
1581
|
+
const fullpath = [...path34, ...issue3.path];
|
|
1582
1582
|
if (fullpath.length === 0) {
|
|
1583
1583
|
result.errors.push(mapper(issue3));
|
|
1584
1584
|
continue;
|
|
@@ -1610,8 +1610,8 @@ function treeifyError(error51, mapper = (issue3) => issue3.message) {
|
|
|
1610
1610
|
}
|
|
1611
1611
|
function toDotPath(_path) {
|
|
1612
1612
|
const segs = [];
|
|
1613
|
-
const
|
|
1614
|
-
for (const seg of
|
|
1613
|
+
const path34 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
1614
|
+
for (const seg of path34) {
|
|
1615
1615
|
if (typeof seg === "number")
|
|
1616
1616
|
segs.push(`[${seg}]`);
|
|
1617
1617
|
else if (typeof seg === "symbol")
|
|
@@ -14275,13 +14275,13 @@ function resolveRef(ref, ctx) {
|
|
|
14275
14275
|
if (!ref.startsWith("#")) {
|
|
14276
14276
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
14277
14277
|
}
|
|
14278
|
-
const
|
|
14279
|
-
if (
|
|
14278
|
+
const path34 = ref.slice(1).split("/").filter(Boolean);
|
|
14279
|
+
if (path34.length === 0) {
|
|
14280
14280
|
return ctx.rootSchema;
|
|
14281
14281
|
}
|
|
14282
14282
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
14283
|
-
if (
|
|
14284
|
-
const key =
|
|
14283
|
+
if (path34[0] === defsKey) {
|
|
14284
|
+
const key = path34[1];
|
|
14285
14285
|
if (!key || !ctx.defs[key]) {
|
|
14286
14286
|
throw new Error(`Reference not found: ${ref}`);
|
|
14287
14287
|
}
|
|
@@ -17913,7 +17913,7 @@ function inferBinName(packageName) {
|
|
|
17913
17913
|
// ../../packages/core-unified-agent/models.json
|
|
17914
17914
|
var models_default = {
|
|
17915
17915
|
version: 1,
|
|
17916
|
-
updatedAt: "2026-06-
|
|
17916
|
+
updatedAt: "2026-06-16T00:00:00Z",
|
|
17917
17917
|
providers: {
|
|
17918
17918
|
claude: {
|
|
17919
17919
|
name: "Claude Code with Anthropic",
|
|
@@ -17923,7 +17923,9 @@ var models_default = {
|
|
|
17923
17923
|
{ modelId: "sonnet", name: "Claude Sonnet", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "medium" } },
|
|
17924
17924
|
{ modelId: "opus", name: "Claude Opus", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "xhigh" } },
|
|
17925
17925
|
{ modelId: "opus[1m]", name: "Claude Opus [1M]", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "xhigh" } },
|
|
17926
|
-
{ modelId: "claude-opus-4-6[1m]", name: "Claude Opus 4.6 [1M]", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "high" } }
|
|
17926
|
+
{ modelId: "claude-opus-4-6[1m]", name: "Claude Opus 4.6 [1M]", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "high" } },
|
|
17927
|
+
{ modelId: "claude-opus-4-7[1m]", name: "Claude Opus 4.7 [1M]", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "high" } },
|
|
17928
|
+
{ modelId: "claude-opus-4-8[1m]", name: "Claude Opus 4.8 [1M]", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "high" } }
|
|
17927
17929
|
]
|
|
17928
17930
|
},
|
|
17929
17931
|
"claude-zai": {
|
|
@@ -21074,7 +21076,7 @@ function specToMcpTool(spec) {
|
|
|
21074
21076
|
}
|
|
21075
21077
|
function installExecutorToolCallRouter(runtime, sessionToken, ctx) {
|
|
21076
21078
|
runtime.server.setOnToolCallArrived(sessionToken, (toolName, args) => {
|
|
21077
|
-
const toolCallId =
|
|
21079
|
+
const toolCallId = crypto5.randomUUID();
|
|
21078
21080
|
void runtime.registry.invoke(toolName, args, { cwd: ctx.cwd, sessionLabel: ctx.sessionLabel, toolCallId, signal: ctx.signal }).then((result) => runtime.server.resolveNextToolCall(sessionToken, toolCallId, result)).catch((err) => {
|
|
21079
21081
|
runtime.server.resolveNextToolCall(sessionToken, toolCallId, {
|
|
21080
21082
|
content: [{ type: "text", text: err instanceof Error ? err.message : String(err) }],
|
|
@@ -21465,7 +21467,7 @@ function createInProcessMcpServer(deps = {}) {
|
|
|
21465
21467
|
if (activeStopPromise) await activeStopPromise;
|
|
21466
21468
|
if (activeServer && activeServerUrl) return activeServerUrl;
|
|
21467
21469
|
if (activeStartPromise) return activeStartPromise;
|
|
21468
|
-
activeOpaquePath = `/${
|
|
21470
|
+
activeOpaquePath = `/${crypto5.randomUUID()}`;
|
|
21469
21471
|
activeStartPromise = new Promise((resolve, reject) => {
|
|
21470
21472
|
const srv = http.createServer(handleRequest);
|
|
21471
21473
|
srv.timeout = MCP_SERVER_TIMEOUT_MS;
|
|
@@ -21722,7 +21724,7 @@ function createExecutorMcpSession(deps, toolTimeoutSeconds, request) {
|
|
|
21722
21724
|
throw new Error("Executor session cwd is required");
|
|
21723
21725
|
}
|
|
21724
21726
|
assertNonEmptyExecutorTools(request.serverName, request.specs);
|
|
21725
|
-
const token =
|
|
21727
|
+
const token = crypto5.randomUUID();
|
|
21726
21728
|
registerExecutorSessionTools(runtime.runtime, token, [...request.specs]);
|
|
21727
21729
|
installExecutorToolCallRouter(runtime.runtime, token, {
|
|
21728
21730
|
cwd,
|
|
@@ -21768,7 +21770,7 @@ function issueSessionToken(deps, sessionTokensByLabel, request) {
|
|
|
21768
21770
|
for (const { name, runtime } of deps.runtimes) {
|
|
21769
21771
|
const tools = runtime.registry.getAllAgentTools();
|
|
21770
21772
|
assertNonEmptyExecutorTools(name, tools);
|
|
21771
|
-
const token =
|
|
21773
|
+
const token = crypto5.randomUUID();
|
|
21772
21774
|
registerExecutorSessionTools(runtime, token, tools);
|
|
21773
21775
|
installExecutorToolCallRouter(runtime, token, { cwd, sessionLabel: label, signal: request.signal });
|
|
21774
21776
|
tokens.push({ name, token });
|
|
@@ -23134,7 +23136,8 @@ function sleepSync(ms) {
|
|
|
23134
23136
|
var DEFAULT_TEMP_FILE_MIN_AGE_MS = 6e4;
|
|
23135
23137
|
function createDurableJsonStore(deps) {
|
|
23136
23138
|
const now = deps.now ?? (() => Date.now());
|
|
23137
|
-
const
|
|
23139
|
+
const sensitivity = deps.sensitivity;
|
|
23140
|
+
const mode = sensitivity === "sensitive" ? SECURE_FILE_MODE : 420;
|
|
23138
23141
|
const minAgeMs = deps.tempCleanupMinAgeMs ?? DEFAULT_TEMP_FILE_MIN_AGE_MS;
|
|
23139
23142
|
const dir = path93.dirname(deps.filePath);
|
|
23140
23143
|
return {
|
|
@@ -23162,10 +23165,10 @@ function createDurableJsonStore(deps) {
|
|
|
23162
23165
|
};
|
|
23163
23166
|
function withLock(operation) {
|
|
23164
23167
|
if (!deps.lockDir) {
|
|
23165
|
-
ensureSafeDirectoryIfSensitive(dir);
|
|
23168
|
+
ensureSafeDirectoryIfSensitive(dir, sensitivity);
|
|
23166
23169
|
return operation();
|
|
23167
23170
|
}
|
|
23168
|
-
ensureSafeDirectoryIfSensitive(dir);
|
|
23171
|
+
ensureSafeDirectoryIfSensitive(dir, sensitivity);
|
|
23169
23172
|
return withDirectoryLock(
|
|
23170
23173
|
{
|
|
23171
23174
|
lockDir: deps.lockDir,
|
|
@@ -23207,8 +23210,10 @@ function readJsonFile(filePath, sanitize) {
|
|
|
23207
23210
|
}
|
|
23208
23211
|
}
|
|
23209
23212
|
function ensureSafeDirectoryIfSensitive(dir, sensitivity) {
|
|
23210
|
-
{
|
|
23213
|
+
if (sensitivity === "sensitive") {
|
|
23211
23214
|
ensureSafeDirectory(dir);
|
|
23215
|
+
} else {
|
|
23216
|
+
fs5.mkdirSync(dir, { recursive: true });
|
|
23212
23217
|
}
|
|
23213
23218
|
}
|
|
23214
23219
|
|
|
@@ -31414,7 +31419,7 @@ var LOCK_FILE_MODE = 384;
|
|
|
31414
31419
|
function createConsoleLock(deps = {}) {
|
|
31415
31420
|
const fsImpl = deps.fs ?? fs5__default;
|
|
31416
31421
|
const now = deps.now ?? Date.now;
|
|
31417
|
-
const randomToken = deps.randomToken ?? (() =>
|
|
31422
|
+
const randomToken = deps.randomToken ?? (() => crypto5.randomBytes(32).toString("base64url"));
|
|
31418
31423
|
const hostname5 = deps.hostname ?? (() => "127.0.0.1");
|
|
31419
31424
|
function ensureLockDir(dir) {
|
|
31420
31425
|
fsImpl.mkdirSync(dir, { recursive: true, mode: LOCK_DIR_MODE });
|
|
@@ -31509,6 +31514,389 @@ function createConsoleLock(deps = {}) {
|
|
|
31509
31514
|
}
|
|
31510
31515
|
return { ensureLockDir, readLock, writeLock, removeLock, assertLockModes, assertTrustedLock };
|
|
31511
31516
|
}
|
|
31517
|
+
var FLEET_DATA_DIR_NAME = ".fleet";
|
|
31518
|
+
function getFleetDataDir() {
|
|
31519
|
+
return path93.join(os22.homedir(), FLEET_DATA_DIR_NAME);
|
|
31520
|
+
}
|
|
31521
|
+
function readAuthStoreFile(filePath) {
|
|
31522
|
+
let fd;
|
|
31523
|
+
try {
|
|
31524
|
+
fd = fs5.openSync(filePath, fs5.constants.O_RDONLY | NOFOLLOW_FLAG);
|
|
31525
|
+
if (!fs5.fstatSync(fd).isFile()) {
|
|
31526
|
+
return {};
|
|
31527
|
+
}
|
|
31528
|
+
return JSON.parse(fs5.readFileSync(fd, "utf-8"));
|
|
31529
|
+
} catch {
|
|
31530
|
+
return {};
|
|
31531
|
+
} finally {
|
|
31532
|
+
if (fd !== void 0) {
|
|
31533
|
+
try {
|
|
31534
|
+
fs5.closeSync(fd);
|
|
31535
|
+
} catch {
|
|
31536
|
+
}
|
|
31537
|
+
}
|
|
31538
|
+
}
|
|
31539
|
+
}
|
|
31540
|
+
var DEFAULT_AUTH_PATH = path93.join(getFleetDataDir(), "auth.json");
|
|
31541
|
+
var AUTH_LOCK_OWNER_FILE_NAME = "owner.json";
|
|
31542
|
+
var AUTH_LOCK_TIMEOUT_MS = 5e3;
|
|
31543
|
+
function createAuthService(deps = {}) {
|
|
31544
|
+
const authPath = deps.authPath ?? DEFAULT_AUTH_PATH;
|
|
31545
|
+
const lockDir = `${authPath}.lock`;
|
|
31546
|
+
return {
|
|
31547
|
+
// [HIGH #1] TOCTOU 수정: existsSync/read/check/delete/write 전체를 락 블록 안으로 이동
|
|
31548
|
+
async deleteApiKey(providerId) {
|
|
31549
|
+
let deleted = false;
|
|
31550
|
+
withAuthLock(authPath, lockDir, () => {
|
|
31551
|
+
if (!fs5.existsSync(authPath)) return;
|
|
31552
|
+
const data = readAuthStoreFile(authPath);
|
|
31553
|
+
if (!Object.prototype.hasOwnProperty.call(data, providerId)) return;
|
|
31554
|
+
delete data[providerId];
|
|
31555
|
+
writeAuthData(authPath, data);
|
|
31556
|
+
deleted = true;
|
|
31557
|
+
});
|
|
31558
|
+
return deleted;
|
|
31559
|
+
},
|
|
31560
|
+
// [HIGH #2] 읽기 경로: fd 기반 O_RDONLY|O_NOFOLLOW+fstatSync isFile
|
|
31561
|
+
async getApiKey(providerId) {
|
|
31562
|
+
let fd;
|
|
31563
|
+
try {
|
|
31564
|
+
if (!fs5.existsSync(authPath)) {
|
|
31565
|
+
return void 0;
|
|
31566
|
+
}
|
|
31567
|
+
fd = fs5.openSync(authPath, fs5.constants.O_RDONLY | NOFOLLOW_FLAG);
|
|
31568
|
+
if (!fs5.fstatSync(fd).isFile()) {
|
|
31569
|
+
return void 0;
|
|
31570
|
+
}
|
|
31571
|
+
const data = JSON.parse(fs5.readFileSync(fd, "utf-8"));
|
|
31572
|
+
return typeof data[providerId]?.key === "string" ? data[providerId].key : void 0;
|
|
31573
|
+
} catch {
|
|
31574
|
+
return void 0;
|
|
31575
|
+
} finally {
|
|
31576
|
+
if (fd !== void 0) {
|
|
31577
|
+
try {
|
|
31578
|
+
fs5.closeSync(fd);
|
|
31579
|
+
} catch {
|
|
31580
|
+
}
|
|
31581
|
+
}
|
|
31582
|
+
}
|
|
31583
|
+
},
|
|
31584
|
+
// [HIGH #2] 읽기 경로: fd 기반 O_RDONLY|O_NOFOLLOW 통일
|
|
31585
|
+
async listProviderIds() {
|
|
31586
|
+
if (!fs5.existsSync(authPath)) {
|
|
31587
|
+
return [];
|
|
31588
|
+
}
|
|
31589
|
+
try {
|
|
31590
|
+
return Object.keys(readAuthStoreFile(authPath)).sort();
|
|
31591
|
+
} catch {
|
|
31592
|
+
return [];
|
|
31593
|
+
}
|
|
31594
|
+
},
|
|
31595
|
+
async setApiKey(providerId, key) {
|
|
31596
|
+
const dir = path93.dirname(authPath);
|
|
31597
|
+
ensureSafeDirectory(dir);
|
|
31598
|
+
withAuthLock(authPath, lockDir, () => {
|
|
31599
|
+
const data = fs5.existsSync(authPath) ? readAuthStoreFile(authPath) : {};
|
|
31600
|
+
data[providerId] = {
|
|
31601
|
+
...data[providerId] ?? {},
|
|
31602
|
+
key
|
|
31603
|
+
};
|
|
31604
|
+
writeAuthData(authPath, data);
|
|
31605
|
+
});
|
|
31606
|
+
}
|
|
31607
|
+
};
|
|
31608
|
+
}
|
|
31609
|
+
function withAuthLock(authPath, lockDir, operation) {
|
|
31610
|
+
return withDirectoryLock(
|
|
31611
|
+
{
|
|
31612
|
+
lockDir,
|
|
31613
|
+
ownerFileName: AUTH_LOCK_OWNER_FILE_NAME,
|
|
31614
|
+
timeoutMs: AUTH_LOCK_TIMEOUT_MS
|
|
31615
|
+
},
|
|
31616
|
+
operation
|
|
31617
|
+
);
|
|
31618
|
+
}
|
|
31619
|
+
function writeAuthData(authPath, data) {
|
|
31620
|
+
writeAtomicSync(authPath, `${JSON.stringify(data, null, 2)}
|
|
31621
|
+
`, {
|
|
31622
|
+
mode: SECURE_FILE_MODE,
|
|
31623
|
+
fsync: true
|
|
31624
|
+
});
|
|
31625
|
+
}
|
|
31626
|
+
function formatMissingAuthKeyMessage(input) {
|
|
31627
|
+
const cliHint = input.cli ? `cli '${input.cli}'` : "selected CLI";
|
|
31628
|
+
return `Auth token not found for ${cliHint} (providerId: '${input.providerId}'). Run \`fleet auth login\` to register one.`;
|
|
31629
|
+
}
|
|
31630
|
+
function formatAuthValidationFailureMessage(input) {
|
|
31631
|
+
const detail = input.detail ? ` Detail: ${input.detail}` : "";
|
|
31632
|
+
if (input.status === "unauthorized") {
|
|
31633
|
+
return `Auth token was rejected (providerId: '${input.providerId}'). Check the token and try again.${detail}`;
|
|
31634
|
+
}
|
|
31635
|
+
if (input.status === "forbidden") {
|
|
31636
|
+
return `Auth token is not allowed for this provider (providerId: '${input.providerId}'). Check the token permissions.${detail}`;
|
|
31637
|
+
}
|
|
31638
|
+
if (input.status === "timeout") {
|
|
31639
|
+
return `Auth token validation timed out (providerId: '${input.providerId}'). Check the connection and try again.${detail}`;
|
|
31640
|
+
}
|
|
31641
|
+
if (input.status === "network") {
|
|
31642
|
+
return `Auth token validation failed due to a network error (providerId: '${input.providerId}'). Check the connection and try again.${detail}`;
|
|
31643
|
+
}
|
|
31644
|
+
if (input.status === "server") {
|
|
31645
|
+
return `Auth token validation failed because the provider returned an error (providerId: '${input.providerId}'). Try again later.${detail}`;
|
|
31646
|
+
}
|
|
31647
|
+
return `Auth token validation failed (providerId: '${input.providerId}'). Check the token and try again.${detail}`;
|
|
31648
|
+
}
|
|
31649
|
+
var LEGACY_AUTH_PATH = path93.join(getFleetDataDir(), "agent", "auth.json");
|
|
31650
|
+
var CURRENT_AUTH_PATH = path93.join(getFleetDataDir(), "auth.json");
|
|
31651
|
+
function mergeAuthStoresNoOverwrite(legacy, current) {
|
|
31652
|
+
const data = { ...current };
|
|
31653
|
+
const migratedProviderIds = [];
|
|
31654
|
+
const skippedProviderIds = [];
|
|
31655
|
+
for (const [providerId, entry] of Object.entries(legacy)) {
|
|
31656
|
+
if (Object.prototype.hasOwnProperty.call(data, providerId)) {
|
|
31657
|
+
skippedProviderIds.push(providerId);
|
|
31658
|
+
continue;
|
|
31659
|
+
}
|
|
31660
|
+
data[providerId] = entry;
|
|
31661
|
+
migratedProviderIds.push(providerId);
|
|
31662
|
+
}
|
|
31663
|
+
return {
|
|
31664
|
+
data,
|
|
31665
|
+
migratedProviderIds,
|
|
31666
|
+
skippedProviderIds
|
|
31667
|
+
};
|
|
31668
|
+
}
|
|
31669
|
+
async function migrateLegacyAuthStore(options = {}) {
|
|
31670
|
+
const legacyPath = options.legacyPath ?? LEGACY_AUTH_PATH;
|
|
31671
|
+
const currentPath = options.currentPath ?? CURRENT_AUTH_PATH;
|
|
31672
|
+
if (!fs5.existsSync(legacyPath)) {
|
|
31673
|
+
return createMigrationResult({
|
|
31674
|
+
legacyPath,
|
|
31675
|
+
currentPath,
|
|
31676
|
+
status: "legacy-missing",
|
|
31677
|
+
migratedProviderIds: [],
|
|
31678
|
+
skippedProviderIds: [],
|
|
31679
|
+
shouldPrintNotice: false
|
|
31680
|
+
});
|
|
31681
|
+
}
|
|
31682
|
+
const legacy = readAuthStoreFile(legacyPath);
|
|
31683
|
+
const current = fs5.existsSync(currentPath) ? readAuthStoreFile(currentPath) : {};
|
|
31684
|
+
const merged = mergeAuthStoresNoOverwrite(legacy, current);
|
|
31685
|
+
if (merged.migratedProviderIds.length > 0) {
|
|
31686
|
+
const dir = path93.dirname(currentPath);
|
|
31687
|
+
ensureSafeDirectory(dir);
|
|
31688
|
+
writeAtomicSync(currentPath, `${JSON.stringify(merged.data, null, 2)}
|
|
31689
|
+
`, {
|
|
31690
|
+
mode: SECURE_FILE_MODE,
|
|
31691
|
+
fsync: true
|
|
31692
|
+
});
|
|
31693
|
+
}
|
|
31694
|
+
return createMigrationResult({
|
|
31695
|
+
legacyPath,
|
|
31696
|
+
currentPath,
|
|
31697
|
+
status: merged.migratedProviderIds.length > 0 ? "migrated" : "unchanged",
|
|
31698
|
+
migratedProviderIds: merged.migratedProviderIds,
|
|
31699
|
+
skippedProviderIds: merged.skippedProviderIds,
|
|
31700
|
+
shouldPrintNotice: options.notify !== false && merged.migratedProviderIds.length > 0
|
|
31701
|
+
});
|
|
31702
|
+
}
|
|
31703
|
+
function createMigrationResult(input) {
|
|
31704
|
+
return {
|
|
31705
|
+
legacyPath: input.legacyPath,
|
|
31706
|
+
currentPath: input.currentPath,
|
|
31707
|
+
migratedCount: input.migratedProviderIds.length,
|
|
31708
|
+
skippedCount: input.skippedProviderIds.length,
|
|
31709
|
+
migratedProviderIds: input.migratedProviderIds,
|
|
31710
|
+
skippedProviderIds: input.skippedProviderIds,
|
|
31711
|
+
shouldPrintNotice: input.shouldPrintNotice,
|
|
31712
|
+
status: input.status
|
|
31713
|
+
};
|
|
31714
|
+
}
|
|
31715
|
+
var DEFAULT_AUTH_VALIDATION_TIMEOUT_MS = 5e3;
|
|
31716
|
+
async function validateAnthropicCompatibleApiKey(request) {
|
|
31717
|
+
const controller = new AbortController();
|
|
31718
|
+
const timeout = setTimeout(() => {
|
|
31719
|
+
controller.abort();
|
|
31720
|
+
}, request.timeoutMs ?? DEFAULT_AUTH_VALIDATION_TIMEOUT_MS);
|
|
31721
|
+
try {
|
|
31722
|
+
const response = await fetch(buildMessagesUrl(request.baseUrl), {
|
|
31723
|
+
method: "POST",
|
|
31724
|
+
headers: {
|
|
31725
|
+
"anthropic-version": "2023-06-01",
|
|
31726
|
+
"content-type": "application/json",
|
|
31727
|
+
"x-api-key": request.apiKey
|
|
31728
|
+
},
|
|
31729
|
+
body: JSON.stringify({
|
|
31730
|
+
model: "claude-3-5-haiku-20241022",
|
|
31731
|
+
max_tokens: 1,
|
|
31732
|
+
messages: [
|
|
31733
|
+
{
|
|
31734
|
+
role: "user",
|
|
31735
|
+
content: "ping"
|
|
31736
|
+
}
|
|
31737
|
+
]
|
|
31738
|
+
}),
|
|
31739
|
+
signal: controller.signal
|
|
31740
|
+
});
|
|
31741
|
+
if (response.ok) {
|
|
31742
|
+
return { providerId: request.providerId, status: "success" };
|
|
31743
|
+
}
|
|
31744
|
+
if (response.status === 401) {
|
|
31745
|
+
return { providerId: request.providerId, status: "unauthorized" };
|
|
31746
|
+
}
|
|
31747
|
+
if (response.status === 403) {
|
|
31748
|
+
return { providerId: request.providerId, status: "forbidden" };
|
|
31749
|
+
}
|
|
31750
|
+
if (response.status >= 500) {
|
|
31751
|
+
return {
|
|
31752
|
+
providerId: request.providerId,
|
|
31753
|
+
status: "server",
|
|
31754
|
+
detail: `HTTP ${response.status}`
|
|
31755
|
+
};
|
|
31756
|
+
}
|
|
31757
|
+
return {
|
|
31758
|
+
providerId: request.providerId,
|
|
31759
|
+
status: "unknown",
|
|
31760
|
+
detail: `HTTP ${response.status}`
|
|
31761
|
+
};
|
|
31762
|
+
} catch (error51) {
|
|
31763
|
+
if (isAbortError(error51)) {
|
|
31764
|
+
return { providerId: request.providerId, status: "timeout" };
|
|
31765
|
+
}
|
|
31766
|
+
return {
|
|
31767
|
+
providerId: request.providerId,
|
|
31768
|
+
status: "network",
|
|
31769
|
+
detail: error51 instanceof Error ? error51.message : String(error51)
|
|
31770
|
+
};
|
|
31771
|
+
} finally {
|
|
31772
|
+
clearTimeout(timeout);
|
|
31773
|
+
}
|
|
31774
|
+
}
|
|
31775
|
+
function isAuthValidationSuccess(result) {
|
|
31776
|
+
return result.status === "success";
|
|
31777
|
+
}
|
|
31778
|
+
function createAuthValidationError(result) {
|
|
31779
|
+
return new Error(formatAuthValidationFailureMessage(result));
|
|
31780
|
+
}
|
|
31781
|
+
function buildMessagesUrl(baseUrl) {
|
|
31782
|
+
return `${baseUrl.replace(/\/+$/, "")}/v1/messages`;
|
|
31783
|
+
}
|
|
31784
|
+
function isAbortError(error51) {
|
|
31785
|
+
return error51 instanceof DOMException && error51.name === "AbortError";
|
|
31786
|
+
}
|
|
31787
|
+
var CLAUDE_ZAI_PROVIDER_ID = "Claude Code with Z.AI GLM";
|
|
31788
|
+
var CLAUDE_KIMI_PROVIDER_ID = "Claude Code with Moonshot Kimi";
|
|
31789
|
+
var AUTH_PROVIDER_DEFINITIONS = {
|
|
31790
|
+
"claude-zai": {
|
|
31791
|
+
providerId: CLAUDE_ZAI_PROVIDER_ID,
|
|
31792
|
+
baseUrl: CLI_BACKENDS["claude-zai"].defaultEnv.ANTHROPIC_BASE_URL,
|
|
31793
|
+
env: CLI_BACKENDS["claude-zai"].defaultEnv
|
|
31794
|
+
},
|
|
31795
|
+
"claude-kimi": {
|
|
31796
|
+
providerId: CLAUDE_KIMI_PROVIDER_ID,
|
|
31797
|
+
baseUrl: CLI_BACKENDS["claude-kimi"].defaultEnv.ANTHROPIC_BASE_URL,
|
|
31798
|
+
env: CLI_BACKENDS["claude-kimi"].defaultEnv
|
|
31799
|
+
}
|
|
31800
|
+
};
|
|
31801
|
+
async function resolveAuthEnv(cli, deps) {
|
|
31802
|
+
const provider = AUTH_PROVIDER_DEFINITIONS[cli];
|
|
31803
|
+
if (!provider) return {};
|
|
31804
|
+
await migrateLegacyAuthStore();
|
|
31805
|
+
const auth = deps?.authService ?? createAuthService({ authPath: DEFAULT_AUTH_PATH });
|
|
31806
|
+
const token = await auth.getApiKey(provider.providerId);
|
|
31807
|
+
if (!token) {
|
|
31808
|
+
throw new Error(formatMissingAuthKeyMessage({ cli, providerId: provider.providerId }));
|
|
31809
|
+
}
|
|
31810
|
+
const validation = await validateAnthropicCompatibleApiKey({
|
|
31811
|
+
providerId: provider.providerId,
|
|
31812
|
+
apiKey: token,
|
|
31813
|
+
baseUrl: provider.baseUrl
|
|
31814
|
+
});
|
|
31815
|
+
if (!isAuthValidationSuccess(validation)) {
|
|
31816
|
+
const failure = {
|
|
31817
|
+
providerId: validation.providerId,
|
|
31818
|
+
status: validation.status,
|
|
31819
|
+
detail: validation.detail
|
|
31820
|
+
};
|
|
31821
|
+
throw createAuthValidationError(failure);
|
|
31822
|
+
}
|
|
31823
|
+
return { ...provider.env, ANTHROPIC_AUTH_TOKEN: token };
|
|
31824
|
+
}
|
|
31825
|
+
var GLOBAL_OPTIONS_VERSION = 1;
|
|
31826
|
+
var GLOBAL_OPTIONS_FILE_NAME = "settings.json";
|
|
31827
|
+
var LOCK_DIR_NAME = "settings.json.lock";
|
|
31828
|
+
var LOCK_OWNER_FILE_NAME = "owner";
|
|
31829
|
+
var TEMP_FILE_PREFIX = `.tmp-${GLOBAL_OPTIONS_FILE_NAME}-`;
|
|
31830
|
+
function createGlobalOptionsStore(deps = {}) {
|
|
31831
|
+
const dataDir = deps.dataDir ?? getFleetDataDir();
|
|
31832
|
+
const optionsPath = path93.join(dataDir, GLOBAL_OPTIONS_FILE_NAME);
|
|
31833
|
+
const lockDir = path93.join(dataDir, LOCK_DIR_NAME);
|
|
31834
|
+
const store2 = createDurableJsonStore({
|
|
31835
|
+
filePath: optionsPath,
|
|
31836
|
+
lockDir,
|
|
31837
|
+
lockOwnerFileName: LOCK_OWNER_FILE_NAME,
|
|
31838
|
+
sanitize: (value) => sanitizeGlobalOptionsData(value).data,
|
|
31839
|
+
sensitivity: "sensitive",
|
|
31840
|
+
timeoutMs: deps.timeoutMs,
|
|
31841
|
+
staleLockMs: deps.staleLockMs,
|
|
31842
|
+
tempCleanupPrefix: TEMP_FILE_PREFIX,
|
|
31843
|
+
now: deps.now
|
|
31844
|
+
});
|
|
31845
|
+
return {
|
|
31846
|
+
path: optionsPath,
|
|
31847
|
+
load: () => store2.load(),
|
|
31848
|
+
save: (data) => store2.save(sanitizeGlobalOptionsData(data).data),
|
|
31849
|
+
update: (mutate) => store2.update((current) => sanitizeGlobalOptionsData(mutate(current)).data)
|
|
31850
|
+
};
|
|
31851
|
+
}
|
|
31852
|
+
function createEmptyGlobalOptionsData() {
|
|
31853
|
+
return {
|
|
31854
|
+
version: GLOBAL_OPTIONS_VERSION
|
|
31855
|
+
};
|
|
31856
|
+
}
|
|
31857
|
+
function sanitizeGlobalOptionsData(value) {
|
|
31858
|
+
if (!isRecord3(value)) {
|
|
31859
|
+
return { data: createEmptyGlobalOptionsData(), changed: true };
|
|
31860
|
+
}
|
|
31861
|
+
if (value.version !== GLOBAL_OPTIONS_VERSION) {
|
|
31862
|
+
return { data: createEmptyGlobalOptionsData(), changed: true };
|
|
31863
|
+
}
|
|
31864
|
+
const data = {
|
|
31865
|
+
version: GLOBAL_OPTIONS_VERSION,
|
|
31866
|
+
...typeof value.replaceSystemPrompt === "boolean" ? { replaceSystemPrompt: value.replaceSystemPrompt } : {},
|
|
31867
|
+
...typeof value.enableMetaphor === "boolean" ? { enableMetaphor: value.enableMetaphor } : {}
|
|
31868
|
+
};
|
|
31869
|
+
const allowedKeys = /* @__PURE__ */ new Set(["version", "replaceSystemPrompt", "enableMetaphor"]);
|
|
31870
|
+
const changed = Object.keys(value).some((key) => !allowedKeys.has(key)) || "replaceSystemPrompt" in value && typeof value.replaceSystemPrompt !== "boolean" || "enableMetaphor" in value && typeof value.enableMetaphor !== "boolean";
|
|
31871
|
+
return { data, changed };
|
|
31872
|
+
}
|
|
31873
|
+
function isRecord3(value) {
|
|
31874
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
31875
|
+
}
|
|
31876
|
+
function createGlobalOptionsService(deps = {}) {
|
|
31877
|
+
const store2 = deps.store ?? createGlobalOptionsStore({ dataDir: deps.dataDir });
|
|
31878
|
+
return {
|
|
31879
|
+
load: () => store2.load(),
|
|
31880
|
+
save: (data) => {
|
|
31881
|
+
store2.save(data);
|
|
31882
|
+
return store2.load();
|
|
31883
|
+
},
|
|
31884
|
+
update: (mutate) => updateGlobalOptions(store2, mutate)
|
|
31885
|
+
};
|
|
31886
|
+
}
|
|
31887
|
+
function updateGlobalOptions(store2, mutate) {
|
|
31888
|
+
return store2.update(mutate);
|
|
31889
|
+
}
|
|
31890
|
+
|
|
31891
|
+
// ../../packages/fleet-infra/dist/index.js
|
|
31892
|
+
function createInfraServices(deps = {}) {
|
|
31893
|
+
const globalOptionsService = createGlobalOptionsService();
|
|
31894
|
+
const authService = createAuthService({ authPath: deps.authPath ?? DEFAULT_AUTH_PATH });
|
|
31895
|
+
return {
|
|
31896
|
+
authService,
|
|
31897
|
+
globalOptionsService
|
|
31898
|
+
};
|
|
31899
|
+
}
|
|
31512
31900
|
function readFleetConsoleRelease() {
|
|
31513
31901
|
const requireFromHere = createRequire(import.meta.url);
|
|
31514
31902
|
const packageJsonPath = requireFromHere.resolve("../package.json");
|
|
@@ -31522,17 +31910,34 @@ function readFleetConsoleRelease() {
|
|
|
31522
31910
|
}
|
|
31523
31911
|
|
|
31524
31912
|
// src/paths.ts
|
|
31525
|
-
var
|
|
31913
|
+
var LOCK_DIR_NAME2 = "fleet-console";
|
|
31914
|
+
var CONSOLE_RUNTIME_DIR_NAME = "console";
|
|
31526
31915
|
var LOCK_FILE_NAME = "console.lock";
|
|
31916
|
+
var CONSOLE_DATA_DIR_NAME = "console";
|
|
31917
|
+
var CONSOLE_STATE_FILE_NAME = "state.json";
|
|
31918
|
+
var CONSOLE_CAPTURES_DIR_NAME = "captures";
|
|
31527
31919
|
function createConsolePaths(deps = {}) {
|
|
31528
31920
|
const env = deps.env ?? process.env;
|
|
31529
31921
|
const base = env.FLEET_CONSOLE_DIR ?? defaultConsoleBaseDir(deps);
|
|
31530
31922
|
return { dir: base, lockFile: path93__default.join(base, LOCK_FILE_NAME) };
|
|
31531
31923
|
}
|
|
31924
|
+
function createConsoleDataPaths(deps = {}) {
|
|
31925
|
+
const dir = path93__default.join(deps.fleetDataDir ?? getFleetDataDir(), CONSOLE_DATA_DIR_NAME);
|
|
31926
|
+
return {
|
|
31927
|
+
dir,
|
|
31928
|
+
stateFile: path93__default.join(dir, CONSOLE_STATE_FILE_NAME),
|
|
31929
|
+
capturesDir: path93__default.join(dir, CONSOLE_CAPTURES_DIR_NAME)
|
|
31930
|
+
};
|
|
31931
|
+
}
|
|
31532
31932
|
function defaultConsoleBaseDir(deps) {
|
|
31933
|
+
let release;
|
|
31934
|
+
const channel = deps.channel ?? (release = readFleetConsoleRelease()).channel;
|
|
31935
|
+
if (channel === "local") {
|
|
31936
|
+
const packageRoot = deps.packageRoot ?? (release ??= readFleetConsoleRelease()).packageRoot;
|
|
31937
|
+
return path93__default.join(path93__default.resolve(packageRoot, "..", ".."), ".fleet", CONSOLE_RUNTIME_DIR_NAME);
|
|
31938
|
+
}
|
|
31533
31939
|
const uid = deps.uid ?? (typeof process.getuid === "function" ? process.getuid() : 0);
|
|
31534
|
-
|
|
31535
|
-
return path93__default.join(os22__default.tmpdir(), `${LOCK_DIR_NAME}-${uid}-${channel}`);
|
|
31940
|
+
return path93__default.join(os22__default.tmpdir(), `${LOCK_DIR_NAME2}-${uid}-${channel}`);
|
|
31536
31941
|
}
|
|
31537
31942
|
var FLEET_PROTOCOL_GATE_PROMPT = String.raw`# Protocol Gate
|
|
31538
31943
|
|
|
@@ -31925,6 +32330,8 @@ function createClaudeFamilyCliDefinition(options) {
|
|
|
31925
32330
|
lineTerminator: "\r",
|
|
31926
32331
|
multilineStrategy: "paste-mode"
|
|
31927
32332
|
},
|
|
32333
|
+
// Claude Code 계열은 세션 이름 변경 슬래시 명령 `/rename`을 지원한다.
|
|
32334
|
+
renameCommand: "/rename",
|
|
31928
32335
|
terminalName: "xterm-256color"
|
|
31929
32336
|
};
|
|
31930
32337
|
}
|
|
@@ -31948,7 +32355,7 @@ var codexCli = {
|
|
|
31948
32355
|
async createProfile(options) {
|
|
31949
32356
|
const { bin, prefixArgs } = resolveBinary("codex", "CODEX_BIN", options.env);
|
|
31950
32357
|
return {
|
|
31951
|
-
args: [...prefixArgs, "--no-alt-screen", ...buildModelArgs2(options.model)],
|
|
32358
|
+
args: [...prefixArgs, ...buildResumeArgs(options.resumeSessionId), "--no-alt-screen", ...buildModelArgs2(options.model)],
|
|
31952
32359
|
bin,
|
|
31953
32360
|
binPrefixArgs: prefixArgs,
|
|
31954
32361
|
cwd: options.cwd,
|
|
@@ -31960,10 +32367,15 @@ var codexCli = {
|
|
|
31960
32367
|
lineTerminator: "\r",
|
|
31961
32368
|
multilineStrategy: "paste-mode"
|
|
31962
32369
|
},
|
|
32370
|
+
// Codex CLI도 세션 이름 변경 슬래시 명령 `/rename`을 지원한다.
|
|
32371
|
+
renameCommand: "/rename",
|
|
31963
32372
|
terminalName: "xterm-256color"
|
|
31964
32373
|
};
|
|
31965
32374
|
}
|
|
31966
32375
|
};
|
|
32376
|
+
function buildResumeArgs(resumeSessionId) {
|
|
32377
|
+
return resumeSessionId === void 0 ? [] : ["resume", resumeSessionId];
|
|
32378
|
+
}
|
|
31967
32379
|
function buildModelArgs2(model) {
|
|
31968
32380
|
return model === void 0 ? [] : ["--model", model];
|
|
31969
32381
|
}
|
|
@@ -31980,7 +32392,8 @@ async function resolveAgentCliProfile(env, cwd, options = {}) {
|
|
|
31980
32392
|
authService: options.authService,
|
|
31981
32393
|
cwd,
|
|
31982
32394
|
env,
|
|
31983
|
-
model: options.model
|
|
32395
|
+
model: options.model,
|
|
32396
|
+
resumeSessionId: options.resumeSessionId
|
|
31984
32397
|
});
|
|
31985
32398
|
}
|
|
31986
32399
|
function resolveAgentCliId(env, options = {}) {
|
|
@@ -32024,6 +32437,20 @@ var AGENT_CLI_INJECTION_CAPABILITIES = {
|
|
|
32024
32437
|
function getAgentCliInjectionCapability(cliId) {
|
|
32025
32438
|
return AGENT_CLI_INJECTION_CAPABILITIES[cliId];
|
|
32026
32439
|
}
|
|
32440
|
+
function createSessionCaptureHookExec(deps) {
|
|
32441
|
+
const args = deps.tsxLoader ? [
|
|
32442
|
+
"--import",
|
|
32443
|
+
pathToFileURL(deps.tsxLoader).href,
|
|
32444
|
+
deps.entryPath,
|
|
32445
|
+
"hook",
|
|
32446
|
+
"capture-session",
|
|
32447
|
+
deps.provider
|
|
32448
|
+
] : [deps.entryPath, "hook", "capture-session", deps.provider];
|
|
32449
|
+
return {
|
|
32450
|
+
command: deps.execPath ?? process5.execPath,
|
|
32451
|
+
args
|
|
32452
|
+
};
|
|
32453
|
+
}
|
|
32027
32454
|
function buildHostCarrierModelDefaults2(config2) {
|
|
32028
32455
|
const cliType = resolveAgentCliType2(config2.id, config2.defaultCliType);
|
|
32029
32456
|
const cliDefaults = buildCarrierModelDefaults(config2, cliType);
|
|
@@ -32053,6 +32480,7 @@ function buildClaudeNativeSubagentPlan2(registry3) {
|
|
|
32053
32480
|
function buildClaudeNativeArgs(context) {
|
|
32054
32481
|
const systemPromptArg = context.replaceSystemPrompt ? "--system-prompt-file" : "--append-system-prompt-file";
|
|
32055
32482
|
return [
|
|
32483
|
+
...buildResumeArgs2(context.resumeSessionId),
|
|
32056
32484
|
systemPromptArg,
|
|
32057
32485
|
requireSystemPromptFile(context),
|
|
32058
32486
|
...context.pluginRoots.flatMap((pluginRoot) => [
|
|
@@ -32063,6 +32491,9 @@ function buildClaudeNativeArgs(context) {
|
|
|
32063
32491
|
"--dangerously-skip-permissions"
|
|
32064
32492
|
];
|
|
32065
32493
|
}
|
|
32494
|
+
function buildResumeArgs2(resumeSessionId) {
|
|
32495
|
+
return resumeSessionId === void 0 ? [] : ["--resume", resumeSessionId];
|
|
32496
|
+
}
|
|
32066
32497
|
function buildClaudeMcpConfig(servers) {
|
|
32067
32498
|
return JSON.stringify({
|
|
32068
32499
|
mcpServers: Object.fromEntries(
|
|
@@ -32120,20 +32551,32 @@ function escapeTomlMultilineString(value) {
|
|
|
32120
32551
|
});
|
|
32121
32552
|
return result;
|
|
32122
32553
|
}
|
|
32554
|
+
function buildPosixShellCommand(values) {
|
|
32555
|
+
return values.map(posixShellQuote).join(" ");
|
|
32556
|
+
}
|
|
32557
|
+
function posixShellQuote(value) {
|
|
32558
|
+
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
32559
|
+
}
|
|
32123
32560
|
var CODEX_TOOL_TIMEOUT_SEC = 1800;
|
|
32124
32561
|
function buildCodexNativeArgs(context) {
|
|
32125
32562
|
const profileName = requireCodexProfileName(context);
|
|
32126
32563
|
const args = [
|
|
32564
|
+
...buildResumeArgs3(context.resumeSessionId),
|
|
32127
32565
|
"--enable",
|
|
32128
32566
|
"plugins",
|
|
32129
32567
|
"--enable",
|
|
32130
32568
|
"child_agents_md",
|
|
32569
|
+
"--enable",
|
|
32570
|
+
"hooks",
|
|
32131
32571
|
"--profile",
|
|
32132
32572
|
profileName,
|
|
32133
32573
|
"-c",
|
|
32134
32574
|
'approval_policy="never"',
|
|
32135
32575
|
"-c",
|
|
32136
|
-
'sandbox_mode="danger-full-access"'
|
|
32576
|
+
'sandbox_mode="danger-full-access"',
|
|
32577
|
+
// hook 신뢰 프롬프트("Hooks need review")를 fleet 관리 세션에서 건너뛴다. bypass_hook_trust는
|
|
32578
|
+
// config 키가 아니라 전용 CLI 플래그이므로 -c override가 아닌 플래그로 전달해야 한다.
|
|
32579
|
+
"--dangerously-bypass-hook-trust"
|
|
32137
32580
|
];
|
|
32138
32581
|
for (const server of context.mcpServers) {
|
|
32139
32582
|
const prefix = `mcp_servers.${server.name}`;
|
|
@@ -32149,6 +32592,9 @@ function buildCodexNativeArgs(context) {
|
|
|
32149
32592
|
}
|
|
32150
32593
|
return args;
|
|
32151
32594
|
}
|
|
32595
|
+
function buildResumeArgs3(resumeSessionId) {
|
|
32596
|
+
return resumeSessionId === void 0 ? [] : ["resume", resumeSessionId];
|
|
32597
|
+
}
|
|
32152
32598
|
function requireCodexProfileName(context) {
|
|
32153
32599
|
if (context.codexProfileName) return context.codexProfileName;
|
|
32154
32600
|
throw new Error("Codex profile name is required for native injection");
|
|
@@ -32359,20 +32805,32 @@ function claudeHooks(options) {
|
|
|
32359
32805
|
if (!hookExec) {
|
|
32360
32806
|
throw new Error("Fleet Claude session hook command is required");
|
|
32361
32807
|
}
|
|
32808
|
+
const captureSessionHookExec = options.captureSessionHookExec;
|
|
32362
32809
|
return {
|
|
32363
32810
|
hooks: {
|
|
32364
32811
|
SessionStart: [{
|
|
32365
|
-
hooks: [
|
|
32366
|
-
|
|
32367
|
-
|
|
32368
|
-
|
|
32369
|
-
|
|
32370
|
-
type: "command"
|
|
32812
|
+
hooks: [claudeCommandHook(hookExec)]
|
|
32813
|
+
}],
|
|
32814
|
+
...captureSessionHookExec ? {
|
|
32815
|
+
UserPromptSubmit: [{
|
|
32816
|
+
hooks: [claudeCommandHook(captureSessionHookExec)]
|
|
32371
32817
|
}]
|
|
32372
|
-
}
|
|
32818
|
+
} : {}
|
|
32373
32819
|
}
|
|
32374
32820
|
};
|
|
32375
32821
|
}
|
|
32822
|
+
function claudeCommandHook(hookExec) {
|
|
32823
|
+
if (!hookExec) {
|
|
32824
|
+
throw new Error("Fleet Claude session hook command is required");
|
|
32825
|
+
}
|
|
32826
|
+
return {
|
|
32827
|
+
// exec 형식: command는 직접 spawn되는 실행 파일, args는 셸 토크나이징 없이 그대로 전달된다.
|
|
32828
|
+
// Windows cmd/powershell의 따옴표 규칙과 무관하게 동작하며 공백 포함 경로도 안전하다.
|
|
32829
|
+
args: [...hookExec.args],
|
|
32830
|
+
command: hookExec.command,
|
|
32831
|
+
type: "command"
|
|
32832
|
+
};
|
|
32833
|
+
}
|
|
32376
32834
|
function claudeAgentFile(subagent) {
|
|
32377
32835
|
const frontmatter = [
|
|
32378
32836
|
"---",
|
|
@@ -32882,7 +33340,7 @@ function homeMarketplaceTarget(fleetRoot) {
|
|
|
32882
33340
|
}
|
|
32883
33341
|
function projectMarketplaceTarget(cwd) {
|
|
32884
33342
|
const projectFleetRoot = resolveProjectFleetRoot(cwd);
|
|
32885
|
-
const hash2 =
|
|
33343
|
+
const hash2 = crypto5.createHash("sha256").update(path93__default.resolve(cwd, ".fleet")).digest("hex").slice(0, 12);
|
|
32886
33344
|
return {
|
|
32887
33345
|
flat: true,
|
|
32888
33346
|
name: `${FLEET_PROJECT_MARKETPLACE_NAME_PREFIX}-${hash2}`,
|
|
@@ -32908,7 +33366,6 @@ function renderPluginRoot(pluginRoot, bundle, options, fleetRoot) {
|
|
|
32908
33366
|
const stagedPluginRoot = path93__default.join(stageParent, path93__default.basename(pluginRoot));
|
|
32909
33367
|
try {
|
|
32910
33368
|
ensurePrivateDir(stagedPluginRoot, stagedPluginRoot);
|
|
32911
|
-
writePrivateJson(path93__default.join(stagedPluginRoot, ".codex-plugin", "plugin.json"), codexManifest(bundle), stagedPluginRoot);
|
|
32912
33369
|
writePrivateJson(path93__default.join(stagedPluginRoot, ".claude-plugin", "plugin.json"), claudeManifest(bundle), stagedPluginRoot);
|
|
32913
33370
|
switch (bundle.source) {
|
|
32914
33371
|
case "asset":
|
|
@@ -32923,6 +33380,7 @@ function renderPluginRoot(pluginRoot, bundle, options, fleetRoot) {
|
|
|
32923
33380
|
renderGlobalPluginRoot(stagedPluginRoot, fleetRoot);
|
|
32924
33381
|
break;
|
|
32925
33382
|
}
|
|
33383
|
+
writePrivateJson(path93__default.join(stagedPluginRoot, ".codex-plugin", "plugin.json"), codexManifest(bundle, stagedPluginRoot), stagedPluginRoot);
|
|
32926
33384
|
removePrivatePath(pluginRoot, parentRoot);
|
|
32927
33385
|
renameSync(stagedPluginRoot, pluginRoot);
|
|
32928
33386
|
} finally {
|
|
@@ -32951,7 +33409,7 @@ function pruneMarketplaceRoot(target) {
|
|
|
32951
33409
|
}
|
|
32952
33410
|
}
|
|
32953
33411
|
function buildContentHash(target) {
|
|
32954
|
-
const hash2 =
|
|
33412
|
+
const hash2 = crypto5.createHash("sha256");
|
|
32955
33413
|
for (const filePath of listRenderableFiles(target)) {
|
|
32956
33414
|
const relativePath2 = path93__default.relative(target.root, filePath);
|
|
32957
33415
|
hash2.update(relativePath2);
|
|
@@ -33054,14 +33512,36 @@ function marketplacePluginPath(target, bundle) {
|
|
|
33054
33512
|
if (target.flat) return `./${FLAT_PLUGIN_DIR_NAME}`;
|
|
33055
33513
|
return `./${PLUGIN_BUNDLES_DIR_NAME}/${bundle.directoryName}`;
|
|
33056
33514
|
}
|
|
33057
|
-
function codexManifest(bundle) {
|
|
33515
|
+
function codexManifest(bundle, pluginRoot) {
|
|
33058
33516
|
return {
|
|
33059
33517
|
name: bundle.name,
|
|
33060
|
-
version:
|
|
33518
|
+
version: codexManifestVersion(bundle, pluginRoot),
|
|
33061
33519
|
description: bundle.description,
|
|
33062
33520
|
skills: "./skills/"
|
|
33063
33521
|
};
|
|
33064
33522
|
}
|
|
33523
|
+
function codexManifestVersion(bundle, pluginRoot) {
|
|
33524
|
+
const hash2 = crypto5.createHash("sha256");
|
|
33525
|
+
hash2.update(bundle.name);
|
|
33526
|
+
hash2.update("\0");
|
|
33527
|
+
hash2.update(bundle.description);
|
|
33528
|
+
hash2.update("\0");
|
|
33529
|
+
for (const filePath of listCodexEffectivePluginFiles(pluginRoot)) {
|
|
33530
|
+
const relativePath2 = path93__default.relative(pluginRoot, filePath);
|
|
33531
|
+
hash2.update(relativePath2);
|
|
33532
|
+
hash2.update("\0");
|
|
33533
|
+
hash2.update(readFileSync(filePath));
|
|
33534
|
+
hash2.update("\0");
|
|
33535
|
+
}
|
|
33536
|
+
return `0.0.0+${hash2.digest("hex").slice(0, 12)}`;
|
|
33537
|
+
}
|
|
33538
|
+
function listCodexEffectivePluginFiles(pluginRoot) {
|
|
33539
|
+
const skillsPath = path93__default.join(pluginRoot, "skills");
|
|
33540
|
+
if (!existsSync(skillsPath)) return [];
|
|
33541
|
+
const files = [];
|
|
33542
|
+
collectRenderableFiles(pluginRoot, skillsPath, files, /* @__PURE__ */ new Set());
|
|
33543
|
+
return files.sort();
|
|
33544
|
+
}
|
|
33065
33545
|
function claudeManifest(bundle) {
|
|
33066
33546
|
return {
|
|
33067
33547
|
name: bundle.name,
|
|
@@ -33081,7 +33561,7 @@ async function injectAgentCliProfile(profile, options) {
|
|
|
33081
33561
|
const injectTone = options.enableMetaphor ?? false;
|
|
33082
33562
|
const endpoint = await options.dedicatedMcpSession.getEndpoint();
|
|
33083
33563
|
const startupDefinitions = buildStartupNativeDefinitions(profile.id, options.carrierRuntime);
|
|
33084
|
-
const tokenLabel = options.mcpSessionLabel ?? `agent:${profile.id}:${
|
|
33564
|
+
const tokenLabel = options.mcpSessionLabel ?? `agent:${profile.id}:${crypto5.randomUUID()}`;
|
|
33085
33565
|
const tokens = await options.dedicatedMcpSession.issueSessionToken({ cwd: profile.cwd, label: tokenLabel });
|
|
33086
33566
|
const mcpServers = buildAgentCliMcpServerConfigs(endpoint.servers, tokens);
|
|
33087
33567
|
const doctrine = options.buildSystemPrompt(injectTone);
|
|
@@ -33095,11 +33575,12 @@ async function injectAgentCliProfile(profile, options) {
|
|
|
33095
33575
|
cwd: profile.cwd,
|
|
33096
33576
|
dataDir: options.dataDir,
|
|
33097
33577
|
rootDir: options.pluginRootDir,
|
|
33578
|
+
captureSessionHookExec: options.captureSessionHookExec,
|
|
33098
33579
|
hookExec: startupDefinitions.host === "claude" ? requireHookExec(options.hookExec) : void 0,
|
|
33099
33580
|
withMarketplaceLock: options.withMarketplaceLock
|
|
33100
33581
|
});
|
|
33101
33582
|
const codexPluginKeys = plugin.codexRegistrations.map((registration) => `${registration.pluginName}@${registration.marketplaceName}`);
|
|
33102
|
-
const codexProfile = profile.id === "codex" ? writeCodexFleetProfile(profile.env, doctrine, codexPluginKeys, (cleanup2) => tempCleanups.push(cleanup2)) : void 0;
|
|
33583
|
+
const codexProfile = profile.id === "codex" ? writeCodexFleetProfile(profile.env, doctrine, codexPluginKeys, options.captureSessionHookExec, (cleanup2) => tempCleanups.push(cleanup2)) : void 0;
|
|
33103
33584
|
const launchWarnings = [];
|
|
33104
33585
|
for (const registration of plugin.codexRegistrations) {
|
|
33105
33586
|
const registrationWarning = await ensureCodexPluginRegistered(registration, {
|
|
@@ -33126,13 +33607,14 @@ async function injectAgentCliProfile(profile, options) {
|
|
|
33126
33607
|
pluginRoot: plugin.pluginRoot,
|
|
33127
33608
|
pluginRoots: plugin.pluginRoots,
|
|
33128
33609
|
codexProfileName: codexProfile?.profileName,
|
|
33129
|
-
replaceSystemPrompt: options.replaceSystemPrompt ??
|
|
33610
|
+
replaceSystemPrompt: options.replaceSystemPrompt ?? false,
|
|
33611
|
+
resumeSessionId: options.resumeSessionId,
|
|
33130
33612
|
systemPromptFile
|
|
33131
33613
|
};
|
|
33132
33614
|
const injectedArgs = buildAgentCliArgs(capability.builderId, context);
|
|
33133
33615
|
return {
|
|
33134
33616
|
...profile,
|
|
33135
|
-
args:
|
|
33617
|
+
args: mergeAgentCliArgs(profile, capability.builderId, context, injectedArgs),
|
|
33136
33618
|
cleanup,
|
|
33137
33619
|
launchWarnings: [...profile.launchWarnings ?? [], ...launchWarnings]
|
|
33138
33620
|
};
|
|
@@ -33174,11 +33656,11 @@ function writeSystemPromptFile(cliId, systemPrompt, onCleanup) {
|
|
|
33174
33656
|
chmodBestEffort2(filePath, SYSTEM_PROMPT_FILE_MODE);
|
|
33175
33657
|
return filePath;
|
|
33176
33658
|
}
|
|
33177
|
-
function writeCodexFleetProfile(env, doctrine, pluginKeys, onCleanup) {
|
|
33659
|
+
function writeCodexFleetProfile(env, doctrine, pluginKeys, captureSessionHookExec, onCleanup) {
|
|
33178
33660
|
const codexHome = env.CODEX_HOME ?? path93__default.join(env.HOME ?? os22__default.homedir(), ".codex");
|
|
33179
33661
|
mkdirSync(codexHome, { recursive: true });
|
|
33180
33662
|
pruneStaleCodexFleetProfiles(codexHome);
|
|
33181
|
-
const profileName = `fleet-${
|
|
33663
|
+
const profileName = `fleet-${crypto5.randomUUID()}`;
|
|
33182
33664
|
const profilePath = path93__default.join(codexHome, `${profileName}.config.toml`);
|
|
33183
33665
|
onCleanup(() => rmBestEffort(profilePath));
|
|
33184
33666
|
writeFileNoFollow2(profilePath, [
|
|
@@ -33193,11 +33675,21 @@ function writeCodexFleetProfile(env, doctrine, pluginKeys, onCleanup) {
|
|
|
33193
33675
|
`[plugins."${escapeTomlBasicString2(pluginKey)}"]`,
|
|
33194
33676
|
"enabled = true",
|
|
33195
33677
|
""
|
|
33196
|
-
])
|
|
33678
|
+
]),
|
|
33679
|
+
...codexCaptureHookConfig(captureSessionHookExec)
|
|
33197
33680
|
].join("\n"));
|
|
33198
33681
|
chmodBestEffort2(profilePath, SYSTEM_PROMPT_FILE_MODE);
|
|
33199
33682
|
return { profileName, profilePath };
|
|
33200
33683
|
}
|
|
33684
|
+
function codexCaptureHookConfig(captureSessionHookExec) {
|
|
33685
|
+
if (captureSessionHookExec === void 0) return [];
|
|
33686
|
+
const command2 = buildPosixShellCommand([captureSessionHookExec.command, ...captureSessionHookExec.args]);
|
|
33687
|
+
return [
|
|
33688
|
+
"[hooks]",
|
|
33689
|
+
`UserPromptSubmit = [{ hooks = [{ type = "command", command = "${escapeTomlBasicString2(command2)}" }] }]`,
|
|
33690
|
+
""
|
|
33691
|
+
];
|
|
33692
|
+
}
|
|
33201
33693
|
function writeFileNoFollow2(filePath, content) {
|
|
33202
33694
|
const flags = constants.O_WRONLY | constants.O_CREAT | constants.O_TRUNC | constants.O_NOFOLLOW;
|
|
33203
33695
|
const fd = openSync(filePath, flags, SYSTEM_PROMPT_FILE_MODE);
|
|
@@ -33270,6 +33762,24 @@ function buildAgentCliArgs(builderId, context) {
|
|
|
33270
33762
|
return buildCodexNativeArgs(context);
|
|
33271
33763
|
}
|
|
33272
33764
|
}
|
|
33765
|
+
function mergeAgentCliArgs(profile, builderId, context, injectedArgs) {
|
|
33766
|
+
if (builderId !== "codex-native" || context.resumeSessionId === void 0) {
|
|
33767
|
+
return [...profile.args, ...injectedArgs];
|
|
33768
|
+
}
|
|
33769
|
+
const resumeSessionId = context.resumeSessionId;
|
|
33770
|
+
const prefixLength = profile.binPrefixArgs?.length ?? 0;
|
|
33771
|
+
const codexResumeArgs = ["resume", resumeSessionId];
|
|
33772
|
+
const injectedTail = injectedArgs.slice(codexResumeArgs.length);
|
|
33773
|
+
return [
|
|
33774
|
+
...profile.args.slice(0, prefixLength),
|
|
33775
|
+
...codexResumeArgs,
|
|
33776
|
+
...profile.args.slice(prefixLength).filter((arg, index, args) => !isCodexResumeArgAt(args, index, resumeSessionId)),
|
|
33777
|
+
...injectedTail
|
|
33778
|
+
];
|
|
33779
|
+
}
|
|
33780
|
+
function isCodexResumeArgAt(args, index, resumeSessionId) {
|
|
33781
|
+
return args[index] === "resume" && args[index + 1] === resumeSessionId || args[index] === resumeSessionId && args[index - 1] === "resume";
|
|
33782
|
+
}
|
|
33273
33783
|
function createOnceCleanup(cleanup) {
|
|
33274
33784
|
let cleaned = false;
|
|
33275
33785
|
return () => {
|
|
@@ -33453,389 +33963,6 @@ function applyMessagePolicy(text, policy) {
|
|
|
33453
33963
|
submit: policy.lineTerminator
|
|
33454
33964
|
};
|
|
33455
33965
|
}
|
|
33456
|
-
var FLEET_DATA_DIR_NAME = ".fleet";
|
|
33457
|
-
function getFleetDataDir() {
|
|
33458
|
-
return path93.join(os22.homedir(), FLEET_DATA_DIR_NAME);
|
|
33459
|
-
}
|
|
33460
|
-
function readAuthStoreFile(filePath) {
|
|
33461
|
-
let fd;
|
|
33462
|
-
try {
|
|
33463
|
-
fd = fs5.openSync(filePath, fs5.constants.O_RDONLY | NOFOLLOW_FLAG);
|
|
33464
|
-
if (!fs5.fstatSync(fd).isFile()) {
|
|
33465
|
-
return {};
|
|
33466
|
-
}
|
|
33467
|
-
return JSON.parse(fs5.readFileSync(fd, "utf-8"));
|
|
33468
|
-
} catch {
|
|
33469
|
-
return {};
|
|
33470
|
-
} finally {
|
|
33471
|
-
if (fd !== void 0) {
|
|
33472
|
-
try {
|
|
33473
|
-
fs5.closeSync(fd);
|
|
33474
|
-
} catch {
|
|
33475
|
-
}
|
|
33476
|
-
}
|
|
33477
|
-
}
|
|
33478
|
-
}
|
|
33479
|
-
var DEFAULT_AUTH_PATH = path93.join(getFleetDataDir(), "auth.json");
|
|
33480
|
-
var AUTH_LOCK_OWNER_FILE_NAME = "owner.json";
|
|
33481
|
-
var AUTH_LOCK_TIMEOUT_MS = 5e3;
|
|
33482
|
-
function createAuthService(deps = {}) {
|
|
33483
|
-
const authPath = deps.authPath ?? DEFAULT_AUTH_PATH;
|
|
33484
|
-
const lockDir = `${authPath}.lock`;
|
|
33485
|
-
return {
|
|
33486
|
-
// [HIGH #1] TOCTOU 수정: existsSync/read/check/delete/write 전체를 락 블록 안으로 이동
|
|
33487
|
-
async deleteApiKey(providerId) {
|
|
33488
|
-
let deleted = false;
|
|
33489
|
-
withAuthLock(authPath, lockDir, () => {
|
|
33490
|
-
if (!fs5.existsSync(authPath)) return;
|
|
33491
|
-
const data = readAuthStoreFile(authPath);
|
|
33492
|
-
if (!Object.prototype.hasOwnProperty.call(data, providerId)) return;
|
|
33493
|
-
delete data[providerId];
|
|
33494
|
-
writeAuthData(authPath, data);
|
|
33495
|
-
deleted = true;
|
|
33496
|
-
});
|
|
33497
|
-
return deleted;
|
|
33498
|
-
},
|
|
33499
|
-
// [HIGH #2] 읽기 경로: fd 기반 O_RDONLY|O_NOFOLLOW+fstatSync isFile
|
|
33500
|
-
async getApiKey(providerId) {
|
|
33501
|
-
let fd;
|
|
33502
|
-
try {
|
|
33503
|
-
if (!fs5.existsSync(authPath)) {
|
|
33504
|
-
return void 0;
|
|
33505
|
-
}
|
|
33506
|
-
fd = fs5.openSync(authPath, fs5.constants.O_RDONLY | NOFOLLOW_FLAG);
|
|
33507
|
-
if (!fs5.fstatSync(fd).isFile()) {
|
|
33508
|
-
return void 0;
|
|
33509
|
-
}
|
|
33510
|
-
const data = JSON.parse(fs5.readFileSync(fd, "utf-8"));
|
|
33511
|
-
return typeof data[providerId]?.key === "string" ? data[providerId].key : void 0;
|
|
33512
|
-
} catch {
|
|
33513
|
-
return void 0;
|
|
33514
|
-
} finally {
|
|
33515
|
-
if (fd !== void 0) {
|
|
33516
|
-
try {
|
|
33517
|
-
fs5.closeSync(fd);
|
|
33518
|
-
} catch {
|
|
33519
|
-
}
|
|
33520
|
-
}
|
|
33521
|
-
}
|
|
33522
|
-
},
|
|
33523
|
-
// [HIGH #2] 읽기 경로: fd 기반 O_RDONLY|O_NOFOLLOW 통일
|
|
33524
|
-
async listProviderIds() {
|
|
33525
|
-
if (!fs5.existsSync(authPath)) {
|
|
33526
|
-
return [];
|
|
33527
|
-
}
|
|
33528
|
-
try {
|
|
33529
|
-
return Object.keys(readAuthStoreFile(authPath)).sort();
|
|
33530
|
-
} catch {
|
|
33531
|
-
return [];
|
|
33532
|
-
}
|
|
33533
|
-
},
|
|
33534
|
-
async setApiKey(providerId, key) {
|
|
33535
|
-
const dir = path93.dirname(authPath);
|
|
33536
|
-
ensureSafeDirectory(dir);
|
|
33537
|
-
withAuthLock(authPath, lockDir, () => {
|
|
33538
|
-
const data = fs5.existsSync(authPath) ? readAuthStoreFile(authPath) : {};
|
|
33539
|
-
data[providerId] = {
|
|
33540
|
-
...data[providerId] ?? {},
|
|
33541
|
-
key
|
|
33542
|
-
};
|
|
33543
|
-
writeAuthData(authPath, data);
|
|
33544
|
-
});
|
|
33545
|
-
}
|
|
33546
|
-
};
|
|
33547
|
-
}
|
|
33548
|
-
function withAuthLock(authPath, lockDir, operation) {
|
|
33549
|
-
return withDirectoryLock(
|
|
33550
|
-
{
|
|
33551
|
-
lockDir,
|
|
33552
|
-
ownerFileName: AUTH_LOCK_OWNER_FILE_NAME,
|
|
33553
|
-
timeoutMs: AUTH_LOCK_TIMEOUT_MS
|
|
33554
|
-
},
|
|
33555
|
-
operation
|
|
33556
|
-
);
|
|
33557
|
-
}
|
|
33558
|
-
function writeAuthData(authPath, data) {
|
|
33559
|
-
writeAtomicSync(authPath, `${JSON.stringify(data, null, 2)}
|
|
33560
|
-
`, {
|
|
33561
|
-
mode: SECURE_FILE_MODE,
|
|
33562
|
-
fsync: true
|
|
33563
|
-
});
|
|
33564
|
-
}
|
|
33565
|
-
function formatMissingAuthKeyMessage(input) {
|
|
33566
|
-
const cliHint = input.cli ? `cli '${input.cli}'` : "selected CLI";
|
|
33567
|
-
return `Auth token not found for ${cliHint} (providerId: '${input.providerId}'). Run \`fleet auth login\` to register one.`;
|
|
33568
|
-
}
|
|
33569
|
-
function formatAuthValidationFailureMessage(input) {
|
|
33570
|
-
const detail = input.detail ? ` Detail: ${input.detail}` : "";
|
|
33571
|
-
if (input.status === "unauthorized") {
|
|
33572
|
-
return `Auth token was rejected (providerId: '${input.providerId}'). Check the token and try again.${detail}`;
|
|
33573
|
-
}
|
|
33574
|
-
if (input.status === "forbidden") {
|
|
33575
|
-
return `Auth token is not allowed for this provider (providerId: '${input.providerId}'). Check the token permissions.${detail}`;
|
|
33576
|
-
}
|
|
33577
|
-
if (input.status === "timeout") {
|
|
33578
|
-
return `Auth token validation timed out (providerId: '${input.providerId}'). Check the connection and try again.${detail}`;
|
|
33579
|
-
}
|
|
33580
|
-
if (input.status === "network") {
|
|
33581
|
-
return `Auth token validation failed due to a network error (providerId: '${input.providerId}'). Check the connection and try again.${detail}`;
|
|
33582
|
-
}
|
|
33583
|
-
if (input.status === "server") {
|
|
33584
|
-
return `Auth token validation failed because the provider returned an error (providerId: '${input.providerId}'). Try again later.${detail}`;
|
|
33585
|
-
}
|
|
33586
|
-
return `Auth token validation failed (providerId: '${input.providerId}'). Check the token and try again.${detail}`;
|
|
33587
|
-
}
|
|
33588
|
-
var LEGACY_AUTH_PATH = path93.join(getFleetDataDir(), "agent", "auth.json");
|
|
33589
|
-
var CURRENT_AUTH_PATH = path93.join(getFleetDataDir(), "auth.json");
|
|
33590
|
-
function mergeAuthStoresNoOverwrite(legacy, current) {
|
|
33591
|
-
const data = { ...current };
|
|
33592
|
-
const migratedProviderIds = [];
|
|
33593
|
-
const skippedProviderIds = [];
|
|
33594
|
-
for (const [providerId, entry] of Object.entries(legacy)) {
|
|
33595
|
-
if (Object.prototype.hasOwnProperty.call(data, providerId)) {
|
|
33596
|
-
skippedProviderIds.push(providerId);
|
|
33597
|
-
continue;
|
|
33598
|
-
}
|
|
33599
|
-
data[providerId] = entry;
|
|
33600
|
-
migratedProviderIds.push(providerId);
|
|
33601
|
-
}
|
|
33602
|
-
return {
|
|
33603
|
-
data,
|
|
33604
|
-
migratedProviderIds,
|
|
33605
|
-
skippedProviderIds
|
|
33606
|
-
};
|
|
33607
|
-
}
|
|
33608
|
-
async function migrateLegacyAuthStore(options = {}) {
|
|
33609
|
-
const legacyPath = options.legacyPath ?? LEGACY_AUTH_PATH;
|
|
33610
|
-
const currentPath = options.currentPath ?? CURRENT_AUTH_PATH;
|
|
33611
|
-
if (!fs5.existsSync(legacyPath)) {
|
|
33612
|
-
return createMigrationResult({
|
|
33613
|
-
legacyPath,
|
|
33614
|
-
currentPath,
|
|
33615
|
-
status: "legacy-missing",
|
|
33616
|
-
migratedProviderIds: [],
|
|
33617
|
-
skippedProviderIds: [],
|
|
33618
|
-
shouldPrintNotice: false
|
|
33619
|
-
});
|
|
33620
|
-
}
|
|
33621
|
-
const legacy = readAuthStoreFile(legacyPath);
|
|
33622
|
-
const current = fs5.existsSync(currentPath) ? readAuthStoreFile(currentPath) : {};
|
|
33623
|
-
const merged = mergeAuthStoresNoOverwrite(legacy, current);
|
|
33624
|
-
if (merged.migratedProviderIds.length > 0) {
|
|
33625
|
-
const dir = path93.dirname(currentPath);
|
|
33626
|
-
ensureSafeDirectory(dir);
|
|
33627
|
-
writeAtomicSync(currentPath, `${JSON.stringify(merged.data, null, 2)}
|
|
33628
|
-
`, {
|
|
33629
|
-
mode: SECURE_FILE_MODE,
|
|
33630
|
-
fsync: true
|
|
33631
|
-
});
|
|
33632
|
-
}
|
|
33633
|
-
return createMigrationResult({
|
|
33634
|
-
legacyPath,
|
|
33635
|
-
currentPath,
|
|
33636
|
-
status: merged.migratedProviderIds.length > 0 ? "migrated" : "unchanged",
|
|
33637
|
-
migratedProviderIds: merged.migratedProviderIds,
|
|
33638
|
-
skippedProviderIds: merged.skippedProviderIds,
|
|
33639
|
-
shouldPrintNotice: options.notify !== false && merged.migratedProviderIds.length > 0
|
|
33640
|
-
});
|
|
33641
|
-
}
|
|
33642
|
-
function createMigrationResult(input) {
|
|
33643
|
-
return {
|
|
33644
|
-
legacyPath: input.legacyPath,
|
|
33645
|
-
currentPath: input.currentPath,
|
|
33646
|
-
migratedCount: input.migratedProviderIds.length,
|
|
33647
|
-
skippedCount: input.skippedProviderIds.length,
|
|
33648
|
-
migratedProviderIds: input.migratedProviderIds,
|
|
33649
|
-
skippedProviderIds: input.skippedProviderIds,
|
|
33650
|
-
shouldPrintNotice: input.shouldPrintNotice,
|
|
33651
|
-
status: input.status
|
|
33652
|
-
};
|
|
33653
|
-
}
|
|
33654
|
-
var DEFAULT_AUTH_VALIDATION_TIMEOUT_MS = 5e3;
|
|
33655
|
-
async function validateAnthropicCompatibleApiKey(request) {
|
|
33656
|
-
const controller = new AbortController();
|
|
33657
|
-
const timeout = setTimeout(() => {
|
|
33658
|
-
controller.abort();
|
|
33659
|
-
}, request.timeoutMs ?? DEFAULT_AUTH_VALIDATION_TIMEOUT_MS);
|
|
33660
|
-
try {
|
|
33661
|
-
const response = await fetch(buildMessagesUrl(request.baseUrl), {
|
|
33662
|
-
method: "POST",
|
|
33663
|
-
headers: {
|
|
33664
|
-
"anthropic-version": "2023-06-01",
|
|
33665
|
-
"content-type": "application/json",
|
|
33666
|
-
"x-api-key": request.apiKey
|
|
33667
|
-
},
|
|
33668
|
-
body: JSON.stringify({
|
|
33669
|
-
model: "claude-3-5-haiku-20241022",
|
|
33670
|
-
max_tokens: 1,
|
|
33671
|
-
messages: [
|
|
33672
|
-
{
|
|
33673
|
-
role: "user",
|
|
33674
|
-
content: "ping"
|
|
33675
|
-
}
|
|
33676
|
-
]
|
|
33677
|
-
}),
|
|
33678
|
-
signal: controller.signal
|
|
33679
|
-
});
|
|
33680
|
-
if (response.ok) {
|
|
33681
|
-
return { providerId: request.providerId, status: "success" };
|
|
33682
|
-
}
|
|
33683
|
-
if (response.status === 401) {
|
|
33684
|
-
return { providerId: request.providerId, status: "unauthorized" };
|
|
33685
|
-
}
|
|
33686
|
-
if (response.status === 403) {
|
|
33687
|
-
return { providerId: request.providerId, status: "forbidden" };
|
|
33688
|
-
}
|
|
33689
|
-
if (response.status >= 500) {
|
|
33690
|
-
return {
|
|
33691
|
-
providerId: request.providerId,
|
|
33692
|
-
status: "server",
|
|
33693
|
-
detail: `HTTP ${response.status}`
|
|
33694
|
-
};
|
|
33695
|
-
}
|
|
33696
|
-
return {
|
|
33697
|
-
providerId: request.providerId,
|
|
33698
|
-
status: "unknown",
|
|
33699
|
-
detail: `HTTP ${response.status}`
|
|
33700
|
-
};
|
|
33701
|
-
} catch (error51) {
|
|
33702
|
-
if (isAbortError(error51)) {
|
|
33703
|
-
return { providerId: request.providerId, status: "timeout" };
|
|
33704
|
-
}
|
|
33705
|
-
return {
|
|
33706
|
-
providerId: request.providerId,
|
|
33707
|
-
status: "network",
|
|
33708
|
-
detail: error51 instanceof Error ? error51.message : String(error51)
|
|
33709
|
-
};
|
|
33710
|
-
} finally {
|
|
33711
|
-
clearTimeout(timeout);
|
|
33712
|
-
}
|
|
33713
|
-
}
|
|
33714
|
-
function isAuthValidationSuccess(result) {
|
|
33715
|
-
return result.status === "success";
|
|
33716
|
-
}
|
|
33717
|
-
function createAuthValidationError(result) {
|
|
33718
|
-
return new Error(formatAuthValidationFailureMessage(result));
|
|
33719
|
-
}
|
|
33720
|
-
function buildMessagesUrl(baseUrl) {
|
|
33721
|
-
return `${baseUrl.replace(/\/+$/, "")}/v1/messages`;
|
|
33722
|
-
}
|
|
33723
|
-
function isAbortError(error51) {
|
|
33724
|
-
return error51 instanceof DOMException && error51.name === "AbortError";
|
|
33725
|
-
}
|
|
33726
|
-
var CLAUDE_ZAI_PROVIDER_ID = "Claude Code with Z.AI GLM";
|
|
33727
|
-
var CLAUDE_KIMI_PROVIDER_ID = "Claude Code with Moonshot Kimi";
|
|
33728
|
-
var AUTH_PROVIDER_DEFINITIONS = {
|
|
33729
|
-
"claude-zai": {
|
|
33730
|
-
providerId: CLAUDE_ZAI_PROVIDER_ID,
|
|
33731
|
-
baseUrl: CLI_BACKENDS["claude-zai"].defaultEnv.ANTHROPIC_BASE_URL,
|
|
33732
|
-
env: CLI_BACKENDS["claude-zai"].defaultEnv
|
|
33733
|
-
},
|
|
33734
|
-
"claude-kimi": {
|
|
33735
|
-
providerId: CLAUDE_KIMI_PROVIDER_ID,
|
|
33736
|
-
baseUrl: CLI_BACKENDS["claude-kimi"].defaultEnv.ANTHROPIC_BASE_URL,
|
|
33737
|
-
env: CLI_BACKENDS["claude-kimi"].defaultEnv
|
|
33738
|
-
}
|
|
33739
|
-
};
|
|
33740
|
-
async function resolveAuthEnv(cli, deps) {
|
|
33741
|
-
const provider = AUTH_PROVIDER_DEFINITIONS[cli];
|
|
33742
|
-
if (!provider) return {};
|
|
33743
|
-
await migrateLegacyAuthStore();
|
|
33744
|
-
const auth = deps?.authService ?? createAuthService({ authPath: DEFAULT_AUTH_PATH });
|
|
33745
|
-
const token = await auth.getApiKey(provider.providerId);
|
|
33746
|
-
if (!token) {
|
|
33747
|
-
throw new Error(formatMissingAuthKeyMessage({ cli, providerId: provider.providerId }));
|
|
33748
|
-
}
|
|
33749
|
-
const validation = await validateAnthropicCompatibleApiKey({
|
|
33750
|
-
providerId: provider.providerId,
|
|
33751
|
-
apiKey: token,
|
|
33752
|
-
baseUrl: provider.baseUrl
|
|
33753
|
-
});
|
|
33754
|
-
if (!isAuthValidationSuccess(validation)) {
|
|
33755
|
-
const failure = {
|
|
33756
|
-
providerId: validation.providerId,
|
|
33757
|
-
status: validation.status,
|
|
33758
|
-
detail: validation.detail
|
|
33759
|
-
};
|
|
33760
|
-
throw createAuthValidationError(failure);
|
|
33761
|
-
}
|
|
33762
|
-
return { ...provider.env, ANTHROPIC_AUTH_TOKEN: token };
|
|
33763
|
-
}
|
|
33764
|
-
var GLOBAL_OPTIONS_VERSION = 1;
|
|
33765
|
-
var GLOBAL_OPTIONS_FILE_NAME = "settings.json";
|
|
33766
|
-
var LOCK_DIR_NAME2 = "settings.json.lock";
|
|
33767
|
-
var LOCK_OWNER_FILE_NAME = "owner";
|
|
33768
|
-
var TEMP_FILE_PREFIX = `.tmp-${GLOBAL_OPTIONS_FILE_NAME}-`;
|
|
33769
|
-
function createGlobalOptionsStore(deps = {}) {
|
|
33770
|
-
const dataDir = deps.dataDir ?? getFleetDataDir();
|
|
33771
|
-
const optionsPath = path93.join(dataDir, GLOBAL_OPTIONS_FILE_NAME);
|
|
33772
|
-
const lockDir = path93.join(dataDir, LOCK_DIR_NAME2);
|
|
33773
|
-
const store2 = createDurableJsonStore({
|
|
33774
|
-
filePath: optionsPath,
|
|
33775
|
-
lockDir,
|
|
33776
|
-
lockOwnerFileName: LOCK_OWNER_FILE_NAME,
|
|
33777
|
-
sanitize: (value) => sanitizeGlobalOptionsData(value).data,
|
|
33778
|
-
sensitivity: "sensitive",
|
|
33779
|
-
timeoutMs: deps.timeoutMs,
|
|
33780
|
-
staleLockMs: deps.staleLockMs,
|
|
33781
|
-
tempCleanupPrefix: TEMP_FILE_PREFIX,
|
|
33782
|
-
now: deps.now
|
|
33783
|
-
});
|
|
33784
|
-
return {
|
|
33785
|
-
path: optionsPath,
|
|
33786
|
-
load: () => store2.load(),
|
|
33787
|
-
save: (data) => store2.save(sanitizeGlobalOptionsData(data).data),
|
|
33788
|
-
update: (mutate) => store2.update((current) => sanitizeGlobalOptionsData(mutate(current)).data)
|
|
33789
|
-
};
|
|
33790
|
-
}
|
|
33791
|
-
function createEmptyGlobalOptionsData() {
|
|
33792
|
-
return {
|
|
33793
|
-
version: GLOBAL_OPTIONS_VERSION
|
|
33794
|
-
};
|
|
33795
|
-
}
|
|
33796
|
-
function sanitizeGlobalOptionsData(value) {
|
|
33797
|
-
if (!isRecord3(value)) {
|
|
33798
|
-
return { data: createEmptyGlobalOptionsData(), changed: true };
|
|
33799
|
-
}
|
|
33800
|
-
if (value.version !== GLOBAL_OPTIONS_VERSION) {
|
|
33801
|
-
return { data: createEmptyGlobalOptionsData(), changed: true };
|
|
33802
|
-
}
|
|
33803
|
-
const data = {
|
|
33804
|
-
version: GLOBAL_OPTIONS_VERSION,
|
|
33805
|
-
...typeof value.replaceSystemPrompt === "boolean" ? { replaceSystemPrompt: value.replaceSystemPrompt } : {},
|
|
33806
|
-
...typeof value.enableMetaphor === "boolean" ? { enableMetaphor: value.enableMetaphor } : {}
|
|
33807
|
-
};
|
|
33808
|
-
const allowedKeys = /* @__PURE__ */ new Set(["version", "replaceSystemPrompt", "enableMetaphor"]);
|
|
33809
|
-
const changed = Object.keys(value).some((key) => !allowedKeys.has(key)) || "replaceSystemPrompt" in value && typeof value.replaceSystemPrompt !== "boolean" || "enableMetaphor" in value && typeof value.enableMetaphor !== "boolean";
|
|
33810
|
-
return { data, changed };
|
|
33811
|
-
}
|
|
33812
|
-
function isRecord3(value) {
|
|
33813
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
33814
|
-
}
|
|
33815
|
-
function createGlobalOptionsService(deps = {}) {
|
|
33816
|
-
const store2 = deps.store ?? createGlobalOptionsStore({ dataDir: deps.dataDir });
|
|
33817
|
-
return {
|
|
33818
|
-
load: () => store2.load(),
|
|
33819
|
-
save: (data) => {
|
|
33820
|
-
store2.save(data);
|
|
33821
|
-
return store2.load();
|
|
33822
|
-
},
|
|
33823
|
-
update: (mutate) => updateGlobalOptions(store2, mutate)
|
|
33824
|
-
};
|
|
33825
|
-
}
|
|
33826
|
-
function updateGlobalOptions(store2, mutate) {
|
|
33827
|
-
return store2.update(mutate);
|
|
33828
|
-
}
|
|
33829
|
-
|
|
33830
|
-
// ../../packages/fleet-infra/dist/index.js
|
|
33831
|
-
function createInfraServices(deps = {}) {
|
|
33832
|
-
const globalOptionsService = createGlobalOptionsService();
|
|
33833
|
-
const authService = createAuthService({ authPath: deps.authPath ?? DEFAULT_AUTH_PATH });
|
|
33834
|
-
return {
|
|
33835
|
-
authService,
|
|
33836
|
-
globalOptionsService
|
|
33837
|
-
};
|
|
33838
|
-
}
|
|
33839
33966
|
var FLEET_WIKI_ENTRY_BEGIN = "<<<FLEET_WIKI_ENTRY_BEGIN";
|
|
33840
33967
|
var FLEET_WIKI_ENTRY_END = "<<<FLEET_WIKI_ENTRY_END>>>";
|
|
33841
33968
|
var FLEET_WIKI_RAW_SOURCE_BEGIN = "<<<FLEET_WIKI_RAW_SOURCE_BEGIN";
|
|
@@ -34862,7 +34989,7 @@ function stripLeadingFrontmatter(body) {
|
|
|
34862
34989
|
return stripped ? next : body;
|
|
34863
34990
|
}
|
|
34864
34991
|
function computeContentHash(content) {
|
|
34865
|
-
return
|
|
34992
|
+
return crypto5.createHash("sha256").update(content, "utf8").digest("hex").slice(0, 8);
|
|
34866
34993
|
}
|
|
34867
34994
|
function assertWithinRawDir(absolutePath, paths) {
|
|
34868
34995
|
const relative = path93__default.relative(paths.rawDir, absolutePath);
|
|
@@ -35075,7 +35202,7 @@ async function writeAtomic(filePath, content, paths) {
|
|
|
35075
35202
|
await ensureMemoryRoot(paths);
|
|
35076
35203
|
const tempPath = path93__default.join(
|
|
35077
35204
|
path93__default.dirname(filePath),
|
|
35078
|
-
`.tmp-${process.pid}-${Date.now()}-${
|
|
35205
|
+
`.tmp-${process.pid}-${Date.now()}-${crypto5.randomUUID()}-${os22__default.hostname()}`
|
|
35079
35206
|
);
|
|
35080
35207
|
await writeFile(tempPath, content, "utf8");
|
|
35081
35208
|
await rename(tempPath, filePath);
|
|
@@ -37612,7 +37739,7 @@ function parseOptionalIsoDate(value) {
|
|
|
37612
37739
|
return Number.isFinite(timestamp) ? timestamp : null;
|
|
37613
37740
|
}
|
|
37614
37741
|
function hashBodyForComparison(body) {
|
|
37615
|
-
return
|
|
37742
|
+
return crypto5.createHash("sha256").update(body.replace(/\s+/g, " ").trim(), "utf8").digest("hex").slice(0, 8);
|
|
37616
37743
|
}
|
|
37617
37744
|
function hasConflictingStatuses(entries) {
|
|
37618
37745
|
const statuses = new Set(entries.map((entry) => entry.status).filter((status) => status !== "unknown"));
|
|
@@ -39795,6 +39922,420 @@ function buildWikiToolSpec(config2, usage) {
|
|
|
39795
39922
|
};
|
|
39796
39923
|
}
|
|
39797
39924
|
|
|
39925
|
+
// src/carrier-settings-routes.ts
|
|
39926
|
+
var SUBAGENT_CLI_TYPES = /* @__PURE__ */ new Set(["claude", "claude-zai", "claude-kimi"]);
|
|
39927
|
+
var TASKFORCE_MIN_BACKENDS = 2;
|
|
39928
|
+
function createCarrierSettingsRouter(deps) {
|
|
39929
|
+
const controller = createStatusOverlayController(deps.registry);
|
|
39930
|
+
return async function handleCarrierSettingsRoute(context) {
|
|
39931
|
+
const { req, res, pathname } = context;
|
|
39932
|
+
if (pathname === "/carrier-settings/state") {
|
|
39933
|
+
if (req.method !== "GET") {
|
|
39934
|
+
deps.writeJson(res, 405, { error: "Method not allowed" });
|
|
39935
|
+
return true;
|
|
39936
|
+
}
|
|
39937
|
+
deps.writeJson(res, 200, buildCarrierSettingsState(deps.registry));
|
|
39938
|
+
return true;
|
|
39939
|
+
}
|
|
39940
|
+
if (pathname === "/carrier-settings/options") {
|
|
39941
|
+
if (req.method !== "GET") {
|
|
39942
|
+
deps.writeJson(res, 405, { error: "Method not allowed" });
|
|
39943
|
+
return true;
|
|
39944
|
+
}
|
|
39945
|
+
deps.writeJson(res, 200, buildCarrierSettingsOptions());
|
|
39946
|
+
return true;
|
|
39947
|
+
}
|
|
39948
|
+
const mutation = parseCarrierMutation(pathname);
|
|
39949
|
+
if (!mutation) return false;
|
|
39950
|
+
await handleCarrierMutation(req, res, deps, controller, mutation);
|
|
39951
|
+
return true;
|
|
39952
|
+
};
|
|
39953
|
+
}
|
|
39954
|
+
function buildCarrierSettingsState(registry3) {
|
|
39955
|
+
const defaultsByCarrier = buildDefaultsByCarrier(registry3);
|
|
39956
|
+
const snapshot = readCarriersSnapshot(defaultsByCarrier);
|
|
39957
|
+
return {
|
|
39958
|
+
generation: snapshot.generation,
|
|
39959
|
+
carriers: getRegisteredOrder(registry3).map((carrierId) => {
|
|
39960
|
+
const config2 = requireCarrierConfig(registry3, carrierId);
|
|
39961
|
+
const resolved = snapshot.carriers[carrierId] ?? fallbackResolvedState(config2);
|
|
39962
|
+
return toCarrierSettingsCarrier(registry3, config2, resolved);
|
|
39963
|
+
})
|
|
39964
|
+
};
|
|
39965
|
+
}
|
|
39966
|
+
function buildCarrierSettingsOptions() {
|
|
39967
|
+
return {
|
|
39968
|
+
cliTypes: getCliTypes().map(toCliOption),
|
|
39969
|
+
taskForceConstraints: { minBackends: TASKFORCE_MIN_BACKENDS }
|
|
39970
|
+
};
|
|
39971
|
+
}
|
|
39972
|
+
async function handleCarrierMutation(req, res, deps, controller, mutation) {
|
|
39973
|
+
const method = req.method ?? "GET";
|
|
39974
|
+
const expectedMethod = mutation.kind === "display-name" ? "PATCH" : mutation.kind === "taskforce-backend" || mutation.kind === "taskforce-all" ? method : "PUT";
|
|
39975
|
+
if (!isExpectedCarrierMethod(mutation, method, expectedMethod)) {
|
|
39976
|
+
deps.writeJson(res, 405, { error: "Method not allowed" });
|
|
39977
|
+
return;
|
|
39978
|
+
}
|
|
39979
|
+
if (!deps.isAuthorized(req)) {
|
|
39980
|
+
deps.writeJson(res, 401, { error: "unauthorized" });
|
|
39981
|
+
return;
|
|
39982
|
+
}
|
|
39983
|
+
if (!isJsonRequest(req)) {
|
|
39984
|
+
deps.writeJson(res, 415, { error: "unsupported_media_type" });
|
|
39985
|
+
return;
|
|
39986
|
+
}
|
|
39987
|
+
if (!getRegisteredCarrierConfig(deps.registry, mutation.carrierId)) {
|
|
39988
|
+
deps.writeJson(res, 404, { error: "carrier_not_found" });
|
|
39989
|
+
return;
|
|
39990
|
+
}
|
|
39991
|
+
if (mutation.kind === "taskforce-backend" && !isCliType(mutation.cliType)) {
|
|
39992
|
+
deps.writeJson(res, 400, { error: "invalid_cli_type" });
|
|
39993
|
+
return;
|
|
39994
|
+
}
|
|
39995
|
+
try {
|
|
39996
|
+
if (mutation.kind === "cli") {
|
|
39997
|
+
const body2 = await readRequiredJsonBody(req, res, deps);
|
|
39998
|
+
if (!body2.ok) return;
|
|
39999
|
+
await mutateCarrierCli(res, deps, controller, mutation.carrierId, body2.body);
|
|
40000
|
+
return;
|
|
40001
|
+
}
|
|
40002
|
+
if (mutation.kind === "model") {
|
|
40003
|
+
const body2 = await readRequiredJsonBody(req, res, deps);
|
|
40004
|
+
if (!body2.ok) return;
|
|
40005
|
+
await mutateCarrierModel(res, deps, mutation.carrierId, body2.body);
|
|
40006
|
+
return;
|
|
40007
|
+
}
|
|
40008
|
+
if (mutation.kind === "display-name") {
|
|
40009
|
+
const body2 = await readRequiredJsonBody(req, res, deps);
|
|
40010
|
+
if (!body2.ok) return;
|
|
40011
|
+
mutateDisplayName(res, deps, mutation.carrierId, body2.body);
|
|
40012
|
+
return;
|
|
40013
|
+
}
|
|
40014
|
+
if (mutation.kind === "agent-mode") {
|
|
40015
|
+
const body2 = await readRequiredJsonBody(req, res, deps);
|
|
40016
|
+
if (!body2.ok) return;
|
|
40017
|
+
mutateAgentMode(res, deps, mutation.carrierId, body2.body);
|
|
40018
|
+
return;
|
|
40019
|
+
}
|
|
40020
|
+
if (mutation.kind === "taskforce-backend") {
|
|
40021
|
+
if (method === "DELETE") {
|
|
40022
|
+
const body3 = await readRequiredJsonBody(req, res, deps);
|
|
40023
|
+
if (!body3.ok) return;
|
|
40024
|
+
resetTaskForceModelSelection(mutation.carrierId, mutation.cliType);
|
|
40025
|
+
refreshTaskForceConfiguredCarriers(deps.registry);
|
|
40026
|
+
writeMutationState(res, deps);
|
|
40027
|
+
return;
|
|
40028
|
+
}
|
|
40029
|
+
const body2 = await readRequiredJsonBody(req, res, deps);
|
|
40030
|
+
if (!body2.ok) return;
|
|
40031
|
+
mutateTaskForceBackend(res, deps, mutation.carrierId, mutation.cliType, body2.body);
|
|
40032
|
+
return;
|
|
40033
|
+
}
|
|
40034
|
+
const body = await readRequiredJsonBody(req, res, deps);
|
|
40035
|
+
if (!body.ok) return;
|
|
40036
|
+
resetCarrierTaskForceConfig(mutation.carrierId);
|
|
40037
|
+
refreshTaskForceConfiguredCarriers(deps.registry);
|
|
40038
|
+
writeMutationState(res, deps);
|
|
40039
|
+
} catch (error51) {
|
|
40040
|
+
deps.writeJson(res, 400, { error: error51 instanceof Error ? error51.message : "invalid_request" });
|
|
40041
|
+
}
|
|
40042
|
+
}
|
|
40043
|
+
async function mutateCarrierCli(res, deps, controller, carrierId, body) {
|
|
40044
|
+
const cliType = readCliType(body.cliType);
|
|
40045
|
+
if (!cliType) {
|
|
40046
|
+
deps.writeJson(res, 400, { error: "invalid_cli_type" });
|
|
40047
|
+
return;
|
|
40048
|
+
}
|
|
40049
|
+
await controller.changeCliType(carrierId, cliType);
|
|
40050
|
+
if (!SUBAGENT_CLI_TYPES.has(cliType)) {
|
|
40051
|
+
const resolved = readCarriersSnapshot(buildDefaultsByCarrier(deps.registry)).carriers[carrierId];
|
|
40052
|
+
if (resolved?.agentMode === "subagent") {
|
|
40053
|
+
const config2 = requireCarrierConfig(deps.registry, carrierId);
|
|
40054
|
+
updateCarrierAgentModeAtomically(carrierId, "cli", config2.defaultAgentMode ?? "cli");
|
|
40055
|
+
}
|
|
40056
|
+
}
|
|
40057
|
+
writeMutationState(res, deps);
|
|
40058
|
+
}
|
|
40059
|
+
async function mutateCarrierModel(res, deps, carrierId, body) {
|
|
40060
|
+
const config2 = requireCarrierConfig(deps.registry, carrierId);
|
|
40061
|
+
const cliType = resolveAgentCliType2(carrierId, config2.defaultCliType);
|
|
40062
|
+
const selection = readSelection(cliType, body);
|
|
40063
|
+
if (!selection) {
|
|
40064
|
+
deps.writeJson(res, 400, { error: "invalid_model_selection" });
|
|
40065
|
+
return;
|
|
40066
|
+
}
|
|
40067
|
+
await updateAgentCliSelection(carrierId, cliType, selection);
|
|
40068
|
+
notifyStatusUpdate(deps.registry);
|
|
40069
|
+
writeMutationState(res, deps);
|
|
40070
|
+
}
|
|
40071
|
+
function mutateDisplayName(res, deps, carrierId, body) {
|
|
40072
|
+
const displayName = normalizeCarrierDisplayNameInput(body.displayName);
|
|
40073
|
+
if (displayName === null) {
|
|
40074
|
+
deps.writeJson(res, 400, { error: "invalid_display_name" });
|
|
40075
|
+
return;
|
|
40076
|
+
}
|
|
40077
|
+
updateCarrierDisplayName(carrierId, displayName, getCarrierSourceDisplayName(deps.registry, carrierId));
|
|
40078
|
+
notifyStatusUpdate(deps.registry);
|
|
40079
|
+
writeMutationState(res, deps);
|
|
40080
|
+
}
|
|
40081
|
+
function mutateAgentMode(res, deps, carrierId, body) {
|
|
40082
|
+
const config2 = requireCarrierConfig(deps.registry, carrierId);
|
|
40083
|
+
const agentMode = body.agentMode;
|
|
40084
|
+
if (agentMode !== "cli" && agentMode !== "subagent") {
|
|
40085
|
+
deps.writeJson(res, 400, { error: "invalid_agent_mode" });
|
|
40086
|
+
return;
|
|
40087
|
+
}
|
|
40088
|
+
const cliType = resolveAgentCliType2(carrierId, config2.defaultCliType);
|
|
40089
|
+
if (agentMode === "subagent" && !SUBAGENT_CLI_TYPES.has(cliType)) {
|
|
40090
|
+
deps.writeJson(res, 400, { error: "subagent_unsupported" });
|
|
40091
|
+
return;
|
|
40092
|
+
}
|
|
40093
|
+
updateCarrierAgentModeAtomically(carrierId, agentMode, config2.defaultAgentMode ?? "cli");
|
|
40094
|
+
if (agentMode === "subagent") refreshTaskForceConfiguredCarriers(deps.registry);
|
|
40095
|
+
notifyStatusUpdate(deps.registry);
|
|
40096
|
+
writeMutationState(res, deps);
|
|
40097
|
+
}
|
|
40098
|
+
function mutateTaskForceBackend(res, deps, carrierId, cliType, body) {
|
|
40099
|
+
const selection = readSelection(cliType, body);
|
|
40100
|
+
if (!selection) {
|
|
40101
|
+
deps.writeJson(res, 400, { error: "invalid_model_selection" });
|
|
40102
|
+
return;
|
|
40103
|
+
}
|
|
40104
|
+
updateTaskForceBackendAtomically(carrierId, cliType, selection);
|
|
40105
|
+
refreshTaskForceConfiguredCarriers(deps.registry);
|
|
40106
|
+
notifyStatusUpdate(deps.registry);
|
|
40107
|
+
writeMutationState(res, deps);
|
|
40108
|
+
}
|
|
40109
|
+
function writeMutationState(res, deps) {
|
|
40110
|
+
const response = { state: buildCarrierSettingsState(deps.registry) };
|
|
40111
|
+
deps.writeJson(res, 200, response);
|
|
40112
|
+
}
|
|
40113
|
+
async function readRequiredJsonBody(req, res, deps) {
|
|
40114
|
+
const body = await deps.readJsonBody(req);
|
|
40115
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) {
|
|
40116
|
+
deps.writeJson(res, 400, { error: "invalid_json" });
|
|
40117
|
+
return { ok: false };
|
|
40118
|
+
}
|
|
40119
|
+
return { ok: true, body };
|
|
40120
|
+
}
|
|
40121
|
+
function buildDefaultsByCarrier(registry3) {
|
|
40122
|
+
return Object.fromEntries(
|
|
40123
|
+
getRegisteredOrder(registry3).map((carrierId) => {
|
|
40124
|
+
const config2 = requireCarrierConfig(registry3, carrierId);
|
|
40125
|
+
return [carrierId, {
|
|
40126
|
+
cliType: config2.defaultCliType,
|
|
40127
|
+
...config2.defaultAgentMode ? { defaultAgentMode: config2.defaultAgentMode } : {},
|
|
40128
|
+
...buildCarrierModelDefaults(config2, config2.defaultCliType)
|
|
40129
|
+
}];
|
|
40130
|
+
})
|
|
40131
|
+
);
|
|
40132
|
+
}
|
|
40133
|
+
function toCarrierSettingsCarrier(registry3, config2, resolved) {
|
|
40134
|
+
const cliType = resolved.agentCliType ?? config2.defaultCliType;
|
|
40135
|
+
const selection = resolved.agentCli[cliType] ?? readDefaultSelection(cliType);
|
|
40136
|
+
const taskForceBackends = toTaskForceBackends(resolved.taskforce);
|
|
40137
|
+
return {
|
|
40138
|
+
carrierId: config2.id,
|
|
40139
|
+
displayName: resolved.displayName ?? getCarrierSourceDisplayName(registry3, config2.id),
|
|
40140
|
+
sourceDisplayName: getCarrierSourceDisplayName(registry3, config2.id),
|
|
40141
|
+
role: config2.carrierMetadata?.title ?? config2.displayName,
|
|
40142
|
+
roleDescription: config2.carrierMetadata?.summary ?? "",
|
|
40143
|
+
...config2.carrierMetadata?.category ? { category: config2.carrierMetadata.category } : {},
|
|
40144
|
+
slot: config2.slot,
|
|
40145
|
+
cliType,
|
|
40146
|
+
defaultCliType: config2.defaultCliType,
|
|
40147
|
+
model: selection.model,
|
|
40148
|
+
...selection.effort ? { effort: selection.effort } : {},
|
|
40149
|
+
agentMode: resolved.agentMode,
|
|
40150
|
+
subagentMode: resolved.agentMode === "subagent",
|
|
40151
|
+
taskForceBackendCount: taskForceBackends.length,
|
|
40152
|
+
taskforce: { backends: taskForceBackends }
|
|
40153
|
+
};
|
|
40154
|
+
}
|
|
40155
|
+
function toTaskForceBackends(taskforce) {
|
|
40156
|
+
return TASKFORCE_CLI_TYPES.map((cliType) => {
|
|
40157
|
+
const selection = taskforce[cliType];
|
|
40158
|
+
if (!selection) return null;
|
|
40159
|
+
return {
|
|
40160
|
+
cliType,
|
|
40161
|
+
model: selection.model,
|
|
40162
|
+
...selection.effort ? { effort: selection.effort } : {}
|
|
40163
|
+
};
|
|
40164
|
+
}).filter((backend) => backend !== null);
|
|
40165
|
+
}
|
|
40166
|
+
function toCliOption(cliType) {
|
|
40167
|
+
const provider = getProviderModels(cliType);
|
|
40168
|
+
return {
|
|
40169
|
+
id: cliType,
|
|
40170
|
+
displayName: CLI_DISPLAY_NAMES[cliType] ?? provider.name,
|
|
40171
|
+
supportsSubagent: SUBAGENT_CLI_TYPES.has(cliType),
|
|
40172
|
+
models: provider.models.map((model) => {
|
|
40173
|
+
const effort = getEffort(cliType, model.modelId);
|
|
40174
|
+
return {
|
|
40175
|
+
modelId: model.modelId,
|
|
40176
|
+
name: model.name,
|
|
40177
|
+
...effort.supported ? { effort: { levels: effort.levels, default: effort.default } } : {}
|
|
40178
|
+
};
|
|
40179
|
+
}),
|
|
40180
|
+
defaultModel: provider.defaultModel ?? provider.models[0]?.modelId
|
|
40181
|
+
};
|
|
40182
|
+
}
|
|
40183
|
+
function createStatusOverlayController(registry3) {
|
|
40184
|
+
return new StatusOverlayController({
|
|
40185
|
+
getEntries: () => [],
|
|
40186
|
+
getRegisteredOrder: () => getRegisteredOrder(registry3),
|
|
40187
|
+
getCarrierConfig: (carrierId) => getRegisteredCarrierConfig(registry3, carrierId),
|
|
40188
|
+
getResolvedCliType: (carrierId) => {
|
|
40189
|
+
const config2 = getRegisteredCarrierConfig(registry3, carrierId);
|
|
40190
|
+
return config2 ? resolveAgentCliType2(carrierId, config2.defaultCliType) : void 0;
|
|
40191
|
+
},
|
|
40192
|
+
getCurrentModelSelection: (carrierId) => {
|
|
40193
|
+
return readCurrentModelSelection(registry3, carrierId);
|
|
40194
|
+
},
|
|
40195
|
+
getAvailableModels: (cliType) => {
|
|
40196
|
+
const provider = getProviderModels(cliType);
|
|
40197
|
+
return {
|
|
40198
|
+
defaultModel: provider.defaultModel,
|
|
40199
|
+
models: provider.models.map((model) => ({
|
|
40200
|
+
modelId: model.modelId,
|
|
40201
|
+
name: model.name,
|
|
40202
|
+
effort: getEffort(cliType, model.modelId)
|
|
40203
|
+
}))
|
|
40204
|
+
};
|
|
40205
|
+
},
|
|
40206
|
+
getEffort: (cliType, modelId) => getEffort(cliType, modelId),
|
|
40207
|
+
getAgentCliSelection: (carrierId, cliType) => getAgentCliSelection(carrierId, cliType),
|
|
40208
|
+
saveAgentCliSelection,
|
|
40209
|
+
updateCarrierCliType: (carrierId, cliType) => updateCarrierCliType(registry3, carrierId),
|
|
40210
|
+
applyAgentCliTypeSelectionUpdate,
|
|
40211
|
+
refreshAgentPanel: () => void 0,
|
|
40212
|
+
syncModelConfig: () => void 0,
|
|
40213
|
+
notifyStatusUpdate: () => notifyStatusUpdate(registry3)
|
|
40214
|
+
});
|
|
40215
|
+
}
|
|
40216
|
+
function updateCarrierAgentModeAtomically(carrierId, agentMode, defaultAgentMode) {
|
|
40217
|
+
if (agentMode === "cli") {
|
|
40218
|
+
setCarrierAgentMode(carrierId, false, defaultAgentMode);
|
|
40219
|
+
return;
|
|
40220
|
+
}
|
|
40221
|
+
updateCarriers((states) => {
|
|
40222
|
+
const carriers = { ...states.carriers ?? {} };
|
|
40223
|
+
const current = carriers[carrierId] ?? {};
|
|
40224
|
+
const next = { ...current };
|
|
40225
|
+
next.agentMode = "subagent";
|
|
40226
|
+
delete next.taskforce;
|
|
40227
|
+
carriers[carrierId] = next;
|
|
40228
|
+
states.carriers = carriers;
|
|
40229
|
+
});
|
|
40230
|
+
}
|
|
40231
|
+
function updateTaskForceBackendAtomically(carrierId, cliType, selection) {
|
|
40232
|
+
updateCarriers((states) => {
|
|
40233
|
+
const carriers = { ...states.carriers ?? {} };
|
|
40234
|
+
const current = carriers[carrierId] ?? {};
|
|
40235
|
+
carriers[carrierId] = {
|
|
40236
|
+
...current,
|
|
40237
|
+
agentMode: "cli",
|
|
40238
|
+
taskforce: {
|
|
40239
|
+
...current.taskforce ?? {},
|
|
40240
|
+
[cliType]: selection
|
|
40241
|
+
}
|
|
40242
|
+
};
|
|
40243
|
+
states.carriers = carriers;
|
|
40244
|
+
});
|
|
40245
|
+
}
|
|
40246
|
+
function refreshTaskForceConfiguredCarriers(registry3) {
|
|
40247
|
+
setTaskForceConfiguredCarriers(registry3, getConfiguredTaskForceCarrierIds(getRegisteredOrder(registry3)));
|
|
40248
|
+
notifyStatusUpdate(registry3);
|
|
40249
|
+
}
|
|
40250
|
+
function readSelection(cliType, body) {
|
|
40251
|
+
if (typeof body.model !== "string") return null;
|
|
40252
|
+
const provider = getProviderModels(cliType);
|
|
40253
|
+
if (!provider.models.some((model) => model.modelId === body.model)) return null;
|
|
40254
|
+
const effort = getEffort(cliType, body.model);
|
|
40255
|
+
if (!effort.supported) {
|
|
40256
|
+
return body.effort === void 0 ? { model: body.model } : null;
|
|
40257
|
+
}
|
|
40258
|
+
if (typeof body.effort !== "string" || !effort.levels.includes(body.effort)) return null;
|
|
40259
|
+
return { model: body.model, effort: body.effort };
|
|
40260
|
+
}
|
|
40261
|
+
function readDefaultSelection(cliType) {
|
|
40262
|
+
const provider = getProviderModels(cliType);
|
|
40263
|
+
const model = provider.defaultModel;
|
|
40264
|
+
const effort = getEffort(cliType, model);
|
|
40265
|
+
return {
|
|
40266
|
+
model,
|
|
40267
|
+
...effort.supported ? { effort: effort.default } : {}
|
|
40268
|
+
};
|
|
40269
|
+
}
|
|
40270
|
+
function readCurrentModelSelection(registry3, carrierId) {
|
|
40271
|
+
const config2 = getRegisteredCarrierConfig(registry3, carrierId);
|
|
40272
|
+
if (!config2) return void 0;
|
|
40273
|
+
const defaults = {
|
|
40274
|
+
[carrierId]: {
|
|
40275
|
+
cliType: config2.defaultCliType,
|
|
40276
|
+
...config2.defaultAgentMode ? { defaultAgentMode: config2.defaultAgentMode } : {},
|
|
40277
|
+
...buildCarrierModelDefaults(config2, config2.defaultCliType)
|
|
40278
|
+
}
|
|
40279
|
+
};
|
|
40280
|
+
const resolved = readCarriersSnapshot(defaults).carriers[carrierId] ?? fallbackResolvedState(config2);
|
|
40281
|
+
const cliType = resolved.agentCliType ?? config2.defaultCliType;
|
|
40282
|
+
return resolved.agentCli[cliType] ?? readDefaultSelection(cliType);
|
|
40283
|
+
}
|
|
40284
|
+
function fallbackResolvedState(config2) {
|
|
40285
|
+
return {
|
|
40286
|
+
agentMode: config2.defaultAgentMode ?? "cli",
|
|
40287
|
+
agentCliType: config2.defaultCliType,
|
|
40288
|
+
agentCli: { [config2.defaultCliType]: readDefaultSelection(config2.defaultCliType) },
|
|
40289
|
+
taskforce: {}
|
|
40290
|
+
};
|
|
40291
|
+
}
|
|
40292
|
+
function parseCarrierMutation(pathname) {
|
|
40293
|
+
const parts = pathname.split("/").filter(Boolean);
|
|
40294
|
+
if (parts[0] !== "carrier-settings" || parts[1] !== "carriers" || !parts[2]) return null;
|
|
40295
|
+
const carrierId = safeDecodeURIComponent(parts[2]);
|
|
40296
|
+
if (!carrierId) return null;
|
|
40297
|
+
if (parts.length === 4 && parts[3] === "cli") return { kind: "cli", carrierId };
|
|
40298
|
+
if (parts.length === 4 && parts[3] === "model") return { kind: "model", carrierId };
|
|
40299
|
+
if (parts.length === 4 && parts[3] === "display-name") return { kind: "display-name", carrierId };
|
|
40300
|
+
if (parts.length === 4 && parts[3] === "agent-mode") return { kind: "agent-mode", carrierId };
|
|
40301
|
+
if (parts.length === 4 && parts[3] === "taskforce") return { kind: "taskforce-all", carrierId };
|
|
40302
|
+
if (parts.length === 5 && parts[3] === "taskforce") {
|
|
40303
|
+
const cliType = safeDecodeURIComponent(parts[4] ?? "");
|
|
40304
|
+
return cliType ? { kind: "taskforce-backend", carrierId, cliType } : null;
|
|
40305
|
+
}
|
|
40306
|
+
return null;
|
|
40307
|
+
}
|
|
40308
|
+
function safeDecodeURIComponent(value) {
|
|
40309
|
+
try {
|
|
40310
|
+
return decodeURIComponent(value);
|
|
40311
|
+
} catch {
|
|
40312
|
+
return null;
|
|
40313
|
+
}
|
|
40314
|
+
}
|
|
40315
|
+
function isExpectedCarrierMethod(mutation, method, expectedMethod) {
|
|
40316
|
+
if (mutation.kind === "taskforce-backend") return method === "PUT" || method === "DELETE";
|
|
40317
|
+
if (mutation.kind === "taskforce-all") return method === "DELETE";
|
|
40318
|
+
return method === expectedMethod;
|
|
40319
|
+
}
|
|
40320
|
+
function isJsonRequest(req) {
|
|
40321
|
+
const contentType = req.headers["content-type"];
|
|
40322
|
+
return typeof contentType === "string" && contentType.toLowerCase().split(";")[0]?.trim() === "application/json";
|
|
40323
|
+
}
|
|
40324
|
+
function readCliType(value) {
|
|
40325
|
+
return typeof value === "string" && isCliType(value) ? value : null;
|
|
40326
|
+
}
|
|
40327
|
+
function isCliType(value) {
|
|
40328
|
+
return Object.prototype.hasOwnProperty.call(CLI_BACKENDS, value);
|
|
40329
|
+
}
|
|
40330
|
+
function getCliTypes() {
|
|
40331
|
+
return Object.keys(CLI_BACKENDS);
|
|
40332
|
+
}
|
|
40333
|
+
function requireCarrierConfig(registry3, carrierId) {
|
|
40334
|
+
const config2 = getRegisteredCarrierConfig(registry3, carrierId);
|
|
40335
|
+
if (!config2) throw new Error(`Carrier not found: ${carrierId}`);
|
|
40336
|
+
return config2;
|
|
40337
|
+
}
|
|
40338
|
+
|
|
39798
40339
|
// src/codex/security-headers.ts
|
|
39799
40340
|
var CONTENT_SECURITY_POLICY = "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'; object-src 'none'; base-uri 'none'";
|
|
39800
40341
|
var SECURITY_HEADERS = {
|
|
@@ -39822,7 +40363,7 @@ function safeEqual(left, right) {
|
|
|
39822
40363
|
return timingSafeEqual(leftBytes, rightBytes);
|
|
39823
40364
|
}
|
|
39824
40365
|
function workspaceHash(canonicalCwd) {
|
|
39825
|
-
return
|
|
40366
|
+
return crypto5.createHash("sha256").update(canonicalCwd).digest("hex").slice(0, 12);
|
|
39826
40367
|
}
|
|
39827
40368
|
async function canonicalizeTheaterPath(cwd) {
|
|
39828
40369
|
return canonicalizeTheaterPathSync(cwd);
|
|
@@ -40702,7 +41243,7 @@ function createCodexGateway(deps) {
|
|
|
40702
41243
|
return true;
|
|
40703
41244
|
}
|
|
40704
41245
|
if (selected.kind === "no-workspace") {
|
|
40705
|
-
if (
|
|
41246
|
+
if (isJsonRequest2(request)) {
|
|
40706
41247
|
sendJson2(response, 404, { error: "no_workspace_registered" });
|
|
40707
41248
|
return true;
|
|
40708
41249
|
}
|
|
@@ -40814,7 +41355,7 @@ function legacyWorkspacePath(url2) {
|
|
|
40814
41355
|
}
|
|
40815
41356
|
return null;
|
|
40816
41357
|
}
|
|
40817
|
-
function
|
|
41358
|
+
function isJsonRequest2(request) {
|
|
40818
41359
|
const accept = Array.isArray(request.headers.accept) ? request.headers.accept.join(",") : request.headers.accept ?? "";
|
|
40819
41360
|
const requestedWith = Array.isArray(request.headers["x-requested-with"]) ? request.headers["x-requested-with"].join(",") : request.headers["x-requested-with"] ?? "";
|
|
40820
41361
|
return accept.includes("application/json") || requestedWith.toLowerCase() === "xmlhttprequest";
|
|
@@ -40889,6 +41430,155 @@ function readRawHeaderValues(rawHeaders, name) {
|
|
|
40889
41430
|
function stripIpv6Brackets2(host) {
|
|
40890
41431
|
return host.startsWith("[") && host.endsWith("]") ? host.slice(1, -1) : host;
|
|
40891
41432
|
}
|
|
41433
|
+
var STATE_VERSION = 1;
|
|
41434
|
+
var STATE_LOCK_DIR_NAME = "state.lock";
|
|
41435
|
+
var STATE_LOCK_OWNER_FILE_NAME = "owner.json";
|
|
41436
|
+
var STATE_TEMP_PREFIX = ".state.";
|
|
41437
|
+
function createConsoleDurableStateStore(deps = {}) {
|
|
41438
|
+
const paths = deps.paths ?? createConsoleDataPaths();
|
|
41439
|
+
const createStore = deps.createStore ?? createDurableJsonStore;
|
|
41440
|
+
return createStore({
|
|
41441
|
+
filePath: paths.stateFile,
|
|
41442
|
+
lockDir: path93__default.join(paths.dir, STATE_LOCK_DIR_NAME),
|
|
41443
|
+
lockOwnerFileName: STATE_LOCK_OWNER_FILE_NAME,
|
|
41444
|
+
now: deps.now,
|
|
41445
|
+
sanitize: sanitizeDurableConsoleState,
|
|
41446
|
+
sensitivity: "sensitive",
|
|
41447
|
+
tempCleanupPrefix: STATE_TEMP_PREFIX
|
|
41448
|
+
});
|
|
41449
|
+
}
|
|
41450
|
+
function sanitizeDurableConsoleState(value) {
|
|
41451
|
+
if (!isRecord4(value) || value.version !== STATE_VERSION) return emptyDurableConsoleState();
|
|
41452
|
+
return {
|
|
41453
|
+
version: STATE_VERSION,
|
|
41454
|
+
theaters: readTheaterRegistrations(value.theaters),
|
|
41455
|
+
operations: readDurableOperations(value.operations)
|
|
41456
|
+
};
|
|
41457
|
+
}
|
|
41458
|
+
function emptyDurableConsoleState() {
|
|
41459
|
+
return { version: STATE_VERSION, theaters: [], operations: [] };
|
|
41460
|
+
}
|
|
41461
|
+
function readProviderSessionCapture(fleetSessionId, deps = {}) {
|
|
41462
|
+
if (!isSafeCaptureId(fleetSessionId)) return null;
|
|
41463
|
+
const capturesDir = deps.capturesDir ?? createConsoleDataPaths().capturesDir;
|
|
41464
|
+
const filePath = path93__default.join(capturesDir, `${fleetSessionId}.json`);
|
|
41465
|
+
try {
|
|
41466
|
+
const parsed = JSON.parse(fs5__default.readFileSync(filePath, "utf8"));
|
|
41467
|
+
return sanitizeProviderSession(parsed);
|
|
41468
|
+
} catch {
|
|
41469
|
+
return null;
|
|
41470
|
+
}
|
|
41471
|
+
}
|
|
41472
|
+
function mergeProviderSessionCaptures(state, deps = {}) {
|
|
41473
|
+
let changed = false;
|
|
41474
|
+
const operations = state.operations.map((operation) => {
|
|
41475
|
+
if (operation.providerSession) return operation;
|
|
41476
|
+
const providerSession = readProviderSessionCapture(operation.sessionId, deps);
|
|
41477
|
+
if (!providerSession) return operation;
|
|
41478
|
+
changed = true;
|
|
41479
|
+
return { ...operation, providerSession };
|
|
41480
|
+
});
|
|
41481
|
+
return changed ? { ...state, operations } : state;
|
|
41482
|
+
}
|
|
41483
|
+
function unlinkProviderSessionCapture(fleetSessionId, deps = {}) {
|
|
41484
|
+
if (!isSafeCaptureId(fleetSessionId)) return false;
|
|
41485
|
+
const capturesDir = deps.capturesDir ?? createConsoleDataPaths().capturesDir;
|
|
41486
|
+
try {
|
|
41487
|
+
fs5__default.unlinkSync(path93__default.join(capturesDir, `${fleetSessionId}.json`));
|
|
41488
|
+
return true;
|
|
41489
|
+
} catch {
|
|
41490
|
+
return false;
|
|
41491
|
+
}
|
|
41492
|
+
}
|
|
41493
|
+
function cleanupProviderSessionCaptures(state, deps = {}) {
|
|
41494
|
+
for (const operation of state.operations) {
|
|
41495
|
+
if (operation.providerSession) unlinkProviderSessionCapture(operation.sessionId, deps);
|
|
41496
|
+
}
|
|
41497
|
+
}
|
|
41498
|
+
function readTheaterRegistrations(value) {
|
|
41499
|
+
if (!Array.isArray(value)) return [];
|
|
41500
|
+
const registrations = [];
|
|
41501
|
+
for (const item of value) {
|
|
41502
|
+
const registration = sanitizeTheaterRegistration(item);
|
|
41503
|
+
if (registration) registrations.push(registration);
|
|
41504
|
+
}
|
|
41505
|
+
return registrations;
|
|
41506
|
+
}
|
|
41507
|
+
function readDurableOperations(value) {
|
|
41508
|
+
if (!Array.isArray(value)) return [];
|
|
41509
|
+
const operations = [];
|
|
41510
|
+
for (const item of value) {
|
|
41511
|
+
const operation = sanitizeDurableOperation(item);
|
|
41512
|
+
if (operation) operations.push(operation);
|
|
41513
|
+
}
|
|
41514
|
+
return operations;
|
|
41515
|
+
}
|
|
41516
|
+
function sanitizeTheaterRegistration(value) {
|
|
41517
|
+
if (!isRecord4(value)) return null;
|
|
41518
|
+
const id = readNonEmptyString(value.id);
|
|
41519
|
+
const theaterPath = readNonEmptyString(value.path);
|
|
41520
|
+
const realpath = readNonEmptyString(value.realpath);
|
|
41521
|
+
const label = readNonEmptyString(value.label);
|
|
41522
|
+
const registeredAt = readNonEmptyString(value.registeredAt);
|
|
41523
|
+
const lastOpenedAt = readNonEmptyString(value.lastOpenedAt);
|
|
41524
|
+
if (!id || !theaterPath || !realpath || !label || !registeredAt || !lastOpenedAt) return null;
|
|
41525
|
+
return { id, path: theaterPath, realpath, label, registeredAt, lastOpenedAt };
|
|
41526
|
+
}
|
|
41527
|
+
function sanitizeDurableOperation(value) {
|
|
41528
|
+
if (!isRecord4(value)) return null;
|
|
41529
|
+
const sessionId = readNonEmptyString(value.sessionId);
|
|
41530
|
+
const theaterId = readNonEmptyString(value.theaterId);
|
|
41531
|
+
const cwd = readNonEmptyString(value.cwd);
|
|
41532
|
+
const cwdLabel = readNonEmptyString(value.cwdLabel);
|
|
41533
|
+
const sequence = readPositiveInteger(value.sequence);
|
|
41534
|
+
const createdAt = readFiniteNumber(value.createdAt);
|
|
41535
|
+
if (!sessionId || !theaterId || !cwd || !cwdLabel || sequence === null || createdAt === null) return null;
|
|
41536
|
+
const providerSession = sanitizeProviderSession(value.providerSession);
|
|
41537
|
+
return {
|
|
41538
|
+
sessionId,
|
|
41539
|
+
theaterId,
|
|
41540
|
+
cwd,
|
|
41541
|
+
cwdLabel,
|
|
41542
|
+
sequence,
|
|
41543
|
+
...readOptionalString(value.label) ? { label: readOptionalString(value.label) } : {},
|
|
41544
|
+
...readOptionalString(value.cliId) ? { cliId: readOptionalString(value.cliId) } : {},
|
|
41545
|
+
...readOptionalString(value.cliLabel) ? { cliLabel: readOptionalString(value.cliLabel) } : {},
|
|
41546
|
+
createdAt,
|
|
41547
|
+
...providerSession ? { providerSession } : {}
|
|
41548
|
+
};
|
|
41549
|
+
}
|
|
41550
|
+
function sanitizeProviderSession(value) {
|
|
41551
|
+
if (!isRecord4(value)) return null;
|
|
41552
|
+
const provider = value.provider === "claude" || value.provider === "codex" ? value.provider : null;
|
|
41553
|
+
const sessionId = readNonEmptyString(value.sessionId);
|
|
41554
|
+
const capturedAt = readNonEmptyString(value.capturedAt);
|
|
41555
|
+
if (!provider || !sessionId || !capturedAt) return null;
|
|
41556
|
+
return {
|
|
41557
|
+
provider,
|
|
41558
|
+
sessionId,
|
|
41559
|
+
...readOptionalString(value.transcriptPath) ? { transcriptPath: readOptionalString(value.transcriptPath) } : {},
|
|
41560
|
+
...readOptionalString(value.source) ? { source: readOptionalString(value.source) } : {},
|
|
41561
|
+
capturedAt
|
|
41562
|
+
};
|
|
41563
|
+
}
|
|
41564
|
+
function isRecord4(value) {
|
|
41565
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
41566
|
+
}
|
|
41567
|
+
function isSafeCaptureId(value) {
|
|
41568
|
+
return value.length > 0 && path93__default.basename(value) === value && !value.includes(path93__default.sep) && !value.includes(path93__default.posix.sep);
|
|
41569
|
+
}
|
|
41570
|
+
function readNonEmptyString(value) {
|
|
41571
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
41572
|
+
}
|
|
41573
|
+
function readOptionalString(value) {
|
|
41574
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
41575
|
+
}
|
|
41576
|
+
function readPositiveInteger(value) {
|
|
41577
|
+
return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : null;
|
|
41578
|
+
}
|
|
41579
|
+
function readFiniteNumber(value) {
|
|
41580
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
41581
|
+
}
|
|
40892
41582
|
|
|
40893
41583
|
// src/observability-routes.ts
|
|
40894
41584
|
function writeObserverEvents(req, res, workspace, store2) {
|
|
@@ -41099,15 +41789,71 @@ function createConsoleObservabilityStore(deps = {}) {
|
|
|
41099
41789
|
terminalSessionsById.set(state.sessionId, state);
|
|
41100
41790
|
return toTerminalSessionInfo(state);
|
|
41101
41791
|
}
|
|
41792
|
+
function injectDormantOperation(operation) {
|
|
41793
|
+
const currentSequence = terminalSequenceByTheater.get(operation.theaterId) ?? 0;
|
|
41794
|
+
terminalSequenceByTheater.set(operation.theaterId, Math.max(currentSequence, operation.sequence));
|
|
41795
|
+
const state = {
|
|
41796
|
+
sessionId: operation.sessionId,
|
|
41797
|
+
cwd: operation.cwd,
|
|
41798
|
+
canonicalCwd: canonicalizeTheaterPathSync(operation.cwd),
|
|
41799
|
+
cwdLabel: operation.cwdLabel,
|
|
41800
|
+
sequence: operation.sequence,
|
|
41801
|
+
label: operation.label,
|
|
41802
|
+
cliId: operation.cliId,
|
|
41803
|
+
cliLabel: operation.cliLabel,
|
|
41804
|
+
createdAt: operation.createdAt,
|
|
41805
|
+
theaterId: operation.theaterId,
|
|
41806
|
+
terminalSessionId: operation.sessionId,
|
|
41807
|
+
status: "dormant",
|
|
41808
|
+
providerSession: operation.providerSession
|
|
41809
|
+
};
|
|
41810
|
+
terminalSessionsById.set(state.sessionId, state);
|
|
41811
|
+
return toTerminalSessionInfo(state);
|
|
41812
|
+
}
|
|
41102
41813
|
function listTerminalSessions() {
|
|
41103
41814
|
return Array.from(terminalSessionsById.values()).map(toTerminalSessionInfo).sort((a, b) => b.createdAt - a.createdAt);
|
|
41104
41815
|
}
|
|
41816
|
+
function listDurableOperations() {
|
|
41817
|
+
return Array.from(terminalSessionsById.values()).map((session) => ({
|
|
41818
|
+
sessionId: session.sessionId,
|
|
41819
|
+
theaterId: session.theaterId,
|
|
41820
|
+
cwd: session.cwd,
|
|
41821
|
+
cwdLabel: session.cwdLabel,
|
|
41822
|
+
sequence: session.sequence,
|
|
41823
|
+
...session.label ? { label: session.label } : {},
|
|
41824
|
+
...session.cliId ? { cliId: session.cliId } : {},
|
|
41825
|
+
...session.cliLabel ? { cliLabel: session.cliLabel } : {},
|
|
41826
|
+
createdAt: session.createdAt,
|
|
41827
|
+
...session.providerSession ? { providerSession: session.providerSession } : {}
|
|
41828
|
+
}));
|
|
41829
|
+
}
|
|
41830
|
+
function getDurableOperation(sessionId) {
|
|
41831
|
+
return listDurableOperations().find((operation) => operation.sessionId === sessionId) ?? null;
|
|
41832
|
+
}
|
|
41833
|
+
function updateTerminalSessionProviderSession(sessionId, providerSession) {
|
|
41834
|
+
const session = terminalSessionsById.get(sessionId);
|
|
41835
|
+
if (!session) return null;
|
|
41836
|
+
session.providerSession = providerSession;
|
|
41837
|
+
return toTerminalSessionInfo(session);
|
|
41838
|
+
}
|
|
41105
41839
|
function updateTerminalSessionStatus(sessionId, status) {
|
|
41106
41840
|
const session = terminalSessionsById.get(sessionId);
|
|
41107
41841
|
if (!session) return null;
|
|
41108
41842
|
session.status = status;
|
|
41109
41843
|
return toTerminalSessionInfo(session);
|
|
41110
41844
|
}
|
|
41845
|
+
function transitionTerminalSessionToDormant(sessionId, providerSession) {
|
|
41846
|
+
const session = terminalSessionsById.get(sessionId);
|
|
41847
|
+
if (!session) return null;
|
|
41848
|
+
const workspace = workspacesByCliRunId.get(sessionId);
|
|
41849
|
+
if (workspace?.terminalSessionId === sessionId) {
|
|
41850
|
+
removeWorkspaceIndexes(workspace);
|
|
41851
|
+
workspacesByCliRunId.delete(sessionId);
|
|
41852
|
+
}
|
|
41853
|
+
session.status = "dormant";
|
|
41854
|
+
session.providerSession = providerSession;
|
|
41855
|
+
return toTerminalSessionInfo(session);
|
|
41856
|
+
}
|
|
41111
41857
|
function renameTerminalSession(sessionId, rawLabel) {
|
|
41112
41858
|
const session = terminalSessionsById.get(sessionId);
|
|
41113
41859
|
if (!session) return null;
|
|
@@ -41147,18 +41893,23 @@ function createConsoleObservabilityStore(deps = {}) {
|
|
|
41147
41893
|
clear,
|
|
41148
41894
|
getLaunchCwd,
|
|
41149
41895
|
getTruncation,
|
|
41896
|
+
getDurableOperation,
|
|
41150
41897
|
getWorkspace,
|
|
41151
41898
|
listEvents,
|
|
41152
41899
|
listJobs,
|
|
41900
|
+
listDurableOperations,
|
|
41153
41901
|
listTerminalSessions,
|
|
41154
41902
|
listWorkspaces,
|
|
41155
41903
|
appendTerminalRuntimeEvent,
|
|
41156
41904
|
createPendingTerminalSession,
|
|
41905
|
+
injectDormantOperation,
|
|
41157
41906
|
notifySessionUpdated,
|
|
41158
41907
|
renameTerminalSession,
|
|
41159
41908
|
subscribe,
|
|
41160
41909
|
subscribeAll,
|
|
41910
|
+
updateTerminalSessionProviderSession,
|
|
41161
41911
|
updateTerminalSessionStatus,
|
|
41912
|
+
transitionTerminalSessionToDormant,
|
|
41162
41913
|
removeTerminalSession,
|
|
41163
41914
|
registerTerminalRuntimeSession,
|
|
41164
41915
|
workspaceCount: () => listWorkspaces().length
|
|
@@ -41230,7 +41981,8 @@ function toTerminalSessionInfo(state) {
|
|
|
41230
41981
|
theaterId: state.theaterId,
|
|
41231
41982
|
registrationId: state.registrationId,
|
|
41232
41983
|
cliRunId: state.cliRunId,
|
|
41233
|
-
tenantId: state.cliRunId
|
|
41984
|
+
tenantId: state.cliRunId,
|
|
41985
|
+
resumeAvailable: state.providerSession !== void 0
|
|
41234
41986
|
};
|
|
41235
41987
|
}
|
|
41236
41988
|
function pruneTenantJobs(state) {
|
|
@@ -41444,7 +42196,7 @@ function resolveConsolePath(pathname) {
|
|
|
41444
42196
|
var GRANT_ID_BYTES = 24;
|
|
41445
42197
|
var DEFAULT_GRANT_TTL_MS = 6e4;
|
|
41446
42198
|
function createFolderGrantStore(deps = {}) {
|
|
41447
|
-
const randomId = deps.randomId ?? (() =>
|
|
42199
|
+
const randomId = deps.randomId ?? (() => crypto5.randomBytes(GRANT_ID_BYTES).toString("base64url"));
|
|
41448
42200
|
const statSync5 = deps.statSync ?? fs5__default.statSync;
|
|
41449
42201
|
const ttlMs = deps.ttlMs ?? DEFAULT_GRANT_TTL_MS;
|
|
41450
42202
|
const now = deps.now ?? Date.now;
|
|
@@ -41659,6 +42411,31 @@ function buildConsoleHookCommand(entry) {
|
|
|
41659
42411
|
}
|
|
41660
42412
|
throw new Error(`Unsupported Fleet Console session hook entry extension: ${extension}`);
|
|
41661
42413
|
}
|
|
42414
|
+
function buildConsoleCaptureHookCommand(entry, cliId) {
|
|
42415
|
+
const extension = path93__default.extname(entry.entryPath);
|
|
42416
|
+
if (JAVASCRIPT_ENTRY_EXTENSIONS.has(extension)) {
|
|
42417
|
+
return createSessionCaptureHookExec({
|
|
42418
|
+
entryPath: entry.entryPath,
|
|
42419
|
+
execPath: entry.execPath,
|
|
42420
|
+
provider: toCaptureProvider(cliId)
|
|
42421
|
+
});
|
|
42422
|
+
}
|
|
42423
|
+
if (TYPESCRIPT_ENTRY_EXTENSIONS.has(extension)) {
|
|
42424
|
+
if (!entry.tsxLoaderPath) {
|
|
42425
|
+
throw new Error("Fleet Console capture session hook requires a tsx loader path");
|
|
42426
|
+
}
|
|
42427
|
+
return createSessionCaptureHookExec({
|
|
42428
|
+
entryPath: entry.entryPath,
|
|
42429
|
+
execPath: entry.execPath,
|
|
42430
|
+
provider: toCaptureProvider(cliId),
|
|
42431
|
+
tsxLoader: entry.tsxLoaderPath
|
|
42432
|
+
});
|
|
42433
|
+
}
|
|
42434
|
+
throw new Error(`Unsupported Fleet Console session hook entry extension: ${extension}`);
|
|
42435
|
+
}
|
|
42436
|
+
function toCaptureProvider(cliId) {
|
|
42437
|
+
return cliId === "codex" ? "codex" : "claude";
|
|
42438
|
+
}
|
|
41662
42439
|
function runCodexCommand(command2) {
|
|
41663
42440
|
const result = spawnSync(command2.bin, command2.args, {
|
|
41664
42441
|
cwd: command2.cwd,
|
|
@@ -41684,12 +42461,12 @@ var CONSOLE_ENTRY_PATH = fileURLToPath(import.meta.url);
|
|
|
41684
42461
|
var HOOK_ENTRY_EXTENSIONS = /* @__PURE__ */ new Set([".cjs", ".cts", ".js", ".mjs", ".mts", ".ts", ".tsx"]);
|
|
41685
42462
|
var require2 = createRequire(import.meta.url);
|
|
41686
42463
|
function createDefaultTerminalLaunchResolver(deps = {}) {
|
|
41687
|
-
const baseCwd = deps.cwd ??
|
|
41688
|
-
const env = deps.env ??
|
|
41689
|
-
const execPath = deps.execPath ??
|
|
42464
|
+
const baseCwd = deps.cwd ?? process5.cwd();
|
|
42465
|
+
const env = deps.env ?? process5.env;
|
|
42466
|
+
const execPath = deps.execPath ?? process5.execPath;
|
|
41690
42467
|
const homedir3 = deps.homedir ?? DEFAULT_TERMINAL_CWD_FALLBACK;
|
|
41691
|
-
const platform = deps.platform ??
|
|
41692
|
-
const entryPath = resolveHookEntryPath(deps.entryPath ??
|
|
42468
|
+
const platform = deps.platform ?? process5.platform;
|
|
42469
|
+
const entryPath = resolveHookEntryPath(deps.entryPath ?? process5.argv[1]);
|
|
41693
42470
|
const tsxLoaderPath = deps.tsxLoaderPath ?? resolveOptionalPackage("tsx");
|
|
41694
42471
|
const dataDir = deps.dataDir ?? getFleetDataDir();
|
|
41695
42472
|
const infraServices = deps.infraServices ?? createInfraServices();
|
|
@@ -41729,6 +42506,7 @@ function createDefaultTerminalLaunchResolver(deps = {}) {
|
|
|
41729
42506
|
onRuntimeSessionStart: deps.onRuntimeSessionStart,
|
|
41730
42507
|
resolveProfile,
|
|
41731
42508
|
cliId: context?.cliId,
|
|
42509
|
+
resumeSessionId: context?.resumeSessionId,
|
|
41732
42510
|
sessionId
|
|
41733
42511
|
});
|
|
41734
42512
|
};
|
|
@@ -41749,7 +42527,7 @@ function hasHookEntryExtension(entryPath) {
|
|
|
41749
42527
|
}
|
|
41750
42528
|
function startTerminalShell(launch, size) {
|
|
41751
42529
|
const { spawn: spawnPty } = require2("node-pty");
|
|
41752
|
-
const useConptyDll = resolveUseConptyDll(
|
|
42530
|
+
const useConptyDll = resolveUseConptyDll(process5.platform, process5.env);
|
|
41753
42531
|
return spawnPty(launch.bin, [...launch.args], {
|
|
41754
42532
|
cols: size.cols,
|
|
41755
42533
|
rows: size.rows,
|
|
@@ -41774,7 +42552,8 @@ async function createAgentCliLaunchSpec(options) {
|
|
|
41774
42552
|
const profile = await options.resolveProfile(options.env, options.cwd, {
|
|
41775
42553
|
authEnvResolver: options.authEnvResolver,
|
|
41776
42554
|
authService: options.infraServices.authService,
|
|
41777
|
-
cliId: options.cliId
|
|
42555
|
+
cliId: options.cliId,
|
|
42556
|
+
resumeSessionId: options.resumeSessionId
|
|
41778
42557
|
});
|
|
41779
42558
|
const injectedProfile = await options.injectProfile(profile, {
|
|
41780
42559
|
buildSystemPrompt: (injectTone) => createSystemPromptBuilder({ carrierRuntime: agentRuntime.carrierRuntime }).build(injectTone),
|
|
@@ -41783,9 +42562,11 @@ async function createAgentCliLaunchSpec(options) {
|
|
|
41783
42562
|
dataDir: options.dataDir,
|
|
41784
42563
|
dedicatedMcpSession: agentRuntime.dedicatedMcpSession,
|
|
41785
42564
|
enableMetaphor: false,
|
|
42565
|
+
captureSessionHookExec: buildConsoleCaptureHookCommand(options.hookEntry, profile.id),
|
|
41786
42566
|
hookExec: buildConsoleHookCommand(options.hookEntry),
|
|
41787
42567
|
onCleanup: (cleanup) => cleanupStack.push(cleanup),
|
|
41788
|
-
replaceSystemPrompt:
|
|
42568
|
+
replaceSystemPrompt: false,
|
|
42569
|
+
resumeSessionId: options.resumeSessionId,
|
|
41789
42570
|
withMarketplaceLock: withConsoleMarketplaceLock,
|
|
41790
42571
|
mcpSessionLabel: options.sessionId
|
|
41791
42572
|
});
|
|
@@ -41819,6 +42600,7 @@ function toLaunchSpec(profile, cleanup) {
|
|
|
41819
42600
|
cwd: profile.cwd,
|
|
41820
42601
|
env: { ...profile.env },
|
|
41821
42602
|
messagePolicy: profile.messagePolicy,
|
|
42603
|
+
renameCommand: profile.renameCommand,
|
|
41822
42604
|
terminalName: profile.terminalName
|
|
41823
42605
|
};
|
|
41824
42606
|
}
|
|
@@ -41912,6 +42694,9 @@ function createTerminalSessionManager(deps) {
|
|
|
41912
42694
|
function getSessionMessagePolicy(sessionId) {
|
|
41913
42695
|
return sessions.get(sessionId)?.messagePolicy;
|
|
41914
42696
|
}
|
|
42697
|
+
function getSessionRenameCommand(sessionId) {
|
|
42698
|
+
return sessions.get(sessionId)?.renameCommand;
|
|
42699
|
+
}
|
|
41915
42700
|
function writeToSession(sessionId, data) {
|
|
41916
42701
|
const session = sessions.get(sessionId);
|
|
41917
42702
|
if (!session || typeof session.pty.write !== "function") return false;
|
|
@@ -41949,7 +42734,7 @@ function createTerminalSessionManager(deps) {
|
|
|
41949
42734
|
}
|
|
41950
42735
|
}
|
|
41951
42736
|
async function launchSession(context) {
|
|
41952
|
-
const launch = await deps.launch(context.cwd, { sessionId: context.sessionId, kind: context.kind, cliId: context.cliId });
|
|
42737
|
+
const launch = await deps.launch(context.cwd, { sessionId: context.sessionId, kind: context.kind, cliId: context.cliId, resumeSessionId: context.resumeSessionId });
|
|
41953
42738
|
let pty;
|
|
41954
42739
|
try {
|
|
41955
42740
|
pty = startShell(launch, { cols: DEFAULT_COLS, rows: DEFAULT_ROWS });
|
|
@@ -41964,6 +42749,7 @@ function createTerminalSessionManager(deps) {
|
|
|
41964
42749
|
scrollback: [],
|
|
41965
42750
|
cleanup: launch.cleanup,
|
|
41966
42751
|
messagePolicy: launch.messagePolicy,
|
|
42752
|
+
renameCommand: launch.renameCommand,
|
|
41967
42753
|
activeSocket: null,
|
|
41968
42754
|
cols: DEFAULT_COLS,
|
|
41969
42755
|
rows: DEFAULT_ROWS
|
|
@@ -42028,7 +42814,7 @@ function createTerminalSessionManager(deps) {
|
|
|
42028
42814
|
await runLaunchCleanup(session.cleanup);
|
|
42029
42815
|
}
|
|
42030
42816
|
}
|
|
42031
|
-
return { canAttach, createSession, attach, getSessionMessagePolicy, terminate, stop, writeToSession };
|
|
42817
|
+
return { canAttach, createSession, attach, getSessionMessagePolicy, getSessionRenameCommand, terminate, stop, writeToSession };
|
|
42032
42818
|
}
|
|
42033
42819
|
async function runLaunchCleanup(cleanup) {
|
|
42034
42820
|
try {
|
|
@@ -42058,7 +42844,7 @@ var DEFAULT_TICKET_TTL_MS = 1e4;
|
|
|
42058
42844
|
function createTerminalTicketRegistry(deps = {}) {
|
|
42059
42845
|
const ttlMs = deps.ttlMs ?? DEFAULT_TICKET_TTL_MS;
|
|
42060
42846
|
const now = deps.now ?? Date.now;
|
|
42061
|
-
const randomTicket = deps.randomTicket ?? (() =>
|
|
42847
|
+
const randomTicket = deps.randomTicket ?? (() => crypto5.randomBytes(32).toString("base64url"));
|
|
42062
42848
|
const tickets = /* @__PURE__ */ new Map();
|
|
42063
42849
|
function issue3(context) {
|
|
42064
42850
|
prune();
|
|
@@ -42246,6 +43032,26 @@ var TheaterRegistry = class {
|
|
|
42246
43032
|
this.#mruId = id;
|
|
42247
43033
|
return item;
|
|
42248
43034
|
}
|
|
43035
|
+
load(items) {
|
|
43036
|
+
this.restore(items);
|
|
43037
|
+
}
|
|
43038
|
+
restore(items) {
|
|
43039
|
+
const restored = /* @__PURE__ */ new Map();
|
|
43040
|
+
let mruId = null;
|
|
43041
|
+
for (const item of items) {
|
|
43042
|
+
const existing = restored.get(item.id);
|
|
43043
|
+
if (existing && existing.realpath !== item.realpath) {
|
|
43044
|
+
throw new Error("theater_id_collision");
|
|
43045
|
+
}
|
|
43046
|
+
restored.set(item.id, item);
|
|
43047
|
+
if (!mruId || item.lastOpenedAt.localeCompare(restored.get(mruId)?.lastOpenedAt ?? "") > 0) {
|
|
43048
|
+
mruId = item.id;
|
|
43049
|
+
}
|
|
43050
|
+
}
|
|
43051
|
+
this.#items.clear();
|
|
43052
|
+
for (const [id, item] of restored) this.#items.set(id, item);
|
|
43053
|
+
this.#mruId = mruId;
|
|
43054
|
+
}
|
|
42249
43055
|
get(id) {
|
|
42250
43056
|
return this.#items.get(id) ?? null;
|
|
42251
43057
|
}
|
|
@@ -42255,6 +43061,11 @@ var TheaterRegistry = class {
|
|
|
42255
43061
|
list() {
|
|
42256
43062
|
return [...this.#items.values()].sort((left, right) => right.lastOpenedAt.localeCompare(left.lastOpenedAt));
|
|
42257
43063
|
}
|
|
43064
|
+
remove(id) {
|
|
43065
|
+
const removed = this.#items.delete(id);
|
|
43066
|
+
if (this.#mruId === id) this.#mruId = this.list()[0]?.id ?? null;
|
|
43067
|
+
return removed;
|
|
43068
|
+
}
|
|
42258
43069
|
};
|
|
42259
43070
|
|
|
42260
43071
|
// src/update-check.ts
|
|
@@ -42331,6 +43142,9 @@ function createConsoleServer(deps = {}) {
|
|
|
42331
43142
|
const folderGrants = createFolderGrantStore();
|
|
42332
43143
|
const infraServices = createInfraServices();
|
|
42333
43144
|
const dataDir = deps.dataDir ?? getFleetDataDir();
|
|
43145
|
+
initStore(dataDir);
|
|
43146
|
+
const durablePaths = createConsoleDataPaths({ fleetDataDir: dataDir });
|
|
43147
|
+
const durableStateStore = createConsoleDurableStateStore({ paths: durablePaths });
|
|
42334
43148
|
const authEnvResolver = (cli) => resolveAuthEnv(cli, { authService: infraServices.authService });
|
|
42335
43149
|
const ownsAgentRuntime = deps.agentRuntime === void 0;
|
|
42336
43150
|
const agentRuntime = deps.agentRuntime ?? createFleetAgentRuntimeLifecycle({
|
|
@@ -42369,10 +43183,18 @@ function createConsoleServer(deps = {}) {
|
|
|
42369
43183
|
}),
|
|
42370
43184
|
startShell: deps.terminalStartShell,
|
|
42371
43185
|
maxSessions: deps.maxTerminalSessions,
|
|
42372
|
-
// PTY가 종료되면 콘솔 세션 목록에서도 제거해 잔존/재실행을 막는다.
|
|
42373
43186
|
onSessionExit: (sessionId) => {
|
|
42374
43187
|
pendingRuntimeSessions.delete(sessionId);
|
|
42375
|
-
observability.
|
|
43188
|
+
const operation = observability.getDurableOperation(sessionId);
|
|
43189
|
+
const providerSession = operation?.providerSession ?? readProviderSessionCapture(sessionId, { capturesDir: durablePaths.capturesDir });
|
|
43190
|
+
if (providerSession) {
|
|
43191
|
+
observability.updateTerminalSessionProviderSession(sessionId, providerSession);
|
|
43192
|
+
const dormant = observability.transitionTerminalSessionToDormant(sessionId, providerSession);
|
|
43193
|
+
if (dormant) observability.notifySessionUpdated(dormant);
|
|
43194
|
+
} else {
|
|
43195
|
+
observability.removeTerminalSession(sessionId);
|
|
43196
|
+
}
|
|
43197
|
+
persistDurableState();
|
|
42376
43198
|
}
|
|
42377
43199
|
});
|
|
42378
43200
|
const unsubscribeCarrierReminderRouter = createCarrierResultReminderRouter({
|
|
@@ -42404,6 +43226,12 @@ function createConsoleServer(deps = {}) {
|
|
|
42404
43226
|
let activeEndpoint = null;
|
|
42405
43227
|
let agentRuntimeStopped = false;
|
|
42406
43228
|
let consoleResourcesDisposed = false;
|
|
43229
|
+
const carrierSettingsRouter = createCarrierSettingsRouter({
|
|
43230
|
+
registry: carrierRegistry,
|
|
43231
|
+
isAuthorized: isTerminalAuthorized,
|
|
43232
|
+
readJsonBody,
|
|
43233
|
+
writeJson
|
|
43234
|
+
});
|
|
42407
43235
|
function handleRequest(req, res) {
|
|
42408
43236
|
const pathname = getPathname(req);
|
|
42409
43237
|
if (pathname === "/console/codex" || pathname.startsWith("/console/codex/")) {
|
|
@@ -42431,6 +43259,11 @@ function createConsoleServer(deps = {}) {
|
|
|
42431
43259
|
runAsyncHandler(handleTerminalSessions(req, res), res);
|
|
42432
43260
|
return;
|
|
42433
43261
|
}
|
|
43262
|
+
const terminalSessionResumeMatch = pathname.match(/^\/terminal\/sessions\/([^/]+)\/resume$/);
|
|
43263
|
+
if (terminalSessionResumeMatch) {
|
|
43264
|
+
runAsyncHandler(handleTerminalSessionResume(req, res, decodeURIComponent(terminalSessionResumeMatch[1] ?? "")), res);
|
|
43265
|
+
return;
|
|
43266
|
+
}
|
|
42434
43267
|
const terminalSessionItemMatch = pathname.match(/^\/terminal\/sessions\/([^/]+)$/);
|
|
42435
43268
|
if (terminalSessionItemMatch) {
|
|
42436
43269
|
runAsyncHandler(handleTerminalSessionItem(req, res, decodeURIComponent(terminalSessionItemMatch[1] ?? "")), res);
|
|
@@ -42440,6 +43273,11 @@ function createConsoleServer(deps = {}) {
|
|
|
42440
43273
|
runAsyncHandler(handleObserverTheaters(req, res), res);
|
|
42441
43274
|
return;
|
|
42442
43275
|
}
|
|
43276
|
+
const theaterItemMatch = pathname.match(/^\/observer\/theaters\/([^/]+)$/);
|
|
43277
|
+
if (theaterItemMatch) {
|
|
43278
|
+
runAsyncHandler(handleObserverTheaterItem(req, res, decodeURIComponent(theaterItemMatch[1] ?? "")), res);
|
|
43279
|
+
return;
|
|
43280
|
+
}
|
|
42443
43281
|
const theaterSessionMatch = pathname.match(/^\/observer\/theaters\/([^/]+)\/sessions$/);
|
|
42444
43282
|
if (theaterSessionMatch) {
|
|
42445
43283
|
runAsyncHandler(handleObserverTheaterSessions(req, res, decodeURIComponent(theaterSessionMatch[1] ?? "")), res);
|
|
@@ -42453,6 +43291,10 @@ function createConsoleServer(deps = {}) {
|
|
|
42453
43291
|
handleObserverCarriers(req, res);
|
|
42454
43292
|
return;
|
|
42455
43293
|
}
|
|
43294
|
+
if (pathname === "/carrier-settings" || pathname.startsWith("/carrier-settings/")) {
|
|
43295
|
+
runAsyncBooleanHandler(carrierSettingsRouter({ req, res, pathname }), res);
|
|
43296
|
+
return;
|
|
43297
|
+
}
|
|
42456
43298
|
if (pathname === "/observer/tenants") {
|
|
42457
43299
|
handleObserverWorkspaces(req, res);
|
|
42458
43300
|
return;
|
|
@@ -42571,6 +43413,17 @@ function createConsoleServer(deps = {}) {
|
|
|
42571
43413
|
}
|
|
42572
43414
|
await createTerminalSessionForCwd(cwd, res, cliId);
|
|
42573
43415
|
}
|
|
43416
|
+
function injectRenameCommand(sessionId, label) {
|
|
43417
|
+
if (!label) return;
|
|
43418
|
+
const renameCommand = terminalSessions.getSessionRenameCommand(sessionId);
|
|
43419
|
+
if (!renameCommand) return;
|
|
43420
|
+
const safeLabel = sanitizeCarrierResultReminder(label.replace(/[\r\n\t]+/g, " ")).trim();
|
|
43421
|
+
if (safeLabel.length === 0) return;
|
|
43422
|
+
const policy = terminalSessions.getSessionMessagePolicy(sessionId) ?? {};
|
|
43423
|
+
for (const chunk of formatCarrierResultReminderMessage(policy, `${renameCommand} ${safeLabel}`)) {
|
|
43424
|
+
terminalSessions.writeToSession(sessionId, chunk);
|
|
43425
|
+
}
|
|
43426
|
+
}
|
|
42574
43427
|
async function handleTerminalSessionItem(req, res, sessionId) {
|
|
42575
43428
|
if (req.method !== "DELETE" && req.method !== "PATCH") {
|
|
42576
43429
|
writeJson(res, 405, { error: "Method not allowed" });
|
|
@@ -42592,13 +43445,62 @@ function createConsoleServer(deps = {}) {
|
|
|
42592
43445
|
return;
|
|
42593
43446
|
}
|
|
42594
43447
|
observability.notifySessionUpdated(updated);
|
|
43448
|
+
injectRenameCommand(sessionId, updated.label);
|
|
43449
|
+
persistDurableState();
|
|
42595
43450
|
writeJson(res, 200, updated);
|
|
42596
43451
|
return;
|
|
42597
43452
|
}
|
|
42598
|
-
|
|
42599
|
-
observability.removeTerminalSession(sessionId);
|
|
43453
|
+
forgetTerminalSession(sessionId);
|
|
42600
43454
|
writeJson(res, 200, { ok: true });
|
|
42601
43455
|
}
|
|
43456
|
+
async function handleTerminalSessionResume(req, res, sessionId) {
|
|
43457
|
+
if (req.method !== "POST") {
|
|
43458
|
+
writeJson(res, 405, { error: "Method not allowed" });
|
|
43459
|
+
return;
|
|
43460
|
+
}
|
|
43461
|
+
if (!isTerminalAuthorized(req)) {
|
|
43462
|
+
writeJson(res, 401, { error: "unauthorized" });
|
|
43463
|
+
return;
|
|
43464
|
+
}
|
|
43465
|
+
const dormantSession = observability.listTerminalSessions().find((session) => session.sessionId === sessionId && session.status === "dormant");
|
|
43466
|
+
const operation = dormantSession ? observability.getDurableOperation(sessionId) : null;
|
|
43467
|
+
if (!operation) {
|
|
43468
|
+
writeJson(res, 404, { error: "session_not_found" });
|
|
43469
|
+
return;
|
|
43470
|
+
}
|
|
43471
|
+
const cliId = readDurableAgentCliId(operation);
|
|
43472
|
+
if (!cliId) {
|
|
43473
|
+
writeJson(res, 409, { error: "resume_unavailable" });
|
|
43474
|
+
return;
|
|
43475
|
+
}
|
|
43476
|
+
const providerSession = operation.providerSession ?? readProviderSessionCapture(sessionId, { capturesDir: durablePaths.capturesDir });
|
|
43477
|
+
if (!providerSession) {
|
|
43478
|
+
writeJson(res, 409, { error: "resume_unavailable" });
|
|
43479
|
+
return;
|
|
43480
|
+
}
|
|
43481
|
+
observability.updateTerminalSessionProviderSession(sessionId, providerSession);
|
|
43482
|
+
const starting = observability.updateTerminalSessionStatus(sessionId, "starting");
|
|
43483
|
+
if (starting) observability.notifySessionUpdated(starting);
|
|
43484
|
+
try {
|
|
43485
|
+
await terminalSessions.createSession({ sessionId, cwd: operation.cwd, cliId, resumeSessionId: providerSession.sessionId });
|
|
43486
|
+
const runtimeSession = pendingRuntimeSessions.get(sessionId);
|
|
43487
|
+
pendingRuntimeSessions.delete(sessionId);
|
|
43488
|
+
const resumed = runtimeSession ? observability.registerTerminalRuntimeSession(runtimeSession) ?? starting : observability.updateTerminalSessionStatus(sessionId, "terminal-only") ?? starting;
|
|
43489
|
+
if (!resumed) {
|
|
43490
|
+
writeJson(res, 404, { error: "session_not_found" });
|
|
43491
|
+
return;
|
|
43492
|
+
}
|
|
43493
|
+
observability.notifySessionUpdated(resumed);
|
|
43494
|
+
persistDurableState();
|
|
43495
|
+
writeJson(res, 200, resumed);
|
|
43496
|
+
} catch {
|
|
43497
|
+
pendingRuntimeSessions.delete(sessionId);
|
|
43498
|
+
const reverted = observability.updateTerminalSessionStatus(sessionId, "dormant");
|
|
43499
|
+
if (reverted) observability.notifySessionUpdated(reverted);
|
|
43500
|
+
persistDurableState();
|
|
43501
|
+
writeJson(res, 503, { error: "terminal_unavailable" });
|
|
43502
|
+
}
|
|
43503
|
+
}
|
|
42602
43504
|
async function handleObserverTheaters(req, res) {
|
|
42603
43505
|
if (req.method === "GET") {
|
|
42604
43506
|
writeJson(res, 200, { theaters: listTheaterInfos(), agentClis: getAgentCliMetadata() });
|
|
@@ -42631,8 +43533,28 @@ function createConsoleServer(deps = {}) {
|
|
|
42631
43533
|
console.warn(`[fleet-console] Codex workspace registration skipped for Theater ${theater.id}: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
42632
43534
|
}
|
|
42633
43535
|
}
|
|
43536
|
+
persistDurableState();
|
|
42634
43537
|
writeJson(res, 200, toTheaterInfo(theater, hasWiki));
|
|
42635
43538
|
}
|
|
43539
|
+
async function handleObserverTheaterItem(req, res, theaterId) {
|
|
43540
|
+
if (req.method !== "DELETE") {
|
|
43541
|
+
writeJson(res, 405, { error: "Method not allowed" });
|
|
43542
|
+
return;
|
|
43543
|
+
}
|
|
43544
|
+
if (!isTerminalAuthorized(req)) {
|
|
43545
|
+
writeJson(res, 401, { error: "unauthorized" });
|
|
43546
|
+
return;
|
|
43547
|
+
}
|
|
43548
|
+
const operations = observability.listDurableOperations().filter((operation) => operation.theaterId === theaterId);
|
|
43549
|
+
const removed = theaters.remove(theaterId);
|
|
43550
|
+
if (!removed) {
|
|
43551
|
+
writeJson(res, 404, { error: "theater_not_found" });
|
|
43552
|
+
return;
|
|
43553
|
+
}
|
|
43554
|
+
for (const operation of operations) forgetTerminalSession(operation.sessionId, { persist: false });
|
|
43555
|
+
persistDurableState();
|
|
43556
|
+
writeJson(res, 200, { ok: true });
|
|
43557
|
+
}
|
|
42636
43558
|
async function handleObserverTheaterSessions(req, res, theaterId) {
|
|
42637
43559
|
if (req.method !== "POST") {
|
|
42638
43560
|
writeJson(res, 405, { error: "Method not allowed" });
|
|
@@ -42653,7 +43575,7 @@ function createConsoleServer(deps = {}) {
|
|
|
42653
43575
|
await createTerminalSessionForCwd(theater.path, res, cliId);
|
|
42654
43576
|
}
|
|
42655
43577
|
async function createTerminalSessionForCwd(cwd, res, cliId) {
|
|
42656
|
-
const sessionId =
|
|
43578
|
+
const sessionId = crypto5.randomUUID();
|
|
42657
43579
|
const session = observability.createPendingTerminalSession({ sessionId, cwd, cliId });
|
|
42658
43580
|
try {
|
|
42659
43581
|
await terminalSessions.createSession({ sessionId, cwd, cliId });
|
|
@@ -42661,6 +43583,7 @@ function createConsoleServer(deps = {}) {
|
|
|
42661
43583
|
pendingRuntimeSessions.delete(sessionId);
|
|
42662
43584
|
const created = runtimeSession ? observability.registerTerminalRuntimeSession(runtimeSession) ?? session : observability.updateTerminalSessionStatus(sessionId, "terminal-only") ?? session;
|
|
42663
43585
|
observability.notifySessionUpdated(created);
|
|
43586
|
+
persistDurableState();
|
|
42664
43587
|
writeJson(res, 200, created);
|
|
42665
43588
|
} catch (error51) {
|
|
42666
43589
|
pendingRuntimeSessions.delete(sessionId);
|
|
@@ -42734,6 +43657,13 @@ function createConsoleServer(deps = {}) {
|
|
|
42734
43657
|
function listTheaterInfos() {
|
|
42735
43658
|
return theaters.list().map((theater) => toTheaterInfo(theater, codex.getWorkspace(theater.id) !== null));
|
|
42736
43659
|
}
|
|
43660
|
+
function forgetTerminalSession(sessionId, options = {}) {
|
|
43661
|
+
terminalSessions.terminate(sessionId);
|
|
43662
|
+
pendingRuntimeSessions.delete(sessionId);
|
|
43663
|
+
observability.removeTerminalSession(sessionId);
|
|
43664
|
+
unlinkProviderSessionCapture(sessionId, { capturesDir: durablePaths.capturesDir });
|
|
43665
|
+
if (options.persist !== false) persistDurableState();
|
|
43666
|
+
}
|
|
42737
43667
|
function toTheaterInfo(theater, hasWiki) {
|
|
42738
43668
|
return {
|
|
42739
43669
|
id: theater.id,
|
|
@@ -42796,12 +43726,69 @@ function createConsoleServer(deps = {}) {
|
|
|
42796
43726
|
terminalUpgrade.close();
|
|
42797
43727
|
currentLock?.release();
|
|
42798
43728
|
}
|
|
43729
|
+
function rehydrateDurableState() {
|
|
43730
|
+
let state;
|
|
43731
|
+
try {
|
|
43732
|
+
state = durableStateStore.load();
|
|
43733
|
+
theaters.restore(state.theaters);
|
|
43734
|
+
} catch (error51) {
|
|
43735
|
+
console.warn(`[fleet-console] Durable state restore skipped: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
43736
|
+
state = emptyDurableConsoleState();
|
|
43737
|
+
theaters.restore([]);
|
|
43738
|
+
}
|
|
43739
|
+
const merged = mergeProviderSessionCaptures(state, { capturesDir: durablePaths.capturesDir });
|
|
43740
|
+
syncProviderSessionsToObservability(merged);
|
|
43741
|
+
const restorable = {
|
|
43742
|
+
...merged,
|
|
43743
|
+
operations: merged.operations.filter((operation) => operation.providerSession)
|
|
43744
|
+
};
|
|
43745
|
+
if (merged !== state || restorable.operations.length !== merged.operations.length) {
|
|
43746
|
+
try {
|
|
43747
|
+
durableStateStore.save(restorable);
|
|
43748
|
+
cleanupProviderSessionCaptures(restorable, { capturesDir: durablePaths.capturesDir });
|
|
43749
|
+
} catch (error51) {
|
|
43750
|
+
console.warn(`[fleet-console] Durable state capture merge was not persisted: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
43751
|
+
}
|
|
43752
|
+
} else {
|
|
43753
|
+
cleanupProviderSessionCaptures(restorable, { capturesDir: durablePaths.capturesDir });
|
|
43754
|
+
}
|
|
43755
|
+
for (const operation of restorable.operations) {
|
|
43756
|
+
if (theaters.get(operation.theaterId)) observability.injectDormantOperation(operation);
|
|
43757
|
+
}
|
|
43758
|
+
}
|
|
43759
|
+
function persistDurableState() {
|
|
43760
|
+
try {
|
|
43761
|
+
const state = mergeProviderSessionCaptures({
|
|
43762
|
+
version: 1,
|
|
43763
|
+
theaters: theaters.list(),
|
|
43764
|
+
operations: observability.listDurableOperations()
|
|
43765
|
+
}, { capturesDir: durablePaths.capturesDir });
|
|
43766
|
+
syncProviderSessionsToObservability(state);
|
|
43767
|
+
const operationsWithProviderSession = state.operations.filter((operation) => operation.providerSession);
|
|
43768
|
+
durableStateStore.save({
|
|
43769
|
+
version: state.version,
|
|
43770
|
+
theaters: state.theaters,
|
|
43771
|
+
// 대화 없는 빈 Operation 드롭은 rehydrate에서 capture 머지 뒤에만 수행한다.
|
|
43772
|
+
// create 시점의 메타데이터를 먼저 남겨야 이후 도착한 capture 파일이 재시작 때 병합될 수 있다.
|
|
43773
|
+
operations: state.operations
|
|
43774
|
+
});
|
|
43775
|
+
cleanupProviderSessionCaptures({ ...state, operations: operationsWithProviderSession }, { capturesDir: durablePaths.capturesDir });
|
|
43776
|
+
} catch (error51) {
|
|
43777
|
+
console.warn(`[fleet-console] Durable state save failed: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
43778
|
+
}
|
|
43779
|
+
}
|
|
43780
|
+
function syncProviderSessionsToObservability(state) {
|
|
43781
|
+
for (const operation of state.operations) {
|
|
43782
|
+
if (operation.providerSession) observability.updateTerminalSessionProviderSession(operation.sessionId, operation.providerSession);
|
|
43783
|
+
}
|
|
43784
|
+
}
|
|
42799
43785
|
return {
|
|
42800
43786
|
host,
|
|
42801
43787
|
port,
|
|
42802
43788
|
async start(lockPaths) {
|
|
42803
43789
|
if (server && lockHandle) return lockHandle.payload.endpoint;
|
|
42804
43790
|
try {
|
|
43791
|
+
rehydrateDurableState();
|
|
42805
43792
|
await new Promise((resolve, reject) => {
|
|
42806
43793
|
const srv = createHttpServer(handleRequest, terminalUpgrade);
|
|
42807
43794
|
srv.once("error", reject);
|
|
@@ -42884,6 +43871,14 @@ function resolveCarrierEventOrigin(event, jobOriginById) {
|
|
|
42884
43871
|
function queueOriginCleanup(jobId, jobOriginById) {
|
|
42885
43872
|
queueMicrotask(() => jobOriginById.delete(jobId));
|
|
42886
43873
|
}
|
|
43874
|
+
function readDurableAgentCliId(operation) {
|
|
43875
|
+
if (!operation.cliId) return null;
|
|
43876
|
+
try {
|
|
43877
|
+
return parseAgentCliId(operation.cliId) ?? null;
|
|
43878
|
+
} catch {
|
|
43879
|
+
return null;
|
|
43880
|
+
}
|
|
43881
|
+
}
|
|
42887
43882
|
function createHttpServer(handler, terminalUpgrade) {
|
|
42888
43883
|
const srv = http.createServer(handler);
|
|
42889
43884
|
srv.timeout = SERVER_TIMEOUT_MS;
|
|
@@ -43001,6 +43996,78 @@ function isAllowedTerminalOrigin(req, expectedPort) {
|
|
|
43001
43996
|
if (origin === void 0) return true;
|
|
43002
43997
|
return origin === `http://127.0.0.1:${expectedPort}`;
|
|
43003
43998
|
}
|
|
43999
|
+
var CAPTURE_TEMP_PREFIX = ".capture.";
|
|
44000
|
+
async function runCaptureSessionHook(provider, env = process5.env) {
|
|
44001
|
+
return captureSession({
|
|
44002
|
+
diagnostics: process5.stderr,
|
|
44003
|
+
env,
|
|
44004
|
+
input: await readStdin(),
|
|
44005
|
+
provider
|
|
44006
|
+
});
|
|
44007
|
+
}
|
|
44008
|
+
function captureSession(options) {
|
|
44009
|
+
try {
|
|
44010
|
+
return captureSessionStrict(options);
|
|
44011
|
+
} catch (error51) {
|
|
44012
|
+
options.diagnostics?.write(`[fleet-console] capture-session skipped: ${error51 instanceof Error ? error51.message : String(error51)}
|
|
44013
|
+
`);
|
|
44014
|
+
return null;
|
|
44015
|
+
}
|
|
44016
|
+
}
|
|
44017
|
+
function captureSessionStrict(options) {
|
|
44018
|
+
const provider = parseProvider(options.provider);
|
|
44019
|
+
const fleetSessionId = readFleetSessionId(options.env ?? process5.env);
|
|
44020
|
+
const input = parseHookInput(options.input ?? "");
|
|
44021
|
+
const providerSession = toProviderSession(provider, input, options.now ?? (() => /* @__PURE__ */ new Date()));
|
|
44022
|
+
const capturesDir = (options.paths ?? createConsoleDataPaths()).capturesDir;
|
|
44023
|
+
const finalPath = path93__default.join(capturesDir, `${fleetSessionId}.json`);
|
|
44024
|
+
const tempPath = path93__default.join(capturesDir, `${CAPTURE_TEMP_PREFIX}${fleetSessionId}.${process5.pid}.${Date.now()}.tmp`);
|
|
44025
|
+
fs5__default.mkdirSync(capturesDir, { recursive: true, mode: 448 });
|
|
44026
|
+
fs5__default.writeFileSync(tempPath, `${JSON.stringify(providerSession, null, 2)}
|
|
44027
|
+
`, { mode: 384 });
|
|
44028
|
+
fs5__default.renameSync(tempPath, finalPath);
|
|
44029
|
+
return { path: finalPath, providerSession };
|
|
44030
|
+
}
|
|
44031
|
+
function parseProvider(value) {
|
|
44032
|
+
if (value === "claude" || value === "codex") return value;
|
|
44033
|
+
throw new Error("invalid_provider");
|
|
44034
|
+
}
|
|
44035
|
+
function readFleetSessionId(env) {
|
|
44036
|
+
const value = env.FLEET_CONSOLE_SESSION_ID;
|
|
44037
|
+
if (!value) throw new Error("missing_fleet_session_id");
|
|
44038
|
+
if (path93__default.basename(value) !== value || value.includes(path93__default.sep) || value.includes(path93__default.posix.sep)) {
|
|
44039
|
+
throw new Error("invalid_fleet_session_id");
|
|
44040
|
+
}
|
|
44041
|
+
return value;
|
|
44042
|
+
}
|
|
44043
|
+
function parseHookInput(input) {
|
|
44044
|
+
try {
|
|
44045
|
+
const parsed = JSON.parse(input);
|
|
44046
|
+
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) return parsed;
|
|
44047
|
+
} catch {
|
|
44048
|
+
}
|
|
44049
|
+
throw new Error("invalid_hook_input");
|
|
44050
|
+
}
|
|
44051
|
+
function toProviderSession(provider, input, now) {
|
|
44052
|
+
if (typeof input.session_id !== "string" || input.session_id.length === 0) throw new Error("missing_provider_session_id");
|
|
44053
|
+
return {
|
|
44054
|
+
provider,
|
|
44055
|
+
sessionId: input.session_id,
|
|
44056
|
+
...typeof input.transcript_path === "string" && input.transcript_path.length > 0 ? { transcriptPath: input.transcript_path } : {},
|
|
44057
|
+
...typeof input.source === "string" && input.source.length > 0 ? { source: input.source } : {},
|
|
44058
|
+
capturedAt: now().toISOString()
|
|
44059
|
+
};
|
|
44060
|
+
}
|
|
44061
|
+
function readStdin() {
|
|
44062
|
+
return new Promise((resolve, reject) => {
|
|
44063
|
+
const chunks = [];
|
|
44064
|
+
process5.stdin.on("data", (chunk) => {
|
|
44065
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
44066
|
+
});
|
|
44067
|
+
process5.stdin.on("error", reject);
|
|
44068
|
+
process5.stdin.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
|
|
44069
|
+
});
|
|
44070
|
+
}
|
|
43004
44071
|
function createConsoleStalePolicy(deps = {}) {
|
|
43005
44072
|
const fsImpl = deps.fs ?? fs5__default;
|
|
43006
44073
|
function isBuildStale(lock, buildFile) {
|
|
@@ -43018,7 +44085,7 @@ function createConsoleStalePolicy(deps = {}) {
|
|
|
43018
44085
|
var FIXED_HOST = "127.0.0.1";
|
|
43019
44086
|
var HELP_BANNER_INDENT = " ";
|
|
43020
44087
|
var DEFAULT_HELP_RELEASE = "local";
|
|
43021
|
-
var CONSOLE_HOOK_COMMANDS = /* @__PURE__ */ new Set(["subagents-context"]);
|
|
44088
|
+
var CONSOLE_HOOK_COMMANDS = /* @__PURE__ */ new Set(["capture-session", "subagents-context"]);
|
|
43022
44089
|
function parseConsoleCliMode(argv) {
|
|
43023
44090
|
if (argv.length === 0) return "start";
|
|
43024
44091
|
const [first, ...rest] = argv;
|
|
@@ -43045,10 +44112,12 @@ Run 'fleet console --help' for usage.`);
|
|
|
43045
44112
|
}
|
|
43046
44113
|
function parseConsoleHookCommand(argv) {
|
|
43047
44114
|
const [commandName, ...rest] = argv;
|
|
43048
|
-
if (!commandName || !CONSOLE_HOOK_COMMANDS.has(commandName)
|
|
44115
|
+
if (!commandName || !CONSOLE_HOOK_COMMANDS.has(commandName)) {
|
|
43049
44116
|
throw new Error("Unknown fleet-console hook command");
|
|
43050
44117
|
}
|
|
43051
|
-
return "subagents-context";
|
|
44118
|
+
if (commandName === "subagents-context" && rest.length === 0) return { command: "subagents-context" };
|
|
44119
|
+
if (commandName === "capture-session" && rest.length === 1 && rest[0]) return { command: "capture-session", provider: rest[0] };
|
|
44120
|
+
throw new Error("Unknown fleet-console hook command");
|
|
43052
44121
|
}
|
|
43053
44122
|
function buildConsoleHelpText(options = {}) {
|
|
43054
44123
|
const colorEnabled = resolveColorEnabled(options);
|
|
@@ -43110,8 +44179,8 @@ function buildWikiHelpText(options = {}) {
|
|
|
43110
44179
|
return colorEnabled ? text : stripAnsi(text);
|
|
43111
44180
|
}
|
|
43112
44181
|
function createConsoleDaemonLifecycle(deps = {}) {
|
|
43113
|
-
const env = deps.env ??
|
|
43114
|
-
const execPath = deps.execPath ??
|
|
44182
|
+
const env = deps.env ?? process5.env;
|
|
44183
|
+
const execPath = deps.execPath ?? process5.execPath;
|
|
43115
44184
|
const serverModulePath = deps.serverModulePath ?? resolveDefaultServerModulePath();
|
|
43116
44185
|
const spawnDetached = deps.spawnDetached ?? ((bin, args, options) => {
|
|
43117
44186
|
spawn(bin, [...args], options).unref();
|
|
@@ -43125,10 +44194,10 @@ function createConsoleDaemonLifecycle(deps = {}) {
|
|
|
43125
44194
|
const server = createConsoleServer();
|
|
43126
44195
|
await server.start(paths);
|
|
43127
44196
|
await new Promise((resolve) => {
|
|
43128
|
-
|
|
44197
|
+
process5.once("SIGTERM", () => {
|
|
43129
44198
|
void server.stop().finally(resolve);
|
|
43130
44199
|
});
|
|
43131
|
-
|
|
44200
|
+
process5.once("SIGINT", () => {
|
|
43132
44201
|
void server.stop().finally(resolve);
|
|
43133
44202
|
});
|
|
43134
44203
|
});
|
|
@@ -43142,14 +44211,14 @@ function createConsoleDaemonLifecycle(deps = {}) {
|
|
|
43142
44211
|
const payload = readTrustedLock();
|
|
43143
44212
|
if (!payload) return;
|
|
43144
44213
|
try {
|
|
43145
|
-
|
|
44214
|
+
process5.kill(payload.pid, "SIGTERM");
|
|
43146
44215
|
} catch (err) {
|
|
43147
44216
|
if (err.code !== "ESRCH") throw err;
|
|
43148
44217
|
}
|
|
43149
44218
|
await sleep(200);
|
|
43150
44219
|
try {
|
|
43151
|
-
|
|
43152
|
-
|
|
44220
|
+
process5.kill(payload.pid, 0);
|
|
44221
|
+
process5.kill(payload.pid, "SIGKILL");
|
|
43153
44222
|
} catch (err) {
|
|
43154
44223
|
if (err.code !== "ESRCH") throw err;
|
|
43155
44224
|
}
|
|
@@ -43256,49 +44325,51 @@ async function runConsoleRestart(deps = {}) {
|
|
|
43256
44325
|
return openFleetConsole({ lifecycle, openBrowser: deps.openBrowser });
|
|
43257
44326
|
}
|
|
43258
44327
|
async function main() {
|
|
43259
|
-
if (
|
|
44328
|
+
if (process5.argv[2] === "serve") {
|
|
43260
44329
|
await createConsoleDaemonLifecycle().runServer();
|
|
43261
44330
|
return;
|
|
43262
44331
|
}
|
|
43263
|
-
if (
|
|
43264
|
-
parseConsoleHookCommand(
|
|
43265
|
-
{
|
|
43266
|
-
|
|
44332
|
+
if (process5.argv[2] === "hook") {
|
|
44333
|
+
const hookCommand = parseConsoleHookCommand(process5.argv.slice(3));
|
|
44334
|
+
if (hookCommand.command === "subagents-context") {
|
|
44335
|
+
process5.stdout.write(`${runSubagentsContextHook(process5.env)}
|
|
43267
44336
|
`);
|
|
43268
44337
|
return;
|
|
43269
44338
|
}
|
|
44339
|
+
await runCaptureSessionHook(hookCommand.provider, process5.env);
|
|
44340
|
+
return;
|
|
43270
44341
|
}
|
|
43271
|
-
if (
|
|
43272
|
-
await mainWiki(
|
|
44342
|
+
if (process5.argv[2] === "codex") {
|
|
44343
|
+
await mainWiki(process5.argv.slice(3));
|
|
43273
44344
|
return;
|
|
43274
44345
|
}
|
|
43275
|
-
const mode = parseConsoleCliMode(
|
|
44346
|
+
const mode = parseConsoleCliMode(process5.argv.slice(2));
|
|
43276
44347
|
if (mode === "help") {
|
|
43277
|
-
|
|
44348
|
+
process5.stdout.write(`${buildConsoleHelpText({ env: process5.env, isTTY: process5.stdout.isTTY })}
|
|
43278
44349
|
`);
|
|
43279
44350
|
return;
|
|
43280
44351
|
}
|
|
43281
44352
|
if (mode === "status") {
|
|
43282
|
-
|
|
44353
|
+
process5.stdout.write(`${await runConsoleStatus()}
|
|
43283
44354
|
`);
|
|
43284
44355
|
return;
|
|
43285
44356
|
}
|
|
43286
44357
|
if (mode === "stop") {
|
|
43287
|
-
|
|
44358
|
+
process5.stdout.write(`${await runConsoleStop()}
|
|
43288
44359
|
`);
|
|
43289
44360
|
return;
|
|
43290
44361
|
}
|
|
43291
44362
|
if (mode === "restart") {
|
|
43292
44363
|
await runConsoleRestart();
|
|
43293
|
-
|
|
44364
|
+
process5.stdout.write("Fleet Console restarted.\n");
|
|
43294
44365
|
return;
|
|
43295
44366
|
}
|
|
43296
44367
|
await openFleetConsole();
|
|
43297
|
-
|
|
44368
|
+
process5.stdout.write("Fleet Console opened.\n");
|
|
43298
44369
|
}
|
|
43299
|
-
async function mainWiki(argv =
|
|
44370
|
+
async function mainWiki(argv = process5.argv.slice(2)) {
|
|
43300
44371
|
if (argv.includes("--help") || argv.includes("-h")) {
|
|
43301
|
-
|
|
44372
|
+
process5.stdout.write(`${buildWikiHelpText({ env: process5.env, isTTY: process5.stdout.isTTY })}
|
|
43302
44373
|
`);
|
|
43303
44374
|
return;
|
|
43304
44375
|
}
|
|
@@ -43310,19 +44381,19 @@ async function mainWiki(argv = process4.argv.slice(2)) {
|
|
|
43310
44381
|
if (unsupported.length > 0) {
|
|
43311
44382
|
throw new Error(`Unknown fleet wiki option: ${unsupported[0]}`);
|
|
43312
44383
|
}
|
|
43313
|
-
await openFleetWikiWorkspace({ cwd:
|
|
44384
|
+
await openFleetWikiWorkspace({ cwd: process5.cwd() });
|
|
43314
44385
|
}
|
|
43315
44386
|
function resolveDefaultServerModulePath() {
|
|
43316
44387
|
const builtPath = new URL("../dist/cli.mjs", import.meta.url).pathname;
|
|
43317
44388
|
if (fs5__default.existsSync(builtPath)) return builtPath;
|
|
43318
44389
|
return fileURLToPath(import.meta.url);
|
|
43319
44390
|
}
|
|
43320
|
-
var isDirectRun =
|
|
44391
|
+
var isDirectRun = process5.argv[1] && path93__default.resolve(process5.argv[1]) === fileURLToPath(import.meta.url);
|
|
43321
44392
|
if (isDirectRun) {
|
|
43322
44393
|
await main().catch((error51) => {
|
|
43323
|
-
|
|
44394
|
+
process5.stderr.write(`${error51 instanceof Error ? error51.message : String(error51)}
|
|
43324
44395
|
`);
|
|
43325
|
-
|
|
44396
|
+
process5.exitCode = 1;
|
|
43326
44397
|
});
|
|
43327
44398
|
}
|
|
43328
44399
|
|