@agent-link/agent 0.1.291 → 0.1.293
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +137 -25
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +9 -0
- package/dist/config.js +25 -3
- package/dist/config.js.map +1 -1
- package/dist/connection.d.ts +12 -0
- package/dist/connection.js +69 -1
- package/dist/connection.js.map +1 -1
- package/dist/encryption.d.ts +4 -0
- package/dist/encryption.js +13 -0
- package/dist/encryption.js.map +1 -1
- package/dist/index.js +54 -10
- package/dist/index.js.map +1 -1
- package/dist/local-control-client.d.ts +15 -0
- package/dist/local-control-client.js +100 -0
- package/dist/local-control-client.js.map +1 -0
- package/dist/local-control-http.d.ts +7 -0
- package/dist/local-control-http.js +208 -0
- package/dist/local-control-http.js.map +1 -0
- package/dist/local-control.d.ts +74 -0
- package/dist/local-control.js +55 -0
- package/dist/local-control.js.map +1 -0
- package/dist/process-control.d.ts +17 -0
- package/dist/process-control.js +48 -0
- package/dist/process-control.js.map +1 -0
- package/dist/shutdown-coordinator.d.ts +19 -0
- package/dist/shutdown-coordinator.js +67 -0
- package/dist/shutdown-coordinator.js.map +1 -0
- package/dist/upgrade-job.d.ts +25 -0
- package/dist/upgrade-job.js +59 -0
- package/dist/upgrade-job.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-control.js","sourceRoot":"","sources":["../src/local-control.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC;AAC3C,MAAM,CAAC,MAAM,0BAA0B,GAAG;IACxC,aAAa;IACb,aAAa;IACb,oBAAoB;CACZ,CAAC;AAuDX,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAExB;IACA;IAFlB,YACkB,MAAc,EACd,IAAY,EAC5B,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;QAJC,WAAM,GAAN,MAAM,CAAQ;QACd,SAAI,GAAJ,IAAI,CAAQ;QAI5B,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF;AAiBD,MAAM,UAAU,yBAAyB,CAAC,IAA6B;IACrE,OAAO;QACL,MAAM;YACJ,OAAO;gBACL,MAAM,EAAE,IAAI;gBACZ,UAAU,EAAE,yBAAyB;gBACrC,YAAY,EAAE,0BAA0B;aACzC,CAAC;QACJ,CAAC;QAED,MAAM;YACJ,OAAO;gBACL,UAAU,EAAE,yBAAyB;gBACrC,YAAY,EAAE,0BAA0B;gBACxC,GAAG,EAAE,OAAO,CAAC,GAAG;gBAChB,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,aAAa,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;gBACxD,QAAQ,EAAE,IAAI,CAAC,iBAAiB,EAAE;gBAClC,UAAU,EAAE,IAAI,CAAC,mBAAmB,EAAE;gBACtC,MAAM,EAAE;oBACN,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM;oBAC1B,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG;oBACpB,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI;oBACtB,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,QAAQ;oBACpC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI;oBACjC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,IAAI;oBACxC,kBAAkB,EAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC;iBAClD;aACF,CAAC;QACJ,CAAC;QAED,QAAQ,CAAC,OAAO;YACd,IAAI,OAAO,CAAC,WAAW,KAAK,SAAS,IAAI,OAAO,CAAC,WAAW,KAAK,OAAO,CAAC,GAAG,EAAE,CAAC;gBAC7E,MAAM,IAAI,iBAAiB,CACzB,GAAG,EACH,cAAc,EACd,gCAAgC,OAAO,CAAC,WAAW,sBAAsB,OAAO,CAAC,GAAG,EAAE,CACvF,CAAC;YACJ,CAAC;YACD,OAAO,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;QACvC,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type RuntimeState } from './config.js';
|
|
2
|
+
import type { ShutdownReason } from './local-control.js';
|
|
3
|
+
export type StopMode = 'control-plane' | 'legacy-force-kill' | 'control-timeout-force-kill';
|
|
4
|
+
export interface StopAgentOptions {
|
|
5
|
+
controlTimeoutMs?: number;
|
|
6
|
+
exitTimeoutMs?: number;
|
|
7
|
+
afterControlAccepted?: () => void | Promise<void>;
|
|
8
|
+
beforeForceKill?: () => void | Promise<void>;
|
|
9
|
+
isAlive?: (pid: number) => boolean;
|
|
10
|
+
forceKill?: (pid: number) => boolean;
|
|
11
|
+
sleep?: (milliseconds: number) => Promise<void>;
|
|
12
|
+
shutdownMetadata?: {
|
|
13
|
+
jobId?: string;
|
|
14
|
+
targetVersion?: string;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export declare function stopAgentProcess(state: RuntimeState, reason: ShutdownReason, options?: StopAgentOptions): Promise<StopMode>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { isProcessAlive, killProcess, } from './config.js';
|
|
2
|
+
import { LocalControlUnavailableError, requestLocalControlShutdown, } from './local-control-client.js';
|
|
3
|
+
async function waitForExit(pid, timeoutMs, isAlive, sleep) {
|
|
4
|
+
const deadline = Date.now() + timeoutMs;
|
|
5
|
+
while (Date.now() < deadline) {
|
|
6
|
+
if (!isAlive(pid))
|
|
7
|
+
return true;
|
|
8
|
+
await sleep(Math.min(100, Math.max(1, deadline - Date.now())));
|
|
9
|
+
}
|
|
10
|
+
return !isAlive(pid);
|
|
11
|
+
}
|
|
12
|
+
export async function stopAgentProcess(state, reason, options = {}) {
|
|
13
|
+
if (!state.pid) {
|
|
14
|
+
throw new Error('Runtime state does not contain a PID');
|
|
15
|
+
}
|
|
16
|
+
const isAlive = options.isAlive ?? isProcessAlive;
|
|
17
|
+
const forceKill = options.forceKill ?? killProcess;
|
|
18
|
+
const sleep = options.sleep ?? ((milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)));
|
|
19
|
+
const exitTimeoutMs = options.exitTimeoutMs ?? 5000;
|
|
20
|
+
let controlAccepted = false;
|
|
21
|
+
if (state.controlPlane) {
|
|
22
|
+
try {
|
|
23
|
+
await requestLocalControlShutdown(state, reason, options.shutdownMetadata, options.controlTimeoutMs);
|
|
24
|
+
controlAccepted = true;
|
|
25
|
+
await options.afterControlAccepted?.();
|
|
26
|
+
if (await waitForExit(state.pid, exitTimeoutMs, isAlive, sleep)) {
|
|
27
|
+
return 'control-plane';
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
if (!(error instanceof LocalControlUnavailableError)) {
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
await options.beforeForceKill?.();
|
|
37
|
+
if (!isAlive(state.pid)) {
|
|
38
|
+
return controlAccepted ? 'control-plane' : 'legacy-force-kill';
|
|
39
|
+
}
|
|
40
|
+
if (!forceKill(state.pid)) {
|
|
41
|
+
throw new Error(`Failed to stop agent process ${state.pid}`);
|
|
42
|
+
}
|
|
43
|
+
if (!await waitForExit(state.pid, exitTimeoutMs, isAlive, sleep)) {
|
|
44
|
+
throw new Error(`Agent process ${state.pid} did not exit after force kill`);
|
|
45
|
+
}
|
|
46
|
+
return controlAccepted ? 'control-timeout-force-kill' : 'legacy-force-kill';
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=process-control.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-control.js","sourceRoot":"","sources":["../src/process-control.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type LocalControlStatus, type ShutdownAccepted, type ShutdownRequest } from './local-control.js';
|
|
2
|
+
export interface ShutdownStep {
|
|
3
|
+
name: string;
|
|
4
|
+
run: (request: ShutdownRequest) => void | Promise<void>;
|
|
5
|
+
}
|
|
6
|
+
export interface ShutdownCoordinatorDeps {
|
|
7
|
+
markShuttingDown: (request: ShutdownRequest) => void;
|
|
8
|
+
steps: ShutdownStep[];
|
|
9
|
+
exit: (code: number) => void;
|
|
10
|
+
schedule?: (run: () => void) => void;
|
|
11
|
+
now?: () => Date;
|
|
12
|
+
log?: Pick<Console, 'log' | 'error'>;
|
|
13
|
+
}
|
|
14
|
+
export interface ShutdownCoordinator {
|
|
15
|
+
request(request: ShutdownRequest): ShutdownAccepted;
|
|
16
|
+
status(): LocalControlStatus['shutdown'];
|
|
17
|
+
completion(): Promise<void> | null;
|
|
18
|
+
}
|
|
19
|
+
export declare function createShutdownCoordinator(deps: ShutdownCoordinatorDeps): ShutdownCoordinator;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { LocalControlError } from './local-control.js';
|
|
2
|
+
export function createShutdownCoordinator(deps) {
|
|
3
|
+
const accepted = new Map();
|
|
4
|
+
const schedule = deps.schedule ?? ((run) => setImmediate(run));
|
|
5
|
+
const now = deps.now ?? (() => new Date());
|
|
6
|
+
const log = deps.log ?? console;
|
|
7
|
+
let activeRequest = null;
|
|
8
|
+
let phase = 'idle';
|
|
9
|
+
let completionPromise = null;
|
|
10
|
+
async function execute(request) {
|
|
11
|
+
phase = 'shutting-down';
|
|
12
|
+
let failed = false;
|
|
13
|
+
for (const step of deps.steps) {
|
|
14
|
+
try {
|
|
15
|
+
await step.run(request);
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
failed = true;
|
|
19
|
+
log.error(`[Control] Shutdown step "${step.name}" failed:`, error);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
phase = failed ? 'failed' : 'completed';
|
|
23
|
+
log.log(`[Control] Shutdown ${phase} (requestId=${request.requestId}, reason=${request.reason})`);
|
|
24
|
+
// Lifecycle shutdown is intentional. A nonzero exit would make systemd or
|
|
25
|
+
// launchd immediately restart an agent the user explicitly stopped.
|
|
26
|
+
deps.exit(0);
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
request(request) {
|
|
30
|
+
const duplicate = accepted.get(request.requestId);
|
|
31
|
+
if (duplicate) {
|
|
32
|
+
if (duplicate.reason !== request.reason) {
|
|
33
|
+
throw new LocalControlError(409, 'IDEMPOTENCY_CONFLICT', 'The requestId was already used for a different shutdown reason');
|
|
34
|
+
}
|
|
35
|
+
return { ...duplicate, phase };
|
|
36
|
+
}
|
|
37
|
+
if (activeRequest) {
|
|
38
|
+
throw new LocalControlError(409, 'SHUTDOWN_IN_PROGRESS', `Agent shutdown is already in progress (requestId=${activeRequest.requestId})`);
|
|
39
|
+
}
|
|
40
|
+
activeRequest = { ...request };
|
|
41
|
+
phase = 'accepted';
|
|
42
|
+
deps.markShuttingDown(request);
|
|
43
|
+
const result = {
|
|
44
|
+
requestId: request.requestId,
|
|
45
|
+
reason: request.reason,
|
|
46
|
+
acceptedAt: now().toISOString(),
|
|
47
|
+
phase,
|
|
48
|
+
};
|
|
49
|
+
accepted.set(request.requestId, result);
|
|
50
|
+
schedule(() => {
|
|
51
|
+
completionPromise = execute(request);
|
|
52
|
+
});
|
|
53
|
+
return result;
|
|
54
|
+
},
|
|
55
|
+
status() {
|
|
56
|
+
return {
|
|
57
|
+
phase,
|
|
58
|
+
requestId: activeRequest?.requestId,
|
|
59
|
+
reason: activeRequest?.reason,
|
|
60
|
+
};
|
|
61
|
+
},
|
|
62
|
+
completion() {
|
|
63
|
+
return completionPromise;
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=shutdown-coordinator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shutdown-coordinator.js","sourceRoot":"","sources":["../src/shutdown-coordinator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ReleaseChannel } from './emergency-upgrade.js';
|
|
2
|
+
export type UpgradeJobPhase = 'prepared' | 'stopping' | 'installing' | 'restarting' | 'completed' | 'failed';
|
|
3
|
+
export interface UpgradeJob {
|
|
4
|
+
schemaVersion: 1;
|
|
5
|
+
jobId: string;
|
|
6
|
+
sourceVersion: string;
|
|
7
|
+
targetVersion: string;
|
|
8
|
+
channel: ReleaseChannel;
|
|
9
|
+
phase: UpgradeJobPhase;
|
|
10
|
+
createdAt: string;
|
|
11
|
+
updatedAt: string;
|
|
12
|
+
launchSpecPath?: string;
|
|
13
|
+
error?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function createUpgradeJob(input: {
|
|
16
|
+
sourceVersion: string;
|
|
17
|
+
targetVersion: string;
|
|
18
|
+
channel: ReleaseChannel;
|
|
19
|
+
launchSpecPath?: string;
|
|
20
|
+
now?: Date;
|
|
21
|
+
}): UpgradeJob;
|
|
22
|
+
export declare function updateUpgradeJob(jobId: string, phase: UpgradeJobPhase, options?: {
|
|
23
|
+
error?: string;
|
|
24
|
+
now?: Date;
|
|
25
|
+
}): UpgradeJob;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { chmodSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { randomUUID } from 'crypto';
|
|
4
|
+
import { CONFIG_DIR } from './config.js';
|
|
5
|
+
const UPGRADE_DIR = join(CONFIG_DIR, 'upgrades');
|
|
6
|
+
function jobPath(jobId) {
|
|
7
|
+
if (!/^[a-zA-Z0-9-]{1,128}$/.test(jobId)) {
|
|
8
|
+
throw new Error(`Invalid upgrade job ID: ${jobId}`);
|
|
9
|
+
}
|
|
10
|
+
return join(UPGRADE_DIR, `${jobId}.json`);
|
|
11
|
+
}
|
|
12
|
+
function writeJob(path, job) {
|
|
13
|
+
mkdirSync(UPGRADE_DIR, { recursive: true });
|
|
14
|
+
const temporaryPath = `${path}.${process.pid}.${randomUUID()}.tmp`;
|
|
15
|
+
writeFileSync(temporaryPath, JSON.stringify(job, null, 2) + '\n', {
|
|
16
|
+
encoding: 'utf8',
|
|
17
|
+
mode: 0o600,
|
|
18
|
+
});
|
|
19
|
+
renameSync(temporaryPath, path);
|
|
20
|
+
if (process.platform !== 'win32')
|
|
21
|
+
chmodSync(path, 0o600);
|
|
22
|
+
}
|
|
23
|
+
export function createUpgradeJob(input) {
|
|
24
|
+
const timestamp = (input.now ?? new Date()).toISOString();
|
|
25
|
+
const job = {
|
|
26
|
+
schemaVersion: 1,
|
|
27
|
+
jobId: randomUUID(),
|
|
28
|
+
sourceVersion: input.sourceVersion,
|
|
29
|
+
targetVersion: input.targetVersion,
|
|
30
|
+
channel: input.channel,
|
|
31
|
+
phase: 'prepared',
|
|
32
|
+
createdAt: timestamp,
|
|
33
|
+
updatedAt: timestamp,
|
|
34
|
+
launchSpecPath: input.launchSpecPath,
|
|
35
|
+
};
|
|
36
|
+
writeJob(jobPath(job.jobId), job);
|
|
37
|
+
writeJob(join(UPGRADE_DIR, 'latest.json'), job);
|
|
38
|
+
return job;
|
|
39
|
+
}
|
|
40
|
+
export function updateUpgradeJob(jobId, phase, options = {}) {
|
|
41
|
+
const path = jobPath(jobId);
|
|
42
|
+
const existing = JSON.parse(readFileSync(path, 'utf8'));
|
|
43
|
+
if (existing.schemaVersion !== 1 || existing.jobId !== jobId) {
|
|
44
|
+
throw new Error(`Invalid upgrade job file: ${path}`);
|
|
45
|
+
}
|
|
46
|
+
const updated = {
|
|
47
|
+
...existing,
|
|
48
|
+
phase,
|
|
49
|
+
updatedAt: (options.now ?? new Date()).toISOString(),
|
|
50
|
+
};
|
|
51
|
+
if (options.error !== undefined)
|
|
52
|
+
updated.error = options.error;
|
|
53
|
+
else
|
|
54
|
+
delete updated.error;
|
|
55
|
+
writeJob(path, updated);
|
|
56
|
+
writeJob(join(UPGRADE_DIR, 'latest.json'), updated);
|
|
57
|
+
return updated;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=upgrade-job.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upgrade-job.js","sourceRoot":"","sources":["../src/upgrade-job.ts"],"names":[],"mappings":"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"}
|