maka-agent 0.2.0-dev.23.20260906 → 0.2.0-dev.25.20260908

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 (215) hide show
  1. package/README.md +38 -19
  2. package/README.zh-CN.md +34 -19
  3. package/dist/acp/maka-acp-agent.js +2 -1
  4. package/dist/acp/session-configuration.js +143 -0
  5. package/dist/acp/session-registry.js +90 -4
  6. package/dist/cli-core.js +2 -0
  7. package/dist/pi-transcript-tools.js +6 -0
  8. package/dist/pi-transcript.js +5 -12
  9. package/dist/pi-tui-layout.js +56 -10
  10. package/dist/pi-tui-pickers.js +102 -1
  11. package/dist/pi-tui-runner.js +230 -46
  12. package/dist/pi-tui-todo.js +221 -0
  13. package/dist/pi-tui-transcript-viewer.js +134 -7
  14. package/dist/runtime-host-cli-context.js +224 -78
  15. package/dist/runtime-host-cli-installation.js +8 -2
  16. package/dist/runtime-host-cli.js +31 -1
  17. package/dist/runtime-host-handoff-surface.js +106 -0
  18. package/dist/runtime-host-installed-update-bootstrap.js +13 -0
  19. package/dist/runtime-host-installed-update-coordinator.js +33 -0
  20. package/dist/runtime-host-lifecycle-transaction.js +9 -1
  21. package/dist/runtime-host-local-handoff.js +48 -5
  22. package/dist/runtime-host-local-managed-activation.js +84 -0
  23. package/dist/runtime-host-local-source-retirement.js +18 -2
  24. package/dist/runtime-host-managed-lifecycle-manager.js +1 -0
  25. package/dist/runtime-host-operator-retirement.js +50 -0
  26. package/dist/runtime-host-service-manager.js +3 -3
  27. package/dist/runtime-host-session-channel.js +13 -0
  28. package/dist/runtime-host-session-driver.js +46 -26
  29. package/dist/runtime-host-session-update.js +62 -0
  30. package/dist/runtime-host-tui-command.js +38 -73
  31. package/dist/runtime-host-tui-context.js +1 -0
  32. package/dist/runtime-host-tui-owner.js +226 -0
  33. package/dist/tui-copy-catalog.js +219 -6
  34. package/dist/tui-host-owner-copy.js +24 -0
  35. package/native/runtime-host-windows-task-launcher/prebuilds/win32-x64/maka-runtime-host-task-launcher.exe +0 -0
  36. package/node_modules/@maka/core/dist/agent-run.js +1 -0
  37. package/node_modules/@maka/core/dist/attachments.js +3 -0
  38. package/node_modules/@maka/core/dist/canonical-json.js +27 -0
  39. package/node_modules/@maka/core/dist/canonical-runtime-event.js +3 -1
  40. package/node_modules/@maka/core/dist/capabilities.js +35 -0
  41. package/node_modules/@maka/core/dist/computer-use.js +0 -1
  42. package/node_modules/@maka/core/dist/display-redaction.js +18 -0
  43. package/node_modules/@maka/core/dist/llm-connections.js +13 -0
  44. package/node_modules/@maka/core/dist/model-call-attempt.js +2 -0
  45. package/node_modules/@maka/core/dist/model-failure.js +40 -0
  46. package/node_modules/@maka/core/dist/model-metadata.generated.js +4 -4
  47. package/node_modules/@maka/core/dist/model-metadata.js +7 -3
  48. package/node_modules/@maka/core/dist/model-web-search.js +5 -4
  49. package/node_modules/@maka/core/dist/provider-registry.js +45 -4
  50. package/node_modules/@maka/core/dist/record-schema.js +9 -2
  51. package/node_modules/@maka/core/dist/redaction.js +35 -0
  52. package/node_modules/@maka/core/dist/run-composition.js +77 -2
  53. package/node_modules/@maka/core/dist/runtime-boundary.js +31 -11
  54. package/node_modules/@maka/core/dist/runtime-event.js +37 -6
  55. package/node_modules/@maka/core/dist/runtime-handoff.js +98 -0
  56. package/node_modules/@maka/core/dist/runtime-invocation.js +1 -1
  57. package/node_modules/@maka/core/dist/runtime-logical-execution.js +112 -0
  58. package/node_modules/@maka/core/dist/session.js +84 -56
  59. package/node_modules/@maka/core/dist/slash-command-catalog.js +3 -0
  60. package/node_modules/@maka/core/dist/tool-result-archive-evidence.js +20 -0
  61. package/node_modules/@maka/core/dist/tool-result-record-schema.js +2 -1
  62. package/node_modules/@maka/core/dist/usage-record-schema.js +26 -35
  63. package/node_modules/@maka/core/package.json +5 -0
  64. package/node_modules/@maka/eval/dist/experiment-directory.js +4 -13
  65. package/node_modules/@maka/mcp/dist/index.js +131 -1
  66. package/node_modules/@maka/runtime/dist/agent-run-inspect.js +0 -13
  67. package/node_modules/@maka/runtime/dist/agent-run.js +351 -105
  68. package/node_modules/@maka/runtime/dist/ai-sdk-backend.js +29 -13
  69. package/node_modules/@maka/runtime/dist/ai-sdk-compaction.js +109 -34
  70. package/node_modules/@maka/runtime/dist/ai-sdk-turn.js +184 -183
  71. package/node_modules/@maka/runtime/dist/archive-read-tool.js +2 -2
  72. package/node_modules/@maka/runtime/dist/context-budget-helpers.js +0 -16
  73. package/node_modules/@maka/runtime/dist/context-budget.js +14 -9
  74. package/node_modules/@maka/runtime/dist/conversation-copy.js +158 -15
  75. package/node_modules/@maka/runtime/dist/github-copilot-oauth-enrollment.js +3 -3
  76. package/node_modules/@maka/runtime/dist/goal-continuation.js +36 -4
  77. package/node_modules/@maka/runtime/dist/history-compact-checkpoint.js +18 -9
  78. package/node_modules/@maka/runtime/dist/history-compact-summarizer.js +30 -22
  79. package/node_modules/@maka/runtime/dist/history-compaction.js +29 -4
  80. package/node_modules/@maka/runtime/dist/ledger-tool-result-archive-reader.js +174 -0
  81. package/node_modules/@maka/runtime/dist/mcp-tools.js +7 -2
  82. package/node_modules/@maka/runtime/dist/message-authority.js +9 -0
  83. package/node_modules/@maka/runtime/dist/model-adapter.js +19 -98
  84. package/node_modules/@maka/runtime/dist/model-factory.js +19 -81
  85. package/node_modules/@maka/runtime/dist/model-fetcher.js +49 -2
  86. package/node_modules/@maka/runtime/dist/model-history.js +0 -112
  87. package/node_modules/@maka/runtime/dist/model-runtime.js +85 -111
  88. package/node_modules/@maka/runtime/dist/native-web-search-tool.js +2 -1
  89. package/node_modules/@maka/runtime/dist/openai-codex-history-compactor.js +2 -2
  90. package/node_modules/@maka/runtime/dist/opencode-session-header.js +4 -2
  91. package/node_modules/@maka/runtime/dist/plugin-runtime.js +20 -10
  92. package/node_modules/@maka/runtime/dist/plugin-tool-service.js +205 -0
  93. package/node_modules/@maka/runtime/dist/provider-error-classification.js +84 -123
  94. package/node_modules/@maka/runtime/dist/provider-request-telemetry.js +76 -109
  95. package/node_modules/@maka/runtime/dist/request-shape.js +23 -0
  96. package/node_modules/@maka/runtime/dist/run-handoff-gate.js +97 -0
  97. package/node_modules/@maka/runtime/dist/runtime-event-backfill.js +83 -55
  98. package/node_modules/@maka/runtime/dist/runtime-event-read-model.js +121 -159
  99. package/node_modules/@maka/runtime/dist/runtime-kernel.js +157 -112
  100. package/node_modules/@maka/runtime/dist/runtime-ledger-repair.js +160 -79
  101. package/node_modules/@maka/runtime/dist/runtime-read-model.js +30 -89
  102. package/node_modules/@maka/runtime/dist/runtime-resume.js +80 -4
  103. package/node_modules/@maka/runtime/dist/session-event-runtime-mapper.js +5 -0
  104. package/node_modules/@maka/runtime/dist/session-manager.js +171 -288
  105. package/node_modules/@maka/runtime/dist/session-projection-helpers.js +0 -27
  106. package/node_modules/@maka/runtime/dist/stream-graph-coordinator.js +21 -0
  107. package/node_modules/@maka/runtime/dist/stream-graph-supervisor-tools.js +0 -5
  108. package/node_modules/@maka/runtime/dist/subscription-model-fetch.js +3 -4
  109. package/node_modules/@maka/runtime/dist/test-connection.js +16 -17
  110. package/node_modules/@maka/runtime/dist/tool-activation-identity.js +41 -0
  111. package/node_modules/@maka/runtime/dist/tool-availability.js +11 -1
  112. package/node_modules/@maka/runtime/dist/tool-result-archive-encoding.js +38 -0
  113. package/node_modules/@maka/runtime/dist/tool-result-archive-resource.js +63 -1
  114. package/node_modules/@maka/runtime/dist/tool-result-archive-transition.js +42 -12
  115. package/node_modules/@maka/runtime/dist/tool-result-archive.js +27 -4
  116. package/node_modules/@maka/runtime/dist/tool-runtime.js +3 -61
  117. package/node_modules/@maka/runtime/package.json +2 -0
  118. package/node_modules/@maka/runtime-host/dist/adapter/session-projector.js +35 -0
  119. package/node_modules/@maka/runtime-host/dist/client/connect-or-spawn.js +9 -1
  120. package/node_modules/@maka/runtime-host/dist/client/connection.js +3 -0
  121. package/node_modules/@maka/runtime-host/dist/client/host-handoff-copy.js +179 -0
  122. package/node_modules/@maka/runtime-host/dist/client/host-handoff.js +275 -0
  123. package/node_modules/@maka/runtime-host/dist/client/host-retirement.js +26 -5
  124. package/node_modules/@maka/runtime-host/dist/client/index.js +2 -0
  125. package/node_modules/@maka/runtime-host/dist/client/launcher.js +3 -0
  126. package/node_modules/@maka/runtime-host/dist/client/remote-compatibility-error.js +2 -0
  127. package/node_modules/@maka/runtime-host/dist/client/session-subscription.js +46 -5
  128. package/node_modules/@maka/runtime-host/dist/control/endpoint.js +1 -3
  129. package/node_modules/@maka/runtime-host/dist/node-error.js +22 -0
  130. package/node_modules/@maka/runtime-host/dist/operator/index.js +2 -1
  131. package/node_modules/@maka/runtime-host/dist/operator/managed-deployment.js +1 -3
  132. package/node_modules/@maka/runtime-host/dist/operator/retirement-cancellation.js +20 -0
  133. package/node_modules/@maka/runtime-host/dist/peer-mesh/limits.js +0 -1
  134. package/node_modules/@maka/runtime-host/dist/peer-mesh/model.js +1 -1
  135. package/node_modules/@maka/runtime-host/dist/peer-reachability/publisher.js +1 -3
  136. package/node_modules/@maka/runtime-host/dist/protocol/host-status.js +21 -12
  137. package/node_modules/@maka/runtime-host/dist/protocol/index.js +29 -1
  138. package/node_modules/@maka/runtime-host/dist/protocol/operations.js +1 -0
  139. package/node_modules/@maka/runtime-host/dist/protocol/plan.js +1 -0
  140. package/node_modules/@maka/runtime-host/dist/protocol/plugin-platform.js +27 -5
  141. package/node_modules/@maka/runtime-host/dist/protocol/project-catalog.js +2 -2
  142. package/node_modules/@maka/runtime-host/dist/protocol/session-continuity.js +40 -20
  143. package/node_modules/@maka/runtime-host/dist/protocol/session-transcript.js +0 -5
  144. package/node_modules/@maka/runtime-host/dist/protocol/session-turns.js +29 -58
  145. package/node_modules/@maka/runtime-host/dist/protocol/turn.js +11 -1
  146. package/node_modules/@maka/runtime-host/dist/protocol/workhub-coordination.js +31 -2
  147. package/node_modules/@maka/runtime-host/dist/server/access-credential-store.js +1 -0
  148. package/node_modules/@maka/runtime-host/dist/server/agent-graph-coordinator.js +0 -3
  149. package/node_modules/@maka/runtime-host/dist/server/canonical-turn-snapshot.js +19 -4
  150. package/node_modules/@maka/runtime-host/dist/server/connection-session.js +7 -6
  151. package/node_modules/@maka/runtime-host/dist/server/execution-artifacts.js +32 -32
  152. package/node_modules/@maka/runtime-host/dist/server/execution-composition.js +144 -33
  153. package/node_modules/@maka/runtime-host/dist/server/execution-model-authority.js +5 -5
  154. package/node_modules/@maka/runtime-host/dist/server/execution-model-composition.js +45 -16
  155. package/node_modules/@maka/runtime-host/dist/server/goal-coordinator.js +40 -1
  156. package/node_modules/@maka/runtime-host/dist/server/host-kernel.js +96 -17
  157. package/node_modules/@maka/runtime-host/dist/server/host-residency-registry.js +13 -7
  158. package/node_modules/@maka/runtime-host/dist/server/hosted-execution-admission-registry.js +3 -1
  159. package/node_modules/@maka/runtime-host/dist/server/hosted-execution-recovery.js +124 -62
  160. package/node_modules/@maka/runtime-host/dist/server/interactive-run-composer.js +47 -22
  161. package/node_modules/@maka/runtime-host/dist/server/message-coordinator.js +76 -6
  162. package/node_modules/@maka/runtime-host/dist/server/plugin-platform-coordinator.js +6 -0
  163. package/node_modules/@maka/runtime-host/dist/server/plugin-platform.js +6 -0
  164. package/node_modules/@maka/runtime-host/dist/server/root-turn-coordinator.js +325 -73
  165. package/node_modules/@maka/runtime-host/dist/server/scheduled-task-coordinator.js +37 -2
  166. package/node_modules/@maka/runtime-host/dist/server/serial-outbound-writer.js +45 -3
  167. package/node_modules/@maka/runtime-host/dist/server/session-catalog-coordinator.js +50 -7
  168. package/node_modules/@maka/runtime-host/dist/server/session-continuity-coordinator.js +87 -25
  169. package/node_modules/@maka/runtime-host/dist/server/session-retirement-coordinator.js +5 -2
  170. package/node_modules/@maka/runtime-host/dist/server/session-revision-coordinator.js +12 -55
  171. package/node_modules/@maka/runtime-host/dist/server/session-sidecar-purge.js +1 -16
  172. package/node_modules/@maka/runtime-host/dist/server/session-transcript-pager.js +0 -1
  173. package/node_modules/@maka/runtime-host/dist/server/session-transcript-reader.js +460 -70
  174. package/node_modules/@maka/runtime-host/dist/server/shared-session-transcript.js +1 -1
  175. package/node_modules/@maka/runtime-host/dist/server/storage-maintenance.js +109 -0
  176. package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-action-gate.js +20 -2
  177. package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-coordinator.js +13 -4
  178. package/node_modules/@maka/runtime-host/dist/server/workhub-message-attachments.js +46 -0
  179. package/node_modules/@maka/storage/dist/artifact-store.js +21 -10
  180. package/node_modules/@maka/storage/dist/artifact-stores.js +1 -1
  181. package/node_modules/@maka/storage/dist/claude-code-session-adapter.js +0 -5
  182. package/node_modules/@maka/storage/dist/codex-session-adapter.js +284 -198
  183. package/node_modules/@maka/storage/dist/context-offload-snapshot.js +325 -0
  184. package/node_modules/@maka/storage/dist/execution-stores.js +9 -7
  185. package/node_modules/@maka/storage/dist/file-session-repository.js +1012 -0
  186. package/node_modules/@maka/storage/dist/git-exec.js +61 -0
  187. package/node_modules/@maka/storage/dist/git-worktree-child-executor.js +8 -35
  188. package/node_modules/@maka/storage/dist/goal-authority.js +2 -2
  189. package/node_modules/@maka/storage/dist/interaction-store.js +2 -2
  190. package/node_modules/@maka/storage/dist/opencode-session-adapter.js +0 -4
  191. package/node_modules/@maka/storage/dist/operational-state-backup.js +9 -5
  192. package/node_modules/@maka/storage/dist/project-catalog.js +2 -23
  193. package/node_modules/@maka/storage/dist/runtime-event-invariants.js +2 -2
  194. package/node_modules/@maka/storage/dist/runtime-event-persistence.js +1 -0
  195. package/node_modules/@maka/storage/dist/runtime-policy/connection-catalog-document.js +8 -3
  196. package/node_modules/@maka/storage/dist/runtime-transcript-query.js +308 -0
  197. package/node_modules/@maka/storage/dist/scheduled-task-store.js +249 -283
  198. package/node_modules/@maka/storage/dist/session-bundle-manifest.js +5 -17
  199. package/node_modules/@maka/storage/dist/session-bundle-policy.js +26 -5
  200. package/node_modules/@maka/storage/dist/session-copy-cleanup.js +2 -1
  201. package/node_modules/@maka/storage/dist/session-message-projection.js +15 -0
  202. package/node_modules/@maka/storage/dist/session-repository.js +767 -0
  203. package/node_modules/@maka/storage/dist/session-store.js +25 -99
  204. package/node_modules/@maka/storage/dist/sqlite-artifact-metadata.js +10 -3
  205. package/node_modules/@maka/storage/dist/sqlite-context-offload-store.js +24 -8
  206. package/node_modules/@maka/storage/dist/sqlite-core-execution-schema.js +7 -1
  207. package/node_modules/@maka/storage/dist/sqlite-runtime-schema.js +44 -1
  208. package/node_modules/@maka/storage/dist/sqlite-runtime-store.js +130 -27
  209. package/node_modules/@maka/storage/dist/sqlite-session-metadata-store.js +109 -892
  210. package/node_modules/@maka/storage/dist/storage-id.js +28 -0
  211. package/node_modules/@maka/storage/dist/tool-result-archive-evidence.js +138 -0
  212. package/node_modules/@maka/storage/dist/workspace-identity.js +2 -15
  213. package/node_modules/@maka/storage/dist/workspace-version-authority-internal.js +1 -8
  214. package/node_modules/@maka/storage/package.json +2 -0
  215. package/package.json +1 -1
