@dotobokuri/fleet-console 1.67.0 → 1.69.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 (68) hide show
  1. package/dist/cli.mjs +470 -49
  2. package/dist/client/assets/{_baseUniq-DG32CEpb.js → _baseUniq-BPBd-J9P.js} +1 -1
  3. package/dist/client/assets/{arc-CoHkSCMF.js → arc-spHqy4X3.js} +1 -1
  4. package/dist/client/assets/{architectureDiagram-Q4EWVU46-f0RKHqJg.js → architectureDiagram-Q4EWVU46-7CHqKfxu.js} +1 -1
  5. package/dist/client/assets/{blockDiagram-DXYQGD6D-Dxb3hLAV.js → blockDiagram-DXYQGD6D-YasFDgl_.js} +1 -1
  6. package/dist/client/assets/{c4Diagram-AHTNJAMY-C5q_ahSd.js → c4Diagram-AHTNJAMY-CcoPJq56.js} +1 -1
  7. package/dist/client/assets/channel-DfEjadrw.js +1 -0
  8. package/dist/client/assets/{chunk-4BX2VUAB-BS0W4Fpt.js → chunk-4BX2VUAB-MYBJn9BE.js} +1 -1
  9. package/dist/client/assets/{chunk-4TB4RGXK-p03eWKTO.js → chunk-4TB4RGXK-C1wg6GR_.js} +1 -1
  10. package/dist/client/assets/{chunk-55IACEB6-BB1ALVX2.js → chunk-55IACEB6-BoufMT1O.js} +1 -1
  11. package/dist/client/assets/{chunk-EDXVE4YY-DV4N-Npm.js → chunk-EDXVE4YY-BzAhAIl3.js} +1 -1
  12. package/dist/client/assets/{chunk-FMBD7UC4-Da8VspnD.js → chunk-FMBD7UC4-yVrLsKzP.js} +1 -1
  13. package/dist/client/assets/{chunk-OYMX7WX6-CWTmAQhy.js → chunk-OYMX7WX6-YiiKaqRQ.js} +1 -1
  14. package/dist/client/assets/{chunk-QZHKN3VN-DE9xUsy3.js → chunk-QZHKN3VN-CqWQlGHT.js} +1 -1
  15. package/dist/client/assets/{chunk-YZCP3GAM-BxriNNdB.js → chunk-YZCP3GAM-9yLOmU5k.js} +1 -1
  16. package/dist/client/assets/classDiagram-6PBFFD2Q-D9vQdv0q.js +1 -0
  17. package/dist/client/assets/classDiagram-v2-HSJHXN6E-D9vQdv0q.js +1 -0
  18. package/dist/client/assets/clone-Ck2x5JX2.js +1 -0
  19. package/dist/client/assets/{cose-bilkent-S5V4N54A-B4sjskIn.js → cose-bilkent-S5V4N54A-XkTuSq7v.js} +1 -1
  20. package/dist/client/assets/{dagre-KV5264BT-oJms5aS3.js → dagre-KV5264BT-DyzXIEAe.js} +1 -1
  21. package/dist/client/assets/{diagram-5BDNPKRD-BAbLGddM.js → diagram-5BDNPKRD-DF24YlCa.js} +1 -1
  22. package/dist/client/assets/{diagram-G4DWMVQ6-BrhRQwe-.js → diagram-G4DWMVQ6-CVhcj9RK.js} +1 -1
  23. package/dist/client/assets/{diagram-MMDJMWI5-Buxu7Ng3.js → diagram-MMDJMWI5-C-kGKk4K.js} +1 -1
  24. package/dist/client/assets/{diagram-TYMM5635-Cnp__7LJ.js → diagram-TYMM5635-mr285WbR.js} +1 -1
  25. package/dist/client/assets/{erDiagram-SMLLAGMA-ctmZHrVO.js → erDiagram-SMLLAGMA-BtEx-XlU.js} +1 -1
  26. package/dist/client/assets/{flowDiagram-DWJPFMVM-DsQXJqF_.js → flowDiagram-DWJPFMVM-DuWy3xzN.js} +1 -1
  27. package/dist/client/assets/{ganttDiagram-T4ZO3ILL-SAFJNY9M.js → ganttDiagram-T4ZO3ILL-B2-xEikU.js} +1 -1
  28. package/dist/client/assets/{gitGraphDiagram-UUTBAWPF-Bd5Dq0vQ.js → gitGraphDiagram-UUTBAWPF-EM17u_t7.js} +1 -1
  29. package/dist/client/assets/{graph-DzMOPhFp.js → graph-xuE12FIq.js} +1 -1
  30. package/dist/client/assets/index-C5EOZGlC.js +466 -0
  31. package/dist/client/assets/index-CHHE3nPw.css +1 -0
  32. package/dist/client/assets/{infoDiagram-42DDH7IO-BrEfG9P4.js → infoDiagram-42DDH7IO-B3MF4XtW.js} +1 -1
  33. package/dist/client/assets/{ishikawaDiagram-UXIWVN3A-Dg22orvH.js → ishikawaDiagram-UXIWVN3A-DoQ2mGyh.js} +1 -1
  34. package/dist/client/assets/{journeyDiagram-VCZTEJTY-DEcjEc6c.js → journeyDiagram-VCZTEJTY-GeR9sFH-.js} +1 -1
  35. package/dist/client/assets/{kanban-definition-6JOO6SKY-C2Xa4znN.js → kanban-definition-6JOO6SKY-DrrYMuvL.js} +1 -1
  36. package/dist/client/assets/{layout-B7E_-0ev.js → layout-DH63A-3u.js} +1 -1
  37. package/dist/client/assets/{linear-BXJsh3FL.js → linear-BIjE6zB1.js} +1 -1
  38. package/dist/client/assets/{mermaid.core-CdZpLnyY.js → mermaid.core-yrrC2Lqo.js} +4 -4
  39. package/dist/client/assets/{min-CEAFFcJY.js → min-CR-H8E6U.js} +1 -1
  40. package/dist/client/assets/{mindmap-definition-QFDTVHPH-iXzcnu1C.js → mindmap-definition-QFDTVHPH-BzSC43J-.js} +1 -1
  41. package/dist/client/assets/{pieDiagram-DEJITSTG-CdRN75ad.js → pieDiagram-DEJITSTG-BdghNtCc.js} +1 -1
  42. package/dist/client/assets/{quadrantDiagram-34T5L4WZ-Dscl0EFH.js → quadrantDiagram-34T5L4WZ-s_zN2epw.js} +1 -1
  43. package/dist/client/assets/{requirementDiagram-MS252O5E-CLmSCaQs.js → requirementDiagram-MS252O5E-DuiGG6Tx.js} +1 -1
  44. package/dist/client/assets/{sankeyDiagram-XADWPNL6-BfPk87jf.js → sankeyDiagram-XADWPNL6-Bp0JBk2g.js} +1 -1
  45. package/dist/client/assets/{sequenceDiagram-FGHM5R23-DE8sU8ej.js → sequenceDiagram-FGHM5R23-AzQ3M31V.js} +1 -1
  46. package/dist/client/assets/{stateDiagram-FHFEXIEX-BmaQc1Nm.js → stateDiagram-FHFEXIEX-BGgm44ev.js} +1 -1
  47. package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-CZDbnuN-.js +1 -0
  48. package/dist/client/assets/{timeline-definition-GMOUNBTQ-C4Z0umzx.js → timeline-definition-GMOUNBTQ-UqfsiBJY.js} +1 -1
  49. package/dist/client/assets/{vennDiagram-DHZGUBPP-BKlcRXlE.js → vennDiagram-DHZGUBPP-PsCGF9nR.js} +1 -1
  50. package/dist/client/assets/{wardley-RL74JXVD-B0RT7bAW.js → wardley-RL74JXVD-BDQbnh-d.js} +1 -1
  51. package/dist/client/assets/{wardleyDiagram-NUSXRM2D-mx28kvam.js → wardleyDiagram-NUSXRM2D-CtVA1JMs.js} +1 -1
  52. package/dist/client/assets/{xychartDiagram-5P7HB3ND-DU6qIPI0.js → xychartDiagram-5P7HB3ND-BsLlZWbc.js} +1 -1
  53. package/dist/client/index.html +2 -2
  54. package/dist/fleet-plugins/file-explorer/routes.mjs +21 -2
  55. package/dist/fleet-plugins/ledger/routes.mjs +100 -3
  56. package/dist/fleet-plugins/quota/routes.mjs +100 -3
  57. package/dist/fleet-plugins/repository/routes.mjs +910 -26
  58. package/dist/fleet-plugins/scuttlebutt/routes.mjs +102 -4
  59. package/dist/fleet-plugins/terminal/routes.mjs +717 -935
  60. package/dist/fleet.mjs +923 -807
  61. package/package.json +1 -1
  62. package/dist/client/assets/channel-C-Qx-Oi-.js +0 -1
  63. package/dist/client/assets/classDiagram-6PBFFD2Q-DA7e8Mft.js +0 -1
  64. package/dist/client/assets/classDiagram-v2-HSJHXN6E-DA7e8Mft.js +0 -1
  65. package/dist/client/assets/clone-Rpb38n4i.js +0 -1
  66. package/dist/client/assets/index-BLA_qnPk.css +0 -1
  67. package/dist/client/assets/index-CGE8u6Es.js +0 -465
  68. package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-TcoFpvuT.js +0 -1
