@dotobokuri/fleet-console 1.6.0 → 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.
Files changed (65) hide show
  1. package/AGENTS.md +1 -0
  2. package/README.md +9 -4
  3. package/dist/cli-bin.mjs +439 -284
  4. package/dist/cli.d.ts +4 -0
  5. package/dist/cli.mjs +439 -284
  6. package/dist/client/assets/{_baseUniq-CYDnUUwD.js → _baseUniq-DaRHKvkJ.js} +1 -1
  7. package/dist/client/assets/{arc-C2kUi1S_.js → arc-ByrjrNFZ.js} +1 -1
  8. package/dist/client/assets/{architectureDiagram-Q4EWVU46-CsfgL2zC.js → architectureDiagram-Q4EWVU46-yRDXYtYq.js} +1 -1
  9. package/dist/client/assets/{blockDiagram-DXYQGD6D-uqim2Pmo.js → blockDiagram-DXYQGD6D-B3Ud4HmY.js} +1 -1
  10. package/dist/client/assets/{c4Diagram-AHTNJAMY-CRz88GqP.js → c4Diagram-AHTNJAMY-BWtT7uJ6.js} +1 -1
  11. package/dist/client/assets/channel-D1hUfR86.js +1 -0
  12. package/dist/client/assets/{chunk-4BX2VUAB-DNgf85a7.js → chunk-4BX2VUAB-Cdk_k5EX.js} +1 -1
  13. package/dist/client/assets/{chunk-4TB4RGXK-Ds39jFtV.js → chunk-4TB4RGXK-CfeLiRAa.js} +1 -1
  14. package/dist/client/assets/{chunk-55IACEB6-Bv7hCHgD.js → chunk-55IACEB6-B26kabv5.js} +1 -1
  15. package/dist/client/assets/{chunk-EDXVE4YY-BUjgWLOR.js → chunk-EDXVE4YY-CZ5hqsgg.js} +1 -1
  16. package/dist/client/assets/{chunk-FMBD7UC4-WVMeE3Je.js → chunk-FMBD7UC4-CuCp-r0v.js} +1 -1
  17. package/dist/client/assets/{chunk-OYMX7WX6-Bd5Z4NNL.js → chunk-OYMX7WX6-Dy5T8Uzb.js} +1 -1
  18. package/dist/client/assets/{chunk-QZHKN3VN-BfIbGoT4.js → chunk-QZHKN3VN-PNRzwWoU.js} +1 -1
  19. package/dist/client/assets/{chunk-YZCP3GAM-T_CDhFqg.js → chunk-YZCP3GAM-BjJxIVvV.js} +1 -1
  20. package/dist/client/assets/classDiagram-6PBFFD2Q-B7ZtwAd2.js +1 -0
  21. package/dist/client/assets/classDiagram-v2-HSJHXN6E-B7ZtwAd2.js +1 -0
  22. package/dist/client/assets/clone-BggxG0Ng.js +1 -0
  23. package/dist/client/assets/{cose-bilkent-S5V4N54A-M6EvTH7M.js → cose-bilkent-S5V4N54A-CIL2KUnC.js} +1 -1
  24. package/dist/client/assets/{dagre-KV5264BT-UUCScvPY.js → dagre-KV5264BT-BoekxdN3.js} +1 -1
  25. package/dist/client/assets/{diagram-5BDNPKRD-BnmEvwtB.js → diagram-5BDNPKRD-8Uqn3Uve.js} +1 -1
  26. package/dist/client/assets/{diagram-G4DWMVQ6-QHdTQz1G.js → diagram-G4DWMVQ6-CWZp4Fw1.js} +1 -1
  27. package/dist/client/assets/{diagram-MMDJMWI5-B-4tZ6wC.js → diagram-MMDJMWI5-Cxxmq5lR.js} +1 -1
  28. package/dist/client/assets/{diagram-TYMM5635-D5KVosUo.js → diagram-TYMM5635-BDL3SVhp.js} +1 -1
  29. package/dist/client/assets/{erDiagram-SMLLAGMA-B-FwpOjI.js → erDiagram-SMLLAGMA-Bm_XDDZi.js} +1 -1
  30. package/dist/client/assets/{flowDiagram-DWJPFMVM-CO00mjhm.js → flowDiagram-DWJPFMVM-z3JhyUpl.js} +1 -1
  31. package/dist/client/assets/{ganttDiagram-T4ZO3ILL-ChcRAmXN.js → ganttDiagram-T4ZO3ILL-DVfDRTRP.js} +1 -1
  32. package/dist/client/assets/{gitGraphDiagram-UUTBAWPF-BWSq2uT3.js → gitGraphDiagram-UUTBAWPF-_gni8LDF.js} +1 -1
  33. package/dist/client/assets/{graph-mErvxWG_.js → graph-Beq1lcyq.js} +1 -1
  34. package/dist/client/assets/index-3nhZQ9tb.css +1 -0
  35. package/dist/client/assets/index-DFffaVk9.js +734 -0
  36. package/dist/client/assets/{infoDiagram-42DDH7IO-CchQFIPi.js → infoDiagram-42DDH7IO-B-TP33al.js} +1 -1
  37. package/dist/client/assets/{ishikawaDiagram-UXIWVN3A-BAsF6BnZ.js → ishikawaDiagram-UXIWVN3A-1YDVINPA.js} +1 -1
  38. package/dist/client/assets/{journeyDiagram-VCZTEJTY-DE0wiQxC.js → journeyDiagram-VCZTEJTY-CZJuR6NC.js} +1 -1
  39. package/dist/client/assets/{kanban-definition-6JOO6SKY-BzPJLpKw.js → kanban-definition-6JOO6SKY-_sSHU_-t.js} +1 -1
  40. package/dist/client/assets/{layout-CO0unZG0.js → layout-UzmHJbGX.js} +1 -1
  41. package/dist/client/assets/{linear-CkDoVGz5.js → linear-BHitegAT.js} +1 -1
  42. package/dist/client/assets/{mermaid.core-BWqsf-WS.js → mermaid.core-ptwBQDH8.js} +4 -4
  43. package/dist/client/assets/{min-BMb-G34C.js → min-CBjwmJst.js} +1 -1
  44. package/dist/client/assets/{mindmap-definition-QFDTVHPH-XVxnUTPw.js → mindmap-definition-QFDTVHPH-C8NIvAO1.js} +1 -1
  45. package/dist/client/assets/{pieDiagram-DEJITSTG-CKM6Cfhz.js → pieDiagram-DEJITSTG-paebhRXC.js} +1 -1
  46. package/dist/client/assets/{quadrantDiagram-34T5L4WZ-Dn_2AZqA.js → quadrantDiagram-34T5L4WZ-Bk0pN-T7.js} +1 -1
  47. package/dist/client/assets/{requirementDiagram-MS252O5E-uNgGGE60.js → requirementDiagram-MS252O5E-CkPyeOJB.js} +1 -1
  48. package/dist/client/assets/{sankeyDiagram-XADWPNL6-B75Ahck1.js → sankeyDiagram-XADWPNL6-tJsRZl9C.js} +1 -1
  49. package/dist/client/assets/{sequenceDiagram-FGHM5R23-Cw5UNG2_.js → sequenceDiagram-FGHM5R23-D1V2Qnb3.js} +1 -1
  50. package/dist/client/assets/{stateDiagram-FHFEXIEX-C6u6py_B.js → stateDiagram-FHFEXIEX-DdEFxPzQ.js} +1 -1
  51. package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-CpqK8Q3C.js +1 -0
  52. package/dist/client/assets/{timeline-definition-GMOUNBTQ-Bi50wA17.js → timeline-definition-GMOUNBTQ-D8sNtFqY.js} +1 -1
  53. package/dist/client/assets/{vennDiagram-DHZGUBPP-CufQGlDN.js → vennDiagram-DHZGUBPP-DoTEQk3E.js} +1 -1
  54. package/dist/client/assets/{wardley-RL74JXVD-BQLghHpH.js → wardley-RL74JXVD-BuEgLJ7M.js} +1 -1
  55. package/dist/client/assets/{wardleyDiagram-NUSXRM2D-C-_4o-CK.js → wardleyDiagram-NUSXRM2D-B0Gl34Zh.js} +1 -1
  56. package/dist/client/assets/{xychartDiagram-5P7HB3ND-e4ekvSc7.js → xychartDiagram-5P7HB3ND-Bf4nAMbM.js} +1 -1
  57. package/dist/client/index.html +2 -2
  58. package/package.json +1 -1
  59. package/dist/client/assets/channel-BDggAVtM.js +0 -1
  60. package/dist/client/assets/classDiagram-6PBFFD2Q-AVod154E.js +0 -1
  61. package/dist/client/assets/classDiagram-v2-HSJHXN6E-AVod154E.js +0 -1
  62. package/dist/client/assets/clone-DMJcvMWj.js +0 -1
  63. package/dist/client/assets/index-B4QPttGw.css +0 -1
  64. package/dist/client/assets/index-GN6Lp6Jj.js +0 -734
  65. package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-BMBsbsoy.js +0 -1
package/dist/cli.mjs CHANGED
@@ -4,7 +4,7 @@ import * as fs5 from 'fs';
4
4
  import fs5__default, { readFileSync, existsSync, mkdtempSync, writeFileSync, mkdirSync, rmSync, chmodSync, renameSync, readdirSync, constants, openSync, closeSync, lstatSync, unlinkSync, realpathSync, statSync, symlinkSync, fstatSync } from 'fs';
5
5
  import * as path93 from 'path';
6
6
  import path93__default, { join, resolve, relative, dirname } from 'path';
7
- import process5 from 'process';
7
+ import process6 from 'process';
8
8
  import { fileURLToPath, pathToFileURL } from 'url';
9
9
  import * as os22 from 'os';
10
10
  import os22__default from 'os';