@@ -0,0 +1,106 @@
1
+ /*
2
+ * Licensed to the Apache Software Foundation (ASF) under one
3
+ * or more contributor license agreements. See the NOTICE file
4
+ * distributed with this work for additional information
5
+ * regarding copyright ownership. The ASF licenses this file
6
+ * to you under the Apache License, Version 2.0 (the
7
+ * "License"); you may not use this file except in compliance
8
+ * with the License. You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing,
13
+ * software distributed under the License is distributed on an
14
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+ * KIND, either express or implied. See the License for the
16
+ * specific language governing permissions and limitations
17
+ * under the License.
18
+ */
19
+ import { clearLine, createInterface, cursorTo } from 'node:readline';
20
+ import { stripVTControlCharacters } from 'node:util';
21
+ import { formatHostHandoff, } from '@maka/runtime-host/client';
22
+ /** The surface owns terminal input; replacement policy stays in the shared handoff. */
23
+ export function createCliHostHandoffSurface(locale, input = process.stdin, output = process.stderr) {
24
+ return (submit) => {
25
+ let readline;
26
+ let current;
27
+ let closed = false;
28
+ let ended = false;
29
+ const releaseReader = () => {
30
+ const previous = readline;
31
+ readline = undefined;
32
+ previous?.close();
33
+ };
34
+ const cancel = () => {
35
+ if (current)
36
+ submit(current.revision, 'cancel');
37
+ };
38
+ return {
39
+ update(view) {
40
+ if (closed || current?.revision === view.revision)
41
+ return;
42
+ current = view;
43
+ if (ended) {
44
+ cancel();
45
+ return;
46
+ }
47
+ // A new observation gets a new input buffer. Ctrl+U leaves text after
48
+ // the cursor intact and is ignored by readline in TERM=dumb.
49
+ releaseReader();
50
+ if (output.isTTY) {
51
+ clearLine(output, 0);
52
+ cursorTo(output, 0);
53
+ }
54
+ const copy = formatHostHandoff(view, locale);
55
+ const text = [copy.title, copy.description, copy.detail, view.diagnostic]
56
+ .filter(Boolean)
57
+ .join('\n');
58
+ output.write('\n' +
59
+ stripVTControlCharacters(text).replace(/[\p{Cc}\p{Cf}]/gu, (character) => character === '\n' ? character : '\uFFFD') +
60
+ '\n');
61
+ if (view.actions.length === 0)
62
+ return;
63
+ const options = copy.actions.map(({ action, label }) => `${action === 'interrupt' ? 'stop' : action === 'retry' ? 'r' : 'Enter'}: ${label}`);
64
+ // Create the reader only after the explanation is visible, with the
65
+ // final action prompt already installed. Never draw readline's default >.
66
+ const reader = createInterface({
67
+ input,
68
+ output,
69
+ terminal: output.isTTY === true,
70
+ prompt: options.join(' · ') + ' > ',
71
+ });
72
+ readline = reader;
73
+ reader.on('SIGINT', cancel);
74
+ reader.on('close', () => {
75
+ if (readline !== reader)
76
+ return;
77
+ ended = true;
78
+ if (!closed)
79
+ cancel();
80
+ });
81
+ reader.on('line', (line) => {
82
+ if (readline !== reader || current?.revision !== view.revision)
83
+ return;
84
+ const answer = line.trim().toLowerCase();
85
+ const action = answer === 'r'
86
+ ? 'retry'
87
+ : answer === 'stop'
88
+ ? 'interrupt'
89
+ : answer === ''
90
+ ? 'cancel'
91
+ : undefined;
92
+ if (!action || !view.actions.includes(action)) {
93
+ reader.prompt();
94
+ return;
95
+ }
96
+ submit(view.revision, action);
97
+ });
98
+ reader.prompt();
99
+ },
100
+ close() {
101
+ closed = true;
102
+ releaseReader();
103
+ },
104
+ };
105
+ };
106
+ }
@@ -64,6 +64,7 @@ export async function runRuntimeHostInstalledUpdateBootstrap(input, overrides =
64
64
  ? {}
65
65
  : { targetCompatibility: target.compatibility }),
