@dotobokuri/fleet-console 1.9.0 → 1.10.1

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 (63) hide show
  1. package/AGENTS.md +4 -4
  2. package/dist/cli-bin.mjs +571 -344
  3. package/dist/cli.mjs +571 -344
  4. package/dist/client/assets/{_baseUniq-_nKBty4x.js → _baseUniq-e_j340KJ.js} +1 -1
  5. package/dist/client/assets/{arc-DEjqUlkY.js → arc-CioNx0k6.js} +1 -1
  6. package/dist/client/assets/{architectureDiagram-Q4EWVU46-CPF3RLab.js → architectureDiagram-Q4EWVU46-B_8HDSCb.js} +1 -1
  7. package/dist/client/assets/{blockDiagram-DXYQGD6D-DguupB0e.js → blockDiagram-DXYQGD6D-CpHdrypQ.js} +1 -1
  8. package/dist/client/assets/{c4Diagram-AHTNJAMY-Dd7AVc09.js → c4Diagram-AHTNJAMY-CkitEGpF.js} +1 -1
  9. package/dist/client/assets/channel-CEwT4AXW.js +1 -0
  10. package/dist/client/assets/{chunk-4BX2VUAB-CSIihHG7.js → chunk-4BX2VUAB-DxyXXSCc.js} +1 -1
  11. package/dist/client/assets/{chunk-4TB4RGXK-DR_cPI3H.js → chunk-4TB4RGXK-C2-nU4zS.js} +1 -1
  12. package/dist/client/assets/{chunk-55IACEB6-97czQ3iV.js → chunk-55IACEB6-Ch5DNHFU.js} +1 -1
  13. package/dist/client/assets/{chunk-EDXVE4YY-piQCPtjQ.js → chunk-EDXVE4YY-CHE6KKZa.js} +1 -1
  14. package/dist/client/assets/{chunk-FMBD7UC4-BIeV9l0L.js → chunk-FMBD7UC4-PFqCeOs6.js} +1 -1
  15. package/dist/client/assets/{chunk-OYMX7WX6-DWUJBKm_.js → chunk-OYMX7WX6-DHE5_rgO.js} +1 -1
  16. package/dist/client/assets/{chunk-QZHKN3VN-DHL5fPU4.js → chunk-QZHKN3VN-BNsfe2Ai.js} +1 -1
  17. package/dist/client/assets/{chunk-YZCP3GAM-Dk19Wldz.js → chunk-YZCP3GAM-Du6aAWOS.js} +1 -1
  18. package/dist/client/assets/classDiagram-6PBFFD2Q-BcAsKAPs.js +1 -0
  19. package/dist/client/assets/classDiagram-v2-HSJHXN6E-BcAsKAPs.js +1 -0
  20. package/dist/client/assets/clone-BbRCSYXZ.js +1 -0
  21. package/dist/client/assets/{cose-bilkent-S5V4N54A-CcROwyfn.js → cose-bilkent-S5V4N54A-BMbRb2Ij.js} +1 -1
  22. package/dist/client/assets/{dagre-KV5264BT-kdHN8OcZ.js → dagre-KV5264BT-BIYIuU4t.js} +1 -1
  23. package/dist/client/assets/{diagram-5BDNPKRD-yqi72mWd.js → diagram-5BDNPKRD-DE58KlL0.js} +1 -1
  24. package/dist/client/assets/{diagram-G4DWMVQ6-CTjHbP--.js → diagram-G4DWMVQ6-BBHYXkDj.js} +1 -1
  25. package/dist/client/assets/{diagram-MMDJMWI5-BCGN9v8i.js → diagram-MMDJMWI5-BGA4ZKw3.js} +1 -1
  26. package/dist/client/assets/{diagram-TYMM5635-p6gtwFXr.js → diagram-TYMM5635-DusN1Hix.js} +1 -1
  27. package/dist/client/assets/{erDiagram-SMLLAGMA-BHNCT04F.js → erDiagram-SMLLAGMA-84E-AJKo.js} +1 -1
  28. package/dist/client/assets/{flowDiagram-DWJPFMVM-DP-E6Gb1.js → flowDiagram-DWJPFMVM-Dpap9NqV.js} +1 -1
  29. package/dist/client/assets/{ganttDiagram-T4ZO3ILL-COKcadl7.js → ganttDiagram-T4ZO3ILL-CukRJAaM.js} +1 -1
  30. package/dist/client/assets/{gitGraphDiagram-UUTBAWPF-CVkte06j.js → gitGraphDiagram-UUTBAWPF-DuAwiTii.js} +1 -1
  31. package/dist/client/assets/{graph-BljmCiGu.js → graph-B7irxl7Q.js} +1 -1
  32. package/dist/client/assets/index-CTyjGQHF.css +1 -0
  33. package/dist/client/assets/index-Uidvbtqb.js +777 -0
  34. package/dist/client/assets/{infoDiagram-42DDH7IO-Dh_U82lE.js → infoDiagram-42DDH7IO-Gdh2w_Ry.js} +1 -1
  35. package/dist/client/assets/{ishikawaDiagram-UXIWVN3A-BtZhb0mv.js → ishikawaDiagram-UXIWVN3A-DvbqJman.js} +1 -1
  36. package/dist/client/assets/{journeyDiagram-VCZTEJTY-_Zd4No67.js → journeyDiagram-VCZTEJTY-DIQYAsjN.js} +1 -1
  37. package/dist/client/assets/{kanban-definition-6JOO6SKY-CpIIMkPJ.js → kanban-definition-6JOO6SKY-8BBtOuAV.js} +1 -1
  38. package/dist/client/assets/{layout-ButG21vs.js → layout-DDUpLunD.js} +1 -1
  39. package/dist/client/assets/{linear-C-frnGuN.js → linear-BzLoJVdP.js} +1 -1
  40. package/dist/client/assets/{mermaid.core-ISlBhdkY.js → mermaid.core-Ddi7z3V3.js} +4 -4
  41. package/dist/client/assets/{min-CalB2Q9y.js → min-CEKwugI-.js} +1 -1
  42. package/dist/client/assets/{mindmap-definition-QFDTVHPH-BfilPIUD.js → mindmap-definition-QFDTVHPH-y-V-6GIi.js} +1 -1
  43. package/dist/client/assets/{pieDiagram-DEJITSTG-Dm_1WIPT.js → pieDiagram-DEJITSTG-DjqTUefi.js} +1 -1
  44. package/dist/client/assets/{quadrantDiagram-34T5L4WZ-DMzRgLeF.js → quadrantDiagram-34T5L4WZ-BZbwyDuC.js} +1 -1
  45. package/dist/client/assets/{requirementDiagram-MS252O5E-Bl1lUR6U.js → requirementDiagram-MS252O5E-M2epVejI.js} +1 -1
  46. package/dist/client/assets/{sankeyDiagram-XADWPNL6-VxDrFumf.js → sankeyDiagram-XADWPNL6-DQHzVL6h.js} +1 -1
  47. package/dist/client/assets/{sequenceDiagram-FGHM5R23-BoB_k7L2.js → sequenceDiagram-FGHM5R23-Dldq08WJ.js} +1 -1
  48. package/dist/client/assets/{stateDiagram-FHFEXIEX-C8DFihD3.js → stateDiagram-FHFEXIEX-B32muPdI.js} +1 -1
  49. package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-Ct3tm_Bq.js +1 -0
  50. package/dist/client/assets/{timeline-definition-GMOUNBTQ-G5hn4rEl.js → timeline-definition-GMOUNBTQ-nSYYEX6t.js} +1 -1
  51. package/dist/client/assets/{vennDiagram-DHZGUBPP-D_jMNDmm.js → vennDiagram-DHZGUBPP-DPIMKKCQ.js} +1 -1
  52. package/dist/client/assets/{wardley-RL74JXVD-Clc5Li47.js → wardley-RL74JXVD-DArerB6Y.js} +1 -1
  53. package/dist/client/assets/{wardleyDiagram-NUSXRM2D-Bygn2On7.js → wardleyDiagram-NUSXRM2D-DRvimWEN.js} +1 -1
  54. package/dist/client/assets/{xychartDiagram-5P7HB3ND-arK3uijt.js → xychartDiagram-5P7HB3ND-D0VCX3ps.js} +1 -1
  55. package/dist/client/index.html +2 -2
  56. package/package.json +1 -1
  57. package/dist/client/assets/channel-DA6xE92d.js +0 -1
  58. package/dist/client/assets/classDiagram-6PBFFD2Q-D46R_D_e.js +0 -1
  59. package/dist/client/assets/classDiagram-v2-HSJHXN6E-D46R_D_e.js +0 -1
  60. package/dist/client/assets/clone-DV233GSJ.js +0 -1
  61. package/dist/client/assets/index-B7IECSX7.css +0 -1
  62. package/dist/client/assets/index-CSTdaEyG.js +0 -777
  63. package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-DlDadEC7.js +0 -1
