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
@@ -0,0 +1,469 @@
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 { lstat, mkdir, open, readFile, readdir, realpath, stat } from 'node:fs/promises';
20
+ import { homedir, userInfo } from 'node:os';
21
+ import { dirname, isAbsolute, join } from 'node:path';
22
+ import { RUNTIME_HOST_SERVICE_LOG_MAX_BYTES, } from '@maka/runtime-host/operator';
23
+ import { resolveXdgConfigHome } from '@maka/storage/workspace-root';
24
+ import { readStableBoundedFile } from '@maka/storage/stable-storage';
25
+ import { formatRuntimeHostServiceLogs, removeRuntimeHostServiceFile, RuntimeHostServiceManagerError, writeRuntimeHostServiceFile, } from './runtime-host-service-manager.js';
26
+ import { RUNTIME_HOST_UPDATE_INITIAL_DELAY_SECONDS, RUNTIME_HOST_UPDATE_INTERVAL_SECONDS, RUNTIME_HOST_UPDATE_RANDOM_DELAY_SECONDS, } from './runtime-host-service-launch.js';
27
+ import { runRuntimeHostServiceManagerCommand, } from './runtime-host-service-manager-process.js';
28
+ import { assertRuntimeHostProviderDefinition, } from './runtime-host-lifecycle-provider.js';
29
+ export function createOpenRcRuntimeHostLifecycleProvider(serviceId, provider, options = {}) {
30
+ assertServiceId(serviceId);
31
+ const env = options.env ?? process.env;
32
+ const homeDir = options.homeDir ?? homedir();
33
+ const paths = options.paths ?? defaultPaths(provider, serviceId, env, homeDir);
34
+ const run = options.runCommand ?? defaultRunOpenRcCommand;
35
+ const host = createContext(provider, serviceId, '', 'host', paths, run);
36
+ const update = createContext(provider, serviceId, '-update', 'update', paths, run);
37
+ const updateCommandPath = join(paths.artifactDirectory, 'update');
38
+ const uid = options.uid ?? process.getuid?.();
39
+ const preflight = async () => {
40
+ if (provider === 'openrc_system' && uid !== 0) {
41
+ throw unavailable('OpenRC system services require an explicit root session; sudo is not used');
42
+ }
43
+ if (provider === 'openrc_user') {
44
+ const runtimeDirectory = env.XDG_RUNTIME_DIR;
45
+ if (!runtimeDirectory || !isAbsolute(runtimeDirectory)) {
46
+ throw unavailable('OpenRC user services require an absolute XDG_RUNTIME_DIR');
47
+ }
48
+ const runtime = await stat(runtimeDirectory).catch(() => undefined);
49
+ if (!runtime?.isDirectory()) {
50
+ throw unavailable('OpenRC user services require an active XDG_RUNTIME_DIR');
51
+ }
52
+ if (!(await detectOpenRcUserSessionActivation(currentUsername()))) {
53
+ throw unavailable('OpenRC user services are not configured for automatic session or boot activation; use an on-demand Runtime Host');
54
+ }
55
+ }
56
+ await requireProbe(run, 'supervise-daemon', ['--help'], false);
57
+ await requireProbe(run, 'rc-service', ['--help'], false);
58
+ const runlevel = await requireProbe(run, 'rc-status', [...scopeArgs(provider), '--runlevel']);
59
+ if (runlevel.stdout.trim() !== 'default') {
60
+ throw unavailable('The OpenRC default runlevel is not active');
61
+ }
62
+ await requireProbe(run, 'rc-update', [...scopeArgs(provider), 'show', 'default']);
63
+ };
64
+ return {
65
+ supervisor: {
66
+ provider,
67
+ preflight,
68
+ converge: (definition) => convergeOpenRcService(host, definition),
69
+ verify: (definition) => verifyOpenRcService(host, definition),
70
+ status: () => readOpenRcSupervisorStatus(host),
71
+ activate: () => startOpenRcService(host),
72
+ retire: () => stopOpenRcService(host),
73
+ logs: () => readOpenRcLogs(host),
74
+ uninstall: () => uninstallOpenRcService(host),
75
+ },
76
+ reconciliationTrigger: {
77
+ provider: 'openrc_supervised_loop',
78
+ converge: (definition) => convergeOpenRcService(update, definition, updateCommandPath),
79
+ verify: (definition) => verifyOpenRcService(update, definition, updateCommandPath),
80
+ status: async () => {
81
+ const observed = await readOpenRcStatus(update);
82
+ return { installed: observed.installed, active: observed.active };
83
+ },
84
+ activate: () => startOpenRcService(update),
85
+ logs: () => readOpenRcLogs(update),
86
+ uninstall: () => uninstallOpenRcService(update, updateCommandPath),
87
+ },
88
+ };
89
+ }
90
+ function renderOpenRcReconciliationLoop(definition) {
91
+ assertRuntimeHostProviderDefinition(definition);
92
+ const command = definition.command.map(quoteShellWord).join(' ');
93
+ return [
94
+ '#!/bin/sh',
95
+ 'umask 077',
96
+ `initial_delay=${String(RUNTIME_HOST_UPDATE_INITIAL_DELAY_SECONDS)}`,
97
+ `random_delay=${String(RUNTIME_HOST_UPDATE_RANDOM_DELAY_SECONDS)}`,
98
+ "now=$(date +%s 2>/dev/null || printf '0')",
99
+ 'sleep "$((initial_delay + now % (random_delay + 1)))"',
100
+ 'while :; do',
101
+ ` ${command} || :`,
102
+ ` sleep ${String(RUNTIME_HOST_UPDATE_INTERVAL_SECONDS)}`,
103
+ 'done',
104
+ '',
105
+ ].join('\n');
106
+ }
107
+ function renderOpenRcService(context, definition, periodicCommandPath) {
108
+ const command = periodicCommandPath ? '/bin/sh' : definition.command[0];
109
+ const commandArguments = periodicCommandPath
110
+ ? [periodicCommandPath]
111
+ : definition.command.slice(1);
112
+ return [
113
+ '#!/sbin/openrc-run',
114
+ `description=${quoteShellWord(context.name)}`,
115
+ 'supervisor=supervise-daemon',
116
+ `command=${quoteDoubleQuotedShellValue(quoteShellWord(command))}`,
117
+ `command_args=${quoteDoubleQuotedShellValue(commandArguments.map(quoteShellWord).join(' '))}`,
118
+ `output_log=${quoteDoubleQuotedShellValue(quoteShellWord(context.stdoutPath))}`,
119
+ `error_log=${quoteDoubleQuotedShellValue(quoteShellWord(context.stderrPath))}`,
120
+ 'retry=TERM/20/KILL/5',
121
+ 'respawn_delay=2',
122
+ 'respawn_max=0',
123
+ '',
124
+ ].join('\n');
125
+ }
126
+ async function convergeOpenRcService(context, definition, periodicCommandPath) {
127
+ assertRuntimeHostProviderDefinition(definition);
128
+ await stopOpenRcService(context);
129
+ await mkdir(dirname(context.stdoutPath), { recursive: true, mode: 0o700 });
130
+ await writeRuntimeHostServiceFile(context.servicePath, renderOpenRcService(context, definition, periodicCommandPath), 0o700);
131
+ if (periodicCommandPath) {
132
+ await writeRuntimeHostServiceFile(periodicCommandPath, renderOpenRcReconciliationLoop(definition), 0o700);
133
+ }
134
+ await requireOpenRc(context, 'rc-update', [...scopeArgs(context.provider), 'add', context.name, 'default'], 'Enabling the Runtime Host OpenRC service failed');
135
+ }
136
+ async function verifyOpenRcService(context, definition, periodicCommandPath) {
137
+ assertRuntimeHostProviderDefinition(definition);
138
+ const expectedService = renderOpenRcService(context, definition, periodicCommandPath);
139
+ const [service, enabled] = await Promise.all([
140
+ readManagedFile(context.servicePath, expectedService),
141
+ isEnabled(context),
142
+ ]);
143
+ const expectedCommand = periodicCommandPath
144
+ ? renderOpenRcReconciliationLoop(definition)
145
+ : undefined;
146
+ const command = expectedCommand
147
+ ? await readManagedFile(periodicCommandPath, expectedCommand)
148
+ : undefined;
149
+ if (service !== expectedService || command !== expectedCommand || !enabled) {
150
+ throw new RuntimeHostServiceManagerError('target_mismatch', `The ${context.provider} service does not match its managed deployment`);
151
+ }
152
+ }
153
+ async function readOpenRcSupervisorStatus(context) {
154
+ const observed = await readOpenRcStatus(context);
155
+ return { provider: context.provider, ...observed };
156
+ }
157
+ async function readOpenRcStatus(context) {
158
+ const installed = await isRegularFile(context.servicePath);
159
+ const enabled = await isEnabled(context);
160
+ if (!installed) {
161
+ return {
162
+ installed: false,
163
+ enabled,
164
+ active: false,
165
+ state: 'not_installed',
166
+ pid: null,
167
+ lastExitCode: null,
168
+ };
169
+ }
170
+ let result;
171
+ try {
172
+ result = await context.run('rc-service', [
173
+ ...scopeArgs(context.provider),
174
+ context.name,
175
+ 'status',
176
+ ]);
177
+ }
178
+ catch (error) {
179
+ throw unavailable('Unable to query the OpenRC service manager', error);
180
+ }
181
+ const active = result.exitCode === 0;
182
+ return {
183
+ installed,
184
+ enabled,
185
+ active,
186
+ state: result.exitCode === 0
187
+ ? 'running'
188
+ : result.exitCode === 8 || result.exitCode === 4
189
+ ? 'starting'
190
+ : result.exitCode === 3 || result.exitCode === 16
191
+ ? 'stopped'
192
+ : 'failed',
193
+ pid: active ? await readOpenRcPid(context.pidPath) : null,
194
+ lastExitCode: null,
195
+ };
196
+ }
197
+ async function startOpenRcService(context) {
198
+ if (!(await isRegularFile(context.servicePath)))
199
+ return;
200
+ const status = await readOpenRcStatus(context);
201
+ if (status.active)
202
+ return;
203
+ await requireOpenRc(context, 'rc-service', [...scopeArgs(context.provider), context.name, 'start'], 'Starting the Runtime Host OpenRC service failed');
204
+ }
205
+ async function stopOpenRcService(context) {
206
+ if (!(await isRegularFile(context.servicePath)))
207
+ return;
208
+ const status = await readOpenRcStatus(context);
209
+ if (status.state === 'stopped')
210
+ return;
211
+ await requireOpenRc(context, 'rc-service', [...scopeArgs(context.provider), context.name, 'stop'], 'Stopping the Runtime Host OpenRC service failed');
212
+ }
213
+ async function uninstallOpenRcService(context, periodicCommandPath) {
214
+ await stopOpenRcService(context);
215
+ if (await pathExists(context.runlevelPath)) {
216
+ await requireOpenRc(context, 'rc-update', [...scopeArgs(context.provider), 'del', context.name, 'default'], 'Disabling the Runtime Host OpenRC service failed');
217
+ }
218
+ await Promise.all([
219
+ removeRuntimeHostServiceFile(context.servicePath, 'OpenRC service'),
220
+ ...(periodicCommandPath
221
+ ? [removeRuntimeHostServiceFile(periodicCommandPath, 'OpenRC command')]
222
+ : []),
223
+ ]);
224
+ const status = await readOpenRcStatus(context);
225
+ if (status.installed ||
226
+ status.enabled ||
227
+ status.active ||
228
+ (await pathExists(context.runlevelPath))) {
229
+ throw new RuntimeHostServiceManagerError('uninstall_incomplete', 'The Runtime Host OpenRC service still has managed state');
230
+ }
231
+ }
232
+ async function readOpenRcLogs(context) {
233
+ const [stdout, stderr] = await Promise.all([
234
+ readLogTail(context.stdoutPath),
235
+ readLogTail(context.stderrPath),
236
+ ]);
237
+ return formatRuntimeHostServiceLogs([
238
+ { label: 'stdout', logs: stdout },
239
+ { label: 'stderr', logs: stderr },
240
+ ]);
241
+ }
242
+ function createContext(provider, serviceId, suffix, artifact, paths, run) {
243
+ const name = `maka-runtime-host-${serviceId}${suffix}`;
244
+ return {
245
+ provider,
246
+ name,
247
+ servicePath: join(paths.initDirectory, name),
248
+ runlevelPath: join(paths.runlevelDirectory, name),
249
+ ...(paths.stateDirectory
250
+ ? { pidPath: join(paths.stateDirectory, 'options', name, 'child_pid') }
251
+ : {}),
252
+ stdoutPath: join(paths.logDirectory, `${artifact}.stdout.log`),
253
+ stderrPath: join(paths.logDirectory, `${artifact}.stderr.log`),
254
+ run,
255
+ };
256
+ }
257
+ function defaultPaths(provider, serviceId, env, homeDir) {
258
+ if (provider === 'openrc_system') {
259
+ return {
260
+ initDirectory: '/etc/init.d',
261
+ runlevelDirectory: '/etc/runlevels/default',
262
+ artifactDirectory: join('/etc/maka/runtime-host', serviceId),
263
+ logDirectory: join('/var/log/maka/runtime-host', serviceId),
264
+ stateDirectory: '/run/openrc',
265
+ };
266
+ }
267
+ const config = resolveXdgConfigHome(env, homeDir);
268
+ const stateHome = env.XDG_STATE_HOME && isAbsolute(env.XDG_STATE_HOME)
269
+ ? env.XDG_STATE_HOME
270
+ : join(homeDir, '.local', 'state');
271
+ const runtime = env.XDG_RUNTIME_DIR;
272
+ return {
273
+ initDirectory: join(config, 'rc', 'init.d'),
274
+ runlevelDirectory: join(config, 'rc', 'runlevels', 'default'),
275
+ artifactDirectory: join(config, 'maka', 'runtime-host', serviceId, 'openrc'),
276
+ logDirectory: join(stateHome, 'maka', 'runtime-host', serviceId),
277
+ ...(runtime && isAbsolute(runtime) ? { stateDirectory: join(runtime, 'openrc') } : {}),
278
+ };
279
+ }
280
+ function scopeArgs(provider) {
281
+ return provider === 'openrc_user' ? ['--user'] : [];
282
+ }
283
+ async function requireProbe(run, command, args, requireSuccess = true) {
284
+ let result;
285
+ try {
286
+ result = await run(command, args);
287
+ }
288
+ catch (error) {
289
+ throw unavailable(`${command} is unavailable`, error);
290
+ }
291
+ if (requireSuccess && result.exitCode !== 0) {
292
+ throw unavailable(`${command} is unavailable${commandDetail(result)}`);
293
+ }
294
+ return result;
295
+ }
296
+ async function requireOpenRc(context, command, args, message) {
297
+ let result;
298
+ try {
299
+ result = await context.run(command, args);
300
+ }
301
+ catch (error) {
302
+ throw unavailable(message, error);
303
+ }
304
+ if (result.exitCode !== 0) {
305
+ throw new RuntimeHostServiceManagerError('service_manager_operation_failed', `${message}${commandDetail(result)}`);
306
+ }
307
+ }
308
+ function commandDetail(result) {
309
+ const detail = result.stderr.trim() || result.stdout.trim();
310
+ return detail ? `: ${detail}` : '';
311
+ }
312
+ async function isEnabled(context) {
313
+ try {
314
+ const [target, service] = await Promise.all([
315
+ realpath(context.runlevelPath),
316
+ realpath(context.servicePath),
317
+ ]);
318
+ return target === service;
319
+ }
320
+ catch (error) {
321
+ if (isNodeError(error, 'ENOENT'))
322
+ return false;
323
+ throw error;
324
+ }
325
+ }
326
+ async function isRegularFile(path) {
327
+ try {
328
+ return (await lstat(path)).isFile();
329
+ }
330
+ catch (error) {
331
+ if (isNodeError(error, 'ENOENT'))
332
+ return false;
333
+ throw error;
334
+ }
335
+ }
336
+ async function pathExists(path) {
337
+ try {
338
+ await lstat(path);
339
+ return true;
340
+ }
341
+ catch (error) {
342
+ if (isNodeError(error, 'ENOENT'))
343
+ return false;
344
+ throw error;
345
+ }
346
+ }
347
+ async function readManagedFile(path, expected) {
348
+ return readStableBoundedFile({
349
+ path,
350
+ maxBytes: Buffer.byteLength(expected),
351
+ invalidFile: () => new RuntimeHostServiceManagerError('target_mismatch', 'A managed OpenRC artifact is not a stable regular file'),
352
+ })
353
+ .then((bytes) => {
354
+ try {
355
+ return new TextDecoder('utf-8', { fatal: true }).decode(bytes);
356
+ }
357
+ catch {
358
+ throw new RuntimeHostServiceManagerError('target_mismatch', 'A managed OpenRC artifact is not valid UTF-8');
359
+ }
360
+ })
361
+ .catch((error) => {
362
+ if (isNodeError(error, 'ENOENT'))
363
+ return null;
364
+ throw error;
365
+ });
366
+ }
367
+ async function readOpenRcPid(path) {
368
+ if (!path)
369
+ return null;
370
+ try {
371
+ const value = (await readStableBoundedFile({
372
+ path,
373
+ maxBytes: 32,
374
+ invalidFile: () => new Error('Invalid OpenRC process state'),
375
+ }))
376
+ .toString('utf8')
377
+ .trim();
378
+ const pid = Number(value);
379
+ return Number.isSafeInteger(pid) && pid > 0 ? pid : null;
380
+ }
381
+ catch (error) {
382
+ if (isNodeError(error, 'ENOENT'))
383
+ return null;
384
+ return null;
385
+ }
386
+ }
387
+ async function readLogTail(path) {
388
+ let file;
389
+ try {
390
+ file = await open(path, 'r');
391
+ }
392
+ catch (error) {
393
+ if (isNodeError(error, 'ENOENT'))
394
+ return '';
395
+ throw error;
396
+ }
397
+ try {
398
+ const size = (await file.stat()).size;
399
+ const length = Math.min(size, Math.floor(RUNTIME_HOST_SERVICE_LOG_MAX_BYTES / 2));
400
+ if (length === 0)
401
+ return '';
402
+ const buffer = Buffer.alloc(length);
403
+ await file.read(buffer, 0, length, size - length);
404
+ return buffer.toString('utf8');
405
+ }
406
+ finally {
407
+ await file.close();
408
+ }
409
+ }
410
+ async function detectOpenRcUserSessionActivation(username) {
411
+ if (username) {
412
+ try {
413
+ const [configured, template] = await Promise.all([
414
+ realpath(join('/etc/runlevels/default', `user.${username}`)),
415
+ realpath('/etc/init.d/user'),
416
+ ]);
417
+ if (configured === template)
418
+ return true;
419
+ }
420
+ catch (error) {
421
+ if (!isNodeError(error, 'ENOENT'))
422
+ throw error;
423
+ }
424
+ }
425
+ let entries;
426
+ try {
427
+ entries = await readdir('/etc/pam.d', { withFileTypes: true });
428
+ }
429
+ catch (error) {
430
+ if (isNodeError(error, 'ENOENT') || isNodeError(error, 'EACCES'))
431
+ return false;
432
+ throw error;
433
+ }
434
+ for (const entry of entries.slice(0, 256)) {
435
+ if (!entry.isFile())
436
+ continue;
437
+ const contents = await readFile(join('/etc/pam.d', entry.name), 'utf8').catch(() => '');
438
+ if (/^[^#\n]*\bpam_openrc\.so\b/mu.test(contents))
439
+ return true;
440
+ }
441
+ return false;
442
+ }
443
+ function quoteShellWord(value) {
444
+ return `'${value.replaceAll("'", "'\\''")}'`;
445
+ }
446
+ function quoteDoubleQuotedShellValue(value) {
447
+ return `"${value.replace(/[\\"$`]/gu, '\\$&')}"`;
448
+ }
449
+ function currentUsername() {
450
+ try {
451
+ return userInfo().username;
452
+ }
453
+ catch {
454
+ return undefined;
455
+ }
456
+ }
457
+ function unavailable(message, cause) {
458
+ return new RuntimeHostServiceManagerError('service_manager_unavailable', message, cause === undefined ? undefined : { cause });
459
+ }
460
+ async function defaultRunOpenRcCommand(command, args) {
461
+ return runRuntimeHostServiceManagerCommand(command, args);
462
+ }
463
+ function assertServiceId(serviceId) {
464
+ if (!/^[a-f0-9]{64}$/u.test(serviceId))
465
+ throw new TypeError('Invalid Runtime Host service ID');
466
+ }
467
+ function isNodeError(error, code) {
468
+ return error instanceof Error && 'code' in error && error.code === code;
469
+ }
@@ -304,7 +304,9 @@ class RuntimeHostRunRuntime {
304
304
  if (next.done)
305
305
  break;
306
306
  const event = next.value;
307
- if (event.type === 'user_question_request' || event.type === 'sandbox_boundary_request') {
307
+ if (event.type === 'user_question_request' ||
308
+ event.type === 'form_request' ||
309
+ event.type === 'sandbox_boundary_request') {
308
310
  continue;
309
311
  }
310
312
  active.outcome.accept(observationFromSessionEvent(event));
@@ -656,7 +658,9 @@ class NonInteractiveInteractionController {
656
658
  await this.#stop(pending);
657
659
  throw new Error(pending.request.kind === 'question'
658
660
  ? 'interactive user questions are unavailable in non-interactive mode'
659
- : 'interactive permission requests are unavailable in non-interactive mode');
661
+ : pending.request.kind === 'form'
662
+ ? 'interactive user forms are unavailable in non-interactive mode'
663
+ : 'interactive permission requests are unavailable in non-interactive mode');
660
664
  }
661
665
  #fail(error) {
662
666
  if (this.#failure)
@@ -62,7 +62,7 @@ export async function runRuntimeHostServiceCli(options) {
62
62
  process.stdout.write(`Runtime Host WebSocket is ready at ${endpoint}\n`);
63
63
  }
64
64
  for (const peer of host.peerListeners) {
65
- process.stdout.write(`Runtime Host direct peer is ready as ${peer.peerId} at ${peer.listenAddresses.join(', ')}\n`);
65
+ process.stdout.write(`Runtime Host direct peer is ready as ${peer.reachability.lease.peerId} at ${peer.reachability.lease.directRoutes.join(', ')}\n`);
66
66
  }
67
67
  },
68
68
  });
