@dotobokuri/fleet-console 1.39.0 → 1.40.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 (67) hide show
  1. package/dist/cli.mjs +43 -1090
  2. package/dist/client/assets/{_baseUniq-BDfju2rW.js → _baseUniq-Bao5GOIa.js} +1 -1
  3. package/dist/client/assets/{arc-DWcMv-ui.js → arc-DnhHMLy9.js} +1 -1
  4. package/dist/client/assets/{architectureDiagram-Q4EWVU46-DhPv_Uba.js → architectureDiagram-Q4EWVU46-DAbURr0a.js} +1 -1
  5. package/dist/client/assets/{blockDiagram-DXYQGD6D-D7RYcNDP.js → blockDiagram-DXYQGD6D-DE1raZQ6.js} +1 -1
  6. package/dist/client/assets/{c4Diagram-AHTNJAMY-9_4dQBo3.js → c4Diagram-AHTNJAMY-beLZlUB3.js} +1 -1
  7. package/dist/client/assets/channel-Bn1wyUhs.js +1 -0
  8. package/dist/client/assets/{chunk-4BX2VUAB-CQf5x2mT.js → chunk-4BX2VUAB-DEqdunZS.js} +1 -1
  9. package/dist/client/assets/{chunk-4TB4RGXK-eeG8BKQB.js → chunk-4TB4RGXK-D8i5nx4L.js} +1 -1
  10. package/dist/client/assets/{chunk-55IACEB6-1dkBlsDt.js → chunk-55IACEB6-eM3-fH_e.js} +1 -1
  11. package/dist/client/assets/{chunk-EDXVE4YY-C5vcF-lT.js → chunk-EDXVE4YY-nQoyt_Pd.js} +1 -1
  12. package/dist/client/assets/{chunk-FMBD7UC4-CGelAuwP.js → chunk-FMBD7UC4-D8Wq8CYj.js} +1 -1
  13. package/dist/client/assets/{chunk-OYMX7WX6-CbKgVyop.js → chunk-OYMX7WX6-Cx4Wr2ZT.js} +1 -1
  14. package/dist/client/assets/{chunk-QZHKN3VN-CT0ppG8R.js → chunk-QZHKN3VN-BM2v7Krr.js} +1 -1
  15. package/dist/client/assets/{chunk-YZCP3GAM-BEf8DhxB.js → chunk-YZCP3GAM-zTniPxm7.js} +1 -1
  16. package/dist/client/assets/classDiagram-6PBFFD2Q-DBE3Ix3c.js +1 -0
  17. package/dist/client/assets/classDiagram-v2-HSJHXN6E-DBE3Ix3c.js +1 -0
  18. package/dist/client/assets/clone-COL47Wy_.js +1 -0
  19. package/dist/client/assets/{cose-bilkent-S5V4N54A-C6GtvpYi.js → cose-bilkent-S5V4N54A-B5pl2A_p.js} +1 -1
  20. package/dist/client/assets/{dagre-KV5264BT-DvrU2BgH.js → dagre-KV5264BT-KHPgW9C2.js} +1 -1
  21. package/dist/client/assets/{diagram-5BDNPKRD-Cy1qKKqt.js → diagram-5BDNPKRD-DCv28c7S.js} +1 -1
  22. package/dist/client/assets/{diagram-G4DWMVQ6-C4GGKnnD.js → diagram-G4DWMVQ6-mT5WQ415.js} +1 -1
  23. package/dist/client/assets/{diagram-MMDJMWI5-By7JFsIw.js → diagram-MMDJMWI5-iKYfjiRC.js} +1 -1
  24. package/dist/client/assets/{diagram-TYMM5635-YwzVWpID.js → diagram-TYMM5635-_uqBP7vH.js} +1 -1
  25. package/dist/client/assets/{erDiagram-SMLLAGMA-CDsNlmLk.js → erDiagram-SMLLAGMA-DxNN1WhN.js} +1 -1
  26. package/dist/client/assets/{flowDiagram-DWJPFMVM-BuUpIzTa.js → flowDiagram-DWJPFMVM-DGTsrBvM.js} +1 -1
  27. package/dist/client/assets/{ganttDiagram-T4ZO3ILL-Dqv9t2x8.js → ganttDiagram-T4ZO3ILL-C17hg4lr.js} +1 -1
  28. package/dist/client/assets/{gitGraphDiagram-UUTBAWPF-DApQn2c7.js → gitGraphDiagram-UUTBAWPF-CeJ25hAd.js} +1 -1
  29. package/dist/client/assets/{graph-CyX-IC4n.js → graph-BQvb-BfT.js} +1 -1
  30. package/dist/client/assets/index-Ca6HkGPQ.css +1 -0
  31. package/dist/client/assets/index-Cr3Xq85X.js +452 -0
  32. package/dist/client/assets/{infoDiagram-42DDH7IO-DIf3qelw.js → infoDiagram-42DDH7IO-BctsofOZ.js} +1 -1
  33. package/dist/client/assets/{ishikawaDiagram-UXIWVN3A-CU3QtNdx.js → ishikawaDiagram-UXIWVN3A-PiPmxcg9.js} +1 -1
  34. package/dist/client/assets/{journeyDiagram-VCZTEJTY-Dfq4OBhW.js → journeyDiagram-VCZTEJTY-BwkjYq3n.js} +1 -1
  35. package/dist/client/assets/{kanban-definition-6JOO6SKY-CWSe3eh7.js → kanban-definition-6JOO6SKY-CSV4dYfF.js} +1 -1
  36. package/dist/client/assets/{layout-CfdpDpEB.js → layout-DdReLJnP.js} +1 -1
  37. package/dist/client/assets/{linear-BQA5wLDW.js → linear-B54euy_k.js} +1 -1
  38. package/dist/client/assets/{mermaid.core-BwJS5O4y.js → mermaid.core-CF92I5mT.js} +4 -4
  39. package/dist/client/assets/{min-Cg-Q6TB5.js → min-BcETQ2qJ.js} +1 -1
  40. package/dist/client/assets/{mindmap-definition-QFDTVHPH-BNXT0q7L.js → mindmap-definition-QFDTVHPH-CrmVPycO.js} +1 -1
  41. package/dist/client/assets/{pieDiagram-DEJITSTG-Cot4WNe7.js → pieDiagram-DEJITSTG-B5d4jR0H.js} +1 -1
  42. package/dist/client/assets/{quadrantDiagram-34T5L4WZ-_YW3nZwc.js → quadrantDiagram-34T5L4WZ-DlgCNExa.js} +1 -1
  43. package/dist/client/assets/{requirementDiagram-MS252O5E-didEilrX.js → requirementDiagram-MS252O5E-CeuVib_X.js} +1 -1
  44. package/dist/client/assets/{sankeyDiagram-XADWPNL6-CIpzp5Ep.js → sankeyDiagram-XADWPNL6-Bzxv73ik.js} +1 -1
  45. package/dist/client/assets/{sequenceDiagram-FGHM5R23-CqvwD_CI.js → sequenceDiagram-FGHM5R23-B0Ondg0u.js} +1 -1
  46. package/dist/client/assets/{stateDiagram-FHFEXIEX-D492KgCG.js → stateDiagram-FHFEXIEX-CuNHg5DJ.js} +1 -1
  47. package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-BVPbUfrG.js +1 -0
  48. package/dist/client/assets/{timeline-definition-GMOUNBTQ-BpAwqH0H.js → timeline-definition-GMOUNBTQ-DXcye6z7.js} +1 -1
  49. package/dist/client/assets/{vennDiagram-DHZGUBPP-DDMPO_HG.js → vennDiagram-DHZGUBPP-CL4rbpzL.js} +1 -1
  50. package/dist/client/assets/{wardley-RL74JXVD-TKEj0wFU.js → wardley-RL74JXVD-rVZBTA_R.js} +1 -1
  51. package/dist/client/assets/{wardleyDiagram-NUSXRM2D-CLjBh2KA.js → wardleyDiagram-NUSXRM2D-Cb8Arj1F.js} +1 -1
  52. package/dist/client/assets/{xychartDiagram-5P7HB3ND-DEn2Z9lG.js → xychartDiagram-5P7HB3ND-C-qp4Say.js} +1 -1
  53. package/dist/client/index.html +2 -2
  54. package/dist/client/theme-boot.js +5 -4
  55. package/dist/fleet-plugins/ledger/routes.mjs +0 -33
  56. package/dist/fleet-plugins/quota/routes.mjs +672 -0
  57. package/dist/fleet-plugins/scuttlebutt/routes.mjs +1 -351
  58. package/dist/fleet-plugins/skills/routes.mjs +0 -33
  59. package/dist/fleet-plugins/terminal/routes.mjs +462 -2017
  60. package/package.json +1 -1
  61. package/dist/client/assets/channel-Cjiuj1tM.js +0 -1
  62. package/dist/client/assets/classDiagram-6PBFFD2Q-B-_6FtAZ.js +0 -1
  63. package/dist/client/assets/classDiagram-v2-HSJHXN6E-B-_6FtAZ.js +0 -1
  64. package/dist/client/assets/clone-BF2H_qSP.js +0 -1
  65. package/dist/client/assets/index-RzoF0XVt.js +0 -452
  66. package/dist/client/assets/index-bog2t8Rz.css +0 -1
  67. package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-DUe9CEL6.js +0 -1
package/dist/cli.mjs CHANGED
@@ -993,56 +993,6 @@ function ensureWorkspaceDirectory(dataDir, cwd) {
993
993
  });
994
994
  return workspace;
995
995
  }
