@agent-link/agent 0.1.294 → 0.1.296
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/adoption-lock.d.ts +14 -0
- package/dist/adoption-lock.js +54 -0
- package/dist/adoption-lock.js.map +1 -0
- package/dist/adoption.d.ts +21 -0
- package/dist/adoption.js +303 -0
- package/dist/adoption.js.map +1 -0
- package/dist/bootstrap-delegator.d.ts +7 -0
- package/dist/bootstrap-delegator.js +36 -0
- package/dist/bootstrap-delegator.js.map +1 -0
- package/dist/cli.js +86 -3
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +17 -2
- package/dist/config.js +25 -2
- package/dist/config.js.map +1 -1
- package/dist/index.js +16 -1
- package/dist/index.js.map +1 -1
- package/dist/launcher-manager.d.ts +9 -0
- package/dist/launcher-manager.js +84 -0
- package/dist/launcher-manager.js.map +1 -0
- package/dist/runtime-release.d.ts +41 -0
- package/dist/runtime-release.js +218 -0
- package/dist/runtime-release.js.map +1 -0
- package/dist/safe-tar.d.ts +11 -0
- package/dist/safe-tar.js +180 -0
- package/dist/safe-tar.js.map +1 -0
- package/dist/self-check.d.ts +14 -0
- package/dist/self-check.js +62 -0
- package/dist/self-check.js.map +1 -0
- package/dist/service.d.ts +11 -1
- package/dist/service.js +32 -4
- package/dist/service.js.map +1 -1
- package/dist/start-launch-spec.d.ts +4 -0
- package/dist/start-launch-spec.js +25 -0
- package/dist/start-launch-spec.js.map +1 -1
- package/dist/version-stager.d.ts +6 -0
- package/dist/version-stager.js +88 -0
- package/dist/version-stager.js.map +1 -0
- package/dist/version-store.d.ts +51 -0
- package/dist/version-store.js +277 -0
- package/dist/version-store.js.map +1 -0
- package/launcher/launcher.cjs +110 -0
- package/package.json +3 -2
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
interface AdoptionLockOwner {
|
|
2
|
+
schemaVersion: 1;
|
|
3
|
+
nonce: string;
|
|
4
|
+
pid: number;
|
|
5
|
+
createdAt: string;
|
|
6
|
+
}
|
|
7
|
+
export interface AdoptionLock {
|
|
8
|
+
path: string;
|
|
9
|
+
owner: AdoptionLockOwner;
|
|
10
|
+
release(): void;
|
|
11
|
+
}
|
|
12
|
+
export declare function getAdoptionLockPath(): string;
|
|
13
|
+
export declare function acquireAdoptionLock(): AdoptionLock;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { mkdirSync, readFileSync, rmSync, writeFileSync, } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { randomUUID } from 'crypto';
|
|
4
|
+
import { CONFIG_DIR } from './config.js';
|
|
5
|
+
export function getAdoptionLockPath() {
|
|
6
|
+
return join(CONFIG_DIR, 'adoption.lock');
|
|
7
|
+
}
|
|
8
|
+
export function acquireAdoptionLock() {
|
|
9
|
+
const path = getAdoptionLockPath();
|
|
10
|
+
mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });
|
|
11
|
+
try {
|
|
12
|
+
mkdirSync(path, { mode: 0o700 });
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
if (error.code === 'EEXIST') {
|
|
16
|
+
throw new Error(`Version-store adoption is already locked at ${path}; `
|
|
17
|
+
+ 'if the owning process crashed, inspect and remove the lock locally before retrying');
|
|
18
|
+
}
|
|
19
|
+
throw error;
|
|
20
|
+
}
|
|
21
|
+
const owner = {
|
|
22
|
+
schemaVersion: 1,
|
|
23
|
+
nonce: randomUUID(),
|
|
24
|
+
pid: process.pid,
|
|
25
|
+
createdAt: new Date().toISOString(),
|
|
26
|
+
};
|
|
27
|
+
try {
|
|
28
|
+
writeFileSync(join(path, 'owner.json'), JSON.stringify(owner, null, 2) + '\n', {
|
|
29
|
+
encoding: 'utf8',
|
|
30
|
+
mode: 0o600,
|
|
31
|
+
flag: 'wx',
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
rmSync(path, { recursive: true, force: true });
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
let released = false;
|
|
39
|
+
return {
|
|
40
|
+
path,
|
|
41
|
+
owner,
|
|
42
|
+
release() {
|
|
43
|
+
if (released)
|
|
44
|
+
return;
|
|
45
|
+
const current = JSON.parse(readFileSync(join(path, 'owner.json'), 'utf8'));
|
|
46
|
+
if (current.nonce !== owner.nonce || current.pid !== owner.pid) {
|
|
47
|
+
throw new Error('Version-store adoption lock ownership changed unexpectedly');
|
|
48
|
+
}
|
|
49
|
+
rmSync(path, { recursive: true, force: true });
|
|
50
|
+
released = true;
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=adoption-lock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adoption-lock.js","sourceRoot":"","sources":["../src/adoption-lock.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,YAAY,EACZ,MAAM,EACN,aAAa,GACd,MAAM,IAAI,CAAC;AACZ,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAezC,MAAM,UAAU,mBAAmB;IACjC,OAAO,IAAI,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,MAAM,IAAI,GAAG,mBAAmB,EAAE,CAAC;IACnC,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACxD,IAAI,CAAC;QACH,SAAS,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACnC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACvD,MAAM,IAAI,KAAK,CACb,+CAA+C,IAAI,IAAI;kBACrD,oFAAoF,CACvF,CAAC;QACJ,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;IACD,MAAM,KAAK,GAAsB;QAC/B,aAAa,EAAE,CAAC;QAChB,KAAK,EAAE,UAAU,EAAE;QACnB,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;IACF,IAAI,CAAC;QACH,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE;YAC7E,QAAQ,EAAE,MAAM;YAChB,IAAI,EAAE,KAAK;YACX,IAAI,EAAE,IAAI;SACX,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/C,MAAM,KAAK,CAAC;IACd,CAAC;IACD,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,OAAO;QACL,IAAI;QACJ,KAAK;QACL,OAAO;YACL,IAAI,QAAQ;gBAAE,OAAO;YACrB,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,EAAE,MAAM,CAAC,CAAsB,CAAC;YAChG,IAAI,OAAO,CAAC,KAAK,KAAK,KAAK,CAAC,KAAK,IAAI,OAAO,CAAC,GAAG,KAAK,KAAK,CAAC,GAAG,EAAE,CAAC;gBAC/D,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;YAChF,CAAC;YACD,MAAM,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YAC/C,QAAQ,GAAG,IAAI,CAAC;QAClB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type RuntimeState } from './config.js';
|
|
2
|
+
import { type RuntimeReleaseManifest } from './runtime-release.js';
|
|
3
|
+
import { type VersionPointer } from './version-store.js';
|
|
4
|
+
export interface AdoptionResult {
|
|
5
|
+
status: 'already-adopted' | 'completed';
|
|
6
|
+
selection: VersionPointer;
|
|
7
|
+
oldPid?: number;
|
|
8
|
+
newPid?: number;
|
|
9
|
+
}
|
|
10
|
+
export declare function adoptVersionStore(options: {
|
|
11
|
+
currentVersion: string;
|
|
12
|
+
manifestUrl?: string;
|
|
13
|
+
fetchImpl?: typeof fetch;
|
|
14
|
+
platform?: NodeJS.Platform;
|
|
15
|
+
arch?: string;
|
|
16
|
+
prepare?: (manifest: RuntimeReleaseManifest, manifestUrl: string) => Promise<VersionPointer>;
|
|
17
|
+
bootstrapCliPath?: string;
|
|
18
|
+
runLauncher?: (launchSpecPath: string, launcherPath: string) => void | Promise<void>;
|
|
19
|
+
restartBootstrap?: (launchSpecPath: string, bootstrapCliPath: string) => void | Promise<void>;
|
|
20
|
+
verifyReplacement?: (oldPid: number, version: string, selection: VersionPointer) => Promise<RuntimeState>;
|
|
21
|
+
}): Promise<AdoptionResult>;
|
package/dist/adoption.js
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
import { rmSync } from 'fs';
|
|
2
|
+
import { fileURLToPath } from 'url';
|
|
3
|
+
import { isProcessAlive, loadRuntimeState, saveRuntimeState, } from './config.js';
|
|
4
|
+
import { fetchRuntimeManifest, prepareRuntimeBundle, } from './runtime-release.js';
|
|
5
|
+
import { stageRuntimeBundle } from './version-stager.js';
|
|
6
|
+
import { getCurrentVersionPath, getLastKnownGoodPath, isVersionStoreAdopted, loadAdoptionState, loadCurrentVersion, loadLastKnownGood, validateVersionInstallation, writeAdoptionState, writeVersionPointer, } from './version-store.js';
|
|
7
|
+
import { getStableLauncherPath, installStableLauncher, runStableLauncher, validateStableLauncher, } from './launcher-manager.js';
|
|
8
|
+
import { captureServiceInstallation, installServiceLaunchSpec, isServiceInstalled, restartServiceAfterUpgrade, restoreServiceInstallation, stopServiceForUpgrade, } from './service.js';
|
|
9
|
+
import { loadLaunchSpec } from './launch-spec.js';
|
|
10
|
+
import { restartAgentFromLaunchSpec, snapshotUpgradeLaunchSpec, } from './upgrade-launch-spec.js';
|
|
11
|
+
import { stopAgentProcess } from './process-control.js';
|
|
12
|
+
import { getLocalControlStatus } from './local-control-client.js';
|
|
13
|
+
import { acquireAdoptionLock } from './adoption-lock.js';
|
|
14
|
+
function updateAdoption(state, phase, error) {
|
|
15
|
+
const next = {
|
|
16
|
+
...state,
|
|
17
|
+
phase,
|
|
18
|
+
updatedAt: new Date().toISOString(),
|
|
19
|
+
};
|
|
20
|
+
if (error)
|
|
21
|
+
next.error = error;
|
|
22
|
+
else
|
|
23
|
+
delete next.error;
|
|
24
|
+
writeAdoptionState(next);
|
|
25
|
+
return next;
|
|
26
|
+
}
|
|
27
|
+
async function waitForAdoptedRuntime(oldPid, version, selection, timeoutMs = 20_000) {
|
|
28
|
+
const deadline = Date.now() + timeoutMs;
|
|
29
|
+
let lastError = 'runtime state was not published';
|
|
30
|
+
while (Date.now() < deadline) {
|
|
31
|
+
const runtime = loadRuntimeState();
|
|
32
|
+
if (runtime?.pid
|
|
33
|
+
&& runtime.pid !== oldPid
|
|
34
|
+
&& isProcessAlive(runtime.pid)
|
|
35
|
+
&& runtime.controlPlane) {
|
|
36
|
+
try {
|
|
37
|
+
const status = await getLocalControlStatus(runtime, 1000);
|
|
38
|
+
if (status.pid === runtime.pid
|
|
39
|
+
&& status.version === version
|
|
40
|
+
&& status.connection.websocketConnected
|
|
41
|
+
&& status.connection.relayReady
|
|
42
|
+
&& status.connection.acceptingWork
|
|
43
|
+
&& runtime.versionStore?.active === true
|
|
44
|
+
&& runtime.versionStore.selectedVersion === version) {
|
|
45
|
+
validateVersionInstallation(selection);
|
|
46
|
+
await new Promise(resolve => setTimeout(resolve, 250));
|
|
47
|
+
const confirmed = loadRuntimeState();
|
|
48
|
+
if (confirmed?.pid !== runtime.pid || confirmed.versionStore?.selectedVersion !== version) {
|
|
49
|
+
throw new Error('Selected runtime state was not stable after health confirmation');
|
|
50
|
+
}
|
|
51
|
+
return runtime;
|
|
52
|
+
}
|
|
53
|
+
lastError = `replacement status version=${status.version}, relayReady=${status.connection.relayReady}`;
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
lastError = error.message;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
await new Promise(resolve => setTimeout(resolve, 200));
|
|
60
|
+
}
|
|
61
|
+
throw new Error(`Version-store activation did not become healthy: ${lastError}`);
|
|
62
|
+
}
|
|
63
|
+
async function waitForReplacementDiscovery(oldPid, timeoutMs = 10_000) {
|
|
64
|
+
const deadline = Date.now() + timeoutMs;
|
|
65
|
+
while (Date.now() < deadline) {
|
|
66
|
+
const runtime = loadRuntimeState();
|
|
67
|
+
if (runtime?.pid
|
|
68
|
+
&& runtime.pid !== oldPid
|
|
69
|
+
&& isProcessAlive(runtime.pid)
|
|
70
|
+
&& runtime.controlPlane) {
|
|
71
|
+
return runtime;
|
|
72
|
+
}
|
|
73
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
74
|
+
}
|
|
75
|
+
throw new Error('Replacement Agent did not publish discoverable runtime state');
|
|
76
|
+
}
|
|
77
|
+
async function waitForBootstrapRuntime(oldPid, version, timeoutMs = 20_000) {
|
|
78
|
+
const deadline = Date.now() + timeoutMs;
|
|
79
|
+
let lastError = 'bootstrap runtime state was not published';
|
|
80
|
+
while (Date.now() < deadline) {
|
|
81
|
+
const runtime = loadRuntimeState();
|
|
82
|
+
if (runtime?.pid
|
|
83
|
+
&& runtime.pid !== oldPid
|
|
84
|
+
&& isProcessAlive(runtime.pid)
|
|
85
|
+
&& runtime.controlPlane
|
|
86
|
+
&& !runtime.versionStore) {
|
|
87
|
+
try {
|
|
88
|
+
const status = await getLocalControlStatus(runtime, 1000);
|
|
89
|
+
if (status.pid === runtime.pid
|
|
90
|
+
&& status.version === version
|
|
91
|
+
&& status.connection.websocketConnected
|
|
92
|
+
&& status.connection.relayReady
|
|
93
|
+
&& status.connection.acceptingWork) {
|
|
94
|
+
await new Promise(resolve => setTimeout(resolve, 250));
|
|
95
|
+
const confirmed = loadRuntimeState();
|
|
96
|
+
if (confirmed?.pid !== runtime.pid || confirmed.versionStore) {
|
|
97
|
+
throw new Error('Bootstrap runtime state was not stable after health confirmation');
|
|
98
|
+
}
|
|
99
|
+
return runtime;
|
|
100
|
+
}
|
|
101
|
+
lastError = `bootstrap status version=${status.version}, relayReady=${status.connection.relayReady}`;
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
lastError = error.message;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
await new Promise(resolve => setTimeout(resolve, 200));
|
|
108
|
+
}
|
|
109
|
+
throw new Error(`Bootstrap rollback did not become healthy: ${lastError}`);
|
|
110
|
+
}
|
|
111
|
+
function restorePointer(path, pointer) {
|
|
112
|
+
if (pointer)
|
|
113
|
+
writeVersionPointer(path, pointer);
|
|
114
|
+
else
|
|
115
|
+
rmSync(path, { force: true });
|
|
116
|
+
}
|
|
117
|
+
async function waitForProcessExit(pid, timeoutMs = 5000) {
|
|
118
|
+
const deadline = Date.now() + timeoutMs;
|
|
119
|
+
while (Date.now() < deadline) {
|
|
120
|
+
if (!isProcessAlive(pid))
|
|
121
|
+
return true;
|
|
122
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
123
|
+
}
|
|
124
|
+
return !isProcessAlive(pid);
|
|
125
|
+
}
|
|
126
|
+
export async function adoptVersionStore(options) {
|
|
127
|
+
const lock = acquireAdoptionLock();
|
|
128
|
+
try {
|
|
129
|
+
const previousAdoption = loadAdoptionState();
|
|
130
|
+
if (isVersionStoreAdopted() && previousAdoption) {
|
|
131
|
+
return { status: 'already-adopted', selection: previousAdoption.selection };
|
|
132
|
+
}
|
|
133
|
+
const previousCurrent = loadCurrentVersion();
|
|
134
|
+
const previousLastKnownGood = loadLastKnownGood();
|
|
135
|
+
const runtime = loadRuntimeState();
|
|
136
|
+
if (!runtime?.pid || !isProcessAlive(runtime.pid)) {
|
|
137
|
+
throw new Error('Version-store adoption requires a healthy running Agent');
|
|
138
|
+
}
|
|
139
|
+
const serviceSnapshot = isServiceInstalled()
|
|
140
|
+
? captureServiceInstallation()
|
|
141
|
+
: null;
|
|
142
|
+
let oldAgentStopped = false;
|
|
143
|
+
let adoption = null;
|
|
144
|
+
let launchSpecPath = null;
|
|
145
|
+
let launchSpec = null;
|
|
146
|
+
let savedState = null;
|
|
147
|
+
let replacementRuntime = null;
|
|
148
|
+
let hostStopped = false;
|
|
149
|
+
let shutdownAccepted = false;
|
|
150
|
+
try {
|
|
151
|
+
const liveStatus = runtime.controlPlane
|
|
152
|
+
? await getLocalControlStatus(runtime, 1500)
|
|
153
|
+
: null;
|
|
154
|
+
if (liveStatus && liveStatus.version !== options.currentVersion) {
|
|
155
|
+
throw new Error(`Running Agent version ${liveStatus.version} does not match bootstrap version ${options.currentVersion}`);
|
|
156
|
+
}
|
|
157
|
+
launchSpecPath = snapshotUpgradeLaunchSpec(runtime);
|
|
158
|
+
launchSpec = loadLaunchSpec(launchSpecPath);
|
|
159
|
+
const runtimeRelease = await fetchRuntimeManifest(options.currentVersion, {
|
|
160
|
+
fetchImpl: options.fetchImpl,
|
|
161
|
+
manifestUrl: options.manifestUrl,
|
|
162
|
+
});
|
|
163
|
+
const selection = options.prepare
|
|
164
|
+
? await options.prepare(runtimeRelease.manifest, runtimeRelease.manifestUrl)
|
|
165
|
+
: stageRuntimeBundle(await prepareRuntimeBundle(runtimeRelease.manifest, {
|
|
166
|
+
fetchImpl: options.fetchImpl,
|
|
167
|
+
platform: options.platform,
|
|
168
|
+
arch: options.arch,
|
|
169
|
+
}), runtimeRelease.manifestUrl);
|
|
170
|
+
validateVersionInstallation(selection);
|
|
171
|
+
const createdAt = new Date().toISOString();
|
|
172
|
+
adoption = {
|
|
173
|
+
schemaVersion: 1,
|
|
174
|
+
version: options.currentVersion,
|
|
175
|
+
phase: 'preparing',
|
|
176
|
+
selection,
|
|
177
|
+
launchSpecPath,
|
|
178
|
+
createdAt,
|
|
179
|
+
updatedAt: createdAt,
|
|
180
|
+
};
|
|
181
|
+
writeAdoptionState(adoption);
|
|
182
|
+
installStableLauncher();
|
|
183
|
+
writeVersionPointer(getLastKnownGoodPath(), selection);
|
|
184
|
+
writeVersionPointer(getCurrentVersionPath(), selection);
|
|
185
|
+
adoption = updateAdoption(adoption, 'prepared');
|
|
186
|
+
const launcherPath = validateStableLauncher();
|
|
187
|
+
if (serviceSnapshot) {
|
|
188
|
+
installServiceLaunchSpec(launchSpec, {
|
|
189
|
+
startIfStopped: false,
|
|
190
|
+
persistPolicy: false,
|
|
191
|
+
launcherPath,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
adoption = updateAdoption(adoption, 'activating');
|
|
195
|
+
savedState = { ...runtime };
|
|
196
|
+
delete savedState.pid;
|
|
197
|
+
delete savedState.processInstanceId;
|
|
198
|
+
delete savedState.controlPlane;
|
|
199
|
+
delete savedState.versionStore;
|
|
200
|
+
const stopHost = () => {
|
|
201
|
+
if (!hostStopped)
|
|
202
|
+
hostStopped = stopServiceForUpgrade(launchSpec);
|
|
203
|
+
};
|
|
204
|
+
await stopAgentProcess(runtime, 'service', {
|
|
205
|
+
afterControlAccepted: async () => {
|
|
206
|
+
shutdownAccepted = true;
|
|
207
|
+
await stopHost();
|
|
208
|
+
},
|
|
209
|
+
beforeForceKill: stopHost,
|
|
210
|
+
});
|
|
211
|
+
oldAgentStopped = true;
|
|
212
|
+
saveRuntimeState(savedState);
|
|
213
|
+
if (!hostStopped || !restartServiceAfterUpgrade(launchSpec)) {
|
|
214
|
+
await (options.runLauncher ?? runStableLauncher)(launchSpecPath, getStableLauncherPath());
|
|
215
|
+
}
|
|
216
|
+
replacementRuntime = await waitForReplacementDiscovery(runtime.pid);
|
|
217
|
+
const replacement = await (options.verifyReplacement ?? waitForAdoptedRuntime)(runtime.pid, options.currentVersion, selection);
|
|
218
|
+
updateAdoption(adoption, 'completed');
|
|
219
|
+
return {
|
|
220
|
+
status: 'completed',
|
|
221
|
+
selection,
|
|
222
|
+
oldPid: runtime.pid,
|
|
223
|
+
newPid: replacement.pid,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
catch (error) {
|
|
227
|
+
if (adoption)
|
|
228
|
+
updateAdoption(adoption, 'failed', error.message);
|
|
229
|
+
const rollbackErrors = [];
|
|
230
|
+
const recordRollbackError = (rollback) => {
|
|
231
|
+
const next = rollback;
|
|
232
|
+
rollbackErrors.push(next.message);
|
|
233
|
+
};
|
|
234
|
+
const current = replacementRuntime ?? loadRuntimeState();
|
|
235
|
+
if (current?.pid && current.pid !== runtime.pid && isProcessAlive(current.pid)) {
|
|
236
|
+
try {
|
|
237
|
+
let replacementHostStopped = false;
|
|
238
|
+
const stopReplacementHost = () => {
|
|
239
|
+
if (!replacementHostStopped && launchSpec) {
|
|
240
|
+
replacementHostStopped = stopServiceForUpgrade(launchSpec);
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
await stopAgentProcess(current, 'service', {
|
|
244
|
+
afterControlAccepted: stopReplacementHost,
|
|
245
|
+
beforeForceKill: stopReplacementHost,
|
|
246
|
+
});
|
|
247
|
+
oldAgentStopped = true;
|
|
248
|
+
}
|
|
249
|
+
catch (stopError) {
|
|
250
|
+
recordRollbackError(stopError);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
try {
|
|
254
|
+
restorePointer(getCurrentVersionPath(), previousCurrent);
|
|
255
|
+
restorePointer(getLastKnownGoodPath(), previousLastKnownGood);
|
|
256
|
+
if (serviceSnapshot)
|
|
257
|
+
restoreServiceInstallation(serviceSnapshot);
|
|
258
|
+
}
|
|
259
|
+
catch (restoreError) {
|
|
260
|
+
recordRollbackError(restoreError);
|
|
261
|
+
}
|
|
262
|
+
if (!oldAgentStopped && shutdownAccepted) {
|
|
263
|
+
oldAgentStopped = await waitForProcessExit(runtime.pid);
|
|
264
|
+
if (!oldAgentStopped) {
|
|
265
|
+
recordRollbackError(new Error('Old Agent did not exit after accepting adoption shutdown'));
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
const active = loadRuntimeState();
|
|
269
|
+
const replacementStillAlive = !!(replacementRuntime?.pid
|
|
270
|
+
&& isProcessAlive(replacementRuntime.pid));
|
|
271
|
+
if (oldAgentStopped
|
|
272
|
+
&& !replacementStillAlive
|
|
273
|
+
&& (!active?.pid || !isProcessAlive(active.pid))) {
|
|
274
|
+
try {
|
|
275
|
+
if (savedState)
|
|
276
|
+
saveRuntimeState(savedState);
|
|
277
|
+
if (!serviceSnapshot || !launchSpec || !restartServiceAfterUpgrade(launchSpec)) {
|
|
278
|
+
await (options.restartBootstrap ?? restartAgentFromLaunchSpec)(launchSpecPath, options.bootstrapCliPath ?? fileURLToPath(new URL('./cli.js', import.meta.url)));
|
|
279
|
+
}
|
|
280
|
+
const bootstrapRuntime = await waitForBootstrapRuntime(runtime.pid, options.currentVersion);
|
|
281
|
+
// Persist the exact verified process identity last so a delayed stale
|
|
282
|
+
// runtime write from the failed replacement cannot win the rollback.
|
|
283
|
+
saveRuntimeState(bootstrapRuntime);
|
|
284
|
+
}
|
|
285
|
+
catch (restartError) {
|
|
286
|
+
recordRollbackError(restartError);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
const rollbackMessage = rollbackErrors.join('; ');
|
|
290
|
+
if (rollbackMessage && adoption) {
|
|
291
|
+
updateAdoption(adoption, 'failed', `${error.message}; bootstrap rollback failed: ${rollbackMessage}`);
|
|
292
|
+
}
|
|
293
|
+
if (rollbackMessage) {
|
|
294
|
+
throw new Error(`${error.message}; bootstrap rollback failed: ${rollbackMessage}`);
|
|
295
|
+
}
|
|
296
|
+
throw error;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
finally {
|
|
300
|
+
lock.release();
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
//# sourceMappingURL=adoption.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adoption.js","sourceRoot":"","sources":["../src/adoption.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface SelectedCli {
|
|
2
|
+
entry: string;
|
|
3
|
+
version: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function createDelegationEnvironment(selected: SelectedCli, environment?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
6
|
+
export declare function resolveSelectedCliForDelegation(currentCliPath: string, args: string[]): SelectedCli | null;
|
|
7
|
+
export declare function delegateToSelectedCli(selected: SelectedCli, args: string[]): never;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { spawnSync } from 'child_process';
|
|
2
|
+
import { resolve } from 'path';
|
|
3
|
+
import { isVersionStoreAdopted, loadCurrentVersion, validateVersionInstallation, } from './version-store.js';
|
|
4
|
+
const BOOTSTRAP_COMMANDS = new Set(['version-store']);
|
|
5
|
+
export function createDelegationEnvironment(selected, environment = process.env) {
|
|
6
|
+
return {
|
|
7
|
+
...environment,
|
|
8
|
+
AGENTLINK_VERSION_STORE_ACTIVE: '1',
|
|
9
|
+
AGENTLINK_SELECTED_VERSION: selected.version,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export function resolveSelectedCliForDelegation(currentCliPath, args) {
|
|
13
|
+
if (args[0] && BOOTSTRAP_COMMANDS.has(args[0]))
|
|
14
|
+
return null;
|
|
15
|
+
if (!isVersionStoreAdopted())
|
|
16
|
+
return null;
|
|
17
|
+
const pointer = loadCurrentVersion();
|
|
18
|
+
if (!pointer)
|
|
19
|
+
return null;
|
|
20
|
+
validateVersionInstallation(pointer);
|
|
21
|
+
const selected = resolve(pointer.entry);
|
|
22
|
+
return selected === resolve(currentCliPath)
|
|
23
|
+
? null
|
|
24
|
+
: { entry: selected, version: pointer.version };
|
|
25
|
+
}
|
|
26
|
+
export function delegateToSelectedCli(selected, args) {
|
|
27
|
+
const result = spawnSync(process.execPath, [selected.entry, ...args], {
|
|
28
|
+
stdio: 'inherit',
|
|
29
|
+
windowsHide: true,
|
|
30
|
+
env: createDelegationEnvironment(selected),
|
|
31
|
+
});
|
|
32
|
+
if (result.error)
|
|
33
|
+
throw result.error;
|
|
34
|
+
process.exit(result.status ?? 1);
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=bootstrap-delegator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bootstrap-delegator.js","sourceRoot":"","sources":["../src/bootstrap-delegator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,2BAA2B,GAC5B,MAAM,oBAAoB,CAAC;AAE5B,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC;AAOtD,MAAM,UAAU,2BAA2B,CACzC,QAAqB,EACrB,cAAiC,OAAO,CAAC,GAAG;IAE5C,OAAO;QACL,GAAG,WAAW;QACd,8BAA8B,EAAE,GAAG;QACnC,0BAA0B,EAAE,QAAQ,CAAC,OAAO;KAC7C,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,+BAA+B,CAC7C,cAAsB,EACtB,IAAc;IAEd,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC5D,IAAI,CAAC,qBAAqB,EAAE;QAAE,OAAO,IAAI,CAAC;IAC1C,MAAM,OAAO,GAAG,kBAAkB,EAAE,CAAC;IACrC,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,2BAA2B,CAAC,OAAO,CAAC,CAAC;IACrC,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACxC,OAAO,QAAQ,KAAK,OAAO,CAAC,cAAc,CAAC;QACzC,CAAC,CAAC,IAAI;QACN,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,QAAqB,EACrB,IAAc;IAEd,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,EAAE;QACpE,KAAK,EAAE,SAAS;QAChB,WAAW,EAAE,IAAI;QACjB,GAAG,EAAE,2BAA2B,CAAC,QAAQ,CAAC;KAC3C,CAAC,CAAC;IACH,IAAI,MAAM,CAAC,KAAK;QAAE,MAAM,MAAM,CAAC,KAAK,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;AACnC,CAAC"}
|
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
|
-
import { resolveConfig, loadConfig, saveConfig, getConfigPath, loadRuntimeState, saveRuntimeState, clearRuntimeState, clearRuntimePid, getLogDir, getLogDate, cleanOldLogs, killProcess, isProcessAlive, writePidFile, } from './config.js';
|
|
3
|
+
import { resolveConfig, loadConfig, saveConfig, getConfigPath, loadRuntimeState, saveRuntimeState, clearRuntimeState, clearRuntimePid, getLogDir, getLogDate, cleanOldLogs, killProcess, forceKillProcess, isProcessAlive, writePidFile, } from './config.js';
|
|
4
4
|
import { isServiceInstalled, restartServiceAfterUpgrade, serviceInstall, serviceUninstall, stopServiceForUpgrade, } from './service.js';
|
|
5
5
|
import { acquireEntraToken } from './entra.js';
|
|
6
6
|
import { assertKnownBackendType } from './backends/index.js';
|
|
@@ -14,15 +14,24 @@ import { fileURLToPath } from 'url';
|
|
|
14
14
|
import { createRequire } from 'module';
|
|
15
15
|
import { fetchEmergencyManifest, prepareEmergencyUpgrade, } from './emergency-upgrade.js';
|
|
16
16
|
import { installVerifiedPackage } from './package-installer.js';
|
|
17
|
-
import { buildLaunchSpecDaemonArgs, isFreshDaemonRuntime, loadStartLaunchSpec, } from './start-launch-spec.js';
|
|
17
|
+
import { buildLaunchSpecDaemonArgs, cleanupFailedDaemonStart, isFreshDaemonRuntime, loadStartLaunchSpec, } from './start-launch-spec.js';
|
|
18
18
|
import { restartAgentFromLaunchSpec, snapshotUpgradeLaunchSpec, } from './upgrade-launch-spec.js';
|
|
19
19
|
import { applyAutoStartPolicyAfterHealth, applyAutoStartPolicyFromRuntime, } from './auto-start.js';
|
|
20
20
|
import { getLocalControlStatus } from './local-control-client.js';
|
|
21
21
|
import { stopAgentProcess } from './process-control.js';
|
|
22
22
|
import { createUpgradeJob, updateUpgradeJob, } from './upgrade-job.js';
|
|
23
|
+
import { delegateToSelectedCli, resolveSelectedCliForDelegation, } from './bootstrap-delegator.js';
|
|
24
|
+
import { runSelfCheck } from './self-check.js';
|
|
25
|
+
import { adoptVersionStore } from './adoption.js';
|
|
26
|
+
import { isVersionStoreAdopted, loadAdoptionState, loadCurrentVersion, loadLastKnownGood, validateVersionInstallation, } from './version-store.js';
|
|
23
27
|
const require = createRequire(import.meta.url);
|
|
24
28
|
const pkg = require('../package.json');
|
|
25
29
|
const qrcode = require('qrcode-terminal');
|
|
30
|
+
const currentCliPath = fileURLToPath(import.meta.url);
|
|
31
|
+
const delegatedCli = resolveSelectedCliForDelegation(currentCliPath, process.argv.slice(2));
|
|
32
|
+
if (delegatedCli) {
|
|
33
|
+
delegateToSelectedCli(delegatedCli, process.argv.slice(2));
|
|
34
|
+
}
|
|
26
35
|
/** Highlight a URL with bold + underline ANSI codes if stdout supports color. */
|
|
27
36
|
function highlightUrl(url) {
|
|
28
37
|
if (!process.stdout.isTTY)
|
|
@@ -127,6 +136,74 @@ program
|
|
|
127
136
|
.name('agentlink-client')
|
|
128
137
|
.description('Local agent that proxies a working directory to a cloud web interface')
|
|
129
138
|
.version(pkg.version);
|
|
139
|
+
program
|
|
140
|
+
.command('self-check')
|
|
141
|
+
.description('Validate a staged Agent runtime without mutating local state')
|
|
142
|
+
.option('--expected-version <version>', 'Expected package version')
|
|
143
|
+
.option('--launch-spec <path>', 'LaunchSpec to validate')
|
|
144
|
+
.action((options) => {
|
|
145
|
+
try {
|
|
146
|
+
const result = runSelfCheck({
|
|
147
|
+
expectedVersion: options.expectedVersion,
|
|
148
|
+
launchSpecPath: options.launchSpec,
|
|
149
|
+
});
|
|
150
|
+
console.log(JSON.stringify(result));
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
console.error(`Self-check failed: ${error.message}`);
|
|
154
|
+
process.exitCode = 1;
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
const versionStoreCmd = program
|
|
158
|
+
.command('version-store')
|
|
159
|
+
.description('Manage the immutable Agent version store');
|
|
160
|
+
versionStoreCmd
|
|
161
|
+
.command('status')
|
|
162
|
+
.description('Show version-store adoption and selection status')
|
|
163
|
+
.action(() => {
|
|
164
|
+
try {
|
|
165
|
+
const adoption = loadAdoptionState();
|
|
166
|
+
const current = loadCurrentVersion();
|
|
167
|
+
const lastKnownGood = loadLastKnownGood();
|
|
168
|
+
if (current)
|
|
169
|
+
validateVersionInstallation(current);
|
|
170
|
+
if (lastKnownGood)
|
|
171
|
+
validateVersionInstallation(lastKnownGood);
|
|
172
|
+
console.log(`Adopted: ${isVersionStoreAdopted() ? 'yes' : 'no'}`);
|
|
173
|
+
console.log(`Adoption phase: ${adoption?.phase ?? '(not started)'}`);
|
|
174
|
+
console.log(`Current version: ${current?.version ?? '(none)'}`);
|
|
175
|
+
console.log(`Last known good: ${lastKnownGood?.version ?? '(none)'}`);
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
console.error(`Version store is unhealthy: ${error.message}`);
|
|
179
|
+
process.exitCode = 1;
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
versionStoreCmd
|
|
183
|
+
.command('adopt')
|
|
184
|
+
.description('Stage the current Agent into the immutable version store and activate the launcher')
|
|
185
|
+
.option('--runtime-manifest <url>', 'Loopback runtime manifest override for local simulation')
|
|
186
|
+
.action(async (options) => {
|
|
187
|
+
if (process.env.AGENTLINK_PID) {
|
|
188
|
+
console.error('ERROR: Run version-store adoption from a separate local terminal.');
|
|
189
|
+
process.exitCode = 1;
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
try {
|
|
193
|
+
const result = await adoptVersionStore({
|
|
194
|
+
currentVersion: pkg.version,
|
|
195
|
+
manifestUrl: options.runtimeManifest,
|
|
196
|
+
});
|
|
197
|
+
console.log(result.status === 'already-adopted'
|
|
198
|
+
? `Version store is already adopted at ${result.selection.version}.`
|
|
199
|
+
: `Version store adoption completed at ${result.selection.version}.`);
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
console.error(`Version-store adoption failed: ${error.message}`);
|
|
203
|
+
process.exitCode = 1;
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
versionStoreCmd.action(() => versionStoreCmd.help());
|
|
130
207
|
program
|
|
131
208
|
.command('start')
|
|
132
209
|
.description('Start the local agent and connect to cloud relay')
|
|
@@ -381,6 +458,7 @@ program
|
|
|
381
458
|
}
|
|
382
459
|
}
|
|
383
460
|
else {
|
|
461
|
+
await cleanupFailedDaemonStart(child.pid, isProcessAlive, killProcess, forceKillProcess);
|
|
384
462
|
console.error('Agent may have failed to start. Check logs:');
|
|
385
463
|
console.error(` ${errFile}`);
|
|
386
464
|
// Still write pid-file with PID so caller can clean up
|
|
@@ -419,6 +497,7 @@ program
|
|
|
419
497
|
}
|
|
420
498
|
}
|
|
421
499
|
else {
|
|
500
|
+
await cleanupFailedDaemonStart(child.pid, isProcessAlive, killProcess, forceKillProcess);
|
|
422
501
|
console.error('Agent may have failed to start. Check logs:');
|
|
423
502
|
console.error(` ${errFile}`);
|
|
424
503
|
process.exit(1);
|
|
@@ -520,7 +599,11 @@ program
|
|
|
520
599
|
}
|
|
521
600
|
else if (!agentState.pid || !isProcessAlive(agentState.pid)) {
|
|
522
601
|
console.log('Agent: not running (stale state)');
|
|
523
|
-
|
|
602
|
+
if (agentState.pid) {
|
|
603
|
+
clearRuntimePid(agentState.processInstanceId
|
|
604
|
+
? { pid: agentState.pid, processInstanceId: agentState.processInstanceId }
|
|
605
|
+
: agentState.pid);
|
|
606
|
+
}
|
|
524
607
|
}
|
|
525
608
|
else {
|
|
526
609
|
const config = loadConfig();
|