@borgee/agents-host 0.2.73 → 0.2.84
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 +17 -30
- package/dist/agents-host-supervisor.d.ts +1 -0
- package/dist/agents-host-supervisor.js +3 -1
- package/dist/agents-host.d.ts +6 -4
- package/dist/agents-host.js +117 -16
- package/dist/background-runs.d.ts +23 -0
- package/dist/background-runs.js +153 -0
- package/dist/chat/chat-control-plane.d.ts +6 -1
- package/dist/chat/sdk-chat-control-plane.d.ts +4 -2
- package/dist/chat/sdk-chat-control-plane.js +7 -0
- package/dist/context/claude-file-brief.js +3 -3
- package/dist/context/injection.d.ts +18 -12
- package/dist/context/injection.js +53 -53
- package/dist/context/prompt.js +10 -10
- package/dist/context/resolved-working-folder.d.ts +3 -0
- package/dist/context/resolved-working-folder.js +106 -0
- package/dist/context/turn-preparation.js +1 -1
- package/dist/local-config.d.ts +7 -0
- package/dist/local-config.js +158 -12
- package/dist/managed-daemon.js +42 -35
- package/dist/plugin-sdk.js +179 -9
- package/dist/plugin-sdk.js.map +3 -3
- package/dist/policy/authorization-audit.d.ts +1 -1
- package/dist/policy/copilot-permission.d.ts +9 -0
- package/dist/policy/copilot-permission.js +120 -1
- package/dist/progress-to-activity.d.ts +1 -1
- package/dist/progress-to-activity.js +1 -0
- package/dist/providers/claude/adapter.d.ts +1 -1
- package/dist/providers/claude/adapter.js +7 -0
- package/dist/providers/claude/cli-client.js +4 -3
- package/dist/providers/codex/adapter.d.ts +1 -1
- package/dist/providers/codex/adapter.js +7 -0
- package/dist/providers/codex/cli-client.js +8 -7
- package/dist/providers/codex/project-doc.js +6 -6
- package/dist/providers/copilot/adapter.d.ts +6 -2
- package/dist/providers/copilot/adapter.js +27 -1
- package/dist/providers/copilot/cli-client.d.ts +37 -10
- package/dist/providers/copilot/cli-client.js +751 -122
- package/dist/providers/copilot/sdk-session.d.ts +149 -0
- package/dist/providers/copilot/sdk-session.js +981 -0
- package/dist/providers/create-provider.js +33 -0
- package/dist/providers/provider-adapter.d.ts +16 -1
- package/dist/providers/provider-adapter.js +13 -0
- package/dist/types.d.ts +32 -11
- package/package.json +3 -2
- package/skills/borgee-agent/references/task-properties.md +3 -3
- package/skills/borgee-agent/scripts/borgee-agent.mjs +1 -1
- package/skills/borgee-agent/scripts/borgee-agent.py +1 -1
- package/dist/context/resolved-workspace.d.ts +0 -3
- package/dist/context/resolved-workspace.js +0 -106
package/dist/context/prompt.js
CHANGED
|
@@ -4,7 +4,7 @@ import { buildAttentionSummaryLines } from './attention.js';
|
|
|
4
4
|
import { buildCollaborationCapabilityDeclarationSummaryLines, buildMissedCollaborationDiagnosticSummaryLines, } from './collaboration-capabilities-diagnostics.js';
|
|
5
5
|
import { buildCollaborationOutcomeSummaryLines } from './collaboration-outcome.js';
|
|
6
6
|
import { MAIN_SESSION_DELEGATION_LINES } from './main-session-delegation.js';
|
|
7
|
-
import {
|
|
7
|
+
import { buildResolvedWorkingFolderGuidanceLines } from './resolved-working-folder.js';
|
|
8
8
|
import { buildSkillManualLines, buildSkillManualReadLine } from './skill-manual.js';
|
|
9
9
|
import { PARENT_CHANNEL_TASK_BOUNDARY_LINES } from './task-channel-boundary.js';
|
|
10
10
|
import { buildTaskThreadCollaborationSummaryLines } from './task-thread-collaboration.js';
|
|
@@ -101,8 +101,8 @@ function buildTaskAssignmentPromptLines(params) {
|
|
|
101
101
|
'This thread is continuing an existing task assignment.',
|
|
102
102
|
'Keep the main work in this thread.',
|
|
103
103
|
];
|
|
104
|
-
if ((params.provider !== 'claude' || params.forceInlineForClaude === true) && params.promptContext?.
|
|
105
|
-
lines.push(...
|
|
104
|
+
if ((params.provider !== 'claude' || params.forceInlineForClaude === true) && params.promptContext?.resolvedWorkingFolder) {
|
|
105
|
+
lines.push(...buildResolvedWorkingFolderPromptLines(params.provider, params.promptContext));
|
|
106
106
|
}
|
|
107
107
|
if ((params.provider !== 'claude' || params.forceInlineForClaude === true) && taskAssignmentContext?.currentTaskId) {
|
|
108
108
|
lines.push(`Current assigned task id: ${taskAssignmentContext.currentTaskId}.`);
|
|
@@ -115,8 +115,8 @@ function buildTaskAssignmentPromptLines(params) {
|
|
|
115
115
|
}
|
|
116
116
|
return lines;
|
|
117
117
|
}
|
|
118
|
-
function
|
|
119
|
-
return
|
|
118
|
+
function buildResolvedWorkingFolderPromptLines(provider, context) {
|
|
119
|
+
return buildResolvedWorkingFolderGuidanceLines(context, provider);
|
|
120
120
|
}
|
|
121
121
|
function buildClaudeOrdinaryGatewayTaskLines(context) {
|
|
122
122
|
if (!context?.skillRuntime || !context.localhostGateway || !context.gatewayCredentialPath) {
|
|
@@ -250,18 +250,18 @@ function buildClaudeProjectedBriefTurnPrompt(params) {
|
|
|
250
250
|
params.incomingContent,
|
|
251
251
|
].join('\n');
|
|
252
252
|
}
|
|
253
|
-
function
|
|
253
|
+
function buildOrdinaryCopilotWorkingFolderPromptLines(params) {
|
|
254
254
|
if (params.provider !== 'copilot') {
|
|
255
255
|
return [];
|
|
256
256
|
}
|
|
257
|
-
if (!params.promptContext?.
|
|
257
|
+
if (!params.promptContext?.resolvedWorkingFolder) {
|
|
258
258
|
return [];
|
|
259
259
|
}
|
|
260
260
|
if (params.incomingMessageType?.trim() === 'task_assignment'
|
|
261
261
|
|| params.promptContext.taskAssignmentContext?.active === true) {
|
|
262
262
|
return [];
|
|
263
263
|
}
|
|
264
|
-
return
|
|
264
|
+
return buildResolvedWorkingFolderPromptLines(params.provider, params.promptContext);
|
|
265
265
|
}
|
|
266
266
|
function buildInboundMetadataLines(params) {
|
|
267
267
|
return [
|
|
@@ -272,7 +272,7 @@ function buildInboundMetadataLines(params) {
|
|
|
272
272
|
return lines.length > 0 ? ['', ...lines] : [];
|
|
273
273
|
})(),
|
|
274
274
|
...(() => {
|
|
275
|
-
const lines =
|
|
275
|
+
const lines = buildOrdinaryCopilotWorkingFolderPromptLines(params);
|
|
276
276
|
return lines.length > 0 ? ['', ...lines] : [];
|
|
277
277
|
})(),
|
|
278
278
|
...buildTaskAssignmentPromptLines({
|
|
@@ -601,7 +601,7 @@ function buildClaudeSessionEnvironmentLines(context) {
|
|
|
601
601
|
if (context.localhostGateway && context.gatewayCredentialPath) {
|
|
602
602
|
lines.push(`Gateway credential file for this session: ${context.gatewayCredentialPath}`);
|
|
603
603
|
}
|
|
604
|
-
lines.push(...
|
|
604
|
+
lines.push(...buildResolvedWorkingFolderGuidanceLines(context));
|
|
605
605
|
if (context.taskAssignmentContext?.currentTaskId) {
|
|
606
606
|
lines.push(`Current assigned task id: ${context.taskAssignmentContext.currentTaskId}.`);
|
|
607
607
|
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { PreparedPromptContext, ProviderKind } from '../types.js';
|
|
2
|
+
export declare function buildResolvedWorkingFolderGuidanceLines(context: PreparedPromptContext | undefined, provider?: ProviderKind): string[];
|
|
3
|
+
export declare function isDiscussionOnlyResolvedWorkingFolder(context: PreparedPromptContext | undefined): boolean;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
function buildWorkingFolderRootLine(context) {
|
|
2
|
+
const resolvedWorkingFolder = context.resolvedWorkingFolder;
|
|
3
|
+
if (!resolvedWorkingFolder) {
|
|
4
|
+
return undefined;
|
|
5
|
+
}
|
|
6
|
+
if (resolvedWorkingFolder.authority === 'task-execution-target') {
|
|
7
|
+
return `Explicit execution local directory for this task thread: ${resolvedWorkingFolder.rootPath}.`;
|
|
8
|
+
}
|
|
9
|
+
if (resolvedWorkingFolder.authority === 'task-thread-scratch') {
|
|
10
|
+
return `Discussion-only scratch working folder for this task thread: ${resolvedWorkingFolder.rootPath}.`;
|
|
11
|
+
}
|
|
12
|
+
if (context.taskAssignmentContext?.active === true) {
|
|
13
|
+
return `Writable working folder inherited from this task thread's channel: ${resolvedWorkingFolder.rootPath}.`;
|
|
14
|
+
}
|
|
15
|
+
return `Writable working folder for this channel: ${resolvedWorkingFolder.rootPath}.`;
|
|
16
|
+
}
|
|
17
|
+
function buildWorkingFolderModeLine(context) {
|
|
18
|
+
if (context.taskAssignmentContext?.active !== true || !context.resolvedWorkingFolder) {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
if (context.resolvedWorkingFolder.authority === 'task-execution-target') {
|
|
22
|
+
return 'This task thread has a valid explicit execution.local_directory target, so execution is bound to that exact existing local directory.';
|
|
23
|
+
}
|
|
24
|
+
if (context.resolvedWorkingFolder.authority === 'task-thread-scratch') {
|
|
25
|
+
return context.resolvedWorkingFolder.reason === 'cross-agent-independent-workspace-disabled'
|
|
26
|
+
? 'This task thread has an explicit execution.local_directory target, but this agents-host currently disables cross-agent independent-working-folder handoff, so it is discussion-only.'
|
|
27
|
+
: 'This task thread has no valid explicit execution.local_directory target, so it is discussion-only.';
|
|
28
|
+
}
|
|
29
|
+
return 'This task thread inherits the channel working folder rather than using a task-isolated working folder.';
|
|
30
|
+
}
|
|
31
|
+
function buildWorkingFolderLocalityLine(context) {
|
|
32
|
+
if (!context.resolvedWorkingFolder) {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
if (context.resolvedWorkingFolder.authority === 'task-execution-target') {
|
|
36
|
+
return 'This is a human-selected existing local directory. The host validates it before use and never creates it.';
|
|
37
|
+
}
|
|
38
|
+
if (context.resolvedWorkingFolder.authority === 'task-thread-scratch') {
|
|
39
|
+
return 'This scratch working folder is host-managed only for discussion turns. It is not a bound project directory and does not imply that any target repository is checked out there.';
|
|
40
|
+
}
|
|
41
|
+
if (context.taskAssignmentContext?.active === true) {
|
|
42
|
+
return 'This writable working folder is local to agents-host for this task thread because the task inherits its channel working folder. It does not imply that the target repository has already been checked out there.';
|
|
43
|
+
}
|
|
44
|
+
return 'This writable working folder is local to agents-host for this channel. It does not imply that the target repository has already been checked out there.';
|
|
45
|
+
}
|
|
46
|
+
function buildCopilotCwdLine(context) {
|
|
47
|
+
if (!context.resolvedWorkingFolder) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
if (context.resolvedWorkingFolder.authority === 'task-execution-target') {
|
|
51
|
+
return 'GitHub Copilot runs this turn with that exact local directory as its real cwd.';
|
|
52
|
+
}
|
|
53
|
+
if (context.resolvedWorkingFolder.authority === 'task-thread-scratch') {
|
|
54
|
+
return 'GitHub Copilot runs this turn with that host-managed scratch working folder as its real cwd.';
|
|
55
|
+
}
|
|
56
|
+
if (context.taskAssignmentContext?.active === true) {
|
|
57
|
+
return 'GitHub Copilot runs this turn with that inherited channel working folder as its real cwd.';
|
|
58
|
+
}
|
|
59
|
+
return 'GitHub Copilot runs this turn with that working folder as its real cwd.';
|
|
60
|
+
}
|
|
61
|
+
function buildDiscussionOnlyPermissionLine(context) {
|
|
62
|
+
if (context.resolvedWorkingFolder?.authority !== 'task-thread-scratch') {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
return context.resolvedWorkingFolder.reason === 'cross-agent-independent-workspace-disabled'
|
|
66
|
+
? 'Filesystem and shell tool permissions stay denied in this discussion-only task thread while this agents-host keeps cross-agent independent-working-folder handoff disabled.'
|
|
67
|
+
: 'Filesystem and shell tool permissions stay denied in this discussion-only task thread until a human sets a valid execution.local_directory target.';
|
|
68
|
+
}
|
|
69
|
+
function buildProjectEntryPrecheckLine(context) {
|
|
70
|
+
if (context.taskAssignmentContext?.active !== true) {
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
if (context.resolvedWorkingFolder?.authority === 'task-execution-target') {
|
|
74
|
+
return 'Precheck before switching this task thread into your own local project directory: the task\'s parent channel must have exactly one human user. Cross-agent independent-working-folder handoff is also governed by this agents-host\'s local policy switch.';
|
|
75
|
+
}
|
|
76
|
+
return 'Before a human switches this task thread into their own local project directory, verify that the task\'s parent channel has exactly one human user; otherwise keep the thread discussion-only. Cross-agent independent-working-folder handoff is also governed by this agents-host\'s local policy switch.';
|
|
77
|
+
}
|
|
78
|
+
export function buildResolvedWorkingFolderGuidanceLines(context, provider) {
|
|
79
|
+
if (!context?.resolvedWorkingFolder) {
|
|
80
|
+
return [];
|
|
81
|
+
}
|
|
82
|
+
const lines = [buildWorkingFolderRootLine(context), buildWorkingFolderModeLine(context)]
|
|
83
|
+
.filter((line) => line != null);
|
|
84
|
+
if (provider === 'copilot') {
|
|
85
|
+
const copilotCwdLine = buildCopilotCwdLine(context);
|
|
86
|
+
if (copilotCwdLine) {
|
|
87
|
+
lines.push(copilotCwdLine);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const localityLine = buildWorkingFolderLocalityLine(context);
|
|
91
|
+
if (localityLine) {
|
|
92
|
+
lines.push(localityLine);
|
|
93
|
+
}
|
|
94
|
+
const permissionLine = buildDiscussionOnlyPermissionLine(context);
|
|
95
|
+
if (permissionLine) {
|
|
96
|
+
lines.push(permissionLine);
|
|
97
|
+
}
|
|
98
|
+
const precheckLine = buildProjectEntryPrecheckLine(context);
|
|
99
|
+
if (precheckLine) {
|
|
100
|
+
lines.push(precheckLine);
|
|
101
|
+
}
|
|
102
|
+
return lines;
|
|
103
|
+
}
|
|
104
|
+
export function isDiscussionOnlyResolvedWorkingFolder(context) {
|
|
105
|
+
return context?.resolvedWorkingFolder?.authority === 'task-thread-scratch';
|
|
106
|
+
}
|
|
@@ -38,7 +38,7 @@ function toPromptContext(channelContext, input) {
|
|
|
38
38
|
skillRuntime: channelContext.skillRuntime,
|
|
39
39
|
localhostGateway: channelContext.localhostGateway,
|
|
40
40
|
taskAssignmentContext: channelContext.payload.taskAssignmentContext,
|
|
41
|
-
|
|
41
|
+
resolvedWorkingFolder: channelContext.resolvedWorkingFolder,
|
|
42
42
|
}
|
|
43
43
|
: {}),
|
|
44
44
|
runtimeSurface,
|
package/dist/local-config.d.ts
CHANGED
|
@@ -41,14 +41,21 @@ export declare function loadLocalConfigSnapshot(hostConfigPath: string, deps?: {
|
|
|
41
41
|
fileSystem?: LocalConfigFileSystem;
|
|
42
42
|
acquireManagedGenerationLease?: boolean;
|
|
43
43
|
env?: NodeJS.ProcessEnv;
|
|
44
|
+
platform?: NodeJS.Platform;
|
|
44
45
|
}): Promise<LocalConfigSnapshot>;
|
|
45
46
|
export declare function loadLocalConfigGenerateSpec(hostConfigPath: string, deps?: {
|
|
46
47
|
fileSystem?: LocalConfigFileSystem;
|
|
47
48
|
acquireManagedGenerationLease?: boolean;
|
|
48
49
|
env?: NodeJS.ProcessEnv;
|
|
50
|
+
platform?: NodeJS.Platform;
|
|
49
51
|
}): Promise<LocalConfigGenerateSpec>;
|
|
52
|
+
export declare function hasManagedLocalConfig(rootPath: string, deps?: {
|
|
53
|
+
fileSystem?: ManagedLocalConfigFileSystem;
|
|
54
|
+
platform?: NodeJS.Platform;
|
|
55
|
+
}): Promise<boolean>;
|
|
50
56
|
export declare function materializeLocalConfig(rootPath: string, spec: LocalConfigGenerateSpec, deps?: {
|
|
51
57
|
fileSystem?: ManagedLocalConfigFileSystem;
|
|
52
58
|
env?: NodeJS.ProcessEnv;
|
|
59
|
+
platform?: NodeJS.Platform;
|
|
53
60
|
}): Promise<LocalConfigGenerateResult>;
|
|
54
61
|
export {};
|
package/dist/local-config.js
CHANGED
|
@@ -10,6 +10,8 @@ export const DEFAULT_LOCAL_AGENTS_DIRNAME = 'agents';
|
|
|
10
10
|
const DEFAULT_AGENTS_DIR = './agents';
|
|
11
11
|
const MANAGED_GENERATIONS_DIRNAME = '.generations';
|
|
12
12
|
const MANAGED_CURRENT_LINK_NAME = 'current';
|
|
13
|
+
const MANAGED_CURRENT_POINTER_FILENAME = 'current.json';
|
|
14
|
+
const MANAGED_CURRENT_POINTER_SCHEMA_VERSION = 1;
|
|
13
15
|
export const MANAGED_WRITE_LOCK_DIRNAME = '.generate-config.lock';
|
|
14
16
|
const MANAGED_READERS_DIRNAME = '.readers';
|
|
15
17
|
const MANAGED_HOLDER_METADATA_FILENAME = '.holder.json';
|
|
@@ -391,10 +393,106 @@ function isDirectManagedGeneration(root, target) {
|
|
|
391
393
|
const resolvedTarget = resolve(root, target);
|
|
392
394
|
return (dirname(resolvedTarget) === generationsDir && relative(generationsDir, resolvedTarget) !== '');
|
|
393
395
|
}
|
|
394
|
-
|
|
396
|
+
function parseManagedCurrentPointer(raw, pointerPath) {
|
|
397
|
+
let parsed;
|
|
398
|
+
try {
|
|
399
|
+
parsed = JSON.parse(raw);
|
|
400
|
+
}
|
|
401
|
+
catch (error) {
|
|
402
|
+
throw new Error(`Invalid managed config pointer ${pointerPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
403
|
+
}
|
|
404
|
+
if (!isRecord(parsed) ||
|
|
405
|
+
Object.keys(parsed).sort().join(',') !== 'generation,schemaVersion' ||
|
|
406
|
+
parsed.schemaVersion !== MANAGED_CURRENT_POINTER_SCHEMA_VERSION ||
|
|
407
|
+
typeof parsed.generation !== 'string' ||
|
|
408
|
+
!MANAGED_GENERATION_NAME_PATTERN.test(parsed.generation) ||
|
|
409
|
+
isAbsolute(parsed.generation) ||
|
|
410
|
+
parsed.generation.includes('/') ||
|
|
411
|
+
parsed.generation.includes('\\')) {
|
|
412
|
+
throw new Error(`Invalid managed config pointer ${pointerPath}: expected schemaVersion ${MANAGED_CURRENT_POINTER_SCHEMA_VERSION} and one direct generation identifier`);
|
|
413
|
+
}
|
|
414
|
+
return {
|
|
415
|
+
schemaVersion: MANAGED_CURRENT_POINTER_SCHEMA_VERSION,
|
|
416
|
+
generation: parsed.generation,
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
async function resolvePointerGeneration(fileSystem, root) {
|
|
420
|
+
const pointerPath = join(root, MANAGED_CURRENT_POINTER_FILENAME);
|
|
421
|
+
const pointerStatus = await pathStatus(fileSystem, pointerPath);
|
|
422
|
+
if (!pointerStatus) {
|
|
423
|
+
return undefined;
|
|
424
|
+
}
|
|
425
|
+
if (pointerStatus.isDirectory || pointerStatus.isSymbolicLink) {
|
|
426
|
+
throw new Error(`Managed config pointer must be an ordinary file: ${pointerPath}`);
|
|
427
|
+
}
|
|
428
|
+
const pointer = parseManagedCurrentPointer(await fileSystem.readFile(pointerPath), pointerPath);
|
|
429
|
+
const generationsDir = join(root, MANAGED_GENERATIONS_DIRNAME);
|
|
430
|
+
const generationPath = resolve(generationsDir, pointer.generation);
|
|
431
|
+
if (dirname(generationPath) !== generationsDir ||
|
|
432
|
+
relative(generationsDir, generationPath) !== pointer.generation) {
|
|
433
|
+
throw new Error(`Managed config pointer generation must be a direct child of ${generationsDir}`);
|
|
434
|
+
}
|
|
435
|
+
const generationStatus = await pathStatus(fileSystem, generationPath);
|
|
436
|
+
if (!generationStatus?.isDirectory || generationStatus.isSymbolicLink) {
|
|
437
|
+
throw new Error(`Managed config pointer target is not a directory: ${generationPath}`);
|
|
438
|
+
}
|
|
439
|
+
return generationPath;
|
|
440
|
+
}
|
|
441
|
+
async function resolveLegacyCurrentGeneration(fileSystem, root) {
|
|
442
|
+
const generationsDir = join(root, MANAGED_GENERATIONS_DIRNAME);
|
|
443
|
+
const currentPath = join(root, MANAGED_CURRENT_LINK_NAME);
|
|
444
|
+
const currentStatus = await pathStatus(fileSystem, currentPath);
|
|
445
|
+
if (!currentStatus) {
|
|
446
|
+
return undefined;
|
|
447
|
+
}
|
|
448
|
+
if (!currentStatus.isSymbolicLink) {
|
|
449
|
+
throw new Error(`Managed config path must be a symbolic link: ${currentPath}`);
|
|
450
|
+
}
|
|
451
|
+
const currentTarget = await fileSystem.readLink(currentPath);
|
|
452
|
+
if (!isDirectManagedGeneration(root, currentTarget)) {
|
|
453
|
+
throw new Error(`Managed config current generation must be inside ${generationsDir}`);
|
|
454
|
+
}
|
|
455
|
+
const currentGenerationPath = resolve(root, currentTarget);
|
|
456
|
+
const generationStatus = await pathStatus(fileSystem, currentGenerationPath);
|
|
457
|
+
if (!generationStatus?.isDirectory || generationStatus.isSymbolicLink) {
|
|
458
|
+
throw new Error(`Managed config current generation is not a directory: ${currentGenerationPath}`);
|
|
459
|
+
}
|
|
460
|
+
return currentGenerationPath;
|
|
461
|
+
}
|
|
462
|
+
async function validateOptionalLegacyAliases(fileSystem, root) {
|
|
463
|
+
const aliases = [
|
|
464
|
+
[
|
|
465
|
+
join(root, DEFAULT_LOCAL_HOST_CONFIG_FILENAME),
|
|
466
|
+
`${MANAGED_CURRENT_LINK_NAME}/${DEFAULT_LOCAL_HOST_CONFIG_FILENAME}`,
|
|
467
|
+
],
|
|
468
|
+
[
|
|
469
|
+
join(root, DEFAULT_LOCAL_AGENTS_DIRNAME),
|
|
470
|
+
`${MANAGED_CURRENT_LINK_NAME}/${DEFAULT_LOCAL_AGENTS_DIRNAME}`,
|
|
471
|
+
],
|
|
472
|
+
];
|
|
473
|
+
for (const [path, target] of aliases) {
|
|
474
|
+
const status = await pathStatus(fileSystem, path);
|
|
475
|
+
if (status && (!status.isSymbolicLink || (await fileSystem.readLink(path)) !== target)) {
|
|
476
|
+
throw new Error(`Managed config path has an unexpected value: ${path}`);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
async function prepareManagedRoot(fileSystem, root, platform) {
|
|
395
481
|
await ensureDirectory(fileSystem, root, MANAGED_ROOT_MODE);
|
|
396
482
|
const generationsDir = join(root, MANAGED_GENERATIONS_DIRNAME);
|
|
397
483
|
await ensureDirectory(fileSystem, generationsDir, MANAGED_ROOT_MODE);
|
|
484
|
+
if (platform === 'win32') {
|
|
485
|
+
await validateOptionalLegacyAliases(fileSystem, root);
|
|
486
|
+
const pointerGeneration = await resolvePointerGeneration(fileSystem, root);
|
|
487
|
+
const legacyGeneration = pointerGeneration
|
|
488
|
+
? undefined
|
|
489
|
+
: await resolveLegacyCurrentGeneration(fileSystem, root);
|
|
490
|
+
const currentGenerationPath = pointerGeneration ?? legacyGeneration;
|
|
491
|
+
if (currentGenerationPath) {
|
|
492
|
+
await fileSystem.chmod(currentGenerationPath, MANAGED_ROOT_MODE);
|
|
493
|
+
}
|
|
494
|
+
return { currentGenerationPath };
|
|
495
|
+
}
|
|
398
496
|
const currentPath = join(root, MANAGED_CURRENT_LINK_NAME);
|
|
399
497
|
const currentStatus = await pathStatus(fileSystem, currentPath);
|
|
400
498
|
const hostAliasPath = join(root, DEFAULT_LOCAL_HOST_CONFIG_FILENAME);
|
|
@@ -483,7 +581,7 @@ function supportsManagedGenerationLeases(fileSystem) {
|
|
|
483
581
|
'chmod' in fileSystem &&
|
|
484
582
|
'readLink' in fileSystem);
|
|
485
583
|
}
|
|
486
|
-
async function managedRootForHostConfigPath(fileSystem, hostConfigPath) {
|
|
584
|
+
async function managedRootForHostConfigPath(fileSystem, hostConfigPath, platform) {
|
|
487
585
|
if (hostConfigPath === join(dirname(hostConfigPath), DEFAULT_LOCAL_HOST_CONFIG_FILENAME)) {
|
|
488
586
|
const generationPath = dirname(hostConfigPath);
|
|
489
587
|
const generationsDir = dirname(generationPath);
|
|
@@ -497,6 +595,11 @@ async function managedRootForHostConfigPath(fileSystem, hostConfigPath) {
|
|
|
497
595
|
return undefined;
|
|
498
596
|
}
|
|
499
597
|
const root = dirname(hostConfigPath);
|
|
598
|
+
if (platform === 'win32') {
|
|
599
|
+
const pointerStatus = await pathStatus(fileSystem, join(root, MANAGED_CURRENT_POINTER_FILENAME));
|
|
600
|
+
const currentStatus = await pathStatus(fileSystem, join(root, MANAGED_CURRENT_LINK_NAME));
|
|
601
|
+
return pointerStatus || currentStatus ? root : undefined;
|
|
602
|
+
}
|
|
500
603
|
const currentPath = join(root, MANAGED_CURRENT_LINK_NAME);
|
|
501
604
|
const currentStatus = await pathStatus(fileSystem, currentPath);
|
|
502
605
|
if (!currentStatus?.isSymbolicLink) {
|
|
@@ -504,7 +607,7 @@ async function managedRootForHostConfigPath(fileSystem, hostConfigPath) {
|
|
|
504
607
|
}
|
|
505
608
|
return isDirectManagedGeneration(root, await fileSystem.readLink(currentPath)) ? root : undefined;
|
|
506
609
|
}
|
|
507
|
-
async function resolveHostConfigWithGenerationLease(fileSystem, absoluteHostConfigPath) {
|
|
610
|
+
async function resolveHostConfigWithGenerationLease(fileSystem, absoluteHostConfigPath, platform) {
|
|
508
611
|
const resolveHostConfigPath = async () => resolve(fileSystem.realPath
|
|
509
612
|
? await fileSystem.realPath(absoluteHostConfigPath)
|
|
510
613
|
: absoluteHostConfigPath);
|
|
@@ -512,14 +615,20 @@ async function resolveHostConfigWithGenerationLease(fileSystem, absoluteHostConf
|
|
|
512
615
|
if (!supportsManagedGenerationLeases(fileSystem)) {
|
|
513
616
|
return { resolvedHostConfigPath: await resolveHostConfigPath(), release: noLease };
|
|
514
617
|
}
|
|
515
|
-
const root = await managedRootForHostConfigPath(fileSystem, absoluteHostConfigPath);
|
|
618
|
+
const root = await managedRootForHostConfigPath(fileSystem, absoluteHostConfigPath, platform);
|
|
516
619
|
if (!root) {
|
|
517
620
|
return { resolvedHostConfigPath: await resolveHostConfigPath(), release: noLease };
|
|
518
621
|
}
|
|
519
622
|
const releaseWriteLock = await acquireManagedWriteLock(fileSystem, root);
|
|
520
623
|
let leasePath;
|
|
521
624
|
try {
|
|
522
|
-
const
|
|
625
|
+
const activeGenerationPath = platform === 'win32'
|
|
626
|
+
? ((await resolvePointerGeneration(fileSystem, root)) ??
|
|
627
|
+
(await resolveLegacyCurrentGeneration(fileSystem, root)))
|
|
628
|
+
: undefined;
|
|
629
|
+
const resolvedHostConfigPath = activeGenerationPath
|
|
630
|
+
? join(activeGenerationPath, DEFAULT_LOCAL_HOST_CONFIG_FILENAME)
|
|
631
|
+
: await resolveHostConfigPath();
|
|
523
632
|
const generationPath = dirname(resolvedHostConfigPath);
|
|
524
633
|
const generationsDir = join(root, MANAGED_GENERATIONS_DIRNAME);
|
|
525
634
|
if (dirname(generationPath) !== generationsDir ||
|
|
@@ -660,7 +769,7 @@ export async function loadLocalConfigSnapshot(hostConfigPath, deps = {}) {
|
|
|
660
769
|
: absoluteHostConfigPath),
|
|
661
770
|
release: async () => undefined,
|
|
662
771
|
}
|
|
663
|
-
: await resolveHostConfigWithGenerationLease(fileSystem, absoluteHostConfigPath);
|
|
772
|
+
: await resolveHostConfigWithGenerationLease(fileSystem, absoluteHostConfigPath, deps.platform ?? process.platform);
|
|
664
773
|
try {
|
|
665
774
|
const { resolvedHostConfigPath } = managedGeneration;
|
|
666
775
|
const hostConfigDir = dirname(absoluteHostConfigPath);
|
|
@@ -718,7 +827,7 @@ export async function loadLocalConfigGenerateSpec(hostConfigPath, deps = {}) {
|
|
|
718
827
|
: absoluteHostConfigPath),
|
|
719
828
|
release: async () => undefined,
|
|
720
829
|
}
|
|
721
|
-
: await resolveHostConfigWithGenerationLease(fileSystem, absoluteHostConfigPath);
|
|
830
|
+
: await resolveHostConfigWithGenerationLease(fileSystem, absoluteHostConfigPath, deps.platform ?? process.platform);
|
|
722
831
|
try {
|
|
723
832
|
const { resolvedHostConfigPath } = managedGeneration;
|
|
724
833
|
const hostConfigRecord = await loadParsedDocument(fileSystem, resolvedHostConfigPath, 'host config');
|
|
@@ -755,9 +864,20 @@ export async function loadLocalConfigGenerateSpec(hostConfigPath, deps = {}) {
|
|
|
755
864
|
await managedGeneration.release();
|
|
756
865
|
}
|
|
757
866
|
}
|
|
867
|
+
export async function hasManagedLocalConfig(rootPath, deps = {}) {
|
|
868
|
+
const fileSystem = deps.fileSystem ?? nodeFileSystem;
|
|
869
|
+
const root = resolve(rootPath);
|
|
870
|
+
const platform = deps.platform ?? process.platform;
|
|
871
|
+
if (platform === 'win32') {
|
|
872
|
+
return ((await resolvePointerGeneration(fileSystem, root)) !== undefined ||
|
|
873
|
+
(await resolveLegacyCurrentGeneration(fileSystem, root)) !== undefined);
|
|
874
|
+
}
|
|
875
|
+
return (await pathStatus(fileSystem, join(root, DEFAULT_LOCAL_HOST_CONFIG_FILENAME))) !== undefined;
|
|
876
|
+
}
|
|
758
877
|
export async function materializeLocalConfig(rootPath, spec, deps = {}) {
|
|
759
878
|
const fileSystem = deps.fileSystem ?? nodeFileSystem;
|
|
760
879
|
const layout = resolveLocalConfigLayout(rootPath);
|
|
880
|
+
const platform = deps.platform ?? process.platform;
|
|
761
881
|
const desiredAgentFiles = new Map();
|
|
762
882
|
for (const agent of spec.agents) {
|
|
763
883
|
desiredAgentFiles.set(toGeneratedAgentConfigPath(layout.agentsDir, agent.key), agent);
|
|
@@ -768,8 +888,10 @@ export async function materializeLocalConfig(rootPath, spec, deps = {}) {
|
|
|
768
888
|
await ensureDirectory(fileSystem, layout.root, MANAGED_ROOT_MODE);
|
|
769
889
|
const releaseWriteLock = await acquireManagedWriteLock(fileSystem, layout.root);
|
|
770
890
|
try {
|
|
771
|
-
const { currentGenerationPath } = await prepareManagedRoot(fileSystem, layout.root);
|
|
772
|
-
const priorAgentConfigPaths = await listSupportedConfigPaths(fileSystem,
|
|
891
|
+
const { currentGenerationPath } = await prepareManagedRoot(fileSystem, layout.root, platform);
|
|
892
|
+
const priorAgentConfigPaths = (await listSupportedConfigPaths(fileSystem, currentGenerationPath
|
|
893
|
+
? join(currentGenerationPath, DEFAULT_LOCAL_AGENTS_DIRNAME)
|
|
894
|
+
: layout.agentsDir)).map((path) => join(layout.agentsDir, path.slice(dirname(path).length + 1)));
|
|
773
895
|
const generationName = randomUUID();
|
|
774
896
|
const generationsDir = join(layout.root, MANAGED_GENERATIONS_DIRNAME);
|
|
775
897
|
const generationPath = join(generationsDir, generationName);
|
|
@@ -792,9 +914,33 @@ export async function materializeLocalConfig(rootPath, spec, deps = {}) {
|
|
|
792
914
|
acquireManagedGenerationLease: false,
|
|
793
915
|
env: deps.env,
|
|
794
916
|
});
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
917
|
+
if (platform === 'win32') {
|
|
918
|
+
const nextCurrentPath = join(layout.root, `.${MANAGED_CURRENT_POINTER_FILENAME}-${generationName}`);
|
|
919
|
+
await fileSystem.writeFile(nextCurrentPath, `${JSON.stringify({
|
|
920
|
+
schemaVersion: MANAGED_CURRENT_POINTER_SCHEMA_VERSION,
|
|
921
|
+
generation: generationName,
|
|
922
|
+
})}\n`);
|
|
923
|
+
await fileSystem.chmod(nextCurrentPath, MANAGED_CONFIG_MODE);
|
|
924
|
+
try {
|
|
925
|
+
await fileSystem.rename(nextCurrentPath, join(layout.root, MANAGED_CURRENT_POINTER_FILENAME));
|
|
926
|
+
}
|
|
927
|
+
catch (error) {
|
|
928
|
+
try {
|
|
929
|
+
await fileSystem.removeFile(nextCurrentPath);
|
|
930
|
+
}
|
|
931
|
+
catch (cleanupError) {
|
|
932
|
+
if (!isNotFoundError(cleanupError)) {
|
|
933
|
+
throw new AggregateError([error, cleanupError], 'Managed config pointer publication and cleanup both failed');
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
throw error;
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
else {
|
|
940
|
+
const nextCurrentPath = join(layout.root, `.${MANAGED_CURRENT_LINK_NAME}-${generationName}`);
|
|
941
|
+
await fileSystem.symlink(join(MANAGED_GENERATIONS_DIRNAME, generationName), nextCurrentPath);
|
|
942
|
+
await fileSystem.rename(nextCurrentPath, join(layout.root, MANAGED_CURRENT_LINK_NAME));
|
|
943
|
+
}
|
|
798
944
|
published = true;
|
|
799
945
|
try {
|
|
800
946
|
await pruneSupersededGenerations(fileSystem, generationsDir, new Set([generationPath, currentGenerationPath].filter((path) => path !== undefined)));
|
package/dist/managed-daemon.js
CHANGED
|
@@ -6,10 +6,10 @@ import { dirname, isAbsolute, join, resolve } from 'node:path';
|
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
7
|
import { AgentsHostSupervisor } from './agents-host-supervisor.js';
|
|
8
8
|
import { DEFAULT_PROJECTION_STRATEGY, normalizeProjectionStrategy, } from './projection-strategy-values.js';
|
|
9
|
-
import {
|
|
9
|
+
import { resolveChannelWorkingFolderDirectory, resolveChannelWorkingFolderRootDirectory, resolveManagedWorkingFolderCollectionRoot, resolveTaskThreadScratchWorkingFolderDirectory, } from './context/injection.js';
|
|
10
10
|
import { CLAUDE_PROVIDER_V2_COMPATIBILITY_GATE, COMPATIBILITY_GATES_ENV, CURRENT_AGENTS_HOST_PACKAGE_VERSION, createManagedRuntimeSettingsFingerprint, INTERNAL_CLAUDE_PROMPT_STRATEGY_ENV, 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, serializeManagedRuntimeSettingsSnapshot, normalizeInternalProviderImplementationOverrides, } from './compatibility-gates.js';
|
|
11
11
|
import { DEFAULT_PROVIDER_COMMAND_CONFIG, hasLegacyClaudeOneShotArgs, loadConfigFromEnv, } from './config.js';
|
|
12
|
-
import { loadLocalConfigGenerateSpec, materializeLocalConfig, parseGenerateConfigSpec, resolveLocalConfigLayout, } from './local-config.js';
|
|
12
|
+
import { hasManagedLocalConfig, loadLocalConfigGenerateSpec, materializeLocalConfig, parseGenerateConfigSpec, resolveLocalConfigLayout, } from './local-config.js';
|
|
13
13
|
import { normalizeManagedRuntimeKey, resolveManagedBootstrapLockPath, resolveManagedDaemonEndpoint, resolveManagedDaemonLogPath, resolveManagedRuntimeRoot, resolveManagedStateRoot, resolveManagedRuntimeSettingsPath, } from './state-paths.js';
|
|
14
14
|
const MANAGED_ROOT_MODE = 0o700;
|
|
15
15
|
const MANAGED_CONFIG_MODE = 0o600;
|
|
@@ -843,19 +843,19 @@ async function shutdownManagedDaemon(rootPath, sendRequest, waitForShutdown) {
|
|
|
843
843
|
}
|
|
844
844
|
await waitForShutdown(rootPath);
|
|
845
845
|
}
|
|
846
|
-
function
|
|
846
|
+
function resolveTrustedPersistedChannelWorkingFolderRoot(workingFolderCollectionRoot, owningChannelId, rootPath) {
|
|
847
847
|
if (!owningChannelId || !isAbsolute(rootPath)) {
|
|
848
848
|
return null;
|
|
849
849
|
}
|
|
850
|
-
const
|
|
851
|
-
if (rootPath !==
|
|
850
|
+
const expectedWorkingFolderPath = resolveChannelWorkingFolderDirectory(workingFolderCollectionRoot, owningChannelId);
|
|
851
|
+
if (rootPath !== expectedWorkingFolderPath) {
|
|
852
852
|
return null;
|
|
853
853
|
}
|
|
854
|
-
return
|
|
854
|
+
return resolveChannelWorkingFolderRootDirectory(workingFolderCollectionRoot, owningChannelId);
|
|
855
855
|
}
|
|
856
|
-
async function
|
|
857
|
-
const
|
|
858
|
-
|
|
856
|
+
async function discoverManagedWorkingFolderRootsForPurge(rootPath, processEnv) {
|
|
857
|
+
const trustedWorkingFolderCollectionRoots = new Set([
|
|
858
|
+
resolveManagedWorkingFolderCollectionRoot(undefined, processEnv),
|
|
859
859
|
]);
|
|
860
860
|
const managedStateRoot = resolveManagedStateRoot(rootPath);
|
|
861
861
|
const agentStateEntries = await fs.readdir(managedStateRoot, { withFileTypes: true }).catch((error) => {
|
|
@@ -864,7 +864,7 @@ async function discoverManagedWorkspaceRootsForPurge(rootPath, processEnv) {
|
|
|
864
864
|
}
|
|
865
865
|
throw error;
|
|
866
866
|
});
|
|
867
|
-
const
|
|
867
|
+
const workingFolderRoots = new Set();
|
|
868
868
|
for (const agentStateEntry of agentStateEntries) {
|
|
869
869
|
if (!agentStateEntry.isDirectory()) {
|
|
870
870
|
continue;
|
|
@@ -900,43 +900,43 @@ async function discoverManagedWorkspaceRootsForPurge(rootPath, processEnv) {
|
|
|
900
900
|
if (!isRecord(parsed) || typeof parsed.channelId !== 'string' || !isRecord(parsed.resolvedWorkspace)) {
|
|
901
901
|
continue;
|
|
902
902
|
}
|
|
903
|
-
const
|
|
904
|
-
if ((
|
|
905
|
-
&&
|
|
906
|
-
&&
|
|
907
|
-
|| typeof
|
|
908
|
-
|| !isAbsolute(
|
|
903
|
+
const resolvedWorkingFolder = parsed.resolvedWorkspace;
|
|
904
|
+
if ((resolvedWorkingFolder.authority !== 'channel'
|
|
905
|
+
&& resolvedWorkingFolder.authority !== 'task-thread-scratch'
|
|
906
|
+
&& resolvedWorkingFolder.authority !== 'task-execution-target')
|
|
907
|
+
|| typeof resolvedWorkingFolder.rootPath !== 'string'
|
|
908
|
+
|| !isAbsolute(resolvedWorkingFolder.rootPath)) {
|
|
909
909
|
continue;
|
|
910
910
|
}
|
|
911
|
-
for (const
|
|
912
|
-
if (
|
|
913
|
-
if (typeof
|
|
914
|
-
||
|
|
911
|
+
for (const workingFolderCollectionRoot of trustedWorkingFolderCollectionRoots) {
|
|
912
|
+
if (resolvedWorkingFolder.authority === 'channel') {
|
|
913
|
+
if (typeof resolvedWorkingFolder.owningChannelId !== 'string'
|
|
914
|
+
|| resolvedWorkingFolder.owningChannelId.length === 0) {
|
|
915
915
|
continue;
|
|
916
916
|
}
|
|
917
|
-
const
|
|
918
|
-
if (!
|
|
917
|
+
const trustedChannelWorkingFolderRoot = resolveTrustedPersistedChannelWorkingFolderRoot(workingFolderCollectionRoot, resolvedWorkingFolder.owningChannelId, resolvedWorkingFolder.rootPath);
|
|
918
|
+
if (!trustedChannelWorkingFolderRoot) {
|
|
919
919
|
continue;
|
|
920
920
|
}
|
|
921
|
-
|
|
921
|
+
workingFolderRoots.add(trustedChannelWorkingFolderRoot);
|
|
922
922
|
break;
|
|
923
923
|
}
|
|
924
|
-
if (
|
|
925
|
-
const
|
|
926
|
-
if (
|
|
924
|
+
if (resolvedWorkingFolder.authority === 'task-thread-scratch') {
|
|
925
|
+
const expectedWorkingFolderPath = resolveTaskThreadScratchWorkingFolderDirectory(workingFolderCollectionRoot, parsed.channelId);
|
|
926
|
+
if (resolvedWorkingFolder.rootPath !== expectedWorkingFolderPath) {
|
|
927
927
|
continue;
|
|
928
928
|
}
|
|
929
|
-
|
|
929
|
+
workingFolderRoots.add(resolveChannelWorkingFolderRootDirectory(workingFolderCollectionRoot, parsed.channelId));
|
|
930
930
|
break;
|
|
931
931
|
}
|
|
932
|
-
if (
|
|
932
|
+
if (resolvedWorkingFolder.authority !== 'task-execution-target') {
|
|
933
933
|
continue;
|
|
934
934
|
}
|
|
935
935
|
continue;
|
|
936
936
|
}
|
|
937
937
|
}
|
|
938
938
|
}
|
|
939
|
-
return [...
|
|
939
|
+
return [...workingFolderRoots].sort((left, right) => left.localeCompare(right));
|
|
940
940
|
}
|
|
941
941
|
export async function cleanupManagedRuntime(options, deps = {}) {
|
|
942
942
|
const sendRequest = deps.sendRequest ?? sendManagedDaemonRequest;
|
|
@@ -974,8 +974,8 @@ export async function cleanupManagedRuntime(options, deps = {}) {
|
|
|
974
974
|
await waitForShutdown(resolved.rootPath);
|
|
975
975
|
}
|
|
976
976
|
if (options.purge === true) {
|
|
977
|
-
for (const
|
|
978
|
-
await fs.rm(
|
|
977
|
+
for (const workingFolderRoot of await discoverManagedWorkingFolderRootsForPurge(resolved.rootPath, options.processEnv ?? process.env)) {
|
|
978
|
+
await fs.rm(workingFolderRoot, { recursive: true, force: true });
|
|
979
979
|
}
|
|
980
980
|
await removeRuntimeRoot(resolved.rootPath);
|
|
981
981
|
}
|
|
@@ -1130,7 +1130,7 @@ export async function bootstrapManagedDaemonStart(options, deps = {}) {
|
|
|
1130
1130
|
});
|
|
1131
1131
|
if (options.apiKey !== undefined
|
|
1132
1132
|
&& currentRuntimeSettings.persistedSettingsSnapshot == null
|
|
1133
|
-
&& await
|
|
1133
|
+
&& await hasManagedLocalConfig(resolved.rootPath)) {
|
|
1134
1134
|
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`);
|
|
1135
1135
|
}
|
|
1136
1136
|
const explicitManagedAgentOverrides = collectExplicitManagedAgentEnvOverrides(options.processEnv ?? process.env, options.env);
|
|
@@ -1628,9 +1628,16 @@ export class ManagedAgentsHostDaemon {
|
|
|
1628
1628
|
this.endpoint = resolveManagedDaemonEndpoint(this.rootPath, deps.platform);
|
|
1629
1629
|
this.createSupervisor =
|
|
1630
1630
|
deps.createSupervisor ??
|
|
1631
|
-
((configPath, daemonDebug) => new AgentsHostSupervisor(configPath, {
|
|
1632
|
-
|
|
1633
|
-
|
|
1631
|
+
((configPath, daemonDebug) => new AgentsHostSupervisor(configPath, {
|
|
1632
|
+
debug: daemonDebug,
|
|
1633
|
+
platform: deps.platform,
|
|
1634
|
+
}));
|
|
1635
|
+
this.loadSpec =
|
|
1636
|
+
deps.loadSpec ??
|
|
1637
|
+
((configPath) => loadLocalConfigGenerateSpec(configPath, { platform: deps.platform }));
|
|
1638
|
+
this.materialize =
|
|
1639
|
+
deps.materialize ??
|
|
1640
|
+
((managedRootPath, spec) => materializeLocalConfig(managedRootPath, spec, { platform: deps.platform }));
|
|
1634
1641
|
const managedRuntimeSettings = resolveDesiredManagedRuntimeSettings(process.env);
|
|
1635
1642
|
this.managedRuntimeFingerprint = managedRuntimeSettings.fingerprint;
|
|
1636
1643
|
this.logger = deps.logger ?? console;
|