996
- function findWorkspaceDirectory(dataDir, cwd) {
997
- const expected = resolveWorkspaceDirectory(dataDir, cwd);
998
- assertSafeWorkspaceRoot(dataDir, expected.root);
999
- const workspaceStat = safeLstat(expected.path);
1000
- if (!workspaceStat) return null;
1001
- if (!workspaceStat.isDirectory() || workspaceStat.isSymbolicLink()) {
1002
- throw new Error(`Workspace directory not found or unsafe: ${expected.name}`);
1003
- }
1004
- const existing = readExistingWorkspaceDirectory(expected.root, expected.name, expected.path);
1005
- if (existing.cwd !== expected.cwd) {
1006
- throw new Error(
1007
- `Workspace directory identity collision for ${expected.name}: expected ${expected.cwd}, found ${existing.cwd}`
1008
- );
1009
- }
1010
- return existing;
1011
- }
1012
- function readExistingWorkspaceDirectory(root, name, workspacePath) {
1013
- const identityPath = path23.join(workspacePath, WORKSPACE_IDENTITY_FILE_NAME);
1014
- const identity2 = readWorkspaceIdentity(identityPath);
1015
- if (!identity2) {
1016
- throw new Error(`Workspace directory identity is missing: ${name}`);
1017
- }
1018
- if (toWorkspaceDirectoryName(identity2.cwd) !== name) {
1019
- throw new Error(`Workspace directory identity does not match its name: ${name}`);
1020
- }
1021
- return {
1022
- cwd: identity2.cwd,
1023
- identityPath,
1024
- name,
1025
- path: workspacePath,
1026
- root
1027
- };
1028
- }
1029
- function assertSafeWorkspaceRoot(dataDir, root, allowMissing) {
1030
- const resolvedDataDir = path23.resolve(dataDir);
1031
- const dataDirStat = safeLstat(resolvedDataDir);
1032
- if (!dataDirStat) {
1033
- return;
1034
- }
1035
- if (!dataDirStat.isDirectory() || dataDirStat.isSymbolicLink()) {
1036
- throw new Error(`Workspace data directory not found or unsafe: ${resolvedDataDir}`);
1037
- }
1038
- const rootStat = safeLstat(root);
1039
- if (!rootStat) {
1040
- return;
1041
- }
1042
- if (!rootStat.isDirectory() || rootStat.isSymbolicLink()) {
1043
- throw new Error(`Workspace directory root not found or unsafe: ${root}`);
1044
- }
1045
- }
1046
996
  function buildWorkspaceDirectory(dataDir, name, cwd) {
1047
997
  assertWorkspaceDirectoryName(name);
1048
998
  const root = getWorkspaceDirectoryRoot(dataDir);
@@ -12164,9 +12114,7 @@ var DESKTOP_TITLE_BAR_OVERLAYS = {
12164
12114
  instrument: { color: "#03080e", symbolColor: "#989fa6", height: 43 },
12165
12115
  maritime: { color: "#041729", symbolColor: "#c8c4b7", height: 43 },
12166
12116
  carbon: { color: "#101215", symbolColor: "#bfc1c3", height: 43 },
12167
- daywatch: { color: "#e6ecf2", symbolColor: "#3e4953", height: 43 },
12168
- whites: { color: "#eef0f3", symbolColor: "#334055", height: 43 },
12169
- drydock: { color: "#ddeaf2", symbolColor: "#30475d", height: 43 }
12117
+ whites: { color: "#f1f0ec", symbolColor: "#424038", height: 43 }
12170
12118
  };
12171
12119
  function desktopThemeSnapshot(theme) {
12172
12120
  return { theme, titleBarOverlay: { ...DESKTOP_TITLE_BAR_OVERLAYS[theme] } };
@@ -12281,7 +12229,7 @@ function readConsoleGeneralSettings(value) {
12281
12229
  const language = value.language === "auto" || value.language === "en" || value.language === "ko" ? value.language : void 0;
12282
12230
  const reducePanelMotion = typeof value.reducePanelMotion === "boolean" ? value.reducePanelMotion : void 0;
12283
12231
  const seenFeatureTours = sanitizeSeenFeatureTours(value.seenFeatureTours);
12284
- const theme = value.theme === "instrument" || value.theme === "maritime" || value.theme === "carbon" || value.theme === "daywatch" || value.theme === "whites" || value.theme === "drydock" ? value.theme : void 0;
12232
+ const theme = value.theme === "instrument" || value.theme === "maritime" || value.theme === "carbon" || value.theme === "whites" ? value.theme : value.theme === "daywatch" || value.theme === "drydock" ? "whites" : void 0;
12285
12233
  const uiFont = sanitizeUiFontSettings(value.uiFont);
12286
12234
  return {
12287
12235
  ...consolePortMode !== void 0 ? { consolePortMode } : {},
@@ -12393,7 +12341,7 @@ async function mutateGlobalSettings(req, res, deps) {
12393
12341
  deps.writeJson(res, 400, { error: "invalid_seen_feature_tours" });
12394
12342
  return;
12395
12343
  }
12396
- if (body2.theme !== void 0 && body2.theme !== "instrument" && body2.theme !== "maritime" && body2.theme !== "carbon" && body2.theme !== "daywatch" && body2.theme !== "whites" && body2.theme !== "drydock") {
12344
+ if (body2.theme !== void 0 && body2.theme !== "instrument" && body2.theme !== "maritime" && body2.theme !== "carbon" && body2.theme !== "whites") {
12397
12345
  deps.writeJson(res, 400, { error: "invalid_theme" });
12398
12346
  return;
12399
12347
  }
@@ -12401,7 +12349,7 @@ async function mutateGlobalSettings(req, res, deps) {
12401
12349
  deps.writeJson(res, 400, { error: "invalid_ui_font" });
12402
12350
  return;
12403
12351
  }
12404
- const theme = body2.theme === "instrument" || body2.theme === "maritime" || body2.theme === "carbon" || body2.theme === "daywatch" || body2.theme === "whites" || body2.theme === "drydock" ? body2.theme : void 0;
12352
+ const theme = body2.theme === "instrument" || body2.theme === "maritime" || body2.theme === "carbon" || body2.theme === "whites" ? body2.theme : void 0;
12405
12353
  const updated = deps.consoleSettingsStore.update((current) => ({
12406
12354
  ...current,
12407
12355
  version: 1,
@@ -13523,10 +13471,10 @@ function mergeDefs(...defs) {
13523
13471
  function cloneDef(schema) {
13524
13472
  return mergeDefs(schema._zod.def);
13525
13473
  }
13526
- function getElementAtPath(obj, path49) {
13527
- if (!path49)
13474
+ function getElementAtPath(obj, path47) {
13475
+ if (!path47)
13528
13476
  return obj;
13529
- return path49.reduce((acc, key) => acc?.[key], obj);
13477
+ return path47.reduce((acc, key) => acc?.[key], obj);
13530
13478
  }
13531
13479
  function promiseAllObject(promisesObj) {
13532
13480
  const keys = Object.keys(promisesObj);
@@ -13935,11 +13883,11 @@ function explicitlyAborted(x, startIndex = 0) {
13935
13883
  }
13936
13884
  return false;
13937
13885
  }
13938
- function prefixIssues(path49, issues) {
13886
+ function prefixIssues(path47, issues) {
13939
13887
  return issues.map((iss) => {
13940
13888
  var _a3;
13941
13889
  (_a3 = iss).path ?? (_a3.path = []);
13942
- iss.path.unshift(path49);
13890
+ iss.path.unshift(path47);
13943
13891
  return iss;
13944
13892
  });
13945
13893
  }
@@ -14086,16 +14034,16 @@ function flattenError(error51, mapper = (issue3) => issue3.message) {
14086
14034
  }
14087
14035
  function formatError(error51, mapper = (issue3) => issue3.message) {
14088
14036
  const fieldErrors = { _errors: [] };
14089
- const processError = (error52, path49 = []) => {
14037
+ const processError = (error52, path47 = []) => {
14090
14038
  for (const issue3 of error52.issues) {
14091
14039
  if (issue3.code === "invalid_union" && issue3.errors.length) {
14092
- issue3.errors.map((issues) => processError({ issues }, [...path49, ...issue3.path]));
14040
+ issue3.errors.map((issues) => processError({ issues }, [...path47, ...issue3.path]));
14093
14041
  } else if (issue3.code === "invalid_key") {
14094
- processError({ issues: issue3.issues }, [...path49, ...issue3.path]);
14042
+ processError({ issues: issue3.issues }, [...path47, ...issue3.path]);
14095
14043
  } else if (issue3.code === "invalid_element") {
14096
- processError({ issues: issue3.issues }, [...path49, ...issue3.path]);
14044
+ processError({ issues: issue3.issues }, [...path47, ...issue3.path]);
14097
14045
  } else {
14098
- const fullpath = [...path49, ...issue3.path];
14046
+ const fullpath = [...path47, ...issue3.path];
14099
14047
  if (fullpath.length === 0) {
14100
14048
  fieldErrors._errors.push(mapper(issue3));
14101
14049
  } else {
@@ -14122,17 +14070,17 @@ function formatError(error51, mapper = (issue3) => issue3.message) {
14122
14070
  }
14123
14071
  function treeifyError(error51, mapper = (issue3) => issue3.message) {
14124
14072
  const result = { errors: [] };
14125
- const processError = (error52, path49 = []) => {
14073
+ const processError = (error52, path47 = []) => {
14126
14074
  var _a3, _b;
14127
14075
  for (const issue3 of error52.issues) {
14128
14076
  if (issue3.code === "invalid_union" && issue3.errors.length) {
14129
- issue3.errors.map((issues) => processError({ issues }, [...path49, ...issue3.path]));
14077
+ issue3.errors.map((issues) => processError({ issues }, [...path47, ...issue3.path]));
14130
14078
  } else if (issue3.code === "invalid_key") {
14131
- processError({ issues: issue3.issues }, [...path49, ...issue3.path]);
14079
+ processError({ issues: issue3.issues }, [...path47, ...issue3.path]);
14132
14080
  } else if (issue3.code === "invalid_element") {
14133
- processError({ issues: issue3.issues }, [...path49, ...issue3.path]);
14081
+ processError({ issues: issue3.issues }, [...path47, ...issue3.path]);
14134
14082
  } else {
14135
- const fullpath = [...path49, ...issue3.path];
14083
+ const fullpath = [...path47, ...issue3.path];
14136
14084
  if (fullpath.length === 0) {
14137
14085
  result.errors.push(mapper(issue3));
14138
14086
  continue;
@@ -14164,8 +14112,8 @@ function treeifyError(error51, mapper = (issue3) => issue3.message) {
14164
14112
  }
14165
14113
  function toDotPath(_path) {
14166
14114
  const segs = [];
14167
- const path49 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
14168
- for (const seg of path49) {
14115
+ const path47 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
14116
+ for (const seg of path47) {
14169
14117
  if (typeof seg === "number")
14170
14118
  segs.push(`[${seg}]`);
14171
14119
  else if (typeof seg === "symbol")
@@ -26829,13 +26777,13 @@ function resolveRef(ref, ctx) {
26829
26777
  if (!ref.startsWith("#")) {
26830
26778
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
26831
26779
  }
26832
- const path49 = ref.slice(1).split("/").filter(Boolean);
26833
- if (path49.length === 0) {
26780
+ const path47 = ref.slice(1).split("/").filter(Boolean);
26781
+ if (path47.length === 0) {
26834
26782
  return ctx.rootSchema;
26835
26783
  }
26836
26784
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
26837
- if (path49[0] === defsKey) {
26838
- const key = path49[1];
26785
+ if (path47[0] === defsKey) {
26786
+ const key = path47[1];
26839
26787
  if (!key || !ctx.defs[key]) {
26840
26788
  throw new Error(`Reference not found: ${ref}`);
26841
26789
  }
@@ -32036,23 +31984,6 @@ var models_default = {
32036
31984
  { modelId: "gpt-5.5-fast", name: "GPT-5.5 Fast", providerModelId: "gpt-5.5", serviceTier: "priority", effort: { supported: true, levels: ["low", "medium", "high", "xhigh"], default: "high" } }
32037
31985
  ]
32038
31986
  },
32039
- "opencode-go": {
32040
- name: "OpenCode Go",
32041
- defaultModel: "opencode-go/deepseek-v4-flash",
32042
- models: [
32043
- { modelId: "opencode-go/deepseek-v4-flash", name: "DeepSeek V4 Flash", effort: { supported: false } },
32044
- { modelId: "opencode-go/deepseek-v4-pro", name: "DeepSeek V4 Pro", effort: { supported: false } },
32045
- { modelId: "opencode-go/glm-5.2", name: "GLM-5.2", effort: { supported: false } },
32046
- { modelId: "opencode-go/grok-4.5", name: "Grok 4.5", effort: { supported: false } },
32047
- { modelId: "opencode-go/kimi-k3", name: "Kimi K3", effort: { supported: false } },
32048
- { modelId: "opencode-go/kimi-k2.7-code", name: "Kimi K2.7 Code", effort: { supported: false } },
32049
- { modelId: "opencode-go/mimo-v2.5", name: "MiMo V2.5", effort: { supported: false } },
32050
- { modelId: "opencode-go/mimo-v2.5-pro", name: "MiMo V2.5 Pro", effort: { supported: false } },
32051
- { modelId: "opencode-go/minimax-m3", name: "MiniMax M3", effort: { supported: false } },
32052
- { modelId: "opencode-go/qwen3.7-max", name: "Qwen3.7 Max", effort: { supported: false } },
32053
- { modelId: "opencode-go/qwen3.7-plus", name: "Qwen3.7 Plus", effort: { supported: false } }
32054
- ]
32055
- },
32056
31987
  cursor: {
32057
31988
  name: "Cursor Agent",
32058
31989
  defaultModel: "auto",
@@ -32314,22 +32245,6 @@ var CLI_BACKENDS = {
32314
32245
  usesNpxBridge: false,
32315
32246
  defaultMaxTokens: 1e5
32316
32247
  },
32317
- "opencode-go": {
32318
- id: "opencode-go",
32319
- cliCommand: "opencode",
32320
- protocol: "acp",
32321
- authRequired: false,
32322
- acpArgs: ["acp"],
32323
- modes: [
32324
- { id: "build", label: "Build" },
32325
- { id: "plan", label: "Plan" }
32326
- ],
32327
- supportsSessionClose: true,
32328
- supportsSessionLoad: true,
32329
- requiresModelAtSpawn: true,
32330
- usesNpxBridge: false,
32331
- defaultMaxTokens: 128e3
32332
- },
32333
32248
  cursor: {
32334
32249
  id: "cursor",
32335
32250
  cliCommand: "cursor-agent",
@@ -32391,8 +32306,6 @@ function getYoloModeId(cli) {
32391
32306
  case "claude":
32392
32307
  case "claude-kimi":
32393
32308
  return "bypassPermissions";
32394
- case "opencode-go":
32395
- return "build";
32396
32309
  case "cursor":
32397
32310
  return "agent";
32398
32311
  case "codex":
@@ -34795,319 +34708,6 @@ var UnifiedCursorAgentClient = class extends EventEmitter {
34795
34708
  return patterns.some((pattern) => pattern.test(text));
34796
34709
  }
34797
34710
  };
34798
- var UnifiedOpenCodeAgentClient = class _UnifiedOpenCodeAgentClient extends EventEmitter {
34799
- providerId;
34800
- connection = null;
34801
- sessionId = null;
34802
- sessionCwd = null;
34803
- currentSystemPrompt = null;
34804
- /** 첫 프롬프트 전송 시 systemPrompt를 텍스트 블록으로 앞에 붙이기 위한 플래그 */
34805
- firstPromptPending = null;
34806
- detector = new CliDetector();
34807
- constructor(providerId) {
34808
- super();
34809
- this.providerId = providerId;
34810
- }
34811
- on(event, listener) {
34812
- return super.on(event, listener);
34813
- }
34814
- once(event, listener) {
34815
- return super.once(event, listener);
34816
- }
34817
- off(event, listener) {
34818
- return super.off(event, listener);
34819
- }
34820
- emitTyped(event, ...args) {
34821
- return super.emit(event, ...args);
34822
- }
34823
- async connect(options) {
34824
- await this.disconnect();
34825
- if (options.cli && options.cli !== this.providerId) {
34826
- throw new Error(`UnifiedOpenCodeAgentClient\uB294 ${this.providerId} CLI\uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4.`);
34827
- }
34828
- const acpMcpServers = this.resolveMcpServers(options.mcpServers);
34829
- const spawnConfig = createSpawnConfig(this.providerId, options);
34830
- const cleanEnv = cleanEnvironment(process.env, options.env);
34831
- cleanEnv.OPENCODE_CONFIG_CONTENT = JSON.stringify({
34832
- agent: {
34833
- explore: { disable: true },
34834
- plan: { disable: true },
34835
- general: { disable: true }
34836
- }
34837
- });
34838
- const connection = new AcpConnection({
34839
- command: spawnConfig.command,
34840
- args: spawnConfig.args,
34841
- cliType: this.providerId,
34842
- cwd: options.cwd,
34843
- env: cleanEnv,
34844
- requestTimeout: options.timeout,
34845
- initTimeout: options.timeout,
34846
- promptIdleTimeout: options.promptIdleTimeout,
34847
- clientInfo: options.clientInfo,
34848
- autoApprove: options.autoApprove,
34849
- fsAccess: options.fsAccess
34850
- });
34851
- this.connection = connection;
34852
- this.setupEventForwarding();
34853
- const recentLogs = [];
34854
- const collectLog = (message) => {
34855
- recentLogs.push(message);
34856
- if (recentLogs.length > 30) {
34857
- recentLogs.shift();
34858
- }
34859
- };
34860
- connection.on("log", collectLog);
34861
- let session;
34862
- try {
34863
- session = await connection.connect(
34864
- options.cwd,
34865
- options.sessionId,
34866
- acpMcpServers,
34867
- void 0
34868
- );
34869
- } catch (error51) {
34870
- const connectionError = this.buildConnectionError(error51, recentLogs);
34871
- await this.cleanupFailedConnection();
34872
- throw connectionError;
34873
- } finally {
34874
- connection.off("log", collectLog);
34875
- }
34876
- return this.finalizeConnect(options, session);
34877
- }
34878
- async disconnect() {
34879
- if (!this.connection) {
34880
- this.clearSessionState();
34881
- return;
34882
- }
34883
- const conn = this.connection;
34884
- await conn.disconnect();
34885
- conn.removeAllListeners();
34886
- this.connection = null;
34887
- this.clearSessionState();
34888
- }
34889
- async endSession() {
34890
- if (!this.connection || !this.sessionId) {
34891
- throw new Error("\uC5F0\uACB0\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
34892
- }
34893
- await this.connection.endSession(this.sessionId);
34894
- this.sessionId = null;
34895
- }
34896
- getConnectionInfo() {
34897
- return {
34898
- cli: this.connection ? this.providerId : null,
34899
- protocol: this.connection ? "acp" : null,
34900
- sessionId: this.sessionId,
34901
- state: this.connection ? this.connection.connectionState : "disconnected"
34902
- };
34903
- }
34904
- async detectClis() {
34905
- return this.detector.detectAll(true);
34906
- }
34907
- async sendMessage(content) {
34908
- if (!this.connection || !this.sessionId) {
34909
- throw new Error("\uC5F0\uACB0\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
34910
- }
34911
- const systemPrompt = this.firstPromptPending;
34912
- if (!systemPrompt) {
34913
- return this.connection.sendPrompt(this.sessionId, content);
34914
- }
34915
- const userBlocks = typeof content === "string" ? [{ type: "text", text: content }] : content;
34916
- const response = await this.connection.sendPrompt(this.sessionId, [
34917
- { type: "text", text: systemPrompt },
34918
- ...userBlocks
34919
- ]);
34920
- this.firstPromptPending = null;
34921
- return response;
34922
- }
34923
- async cancelPrompt() {
34924
- if (!this.connection || !this.sessionId) {
34925
- throw new Error("\uC5F0\uACB0\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
34926
- }
34927
- await this.connection.cancelSession(this.sessionId);
34928
- }
34929
- async setModel(model) {
34930
- if (!this.connection || !this.sessionId) {
34931
- throw new Error("\uC5F0\uACB0\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
34932
- }
34933
- await this.connection.setModel(this.sessionId, model);
34934
- }
34935
- async setConfigOption(configId, value) {
34936
- if (!this.connection || !this.sessionId) {
34937
- throw new Error("\uC5F0\uACB0\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
34938
- }
34939
- await this.connection.setConfigOption(this.sessionId, configId, value);
34940
- }
34941
- async setMode(mode) {
34942
- if (!this.connection || !this.sessionId) {
34943
- throw new Error("\uC5F0\uACB0\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
34944
- }
34945
- await this.connection.setMode(this.sessionId, mode);
34946
- }
34947
- async setYoloMode(enabled) {
34948
- return this.setMode(enabled ? getYoloModeId(this.providerId) : "plan");
34949
- }
34950
- getAvailableModes() {
34951
- return getBackendConfig(this.providerId).modes ?? [];
34952
- }
34953
- getAvailableModels() {
34954
- return getProviderModels(this.providerId);
34955
- }
34956
- getCurrentSystemPrompt() {
34957
- return this.currentSystemPrompt;
34958
- }
34959
- async loadSession(sessionId, mcpServers) {
34960
- if (!this.connection) {
34961
- throw new Error("\uC5F0\uACB0\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
34962
- }
34963
- await this.connection.loadSession({
34964
- sessionId,
34965
- cwd: this.sessionCwd ?? process.cwd(),
34966
- mcpServers: this.resolveMcpServers(mcpServers)
34967
- });
34968
- this.sessionId = sessionId;
34969
- this.currentSystemPrompt = null;
34970
- this.firstPromptPending = null;
34971
- }
34972
- async resetSession(cwd) {
34973
- if (!this.connection) {
34974
- throw new Error("\uC5F0\uACB0\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
34975
- }
34976
- const targetCwd = cwd ?? this.sessionCwd ?? process.cwd();
34977
- await this.disconnect();
34978
- const newClient = new _UnifiedOpenCodeAgentClient(this.providerId);
34979
- const result = await newClient.connect({
34980
- cwd: targetCwd,
34981
- autoApprove: true,
34982
- systemPrompt: this.currentSystemPrompt ?? void 0
34983
- });
34984
- this.connection = newClient.connection;
34985
- this.sessionId = newClient.sessionId;
34986
- this.sessionCwd = newClient.sessionCwd;
34987
- this.currentSystemPrompt = newClient.currentSystemPrompt;
34988
- this.firstPromptPending = newClient.firstPromptPending;
34989
- this.setupEventForwarding();
34990
- newClient.removeAllListeners();
34991
- return {
34992
- cli: this.providerId,
34993
- protocol: "acp",
34994
- session: result.session
34995
- };
34996
- }
34997
- resolveMcpServers(servers) {
34998
- return servers?.length ? mcpServerConfigsToAcp(servers) : [];
34999
- }
35000
- async finalizeConnect(options, session) {
35001
- if (options.yoloMode && session.sessionId) {
35002
- try {
35003
- await this.connection.setMode(session.sessionId, getYoloModeId(this.providerId));
35004
- } catch {
35005
- }
35006
- }
35007
- if (options.model && session.sessionId) {
35008
- try {
35009
- await this.connection.setModel(session.sessionId, options.model);
35010
- } catch {
35011
- }
35012
- }
35013
- this.sessionId = session.sessionId;
35014
- this.sessionCwd = options.cwd;
35015
- this.currentSystemPrompt = options.systemPrompt ?? null;
35016
- this.firstPromptPending = options.sessionId ? null : this.currentSystemPrompt;
35017
- return {
35018
- cli: this.providerId,
35019
- protocol: "acp",
35020
- session
35021
- };
35022
- }
35023
- clearSessionState() {
35024
- this.sessionId = null;
35025
- this.sessionCwd = null;
35026
- this.currentSystemPrompt = null;
35027
- this.firstPromptPending = null;
35028
- }
35029
- setupEventForwarding() {
35030
- if (!this.connection) return;
35031
- this.connection.on("stateChange", (state) => {
35032
- this.emitTyped("stateChange", state);
35033
- });
35034
- this.connection.on("userMessageChunk", (text, sessionId) => {
35035
- this.emitTyped("userMessageChunk", text, sessionId);
35036
- });
35037
- this.connection.on("messageChunk", (text, sessionId) => {
35038
- this.emitTyped("messageChunk", text, sessionId);
35039
- });
35040
- this.connection.on("thoughtChunk", (text, sessionId) => {
35041
- this.emitTyped("thoughtChunk", text, sessionId);
35042
- });
35043
- this.connection.on("toolCall", (title, status, sessionId, data) => {
35044
- this.emitTyped("toolCall", title, status, sessionId, data);
35045
- });
35046
- this.connection.on("toolCallUpdate", (title, status, sessionId, data) => {
35047
- this.emitTyped("toolCallUpdate", title, status, sessionId, data);
35048
- });
35049
- this.connection.on("plan", (plan, sessionId) => {
35050
- this.emitTyped("plan", plan, sessionId);
35051
- });
35052
- this.connection.on("availableCommandsUpdate", (commands, sessionId) => {
35053
- this.emitTyped("availableCommandsUpdate", commands, sessionId);
35054
- });
35055
- this.connection.on("sessionUpdate", (update) => {
35056
- this.emitTyped("sessionUpdate", update);
35057
- });
35058
- this.connection.on("permissionRequest", (params, resolve3) => {
35059
- this.emitTyped("permissionRequest", params, resolve3);
35060
- });
35061
- this.connection.on("fileRead", (params, resolve3) => {
35062
- this.emitTyped("fileRead", params, resolve3);
35063
- });
35064
- this.connection.on("fileWrite", (params, resolve3) => {
35065
- this.emitTyped("fileWrite", params, resolve3);
35066
- });
35067
- this.connection.on("promptComplete", (sessionId) => {
35068
- this.emitTyped("promptComplete", sessionId);
35069
- });
35070
- this.connection.on("error", (err) => {
35071
- this.emitTyped("error", err);
35072
- });
35073
- this.connection.on("exit", (code, signal) => {
35074
- this.emitTyped("exit", code, signal);
35075
- });
35076
- this.connection.on("log", (msg) => {
35077
- this.emitTyped("log", msg);
35078
- });
35079
- this.connection.on("logEntry", (entry) => {
35080
- this.emitTyped("logEntry", entry);
35081
- });
35082
- }
35083
- async cleanupFailedConnection() {
35084
- if (!this.connection) {
35085
- return;
35086
- }
35087
- try {
35088
- await this.connection.disconnect();
35089
- } catch {
35090
- }
35091
- this.connection.removeAllListeners();
35092
- this.connection = null;
35093
- this.clearSessionState();
35094
- }
35095
- buildConnectionError(error51, _recentLogs) {
35096
- if (error51 instanceof Error) {
35097
- return error51;
35098
- }
35099
- if (typeof error51 === "object" && error51 !== null) {
35100
- const obj = error51;
35101
- if (typeof obj.message === "string") {
35102
- const code = typeof obj.code === "number" ? ` (code: ${obj.code})` : "";
35103
- const data = obj.data ? ` \u2014 ${JSON.stringify(obj.data)}` : "";
35104
- return new Error(`${obj.message}${code}${data}`);
35105
- }
35106
- return new Error(JSON.stringify(error51));
35107
- }
35108
- return new Error(String(error51));
35109
- }
35110
- };
35111
34711
 
35112
34712
  // ../../packages/core-unified-agent/src/client/UnifiedAgent.ts
35113
34713
  var UnifiedAgent = {
@@ -35118,8 +34718,6 @@ var UnifiedAgent = {
35118
34718
  return new UnifiedClaudeAgentClient(cli);
35119
34719
  case "codex":
35120
34720
  return new UnifiedCodexAgentClient();
35121
- case "opencode-go":
35122
- return new UnifiedOpenCodeAgentClient("opencode-go");
35123
34721
  case "cursor":
35124
34722
  return new UnifiedCursorAgentClient();
35125
34723
  }
@@ -35134,7 +34732,7 @@ var UnifiedAgent = {
35134
34732
  const preferred = await new CliDetector().getPreferred();
35135
34733
  if (!preferred) {
35136
34734
  throw new Error(
35137
- "\uC0AC\uC6A9 \uAC00\uB2A5\uD55C CLI\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. claude, claude-kimi, codex, opencode-go, cursor \uC911 \uD558\uB098\uB97C \uC124\uCE58\uD574\uC8FC\uC138\uC694."
34735
+ "\uC0AC\uC6A9 \uAC00\uB2A5\uD55C CLI\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. claude, claude-kimi, codex, cursor \uC911 \uD558\uB098\uB97C \uC124\uCE58\uD574\uC8FC\uC138\uC694."
35138
34736
  );
35139
34737
  }
35140
34738
  return this.createClient(preferred.cli);
@@ -36115,11 +35713,6 @@ var CoworkStore = class {
36115
35713
  function hash2(value) {
36116
35714
  return crypto2.createHash("sha256").update(value).digest("hex");
36117
35715
  }
36118
-
36119
- // ../../packages/core-agent/src/types.ts
36120
- function snapshotAgentServerBindings(bindings) {
36121
- return bindings === void 0 ? void 0 : Object.freeze({ ...bindings });
36122
- }
36123
35716
  function specToMcpTool(spec) {
36124
35717
  return {
36125
35718
  name: spec.id,
@@ -36134,8 +35727,7 @@ function installExecutorToolCallRouter(runtime, sessionToken, ctx) {
36134
35727
  cwd: ctx.cwd,
36135
35728
  sessionLabel: ctx.sessionLabel,
36136
35729
  toolCallId,
36137
- signal: ctx.signal,
36138
- serverBindings: ctx.serverBindings
35730
+ signal: ctx.signal
36139
35731
  }).then((result) => runtime.server.resolveNextToolCall(sessionToken, toolCallId, result)).catch((err) => {
36140
35732
  runtime.server.resolveNextToolCall(sessionToken, toolCallId, {
36141
35733
  content: [{ type: "text", text: err instanceof Error ? err.message : String(err) }],
@@ -36223,8 +35815,7 @@ function createMcpToolRegistry() {
36223
35815
  cwd: ctx?.cwd ?? process.cwd(),
36224
35816
  sessionLabel: ctx?.sessionLabel,
36225
35817
  toolCallId: ctx?.toolCallId,
36226
- signal: ctx?.signal,
36227
- serverBindings: ctx?.serverBindings
35818
+ signal: ctx?.signal
36228
35819
  };
36229
35820
  const spec = primaryToolSpecs.get(name);
36230
35821
  if (!spec) {
@@ -36785,12 +36376,10 @@ function createExecutorMcpSession(deps, toolTimeoutSeconds, request) {
36785
36376
  }
36786
36377
  assertNonEmptyExecutorTools(request.serverName, request.specs);
36787
36378
  const token = crypto2.randomUUID();
36788
- const serverBindings = snapshotAgentServerBindings(request.serverBindings);
36789
36379
  registerExecutorSessionTools(runtime.runtime, token, [...request.specs]);
36790
36380
  installExecutorToolCallRouter(runtime.runtime, token, {
36791
36381
  cwd,
36792
- signal: request.signal,
36793
- serverBindings
36382
+ signal: request.signal
36794
36383
  });
36795
36384
  return runtime.runtime.server.start().then((url2) => ({
36796
36385
  serverName: request.serverName,
@@ -36820,7 +36409,6 @@ function issueSessionToken(deps, sessionTokensByLabel, request) {
36820
36409
  cleanupExecutorServerTokens(deps, previous.tokens);
36821
36410
  }
36822
36411
  const tokens = [];
36823
- const serverBindings = snapshotAgentServerBindings(request.serverBindings);
36824
36412
  try {
36825
36413
  for (const { name, runtime } of deps.runtimes) {
36826
36414
  const tools = runtime.registry.getAllAgentTools();
@@ -36830,8 +36418,7 @@ function issueSessionToken(deps, sessionTokensByLabel, request) {
36830
36418
  installExecutorToolCallRouter(runtime, token, {
36831
36419
  cwd,
36832
36420
  sessionLabel: label,
36833
- signal: request.signal,
36834
- serverBindings
36421
+ signal: request.signal
36835
36422
  });
36836
36423
  tokens.push({ name, token });
36837
36424
  }
@@ -36842,8 +36429,7 @@ function issueSessionToken(deps, sessionTokensByLabel, request) {
36842
36429
  sessionTokensByLabel.set(label, {
36843
36430
  tokens,
36844
36431
  cwd,
36845
- signal: request.signal,
36846
- serverBindings
36432
+ signal: request.signal
36847
36433
  });
36848
36434
  return tokens;
36849
36435
  }
@@ -38830,573 +38416,6 @@ function sanitizeReplacementNodes(nextNodes) {
38830
38416
  return result;
38831
38417
  }
38832
38418
 
38833
- // core/host/plans/plan-parse.ts
38834
- var TITLE_PATTERN = /^#\s+(.+)$/;
38835
- var EXECUTION_MODE_PATTERN = /^-\s*Execution mode:\s*(sequential|parallel)\b/i;
38836
- var WAVE_PATTERN = /^##\s+wave\s+(\d+)\b/i;
38837
- var LANE_PATTERN = /^###\s+lane\s+(.+)$/i;
38838
- var LANE_ID_PATTERN = /^(W\d+-[A-Za-z0-9]+)\b/i;
38839
- var LANE_BOUNDARY_PATTERN = /^#{1,3}\s/;
38840
- var SECTION_HEADING_PATTERN = /^#{1,2}\s/;
38841
- var CHECKBOX_PATTERN = /^\s*-\s*\[( |x|X)\]/;
38842
- var FENCE_PATTERN = /^\s*(`{3,}|~{3,})/;
38843
- var CLOSING_FENCE_PATTERN = /^\s*(`{3,}|~{3,})\s*$/;
38844
- var TEMPLATE_SECTION_TITLES = /* @__PURE__ */ new Set([
38845
- "objective",
38846
- "file ownership",
38847
- "waves",
38848
- "qa gates",
38849
- "acceptance criteria",
38850
- "documentation updates",
38851
- "final review loop"
38852
- ]);
38853
- function parsePlan(content) {
38854
- const lines = scanPlanLines(content.split(/\r?\n/));
38855
- const title = findTitle(lines);
38856
- const executionMode = findExecutionMode(lines);
38857
- const waveStarts = findWaveStarts(lines);
38858
- const waves = waveStarts.map(({ index, heading, lineIndex }, waveIndex) => {
38859
- const nextWaveLineIndex = waveStarts[waveIndex + 1]?.lineIndex ?? lines.length;
38860
- const endLineIndex = findSectionEnd(lines, lineIndex + 1, nextWaveLineIndex);
38861
- const waveLines = lines.slice(lineIndex + 1, endLineIndex);
38862
- const counts = countTasks(waveLines);
38863
- return { index, heading, lanes: findLanes(waveLines), ...counts };
38864
- });
38865
- return { title, executionMode, waves, ...countTasks(lines) };
38866
- }
38867
- function scanPlanLines(lines) {
38868
- let activeFence = null;
38869
- return lines.map((text) => {
38870
- if (activeFence !== null) {
38871
- const closer = CLOSING_FENCE_PATTERN.exec(text)?.[1];
38872
- if (closer !== void 0 && closer.startsWith(activeFence.char) && closer.length >= activeFence.length) {
38873
- activeFence = null;
38874
- }
38875
- return { text, isFenced: true };
38876
- }
38877
- const marker = FENCE_PATTERN.exec(text)?.[1];
38878
- if (marker !== void 0) {
38879
- activeFence = { char: marker[0] ?? "`", length: marker.length };
38880
- return { text, isFenced: true };
38881
- }
38882
- return { text, isFenced: false };
38883
- });
38884
- }
38885
- function findTitle(lines) {
38886
- for (const line of lines) {
38887
- if (line.isFenced) continue;
38888
- const match = TITLE_PATTERN.exec(line.text);
38889
- if (!match?.[1]) continue;
38890
- const heading = match[1].trim();
38891
- if (TEMPLATE_SECTION_TITLES.has(heading.toLowerCase())) return null;
38892
- return heading;
38893
- }
38894
- return null;
38895
- }
38896
- function findExecutionMode(lines) {
38897
- for (const line of lines) {
38898
- if (line.isFenced) continue;
38899
- const match = EXECUTION_MODE_PATTERN.exec(line.text.trim());
38900
- if (match?.[1]) return match[1].toLowerCase();
38901
- }
38902
- return null;
38903
- }
38904
- function findWaveStarts(lines) {
38905
- const waves = [];
38906
- for (const [lineIndex, line] of lines.entries()) {
38907
- if (line.isFenced) continue;
38908
- const match = WAVE_PATTERN.exec(line.text);
38909
- if (!match?.[1]) continue;
38910
- waves.push({
38911
- index: Number(match[1]),
38912
- heading: line.text.replace(/^##\s+/, ""),
38913
- lineIndex
38914
- });
38915
- }
38916
- return waves;
38917
- }
38918
- function findLanes(waveLines) {
38919
- const laneStarts = [];
38920
- for (const [lineIndex, line] of waveLines.entries()) {
38921
- if (line.isFenced) continue;
38922
- const match = LANE_PATTERN.exec(line.text);
38923
- if (!match?.[1]) continue;
38924
- const heading = match[1].trim();
38925
- laneStarts.push({ heading, id: LANE_ID_PATTERN.exec(heading)?.[1]?.toUpperCase() ?? null, lineIndex });
38926
- }
38927
- return laneStarts.map(({ heading, id, lineIndex }, laneIndex) => {
38928
- const nextLaneLineIndex = laneStarts[laneIndex + 1]?.lineIndex ?? waveLines.length;
38929
- let endLineIndex = nextLaneLineIndex;
38930
- for (let cursor = lineIndex + 1; cursor < nextLaneLineIndex; cursor++) {
38931
- const line = waveLines[cursor];
38932
- if (!line?.isFenced && LANE_BOUNDARY_PATTERN.test(line?.text ?? "")) {
38933
- endLineIndex = cursor;
38934
- break;
38935
- }
38936
- }
38937
- return { id, heading, ...countTasks(waveLines.slice(lineIndex + 1, endLineIndex)) };
38938
- });
38939
- }
38940
- function findSectionEnd(lines, startLineIndex, maxLineIndex) {
38941
- for (let lineIndex = startLineIndex; lineIndex < maxLineIndex; lineIndex++) {
38942
- const line = lines[lineIndex];
38943
- if (!line?.isFenced && SECTION_HEADING_PATTERN.test(line?.text ?? "")) return lineIndex;
38944
- }
38945
- return maxLineIndex;
38946
- }
38947
- function countTasks(lines) {
38948
- let tasksDone = 0;
38949
- let tasksTotal = 0;
38950
- for (const line of lines) {
38951
- if (line.isFenced) continue;
38952
- const match = CHECKBOX_PATTERN.exec(line.text);
38953
- if (!match) continue;
38954
- tasksTotal++;
38955
- if (match[1] === "x" || match[1] === "X") tasksDone++;
38956
- }
38957
- return { tasksDone, tasksTotal };
38958
- }
38959
-
38960
- // core/host/plans/plan-store.ts
38961
- var PLANS_DIRECTORY_NAME = "plans";
38962
- var MARKDOWN_EXTENSION = ".md";
38963
- var PLAN_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*\.md$/;
38964
- var LIST_READ_CONCURRENCY = 16;
38965
- var PLAN_READ_SIZE_CAP = 2 * 1024 * 1024;
38966
- var PlanStoreError = class extends Error {
38967
- code;
38968
- constructor(code) {
38969
- super(code);
38970
- this.name = "PlanStoreError";
38971
- this.code = code;
38972
- }
38973
- };
38974
- async function listPlansForWorkspace(dataDir, cwd) {
38975
- const plansRoot = resolvePlansRoot(dataDir, cwd, true);
38976
- if (plansRoot === null) return [];
38977
- let entries;
38978
- try {
38979
- entries = await fs10__default.promises.readdir(plansRoot.plansPath, { withFileTypes: true });
38980
- } catch (error51) {
38981
- throw toPlanStoreError(error51);
38982
- }
38983
- const names = entries.filter((entry) => (entry.isFile() || entry.isSymbolicLink()) && entry.name.endsWith(MARKDOWN_EXTENSION) && isValidPlanName(entry.name)).map((entry) => entry.name);
38984
- const plans = [];
38985
- for (let startIndex = 0; startIndex < names.length; startIndex += LIST_READ_CONCURRENCY) {
38986
- const chunk = names.slice(startIndex, startIndex + LIST_READ_CONCURRENCY);
38987
- const results = await Promise.all(chunk.map((name) => toPlanListItem(plansRoot, name).catch(() => null)));
38988
- plans.push(...results.filter((plan) => plan !== null));
38989
- }
38990
- return plans.sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
38991
- }
38992
- function resolvePlansWatchDirectory(dataDir, cwd) {
38993
- return resolvePlansRoot(dataDir, cwd, true)?.plansPath ?? null;
38994
- }
38995
- function isValidPlanName(name) {
38996
- return PLAN_NAME_PATTERN.test(name) && !name.includes("..");
38997
- }
38998
- async function readPlanForWorkspace(dataDir, cwd, name) {
38999
- const plansRoot = resolvePlansRoot(dataDir, cwd, false);
39000
- if (plansRoot === null) throw new PlanStoreError("not_found");
39001
- const file2 = await resolvePlanFile(plansRoot, name);
39002
- if (file2.stat.size > PLAN_READ_SIZE_CAP) throw new PlanStoreError("too_large");
39003
- let content;
39004
- try {
39005
- content = await fs10__default.promises.readFile(file2.path, "utf8");
39006
- } catch (error51) {
39007
- throw toPlanStoreError(error51);
39008
- }
39009
- const parsed = parsePlan(content);
39010
- return {
39011
- name,
39012
- title: parsed.title ?? name,
39013
- executionMode: parsed.executionMode,
39014
- updatedAt: file2.stat.mtime.toISOString(),
39015
- content,
39016
- waves: parsed.waves,
39017
- tasksDone: parsed.tasksDone,
39018
- tasksTotal: parsed.tasksTotal
39019
- };
39020
- }
39021
- async function deletePlanForWorkspace(dataDir, cwd, name) {
39022
- const plansRoot = resolvePlansRoot(dataDir, cwd, false);
39023
- if (plansRoot === null) throw new PlanStoreError("not_found");
39024
- const file2 = await resolvePlanFile(plansRoot, name);
39025
- try {
39026
- await fs10__default.promises.unlink(file2.path);
39027
- } catch (error51) {
39028
- throw toPlanStoreError(error51);
39029
- }
39030
- }
39031
- async function toPlanListItem(plansRoot, name) {
39032
- const file2 = await resolvePlanFile(plansRoot, name);
39033
- if (file2.stat.size > PLAN_READ_SIZE_CAP) {
39034
- return {
39035
- name,
39036
- title: name,
39037
- executionMode: null,
39038
- waveCount: 0,
39039
- tasksDone: 0,
39040
- tasksTotal: 0,
39041
- updatedAt: file2.stat.mtime.toISOString(),
39042
- sizeBytes: file2.stat.size
39043
- };
39044
- }
39045
- const content = await fs10__default.promises.readFile(file2.path, "utf8").catch((error51) => {
39046
- throw toPlanStoreError(error51);
39047
- });
39048
- const parsed = parsePlan(content);
39049
- return {
39050
- name,
39051
- title: parsed.title ?? name,
39052
- executionMode: parsed.executionMode,
39053
- waveCount: parsed.waves.length,
39054
- tasksDone: parsed.tasksDone,
39055
- tasksTotal: parsed.tasksTotal,
39056
- updatedAt: file2.stat.mtime.toISOString(),
39057
- sizeBytes: file2.stat.size
39058
- };
39059
- }
39060
- function resolvePlansRoot(dataDir, cwd, allowMissing) {
39061
- let workspace;
39062
- try {
39063
- workspace = findWorkspaceDirectory(dataDir, cwd);
39064
- } catch {
39065
- throw new PlanStoreError("unsafe_path");
39066
- }
39067
- if (!workspace) {
39068
- if (allowMissing) return null;
39069
- throw new PlanStoreError("not_found");
39070
- }
39071
- const plansPath = path23__default.join(workspace.path, PLANS_DIRECTORY_NAME);
39072
- assertWithinRoot(workspace.path, plansPath);
39073
- const stat4 = safeLstat(plansPath);
39074
- if (!stat4) {
39075
- if (allowMissing) return null;
39076
- throw new PlanStoreError("not_found");
39077
- }
39078
- if (!stat4.isDirectory() || stat4.isSymbolicLink()) throw new PlanStoreError("unsafe_path");
39079
- return { plansPath, workspacePath: workspace.path };
39080
- }
39081
- async function resolvePlanFile(plansRoot, name) {
39082
- try {
39083
- const candidatePath = path23__default.resolve(plansRoot.plansPath, name);
39084
- assertWithinRoot(plansRoot.plansPath, candidatePath);
39085
- assertWithinRoot(plansRoot.workspacePath, candidatePath);
39086
- const stat4 = safeLstat(candidatePath);
39087
- if (stat4?.isSymbolicLink()) throw new PlanStoreError("unsafe_path");
39088
- if (!stat4?.isFile()) throw new PlanStoreError("not_found");
39089
- return { path: candidatePath, stat: stat4 };
39090
- } catch (error51) {
39091
- if (error51 instanceof PlanStoreError) throw error51;
39092
- throw new PlanStoreError("unsafe_path");
39093
- }
39094
- }
39095
- function toPlanStoreError(error51) {
39096
- if (error51 instanceof PlanStoreError) return error51;
39097
- return new PlanStoreError("not_found");
39098
- }
39099
- var TheaterRootError = class extends Error {
39100
- code;
39101
- constructor(code) {
39102
- super(code);
39103
- this.code = code;
39104
- }
39105
- };
39106
- async function resolveTheaterRoot(theaterRoot) {
39107
- const nominalRoot = path23__default.resolve(theaterRoot);
39108
- let realRoot;
39109
- try {
39110
- realRoot = await fs10__default.promises.realpath(nominalRoot);
39111
- } catch (error51) {
39112
- throw mapFsError(error51);
39113
- }
39114
- let stat4;
39115
- try {
39116
- stat4 = await fs10__default.promises.stat(realRoot);
39117
- } catch (error51) {
39118
- throw mapFsError(error51);
39119
- }
39120
- if (!stat4.isDirectory()) throw new TheaterRootError("invalid_path");
39121
- return { realRoot };
39122
- }
39123
- function mapFsError(error51) {
39124
- const code = error51.code;
39125
- if (code === "ENOENT" || code === "ENOTDIR") return new TheaterRootError("not_found");
39126
- if (code === "EACCES" || code === "EPERM") return new TheaterRootError("forbidden");
39127
- return new TheaterRootError("invalid_path");
39128
- }
39129
-
39130
- // core/host/plans/routes.ts
39131
- function createPlansRouter(deps) {
39132
- return async function handlePlansRoute(context) {
39133
- const { req, res, pathname } = context;
39134
- if (pathname === "/api/v1/plans/list") {
39135
- await handlePlansList(req, res, deps);
39136
- return true;
39137
- }
39138
- if (pathname === "/api/v1/plans/read") {
39139
- await handlePlansRead(req, res, deps);
39140
- return true;
39141
- }
39142
- if (pathname === "/api/v1/plans/delete") {
39143
- await handlePlansDelete(req, res, deps);
39144
- return true;
39145
- }
39146
- if (pathname === "/api/v1/plans/search") {
39147
- await handlePlansSearch(req, res, deps);
39148
- return true;
39149
- }
39150
- if (pathname === "/api/v1/plans/events") {
39151
- await handlePlansEvents(req, res, deps);
39152
- return true;
39153
- }
39154
- return false;
39155
- };
39156
- }
39157
- async function handlePlansSearch(req, res, deps) {
39158
- if (req.method !== "POST") {
39159
- deps.writeJson(res, 405, { error: "Method not allowed" });
39160
- return;
39161
- }
39162
- if (!deps.isAuthorized(req)) {
39163
- deps.writeJson(res, 401, { error: "unauthorized" });
39164
- return;
39165
- }
39166
- const body2 = await deps.readJsonBody(req);
39167
- if (!isPlainObject2(body2) || typeof body2.theaterId !== "string" || typeof body2.query !== "string" || body2.query.trim() === "" || !Number.isInteger(body2.limit) || body2.limit < 1 || body2.limit > 8 || "relPath" in body2) {
39168
- deps.writeJson(res, 400, { error: "invalid_request" });
39169
- return;
39170
- }
39171
- const theaterPath = deps.resolveTheaterPath(body2.theaterId);
39172
- if (!theaterPath) {
39173
- deps.writeJson(res, 404, { error: "theater_not_found" });
39174
- return;
39175
- }
39176
- try {
39177
- const context = await resolveTheaterRoot(theaterPath);
39178
- const tokens = body2.query.trim().toLocaleLowerCase().split(/\s+/).filter(Boolean);
39179
- const plans = (await listPlansForWorkspace(deps.dataDir, context.realRoot)).filter((plan) => {
39180
- const text = `${plan.name}
39181
- ${plan.title}`.toLocaleLowerCase();
39182
- return tokens.every((token) => text.includes(token));
39183
- }).slice(0, body2.limit).map((plan) => ({ name: plan.name, title: plan.title }));
39184
- deps.writeJson(res, 200, { plans });
39185
- } catch (error51) {
39186
- writePlanStoreError(res, deps, error51);
39187
- }
39188
- }
39189
- async function handlePlansEvents(req, res, deps) {
39190
- if (req.method !== "GET") {
39191
- deps.writeJson(res, 405, { error: "Method not allowed" });
39192
- return;
39193
- }
39194
- if (!deps.isEventsAuthorized?.(req)) {
39195
- deps.writeJson(res, 401, { error: "unauthorized" });
39196
- return;
39197
- }
39198
- const theaterId = readEventsTheaterId(req);
39199
- if (!theaterId) {
39200
- deps.writeJson(res, 400, { error: "invalid_request" });
39201
- return;
39202
- }
39203
- const theaterPath = deps.resolveTheaterPath(theaterId);
39204
- if (!theaterPath) {
39205
- deps.writeJson(res, 404, { error: "theater_not_found" });
39206
- return;
39207
- }
39208
- try {
39209
- const context = await resolveTheaterRoot(theaterPath);
39210
- const watchPath = resolvePlansWatchDirectory(deps.dataDir, context.realRoot);
39211
- if (!watchPath || !deps.subscribeToChanges) {
39212
- deps.writeJson(res, 404, { error: "not_found" });
39213
- return;
39214
- }
39215
- deps.subscribeToChanges(res, watchPath);
39216
- } catch (error51) {
39217
- writePlanStoreError(res, deps, error51);
39218
- }
39219
- }
39220
- function readEventsTheaterId(req) {
39221
- const url2 = new URL(req.url ?? "/", "http://localhost");
39222
- const theaterIds = url2.searchParams.getAll("theaterId");
39223
- if (theaterIds.length !== 1 || theaterIds[0] === "" || [...url2.searchParams.keys()].some((key) => key !== "theaterId")) return null;
39224
- return theaterIds[0] ?? null;
39225
- }
39226
- async function handlePlansList(req, res, deps) {
39227
- if (req.method !== "POST") {
39228
- deps.writeJson(res, 405, { error: "Method not allowed" });
39229
- return;
39230
- }
39231
- if (!deps.isAuthorized(req)) {
39232
- deps.writeJson(res, 401, { error: "unauthorized" });
39233
- return;
39234
- }
39235
- const body2 = await deps.readJsonBody(req);
39236
- if (!isPlainObject2(body2) || typeof body2.theaterId !== "string" || "relPath" in body2) {
39237
- deps.writeJson(res, 400, { error: "invalid_request" });
39238
- return;
39239
- }
39240
- const theaterPath = deps.resolveTheaterPath(body2.theaterId);
39241
- if (!theaterPath) {
39242
- deps.writeJson(res, 404, { error: "theater_not_found" });
39243
- return;
39244
- }
39245
- try {
39246
- const context = await resolveTheaterRoot(theaterPath);
39247
- deps.writeJson(res, 200, { plans: await listPlansForWorkspace(deps.dataDir, context.realRoot) });
39248
- } catch (error51) {
39249
- writePlanStoreError(res, deps, error51);
39250
- }
39251
- }
39252
- async function handlePlansRead(req, res, deps) {
39253
- if (req.method !== "POST") {
39254
- deps.writeJson(res, 405, { error: "Method not allowed" });
39255
- return;
39256
- }
39257
- if (!deps.isAuthorized(req)) {
39258
- deps.writeJson(res, 401, { error: "unauthorized" });
39259
- return;
39260
- }
39261
- const body2 = await deps.readJsonBody(req);
39262
- if (!isPlainObject2(body2) || typeof body2.theaterId !== "string" || "relPath" in body2) {
39263
- deps.writeJson(res, 400, { error: "invalid_request" });
39264
- return;
39265
- }
39266
- if (typeof body2.name !== "string" || !isValidPlanName(body2.name)) {
39267
- deps.writeJson(res, 400, { error: "invalid_name" });
39268
- return;
39269
- }
39270
- const theaterPath = deps.resolveTheaterPath(body2.theaterId);
39271
- if (!theaterPath) {
39272
- deps.writeJson(res, 404, { error: "theater_not_found" });
39273
- return;
39274
- }
39275
- try {
39276
- const context = await resolveTheaterRoot(theaterPath);
39277
- deps.writeJson(res, 200, await readPlanForWorkspace(deps.dataDir, context.realRoot, body2.name));
39278
- } catch (error51) {
39279
- writePlanStoreError(res, deps, error51);
39280
- }
39281
- }
39282
- async function handlePlansDelete(req, res, deps) {
39283
- if (req.method !== "POST") {
39284
- deps.writeJson(res, 405, { error: "Method not allowed" });
39285
- return;
39286
- }
39287
- if (!deps.isAuthorized(req)) {
39288
- deps.writeJson(res, 401, { error: "unauthorized" });
39289
- return;
39290
- }
39291
- const body2 = await deps.readJsonBody(req);
39292
- if (!isPlainObject2(body2) || typeof body2.theaterId !== "string" || "relPath" in body2) {
39293
- deps.writeJson(res, 400, { error: "invalid_request" });
39294
- return;
39295
- }
39296
- if (typeof body2.name !== "string" || !isValidPlanName(body2.name)) {
39297
- deps.writeJson(res, 400, { error: "invalid_name" });
39298
- return;
39299
- }
39300
- const theaterPath = deps.resolveTheaterPath(body2.theaterId);
39301
- if (!theaterPath) {
39302
- deps.writeJson(res, 404, { error: "theater_not_found" });
39303
- return;
39304
- }
39305
- try {
39306
- const context = await resolveTheaterRoot(theaterPath);
39307
- await deletePlanForWorkspace(deps.dataDir, context.realRoot, body2.name);
39308
- deps.writeJson(res, 200, { deleted: true });
39309
- } catch (error51) {
39310
- writePlanStoreError(res, deps, error51);
39311
- }
39312
- }
39313
- function isPlainObject2(value) {
39314
- return typeof value === "object" && value !== null && !Array.isArray(value);
39315
- }
39316
- function writePlanStoreError(res, deps, error51) {
39317
- if (error51 instanceof TheaterRootError) {
39318
- const httpStatus2 = error51.code === "forbidden" ? 403 : error51.code === "not_found" ? 404 : 400;
39319
- deps.writeJson(res, httpStatus2, { error: error51.code });
39320
- return;
39321
- }
39322
- if (!(error51 instanceof PlanStoreError)) throw error51;
39323
- const httpStatus = error51.code === "unsafe_path" ? 403 : error51.code === "too_large" ? 413 : 404;
39324
- deps.writeJson(res, httpStatus, { error: error51.code });
39325
- }
39326
- var PLANS_WATCH_DEBOUNCE_MS = 200;
39327
- function createPlansWatcherRegistry(watcherFactory = (watchPath, options, listener) => fs10__default.watch(watchPath, options, listener), debounceMs = PLANS_WATCH_DEBOUNCE_MS, directoryIdentity = (watchPath) => {
39328
- try {
39329
- const stat4 = fs10__default.statSync(watchPath);
39330
- return { dev: stat4.dev, ino: stat4.ino };
39331
- } catch {
39332
- return null;
39333
- }
39334
- }) {
39335
- const entries = /* @__PURE__ */ new Map();
39336
- return {
39337
- subscribe(watchPath, onChange, onClose) {
39338
- let entry = entries.get(watchPath);
39339
- if (!entry) {
39340
- entry = createEntry(watchPath);
39341
- if (!entry) {
39342
- onClose();
39343
- return () => {
39344
- };
39345
- }
39346
- entries.set(watchPath, entry);
39347
- }
39348
- const subscriber = { onChange, onClose };
39349
- entry.subscribers.add(subscriber);
39350
- let unsubscribed = false;
39351
- return () => {
39352
- if (unsubscribed) return;
39353
- unsubscribed = true;
39354
- entry.subscribers.delete(subscriber);
39355
- if (entry.subscribers.size !== 0) return;
39356
- closeEntry(watchPath, entry);
39357
- };
39358
- }
39359
- };
39360
- function createEntry(watchPath) {
39361
- const subscribers = /* @__PURE__ */ new Set();
39362
- let entry;
39363
- try {
39364
- const watcher = watcherFactory(watchPath, { recursive: false }, () => {
39365
- if (entry.closed) return;
39366
- const current = directoryIdentity(watchPath);
39367
- if (!current || entry.identity === null || current.dev !== entry.identity.dev || current.ino !== entry.identity.ino) {
39368
- closeEntry(watchPath, entry, true);
39369
- return;
39370
- }
39371
- if (entry.timer) clearTimeout(entry.timer);
39372
- entry.timer = setTimeout(() => {
39373
- entry.timer = null;
39374
- for (const subscriber of entry.subscribers) subscriber.onChange();
39375
- }, debounceMs);
39376
- });
39377
- entry = { watcher, subscribers, identity: directoryIdentity(watchPath), timer: null, closed: false };
39378
- watcher.on("error", () => closeEntry(watchPath, entry, true));
39379
- return entry;
39380
- } catch {
39381
- return null;
39382
- }
39383
- }
39384
- function closeEntry(watchPath, entry, notifySubscribers = false) {
39385
- if (entry.closed) return;
39386
- entry.closed = true;
39387
- if (entry.timer) clearTimeout(entry.timer);
39388
- entry.timer = null;
39389
- try {
39390
- entry.watcher.close();
39391
- } catch {
39392
- }
39393
- if (entries.get(watchPath) === entry) entries.delete(watchPath);
39394
- if (notifySubscribers) {
39395
- for (const subscriber of entry.subscribers) subscriber.onClose();
39396
- }
39397
- }
39398
- }
39399
-
39400
38419
  // sdk/version.ts
39401
38420
  var SDK_API_VERSION = 1;
39402
38421
 
@@ -40298,7 +39317,7 @@ function serveFallbackIndex(req, res, consoleRoot, getActiveTheme) {
40298
39317
  function injectActiveTheme(html, getActiveTheme) {
40299
39318
  if (!getActiveTheme) return html;
40300
39319
  const theme = getActiveTheme();
40301
- if (theme !== "instrument" && theme !== "maritime" && theme !== "carbon" && theme !== "daywatch" && theme !== "whites" && theme !== "drydock") {
39320
+ if (theme !== "instrument" && theme !== "maritime" && theme !== "carbon" && theme !== "whites") {
40302
39321
  return html;
40303
39322
  }
40304
39323
  return html.replace('data-theme="instrument"', `data-theme="${theme}" data-theme-source="server"`);
@@ -40375,7 +39394,7 @@ async function statDirectory(targetPath, stat4) {
40375
39394
  try {
40376
39395
  return await stat4(targetPath);
40377
39396
  } catch (error51) {
40378
- throw mapFsError2(error51);
39397
+ throw mapFsError(error51);
40379
39398
  }
40380
39399
  }
40381
39400
  async function collectDirectoryEntries(targetPath, opendir, stat4, entries) {
@@ -40392,7 +39411,7 @@ async function collectDirectoryEntries(targetPath, opendir, stat4, entries) {
40392
39411
  }
40393
39412
  return false;
40394
39413
  } catch (error51) {
40395
- throw mapFsError2(error51);
39414
+ throw mapFsError(error51);
40396
39415
  } finally {
40397
39416
  await directory.close();
40398
39417
  }
@@ -40401,7 +39420,7 @@ async function openDirectory(targetPath, opendir) {
40401
39420
  try {
40402
39421
  return await opendir(targetPath);
40403
39422
  } catch (error51) {
40404
- throw mapFsError2(error51);
39423
+ throw mapFsError(error51);
40405
39424
  }
40406
39425
  }
40407
39426
  async function toTheaterFolderEntry(targetPath, dirent, stat4) {
@@ -40419,7 +39438,7 @@ async function statSymlinkDirectory(entryPath, stat4) {
40419
39438
  return false;
40420
39439
  }
40421
39440
  }
40422
- function mapFsError2(error51) {
39441
+ function mapFsError(error51) {
40423
39442
  const code = error51.code;
40424
39443
  if (code === "EACCES" || code === "EPERM") return new TheaterFolderListError("forbidden");
40425
39444
  if (code === "ENOENT" || code === "ENOTDIR") return new TheaterFolderListError("not_found");
@@ -41148,34 +40167,6 @@ var SERVER_API_CATALOG = [
41148
40167
  category: "Observer",
41149
40168
  gate: "origin-write"
41150
40169
  },
41151
- {
41152
- method: "POST",
41153
- path: "/api/v1/plans/list",
41154
- summary: "Theater\uC758 \uC2E4\uD589 \uACC4\uD68D \uBAA9\uB85D\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4.",
41155
- category: "Observer",
41156
- gate: "origin-write"
41157
- },
41158
- {
41159
- method: "POST",
41160
- path: "/api/v1/plans/read",
41161
- summary: "\uC2E4\uD589 \uACC4\uD68D \uBB38\uC11C\uB97C \uC870\uD68C\uD569\uB2C8\uB2E4.",
41162
- category: "Observer",
41163
- gate: "origin-write"
41164
- },
41165
- {
41166
- method: "POST",
41167
- path: "/api/v1/plans/delete",
41168
- summary: "\uC2E4\uD589 \uACC4\uD68D \uD30C\uC77C\uC744 \uC0AD\uC81C\uD569\uB2C8\uB2E4.",
41169
- category: "Observer",
41170
- gate: "origin-write"
41171
- },
41172
- {
41173
- method: "GET",
41174
- path: "/api/v1/plans/events",
41175
- summary: "Theater \uC2E4\uD589 \uACC4\uD68D \uBCC0\uACBD \uC2E0\uD638\uB97C \uC2A4\uD2B8\uB9AC\uBC0D\uD569\uB2C8\uB2E4.",
41176
- category: "Observer",
41177
- gate: "origin-write"
41178
- },
41179
40170
  {
41180
40171
  method: "POST",
41181
40172
  path: "/api/v1/updates/apply",
@@ -41458,40 +40449,6 @@ function createConsoleServer(deps = {}) {
41458
40449
  systemFonts: deps.systemFonts ?? createSystemFontsService(),
41459
40450
  writeJson
41460
40451
  });
41461
- const plansWatcherRegistry = createPlansWatcherRegistry();
41462
- const plansRouter = createPlansRouter({
41463
- dataDir: fleetDataDir,
41464
- isAuthorized: isTerminalAuthorized,
41465
- // events는 same-origin EventSource가 Origin 헤더를 보내지 않으므로 exact-Origin 게이트를 쓸 수 없다.
41466
- // list/read와 동일한 terminal Origin 게이트(무-Origin 허용·존재 시 정확 일치)를 적용한다.
41467
- isEventsAuthorized: isTerminalAuthorized,
41468
- readJsonBody,
41469
- resolveTheaterPath: (theaterId) => theaters.get(theaterId)?.realpath ?? null,
41470
- writeJson,
41471
- subscribeToChanges: (res, watchPath) => {
41472
- res.writeHead(200, withSecurityHeaders2({
41473
- "Content-Type": "text/event-stream",
41474
- "Cache-Control": "no-cache",
41475
- "Connection": "keep-alive"
41476
- }));
41477
- res.write(":connected\n\n");
41478
- const unsubscribe = plansWatcherRegistry.subscribe(
41479
- watchPath,
41480
- () => {
41481
- res.write(encodeSseData("plans-changed", {}));
41482
- },
41483
- () => res.end()
41484
- );
41485
- let cleanedUp = false;
41486
- const cleanup = () => {
41487
- if (cleanedUp) return;
41488
- cleanedUp = true;
41489
- unsubscribe();
41490
- };
41491
- res.on("close", cleanup);
41492
- res.on("error", cleanup);
41493
- }
41494
- });
41495
40452
  const codexWorkspaceRouter = createCodexWorkspaceRouter({
41496
40453
  getTheater: (theaterId) => theaters.get(theaterId),
41497
40454
  isAuthorized: isTerminalAuthorized,
@@ -41592,10 +40549,6 @@ function createConsoleServer(deps = {}) {
41592
40549
  runAsyncHandler(handleTheaterFolderGrants(req, res), res);
41593
40550
  return;
41594
40551
  }
41595
- if (pathname === "/api/v1/plans/list" || pathname === "/api/v1/plans/read" || pathname === "/api/v1/plans/delete" || pathname === "/api/v1/plans/events") {
41596
- runAsyncBooleanHandler(plansRouter({ req, res, pathname }), res, () => false);
41597
- return;
41598
- }
41599
40552
  const restoreMatch = pathname.match(/^\/api\/v1\/deletions\/([^/]+)\/restore$/);
41600
40553
  if (restoreMatch) {
41601
40554
  runAsyncHandler(handleDeferredDeletionRestore(req, res, decodeURIComponent(restoreMatch[1] ?? "")), res);
@@ -41690,7 +40643,7 @@ function createConsoleServer(deps = {}) {
41690
40643
  return;
41691
40644
  }
41692
40645
  const body2 = await readJsonBody(req);
41693
- if (!isPlainObject3(body2) || body2.path !== void 0 && body2.path !== null && typeof body2.path !== "string") {
40646
+ if (!isPlainObject2(body2) || body2.path !== void 0 && body2.path !== null && typeof body2.path !== "string") {
41694
40647
  writeJson(res, 400, { error: "invalid_path" });
41695
40648
  return;
41696
40649
  }
@@ -41715,7 +40668,7 @@ function createConsoleServer(deps = {}) {
41715
40668
  return;
41716
40669
  }
41717
40670
  const body2 = await readJsonBody(req);
41718
- if (!isPlainObject3(body2) || typeof body2.path !== "string") {
40671
+ if (!isPlainObject2(body2) || typeof body2.path !== "string") {
41719
40672
  writeJson(res, 400, { error: "invalid_folder" });
41720
40673
  return;
41721
40674
  }
@@ -41739,7 +40692,7 @@ function createConsoleServer(deps = {}) {
41739
40692
  return;
41740
40693
  }
41741
40694
  const body2 = await readJsonBody(req);
41742
- if (!isPlainObject3(body2) || typeof body2.folderGrantId !== "string") {
40695
+ if (!isPlainObject2(body2) || typeof body2.folderGrantId !== "string") {
41743
40696
  writeJson(res, 400, { error: "invalid_folder_grant" });
41744
40697
  return;
41745
40698
  }
@@ -41769,7 +40722,7 @@ function createConsoleServer(deps = {}) {
41769
40722
  }
41770
40723
  if (req.method === "PATCH") {
41771
40724
  const body2 = await readJsonBody(req);
41772
- if (!isPlainObject3(body2) || typeof body2.order !== "number" || !Number.isInteger(body2.order) || body2.order < 0) {
40725
+ if (!isPlainObject2(body2) || typeof body2.order !== "number" || !Number.isInteger(body2.order) || body2.order < 0) {
41773
40726
  writeJson(res, 400, { error: "invalid_theater_order" });
41774
40727
  return;
41775
40728
  }
@@ -41886,7 +40839,7 @@ function createConsoleServer(deps = {}) {
41886
40839
  writeJson(res, 400, { error: "invalid_update_apply_body" });
41887
40840
  return;
41888
40841
  }
41889
- if (body2 !== null && (!isPlainObject3(body2) || hasForbiddenUpdateApplyBodyKeys(body2))) {
40842
+ if (body2 !== null && (!isPlainObject2(body2) || hasForbiddenUpdateApplyBodyKeys(body2))) {
41890
40843
  writeJson(res, 400, { error: "invalid_update_apply_body" });
41891
40844
  return;
41892
40845
  }
@@ -42281,7 +41234,7 @@ function theaterFolderListStatus(error51) {
42281
41234
  if (error51.code === "not_found") return 404;
42282
41235
  return 400;
42283
41236
  }
42284
- function isPlainObject3(value) {
41237
+ function isPlainObject2(value) {
42285
41238
  return typeof value === "object" && value !== null && !Array.isArray(value);
42286
41239
  }
42287
41240
  function hasForbiddenUpdateApplyBodyKeys(body2) {
@@ -42291,7 +41244,7 @@ function isValidConsoleStaticPort3(value) {
42291
41244
  return typeof value === "number" && Number.isInteger(value) && value >= MIN_CONSOLE_STATIC_PORT3 && value <= MAX_CONSOLE_STATIC_PORT3;
42292
41245
  }
42293
41246
  function sanitizeLaunchKind(value) {
42294
- if (!isPlainObject3(value) || typeof value.id !== "string" || typeof value.type !== "string" || typeof value.title !== "string") return null;
41247
+ if (!isPlainObject2(value) || typeof value.id !== "string" || typeof value.type !== "string" || typeof value.title !== "string") return null;
42295
41248
  return {
42296
41249
  id: value.id,
42297
41250
  type: value.type,