pilotswarm 0.5.41 → 0.5.43

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 (112) hide show
  1. package/mcp/README.md +25 -1
  2. package/mcp/dist/src/auth.d.ts.map +1 -1
  3. package/mcp/dist/src/auth.js +5 -3
  4. package/mcp/dist/src/auth.js.map +1 -1
  5. package/mcp/dist/src/resources/models.d.ts.map +1 -1
  6. package/mcp/dist/src/resources/models.js +21 -14
  7. package/mcp/dist/src/resources/models.js.map +1 -1
  8. package/mcp/dist/src/server.d.ts.map +1 -1
  9. package/mcp/dist/src/server.js +2 -0
  10. package/mcp/dist/src/server.js.map +1 -1
  11. package/mcp/dist/src/tools/agent-packages.d.ts.map +1 -1
  12. package/mcp/dist/src/tools/agent-packages.js +28 -16
  13. package/mcp/dist/src/tools/agent-packages.js.map +1 -1
  14. package/mcp/dist/src/tools/models.d.ts.map +1 -1
  15. package/mcp/dist/src/tools/models.js +55 -47
  16. package/mcp/dist/src/tools/models.js.map +1 -1
  17. package/mcp/dist/src/tools/providers.d.ts +18 -0
  18. package/mcp/dist/src/tools/providers.d.ts.map +1 -0
  19. package/mcp/dist/src/tools/providers.js +284 -0
  20. package/mcp/dist/src/tools/providers.js.map +1 -0
  21. package/mcp/dist/src/tools/sessions.d.ts.map +1 -1
  22. package/mcp/dist/src/tools/sessions.js +10 -1
  23. package/mcp/dist/src/tools/sessions.js.map +1 -1
  24. package/mcp/dist/src/tools/system.js +2 -2
  25. package/mcp/dist/src/tools/system.js.map +1 -1
  26. package/mcp/dist/src/util/respond.d.ts.map +1 -1
  27. package/mcp/dist/src/util/respond.js +6 -0
  28. package/mcp/dist/src/util/respond.js.map +1 -1
  29. package/package.json +3 -3
  30. package/tui/README.md +8 -5
  31. package/tui/src/agents-cli.js +80 -78
  32. package/tui/src/app.js +119 -17
  33. package/tui/src/node-sdk-transport.js +150 -347
  34. package/ui/core/src/controller.js +1079 -23
  35. package/ui/core/src/history.js +25 -1
  36. package/ui/core/src/reducer.js +649 -1
  37. package/ui/core/src/selectors.js +906 -6
  38. package/ui/core/src/state.js +163 -3
  39. package/ui/react/src/components.js +146 -4
  40. package/ui/react/src/web-app.js +1942 -125
  41. package/web/README.md +4 -4
  42. package/web/api/router.js +33 -0
  43. package/web/dist/assets/{abnfDiagram-VRR7QNED-kpxu_PEa.js → abnfDiagram-VRR7QNED-BqKIaTz5.js} +1 -1
  44. package/web/dist/assets/{arc-BnVQmtB5.js → arc-DCSwKNAt.js} +1 -1
  45. package/web/dist/assets/{architectureDiagram-ZJ3FMSHR-CDynQ_6_.js → architectureDiagram-ZJ3FMSHR-B6j7Bv5B.js} +1 -1
  46. package/web/dist/assets/{blockDiagram-677ZJIJ3-BUpYaSDb.js → blockDiagram-677ZJIJ3-BT1iegLO.js} +1 -1
  47. package/web/dist/assets/{c4Diagram-LMCZKHZV-ZL8eskDB.js → c4Diagram-LMCZKHZV-DXEt-_ny.js} +1 -1
  48. package/web/dist/assets/channel-BLVoqfUa.js +1 -0
  49. package/web/dist/assets/{chunk-2Q5K7J3B-o0Nsyp1T.js → chunk-2Q5K7J3B-B144-8I2.js} +1 -1
  50. package/web/dist/assets/{chunk-32BRIVSS-CH5CSNRP.js → chunk-32BRIVSS-CMHrtYOC.js} +1 -1
  51. package/web/dist/assets/{chunk-5VM5RSS4-C9wwtPWL.js → chunk-5VM5RSS4-4r8OmbGE.js} +1 -1
  52. package/web/dist/assets/{chunk-EX3LRPZG--F9yFbhA.js → chunk-EX3LRPZG-R_j3wosN.js} +1 -1
  53. package/web/dist/assets/{chunk-JWPE2WC7-BPIstyWL.js → chunk-JWPE2WC7-BKlFEYXC.js} +1 -1
  54. package/web/dist/assets/{chunk-MOJQB5TN-5Dm2u-0k.js → chunk-MOJQB5TN-C2S4TPSa.js} +1 -1
  55. package/web/dist/assets/{chunk-RYQCIY6F-Dbtf9iQK.js → chunk-RYQCIY6F-Y2kpzPD7.js} +1 -1
  56. package/web/dist/assets/{chunk-V7JOEXUC-DrZEBJ5l.js → chunk-V7JOEXUC-kAOP_3Kc.js} +1 -1
  57. package/web/dist/assets/{chunk-VR4S4FIN-AqAUynqK.js → chunk-VR4S4FIN-B2Au1EfR.js} +1 -1
  58. package/web/dist/assets/{chunk-XXDRQBXY-DQlFaqCy.js → chunk-XXDRQBXY-CZfTG6DD.js} +1 -1
  59. package/web/dist/assets/classDiagram-OUVF2IWQ-BgaYclQI.js +1 -0
  60. package/web/dist/assets/classDiagram-v2-EOCWNBFH-BgaYclQI.js +1 -0
  61. package/web/dist/assets/{cose-bilkent-JH36ORCC-RAtPG1Ou.js → cose-bilkent-JH36ORCC--tNLpMEb.js} +1 -1
  62. package/web/dist/assets/{cynefin-VYW2F7L2-CbeHaUWZ.js → cynefin-VYW2F7L2-BeIRFyvX.js} +1 -1
  63. package/web/dist/assets/{cynefinDiagram-TSTJHNR4-B6paqF5Y.js → cynefinDiagram-TSTJHNR4-Bm5lb_xz.js} +1 -1
  64. package/web/dist/assets/{dagre-VKFMJZFB-DziTBO2K.js → dagre-VKFMJZFB-Cz1i_B0y.js} +1 -1
  65. package/web/dist/assets/{diagram-FQU43EPY-CPRUiLcr.js → diagram-FQU43EPY-BF0j7c1T.js} +1 -1
  66. package/web/dist/assets/{diagram-G47NLZAW-CIMVdcL1.js → diagram-G47NLZAW-C2QWJ-Y4.js} +1 -1
  67. package/web/dist/assets/{diagram-NH7WQ7WH-CHPFllxR.js → diagram-NH7WQ7WH-BiNeThAA.js} +1 -1
  68. package/web/dist/assets/{diagram-OA4YK3LP-DwS6unBJ.js → diagram-OA4YK3LP-Cq7_37rx.js} +1 -1
  69. package/web/dist/assets/{diagram-WEI45ONY-DKWgkObI.js → diagram-WEI45ONY-Cl0GjIma.js} +1 -1
  70. package/web/dist/assets/{ebnfDiagram-CCIWWBDH-zAVWV6-D.js → ebnfDiagram-CCIWWBDH-C-dTpVrf.js} +1 -1
  71. package/web/dist/assets/{erDiagram-Q63AITRT-D0tYX4h0.js → erDiagram-Q63AITRT-RPSg6Lws.js} +1 -1
  72. package/web/dist/assets/{flowDiagram-23GEKE2U-Cfq4I7R0.js → flowDiagram-23GEKE2U-CslnZm0D.js} +1 -1
  73. package/web/dist/assets/{ganttDiagram-NO4QXBWP-wgBAHr5I.js → ganttDiagram-NO4QXBWP-dzr6nimS.js} +1 -1
  74. package/web/dist/assets/{gitGraphDiagram-IHSO6WYX-BTIPX5PR.js → gitGraphDiagram-IHSO6WYX-UpjDHGP0.js} +1 -1
  75. package/web/dist/assets/index-C-ujPKpy.css +1 -0
  76. package/web/dist/assets/index-Cf_e477H.js +24 -0
  77. package/web/dist/assets/{infoDiagram-FWYZ7A6U-CRLiQ87D.js → infoDiagram-FWYZ7A6U-R4qLdwe7.js} +1 -1
  78. package/web/dist/assets/{ishikawaDiagram-FXEZZL3T-CwzwUis1.js → ishikawaDiagram-FXEZZL3T-Cst7PjW4.js} +1 -1
  79. package/web/dist/assets/{journeyDiagram-5HDEW3XC-B9pqMeFw.js → journeyDiagram-5HDEW3XC-CugDTBMp.js} +1 -1
  80. package/web/dist/assets/{kanban-definition-HUTT4EX6-CZ5Xky4p.js → kanban-definition-HUTT4EX6-D6Yf2Lgg.js} +1 -1
  81. package/web/dist/assets/{linear-BLZ2eH4a.js → linear-hUntimCu.js} +1 -1
  82. package/web/dist/assets/{mermaid.core-CPN1IVjz.js → mermaid.core-BhKlcGBI.js} +4 -4
  83. package/web/dist/assets/{mindmap-definition-LN4V7U3C-MdC8d2tc.js → mindmap-definition-LN4V7U3C-DKVBRUj4.js} +1 -1
  84. package/web/dist/assets/{papaparse.min-CtrVJupf.js → papaparse.min-DbTWBfDP.js} +1 -1
  85. package/web/dist/assets/{pegDiagram-2B236MQR-B2DqAc-A.js → pegDiagram-2B236MQR-DeilQyRr.js} +1 -1
  86. package/web/dist/assets/{pieDiagram-ENE6RG2P-C3QAoXZh.js → pieDiagram-ENE6RG2P-CSVE3nUJ.js} +1 -1
  87. package/web/dist/assets/pilotswarm-DaQpAPI0.js +97 -0
  88. package/web/dist/assets/{quadrantDiagram-ABIIQ3AL-BoUr5qFH.js → quadrantDiagram-ABIIQ3AL-Di-WUa_j.js} +1 -1
  89. package/web/dist/assets/{railroadDiagram-RFXS5EU6-bZzE4KFN.js → railroadDiagram-RFXS5EU6-jBlJSP-m.js} +1 -1
  90. package/web/dist/assets/{requirementDiagram-TGXJPOKE-B2ENAqLS.js → requirementDiagram-TGXJPOKE-BlLuScOr.js} +1 -1
  91. package/web/dist/assets/{sankeyDiagram-HTMAVEWB-AJZ3h46Z.js → sankeyDiagram-HTMAVEWB-D76NurlB.js} +1 -1
  92. package/web/dist/assets/{sequenceDiagram-DBY2YBRQ-QUf0VVE7.js → sequenceDiagram-DBY2YBRQ-BGPIUJo0.js} +1 -1
  93. package/web/dist/assets/{sizeCapture-X5ZJPWSS-Cv9RcUy6.js → sizeCapture-X5ZJPWSS-DKmGUrSI.js} +1 -1
  94. package/web/dist/assets/{stateDiagram-2N3HPSRC-hDiye45t.js → stateDiagram-2N3HPSRC-DAYHO_nW.js} +1 -1
  95. package/web/dist/assets/stateDiagram-v2-6OUMAXLB-jZoHf_Ku.js +1 -0
  96. package/web/dist/assets/{swimlanes-5IMT3BWC-hSk_OF85.js → swimlanes-5IMT3BWC-CiRowk4M.js} +2 -2
  97. package/web/dist/assets/swimlanesDiagram-G3AALYLV-C0ms7UKB.js +8 -0
  98. package/web/dist/assets/{timeline-definition-FHXFAJF6-ccOZEJ5e.js → timeline-definition-FHXFAJF6-iN7kQL24.js} +1 -1
  99. package/web/dist/assets/{vennDiagram-L72KCM5P-Bk5DLH_V.js → vennDiagram-L72KCM5P-C6TtJ36b.js} +1 -1
  100. package/web/dist/assets/{wardleyDiagram-EHGQE667-C20AX8ot.js → wardleyDiagram-EHGQE667-CBiv7EU-.js} +1 -1
  101. package/web/dist/assets/{xychartDiagram-FW5EYKEG-DaHqmi-R.js → xychartDiagram-FW5EYKEG-zXUejHih.js} +1 -1
  102. package/web/dist/index.html +3 -3
  103. package/web/runtime.js +220 -2
  104. package/web/server.js +35 -7
  105. package/web/dist/assets/channel-Bi5A6sHR.js +0 -1
  106. package/web/dist/assets/classDiagram-OUVF2IWQ-D8dCxI54.js +0 -1
  107. package/web/dist/assets/classDiagram-v2-EOCWNBFH-D8dCxI54.js +0 -1
  108. package/web/dist/assets/index-OHj-gGHp.js +0 -24
  109. package/web/dist/assets/index-eTH1FBtN.css +0 -1
  110. package/web/dist/assets/pilotswarm-CF1nmpMy.js +0 -97
  111. package/web/dist/assets/stateDiagram-v2-6OUMAXLB-Bu4ufvaU.js +0 -1
  112. package/web/dist/assets/swimlanesDiagram-G3AALYLV-BTFePb1Y.js +0 -8
