@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 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-13T00:00:00Z",
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
- // exec 형식: command는 직접 spawn되는 실행 파일, args는 셸 토크나이징 없이 그대로 전달된다.
33876
- // Windows cmd/powershell의 따옴표 규칙과 무관하게 동작하며 공백 포함 경로도 안전하다.
33877
- args: [...hookExec.args],
33878
- command: hookExec.command,
33879
- type: "command"
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: "0.0.0",
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, (cleanup2) => tempCleanups.push(cleanup2)) : void 0;
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 ?? true,
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: [...profile.args, ...injectedArgs],
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 process4 from "process";
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 crypto32, { createHash as createHash2, randomUUID as randomUUID2, timingSafeEqual } from "crypto";
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, path30) {
40548
- if (!path30)
40673
+ function getElementAtPath2(obj, path35) {
40674
+ if (!path35)
40549
40675
  return obj;
40550
- return path30.reduce((acc, key) => acc?.[key], obj);
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(path30, issues) {
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(path30);
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, path30 = []) => {
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 }, [...path30, ...issue32.path]));
41237
+ issue32.errors.map((issues) => processError({ issues }, [...path35, ...issue32.path]));
41112
41238
  } else if (issue32.code === "invalid_key") {
41113
- processError({ issues: issue32.issues }, [...path30, ...issue32.path]);
41239
+ processError({ issues: issue32.issues }, [...path35, ...issue32.path]);
41114
41240
  } else if (issue32.code === "invalid_element") {
41115
- processError({ issues: issue32.issues }, [...path30, ...issue32.path]);
41241
+ processError({ issues: issue32.issues }, [...path35, ...issue32.path]);
41116
41242
  } else {
41117
- const fullpath = [...path30, ...issue32.path];
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, path30 = []) => {
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 }, [...path30, ...issue32.path]));
41274
+ issue32.errors.map((issues) => processError({ issues }, [...path35, ...issue32.path]));
41149
41275
  } else if (issue32.code === "invalid_key") {
41150
- processError({ issues: issue32.issues }, [...path30, ...issue32.path]);
41276
+ processError({ issues: issue32.issues }, [...path35, ...issue32.path]);
41151
41277
  } else if (issue32.code === "invalid_element") {
41152
- processError({ issues: issue32.issues }, [...path30, ...issue32.path]);
41278
+ processError({ issues: issue32.issues }, [...path35, ...issue32.path]);
41153
41279
  } else {
41154
- const fullpath = [...path30, ...issue32.path];
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 path30 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
41187
- for (const seg of path30) {
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 path30 = ref.slice(1).split("/").filter(Boolean);
53709
- if (path30.length === 0) {
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 (path30[0] === defsKey) {
53714
- const key = path30[1];
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-13T00:00:00Z",
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 = crypto32.randomUUID();
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 = `/${crypto32.randomUUID()}`;
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 = crypto32.randomUUID();
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 = crypto32.randomUUID();
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 mode = SECURE_FILE_MODE2;
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 ?? (() => crypto32.randomBytes(32).toString("base64url"));
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 LOCK_DIR_NAME2 = "fleet-console";
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
- const channel = deps.channel ?? readFleetConsoleRelease().channel;
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
- // exec 형식: command는 직접 spawn되는 실행 파일, args는 셸 토크나이징 없이 그대로 전달된다.
71229
- // Windows cmd/powershell의 따옴표 규칙과 무관하게 동작하며 공백 포함 경로도 안전하다.
71230
- args: [...hookExec.args],
71231
- command: hookExec.command,
71232
- type: "command"
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 = crypto32.createHash("sha256").update(path93__default.resolve(cwd, ".fleet")).digest("hex").slice(0, 12);
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 = crypto32.createHash("sha256");
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: "0.0.0",
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}:${crypto32.randomUUID()}`;
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, (cleanup2) => tempCleanups.push(cleanup2)) : void 0;
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 ?? true,
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: [...profile.args, ...injectedArgs],
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-${crypto32.randomUUID()}`;
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 crypto32.createHash("sha256").update(content, "utf8").digest("hex").slice(0, 8);
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()}-${crypto32.randomUUID()}-${os22__default.hostname()}`
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 crypto32.createHash("sha256").update(body.replace(/\s+/g, " ").trim(), "utf8").digest("hex").slice(0, 8);
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 crypto32.createHash("sha256").update(canonicalCwd).digest("hex").slice(0, 12);
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 (isJsonRequest(request)) {
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 isJsonRequest(request) {
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 ?? (() => crypto32.randomBytes(GRANT_ID_BYTES).toString("base64url"));
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 (!path93__default.isAbsolute(cwd)) throw new Error("invalid_folder");
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
- var execFileAsync = promisify(execFile2);
80329
- var DIALOG_TIMEOUT_MS = 3e4;
80330
- var POWERSHELL_FOLDER_PICKER_CSHARP = `
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
- command: entry.execPath,
80494
- args: [entry.entryPath, "hook", "subagents-context"]
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 command for TypeScript entries requires a tsx loader path");
81393
+ throw new Error("Fleet Console capture session hook requires a tsx loader path");
80500
81394
  }
80501
- return {
80502
- command: entry.execPath,
80503
- args: ["--import", pathToFileURL2(entry.tsxLoaderPath).href, entry.entryPath, "hook", "subagents-context"]
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 ?? process4.cwd();
80532
- const env = deps.env ?? process4.env;
80533
- const execPath = deps.execPath ?? process4.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 ?? process4.platform;
80536
- const entryPath = resolveHookEntryPath(deps.entryPath ?? process4.argv[1]);
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(process4.platform, process4.env);
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: true,
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 ?? (() => crypto32.randomBytes(32).toString("base64url"));
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 execFileAsync2 = promisify(execFile2);
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 execFileAsync2("git", ["status", "--porcelain=v1", "-z", "--untracked-files=all"], {
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.removeTerminalSession(sessionId);
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/pick") {
81265
- runAsyncHandler(handleTerminalFolderPick(req, res), res);
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
- sessionId = SHELL_TERMINAL_SESSION_ID;
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 handleTerminalFolderPick(req, res) {
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 result = await pickTerminalFolder();
81375
- if (result.kind === "cancelled") {
81376
- writeJson(res, 200, { cancelled: true });
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
- if (result.kind === "error") {
81380
- writeJson(res, result.error === "invalid_folder" ? 400 : 503, { error: result.error });
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
- writeJson(res, 200, { folderGrantId: folderGrants.issue(result.cwd) });
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
- terminalSessions.terminate(sessionId);
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 result = await pickTerminalFolder();
81454
- if (result.kind === "cancelled") {
81455
- writeJson(res, 200, { cancelled: true });
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
- if (result.kind === "error") {
81459
- writeJson(res, result.error === "invalid_folder" ? 400 : 503, { error: result.error });
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(result.cwd);
82605
+ const theater = await theaters.register(cwd);
81463
82606
  let hasWiki = false;
81464
82607
  try {
81465
- await codex.registerWorkspace(result.cwd);
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 = crypto32.randomUUID();
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) || rest.length > 0) {
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 ?? process4.env;
81950
- const execPath = deps.execPath ?? process4.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
- process4.once("SIGTERM", () => {
83310
+ process6.once("SIGTERM", () => {
81965
83311
  void server.stop().finally(resolve2);
81966
83312
  });
81967
- process4.once("SIGINT", () => {
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
- process4.kill(payload.pid, "SIGTERM");
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
- process4.kill(payload.pid, 0);
81988
- process4.kill(payload.pid, "SIGKILL");
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 (process4.argv[2] === "serve") {
83452
+ if (process6.argv[2] === "serve") {
82107
83453
  await createConsoleDaemonLifecycle().runServer();
82108
83454
  return;
82109
83455
  }
82110
- if (process4.argv[2] === "hook") {
82111
- parseConsoleHookCommand(process4.argv.slice(3));
82112
- {
82113
- process4.stdout.write(`${runSubagentsContextHook(process4.env)}
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 (process4.argv[2] === "codex") {
82119
- await mainWiki(process4.argv.slice(3));
83470
+ if (process6.argv[2] === "codex") {
83471
+ await mainWiki(process6.argv.slice(3));
82120
83472
  return;
82121
83473
  }
82122
- const mode = parseConsoleCliMode(process4.argv.slice(2));
83474
+ const mode = parseConsoleCliMode(process6.argv.slice(2));
82123
83475
  if (mode === "help") {
82124
- process4.stdout.write(`${buildConsoleHelpText({ env: process4.env, isTTY: process4.stdout.isTTY })}
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
- process4.stdout.write(`${await runConsoleStatus()}
83481
+ process6.stdout.write(`${await runConsoleStatus()}
82130
83482
  `);
82131
83483
  return;
82132
83484
  }
82133
83485
  if (mode === "stop") {
82134
- process4.stdout.write(`${await runConsoleStop()}
83486
+ process6.stdout.write(`${await runConsoleStop()}
82135
83487
  `);
82136
83488
  return;
82137
83489
  }
82138
83490
  if (mode === "restart") {
82139
83491
  await runConsoleRestart();
82140
- process4.stdout.write("Fleet Console restarted.\n");
83492
+ process6.stdout.write("Fleet Console restarted.\n");
82141
83493
  return;
82142
83494
  }
82143
83495
  await openFleetConsole();
82144
- process4.stdout.write("Fleet Console opened.\n");
83496
+ process6.stdout.write("Fleet Console opened.\n");
82145
83497
  }
82146
- async function mainWiki(argv2 = process4.argv.slice(2)) {
83498
+ async function mainWiki(argv2 = process6.argv.slice(2)) {
82147
83499
  if (argv2.includes("--help") || argv2.includes("-h")) {
82148
- process4.stdout.write(`${buildWikiHelpText({ env: process4.env, isTTY: process4.stdout.isTTY })}
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: process4.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 = process4.argv[1] && path93__default.resolve(process4.argv[1]) === fileURLToPath(import.meta.url);
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
- process4.stderr.write(`${error512 instanceof Error ? error512.message : String(error512)}
83522
+ process6.stderr.write(`${error512 instanceof Error ? error512.message : String(error512)}
82171
83523
  `);
82172
- process4.exitCode = 1;
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 crypto5 from "crypto";
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 crypto5.createHash("sha256").update(content, "utf8").digest("hex").slice(0, 8);
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()}-${crypto5.randomUUID()}-${os6.hostname()}`
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 execFileAsync3 = promisify2(execFile3);
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 execFileAsync3("git", ["status", "--porcelain=v1", "-z", "--untracked-files=all"], {
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: true
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 (!isRecord4(value)) return false;
92628
+ if (!isRecord5(value)) return false;
91273
92629
  const carriers = value.carriers;
91274
- return carriers === void 0 || isRecord4(carriers);
92630
+ return carriers === void 0 || isRecord5(carriers);
91275
92631
  }
91276
- function isRecord4(value) {
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: true
92673
+ replaceSystemPrompt: false
91318
92674
  },
91319
92675
  env: process.env,
91320
92676
  globalOptionsService: runtime.infraServices.globalOptionsService,