@amalgm/shell 0.1.161 → 0.1.163
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 +98 -14
- package/README.md +16 -0
- package/dist/authorization/recovery-host.d.ts +2 -1
- package/dist/authorization/recovery-host.js +3 -15
- package/dist/authorization/recovery-host.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 +85 -73
- package/dist/cli.js.map +1 -1
- package/dist/compose.js +4 -3
- package/dist/compose.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/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 +26 -5
- package/dist/machine-host.js +192 -69
- 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 +8 -0
- package/dist/process-lifecycle.js +32 -0
- package/dist/process-lifecycle.js.map +1 -0
- 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 +196 -0
- package/dist/service/cli.js.map +1 -0
- package/dist/service/control.d.ts +29 -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 +11 -0
- package/dist/service/keepalive.js +180 -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/registration.d.ts +82 -0
- package/dist/service/registration.js +114 -0
- package/dist/service/registration.js.map +1 -0
- package/dist/service/systemd.d.ts +9 -0
- package/dist/service/systemd.js +94 -0
- package/dist/service/systemd.js.map +1 -0
- package/dist/service/windows-task.d.ts +16 -0
- package/dist/service/windows-task.js +82 -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/user-ground-host.d.ts +3 -0
- package/dist/user-ground-host.js +13 -0
- package/dist/user-ground-host.js.map +1 -1
- package/npm-shrinkwrap.json +49 -83
- package/package.json +9 -9
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { existsSync, mkdirSync, realpathSync, statSync } from 'node:fs';
|
|
3
|
+
import { basename, dirname, join, parse, resolve, sep } from 'node:path';
|
|
4
|
+
import Database from 'better-sqlite3';
|
|
5
|
+
import { acquireProcessLease } from './lease.js';
|
|
6
|
+
import { resolveRuntimeBinding, runtimeBindingsMatch, writableRootsOverlap, } from '@amalgm/core/identity';
|
|
7
|
+
/** One machine-local ownership ledger, independent of any selected lane.
|
|
8
|
+
* SQLite serializes competing processes; no polling or idle worker is needed.
|
|
9
|
+
* Root claims survive shutdown because stopped runtimes still own their data. */
|
|
10
|
+
export class InstallationOwnership {
|
|
11
|
+
database;
|
|
12
|
+
runtimeLeases = new Map();
|
|
13
|
+
leaseDirectory;
|
|
14
|
+
installationRoot;
|
|
15
|
+
binding;
|
|
16
|
+
constructor(input) {
|
|
17
|
+
this.binding = resolveRuntimeBinding(input.binding);
|
|
18
|
+
this.installationRoot = physicalPath(input.installationRoot);
|
|
19
|
+
const directory = join(input.home, '.amalgm');
|
|
20
|
+
this.leaseDirectory = join(directory, 'owners');
|
|
21
|
+
mkdirSync(directory, { recursive: true, mode: 0o700 });
|
|
22
|
+
this.database = new Database(join(directory, 'installation-ownership.sqlite'));
|
|
23
|
+
this.database.pragma('busy_timeout = 5000');
|
|
24
|
+
this.database.exec(`
|
|
25
|
+
CREATE TABLE IF NOT EXISTS writable_roots (
|
|
26
|
+
path TEXT PRIMARY KEY, installation TEXT NOT NULL, binding TEXT NOT NULL,
|
|
27
|
+
user_scope TEXT NOT NULL, physical TEXT NOT NULL
|
|
28
|
+
);
|
|
29
|
+
`);
|
|
30
|
+
try {
|
|
31
|
+
this.reserve(this.installationRoot);
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
this.database.close();
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** Reserve before registration, materialization, Watch or another writer.
|
|
39
|
+
* Empty scope reserves the installation container, not a user's workspace. */
|
|
40
|
+
reserve(requestedPath, userScope = '') {
|
|
41
|
+
const path = physicalPath(requestedPath);
|
|
42
|
+
const physical = physicalComponents(path);
|
|
43
|
+
const binding = JSON.stringify(this.binding);
|
|
44
|
+
this.database.transaction(() => {
|
|
45
|
+
const claims = this.database.prepare('SELECT * FROM writable_roots').all();
|
|
46
|
+
for (const claim of claims) {
|
|
47
|
+
const previous = physicalComponents(claim.path);
|
|
48
|
+
const recorded = JSON.parse(claim.physical);
|
|
49
|
+
const overlaps = writableRootsOverlap(pathComponents(path), pathComponents(claim.path))
|
|
50
|
+
|| writableRootsOverlap(physical, previous)
|
|
51
|
+
|| writableRootsOverlap(physical, recorded)
|
|
52
|
+
|| (recorded.at(-1).startsWith('inode:') && physical.includes(recorded.at(-1)))
|
|
53
|
+
|| (physical.at(-1).startsWith('inode:') && recorded.includes(physical.at(-1)));
|
|
54
|
+
if (!overlaps)
|
|
55
|
+
continue;
|
|
56
|
+
const sameInstallation = claim.installation === this.installationRoot
|
|
57
|
+
&& runtimeBindingsMatch(JSON.parse(claim.binding), this.binding);
|
|
58
|
+
const sameUser = !claim.user_scope || !userScope || claim.user_scope === userScope;
|
|
59
|
+
if (!sameInstallation || !sameUser) {
|
|
60
|
+
throw Object.assign(new Error(`Writable root ${path} overlaps ${claim.path}, owned by another Amalgm installation or user. Use a separate checkout.`), {
|
|
61
|
+
code: 'installation_root_conflict',
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const existing = this.database.prepare('SELECT * FROM writable_roots WHERE path = ?').get(path);
|
|
66
|
+
if (!existing) {
|
|
67
|
+
this.database.prepare('INSERT INTO writable_roots VALUES (?, ?, ?, ?, ?)')
|
|
68
|
+
.run(path, this.installationRoot, binding, userScope, JSON.stringify(physical));
|
|
69
|
+
}
|
|
70
|
+
}).immediate();
|
|
71
|
+
return path;
|
|
72
|
+
}
|
|
73
|
+
/** Serialize initialization with other claimants before creating a manifest. */
|
|
74
|
+
initialize(effect) {
|
|
75
|
+
return this.database.transaction(effect).immediate();
|
|
76
|
+
}
|
|
77
|
+
/** An OS-held SQLite write lock is the lease: process exit releases it,
|
|
78
|
+
* suspension does not, and PID reuse cannot either steal or strand it. */
|
|
79
|
+
acquireRuntime(userScope) {
|
|
80
|
+
if (!userScope)
|
|
81
|
+
throw new Error('Runtime ownership requires a user scope.');
|
|
82
|
+
if (this.runtimeLeases.has(userScope))
|
|
83
|
+
return;
|
|
84
|
+
const scope = createHash('sha256').update(JSON.stringify([this.binding, userScope])).digest('hex');
|
|
85
|
+
const lease = acquireProcessLease(join(this.leaseDirectory, `${scope}.sqlite`));
|
|
86
|
+
if (!lease)
|
|
87
|
+
throw Object.assign(new Error(`Amalgm already has a runtime owner for ${userScope} in this environment. Bind to that runtime.`), {
|
|
88
|
+
code: 'runtime_already_owned',
|
|
89
|
+
});
|
|
90
|
+
this.runtimeLeases.set(userScope, lease);
|
|
91
|
+
}
|
|
92
|
+
releaseRuntime(userScope) {
|
|
93
|
+
const lease = this.runtimeLeases.get(userScope);
|
|
94
|
+
if (!lease)
|
|
95
|
+
return;
|
|
96
|
+
lease.close();
|
|
97
|
+
this.runtimeLeases.delete(userScope);
|
|
98
|
+
}
|
|
99
|
+
/** Contention is bounded setup work, never an idle ownership-recovery poll. */
|
|
100
|
+
async waitForRuntime(userScope, timeoutMs = 600_000) {
|
|
101
|
+
const deadline = Date.now() + timeoutMs;
|
|
102
|
+
for (;;) {
|
|
103
|
+
try {
|
|
104
|
+
this.acquireRuntime(userScope);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
if (error.code !== 'runtime_already_owned' || Date.now() >= deadline)
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
111
|
+
await new Promise((done) => setTimeout(done, 250));
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
close() {
|
|
115
|
+
for (const scope of this.runtimeLeases.keys())
|
|
116
|
+
this.releaseRuntime(scope);
|
|
117
|
+
if (this.database.open)
|
|
118
|
+
this.database.close();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/** Resolve existing symlink ancestors even before a new destination exists. */
|
|
122
|
+
export function physicalPath(requestedPath) {
|
|
123
|
+
let ancestor = resolve(requestedPath);
|
|
124
|
+
const absent = [];
|
|
125
|
+
while (!existsSync(ancestor)) {
|
|
126
|
+
const parent = dirname(ancestor);
|
|
127
|
+
if (parent === ancestor)
|
|
128
|
+
throw new Error(`Cannot resolve physical root ${requestedPath}`);
|
|
129
|
+
absent.unshift(basename(ancestor));
|
|
130
|
+
ancestor = parent;
|
|
131
|
+
}
|
|
132
|
+
return join(realpathSync.native(ancestor), ...absent);
|
|
133
|
+
}
|
|
134
|
+
function physicalComponents(path) {
|
|
135
|
+
const root = parse(path).root;
|
|
136
|
+
const components = [root, ...path.slice(root.length).split(sep).filter(Boolean)];
|
|
137
|
+
let current = root;
|
|
138
|
+
return components.map((component, index) => {
|
|
139
|
+
if (index > 0)
|
|
140
|
+
current = join(current, component);
|
|
141
|
+
try {
|
|
142
|
+
const info = statSync(current);
|
|
143
|
+
return `inode:${info.dev}:${info.ino}:${info.birthtimeMs}`;
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
if (error.code !== 'ENOENT')
|
|
147
|
+
throw error;
|
|
148
|
+
return `name:${process.platform === 'win32' ? component.toLowerCase() : component}`;
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
function pathComponents(path) {
|
|
153
|
+
const absolute = process.platform === 'win32' ? path.toLowerCase() : path;
|
|
154
|
+
return [parse(absolute).root, ...absolute.slice(parse(absolute).root.length).split(sep).filter(Boolean)];
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=ownership.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ownership.js","sourceRoot":"","sources":["../../src/installation/ownership.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type RuntimeBinding, type RuntimeLabel } from '@amalgm/core/identity';
|
|
2
|
+
import type { ParsedArguments } from '../cli-arguments.js';
|
|
3
|
+
/** Public command prefixes select the environment, never ambient env vars. */
|
|
4
|
+
export declare function selectRuntimeInvocation(args: readonly string[]): {
|
|
5
|
+
runtimeLabel: RuntimeLabel;
|
|
6
|
+
args: readonly string[];
|
|
7
|
+
};
|
|
8
|
+
export declare function resolveInvocationBinding(runtimeLabel: RuntimeLabel, parsed: ParsedArguments): RuntimeBinding;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { resolveRuntimeBinding } from '@amalgm/core/identity';
|
|
2
|
+
/** Public command prefixes select the environment, never ambient env vars. */
|
|
3
|
+
export function selectRuntimeInvocation(args) {
|
|
4
|
+
if (args[0] === 'preview')
|
|
5
|
+
return { runtimeLabel: 'preview', args: args.slice(1) };
|
|
6
|
+
if (args[0] === 'dev')
|
|
7
|
+
return { runtimeLabel: 'local', args: args.slice(1) };
|
|
8
|
+
return { runtimeLabel: 'main', args };
|
|
9
|
+
}
|
|
10
|
+
export function resolveInvocationBinding(runtimeLabel, parsed) {
|
|
11
|
+
const explicitLabel = stringOption(parsed, 'runtime-label');
|
|
12
|
+
if (explicitLabel !== undefined && explicitLabel !== runtimeLabel) {
|
|
13
|
+
throw new Error('The runtime label conflicts with the command prefix. Use amalgm preview … or amalgm dev … to select that environment.');
|
|
14
|
+
}
|
|
15
|
+
return resolveRuntimeBinding({
|
|
16
|
+
runtimeLabel,
|
|
17
|
+
branch: stringOption(parsed, 'branch'),
|
|
18
|
+
localSession: stringOption(parsed, 'local-session'),
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
function stringOption(parsed, name) {
|
|
22
|
+
const value = parsed.options[name];
|
|
23
|
+
if (value === undefined)
|
|
24
|
+
return undefined;
|
|
25
|
+
if (typeof value !== 'string' || value.length === 0)
|
|
26
|
+
throw new Error(`--${name} requires a value.`);
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=selection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selection.js","sourceRoot":"","sources":["../../src/installation/selection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAA0C,MAAM,uBAAuB,CAAC;AAGtG,8EAA8E;AAC9E,MAAM,UAAU,uBAAuB,CAAC,IAAuB;IAC7D,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,SAAS;QAAE,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IACnF,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,KAAK;QAAE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7E,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,YAA0B,EAAE,MAAuB;IAC1F,MAAM,aAAa,GAAG,YAAY,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC5D,IAAI,aAAa,KAAK,SAAS,IAAI,aAAa,KAAK,YAAY,EAAE,CAAC;QAClE,MAAM,IAAI,KAAK,CAAC,uHAAuH,CAAC,CAAC;IAC3I,CAAC;IACD,OAAO,qBAAqB,CAAC;QAC3B,YAAY;QACZ,MAAM,EAAE,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC;QACtC,YAAY,EAAE,YAAY,CAAC,MAAM,EAAE,eAAe,CAAC;KACpD,CAAC,CAAC;AACL,CAAC;AAED,SAAS,YAAY,CAAC,MAAuB,EAAE,IAAY;IACzD,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,KAAK,IAAI,oBAAoB,CAAC,CAAC;IACpG,OAAO,KAAK,CAAC;AACf,CAAC"}
|
package/dist/machine-host.d.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import type { ChannelsCommands } from "@amalgm/channels";
|
|
2
2
|
import type { ChatRuntimePort } from "@amalgm/chat";
|
|
3
|
-
import { type JoinMachineInput, type MachineSetupPorts, type ReadyMachine } from "@amalgm/core/identity";
|
|
4
|
-
import {
|
|
3
|
+
import { type JoinMachineInput, type MachineSetupPorts, type ReadyMachine, type RuntimeBinding } from "@amalgm/core/identity";
|
|
4
|
+
import type { FilesAddResult } from "@amalgm/live/files";
|
|
5
5
|
import { type FilesStageObserver } from "./files-observability.js";
|
|
6
6
|
import type { EntityApplyStageEvidence } from "./entity-apply-host.js";
|
|
7
7
|
import { type DeviceKeyStore } from "./authorization/index.js";
|
|
8
8
|
import { type AuthorizationKeyRecoveryResult } from "./authorization/recovery-host.js";
|
|
9
|
-
import {
|
|
9
|
+
import type { PlatformProductHostOptions } from "./platform-product-host.js";
|
|
10
10
|
import { type RuntimeCommandConnection } from "./runtime-command-host.js";
|
|
11
|
-
import { UserGroundHost,
|
|
11
|
+
import type { UserGroundHost, DetectScanEvidence, UserGroundCloseOptions, WorkspaceAddStage } from "./user-ground-host.js";
|
|
12
12
|
import type { OpenNativeWatch, WatchCoverageEvidence, WatchHealth } from "./watching/index.js";
|
|
13
13
|
export interface MachineHostOptions {
|
|
14
14
|
readonly homedir?: string;
|
|
@@ -19,7 +19,11 @@ export interface MachineHostOptions {
|
|
|
19
19
|
readonly runtimeVersion: string;
|
|
20
20
|
readonly runtimeLabel?: string;
|
|
21
21
|
readonly branch?: string;
|
|
22
|
+
readonly localSession?: string;
|
|
23
|
+
/** Explicit local availability; managed installations retain their release selection. */
|
|
24
|
+
readonly services?: readonly string[];
|
|
22
25
|
readonly proxyUrl?: string;
|
|
26
|
+
readonly wireUrl?: string;
|
|
23
27
|
/** Hosted product endpoints. Omit in isolated hosts that do not compose them. */
|
|
24
28
|
readonly platformProducts?: Omit<PlatformProductHostOptions, 'authorization'>;
|
|
25
29
|
/** Test/adapter seam; production defaults to the OS-backed device key store. */
|
|
@@ -63,6 +67,7 @@ interface MachinePaths {
|
|
|
63
67
|
readonly status: string;
|
|
64
68
|
}
|
|
65
69
|
export interface MachineStatus {
|
|
70
|
+
readonly binding: RuntimeBinding;
|
|
66
71
|
readonly user: string;
|
|
67
72
|
readonly deviceId: string | null;
|
|
68
73
|
readonly registration: "absent" | "incomplete" | "ready";
|
|
@@ -74,6 +79,14 @@ export interface MachineStatus {
|
|
|
74
79
|
readonly machineDir: string | null;
|
|
75
80
|
readonly database: string | null;
|
|
76
81
|
}
|
|
82
|
+
type HostJoinInput = Omit<JoinMachineInput, 'appUrl' | 'platform' | 'appVersion' | 'runtimeLabel' | 'branch' | 'localSession'>;
|
|
83
|
+
export interface MachineSetupResult {
|
|
84
|
+
readonly disposition: 'enrolled' | 'adopted';
|
|
85
|
+
readonly userEmail: string;
|
|
86
|
+
readonly userId: string;
|
|
87
|
+
readonly computerId: string;
|
|
88
|
+
readonly deviceId: string;
|
|
89
|
+
}
|
|
77
90
|
/** The production effects around Core's machine-setup operation. It does not
|
|
78
91
|
* decide ordering, readiness, or installation selection; those remain Core. */
|
|
79
92
|
export declare class MachineHost {
|
|
@@ -82,13 +95,19 @@ export declare class MachineHost {
|
|
|
82
95
|
readonly amalgmRoot: string;
|
|
83
96
|
readonly deviceFile: string;
|
|
84
97
|
readonly ports: MachineSetupPorts;
|
|
98
|
+
readonly binding: RuntimeBinding;
|
|
99
|
+
private readonly ownership;
|
|
85
100
|
private selectedUserEmail;
|
|
86
101
|
private groundHost;
|
|
87
102
|
private running;
|
|
88
103
|
private readonly stages;
|
|
89
104
|
constructor(options: MachineHostOptions);
|
|
90
|
-
|
|
105
|
+
private approveSetup;
|
|
106
|
+
join(input: HostJoinInput): Promise<ReadyMachine>;
|
|
107
|
+
/** Shared, finite UI setup. An existing owner is never disturbed by adoption. */
|
|
108
|
+
setup(input: HostJoinInput): Promise<MachineSetupResult>;
|
|
91
109
|
resume(): Promise<ReadyMachine>;
|
|
110
|
+
assertRuntimeCanStart(): void;
|
|
92
111
|
recoverAuthorizationKey(input?: Readonly<{
|
|
93
112
|
setupCode?: string;
|
|
94
113
|
}>): Promise<AuthorizationKeyRecoveryResult>;
|
|
@@ -116,6 +135,7 @@ export declare class MachineHost {
|
|
|
116
135
|
* loopback MCP route. Shell alone reads the local admission capability. */
|
|
117
136
|
channelsCommands(): ChannelsCommands;
|
|
118
137
|
close(options?: UserGroundCloseOptions): Promise<void>;
|
|
138
|
+
private drainRuntime;
|
|
119
139
|
private ensureInstallationRoot;
|
|
120
140
|
private openChannelsCommands;
|
|
121
141
|
private runtimeCommandAddress;
|
|
@@ -124,6 +144,7 @@ export declare class MachineHost {
|
|
|
124
144
|
private paths;
|
|
125
145
|
private requireSelectedUser;
|
|
126
146
|
private resolveUserForResume;
|
|
147
|
+
private assertRecordBinding;
|
|
127
148
|
private loadMachine;
|
|
128
149
|
private saveMachine;
|
|
129
150
|
private startRuntime;
|