@@ -239,6 +239,56 @@ export function normalizeStoredActiveSessionId(value) {
239
239
  return id ? id : null;
240
240
  }
241
241
 
242
+ /**
243
+ * Why a session is waiting on a budget. Four reasons, four remedies: a limit
244
+ * needs raising, an allowance needs widening, a hold needs releasing, and a
245
+ * missing provider needs creating (or the session switching model).
246
+ */
247
+ export const BUDGET_PAUSE_KINDS = Object.freeze(["limit", "allowance", "hold", "no_provider"]);
248
+
249
+ /**
250
+ * A session's `pauseState` record, or null when it is not paused.
251
+ *
252
+ * Lives here rather than in the selectors because the REDUCER stamps the
253
+ * debounced row status from it and the selectors colour the row from it, and
254
+ * the two must agree — see computeRawSessionVisualStatus.
255
+ *
256
+ * An unrecognized `kind` reads as no pause at all. A newer server that
257
+ * invents a fifth reason must not make an older portal draw a mark it has no
258
+ * words for.
259
+ */
260
+ export function normalizeSessionPause(session) {
261
+ const pause = session?.pauseState;
262
+ if (!pause || typeof pause !== "object") return null;
263
+ const kind = String(pause.kind || "");
264
+ if (!BUDGET_PAUSE_KINDS.includes(kind)) return null;
265
+ const text = (value) => {
266
+ const trimmed = String(value ?? "").trim();
267
+ return trimmed ? trimmed : null;
268
+ };
269
+ const num = (value) => (Number.isFinite(Number(value)) ? Number(value) : null);
270
+ return {
271
+ kind,
272
+ provider: text(pause.provider),
273
+ period: ["day", "week", "month"].includes(String(pause.period)) ? String(pause.period) : null,
274
+ modelQualified: text(pause.modelQualified),
275
+ limitTokens: num(pause.limitTokens),
276
+ usedTokens: num(pause.usedTokens),
277
+ ceilingTokens: num(pause.ceilingTokens),
278
+ yourUsedTokens: num(pause.yourUsedTokens),
279
+ // Null for a hold with no end, and for a provider that is simply
280
+ // absent — both wait until a person does something.
281
+ resetsAtUtc: text(pause.resetsAtUtc),
282
+ };
283
+ }
284
+
285
+ /** The three period columns the provider table draws, left to right. */
286
+ export const BUDGET_PERIODS = Object.freeze(["day", "week", "month"]);
287
+
288
+ /** Supported usage-history windows; the daily quota line remains today's. */
289
+ export const BUDGET_SERIES_RANGES = Object.freeze([14, 30, 90]);
290
+ export const BUDGET_SERIES_DAYS = 14;
291
+
242
292
  export function createInitialState({ mode = "local", branding = null, docs = null, themeId = null, sessionOwnerFilter = null, layoutAdjustments = null, pinnedSessionIds = null, collapsedSessionIds = null, activeSessionId = null, sessionOrder = null, rightPaneMode = null, desktopPanes: storedDesktopPanes = null, canvasPrefs = null } = {}) {
243
293
  const desktopPanes = normalizeStoredDesktopPanes(
244
294
  storedDesktopPanes,
@@ -266,6 +316,11 @@ export function createInitialState({ mode = "local", branding = null, docs = nul
266
316
  },
267
317
  ui: {
268
318
  focusRegion: FOCUS_REGIONS.SESSIONS,
319
+ // The Providers & Budgets surface (the coin button in the header).
320
+ // It REPLACES the workspace under the header — the same slot the
321
+ // admin console takes — so the two close each other. Never
322
+ // persisted: it is a place you go, not a layout you keep.
323
+ budgetOpen: false,
269
324
  inspectorTab: INSPECTOR_TABS[0],
270
325
  /** Node Map selection: short node label, scopes the Activity pane. */
271
326
  nodeMapSelectedNode: null,
@@ -458,6 +513,88 @@ export function createInitialState({ mode = "local", branding = null, docs = nul
458
513
  userStats: null,
459
514
  fetchedAt: 0,
460
515
  },
516
+ // Providers & Budgets — one table, and what it needs to draw itself.
517
+ // The table's numbers come from ONE read (getProviderUsageGrid); the
518
+ // paused list is a second read, kept because a stopped session says
519
+ // why on the session row too, not only on this screen. See
520
+ // docs/proposals/providers-and-budgets-meters.md.
521
+ budget: {
522
+ // A first load, with nothing on screen yet.
523
+ loading: false,
524
+ // A re-read WITH numbers already on screen. Separate from
525
+ // `loading` so a refresh does not blank the table someone is
526
+ // reading mid-sentence.
527
+ refreshing: false,
528
+ // Set by a successful load and never cleared by a failure.
529
+ // Without it an empty `grid` is ambiguous: "this namespace has no
530
+ // providers" and "we never found out" would look the same, and
531
+ // only one of them is safe to act on.
532
+ loaded: false,
533
+ // The message the SERVER wrote. It is written for a person and
534
+ // names the remedy, so it is passed through, never replaced.
535
+ error: null,
536
+ fetchedAt: 0,
537
+ // getProviderUsageGrid, verbatim and in render order: shared
538
+ // providers first, then the viewer's own, each immediately
539
+ // followed by its model rows. Never re-sorted.
540
+ grid: [],
541
+ // The "show overall usage" tick. Off = your usage against your
542
+ // share; on = everyone's usage against the limit. The two pairs
543
+ // of numbers are never mixed, so which one is on screen is a
544
+ // fact the table has to carry.
545
+ overall: false,
546
+ // Usage history window for both user and system reports.
547
+ rangeDays: BUDGET_SERIES_DAYS,
548
+ // The provider whose model rows are expanded and whose chart is
549
+ // drawn. Null means nothing is selected — this screen shows no
550
+ // provider until one is picked.
551
+ selectedProvider: null,
552
+ // Which row under that provider: '*' is the provider itself, and
553
+ // a qualified model reference is one of its per-model limits. The
554
+ // chart follows this, so standing on a model row shows that
555
+ // model's days alone.
556
+ selectedScope: "*",
557
+ // A name that was asked for and is not in the table. Set when a
558
+ // load drops the selection, because that is the case where
559
+ // somebody arrived here BY that name — from a session stopped on
560
+ // a provider that no longer exists — and clearing the selection
561
+ // silently would leave them with nothing to read and nothing to do.
562
+ missingProvider: null,
563
+ // The selected provider's day-by-day usage, read separately so a
564
+ // failed chart never blanks the table above it.
565
+ series: {
566
+ provider: null,
567
+ scope: "*",
568
+ rangeDays: BUDGET_SERIES_DAYS,
569
+ days: [],
570
+ loading: false,
571
+ loaded: false,
572
+ error: null,
573
+ fetchedAt: 0,
574
+ },
575
+ // Admin-only machinery spend for the selected provider. Kept
576
+ // separate from `series`: system turns are metered but exempt
577
+ // from user limits, so they must never borrow the quota line.
578
+ systemUsage: {
579
+ provider: null,
580
+ scope: "*",
581
+ rangeDays: BUDGET_SERIES_DAYS,
582
+ totals: null,
583
+ days: [],
584
+ breakdown: [],
585
+ loading: false,
586
+ loaded: false,
587
+ error: null,
588
+ fetchedAt: 0,
589
+ },
590
+ /** listPausedSessions: sessions waiting, each with its reason. */
591
+ paused: [],
592
+ // That list's OWN failure. Separate from `error`, which is the
593
+ // table's: one flag for both meant a failed waiting-list read
594
+ // marked freshly-read numbers as stale, and left the actually
595
+ // stale waiting line unmarked.
596
+ pausedError: null,
597
+ },
461
598
  admin: {
462
599
  // Whether the Admin Console is taking over the workspace and
463
600
  // hiding the session/chat panes. Persisted only in-memory.
@@ -498,9 +635,32 @@ export function createInitialState({ mode = "local", branding = null, docs = nul
498
635
  changedAt: null,
499
636
  error: null,
500
637
  },
501
- // Which settings-tree node is active: "ghcp" (GitHub Keys) or
502
- // "packages" (Agents). The tree replaces the old flat panel.
503
- section: "ghcp",
638
+ modelProviders: {
639
+ loading: false,
640
+ error: null,
641
+ page: "mine",
642
+ providers: [],
643
+ models: [],
644
+ defaults: null,
645
+ fetchedAt: 0,
646
+ mutation: { pending: null, error: null },
647
+ selection: { focus: "providers", providerName: null, agentId: null },
648
+ create: {
649
+ editing: false,
650
+ stage: "name",
651
+ name: "",
652
+ typeId: "",
653
+ shared: false,
654
+ draft: "",
655
+ cursorIndex: 0,
656
+ saving: false,
657
+ error: null,
658
+ },
659
+ },
660
+ // Which settings-tree node is active. The provider/default page
661
+ // replaces the legacy GitHub-key editor in new UI; the legacy
662
+ // state remains available for rollback compatibility only.
663
+ section: "providers",
504
664
  // Agent packages (docs/proposals/agent-packages.md) — registry
505
665
  // list, selected package detail, and the workspace viewer.
506
666
  packages: {
@@ -6,7 +6,7 @@ import {
6
6
  getPromptInputRows,
7
7
  selectActiveSession,
8
8
  selectAdminConsole,
9
- selectAdminGhcpKeyEditorModal,
9
+ selectAdminProviderCreateModal,
10
10
  selectChatPaneChrome,
11
11
  selectLiveActivityLines,
12
12
  selectChatLines,
@@ -2036,7 +2036,7 @@ function buildAdminPackagesLines(view) {
2036
2036
  lines.push([
2037
2037
  { text: " j/k ", color: "green", bold: true }, { text: "select ", color: "gray" },
2038
2038
  { text: "r ", color: "cyan", bold: true }, { text: "refresh ", color: "gray" },
2039
- { text: "g ", color: "yellow", bold: true }, { text: "GitHub Keys ", color: "gray" },
2039
+ { text: "m ", color: "yellow", bold: true }, { text: "Model Providers ", color: "gray" },
2040
2040
  { text: "Esc ", color: "red", bold: true }, { text: "close", color: "gray" },
2041
2041
  ]);
2042
2042
  return lines;
@@ -2083,7 +2083,95 @@ function buildAdminWorkersLines(view) {
2083
2083
  lines.push([
2084
2084
  { text: " r ", color: "cyan", bold: true }, { text: "refresh ", color: "gray" },
2085
2085
  { text: "a ", color: "yellow", bold: true }, { text: "Agents ", color: "gray" },
2086
- { text: "g ", color: "yellow", bold: true }, { text: "GitHub Keys ", color: "gray" },
2086
+ { text: "m ", color: "yellow", bold: true }, { text: "Model Providers ", color: "gray" },
2087
+ { text: "Esc ", color: "red", bold: true }, { text: "close", color: "gray" },
2088
+ ]);
2089
+ return lines;
2090
+ }
2091
+
2092
+ function buildAdminModelProviderLines(view) {
2093
+ const providers = view.modelProviders || {};
2094
+ const lines = [];
2095
+ const configured = (entry) => entry?.configured?.model || "automatic";
2096
+ const effective = (entry) => entry?.effective?.model || "blocked — no usable provider";
2097
+ lines.push([{ text: "Model Providers", color: "cyan", bold: true }]);
2098
+ if (providers.loading) lines.push([{ text: "Loading providers and defaults...", color: "gray" }]);
2099
+ if (providers.error || providers.mutation?.error) {
2100
+ lines.push([{ text: `! ${providers.mutation?.error || providers.error}`, color: "red", bold: true }]);
2101
+ }
2102
+ lines.push([{ text: "", color: "gray" }]);
2103
+ if (providers.page !== "shared") {
2104
+ lines.push([{ text: "My Providers", color: "white", bold: true }]);
2105
+ if (!(providers.myProviders || []).length) {
2106
+ lines.push([{ text: " No personal providers.", color: "gray" }]);
2107
+ }
2108
+ for (const provider of providers.myProviders || []) {
2109
+ const selected = providers.selection?.providerName === provider.name;
2110
+ lines.push([
2111
+ { text: selected ? "› " : " ", color: selected ? "green" : "gray", bold: selected },
2112
+ { text: provider.name, color: selected ? "white" : "gray", bold: selected },
2113
+ ...(view.isAdmin ? [{ text: provider.systemUseEnabled ? " [system]" : " [user]", color: provider.systemUseEnabled ? "green" : "gray" }] : []),
2114
+ ]);
2115
+ }
2116
+ lines.push([{ text: "", color: "gray" }]);
2117
+ lines.push([{ text: "My Session Default", color: "white", bold: true }]);
2118
+ lines.push([{ text: ` configured ${configured(providers.mySessionDefault)}`, color: "gray" }]);
2119
+ lines.push([{ text: ` effective ${effective(providers.mySessionDefault)}`, color: "cyan" }]);
2120
+ } else if (view.isAdmin) {
2121
+ lines.push([{ text: "Shared Providers", color: "white", bold: true }]);
2122
+ if (!(providers.sharedProviders || []).length) {
2123
+ lines.push([{ text: " No shared providers.", color: "gray" }]);
2124
+ }
2125
+ for (const provider of providers.sharedProviders || []) {
2126
+ const selected = providers.selection?.providerName === provider.name;
2127
+ lines.push([
2128
+ { text: selected ? "› " : " ", color: selected ? "green" : "gray", bold: selected },
2129
+ { text: provider.name, color: selected ? "white" : "gray", bold: selected },
2130
+ { text: " [shared]", color: "green" },
2131
+ ]);
2132
+ }
2133
+ lines.push([{ text: ` Cluster Session Default ${configured(providers.clusterSessionDefault)}`, color: "gray" }]);
2134
+ lines.push([{ text: ` System Session Default ${configured(providers.systemSessionDefault)}`, color: "gray" }]);
2135
+ lines.push([{ text: "", color: "gray" }]);
2136
+ lines.push([{ text: "System Agent Overrides", color: "white", bold: true }]);
2137
+ if (!(providers.systemAgentRoutes || []).length) {
2138
+ lines.push([{ text: " No registered or overridden system agents.", color: "gray" }]);
2139
+ }
2140
+ for (const route of providers.systemAgentRoutes || []) {
2141
+ const selected = providers.selection?.agentId === route.agentId;
2142
+ lines.push([
2143
+ { text: selected ? "› " : " ", color: selected ? "green" : "gray", bold: selected },
2144
+ { text: route.title, color: selected ? "white" : "gray", bold: selected },
2145
+ { text: ` ${route.effectiveModel || "blocked"}`, color: "cyan" },
2146
+ { text: route.override ? " [override]" : " [system default]", color: route.override ? "yellow" : "gray" },
2147
+ ]);
2148
+ }
2149
+ }
2150
+ lines.push([{ text: "", color: "gray" }]);
2151
+ lines.push([{ text: "Actions", color: "cyan", bold: true }]);
2152
+ if (providers.page !== "shared") {
2153
+ lines.push([
2154
+ { text: " e ", color: "green", bold: true }, { text: "add ", color: "gray" },
2155
+ { text: "d ", color: "red", bold: true }, { text: "delete ", color: "gray" },
2156
+ { text: "u ", color: "cyan", bold: true }, { text: "my default ", color: "gray" },
2157
+ ...(view.isAdmin ? [{ text: "t ", color: "yellow", bold: true }, { text: "system use ", color: "gray" }] : []),
2158
+ ]);
2159
+ } else if (view.isAdmin) {
2160
+ lines.push([
2161
+ { text: " E ", color: "green", bold: true }, { text: "add ", color: "gray" },
2162
+ { text: "d ", color: "red", bold: true }, { text: "delete ", color: "gray" },
2163
+ { text: "l ", color: "cyan", bold: true }, { text: "cluster default ", color: "gray" },
2164
+ { text: "s ", color: "cyan", bold: true }, { text: "system default ", color: "gray" },
2165
+ { text: " C/T/H ", color: "yellow", bold: true }, { text: "next system default + Complete/Terminate/Hard Delete restart ", color: "gray" },
2166
+ { text: "Tab ", color: "cyan", bold: true }, { text: "providers/agents ", color: "gray" },
2167
+ { text: "j/k ", color: "cyan", bold: true }, { text: "select ", color: "gray" },
2168
+ { text: "o ", color: "yellow", bold: true }, { text: "cycle override", color: "gray" },
2169
+ ]);
2170
+ }
2171
+ lines.push([
2172
+ { text: " r ", color: "cyan", bold: true }, { text: "refresh ", color: "gray" },
2173
+ { text: "m/M ", color: "cyan", bold: true }, { text: "my/shared ", color: "gray" },
2174
+ { text: "a ", color: "yellow", bold: true }, { text: "Agents ", color: "gray" },
2087
2175
  { text: "Esc ", color: "red", bold: true }, { text: "close", color: "gray" },
2088
2176
  ]);
2089
2177
  return lines;
@@ -2118,6 +2206,11 @@ function buildAdminConsoleLines(view) {
2118
2206
  return lines;
2119
2207
  }
2120
2208
 
2209
+ if (view.section === "providers") {
2210
+ lines.push(...buildAdminModelProviderLines(view));
2211
+ return lines;
2212
+ }
2213
+
2121
2214
  lines.push([{ text: "GitHub Copilot key", color: "cyan", bold: true }]);
2122
2215
  lines.push([
2123
2216
  { text: "Status ", color: "gray" },
@@ -2262,6 +2355,55 @@ function AdminGhcpKeyEditorModalContainer({ controller }) {
2262
2355
  return React.createElement(AdminGhcpKeyEditorModal, { state });
2263
2356
  }
2264
2357
 
2358
+ function AdminProviderCreateModal({ state }) {
2359
+ const platform = useUiPlatform();
2360
+ const modal = selectAdminProviderCreateModal(state);
2361
+ if (!modal) return null;
2362
+ const viewport = typeof platform.getViewport === "function"
2363
+ ? platform.getViewport()
2364
+ : { width: 120, height: 40 };
2365
+ const width = Math.max(56, Math.min(modal.idealWidth || 72, (viewport.width || 120) - 12));
2366
+ const statusLines = modal.error
2367
+ ? [[{ text: `! ${modal.error}`, color: "red", bold: true }]]
2368
+ : modal.saving ? [[{ text: "Creating provider...", color: "yellow" }]] : [];
2369
+ return React.createElement(platform.Overlay, null,
2370
+ React.createElement(platform.Column, { width },
2371
+ React.createElement(platform.Panel, {
2372
+ title: modal.title,
2373
+ color: "cyan",
2374
+ focused: false,
2375
+ width,
2376
+ height: Math.max(5, (modal.detailsLines?.length || 0) + 2),
2377
+ lines: modal.detailsLines,
2378
+ scrollOffset: 0,
2379
+ scrollMode: "top",
2380
+ marginBottom: 1,
2381
+ fillColor: "surface",
2382
+ }),
2383
+ React.createElement(platform.Input, {
2384
+ label: modal.label,
2385
+ value: modal.displayValue,
2386
+ cursorIndex: modal.cursorIndex,
2387
+ focused: !modal.saving,
2388
+ placeholder: modal.placeholder,
2389
+ rows: 1,
2390
+ readOnly: modal.saving,
2391
+ }),
2392
+ statusLines.length ? React.createElement(platform.Panel, {
2393
+ title: "Status", color: modal.error ? "red" : "yellow", focused: false,
2394
+ width, height: 3, lines: statusLines, scrollOffset: 0, scrollMode: "top", marginBottom: 1, fillColor: "surface",
2395
+ }) : null,
2396
+ React.createElement(platform.Panel, {
2397
+ title: "Help", color: "cyan", focused: false,
2398
+ width, height: 6, lines: modal.helpLines, scrollOffset: 0, scrollMode: "top", fillColor: "surface",
2399
+ })));
2400
+ }
2401
+
2402
+ function AdminProviderCreateModalContainer({ controller }) {
2403
+ const state = useControllerSelector(controller, (rootState) => ({ admin: rootState.admin }), shallowEqualObject);
2404
+ return React.createElement(AdminProviderCreateModal, { state });
2405
+ }
2406
+
2265
2407
  export function SharedPilotSwarmApp({ controller, versionLabel = null }) {
2266
2408
  const platform = useUiPlatform();
2267
2409
  const layoutState = useControllerSelector(controller, (state) => ({
@@ -2406,6 +2548,6 @@ export function SharedPilotSwarmApp({ controller, versionLabel = null }) {
2406
2548
  React.createElement(FilesFilterModalContainer, { controller }),
2407
2549
  React.createElement(HistoryFormatModalContainer, { controller }),
2408
2550
  React.createElement(ConfirmModalContainer, { controller }),
2409
- React.createElement(AdminGhcpKeyEditorModalContainer, { controller }),
2551
+ React.createElement(AdminProviderCreateModalContainer, { controller }),
2410
2552
  );
2411
2553
  }