@dotobokuri/fleet-cli 1.5.5 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +2076 -720
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -17560,7 +17560,9 @@ function killProcess(child, forceTimeoutMs = 3e3) {
|
|
|
17560
17560
|
try {
|
|
17561
17561
|
execSync(`taskkill /PID ${child.pid} /T /F`, {
|
|
17562
17562
|
stdio: "pipe",
|
|
17563
|
-
timeout: 5e3
|
|
17563
|
+
timeout: 5e3,
|
|
17564
|
+
// 콘솔 없는 호스트에서 taskkill 호출 시 새 콘솔 창이 깜빡이는 것을 방지한다.
|
|
17565
|
+
windowsHide: true
|
|
17564
17566
|
});
|
|
17565
17567
|
} catch {
|
|
17566
17568
|
child.kill("SIGKILL");
|
|
@@ -17663,7 +17665,12 @@ var init_BaseConnection = __esm({
|
|
|
17663
17665
|
cwd: this.cwd,
|
|
17664
17666
|
stdio: ["pipe", "pipe", "pipe"],
|
|
17665
17667
|
env: this.env,
|
|
17666
|
-
windowsVerbatimArguments: true
|
|
17668
|
+
windowsVerbatimArguments: true,
|
|
17669
|
+
// 콘솔이 없는 호스트(예: fleet-console 백엔드)에서 cmd.exe를 spawn하면
|
|
17670
|
+
// Windows가 새 콘솔 창을 할당해 깜빡인다. stdio는 모두 pipe라 가시 콘솔이
|
|
17671
|
+
// 불필요하므로 CREATE_NO_WINDOW로 창 생성을 억제한다. (fleet-cli처럼 콘솔이
|
|
17672
|
+
// 이미 있는 경우에도 무해하다.)
|
|
17673
|
+
windowsHide: true
|
|
17667
17674
|
}) : spawn(this.command, this.args, {
|
|
17668
17675
|
cwd: this.cwd,
|
|
17669
17676
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -18423,7 +18430,9 @@ function resolveNpxPath(env) {
|
|
|
18423
18430
|
encoding: "utf-8",
|
|
18424
18431
|
stdio: "pipe",
|
|
18425
18432
|
timeout: 5e3,
|
|
18426
|
-
env
|
|
18433
|
+
env,
|
|
18434
|
+
// 콘솔 없는 호스트에서 `where npx` 실행 시 콘솔 창이 깜빡이는 것을 방지한다.
|
|
18435
|
+
windowsHide: true
|
|
18427
18436
|
}).trim();
|
|
18428
18437
|
const candidates = result.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
|
|
18429
18438
|
if (windows) {
|
|
@@ -18469,7 +18478,7 @@ var init_models = __esm({
|
|
|
18469
18478
|
"../../packages/core-unified-agent/models.json"() {
|
|
18470
18479
|
models_default = {
|
|
18471
18480
|
version: 1,
|
|
18472
|
-
updatedAt: "2026-06-
|
|
18481
|
+
updatedAt: "2026-06-16T00:00:00Z",
|
|
18473
18482
|
providers: {
|
|
18474
18483
|
claude: {
|
|
18475
18484
|
name: "Claude Code with Anthropic",
|
|
@@ -18479,7 +18488,9 @@ var init_models = __esm({
|
|
|
18479
18488
|
{ modelId: "sonnet", name: "Claude Sonnet", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "medium" } },
|
|
18480
18489
|
{ modelId: "opus", name: "Claude Opus", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "xhigh" } },
|
|
18481
18490
|
{ 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" } }
|
|
18491
|
+
{ modelId: "claude-opus-4-6[1m]", name: "Claude Opus 4.6 [1M]", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "high" } },
|
|
18492
|
+
{ modelId: "claude-opus-4-7[1m]", name: "Claude Opus 4.7 [1M]", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "high" } },
|
|
18493
|
+
{ modelId: "claude-opus-4-8[1m]", name: "Claude Opus 4.8 [1M]", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "high" } }
|
|
18483
18494
|
]
|
|
18484
18495
|
},
|
|
18485
18496
|
"claude-zai": {
|
|
@@ -33431,6 +33442,8 @@ function createClaudeFamilyCliDefinition(options2) {
|
|
|
33431
33442
|
lineTerminator: "\r",
|
|
33432
33443
|
multilineStrategy: "paste-mode"
|
|
33433
33444
|
},
|
|
33445
|
+
// Claude Code 계열은 세션 이름 변경 슬래시 명령 `/rename`을 지원한다.
|
|
33446
|
+
renameCommand: "/rename",
|
|
33434
33447
|
terminalName: "xterm-256color"
|
|
33435
33448
|
};
|
|
33436
33449
|
}
|
|
@@ -33454,7 +33467,7 @@ var codexCli = {
|
|
|
33454
33467
|
async createProfile(options2) {
|
|
33455
33468
|
const { bin, prefixArgs } = resolveBinary("codex", "CODEX_BIN", options2.env);
|
|
33456
33469
|
return {
|
|
33457
|
-
args: [...prefixArgs, "--no-alt-screen", ...buildModelArgs2(options2.model)],
|
|
33470
|
+
args: [...prefixArgs, ...buildResumeArgs(options2.resumeSessionId), "--no-alt-screen", ...buildModelArgs2(options2.model)],
|
|
33458
33471
|
bin,
|
|
33459
33472
|
binPrefixArgs: prefixArgs,
|
|
33460
33473
|
cwd: options2.cwd,
|
|
@@ -33466,10 +33479,15 @@ var codexCli = {
|
|
|
33466
33479
|
lineTerminator: "\r",
|
|
33467
33480
|
multilineStrategy: "paste-mode"
|
|
33468
33481
|
},
|
|
33482
|
+
// Codex CLI도 세션 이름 변경 슬래시 명령 `/rename`을 지원한다.
|
|
33483
|
+
renameCommand: "/rename",
|
|
33469
33484
|
terminalName: "xterm-256color"
|
|
33470
33485
|
};
|
|
33471
33486
|
}
|
|
33472
33487
|
};
|
|
33488
|
+
function buildResumeArgs(resumeSessionId) {
|
|
33489
|
+
return resumeSessionId === void 0 ? [] : ["resume", resumeSessionId];
|
|
33490
|
+
}
|
|
33473
33491
|
function buildModelArgs2(model) {
|
|
33474
33492
|
return model === void 0 ? [] : ["--model", model];
|
|
33475
33493
|
}
|
|
@@ -33486,7 +33504,8 @@ async function resolveAgentCliProfile(env, cwd, options2 = {}) {
|
|
|
33486
33504
|
authService: options2.authService,
|
|
33487
33505
|
cwd,
|
|
33488
33506
|
env,
|
|
33489
|
-
model: options2.model
|
|
33507
|
+
model: options2.model,
|
|
33508
|
+
resumeSessionId: options2.resumeSessionId
|
|
33490
33509
|
});
|
|
33491
33510
|
}
|
|
33492
33511
|
function resolveAgentCliId(env, options2 = {}) {
|
|
@@ -33562,6 +33581,7 @@ function buildClaudeNativeSubagentPlan(registry4) {
|
|
|
33562
33581
|
function buildClaudeNativeArgs(context) {
|
|
33563
33582
|
const systemPromptArg = context.replaceSystemPrompt ? "--system-prompt-file" : "--append-system-prompt-file";
|
|
33564
33583
|
return [
|
|
33584
|
+
...buildResumeArgs2(context.resumeSessionId),
|
|
33565
33585
|
systemPromptArg,
|
|
33566
33586
|
requireSystemPromptFile(context),
|
|
33567
33587
|
...context.pluginRoots.flatMap((pluginRoot) => [
|
|
@@ -33572,6 +33592,9 @@ function buildClaudeNativeArgs(context) {
|
|
|
33572
33592
|
"--dangerously-skip-permissions"
|
|
33573
33593
|
];
|
|
33574
33594
|
}
|
|
33595
|
+
function buildResumeArgs2(resumeSessionId) {
|
|
33596
|
+
return resumeSessionId === void 0 ? [] : ["--resume", resumeSessionId];
|
|
33597
|
+
}
|
|
33575
33598
|
function buildClaudeMcpConfig(servers) {
|
|
33576
33599
|
return JSON.stringify({
|
|
33577
33600
|
mcpServers: Object.fromEntries(
|
|
@@ -33629,20 +33652,32 @@ function escapeTomlMultilineString(value) {
|
|
|
33629
33652
|
});
|
|
33630
33653
|
return result;
|
|
33631
33654
|
}
|
|
33655
|
+
function buildPosixShellCommand(values) {
|
|
33656
|
+
return values.map(posixShellQuote).join(" ");
|
|
33657
|
+
}
|
|
33658
|
+
function posixShellQuote(value) {
|
|
33659
|
+
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
33660
|
+
}
|
|
33632
33661
|
var CODEX_TOOL_TIMEOUT_SEC = 1800;
|
|
33633
33662
|
function buildCodexNativeArgs(context) {
|
|
33634
33663
|
const profileName = requireCodexProfileName(context);
|
|
33635
33664
|
const args = [
|
|
33665
|
+
...buildResumeArgs3(context.resumeSessionId),
|
|
33636
33666
|
"--enable",
|
|
33637
33667
|
"plugins",
|
|
33638
33668
|
"--enable",
|
|
33639
33669
|
"child_agents_md",
|
|
33670
|
+
"--enable",
|
|
33671
|
+
"hooks",
|
|
33640
33672
|
"--profile",
|
|
33641
33673
|
profileName,
|
|
33642
33674
|
"-c",
|
|
33643
33675
|
'approval_policy="never"',
|
|
33644
33676
|
"-c",
|
|
33645
|
-
'sandbox_mode="danger-full-access"'
|
|
33677
|
+
'sandbox_mode="danger-full-access"',
|
|
33678
|
+
// hook 신뢰 프롬프트("Hooks need review")를 fleet 관리 세션에서 건너뛴다. bypass_hook_trust는
|
|
33679
|
+
// config 키가 아니라 전용 CLI 플래그이므로 -c override가 아닌 플래그로 전달해야 한다.
|
|
33680
|
+
"--dangerously-bypass-hook-trust"
|
|
33646
33681
|
];
|
|
33647
33682
|
for (const server of context.mcpServers) {
|
|
33648
33683
|
const prefix = `mcp_servers.${server.name}`;
|
|
@@ -33658,6 +33693,9 @@ function buildCodexNativeArgs(context) {
|
|
|
33658
33693
|
}
|
|
33659
33694
|
return args;
|
|
33660
33695
|
}
|
|
33696
|
+
function buildResumeArgs3(resumeSessionId) {
|
|
33697
|
+
return resumeSessionId === void 0 ? [] : ["resume", resumeSessionId];
|
|
33698
|
+
}
|
|
33661
33699
|
function requireCodexProfileName(context) {
|
|
33662
33700
|
if (context.codexProfileName) return context.codexProfileName;
|
|
33663
33701
|
throw new Error("Codex profile name is required for native injection");
|
|
@@ -33868,20 +33906,38 @@ function claudeHooks(options2) {
|
|
|
33868
33906
|
if (!hookExec) {
|
|
33869
33907
|
throw new Error("Fleet Claude session hook command is required");
|
|
33870
33908
|
}
|
|
33909
|
+
const userPromptSubmitExecs = [options2.captureSessionHookExec, options2.turnStartHookExec].filter((exec) => exec !== void 0);
|
|
33910
|
+
const stopExecs = [options2.turnEndHookExec].filter((exec) => exec !== void 0);
|
|
33871
33911
|
return {
|
|
33872
33912
|
hooks: {
|
|
33873
33913
|
SessionStart: [{
|
|
33874
|
-
hooks: [
|
|
33875
|
-
|
|
33876
|
-
|
|
33877
|
-
|
|
33878
|
-
|
|
33879
|
-
|
|
33914
|
+
hooks: [claudeCommandHook(hookExec)]
|
|
33915
|
+
}],
|
|
33916
|
+
...userPromptSubmitExecs.length > 0 ? {
|
|
33917
|
+
UserPromptSubmit: [{
|
|
33918
|
+
hooks: userPromptSubmitExecs.map(claudeCommandHook)
|
|
33919
|
+
}]
|
|
33920
|
+
} : {},
|
|
33921
|
+
...stopExecs.length > 0 ? {
|
|
33922
|
+
Stop: [{
|
|
33923
|
+
hooks: stopExecs.map(claudeCommandHook)
|
|
33880
33924
|
}]
|
|
33881
|
-
}
|
|
33925
|
+
} : {}
|
|
33882
33926
|
}
|
|
33883
33927
|
};
|
|
33884
33928
|
}
|
|
33929
|
+
function claudeCommandHook(hookExec) {
|
|
33930
|
+
if (!hookExec) {
|
|
33931
|
+
throw new Error("Fleet Claude session hook command is required");
|
|
33932
|
+
}
|
|
33933
|
+
return {
|
|
33934
|
+
// exec 형식: command는 직접 spawn되는 실행 파일, args는 셸 토크나이징 없이 그대로 전달된다.
|
|
33935
|
+
// Windows cmd/powershell의 따옴표 규칙과 무관하게 동작하며 공백 포함 경로도 안전하다.
|
|
33936
|
+
args: [...hookExec.args],
|
|
33937
|
+
command: hookExec.command,
|
|
33938
|
+
type: "command"
|
|
33939
|
+
};
|
|
33940
|
+
}
|
|
33885
33941
|
function claudeAgentFile(subagent) {
|
|
33886
33942
|
const frontmatter = [
|
|
33887
33943
|
"---",
|
|
@@ -34417,7 +34473,6 @@ function renderPluginRoot(pluginRoot, bundle, options2, fleetRoot) {
|
|
|
34417
34473
|
const stagedPluginRoot = path82.join(stageParent, path82.basename(pluginRoot));
|
|
34418
34474
|
try {
|
|
34419
34475
|
ensurePrivateDir(stagedPluginRoot, stagedPluginRoot);
|
|
34420
|
-
writePrivateJson(path82.join(stagedPluginRoot, ".codex-plugin", "plugin.json"), codexManifest(bundle), stagedPluginRoot);
|
|
34421
34476
|
writePrivateJson(path82.join(stagedPluginRoot, ".claude-plugin", "plugin.json"), claudeManifest(bundle), stagedPluginRoot);
|
|
34422
34477
|
switch (bundle.source) {
|
|
34423
34478
|
case "asset":
|
|
@@ -34432,6 +34487,7 @@ function renderPluginRoot(pluginRoot, bundle, options2, fleetRoot) {
|
|
|
34432
34487
|
renderGlobalPluginRoot(stagedPluginRoot, fleetRoot);
|
|
34433
34488
|
break;
|
|
34434
34489
|
}
|
|
34490
|
+
writePrivateJson(path82.join(stagedPluginRoot, ".codex-plugin", "plugin.json"), codexManifest(bundle, stagedPluginRoot), stagedPluginRoot);
|
|
34435
34491
|
removePrivatePath(pluginRoot, parentRoot);
|
|
34436
34492
|
renameSync22(stagedPluginRoot, pluginRoot);
|
|
34437
34493
|
} finally {
|
|
@@ -34563,14 +34619,36 @@ function marketplacePluginPath(target, bundle) {
|
|
|
34563
34619
|
if (target.flat) return `./${FLAT_PLUGIN_DIR_NAME}`;
|
|
34564
34620
|
return `./${PLUGIN_BUNDLES_DIR_NAME}/${bundle.directoryName}`;
|
|
34565
34621
|
}
|
|
34566
|
-
function codexManifest(bundle) {
|
|
34622
|
+
function codexManifest(bundle, pluginRoot) {
|
|
34567
34623
|
return {
|
|
34568
34624
|
name: bundle.name,
|
|
34569
|
-
version:
|
|
34625
|
+
version: codexManifestVersion(bundle, pluginRoot),
|
|
34570
34626
|
description: bundle.description,
|
|
34571
34627
|
skills: "./skills/"
|
|
34572
34628
|
};
|
|
34573
34629
|
}
|
|
34630
|
+
function codexManifestVersion(bundle, pluginRoot) {
|
|
34631
|
+
const hash3 = crypto4.createHash("sha256");
|
|
34632
|
+
hash3.update(bundle.name);
|
|
34633
|
+
hash3.update("\0");
|
|
34634
|
+
hash3.update(bundle.description);
|
|
34635
|
+
hash3.update("\0");
|
|
34636
|
+
for (const filePath of listCodexEffectivePluginFiles(pluginRoot)) {
|
|
34637
|
+
const relativePath = path82.relative(pluginRoot, filePath);
|
|
34638
|
+
hash3.update(relativePath);
|
|
34639
|
+
hash3.update("\0");
|
|
34640
|
+
hash3.update(readFileSync42(filePath));
|
|
34641
|
+
hash3.update("\0");
|
|
34642
|
+
}
|
|
34643
|
+
return `0.0.0+${hash3.digest("hex").slice(0, 12)}`;
|
|
34644
|
+
}
|
|
34645
|
+
function listCodexEffectivePluginFiles(pluginRoot) {
|
|
34646
|
+
const skillsPath = path82.join(pluginRoot, "skills");
|
|
34647
|
+
if (!existsSync5(skillsPath)) return [];
|
|
34648
|
+
const files = [];
|
|
34649
|
+
collectRenderableFiles(pluginRoot, skillsPath, files, /* @__PURE__ */ new Set());
|
|
34650
|
+
return files.sort();
|
|
34651
|
+
}
|
|
34574
34652
|
function claudeManifest(bundle) {
|
|
34575
34653
|
return {
|
|
34576
34654
|
name: bundle.name,
|
|
@@ -34604,11 +34682,18 @@ async function injectAgentCliProfile(profile, options2) {
|
|
|
34604
34682
|
cwd: profile.cwd,
|
|
34605
34683
|
dataDir: options2.dataDir,
|
|
34606
34684
|
rootDir: options2.pluginRootDir,
|
|
34685
|
+
captureSessionHookExec: options2.captureSessionHookExec,
|
|
34686
|
+
turnStartHookExec: options2.turnStartHookExec,
|
|
34687
|
+
turnEndHookExec: options2.turnEndHookExec,
|
|
34607
34688
|
hookExec: startupDefinitions.host === "claude" ? requireHookExec(options2.hookExec) : void 0,
|
|
34608
34689
|
withMarketplaceLock: options2.withMarketplaceLock
|
|
34609
34690
|
});
|
|
34610
34691
|
const codexPluginKeys = plugin.codexRegistrations.map((registration) => `${registration.pluginName}@${registration.marketplaceName}`);
|
|
34611
|
-
const codexProfile = profile.id === "codex" ? writeCodexFleetProfile(profile.env, doctrine, codexPluginKeys,
|
|
34692
|
+
const codexProfile = profile.id === "codex" ? writeCodexFleetProfile(profile.env, doctrine, codexPluginKeys, {
|
|
34693
|
+
captureSessionHookExec: options2.captureSessionHookExec,
|
|
34694
|
+
turnStartHookExec: options2.turnStartHookExec,
|
|
34695
|
+
turnEndHookExec: options2.turnEndHookExec
|
|
34696
|
+
}, (cleanup2) => tempCleanups.push(cleanup2)) : void 0;
|
|
34612
34697
|
const launchWarnings = [];
|
|
34613
34698
|
for (const registration of plugin.codexRegistrations) {
|
|
34614
34699
|
const registrationWarning = await ensureCodexPluginRegistered(registration, {
|
|
@@ -34635,13 +34720,14 @@ async function injectAgentCliProfile(profile, options2) {
|
|
|
34635
34720
|
pluginRoot: plugin.pluginRoot,
|
|
34636
34721
|
pluginRoots: plugin.pluginRoots,
|
|
34637
34722
|
codexProfileName: codexProfile?.profileName,
|
|
34638
|
-
replaceSystemPrompt: options2.replaceSystemPrompt ??
|
|
34723
|
+
replaceSystemPrompt: options2.replaceSystemPrompt ?? false,
|
|
34724
|
+
resumeSessionId: options2.resumeSessionId,
|
|
34639
34725
|
systemPromptFile
|
|
34640
34726
|
};
|
|
34641
34727
|
const injectedArgs = buildAgentCliArgs(capability.builderId, context);
|
|
34642
34728
|
return {
|
|
34643
34729
|
...profile,
|
|
34644
|
-
args:
|
|
34730
|
+
args: mergeAgentCliArgs(profile, capability.builderId, context, injectedArgs),
|
|
34645
34731
|
cleanup,
|
|
34646
34732
|
launchWarnings: [...profile.launchWarnings ?? [], ...launchWarnings]
|
|
34647
34733
|
};
|
|
@@ -34683,7 +34769,7 @@ function writeSystemPromptFile(cliId, systemPrompt, onCleanup) {
|
|
|
34683
34769
|
chmodBestEffort2(filePath, SYSTEM_PROMPT_FILE_MODE);
|
|
34684
34770
|
return filePath;
|
|
34685
34771
|
}
|
|
34686
|
-
function writeCodexFleetProfile(env, doctrine, pluginKeys, onCleanup) {
|
|
34772
|
+
function writeCodexFleetProfile(env, doctrine, pluginKeys, hookExecs, onCleanup) {
|
|
34687
34773
|
const codexHome = env.CODEX_HOME ?? path92.join(env.HOME ?? os23.homedir(), ".codex");
|
|
34688
34774
|
mkdirSync32(codexHome, { recursive: true });
|
|
34689
34775
|
pruneStaleCodexFleetProfiles(codexHome);
|
|
@@ -34702,11 +34788,33 @@ function writeCodexFleetProfile(env, doctrine, pluginKeys, onCleanup) {
|
|
|
34702
34788
|
`[plugins."${escapeTomlBasicString2(pluginKey)}"]`,
|
|
34703
34789
|
"enabled = true",
|
|
34704
34790
|
""
|
|
34705
|
-
])
|
|
34791
|
+
]),
|
|
34792
|
+
...codexHooksConfig(hookExecs)
|
|
34706
34793
|
].join("\n"));
|
|
34707
34794
|
chmodBestEffort2(profilePath, SYSTEM_PROMPT_FILE_MODE);
|
|
34708
34795
|
return { profileName, profilePath };
|
|
34709
34796
|
}
|
|
34797
|
+
function codexHooksConfig(hookExecs) {
|
|
34798
|
+
const userPromptSubmitExecs = [hookExecs.captureSessionHookExec, hookExecs.turnStartHookExec].filter((exec) => exec !== void 0);
|
|
34799
|
+
const stopExecs = [hookExecs.turnEndHookExec].filter((exec) => exec !== void 0);
|
|
34800
|
+
if (userPromptSubmitExecs.length === 0 && stopExecs.length === 0) return [];
|
|
34801
|
+
const lines = ["[hooks]"];
|
|
34802
|
+
if (userPromptSubmitExecs.length > 0) {
|
|
34803
|
+
lines.push(`UserPromptSubmit = ${codexHookHandlersInline(userPromptSubmitExecs)}`);
|
|
34804
|
+
}
|
|
34805
|
+
if (stopExecs.length > 0) {
|
|
34806
|
+
lines.push(`Stop = ${codexHookHandlersInline(stopExecs)}`);
|
|
34807
|
+
}
|
|
34808
|
+
lines.push("");
|
|
34809
|
+
return lines;
|
|
34810
|
+
}
|
|
34811
|
+
function codexHookHandlersInline(execs) {
|
|
34812
|
+
const handlers = execs.map((exec) => {
|
|
34813
|
+
const command3 = buildPosixShellCommand([exec.command, ...exec.args]);
|
|
34814
|
+
return `{ type = "command", command = "${escapeTomlBasicString2(command3)}" }`;
|
|
34815
|
+
}).join(", ");
|
|
34816
|
+
return `[{ hooks = [${handlers}] }]`;
|
|
34817
|
+
}
|
|
34710
34818
|
function writeFileNoFollow2(filePath, content) {
|
|
34711
34819
|
const flags = constants32.O_WRONLY | constants32.O_CREAT | constants32.O_TRUNC | constants32.O_NOFOLLOW;
|
|
34712
34820
|
const fd = openSync32(filePath, flags, SYSTEM_PROMPT_FILE_MODE);
|
|
@@ -34779,6 +34887,24 @@ function buildAgentCliArgs(builderId, context) {
|
|
|
34779
34887
|
return buildCodexNativeArgs(context);
|
|
34780
34888
|
}
|
|
34781
34889
|
}
|
|
34890
|
+
function mergeAgentCliArgs(profile, builderId, context, injectedArgs) {
|
|
34891
|
+
if (builderId !== "codex-native" || context.resumeSessionId === void 0) {
|
|
34892
|
+
return [...profile.args, ...injectedArgs];
|
|
34893
|
+
}
|
|
34894
|
+
const resumeSessionId = context.resumeSessionId;
|
|
34895
|
+
const prefixLength = profile.binPrefixArgs?.length ?? 0;
|
|
34896
|
+
const codexResumeArgs = ["resume", resumeSessionId];
|
|
34897
|
+
const injectedTail = injectedArgs.slice(codexResumeArgs.length);
|
|
34898
|
+
return [
|
|
34899
|
+
...profile.args.slice(0, prefixLength),
|
|
34900
|
+
...codexResumeArgs,
|
|
34901
|
+
...profile.args.slice(prefixLength).filter((arg, index, args) => !isCodexResumeArgAt(args, index, resumeSessionId)),
|
|
34902
|
+
...injectedTail
|
|
34903
|
+
];
|
|
34904
|
+
}
|
|
34905
|
+
function isCodexResumeArgAt(args, index, resumeSessionId) {
|
|
34906
|
+
return args[index] === "resume" && args[index + 1] === resumeSessionId || args[index] === resumeSessionId && args[index - 1] === "resume";
|
|
34907
|
+
}
|
|
34782
34908
|
function createOnceCleanup(cleanup) {
|
|
34783
34909
|
let cleaned = false;
|
|
34784
34910
|
return () => {
|
|
@@ -39592,14 +39718,14 @@ import * as fs52 from "fs";
|
|
|
39592
39718
|
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
39719
|
import * as path93 from "path";
|
|
39594
39720
|
import path93__default, { join as join10, resolve, relative, dirname as dirname6 } from "path";
|
|
39595
|
-
import
|
|
39721
|
+
import process6 from "process";
|
|
39596
39722
|
import { fileURLToPath, pathToFileURL as pathToFileURL2 } from "url";
|
|
39597
39723
|
import * as os222 from "os";
|
|
39598
39724
|
import os22__default from "os";
|
|
39599
39725
|
import { EventEmitter as EventEmitter6 } from "events";
|
|
39600
39726
|
import { stat, mkdir as mkdir2, readFile as readFile2, readdir, appendFile, writeFile as writeFile2, rename, access as access2, rm } from "fs/promises";
|
|
39601
39727
|
import { Writable as Writable2, Readable as Readable2 } from "stream";
|
|
39602
|
-
import
|
|
39728
|
+
import crypto5, { createHash as createHash2, randomUUID as randomUUID2, timingSafeEqual } from "crypto";
|
|
39603
39729
|
import http2 from "http";
|
|
39604
39730
|
import { createRequire } from "module";
|
|
39605
39731
|
import net2 from "net";
|
|
@@ -40544,10 +40670,10 @@ function mergeDefs2(...defs) {
|
|
|
40544
40670
|
function cloneDef2(schema) {
|
|
40545
40671
|
return mergeDefs2(schema._zod.def);
|
|
40546
40672
|
}
|
|
40547
|
-
function getElementAtPath2(obj,
|
|
40548
|
-
if (!
|
|
40673
|
+
function getElementAtPath2(obj, path35) {
|
|
40674
|
+
if (!path35)
|
|
40549
40675
|
return obj;
|
|
40550
|
-
return
|
|
40676
|
+
return path35.reduce((acc, key) => acc?.[key], obj);
|
|
40551
40677
|
}
|
|
40552
40678
|
function promiseAllObject2(promisesObj) {
|
|
40553
40679
|
const keys = Object.keys(promisesObj);
|
|
@@ -40956,11 +41082,11 @@ function explicitlyAborted2(x, startIndex = 0) {
|
|
|
40956
41082
|
}
|
|
40957
41083
|
return false;
|
|
40958
41084
|
}
|
|
40959
|
-
function prefixIssues2(
|
|
41085
|
+
function prefixIssues2(path35, issues) {
|
|
40960
41086
|
return issues.map((iss) => {
|
|
40961
41087
|
var _a32;
|
|
40962
41088
|
(_a32 = iss).path ?? (_a32.path = []);
|
|
40963
|
-
iss.path.unshift(
|
|
41089
|
+
iss.path.unshift(path35);
|
|
40964
41090
|
return iss;
|
|
40965
41091
|
});
|
|
40966
41092
|
}
|
|
@@ -41105,16 +41231,16 @@ function flattenError2(error512, mapper = (issue32) => issue32.message) {
|
|
|
41105
41231
|
}
|
|
41106
41232
|
function formatError3(error512, mapper = (issue32) => issue32.message) {
|
|
41107
41233
|
const fieldErrors = { _errors: [] };
|
|
41108
|
-
const processError = (error522,
|
|
41234
|
+
const processError = (error522, path35 = []) => {
|
|
41109
41235
|
for (const issue32 of error522.issues) {
|
|
41110
41236
|
if (issue32.code === "invalid_union" && issue32.errors.length) {
|
|
41111
|
-
issue32.errors.map((issues) => processError({ issues }, [...
|
|
41237
|
+
issue32.errors.map((issues) => processError({ issues }, [...path35, ...issue32.path]));
|
|
41112
41238
|
} else if (issue32.code === "invalid_key") {
|
|
41113
|
-
processError({ issues: issue32.issues }, [...
|
|
41239
|
+
processError({ issues: issue32.issues }, [...path35, ...issue32.path]);
|
|
41114
41240
|
} else if (issue32.code === "invalid_element") {
|
|
41115
|
-
processError({ issues: issue32.issues }, [...
|
|
41241
|
+
processError({ issues: issue32.issues }, [...path35, ...issue32.path]);
|
|
41116
41242
|
} else {
|
|
41117
|
-
const fullpath = [...
|
|
41243
|
+
const fullpath = [...path35, ...issue32.path];
|
|
41118
41244
|
if (fullpath.length === 0) {
|
|
41119
41245
|
fieldErrors._errors.push(mapper(issue32));
|
|
41120
41246
|
} else {
|
|
@@ -41141,17 +41267,17 @@ function formatError3(error512, mapper = (issue32) => issue32.message) {
|
|
|
41141
41267
|
}
|
|
41142
41268
|
function treeifyError2(error512, mapper = (issue32) => issue32.message) {
|
|
41143
41269
|
const result = { errors: [] };
|
|
41144
|
-
const processError = (error522,
|
|
41270
|
+
const processError = (error522, path35 = []) => {
|
|
41145
41271
|
var _a32, _b;
|
|
41146
41272
|
for (const issue32 of error522.issues) {
|
|
41147
41273
|
if (issue32.code === "invalid_union" && issue32.errors.length) {
|
|
41148
|
-
issue32.errors.map((issues) => processError({ issues }, [...
|
|
41274
|
+
issue32.errors.map((issues) => processError({ issues }, [...path35, ...issue32.path]));
|
|
41149
41275
|
} else if (issue32.code === "invalid_key") {
|
|
41150
|
-
processError({ issues: issue32.issues }, [...
|
|
41276
|
+
processError({ issues: issue32.issues }, [...path35, ...issue32.path]);
|
|
41151
41277
|
} else if (issue32.code === "invalid_element") {
|
|
41152
|
-
processError({ issues: issue32.issues }, [...
|
|
41278
|
+
processError({ issues: issue32.issues }, [...path35, ...issue32.path]);
|
|
41153
41279
|
} else {
|
|
41154
|
-
const fullpath = [...
|
|
41280
|
+
const fullpath = [...path35, ...issue32.path];
|
|
41155
41281
|
if (fullpath.length === 0) {
|
|
41156
41282
|
result.errors.push(mapper(issue32));
|
|
41157
41283
|
continue;
|
|
@@ -41183,8 +41309,8 @@ function treeifyError2(error512, mapper = (issue32) => issue32.message) {
|
|
|
41183
41309
|
}
|
|
41184
41310
|
function toDotPath2(_path) {
|
|
41185
41311
|
const segs = [];
|
|
41186
|
-
const
|
|
41187
|
-
for (const seg of
|
|
41312
|
+
const path35 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
41313
|
+
for (const seg of path35) {
|
|
41188
41314
|
if (typeof seg === "number")
|
|
41189
41315
|
segs.push(`[${seg}]`);
|
|
41190
41316
|
else if (typeof seg === "symbol")
|
|
@@ -53705,13 +53831,13 @@ function resolveRef2(ref, ctx) {
|
|
|
53705
53831
|
if (!ref.startsWith("#")) {
|
|
53706
53832
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
53707
53833
|
}
|
|
53708
|
-
const
|
|
53709
|
-
if (
|
|
53834
|
+
const path35 = ref.slice(1).split("/").filter(Boolean);
|
|
53835
|
+
if (path35.length === 0) {
|
|
53710
53836
|
return ctx.rootSchema;
|
|
53711
53837
|
}
|
|
53712
53838
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
53713
|
-
if (
|
|
53714
|
-
const key =
|
|
53839
|
+
if (path35[0] === defsKey) {
|
|
53840
|
+
const key = path35[1];
|
|
53715
53841
|
if (!key || !ctx.defs[key]) {
|
|
53716
53842
|
throw new Error(`Reference not found: ${ref}`);
|
|
53717
53843
|
}
|
|
@@ -56462,7 +56588,9 @@ function killProcess2(child, forceTimeoutMs = 3e3) {
|
|
|
56462
56588
|
try {
|
|
56463
56589
|
execSync3(`taskkill /PID ${child.pid} /T /F`, {
|
|
56464
56590
|
stdio: "pipe",
|
|
56465
|
-
timeout: 5e3
|
|
56591
|
+
timeout: 5e3,
|
|
56592
|
+
// 콘솔 없는 호스트에서 taskkill 호출 시 새 콘솔 창이 깜빡이는 것을 방지한다.
|
|
56593
|
+
windowsHide: true
|
|
56466
56594
|
});
|
|
56467
56595
|
} catch {
|
|
56468
56596
|
child.kill("SIGKILL");
|
|
@@ -56534,7 +56662,12 @@ var BaseConnection2 = class extends EventEmitter6 {
|
|
|
56534
56662
|
cwd: this.cwd,
|
|
56535
56663
|
stdio: ["pipe", "pipe", "pipe"],
|
|
56536
56664
|
env: this.env,
|
|
56537
|
-
windowsVerbatimArguments: true
|
|
56665
|
+
windowsVerbatimArguments: true,
|
|
56666
|
+
// 콘솔이 없는 호스트(예: fleet-console 백엔드)에서 cmd.exe를 spawn하면
|
|
56667
|
+
// Windows가 새 콘솔 창을 할당해 깜빡인다. stdio는 모두 pipe라 가시 콘솔이
|
|
56668
|
+
// 불필요하므로 CREATE_NO_WINDOW로 창 생성을 억제한다. (fleet-cli처럼 콘솔이
|
|
56669
|
+
// 이미 있는 경우에도 무해하다.)
|
|
56670
|
+
windowsHide: true
|
|
56538
56671
|
}) : spawn3(this.command, this.args, {
|
|
56539
56672
|
cwd: this.cwd,
|
|
56540
56673
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -57288,7 +57421,9 @@ function resolveNpxPath2(env) {
|
|
|
57288
57421
|
encoding: "utf-8",
|
|
57289
57422
|
stdio: "pipe",
|
|
57290
57423
|
timeout: 5e3,
|
|
57291
|
-
env
|
|
57424
|
+
env,
|
|
57425
|
+
// 콘솔 없는 호스트에서 `where npx` 실행 시 콘솔 창이 깜빡이는 것을 방지한다.
|
|
57426
|
+
windowsHide: true
|
|
57292
57427
|
}).trim();
|
|
57293
57428
|
const candidates = result.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
|
|
57294
57429
|
if (windows) {
|
|
@@ -57323,7 +57458,7 @@ function inferBinName2(packageName) {
|
|
|
57323
57458
|
}
|
|
57324
57459
|
var models_default2 = {
|
|
57325
57460
|
version: 1,
|
|
57326
|
-
updatedAt: "2026-06-
|
|
57461
|
+
updatedAt: "2026-06-16T00:00:00Z",
|
|
57327
57462
|
providers: {
|
|
57328
57463
|
claude: {
|
|
57329
57464
|
name: "Claude Code with Anthropic",
|
|
@@ -57333,7 +57468,9 @@ var models_default2 = {
|
|
|
57333
57468
|
{ modelId: "sonnet", name: "Claude Sonnet", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "medium" } },
|
|
57334
57469
|
{ modelId: "opus", name: "Claude Opus", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "xhigh" } },
|
|
57335
57470
|
{ 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" } }
|
|
57471
|
+
{ modelId: "claude-opus-4-6[1m]", name: "Claude Opus 4.6 [1M]", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "high" } },
|
|
57472
|
+
{ modelId: "claude-opus-4-7[1m]", name: "Claude Opus 4.7 [1M]", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "high" } },
|
|
57473
|
+
{ modelId: "claude-opus-4-8[1m]", name: "Claude Opus 4.8 [1M]", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "high" } }
|
|
57337
57474
|
]
|
|
57338
57475
|
},
|
|
57339
57476
|
"claude-zai": {
|
|
@@ -60466,7 +60603,7 @@ function specToMcpTool2(spec) {
|
|
|
60466
60603
|
}
|
|
60467
60604
|
function installExecutorToolCallRouter2(runtime, sessionToken, ctx) {
|
|
60468
60605
|
runtime.server.setOnToolCallArrived(sessionToken, (toolName, args) => {
|
|
60469
|
-
const toolCallId =
|
|
60606
|
+
const toolCallId = crypto5.randomUUID();
|
|
60470
60607
|
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
60608
|
runtime.server.resolveNextToolCall(sessionToken, toolCallId, {
|
|
60472
60609
|
content: [{ type: "text", text: err instanceof Error ? err.message : String(err) }],
|
|
@@ -60857,7 +60994,7 @@ function createInProcessMcpServer2(deps = {}) {
|
|
|
60857
60994
|
if (activeStopPromise) await activeStopPromise;
|
|
60858
60995
|
if (activeServer && activeServerUrl) return activeServerUrl;
|
|
60859
60996
|
if (activeStartPromise) return activeStartPromise;
|
|
60860
|
-
activeOpaquePath = `/${
|
|
60997
|
+
activeOpaquePath = `/${crypto5.randomUUID()}`;
|
|
60861
60998
|
activeStartPromise = new Promise((resolve2, reject) => {
|
|
60862
60999
|
const srv = http2.createServer(handleRequest);
|
|
60863
61000
|
srv.timeout = MCP_SERVER_TIMEOUT_MS2;
|
|
@@ -61114,7 +61251,7 @@ function createExecutorMcpSession2(deps, toolTimeoutSeconds, request) {
|
|
|
61114
61251
|
throw new Error("Executor session cwd is required");
|
|
61115
61252
|
}
|
|
61116
61253
|
assertNonEmptyExecutorTools2(request.serverName, request.specs);
|
|
61117
|
-
const token =
|
|
61254
|
+
const token = crypto5.randomUUID();
|
|
61118
61255
|
registerExecutorSessionTools2(runtime.runtime, token, [...request.specs]);
|
|
61119
61256
|
installExecutorToolCallRouter2(runtime.runtime, token, {
|
|
61120
61257
|
cwd,
|
|
@@ -61160,7 +61297,7 @@ function issueSessionToken2(deps, sessionTokensByLabel, request) {
|
|
|
61160
61297
|
for (const { name, runtime } of deps.runtimes) {
|
|
61161
61298
|
const tools = runtime.registry.getAllAgentTools();
|
|
61162
61299
|
assertNonEmptyExecutorTools2(name, tools);
|
|
61163
|
-
const token =
|
|
61300
|
+
const token = crypto5.randomUUID();
|
|
61164
61301
|
registerExecutorSessionTools2(runtime, token, tools);
|
|
61165
61302
|
installExecutorToolCallRouter2(runtime, token, { cwd, sessionLabel: label, signal: request.signal });
|
|
61166
61303
|
tokens.push({ name, token });
|
|
@@ -62526,7 +62663,8 @@ function sleepSync2(ms) {
|
|
|
62526
62663
|
var DEFAULT_TEMP_FILE_MIN_AGE_MS2 = 6e4;
|
|
62527
62664
|
function createDurableJsonStore2(deps) {
|
|
62528
62665
|
const now = deps.now ?? (() => Date.now());
|
|
62529
|
-
const
|
|
62666
|
+
const sensitivity = deps.sensitivity;
|
|
62667
|
+
const mode = sensitivity === "sensitive" ? SECURE_FILE_MODE2 : 420;
|
|
62530
62668
|
const minAgeMs = deps.tempCleanupMinAgeMs ?? DEFAULT_TEMP_FILE_MIN_AGE_MS2;
|
|
62531
62669
|
const dir = path93.dirname(deps.filePath);
|
|
62532
62670
|
return {
|
|
@@ -62554,10 +62692,10 @@ function createDurableJsonStore2(deps) {
|
|
|
62554
62692
|
};
|
|
62555
62693
|
function withLock(operation) {
|
|
62556
62694
|
if (!deps.lockDir) {
|
|
62557
|
-
ensureSafeDirectoryIfSensitive2(dir);
|
|
62695
|
+
ensureSafeDirectoryIfSensitive2(dir, sensitivity);
|
|
62558
62696
|
return operation();
|
|
62559
62697
|
}
|
|
62560
|
-
ensureSafeDirectoryIfSensitive2(dir);
|
|
62698
|
+
ensureSafeDirectoryIfSensitive2(dir, sensitivity);
|
|
62561
62699
|
return withDirectoryLock2(
|
|
62562
62700
|
{
|
|
62563
62701
|
lockDir: deps.lockDir,
|
|
@@ -62599,8 +62737,10 @@ function readJsonFile2(filePath, sanitize) {
|
|
|
62599
62737
|
}
|
|
62600
62738
|
}
|
|
62601
62739
|
function ensureSafeDirectoryIfSensitive2(dir, sensitivity) {
|
|
62602
|
-
{
|
|
62740
|
+
if (sensitivity === "sensitive") {
|
|
62603
62741
|
ensureSafeDirectory2(dir);
|
|
62742
|
+
} else {
|
|
62743
|
+
fs52.mkdirSync(dir, { recursive: true });
|
|
62604
62744
|
}
|
|
62605
62745
|
}
|
|
62606
62746
|
var memory_exports2 = {};
|
|
@@ -70278,7 +70418,7 @@ var LOCK_FILE_MODE = 384;
|
|
|
70278
70418
|
function createConsoleLock(deps = {}) {
|
|
70279
70419
|
const fsImpl = deps.fs ?? fs5__default;
|
|
70280
70420
|
const now = deps.now ?? Date.now;
|
|
70281
|
-
const randomToken = deps.randomToken ?? (() =>
|
|
70421
|
+
const randomToken = deps.randomToken ?? (() => crypto5.randomBytes(32).toString("base64url"));
|
|
70282
70422
|
const hostname52 = deps.hostname ?? (() => "127.0.0.1");
|
|
70283
70423
|
function ensureLockDir(dir) {
|
|
70284
70424
|
fsImpl.mkdirSync(dir, { recursive: true, mode: LOCK_DIR_MODE });
|
|
@@ -70373,6 +70513,387 @@ function createConsoleLock(deps = {}) {
|
|
|
70373
70513
|
}
|
|
70374
70514
|
return { ensureLockDir, readLock, writeLock, removeLock, assertLockModes, assertTrustedLock };
|
|
70375
70515
|
}
|
|
70516
|
+
var FLEET_DATA_DIR_NAME2 = ".fleet";
|
|
70517
|
+
function getFleetDataDir2() {
|
|
70518
|
+
return path93.join(os222.homedir(), FLEET_DATA_DIR_NAME2);
|
|
70519
|
+
}
|
|
70520
|
+
function readAuthStoreFile2(filePath) {
|
|
70521
|
+
let fd;
|
|
70522
|
+
try {
|
|
70523
|
+
fd = fs52.openSync(filePath, fs52.constants.O_RDONLY | NOFOLLOW_FLAG2);
|
|
70524
|
+
if (!fs52.fstatSync(fd).isFile()) {
|
|
70525
|
+
return {};
|
|
70526
|
+
}
|
|
70527
|
+
return JSON.parse(fs52.readFileSync(fd, "utf-8"));
|
|
70528
|
+
} catch {
|
|
70529
|
+
return {};
|
|
70530
|
+
} finally {
|
|
70531
|
+
if (fd !== void 0) {
|
|
70532
|
+
try {
|
|
70533
|
+
fs52.closeSync(fd);
|
|
70534
|
+
} catch {
|
|
70535
|
+
}
|
|
70536
|
+
}
|
|
70537
|
+
}
|
|
70538
|
+
}
|
|
70539
|
+
var DEFAULT_AUTH_PATH2 = path93.join(getFleetDataDir2(), "auth.json");
|
|
70540
|
+
var AUTH_LOCK_OWNER_FILE_NAME2 = "owner.json";
|
|
70541
|
+
var AUTH_LOCK_TIMEOUT_MS2 = 5e3;
|
|
70542
|
+
function createAuthService2(deps = {}) {
|
|
70543
|
+
const authPath = deps.authPath ?? DEFAULT_AUTH_PATH2;
|
|
70544
|
+
const lockDir = `${authPath}.lock`;
|
|
70545
|
+
return {
|
|
70546
|
+
// [HIGH #1] TOCTOU 수정: existsSync/read/check/delete/write 전체를 락 블록 안으로 이동
|
|
70547
|
+
async deleteApiKey(providerId) {
|
|
70548
|
+
let deleted = false;
|
|
70549
|
+
withAuthLock2(authPath, lockDir, () => {
|
|
70550
|
+
if (!fs52.existsSync(authPath)) return;
|
|
70551
|
+
const data = readAuthStoreFile2(authPath);
|
|
70552
|
+
if (!Object.prototype.hasOwnProperty.call(data, providerId)) return;
|
|
70553
|
+
delete data[providerId];
|
|
70554
|
+
writeAuthData2(authPath, data);
|
|
70555
|
+
deleted = true;
|
|
70556
|
+
});
|
|
70557
|
+
return deleted;
|
|
70558
|
+
},
|
|
70559
|
+
// [HIGH #2] 읽기 경로: fd 기반 O_RDONLY|O_NOFOLLOW+fstatSync isFile
|
|
70560
|
+
async getApiKey(providerId) {
|
|
70561
|
+
let fd;
|
|
70562
|
+
try {
|
|
70563
|
+
if (!fs52.existsSync(authPath)) {
|
|
70564
|
+
return void 0;
|
|
70565
|
+
}
|
|
70566
|
+
fd = fs52.openSync(authPath, fs52.constants.O_RDONLY | NOFOLLOW_FLAG2);
|
|
70567
|
+
if (!fs52.fstatSync(fd).isFile()) {
|
|
70568
|
+
return void 0;
|
|
70569
|
+
}
|
|
70570
|
+
const data = JSON.parse(fs52.readFileSync(fd, "utf-8"));
|
|
70571
|
+
return typeof data[providerId]?.key === "string" ? data[providerId].key : void 0;
|
|
70572
|
+
} catch {
|
|
70573
|
+
return void 0;
|
|
70574
|
+
} finally {
|
|
70575
|
+
if (fd !== void 0) {
|
|
70576
|
+
try {
|
|
70577
|
+
fs52.closeSync(fd);
|
|
70578
|
+
} catch {
|
|
70579
|
+
}
|
|
70580
|
+
}
|
|
70581
|
+
}
|
|
70582
|
+
},
|
|
70583
|
+
// [HIGH #2] 읽기 경로: fd 기반 O_RDONLY|O_NOFOLLOW 통일
|
|
70584
|
+
async listProviderIds() {
|
|
70585
|
+
if (!fs52.existsSync(authPath)) {
|
|
70586
|
+
return [];
|
|
70587
|
+
}
|
|
70588
|
+
try {
|
|
70589
|
+
return Object.keys(readAuthStoreFile2(authPath)).sort();
|
|
70590
|
+
} catch {
|
|
70591
|
+
return [];
|
|
70592
|
+
}
|
|
70593
|
+
},
|
|
70594
|
+
async setApiKey(providerId, key) {
|
|
70595
|
+
const dir = path93.dirname(authPath);
|
|
70596
|
+
ensureSafeDirectory2(dir);
|
|
70597
|
+
withAuthLock2(authPath, lockDir, () => {
|
|
70598
|
+
const data = fs52.existsSync(authPath) ? readAuthStoreFile2(authPath) : {};
|
|
70599
|
+
data[providerId] = {
|
|
70600
|
+
...data[providerId] ?? {},
|
|
70601
|
+
key
|
|
70602
|
+
};
|
|
70603
|
+
writeAuthData2(authPath, data);
|
|
70604
|
+
});
|
|
70605
|
+
}
|
|
70606
|
+
};
|
|
70607
|
+
}
|
|
70608
|
+
function withAuthLock2(authPath, lockDir, operation) {
|
|
70609
|
+
return withDirectoryLock2(
|
|
70610
|
+
{
|
|
70611
|
+
lockDir,
|
|
70612
|
+
ownerFileName: AUTH_LOCK_OWNER_FILE_NAME2,
|
|
70613
|
+
timeoutMs: AUTH_LOCK_TIMEOUT_MS2
|
|
70614
|
+
},
|
|
70615
|
+
operation
|
|
70616
|
+
);
|
|
70617
|
+
}
|
|
70618
|
+
function writeAuthData2(authPath, data) {
|
|
70619
|
+
writeAtomicSync2(authPath, `${JSON.stringify(data, null, 2)}
|
|
70620
|
+
`, {
|
|
70621
|
+
mode: SECURE_FILE_MODE2,
|
|
70622
|
+
fsync: true
|
|
70623
|
+
});
|
|
70624
|
+
}
|
|
70625
|
+
function formatMissingAuthKeyMessage2(input) {
|
|
70626
|
+
const cliHint = input.cli ? `cli '${input.cli}'` : "selected CLI";
|
|
70627
|
+
return `Auth token not found for ${cliHint} (providerId: '${input.providerId}'). Run \`fleet auth login\` to register one.`;
|
|
70628
|
+
}
|
|
70629
|
+
function formatAuthValidationFailureMessage2(input) {
|
|
70630
|
+
const detail = input.detail ? ` Detail: ${input.detail}` : "";
|
|
70631
|
+
if (input.status === "unauthorized") {
|
|
70632
|
+
return `Auth token was rejected (providerId: '${input.providerId}'). Check the token and try again.${detail}`;
|
|
70633
|
+
}
|
|
70634
|
+
if (input.status === "forbidden") {
|
|
70635
|
+
return `Auth token is not allowed for this provider (providerId: '${input.providerId}'). Check the token permissions.${detail}`;
|
|
70636
|
+
}
|
|
70637
|
+
if (input.status === "timeout") {
|
|
70638
|
+
return `Auth token validation timed out (providerId: '${input.providerId}'). Check the connection and try again.${detail}`;
|
|
70639
|
+
}
|
|
70640
|
+
if (input.status === "network") {
|
|
70641
|
+
return `Auth token validation failed due to a network error (providerId: '${input.providerId}'). Check the connection and try again.${detail}`;
|
|
70642
|
+
}
|
|
70643
|
+
if (input.status === "server") {
|
|
70644
|
+
return `Auth token validation failed because the provider returned an error (providerId: '${input.providerId}'). Try again later.${detail}`;
|
|
70645
|
+
}
|
|
70646
|
+
return `Auth token validation failed (providerId: '${input.providerId}'). Check the token and try again.${detail}`;
|
|
70647
|
+
}
|
|
70648
|
+
var LEGACY_AUTH_PATH2 = path93.join(getFleetDataDir2(), "agent", "auth.json");
|
|
70649
|
+
var CURRENT_AUTH_PATH2 = path93.join(getFleetDataDir2(), "auth.json");
|
|
70650
|
+
function mergeAuthStoresNoOverwrite2(legacy, current) {
|
|
70651
|
+
const data = { ...current };
|
|
70652
|
+
const migratedProviderIds = [];
|
|
70653
|
+
const skippedProviderIds = [];
|
|
70654
|
+
for (const [providerId, entry] of Object.entries(legacy)) {
|
|
70655
|
+
if (Object.prototype.hasOwnProperty.call(data, providerId)) {
|
|
70656
|
+
skippedProviderIds.push(providerId);
|
|
70657
|
+
continue;
|
|
70658
|
+
}
|
|
70659
|
+
data[providerId] = entry;
|
|
70660
|
+
migratedProviderIds.push(providerId);
|
|
70661
|
+
}
|
|
70662
|
+
return {
|
|
70663
|
+
data,
|
|
70664
|
+
migratedProviderIds,
|
|
70665
|
+
skippedProviderIds
|
|
70666
|
+
};
|
|
70667
|
+
}
|
|
70668
|
+
async function migrateLegacyAuthStore2(options2 = {}) {
|
|
70669
|
+
const legacyPath = options2.legacyPath ?? LEGACY_AUTH_PATH2;
|
|
70670
|
+
const currentPath = options2.currentPath ?? CURRENT_AUTH_PATH2;
|
|
70671
|
+
if (!fs52.existsSync(legacyPath)) {
|
|
70672
|
+
return createMigrationResult2({
|
|
70673
|
+
legacyPath,
|
|
70674
|
+
currentPath,
|
|
70675
|
+
status: "legacy-missing",
|
|
70676
|
+
migratedProviderIds: [],
|
|
70677
|
+
skippedProviderIds: [],
|
|
70678
|
+
shouldPrintNotice: false
|
|
70679
|
+
});
|
|
70680
|
+
}
|
|
70681
|
+
const legacy = readAuthStoreFile2(legacyPath);
|
|
70682
|
+
const current = fs52.existsSync(currentPath) ? readAuthStoreFile2(currentPath) : {};
|
|
70683
|
+
const merged = mergeAuthStoresNoOverwrite2(legacy, current);
|
|
70684
|
+
if (merged.migratedProviderIds.length > 0) {
|
|
70685
|
+
const dir = path93.dirname(currentPath);
|
|
70686
|
+
ensureSafeDirectory2(dir);
|
|
70687
|
+
writeAtomicSync2(currentPath, `${JSON.stringify(merged.data, null, 2)}
|
|
70688
|
+
`, {
|
|
70689
|
+
mode: SECURE_FILE_MODE2,
|
|
70690
|
+
fsync: true
|
|
70691
|
+
});
|
|
70692
|
+
}
|
|
70693
|
+
return createMigrationResult2({
|
|
70694
|
+
legacyPath,
|
|
70695
|
+
currentPath,
|
|
70696
|
+
status: merged.migratedProviderIds.length > 0 ? "migrated" : "unchanged",
|
|
70697
|
+
migratedProviderIds: merged.migratedProviderIds,
|
|
70698
|
+
skippedProviderIds: merged.skippedProviderIds,
|
|
70699
|
+
shouldPrintNotice: options2.notify !== false && merged.migratedProviderIds.length > 0
|
|
70700
|
+
});
|
|
70701
|
+
}
|
|
70702
|
+
function createMigrationResult2(input) {
|
|
70703
|
+
return {
|
|
70704
|
+
legacyPath: input.legacyPath,
|
|
70705
|
+
currentPath: input.currentPath,
|
|
70706
|
+
migratedCount: input.migratedProviderIds.length,
|
|
70707
|
+
skippedCount: input.skippedProviderIds.length,
|
|
70708
|
+
migratedProviderIds: input.migratedProviderIds,
|
|
70709
|
+
skippedProviderIds: input.skippedProviderIds,
|
|
70710
|
+
shouldPrintNotice: input.shouldPrintNotice,
|
|
70711
|
+
status: input.status
|
|
70712
|
+
};
|
|
70713
|
+
}
|
|
70714
|
+
var DEFAULT_AUTH_VALIDATION_TIMEOUT_MS2 = 5e3;
|
|
70715
|
+
async function validateAnthropicCompatibleApiKey2(request) {
|
|
70716
|
+
const controller = new AbortController();
|
|
70717
|
+
const timeout = setTimeout(() => {
|
|
70718
|
+
controller.abort();
|
|
70719
|
+
}, request.timeoutMs ?? DEFAULT_AUTH_VALIDATION_TIMEOUT_MS2);
|
|
70720
|
+
try {
|
|
70721
|
+
const response = await fetch(buildMessagesUrl2(request.baseUrl), {
|
|
70722
|
+
method: "POST",
|
|
70723
|
+
headers: {
|
|
70724
|
+
"anthropic-version": "2023-06-01",
|
|
70725
|
+
"content-type": "application/json",
|
|
70726
|
+
"x-api-key": request.apiKey
|
|
70727
|
+
},
|
|
70728
|
+
body: JSON.stringify({
|
|
70729
|
+
model: "claude-3-5-haiku-20241022",
|
|
70730
|
+
max_tokens: 1,
|
|
70731
|
+
messages: [
|
|
70732
|
+
{
|
|
70733
|
+
role: "user",
|
|
70734
|
+
content: "ping"
|
|
70735
|
+
}
|
|
70736
|
+
]
|
|
70737
|
+
}),
|
|
70738
|
+
signal: controller.signal
|
|
70739
|
+
});
|
|
70740
|
+
if (response.ok) {
|
|
70741
|
+
return { providerId: request.providerId, status: "success" };
|
|
70742
|
+
}
|
|
70743
|
+
if (response.status === 401) {
|
|
70744
|
+
return { providerId: request.providerId, status: "unauthorized" };
|
|
70745
|
+
}
|
|
70746
|
+
if (response.status === 403) {
|
|
70747
|
+
return { providerId: request.providerId, status: "forbidden" };
|
|
70748
|
+
}
|
|
70749
|
+
if (response.status >= 500) {
|
|
70750
|
+
return {
|
|
70751
|
+
providerId: request.providerId,
|
|
70752
|
+
status: "server",
|
|
70753
|
+
detail: `HTTP ${response.status}`
|
|
70754
|
+
};
|
|
70755
|
+
}
|
|
70756
|
+
return {
|
|
70757
|
+
providerId: request.providerId,
|
|
70758
|
+
status: "unknown",
|
|
70759
|
+
detail: `HTTP ${response.status}`
|
|
70760
|
+
};
|
|
70761
|
+
} catch (error512) {
|
|
70762
|
+
if (isAbortError2(error512)) {
|
|
70763
|
+
return { providerId: request.providerId, status: "timeout" };
|
|
70764
|
+
}
|
|
70765
|
+
return {
|
|
70766
|
+
providerId: request.providerId,
|
|
70767
|
+
status: "network",
|
|
70768
|
+
detail: error512 instanceof Error ? error512.message : String(error512)
|
|
70769
|
+
};
|
|
70770
|
+
} finally {
|
|
70771
|
+
clearTimeout(timeout);
|
|
70772
|
+
}
|
|
70773
|
+
}
|
|
70774
|
+
function isAuthValidationSuccess2(result) {
|
|
70775
|
+
return result.status === "success";
|
|
70776
|
+
}
|
|
70777
|
+
function createAuthValidationError2(result) {
|
|
70778
|
+
return new Error(formatAuthValidationFailureMessage2(result));
|
|
70779
|
+
}
|
|
70780
|
+
function buildMessagesUrl2(baseUrl) {
|
|
70781
|
+
return `${baseUrl.replace(/\/+$/, "")}/v1/messages`;
|
|
70782
|
+
}
|
|
70783
|
+
function isAbortError2(error512) {
|
|
70784
|
+
return error512 instanceof DOMException && error512.name === "AbortError";
|
|
70785
|
+
}
|
|
70786
|
+
var CLAUDE_ZAI_PROVIDER_ID2 = "Claude Code with Z.AI GLM";
|
|
70787
|
+
var CLAUDE_KIMI_PROVIDER_ID2 = "Claude Code with Moonshot Kimi";
|
|
70788
|
+
var AUTH_PROVIDER_DEFINITIONS2 = {
|
|
70789
|
+
"claude-zai": {
|
|
70790
|
+
providerId: CLAUDE_ZAI_PROVIDER_ID2,
|
|
70791
|
+
baseUrl: CLI_BACKENDS2["claude-zai"].defaultEnv.ANTHROPIC_BASE_URL,
|
|
70792
|
+
env: CLI_BACKENDS2["claude-zai"].defaultEnv
|
|
70793
|
+
},
|
|
70794
|
+
"claude-kimi": {
|
|
70795
|
+
providerId: CLAUDE_KIMI_PROVIDER_ID2,
|
|
70796
|
+
baseUrl: CLI_BACKENDS2["claude-kimi"].defaultEnv.ANTHROPIC_BASE_URL,
|
|
70797
|
+
env: CLI_BACKENDS2["claude-kimi"].defaultEnv
|
|
70798
|
+
}
|
|
70799
|
+
};
|
|
70800
|
+
async function resolveAuthEnv2(cli, deps) {
|
|
70801
|
+
const provider = AUTH_PROVIDER_DEFINITIONS2[cli];
|
|
70802
|
+
if (!provider) return {};
|
|
70803
|
+
await migrateLegacyAuthStore2();
|
|
70804
|
+
const auth = deps?.authService ?? createAuthService2({ authPath: DEFAULT_AUTH_PATH2 });
|
|
70805
|
+
const token = await auth.getApiKey(provider.providerId);
|
|
70806
|
+
if (!token) {
|
|
70807
|
+
throw new Error(formatMissingAuthKeyMessage2({ cli, providerId: provider.providerId }));
|
|
70808
|
+
}
|
|
70809
|
+
const validation = await validateAnthropicCompatibleApiKey2({
|
|
70810
|
+
providerId: provider.providerId,
|
|
70811
|
+
apiKey: token,
|
|
70812
|
+
baseUrl: provider.baseUrl
|
|
70813
|
+
});
|
|
70814
|
+
if (!isAuthValidationSuccess2(validation)) {
|
|
70815
|
+
const failure = {
|
|
70816
|
+
providerId: validation.providerId,
|
|
70817
|
+
status: validation.status,
|
|
70818
|
+
detail: validation.detail
|
|
70819
|
+
};
|
|
70820
|
+
throw createAuthValidationError2(failure);
|
|
70821
|
+
}
|
|
70822
|
+
return { ...provider.env, ANTHROPIC_AUTH_TOKEN: token };
|
|
70823
|
+
}
|
|
70824
|
+
var GLOBAL_OPTIONS_VERSION2 = 1;
|
|
70825
|
+
var GLOBAL_OPTIONS_FILE_NAME2 = "settings.json";
|
|
70826
|
+
var LOCK_DIR_NAME2 = "settings.json.lock";
|
|
70827
|
+
var LOCK_OWNER_FILE_NAME2 = "owner";
|
|
70828
|
+
var TEMP_FILE_PREFIX2 = `.tmp-${GLOBAL_OPTIONS_FILE_NAME2}-`;
|
|
70829
|
+
function createGlobalOptionsStore2(deps = {}) {
|
|
70830
|
+
const dataDir = deps.dataDir ?? getFleetDataDir2();
|
|
70831
|
+
const optionsPath = path93.join(dataDir, GLOBAL_OPTIONS_FILE_NAME2);
|
|
70832
|
+
const lockDir = path93.join(dataDir, LOCK_DIR_NAME2);
|
|
70833
|
+
const store22 = createDurableJsonStore2({
|
|
70834
|
+
filePath: optionsPath,
|
|
70835
|
+
lockDir,
|
|
70836
|
+
lockOwnerFileName: LOCK_OWNER_FILE_NAME2,
|
|
70837
|
+
sanitize: (value) => sanitizeGlobalOptionsData2(value).data,
|
|
70838
|
+
sensitivity: "sensitive",
|
|
70839
|
+
timeoutMs: deps.timeoutMs,
|
|
70840
|
+
staleLockMs: deps.staleLockMs,
|
|
70841
|
+
tempCleanupPrefix: TEMP_FILE_PREFIX2,
|
|
70842
|
+
now: deps.now
|
|
70843
|
+
});
|
|
70844
|
+
return {
|
|
70845
|
+
path: optionsPath,
|
|
70846
|
+
load: () => store22.load(),
|
|
70847
|
+
save: (data) => store22.save(sanitizeGlobalOptionsData2(data).data),
|
|
70848
|
+
update: (mutate) => store22.update((current) => sanitizeGlobalOptionsData2(mutate(current)).data)
|
|
70849
|
+
};
|
|
70850
|
+
}
|
|
70851
|
+
function createEmptyGlobalOptionsData2() {
|
|
70852
|
+
return {
|
|
70853
|
+
version: GLOBAL_OPTIONS_VERSION2
|
|
70854
|
+
};
|
|
70855
|
+
}
|
|
70856
|
+
function sanitizeGlobalOptionsData2(value) {
|
|
70857
|
+
if (!isRecord32(value)) {
|
|
70858
|
+
return { data: createEmptyGlobalOptionsData2(), changed: true };
|
|
70859
|
+
}
|
|
70860
|
+
if (value.version !== GLOBAL_OPTIONS_VERSION2) {
|
|
70861
|
+
return { data: createEmptyGlobalOptionsData2(), changed: true };
|
|
70862
|
+
}
|
|
70863
|
+
const data = {
|
|
70864
|
+
version: GLOBAL_OPTIONS_VERSION2,
|
|
70865
|
+
...typeof value.replaceSystemPrompt === "boolean" ? { replaceSystemPrompt: value.replaceSystemPrompt } : {},
|
|
70866
|
+
...typeof value.enableMetaphor === "boolean" ? { enableMetaphor: value.enableMetaphor } : {}
|
|
70867
|
+
};
|
|
70868
|
+
const allowedKeys = /* @__PURE__ */ new Set(["version", "replaceSystemPrompt", "enableMetaphor"]);
|
|
70869
|
+
const changed = Object.keys(value).some((key) => !allowedKeys.has(key)) || "replaceSystemPrompt" in value && typeof value.replaceSystemPrompt !== "boolean" || "enableMetaphor" in value && typeof value.enableMetaphor !== "boolean";
|
|
70870
|
+
return { data, changed };
|
|
70871
|
+
}
|
|
70872
|
+
function isRecord32(value) {
|
|
70873
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
70874
|
+
}
|
|
70875
|
+
function createGlobalOptionsService2(deps = {}) {
|
|
70876
|
+
const store22 = deps.store ?? createGlobalOptionsStore2({ dataDir: deps.dataDir });
|
|
70877
|
+
return {
|
|
70878
|
+
load: () => store22.load(),
|
|
70879
|
+
save: (data) => {
|
|
70880
|
+
store22.save(data);
|
|
70881
|
+
return store22.load();
|
|
70882
|
+
},
|
|
70883
|
+
update: (mutate) => updateGlobalOptions2(store22, mutate)
|
|
70884
|
+
};
|
|
70885
|
+
}
|
|
70886
|
+
function updateGlobalOptions2(store22, mutate) {
|
|
70887
|
+
return store22.update(mutate);
|
|
70888
|
+
}
|
|
70889
|
+
function createInfraServices2(deps = {}) {
|
|
70890
|
+
const globalOptionsService = createGlobalOptionsService2();
|
|
70891
|
+
const authService = createAuthService2({ authPath: deps.authPath ?? DEFAULT_AUTH_PATH2 });
|
|
70892
|
+
return {
|
|
70893
|
+
authService,
|
|
70894
|
+
globalOptionsService
|
|
70895
|
+
};
|
|
70896
|
+
}
|
|
70376
70897
|
function readFleetConsoleRelease() {
|
|
70377
70898
|
const requireFromHere2 = createRequire(import.meta.url);
|
|
70378
70899
|
const packageJsonPath = requireFromHere2.resolve("../package.json");
|
|
@@ -70384,17 +70905,34 @@ function readFleetConsoleRelease() {
|
|
|
70384
70905
|
}
|
|
70385
70906
|
return { channel: "stable", version: version22, packageRoot };
|
|
70386
70907
|
}
|
|
70387
|
-
var
|
|
70908
|
+
var LOCK_DIR_NAME22 = "fleet-console";
|
|
70909
|
+
var CONSOLE_RUNTIME_DIR_NAME = "console";
|
|
70388
70910
|
var LOCK_FILE_NAME = "console.lock";
|
|
70911
|
+
var CONSOLE_DATA_DIR_NAME = "console";
|
|
70912
|
+
var CONSOLE_STATE_FILE_NAME = "state.json";
|
|
70913
|
+
var CONSOLE_CAPTURES_DIR_NAME = "captures";
|
|
70389
70914
|
function createConsolePaths(deps = {}) {
|
|
70390
70915
|
const env = deps.env ?? process.env;
|
|
70391
70916
|
const base = env.FLEET_CONSOLE_DIR ?? defaultConsoleBaseDir(deps);
|
|
70392
70917
|
return { dir: base, lockFile: path93__default.join(base, LOCK_FILE_NAME) };
|
|
70393
70918
|
}
|
|
70919
|
+
function createConsoleDataPaths(deps = {}) {
|
|
70920
|
+
const dir = path93__default.join(deps.fleetDataDir ?? getFleetDataDir2(), CONSOLE_DATA_DIR_NAME);
|
|
70921
|
+
return {
|
|
70922
|
+
dir,
|
|
70923
|
+
stateFile: path93__default.join(dir, CONSOLE_STATE_FILE_NAME),
|
|
70924
|
+
capturesDir: path93__default.join(dir, CONSOLE_CAPTURES_DIR_NAME)
|
|
70925
|
+
};
|
|
70926
|
+
}
|
|
70394
70927
|
function defaultConsoleBaseDir(deps) {
|
|
70928
|
+
let release2;
|
|
70929
|
+
const channel = deps.channel ?? (release2 = readFleetConsoleRelease()).channel;
|
|
70930
|
+
if (channel === "local") {
|
|
70931
|
+
const packageRoot = deps.packageRoot ?? (release2 ??= readFleetConsoleRelease()).packageRoot;
|
|
70932
|
+
return path93__default.join(path93__default.resolve(packageRoot, "..", ".."), ".fleet", CONSOLE_RUNTIME_DIR_NAME);
|
|
70933
|
+
}
|
|
70395
70934
|
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}`);
|
|
70935
|
+
return path93__default.join(os22__default.tmpdir(), `${LOCK_DIR_NAME22}-${uid}-${channel}`);
|
|
70398
70936
|
}
|
|
70399
70937
|
var FLEET_PROTOCOL_GATE_PROMPT2 = String.raw`# Protocol Gate
|
|
70400
70938
|
|
|
@@ -70787,6 +71325,8 @@ function createClaudeFamilyCliDefinition2(options2) {
|
|
|
70787
71325
|
lineTerminator: "\r",
|
|
70788
71326
|
multilineStrategy: "paste-mode"
|
|
70789
71327
|
},
|
|
71328
|
+
// Claude Code 계열은 세션 이름 변경 슬래시 명령 `/rename`을 지원한다.
|
|
71329
|
+
renameCommand: "/rename",
|
|
70790
71330
|
terminalName: "xterm-256color"
|
|
70791
71331
|
};
|
|
70792
71332
|
}
|
|
@@ -70810,7 +71350,7 @@ var codexCli2 = {
|
|
|
70810
71350
|
async createProfile(options2) {
|
|
70811
71351
|
const { bin, prefixArgs } = resolveBinary2("codex", "CODEX_BIN", options2.env);
|
|
70812
71352
|
return {
|
|
70813
|
-
args: [...prefixArgs, "--no-alt-screen", ...buildModelArgs22(options2.model)],
|
|
71353
|
+
args: [...prefixArgs, ...buildResumeArgs4(options2.resumeSessionId), "--no-alt-screen", ...buildModelArgs22(options2.model)],
|
|
70814
71354
|
bin,
|
|
70815
71355
|
binPrefixArgs: prefixArgs,
|
|
70816
71356
|
cwd: options2.cwd,
|
|
@@ -70822,10 +71362,15 @@ var codexCli2 = {
|
|
|
70822
71362
|
lineTerminator: "\r",
|
|
70823
71363
|
multilineStrategy: "paste-mode"
|
|
70824
71364
|
},
|
|
71365
|
+
// Codex CLI도 세션 이름 변경 슬래시 명령 `/rename`을 지원한다.
|
|
71366
|
+
renameCommand: "/rename",
|
|
70825
71367
|
terminalName: "xterm-256color"
|
|
70826
71368
|
};
|
|
70827
71369
|
}
|
|
70828
71370
|
};
|
|
71371
|
+
function buildResumeArgs4(resumeSessionId) {
|
|
71372
|
+
return resumeSessionId === void 0 ? [] : ["resume", resumeSessionId];
|
|
71373
|
+
}
|
|
70829
71374
|
function buildModelArgs22(model) {
|
|
70830
71375
|
return model === void 0 ? [] : ["--model", model];
|
|
70831
71376
|
}
|
|
@@ -70842,7 +71387,8 @@ async function resolveAgentCliProfile2(env, cwd, options2 = {}) {
|
|
|
70842
71387
|
authService: options2.authService,
|
|
70843
71388
|
cwd,
|
|
70844
71389
|
env,
|
|
70845
|
-
model: options2.model
|
|
71390
|
+
model: options2.model,
|
|
71391
|
+
resumeSessionId: options2.resumeSessionId
|
|
70846
71392
|
});
|
|
70847
71393
|
}
|
|
70848
71394
|
function resolveAgentCliId2(env, options2 = {}) {
|
|
@@ -70886,6 +71432,20 @@ var AGENT_CLI_INJECTION_CAPABILITIES2 = {
|
|
|
70886
71432
|
function getAgentCliInjectionCapability2(cliId) {
|
|
70887
71433
|
return AGENT_CLI_INJECTION_CAPABILITIES2[cliId];
|
|
70888
71434
|
}
|
|
71435
|
+
function createSessionCaptureHookExec(deps) {
|
|
71436
|
+
const args = deps.tsxLoader ? [
|
|
71437
|
+
"--import",
|
|
71438
|
+
pathToFileURL2(deps.tsxLoader).href,
|
|
71439
|
+
deps.entryPath,
|
|
71440
|
+
"hook",
|
|
71441
|
+
"capture-session",
|
|
71442
|
+
deps.provider
|
|
71443
|
+
] : [deps.entryPath, "hook", "capture-session", deps.provider];
|
|
71444
|
+
return {
|
|
71445
|
+
command: deps.execPath ?? process6.execPath,
|
|
71446
|
+
args
|
|
71447
|
+
};
|
|
71448
|
+
}
|
|
70889
71449
|
function buildHostCarrierModelDefaults22(config22) {
|
|
70890
71450
|
const cliType = resolveAgentCliType22(config22.id, config22.defaultCliType);
|
|
70891
71451
|
const cliDefaults = buildCarrierModelDefaults2(config22, cliType);
|
|
@@ -70915,6 +71475,7 @@ function buildClaudeNativeSubagentPlan22(registry32) {
|
|
|
70915
71475
|
function buildClaudeNativeArgs2(context) {
|
|
70916
71476
|
const systemPromptArg = context.replaceSystemPrompt ? "--system-prompt-file" : "--append-system-prompt-file";
|
|
70917
71477
|
return [
|
|
71478
|
+
...buildResumeArgs22(context.resumeSessionId),
|
|
70918
71479
|
systemPromptArg,
|
|
70919
71480
|
requireSystemPromptFile2(context),
|
|
70920
71481
|
...context.pluginRoots.flatMap((pluginRoot) => [
|
|
@@ -70925,6 +71486,9 @@ function buildClaudeNativeArgs2(context) {
|
|
|
70925
71486
|
"--dangerously-skip-permissions"
|
|
70926
71487
|
];
|
|
70927
71488
|
}
|
|
71489
|
+
function buildResumeArgs22(resumeSessionId) {
|
|
71490
|
+
return resumeSessionId === void 0 ? [] : ["--resume", resumeSessionId];
|
|
71491
|
+
}
|
|
70928
71492
|
function buildClaudeMcpConfig2(servers) {
|
|
70929
71493
|
return JSON.stringify({
|
|
70930
71494
|
mcpServers: Object.fromEntries(
|
|
@@ -70982,20 +71546,32 @@ function escapeTomlMultilineString2(value) {
|
|
|
70982
71546
|
});
|
|
70983
71547
|
return result;
|
|
70984
71548
|
}
|
|
71549
|
+
function buildPosixShellCommand2(values) {
|
|
71550
|
+
return values.map(posixShellQuote2).join(" ");
|
|
71551
|
+
}
|
|
71552
|
+
function posixShellQuote2(value) {
|
|
71553
|
+
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
71554
|
+
}
|
|
70985
71555
|
var CODEX_TOOL_TIMEOUT_SEC2 = 1800;
|
|
70986
71556
|
function buildCodexNativeArgs2(context) {
|
|
70987
71557
|
const profileName = requireCodexProfileName2(context);
|
|
70988
71558
|
const args = [
|
|
71559
|
+
...buildResumeArgs32(context.resumeSessionId),
|
|
70989
71560
|
"--enable",
|
|
70990
71561
|
"plugins",
|
|
70991
71562
|
"--enable",
|
|
70992
71563
|
"child_agents_md",
|
|
71564
|
+
"--enable",
|
|
71565
|
+
"hooks",
|
|
70993
71566
|
"--profile",
|
|
70994
71567
|
profileName,
|
|
70995
71568
|
"-c",
|
|
70996
71569
|
'approval_policy="never"',
|
|
70997
71570
|
"-c",
|
|
70998
|
-
'sandbox_mode="danger-full-access"'
|
|
71571
|
+
'sandbox_mode="danger-full-access"',
|
|
71572
|
+
// hook 신뢰 프롬프트("Hooks need review")를 fleet 관리 세션에서 건너뛴다. bypass_hook_trust는
|
|
71573
|
+
// config 키가 아니라 전용 CLI 플래그이므로 -c override가 아닌 플래그로 전달해야 한다.
|
|
71574
|
+
"--dangerously-bypass-hook-trust"
|
|
70999
71575
|
];
|
|
71000
71576
|
for (const server of context.mcpServers) {
|
|
71001
71577
|
const prefix = `mcp_servers.${server.name}`;
|
|
@@ -71011,6 +71587,9 @@ function buildCodexNativeArgs2(context) {
|
|
|
71011
71587
|
}
|
|
71012
71588
|
return args;
|
|
71013
71589
|
}
|
|
71590
|
+
function buildResumeArgs32(resumeSessionId) {
|
|
71591
|
+
return resumeSessionId === void 0 ? [] : ["resume", resumeSessionId];
|
|
71592
|
+
}
|
|
71014
71593
|
function requireCodexProfileName2(context) {
|
|
71015
71594
|
if (context.codexProfileName) return context.codexProfileName;
|
|
71016
71595
|
throw new Error("Codex profile name is required for native injection");
|
|
@@ -71221,20 +71800,38 @@ function claudeHooks2(options2) {
|
|
|
71221
71800
|
if (!hookExec) {
|
|
71222
71801
|
throw new Error("Fleet Claude session hook command is required");
|
|
71223
71802
|
}
|
|
71803
|
+
const userPromptSubmitExecs = [options2.captureSessionHookExec, options2.turnStartHookExec].filter((exec) => exec !== void 0);
|
|
71804
|
+
const stopExecs = [options2.turnEndHookExec].filter((exec) => exec !== void 0);
|
|
71224
71805
|
return {
|
|
71225
71806
|
hooks: {
|
|
71226
71807
|
SessionStart: [{
|
|
71227
|
-
hooks: [
|
|
71228
|
-
|
|
71229
|
-
|
|
71230
|
-
|
|
71231
|
-
|
|
71232
|
-
|
|
71808
|
+
hooks: [claudeCommandHook2(hookExec)]
|
|
71809
|
+
}],
|
|
71810
|
+
...userPromptSubmitExecs.length > 0 ? {
|
|
71811
|
+
UserPromptSubmit: [{
|
|
71812
|
+
hooks: userPromptSubmitExecs.map(claudeCommandHook2)
|
|
71813
|
+
}]
|
|
71814
|
+
} : {},
|
|
71815
|
+
...stopExecs.length > 0 ? {
|
|
71816
|
+
Stop: [{
|
|
71817
|
+
hooks: stopExecs.map(claudeCommandHook2)
|
|
71233
71818
|
}]
|
|
71234
|
-
}
|
|
71819
|
+
} : {}
|
|
71235
71820
|
}
|
|
71236
71821
|
};
|
|
71237
71822
|
}
|
|
71823
|
+
function claudeCommandHook2(hookExec) {
|
|
71824
|
+
if (!hookExec) {
|
|
71825
|
+
throw new Error("Fleet Claude session hook command is required");
|
|
71826
|
+
}
|
|
71827
|
+
return {
|
|
71828
|
+
// exec 형식: command는 직접 spawn되는 실행 파일, args는 셸 토크나이징 없이 그대로 전달된다.
|
|
71829
|
+
// Windows cmd/powershell의 따옴표 규칙과 무관하게 동작하며 공백 포함 경로도 안전하다.
|
|
71830
|
+
args: [...hookExec.args],
|
|
71831
|
+
command: hookExec.command,
|
|
71832
|
+
type: "command"
|
|
71833
|
+
};
|
|
71834
|
+
}
|
|
71238
71835
|
function claudeAgentFile2(subagent) {
|
|
71239
71836
|
const frontmatter = [
|
|
71240
71837
|
"---",
|
|
@@ -71744,7 +72341,7 @@ function homeMarketplaceTarget2(fleetRoot) {
|
|
|
71744
72341
|
}
|
|
71745
72342
|
function projectMarketplaceTarget2(cwd) {
|
|
71746
72343
|
const projectFleetRoot = resolveProjectFleetRoot2(cwd);
|
|
71747
|
-
const hash22 =
|
|
72344
|
+
const hash22 = crypto5.createHash("sha256").update(path93__default.resolve(cwd, ".fleet")).digest("hex").slice(0, 12);
|
|
71748
72345
|
return {
|
|
71749
72346
|
flat: true,
|
|
71750
72347
|
name: `${FLEET_PROJECT_MARKETPLACE_NAME_PREFIX2}-${hash22}`,
|
|
@@ -71770,7 +72367,6 @@ function renderPluginRoot2(pluginRoot, bundle, options2, fleetRoot) {
|
|
|
71770
72367
|
const stagedPluginRoot = path93__default.join(stageParent, path93__default.basename(pluginRoot));
|
|
71771
72368
|
try {
|
|
71772
72369
|
ensurePrivateDir2(stagedPluginRoot, stagedPluginRoot);
|
|
71773
|
-
writePrivateJson2(path93__default.join(stagedPluginRoot, ".codex-plugin", "plugin.json"), codexManifest2(bundle), stagedPluginRoot);
|
|
71774
72370
|
writePrivateJson2(path93__default.join(stagedPluginRoot, ".claude-plugin", "plugin.json"), claudeManifest2(bundle), stagedPluginRoot);
|
|
71775
72371
|
switch (bundle.source) {
|
|
71776
72372
|
case "asset":
|
|
@@ -71785,6 +72381,7 @@ function renderPluginRoot2(pluginRoot, bundle, options2, fleetRoot) {
|
|
|
71785
72381
|
renderGlobalPluginRoot2(stagedPluginRoot, fleetRoot);
|
|
71786
72382
|
break;
|
|
71787
72383
|
}
|
|
72384
|
+
writePrivateJson2(path93__default.join(stagedPluginRoot, ".codex-plugin", "plugin.json"), codexManifest2(bundle, stagedPluginRoot), stagedPluginRoot);
|
|
71788
72385
|
removePrivatePath2(pluginRoot, parentRoot);
|
|
71789
72386
|
renameSync5(stagedPluginRoot, pluginRoot);
|
|
71790
72387
|
} finally {
|
|
@@ -71813,7 +72410,7 @@ function pruneMarketplaceRoot2(target) {
|
|
|
71813
72410
|
}
|
|
71814
72411
|
}
|
|
71815
72412
|
function buildContentHash2(target) {
|
|
71816
|
-
const hash22 =
|
|
72413
|
+
const hash22 = crypto5.createHash("sha256");
|
|
71817
72414
|
for (const filePath of listRenderableFiles2(target)) {
|
|
71818
72415
|
const relativePath2 = path93__default.relative(target.root, filePath);
|
|
71819
72416
|
hash22.update(relativePath2);
|
|
@@ -71916,14 +72513,36 @@ function marketplacePluginPath2(target, bundle) {
|
|
|
71916
72513
|
if (target.flat) return `./${FLAT_PLUGIN_DIR_NAME2}`;
|
|
71917
72514
|
return `./${PLUGIN_BUNDLES_DIR_NAME2}/${bundle.directoryName}`;
|
|
71918
72515
|
}
|
|
71919
|
-
function codexManifest2(bundle) {
|
|
72516
|
+
function codexManifest2(bundle, pluginRoot) {
|
|
71920
72517
|
return {
|
|
71921
72518
|
name: bundle.name,
|
|
71922
|
-
version:
|
|
72519
|
+
version: codexManifestVersion2(bundle, pluginRoot),
|
|
71923
72520
|
description: bundle.description,
|
|
71924
72521
|
skills: "./skills/"
|
|
71925
72522
|
};
|
|
71926
72523
|
}
|
|
72524
|
+
function codexManifestVersion2(bundle, pluginRoot) {
|
|
72525
|
+
const hash22 = crypto5.createHash("sha256");
|
|
72526
|
+
hash22.update(bundle.name);
|
|
72527
|
+
hash22.update("\0");
|
|
72528
|
+
hash22.update(bundle.description);
|
|
72529
|
+
hash22.update("\0");
|
|
72530
|
+
for (const filePath of listCodexEffectivePluginFiles2(pluginRoot)) {
|
|
72531
|
+
const relativePath2 = path93__default.relative(pluginRoot, filePath);
|
|
72532
|
+
hash22.update(relativePath2);
|
|
72533
|
+
hash22.update("\0");
|
|
72534
|
+
hash22.update(readFileSync8(filePath));
|
|
72535
|
+
hash22.update("\0");
|
|
72536
|
+
}
|
|
72537
|
+
return `0.0.0+${hash22.digest("hex").slice(0, 12)}`;
|
|
72538
|
+
}
|
|
72539
|
+
function listCodexEffectivePluginFiles2(pluginRoot) {
|
|
72540
|
+
const skillsPath = path93__default.join(pluginRoot, "skills");
|
|
72541
|
+
if (!existsSync8(skillsPath)) return [];
|
|
72542
|
+
const files = [];
|
|
72543
|
+
collectRenderableFiles2(pluginRoot, skillsPath, files, /* @__PURE__ */ new Set());
|
|
72544
|
+
return files.sort();
|
|
72545
|
+
}
|
|
71927
72546
|
function claudeManifest2(bundle) {
|
|
71928
72547
|
return {
|
|
71929
72548
|
name: bundle.name,
|
|
@@ -71943,7 +72562,7 @@ async function injectAgentCliProfile2(profile, options2) {
|
|
|
71943
72562
|
const injectTone = options2.enableMetaphor ?? false;
|
|
71944
72563
|
const endpoint = await options2.dedicatedMcpSession.getEndpoint();
|
|
71945
72564
|
const startupDefinitions = buildStartupNativeDefinitions2(profile.id, options2.carrierRuntime);
|
|
71946
|
-
const tokenLabel = options2.mcpSessionLabel ?? `agent:${profile.id}:${
|
|
72565
|
+
const tokenLabel = options2.mcpSessionLabel ?? `agent:${profile.id}:${crypto5.randomUUID()}`;
|
|
71947
72566
|
const tokens = await options2.dedicatedMcpSession.issueSessionToken({ cwd: profile.cwd, label: tokenLabel });
|
|
71948
72567
|
const mcpServers = buildAgentCliMcpServerConfigs2(endpoint.servers, tokens);
|
|
71949
72568
|
const doctrine = options2.buildSystemPrompt(injectTone);
|
|
@@ -71957,11 +72576,18 @@ async function injectAgentCliProfile2(profile, options2) {
|
|
|
71957
72576
|
cwd: profile.cwd,
|
|
71958
72577
|
dataDir: options2.dataDir,
|
|
71959
72578
|
rootDir: options2.pluginRootDir,
|
|
72579
|
+
captureSessionHookExec: options2.captureSessionHookExec,
|
|
72580
|
+
turnStartHookExec: options2.turnStartHookExec,
|
|
72581
|
+
turnEndHookExec: options2.turnEndHookExec,
|
|
71960
72582
|
hookExec: startupDefinitions.host === "claude" ? requireHookExec2(options2.hookExec) : void 0,
|
|
71961
72583
|
withMarketplaceLock: options2.withMarketplaceLock
|
|
71962
72584
|
});
|
|
71963
72585
|
const codexPluginKeys = plugin.codexRegistrations.map((registration) => `${registration.pluginName}@${registration.marketplaceName}`);
|
|
71964
|
-
const codexProfile = profile.id === "codex" ? writeCodexFleetProfile2(profile.env, doctrine, codexPluginKeys,
|
|
72586
|
+
const codexProfile = profile.id === "codex" ? writeCodexFleetProfile2(profile.env, doctrine, codexPluginKeys, {
|
|
72587
|
+
captureSessionHookExec: options2.captureSessionHookExec,
|
|
72588
|
+
turnStartHookExec: options2.turnStartHookExec,
|
|
72589
|
+
turnEndHookExec: options2.turnEndHookExec
|
|
72590
|
+
}, (cleanup2) => tempCleanups.push(cleanup2)) : void 0;
|
|
71965
72591
|
const launchWarnings = [];
|
|
71966
72592
|
for (const registration of plugin.codexRegistrations) {
|
|
71967
72593
|
const registrationWarning = await ensureCodexPluginRegistered2(registration, {
|
|
@@ -71988,13 +72614,14 @@ async function injectAgentCliProfile2(profile, options2) {
|
|
|
71988
72614
|
pluginRoot: plugin.pluginRoot,
|
|
71989
72615
|
pluginRoots: plugin.pluginRoots,
|
|
71990
72616
|
codexProfileName: codexProfile?.profileName,
|
|
71991
|
-
replaceSystemPrompt: options2.replaceSystemPrompt ??
|
|
72617
|
+
replaceSystemPrompt: options2.replaceSystemPrompt ?? false,
|
|
72618
|
+
resumeSessionId: options2.resumeSessionId,
|
|
71992
72619
|
systemPromptFile
|
|
71993
72620
|
};
|
|
71994
72621
|
const injectedArgs = buildAgentCliArgs2(capability.builderId, context);
|
|
71995
72622
|
return {
|
|
71996
72623
|
...profile,
|
|
71997
|
-
args:
|
|
72624
|
+
args: mergeAgentCliArgs2(profile, capability.builderId, context, injectedArgs),
|
|
71998
72625
|
cleanup,
|
|
71999
72626
|
launchWarnings: [...profile.launchWarnings ?? [], ...launchWarnings]
|
|
72000
72627
|
};
|
|
@@ -72036,11 +72663,11 @@ function writeSystemPromptFile2(cliId, systemPrompt, onCleanup) {
|
|
|
72036
72663
|
chmodBestEffort22(filePath, SYSTEM_PROMPT_FILE_MODE2);
|
|
72037
72664
|
return filePath;
|
|
72038
72665
|
}
|
|
72039
|
-
function writeCodexFleetProfile2(env, doctrine, pluginKeys, onCleanup) {
|
|
72666
|
+
function writeCodexFleetProfile2(env, doctrine, pluginKeys, hookExecs, onCleanup) {
|
|
72040
72667
|
const codexHome = env.CODEX_HOME ?? path93__default.join(env.HOME ?? os22__default.homedir(), ".codex");
|
|
72041
72668
|
mkdirSync8(codexHome, { recursive: true });
|
|
72042
72669
|
pruneStaleCodexFleetProfiles2(codexHome);
|
|
72043
|
-
const profileName = `fleet-${
|
|
72670
|
+
const profileName = `fleet-${crypto5.randomUUID()}`;
|
|
72044
72671
|
const profilePath = path93__default.join(codexHome, `${profileName}.config.toml`);
|
|
72045
72672
|
onCleanup(() => rmBestEffort2(profilePath));
|
|
72046
72673
|
writeFileNoFollow22(profilePath, [
|
|
@@ -72055,11 +72682,33 @@ function writeCodexFleetProfile2(env, doctrine, pluginKeys, onCleanup) {
|
|
|
72055
72682
|
`[plugins."${escapeTomlBasicString22(pluginKey)}"]`,
|
|
72056
72683
|
"enabled = true",
|
|
72057
72684
|
""
|
|
72058
|
-
])
|
|
72685
|
+
]),
|
|
72686
|
+
...codexHooksConfig2(hookExecs)
|
|
72059
72687
|
].join("\n"));
|
|
72060
72688
|
chmodBestEffort22(profilePath, SYSTEM_PROMPT_FILE_MODE2);
|
|
72061
72689
|
return { profileName, profilePath };
|
|
72062
72690
|
}
|
|
72691
|
+
function codexHooksConfig2(hookExecs) {
|
|
72692
|
+
const userPromptSubmitExecs = [hookExecs.captureSessionHookExec, hookExecs.turnStartHookExec].filter((exec) => exec !== void 0);
|
|
72693
|
+
const stopExecs = [hookExecs.turnEndHookExec].filter((exec) => exec !== void 0);
|
|
72694
|
+
if (userPromptSubmitExecs.length === 0 && stopExecs.length === 0) return [];
|
|
72695
|
+
const lines = ["[hooks]"];
|
|
72696
|
+
if (userPromptSubmitExecs.length > 0) {
|
|
72697
|
+
lines.push(`UserPromptSubmit = ${codexHookHandlersInline2(userPromptSubmitExecs)}`);
|
|
72698
|
+
}
|
|
72699
|
+
if (stopExecs.length > 0) {
|
|
72700
|
+
lines.push(`Stop = ${codexHookHandlersInline2(stopExecs)}`);
|
|
72701
|
+
}
|
|
72702
|
+
lines.push("");
|
|
72703
|
+
return lines;
|
|
72704
|
+
}
|
|
72705
|
+
function codexHookHandlersInline2(execs) {
|
|
72706
|
+
const handlers = execs.map((exec) => {
|
|
72707
|
+
const command22 = buildPosixShellCommand2([exec.command, ...exec.args]);
|
|
72708
|
+
return `{ type = "command", command = "${escapeTomlBasicString22(command22)}" }`;
|
|
72709
|
+
}).join(", ");
|
|
72710
|
+
return `[{ hooks = [${handlers}] }]`;
|
|
72711
|
+
}
|
|
72063
72712
|
function writeFileNoFollow22(filePath, content) {
|
|
72064
72713
|
const flags = constants8.O_WRONLY | constants8.O_CREAT | constants8.O_TRUNC | constants8.O_NOFOLLOW;
|
|
72065
72714
|
const fd = openSync8(filePath, flags, SYSTEM_PROMPT_FILE_MODE2);
|
|
@@ -72132,6 +72781,24 @@ function buildAgentCliArgs2(builderId, context) {
|
|
|
72132
72781
|
return buildCodexNativeArgs2(context);
|
|
72133
72782
|
}
|
|
72134
72783
|
}
|
|
72784
|
+
function mergeAgentCliArgs2(profile, builderId, context, injectedArgs) {
|
|
72785
|
+
if (builderId !== "codex-native" || context.resumeSessionId === void 0) {
|
|
72786
|
+
return [...profile.args, ...injectedArgs];
|
|
72787
|
+
}
|
|
72788
|
+
const resumeSessionId = context.resumeSessionId;
|
|
72789
|
+
const prefixLength = profile.binPrefixArgs?.length ?? 0;
|
|
72790
|
+
const codexResumeArgs = ["resume", resumeSessionId];
|
|
72791
|
+
const injectedTail = injectedArgs.slice(codexResumeArgs.length);
|
|
72792
|
+
return [
|
|
72793
|
+
...profile.args.slice(0, prefixLength),
|
|
72794
|
+
...codexResumeArgs,
|
|
72795
|
+
...profile.args.slice(prefixLength).filter((arg, index, args) => !isCodexResumeArgAt2(args, index, resumeSessionId)),
|
|
72796
|
+
...injectedTail
|
|
72797
|
+
];
|
|
72798
|
+
}
|
|
72799
|
+
function isCodexResumeArgAt2(args, index, resumeSessionId) {
|
|
72800
|
+
return args[index] === "resume" && args[index + 1] === resumeSessionId || args[index] === resumeSessionId && args[index - 1] === "resume";
|
|
72801
|
+
}
|
|
72135
72802
|
function createOnceCleanup2(cleanup) {
|
|
72136
72803
|
let cleaned = false;
|
|
72137
72804
|
return () => {
|
|
@@ -72315,387 +72982,6 @@ function applyMessagePolicy2(text, policy) {
|
|
|
72315
72982
|
submit: policy.lineTerminator
|
|
72316
72983
|
};
|
|
72317
72984
|
}
|
|
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
72985
|
var FLEET_WIKI_ENTRY_BEGIN = "<<<FLEET_WIKI_ENTRY_BEGIN";
|
|
72700
72986
|
var FLEET_WIKI_ENTRY_END = "<<<FLEET_WIKI_ENTRY_END>>>";
|
|
72701
72987
|
var FLEET_WIKI_RAW_SOURCE_BEGIN = "<<<FLEET_WIKI_RAW_SOURCE_BEGIN";
|
|
@@ -73722,7 +74008,7 @@ function stripLeadingFrontmatter(body) {
|
|
|
73722
74008
|
return stripped ? next : body;
|
|
73723
74009
|
}
|
|
73724
74010
|
function computeContentHash(content) {
|
|
73725
|
-
return
|
|
74011
|
+
return crypto5.createHash("sha256").update(content, "utf8").digest("hex").slice(0, 8);
|
|
73726
74012
|
}
|
|
73727
74013
|
function assertWithinRawDir(absolutePath, paths) {
|
|
73728
74014
|
const relative2 = path93__default.relative(paths.rawDir, absolutePath);
|
|
@@ -73935,7 +74221,7 @@ async function writeAtomic(filePath, content, paths) {
|
|
|
73935
74221
|
await ensureMemoryRoot(paths);
|
|
73936
74222
|
const tempPath = path93__default.join(
|
|
73937
74223
|
path93__default.dirname(filePath),
|
|
73938
|
-
`.tmp-${process.pid}-${Date.now()}-${
|
|
74224
|
+
`.tmp-${process.pid}-${Date.now()}-${crypto5.randomUUID()}-${os22__default.hostname()}`
|
|
73939
74225
|
);
|
|
73940
74226
|
await writeFile2(tempPath, content, "utf8");
|
|
73941
74227
|
await rename(tempPath, filePath);
|
|
@@ -76472,7 +76758,7 @@ function parseOptionalIsoDate(value) {
|
|
|
76472
76758
|
return Number.isFinite(timestamp) ? timestamp : null;
|
|
76473
76759
|
}
|
|
76474
76760
|
function hashBodyForComparison(body) {
|
|
76475
|
-
return
|
|
76761
|
+
return crypto5.createHash("sha256").update(body.replace(/\s+/g, " ").trim(), "utf8").digest("hex").slice(0, 8);
|
|
76476
76762
|
}
|
|
76477
76763
|
function hasConflictingStatuses(entries) {
|
|
76478
76764
|
const statuses = new Set(entries.map((entry) => entry.status).filter((status) => status !== "unknown"));
|
|
@@ -78654,6 +78940,418 @@ function buildWikiToolSpec(config22, usage) {
|
|
|
78654
78940
|
}
|
|
78655
78941
|
};
|
|
78656
78942
|
}
|
|
78943
|
+
var SUBAGENT_CLI_TYPES = /* @__PURE__ */ new Set(["claude", "claude-zai", "claude-kimi"]);
|
|
78944
|
+
var TASKFORCE_MIN_BACKENDS = 2;
|
|
78945
|
+
function createCarrierSettingsRouter(deps) {
|
|
78946
|
+
const controller = createStatusOverlayController(deps.registry);
|
|
78947
|
+
return async function handleCarrierSettingsRoute(context) {
|
|
78948
|
+
const { req, res, pathname } = context;
|
|
78949
|
+
if (pathname === "/carrier-settings/state") {
|
|
78950
|
+
if (req.method !== "GET") {
|
|
78951
|
+
deps.writeJson(res, 405, { error: "Method not allowed" });
|
|
78952
|
+
return true;
|
|
78953
|
+
}
|
|
78954
|
+
deps.writeJson(res, 200, buildCarrierSettingsState(deps.registry));
|
|
78955
|
+
return true;
|
|
78956
|
+
}
|
|
78957
|
+
if (pathname === "/carrier-settings/options") {
|
|
78958
|
+
if (req.method !== "GET") {
|
|
78959
|
+
deps.writeJson(res, 405, { error: "Method not allowed" });
|
|
78960
|
+
return true;
|
|
78961
|
+
}
|
|
78962
|
+
deps.writeJson(res, 200, buildCarrierSettingsOptions());
|
|
78963
|
+
return true;
|
|
78964
|
+
}
|
|
78965
|
+
const mutation = parseCarrierMutation(pathname);
|
|
78966
|
+
if (!mutation) return false;
|
|
78967
|
+
await handleCarrierMutation(req, res, deps, controller, mutation);
|
|
78968
|
+
return true;
|
|
78969
|
+
};
|
|
78970
|
+
}
|
|
78971
|
+
function buildCarrierSettingsState(registry32) {
|
|
78972
|
+
const defaultsByCarrier = buildDefaultsByCarrier(registry32);
|
|
78973
|
+
const snapshot = readCarriersSnapshot2(defaultsByCarrier);
|
|
78974
|
+
return {
|
|
78975
|
+
generation: snapshot.generation,
|
|
78976
|
+
carriers: getRegisteredOrder2(registry32).map((carrierId) => {
|
|
78977
|
+
const config22 = requireCarrierConfig(registry32, carrierId);
|
|
78978
|
+
const resolved = snapshot.carriers[carrierId] ?? fallbackResolvedState(config22);
|
|
78979
|
+
return toCarrierSettingsCarrier(registry32, config22, resolved);
|
|
78980
|
+
})
|
|
78981
|
+
};
|
|
78982
|
+
}
|
|
78983
|
+
function buildCarrierSettingsOptions() {
|
|
78984
|
+
return {
|
|
78985
|
+
cliTypes: getCliTypes().map(toCliOption),
|
|
78986
|
+
taskForceConstraints: { minBackends: TASKFORCE_MIN_BACKENDS }
|
|
78987
|
+
};
|
|
78988
|
+
}
|
|
78989
|
+
async function handleCarrierMutation(req, res, deps, controller, mutation) {
|
|
78990
|
+
const method = req.method ?? "GET";
|
|
78991
|
+
const expectedMethod = mutation.kind === "display-name" ? "PATCH" : mutation.kind === "taskforce-backend" || mutation.kind === "taskforce-all" ? method : "PUT";
|
|
78992
|
+
if (!isExpectedCarrierMethod(mutation, method, expectedMethod)) {
|
|
78993
|
+
deps.writeJson(res, 405, { error: "Method not allowed" });
|
|
78994
|
+
return;
|
|
78995
|
+
}
|
|
78996
|
+
if (!deps.isAuthorized(req)) {
|
|
78997
|
+
deps.writeJson(res, 401, { error: "unauthorized" });
|
|
78998
|
+
return;
|
|
78999
|
+
}
|
|
79000
|
+
if (!isJsonRequest(req)) {
|
|
79001
|
+
deps.writeJson(res, 415, { error: "unsupported_media_type" });
|
|
79002
|
+
return;
|
|
79003
|
+
}
|
|
79004
|
+
if (!getRegisteredCarrierConfig2(deps.registry, mutation.carrierId)) {
|
|
79005
|
+
deps.writeJson(res, 404, { error: "carrier_not_found" });
|
|
79006
|
+
return;
|
|
79007
|
+
}
|
|
79008
|
+
if (mutation.kind === "taskforce-backend" && !isCliType(mutation.cliType)) {
|
|
79009
|
+
deps.writeJson(res, 400, { error: "invalid_cli_type" });
|
|
79010
|
+
return;
|
|
79011
|
+
}
|
|
79012
|
+
try {
|
|
79013
|
+
if (mutation.kind === "cli") {
|
|
79014
|
+
const body2 = await readRequiredJsonBody(req, res, deps);
|
|
79015
|
+
if (!body2.ok) return;
|
|
79016
|
+
await mutateCarrierCli(res, deps, controller, mutation.carrierId, body2.body);
|
|
79017
|
+
return;
|
|
79018
|
+
}
|
|
79019
|
+
if (mutation.kind === "model") {
|
|
79020
|
+
const body2 = await readRequiredJsonBody(req, res, deps);
|
|
79021
|
+
if (!body2.ok) return;
|
|
79022
|
+
await mutateCarrierModel(res, deps, mutation.carrierId, body2.body);
|
|
79023
|
+
return;
|
|
79024
|
+
}
|
|
79025
|
+
if (mutation.kind === "display-name") {
|
|
79026
|
+
const body2 = await readRequiredJsonBody(req, res, deps);
|
|
79027
|
+
if (!body2.ok) return;
|
|
79028
|
+
mutateDisplayName(res, deps, mutation.carrierId, body2.body);
|
|
79029
|
+
return;
|
|
79030
|
+
}
|
|
79031
|
+
if (mutation.kind === "agent-mode") {
|
|
79032
|
+
const body2 = await readRequiredJsonBody(req, res, deps);
|
|
79033
|
+
if (!body2.ok) return;
|
|
79034
|
+
mutateAgentMode(res, deps, mutation.carrierId, body2.body);
|
|
79035
|
+
return;
|
|
79036
|
+
}
|
|
79037
|
+
if (mutation.kind === "taskforce-backend") {
|
|
79038
|
+
if (method === "DELETE") {
|
|
79039
|
+
const body3 = await readRequiredJsonBody(req, res, deps);
|
|
79040
|
+
if (!body3.ok) return;
|
|
79041
|
+
resetTaskForceModelSelection2(mutation.carrierId, mutation.cliType);
|
|
79042
|
+
refreshTaskForceConfiguredCarriers(deps.registry);
|
|
79043
|
+
writeMutationState(res, deps);
|
|
79044
|
+
return;
|
|
79045
|
+
}
|
|
79046
|
+
const body2 = await readRequiredJsonBody(req, res, deps);
|
|
79047
|
+
if (!body2.ok) return;
|
|
79048
|
+
mutateTaskForceBackend(res, deps, mutation.carrierId, mutation.cliType, body2.body);
|
|
79049
|
+
return;
|
|
79050
|
+
}
|
|
79051
|
+
const body = await readRequiredJsonBody(req, res, deps);
|
|
79052
|
+
if (!body.ok) return;
|
|
79053
|
+
resetCarrierTaskForceConfig2(mutation.carrierId);
|
|
79054
|
+
refreshTaskForceConfiguredCarriers(deps.registry);
|
|
79055
|
+
writeMutationState(res, deps);
|
|
79056
|
+
} catch (error512) {
|
|
79057
|
+
deps.writeJson(res, 400, { error: error512 instanceof Error ? error512.message : "invalid_request" });
|
|
79058
|
+
}
|
|
79059
|
+
}
|
|
79060
|
+
async function mutateCarrierCli(res, deps, controller, carrierId, body) {
|
|
79061
|
+
const cliType = readCliType(body.cliType);
|
|
79062
|
+
if (!cliType) {
|
|
79063
|
+
deps.writeJson(res, 400, { error: "invalid_cli_type" });
|
|
79064
|
+
return;
|
|
79065
|
+
}
|
|
79066
|
+
await controller.changeCliType(carrierId, cliType);
|
|
79067
|
+
if (!SUBAGENT_CLI_TYPES.has(cliType)) {
|
|
79068
|
+
const resolved = readCarriersSnapshot2(buildDefaultsByCarrier(deps.registry)).carriers[carrierId];
|
|
79069
|
+
if (resolved?.agentMode === "subagent") {
|
|
79070
|
+
const config22 = requireCarrierConfig(deps.registry, carrierId);
|
|
79071
|
+
updateCarrierAgentModeAtomically(carrierId, "cli", config22.defaultAgentMode ?? "cli");
|
|
79072
|
+
}
|
|
79073
|
+
}
|
|
79074
|
+
writeMutationState(res, deps);
|
|
79075
|
+
}
|
|
79076
|
+
async function mutateCarrierModel(res, deps, carrierId, body) {
|
|
79077
|
+
const config22 = requireCarrierConfig(deps.registry, carrierId);
|
|
79078
|
+
const cliType = resolveAgentCliType22(carrierId, config22.defaultCliType);
|
|
79079
|
+
const selection = readSelection(cliType, body);
|
|
79080
|
+
if (!selection) {
|
|
79081
|
+
deps.writeJson(res, 400, { error: "invalid_model_selection" });
|
|
79082
|
+
return;
|
|
79083
|
+
}
|
|
79084
|
+
await updateAgentCliSelection2(carrierId, cliType, selection);
|
|
79085
|
+
notifyStatusUpdate2(deps.registry);
|
|
79086
|
+
writeMutationState(res, deps);
|
|
79087
|
+
}
|
|
79088
|
+
function mutateDisplayName(res, deps, carrierId, body) {
|
|
79089
|
+
const displayName = normalizeCarrierDisplayNameInput2(body.displayName);
|
|
79090
|
+
if (displayName === null) {
|
|
79091
|
+
deps.writeJson(res, 400, { error: "invalid_display_name" });
|
|
79092
|
+
return;
|
|
79093
|
+
}
|
|
79094
|
+
updateCarrierDisplayName2(carrierId, displayName, getCarrierSourceDisplayName2(deps.registry, carrierId));
|
|
79095
|
+
notifyStatusUpdate2(deps.registry);
|
|
79096
|
+
writeMutationState(res, deps);
|
|
79097
|
+
}
|
|
79098
|
+
function mutateAgentMode(res, deps, carrierId, body) {
|
|
79099
|
+
const config22 = requireCarrierConfig(deps.registry, carrierId);
|
|
79100
|
+
const agentMode = body.agentMode;
|
|
79101
|
+
if (agentMode !== "cli" && agentMode !== "subagent") {
|
|
79102
|
+
deps.writeJson(res, 400, { error: "invalid_agent_mode" });
|
|
79103
|
+
return;
|
|
79104
|
+
}
|
|
79105
|
+
const cliType = resolveAgentCliType22(carrierId, config22.defaultCliType);
|
|
79106
|
+
if (agentMode === "subagent" && !SUBAGENT_CLI_TYPES.has(cliType)) {
|
|
79107
|
+
deps.writeJson(res, 400, { error: "subagent_unsupported" });
|
|
79108
|
+
return;
|
|
79109
|
+
}
|
|
79110
|
+
updateCarrierAgentModeAtomically(carrierId, agentMode, config22.defaultAgentMode ?? "cli");
|
|
79111
|
+
if (agentMode === "subagent") refreshTaskForceConfiguredCarriers(deps.registry);
|
|
79112
|
+
notifyStatusUpdate2(deps.registry);
|
|
79113
|
+
writeMutationState(res, deps);
|
|
79114
|
+
}
|
|
79115
|
+
function mutateTaskForceBackend(res, deps, carrierId, cliType, body) {
|
|
79116
|
+
const selection = readSelection(cliType, body);
|
|
79117
|
+
if (!selection) {
|
|
79118
|
+
deps.writeJson(res, 400, { error: "invalid_model_selection" });
|
|
79119
|
+
return;
|
|
79120
|
+
}
|
|
79121
|
+
updateTaskForceBackendAtomically(carrierId, cliType, selection);
|
|
79122
|
+
refreshTaskForceConfiguredCarriers(deps.registry);
|
|
79123
|
+
notifyStatusUpdate2(deps.registry);
|
|
79124
|
+
writeMutationState(res, deps);
|
|
79125
|
+
}
|
|
79126
|
+
function writeMutationState(res, deps) {
|
|
79127
|
+
const response = { state: buildCarrierSettingsState(deps.registry) };
|
|
79128
|
+
deps.writeJson(res, 200, response);
|
|
79129
|
+
}
|
|
79130
|
+
async function readRequiredJsonBody(req, res, deps) {
|
|
79131
|
+
const body = await deps.readJsonBody(req);
|
|
79132
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) {
|
|
79133
|
+
deps.writeJson(res, 400, { error: "invalid_json" });
|
|
79134
|
+
return { ok: false };
|
|
79135
|
+
}
|
|
79136
|
+
return { ok: true, body };
|
|
79137
|
+
}
|
|
79138
|
+
function buildDefaultsByCarrier(registry32) {
|
|
79139
|
+
return Object.fromEntries(
|
|
79140
|
+
getRegisteredOrder2(registry32).map((carrierId) => {
|
|
79141
|
+
const config22 = requireCarrierConfig(registry32, carrierId);
|
|
79142
|
+
return [carrierId, {
|
|
79143
|
+
cliType: config22.defaultCliType,
|
|
79144
|
+
...config22.defaultAgentMode ? { defaultAgentMode: config22.defaultAgentMode } : {},
|
|
79145
|
+
...buildCarrierModelDefaults2(config22, config22.defaultCliType)
|
|
79146
|
+
}];
|
|
79147
|
+
})
|
|
79148
|
+
);
|
|
79149
|
+
}
|
|
79150
|
+
function toCarrierSettingsCarrier(registry32, config22, resolved) {
|
|
79151
|
+
const cliType = resolved.agentCliType ?? config22.defaultCliType;
|
|
79152
|
+
const selection = resolved.agentCli[cliType] ?? readDefaultSelection(cliType);
|
|
79153
|
+
const taskForceBackends = toTaskForceBackends(resolved.taskforce);
|
|
79154
|
+
return {
|
|
79155
|
+
carrierId: config22.id,
|
|
79156
|
+
displayName: resolved.displayName ?? getCarrierSourceDisplayName2(registry32, config22.id),
|
|
79157
|
+
sourceDisplayName: getCarrierSourceDisplayName2(registry32, config22.id),
|
|
79158
|
+
role: config22.carrierMetadata?.title ?? config22.displayName,
|
|
79159
|
+
roleDescription: config22.carrierMetadata?.summary ?? "",
|
|
79160
|
+
...config22.carrierMetadata?.category ? { category: config22.carrierMetadata.category } : {},
|
|
79161
|
+
slot: config22.slot,
|
|
79162
|
+
cliType,
|
|
79163
|
+
defaultCliType: config22.defaultCliType,
|
|
79164
|
+
model: selection.model,
|
|
79165
|
+
...selection.effort ? { effort: selection.effort } : {},
|
|
79166
|
+
agentMode: resolved.agentMode,
|
|
79167
|
+
subagentMode: resolved.agentMode === "subagent",
|
|
79168
|
+
taskForceBackendCount: taskForceBackends.length,
|
|
79169
|
+
taskforce: { backends: taskForceBackends }
|
|
79170
|
+
};
|
|
79171
|
+
}
|
|
79172
|
+
function toTaskForceBackends(taskforce) {
|
|
79173
|
+
return TASKFORCE_CLI_TYPES2.map((cliType) => {
|
|
79174
|
+
const selection = taskforce[cliType];
|
|
79175
|
+
if (!selection) return null;
|
|
79176
|
+
return {
|
|
79177
|
+
cliType,
|
|
79178
|
+
model: selection.model,
|
|
79179
|
+
...selection.effort ? { effort: selection.effort } : {}
|
|
79180
|
+
};
|
|
79181
|
+
}).filter((backend) => backend !== null);
|
|
79182
|
+
}
|
|
79183
|
+
function toCliOption(cliType) {
|
|
79184
|
+
const provider = getProviderModels2(cliType);
|
|
79185
|
+
return {
|
|
79186
|
+
id: cliType,
|
|
79187
|
+
displayName: CLI_DISPLAY_NAMES2[cliType] ?? provider.name,
|
|
79188
|
+
supportsSubagent: SUBAGENT_CLI_TYPES.has(cliType),
|
|
79189
|
+
models: provider.models.map((model) => {
|
|
79190
|
+
const effort = getEffort2(cliType, model.modelId);
|
|
79191
|
+
return {
|
|
79192
|
+
modelId: model.modelId,
|
|
79193
|
+
name: model.name,
|
|
79194
|
+
...effort.supported ? { effort: { levels: effort.levels, default: effort.default } } : {}
|
|
79195
|
+
};
|
|
79196
|
+
}),
|
|
79197
|
+
defaultModel: provider.defaultModel ?? provider.models[0]?.modelId
|
|
79198
|
+
};
|
|
79199
|
+
}
|
|
79200
|
+
function createStatusOverlayController(registry32) {
|
|
79201
|
+
return new StatusOverlayController2({
|
|
79202
|
+
getEntries: () => [],
|
|
79203
|
+
getRegisteredOrder: () => getRegisteredOrder2(registry32),
|
|
79204
|
+
getCarrierConfig: (carrierId) => getRegisteredCarrierConfig2(registry32, carrierId),
|
|
79205
|
+
getResolvedCliType: (carrierId) => {
|
|
79206
|
+
const config22 = getRegisteredCarrierConfig2(registry32, carrierId);
|
|
79207
|
+
return config22 ? resolveAgentCliType22(carrierId, config22.defaultCliType) : void 0;
|
|
79208
|
+
},
|
|
79209
|
+
getCurrentModelSelection: (carrierId) => {
|
|
79210
|
+
return readCurrentModelSelection(registry32, carrierId);
|
|
79211
|
+
},
|
|
79212
|
+
getAvailableModels: (cliType) => {
|
|
79213
|
+
const provider = getProviderModels2(cliType);
|
|
79214
|
+
return {
|
|
79215
|
+
defaultModel: provider.defaultModel,
|
|
79216
|
+
models: provider.models.map((model) => ({
|
|
79217
|
+
modelId: model.modelId,
|
|
79218
|
+
name: model.name,
|
|
79219
|
+
effort: getEffort2(cliType, model.modelId)
|
|
79220
|
+
}))
|
|
79221
|
+
};
|
|
79222
|
+
},
|
|
79223
|
+
getEffort: (cliType, modelId) => getEffort2(cliType, modelId),
|
|
79224
|
+
getAgentCliSelection: (carrierId, cliType) => getAgentCliSelection2(carrierId, cliType),
|
|
79225
|
+
saveAgentCliSelection: saveAgentCliSelection2,
|
|
79226
|
+
updateCarrierCliType: (carrierId, cliType) => updateCarrierCliType2(registry32, carrierId),
|
|
79227
|
+
applyAgentCliTypeSelectionUpdate: applyAgentCliTypeSelectionUpdate2,
|
|
79228
|
+
refreshAgentPanel: () => void 0,
|
|
79229
|
+
syncModelConfig: () => void 0,
|
|
79230
|
+
notifyStatusUpdate: () => notifyStatusUpdate2(registry32)
|
|
79231
|
+
});
|
|
79232
|
+
}
|
|
79233
|
+
function updateCarrierAgentModeAtomically(carrierId, agentMode, defaultAgentMode) {
|
|
79234
|
+
if (agentMode === "cli") {
|
|
79235
|
+
setCarrierAgentMode2(carrierId, false, defaultAgentMode);
|
|
79236
|
+
return;
|
|
79237
|
+
}
|
|
79238
|
+
updateCarriers2((states) => {
|
|
79239
|
+
const carriers = { ...states.carriers ?? {} };
|
|
79240
|
+
const current = carriers[carrierId] ?? {};
|
|
79241
|
+
const next = { ...current };
|
|
79242
|
+
next.agentMode = "subagent";
|
|
79243
|
+
delete next.taskforce;
|
|
79244
|
+
carriers[carrierId] = next;
|
|
79245
|
+
states.carriers = carriers;
|
|
79246
|
+
});
|
|
79247
|
+
}
|
|
79248
|
+
function updateTaskForceBackendAtomically(carrierId, cliType, selection) {
|
|
79249
|
+
updateCarriers2((states) => {
|
|
79250
|
+
const carriers = { ...states.carriers ?? {} };
|
|
79251
|
+
const current = carriers[carrierId] ?? {};
|
|
79252
|
+
carriers[carrierId] = {
|
|
79253
|
+
...current,
|
|
79254
|
+
agentMode: "cli",
|
|
79255
|
+
taskforce: {
|
|
79256
|
+
...current.taskforce ?? {},
|
|
79257
|
+
[cliType]: selection
|
|
79258
|
+
}
|
|
79259
|
+
};
|
|
79260
|
+
states.carriers = carriers;
|
|
79261
|
+
});
|
|
79262
|
+
}
|
|
79263
|
+
function refreshTaskForceConfiguredCarriers(registry32) {
|
|
79264
|
+
setTaskForceConfiguredCarriers2(registry32, getConfiguredTaskForceCarrierIds2(getRegisteredOrder2(registry32)));
|
|
79265
|
+
notifyStatusUpdate2(registry32);
|
|
79266
|
+
}
|
|
79267
|
+
function readSelection(cliType, body) {
|
|
79268
|
+
if (typeof body.model !== "string") return null;
|
|
79269
|
+
const provider = getProviderModels2(cliType);
|
|
79270
|
+
if (!provider.models.some((model) => model.modelId === body.model)) return null;
|
|
79271
|
+
const effort = getEffort2(cliType, body.model);
|
|
79272
|
+
if (!effort.supported) {
|
|
79273
|
+
return body.effort === void 0 ? { model: body.model } : null;
|
|
79274
|
+
}
|
|
79275
|
+
if (typeof body.effort !== "string" || !effort.levels.includes(body.effort)) return null;
|
|
79276
|
+
return { model: body.model, effort: body.effort };
|
|
79277
|
+
}
|
|
79278
|
+
function readDefaultSelection(cliType) {
|
|
79279
|
+
const provider = getProviderModels2(cliType);
|
|
79280
|
+
const model = provider.defaultModel;
|
|
79281
|
+
const effort = getEffort2(cliType, model);
|
|
79282
|
+
return {
|
|
79283
|
+
model,
|
|
79284
|
+
...effort.supported ? { effort: effort.default } : {}
|
|
79285
|
+
};
|
|
79286
|
+
}
|
|
79287
|
+
function readCurrentModelSelection(registry32, carrierId) {
|
|
79288
|
+
const config22 = getRegisteredCarrierConfig2(registry32, carrierId);
|
|
79289
|
+
if (!config22) return void 0;
|
|
79290
|
+
const defaults = {
|
|
79291
|
+
[carrierId]: {
|
|
79292
|
+
cliType: config22.defaultCliType,
|
|
79293
|
+
...config22.defaultAgentMode ? { defaultAgentMode: config22.defaultAgentMode } : {},
|
|
79294
|
+
...buildCarrierModelDefaults2(config22, config22.defaultCliType)
|
|
79295
|
+
}
|
|
79296
|
+
};
|
|
79297
|
+
const resolved = readCarriersSnapshot2(defaults).carriers[carrierId] ?? fallbackResolvedState(config22);
|
|
79298
|
+
const cliType = resolved.agentCliType ?? config22.defaultCliType;
|
|
79299
|
+
return resolved.agentCli[cliType] ?? readDefaultSelection(cliType);
|
|
79300
|
+
}
|
|
79301
|
+
function fallbackResolvedState(config22) {
|
|
79302
|
+
return {
|
|
79303
|
+
agentMode: config22.defaultAgentMode ?? "cli",
|
|
79304
|
+
agentCliType: config22.defaultCliType,
|
|
79305
|
+
agentCli: { [config22.defaultCliType]: readDefaultSelection(config22.defaultCliType) },
|
|
79306
|
+
taskforce: {}
|
|
79307
|
+
};
|
|
79308
|
+
}
|
|
79309
|
+
function parseCarrierMutation(pathname) {
|
|
79310
|
+
const parts = pathname.split("/").filter(Boolean);
|
|
79311
|
+
if (parts[0] !== "carrier-settings" || parts[1] !== "carriers" || !parts[2]) return null;
|
|
79312
|
+
const carrierId = safeDecodeURIComponent(parts[2]);
|
|
79313
|
+
if (!carrierId) return null;
|
|
79314
|
+
if (parts.length === 4 && parts[3] === "cli") return { kind: "cli", carrierId };
|
|
79315
|
+
if (parts.length === 4 && parts[3] === "model") return { kind: "model", carrierId };
|
|
79316
|
+
if (parts.length === 4 && parts[3] === "display-name") return { kind: "display-name", carrierId };
|
|
79317
|
+
if (parts.length === 4 && parts[3] === "agent-mode") return { kind: "agent-mode", carrierId };
|
|
79318
|
+
if (parts.length === 4 && parts[3] === "taskforce") return { kind: "taskforce-all", carrierId };
|
|
79319
|
+
if (parts.length === 5 && parts[3] === "taskforce") {
|
|
79320
|
+
const cliType = safeDecodeURIComponent(parts[4] ?? "");
|
|
79321
|
+
return cliType ? { kind: "taskforce-backend", carrierId, cliType } : null;
|
|
79322
|
+
}
|
|
79323
|
+
return null;
|
|
79324
|
+
}
|
|
79325
|
+
function safeDecodeURIComponent(value) {
|
|
79326
|
+
try {
|
|
79327
|
+
return decodeURIComponent(value);
|
|
79328
|
+
} catch {
|
|
79329
|
+
return null;
|
|
79330
|
+
}
|
|
79331
|
+
}
|
|
79332
|
+
function isExpectedCarrierMethod(mutation, method, expectedMethod) {
|
|
79333
|
+
if (mutation.kind === "taskforce-backend") return method === "PUT" || method === "DELETE";
|
|
79334
|
+
if (mutation.kind === "taskforce-all") return method === "DELETE";
|
|
79335
|
+
return method === expectedMethod;
|
|
79336
|
+
}
|
|
79337
|
+
function isJsonRequest(req) {
|
|
79338
|
+
const contentType = req.headers["content-type"];
|
|
79339
|
+
return typeof contentType === "string" && contentType.toLowerCase().split(";")[0]?.trim() === "application/json";
|
|
79340
|
+
}
|
|
79341
|
+
function readCliType(value) {
|
|
79342
|
+
return typeof value === "string" && isCliType(value) ? value : null;
|
|
79343
|
+
}
|
|
79344
|
+
function isCliType(value) {
|
|
79345
|
+
return Object.prototype.hasOwnProperty.call(CLI_BACKENDS2, value);
|
|
79346
|
+
}
|
|
79347
|
+
function getCliTypes() {
|
|
79348
|
+
return Object.keys(CLI_BACKENDS2);
|
|
79349
|
+
}
|
|
79350
|
+
function requireCarrierConfig(registry32, carrierId) {
|
|
79351
|
+
const config22 = getRegisteredCarrierConfig2(registry32, carrierId);
|
|
79352
|
+
if (!config22) throw new Error(`Carrier not found: ${carrierId}`);
|
|
79353
|
+
return config22;
|
|
79354
|
+
}
|
|
78657
79355
|
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
79356
|
var SECURITY_HEADERS = {
|
|
78659
79357
|
"content-security-policy": CONTENT_SECURITY_POLICY,
|
|
@@ -78680,7 +79378,7 @@ function safeEqual(left, right) {
|
|
|
78680
79378
|
return timingSafeEqual(leftBytes, rightBytes);
|
|
78681
79379
|
}
|
|
78682
79380
|
function workspaceHash(canonicalCwd) {
|
|
78683
|
-
return
|
|
79381
|
+
return crypto5.createHash("sha256").update(canonicalCwd).digest("hex").slice(0, 12);
|
|
78684
79382
|
}
|
|
78685
79383
|
async function canonicalizeTheaterPath(cwd) {
|
|
78686
79384
|
return canonicalizeTheaterPathSync(cwd);
|
|
@@ -79552,7 +80250,7 @@ function createCodexGateway(deps) {
|
|
|
79552
80250
|
return true;
|
|
79553
80251
|
}
|
|
79554
80252
|
if (selected.kind === "no-workspace") {
|
|
79555
|
-
if (
|
|
80253
|
+
if (isJsonRequest2(request)) {
|
|
79556
80254
|
sendJson2(response, 404, { error: "no_workspace_registered" });
|
|
79557
80255
|
return true;
|
|
79558
80256
|
}
|
|
@@ -79664,7 +80362,7 @@ function legacyWorkspacePath(url22) {
|
|
|
79664
80362
|
}
|
|
79665
80363
|
return null;
|
|
79666
80364
|
}
|
|
79667
|
-
function
|
|
80365
|
+
function isJsonRequest2(request) {
|
|
79668
80366
|
const accept = Array.isArray(request.headers.accept) ? request.headers.accept.join(",") : request.headers.accept ?? "";
|
|
79669
80367
|
const requestedWith = Array.isArray(request.headers["x-requested-with"]) ? request.headers["x-requested-with"].join(",") : request.headers["x-requested-with"] ?? "";
|
|
79670
80368
|
return accept.includes("application/json") || requestedWith.toLowerCase() === "xmlhttprequest";
|
|
@@ -79739,6 +80437,155 @@ function readRawHeaderValues(rawHeaders, name) {
|
|
|
79739
80437
|
function stripIpv6Brackets2(host) {
|
|
79740
80438
|
return host.startsWith("[") && host.endsWith("]") ? host.slice(1, -1) : host;
|
|
79741
80439
|
}
|
|
80440
|
+
var STATE_VERSION = 1;
|
|
80441
|
+
var STATE_LOCK_DIR_NAME = "state.lock";
|
|
80442
|
+
var STATE_LOCK_OWNER_FILE_NAME = "owner.json";
|
|
80443
|
+
var STATE_TEMP_PREFIX = ".state.";
|
|
80444
|
+
function createConsoleDurableStateStore(deps = {}) {
|
|
80445
|
+
const paths = deps.paths ?? createConsoleDataPaths();
|
|
80446
|
+
const createStore = deps.createStore ?? createDurableJsonStore2;
|
|
80447
|
+
return createStore({
|
|
80448
|
+
filePath: paths.stateFile,
|
|
80449
|
+
lockDir: path93__default.join(paths.dir, STATE_LOCK_DIR_NAME),
|
|
80450
|
+
lockOwnerFileName: STATE_LOCK_OWNER_FILE_NAME,
|
|
80451
|
+
now: deps.now,
|
|
80452
|
+
sanitize: sanitizeDurableConsoleState,
|
|
80453
|
+
sensitivity: "sensitive",
|
|
80454
|
+
tempCleanupPrefix: STATE_TEMP_PREFIX
|
|
80455
|
+
});
|
|
80456
|
+
}
|
|
80457
|
+
function sanitizeDurableConsoleState(value) {
|
|
80458
|
+
if (!isRecord4(value) || value.version !== STATE_VERSION) return emptyDurableConsoleState();
|
|
80459
|
+
return {
|
|
80460
|
+
version: STATE_VERSION,
|
|
80461
|
+
theaters: readTheaterRegistrations(value.theaters),
|
|
80462
|
+
operations: readDurableOperations(value.operations)
|
|
80463
|
+
};
|
|
80464
|
+
}
|
|
80465
|
+
function emptyDurableConsoleState() {
|
|
80466
|
+
return { version: STATE_VERSION, theaters: [], operations: [] };
|
|
80467
|
+
}
|
|
80468
|
+
function readProviderSessionCapture(fleetSessionId, deps = {}) {
|
|
80469
|
+
if (!isSafeCaptureId(fleetSessionId)) return null;
|
|
80470
|
+
const capturesDir = deps.capturesDir ?? createConsoleDataPaths().capturesDir;
|
|
80471
|
+
const filePath = path93__default.join(capturesDir, `${fleetSessionId}.json`);
|
|
80472
|
+
try {
|
|
80473
|
+
const parsed = JSON.parse(fs5__default.readFileSync(filePath, "utf8"));
|
|
80474
|
+
return sanitizeProviderSession(parsed);
|
|
80475
|
+
} catch {
|
|
80476
|
+
return null;
|
|
80477
|
+
}
|
|
80478
|
+
}
|
|
80479
|
+
function mergeProviderSessionCaptures(state, deps = {}) {
|
|
80480
|
+
let changed = false;
|
|
80481
|
+
const operations = state.operations.map((operation) => {
|
|
80482
|
+
if (operation.providerSession) return operation;
|
|
80483
|
+
const providerSession = readProviderSessionCapture(operation.sessionId, deps);
|
|
80484
|
+
if (!providerSession) return operation;
|
|
80485
|
+
changed = true;
|
|
80486
|
+
return { ...operation, providerSession };
|
|
80487
|
+
});
|
|
80488
|
+
return changed ? { ...state, operations } : state;
|
|
80489
|
+
}
|
|
80490
|
+
function unlinkProviderSessionCapture(fleetSessionId, deps = {}) {
|
|
80491
|
+
if (!isSafeCaptureId(fleetSessionId)) return false;
|
|
80492
|
+
const capturesDir = deps.capturesDir ?? createConsoleDataPaths().capturesDir;
|
|
80493
|
+
try {
|
|
80494
|
+
fs5__default.unlinkSync(path93__default.join(capturesDir, `${fleetSessionId}.json`));
|
|
80495
|
+
return true;
|
|
80496
|
+
} catch {
|
|
80497
|
+
return false;
|
|
80498
|
+
}
|
|
80499
|
+
}
|
|
80500
|
+
function cleanupProviderSessionCaptures(state, deps = {}) {
|
|
80501
|
+
for (const operation of state.operations) {
|
|
80502
|
+
if (operation.providerSession) unlinkProviderSessionCapture(operation.sessionId, deps);
|
|
80503
|
+
}
|
|
80504
|
+
}
|
|
80505
|
+
function readTheaterRegistrations(value) {
|
|
80506
|
+
if (!Array.isArray(value)) return [];
|
|
80507
|
+
const registrations = [];
|
|
80508
|
+
for (const item of value) {
|
|
80509
|
+
const registration = sanitizeTheaterRegistration(item);
|
|
80510
|
+
if (registration) registrations.push(registration);
|
|
80511
|
+
}
|
|
80512
|
+
return registrations;
|
|
80513
|
+
}
|
|
80514
|
+
function readDurableOperations(value) {
|
|
80515
|
+
if (!Array.isArray(value)) return [];
|
|
80516
|
+
const operations = [];
|
|
80517
|
+
for (const item of value) {
|
|
80518
|
+
const operation = sanitizeDurableOperation(item);
|
|
80519
|
+
if (operation) operations.push(operation);
|
|
80520
|
+
}
|
|
80521
|
+
return operations;
|
|
80522
|
+
}
|
|
80523
|
+
function sanitizeTheaterRegistration(value) {
|
|
80524
|
+
if (!isRecord4(value)) return null;
|
|
80525
|
+
const id = readNonEmptyString(value.id);
|
|
80526
|
+
const theaterPath = readNonEmptyString(value.path);
|
|
80527
|
+
const realpath = readNonEmptyString(value.realpath);
|
|
80528
|
+
const label = readNonEmptyString(value.label);
|
|
80529
|
+
const registeredAt = readNonEmptyString(value.registeredAt);
|
|
80530
|
+
const lastOpenedAt = readNonEmptyString(value.lastOpenedAt);
|
|
80531
|
+
if (!id || !theaterPath || !realpath || !label || !registeredAt || !lastOpenedAt) return null;
|
|
80532
|
+
return { id, path: theaterPath, realpath, label, registeredAt, lastOpenedAt };
|
|
80533
|
+
}
|
|
80534
|
+
function sanitizeDurableOperation(value) {
|
|
80535
|
+
if (!isRecord4(value)) return null;
|
|
80536
|
+
const sessionId = readNonEmptyString(value.sessionId);
|
|
80537
|
+
const theaterId = readNonEmptyString(value.theaterId);
|
|
80538
|
+
const cwd = readNonEmptyString(value.cwd);
|
|
80539
|
+
const cwdLabel = readNonEmptyString(value.cwdLabel);
|
|
80540
|
+
const sequence = readPositiveInteger(value.sequence);
|
|
80541
|
+
const createdAt = readFiniteNumber(value.createdAt);
|
|
80542
|
+
if (!sessionId || !theaterId || !cwd || !cwdLabel || sequence === null || createdAt === null) return null;
|
|
80543
|
+
const providerSession = sanitizeProviderSession(value.providerSession);
|
|
80544
|
+
return {
|
|
80545
|
+
sessionId,
|
|
80546
|
+
theaterId,
|
|
80547
|
+
cwd,
|
|
80548
|
+
cwdLabel,
|
|
80549
|
+
sequence,
|
|
80550
|
+
...readOptionalString(value.label) ? { label: readOptionalString(value.label) } : {},
|
|
80551
|
+
...readOptionalString(value.cliId) ? { cliId: readOptionalString(value.cliId) } : {},
|
|
80552
|
+
...readOptionalString(value.cliLabel) ? { cliLabel: readOptionalString(value.cliLabel) } : {},
|
|
80553
|
+
createdAt,
|
|
80554
|
+
...providerSession ? { providerSession } : {}
|
|
80555
|
+
};
|
|
80556
|
+
}
|
|
80557
|
+
function sanitizeProviderSession(value) {
|
|
80558
|
+
if (!isRecord4(value)) return null;
|
|
80559
|
+
const provider = value.provider === "claude" || value.provider === "codex" ? value.provider : null;
|
|
80560
|
+
const sessionId = readNonEmptyString(value.sessionId);
|
|
80561
|
+
const capturedAt = readNonEmptyString(value.capturedAt);
|
|
80562
|
+
if (!provider || !sessionId || !capturedAt) return null;
|
|
80563
|
+
return {
|
|
80564
|
+
provider,
|
|
80565
|
+
sessionId,
|
|
80566
|
+
...readOptionalString(value.transcriptPath) ? { transcriptPath: readOptionalString(value.transcriptPath) } : {},
|
|
80567
|
+
...readOptionalString(value.source) ? { source: readOptionalString(value.source) } : {},
|
|
80568
|
+
capturedAt
|
|
80569
|
+
};
|
|
80570
|
+
}
|
|
80571
|
+
function isRecord4(value) {
|
|
80572
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
80573
|
+
}
|
|
80574
|
+
function isSafeCaptureId(value) {
|
|
80575
|
+
return value.length > 0 && path93__default.basename(value) === value && !value.includes(path93__default.sep) && !value.includes(path93__default.posix.sep);
|
|
80576
|
+
}
|
|
80577
|
+
function readNonEmptyString(value) {
|
|
80578
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
80579
|
+
}
|
|
80580
|
+
function readOptionalString(value) {
|
|
80581
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
80582
|
+
}
|
|
80583
|
+
function readPositiveInteger(value) {
|
|
80584
|
+
return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : null;
|
|
80585
|
+
}
|
|
80586
|
+
function readFiniteNumber(value) {
|
|
80587
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
80588
|
+
}
|
|
79742
80589
|
function writeObserverEvents(req, res, workspace, store22) {
|
|
79743
80590
|
res.writeHead(200, withSecurityHeaders2({
|
|
79744
80591
|
"Content-Type": "text/event-stream",
|
|
@@ -79947,15 +80794,77 @@ function createConsoleObservabilityStore(deps = {}) {
|
|
|
79947
80794
|
terminalSessionsById.set(state.sessionId, state);
|
|
79948
80795
|
return toTerminalSessionInfo(state);
|
|
79949
80796
|
}
|
|
80797
|
+
function injectDormantOperation(operation) {
|
|
80798
|
+
const currentSequence = terminalSequenceByTheater.get(operation.theaterId) ?? 0;
|
|
80799
|
+
terminalSequenceByTheater.set(operation.theaterId, Math.max(currentSequence, operation.sequence));
|
|
80800
|
+
const state = {
|
|
80801
|
+
sessionId: operation.sessionId,
|
|
80802
|
+
cwd: operation.cwd,
|
|
80803
|
+
canonicalCwd: canonicalizeTheaterPathSync(operation.cwd),
|
|
80804
|
+
cwdLabel: operation.cwdLabel,
|
|
80805
|
+
sequence: operation.sequence,
|
|
80806
|
+
label: operation.label,
|
|
80807
|
+
cliId: operation.cliId,
|
|
80808
|
+
cliLabel: operation.cliLabel,
|
|
80809
|
+
createdAt: operation.createdAt,
|
|
80810
|
+
theaterId: operation.theaterId,
|
|
80811
|
+
terminalSessionId: operation.sessionId,
|
|
80812
|
+
status: "dormant",
|
|
80813
|
+
providerSession: operation.providerSession
|
|
80814
|
+
};
|
|
80815
|
+
terminalSessionsById.set(state.sessionId, state);
|
|
80816
|
+
return toTerminalSessionInfo(state);
|
|
80817
|
+
}
|
|
79950
80818
|
function listTerminalSessions() {
|
|
79951
80819
|
return Array.from(terminalSessionsById.values()).map(toTerminalSessionInfo).sort((a, b) => b.createdAt - a.createdAt);
|
|
79952
80820
|
}
|
|
80821
|
+
function listDurableOperations() {
|
|
80822
|
+
return Array.from(terminalSessionsById.values()).map((session) => ({
|
|
80823
|
+
sessionId: session.sessionId,
|
|
80824
|
+
theaterId: session.theaterId,
|
|
80825
|
+
cwd: session.cwd,
|
|
80826
|
+
cwdLabel: session.cwdLabel,
|
|
80827
|
+
sequence: session.sequence,
|
|
80828
|
+
...session.label ? { label: session.label } : {},
|
|
80829
|
+
...session.cliId ? { cliId: session.cliId } : {},
|
|
80830
|
+
...session.cliLabel ? { cliLabel: session.cliLabel } : {},
|
|
80831
|
+
createdAt: session.createdAt,
|
|
80832
|
+
...session.providerSession ? { providerSession: session.providerSession } : {}
|
|
80833
|
+
}));
|
|
80834
|
+
}
|
|
80835
|
+
function getDurableOperation(sessionId) {
|
|
80836
|
+
return listDurableOperations().find((operation) => operation.sessionId === sessionId) ?? null;
|
|
80837
|
+
}
|
|
80838
|
+
function updateTerminalSessionProviderSession(sessionId, providerSession) {
|
|
80839
|
+
const session = terminalSessionsById.get(sessionId);
|
|
80840
|
+
if (!session) return null;
|
|
80841
|
+
session.providerSession = providerSession;
|
|
80842
|
+
return toTerminalSessionInfo(session);
|
|
80843
|
+
}
|
|
79953
80844
|
function updateTerminalSessionStatus(sessionId, status) {
|
|
79954
80845
|
const session = terminalSessionsById.get(sessionId);
|
|
79955
80846
|
if (!session) return null;
|
|
79956
80847
|
session.status = status;
|
|
79957
80848
|
return toTerminalSessionInfo(session);
|
|
79958
80849
|
}
|
|
80850
|
+
function setTerminalSessionTurnState(sessionId, turnState) {
|
|
80851
|
+
const session = terminalSessionsById.get(sessionId);
|
|
80852
|
+
if (!session) return null;
|
|
80853
|
+
session.turnState = turnState;
|
|
80854
|
+
return toTerminalSessionInfo(session);
|
|
80855
|
+
}
|
|
80856
|
+
function transitionTerminalSessionToDormant(sessionId, providerSession) {
|
|
80857
|
+
const session = terminalSessionsById.get(sessionId);
|
|
80858
|
+
if (!session) return null;
|
|
80859
|
+
const workspace = workspacesByCliRunId.get(sessionId);
|
|
80860
|
+
if (workspace?.terminalSessionId === sessionId) {
|
|
80861
|
+
removeWorkspaceIndexes(workspace);
|
|
80862
|
+
workspacesByCliRunId.delete(sessionId);
|
|
80863
|
+
}
|
|
80864
|
+
session.status = "dormant";
|
|
80865
|
+
session.providerSession = providerSession;
|
|
80866
|
+
return toTerminalSessionInfo(session);
|
|
80867
|
+
}
|
|
79959
80868
|
function renameTerminalSession(sessionId, rawLabel) {
|
|
79960
80869
|
const session = terminalSessionsById.get(sessionId);
|
|
79961
80870
|
if (!session) return null;
|
|
@@ -79995,18 +80904,24 @@ function createConsoleObservabilityStore(deps = {}) {
|
|
|
79995
80904
|
clear,
|
|
79996
80905
|
getLaunchCwd,
|
|
79997
80906
|
getTruncation,
|
|
80907
|
+
getDurableOperation,
|
|
79998
80908
|
getWorkspace,
|
|
79999
80909
|
listEvents,
|
|
80000
80910
|
listJobs,
|
|
80911
|
+
listDurableOperations,
|
|
80001
80912
|
listTerminalSessions,
|
|
80002
80913
|
listWorkspaces,
|
|
80003
80914
|
appendTerminalRuntimeEvent,
|
|
80004
80915
|
createPendingTerminalSession,
|
|
80916
|
+
injectDormantOperation,
|
|
80005
80917
|
notifySessionUpdated,
|
|
80006
80918
|
renameTerminalSession,
|
|
80007
80919
|
subscribe,
|
|
80008
80920
|
subscribeAll,
|
|
80921
|
+
updateTerminalSessionProviderSession,
|
|
80009
80922
|
updateTerminalSessionStatus,
|
|
80923
|
+
setTerminalSessionTurnState,
|
|
80924
|
+
transitionTerminalSessionToDormant,
|
|
80010
80925
|
removeTerminalSession,
|
|
80011
80926
|
registerTerminalRuntimeSession,
|
|
80012
80927
|
workspaceCount: () => listWorkspaces().length
|
|
@@ -80074,11 +80989,13 @@ function toTerminalSessionInfo(state) {
|
|
|
80074
80989
|
cliId: state.cliId,
|
|
80075
80990
|
cliLabel: state.cliLabel,
|
|
80076
80991
|
status: state.status,
|
|
80992
|
+
turnState: state.turnState ?? "none",
|
|
80077
80993
|
createdAt: state.createdAt,
|
|
80078
80994
|
theaterId: state.theaterId,
|
|
80079
80995
|
registrationId: state.registrationId,
|
|
80080
80996
|
cliRunId: state.cliRunId,
|
|
80081
|
-
tenantId: state.cliRunId
|
|
80997
|
+
tenantId: state.cliRunId,
|
|
80998
|
+
resumeAvailable: state.providerSession !== void 0
|
|
80082
80999
|
};
|
|
80083
81000
|
}
|
|
80084
81001
|
function pruneTenantJobs(state) {
|
|
@@ -80289,10 +81206,130 @@ function resolveConsolePath(pathname) {
|
|
|
80289
81206
|
if (!path93__default.extname(withoutPrefix)) return "index.html";
|
|
80290
81207
|
return withoutPrefix;
|
|
80291
81208
|
}
|
|
81209
|
+
var TerminalFolderListError = class extends Error {
|
|
81210
|
+
code;
|
|
81211
|
+
constructor(code) {
|
|
81212
|
+
super(code);
|
|
81213
|
+
this.name = "TerminalFolderListError";
|
|
81214
|
+
this.code = code;
|
|
81215
|
+
}
|
|
81216
|
+
};
|
|
81217
|
+
var DIRECTORY_ENTRY_CAP = 500;
|
|
81218
|
+
var WINDOWS_DRIVE_LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");
|
|
81219
|
+
async function listTerminalFolders(requestedPath, deps = {}) {
|
|
81220
|
+
const platform2 = deps.platform ?? process.platform;
|
|
81221
|
+
const stat5 = deps.stat ?? fs5__default.promises.stat;
|
|
81222
|
+
const opendir = deps.opendir ?? fs5__default.promises.opendir;
|
|
81223
|
+
const targetPath = normalizeListPath(requestedPath, platform2, deps);
|
|
81224
|
+
const roots = await listRoots(platform2, stat5);
|
|
81225
|
+
const targetStat = await statDirectory(targetPath, stat5);
|
|
81226
|
+
if (!targetStat.isDirectory()) throw new TerminalFolderListError("invalid_path");
|
|
81227
|
+
const entries = [];
|
|
81228
|
+
const truncated = await collectDirectoryEntries(targetPath, opendir, stat5, entries);
|
|
81229
|
+
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
81230
|
+
return {
|
|
81231
|
+
path: targetPath,
|
|
81232
|
+
parentPath: parentPath(targetPath, platform2),
|
|
81233
|
+
roots,
|
|
81234
|
+
entries,
|
|
81235
|
+
...truncated ? { truncated: true } : {}
|
|
81236
|
+
};
|
|
81237
|
+
}
|
|
81238
|
+
function normalizeFolderBrowserPath(value, platform2 = process.platform) {
|
|
81239
|
+
if (typeof value !== "string" || value.length === 0 || value.includes("\0")) throw new TerminalFolderListError("invalid_path");
|
|
81240
|
+
if (isWindowsAmbiguousPath(value, platform2) || !path93__default.isAbsolute(value)) throw new TerminalFolderListError("invalid_path");
|
|
81241
|
+
return path93__default.resolve(value);
|
|
81242
|
+
}
|
|
81243
|
+
function normalizeListPath(requestedPath, platform2, deps) {
|
|
81244
|
+
if (requestedPath === null || requestedPath === void 0) {
|
|
81245
|
+
const home = deps.homedir?.() ?? os22__default.homedir();
|
|
81246
|
+
const start = home || deps.cwd?.() || process.cwd();
|
|
81247
|
+
return path93__default.resolve(start);
|
|
81248
|
+
}
|
|
81249
|
+
return normalizeFolderBrowserPath(requestedPath, platform2);
|
|
81250
|
+
}
|
|
81251
|
+
async function listRoots(platform2, stat5) {
|
|
81252
|
+
if (platform2 !== "win32") return ["/"];
|
|
81253
|
+
const roots = [];
|
|
81254
|
+
await Promise.all(WINDOWS_DRIVE_LETTERS.map(async (letter) => {
|
|
81255
|
+
const root = `${letter}:\\`;
|
|
81256
|
+
try {
|
|
81257
|
+
if ((await stat5(root)).isDirectory()) roots.push(root);
|
|
81258
|
+
} catch {
|
|
81259
|
+
}
|
|
81260
|
+
}));
|
|
81261
|
+
return roots.sort();
|
|
81262
|
+
}
|
|
81263
|
+
async function statDirectory(targetPath, stat5) {
|
|
81264
|
+
try {
|
|
81265
|
+
return await stat5(targetPath);
|
|
81266
|
+
} catch (error512) {
|
|
81267
|
+
throw mapFsError(error512);
|
|
81268
|
+
}
|
|
81269
|
+
}
|
|
81270
|
+
async function collectDirectoryEntries(targetPath, opendir, stat5, entries) {
|
|
81271
|
+
const directory = await openDirectory(targetPath, opendir);
|
|
81272
|
+
try {
|
|
81273
|
+
let dirent = await directory.read();
|
|
81274
|
+
while (dirent !== null) {
|
|
81275
|
+
const entry = await toTerminalFolderEntry(targetPath, dirent, stat5);
|
|
81276
|
+
if (entry !== null) {
|
|
81277
|
+
if (entries.length >= DIRECTORY_ENTRY_CAP) return true;
|
|
81278
|
+
entries.push(entry);
|
|
81279
|
+
}
|
|
81280
|
+
dirent = await directory.read();
|
|
81281
|
+
}
|
|
81282
|
+
return false;
|
|
81283
|
+
} catch (error512) {
|
|
81284
|
+
throw mapFsError(error512);
|
|
81285
|
+
} finally {
|
|
81286
|
+
await directory.close();
|
|
81287
|
+
}
|
|
81288
|
+
}
|
|
81289
|
+
async function openDirectory(targetPath, opendir) {
|
|
81290
|
+
try {
|
|
81291
|
+
return await opendir(targetPath);
|
|
81292
|
+
} catch (error512) {
|
|
81293
|
+
throw mapFsError(error512);
|
|
81294
|
+
}
|
|
81295
|
+
}
|
|
81296
|
+
async function toTerminalFolderEntry(targetPath, dirent, stat5) {
|
|
81297
|
+
if (!dirent.isDirectory() && !dirent.isSymbolicLink()) return null;
|
|
81298
|
+
const entryPath = path93__default.join(targetPath, dirent.name);
|
|
81299
|
+
if (dirent.isDirectory()) return { name: dirent.name, path: entryPath, kind: "dir", accessible: true };
|
|
81300
|
+
const accessible = await statSymlinkDirectory(entryPath, stat5);
|
|
81301
|
+
if (accessible === null) return null;
|
|
81302
|
+
return { name: dirent.name, path: entryPath, kind: "dir", accessible };
|
|
81303
|
+
}
|
|
81304
|
+
async function statSymlinkDirectory(entryPath, stat5) {
|
|
81305
|
+
try {
|
|
81306
|
+
return (await stat5(entryPath)).isDirectory() ? true : null;
|
|
81307
|
+
} catch {
|
|
81308
|
+
return false;
|
|
81309
|
+
}
|
|
81310
|
+
}
|
|
81311
|
+
function mapFsError(error512) {
|
|
81312
|
+
const code = error512.code;
|
|
81313
|
+
if (code === "EACCES" || code === "EPERM") return new TerminalFolderListError("forbidden");
|
|
81314
|
+
if (code === "ENOENT" || code === "ENOTDIR") return new TerminalFolderListError("not_found");
|
|
81315
|
+
return new TerminalFolderListError("invalid_path");
|
|
81316
|
+
}
|
|
81317
|
+
function parentPath(targetPath, platform2) {
|
|
81318
|
+
const parsed = path93__default.parse(targetPath);
|
|
81319
|
+
const resolved = path93__default.resolve(targetPath);
|
|
81320
|
+
if (resolved === path93__default.resolve(parsed.root)) return null;
|
|
81321
|
+
const parent = path93__default.dirname(resolved);
|
|
81322
|
+
if (platform2 === "win32" && parent === resolved) return null;
|
|
81323
|
+
return parent;
|
|
81324
|
+
}
|
|
81325
|
+
function isWindowsAmbiguousPath(value, platform2) {
|
|
81326
|
+
if (platform2 !== "win32") return false;
|
|
81327
|
+
return /^[a-zA-Z]:(?![\\/])/.test(value) || /^[\\/](?![\\/])/.test(value);
|
|
81328
|
+
}
|
|
80292
81329
|
var GRANT_ID_BYTES = 24;
|
|
80293
81330
|
var DEFAULT_GRANT_TTL_MS = 6e4;
|
|
80294
81331
|
function createFolderGrantStore(deps = {}) {
|
|
80295
|
-
const randomId = deps.randomId ?? (() =>
|
|
81332
|
+
const randomId = deps.randomId ?? (() => crypto5.randomBytes(GRANT_ID_BYTES).toString("base64url"));
|
|
80296
81333
|
const statSync52 = deps.statSync ?? fs5__default.statSync;
|
|
80297
81334
|
const ttlMs = deps.ttlMs ?? DEFAULT_GRANT_TTL_MS;
|
|
80298
81335
|
const now = deps.now ?? Date.now;
|
|
@@ -80320,165 +81357,15 @@ function createFolderGrantStore(deps = {}) {
|
|
|
80320
81357
|
return { issue: issue32, consume };
|
|
80321
81358
|
}
|
|
80322
81359
|
function validateAbsoluteDirectory(cwd, statSync52 = fs5__default.statSync) {
|
|
80323
|
-
if (
|
|
81360
|
+
if (typeof cwd !== "string" || cwd.length === 0 || cwd.includes("\0")) throw new Error("invalid_folder");
|
|
81361
|
+
if (isWindowsAmbiguousPath2(cwd) || !path93__default.isAbsolute(cwd)) throw new Error("invalid_folder");
|
|
80324
81362
|
const normalized = path93__default.resolve(cwd);
|
|
80325
81363
|
if (!statSync52(normalized).isDirectory()) throw new Error("invalid_folder");
|
|
80326
81364
|
return normalized;
|
|
80327
81365
|
}
|
|
80328
|
-
|
|
80329
|
-
|
|
80330
|
-
|
|
80331
|
-
using System;
|
|
80332
|
-
using System.Runtime.InteropServices;
|
|
80333
|
-
namespace FleetPicker {
|
|
80334
|
-
[ComImport, Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
|
80335
|
-
public interface IShellItem {
|
|
80336
|
-
void BindToHandler();
|
|
80337
|
-
void GetParent();
|
|
80338
|
-
[PreserveSig] int GetDisplayName(int sigdn, out IntPtr ppszName);
|
|
80339
|
-
void GetAttributes();
|
|
80340
|
-
void Compare();
|
|
80341
|
-
}
|
|
80342
|
-
[ComImport, Guid("d57c7288-d4ad-4768-be02-9d969532d960"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
|
80343
|
-
public interface IFileOpenDialog {
|
|
80344
|
-
[PreserveSig] int Show(IntPtr parent);
|
|
80345
|
-
void SetFileTypes(); void SetFileTypeIndex(); void GetFileTypeIndex();
|
|
80346
|
-
void Advise(); void Unadvise();
|
|
80347
|
-
[PreserveSig] int SetOptions(uint fos);
|
|
80348
|
-
[PreserveSig] int GetOptions(out uint pfos);
|
|
80349
|
-
void SetDefaultFolder();
|
|
80350
|
-
void SetFolder(IShellItem psi);
|
|
80351
|
-
void GetFolder(); void GetCurrentSelection();
|
|
80352
|
-
void SetFileName(); void GetFileName(); void SetTitle(); void SetOkButtonLabel(); void SetFileNameLabel();
|
|
80353
|
-
[PreserveSig] int GetResult(out IShellItem ppsi);
|
|
80354
|
-
void AddPlace(IShellItem psi, int fdap);
|
|
80355
|
-
void SetDefaultExtension(); void Close(); void SetClientGuid(); void ClearClientData(); void SetFilter();
|
|
80356
|
-
void GetResults(); void GetSelectedItems();
|
|
80357
|
-
}
|
|
80358
|
-
[ComImport, Guid("DC1C5A9C-E88A-4DDE-A5A1-60F82A20AEF7")] public class FileOpenDialog { }
|
|
80359
|
-
public static class Picker {
|
|
80360
|
-
[DllImport("shell32.dll", CharSet=CharSet.Unicode, PreserveSig=false)]
|
|
80361
|
-
static extern void SHCreateItemFromParsingName(string pszPath, IntPtr pbc, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out IShellItem ppv);
|
|
80362
|
-
static IShellItem ItemFromPath(string path) {
|
|
80363
|
-
Guid iid = new Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe");
|
|
80364
|
-
IShellItem it; SHCreateItemFromParsingName(path, IntPtr.Zero, ref iid, out it); return it;
|
|
80365
|
-
}
|
|
80366
|
-
public static string Pick(string initialPath) {
|
|
80367
|
-
var dlg = (IFileOpenDialog)(new FileOpenDialog());
|
|
80368
|
-
uint opts; dlg.GetOptions(out opts);
|
|
80369
|
-
dlg.SetOptions(opts | 0x20); // FOS_PICKFOLDERS
|
|
80370
|
-
if (!string.IsNullOrEmpty(initialPath)) {
|
|
80371
|
-
// \uC2DC\uC791 \uD3F4\uB354\uB97C WSL \uC704\uCE58\uB85C \uC9C0\uC815\uD558\uACE0 \uC88C\uCE21\uC5D0 \uACE0\uC815(FDAP_TOP). \uC2E4\uD328\uD574\uB3C4 \uAE30\uBCF8 \uC704\uCE58\uB85C \uC9C4\uD589\uD55C\uB2E4.
|
|
80372
|
-
try { IShellItem s = ItemFromPath(initialPath); dlg.AddPlace(s, 1); dlg.SetFolder(s); } catch { }
|
|
80373
|
-
}
|
|
80374
|
-
if (dlg.Show(IntPtr.Zero) != 0) return null; // \uCDE8\uC18C/\uC2E4\uD328 \uC2DC null
|
|
80375
|
-
IShellItem item; dlg.GetResult(out item);
|
|
80376
|
-
IntPtr ptr; if (item.GetDisplayName(unchecked((int)0x80058000), out ptr) != 0) return null; // SIGDN_FILESYSPATH; \uBE44 \uD30C\uC77C\uC2DC\uC2A4\uD15C \uC120\uD0DD \uAC00\uB4DC
|
|
80377
|
-
string path = Marshal.PtrToStringAuto(ptr);
|
|
80378
|
-
Marshal.FreeCoTaskMem(ptr);
|
|
80379
|
-
return path;
|
|
80380
|
-
}
|
|
80381
|
-
}
|
|
80382
|
-
}`;
|
|
80383
|
-
function createNativeFolderPicker(deps = {}) {
|
|
80384
|
-
const platform2 = deps.platform ?? process.platform;
|
|
80385
|
-
const runCommand = deps.runCommand ?? runNativeCommand;
|
|
80386
|
-
const statSync52 = deps.statSync ?? fs5__default.statSync;
|
|
80387
|
-
const readProcVersion = deps.readProcVersion ?? defaultReadProcVersion;
|
|
80388
|
-
const env = deps.env ?? process.env;
|
|
80389
|
-
return async () => {
|
|
80390
|
-
const isWsl = platform2 === "linux" && detectWsl(readProcVersion, env);
|
|
80391
|
-
const wslStartPath = isWsl ? wslStartFolderUnc(env) : "";
|
|
80392
|
-
const commands = buildPickerCommands(platform2, isWsl, wslStartPath);
|
|
80393
|
-
if (commands.length === 0) return { kind: "error", error: "unsupported_platform" };
|
|
80394
|
-
for (const command22 of commands) {
|
|
80395
|
-
const result = await runPickerCommand(runCommand, command22);
|
|
80396
|
-
if ("kind" in result && result.kind === "unavailable") continue;
|
|
80397
|
-
if ("kind" in result && result.kind === "cancelled") return { kind: "cancelled" };
|
|
80398
|
-
if ("kind" in result && result.kind === "timeout") return { kind: "error", error: "dialog_timeout" };
|
|
80399
|
-
if ("kind" in result) continue;
|
|
80400
|
-
let resolvedPath = result.stdout.trim();
|
|
80401
|
-
if (command22.postProcess === "wslpath") {
|
|
80402
|
-
try {
|
|
80403
|
-
const wslResult = await runCommand("wslpath", ["-u", resolvedPath]);
|
|
80404
|
-
resolvedPath = wslResult.stdout.trim();
|
|
80405
|
-
} catch {
|
|
80406
|
-
return { kind: "error", error: "invalid_folder" };
|
|
80407
|
-
}
|
|
80408
|
-
}
|
|
80409
|
-
try {
|
|
80410
|
-
return { kind: "selected", cwd: validateAbsoluteDirectory(resolvedPath, statSync52) };
|
|
80411
|
-
} catch {
|
|
80412
|
-
return { kind: "error", error: "invalid_folder" };
|
|
80413
|
-
}
|
|
80414
|
-
}
|
|
80415
|
-
return { kind: "error", error: "dialog_unavailable" };
|
|
80416
|
-
};
|
|
80417
|
-
}
|
|
80418
|
-
function defaultReadProcVersion() {
|
|
80419
|
-
try {
|
|
80420
|
-
return fs5__default.readFileSync("/proc/version", "utf8");
|
|
80421
|
-
} catch {
|
|
80422
|
-
return "";
|
|
80423
|
-
}
|
|
80424
|
-
}
|
|
80425
|
-
function detectWsl(readProcVersion, env) {
|
|
80426
|
-
if (env.WSL_INTEROP !== void 0 || env.WSL_DISTRO_NAME !== void 0) return true;
|
|
80427
|
-
return /microsoft|wsl/i.test(readProcVersion());
|
|
80428
|
-
}
|
|
80429
|
-
function buildPickerCommands(platform2, isWsl = false, wslStartPath = "") {
|
|
80430
|
-
if (platform2 === "darwin") {
|
|
80431
|
-
return [{ bin: "osascript", args: ["-e", 'POSIX path of (choose folder with prompt "Choose a Fleet workspace")'] }];
|
|
80432
|
-
}
|
|
80433
|
-
if (platform2 === "linux") {
|
|
80434
|
-
const commands = [];
|
|
80435
|
-
if (isWsl) {
|
|
80436
|
-
commands.push({ bin: "powershell.exe", args: buildPowerShellPickerArgs(wslStartPath), postProcess: "wslpath" });
|
|
80437
|
-
}
|
|
80438
|
-
commands.push(
|
|
80439
|
-
{ bin: "zenity", args: ["--file-selection", "--directory", "--title=Choose a Fleet workspace"] },
|
|
80440
|
-
{ bin: "kdialog", args: ["--getexistingdirectory", ".", "Choose a Fleet workspace"] }
|
|
80441
|
-
);
|
|
80442
|
-
return commands;
|
|
80443
|
-
}
|
|
80444
|
-
if (platform2 === "win32") {
|
|
80445
|
-
return [{ bin: "powershell.exe", args: buildPowerShellPickerArgs("") }];
|
|
80446
|
-
}
|
|
80447
|
-
return [];
|
|
80448
|
-
}
|
|
80449
|
-
function buildPowerShellPickerArgs(initialWindowsPath) {
|
|
80450
|
-
const escaped = initialWindowsPath.replace(/'/g, "''");
|
|
80451
|
-
const script = [
|
|
80452
|
-
"[Console]::OutputEncoding=[Text.Encoding]::UTF8",
|
|
80453
|
-
`Add-Type -TypeDefinition '${POWERSHELL_FOLDER_PICKER_CSHARP}'`,
|
|
80454
|
-
`$selection = [FleetPicker.Picker]::Pick('${escaped}')`,
|
|
80455
|
-
"if ([string]::IsNullOrEmpty($selection)) { exit 1 }",
|
|
80456
|
-
"[Console]::Out.Write($selection)"
|
|
80457
|
-
].join("\n");
|
|
80458
|
-
return ["-NoProfile", "-Sta", "-Command", script];
|
|
80459
|
-
}
|
|
80460
|
-
function wslStartFolderUnc(env) {
|
|
80461
|
-
const distro = env.WSL_DISTRO_NAME;
|
|
80462
|
-
if (!distro) return "";
|
|
80463
|
-
const home = env.HOME;
|
|
80464
|
-
if (home && home.startsWith("/") && !home.startsWith("/mnt/")) {
|
|
80465
|
-
return `\\\\wsl.localhost\\${distro}${home.replace(/\//g, "\\")}`;
|
|
80466
|
-
}
|
|
80467
|
-
return `\\\\wsl.localhost\\${distro}`;
|
|
80468
|
-
}
|
|
80469
|
-
async function runPickerCommand(runCommand, command22) {
|
|
80470
|
-
try {
|
|
80471
|
-
return await runCommand(command22.bin, command22.args);
|
|
80472
|
-
} catch (error512) {
|
|
80473
|
-
const err = error512;
|
|
80474
|
-
if (err.code === "ENOENT") return { kind: "unavailable" };
|
|
80475
|
-
if (err.code === "ETIMEDOUT") return { kind: "timeout" };
|
|
80476
|
-
return { kind: "cancelled" };
|
|
80477
|
-
}
|
|
80478
|
-
}
|
|
80479
|
-
async function runNativeCommand(bin, args) {
|
|
80480
|
-
const result = await execFileAsync(bin, [...args], { timeout: DIALOG_TIMEOUT_MS, windowsHide: true });
|
|
80481
|
-
return { stdout: result.stdout, stderr: result.stderr };
|
|
81366
|
+
function isWindowsAmbiguousPath2(value) {
|
|
81367
|
+
if (process.platform !== "win32") return false;
|
|
81368
|
+
return /^[a-zA-Z]:(?![\\/])/.test(value) || /^[\\/](?![\\/])/.test(value);
|
|
80482
81369
|
}
|
|
80483
81370
|
var JAVASCRIPT_ENTRY_EXTENSIONS2 = /* @__PURE__ */ new Set([".cjs", ".js", ".mjs"]);
|
|
80484
81371
|
var TYPESCRIPT_ENTRY_EXTENSIONS2 = /* @__PURE__ */ new Set([".cts", ".mts", ".ts", ".tsx"]);
|
|
@@ -80487,29 +81374,43 @@ function buildConsoleHookCommand(entry) {
|
|
|
80487
81374
|
if (entry === void 0) {
|
|
80488
81375
|
throw new Error("Fleet Console session hook command requires the current console entry path");
|
|
80489
81376
|
}
|
|
81377
|
+
return buildConsoleCliHookExec(entry, ["hook", "subagents-context"]);
|
|
81378
|
+
}
|
|
81379
|
+
function buildConsoleTurnHookCommand(entry, phase) {
|
|
81380
|
+
return buildConsoleCliHookExec(entry, ["hook", phase === "start" ? "turn-start" : "turn-end"]);
|
|
81381
|
+
}
|
|
81382
|
+
function buildConsoleCaptureHookCommand(entry, cliId) {
|
|
80490
81383
|
const extension = path93__default.extname(entry.entryPath);
|
|
80491
81384
|
if (JAVASCRIPT_ENTRY_EXTENSIONS2.has(extension)) {
|
|
80492
|
-
return {
|
|
80493
|
-
|
|
80494
|
-
|
|
80495
|
-
|
|
81385
|
+
return createSessionCaptureHookExec({
|
|
81386
|
+
entryPath: entry.entryPath,
|
|
81387
|
+
execPath: entry.execPath,
|
|
81388
|
+
provider: toCaptureProvider(cliId)
|
|
81389
|
+
});
|
|
80496
81390
|
}
|
|
80497
81391
|
if (TYPESCRIPT_ENTRY_EXTENSIONS2.has(extension)) {
|
|
80498
81392
|
if (!entry.tsxLoaderPath) {
|
|
80499
|
-
throw new Error("Fleet Console session hook
|
|
81393
|
+
throw new Error("Fleet Console capture session hook requires a tsx loader path");
|
|
80500
81394
|
}
|
|
80501
|
-
return {
|
|
80502
|
-
|
|
80503
|
-
|
|
80504
|
-
|
|
81395
|
+
return createSessionCaptureHookExec({
|
|
81396
|
+
entryPath: entry.entryPath,
|
|
81397
|
+
execPath: entry.execPath,
|
|
81398
|
+
provider: toCaptureProvider(cliId),
|
|
81399
|
+
tsxLoader: entry.tsxLoaderPath
|
|
81400
|
+
});
|
|
80505
81401
|
}
|
|
80506
81402
|
throw new Error(`Unsupported Fleet Console session hook entry extension: ${extension}`);
|
|
80507
81403
|
}
|
|
81404
|
+
function toCaptureProvider(cliId) {
|
|
81405
|
+
return cliId === "codex" ? "codex" : "claude";
|
|
81406
|
+
}
|
|
80508
81407
|
function runCodexCommand2(command22) {
|
|
80509
81408
|
const result = spawnSync2(command22.bin, command22.args, {
|
|
80510
81409
|
cwd: command22.cwd,
|
|
80511
81410
|
encoding: "utf8",
|
|
80512
|
-
env: command22.env
|
|
81411
|
+
env: command22.env,
|
|
81412
|
+
// 콘솔 없는 fleet-console 백엔드에서 codex 등록 명령 실행 시 콘솔 창이 깜빡이는 것을 방지한다.
|
|
81413
|
+
windowsHide: true
|
|
80513
81414
|
});
|
|
80514
81415
|
return {
|
|
80515
81416
|
status: result.status,
|
|
@@ -80522,18 +81423,37 @@ function withConsoleMarketplaceLock(target, fn) {
|
|
|
80522
81423
|
mkdirSync8(path93__default.dirname(lockDir), { recursive: true });
|
|
80523
81424
|
return withDirectoryLock2({ lockDir }, fn);
|
|
80524
81425
|
}
|
|
81426
|
+
function buildConsoleCliHookExec(entry, trailingArgs) {
|
|
81427
|
+
const extension = path93__default.extname(entry.entryPath);
|
|
81428
|
+
if (JAVASCRIPT_ENTRY_EXTENSIONS2.has(extension)) {
|
|
81429
|
+
return {
|
|
81430
|
+
command: entry.execPath,
|
|
81431
|
+
args: [entry.entryPath, ...trailingArgs]
|
|
81432
|
+
};
|
|
81433
|
+
}
|
|
81434
|
+
if (TYPESCRIPT_ENTRY_EXTENSIONS2.has(extension)) {
|
|
81435
|
+
if (!entry.tsxLoaderPath) {
|
|
81436
|
+
throw new Error("Fleet Console session hook command for TypeScript entries requires a tsx loader path");
|
|
81437
|
+
}
|
|
81438
|
+
return {
|
|
81439
|
+
command: entry.execPath,
|
|
81440
|
+
args: ["--import", pathToFileURL2(entry.tsxLoaderPath).href, entry.entryPath, ...trailingArgs]
|
|
81441
|
+
};
|
|
81442
|
+
}
|
|
81443
|
+
throw new Error(`Unsupported Fleet Console session hook entry extension: ${extension}`);
|
|
81444
|
+
}
|
|
80525
81445
|
var DEFAULT_TERMINAL_CWD_FALLBACK = os22__default.homedir;
|
|
80526
81446
|
var TERMINAL_TERM = "xterm-256color";
|
|
80527
81447
|
var CONSOLE_ENTRY_PATH = fileURLToPath(import.meta.url);
|
|
80528
81448
|
var HOOK_ENTRY_EXTENSIONS = /* @__PURE__ */ new Set([".cjs", ".cts", ".js", ".mjs", ".mts", ".ts", ".tsx"]);
|
|
80529
81449
|
var require2 = createRequire(import.meta.url);
|
|
80530
81450
|
function createDefaultTerminalLaunchResolver(deps = {}) {
|
|
80531
|
-
const baseCwd = deps.cwd ??
|
|
80532
|
-
const env = deps.env ??
|
|
80533
|
-
const execPath = deps.execPath ??
|
|
81451
|
+
const baseCwd = deps.cwd ?? process6.cwd();
|
|
81452
|
+
const env = deps.env ?? process6.env;
|
|
81453
|
+
const execPath = deps.execPath ?? process6.execPath;
|
|
80534
81454
|
const homedir32 = deps.homedir ?? DEFAULT_TERMINAL_CWD_FALLBACK;
|
|
80535
|
-
const platform2 = deps.platform ??
|
|
80536
|
-
const entryPath = resolveHookEntryPath(deps.entryPath ??
|
|
81455
|
+
const platform2 = deps.platform ?? process6.platform;
|
|
81456
|
+
const entryPath = resolveHookEntryPath(deps.entryPath ?? process6.argv[1]);
|
|
80537
81457
|
const tsxLoaderPath = deps.tsxLoaderPath ?? resolveOptionalPackage("tsx");
|
|
80538
81458
|
const dataDir = deps.dataDir ?? getFleetDataDir2();
|
|
80539
81459
|
const infraServices = deps.infraServices ?? createInfraServices2();
|
|
@@ -80573,6 +81493,7 @@ function createDefaultTerminalLaunchResolver(deps = {}) {
|
|
|
80573
81493
|
onRuntimeSessionStart: deps.onRuntimeSessionStart,
|
|
80574
81494
|
resolveProfile,
|
|
80575
81495
|
cliId: context?.cliId,
|
|
81496
|
+
resumeSessionId: context?.resumeSessionId,
|
|
80576
81497
|
sessionId
|
|
80577
81498
|
});
|
|
80578
81499
|
};
|
|
@@ -80593,7 +81514,7 @@ function hasHookEntryExtension(entryPath) {
|
|
|
80593
81514
|
}
|
|
80594
81515
|
function startTerminalShell(launch, size) {
|
|
80595
81516
|
const { spawn: spawnPty } = require2("node-pty");
|
|
80596
|
-
const useConptyDll = resolveUseConptyDll2(
|
|
81517
|
+
const useConptyDll = resolveUseConptyDll2(process6.platform, process6.env);
|
|
80597
81518
|
return spawnPty(launch.bin, [...launch.args], {
|
|
80598
81519
|
cols: size.cols,
|
|
80599
81520
|
rows: size.rows,
|
|
@@ -80618,7 +81539,8 @@ async function createAgentCliLaunchSpec(options2) {
|
|
|
80618
81539
|
const profile = await options2.resolveProfile(options2.env, options2.cwd, {
|
|
80619
81540
|
authEnvResolver: options2.authEnvResolver,
|
|
80620
81541
|
authService: options2.infraServices.authService,
|
|
80621
|
-
cliId: options2.cliId
|
|
81542
|
+
cliId: options2.cliId,
|
|
81543
|
+
resumeSessionId: options2.resumeSessionId
|
|
80622
81544
|
});
|
|
80623
81545
|
const injectedProfile = await options2.injectProfile(profile, {
|
|
80624
81546
|
buildSystemPrompt: (injectTone) => createSystemPromptBuilder2({ carrierRuntime: agentRuntime.carrierRuntime }).build(injectTone),
|
|
@@ -80627,9 +81549,13 @@ async function createAgentCliLaunchSpec(options2) {
|
|
|
80627
81549
|
dataDir: options2.dataDir,
|
|
80628
81550
|
dedicatedMcpSession: agentRuntime.dedicatedMcpSession,
|
|
80629
81551
|
enableMetaphor: false,
|
|
81552
|
+
captureSessionHookExec: buildConsoleCaptureHookCommand(options2.hookEntry, profile.id),
|
|
81553
|
+
turnStartHookExec: buildConsoleTurnHookCommand(options2.hookEntry, "start"),
|
|
81554
|
+
turnEndHookExec: buildConsoleTurnHookCommand(options2.hookEntry, "end"),
|
|
80630
81555
|
hookExec: buildConsoleHookCommand(options2.hookEntry),
|
|
80631
81556
|
onCleanup: (cleanup) => cleanupStack.push(cleanup),
|
|
80632
|
-
replaceSystemPrompt:
|
|
81557
|
+
replaceSystemPrompt: false,
|
|
81558
|
+
resumeSessionId: options2.resumeSessionId,
|
|
80633
81559
|
withMarketplaceLock: withConsoleMarketplaceLock,
|
|
80634
81560
|
mcpSessionLabel: options2.sessionId
|
|
80635
81561
|
});
|
|
@@ -80663,6 +81589,7 @@ function toLaunchSpec(profile, cleanup) {
|
|
|
80663
81589
|
cwd: profile.cwd,
|
|
80664
81590
|
env: { ...profile.env },
|
|
80665
81591
|
messagePolicy: profile.messagePolicy,
|
|
81592
|
+
renameCommand: profile.renameCommand,
|
|
80666
81593
|
terminalName: profile.terminalName
|
|
80667
81594
|
};
|
|
80668
81595
|
}
|
|
@@ -80723,6 +81650,8 @@ var DEFAULT_COLS = 80;
|
|
|
80723
81650
|
var DEFAULT_ROWS2 = 24;
|
|
80724
81651
|
var DEFAULT_SCROLLBACK_LIMIT = 512;
|
|
80725
81652
|
var WS_OPEN_STATE = 1;
|
|
81653
|
+
var THEATER_SHELL_SESSION_PREFIX = "shell:";
|
|
81654
|
+
var THEATER_SHELL_DETACH_GRACE_MS = 4e3;
|
|
80726
81655
|
function createTerminalSessionManager(deps) {
|
|
80727
81656
|
const startShell2 = deps.startShell ?? startTerminalShell;
|
|
80728
81657
|
const scrollbackLimit = deps.scrollbackLimit ?? DEFAULT_SCROLLBACK_LIMIT;
|
|
@@ -80733,6 +81662,7 @@ function createTerminalSessionManager(deps) {
|
|
|
80733
81662
|
}
|
|
80734
81663
|
async function attach(socket, context) {
|
|
80735
81664
|
const session = await getOrCreateSession(context);
|
|
81665
|
+
clearGraceTimer(session);
|
|
80736
81666
|
if (session.activeSocket && session.activeSocket !== socket) {
|
|
80737
81667
|
session.activeSocket.close(4e3, "terminal_replaced");
|
|
80738
81668
|
}
|
|
@@ -80754,6 +81684,9 @@ function createTerminalSessionManager(deps) {
|
|
|
80754
81684
|
function getSessionMessagePolicy(sessionId) {
|
|
80755
81685
|
return sessions.get(sessionId)?.messagePolicy;
|
|
80756
81686
|
}
|
|
81687
|
+
function getSessionRenameCommand(sessionId) {
|
|
81688
|
+
return sessions.get(sessionId)?.renameCommand;
|
|
81689
|
+
}
|
|
80757
81690
|
function writeToSession(sessionId, data) {
|
|
80758
81691
|
const session = sessions.get(sessionId);
|
|
80759
81692
|
if (!session || typeof session.pty.write !== "function") return false;
|
|
@@ -80791,7 +81724,7 @@ function createTerminalSessionManager(deps) {
|
|
|
80791
81724
|
}
|
|
80792
81725
|
}
|
|
80793
81726
|
async function launchSession(context) {
|
|
80794
|
-
const launch = await deps.launch(context.cwd, { sessionId: context.sessionId, kind: context.kind, cliId: context.cliId });
|
|
81727
|
+
const launch = await deps.launch(context.cwd, { sessionId: context.sessionId, kind: context.kind, cliId: context.cliId, resumeSessionId: context.resumeSessionId });
|
|
80795
81728
|
let pty;
|
|
80796
81729
|
try {
|
|
80797
81730
|
pty = startShell2(launch, { cols: DEFAULT_COLS, rows: DEFAULT_ROWS2 });
|
|
@@ -80806,9 +81739,11 @@ function createTerminalSessionManager(deps) {
|
|
|
80806
81739
|
scrollback: [],
|
|
80807
81740
|
cleanup: launch.cleanup,
|
|
80808
81741
|
messagePolicy: launch.messagePolicy,
|
|
81742
|
+
renameCommand: launch.renameCommand,
|
|
80809
81743
|
activeSocket: null,
|
|
80810
81744
|
cols: DEFAULT_COLS,
|
|
80811
|
-
rows: DEFAULT_ROWS2
|
|
81745
|
+
rows: DEFAULT_ROWS2,
|
|
81746
|
+
graceTimer: null
|
|
80812
81747
|
};
|
|
80813
81748
|
const dataDisposable = pty.onData((data) => handlePtyData(session, data));
|
|
80814
81749
|
const exitDisposable = pty.onExit(() => removeSession(session));
|
|
@@ -80846,6 +81781,13 @@ function createTerminalSessionManager(deps) {
|
|
|
80846
81781
|
function detachSocket(session, socket) {
|
|
80847
81782
|
if (session.activeSocket !== socket) return;
|
|
80848
81783
|
session.activeSocket = null;
|
|
81784
|
+
if (isTheaterShell(session.id)) {
|
|
81785
|
+
clearGraceTimer(session);
|
|
81786
|
+
session.graceTimer = setTimeout(() => {
|
|
81787
|
+
session.graceTimer = null;
|
|
81788
|
+
if (session.activeSocket === null) removeSession(session);
|
|
81789
|
+
}, THEATER_SHELL_DETACH_GRACE_MS);
|
|
81790
|
+
}
|
|
80849
81791
|
}
|
|
80850
81792
|
function replayScrollback(session, socket) {
|
|
80851
81793
|
for (const chunk of session.scrollback) {
|
|
@@ -80861,6 +81803,7 @@ function createTerminalSessionManager(deps) {
|
|
|
80861
81803
|
}
|
|
80862
81804
|
async function killSession(session, options2 = {}) {
|
|
80863
81805
|
const killPty = options2.killPty ?? true;
|
|
81806
|
+
clearGraceTimer(session);
|
|
80864
81807
|
session.activeSocket?.close(4001, "terminal_closed");
|
|
80865
81808
|
session.activeSocket = null;
|
|
80866
81809
|
for (const disposable of session.disposables) disposable.dispose();
|
|
@@ -80870,7 +81813,7 @@ function createTerminalSessionManager(deps) {
|
|
|
80870
81813
|
await runLaunchCleanup(session.cleanup);
|
|
80871
81814
|
}
|
|
80872
81815
|
}
|
|
80873
|
-
return { canAttach, createSession, attach, getSessionMessagePolicy, terminate, stop, writeToSession };
|
|
81816
|
+
return { canAttach, createSession, attach, getSessionMessagePolicy, getSessionRenameCommand, terminate, stop, writeToSession };
|
|
80874
81817
|
}
|
|
80875
81818
|
async function runLaunchCleanup(cleanup) {
|
|
80876
81819
|
try {
|
|
@@ -80884,6 +81827,14 @@ function killPtyBestEffort2(pty) {
|
|
|
80884
81827
|
} catch {
|
|
80885
81828
|
}
|
|
80886
81829
|
}
|
|
81830
|
+
function isTheaterShell(sessionId) {
|
|
81831
|
+
return sessionId.startsWith(THEATER_SHELL_SESSION_PREFIX);
|
|
81832
|
+
}
|
|
81833
|
+
function clearGraceTimer(session) {
|
|
81834
|
+
if (session.graceTimer === null) return;
|
|
81835
|
+
clearTimeout(session.graceTimer);
|
|
81836
|
+
session.graceTimer = null;
|
|
81837
|
+
}
|
|
80887
81838
|
function toBuffer(data) {
|
|
80888
81839
|
if (Buffer.isBuffer(data)) return data;
|
|
80889
81840
|
if (Array.isArray(data)) return Buffer.concat(data);
|
|
@@ -80900,7 +81851,7 @@ var DEFAULT_TICKET_TTL_MS = 1e4;
|
|
|
80900
81851
|
function createTerminalTicketRegistry(deps = {}) {
|
|
80901
81852
|
const ttlMs = deps.ttlMs ?? DEFAULT_TICKET_TTL_MS;
|
|
80902
81853
|
const now = deps.now ?? Date.now;
|
|
80903
|
-
const randomTicket = deps.randomTicket ?? (() =>
|
|
81854
|
+
const randomTicket = deps.randomTicket ?? (() => crypto5.randomBytes(32).toString("base64url"));
|
|
80904
81855
|
const tickets = /* @__PURE__ */ new Map();
|
|
80905
81856
|
function issue32(context) {
|
|
80906
81857
|
prune();
|
|
@@ -80927,7 +81878,7 @@ function createTerminalTicketRegistry(deps = {}) {
|
|
|
80927
81878
|
}
|
|
80928
81879
|
return { ttlMs, issue: issue32, consume, prune };
|
|
80929
81880
|
}
|
|
80930
|
-
var
|
|
81881
|
+
var execFileAsync = promisify(execFile2);
|
|
80931
81882
|
var GIT_STATUS_TIMEOUT_MS = 4e3;
|
|
80932
81883
|
var GIT_STATUS_MAX_BUFFER = 1024 * 1024;
|
|
80933
81884
|
var GIT_HASH_TIMEOUT_MS = 4e3;
|
|
@@ -80936,11 +81887,13 @@ function createWorkspaceChangeScanner() {
|
|
|
80936
81887
|
return {
|
|
80937
81888
|
async snapshot(cwd) {
|
|
80938
81889
|
try {
|
|
80939
|
-
const { stdout } = await
|
|
81890
|
+
const { stdout } = await execFileAsync("git", ["status", "--porcelain=v1", "-z", "--untracked-files=all"], {
|
|
80940
81891
|
cwd,
|
|
80941
81892
|
encoding: "utf8",
|
|
80942
81893
|
maxBuffer: GIT_STATUS_MAX_BUFFER,
|
|
80943
|
-
timeout: GIT_STATUS_TIMEOUT_MS
|
|
81894
|
+
timeout: GIT_STATUS_TIMEOUT_MS,
|
|
81895
|
+
// 콘솔 없는 fleet-console 백엔드에서 git.exe 실행 시 콘솔 창이 깜빡이는 것을 방지한다.
|
|
81896
|
+
windowsHide: true
|
|
80944
81897
|
});
|
|
80945
81898
|
const entries = parseGitStatusPorcelainZ(stdout);
|
|
80946
81899
|
if (!entries) return null;
|
|
@@ -81000,7 +81953,9 @@ function execGitHashObject(cwd, paths) {
|
|
|
81000
81953
|
cwd,
|
|
81001
81954
|
encoding: "utf8",
|
|
81002
81955
|
maxBuffer: GIT_HASH_MAX_BUFFER,
|
|
81003
|
-
timeout: GIT_HASH_TIMEOUT_MS
|
|
81956
|
+
timeout: GIT_HASH_TIMEOUT_MS,
|
|
81957
|
+
// 콘솔 없는 fleet-console 백엔드에서 git.exe 실행 시 콘솔 창이 깜빡이는 것을 방지한다.
|
|
81958
|
+
windowsHide: true
|
|
81004
81959
|
},
|
|
81005
81960
|
(error512, stdout) => {
|
|
81006
81961
|
if (error512) {
|
|
@@ -81088,6 +82043,26 @@ var TheaterRegistry = class {
|
|
|
81088
82043
|
this.#mruId = id;
|
|
81089
82044
|
return item;
|
|
81090
82045
|
}
|
|
82046
|
+
load(items) {
|
|
82047
|
+
this.restore(items);
|
|
82048
|
+
}
|
|
82049
|
+
restore(items) {
|
|
82050
|
+
const restored = /* @__PURE__ */ new Map();
|
|
82051
|
+
let mruId = null;
|
|
82052
|
+
for (const item of items) {
|
|
82053
|
+
const existing = restored.get(item.id);
|
|
82054
|
+
if (existing && existing.realpath !== item.realpath) {
|
|
82055
|
+
throw new Error("theater_id_collision");
|
|
82056
|
+
}
|
|
82057
|
+
restored.set(item.id, item);
|
|
82058
|
+
if (!mruId || item.lastOpenedAt.localeCompare(restored.get(mruId)?.lastOpenedAt ?? "") > 0) {
|
|
82059
|
+
mruId = item.id;
|
|
82060
|
+
}
|
|
82061
|
+
}
|
|
82062
|
+
this.#items.clear();
|
|
82063
|
+
for (const [id, item] of restored) this.#items.set(id, item);
|
|
82064
|
+
this.#mruId = mruId;
|
|
82065
|
+
}
|
|
81091
82066
|
get(id) {
|
|
81092
82067
|
return this.#items.get(id) ?? null;
|
|
81093
82068
|
}
|
|
@@ -81097,6 +82072,11 @@ var TheaterRegistry = class {
|
|
|
81097
82072
|
list() {
|
|
81098
82073
|
return [...this.#items.values()].sort((left, right) => right.lastOpenedAt.localeCompare(left.lastOpenedAt));
|
|
81099
82074
|
}
|
|
82075
|
+
remove(id) {
|
|
82076
|
+
const removed = this.#items.delete(id);
|
|
82077
|
+
if (this.#mruId === id) this.#mruId = this.list()[0]?.id ?? null;
|
|
82078
|
+
return removed;
|
|
82079
|
+
}
|
|
81100
82080
|
};
|
|
81101
82081
|
var FLEET_CONSOLE_PACKAGE_NAME = "@dotobokuri/fleet-console";
|
|
81102
82082
|
var UPDATE_CHECK_TTL_MS = 60 * 60 * 1e3;
|
|
@@ -81152,6 +82132,7 @@ function createConsoleUpdateCheckService(deps = {}) {
|
|
|
81152
82132
|
var DEFAULT_HOST22 = "127.0.0.1";
|
|
81153
82133
|
var DEFAULT_PORT22 = 0;
|
|
81154
82134
|
var SHELL_TERMINAL_SESSION_ID = "shell";
|
|
82135
|
+
var THEATER_SHELL_SESSION_PREFIX2 = "shell:";
|
|
81155
82136
|
var SERVER_TIMEOUT_MS = 30 * 60 * 1e3;
|
|
81156
82137
|
var MAX_BODY_BYTES = 1024 * 1024;
|
|
81157
82138
|
function createConsoleServer(deps = {}) {
|
|
@@ -81169,6 +82150,9 @@ function createConsoleServer(deps = {}) {
|
|
|
81169
82150
|
const folderGrants = createFolderGrantStore();
|
|
81170
82151
|
const infraServices = createInfraServices2();
|
|
81171
82152
|
const dataDir = deps.dataDir ?? getFleetDataDir2();
|
|
82153
|
+
initStore2(dataDir);
|
|
82154
|
+
const durablePaths = createConsoleDataPaths({ fleetDataDir: dataDir });
|
|
82155
|
+
const durableStateStore = createConsoleDurableStateStore({ paths: durablePaths });
|
|
81172
82156
|
const authEnvResolver = (cli) => resolveAuthEnv2(cli, { authService: infraServices.authService });
|
|
81173
82157
|
const ownsAgentRuntime = deps.agentRuntime === void 0;
|
|
81174
82158
|
const agentRuntime = deps.agentRuntime ?? createFleetAgentRuntimeLifecycle2({
|
|
@@ -81193,7 +82177,6 @@ function createConsoleServer(deps = {}) {
|
|
|
81193
82177
|
getPort: () => lockHandle?.payload.port ?? port,
|
|
81194
82178
|
getAdminToken: () => lockHandle?.payload.token ?? null
|
|
81195
82179
|
});
|
|
81196
|
-
const pickTerminalFolder = deps.terminalPickFolder ?? createNativeFolderPicker();
|
|
81197
82180
|
const pendingRuntimeSessions = /* @__PURE__ */ new Map();
|
|
81198
82181
|
const terminalSessions = createTerminalSessionManager({
|
|
81199
82182
|
launch: deps.terminalLaunch ?? createDefaultTerminalLaunchResolver({
|
|
@@ -81207,10 +82190,18 @@ function createConsoleServer(deps = {}) {
|
|
|
81207
82190
|
}),
|
|
81208
82191
|
startShell: deps.terminalStartShell,
|
|
81209
82192
|
maxSessions: deps.maxTerminalSessions,
|
|
81210
|
-
// PTY가 종료되면 콘솔 세션 목록에서도 제거해 잔존/재실행을 막는다.
|
|
81211
82193
|
onSessionExit: (sessionId) => {
|
|
81212
82194
|
pendingRuntimeSessions.delete(sessionId);
|
|
81213
|
-
observability.
|
|
82195
|
+
const operation = observability.getDurableOperation(sessionId);
|
|
82196
|
+
const providerSession = operation?.providerSession ?? readProviderSessionCapture(sessionId, { capturesDir: durablePaths.capturesDir });
|
|
82197
|
+
if (providerSession) {
|
|
82198
|
+
observability.updateTerminalSessionProviderSession(sessionId, providerSession);
|
|
82199
|
+
const dormant = observability.transitionTerminalSessionToDormant(sessionId, providerSession);
|
|
82200
|
+
if (dormant) observability.notifySessionUpdated(dormant);
|
|
82201
|
+
} else {
|
|
82202
|
+
observability.removeTerminalSession(sessionId);
|
|
82203
|
+
}
|
|
82204
|
+
persistDurableState();
|
|
81214
82205
|
}
|
|
81215
82206
|
});
|
|
81216
82207
|
const unsubscribeCarrierReminderRouter = createCarrierResultReminderRouter2({
|
|
@@ -81242,6 +82233,12 @@ function createConsoleServer(deps = {}) {
|
|
|
81242
82233
|
let activeEndpoint = null;
|
|
81243
82234
|
let agentRuntimeStopped = false;
|
|
81244
82235
|
let consoleResourcesDisposed = false;
|
|
82236
|
+
const carrierSettingsRouter = createCarrierSettingsRouter({
|
|
82237
|
+
registry: carrierRegistry,
|
|
82238
|
+
isAuthorized: isTerminalAuthorized,
|
|
82239
|
+
readJsonBody,
|
|
82240
|
+
writeJson
|
|
82241
|
+
});
|
|
81245
82242
|
function handleRequest(req, res) {
|
|
81246
82243
|
const pathname = getPathname(req);
|
|
81247
82244
|
if (pathname === "/console/codex" || pathname.startsWith("/console/codex/")) {
|
|
@@ -81261,14 +82258,28 @@ function createConsoleServer(deps = {}) {
|
|
|
81261
82258
|
runAsyncHandler(handleTerminalTicket(req, res), res);
|
|
81262
82259
|
return;
|
|
81263
82260
|
}
|
|
81264
|
-
if (pathname === "/terminal/folders/
|
|
81265
|
-
runAsyncHandler(
|
|
82261
|
+
if (pathname === "/terminal/folders/list") {
|
|
82262
|
+
runAsyncHandler(handleTerminalFoldersList(req, res), res);
|
|
82263
|
+
return;
|
|
82264
|
+
}
|
|
82265
|
+
if (pathname === "/terminal/folders/grants") {
|
|
82266
|
+
runAsyncHandler(handleTerminalFolderGrants(req, res), res);
|
|
81266
82267
|
return;
|
|
81267
82268
|
}
|
|
81268
82269
|
if (pathname === "/terminal/sessions") {
|
|
81269
82270
|
runAsyncHandler(handleTerminalSessions(req, res), res);
|
|
81270
82271
|
return;
|
|
81271
82272
|
}
|
|
82273
|
+
const terminalSessionResumeMatch = pathname.match(/^\/terminal\/sessions\/([^/]+)\/resume$/);
|
|
82274
|
+
if (terminalSessionResumeMatch) {
|
|
82275
|
+
runAsyncHandler(handleTerminalSessionResume(req, res, decodeURIComponent(terminalSessionResumeMatch[1] ?? "")), res);
|
|
82276
|
+
return;
|
|
82277
|
+
}
|
|
82278
|
+
const terminalSessionTurnMatch = pathname.match(/^\/terminal\/sessions\/([^/]+)\/turn$/);
|
|
82279
|
+
if (terminalSessionTurnMatch) {
|
|
82280
|
+
runAsyncHandler(handleTerminalSessionTurn(req, res, decodeURIComponent(terminalSessionTurnMatch[1] ?? "")), res);
|
|
82281
|
+
return;
|
|
82282
|
+
}
|
|
81272
82283
|
const terminalSessionItemMatch = pathname.match(/^\/terminal\/sessions\/([^/]+)$/);
|
|
81273
82284
|
if (terminalSessionItemMatch) {
|
|
81274
82285
|
runAsyncHandler(handleTerminalSessionItem(req, res, decodeURIComponent(terminalSessionItemMatch[1] ?? "")), res);
|
|
@@ -81278,6 +82289,11 @@ function createConsoleServer(deps = {}) {
|
|
|
81278
82289
|
runAsyncHandler(handleObserverTheaters(req, res), res);
|
|
81279
82290
|
return;
|
|
81280
82291
|
}
|
|
82292
|
+
const theaterItemMatch = pathname.match(/^\/observer\/theaters\/([^/]+)$/);
|
|
82293
|
+
if (theaterItemMatch) {
|
|
82294
|
+
runAsyncHandler(handleObserverTheaterItem(req, res, decodeURIComponent(theaterItemMatch[1] ?? "")), res);
|
|
82295
|
+
return;
|
|
82296
|
+
}
|
|
81281
82297
|
const theaterSessionMatch = pathname.match(/^\/observer\/theaters\/([^/]+)\/sessions$/);
|
|
81282
82298
|
if (theaterSessionMatch) {
|
|
81283
82299
|
runAsyncHandler(handleObserverTheaterSessions(req, res, decodeURIComponent(theaterSessionMatch[1] ?? "")), res);
|
|
@@ -81291,6 +82307,10 @@ function createConsoleServer(deps = {}) {
|
|
|
81291
82307
|
handleObserverCarriers(req, res);
|
|
81292
82308
|
return;
|
|
81293
82309
|
}
|
|
82310
|
+
if (pathname === "/carrier-settings" || pathname.startsWith("/carrier-settings/")) {
|
|
82311
|
+
runAsyncBooleanHandler(carrierSettingsRouter({ req, res, pathname }), res);
|
|
82312
|
+
return;
|
|
82313
|
+
}
|
|
81294
82314
|
if (pathname === "/observer/tenants") {
|
|
81295
82315
|
handleObserverWorkspaces(req, res);
|
|
81296
82316
|
return;
|
|
@@ -81326,6 +82346,30 @@ function createConsoleServer(deps = {}) {
|
|
|
81326
82346
|
};
|
|
81327
82347
|
writeJson(res, 200, body);
|
|
81328
82348
|
}
|
|
82349
|
+
async function handleTerminalSessionTurn(req, res, sessionId) {
|
|
82350
|
+
if (req.method !== "POST") {
|
|
82351
|
+
writeJson(res, 405, { error: "Method not allowed" });
|
|
82352
|
+
return;
|
|
82353
|
+
}
|
|
82354
|
+
const token = lockHandle?.payload.token;
|
|
82355
|
+
if (!token || req.headers.authorization !== `Bearer ${token}`) {
|
|
82356
|
+
writeJson(res, 401, { error: "Unauthorized" });
|
|
82357
|
+
return;
|
|
82358
|
+
}
|
|
82359
|
+
const body = await readJsonBody(req);
|
|
82360
|
+
const turnState = body?.phase === "start" ? "running" : body?.phase === "end" ? "ended" : null;
|
|
82361
|
+
if (turnState === null) {
|
|
82362
|
+
writeJson(res, 400, { error: "invalid_phase" });
|
|
82363
|
+
return;
|
|
82364
|
+
}
|
|
82365
|
+
const updated = observability.setTerminalSessionTurnState(sessionId, turnState);
|
|
82366
|
+
if (!updated) {
|
|
82367
|
+
writeJson(res, 404, { error: "terminal_session_not_found" });
|
|
82368
|
+
return;
|
|
82369
|
+
}
|
|
82370
|
+
observability.notifySessionUpdated(updated);
|
|
82371
|
+
writeJson(res, 200, { ok: true });
|
|
82372
|
+
}
|
|
81329
82373
|
async function handleTerminalTicket(req, res) {
|
|
81330
82374
|
if (req.method !== "POST") {
|
|
81331
82375
|
writeJson(res, 405, { error: "Method not allowed" });
|
|
@@ -81338,16 +82382,29 @@ function createConsoleServer(deps = {}) {
|
|
|
81338
82382
|
const body = await readJsonBody(req);
|
|
81339
82383
|
const kind = body?.kind === "shell" ? "shell" : "fleet";
|
|
81340
82384
|
const requestedSessionId = body?.sessionId;
|
|
82385
|
+
const requestedTheaterId = typeof body?.theaterId === "string" ? body.theaterId : void 0;
|
|
81341
82386
|
let sessionId;
|
|
82387
|
+
let cwd;
|
|
81342
82388
|
if (kind === "shell") {
|
|
81343
|
-
|
|
82389
|
+
if (typeof requestedSessionId === "string" && requestedSessionId.startsWith(THEATER_SHELL_SESSION_PREFIX2) && requestedTheaterId) {
|
|
82390
|
+
const theater = theaters.get(requestedTheaterId);
|
|
82391
|
+
if (!theater) {
|
|
82392
|
+
writeJson(res, 404, { error: "theater_not_found" });
|
|
82393
|
+
return;
|
|
82394
|
+
}
|
|
82395
|
+
sessionId = requestedSessionId;
|
|
82396
|
+
cwd = theater.path;
|
|
82397
|
+
} else {
|
|
82398
|
+
sessionId = SHELL_TERMINAL_SESSION_ID;
|
|
82399
|
+
cwd = "";
|
|
82400
|
+
}
|
|
81344
82401
|
} else if (typeof requestedSessionId === "string" && requestedSessionId.length > 0) {
|
|
81345
82402
|
sessionId = requestedSessionId;
|
|
82403
|
+
cwd = observability.getLaunchCwd(sessionId);
|
|
81346
82404
|
} else {
|
|
81347
82405
|
writeJson(res, 400, { error: "terminal_session_not_found" });
|
|
81348
82406
|
return;
|
|
81349
82407
|
}
|
|
81350
|
-
const cwd = kind === "shell" ? "" : observability.getLaunchCwd(sessionId);
|
|
81351
82408
|
if (cwd === null) {
|
|
81352
82409
|
writeJson(res, 404, { error: "terminal_session_not_found" });
|
|
81353
82410
|
return;
|
|
@@ -81362,7 +82419,7 @@ function createConsoleServer(deps = {}) {
|
|
|
81362
82419
|
kind
|
|
81363
82420
|
}));
|
|
81364
82421
|
}
|
|
81365
|
-
async function
|
|
82422
|
+
async function handleTerminalFoldersList(req, res) {
|
|
81366
82423
|
if (req.method !== "POST") {
|
|
81367
82424
|
writeJson(res, 405, { error: "Method not allowed" });
|
|
81368
82425
|
return;
|
|
@@ -81371,16 +82428,41 @@ function createConsoleServer(deps = {}) {
|
|
|
81371
82428
|
writeJson(res, 401, { error: "unauthorized" });
|
|
81372
82429
|
return;
|
|
81373
82430
|
}
|
|
81374
|
-
const
|
|
81375
|
-
if (
|
|
81376
|
-
writeJson(res,
|
|
82431
|
+
const body = await readJsonBody(req);
|
|
82432
|
+
if (!isPlainObject22(body) || body.path !== void 0 && body.path !== null && typeof body.path !== "string") {
|
|
82433
|
+
writeJson(res, 400, { error: "invalid_path" });
|
|
81377
82434
|
return;
|
|
81378
82435
|
}
|
|
81379
|
-
|
|
81380
|
-
|
|
82436
|
+
try {
|
|
82437
|
+
const payload = await listTerminalFolders(body.path === void 0 ? null : body.path);
|
|
82438
|
+
writeJson(res, 200, payload);
|
|
82439
|
+
} catch (error512) {
|
|
82440
|
+
if (error512 instanceof TerminalFolderListError) {
|
|
82441
|
+
writeJson(res, terminalFolderListStatus(error512), { error: error512.code });
|
|
82442
|
+
return;
|
|
82443
|
+
}
|
|
82444
|
+
throw error512;
|
|
82445
|
+
}
|
|
82446
|
+
}
|
|
82447
|
+
async function handleTerminalFolderGrants(req, res) {
|
|
82448
|
+
if (req.method !== "POST") {
|
|
82449
|
+
writeJson(res, 405, { error: "Method not allowed" });
|
|
81381
82450
|
return;
|
|
81382
82451
|
}
|
|
81383
|
-
|
|
82452
|
+
if (!isTerminalAuthorized(req)) {
|
|
82453
|
+
writeJson(res, 401, { error: "unauthorized" });
|
|
82454
|
+
return;
|
|
82455
|
+
}
|
|
82456
|
+
const body = await readJsonBody(req);
|
|
82457
|
+
if (!isPlainObject22(body) || typeof body.path !== "string") {
|
|
82458
|
+
writeJson(res, 400, { error: "invalid_folder" });
|
|
82459
|
+
return;
|
|
82460
|
+
}
|
|
82461
|
+
try {
|
|
82462
|
+
writeJson(res, 200, { folderGrantId: folderGrants.issue(body.path) });
|
|
82463
|
+
} catch {
|
|
82464
|
+
writeJson(res, 400, { error: "invalid_folder" });
|
|
82465
|
+
}
|
|
81384
82466
|
}
|
|
81385
82467
|
async function handleTerminalSessions(req, res) {
|
|
81386
82468
|
if (!isTerminalAuthorized(req)) {
|
|
@@ -81409,6 +82491,17 @@ function createConsoleServer(deps = {}) {
|
|
|
81409
82491
|
}
|
|
81410
82492
|
await createTerminalSessionForCwd(cwd, res, cliId);
|
|
81411
82493
|
}
|
|
82494
|
+
function injectRenameCommand(sessionId, label) {
|
|
82495
|
+
if (!label) return;
|
|
82496
|
+
const renameCommand = terminalSessions.getSessionRenameCommand(sessionId);
|
|
82497
|
+
if (!renameCommand) return;
|
|
82498
|
+
const safeLabel = sanitizeCarrierResultReminder2(label.replace(/[\r\n\t]+/g, " ")).trim();
|
|
82499
|
+
if (safeLabel.length === 0) return;
|
|
82500
|
+
const policy = terminalSessions.getSessionMessagePolicy(sessionId) ?? {};
|
|
82501
|
+
for (const chunk of formatCarrierResultReminderMessage2(policy, `${renameCommand} ${safeLabel}`)) {
|
|
82502
|
+
terminalSessions.writeToSession(sessionId, chunk);
|
|
82503
|
+
}
|
|
82504
|
+
}
|
|
81412
82505
|
async function handleTerminalSessionItem(req, res, sessionId) {
|
|
81413
82506
|
if (req.method !== "DELETE" && req.method !== "PATCH") {
|
|
81414
82507
|
writeJson(res, 405, { error: "Method not allowed" });
|
|
@@ -81430,13 +82523,62 @@ function createConsoleServer(deps = {}) {
|
|
|
81430
82523
|
return;
|
|
81431
82524
|
}
|
|
81432
82525
|
observability.notifySessionUpdated(updated);
|
|
82526
|
+
injectRenameCommand(sessionId, updated.label);
|
|
82527
|
+
persistDurableState();
|
|
81433
82528
|
writeJson(res, 200, updated);
|
|
81434
82529
|
return;
|
|
81435
82530
|
}
|
|
81436
|
-
|
|
81437
|
-
observability.removeTerminalSession(sessionId);
|
|
82531
|
+
forgetTerminalSession(sessionId);
|
|
81438
82532
|
writeJson(res, 200, { ok: true });
|
|
81439
82533
|
}
|
|
82534
|
+
async function handleTerminalSessionResume(req, res, sessionId) {
|
|
82535
|
+
if (req.method !== "POST") {
|
|
82536
|
+
writeJson(res, 405, { error: "Method not allowed" });
|
|
82537
|
+
return;
|
|
82538
|
+
}
|
|
82539
|
+
if (!isTerminalAuthorized(req)) {
|
|
82540
|
+
writeJson(res, 401, { error: "unauthorized" });
|
|
82541
|
+
return;
|
|
82542
|
+
}
|
|
82543
|
+
const dormantSession = observability.listTerminalSessions().find((session) => session.sessionId === sessionId && session.status === "dormant");
|
|
82544
|
+
const operation = dormantSession ? observability.getDurableOperation(sessionId) : null;
|
|
82545
|
+
if (!operation) {
|
|
82546
|
+
writeJson(res, 404, { error: "session_not_found" });
|
|
82547
|
+
return;
|
|
82548
|
+
}
|
|
82549
|
+
const cliId = readDurableAgentCliId(operation);
|
|
82550
|
+
if (!cliId) {
|
|
82551
|
+
writeJson(res, 409, { error: "resume_unavailable" });
|
|
82552
|
+
return;
|
|
82553
|
+
}
|
|
82554
|
+
const providerSession = operation.providerSession ?? readProviderSessionCapture(sessionId, { capturesDir: durablePaths.capturesDir });
|
|
82555
|
+
if (!providerSession) {
|
|
82556
|
+
writeJson(res, 409, { error: "resume_unavailable" });
|
|
82557
|
+
return;
|
|
82558
|
+
}
|
|
82559
|
+
observability.updateTerminalSessionProviderSession(sessionId, providerSession);
|
|
82560
|
+
const starting = observability.updateTerminalSessionStatus(sessionId, "starting");
|
|
82561
|
+
if (starting) observability.notifySessionUpdated(starting);
|
|
82562
|
+
try {
|
|
82563
|
+
await terminalSessions.createSession({ sessionId, cwd: operation.cwd, cliId, resumeSessionId: providerSession.sessionId });
|
|
82564
|
+
const runtimeSession = pendingRuntimeSessions.get(sessionId);
|
|
82565
|
+
pendingRuntimeSessions.delete(sessionId);
|
|
82566
|
+
const resumed = runtimeSession ? observability.registerTerminalRuntimeSession(runtimeSession) ?? starting : observability.updateTerminalSessionStatus(sessionId, "terminal-only") ?? starting;
|
|
82567
|
+
if (!resumed) {
|
|
82568
|
+
writeJson(res, 404, { error: "session_not_found" });
|
|
82569
|
+
return;
|
|
82570
|
+
}
|
|
82571
|
+
observability.notifySessionUpdated(resumed);
|
|
82572
|
+
persistDurableState();
|
|
82573
|
+
writeJson(res, 200, resumed);
|
|
82574
|
+
} catch {
|
|
82575
|
+
pendingRuntimeSessions.delete(sessionId);
|
|
82576
|
+
const reverted = observability.updateTerminalSessionStatus(sessionId, "dormant");
|
|
82577
|
+
if (reverted) observability.notifySessionUpdated(reverted);
|
|
82578
|
+
persistDurableState();
|
|
82579
|
+
writeJson(res, 503, { error: "terminal_unavailable" });
|
|
82580
|
+
}
|
|
82581
|
+
}
|
|
81440
82582
|
async function handleObserverTheaters(req, res) {
|
|
81441
82583
|
if (req.method === "GET") {
|
|
81442
82584
|
writeJson(res, 200, { theaters: listTheaterInfos(), agentClis: getAgentCliMetadata2() });
|
|
@@ -81450,27 +82592,44 @@ function createConsoleServer(deps = {}) {
|
|
|
81450
82592
|
writeJson(res, 401, { error: "unauthorized" });
|
|
81451
82593
|
return;
|
|
81452
82594
|
}
|
|
81453
|
-
const
|
|
81454
|
-
if (
|
|
81455
|
-
writeJson(res,
|
|
82595
|
+
const body = await readJsonBody(req);
|
|
82596
|
+
if (!isPlainObject22(body) || typeof body.folderGrantId !== "string") {
|
|
82597
|
+
writeJson(res, 400, { error: "invalid_folder_grant" });
|
|
81456
82598
|
return;
|
|
81457
82599
|
}
|
|
81458
|
-
|
|
81459
|
-
|
|
82600
|
+
const cwd = folderGrants.consume(body.folderGrantId);
|
|
82601
|
+
if (!cwd) {
|
|
82602
|
+
writeJson(res, 400, { error: "invalid_folder_grant" });
|
|
81460
82603
|
return;
|
|
81461
82604
|
}
|
|
81462
|
-
const theater = await theaters.register(
|
|
82605
|
+
const theater = await theaters.register(cwd);
|
|
81463
82606
|
let hasWiki = false;
|
|
81464
82607
|
try {
|
|
81465
|
-
await codex.registerWorkspace(
|
|
82608
|
+
await codex.registerWorkspace(cwd);
|
|
81466
82609
|
hasWiki = true;
|
|
81467
82610
|
} catch (error512) {
|
|
81468
82611
|
if (!(error512 instanceof Error && error512.message === "knowledge_root_missing")) {
|
|
81469
82612
|
console.warn(`[fleet-console] Codex workspace registration skipped for Theater ${theater.id}: ${error512 instanceof Error ? error512.message : String(error512)}`);
|
|
81470
82613
|
}
|
|
81471
82614
|
}
|
|
82615
|
+
persistDurableState();
|
|
81472
82616
|
writeJson(res, 200, toTheaterInfo(theater, hasWiki));
|
|
81473
82617
|
}
|
|
82618
|
+
async function handleObserverTheaterItem(req, res, theaterId) {
|
|
82619
|
+
if (req.method !== "DELETE") {
|
|
82620
|
+
writeJson(res, 405, { error: "Method not allowed" });
|
|
82621
|
+
return;
|
|
82622
|
+
}
|
|
82623
|
+
if (!isTerminalAuthorized(req)) {
|
|
82624
|
+
writeJson(res, 401, { error: "unauthorized" });
|
|
82625
|
+
return;
|
|
82626
|
+
}
|
|
82627
|
+
const operations = observability.listDurableOperations().filter((operation) => operation.theaterId === theaterId);
|
|
82628
|
+
theaters.remove(theaterId);
|
|
82629
|
+
for (const operation of operations) forgetTerminalSession(operation.sessionId, { persist: false });
|
|
82630
|
+
persistDurableState();
|
|
82631
|
+
writeJson(res, 200, { ok: true });
|
|
82632
|
+
}
|
|
81474
82633
|
async function handleObserverTheaterSessions(req, res, theaterId) {
|
|
81475
82634
|
if (req.method !== "POST") {
|
|
81476
82635
|
writeJson(res, 405, { error: "Method not allowed" });
|
|
@@ -81491,7 +82650,7 @@ function createConsoleServer(deps = {}) {
|
|
|
81491
82650
|
await createTerminalSessionForCwd(theater.path, res, cliId);
|
|
81492
82651
|
}
|
|
81493
82652
|
async function createTerminalSessionForCwd(cwd, res, cliId) {
|
|
81494
|
-
const sessionId =
|
|
82653
|
+
const sessionId = crypto5.randomUUID();
|
|
81495
82654
|
const session = observability.createPendingTerminalSession({ sessionId, cwd, cliId });
|
|
81496
82655
|
try {
|
|
81497
82656
|
await terminalSessions.createSession({ sessionId, cwd, cliId });
|
|
@@ -81499,6 +82658,7 @@ function createConsoleServer(deps = {}) {
|
|
|
81499
82658
|
pendingRuntimeSessions.delete(sessionId);
|
|
81500
82659
|
const created = runtimeSession ? observability.registerTerminalRuntimeSession(runtimeSession) ?? session : observability.updateTerminalSessionStatus(sessionId, "terminal-only") ?? session;
|
|
81501
82660
|
observability.notifySessionUpdated(created);
|
|
82661
|
+
persistDurableState();
|
|
81502
82662
|
writeJson(res, 200, created);
|
|
81503
82663
|
} catch (error512) {
|
|
81504
82664
|
pendingRuntimeSessions.delete(sessionId);
|
|
@@ -81572,6 +82732,13 @@ function createConsoleServer(deps = {}) {
|
|
|
81572
82732
|
function listTheaterInfos() {
|
|
81573
82733
|
return theaters.list().map((theater) => toTheaterInfo(theater, codex.getWorkspace(theater.id) !== null));
|
|
81574
82734
|
}
|
|
82735
|
+
function forgetTerminalSession(sessionId, options2 = {}) {
|
|
82736
|
+
terminalSessions.terminate(sessionId);
|
|
82737
|
+
pendingRuntimeSessions.delete(sessionId);
|
|
82738
|
+
observability.removeTerminalSession(sessionId);
|
|
82739
|
+
unlinkProviderSessionCapture(sessionId, { capturesDir: durablePaths.capturesDir });
|
|
82740
|
+
if (options2.persist !== false) persistDurableState();
|
|
82741
|
+
}
|
|
81575
82742
|
function toTheaterInfo(theater, hasWiki) {
|
|
81576
82743
|
return {
|
|
81577
82744
|
id: theater.id,
|
|
@@ -81634,12 +82801,69 @@ function createConsoleServer(deps = {}) {
|
|
|
81634
82801
|
terminalUpgrade.close();
|
|
81635
82802
|
currentLock?.release();
|
|
81636
82803
|
}
|
|
82804
|
+
function rehydrateDurableState() {
|
|
82805
|
+
let state;
|
|
82806
|
+
try {
|
|
82807
|
+
state = durableStateStore.load();
|
|
82808
|
+
theaters.restore(state.theaters);
|
|
82809
|
+
} catch (error512) {
|
|
82810
|
+
console.warn(`[fleet-console] Durable state restore skipped: ${error512 instanceof Error ? error512.message : String(error512)}`);
|
|
82811
|
+
state = emptyDurableConsoleState();
|
|
82812
|
+
theaters.restore([]);
|
|
82813
|
+
}
|
|
82814
|
+
const merged = mergeProviderSessionCaptures(state, { capturesDir: durablePaths.capturesDir });
|
|
82815
|
+
syncProviderSessionsToObservability(merged);
|
|
82816
|
+
const restorable = {
|
|
82817
|
+
...merged,
|
|
82818
|
+
operations: merged.operations.filter((operation) => operation.providerSession)
|
|
82819
|
+
};
|
|
82820
|
+
if (merged !== state || restorable.operations.length !== merged.operations.length) {
|
|
82821
|
+
try {
|
|
82822
|
+
durableStateStore.save(restorable);
|
|
82823
|
+
cleanupProviderSessionCaptures(restorable, { capturesDir: durablePaths.capturesDir });
|
|
82824
|
+
} catch (error512) {
|
|
82825
|
+
console.warn(`[fleet-console] Durable state capture merge was not persisted: ${error512 instanceof Error ? error512.message : String(error512)}`);
|
|
82826
|
+
}
|
|
82827
|
+
} else {
|
|
82828
|
+
cleanupProviderSessionCaptures(restorable, { capturesDir: durablePaths.capturesDir });
|
|
82829
|
+
}
|
|
82830
|
+
for (const operation of restorable.operations) {
|
|
82831
|
+
if (theaters.get(operation.theaterId)) observability.injectDormantOperation(operation);
|
|
82832
|
+
}
|
|
82833
|
+
}
|
|
82834
|
+
function persistDurableState() {
|
|
82835
|
+
try {
|
|
82836
|
+
const state = mergeProviderSessionCaptures({
|
|
82837
|
+
version: 1,
|
|
82838
|
+
theaters: theaters.list(),
|
|
82839
|
+
operations: observability.listDurableOperations()
|
|
82840
|
+
}, { capturesDir: durablePaths.capturesDir });
|
|
82841
|
+
syncProviderSessionsToObservability(state);
|
|
82842
|
+
const operationsWithProviderSession = state.operations.filter((operation) => operation.providerSession);
|
|
82843
|
+
durableStateStore.save({
|
|
82844
|
+
version: state.version,
|
|
82845
|
+
theaters: state.theaters,
|
|
82846
|
+
// 대화 없는 빈 Operation 드롭은 rehydrate에서 capture 머지 뒤에만 수행한다.
|
|
82847
|
+
// create 시점의 메타데이터를 먼저 남겨야 이후 도착한 capture 파일이 재시작 때 병합될 수 있다.
|
|
82848
|
+
operations: state.operations
|
|
82849
|
+
});
|
|
82850
|
+
cleanupProviderSessionCaptures({ ...state, operations: operationsWithProviderSession }, { capturesDir: durablePaths.capturesDir });
|
|
82851
|
+
} catch (error512) {
|
|
82852
|
+
console.warn(`[fleet-console] Durable state save failed: ${error512 instanceof Error ? error512.message : String(error512)}`);
|
|
82853
|
+
}
|
|
82854
|
+
}
|
|
82855
|
+
function syncProviderSessionsToObservability(state) {
|
|
82856
|
+
for (const operation of state.operations) {
|
|
82857
|
+
if (operation.providerSession) observability.updateTerminalSessionProviderSession(operation.sessionId, operation.providerSession);
|
|
82858
|
+
}
|
|
82859
|
+
}
|
|
81637
82860
|
return {
|
|
81638
82861
|
host,
|
|
81639
82862
|
port,
|
|
81640
82863
|
async start(lockPaths) {
|
|
81641
82864
|
if (server && lockHandle) return lockHandle.payload.endpoint;
|
|
81642
82865
|
try {
|
|
82866
|
+
rehydrateDurableState();
|
|
81643
82867
|
await new Promise((resolve2, reject) => {
|
|
81644
82868
|
const srv = createHttpServer(handleRequest, terminalUpgrade);
|
|
81645
82869
|
srv.once("error", reject);
|
|
@@ -81722,6 +82946,14 @@ function resolveCarrierEventOrigin(event, jobOriginById) {
|
|
|
81722
82946
|
function queueOriginCleanup(jobId, jobOriginById) {
|
|
81723
82947
|
queueMicrotask(() => jobOriginById.delete(jobId));
|
|
81724
82948
|
}
|
|
82949
|
+
function readDurableAgentCliId(operation) {
|
|
82950
|
+
if (!operation.cliId) return null;
|
|
82951
|
+
try {
|
|
82952
|
+
return parseAgentCliId2(operation.cliId) ?? null;
|
|
82953
|
+
} catch {
|
|
82954
|
+
return null;
|
|
82955
|
+
}
|
|
82956
|
+
}
|
|
81725
82957
|
function createHttpServer(handler, terminalUpgrade) {
|
|
81726
82958
|
const srv = http2.createServer(handler);
|
|
81727
82959
|
srv.timeout = SERVER_TIMEOUT_MS;
|
|
@@ -81781,6 +83013,14 @@ function readOptionalAgentCliId(value, res) {
|
|
|
81781
83013
|
return false;
|
|
81782
83014
|
}
|
|
81783
83015
|
}
|
|
83016
|
+
function terminalFolderListStatus(error512) {
|
|
83017
|
+
if (error512.code === "forbidden") return 403;
|
|
83018
|
+
if (error512.code === "not_found") return 404;
|
|
83019
|
+
return 400;
|
|
83020
|
+
}
|
|
83021
|
+
function isPlainObject22(value) {
|
|
83022
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
83023
|
+
}
|
|
81784
83024
|
async function readJsonBody(req) {
|
|
81785
83025
|
const chunks = [];
|
|
81786
83026
|
let total = 0;
|
|
@@ -81839,6 +83079,78 @@ function isAllowedTerminalOrigin(req, expectedPort) {
|
|
|
81839
83079
|
if (origin === void 0) return true;
|
|
81840
83080
|
return origin === `http://127.0.0.1:${expectedPort}`;
|
|
81841
83081
|
}
|
|
83082
|
+
var CAPTURE_TEMP_PREFIX = ".capture.";
|
|
83083
|
+
async function runCaptureSessionHook(provider, env = process6.env) {
|
|
83084
|
+
return captureSession({
|
|
83085
|
+
diagnostics: process6.stderr,
|
|
83086
|
+
env,
|
|
83087
|
+
input: await readStdin(),
|
|
83088
|
+
provider
|
|
83089
|
+
});
|
|
83090
|
+
}
|
|
83091
|
+
function captureSession(options2) {
|
|
83092
|
+
try {
|
|
83093
|
+
return captureSessionStrict(options2);
|
|
83094
|
+
} catch (error512) {
|
|
83095
|
+
options2.diagnostics?.write(`[fleet-console] capture-session skipped: ${error512 instanceof Error ? error512.message : String(error512)}
|
|
83096
|
+
`);
|
|
83097
|
+
return null;
|
|
83098
|
+
}
|
|
83099
|
+
}
|
|
83100
|
+
function captureSessionStrict(options2) {
|
|
83101
|
+
const provider = parseProvider(options2.provider);
|
|
83102
|
+
const fleetSessionId = readFleetSessionId(options2.env ?? process6.env);
|
|
83103
|
+
const input = parseHookInput(options2.input ?? "");
|
|
83104
|
+
const providerSession = toProviderSession(provider, input, options2.now ?? (() => /* @__PURE__ */ new Date()));
|
|
83105
|
+
const capturesDir = (options2.paths ?? createConsoleDataPaths()).capturesDir;
|
|
83106
|
+
const finalPath = path93__default.join(capturesDir, `${fleetSessionId}.json`);
|
|
83107
|
+
const tempPath = path93__default.join(capturesDir, `${CAPTURE_TEMP_PREFIX}${fleetSessionId}.${process6.pid}.${Date.now()}.tmp`);
|
|
83108
|
+
fs5__default.mkdirSync(capturesDir, { recursive: true, mode: 448 });
|
|
83109
|
+
fs5__default.writeFileSync(tempPath, `${JSON.stringify(providerSession, null, 2)}
|
|
83110
|
+
`, { mode: 384 });
|
|
83111
|
+
fs5__default.renameSync(tempPath, finalPath);
|
|
83112
|
+
return { path: finalPath, providerSession };
|
|
83113
|
+
}
|
|
83114
|
+
function parseProvider(value) {
|
|
83115
|
+
if (value === "claude" || value === "codex") return value;
|
|
83116
|
+
throw new Error("invalid_provider");
|
|
83117
|
+
}
|
|
83118
|
+
function readFleetSessionId(env) {
|
|
83119
|
+
const value = env.FLEET_CONSOLE_SESSION_ID;
|
|
83120
|
+
if (!value) throw new Error("missing_fleet_session_id");
|
|
83121
|
+
if (path93__default.basename(value) !== value || value.includes(path93__default.sep) || value.includes(path93__default.posix.sep)) {
|
|
83122
|
+
throw new Error("invalid_fleet_session_id");
|
|
83123
|
+
}
|
|
83124
|
+
return value;
|
|
83125
|
+
}
|
|
83126
|
+
function parseHookInput(input) {
|
|
83127
|
+
try {
|
|
83128
|
+
const parsed = JSON.parse(input);
|
|
83129
|
+
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) return parsed;
|
|
83130
|
+
} catch {
|
|
83131
|
+
}
|
|
83132
|
+
throw new Error("invalid_hook_input");
|
|
83133
|
+
}
|
|
83134
|
+
function toProviderSession(provider, input, now) {
|
|
83135
|
+
if (typeof input.session_id !== "string" || input.session_id.length === 0) throw new Error("missing_provider_session_id");
|
|
83136
|
+
return {
|
|
83137
|
+
provider,
|
|
83138
|
+
sessionId: input.session_id,
|
|
83139
|
+
...typeof input.transcript_path === "string" && input.transcript_path.length > 0 ? { transcriptPath: input.transcript_path } : {},
|
|
83140
|
+
...typeof input.source === "string" && input.source.length > 0 ? { source: input.source } : {},
|
|
83141
|
+
capturedAt: now().toISOString()
|
|
83142
|
+
};
|
|
83143
|
+
}
|
|
83144
|
+
function readStdin() {
|
|
83145
|
+
return new Promise((resolve2, reject) => {
|
|
83146
|
+
const chunks = [];
|
|
83147
|
+
process6.stdin.on("data", (chunk) => {
|
|
83148
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
83149
|
+
});
|
|
83150
|
+
process6.stdin.on("error", reject);
|
|
83151
|
+
process6.stdin.on("end", () => resolve2(Buffer.concat(chunks).toString("utf8")));
|
|
83152
|
+
});
|
|
83153
|
+
}
|
|
81842
83154
|
function createConsoleStalePolicy(deps = {}) {
|
|
81843
83155
|
const fsImpl = deps.fs ?? fs5__default;
|
|
81844
83156
|
function isBuildStale(lock, buildFile) {
|
|
@@ -81851,10 +83163,40 @@ function createConsoleStalePolicy(deps = {}) {
|
|
|
81851
83163
|
}
|
|
81852
83164
|
return { isBuildStale };
|
|
81853
83165
|
}
|
|
83166
|
+
var TURN_POST_TIMEOUT_MS = 1500;
|
|
83167
|
+
async function runTurnStateHook(phase, env = process6.env, options2 = {}) {
|
|
83168
|
+
try {
|
|
83169
|
+
await postTurnState(phase, env, options2);
|
|
83170
|
+
} catch {
|
|
83171
|
+
}
|
|
83172
|
+
}
|
|
83173
|
+
async function postTurnState(phase, env, options2) {
|
|
83174
|
+
const sessionId = env.FLEET_CONSOLE_SESSION_ID;
|
|
83175
|
+
if (!sessionId) return;
|
|
83176
|
+
const paths = createConsolePaths({ env });
|
|
83177
|
+
const lock = createConsoleLock().readLock(paths.lockFile);
|
|
83178
|
+
if (!lock) return;
|
|
83179
|
+
const fetchImpl = options2.fetchImpl ?? fetch;
|
|
83180
|
+
const controller = new AbortController();
|
|
83181
|
+
const timer = setTimeout(() => controller.abort(), options2.timeoutMs ?? TURN_POST_TIMEOUT_MS);
|
|
83182
|
+
try {
|
|
83183
|
+
await fetchImpl(`${lock.endpoint}terminal/sessions/${encodeURIComponent(sessionId)}/turn`, {
|
|
83184
|
+
method: "POST",
|
|
83185
|
+
headers: {
|
|
83186
|
+
authorization: `Bearer ${lock.token}`,
|
|
83187
|
+
"content-type": "application/json"
|
|
83188
|
+
},
|
|
83189
|
+
body: JSON.stringify({ phase }),
|
|
83190
|
+
signal: controller.signal
|
|
83191
|
+
});
|
|
83192
|
+
} finally {
|
|
83193
|
+
clearTimeout(timer);
|
|
83194
|
+
}
|
|
83195
|
+
}
|
|
81854
83196
|
var FIXED_HOST = "127.0.0.1";
|
|
81855
83197
|
var HELP_BANNER_INDENT = " ";
|
|
81856
83198
|
var DEFAULT_HELP_RELEASE = "local";
|
|
81857
|
-
var CONSOLE_HOOK_COMMANDS = /* @__PURE__ */ new Set(["subagents-context"]);
|
|
83199
|
+
var CONSOLE_HOOK_COMMANDS = /* @__PURE__ */ new Set(["capture-session", "subagents-context", "turn-start", "turn-end"]);
|
|
81858
83200
|
function parseConsoleCliMode(argv2) {
|
|
81859
83201
|
if (argv2.length === 0) return "start";
|
|
81860
83202
|
const [first, ...rest] = argv2;
|
|
@@ -81881,10 +83223,14 @@ Run 'fleet console --help' for usage.`);
|
|
|
81881
83223
|
}
|
|
81882
83224
|
function parseConsoleHookCommand(argv2) {
|
|
81883
83225
|
const [commandName, ...rest] = argv2;
|
|
81884
|
-
if (!commandName || !CONSOLE_HOOK_COMMANDS.has(commandName)
|
|
83226
|
+
if (!commandName || !CONSOLE_HOOK_COMMANDS.has(commandName)) {
|
|
81885
83227
|
throw new Error("Unknown fleet-console hook command");
|
|
81886
83228
|
}
|
|
81887
|
-
return "subagents-context";
|
|
83229
|
+
if (commandName === "subagents-context" && rest.length === 0) return { command: "subagents-context" };
|
|
83230
|
+
if (commandName === "turn-start" && rest.length === 0) return { command: "turn-start" };
|
|
83231
|
+
if (commandName === "turn-end" && rest.length === 0) return { command: "turn-end" };
|
|
83232
|
+
if (commandName === "capture-session" && rest.length === 1 && rest[0]) return { command: "capture-session", provider: rest[0] };
|
|
83233
|
+
throw new Error("Unknown fleet-console hook command");
|
|
81888
83234
|
}
|
|
81889
83235
|
function buildConsoleHelpText(options2 = {}) {
|
|
81890
83236
|
const colorEnabled = resolveColorEnabled2(options2);
|
|
@@ -81946,8 +83292,8 @@ function buildWikiHelpText(options2 = {}) {
|
|
|
81946
83292
|
return colorEnabled ? text : stripAnsi2(text);
|
|
81947
83293
|
}
|
|
81948
83294
|
function createConsoleDaemonLifecycle(deps = {}) {
|
|
81949
|
-
const env = deps.env ??
|
|
81950
|
-
const execPath = deps.execPath ??
|
|
83295
|
+
const env = deps.env ?? process6.env;
|
|
83296
|
+
const execPath = deps.execPath ?? process6.execPath;
|
|
81951
83297
|
const serverModulePath = deps.serverModulePath ?? resolveDefaultServerModulePath();
|
|
81952
83298
|
const spawnDetached = deps.spawnDetached ?? ((bin, args, options2) => {
|
|
81953
83299
|
spawn3(bin, [...args], options2).unref();
|
|
@@ -81961,10 +83307,10 @@ function createConsoleDaemonLifecycle(deps = {}) {
|
|
|
81961
83307
|
const server = createConsoleServer();
|
|
81962
83308
|
await server.start(paths);
|
|
81963
83309
|
await new Promise((resolve2) => {
|
|
81964
|
-
|
|
83310
|
+
process6.once("SIGTERM", () => {
|
|
81965
83311
|
void server.stop().finally(resolve2);
|
|
81966
83312
|
});
|
|
81967
|
-
|
|
83313
|
+
process6.once("SIGINT", () => {
|
|
81968
83314
|
void server.stop().finally(resolve2);
|
|
81969
83315
|
});
|
|
81970
83316
|
});
|
|
@@ -81978,14 +83324,14 @@ function createConsoleDaemonLifecycle(deps = {}) {
|
|
|
81978
83324
|
const payload = readTrustedLock();
|
|
81979
83325
|
if (!payload) return;
|
|
81980
83326
|
try {
|
|
81981
|
-
|
|
83327
|
+
process6.kill(payload.pid, "SIGTERM");
|
|
81982
83328
|
} catch (err) {
|
|
81983
83329
|
if (err.code !== "ESRCH") throw err;
|
|
81984
83330
|
}
|
|
81985
83331
|
await sleep(200);
|
|
81986
83332
|
try {
|
|
81987
|
-
|
|
81988
|
-
|
|
83333
|
+
process6.kill(payload.pid, 0);
|
|
83334
|
+
process6.kill(payload.pid, "SIGKILL");
|
|
81989
83335
|
} catch (err) {
|
|
81990
83336
|
if (err.code !== "ESRCH") throw err;
|
|
81991
83337
|
}
|
|
@@ -82103,49 +83449,55 @@ async function runConsoleRestart(deps = {}) {
|
|
|
82103
83449
|
return openFleetConsole({ lifecycle, openBrowser: deps.openBrowser });
|
|
82104
83450
|
}
|
|
82105
83451
|
async function main() {
|
|
82106
|
-
if (
|
|
83452
|
+
if (process6.argv[2] === "serve") {
|
|
82107
83453
|
await createConsoleDaemonLifecycle().runServer();
|
|
82108
83454
|
return;
|
|
82109
83455
|
}
|
|
82110
|
-
if (
|
|
82111
|
-
parseConsoleHookCommand(
|
|
82112
|
-
{
|
|
82113
|
-
|
|
83456
|
+
if (process6.argv[2] === "hook") {
|
|
83457
|
+
const hookCommand = parseConsoleHookCommand(process6.argv.slice(3));
|
|
83458
|
+
if (hookCommand.command === "subagents-context") {
|
|
83459
|
+
process6.stdout.write(`${runSubagentsContextHook(process6.env)}
|
|
82114
83460
|
`);
|
|
82115
83461
|
return;
|
|
82116
83462
|
}
|
|
83463
|
+
if (hookCommand.command === "turn-start" || hookCommand.command === "turn-end") {
|
|
83464
|
+
await runTurnStateHook(hookCommand.command === "turn-start" ? "start" : "end", process6.env);
|
|
83465
|
+
return;
|
|
83466
|
+
}
|
|
83467
|
+
await runCaptureSessionHook(hookCommand.provider, process6.env);
|
|
83468
|
+
return;
|
|
82117
83469
|
}
|
|
82118
|
-
if (
|
|
82119
|
-
await mainWiki(
|
|
83470
|
+
if (process6.argv[2] === "codex") {
|
|
83471
|
+
await mainWiki(process6.argv.slice(3));
|
|
82120
83472
|
return;
|
|
82121
83473
|
}
|
|
82122
|
-
const mode = parseConsoleCliMode(
|
|
83474
|
+
const mode = parseConsoleCliMode(process6.argv.slice(2));
|
|
82123
83475
|
if (mode === "help") {
|
|
82124
|
-
|
|
83476
|
+
process6.stdout.write(`${buildConsoleHelpText({ env: process6.env, isTTY: process6.stdout.isTTY })}
|
|
82125
83477
|
`);
|
|
82126
83478
|
return;
|
|
82127
83479
|
}
|
|
82128
83480
|
if (mode === "status") {
|
|
82129
|
-
|
|
83481
|
+
process6.stdout.write(`${await runConsoleStatus()}
|
|
82130
83482
|
`);
|
|
82131
83483
|
return;
|
|
82132
83484
|
}
|
|
82133
83485
|
if (mode === "stop") {
|
|
82134
|
-
|
|
83486
|
+
process6.stdout.write(`${await runConsoleStop()}
|
|
82135
83487
|
`);
|
|
82136
83488
|
return;
|
|
82137
83489
|
}
|
|
82138
83490
|
if (mode === "restart") {
|
|
82139
83491
|
await runConsoleRestart();
|
|
82140
|
-
|
|
83492
|
+
process6.stdout.write("Fleet Console restarted.\n");
|
|
82141
83493
|
return;
|
|
82142
83494
|
}
|
|
82143
83495
|
await openFleetConsole();
|
|
82144
|
-
|
|
83496
|
+
process6.stdout.write("Fleet Console opened.\n");
|
|
82145
83497
|
}
|
|
82146
|
-
async function mainWiki(argv2 =
|
|
83498
|
+
async function mainWiki(argv2 = process6.argv.slice(2)) {
|
|
82147
83499
|
if (argv2.includes("--help") || argv2.includes("-h")) {
|
|
82148
|
-
|
|
83500
|
+
process6.stdout.write(`${buildWikiHelpText({ env: process6.env, isTTY: process6.stdout.isTTY })}
|
|
82149
83501
|
`);
|
|
82150
83502
|
return;
|
|
82151
83503
|
}
|
|
@@ -82157,19 +83509,19 @@ async function mainWiki(argv2 = process4.argv.slice(2)) {
|
|
|
82157
83509
|
if (unsupported.length > 0) {
|
|
82158
83510
|
throw new Error(`Unknown fleet wiki option: ${unsupported[0]}`);
|
|
82159
83511
|
}
|
|
82160
|
-
await openFleetWikiWorkspace({ cwd:
|
|
83512
|
+
await openFleetWikiWorkspace({ cwd: process6.cwd() });
|
|
82161
83513
|
}
|
|
82162
83514
|
function resolveDefaultServerModulePath() {
|
|
82163
83515
|
const builtPath = new URL("../dist/cli.mjs", import.meta.url).pathname;
|
|
82164
83516
|
if (fs5__default.existsSync(builtPath)) return builtPath;
|
|
82165
83517
|
return fileURLToPath(import.meta.url);
|
|
82166
83518
|
}
|
|
82167
|
-
var isDirectRun =
|
|
83519
|
+
var isDirectRun = process6.argv[1] && path93__default.resolve(process6.argv[1]) === fileURLToPath(import.meta.url);
|
|
82168
83520
|
if (isDirectRun) {
|
|
82169
83521
|
await main().catch((error512) => {
|
|
82170
|
-
|
|
83522
|
+
process6.stderr.write(`${error512 instanceof Error ? error512.message : String(error512)}
|
|
82171
83523
|
`);
|
|
82172
|
-
|
|
83524
|
+
process6.exitCode = 1;
|
|
82173
83525
|
});
|
|
82174
83526
|
}
|
|
82175
83527
|
|
|
@@ -82997,7 +84349,7 @@ import { join as join11 } from "path";
|
|
|
82997
84349
|
import path63 from "path";
|
|
82998
84350
|
import path12 from "path";
|
|
82999
84351
|
import path53 from "path";
|
|
83000
|
-
import
|
|
84352
|
+
import crypto6 from "crypto";
|
|
83001
84353
|
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
84354
|
import os6 from "os";
|
|
83003
84355
|
import path43 from "path";
|
|
@@ -84050,7 +85402,7 @@ function stripLeadingFrontmatter2(body) {
|
|
|
84050
85402
|
return stripped ? next : body;
|
|
84051
85403
|
}
|
|
84052
85404
|
function computeContentHash2(content) {
|
|
84053
|
-
return
|
|
85405
|
+
return crypto6.createHash("sha256").update(content, "utf8").digest("hex").slice(0, 8);
|
|
84054
85406
|
}
|
|
84055
85407
|
function assertWithinRawDir2(absolutePath, paths) {
|
|
84056
85408
|
const relative2 = path43.relative(paths.rawDir, absolutePath);
|
|
@@ -84263,7 +85615,7 @@ async function writeAtomic2(filePath, content, paths) {
|
|
|
84263
85615
|
await ensureMemoryRoot2(paths);
|
|
84264
85616
|
const tempPath = path43.join(
|
|
84265
85617
|
path43.dirname(filePath),
|
|
84266
|
-
`.tmp-${process.pid}-${Date.now()}-${
|
|
85618
|
+
`.tmp-${process.pid}-${Date.now()}-${crypto6.randomUUID()}-${os6.hostname()}`
|
|
84267
85619
|
);
|
|
84268
85620
|
await writeFile22(tempPath, content, "utf8");
|
|
84269
85621
|
await rename2(tempPath, filePath);
|
|
@@ -90389,7 +91741,7 @@ function reconcileRuntimeState(carrierRuntime) {
|
|
|
90389
91741
|
// src/runtime/workspace-scanner.ts
|
|
90390
91742
|
import { execFile as execFile3 } from "child_process";
|
|
90391
91743
|
import { promisify as promisify2 } from "util";
|
|
90392
|
-
var
|
|
91744
|
+
var execFileAsync2 = promisify2(execFile3);
|
|
90393
91745
|
var GIT_STATUS_TIMEOUT_MS2 = 4e3;
|
|
90394
91746
|
var GIT_STATUS_MAX_BUFFER2 = 1024 * 1024;
|
|
90395
91747
|
var GIT_HASH_TIMEOUT_MS2 = 4e3;
|
|
@@ -90398,11 +91750,13 @@ function createWorkspaceChangeScanner2() {
|
|
|
90398
91750
|
return {
|
|
90399
91751
|
async snapshot(cwd) {
|
|
90400
91752
|
try {
|
|
90401
|
-
const { stdout } = await
|
|
91753
|
+
const { stdout } = await execFileAsync2("git", ["status", "--porcelain=v1", "-z", "--untracked-files=all"], {
|
|
90402
91754
|
cwd,
|
|
90403
91755
|
encoding: "utf8",
|
|
90404
91756
|
maxBuffer: GIT_STATUS_MAX_BUFFER2,
|
|
90405
|
-
timeout: GIT_STATUS_TIMEOUT_MS2
|
|
91757
|
+
timeout: GIT_STATUS_TIMEOUT_MS2,
|
|
91758
|
+
// 콘솔 없는 호스트에서 git.exe 실행 시 콘솔 창이 깜빡이는 것을 방지한다(방어적).
|
|
91759
|
+
windowsHide: true
|
|
90406
91760
|
});
|
|
90407
91761
|
const entries = parseGitStatusPorcelainZ2(stdout);
|
|
90408
91762
|
if (!entries) return null;
|
|
@@ -90461,7 +91815,9 @@ function execGitHashObject2(cwd, paths) {
|
|
|
90461
91815
|
cwd,
|
|
90462
91816
|
encoding: "utf8",
|
|
90463
91817
|
maxBuffer: GIT_HASH_MAX_BUFFER2,
|
|
90464
|
-
timeout: GIT_HASH_TIMEOUT_MS2
|
|
91818
|
+
timeout: GIT_HASH_TIMEOUT_MS2,
|
|
91819
|
+
// 콘솔 없는 호스트에서 git.exe 실행 시 콘솔 창이 깜빡이는 것을 방지한다(방어적).
|
|
91820
|
+
windowsHide: true
|
|
90465
91821
|
},
|
|
90466
91822
|
(error53, stdout) => {
|
|
90467
91823
|
if (error53) {
|
|
@@ -90884,7 +92240,7 @@ async function runApp(options2 = {}) {
|
|
|
90884
92240
|
defaults: {
|
|
90885
92241
|
cliId: getDefaultAgentCliId(),
|
|
90886
92242
|
enableMetaphor: false,
|
|
90887
|
-
replaceSystemPrompt:
|
|
92243
|
+
replaceSystemPrompt: false
|
|
90888
92244
|
},
|
|
90889
92245
|
env: process.env,
|
|
90890
92246
|
globalOptionsService: runtime.infraServices.globalOptionsService,
|
|
@@ -91269,11 +92625,11 @@ function canReadCarrierState2(filePath) {
|
|
|
91269
92625
|
}
|
|
91270
92626
|
}
|
|
91271
92627
|
function isReadableCarrierStateRoot2(value) {
|
|
91272
|
-
if (!
|
|
92628
|
+
if (!isRecord5(value)) return false;
|
|
91273
92629
|
const carriers = value.carriers;
|
|
91274
|
-
return carriers === void 0 ||
|
|
92630
|
+
return carriers === void 0 || isRecord5(carriers);
|
|
91275
92631
|
}
|
|
91276
|
-
function
|
|
92632
|
+
function isRecord5(value) {
|
|
91277
92633
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
91278
92634
|
}
|
|
91279
92635
|
|
|
@@ -91314,7 +92670,7 @@ async function runNativeApp(options2 = {}) {
|
|
|
91314
92670
|
defaults: {
|
|
91315
92671
|
cliId: getDefaultAgentCliId(),
|
|
91316
92672
|
enableMetaphor: false,
|
|
91317
|
-
replaceSystemPrompt:
|
|
92673
|
+
replaceSystemPrompt: false
|
|
91318
92674
|
},
|
|
91319
92675
|
env: process.env,
|
|
91320
92676
|
globalOptionsService: runtime.infraServices.globalOptionsService,
|