maka-agent 0.2.0-dev.14.20260902 → 0.2.0-dev.16.20260903

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 (160) hide show
  1. package/dist/cli-core.js +0 -1
  2. package/dist/pi-transcript.js +48 -0
  3. package/dist/pi-tui-form-interaction.js +497 -0
  4. package/dist/pi-tui-pickers.js +256 -55
  5. package/dist/pi-tui-runner.js +215 -12
  6. package/dist/runtime-host-cli.js +17 -42
  7. package/dist/runtime-host-lifecycle-transaction.js +31 -13
  8. package/dist/runtime-host-managed-lifecycle-manager.js +1 -1
  9. package/dist/runtime-host-onboarding.js +3 -1
  10. package/dist/runtime-host-openrc-service.js +469 -0
  11. package/dist/runtime-host-run-command.js +6 -2
  12. package/dist/runtime-host-service-command.js +3 -3
  13. package/dist/runtime-host-service-management-command.js +43 -15
  14. package/dist/runtime-host-session-channel.js +3 -0
  15. package/dist/runtime-host-session-driver.js +21 -6
  16. package/dist/runtime-host-setup-command.js +30 -31
  17. package/dist/tui-context-refresh.js +103 -0
  18. package/dist/tui-copy-catalog.js +73 -0
  19. package/native/runtime-host-peer/prebuilds/darwin-arm64/maka_runtime_host_peer.node +0 -0
  20. package/native/runtime-host-peer/prebuilds/linux-arm64/maka_runtime_host_peer.node +0 -0
  21. package/native/runtime-host-peer/prebuilds/linux-x64/maka_runtime_host_peer.node +0 -0
  22. package/native/runtime-host-peer/prebuilds/win32-x64/maka_runtime_host_peer.node +0 -0
  23. package/node_modules/@maka/core/dist/chat-model-choice.js +4 -0
  24. package/node_modules/@maka/core/dist/computer-use.js +27 -92
  25. package/node_modules/@maka/core/dist/interaction.js +577 -3
  26. package/node_modules/@maka/core/dist/llm-connections.js +4 -0
  27. package/node_modules/@maka/core/dist/local-memory.js +2 -2
  28. package/node_modules/@maka/core/dist/model-call-usage-projection.js +3 -0
  29. package/node_modules/@maka/core/dist/model-metadata.js +26 -7
  30. package/node_modules/@maka/core/dist/model-thinking.js +17 -0
  31. package/node_modules/@maka/core/dist/provider-registry.js +1 -0
  32. package/node_modules/@maka/core/dist/runtime-event.js +23 -1
  33. package/node_modules/@maka/core/dist/scheduled-task.js +4 -0
  34. package/node_modules/@maka/core/dist/session.js +95 -2
  35. package/node_modules/@maka/core/dist/text-sanitize.js +19 -0
  36. package/node_modules/@maka/core/dist/usage-ledger-merge.js +3 -0
  37. package/node_modules/@maka/core/dist/usage-record-schema.js +11 -5
  38. package/node_modules/@maka/core/dist/workhub-creation-intent.js +75 -9
  39. package/node_modules/@maka/core/dist/workhub-session-resolver.js +50 -0
  40. package/node_modules/@maka/core/package.json +2 -0
  41. package/node_modules/@maka/eval/dist/harbor-external-subject.js +2 -1
  42. package/node_modules/@maka/eval/dist/harness-executor.js +3 -2
  43. package/node_modules/@maka/eval/dist/install-preflight.js +39 -10
  44. package/node_modules/@maka/eval/dist/process-termination.js +83 -0
  45. package/node_modules/@maka/mcp/dist/sep-2243.js +3 -3
  46. package/node_modules/@maka/runtime/dist/agent-run.js +6 -3
  47. package/node_modules/@maka/runtime/dist/ai-sdk-backend.js +332 -118
  48. package/node_modules/@maka/runtime/dist/ai-sdk-compaction-contract.js +6 -1
  49. package/node_modules/@maka/runtime/dist/ai-sdk-compaction.js +171 -341
  50. package/node_modules/@maka/runtime/dist/bots/telegram-bridge.js +3 -26
  51. package/node_modules/@maka/runtime/dist/bundled-skill-catalog.generated.js +1 -1
  52. package/node_modules/@maka/runtime/dist/computer-use-codec.js +1 -141
  53. package/node_modules/@maka/runtime/dist/computer-use-tools.js +23 -105
  54. package/node_modules/@maka/runtime/dist/context-budget-policy.js +20 -26
  55. package/node_modules/@maka/runtime/dist/context-budget.js +18 -20
  56. package/node_modules/@maka/runtime/dist/conversation-copy.js +23 -19
  57. package/node_modules/@maka/runtime/dist/cua-frame-state.js +1 -69
  58. package/node_modules/@maka/runtime/dist/github-copilot-oauth-enrollment.js +267 -0
  59. package/node_modules/@maka/runtime/dist/history-compact-checkpoint.js +6 -9
  60. package/node_modules/@maka/runtime/dist/history-compact-summarizer.js +67 -23
  61. package/node_modules/@maka/runtime/dist/history-compact-summary-validation.js +11 -18
  62. package/node_modules/@maka/runtime/dist/history-compaction.js +66 -73
  63. package/node_modules/@maka/runtime/dist/interaction-authority.js +69 -0
  64. package/node_modules/@maka/runtime/dist/mcp-tools.js +13 -1
  65. package/node_modules/@maka/runtime/dist/memory-extraction.js +11 -11
  66. package/node_modules/@maka/runtime/dist/model-adapter.js +24 -6
  67. package/node_modules/@maka/runtime/dist/model-factory.js +14 -5
  68. package/node_modules/@maka/runtime/dist/oauth-provider-contracts.js +28 -1
  69. package/node_modules/@maka/runtime/dist/openai-codex-history-compactor.js +7 -6
  70. package/node_modules/@maka/runtime/dist/opencode-session-header.js +29 -0
  71. package/node_modules/@maka/runtime/dist/runtime-event-read-model.js +11 -1
  72. package/node_modules/@maka/runtime/dist/runtime-kernel.js +12 -11
  73. package/node_modules/@maka/runtime/dist/runtime-read-model.js +51 -13
  74. package/node_modules/@maka/runtime/dist/scheduled-task-tools.js +3 -0
  75. package/node_modules/@maka/runtime/dist/session-event-runtime-mapper.js +26 -0
  76. package/node_modules/@maka/runtime/dist/session-manager.js +1 -0
  77. package/node_modules/@maka/runtime/dist/session-projection-helpers.js +16 -1
  78. package/node_modules/@maka/runtime/dist/stream-graph-projection.js +6 -0
  79. package/node_modules/@maka/runtime/dist/stream-graph-read-model.js +5 -0
  80. package/node_modules/@maka/runtime/dist/stream-usage-fallback-fetch.js +74 -0
  81. package/node_modules/@maka/runtime/dist/subscription-credentials.js +51 -4
  82. package/node_modules/@maka/runtime/dist/subscription-model-fetch.js +47 -3
  83. package/node_modules/@maka/runtime/dist/system-prompt/main-session-prompt.js +20 -1
  84. package/node_modules/@maka/runtime/dist/test-connection.js +18 -11
  85. package/node_modules/@maka/runtime/dist/tool-runtime.js +183 -0
  86. package/node_modules/@maka/runtime/package.json +1 -0
  87. package/node_modules/@maka/runtime-host/dist/adapter/session-projector.js +14 -0
  88. package/node_modules/@maka/runtime-host/dist/client/client-capability-channel.js +84 -1
  89. package/node_modules/@maka/runtime-host/dist/client/host-profile.js +68 -51
  90. package/node_modules/@maka/runtime-host/dist/client/index.js +1 -1
  91. package/node_modules/@maka/runtime-host/dist/client/owner-connection-code.js +8 -5
  92. package/node_modules/@maka/runtime-host/dist/client/peer-client.js +342 -36
  93. package/node_modules/@maka/runtime-host/dist/client/reconnect-lifecycle.js +60 -4
  94. package/node_modules/@maka/runtime-host/dist/peer-mesh/index.js +3 -3
  95. package/node_modules/@maka/runtime-host/dist/peer-mesh/limits.js +1 -1
  96. package/node_modules/@maka/runtime-host/dist/peer-mesh/model.js +48 -60
  97. package/node_modules/@maka/runtime-host/dist/peer-mesh/node.js +847 -431
  98. package/node_modules/@maka/runtime-host/dist/peer-mesh/owner.js +33 -74
  99. package/node_modules/@maka/runtime-host/dist/peer-mesh/store.js +82 -69
  100. package/node_modules/@maka/runtime-host/dist/peer-reachability/index.js +21 -0
  101. package/node_modules/@maka/runtime-host/dist/peer-reachability/model.js +202 -0
  102. package/node_modules/@maka/runtime-host/dist/peer-reachability/owner.js +119 -0
  103. package/node_modules/@maka/runtime-host/dist/peer-reachability/publisher.js +245 -0
  104. package/node_modules/@maka/runtime-host/dist/protocol/agent-graph.js +4 -1
  105. package/node_modules/@maka/runtime-host/dist/protocol/client-capability.js +68 -0
  106. package/node_modules/@maka/runtime-host/dist/protocol/connection-effects.js +15 -8
  107. package/node_modules/@maka/runtime-host/dist/protocol/host-status.js +7 -23
  108. package/node_modules/@maka/runtime-host/dist/protocol/index.js +47 -1
  109. package/node_modules/@maka/runtime-host/dist/protocol/oauth.js +25 -1
  110. package/node_modules/@maka/runtime-host/dist/protocol/operations.js +1 -0
  111. package/node_modules/@maka/runtime-host/dist/protocol/peer-mesh.js +14 -31
  112. package/node_modules/@maka/runtime-host/dist/protocol/scheduled-task.js +19 -6
  113. package/node_modules/@maka/runtime-host/dist/protocol/session-collaboration.js +36 -1
  114. package/node_modules/@maka/runtime-host/dist/protocol/session-revision.js +11 -2
  115. package/node_modules/@maka/runtime-host/dist/protocol/usage-pricing.js +16 -2
  116. package/node_modules/@maka/runtime-host/dist/protocol/workhub-coordination.js +51 -2
  117. package/node_modules/@maka/runtime-host/dist/server/access-authority.js +35 -2
  118. package/node_modules/@maka/runtime-host/dist/server/access-credential-store.js +1 -0
  119. package/node_modules/@maka/runtime-host/dist/server/client-capability-coordinator.js +12 -10
  120. package/node_modules/@maka/runtime-host/dist/server/client-capability-invocation-broker.js +163 -30
  121. package/node_modules/@maka/runtime-host/dist/server/connection-effect-coordinator.js +38 -14
  122. package/node_modules/@maka/runtime-host/dist/server/daily-review-coordinator.js +45 -22
  123. package/node_modules/@maka/runtime-host/dist/server/execution-composition.js +78 -20
  124. package/node_modules/@maka/runtime-host/dist/server/execution-model-authority.js +4 -2
  125. package/node_modules/@maka/runtime-host/dist/server/execution-model-composition.js +2 -1
  126. package/node_modules/@maka/runtime-host/dist/server/execution-service.js +49 -28
  127. package/node_modules/@maka/runtime-host/dist/server/host-kernel.js +3 -6
  128. package/node_modules/@maka/runtime-host/dist/server/interaction-coordinator.js +130 -27
  129. package/node_modules/@maka/runtime-host/dist/server/interaction-projection.js +30 -1
  130. package/node_modules/@maka/runtime-host/dist/server/listener-set.js +2 -4
  131. package/node_modules/@maka/runtime-host/dist/server/message-coordinator.js +16 -3
  132. package/node_modules/@maka/runtime-host/dist/server/oauth-coordinator.js +66 -3
  133. package/node_modules/@maka/runtime-host/dist/server/oauth-execution-authority.js +20 -3
  134. package/node_modules/@maka/runtime-host/dist/server/peer-listener.js +8 -21
  135. package/node_modules/@maka/runtime-host/dist/server/peer-mesh-authority.js +1 -1
  136. package/node_modules/@maka/runtime-host/dist/server/root-turn-coordinator.js +6 -3
  137. package/node_modules/@maka/runtime-host/dist/server/scheduled-task-coordinator.js +72 -12
  138. package/node_modules/@maka/runtime-host/dist/server/session-revision-coordinator.js +48 -18
  139. package/node_modules/@maka/runtime-host/dist/server/session-turn-access-request-coordinator.js +43 -26
  140. package/node_modules/@maka/runtime-host/dist/server/usage-pricing-coordinator.js +15 -1
  141. package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-action-gate.js +229 -4
  142. package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-coordinator.js +146 -8
  143. package/node_modules/@maka/runtime-host/dist/transport/peer-native.js +32 -6
  144. package/node_modules/@maka/runtime-host/package.json +1 -0
  145. package/node_modules/@maka/storage/dist/agent-run-store.js +18 -5
  146. package/node_modules/@maka/storage/dist/codex-session-adapter.js +14 -0
  147. package/node_modules/@maka/storage/dist/execution-stores.js +5 -0
  148. package/node_modules/@maka/storage/dist/interaction-store.js +13 -1
  149. package/node_modules/@maka/storage/dist/runtime-policy/connection-catalog-document.js +9 -3
  150. package/node_modules/@maka/storage/dist/runtime-policy/coordinator.js +49 -19
  151. package/node_modules/@maka/storage/dist/runtime-policy/oauth-login-receipt-document.js +3 -1
  152. package/node_modules/@maka/storage/dist/runtime-policy/onboarding-transaction.js +13 -5
  153. package/node_modules/@maka/storage/dist/session-copy-cleanup.js +4 -2
  154. package/node_modules/@maka/storage/dist/session-store.js +39 -6
  155. package/node_modules/@maka/storage/dist/sqlite-runtime-store.js +16 -9
  156. package/node_modules/@maka/storage/dist/sqlite-session-metadata-schema.js +30 -3
  157. package/node_modules/@maka/storage/dist/sqlite-session-metadata-store.js +117 -0
  158. package/node_modules/@maka/storage/dist/sqlite-usage-store.js +29 -6
  159. package/node_modules/@maka/storage/dist/usage-stores.js +3 -1
  160. package/package.json +1 -1