package/dist/cli.mjs CHANGED
@@ -917,16 +917,14 @@ function sanitizeGlobalOptionsData(value) {
917
917
  return { data: createEmptyGlobalOptionsData(), changed: true };
918
918
  }
919
919
  const agentIdleDormantMinutes = sanitizeAgentIdleDormantMinutes(value.agentIdleDormantMinutes);
920
- const hasCanonicalMode = "claudeGatewaySystemPromptMode" in value;
921
- const validMode = sanitizeClaudeGatewaySystemPromptMode(value.claudeGatewaySystemPromptMode);
922
- const claudeGatewaySystemPromptMode = validMode ?? (!hasCanonicalMode && value.replaceClaudeGatewaySystemPrompt === true ? "replace" : "append");
920
+ const claudeCodeSystemPrompt = sanitizeClaudeCodeSystemPrompt(value.claudeCodeSystemPrompt);
923
921
  const data = {
924
922
  version: GLOBAL_OPTIONS_VERSION,
925
923
  ...agentIdleDormantMinutes !== void 0 ? { agentIdleDormantMinutes } : {},
926
- claudeGatewaySystemPromptMode
924
+ ...claudeCodeSystemPrompt !== void 0 ? { claudeCodeSystemPrompt } : {}
927
925
  };
928
- const allowedKeys = /* @__PURE__ */ new Set(["version", "agentIdleDormantMinutes", "claudeGatewaySystemPromptMode"]);
929
- const changed = Object.keys(value).some((key) => !allowedKeys.has(key)) || "agentIdleDormantMinutes" in value && agentIdleDormantMinutes === void 0 || validMode === void 0;
926
+ const allowedKeys = /* @__PURE__ */ new Set(["version", "agentIdleDormantMinutes", "claudeCodeSystemPrompt"]);
927
+ const changed = Object.keys(value).some((key) => !allowedKeys.has(key)) || "agentIdleDormantMinutes" in value && agentIdleDormantMinutes === void 0 || "claudeCodeSystemPrompt" in value && claudeCodeSystemPrompt === void 0;
930
928
  return { data, changed };
931
929
  }
