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.
- package/dist/cli-core.js +0 -1
- package/dist/pi-transcript.js +48 -0
- package/dist/pi-tui-form-interaction.js +497 -0
- package/dist/pi-tui-pickers.js +256 -55
- package/dist/pi-tui-runner.js +215 -12
- package/dist/runtime-host-cli.js +17 -42
- package/dist/runtime-host-lifecycle-transaction.js +31 -13
- package/dist/runtime-host-managed-lifecycle-manager.js +1 -1
- package/dist/runtime-host-onboarding.js +3 -1
- package/dist/runtime-host-openrc-service.js +469 -0
- package/dist/runtime-host-run-command.js +6 -2
- package/dist/runtime-host-service-command.js +3 -3
- package/dist/runtime-host-service-management-command.js +43 -15
- package/dist/runtime-host-session-channel.js +3 -0
- package/dist/runtime-host-session-driver.js +21 -6
- package/dist/runtime-host-setup-command.js +30 -31
- package/dist/tui-context-refresh.js +103 -0
- package/dist/tui-copy-catalog.js +73 -0
- package/native/runtime-host-peer/prebuilds/darwin-arm64/maka_runtime_host_peer.node +0 -0
- package/native/runtime-host-peer/prebuilds/linux-arm64/maka_runtime_host_peer.node +0 -0
- package/native/runtime-host-peer/prebuilds/linux-x64/maka_runtime_host_peer.node +0 -0
- package/native/runtime-host-peer/prebuilds/win32-x64/maka_runtime_host_peer.node +0 -0
- package/node_modules/@maka/core/dist/chat-model-choice.js +4 -0
- package/node_modules/@maka/core/dist/computer-use.js +27 -92
- package/node_modules/@maka/core/dist/interaction.js +577 -3
- package/node_modules/@maka/core/dist/llm-connections.js +4 -0
- package/node_modules/@maka/core/dist/local-memory.js +2 -2
- package/node_modules/@maka/core/dist/model-call-usage-projection.js +3 -0
- package/node_modules/@maka/core/dist/model-metadata.js +26 -7
- package/node_modules/@maka/core/dist/model-thinking.js +17 -0
- package/node_modules/@maka/core/dist/provider-registry.js +1 -0
- package/node_modules/@maka/core/dist/runtime-event.js +23 -1
- package/node_modules/@maka/core/dist/scheduled-task.js +4 -0
- package/node_modules/@maka/core/dist/session.js +95 -2
- package/node_modules/@maka/core/dist/text-sanitize.js +19 -0
- package/node_modules/@maka/core/dist/usage-ledger-merge.js +3 -0
- package/node_modules/@maka/core/dist/usage-record-schema.js +11 -5
- package/node_modules/@maka/core/dist/workhub-creation-intent.js +75 -9
- package/node_modules/@maka/core/dist/workhub-session-resolver.js +50 -0
- package/node_modules/@maka/core/package.json +2 -0
- package/node_modules/@maka/eval/dist/harbor-external-subject.js +2 -1
- package/node_modules/@maka/eval/dist/harness-executor.js +3 -2
- package/node_modules/@maka/eval/dist/install-preflight.js +39 -10
- package/node_modules/@maka/eval/dist/process-termination.js +83 -0
- package/node_modules/@maka/mcp/dist/sep-2243.js +3 -3
- package/node_modules/@maka/runtime/dist/agent-run.js +6 -3
- package/node_modules/@maka/runtime/dist/ai-sdk-backend.js +332 -118
- package/node_modules/@maka/runtime/dist/ai-sdk-compaction-contract.js +6 -1
- package/node_modules/@maka/runtime/dist/ai-sdk-compaction.js +171 -341
- package/node_modules/@maka/runtime/dist/bots/telegram-bridge.js +3 -26
- package/node_modules/@maka/runtime/dist/bundled-skill-catalog.generated.js +1 -1
- package/node_modules/@maka/runtime/dist/computer-use-codec.js +1 -141
- package/node_modules/@maka/runtime/dist/computer-use-tools.js +23 -105
- package/node_modules/@maka/runtime/dist/context-budget-policy.js +20 -26
- package/node_modules/@maka/runtime/dist/context-budget.js +18 -20
- package/node_modules/@maka/runtime/dist/conversation-copy.js +23 -19
- package/node_modules/@maka/runtime/dist/cua-frame-state.js +1 -69
- package/node_modules/@maka/runtime/dist/github-copilot-oauth-enrollment.js +267 -0
- package/node_modules/@maka/runtime/dist/history-compact-checkpoint.js +6 -9
- package/node_modules/@maka/runtime/dist/history-compact-summarizer.js +67 -23
- package/node_modules/@maka/runtime/dist/history-compact-summary-validation.js +11 -18
- package/node_modules/@maka/runtime/dist/history-compaction.js +66 -73
- package/node_modules/@maka/runtime/dist/interaction-authority.js +69 -0
- package/node_modules/@maka/runtime/dist/mcp-tools.js +13 -1
- package/node_modules/@maka/runtime/dist/memory-extraction.js +11 -11
- package/node_modules/@maka/runtime/dist/model-adapter.js +24 -6
- package/node_modules/@maka/runtime/dist/model-factory.js +14 -5
- package/node_modules/@maka/runtime/dist/oauth-provider-contracts.js +28 -1
- package/node_modules/@maka/runtime/dist/openai-codex-history-compactor.js +7 -6
- package/node_modules/@maka/runtime/dist/opencode-session-header.js +29 -0
- package/node_modules/@maka/runtime/dist/runtime-event-read-model.js +11 -1
- package/node_modules/@maka/runtime/dist/runtime-kernel.js +12 -11
- package/node_modules/@maka/runtime/dist/runtime-read-model.js +51 -13
- package/node_modules/@maka/runtime/dist/scheduled-task-tools.js +3 -0
- package/node_modules/@maka/runtime/dist/session-event-runtime-mapper.js +26 -0
- package/node_modules/@maka/runtime/dist/session-manager.js +1 -0
- package/node_modules/@maka/runtime/dist/session-projection-helpers.js +16 -1
- package/node_modules/@maka/runtime/dist/stream-graph-projection.js +6 -0
- package/node_modules/@maka/runtime/dist/stream-graph-read-model.js +5 -0
- package/node_modules/@maka/runtime/dist/stream-usage-fallback-fetch.js +74 -0
- package/node_modules/@maka/runtime/dist/subscription-credentials.js +51 -4
- package/node_modules/@maka/runtime/dist/subscription-model-fetch.js +47 -3
- package/node_modules/@maka/runtime/dist/system-prompt/main-session-prompt.js +20 -1
- package/node_modules/@maka/runtime/dist/test-connection.js +18 -11
- package/node_modules/@maka/runtime/dist/tool-runtime.js +183 -0
- package/node_modules/@maka/runtime/package.json +1 -0
- package/node_modules/@maka/runtime-host/dist/adapter/session-projector.js +14 -0
- package/node_modules/@maka/runtime-host/dist/client/client-capability-channel.js +84 -1
- package/node_modules/@maka/runtime-host/dist/client/host-profile.js +68 -51
- package/node_modules/@maka/runtime-host/dist/client/index.js +1 -1
- package/node_modules/@maka/runtime-host/dist/client/owner-connection-code.js +8 -5
- package/node_modules/@maka/runtime-host/dist/client/peer-client.js +342 -36
- package/node_modules/@maka/runtime-host/dist/client/reconnect-lifecycle.js +60 -4
- package/node_modules/@maka/runtime-host/dist/peer-mesh/index.js +3 -3
- package/node_modules/@maka/runtime-host/dist/peer-mesh/limits.js +1 -1
- package/node_modules/@maka/runtime-host/dist/peer-mesh/model.js +48 -60
- package/node_modules/@maka/runtime-host/dist/peer-mesh/node.js +847 -431
- package/node_modules/@maka/runtime-host/dist/peer-mesh/owner.js +33 -74
- package/node_modules/@maka/runtime-host/dist/peer-mesh/store.js +82 -69
- package/node_modules/@maka/runtime-host/dist/peer-reachability/index.js +21 -0
- package/node_modules/@maka/runtime-host/dist/peer-reachability/model.js +202 -0
- package/node_modules/@maka/runtime-host/dist/peer-reachability/owner.js +119 -0
- package/node_modules/@maka/runtime-host/dist/peer-reachability/publisher.js +245 -0
- package/node_modules/@maka/runtime-host/dist/protocol/agent-graph.js +4 -1
- package/node_modules/@maka/runtime-host/dist/protocol/client-capability.js +68 -0
- package/node_modules/@maka/runtime-host/dist/protocol/connection-effects.js +15 -8
- package/node_modules/@maka/runtime-host/dist/protocol/host-status.js +7 -23
- package/node_modules/@maka/runtime-host/dist/protocol/index.js +47 -1
- package/node_modules/@maka/runtime-host/dist/protocol/oauth.js +25 -1
- package/node_modules/@maka/runtime-host/dist/protocol/operations.js +1 -0
- package/node_modules/@maka/runtime-host/dist/protocol/peer-mesh.js +14 -31
- package/node_modules/@maka/runtime-host/dist/protocol/scheduled-task.js +19 -6
- package/node_modules/@maka/runtime-host/dist/protocol/session-collaboration.js +36 -1
- package/node_modules/@maka/runtime-host/dist/protocol/session-revision.js +11 -2
- package/node_modules/@maka/runtime-host/dist/protocol/usage-pricing.js +16 -2
- package/node_modules/@maka/runtime-host/dist/protocol/workhub-coordination.js +51 -2
- package/node_modules/@maka/runtime-host/dist/server/access-authority.js +35 -2
- package/node_modules/@maka/runtime-host/dist/server/access-credential-store.js +1 -0
- package/node_modules/@maka/runtime-host/dist/server/client-capability-coordinator.js +12 -10
- package/node_modules/@maka/runtime-host/dist/server/client-capability-invocation-broker.js +163 -30
- package/node_modules/@maka/runtime-host/dist/server/connection-effect-coordinator.js +38 -14
- package/node_modules/@maka/runtime-host/dist/server/daily-review-coordinator.js +45 -22
- package/node_modules/@maka/runtime-host/dist/server/execution-composition.js +78 -20
- package/node_modules/@maka/runtime-host/dist/server/execution-model-authority.js +4 -2
- package/node_modules/@maka/runtime-host/dist/server/execution-model-composition.js +2 -1
- package/node_modules/@maka/runtime-host/dist/server/execution-service.js +49 -28
- package/node_modules/@maka/runtime-host/dist/server/host-kernel.js +3 -6
- package/node_modules/@maka/runtime-host/dist/server/interaction-coordinator.js +130 -27
- package/node_modules/@maka/runtime-host/dist/server/interaction-projection.js +30 -1
- package/node_modules/@maka/runtime-host/dist/server/listener-set.js +2 -4
- package/node_modules/@maka/runtime-host/dist/server/message-coordinator.js +16 -3
- package/node_modules/@maka/runtime-host/dist/server/oauth-coordinator.js +66 -3
- package/node_modules/@maka/runtime-host/dist/server/oauth-execution-authority.js +20 -3
- package/node_modules/@maka/runtime-host/dist/server/peer-listener.js +8 -21
- package/node_modules/@maka/runtime-host/dist/server/peer-mesh-authority.js +1 -1
- package/node_modules/@maka/runtime-host/dist/server/root-turn-coordinator.js +6 -3
- package/node_modules/@maka/runtime-host/dist/server/scheduled-task-coordinator.js +72 -12
- package/node_modules/@maka/runtime-host/dist/server/session-revision-coordinator.js +48 -18
- package/node_modules/@maka/runtime-host/dist/server/session-turn-access-request-coordinator.js +43 -26
- package/node_modules/@maka/runtime-host/dist/server/usage-pricing-coordinator.js +15 -1
- package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-action-gate.js +229 -4
- package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-coordinator.js +146 -8
- package/node_modules/@maka/runtime-host/dist/transport/peer-native.js +32 -6
- package/node_modules/@maka/runtime-host/package.json +1 -0
- package/node_modules/@maka/storage/dist/agent-run-store.js +18 -5
- package/node_modules/@maka/storage/dist/codex-session-adapter.js +14 -0
- package/node_modules/@maka/storage/dist/execution-stores.js +5 -0
- package/node_modules/@maka/storage/dist/interaction-store.js +13 -1
- package/node_modules/@maka/storage/dist/runtime-policy/connection-catalog-document.js +9 -3
- package/node_modules/@maka/storage/dist/runtime-policy/coordinator.js +49 -19
- package/node_modules/@maka/storage/dist/runtime-policy/oauth-login-receipt-document.js +3 -1
- package/node_modules/@maka/storage/dist/runtime-policy/onboarding-transaction.js +13 -5
- package/node_modules/@maka/storage/dist/session-copy-cleanup.js +4 -2
- package/node_modules/@maka/storage/dist/session-store.js +39 -6
- package/node_modules/@maka/storage/dist/sqlite-runtime-store.js +16 -9
- package/node_modules/@maka/storage/dist/sqlite-session-metadata-schema.js +30 -3
- package/node_modules/@maka/storage/dist/sqlite-session-metadata-store.js +117 -0
- package/node_modules/@maka/storage/dist/sqlite-usage-store.js +29 -6
- package/node_modules/@maka/storage/dist/usage-stores.js +3 -1
- 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' ||
|
|
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
|
-
:
|
|
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.
|
|
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.
|
|
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
|
|
326
|
-
|
|
327
|
-
|
|
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
|
-
|
|
330
|
-
|
|
331
|
-
|
|
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:
|
|
337
|
-
availability: isWslEnvironment(
|
|
343
|
+
provider: systemd,
|
|
344
|
+
availability: isWslEnvironment(environment) ? 'environment' : 'machine',
|
|
338
345
|
};
|
|
339
346
|
}
|
|
340
|
-
|
|
341
|
-
|
|
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
|
-
|
|
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
|
});
|