@dotobokuri/fleet-cli 1.5.5 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1683 -521
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -18469,7 +18469,7 @@ var init_models = __esm({
|
|
|
18469
18469
|
"../../packages/core-unified-agent/models.json"() {
|
|
18470
18470
|
models_default = {
|
|
18471
18471
|
version: 1,
|
|
18472
|
-
updatedAt: "2026-06-
|
|
18472
|
+
updatedAt: "2026-06-16T00:00:00Z",
|
|
18473
18473
|
providers: {
|
|
18474
18474
|
claude: {
|
|
18475
18475
|
name: "Claude Code with Anthropic",
|
|
@@ -18479,7 +18479,9 @@ var init_models = __esm({
|
|
|
18479
18479
|
{ modelId: "sonnet", name: "Claude Sonnet", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "medium" } },
|
|
18480
18480
|
{ modelId: "opus", name: "Claude Opus", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "xhigh" } },
|
|
18481
18481
|
{ modelId: "opus[1m]", name: "Claude Opus [1M]", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "xhigh" } },
|
|
18482
|
-
{ modelId: "claude-opus-4-6[1m]", name: "Claude Opus 4.6 [1M]", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "high" } }
|
|
18482
|
+
{ modelId: "claude-opus-4-6[1m]", name: "Claude Opus 4.6 [1M]", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "high" } },
|
|
18483
|
+
{ modelId: "claude-opus-4-7[1m]", name: "Claude Opus 4.7 [1M]", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "high" } },
|
|
18484
|
+
{ modelId: "claude-opus-4-8[1m]", name: "Claude Opus 4.8 [1M]", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "high" } }
|
|
18483
18485
|
]
|
|
18484
18486
|
},
|
|
18485
18487
|
"claude-zai": {
|
|
@@ -33431,6 +33433,8 @@ function createClaudeFamilyCliDefinition(options2) {
|
|
|
33431
33433
|
lineTerminator: "\r",
|
|
33432
33434
|
multilineStrategy: "paste-mode"
|
|
33433
33435
|
},
|
|
33436
|
+
// Claude Code 계열은 세션 이름 변경 슬래시 명령 `/rename`을 지원한다.
|
|
33437
|
+
renameCommand: "/rename",
|
|
33434
33438
|
terminalName: "xterm-256color"
|
|
33435
33439
|
};
|
|
33436
33440
|
}
|
|
@@ -33454,7 +33458,7 @@ var codexCli = {
|
|
|
33454
33458
|
async createProfile(options2) {
|
|
33455
33459
|
const { bin, prefixArgs } = resolveBinary("codex", "CODEX_BIN", options2.env);
|
|
33456
33460
|
return {
|
|
33457
|
-
args: [...prefixArgs, "--no-alt-screen", ...buildModelArgs2(options2.model)],
|
|
33461
|
+
args: [...prefixArgs, ...buildResumeArgs(options2.resumeSessionId), "--no-alt-screen", ...buildModelArgs2(options2.model)],
|
|
33458
33462
|
bin,
|
|
33459
33463
|
binPrefixArgs: prefixArgs,
|
|
33460
33464
|
cwd: options2.cwd,
|
|
@@ -33466,10 +33470,15 @@ var codexCli = {
|
|
|
33466
33470
|
lineTerminator: "\r",
|
|
33467
33471
|
multilineStrategy: "paste-mode"
|
|
33468
33472
|
},
|
|
33473
|
+
// Codex CLI도 세션 이름 변경 슬래시 명령 `/rename`을 지원한다.
|
|
33474
|
+
renameCommand: "/rename",
|
|
33469
33475
|
terminalName: "xterm-256color"
|
|
33470
33476
|
};
|
|
33471
33477
|
}
|
|
33472
33478
|
};
|
|
33479
|
+
function buildResumeArgs(resumeSessionId) {
|
|
33480
|
+
return resumeSessionId === void 0 ? [] : ["resume", resumeSessionId];
|
|
33481
|
+
}
|
|
33473
33482
|
function buildModelArgs2(model) {
|
|
33474
33483
|
return model === void 0 ? [] : ["--model", model];
|
|
33475
33484
|
}
|
|
@@ -33486,7 +33495,8 @@ async function resolveAgentCliProfile(env, cwd, options2 = {}) {
|
|
|
33486
33495
|
authService: options2.authService,
|
|
33487
33496
|
cwd,
|
|
33488
33497
|
env,
|
|
33489
|
-
model: options2.model
|
|
33498
|
+
model: options2.model,
|
|
33499
|
+
resumeSessionId: options2.resumeSessionId
|
|
33490
33500
|
});
|
|
33491
33501
|
}
|
|
33492
33502
|
function resolveAgentCliId(env, options2 = {}) {
|
|
@@ -33562,6 +33572,7 @@ function buildClaudeNativeSubagentPlan(registry4) {
|
|
|
33562
33572
|
function buildClaudeNativeArgs(context) {
|
|
33563
33573
|
const systemPromptArg = context.replaceSystemPrompt ? "--system-prompt-file" : "--append-system-prompt-file";
|
|
33564
33574
|
return [
|
|
33575
|
+
...buildResumeArgs2(context.resumeSessionId),
|
|
33565
33576
|
systemPromptArg,
|
|
33566
33577
|
requireSystemPromptFile(context),
|
|
33567
33578
|
...context.pluginRoots.flatMap((pluginRoot) => [
|
|
@@ -33572,6 +33583,9 @@ function buildClaudeNativeArgs(context) {
|
|
|
33572
33583
|
"--dangerously-skip-permissions"
|
|
33573
33584
|
];
|
|
33574
33585
|
}
|
|
33586
|
+
function buildResumeArgs2(resumeSessionId) {
|
|
33587
|
+
return resumeSessionId === void 0 ? [] : ["--resume", resumeSessionId];
|
|
33588
|
+
}
|
|
33575
33589
|
function buildClaudeMcpConfig(servers) {
|
|
33576
33590
|
return JSON.stringify({
|
|
33577
33591
|
mcpServers: Object.fromEntries(
|
|
@@ -33629,20 +33643,32 @@ function escapeTomlMultilineString(value) {
|
|
|
33629
33643
|
});
|
|
33630
33644
|
return result;
|
|
33631
33645
|
}
|
|
33646
|
+
function buildPosixShellCommand(values) {
|
|
33647
|
+
return values.map(posixShellQuote).join(" ");
|
|
33648
|
+
}
|
|
33649
|
+
function posixShellQuote(value) {
|
|
33650
|
+
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
33651
|
+
}
|
|
33632
33652
|
var CODEX_TOOL_TIMEOUT_SEC = 1800;
|
|
33633
33653
|
function buildCodexNativeArgs(context) {
|
|
33634
33654
|
const profileName = requireCodexProfileName(context);
|
|
33635
33655
|
const args = [
|
|
33656
|
+
...buildResumeArgs3(context.resumeSessionId),
|
|
33636
33657
|
"--enable",
|
|
33637
33658
|
"plugins",
|
|
33638
33659
|
"--enable",
|
|
33639
33660
|
"child_agents_md",
|
|
33661
|
+
"--enable",
|
|
33662
|
+
"hooks",
|
|
33640
33663
|
"--profile",
|
|
33641
33664
|
profileName,
|
|
33642
33665
|
"-c",
|
|
33643
33666
|
'approval_policy="never"',
|
|
33644
33667
|
"-c",
|
|
33645
|
-
'sandbox_mode="danger-full-access"'
|
|
33668
|
+
'sandbox_mode="danger-full-access"',
|
|
33669
|
+
// hook 신뢰 프롬프트("Hooks need review")를 fleet 관리 세션에서 건너뛴다. bypass_hook_trust는
|
|
33670
|
+
// config 키가 아니라 전용 CLI 플래그이므로 -c override가 아닌 플래그로 전달해야 한다.
|
|
33671
|
+
"--dangerously-bypass-hook-trust"
|
|
33646
33672
|
];
|
|
33647
33673
|
for (const server of context.mcpServers) {
|
|
33648
33674
|
const prefix = `mcp_servers.${server.name}`;
|
|
@@ -33658,6 +33684,9 @@ function buildCodexNativeArgs(context) {
|
|
|
33658
33684
|
}
|
|
33659
33685
|
return args;
|
|
33660
33686
|
}
|
|
33687
|
+
function buildResumeArgs3(resumeSessionId) {
|
|
33688
|
+
return resumeSessionId === void 0 ? [] : ["resume", resumeSessionId];
|
|
33689
|
+
}
|
|
33661
33690
|
function requireCodexProfileName(context) {
|
|
33662
33691
|
if (context.codexProfileName) return context.codexProfileName;
|
|
33663
33692
|
throw new Error("Codex profile name is required for native injection");
|
|
@@ -33868,20 +33897,32 @@ function claudeHooks(options2) {
|
|
|
33868
33897
|
if (!hookExec) {
|
|
33869
33898
|
throw new Error("Fleet Claude session hook command is required");
|
|
33870
33899
|
}
|
|
33900
|
+
const captureSessionHookExec = options2.captureSessionHookExec;
|
|
33871
33901
|
return {
|
|
33872
33902
|
hooks: {
|
|
33873
33903
|
SessionStart: [{
|
|
33874
|
-
hooks: [
|
|
33875
|
-
|
|
33876
|
-
|
|
33877
|
-
|
|
33878
|
-
|
|
33879
|
-
type: "command"
|
|
33904
|
+
hooks: [claudeCommandHook(hookExec)]
|
|
33905
|
+
}],
|
|
33906
|
+
...captureSessionHookExec ? {
|
|
33907
|
+
UserPromptSubmit: [{
|
|
33908
|
+
hooks: [claudeCommandHook(captureSessionHookExec)]
|
|
33880
33909
|
}]
|
|
33881
|
-
}
|
|
33910
|
+
} : {}
|
|
33882
33911
|
}
|
|
33883
33912
|
};
|
|
33884
33913
|
}
|
|
33914
|
+
function claudeCommandHook(hookExec) {
|
|
33915
|
+
if (!hookExec) {
|
|
33916
|
+
throw new Error("Fleet Claude session hook command is required");
|
|
33917
|
+
}
|
|
33918
|
+
return {
|
|
33919
|
+
// exec 형식: command는 직접 spawn되는 실행 파일, args는 셸 토크나이징 없이 그대로 전달된다.
|
|
33920
|
+
// Windows cmd/powershell의 따옴표 규칙과 무관하게 동작하며 공백 포함 경로도 안전하다.
|
|
33921
|
+
args: [...hookExec.args],
|
|
33922
|
+
command: hookExec.command,
|
|
33923
|
+
type: "command"
|
|
33924
|
+
};
|
|
33925
|
+
}
|
|
33885
33926
|
function claudeAgentFile(subagent) {
|
|
33886
33927
|
const frontmatter = [
|
|
33887
33928
|
"---",
|
|
@@ -34417,7 +34458,6 @@ function renderPluginRoot(pluginRoot, bundle, options2, fleetRoot) {
|
|
|
34417
34458
|
const stagedPluginRoot = path82.join(stageParent, path82.basename(pluginRoot));
|
|
34418
34459
|
try {
|
|
34419
34460
|
ensurePrivateDir(stagedPluginRoot, stagedPluginRoot);
|
|
34420
|
-
writePrivateJson(path82.join(stagedPluginRoot, ".codex-plugin", "plugin.json"), codexManifest(bundle), stagedPluginRoot);
|
|
34421
34461
|
writePrivateJson(path82.join(stagedPluginRoot, ".claude-plugin", "plugin.json"), claudeManifest(bundle), stagedPluginRoot);
|
|
34422
34462
|
switch (bundle.source) {
|
|
34423
34463
|
case "asset":
|
|
@@ -34432,6 +34472,7 @@ function renderPluginRoot(pluginRoot, bundle, options2, fleetRoot) {
|
|
|
34432
34472
|
renderGlobalPluginRoot(stagedPluginRoot, fleetRoot);
|
|
34433
34473
|
break;
|
|
34434
34474
|
}
|
|
34475
|
+
writePrivateJson(path82.join(stagedPluginRoot, ".codex-plugin", "plugin.json"), codexManifest(bundle, stagedPluginRoot), stagedPluginRoot);
|
|
34435
34476
|
removePrivatePath(pluginRoot, parentRoot);
|
|
34436
34477
|
renameSync22(stagedPluginRoot, pluginRoot);
|
|
34437
34478
|
} finally {
|
|
@@ -34563,14 +34604,36 @@ function marketplacePluginPath(target, bundle) {
|
|
|
34563
34604
|
if (target.flat) return `./${FLAT_PLUGIN_DIR_NAME}`;
|
|
34564
34605
|
return `./${PLUGIN_BUNDLES_DIR_NAME}/${bundle.directoryName}`;
|
|
34565
34606
|
}
|
|
34566
|
-
function codexManifest(bundle) {
|
|
34607
|
+
function codexManifest(bundle, pluginRoot) {
|
|
34567
34608
|
return {
|
|
34568
34609
|
name: bundle.name,
|
|
34569
|
-
version:
|
|
34610
|
+
version: codexManifestVersion(bundle, pluginRoot),
|
|
34570
34611
|
description: bundle.description,
|
|
34571
34612
|
skills: "./skills/"
|
|
34572
34613
|
};
|
|
34573
34614
|
}
|
|
34615
|
+
function codexManifestVersion(bundle, pluginRoot) {
|
|
34616
|
+
const hash3 = crypto4.createHash("sha256");
|
|
34617
|
+
hash3.update(bundle.name);
|
|
34618
|
+
hash3.update("\0");
|
|
34619
|
+
hash3.update(bundle.description);
|
|
34620
|
+
hash3.update("\0");
|
|
34621
|
+
for (const filePath of listCodexEffectivePluginFiles(pluginRoot)) {
|
|
34622
|
+
const relativePath = path82.relative(pluginRoot, filePath);
|
|
34623
|
+
hash3.update(relativePath);
|
|
34624
|
+
hash3.update("\0");
|
|
34625
|
+
hash3.update(readFileSync42(filePath));
|
|
34626
|
+
hash3.update("\0");
|
|
34627
|
+
}
|
|
34628
|
+
return `0.0.0+${hash3.digest("hex").slice(0, 12)}`;
|
|
34629
|
+
}
|
|
34630
|
+
function listCodexEffectivePluginFiles(pluginRoot) {
|
|
34631
|
+
const skillsPath = path82.join(pluginRoot, "skills");
|
|
34632
|
+
if (!existsSync5(skillsPath)) return [];
|
|
34633
|
+
const files = [];
|
|
34634
|
+
collectRenderableFiles(pluginRoot, skillsPath, files, /* @__PURE__ */ new Set());
|
|
34635
|
+
return files.sort();
|
|
34636
|
+
}
|
|
34574
34637
|
function claudeManifest(bundle) {
|
|
34575
34638
|
return {
|
|
34576
34639
|
name: bundle.name,
|
|
@@ -34604,11 +34667,12 @@ async function injectAgentCliProfile(profile, options2) {
|
|
|
34604
34667
|
cwd: profile.cwd,
|
|
34605
34668
|
dataDir: options2.dataDir,
|
|
34606
34669
|
rootDir: options2.pluginRootDir,
|
|
34670
|
+
captureSessionHookExec: options2.captureSessionHookExec,
|
|
34607
34671
|
hookExec: startupDefinitions.host === "claude" ? requireHookExec(options2.hookExec) : void 0,
|
|
34608
34672
|
withMarketplaceLock: options2.withMarketplaceLock
|
|
34609
34673
|
});
|
|
34610
34674
|
const codexPluginKeys = plugin.codexRegistrations.map((registration) => `${registration.pluginName}@${registration.marketplaceName}`);
|
|
34611
|
-
const codexProfile = profile.id === "codex" ? writeCodexFleetProfile(profile.env, doctrine, codexPluginKeys, (cleanup2) => tempCleanups.push(cleanup2)) : void 0;
|
|
34675
|
+
const codexProfile = profile.id === "codex" ? writeCodexFleetProfile(profile.env, doctrine, codexPluginKeys, options2.captureSessionHookExec, (cleanup2) => tempCleanups.push(cleanup2)) : void 0;
|
|
34612
34676
|
const launchWarnings = [];
|
|
34613
34677
|
for (const registration of plugin.codexRegistrations) {
|
|
34614
34678
|
const registrationWarning = await ensureCodexPluginRegistered(registration, {
|
|
@@ -34635,13 +34699,14 @@ async function injectAgentCliProfile(profile, options2) {
|
|
|
34635
34699
|
pluginRoot: plugin.pluginRoot,
|
|
34636
34700
|
pluginRoots: plugin.pluginRoots,
|
|
34637
34701
|
codexProfileName: codexProfile?.profileName,
|
|
34638
|
-
replaceSystemPrompt: options2.replaceSystemPrompt ??
|
|
34702
|
+
replaceSystemPrompt: options2.replaceSystemPrompt ?? false,
|
|
34703
|
+
resumeSessionId: options2.resumeSessionId,
|
|
34639
34704
|
systemPromptFile
|
|
34640
34705
|
};
|
|
34641
34706
|
const injectedArgs = buildAgentCliArgs(capability.builderId, context);
|
|
34642
34707
|
return {
|
|
34643
34708
|
...profile,
|
|
34644
|
-
args:
|
|
34709
|
+
args: mergeAgentCliArgs(profile, capability.builderId, context, injectedArgs),
|
|
34645
34710
|
cleanup,
|
|
34646
34711
|
launchWarnings: [...profile.launchWarnings ?? [], ...launchWarnings]
|
|
34647
34712
|
};
|
|
@@ -34683,7 +34748,7 @@ function writeSystemPromptFile(cliId, systemPrompt, onCleanup) {
|
|
|
34683
34748
|
chmodBestEffort2(filePath, SYSTEM_PROMPT_FILE_MODE);
|
|
34684
34749
|
return filePath;
|
|
34685
34750
|
}
|
|
34686
|
-
function writeCodexFleetProfile(env, doctrine, pluginKeys, onCleanup) {
|
|
34751
|
+
function writeCodexFleetProfile(env, doctrine, pluginKeys, captureSessionHookExec, onCleanup) {
|
|
34687
34752
|
const codexHome = env.CODEX_HOME ?? path92.join(env.HOME ?? os23.homedir(), ".codex");
|
|
34688
34753
|
mkdirSync32(codexHome, { recursive: true });
|
|
34689
34754
|
pruneStaleCodexFleetProfiles(codexHome);
|
|
@@ -34702,11 +34767,21 @@ function writeCodexFleetProfile(env, doctrine, pluginKeys, onCleanup) {
|
|
|
34702
34767
|
`[plugins."${escapeTomlBasicString2(pluginKey)}"]`,
|
|
34703
34768
|
"enabled = true",
|
|
34704
34769
|
""
|
|
34705
|
-
])
|
|
34770
|
+
]),
|
|
34771
|
+
...codexCaptureHookConfig(captureSessionHookExec)
|
|
34706
34772
|
].join("\n"));
|
|
34707
34773
|
chmodBestEffort2(profilePath, SYSTEM_PROMPT_FILE_MODE);
|
|
34708
34774
|
return { profileName, profilePath };
|
|
34709
34775
|
}
|
|
34776
|
+
function codexCaptureHookConfig(captureSessionHookExec) {
|
|
34777
|
+
if (captureSessionHookExec === void 0) return [];
|
|
34778
|
+
const command3 = buildPosixShellCommand([captureSessionHookExec.command, ...captureSessionHookExec.args]);
|
|
34779
|
+
return [
|
|
34780
|
+
"[hooks]",
|
|
34781
|
+
`UserPromptSubmit = [{ hooks = [{ type = "command", command = "${escapeTomlBasicString2(command3)}" }] }]`,
|
|
34782
|
+
""
|
|
34783
|
+
];
|
|
34784
|
+
}
|
|
34710
34785
|
function writeFileNoFollow2(filePath, content) {
|
|
34711
34786
|
const flags = constants32.O_WRONLY | constants32.O_CREAT | constants32.O_TRUNC | constants32.O_NOFOLLOW;
|
|
34712
34787
|
const fd = openSync32(filePath, flags, SYSTEM_PROMPT_FILE_MODE);
|
|
@@ -34779,6 +34854,24 @@ function buildAgentCliArgs(builderId, context) {
|
|
|
34779
34854
|
return buildCodexNativeArgs(context);
|
|
34780
34855
|
}
|
|
34781
34856
|
}
|
|
34857
|
+
function mergeAgentCliArgs(profile, builderId, context, injectedArgs) {
|
|
34858
|
+
if (builderId !== "codex-native" || context.resumeSessionId === void 0) {
|
|
34859
|
+
return [...profile.args, ...injectedArgs];
|
|
34860
|
+
}
|
|
34861
|
+
const resumeSessionId = context.resumeSessionId;
|
|
34862
|
+
const prefixLength = profile.binPrefixArgs?.length ?? 0;
|
|
34863
|
+
const codexResumeArgs = ["resume", resumeSessionId];
|
|
34864
|
+
const injectedTail = injectedArgs.slice(codexResumeArgs.length);
|
|
34865
|
+
return [
|
|
34866
|
+
...profile.args.slice(0, prefixLength),
|
|
34867
|
+
...codexResumeArgs,
|
|
34868
|
+
...profile.args.slice(prefixLength).filter((arg, index, args) => !isCodexResumeArgAt(args, index, resumeSessionId)),
|
|
34869
|
+
...injectedTail
|
|
34870
|
+
];
|
|
34871
|
+
}
|
|
34872
|
+
function isCodexResumeArgAt(args, index, resumeSessionId) {
|
|
34873
|
+
return args[index] === "resume" && args[index + 1] === resumeSessionId || args[index] === resumeSessionId && args[index - 1] === "resume";
|
|
34874
|
+
}
|
|
34782
34875
|
function createOnceCleanup(cleanup) {
|
|
34783
34876
|
let cleaned = false;
|
|
34784
34877
|
return () => {
|
|
@@ -39592,14 +39685,14 @@ import * as fs52 from "fs";
|
|
|
39592
39685
|
import fs5__default, { readFileSync as readFileSync8, existsSync as existsSync8, mkdtempSync as mkdtempSync3, writeFileSync as writeFileSync6, mkdirSync as mkdirSync8, rmSync as rmSync5, chmodSync as chmodSync5, renameSync as renameSync5, readdirSync as readdirSync6, constants as constants8, openSync as openSync8, closeSync as closeSync8, lstatSync as lstatSync8, unlinkSync as unlinkSync5, realpathSync as realpathSync6, statSync as statSync6, symlinkSync as symlinkSync2, fstatSync as fstatSync7 } from "fs";
|
|
39593
39686
|
import * as path93 from "path";
|
|
39594
39687
|
import path93__default, { join as join10, resolve, relative, dirname as dirname6 } from "path";
|
|
39595
|
-
import
|
|
39688
|
+
import process5 from "process";
|
|
39596
39689
|
import { fileURLToPath, pathToFileURL as pathToFileURL2 } from "url";
|
|
39597
39690
|
import * as os222 from "os";
|
|
39598
39691
|
import os22__default from "os";
|
|
39599
39692
|
import { EventEmitter as EventEmitter6 } from "events";
|
|
39600
39693
|
import { stat, mkdir as mkdir2, readFile as readFile2, readdir, appendFile, writeFile as writeFile2, rename, access as access2, rm } from "fs/promises";
|
|
39601
39694
|
import { Writable as Writable2, Readable as Readable2 } from "stream";
|
|
39602
|
-
import
|
|
39695
|
+
import crypto5, { createHash as createHash2, randomUUID as randomUUID2, timingSafeEqual } from "crypto";
|
|
39603
39696
|
import http2 from "http";
|
|
39604
39697
|
import { createRequire } from "module";
|
|
39605
39698
|
import net2 from "net";
|
|
@@ -40544,10 +40637,10 @@ function mergeDefs2(...defs) {
|
|
|
40544
40637
|
function cloneDef2(schema) {
|
|
40545
40638
|
return mergeDefs2(schema._zod.def);
|
|
40546
40639
|
}
|
|
40547
|
-
function getElementAtPath2(obj,
|
|
40548
|
-
if (!
|
|
40640
|
+
function getElementAtPath2(obj, path34) {
|
|
40641
|
+
if (!path34)
|
|
40549
40642
|
return obj;
|
|
40550
|
-
return
|
|
40643
|
+
return path34.reduce((acc, key) => acc?.[key], obj);
|
|
40551
40644
|
}
|
|
40552
40645
|
function promiseAllObject2(promisesObj) {
|
|
40553
40646
|
const keys = Object.keys(promisesObj);
|
|
@@ -40956,11 +41049,11 @@ function explicitlyAborted2(x, startIndex = 0) {
|
|
|
40956
41049
|
}
|
|
40957
41050
|
return false;
|
|
40958
41051
|
}
|
|
40959
|
-
function prefixIssues2(
|
|
41052
|
+
function prefixIssues2(path34, issues) {
|
|
40960
41053
|
return issues.map((iss) => {
|
|
40961
41054
|
var _a32;
|
|
40962
41055
|
(_a32 = iss).path ?? (_a32.path = []);
|
|
40963
|
-
iss.path.unshift(
|
|
41056
|
+
iss.path.unshift(path34);
|
|
40964
41057
|
return iss;
|
|
40965
41058
|
});
|
|
40966
41059
|
}
|
|
@@ -41105,16 +41198,16 @@ function flattenError2(error512, mapper = (issue32) => issue32.message) {
|
|
|
41105
41198
|
}
|
|
41106
41199
|
function formatError3(error512, mapper = (issue32) => issue32.message) {
|
|
41107
41200
|
const fieldErrors = { _errors: [] };
|
|
41108
|
-
const processError = (error522,
|
|
41201
|
+
const processError = (error522, path34 = []) => {
|
|
41109
41202
|
for (const issue32 of error522.issues) {
|
|
41110
41203
|
if (issue32.code === "invalid_union" && issue32.errors.length) {
|
|
41111
|
-
issue32.errors.map((issues) => processError({ issues }, [...
|
|
41204
|
+
issue32.errors.map((issues) => processError({ issues }, [...path34, ...issue32.path]));
|
|
41112
41205
|
} else if (issue32.code === "invalid_key") {
|
|
41113
|
-
processError({ issues: issue32.issues }, [...
|
|
41206
|
+
processError({ issues: issue32.issues }, [...path34, ...issue32.path]);
|
|
41114
41207
|
} else if (issue32.code === "invalid_element") {
|
|
41115
|
-
processError({ issues: issue32.issues }, [...
|
|
41208
|
+
processError({ issues: issue32.issues }, [...path34, ...issue32.path]);
|
|
41116
41209
|
} else {
|
|
41117
|
-
const fullpath = [...
|
|
41210
|
+
const fullpath = [...path34, ...issue32.path];
|
|
41118
41211
|
if (fullpath.length === 0) {
|
|
41119
41212
|
fieldErrors._errors.push(mapper(issue32));
|
|
41120
41213
|
} else {
|
|
@@ -41141,17 +41234,17 @@ function formatError3(error512, mapper = (issue32) => issue32.message) {
|
|
|
41141
41234
|
}
|
|
41142
41235
|
function treeifyError2(error512, mapper = (issue32) => issue32.message) {
|
|
41143
41236
|
const result = { errors: [] };
|
|
41144
|
-
const processError = (error522,
|
|
41237
|
+
const processError = (error522, path34 = []) => {
|
|
41145
41238
|
var _a32, _b;
|
|
41146
41239
|
for (const issue32 of error522.issues) {
|
|
41147
41240
|
if (issue32.code === "invalid_union" && issue32.errors.length) {
|
|
41148
|
-
issue32.errors.map((issues) => processError({ issues }, [...
|
|
41241
|
+
issue32.errors.map((issues) => processError({ issues }, [...path34, ...issue32.path]));
|
|
41149
41242
|
} else if (issue32.code === "invalid_key") {
|
|
41150
|
-
processError({ issues: issue32.issues }, [...
|
|
41243
|
+
processError({ issues: issue32.issues }, [...path34, ...issue32.path]);
|
|
41151
41244
|
} else if (issue32.code === "invalid_element") {
|
|
41152
|
-
processError({ issues: issue32.issues }, [...
|
|
41245
|
+
processError({ issues: issue32.issues }, [...path34, ...issue32.path]);
|
|
41153
41246
|
} else {
|
|
41154
|
-
const fullpath = [...
|
|
41247
|
+
const fullpath = [...path34, ...issue32.path];
|
|
41155
41248
|
if (fullpath.length === 0) {
|
|
41156
41249
|
result.errors.push(mapper(issue32));
|
|
41157
41250
|
continue;
|
|
@@ -41183,8 +41276,8 @@ function treeifyError2(error512, mapper = (issue32) => issue32.message) {
|
|
|
41183
41276
|
}
|
|
41184
41277
|
function toDotPath2(_path) {
|
|
41185
41278
|
const segs = [];
|
|
41186
|
-
const
|
|
41187
|
-
for (const seg of
|
|
41279
|
+
const path34 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
41280
|
+
for (const seg of path34) {
|
|
41188
41281
|
if (typeof seg === "number")
|
|
41189
41282
|
segs.push(`[${seg}]`);
|
|
41190
41283
|
else if (typeof seg === "symbol")
|
|
@@ -53705,13 +53798,13 @@ function resolveRef2(ref, ctx) {
|
|
|
53705
53798
|
if (!ref.startsWith("#")) {
|
|
53706
53799
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
53707
53800
|
}
|
|
53708
|
-
const
|
|
53709
|
-
if (
|
|
53801
|
+
const path34 = ref.slice(1).split("/").filter(Boolean);
|
|
53802
|
+
if (path34.length === 0) {
|
|
53710
53803
|
return ctx.rootSchema;
|
|
53711
53804
|
}
|
|
53712
53805
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
53713
|
-
if (
|
|
53714
|
-
const key =
|
|
53806
|
+
if (path34[0] === defsKey) {
|
|
53807
|
+
const key = path34[1];
|
|
53715
53808
|
if (!key || !ctx.defs[key]) {
|
|
53716
53809
|
throw new Error(`Reference not found: ${ref}`);
|
|
53717
53810
|
}
|
|
@@ -57323,7 +57416,7 @@ function inferBinName2(packageName) {
|
|
|
57323
57416
|
}
|
|
57324
57417
|
var models_default2 = {
|
|
57325
57418
|
version: 1,
|
|
57326
|
-
updatedAt: "2026-06-
|
|
57419
|
+
updatedAt: "2026-06-16T00:00:00Z",
|
|
57327
57420
|
providers: {
|
|
57328
57421
|
claude: {
|
|
57329
57422
|
name: "Claude Code with Anthropic",
|
|
@@ -57333,7 +57426,9 @@ var models_default2 = {
|
|
|
57333
57426
|
{ modelId: "sonnet", name: "Claude Sonnet", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "medium" } },
|
|
57334
57427
|
{ modelId: "opus", name: "Claude Opus", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "xhigh" } },
|
|
57335
57428
|
{ modelId: "opus[1m]", name: "Claude Opus [1M]", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "xhigh" } },
|
|
57336
|
-
{ modelId: "claude-opus-4-6[1m]", name: "Claude Opus 4.6 [1M]", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "high" } }
|
|
57429
|
+
{ modelId: "claude-opus-4-6[1m]", name: "Claude Opus 4.6 [1M]", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "high" } },
|
|
57430
|
+
{ modelId: "claude-opus-4-7[1m]", name: "Claude Opus 4.7 [1M]", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "high" } },
|
|
57431
|
+
{ modelId: "claude-opus-4-8[1m]", name: "Claude Opus 4.8 [1M]", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "high" } }
|
|
57337
57432
|
]
|
|
57338
57433
|
},
|
|
57339
57434
|
"claude-zai": {
|
|
@@ -60466,7 +60561,7 @@ function specToMcpTool2(spec) {
|
|
|
60466
60561
|
}
|
|
60467
60562
|
function installExecutorToolCallRouter2(runtime, sessionToken, ctx) {
|
|
60468
60563
|
runtime.server.setOnToolCallArrived(sessionToken, (toolName, args) => {
|
|
60469
|
-
const toolCallId =
|
|
60564
|
+
const toolCallId = crypto5.randomUUID();
|
|
60470
60565
|
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) => {
|
|
60471
60566
|
runtime.server.resolveNextToolCall(sessionToken, toolCallId, {
|
|
60472
60567
|
content: [{ type: "text", text: err instanceof Error ? err.message : String(err) }],
|
|
@@ -60857,7 +60952,7 @@ function createInProcessMcpServer2(deps = {}) {
|
|
|
60857
60952
|
if (activeStopPromise) await activeStopPromise;
|
|
60858
60953
|
if (activeServer && activeServerUrl) return activeServerUrl;
|
|
60859
60954
|
if (activeStartPromise) return activeStartPromise;
|
|
60860
|
-
activeOpaquePath = `/${
|
|
60955
|
+
activeOpaquePath = `/${crypto5.randomUUID()}`;
|
|
60861
60956
|
activeStartPromise = new Promise((resolve2, reject) => {
|
|
60862
60957
|
const srv = http2.createServer(handleRequest);
|
|
60863
60958
|
srv.timeout = MCP_SERVER_TIMEOUT_MS2;
|
|
@@ -61114,7 +61209,7 @@ function createExecutorMcpSession2(deps, toolTimeoutSeconds, request) {
|
|
|
61114
61209
|
throw new Error("Executor session cwd is required");
|
|
61115
61210
|
}
|
|
61116
61211
|
assertNonEmptyExecutorTools2(request.serverName, request.specs);
|
|
61117
|
-
const token =
|
|
61212
|
+
const token = crypto5.randomUUID();
|
|
61118
61213
|
registerExecutorSessionTools2(runtime.runtime, token, [...request.specs]);
|
|
61119
61214
|
installExecutorToolCallRouter2(runtime.runtime, token, {
|
|
61120
61215
|
cwd,
|
|
@@ -61160,7 +61255,7 @@ function issueSessionToken2(deps, sessionTokensByLabel, request) {
|
|
|
61160
61255
|
for (const { name, runtime } of deps.runtimes) {
|
|
61161
61256
|
const tools = runtime.registry.getAllAgentTools();
|
|
61162
61257
|
assertNonEmptyExecutorTools2(name, tools);
|
|
61163
|
-
const token =
|
|
61258
|
+
const token = crypto5.randomUUID();
|
|
61164
61259
|
registerExecutorSessionTools2(runtime, token, tools);
|
|
61165
61260
|
installExecutorToolCallRouter2(runtime, token, { cwd, sessionLabel: label, signal: request.signal });
|
|
61166
61261
|
tokens.push({ name, token });
|
|
@@ -62526,7 +62621,8 @@ function sleepSync2(ms) {
|
|
|
62526
62621
|
var DEFAULT_TEMP_FILE_MIN_AGE_MS2 = 6e4;
|
|
62527
62622
|
function createDurableJsonStore2(deps) {
|
|
62528
62623
|
const now = deps.now ?? (() => Date.now());
|
|
62529
|
-
const
|
|
62624
|
+
const sensitivity = deps.sensitivity;
|
|
62625
|
+
const mode = sensitivity === "sensitive" ? SECURE_FILE_MODE2 : 420;
|
|
62530
62626
|
const minAgeMs = deps.tempCleanupMinAgeMs ?? DEFAULT_TEMP_FILE_MIN_AGE_MS2;
|
|
62531
62627
|
const dir = path93.dirname(deps.filePath);
|
|
62532
62628
|
return {
|
|
@@ -62554,10 +62650,10 @@ function createDurableJsonStore2(deps) {
|
|
|
62554
62650
|
};
|
|
62555
62651
|
function withLock(operation) {
|
|
62556
62652
|
if (!deps.lockDir) {
|
|
62557
|
-
ensureSafeDirectoryIfSensitive2(dir);
|
|
62653
|
+
ensureSafeDirectoryIfSensitive2(dir, sensitivity);
|
|
62558
62654
|
return operation();
|
|
62559
62655
|
}
|
|
62560
|
-
ensureSafeDirectoryIfSensitive2(dir);
|
|
62656
|
+
ensureSafeDirectoryIfSensitive2(dir, sensitivity);
|
|
62561
62657
|
return withDirectoryLock2(
|
|
62562
62658
|
{
|
|
62563
62659
|
lockDir: deps.lockDir,
|
|
@@ -62599,8 +62695,10 @@ function readJsonFile2(filePath, sanitize) {
|
|
|
62599
62695
|
}
|
|
62600
62696
|
}
|
|
62601
62697
|
function ensureSafeDirectoryIfSensitive2(dir, sensitivity) {
|
|
62602
|
-
{
|
|
62698
|
+
if (sensitivity === "sensitive") {
|
|
62603
62699
|
ensureSafeDirectory2(dir);
|
|
62700
|
+
} else {
|
|
62701
|
+
fs52.mkdirSync(dir, { recursive: true });
|
|
62604
62702
|
}
|
|
62605
62703
|
}
|
|
62606
62704
|
var memory_exports2 = {};
|
|
@@ -70278,7 +70376,7 @@ var LOCK_FILE_MODE = 384;
|
|
|
70278
70376
|
function createConsoleLock(deps = {}) {
|
|
70279
70377
|
const fsImpl = deps.fs ?? fs5__default;
|
|
70280
70378
|
const now = deps.now ?? Date.now;
|
|
70281
|
-
const randomToken = deps.randomToken ?? (() =>
|
|
70379
|
+
const randomToken = deps.randomToken ?? (() => crypto5.randomBytes(32).toString("base64url"));
|
|
70282
70380
|
const hostname52 = deps.hostname ?? (() => "127.0.0.1");
|
|
70283
70381
|
function ensureLockDir(dir) {
|
|
70284
70382
|
fsImpl.mkdirSync(dir, { recursive: true, mode: LOCK_DIR_MODE });
|
|
@@ -70373,6 +70471,387 @@ function createConsoleLock(deps = {}) {
|
|
|
70373
70471
|
}
|
|
70374
70472
|
return { ensureLockDir, readLock, writeLock, removeLock, assertLockModes, assertTrustedLock };
|
|
70375
70473
|
}
|
|
70474
|
+
var FLEET_DATA_DIR_NAME2 = ".fleet";
|
|
70475
|
+
function getFleetDataDir2() {
|
|
70476
|
+
return path93.join(os222.homedir(), FLEET_DATA_DIR_NAME2);
|
|
70477
|
+
}
|
|
70478
|
+
function readAuthStoreFile2(filePath) {
|
|
70479
|
+
let fd;
|
|
70480
|
+
try {
|
|
70481
|
+
fd = fs52.openSync(filePath, fs52.constants.O_RDONLY | NOFOLLOW_FLAG2);
|
|
70482
|
+
if (!fs52.fstatSync(fd).isFile()) {
|
|
70483
|
+
return {};
|
|
70484
|
+
}
|
|
70485
|
+
return JSON.parse(fs52.readFileSync(fd, "utf-8"));
|
|
70486
|
+
} catch {
|
|
70487
|
+
return {};
|
|
70488
|
+
} finally {
|
|
70489
|
+
if (fd !== void 0) {
|
|
70490
|
+
try {
|
|
70491
|
+
fs52.closeSync(fd);
|
|
70492
|
+
} catch {
|
|
70493
|
+
}
|
|
70494
|
+
}
|
|
70495
|
+
}
|
|
70496
|
+
}
|
|
70497
|
+
var DEFAULT_AUTH_PATH2 = path93.join(getFleetDataDir2(), "auth.json");
|
|
70498
|
+
var AUTH_LOCK_OWNER_FILE_NAME2 = "owner.json";
|
|
70499
|
+
var AUTH_LOCK_TIMEOUT_MS2 = 5e3;
|
|
70500
|
+
function createAuthService2(deps = {}) {
|
|
70501
|
+
const authPath = deps.authPath ?? DEFAULT_AUTH_PATH2;
|
|
70502
|
+
const lockDir = `${authPath}.lock`;
|
|
70503
|
+
return {
|
|
70504
|
+
// [HIGH #1] TOCTOU 수정: existsSync/read/check/delete/write 전체를 락 블록 안으로 이동
|
|
70505
|
+
async deleteApiKey(providerId) {
|
|
70506
|
+
let deleted = false;
|
|
70507
|
+
withAuthLock2(authPath, lockDir, () => {
|
|
70508
|
+
if (!fs52.existsSync(authPath)) return;
|
|
70509
|
+
const data = readAuthStoreFile2(authPath);
|
|
70510
|
+
if (!Object.prototype.hasOwnProperty.call(data, providerId)) return;
|
|
70511
|
+
delete data[providerId];
|
|
70512
|
+
writeAuthData2(authPath, data);
|
|
70513
|
+
deleted = true;
|
|
70514
|
+
});
|
|
70515
|
+
return deleted;
|
|
70516
|
+
},
|
|
70517
|
+
// [HIGH #2] 읽기 경로: fd 기반 O_RDONLY|O_NOFOLLOW+fstatSync isFile
|
|
70518
|
+
async getApiKey(providerId) {
|
|
70519
|
+
let fd;
|
|
70520
|
+
try {
|
|
70521
|
+
if (!fs52.existsSync(authPath)) {
|
|
70522
|
+
return void 0;
|
|
70523
|
+
}
|
|
70524
|
+
fd = fs52.openSync(authPath, fs52.constants.O_RDONLY | NOFOLLOW_FLAG2);
|
|
70525
|
+
if (!fs52.fstatSync(fd).isFile()) {
|
|
70526
|
+
return void 0;
|
|
70527
|
+
}
|
|
70528
|
+
const data = JSON.parse(fs52.readFileSync(fd, "utf-8"));
|
|
70529
|
+
return typeof data[providerId]?.key === "string" ? data[providerId].key : void 0;
|
|
70530
|
+
} catch {
|
|
70531
|
+
return void 0;
|
|
70532
|
+
} finally {
|
|
70533
|
+
if (fd !== void 0) {
|
|
70534
|
+
try {
|
|
70535
|
+
fs52.closeSync(fd);
|
|
70536
|
+
} catch {
|
|
70537
|
+
}
|
|
70538
|
+
}
|
|
70539
|
+
}
|
|
70540
|
+
},
|
|
70541
|
+
// [HIGH #2] 읽기 경로: fd 기반 O_RDONLY|O_NOFOLLOW 통일
|
|
70542
|
+
async listProviderIds() {
|
|
70543
|
+
if (!fs52.existsSync(authPath)) {
|
|
70544
|
+
return [];
|
|
70545
|
+
}
|
|
70546
|
+
try {
|
|
70547
|
+
return Object.keys(readAuthStoreFile2(authPath)).sort();
|
|
70548
|
+
} catch {
|
|
70549
|
+
return [];
|
|
70550
|
+
}
|
|
70551
|
+
},
|
|
70552
|
+
async setApiKey(providerId, key) {
|
|
70553
|
+
const dir = path93.dirname(authPath);
|
|
70554
|
+
ensureSafeDirectory2(dir);
|
|
70555
|
+
withAuthLock2(authPath, lockDir, () => {
|
|
70556
|
+
const data = fs52.existsSync(authPath) ? readAuthStoreFile2(authPath) : {};
|
|
70557
|
+
data[providerId] = {
|
|
70558
|
+
...data[providerId] ?? {},
|
|
70559
|
+
key
|
|
70560
|
+
};
|
|
70561
|
+
writeAuthData2(authPath, data);
|
|
70562
|
+
});
|
|
70563
|
+
}
|
|
70564
|
+
};
|
|
70565
|
+
}
|
|
70566
|
+
function withAuthLock2(authPath, lockDir, operation) {
|
|
70567
|
+
return withDirectoryLock2(
|
|
70568
|
+
{
|
|
70569
|
+
lockDir,
|
|
70570
|
+
ownerFileName: AUTH_LOCK_OWNER_FILE_NAME2,
|
|
70571
|
+
timeoutMs: AUTH_LOCK_TIMEOUT_MS2
|
|
70572
|
+
},
|
|
70573
|
+
operation
|
|
70574
|
+
);
|
|
70575
|
+
}
|
|
70576
|
+
function writeAuthData2(authPath, data) {
|
|
70577
|
+
writeAtomicSync2(authPath, `${JSON.stringify(data, null, 2)}
|
|
70578
|
+
`, {
|
|
70579
|
+
mode: SECURE_FILE_MODE2,
|
|
70580
|
+
fsync: true
|
|
70581
|
+
});
|
|
70582
|
+
}
|
|
70583
|
+
function formatMissingAuthKeyMessage2(input) {
|
|
70584
|
+
const cliHint = input.cli ? `cli '${input.cli}'` : "selected CLI";
|
|
70585
|
+
return `Auth token not found for ${cliHint} (providerId: '${input.providerId}'). Run \`fleet auth login\` to register one.`;
|
|
70586
|
+
}
|
|
70587
|
+
function formatAuthValidationFailureMessage2(input) {
|
|
70588
|
+
const detail = input.detail ? ` Detail: ${input.detail}` : "";
|
|
70589
|
+
if (input.status === "unauthorized") {
|
|
70590
|
+
return `Auth token was rejected (providerId: '${input.providerId}'). Check the token and try again.${detail}`;
|
|
70591
|
+
}
|
|
70592
|
+
if (input.status === "forbidden") {
|
|
70593
|
+
return `Auth token is not allowed for this provider (providerId: '${input.providerId}'). Check the token permissions.${detail}`;
|
|
70594
|
+
}
|
|
70595
|
+
if (input.status === "timeout") {
|
|
70596
|
+
return `Auth token validation timed out (providerId: '${input.providerId}'). Check the connection and try again.${detail}`;
|
|
70597
|
+
}
|
|
70598
|
+
if (input.status === "network") {
|
|
70599
|
+
return `Auth token validation failed due to a network error (providerId: '${input.providerId}'). Check the connection and try again.${detail}`;
|
|
70600
|
+
}
|
|
70601
|
+
if (input.status === "server") {
|
|
70602
|
+
return `Auth token validation failed because the provider returned an error (providerId: '${input.providerId}'). Try again later.${detail}`;
|
|
70603
|
+
}
|
|
70604
|
+
return `Auth token validation failed (providerId: '${input.providerId}'). Check the token and try again.${detail}`;
|
|
70605
|
+
}
|
|
70606
|
+
var LEGACY_AUTH_PATH2 = path93.join(getFleetDataDir2(), "agent", "auth.json");
|
|
70607
|
+
var CURRENT_AUTH_PATH2 = path93.join(getFleetDataDir2(), "auth.json");
|
|
70608
|
+
function mergeAuthStoresNoOverwrite2(legacy, current) {
|
|
70609
|
+
const data = { ...current };
|
|
70610
|
+
const migratedProviderIds = [];
|
|
70611
|
+
const skippedProviderIds = [];
|
|
70612
|
+
for (const [providerId, entry] of Object.entries(legacy)) {
|
|
70613
|
+
if (Object.prototype.hasOwnProperty.call(data, providerId)) {
|
|
70614
|
+
skippedProviderIds.push(providerId);
|
|
70615
|
+
continue;
|
|
70616
|
+
}
|
|
70617
|
+
data[providerId] = entry;
|
|
70618
|
+
migratedProviderIds.push(providerId);
|
|
70619
|
+
}
|
|
70620
|
+
return {
|
|
70621
|
+
data,
|
|
70622
|
+
migratedProviderIds,
|
|
70623
|
+
skippedProviderIds
|
|
70624
|
+
};
|
|
70625
|
+
}
|
|
70626
|
+
async function migrateLegacyAuthStore2(options2 = {}) {
|
|
70627
|
+
const legacyPath = options2.legacyPath ?? LEGACY_AUTH_PATH2;
|
|
70628
|
+
const currentPath = options2.currentPath ?? CURRENT_AUTH_PATH2;
|
|
70629
|
+
if (!fs52.existsSync(legacyPath)) {
|
|
70630
|
+
return createMigrationResult2({
|
|
70631
|
+
legacyPath,
|
|
70632
|
+
currentPath,
|
|
70633
|
+
status: "legacy-missing",
|
|
70634
|
+
migratedProviderIds: [],
|
|
70635
|
+
skippedProviderIds: [],
|
|
70636
|
+
shouldPrintNotice: false
|
|
70637
|
+
});
|
|
70638
|
+
}
|
|
70639
|
+
const legacy = readAuthStoreFile2(legacyPath);
|
|
70640
|
+
const current = fs52.existsSync(currentPath) ? readAuthStoreFile2(currentPath) : {};
|
|
70641
|
+
const merged = mergeAuthStoresNoOverwrite2(legacy, current);
|
|
70642
|
+
if (merged.migratedProviderIds.length > 0) {
|
|
70643
|
+
const dir = path93.dirname(currentPath);
|
|
70644
|
+
ensureSafeDirectory2(dir);
|
|
70645
|
+
writeAtomicSync2(currentPath, `${JSON.stringify(merged.data, null, 2)}
|
|
70646
|
+
`, {
|
|
70647
|
+
mode: SECURE_FILE_MODE2,
|
|
70648
|
+
fsync: true
|
|
70649
|
+
});
|
|
70650
|
+
}
|
|
70651
|
+
return createMigrationResult2({
|
|
70652
|
+
legacyPath,
|
|
70653
|
+
currentPath,
|
|
70654
|
+
status: merged.migratedProviderIds.length > 0 ? "migrated" : "unchanged",
|
|
70655
|
+
migratedProviderIds: merged.migratedProviderIds,
|
|
70656
|
+
skippedProviderIds: merged.skippedProviderIds,
|
|
70657
|
+
shouldPrintNotice: options2.notify !== false && merged.migratedProviderIds.length > 0
|
|
70658
|
+
});
|
|
70659
|
+
}
|
|
70660
|
+
function createMigrationResult2(input) {
|
|
70661
|
+
return {
|
|
70662
|
+
legacyPath: input.legacyPath,
|
|
70663
|
+
currentPath: input.currentPath,
|
|
70664
|
+
migratedCount: input.migratedProviderIds.length,
|
|
70665
|
+
skippedCount: input.skippedProviderIds.length,
|
|
70666
|
+
migratedProviderIds: input.migratedProviderIds,
|
|
70667
|
+
skippedProviderIds: input.skippedProviderIds,
|
|
70668
|
+
shouldPrintNotice: input.shouldPrintNotice,
|
|
70669
|
+
status: input.status
|
|
70670
|
+
};
|
|
70671
|
+
}
|
|
70672
|
+
var DEFAULT_AUTH_VALIDATION_TIMEOUT_MS2 = 5e3;
|
|
70673
|
+
async function validateAnthropicCompatibleApiKey2(request) {
|
|
70674
|
+
const controller = new AbortController();
|
|
70675
|
+
const timeout = setTimeout(() => {
|
|
70676
|
+
controller.abort();
|
|
70677
|
+
}, request.timeoutMs ?? DEFAULT_AUTH_VALIDATION_TIMEOUT_MS2);
|
|
70678
|
+
try {
|
|
70679
|
+
const response = await fetch(buildMessagesUrl2(request.baseUrl), {
|
|
70680
|
+
method: "POST",
|
|
70681
|
+
headers: {
|
|
70682
|
+
"anthropic-version": "2023-06-01",
|
|
70683
|
+
"content-type": "application/json",
|
|
70684
|
+
"x-api-key": request.apiKey
|
|
70685
|
+
},
|
|
70686
|
+
body: JSON.stringify({
|
|
70687
|
+
model: "claude-3-5-haiku-20241022",
|
|
70688
|
+
max_tokens: 1,
|
|
70689
|
+
messages: [
|
|
70690
|
+
{
|
|
70691
|
+
role: "user",
|
|
70692
|
+
content: "ping"
|
|
70693
|
+
}
|
|
70694
|
+
]
|
|
70695
|
+
}),
|
|
70696
|
+
signal: controller.signal
|
|
70697
|
+
});
|
|
70698
|
+
if (response.ok) {
|
|
70699
|
+
return { providerId: request.providerId, status: "success" };
|
|
70700
|
+
}
|
|
70701
|
+
if (response.status === 401) {
|
|
70702
|
+
return { providerId: request.providerId, status: "unauthorized" };
|
|
70703
|
+
}
|
|
70704
|
+
if (response.status === 403) {
|
|
70705
|
+
return { providerId: request.providerId, status: "forbidden" };
|
|
70706
|
+
}
|
|
70707
|
+
if (response.status >= 500) {
|
|
70708
|
+
return {
|
|
70709
|
+
providerId: request.providerId,
|
|
70710
|
+
status: "server",
|
|
70711
|
+
detail: `HTTP ${response.status}`
|
|
70712
|
+
};
|
|
70713
|
+
}
|
|
70714
|
+
return {
|
|
70715
|
+
providerId: request.providerId,
|
|
70716
|
+
status: "unknown",
|
|
70717
|
+
detail: `HTTP ${response.status}`
|
|
70718
|
+
};
|
|
70719
|
+
} catch (error512) {
|
|
70720
|
+
if (isAbortError2(error512)) {
|
|
70721
|
+
return { providerId: request.providerId, status: "timeout" };
|
|
70722
|
+
}
|
|
70723
|
+
return {
|
|
70724
|
+
providerId: request.providerId,
|
|
70725
|
+
status: "network",
|
|
70726
|
+
detail: error512 instanceof Error ? error512.message : String(error512)
|
|
70727
|
+
};
|
|
70728
|
+
} finally {
|
|
70729
|
+
clearTimeout(timeout);
|
|
70730
|
+
}
|
|
70731
|
+
}
|
|
70732
|
+
function isAuthValidationSuccess2(result) {
|
|
70733
|
+
return result.status === "success";
|
|
70734
|
+
}
|
|
70735
|
+
function createAuthValidationError2(result) {
|
|
70736
|
+
return new Error(formatAuthValidationFailureMessage2(result));
|
|
70737
|
+
}
|
|
70738
|
+
function buildMessagesUrl2(baseUrl) {
|
|
70739
|
+
return `${baseUrl.replace(/\/+$/, "")}/v1/messages`;
|
|
70740
|
+
}
|
|
70741
|
+
function isAbortError2(error512) {
|
|
70742
|
+
return error512 instanceof DOMException && error512.name === "AbortError";
|
|
70743
|
+
}
|
|
70744
|
+
var CLAUDE_ZAI_PROVIDER_ID2 = "Claude Code with Z.AI GLM";
|
|
70745
|
+
var CLAUDE_KIMI_PROVIDER_ID2 = "Claude Code with Moonshot Kimi";
|
|
70746
|
+
var AUTH_PROVIDER_DEFINITIONS2 = {
|
|
70747
|
+
"claude-zai": {
|
|
70748
|
+
providerId: CLAUDE_ZAI_PROVIDER_ID2,
|
|
70749
|
+
baseUrl: CLI_BACKENDS2["claude-zai"].defaultEnv.ANTHROPIC_BASE_URL,
|
|
70750
|
+
env: CLI_BACKENDS2["claude-zai"].defaultEnv
|
|
70751
|
+
},
|
|
70752
|
+
"claude-kimi": {
|
|
70753
|
+
providerId: CLAUDE_KIMI_PROVIDER_ID2,
|
|
70754
|
+
baseUrl: CLI_BACKENDS2["claude-kimi"].defaultEnv.ANTHROPIC_BASE_URL,
|
|
70755
|
+
env: CLI_BACKENDS2["claude-kimi"].defaultEnv
|
|
70756
|
+
}
|
|
70757
|
+
};
|
|
70758
|
+
async function resolveAuthEnv2(cli, deps) {
|
|
70759
|
+
const provider = AUTH_PROVIDER_DEFINITIONS2[cli];
|
|
70760
|
+
if (!provider) return {};
|
|
70761
|
+
await migrateLegacyAuthStore2();
|
|
70762
|
+
const auth = deps?.authService ?? createAuthService2({ authPath: DEFAULT_AUTH_PATH2 });
|
|
70763
|
+
const token = await auth.getApiKey(provider.providerId);
|
|
70764
|
+
if (!token) {
|
|
70765
|
+
throw new Error(formatMissingAuthKeyMessage2({ cli, providerId: provider.providerId }));
|
|
70766
|
+
}
|
|
70767
|
+
const validation = await validateAnthropicCompatibleApiKey2({
|
|
70768
|
+
providerId: provider.providerId,
|
|
70769
|
+
apiKey: token,
|
|
70770
|
+
baseUrl: provider.baseUrl
|
|
70771
|
+
});
|
|
70772
|
+
if (!isAuthValidationSuccess2(validation)) {
|
|
70773
|
+
const failure = {
|
|
70774
|
+
providerId: validation.providerId,
|
|
70775
|
+
status: validation.status,
|
|
70776
|
+
detail: validation.detail
|
|
70777
|
+
};
|
|
70778
|
+
throw createAuthValidationError2(failure);
|
|
70779
|
+
}
|
|
70780
|
+
return { ...provider.env, ANTHROPIC_AUTH_TOKEN: token };
|
|
70781
|
+
}
|
|
70782
|
+
var GLOBAL_OPTIONS_VERSION2 = 1;
|
|
70783
|
+
var GLOBAL_OPTIONS_FILE_NAME2 = "settings.json";
|
|
70784
|
+
var LOCK_DIR_NAME2 = "settings.json.lock";
|
|
70785
|
+
var LOCK_OWNER_FILE_NAME2 = "owner";
|
|
70786
|
+
var TEMP_FILE_PREFIX2 = `.tmp-${GLOBAL_OPTIONS_FILE_NAME2}-`;
|
|
70787
|
+
function createGlobalOptionsStore2(deps = {}) {
|
|
70788
|
+
const dataDir = deps.dataDir ?? getFleetDataDir2();
|
|
70789
|
+
const optionsPath = path93.join(dataDir, GLOBAL_OPTIONS_FILE_NAME2);
|
|
70790
|
+
const lockDir = path93.join(dataDir, LOCK_DIR_NAME2);
|
|
70791
|
+
const store22 = createDurableJsonStore2({
|
|
70792
|
+
filePath: optionsPath,
|
|
70793
|
+
lockDir,
|
|
70794
|
+
lockOwnerFileName: LOCK_OWNER_FILE_NAME2,
|
|
70795
|
+
sanitize: (value) => sanitizeGlobalOptionsData2(value).data,
|
|
70796
|
+
sensitivity: "sensitive",
|
|
70797
|
+
timeoutMs: deps.timeoutMs,
|
|
70798
|
+
staleLockMs: deps.staleLockMs,
|
|
70799
|
+
tempCleanupPrefix: TEMP_FILE_PREFIX2,
|
|
70800
|
+
now: deps.now
|
|
70801
|
+
});
|
|
70802
|
+
return {
|
|
70803
|
+
path: optionsPath,
|
|
70804
|
+
load: () => store22.load(),
|
|
70805
|
+
save: (data) => store22.save(sanitizeGlobalOptionsData2(data).data),
|
|
70806
|
+
update: (mutate) => store22.update((current) => sanitizeGlobalOptionsData2(mutate(current)).data)
|
|
70807
|
+
};
|
|
70808
|
+
}
|
|
70809
|
+
function createEmptyGlobalOptionsData2() {
|
|
70810
|
+
return {
|
|
70811
|
+
version: GLOBAL_OPTIONS_VERSION2
|
|
70812
|
+
};
|
|
70813
|
+
}
|
|
70814
|
+
function sanitizeGlobalOptionsData2(value) {
|
|
70815
|
+
if (!isRecord32(value)) {
|
|
70816
|
+
return { data: createEmptyGlobalOptionsData2(), changed: true };
|
|
70817
|
+
}
|
|
70818
|
+
if (value.version !== GLOBAL_OPTIONS_VERSION2) {
|
|
70819
|
+
return { data: createEmptyGlobalOptionsData2(), changed: true };
|
|
70820
|
+
}
|
|
70821
|
+
const data = {
|
|
70822
|
+
version: GLOBAL_OPTIONS_VERSION2,
|
|
70823
|
+
...typeof value.replaceSystemPrompt === "boolean" ? { replaceSystemPrompt: value.replaceSystemPrompt } : {},
|
|
70824
|
+
...typeof value.enableMetaphor === "boolean" ? { enableMetaphor: value.enableMetaphor } : {}
|
|
70825
|
+
};
|
|
70826
|
+
const allowedKeys = /* @__PURE__ */ new Set(["version", "replaceSystemPrompt", "enableMetaphor"]);
|
|
70827
|
+
const changed = Object.keys(value).some((key) => !allowedKeys.has(key)) || "replaceSystemPrompt" in value && typeof value.replaceSystemPrompt !== "boolean" || "enableMetaphor" in value && typeof value.enableMetaphor !== "boolean";
|
|
70828
|
+
return { data, changed };
|
|
70829
|
+
}
|
|
70830
|
+
function isRecord32(value) {
|
|
70831
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
70832
|
+
}
|
|
70833
|
+
function createGlobalOptionsService2(deps = {}) {
|
|
70834
|
+
const store22 = deps.store ?? createGlobalOptionsStore2({ dataDir: deps.dataDir });
|
|
70835
|
+
return {
|
|
70836
|
+
load: () => store22.load(),
|
|
70837
|
+
save: (data) => {
|
|
70838
|
+
store22.save(data);
|
|
70839
|
+
return store22.load();
|
|
70840
|
+
},
|
|
70841
|
+
update: (mutate) => updateGlobalOptions2(store22, mutate)
|
|
70842
|
+
};
|
|
70843
|
+
}
|
|
70844
|
+
function updateGlobalOptions2(store22, mutate) {
|
|
70845
|
+
return store22.update(mutate);
|
|
70846
|
+
}
|
|
70847
|
+
function createInfraServices2(deps = {}) {
|
|
70848
|
+
const globalOptionsService = createGlobalOptionsService2();
|
|
70849
|
+
const authService = createAuthService2({ authPath: deps.authPath ?? DEFAULT_AUTH_PATH2 });
|
|
70850
|
+
return {
|
|
70851
|
+
authService,
|
|
70852
|
+
globalOptionsService
|
|
70853
|
+
};
|
|
70854
|
+
}
|
|
70376
70855
|
function readFleetConsoleRelease() {
|
|
70377
70856
|
const requireFromHere2 = createRequire(import.meta.url);
|
|
70378
70857
|
const packageJsonPath = requireFromHere2.resolve("../package.json");
|
|
@@ -70384,17 +70863,34 @@ function readFleetConsoleRelease() {
|
|
|
70384
70863
|
}
|
|
70385
70864
|
return { channel: "stable", version: version22, packageRoot };
|
|
70386
70865
|
}
|
|
70387
|
-
var
|
|
70866
|
+
var LOCK_DIR_NAME22 = "fleet-console";
|
|
70867
|
+
var CONSOLE_RUNTIME_DIR_NAME = "console";
|
|
70388
70868
|
var LOCK_FILE_NAME = "console.lock";
|
|
70869
|
+
var CONSOLE_DATA_DIR_NAME = "console";
|
|
70870
|
+
var CONSOLE_STATE_FILE_NAME = "state.json";
|
|
70871
|
+
var CONSOLE_CAPTURES_DIR_NAME = "captures";
|
|
70389
70872
|
function createConsolePaths(deps = {}) {
|
|
70390
70873
|
const env = deps.env ?? process.env;
|
|
70391
70874
|
const base = env.FLEET_CONSOLE_DIR ?? defaultConsoleBaseDir(deps);
|
|
70392
70875
|
return { dir: base, lockFile: path93__default.join(base, LOCK_FILE_NAME) };
|
|
70393
70876
|
}
|
|
70877
|
+
function createConsoleDataPaths(deps = {}) {
|
|
70878
|
+
const dir = path93__default.join(deps.fleetDataDir ?? getFleetDataDir2(), CONSOLE_DATA_DIR_NAME);
|
|
70879
|
+
return {
|
|
70880
|
+
dir,
|
|
70881
|
+
stateFile: path93__default.join(dir, CONSOLE_STATE_FILE_NAME),
|
|
70882
|
+
capturesDir: path93__default.join(dir, CONSOLE_CAPTURES_DIR_NAME)
|
|
70883
|
+
};
|
|
70884
|
+
}
|
|
70394
70885
|
function defaultConsoleBaseDir(deps) {
|
|
70886
|
+
let release2;
|
|
70887
|
+
const channel = deps.channel ?? (release2 = readFleetConsoleRelease()).channel;
|
|
70888
|
+
if (channel === "local") {
|
|
70889
|
+
const packageRoot = deps.packageRoot ?? (release2 ??= readFleetConsoleRelease()).packageRoot;
|
|
70890
|
+
return path93__default.join(path93__default.resolve(packageRoot, "..", ".."), ".fleet", CONSOLE_RUNTIME_DIR_NAME);
|
|
70891
|
+
}
|
|
70395
70892
|
const uid = deps.uid ?? (typeof process.getuid === "function" ? process.getuid() : 0);
|
|
70396
|
-
|
|
70397
|
-
return path93__default.join(os22__default.tmpdir(), `${LOCK_DIR_NAME2}-${uid}-${channel}`);
|
|
70893
|
+
return path93__default.join(os22__default.tmpdir(), `${LOCK_DIR_NAME22}-${uid}-${channel}`);
|
|
70398
70894
|
}
|
|
70399
70895
|
var FLEET_PROTOCOL_GATE_PROMPT2 = String.raw`# Protocol Gate
|
|
70400
70896
|
|
|
@@ -70787,6 +71283,8 @@ function createClaudeFamilyCliDefinition2(options2) {
|
|
|
70787
71283
|
lineTerminator: "\r",
|
|
70788
71284
|
multilineStrategy: "paste-mode"
|
|
70789
71285
|
},
|
|
71286
|
+
// Claude Code 계열은 세션 이름 변경 슬래시 명령 `/rename`을 지원한다.
|
|
71287
|
+
renameCommand: "/rename",
|
|
70790
71288
|
terminalName: "xterm-256color"
|
|
70791
71289
|
};
|
|
70792
71290
|
}
|
|
@@ -70810,7 +71308,7 @@ var codexCli2 = {
|
|
|
70810
71308
|
async createProfile(options2) {
|
|
70811
71309
|
const { bin, prefixArgs } = resolveBinary2("codex", "CODEX_BIN", options2.env);
|
|
70812
71310
|
return {
|
|
70813
|
-
args: [...prefixArgs, "--no-alt-screen", ...buildModelArgs22(options2.model)],
|
|
71311
|
+
args: [...prefixArgs, ...buildResumeArgs4(options2.resumeSessionId), "--no-alt-screen", ...buildModelArgs22(options2.model)],
|
|
70814
71312
|
bin,
|
|
70815
71313
|
binPrefixArgs: prefixArgs,
|
|
70816
71314
|
cwd: options2.cwd,
|
|
@@ -70822,10 +71320,15 @@ var codexCli2 = {
|
|
|
70822
71320
|
lineTerminator: "\r",
|
|
70823
71321
|
multilineStrategy: "paste-mode"
|
|
70824
71322
|
},
|
|
71323
|
+
// Codex CLI도 세션 이름 변경 슬래시 명령 `/rename`을 지원한다.
|
|
71324
|
+
renameCommand: "/rename",
|
|
70825
71325
|
terminalName: "xterm-256color"
|
|
70826
71326
|
};
|
|
70827
71327
|
}
|
|
70828
71328
|
};
|
|
71329
|
+
function buildResumeArgs4(resumeSessionId) {
|
|
71330
|
+
return resumeSessionId === void 0 ? [] : ["resume", resumeSessionId];
|
|
71331
|
+
}
|
|
70829
71332
|
function buildModelArgs22(model) {
|
|
70830
71333
|
return model === void 0 ? [] : ["--model", model];
|
|
70831
71334
|
}
|
|
@@ -70842,7 +71345,8 @@ async function resolveAgentCliProfile2(env, cwd, options2 = {}) {
|
|
|
70842
71345
|
authService: options2.authService,
|
|
70843
71346
|
cwd,
|
|
70844
71347
|
env,
|
|
70845
|
-
model: options2.model
|
|
71348
|
+
model: options2.model,
|
|
71349
|
+
resumeSessionId: options2.resumeSessionId
|
|
70846
71350
|
});
|
|
70847
71351
|
}
|
|
70848
71352
|
function resolveAgentCliId2(env, options2 = {}) {
|
|
@@ -70886,6 +71390,20 @@ var AGENT_CLI_INJECTION_CAPABILITIES2 = {
|
|
|
70886
71390
|
function getAgentCliInjectionCapability2(cliId) {
|
|
70887
71391
|
return AGENT_CLI_INJECTION_CAPABILITIES2[cliId];
|
|
70888
71392
|
}
|
|
71393
|
+
function createSessionCaptureHookExec(deps) {
|
|
71394
|
+
const args = deps.tsxLoader ? [
|
|
71395
|
+
"--import",
|
|
71396
|
+
pathToFileURL2(deps.tsxLoader).href,
|
|
71397
|
+
deps.entryPath,
|
|
71398
|
+
"hook",
|
|
71399
|
+
"capture-session",
|
|
71400
|
+
deps.provider
|
|
71401
|
+
] : [deps.entryPath, "hook", "capture-session", deps.provider];
|
|
71402
|
+
return {
|
|
71403
|
+
command: deps.execPath ?? process5.execPath,
|
|
71404
|
+
args
|
|
71405
|
+
};
|
|
71406
|
+
}
|
|
70889
71407
|
function buildHostCarrierModelDefaults22(config22) {
|
|
70890
71408
|
const cliType = resolveAgentCliType22(config22.id, config22.defaultCliType);
|
|
70891
71409
|
const cliDefaults = buildCarrierModelDefaults2(config22, cliType);
|
|
@@ -70915,6 +71433,7 @@ function buildClaudeNativeSubagentPlan22(registry32) {
|
|
|
70915
71433
|
function buildClaudeNativeArgs2(context) {
|
|
70916
71434
|
const systemPromptArg = context.replaceSystemPrompt ? "--system-prompt-file" : "--append-system-prompt-file";
|
|
70917
71435
|
return [
|
|
71436
|
+
...buildResumeArgs22(context.resumeSessionId),
|
|
70918
71437
|
systemPromptArg,
|
|
70919
71438
|
requireSystemPromptFile2(context),
|
|
70920
71439
|
...context.pluginRoots.flatMap((pluginRoot) => [
|
|
@@ -70925,6 +71444,9 @@ function buildClaudeNativeArgs2(context) {
|
|
|
70925
71444
|
"--dangerously-skip-permissions"
|
|
70926
71445
|
];
|
|
70927
71446
|
}
|
|
71447
|
+
function buildResumeArgs22(resumeSessionId) {
|
|
71448
|
+
return resumeSessionId === void 0 ? [] : ["--resume", resumeSessionId];
|
|
71449
|
+
}
|
|
70928
71450
|
function buildClaudeMcpConfig2(servers) {
|
|
70929
71451
|
return JSON.stringify({
|
|
70930
71452
|
mcpServers: Object.fromEntries(
|
|
@@ -70982,20 +71504,32 @@ function escapeTomlMultilineString2(value) {
|
|
|
70982
71504
|
});
|
|
70983
71505
|
return result;
|
|
70984
71506
|
}
|
|
71507
|
+
function buildPosixShellCommand2(values) {
|
|
71508
|
+
return values.map(posixShellQuote2).join(" ");
|
|
71509
|
+
}
|
|
71510
|
+
function posixShellQuote2(value) {
|
|
71511
|
+
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
71512
|
+
}
|
|
70985
71513
|
var CODEX_TOOL_TIMEOUT_SEC2 = 1800;
|
|
70986
71514
|
function buildCodexNativeArgs2(context) {
|
|
70987
71515
|
const profileName = requireCodexProfileName2(context);
|
|
70988
71516
|
const args = [
|
|
71517
|
+
...buildResumeArgs32(context.resumeSessionId),
|
|
70989
71518
|
"--enable",
|
|
70990
71519
|
"plugins",
|
|
70991
71520
|
"--enable",
|
|
70992
71521
|
"child_agents_md",
|
|
71522
|
+
"--enable",
|
|
71523
|
+
"hooks",
|
|
70993
71524
|
"--profile",
|
|
70994
71525
|
profileName,
|
|
70995
71526
|
"-c",
|
|
70996
71527
|
'approval_policy="never"',
|
|
70997
71528
|
"-c",
|
|
70998
|
-
'sandbox_mode="danger-full-access"'
|
|
71529
|
+
'sandbox_mode="danger-full-access"',
|
|
71530
|
+
// hook 신뢰 프롬프트("Hooks need review")를 fleet 관리 세션에서 건너뛴다. bypass_hook_trust는
|
|
71531
|
+
// config 키가 아니라 전용 CLI 플래그이므로 -c override가 아닌 플래그로 전달해야 한다.
|
|
71532
|
+
"--dangerously-bypass-hook-trust"
|
|
70999
71533
|
];
|
|
71000
71534
|
for (const server of context.mcpServers) {
|
|
71001
71535
|
const prefix = `mcp_servers.${server.name}`;
|
|
@@ -71011,6 +71545,9 @@ function buildCodexNativeArgs2(context) {
|
|
|
71011
71545
|
}
|
|
71012
71546
|
return args;
|
|
71013
71547
|
}
|
|
71548
|
+
function buildResumeArgs32(resumeSessionId) {
|
|
71549
|
+
return resumeSessionId === void 0 ? [] : ["resume", resumeSessionId];
|
|
71550
|
+
}
|
|
71014
71551
|
function requireCodexProfileName2(context) {
|
|
71015
71552
|
if (context.codexProfileName) return context.codexProfileName;
|
|
71016
71553
|
throw new Error("Codex profile name is required for native injection");
|
|
@@ -71221,20 +71758,32 @@ function claudeHooks2(options2) {
|
|
|
71221
71758
|
if (!hookExec) {
|
|
71222
71759
|
throw new Error("Fleet Claude session hook command is required");
|
|
71223
71760
|
}
|
|
71761
|
+
const captureSessionHookExec = options2.captureSessionHookExec;
|
|
71224
71762
|
return {
|
|
71225
71763
|
hooks: {
|
|
71226
71764
|
SessionStart: [{
|
|
71227
|
-
hooks: [
|
|
71228
|
-
|
|
71229
|
-
|
|
71230
|
-
|
|
71231
|
-
|
|
71232
|
-
type: "command"
|
|
71765
|
+
hooks: [claudeCommandHook2(hookExec)]
|
|
71766
|
+
}],
|
|
71767
|
+
...captureSessionHookExec ? {
|
|
71768
|
+
UserPromptSubmit: [{
|
|
71769
|
+
hooks: [claudeCommandHook2(captureSessionHookExec)]
|
|
71233
71770
|
}]
|
|
71234
|
-
}
|
|
71771
|
+
} : {}
|
|
71235
71772
|
}
|
|
71236
71773
|
};
|
|
71237
71774
|
}
|
|
71775
|
+
function claudeCommandHook2(hookExec) {
|
|
71776
|
+
if (!hookExec) {
|
|
71777
|
+
throw new Error("Fleet Claude session hook command is required");
|
|
71778
|
+
}
|
|
71779
|
+
return {
|
|
71780
|
+
// exec 형식: command는 직접 spawn되는 실행 파일, args는 셸 토크나이징 없이 그대로 전달된다.
|
|
71781
|
+
// Windows cmd/powershell의 따옴표 규칙과 무관하게 동작하며 공백 포함 경로도 안전하다.
|
|
71782
|
+
args: [...hookExec.args],
|
|
71783
|
+
command: hookExec.command,
|
|
71784
|
+
type: "command"
|
|
71785
|
+
};
|
|
71786
|
+
}
|
|
71238
71787
|
function claudeAgentFile2(subagent) {
|
|
71239
71788
|
const frontmatter = [
|
|
71240
71789
|
"---",
|
|
@@ -71744,7 +72293,7 @@ function homeMarketplaceTarget2(fleetRoot) {
|
|
|
71744
72293
|
}
|
|
71745
72294
|
function projectMarketplaceTarget2(cwd) {
|
|
71746
72295
|
const projectFleetRoot = resolveProjectFleetRoot2(cwd);
|
|
71747
|
-
const hash22 =
|
|
72296
|
+
const hash22 = crypto5.createHash("sha256").update(path93__default.resolve(cwd, ".fleet")).digest("hex").slice(0, 12);
|
|
71748
72297
|
return {
|
|
71749
72298
|
flat: true,
|
|
71750
72299
|
name: `${FLEET_PROJECT_MARKETPLACE_NAME_PREFIX2}-${hash22}`,
|
|
@@ -71770,7 +72319,6 @@ function renderPluginRoot2(pluginRoot, bundle, options2, fleetRoot) {
|
|
|
71770
72319
|
const stagedPluginRoot = path93__default.join(stageParent, path93__default.basename(pluginRoot));
|
|
71771
72320
|
try {
|
|
71772
72321
|
ensurePrivateDir2(stagedPluginRoot, stagedPluginRoot);
|
|
71773
|
-
writePrivateJson2(path93__default.join(stagedPluginRoot, ".codex-plugin", "plugin.json"), codexManifest2(bundle), stagedPluginRoot);
|
|
71774
72322
|
writePrivateJson2(path93__default.join(stagedPluginRoot, ".claude-plugin", "plugin.json"), claudeManifest2(bundle), stagedPluginRoot);
|
|
71775
72323
|
switch (bundle.source) {
|
|
71776
72324
|
case "asset":
|
|
@@ -71785,6 +72333,7 @@ function renderPluginRoot2(pluginRoot, bundle, options2, fleetRoot) {
|
|
|
71785
72333
|
renderGlobalPluginRoot2(stagedPluginRoot, fleetRoot);
|
|
71786
72334
|
break;
|
|
71787
72335
|
}
|
|
72336
|
+
writePrivateJson2(path93__default.join(stagedPluginRoot, ".codex-plugin", "plugin.json"), codexManifest2(bundle, stagedPluginRoot), stagedPluginRoot);
|
|
71788
72337
|
removePrivatePath2(pluginRoot, parentRoot);
|
|
71789
72338
|
renameSync5(stagedPluginRoot, pluginRoot);
|
|
71790
72339
|
} finally {
|
|
@@ -71813,7 +72362,7 @@ function pruneMarketplaceRoot2(target) {
|
|
|
71813
72362
|
}
|
|
71814
72363
|
}
|
|
71815
72364
|
function buildContentHash2(target) {
|
|
71816
|
-
const hash22 =
|
|
72365
|
+
const hash22 = crypto5.createHash("sha256");
|
|
71817
72366
|
for (const filePath of listRenderableFiles2(target)) {
|
|
71818
72367
|
const relativePath2 = path93__default.relative(target.root, filePath);
|
|
71819
72368
|
hash22.update(relativePath2);
|
|
@@ -71916,14 +72465,36 @@ function marketplacePluginPath2(target, bundle) {
|
|
|
71916
72465
|
if (target.flat) return `./${FLAT_PLUGIN_DIR_NAME2}`;
|
|
71917
72466
|
return `./${PLUGIN_BUNDLES_DIR_NAME2}/${bundle.directoryName}`;
|
|
71918
72467
|
}
|
|
71919
|
-
function codexManifest2(bundle) {
|
|
72468
|
+
function codexManifest2(bundle, pluginRoot) {
|
|
71920
72469
|
return {
|
|
71921
72470
|
name: bundle.name,
|
|
71922
|
-
version:
|
|
72471
|
+
version: codexManifestVersion2(bundle, pluginRoot),
|
|
71923
72472
|
description: bundle.description,
|
|
71924
72473
|
skills: "./skills/"
|
|
71925
72474
|
};
|
|
71926
72475
|
}
|
|
72476
|
+
function codexManifestVersion2(bundle, pluginRoot) {
|
|
72477
|
+
const hash22 = crypto5.createHash("sha256");
|
|
72478
|
+
hash22.update(bundle.name);
|
|
72479
|
+
hash22.update("\0");
|
|
72480
|
+
hash22.update(bundle.description);
|
|
72481
|
+
hash22.update("\0");
|
|
72482
|
+
for (const filePath of listCodexEffectivePluginFiles2(pluginRoot)) {
|
|
72483
|
+
const relativePath2 = path93__default.relative(pluginRoot, filePath);
|
|
72484
|
+
hash22.update(relativePath2);
|
|
72485
|
+
hash22.update("\0");
|
|
72486
|
+
hash22.update(readFileSync8(filePath));
|
|
72487
|
+
hash22.update("\0");
|
|
72488
|
+
}
|
|
72489
|
+
return `0.0.0+${hash22.digest("hex").slice(0, 12)}`;
|
|
72490
|
+
}
|
|
72491
|
+
function listCodexEffectivePluginFiles2(pluginRoot) {
|
|
72492
|
+
const skillsPath = path93__default.join(pluginRoot, "skills");
|
|
72493
|
+
if (!existsSync8(skillsPath)) return [];
|
|
72494
|
+
const files = [];
|
|
72495
|
+
collectRenderableFiles2(pluginRoot, skillsPath, files, /* @__PURE__ */ new Set());
|
|
72496
|
+
return files.sort();
|
|
72497
|
+
}
|
|
71927
72498
|
function claudeManifest2(bundle) {
|
|
71928
72499
|
return {
|
|
71929
72500
|
name: bundle.name,
|
|
@@ -71943,7 +72514,7 @@ async function injectAgentCliProfile2(profile, options2) {
|
|
|
71943
72514
|
const injectTone = options2.enableMetaphor ?? false;
|
|
71944
72515
|
const endpoint = await options2.dedicatedMcpSession.getEndpoint();
|
|
71945
72516
|
const startupDefinitions = buildStartupNativeDefinitions2(profile.id, options2.carrierRuntime);
|
|
71946
|
-
const tokenLabel = options2.mcpSessionLabel ?? `agent:${profile.id}:${
|
|
72517
|
+
const tokenLabel = options2.mcpSessionLabel ?? `agent:${profile.id}:${crypto5.randomUUID()}`;
|
|
71947
72518
|
const tokens = await options2.dedicatedMcpSession.issueSessionToken({ cwd: profile.cwd, label: tokenLabel });
|
|
71948
72519
|
const mcpServers = buildAgentCliMcpServerConfigs2(endpoint.servers, tokens);
|
|
71949
72520
|
const doctrine = options2.buildSystemPrompt(injectTone);
|
|
@@ -71957,11 +72528,12 @@ async function injectAgentCliProfile2(profile, options2) {
|
|
|
71957
72528
|
cwd: profile.cwd,
|
|
71958
72529
|
dataDir: options2.dataDir,
|
|
71959
72530
|
rootDir: options2.pluginRootDir,
|
|
72531
|
+
captureSessionHookExec: options2.captureSessionHookExec,
|
|
71960
72532
|
hookExec: startupDefinitions.host === "claude" ? requireHookExec2(options2.hookExec) : void 0,
|
|
71961
72533
|
withMarketplaceLock: options2.withMarketplaceLock
|
|
71962
72534
|
});
|
|
71963
72535
|
const codexPluginKeys = plugin.codexRegistrations.map((registration) => `${registration.pluginName}@${registration.marketplaceName}`);
|
|
71964
|
-
const codexProfile = profile.id === "codex" ? writeCodexFleetProfile2(profile.env, doctrine, codexPluginKeys, (cleanup2) => tempCleanups.push(cleanup2)) : void 0;
|
|
72536
|
+
const codexProfile = profile.id === "codex" ? writeCodexFleetProfile2(profile.env, doctrine, codexPluginKeys, options2.captureSessionHookExec, (cleanup2) => tempCleanups.push(cleanup2)) : void 0;
|
|
71965
72537
|
const launchWarnings = [];
|
|
71966
72538
|
for (const registration of plugin.codexRegistrations) {
|
|
71967
72539
|
const registrationWarning = await ensureCodexPluginRegistered2(registration, {
|
|
@@ -71988,13 +72560,14 @@ async function injectAgentCliProfile2(profile, options2) {
|
|
|
71988
72560
|
pluginRoot: plugin.pluginRoot,
|
|
71989
72561
|
pluginRoots: plugin.pluginRoots,
|
|
71990
72562
|
codexProfileName: codexProfile?.profileName,
|
|
71991
|
-
replaceSystemPrompt: options2.replaceSystemPrompt ??
|
|
72563
|
+
replaceSystemPrompt: options2.replaceSystemPrompt ?? false,
|
|
72564
|
+
resumeSessionId: options2.resumeSessionId,
|
|
71992
72565
|
systemPromptFile
|
|
71993
72566
|
};
|
|
71994
72567
|
const injectedArgs = buildAgentCliArgs2(capability.builderId, context);
|
|
71995
72568
|
return {
|
|
71996
72569
|
...profile,
|
|
71997
|
-
args:
|
|
72570
|
+
args: mergeAgentCliArgs2(profile, capability.builderId, context, injectedArgs),
|
|
71998
72571
|
cleanup,
|
|
71999
72572
|
launchWarnings: [...profile.launchWarnings ?? [], ...launchWarnings]
|
|
72000
72573
|
};
|
|
@@ -72036,11 +72609,11 @@ function writeSystemPromptFile2(cliId, systemPrompt, onCleanup) {
|
|
|
72036
72609
|
chmodBestEffort22(filePath, SYSTEM_PROMPT_FILE_MODE2);
|
|
72037
72610
|
return filePath;
|
|
72038
72611
|
}
|
|
72039
|
-
function writeCodexFleetProfile2(env, doctrine, pluginKeys, onCleanup) {
|
|
72612
|
+
function writeCodexFleetProfile2(env, doctrine, pluginKeys, captureSessionHookExec, onCleanup) {
|
|
72040
72613
|
const codexHome = env.CODEX_HOME ?? path93__default.join(env.HOME ?? os22__default.homedir(), ".codex");
|
|
72041
72614
|
mkdirSync8(codexHome, { recursive: true });
|
|
72042
72615
|
pruneStaleCodexFleetProfiles2(codexHome);
|
|
72043
|
-
const profileName = `fleet-${
|
|
72616
|
+
const profileName = `fleet-${crypto5.randomUUID()}`;
|
|
72044
72617
|
const profilePath = path93__default.join(codexHome, `${profileName}.config.toml`);
|
|
72045
72618
|
onCleanup(() => rmBestEffort2(profilePath));
|
|
72046
72619
|
writeFileNoFollow22(profilePath, [
|
|
@@ -72055,11 +72628,21 @@ function writeCodexFleetProfile2(env, doctrine, pluginKeys, onCleanup) {
|
|
|
72055
72628
|
`[plugins."${escapeTomlBasicString22(pluginKey)}"]`,
|
|
72056
72629
|
"enabled = true",
|
|
72057
72630
|
""
|
|
72058
|
-
])
|
|
72631
|
+
]),
|
|
72632
|
+
...codexCaptureHookConfig2(captureSessionHookExec)
|
|
72059
72633
|
].join("\n"));
|
|
72060
72634
|
chmodBestEffort22(profilePath, SYSTEM_PROMPT_FILE_MODE2);
|
|
72061
72635
|
return { profileName, profilePath };
|
|
72062
72636
|
}
|
|
72637
|
+
function codexCaptureHookConfig2(captureSessionHookExec) {
|
|
72638
|
+
if (captureSessionHookExec === void 0) return [];
|
|
72639
|
+
const command22 = buildPosixShellCommand2([captureSessionHookExec.command, ...captureSessionHookExec.args]);
|
|
72640
|
+
return [
|
|
72641
|
+
"[hooks]",
|
|
72642
|
+
`UserPromptSubmit = [{ hooks = [{ type = "command", command = "${escapeTomlBasicString22(command22)}" }] }]`,
|
|
72643
|
+
""
|
|
72644
|
+
];
|
|
72645
|
+
}
|
|
72063
72646
|
function writeFileNoFollow22(filePath, content) {
|
|
72064
72647
|
const flags = constants8.O_WRONLY | constants8.O_CREAT | constants8.O_TRUNC | constants8.O_NOFOLLOW;
|
|
72065
72648
|
const fd = openSync8(filePath, flags, SYSTEM_PROMPT_FILE_MODE2);
|
|
@@ -72132,6 +72715,24 @@ function buildAgentCliArgs2(builderId, context) {
|
|
|
72132
72715
|
return buildCodexNativeArgs2(context);
|
|
72133
72716
|
}
|
|
72134
72717
|
}
|
|
72718
|
+
function mergeAgentCliArgs2(profile, builderId, context, injectedArgs) {
|
|
72719
|
+
if (builderId !== "codex-native" || context.resumeSessionId === void 0) {
|
|
72720
|
+
return [...profile.args, ...injectedArgs];
|
|
72721
|
+
}
|
|
72722
|
+
const resumeSessionId = context.resumeSessionId;
|
|
72723
|
+
const prefixLength = profile.binPrefixArgs?.length ?? 0;
|
|
72724
|
+
const codexResumeArgs = ["resume", resumeSessionId];
|
|
72725
|
+
const injectedTail = injectedArgs.slice(codexResumeArgs.length);
|
|
72726
|
+
return [
|
|
72727
|
+
...profile.args.slice(0, prefixLength),
|
|
72728
|
+
...codexResumeArgs,
|
|
72729
|
+
...profile.args.slice(prefixLength).filter((arg, index, args) => !isCodexResumeArgAt2(args, index, resumeSessionId)),
|
|
72730
|
+
...injectedTail
|
|
72731
|
+
];
|
|
72732
|
+
}
|
|
72733
|
+
function isCodexResumeArgAt2(args, index, resumeSessionId) {
|
|
72734
|
+
return args[index] === "resume" && args[index + 1] === resumeSessionId || args[index] === resumeSessionId && args[index - 1] === "resume";
|
|
72735
|
+
}
|
|
72135
72736
|
function createOnceCleanup2(cleanup) {
|
|
72136
72737
|
let cleaned = false;
|
|
72137
72738
|
return () => {
|
|
@@ -72315,387 +72916,6 @@ function applyMessagePolicy2(text, policy) {
|
|
|
72315
72916
|
submit: policy.lineTerminator
|
|
72316
72917
|
};
|
|
72317
72918
|
}
|
|
72318
|
-
var FLEET_DATA_DIR_NAME2 = ".fleet";
|
|
72319
|
-
function getFleetDataDir2() {
|
|
72320
|
-
return path93.join(os222.homedir(), FLEET_DATA_DIR_NAME2);
|
|
72321
|
-
}
|
|
72322
|
-
function readAuthStoreFile2(filePath) {
|
|
72323
|
-
let fd;
|
|
72324
|
-
try {
|
|
72325
|
-
fd = fs52.openSync(filePath, fs52.constants.O_RDONLY | NOFOLLOW_FLAG2);
|
|
72326
|
-
if (!fs52.fstatSync(fd).isFile()) {
|
|
72327
|
-
return {};
|
|
72328
|
-
}
|
|
72329
|
-
return JSON.parse(fs52.readFileSync(fd, "utf-8"));
|
|
72330
|
-
} catch {
|
|
72331
|
-
return {};
|
|
72332
|
-
} finally {
|
|
72333
|
-
if (fd !== void 0) {
|
|
72334
|
-
try {
|
|
72335
|
-
fs52.closeSync(fd);
|
|
72336
|
-
} catch {
|
|
72337
|
-
}
|
|
72338
|
-
}
|
|
72339
|
-
}
|
|
72340
|
-
}
|
|
72341
|
-
var DEFAULT_AUTH_PATH2 = path93.join(getFleetDataDir2(), "auth.json");
|
|
72342
|
-
var AUTH_LOCK_OWNER_FILE_NAME2 = "owner.json";
|
|
72343
|
-
var AUTH_LOCK_TIMEOUT_MS2 = 5e3;
|
|
72344
|
-
function createAuthService2(deps = {}) {
|
|
72345
|
-
const authPath = deps.authPath ?? DEFAULT_AUTH_PATH2;
|
|
72346
|
-
const lockDir = `${authPath}.lock`;
|
|
72347
|
-
return {
|
|
72348
|
-
// [HIGH #1] TOCTOU 수정: existsSync/read/check/delete/write 전체를 락 블록 안으로 이동
|
|
72349
|
-
async deleteApiKey(providerId) {
|
|
72350
|
-
let deleted = false;
|
|
72351
|
-
withAuthLock2(authPath, lockDir, () => {
|
|
72352
|
-
if (!fs52.existsSync(authPath)) return;
|
|
72353
|
-
const data = readAuthStoreFile2(authPath);
|
|
72354
|
-
if (!Object.prototype.hasOwnProperty.call(data, providerId)) return;
|
|
72355
|
-
delete data[providerId];
|
|
72356
|
-
writeAuthData2(authPath, data);
|
|
72357
|
-
deleted = true;
|
|
72358
|
-
});
|
|
72359
|
-
return deleted;
|
|
72360
|
-
},
|
|
72361
|
-
// [HIGH #2] 읽기 경로: fd 기반 O_RDONLY|O_NOFOLLOW+fstatSync isFile
|
|
72362
|
-
async getApiKey(providerId) {
|
|
72363
|
-
let fd;
|
|
72364
|
-
try {
|
|
72365
|
-
if (!fs52.existsSync(authPath)) {
|
|
72366
|
-
return void 0;
|
|
72367
|
-
}
|
|
72368
|
-
fd = fs52.openSync(authPath, fs52.constants.O_RDONLY | NOFOLLOW_FLAG2);
|
|
72369
|
-
if (!fs52.fstatSync(fd).isFile()) {
|
|
72370
|
-
return void 0;
|
|
72371
|
-
}
|
|
72372
|
-
const data = JSON.parse(fs52.readFileSync(fd, "utf-8"));
|
|
72373
|
-
return typeof data[providerId]?.key === "string" ? data[providerId].key : void 0;
|
|
72374
|
-
} catch {
|
|
72375
|
-
return void 0;
|
|
72376
|
-
} finally {
|
|
72377
|
-
if (fd !== void 0) {
|
|
72378
|
-
try {
|
|
72379
|
-
fs52.closeSync(fd);
|
|
72380
|
-
} catch {
|
|
72381
|
-
}
|
|
72382
|
-
}
|
|
72383
|
-
}
|
|
72384
|
-
},
|
|
72385
|
-
// [HIGH #2] 읽기 경로: fd 기반 O_RDONLY|O_NOFOLLOW 통일
|
|
72386
|
-
async listProviderIds() {
|
|
72387
|
-
if (!fs52.existsSync(authPath)) {
|
|
72388
|
-
return [];
|
|
72389
|
-
}
|
|
72390
|
-
try {
|
|
72391
|
-
return Object.keys(readAuthStoreFile2(authPath)).sort();
|
|
72392
|
-
} catch {
|
|
72393
|
-
return [];
|
|
72394
|
-
}
|
|
72395
|
-
},
|
|
72396
|
-
async setApiKey(providerId, key) {
|
|
72397
|
-
const dir = path93.dirname(authPath);
|
|
72398
|
-
ensureSafeDirectory2(dir);
|
|
72399
|
-
withAuthLock2(authPath, lockDir, () => {
|
|
72400
|
-
const data = fs52.existsSync(authPath) ? readAuthStoreFile2(authPath) : {};
|
|
72401
|
-
data[providerId] = {
|
|
72402
|
-
...data[providerId] ?? {},
|
|
72403
|
-
key
|
|
72404
|
-
};
|
|
72405
|
-
writeAuthData2(authPath, data);
|
|
72406
|
-
});
|
|
72407
|
-
}
|
|
72408
|
-
};
|
|
72409
|
-
}
|
|
72410
|
-
function withAuthLock2(authPath, lockDir, operation) {
|
|
72411
|
-
return withDirectoryLock2(
|
|
72412
|
-
{
|
|
72413
|
-
lockDir,
|
|
72414
|
-
ownerFileName: AUTH_LOCK_OWNER_FILE_NAME2,
|
|
72415
|
-
timeoutMs: AUTH_LOCK_TIMEOUT_MS2
|
|
72416
|
-
},
|
|
72417
|
-
operation
|
|
72418
|
-
);
|
|
72419
|
-
}
|
|
72420
|
-
function writeAuthData2(authPath, data) {
|
|
72421
|
-
writeAtomicSync2(authPath, `${JSON.stringify(data, null, 2)}
|
|
72422
|
-
`, {
|
|
72423
|
-
mode: SECURE_FILE_MODE2,
|
|
72424
|
-
fsync: true
|
|
72425
|
-
});
|
|
72426
|
-
}
|
|
72427
|
-
function formatMissingAuthKeyMessage2(input) {
|
|
72428
|
-
const cliHint = input.cli ? `cli '${input.cli}'` : "selected CLI";
|
|
72429
|
-
return `Auth token not found for ${cliHint} (providerId: '${input.providerId}'). Run \`fleet auth login\` to register one.`;
|
|
72430
|
-
}
|
|
72431
|
-
function formatAuthValidationFailureMessage2(input) {
|
|
72432
|
-
const detail = input.detail ? ` Detail: ${input.detail}` : "";
|
|
72433
|
-
if (input.status === "unauthorized") {
|
|
72434
|
-
return `Auth token was rejected (providerId: '${input.providerId}'). Check the token and try again.${detail}`;
|
|
72435
|
-
}
|
|
72436
|
-
if (input.status === "forbidden") {
|
|
72437
|
-
return `Auth token is not allowed for this provider (providerId: '${input.providerId}'). Check the token permissions.${detail}`;
|
|
72438
|
-
}
|
|
72439
|
-
if (input.status === "timeout") {
|
|
72440
|
-
return `Auth token validation timed out (providerId: '${input.providerId}'). Check the connection and try again.${detail}`;
|
|
72441
|
-
}
|
|
72442
|
-
if (input.status === "network") {
|
|
72443
|
-
return `Auth token validation failed due to a network error (providerId: '${input.providerId}'). Check the connection and try again.${detail}`;
|
|
72444
|
-
}
|
|
72445
|
-
if (input.status === "server") {
|
|
72446
|
-
return `Auth token validation failed because the provider returned an error (providerId: '${input.providerId}'). Try again later.${detail}`;
|
|
72447
|
-
}
|
|
72448
|
-
return `Auth token validation failed (providerId: '${input.providerId}'). Check the token and try again.${detail}`;
|
|
72449
|
-
}
|
|
72450
|
-
var LEGACY_AUTH_PATH2 = path93.join(getFleetDataDir2(), "agent", "auth.json");
|
|
72451
|
-
var CURRENT_AUTH_PATH2 = path93.join(getFleetDataDir2(), "auth.json");
|
|
72452
|
-
function mergeAuthStoresNoOverwrite2(legacy, current) {
|
|
72453
|
-
const data = { ...current };
|
|
72454
|
-
const migratedProviderIds = [];
|
|
72455
|
-
const skippedProviderIds = [];
|
|
72456
|
-
for (const [providerId, entry] of Object.entries(legacy)) {
|
|
72457
|
-
if (Object.prototype.hasOwnProperty.call(data, providerId)) {
|
|
72458
|
-
skippedProviderIds.push(providerId);
|
|
72459
|
-
continue;
|
|
72460
|
-
}
|
|
72461
|
-
data[providerId] = entry;
|
|
72462
|
-
migratedProviderIds.push(providerId);
|
|
72463
|
-
}
|
|
72464
|
-
return {
|
|
72465
|
-
data,
|
|
72466
|
-
migratedProviderIds,
|
|
72467
|
-
skippedProviderIds
|
|
72468
|
-
};
|
|
72469
|
-
}
|
|
72470
|
-
async function migrateLegacyAuthStore2(options2 = {}) {
|
|
72471
|
-
const legacyPath = options2.legacyPath ?? LEGACY_AUTH_PATH2;
|
|
72472
|
-
const currentPath = options2.currentPath ?? CURRENT_AUTH_PATH2;
|
|
72473
|
-
if (!fs52.existsSync(legacyPath)) {
|
|
72474
|
-
return createMigrationResult2({
|
|
72475
|
-
legacyPath,
|
|
72476
|
-
currentPath,
|
|
72477
|
-
status: "legacy-missing",
|
|
72478
|
-
migratedProviderIds: [],
|
|
72479
|
-
skippedProviderIds: [],
|
|
72480
|
-
shouldPrintNotice: false
|
|
72481
|
-
});
|
|
72482
|
-
}
|
|
72483
|
-
const legacy = readAuthStoreFile2(legacyPath);
|
|
72484
|
-
const current = fs52.existsSync(currentPath) ? readAuthStoreFile2(currentPath) : {};
|
|
72485
|
-
const merged = mergeAuthStoresNoOverwrite2(legacy, current);
|
|
72486
|
-
if (merged.migratedProviderIds.length > 0) {
|
|
72487
|
-
const dir = path93.dirname(currentPath);
|
|
72488
|
-
ensureSafeDirectory2(dir);
|
|
72489
|
-
writeAtomicSync2(currentPath, `${JSON.stringify(merged.data, null, 2)}
|
|
72490
|
-
`, {
|
|
72491
|
-
mode: SECURE_FILE_MODE2,
|
|
72492
|
-
fsync: true
|
|
72493
|
-
});
|
|
72494
|
-
}
|
|
72495
|
-
return createMigrationResult2({
|
|
72496
|
-
legacyPath,
|
|
72497
|
-
currentPath,
|
|
72498
|
-
status: merged.migratedProviderIds.length > 0 ? "migrated" : "unchanged",
|
|
72499
|
-
migratedProviderIds: merged.migratedProviderIds,
|
|
72500
|
-
skippedProviderIds: merged.skippedProviderIds,
|
|
72501
|
-
shouldPrintNotice: options2.notify !== false && merged.migratedProviderIds.length > 0
|
|
72502
|
-
});
|
|
72503
|
-
}
|
|
72504
|
-
function createMigrationResult2(input) {
|
|
72505
|
-
return {
|
|
72506
|
-
legacyPath: input.legacyPath,
|
|
72507
|
-
currentPath: input.currentPath,
|
|
72508
|
-
migratedCount: input.migratedProviderIds.length,
|
|
72509
|
-
skippedCount: input.skippedProviderIds.length,
|
|
72510
|
-
migratedProviderIds: input.migratedProviderIds,
|
|
72511
|
-
skippedProviderIds: input.skippedProviderIds,
|
|
72512
|
-
shouldPrintNotice: input.shouldPrintNotice,
|
|
72513
|
-
status: input.status
|
|
72514
|
-
};
|
|
72515
|
-
}
|
|
72516
|
-
var DEFAULT_AUTH_VALIDATION_TIMEOUT_MS2 = 5e3;
|
|
72517
|
-
async function validateAnthropicCompatibleApiKey2(request) {
|
|
72518
|
-
const controller = new AbortController();
|
|
72519
|
-
const timeout = setTimeout(() => {
|
|
72520
|
-
controller.abort();
|
|
72521
|
-
}, request.timeoutMs ?? DEFAULT_AUTH_VALIDATION_TIMEOUT_MS2);
|
|
72522
|
-
try {
|
|
72523
|
-
const response = await fetch(buildMessagesUrl2(request.baseUrl), {
|
|
72524
|
-
method: "POST",
|
|
72525
|
-
headers: {
|
|
72526
|
-
"anthropic-version": "2023-06-01",
|
|
72527
|
-
"content-type": "application/json",
|
|
72528
|
-
"x-api-key": request.apiKey
|
|
72529
|
-
},
|
|
72530
|
-
body: JSON.stringify({
|
|
72531
|
-
model: "claude-3-5-haiku-20241022",
|
|
72532
|
-
max_tokens: 1,
|
|
72533
|
-
messages: [
|
|
72534
|
-
{
|
|
72535
|
-
role: "user",
|
|
72536
|
-
content: "ping"
|
|
72537
|
-
}
|
|
72538
|
-
]
|
|
72539
|
-
}),
|
|
72540
|
-
signal: controller.signal
|
|
72541
|
-
});
|
|
72542
|
-
if (response.ok) {
|
|
72543
|
-
return { providerId: request.providerId, status: "success" };
|
|
72544
|
-
}
|
|
72545
|
-
if (response.status === 401) {
|
|
72546
|
-
return { providerId: request.providerId, status: "unauthorized" };
|
|
72547
|
-
}
|
|
72548
|
-
if (response.status === 403) {
|
|
72549
|
-
return { providerId: request.providerId, status: "forbidden" };
|
|
72550
|
-
}
|
|
72551
|
-
if (response.status >= 500) {
|
|
72552
|
-
return {
|
|
72553
|
-
providerId: request.providerId,
|
|
72554
|
-
status: "server",
|
|
72555
|
-
detail: `HTTP ${response.status}`
|
|
72556
|
-
};
|
|
72557
|
-
}
|
|
72558
|
-
return {
|
|
72559
|
-
providerId: request.providerId,
|
|
72560
|
-
status: "unknown",
|
|
72561
|
-
detail: `HTTP ${response.status}`
|
|
72562
|
-
};
|
|
72563
|
-
} catch (error512) {
|
|
72564
|
-
if (isAbortError2(error512)) {
|
|
72565
|
-
return { providerId: request.providerId, status: "timeout" };
|
|
72566
|
-
}
|
|
72567
|
-
return {
|
|
72568
|
-
providerId: request.providerId,
|
|
72569
|
-
status: "network",
|
|
72570
|
-
detail: error512 instanceof Error ? error512.message : String(error512)
|
|
72571
|
-
};
|
|
72572
|
-
} finally {
|
|
72573
|
-
clearTimeout(timeout);
|
|
72574
|
-
}
|
|
72575
|
-
}
|
|
72576
|
-
function isAuthValidationSuccess2(result) {
|
|
72577
|
-
return result.status === "success";
|
|
72578
|
-
}
|
|
72579
|
-
function createAuthValidationError2(result) {
|
|
72580
|
-
return new Error(formatAuthValidationFailureMessage2(result));
|
|
72581
|
-
}
|
|
72582
|
-
function buildMessagesUrl2(baseUrl) {
|
|
72583
|
-
return `${baseUrl.replace(/\/+$/, "")}/v1/messages`;
|
|
72584
|
-
}
|
|
72585
|
-
function isAbortError2(error512) {
|
|
72586
|
-
return error512 instanceof DOMException && error512.name === "AbortError";
|
|
72587
|
-
}
|
|
72588
|
-
var CLAUDE_ZAI_PROVIDER_ID2 = "Claude Code with Z.AI GLM";
|
|
72589
|
-
var CLAUDE_KIMI_PROVIDER_ID2 = "Claude Code with Moonshot Kimi";
|
|
72590
|
-
var AUTH_PROVIDER_DEFINITIONS2 = {
|
|
72591
|
-
"claude-zai": {
|
|
72592
|
-
providerId: CLAUDE_ZAI_PROVIDER_ID2,
|
|
72593
|
-
baseUrl: CLI_BACKENDS2["claude-zai"].defaultEnv.ANTHROPIC_BASE_URL,
|
|
72594
|
-
env: CLI_BACKENDS2["claude-zai"].defaultEnv
|
|
72595
|
-
},
|
|
72596
|
-
"claude-kimi": {
|
|
72597
|
-
providerId: CLAUDE_KIMI_PROVIDER_ID2,
|
|
72598
|
-
baseUrl: CLI_BACKENDS2["claude-kimi"].defaultEnv.ANTHROPIC_BASE_URL,
|
|
72599
|
-
env: CLI_BACKENDS2["claude-kimi"].defaultEnv
|
|
72600
|
-
}
|
|
72601
|
-
};
|
|
72602
|
-
async function resolveAuthEnv2(cli, deps) {
|
|
72603
|
-
const provider = AUTH_PROVIDER_DEFINITIONS2[cli];
|
|
72604
|
-
if (!provider) return {};
|
|
72605
|
-
await migrateLegacyAuthStore2();
|
|
72606
|
-
const auth = deps?.authService ?? createAuthService2({ authPath: DEFAULT_AUTH_PATH2 });
|
|
72607
|
-
const token = await auth.getApiKey(provider.providerId);
|
|
72608
|
-
if (!token) {
|
|
72609
|
-
throw new Error(formatMissingAuthKeyMessage2({ cli, providerId: provider.providerId }));
|
|
72610
|
-
}
|
|
72611
|
-
const validation = await validateAnthropicCompatibleApiKey2({
|
|
72612
|
-
providerId: provider.providerId,
|
|
72613
|
-
apiKey: token,
|
|
72614
|
-
baseUrl: provider.baseUrl
|
|
72615
|
-
});
|
|
72616
|
-
if (!isAuthValidationSuccess2(validation)) {
|
|
72617
|
-
const failure = {
|
|
72618
|
-
providerId: validation.providerId,
|
|
72619
|
-
status: validation.status,
|
|
72620
|
-
detail: validation.detail
|
|
72621
|
-
};
|
|
72622
|
-
throw createAuthValidationError2(failure);
|
|
72623
|
-
}
|
|
72624
|
-
return { ...provider.env, ANTHROPIC_AUTH_TOKEN: token };
|
|
72625
|
-
}
|
|
72626
|
-
var GLOBAL_OPTIONS_VERSION2 = 1;
|
|
72627
|
-
var GLOBAL_OPTIONS_FILE_NAME2 = "settings.json";
|
|
72628
|
-
var LOCK_DIR_NAME22 = "settings.json.lock";
|
|
72629
|
-
var LOCK_OWNER_FILE_NAME2 = "owner";
|
|
72630
|
-
var TEMP_FILE_PREFIX2 = `.tmp-${GLOBAL_OPTIONS_FILE_NAME2}-`;
|
|
72631
|
-
function createGlobalOptionsStore2(deps = {}) {
|
|
72632
|
-
const dataDir = deps.dataDir ?? getFleetDataDir2();
|
|
72633
|
-
const optionsPath = path93.join(dataDir, GLOBAL_OPTIONS_FILE_NAME2);
|
|
72634
|
-
const lockDir = path93.join(dataDir, LOCK_DIR_NAME22);
|
|
72635
|
-
const store22 = createDurableJsonStore2({
|
|
72636
|
-
filePath: optionsPath,
|
|
72637
|
-
lockDir,
|
|
72638
|
-
lockOwnerFileName: LOCK_OWNER_FILE_NAME2,
|
|
72639
|
-
sanitize: (value) => sanitizeGlobalOptionsData2(value).data,
|
|
72640
|
-
sensitivity: "sensitive",
|
|
72641
|
-
timeoutMs: deps.timeoutMs,
|
|
72642
|
-
staleLockMs: deps.staleLockMs,
|
|
72643
|
-
tempCleanupPrefix: TEMP_FILE_PREFIX2,
|
|
72644
|
-
now: deps.now
|
|
72645
|
-
});
|
|
72646
|
-
return {
|
|
72647
|
-
path: optionsPath,
|
|
72648
|
-
load: () => store22.load(),
|
|
72649
|
-
save: (data) => store22.save(sanitizeGlobalOptionsData2(data).data),
|
|
72650
|
-
update: (mutate) => store22.update((current) => sanitizeGlobalOptionsData2(mutate(current)).data)
|
|
72651
|
-
};
|
|
72652
|
-
}
|
|
72653
|
-
function createEmptyGlobalOptionsData2() {
|
|
72654
|
-
return {
|
|
72655
|
-
version: GLOBAL_OPTIONS_VERSION2
|
|
72656
|
-
};
|
|
72657
|
-
}
|
|
72658
|
-
function sanitizeGlobalOptionsData2(value) {
|
|
72659
|
-
if (!isRecord32(value)) {
|
|
72660
|
-
return { data: createEmptyGlobalOptionsData2(), changed: true };
|
|
72661
|
-
}
|
|
72662
|
-
if (value.version !== GLOBAL_OPTIONS_VERSION2) {
|
|
72663
|
-
return { data: createEmptyGlobalOptionsData2(), changed: true };
|
|
72664
|
-
}
|
|
72665
|
-
const data = {
|
|
72666
|
-
version: GLOBAL_OPTIONS_VERSION2,
|
|
72667
|
-
...typeof value.replaceSystemPrompt === "boolean" ? { replaceSystemPrompt: value.replaceSystemPrompt } : {},
|
|
72668
|
-
...typeof value.enableMetaphor === "boolean" ? { enableMetaphor: value.enableMetaphor } : {}
|
|
72669
|
-
};
|
|
72670
|
-
const allowedKeys = /* @__PURE__ */ new Set(["version", "replaceSystemPrompt", "enableMetaphor"]);
|
|
72671
|
-
const changed = Object.keys(value).some((key) => !allowedKeys.has(key)) || "replaceSystemPrompt" in value && typeof value.replaceSystemPrompt !== "boolean" || "enableMetaphor" in value && typeof value.enableMetaphor !== "boolean";
|
|
72672
|
-
return { data, changed };
|
|
72673
|
-
}
|
|
72674
|
-
function isRecord32(value) {
|
|
72675
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
72676
|
-
}
|
|
72677
|
-
function createGlobalOptionsService2(deps = {}) {
|
|
72678
|
-
const store22 = deps.store ?? createGlobalOptionsStore2({ dataDir: deps.dataDir });
|
|
72679
|
-
return {
|
|
72680
|
-
load: () => store22.load(),
|
|
72681
|
-
save: (data) => {
|
|
72682
|
-
store22.save(data);
|
|
72683
|
-
return store22.load();
|
|
72684
|
-
},
|
|
72685
|
-
update: (mutate) => updateGlobalOptions2(store22, mutate)
|
|
72686
|
-
};
|
|
72687
|
-
}
|
|
72688
|
-
function updateGlobalOptions2(store22, mutate) {
|
|
72689
|
-
return store22.update(mutate);
|
|
72690
|
-
}
|
|
72691
|
-
function createInfraServices2(deps = {}) {
|
|
72692
|
-
const globalOptionsService = createGlobalOptionsService2();
|
|
72693
|
-
const authService = createAuthService2({ authPath: deps.authPath ?? DEFAULT_AUTH_PATH2 });
|
|
72694
|
-
return {
|
|
72695
|
-
authService,
|
|
72696
|
-
globalOptionsService
|
|
72697
|
-
};
|
|
72698
|
-
}
|
|
72699
72919
|
var FLEET_WIKI_ENTRY_BEGIN = "<<<FLEET_WIKI_ENTRY_BEGIN";
|
|
72700
72920
|
var FLEET_WIKI_ENTRY_END = "<<<FLEET_WIKI_ENTRY_END>>>";
|
|
72701
72921
|
var FLEET_WIKI_RAW_SOURCE_BEGIN = "<<<FLEET_WIKI_RAW_SOURCE_BEGIN";
|
|
@@ -73722,7 +73942,7 @@ function stripLeadingFrontmatter(body) {
|
|
|
73722
73942
|
return stripped ? next : body;
|
|
73723
73943
|
}
|
|
73724
73944
|
function computeContentHash(content) {
|
|
73725
|
-
return
|
|
73945
|
+
return crypto5.createHash("sha256").update(content, "utf8").digest("hex").slice(0, 8);
|
|
73726
73946
|
}
|
|
73727
73947
|
function assertWithinRawDir(absolutePath, paths) {
|
|
73728
73948
|
const relative2 = path93__default.relative(paths.rawDir, absolutePath);
|
|
@@ -73935,7 +74155,7 @@ async function writeAtomic(filePath, content, paths) {
|
|
|
73935
74155
|
await ensureMemoryRoot(paths);
|
|
73936
74156
|
const tempPath = path93__default.join(
|
|
73937
74157
|
path93__default.dirname(filePath),
|
|
73938
|
-
`.tmp-${process.pid}-${Date.now()}-${
|
|
74158
|
+
`.tmp-${process.pid}-${Date.now()}-${crypto5.randomUUID()}-${os22__default.hostname()}`
|
|
73939
74159
|
);
|
|
73940
74160
|
await writeFile2(tempPath, content, "utf8");
|
|
73941
74161
|
await rename(tempPath, filePath);
|
|
@@ -76472,7 +76692,7 @@ function parseOptionalIsoDate(value) {
|
|
|
76472
76692
|
return Number.isFinite(timestamp) ? timestamp : null;
|
|
76473
76693
|
}
|
|
76474
76694
|
function hashBodyForComparison(body) {
|
|
76475
|
-
return
|
|
76695
|
+
return crypto5.createHash("sha256").update(body.replace(/\s+/g, " ").trim(), "utf8").digest("hex").slice(0, 8);
|
|
76476
76696
|
}
|
|
76477
76697
|
function hasConflictingStatuses(entries) {
|
|
76478
76698
|
const statuses = new Set(entries.map((entry) => entry.status).filter((status) => status !== "unknown"));
|
|
@@ -78654,6 +78874,418 @@ function buildWikiToolSpec(config22, usage) {
|
|
|
78654
78874
|
}
|
|
78655
78875
|
};
|
|
78656
78876
|
}
|
|
78877
|
+
var SUBAGENT_CLI_TYPES = /* @__PURE__ */ new Set(["claude", "claude-zai", "claude-kimi"]);
|
|
78878
|
+
var TASKFORCE_MIN_BACKENDS = 2;
|
|
78879
|
+
function createCarrierSettingsRouter(deps) {
|
|
78880
|
+
const controller = createStatusOverlayController(deps.registry);
|
|
78881
|
+
return async function handleCarrierSettingsRoute(context) {
|
|
78882
|
+
const { req, res, pathname } = context;
|
|
78883
|
+
if (pathname === "/carrier-settings/state") {
|
|
78884
|
+
if (req.method !== "GET") {
|
|
78885
|
+
deps.writeJson(res, 405, { error: "Method not allowed" });
|
|
78886
|
+
return true;
|
|
78887
|
+
}
|
|
78888
|
+
deps.writeJson(res, 200, buildCarrierSettingsState(deps.registry));
|
|
78889
|
+
return true;
|
|
78890
|
+
}
|
|
78891
|
+
if (pathname === "/carrier-settings/options") {
|
|
78892
|
+
if (req.method !== "GET") {
|
|
78893
|
+
deps.writeJson(res, 405, { error: "Method not allowed" });
|
|
78894
|
+
return true;
|
|
78895
|
+
}
|
|
78896
|
+
deps.writeJson(res, 200, buildCarrierSettingsOptions());
|
|
78897
|
+
return true;
|
|
78898
|
+
}
|
|
78899
|
+
const mutation = parseCarrierMutation(pathname);
|
|
78900
|
+
if (!mutation) return false;
|
|
78901
|
+
await handleCarrierMutation(req, res, deps, controller, mutation);
|
|
78902
|
+
return true;
|
|
78903
|
+
};
|
|
78904
|
+
}
|
|
78905
|
+
function buildCarrierSettingsState(registry32) {
|
|
78906
|
+
const defaultsByCarrier = buildDefaultsByCarrier(registry32);
|
|
78907
|
+
const snapshot = readCarriersSnapshot2(defaultsByCarrier);
|
|
78908
|
+
return {
|
|
78909
|
+
generation: snapshot.generation,
|
|
78910
|
+
carriers: getRegisteredOrder2(registry32).map((carrierId) => {
|
|
78911
|
+
const config22 = requireCarrierConfig(registry32, carrierId);
|
|
78912
|
+
const resolved = snapshot.carriers[carrierId] ?? fallbackResolvedState(config22);
|
|
78913
|
+
return toCarrierSettingsCarrier(registry32, config22, resolved);
|
|
78914
|
+
})
|
|
78915
|
+
};
|
|
78916
|
+
}
|
|
78917
|
+
function buildCarrierSettingsOptions() {
|
|
78918
|
+
return {
|
|
78919
|
+
cliTypes: getCliTypes().map(toCliOption),
|
|
78920
|
+
taskForceConstraints: { minBackends: TASKFORCE_MIN_BACKENDS }
|
|
78921
|
+
};
|
|
78922
|
+
}
|
|
78923
|
+
async function handleCarrierMutation(req, res, deps, controller, mutation) {
|
|
78924
|
+
const method = req.method ?? "GET";
|
|
78925
|
+
const expectedMethod = mutation.kind === "display-name" ? "PATCH" : mutation.kind === "taskforce-backend" || mutation.kind === "taskforce-all" ? method : "PUT";
|
|
78926
|
+
if (!isExpectedCarrierMethod(mutation, method, expectedMethod)) {
|
|
78927
|
+
deps.writeJson(res, 405, { error: "Method not allowed" });
|
|
78928
|
+
return;
|
|
78929
|
+
}
|
|
78930
|
+
if (!deps.isAuthorized(req)) {
|
|
78931
|
+
deps.writeJson(res, 401, { error: "unauthorized" });
|
|
78932
|
+
return;
|
|
78933
|
+
}
|
|
78934
|
+
if (!isJsonRequest(req)) {
|
|
78935
|
+
deps.writeJson(res, 415, { error: "unsupported_media_type" });
|
|
78936
|
+
return;
|
|
78937
|
+
}
|
|
78938
|
+
if (!getRegisteredCarrierConfig2(deps.registry, mutation.carrierId)) {
|
|
78939
|
+
deps.writeJson(res, 404, { error: "carrier_not_found" });
|
|
78940
|
+
return;
|
|
78941
|
+
}
|
|
78942
|
+
if (mutation.kind === "taskforce-backend" && !isCliType(mutation.cliType)) {
|
|
78943
|
+
deps.writeJson(res, 400, { error: "invalid_cli_type" });
|
|
78944
|
+
return;
|
|
78945
|
+
}
|
|
78946
|
+
try {
|
|
78947
|
+
if (mutation.kind === "cli") {
|
|
78948
|
+
const body2 = await readRequiredJsonBody(req, res, deps);
|
|
78949
|
+
if (!body2.ok) return;
|
|
78950
|
+
await mutateCarrierCli(res, deps, controller, mutation.carrierId, body2.body);
|
|
78951
|
+
return;
|
|
78952
|
+
}
|
|
78953
|
+
if (mutation.kind === "model") {
|
|
78954
|
+
const body2 = await readRequiredJsonBody(req, res, deps);
|
|
78955
|
+
if (!body2.ok) return;
|
|
78956
|
+
await mutateCarrierModel(res, deps, mutation.carrierId, body2.body);
|
|
78957
|
+
return;
|
|
78958
|
+
}
|
|
78959
|
+
if (mutation.kind === "display-name") {
|
|
78960
|
+
const body2 = await readRequiredJsonBody(req, res, deps);
|
|
78961
|
+
if (!body2.ok) return;
|
|
78962
|
+
mutateDisplayName(res, deps, mutation.carrierId, body2.body);
|
|
78963
|
+
return;
|
|
78964
|
+
}
|
|
78965
|
+
if (mutation.kind === "agent-mode") {
|
|
78966
|
+
const body2 = await readRequiredJsonBody(req, res, deps);
|
|
78967
|
+
if (!body2.ok) return;
|
|
78968
|
+
mutateAgentMode(res, deps, mutation.carrierId, body2.body);
|
|
78969
|
+
return;
|
|
78970
|
+
}
|
|
78971
|
+
if (mutation.kind === "taskforce-backend") {
|
|
78972
|
+
if (method === "DELETE") {
|
|
78973
|
+
const body3 = await readRequiredJsonBody(req, res, deps);
|
|
78974
|
+
if (!body3.ok) return;
|
|
78975
|
+
resetTaskForceModelSelection2(mutation.carrierId, mutation.cliType);
|
|
78976
|
+
refreshTaskForceConfiguredCarriers(deps.registry);
|
|
78977
|
+
writeMutationState(res, deps);
|
|
78978
|
+
return;
|
|
78979
|
+
}
|
|
78980
|
+
const body2 = await readRequiredJsonBody(req, res, deps);
|
|
78981
|
+
if (!body2.ok) return;
|
|
78982
|
+
mutateTaskForceBackend(res, deps, mutation.carrierId, mutation.cliType, body2.body);
|
|
78983
|
+
return;
|
|
78984
|
+
}
|
|
78985
|
+
const body = await readRequiredJsonBody(req, res, deps);
|
|
78986
|
+
if (!body.ok) return;
|
|
78987
|
+
resetCarrierTaskForceConfig2(mutation.carrierId);
|
|
78988
|
+
refreshTaskForceConfiguredCarriers(deps.registry);
|
|
78989
|
+
writeMutationState(res, deps);
|
|
78990
|
+
} catch (error512) {
|
|
78991
|
+
deps.writeJson(res, 400, { error: error512 instanceof Error ? error512.message : "invalid_request" });
|
|
78992
|
+
}
|
|
78993
|
+
}
|
|
78994
|
+
async function mutateCarrierCli(res, deps, controller, carrierId, body) {
|
|
78995
|
+
const cliType = readCliType(body.cliType);
|
|
78996
|
+
if (!cliType) {
|
|
78997
|
+
deps.writeJson(res, 400, { error: "invalid_cli_type" });
|
|
78998
|
+
return;
|
|
78999
|
+
}
|
|
79000
|
+
await controller.changeCliType(carrierId, cliType);
|
|
79001
|
+
if (!SUBAGENT_CLI_TYPES.has(cliType)) {
|
|
79002
|
+
const resolved = readCarriersSnapshot2(buildDefaultsByCarrier(deps.registry)).carriers[carrierId];
|
|
79003
|
+
if (resolved?.agentMode === "subagent") {
|
|
79004
|
+
const config22 = requireCarrierConfig(deps.registry, carrierId);
|
|
79005
|
+
updateCarrierAgentModeAtomically(carrierId, "cli", config22.defaultAgentMode ?? "cli");
|
|
79006
|
+
}
|
|
79007
|
+
}
|
|
79008
|
+
writeMutationState(res, deps);
|
|
79009
|
+
}
|
|
79010
|
+
async function mutateCarrierModel(res, deps, carrierId, body) {
|
|
79011
|
+
const config22 = requireCarrierConfig(deps.registry, carrierId);
|
|
79012
|
+
const cliType = resolveAgentCliType22(carrierId, config22.defaultCliType);
|
|
79013
|
+
const selection = readSelection(cliType, body);
|
|
79014
|
+
if (!selection) {
|
|
79015
|
+
deps.writeJson(res, 400, { error: "invalid_model_selection" });
|
|
79016
|
+
return;
|
|
79017
|
+
}
|
|
79018
|
+
await updateAgentCliSelection2(carrierId, cliType, selection);
|
|
79019
|
+
notifyStatusUpdate2(deps.registry);
|
|
79020
|
+
writeMutationState(res, deps);
|
|
79021
|
+
}
|
|
79022
|
+
function mutateDisplayName(res, deps, carrierId, body) {
|
|
79023
|
+
const displayName = normalizeCarrierDisplayNameInput2(body.displayName);
|
|
79024
|
+
if (displayName === null) {
|
|
79025
|
+
deps.writeJson(res, 400, { error: "invalid_display_name" });
|
|
79026
|
+
return;
|
|
79027
|
+
}
|
|
79028
|
+
updateCarrierDisplayName2(carrierId, displayName, getCarrierSourceDisplayName2(deps.registry, carrierId));
|
|
79029
|
+
notifyStatusUpdate2(deps.registry);
|
|
79030
|
+
writeMutationState(res, deps);
|
|
79031
|
+
}
|
|
79032
|
+
function mutateAgentMode(res, deps, carrierId, body) {
|
|
79033
|
+
const config22 = requireCarrierConfig(deps.registry, carrierId);
|
|
79034
|
+
const agentMode = body.agentMode;
|
|
79035
|
+
if (agentMode !== "cli" && agentMode !== "subagent") {
|
|
79036
|
+
deps.writeJson(res, 400, { error: "invalid_agent_mode" });
|
|
79037
|
+
return;
|
|
79038
|
+
}
|
|
79039
|
+
const cliType = resolveAgentCliType22(carrierId, config22.defaultCliType);
|
|
79040
|
+
if (agentMode === "subagent" && !SUBAGENT_CLI_TYPES.has(cliType)) {
|
|
79041
|
+
deps.writeJson(res, 400, { error: "subagent_unsupported" });
|
|
79042
|
+
return;
|
|
79043
|
+
}
|
|
79044
|
+
updateCarrierAgentModeAtomically(carrierId, agentMode, config22.defaultAgentMode ?? "cli");
|
|
79045
|
+
if (agentMode === "subagent") refreshTaskForceConfiguredCarriers(deps.registry);
|
|
79046
|
+
notifyStatusUpdate2(deps.registry);
|
|
79047
|
+
writeMutationState(res, deps);
|
|
79048
|
+
}
|
|
79049
|
+
function mutateTaskForceBackend(res, deps, carrierId, cliType, body) {
|
|
79050
|
+
const selection = readSelection(cliType, body);
|
|
79051
|
+
if (!selection) {
|
|
79052
|
+
deps.writeJson(res, 400, { error: "invalid_model_selection" });
|
|
79053
|
+
return;
|
|
79054
|
+
}
|
|
79055
|
+
updateTaskForceBackendAtomically(carrierId, cliType, selection);
|
|
79056
|
+
refreshTaskForceConfiguredCarriers(deps.registry);
|
|
79057
|
+
notifyStatusUpdate2(deps.registry);
|
|
79058
|
+
writeMutationState(res, deps);
|
|
79059
|
+
}
|
|
79060
|
+
function writeMutationState(res, deps) {
|
|
79061
|
+
const response = { state: buildCarrierSettingsState(deps.registry) };
|
|
79062
|
+
deps.writeJson(res, 200, response);
|
|
79063
|
+
}
|
|
79064
|
+
async function readRequiredJsonBody(req, res, deps) {
|
|
79065
|
+
const body = await deps.readJsonBody(req);
|
|
79066
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) {
|
|
79067
|
+
deps.writeJson(res, 400, { error: "invalid_json" });
|
|
79068
|
+
return { ok: false };
|
|
79069
|
+
}
|
|
79070
|
+
return { ok: true, body };
|
|
79071
|
+
}
|
|
79072
|
+
function buildDefaultsByCarrier(registry32) {
|
|
79073
|
+
return Object.fromEntries(
|
|
79074
|
+
getRegisteredOrder2(registry32).map((carrierId) => {
|
|
79075
|
+
const config22 = requireCarrierConfig(registry32, carrierId);
|
|
79076
|
+
return [carrierId, {
|
|
79077
|
+
cliType: config22.defaultCliType,
|
|
79078
|
+
...config22.defaultAgentMode ? { defaultAgentMode: config22.defaultAgentMode } : {},
|
|
79079
|
+
...buildCarrierModelDefaults2(config22, config22.defaultCliType)
|
|
79080
|
+
}];
|
|
79081
|
+
})
|
|
79082
|
+
);
|
|
79083
|
+
}
|
|
79084
|
+
function toCarrierSettingsCarrier(registry32, config22, resolved) {
|
|
79085
|
+
const cliType = resolved.agentCliType ?? config22.defaultCliType;
|
|
79086
|
+
const selection = resolved.agentCli[cliType] ?? readDefaultSelection(cliType);
|
|
79087
|
+
const taskForceBackends = toTaskForceBackends(resolved.taskforce);
|
|
79088
|
+
return {
|
|
79089
|
+
carrierId: config22.id,
|
|
79090
|
+
displayName: resolved.displayName ?? getCarrierSourceDisplayName2(registry32, config22.id),
|
|
79091
|
+
sourceDisplayName: getCarrierSourceDisplayName2(registry32, config22.id),
|
|
79092
|
+
role: config22.carrierMetadata?.title ?? config22.displayName,
|
|
79093
|
+
roleDescription: config22.carrierMetadata?.summary ?? "",
|
|
79094
|
+
...config22.carrierMetadata?.category ? { category: config22.carrierMetadata.category } : {},
|
|
79095
|
+
slot: config22.slot,
|
|
79096
|
+
cliType,
|
|
79097
|
+
defaultCliType: config22.defaultCliType,
|
|
79098
|
+
model: selection.model,
|
|
79099
|
+
...selection.effort ? { effort: selection.effort } : {},
|
|
79100
|
+
agentMode: resolved.agentMode,
|
|
79101
|
+
subagentMode: resolved.agentMode === "subagent",
|
|
79102
|
+
taskForceBackendCount: taskForceBackends.length,
|
|
79103
|
+
taskforce: { backends: taskForceBackends }
|
|
79104
|
+
};
|
|
79105
|
+
}
|
|
79106
|
+
function toTaskForceBackends(taskforce) {
|
|
79107
|
+
return TASKFORCE_CLI_TYPES2.map((cliType) => {
|
|
79108
|
+
const selection = taskforce[cliType];
|
|
79109
|
+
if (!selection) return null;
|
|
79110
|
+
return {
|
|
79111
|
+
cliType,
|
|
79112
|
+
model: selection.model,
|
|
79113
|
+
...selection.effort ? { effort: selection.effort } : {}
|
|
79114
|
+
};
|
|
79115
|
+
}).filter((backend) => backend !== null);
|
|
79116
|
+
}
|
|
79117
|
+
function toCliOption(cliType) {
|
|
79118
|
+
const provider = getProviderModels2(cliType);
|
|
79119
|
+
return {
|
|
79120
|
+
id: cliType,
|
|
79121
|
+
displayName: CLI_DISPLAY_NAMES2[cliType] ?? provider.name,
|
|
79122
|
+
supportsSubagent: SUBAGENT_CLI_TYPES.has(cliType),
|
|
79123
|
+
models: provider.models.map((model) => {
|
|
79124
|
+
const effort = getEffort2(cliType, model.modelId);
|
|
79125
|
+
return {
|
|
79126
|
+
modelId: model.modelId,
|
|
79127
|
+
name: model.name,
|
|
79128
|
+
...effort.supported ? { effort: { levels: effort.levels, default: effort.default } } : {}
|
|
79129
|
+
};
|
|
79130
|
+
}),
|
|
79131
|
+
defaultModel: provider.defaultModel ?? provider.models[0]?.modelId
|
|
79132
|
+
};
|
|
79133
|
+
}
|
|
79134
|
+
function createStatusOverlayController(registry32) {
|
|
79135
|
+
return new StatusOverlayController2({
|
|
79136
|
+
getEntries: () => [],
|
|
79137
|
+
getRegisteredOrder: () => getRegisteredOrder2(registry32),
|
|
79138
|
+
getCarrierConfig: (carrierId) => getRegisteredCarrierConfig2(registry32, carrierId),
|
|
79139
|
+
getResolvedCliType: (carrierId) => {
|
|
79140
|
+
const config22 = getRegisteredCarrierConfig2(registry32, carrierId);
|
|
79141
|
+
return config22 ? resolveAgentCliType22(carrierId, config22.defaultCliType) : void 0;
|
|
79142
|
+
},
|
|
79143
|
+
getCurrentModelSelection: (carrierId) => {
|
|
79144
|
+
return readCurrentModelSelection(registry32, carrierId);
|
|
79145
|
+
},
|
|
79146
|
+
getAvailableModels: (cliType) => {
|
|
79147
|
+
const provider = getProviderModels2(cliType);
|
|
79148
|
+
return {
|
|
79149
|
+
defaultModel: provider.defaultModel,
|
|
79150
|
+
models: provider.models.map((model) => ({
|
|
79151
|
+
modelId: model.modelId,
|
|
79152
|
+
name: model.name,
|
|
79153
|
+
effort: getEffort2(cliType, model.modelId)
|
|
79154
|
+
}))
|
|
79155
|
+
};
|
|
79156
|
+
},
|
|
79157
|
+
getEffort: (cliType, modelId) => getEffort2(cliType, modelId),
|
|
79158
|
+
getAgentCliSelection: (carrierId, cliType) => getAgentCliSelection2(carrierId, cliType),
|
|
79159
|
+
saveAgentCliSelection: saveAgentCliSelection2,
|
|
79160
|
+
updateCarrierCliType: (carrierId, cliType) => updateCarrierCliType2(registry32, carrierId),
|
|
79161
|
+
applyAgentCliTypeSelectionUpdate: applyAgentCliTypeSelectionUpdate2,
|
|
79162
|
+
refreshAgentPanel: () => void 0,
|
|
79163
|
+
syncModelConfig: () => void 0,
|
|
79164
|
+
notifyStatusUpdate: () => notifyStatusUpdate2(registry32)
|
|
79165
|
+
});
|
|
79166
|
+
}
|
|
79167
|
+
function updateCarrierAgentModeAtomically(carrierId, agentMode, defaultAgentMode) {
|
|
79168
|
+
if (agentMode === "cli") {
|
|
79169
|
+
setCarrierAgentMode2(carrierId, false, defaultAgentMode);
|
|
79170
|
+
return;
|
|
79171
|
+
}
|
|
79172
|
+
updateCarriers2((states) => {
|
|
79173
|
+
const carriers = { ...states.carriers ?? {} };
|
|
79174
|
+
const current = carriers[carrierId] ?? {};
|
|
79175
|
+
const next = { ...current };
|
|
79176
|
+
next.agentMode = "subagent";
|
|
79177
|
+
delete next.taskforce;
|
|
79178
|
+
carriers[carrierId] = next;
|
|
79179
|
+
states.carriers = carriers;
|
|
79180
|
+
});
|
|
79181
|
+
}
|
|
79182
|
+
function updateTaskForceBackendAtomically(carrierId, cliType, selection) {
|
|
79183
|
+
updateCarriers2((states) => {
|
|
79184
|
+
const carriers = { ...states.carriers ?? {} };
|
|
79185
|
+
const current = carriers[carrierId] ?? {};
|
|
79186
|
+
carriers[carrierId] = {
|
|
79187
|
+
...current,
|
|
79188
|
+
agentMode: "cli",
|
|
79189
|
+
taskforce: {
|
|
79190
|
+
...current.taskforce ?? {},
|
|
79191
|
+
[cliType]: selection
|
|
79192
|
+
}
|
|
79193
|
+
};
|
|
79194
|
+
states.carriers = carriers;
|
|
79195
|
+
});
|
|
79196
|
+
}
|
|
79197
|
+
function refreshTaskForceConfiguredCarriers(registry32) {
|
|
79198
|
+
setTaskForceConfiguredCarriers2(registry32, getConfiguredTaskForceCarrierIds2(getRegisteredOrder2(registry32)));
|
|
79199
|
+
notifyStatusUpdate2(registry32);
|
|
79200
|
+
}
|
|
79201
|
+
function readSelection(cliType, body) {
|
|
79202
|
+
if (typeof body.model !== "string") return null;
|
|
79203
|
+
const provider = getProviderModels2(cliType);
|
|
79204
|
+
if (!provider.models.some((model) => model.modelId === body.model)) return null;
|
|
79205
|
+
const effort = getEffort2(cliType, body.model);
|
|
79206
|
+
if (!effort.supported) {
|
|
79207
|
+
return body.effort === void 0 ? { model: body.model } : null;
|
|
79208
|
+
}
|
|
79209
|
+
if (typeof body.effort !== "string" || !effort.levels.includes(body.effort)) return null;
|
|
79210
|
+
return { model: body.model, effort: body.effort };
|
|
79211
|
+
}
|
|
79212
|
+
function readDefaultSelection(cliType) {
|
|
79213
|
+
const provider = getProviderModels2(cliType);
|
|
79214
|
+
const model = provider.defaultModel;
|
|
79215
|
+
const effort = getEffort2(cliType, model);
|
|
79216
|
+
return {
|
|
79217
|
+
model,
|
|
79218
|
+
...effort.supported ? { effort: effort.default } : {}
|
|
79219
|
+
};
|
|
79220
|
+
}
|
|
79221
|
+
function readCurrentModelSelection(registry32, carrierId) {
|
|
79222
|
+
const config22 = getRegisteredCarrierConfig2(registry32, carrierId);
|
|
79223
|
+
if (!config22) return void 0;
|
|
79224
|
+
const defaults = {
|
|
79225
|
+
[carrierId]: {
|
|
79226
|
+
cliType: config22.defaultCliType,
|
|
79227
|
+
...config22.defaultAgentMode ? { defaultAgentMode: config22.defaultAgentMode } : {},
|
|
79228
|
+
...buildCarrierModelDefaults2(config22, config22.defaultCliType)
|
|
79229
|
+
}
|
|
79230
|
+
};
|
|
79231
|
+
const resolved = readCarriersSnapshot2(defaults).carriers[carrierId] ?? fallbackResolvedState(config22);
|
|
79232
|
+
const cliType = resolved.agentCliType ?? config22.defaultCliType;
|
|
79233
|
+
return resolved.agentCli[cliType] ?? readDefaultSelection(cliType);
|
|
79234
|
+
}
|
|
79235
|
+
function fallbackResolvedState(config22) {
|
|
79236
|
+
return {
|
|
79237
|
+
agentMode: config22.defaultAgentMode ?? "cli",
|
|
79238
|
+
agentCliType: config22.defaultCliType,
|
|
79239
|
+
agentCli: { [config22.defaultCliType]: readDefaultSelection(config22.defaultCliType) },
|
|
79240
|
+
taskforce: {}
|
|
79241
|
+
};
|
|
79242
|
+
}
|
|
79243
|
+
function parseCarrierMutation(pathname) {
|
|
79244
|
+
const parts = pathname.split("/").filter(Boolean);
|
|
79245
|
+
if (parts[0] !== "carrier-settings" || parts[1] !== "carriers" || !parts[2]) return null;
|
|
79246
|
+
const carrierId = safeDecodeURIComponent(parts[2]);
|
|
79247
|
+
if (!carrierId) return null;
|
|
79248
|
+
if (parts.length === 4 && parts[3] === "cli") return { kind: "cli", carrierId };
|
|
79249
|
+
if (parts.length === 4 && parts[3] === "model") return { kind: "model", carrierId };
|
|
79250
|
+
if (parts.length === 4 && parts[3] === "display-name") return { kind: "display-name", carrierId };
|
|
79251
|
+
if (parts.length === 4 && parts[3] === "agent-mode") return { kind: "agent-mode", carrierId };
|
|
79252
|
+
if (parts.length === 4 && parts[3] === "taskforce") return { kind: "taskforce-all", carrierId };
|
|
79253
|
+
if (parts.length === 5 && parts[3] === "taskforce") {
|
|
79254
|
+
const cliType = safeDecodeURIComponent(parts[4] ?? "");
|
|
79255
|
+
return cliType ? { kind: "taskforce-backend", carrierId, cliType } : null;
|
|
79256
|
+
}
|
|
79257
|
+
return null;
|
|
79258
|
+
}
|
|
79259
|
+
function safeDecodeURIComponent(value) {
|
|
79260
|
+
try {
|
|
79261
|
+
return decodeURIComponent(value);
|
|
79262
|
+
} catch {
|
|
79263
|
+
return null;
|
|
79264
|
+
}
|
|
79265
|
+
}
|
|
79266
|
+
function isExpectedCarrierMethod(mutation, method, expectedMethod) {
|
|
79267
|
+
if (mutation.kind === "taskforce-backend") return method === "PUT" || method === "DELETE";
|
|
79268
|
+
if (mutation.kind === "taskforce-all") return method === "DELETE";
|
|
79269
|
+
return method === expectedMethod;
|
|
79270
|
+
}
|
|
79271
|
+
function isJsonRequest(req) {
|
|
79272
|
+
const contentType = req.headers["content-type"];
|
|
79273
|
+
return typeof contentType === "string" && contentType.toLowerCase().split(";")[0]?.trim() === "application/json";
|
|
79274
|
+
}
|
|
79275
|
+
function readCliType(value) {
|
|
79276
|
+
return typeof value === "string" && isCliType(value) ? value : null;
|
|
79277
|
+
}
|
|
79278
|
+
function isCliType(value) {
|
|
79279
|
+
return Object.prototype.hasOwnProperty.call(CLI_BACKENDS2, value);
|
|
79280
|
+
}
|
|
79281
|
+
function getCliTypes() {
|
|
79282
|
+
return Object.keys(CLI_BACKENDS2);
|
|
79283
|
+
}
|
|
79284
|
+
function requireCarrierConfig(registry32, carrierId) {
|
|
79285
|
+
const config22 = getRegisteredCarrierConfig2(registry32, carrierId);
|
|
79286
|
+
if (!config22) throw new Error(`Carrier not found: ${carrierId}`);
|
|
79287
|
+
return config22;
|
|
79288
|
+
}
|
|
78657
79289
|
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'";
|
|
78658
79290
|
var SECURITY_HEADERS = {
|
|
78659
79291
|
"content-security-policy": CONTENT_SECURITY_POLICY,
|
|
@@ -78680,7 +79312,7 @@ function safeEqual(left, right) {
|
|
|
78680
79312
|
return timingSafeEqual(leftBytes, rightBytes);
|
|
78681
79313
|
}
|
|
78682
79314
|
function workspaceHash(canonicalCwd) {
|
|
78683
|
-
return
|
|
79315
|
+
return crypto5.createHash("sha256").update(canonicalCwd).digest("hex").slice(0, 12);
|
|
78684
79316
|
}
|
|
78685
79317
|
async function canonicalizeTheaterPath(cwd) {
|
|
78686
79318
|
return canonicalizeTheaterPathSync(cwd);
|
|
@@ -79552,7 +80184,7 @@ function createCodexGateway(deps) {
|
|
|
79552
80184
|
return true;
|
|
79553
80185
|
}
|
|
79554
80186
|
if (selected.kind === "no-workspace") {
|
|
79555
|
-
if (
|
|
80187
|
+
if (isJsonRequest2(request)) {
|
|
79556
80188
|
sendJson2(response, 404, { error: "no_workspace_registered" });
|
|
79557
80189
|
return true;
|
|
79558
80190
|
}
|
|
@@ -79664,7 +80296,7 @@ function legacyWorkspacePath(url22) {
|
|
|
79664
80296
|
}
|
|
79665
80297
|
return null;
|
|
79666
80298
|
}
|
|
79667
|
-
function
|
|
80299
|
+
function isJsonRequest2(request) {
|
|
79668
80300
|
const accept = Array.isArray(request.headers.accept) ? request.headers.accept.join(",") : request.headers.accept ?? "";
|
|
79669
80301
|
const requestedWith = Array.isArray(request.headers["x-requested-with"]) ? request.headers["x-requested-with"].join(",") : request.headers["x-requested-with"] ?? "";
|
|
79670
80302
|
return accept.includes("application/json") || requestedWith.toLowerCase() === "xmlhttprequest";
|
|
@@ -79739,6 +80371,155 @@ function readRawHeaderValues(rawHeaders, name) {
|
|
|
79739
80371
|
function stripIpv6Brackets2(host) {
|
|
79740
80372
|
return host.startsWith("[") && host.endsWith("]") ? host.slice(1, -1) : host;
|
|
79741
80373
|
}
|
|
80374
|
+
var STATE_VERSION = 1;
|
|
80375
|
+
var STATE_LOCK_DIR_NAME = "state.lock";
|
|
80376
|
+
var STATE_LOCK_OWNER_FILE_NAME = "owner.json";
|
|
80377
|
+
var STATE_TEMP_PREFIX = ".state.";
|
|
80378
|
+
function createConsoleDurableStateStore(deps = {}) {
|
|
80379
|
+
const paths = deps.paths ?? createConsoleDataPaths();
|
|
80380
|
+
const createStore = deps.createStore ?? createDurableJsonStore2;
|
|
80381
|
+
return createStore({
|
|
80382
|
+
filePath: paths.stateFile,
|
|
80383
|
+
lockDir: path93__default.join(paths.dir, STATE_LOCK_DIR_NAME),
|
|
80384
|
+
lockOwnerFileName: STATE_LOCK_OWNER_FILE_NAME,
|
|
80385
|
+
now: deps.now,
|
|
80386
|
+
sanitize: sanitizeDurableConsoleState,
|
|
80387
|
+
sensitivity: "sensitive",
|
|
80388
|
+
tempCleanupPrefix: STATE_TEMP_PREFIX
|
|
80389
|
+
});
|
|
80390
|
+
}
|
|
80391
|
+
function sanitizeDurableConsoleState(value) {
|
|
80392
|
+
if (!isRecord4(value) || value.version !== STATE_VERSION) return emptyDurableConsoleState();
|
|
80393
|
+
return {
|
|
80394
|
+
version: STATE_VERSION,
|
|
80395
|
+
theaters: readTheaterRegistrations(value.theaters),
|
|
80396
|
+
operations: readDurableOperations(value.operations)
|
|
80397
|
+
};
|
|
80398
|
+
}
|
|
80399
|
+
function emptyDurableConsoleState() {
|
|
80400
|
+
return { version: STATE_VERSION, theaters: [], operations: [] };
|
|
80401
|
+
}
|
|
80402
|
+
function readProviderSessionCapture(fleetSessionId, deps = {}) {
|
|
80403
|
+
if (!isSafeCaptureId(fleetSessionId)) return null;
|
|
80404
|
+
const capturesDir = deps.capturesDir ?? createConsoleDataPaths().capturesDir;
|
|
80405
|
+
const filePath = path93__default.join(capturesDir, `${fleetSessionId}.json`);
|
|
80406
|
+
try {
|
|
80407
|
+
const parsed = JSON.parse(fs5__default.readFileSync(filePath, "utf8"));
|
|
80408
|
+
return sanitizeProviderSession(parsed);
|
|
80409
|
+
} catch {
|
|
80410
|
+
return null;
|
|
80411
|
+
}
|
|
80412
|
+
}
|
|
80413
|
+
function mergeProviderSessionCaptures(state, deps = {}) {
|
|
80414
|
+
let changed = false;
|
|
80415
|
+
const operations = state.operations.map((operation) => {
|
|
80416
|
+
if (operation.providerSession) return operation;
|
|
80417
|
+
const providerSession = readProviderSessionCapture(operation.sessionId, deps);
|
|
80418
|
+
if (!providerSession) return operation;
|
|
80419
|
+
changed = true;
|
|
80420
|
+
return { ...operation, providerSession };
|
|
80421
|
+
});
|
|
80422
|
+
return changed ? { ...state, operations } : state;
|
|
80423
|
+
}
|
|
80424
|
+
function unlinkProviderSessionCapture(fleetSessionId, deps = {}) {
|
|
80425
|
+
if (!isSafeCaptureId(fleetSessionId)) return false;
|
|
80426
|
+
const capturesDir = deps.capturesDir ?? createConsoleDataPaths().capturesDir;
|
|
80427
|
+
try {
|
|
80428
|
+
fs5__default.unlinkSync(path93__default.join(capturesDir, `${fleetSessionId}.json`));
|
|
80429
|
+
return true;
|
|
80430
|
+
} catch {
|
|
80431
|
+
return false;
|
|
80432
|
+
}
|
|
80433
|
+
}
|
|
80434
|
+
function cleanupProviderSessionCaptures(state, deps = {}) {
|
|
80435
|
+
for (const operation of state.operations) {
|
|
80436
|
+
if (operation.providerSession) unlinkProviderSessionCapture(operation.sessionId, deps);
|
|
80437
|
+
}
|
|
80438
|
+
}
|
|
80439
|
+
function readTheaterRegistrations(value) {
|
|
80440
|
+
if (!Array.isArray(value)) return [];
|
|
80441
|
+
const registrations = [];
|
|
80442
|
+
for (const item of value) {
|
|
80443
|
+
const registration = sanitizeTheaterRegistration(item);
|
|
80444
|
+
if (registration) registrations.push(registration);
|
|
80445
|
+
}
|
|
80446
|
+
return registrations;
|
|
80447
|
+
}
|
|
80448
|
+
function readDurableOperations(value) {
|
|
80449
|
+
if (!Array.isArray(value)) return [];
|
|
80450
|
+
const operations = [];
|
|
80451
|
+
for (const item of value) {
|
|
80452
|
+
const operation = sanitizeDurableOperation(item);
|
|
80453
|
+
if (operation) operations.push(operation);
|
|
80454
|
+
}
|
|
80455
|
+
return operations;
|
|
80456
|
+
}
|
|
80457
|
+
function sanitizeTheaterRegistration(value) {
|
|
80458
|
+
if (!isRecord4(value)) return null;
|
|
80459
|
+
const id = readNonEmptyString(value.id);
|
|
80460
|
+
const theaterPath = readNonEmptyString(value.path);
|
|
80461
|
+
const realpath = readNonEmptyString(value.realpath);
|
|
80462
|
+
const label = readNonEmptyString(value.label);
|
|
80463
|
+
const registeredAt = readNonEmptyString(value.registeredAt);
|
|
80464
|
+
const lastOpenedAt = readNonEmptyString(value.lastOpenedAt);
|
|
80465
|
+
if (!id || !theaterPath || !realpath || !label || !registeredAt || !lastOpenedAt) return null;
|
|
80466
|
+
return { id, path: theaterPath, realpath, label, registeredAt, lastOpenedAt };
|
|
80467
|
+
}
|
|
80468
|
+
function sanitizeDurableOperation(value) {
|
|
80469
|
+
if (!isRecord4(value)) return null;
|
|
80470
|
+
const sessionId = readNonEmptyString(value.sessionId);
|
|
80471
|
+
const theaterId = readNonEmptyString(value.theaterId);
|
|
80472
|
+
const cwd = readNonEmptyString(value.cwd);
|
|
80473
|
+
const cwdLabel = readNonEmptyString(value.cwdLabel);
|
|
80474
|
+
const sequence = readPositiveInteger(value.sequence);
|
|
80475
|
+
const createdAt = readFiniteNumber(value.createdAt);
|
|
80476
|
+
if (!sessionId || !theaterId || !cwd || !cwdLabel || sequence === null || createdAt === null) return null;
|
|
80477
|
+
const providerSession = sanitizeProviderSession(value.providerSession);
|
|
80478
|
+
return {
|
|
80479
|
+
sessionId,
|
|
80480
|
+
theaterId,
|
|
80481
|
+
cwd,
|
|
80482
|
+
cwdLabel,
|
|
80483
|
+
sequence,
|
|
80484
|
+
...readOptionalString(value.label) ? { label: readOptionalString(value.label) } : {},
|
|
80485
|
+
...readOptionalString(value.cliId) ? { cliId: readOptionalString(value.cliId) } : {},
|
|
80486
|
+
...readOptionalString(value.cliLabel) ? { cliLabel: readOptionalString(value.cliLabel) } : {},
|
|
80487
|
+
createdAt,
|
|
80488
|
+
...providerSession ? { providerSession } : {}
|
|
80489
|
+
};
|
|
80490
|
+
}
|
|
80491
|
+
function sanitizeProviderSession(value) {
|
|
80492
|
+
if (!isRecord4(value)) return null;
|
|
80493
|
+
const provider = value.provider === "claude" || value.provider === "codex" ? value.provider : null;
|
|
80494
|
+
const sessionId = readNonEmptyString(value.sessionId);
|
|
80495
|
+
const capturedAt = readNonEmptyString(value.capturedAt);
|
|
80496
|
+
if (!provider || !sessionId || !capturedAt) return null;
|
|
80497
|
+
return {
|
|
80498
|
+
provider,
|
|
80499
|
+
sessionId,
|
|
80500
|
+
...readOptionalString(value.transcriptPath) ? { transcriptPath: readOptionalString(value.transcriptPath) } : {},
|
|
80501
|
+
...readOptionalString(value.source) ? { source: readOptionalString(value.source) } : {},
|
|
80502
|
+
capturedAt
|
|
80503
|
+
};
|
|
80504
|
+
}
|
|
80505
|
+
function isRecord4(value) {
|
|
80506
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
80507
|
+
}
|
|
80508
|
+
function isSafeCaptureId(value) {
|
|
80509
|
+
return value.length > 0 && path93__default.basename(value) === value && !value.includes(path93__default.sep) && !value.includes(path93__default.posix.sep);
|
|
80510
|
+
}
|
|
80511
|
+
function readNonEmptyString(value) {
|
|
80512
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
80513
|
+
}
|
|
80514
|
+
function readOptionalString(value) {
|
|
80515
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
80516
|
+
}
|
|
80517
|
+
function readPositiveInteger(value) {
|
|
80518
|
+
return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : null;
|
|
80519
|
+
}
|
|
80520
|
+
function readFiniteNumber(value) {
|
|
80521
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
80522
|
+
}
|
|
79742
80523
|
function writeObserverEvents(req, res, workspace, store22) {
|
|
79743
80524
|
res.writeHead(200, withSecurityHeaders2({
|
|
79744
80525
|
"Content-Type": "text/event-stream",
|
|
@@ -79947,15 +80728,71 @@ function createConsoleObservabilityStore(deps = {}) {
|
|
|
79947
80728
|
terminalSessionsById.set(state.sessionId, state);
|
|
79948
80729
|
return toTerminalSessionInfo(state);
|
|
79949
80730
|
}
|
|
80731
|
+
function injectDormantOperation(operation) {
|
|
80732
|
+
const currentSequence = terminalSequenceByTheater.get(operation.theaterId) ?? 0;
|
|
80733
|
+
terminalSequenceByTheater.set(operation.theaterId, Math.max(currentSequence, operation.sequence));
|
|
80734
|
+
const state = {
|
|
80735
|
+
sessionId: operation.sessionId,
|
|
80736
|
+
cwd: operation.cwd,
|
|
80737
|
+
canonicalCwd: canonicalizeTheaterPathSync(operation.cwd),
|
|
80738
|
+
cwdLabel: operation.cwdLabel,
|
|
80739
|
+
sequence: operation.sequence,
|
|
80740
|
+
label: operation.label,
|
|
80741
|
+
cliId: operation.cliId,
|
|
80742
|
+
cliLabel: operation.cliLabel,
|
|
80743
|
+
createdAt: operation.createdAt,
|
|
80744
|
+
theaterId: operation.theaterId,
|
|
80745
|
+
terminalSessionId: operation.sessionId,
|
|
80746
|
+
status: "dormant",
|
|
80747
|
+
providerSession: operation.providerSession
|
|
80748
|
+
};
|
|
80749
|
+
terminalSessionsById.set(state.sessionId, state);
|
|
80750
|
+
return toTerminalSessionInfo(state);
|
|
80751
|
+
}
|
|
79950
80752
|
function listTerminalSessions() {
|
|
79951
80753
|
return Array.from(terminalSessionsById.values()).map(toTerminalSessionInfo).sort((a, b) => b.createdAt - a.createdAt);
|
|
79952
80754
|
}
|
|
80755
|
+
function listDurableOperations() {
|
|
80756
|
+
return Array.from(terminalSessionsById.values()).map((session) => ({
|
|
80757
|
+
sessionId: session.sessionId,
|
|
80758
|
+
theaterId: session.theaterId,
|
|
80759
|
+
cwd: session.cwd,
|
|
80760
|
+
cwdLabel: session.cwdLabel,
|
|
80761
|
+
sequence: session.sequence,
|
|
80762
|
+
...session.label ? { label: session.label } : {},
|
|
80763
|
+
...session.cliId ? { cliId: session.cliId } : {},
|
|
80764
|
+
...session.cliLabel ? { cliLabel: session.cliLabel } : {},
|
|
80765
|
+
createdAt: session.createdAt,
|
|
80766
|
+
...session.providerSession ? { providerSession: session.providerSession } : {}
|
|
80767
|
+
}));
|
|
80768
|
+
}
|
|
80769
|
+
function getDurableOperation(sessionId) {
|
|
80770
|
+
return listDurableOperations().find((operation) => operation.sessionId === sessionId) ?? null;
|
|
80771
|
+
}
|
|
80772
|
+
function updateTerminalSessionProviderSession(sessionId, providerSession) {
|
|
80773
|
+
const session = terminalSessionsById.get(sessionId);
|
|
80774
|
+
if (!session) return null;
|
|
80775
|
+
session.providerSession = providerSession;
|
|
80776
|
+
return toTerminalSessionInfo(session);
|
|
80777
|
+
}
|
|
79953
80778
|
function updateTerminalSessionStatus(sessionId, status) {
|
|
79954
80779
|
const session = terminalSessionsById.get(sessionId);
|
|
79955
80780
|
if (!session) return null;
|
|
79956
80781
|
session.status = status;
|
|
79957
80782
|
return toTerminalSessionInfo(session);
|
|
79958
80783
|
}
|
|
80784
|
+
function transitionTerminalSessionToDormant(sessionId, providerSession) {
|
|
80785
|
+
const session = terminalSessionsById.get(sessionId);
|
|
80786
|
+
if (!session) return null;
|
|
80787
|
+
const workspace = workspacesByCliRunId.get(sessionId);
|
|
80788
|
+
if (workspace?.terminalSessionId === sessionId) {
|
|
80789
|
+
removeWorkspaceIndexes(workspace);
|
|
80790
|
+
workspacesByCliRunId.delete(sessionId);
|
|
80791
|
+
}
|
|
80792
|
+
session.status = "dormant";
|
|
80793
|
+
session.providerSession = providerSession;
|
|
80794
|
+
return toTerminalSessionInfo(session);
|
|
80795
|
+
}
|
|
79959
80796
|
function renameTerminalSession(sessionId, rawLabel) {
|
|
79960
80797
|
const session = terminalSessionsById.get(sessionId);
|
|
79961
80798
|
if (!session) return null;
|
|
@@ -79995,18 +80832,23 @@ function createConsoleObservabilityStore(deps = {}) {
|
|
|
79995
80832
|
clear,
|
|
79996
80833
|
getLaunchCwd,
|
|
79997
80834
|
getTruncation,
|
|
80835
|
+
getDurableOperation,
|
|
79998
80836
|
getWorkspace,
|
|
79999
80837
|
listEvents,
|
|
80000
80838
|
listJobs,
|
|
80839
|
+
listDurableOperations,
|
|
80001
80840
|
listTerminalSessions,
|
|
80002
80841
|
listWorkspaces,
|
|
80003
80842
|
appendTerminalRuntimeEvent,
|
|
80004
80843
|
createPendingTerminalSession,
|
|
80844
|
+
injectDormantOperation,
|
|
80005
80845
|
notifySessionUpdated,
|
|
80006
80846
|
renameTerminalSession,
|
|
80007
80847
|
subscribe,
|
|
80008
80848
|
subscribeAll,
|
|
80849
|
+
updateTerminalSessionProviderSession,
|
|
80009
80850
|
updateTerminalSessionStatus,
|
|
80851
|
+
transitionTerminalSessionToDormant,
|
|
80010
80852
|
removeTerminalSession,
|
|
80011
80853
|
registerTerminalRuntimeSession,
|
|
80012
80854
|
workspaceCount: () => listWorkspaces().length
|
|
@@ -80078,7 +80920,8 @@ function toTerminalSessionInfo(state) {
|
|
|
80078
80920
|
theaterId: state.theaterId,
|
|
80079
80921
|
registrationId: state.registrationId,
|
|
80080
80922
|
cliRunId: state.cliRunId,
|
|
80081
|
-
tenantId: state.cliRunId
|
|
80923
|
+
tenantId: state.cliRunId,
|
|
80924
|
+
resumeAvailable: state.providerSession !== void 0
|
|
80082
80925
|
};
|
|
80083
80926
|
}
|
|
80084
80927
|
function pruneTenantJobs(state) {
|
|
@@ -80292,7 +81135,7 @@ function resolveConsolePath(pathname) {
|
|
|
80292
81135
|
var GRANT_ID_BYTES = 24;
|
|
80293
81136
|
var DEFAULT_GRANT_TTL_MS = 6e4;
|
|
80294
81137
|
function createFolderGrantStore(deps = {}) {
|
|
80295
|
-
const randomId = deps.randomId ?? (() =>
|
|
81138
|
+
const randomId = deps.randomId ?? (() => crypto5.randomBytes(GRANT_ID_BYTES).toString("base64url"));
|
|
80296
81139
|
const statSync52 = deps.statSync ?? fs5__default.statSync;
|
|
80297
81140
|
const ttlMs = deps.ttlMs ?? DEFAULT_GRANT_TTL_MS;
|
|
80298
81141
|
const now = deps.now ?? Date.now;
|
|
@@ -80505,6 +81348,31 @@ function buildConsoleHookCommand(entry) {
|
|
|
80505
81348
|
}
|
|
80506
81349
|
throw new Error(`Unsupported Fleet Console session hook entry extension: ${extension}`);
|
|
80507
81350
|
}
|
|
81351
|
+
function buildConsoleCaptureHookCommand(entry, cliId) {
|
|
81352
|
+
const extension = path93__default.extname(entry.entryPath);
|
|
81353
|
+
if (JAVASCRIPT_ENTRY_EXTENSIONS2.has(extension)) {
|
|
81354
|
+
return createSessionCaptureHookExec({
|
|
81355
|
+
entryPath: entry.entryPath,
|
|
81356
|
+
execPath: entry.execPath,
|
|
81357
|
+
provider: toCaptureProvider(cliId)
|
|
81358
|
+
});
|
|
81359
|
+
}
|
|
81360
|
+
if (TYPESCRIPT_ENTRY_EXTENSIONS2.has(extension)) {
|
|
81361
|
+
if (!entry.tsxLoaderPath) {
|
|
81362
|
+
throw new Error("Fleet Console capture session hook requires a tsx loader path");
|
|
81363
|
+
}
|
|
81364
|
+
return createSessionCaptureHookExec({
|
|
81365
|
+
entryPath: entry.entryPath,
|
|
81366
|
+
execPath: entry.execPath,
|
|
81367
|
+
provider: toCaptureProvider(cliId),
|
|
81368
|
+
tsxLoader: entry.tsxLoaderPath
|
|
81369
|
+
});
|
|
81370
|
+
}
|
|
81371
|
+
throw new Error(`Unsupported Fleet Console session hook entry extension: ${extension}`);
|
|
81372
|
+
}
|
|
81373
|
+
function toCaptureProvider(cliId) {
|
|
81374
|
+
return cliId === "codex" ? "codex" : "claude";
|
|
81375
|
+
}
|
|
80508
81376
|
function runCodexCommand2(command22) {
|
|
80509
81377
|
const result = spawnSync2(command22.bin, command22.args, {
|
|
80510
81378
|
cwd: command22.cwd,
|
|
@@ -80528,12 +81396,12 @@ var CONSOLE_ENTRY_PATH = fileURLToPath(import.meta.url);
|
|
|
80528
81396
|
var HOOK_ENTRY_EXTENSIONS = /* @__PURE__ */ new Set([".cjs", ".cts", ".js", ".mjs", ".mts", ".ts", ".tsx"]);
|
|
80529
81397
|
var require2 = createRequire(import.meta.url);
|
|
80530
81398
|
function createDefaultTerminalLaunchResolver(deps = {}) {
|
|
80531
|
-
const baseCwd = deps.cwd ??
|
|
80532
|
-
const env = deps.env ??
|
|
80533
|
-
const execPath = deps.execPath ??
|
|
81399
|
+
const baseCwd = deps.cwd ?? process5.cwd();
|
|
81400
|
+
const env = deps.env ?? process5.env;
|
|
81401
|
+
const execPath = deps.execPath ?? process5.execPath;
|
|
80534
81402
|
const homedir32 = deps.homedir ?? DEFAULT_TERMINAL_CWD_FALLBACK;
|
|
80535
|
-
const platform2 = deps.platform ??
|
|
80536
|
-
const entryPath = resolveHookEntryPath(deps.entryPath ??
|
|
81403
|
+
const platform2 = deps.platform ?? process5.platform;
|
|
81404
|
+
const entryPath = resolveHookEntryPath(deps.entryPath ?? process5.argv[1]);
|
|
80537
81405
|
const tsxLoaderPath = deps.tsxLoaderPath ?? resolveOptionalPackage("tsx");
|
|
80538
81406
|
const dataDir = deps.dataDir ?? getFleetDataDir2();
|
|
80539
81407
|
const infraServices = deps.infraServices ?? createInfraServices2();
|
|
@@ -80573,6 +81441,7 @@ function createDefaultTerminalLaunchResolver(deps = {}) {
|
|
|
80573
81441
|
onRuntimeSessionStart: deps.onRuntimeSessionStart,
|
|
80574
81442
|
resolveProfile,
|
|
80575
81443
|
cliId: context?.cliId,
|
|
81444
|
+
resumeSessionId: context?.resumeSessionId,
|
|
80576
81445
|
sessionId
|
|
80577
81446
|
});
|
|
80578
81447
|
};
|
|
@@ -80593,7 +81462,7 @@ function hasHookEntryExtension(entryPath) {
|
|
|
80593
81462
|
}
|
|
80594
81463
|
function startTerminalShell(launch, size) {
|
|
80595
81464
|
const { spawn: spawnPty } = require2("node-pty");
|
|
80596
|
-
const useConptyDll = resolveUseConptyDll2(
|
|
81465
|
+
const useConptyDll = resolveUseConptyDll2(process5.platform, process5.env);
|
|
80597
81466
|
return spawnPty(launch.bin, [...launch.args], {
|
|
80598
81467
|
cols: size.cols,
|
|
80599
81468
|
rows: size.rows,
|
|
@@ -80618,7 +81487,8 @@ async function createAgentCliLaunchSpec(options2) {
|
|
|
80618
81487
|
const profile = await options2.resolveProfile(options2.env, options2.cwd, {
|
|
80619
81488
|
authEnvResolver: options2.authEnvResolver,
|
|
80620
81489
|
authService: options2.infraServices.authService,
|
|
80621
|
-
cliId: options2.cliId
|
|
81490
|
+
cliId: options2.cliId,
|
|
81491
|
+
resumeSessionId: options2.resumeSessionId
|
|
80622
81492
|
});
|
|
80623
81493
|
const injectedProfile = await options2.injectProfile(profile, {
|
|
80624
81494
|
buildSystemPrompt: (injectTone) => createSystemPromptBuilder2({ carrierRuntime: agentRuntime.carrierRuntime }).build(injectTone),
|
|
@@ -80627,9 +81497,11 @@ async function createAgentCliLaunchSpec(options2) {
|
|
|
80627
81497
|
dataDir: options2.dataDir,
|
|
80628
81498
|
dedicatedMcpSession: agentRuntime.dedicatedMcpSession,
|
|
80629
81499
|
enableMetaphor: false,
|
|
81500
|
+
captureSessionHookExec: buildConsoleCaptureHookCommand(options2.hookEntry, profile.id),
|
|
80630
81501
|
hookExec: buildConsoleHookCommand(options2.hookEntry),
|
|
80631
81502
|
onCleanup: (cleanup) => cleanupStack.push(cleanup),
|
|
80632
|
-
replaceSystemPrompt:
|
|
81503
|
+
replaceSystemPrompt: false,
|
|
81504
|
+
resumeSessionId: options2.resumeSessionId,
|
|
80633
81505
|
withMarketplaceLock: withConsoleMarketplaceLock,
|
|
80634
81506
|
mcpSessionLabel: options2.sessionId
|
|
80635
81507
|
});
|
|
@@ -80663,6 +81535,7 @@ function toLaunchSpec(profile, cleanup) {
|
|
|
80663
81535
|
cwd: profile.cwd,
|
|
80664
81536
|
env: { ...profile.env },
|
|
80665
81537
|
messagePolicy: profile.messagePolicy,
|
|
81538
|
+
renameCommand: profile.renameCommand,
|
|
80666
81539
|
terminalName: profile.terminalName
|
|
80667
81540
|
};
|
|
80668
81541
|
}
|
|
@@ -80754,6 +81627,9 @@ function createTerminalSessionManager(deps) {
|
|
|
80754
81627
|
function getSessionMessagePolicy(sessionId) {
|
|
80755
81628
|
return sessions.get(sessionId)?.messagePolicy;
|
|
80756
81629
|
}
|
|
81630
|
+
function getSessionRenameCommand(sessionId) {
|
|
81631
|
+
return sessions.get(sessionId)?.renameCommand;
|
|
81632
|
+
}
|
|
80757
81633
|
function writeToSession(sessionId, data) {
|
|
80758
81634
|
const session = sessions.get(sessionId);
|
|
80759
81635
|
if (!session || typeof session.pty.write !== "function") return false;
|
|
@@ -80791,7 +81667,7 @@ function createTerminalSessionManager(deps) {
|
|
|
80791
81667
|
}
|
|
80792
81668
|
}
|
|
80793
81669
|
async function launchSession(context) {
|
|
80794
|
-
const launch = await deps.launch(context.cwd, { sessionId: context.sessionId, kind: context.kind, cliId: context.cliId });
|
|
81670
|
+
const launch = await deps.launch(context.cwd, { sessionId: context.sessionId, kind: context.kind, cliId: context.cliId, resumeSessionId: context.resumeSessionId });
|
|
80795
81671
|
let pty;
|
|
80796
81672
|
try {
|
|
80797
81673
|
pty = startShell2(launch, { cols: DEFAULT_COLS, rows: DEFAULT_ROWS2 });
|
|
@@ -80806,6 +81682,7 @@ function createTerminalSessionManager(deps) {
|
|
|
80806
81682
|
scrollback: [],
|
|
80807
81683
|
cleanup: launch.cleanup,
|
|
80808
81684
|
messagePolicy: launch.messagePolicy,
|
|
81685
|
+
renameCommand: launch.renameCommand,
|
|
80809
81686
|
activeSocket: null,
|
|
80810
81687
|
cols: DEFAULT_COLS,
|
|
80811
81688
|
rows: DEFAULT_ROWS2
|
|
@@ -80870,7 +81747,7 @@ function createTerminalSessionManager(deps) {
|
|
|
80870
81747
|
await runLaunchCleanup(session.cleanup);
|
|
80871
81748
|
}
|
|
80872
81749
|
}
|
|
80873
|
-
return { canAttach, createSession, attach, getSessionMessagePolicy, terminate, stop, writeToSession };
|
|
81750
|
+
return { canAttach, createSession, attach, getSessionMessagePolicy, getSessionRenameCommand, terminate, stop, writeToSession };
|
|
80874
81751
|
}
|
|
80875
81752
|
async function runLaunchCleanup(cleanup) {
|
|
80876
81753
|
try {
|
|
@@ -80900,7 +81777,7 @@ var DEFAULT_TICKET_TTL_MS = 1e4;
|
|
|
80900
81777
|
function createTerminalTicketRegistry(deps = {}) {
|
|
80901
81778
|
const ttlMs = deps.ttlMs ?? DEFAULT_TICKET_TTL_MS;
|
|
80902
81779
|
const now = deps.now ?? Date.now;
|
|
80903
|
-
const randomTicket = deps.randomTicket ?? (() =>
|
|
81780
|
+
const randomTicket = deps.randomTicket ?? (() => crypto5.randomBytes(32).toString("base64url"));
|
|
80904
81781
|
const tickets = /* @__PURE__ */ new Map();
|
|
80905
81782
|
function issue32(context) {
|
|
80906
81783
|
prune();
|
|
@@ -81088,6 +81965,26 @@ var TheaterRegistry = class {
|
|
|
81088
81965
|
this.#mruId = id;
|
|
81089
81966
|
return item;
|
|
81090
81967
|
}
|
|
81968
|
+
load(items) {
|
|
81969
|
+
this.restore(items);
|
|
81970
|
+
}
|
|
81971
|
+
restore(items) {
|
|
81972
|
+
const restored = /* @__PURE__ */ new Map();
|
|
81973
|
+
let mruId = null;
|
|
81974
|
+
for (const item of items) {
|
|
81975
|
+
const existing = restored.get(item.id);
|
|
81976
|
+
if (existing && existing.realpath !== item.realpath) {
|
|
81977
|
+
throw new Error("theater_id_collision");
|
|
81978
|
+
}
|
|
81979
|
+
restored.set(item.id, item);
|
|
81980
|
+
if (!mruId || item.lastOpenedAt.localeCompare(restored.get(mruId)?.lastOpenedAt ?? "") > 0) {
|
|
81981
|
+
mruId = item.id;
|
|
81982
|
+
}
|
|
81983
|
+
}
|
|
81984
|
+
this.#items.clear();
|
|
81985
|
+
for (const [id, item] of restored) this.#items.set(id, item);
|
|
81986
|
+
this.#mruId = mruId;
|
|
81987
|
+
}
|
|
81091
81988
|
get(id) {
|
|
81092
81989
|
return this.#items.get(id) ?? null;
|
|
81093
81990
|
}
|
|
@@ -81097,6 +81994,11 @@ var TheaterRegistry = class {
|
|
|
81097
81994
|
list() {
|
|
81098
81995
|
return [...this.#items.values()].sort((left, right) => right.lastOpenedAt.localeCompare(left.lastOpenedAt));
|
|
81099
81996
|
}
|
|
81997
|
+
remove(id) {
|
|
81998
|
+
const removed = this.#items.delete(id);
|
|
81999
|
+
if (this.#mruId === id) this.#mruId = this.list()[0]?.id ?? null;
|
|
82000
|
+
return removed;
|
|
82001
|
+
}
|
|
81100
82002
|
};
|
|
81101
82003
|
var FLEET_CONSOLE_PACKAGE_NAME = "@dotobokuri/fleet-console";
|
|
81102
82004
|
var UPDATE_CHECK_TTL_MS = 60 * 60 * 1e3;
|
|
@@ -81169,6 +82071,9 @@ function createConsoleServer(deps = {}) {
|
|
|
81169
82071
|
const folderGrants = createFolderGrantStore();
|
|
81170
82072
|
const infraServices = createInfraServices2();
|
|
81171
82073
|
const dataDir = deps.dataDir ?? getFleetDataDir2();
|
|
82074
|
+
initStore2(dataDir);
|
|
82075
|
+
const durablePaths = createConsoleDataPaths({ fleetDataDir: dataDir });
|
|
82076
|
+
const durableStateStore = createConsoleDurableStateStore({ paths: durablePaths });
|
|
81172
82077
|
const authEnvResolver = (cli) => resolveAuthEnv2(cli, { authService: infraServices.authService });
|
|
81173
82078
|
const ownsAgentRuntime = deps.agentRuntime === void 0;
|
|
81174
82079
|
const agentRuntime = deps.agentRuntime ?? createFleetAgentRuntimeLifecycle2({
|
|
@@ -81207,10 +82112,18 @@ function createConsoleServer(deps = {}) {
|
|
|
81207
82112
|
}),
|
|
81208
82113
|
startShell: deps.terminalStartShell,
|
|
81209
82114
|
maxSessions: deps.maxTerminalSessions,
|
|
81210
|
-
// PTY가 종료되면 콘솔 세션 목록에서도 제거해 잔존/재실행을 막는다.
|
|
81211
82115
|
onSessionExit: (sessionId) => {
|
|
81212
82116
|
pendingRuntimeSessions.delete(sessionId);
|
|
81213
|
-
observability.
|
|
82117
|
+
const operation = observability.getDurableOperation(sessionId);
|
|
82118
|
+
const providerSession = operation?.providerSession ?? readProviderSessionCapture(sessionId, { capturesDir: durablePaths.capturesDir });
|
|
82119
|
+
if (providerSession) {
|
|
82120
|
+
observability.updateTerminalSessionProviderSession(sessionId, providerSession);
|
|
82121
|
+
const dormant = observability.transitionTerminalSessionToDormant(sessionId, providerSession);
|
|
82122
|
+
if (dormant) observability.notifySessionUpdated(dormant);
|
|
82123
|
+
} else {
|
|
82124
|
+
observability.removeTerminalSession(sessionId);
|
|
82125
|
+
}
|
|
82126
|
+
persistDurableState();
|
|
81214
82127
|
}
|
|
81215
82128
|
});
|
|
81216
82129
|
const unsubscribeCarrierReminderRouter = createCarrierResultReminderRouter2({
|
|
@@ -81242,6 +82155,12 @@ function createConsoleServer(deps = {}) {
|
|
|
81242
82155
|
let activeEndpoint = null;
|
|
81243
82156
|
let agentRuntimeStopped = false;
|
|
81244
82157
|
let consoleResourcesDisposed = false;
|
|
82158
|
+
const carrierSettingsRouter = createCarrierSettingsRouter({
|
|
82159
|
+
registry: carrierRegistry,
|
|
82160
|
+
isAuthorized: isTerminalAuthorized,
|
|
82161
|
+
readJsonBody,
|
|
82162
|
+
writeJson
|
|
82163
|
+
});
|
|
81245
82164
|
function handleRequest(req, res) {
|
|
81246
82165
|
const pathname = getPathname(req);
|
|
81247
82166
|
if (pathname === "/console/codex" || pathname.startsWith("/console/codex/")) {
|
|
@@ -81269,6 +82188,11 @@ function createConsoleServer(deps = {}) {
|
|
|
81269
82188
|
runAsyncHandler(handleTerminalSessions(req, res), res);
|
|
81270
82189
|
return;
|
|
81271
82190
|
}
|
|
82191
|
+
const terminalSessionResumeMatch = pathname.match(/^\/terminal\/sessions\/([^/]+)\/resume$/);
|
|
82192
|
+
if (terminalSessionResumeMatch) {
|
|
82193
|
+
runAsyncHandler(handleTerminalSessionResume(req, res, decodeURIComponent(terminalSessionResumeMatch[1] ?? "")), res);
|
|
82194
|
+
return;
|
|
82195
|
+
}
|
|
81272
82196
|
const terminalSessionItemMatch = pathname.match(/^\/terminal\/sessions\/([^/]+)$/);
|
|
81273
82197
|
if (terminalSessionItemMatch) {
|
|
81274
82198
|
runAsyncHandler(handleTerminalSessionItem(req, res, decodeURIComponent(terminalSessionItemMatch[1] ?? "")), res);
|
|
@@ -81278,6 +82202,11 @@ function createConsoleServer(deps = {}) {
|
|
|
81278
82202
|
runAsyncHandler(handleObserverTheaters(req, res), res);
|
|
81279
82203
|
return;
|
|
81280
82204
|
}
|
|
82205
|
+
const theaterItemMatch = pathname.match(/^\/observer\/theaters\/([^/]+)$/);
|
|
82206
|
+
if (theaterItemMatch) {
|
|
82207
|
+
runAsyncHandler(handleObserverTheaterItem(req, res, decodeURIComponent(theaterItemMatch[1] ?? "")), res);
|
|
82208
|
+
return;
|
|
82209
|
+
}
|
|
81281
82210
|
const theaterSessionMatch = pathname.match(/^\/observer\/theaters\/([^/]+)\/sessions$/);
|
|
81282
82211
|
if (theaterSessionMatch) {
|
|
81283
82212
|
runAsyncHandler(handleObserverTheaterSessions(req, res, decodeURIComponent(theaterSessionMatch[1] ?? "")), res);
|
|
@@ -81291,6 +82220,10 @@ function createConsoleServer(deps = {}) {
|
|
|
81291
82220
|
handleObserverCarriers(req, res);
|
|
81292
82221
|
return;
|
|
81293
82222
|
}
|
|
82223
|
+
if (pathname === "/carrier-settings" || pathname.startsWith("/carrier-settings/")) {
|
|
82224
|
+
runAsyncBooleanHandler(carrierSettingsRouter({ req, res, pathname }), res);
|
|
82225
|
+
return;
|
|
82226
|
+
}
|
|
81294
82227
|
if (pathname === "/observer/tenants") {
|
|
81295
82228
|
handleObserverWorkspaces(req, res);
|
|
81296
82229
|
return;
|
|
@@ -81409,6 +82342,17 @@ function createConsoleServer(deps = {}) {
|
|
|
81409
82342
|
}
|
|
81410
82343
|
await createTerminalSessionForCwd(cwd, res, cliId);
|
|
81411
82344
|
}
|
|
82345
|
+
function injectRenameCommand(sessionId, label) {
|
|
82346
|
+
if (!label) return;
|
|
82347
|
+
const renameCommand = terminalSessions.getSessionRenameCommand(sessionId);
|
|
82348
|
+
if (!renameCommand) return;
|
|
82349
|
+
const safeLabel = sanitizeCarrierResultReminder2(label.replace(/[\r\n\t]+/g, " ")).trim();
|
|
82350
|
+
if (safeLabel.length === 0) return;
|
|
82351
|
+
const policy = terminalSessions.getSessionMessagePolicy(sessionId) ?? {};
|
|
82352
|
+
for (const chunk of formatCarrierResultReminderMessage2(policy, `${renameCommand} ${safeLabel}`)) {
|
|
82353
|
+
terminalSessions.writeToSession(sessionId, chunk);
|
|
82354
|
+
}
|
|
82355
|
+
}
|
|
81412
82356
|
async function handleTerminalSessionItem(req, res, sessionId) {
|
|
81413
82357
|
if (req.method !== "DELETE" && req.method !== "PATCH") {
|
|
81414
82358
|
writeJson(res, 405, { error: "Method not allowed" });
|
|
@@ -81430,13 +82374,62 @@ function createConsoleServer(deps = {}) {
|
|
|
81430
82374
|
return;
|
|
81431
82375
|
}
|
|
81432
82376
|
observability.notifySessionUpdated(updated);
|
|
82377
|
+
injectRenameCommand(sessionId, updated.label);
|
|
82378
|
+
persistDurableState();
|
|
81433
82379
|
writeJson(res, 200, updated);
|
|
81434
82380
|
return;
|
|
81435
82381
|
}
|
|
81436
|
-
|
|
81437
|
-
observability.removeTerminalSession(sessionId);
|
|
82382
|
+
forgetTerminalSession(sessionId);
|
|
81438
82383
|
writeJson(res, 200, { ok: true });
|
|
81439
82384
|
}
|
|
82385
|
+
async function handleTerminalSessionResume(req, res, sessionId) {
|
|
82386
|
+
if (req.method !== "POST") {
|
|
82387
|
+
writeJson(res, 405, { error: "Method not allowed" });
|
|
82388
|
+
return;
|
|
82389
|
+
}
|
|
82390
|
+
if (!isTerminalAuthorized(req)) {
|
|
82391
|
+
writeJson(res, 401, { error: "unauthorized" });
|
|
82392
|
+
return;
|
|
82393
|
+
}
|
|
82394
|
+
const dormantSession = observability.listTerminalSessions().find((session) => session.sessionId === sessionId && session.status === "dormant");
|
|
82395
|
+
const operation = dormantSession ? observability.getDurableOperation(sessionId) : null;
|
|
82396
|
+
if (!operation) {
|
|
82397
|
+
writeJson(res, 404, { error: "session_not_found" });
|
|
82398
|
+
return;
|
|
82399
|
+
}
|
|
82400
|
+
const cliId = readDurableAgentCliId(operation);
|
|
82401
|
+
if (!cliId) {
|
|
82402
|
+
writeJson(res, 409, { error: "resume_unavailable" });
|
|
82403
|
+
return;
|
|
82404
|
+
}
|
|
82405
|
+
const providerSession = operation.providerSession ?? readProviderSessionCapture(sessionId, { capturesDir: durablePaths.capturesDir });
|
|
82406
|
+
if (!providerSession) {
|
|
82407
|
+
writeJson(res, 409, { error: "resume_unavailable" });
|
|
82408
|
+
return;
|
|
82409
|
+
}
|
|
82410
|
+
observability.updateTerminalSessionProviderSession(sessionId, providerSession);
|
|
82411
|
+
const starting = observability.updateTerminalSessionStatus(sessionId, "starting");
|
|
82412
|
+
if (starting) observability.notifySessionUpdated(starting);
|
|
82413
|
+
try {
|
|
82414
|
+
await terminalSessions.createSession({ sessionId, cwd: operation.cwd, cliId, resumeSessionId: providerSession.sessionId });
|
|
82415
|
+
const runtimeSession = pendingRuntimeSessions.get(sessionId);
|
|
82416
|
+
pendingRuntimeSessions.delete(sessionId);
|
|
82417
|
+
const resumed = runtimeSession ? observability.registerTerminalRuntimeSession(runtimeSession) ?? starting : observability.updateTerminalSessionStatus(sessionId, "terminal-only") ?? starting;
|
|
82418
|
+
if (!resumed) {
|
|
82419
|
+
writeJson(res, 404, { error: "session_not_found" });
|
|
82420
|
+
return;
|
|
82421
|
+
}
|
|
82422
|
+
observability.notifySessionUpdated(resumed);
|
|
82423
|
+
persistDurableState();
|
|
82424
|
+
writeJson(res, 200, resumed);
|
|
82425
|
+
} catch {
|
|
82426
|
+
pendingRuntimeSessions.delete(sessionId);
|
|
82427
|
+
const reverted = observability.updateTerminalSessionStatus(sessionId, "dormant");
|
|
82428
|
+
if (reverted) observability.notifySessionUpdated(reverted);
|
|
82429
|
+
persistDurableState();
|
|
82430
|
+
writeJson(res, 503, { error: "terminal_unavailable" });
|
|
82431
|
+
}
|
|
82432
|
+
}
|
|
81440
82433
|
async function handleObserverTheaters(req, res) {
|
|
81441
82434
|
if (req.method === "GET") {
|
|
81442
82435
|
writeJson(res, 200, { theaters: listTheaterInfos(), agentClis: getAgentCliMetadata2() });
|
|
@@ -81469,8 +82462,28 @@ function createConsoleServer(deps = {}) {
|
|
|
81469
82462
|
console.warn(`[fleet-console] Codex workspace registration skipped for Theater ${theater.id}: ${error512 instanceof Error ? error512.message : String(error512)}`);
|
|
81470
82463
|
}
|
|
81471
82464
|
}
|
|
82465
|
+
persistDurableState();
|
|
81472
82466
|
writeJson(res, 200, toTheaterInfo(theater, hasWiki));
|
|
81473
82467
|
}
|
|
82468
|
+
async function handleObserverTheaterItem(req, res, theaterId) {
|
|
82469
|
+
if (req.method !== "DELETE") {
|
|
82470
|
+
writeJson(res, 405, { error: "Method not allowed" });
|
|
82471
|
+
return;
|
|
82472
|
+
}
|
|
82473
|
+
if (!isTerminalAuthorized(req)) {
|
|
82474
|
+
writeJson(res, 401, { error: "unauthorized" });
|
|
82475
|
+
return;
|
|
82476
|
+
}
|
|
82477
|
+
const operations = observability.listDurableOperations().filter((operation) => operation.theaterId === theaterId);
|
|
82478
|
+
const removed = theaters.remove(theaterId);
|
|
82479
|
+
if (!removed) {
|
|
82480
|
+
writeJson(res, 404, { error: "theater_not_found" });
|
|
82481
|
+
return;
|
|
82482
|
+
}
|
|
82483
|
+
for (const operation of operations) forgetTerminalSession(operation.sessionId, { persist: false });
|
|
82484
|
+
persistDurableState();
|
|
82485
|
+
writeJson(res, 200, { ok: true });
|
|
82486
|
+
}
|
|
81474
82487
|
async function handleObserverTheaterSessions(req, res, theaterId) {
|
|
81475
82488
|
if (req.method !== "POST") {
|
|
81476
82489
|
writeJson(res, 405, { error: "Method not allowed" });
|
|
@@ -81491,7 +82504,7 @@ function createConsoleServer(deps = {}) {
|
|
|
81491
82504
|
await createTerminalSessionForCwd(theater.path, res, cliId);
|
|
81492
82505
|
}
|
|
81493
82506
|
async function createTerminalSessionForCwd(cwd, res, cliId) {
|
|
81494
|
-
const sessionId =
|
|
82507
|
+
const sessionId = crypto5.randomUUID();
|
|
81495
82508
|
const session = observability.createPendingTerminalSession({ sessionId, cwd, cliId });
|
|
81496
82509
|
try {
|
|
81497
82510
|
await terminalSessions.createSession({ sessionId, cwd, cliId });
|
|
@@ -81499,6 +82512,7 @@ function createConsoleServer(deps = {}) {
|
|
|
81499
82512
|
pendingRuntimeSessions.delete(sessionId);
|
|
81500
82513
|
const created = runtimeSession ? observability.registerTerminalRuntimeSession(runtimeSession) ?? session : observability.updateTerminalSessionStatus(sessionId, "terminal-only") ?? session;
|
|
81501
82514
|
observability.notifySessionUpdated(created);
|
|
82515
|
+
persistDurableState();
|
|
81502
82516
|
writeJson(res, 200, created);
|
|
81503
82517
|
} catch (error512) {
|
|
81504
82518
|
pendingRuntimeSessions.delete(sessionId);
|
|
@@ -81572,6 +82586,13 @@ function createConsoleServer(deps = {}) {
|
|
|
81572
82586
|
function listTheaterInfos() {
|
|
81573
82587
|
return theaters.list().map((theater) => toTheaterInfo(theater, codex.getWorkspace(theater.id) !== null));
|
|
81574
82588
|
}
|
|
82589
|
+
function forgetTerminalSession(sessionId, options2 = {}) {
|
|
82590
|
+
terminalSessions.terminate(sessionId);
|
|
82591
|
+
pendingRuntimeSessions.delete(sessionId);
|
|
82592
|
+
observability.removeTerminalSession(sessionId);
|
|
82593
|
+
unlinkProviderSessionCapture(sessionId, { capturesDir: durablePaths.capturesDir });
|
|
82594
|
+
if (options2.persist !== false) persistDurableState();
|
|
82595
|
+
}
|
|
81575
82596
|
function toTheaterInfo(theater, hasWiki) {
|
|
81576
82597
|
return {
|
|
81577
82598
|
id: theater.id,
|
|
@@ -81634,12 +82655,69 @@ function createConsoleServer(deps = {}) {
|
|
|
81634
82655
|
terminalUpgrade.close();
|
|
81635
82656
|
currentLock?.release();
|
|
81636
82657
|
}
|
|
82658
|
+
function rehydrateDurableState() {
|
|
82659
|
+
let state;
|
|
82660
|
+
try {
|
|
82661
|
+
state = durableStateStore.load();
|
|
82662
|
+
theaters.restore(state.theaters);
|
|
82663
|
+
} catch (error512) {
|
|
82664
|
+
console.warn(`[fleet-console] Durable state restore skipped: ${error512 instanceof Error ? error512.message : String(error512)}`);
|
|
82665
|
+
state = emptyDurableConsoleState();
|
|
82666
|
+
theaters.restore([]);
|
|
82667
|
+
}
|
|
82668
|
+
const merged = mergeProviderSessionCaptures(state, { capturesDir: durablePaths.capturesDir });
|
|
82669
|
+
syncProviderSessionsToObservability(merged);
|
|
82670
|
+
const restorable = {
|
|
82671
|
+
...merged,
|
|
82672
|
+
operations: merged.operations.filter((operation) => operation.providerSession)
|
|
82673
|
+
};
|
|
82674
|
+
if (merged !== state || restorable.operations.length !== merged.operations.length) {
|
|
82675
|
+
try {
|
|
82676
|
+
durableStateStore.save(restorable);
|
|
82677
|
+
cleanupProviderSessionCaptures(restorable, { capturesDir: durablePaths.capturesDir });
|
|
82678
|
+
} catch (error512) {
|
|
82679
|
+
console.warn(`[fleet-console] Durable state capture merge was not persisted: ${error512 instanceof Error ? error512.message : String(error512)}`);
|
|
82680
|
+
}
|
|
82681
|
+
} else {
|
|
82682
|
+
cleanupProviderSessionCaptures(restorable, { capturesDir: durablePaths.capturesDir });
|
|
82683
|
+
}
|
|
82684
|
+
for (const operation of restorable.operations) {
|
|
82685
|
+
if (theaters.get(operation.theaterId)) observability.injectDormantOperation(operation);
|
|
82686
|
+
}
|
|
82687
|
+
}
|
|
82688
|
+
function persistDurableState() {
|
|
82689
|
+
try {
|
|
82690
|
+
const state = mergeProviderSessionCaptures({
|
|
82691
|
+
version: 1,
|
|
82692
|
+
theaters: theaters.list(),
|
|
82693
|
+
operations: observability.listDurableOperations()
|
|
82694
|
+
}, { capturesDir: durablePaths.capturesDir });
|
|
82695
|
+
syncProviderSessionsToObservability(state);
|
|
82696
|
+
const operationsWithProviderSession = state.operations.filter((operation) => operation.providerSession);
|
|
82697
|
+
durableStateStore.save({
|
|
82698
|
+
version: state.version,
|
|
82699
|
+
theaters: state.theaters,
|
|
82700
|
+
// 대화 없는 빈 Operation 드롭은 rehydrate에서 capture 머지 뒤에만 수행한다.
|
|
82701
|
+
// create 시점의 메타데이터를 먼저 남겨야 이후 도착한 capture 파일이 재시작 때 병합될 수 있다.
|
|
82702
|
+
operations: state.operations
|
|
82703
|
+
});
|
|
82704
|
+
cleanupProviderSessionCaptures({ ...state, operations: operationsWithProviderSession }, { capturesDir: durablePaths.capturesDir });
|
|
82705
|
+
} catch (error512) {
|
|
82706
|
+
console.warn(`[fleet-console] Durable state save failed: ${error512 instanceof Error ? error512.message : String(error512)}`);
|
|
82707
|
+
}
|
|
82708
|
+
}
|
|
82709
|
+
function syncProviderSessionsToObservability(state) {
|
|
82710
|
+
for (const operation of state.operations) {
|
|
82711
|
+
if (operation.providerSession) observability.updateTerminalSessionProviderSession(operation.sessionId, operation.providerSession);
|
|
82712
|
+
}
|
|
82713
|
+
}
|
|
81637
82714
|
return {
|
|
81638
82715
|
host,
|
|
81639
82716
|
port,
|
|
81640
82717
|
async start(lockPaths) {
|
|
81641
82718
|
if (server && lockHandle) return lockHandle.payload.endpoint;
|
|
81642
82719
|
try {
|
|
82720
|
+
rehydrateDurableState();
|
|
81643
82721
|
await new Promise((resolve2, reject) => {
|
|
81644
82722
|
const srv = createHttpServer(handleRequest, terminalUpgrade);
|
|
81645
82723
|
srv.once("error", reject);
|
|
@@ -81722,6 +82800,14 @@ function resolveCarrierEventOrigin(event, jobOriginById) {
|
|
|
81722
82800
|
function queueOriginCleanup(jobId, jobOriginById) {
|
|
81723
82801
|
queueMicrotask(() => jobOriginById.delete(jobId));
|
|
81724
82802
|
}
|
|
82803
|
+
function readDurableAgentCliId(operation) {
|
|
82804
|
+
if (!operation.cliId) return null;
|
|
82805
|
+
try {
|
|
82806
|
+
return parseAgentCliId2(operation.cliId) ?? null;
|
|
82807
|
+
} catch {
|
|
82808
|
+
return null;
|
|
82809
|
+
}
|
|
82810
|
+
}
|
|
81725
82811
|
function createHttpServer(handler, terminalUpgrade) {
|
|
81726
82812
|
const srv = http2.createServer(handler);
|
|
81727
82813
|
srv.timeout = SERVER_TIMEOUT_MS;
|
|
@@ -81839,6 +82925,78 @@ function isAllowedTerminalOrigin(req, expectedPort) {
|
|
|
81839
82925
|
if (origin === void 0) return true;
|
|
81840
82926
|
return origin === `http://127.0.0.1:${expectedPort}`;
|
|
81841
82927
|
}
|
|
82928
|
+
var CAPTURE_TEMP_PREFIX = ".capture.";
|
|
82929
|
+
async function runCaptureSessionHook(provider, env = process5.env) {
|
|
82930
|
+
return captureSession({
|
|
82931
|
+
diagnostics: process5.stderr,
|
|
82932
|
+
env,
|
|
82933
|
+
input: await readStdin(),
|
|
82934
|
+
provider
|
|
82935
|
+
});
|
|
82936
|
+
}
|
|
82937
|
+
function captureSession(options2) {
|
|
82938
|
+
try {
|
|
82939
|
+
return captureSessionStrict(options2);
|
|
82940
|
+
} catch (error512) {
|
|
82941
|
+
options2.diagnostics?.write(`[fleet-console] capture-session skipped: ${error512 instanceof Error ? error512.message : String(error512)}
|
|
82942
|
+
`);
|
|
82943
|
+
return null;
|
|
82944
|
+
}
|
|
82945
|
+
}
|
|
82946
|
+
function captureSessionStrict(options2) {
|
|
82947
|
+
const provider = parseProvider(options2.provider);
|
|
82948
|
+
const fleetSessionId = readFleetSessionId(options2.env ?? process5.env);
|
|
82949
|
+
const input = parseHookInput(options2.input ?? "");
|
|
82950
|
+
const providerSession = toProviderSession(provider, input, options2.now ?? (() => /* @__PURE__ */ new Date()));
|
|
82951
|
+
const capturesDir = (options2.paths ?? createConsoleDataPaths()).capturesDir;
|
|
82952
|
+
const finalPath = path93__default.join(capturesDir, `${fleetSessionId}.json`);
|
|
82953
|
+
const tempPath = path93__default.join(capturesDir, `${CAPTURE_TEMP_PREFIX}${fleetSessionId}.${process5.pid}.${Date.now()}.tmp`);
|
|
82954
|
+
fs5__default.mkdirSync(capturesDir, { recursive: true, mode: 448 });
|
|
82955
|
+
fs5__default.writeFileSync(tempPath, `${JSON.stringify(providerSession, null, 2)}
|
|
82956
|
+
`, { mode: 384 });
|
|
82957
|
+
fs5__default.renameSync(tempPath, finalPath);
|
|
82958
|
+
return { path: finalPath, providerSession };
|
|
82959
|
+
}
|
|
82960
|
+
function parseProvider(value) {
|
|
82961
|
+
if (value === "claude" || value === "codex") return value;
|
|
82962
|
+
throw new Error("invalid_provider");
|
|
82963
|
+
}
|
|
82964
|
+
function readFleetSessionId(env) {
|
|
82965
|
+
const value = env.FLEET_CONSOLE_SESSION_ID;
|
|
82966
|
+
if (!value) throw new Error("missing_fleet_session_id");
|
|
82967
|
+
if (path93__default.basename(value) !== value || value.includes(path93__default.sep) || value.includes(path93__default.posix.sep)) {
|
|
82968
|
+
throw new Error("invalid_fleet_session_id");
|
|
82969
|
+
}
|
|
82970
|
+
return value;
|
|
82971
|
+
}
|
|
82972
|
+
function parseHookInput(input) {
|
|
82973
|
+
try {
|
|
82974
|
+
const parsed = JSON.parse(input);
|
|
82975
|
+
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) return parsed;
|
|
82976
|
+
} catch {
|
|
82977
|
+
}
|
|
82978
|
+
throw new Error("invalid_hook_input");
|
|
82979
|
+
}
|
|
82980
|
+
function toProviderSession(provider, input, now) {
|
|
82981
|
+
if (typeof input.session_id !== "string" || input.session_id.length === 0) throw new Error("missing_provider_session_id");
|
|
82982
|
+
return {
|
|
82983
|
+
provider,
|
|
82984
|
+
sessionId: input.session_id,
|
|
82985
|
+
...typeof input.transcript_path === "string" && input.transcript_path.length > 0 ? { transcriptPath: input.transcript_path } : {},
|
|
82986
|
+
...typeof input.source === "string" && input.source.length > 0 ? { source: input.source } : {},
|
|
82987
|
+
capturedAt: now().toISOString()
|
|
82988
|
+
};
|
|
82989
|
+
}
|
|
82990
|
+
function readStdin() {
|
|
82991
|
+
return new Promise((resolve2, reject) => {
|
|
82992
|
+
const chunks = [];
|
|
82993
|
+
process5.stdin.on("data", (chunk) => {
|
|
82994
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
82995
|
+
});
|
|
82996
|
+
process5.stdin.on("error", reject);
|
|
82997
|
+
process5.stdin.on("end", () => resolve2(Buffer.concat(chunks).toString("utf8")));
|
|
82998
|
+
});
|
|
82999
|
+
}
|
|
81842
83000
|
function createConsoleStalePolicy(deps = {}) {
|
|
81843
83001
|
const fsImpl = deps.fs ?? fs5__default;
|
|
81844
83002
|
function isBuildStale(lock, buildFile) {
|
|
@@ -81854,7 +83012,7 @@ function createConsoleStalePolicy(deps = {}) {
|
|
|
81854
83012
|
var FIXED_HOST = "127.0.0.1";
|
|
81855
83013
|
var HELP_BANNER_INDENT = " ";
|
|
81856
83014
|
var DEFAULT_HELP_RELEASE = "local";
|
|
81857
|
-
var CONSOLE_HOOK_COMMANDS = /* @__PURE__ */ new Set(["subagents-context"]);
|
|
83015
|
+
var CONSOLE_HOOK_COMMANDS = /* @__PURE__ */ new Set(["capture-session", "subagents-context"]);
|
|
81858
83016
|
function parseConsoleCliMode(argv2) {
|
|
81859
83017
|
if (argv2.length === 0) return "start";
|
|
81860
83018
|
const [first, ...rest] = argv2;
|
|
@@ -81881,10 +83039,12 @@ Run 'fleet console --help' for usage.`);
|
|
|
81881
83039
|
}
|
|
81882
83040
|
function parseConsoleHookCommand(argv2) {
|
|
81883
83041
|
const [commandName, ...rest] = argv2;
|
|
81884
|
-
if (!commandName || !CONSOLE_HOOK_COMMANDS.has(commandName)
|
|
83042
|
+
if (!commandName || !CONSOLE_HOOK_COMMANDS.has(commandName)) {
|
|
81885
83043
|
throw new Error("Unknown fleet-console hook command");
|
|
81886
83044
|
}
|
|
81887
|
-
return "subagents-context";
|
|
83045
|
+
if (commandName === "subagents-context" && rest.length === 0) return { command: "subagents-context" };
|
|
83046
|
+
if (commandName === "capture-session" && rest.length === 1 && rest[0]) return { command: "capture-session", provider: rest[0] };
|
|
83047
|
+
throw new Error("Unknown fleet-console hook command");
|
|
81888
83048
|
}
|
|
81889
83049
|
function buildConsoleHelpText(options2 = {}) {
|
|
81890
83050
|
const colorEnabled = resolveColorEnabled2(options2);
|
|
@@ -81946,8 +83106,8 @@ function buildWikiHelpText(options2 = {}) {
|
|
|
81946
83106
|
return colorEnabled ? text : stripAnsi2(text);
|
|
81947
83107
|
}
|
|
81948
83108
|
function createConsoleDaemonLifecycle(deps = {}) {
|
|
81949
|
-
const env = deps.env ??
|
|
81950
|
-
const execPath = deps.execPath ??
|
|
83109
|
+
const env = deps.env ?? process5.env;
|
|
83110
|
+
const execPath = deps.execPath ?? process5.execPath;
|
|
81951
83111
|
const serverModulePath = deps.serverModulePath ?? resolveDefaultServerModulePath();
|
|
81952
83112
|
const spawnDetached = deps.spawnDetached ?? ((bin, args, options2) => {
|
|
81953
83113
|
spawn3(bin, [...args], options2).unref();
|
|
@@ -81961,10 +83121,10 @@ function createConsoleDaemonLifecycle(deps = {}) {
|
|
|
81961
83121
|
const server = createConsoleServer();
|
|
81962
83122
|
await server.start(paths);
|
|
81963
83123
|
await new Promise((resolve2) => {
|
|
81964
|
-
|
|
83124
|
+
process5.once("SIGTERM", () => {
|
|
81965
83125
|
void server.stop().finally(resolve2);
|
|
81966
83126
|
});
|
|
81967
|
-
|
|
83127
|
+
process5.once("SIGINT", () => {
|
|
81968
83128
|
void server.stop().finally(resolve2);
|
|
81969
83129
|
});
|
|
81970
83130
|
});
|
|
@@ -81978,14 +83138,14 @@ function createConsoleDaemonLifecycle(deps = {}) {
|
|
|
81978
83138
|
const payload = readTrustedLock();
|
|
81979
83139
|
if (!payload) return;
|
|
81980
83140
|
try {
|
|
81981
|
-
|
|
83141
|
+
process5.kill(payload.pid, "SIGTERM");
|
|
81982
83142
|
} catch (err) {
|
|
81983
83143
|
if (err.code !== "ESRCH") throw err;
|
|
81984
83144
|
}
|
|
81985
83145
|
await sleep(200);
|
|
81986
83146
|
try {
|
|
81987
|
-
|
|
81988
|
-
|
|
83147
|
+
process5.kill(payload.pid, 0);
|
|
83148
|
+
process5.kill(payload.pid, "SIGKILL");
|
|
81989
83149
|
} catch (err) {
|
|
81990
83150
|
if (err.code !== "ESRCH") throw err;
|
|
81991
83151
|
}
|
|
@@ -82103,49 +83263,51 @@ async function runConsoleRestart(deps = {}) {
|
|
|
82103
83263
|
return openFleetConsole({ lifecycle, openBrowser: deps.openBrowser });
|
|
82104
83264
|
}
|
|
82105
83265
|
async function main() {
|
|
82106
|
-
if (
|
|
83266
|
+
if (process5.argv[2] === "serve") {
|
|
82107
83267
|
await createConsoleDaemonLifecycle().runServer();
|
|
82108
83268
|
return;
|
|
82109
83269
|
}
|
|
82110
|
-
if (
|
|
82111
|
-
parseConsoleHookCommand(
|
|
82112
|
-
{
|
|
82113
|
-
|
|
83270
|
+
if (process5.argv[2] === "hook") {
|
|
83271
|
+
const hookCommand = parseConsoleHookCommand(process5.argv.slice(3));
|
|
83272
|
+
if (hookCommand.command === "subagents-context") {
|
|
83273
|
+
process5.stdout.write(`${runSubagentsContextHook(process5.env)}
|
|
82114
83274
|
`);
|
|
82115
83275
|
return;
|
|
82116
83276
|
}
|
|
83277
|
+
await runCaptureSessionHook(hookCommand.provider, process5.env);
|
|
83278
|
+
return;
|
|
82117
83279
|
}
|
|
82118
|
-
if (
|
|
82119
|
-
await mainWiki(
|
|
83280
|
+
if (process5.argv[2] === "codex") {
|
|
83281
|
+
await mainWiki(process5.argv.slice(3));
|
|
82120
83282
|
return;
|
|
82121
83283
|
}
|
|
82122
|
-
const mode = parseConsoleCliMode(
|
|
83284
|
+
const mode = parseConsoleCliMode(process5.argv.slice(2));
|
|
82123
83285
|
if (mode === "help") {
|
|
82124
|
-
|
|
83286
|
+
process5.stdout.write(`${buildConsoleHelpText({ env: process5.env, isTTY: process5.stdout.isTTY })}
|
|
82125
83287
|
`);
|
|
82126
83288
|
return;
|
|
82127
83289
|
}
|
|
82128
83290
|
if (mode === "status") {
|
|
82129
|
-
|
|
83291
|
+
process5.stdout.write(`${await runConsoleStatus()}
|
|
82130
83292
|
`);
|
|
82131
83293
|
return;
|
|
82132
83294
|
}
|
|
82133
83295
|
if (mode === "stop") {
|
|
82134
|
-
|
|
83296
|
+
process5.stdout.write(`${await runConsoleStop()}
|
|
82135
83297
|
`);
|
|
82136
83298
|
return;
|
|
82137
83299
|
}
|
|
82138
83300
|
if (mode === "restart") {
|
|
82139
83301
|
await runConsoleRestart();
|
|
82140
|
-
|
|
83302
|
+
process5.stdout.write("Fleet Console restarted.\n");
|
|
82141
83303
|
return;
|
|
82142
83304
|
}
|
|
82143
83305
|
await openFleetConsole();
|
|
82144
|
-
|
|
83306
|
+
process5.stdout.write("Fleet Console opened.\n");
|
|
82145
83307
|
}
|
|
82146
|
-
async function mainWiki(argv2 =
|
|
83308
|
+
async function mainWiki(argv2 = process5.argv.slice(2)) {
|
|
82147
83309
|
if (argv2.includes("--help") || argv2.includes("-h")) {
|
|
82148
|
-
|
|
83310
|
+
process5.stdout.write(`${buildWikiHelpText({ env: process5.env, isTTY: process5.stdout.isTTY })}
|
|
82149
83311
|
`);
|
|
82150
83312
|
return;
|
|
82151
83313
|
}
|
|
@@ -82157,19 +83319,19 @@ async function mainWiki(argv2 = process4.argv.slice(2)) {
|
|
|
82157
83319
|
if (unsupported.length > 0) {
|
|
82158
83320
|
throw new Error(`Unknown fleet wiki option: ${unsupported[0]}`);
|
|
82159
83321
|
}
|
|
82160
|
-
await openFleetWikiWorkspace({ cwd:
|
|
83322
|
+
await openFleetWikiWorkspace({ cwd: process5.cwd() });
|
|
82161
83323
|
}
|
|
82162
83324
|
function resolveDefaultServerModulePath() {
|
|
82163
83325
|
const builtPath = new URL("../dist/cli.mjs", import.meta.url).pathname;
|
|
82164
83326
|
if (fs5__default.existsSync(builtPath)) return builtPath;
|
|
82165
83327
|
return fileURLToPath(import.meta.url);
|
|
82166
83328
|
}
|
|
82167
|
-
var isDirectRun =
|
|
83329
|
+
var isDirectRun = process5.argv[1] && path93__default.resolve(process5.argv[1]) === fileURLToPath(import.meta.url);
|
|
82168
83330
|
if (isDirectRun) {
|
|
82169
83331
|
await main().catch((error512) => {
|
|
82170
|
-
|
|
83332
|
+
process5.stderr.write(`${error512 instanceof Error ? error512.message : String(error512)}
|
|
82171
83333
|
`);
|
|
82172
|
-
|
|
83334
|
+
process5.exitCode = 1;
|
|
82173
83335
|
});
|
|
82174
83336
|
}
|
|
82175
83337
|
|
|
@@ -82997,7 +84159,7 @@ import { join as join11 } from "path";
|
|
|
82997
84159
|
import path63 from "path";
|
|
82998
84160
|
import path12 from "path";
|
|
82999
84161
|
import path53 from "path";
|
|
83000
|
-
import
|
|
84162
|
+
import crypto6 from "crypto";
|
|
83001
84163
|
import { mkdir as mkdir4, readdir as readdir2, readFile as readFile3, rename as rename2, rm as rm2, stat as stat2, writeFile as writeFile22 } from "fs/promises";
|
|
83002
84164
|
import os6 from "os";
|
|
83003
84165
|
import path43 from "path";
|
|
@@ -84050,7 +85212,7 @@ function stripLeadingFrontmatter2(body) {
|
|
|
84050
85212
|
return stripped ? next : body;
|
|
84051
85213
|
}
|
|
84052
85214
|
function computeContentHash2(content) {
|
|
84053
|
-
return
|
|
85215
|
+
return crypto6.createHash("sha256").update(content, "utf8").digest("hex").slice(0, 8);
|
|
84054
85216
|
}
|
|
84055
85217
|
function assertWithinRawDir2(absolutePath, paths) {
|
|
84056
85218
|
const relative2 = path43.relative(paths.rawDir, absolutePath);
|
|
@@ -84263,7 +85425,7 @@ async function writeAtomic2(filePath, content, paths) {
|
|
|
84263
85425
|
await ensureMemoryRoot2(paths);
|
|
84264
85426
|
const tempPath = path43.join(
|
|
84265
85427
|
path43.dirname(filePath),
|
|
84266
|
-
`.tmp-${process.pid}-${Date.now()}-${
|
|
85428
|
+
`.tmp-${process.pid}-${Date.now()}-${crypto6.randomUUID()}-${os6.hostname()}`
|
|
84267
85429
|
);
|
|
84268
85430
|
await writeFile22(tempPath, content, "utf8");
|
|
84269
85431
|
await rename2(tempPath, filePath);
|
|
@@ -90884,7 +92046,7 @@ async function runApp(options2 = {}) {
|
|
|
90884
92046
|
defaults: {
|
|
90885
92047
|
cliId: getDefaultAgentCliId(),
|
|
90886
92048
|
enableMetaphor: false,
|
|
90887
|
-
replaceSystemPrompt:
|
|
92049
|
+
replaceSystemPrompt: false
|
|
90888
92050
|
},
|
|
90889
92051
|
env: process.env,
|
|
90890
92052
|
globalOptionsService: runtime.infraServices.globalOptionsService,
|
|
@@ -91269,11 +92431,11 @@ function canReadCarrierState2(filePath) {
|
|
|
91269
92431
|
}
|
|
91270
92432
|
}
|
|
91271
92433
|
function isReadableCarrierStateRoot2(value) {
|
|
91272
|
-
if (!
|
|
92434
|
+
if (!isRecord5(value)) return false;
|
|
91273
92435
|
const carriers = value.carriers;
|
|
91274
|
-
return carriers === void 0 ||
|
|
92436
|
+
return carriers === void 0 || isRecord5(carriers);
|
|
91275
92437
|
}
|
|
91276
|
-
function
|
|
92438
|
+
function isRecord5(value) {
|
|
91277
92439
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
91278
92440
|
}
|
|
91279
92441
|
|
|
@@ -91314,7 +92476,7 @@ async function runNativeApp(options2 = {}) {
|
|
|
91314
92476
|
defaults: {
|
|
91315
92477
|
cliId: getDefaultAgentCliId(),
|
|
91316
92478
|
enableMetaphor: false,
|
|
91317
|
-
replaceSystemPrompt:
|
|
92479
|
+
replaceSystemPrompt: false
|
|
91318
92480
|
},
|
|
91319
92481
|
env: process.env,
|
|
91320
92482
|
globalOptionsService: runtime.infraServices.globalOptionsService,
|