932
930
  function sanitizeAgentIdleDormantMinutes(value) {
@@ -934,8 +932,8 @@ function sanitizeAgentIdleDormantMinutes(value) {
934
932
  if (typeof value === "number" && Number.isFinite(value) && Number.isInteger(value) && value > 0) return value;
935
933
  return void 0;
936
934
  }
937
- function sanitizeClaudeGatewaySystemPromptMode(value) {
938
- return value === "append" || value === "replace" || value === "off" ? value : void 0;
935
+ function sanitizeClaudeCodeSystemPrompt(value) {
936
+ return value === "on" || value === "off" ? value : void 0;
939
937
  }
940
938
  function isRecord(value) {
941
939
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -12259,6 +12257,48 @@ function createDesktopThemeRouter(deps) {
12259
12257
  return true;
12260
12258
  };
12261
12259
  }
12260
+ var DESKTOP_UPDATE_PATH = "/api/v1/desktop/update";
12261
+ var DESKTOP_UPDATE_EVENTS_PATH = "/api/v1/desktop/update/events";
12262
+ var DESKTOP_UPDATE_EVENT = "desktop:update";
12263
+ var emptyDesktopUpdateRequest = () => ({ requestedVersion: null, requestId: null });
12264
+ var DESKTOP_UPDATE_API_CATALOG = [
12265
+ {
12266
+ method: "GET",
12267
+ path: DESKTOP_UPDATE_PATH,
12268
+ summary: "Read whether an update was requested for the shell that owns this window to perform.",
12269
+ category: "Desktop",
12270
+ gate: "origin-strict",
12271
+ transport: "http"
12272
+ },
12273
+ {
12274
+ method: "GET",
12275
+ path: DESKTOP_UPDATE_EVENTS_PATH,
12276
+ summary: "Stream update requests the owning shell must perform.",
12277
+ category: "Desktop",
12278
+ gate: "origin-strict",
12279
+ transport: "sse"
12280
+ }
12281
+ ];
12282
+ function createDesktopUpdateRouter(deps) {
12283
+ return ({ req, res, pathname }) => {
12284
+ if (pathname !== DESKTOP_UPDATE_PATH && pathname !== DESKTOP_UPDATE_EVENTS_PATH) return false;
12285
+ if (req.method !== "GET") {
12286
+ deps.writeJson(res, 405, { error: "Method not allowed" });
12287
+ return true;
12288
+ }
12289
+ if (!deps.isAuthorized(req)) {
12290
+ deps.writeJson(res, 401, { error: "unauthorized" });
12291
+ return true;
12292
+ }
12293
+ const snapshot = deps.getUpdateRequest();
12294
+ if (pathname === DESKTOP_UPDATE_PATH) {
12295
+ deps.writeJson(res, 200, snapshot);
12296
+ return true;
12297
+ }
12298
+ deps.subscribe(res, snapshot);
12299
+ return true;
12300
+ };
12301
+ }
12262
12302
  var REMOTE_AUTO_PORT_MIN = 49152;
12263
12303
  var REMOTE_AUTO_PORT_MAX = 65535;
12264
12304
  var REMOTE_AUTO_PORT_ATTEMPTS = 12;
@@ -13307,6 +13347,7 @@ function buildApiCatalog(extraEntries = []) {
13307
13347
  ...DESKTOP_FULLSCREEN_API_CATALOG,
13308
13348
  ...DESKTOP_SHELL_API_CATALOG,
13309
13349
  ...DESKTOP_THEME_API_CATALOG,
13350
+ ...DESKTOP_UPDATE_API_CATALOG,
13310
13351
  ...GLOBAL_SETTINGS_API_CATALOG,
13311
13352
  ...PLUGIN_SETTINGS_API_CATALOG,
13312
13353
  ...SYSTEM_FONTS_API_CATALOG,
@@ -16882,10 +16923,10 @@ function mergeDefs(...defs) {
16882
16923
  function cloneDef(schema) {
16883
16924
  return mergeDefs(schema._zod.def);
16884
16925
  }
16885
- function getElementAtPath(obj, path42) {
16886
- if (!path42)
16926
+ function getElementAtPath(obj, path43) {
16927
+ if (!path43)
16887
16928
  return obj;
16888
- return path42.reduce((acc, key) => acc?.[key], obj);
16929
+ return path43.reduce((acc, key) => acc?.[key], obj);
16889
16930
  }
16890
16931
  function promiseAllObject(promisesObj) {
16891
16932
  const keys = Object.keys(promisesObj);
@@ -17294,11 +17335,11 @@ function explicitlyAborted(x, startIndex = 0) {
17294
17335
  }
17295
17336
  return false;
17296
17337
  }
17297
- function prefixIssues(path42, issues) {
17338
+ function prefixIssues(path43, issues) {
17298
17339
  return issues.map((iss) => {
17299
17340
  var _a3;
17300
17341
  (_a3 = iss).path ?? (_a3.path = []);
17301
- iss.path.unshift(path42);
17342
+ iss.path.unshift(path43);
17302
17343
  return iss;
17303
17344
  });
17304
17345
  }
@@ -17445,16 +17486,16 @@ function flattenError(error51, mapper = (issue3) => issue3.message) {
17445
17486
  }
17446
17487
  function formatError2(error51, mapper = (issue3) => issue3.message) {
17447
17488
  const fieldErrors = { _errors: [] };
17448
- const processError = (error52, path42 = []) => {
17489
+ const processError = (error52, path43 = []) => {
17449
17490
  for (const issue3 of error52.issues) {
17450
17491
  if (issue3.code === "invalid_union" && issue3.errors.length) {
17451
- issue3.errors.map((issues) => processError({ issues }, [...path42, ...issue3.path]));
17492
+ issue3.errors.map((issues) => processError({ issues }, [...path43, ...issue3.path]));
17452
17493
  } else if (issue3.code === "invalid_key") {
17453
- processError({ issues: issue3.issues }, [...path42, ...issue3.path]);
17494
+ processError({ issues: issue3.issues }, [...path43, ...issue3.path]);
17454
17495
  } else if (issue3.code === "invalid_element") {
17455
- processError({ issues: issue3.issues }, [...path42, ...issue3.path]);
17496
+ processError({ issues: issue3.issues }, [...path43, ...issue3.path]);
17456
17497
  } else {
17457
- const fullpath = [...path42, ...issue3.path];
17498
+ const fullpath = [...path43, ...issue3.path];
17458
17499
  if (fullpath.length === 0) {
17459
17500
  fieldErrors._errors.push(mapper(issue3));
17460
17501
  } else {
@@ -17481,17 +17522,17 @@ function formatError2(error51, mapper = (issue3) => issue3.message) {
17481
17522
  }
17482
17523
  function treeifyError(error51, mapper = (issue3) => issue3.message) {
17483
17524
  const result = { errors: [] };
17484
- const processError = (error52, path42 = []) => {
17525
+ const processError = (error52, path43 = []) => {
17485
17526
  var _a3, _b;
17486
17527
  for (const issue3 of error52.issues) {
17487
17528
  if (issue3.code === "invalid_union" && issue3.errors.length) {
17488
- issue3.errors.map((issues) => processError({ issues }, [...path42, ...issue3.path]));
17529
+ issue3.errors.map((issues) => processError({ issues }, [...path43, ...issue3.path]));
17489
17530
  } else if (issue3.code === "invalid_key") {
17490
- processError({ issues: issue3.issues }, [...path42, ...issue3.path]);
17531
+ processError({ issues: issue3.issues }, [...path43, ...issue3.path]);
17491
17532
  } else if (issue3.code === "invalid_element") {
17492
- processError({ issues: issue3.issues }, [...path42, ...issue3.path]);
17533
+ processError({ issues: issue3.issues }, [...path43, ...issue3.path]);
17493
17534
  } else {
17494
- const fullpath = [...path42, ...issue3.path];
17535
+ const fullpath = [...path43, ...issue3.path];
17495
17536
  if (fullpath.length === 0) {
17496
17537
  result.errors.push(mapper(issue3));
17497
17538
  continue;
@@ -17523,8 +17564,8 @@ function treeifyError(error51, mapper = (issue3) => issue3.message) {
17523
17564
  }
17524
17565
  function toDotPath(_path) {
17525
17566
  const segs = [];
17526
- const path42 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
17527
- for (const seg of path42) {
17567
+ const path43 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
17568
+ for (const seg of path43) {
17528
17569
  if (typeof seg === "number")
17529
17570
  segs.push(`[${seg}]`);
17530
17571
  else if (typeof seg === "symbol")
@@ -30188,13 +30229,13 @@ function resolveRef(ref, ctx) {
30188
30229
  if (!ref.startsWith("#")) {
30189
30230
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
30190
30231
  }
30191
- const path42 = ref.slice(1).split("/").filter(Boolean);
30192
- if (path42.length === 0) {
30232
+ const path43 = ref.slice(1).split("/").filter(Boolean);
30233
+ if (path43.length === 0) {
30193
30234
  return ctx.rootSchema;
30194
30235
  }
30195
30236
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
30196
- if (path42[0] === defsKey) {
30197
- const key = path42[1];
30237
+ if (path43[0] === defsKey) {
30238
+ const key = path43[1];
30198
30239
  if (!key || !ctx.defs[key]) {
30199
30240
  throw new Error(`Reference not found: ${ref}`);
30200
30241
  }
@@ -33182,8 +33223,8 @@ function bootEnumDescriptorProto(init) {
33182
33223
  }
33183
33224
 
33184
33225
  // ../../node_modules/.pnpm/@bufbuild+protobuf@2.13.0/node_modules/@bufbuild/protobuf/dist/esm/codegenv2/message.js
33185
- function messageDesc(file2, path42, ...paths) {
33186
- return paths.reduce((acc, cur) => acc.nestedMessages[cur], file2.messages[path42]);
33226
+ function messageDesc(file2, path43, ...paths) {
33227
+ return paths.reduce((acc, cur) => acc.nestedMessages[cur], file2.messages[path43]);
33187
33228
  }
33188
33229
 
33189
33230
  // ../../node_modules/.pnpm/@bufbuild+protobuf@2.13.0/node_modules/@bufbuild/protobuf/dist/esm/wkt/gen/google/protobuf/descriptor_pb.js
@@ -33778,7 +33819,7 @@ var benchmarks_default = {
33778
33819
  };
33779
33820
  var models_default = {
33780
33821
  version: 1,
33781
- updatedAt: "2026-08-17T00:00:00Z",
33822
+ updatedAt: "2026-08-20T00:00:00Z",
33782
33823
  providers: {
33783
33824
  codex: {
33784
33825
  name: "Codex",
@@ -34174,7 +34215,7 @@ var models_default = {
34174
34215
  cursor: {
34175
34216
  name: "Cursor",
34176
34217
  defaultModel: "auto",
34177
- source: "Cursor GetUsableModels + Run conversationCheckpointUpdate.token_details.max_tokens (cli-2026.07.08-0c04a8a; auto, composer-2.5, and grok-4.5 families observed 2026-08-01); cursor-agent 2026.08.11-e8db854 observed 2026-08-13 for grok-4.6; claude-opus-5 and claude-fable-5 standard/Max Mode windows observed 2026-08-10; quotaScope from DashboardService/GetCurrentPeriodUsage autoBucketModels (2026-08-05)",
34218
+ source: "Cursor GetUsableModels + Run conversationCheckpointUpdate.token_details.max_tokens (cli-2026.07.08-0c04a8a; auto, composer-2.5, and grok-4.5 families observed 2026-08-01); cursor-agent 2026.08.11-e8db854 observed 2026-08-13 for grok-4.6; claude-opus-5 and claude-fable-5 standard/Max Mode windows observed 2026-08-10; quotaScope from DashboardService/GetCurrentPeriodUsage autoBucketModels (2026-08-05); gpt-5.6-sol/terra/luna, gemini-3.7-flash, and kimi-k3 ids, effort rungs, and api quotaScope observed 2026-08-20 from live GetUsableModels (cursor-agent 2026.08.11-e8db854) and GetCurrentPeriodUsage autoBucketModels. Their windows are unmeasured because Cursor answers a first-turn Run with an empty token_details, so each carries the conservative cross-provider figure (272000 from the Codex catalog for the GPT-5.6 lineup, 256000 elsewhere); no Max Mode or -fast sibling is published for them",
34178
34219
  models: [
34179
34220
  {
34180
34221
  modelId: "auto",
@@ -34356,6 +34397,96 @@ var models_default = {
34356
34397
  upstreamModelIdTemplate: "claude-fable-5-{effort}"
34357
34398
  },
34358
34399
  benchmarkKey: "claude-fable-5"
34400
+ },
34401
+ {
34402
+ modelId: "gpt-5.6-sol",
34403
+ name: "GPT-5.6-Sol",
34404
+ capabilityClass: "flagship",
34405
+ quotaScope: "api",
34406
+ contextWindow: 272e3,
34407
+ effort: {
34408
+ supported: true,
34409
+ levels: [
34410
+ "low",
34411
+ "medium",
34412
+ "high",
34413
+ "xhigh",
34414
+ "max"
34415
+ ],
34416
+ upstreamModelIdTemplate: "gpt-5.6-sol-{effort}"
34417
+ },
34418
+ benchmarkKey: "gpt-5.6-sol"
34419
+ },
34420
+ {
34421
+ modelId: "gpt-5.6-terra",
34422
+ name: "GPT-5.6-Terra",
34423
+ capabilityClass: "standard",
34424
+ quotaScope: "api",
34425
+ contextWindow: 272e3,
34426
+ effort: {
34427
+ supported: true,
34428
+ levels: [
34429
+ "low",
34430
+ "medium",
34431
+ "high",
34432
+ "xhigh",
34433
+ "max"
34434
+ ],
34435
+ upstreamModelIdTemplate: "gpt-5.6-terra-{effort}"
34436
+ },
34437
+ benchmarkKey: "gpt-5.6-terra"
34438
+ },
34439
+ {
34440
+ modelId: "gpt-5.6-luna",
34441
+ name: "GPT-5.6-Luna",
34442
+ capabilityClass: "light",
34443
+ quotaScope: "api",
34444
+ contextWindow: 272e3,
34445
+ effort: {
34446
+ supported: true,
34447
+ levels: [
34448
+ "low",
34449
+ "medium",
34450
+ "high",
34451
+ "xhigh",
34452
+ "max"
34453
+ ],
34454
+ upstreamModelIdTemplate: "gpt-5.6-luna-{effort}"
34455
+ },
34456
+ benchmarkKey: "gpt-5.6-luna"
34457
+ },
34458
+ {
34459
+ modelId: "gemini-3.7-flash",
34460
+ name: "Gemini-3.7-Flash",
34461
+ capabilityClass: "light",
34462
+ quotaScope: "api",
34463
+ contextWindow: 256e3,
34464
+ effort: {
34465
+ supported: true,
34466
+ levels: [
34467
+ "low",
34468
+ "medium",
34469
+ "high"
34470
+ ],
34471
+ upstreamModelIdTemplate: "gemini-3.7-flash-{effort}"
34472
+ }
34473
+ },
34474
+ {
34475
+ modelId: "kimi-k3",
34476
+ name: "Kimi-K3",
34477
+ capabilityClass: "flagship",
34478
+ quotaScope: "api",
34479
+ contextWindow: 256e3,
34480
+ effort: {
34481
+ supported: true,
34482
+ levels: [
34483
+ "low",
34484
+ "high",
34485
+ "max"
34486
+ ],
34487
+ upstreamModelIdTemplate: "kimi-k3-{effort}"
34488
+ },
34489
+ benchmarkKey: "kimi-k3"
34359
34490
  }
34360
34491
  ]
34361
34492
  },
@@ -34509,7 +34640,7 @@ var models_default = {
34509
34640
  xai: {
34510
34641
  name: "xAI",
34511
34642
  defaultModel: "grok-4.6",
34512
- source: "official Grok CLI 1.0.3 ~/.grok/models_cache.json from GET https://cli-chat-proxy.grok.com/v1/models (observed 2026-08-13)",
34643
+ source: "official Grok CLI 1.0.4 ~/.grok/models_cache.json from GET https://cli-chat-proxy.grok.com/v1/models (grok-4.6 observed 2026-08-13); grok-composer-2.5-fast is the account-verified OpenCodex xAI identity, live POST /v1/responses accepted on the Grok CLI proxy 2026-08-19 (absent from the public docs.x.ai catalog)",
34513
34644
  models: [
34514
34645
  {
34515
34646
  modelId: "grok-4.6",
@@ -34527,6 +34658,13 @@ var models_default = {
34527
34658
  ]
34528
34659
  },
34529
34660
  benchmarkKey: "grok-4.6"
34661
+ },
34662
+ {
34663
+ modelId: "grok-composer-2.5-fast",
34664
+ name: "Grok-Composer-2.5-Fast",
34665
+ capabilityClass: "light",
34666
+ wire: "responses",
34667
+ contextWindow: 2e5
34530
34668
  }
34531
34669
  ]
34532
34670
  }
@@ -36440,13 +36578,14 @@ function vendorFlagSettings(options) {
36440
36578
  return Object.keys(settings2).length > 0 ? { settings: settings2 } : {};
36441
36579
  }
36442
36580
  function vendorSystemPrompt(systemPrompt) {
36581
+ if (systemPrompt?.mode === "preset") return { type: "preset", preset: "claude_code" };
36443
36582
  const text = systemPrompt?.text;
36444
36583
  if (typeof text !== "string" || text.length === 0) {
36445
36584
  throw new TypeError("turn.systemPrompt.text must be a non-empty string.");
36446
36585
  }
36447
36586
  if (systemPrompt.mode === "replace") return text;
36448
36587
  if (systemPrompt.mode === "append") return { type: "preset", preset: "claude_code", append: text };
36449
- throw new TypeError(`turn.systemPrompt.mode must be "replace" or "append", got: ${String(systemPrompt.mode)}`);
36588
+ throw new TypeError(`turn.systemPrompt.mode must be "replace", "append", or "preset", got: ${String(systemPrompt.mode)}`);
36450
36589
  }
36451
36590
  function assertKnownTurnKeys(turn) {
36452
36591
  const unknown2 = Object.keys(turn).filter((key) => !CLAUDE_GATEWAY_TURN_KEYS.includes(key));
@@ -39958,6 +40097,86 @@ function resolveConsolePath(pathname) {
39958
40097
  if (!path18__default.extname(withoutPrefix)) return "index.html";
39959
40098
  return withoutPrefix;
39960
40099
  }
40100
+ var CONSOLE_UPDATE_PROGRESS_FILE = "update-progress.json";
40101
+ var IDLE_CONSOLE_UPDATE_PROGRESS = { state: "idle" };
40102
+ var CONSOLE_UPDATE_PROGRESS_STALE_MS = 10 * 60 * 1e3;
40103
+ var CONSOLE_UPDATE_OUTCOME_TTL_MS = 6 * 60 * 60 * 1e3;
40104
+ var RUNNING_PHASES = /* @__PURE__ */ new Set(["starting", "preflight-ok", "stopping-console", "installing", "starting-daemon"]);
40105
+ var PROGRESS_FILE_MODE = 384;
40106
+ function consoleUpdateProgressPath(dataDir) {
40107
+ return path18__default.join(dataDir, CONSOLE_UPDATE_PROGRESS_FILE);
40108
+ }
40109
+ function readConsoleUpdateProgress(dataDir, deps = {}) {
40110
+ const readFile7 = deps.readFile ?? ((filePath) => fs9__default.readFileSync(filePath, "utf8"));
40111
+ const now = deps.now ?? Date.now;
40112
+ let raw;
40113
+ try {
40114
+ raw = readFile7(consoleUpdateProgressPath(dataDir));
40115
+ } catch {
40116
+ return IDLE_CONSOLE_UPDATE_PROGRESS;
40117
+ }
40118
+ const record4 = parseConsoleUpdateProgressRecord(raw);
40119
+ if (!record4) return IDLE_CONSOLE_UPDATE_PROGRESS;
40120
+ return toConsoleUpdateProgressStatus(record4, now());
40121
+ }
40122
+ function toConsoleUpdateProgressStatus(record4, nowMs) {
40123
+ const shared = {
40124
+ phase: record4.phase,
40125
+ startedAt: record4.startedAt,
40126
+ targetVersion: record4.targetVersion,
40127
+ fromVersion: record4.fromVersion,
40128
+ ...record4.endpointChanged === true ? { endpointChanged: true } : {}
40129
+ };
40130
+ if (record4.phase === "completed" || record4.phase === "failed") {
40131
+ const finishedAtMs = Date.parse(record4.updatedAt);
40132
+ if (Number.isFinite(finishedAtMs) && nowMs - finishedAtMs > CONSOLE_UPDATE_OUTCOME_TTL_MS) return IDLE_CONSOLE_UPDATE_PROGRESS;
40133
+ if (record4.phase === "completed") return { state: "completed", ...shared };
40134
+ return { state: "failed", ...shared, ...record4.error ? { error: record4.error } : {} };
40135
+ }
40136
+ if (!RUNNING_PHASES.has(record4.phase)) return IDLE_CONSOLE_UPDATE_PROGRESS;
40137
+ const updatedAtMs = Date.parse(record4.updatedAt);
40138
+ if (Number.isFinite(updatedAtMs) && nowMs - updatedAtMs > CONSOLE_UPDATE_PROGRESS_STALE_MS) {
40139
+ return { state: "failed", ...shared, error: "update_worker_lost" };
40140
+ }
40141
+ return { state: "running", ...shared };
40142
+ }
40143
+ function parseConsoleUpdateProgressRecord(raw) {
40144
+ let value;
40145
+ try {
40146
+ value = JSON.parse(raw);
40147
+ } catch {
40148
+ return null;
40149
+ }
40150
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
40151
+ const entry = value;
40152
+ if (!isConsoleUpdatePhase(entry.phase)) return null;
40153
+ if (typeof entry.startedAt !== "string" || typeof entry.updatedAt !== "string") return null;
40154
+ if (typeof entry.targetVersion !== "string" || typeof entry.fromVersion !== "string") return null;
40155
+ return {
40156
+ phase: entry.phase,
40157
+ startedAt: entry.startedAt,
40158
+ updatedAt: entry.updatedAt,
40159
+ targetVersion: entry.targetVersion,
40160
+ fromVersion: entry.fromVersion,
40161
+ ...entry.endpointChanged === true ? { endpointChanged: true } : {},
40162
+ ...typeof entry.error === "string" ? { error: entry.error } : {}
40163
+ };
40164
+ }
40165
+ function isConsoleUpdatePhase(value) {
40166
+ return typeof value === "string" && (RUNNING_PHASES.has(value) || value === "completed" || value === "failed");
40167
+ }
40168
+ function writeConsoleUpdateProgress(dataDir, record4, deps = {}) {
40169
+ const makeDir = deps.makeDir ?? ((dirPath, options) => {
40170
+ fs9__default.mkdirSync(dirPath, options);
40171
+ });
40172
+ const writeFile5 = deps.writeFile ?? ((filePath, content, options) => {
40173
+ fs9__default.writeFileSync(filePath, content, { mode: options.mode });
40174
+ });
40175
+ makeDir(dataDir, { recursive: true, mode: 448 });
40176
+ writeFile5(consoleUpdateProgressPath(dataDir), JSON.stringify(record4, null, 2), { mode: PROGRESS_FILE_MODE });
40177
+ }
40178
+
40179
+ // core/host/update-apply.ts
39961
40180
  var PACKAGE_NAMES = ["@dotobokuri/fleet-console"];
39962
40181
  var WORKER_FILE_PREFIX = "fleet-console-update-";
39963
40182
  var WORKER_FILE_SUFFIX = ".mjs";
@@ -39988,21 +40207,34 @@ function createConsoleUpdateApplyService(deps = {}) {
39988
40207
  makeDir(request.dataDir, { recursive: true, mode: 448 });
39989
40208
  const statusFile = path18__default.join(request.dataDir, `${WORKER_FILE_PREFIX}${stamp}${STATUS_FILE_SUFFIX}`);
39990
40209
  const logFile = path18__default.join(request.dataDir, `${WORKER_FILE_PREFIX}${stamp}${LOG_FILE_SUFFIX}`);
40210
+ const progressFile = path18__default.join(request.dataDir, CONSOLE_UPDATE_PROGRESS_FILE);
40211
+ const startedAt = new Date(now()).toISOString();
39991
40212
  const script = emitConsoleUpdateWorkerScript({
39992
40213
  currentEndpoint: request.currentEndpoint,
39993
40214
  currentPackageRoot: request.currentPackageRoot,
39994
40215
  currentPid: request.currentPid,
40216
+ fromVersion: request.fromVersion,
39995
40217
  lockFile: request.lockFile,
39996
40218
  logFile,
39997
40219
  packageManager,
39998
40220
  packageNames: PACKAGE_NAMES,
40221
+ progressFile,
40222
+ resumePort: readEndpointPort(request.currentEndpoint),
39999
40223
  serverModulePath,
40000
40224
  statusFile,
40225
+ startedAt,
40001
40226
  targetVersion: request.targetVersion,
40002
40227
  workerPath
40003
40228
  });
40004
40229
  writeFile5(workerPath, script, { mode: TEMP_FILE_MODE });
40005
40230
  await spawnDetachedWorker(spawnWorker, execPath, [workerPath], childEnv);
40231
+ writeConsoleUpdateProgress(request.dataDir, {
40232
+ phase: "starting",
40233
+ startedAt,
40234
+ updatedAt: startedAt,
40235
+ targetVersion: request.targetVersion,
40236
+ fromVersion: request.fromVersion
40237
+ }, { makeDir, writeFile: writeFile5 });
40006
40238
  return { accepted: true };
40007
40239
  }
40008
40240
  return { start };
@@ -40020,6 +40252,8 @@ const stopTimeoutMs = 60000;
40020
40252
  const startTimeoutMs = 60000;
40021
40253
  const sleepMs = 250;
40022
40254
 
40255
+ let consoleStopped = false;
40256
+
40023
40257
  async function main() {
40024
40258
  writeStatus("starting");
40025
40259
  cleanupStaleWorkers();
@@ -40032,14 +40266,21 @@ async function main() {
40032
40266
  await installPackages(manager);
40033
40267
  writeStatus("starting-daemon");
40034
40268
  const lock = await startNewDaemon();
40035
- openBrowser(new URL("console/", lock.endpoint).toString());
40036
- writeStatus("completed");
40269
+ // \uAC19\uC740 \uC8FC\uC18C\uB85C \uB3CC\uC544\uC654\uC73C\uBA74 \uC5F4\uB824 \uC788\uB358 \uD654\uBA74\uC774 \uC2A4\uC2A4\uB85C \uB2E4\uC2DC \uBD99\uB294\uB2E4 \u2014 \uC0C8 \uCC3D\uC740 \uADF8 \uBCF5\uADC0\uB97C
40270
+ // \uB36E\uC5B4\uC4F8 \uBFD0\uC774\uB2E4. \uC8FC\uC18C\uB97C \uB418\uCC3E\uC9C0 \uBABB\uD588\uC744 \uB54C\uB9CC, \uAC08 \uACF3\uC744 \uC783\uC9C0 \uC54A\uB3C4\uB85D \uCC3D\uC744 \uC5F0\uB2E4.
40271
+ const endpointChanged = !isSameEndpoint(lock.endpoint, config.currentEndpoint);
40272
+ if (endpointChanged) openBrowser(new URL("console/", lock.endpoint).toString());
40273
+ writeStatus("completed", endpointChanged ? { endpointChanged: true } : {});
40037
40274
  }
40038
40275
 
40039
40276
  main()
40040
- .catch((error) => {
40041
- writeStatus("failed", { error: sanitizeError(error) });
40042
- log("failed: " + sanitizeError(error));
40277
+ .catch(async (error) => {
40278
+ const reason = sanitizeError(error);
40279
+ log("failed: " + reason);
40280
+ // \uCF58\uC194\uC744 \uC774\uBBF8 \uB0B4\uB9B0 \uB4A4\uC5D0 \uC2E4\uD328\uD588\uB2E4\uBA74, \uC2E4\uD328\uB97C \uB9D0\uD560 \uD654\uBA74\uC870\uCC28 \uC5C6\uB2E4. \uC61B \uBC84\uC804\uC774\uB77C\uB3C4
40281
+ // \uB2E4\uC2DC \uC138\uC6CC\uC57C \uC0AC\uC6A9\uC790\uAC00 \uBB34\uC5C7\uC774 \uC798\uBABB\uB410\uB294\uC9C0 \uC77D\uC744 \uC218 \uC788\uB2E4.
40282
+ if (consoleStopped) await recoverConsoleBestEffort();
40283
+ writeStatus("failed", { error: reason });
40043
40284
  process.exitCode = 1;
40044
40285
  })
40045
40286
  .finally(() => {
@@ -40051,12 +40292,24 @@ main()
40051
40292
  });
40052
40293
 
40053
40294
  function writeStatus(phase, extra = {}) {
40054
- const payload = {
40295
+ const updatedAt = new Date().toISOString();
40296
+ fs.writeFileSync(config.statusFile, JSON.stringify({ phase, updatedAt, ...extra }, null, 2), { mode: 0o600 });
40297
+ // \uC7AC\uAE30\uB3D9\uD55C \uB370\uBAAC\uC774 \uC77D\uB294 \uAC83\uC740 \uC774 \uACE0\uC815 \uC774\uB984\uC758 \uAE30\uB85D\uC774\uB2E4. \uD0C0\uC784\uC2A4\uD0EC\uD504\uAC00 \uBD99\uC740 \uC704 \uD30C\uC77C\uC740
40298
+ // \uC774 \uC2E4\uD589\uC758 \uC9C4\uB2E8 \uD754\uC801\uC774\uACE0, \uC544\uB798\uAC00 "\uBC29\uAE08 \uBB34\uC2A8 \uC77C\uC774 \uC788\uC5C8\uB294\uAC00"\uC5D0 \uB2F5\uD558\uB294 \uCABD\uC774\uB2E4.
40299
+ const record = {
40055
40300
  phase,
40056
- updatedAt: new Date().toISOString(),
40057
- ...extra,
40301
+ startedAt: config.startedAt,
40302
+ updatedAt,
40303
+ targetVersion: config.targetVersion,
40304
+ fromVersion: config.fromVersion,
40058
40305
  };
40059
- fs.writeFileSync(config.statusFile, JSON.stringify(payload, null, 2), { mode: 0o600 });
40306
+ if (extra.endpointChanged === true) record.endpointChanged = true;
40307
+ if (typeof extra.error === "string") record.error = extra.error;
40308
+ try {
40309
+ fs.writeFileSync(config.progressFile, JSON.stringify(record, null, 2), { mode: 0o600 });
40310
+ } catch {
40311
+ // \uC9C4\uB2E8 \uAE30\uB85D\uC774 \uC5C6\uB2E4\uACE0 \uC5C5\uB370\uC774\uD2B8\uB97C \uBA48\uCD94\uC9C0\uB294 \uC54A\uB294\uB2E4.
40312
+ }
40060
40313
  log("phase: " + phase);
40061
40314
  }
40062
40315
 
@@ -40081,6 +40334,7 @@ function cleanupStaleWorkers() {
40081
40334
 
40082
40335
  async function stopCurrentConsole() {
40083
40336
  writeStatus("stopping-console");
40337
+ consoleStopped = true;
40084
40338
  try {
40085
40339
  process.kill(config.currentPid, "SIGTERM");
40086
40340
  } catch (error) {
@@ -40093,9 +40347,14 @@ async function waitForOldConsoleExit() {
40093
40347
  let escalated = false;
40094
40348
  while (Date.now() < deadline) {
40095
40349
  const pidGone = !isProcessAlive(config.currentPid);
40096
- const lockGone = !fs.existsSync(config.lockFile);
40097
40350
  const healthGone = await isHealthGone(config.currentEndpoint);
40098
- if (pidGone && lockGone && healthGone) return;
40351
+ if (pidGone && healthGone) {
40352
+ // \uC8FD\uC740 \uD504\uB85C\uC138\uC2A4\uAC00 \uB0A8\uAE34 \uB77D\uC740 \uC815\uC758\uC0C1 stale\uC774\uB2E4. \uADF8\uAC83\uC774 \uC2A4\uC2A4\uB85C \uC0AC\uB77C\uC9C0\uAE30\uB97C \uAE30\uB2E4\uB9AC\uBA74
40353
+ // SIGKILL\uB85C \uB0B4\uB9B0 \uCF58\uC194 \uB4A4\uC5D0\uC11C\uB294 \uC601\uC6D0\uD788 \uAE30\uB2E4\uB9AC\uAC8C \uB418\uACE0, \uC5C5\uB370\uC774\uD2B8\uB294 \uB298 \uC2DC\uAC04 \uCD08\uACFC\uB85C
40354
+ // \uB05D\uB09C\uB2E4. \uC6B0\uB9AC\uAC00 \uB0B4\uB9B0 \uADF8 pid\uC758 \uB77D\uC774\uBA74 \uC6B0\uB9AC\uAC00 \uCE58\uC6B4\uB2E4.
40355
+ removeStaleLock();
40356
+ return;
40357
+ }
40099
40358
  if (!escalated && Date.now() > deadline - 10000 && isProcessAlive(config.currentPid)) {
40100
40359
  escalated = true;
40101
40360
  try {
@@ -40145,10 +40404,15 @@ async function installPackages(manager) {
40145
40404
  if (code !== 0) throw new Error("global package install failed with exit code " + code);
40146
40405
  }
40147
40406
 
40407
+ function daemonEnv() {
40408
+ if (config.resumePort === null) return process.env;
40409
+ return { ...process.env, FLEET_CONSOLE_RESUME_PORT: String(config.resumePort) };
40410
+ }
40411
+
40148
40412
  async function startNewDaemon() {
40149
40413
  const child = spawn(process.execPath, [config.serverModulePath, "serve"], {
40150
40414
  detached: true,
40151
- env: process.env,
40415
+ env: daemonEnv(),
40152
40416
  stdio: "ignore",
40153
40417
  windowsHide: true,
40154
40418
  });
@@ -40163,6 +40427,43 @@ async function startNewDaemon() {
40163
40427
  throw new Error("new console daemon did not become healthy");
40164
40428
  }
40165
40429
 
40430
+ /**
40431
+ * \uC124\uCE58\uAC00 \uC2E4\uD328\uD55C \uB4A4\uC758 \uB9C8\uC9C0\uB9C9 \uC758\uBB34: \uC5B4\uB5A4 \uBC84\uC804\uC774\uB4E0 \uCF58\uC194\uC744 \uB2E4\uC2DC \uC138\uC6B4\uB2E4. \uC5EC\uAE30\uC11C\uB294 \uBAA9\uD45C \uBC84\uC804\uC744
40432
+ * \uC694\uAD6C\uD558\uC9C0 \uC54A\uB294\uB2E4 \u2014 \uC61B \uBC84\uC804\uC73C\uB85C\uB77C\uB3C4 \uC0B4\uC544 \uC788\uC5B4\uC57C \uC2E4\uD328\uB97C \uC77D\uC744 \uD654\uBA74\uC774 \uC0DD\uAE34\uB2E4.
40433
+ */
40434
+ async function recoverConsoleBestEffort() {
40435
+ try {
40436
+ const child = spawn(process.execPath, [config.serverModulePath, "serve"], {
40437
+ detached: true,
40438
+ env: daemonEnv(),
40439
+ stdio: "ignore",
40440
+ windowsHide: true,
40441
+ });
40442
+ child.once("error", () => {});
40443
+ child.unref();
40444
+ const deadline = Date.now() + startTimeoutMs;
40445
+ while (Date.now() < deadline) {
40446
+ const lock = readLock();
40447
+ if (lock && isProcessAlive(lock.pid) && await isAnyHealthOk(lock)) {
40448
+ log("recovered console after failure");
40449
+ return;
40450
+ }
40451
+ await sleep(sleepMs);
40452
+ }
40453
+ log("recovery did not become healthy before timeout");
40454
+ } catch (error) {
40455
+ log("recovery failed: " + sanitizeError(error));
40456
+ }
40457
+ }
40458
+
40459
+ function isSameEndpoint(left, right) {
40460
+ try {
40461
+ return new URL(left).host === new URL(right).host;
40462
+ } catch {
40463
+ return false;
40464
+ }
40465
+ }
40466
+
40166
40467
  function openBrowser(url) {
40167
40468
  const platform = os.platform();
40168
40469
  if (platform === "darwin") {
@@ -40190,6 +40491,18 @@ function spawnExit(command, args) {
40190
40491
  });
40191
40492
  }
40192
40493
 
40494
+ /** \uC6B0\uB9AC\uAC00 \uB0B4\uB9B0 pid\uC758 \uB77D\uB9CC \uC9C0\uC6B4\uB2E4 \u2014 \uADF8 \uC0AC\uC774 \uC62C\uB77C\uC628 \uC0C8 \uCF58\uC194\uC758 \uB77D\uC740 \uAC74\uB4DC\uB9AC\uC9C0 \uC54A\uB294\uB2E4. */
40495
+ function removeStaleLock() {
40496
+ const lock = readLock();
40497
+ if (!lock || lock.pid !== config.currentPid) return;
40498
+ try {
40499
+ fs.rmSync(config.lockFile, { force: true });
40500
+ log("removed the stale lock of the console we stopped");
40501
+ } catch {
40502
+ // \uC9C0\uC6B0\uC9C0 \uBABB\uD574\uB3C4 \uC0C8 \uB370\uBAAC\uC774 stale lock\uC744 \uC2A4\uC2A4\uB85C \uC815\uB9AC\uD55C\uB2E4.
40503
+ }
40504
+ }
40505
+
40193
40506
  function readLock() {
40194
40507
  try {
40195
40508
  return JSON.parse(fs.readFileSync(config.lockFile, "utf8"));
@@ -40216,6 +40529,18 @@ async function isNewHealthOk(lock) {
40216
40529
  }
40217
40530
  }
40218
40531
 
40532
+ async function isAnyHealthOk(lock) {
40533
+ if (!lock || typeof lock.endpoint !== "string" || typeof lock.token !== "string") return false;
40534
+ try {
40535
+ const response = await fetch(new URL("api/v1/health", lock.endpoint), {
40536
+ headers: { authorization: "Bearer " + lock.token },
40537
+ });
40538
+ return response.ok;
40539
+ } catch {
40540
+ return false;
40541
+ }
40542
+ }
40543
+
40219
40544
  async function readHealthVersion(response) {
40220
40545
  try {
40221
40546
  const payload = await response.json();
@@ -40284,6 +40609,14 @@ function sanitizeError(error) {
40284
40609
  }
40285
40610
  `;
40286
40611
  }
40612
+ function readEndpointPort(endpoint) {
40613
+ try {
40614
+ const port = Number.parseInt(new URL(endpoint).port, 10);
40615
+ return Number.isInteger(port) && port > 0 && port < 65536 ? port : null;
40616
+ } catch {
40617
+ return null;
40618
+ }
40619
+ }
40287
40620
  function isManagedRuntimePackageRoot(packageRoot) {
40288
40621
  if (path18__default.basename(packageRoot) !== "latest" || path18__default.basename(path18__default.dirname(packageRoot)) !== "console") return false;
40289
40622
  try {
@@ -40446,6 +40779,7 @@ var MIN_CONSOLE_STATIC_PORT2 = 1024;
40446
40779
  var MAX_CONSOLE_STATIC_PORT2 = 65535;
40447
40780
  var SERVER_TIMEOUT_MS = 30 * 60 * 1e3;
40448
40781
  var MAX_BODY_BYTES = 1024 * 1024;
40782
+ var DESKTOP_UPDATE_REQUEST_TTL_MS = 6e4;
40449
40783
  var UPDATE_APPLY_FORBIDDEN_BODY_KEYS = /* @__PURE__ */ new Set(["channel", "package", "packageName", "packageVersion", "packages", "targetVersion", "version"]);
40450
40784
  var OPERATION_RENAMED_EVENT_CHANNEL = "operation:renamed";
40451
40785
  var PAIRING_IDENTITY_PATH = "/api/v1/pairing-identity";
@@ -40547,6 +40881,14 @@ var SERVER_API_CATALOG = [
40547
40881
  gate: "origin-write",
40548
40882
  transport: "http"
40549
40883
  },
40884
+ {
40885
+ method: "GET",
40886
+ path: "/api/v1/updates/progress",
40887
+ summary: "Read the outcome of the update this console just came back from.",
40888
+ category: "Update",
40889
+ gate: "loopback",
40890
+ transport: "http"
40891
+ },
40550
40892
  {
40551
40893
  method: "POST",
40552
40894
  path: "/api/v1/updates/apply",
@@ -40694,6 +41036,7 @@ function createConsoleServer(deps = {}) {
40694
41036
  const desktop = readDesktopProtocolEnvironment();
40695
41037
  const version2 = deps.version ?? release.version;
40696
41038
  const channel = release.channel;
41039
+ const resumePort = takeConsoleResumePort(process.env);
40697
41040
  const lock = createConsoleLock({ hostname: () => host });
40698
41041
  const releaseNotes = deps.releaseNotes ?? createConsoleReleaseNotesService();
40699
41042
  const updateCheck = deps.updateCheck ?? createConsoleUpdateCheckService({ readRelease: () => release });
@@ -40760,6 +41103,9 @@ function createConsoleServer(deps = {}) {
40760
41103
  const pluginEventListeners = /* @__PURE__ */ new Map();
40761
41104
  const operationSseSubscribers = /* @__PURE__ */ new Set();
40762
41105
  const desktopThemeSseSubscribers = /* @__PURE__ */ new Set();
41106
+ const desktopUpdateSseSubscribers = /* @__PURE__ */ new Set();
41107
+ let desktopUpdateRequest = emptyDesktopUpdateRequest();
41108
+ let desktopUpdateRequestedAt = 0;
40763
41109
  function publishPluginEvent(channel2, payload) {
40764
41110
  for (const listener of pluginEventListeners.get(channel2) ?? []) listener(payload);
40765
41111
  }
@@ -40970,6 +41316,24 @@ function createConsoleServer(deps = {}) {
40970
41316
  });
40971
41317
  }
40972
41318
  });
41319
+ const desktopUpdateRouter = createDesktopUpdateRouter({
41320
+ getUpdateRequest: () => readDesktopUpdateRequest(),
41321
+ isAuthorized: isExactConsoleOrigin,
41322
+ writeJson,
41323
+ subscribe: (res, snapshot) => {
41324
+ res.writeHead(200, withSecurityHeaders2({
41325
+ "Content-Type": "text/event-stream",
41326
+ "Cache-Control": "no-cache",
41327
+ "Connection": "keep-alive"
41328
+ }));
41329
+ res.write(":connected\n\n");
41330
+ res.write(encodeSseData(DESKTOP_UPDATE_EVENT, snapshot));
41331
+ desktopUpdateSseSubscribers.add(res);
41332
+ res.on("close", () => {
41333
+ desktopUpdateSseSubscribers.delete(res);
41334
+ });
41335
+ }
41336
+ });
40973
41337
  const desktopShellRouter = createDesktopShellRouter({
40974
41338
  getShell: (req) => {
40975
41339
  const owner = shellOwnerOf(req);
@@ -41070,6 +41434,7 @@ function createConsoleServer(deps = {}) {
41070
41434
  routeRegistry.register("/api/v1/desktop", async (context) => {
41071
41435
  if (await desktopShellRouter(context)) return true;
41072
41436
  if (await desktopFullscreenRouter(context)) return true;
41437
+ if (desktopUpdateRouter(context)) return true;
41073
41438
  return desktopThemeRouter(context);
41074
41439
  });
41075
41440
  routeRegistry.register("/plugin-runtime", handlePluginRuntimeRoute);
@@ -41195,6 +41560,10 @@ function createConsoleServer(deps = {}) {
41195
41560
  runAsyncHandler(handleObserverReleaseNotes(req, res), res);
41196
41561
  return;
41197
41562
  }
41563
+ if (pathname === "/api/v1/updates/progress") {
41564
+ handleUpdateProgress(req, res);
41565
+ return;
41566
+ }
41198
41567
  if (pathname === "/api/v1/updates/apply") {
41199
41568
  runAsyncHandler(handleUpdateApply(req, res), res);
41200
41569
  return;
@@ -41860,6 +42229,19 @@ function createConsoleServer(deps = {}) {
41860
42229
  throw error51;
41861
42230
  }
41862
42231
  }
42232
+ function handleUpdateProgress(req, res) {
42233
+ if (req.method !== "GET") {
42234
+ writeJson(res, 405, { error: "Method not allowed" });
42235
+ return;
42236
+ }
42237
+ let progress;
42238
+ try {
42239
+ progress = readConsoleUpdateProgress(durablePaths.dir);
42240
+ } catch {
42241
+ progress = IDLE_CONSOLE_UPDATE_PROGRESS;
42242
+ }
42243
+ writeJson(res, 200, progress);
42244
+ }
41863
42245
  async function handleUpdateApply(req, res) {
41864
42246
  if (req.method !== "POST") {
41865
42247
  writeJson(res, 405, { error: "Method not allowed" });
@@ -41891,6 +42273,16 @@ function createConsoleServer(deps = {}) {
41891
42273
  writeJson(res, 409, { error: "update_not_available" });
41892
42274
  return;
41893
42275
  }
42276
+ if (!isLoopbackListener(req) && (body2 === null || body2.acknowledgeHostRestart !== true)) {
42277
+ writeJson(res, 409, { error: "host_restart_confirmation_required" });
42278
+ return;
42279
+ }
42280
+ if (isManagedRuntimePackageRoot(release.packageRoot)) {
42281
+ publishDesktopUpdateRequest({ requestedVersion: freshStatus.latestVersion, requestId: crypto5.randomUUID() });
42282
+ const delegated = { status: "delegated" };
42283
+ writeJson(res, 202, delegated);
42284
+ return;
42285
+ }
41894
42286
  const handle = lockHandle;
41895
42287
  if (!handle || !activeEndpoint || !activeLockFile) {
41896
42288
  writeJson(res, 503, { error: "console_not_ready" });
@@ -41903,6 +42295,7 @@ function createConsoleServer(deps = {}) {
41903
42295
  currentPackageRoot: release.packageRoot,
41904
42296
  currentPid: process.pid,
41905
42297
  dataDir: durablePaths.dir,
42298
+ fromVersion: version2,
41906
42299
  lockFile: activeLockFile,
41907
42300
  targetVersion: freshStatus.latestVersion
41908
42301
  });
@@ -41989,7 +42382,7 @@ function createConsoleServer(deps = {}) {
41989
42382
  listeners = [];
41990
42383
  boundPort = null;
41991
42384
  access.revokeAllSessions();
41992
- if (closingRemote) await new Promise((resolve3) => closingRemote.close(() => resolve3()));
42385
+ await closeHttpServer(closingRemote);
41993
42386
  const cleanupResults = await Promise.allSettled([...pluginCleanupCallbacks].map((cleanup) => cleanup()));
41994
42387
  for (const result of cleanupResults) {
41995
42388
  if (result.status === "rejected") {
@@ -42118,6 +42511,21 @@ function createConsoleServer(deps = {}) {
42118
42511
  res.write(data);
42119
42512
  }
42120
42513
  }
42514
+ function readDesktopUpdateRequest() {
42515
+ if (desktopUpdateRequest.requestId === null) return desktopUpdateRequest;
42516
+ if (Date.now() - desktopUpdateRequestedAt <= DESKTOP_UPDATE_REQUEST_TTL_MS) return desktopUpdateRequest;
42517
+ desktopUpdateRequest = emptyDesktopUpdateRequest();
42518
+ return desktopUpdateRequest;
42519
+ }
42520
+ function publishDesktopUpdateRequest(snapshot) {
42521
+ desktopUpdateRequestedAt = Date.now();
42522
+ desktopUpdateRequest = snapshot;
42523
+ if (desktopUpdateSseSubscribers.size === 0) return;
42524
+ const data = encodeSseData(DESKTOP_UPDATE_EVENT, snapshot);
42525
+ for (const res of desktopUpdateSseSubscribers) {
42526
+ res.write(data);
42527
+ }
42528
+ }
42121
42529
  function persistDurableState() {
42122
42530
  try {
42123
42531
  saveDurableState(deletionCoordinator.list());
@@ -42193,6 +42601,11 @@ function createConsoleServer(deps = {}) {
42193
42601
  }
42194
42602
  };
42195
42603
  function resolveConsolePortListenPlan() {
42604
+ const plan = resolveConfiguredConsolePortListenPlan();
42605
+ if (resumePort === null || plan.portMode !== "dynamic") return plan;
42606
+ return { ...plan, port: resumePort, allowFallback: true };
42607
+ }
42608
+ function resolveConfiguredConsolePortListenPlan() {
42196
42609
  if (deps.port !== void 0) {
42197
42610
  return {
42198
42611
  port,
@@ -42322,7 +42735,7 @@ function createConsoleServer(deps = {}) {
42322
42735
  if (owner !== "local") desktopShellsByOwner.delete(owner);
42323
42736
  }
42324
42737
  broadcastControlChanged();
42325
- if (closing) await new Promise((resolve3) => closing.close(() => resolve3()));
42738
+ await closeHttpServer(closing);
42326
42739
  }
42327
42740
  async function startRemoteAccessIfEnabled(_actualPort) {
42328
42741
  const configured = consoleSettingsStore.load().general?.remoteAccess;
@@ -42582,6 +42995,14 @@ function isPlainObject2(value) {
42582
42995
  function hasForbiddenUpdateApplyBodyKeys(body2) {
42583
42996
  return Object.keys(body2).some((key) => UPDATE_APPLY_FORBIDDEN_BODY_KEYS.has(key));
42584
42997
  }
42998
+ var CONSOLE_RESUME_PORT_ENV = "FLEET_CONSOLE_RESUME_PORT";
42999
+ function takeConsoleResumePort(env) {
43000
+ const raw = env[CONSOLE_RESUME_PORT_ENV];
43001
+ delete env[CONSOLE_RESUME_PORT_ENV];
43002
+ if (raw === void 0) return null;
43003
+ const port = Number.parseInt(raw, 10);
43004
+ return Number.isInteger(port) && port > 0 && port < 65536 ? port : null;
43005
+ }
42585
43006
  function isValidConsoleStaticPort2(value) {
42586
43007
  return typeof value === "number" && Number.isInteger(value) && value >= MIN_CONSOLE_STATIC_PORT2 && value <= MAX_CONSOLE_STATIC_PORT2;
42587
43008
  }