@dotobokuri/fleet-console 1.5.5 → 1.7.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 +14 -11
- package/README.md +9 -4
- package/dist/cli-bin.mjs +1915 -689
- package/dist/cli.d.ts +10 -1
- package/dist/cli.mjs +1915 -689
- package/dist/client/assets/{_baseUniq-CpEjig2A.js → _baseUniq-DaRHKvkJ.js} +1 -1
- package/dist/client/assets/{arc-BmymS_Kz.js → arc-ByrjrNFZ.js} +1 -1
- package/dist/client/assets/{architectureDiagram-Q4EWVU46-D1d0KVz1.js → architectureDiagram-Q4EWVU46-yRDXYtYq.js} +1 -1
- package/dist/client/assets/{blockDiagram-DXYQGD6D-Cwuv0sNk.js → blockDiagram-DXYQGD6D-B3Ud4HmY.js} +1 -1
- package/dist/client/assets/{c4Diagram-AHTNJAMY-Bsk-GjC_.js → c4Diagram-AHTNJAMY-BWtT7uJ6.js} +1 -1
- package/dist/client/assets/channel-D1hUfR86.js +1 -0
- package/dist/client/assets/{chunk-4BX2VUAB-ZM4i9T4D.js → chunk-4BX2VUAB-Cdk_k5EX.js} +1 -1
- package/dist/client/assets/{chunk-4TB4RGXK-Sw5ODKRj.js → chunk-4TB4RGXK-CfeLiRAa.js} +1 -1
- package/dist/client/assets/{chunk-55IACEB6-DDDLwVg4.js → chunk-55IACEB6-B26kabv5.js} +1 -1
- package/dist/client/assets/{chunk-EDXVE4YY-BNk5Xk1Q.js → chunk-EDXVE4YY-CZ5hqsgg.js} +1 -1
- package/dist/client/assets/{chunk-FMBD7UC4-C_CC6grw.js → chunk-FMBD7UC4-CuCp-r0v.js} +1 -1
- package/dist/client/assets/{chunk-OYMX7WX6-DTbaYVUc.js → chunk-OYMX7WX6-Dy5T8Uzb.js} +1 -1
- package/dist/client/assets/{chunk-QZHKN3VN-i7z9jXPR.js → chunk-QZHKN3VN-PNRzwWoU.js} +1 -1
- package/dist/client/assets/{chunk-YZCP3GAM-cTSeZOtz.js → chunk-YZCP3GAM-BjJxIVvV.js} +1 -1
- package/dist/client/assets/classDiagram-6PBFFD2Q-B7ZtwAd2.js +1 -0
- package/dist/client/assets/classDiagram-v2-HSJHXN6E-B7ZtwAd2.js +1 -0
- package/dist/client/assets/clone-BggxG0Ng.js +1 -0
- package/dist/client/assets/{cose-bilkent-S5V4N54A-uVW4wTRq.js → cose-bilkent-S5V4N54A-CIL2KUnC.js} +1 -1
- package/dist/client/assets/{dagre-KV5264BT-CclQ97X6.js → dagre-KV5264BT-BoekxdN3.js} +1 -1
- package/dist/client/assets/{diagram-5BDNPKRD-eZaXK0Xj.js → diagram-5BDNPKRD-8Uqn3Uve.js} +1 -1
- package/dist/client/assets/{diagram-G4DWMVQ6-DIQ8qOFv.js → diagram-G4DWMVQ6-CWZp4Fw1.js} +1 -1
- package/dist/client/assets/{diagram-MMDJMWI5-B_EbeR8B.js → diagram-MMDJMWI5-Cxxmq5lR.js} +1 -1
- package/dist/client/assets/{diagram-TYMM5635-DI64qX-Y.js → diagram-TYMM5635-BDL3SVhp.js} +1 -1
- package/dist/client/assets/{erDiagram-SMLLAGMA-DLkwbOsk.js → erDiagram-SMLLAGMA-Bm_XDDZi.js} +1 -1
- package/dist/client/assets/{flowDiagram-DWJPFMVM-BWvMzejD.js → flowDiagram-DWJPFMVM-z3JhyUpl.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-DVfDRTRP.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-UUTBAWPF-CnvcLURP.js → gitGraphDiagram-UUTBAWPF-_gni8LDF.js} +1 -1
- package/dist/client/assets/{graph-N4oFFLXe.js → graph-Beq1lcyq.js} +1 -1
- package/dist/client/assets/index-3nhZQ9tb.css +1 -0
- package/dist/client/assets/index-DFffaVk9.js +734 -0
- package/dist/client/assets/{infoDiagram-42DDH7IO-3uxP8aX_.js → infoDiagram-42DDH7IO-B-TP33al.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-UXIWVN3A-DQomHvSO.js → ishikawaDiagram-UXIWVN3A-1YDVINPA.js} +1 -1
- package/dist/client/assets/{journeyDiagram-VCZTEJTY-C_Ogwo77.js → journeyDiagram-VCZTEJTY-CZJuR6NC.js} +1 -1
- package/dist/client/assets/{kanban-definition-6JOO6SKY-CGOeur5D.js → kanban-definition-6JOO6SKY-_sSHU_-t.js} +1 -1
- package/dist/client/assets/{layout-DKlBkSB9.js → layout-UzmHJbGX.js} +1 -1
- package/dist/client/assets/{linear-2pQUtBdp.js → linear-BHitegAT.js} +1 -1
- package/dist/client/assets/{mermaid.core-BrseLPLb.js → mermaid.core-ptwBQDH8.js} +4 -4
- package/dist/client/assets/{min-OFtHLPyF.js → min-CBjwmJst.js} +1 -1
- package/dist/client/assets/{mindmap-definition-QFDTVHPH-DQk9T3wA.js → mindmap-definition-QFDTVHPH-C8NIvAO1.js} +1 -1
- package/dist/client/assets/{pieDiagram-DEJITSTG-Btu4aJWj.js → pieDiagram-DEJITSTG-paebhRXC.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-34T5L4WZ-BHMDVip9.js → quadrantDiagram-34T5L4WZ-Bk0pN-T7.js} +1 -1
- package/dist/client/assets/{requirementDiagram-MS252O5E-CbXi80dX.js → requirementDiagram-MS252O5E-CkPyeOJB.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-XADWPNL6-D5c7vUw4.js → sankeyDiagram-XADWPNL6-tJsRZl9C.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-FGHM5R23-CGuRanG_.js → sequenceDiagram-FGHM5R23-D1V2Qnb3.js} +1 -1
- package/dist/client/assets/{stateDiagram-FHFEXIEX-CVD3CB69.js → stateDiagram-FHFEXIEX-DdEFxPzQ.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-CpqK8Q3C.js +1 -0
- package/dist/client/assets/{timeline-definition-GMOUNBTQ-DMTeeglq.js → timeline-definition-GMOUNBTQ-D8sNtFqY.js} +1 -1
- package/dist/client/assets/{vennDiagram-DHZGUBPP-CQ6TwRhb.js → vennDiagram-DHZGUBPP-DoTEQk3E.js} +1 -1
- package/dist/client/assets/{wardley-RL74JXVD-DdgusU4o.js → wardley-RL74JXVD-BuEgLJ7M.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-NUSXRM2D-BFsWqK49.js → wardleyDiagram-NUSXRM2D-B0Gl34Zh.js} +1 -1
- package/dist/client/assets/{xychartDiagram-5P7HB3ND-Hca3jUV6.js → xychartDiagram-5P7HB3ND-Bf4nAMbM.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 process6 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, path35) {
|
|
973
|
+
if (!path35)
|
|
974
974
|
return obj;
|
|
975
|
-
return
|
|
975
|
+
return path35.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(path35, 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(path35);
|
|
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, path35 = []) => {
|
|
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 }, [...path35, ...issue3.path]));
|
|
1539
1539
|
} else if (issue3.code === "invalid_key") {
|
|
1540
|
-
processError({ issues: issue3.issues }, [...
|
|
1540
|
+
processError({ issues: issue3.issues }, [...path35, ...issue3.path]);
|
|
1541
1541
|
} else if (issue3.code === "invalid_element") {
|
|
1542
|
-
processError({ issues: issue3.issues }, [...
|
|
1542
|
+
processError({ issues: issue3.issues }, [...path35, ...issue3.path]);
|
|
1543
1543
|
} else {
|
|
1544
|
-
const fullpath = [...
|
|
1544
|
+
const fullpath = [...path35, ...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, path35 = []) => {
|
|
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 }, [...path35, ...issue3.path]));
|
|
1576
1576
|
} else if (issue3.code === "invalid_key") {
|
|
1577
|
-
processError({ issues: issue3.issues }, [...
|
|
1577
|
+
processError({ issues: issue3.issues }, [...path35, ...issue3.path]);
|
|
1578
1578
|
} else if (issue3.code === "invalid_element") {
|
|
1579
|
-
processError({ issues: issue3.issues }, [...
|
|
1579
|
+
processError({ issues: issue3.issues }, [...path35, ...issue3.path]);
|
|
1580
1580
|
} else {
|
|
1581
|
-
const fullpath = [...
|
|
1581
|
+
const fullpath = [...path35, ...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 path35 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
1614
|
+
for (const seg of path35) {
|
|
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 path35 = ref.slice(1).split("/").filter(Boolean);
|
|
14279
|
+
if (path35.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 (path35[0] === defsKey) {
|
|
14284
|
+
const key = path35[1];
|
|
14285
14285
|
if (!key || !ctx.defs[key]) {
|
|
14286
14286
|
throw new Error(`Reference not found: ${ref}`);
|
|
14287
14287
|
}
|
|
@@ -17046,7 +17046,9 @@ function killProcess(child, forceTimeoutMs = 3e3) {
|
|
|
17046
17046
|
try {
|
|
17047
17047
|
execSync(`taskkill /PID ${child.pid} /T /F`, {
|
|
17048
17048
|
stdio: "pipe",
|
|
17049
|
-
timeout: 5e3
|
|
17049
|
+
timeout: 5e3,
|
|
17050
|
+
// 콘솔 없는 호스트에서 taskkill 호출 시 새 콘솔 창이 깜빡이는 것을 방지한다.
|
|
17051
|
+
windowsHide: true
|
|
17050
17052
|
});
|
|
17051
17053
|
} catch {
|
|
17052
17054
|
child.kill("SIGKILL");
|
|
@@ -17120,7 +17122,12 @@ var BaseConnection = class extends EventEmitter {
|
|
|
17120
17122
|
cwd: this.cwd,
|
|
17121
17123
|
stdio: ["pipe", "pipe", "pipe"],
|
|
17122
17124
|
env: this.env,
|
|
17123
|
-
windowsVerbatimArguments: true
|
|
17125
|
+
windowsVerbatimArguments: true,
|
|
17126
|
+
// 콘솔이 없는 호스트(예: fleet-console 백엔드)에서 cmd.exe를 spawn하면
|
|
17127
|
+
// Windows가 새 콘솔 창을 할당해 깜빡인다. stdio는 모두 pipe라 가시 콘솔이
|
|
17128
|
+
// 불필요하므로 CREATE_NO_WINDOW로 창 생성을 억제한다. (fleet-cli처럼 콘솔이
|
|
17129
|
+
// 이미 있는 경우에도 무해하다.)
|
|
17130
|
+
windowsHide: true
|
|
17124
17131
|
}) : spawn(this.command, this.args, {
|
|
17125
17132
|
cwd: this.cwd,
|
|
17126
17133
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -17876,7 +17883,9 @@ function resolveNpxPath(env) {
|
|
|
17876
17883
|
encoding: "utf-8",
|
|
17877
17884
|
stdio: "pipe",
|
|
17878
17885
|
timeout: 5e3,
|
|
17879
|
-
env
|
|
17886
|
+
env,
|
|
17887
|
+
// 콘솔 없는 호스트에서 `where npx` 실행 시 콘솔 창이 깜빡이는 것을 방지한다.
|
|
17888
|
+
windowsHide: true
|
|
17880
17889
|
}).trim();
|
|
17881
17890
|
const candidates = result.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
|
|
17882
17891
|
if (windows) {
|
|
@@ -17913,7 +17922,7 @@ function inferBinName(packageName) {
|
|
|
17913
17922
|
// ../../packages/core-unified-agent/models.json
|
|
17914
17923
|
var models_default = {
|
|
17915
17924
|
version: 1,
|
|
17916
|
-
updatedAt: "2026-06-
|
|
17925
|
+
updatedAt: "2026-06-16T00:00:00Z",
|
|
17917
17926
|
providers: {
|
|
17918
17927
|
claude: {
|
|
17919
17928
|
name: "Claude Code with Anthropic",
|
|
@@ -17923,7 +17932,9 @@ var models_default = {
|
|
|
17923
17932
|
{ modelId: "sonnet", name: "Claude Sonnet", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "medium" } },
|
|
17924
17933
|
{ modelId: "opus", name: "Claude Opus", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "xhigh" } },
|
|
17925
17934
|
{ 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" } }
|
|
17935
|
+
{ modelId: "claude-opus-4-6[1m]", name: "Claude Opus 4.6 [1M]", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "high" } },
|
|
17936
|
+
{ modelId: "claude-opus-4-7[1m]", name: "Claude Opus 4.7 [1M]", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "high" } },
|
|
17937
|
+
{ modelId: "claude-opus-4-8[1m]", name: "Claude Opus 4.8 [1M]", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "high" } }
|
|
17927
17938
|
]
|
|
17928
17939
|
},
|
|
17929
17940
|
"claude-zai": {
|
|
@@ -21074,7 +21085,7 @@ function specToMcpTool(spec) {
|
|
|
21074
21085
|
}
|
|
21075
21086
|
function installExecutorToolCallRouter(runtime, sessionToken, ctx) {
|
|
21076
21087
|
runtime.server.setOnToolCallArrived(sessionToken, (toolName, args) => {
|
|
21077
|
-
const toolCallId =
|
|
21088
|
+
const toolCallId = crypto5.randomUUID();
|
|
21078
21089
|
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
21090
|
runtime.server.resolveNextToolCall(sessionToken, toolCallId, {
|
|
21080
21091
|
content: [{ type: "text", text: err instanceof Error ? err.message : String(err) }],
|
|
@@ -21465,7 +21476,7 @@ function createInProcessMcpServer(deps = {}) {
|
|
|
21465
21476
|
if (activeStopPromise) await activeStopPromise;
|
|
21466
21477
|
if (activeServer && activeServerUrl) return activeServerUrl;
|
|
21467
21478
|
if (activeStartPromise) return activeStartPromise;
|
|
21468
|
-
activeOpaquePath = `/${
|
|
21479
|
+
activeOpaquePath = `/${crypto5.randomUUID()}`;
|
|
21469
21480
|
activeStartPromise = new Promise((resolve, reject) => {
|
|
21470
21481
|
const srv = http.createServer(handleRequest);
|
|
21471
21482
|
srv.timeout = MCP_SERVER_TIMEOUT_MS;
|
|
@@ -21722,7 +21733,7 @@ function createExecutorMcpSession(deps, toolTimeoutSeconds, request) {
|
|
|
21722
21733
|
throw new Error("Executor session cwd is required");
|
|
21723
21734
|
}
|
|
21724
21735
|
assertNonEmptyExecutorTools(request.serverName, request.specs);
|
|
21725
|
-
const token =
|
|
21736
|
+
const token = crypto5.randomUUID();
|
|
21726
21737
|
registerExecutorSessionTools(runtime.runtime, token, [...request.specs]);
|
|
21727
21738
|
installExecutorToolCallRouter(runtime.runtime, token, {
|
|
21728
21739
|
cwd,
|
|
@@ -21768,7 +21779,7 @@ function issueSessionToken(deps, sessionTokensByLabel, request) {
|
|
|
21768
21779
|
for (const { name, runtime } of deps.runtimes) {
|
|
21769
21780
|
const tools = runtime.registry.getAllAgentTools();
|
|
21770
21781
|
assertNonEmptyExecutorTools(name, tools);
|
|
21771
|
-
const token =
|
|
21782
|
+
const token = crypto5.randomUUID();
|
|
21772
21783
|
registerExecutorSessionTools(runtime, token, tools);
|
|
21773
21784
|
installExecutorToolCallRouter(runtime, token, { cwd, sessionLabel: label, signal: request.signal });
|
|
21774
21785
|
tokens.push({ name, token });
|
|
@@ -23134,7 +23145,8 @@ function sleepSync(ms) {
|
|
|
23134
23145
|
var DEFAULT_TEMP_FILE_MIN_AGE_MS = 6e4;
|
|
23135
23146
|
function createDurableJsonStore(deps) {
|
|
23136
23147
|
const now = deps.now ?? (() => Date.now());
|
|
23137
|
-
const
|
|
23148
|
+
const sensitivity = deps.sensitivity;
|
|
23149
|
+
const mode = sensitivity === "sensitive" ? SECURE_FILE_MODE : 420;
|
|
23138
23150
|
const minAgeMs = deps.tempCleanupMinAgeMs ?? DEFAULT_TEMP_FILE_MIN_AGE_MS;
|
|
23139
23151
|
const dir = path93.dirname(deps.filePath);
|
|
23140
23152
|
return {
|
|
@@ -23162,10 +23174,10 @@ function createDurableJsonStore(deps) {
|
|
|
23162
23174
|
};
|
|
23163
23175
|
function withLock(operation) {
|
|
23164
23176
|
if (!deps.lockDir) {
|
|
23165
|
-
ensureSafeDirectoryIfSensitive(dir);
|
|
23177
|
+
ensureSafeDirectoryIfSensitive(dir, sensitivity);
|
|
23166
23178
|
return operation();
|
|
23167
23179
|
}
|
|
23168
|
-
ensureSafeDirectoryIfSensitive(dir);
|
|
23180
|
+
ensureSafeDirectoryIfSensitive(dir, sensitivity);
|
|
23169
23181
|
return withDirectoryLock(
|
|
23170
23182
|
{
|
|
23171
23183
|
lockDir: deps.lockDir,
|
|
@@ -23207,8 +23219,10 @@ function readJsonFile(filePath, sanitize) {
|
|
|
23207
23219
|
}
|
|
23208
23220
|
}
|
|
23209
23221
|
function ensureSafeDirectoryIfSensitive(dir, sensitivity) {
|
|
23210
|
-
{
|
|
23222
|
+
if (sensitivity === "sensitive") {
|
|
23211
23223
|
ensureSafeDirectory(dir);
|
|
23224
|
+
} else {
|
|
23225
|
+
fs5.mkdirSync(dir, { recursive: true });
|
|
23212
23226
|
}
|
|
23213
23227
|
}
|
|
23214
23228
|
|
|
@@ -31414,7 +31428,7 @@ var LOCK_FILE_MODE = 384;
|
|
|
31414
31428
|
function createConsoleLock(deps = {}) {
|
|
31415
31429
|
const fsImpl = deps.fs ?? fs5__default;
|
|
31416
31430
|
const now = deps.now ?? Date.now;
|
|
31417
|
-
const randomToken = deps.randomToken ?? (() =>
|
|
31431
|
+
const randomToken = deps.randomToken ?? (() => crypto5.randomBytes(32).toString("base64url"));
|
|
31418
31432
|
const hostname5 = deps.hostname ?? (() => "127.0.0.1");
|
|
31419
31433
|
function ensureLockDir(dir) {
|
|
31420
31434
|
fsImpl.mkdirSync(dir, { recursive: true, mode: LOCK_DIR_MODE });
|
|
@@ -31509,6 +31523,389 @@ function createConsoleLock(deps = {}) {
|
|
|
31509
31523
|
}
|
|
31510
31524
|
return { ensureLockDir, readLock, writeLock, removeLock, assertLockModes, assertTrustedLock };
|
|
31511
31525
|
}
|
|
31526
|
+
var FLEET_DATA_DIR_NAME = ".fleet";
|
|
31527
|
+
function getFleetDataDir() {
|
|
31528
|
+
return path93.join(os22.homedir(), FLEET_DATA_DIR_NAME);
|
|
31529
|
+
}
|
|
31530
|
+
function readAuthStoreFile(filePath) {
|
|
31531
|
+
let fd;
|
|
31532
|
+
try {
|
|
31533
|
+
fd = fs5.openSync(filePath, fs5.constants.O_RDONLY | NOFOLLOW_FLAG);
|
|
31534
|
+
if (!fs5.fstatSync(fd).isFile()) {
|
|
31535
|
+
return {};
|
|
31536
|
+
}
|
|
31537
|
+
return JSON.parse(fs5.readFileSync(fd, "utf-8"));
|
|
31538
|
+
} catch {
|
|
31539
|
+
return {};
|
|
31540
|
+
} finally {
|
|
31541
|
+
if (fd !== void 0) {
|
|
31542
|
+
try {
|
|
31543
|
+
fs5.closeSync(fd);
|
|
31544
|
+
} catch {
|
|
31545
|
+
}
|
|
31546
|
+
}
|
|
31547
|
+
}
|
|
31548
|
+
}
|
|
31549
|
+
var DEFAULT_AUTH_PATH = path93.join(getFleetDataDir(), "auth.json");
|
|
31550
|
+
var AUTH_LOCK_OWNER_FILE_NAME = "owner.json";
|
|
31551
|
+
var AUTH_LOCK_TIMEOUT_MS = 5e3;
|
|
31552
|
+
function createAuthService(deps = {}) {
|
|
31553
|
+
const authPath = deps.authPath ?? DEFAULT_AUTH_PATH;
|
|
31554
|
+
const lockDir = `${authPath}.lock`;
|
|
31555
|
+
return {
|
|
31556
|
+
// [HIGH #1] TOCTOU 수정: existsSync/read/check/delete/write 전체를 락 블록 안으로 이동
|
|
31557
|
+
async deleteApiKey(providerId) {
|
|
31558
|
+
let deleted = false;
|
|
31559
|
+
withAuthLock(authPath, lockDir, () => {
|
|
31560
|
+
if (!fs5.existsSync(authPath)) return;
|
|
31561
|
+
const data = readAuthStoreFile(authPath);
|
|
31562
|
+
if (!Object.prototype.hasOwnProperty.call(data, providerId)) return;
|
|
31563
|
+
delete data[providerId];
|
|
31564
|
+
writeAuthData(authPath, data);
|
|
31565
|
+
deleted = true;
|
|
31566
|
+
});
|
|
31567
|
+
return deleted;
|
|
31568
|
+
},
|
|
31569
|
+
// [HIGH #2] 읽기 경로: fd 기반 O_RDONLY|O_NOFOLLOW+fstatSync isFile
|
|
31570
|
+
async getApiKey(providerId) {
|
|
31571
|
+
let fd;
|
|
31572
|
+
try {
|
|
31573
|
+
if (!fs5.existsSync(authPath)) {
|
|
31574
|
+
return void 0;
|
|
31575
|
+
}
|
|
31576
|
+
fd = fs5.openSync(authPath, fs5.constants.O_RDONLY | NOFOLLOW_FLAG);
|
|
31577
|
+
if (!fs5.fstatSync(fd).isFile()) {
|
|
31578
|
+
return void 0;
|
|
31579
|
+
}
|
|
31580
|
+
const data = JSON.parse(fs5.readFileSync(fd, "utf-8"));
|
|
31581
|
+
return typeof data[providerId]?.key === "string" ? data[providerId].key : void 0;
|
|
31582
|
+
} catch {
|
|
31583
|
+
return void 0;
|
|
31584
|
+
} finally {
|
|
31585
|
+
if (fd !== void 0) {
|
|
31586
|
+
try {
|
|
31587
|
+
fs5.closeSync(fd);
|
|
31588
|
+
} catch {
|
|
31589
|
+
}
|
|
31590
|
+
}
|
|
31591
|
+
}
|
|
31592
|
+
},
|
|
31593
|
+
// [HIGH #2] 읽기 경로: fd 기반 O_RDONLY|O_NOFOLLOW 통일
|
|
31594
|
+
async listProviderIds() {
|
|
31595
|
+
if (!fs5.existsSync(authPath)) {
|
|
31596
|
+
return [];
|
|
31597
|
+
}
|
|
31598
|
+
try {
|
|
31599
|
+
return Object.keys(readAuthStoreFile(authPath)).sort();
|
|
31600
|
+
} catch {
|
|
31601
|
+
return [];
|
|
31602
|
+
}
|
|
31603
|
+
},
|
|
31604
|
+
async setApiKey(providerId, key) {
|
|
31605
|
+
const dir = path93.dirname(authPath);
|
|
31606
|
+
ensureSafeDirectory(dir);
|
|
31607
|
+
withAuthLock(authPath, lockDir, () => {
|
|
31608
|
+
const data = fs5.existsSync(authPath) ? readAuthStoreFile(authPath) : {};
|
|
31609
|
+
data[providerId] = {
|
|
31610
|
+
...data[providerId] ?? {},
|
|
31611
|
+
key
|
|
31612
|
+
};
|
|
31613
|
+
writeAuthData(authPath, data);
|
|
31614
|
+
});
|
|
31615
|
+
}
|
|
31616
|
+
};
|
|
31617
|
+
}
|
|
31618
|
+
function withAuthLock(authPath, lockDir, operation) {
|
|
31619
|
+
return withDirectoryLock(
|
|
31620
|
+
{
|
|
31621
|
+
lockDir,
|
|
31622
|
+
ownerFileName: AUTH_LOCK_OWNER_FILE_NAME,
|
|
31623
|
+
timeoutMs: AUTH_LOCK_TIMEOUT_MS
|
|
31624
|
+
},
|
|
31625
|
+
operation
|
|
31626
|
+
);
|
|
31627
|
+
}
|
|
31628
|
+
function writeAuthData(authPath, data) {
|
|
31629
|
+
writeAtomicSync(authPath, `${JSON.stringify(data, null, 2)}
|
|
31630
|
+
`, {
|
|
31631
|
+
mode: SECURE_FILE_MODE,
|
|
31632
|
+
fsync: true
|
|
31633
|
+
});
|
|
31634
|
+
}
|
|
31635
|
+
function formatMissingAuthKeyMessage(input) {
|
|
31636
|
+
const cliHint = input.cli ? `cli '${input.cli}'` : "selected CLI";
|
|
31637
|
+
return `Auth token not found for ${cliHint} (providerId: '${input.providerId}'). Run \`fleet auth login\` to register one.`;
|
|
31638
|
+
}
|
|
31639
|
+
function formatAuthValidationFailureMessage(input) {
|
|
31640
|
+
const detail = input.detail ? ` Detail: ${input.detail}` : "";
|
|
31641
|
+
if (input.status === "unauthorized") {
|
|
31642
|
+
return `Auth token was rejected (providerId: '${input.providerId}'). Check the token and try again.${detail}`;
|
|
31643
|
+
}
|
|
31644
|
+
if (input.status === "forbidden") {
|
|
31645
|
+
return `Auth token is not allowed for this provider (providerId: '${input.providerId}'). Check the token permissions.${detail}`;
|
|
31646
|
+
}
|
|
31647
|
+
if (input.status === "timeout") {
|
|
31648
|
+
return `Auth token validation timed out (providerId: '${input.providerId}'). Check the connection and try again.${detail}`;
|
|
31649
|
+
}
|
|
31650
|
+
if (input.status === "network") {
|
|
31651
|
+
return `Auth token validation failed due to a network error (providerId: '${input.providerId}'). Check the connection and try again.${detail}`;
|
|
31652
|
+
}
|
|
31653
|
+
if (input.status === "server") {
|
|
31654
|
+
return `Auth token validation failed because the provider returned an error (providerId: '${input.providerId}'). Try again later.${detail}`;
|
|
31655
|
+
}
|
|
31656
|
+
return `Auth token validation failed (providerId: '${input.providerId}'). Check the token and try again.${detail}`;
|
|
31657
|
+
}
|
|
31658
|
+
var LEGACY_AUTH_PATH = path93.join(getFleetDataDir(), "agent", "auth.json");
|
|
31659
|
+
var CURRENT_AUTH_PATH = path93.join(getFleetDataDir(), "auth.json");
|
|
31660
|
+
function mergeAuthStoresNoOverwrite(legacy, current) {
|
|
31661
|
+
const data = { ...current };
|
|
31662
|
+
const migratedProviderIds = [];
|
|
31663
|
+
const skippedProviderIds = [];
|
|
31664
|
+
for (const [providerId, entry] of Object.entries(legacy)) {
|
|
31665
|
+
if (Object.prototype.hasOwnProperty.call(data, providerId)) {
|
|
31666
|
+
skippedProviderIds.push(providerId);
|
|
31667
|
+
continue;
|
|
31668
|
+
}
|
|
31669
|
+
data[providerId] = entry;
|
|
31670
|
+
migratedProviderIds.push(providerId);
|
|
31671
|
+
}
|
|
31672
|
+
return {
|
|
31673
|
+
data,
|
|
31674
|
+
migratedProviderIds,
|
|
31675
|
+
skippedProviderIds
|
|
31676
|
+
};
|
|
31677
|
+
}
|
|
31678
|
+
async function migrateLegacyAuthStore(options = {}) {
|
|
31679
|
+
const legacyPath = options.legacyPath ?? LEGACY_AUTH_PATH;
|
|
31680
|
+
const currentPath = options.currentPath ?? CURRENT_AUTH_PATH;
|
|
31681
|
+
if (!fs5.existsSync(legacyPath)) {
|
|
31682
|
+
return createMigrationResult({
|
|
31683
|
+
legacyPath,
|
|
31684
|
+
currentPath,
|
|
31685
|
+
status: "legacy-missing",
|
|
31686
|
+
migratedProviderIds: [],
|
|
31687
|
+
skippedProviderIds: [],
|
|
31688
|
+
shouldPrintNotice: false
|
|
31689
|
+
});
|
|
31690
|
+
}
|
|
31691
|
+
const legacy = readAuthStoreFile(legacyPath);
|
|
31692
|
+
const current = fs5.existsSync(currentPath) ? readAuthStoreFile(currentPath) : {};
|
|
31693
|
+
const merged = mergeAuthStoresNoOverwrite(legacy, current);
|
|
31694
|
+
if (merged.migratedProviderIds.length > 0) {
|
|
31695
|
+
const dir = path93.dirname(currentPath);
|
|
31696
|
+
ensureSafeDirectory(dir);
|
|
31697
|
+
writeAtomicSync(currentPath, `${JSON.stringify(merged.data, null, 2)}
|
|
31698
|
+
`, {
|
|
31699
|
+
mode: SECURE_FILE_MODE,
|
|
31700
|
+
fsync: true
|
|
31701
|
+
});
|
|
31702
|
+
}
|
|
31703
|
+
return createMigrationResult({
|
|
31704
|
+
legacyPath,
|
|
31705
|
+
currentPath,
|
|
31706
|
+
status: merged.migratedProviderIds.length > 0 ? "migrated" : "unchanged",
|
|
31707
|
+
migratedProviderIds: merged.migratedProviderIds,
|
|
31708
|
+
skippedProviderIds: merged.skippedProviderIds,
|
|
31709
|
+
shouldPrintNotice: options.notify !== false && merged.migratedProviderIds.length > 0
|
|
31710
|
+
});
|
|
31711
|
+
}
|
|
31712
|
+
function createMigrationResult(input) {
|
|
31713
|
+
return {
|
|
31714
|
+
legacyPath: input.legacyPath,
|
|
31715
|
+
currentPath: input.currentPath,
|
|
31716
|
+
migratedCount: input.migratedProviderIds.length,
|
|
31717
|
+
skippedCount: input.skippedProviderIds.length,
|
|
31718
|
+
migratedProviderIds: input.migratedProviderIds,
|
|
31719
|
+
skippedProviderIds: input.skippedProviderIds,
|
|
31720
|
+
shouldPrintNotice: input.shouldPrintNotice,
|
|
31721
|
+
status: input.status
|
|
31722
|
+
};
|
|
31723
|
+
}
|
|
31724
|
+
var DEFAULT_AUTH_VALIDATION_TIMEOUT_MS = 5e3;
|
|
31725
|
+
async function validateAnthropicCompatibleApiKey(request) {
|
|
31726
|
+
const controller = new AbortController();
|
|
31727
|
+
const timeout = setTimeout(() => {
|
|
31728
|
+
controller.abort();
|
|
31729
|
+
}, request.timeoutMs ?? DEFAULT_AUTH_VALIDATION_TIMEOUT_MS);
|
|
31730
|
+
try {
|
|
31731
|
+
const response = await fetch(buildMessagesUrl(request.baseUrl), {
|
|
31732
|
+
method: "POST",
|
|
31733
|
+
headers: {
|
|
31734
|
+
"anthropic-version": "2023-06-01",
|
|
31735
|
+
"content-type": "application/json",
|
|
31736
|
+
"x-api-key": request.apiKey
|
|
31737
|
+
},
|
|
31738
|
+
body: JSON.stringify({
|
|
31739
|
+
model: "claude-3-5-haiku-20241022",
|
|
31740
|
+
max_tokens: 1,
|
|
31741
|
+
messages: [
|
|
31742
|
+
{
|
|
31743
|
+
role: "user",
|
|
31744
|
+
content: "ping"
|
|
31745
|
+
}
|
|
31746
|
+
]
|
|
31747
|
+
}),
|
|
31748
|
+
signal: controller.signal
|
|
31749
|
+
});
|
|
31750
|
+
if (response.ok) {
|
|
31751
|
+
return { providerId: request.providerId, status: "success" };
|
|
31752
|
+
}
|
|
31753
|
+
if (response.status === 401) {
|
|
31754
|
+
return { providerId: request.providerId, status: "unauthorized" };
|
|
31755
|
+
}
|
|
31756
|
+
if (response.status === 403) {
|
|
31757
|
+
return { providerId: request.providerId, status: "forbidden" };
|
|
31758
|
+
}
|
|
31759
|
+
if (response.status >= 500) {
|
|
31760
|
+
return {
|
|
31761
|
+
providerId: request.providerId,
|
|
31762
|
+
status: "server",
|
|
31763
|
+
detail: `HTTP ${response.status}`
|
|
31764
|
+
};
|
|
31765
|
+
}
|
|
31766
|
+
return {
|
|
31767
|
+
providerId: request.providerId,
|
|
31768
|
+
status: "unknown",
|
|
31769
|
+
detail: `HTTP ${response.status}`
|
|
31770
|
+
};
|
|
31771
|
+
} catch (error51) {
|
|
31772
|
+
if (isAbortError(error51)) {
|
|
31773
|
+
return { providerId: request.providerId, status: "timeout" };
|
|
31774
|
+
}
|
|
31775
|
+
return {
|
|
31776
|
+
providerId: request.providerId,
|
|
31777
|
+
status: "network",
|
|
31778
|
+
detail: error51 instanceof Error ? error51.message : String(error51)
|
|
31779
|
+
};
|
|
31780
|
+
} finally {
|
|
31781
|
+
clearTimeout(timeout);
|
|
31782
|
+
}
|
|
31783
|
+
}
|
|
31784
|
+
function isAuthValidationSuccess(result) {
|
|
31785
|
+
return result.status === "success";
|
|
31786
|
+
}
|
|
31787
|
+
function createAuthValidationError(result) {
|
|
31788
|
+
return new Error(formatAuthValidationFailureMessage(result));
|
|
31789
|
+
}
|
|
31790
|
+
function buildMessagesUrl(baseUrl) {
|
|
31791
|
+
return `${baseUrl.replace(/\/+$/, "")}/v1/messages`;
|
|
31792
|
+
}
|
|
31793
|
+
function isAbortError(error51) {
|
|
31794
|
+
return error51 instanceof DOMException && error51.name === "AbortError";
|
|
31795
|
+
}
|
|
31796
|
+
var CLAUDE_ZAI_PROVIDER_ID = "Claude Code with Z.AI GLM";
|
|
31797
|
+
var CLAUDE_KIMI_PROVIDER_ID = "Claude Code with Moonshot Kimi";
|
|
31798
|
+
var AUTH_PROVIDER_DEFINITIONS = {
|
|
31799
|
+
"claude-zai": {
|
|
31800
|
+
providerId: CLAUDE_ZAI_PROVIDER_ID,
|
|
31801
|
+
baseUrl: CLI_BACKENDS["claude-zai"].defaultEnv.ANTHROPIC_BASE_URL,
|
|
31802
|
+
env: CLI_BACKENDS["claude-zai"].defaultEnv
|
|
31803
|
+
},
|
|
31804
|
+
"claude-kimi": {
|
|
31805
|
+
providerId: CLAUDE_KIMI_PROVIDER_ID,
|
|
31806
|
+
baseUrl: CLI_BACKENDS["claude-kimi"].defaultEnv.ANTHROPIC_BASE_URL,
|
|
31807
|
+
env: CLI_BACKENDS["claude-kimi"].defaultEnv
|
|
31808
|
+
}
|
|
31809
|
+
};
|
|
31810
|
+
async function resolveAuthEnv(cli, deps) {
|
|
31811
|
+
const provider = AUTH_PROVIDER_DEFINITIONS[cli];
|
|
31812
|
+
if (!provider) return {};
|
|
31813
|
+
await migrateLegacyAuthStore();
|
|
31814
|
+
const auth = deps?.authService ?? createAuthService({ authPath: DEFAULT_AUTH_PATH });
|
|
31815
|
+
const token = await auth.getApiKey(provider.providerId);
|
|
31816
|
+
if (!token) {
|
|
31817
|
+
throw new Error(formatMissingAuthKeyMessage({ cli, providerId: provider.providerId }));
|
|
31818
|
+
}
|
|
31819
|
+
const validation = await validateAnthropicCompatibleApiKey({
|
|
31820
|
+
providerId: provider.providerId,
|
|
31821
|
+
apiKey: token,
|
|
31822
|
+
baseUrl: provider.baseUrl
|
|
31823
|
+
});
|
|
31824
|
+
if (!isAuthValidationSuccess(validation)) {
|
|
31825
|
+
const failure = {
|
|
31826
|
+
providerId: validation.providerId,
|
|
31827
|
+
status: validation.status,
|
|
31828
|
+
detail: validation.detail
|
|
31829
|
+
};
|
|
31830
|
+
throw createAuthValidationError(failure);
|
|
31831
|
+
}
|
|
31832
|
+
return { ...provider.env, ANTHROPIC_AUTH_TOKEN: token };
|
|
31833
|
+
}
|
|
31834
|
+
var GLOBAL_OPTIONS_VERSION = 1;
|
|
31835
|
+
var GLOBAL_OPTIONS_FILE_NAME = "settings.json";
|
|
31836
|
+
var LOCK_DIR_NAME = "settings.json.lock";
|
|
31837
|
+
var LOCK_OWNER_FILE_NAME = "owner";
|
|
31838
|
+
var TEMP_FILE_PREFIX = `.tmp-${GLOBAL_OPTIONS_FILE_NAME}-`;
|
|
31839
|
+
function createGlobalOptionsStore(deps = {}) {
|
|
31840
|
+
const dataDir = deps.dataDir ?? getFleetDataDir();
|
|
31841
|
+
const optionsPath = path93.join(dataDir, GLOBAL_OPTIONS_FILE_NAME);
|
|
31842
|
+
const lockDir = path93.join(dataDir, LOCK_DIR_NAME);
|
|
31843
|
+
const store2 = createDurableJsonStore({
|
|
31844
|
+
filePath: optionsPath,
|
|
31845
|
+
lockDir,
|
|
31846
|
+
lockOwnerFileName: LOCK_OWNER_FILE_NAME,
|
|
31847
|
+
sanitize: (value) => sanitizeGlobalOptionsData(value).data,
|
|
31848
|
+
sensitivity: "sensitive",
|
|
31849
|
+
timeoutMs: deps.timeoutMs,
|
|
31850
|
+
staleLockMs: deps.staleLockMs,
|
|
31851
|
+
tempCleanupPrefix: TEMP_FILE_PREFIX,
|
|
31852
|
+
now: deps.now
|
|
31853
|
+
});
|
|
31854
|
+
return {
|
|
31855
|
+
path: optionsPath,
|
|
31856
|
+
load: () => store2.load(),
|
|
31857
|
+
save: (data) => store2.save(sanitizeGlobalOptionsData(data).data),
|
|
31858
|
+
update: (mutate) => store2.update((current) => sanitizeGlobalOptionsData(mutate(current)).data)
|
|
31859
|
+
};
|
|
31860
|
+
}
|
|
31861
|
+
function createEmptyGlobalOptionsData() {
|
|
31862
|
+
return {
|
|
31863
|
+
version: GLOBAL_OPTIONS_VERSION
|
|
31864
|
+
};
|
|
31865
|
+
}
|
|
31866
|
+
function sanitizeGlobalOptionsData(value) {
|
|
31867
|
+
if (!isRecord3(value)) {
|
|
31868
|
+
return { data: createEmptyGlobalOptionsData(), changed: true };
|
|
31869
|
+
}
|
|
31870
|
+
if (value.version !== GLOBAL_OPTIONS_VERSION) {
|
|
31871
|
+
return { data: createEmptyGlobalOptionsData(), changed: true };
|
|
31872
|
+
}
|
|
31873
|
+
const data = {
|
|
31874
|
+
version: GLOBAL_OPTIONS_VERSION,
|
|
31875
|
+
...typeof value.replaceSystemPrompt === "boolean" ? { replaceSystemPrompt: value.replaceSystemPrompt } : {},
|
|
31876
|
+
...typeof value.enableMetaphor === "boolean" ? { enableMetaphor: value.enableMetaphor } : {}
|
|
31877
|
+
};
|
|
31878
|
+
const allowedKeys = /* @__PURE__ */ new Set(["version", "replaceSystemPrompt", "enableMetaphor"]);
|
|
31879
|
+
const changed = Object.keys(value).some((key) => !allowedKeys.has(key)) || "replaceSystemPrompt" in value && typeof value.replaceSystemPrompt !== "boolean" || "enableMetaphor" in value && typeof value.enableMetaphor !== "boolean";
|
|
31880
|
+
return { data, changed };
|
|
31881
|
+
}
|
|
31882
|
+
function isRecord3(value) {
|
|
31883
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
31884
|
+
}
|
|
31885
|
+
function createGlobalOptionsService(deps = {}) {
|
|
31886
|
+
const store2 = deps.store ?? createGlobalOptionsStore({ dataDir: deps.dataDir });
|
|
31887
|
+
return {
|
|
31888
|
+
load: () => store2.load(),
|
|
31889
|
+
save: (data) => {
|
|
31890
|
+
store2.save(data);
|
|
31891
|
+
return store2.load();
|
|
31892
|
+
},
|
|
31893
|
+
update: (mutate) => updateGlobalOptions(store2, mutate)
|
|
31894
|
+
};
|
|
31895
|
+
}
|
|
31896
|
+
function updateGlobalOptions(store2, mutate) {
|
|
31897
|
+
return store2.update(mutate);
|
|
31898
|
+
}
|
|
31899
|
+
|
|
31900
|
+
// ../../packages/fleet-infra/dist/index.js
|
|
31901
|
+
function createInfraServices(deps = {}) {
|
|
31902
|
+
const globalOptionsService = createGlobalOptionsService();
|
|
31903
|
+
const authService = createAuthService({ authPath: deps.authPath ?? DEFAULT_AUTH_PATH });
|
|
31904
|
+
return {
|
|
31905
|
+
authService,
|
|
31906
|
+
globalOptionsService
|
|
31907
|
+
};
|
|
31908
|
+
}
|
|
31512
31909
|
function readFleetConsoleRelease() {
|
|
31513
31910
|
const requireFromHere = createRequire(import.meta.url);
|
|
31514
31911
|
const packageJsonPath = requireFromHere.resolve("../package.json");
|
|
@@ -31522,17 +31919,34 @@ function readFleetConsoleRelease() {
|
|
|
31522
31919
|
}
|
|
31523
31920
|
|
|
31524
31921
|
// src/paths.ts
|
|
31525
|
-
var
|
|
31922
|
+
var LOCK_DIR_NAME2 = "fleet-console";
|
|
31923
|
+
var CONSOLE_RUNTIME_DIR_NAME = "console";
|
|
31526
31924
|
var LOCK_FILE_NAME = "console.lock";
|
|
31925
|
+
var CONSOLE_DATA_DIR_NAME = "console";
|
|
31926
|
+
var CONSOLE_STATE_FILE_NAME = "state.json";
|
|
31927
|
+
var CONSOLE_CAPTURES_DIR_NAME = "captures";
|
|
31527
31928
|
function createConsolePaths(deps = {}) {
|
|
31528
31929
|
const env = deps.env ?? process.env;
|
|
31529
31930
|
const base = env.FLEET_CONSOLE_DIR ?? defaultConsoleBaseDir(deps);
|
|
31530
31931
|
return { dir: base, lockFile: path93__default.join(base, LOCK_FILE_NAME) };
|
|
31531
31932
|
}
|
|
31933
|
+
function createConsoleDataPaths(deps = {}) {
|
|
31934
|
+
const dir = path93__default.join(deps.fleetDataDir ?? getFleetDataDir(), CONSOLE_DATA_DIR_NAME);
|
|
31935
|
+
return {
|
|
31936
|
+
dir,
|
|
31937
|
+
stateFile: path93__default.join(dir, CONSOLE_STATE_FILE_NAME),
|
|
31938
|
+
capturesDir: path93__default.join(dir, CONSOLE_CAPTURES_DIR_NAME)
|
|
31939
|
+
};
|
|
31940
|
+
}
|
|
31532
31941
|
function defaultConsoleBaseDir(deps) {
|
|
31942
|
+
let release;
|
|
31943
|
+
const channel = deps.channel ?? (release = readFleetConsoleRelease()).channel;
|
|
31944
|
+
if (channel === "local") {
|
|
31945
|
+
const packageRoot = deps.packageRoot ?? (release ??= readFleetConsoleRelease()).packageRoot;
|
|
31946
|
+
return path93__default.join(path93__default.resolve(packageRoot, "..", ".."), ".fleet", CONSOLE_RUNTIME_DIR_NAME);
|
|
31947
|
+
}
|
|
31533
31948
|
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}`);
|
|
31949
|
+
return path93__default.join(os22__default.tmpdir(), `${LOCK_DIR_NAME2}-${uid}-${channel}`);
|
|
31536
31950
|
}
|
|
31537
31951
|
var FLEET_PROTOCOL_GATE_PROMPT = String.raw`# Protocol Gate
|
|
31538
31952
|
|
|
@@ -31925,6 +32339,8 @@ function createClaudeFamilyCliDefinition(options) {
|
|
|
31925
32339
|
lineTerminator: "\r",
|
|
31926
32340
|
multilineStrategy: "paste-mode"
|
|
31927
32341
|
},
|
|
32342
|
+
// Claude Code 계열은 세션 이름 변경 슬래시 명령 `/rename`을 지원한다.
|
|
32343
|
+
renameCommand: "/rename",
|
|
31928
32344
|
terminalName: "xterm-256color"
|
|
31929
32345
|
};
|
|
31930
32346
|
}
|
|
@@ -31948,7 +32364,7 @@ var codexCli = {
|
|
|
31948
32364
|
async createProfile(options) {
|
|
31949
32365
|
const { bin, prefixArgs } = resolveBinary("codex", "CODEX_BIN", options.env);
|
|
31950
32366
|
return {
|
|
31951
|
-
args: [...prefixArgs, "--no-alt-screen", ...buildModelArgs2(options.model)],
|
|
32367
|
+
args: [...prefixArgs, ...buildResumeArgs(options.resumeSessionId), "--no-alt-screen", ...buildModelArgs2(options.model)],
|
|
31952
32368
|
bin,
|
|
31953
32369
|
binPrefixArgs: prefixArgs,
|
|
31954
32370
|
cwd: options.cwd,
|
|
@@ -31960,10 +32376,15 @@ var codexCli = {
|
|
|
31960
32376
|
lineTerminator: "\r",
|
|
31961
32377
|
multilineStrategy: "paste-mode"
|
|
31962
32378
|
},
|
|
32379
|
+
// Codex CLI도 세션 이름 변경 슬래시 명령 `/rename`을 지원한다.
|
|
32380
|
+
renameCommand: "/rename",
|
|
31963
32381
|
terminalName: "xterm-256color"
|
|
31964
32382
|
};
|
|
31965
32383
|
}
|
|
31966
32384
|
};
|
|
32385
|
+
function buildResumeArgs(resumeSessionId) {
|
|
32386
|
+
return resumeSessionId === void 0 ? [] : ["resume", resumeSessionId];
|
|
32387
|
+
}
|
|
31967
32388
|
function buildModelArgs2(model) {
|
|
31968
32389
|
return model === void 0 ? [] : ["--model", model];
|
|
31969
32390
|
}
|
|
@@ -31980,7 +32401,8 @@ async function resolveAgentCliProfile(env, cwd, options = {}) {
|
|
|
31980
32401
|
authService: options.authService,
|
|
31981
32402
|
cwd,
|
|
31982
32403
|
env,
|
|
31983
|
-
model: options.model
|
|
32404
|
+
model: options.model,
|
|
32405
|
+
resumeSessionId: options.resumeSessionId
|
|
31984
32406
|
});
|
|
31985
32407
|
}
|
|
31986
32408
|
function resolveAgentCliId(env, options = {}) {
|
|
@@ -32024,6 +32446,20 @@ var AGENT_CLI_INJECTION_CAPABILITIES = {
|
|
|
32024
32446
|
function getAgentCliInjectionCapability(cliId) {
|
|
32025
32447
|
return AGENT_CLI_INJECTION_CAPABILITIES[cliId];
|
|
32026
32448
|
}
|
|
32449
|
+
function createSessionCaptureHookExec(deps) {
|
|
32450
|
+
const args = deps.tsxLoader ? [
|
|
32451
|
+
"--import",
|
|
32452
|
+
pathToFileURL(deps.tsxLoader).href,
|
|
32453
|
+
deps.entryPath,
|
|
32454
|
+
"hook",
|
|
32455
|
+
"capture-session",
|
|
32456
|
+
deps.provider
|
|
32457
|
+
] : [deps.entryPath, "hook", "capture-session", deps.provider];
|
|
32458
|
+
return {
|
|
32459
|
+
command: deps.execPath ?? process6.execPath,
|
|
32460
|
+
args
|
|
32461
|
+
};
|
|
32462
|
+
}
|
|
32027
32463
|
function buildHostCarrierModelDefaults2(config2) {
|
|
32028
32464
|
const cliType = resolveAgentCliType2(config2.id, config2.defaultCliType);
|
|
32029
32465
|
const cliDefaults = buildCarrierModelDefaults(config2, cliType);
|
|
@@ -32053,6 +32489,7 @@ function buildClaudeNativeSubagentPlan2(registry3) {
|
|
|
32053
32489
|
function buildClaudeNativeArgs(context) {
|
|
32054
32490
|
const systemPromptArg = context.replaceSystemPrompt ? "--system-prompt-file" : "--append-system-prompt-file";
|
|
32055
32491
|
return [
|
|
32492
|
+
...buildResumeArgs2(context.resumeSessionId),
|
|
32056
32493
|
systemPromptArg,
|
|
32057
32494
|
requireSystemPromptFile(context),
|
|
32058
32495
|
...context.pluginRoots.flatMap((pluginRoot) => [
|
|
@@ -32063,6 +32500,9 @@ function buildClaudeNativeArgs(context) {
|
|
|
32063
32500
|
"--dangerously-skip-permissions"
|
|
32064
32501
|
];
|
|
32065
32502
|
}
|
|
32503
|
+
function buildResumeArgs2(resumeSessionId) {
|
|
32504
|
+
return resumeSessionId === void 0 ? [] : ["--resume", resumeSessionId];
|
|
32505
|
+
}
|
|
32066
32506
|
function buildClaudeMcpConfig(servers) {
|
|
32067
32507
|
return JSON.stringify({
|
|
32068
32508
|
mcpServers: Object.fromEntries(
|
|
@@ -32120,20 +32560,32 @@ function escapeTomlMultilineString(value) {
|
|
|
32120
32560
|
});
|
|
32121
32561
|
return result;
|
|
32122
32562
|
}
|
|
32563
|
+
function buildPosixShellCommand(values) {
|
|
32564
|
+
return values.map(posixShellQuote).join(" ");
|
|
32565
|
+
}
|
|
32566
|
+
function posixShellQuote(value) {
|
|
32567
|
+
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
32568
|
+
}
|
|
32123
32569
|
var CODEX_TOOL_TIMEOUT_SEC = 1800;
|
|
32124
32570
|
function buildCodexNativeArgs(context) {
|
|
32125
32571
|
const profileName = requireCodexProfileName(context);
|
|
32126
32572
|
const args = [
|
|
32573
|
+
...buildResumeArgs3(context.resumeSessionId),
|
|
32127
32574
|
"--enable",
|
|
32128
32575
|
"plugins",
|
|
32129
32576
|
"--enable",
|
|
32130
32577
|
"child_agents_md",
|
|
32578
|
+
"--enable",
|
|
32579
|
+
"hooks",
|
|
32131
32580
|
"--profile",
|
|
32132
32581
|
profileName,
|
|
32133
32582
|
"-c",
|
|
32134
32583
|
'approval_policy="never"',
|
|
32135
32584
|
"-c",
|
|
32136
|
-
'sandbox_mode="danger-full-access"'
|
|
32585
|
+
'sandbox_mode="danger-full-access"',
|
|
32586
|
+
// hook 신뢰 프롬프트("Hooks need review")를 fleet 관리 세션에서 건너뛴다. bypass_hook_trust는
|
|
32587
|
+
// config 키가 아니라 전용 CLI 플래그이므로 -c override가 아닌 플래그로 전달해야 한다.
|
|
32588
|
+
"--dangerously-bypass-hook-trust"
|
|
32137
32589
|
];
|
|
32138
32590
|
for (const server of context.mcpServers) {
|
|
32139
32591
|
const prefix = `mcp_servers.${server.name}`;
|
|
@@ -32149,6 +32601,9 @@ function buildCodexNativeArgs(context) {
|
|
|
32149
32601
|
}
|
|
32150
32602
|
return args;
|
|
32151
32603
|
}
|
|
32604
|
+
function buildResumeArgs3(resumeSessionId) {
|
|
32605
|
+
return resumeSessionId === void 0 ? [] : ["resume", resumeSessionId];
|
|
32606
|
+
}
|
|
32152
32607
|
function requireCodexProfileName(context) {
|
|
32153
32608
|
if (context.codexProfileName) return context.codexProfileName;
|
|
32154
32609
|
throw new Error("Codex profile name is required for native injection");
|
|
@@ -32359,20 +32814,38 @@ function claudeHooks(options) {
|
|
|
32359
32814
|
if (!hookExec) {
|
|
32360
32815
|
throw new Error("Fleet Claude session hook command is required");
|
|
32361
32816
|
}
|
|
32817
|
+
const userPromptSubmitExecs = [options.captureSessionHookExec, options.turnStartHookExec].filter((exec) => exec !== void 0);
|
|
32818
|
+
const stopExecs = [options.turnEndHookExec].filter((exec) => exec !== void 0);
|
|
32362
32819
|
return {
|
|
32363
32820
|
hooks: {
|
|
32364
32821
|
SessionStart: [{
|
|
32365
|
-
hooks: [
|
|
32366
|
-
|
|
32367
|
-
|
|
32368
|
-
|
|
32369
|
-
|
|
32370
|
-
|
|
32822
|
+
hooks: [claudeCommandHook(hookExec)]
|
|
32823
|
+
}],
|
|
32824
|
+
...userPromptSubmitExecs.length > 0 ? {
|
|
32825
|
+
UserPromptSubmit: [{
|
|
32826
|
+
hooks: userPromptSubmitExecs.map(claudeCommandHook)
|
|
32827
|
+
}]
|
|
32828
|
+
} : {},
|
|
32829
|
+
...stopExecs.length > 0 ? {
|
|
32830
|
+
Stop: [{
|
|
32831
|
+
hooks: stopExecs.map(claudeCommandHook)
|
|
32371
32832
|
}]
|
|
32372
|
-
}
|
|
32833
|
+
} : {}
|
|
32373
32834
|
}
|
|
32374
32835
|
};
|
|
32375
32836
|
}
|
|
32837
|
+
function claudeCommandHook(hookExec) {
|
|
32838
|
+
if (!hookExec) {
|
|
32839
|
+
throw new Error("Fleet Claude session hook command is required");
|
|
32840
|
+
}
|
|
32841
|
+
return {
|
|
32842
|
+
// exec 형식: command는 직접 spawn되는 실행 파일, args는 셸 토크나이징 없이 그대로 전달된다.
|
|
32843
|
+
// Windows cmd/powershell의 따옴표 규칙과 무관하게 동작하며 공백 포함 경로도 안전하다.
|
|
32844
|
+
args: [...hookExec.args],
|
|
32845
|
+
command: hookExec.command,
|
|
32846
|
+
type: "command"
|
|
32847
|
+
};
|
|
32848
|
+
}
|
|
32376
32849
|
function claudeAgentFile(subagent) {
|
|
32377
32850
|
const frontmatter = [
|
|
32378
32851
|
"---",
|
|
@@ -32882,7 +33355,7 @@ function homeMarketplaceTarget(fleetRoot) {
|
|
|
32882
33355
|
}
|
|
32883
33356
|
function projectMarketplaceTarget(cwd) {
|
|
32884
33357
|
const projectFleetRoot = resolveProjectFleetRoot(cwd);
|
|
32885
|
-
const hash2 =
|
|
33358
|
+
const hash2 = crypto5.createHash("sha256").update(path93__default.resolve(cwd, ".fleet")).digest("hex").slice(0, 12);
|
|
32886
33359
|
return {
|
|
32887
33360
|
flat: true,
|
|
32888
33361
|
name: `${FLEET_PROJECT_MARKETPLACE_NAME_PREFIX}-${hash2}`,
|
|
@@ -32908,7 +33381,6 @@ function renderPluginRoot(pluginRoot, bundle, options, fleetRoot) {
|
|
|
32908
33381
|
const stagedPluginRoot = path93__default.join(stageParent, path93__default.basename(pluginRoot));
|
|
32909
33382
|
try {
|
|
32910
33383
|
ensurePrivateDir(stagedPluginRoot, stagedPluginRoot);
|
|
32911
|
-
writePrivateJson(path93__default.join(stagedPluginRoot, ".codex-plugin", "plugin.json"), codexManifest(bundle), stagedPluginRoot);
|
|
32912
33384
|
writePrivateJson(path93__default.join(stagedPluginRoot, ".claude-plugin", "plugin.json"), claudeManifest(bundle), stagedPluginRoot);
|
|
32913
33385
|
switch (bundle.source) {
|
|
32914
33386
|
case "asset":
|
|
@@ -32923,6 +33395,7 @@ function renderPluginRoot(pluginRoot, bundle, options, fleetRoot) {
|
|
|
32923
33395
|
renderGlobalPluginRoot(stagedPluginRoot, fleetRoot);
|
|
32924
33396
|
break;
|
|
32925
33397
|
}
|
|
33398
|
+
writePrivateJson(path93__default.join(stagedPluginRoot, ".codex-plugin", "plugin.json"), codexManifest(bundle, stagedPluginRoot), stagedPluginRoot);
|
|
32926
33399
|
removePrivatePath(pluginRoot, parentRoot);
|
|
32927
33400
|
renameSync(stagedPluginRoot, pluginRoot);
|
|
32928
33401
|
} finally {
|
|
@@ -32951,7 +33424,7 @@ function pruneMarketplaceRoot(target) {
|
|
|
32951
33424
|
}
|
|
32952
33425
|
}
|
|
32953
33426
|
function buildContentHash(target) {
|
|
32954
|
-
const hash2 =
|
|
33427
|
+
const hash2 = crypto5.createHash("sha256");
|
|
32955
33428
|
for (const filePath of listRenderableFiles(target)) {
|
|
32956
33429
|
const relativePath2 = path93__default.relative(target.root, filePath);
|
|
32957
33430
|
hash2.update(relativePath2);
|
|
@@ -33054,14 +33527,36 @@ function marketplacePluginPath(target, bundle) {
|
|
|
33054
33527
|
if (target.flat) return `./${FLAT_PLUGIN_DIR_NAME}`;
|
|
33055
33528
|
return `./${PLUGIN_BUNDLES_DIR_NAME}/${bundle.directoryName}`;
|
|
33056
33529
|
}
|
|
33057
|
-
function codexManifest(bundle) {
|
|
33530
|
+
function codexManifest(bundle, pluginRoot) {
|
|
33058
33531
|
return {
|
|
33059
33532
|
name: bundle.name,
|
|
33060
|
-
version:
|
|
33533
|
+
version: codexManifestVersion(bundle, pluginRoot),
|
|
33061
33534
|
description: bundle.description,
|
|
33062
33535
|
skills: "./skills/"
|
|
33063
33536
|
};
|
|
33064
33537
|
}
|
|
33538
|
+
function codexManifestVersion(bundle, pluginRoot) {
|
|
33539
|
+
const hash2 = crypto5.createHash("sha256");
|
|
33540
|
+
hash2.update(bundle.name);
|
|
33541
|
+
hash2.update("\0");
|
|
33542
|
+
hash2.update(bundle.description);
|
|
33543
|
+
hash2.update("\0");
|
|
33544
|
+
for (const filePath of listCodexEffectivePluginFiles(pluginRoot)) {
|
|
33545
|
+
const relativePath2 = path93__default.relative(pluginRoot, filePath);
|
|
33546
|
+
hash2.update(relativePath2);
|
|
33547
|
+
hash2.update("\0");
|
|
33548
|
+
hash2.update(readFileSync(filePath));
|
|
33549
|
+
hash2.update("\0");
|
|
33550
|
+
}
|
|
33551
|
+
return `0.0.0+${hash2.digest("hex").slice(0, 12)}`;
|
|
33552
|
+
}
|
|
33553
|
+
function listCodexEffectivePluginFiles(pluginRoot) {
|
|
33554
|
+
const skillsPath = path93__default.join(pluginRoot, "skills");
|
|
33555
|
+
if (!existsSync(skillsPath)) return [];
|
|
33556
|
+
const files = [];
|
|
33557
|
+
collectRenderableFiles(pluginRoot, skillsPath, files, /* @__PURE__ */ new Set());
|
|
33558
|
+
return files.sort();
|
|
33559
|
+
}
|
|
33065
33560
|
function claudeManifest(bundle) {
|
|
33066
33561
|
return {
|
|
33067
33562
|
name: bundle.name,
|
|
@@ -33081,7 +33576,7 @@ async function injectAgentCliProfile(profile, options) {
|
|
|
33081
33576
|
const injectTone = options.enableMetaphor ?? false;
|
|
33082
33577
|
const endpoint = await options.dedicatedMcpSession.getEndpoint();
|
|
33083
33578
|
const startupDefinitions = buildStartupNativeDefinitions(profile.id, options.carrierRuntime);
|
|
33084
|
-
const tokenLabel = options.mcpSessionLabel ?? `agent:${profile.id}:${
|
|
33579
|
+
const tokenLabel = options.mcpSessionLabel ?? `agent:${profile.id}:${crypto5.randomUUID()}`;
|
|
33085
33580
|
const tokens = await options.dedicatedMcpSession.issueSessionToken({ cwd: profile.cwd, label: tokenLabel });
|
|
33086
33581
|
const mcpServers = buildAgentCliMcpServerConfigs(endpoint.servers, tokens);
|
|
33087
33582
|
const doctrine = options.buildSystemPrompt(injectTone);
|
|
@@ -33095,11 +33590,18 @@ async function injectAgentCliProfile(profile, options) {
|
|
|
33095
33590
|
cwd: profile.cwd,
|
|
33096
33591
|
dataDir: options.dataDir,
|
|
33097
33592
|
rootDir: options.pluginRootDir,
|
|
33593
|
+
captureSessionHookExec: options.captureSessionHookExec,
|
|
33594
|
+
turnStartHookExec: options.turnStartHookExec,
|
|
33595
|
+
turnEndHookExec: options.turnEndHookExec,
|
|
33098
33596
|
hookExec: startupDefinitions.host === "claude" ? requireHookExec(options.hookExec) : void 0,
|
|
33099
33597
|
withMarketplaceLock: options.withMarketplaceLock
|
|
33100
33598
|
});
|
|
33101
33599
|
const codexPluginKeys = plugin.codexRegistrations.map((registration) => `${registration.pluginName}@${registration.marketplaceName}`);
|
|
33102
|
-
const codexProfile = profile.id === "codex" ? writeCodexFleetProfile(profile.env, doctrine, codexPluginKeys,
|
|
33600
|
+
const codexProfile = profile.id === "codex" ? writeCodexFleetProfile(profile.env, doctrine, codexPluginKeys, {
|
|
33601
|
+
captureSessionHookExec: options.captureSessionHookExec,
|
|
33602
|
+
turnStartHookExec: options.turnStartHookExec,
|
|
33603
|
+
turnEndHookExec: options.turnEndHookExec
|
|
33604
|
+
}, (cleanup2) => tempCleanups.push(cleanup2)) : void 0;
|
|
33103
33605
|
const launchWarnings = [];
|
|
33104
33606
|
for (const registration of plugin.codexRegistrations) {
|
|
33105
33607
|
const registrationWarning = await ensureCodexPluginRegistered(registration, {
|
|
@@ -33126,13 +33628,14 @@ async function injectAgentCliProfile(profile, options) {
|
|
|
33126
33628
|
pluginRoot: plugin.pluginRoot,
|
|
33127
33629
|
pluginRoots: plugin.pluginRoots,
|
|
33128
33630
|
codexProfileName: codexProfile?.profileName,
|
|
33129
|
-
replaceSystemPrompt: options.replaceSystemPrompt ??
|
|
33631
|
+
replaceSystemPrompt: options.replaceSystemPrompt ?? false,
|
|
33632
|
+
resumeSessionId: options.resumeSessionId,
|
|
33130
33633
|
systemPromptFile
|
|
33131
33634
|
};
|
|
33132
33635
|
const injectedArgs = buildAgentCliArgs(capability.builderId, context);
|
|
33133
33636
|
return {
|
|
33134
33637
|
...profile,
|
|
33135
|
-
args:
|
|
33638
|
+
args: mergeAgentCliArgs(profile, capability.builderId, context, injectedArgs),
|
|
33136
33639
|
cleanup,
|
|
33137
33640
|
launchWarnings: [...profile.launchWarnings ?? [], ...launchWarnings]
|
|
33138
33641
|
};
|
|
@@ -33174,11 +33677,11 @@ function writeSystemPromptFile(cliId, systemPrompt, onCleanup) {
|
|
|
33174
33677
|
chmodBestEffort2(filePath, SYSTEM_PROMPT_FILE_MODE);
|
|
33175
33678
|
return filePath;
|
|
33176
33679
|
}
|
|
33177
|
-
function writeCodexFleetProfile(env, doctrine, pluginKeys, onCleanup) {
|
|
33680
|
+
function writeCodexFleetProfile(env, doctrine, pluginKeys, hookExecs, onCleanup) {
|
|
33178
33681
|
const codexHome = env.CODEX_HOME ?? path93__default.join(env.HOME ?? os22__default.homedir(), ".codex");
|
|
33179
33682
|
mkdirSync(codexHome, { recursive: true });
|
|
33180
33683
|
pruneStaleCodexFleetProfiles(codexHome);
|
|
33181
|
-
const profileName = `fleet-${
|
|
33684
|
+
const profileName = `fleet-${crypto5.randomUUID()}`;
|
|
33182
33685
|
const profilePath = path93__default.join(codexHome, `${profileName}.config.toml`);
|
|
33183
33686
|
onCleanup(() => rmBestEffort(profilePath));
|
|
33184
33687
|
writeFileNoFollow2(profilePath, [
|
|
@@ -33193,11 +33696,33 @@ function writeCodexFleetProfile(env, doctrine, pluginKeys, onCleanup) {
|
|
|
33193
33696
|
`[plugins."${escapeTomlBasicString2(pluginKey)}"]`,
|
|
33194
33697
|
"enabled = true",
|
|
33195
33698
|
""
|
|
33196
|
-
])
|
|
33699
|
+
]),
|
|
33700
|
+
...codexHooksConfig(hookExecs)
|
|
33197
33701
|
].join("\n"));
|
|
33198
33702
|
chmodBestEffort2(profilePath, SYSTEM_PROMPT_FILE_MODE);
|
|
33199
33703
|
return { profileName, profilePath };
|
|
33200
33704
|
}
|
|
33705
|
+
function codexHooksConfig(hookExecs) {
|
|
33706
|
+
const userPromptSubmitExecs = [hookExecs.captureSessionHookExec, hookExecs.turnStartHookExec].filter((exec) => exec !== void 0);
|
|
33707
|
+
const stopExecs = [hookExecs.turnEndHookExec].filter((exec) => exec !== void 0);
|
|
33708
|
+
if (userPromptSubmitExecs.length === 0 && stopExecs.length === 0) return [];
|
|
33709
|
+
const lines = ["[hooks]"];
|
|
33710
|
+
if (userPromptSubmitExecs.length > 0) {
|
|
33711
|
+
lines.push(`UserPromptSubmit = ${codexHookHandlersInline(userPromptSubmitExecs)}`);
|
|
33712
|
+
}
|
|
33713
|
+
if (stopExecs.length > 0) {
|
|
33714
|
+
lines.push(`Stop = ${codexHookHandlersInline(stopExecs)}`);
|
|
33715
|
+
}
|
|
33716
|
+
lines.push("");
|
|
33717
|
+
return lines;
|
|
33718
|
+
}
|
|
33719
|
+
function codexHookHandlersInline(execs) {
|
|
33720
|
+
const handlers = execs.map((exec) => {
|
|
33721
|
+
const command2 = buildPosixShellCommand([exec.command, ...exec.args]);
|
|
33722
|
+
return `{ type = "command", command = "${escapeTomlBasicString2(command2)}" }`;
|
|
33723
|
+
}).join(", ");
|
|
33724
|
+
return `[{ hooks = [${handlers}] }]`;
|
|
33725
|
+
}
|
|
33201
33726
|
function writeFileNoFollow2(filePath, content) {
|
|
33202
33727
|
const flags = constants.O_WRONLY | constants.O_CREAT | constants.O_TRUNC | constants.O_NOFOLLOW;
|
|
33203
33728
|
const fd = openSync(filePath, flags, SYSTEM_PROMPT_FILE_MODE);
|
|
@@ -33270,6 +33795,24 @@ function buildAgentCliArgs(builderId, context) {
|
|
|
33270
33795
|
return buildCodexNativeArgs(context);
|
|
33271
33796
|
}
|
|
33272
33797
|
}
|
|
33798
|
+
function mergeAgentCliArgs(profile, builderId, context, injectedArgs) {
|
|
33799
|
+
if (builderId !== "codex-native" || context.resumeSessionId === void 0) {
|
|
33800
|
+
return [...profile.args, ...injectedArgs];
|
|
33801
|
+
}
|
|
33802
|
+
const resumeSessionId = context.resumeSessionId;
|
|
33803
|
+
const prefixLength = profile.binPrefixArgs?.length ?? 0;
|
|
33804
|
+
const codexResumeArgs = ["resume", resumeSessionId];
|
|
33805
|
+
const injectedTail = injectedArgs.slice(codexResumeArgs.length);
|
|
33806
|
+
return [
|
|
33807
|
+
...profile.args.slice(0, prefixLength),
|
|
33808
|
+
...codexResumeArgs,
|
|
33809
|
+
...profile.args.slice(prefixLength).filter((arg, index, args) => !isCodexResumeArgAt(args, index, resumeSessionId)),
|
|
33810
|
+
...injectedTail
|
|
33811
|
+
];
|
|
33812
|
+
}
|
|
33813
|
+
function isCodexResumeArgAt(args, index, resumeSessionId) {
|
|
33814
|
+
return args[index] === "resume" && args[index + 1] === resumeSessionId || args[index] === resumeSessionId && args[index - 1] === "resume";
|
|
33815
|
+
}
|
|
33273
33816
|
function createOnceCleanup(cleanup) {
|
|
33274
33817
|
let cleaned = false;
|
|
33275
33818
|
return () => {
|
|
@@ -33453,389 +33996,6 @@ function applyMessagePolicy(text, policy) {
|
|
|
33453
33996
|
submit: policy.lineTerminator
|
|
33454
33997
|
};
|
|
33455
33998
|
}
|
|
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
33999
|
var FLEET_WIKI_ENTRY_BEGIN = "<<<FLEET_WIKI_ENTRY_BEGIN";
|
|
33840
34000
|
var FLEET_WIKI_ENTRY_END = "<<<FLEET_WIKI_ENTRY_END>>>";
|
|
33841
34001
|
var FLEET_WIKI_RAW_SOURCE_BEGIN = "<<<FLEET_WIKI_RAW_SOURCE_BEGIN";
|
|
@@ -34862,7 +35022,7 @@ function stripLeadingFrontmatter(body) {
|
|
|
34862
35022
|
return stripped ? next : body;
|
|
34863
35023
|
}
|
|
34864
35024
|
function computeContentHash(content) {
|
|
34865
|
-
return
|
|
35025
|
+
return crypto5.createHash("sha256").update(content, "utf8").digest("hex").slice(0, 8);
|
|
34866
35026
|
}
|
|
34867
35027
|
function assertWithinRawDir(absolutePath, paths) {
|
|
34868
35028
|
const relative = path93__default.relative(paths.rawDir, absolutePath);
|
|
@@ -35075,7 +35235,7 @@ async function writeAtomic(filePath, content, paths) {
|
|
|
35075
35235
|
await ensureMemoryRoot(paths);
|
|
35076
35236
|
const tempPath = path93__default.join(
|
|
35077
35237
|
path93__default.dirname(filePath),
|
|
35078
|
-
`.tmp-${process.pid}-${Date.now()}-${
|
|
35238
|
+
`.tmp-${process.pid}-${Date.now()}-${crypto5.randomUUID()}-${os22__default.hostname()}`
|
|
35079
35239
|
);
|
|
35080
35240
|
await writeFile(tempPath, content, "utf8");
|
|
35081
35241
|
await rename(tempPath, filePath);
|
|
@@ -37612,7 +37772,7 @@ function parseOptionalIsoDate(value) {
|
|
|
37612
37772
|
return Number.isFinite(timestamp) ? timestamp : null;
|
|
37613
37773
|
}
|
|
37614
37774
|
function hashBodyForComparison(body) {
|
|
37615
|
-
return
|
|
37775
|
+
return crypto5.createHash("sha256").update(body.replace(/\s+/g, " ").trim(), "utf8").digest("hex").slice(0, 8);
|
|
37616
37776
|
}
|
|
37617
37777
|
function hasConflictingStatuses(entries) {
|
|
37618
37778
|
const statuses = new Set(entries.map((entry) => entry.status).filter((status) => status !== "unknown"));
|
|
@@ -39795,6 +39955,420 @@ function buildWikiToolSpec(config2, usage) {
|
|
|
39795
39955
|
};
|
|
39796
39956
|
}
|
|
39797
39957
|
|
|
39958
|
+
// src/carrier-settings-routes.ts
|
|
39959
|
+
var SUBAGENT_CLI_TYPES = /* @__PURE__ */ new Set(["claude", "claude-zai", "claude-kimi"]);
|
|
39960
|
+
var TASKFORCE_MIN_BACKENDS = 2;
|
|
39961
|
+
function createCarrierSettingsRouter(deps) {
|
|
39962
|
+
const controller = createStatusOverlayController(deps.registry);
|
|
39963
|
+
return async function handleCarrierSettingsRoute(context) {
|
|
39964
|
+
const { req, res, pathname } = context;
|
|
39965
|
+
if (pathname === "/carrier-settings/state") {
|
|
39966
|
+
if (req.method !== "GET") {
|
|
39967
|
+
deps.writeJson(res, 405, { error: "Method not allowed" });
|
|
39968
|
+
return true;
|
|
39969
|
+
}
|
|
39970
|
+
deps.writeJson(res, 200, buildCarrierSettingsState(deps.registry));
|
|
39971
|
+
return true;
|
|
39972
|
+
}
|
|
39973
|
+
if (pathname === "/carrier-settings/options") {
|
|
39974
|
+
if (req.method !== "GET") {
|
|
39975
|
+
deps.writeJson(res, 405, { error: "Method not allowed" });
|
|
39976
|
+
return true;
|
|
39977
|
+
}
|
|
39978
|
+
deps.writeJson(res, 200, buildCarrierSettingsOptions());
|
|
39979
|
+
return true;
|
|
39980
|
+
}
|
|
39981
|
+
const mutation = parseCarrierMutation(pathname);
|
|
39982
|
+
if (!mutation) return false;
|
|
39983
|
+
await handleCarrierMutation(req, res, deps, controller, mutation);
|
|
39984
|
+
return true;
|
|
39985
|
+
};
|
|
39986
|
+
}
|
|
39987
|
+
function buildCarrierSettingsState(registry3) {
|
|
39988
|
+
const defaultsByCarrier = buildDefaultsByCarrier(registry3);
|
|
39989
|
+
const snapshot = readCarriersSnapshot(defaultsByCarrier);
|
|
39990
|
+
return {
|
|
39991
|
+
generation: snapshot.generation,
|
|
39992
|
+
carriers: getRegisteredOrder(registry3).map((carrierId) => {
|
|
39993
|
+
const config2 = requireCarrierConfig(registry3, carrierId);
|
|
39994
|
+
const resolved = snapshot.carriers[carrierId] ?? fallbackResolvedState(config2);
|
|
39995
|
+
return toCarrierSettingsCarrier(registry3, config2, resolved);
|
|
39996
|
+
})
|
|
39997
|
+
};
|
|
39998
|
+
}
|
|
39999
|
+
function buildCarrierSettingsOptions() {
|
|
40000
|
+
return {
|
|
40001
|
+
cliTypes: getCliTypes().map(toCliOption),
|
|
40002
|
+
taskForceConstraints: { minBackends: TASKFORCE_MIN_BACKENDS }
|
|
40003
|
+
};
|
|
40004
|
+
}
|
|
40005
|
+
async function handleCarrierMutation(req, res, deps, controller, mutation) {
|
|
40006
|
+
const method = req.method ?? "GET";
|
|
40007
|
+
const expectedMethod = mutation.kind === "display-name" ? "PATCH" : mutation.kind === "taskforce-backend" || mutation.kind === "taskforce-all" ? method : "PUT";
|
|
40008
|
+
if (!isExpectedCarrierMethod(mutation, method, expectedMethod)) {
|
|
40009
|
+
deps.writeJson(res, 405, { error: "Method not allowed" });
|
|
40010
|
+
return;
|
|
40011
|
+
}
|
|
40012
|
+
if (!deps.isAuthorized(req)) {
|
|
40013
|
+
deps.writeJson(res, 401, { error: "unauthorized" });
|
|
40014
|
+
return;
|
|
40015
|
+
}
|
|
40016
|
+
if (!isJsonRequest(req)) {
|
|
40017
|
+
deps.writeJson(res, 415, { error: "unsupported_media_type" });
|
|
40018
|
+
return;
|
|
40019
|
+
}
|
|
40020
|
+
if (!getRegisteredCarrierConfig(deps.registry, mutation.carrierId)) {
|
|
40021
|
+
deps.writeJson(res, 404, { error: "carrier_not_found" });
|
|
40022
|
+
return;
|
|
40023
|
+
}
|
|
40024
|
+
if (mutation.kind === "taskforce-backend" && !isCliType(mutation.cliType)) {
|
|
40025
|
+
deps.writeJson(res, 400, { error: "invalid_cli_type" });
|
|
40026
|
+
return;
|
|
40027
|
+
}
|
|
40028
|
+
try {
|
|
40029
|
+
if (mutation.kind === "cli") {
|
|
40030
|
+
const body2 = await readRequiredJsonBody(req, res, deps);
|
|
40031
|
+
if (!body2.ok) return;
|
|
40032
|
+
await mutateCarrierCli(res, deps, controller, mutation.carrierId, body2.body);
|
|
40033
|
+
return;
|
|
40034
|
+
}
|
|
40035
|
+
if (mutation.kind === "model") {
|
|
40036
|
+
const body2 = await readRequiredJsonBody(req, res, deps);
|
|
40037
|
+
if (!body2.ok) return;
|
|
40038
|
+
await mutateCarrierModel(res, deps, mutation.carrierId, body2.body);
|
|
40039
|
+
return;
|
|
40040
|
+
}
|
|
40041
|
+
if (mutation.kind === "display-name") {
|
|
40042
|
+
const body2 = await readRequiredJsonBody(req, res, deps);
|
|
40043
|
+
if (!body2.ok) return;
|
|
40044
|
+
mutateDisplayName(res, deps, mutation.carrierId, body2.body);
|
|
40045
|
+
return;
|
|
40046
|
+
}
|
|
40047
|
+
if (mutation.kind === "agent-mode") {
|
|
40048
|
+
const body2 = await readRequiredJsonBody(req, res, deps);
|
|
40049
|
+
if (!body2.ok) return;
|
|
40050
|
+
mutateAgentMode(res, deps, mutation.carrierId, body2.body);
|
|
40051
|
+
return;
|
|
40052
|
+
}
|
|
40053
|
+
if (mutation.kind === "taskforce-backend") {
|
|
40054
|
+
if (method === "DELETE") {
|
|
40055
|
+
const body3 = await readRequiredJsonBody(req, res, deps);
|
|
40056
|
+
if (!body3.ok) return;
|
|
40057
|
+
resetTaskForceModelSelection(mutation.carrierId, mutation.cliType);
|
|
40058
|
+
refreshTaskForceConfiguredCarriers(deps.registry);
|
|
40059
|
+
writeMutationState(res, deps);
|
|
40060
|
+
return;
|
|
40061
|
+
}
|
|
40062
|
+
const body2 = await readRequiredJsonBody(req, res, deps);
|
|
40063
|
+
if (!body2.ok) return;
|
|
40064
|
+
mutateTaskForceBackend(res, deps, mutation.carrierId, mutation.cliType, body2.body);
|
|
40065
|
+
return;
|
|
40066
|
+
}
|
|
40067
|
+
const body = await readRequiredJsonBody(req, res, deps);
|
|
40068
|
+
if (!body.ok) return;
|
|
40069
|
+
resetCarrierTaskForceConfig(mutation.carrierId);
|
|
40070
|
+
refreshTaskForceConfiguredCarriers(deps.registry);
|
|
40071
|
+
writeMutationState(res, deps);
|
|
40072
|
+
} catch (error51) {
|
|
40073
|
+
deps.writeJson(res, 400, { error: error51 instanceof Error ? error51.message : "invalid_request" });
|
|
40074
|
+
}
|
|
40075
|
+
}
|
|
40076
|
+
async function mutateCarrierCli(res, deps, controller, carrierId, body) {
|
|
40077
|
+
const cliType = readCliType(body.cliType);
|
|
40078
|
+
if (!cliType) {
|
|
40079
|
+
deps.writeJson(res, 400, { error: "invalid_cli_type" });
|
|
40080
|
+
return;
|
|
40081
|
+
}
|
|
40082
|
+
await controller.changeCliType(carrierId, cliType);
|
|
40083
|
+
if (!SUBAGENT_CLI_TYPES.has(cliType)) {
|
|
40084
|
+
const resolved = readCarriersSnapshot(buildDefaultsByCarrier(deps.registry)).carriers[carrierId];
|
|
40085
|
+
if (resolved?.agentMode === "subagent") {
|
|
40086
|
+
const config2 = requireCarrierConfig(deps.registry, carrierId);
|
|
40087
|
+
updateCarrierAgentModeAtomically(carrierId, "cli", config2.defaultAgentMode ?? "cli");
|
|
40088
|
+
}
|
|
40089
|
+
}
|
|
40090
|
+
writeMutationState(res, deps);
|
|
40091
|
+
}
|
|
40092
|
+
async function mutateCarrierModel(res, deps, carrierId, body) {
|
|
40093
|
+
const config2 = requireCarrierConfig(deps.registry, carrierId);
|
|
40094
|
+
const cliType = resolveAgentCliType2(carrierId, config2.defaultCliType);
|
|
40095
|
+
const selection = readSelection(cliType, body);
|
|
40096
|
+
if (!selection) {
|
|
40097
|
+
deps.writeJson(res, 400, { error: "invalid_model_selection" });
|
|
40098
|
+
return;
|
|
40099
|
+
}
|
|
40100
|
+
await updateAgentCliSelection(carrierId, cliType, selection);
|
|
40101
|
+
notifyStatusUpdate(deps.registry);
|
|
40102
|
+
writeMutationState(res, deps);
|
|
40103
|
+
}
|
|
40104
|
+
function mutateDisplayName(res, deps, carrierId, body) {
|
|
40105
|
+
const displayName = normalizeCarrierDisplayNameInput(body.displayName);
|
|
40106
|
+
if (displayName === null) {
|
|
40107
|
+
deps.writeJson(res, 400, { error: "invalid_display_name" });
|
|
40108
|
+
return;
|
|
40109
|
+
}
|
|
40110
|
+
updateCarrierDisplayName(carrierId, displayName, getCarrierSourceDisplayName(deps.registry, carrierId));
|
|
40111
|
+
notifyStatusUpdate(deps.registry);
|
|
40112
|
+
writeMutationState(res, deps);
|
|
40113
|
+
}
|
|
40114
|
+
function mutateAgentMode(res, deps, carrierId, body) {
|
|
40115
|
+
const config2 = requireCarrierConfig(deps.registry, carrierId);
|
|
40116
|
+
const agentMode = body.agentMode;
|
|
40117
|
+
if (agentMode !== "cli" && agentMode !== "subagent") {
|
|
40118
|
+
deps.writeJson(res, 400, { error: "invalid_agent_mode" });
|
|
40119
|
+
return;
|
|
40120
|
+
}
|
|
40121
|
+
const cliType = resolveAgentCliType2(carrierId, config2.defaultCliType);
|
|
40122
|
+
if (agentMode === "subagent" && !SUBAGENT_CLI_TYPES.has(cliType)) {
|
|
40123
|
+
deps.writeJson(res, 400, { error: "subagent_unsupported" });
|
|
40124
|
+
return;
|
|
40125
|
+
}
|
|
40126
|
+
updateCarrierAgentModeAtomically(carrierId, agentMode, config2.defaultAgentMode ?? "cli");
|
|
40127
|
+
if (agentMode === "subagent") refreshTaskForceConfiguredCarriers(deps.registry);
|
|
40128
|
+
notifyStatusUpdate(deps.registry);
|
|
40129
|
+
writeMutationState(res, deps);
|
|
40130
|
+
}
|
|
40131
|
+
function mutateTaskForceBackend(res, deps, carrierId, cliType, body) {
|
|
40132
|
+
const selection = readSelection(cliType, body);
|
|
40133
|
+
if (!selection) {
|
|
40134
|
+
deps.writeJson(res, 400, { error: "invalid_model_selection" });
|
|
40135
|
+
return;
|
|
40136
|
+
}
|
|
40137
|
+
updateTaskForceBackendAtomically(carrierId, cliType, selection);
|
|
40138
|
+
refreshTaskForceConfiguredCarriers(deps.registry);
|
|
40139
|
+
notifyStatusUpdate(deps.registry);
|
|
40140
|
+
writeMutationState(res, deps);
|
|
40141
|
+
}
|
|
40142
|
+
function writeMutationState(res, deps) {
|
|
40143
|
+
const response = { state: buildCarrierSettingsState(deps.registry) };
|
|
40144
|
+
deps.writeJson(res, 200, response);
|
|
40145
|
+
}
|
|
40146
|
+
async function readRequiredJsonBody(req, res, deps) {
|
|
40147
|
+
const body = await deps.readJsonBody(req);
|
|
40148
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) {
|
|
40149
|
+
deps.writeJson(res, 400, { error: "invalid_json" });
|
|
40150
|
+
return { ok: false };
|
|
40151
|
+
}
|
|
40152
|
+
return { ok: true, body };
|
|
40153
|
+
}
|
|
40154
|
+
function buildDefaultsByCarrier(registry3) {
|
|
40155
|
+
return Object.fromEntries(
|
|
40156
|
+
getRegisteredOrder(registry3).map((carrierId) => {
|
|
40157
|
+
const config2 = requireCarrierConfig(registry3, carrierId);
|
|
40158
|
+
return [carrierId, {
|
|
40159
|
+
cliType: config2.defaultCliType,
|
|
40160
|
+
...config2.defaultAgentMode ? { defaultAgentMode: config2.defaultAgentMode } : {},
|
|
40161
|
+
...buildCarrierModelDefaults(config2, config2.defaultCliType)
|
|
40162
|
+
}];
|
|
40163
|
+
})
|
|
40164
|
+
);
|
|
40165
|
+
}
|
|
40166
|
+
function toCarrierSettingsCarrier(registry3, config2, resolved) {
|
|
40167
|
+
const cliType = resolved.agentCliType ?? config2.defaultCliType;
|
|
40168
|
+
const selection = resolved.agentCli[cliType] ?? readDefaultSelection(cliType);
|
|
40169
|
+
const taskForceBackends = toTaskForceBackends(resolved.taskforce);
|
|
40170
|
+
return {
|
|
40171
|
+
carrierId: config2.id,
|
|
40172
|
+
displayName: resolved.displayName ?? getCarrierSourceDisplayName(registry3, config2.id),
|
|
40173
|
+
sourceDisplayName: getCarrierSourceDisplayName(registry3, config2.id),
|
|
40174
|
+
role: config2.carrierMetadata?.title ?? config2.displayName,
|
|
40175
|
+
roleDescription: config2.carrierMetadata?.summary ?? "",
|
|
40176
|
+
...config2.carrierMetadata?.category ? { category: config2.carrierMetadata.category } : {},
|
|
40177
|
+
slot: config2.slot,
|
|
40178
|
+
cliType,
|
|
40179
|
+
defaultCliType: config2.defaultCliType,
|
|
40180
|
+
model: selection.model,
|
|
40181
|
+
...selection.effort ? { effort: selection.effort } : {},
|
|
40182
|
+
agentMode: resolved.agentMode,
|
|
40183
|
+
subagentMode: resolved.agentMode === "subagent",
|
|
40184
|
+
taskForceBackendCount: taskForceBackends.length,
|
|
40185
|
+
taskforce: { backends: taskForceBackends }
|
|
40186
|
+
};
|
|
40187
|
+
}
|
|
40188
|
+
function toTaskForceBackends(taskforce) {
|
|
40189
|
+
return TASKFORCE_CLI_TYPES.map((cliType) => {
|
|
40190
|
+
const selection = taskforce[cliType];
|
|
40191
|
+
if (!selection) return null;
|
|
40192
|
+
return {
|
|
40193
|
+
cliType,
|
|
40194
|
+
model: selection.model,
|
|
40195
|
+
...selection.effort ? { effort: selection.effort } : {}
|
|
40196
|
+
};
|
|
40197
|
+
}).filter((backend) => backend !== null);
|
|
40198
|
+
}
|
|
40199
|
+
function toCliOption(cliType) {
|
|
40200
|
+
const provider = getProviderModels(cliType);
|
|
40201
|
+
return {
|
|
40202
|
+
id: cliType,
|
|
40203
|
+
displayName: CLI_DISPLAY_NAMES[cliType] ?? provider.name,
|
|
40204
|
+
supportsSubagent: SUBAGENT_CLI_TYPES.has(cliType),
|
|
40205
|
+
models: provider.models.map((model) => {
|
|
40206
|
+
const effort = getEffort(cliType, model.modelId);
|
|
40207
|
+
return {
|
|
40208
|
+
modelId: model.modelId,
|
|
40209
|
+
name: model.name,
|
|
40210
|
+
...effort.supported ? { effort: { levels: effort.levels, default: effort.default } } : {}
|
|
40211
|
+
};
|
|
40212
|
+
}),
|
|
40213
|
+
defaultModel: provider.defaultModel ?? provider.models[0]?.modelId
|
|
40214
|
+
};
|
|
40215
|
+
}
|
|
40216
|
+
function createStatusOverlayController(registry3) {
|
|
40217
|
+
return new StatusOverlayController({
|
|
40218
|
+
getEntries: () => [],
|
|
40219
|
+
getRegisteredOrder: () => getRegisteredOrder(registry3),
|
|
40220
|
+
getCarrierConfig: (carrierId) => getRegisteredCarrierConfig(registry3, carrierId),
|
|
40221
|
+
getResolvedCliType: (carrierId) => {
|
|
40222
|
+
const config2 = getRegisteredCarrierConfig(registry3, carrierId);
|
|
40223
|
+
return config2 ? resolveAgentCliType2(carrierId, config2.defaultCliType) : void 0;
|
|
40224
|
+
},
|
|
40225
|
+
getCurrentModelSelection: (carrierId) => {
|
|
40226
|
+
return readCurrentModelSelection(registry3, carrierId);
|
|
40227
|
+
},
|
|
40228
|
+
getAvailableModels: (cliType) => {
|
|
40229
|
+
const provider = getProviderModels(cliType);
|
|
40230
|
+
return {
|
|
40231
|
+
defaultModel: provider.defaultModel,
|
|
40232
|
+
models: provider.models.map((model) => ({
|
|
40233
|
+
modelId: model.modelId,
|
|
40234
|
+
name: model.name,
|
|
40235
|
+
effort: getEffort(cliType, model.modelId)
|
|
40236
|
+
}))
|
|
40237
|
+
};
|
|
40238
|
+
},
|
|
40239
|
+
getEffort: (cliType, modelId) => getEffort(cliType, modelId),
|
|
40240
|
+
getAgentCliSelection: (carrierId, cliType) => getAgentCliSelection(carrierId, cliType),
|
|
40241
|
+
saveAgentCliSelection,
|
|
40242
|
+
updateCarrierCliType: (carrierId, cliType) => updateCarrierCliType(registry3, carrierId),
|
|
40243
|
+
applyAgentCliTypeSelectionUpdate,
|
|
40244
|
+
refreshAgentPanel: () => void 0,
|
|
40245
|
+
syncModelConfig: () => void 0,
|
|
40246
|
+
notifyStatusUpdate: () => notifyStatusUpdate(registry3)
|
|
40247
|
+
});
|
|
40248
|
+
}
|
|
40249
|
+
function updateCarrierAgentModeAtomically(carrierId, agentMode, defaultAgentMode) {
|
|
40250
|
+
if (agentMode === "cli") {
|
|
40251
|
+
setCarrierAgentMode(carrierId, false, defaultAgentMode);
|
|
40252
|
+
return;
|
|
40253
|
+
}
|
|
40254
|
+
updateCarriers((states) => {
|
|
40255
|
+
const carriers = { ...states.carriers ?? {} };
|
|
40256
|
+
const current = carriers[carrierId] ?? {};
|
|
40257
|
+
const next = { ...current };
|
|
40258
|
+
next.agentMode = "subagent";
|
|
40259
|
+
delete next.taskforce;
|
|
40260
|
+
carriers[carrierId] = next;
|
|
40261
|
+
states.carriers = carriers;
|
|
40262
|
+
});
|
|
40263
|
+
}
|
|
40264
|
+
function updateTaskForceBackendAtomically(carrierId, cliType, selection) {
|
|
40265
|
+
updateCarriers((states) => {
|
|
40266
|
+
const carriers = { ...states.carriers ?? {} };
|
|
40267
|
+
const current = carriers[carrierId] ?? {};
|
|
40268
|
+
carriers[carrierId] = {
|
|
40269
|
+
...current,
|
|
40270
|
+
agentMode: "cli",
|
|
40271
|
+
taskforce: {
|
|
40272
|
+
...current.taskforce ?? {},
|
|
40273
|
+
[cliType]: selection
|
|
40274
|
+
}
|
|
40275
|
+
};
|
|
40276
|
+
states.carriers = carriers;
|
|
40277
|
+
});
|
|
40278
|
+
}
|
|
40279
|
+
function refreshTaskForceConfiguredCarriers(registry3) {
|
|
40280
|
+
setTaskForceConfiguredCarriers(registry3, getConfiguredTaskForceCarrierIds(getRegisteredOrder(registry3)));
|
|
40281
|
+
notifyStatusUpdate(registry3);
|
|
40282
|
+
}
|
|
40283
|
+
function readSelection(cliType, body) {
|
|
40284
|
+
if (typeof body.model !== "string") return null;
|
|
40285
|
+
const provider = getProviderModels(cliType);
|
|
40286
|
+
if (!provider.models.some((model) => model.modelId === body.model)) return null;
|
|
40287
|
+
const effort = getEffort(cliType, body.model);
|
|
40288
|
+
if (!effort.supported) {
|
|
40289
|
+
return body.effort === void 0 ? { model: body.model } : null;
|
|
40290
|
+
}
|
|
40291
|
+
if (typeof body.effort !== "string" || !effort.levels.includes(body.effort)) return null;
|
|
40292
|
+
return { model: body.model, effort: body.effort };
|
|
40293
|
+
}
|
|
40294
|
+
function readDefaultSelection(cliType) {
|
|
40295
|
+
const provider = getProviderModels(cliType);
|
|
40296
|
+
const model = provider.defaultModel;
|
|
40297
|
+
const effort = getEffort(cliType, model);
|
|
40298
|
+
return {
|
|
40299
|
+
model,
|
|
40300
|
+
...effort.supported ? { effort: effort.default } : {}
|
|
40301
|
+
};
|
|
40302
|
+
}
|
|
40303
|
+
function readCurrentModelSelection(registry3, carrierId) {
|
|
40304
|
+
const config2 = getRegisteredCarrierConfig(registry3, carrierId);
|
|
40305
|
+
if (!config2) return void 0;
|
|
40306
|
+
const defaults = {
|
|
40307
|
+
[carrierId]: {
|
|
40308
|
+
cliType: config2.defaultCliType,
|
|
40309
|
+
...config2.defaultAgentMode ? { defaultAgentMode: config2.defaultAgentMode } : {},
|
|
40310
|
+
...buildCarrierModelDefaults(config2, config2.defaultCliType)
|
|
40311
|
+
}
|
|
40312
|
+
};
|
|
40313
|
+
const resolved = readCarriersSnapshot(defaults).carriers[carrierId] ?? fallbackResolvedState(config2);
|
|
40314
|
+
const cliType = resolved.agentCliType ?? config2.defaultCliType;
|
|
40315
|
+
return resolved.agentCli[cliType] ?? readDefaultSelection(cliType);
|
|
40316
|
+
}
|
|
40317
|
+
function fallbackResolvedState(config2) {
|
|
40318
|
+
return {
|
|
40319
|
+
agentMode: config2.defaultAgentMode ?? "cli",
|
|
40320
|
+
agentCliType: config2.defaultCliType,
|
|
40321
|
+
agentCli: { [config2.defaultCliType]: readDefaultSelection(config2.defaultCliType) },
|
|
40322
|
+
taskforce: {}
|
|
40323
|
+
};
|
|
40324
|
+
}
|
|
40325
|
+
function parseCarrierMutation(pathname) {
|
|
40326
|
+
const parts = pathname.split("/").filter(Boolean);
|
|
40327
|
+
if (parts[0] !== "carrier-settings" || parts[1] !== "carriers" || !parts[2]) return null;
|
|
40328
|
+
const carrierId = safeDecodeURIComponent(parts[2]);
|
|
40329
|
+
if (!carrierId) return null;
|
|
40330
|
+
if (parts.length === 4 && parts[3] === "cli") return { kind: "cli", carrierId };
|
|
40331
|
+
if (parts.length === 4 && parts[3] === "model") return { kind: "model", carrierId };
|
|
40332
|
+
if (parts.length === 4 && parts[3] === "display-name") return { kind: "display-name", carrierId };
|
|
40333
|
+
if (parts.length === 4 && parts[3] === "agent-mode") return { kind: "agent-mode", carrierId };
|
|
40334
|
+
if (parts.length === 4 && parts[3] === "taskforce") return { kind: "taskforce-all", carrierId };
|
|
40335
|
+
if (parts.length === 5 && parts[3] === "taskforce") {
|
|
40336
|
+
const cliType = safeDecodeURIComponent(parts[4] ?? "");
|
|
40337
|
+
return cliType ? { kind: "taskforce-backend", carrierId, cliType } : null;
|
|
40338
|
+
}
|
|
40339
|
+
return null;
|
|
40340
|
+
}
|
|
40341
|
+
function safeDecodeURIComponent(value) {
|
|
40342
|
+
try {
|
|
40343
|
+
return decodeURIComponent(value);
|
|
40344
|
+
} catch {
|
|
40345
|
+
return null;
|
|
40346
|
+
}
|
|
40347
|
+
}
|
|
40348
|
+
function isExpectedCarrierMethod(mutation, method, expectedMethod) {
|
|
40349
|
+
if (mutation.kind === "taskforce-backend") return method === "PUT" || method === "DELETE";
|
|
40350
|
+
if (mutation.kind === "taskforce-all") return method === "DELETE";
|
|
40351
|
+
return method === expectedMethod;
|
|
40352
|
+
}
|
|
40353
|
+
function isJsonRequest(req) {
|
|
40354
|
+
const contentType = req.headers["content-type"];
|
|
40355
|
+
return typeof contentType === "string" && contentType.toLowerCase().split(";")[0]?.trim() === "application/json";
|
|
40356
|
+
}
|
|
40357
|
+
function readCliType(value) {
|
|
40358
|
+
return typeof value === "string" && isCliType(value) ? value : null;
|
|
40359
|
+
}
|
|
40360
|
+
function isCliType(value) {
|
|
40361
|
+
return Object.prototype.hasOwnProperty.call(CLI_BACKENDS, value);
|
|
40362
|
+
}
|
|
40363
|
+
function getCliTypes() {
|
|
40364
|
+
return Object.keys(CLI_BACKENDS);
|
|
40365
|
+
}
|
|
40366
|
+
function requireCarrierConfig(registry3, carrierId) {
|
|
40367
|
+
const config2 = getRegisteredCarrierConfig(registry3, carrierId);
|
|
40368
|
+
if (!config2) throw new Error(`Carrier not found: ${carrierId}`);
|
|
40369
|
+
return config2;
|
|
40370
|
+
}
|
|
40371
|
+
|
|
39798
40372
|
// src/codex/security-headers.ts
|
|
39799
40373
|
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
40374
|
var SECURITY_HEADERS = {
|
|
@@ -39822,7 +40396,7 @@ function safeEqual(left, right) {
|
|
|
39822
40396
|
return timingSafeEqual(leftBytes, rightBytes);
|
|
39823
40397
|
}
|
|
39824
40398
|
function workspaceHash(canonicalCwd) {
|
|
39825
|
-
return
|
|
40399
|
+
return crypto5.createHash("sha256").update(canonicalCwd).digest("hex").slice(0, 12);
|
|
39826
40400
|
}
|
|
39827
40401
|
async function canonicalizeTheaterPath(cwd) {
|
|
39828
40402
|
return canonicalizeTheaterPathSync(cwd);
|
|
@@ -40702,7 +41276,7 @@ function createCodexGateway(deps) {
|
|
|
40702
41276
|
return true;
|
|
40703
41277
|
}
|
|
40704
41278
|
if (selected.kind === "no-workspace") {
|
|
40705
|
-
if (
|
|
41279
|
+
if (isJsonRequest2(request)) {
|
|
40706
41280
|
sendJson2(response, 404, { error: "no_workspace_registered" });
|
|
40707
41281
|
return true;
|
|
40708
41282
|
}
|
|
@@ -40814,7 +41388,7 @@ function legacyWorkspacePath(url2) {
|
|
|
40814
41388
|
}
|
|
40815
41389
|
return null;
|
|
40816
41390
|
}
|
|
40817
|
-
function
|
|
41391
|
+
function isJsonRequest2(request) {
|
|
40818
41392
|
const accept = Array.isArray(request.headers.accept) ? request.headers.accept.join(",") : request.headers.accept ?? "";
|
|
40819
41393
|
const requestedWith = Array.isArray(request.headers["x-requested-with"]) ? request.headers["x-requested-with"].join(",") : request.headers["x-requested-with"] ?? "";
|
|
40820
41394
|
return accept.includes("application/json") || requestedWith.toLowerCase() === "xmlhttprequest";
|
|
@@ -40889,6 +41463,155 @@ function readRawHeaderValues(rawHeaders, name) {
|
|
|
40889
41463
|
function stripIpv6Brackets2(host) {
|
|
40890
41464
|
return host.startsWith("[") && host.endsWith("]") ? host.slice(1, -1) : host;
|
|
40891
41465
|
}
|
|
41466
|
+
var STATE_VERSION = 1;
|
|
41467
|
+
var STATE_LOCK_DIR_NAME = "state.lock";
|
|
41468
|
+
var STATE_LOCK_OWNER_FILE_NAME = "owner.json";
|
|
41469
|
+
var STATE_TEMP_PREFIX = ".state.";
|
|
41470
|
+
function createConsoleDurableStateStore(deps = {}) {
|
|
41471
|
+
const paths = deps.paths ?? createConsoleDataPaths();
|
|
41472
|
+
const createStore = deps.createStore ?? createDurableJsonStore;
|
|
41473
|
+
return createStore({
|
|
41474
|
+
filePath: paths.stateFile,
|
|
41475
|
+
lockDir: path93__default.join(paths.dir, STATE_LOCK_DIR_NAME),
|
|
41476
|
+
lockOwnerFileName: STATE_LOCK_OWNER_FILE_NAME,
|
|
41477
|
+
now: deps.now,
|
|
41478
|
+
sanitize: sanitizeDurableConsoleState,
|
|
41479
|
+
sensitivity: "sensitive",
|
|
41480
|
+
tempCleanupPrefix: STATE_TEMP_PREFIX
|
|
41481
|
+
});
|
|
41482
|
+
}
|
|
41483
|
+
function sanitizeDurableConsoleState(value) {
|
|
41484
|
+
if (!isRecord4(value) || value.version !== STATE_VERSION) return emptyDurableConsoleState();
|
|
41485
|
+
return {
|
|
41486
|
+
version: STATE_VERSION,
|
|
41487
|
+
theaters: readTheaterRegistrations(value.theaters),
|
|
41488
|
+
operations: readDurableOperations(value.operations)
|
|
41489
|
+
};
|
|
41490
|
+
}
|
|
41491
|
+
function emptyDurableConsoleState() {
|
|
41492
|
+
return { version: STATE_VERSION, theaters: [], operations: [] };
|
|
41493
|
+
}
|
|
41494
|
+
function readProviderSessionCapture(fleetSessionId, deps = {}) {
|
|
41495
|
+
if (!isSafeCaptureId(fleetSessionId)) return null;
|
|
41496
|
+
const capturesDir = deps.capturesDir ?? createConsoleDataPaths().capturesDir;
|
|
41497
|
+
const filePath = path93__default.join(capturesDir, `${fleetSessionId}.json`);
|
|
41498
|
+
try {
|
|
41499
|
+
const parsed = JSON.parse(fs5__default.readFileSync(filePath, "utf8"));
|
|
41500
|
+
return sanitizeProviderSession(parsed);
|
|
41501
|
+
} catch {
|
|
41502
|
+
return null;
|
|
41503
|
+
}
|
|
41504
|
+
}
|
|
41505
|
+
function mergeProviderSessionCaptures(state, deps = {}) {
|
|
41506
|
+
let changed = false;
|
|
41507
|
+
const operations = state.operations.map((operation) => {
|
|
41508
|
+
if (operation.providerSession) return operation;
|
|
41509
|
+
const providerSession = readProviderSessionCapture(operation.sessionId, deps);
|
|
41510
|
+
if (!providerSession) return operation;
|
|
41511
|
+
changed = true;
|
|
41512
|
+
return { ...operation, providerSession };
|
|
41513
|
+
});
|
|
41514
|
+
return changed ? { ...state, operations } : state;
|
|
41515
|
+
}
|
|
41516
|
+
function unlinkProviderSessionCapture(fleetSessionId, deps = {}) {
|
|
41517
|
+
if (!isSafeCaptureId(fleetSessionId)) return false;
|
|
41518
|
+
const capturesDir = deps.capturesDir ?? createConsoleDataPaths().capturesDir;
|
|
41519
|
+
try {
|
|
41520
|
+
fs5__default.unlinkSync(path93__default.join(capturesDir, `${fleetSessionId}.json`));
|
|
41521
|
+
return true;
|
|
41522
|
+
} catch {
|
|
41523
|
+
return false;
|
|
41524
|
+
}
|
|
41525
|
+
}
|
|
41526
|
+
function cleanupProviderSessionCaptures(state, deps = {}) {
|
|
41527
|
+
for (const operation of state.operations) {
|
|
41528
|
+
if (operation.providerSession) unlinkProviderSessionCapture(operation.sessionId, deps);
|
|
41529
|
+
}
|
|
41530
|
+
}
|
|
41531
|
+
function readTheaterRegistrations(value) {
|
|
41532
|
+
if (!Array.isArray(value)) return [];
|
|
41533
|
+
const registrations = [];
|
|
41534
|
+
for (const item of value) {
|
|
41535
|
+
const registration = sanitizeTheaterRegistration(item);
|
|
41536
|
+
if (registration) registrations.push(registration);
|
|
41537
|
+
}
|
|
41538
|
+
return registrations;
|
|
41539
|
+
}
|
|
41540
|
+
function readDurableOperations(value) {
|
|
41541
|
+
if (!Array.isArray(value)) return [];
|
|
41542
|
+
const operations = [];
|
|
41543
|
+
for (const item of value) {
|
|
41544
|
+
const operation = sanitizeDurableOperation(item);
|
|
41545
|
+
if (operation) operations.push(operation);
|
|
41546
|
+
}
|
|
41547
|
+
return operations;
|
|
41548
|
+
}
|
|
41549
|
+
function sanitizeTheaterRegistration(value) {
|
|
41550
|
+
if (!isRecord4(value)) return null;
|
|
41551
|
+
const id = readNonEmptyString(value.id);
|
|
41552
|
+
const theaterPath = readNonEmptyString(value.path);
|
|
41553
|
+
const realpath = readNonEmptyString(value.realpath);
|
|
41554
|
+
const label = readNonEmptyString(value.label);
|
|
41555
|
+
const registeredAt = readNonEmptyString(value.registeredAt);
|
|
41556
|
+
const lastOpenedAt = readNonEmptyString(value.lastOpenedAt);
|
|
41557
|
+
if (!id || !theaterPath || !realpath || !label || !registeredAt || !lastOpenedAt) return null;
|
|
41558
|
+
return { id, path: theaterPath, realpath, label, registeredAt, lastOpenedAt };
|
|
41559
|
+
}
|
|
41560
|
+
function sanitizeDurableOperation(value) {
|
|
41561
|
+
if (!isRecord4(value)) return null;
|
|
41562
|
+
const sessionId = readNonEmptyString(value.sessionId);
|
|
41563
|
+
const theaterId = readNonEmptyString(value.theaterId);
|
|
41564
|
+
const cwd = readNonEmptyString(value.cwd);
|
|
41565
|
+
const cwdLabel = readNonEmptyString(value.cwdLabel);
|
|
41566
|
+
const sequence = readPositiveInteger(value.sequence);
|
|
41567
|
+
const createdAt = readFiniteNumber(value.createdAt);
|
|
41568
|
+
if (!sessionId || !theaterId || !cwd || !cwdLabel || sequence === null || createdAt === null) return null;
|
|
41569
|
+
const providerSession = sanitizeProviderSession(value.providerSession);
|
|
41570
|
+
return {
|
|
41571
|
+
sessionId,
|
|
41572
|
+
theaterId,
|
|
41573
|
+
cwd,
|
|
41574
|
+
cwdLabel,
|
|
41575
|
+
sequence,
|
|
41576
|
+
...readOptionalString(value.label) ? { label: readOptionalString(value.label) } : {},
|
|
41577
|
+
...readOptionalString(value.cliId) ? { cliId: readOptionalString(value.cliId) } : {},
|
|
41578
|
+
...readOptionalString(value.cliLabel) ? { cliLabel: readOptionalString(value.cliLabel) } : {},
|
|
41579
|
+
createdAt,
|
|
41580
|
+
...providerSession ? { providerSession } : {}
|
|
41581
|
+
};
|
|
41582
|
+
}
|
|
41583
|
+
function sanitizeProviderSession(value) {
|
|
41584
|
+
if (!isRecord4(value)) return null;
|
|
41585
|
+
const provider = value.provider === "claude" || value.provider === "codex" ? value.provider : null;
|
|
41586
|
+
const sessionId = readNonEmptyString(value.sessionId);
|
|
41587
|
+
const capturedAt = readNonEmptyString(value.capturedAt);
|
|
41588
|
+
if (!provider || !sessionId || !capturedAt) return null;
|
|
41589
|
+
return {
|
|
41590
|
+
provider,
|
|
41591
|
+
sessionId,
|
|
41592
|
+
...readOptionalString(value.transcriptPath) ? { transcriptPath: readOptionalString(value.transcriptPath) } : {},
|
|
41593
|
+
...readOptionalString(value.source) ? { source: readOptionalString(value.source) } : {},
|
|
41594
|
+
capturedAt
|
|
41595
|
+
};
|
|
41596
|
+
}
|
|
41597
|
+
function isRecord4(value) {
|
|
41598
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
41599
|
+
}
|
|
41600
|
+
function isSafeCaptureId(value) {
|
|
41601
|
+
return value.length > 0 && path93__default.basename(value) === value && !value.includes(path93__default.sep) && !value.includes(path93__default.posix.sep);
|
|
41602
|
+
}
|
|
41603
|
+
function readNonEmptyString(value) {
|
|
41604
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
41605
|
+
}
|
|
41606
|
+
function readOptionalString(value) {
|
|
41607
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
41608
|
+
}
|
|
41609
|
+
function readPositiveInteger(value) {
|
|
41610
|
+
return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : null;
|
|
41611
|
+
}
|
|
41612
|
+
function readFiniteNumber(value) {
|
|
41613
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
41614
|
+
}
|
|
40892
41615
|
|
|
40893
41616
|
// src/observability-routes.ts
|
|
40894
41617
|
function writeObserverEvents(req, res, workspace, store2) {
|
|
@@ -41099,15 +41822,77 @@ function createConsoleObservabilityStore(deps = {}) {
|
|
|
41099
41822
|
terminalSessionsById.set(state.sessionId, state);
|
|
41100
41823
|
return toTerminalSessionInfo(state);
|
|
41101
41824
|
}
|
|
41825
|
+
function injectDormantOperation(operation) {
|
|
41826
|
+
const currentSequence = terminalSequenceByTheater.get(operation.theaterId) ?? 0;
|
|
41827
|
+
terminalSequenceByTheater.set(operation.theaterId, Math.max(currentSequence, operation.sequence));
|
|
41828
|
+
const state = {
|
|
41829
|
+
sessionId: operation.sessionId,
|
|
41830
|
+
cwd: operation.cwd,
|
|
41831
|
+
canonicalCwd: canonicalizeTheaterPathSync(operation.cwd),
|
|
41832
|
+
cwdLabel: operation.cwdLabel,
|
|
41833
|
+
sequence: operation.sequence,
|
|
41834
|
+
label: operation.label,
|
|
41835
|
+
cliId: operation.cliId,
|
|
41836
|
+
cliLabel: operation.cliLabel,
|
|
41837
|
+
createdAt: operation.createdAt,
|
|
41838
|
+
theaterId: operation.theaterId,
|
|
41839
|
+
terminalSessionId: operation.sessionId,
|
|
41840
|
+
status: "dormant",
|
|
41841
|
+
providerSession: operation.providerSession
|
|
41842
|
+
};
|
|
41843
|
+
terminalSessionsById.set(state.sessionId, state);
|
|
41844
|
+
return toTerminalSessionInfo(state);
|
|
41845
|
+
}
|
|
41102
41846
|
function listTerminalSessions() {
|
|
41103
41847
|
return Array.from(terminalSessionsById.values()).map(toTerminalSessionInfo).sort((a, b) => b.createdAt - a.createdAt);
|
|
41104
41848
|
}
|
|
41849
|
+
function listDurableOperations() {
|
|
41850
|
+
return Array.from(terminalSessionsById.values()).map((session) => ({
|
|
41851
|
+
sessionId: session.sessionId,
|
|
41852
|
+
theaterId: session.theaterId,
|
|
41853
|
+
cwd: session.cwd,
|
|
41854
|
+
cwdLabel: session.cwdLabel,
|
|
41855
|
+
sequence: session.sequence,
|
|
41856
|
+
...session.label ? { label: session.label } : {},
|
|
41857
|
+
...session.cliId ? { cliId: session.cliId } : {},
|
|
41858
|
+
...session.cliLabel ? { cliLabel: session.cliLabel } : {},
|
|
41859
|
+
createdAt: session.createdAt,
|
|
41860
|
+
...session.providerSession ? { providerSession: session.providerSession } : {}
|
|
41861
|
+
}));
|
|
41862
|
+
}
|
|
41863
|
+
function getDurableOperation(sessionId) {
|
|
41864
|
+
return listDurableOperations().find((operation) => operation.sessionId === sessionId) ?? null;
|
|
41865
|
+
}
|
|
41866
|
+
function updateTerminalSessionProviderSession(sessionId, providerSession) {
|
|
41867
|
+
const session = terminalSessionsById.get(sessionId);
|
|
41868
|
+
if (!session) return null;
|
|
41869
|
+
session.providerSession = providerSession;
|
|
41870
|
+
return toTerminalSessionInfo(session);
|
|
41871
|
+
}
|
|
41105
41872
|
function updateTerminalSessionStatus(sessionId, status) {
|
|
41106
41873
|
const session = terminalSessionsById.get(sessionId);
|
|
41107
41874
|
if (!session) return null;
|
|
41108
41875
|
session.status = status;
|
|
41109
41876
|
return toTerminalSessionInfo(session);
|
|
41110
41877
|
}
|
|
41878
|
+
function setTerminalSessionTurnState(sessionId, turnState) {
|
|
41879
|
+
const session = terminalSessionsById.get(sessionId);
|
|
41880
|
+
if (!session) return null;
|
|
41881
|
+
session.turnState = turnState;
|
|
41882
|
+
return toTerminalSessionInfo(session);
|
|
41883
|
+
}
|
|
41884
|
+
function transitionTerminalSessionToDormant(sessionId, providerSession) {
|
|
41885
|
+
const session = terminalSessionsById.get(sessionId);
|
|
41886
|
+
if (!session) return null;
|
|
41887
|
+
const workspace = workspacesByCliRunId.get(sessionId);
|
|
41888
|
+
if (workspace?.terminalSessionId === sessionId) {
|
|
41889
|
+
removeWorkspaceIndexes(workspace);
|
|
41890
|
+
workspacesByCliRunId.delete(sessionId);
|
|
41891
|
+
}
|
|
41892
|
+
session.status = "dormant";
|
|
41893
|
+
session.providerSession = providerSession;
|
|
41894
|
+
return toTerminalSessionInfo(session);
|
|
41895
|
+
}
|
|
41111
41896
|
function renameTerminalSession(sessionId, rawLabel) {
|
|
41112
41897
|
const session = terminalSessionsById.get(sessionId);
|
|
41113
41898
|
if (!session) return null;
|
|
@@ -41147,18 +41932,24 @@ function createConsoleObservabilityStore(deps = {}) {
|
|
|
41147
41932
|
clear,
|
|
41148
41933
|
getLaunchCwd,
|
|
41149
41934
|
getTruncation,
|
|
41935
|
+
getDurableOperation,
|
|
41150
41936
|
getWorkspace,
|
|
41151
41937
|
listEvents,
|
|
41152
41938
|
listJobs,
|
|
41939
|
+
listDurableOperations,
|
|
41153
41940
|
listTerminalSessions,
|
|
41154
41941
|
listWorkspaces,
|
|
41155
41942
|
appendTerminalRuntimeEvent,
|
|
41156
41943
|
createPendingTerminalSession,
|
|
41944
|
+
injectDormantOperation,
|
|
41157
41945
|
notifySessionUpdated,
|
|
41158
41946
|
renameTerminalSession,
|
|
41159
41947
|
subscribe,
|
|
41160
41948
|
subscribeAll,
|
|
41949
|
+
updateTerminalSessionProviderSession,
|
|
41161
41950
|
updateTerminalSessionStatus,
|
|
41951
|
+
setTerminalSessionTurnState,
|
|
41952
|
+
transitionTerminalSessionToDormant,
|
|
41162
41953
|
removeTerminalSession,
|
|
41163
41954
|
registerTerminalRuntimeSession,
|
|
41164
41955
|
workspaceCount: () => listWorkspaces().length
|
|
@@ -41226,11 +42017,13 @@ function toTerminalSessionInfo(state) {
|
|
|
41226
42017
|
cliId: state.cliId,
|
|
41227
42018
|
cliLabel: state.cliLabel,
|
|
41228
42019
|
status: state.status,
|
|
42020
|
+
turnState: state.turnState ?? "none",
|
|
41229
42021
|
createdAt: state.createdAt,
|
|
41230
42022
|
theaterId: state.theaterId,
|
|
41231
42023
|
registrationId: state.registrationId,
|
|
41232
42024
|
cliRunId: state.cliRunId,
|
|
41233
|
-
tenantId: state.cliRunId
|
|
42025
|
+
tenantId: state.cliRunId,
|
|
42026
|
+
resumeAvailable: state.providerSession !== void 0
|
|
41234
42027
|
};
|
|
41235
42028
|
}
|
|
41236
42029
|
function pruneTenantJobs(state) {
|
|
@@ -41441,10 +42234,130 @@ function resolveConsolePath(pathname) {
|
|
|
41441
42234
|
if (!path93__default.extname(withoutPrefix)) return "index.html";
|
|
41442
42235
|
return withoutPrefix;
|
|
41443
42236
|
}
|
|
42237
|
+
var TerminalFolderListError = class extends Error {
|
|
42238
|
+
code;
|
|
42239
|
+
constructor(code) {
|
|
42240
|
+
super(code);
|
|
42241
|
+
this.name = "TerminalFolderListError";
|
|
42242
|
+
this.code = code;
|
|
42243
|
+
}
|
|
42244
|
+
};
|
|
42245
|
+
var DIRECTORY_ENTRY_CAP = 500;
|
|
42246
|
+
var WINDOWS_DRIVE_LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");
|
|
42247
|
+
async function listTerminalFolders(requestedPath, deps = {}) {
|
|
42248
|
+
const platform = deps.platform ?? process.platform;
|
|
42249
|
+
const stat5 = deps.stat ?? fs5__default.promises.stat;
|
|
42250
|
+
const opendir = deps.opendir ?? fs5__default.promises.opendir;
|
|
42251
|
+
const targetPath = normalizeListPath(requestedPath, platform, deps);
|
|
42252
|
+
const roots = await listRoots(platform, stat5);
|
|
42253
|
+
const targetStat = await statDirectory(targetPath, stat5);
|
|
42254
|
+
if (!targetStat.isDirectory()) throw new TerminalFolderListError("invalid_path");
|
|
42255
|
+
const entries = [];
|
|
42256
|
+
const truncated = await collectDirectoryEntries(targetPath, opendir, stat5, entries);
|
|
42257
|
+
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
42258
|
+
return {
|
|
42259
|
+
path: targetPath,
|
|
42260
|
+
parentPath: parentPath(targetPath, platform),
|
|
42261
|
+
roots,
|
|
42262
|
+
entries,
|
|
42263
|
+
...truncated ? { truncated: true } : {}
|
|
42264
|
+
};
|
|
42265
|
+
}
|
|
42266
|
+
function normalizeFolderBrowserPath(value, platform = process.platform) {
|
|
42267
|
+
if (typeof value !== "string" || value.length === 0 || value.includes("\0")) throw new TerminalFolderListError("invalid_path");
|
|
42268
|
+
if (isWindowsAmbiguousPath(value, platform) || !path93__default.isAbsolute(value)) throw new TerminalFolderListError("invalid_path");
|
|
42269
|
+
return path93__default.resolve(value);
|
|
42270
|
+
}
|
|
42271
|
+
function normalizeListPath(requestedPath, platform, deps) {
|
|
42272
|
+
if (requestedPath === null || requestedPath === void 0) {
|
|
42273
|
+
const home = deps.homedir?.() ?? os22__default.homedir();
|
|
42274
|
+
const start = home || deps.cwd?.() || process.cwd();
|
|
42275
|
+
return path93__default.resolve(start);
|
|
42276
|
+
}
|
|
42277
|
+
return normalizeFolderBrowserPath(requestedPath, platform);
|
|
42278
|
+
}
|
|
42279
|
+
async function listRoots(platform, stat5) {
|
|
42280
|
+
if (platform !== "win32") return ["/"];
|
|
42281
|
+
const roots = [];
|
|
42282
|
+
await Promise.all(WINDOWS_DRIVE_LETTERS.map(async (letter) => {
|
|
42283
|
+
const root = `${letter}:\\`;
|
|
42284
|
+
try {
|
|
42285
|
+
if ((await stat5(root)).isDirectory()) roots.push(root);
|
|
42286
|
+
} catch {
|
|
42287
|
+
}
|
|
42288
|
+
}));
|
|
42289
|
+
return roots.sort();
|
|
42290
|
+
}
|
|
42291
|
+
async function statDirectory(targetPath, stat5) {
|
|
42292
|
+
try {
|
|
42293
|
+
return await stat5(targetPath);
|
|
42294
|
+
} catch (error51) {
|
|
42295
|
+
throw mapFsError(error51);
|
|
42296
|
+
}
|
|
42297
|
+
}
|
|
42298
|
+
async function collectDirectoryEntries(targetPath, opendir, stat5, entries) {
|
|
42299
|
+
const directory = await openDirectory(targetPath, opendir);
|
|
42300
|
+
try {
|
|
42301
|
+
let dirent = await directory.read();
|
|
42302
|
+
while (dirent !== null) {
|
|
42303
|
+
const entry = await toTerminalFolderEntry(targetPath, dirent, stat5);
|
|
42304
|
+
if (entry !== null) {
|
|
42305
|
+
if (entries.length >= DIRECTORY_ENTRY_CAP) return true;
|
|
42306
|
+
entries.push(entry);
|
|
42307
|
+
}
|
|
42308
|
+
dirent = await directory.read();
|
|
42309
|
+
}
|
|
42310
|
+
return false;
|
|
42311
|
+
} catch (error51) {
|
|
42312
|
+
throw mapFsError(error51);
|
|
42313
|
+
} finally {
|
|
42314
|
+
await directory.close();
|
|
42315
|
+
}
|
|
42316
|
+
}
|
|
42317
|
+
async function openDirectory(targetPath, opendir) {
|
|
42318
|
+
try {
|
|
42319
|
+
return await opendir(targetPath);
|
|
42320
|
+
} catch (error51) {
|
|
42321
|
+
throw mapFsError(error51);
|
|
42322
|
+
}
|
|
42323
|
+
}
|
|
42324
|
+
async function toTerminalFolderEntry(targetPath, dirent, stat5) {
|
|
42325
|
+
if (!dirent.isDirectory() && !dirent.isSymbolicLink()) return null;
|
|
42326
|
+
const entryPath = path93__default.join(targetPath, dirent.name);
|
|
42327
|
+
if (dirent.isDirectory()) return { name: dirent.name, path: entryPath, kind: "dir", accessible: true };
|
|
42328
|
+
const accessible = await statSymlinkDirectory(entryPath, stat5);
|
|
42329
|
+
if (accessible === null) return null;
|
|
42330
|
+
return { name: dirent.name, path: entryPath, kind: "dir", accessible };
|
|
42331
|
+
}
|
|
42332
|
+
async function statSymlinkDirectory(entryPath, stat5) {
|
|
42333
|
+
try {
|
|
42334
|
+
return (await stat5(entryPath)).isDirectory() ? true : null;
|
|
42335
|
+
} catch {
|
|
42336
|
+
return false;
|
|
42337
|
+
}
|
|
42338
|
+
}
|
|
42339
|
+
function mapFsError(error51) {
|
|
42340
|
+
const code = error51.code;
|
|
42341
|
+
if (code === "EACCES" || code === "EPERM") return new TerminalFolderListError("forbidden");
|
|
42342
|
+
if (code === "ENOENT" || code === "ENOTDIR") return new TerminalFolderListError("not_found");
|
|
42343
|
+
return new TerminalFolderListError("invalid_path");
|
|
42344
|
+
}
|
|
42345
|
+
function parentPath(targetPath, platform) {
|
|
42346
|
+
const parsed = path93__default.parse(targetPath);
|
|
42347
|
+
const resolved = path93__default.resolve(targetPath);
|
|
42348
|
+
if (resolved === path93__default.resolve(parsed.root)) return null;
|
|
42349
|
+
const parent = path93__default.dirname(resolved);
|
|
42350
|
+
if (platform === "win32" && parent === resolved) return null;
|
|
42351
|
+
return parent;
|
|
42352
|
+
}
|
|
42353
|
+
function isWindowsAmbiguousPath(value, platform) {
|
|
42354
|
+
if (platform !== "win32") return false;
|
|
42355
|
+
return /^[a-zA-Z]:(?![\\/])/.test(value) || /^[\\/](?![\\/])/.test(value);
|
|
42356
|
+
}
|
|
41444
42357
|
var GRANT_ID_BYTES = 24;
|
|
41445
42358
|
var DEFAULT_GRANT_TTL_MS = 6e4;
|
|
41446
42359
|
function createFolderGrantStore(deps = {}) {
|
|
41447
|
-
const randomId = deps.randomId ?? (() =>
|
|
42360
|
+
const randomId = deps.randomId ?? (() => crypto5.randomBytes(GRANT_ID_BYTES).toString("base64url"));
|
|
41448
42361
|
const statSync5 = deps.statSync ?? fs5__default.statSync;
|
|
41449
42362
|
const ttlMs = deps.ttlMs ?? DEFAULT_GRANT_TTL_MS;
|
|
41450
42363
|
const now = deps.now ?? Date.now;
|
|
@@ -41472,167 +42385,15 @@ function createFolderGrantStore(deps = {}) {
|
|
|
41472
42385
|
return { issue: issue3, consume };
|
|
41473
42386
|
}
|
|
41474
42387
|
function validateAbsoluteDirectory(cwd, statSync5 = fs5__default.statSync) {
|
|
41475
|
-
if (
|
|
42388
|
+
if (typeof cwd !== "string" || cwd.length === 0 || cwd.includes("\0")) throw new Error("invalid_folder");
|
|
42389
|
+
if (isWindowsAmbiguousPath2(cwd) || !path93__default.isAbsolute(cwd)) throw new Error("invalid_folder");
|
|
41476
42390
|
const normalized = path93__default.resolve(cwd);
|
|
41477
42391
|
if (!statSync5(normalized).isDirectory()) throw new Error("invalid_folder");
|
|
41478
42392
|
return normalized;
|
|
41479
42393
|
}
|
|
41480
|
-
|
|
41481
|
-
|
|
41482
|
-
|
|
41483
|
-
var DIALOG_TIMEOUT_MS = 3e4;
|
|
41484
|
-
var POWERSHELL_FOLDER_PICKER_CSHARP = `
|
|
41485
|
-
using System;
|
|
41486
|
-
using System.Runtime.InteropServices;
|
|
41487
|
-
namespace FleetPicker {
|
|
41488
|
-
[ComImport, Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
|
41489
|
-
public interface IShellItem {
|
|
41490
|
-
void BindToHandler();
|
|
41491
|
-
void GetParent();
|
|
41492
|
-
[PreserveSig] int GetDisplayName(int sigdn, out IntPtr ppszName);
|
|
41493
|
-
void GetAttributes();
|
|
41494
|
-
void Compare();
|
|
41495
|
-
}
|
|
41496
|
-
[ComImport, Guid("d57c7288-d4ad-4768-be02-9d969532d960"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
|
41497
|
-
public interface IFileOpenDialog {
|
|
41498
|
-
[PreserveSig] int Show(IntPtr parent);
|
|
41499
|
-
void SetFileTypes(); void SetFileTypeIndex(); void GetFileTypeIndex();
|
|
41500
|
-
void Advise(); void Unadvise();
|
|
41501
|
-
[PreserveSig] int SetOptions(uint fos);
|
|
41502
|
-
[PreserveSig] int GetOptions(out uint pfos);
|
|
41503
|
-
void SetDefaultFolder();
|
|
41504
|
-
void SetFolder(IShellItem psi);
|
|
41505
|
-
void GetFolder(); void GetCurrentSelection();
|
|
41506
|
-
void SetFileName(); void GetFileName(); void SetTitle(); void SetOkButtonLabel(); void SetFileNameLabel();
|
|
41507
|
-
[PreserveSig] int GetResult(out IShellItem ppsi);
|
|
41508
|
-
void AddPlace(IShellItem psi, int fdap);
|
|
41509
|
-
void SetDefaultExtension(); void Close(); void SetClientGuid(); void ClearClientData(); void SetFilter();
|
|
41510
|
-
void GetResults(); void GetSelectedItems();
|
|
41511
|
-
}
|
|
41512
|
-
[ComImport, Guid("DC1C5A9C-E88A-4DDE-A5A1-60F82A20AEF7")] public class FileOpenDialog { }
|
|
41513
|
-
public static class Picker {
|
|
41514
|
-
[DllImport("shell32.dll", CharSet=CharSet.Unicode, PreserveSig=false)]
|
|
41515
|
-
static extern void SHCreateItemFromParsingName(string pszPath, IntPtr pbc, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out IShellItem ppv);
|
|
41516
|
-
static IShellItem ItemFromPath(string path) {
|
|
41517
|
-
Guid iid = new Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe");
|
|
41518
|
-
IShellItem it; SHCreateItemFromParsingName(path, IntPtr.Zero, ref iid, out it); return it;
|
|
41519
|
-
}
|
|
41520
|
-
public static string Pick(string initialPath) {
|
|
41521
|
-
var dlg = (IFileOpenDialog)(new FileOpenDialog());
|
|
41522
|
-
uint opts; dlg.GetOptions(out opts);
|
|
41523
|
-
dlg.SetOptions(opts | 0x20); // FOS_PICKFOLDERS
|
|
41524
|
-
if (!string.IsNullOrEmpty(initialPath)) {
|
|
41525
|
-
// \uC2DC\uC791 \uD3F4\uB354\uB97C WSL \uC704\uCE58\uB85C \uC9C0\uC815\uD558\uACE0 \uC88C\uCE21\uC5D0 \uACE0\uC815(FDAP_TOP). \uC2E4\uD328\uD574\uB3C4 \uAE30\uBCF8 \uC704\uCE58\uB85C \uC9C4\uD589\uD55C\uB2E4.
|
|
41526
|
-
try { IShellItem s = ItemFromPath(initialPath); dlg.AddPlace(s, 1); dlg.SetFolder(s); } catch { }
|
|
41527
|
-
}
|
|
41528
|
-
if (dlg.Show(IntPtr.Zero) != 0) return null; // \uCDE8\uC18C/\uC2E4\uD328 \uC2DC null
|
|
41529
|
-
IShellItem item; dlg.GetResult(out item);
|
|
41530
|
-
IntPtr ptr; if (item.GetDisplayName(unchecked((int)0x80058000), out ptr) != 0) return null; // SIGDN_FILESYSPATH; \uBE44 \uD30C\uC77C\uC2DC\uC2A4\uD15C \uC120\uD0DD \uAC00\uB4DC
|
|
41531
|
-
string path = Marshal.PtrToStringAuto(ptr);
|
|
41532
|
-
Marshal.FreeCoTaskMem(ptr);
|
|
41533
|
-
return path;
|
|
41534
|
-
}
|
|
41535
|
-
}
|
|
41536
|
-
}`;
|
|
41537
|
-
function createNativeFolderPicker(deps = {}) {
|
|
41538
|
-
const platform = deps.platform ?? process.platform;
|
|
41539
|
-
const runCommand = deps.runCommand ?? runNativeCommand;
|
|
41540
|
-
const statSync5 = deps.statSync ?? fs5__default.statSync;
|
|
41541
|
-
const readProcVersion = deps.readProcVersion ?? defaultReadProcVersion;
|
|
41542
|
-
const env = deps.env ?? process.env;
|
|
41543
|
-
return async () => {
|
|
41544
|
-
const isWsl = platform === "linux" && detectWsl(readProcVersion, env);
|
|
41545
|
-
const wslStartPath = isWsl ? wslStartFolderUnc(env) : "";
|
|
41546
|
-
const commands = buildPickerCommands(platform, isWsl, wslStartPath);
|
|
41547
|
-
if (commands.length === 0) return { kind: "error", error: "unsupported_platform" };
|
|
41548
|
-
for (const command2 of commands) {
|
|
41549
|
-
const result = await runPickerCommand(runCommand, command2);
|
|
41550
|
-
if ("kind" in result && result.kind === "unavailable") continue;
|
|
41551
|
-
if ("kind" in result && result.kind === "cancelled") return { kind: "cancelled" };
|
|
41552
|
-
if ("kind" in result && result.kind === "timeout") return { kind: "error", error: "dialog_timeout" };
|
|
41553
|
-
if ("kind" in result) continue;
|
|
41554
|
-
let resolvedPath = result.stdout.trim();
|
|
41555
|
-
if (command2.postProcess === "wslpath") {
|
|
41556
|
-
try {
|
|
41557
|
-
const wslResult = await runCommand("wslpath", ["-u", resolvedPath]);
|
|
41558
|
-
resolvedPath = wslResult.stdout.trim();
|
|
41559
|
-
} catch {
|
|
41560
|
-
return { kind: "error", error: "invalid_folder" };
|
|
41561
|
-
}
|
|
41562
|
-
}
|
|
41563
|
-
try {
|
|
41564
|
-
return { kind: "selected", cwd: validateAbsoluteDirectory(resolvedPath, statSync5) };
|
|
41565
|
-
} catch {
|
|
41566
|
-
return { kind: "error", error: "invalid_folder" };
|
|
41567
|
-
}
|
|
41568
|
-
}
|
|
41569
|
-
return { kind: "error", error: "dialog_unavailable" };
|
|
41570
|
-
};
|
|
41571
|
-
}
|
|
41572
|
-
function defaultReadProcVersion() {
|
|
41573
|
-
try {
|
|
41574
|
-
return fs5__default.readFileSync("/proc/version", "utf8");
|
|
41575
|
-
} catch {
|
|
41576
|
-
return "";
|
|
41577
|
-
}
|
|
41578
|
-
}
|
|
41579
|
-
function detectWsl(readProcVersion, env) {
|
|
41580
|
-
if (env.WSL_INTEROP !== void 0 || env.WSL_DISTRO_NAME !== void 0) return true;
|
|
41581
|
-
return /microsoft|wsl/i.test(readProcVersion());
|
|
41582
|
-
}
|
|
41583
|
-
function buildPickerCommands(platform, isWsl = false, wslStartPath = "") {
|
|
41584
|
-
if (platform === "darwin") {
|
|
41585
|
-
return [{ bin: "osascript", args: ["-e", 'POSIX path of (choose folder with prompt "Choose a Fleet workspace")'] }];
|
|
41586
|
-
}
|
|
41587
|
-
if (platform === "linux") {
|
|
41588
|
-
const commands = [];
|
|
41589
|
-
if (isWsl) {
|
|
41590
|
-
commands.push({ bin: "powershell.exe", args: buildPowerShellPickerArgs(wslStartPath), postProcess: "wslpath" });
|
|
41591
|
-
}
|
|
41592
|
-
commands.push(
|
|
41593
|
-
{ bin: "zenity", args: ["--file-selection", "--directory", "--title=Choose a Fleet workspace"] },
|
|
41594
|
-
{ bin: "kdialog", args: ["--getexistingdirectory", ".", "Choose a Fleet workspace"] }
|
|
41595
|
-
);
|
|
41596
|
-
return commands;
|
|
41597
|
-
}
|
|
41598
|
-
if (platform === "win32") {
|
|
41599
|
-
return [{ bin: "powershell.exe", args: buildPowerShellPickerArgs("") }];
|
|
41600
|
-
}
|
|
41601
|
-
return [];
|
|
41602
|
-
}
|
|
41603
|
-
function buildPowerShellPickerArgs(initialWindowsPath) {
|
|
41604
|
-
const escaped = initialWindowsPath.replace(/'/g, "''");
|
|
41605
|
-
const script = [
|
|
41606
|
-
"[Console]::OutputEncoding=[Text.Encoding]::UTF8",
|
|
41607
|
-
`Add-Type -TypeDefinition '${POWERSHELL_FOLDER_PICKER_CSHARP}'`,
|
|
41608
|
-
`$selection = [FleetPicker.Picker]::Pick('${escaped}')`,
|
|
41609
|
-
"if ([string]::IsNullOrEmpty($selection)) { exit 1 }",
|
|
41610
|
-
"[Console]::Out.Write($selection)"
|
|
41611
|
-
].join("\n");
|
|
41612
|
-
return ["-NoProfile", "-Sta", "-Command", script];
|
|
41613
|
-
}
|
|
41614
|
-
function wslStartFolderUnc(env) {
|
|
41615
|
-
const distro = env.WSL_DISTRO_NAME;
|
|
41616
|
-
if (!distro) return "";
|
|
41617
|
-
const home = env.HOME;
|
|
41618
|
-
if (home && home.startsWith("/") && !home.startsWith("/mnt/")) {
|
|
41619
|
-
return `\\\\wsl.localhost\\${distro}${home.replace(/\//g, "\\")}`;
|
|
41620
|
-
}
|
|
41621
|
-
return `\\\\wsl.localhost\\${distro}`;
|
|
41622
|
-
}
|
|
41623
|
-
async function runPickerCommand(runCommand, command2) {
|
|
41624
|
-
try {
|
|
41625
|
-
return await runCommand(command2.bin, command2.args);
|
|
41626
|
-
} catch (error51) {
|
|
41627
|
-
const err = error51;
|
|
41628
|
-
if (err.code === "ENOENT") return { kind: "unavailable" };
|
|
41629
|
-
if (err.code === "ETIMEDOUT") return { kind: "timeout" };
|
|
41630
|
-
return { kind: "cancelled" };
|
|
41631
|
-
}
|
|
41632
|
-
}
|
|
41633
|
-
async function runNativeCommand(bin, args) {
|
|
41634
|
-
const result = await execFileAsync(bin, [...args], { timeout: DIALOG_TIMEOUT_MS, windowsHide: true });
|
|
41635
|
-
return { stdout: result.stdout, stderr: result.stderr };
|
|
42394
|
+
function isWindowsAmbiguousPath2(value) {
|
|
42395
|
+
if (process.platform !== "win32") return false;
|
|
42396
|
+
return /^[a-zA-Z]:(?![\\/])/.test(value) || /^[\\/](?![\\/])/.test(value);
|
|
41636
42397
|
}
|
|
41637
42398
|
var JAVASCRIPT_ENTRY_EXTENSIONS = /* @__PURE__ */ new Set([".cjs", ".js", ".mjs"]);
|
|
41638
42399
|
var TYPESCRIPT_ENTRY_EXTENSIONS = /* @__PURE__ */ new Set([".cts", ".mts", ".ts", ".tsx"]);
|
|
@@ -41641,29 +42402,43 @@ function buildConsoleHookCommand(entry) {
|
|
|
41641
42402
|
if (entry === void 0) {
|
|
41642
42403
|
throw new Error("Fleet Console session hook command requires the current console entry path");
|
|
41643
42404
|
}
|
|
42405
|
+
return buildConsoleCliHookExec(entry, ["hook", "subagents-context"]);
|
|
42406
|
+
}
|
|
42407
|
+
function buildConsoleTurnHookCommand(entry, phase) {
|
|
42408
|
+
return buildConsoleCliHookExec(entry, ["hook", phase === "start" ? "turn-start" : "turn-end"]);
|
|
42409
|
+
}
|
|
42410
|
+
function buildConsoleCaptureHookCommand(entry, cliId) {
|
|
41644
42411
|
const extension = path93__default.extname(entry.entryPath);
|
|
41645
42412
|
if (JAVASCRIPT_ENTRY_EXTENSIONS.has(extension)) {
|
|
41646
|
-
return {
|
|
41647
|
-
|
|
41648
|
-
|
|
41649
|
-
|
|
42413
|
+
return createSessionCaptureHookExec({
|
|
42414
|
+
entryPath: entry.entryPath,
|
|
42415
|
+
execPath: entry.execPath,
|
|
42416
|
+
provider: toCaptureProvider(cliId)
|
|
42417
|
+
});
|
|
41650
42418
|
}
|
|
41651
42419
|
if (TYPESCRIPT_ENTRY_EXTENSIONS.has(extension)) {
|
|
41652
42420
|
if (!entry.tsxLoaderPath) {
|
|
41653
|
-
throw new Error("Fleet Console session hook
|
|
42421
|
+
throw new Error("Fleet Console capture session hook requires a tsx loader path");
|
|
41654
42422
|
}
|
|
41655
|
-
return {
|
|
41656
|
-
|
|
41657
|
-
|
|
41658
|
-
|
|
42423
|
+
return createSessionCaptureHookExec({
|
|
42424
|
+
entryPath: entry.entryPath,
|
|
42425
|
+
execPath: entry.execPath,
|
|
42426
|
+
provider: toCaptureProvider(cliId),
|
|
42427
|
+
tsxLoader: entry.tsxLoaderPath
|
|
42428
|
+
});
|
|
41659
42429
|
}
|
|
41660
42430
|
throw new Error(`Unsupported Fleet Console session hook entry extension: ${extension}`);
|
|
41661
42431
|
}
|
|
42432
|
+
function toCaptureProvider(cliId) {
|
|
42433
|
+
return cliId === "codex" ? "codex" : "claude";
|
|
42434
|
+
}
|
|
41662
42435
|
function runCodexCommand(command2) {
|
|
41663
42436
|
const result = spawnSync(command2.bin, command2.args, {
|
|
41664
42437
|
cwd: command2.cwd,
|
|
41665
42438
|
encoding: "utf8",
|
|
41666
|
-
env: command2.env
|
|
42439
|
+
env: command2.env,
|
|
42440
|
+
// 콘솔 없는 fleet-console 백엔드에서 codex 등록 명령 실행 시 콘솔 창이 깜빡이는 것을 방지한다.
|
|
42441
|
+
windowsHide: true
|
|
41667
42442
|
});
|
|
41668
42443
|
return {
|
|
41669
42444
|
status: result.status,
|
|
@@ -41676,6 +42451,25 @@ function withConsoleMarketplaceLock(target, fn) {
|
|
|
41676
42451
|
mkdirSync(path93__default.dirname(lockDir), { recursive: true });
|
|
41677
42452
|
return withDirectoryLock({ lockDir }, fn);
|
|
41678
42453
|
}
|
|
42454
|
+
function buildConsoleCliHookExec(entry, trailingArgs) {
|
|
42455
|
+
const extension = path93__default.extname(entry.entryPath);
|
|
42456
|
+
if (JAVASCRIPT_ENTRY_EXTENSIONS.has(extension)) {
|
|
42457
|
+
return {
|
|
42458
|
+
command: entry.execPath,
|
|
42459
|
+
args: [entry.entryPath, ...trailingArgs]
|
|
42460
|
+
};
|
|
42461
|
+
}
|
|
42462
|
+
if (TYPESCRIPT_ENTRY_EXTENSIONS.has(extension)) {
|
|
42463
|
+
if (!entry.tsxLoaderPath) {
|
|
42464
|
+
throw new Error("Fleet Console session hook command for TypeScript entries requires a tsx loader path");
|
|
42465
|
+
}
|
|
42466
|
+
return {
|
|
42467
|
+
command: entry.execPath,
|
|
42468
|
+
args: ["--import", pathToFileURL(entry.tsxLoaderPath).href, entry.entryPath, ...trailingArgs]
|
|
42469
|
+
};
|
|
42470
|
+
}
|
|
42471
|
+
throw new Error(`Unsupported Fleet Console session hook entry extension: ${extension}`);
|
|
42472
|
+
}
|
|
41679
42473
|
|
|
41680
42474
|
// src/terminal/launch.ts
|
|
41681
42475
|
var DEFAULT_TERMINAL_CWD_FALLBACK = os22__default.homedir;
|
|
@@ -41684,12 +42478,12 @@ var CONSOLE_ENTRY_PATH = fileURLToPath(import.meta.url);
|
|
|
41684
42478
|
var HOOK_ENTRY_EXTENSIONS = /* @__PURE__ */ new Set([".cjs", ".cts", ".js", ".mjs", ".mts", ".ts", ".tsx"]);
|
|
41685
42479
|
var require2 = createRequire(import.meta.url);
|
|
41686
42480
|
function createDefaultTerminalLaunchResolver(deps = {}) {
|
|
41687
|
-
const baseCwd = deps.cwd ??
|
|
41688
|
-
const env = deps.env ??
|
|
41689
|
-
const execPath = deps.execPath ??
|
|
42481
|
+
const baseCwd = deps.cwd ?? process6.cwd();
|
|
42482
|
+
const env = deps.env ?? process6.env;
|
|
42483
|
+
const execPath = deps.execPath ?? process6.execPath;
|
|
41690
42484
|
const homedir3 = deps.homedir ?? DEFAULT_TERMINAL_CWD_FALLBACK;
|
|
41691
|
-
const platform = deps.platform ??
|
|
41692
|
-
const entryPath = resolveHookEntryPath(deps.entryPath ??
|
|
42485
|
+
const platform = deps.platform ?? process6.platform;
|
|
42486
|
+
const entryPath = resolveHookEntryPath(deps.entryPath ?? process6.argv[1]);
|
|
41693
42487
|
const tsxLoaderPath = deps.tsxLoaderPath ?? resolveOptionalPackage("tsx");
|
|
41694
42488
|
const dataDir = deps.dataDir ?? getFleetDataDir();
|
|
41695
42489
|
const infraServices = deps.infraServices ?? createInfraServices();
|
|
@@ -41729,6 +42523,7 @@ function createDefaultTerminalLaunchResolver(deps = {}) {
|
|
|
41729
42523
|
onRuntimeSessionStart: deps.onRuntimeSessionStart,
|
|
41730
42524
|
resolveProfile,
|
|
41731
42525
|
cliId: context?.cliId,
|
|
42526
|
+
resumeSessionId: context?.resumeSessionId,
|
|
41732
42527
|
sessionId
|
|
41733
42528
|
});
|
|
41734
42529
|
};
|
|
@@ -41749,7 +42544,7 @@ function hasHookEntryExtension(entryPath) {
|
|
|
41749
42544
|
}
|
|
41750
42545
|
function startTerminalShell(launch, size) {
|
|
41751
42546
|
const { spawn: spawnPty } = require2("node-pty");
|
|
41752
|
-
const useConptyDll = resolveUseConptyDll(
|
|
42547
|
+
const useConptyDll = resolveUseConptyDll(process6.platform, process6.env);
|
|
41753
42548
|
return spawnPty(launch.bin, [...launch.args], {
|
|
41754
42549
|
cols: size.cols,
|
|
41755
42550
|
rows: size.rows,
|
|
@@ -41774,7 +42569,8 @@ async function createAgentCliLaunchSpec(options) {
|
|
|
41774
42569
|
const profile = await options.resolveProfile(options.env, options.cwd, {
|
|
41775
42570
|
authEnvResolver: options.authEnvResolver,
|
|
41776
42571
|
authService: options.infraServices.authService,
|
|
41777
|
-
cliId: options.cliId
|
|
42572
|
+
cliId: options.cliId,
|
|
42573
|
+
resumeSessionId: options.resumeSessionId
|
|
41778
42574
|
});
|
|
41779
42575
|
const injectedProfile = await options.injectProfile(profile, {
|
|
41780
42576
|
buildSystemPrompt: (injectTone) => createSystemPromptBuilder({ carrierRuntime: agentRuntime.carrierRuntime }).build(injectTone),
|
|
@@ -41783,9 +42579,13 @@ async function createAgentCliLaunchSpec(options) {
|
|
|
41783
42579
|
dataDir: options.dataDir,
|
|
41784
42580
|
dedicatedMcpSession: agentRuntime.dedicatedMcpSession,
|
|
41785
42581
|
enableMetaphor: false,
|
|
42582
|
+
captureSessionHookExec: buildConsoleCaptureHookCommand(options.hookEntry, profile.id),
|
|
42583
|
+
turnStartHookExec: buildConsoleTurnHookCommand(options.hookEntry, "start"),
|
|
42584
|
+
turnEndHookExec: buildConsoleTurnHookCommand(options.hookEntry, "end"),
|
|
41786
42585
|
hookExec: buildConsoleHookCommand(options.hookEntry),
|
|
41787
42586
|
onCleanup: (cleanup) => cleanupStack.push(cleanup),
|
|
41788
|
-
replaceSystemPrompt:
|
|
42587
|
+
replaceSystemPrompt: false,
|
|
42588
|
+
resumeSessionId: options.resumeSessionId,
|
|
41789
42589
|
withMarketplaceLock: withConsoleMarketplaceLock,
|
|
41790
42590
|
mcpSessionLabel: options.sessionId
|
|
41791
42591
|
});
|
|
@@ -41819,6 +42619,7 @@ function toLaunchSpec(profile, cleanup) {
|
|
|
41819
42619
|
cwd: profile.cwd,
|
|
41820
42620
|
env: { ...profile.env },
|
|
41821
42621
|
messagePolicy: profile.messagePolicy,
|
|
42622
|
+
renameCommand: profile.renameCommand,
|
|
41822
42623
|
terminalName: profile.terminalName
|
|
41823
42624
|
};
|
|
41824
42625
|
}
|
|
@@ -41881,6 +42682,8 @@ var DEFAULT_COLS = 80;
|
|
|
41881
42682
|
var DEFAULT_ROWS = 24;
|
|
41882
42683
|
var DEFAULT_SCROLLBACK_LIMIT = 512;
|
|
41883
42684
|
var WS_OPEN_STATE = 1;
|
|
42685
|
+
var THEATER_SHELL_SESSION_PREFIX = "shell:";
|
|
42686
|
+
var THEATER_SHELL_DETACH_GRACE_MS = 4e3;
|
|
41884
42687
|
function createTerminalSessionManager(deps) {
|
|
41885
42688
|
const startShell = deps.startShell ?? startTerminalShell;
|
|
41886
42689
|
const scrollbackLimit = deps.scrollbackLimit ?? DEFAULT_SCROLLBACK_LIMIT;
|
|
@@ -41891,6 +42694,7 @@ function createTerminalSessionManager(deps) {
|
|
|
41891
42694
|
}
|
|
41892
42695
|
async function attach(socket, context) {
|
|
41893
42696
|
const session = await getOrCreateSession(context);
|
|
42697
|
+
clearGraceTimer(session);
|
|
41894
42698
|
if (session.activeSocket && session.activeSocket !== socket) {
|
|
41895
42699
|
session.activeSocket.close(4e3, "terminal_replaced");
|
|
41896
42700
|
}
|
|
@@ -41912,6 +42716,9 @@ function createTerminalSessionManager(deps) {
|
|
|
41912
42716
|
function getSessionMessagePolicy(sessionId) {
|
|
41913
42717
|
return sessions.get(sessionId)?.messagePolicy;
|
|
41914
42718
|
}
|
|
42719
|
+
function getSessionRenameCommand(sessionId) {
|
|
42720
|
+
return sessions.get(sessionId)?.renameCommand;
|
|
42721
|
+
}
|
|
41915
42722
|
function writeToSession(sessionId, data) {
|
|
41916
42723
|
const session = sessions.get(sessionId);
|
|
41917
42724
|
if (!session || typeof session.pty.write !== "function") return false;
|
|
@@ -41949,7 +42756,7 @@ function createTerminalSessionManager(deps) {
|
|
|
41949
42756
|
}
|
|
41950
42757
|
}
|
|
41951
42758
|
async function launchSession(context) {
|
|
41952
|
-
const launch = await deps.launch(context.cwd, { sessionId: context.sessionId, kind: context.kind, cliId: context.cliId });
|
|
42759
|
+
const launch = await deps.launch(context.cwd, { sessionId: context.sessionId, kind: context.kind, cliId: context.cliId, resumeSessionId: context.resumeSessionId });
|
|
41953
42760
|
let pty;
|
|
41954
42761
|
try {
|
|
41955
42762
|
pty = startShell(launch, { cols: DEFAULT_COLS, rows: DEFAULT_ROWS });
|
|
@@ -41964,9 +42771,11 @@ function createTerminalSessionManager(deps) {
|
|
|
41964
42771
|
scrollback: [],
|
|
41965
42772
|
cleanup: launch.cleanup,
|
|
41966
42773
|
messagePolicy: launch.messagePolicy,
|
|
42774
|
+
renameCommand: launch.renameCommand,
|
|
41967
42775
|
activeSocket: null,
|
|
41968
42776
|
cols: DEFAULT_COLS,
|
|
41969
|
-
rows: DEFAULT_ROWS
|
|
42777
|
+
rows: DEFAULT_ROWS,
|
|
42778
|
+
graceTimer: null
|
|
41970
42779
|
};
|
|
41971
42780
|
const dataDisposable = pty.onData((data) => handlePtyData(session, data));
|
|
41972
42781
|
const exitDisposable = pty.onExit(() => removeSession(session));
|
|
@@ -42004,6 +42813,13 @@ function createTerminalSessionManager(deps) {
|
|
|
42004
42813
|
function detachSocket(session, socket) {
|
|
42005
42814
|
if (session.activeSocket !== socket) return;
|
|
42006
42815
|
session.activeSocket = null;
|
|
42816
|
+
if (isTheaterShell(session.id)) {
|
|
42817
|
+
clearGraceTimer(session);
|
|
42818
|
+
session.graceTimer = setTimeout(() => {
|
|
42819
|
+
session.graceTimer = null;
|
|
42820
|
+
if (session.activeSocket === null) removeSession(session);
|
|
42821
|
+
}, THEATER_SHELL_DETACH_GRACE_MS);
|
|
42822
|
+
}
|
|
42007
42823
|
}
|
|
42008
42824
|
function replayScrollback(session, socket) {
|
|
42009
42825
|
for (const chunk of session.scrollback) {
|
|
@@ -42019,6 +42835,7 @@ function createTerminalSessionManager(deps) {
|
|
|
42019
42835
|
}
|
|
42020
42836
|
async function killSession(session, options = {}) {
|
|
42021
42837
|
const killPty = options.killPty ?? true;
|
|
42838
|
+
clearGraceTimer(session);
|
|
42022
42839
|
session.activeSocket?.close(4001, "terminal_closed");
|
|
42023
42840
|
session.activeSocket = null;
|
|
42024
42841
|
for (const disposable of session.disposables) disposable.dispose();
|
|
@@ -42028,7 +42845,7 @@ function createTerminalSessionManager(deps) {
|
|
|
42028
42845
|
await runLaunchCleanup(session.cleanup);
|
|
42029
42846
|
}
|
|
42030
42847
|
}
|
|
42031
|
-
return { canAttach, createSession, attach, getSessionMessagePolicy, terminate, stop, writeToSession };
|
|
42848
|
+
return { canAttach, createSession, attach, getSessionMessagePolicy, getSessionRenameCommand, terminate, stop, writeToSession };
|
|
42032
42849
|
}
|
|
42033
42850
|
async function runLaunchCleanup(cleanup) {
|
|
42034
42851
|
try {
|
|
@@ -42042,6 +42859,14 @@ function killPtyBestEffort(pty) {
|
|
|
42042
42859
|
} catch {
|
|
42043
42860
|
}
|
|
42044
42861
|
}
|
|
42862
|
+
function isTheaterShell(sessionId) {
|
|
42863
|
+
return sessionId.startsWith(THEATER_SHELL_SESSION_PREFIX);
|
|
42864
|
+
}
|
|
42865
|
+
function clearGraceTimer(session) {
|
|
42866
|
+
if (session.graceTimer === null) return;
|
|
42867
|
+
clearTimeout(session.graceTimer);
|
|
42868
|
+
session.graceTimer = null;
|
|
42869
|
+
}
|
|
42045
42870
|
function toBuffer(data) {
|
|
42046
42871
|
if (Buffer.isBuffer(data)) return data;
|
|
42047
42872
|
if (Array.isArray(data)) return Buffer.concat(data);
|
|
@@ -42058,7 +42883,7 @@ var DEFAULT_TICKET_TTL_MS = 1e4;
|
|
|
42058
42883
|
function createTerminalTicketRegistry(deps = {}) {
|
|
42059
42884
|
const ttlMs = deps.ttlMs ?? DEFAULT_TICKET_TTL_MS;
|
|
42060
42885
|
const now = deps.now ?? Date.now;
|
|
42061
|
-
const randomTicket = deps.randomTicket ?? (() =>
|
|
42886
|
+
const randomTicket = deps.randomTicket ?? (() => crypto5.randomBytes(32).toString("base64url"));
|
|
42062
42887
|
const tickets = /* @__PURE__ */ new Map();
|
|
42063
42888
|
function issue3(context) {
|
|
42064
42889
|
prune();
|
|
@@ -42085,7 +42910,7 @@ function createTerminalTicketRegistry(deps = {}) {
|
|
|
42085
42910
|
}
|
|
42086
42911
|
return { ttlMs, issue: issue3, consume, prune };
|
|
42087
42912
|
}
|
|
42088
|
-
var
|
|
42913
|
+
var execFileAsync = promisify(execFile);
|
|
42089
42914
|
var GIT_STATUS_TIMEOUT_MS = 4e3;
|
|
42090
42915
|
var GIT_STATUS_MAX_BUFFER = 1024 * 1024;
|
|
42091
42916
|
var GIT_HASH_TIMEOUT_MS = 4e3;
|
|
@@ -42094,11 +42919,13 @@ function createWorkspaceChangeScanner() {
|
|
|
42094
42919
|
return {
|
|
42095
42920
|
async snapshot(cwd) {
|
|
42096
42921
|
try {
|
|
42097
|
-
const { stdout } = await
|
|
42922
|
+
const { stdout } = await execFileAsync("git", ["status", "--porcelain=v1", "-z", "--untracked-files=all"], {
|
|
42098
42923
|
cwd,
|
|
42099
42924
|
encoding: "utf8",
|
|
42100
42925
|
maxBuffer: GIT_STATUS_MAX_BUFFER,
|
|
42101
|
-
timeout: GIT_STATUS_TIMEOUT_MS
|
|
42926
|
+
timeout: GIT_STATUS_TIMEOUT_MS,
|
|
42927
|
+
// 콘솔 없는 fleet-console 백엔드에서 git.exe 실행 시 콘솔 창이 깜빡이는 것을 방지한다.
|
|
42928
|
+
windowsHide: true
|
|
42102
42929
|
});
|
|
42103
42930
|
const entries = parseGitStatusPorcelainZ(stdout);
|
|
42104
42931
|
if (!entries) return null;
|
|
@@ -42158,7 +42985,9 @@ function execGitHashObject(cwd, paths) {
|
|
|
42158
42985
|
cwd,
|
|
42159
42986
|
encoding: "utf8",
|
|
42160
42987
|
maxBuffer: GIT_HASH_MAX_BUFFER,
|
|
42161
|
-
timeout: GIT_HASH_TIMEOUT_MS
|
|
42988
|
+
timeout: GIT_HASH_TIMEOUT_MS,
|
|
42989
|
+
// 콘솔 없는 fleet-console 백엔드에서 git.exe 실행 시 콘솔 창이 깜빡이는 것을 방지한다.
|
|
42990
|
+
windowsHide: true
|
|
42162
42991
|
},
|
|
42163
42992
|
(error51, stdout) => {
|
|
42164
42993
|
if (error51) {
|
|
@@ -42246,6 +43075,26 @@ var TheaterRegistry = class {
|
|
|
42246
43075
|
this.#mruId = id;
|
|
42247
43076
|
return item;
|
|
42248
43077
|
}
|
|
43078
|
+
load(items) {
|
|
43079
|
+
this.restore(items);
|
|
43080
|
+
}
|
|
43081
|
+
restore(items) {
|
|
43082
|
+
const restored = /* @__PURE__ */ new Map();
|
|
43083
|
+
let mruId = null;
|
|
43084
|
+
for (const item of items) {
|
|
43085
|
+
const existing = restored.get(item.id);
|
|
43086
|
+
if (existing && existing.realpath !== item.realpath) {
|
|
43087
|
+
throw new Error("theater_id_collision");
|
|
43088
|
+
}
|
|
43089
|
+
restored.set(item.id, item);
|
|
43090
|
+
if (!mruId || item.lastOpenedAt.localeCompare(restored.get(mruId)?.lastOpenedAt ?? "") > 0) {
|
|
43091
|
+
mruId = item.id;
|
|
43092
|
+
}
|
|
43093
|
+
}
|
|
43094
|
+
this.#items.clear();
|
|
43095
|
+
for (const [id, item] of restored) this.#items.set(id, item);
|
|
43096
|
+
this.#mruId = mruId;
|
|
43097
|
+
}
|
|
42249
43098
|
get(id) {
|
|
42250
43099
|
return this.#items.get(id) ?? null;
|
|
42251
43100
|
}
|
|
@@ -42255,6 +43104,11 @@ var TheaterRegistry = class {
|
|
|
42255
43104
|
list() {
|
|
42256
43105
|
return [...this.#items.values()].sort((left, right) => right.lastOpenedAt.localeCompare(left.lastOpenedAt));
|
|
42257
43106
|
}
|
|
43107
|
+
remove(id) {
|
|
43108
|
+
const removed = this.#items.delete(id);
|
|
43109
|
+
if (this.#mruId === id) this.#mruId = this.list()[0]?.id ?? null;
|
|
43110
|
+
return removed;
|
|
43111
|
+
}
|
|
42258
43112
|
};
|
|
42259
43113
|
|
|
42260
43114
|
// src/update-check.ts
|
|
@@ -42314,6 +43168,7 @@ function createConsoleUpdateCheckService(deps = {}) {
|
|
|
42314
43168
|
var DEFAULT_HOST2 = "127.0.0.1";
|
|
42315
43169
|
var DEFAULT_PORT2 = 0;
|
|
42316
43170
|
var SHELL_TERMINAL_SESSION_ID = "shell";
|
|
43171
|
+
var THEATER_SHELL_SESSION_PREFIX2 = "shell:";
|
|
42317
43172
|
var SERVER_TIMEOUT_MS = 30 * 60 * 1e3;
|
|
42318
43173
|
var MAX_BODY_BYTES = 1024 * 1024;
|
|
42319
43174
|
function createConsoleServer(deps = {}) {
|
|
@@ -42331,6 +43186,9 @@ function createConsoleServer(deps = {}) {
|
|
|
42331
43186
|
const folderGrants = createFolderGrantStore();
|
|
42332
43187
|
const infraServices = createInfraServices();
|
|
42333
43188
|
const dataDir = deps.dataDir ?? getFleetDataDir();
|
|
43189
|
+
initStore(dataDir);
|
|
43190
|
+
const durablePaths = createConsoleDataPaths({ fleetDataDir: dataDir });
|
|
43191
|
+
const durableStateStore = createConsoleDurableStateStore({ paths: durablePaths });
|
|
42334
43192
|
const authEnvResolver = (cli) => resolveAuthEnv(cli, { authService: infraServices.authService });
|
|
42335
43193
|
const ownsAgentRuntime = deps.agentRuntime === void 0;
|
|
42336
43194
|
const agentRuntime = deps.agentRuntime ?? createFleetAgentRuntimeLifecycle({
|
|
@@ -42355,7 +43213,6 @@ function createConsoleServer(deps = {}) {
|
|
|
42355
43213
|
getPort: () => lockHandle?.payload.port ?? port,
|
|
42356
43214
|
getAdminToken: () => lockHandle?.payload.token ?? null
|
|
42357
43215
|
});
|
|
42358
|
-
const pickTerminalFolder = deps.terminalPickFolder ?? createNativeFolderPicker();
|
|
42359
43216
|
const pendingRuntimeSessions = /* @__PURE__ */ new Map();
|
|
42360
43217
|
const terminalSessions = createTerminalSessionManager({
|
|
42361
43218
|
launch: deps.terminalLaunch ?? createDefaultTerminalLaunchResolver({
|
|
@@ -42369,10 +43226,18 @@ function createConsoleServer(deps = {}) {
|
|
|
42369
43226
|
}),
|
|
42370
43227
|
startShell: deps.terminalStartShell,
|
|
42371
43228
|
maxSessions: deps.maxTerminalSessions,
|
|
42372
|
-
// PTY가 종료되면 콘솔 세션 목록에서도 제거해 잔존/재실행을 막는다.
|
|
42373
43229
|
onSessionExit: (sessionId) => {
|
|
42374
43230
|
pendingRuntimeSessions.delete(sessionId);
|
|
42375
|
-
observability.
|
|
43231
|
+
const operation = observability.getDurableOperation(sessionId);
|
|
43232
|
+
const providerSession = operation?.providerSession ?? readProviderSessionCapture(sessionId, { capturesDir: durablePaths.capturesDir });
|
|
43233
|
+
if (providerSession) {
|
|
43234
|
+
observability.updateTerminalSessionProviderSession(sessionId, providerSession);
|
|
43235
|
+
const dormant = observability.transitionTerminalSessionToDormant(sessionId, providerSession);
|
|
43236
|
+
if (dormant) observability.notifySessionUpdated(dormant);
|
|
43237
|
+
} else {
|
|
43238
|
+
observability.removeTerminalSession(sessionId);
|
|
43239
|
+
}
|
|
43240
|
+
persistDurableState();
|
|
42376
43241
|
}
|
|
42377
43242
|
});
|
|
42378
43243
|
const unsubscribeCarrierReminderRouter = createCarrierResultReminderRouter({
|
|
@@ -42404,6 +43269,12 @@ function createConsoleServer(deps = {}) {
|
|
|
42404
43269
|
let activeEndpoint = null;
|
|
42405
43270
|
let agentRuntimeStopped = false;
|
|
42406
43271
|
let consoleResourcesDisposed = false;
|
|
43272
|
+
const carrierSettingsRouter = createCarrierSettingsRouter({
|
|
43273
|
+
registry: carrierRegistry,
|
|
43274
|
+
isAuthorized: isTerminalAuthorized,
|
|
43275
|
+
readJsonBody,
|
|
43276
|
+
writeJson
|
|
43277
|
+
});
|
|
42407
43278
|
function handleRequest(req, res) {
|
|
42408
43279
|
const pathname = getPathname(req);
|
|
42409
43280
|
if (pathname === "/console/codex" || pathname.startsWith("/console/codex/")) {
|
|
@@ -42423,14 +43294,28 @@ function createConsoleServer(deps = {}) {
|
|
|
42423
43294
|
runAsyncHandler(handleTerminalTicket(req, res), res);
|
|
42424
43295
|
return;
|
|
42425
43296
|
}
|
|
42426
|
-
if (pathname === "/terminal/folders/
|
|
42427
|
-
runAsyncHandler(
|
|
43297
|
+
if (pathname === "/terminal/folders/list") {
|
|
43298
|
+
runAsyncHandler(handleTerminalFoldersList(req, res), res);
|
|
43299
|
+
return;
|
|
43300
|
+
}
|
|
43301
|
+
if (pathname === "/terminal/folders/grants") {
|
|
43302
|
+
runAsyncHandler(handleTerminalFolderGrants(req, res), res);
|
|
42428
43303
|
return;
|
|
42429
43304
|
}
|
|
42430
43305
|
if (pathname === "/terminal/sessions") {
|
|
42431
43306
|
runAsyncHandler(handleTerminalSessions(req, res), res);
|
|
42432
43307
|
return;
|
|
42433
43308
|
}
|
|
43309
|
+
const terminalSessionResumeMatch = pathname.match(/^\/terminal\/sessions\/([^/]+)\/resume$/);
|
|
43310
|
+
if (terminalSessionResumeMatch) {
|
|
43311
|
+
runAsyncHandler(handleTerminalSessionResume(req, res, decodeURIComponent(terminalSessionResumeMatch[1] ?? "")), res);
|
|
43312
|
+
return;
|
|
43313
|
+
}
|
|
43314
|
+
const terminalSessionTurnMatch = pathname.match(/^\/terminal\/sessions\/([^/]+)\/turn$/);
|
|
43315
|
+
if (terminalSessionTurnMatch) {
|
|
43316
|
+
runAsyncHandler(handleTerminalSessionTurn(req, res, decodeURIComponent(terminalSessionTurnMatch[1] ?? "")), res);
|
|
43317
|
+
return;
|
|
43318
|
+
}
|
|
42434
43319
|
const terminalSessionItemMatch = pathname.match(/^\/terminal\/sessions\/([^/]+)$/);
|
|
42435
43320
|
if (terminalSessionItemMatch) {
|
|
42436
43321
|
runAsyncHandler(handleTerminalSessionItem(req, res, decodeURIComponent(terminalSessionItemMatch[1] ?? "")), res);
|
|
@@ -42440,6 +43325,11 @@ function createConsoleServer(deps = {}) {
|
|
|
42440
43325
|
runAsyncHandler(handleObserverTheaters(req, res), res);
|
|
42441
43326
|
return;
|
|
42442
43327
|
}
|
|
43328
|
+
const theaterItemMatch = pathname.match(/^\/observer\/theaters\/([^/]+)$/);
|
|
43329
|
+
if (theaterItemMatch) {
|
|
43330
|
+
runAsyncHandler(handleObserverTheaterItem(req, res, decodeURIComponent(theaterItemMatch[1] ?? "")), res);
|
|
43331
|
+
return;
|
|
43332
|
+
}
|
|
42443
43333
|
const theaterSessionMatch = pathname.match(/^\/observer\/theaters\/([^/]+)\/sessions$/);
|
|
42444
43334
|
if (theaterSessionMatch) {
|
|
42445
43335
|
runAsyncHandler(handleObserverTheaterSessions(req, res, decodeURIComponent(theaterSessionMatch[1] ?? "")), res);
|
|
@@ -42453,6 +43343,10 @@ function createConsoleServer(deps = {}) {
|
|
|
42453
43343
|
handleObserverCarriers(req, res);
|
|
42454
43344
|
return;
|
|
42455
43345
|
}
|
|
43346
|
+
if (pathname === "/carrier-settings" || pathname.startsWith("/carrier-settings/")) {
|
|
43347
|
+
runAsyncBooleanHandler(carrierSettingsRouter({ req, res, pathname }), res);
|
|
43348
|
+
return;
|
|
43349
|
+
}
|
|
42456
43350
|
if (pathname === "/observer/tenants") {
|
|
42457
43351
|
handleObserverWorkspaces(req, res);
|
|
42458
43352
|
return;
|
|
@@ -42488,6 +43382,30 @@ function createConsoleServer(deps = {}) {
|
|
|
42488
43382
|
};
|
|
42489
43383
|
writeJson(res, 200, body);
|
|
42490
43384
|
}
|
|
43385
|
+
async function handleTerminalSessionTurn(req, res, sessionId) {
|
|
43386
|
+
if (req.method !== "POST") {
|
|
43387
|
+
writeJson(res, 405, { error: "Method not allowed" });
|
|
43388
|
+
return;
|
|
43389
|
+
}
|
|
43390
|
+
const token = lockHandle?.payload.token;
|
|
43391
|
+
if (!token || req.headers.authorization !== `Bearer ${token}`) {
|
|
43392
|
+
writeJson(res, 401, { error: "Unauthorized" });
|
|
43393
|
+
return;
|
|
43394
|
+
}
|
|
43395
|
+
const body = await readJsonBody(req);
|
|
43396
|
+
const turnState = body?.phase === "start" ? "running" : body?.phase === "end" ? "ended" : null;
|
|
43397
|
+
if (turnState === null) {
|
|
43398
|
+
writeJson(res, 400, { error: "invalid_phase" });
|
|
43399
|
+
return;
|
|
43400
|
+
}
|
|
43401
|
+
const updated = observability.setTerminalSessionTurnState(sessionId, turnState);
|
|
43402
|
+
if (!updated) {
|
|
43403
|
+
writeJson(res, 404, { error: "terminal_session_not_found" });
|
|
43404
|
+
return;
|
|
43405
|
+
}
|
|
43406
|
+
observability.notifySessionUpdated(updated);
|
|
43407
|
+
writeJson(res, 200, { ok: true });
|
|
43408
|
+
}
|
|
42491
43409
|
async function handleTerminalTicket(req, res) {
|
|
42492
43410
|
if (req.method !== "POST") {
|
|
42493
43411
|
writeJson(res, 405, { error: "Method not allowed" });
|
|
@@ -42500,16 +43418,29 @@ function createConsoleServer(deps = {}) {
|
|
|
42500
43418
|
const body = await readJsonBody(req);
|
|
42501
43419
|
const kind = body?.kind === "shell" ? "shell" : "fleet";
|
|
42502
43420
|
const requestedSessionId = body?.sessionId;
|
|
43421
|
+
const requestedTheaterId = typeof body?.theaterId === "string" ? body.theaterId : void 0;
|
|
42503
43422
|
let sessionId;
|
|
43423
|
+
let cwd;
|
|
42504
43424
|
if (kind === "shell") {
|
|
42505
|
-
|
|
43425
|
+
if (typeof requestedSessionId === "string" && requestedSessionId.startsWith(THEATER_SHELL_SESSION_PREFIX2) && requestedTheaterId) {
|
|
43426
|
+
const theater = theaters.get(requestedTheaterId);
|
|
43427
|
+
if (!theater) {
|
|
43428
|
+
writeJson(res, 404, { error: "theater_not_found" });
|
|
43429
|
+
return;
|
|
43430
|
+
}
|
|
43431
|
+
sessionId = requestedSessionId;
|
|
43432
|
+
cwd = theater.path;
|
|
43433
|
+
} else {
|
|
43434
|
+
sessionId = SHELL_TERMINAL_SESSION_ID;
|
|
43435
|
+
cwd = "";
|
|
43436
|
+
}
|
|
42506
43437
|
} else if (typeof requestedSessionId === "string" && requestedSessionId.length > 0) {
|
|
42507
43438
|
sessionId = requestedSessionId;
|
|
43439
|
+
cwd = observability.getLaunchCwd(sessionId);
|
|
42508
43440
|
} else {
|
|
42509
43441
|
writeJson(res, 400, { error: "terminal_session_not_found" });
|
|
42510
43442
|
return;
|
|
42511
43443
|
}
|
|
42512
|
-
const cwd = kind === "shell" ? "" : observability.getLaunchCwd(sessionId);
|
|
42513
43444
|
if (cwd === null) {
|
|
42514
43445
|
writeJson(res, 404, { error: "terminal_session_not_found" });
|
|
42515
43446
|
return;
|
|
@@ -42524,7 +43455,7 @@ function createConsoleServer(deps = {}) {
|
|
|
42524
43455
|
kind
|
|
42525
43456
|
}));
|
|
42526
43457
|
}
|
|
42527
|
-
async function
|
|
43458
|
+
async function handleTerminalFoldersList(req, res) {
|
|
42528
43459
|
if (req.method !== "POST") {
|
|
42529
43460
|
writeJson(res, 405, { error: "Method not allowed" });
|
|
42530
43461
|
return;
|
|
@@ -42533,16 +43464,41 @@ function createConsoleServer(deps = {}) {
|
|
|
42533
43464
|
writeJson(res, 401, { error: "unauthorized" });
|
|
42534
43465
|
return;
|
|
42535
43466
|
}
|
|
42536
|
-
const
|
|
42537
|
-
if (
|
|
42538
|
-
writeJson(res,
|
|
43467
|
+
const body = await readJsonBody(req);
|
|
43468
|
+
if (!isPlainObject2(body) || body.path !== void 0 && body.path !== null && typeof body.path !== "string") {
|
|
43469
|
+
writeJson(res, 400, { error: "invalid_path" });
|
|
43470
|
+
return;
|
|
43471
|
+
}
|
|
43472
|
+
try {
|
|
43473
|
+
const payload = await listTerminalFolders(body.path === void 0 ? null : body.path);
|
|
43474
|
+
writeJson(res, 200, payload);
|
|
43475
|
+
} catch (error51) {
|
|
43476
|
+
if (error51 instanceof TerminalFolderListError) {
|
|
43477
|
+
writeJson(res, terminalFolderListStatus(error51), { error: error51.code });
|
|
43478
|
+
return;
|
|
43479
|
+
}
|
|
43480
|
+
throw error51;
|
|
43481
|
+
}
|
|
43482
|
+
}
|
|
43483
|
+
async function handleTerminalFolderGrants(req, res) {
|
|
43484
|
+
if (req.method !== "POST") {
|
|
43485
|
+
writeJson(res, 405, { error: "Method not allowed" });
|
|
43486
|
+
return;
|
|
43487
|
+
}
|
|
43488
|
+
if (!isTerminalAuthorized(req)) {
|
|
43489
|
+
writeJson(res, 401, { error: "unauthorized" });
|
|
42539
43490
|
return;
|
|
42540
43491
|
}
|
|
42541
|
-
|
|
42542
|
-
|
|
43492
|
+
const body = await readJsonBody(req);
|
|
43493
|
+
if (!isPlainObject2(body) || typeof body.path !== "string") {
|
|
43494
|
+
writeJson(res, 400, { error: "invalid_folder" });
|
|
42543
43495
|
return;
|
|
42544
43496
|
}
|
|
42545
|
-
|
|
43497
|
+
try {
|
|
43498
|
+
writeJson(res, 200, { folderGrantId: folderGrants.issue(body.path) });
|
|
43499
|
+
} catch {
|
|
43500
|
+
writeJson(res, 400, { error: "invalid_folder" });
|
|
43501
|
+
}
|
|
42546
43502
|
}
|
|
42547
43503
|
async function handleTerminalSessions(req, res) {
|
|
42548
43504
|
if (!isTerminalAuthorized(req)) {
|
|
@@ -42571,6 +43527,17 @@ function createConsoleServer(deps = {}) {
|
|
|
42571
43527
|
}
|
|
42572
43528
|
await createTerminalSessionForCwd(cwd, res, cliId);
|
|
42573
43529
|
}
|
|
43530
|
+
function injectRenameCommand(sessionId, label) {
|
|
43531
|
+
if (!label) return;
|
|
43532
|
+
const renameCommand = terminalSessions.getSessionRenameCommand(sessionId);
|
|
43533
|
+
if (!renameCommand) return;
|
|
43534
|
+
const safeLabel = sanitizeCarrierResultReminder(label.replace(/[\r\n\t]+/g, " ")).trim();
|
|
43535
|
+
if (safeLabel.length === 0) return;
|
|
43536
|
+
const policy = terminalSessions.getSessionMessagePolicy(sessionId) ?? {};
|
|
43537
|
+
for (const chunk of formatCarrierResultReminderMessage(policy, `${renameCommand} ${safeLabel}`)) {
|
|
43538
|
+
terminalSessions.writeToSession(sessionId, chunk);
|
|
43539
|
+
}
|
|
43540
|
+
}
|
|
42574
43541
|
async function handleTerminalSessionItem(req, res, sessionId) {
|
|
42575
43542
|
if (req.method !== "DELETE" && req.method !== "PATCH") {
|
|
42576
43543
|
writeJson(res, 405, { error: "Method not allowed" });
|
|
@@ -42592,13 +43559,62 @@ function createConsoleServer(deps = {}) {
|
|
|
42592
43559
|
return;
|
|
42593
43560
|
}
|
|
42594
43561
|
observability.notifySessionUpdated(updated);
|
|
43562
|
+
injectRenameCommand(sessionId, updated.label);
|
|
43563
|
+
persistDurableState();
|
|
42595
43564
|
writeJson(res, 200, updated);
|
|
42596
43565
|
return;
|
|
42597
43566
|
}
|
|
42598
|
-
|
|
42599
|
-
observability.removeTerminalSession(sessionId);
|
|
43567
|
+
forgetTerminalSession(sessionId);
|
|
42600
43568
|
writeJson(res, 200, { ok: true });
|
|
42601
43569
|
}
|
|
43570
|
+
async function handleTerminalSessionResume(req, res, sessionId) {
|
|
43571
|
+
if (req.method !== "POST") {
|
|
43572
|
+
writeJson(res, 405, { error: "Method not allowed" });
|
|
43573
|
+
return;
|
|
43574
|
+
}
|
|
43575
|
+
if (!isTerminalAuthorized(req)) {
|
|
43576
|
+
writeJson(res, 401, { error: "unauthorized" });
|
|
43577
|
+
return;
|
|
43578
|
+
}
|
|
43579
|
+
const dormantSession = observability.listTerminalSessions().find((session) => session.sessionId === sessionId && session.status === "dormant");
|
|
43580
|
+
const operation = dormantSession ? observability.getDurableOperation(sessionId) : null;
|
|
43581
|
+
if (!operation) {
|
|
43582
|
+
writeJson(res, 404, { error: "session_not_found" });
|
|
43583
|
+
return;
|
|
43584
|
+
}
|
|
43585
|
+
const cliId = readDurableAgentCliId(operation);
|
|
43586
|
+
if (!cliId) {
|
|
43587
|
+
writeJson(res, 409, { error: "resume_unavailable" });
|
|
43588
|
+
return;
|
|
43589
|
+
}
|
|
43590
|
+
const providerSession = operation.providerSession ?? readProviderSessionCapture(sessionId, { capturesDir: durablePaths.capturesDir });
|
|
43591
|
+
if (!providerSession) {
|
|
43592
|
+
writeJson(res, 409, { error: "resume_unavailable" });
|
|
43593
|
+
return;
|
|
43594
|
+
}
|
|
43595
|
+
observability.updateTerminalSessionProviderSession(sessionId, providerSession);
|
|
43596
|
+
const starting = observability.updateTerminalSessionStatus(sessionId, "starting");
|
|
43597
|
+
if (starting) observability.notifySessionUpdated(starting);
|
|
43598
|
+
try {
|
|
43599
|
+
await terminalSessions.createSession({ sessionId, cwd: operation.cwd, cliId, resumeSessionId: providerSession.sessionId });
|
|
43600
|
+
const runtimeSession = pendingRuntimeSessions.get(sessionId);
|
|
43601
|
+
pendingRuntimeSessions.delete(sessionId);
|
|
43602
|
+
const resumed = runtimeSession ? observability.registerTerminalRuntimeSession(runtimeSession) ?? starting : observability.updateTerminalSessionStatus(sessionId, "terminal-only") ?? starting;
|
|
43603
|
+
if (!resumed) {
|
|
43604
|
+
writeJson(res, 404, { error: "session_not_found" });
|
|
43605
|
+
return;
|
|
43606
|
+
}
|
|
43607
|
+
observability.notifySessionUpdated(resumed);
|
|
43608
|
+
persistDurableState();
|
|
43609
|
+
writeJson(res, 200, resumed);
|
|
43610
|
+
} catch {
|
|
43611
|
+
pendingRuntimeSessions.delete(sessionId);
|
|
43612
|
+
const reverted = observability.updateTerminalSessionStatus(sessionId, "dormant");
|
|
43613
|
+
if (reverted) observability.notifySessionUpdated(reverted);
|
|
43614
|
+
persistDurableState();
|
|
43615
|
+
writeJson(res, 503, { error: "terminal_unavailable" });
|
|
43616
|
+
}
|
|
43617
|
+
}
|
|
42602
43618
|
async function handleObserverTheaters(req, res) {
|
|
42603
43619
|
if (req.method === "GET") {
|
|
42604
43620
|
writeJson(res, 200, { theaters: listTheaterInfos(), agentClis: getAgentCliMetadata() });
|
|
@@ -42612,27 +43628,44 @@ function createConsoleServer(deps = {}) {
|
|
|
42612
43628
|
writeJson(res, 401, { error: "unauthorized" });
|
|
42613
43629
|
return;
|
|
42614
43630
|
}
|
|
42615
|
-
const
|
|
42616
|
-
if (
|
|
42617
|
-
writeJson(res,
|
|
43631
|
+
const body = await readJsonBody(req);
|
|
43632
|
+
if (!isPlainObject2(body) || typeof body.folderGrantId !== "string") {
|
|
43633
|
+
writeJson(res, 400, { error: "invalid_folder_grant" });
|
|
42618
43634
|
return;
|
|
42619
43635
|
}
|
|
42620
|
-
|
|
42621
|
-
|
|
43636
|
+
const cwd = folderGrants.consume(body.folderGrantId);
|
|
43637
|
+
if (!cwd) {
|
|
43638
|
+
writeJson(res, 400, { error: "invalid_folder_grant" });
|
|
42622
43639
|
return;
|
|
42623
43640
|
}
|
|
42624
|
-
const theater = await theaters.register(
|
|
43641
|
+
const theater = await theaters.register(cwd);
|
|
42625
43642
|
let hasWiki = false;
|
|
42626
43643
|
try {
|
|
42627
|
-
await codex.registerWorkspace(
|
|
43644
|
+
await codex.registerWorkspace(cwd);
|
|
42628
43645
|
hasWiki = true;
|
|
42629
43646
|
} catch (error51) {
|
|
42630
43647
|
if (!(error51 instanceof Error && error51.message === "knowledge_root_missing")) {
|
|
42631
43648
|
console.warn(`[fleet-console] Codex workspace registration skipped for Theater ${theater.id}: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
42632
43649
|
}
|
|
42633
43650
|
}
|
|
43651
|
+
persistDurableState();
|
|
42634
43652
|
writeJson(res, 200, toTheaterInfo(theater, hasWiki));
|
|
42635
43653
|
}
|
|
43654
|
+
async function handleObserverTheaterItem(req, res, theaterId) {
|
|
43655
|
+
if (req.method !== "DELETE") {
|
|
43656
|
+
writeJson(res, 405, { error: "Method not allowed" });
|
|
43657
|
+
return;
|
|
43658
|
+
}
|
|
43659
|
+
if (!isTerminalAuthorized(req)) {
|
|
43660
|
+
writeJson(res, 401, { error: "unauthorized" });
|
|
43661
|
+
return;
|
|
43662
|
+
}
|
|
43663
|
+
const operations = observability.listDurableOperations().filter((operation) => operation.theaterId === theaterId);
|
|
43664
|
+
theaters.remove(theaterId);
|
|
43665
|
+
for (const operation of operations) forgetTerminalSession(operation.sessionId, { persist: false });
|
|
43666
|
+
persistDurableState();
|
|
43667
|
+
writeJson(res, 200, { ok: true });
|
|
43668
|
+
}
|
|
42636
43669
|
async function handleObserverTheaterSessions(req, res, theaterId) {
|
|
42637
43670
|
if (req.method !== "POST") {
|
|
42638
43671
|
writeJson(res, 405, { error: "Method not allowed" });
|
|
@@ -42653,7 +43686,7 @@ function createConsoleServer(deps = {}) {
|
|
|
42653
43686
|
await createTerminalSessionForCwd(theater.path, res, cliId);
|
|
42654
43687
|
}
|
|
42655
43688
|
async function createTerminalSessionForCwd(cwd, res, cliId) {
|
|
42656
|
-
const sessionId =
|
|
43689
|
+
const sessionId = crypto5.randomUUID();
|
|
42657
43690
|
const session = observability.createPendingTerminalSession({ sessionId, cwd, cliId });
|
|
42658
43691
|
try {
|
|
42659
43692
|
await terminalSessions.createSession({ sessionId, cwd, cliId });
|
|
@@ -42661,6 +43694,7 @@ function createConsoleServer(deps = {}) {
|
|
|
42661
43694
|
pendingRuntimeSessions.delete(sessionId);
|
|
42662
43695
|
const created = runtimeSession ? observability.registerTerminalRuntimeSession(runtimeSession) ?? session : observability.updateTerminalSessionStatus(sessionId, "terminal-only") ?? session;
|
|
42663
43696
|
observability.notifySessionUpdated(created);
|
|
43697
|
+
persistDurableState();
|
|
42664
43698
|
writeJson(res, 200, created);
|
|
42665
43699
|
} catch (error51) {
|
|
42666
43700
|
pendingRuntimeSessions.delete(sessionId);
|
|
@@ -42734,6 +43768,13 @@ function createConsoleServer(deps = {}) {
|
|
|
42734
43768
|
function listTheaterInfos() {
|
|
42735
43769
|
return theaters.list().map((theater) => toTheaterInfo(theater, codex.getWorkspace(theater.id) !== null));
|
|
42736
43770
|
}
|
|
43771
|
+
function forgetTerminalSession(sessionId, options = {}) {
|
|
43772
|
+
terminalSessions.terminate(sessionId);
|
|
43773
|
+
pendingRuntimeSessions.delete(sessionId);
|
|
43774
|
+
observability.removeTerminalSession(sessionId);
|
|
43775
|
+
unlinkProviderSessionCapture(sessionId, { capturesDir: durablePaths.capturesDir });
|
|
43776
|
+
if (options.persist !== false) persistDurableState();
|
|
43777
|
+
}
|
|
42737
43778
|
function toTheaterInfo(theater, hasWiki) {
|
|
42738
43779
|
return {
|
|
42739
43780
|
id: theater.id,
|
|
@@ -42796,12 +43837,69 @@ function createConsoleServer(deps = {}) {
|
|
|
42796
43837
|
terminalUpgrade.close();
|
|
42797
43838
|
currentLock?.release();
|
|
42798
43839
|
}
|
|
43840
|
+
function rehydrateDurableState() {
|
|
43841
|
+
let state;
|
|
43842
|
+
try {
|
|
43843
|
+
state = durableStateStore.load();
|
|
43844
|
+
theaters.restore(state.theaters);
|
|
43845
|
+
} catch (error51) {
|
|
43846
|
+
console.warn(`[fleet-console] Durable state restore skipped: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
43847
|
+
state = emptyDurableConsoleState();
|
|
43848
|
+
theaters.restore([]);
|
|
43849
|
+
}
|
|
43850
|
+
const merged = mergeProviderSessionCaptures(state, { capturesDir: durablePaths.capturesDir });
|
|
43851
|
+
syncProviderSessionsToObservability(merged);
|
|
43852
|
+
const restorable = {
|
|
43853
|
+
...merged,
|
|
43854
|
+
operations: merged.operations.filter((operation) => operation.providerSession)
|
|
43855
|
+
};
|
|
43856
|
+
if (merged !== state || restorable.operations.length !== merged.operations.length) {
|
|
43857
|
+
try {
|
|
43858
|
+
durableStateStore.save(restorable);
|
|
43859
|
+
cleanupProviderSessionCaptures(restorable, { capturesDir: durablePaths.capturesDir });
|
|
43860
|
+
} catch (error51) {
|
|
43861
|
+
console.warn(`[fleet-console] Durable state capture merge was not persisted: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
43862
|
+
}
|
|
43863
|
+
} else {
|
|
43864
|
+
cleanupProviderSessionCaptures(restorable, { capturesDir: durablePaths.capturesDir });
|
|
43865
|
+
}
|
|
43866
|
+
for (const operation of restorable.operations) {
|
|
43867
|
+
if (theaters.get(operation.theaterId)) observability.injectDormantOperation(operation);
|
|
43868
|
+
}
|
|
43869
|
+
}
|
|
43870
|
+
function persistDurableState() {
|
|
43871
|
+
try {
|
|
43872
|
+
const state = mergeProviderSessionCaptures({
|
|
43873
|
+
version: 1,
|
|
43874
|
+
theaters: theaters.list(),
|
|
43875
|
+
operations: observability.listDurableOperations()
|
|
43876
|
+
}, { capturesDir: durablePaths.capturesDir });
|
|
43877
|
+
syncProviderSessionsToObservability(state);
|
|
43878
|
+
const operationsWithProviderSession = state.operations.filter((operation) => operation.providerSession);
|
|
43879
|
+
durableStateStore.save({
|
|
43880
|
+
version: state.version,
|
|
43881
|
+
theaters: state.theaters,
|
|
43882
|
+
// 대화 없는 빈 Operation 드롭은 rehydrate에서 capture 머지 뒤에만 수행한다.
|
|
43883
|
+
// create 시점의 메타데이터를 먼저 남겨야 이후 도착한 capture 파일이 재시작 때 병합될 수 있다.
|
|
43884
|
+
operations: state.operations
|
|
43885
|
+
});
|
|
43886
|
+
cleanupProviderSessionCaptures({ ...state, operations: operationsWithProviderSession }, { capturesDir: durablePaths.capturesDir });
|
|
43887
|
+
} catch (error51) {
|
|
43888
|
+
console.warn(`[fleet-console] Durable state save failed: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
43889
|
+
}
|
|
43890
|
+
}
|
|
43891
|
+
function syncProviderSessionsToObservability(state) {
|
|
43892
|
+
for (const operation of state.operations) {
|
|
43893
|
+
if (operation.providerSession) observability.updateTerminalSessionProviderSession(operation.sessionId, operation.providerSession);
|
|
43894
|
+
}
|
|
43895
|
+
}
|
|
42799
43896
|
return {
|
|
42800
43897
|
host,
|
|
42801
43898
|
port,
|
|
42802
43899
|
async start(lockPaths) {
|
|
42803
43900
|
if (server && lockHandle) return lockHandle.payload.endpoint;
|
|
42804
43901
|
try {
|
|
43902
|
+
rehydrateDurableState();
|
|
42805
43903
|
await new Promise((resolve, reject) => {
|
|
42806
43904
|
const srv = createHttpServer(handleRequest, terminalUpgrade);
|
|
42807
43905
|
srv.once("error", reject);
|
|
@@ -42884,6 +43982,14 @@ function resolveCarrierEventOrigin(event, jobOriginById) {
|
|
|
42884
43982
|
function queueOriginCleanup(jobId, jobOriginById) {
|
|
42885
43983
|
queueMicrotask(() => jobOriginById.delete(jobId));
|
|
42886
43984
|
}
|
|
43985
|
+
function readDurableAgentCliId(operation) {
|
|
43986
|
+
if (!operation.cliId) return null;
|
|
43987
|
+
try {
|
|
43988
|
+
return parseAgentCliId(operation.cliId) ?? null;
|
|
43989
|
+
} catch {
|
|
43990
|
+
return null;
|
|
43991
|
+
}
|
|
43992
|
+
}
|
|
42887
43993
|
function createHttpServer(handler, terminalUpgrade) {
|
|
42888
43994
|
const srv = http.createServer(handler);
|
|
42889
43995
|
srv.timeout = SERVER_TIMEOUT_MS;
|
|
@@ -42943,6 +44049,14 @@ function readOptionalAgentCliId(value, res) {
|
|
|
42943
44049
|
return false;
|
|
42944
44050
|
}
|
|
42945
44051
|
}
|
|
44052
|
+
function terminalFolderListStatus(error51) {
|
|
44053
|
+
if (error51.code === "forbidden") return 403;
|
|
44054
|
+
if (error51.code === "not_found") return 404;
|
|
44055
|
+
return 400;
|
|
44056
|
+
}
|
|
44057
|
+
function isPlainObject2(value) {
|
|
44058
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
44059
|
+
}
|
|
42946
44060
|
async function readJsonBody(req) {
|
|
42947
44061
|
const chunks = [];
|
|
42948
44062
|
let total = 0;
|
|
@@ -43001,6 +44115,78 @@ function isAllowedTerminalOrigin(req, expectedPort) {
|
|
|
43001
44115
|
if (origin === void 0) return true;
|
|
43002
44116
|
return origin === `http://127.0.0.1:${expectedPort}`;
|
|
43003
44117
|
}
|
|
44118
|
+
var CAPTURE_TEMP_PREFIX = ".capture.";
|
|
44119
|
+
async function runCaptureSessionHook(provider, env = process6.env) {
|
|
44120
|
+
return captureSession({
|
|
44121
|
+
diagnostics: process6.stderr,
|
|
44122
|
+
env,
|
|
44123
|
+
input: await readStdin(),
|
|
44124
|
+
provider
|
|
44125
|
+
});
|
|
44126
|
+
}
|
|
44127
|
+
function captureSession(options) {
|
|
44128
|
+
try {
|
|
44129
|
+
return captureSessionStrict(options);
|
|
44130
|
+
} catch (error51) {
|
|
44131
|
+
options.diagnostics?.write(`[fleet-console] capture-session skipped: ${error51 instanceof Error ? error51.message : String(error51)}
|
|
44132
|
+
`);
|
|
44133
|
+
return null;
|
|
44134
|
+
}
|
|
44135
|
+
}
|
|
44136
|
+
function captureSessionStrict(options) {
|
|
44137
|
+
const provider = parseProvider(options.provider);
|
|
44138
|
+
const fleetSessionId = readFleetSessionId(options.env ?? process6.env);
|
|
44139
|
+
const input = parseHookInput(options.input ?? "");
|
|
44140
|
+
const providerSession = toProviderSession(provider, input, options.now ?? (() => /* @__PURE__ */ new Date()));
|
|
44141
|
+
const capturesDir = (options.paths ?? createConsoleDataPaths()).capturesDir;
|
|
44142
|
+
const finalPath = path93__default.join(capturesDir, `${fleetSessionId}.json`);
|
|
44143
|
+
const tempPath = path93__default.join(capturesDir, `${CAPTURE_TEMP_PREFIX}${fleetSessionId}.${process6.pid}.${Date.now()}.tmp`);
|
|
44144
|
+
fs5__default.mkdirSync(capturesDir, { recursive: true, mode: 448 });
|
|
44145
|
+
fs5__default.writeFileSync(tempPath, `${JSON.stringify(providerSession, null, 2)}
|
|
44146
|
+
`, { mode: 384 });
|
|
44147
|
+
fs5__default.renameSync(tempPath, finalPath);
|
|
44148
|
+
return { path: finalPath, providerSession };
|
|
44149
|
+
}
|
|
44150
|
+
function parseProvider(value) {
|
|
44151
|
+
if (value === "claude" || value === "codex") return value;
|
|
44152
|
+
throw new Error("invalid_provider");
|
|
44153
|
+
}
|
|
44154
|
+
function readFleetSessionId(env) {
|
|
44155
|
+
const value = env.FLEET_CONSOLE_SESSION_ID;
|
|
44156
|
+
if (!value) throw new Error("missing_fleet_session_id");
|
|
44157
|
+
if (path93__default.basename(value) !== value || value.includes(path93__default.sep) || value.includes(path93__default.posix.sep)) {
|
|
44158
|
+
throw new Error("invalid_fleet_session_id");
|
|
44159
|
+
}
|
|
44160
|
+
return value;
|
|
44161
|
+
}
|
|
44162
|
+
function parseHookInput(input) {
|
|
44163
|
+
try {
|
|
44164
|
+
const parsed = JSON.parse(input);
|
|
44165
|
+
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) return parsed;
|
|
44166
|
+
} catch {
|
|
44167
|
+
}
|
|
44168
|
+
throw new Error("invalid_hook_input");
|
|
44169
|
+
}
|
|
44170
|
+
function toProviderSession(provider, input, now) {
|
|
44171
|
+
if (typeof input.session_id !== "string" || input.session_id.length === 0) throw new Error("missing_provider_session_id");
|
|
44172
|
+
return {
|
|
44173
|
+
provider,
|
|
44174
|
+
sessionId: input.session_id,
|
|
44175
|
+
...typeof input.transcript_path === "string" && input.transcript_path.length > 0 ? { transcriptPath: input.transcript_path } : {},
|
|
44176
|
+
...typeof input.source === "string" && input.source.length > 0 ? { source: input.source } : {},
|
|
44177
|
+
capturedAt: now().toISOString()
|
|
44178
|
+
};
|
|
44179
|
+
}
|
|
44180
|
+
function readStdin() {
|
|
44181
|
+
return new Promise((resolve, reject) => {
|
|
44182
|
+
const chunks = [];
|
|
44183
|
+
process6.stdin.on("data", (chunk) => {
|
|
44184
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
44185
|
+
});
|
|
44186
|
+
process6.stdin.on("error", reject);
|
|
44187
|
+
process6.stdin.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
|
|
44188
|
+
});
|
|
44189
|
+
}
|
|
43004
44190
|
function createConsoleStalePolicy(deps = {}) {
|
|
43005
44191
|
const fsImpl = deps.fs ?? fs5__default;
|
|
43006
44192
|
function isBuildStale(lock, buildFile) {
|
|
@@ -43013,12 +44199,42 @@ function createConsoleStalePolicy(deps = {}) {
|
|
|
43013
44199
|
}
|
|
43014
44200
|
return { isBuildStale };
|
|
43015
44201
|
}
|
|
44202
|
+
var TURN_POST_TIMEOUT_MS = 1500;
|
|
44203
|
+
async function runTurnStateHook(phase, env = process6.env, options = {}) {
|
|
44204
|
+
try {
|
|
44205
|
+
await postTurnState(phase, env, options);
|
|
44206
|
+
} catch {
|
|
44207
|
+
}
|
|
44208
|
+
}
|
|
44209
|
+
async function postTurnState(phase, env, options) {
|
|
44210
|
+
const sessionId = env.FLEET_CONSOLE_SESSION_ID;
|
|
44211
|
+
if (!sessionId) return;
|
|
44212
|
+
const paths = createConsolePaths({ env });
|
|
44213
|
+
const lock = createConsoleLock().readLock(paths.lockFile);
|
|
44214
|
+
if (!lock) return;
|
|
44215
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
44216
|
+
const controller = new AbortController();
|
|
44217
|
+
const timer = setTimeout(() => controller.abort(), options.timeoutMs ?? TURN_POST_TIMEOUT_MS);
|
|
44218
|
+
try {
|
|
44219
|
+
await fetchImpl(`${lock.endpoint}terminal/sessions/${encodeURIComponent(sessionId)}/turn`, {
|
|
44220
|
+
method: "POST",
|
|
44221
|
+
headers: {
|
|
44222
|
+
authorization: `Bearer ${lock.token}`,
|
|
44223
|
+
"content-type": "application/json"
|
|
44224
|
+
},
|
|
44225
|
+
body: JSON.stringify({ phase }),
|
|
44226
|
+
signal: controller.signal
|
|
44227
|
+
});
|
|
44228
|
+
} finally {
|
|
44229
|
+
clearTimeout(timer);
|
|
44230
|
+
}
|
|
44231
|
+
}
|
|
43016
44232
|
|
|
43017
44233
|
// src/cli.ts
|
|
43018
44234
|
var FIXED_HOST = "127.0.0.1";
|
|
43019
44235
|
var HELP_BANNER_INDENT = " ";
|
|
43020
44236
|
var DEFAULT_HELP_RELEASE = "local";
|
|
43021
|
-
var CONSOLE_HOOK_COMMANDS = /* @__PURE__ */ new Set(["subagents-context"]);
|
|
44237
|
+
var CONSOLE_HOOK_COMMANDS = /* @__PURE__ */ new Set(["capture-session", "subagents-context", "turn-start", "turn-end"]);
|
|
43022
44238
|
function parseConsoleCliMode(argv) {
|
|
43023
44239
|
if (argv.length === 0) return "start";
|
|
43024
44240
|
const [first, ...rest] = argv;
|
|
@@ -43045,10 +44261,14 @@ Run 'fleet console --help' for usage.`);
|
|
|
43045
44261
|
}
|
|
43046
44262
|
function parseConsoleHookCommand(argv) {
|
|
43047
44263
|
const [commandName, ...rest] = argv;
|
|
43048
|
-
if (!commandName || !CONSOLE_HOOK_COMMANDS.has(commandName)
|
|
44264
|
+
if (!commandName || !CONSOLE_HOOK_COMMANDS.has(commandName)) {
|
|
43049
44265
|
throw new Error("Unknown fleet-console hook command");
|
|
43050
44266
|
}
|
|
43051
|
-
return "subagents-context";
|
|
44267
|
+
if (commandName === "subagents-context" && rest.length === 0) return { command: "subagents-context" };
|
|
44268
|
+
if (commandName === "turn-start" && rest.length === 0) return { command: "turn-start" };
|
|
44269
|
+
if (commandName === "turn-end" && rest.length === 0) return { command: "turn-end" };
|
|
44270
|
+
if (commandName === "capture-session" && rest.length === 1 && rest[0]) return { command: "capture-session", provider: rest[0] };
|
|
44271
|
+
throw new Error("Unknown fleet-console hook command");
|
|
43052
44272
|
}
|
|
43053
44273
|
function buildConsoleHelpText(options = {}) {
|
|
43054
44274
|
const colorEnabled = resolveColorEnabled(options);
|
|
@@ -43110,8 +44330,8 @@ function buildWikiHelpText(options = {}) {
|
|
|
43110
44330
|
return colorEnabled ? text : stripAnsi(text);
|
|
43111
44331
|
}
|
|
43112
44332
|
function createConsoleDaemonLifecycle(deps = {}) {
|
|
43113
|
-
const env = deps.env ??
|
|
43114
|
-
const execPath = deps.execPath ??
|
|
44333
|
+
const env = deps.env ?? process6.env;
|
|
44334
|
+
const execPath = deps.execPath ?? process6.execPath;
|
|
43115
44335
|
const serverModulePath = deps.serverModulePath ?? resolveDefaultServerModulePath();
|
|
43116
44336
|
const spawnDetached = deps.spawnDetached ?? ((bin, args, options) => {
|
|
43117
44337
|
spawn(bin, [...args], options).unref();
|
|
@@ -43125,10 +44345,10 @@ function createConsoleDaemonLifecycle(deps = {}) {
|
|
|
43125
44345
|
const server = createConsoleServer();
|
|
43126
44346
|
await server.start(paths);
|
|
43127
44347
|
await new Promise((resolve) => {
|
|
43128
|
-
|
|
44348
|
+
process6.once("SIGTERM", () => {
|
|
43129
44349
|
void server.stop().finally(resolve);
|
|
43130
44350
|
});
|
|
43131
|
-
|
|
44351
|
+
process6.once("SIGINT", () => {
|
|
43132
44352
|
void server.stop().finally(resolve);
|
|
43133
44353
|
});
|
|
43134
44354
|
});
|
|
@@ -43142,14 +44362,14 @@ function createConsoleDaemonLifecycle(deps = {}) {
|
|
|
43142
44362
|
const payload = readTrustedLock();
|
|
43143
44363
|
if (!payload) return;
|
|
43144
44364
|
try {
|
|
43145
|
-
|
|
44365
|
+
process6.kill(payload.pid, "SIGTERM");
|
|
43146
44366
|
} catch (err) {
|
|
43147
44367
|
if (err.code !== "ESRCH") throw err;
|
|
43148
44368
|
}
|
|
43149
44369
|
await sleep(200);
|
|
43150
44370
|
try {
|
|
43151
|
-
|
|
43152
|
-
|
|
44371
|
+
process6.kill(payload.pid, 0);
|
|
44372
|
+
process6.kill(payload.pid, "SIGKILL");
|
|
43153
44373
|
} catch (err) {
|
|
43154
44374
|
if (err.code !== "ESRCH") throw err;
|
|
43155
44375
|
}
|
|
@@ -43256,49 +44476,55 @@ async function runConsoleRestart(deps = {}) {
|
|
|
43256
44476
|
return openFleetConsole({ lifecycle, openBrowser: deps.openBrowser });
|
|
43257
44477
|
}
|
|
43258
44478
|
async function main() {
|
|
43259
|
-
if (
|
|
44479
|
+
if (process6.argv[2] === "serve") {
|
|
43260
44480
|
await createConsoleDaemonLifecycle().runServer();
|
|
43261
44481
|
return;
|
|
43262
44482
|
}
|
|
43263
|
-
if (
|
|
43264
|
-
parseConsoleHookCommand(
|
|
43265
|
-
{
|
|
43266
|
-
|
|
44483
|
+
if (process6.argv[2] === "hook") {
|
|
44484
|
+
const hookCommand = parseConsoleHookCommand(process6.argv.slice(3));
|
|
44485
|
+
if (hookCommand.command === "subagents-context") {
|
|
44486
|
+
process6.stdout.write(`${runSubagentsContextHook(process6.env)}
|
|
43267
44487
|
`);
|
|
43268
44488
|
return;
|
|
43269
44489
|
}
|
|
44490
|
+
if (hookCommand.command === "turn-start" || hookCommand.command === "turn-end") {
|
|
44491
|
+
await runTurnStateHook(hookCommand.command === "turn-start" ? "start" : "end", process6.env);
|
|
44492
|
+
return;
|
|
44493
|
+
}
|
|
44494
|
+
await runCaptureSessionHook(hookCommand.provider, process6.env);
|
|
44495
|
+
return;
|
|
43270
44496
|
}
|
|
43271
|
-
if (
|
|
43272
|
-
await mainWiki(
|
|
44497
|
+
if (process6.argv[2] === "codex") {
|
|
44498
|
+
await mainWiki(process6.argv.slice(3));
|
|
43273
44499
|
return;
|
|
43274
44500
|
}
|
|
43275
|
-
const mode = parseConsoleCliMode(
|
|
44501
|
+
const mode = parseConsoleCliMode(process6.argv.slice(2));
|
|
43276
44502
|
if (mode === "help") {
|
|
43277
|
-
|
|
44503
|
+
process6.stdout.write(`${buildConsoleHelpText({ env: process6.env, isTTY: process6.stdout.isTTY })}
|
|
43278
44504
|
`);
|
|
43279
44505
|
return;
|
|
43280
44506
|
}
|
|
43281
44507
|
if (mode === "status") {
|
|
43282
|
-
|
|
44508
|
+
process6.stdout.write(`${await runConsoleStatus()}
|
|
43283
44509
|
`);
|
|
43284
44510
|
return;
|
|
43285
44511
|
}
|
|
43286
44512
|
if (mode === "stop") {
|
|
43287
|
-
|
|
44513
|
+
process6.stdout.write(`${await runConsoleStop()}
|
|
43288
44514
|
`);
|
|
43289
44515
|
return;
|
|
43290
44516
|
}
|
|
43291
44517
|
if (mode === "restart") {
|
|
43292
44518
|
await runConsoleRestart();
|
|
43293
|
-
|
|
44519
|
+
process6.stdout.write("Fleet Console restarted.\n");
|
|
43294
44520
|
return;
|
|
43295
44521
|
}
|
|
43296
44522
|
await openFleetConsole();
|
|
43297
|
-
|
|
44523
|
+
process6.stdout.write("Fleet Console opened.\n");
|
|
43298
44524
|
}
|
|
43299
|
-
async function mainWiki(argv =
|
|
44525
|
+
async function mainWiki(argv = process6.argv.slice(2)) {
|
|
43300
44526
|
if (argv.includes("--help") || argv.includes("-h")) {
|
|
43301
|
-
|
|
44527
|
+
process6.stdout.write(`${buildWikiHelpText({ env: process6.env, isTTY: process6.stdout.isTTY })}
|
|
43302
44528
|
`);
|
|
43303
44529
|
return;
|
|
43304
44530
|
}
|
|
@@ -43310,19 +44536,19 @@ async function mainWiki(argv = process4.argv.slice(2)) {
|
|
|
43310
44536
|
if (unsupported.length > 0) {
|
|
43311
44537
|
throw new Error(`Unknown fleet wiki option: ${unsupported[0]}`);
|
|
43312
44538
|
}
|
|
43313
|
-
await openFleetWikiWorkspace({ cwd:
|
|
44539
|
+
await openFleetWikiWorkspace({ cwd: process6.cwd() });
|
|
43314
44540
|
}
|
|
43315
44541
|
function resolveDefaultServerModulePath() {
|
|
43316
44542
|
const builtPath = new URL("../dist/cli.mjs", import.meta.url).pathname;
|
|
43317
44543
|
if (fs5__default.existsSync(builtPath)) return builtPath;
|
|
43318
44544
|
return fileURLToPath(import.meta.url);
|
|
43319
44545
|
}
|
|
43320
|
-
var isDirectRun =
|
|
44546
|
+
var isDirectRun = process6.argv[1] && path93__default.resolve(process6.argv[1]) === fileURLToPath(import.meta.url);
|
|
43321
44547
|
if (isDirectRun) {
|
|
43322
44548
|
await main().catch((error51) => {
|
|
43323
|
-
|
|
44549
|
+
process6.stderr.write(`${error51 instanceof Error ? error51.message : String(error51)}
|
|
43324
44550
|
`);
|
|
43325
|
-
|
|
44551
|
+
process6.exitCode = 1;
|
|
43326
44552
|
});
|
|
43327
44553
|
}
|
|
43328
44554
|
|