@@ -20,6 +20,7 @@ import { randomUUID } from 'node:crypto';
20
20
  import { basename } from 'node:path';
21
21
  import { Key, ProcessTerminal, SelectList, TuiMainScreen, isKeyRelease, isKeyRepeat, matchesKey, } from '@earendil-works/pi-tui';
22
22
  import { isThinkingLevel } from '@maka/core/model-thinking';
23
+ import { deriveConnectionSlug, } from '@maka/core/llm-connections';
23
24
  import { projectRevisionLinkedSessionTree } from '@maka/core/session-revisions';
24
25
  import { slashCommandsForSurface, } from '@maka/core/slash-command-catalog';
25
26
  import { latestAssistantModelId, } from '@maka/core/session';
@@ -32,7 +33,8 @@ import { parseGraphCommand } from '@maka/core/graph-command';
32
33
  import { parseSwarmCommand } from '@maka/core/swarm-command';
33
34
  import { inspectSessionResumeAvailability, } from './session-driver.js';
34
35
  import { SafeBoundaryResumeParkedError } from './runtime-host-session-driver.js';
35
- import { appendExpansionCollapseConfirmation, appendTurnFailureToTranscript, appendUserCommandToTranscript, appendUserPrompt, applyMakaSessionEventToTranscript, applyShellRunUpdateToTranscript, createMakaPiTranscriptState, hasRunningUserCommand, activeSandboxBoundaryRequest, activeUserQuestionRequest, applyExpansionDefaultToAll, completePendingInteraction, applyShellRunViewUpdateToTranscript, EXPANSION_COLLAPSE_CONFIRM_WINDOW_MS, hasExpandedEntriesAboveViewport, permissionModeLabel, retireCancelledTransientMessages, replaceTranscriptWithStoredMessages, hydrateToolsWithStoredMessages, submitCompactToTranscript, toggleAllThinkingExpansion, toggleAllToolExpansion, } from './pi-transcript.js';
36
+ import { appendExpansionCollapseConfirmation, appendTurnFailureToTranscript, appendUserCommandToTranscript, appendUserPrompt, applyMakaSessionEventToTranscript, applyShellRunUpdateToTranscript, createMakaPiTranscriptState, hasRunningUserCommand, activeSandboxBoundaryRequest, activeFormRequest, activeUserQuestionRequest, applyExpansionDefaultToAll, completePendingInteraction, applyShellRunViewUpdateToTranscript, EXPANSION_COLLAPSE_CONFIRM_WINDOW_MS, hasExpandedEntriesAboveViewport, permissionModeLabel, retireCancelledTransientMessages, replaceTranscriptWithStoredMessages, hydrateToolsWithStoredMessages, submitCompactToTranscript, toggleAllThinkingExpansion, toggleAllToolExpansion, } from './pi-transcript.js';
37
+ import { FormInteractionOverlay } from './pi-tui-form-interaction.js';
36
38
  import { runMakaPiTuiTurn } from './pi-tui-turn.js';
