@hivemagnus/magnus-agent 1.1.2 → 1.1.4

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.
@@ -1,6 +1,23 @@
1
- import { type AgentSelfUpgradeStatus, type AgentUpgradeRequest } from '@hivemagnus/magnus-contracts';
1
+ import { type AgentSelfUpgradeStatus, type AgentUpgradeReport, type AgentUpgradeRequest } from '@hivemagnus/magnus-contracts';
2
2
  export declare const STATE_FILE = "upgrade-state.json";
3
+ export declare const LOCK_FILE = "upgrade-state.lock";
4
+ /** Written while on trial when heartbeats cannot reach the control API; the launcher then extends the trial. */
5
+ export declare const ALIVE_FILE = "trial-alive.json";
3
6
  export declare const AGENT_PACKAGE = "@hivemagnus/magnus-agent";
7
+ /** The launcher protocol this agent needs. Kept equal to `magnusAgent.minLauncher` in package.json. */
8
+ export declare const MIN_LAUNCHER_PROTOCOL = 1;
9
+ /** Oldest npm the upgrade steps are tested with (overrides, `audit signatures`). */
10
+ export declare const MIN_NPM_VERSION = "10.0.0";
11
+ /** Per-step limits and the total budget; the server waits 15 minutes for an upgrade. */
12
+ export declare const STEP_TIMEOUT_MS: {
13
+ readonly pack: number;
14
+ readonly install: number;
15
+ readonly audit: number;
16
+ readonly smoke: 60000;
17
+ };
18
+ export declare const STAGE_BUDGET_MS: number;
19
+ /** After staging, the agent exits even if a graceful shutdown hangs. */
20
+ export declare const EXIT_BACKSTOP_MS = 60000;
4
21
  export interface UpgradeState {
5
22
  state: 'idle' | 'staged' | 'trial' | 'confirmed' | 'reverted' | 'failed';
6
23
  from: string | null;
@@ -9,6 +26,7 @@ export interface UpgradeState {
9
26
  attempt?: number;
10
27
  maxAttempts?: number;
11
28
  trialDeadline?: string;
29
+ extended?: number;
12
30
  reason?: string | null;
13
31
  updatedAt?: string;
14
32
  }
@@ -20,51 +38,108 @@ export declare function readUpgradeState(dir: string): UpgradeState | null;
20
38
  * the owner can still replace or remove it. Otherwise this does nothing.
21
39
  */
22
40
  export declare function adoptInstallOwner(dir: string, path: string, uid?: number | undefined): void;
41
+ /** Temp file, fsync, rename, fsync the directory: a crash leaves the old or the new content, never a torn file. */
42
+ export declare function writeDurable(dir: string, name: string, text: string, mode?: number): void;
23
43
  export declare function writeUpgradeState(dir: string, state: UpgradeState): void;
44
+ /** Atomically point `<dir>/<name>` (current, last-good) at versions/<version>. */
45
+ export declare function pointLink(dir: string, name: string, version: string): void;
24
46
  export declare function pointCurrentAt(dir: string, version: string): void;
47
+ /** The X of a `<name> -> versions/X` link, or null. */
48
+ export declare function linkVersion(dir: string, name: string): string | null;
49
+ /** versions/<version> holds a runnable agent. */
50
+ export declare function versionComplete(dir: string, version: string | null | undefined): boolean;
51
+ /** ./current resolves to versions/<version>. */
52
+ export declare function runsVersion(dir: string, version: string): boolean;
53
+ /** O_EXCL lock shared with the launcher around a read-modify-write of the state file. Synchronous; waits up to timeoutMs. */
54
+ export declare function withStateLock<T>(dir: string, fn: () => T, { timeoutMs, staleMs }?: {
55
+ timeoutMs?: number | undefined;
56
+ staleMs?: number | undefined;
57
+ }): T;
25
58
  export type Layout = AgentSelfUpgradeStatus['layout'];
26
59
  export declare function detectLayout(dir: string, env?: NodeJS.ProcessEnv): Layout;
60
+ export interface NpmCommand {
61
+ command: string;
62
+ args: string[];
63
+ /** Prepended to PATH so npm and lifecycle scripts run the agent's own Node.js. */
64
+ pathPrefix: string;
65
+ version: string | null;
66
+ problem: string | null;
67
+ }
68
+ /**
69
+ * The npm that belongs to the running Node.js (npm-cli.js beside it, run with
70
+ * process.execPath), then MAGNUS_AGENT_NPM, then npm on PATH. A systemd PATH
71
+ * often lacks the directory of a version-managed Node.js.
72
+ */
73
+ export declare function resolveNpm(env?: NodeJS.ProcessEnv, execPath?: string): NpmCommand;
27
74
  /** Whether this agent can upgrade itself, and why not. Reported with every heartbeat. */
28
75
  export declare function selfUpgradeStatus(version: string, env?: NodeJS.ProcessEnv): AgentSelfUpgradeStatus;
76
+ /** The upgrade state when `version` is the one on trial. */
77
+ export declare function trialOf(version: string, env?: NodeJS.ProcessEnv): UpgradeState | null;
78
+ /** Tell the launcher this version runs but cannot reach the control API, so it extends the trial instead of reverting. */
79
+ export declare function recordTrialAlive(version: string, error: string, env?: NodeJS.ProcessEnv, now?: number): boolean;
80
+ /** A failed heartbeat POST that says nothing about this version: no answer, or a gateway with no upstream. */
81
+ export declare function controlApiUnreachable(error: unknown): boolean;
82
+ /** `export const LAUNCHER_PROTOCOL = N` in a launcher file, without running it. */
83
+ export declare function declaredLauncherProtocol(path: string): number | null;
29
84
  /**
30
- * Called after every accepted heartbeat: the first one from a version on trial
31
- * confirms it, and versions other than the previous and the current one are pruned.
85
+ * Replace launcher/launcher.mjs with the confirmed version's copy when that
86
+ * declares a higher protocol and passes a self-check (`--protocol`). The
87
+ * running launcher keeps its loaded code; the new one is used from the next
88
+ * service start. The previous file is kept as launcher.mjs.previous.
89
+ */
90
+ export declare function upgradeLauncher(dir: string, version: string, execPath?: string): string | null;
91
+ /**
92
+ * Called after every accepted heartbeat: the first one from a version on
93
+ * trial confirms it (unless the trial window has closed or ./current no
94
+ * longer runs it), records it as last-good, and prunes other versions.
32
95
  */
33
96
  export declare function confirmTrial(version: string, env?: NodeJS.ProcessEnv, now?: Date): boolean;
34
97
  export declare function pruneVersions(dir: string, keep: ReadonlyArray<string | null>): void;
35
98
  export declare class SelfUpgradeError extends Error {
36
99
  readonly code: string;
37
- readonly status: 400 | 409 | 422 | 500;
38
- constructor(code: string, message: string, status?: 400 | 409 | 422 | 500);
100
+ readonly status: 400 | 409 | 422 | 500 | 504;
101
+ constructor(code: string, message: string, status?: 400 | 409 | 422 | 500 | 504);
102
+ }
103
+ export interface RunResult {
104
+ code: number;
105
+ stdout: string;
106
+ stderr: string;
107
+ timedOut?: boolean;
39
108
  }
40
109
  export interface Runner {
41
110
  (command: string, args: readonly string[], options: {
42
111
  cwd: string;
43
112
  env: NodeJS.ProcessEnv;
44
- }): Promise<{
45
- code: number;
46
- stdout: string;
47
- stderr: string;
48
- }>;
113
+ timeoutMs?: number;
114
+ }): Promise<RunResult>;
49
115
  }