@@ -99,8 +99,8 @@ export function createRuntimeHostServiceReadyEvent(host) {
99
99
  }),
100
100
  ...host.peerListeners.map((peer) => ({
101
101
  kind: 'libp2p_direct',
102
- peerId: peer.peerId,
103
- listenAddresses: peer.listenAddresses,
102
+ peerId: peer.reachability.lease.peerId,
103
+ listenAddresses: peer.reachability.lease.directRoutes,
104
104
  })),
105
105
  ],
106
106
  };
@@ -24,6 +24,7 @@ import { cleanupRuntimeHostManagedDeployment, effectiveRuntimeHostProjectDirecto
24
24
  import { createLaunchAgentRuntimeHostService } from './runtime-host-launch-agent-service.js';
25
25
  import { createLaunchAgentRuntimeHostLifecycleProvider } from './runtime-host-launch-agent-service.js';
26
26
  import { createSystemdUserRuntimeHostLifecycleProvider, createSystemdUserRuntimeHostService, } from './runtime-host-systemd-service.js';
27
+ import { createOpenRcRuntimeHostLifecycleProvider } from './runtime-host-openrc-service.js';
27
28
  import { manageRuntimeHostManagedLifecycle } from './runtime-host-managed-lifecycle-manager.js';
28
29
  import { acknowledgeRuntimeHostManagedDeploymentCleanup, assertRuntimeHostManagedOperatorDeployment, clearRuntimeHostManagedDeploymentCleanupReceipt, readRuntimeHostManagedDeploymentCleanupReceipt, removeRuntimeHostManagedDeployment, resolveRuntimeHostManagedControlRoot, resolveRuntimeHostManagedDeploymentForCli, } from './runtime-host-managed-deployment.js';
29
30
  export async function runManagedRuntimeHostServiceCli(options, overrides = {}) {
@@ -322,25 +323,52 @@ export function createPlatformRuntimeHostServiceBackend(serviceId, clientDataRoo
322
323
  throw new RuntimeHostServiceManagerError('unsupported_platform', 'Managed Runtime Host services currently require Linux or macOS');
323
324
  }
324
325
  export async function discoverRuntimeHostLifecycleProvider(rootId, options = {}) {
325
- const selection = selectRuntimeHostLifecycleProvider({
326
- platform: options.platform ?? process.platform,
327
- environment: options.environment ?? process.env,
326
+ const platform = options.platform ?? process.platform;
327
+ const environment = options.environment ?? process.env;
328
+ if (platform === 'darwin') {
329
+ const provider = createLaunchAgentRuntimeHostLifecycleProvider(rootId);
330
+ await provider.supervisor.preflight();
331
+ return { provider, availability: 'session' };
332
+ }
333
+ if (platform !== 'linux') {
334
+ throw new RuntimeHostServiceManagerError('unsupported_platform', 'Supervised Runtime Host deployments currently require Linux or macOS');
335
+ }
336
+ const systemd = createSystemdUserRuntimeHostLifecycleProvider(rootId, {
337
+ env: environment,
328
338
  });
329
- const provider = resolveRuntimeHostLifecycleProvider(rootId, selection.provider);
330
- await provider.supervisor.preflight();
331
- return { provider, availability: selection.availability };
332
- }
333
- export function selectRuntimeHostLifecycleProvider(options) {
334
- if (options.platform === 'linux') {
339
+ let systemdError;
340
+ try {
341
+ await systemd.supervisor.preflight();
335
342
  return {
336
- provider: 'systemd_user',
337
- availability: isWslEnvironment(options.environment) ? 'environment' : 'machine',
343
+ provider: systemd,
344
+ availability: isWslEnvironment(environment) ? 'environment' : 'machine',
338
345
  };
339
346
  }
340
- if (options.platform === 'darwin') {
341
- return { provider: 'launch_agent', availability: 'session' };
347
+ catch (error) {
348
+ systemdError = error;
349
+ }
350
+ const openRcProvider = process.getuid?.() === 0 ? 'openrc_system' : 'openrc_user';
351
+ const openRc = createOpenRcRuntimeHostLifecycleProvider(rootId, openRcProvider, {
352
+ env: environment,
353
+ });
354
+ try {
355
+ await openRc.supervisor.preflight();
356
+ return {
357
+ provider: openRc,
358
+ availability: isWslEnvironment(environment)
359
+ ? 'environment'
360
+ : openRcProvider === 'openrc_system'
361
+ ? 'machine'
362
+ : 'session',
363
+ };
364
+ }
365
+ catch (openRcError) {
366
+ if (systemdError instanceof RuntimeHostServiceManagerError &&
367
+ systemdError.code === 'linger_disabled') {
368
+ throw systemdError;
369
+ }
370
+ throw new RuntimeHostServiceManagerError('service_manager_unavailable', 'No supervised Linux lifecycle provider is available; configure systemd user lingering or OpenRC activation, or use an on-demand Runtime Host', { cause: new AggregateError([systemdError, openRcError]) });
342
371
  }
343
- throw new RuntimeHostServiceManagerError('unsupported_platform', 'Supervised Runtime Host deployments currently require Linux or macOS');
344
372
  }
345
373
  /** Resolves only the provider identity already persisted by the deployment authority. */
346
374
  export function resolveRuntimeHostLifecycleProvider(rootId, provider) {
@@ -348,7 +376,7 @@ export function resolveRuntimeHostLifecycleProvider(rootId, provider) {
348
376
  return createSystemdUserRuntimeHostLifecycleProvider(rootId, {});
349
377
  if (provider === 'launch_agent')
350
378
  return createLaunchAgentRuntimeHostLifecycleProvider(rootId);
351
- throw new RuntimeHostServiceManagerError('service_manager_unavailable', `The persisted Runtime Host provider ${provider} is unavailable`);
379
+ return createOpenRcRuntimeHostLifecycleProvider(rootId, provider);
352
380
  }
353
381
  function isWslEnvironment(environment) {
354
382
  return Boolean(environment.WSL_DISTRO_NAME?.trim() || environment.WSL_INTEROP?.trim());
@@ -217,6 +217,9 @@ export class RuntimeHostSessionChannel {
217
217
  if (answered.outcome.kind === 'question_answer') {
218
218
  this.#emit({ type: 'user_question_answer_ack', ...base });
219
219
  }
220
+ else if (answered.outcome.kind === 'form_answer') {
221
+ this.#emit({ type: 'form_answer_ack', ...base });
222
+ }
220
223
  else if (answered.outcome.kind === 'sandbox_boundary_decision') {
221
224
  this.#emit({
222
225
  type: 'sandbox_boundary_decision_ack',
@@ -415,6 +415,22 @@ class RuntimeHostMakaSessionDriverImpl {
415
415
  if (pending)
416
416
  this.#channel?.publishInteractionAnswer(answered, pending);
417
417
  }
418
+ async respondToUserForm(response) {
419
+ const sessionId = this.#requireSession('respond to a user form');
420
+ const pending = this.#channel?.pendingInteraction(response.requestId);
421
+ if (pending && pending.request.kind !== 'form') {
422
+ throw new Error('Interaction is not a form request');
423
+ }
424
+ const answered = await this.#request('interaction.answer', {
425
+ sessionId,
426
+ interactionId: response.requestId,
427
+ answer: response.action === 'accept'
428
+ ? { kind: 'form', action: 'accept', values: response.values }
429
+ : { kind: 'form', action: response.action },
430
+ });
431
+ if (pending)
432
+ this.#channel?.publishInteractionAnswer(answered, pending);
433
+ }
418
434
  setModel(model, connectionSlug, connectionId) {
419
435
  return this.#admit(() => this.#setModel(model, connectionSlug, connectionId));
420
436
  }
@@ -639,26 +655,25 @@ class RuntimeHostMakaSessionDriverImpl {
639
655
  async openSideConversation() {
640
656
  const parentSessionId = this.#requireSession('open a side conversation');
641
657
  const messages = await loadCurrentMessages(this.#connection, parentSessionId);
658
+ // Absent when the parent has no completed turn yet: fork with an empty
659
+ // context instead of failing, matching the desktop side conversation.
642
660
  const sourceTurnId = deriveTurnRecords(messages)
643
661
  .reverse()
644
662
  .find((turn) => turn.status === 'completed')?.turnId;
645
- if (!sourceTurnId) {
646
- throw new Error('A side conversation requires at least one completed Turn.');
647
- }
648
663
  const sideSessionId = this.#newId();
649
664
  const cleanup = this.#requireSessionCopyCleanup();
650
665
  await cleanup.ownCreation({
651
666
  sessionId: sideSessionId,
652
667
  kind: 'branch',
653
668
  sourceSessionId: parentSessionId,
654
- sourceTurnId,
669
+ ...(sourceTurnId === undefined ? {} : { sourceTurnId }),
655
670
  intent: 'side_conversation',
656
671
  ownerId: 'tui-side',
657
672
  }, () => this.#resumeSessionCopy({
658
673
  sessionId: sideSessionId,
659
674
  kind: 'branch',
660
675
  sourceSessionId: parentSessionId,
661
- sourceTurnId,
676
+ ...(sourceTurnId === undefined ? {} : { sourceTurnId }),
662
677
  intent: 'side_conversation',
663
678
  }));
664
679
  try {
@@ -1111,7 +1126,7 @@ class RuntimeHostMakaSessionDriverImpl {
1111
1126
  const result = await this.#request('session.branch.create', {
1112
1127
  sourceSessionId: input.sourceSessionId,
1113
1128
  targetSessionId: input.sessionId,
1114
- sourceTurnId: input.sourceTurnId,
1129
+ ...(input.sourceTurnId === undefined ? {} : { sourceTurnId: input.sourceTurnId }),
1115
1130
  expectedSourceRevision: source.revision,
1116
1131
  ...(input.intent ? { intent: input.intent } : {}),
1117
1132
  });