@amalgm/shell 0.1.162 → 0.1.164-main.34182640231
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/PURPOSE.md +163 -17
- package/README.md +74 -11
- package/config/releases/trust/runtime/main.root.json +84 -0
- package/config/releases/trust/runtime/preview.root.json +84 -0
- package/dist/authorization/recovery-host.d.ts +1 -0
- package/dist/authorization/recovery-host.js +2 -3
- package/dist/authorization/recovery-host.js.map +1 -1
- package/dist/boot.js +28 -20
- package/dist/boot.js.map +1 -1
- package/dist/cli-arguments.d.ts +8 -0
- package/dist/cli-arguments.js +47 -0
- package/dist/cli-arguments.js.map +1 -0
- package/dist/cli.d.ts +6 -4
- package/dist/cli.js +91 -73
- package/dist/cli.js.map +1 -1
- package/dist/compose.js +4 -3
- package/dist/compose.js.map +1 -1
- package/dist/content-cache-index.js +2 -2
- package/dist/content-cache-index.js.map +1 -1
- package/dist/detection/runtime.js +2 -2
- package/dist/detection/runtime.js.map +1 -1
- package/dist/development/profile.d.ts +27 -0
- package/dist/development/profile.js +142 -0
- package/dist/development/profile.js.map +1 -0
- package/dist/entity-apply-host.js +2 -2
- package/dist/entity-apply-host.js.map +1 -1
- package/dist/entity-apply-store.d.ts +2 -1
- package/dist/entity-apply-store.js +52 -37
- package/dist/entity-apply-store.js.map +1 -1
- package/dist/files-register-host.d.ts +1 -0
- package/dist/files-register-host.js +1 -0
- package/dist/files-register-host.js.map +1 -1
- package/dist/installation/environment.d.ts +30 -0
- package/dist/installation/environment.js +28 -0
- package/dist/installation/environment.js.map +1 -0
- package/dist/installation/lease.d.ts +6 -0
- package/dist/installation/lease.js +28 -0
- package/dist/installation/lease.js.map +1 -0
- package/dist/installation/ownership.d.ts +30 -0
- package/dist/installation/ownership.js +156 -0
- package/dist/installation/ownership.js.map +1 -0
- package/dist/installation/selection.d.ts +8 -0
- package/dist/installation/selection.js +29 -0
- package/dist/installation/selection.js.map +1 -0
- package/dist/machine-host.d.ts +27 -5
- package/dist/machine-host.js +244 -96
- package/dist/machine-host.js.map +1 -1
- package/dist/main.js +56 -2
- package/dist/main.js.map +1 -1
- package/dist/platform-product-host.d.ts +9 -9
- package/dist/platform-product-host.js +17 -17
- package/dist/platform-product-host.js.map +1 -1
- package/dist/platform-tools.d.ts +4 -3
- package/dist/platform-tools.js +34 -37
- package/dist/platform-tools.js.map +1 -1
- package/dist/process-lifecycle.d.ts +6 -0
- package/dist/process-lifecycle.js +42 -0
- package/dist/process-lifecycle.js.map +1 -0
- package/dist/pty-host.d.ts +1 -1
- package/dist/pty-host.js +70 -21
- package/dist/pty-host.js.map +1 -1
- package/dist/runtime-command-host.d.ts +7 -0
- package/dist/runtime-command-host.js +49 -13
- package/dist/runtime-command-host.js.map +1 -1
- package/dist/service/adapter.d.ts +36 -0
- package/dist/service/adapter.js +24 -0
- package/dist/service/adapter.js.map +1 -0
- package/dist/service/cli.d.ts +8 -0
- package/dist/service/cli.js +237 -0
- package/dist/service/cli.js.map +1 -0
- package/dist/service/control.d.ts +38 -0
- package/dist/service/control.js +68 -0
- package/dist/service/control.js.map +1 -0
- package/dist/service/index.d.ts +9 -0
- package/dist/service/index.js +10 -0
- package/dist/service/index.js.map +1 -0
- package/dist/service/keepalive.d.ts +18 -0
- package/dist/service/keepalive.js +418 -0
- package/dist/service/keepalive.js.map +1 -0
- package/dist/service/launchd.d.ts +9 -0
- package/dist/service/launchd.js +105 -0
- package/dist/service/launchd.js.map +1 -0
- package/dist/service/owner.d.ts +4 -0
- package/dist/service/owner.js +14 -0
- package/dist/service/owner.js.map +1 -0
- package/dist/service/portable.d.ts +10 -0
- package/dist/service/portable.js +32 -0
- package/dist/service/portable.js.map +1 -0
- package/dist/service/recovery.d.ts +27 -0
- package/dist/service/recovery.js +58 -0
- package/dist/service/recovery.js.map +1 -0
- package/dist/service/registration.d.ts +82 -0
- package/dist/service/registration.js +114 -0
- package/dist/service/registration.js.map +1 -0
- package/dist/service/systemd-unit.d.ts +7 -0
- package/dist/service/systemd-unit.js +43 -0
- package/dist/service/systemd-unit.js.map +1 -0
- package/dist/service/systemd.d.ts +5 -0
- package/dist/service/systemd.js +72 -0
- package/dist/service/systemd.js.map +1 -0
- package/dist/service/windows-action.d.ts +9 -0
- package/dist/service/windows-action.js +55 -0
- package/dist/service/windows-action.js.map +1 -0
- package/dist/service/windows-task.d.ts +9 -0
- package/dist/service/windows-task.js +46 -0
- package/dist/service/windows-task.js.map +1 -0
- package/dist/service/windows.d.ts +2 -0
- package/dist/service/windows.js +65 -0
- package/dist/service/windows.js.map +1 -0
- package/dist/sqlite.d.ts +4 -0
- package/dist/sqlite.js +16 -0
- package/dist/sqlite.js.map +1 -0
- package/dist/updates/artifacts.d.ts +40 -0
- package/dist/updates/artifacts.js +299 -0
- package/dist/updates/artifacts.js.map +1 -0
- package/dist/updates/bootstrap.d.ts +48 -0
- package/dist/updates/bootstrap.js +384 -0
- package/dist/updates/bootstrap.js.map +1 -0
- package/dist/updates/controller.d.ts +66 -0
- package/dist/updates/controller.js +322 -0
- package/dist/updates/controller.js.map +1 -0
- package/dist/updates/isolated-command-lifetime.d.ts +1 -0
- package/dist/updates/isolated-command-lifetime.js +63 -0
- package/dist/updates/isolated-command-lifetime.js.map +1 -0
- package/dist/updates/store.d.ts +41 -0
- package/dist/updates/store.js +80 -0
- package/dist/updates/store.js.map +1 -0
- package/dist/updates/trust.d.ts +20 -0
- package/dist/updates/trust.js +138 -0
- package/dist/updates/trust.js.map +1 -0
- package/dist/user-ground-host.d.ts +4 -1
- package/dist/user-ground-host.js +16 -3
- package/dist/user-ground-host.js.map +1 -1
- package/dist/watching/host.js +4 -2
- package/dist/watching/host.js.map +1 -1
- package/dist/workspace-add-staging.js +2 -2
- package/dist/workspace-add-staging.js.map +1 -1
- package/examinations/fixtures/machine-control-plane.js +57 -0
- package/examinations/fixtures/private-wire-authority.js +1065 -0
- package/examinations/native-service.mjs +92 -0
- package/examinations/network-view.mjs +202 -0
- package/examinations/runtime-upgrade.native-test.mjs +198 -0
- package/npm-shrinkwrap.json +2097 -218
- package/package.json +95 -14
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `amalgm service …`: the verbs a person or an installer uses to put the
|
|
3
|
+
* runtime under OS care. Every verb resolves the same identity from
|
|
4
|
+
* `--user` (and the optional root/home/label selectors), then hands one
|
|
5
|
+
* owner one job. `keepalive` is the verb the OS itself runs.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, readFileSync, rmSync } from "node:fs";
|
|
8
|
+
import { CHILD_HEALTH_POLICY, CHILD_RESTART_POLICY, readyDeadlineMs } from '@amalgm/core/supervision';
|
|
9
|
+
import { option, parseArguments } from "../cli-arguments.js";
|
|
10
|
+
import { runKeepalive } from "./keepalive.js";
|
|
11
|
+
import { controllerLeaseFile, controllerRequest, keepaliveStatus, stopKeepalive } from "./control.js";
|
|
12
|
+
import { acquireProcessLease } from "../installation/lease.js";
|
|
13
|
+
import { dirname, join, resolve } from "node:path";
|
|
14
|
+
import { initializeBootstrap, retryBootstrap } from '../updates/bootstrap.js';
|
|
15
|
+
import { runtimeAppOrigin, runtimeProxyOrigin } from "../installation/environment.js";
|
|
16
|
+
import { resolveInvocationBinding } from "../installation/selection.js";
|
|
17
|
+
import { ownerFor } from "./owner.js";
|
|
18
|
+
import { portableEntrypoint } from "./portable.js";
|
|
19
|
+
import { currentLauncher, detectBackend, readRegistration, registrationSatisfies, serviceIdentity, writeRegistration, registrationFile, } from "./registration.js";
|
|
20
|
+
import { userSystemdAvailable } from "./systemd.js";
|
|
21
|
+
const VERBS = new Set(["install", "start", "stop", "retry", "status", "uninstall", "keepalive"]);
|
|
22
|
+
const ALL_BACKENDS = ["launchd", "systemd", "windows", "portable"];
|
|
23
|
+
/** Options that shape the runtime; forwarded to `amalgm run` as well. */
|
|
24
|
+
const RUNTIME_OPTIONS = ["app-url", "proxy-url", "wire-url", "port", "profile"];
|
|
25
|
+
export async function runServiceCli(args, runtimeLabel = "main") {
|
|
26
|
+
const parsed = parseArguments(args);
|
|
27
|
+
if (parsed.command === "help" || parsed.options.help) {
|
|
28
|
+
process.stdout.write(helpText());
|
|
29
|
+
return 0;
|
|
30
|
+
}
|
|
31
|
+
if (!VERBS.has(parsed.command)) {
|
|
32
|
+
process.stderr.write(`Unknown service command: ${parsed.command}\n\n${helpText()}`);
|
|
33
|
+
return 2;
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
const binding = resolveInvocationBinding(runtimeLabel, parsed);
|
|
37
|
+
const identity = serviceIdentity({
|
|
38
|
+
...binding,
|
|
39
|
+
user: option(parsed, "user"),
|
|
40
|
+
home: option(parsed, "home") || undefined,
|
|
41
|
+
amalgmRoot: option(parsed, "amalgm-root") || undefined,
|
|
42
|
+
});
|
|
43
|
+
if (parsed.command === "keepalive")
|
|
44
|
+
return await runKeepalive(identity);
|
|
45
|
+
if (parsed.command === "install")
|
|
46
|
+
return await install(identity, parsed);
|
|
47
|
+
if (parsed.command === "status") {
|
|
48
|
+
process.stdout.write(`${JSON.stringify(await status(identity), null, 2)}\n`);
|
|
49
|
+
return 0;
|
|
50
|
+
}
|
|
51
|
+
if (parsed.command === "uninstall") {
|
|
52
|
+
await uninstall(identity);
|
|
53
|
+
report("uninstalled", { label: identity.label });
|
|
54
|
+
return 0;
|
|
55
|
+
}
|
|
56
|
+
const registration = readRegistration(identity);
|
|
57
|
+
if (!registration && parsed.command === "start")
|
|
58
|
+
return await install(identity, parsed);
|
|
59
|
+
if (!registration)
|
|
60
|
+
throw new Error(`No service is registered for ${identity.label}; run: amalgm service install --user ${identity.user}`);
|
|
61
|
+
const owner = ownerFor(registration.backend);
|
|
62
|
+
if (parsed.command === "retry") {
|
|
63
|
+
const state = await controllerRequest(identity, 'retry');
|
|
64
|
+
if (!state) {
|
|
65
|
+
if (!registration.files.bootstrap || !retryBootstrap(join(identity.serviceDir, 'updates.sqlite'))) {
|
|
66
|
+
throw new Error('The runtime controller is unavailable or its managed handover requires recovery; its release intent was preserved.');
|
|
67
|
+
}
|
|
68
|
+
await owner.stop(identity);
|
|
69
|
+
await owner.start(identity, registration);
|
|
70
|
+
report('retried', { label: identity.label, phase: 'starting' });
|
|
71
|
+
return 0;
|
|
72
|
+
}
|
|
73
|
+
report("retried", { label: identity.label, phase: state.phase });
|
|
74
|
+
return 0;
|
|
75
|
+
}
|
|
76
|
+
if (parsed.command === "start")
|
|
77
|
+
await owner.start(identity, registration);
|
|
78
|
+
else
|
|
79
|
+
await owner.stop(identity);
|
|
80
|
+
report(parsed.command === "start" ? "started" : "stopped", { label: identity.label, backend: registration.backend });
|
|
81
|
+
return 0;
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
85
|
+
return 1;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
async function install(identity, parsed) {
|
|
89
|
+
const file = join(identity.home, '.amalgm', 'owners', `service-install-${identity.labelScope}.sqlite`);
|
|
90
|
+
const deadline = Date.now() + 15_000;
|
|
91
|
+
let lease = acquireProcessLease(file);
|
|
92
|
+
while (!lease && Date.now() < deadline) {
|
|
93
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
94
|
+
lease = acquireProcessLease(file);
|
|
95
|
+
}
|
|
96
|
+
if (!lease)
|
|
97
|
+
throw new Error('Another setup owns this runtime installation; retry after it completes.');
|
|
98
|
+
try {
|
|
99
|
+
return await installOwned(identity, parsed);
|
|
100
|
+
}
|
|
101
|
+
finally {
|
|
102
|
+
lease.close();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
async function installOwned(identity, parsed) {
|
|
106
|
+
const appUrl = runtimeAppOrigin(identity.binding, option(parsed, "app-url") || undefined);
|
|
107
|
+
runtimeProxyOrigin(identity.binding, appUrl, option(parsed, "proxy-url") || undefined);
|
|
108
|
+
let launcher = currentLauncher();
|
|
109
|
+
const backend = detectBackend(option(parsed, "mode") || "auto", {
|
|
110
|
+
platform: process.platform,
|
|
111
|
+
userSystemd: userSystemdAvailable,
|
|
112
|
+
});
|
|
113
|
+
const prefix = identity.binding.runtimeLabel === 'main' ? [] : [identity.binding.runtimeLabel === 'preview' ? 'preview' : 'dev'];
|
|
114
|
+
const selectors = selectorArguments(identity);
|
|
115
|
+
const keepaliveArgs = [...prefix, 'service', 'keepalive', ...selectors];
|
|
116
|
+
const runArgs = [...prefix, 'run', ...selectors, '--app-url', appUrl, ...forwarded(parsed, RUNTIME_OPTIONS.filter((key) => key !== 'app-url'))];
|
|
117
|
+
const existing = readRegistration(identity);
|
|
118
|
+
const owner = ownerFor(backend);
|
|
119
|
+
const metadata = JSON.parse(readFileSync(join(launcher.packageRoot, 'package.json'), 'utf8'));
|
|
120
|
+
const managed = backend !== 'portable' && identity.binding.runtimeLabel !== 'local' && metadata.name === 'amalgm'
|
|
121
|
+
&& metadata.amalgmSource?.repository === 'amalgm-inc/amalgm-shell' && metadata.amalgmSource.branch === identity.binding.branch
|
|
122
|
+
&& /^[a-f0-9]{40}$/.test(metadata.amalgmSource.commit) && metadata.amalgmRuntime?.schema === 1;
|
|
123
|
+
const bootstrap = managed ? initializeBootstrap({ serviceDir: identity.serviceDir, controllerLease: controllerLeaseFile(identity),
|
|
124
|
+
current: { node: launcher.node, bin: launcher.bin, args: keepaliveArgs }, limits: {
|
|
125
|
+
maxAttempts: CHILD_RESTART_POLICY.maxRestarts + 1, initialDelayMs: CHILD_RESTART_POLICY.initialDelayMs,
|
|
126
|
+
maxDelayMs: CHILD_RESTART_POLICY.maxDelayMs, stableAfterMs: CHILD_RESTART_POLICY.stableAfterMs,
|
|
127
|
+
readyTimeoutMs: readyDeadlineMs(CHILD_HEALTH_POLICY), healthIntervalMs: CHILD_HEALTH_POLICY.intervalMs,
|
|
128
|
+
healthTimeoutMs: CHILD_HEALTH_POLICY.timeoutMs, maxHealthFailures: CHILD_HEALTH_POLICY.maxFailures, stopGraceMs: 30_000,
|
|
129
|
+
} }) : null;
|
|
130
|
+
if (bootstrap) {
|
|
131
|
+
// A reinstall through an older compatible CLI cannot replace an already
|
|
132
|
+
// selected managed controller with that CLI's immutable package generation.
|
|
133
|
+
const packageRoot = resolve(dirname(bootstrap.current.bin), '..');
|
|
134
|
+
const selected = JSON.parse(readFileSync(join(packageRoot, 'package.json'), 'utf8'));
|
|
135
|
+
if (selected.name !== 'amalgm' || selected.amalgmSource?.branch !== identity.binding.branch)
|
|
136
|
+
throw new Error('The selected controller belongs to another managed package');
|
|
137
|
+
launcher = { node: bootstrap.current.node, bin: bootstrap.current.bin, packageRoot, packageVersion: selected.version };
|
|
138
|
+
}
|
|
139
|
+
if (existing && existing.backend === backend && (!bootstrap || existing.files.bootstrap === bootstrap.bin)
|
|
140
|
+
&& registrationSatisfies(existing, { launcher, backend, run_args: runArgs })) {
|
|
141
|
+
if (backend !== "portable")
|
|
142
|
+
await owner.start(identity, existing);
|
|
143
|
+
report("installed", { label: identity.label, backend, unchanged: true, files: existing.files });
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
if (existing && existing.backend !== backend)
|
|
147
|
+
await ownerFor(existing.backend).uninstall(identity);
|
|
148
|
+
const registration = {
|
|
149
|
+
binding: identity.binding, user: identity.user, amalgm_root: identity.amalgmRoot,
|
|
150
|
+
backend,
|
|
151
|
+
label: identity.label,
|
|
152
|
+
package_root: launcher.packageRoot,
|
|
153
|
+
package_version: launcher.packageVersion,
|
|
154
|
+
node: launcher.node,
|
|
155
|
+
bin: launcher.bin,
|
|
156
|
+
runtime_host: "node",
|
|
157
|
+
local_only: false,
|
|
158
|
+
files: { ...owner.files(identity), ...(bootstrap ? { bootstrap: bootstrap.bin } : {}) },
|
|
159
|
+
keepalive_args: keepaliveArgs,
|
|
160
|
+
run_args: runArgs,
|
|
161
|
+
installed_at: new Date().toISOString(),
|
|
162
|
+
};
|
|
163
|
+
writeRegistration(identity, registration);
|
|
164
|
+
await owner.install(identity, bootstrap ? { ...launcher, node: bootstrap.node, bin: bootstrap.bin } : launcher, bootstrap ? bootstrap.args : keepaliveArgs);
|
|
165
|
+
report("installed", { label: identity.label, backend, unchanged: false, files: registration.files });
|
|
166
|
+
}
|
|
167
|
+
if (backend === "portable") {
|
|
168
|
+
process.stdout.write(`Portable mode has no OS owner. Run this in the foreground as your entrypoint:\n ${portableEntrypoint(identity, keepaliveArgs)}\n`);
|
|
169
|
+
}
|
|
170
|
+
return 0;
|
|
171
|
+
}
|
|
172
|
+
async function status(identity) {
|
|
173
|
+
const registration = readRegistration(identity);
|
|
174
|
+
return {
|
|
175
|
+
label: identity.label,
|
|
176
|
+
backend: registration?.backend ?? null,
|
|
177
|
+
registered: registration !== null,
|
|
178
|
+
launcher: registration ? {
|
|
179
|
+
node: registration.node,
|
|
180
|
+
nodeExists: existsSync(registration.node),
|
|
181
|
+
bin: registration.bin,
|
|
182
|
+
binExists: existsSync(registration.bin),
|
|
183
|
+
version: registration.package_version,
|
|
184
|
+
} : null,
|
|
185
|
+
owner: registration ? await ownerFor(registration.backend).status(identity) : null,
|
|
186
|
+
keepalive: await keepaliveStatus(identity),
|
|
187
|
+
serviceDir: identity.serviceDir,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
/** Remove OS launch registration, retaining logs and durable lease files. */
|
|
191
|
+
async function uninstall(identity) {
|
|
192
|
+
const registration = readRegistration(identity);
|
|
193
|
+
if (registration)
|
|
194
|
+
await ownerFor(registration.backend).uninstall(identity);
|
|
195
|
+
for (const backend of ALL_BACKENDS) {
|
|
196
|
+
const owner = ownerFor(backend);
|
|
197
|
+
if (Object.values(owner.files(identity)).some((file) => existsSync(file)))
|
|
198
|
+
await owner.uninstall(identity);
|
|
199
|
+
}
|
|
200
|
+
await stopKeepalive(identity);
|
|
201
|
+
rmSync(registrationFile(identity), { force: true });
|
|
202
|
+
}
|
|
203
|
+
function selectorArguments(identity) {
|
|
204
|
+
const args = ['--user', identity.user, '--home', identity.home, '--amalgm-root', identity.amalgmRoot, '--branch', identity.binding.branch];
|
|
205
|
+
if (identity.binding.localSession)
|
|
206
|
+
args.push('--local-session', identity.binding.localSession);
|
|
207
|
+
return args;
|
|
208
|
+
}
|
|
209
|
+
function forwarded(parsed, keys) {
|
|
210
|
+
return keys.flatMap((key) => (option(parsed, key) ? [`--${key}`, option(parsed, key)] : []));
|
|
211
|
+
}
|
|
212
|
+
function report(event, details) {
|
|
213
|
+
process.stdout.write(`AMALGM_SERVICE ${JSON.stringify({ event, ...details })}\n`);
|
|
214
|
+
}
|
|
215
|
+
function helpText() {
|
|
216
|
+
return `amalgm service — keep the runtime running whenever you are logged in
|
|
217
|
+
|
|
218
|
+
Usage:
|
|
219
|
+
amalgm service install --user EMAIL [--mode auto|launchd|systemd|windows|portable]
|
|
220
|
+
amalgm service start --user EMAIL
|
|
221
|
+
amalgm service stop --user EMAIL
|
|
222
|
+
amalgm service retry --user EMAIL (resume a parked runtime)
|
|
223
|
+
amalgm service status --user EMAIL
|
|
224
|
+
amalgm service uninstall --user EMAIL
|
|
225
|
+
amalgm service keepalive --user EMAIL (what the OS runs; the foreground entrypoint in portable mode)
|
|
226
|
+
|
|
227
|
+
install registers one keepalive with the OS and starts it: a LaunchAgent on
|
|
228
|
+
macOS, a systemd user unit on Linux, a per-user Task Scheduler owner on
|
|
229
|
+
Windows. The keepalive runs "amalgm run", retries crashes with capped backoff,
|
|
230
|
+
and parks repeated failures while status and control remain available.
|
|
231
|
+
Sustained ready health resets the allowance. Start and reinstall preserve it;
|
|
232
|
+
retry explicitly grants a parked runtime a fresh allowance.
|
|
233
|
+
Options given to install (--runtime-label, --home, --amalgm-root, --app-url,
|
|
234
|
+
--branch, --proxy-url, --port) are the options the service will run with.
|
|
235
|
+
`;
|
|
236
|
+
}
|
|
237
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/service/cli.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAEtG,OAAO,EAAE,MAAM,EAAE,cAAc,EAAwB,MAAM,qBAAqB,CAAC;AACnF,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACtG,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9E,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACtF,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAExE,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EACL,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,qBAAqB,EACrB,eAAe,EACf,iBAAiB,EACjB,gBAAgB,GAIjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEpD,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC;AACjG,MAAM,YAAY,GAAuB,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;AACvF,yEAAyE;AACzE,MAAM,eAAe,GAAG,CAAC,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,CAAU,CAAC;AAEzF,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAuB,EAAE,eAA6B,MAAM;IAC9F,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IACpC,IAAI,MAAM,CAAC,OAAO,KAAK,MAAM,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QACrD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;QACjC,OAAO,CAAC,CAAC;IACX,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;QAC/B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,4BAA4B,MAAM,CAAC,OAAO,OAAO,QAAQ,EAAE,EAAE,CAAC,CAAC;QACpF,OAAO,CAAC,CAAC;IACX,CAAC;IACD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,wBAAwB,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;QAC/D,MAAM,QAAQ,GAAG,eAAe,CAAC;YAC/B,GAAG,OAAO;YACV,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;YAC5B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,SAAS;YACzC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,IAAI,SAAS;SACvD,CAAC,CAAC;QACH,IAAI,MAAM,CAAC,OAAO,KAAK,WAAW;YAAE,OAAO,MAAM,YAAY,CAAC,QAAQ,CAAC,CAAC;QACxE,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS;YAAE,OAAO,MAAM,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACzE,IAAI,MAAM,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;YAChC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,MAAM,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;YAC7E,OAAO,CAAC,CAAC;QACX,CAAC;QACD,IAAI,MAAM,CAAC,OAAO,KAAK,WAAW,EAAE,CAAC;YACnC,MAAM,SAAS,CAAC,QAAQ,CAAC,CAAC;YAC1B,MAAM,CAAC,aAAa,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;YACjD,OAAO,CAAC,CAAC;QACX,CAAC;QACD,MAAM,YAAY,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAChD,IAAI,CAAC,YAAY,IAAI,MAAM,CAAC,OAAO,KAAK,OAAO;YAAE,OAAO,MAAM,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACxF,IAAI,CAAC,YAAY;YAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,QAAQ,CAAC,KAAK,wCAAwC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;QAC1I,MAAM,KAAK,GAAG,QAAQ,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QAC7C,IAAI,MAAM,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC;YAC/B,MAAM,KAAK,GAAG,MAAM,iBAAiB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YACzD,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,SAAS,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAC,EAAE,CAAC;oBAClG,MAAM,IAAI,KAAK,CAAC,oHAAoH,CAAC,CAAC;gBACxI,CAAC;gBACD,MAAM,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBAC3B,MAAM,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;gBAC1C,MAAM,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC;gBAChE,OAAO,CAAC,CAAC;YACX,CAAC;YACD,MAAM,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;YACjE,OAAO,CAAC,CAAC;QACX,CAAC;QACD,IAAI,MAAM,CAAC,OAAO,KAAK,OAAO;YAAE,MAAM,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;;YACrE,MAAM,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAChC,MAAM,CAAC,MAAM,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC;QACrH,OAAO,CAAC,CAAC;IACX,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACpF,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC;AAED,KAAK,UAAU,OAAO,CAAC,QAAyB,EAAE,MAAuB;IACvE,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,mBAAmB,QAAQ,CAAC,UAAU,SAAS,CAAC,CAAC;IACvG,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC;IACrC,IAAI,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;IACtC,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;QACvC,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;QACxD,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;IACD,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,yEAAyE,CAAC,CAAC;IACvG,IAAI,CAAC;QAAC,OAAO,MAAM,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAAC,CAAC;YAC5C,CAAC;QAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IAAC,CAAC;AAC5B,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,QAAyB,EAAE,MAAuB;IAC5E,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,IAAI,SAAS,CAAC,CAAC;IAC1F,kBAAkB,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,IAAI,SAAS,CAAC,CAAC;IACvF,IAAI,QAAQ,GAAG,eAAe,EAAE,CAAC;IACjC,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,MAAM,EAAE;QAC9D,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,WAAW,EAAE,oBAAoB;KAClC,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,YAAY,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACjI,MAAM,SAAS,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAC9C,MAAM,aAAa,GAAG,CAAC,GAAG,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC,CAAC;IACxE,MAAM,OAAO,GAAG,CAAC,GAAG,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC;IAChJ,MAAM,QAAQ,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAC5C,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;IAChC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;IAC9F,MAAM,OAAO,GAAG,OAAO,KAAK,UAAU,IAAI,QAAQ,CAAC,OAAO,CAAC,YAAY,KAAK,OAAO,IAAI,QAAQ,CAAC,IAAI,KAAK,QAAQ;WAC5G,QAAQ,CAAC,YAAY,EAAE,UAAU,KAAK,yBAAyB,IAAI,QAAQ,CAAC,YAAY,CAAC,MAAM,KAAK,QAAQ,CAAC,OAAO,CAAC,MAAM;WAC3H,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,QAAQ,CAAC,aAAa,EAAE,MAAM,KAAK,CAAC,CAAC;IACjG,MAAM,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC,EAAE,UAAU,EAAE,QAAQ,CAAC,UAAU,EAAE,eAAe,EAAE,mBAAmB,CAAC,QAAQ,CAAC;QAC/H,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,GAAG,EAAE,QAAQ,CAAC,GAAG,EAAE,IAAI,EAAE,aAAa,EAAE,EAAE,MAAM,EAAE;YAChF,WAAW,EAAE,oBAAoB,CAAC,WAAW,GAAG,CAAC,EAAE,cAAc,EAAE,oBAAoB,CAAC,cAAc;YACtG,UAAU,EAAE,oBAAoB,CAAC,UAAU,EAAE,aAAa,EAAE,oBAAoB,CAAC,aAAa;YAC9F,cAAc,EAAE,eAAe,CAAC,mBAAmB,CAAC,EAAE,gBAAgB,EAAE,mBAAmB,CAAC,UAAU;YACtG,eAAe,EAAE,mBAAmB,CAAC,SAAS,EAAE,iBAAiB,EAAE,mBAAmB,CAAC,WAAW,EAAE,WAAW,EAAE,MAAM;SACxH,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACd,IAAI,SAAS,EAAE,CAAC;QACd,wEAAwE;QACxE,4EAA4E;QAC5E,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC;QAClE,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QACrF,IAAI,QAAQ,CAAC,IAAI,KAAK,QAAQ,IAAI,QAAQ,CAAC,YAAY,EAAE,MAAM,KAAK,QAAQ,CAAC,OAAO,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;QAC3K,QAAQ,GAAG,EAAE,IAAI,EAAE,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE,SAAS,CAAC,OAAO,CAAC,GAAG,EAAE,WAAW,EAAE,cAAc,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAC;IACzH,CAAC;IACD,IAAI,QAAQ,IAAI,QAAQ,CAAC,OAAO,KAAK,OAAO,IAAI,CAAC,CAAC,SAAS,IAAI,QAAQ,CAAC,KAAK,CAAC,SAAS,KAAK,SAAS,CAAC,GAAG,CAAC;WACrG,qBAAqB,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;QAC/E,IAAI,OAAO,KAAK,UAAU;YAAE,MAAM,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAClE,MAAM,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAClG,CAAC;SAAM,CAAC;QACN,IAAI,QAAQ,IAAI,QAAQ,CAAC,OAAO,KAAK,OAAO;YAAE,MAAM,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACnG,MAAM,YAAY,GAAiB;YACjC,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,EAAE,QAAQ,CAAC,UAAU;YAChF,OAAO;YACP,KAAK,EAAE,QAAQ,CAAC,KAAK;YACrB,YAAY,EAAE,QAAQ,CAAC,WAAW;YAClC,eAAe,EAAE,QAAQ,CAAC,cAAc;YACxC,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,GAAG,EAAE,QAAQ,CAAC,GAAG;YACjB,YAAY,EAAE,MAAM;YACpB,UAAU,EAAE,KAAK;YACjB,KAAK,EAAE,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,SAAS,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;YACvF,cAAc,EAAE,aAAa;YAC7B,QAAQ,EAAE,OAAO;YACjB,YAAY,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACvC,CAAC;QACF,iBAAiB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;QAC1C,MAAM,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,QAAQ,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,SAAS,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,QAAQ,EAC5G,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;QAC9C,MAAM,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC,KAAK,EAAE,CAAC,CAAC;IACvG,CAAC;IACD,IAAI,OAAO,KAAK,UAAU,EAAE,CAAC;QAC3B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,oFAAoF,kBAAkB,CAAC,QAAQ,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC;IAC5J,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,QAAyB;IAC7C,MAAM,YAAY,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAChD,OAAO;QACL,KAAK,EAAE,QAAQ,CAAC,KAAK;QACrB,OAAO,EAAE,YAAY,EAAE,OAAO,IAAI,IAAI;QACtC,UAAU,EAAE,YAAY,KAAK,IAAI;QACjC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC;YACvB,IAAI,EAAE,YAAY,CAAC,IAAI;YACvB,UAAU,EAAE,UAAU,CAAC,YAAY,CAAC,IAAI,CAAC;YACzC,GAAG,EAAE,YAAY,CAAC,GAAG;YACrB,SAAS,EAAE,UAAU,CAAC,YAAY,CAAC,GAAG,CAAC;YACvC,OAAO,EAAE,YAAY,CAAC,eAAe;SACtC,CAAC,CAAC,CAAC,IAAI;QACR,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,MAAM,QAAQ,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI;QAClF,SAAS,EAAE,MAAM,eAAe,CAAC,QAAQ,CAAC;QAC1C,UAAU,EAAE,QAAQ,CAAC,UAAU;KAChC,CAAC;AACJ,CAAC;AAED,6EAA6E;AAC7E,KAAK,UAAU,SAAS,CAAC,QAAyB;IAChD,MAAM,YAAY,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAChD,IAAI,YAAY;QAAE,MAAM,QAAQ,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC3E,KAAK,MAAM,OAAO,IAAI,YAAY,EAAE,CAAC;QACnC,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;QAChC,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;YAAE,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC7G,CAAC;IACD,MAAM,aAAa,CAAC,QAAQ,CAAC,CAAC;IAC9B,MAAM,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AACtD,CAAC;AAED,SAAS,iBAAiB,CAAC,QAAyB;IAClD,MAAM,IAAI,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC,IAAI,EAAE,eAAe,EAAE,QAAQ,CAAC,UAAU,EAAE,UAAU,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3I,IAAI,QAAQ,CAAC,OAAO,CAAC,YAAY;QAAE,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,QAAQ,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAC/F,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,SAAS,CAAC,MAAuB,EAAE,IAAuB;IACjE,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAC/F,CAAC;AAED,SAAS,MAAM,CAAC,KAAa,EAAE,OAA0C;IACvE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,kBAAkB,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,GAAG,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC;AACpF,CAAC;AAED,SAAS,QAAQ;IACf,OAAO;;;;;;;;;;;;;;;;;;;CAmBR,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type RuntimeBinding } from '@amalgm/core/binding';
|
|
2
|
+
import type { ServiceIdentity } from './registration.js';
|
|
3
|
+
import type { RecoveryState } from './recovery.js';
|
|
4
|
+
export interface ControllerState {
|
|
5
|
+
readonly binding: RuntimeBinding;
|
|
6
|
+
readonly user: string;
|
|
7
|
+
readonly instanceId: string;
|
|
8
|
+
readonly pid: number;
|
|
9
|
+
readonly bootstrapPid?: number | null;
|
|
10
|
+
readonly update?: unknown;
|
|
11
|
+
readonly port: number;
|
|
12
|
+
readonly token: string;
|
|
13
|
+
readonly childPid: number | null;
|
|
14
|
+
readonly restarts: number;
|
|
15
|
+
readonly phase: 'starting' | 'running' | 'backoff' | 'parked' | 'stopping';
|
|
16
|
+
readonly recovery: RecoveryState;
|
|
17
|
+
}
|
|
18
|
+
export declare const controllerStateFile: (identity: ServiceIdentity) => string;
|
|
19
|
+
export declare const controllerLeaseFile: (identity: ServiceIdentity) => string;
|
|
20
|
+
/** A recorded port/PID is an address, not proof. Authenticate the live owner. */
|
|
21
|
+
export declare function controllerRequest(identity: ServiceIdentity, action: 'status' | 'stop' | 'retry'): Promise<ControllerState | null>;
|
|
22
|
+
export declare function keepaliveStatus(identity: ServiceIdentity): Promise<{
|
|
23
|
+
alive: boolean;
|
|
24
|
+
binding: RuntimeBinding;
|
|
25
|
+
user: string;
|
|
26
|
+
instanceId: string;
|
|
27
|
+
pid: number;
|
|
28
|
+
bootstrapPid?: number | null;
|
|
29
|
+
update?: unknown;
|
|
30
|
+
port: number;
|
|
31
|
+
token: string;
|
|
32
|
+
childPid: number | null;
|
|
33
|
+
restarts: number;
|
|
34
|
+
phase: "starting" | "running" | "backoff" | "parked" | "stopping";
|
|
35
|
+
recovery: RecoveryState;
|
|
36
|
+
} | null>;
|
|
37
|
+
/** Stop only the authenticated owner. Never signal a remembered PID. */
|
|
38
|
+
export declare function stopKeepalive(identity: ServiceIdentity, timeoutMs?: number): Promise<void>;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { runtimeBindingsMatch } from '@amalgm/core/binding';
|
|
4
|
+
import { readJson } from '../filesystem.js';
|
|
5
|
+
import { processLeaseHeld } from '../installation/lease.js';
|
|
6
|
+
export const controllerStateFile = (identity) => join(identity.serviceDir, 'controller.json');
|
|
7
|
+
export const controllerLeaseFile = (identity) => join(identity.home, '.amalgm', 'owners', `service-${identity.labelScope}.sqlite`);
|
|
8
|
+
/** A recorded port/PID is an address, not proof. Authenticate the live owner. */
|
|
9
|
+
export async function controllerRequest(identity, action) {
|
|
10
|
+
const state = readJson(controllerStateFile(identity));
|
|
11
|
+
if (!state || !runtimeBindingsMatch(state.binding, identity.binding) || state.user !== identity.user
|
|
12
|
+
|| !Number.isInteger(state.port) || state.port < 1 || state.port > 65535
|
|
13
|
+
|| typeof state.token !== 'string' || state.token.length < 32 || typeof state.instanceId !== 'string')
|
|
14
|
+
return null;
|
|
15
|
+
try {
|
|
16
|
+
const response = await fetch(`http://127.0.0.1:${state.port}/${action}`, {
|
|
17
|
+
method: action === 'status' ? 'GET' : 'POST',
|
|
18
|
+
headers: { authorization: `Bearer ${state.token}`,
|
|
19
|
+
'x-amalgm-controller-identity': JSON.stringify({ instanceId: state.instanceId, user: identity.user, binding: identity.binding }) },
|
|
20
|
+
signal: AbortSignal.timeout(2_000), redirect: 'error',
|
|
21
|
+
});
|
|
22
|
+
if (!response.ok) {
|
|
23
|
+
await response.body?.cancel();
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
if (!response.body)
|
|
27
|
+
return null;
|
|
28
|
+
const chunks = [];
|
|
29
|
+
let size = 0;
|
|
30
|
+
const reader = response.body.getReader();
|
|
31
|
+
for (;;) {
|
|
32
|
+
const { value, done } = await reader.read();
|
|
33
|
+
if (done)
|
|
34
|
+
break;
|
|
35
|
+
size += value.length;
|
|
36
|
+
if (size > 16_384) {
|
|
37
|
+
await reader.cancel();
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
chunks.push(value);
|
|
41
|
+
}
|
|
42
|
+
const live = JSON.parse(Buffer.concat(chunks).toString('utf8'));
|
|
43
|
+
return live.instanceId === state.instanceId && live.user === state.user
|
|
44
|
+
&& runtimeBindingsMatch(live.binding, identity.binding) ? { ...live, token: '' } : null;
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export async function keepaliveStatus(identity) {
|
|
51
|
+
const state = await controllerRequest(identity, 'status');
|
|
52
|
+
return state ? { ...state, alive: true } : null;
|
|
53
|
+
}
|
|
54
|
+
/** Stop only the authenticated owner. Never signal a remembered PID. */
|
|
55
|
+
export async function stopKeepalive(identity, timeoutMs = 30_000) {
|
|
56
|
+
const leaseFile = controllerLeaseFile(identity);
|
|
57
|
+
if (!existsSync(leaseFile) || !processLeaseHeld(leaseFile))
|
|
58
|
+
return;
|
|
59
|
+
if (!await controllerRequest(identity, 'stop'))
|
|
60
|
+
throw new Error('The runtime controller is occupied but unavailable; ownership was not changed.');
|
|
61
|
+
const deadline = Date.now() + timeoutMs;
|
|
62
|
+
while (processLeaseHeld(leaseFile)) {
|
|
63
|
+
if (Date.now() >= deadline)
|
|
64
|
+
throw new Error('The runtime controller did not finish stopping; ownership was not changed.');
|
|
65
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=control.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"control.js","sourceRoot":"","sources":["../../src/service/control.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** OS adapters start one leased controller; it owns one independent runtime.
|
|
2
|
+
* UI shutdown never stops that controller. Status and stop authenticate the
|
|
3
|
+
* live controller; lock age and remembered PIDs never authorize takeover. */
|
|
4
|
+
export { runServiceCli } from './cli.js';
|
|
5
|
+
export { serviceIdentity, detectBackend, currentLauncher } from './registration.js';
|
|
6
|
+
export { keepaliveStatus, stopKeepalive } from './control.js';
|
|
7
|
+
export { renderLaunchdPlist } from './launchd.js';
|
|
8
|
+
export { renderSystemdUnit } from './systemd.js';
|
|
9
|
+
export { windowsControllerAction } from './windows-task.js';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** OS adapters start one leased controller; it owns one independent runtime.
|
|
2
|
+
* UI shutdown never stops that controller. Status and stop authenticate the
|
|
3
|
+
* live controller; lock age and remembered PIDs never authorize takeover. */
|
|
4
|
+
export { runServiceCli } from './cli.js';
|
|
5
|
+
export { serviceIdentity, detectBackend, currentLauncher } from './registration.js';
|
|
6
|
+
export { keepaliveStatus, stopKeepalive } from './control.js';
|
|
7
|
+
export { renderLaunchdPlist } from './launchd.js';
|
|
8
|
+
export { renderSystemdUnit } from './systemd.js';
|
|
9
|
+
export { windowsControllerAction } from './windows-task.js';
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/service/index.ts"],"names":[],"mappings":"AAAA;;6EAE6E;AAC7E,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpF,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type ChildHealthPolicy, type ChildRestartPolicy } from '@amalgm/core/supervision';
|
|
2
|
+
import { type ServiceIdentity } from './registration.js';
|
|
3
|
+
export declare const STOP_GRACE_MS = 25000;
|
|
4
|
+
export declare const LOG_LIMIT_BYTES: number;
|
|
5
|
+
interface ControllerPolicy {
|
|
6
|
+
readonly restart?: ChildRestartPolicy;
|
|
7
|
+
readonly health?: ChildHealthPolicy;
|
|
8
|
+
readonly stopGraceMs?: number;
|
|
9
|
+
}
|
|
10
|
+
/** One leased controller supervises one runtime over IPC. The optional policy
|
|
11
|
+
* lets process examinations use short clocks; the CLI always uses Core defaults. */
|
|
12
|
+
export declare function runKeepalive(identity: ServiceIdentity, policy?: ControllerPolicy): Promise<number>;
|
|
13
|
+
/** Two bounded log files; even a single oversized write obeys the limit. */
|
|
14
|
+
export declare function openRotatingLog(file: string, limitBytes: number): {
|
|
15
|
+
write(chunk: Buffer | string): void;
|
|
16
|
+
close(): void;
|
|
17
|
+
};
|
|
18
|
+
export {};
|