116
+ /** Runs a command in its own process group; at timeoutMs the whole group gets SIGTERM, then SIGKILL. */
50
117
  export declare const runProcess: Runner;
51
118
  /** npm pack names files `<scope>-<name>-<version>.tgz`. */
52
119
  export declare function tarballName(version: string): string;
53
120
  export declare function sha512Integrity(file: string): string;
54
121
  /** Other @hivemagnus tarballs in the source directory, used instead of the registry (offline nodes). */
55
122
  export declare function sourceOverrides(sourceDir: string, agentTarball: string): Record<string, string>;
123
+ /** Why `engines.node` rules out `nodeVersion`, or null. Range forms satisfiesRange cannot judge are not refused. */
124
+ export declare function engineProblem(range: string | undefined, nodeVersion: string): string | null;
56
125
  export interface StageOptions {
57
126
  request: AgentUpgradeRequest;
58
127
  version: string;
59
128
  env?: NodeJS.ProcessEnv;
60
129
  run?: Runner;
61
130
  now?: Date;
131
+ /** Monotonic-enough milliseconds for the step budget (tests). */
132
+ clock?: () => number;
133
+ nodeVersion?: string;
62
134
  }
63
135
  export interface StageResult {
64
136
  from: string;
65
137
  to: string;
66
138
  integrity: string;
67
139
  requestId: string;
140
+ /** The same request was already handled: nothing was changed, `upgrade` is the current state. */
141
+ repeated?: boolean;
142
+ upgrade?: AgentUpgradeReport;
68
143
  }
69
144
  /** Download, verify, install and switch. The caller exits afterwards so the launcher starts the new version. */
70
145
  export declare function stageUpgrade(options: StageOptions): Promise<StageResult>;