66
66
  allowInterruptActiveTasks: input.allowInterruptActiveTasks,
67
+ ...(input.expectedSource ? { expectedSource: input.expectedSource } : {}),
67
68
  });
68
69
  }
69
70
  finally {
@@ -94,6 +95,18 @@ function launchCoordinator(input) {
94
95
  ? []
95
96
  : ['--target-compatibility', String(input.targetCompatibility)]),
96
97
  ...(input.allowInterruptActiveTasks ? ['--allow-interrupt-active-tasks'] : []),
98
+ ...(input.expectedSource
99
+ ? [
100
+ '--expected-root-id',
101
+ input.expectedSource.rootId,
102
+ '--expected-deployment-revision',
103
+ input.expectedSource.deploymentRevision,
104
+ '--expected-owner-installation-id',
105
+ input.expectedSource.ownerInstallationId,
106
+ '--expected-host-epoch',
107
+ input.expectedSource.hostEpoch,
108
+ ]
109
+ : []),
97
110
  ];
98
111
  return new Promise((resolve, reject) => {
99
112
  const child = spawn(process.execPath, args, { stdio: 'inherit', windowsHide: false });
@@ -22,6 +22,7 @@ import { homedir } from 'node:os';
22
22
  import { dirname, join } from 'node:path';
23
23
  import { pathToFileURL } from 'node:url';
24
24
  import { connectExistingRuntimeHost, prepareConnectedRuntimeHostRetirement, waitForRuntimeHostReady, } from '@maka/runtime-host/client';
25
+ import { resolveRuntimeHostManagedDeploymentAuthority, } from '@maka/runtime-host/operator';
25
26
  import { INTERACTIVE_RUNTIME_HOST_COMPOSITION_ID, RUNTIME_HOST_PROTOCOL_VERSION, } from '@maka/runtime-host/protocol';
26
27
  import { resolveStorageRoot } from '@maka/storage/root-authority';
27
28
  import { prepareRuntimeHostNpmGlobalStagedDeployment, reconcilePreparedRuntimeHostNpmGlobalDeployment, } from './runtime-host-local-handoff.js';
@@ -35,6 +36,7 @@ export async function runRuntimeHostInstalledUpdateCoordinator(input, authorityO
35
36
  const deps = {
36
37
  resolveInstallation: resolveRuntimeHostNpmGlobalInstallation,
37
38
  resolveRoot: resolveStorageRoot,
39
+ resolveManagedAuthority: resolveRuntimeHostManagedDeploymentAuthority,
38
40
  connectExisting: connectExistingRuntimeHost,
39
41
  waitForReady: waitForRuntimeHostReady,
40
42
  prepareRetirement: prepareConnectedRuntimeHostRetirement,
@@ -54,6 +56,14 @@ export async function runRuntimeHostInstalledUpdateCoordinator(input, authorityO
54
56
  throw new Error(`The installed Maka release changed from ${input.currentVersion} to ${installation.observedRelease.version} before update coordination`);
55
57
  }
56
58
  const root = await deps.resolveRoot({ path: input.rootPath, kind: 'interactive' });
59
+ if (input.expectedSource &&
60
+ (root.rootId !== input.expectedSource.rootId ||
61
+ installation.owner.installationId !== input.expectedSource.ownerInstallationId)) {
62
+ throw new Error('The observed local Host installation owner changed before update.');
63
+ }
64
+ if (await deps.resolveManagedAuthority(root.rootId)) {
65
+ throw new Error('The managed Runtime Host must be updated through its installed operator.');
66
+ }
57
67
  const transactionId = updateTransactionId(root.rootId, installation, input.target);
58
68
  return deps.withArchive(input.target, input.archivePath, async ({ packageRoot, archivePath }) => {
59
69
  const staged = await deps.prepareStaged({
@@ -90,7 +100,19 @@ export async function runRuntimeHostInstalledUpdateCoordinator(input, authorityO
90
100
  return 'target_present';
91
101
  };
92
102
  const prepare = async (inheritableAuthorityLeaseFd) => {
103
+ if (await deps.resolveManagedAuthority(root.rootId)) {
104
+ throw new Error('The managed Runtime Host must be updated through its installed operator.');
105
+ }
93
106
  observation = await observeCurrentHost(input.rootPath, root.rootId, deps);
107
+ // This callback runs under the existing deployment-authority lease.
108
+ // Do not turn the TUI's consent for one observed Host into retirement of
109
+ // a successor that appeared while the archive/coordinator was prepared.
110
+ if (input.expectedSource &&
111
+ observation.registration?.hostEpoch !== input.expectedSource.hostEpoch) {
112
+ await observation.connection?.close();
113
+ observation = {};
114
+ throw new Error('The observed Runtime Host changed before update retirement.');
115
+ }
94
116
  if (observation.registration && observation.registration.lifecycleMode !== 'ephemeral') {
95
117
  throw new Error('Only an ephemeral local Runtime Host can be updated by this CLI');
96
118
  }
@@ -149,6 +171,17 @@ export async function runRuntimeHostInstalledUpdateCoordinator(input, authorityO
149
171
  : 'refuse_active_work',
150
172
  installation,
151
173
  staged,
174
+ ...(input.expectedSource
175
+ ? {
176
+ expectedOwner: {
177
+ revision: input.expectedSource.deploymentRevision,
178
+ owner: {
179
+ kind: 'cli',
180
+ installationId: input.expectedSource.ownerInstallationId,
181
+ },
182
+ },
183
+ }
184
+ : {}),
152
185
  }, {
153
186
  prepareUnownedHostCutover: (_rootId, _target, _staged, _policy, leaseFd) => prepare(leaseFd),
154
187
  prepareHostCutover: (_rootId, _selected, _target, _staged, _policy, leaseFd) => prepare(leaseFd),
@@ -17,6 +17,7 @@
17
17
  * under the License.
18
18
  */
19
19
  import { randomUUID } from 'node:crypto';
20
+ import { withOperatorRetirementCancellation } from './runtime-host-operator-retirement.js';
20
21
  import { isDeepStrictEqual } from 'node:util';
21
22
  import { resolveExistingStorageRoot, tryAcquireStateRootOwner, } from '@maka/storage/root-authority';
22
23
  import { connectExistingRuntimeHost, prepareConnectedRuntimeHostRetirement, RuntimeHostOperationError, RuntimeHostRequestInterruptedError, waitForRuntimeHostReady, } from '@maka/runtime-host/client';
@@ -173,6 +174,10 @@ function assertRecoveryTarget(expected, rootId, record) {
173
174
  }
174
175
  }
175
176
  export async function retireRuntimeHostLifecycleOwner(input) {
177
+ return withOperatorRetirementCancellation((signal) => retireRuntimeHostLifecycleOwnerWithSignal(input, signal));
178
+ }
179
+ async function retireRuntimeHostLifecycleOwnerWithSignal(input, signal) {
180
+ signal?.throwIfAborted();
176
181
  if (input.expectedOwner && !input.supervisor) {
177
182
  throw new RuntimeHostLifecycleTransactionError('owner_changed', 'A Runtime Host identity fence requires a supervised deployment');
178
183
  }
@@ -188,6 +193,7 @@ export async function retireRuntimeHostLifecycleOwner(input) {
188
193
  const status = await input.supervisor.status();
189
194
  assertExpectedSupervisorOwner(input.expectedOwner, status);
190
195
  }
196
+ signal?.throwIfAborted();
191
197
  if (input.retireIdleSupervisor !== false)
192
198
  await input.supervisor?.retire();
193
199
  return { kind: 'retired', owner: idleOwner };
@@ -212,6 +218,7 @@ export async function retireRuntimeHostLifecycleOwner(input) {
212
218
  if (status.active && status.pid !== null) {
213
219
  if (!input.allowInterruptActiveTasks)
214
220
  return { kind: 'active_tasks' };
221
+ signal?.throwIfAborted();
215
222
  await input.supervisor.retire();
216
223
  return waitForRuntimeHostLifecycleOwner(capability, input.timeoutMs ?? 45_000);
217
224
  }
@@ -234,7 +241,7 @@ export async function retireRuntimeHostLifecycleOwner(input) {
234
241
  // The exact Root owner and canonical supervisor now agree while the deployment lock is held.
235
242
  // This admits retirement of that deployment; a later same-deployment restart is not a new
236
243
  // authority, but it must not acquire the Root before the supervisor is retired.
237
- const prepared = await prepareConnectedRuntimeHostRetirement(connected.connection, input.allowInterruptActiveTasks ? 'interrupt_active_work' : 'refuse_active_work');
244
+ const prepared = await prepareConnectedRuntimeHostRetirement(connected.connection, input.allowInterruptActiveTasks ? 'interrupt_active_work' : 'refuse_active_work', undefined, signal);
238
245
  if (prepared.kind === 'active_tasks')
239
246
  return prepared;
240
247
  if (prepared.pid !== diagnostics.pid) {
@@ -242,6 +249,7 @@ export async function retireRuntimeHostLifecycleOwner(input) {
242
249
  }
243
250
  }
244
251
  catch (error) {
252
+ signal?.throwIfAborted();
245
253
  if (!isRuntimeHostRetirementUnavailable(error) || !input.supervisor)
246
254
  throw error;
247
255
  if (!input.allowInterruptActiveTasks)
@@ -20,9 +20,10 @@ import { createHash, randomUUID } from 'node:crypto';
20
20
  import { realpath, stat } from 'node:fs/promises';
21
21
  import { homedir } from 'node:os';
22
22
  import { dirname, join, posix, resolve, win32 } from 'node:path';
23
- import { claimLocalHostProcessDeployment, handoffLocalHostProcessDeployment, readLocalHostDeploymentRecord, } from '@maka/runtime-host/operator';
23
+ import { isDeepStrictEqual } from 'node:util';
24
+ import { claimLocalHostProcessDeployment, handoffLocalHostProcessDeployment, readLocalHostDeploymentRecord, resolveRuntimeHostManagedDeploymentAuthority, } from '@maka/runtime-host/operator';
24
25
  import { compareProductReleaseVersions } from '@maka/runtime-host/operator/update-package-evidence';
25
- import { connectExistingRuntimeHost } from '@maka/runtime-host/client';
26
+ import { connectExistingRuntimeHost, forceTerminateObservedRegisteredRuntimeHost, } from '@maka/runtime-host/client';
26
27
  import { INTERACTIVE_RUNTIME_HOST_COMPOSITION_ID, RUNTIME_HOST_PROTOCOL_VERSION, } from '@maka/runtime-host/protocol';
27
28
  import { resolveRuntimeHostNpmGlobalInstallation, } from './runtime-host-cli-installation.js';
28
29
  import { openRuntimeHostPackageDeployment, prepareRuntimeHostPackageDeployment, resolveRuntimeHostPackageCliPath, } from './runtime-host-package-deployment.js';
@@ -53,6 +54,7 @@ export class RuntimeHostLocalHandoffError extends Error {
53
54
  * retain only the bounded true-idle takeover adapter.
54
55
  */
55
56
  export async function restartRuntimeHostNpmGlobalDeployment(input, authorityOptions = {}, overrides = {}) {
57
+ input.signal?.throwIfAborted();
56
58
  if (input.registration.lifecycleMode !== 'ephemeral') {
57
59
  return {
58
60
  kind: 'operator_required',
@@ -64,15 +66,23 @@ export async function restartRuntimeHostNpmGlobalDeployment(input, authorityOpti
64
66
  withPackage: withRuntimeHostRegistryUpdatePackage,
65
67
  prepareDeployment: prepareRuntimeHostPackageDeployment,
66
68
  readRecord: readLocalHostDeploymentRecord,
69
+ resolveManagedAuthority: resolveRuntimeHostManagedDeploymentAuthority,
67
70
  claim: claimLocalHostProcessDeployment,
68
71
  handoff: handoffLocalHostProcessDeployment,
69
72
  resolveCandidate: resolveRuntimeHostRegistryUpdateCandidate,
70
73
  connectExisting: connectExistingRuntimeHost,
71
74
  activateTarget: launchRuntimeHostTargetActivator,
72
75
  retireSource: launchRuntimeHostLocalSourceRetirement,
76
+ terminateObservedHost: forceTerminateObservedRegisteredRuntimeHost,
73
77
  ...overrides,
74
78
  };
79
+ if (await deps.resolveManagedAuthority(input.registration.rootId)) {
80
+ return { kind: 'operator_required', reason: 'unowned_host' };
81
+ }
75
82
  const installation = await deps.resolveInstallation(input.installationOptions);
83
+ if (input.expectedInstallation && !isDeepStrictEqual(installation, input.expectedInstallation)) {
84
+ return { kind: 'changed' };
85
+ }
76
86
  const current = await deps.readRecord(input.registration.rootId, authorityOptions);
77
87
  const sourceOwner = current?.state.kind === 'handoff' ? current.state.from : current?.state.owner;
78
88
  if (sourceOwner && !sameOwner(sourceOwner, installation.owner)) {
@@ -130,9 +140,13 @@ export async function restartRuntimeHostNpmGlobalDeployment(input, authorityOpti
130
140
  return 'target_present';
131
141
  };
132
142
  const prepare = async (rootId, selectedDeployment, stagedTarget, inheritableAuthorityLeaseFd) => {
143
+ input.signal?.throwIfAborted();
133
144
  if (rootId !== input.registration.rootId) {
134
145
  throw new RuntimeHostLocalHandoffError('root_changed', 'The local Runtime Host State Root changed before restart');
135
146
  }
147
+ if (await deps.resolveManagedAuthority(rootId)) {
148
+ throw new Error('The managed Runtime Host requires its operator to perform replacement');
149
+ }
136
150
  const observed = await deps.connectExisting({
137
151
  rootPath: input.rootPath,
138
152
  protocol: { min: RUNTIME_HOST_PROTOCOL_VERSION, max: RUNTIME_HOST_PROTOCOL_VERSION },
@@ -179,6 +193,7 @@ export async function restartRuntimeHostNpmGlobalDeployment(input, authorityOpti
179
193
  expectedHostEpoch: registration.hostEpoch,
180
194
  activeWorkPolicy,
181
195
  inheritableAuthorityLeaseFd,
196
+ ...(input.signal ? { signal: input.signal } : {}),
182
197
  });
183
198
  if (retired === 'active_work')
184
199
  return { kind: 'active_work' };
@@ -191,6 +206,15 @@ export async function restartRuntimeHostNpmGlobalDeployment(input, authorityOpti
191
206
  }
192
207
  return { kind: 'target_present' };
193
208
  }
209
+ // Older source packages cannot negotiate retirement. Explicit consent may
210
+ // use Desktop's exact-process recovery, inside this existing deployment
211
+ // transaction and only after staging the verified successor.
212
+ if (activeWorkPolicy === 'interrupt_active_work' && input.processIdentity) {
213
+ input.signal?.throwIfAborted();
214
+ const stopped = await deps.terminateObservedHost({ rootPath: input.rootPath, registration: input.registration }, { processIdentity: input.processIdentity, isCurrent: () => !input.signal?.aborted });
215
+ if (!stopped)
216
+ throw new Error('The observed Runtime Host changed before it could be stopped safely');
217
+ }
194
218
  const activated = await activateExactTarget(rootId, stagedTarget, inheritableAuthorityLeaseFd, registration.hostEpoch);
195
219
  if (activated === 'active_work')
196
220
  return { kind: 'active_work' };
@@ -286,6 +310,12 @@ export async function reconcilePreparedRuntimeHostNpmGlobalDeployment(request, l
286
310
  return request.staged;
287
311
  };
288
312
  const current = await overrides.readRecord(request.rootId, authorityOptions);
313
+ if (request.expectedOwner &&
314
+ (current?.state.kind !== 'owned' ||
315
+ current.revision !== request.expectedOwner.revision ||
316
+ !sameOwner(current.state.owner, request.expectedOwner.owner))) {
317
+ throw new RuntimeHostLocalHandoffError('source_owner_mismatch', 'The observed local Host owner changed before update reconciliation');
318
+ }
289
319
  if (!current) {
290
320
  return overrides.claim({
291
321
  rootId: request.rootId,
@@ -297,9 +327,12 @@ export async function reconcilePreparedRuntimeHostNpmGlobalDeployment(request, l
297
327
  }
298
328
  return overrides.handoff({
299
329
  rootId: request.rootId,
300
- expectedRevision: current.revision,
330
+ // The same captured CAS token is checked again by begin_handoff under
331
+ // the authority lock. Never substitute a newly observed owner revision.
332
+ expectedRevision: request.expectedOwner?.revision ?? current.revision,
301
333
  transactionId: current.state.kind === 'handoff' ? current.state.transactionId : request.transactionId,
302
- from: current.state.kind === 'handoff' ? current.state.from : current.state.owner,
334
+ from: request.expectedOwner?.owner ??
335
+ (current.state.kind === 'handoff' ? current.state.from : current.state.owner),
303
336
  to: request.installation.owner,
304
337
  target: request.target,
305
338
  activeWorkPolicy: request.activeWorkPolicy,
@@ -331,7 +364,7 @@ export async function prepareRuntimeHostNpmGlobalStagedDeployment(input, pathOpt
331
364
  launchGeneration: launchGeneration(input.transactionId, input.target),
332
365
  };
333
366
  }
334
- async function openRuntimeHostNpmGlobalStagedDeployment(input, pathOptions = {}) {
367
+ export async function openRuntimeHostNpmGlobalStagedDeployment(input, pathOptions = {}) {
335
368
  const deploymentRoot = resolveRuntimeHostLocalCliDeploymentRoot(input.rootId, input.owner, pathOptions);
336
369
  const staged = await openRuntimeHostPackageDeployment({
337
370
  deploymentRoot,
@@ -379,6 +412,16 @@ async function requireCandidateEntrypoint(packageRoot) {
379
412
  }
380
413
  return candidate;
381
414
  }
415
+ /** Read-only capability check against the same verified source package the transaction uses. */
416
+ export async function runtimeHostNpmGlobalSourceRetirementAvailable(input) {
417
+ const source = await openRuntimeHostNpmGlobalStagedDeployment({
418
+ rootId: input.rootId,
419
+ owner: input.owner,
420
+ target: input.source,
421
+ transactionId: 'source-capability-probe',
422
+ }, input.deploymentPathOptions);
423
+ return hasSourceRetirementHelper(source);
424
+ }
382
425
  async function hasSourceRetirementHelper(source) {
383
426
  try {
384
427
  return (await stat(join(dirname(source.cliPath), 'runtime-host-local-source-retirement.js'))).isFile();
@@ -0,0 +1,84 @@
1
+ /*
2
+ * Licensed to the Apache Software Foundation (ASF) under one
3
+ * or more contributor license agreements. See the NOTICE file
4
+ * distributed with this work for additional information
5
+ * regarding copyright ownership. The ASF licenses this file
6
+ * to you under the Apache License, Version 2.0 (the
7
+ * "License"); you may not use this file except in compliance
8
+ * with the License. You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing,
13
+ * software distributed under the License is distributed on an
14
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+ * KIND, either express or implied. See the License for the
16
+ * specific language governing permissions and limitations
17
+ * under the License.
18
+ */
19
+ import { execFile } from 'node:child_process';
20
+ import { access } from 'node:fs/promises';
21
+ import { join } from 'node:path';
22
+ import { promisify } from 'node:util';
23
+ import { resolveStorageRoot } from '@maka/storage/root-authority';
24
+ import { runtimeHostStartupError } from '@maka/runtime-host/client';
25
+ import { decodeRuntimeHostActivationFrame, readRuntimeHostManagedDeploymentConfig, RUNTIME_HOST_ACTIVATION_FRAME_MAX_BYTES, runtimeHostManagedOperatorCommand, runtimeHostOperatorInvocation, } from '@maka/runtime-host/operator';
26
+ const run = promisify(execFile);
27
+ /** Invoke the installed owner; never launch the calling CLI's candidate as the owner. */
28
+ export async function activateLocalManagedRuntimeHost(input) {
29
+ input.signal?.throwIfAborted();
30
+ const capability = await resolveStorageRoot({ path: input.rootPath, kind: 'interactive' });
31
+ const config = await readRuntimeHostManagedDeploymentConfig(capability);
32
+ if (!config || config.lifecycle.mode !== 'on_demand') {
33
+ throw runtimeHostStartupError('managed_root_requires_operator');
34
+ }
35
+ const operator = runtimeHostManagedOperatorCommand(config, process.platform === 'win32' ? 'win32' : 'posix');
36
+ let invocation = runtimeHostOperatorInvocation(operator, [
37
+ 'activate',
38
+ '--framed',
39
+ '--root-id',
40
+ capability.rootId,
41
+ ]);
42
+ // Older installations have only the stable POSIX operator executable.
43
+ try {
44
+ await access(operator.modulePath);
45
+ }
46
+ catch (error) {
47
+ if (error.code !== 'ENOENT' || process.platform === 'win32') {
48
+ throw error;
49
+ }
50
+ invocation = {
51
+ executable: join(config.deploymentRoot, 'operator'),
52
+ args: invocation.args.slice(1),
53
+ };
54
+ }
55
+ const result = await run(invocation.executable, [...invocation.args], {
56
+ encoding: 'utf8',
57
+ timeout: 120_000,
58
+ killSignal: 'SIGKILL',
59
+ maxBuffer: RUNTIME_HOST_ACTIVATION_FRAME_MAX_BYTES + 256,
60
+ ...(input.signal ? { signal: input.signal } : {}),
61
+ }).catch((error) => {
62
+ input.signal?.throwIfAborted();
63
+ // Operators report a framed diagnostic and exit nonzero on expected failures.
64
+ if (error instanceof Error && 'stdout' in error && typeof error.stdout === 'string') {
65
+ const frame = decodeSingleActivationFrame(error.stdout);
66
+ if (frame?.kind === 'error')
67
+ throw new Error(frame.error.message, { cause: error });
68
+ }
69
+ throw error;
70
+ });
71
+ input.signal?.throwIfAborted();
72
+ const frame = decodeSingleActivationFrame(result.stdout);
73
+ if (!frame)
74
+ throw new Error('The installed Runtime Host operator returned an invalid activation result');
75
+ if (frame.kind === 'error')
76
+ throw new Error(frame.error.message);
77
+ if (frame.rootId !== capability.rootId || frame.deploymentId !== config.deploymentId) {
78
+ throw new Error('The installed Runtime Host operator activated a different deployment');
79
+ }
80
+ }
81
+ function decodeSingleActivationFrame(stdout) {
82
+ const line = stdout.replace(/\r?\n$/u, '');
83
+ return /[\r\n]/u.test(line) ? undefined : decodeRuntimeHostActivationFrame(line);
84
+ }
@@ -58,6 +58,7 @@ export async function runRuntimeHostLocalSourceRetirement(input, overrides = {})
58
58
  }
59
59
  }
60
60
  export function launchRuntimeHostLocalSourceRetirement(input) {
61
+ input.signal?.throwIfAborted();
61
62
  const args = [
62
63
  input.sourceCliPath,
63
64
  'runtime-host',
@@ -81,9 +82,24 @@ export function launchRuntimeHostLocalSourceRetirement(input) {
81
82
  killSignal: 'SIGKILL',
82
83
  windowsHide: false,
83
84
  });
84
- child.once('error', reject);
85
+ // Only this retirement client is stopped, never the parent that owns the
86
+ // durable deployment transaction. Wait for its fd/connection to close.
87
+ const cancel = () => {
88
+ child.kill('SIGKILL');
89
+ };
90
+ input.signal?.addEventListener('abort', cancel, { once: true });
91
+ if (input.signal?.aborted)
92
+ cancel();
93
+ let spawnError;
94
+ child.once('error', (error) => {
95
+ spawnError = error;
96
+ });
85
97
  child.once('close', (code, signal) => {
86
- if (signal) {
98
+ input.signal?.removeEventListener('abort', cancel);
99
+ if (spawnError) {
100
+ reject(spawnError);
101
+ }
102
+ else if (signal) {
87
103
  reject(new Error(`Maka source retirement helper exited on ${signal}`));
88
104
  }
89
105
  else if (code === 0) {
@@ -77,6 +77,7 @@ export async function manageRuntimeHostManagedLifecycle(rootId, input, dependenc
77
77
  }
78
78
  if (input.action === 'restart') {
79
79
  const retirement = await retireRuntimeHostLifecycleOwner({
80
+ ...(input.expectedHost ? { expectedOwner: input.expectedHost } : {}),
80
81
  rootPath: config.root.path,
81
82
  rootId,
82
83
  supervisor: provider.supervisor,
@@ -0,0 +1,50 @@
1
+ /*
2
+ * Licensed to the Apache Software Foundation (ASF) under one
3
+ * or more contributor license agreements. See the NOTICE file
4
+ * distributed with this work for additional information
5
+ * regarding copyright ownership. The ASF licenses this file
6
+ * to you under the Apache License, Version 2.0 (the
7
+ * "License"); you may not use this file except in compliance
8
+ * with the License. You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing,
13
+ * software distributed under the License is distributed on an
14
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+ * KIND, either express or implied. See the License for the
16
+ * specific language governing permissions and limitations
17
+ * under the License.
18
+ */
19
+ import { RUNTIME_HOST_OPERATOR_RETIREMENT_CANCELLATION_ENV } from '@maka/runtime-host/operator';
20
+ /** Consume the operator's one-shot cancellation channel only around reversible retirement. */
21
+ export function withOperatorRetirementCancellation(operation) {
22
+ if (process.env[RUNTIME_HOST_OPERATOR_RETIREMENT_CANCELLATION_ENV] !== '1') {
23
+ return operation(undefined);
24
+ }
25
+ // Recovery may retire another owner later. It must finish independently of
26
+ // the original user's cancellation, and activators must not inherit this channel.
27
+ delete process.env[RUNTIME_HOST_OPERATOR_RETIREMENT_CANCELLATION_ENV];
28
+ return withRetirementCancellation(process.stdin, operation);
29
+ }
30
+ export async function withRetirementCancellation(input, operation) {
31
+ const controller = new AbortController();
32
+ const cancel = () => controller.abort(new Error('Runtime Host retirement was cancelled'));
33
+ input.once('end', cancel);
34
+ input.once('error', cancel);
35
+ input.once('close', cancel);
36
+ input.resume();
37
+ if (input.readableEnded || input.destroyed)
38
+ cancel();
39
+ try {
40
+ return await operation(controller.signal);
41
+ }
42
+ finally {
43
+ input.removeListener('end', cancel);
44
+ input.removeListener('error', cancel);
45
+ input.removeListener('close', cancel);
46
+ input.pause();
47
+ // A parent's still-open cancellation pipe must not keep the completed CLI alive.
48
+ input.unref?.();
49
+ }
50
+ }
@@ -59,6 +59,9 @@ function runtimeHostServiceManagerDeps(overrides) {
59
59
  };
60
60
  }
61
61
  export async function manageRuntimeHostService(input, backend, overrides = {}) {
62
+ if (input.expectedHost) {
63
+ throw new RuntimeHostServiceManagerError('target_mismatch', 'An exact Host fence requires the canonical managed deployment operator');
64
+ }
62
65
  const deps = runtimeHostServiceManagerDeps(overrides);
63
66
  const configPath = resolveRuntimeHostManagedServiceConfigPath(input.clientDataRoot);
64
67
  const configDirectory = dirname(configPath);
@@ -667,9 +670,6 @@ async function normalizeStateRoot(requestedRoot) {
667
670
  throw new RuntimeHostServiceManagerError('invalid_config', `Invalid Runtime Host State Root: ${requestedRoot}`, { cause: error });
668
671
  }
669
672
  }
670
- export async function resolveRuntimeHostManagedStateRoot(requestedRoot) {
671
- return normalizeStateRoot(requestedRoot);
672
- }
673
673
  async function normalizeProjectDirectoryRoots(roots) {
674
674
  let canonicalRoots;
675
675
  try {
@@ -37,6 +37,7 @@ export class RuntimeHostSessionChannel {
37
37
  #now;
38
38
  #onTurnStarted;
39
39
  #onRuntimeResourceChanged;
40
+ #onSessionDomainChanged;
40
41
  #onInteractionPending;
41
42
  #onInteractionResolved;
42
43
  #onTranscriptSettlement;
@@ -71,6 +72,7 @@ export class RuntimeHostSessionChannel {
71
72
  this.#now = options.now;
72
73
  this.#onTurnStarted = options.onTurnStarted;
73
74
  this.#onRuntimeResourceChanged = options.onRuntimeResourceChanged;
75
+ this.#onSessionDomainChanged = options.onSessionDomainChanged;
74
76
  this.#onInteractionPending = options.onInteractionPending;
75
77
  this.#onInteractionResolved = options.onInteractionResolved;
76
78
  this.#onTranscriptSettlement = options.onTranscriptSettlement;
@@ -79,6 +81,16 @@ export class RuntimeHostSessionChannel {
79
81
  this.#onSnapshotChanged = options.onSnapshotChanged;
80
82
  this.#onFailed = options.onFailed;
81
83
  this.#onRecovered = options.onRecovered;
84
+ this.#subscribeSessionDomainChanges(subscription);
85
+ }
86
+ #subscribeSessionDomainChanges(subscription) {
87
+ if (!this.#onSessionDomainChanged)
88
+ return;
89
+ subscription.subscribeSessionDomainChanges((frame) => {
90
+ if (!this.#closing && this.#subscription === subscription) {
91
+ this.#onSessionDomainChanged?.(frame);
92
+ }
93
+ });
82
94
  }
83
95
  static async open(options) {
84
96
  const subscription = await options.connection.openSessionSubscription({
@@ -343,6 +355,7 @@ export class RuntimeHostSessionChannel {
343
355
  return;
344
356
  }
345
357
  this.#subscription = replacement;
358
+ this.#subscribeSessionDomainChanges(replacement);
346
359
  this.#ready = false;
347
360
  this.#pendingFrames.length = 0;
348
361
  void this.#pump(replacement);