@@ -969,10 +969,10 @@ function mergeDefs(...defs) {
969
969
  function cloneDef(schema) {
970
970
  return mergeDefs(schema._zod.def);
971
971
  }
972
- function getElementAtPath(obj, path34) {
973
- if (!path34)
972
+ function getElementAtPath(obj, path35) {
973
+ if (!path35)
974
974
  return obj;
975
- return path34.reduce((acc, key) => acc?.[key], obj);
975
+ return path35.reduce((acc, key) => acc?.[key], obj);
976
976
  }
977
977
  function promiseAllObject(promisesObj) {
978
978
  const keys = Object.keys(promisesObj);
@@ -1381,11 +1381,11 @@ function explicitlyAborted(x, startIndex = 0) {
1381
1381
  }
1382
1382
  return false;
1383
1383
  }
1384
- function prefixIssues(path34, issues) {
1384
+ function prefixIssues(path35, issues) {
1385
1385
  return issues.map((iss) => {
1386
1386
  var _a3;
1387
1387
  (_a3 = iss).path ?? (_a3.path = []);
1388
- iss.path.unshift(path34);
1388
+ iss.path.unshift(path35);
1389
1389
  return iss;
1390
1390
  });
1391
1391
  }
@@ -1532,16 +1532,16 @@ function flattenError(error51, mapper = (issue3) => issue3.message) {
1532
1532
  }
1533
1533
  function formatError(error51, mapper = (issue3) => issue3.message) {
1534
1534
  const fieldErrors = { _errors: [] };
1535
- const processError = (error52, path34 = []) => {
1535
+ const processError = (error52, path35 = []) => {
1536
1536
  for (const issue3 of error52.issues) {
1537
1537
  if (issue3.code === "invalid_union" && issue3.errors.length) {
1538
- issue3.errors.map((issues) => processError({ issues }, [...path34, ...issue3.path]));
1538
+ issue3.errors.map((issues) => processError({ issues }, [...path35, ...issue3.path]));
1539
1539
  } else if (issue3.code === "invalid_key") {
1540
- processError({ issues: issue3.issues }, [...path34, ...issue3.path]);
1540
+ processError({ issues: issue3.issues }, [...path35, ...issue3.path]);
1541
1541
  } else if (issue3.code === "invalid_element") {
1542
- processError({ issues: issue3.issues }, [...path34, ...issue3.path]);
1542
+ processError({ issues: issue3.issues }, [...path35, ...issue3.path]);
1543
1543
  } else {
1544
- const fullpath = [...path34, ...issue3.path];
1544
+ const fullpath = [...path35, ...issue3.path];
1545
1545
  if (fullpath.length === 0) {
1546
1546
  fieldErrors._errors.push(mapper(issue3));
1547
1547
  } else {
@@ -1568,17 +1568,17 @@ function formatError(error51, mapper = (issue3) => issue3.message) {
1568
1568
  }
1569
1569
  function treeifyError(error51, mapper = (issue3) => issue3.message) {
1570
1570
  const result = { errors: [] };
1571
- const processError = (error52, path34 = []) => {
1571
+ const processError = (error52, path35 = []) => {
1572
1572
  var _a3, _b;
1573
1573
  for (const issue3 of error52.issues) {
1574
1574
  if (issue3.code === "invalid_union" && issue3.errors.length) {
1575
- issue3.errors.map((issues) => processError({ issues }, [...path34, ...issue3.path]));
1575
+ issue3.errors.map((issues) => processError({ issues }, [...path35, ...issue3.path]));
1576
1576
  } else if (issue3.code === "invalid_key") {
1577
- processError({ issues: issue3.issues }, [...path34, ...issue3.path]);
1577
+ processError({ issues: issue3.issues }, [...path35, ...issue3.path]);
1578
1578
  } else if (issue3.code === "invalid_element") {
1579
- processError({ issues: issue3.issues }, [...path34, ...issue3.path]);
1579
+ processError({ issues: issue3.issues }, [...path35, ...issue3.path]);
1580
1580
  } else {
1581
- const fullpath = [...path34, ...issue3.path];
1581
+ const fullpath = [...path35, ...issue3.path];
1582
1582
  if (fullpath.length === 0) {
1583
1583
  result.errors.push(mapper(issue3));
1584
1584
  continue;
@@ -1610,8 +1610,8 @@ function treeifyError(error51, mapper = (issue3) => issue3.message) {
1610
1610
  }
1611
1611
  function toDotPath(_path) {
1612
1612
  const segs = [];
1613
- const path34 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1614
- for (const seg of path34) {
1613
+ const path35 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1614
+ for (const seg of path35) {
1615
1615
  if (typeof seg === "number")
1616
1616
  segs.push(`[${seg}]`);
1617
1617
  else if (typeof seg === "symbol")
@@ -14275,13 +14275,13 @@ function resolveRef(ref, ctx) {
14275
14275
  if (!ref.startsWith("#")) {
14276
14276
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
14277
14277
  }
14278
- const path34 = ref.slice(1).split("/").filter(Boolean);
14279
- if (path34.length === 0) {
14278
+ const path35 = ref.slice(1).split("/").filter(Boolean);
14279
+ if (path35.length === 0) {
14280
14280
  return ctx.rootSchema;
14281
14281
  }
14282
14282
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
14283
- if (path34[0] === defsKey) {
14284
- const key = path34[1];
14283
+ if (path35[0] === defsKey) {
14284
+ const key = path35[1];
14285
14285
  if (!key || !ctx.defs[key]) {
14286
14286
  throw new Error(`Reference not found: ${ref}`);
14287
14287
  }
@@ -17046,7 +17046,9 @@ function killProcess(child, forceTimeoutMs = 3e3) {
17046
17046
  try {
17047
17047
  execSync(`taskkill /PID ${child.pid} /T /F`, {
17048
17048
  stdio: "pipe",
17049
- timeout: 5e3
17049
+ timeout: 5e3,
17050
+ // 콘솔 없는 호스트에서 taskkill 호출 시 새 콘솔 창이 깜빡이는 것을 방지한다.
17051
+ windowsHide: true
17050
17052
  });
17051
17053
  } catch {
17052
17054
  child.kill("SIGKILL");
@@ -17120,7 +17122,12 @@ var BaseConnection = class extends EventEmitter {
17120
17122
  cwd: this.cwd,
17121
17123
  stdio: ["pipe", "pipe", "pipe"],
17122
17124
  env: this.env,
17123
- windowsVerbatimArguments: true
17125
+ windowsVerbatimArguments: true,
17126
+ // 콘솔이 없는 호스트(예: fleet-console 백엔드)에서 cmd.exe를 spawn하면
17127
+ // Windows가 새 콘솔 창을 할당해 깜빡인다. stdio는 모두 pipe라 가시 콘솔이
17128
+ // 불필요하므로 CREATE_NO_WINDOW로 창 생성을 억제한다. (fleet-cli처럼 콘솔이
17129
+ // 이미 있는 경우에도 무해하다.)
17130
+ windowsHide: true
17124
17131
  }) : spawn(this.command, this.args, {
17125
17132
  cwd: this.cwd,
17126
17133
  stdio: ["pipe", "pipe", "pipe"],
@@ -17876,7 +17883,9 @@ function resolveNpxPath(env) {
17876
17883
  encoding: "utf-8",
17877
17884
  stdio: "pipe",
17878
17885
  timeout: 5e3,
17879
- env
17886
+ env,
17887
+ // 콘솔 없는 호스트에서 `where npx` 실행 시 콘솔 창이 깜빡이는 것을 방지한다.
17888
+ windowsHide: true
17880
17889
  }).trim();
17881
17890
  const candidates = result.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
17882
17891
  if (windows) {
@@ -32447,7 +32456,7 @@ function createSessionCaptureHookExec(deps) {
32447
32456
  deps.provider
32448
32457
  ] : [deps.entryPath, "hook", "capture-session", deps.provider];
32449
32458
  return {
32450
- command: deps.execPath ?? process5.execPath,
32459
+ command: deps.execPath ?? process6.execPath,
32451
32460
  args
32452
32461
  };
32453
32462
  }
@@ -32805,15 +32814,21 @@ function claudeHooks(options) {
32805
32814
  if (!hookExec) {
32806
32815
  throw new Error("Fleet Claude session hook command is required");
32807
32816
  }
32808
- const captureSessionHookExec = options.captureSessionHookExec;
32817
+ const userPromptSubmitExecs = [options.captureSessionHookExec, options.turnStartHookExec].filter((exec) => exec !== void 0);
32818
+ const stopExecs = [options.turnEndHookExec].filter((exec) => exec !== void 0);
32809
32819
  return {
32810
32820
  hooks: {
32811
32821
  SessionStart: [{
32812
32822
  hooks: [claudeCommandHook(hookExec)]
32813
32823
  }],
32814
- ...captureSessionHookExec ? {
32824
+ ...userPromptSubmitExecs.length > 0 ? {
32815
32825
  UserPromptSubmit: [{
32816
- hooks: [claudeCommandHook(captureSessionHookExec)]
32826
+ hooks: userPromptSubmitExecs.map(claudeCommandHook)
32827
+ }]
32828
+ } : {},
32829
+ ...stopExecs.length > 0 ? {
32830
+ Stop: [{
32831
+ hooks: stopExecs.map(claudeCommandHook)
32817
32832
  }]
32818
32833
  } : {}
32819
32834
  }
@@ -33576,11 +33591,17 @@ async function injectAgentCliProfile(profile, options) {
33576
33591
  dataDir: options.dataDir,
33577
33592
  rootDir: options.pluginRootDir,
33578
33593
  captureSessionHookExec: options.captureSessionHookExec,
33594
+ turnStartHookExec: options.turnStartHookExec,
33595
+ turnEndHookExec: options.turnEndHookExec,
33579
33596
  hookExec: startupDefinitions.host === "claude" ? requireHookExec(options.hookExec) : void 0,
33580
33597
  withMarketplaceLock: options.withMarketplaceLock
33581
33598
  });
33582
33599
  const codexPluginKeys = plugin.codexRegistrations.map((registration) => `${registration.pluginName}@${registration.marketplaceName}`);
33583
- const codexProfile = profile.id === "codex" ? writeCodexFleetProfile(profile.env, doctrine, codexPluginKeys, options.captureSessionHookExec, (cleanup2) => tempCleanups.push(cleanup2)) : void 0;
33600
+ const codexProfile = profile.id === "codex" ? writeCodexFleetProfile(profile.env, doctrine, codexPluginKeys, {
33601
+ captureSessionHookExec: options.captureSessionHookExec,
33602
+ turnStartHookExec: options.turnStartHookExec,
33603
+ turnEndHookExec: options.turnEndHookExec
33604
+ }, (cleanup2) => tempCleanups.push(cleanup2)) : void 0;
33584
33605
  const launchWarnings = [];
33585
33606
  for (const registration of plugin.codexRegistrations) {
33586
33607
  const registrationWarning = await ensureCodexPluginRegistered(registration, {
@@ -33656,7 +33677,7 @@ function writeSystemPromptFile(cliId, systemPrompt, onCleanup) {
33656
33677
  chmodBestEffort2(filePath, SYSTEM_PROMPT_FILE_MODE);
33657
33678
  return filePath;
33658
33679
  }
33659
- function writeCodexFleetProfile(env, doctrine, pluginKeys, captureSessionHookExec, onCleanup) {
33680
+ function writeCodexFleetProfile(env, doctrine, pluginKeys, hookExecs, onCleanup) {
33660
33681
  const codexHome = env.CODEX_HOME ?? path93__default.join(env.HOME ?? os22__default.homedir(), ".codex");
33661
33682
  mkdirSync(codexHome, { recursive: true });
33662
33683
  pruneStaleCodexFleetProfiles(codexHome);
@@ -33676,19 +33697,31 @@ function writeCodexFleetProfile(env, doctrine, pluginKeys, captureSessionHookExe
33676
33697
  "enabled = true",
33677
33698
  ""
33678
33699
  ]),
33679
- ...codexCaptureHookConfig(captureSessionHookExec)
33700
+ ...codexHooksConfig(hookExecs)
33680
33701
  ].join("\n"));
33681
33702
  chmodBestEffort2(profilePath, SYSTEM_PROMPT_FILE_MODE);
33682
33703
  return { profileName, profilePath };
33683
33704
  }
33684
- function codexCaptureHookConfig(captureSessionHookExec) {
33685
- if (captureSessionHookExec === void 0) return [];
33686
- const command2 = buildPosixShellCommand([captureSessionHookExec.command, ...captureSessionHookExec.args]);
33687
- return [
33688
- "[hooks]",
33689
- `UserPromptSubmit = [{ hooks = [{ type = "command", command = "${escapeTomlBasicString2(command2)}" }] }]`,
33690
- ""
33691
- ];
33705
+ function codexHooksConfig(hookExecs) {
33706
+ const userPromptSubmitExecs = [hookExecs.captureSessionHookExec, hookExecs.turnStartHookExec].filter((exec) => exec !== void 0);
33707
+ const stopExecs = [hookExecs.turnEndHookExec].filter((exec) => exec !== void 0);
33708
+ if (userPromptSubmitExecs.length === 0 && stopExecs.length === 0) return [];
33709
+ const lines = ["[hooks]"];
33710
+ if (userPromptSubmitExecs.length > 0) {
33711
+ lines.push(`UserPromptSubmit = ${codexHookHandlersInline(userPromptSubmitExecs)}`);
33712
+ }
33713
+ if (stopExecs.length > 0) {
33714
+ lines.push(`Stop = ${codexHookHandlersInline(stopExecs)}`);
33715
+ }
33716
+ lines.push("");
33717
+ return lines;
33718
+ }
33719
+ function codexHookHandlersInline(execs) {
33720
+ const handlers = execs.map((exec) => {
33721
+ const command2 = buildPosixShellCommand([exec.command, ...exec.args]);
33722
+ return `{ type = "command", command = "${escapeTomlBasicString2(command2)}" }`;
33723
+ }).join(", ");
33724
+ return `[{ hooks = [${handlers}] }]`;
33692
33725
  }
33693
33726
  function writeFileNoFollow2(filePath, content) {
33694
33727
  const flags = constants.O_WRONLY | constants.O_CREAT | constants.O_TRUNC | constants.O_NOFOLLOW;
@@ -41842,6 +41875,12 @@ function createConsoleObservabilityStore(deps = {}) {
41842
41875
  session.status = status;
41843
41876
  return toTerminalSessionInfo(session);
41844
41877
  }
41878
+ function setTerminalSessionTurnState(sessionId, turnState) {
41879
+ const session = terminalSessionsById.get(sessionId);
41880
+ if (!session) return null;
41881
+ session.turnState = turnState;
41882
+ return toTerminalSessionInfo(session);
41883
+ }
41845
41884
  function transitionTerminalSessionToDormant(sessionId, providerSession) {
41846
41885
  const session = terminalSessionsById.get(sessionId);
41847
41886
  if (!session) return null;
@@ -41909,6 +41948,7 @@ function createConsoleObservabilityStore(deps = {}) {
41909
41948
  subscribeAll,
41910
41949
  updateTerminalSessionProviderSession,
41911
41950
  updateTerminalSessionStatus,
41951
+ setTerminalSessionTurnState,
41912
41952
  transitionTerminalSessionToDormant,
41913
41953
  removeTerminalSession,
41914
41954
  registerTerminalRuntimeSession,
@@ -41977,6 +42017,7 @@ function toTerminalSessionInfo(state) {
41977
42017
  cliId: state.cliId,
41978
42018
  cliLabel: state.cliLabel,
41979
42019
  status: state.status,
42020
+ turnState: state.turnState ?? "none",
41980
42021
  createdAt: state.createdAt,
41981
42022
  theaterId: state.theaterId,
41982
42023
  registrationId: state.registrationId,
@@ -42193,6 +42234,126 @@ function resolveConsolePath(pathname) {
42193
42234
  if (!path93__default.extname(withoutPrefix)) return "index.html";
42194
42235
  return withoutPrefix;
42195
42236
  }
42237
+ var TerminalFolderListError = class extends Error {
42238
+ code;
42239
+ constructor(code) {
42240
+ super(code);
42241
+ this.name = "TerminalFolderListError";
42242
+ this.code = code;
42243
+ }
42244
+ };
42245
+ var DIRECTORY_ENTRY_CAP = 500;
42246
+ var WINDOWS_DRIVE_LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");
42247
+ async function listTerminalFolders(requestedPath, deps = {}) {
42248
+ const platform = deps.platform ?? process.platform;
42249
+ const stat5 = deps.stat ?? fs5__default.promises.stat;
42250
+ const opendir = deps.opendir ?? fs5__default.promises.opendir;
42251
+ const targetPath = normalizeListPath(requestedPath, platform, deps);
42252
+ const roots = await listRoots(platform, stat5);
42253
+ const targetStat = await statDirectory(targetPath, stat5);
42254
+ if (!targetStat.isDirectory()) throw new TerminalFolderListError("invalid_path");
42255
+ const entries = [];
42256
+ const truncated = await collectDirectoryEntries(targetPath, opendir, stat5, entries);
42257
+ entries.sort((a, b) => a.name.localeCompare(b.name));
42258
+ return {
42259
+ path: targetPath,
42260
+ parentPath: parentPath(targetPath, platform),
42261
+ roots,
42262
+ entries,
42263
+ ...truncated ? { truncated: true } : {}
42264
+ };
42265
+ }
42266
+ function normalizeFolderBrowserPath(value, platform = process.platform) {
42267
+ if (typeof value !== "string" || value.length === 0 || value.includes("\0")) throw new TerminalFolderListError("invalid_path");
42268
+ if (isWindowsAmbiguousPath(value, platform) || !path93__default.isAbsolute(value)) throw new TerminalFolderListError("invalid_path");
42269
+ return path93__default.resolve(value);
42270
+ }
42271
+ function normalizeListPath(requestedPath, platform, deps) {
42272
+ if (requestedPath === null || requestedPath === void 0) {
42273
+ const home = deps.homedir?.() ?? os22__default.homedir();
42274
+ const start = home || deps.cwd?.() || process.cwd();
42275
+ return path93__default.resolve(start);
42276
+ }
42277
+ return normalizeFolderBrowserPath(requestedPath, platform);
42278
+ }
42279
+ async function listRoots(platform, stat5) {
42280
+ if (platform !== "win32") return ["/"];
42281
+ const roots = [];
42282
+ await Promise.all(WINDOWS_DRIVE_LETTERS.map(async (letter) => {
42283
+ const root = `${letter}:\\`;
42284
+ try {
42285
+ if ((await stat5(root)).isDirectory()) roots.push(root);
42286
+ } catch {
42287
+ }
42288
+ }));
42289
+ return roots.sort();
42290
+ }
42291
+ async function statDirectory(targetPath, stat5) {
42292
+ try {
42293
+ return await stat5(targetPath);
42294
+ } catch (error51) {
42295
+ throw mapFsError(error51);
42296
+ }
42297
+ }
42298
+ async function collectDirectoryEntries(targetPath, opendir, stat5, entries) {
42299
+ const directory = await openDirectory(targetPath, opendir);
42300
+ try {
42301
+ let dirent = await directory.read();
42302
+ while (dirent !== null) {
42303
+ const entry = await toTerminalFolderEntry(targetPath, dirent, stat5);
42304
+ if (entry !== null) {
42305
+ if (entries.length >= DIRECTORY_ENTRY_CAP) return true;
42306
+ entries.push(entry);
42307
+ }
42308
+ dirent = await directory.read();
42309
+ }
42310
+ return false;
42311
+ } catch (error51) {
42312
+ throw mapFsError(error51);
42313
+ } finally {
42314
+ await directory.close();
42315
+ }
42316
+ }
42317
+ async function openDirectory(targetPath, opendir) {
42318
+ try {
42319
+ return await opendir(targetPath);
42320
+ } catch (error51) {
42321
+ throw mapFsError(error51);
42322
+ }
42323
+ }
42324
+ async function toTerminalFolderEntry(targetPath, dirent, stat5) {
42325
+ if (!dirent.isDirectory() && !dirent.isSymbolicLink()) return null;
42326
+ const entryPath = path93__default.join(targetPath, dirent.name);
42327
+ if (dirent.isDirectory()) return { name: dirent.name, path: entryPath, kind: "dir", accessible: true };
42328
+ const accessible = await statSymlinkDirectory(entryPath, stat5);
42329
+ if (accessible === null) return null;
42330
+ return { name: dirent.name, path: entryPath, kind: "dir", accessible };
42331
+ }
42332
+ async function statSymlinkDirectory(entryPath, stat5) {
42333
+ try {
42334
+ return (await stat5(entryPath)).isDirectory() ? true : null;
42335
+ } catch {
42336
+ return false;
42337
+ }
42338
+ }
42339
+ function mapFsError(error51) {
42340
+ const code = error51.code;
42341
+ if (code === "EACCES" || code === "EPERM") return new TerminalFolderListError("forbidden");
42342
+ if (code === "ENOENT" || code === "ENOTDIR") return new TerminalFolderListError("not_found");
42343
+ return new TerminalFolderListError("invalid_path");
42344
+ }
42345
+ function parentPath(targetPath, platform) {
42346
+ const parsed = path93__default.parse(targetPath);
42347
+ const resolved = path93__default.resolve(targetPath);
42348
+ if (resolved === path93__default.resolve(parsed.root)) return null;
42349
+ const parent = path93__default.dirname(resolved);
42350
+ if (platform === "win32" && parent === resolved) return null;
42351
+ return parent;
42352
+ }
42353
+ function isWindowsAmbiguousPath(value, platform) {
42354
+ if (platform !== "win32") return false;
42355
+ return /^[a-zA-Z]:(?![\\/])/.test(value) || /^[\\/](?![\\/])/.test(value);
42356
+ }
42196
42357
  var GRANT_ID_BYTES = 24;
42197
42358
  var DEFAULT_GRANT_TTL_MS = 6e4;
42198
42359
  function createFolderGrantStore(deps = {}) {
@@ -42224,167 +42385,15 @@ function createFolderGrantStore(deps = {}) {
42224
42385
  return { issue: issue3, consume };
42225
42386
  }
42226
42387
  function validateAbsoluteDirectory(cwd, statSync5 = fs5__default.statSync) {
42227
- if (!path93__default.isAbsolute(cwd)) throw new Error("invalid_folder");
42388
+ if (typeof cwd !== "string" || cwd.length === 0 || cwd.includes("\0")) throw new Error("invalid_folder");
42389
+ if (isWindowsAmbiguousPath2(cwd) || !path93__default.isAbsolute(cwd)) throw new Error("invalid_folder");
42228
42390
  const normalized = path93__default.resolve(cwd);
42229
42391
  if (!statSync5(normalized).isDirectory()) throw new Error("invalid_folder");
42230
42392
  return normalized;
42231
42393
  }
42232
-
42233
- // src/terminal/folder-picker.ts
42234
- var execFileAsync = promisify(execFile);
42235
- var DIALOG_TIMEOUT_MS = 3e4;
42236
- var POWERSHELL_FOLDER_PICKER_CSHARP = `
42237
- using System;
42238
- using System.Runtime.InteropServices;
42239
- namespace FleetPicker {
42240
- [ComImport, Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
42241
- public interface IShellItem {
42242
- void BindToHandler();
42243
- void GetParent();
42244
- [PreserveSig] int GetDisplayName(int sigdn, out IntPtr ppszName);
42245
- void GetAttributes();
42246
- void Compare();
42247
- }
42248
- [ComImport, Guid("d57c7288-d4ad-4768-be02-9d969532d960"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
42249
- public interface IFileOpenDialog {
42250
- [PreserveSig] int Show(IntPtr parent);
42251
- void SetFileTypes(); void SetFileTypeIndex(); void GetFileTypeIndex();
42252
- void Advise(); void Unadvise();
42253
- [PreserveSig] int SetOptions(uint fos);
42254
- [PreserveSig] int GetOptions(out uint pfos);
42255
- void SetDefaultFolder();
42256
- void SetFolder(IShellItem psi);
42257
- void GetFolder(); void GetCurrentSelection();
42258
- void SetFileName(); void GetFileName(); void SetTitle(); void SetOkButtonLabel(); void SetFileNameLabel();
42259
- [PreserveSig] int GetResult(out IShellItem ppsi);
42260
- void AddPlace(IShellItem psi, int fdap);
42261
- void SetDefaultExtension(); void Close(); void SetClientGuid(); void ClearClientData(); void SetFilter();
42262
- void GetResults(); void GetSelectedItems();
42263
- }
42264
- [ComImport, Guid("DC1C5A9C-E88A-4DDE-A5A1-60F82A20AEF7")] public class FileOpenDialog { }
42265
- public static class Picker {
42266
- [DllImport("shell32.dll", CharSet=CharSet.Unicode, PreserveSig=false)]
42267
- static extern void SHCreateItemFromParsingName(string pszPath, IntPtr pbc, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out IShellItem ppv);
42268
- static IShellItem ItemFromPath(string path) {
42269
- Guid iid = new Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe");
42270
- IShellItem it; SHCreateItemFromParsingName(path, IntPtr.Zero, ref iid, out it); return it;
42271
- }
42272
- public static string Pick(string initialPath) {
42273
- var dlg = (IFileOpenDialog)(new FileOpenDialog());
42274
- uint opts; dlg.GetOptions(out opts);
42275
- dlg.SetOptions(opts | 0x20); // FOS_PICKFOLDERS
42276
- if (!string.IsNullOrEmpty(initialPath)) {
42277
- // \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.
42278
- try { IShellItem s = ItemFromPath(initialPath); dlg.AddPlace(s, 1); dlg.SetFolder(s); } catch { }
42279
- }
42280
- if (dlg.Show(IntPtr.Zero) != 0) return null; // \uCDE8\uC18C/\uC2E4\uD328 \uC2DC null
42281
- IShellItem item; dlg.GetResult(out item);
42282
- 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
42283
- string path = Marshal.PtrToStringAuto(ptr);
42284
- Marshal.FreeCoTaskMem(ptr);
42285
- return path;
42286
- }
42287
- }
42288
- }`;
42289
- function createNativeFolderPicker(deps = {}) {
42290
- const platform = deps.platform ?? process.platform;
42291
- const runCommand = deps.runCommand ?? runNativeCommand;
42292
- const statSync5 = deps.statSync ?? fs5__default.statSync;
42293
- const readProcVersion = deps.readProcVersion ?? defaultReadProcVersion;
42294
- const env = deps.env ?? process.env;
42295
- return async () => {
42296
- const isWsl = platform === "linux" && detectWsl(readProcVersion, env);
42297
- const wslStartPath = isWsl ? wslStartFolderUnc(env) : "";
42298
- const commands = buildPickerCommands(platform, isWsl, wslStartPath);
42299
- if (commands.length === 0) return { kind: "error", error: "unsupported_platform" };
42300
- for (const command2 of commands) {
42301
- const result = await runPickerCommand(runCommand, command2);
42302
- if ("kind" in result && result.kind === "unavailable") continue;
42303
- if ("kind" in result && result.kind === "cancelled") return { kind: "cancelled" };
42304
- if ("kind" in result && result.kind === "timeout") return { kind: "error", error: "dialog_timeout" };
42305
- if ("kind" in result) continue;
42306
- let resolvedPath = result.stdout.trim();
42307
- if (command2.postProcess === "wslpath") {
42308
- try {
42309
- const wslResult = await runCommand("wslpath", ["-u", resolvedPath]);
42310
- resolvedPath = wslResult.stdout.trim();
42311
- } catch {
42312
- return { kind: "error", error: "invalid_folder" };
42313
- }
42314
- }
42315
- try {
42316
- return { kind: "selected", cwd: validateAbsoluteDirectory(resolvedPath, statSync5) };
42317
- } catch {
42318
- return { kind: "error", error: "invalid_folder" };
42319
- }
42320
- }
42321
- return { kind: "error", error: "dialog_unavailable" };
42322
- };
42323
- }
42324
- function defaultReadProcVersion() {
42325
- try {
42326
- return fs5__default.readFileSync("/proc/version", "utf8");
42327
- } catch {
42328
- return "";
42329
- }
42330
- }
42331
- function detectWsl(readProcVersion, env) {
42332
- if (env.WSL_INTEROP !== void 0 || env.WSL_DISTRO_NAME !== void 0) return true;
42333
- return /microsoft|wsl/i.test(readProcVersion());
42334
- }
42335
- function buildPickerCommands(platform, isWsl = false, wslStartPath = "") {
42336
- if (platform === "darwin") {
42337
- return [{ bin: "osascript", args: ["-e", 'POSIX path of (choose folder with prompt "Choose a Fleet workspace")'] }];
42338
- }
42339
- if (platform === "linux") {
42340
- const commands = [];
42341
- if (isWsl) {
42342
- commands.push({ bin: "powershell.exe", args: buildPowerShellPickerArgs(wslStartPath), postProcess: "wslpath" });
42343
- }
42344
- commands.push(
42345
- { bin: "zenity", args: ["--file-selection", "--directory", "--title=Choose a Fleet workspace"] },
42346
- { bin: "kdialog", args: ["--getexistingdirectory", ".", "Choose a Fleet workspace"] }
42347
- );
42348
- return commands;
42349
- }
42350
- if (platform === "win32") {
42351
- return [{ bin: "powershell.exe", args: buildPowerShellPickerArgs("") }];
42352
- }
42353
- return [];
42354
- }
42355
- function buildPowerShellPickerArgs(initialWindowsPath) {
42356
- const escaped = initialWindowsPath.replace(/'/g, "''");
42357
- const script = [
42358
- "[Console]::OutputEncoding=[Text.Encoding]::UTF8",
42359
- `Add-Type -TypeDefinition '${POWERSHELL_FOLDER_PICKER_CSHARP}'`,
42360
- `$selection = [FleetPicker.Picker]::Pick('${escaped}')`,
42361
- "if ([string]::IsNullOrEmpty($selection)) { exit 1 }",
42362
- "[Console]::Out.Write($selection)"
42363
- ].join("\n");
42364
- return ["-NoProfile", "-Sta", "-Command", script];
42365
- }
42366
- function wslStartFolderUnc(env) {
42367
- const distro = env.WSL_DISTRO_NAME;
42368
- if (!distro) return "";
42369
- const home = env.HOME;
42370
- if (home && home.startsWith("/") && !home.startsWith("/mnt/")) {
42371
- return `\\\\wsl.localhost\\${distro}${home.replace(/\//g, "\\")}`;
42372
- }
42373
- return `\\\\wsl.localhost\\${distro}`;
42374
- }
42375
- async function runPickerCommand(runCommand, command2) {
42376
- try {
42377
- return await runCommand(command2.bin, command2.args);
42378
- } catch (error51) {
42379
- const err = error51;
42380
- if (err.code === "ENOENT") return { kind: "unavailable" };
42381
- if (err.code === "ETIMEDOUT") return { kind: "timeout" };
42382
- return { kind: "cancelled" };
42383
- }
42384
- }
42385
- async function runNativeCommand(bin, args) {
42386
- const result = await execFileAsync(bin, [...args], { timeout: DIALOG_TIMEOUT_MS, windowsHide: true });
42387
- return { stdout: result.stdout, stderr: result.stderr };
42394
+ function isWindowsAmbiguousPath2(value) {
42395
+ if (process.platform !== "win32") return false;
42396
+ return /^[a-zA-Z]:(?![\\/])/.test(value) || /^[\\/](?![\\/])/.test(value);
42388
42397
  }
42389
42398
  var JAVASCRIPT_ENTRY_EXTENSIONS = /* @__PURE__ */ new Set([".cjs", ".js", ".mjs"]);
42390
42399
  var TYPESCRIPT_ENTRY_EXTENSIONS = /* @__PURE__ */ new Set([".cts", ".mts", ".ts", ".tsx"]);
@@ -42393,23 +42402,10 @@ function buildConsoleHookCommand(entry) {
42393
42402
  if (entry === void 0) {
42394
42403
  throw new Error("Fleet Console session hook command requires the current console entry path");
42395
42404
  }
42396
- const extension = path93__default.extname(entry.entryPath);
42397
- if (JAVASCRIPT_ENTRY_EXTENSIONS.has(extension)) {
42398
- return {
42399
- command: entry.execPath,
42400
- args: [entry.entryPath, "hook", "subagents-context"]
42401
- };
42402
- }
42403
- if (TYPESCRIPT_ENTRY_EXTENSIONS.has(extension)) {
42404
- if (!entry.tsxLoaderPath) {
42405
- throw new Error("Fleet Console session hook command for TypeScript entries requires a tsx loader path");
42406
- }
42407
- return {
42408
- command: entry.execPath,
42409
- args: ["--import", pathToFileURL(entry.tsxLoaderPath).href, entry.entryPath, "hook", "subagents-context"]
42410
- };
42411
- }
42412
- throw new Error(`Unsupported Fleet Console session hook entry extension: ${extension}`);
42405
+ return buildConsoleCliHookExec(entry, ["hook", "subagents-context"]);
42406
+ }
42407
+ function buildConsoleTurnHookCommand(entry, phase) {
42408
+ return buildConsoleCliHookExec(entry, ["hook", phase === "start" ? "turn-start" : "turn-end"]);
42413
42409
  }
42414
42410
  function buildConsoleCaptureHookCommand(entry, cliId) {
42415
42411
  const extension = path93__default.extname(entry.entryPath);
@@ -42440,7 +42436,9 @@ function runCodexCommand(command2) {
42440
42436
  const result = spawnSync(command2.bin, command2.args, {
42441
42437
  cwd: command2.cwd,
42442
42438
  encoding: "utf8",
42443
- env: command2.env
42439
+ env: command2.env,
42440
+ // 콘솔 없는 fleet-console 백엔드에서 codex 등록 명령 실행 시 콘솔 창이 깜빡이는 것을 방지한다.
42441
+ windowsHide: true
42444
42442
  });
42445
42443
  return {
42446
42444
  status: result.status,
@@ -42453,6 +42451,25 @@ function withConsoleMarketplaceLock(target, fn) {
42453
42451
  mkdirSync(path93__default.dirname(lockDir), { recursive: true });
42454
42452
  return withDirectoryLock({ lockDir }, fn);
42455
42453
  }
42454
+ function buildConsoleCliHookExec(entry, trailingArgs) {
42455
+ const extension = path93__default.extname(entry.entryPath);
42456
+ if (JAVASCRIPT_ENTRY_EXTENSIONS.has(extension)) {
42457
+ return {
42458
+ command: entry.execPath,
42459
+ args: [entry.entryPath, ...trailingArgs]
42460
+ };
42461
+ }
42462
+ if (TYPESCRIPT_ENTRY_EXTENSIONS.has(extension)) {
42463
+ if (!entry.tsxLoaderPath) {
42464
+ throw new Error("Fleet Console session hook command for TypeScript entries requires a tsx loader path");
42465
+ }
42466
+ return {
42467
+ command: entry.execPath,
42468
+ args: ["--import", pathToFileURL(entry.tsxLoaderPath).href, entry.entryPath, ...trailingArgs]
42469
+ };
42470
+ }
42471
+ throw new Error(`Unsupported Fleet Console session hook entry extension: ${extension}`);
42472
+ }
42456
42473
 
42457
42474
  // src/terminal/launch.ts
42458
42475
  var DEFAULT_TERMINAL_CWD_FALLBACK = os22__default.homedir;
@@ -42461,12 +42478,12 @@ var CONSOLE_ENTRY_PATH = fileURLToPath(import.meta.url);
42461
42478
  var HOOK_ENTRY_EXTENSIONS = /* @__PURE__ */ new Set([".cjs", ".cts", ".js", ".mjs", ".mts", ".ts", ".tsx"]);
42462
42479
  var require2 = createRequire(import.meta.url);
42463
42480
  function createDefaultTerminalLaunchResolver(deps = {}) {
42464
- const baseCwd = deps.cwd ?? process5.cwd();
42465
- const env = deps.env ?? process5.env;
42466
- const execPath = deps.execPath ?? process5.execPath;
42481
+ const baseCwd = deps.cwd ?? process6.cwd();
42482
+ const env = deps.env ?? process6.env;
42483
+ const execPath = deps.execPath ?? process6.execPath;
42467
42484
  const homedir3 = deps.homedir ?? DEFAULT_TERMINAL_CWD_FALLBACK;
42468
- const platform = deps.platform ?? process5.platform;
42469
- const entryPath = resolveHookEntryPath(deps.entryPath ?? process5.argv[1]);
42485
+ const platform = deps.platform ?? process6.platform;
42486
+ const entryPath = resolveHookEntryPath(deps.entryPath ?? process6.argv[1]);
42470
42487
  const tsxLoaderPath = deps.tsxLoaderPath ?? resolveOptionalPackage("tsx");
42471
42488
  const dataDir = deps.dataDir ?? getFleetDataDir();
42472
42489
  const infraServices = deps.infraServices ?? createInfraServices();
@@ -42527,7 +42544,7 @@ function hasHookEntryExtension(entryPath) {
42527
42544
  }
42528
42545
  function startTerminalShell(launch, size) {
42529
42546
  const { spawn: spawnPty } = require2("node-pty");
42530
- const useConptyDll = resolveUseConptyDll(process5.platform, process5.env);
42547
+ const useConptyDll = resolveUseConptyDll(process6.platform, process6.env);
42531
42548
  return spawnPty(launch.bin, [...launch.args], {
42532
42549
  cols: size.cols,
42533
42550
  rows: size.rows,
@@ -42563,6 +42580,8 @@ async function createAgentCliLaunchSpec(options) {
42563
42580
  dedicatedMcpSession: agentRuntime.dedicatedMcpSession,
42564
42581
  enableMetaphor: false,
42565
42582
  captureSessionHookExec: buildConsoleCaptureHookCommand(options.hookEntry, profile.id),
42583
+ turnStartHookExec: buildConsoleTurnHookCommand(options.hookEntry, "start"),
42584
+ turnEndHookExec: buildConsoleTurnHookCommand(options.hookEntry, "end"),
42566
42585
  hookExec: buildConsoleHookCommand(options.hookEntry),
42567
42586
  onCleanup: (cleanup) => cleanupStack.push(cleanup),
42568
42587
  replaceSystemPrompt: false,
@@ -42663,6 +42682,8 @@ var DEFAULT_COLS = 80;
42663
42682
  var DEFAULT_ROWS = 24;
42664
42683
  var DEFAULT_SCROLLBACK_LIMIT = 512;
42665
42684
  var WS_OPEN_STATE = 1;
42685
+ var THEATER_SHELL_SESSION_PREFIX = "shell:";
42686
+ var THEATER_SHELL_DETACH_GRACE_MS = 4e3;
42666
42687
  function createTerminalSessionManager(deps) {
42667
42688
  const startShell = deps.startShell ?? startTerminalShell;
42668
42689
  const scrollbackLimit = deps.scrollbackLimit ?? DEFAULT_SCROLLBACK_LIMIT;
@@ -42673,6 +42694,7 @@ function createTerminalSessionManager(deps) {
42673
42694
  }
42674
42695
  async function attach(socket, context) {
42675
42696
  const session = await getOrCreateSession(context);
42697
+ clearGraceTimer(session);
42676
42698
  if (session.activeSocket && session.activeSocket !== socket) {
42677
42699
  session.activeSocket.close(4e3, "terminal_replaced");
42678
42700
  }
@@ -42752,7 +42774,8 @@ function createTerminalSessionManager(deps) {
42752
42774
  renameCommand: launch.renameCommand,
42753
42775
  activeSocket: null,
42754
42776
  cols: DEFAULT_COLS,
42755
- rows: DEFAULT_ROWS
42777
+ rows: DEFAULT_ROWS,
42778
+ graceTimer: null
42756
42779
  };
42757
42780
  const dataDisposable = pty.onData((data) => handlePtyData(session, data));
42758
42781
  const exitDisposable = pty.onExit(() => removeSession(session));
@@ -42790,6 +42813,13 @@ function createTerminalSessionManager(deps) {
42790
42813
  function detachSocket(session, socket) {
42791
42814
  if (session.activeSocket !== socket) return;
42792
42815
  session.activeSocket = null;
42816
+ if (isTheaterShell(session.id)) {
42817
+ clearGraceTimer(session);
42818
+ session.graceTimer = setTimeout(() => {
42819
+ session.graceTimer = null;
42820
+ if (session.activeSocket === null) removeSession(session);
42821
+ }, THEATER_SHELL_DETACH_GRACE_MS);
42822
+ }
42793
42823
  }
42794
42824
  function replayScrollback(session, socket) {
42795
42825
  for (const chunk of session.scrollback) {
@@ -42805,6 +42835,7 @@ function createTerminalSessionManager(deps) {
42805
42835
  }
42806
42836
  async function killSession(session, options = {}) {
42807
42837
  const killPty = options.killPty ?? true;
42838
+ clearGraceTimer(session);
42808
42839
  session.activeSocket?.close(4001, "terminal_closed");
42809
42840
  session.activeSocket = null;
42810
42841
  for (const disposable of session.disposables) disposable.dispose();
@@ -42828,6 +42859,14 @@ function killPtyBestEffort(pty) {
42828
42859
  } catch {
42829
42860
  }
42830
42861
  }
42862
+ function isTheaterShell(sessionId) {
42863
+ return sessionId.startsWith(THEATER_SHELL_SESSION_PREFIX);
42864
+ }
42865
+ function clearGraceTimer(session) {
42866
+ if (session.graceTimer === null) return;
42867
+ clearTimeout(session.graceTimer);
42868
+ session.graceTimer = null;
42869
+ }
42831
42870
  function toBuffer(data) {
42832
42871
  if (Buffer.isBuffer(data)) return data;
42833
42872
  if (Array.isArray(data)) return Buffer.concat(data);
@@ -42871,7 +42910,7 @@ function createTerminalTicketRegistry(deps = {}) {
42871
42910
  }
42872
42911
  return { ttlMs, issue: issue3, consume, prune };
42873
42912
  }
42874
- var execFileAsync2 = promisify(execFile);
42913
+ var execFileAsync = promisify(execFile);
42875
42914
  var GIT_STATUS_TIMEOUT_MS = 4e3;
42876
42915
  var GIT_STATUS_MAX_BUFFER = 1024 * 1024;
42877
42916
  var GIT_HASH_TIMEOUT_MS = 4e3;
@@ -42880,11 +42919,13 @@ function createWorkspaceChangeScanner() {
42880
42919
  return {
42881
42920
  async snapshot(cwd) {
42882
42921
  try {
42883
- const { stdout } = await execFileAsync2("git", ["status", "--porcelain=v1", "-z", "--untracked-files=all"], {
42922
+ const { stdout } = await execFileAsync("git", ["status", "--porcelain=v1", "-z", "--untracked-files=all"], {
42884
42923
  cwd,
42885
42924
  encoding: "utf8",
42886
42925
  maxBuffer: GIT_STATUS_MAX_BUFFER,
42887
- timeout: GIT_STATUS_TIMEOUT_MS
42926
+ timeout: GIT_STATUS_TIMEOUT_MS,
42927
+ // 콘솔 없는 fleet-console 백엔드에서 git.exe 실행 시 콘솔 창이 깜빡이는 것을 방지한다.
42928
+ windowsHide: true
42888
42929
  });
42889
42930
  const entries = parseGitStatusPorcelainZ(stdout);
42890
42931
  if (!entries) return null;
@@ -42944,7 +42985,9 @@ function execGitHashObject(cwd, paths) {
42944
42985
  cwd,
42945
42986
  encoding: "utf8",
42946
42987
  maxBuffer: GIT_HASH_MAX_BUFFER,
42947
- timeout: GIT_HASH_TIMEOUT_MS
42988
+ timeout: GIT_HASH_TIMEOUT_MS,
42989
+ // 콘솔 없는 fleet-console 백엔드에서 git.exe 실행 시 콘솔 창이 깜빡이는 것을 방지한다.
42990
+ windowsHide: true
42948
42991
  },
42949
42992
  (error51, stdout) => {
42950
42993
  if (error51) {
@@ -43125,6 +43168,7 @@ function createConsoleUpdateCheckService(deps = {}) {
43125
43168
  var DEFAULT_HOST2 = "127.0.0.1";
43126
43169
  var DEFAULT_PORT2 = 0;
43127
43170
  var SHELL_TERMINAL_SESSION_ID = "shell";
43171
+ var THEATER_SHELL_SESSION_PREFIX2 = "shell:";
43128
43172
  var SERVER_TIMEOUT_MS = 30 * 60 * 1e3;
43129
43173
  var MAX_BODY_BYTES = 1024 * 1024;
43130
43174
  function createConsoleServer(deps = {}) {
@@ -43169,7 +43213,6 @@ function createConsoleServer(deps = {}) {
43169
43213
  getPort: () => lockHandle?.payload.port ?? port,
43170
43214
  getAdminToken: () => lockHandle?.payload.token ?? null
43171
43215
  });
43172
- const pickTerminalFolder = deps.terminalPickFolder ?? createNativeFolderPicker();
43173
43216
  const pendingRuntimeSessions = /* @__PURE__ */ new Map();
43174
43217
  const terminalSessions = createTerminalSessionManager({
43175
43218
  launch: deps.terminalLaunch ?? createDefaultTerminalLaunchResolver({
@@ -43251,8 +43294,12 @@ function createConsoleServer(deps = {}) {
43251
43294
  runAsyncHandler(handleTerminalTicket(req, res), res);
43252
43295
  return;
43253
43296
  }
43254
- if (pathname === "/terminal/folders/pick") {
43255
- runAsyncHandler(handleTerminalFolderPick(req, res), res);
43297
+ if (pathname === "/terminal/folders/list") {
43298
+ runAsyncHandler(handleTerminalFoldersList(req, res), res);
43299
+ return;
43300
+ }
43301
+ if (pathname === "/terminal/folders/grants") {
43302
+ runAsyncHandler(handleTerminalFolderGrants(req, res), res);
43256
43303
  return;
43257
43304
  }
43258
43305
  if (pathname === "/terminal/sessions") {
@@ -43264,6 +43311,11 @@ function createConsoleServer(deps = {}) {
43264
43311
  runAsyncHandler(handleTerminalSessionResume(req, res, decodeURIComponent(terminalSessionResumeMatch[1] ?? "")), res);
43265
43312
  return;
43266
43313
  }
43314
+ const terminalSessionTurnMatch = pathname.match(/^\/terminal\/sessions\/([^/]+)\/turn$/);
43315
+ if (terminalSessionTurnMatch) {
43316
+ runAsyncHandler(handleTerminalSessionTurn(req, res, decodeURIComponent(terminalSessionTurnMatch[1] ?? "")), res);
43317
+ return;
43318
+ }
43267
43319
  const terminalSessionItemMatch = pathname.match(/^\/terminal\/sessions\/([^/]+)$/);
43268
43320
  if (terminalSessionItemMatch) {
43269
43321
  runAsyncHandler(handleTerminalSessionItem(req, res, decodeURIComponent(terminalSessionItemMatch[1] ?? "")), res);
@@ -43330,6 +43382,30 @@ function createConsoleServer(deps = {}) {
43330
43382
  };
43331
43383
  writeJson(res, 200, body);
43332
43384
  }
43385
+ async function handleTerminalSessionTurn(req, res, sessionId) {
43386
+ if (req.method !== "POST") {
43387
+ writeJson(res, 405, { error: "Method not allowed" });
43388
+ return;
43389
+ }
43390
+ const token = lockHandle?.payload.token;
43391
+ if (!token || req.headers.authorization !== `Bearer ${token}`) {
43392
+ writeJson(res, 401, { error: "Unauthorized" });
43393
+ return;
43394
+ }
43395
+ const body = await readJsonBody(req);
43396
+ const turnState = body?.phase === "start" ? "running" : body?.phase === "end" ? "ended" : null;
43397
+ if (turnState === null) {
43398
+ writeJson(res, 400, { error: "invalid_phase" });
43399
+ return;
43400
+ }
43401
+ const updated = observability.setTerminalSessionTurnState(sessionId, turnState);
43402
+ if (!updated) {
43403
+ writeJson(res, 404, { error: "terminal_session_not_found" });
43404
+ return;
43405
+ }
43406
+ observability.notifySessionUpdated(updated);
43407
+ writeJson(res, 200, { ok: true });
43408
+ }
43333
43409
  async function handleTerminalTicket(req, res) {
43334
43410
  if (req.method !== "POST") {
43335
43411
  writeJson(res, 405, { error: "Method not allowed" });
@@ -43342,16 +43418,29 @@ function createConsoleServer(deps = {}) {
43342
43418
  const body = await readJsonBody(req);
43343
43419
  const kind = body?.kind === "shell" ? "shell" : "fleet";
43344
43420
  const requestedSessionId = body?.sessionId;
43421
+ const requestedTheaterId = typeof body?.theaterId === "string" ? body.theaterId : void 0;
43345
43422
  let sessionId;
43423
+ let cwd;
43346
43424
  if (kind === "shell") {
43347
- sessionId = SHELL_TERMINAL_SESSION_ID;
43425
+ if (typeof requestedSessionId === "string" && requestedSessionId.startsWith(THEATER_SHELL_SESSION_PREFIX2) && requestedTheaterId) {
43426
+ const theater = theaters.get(requestedTheaterId);
43427
+ if (!theater) {
43428
+ writeJson(res, 404, { error: "theater_not_found" });
43429
+ return;
43430
+ }
43431
+ sessionId = requestedSessionId;
43432
+ cwd = theater.path;
43433
+ } else {
43434
+ sessionId = SHELL_TERMINAL_SESSION_ID;
43435
+ cwd = "";
43436
+ }
43348
43437
  } else if (typeof requestedSessionId === "string" && requestedSessionId.length > 0) {
43349
43438
  sessionId = requestedSessionId;
43439
+ cwd = observability.getLaunchCwd(sessionId);
43350
43440
  } else {
43351
43441
  writeJson(res, 400, { error: "terminal_session_not_found" });
43352
43442
  return;
43353
43443
  }
43354
- const cwd = kind === "shell" ? "" : observability.getLaunchCwd(sessionId);
43355
43444
  if (cwd === null) {
43356
43445
  writeJson(res, 404, { error: "terminal_session_not_found" });
43357
43446
  return;
@@ -43366,7 +43455,7 @@ function createConsoleServer(deps = {}) {
43366
43455
  kind
43367
43456
  }));
43368
43457
  }
43369
- async function handleTerminalFolderPick(req, res) {
43458
+ async function handleTerminalFoldersList(req, res) {
43370
43459
  if (req.method !== "POST") {
43371
43460
  writeJson(res, 405, { error: "Method not allowed" });
43372
43461
  return;
@@ -43375,16 +43464,41 @@ function createConsoleServer(deps = {}) {
43375
43464
  writeJson(res, 401, { error: "unauthorized" });
43376
43465
  return;
43377
43466
  }
43378
- const result = await pickTerminalFolder();
43379
- if (result.kind === "cancelled") {
43380
- writeJson(res, 200, { cancelled: true });
43467
+ const body = await readJsonBody(req);
43468
+ if (!isPlainObject2(body) || body.path !== void 0 && body.path !== null && typeof body.path !== "string") {
43469
+ writeJson(res, 400, { error: "invalid_path" });
43470
+ return;
43471
+ }
43472
+ try {
43473
+ const payload = await listTerminalFolders(body.path === void 0 ? null : body.path);
43474
+ writeJson(res, 200, payload);
43475
+ } catch (error51) {
43476
+ if (error51 instanceof TerminalFolderListError) {
43477
+ writeJson(res, terminalFolderListStatus(error51), { error: error51.code });
43478
+ return;
43479
+ }
43480
+ throw error51;
43481
+ }
43482
+ }
43483
+ async function handleTerminalFolderGrants(req, res) {
43484
+ if (req.method !== "POST") {
43485
+ writeJson(res, 405, { error: "Method not allowed" });
43486
+ return;
43487
+ }
43488
+ if (!isTerminalAuthorized(req)) {
43489
+ writeJson(res, 401, { error: "unauthorized" });
43381
43490
  return;
43382
43491
  }
43383
- if (result.kind === "error") {
43384
- writeJson(res, result.error === "invalid_folder" ? 400 : 503, { error: result.error });
43492
+ const body = await readJsonBody(req);
43493
+ if (!isPlainObject2(body) || typeof body.path !== "string") {
43494
+ writeJson(res, 400, { error: "invalid_folder" });
43385
43495
  return;
43386
43496
  }
43387
- writeJson(res, 200, { folderGrantId: folderGrants.issue(result.cwd) });
43497
+ try {
43498
+ writeJson(res, 200, { folderGrantId: folderGrants.issue(body.path) });
43499
+ } catch {
43500
+ writeJson(res, 400, { error: "invalid_folder" });
43501
+ }
43388
43502
  }
43389
43503
  async function handleTerminalSessions(req, res) {
43390
43504
  if (!isTerminalAuthorized(req)) {
@@ -43514,19 +43628,20 @@ function createConsoleServer(deps = {}) {
43514
43628
  writeJson(res, 401, { error: "unauthorized" });
43515
43629
  return;
43516
43630
  }
43517
- const result = await pickTerminalFolder();
43518
- if (result.kind === "cancelled") {
43519
- writeJson(res, 200, { cancelled: true });
43631
+ const body = await readJsonBody(req);
43632
+ if (!isPlainObject2(body) || typeof body.folderGrantId !== "string") {
43633
+ writeJson(res, 400, { error: "invalid_folder_grant" });
43520
43634
  return;
43521
43635
  }
43522
- if (result.kind === "error") {
43523
- writeJson(res, result.error === "invalid_folder" ? 400 : 503, { error: result.error });
43636
+ const cwd = folderGrants.consume(body.folderGrantId);
43637
+ if (!cwd) {
43638
+ writeJson(res, 400, { error: "invalid_folder_grant" });
43524
43639
  return;
43525
43640
  }
43526
- const theater = await theaters.register(result.cwd);
43641
+ const theater = await theaters.register(cwd);
43527
43642
  let hasWiki = false;
43528
43643
  try {
43529
- await codex.registerWorkspace(result.cwd);
43644
+ await codex.registerWorkspace(cwd);
43530
43645
  hasWiki = true;
43531
43646
  } catch (error51) {
43532
43647
  if (!(error51 instanceof Error && error51.message === "knowledge_root_missing")) {
@@ -43546,11 +43661,7 @@ function createConsoleServer(deps = {}) {
43546
43661
  return;
43547
43662
  }
43548
43663
  const operations = observability.listDurableOperations().filter((operation) => operation.theaterId === theaterId);
43549
- const removed = theaters.remove(theaterId);
43550
- if (!removed) {
43551
- writeJson(res, 404, { error: "theater_not_found" });
43552
- return;
43553
- }
43664
+ theaters.remove(theaterId);
43554
43665
  for (const operation of operations) forgetTerminalSession(operation.sessionId, { persist: false });
43555
43666
  persistDurableState();
43556
43667
  writeJson(res, 200, { ok: true });
@@ -43938,6 +44049,14 @@ function readOptionalAgentCliId(value, res) {
43938
44049
  return false;
43939
44050
  }
43940
44051
  }
44052
+ function terminalFolderListStatus(error51) {
44053
+ if (error51.code === "forbidden") return 403;
44054
+ if (error51.code === "not_found") return 404;
44055
+ return 400;
44056
+ }
44057
+ function isPlainObject2(value) {
44058
+ return typeof value === "object" && value !== null && !Array.isArray(value);
44059
+ }
43941
44060
  async function readJsonBody(req) {
43942
44061
  const chunks = [];
43943
44062
  let total = 0;
@@ -43997,9 +44116,9 @@ function isAllowedTerminalOrigin(req, expectedPort) {
43997
44116
  return origin === `http://127.0.0.1:${expectedPort}`;
43998
44117
  }
43999
44118
  var CAPTURE_TEMP_PREFIX = ".capture.";
44000
- async function runCaptureSessionHook(provider, env = process5.env) {
44119
+ async function runCaptureSessionHook(provider, env = process6.env) {
44001
44120
  return captureSession({
44002
- diagnostics: process5.stderr,
44121
+ diagnostics: process6.stderr,
44003
44122
  env,
44004
44123
  input: await readStdin(),
44005
44124
  provider
@@ -44016,12 +44135,12 @@ function captureSession(options) {
44016
44135
  }
44017
44136
  function captureSessionStrict(options) {
44018
44137
  const provider = parseProvider(options.provider);
44019
- const fleetSessionId = readFleetSessionId(options.env ?? process5.env);
44138
+ const fleetSessionId = readFleetSessionId(options.env ?? process6.env);
44020
44139
  const input = parseHookInput(options.input ?? "");
44021
44140
  const providerSession = toProviderSession(provider, input, options.now ?? (() => /* @__PURE__ */ new Date()));
44022
44141
  const capturesDir = (options.paths ?? createConsoleDataPaths()).capturesDir;
44023
44142
  const finalPath = path93__default.join(capturesDir, `${fleetSessionId}.json`);
44024
- const tempPath = path93__default.join(capturesDir, `${CAPTURE_TEMP_PREFIX}${fleetSessionId}.${process5.pid}.${Date.now()}.tmp`);
44143
+ const tempPath = path93__default.join(capturesDir, `${CAPTURE_TEMP_PREFIX}${fleetSessionId}.${process6.pid}.${Date.now()}.tmp`);
44025
44144
  fs5__default.mkdirSync(capturesDir, { recursive: true, mode: 448 });
44026
44145
  fs5__default.writeFileSync(tempPath, `${JSON.stringify(providerSession, null, 2)}
44027
44146
  `, { mode: 384 });
@@ -44061,11 +44180,11 @@ function toProviderSession(provider, input, now) {
44061
44180
  function readStdin() {
44062
44181
  return new Promise((resolve, reject) => {
44063
44182
  const chunks = [];
44064
- process5.stdin.on("data", (chunk) => {
44183
+ process6.stdin.on("data", (chunk) => {
44065
44184
  chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
44066
44185
  });
44067
- process5.stdin.on("error", reject);
44068
- process5.stdin.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
44186
+ process6.stdin.on("error", reject);
44187
+ process6.stdin.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
44069
44188
  });
44070
44189
  }
44071
44190
  function createConsoleStalePolicy(deps = {}) {
@@ -44080,12 +44199,42 @@ function createConsoleStalePolicy(deps = {}) {
44080
44199
  }
44081
44200
  return { isBuildStale };
44082
44201
  }
44202
+ var TURN_POST_TIMEOUT_MS = 1500;
44203
+ async function runTurnStateHook(phase, env = process6.env, options = {}) {
44204
+ try {
44205
+ await postTurnState(phase, env, options);
44206
+ } catch {
44207
+ }
44208
+ }
44209
+ async function postTurnState(phase, env, options) {
44210
+ const sessionId = env.FLEET_CONSOLE_SESSION_ID;
44211
+ if (!sessionId) return;
44212
+ const paths = createConsolePaths({ env });
44213
+ const lock = createConsoleLock().readLock(paths.lockFile);
44214
+ if (!lock) return;
44215
+ const fetchImpl = options.fetchImpl ?? fetch;
44216
+ const controller = new AbortController();
44217
+ const timer = setTimeout(() => controller.abort(), options.timeoutMs ?? TURN_POST_TIMEOUT_MS);
44218
+ try {
44219
+ await fetchImpl(`${lock.endpoint}terminal/sessions/${encodeURIComponent(sessionId)}/turn`, {
44220
+ method: "POST",
44221
+ headers: {
44222
+ authorization: `Bearer ${lock.token}`,
44223
+ "content-type": "application/json"
44224
+ },
44225
+ body: JSON.stringify({ phase }),
44226
+ signal: controller.signal
44227
+ });
44228
+ } finally {
44229
+ clearTimeout(timer);
44230
+ }
44231
+ }
44083
44232
 
44084
44233
  // src/cli.ts
44085
44234
  var FIXED_HOST = "127.0.0.1";
44086
44235
  var HELP_BANNER_INDENT = " ";
44087
44236
  var DEFAULT_HELP_RELEASE = "local";
44088
- var CONSOLE_HOOK_COMMANDS = /* @__PURE__ */ new Set(["capture-session", "subagents-context"]);
44237
+ var CONSOLE_HOOK_COMMANDS = /* @__PURE__ */ new Set(["capture-session", "subagents-context", "turn-start", "turn-end"]);
44089
44238
  function parseConsoleCliMode(argv) {
44090
44239
  if (argv.length === 0) return "start";
44091
44240
  const [first, ...rest] = argv;
@@ -44116,6 +44265,8 @@ function parseConsoleHookCommand(argv) {
44116
44265
  throw new Error("Unknown fleet-console hook command");
44117
44266
  }
44118
44267
  if (commandName === "subagents-context" && rest.length === 0) return { command: "subagents-context" };
44268
+ if (commandName === "turn-start" && rest.length === 0) return { command: "turn-start" };
44269
+ if (commandName === "turn-end" && rest.length === 0) return { command: "turn-end" };
44119
44270
  if (commandName === "capture-session" && rest.length === 1 && rest[0]) return { command: "capture-session", provider: rest[0] };
44120
44271
  throw new Error("Unknown fleet-console hook command");
44121
44272
  }
@@ -44179,8 +44330,8 @@ function buildWikiHelpText(options = {}) {
44179
44330
  return colorEnabled ? text : stripAnsi(text);
44180
44331
  }
44181
44332
  function createConsoleDaemonLifecycle(deps = {}) {
44182
- const env = deps.env ?? process5.env;
44183
- const execPath = deps.execPath ?? process5.execPath;
44333
+ const env = deps.env ?? process6.env;
44334
+ const execPath = deps.execPath ?? process6.execPath;
44184
44335
  const serverModulePath = deps.serverModulePath ?? resolveDefaultServerModulePath();
44185
44336
  const spawnDetached = deps.spawnDetached ?? ((bin, args, options) => {
44186
44337
  spawn(bin, [...args], options).unref();
@@ -44194,10 +44345,10 @@ function createConsoleDaemonLifecycle(deps = {}) {
44194
44345
  const server = createConsoleServer();
44195
44346
  await server.start(paths);
44196
44347
  await new Promise((resolve) => {
44197
- process5.once("SIGTERM", () => {
44348
+ process6.once("SIGTERM", () => {
44198
44349
  void server.stop().finally(resolve);
44199
44350
  });
44200
- process5.once("SIGINT", () => {
44351
+ process6.once("SIGINT", () => {
44201
44352
  void server.stop().finally(resolve);
44202
44353
  });
44203
44354
  });
@@ -44211,14 +44362,14 @@ function createConsoleDaemonLifecycle(deps = {}) {
44211
44362
  const payload = readTrustedLock();
44212
44363
  if (!payload) return;
44213
44364
  try {
44214
- process5.kill(payload.pid, "SIGTERM");
44365
+ process6.kill(payload.pid, "SIGTERM");
44215
44366
  } catch (err) {
44216
44367
  if (err.code !== "ESRCH") throw err;
44217
44368
  }
44218
44369
  await sleep(200);
44219
44370
  try {
44220
- process5.kill(payload.pid, 0);
44221
- process5.kill(payload.pid, "SIGKILL");
44371
+ process6.kill(payload.pid, 0);
44372
+ process6.kill(payload.pid, "SIGKILL");
44222
44373
  } catch (err) {
44223
44374
  if (err.code !== "ESRCH") throw err;
44224
44375
  }
@@ -44336,51 +44487,55 @@ async function runConsoleRestart(deps = {}) {
44336
44487
  return openFleetConsole({ lifecycle, openBrowser: deps.openBrowser });
44337
44488
  }
44338
44489
  async function main() {
44339
- if (process5.argv[2] === "serve") {
44490
+ if (process6.argv[2] === "serve") {
44340
44491
  await createConsoleDaemonLifecycle().runServer();
44341
44492
  return;
44342
44493
  }
44343
- if (process5.argv[2] === "hook") {
44344
- const hookCommand = parseConsoleHookCommand(process5.argv.slice(3));
44494
+ if (process6.argv[2] === "hook") {
44495
+ const hookCommand = parseConsoleHookCommand(process6.argv.slice(3));
44345
44496
  if (hookCommand.command === "subagents-context") {
44346
- process5.stdout.write(`${runSubagentsContextHook(process5.env)}
44497
+ process6.stdout.write(`${runSubagentsContextHook(process6.env)}
44347
44498
  `);
44348
44499
  return;
44349
44500
  }
44350
- await runCaptureSessionHook(hookCommand.provider, process5.env);
44501
+ if (hookCommand.command === "turn-start" || hookCommand.command === "turn-end") {
44502
+ await runTurnStateHook(hookCommand.command === "turn-start" ? "start" : "end", process6.env);
44503
+ return;
44504
+ }
44505
+ await runCaptureSessionHook(hookCommand.provider, process6.env);
44351
44506
  return;
44352
44507
  }
44353
- if (process5.argv[2] === "codex") {
44354
- await mainWiki(process5.argv.slice(3));
44508
+ if (process6.argv[2] === "codex") {
44509
+ await mainWiki(process6.argv.slice(3));
44355
44510
  return;
44356
44511
  }
44357
- const mode = parseConsoleCliMode(process5.argv.slice(2));
44512
+ const mode = parseConsoleCliMode(process6.argv.slice(2));
44358
44513
  if (mode === "help") {
44359
- process5.stdout.write(`${buildConsoleHelpText({ env: process5.env, isTTY: process5.stdout.isTTY })}
44514
+ process6.stdout.write(`${buildConsoleHelpText({ env: process6.env, isTTY: process6.stdout.isTTY })}
44360
44515
  `);
44361
44516
  return;
44362
44517
  }
44363
44518
  if (mode === "status") {
44364
- process5.stdout.write(`${await runConsoleStatus()}
44519
+ process6.stdout.write(`${await runConsoleStatus()}
44365
44520
  `);
44366
44521
  return;
44367
44522
  }
44368
44523
  if (mode === "stop") {
44369
- process5.stdout.write(`${await runConsoleStop()}
44524
+ process6.stdout.write(`${await runConsoleStop()}
44370
44525
  `);
44371
44526
  return;
44372
44527
  }
44373
44528
  if (mode === "restart") {
44374
44529
  await runConsoleRestart();
44375
- process5.stdout.write("Fleet Console restarted.\n");
44530
+ process6.stdout.write("Fleet Console restarted.\n");
44376
44531
  return;
44377
44532
  }
44378
44533
  await openFleetConsole();
44379
- process5.stdout.write("Fleet Console opened.\n");
44534
+ process6.stdout.write("Fleet Console opened.\n");
44380
44535
  }
44381
- async function mainWiki(argv = process5.argv.slice(2)) {
44536
+ async function mainWiki(argv = process6.argv.slice(2)) {
44382
44537
  if (argv.includes("--help") || argv.includes("-h")) {
44383
- process5.stdout.write(`${buildWikiHelpText({ env: process5.env, isTTY: process5.stdout.isTTY })}
44538
+ process6.stdout.write(`${buildWikiHelpText({ env: process6.env, isTTY: process6.stdout.isTTY })}
44384
44539
  `);
44385
44540
  return;
44386
44541
  }
@@ -44392,19 +44547,19 @@ async function mainWiki(argv = process5.argv.slice(2)) {
44392
44547
  if (unsupported.length > 0) {
44393
44548
  throw new Error(`Unknown fleet wiki option: ${unsupported[0]}`);
44394
44549
  }
44395
- await openFleetWikiWorkspace({ cwd: process5.cwd() });
44550
+ await openFleetWikiWorkspace({ cwd: process6.cwd() });
44396
44551
  }
44397
44552
  function resolveDefaultServerModulePath() {
44398
44553
  const builtPath = new URL("../dist/cli.mjs", import.meta.url).pathname;
44399
44554
  if (fs5__default.existsSync(builtPath)) return builtPath;
44400
44555
  return fileURLToPath(import.meta.url);
44401
44556
  }
44402
- var isDirectRun = process5.argv[1] && path93__default.resolve(process5.argv[1]) === fileURLToPath(import.meta.url);
44557
+ var isDirectRun = process6.argv[1] && path93__default.resolve(process6.argv[1]) === fileURLToPath(import.meta.url);
44403
44558
  if (isDirectRun) {
44404
44559
  await main().catch((error51) => {
44405
- process5.stderr.write(`${error51 instanceof Error ? error51.message : String(error51)}
44560
+ process6.stderr.write(`${error51 instanceof Error ? error51.message : String(error51)}
44406
44561
  `);
44407
- process5.exitCode = 1;
44562
+ process6.exitCode = 1;
44408
44563
  });
44409
44564
  }
44410
44565