37
39
  import { editorTheme, selectListTheme } from './tui-ansi.js';
38
40
  import { MakaAutocompleteAboveEditorComponent } from './tui-autocomplete-layout.js';
@@ -42,6 +44,7 @@ import { getTuiCopyCopy, lastAssistantText, serializeTranscriptText } from './tu
42
44
  import { McpManagementOverlay } from './pi-tui-mcp-status.js';
43
45
  import { createShellRunElapsedTicker } from './shell-run-elapsed-ticker.js';
44
46
  import { createShellRunHydrationController } from './shell-run-hydration.js';
47
+ import { CTX_REFRESH_DEBOUNCE_MS, createCtxRefresher, scheduleCtxRefreshTimeout, } from './tui-context-refresh.js';
45
48
  import { sessionStatusBadge } from './tui-session-status.js';
46
49
  import { AttentionController, DISABLE_FOCUS_REPORTING, ENABLE_FOCUS_REPORTING, FOCUS_IN_SEQUENCE, FOCUS_OUT_SEQUENCE, } from './tui-attention.js';
47
50
  import { MakaActivityStripComponent, MakaPendingQueueComponent, MakaPiLayoutComponent, MakaStatusLineComponent, MakaTranscriptComponent, } from './pi-tui-layout.js';
@@ -184,6 +187,13 @@ export async function runMakaPiTui(input) {
184
187
  let userQuestionInFlight = false;
185
188
  let userQuestionOverlay;
186
189
  let userQuestionProgress;
190
+ let formResponseInFlightRequestId;
191
+ let formOverlay;
192
+ let formOverlayComponent;
193
+ let formOverlayRequestId;
194
+ let formOverlaySessionId;
195
+ let formOverlaySchema;
196
+ let retainedFormDraft;
187
197
  let turnRunning = false;
188
198
  // Monotonic generation for visible agent turns. A mid-turn `/session`
189
199
  // switch-away (#3380) bumps it to orphan the in-flight drain: every callback
@@ -369,7 +379,7 @@ export async function runMakaPiTui(input) {
369
379
  return;
370
380
  }
371
381
  permissionResponseInFlightRequestId = null;
372
- syncUserQuestionOverlay();
382
+ syncInteractionOverlays();
373
383
  requestRender();
374
384
  }) ?? (() => { });
