@borgee/agents-host 0.2.28 → 0.2.29
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/README.md +27 -4
- package/dist/compatibility-gates.d.ts +4 -1
- package/dist/compatibility-gates.js +39 -3
- package/dist/config.js +3 -3
- package/dist/managed-daemon.js +183 -47
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -54,6 +54,7 @@ agents-host start-managed <serverUrl> <apiKey> [agent-options]
|
|
|
54
54
|
agents-host describe-managed <serverUrl>
|
|
55
55
|
agents-host apply-managed <serverUrl> --stdin
|
|
56
56
|
agents-host apply-managed <serverUrl> --spec-json <json>
|
|
57
|
+
agents-host cleanup-managed <serverUrl> [--purge]
|
|
57
58
|
agents-host log <serverUrl> [--lines <n>] [--follow]
|
|
58
59
|
agents-host log <serverUrl> --path
|
|
59
60
|
agents-host start --config <path-to-host-config> [--debug]
|
|
@@ -77,7 +78,28 @@ RUNTIME_PROVIDER=claude \
|
|
|
77
78
|
pnpm --filter @borgee/agents-host dev
|
|
78
79
|
```
|
|
79
80
|
|
|
80
|
-
Codex
|
|
81
|
+
Codex now ships on the same default hosted-provider surface as Claude and Copilot. Select `RUNTIME_PROVIDER=codex` directly unless you are explicitly rolling that path back with `AGENTS_HOST_INTERNAL_DISABLED_COMPATIBILITY_GATES=codex-provider`.
|
|
82
|
+
|
|
83
|
+
### Shipped internal compatibility defaults and rollback controls
|
|
84
|
+
|
|
85
|
+
The current shipped internal compatibility surface resolves gates in this order:
|
|
86
|
+
|
|
87
|
+
1. start from the shipped defaults: `claude-provider-v2`, `copilot-provider-v2`, `codex-provider`, `managed-runtime-convergence`, and `policy-audit-enforcement`
|
|
88
|
+
2. add any explicit entries from `AGENTS_HOST_INTERNAL_COMPATIBILITY_GATES`
|
|
89
|
+
3. subtract any explicit entries from `AGENTS_HOST_INTERNAL_DISABLED_COMPATIBILITY_GATES`
|
|
90
|
+
|
|
91
|
+
The shipped default set now also includes `connections-state-layer`, `context-injection`, `skill-runtime`, `localhost-gateway`, `token-binding`, `collaboration-outcome-model`, `task-thread-collaboration-contract`, and `collaboration-capabilities-diagnostics`. `attention-follow-semantics`, `collaboration-skill-first`, and hosted `praestoclaw-provider` still remain opt-in.
|
|
92
|
+
|
|
93
|
+
Managed-runtime settings still preserve the managed rollback rule for `connections-state-layer` plus `token-binding`: when `managed-runtime-convergence` remains enabled, the managed surface forces that pair on; explicitly disabling `managed-runtime-convergence` removes that pair from the managed surface again unless you also explicitly re-enable them.
|
|
94
|
+
|
|
95
|
+
Managed runtime precedence stays intentional: detached daemon respawns always reuse the persisted `managed-runtime-settings.json` snapshot, bare `start-managed <serverUrl>` and `apply-managed` treat the caller's current env as an explicit request to update that managed runtime surface, and full `start-managed <serverUrl> <apiKey> ...` validates the agent upsert against the existing managed-root snapshot before ambient rollback env can reject an otherwise valid existing surface.
|
|
96
|
+
Legacy managed roots created before `managed-runtime-settings.json` existed need one bare `agents-host start-managed <serverUrl>` migration pass before full per-agent updates can rely on that snapshot-backed precedence.
|
|
97
|
+
|
|
98
|
+
Rollback and hardening controls stay explicit:
|
|
99
|
+
|
|
100
|
+
- `AGENTS_HOST_INTERNAL_DISABLED_COMPATIBILITY_GATES=<comma-list>` disables shipped gates for rollback
|
|
101
|
+
- `AGENTS_HOST_INTERNAL_PROVIDER_IMPLEMENTATIONS=claude:v1,copilot:v1` forces Claude and/or Copilot back to the v1 adapters while their v2 gates stay enabled
|
|
102
|
+
- `AGENTS_HOST_INTERNAL_POLICY_MODE=enforce` hardens the shipped `policy-audit-enforcement` gate beyond its default `audit-only` mode
|
|
81
103
|
|
|
82
104
|
Or with the CLI:
|
|
83
105
|
|
|
@@ -117,6 +139,7 @@ and resumable in that case.
|
|
|
117
139
|
Each managed runtime root keeps:
|
|
118
140
|
|
|
119
141
|
- `agents-host.yaml` and `agents/` as the stable generated local-config entrypoints
|
|
142
|
+
- `managed-runtime-settings.json` as the persisted managed runtime surface snapshot
|
|
120
143
|
- `daemon.log` as the detached managed daemon stdout/stderr log file
|
|
121
144
|
- `.state/` as the per-agent runtime state base
|
|
122
145
|
- `ctl.sock` as the local control socket
|
|
@@ -210,8 +233,8 @@ Notes:
|
|
|
210
233
|
| `BORGEE_AGENT_API_KEY` | positional `<apiKey>` | yes | — | Agent API key from the web UI |
|
|
211
234
|
| `AGENTS_HOST_DEBUG` | `--debug` | no | off | Extra host/provider lifecycle logs. Set `AGENTS_HOST_DEBUG=1` to enable without the CLI flag. |
|
|
212
235
|
| `BORGEE_AGENT_NAME` | `--name` | no | `Assistant` | Display name used in prompts |
|
|
213
|
-
| `RUNTIME_PROVIDER` | `--provider` | no | `claude` | `claude`, `copilot`, or `codex`
|
|
214
|
-
| `CLAUDE_COMMAND` / `CLAUDE_ARGS` | `--claude-command` / `--claude-args` | no | `claude` / `--print`
|
|
236
|
+
| `RUNTIME_PROVIDER` | `--provider` | no | `claude` | `claude`, `copilot`, or `codex` |
|
|
237
|
+
| `CLAUDE_COMMAND` / `CLAUDE_ARGS` | `--claude-command` / `--claude-args` | no | `claude` / `--print --permission-mode bypassPermissions` | Local Claude CLI command + args |
|
|
215
238
|
| `CODEX_COMMAND` / `CODEX_ARGS` | `--codex-command` / `--codex-args` | no | `codex-acp` / empty | Local Codex ACP adapter command + args. The default launch resolves the bundled `@agentclientprotocol/codex-acp` entrypoint. |
|
|
216
239
|
| `COPILOT_COMMAND` / `COPILOT_ARGS` | `--copilot-command` / `--copilot-args` | no | `copilot` / parsed but ignored by ACP runtime | Local Copilot CLI command. The persistent Copilot ACP prototype always launches `copilot --acp`. |
|
|
217
240
|
| `COPILOT_SESSION_TTL_MINUTES` | `--copilot-session-ttl-minutes` | no | `2880` | Idle TTL for per-channel Copilot ACP sessions |
|
|
@@ -414,7 +437,7 @@ Agent config fields:
|
|
|
414
437
|
- `key` (**required**): stable identity used for diffing and reload decisions
|
|
415
438
|
- `name` (**required**)
|
|
416
439
|
- `apiKey` (**required**)
|
|
417
|
-
- `provider` (**required**): `claude`, `copilot`, or
|
|
440
|
+
- `provider` (**required**): `claude`, `copilot`, or `codex` (roll back Codex only with `AGENTS_HOST_INTERNAL_DISABLED_COMPATIBILITY_GATES=codex-provider`)
|
|
418
441
|
- `enabled` (optional, default `true`)
|
|
419
442
|
- optional overrides for `claudeCommand`, `claudeArgs`, `codexCommand`,
|
|
420
443
|
`codexArgs`, `copilotCommand`, `copilotArgs`, and
|
|
@@ -14,6 +14,7 @@ export declare const TOKEN_BINDING_COMPATIBILITY_GATE = "token-binding";
|
|
|
14
14
|
export declare const POLICY_AUDIT_ENFORCEMENT_COMPATIBILITY_GATE = "policy-audit-enforcement";
|
|
15
15
|
export declare const MANAGED_RUNTIME_CONVERGENCE_COMPATIBILITY_GATE = "managed-runtime-convergence";
|
|
16
16
|
export declare const COMPATIBILITY_GATES_ENV = "AGENTS_HOST_INTERNAL_COMPATIBILITY_GATES";
|
|
17
|
+
export declare const INTERNAL_DISABLED_COMPATIBILITY_GATES_ENV = "AGENTS_HOST_INTERNAL_DISABLED_COMPATIBILITY_GATES";
|
|
17
18
|
export declare const INTERNAL_POLICY_MODE_ENV = "AGENTS_HOST_INTERNAL_POLICY_MODE";
|
|
18
19
|
export declare const INTERNAL_PROVIDER_IMPLEMENTATIONS_ENV = "AGENTS_HOST_INTERNAL_PROVIDER_IMPLEMENTATIONS";
|
|
19
20
|
export declare const MANAGED_RUNTIME_SETTINGS_SCHEMA_VERSION = 1;
|
|
@@ -27,8 +28,10 @@ export interface ManagedRuntimeSettingsSnapshot {
|
|
|
27
28
|
providerImplementationOverrides: string[];
|
|
28
29
|
internalPolicyMode: InternalPolicyMode;
|
|
29
30
|
}
|
|
31
|
+
export declare const DEFAULT_INTERNAL_COMPATIBILITY_GATES: readonly string[];
|
|
30
32
|
export declare function parseCompatibilityGates(rawValue: string | undefined): ReadonlySet<string>;
|
|
31
|
-
export declare function resolveInternalCompatibilityGates(): ReadonlySet<string>;
|
|
33
|
+
export declare function resolveInternalCompatibilityGates(env?: NodeJS.ProcessEnv): ReadonlySet<string>;
|
|
34
|
+
export declare function resolveDisabledDefaultCompatibilityGates(compatibilityGates: Iterable<string>): string[];
|
|
32
35
|
export declare function normalizeInternalProviderImplementationOverrides(rawValue: string | undefined): string[];
|
|
33
36
|
export declare function parseInternalProviderImplementationOverrides(rawValue: string | undefined): InternalProviderImplementationOverrides;
|
|
34
37
|
export declare function resolveManagedRuntimeProviderImplementationOverrides(env?: NodeJS.ProcessEnv, compatibilityGates?: string[]): string[];
|
|
@@ -15,10 +15,26 @@ export const TOKEN_BINDING_COMPATIBILITY_GATE = 'token-binding';
|
|
|
15
15
|
export const POLICY_AUDIT_ENFORCEMENT_COMPATIBILITY_GATE = 'policy-audit-enforcement';
|
|
16
16
|
export const MANAGED_RUNTIME_CONVERGENCE_COMPATIBILITY_GATE = 'managed-runtime-convergence';
|
|
17
17
|
export const COMPATIBILITY_GATES_ENV = 'AGENTS_HOST_INTERNAL_COMPATIBILITY_GATES';
|
|
18
|
+
export const INTERNAL_DISABLED_COMPATIBILITY_GATES_ENV = 'AGENTS_HOST_INTERNAL_DISABLED_COMPATIBILITY_GATES';
|
|
18
19
|
export const INTERNAL_POLICY_MODE_ENV = 'AGENTS_HOST_INTERNAL_POLICY_MODE';
|
|
19
20
|
export const INTERNAL_PROVIDER_IMPLEMENTATIONS_ENV = 'AGENTS_HOST_INTERNAL_PROVIDER_IMPLEMENTATIONS';
|
|
20
21
|
export const MANAGED_RUNTIME_SETTINGS_SCHEMA_VERSION = 1;
|
|
21
22
|
const VALID_PROVIDER_IMPLEMENTATION_ENTRIES = '"claude:v1", "claude:v2", "copilot:v1", or "copilot:v2"';
|
|
23
|
+
export const DEFAULT_INTERNAL_COMPATIBILITY_GATES = Object.freeze([
|
|
24
|
+
CLAUDE_PROVIDER_V2_COMPATIBILITY_GATE,
|
|
25
|
+
COLLABORATION_CAPABILITIES_DIAGNOSTICS_COMPATIBILITY_GATE,
|
|
26
|
+
COLLABORATION_OUTCOME_MODEL_COMPATIBILITY_GATE,
|
|
27
|
+
CONNECTIONS_STATE_LAYER_COMPATIBILITY_GATE,
|
|
28
|
+
CONTEXT_INJECTION_COMPATIBILITY_GATE,
|
|
29
|
+
CODEX_PROVIDER_COMPATIBILITY_GATE,
|
|
30
|
+
COPILOT_PROVIDER_V2_COMPATIBILITY_GATE,
|
|
31
|
+
LOCALHOST_GATEWAY_COMPATIBILITY_GATE,
|
|
32
|
+
MANAGED_RUNTIME_CONVERGENCE_COMPATIBILITY_GATE,
|
|
33
|
+
POLICY_AUDIT_ENFORCEMENT_COMPATIBILITY_GATE,
|
|
34
|
+
SKILL_RUNTIME_COMPATIBILITY_GATE,
|
|
35
|
+
TASK_THREAD_COLLABORATION_CONTRACT_COMPATIBILITY_GATE,
|
|
36
|
+
TOKEN_BINDING_COMPATIBILITY_GATE,
|
|
37
|
+
]);
|
|
22
38
|
const PROVIDER_IMPLEMENTATION_COMPATIBILITY_GATES = {
|
|
23
39
|
claude: CLAUDE_PROVIDER_V2_COMPATIBILITY_GATE,
|
|
24
40
|
copilot: COPILOT_PROVIDER_V2_COMPATIBILITY_GATE,
|
|
@@ -50,8 +66,19 @@ export function parseCompatibilityGates(rawValue) {
|
|
|
50
66
|
}
|
|
51
67
|
return gates;
|
|
52
68
|
}
|
|
53
|
-
export function resolveInternalCompatibilityGates() {
|
|
54
|
-
|
|
69
|
+
export function resolveInternalCompatibilityGates(env = process.env) {
|
|
70
|
+
const compatibilityGates = new Set(DEFAULT_INTERNAL_COMPATIBILITY_GATES);
|
|
71
|
+
for (const gate of parseCompatibilityGates(env[COMPATIBILITY_GATES_ENV])) {
|
|
72
|
+
compatibilityGates.add(gate);
|
|
73
|
+
}
|
|
74
|
+
for (const gate of parseCompatibilityGates(env[INTERNAL_DISABLED_COMPATIBILITY_GATES_ENV])) {
|
|
75
|
+
compatibilityGates.delete(gate);
|
|
76
|
+
}
|
|
77
|
+
return compatibilityGates;
|
|
78
|
+
}
|
|
79
|
+
export function resolveDisabledDefaultCompatibilityGates(compatibilityGates) {
|
|
80
|
+
const enabledGates = new Set(compatibilityGates);
|
|
81
|
+
return DEFAULT_INTERNAL_COMPATIBILITY_GATES.filter((gate) => !enabledGates.has(gate));
|
|
55
82
|
}
|
|
56
83
|
export function normalizeInternalProviderImplementationOverrides(rawValue) {
|
|
57
84
|
if (!rawValue || rawValue.trim().length === 0) {
|
|
@@ -95,11 +122,20 @@ export function resolveManagedRuntimeProviderImplementationOverrides(env = proce
|
|
|
95
122
|
});
|
|
96
123
|
}
|
|
97
124
|
export function resolveManagedRuntimeCompatibilityGates(env = process.env) {
|
|
98
|
-
const compatibilityGates = new Set(
|
|
125
|
+
const compatibilityGates = new Set(resolveInternalCompatibilityGates(env));
|
|
126
|
+
const explicitlyEnabledGates = parseCompatibilityGates(env[COMPATIBILITY_GATES_ENV]);
|
|
99
127
|
if (compatibilityGates.has(MANAGED_RUNTIME_CONVERGENCE_COMPATIBILITY_GATE)) {
|
|
100
128
|
compatibilityGates.add(CONNECTIONS_STATE_LAYER_COMPATIBILITY_GATE);
|
|
101
129
|
compatibilityGates.add(TOKEN_BINDING_COMPATIBILITY_GATE);
|
|
102
130
|
}
|
|
131
|
+
else {
|
|
132
|
+
if (!explicitlyEnabledGates.has(CONNECTIONS_STATE_LAYER_COMPATIBILITY_GATE)) {
|
|
133
|
+
compatibilityGates.delete(CONNECTIONS_STATE_LAYER_COMPATIBILITY_GATE);
|
|
134
|
+
}
|
|
135
|
+
if (!explicitlyEnabledGates.has(TOKEN_BINDING_COMPATIBILITY_GATE)) {
|
|
136
|
+
compatibilityGates.delete(TOKEN_BINDING_COMPATIBILITY_GATE);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
103
139
|
return sortUniqueStrings(compatibilityGates);
|
|
104
140
|
}
|
|
105
141
|
export function resolveInternalPolicyMode(gateEnabled, env = process.env) {
|
package/dist/config.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { resolveSingleAgentStateRoot } from './state-paths.js';
|
|
2
|
-
import { CODEX_PROVIDER_COMPATIBILITY_GATE,
|
|
2
|
+
import { CODEX_PROVIDER_COMPATIBILITY_GATE, resolveInternalCompatibilityGates, } from './compatibility-gates.js';
|
|
3
3
|
const MAX_TIMER_DELAY_MS = 2_147_483_647;
|
|
4
4
|
export const MAX_COPILOT_SESSION_TTL_MINUTES = MAX_TIMER_DELAY_MS / 60_000;
|
|
5
5
|
export const DEFAULT_COPILOT_SESSION_TTL_MINUTES = 2 * 24 * 60;
|
|
@@ -69,9 +69,9 @@ export function assertProviderCompatibility(provider, sourceLabel, env = process
|
|
|
69
69
|
if (provider !== 'codex') {
|
|
70
70
|
return;
|
|
71
71
|
}
|
|
72
|
-
const compatibilityGates =
|
|
72
|
+
const compatibilityGates = resolveInternalCompatibilityGates(env);
|
|
73
73
|
if (!compatibilityGates.has(CODEX_PROVIDER_COMPATIBILITY_GATE)) {
|
|
74
|
-
throw new Error(`${sourceLabel}: provider "codex" requires ${
|
|
74
|
+
throw new Error(`${sourceLabel}: provider "codex" requires the shipped ${CODEX_PROVIDER_COMPATIBILITY_GATE} path to remain enabled`);
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
export function resolveProviderCommandConfig(overrides = {}) {
|
package/dist/managed-daemon.js
CHANGED
|
@@ -5,7 +5,7 @@ import { createConnection, createServer } from 'node:net';
|
|
|
5
5
|
import { dirname, join, resolve } from 'node:path';
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
7
|
import { AgentsHostSupervisor } from './agents-host-supervisor.js';
|
|
8
|
-
import { COMPATIBILITY_GATES_ENV, createManagedRuntimeSettingsFingerprint, INTERNAL_POLICY_MODE_ENV, INTERNAL_PROVIDER_IMPLEMENTATIONS_ENV, MANAGED_RUNTIME_CONVERGENCE_COMPATIBILITY_GATE, MANAGED_RUNTIME_SETTINGS_SCHEMA_VERSION, resolveManagedRuntimeSettingsSnapshot, normalizeInternalProviderImplementationOverrides, } from './compatibility-gates.js';
|
|
8
|
+
import { COMPATIBILITY_GATES_ENV, createManagedRuntimeSettingsFingerprint, INTERNAL_DISABLED_COMPATIBILITY_GATES_ENV, INTERNAL_POLICY_MODE_ENV, INTERNAL_PROVIDER_IMPLEMENTATIONS_ENV, MANAGED_RUNTIME_CONVERGENCE_COMPATIBILITY_GATE, MANAGED_RUNTIME_SETTINGS_SCHEMA_VERSION, resolveDisabledDefaultCompatibilityGates, resolveManagedRuntimeSettingsSnapshot, normalizeInternalProviderImplementationOverrides, } from './compatibility-gates.js';
|
|
9
9
|
import { loadConfigFromEnv } from './config.js';
|
|
10
10
|
import { loadLocalConfigGenerateSpec, materializeLocalConfig, parseGenerateConfigSpec, resolveLocalConfigLayout, } from './local-config.js';
|
|
11
11
|
import { normalizeManagedRuntimeKey, resolveManagedBootstrapLockPath, resolveManagedDaemonLogPath, resolveManagedDaemonSocketPath, resolveManagedRuntimeRoot, resolveManagedRuntimeSettingsPath, } from './state-paths.js';
|
|
@@ -222,15 +222,45 @@ function buildManagedRuntimeSettingsEnv(baseEnv, snapshot) {
|
|
|
222
222
|
return {
|
|
223
223
|
...baseEnv,
|
|
224
224
|
[COMPATIBILITY_GATES_ENV]: snapshot.compatibilityGates.join(','),
|
|
225
|
+
[INTERNAL_DISABLED_COMPATIBILITY_GATES_ENV]: resolveDisabledDefaultCompatibilityGates(snapshot.compatibilityGates).join(','),
|
|
225
226
|
[INTERNAL_PROVIDER_IMPLEMENTATIONS_ENV]: snapshot.providerImplementationOverrides.join(','),
|
|
226
227
|
[INTERNAL_POLICY_MODE_ENV]: snapshot.internalPolicyMode,
|
|
227
228
|
};
|
|
228
229
|
}
|
|
229
|
-
function
|
|
230
|
-
|
|
231
|
-
|
|
230
|
+
function buildDesiredManagedRuntimeSettingsFromSnapshot(snapshot) {
|
|
231
|
+
return {
|
|
232
|
+
snapshot,
|
|
233
|
+
fingerprint: createManagedRuntimeSettingsFingerprint(snapshot),
|
|
234
|
+
convergenceEnabled: snapshot.compatibilityGates.includes(MANAGED_RUNTIME_CONVERGENCE_COMPATIBILITY_GATE),
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
async function getManagedRuntimeFingerprintMismatch(rootPath, status, desiredSettings) {
|
|
238
|
+
if (status.managedRuntimeFingerprint != null) {
|
|
239
|
+
return status.managedRuntimeFingerprint !== desiredSettings.fingerprint;
|
|
240
|
+
}
|
|
241
|
+
if (desiredSettings.convergenceEnabled) {
|
|
242
|
+
return true;
|
|
243
|
+
}
|
|
244
|
+
const persistedSettingsSnapshot = await loadManagedRuntimeSettingsSnapshot(rootPath);
|
|
245
|
+
if (!persistedSettingsSnapshot) {
|
|
246
|
+
return true;
|
|
247
|
+
}
|
|
248
|
+
return createManagedRuntimeSettingsFingerprint(persistedSettingsSnapshot) !== desiredSettings.fingerprint;
|
|
249
|
+
}
|
|
250
|
+
async function resolveAuthoritativeManagedRuntimeSettings(rootPath, effectiveProcessEnv) {
|
|
251
|
+
const persistedSettingsSnapshot = await loadManagedRuntimeSettingsSnapshot(rootPath);
|
|
252
|
+
if (!persistedSettingsSnapshot) {
|
|
253
|
+
return {
|
|
254
|
+
desiredSettings: resolveDesiredManagedRuntimeSettings(effectiveProcessEnv),
|
|
255
|
+
processEnv: effectiveProcessEnv,
|
|
256
|
+
persistedSettingsSnapshot: null,
|
|
257
|
+
};
|
|
232
258
|
}
|
|
233
|
-
return
|
|
259
|
+
return {
|
|
260
|
+
desiredSettings: buildDesiredManagedRuntimeSettingsFromSnapshot(persistedSettingsSnapshot),
|
|
261
|
+
processEnv: buildManagedRuntimeSettingsEnv(effectiveProcessEnv, persistedSettingsSnapshot),
|
|
262
|
+
persistedSettingsSnapshot,
|
|
263
|
+
};
|
|
234
264
|
}
|
|
235
265
|
function cloneLocalAgentConfig(agent) {
|
|
236
266
|
return {
|
|
@@ -311,6 +341,57 @@ export function buildManagedLocalAgentConfig(options) {
|
|
|
311
341
|
},
|
|
312
342
|
};
|
|
313
343
|
}
|
|
344
|
+
function mergeManagedLocalAgentConfig(existingAgent, generatedAgent, envOverrides) {
|
|
345
|
+
const overrides = envOverrides ?? {};
|
|
346
|
+
const hasOverride = (key) => Object.prototype.hasOwnProperty.call(overrides, key);
|
|
347
|
+
return {
|
|
348
|
+
...cloneLocalAgentConfig(existingAgent),
|
|
349
|
+
key: generatedAgent.key,
|
|
350
|
+
apiKey: generatedAgent.apiKey,
|
|
351
|
+
enabled: true,
|
|
352
|
+
name: hasOverride('BORGEE_AGENT_NAME') ? generatedAgent.name : existingAgent.name,
|
|
353
|
+
provider: hasOverride('RUNTIME_PROVIDER') ? generatedAgent.provider : existingAgent.provider,
|
|
354
|
+
claudeCommand: hasOverride('CLAUDE_COMMAND') ? generatedAgent.claudeCommand : existingAgent.claudeCommand,
|
|
355
|
+
claudeArgs: hasOverride('CLAUDE_ARGS')
|
|
356
|
+
? [...(generatedAgent.claudeArgs ?? [])]
|
|
357
|
+
: [...(existingAgent.claudeArgs ?? [])],
|
|
358
|
+
codexCommand: hasOverride('CODEX_COMMAND') ? generatedAgent.codexCommand : existingAgent.codexCommand,
|
|
359
|
+
codexArgs: hasOverride('CODEX_ARGS')
|
|
360
|
+
? [...(generatedAgent.codexArgs ?? [])]
|
|
361
|
+
: [...(existingAgent.codexArgs ?? [])],
|
|
362
|
+
copilotCommand: hasOverride('COPILOT_COMMAND')
|
|
363
|
+
? generatedAgent.copilotCommand
|
|
364
|
+
: existingAgent.copilotCommand,
|
|
365
|
+
copilotArgs: hasOverride('COPILOT_ARGS')
|
|
366
|
+
? [...(generatedAgent.copilotArgs ?? [])]
|
|
367
|
+
: [...(existingAgent.copilotArgs ?? [])],
|
|
368
|
+
copilotSessionTtlMinutes: hasOverride('COPILOT_SESSION_TTL_MINUTES')
|
|
369
|
+
? generatedAgent.copilotSessionTtlMinutes
|
|
370
|
+
: existingAgent.copilotSessionTtlMinutes,
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
function collectExplicitManagedAgentEnvOverrides(processEnv, optionEnv) {
|
|
374
|
+
const explicitOverrides = {};
|
|
375
|
+
for (const key of [
|
|
376
|
+
'BORGEE_AGENT_NAME',
|
|
377
|
+
'RUNTIME_PROVIDER',
|
|
378
|
+
'CLAUDE_COMMAND',
|
|
379
|
+
'CLAUDE_ARGS',
|
|
380
|
+
'CODEX_COMMAND',
|
|
381
|
+
'CODEX_ARGS',
|
|
382
|
+
'COPILOT_COMMAND',
|
|
383
|
+
'COPILOT_ARGS',
|
|
384
|
+
'COPILOT_SESSION_TTL_MINUTES',
|
|
385
|
+
]) {
|
|
386
|
+
if (processEnv[key] !== undefined) {
|
|
387
|
+
explicitOverrides[key] = processEnv[key];
|
|
388
|
+
}
|
|
389
|
+
if (optionEnv && Object.prototype.hasOwnProperty.call(optionEnv, key)) {
|
|
390
|
+
explicitOverrides[key] = optionEnv[key];
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
return explicitOverrides;
|
|
394
|
+
}
|
|
314
395
|
function resolveManagedRuntimeLayoutForServerUrl(serverUrl, processEnv = process.env) {
|
|
315
396
|
const rootPath = resolveManagedRuntimeRoot(serverUrl, processEnv);
|
|
316
397
|
return {
|
|
@@ -884,8 +965,6 @@ export async function bootstrapManagedDaemonStart(options, deps = {}) {
|
|
|
884
965
|
...(options.processEnv ?? process.env),
|
|
885
966
|
...options.env,
|
|
886
967
|
};
|
|
887
|
-
const loadSpec = deps.loadSpec
|
|
888
|
-
?? ((hostConfigPath) => loadLocalConfigGenerateSpec(hostConfigPath, { env: effectiveProcessEnv }));
|
|
889
968
|
const materialize = deps.materialize ?? materializeLocalConfig;
|
|
890
969
|
const sendRequest = deps.sendRequest ?? sendManagedDaemonRequest;
|
|
891
970
|
const spawnDaemonProcess = deps.spawnDaemon ?? spawnManagedDaemonProcess;
|
|
@@ -895,19 +974,51 @@ export async function bootstrapManagedDaemonStart(options, deps = {}) {
|
|
|
895
974
|
?? (async (rootPath) => {
|
|
896
975
|
await waitForManagedDaemonShutdown(rootPath, canConnectToSocket);
|
|
897
976
|
});
|
|
898
|
-
const
|
|
899
|
-
const
|
|
900
|
-
const resolved = resolvedManagedAgent ??
|
|
901
|
-
resolveManagedRuntimeLayoutForServerUrl(options.serverUrl, options.processEnv);
|
|
977
|
+
const requestedSettings = resolveDesiredManagedRuntimeSettings(effectiveProcessEnv);
|
|
978
|
+
const resolved = resolveManagedRuntimeLayoutForServerUrl(options.serverUrl, options.processEnv);
|
|
902
979
|
const releaseBootstrapLock = await acquireLock(resolved.rootPath);
|
|
903
980
|
try {
|
|
981
|
+
const currentRuntimeSettings = await resolveAuthoritativeManagedRuntimeSettings(resolved.rootPath, effectiveProcessEnv);
|
|
982
|
+
const loadManagedSpecWithCurrentRuntimeEnv = (hostConfigPath) => deps.loadSpec
|
|
983
|
+
? deps.loadSpec(hostConfigPath)
|
|
984
|
+
: loadLocalConfigGenerateSpec(hostConfigPath, {
|
|
985
|
+
env: currentRuntimeSettings.processEnv,
|
|
986
|
+
});
|
|
987
|
+
if (options.apiKey !== undefined
|
|
988
|
+
&& currentRuntimeSettings.persistedSettingsSnapshot == null
|
|
989
|
+
&& await fs.access(resolved.hostConfigPath).then(() => true).catch(() => false)) {
|
|
990
|
+
throw new Error(`Managed runtime root ${resolved.rootPath} predates managed-runtime-settings.json; run \`agents-host start-managed ${options.serverUrl}\` once to migrate it before updating an individual agent`);
|
|
991
|
+
}
|
|
992
|
+
const explicitManagedAgentOverrides = collectExplicitManagedAgentEnvOverrides(options.processEnv ?? process.env, options.env);
|
|
993
|
+
const currentManagedSpec = options.apiKey === undefined
|
|
994
|
+
? undefined
|
|
995
|
+
: await loadManagedSpecOrUndefined(resolved.hostConfigPath, loadManagedSpecWithCurrentRuntimeEnv);
|
|
996
|
+
const resolvedManagedAgent = options.apiKey === undefined
|
|
997
|
+
? null
|
|
998
|
+
: (() => {
|
|
999
|
+
const generatedManagedAgent = buildManagedLocalAgentConfig({
|
|
1000
|
+
...options,
|
|
1001
|
+
processEnv: currentRuntimeSettings.processEnv,
|
|
1002
|
+
env: options.env,
|
|
1003
|
+
});
|
|
1004
|
+
const existingAgent = currentManagedSpec?.agents.find((agent) => agent.key === generatedManagedAgent.agent.key);
|
|
1005
|
+
return existingAgent
|
|
1006
|
+
? {
|
|
1007
|
+
...generatedManagedAgent,
|
|
1008
|
+
agent: mergeManagedLocalAgentConfig(existingAgent, generatedManagedAgent.agent, explicitManagedAgentOverrides),
|
|
1009
|
+
}
|
|
1010
|
+
: generatedManagedAgent;
|
|
1011
|
+
})();
|
|
1012
|
+
const desiredBootstrapSettings = options.apiKey === undefined ? requestedSettings : currentRuntimeSettings.desiredSettings;
|
|
1013
|
+
const desiredBootstrapProcessEnv = options.apiKey === undefined ? effectiveProcessEnv : currentRuntimeSettings.processEnv;
|
|
904
1014
|
let statusResponse = await readReadyManagedDaemonStatus(resolved.rootPath, sendRequest);
|
|
905
|
-
if (statusResponse
|
|
1015
|
+
if (statusResponse
|
|
1016
|
+
&& await getManagedRuntimeFingerprintMismatch(resolved.rootPath, statusResponse, desiredBootstrapSettings)) {
|
|
906
1017
|
await recycleManagedDaemonWithDesiredSettings({
|
|
907
1018
|
rootPath: resolved.rootPath,
|
|
908
1019
|
debug: options.debug === true,
|
|
909
|
-
processEnv:
|
|
910
|
-
desiredSettings,
|
|
1020
|
+
processEnv: desiredBootstrapProcessEnv,
|
|
1021
|
+
desiredSettings: desiredBootstrapSettings,
|
|
911
1022
|
sendRequest,
|
|
912
1023
|
waitForShutdown,
|
|
913
1024
|
spawnDaemonProcess,
|
|
@@ -917,11 +1028,17 @@ export async function bootstrapManagedDaemonStart(options, deps = {}) {
|
|
|
917
1028
|
}
|
|
918
1029
|
if (!statusResponse) {
|
|
919
1030
|
if (options.apiKey === undefined) {
|
|
920
|
-
await ensurePersistedManagedAgentsExist(options.serverUrl, resolved.hostConfigPath,
|
|
1031
|
+
await ensurePersistedManagedAgentsExist(options.serverUrl, resolved.hostConfigPath, (hostConfigPath) => options.apiKey === undefined
|
|
1032
|
+
? (deps.loadSpec
|
|
1033
|
+
? deps.loadSpec(hostConfigPath)
|
|
1034
|
+
: loadLocalConfigGenerateSpec(hostConfigPath, {
|
|
1035
|
+
env: desiredBootstrapProcessEnv,
|
|
1036
|
+
}))
|
|
1037
|
+
: loadManagedSpecWithCurrentRuntimeEnv(hostConfigPath));
|
|
921
1038
|
}
|
|
922
1039
|
else {
|
|
923
1040
|
try {
|
|
924
|
-
await
|
|
1041
|
+
await loadManagedSpecWithCurrentRuntimeEnv(resolved.hostConfigPath);
|
|
925
1042
|
}
|
|
926
1043
|
catch (error) {
|
|
927
1044
|
if (isNotFoundError(error)) {
|
|
@@ -938,8 +1055,8 @@ export async function bootstrapManagedDaemonStart(options, deps = {}) {
|
|
|
938
1055
|
await startManagedDaemonWithPersistedSettings({
|
|
939
1056
|
rootPath: resolved.rootPath,
|
|
940
1057
|
debug: options.debug === true,
|
|
941
|
-
processEnv:
|
|
942
|
-
desiredSettings,
|
|
1058
|
+
processEnv: desiredBootstrapProcessEnv,
|
|
1059
|
+
desiredSettings: desiredBootstrapSettings,
|
|
943
1060
|
spawnDaemonProcess,
|
|
944
1061
|
waitForDaemon,
|
|
945
1062
|
sendRequest,
|
|
@@ -948,7 +1065,11 @@ export async function bootstrapManagedDaemonStart(options, deps = {}) {
|
|
|
948
1065
|
}
|
|
949
1066
|
if (options.apiKey === undefined) {
|
|
950
1067
|
if (!statusResponse) {
|
|
951
|
-
await ensurePersistedManagedAgentsExist(options.serverUrl, resolved.hostConfigPath, loadSpec
|
|
1068
|
+
await ensurePersistedManagedAgentsExist(options.serverUrl, resolved.hostConfigPath, (hostConfigPath) => deps.loadSpec
|
|
1069
|
+
? deps.loadSpec(hostConfigPath)
|
|
1070
|
+
: loadLocalConfigGenerateSpec(hostConfigPath, {
|
|
1071
|
+
env: desiredBootstrapProcessEnv,
|
|
1072
|
+
}));
|
|
952
1073
|
}
|
|
953
1074
|
else {
|
|
954
1075
|
assertManagedRuntimeBinding(statusResponse.borgeeBaseUrl, options.serverUrl);
|
|
@@ -1079,10 +1200,11 @@ async function terminateChildProcessAndWait(child) {
|
|
|
1079
1200
|
}
|
|
1080
1201
|
await waitForChildExit(child, DAEMON_FORCE_KILL_WAIT_MS);
|
|
1081
1202
|
}
|
|
1082
|
-
async function rollbackManagedApplyFailure(rootPath, previousSpec, materialize, clearRuntimeImpl, applyError) {
|
|
1203
|
+
async function rollbackManagedApplyFailure(rootPath, previousSpec, previousSettingsSnapshot, materialize, clearRuntimeImpl, applyError) {
|
|
1083
1204
|
const original = toManagedErrorPayload(applyError, 'MANAGED_RELOAD_FAILED');
|
|
1084
1205
|
try {
|
|
1085
1206
|
if (previousSpec) {
|
|
1207
|
+
await restoreManagedRuntimeSettingsSnapshot(rootPath, previousSettingsSnapshot);
|
|
1086
1208
|
await materialize(rootPath, cloneLocalConfigGenerateSpec(previousSpec));
|
|
1087
1209
|
}
|
|
1088
1210
|
else {
|
|
@@ -1139,8 +1261,6 @@ function validateDaemonUpsertAgentInput(currentSpec, serverUrl, agent, env = pro
|
|
|
1139
1261
|
}
|
|
1140
1262
|
export async function describeManagedSpec(options, deps = {}) {
|
|
1141
1263
|
const effectiveProcessEnv = options.processEnv ?? process.env;
|
|
1142
|
-
const loadSpec = deps.loadSpec
|
|
1143
|
-
?? ((hostConfigPath) => loadLocalConfigGenerateSpec(hostConfigPath, { env: effectiveProcessEnv }));
|
|
1144
1264
|
const sendRequest = deps.sendRequest ?? sendManagedDaemonRequest;
|
|
1145
1265
|
const resolved = resolveManagedRuntimeLayoutForServerUrl(options.serverUrl, options.processEnv);
|
|
1146
1266
|
try {
|
|
@@ -1167,7 +1287,12 @@ export async function describeManagedSpec(options, deps = {}) {
|
|
|
1167
1287
|
}
|
|
1168
1288
|
}
|
|
1169
1289
|
try {
|
|
1170
|
-
const
|
|
1290
|
+
const currentRuntimeSettings = await resolveAuthoritativeManagedRuntimeSettings(resolved.rootPath, effectiveProcessEnv);
|
|
1291
|
+
const persistedSpec = await loadManagedSpecOrUndefined(resolved.hostConfigPath, (hostConfigPath) => deps.loadSpec
|
|
1292
|
+
? deps.loadSpec(hostConfigPath)
|
|
1293
|
+
: loadLocalConfigGenerateSpec(hostConfigPath, {
|
|
1294
|
+
env: currentRuntimeSettings.processEnv,
|
|
1295
|
+
}));
|
|
1171
1296
|
if (!persistedSpec) {
|
|
1172
1297
|
return { ok: true, present: false };
|
|
1173
1298
|
}
|
|
@@ -1207,27 +1332,13 @@ async function applySpecToRunningManagedDaemon(rootPath, borgeeBaseUrl, spec, se
|
|
|
1207
1332
|
}
|
|
1208
1333
|
export async function applyManagedSpec(options, deps = {}) {
|
|
1209
1334
|
const effectiveProcessEnv = options.processEnv ?? process.env;
|
|
1210
|
-
const
|
|
1211
|
-
?? ((hostConfigPath) => loadLocalConfigGenerateSpec(hostConfigPath, { env: effectiveProcessEnv }));
|
|
1212
|
-
const materialize = deps.materialize
|
|
1213
|
-
?? ((rootPath, spec) => materializeLocalConfig(rootPath, spec, { env: effectiveProcessEnv }));
|
|
1335
|
+
const desiredSettings = resolveDesiredManagedRuntimeSettings(effectiveProcessEnv);
|
|
1214
1336
|
const sendRequest = deps.sendRequest ?? sendManagedDaemonRequest;
|
|
1215
1337
|
const spawnDaemonProcess = deps.spawnDaemon ?? spawnManagedDaemonProcess;
|
|
1216
1338
|
const waitForDaemon = deps.waitForDaemonReady ?? waitForManagedDaemonReady;
|
|
1217
1339
|
const acquireLock = deps.acquireBootstrapLock ?? acquireBootstrapLock;
|
|
1218
1340
|
const clearManagedRuntimeImpl = deps.clearManagedRuntime ?? clearManagedRuntime;
|
|
1219
1341
|
const resolved = resolveManagedRuntimeLayoutForServerUrl(options.serverUrl, options.processEnv);
|
|
1220
|
-
let spec;
|
|
1221
|
-
try {
|
|
1222
|
-
spec = validateApplyManagedInput(options.spec, options.serverUrl, effectiveProcessEnv);
|
|
1223
|
-
}
|
|
1224
|
-
catch (error) {
|
|
1225
|
-
if (isManagedOperationError(error)) {
|
|
1226
|
-
return toManagedErrorResponse(error);
|
|
1227
|
-
}
|
|
1228
|
-
return toManagedErrorResponse(managedOperationError('MANAGED_SPEC_INVALID', `Invalid managed spec: ${toErrorMessage(error)}`));
|
|
1229
|
-
}
|
|
1230
|
-
const desiredSettings = resolveDesiredManagedRuntimeSettings(effectiveProcessEnv);
|
|
1231
1342
|
const waitForShutdown = deps.waitForShutdown
|
|
1232
1343
|
?? (async (rootPath) => {
|
|
1233
1344
|
await waitForManagedDaemonShutdown(rootPath, canConnectToSocket);
|
|
@@ -1240,6 +1351,32 @@ export async function applyManagedSpec(options, deps = {}) {
|
|
|
1240
1351
|
return toApplyManagedColdStartErrorResponse(error);
|
|
1241
1352
|
}
|
|
1242
1353
|
try {
|
|
1354
|
+
const currentRuntimeSettings = await resolveAuthoritativeManagedRuntimeSettings(resolved.rootPath, effectiveProcessEnv);
|
|
1355
|
+
const loadSpecWithCurrentRuntimeEnv = (hostConfigPath) => deps.loadSpec
|
|
1356
|
+
? deps.loadSpec(hostConfigPath)
|
|
1357
|
+
: loadLocalConfigGenerateSpec(hostConfigPath, {
|
|
1358
|
+
env: currentRuntimeSettings.processEnv,
|
|
1359
|
+
});
|
|
1360
|
+
const materializeWithDesiredEnv = (rootPath, nextSpec) => deps.materialize
|
|
1361
|
+
? deps.materialize(rootPath, nextSpec)
|
|
1362
|
+
: materializeLocalConfig(rootPath, nextSpec, {
|
|
1363
|
+
env: effectiveProcessEnv,
|
|
1364
|
+
});
|
|
1365
|
+
const materializeWithCurrentRuntimeEnv = (rootPath, nextSpec) => deps.materialize
|
|
1366
|
+
? deps.materialize(rootPath, nextSpec)
|
|
1367
|
+
: materializeLocalConfig(rootPath, nextSpec, {
|
|
1368
|
+
env: currentRuntimeSettings.processEnv,
|
|
1369
|
+
});
|
|
1370
|
+
let spec;
|
|
1371
|
+
try {
|
|
1372
|
+
spec = validateApplyManagedInput(options.spec, options.serverUrl, effectiveProcessEnv);
|
|
1373
|
+
}
|
|
1374
|
+
catch (error) {
|
|
1375
|
+
if (isManagedOperationError(error)) {
|
|
1376
|
+
return toManagedErrorResponse(error);
|
|
1377
|
+
}
|
|
1378
|
+
return toManagedErrorResponse(managedOperationError('MANAGED_SPEC_INVALID', `Invalid managed spec: ${toErrorMessage(error)}`));
|
|
1379
|
+
}
|
|
1243
1380
|
let statusResponse;
|
|
1244
1381
|
try {
|
|
1245
1382
|
statusResponse = await readReadyManagedDaemonStatus(resolved.rootPath, sendRequest);
|
|
@@ -1250,7 +1387,8 @@ export async function applyManagedSpec(options, deps = {}) {
|
|
|
1250
1387
|
}
|
|
1251
1388
|
throw error;
|
|
1252
1389
|
}
|
|
1253
|
-
if (statusResponse
|
|
1390
|
+
if (statusResponse
|
|
1391
|
+
&& await getManagedRuntimeFingerprintMismatch(resolved.rootPath, statusResponse, desiredSettings)) {
|
|
1254
1392
|
try {
|
|
1255
1393
|
await recycleManagedDaemonWithDesiredSettings({
|
|
1256
1394
|
rootPath: resolved.rootPath,
|
|
@@ -1273,7 +1411,7 @@ export async function applyManagedSpec(options, deps = {}) {
|
|
|
1273
1411
|
}
|
|
1274
1412
|
let previousSpec;
|
|
1275
1413
|
try {
|
|
1276
|
-
previousSpec = await loadManagedSpecOrUndefined(resolved.hostConfigPath,
|
|
1414
|
+
previousSpec = await loadManagedSpecOrUndefined(resolved.hostConfigPath, loadSpecWithCurrentRuntimeEnv);
|
|
1277
1415
|
if (previousSpec) {
|
|
1278
1416
|
assertManagedSpecBinding(previousSpec, options.serverUrl);
|
|
1279
1417
|
}
|
|
@@ -1282,10 +1420,10 @@ export async function applyManagedSpec(options, deps = {}) {
|
|
|
1282
1420
|
return toApplyManagedColdStartErrorResponse(error);
|
|
1283
1421
|
}
|
|
1284
1422
|
try {
|
|
1285
|
-
await
|
|
1423
|
+
await materializeWithDesiredEnv(resolved.rootPath, cloneLocalConfigGenerateSpec(spec));
|
|
1286
1424
|
}
|
|
1287
1425
|
catch (error) {
|
|
1288
|
-
return rollbackManagedApplyFailure(resolved.rootPath, previousSpec,
|
|
1426
|
+
return rollbackManagedApplyFailure(resolved.rootPath, previousSpec, currentRuntimeSettings.persistedSettingsSnapshot ?? undefined, materializeWithCurrentRuntimeEnv, clearManagedRuntimeImpl, error);
|
|
1289
1427
|
}
|
|
1290
1428
|
try {
|
|
1291
1429
|
await startManagedDaemonWithPersistedSettings({
|
|
@@ -1300,7 +1438,7 @@ export async function applyManagedSpec(options, deps = {}) {
|
|
|
1300
1438
|
const status = await sendRequest(resolved.rootPath, { type: 'status' });
|
|
1301
1439
|
if (!status.ok) {
|
|
1302
1440
|
const managedError = getManagedErrorPayload(status);
|
|
1303
|
-
return rollbackManagedApplyFailure(resolved.rootPath, previousSpec,
|
|
1441
|
+
return rollbackManagedApplyFailure(resolved.rootPath, previousSpec, currentRuntimeSettings.persistedSettingsSnapshot ?? undefined, materializeWithCurrentRuntimeEnv, clearManagedRuntimeImpl, managedOperationError(managedError.code, managedError.message));
|
|
1304
1442
|
}
|
|
1305
1443
|
if (status.type !== 'status') {
|
|
1306
1444
|
throw new Error('Unexpected managed daemon response for status');
|
|
@@ -1314,7 +1452,7 @@ export async function applyManagedSpec(options, deps = {}) {
|
|
|
1314
1452
|
};
|
|
1315
1453
|
}
|
|
1316
1454
|
catch (error) {
|
|
1317
|
-
return rollbackManagedApplyFailure(resolved.rootPath, previousSpec,
|
|
1455
|
+
return rollbackManagedApplyFailure(resolved.rootPath, previousSpec, currentRuntimeSettings.persistedSettingsSnapshot ?? undefined, materializeWithCurrentRuntimeEnv, clearManagedRuntimeImpl, error);
|
|
1318
1456
|
}
|
|
1319
1457
|
}
|
|
1320
1458
|
finally {
|
|
@@ -1350,9 +1488,7 @@ export class ManagedAgentsHostDaemon {
|
|
|
1350
1488
|
this.loadSpec = deps.loadSpec ?? loadLocalConfigGenerateSpec;
|
|
1351
1489
|
this.materialize = deps.materialize ?? materializeLocalConfig;
|
|
1352
1490
|
const managedRuntimeSettings = resolveDesiredManagedRuntimeSettings(process.env);
|
|
1353
|
-
this.managedRuntimeFingerprint = managedRuntimeSettings.
|
|
1354
|
-
? managedRuntimeSettings.fingerprint
|
|
1355
|
-
: null;
|
|
1491
|
+
this.managedRuntimeFingerprint = managedRuntimeSettings.fingerprint;
|
|
1356
1492
|
this.logger = deps.logger ?? console;
|
|
1357
1493
|
this.logPath = deps.logPath ?? null;
|
|
1358
1494
|
this.server = createServer((socket) => {
|