package/dist/cli.mjs CHANGED
@@ -1144,10 +1144,10 @@ function mergeDefs(...defs) {
1144
1144
  function cloneDef(schema) {
1145
1145
  return mergeDefs(schema._zod.def);
1146
1146
  }
1147
- function getElementAtPath(obj, path36) {
1148
- if (!path36)
1147
+ function getElementAtPath(obj, path37) {
1148
+ if (!path37)
1149
1149
  return obj;
1150
- return path36.reduce((acc, key) => acc?.[key], obj);
1150
+ return path37.reduce((acc, key) => acc?.[key], obj);
1151
1151
  }
1152
1152
  function promiseAllObject(promisesObj) {
1153
1153
  const keys = Object.keys(promisesObj);
@@ -1556,11 +1556,11 @@ function explicitlyAborted(x, startIndex = 0) {
1556
1556
  }
1557
1557
  return false;
1558
1558
  }
1559
- function prefixIssues(path36, issues) {
1559
+ function prefixIssues(path37, issues) {
1560
1560
  return issues.map((iss) => {
1561
1561
  var _a3;
1562
1562
  (_a3 = iss).path ?? (_a3.path = []);
1563
- iss.path.unshift(path36);
1563
+ iss.path.unshift(path37);
1564
1564
  return iss;
1565
1565
  });
1566
1566
  }
@@ -1707,16 +1707,16 @@ function flattenError(error51, mapper = (issue3) => issue3.message) {
1707
1707
  }
1708
1708
  function formatError(error51, mapper = (issue3) => issue3.message) {
1709
1709
  const fieldErrors = { _errors: [] };
1710
- const processError = (error52, path36 = []) => {
1710
+ const processError = (error52, path37 = []) => {
1711
1711
  for (const issue3 of error52.issues) {
1712
1712
  if (issue3.code === "invalid_union" && issue3.errors.length) {
1713
- issue3.errors.map((issues) => processError({ issues }, [...path36, ...issue3.path]));
1713
+ issue3.errors.map((issues) => processError({ issues }, [...path37, ...issue3.path]));
1714
1714
  } else if (issue3.code === "invalid_key") {
1715
- processError({ issues: issue3.issues }, [...path36, ...issue3.path]);
1715
+ processError({ issues: issue3.issues }, [...path37, ...issue3.path]);
1716
1716
  } else if (issue3.code === "invalid_element") {
1717
- processError({ issues: issue3.issues }, [...path36, ...issue3.path]);
1717
+ processError({ issues: issue3.issues }, [...path37, ...issue3.path]);
1718
1718
  } else {
1719
- const fullpath = [...path36, ...issue3.path];
1719
+ const fullpath = [...path37, ...issue3.path];
1720
1720
  if (fullpath.length === 0) {
1721
1721
  fieldErrors._errors.push(mapper(issue3));
1722
1722
  } else {
@@ -1743,17 +1743,17 @@ function formatError(error51, mapper = (issue3) => issue3.message) {
1743
1743
  }
1744
1744
  function treeifyError(error51, mapper = (issue3) => issue3.message) {
1745
1745
  const result = { errors: [] };
1746
- const processError = (error52, path36 = []) => {
1746
+ const processError = (error52, path37 = []) => {
1747
1747
  var _a3, _b;
1748
1748
  for (const issue3 of error52.issues) {
1749
1749
  if (issue3.code === "invalid_union" && issue3.errors.length) {
1750
- issue3.errors.map((issues) => processError({ issues }, [...path36, ...issue3.path]));
1750
+ issue3.errors.map((issues) => processError({ issues }, [...path37, ...issue3.path]));
1751
1751
  } else if (issue3.code === "invalid_key") {
1752
- processError({ issues: issue3.issues }, [...path36, ...issue3.path]);
1752
+ processError({ issues: issue3.issues }, [...path37, ...issue3.path]);
1753
1753
  } else if (issue3.code === "invalid_element") {
1754
- processError({ issues: issue3.issues }, [...path36, ...issue3.path]);
1754
+ processError({ issues: issue3.issues }, [...path37, ...issue3.path]);
1755
1755
  } else {
1756
- const fullpath = [...path36, ...issue3.path];
1756
+ const fullpath = [...path37, ...issue3.path];
1757
1757
  if (fullpath.length === 0) {
1758
1758
  result.errors.push(mapper(issue3));
1759
1759
  continue;
@@ -1785,8 +1785,8 @@ function treeifyError(error51, mapper = (issue3) => issue3.message) {
1785
1785
  }
1786
1786
  function toDotPath(_path) {
1787
1787
  const segs = [];
1788
- const path36 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1789
- for (const seg of path36) {
1788
+ const path37 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1789
+ for (const seg of path37) {
1790
1790
  if (typeof seg === "number")
1791
1791
  segs.push(`[${seg}]`);
1792
1792
  else if (typeof seg === "symbol")
@@ -14450,13 +14450,13 @@ function resolveRef(ref, ctx) {
14450
14450
  if (!ref.startsWith("#")) {
14451
14451
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
14452
14452
  }
14453
- const path36 = ref.slice(1).split("/").filter(Boolean);
14454
- if (path36.length === 0) {
14453
+ const path37 = ref.slice(1).split("/").filter(Boolean);
14454
+ if (path37.length === 0) {
14455
14455
  return ctx.rootSchema;
14456
14456
  }
14457
14457
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
14458
- if (path36[0] === defsKey) {
14459
- const key = path36[1];
14458
+ if (path37[0] === defsKey) {
14459
+ const key = path37[1];
14460
14460
  if (!key || !ctx.defs[key]) {
14461
14461
  throw new Error(`Reference not found: ${ref}`);
14462
14462
  }
@@ -28290,8 +28290,6 @@ __export(typebox_exports, {
28290
28290
  Uppercase: () => Uppercase,
28291
28291
  Void: () => Void
28292
28292
  });
28293
-
28294
- // ../../packages/fleet-carriers/dist/index.js
28295
28293
  var __defProp2 = Object.defineProperty;
28296
28294
  var __export2 = (target, all) => {
28297
28295
  for (var name in all)
@@ -28484,11 +28482,11 @@ function sanitizeCarriersMap(value) {
28484
28482
  return result;
28485
28483
  }
28486
28484
  var TASK_FORCE_POOL_KEY_PATTERN = /(?:^|:)taskforce:[^:]+:([^:]+)$/;
28487
- function buildCarrierExecutorPoolKey(carrierId, originSessionId) {
28488
- return namespacePoolKey(carrierId, originSessionId);
28485
+ function buildCarrierExecutorPoolKey(carrierId, originSessionId, cwd) {
28486
+ return namespacePoolKey(carrierId, joinSessionCwdNamespace(originSessionId, cwd));
28489
28487
  }
28490
- function buildTaskForceExecutorPoolKey(carrierId, cliType, originSessionId) {
28491
- return namespacePoolKey(buildTaskForceRunId(carrierId, cliType), originSessionId);
28488
+ function buildTaskForceExecutorPoolKey(carrierId, cliType, originSessionId, cwd) {
28489
+ return namespacePoolKey(buildTaskForceRunId(carrierId, cliType), joinSessionCwdNamespace(originSessionId, cwd));
28492
28490
  }
28493
28491
  function buildTaskForceRunId(carrierId, cliType) {
28494
28492
  const encodedCarrierId = Buffer.from(carrierId, "utf-8").toString("base64url");
@@ -28503,6 +28501,11 @@ function matchesCarrierPoolKey(poolKey, carrierId) {
28503
28501
  function namespacePoolKey(baseKey, originSessionId) {
28504
28502
  return originSessionId ? `${originSessionId}:${baseKey}` : baseKey;
28505
28503
  }
28504
+ function joinSessionCwdNamespace(originSessionId, cwd) {
28505
+ const cwdNamespace = cwd ? `cwd-${Buffer.from(cwd, "utf-8").toString("base64url")}` : void 0;
28506
+ if (originSessionId && cwdNamespace) return `${originSessionId}:${cwdNamespace}`;
28507
+ return originSessionId ?? cwdNamespace;
28508
+ }
28506
28509
  async function disconnectCarrierExecutorPools(carrierId) {
28507
28510
  const poolKeys = new Set(listActivePoolKeys().filter((poolKey) => matchesCarrierPoolKey(poolKey, carrierId)));
28508
28511
  poolKeys.add(carrierId);
@@ -31306,7 +31309,7 @@ function escapeRegExp(str) {
31306
31309
  }
31307
31310
  var taskForceStateStore = /* @__PURE__ */ new Map();
31308
31311
  function launchTaskForceJob(options) {
31309
- const { registry: registry3, carrierId, request, label, startedAt, toolName, ctx, deps } = options;
31312
+ const { registry: registry3, carrierId, request, label, startedAt, toolName, ctx, cwd, deps } = options;
31310
31313
  const requestKey = buildTaskForceRequestKey(carrierId, request);
31311
31314
  getConfiguredTaskForceBackends(carrierId);
31312
31315
  assertRegisteredCarrier(registry3, carrierId);
@@ -31359,7 +31362,7 @@ function launchTaskForceJob(options) {
31359
31362
  request,
31360
31363
  state,
31361
31364
  signal: launch.signal,
31362
- cwd: ctx.cwd,
31365
+ cwd,
31363
31366
  permit: launch.permit,
31364
31367
  startedAt,
31365
31368
  toolName,
@@ -31451,7 +31454,7 @@ function getRequiredTaskForceModelConfig(carrierId, cliType) {
31451
31454
  async function runTaskForceBackend(registry3, cliType, carrierId, originSessionId, requestKey, request, state, signal, cwd, jobId, trackModelInfoByCli, deps) {
31452
31455
  const execStartedAt = Date.now();
31453
31456
  const progress = state.backends.get(cliType);
31454
- const poolKey = buildTaskForceExecutorPoolKey(carrierId, cliType, originSessionId);
31457
+ const poolKey = buildTaskForceExecutorPoolKey(carrierId, cliType, originSessionId, cwd);
31455
31458
  buildTaskForceScopedRunId(requestKey, cliType);
31456
31459
  const modelInfo = trackModelInfoByCli.get(cliType);
31457
31460
  if (!modelInfo) throw new Error(`Task Force config missing for ${cliType} on carrier "${carrierId}".`);
@@ -31656,7 +31659,8 @@ function buildCarrierDispatchToolSpec(registry3, deps) {
31656
31659
  CARRIER_REQUEST_BREVITY_GUIDELINE
31657
31660
  ],
31658
31661
  guardrails: [
31659
- `Multiple agents may be working on this codebase at the same time on a single filesystem and branch. Only touch changes you made \u2014 never revert or overwrite modifications made by others. Prefer precise edits (edit) over full-file writes (write). Always re-read a file before modifying it, as it may have changed since your last read.`
31662
+ `Multiple agents may be working on this codebase at the same time on a single filesystem and branch. Only touch changes you made \u2014 never revert or overwrite modifications made by others. Prefer precise edits (edit) over full-file writes (write). Always re-read a file before modifying it, as it may have changed since your last read.`,
31663
+ `When the carrier must work in a directory other than the host session cwd (e.g. a git worktree checkout), pass cwd as an absolute path so the carrier's CLI spawns there; never pass a relative path. Omit cwd to use the host session cwd.`
31660
31664
  ],
31661
31665
  get parameters() {
31662
31666
  const carrierIds = getRegisteredOrder(registry3);
@@ -31670,12 +31674,14 @@ function buildCarrierDispatchToolSpec(registry3, deps) {
31670
31674
  }),
31671
31675
  request: typebox_exports.String({
31672
31676
  description: `The task/prompt to send to the carrier. Required blocks per carrier -- see <fleet section="roster">. Missing blocks cause hard-error rejection.`
31673
- })
31677
+ }),
31678
+ cwd: typebox_exports.Optional(typebox_exports.String({
31679
+ description: `Optional absolute working directory for the carrier's CLI spawn. MUST be an absolute path. Provide it when delegating work to a directory other than the host session cwd (e.g. a git worktree checkout) so the carrier spawns deterministically at that path. Omit to default to the host session cwd.`
31680
+ }))
31674
31681
  });
31675
31682
  },
31676
31683
  async execute(args, ctx) {
31677
31684
  const t0 = Date.now();
31678
- const cwd = ctx.cwd;
31679
31685
  const toolCallId = ctx.toolCallId ?? "";
31680
31686
  const jobId = buildCarrierJobId("carrier", toolCallId);
31681
31687
  const toolName = "carrier_dispatch";
@@ -31686,6 +31692,11 @@ function buildCarrierDispatchToolSpec(registry3, deps) {
31686
31692
  error: "Invalid arguments: carrier_id, label, and request must be non-empty strings."
31687
31693
  });
31688
31694
  }
31695
+ const cwdResolution = resolveDispatchCwd(args.cwd, ctx.cwd);
31696
+ if (!cwdResolution.ok) {
31697
+ return launchResponseResult({ job_id: jobId, accepted: false, error: cwdResolution.error });
31698
+ }
31699
+ const cwd = cwdResolution.cwd;
31689
31700
  const carrierId = args.carrier_id.trim();
31690
31701
  const label = args.label.trim();
31691
31702
  const request = args.request;
@@ -31718,6 +31729,7 @@ function buildCarrierDispatchToolSpec(registry3, deps) {
31718
31729
  startedAt: t0,
31719
31730
  toolName,
31720
31731
  ctx,
31732
+ cwd,
31721
31733
  deps
31722
31734
  });
31723
31735
  }
@@ -31830,7 +31842,7 @@ async function runSingleCarrier(opts) {
31830
31842
  });
31831
31843
  try {
31832
31844
  const execResult = await executeWithPool({
31833
- poolKey: buildCarrierExecutorPoolKey(opts.carrierId, opts.originSessionId),
31845
+ poolKey: buildCarrierExecutorPoolKey(opts.carrierId, opts.originSessionId, opts.cwd),
31834
31846
  scopeId: opts.carrierId,
31835
31847
  authEnvResolver: opts.deps.authEnvResolver,
31836
31848
  reservedExternalMcpServerIds: opts.deps.reservedExternalMcpServerIds,
@@ -31960,7 +31972,19 @@ function buildCarrierDispatchRunId(jobId, carrierId) {
31960
31972
  function isDispatchArgs(v) {
31961
31973
  if (typeof v !== "object" || v === null) return false;
31962
31974
  const obj = v;
31963
- return typeof obj.carrier_id === "string" && obj.carrier_id.trim().length > 0 && typeof obj.label === "string" && obj.label.trim().length > 0 && typeof obj.request === "string" && obj.request.trim().length > 0;
31975
+ return typeof obj.carrier_id === "string" && obj.carrier_id.trim().length > 0 && typeof obj.label === "string" && obj.label.trim().length > 0 && typeof obj.request === "string" && obj.request.trim().length > 0 && (obj.cwd === void 0 || typeof obj.cwd === "string");
31976
+ }
31977
+ function resolveDispatchCwd(rawCwd, fallbackCwd) {
31978
+ if (rawCwd === void 0) return { ok: true, cwd: fallbackCwd };
31979
+ const trimmed = rawCwd.trim();
31980
+ if (trimmed.length === 0) return { ok: true, cwd: fallbackCwd };
31981
+ if (!path92__default.isAbsolute(trimmed)) {
31982
+ return {
31983
+ ok: false,
31984
+ error: `Invalid cwd "${rawCwd}": must be an absolute path. Provide an absolute directory or omit cwd to use the host session cwd.`
31985
+ };
31986
+ }
31987
+ return { ok: true, cwd: trimmed };
31964
31988
  }
31965
31989
  function buildCarrierRoster(registry3, carrierIds, options) {
31966
31990
  const { excludeCarrierIds, heading, preambleLines, extraLines } = options ?? {};
@@ -32077,68 +32101,6 @@ function getClaudeModel(config2) {
32077
32101
  function clampClaudeEffort(effort) {
32078
32102
  return effort === "max" ? CLAUDE_MAX_EFFORT : effort;
32079
32103
  }
32080
- var ROLE_DESCRIPTION_SEPARATOR = " - ";
32081
- function readCarrierStatusEntries(registry3) {
32082
- const carrierDefaults = buildCarrierDefaultsByCarrier(registry3);
32083
- return buildCarrierStatusEntriesFromSnapshot(registry3, readFileBackedCarriersSnapshot(carrierDefaults));
32084
- }
32085
- function buildCarrierStatusEntriesFromSnapshot(registry3, snapshot) {
32086
- const entries = [];
32087
- for (const carrierId of getRegisteredOrder(registry3)) {
32088
- const config2 = getRegisteredCarrierConfig(registry3, carrierId);
32089
- if (!config2) continue;
32090
- const state = snapshot.carriers[carrierId];
32091
- const cliType = snapshot.carriers[carrierId]?.agentCliType ?? config2.defaultCliType;
32092
- const selection = snapshot.carriers[carrierId]?.agentCli[cliType];
32093
- const provider = getProviderModels(cliType);
32094
- const role = sanitizeCarrierMetadataText(config2.carrierMetadata?.title);
32095
- const roleSummary = sanitizeCarrierMetadataText(config2.carrierMetadata?.summary);
32096
- entries.push({
32097
- carrierId,
32098
- category: config2.carrierMetadata?.category,
32099
- cliType,
32100
- defaultCliType: config2.defaultCliType,
32101
- displayName: state?.displayName ?? getCarrierSourceDisplayName(registry3, carrierId),
32102
- effort: selection?.effort ?? null,
32103
- isDefault: !selection?.model,
32104
- model: selection?.model || provider.defaultModel,
32105
- role,
32106
- roleDescription: buildRoleDescription(role, roleSummary),
32107
- slot: config2.slot,
32108
- subagentMode: state?.agentMode === "subagent",
32109
- taskForceBackendCount: getConfiguredTaskForceBackendsFromSnapshot(snapshot, carrierId).length
32110
- });
32111
- }
32112
- return entries;
32113
- }
32114
- function buildCarrierDefaultsByCarrier(registry3) {
32115
- return Object.fromEntries(
32116
- getRegisteredOrder(registry3).map((carrierId) => {
32117
- const config2 = getRegisteredCarrierConfig(registry3, carrierId);
32118
- if (!config2) return null;
32119
- return [carrierId, buildCarrierDefaults(config2)];
32120
- }).filter((entry) => entry !== null)
32121
- );
32122
- }
32123
- function buildCarrierDefaults(config2) {
32124
- const cliType = resolveAgentCliType2(config2.id, config2.defaultCliType);
32125
- const cliDefaults = buildCarrierModelDefaults(config2, cliType);
32126
- return {
32127
- cliType,
32128
- ...config2.defaultAgentMode ? { defaultAgentMode: config2.defaultAgentMode } : {},
32129
- ...cliDefaults.defaultEffort ? { defaultEffort: cliDefaults.defaultEffort } : {},
32130
- ...cliDefaults.defaultModel ? { defaultModel: cliDefaults.defaultModel } : {}
32131
- };
32132
- }
32133
- function buildRoleDescription(role, summary) {
32134
- if (role && summary) return `${role}${ROLE_DESCRIPTION_SEPARATOR}${summary}`;
32135
- return role ?? summary;
32136
- }
32137
- function sanitizeCarrierMetadataText(value) {
32138
- if (typeof value !== "string") return null;
32139
- const sanitized = sanitizeToolBlockLabel(value).trim();
32140
- return sanitized.length > 0 ? sanitized : null;
32141
- }
32142
32104
  var dispatch = {
32143
32105
  ...framework_exports,
32144
32106
  framework: framework_exports,
@@ -40269,9 +40231,101 @@ function buildWikiToolSpec(config2, usage) {
40269
40231
  };
40270
40232
  }
40271
40233
 
40234
+ // src/agent-cli-routes.ts
40235
+ var AGENT_CLI_API_CATALOG = [
40236
+ {
40237
+ method: "GET",
40238
+ path: "/agent-cli/state",
40239
+ summary: "Get the installed Agent CLI status.",
40240
+ category: "Agent CLI",
40241
+ gate: "loopback"
40242
+ }
40243
+ ];
40244
+ function createAgentCliRouter(deps) {
40245
+ return async function handleAgentCliRoute(context) {
40246
+ const { req, res, pathname } = context;
40247
+ if (pathname === "/agent-cli/state") {
40248
+ if (req.method !== "GET") {
40249
+ deps.writeJson(res, 405, { error: "Method not allowed" });
40250
+ return true;
40251
+ }
40252
+ const clis = await deps.detect();
40253
+ const body = { clis };
40254
+ deps.writeJson(res, 200, body);
40255
+ return true;
40256
+ }
40257
+ return false;
40258
+ };
40259
+ }
40260
+
40272
40261
  // src/carrier-settings-routes.ts
40273
40262
  var SUBAGENT_CLI_TYPES = /* @__PURE__ */ new Set(["claude", "claude-zai", "claude-kimi", "claude-glm"]);
40274
40263
  var TASKFORCE_MIN_BACKENDS = 2;
40264
+ var CARRIER_SETTINGS_API_CATALOG = [
40265
+ {
40266
+ method: "GET",
40267
+ path: "/carrier-settings/state",
40268
+ summary: "Get the carrier settings status.",
40269
+ category: "Carrier Settings",
40270
+ gate: "loopback"
40271
+ },
40272
+ {
40273
+ method: "GET",
40274
+ path: "/carrier-settings/options",
40275
+ summary: "Get the carrier settings options.",
40276
+ category: "Carrier Settings",
40277
+ gate: "loopback"
40278
+ },
40279
+ {
40280
+ method: "PUT",
40281
+ path: "/carrier-settings/carriers/:id/cli",
40282
+ summary: "Change the carrier Agent CLI.",
40283
+ category: "Carrier Settings",
40284
+ gate: "terminal-origin"
40285
+ },
40286
+ {
40287
+ method: "PUT",
40288
+ path: "/carrier-settings/carriers/:id/model",
40289
+ summary: "Change the carrier model selection.",
40290
+ category: "Carrier Settings",
40291
+ gate: "terminal-origin"
40292
+ },
40293
+ {
40294
+ method: "PATCH",
40295
+ path: "/carrier-settings/carriers/:id/display-name",
40296
+ summary: "Change the carrier display name.",
40297
+ category: "Carrier Settings",
40298
+ gate: "terminal-origin"
40299
+ },
40300
+ {
40301
+ method: "PUT",
40302
+ path: "/carrier-settings/carriers/:id/agent-mode",
40303
+ summary: "Change the carrier execution mode.",
40304
+ category: "Carrier Settings",
40305
+ gate: "terminal-origin"
40306
+ },
40307
+ {
40308
+ method: "PUT",
40309
+ path: "/carrier-settings/carriers/:id/taskforce/:cliType",
40310
+ summary: "Set the Task Force backend model.",
40311
+ category: "Carrier Settings",
40312
+ gate: "terminal-origin"
40313
+ },
40314
+ {
40315
+ method: "DELETE",
40316
+ path: "/carrier-settings/carriers/:id/taskforce/:cliType",
40317
+ summary: "Unset the Task Force backend model.",
40318
+ category: "Carrier Settings",
40319
+ gate: "terminal-origin"
40320
+ },
40321
+ {
40322
+ method: "DELETE",
40323
+ path: "/carrier-settings/carriers/:id/taskforce",
40324
+ summary: "Reset the carrier Task Force settings.",
40325
+ category: "Carrier Settings",
40326
+ gate: "terminal-origin"
40327
+ }
40328
+ ];
40275
40329
  function createCarrierSettingsRouter(deps) {
40276
40330
  const controller = createStatusOverlayController(deps.registry);
40277
40331
  return async function handleCarrierSettingsRoute(context) {
@@ -40683,6 +40737,261 @@ function requireCarrierConfig(registry3, carrierId) {
40683
40737
  return config2;
40684
40738
  }
40685
40739
 
40740
+ // src/global-settings-routes.ts
40741
+ var GLOBAL_SETTINGS_API_CATALOG = [
40742
+ {
40743
+ method: "GET",
40744
+ path: "/global-settings/state",
40745
+ summary: "Get the global console settings status.",
40746
+ category: "Global Settings",
40747
+ gate: "loopback"
40748
+ },
40749
+ {
40750
+ method: "PUT",
40751
+ path: "/global-settings",
40752
+ summary: "Save the global console settings.",
40753
+ category: "Global Settings",
40754
+ gate: "terminal-origin"
40755
+ }
40756
+ ];
40757
+ function createGlobalSettingsRouter(deps) {
40758
+ return async function handleGlobalSettingsRoute(context) {
40759
+ const { req, res, pathname } = context;
40760
+ if (pathname === "/global-settings/state") {
40761
+ if (req.method !== "GET") {
40762
+ deps.writeJson(res, 405, { error: "Method not allowed" });
40763
+ return true;
40764
+ }
40765
+ deps.writeJson(res, 200, buildGlobalSettingsState(deps.globalOptionsService));
40766
+ return true;
40767
+ }
40768
+ if (pathname === "/global-settings") {
40769
+ if (req.method !== "PUT") {
40770
+ deps.writeJson(res, 405, { error: "Method not allowed" });
40771
+ return true;
40772
+ }
40773
+ await mutateGlobalSettings(req, res, deps);
40774
+ return true;
40775
+ }
40776
+ return false;
40777
+ };
40778
+ }
40779
+ function buildGlobalSettingsState(service) {
40780
+ return toGlobalSettingsState(service.load());
40781
+ }
40782
+ async function mutateGlobalSettings(req, res, deps) {
40783
+ if (!deps.isAuthorized(req)) {
40784
+ deps.writeJson(res, 401, { error: "unauthorized" });
40785
+ return;
40786
+ }
40787
+ if (!isJsonRequest2(req)) {
40788
+ deps.writeJson(res, 415, { error: "unsupported_media_type" });
40789
+ return;
40790
+ }
40791
+ const body = await deps.readJsonBody(req);
40792
+ if (!body || typeof body !== "object" || Array.isArray(body)) {
40793
+ deps.writeJson(res, 400, { error: "invalid_json" });
40794
+ return;
40795
+ }
40796
+ if (body.replaceSystemPrompt !== void 0 && typeof body.replaceSystemPrompt !== "boolean") {
40797
+ deps.writeJson(res, 400, { error: "invalid_replace_system_prompt" });
40798
+ return;
40799
+ }
40800
+ if (body.enableMetaphor !== void 0 && typeof body.enableMetaphor !== "boolean") {
40801
+ deps.writeJson(res, 400, { error: "invalid_enable_metaphor" });
40802
+ return;
40803
+ }
40804
+ const updated = deps.globalOptionsService.update((current) => ({
40805
+ ...current,
40806
+ ...typeof body.replaceSystemPrompt === "boolean" ? { replaceSystemPrompt: body.replaceSystemPrompt } : {},
40807
+ ...typeof body.enableMetaphor === "boolean" ? { enableMetaphor: body.enableMetaphor } : {}
40808
+ }));
40809
+ const response = { state: toGlobalSettingsState(updated) };
40810
+ deps.writeJson(res, 200, response);
40811
+ }
40812
+ function toGlobalSettingsState(data) {
40813
+ return {
40814
+ replaceSystemPrompt: data.replaceSystemPrompt ?? false,
40815
+ enableMetaphor: data.enableMetaphor ?? false
40816
+ };
40817
+ }
40818
+ function isJsonRequest2(req) {
40819
+ const contentType = req.headers["content-type"];
40820
+ return typeof contentType === "string" && contentType.toLowerCase().split(";")[0]?.trim() === "application/json";
40821
+ }
40822
+
40823
+ // src/model-auth-routes.ts
40824
+ var MODEL_AUTH_PROVIDERS = [
40825
+ { cli: "claude-kimi", displayName: "Moonshot Kimi" },
40826
+ { cli: "claude-glm", displayName: "ZhipuAI GLM" }
40827
+ ];
40828
+ var UPSTREAM_FAILURE_STATUSES = /* @__PURE__ */ new Set(["timeout", "network", "server"]);
40829
+ var MODEL_AUTH_API_CATALOG = [
40830
+ {
40831
+ method: "GET",
40832
+ path: "/model-auth/state",
40833
+ summary: "Get the model login status.",
40834
+ category: "Model Auth",
40835
+ gate: "loopback"
40836
+ },
40837
+ {
40838
+ method: "PUT",
40839
+ path: "/model-auth/providers/:cli",
40840
+ summary: "Register a model provider API key.",
40841
+ category: "Model Auth",
40842
+ gate: "terminal-origin"
40843
+ },
40844
+ {
40845
+ method: "DELETE",
40846
+ path: "/model-auth/providers/:cli",
40847
+ summary: "Remove a model provider API key.",
40848
+ category: "Model Auth",
40849
+ gate: "terminal-origin"
40850
+ }
40851
+ ];
40852
+ function createModelAuthRouter(deps) {
40853
+ return async function handleModelAuthRoute(context) {
40854
+ const { req, res, pathname } = context;
40855
+ if (pathname === "/model-auth/state") {
40856
+ if (req.method !== "GET") {
40857
+ deps.writeJson(res, 405, { error: "Method not allowed" });
40858
+ return true;
40859
+ }
40860
+ deps.writeJson(res, 200, await buildModelAuthState(deps.authService));
40861
+ return true;
40862
+ }
40863
+ const cli = parseProviderPath(pathname);
40864
+ if (!cli) return false;
40865
+ const provider = MODEL_AUTH_PROVIDERS.find((entry) => entry.cli === cli);
40866
+ if (!provider) {
40867
+ deps.writeJson(res, 404, { error: "provider_not_found" });
40868
+ return true;
40869
+ }
40870
+ if (req.method === "PUT") {
40871
+ await signInProvider(req, res, deps, provider);
40872
+ return true;
40873
+ }
40874
+ if (req.method === "DELETE") {
40875
+ await signOutProvider(req, res, deps, provider);
40876
+ return true;
40877
+ }
40878
+ deps.writeJson(res, 405, { error: "Method not allowed" });
40879
+ return true;
40880
+ };
40881
+ }
40882
+ async function buildModelAuthState(authService) {
40883
+ const signedInIds = new Set(await authService.listProviderIds());
40884
+ return {
40885
+ providers: MODEL_AUTH_PROVIDERS.map((provider) => toProviderState(provider, signedInIds))
40886
+ };
40887
+ }
40888
+ async function signInProvider(req, res, deps, provider) {
40889
+ if (!deps.isAuthorized(req)) {
40890
+ deps.writeJson(res, 401, { error: "unauthorized" });
40891
+ return;
40892
+ }
40893
+ if (!isJsonRequest3(req)) {
40894
+ deps.writeJson(res, 415, { error: "unsupported_media_type" });
40895
+ return;
40896
+ }
40897
+ const body = await deps.readJsonBody(req);
40898
+ if (!body || typeof body !== "object" || Array.isArray(body)) {
40899
+ deps.writeJson(res, 400, { error: "invalid_json" });
40900
+ return;
40901
+ }
40902
+ const apiKey = typeof body.apiKey === "string" ? body.apiKey.trim() : "";
40903
+ if (apiKey.length === 0) {
40904
+ deps.writeJson(res, 400, { error: "invalid_api_key" });
40905
+ return;
40906
+ }
40907
+ const providerId = CLI_TO_AUTH_PROVIDER_ID[provider.cli];
40908
+ if (!providerId) {
40909
+ deps.writeJson(res, 500, { error: "provider_unavailable" });
40910
+ return;
40911
+ }
40912
+ const validation = await deps.validateApiKey(provider.cli, apiKey);
40913
+ if (validation.status !== "success") {
40914
+ const status = UPSTREAM_FAILURE_STATUSES.has(validation.status) ? 502 : 400;
40915
+ deps.writeJson(res, status, {
40916
+ error: formatSignInFailureMessage(provider.displayName, validation.status),
40917
+ status: validation.status
40918
+ });
40919
+ return;
40920
+ }
40921
+ await deps.authService.setApiKey(providerId, apiKey);
40922
+ await writeMutationState2(res, deps);
40923
+ }
40924
+ async function signOutProvider(req, res, deps, provider) {
40925
+ if (!deps.isAuthorized(req)) {
40926
+ deps.writeJson(res, 401, { error: "unauthorized" });
40927
+ return;
40928
+ }
40929
+ const providerId = CLI_TO_AUTH_PROVIDER_ID[provider.cli];
40930
+ if (!providerId) {
40931
+ deps.writeJson(res, 500, { error: "provider_unavailable" });
40932
+ return;
40933
+ }
40934
+ await deps.authService.deleteApiKey(providerId);
40935
+ await writeMutationState2(res, deps);
40936
+ }
40937
+ async function writeMutationState2(res, deps) {
40938
+ const response = { state: await buildModelAuthState(deps.authService) };
40939
+ deps.writeJson(res, 200, response);
40940
+ }
40941
+ function toProviderState(provider, signedInIds) {
40942
+ const providerId = CLI_TO_AUTH_PROVIDER_ID[provider.cli] ?? provider.cli;
40943
+ return {
40944
+ cli: provider.cli,
40945
+ displayName: provider.displayName,
40946
+ signedIn: signedInIds.has(providerId)
40947
+ };
40948
+ }
40949
+ function parseProviderPath(pathname) {
40950
+ const parts = pathname.split("/").filter(Boolean);
40951
+ if (parts.length !== 3 || parts[0] !== "model-auth" || parts[1] !== "providers") return null;
40952
+ const cli = safeDecodeURIComponent2(parts[2] ?? "");
40953
+ return cli ? cli : null;
40954
+ }
40955
+ function safeDecodeURIComponent2(value) {
40956
+ try {
40957
+ return decodeURIComponent(value);
40958
+ } catch {
40959
+ return null;
40960
+ }
40961
+ }
40962
+ function isJsonRequest3(req) {
40963
+ const contentType = req.headers["content-type"];
40964
+ return typeof contentType === "string" && contentType.toLowerCase().split(";")[0]?.trim() === "application/json";
40965
+ }
40966
+ function formatSignInFailureMessage(displayName, status) {
40967
+ switch (status) {
40968
+ case "unauthorized":
40969
+ return `${displayName} rejected the API key. Check the key and try again.`;
40970
+ case "forbidden":
40971
+ return `The API key is not allowed for ${displayName}. Check its permissions.`;
40972
+ case "timeout":
40973
+ return `Validating the ${displayName} API key timed out. Check your connection and try again.`;
40974
+ case "network":
40975
+ return `Could not reach ${displayName} to validate the API key. Check your connection and try again.`;
40976
+ case "server":
40977
+ return `${displayName} returned an error while validating the API key. Try again later.`;
40978
+ default:
40979
+ return `Could not validate the ${displayName} API key. Check the key and try again.`;
40980
+ }
40981
+ }
40982
+
40983
+ // src/api-catalog.ts
40984
+ var compareApiCatalogEntries = (left, right) => left.category.localeCompare(right.category) || left.path.localeCompare(right.path) || left.method.localeCompare(right.method);
40985
+ function buildApiCatalog() {
40986
+ return [
40987
+ ...SERVER_API_CATALOG,
40988
+ ...CARRIER_SETTINGS_API_CATALOG,
40989
+ ...GLOBAL_SETTINGS_API_CATALOG,
40990
+ ...AGENT_CLI_API_CATALOG,
40991
+ ...MODEL_AUTH_API_CATALOG
40992
+ ].slice().sort(compareApiCatalogEntries);
40993
+ }
40994
+
40686
40995
  // src/codex/security-headers.ts
40687
40996
  var CONTENT_SECURITY_POLICY = "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'; object-src 'none'; base-uri 'none'";
40688
40997
  var SECURITY_HEADERS = {
@@ -41598,7 +41907,7 @@ function createCodexGateway(deps) {
41598
41907
  return true;
41599
41908
  }
41600
41909
  if (selected.kind === "no-workspace") {
41601
- if (isJsonRequest2(request)) {
41910
+ if (isJsonRequest4(request)) {
41602
41911
  sendJson2(response, 404, { error: "no_workspace_registered" });
41603
41912
  return true;
41604
41913
  }
@@ -41719,7 +42028,7 @@ function legacyWorkspacePath(url2) {
41719
42028
  }
41720
42029
  return null;
41721
42030
  }
41722
- function isJsonRequest2(request) {
42031
+ function isJsonRequest4(request) {
41723
42032
  const accept = Array.isArray(request.headers.accept) ? request.headers.accept.join(",") : request.headers.accept ?? "";
41724
42033
  const requestedWith = Array.isArray(request.headers["x-requested-with"]) ? request.headers["x-requested-with"].join(",") : request.headers["x-requested-with"] ?? "";
41725
42034
  return accept.includes("application/json") || requestedWith.toLowerCase() === "xmlhttprequest";
@@ -42014,73 +42323,6 @@ function looksSecretToken(rawToken) {
42014
42323
  if (SECRET_PREFIX_PATTERN.test(token)) return true;
42015
42324
  return token.length >= SECRET_MIN_TOKEN_LENGTH && SECRET_CHARSET_PATTERN.test(token) && /[0-9]/.test(token) && /[A-Za-z]/.test(token);
42016
42325
  }
42017
-
42018
- // src/global-settings-routes.ts
42019
- function createGlobalSettingsRouter(deps) {
42020
- return async function handleGlobalSettingsRoute(context) {
42021
- const { req, res, pathname } = context;
42022
- if (pathname === "/global-settings/state") {
42023
- if (req.method !== "GET") {
42024
- deps.writeJson(res, 405, { error: "Method not allowed" });
42025
- return true;
42026
- }
42027
- deps.writeJson(res, 200, buildGlobalSettingsState(deps.globalOptionsService));
42028
- return true;
42029
- }
42030
- if (pathname === "/global-settings") {
42031
- if (req.method !== "PUT") {
42032
- deps.writeJson(res, 405, { error: "Method not allowed" });
42033
- return true;
42034
- }
42035
- await mutateGlobalSettings(req, res, deps);
42036
- return true;
42037
- }
42038
- return false;
42039
- };
42040
- }
42041
- function buildGlobalSettingsState(service) {
42042
- return toGlobalSettingsState(service.load());
42043
- }
42044
- async function mutateGlobalSettings(req, res, deps) {
42045
- if (!deps.isAuthorized(req)) {
42046
- deps.writeJson(res, 401, { error: "unauthorized" });
42047
- return;
42048
- }
42049
- if (!isJsonRequest3(req)) {
42050
- deps.writeJson(res, 415, { error: "unsupported_media_type" });
42051
- return;
42052
- }
42053
- const body = await deps.readJsonBody(req);
42054
- if (!body || typeof body !== "object" || Array.isArray(body)) {
42055
- deps.writeJson(res, 400, { error: "invalid_json" });
42056
- return;
42057
- }
42058
- if (body.replaceSystemPrompt !== void 0 && typeof body.replaceSystemPrompt !== "boolean") {
42059
- deps.writeJson(res, 400, { error: "invalid_replace_system_prompt" });
42060
- return;
42061
- }
42062
- if (body.enableMetaphor !== void 0 && typeof body.enableMetaphor !== "boolean") {
42063
- deps.writeJson(res, 400, { error: "invalid_enable_metaphor" });
42064
- return;
42065
- }
42066
- const updated = deps.globalOptionsService.update((current) => ({
42067
- ...current,
42068
- ...typeof body.replaceSystemPrompt === "boolean" ? { replaceSystemPrompt: body.replaceSystemPrompt } : {},
42069
- ...typeof body.enableMetaphor === "boolean" ? { enableMetaphor: body.enableMetaphor } : {}
42070
- }));
42071
- const response = { state: toGlobalSettingsState(updated) };
42072
- deps.writeJson(res, 200, response);
42073
- }
42074
- function toGlobalSettingsState(data) {
42075
- return {
42076
- replaceSystemPrompt: data.replaceSystemPrompt ?? false,
42077
- enableMetaphor: data.enableMetaphor ?? false
42078
- };
42079
- }
42080
- function isJsonRequest3(req) {
42081
- const contentType = req.headers["content-type"];
42082
- return typeof contentType === "string" && contentType.toLowerCase().split(";")[0]?.trim() === "application/json";
42083
- }
42084
42326
  var BINARY_DISPLAY_NAMES = {
42085
42327
  claude: "Claude Code",
42086
42328
  codex: "Codex CLI",
@@ -42180,161 +42422,6 @@ function combineAgentCliLaunchMetadata(metadata, installStatuses, authStatuses)
42180
42422
  }));
42181
42423
  }
42182
42424
 
42183
- // src/agent-cli-routes.ts
42184
- function createAgentCliRouter(deps) {
42185
- return async function handleAgentCliRoute(context) {
42186
- const { req, res, pathname } = context;
42187
- if (pathname === "/agent-cli/state") {
42188
- if (req.method !== "GET") {
42189
- deps.writeJson(res, 405, { error: "Method not allowed" });
42190
- return true;
42191
- }
42192
- const clis = await deps.detect();
42193
- const body = { clis };
42194
- deps.writeJson(res, 200, body);
42195
- return true;
42196
- }
42197
- return false;
42198
- };
42199
- }
42200
-
42201
- // src/model-auth-routes.ts
42202
- var MODEL_AUTH_PROVIDERS = [
42203
- { cli: "claude-kimi", displayName: "Moonshot Kimi" },
42204
- { cli: "claude-glm", displayName: "ZhipuAI GLM" }
42205
- ];
42206
- var UPSTREAM_FAILURE_STATUSES = /* @__PURE__ */ new Set(["timeout", "network", "server"]);
42207
- function createModelAuthRouter(deps) {
42208
- return async function handleModelAuthRoute(context) {
42209
- const { req, res, pathname } = context;
42210
- if (pathname === "/model-auth/state") {
42211
- if (req.method !== "GET") {
42212
- deps.writeJson(res, 405, { error: "Method not allowed" });
42213
- return true;
42214
- }
42215
- deps.writeJson(res, 200, await buildModelAuthState(deps.authService));
42216
- return true;
42217
- }
42218
- const cli = parseProviderPath(pathname);
42219
- if (!cli) return false;
42220
- const provider = MODEL_AUTH_PROVIDERS.find((entry) => entry.cli === cli);
42221
- if (!provider) {
42222
- deps.writeJson(res, 404, { error: "provider_not_found" });
42223
- return true;
42224
- }
42225
- if (req.method === "PUT") {
42226
- await signInProvider(req, res, deps, provider);
42227
- return true;
42228
- }
42229
- if (req.method === "DELETE") {
42230
- await signOutProvider(req, res, deps, provider);
42231
- return true;
42232
- }
42233
- deps.writeJson(res, 405, { error: "Method not allowed" });
42234
- return true;
42235
- };
42236
- }
42237
- async function buildModelAuthState(authService) {
42238
- const signedInIds = new Set(await authService.listProviderIds());
42239
- return {
42240
- providers: MODEL_AUTH_PROVIDERS.map((provider) => toProviderState(provider, signedInIds))
42241
- };
42242
- }
42243
- async function signInProvider(req, res, deps, provider) {
42244
- if (!deps.isAuthorized(req)) {
42245
- deps.writeJson(res, 401, { error: "unauthorized" });
42246
- return;
42247
- }
42248
- if (!isJsonRequest4(req)) {
42249
- deps.writeJson(res, 415, { error: "unsupported_media_type" });
42250
- return;
42251
- }
42252
- const body = await deps.readJsonBody(req);
42253
- if (!body || typeof body !== "object" || Array.isArray(body)) {
42254
- deps.writeJson(res, 400, { error: "invalid_json" });
42255
- return;
42256
- }
42257
- const apiKey = typeof body.apiKey === "string" ? body.apiKey.trim() : "";
42258
- if (apiKey.length === 0) {
42259
- deps.writeJson(res, 400, { error: "invalid_api_key" });
42260
- return;
42261
- }
42262
- const providerId = CLI_TO_AUTH_PROVIDER_ID[provider.cli];
42263
- if (!providerId) {
42264
- deps.writeJson(res, 500, { error: "provider_unavailable" });
42265
- return;
42266
- }
42267
- const validation = await deps.validateApiKey(provider.cli, apiKey);
42268
- if (validation.status !== "success") {
42269
- const status = UPSTREAM_FAILURE_STATUSES.has(validation.status) ? 502 : 400;
42270
- deps.writeJson(res, status, {
42271
- error: formatSignInFailureMessage(provider.displayName, validation.status),
42272
- status: validation.status
42273
- });
42274
- return;
42275
- }
42276
- await deps.authService.setApiKey(providerId, apiKey);
42277
- await writeMutationState2(res, deps);
42278
- }
42279
- async function signOutProvider(req, res, deps, provider) {
42280
- if (!deps.isAuthorized(req)) {
42281
- deps.writeJson(res, 401, { error: "unauthorized" });
42282
- return;
42283
- }
42284
- const providerId = CLI_TO_AUTH_PROVIDER_ID[provider.cli];
42285
- if (!providerId) {
42286
- deps.writeJson(res, 500, { error: "provider_unavailable" });
42287
- return;
42288
- }
42289
- await deps.authService.deleteApiKey(providerId);
42290
- await writeMutationState2(res, deps);
42291
- }
42292
- async function writeMutationState2(res, deps) {
42293
- const response = { state: await buildModelAuthState(deps.authService) };
42294
- deps.writeJson(res, 200, response);
42295
- }
42296
- function toProviderState(provider, signedInIds) {
42297
- const providerId = CLI_TO_AUTH_PROVIDER_ID[provider.cli] ?? provider.cli;
42298
- return {
42299
- cli: provider.cli,
42300
- displayName: provider.displayName,
42301
- signedIn: signedInIds.has(providerId)
42302
- };
42303
- }
42304
- function parseProviderPath(pathname) {
42305
- const parts = pathname.split("/").filter(Boolean);
42306
- if (parts.length !== 3 || parts[0] !== "model-auth" || parts[1] !== "providers") return null;
42307
- const cli = safeDecodeURIComponent2(parts[2] ?? "");
42308
- return cli ? cli : null;
42309
- }
42310
- function safeDecodeURIComponent2(value) {
42311
- try {
42312
- return decodeURIComponent(value);
42313
- } catch {
42314
- return null;
42315
- }
42316
- }
42317
- function isJsonRequest4(req) {
42318
- const contentType = req.headers["content-type"];
42319
- return typeof contentType === "string" && contentType.toLowerCase().split(";")[0]?.trim() === "application/json";
42320
- }
42321
- function formatSignInFailureMessage(displayName, status) {
42322
- switch (status) {
42323
- case "unauthorized":
42324
- return `${displayName} rejected the API key. Check the key and try again.`;
42325
- case "forbidden":
42326
- return `The API key is not allowed for ${displayName}. Check its permissions.`;
42327
- case "timeout":
42328
- return `Validating the ${displayName} API key timed out. Check your connection and try again.`;
42329
- case "network":
42330
- return `Could not reach ${displayName} to validate the API key. Check your connection and try again.`;
42331
- case "server":
42332
- return `${displayName} returned an error while validating the API key. Try again later.`;
42333
- default:
42334
- return `Could not validate the ${displayName} API key. Check the key and try again.`;
42335
- }
42336
- }
42337
-
42338
42425
  // src/observability-routes.ts
42339
42426
  function writeObserverEvents(req, res, workspace, store2) {
42340
42427
  res.writeHead(200, withSecurityHeaders2({
@@ -44336,6 +44423,162 @@ var THEATER_SHELL_SESSION_PREFIX2 = "shell:";
44336
44423
  var SERVER_TIMEOUT_MS = 30 * 60 * 1e3;
44337
44424
  var MAX_BODY_BYTES = 1024 * 1024;
44338
44425
  var UPDATE_APPLY_FORBIDDEN_BODY_KEYS = /* @__PURE__ */ new Set(["channel", "package", "packageName", "packageVersion", "packages", "targetVersion", "version"]);
44426
+ var SERVER_API_CATALOG = [
44427
+ {
44428
+ method: "GET",
44429
+ path: "/observer/status",
44430
+ summary: "Get the console observation status.",
44431
+ category: "Observer",
44432
+ gate: "loopback"
44433
+ },
44434
+ {
44435
+ method: "GET",
44436
+ path: "/observer/api-catalog",
44437
+ summary: "Get the backend API catalog.",
44438
+ category: "Observer",
44439
+ gate: "loopback"
44440
+ },
44441
+ {
44442
+ method: "GET",
44443
+ path: "/observer/tenants",
44444
+ summary: "List observed terminal workspaces.",
44445
+ category: "Observer",
44446
+ gate: "loopback"
44447
+ },
44448
+ {
44449
+ method: "GET",
44450
+ path: "/observer/jobs",
44451
+ summary: "List observed carrier jobs.",
44452
+ category: "Observer",
44453
+ gate: "loopback"
44454
+ },
44455
+ {
44456
+ method: "GET",
44457
+ path: "/observer/events",
44458
+ summary: "Open the observation event stream.",
44459
+ category: "Observer",
44460
+ gate: "loopback"
44461
+ },
44462
+ {
44463
+ method: "GET",
44464
+ path: "/observer/theaters",
44465
+ summary: "List Theaters.",
44466
+ category: "Observer",
44467
+ gate: "loopback"
44468
+ },
44469
+ {
44470
+ method: "POST",
44471
+ path: "/observer/theaters",
44472
+ summary: "Register a new Theater.",
44473
+ category: "Observer",
44474
+ gate: "terminal-origin"
44475
+ },
44476
+ {
44477
+ method: "DELETE",
44478
+ path: "/observer/theaters/:theaterId",
44479
+ summary: "Remove a Theater and its Operations.",
44480
+ category: "Observer",
44481
+ gate: "terminal-origin"
44482
+ },
44483
+ {
44484
+ method: "POST",
44485
+ path: "/observer/theaters/:theaterId/sessions",
44486
+ summary: "Create a new Operation in a Theater.",
44487
+ category: "Observer",
44488
+ gate: "terminal-origin"
44489
+ },
44490
+ {
44491
+ method: "POST",
44492
+ path: "/terminal/ticket",
44493
+ summary: "Issue a terminal WebSocket connection ticket.",
44494
+ category: "Terminal",
44495
+ gate: "terminal-origin"
44496
+ },
44497
+ {
44498
+ method: "POST",
44499
+ path: "/terminal/folders/list",
44500
+ summary: "List terminal folder selection entries.",
44501
+ category: "Terminal",
44502
+ gate: "terminal-origin"
44503
+ },
44504
+ {
44505
+ method: "POST",
44506
+ path: "/terminal/folders/grants",
44507
+ summary: "Issue a terminal folder access grant.",
44508
+ category: "Terminal",
44509
+ gate: "terminal-origin"
44510
+ },
44511
+ {
44512
+ method: "GET",
44513
+ path: "/terminal/sessions",
44514
+ summary: "List terminal Operations.",
44515
+ category: "Terminal",
44516
+ gate: "terminal-origin"
44517
+ },
44518
+ {
44519
+ method: "POST",
44520
+ path: "/terminal/sessions",
44521
+ summary: "Create a new terminal Operation.",
44522
+ category: "Terminal",
44523
+ gate: "terminal-origin"
44524
+ },
44525
+ {
44526
+ method: "POST",
44527
+ path: "/terminal/sessions/:sessionId/resume",
44528
+ summary: "Resume a dormant Operation.",
44529
+ category: "Terminal",
44530
+ gate: "terminal-origin"
44531
+ },
44532
+ {
44533
+ method: "POST",
44534
+ path: "/terminal/sessions/:sessionId/turn",
44535
+ summary: "Receive an Agent CLI turn state hook.",
44536
+ category: "Terminal",
44537
+ gate: "lock-token"
44538
+ },
44539
+ {
44540
+ method: "POST",
44541
+ path: "/terminal/sessions/:sessionId/attention",
44542
+ summary: "Receive an input-waiting attention hook.",
44543
+ category: "Terminal",
44544
+ gate: "lock-token"
44545
+ },
44546
+ {
44547
+ method: "POST",
44548
+ path: "/terminal/sessions/:sessionId/auto-name",
44549
+ summary: "Receive an Operation auto-name hook.",
44550
+ category: "Terminal",
44551
+ gate: "lock-token"
44552
+ },
44553
+ {
44554
+ method: "DELETE",
44555
+ path: "/terminal/sessions/:sessionId",
44556
+ summary: "Remove a terminal Operation.",
44557
+ category: "Terminal",
44558
+ gate: "terminal-origin"
44559
+ },
44560
+ {
44561
+ method: "PATCH",
44562
+ path: "/terminal/sessions/:sessionId",
44563
+ summary: "Rename a terminal Operation.",
44564
+ category: "Terminal",
44565
+ gate: "terminal-origin"
44566
+ },
44567
+ {
44568
+ method: "POST",
44569
+ path: "/update/apply",
44570
+ summary: "Request console update application.",
44571
+ category: "Update",
44572
+ gate: "console-origin"
44573
+ },
44574
+ {
44575
+ method: "GET",
44576
+ path: "/health",
44577
+ summary: "Check console status with the lock token.",
44578
+ category: "Health",
44579
+ gate: "lock-token"
44580
+ }
44581
+ ];
44339
44582
  function createConsoleServer(deps = {}) {
44340
44583
  const host = deps.host ?? DEFAULT_HOST2;
44341
44584
  const port = deps.port ?? DEFAULT_PORT2;
@@ -44536,12 +44779,12 @@ function createConsoleServer(deps = {}) {
44536
44779
  handleObserverStatus(req, res);
44537
44780
  return;
44538
44781
  }
44539
- if (pathname === "/update/apply") {
44540
- runAsyncHandler(handleUpdateApply(req, res), res);
44782
+ if (pathname === "/observer/api-catalog") {
44783
+ handleObserverApiCatalog(req, res);
44541
44784
  return;
44542
44785
  }
44543
- if (pathname === "/observer/carriers") {
44544
- handleObserverCarriers(req, res);
44786
+ if (pathname === "/update/apply") {
44787
+ runAsyncHandler(handleUpdateApply(req, res), res);
44545
44788
  return;
44546
44789
  }
44547
44790
  if (pathname === "/carrier-settings" || pathname.startsWith("/carrier-settings/")) {
@@ -44987,6 +45230,9 @@ function createConsoleServer(deps = {}) {
44987
45230
  };
44988
45231
  writeJson(res, 200, payload);
44989
45232
  }
45233
+ function handleObserverApiCatalog(_req, res) {
45234
+ writeJson(res, 200, { version: version2, routes: buildApiCatalog() });
45235
+ }
44990
45236
  async function handleUpdateApply(req, res) {
44991
45237
  if (req.method !== "POST") {
44992
45238
  writeJson(res, 405, { error: "Method not allowed" });
@@ -45050,11 +45296,6 @@ function createConsoleServer(deps = {}) {
45050
45296
  const payload = { status: "accepted" };
45051
45297
  writeJson(res, 202, payload);
45052
45298
  }
45053
- function handleObserverCarriers(_req, res) {
45054
- writeJson(res, 200, {
45055
- carriers: readCarrierStatusEntries(carrierRegistry).map(toCarrierReadinessEntry)
45056
- });
45057
- }
45058
45299
  function handleObserverWorkspaces(_req, res) {
45059
45300
  writeJson(res, 200, { tenants: observability.listWorkspaces() });
45060
45301
  }
@@ -45124,20 +45365,6 @@ function createConsoleServer(deps = {}) {
45124
45365
  activeAdmiralCount: observability.listWorkspaces().filter((workspace) => workspace.theaterId === theater.id).length
45125
45366
  };
45126
45367
  }
45127
- function toCarrierReadinessEntry(entry) {
45128
- return {
45129
- carrierId: entry.carrierId,
45130
- displayName: entry.displayName,
45131
- role: entry.role,
45132
- model: entry.model,
45133
- effort: entry.effort,
45134
- taskForceBackendCount: entry.taskForceBackendCount,
45135
- subagentMode: entry.subagentMode,
45136
- ...entry.category ? { category: entry.category } : {},
45137
- slot: entry.slot,
45138
- cliType: entry.cliType
45139
- };
45140
- }
45141
45368
  function resolveWikiServerStatus(theaterId) {
45142
45369
  if (!theaterId) return "unknown";
45143
45370
  if (!theaters.get(theaterId)) return "unknown";