375
385
  const unsubscribeTranscriptReplacements = input.driver.subscribeTranscriptReplacements?.((sessionId, turnId, messages, reason) => {
@@ -377,6 +387,7 @@ export async function runMakaPiTui(input) {
377
387
  return;
378
388
  if (reason === 'reconnect') {
379
389
  replaceTranscript(messages, { preserveClientLocalEntries: true });
390
+ syncInteractionOverlays();
380
391
  shellRunElapsedTicker.sync();
381
392
  requestRender();
382
393
  const messageIds = state.entries.flatMap((entry) => entry.kind === 'user' && entry.transient === true ? [entry.messageId] : []);
@@ -405,6 +416,40 @@ export async function runMakaPiTui(input) {
405
416
  now: input.shellRunTicker?.now,
406
417
  schedule: input.shellRunTicker?.schedule,
407
418
  });
419
+ // Live ctx refresh (#4545): the end-of-turn token_usage event moves the
420
+ // statusline once per turn, but the Host's latest-context snapshot moves at
421
+ // every settled provider request. Pull it on the desktop inspector's signal
422
+ // (tui-context-refresh.ts) so a long turn shows the context filling as it
423
+ // fills. The query is a plain read on the driver — deliberately not routed
424
+ // through runControl, whose serial lock exists for mutations.
425
+ const getContextDiagnostics = input.driver.getContextDiagnostics?.bind(input.driver);
426
+ const ctxRefresher = getContextDiagnostics
427
+ ? createCtxRefresher({
428
+ query: async () => {
429
+ const sessionId = input.driver.getSessionId();
430
+ const diagnostics = await getContextDiagnostics();
431
+ return { sessionId, diagnostics };
432
+ },
433
+ apply: ({ sessionId, diagnostics }) => {
434
+ // The session moved under the query (switch, /new): its usage was
435
+ // rebuilt from stored messages, and a pre-switch snapshot must not
436
+ // overwrite it.
437
+ if (closed || input.driver.getSessionId() !== sessionId)
438
+ return;
439
+ if (diagnostics.status !== 'available')
440
+ return;
441
+ const { inputTokens, contextWindow } = diagnostics;
442
+ if (inputTokens === undefined || contextWindow === undefined || contextWindow <= 0)
443
+ return;
444
+ // Same formula the token_usage path uses (#1067), from the same
445
+ // settled request — the two cannot disagree.
446
+ state.usage.contextRemaining = Math.max(0, contextWindow - inputTokens);
447
+ requestRender();
448
+ },
449
+ delayMs: input.ctxRefreshTicker?.delayMs ?? CTX_REFRESH_DEBOUNCE_MS,
450
+ schedule: input.ctxRefreshTicker?.schedule ?? scheduleCtxRefreshTimeout,
451
+ })
452
+ : undefined;
408
453
  // ── Explicit skill invocation (#1148) ────────────────────────────────────
409
454
  // One cached list feeds autocomplete, the `/skill` picker, and the editor's
410
455
  // sync highlight validator. The cache is keyed by cwd (project-level skill
@@ -568,6 +613,7 @@ export async function runMakaPiTui(input) {
568
613
  unsubscribeTranscriptReplacements();
569
614
  shellRunHydration.dispose();
570
615
  shellRunElapsedTicker.dispose();
616
+ ctxRefresher?.cancel();
571
617
  stopTurnElapsedTicker();
572
618
  setTaskbarProgress(false);
573
619
  // Drop the busy / attention title marker so the tab is not handed back to
@@ -859,6 +905,10 @@ export async function runMakaPiTui(input) {
859
905
  // The existing connection the picked provider resolved to, so saving edits
860
906
  // it in place (a Desktop-created relay may live under a custom slug).
861
907
  let wizardTarget;
908
+ // The identity step's answer for a create target. Null halves keep the wire
909
+ // target bare so any Host vintage accepts it; an edited slug/name rides on
910
+ // the target and gets `slug_taken` back when it loses.
911
+ let wizardIdentity = { slug: null, name: null };
862
912
  let wizardModels = [];
863
913
  // Authoritative ready model choices for `/model`. A startup snapshot refreshed
864
914
  // in place after `/setup` saves so newly configured models are immediately
@@ -1043,6 +1093,7 @@ export async function runMakaPiTui(input) {
1043
1093
  replaceTranscript(authoritativeAttachedTurn.messages, {
1044
1094
  preserveClientLocalEntries: true,
1045
1095
  });
1096
+ syncInteractionOverlays();
1046
1097
  shellRunHydration.reset();
1047
1098
  if (input.listShellRunUpdates) {
1048
1099
  await shellRunHydration.hydrate(authoritativeAttachedTurn.sessionId);
@@ -1067,11 +1118,14 @@ export async function runMakaPiTui(input) {
1067
1118
  // not reach the adopted Session's transcript or overlays.
1068
1119
  if (superseded())
1069
1120
  return;
1070
- if ((event.type === 'sandbox_boundary_request' || event.type === 'user_question_request') &&
1121
+ if ((event.type === 'sandbox_boundary_request' ||
1122
+ event.type === 'user_question_request' ||
1123
+ event.type === 'form_request') &&
1071
1124
  resolvedInteractionIds.delete(event.requestId)) {
1072
1125
  return;
1073
1126
  }
1074
1127
  applyMakaSessionEventToTranscript(state, event);
1128
+ ctxRefresher?.observe(event);
1075
1129
  if (event.type === 'error')
1076
1130
  attention.attentionNeeded();
1077
1131
  if (permissionResponseInFlightRequestId !== null &&
@@ -1091,7 +1145,7 @@ export async function runMakaPiTui(input) {
1091
1145
  permissionAlerted = false;
1092
1146
  }
1093
1147
  shellRunElapsedTicker.sync();
1094
- syncUserQuestionOverlay();
1148
+ syncInteractionOverlays();
1095
1149
  requestRender();
1096
1150
  },
1097
1151
  // A turn failing is worth pulling the user back, regardless of how long it
@@ -1106,7 +1160,7 @@ export async function runMakaPiTui(input) {
1106
1160
  appendTurnFailureToTranscript(state, error);
1107
1161
  attention.attentionNeeded();
1108
1162
  shellRunElapsedTicker.sync();
1109
- syncUserQuestionOverlay();
1163
+ syncInteractionOverlays();
1110
1164
  requestRender();
1111
1165
  },
1112
1166
  }).then(async (outcome) => {
@@ -1246,6 +1300,7 @@ export async function runMakaPiTui(input) {
1246
1300
  const applySwitchResult = async ({ summary, messages, activeTurn, }) => {
1247
1301
  adoptSessionMetadata(summary, false);
1248
1302
  replaceTranscript(messages);
1303
+ syncInteractionOverlays();
1249
1304
  if (connectionIdentityNotice) {
1250
1305
  state.entries.push({ kind: 'notice', level: 'error', text: connectionIdentityNotice });
1251
1306
  }
@@ -1606,7 +1661,10 @@ export async function runMakaPiTui(input) {
1606
1661
  const showBottomPicker = (picker) => tui.showOverlay(picker, {
1607
1662
  anchor: 'bottom-left',
1608
1663
  width: '100%',
1609
- maxHeight: Math.max(1, terminal.rows - BOTTOM_PICKER_MARGIN_ROWS),
1664
+ // A numeric cap would freeze today's rows into the option; '100%' is
1665
+ // re-resolved against the live terminal height on every composite, so
1666
+ // after a resize the cap still lands at rows - margin (#4610 review).
1667
+ maxHeight: '100%',
1610
1668
  margin: { bottom: BOTTOM_PICKER_MARGIN_ROWS },
1611
1669
  });
1612
1670
  const closeUserQuestionOverlay = () => {
@@ -1631,13 +1689,13 @@ export async function runMakaPiTui(input) {
1631
1689
  completePendingInteraction(state, requestId);
1632
1690
  }
1633
1691
  userQuestionProgress = undefined;
1634
- syncUserQuestionOverlay();
1692
+ syncInteractionOverlays();
1635
1693
  requestRender();
1636
1694
  })
1637
1695
  .catch((error) => {
1638
1696
  userQuestionInFlight = false;
1639
1697
  reportError(error);
1640
- syncUserQuestionOverlay();
1698
+ syncInteractionOverlays();
1641
1699
  });
1642
1700
  };
1643
1701
  const showUserQuestion = () => {
@@ -1662,6 +1720,9 @@ export async function runMakaPiTui(input) {
1662
1720
  hint: '↑↓ move · type to answer · Enter select · Esc unanswered · Ctrl+C stop',
1663
1721
  placeholder: 'Other: type your answer…',
1664
1722
  options: question.options,
1723
+ // Live budget: terminal.rows changes on resize, so read it per render
1724
+ // rather than at overlay construction.
1725
+ maxRows: () => Math.max(1, terminal.rows - BOTTOM_PICKER_MARGIN_ROWS),
1665
1726
  onSelectOption: (index) => advance(question.options[index]?.label ?? null),
1666
1727
  onSubmitText: (value) => advance(value),
1667
1728
  onSkip: () => advance(null),
@@ -1685,6 +1746,120 @@ export async function runMakaPiTui(input) {
1685
1746
  showUserQuestion();
1686
1747
  }
1687
1748
  };
1749
+ const closeFormOverlay = (retainDraft = true) => {
1750
+ if (retainDraft &&
1751
+ formOverlayComponent &&
1752
+ formOverlaySessionId &&
1753
+ formOverlayRequestId &&
1754
+ formOverlaySchema) {
1755
+ retainedFormDraft = {
1756
+ sessionId: formOverlaySessionId,
1757
+ requestId: formOverlayRequestId,
1758
+ schema: formOverlaySchema,
1759
+ drafts: formOverlayComponent.snapshotDrafts(),
1760
+ };
1761
+ }
1762
+ formOverlay?.hide();
1763
+ formOverlay = undefined;
1764
+ formOverlayComponent = undefined;
1765
+ formOverlayRequestId = undefined;
1766
+ formOverlaySessionId = undefined;
1767
+ formOverlaySchema = undefined;
1768
+ };
1769
+ const finishUserForm = (response) => {
1770
+ if (formResponseInFlightRequestId)
1771
+ return;
1772
+ const respond = input.driver.respondToUserForm;
1773
+ if (!respond) {
1774
+ formOverlayComponent?.setSubmissionFailed();
1775
+ reportError(new Error('User forms are unavailable on this driver.'));
1776
+ return;
1777
+ }
1778
+ const responseSessionId = formOverlaySessionId ?? input.driver.getSessionId();
1779
+ formResponseInFlightRequestId = response.requestId;
1780
+ void respond
1781
+ .call(input.driver, response)
1782
+ .then(() => {
1783
+ if (formResponseInFlightRequestId === response.requestId) {
1784
+ formResponseInFlightRequestId = undefined;
1785
+ }
1786
+ if (input.driver.getSessionId() === responseSessionId &&
1787
+ activeFormRequest(state)?.requestId === response.requestId) {
1788
+ completePendingInteraction(state, response.requestId);
1789
+ }
1790
+ if (retainedFormDraft?.sessionId === responseSessionId &&
1791
+ retainedFormDraft.requestId === response.requestId) {
1792
+ retainedFormDraft = undefined;
1793
+ }
1794
+ if (formOverlaySessionId === responseSessionId &&
1795
+ formOverlayRequestId === response.requestId) {
1796
+ closeFormOverlay(false);
1797
+ }
1798
+ syncInteractionOverlays();
1799
+ requestRender();
1800
+ })
1801
+ .catch((error) => {
1802
+ if (formResponseInFlightRequestId === response.requestId) {
1803
+ formResponseInFlightRequestId = undefined;
1804
+ }
1805
+ if (activeFormRequest(state)?.requestId === response.requestId &&
1806
+ formOverlaySessionId === responseSessionId &&
1807
+ formOverlayRequestId === response.requestId) {
1808
+ formOverlayComponent?.setSubmissionFailed();
1809
+ }
1810
+ else {
1811
+ closeFormOverlay();
1812
+ syncInteractionOverlays();
1813
+ }
1814
+ reportError(error);
1815
+ requestRender();
1816
+ });
1817
+ };
1818
+ const syncFormOverlay = () => {
1819
+ const request = activeFormRequest(state);
1820
+ if (!request) {
1821
+ closeFormOverlay();
1822
+ return;
1823
+ }
1824
+ const sessionId = input.driver.getSessionId();
1825
+ if (!sessionId) {
1826
+ closeFormOverlay();
1827
+ return;
1828
+ }
1829
+ if (retainedFormDraft?.sessionId === sessionId &&
1830
+ retainedFormDraft.requestId !== request.requestId) {
1831
+ retainedFormDraft = undefined;
1832
+ }
1833
+ if (formOverlaySessionId !== sessionId || formOverlayRequestId !== request.requestId)
1834
+ closeFormOverlay();
1835
+ if (formResponseInFlightRequestId || formOverlayComponent)
1836
+ return;
1837
+ const schema = JSON.stringify(request.fields);
1838
+ const restoredDrafts = retainedFormDraft?.sessionId === sessionId &&
1839
+ retainedFormDraft.requestId === request.requestId &&
1840
+ retainedFormDraft.schema === schema
1841
+ ? retainedFormDraft.drafts
1842
+ : undefined;
1843
+ if (retainedFormDraft?.sessionId === sessionId &&
1844
+ retainedFormDraft.requestId === request.requestId &&
1845
+ retainedFormDraft.schema !== schema) {
1846
+ retainedFormDraft = undefined;
1847
+ }
1848
+ formOverlayComponent = new FormInteractionOverlay(tui, {
1849
+ locale,
1850
+ request,
1851
+ initialDrafts: restoredDrafts,
1852
+ onRespond: finishUserForm,
1853
+ });
1854
+ formOverlaySessionId = sessionId;
1855
+ formOverlaySchema = schema;
1856
+ formOverlayRequestId = request.requestId;
1857
+ formOverlay = showBottomPicker(formOverlayComponent);
1858
+ };
1859
+ const syncInteractionOverlays = () => {
1860
+ syncUserQuestionOverlay();
1861
+ syncFormOverlay();
1862
+ };
1688
1863
  const showSelectPicker = (title, rightLabel, items, onSelect, options) => {
1689
1864
  const list = new SelectList(items, 10, selectListTheme(), {
1690
1865
  minPrimaryColumnWidth: options.minPrimaryColumnWidth,
@@ -1717,6 +1892,7 @@ export async function runMakaPiTui(input) {
1717
1892
  wizardApiKey = '';
1718
1893
  wizardBaseUrl = '';
1719
1894
  wizardTarget = undefined;
1895
+ wizardIdentity = { slug: null, name: null };
1720
1896
  wizardModels = [];
1721
1897
  };
1722
1898
  // Key submit from the wizard. Slash commands route as commands (so /exit
@@ -1745,7 +1921,13 @@ export async function runMakaPiTui(input) {
1745
1921
  if (closed || wizard !== targetWizard || attempt !== wizardAttempt)
1746
1922
  return;
1747
1923
  if (result.kind !== 'ok') {
1748
- wizard.setKeyError(onboardingFailureMessage(result, locale));
1924
+ // A rejected slug is the identity step's to fix, not the key's.
1925
+ if (result.kind === 'rejected' && result.reason === 'slug_taken') {
1926
+ wizard.setIdentityError(onboardingFailureMessage(result, locale));
1927
+ }
1928
+ else {
1929
+ wizard.setKeyError(onboardingFailureMessage(result, locale));
1930
+ }
1749
1931
  requestRender();
1750
1932
  return;
1751
1933
  }
@@ -1787,7 +1969,12 @@ export async function runMakaPiTui(input) {
1787
1969
  if (result.kind !== 'ok') {
1788
1970
  if (closed || wizard !== targetWizard || attempt !== wizardAttempt)
1789
1971
  return;
1790
- wizard.setModelError(onboardingFailureMessage(result, locale));
1972
+ if (result.kind === 'rejected' && result.reason === 'slug_taken') {
1973
+ wizard.setIdentityError(onboardingFailureMessage(result, locale));
1974
+ }
1975
+ else {
1976
+ wizard.setModelError(onboardingFailureMessage(result, locale));
1977
+ }
1791
1978
  requestRender();
1792
1979
  return;
1793
1980
  }
@@ -1845,6 +2032,7 @@ export async function runMakaPiTui(input) {
1845
2032
  ...provider,
1846
2033
  target: { kind: 'create', providerType: provider.providerType },
1847
2034
  label: provider.label,
2035
+ suggestedSlug: deriveConnectionSlug(provider.providerType),
1848
2036
  enabledModelIds: [],
1849
2037
  }));
1850
2038
  }
@@ -1866,12 +2054,25 @@ export async function runMakaPiTui(input) {
1866
2054
  // reselects the same catalog row. A late save may converge only the
1867
2055
  // exact target object captured by its own submit.
1868
2056
  wizardTarget = { ...provider.target };
2057
+ wizardIdentity = { slug: null, name: null };
1869
2058
  wizardApiKey = '';
1870
2059
  wizardBaseUrl = '';
1871
2060
  wizardModels = [];
1872
2061
  wizardAttempt += 1; // a new pick supersedes any in-flight attempt
1873
2062
  requestRender();
1874
2063
  },
2064
+ onSubmitIdentity: (identity) => {
2065
+ wizardIdentity = identity;
2066
+ if (wizardTarget?.kind === 'create') {
2067
+ wizardTarget = {
2068
+ kind: 'create',
2069
+ providerType: wizardTarget.providerType,
2070
+ ...(identity.slug === null ? {} : { slug: identity.slug }),
2071
+ ...(identity.name === null ? {} : { name: identity.name }),
2072
+ };
2073
+ }
2074
+ requestRender();
2075
+ },
1875
2076
  onSubmitBaseUrl: (baseUrl) => {
1876
2077
  wizardBaseUrl = baseUrl;
1877
2078
  requestRender();
@@ -2038,8 +2239,9 @@ export async function runMakaPiTui(input) {
2038
2239
  try {
2039
2240
  for await (const event of input.driver.resumeLatest()) {
2040
2241
  applyMakaSessionEventToTranscript(state, event);
2242
+ ctxRefresher?.observe(event);
2041
2243
  shellRunElapsedTicker.sync();
2042
- syncUserQuestionOverlay();
2244
+ syncInteractionOverlays();
2043
2245
  requestRender();
2044
2246
  }
2045
2247
  }
@@ -2240,6 +2442,7 @@ export async function runMakaPiTui(input) {
2240
2442
  // session, send a prompt to begin" cue. A notice here would make entries
2241
2443
  // non-empty and suppress it.
2242
2444
  replaceTranscript([]);
2445
+ syncInteractionOverlays();
2243
2446
  shellRunElapsedTicker.sync();
2244
2447
  await discardCurrentSidePair();
2245
2448
  requestRender();
@@ -3277,7 +3480,7 @@ export async function runMakaPiTui(input) {
3277
3480
  void runControl(closeSideConversation);
3278
3481
  return { consume: true };
3279
3482
  }
3280
- if (activeUserQuestionRequest(state) &&
3483
+ if ((activeUserQuestionRequest(state) || activeFormRequest(state)) &&
3281
3484
  turnRunning &&
3282
3485
  matchesKey(data, Key.ctrl('c')) &&
3283
3486
  !isKeyRepeat(data)) {
@@ -1347,11 +1347,8 @@ function parseProfileCommand(argv) {
1347
1347
  let sshRemotePort;
1348
1348
  let sshWebSocketPath = '/runtime-host';
1349
1349
  let sshWebSocketPathConfigured = false;
1350
- let peerId;
1351
1350
  let wslDistribution;
1352
1351
  let operatorPath;
1353
- const peerRouteHints = [];
1354
- const peerCoordinationRelays = [];
1355
1352
  let expectedRootId;
1356
1353
  let credentialEnv;
1357
1354
  for (let index = 1; index < argv.length; index += 1) {
@@ -1364,9 +1361,6 @@ function parseProfileCommand(argv) {
1364
1361
  argument !== '--ssh-port' &&
1365
1362
  argument !== '--ssh-remote-port' &&
1366
1363
  argument !== '--ssh-websocket-path' &&
1367
- argument !== '--peer-id' &&
1368
- argument !== '--peer-route' &&
1369
- argument !== '--peer-coordination-relay' &&
1370
1364
  argument !== '--wsl-distribution' &&
1371
1365
  argument !== '--operator-path' &&
1372
1366
  argument !== '--expected-root' &&
@@ -1399,12 +1393,6 @@ function parseProfileCommand(argv) {
1399
1393
  sshWebSocketPath = parsed;
1400
1394
  sshWebSocketPathConfigured = true;
1401
1395
  }
1402
- if (argument === '--peer-id')
1403
- peerId = parsed;
1404
- if (argument === '--peer-route')
1405
- peerRouteHints.push(parsed);
1406
- if (argument === '--peer-coordination-relay')
1407
- peerCoordinationRelays.push(parsed);
1408
1396
  if (argument === '--wsl-distribution')
1409
1397
  wslDistribution = parsed;
1410
1398
  if (argument === '--operator-path')
@@ -1422,10 +1410,9 @@ function parseProfileCommand(argv) {
1422
1410
  if ((tlsUrl ? 1 : 0) +
1423
1411
  (plaintextUrl ? 1 : 0) +
1424
1412
  (sshDestination ? 1 : 0) +
1425
- (peerId ? 1 : 0) +
1426
1413
  (wslDistribution ? 1 : 0) !==
1427
1414
  1) {
1428
- return error('exactly one of --tls-url, --plaintext-url, --ssh-destination, --peer-id, or --wsl-distribution is required');
1415
+ return error('exactly one of --tls-url, --plaintext-url, --ssh-destination, or --wsl-distribution is required');
1429
1416
  }
1430
1417
  if (wslDistribution && !operatorPath) {
1431
1418
  return error('--wsl-distribution requires --operator-path');
@@ -1449,12 +1436,6 @@ function parseProfileCommand(argv) {
1449
1436
  if (sshDestination && !sshRemotePort) {
1450
1437
  return error('--ssh-destination requires --ssh-remote-port');
1451
1438
  }
1452
- if (!peerId && (peerRouteHints.length > 0 || peerCoordinationRelays.length > 0)) {
1453
- return error('peer route options require --peer-id');
1454
- }
1455
- if (peerId && peerRouteHints.length === 0 && peerCoordinationRelays.length === 0) {
1456
- return error('--peer-id requires at least one --peer-route or --peer-coordination-relay');
1457
- }
1458
1439
  if (sshPort !== undefined && (!Number.isInteger(sshPort) || sshPort < 1 || sshPort > 65_535)) {
1459
1440
  return error('--ssh-port must be an integer between 1 and 65535');
1460
1441
  }
@@ -1474,32 +1455,26 @@ function parseProfileCommand(argv) {
1474
1455
  expectedRootId,
1475
1456
  };
1476
1457
  }
1458
+ const transport = tlsUrl
1459
+ ? { kind: 'tls', url: tlsUrl }
1460
+ : plaintextUrl
1461
+ ? {
1462
+ kind: 'plaintext',
1463
+ url: plaintextUrl,
1464
+ acknowledgement: 'plaintext-bearer-v1',
1465
+ }
1466
+ : {
1467
+ kind: 'ssh',
1468
+ destination: sshDestination,
1469
+ ...(sshPort === undefined ? {} : { sshPort }),
1470
+ remotePort: sshRemotePort,
1471
+ websocketPath: sshWebSocketPath,
1472
+ };
1477
1473
  return {
1478
1474
  kind: 'runtime-host-profile-set',
1479
1475
  id,
1480
1476
  name,
1481
- transport: tlsUrl
1482
- ? { kind: 'tls', url: tlsUrl }
1483
- : plaintextUrl
1484
- ? {
1485
- kind: 'plaintext',
1486
- url: plaintextUrl,
1487
- acknowledgement: 'plaintext-bearer-v1',
1488
- }
1489
- : sshDestination
1490
- ? {
1491
- kind: 'ssh',
1492
- destination: sshDestination,
1493
- ...(sshPort === undefined ? {} : { sshPort }),
1494
- remotePort: sshRemotePort,
1495
- websocketPath: sshWebSocketPath,
1496
- }
1497
- : {
1498
- kind: 'libp2p-direct',
1499
- peerId: peerId,
1500
- routeHints: peerRouteHints,
1501
- coordinationRelays: peerCoordinationRelays,
1502
- },
1477
+ transport,
1503
1478
  expectedRootId,
1504
1479
  ...(credentialEnv ? { credentialEnv } : {}),
1505
1480
  };
@@ -20,7 +20,7 @@ import { randomUUID } from 'node:crypto';
20
20
  import { join } from 'node:path';
21
21
  import { isDeepStrictEqual } from 'node:util';
22
22
  import { resolveExistingStorageRoot, tryAcquireStateRootOwner, } from '@maka/storage/root-authority';
23
- import { connectExistingRuntimeHost, prepareConnectedRuntimeHostRetirement, waitForRuntimeHostReady, } from '@maka/runtime-host/client';
23
+ import { connectExistingRuntimeHost, prepareConnectedRuntimeHostRetirement, RuntimeHostOperationError, RuntimeHostRequestInterruptedError, waitForRuntimeHostReady, } from '@maka/runtime-host/client';
24
24
  import { RUNTIME_HOST_PROTOCOL_VERSION } from '@maka/runtime-host/protocol';
25
25
  import { beginRuntimeHostManagedDeploymentTransition, blockRuntimeHostManagedDeploymentTransition, commitRuntimeHostManagedDeploymentTransition, decodeRuntimeHostManagedDeploymentConfig, readRuntimeHostManagedDeploymentAuthorityRecord, resolveRuntimeHostManagedDeploymentAuthority, resolveRuntimeHostNpmDeploymentLayout, rollbackRuntimeHostManagedDeploymentTransition, RuntimeHostManagedDeploymentError, } from '@maka/runtime-host/operator';
26
26
  /** The budget a managed Runtime Host has to become reachable after its lifecycle is activated. */
@@ -198,7 +198,7 @@ export async function retireRuntimeHostLifecycleOwner(input) {
198
198
  throw error;
199
199
  }
200
200
  }
201
- const connected = await connectExistingRuntimeHost({
201
+ const connected = await (input.connectExisting ?? connectExistingRuntimeHost)({
202
202
  rootPath: capability.canonicalPath,
203
203
  protocol: {
204
204
  min: RUNTIME_HOST_PROTOCOL_VERSION,
@@ -220,22 +220,35 @@ export async function retireRuntimeHostLifecycleOwner(input) {
220
220
  throw new RuntimeHostLifecycleTransactionError('transition_failed', `Runtime Host cannot prepare for retirement: ${connected.kind}`);
221
221
  }
222
222
  try {
223
- const diagnostics = await connected.connection.request('host.diagnostics.query', {});
224
223
  const supervisorStatus = await input.supervisor?.status();
225
224
  if (supervisorStatus)
226
225
  assertExpectedSupervisorOwner(input.expectedOwner, supervisorStatus);
227
226
  if (supervisorStatus &&
228
- (!supervisorStatus.active || supervisorStatus.pid !== diagnostics.pid)) {
229
- throw new RuntimeHostLifecycleTransactionError('transition_failed', 'The supervisor and State Root report different Runtime Host processes');
227
+ (!supervisorStatus.active || supervisorStatus.pid !== connected.registration.pid)) {
228
+ throw new RuntimeHostLifecycleTransactionError('transition_failed', 'The supervisor and Runtime Host registration report different processes');
230
229
  }
231
- // The exact Root owner and canonical supervisor now agree while the deployment lock is held.
232
- // This admits retirement of that deployment; a later same-deployment restart is not a new
233
- // authority, but it must not acquire the Root before the supervisor is retired.
234
- const prepared = await prepareConnectedRuntimeHostRetirement(connected.connection, input.allowInterruptActiveTasks ? 'interrupt_active_work' : 'refuse_active_work');
235
- if (prepared.kind === 'active_tasks')
236
- return prepared;
237
- if (prepared.pid !== diagnostics.pid) {
238
- throw new RuntimeHostLifecycleTransactionError('transition_failed', 'The Runtime Host process changed while retirement was prepared');
230
+ try {
231
+ const diagnostics = await connected.connection.request('host.diagnostics.query', {});
232
+ if (diagnostics.pid !== connected.registration.pid) {
233
+ throw new RuntimeHostLifecycleTransactionError('transition_failed', 'The Runtime Host registration and diagnostics report different processes');
234
+ }
235
+ // The exact Root owner and canonical supervisor now agree while the deployment lock is held.
236
+ // This admits retirement of that deployment; a later same-deployment restart is not a new
237
+ // authority, but it must not acquire the Root before the supervisor is retired.
238
+ const prepared = await prepareConnectedRuntimeHostRetirement(connected.connection, input.allowInterruptActiveTasks ? 'interrupt_active_work' : 'refuse_active_work');
239
+ if (prepared.kind === 'active_tasks')
240
+ return prepared;
241
+ if (prepared.pid !== diagnostics.pid) {
242
+ throw new RuntimeHostLifecycleTransactionError('transition_failed', 'The Runtime Host process changed while retirement was prepared');
243
+ }
244
+ }
245
+ catch (error) {
246
+ if (!isRuntimeHostRetirementUnavailable(error) || !input.supervisor)
247
+ throw error;
248
+ if (!input.allowInterruptActiveTasks)
249
+ return { kind: 'active_tasks' };
250
+ await input.supervisor.retire();
251
+ return waitForRuntimeHostLifecycleOwner(capability, input.timeoutMs ?? 45_000);
239
252
  }
240
253
  const retirement = await waitForRuntimeHostLifecycleOwner(capability, input.timeoutMs ?? 45_000);
241
254
  try {
@@ -251,6 +264,11 @@ export async function retireRuntimeHostLifecycleOwner(input) {
251
264
  await connected.connection.close().catch(() => undefined);
252
265
  }
253
266
  }
267
+ function isRuntimeHostRetirementUnavailable(error) {
268
+ return (error instanceof RuntimeHostRequestInterruptedError ||
269
+ (error instanceof RuntimeHostOperationError &&
270
+ (error.code === 'host_not_ready' || error.code === 'host_draining')));
271
+ }
254
272
  function assertExpectedRuntimeHostOwner(expected, observed) {
255
273
  if (!expected)
256
274
  return;
@@ -276,7 +276,7 @@ function absentStatus(config) {
276
276
  function presentationManager(config) {
277
277
  if (config.lifecycle.mode === 'on_demand')
278
278
  return 'on_demand';
279
- return config.lifecycle.provider === 'systemd_user' ? 'systemd_user' : 'launch_agent';
279
+ return config.lifecycle.provider;
280
280
  }
281
281
  function projectLegacyConfig(config) {
282
282
  const layout = resolveRuntimeHostNpmDeploymentLayout(config.deploymentRoot, config.launch.package.integrity);
@@ -16,7 +16,7 @@
16
16
  * specific language governing permissions and limitations
17
17
  * under the License.
18
18
  */
19
- import { offerableCatalogEntries } from '@maka/core/llm-connections';
19
+ import { deriveConnectionSlug, offerableCatalogEntries } from '@maka/core/llm-connections';
20
20
  import { readRuntimeHostConnectionCatalog, } from '@maka/runtime-host/client';
21
21
  import { listApiKeyOnboardableProviders } from './onboarding-catalog.js';
22
22
  /** Adapt the TUI onboarding workflow to Host-owned verification and persistence. */
@@ -115,6 +115,7 @@ export function projectRuntimeHostConnectionIdentities(catalog) {
115
115
  }
116
116
  export function projectProviders(catalog) {
117
117
  const entries = [];
118
+ const existingSlugs = catalog.connections.map((connection) => connection.slug);
118
119
  for (const provider of listApiKeyOnboardableProviders()) {
119
120
  for (const connection of catalog.connections) {
120
121
  if (connection.providerType !== provider.providerType)
@@ -131,6 +132,7 @@ export function projectProviders(catalog) {
131
132
  ...provider,
132
133
  target: { kind: 'create', providerType: provider.providerType },
133
134
  label: provider.label,
135
+ suggestedSlug: deriveConnectionSlug(provider.providerType, existingSlugs),
134
136
  enabledModelIds: [],
135
137
  });
136
138
  }