@moretea-labs/forge 1.7.0 → 1.7.2
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/AGENTS.md +2 -0
- package/CHANGELOG.md +26 -0
- package/CLAUDE.md +2 -0
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/agents/openai.yaml +1 -1
- package/assets/partials-agents/02-operating-mode.partial.md +2 -0
- package/assets/plugin-registry.v1.json +3 -3
- package/assets/skill-version.json +2 -2
- package/assets/templates/helpers/check-architecture-sync.sh +17 -0
- package/assets/templates/helpers/inspect-project-state.ts +8 -6
- package/assets/templates/helpers/migrate-workflow-docs.ts +9 -7
- package/assets/templates/helpers/workflow-contract.ts +5 -1
- package/docs/architecture/CURRENT.md +12 -4
- package/docs/forge-plugin-management.md +1 -1
- package/docs/operations/controller-performance-and-502.md +19 -0
- package/docs/operations/homebrew.md +2 -2
- package/package.json +5 -2
- package/scripts/architecture-event.ts +2 -820
- package/scripts/architecture-queue.sh +2 -645
- package/scripts/archive-architecture-request.sh +2 -242
- package/scripts/archive-workflow.sh +1 -291
- package/scripts/benchmark-work-efficiency.ts +0 -0
- package/scripts/capability-config.ts +2 -392
- package/scripts/capability-resolver.ts +2 -503
- package/scripts/capture-plan.sh +1 -332
- package/scripts/check-agent-tooling.sh +2 -1531
- package/scripts/check-architecture-sync.sh +2 -302
- package/scripts/check-brain-manifest.sh +2 -253
- package/scripts/check-context-files.sh +2 -47
- package/scripts/check-deploy-sql-order.sh +2 -115
- package/scripts/check-runtime-architecture.mjs +243 -16
- package/scripts/check-skill-version.ts +3 -191
- package/scripts/check-source-duplication.mjs +61 -0
- package/scripts/check-stable-baseline.ts +0 -0
- package/scripts/check-task-sync.sh +2 -63
- package/scripts/check-task-workflow.sh +2 -1000
- package/scripts/codex-handoff-resume.sh +2 -267
- package/scripts/context-contract-sync.sh +2 -514
- package/scripts/contract-run.ts +2 -463
- package/scripts/contract-worktree.sh +1 -702
- package/scripts/ensure-task-workflow.sh +1 -1192
- package/scripts/inspect-project-state.ts +4 -279
- package/scripts/lib/project-init-lib.sh +7 -2
- package/scripts/lib/run-forge-helper.sh +19 -0
- package/scripts/lib/run-forge-helper.ts +26 -0
- package/scripts/migrate-project-template.sh +1 -33
- package/scripts/migrate-workflow-docs.ts +4 -412
- package/scripts/new-plan.sh +1 -180
- package/scripts/new-spec.sh +1 -47
- package/scripts/new-sprint.sh +1 -46
- package/scripts/plan-to-todo.sh +1 -771
- package/scripts/prepare-codex-handoff.sh +2 -201
- package/scripts/prepare-handoff.sh +1 -78
- package/scripts/refresh-current-status.sh +2 -467
- package/scripts/run-governed-gate.ts +3 -0
- package/scripts/select-agent-context-blocks.sh +2 -64
- package/scripts/ship-worktrees.sh +1 -531
- package/scripts/sprint-backlog.sh +1 -834
- package/scripts/stage-runtime-release.ts +2 -1
- package/scripts/summarize-failures.sh +2 -123
- package/scripts/switch-plan.sh +1 -150
- package/scripts/sync-brain-docs.sh +2 -379
- package/scripts/sync-generated-authority.mjs +175 -0
- package/scripts/verify-contract.sh +2 -593
- package/scripts/verify-sprint.sh +1 -500
- package/scripts/workflow-contract.ts +4 -201
- package/scripts/workstream-sync.sh +2 -261
- package/src/cli/agent-jobs/executor-health.ts +1 -1
- package/src/cli/commands/plugin.ts +12 -3
- package/src/cli/controller/check-runner.ts +7 -2
- package/src/cli/controller/context-pack.ts +46 -21
- package/src/cli/github/contracts.ts +16 -0
- package/src/cli/github/github.ts +2 -16
- package/src/cli/github/session.ts +2 -1
- package/src/cli/local-bridge/facade-api.ts +37 -47
- package/src/cli/local-bridge/server.ts +2 -2
- package/src/cli/mcp/legacy-tool-service.ts +10 -33
- package/src/cli/mcp/post-finalize-work-attribution.ts +150 -0
- package/src/cli/mcp/repository-tools.ts +125 -101
- package/src/cli/mcp/server.ts +57 -13
- package/src/cli/mcp/tool-contract.ts +14 -0
- package/src/cli/mcp/toolset.ts +2 -2
- package/src/cli/mcp/transports/http.ts +23 -0
- package/src/cli/repositories/command-classifier.ts +2 -2
- package/src/cli/repositories/command-executor.ts +24 -6
- package/src/cli/repositories/repository-snapshot.ts +5 -2
- package/src/cli/repositories/structured-git.ts +57 -3
- package/src/cli/repository/inspector.ts +11 -3
- package/src/runtime/context/generic-lsp-provider.ts +1 -1
- package/src/runtime/context/semantic-navigation-contract.ts +61 -0
- package/src/runtime/context/semantic-navigation.ts +9 -61
- package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +69 -29
- package/src/runtime/control-plane/execution/repository-work-attribution.ts +106 -0
- package/src/runtime/control-plane/execution/retained-work-resume.ts +203 -0
- package/src/runtime/control-plane/execution/work-completion-authority.ts +58 -0
- package/src/runtime/control-plane/execution/work-evidence-policy.ts +200 -0
- package/src/runtime/control-plane/execution/work-execution-support.ts +386 -0
- package/src/runtime/control-plane/execution/work-finalization-service.ts +1913 -0
- package/src/runtime/control-plane/execution/work-handle-authority.ts +150 -0
- package/src/runtime/control-plane/execution/work-handle-store.ts +1 -1
- package/src/runtime/control-plane/execution/work-operation-service.ts +468 -0
- package/src/runtime/control-plane/execution/work-path-scope.ts +37 -0
- package/src/runtime/control-plane/execution/work-preparation-service.ts +479 -0
- package/src/runtime/control-plane/execution/work-process-evidence.ts +129 -0
- package/src/runtime/control-plane/execution/work-task-receipt.ts +4 -43
- package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +13 -3
- package/src/runtime/control-plane/execution/work-verification-context.ts +56 -0
- package/src/runtime/control-plane/execution/work-verification-service.ts +388 -0
- package/src/runtime/control-plane/execution/work-verification-snapshot.ts +5 -1
- package/src/runtime/control-plane/facade/controller-round-relay.ts +164 -37
- package/src/runtime/control-plane/facade/controller-session-store.ts +183 -24
- package/src/runtime/control-plane/facade/goal-workloop-access.ts +15 -1
- package/src/runtime/control-plane/facade/goal-workloop.ts +329 -148
- package/src/runtime/control-plane/facade/index.ts +2 -0
- package/src/runtime/control-plane/facade/plan-contract-store.ts +90 -22
- package/src/runtime/control-plane/facade/repository-work-admission.ts +147 -0
- package/src/runtime/control-plane/facade/requirement-authority.ts +83 -0
- package/src/runtime/control-plane/facade/types.ts +68 -5
- package/src/runtime/control-plane/facade/work-contract-store.ts +3 -209
- package/src/runtime/control-plane/facade/work-state-machine.ts +250 -0
- package/src/runtime/control-plane/global-scheduler/maintenance.ts +14 -7
- package/src/runtime/control-plane/global-scheduler/scheduler.ts +5 -1
- package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +13 -0
- package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +15 -6
- package/src/runtime/control-plane/launcher/launch-reservation-store.ts +54 -5
- package/src/runtime/control-plane/launcher/thin-launcher.ts +56 -7
- package/src/runtime/control-plane/persistence/requirement-store.ts +0 -12
- package/src/runtime/control-plane/repo-actor/registry.ts +4 -2
- package/src/runtime/control-plane/routing/route-policy.ts +18 -6
- package/src/runtime/control-plane/routing/workspace-admission.ts +70 -0
- package/src/runtime/evidence/process-check-execution.ts +18 -0
- package/src/runtime/execution/jobs/child-reference.ts +6 -2
- package/src/runtime/execution/process-runtime/check-result.ts +53 -18
- package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +7 -1
- package/src/runtime/execution/process-runtime/command-facade.ts +39 -17
- package/src/runtime/execution/process-runtime/lightweight-managed.ts +20 -3
- package/src/runtime/execution/process-runtime/persisted-check.ts +4 -1
- package/src/runtime/execution/process-runtime/runtime.ts +10 -0
- package/src/runtime/execution/process-runtime/types.ts +2 -12
- package/src/runtime/execution/work-activity.ts +21 -0
- package/src/runtime/execution/workers/executor.ts +18 -13
- package/src/runtime/gateway/mcp/execution-tools.ts +35 -2930
- package/src/runtime/gateway/mcp/legacy-ios-tool-adapter.ts +61 -0
- package/src/runtime/gateway/mcp/router.ts +2 -2
- package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +21 -2
- package/src/runtime/gateway/mcp/runtime-tools.ts +815 -1015
- package/src/runtime/plugins/app-store-connect-adapter.ts +93 -28
- package/src/runtime/plugins/browser-adapter.ts +256 -1083
- package/src/runtime/plugins/browser-handoff-host.ts +2 -25
- package/src/runtime/plugins/browser-handoff.ts +18 -3
- package/src/runtime/plugins/browser-macos-bridge.ts +121 -16
- package/src/runtime/plugins/browser-manifest-surface.ts +603 -0
- package/src/runtime/plugins/browser-native-session-service.ts +222 -0
- package/src/runtime/plugins/browser-runtime-contract.ts +2 -0
- package/src/runtime/plugins/browser-runtime.ts +10 -0
- package/src/runtime/plugins/browser-session-store.ts +121 -0
- package/src/runtime/plugins/browser-session-types.ts +98 -0
- package/src/runtime/plugins/desktop-operator-registration.ts +4 -4
- package/src/runtime/plugins/external-adapter.ts +92 -58
- package/src/runtime/plugins/macos-capability-broker.ts +0 -8
- package/src/runtime/plugins/store.ts +66 -9
- package/src/runtime/plugins/types.ts +3 -1
- package/src/runtime/recovery/maintenance-executor.ts +61 -25
- package/src/runtime/root/package-connector-service.ts +46 -4
- package/src/runtime/root/package-runtime-release.ts +3 -2
- package/src/runtime/root/package-runtime-service.ts +48 -3
- package/src/runtime/root/release-manifest.ts +137 -16
- package/src/runtime/root/release-materialize.ts +109 -35
- package/src/runtime/root/types.ts +10 -0
- package/src/runtime/standalone-recovery/core.ts +425 -194
- package/src/runtime/standalone-recovery/entry.ts +1 -1
- package/src/runtime/standalone-recovery/installer.ts +1 -1
- package/src/runtime/workflow/schedules/engine.ts +113 -87
- package/src/runtime/workflow/schedules/settlement.ts +26 -23
- package/src/runtime/workflow/schedules/store.ts +79 -10
|
@@ -107,7 +107,7 @@ function assertPackageRuntimeSnapshot(snapshotRoot: string, records: PackageRunt
|
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
function stagePackageRuntimeSnapshot(sourceRoot: string, snapshotRoot: string, records: PackageRuntimeFileRecord[]): void {
|
|
110
|
+
export function stagePackageRuntimeSnapshot(sourceRoot: string, snapshotRoot: string, records: PackageRuntimeFileRecord[]): void {
|
|
111
111
|
mkdirSync(snapshotRoot, { recursive: false, mode: 0o700 });
|
|
112
112
|
for (const record of records) {
|
|
113
113
|
const source = join(sourceRoot, record.path);
|
|
@@ -156,7 +156,8 @@ function launcherSource(input: { packageRoot: string; indexPath: string; indexSh
|
|
|
156
156
|
+ `const loader=join(packageRoot,'src','runtime','shared','node-ts-loader.mjs');\n`
|
|
157
157
|
+ `const args=process.versions?.bun?[entry,...process.argv.slice(2)]:['--loader',loader,entry,...process.argv.slice(2)];\n`
|
|
158
158
|
+ `const child=spawn(process.execPath,args,{stdio:'inherit',env:process.env});\n`
|
|
159
|
-
+ `
|
|
159
|
+
+ `const managerSignalsProcessGroup=process.platform==='linux'&&Boolean(process.env.INVOCATION_ID);\n`
|
|
160
|
+
+ `for(const signal of ['SIGINT','SIGTERM','SIGHUP']){try{process.on(signal,()=>{if(!managerSignalsProcessGroup)child.kill(signal);});}catch{}}\n`
|
|
160
161
|
+ `child.on('error',(error)=>{console.error('FORGE_PACKAGE_RUNTIME_LAUNCH_FAILED: '+error.message);process.exit(1);});\n`
|
|
161
162
|
+ `child.on('exit',(code)=>process.exit(code??1));\n`;
|
|
162
163
|
}
|
|
@@ -176,6 +176,20 @@ function cleanRuntimeInstallerEnvironment(env: NodeJS.ProcessEnv, releaseEnviron
|
|
|
176
176
|
return { ...next, ...releaseEnvironment };
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
+
export function systemdRuntimeInstallCommands(unitName: string): string[][] {
|
|
180
|
+
// `enable --now` only starts an inactive unit. When Forge is already running,
|
|
181
|
+
// replacing the unit file and calling enable --now leaves the old ExecStart
|
|
182
|
+
// process alive even though release authority has advanced, fencing that
|
|
183
|
+
// process from writes. Enable and restart are intentionally separate so both
|
|
184
|
+
// first install and in-place immutable-release activation converge on the
|
|
185
|
+
// just-written unit while systemd remains the sole lifecycle owner.
|
|
186
|
+
return [
|
|
187
|
+
['--user', 'daemon-reload'],
|
|
188
|
+
['--user', 'enable', unitName],
|
|
189
|
+
['--user', 'restart', unitName],
|
|
190
|
+
];
|
|
191
|
+
}
|
|
192
|
+
|
|
179
193
|
function installSystemdUserService(controllerHome: string, env: NodeJS.ProcessEnv): string {
|
|
180
194
|
const entrypoint = activeRuntimeEntrypoint(controllerHome);
|
|
181
195
|
const launch = activeRuntimeLaunchSpec(controllerHome);
|
|
@@ -184,7 +198,7 @@ function installSystemdUserService(controllerHome: string, env: NodeJS.ProcessEn
|
|
|
184
198
|
const unitName = `${label}.service`;
|
|
185
199
|
const unitPath = join(env.HOME ?? homedir(), '.config', 'systemd', 'user', unitName);
|
|
186
200
|
atomicWrite(unitPath, renderForgeRuntimeSystemdUserUnit({ executable: entrypoint, args: launch.args, environment: launch.environment }), 0o644);
|
|
187
|
-
for (const args of
|
|
201
|
+
for (const args of systemdRuntimeInstallCommands(unitName)) {
|
|
188
202
|
const result = commandSucceeded('systemctl', args, env);
|
|
189
203
|
if (result.status !== 0) throw new Error(`FORGE_RUNTIME_SYSTEMD_INSTALL_FAILED: systemctl ${args.join(' ')}: ${(result.stderr || result.stdout || '').trim()}`);
|
|
190
204
|
}
|
|
@@ -357,6 +371,10 @@ async function cleanupActivationHelper(request: PackageRuntimeActivationRequest)
|
|
|
357
371
|
async function rollbackPackageRuntimeActivation(
|
|
358
372
|
request: PackageRuntimeActivationRequest,
|
|
359
373
|
installDarwinService: typeof installForgeRuntimeService,
|
|
374
|
+
options: {
|
|
375
|
+
restoreConnector?: boolean;
|
|
376
|
+
ensureConnectorService?: typeof ensurePackageConnectorService;
|
|
377
|
+
} = {},
|
|
360
378
|
): Promise<string[]> {
|
|
361
379
|
const errors: string[] = [];
|
|
362
380
|
const servicePaths = forgeRuntimeServicePaths(request.controllerHome);
|
|
@@ -391,6 +409,29 @@ async function rollbackPackageRuntimeActivation(
|
|
|
391
409
|
errors.push(error instanceof Error ? error.message : String(error));
|
|
392
410
|
}
|
|
393
411
|
}
|
|
412
|
+
if (options.restoreConnector && request.connectorEndpoint && request.priorAuthorityPresent) {
|
|
413
|
+
try {
|
|
414
|
+
const restored = readRuntimeReleaseAuthority(request.controllerHome);
|
|
415
|
+
if (!restored) throw new Error('FORGE_PACKAGE_CONNECTOR_ROLLBACK_AUTHORITY_MISSING');
|
|
416
|
+
const releaseRoot = dirname(resolve(restored.active.manifestPath));
|
|
417
|
+
const packageRoot = join(releaseRoot, 'package');
|
|
418
|
+
const ensureConnectorService = options.ensureConnectorService ?? ensurePackageConnectorService;
|
|
419
|
+
await ensureConnectorService({
|
|
420
|
+
release: {
|
|
421
|
+
releaseId: restored.active.releaseId,
|
|
422
|
+
releaseRoot,
|
|
423
|
+
packageRoot,
|
|
424
|
+
},
|
|
425
|
+
controllerHome: request.controllerHome,
|
|
426
|
+
endpoint: request.connectorEndpoint,
|
|
427
|
+
executable: request.nodeExecutable,
|
|
428
|
+
platform: 'darwin',
|
|
429
|
+
refresh: true,
|
|
430
|
+
});
|
|
431
|
+
} catch (error) {
|
|
432
|
+
errors.push(`primary Connector rollback failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
394
435
|
return errors;
|
|
395
436
|
}
|
|
396
437
|
|
|
@@ -421,6 +462,7 @@ export async function activateScheduledPackageRuntimeService(
|
|
|
421
462
|
release: request.release,
|
|
422
463
|
controllerHome: request.controllerHome,
|
|
423
464
|
endpoint: request.connectorEndpoint,
|
|
465
|
+
executable: request.nodeExecutable,
|
|
424
466
|
platform: 'darwin',
|
|
425
467
|
refresh: request.refreshConnector === true,
|
|
426
468
|
});
|
|
@@ -428,7 +470,10 @@ export async function activateScheduledPackageRuntimeService(
|
|
|
428
470
|
return writeActivationReceipt(request, 'activated', { servicePath: paths.installedPlistPath });
|
|
429
471
|
} catch (error) {
|
|
430
472
|
const detail = error instanceof Error ? error.message : String(error);
|
|
431
|
-
const rollbackErrors = await rollbackPackageRuntimeActivation(request, installDarwinService
|
|
473
|
+
const rollbackErrors = await rollbackPackageRuntimeActivation(request, installDarwinService, {
|
|
474
|
+
restoreConnector: Boolean(request.connectorEndpoint),
|
|
475
|
+
ensureConnectorService,
|
|
476
|
+
});
|
|
432
477
|
writeActivationReceipt(request, 'failed+rollback', {
|
|
433
478
|
error: detail,
|
|
434
479
|
rollbackSucceeded: rollbackErrors.length === 0,
|
|
@@ -587,7 +632,7 @@ export async function installPackageRuntimeService(
|
|
|
587
632
|
if (!connectorEndpoint || base.status === 'activation_scheduled') return base;
|
|
588
633
|
const ensureConnectorService = dependencies.ensureConnectorService ?? ensurePackageConnectorService;
|
|
589
634
|
const connector = await ensureConnectorService({
|
|
590
|
-
release, controllerHome, endpoint: connectorEndpoint, platform, env, forcePortable: options.forcePortable === true, refresh: options.refreshConnector === true,
|
|
635
|
+
release, controllerHome, endpoint: connectorEndpoint, executable: process.execPath, platform, env, forcePortable: options.forcePortable === true, refresh: options.refreshConnector === true,
|
|
591
636
|
});
|
|
592
637
|
return { ...base, connector };
|
|
593
638
|
}
|
|
@@ -13,6 +13,77 @@ function canonicalExistingPathIdentity(path: string): string {
|
|
|
13
13
|
return existsSync(resolved) ? realpathSync(resolved) : resolved;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
function requireSha256Identity(value: unknown, field: string): string {
|
|
17
|
+
const identity = requireString(value, field);
|
|
18
|
+
if (!/^sha256:[a-f0-9]{64}$/i.test(identity)) {
|
|
19
|
+
throw new Error(`RELEASE_MANIFEST_INVALID: ${field} must be sha256:<64 hex>`);
|
|
20
|
+
}
|
|
21
|
+
return identity;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
type RuntimeComponentPair<KEntry extends keyof RuntimeReleaseManifest, KIdentity extends keyof RuntimeReleaseManifest> = Pick<
|
|
25
|
+
RuntimeReleaseManifest,
|
|
26
|
+
KEntry | KIdentity
|
|
27
|
+
>;
|
|
28
|
+
|
|
29
|
+
function optionalRuntimeComponent<
|
|
30
|
+
KEntry extends keyof RuntimeReleaseManifest,
|
|
31
|
+
KIdentity extends keyof RuntimeReleaseManifest,
|
|
32
|
+
>(input: {
|
|
33
|
+
value: Record<string, unknown>;
|
|
34
|
+
entryField: KEntry;
|
|
35
|
+
identityField: KIdentity;
|
|
36
|
+
canonicalEntry: RuntimeReleaseManifest[KEntry];
|
|
37
|
+
}): RuntimeComponentPair<KEntry, KIdentity> | undefined {
|
|
38
|
+
const rawEntry = input.value[input.entryField as string];
|
|
39
|
+
const rawIdentity = input.value[input.identityField as string];
|
|
40
|
+
if (rawEntry === undefined && rawIdentity === undefined) return undefined;
|
|
41
|
+
const entry = requireString(rawEntry, input.entryField as string);
|
|
42
|
+
if (entry !== input.canonicalEntry) {
|
|
43
|
+
throw new Error(`RELEASE_MANIFEST_INVALID: ${String(input.entryField)} must be ${String(input.canonicalEntry)}, got ${entry}`);
|
|
44
|
+
}
|
|
45
|
+
const identity = requireSha256Identity(rawIdentity, input.identityField as string);
|
|
46
|
+
return {
|
|
47
|
+
[input.entryField]: input.canonicalEntry,
|
|
48
|
+
[input.identityField]: identity,
|
|
49
|
+
} as RuntimeComponentPair<KEntry, KIdentity>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const COMPILED_RUNTIME_RELEASE_COMPONENT_FIELDS = [
|
|
53
|
+
'diagnosticEntrypoint', 'diagnosticArtifactIdentity',
|
|
54
|
+
'browserNodeBridgeEntrypoint', 'browserNodeBridgeArtifactIdentity',
|
|
55
|
+
'browserHandoffEntrypoint', 'browserHandoffArtifactIdentity',
|
|
56
|
+
'processRunnerEntrypoint', 'processRunnerArtifactIdentity',
|
|
57
|
+
'checkRunnerEntrypoint', 'checkRunnerArtifactIdentity',
|
|
58
|
+
'pluginActionSidecarEntrypoint', 'pluginActionSidecarArtifactIdentity',
|
|
59
|
+
'externalPluginProbeEntrypoint', 'externalPluginProbeArtifactIdentity',
|
|
60
|
+
'codeGraphNodeEntrypoint', 'codeGraphNodeArtifactIdentity',
|
|
61
|
+
'codeGraphSidecarEntrypoint', 'codeGraphSidecarArtifactIdentity',
|
|
62
|
+
'codeGraphLibraryRoot', 'codeGraphLibraryArtifactIdentity',
|
|
63
|
+
'packageRoot', 'packageArtifactIdentity',
|
|
64
|
+
'controllerUiRoot', 'controllerUiArtifactIdentity',
|
|
65
|
+
] as const satisfies readonly (keyof RuntimeReleaseManifest)[];
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Compiled self-host candidates have a closed execution surface. Package
|
|
69
|
+
* launcher releases are a separate source-backed release form and therefore
|
|
70
|
+
* intentionally do not satisfy this contract.
|
|
71
|
+
*/
|
|
72
|
+
export type CompleteCompiledRuntimeReleaseManifest = RuntimeReleaseManifest & Required<Pick<
|
|
73
|
+
RuntimeReleaseManifest,
|
|
74
|
+
typeof COMPILED_RUNTIME_RELEASE_COMPONENT_FIELDS[number]
|
|
75
|
+
>>;
|
|
76
|
+
|
|
77
|
+
export function requireCompleteCompiledRuntimeReleaseManifest(
|
|
78
|
+
manifest: RuntimeReleaseManifest,
|
|
79
|
+
): asserts manifest is CompleteCompiledRuntimeReleaseManifest {
|
|
80
|
+
for (const field of COMPILED_RUNTIME_RELEASE_COMPONENT_FIELDS) {
|
|
81
|
+
if (manifest[field] === undefined) {
|
|
82
|
+
throw new Error(`RUNTIME_RELEASE_COMPILED_COMPONENT_MISSING: ${field}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
16
87
|
export function loadRuntimeReleaseManifest(
|
|
17
88
|
path: string,
|
|
18
89
|
expectedControllerHome: string,
|
|
@@ -50,18 +121,60 @@ export function loadRuntimeReleaseManifest(
|
|
|
50
121
|
`RELEASE_DATABASE_SCHEMA_INCOMPATIBLE: runtime=${CONTROL_PLANE_SCHEMA_VERSION} supported=${minimum}-${maximum}`,
|
|
51
122
|
);
|
|
52
123
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
124
|
+
const diagnostic = optionalRuntimeComponent({
|
|
125
|
+
value,
|
|
126
|
+
entryField: 'diagnosticEntrypoint',
|
|
127
|
+
identityField: 'diagnosticArtifactIdentity',
|
|
128
|
+
canonicalEntry: 'forge-cli',
|
|
129
|
+
});
|
|
130
|
+
const browserNodeBridge = optionalRuntimeComponent({
|
|
131
|
+
value,
|
|
132
|
+
entryField: 'browserNodeBridgeEntrypoint',
|
|
133
|
+
identityField: 'browserNodeBridgeArtifactIdentity',
|
|
134
|
+
canonicalEntry: 'browser-node-bridge-host.js',
|
|
135
|
+
});
|
|
136
|
+
const browserHandoff = optionalRuntimeComponent({
|
|
137
|
+
value,
|
|
138
|
+
entryField: 'browserHandoffEntrypoint',
|
|
139
|
+
identityField: 'browserHandoffArtifactIdentity',
|
|
140
|
+
canonicalEntry: 'browser-handoff-host.js',
|
|
141
|
+
});
|
|
142
|
+
const processRunner = optionalRuntimeComponent({
|
|
143
|
+
value,
|
|
144
|
+
entryField: 'processRunnerEntrypoint',
|
|
145
|
+
identityField: 'processRunnerArtifactIdentity',
|
|
146
|
+
canonicalEntry: 'process-runner.js',
|
|
147
|
+
});
|
|
148
|
+
const checkRunner = optionalRuntimeComponent({
|
|
149
|
+
value,
|
|
150
|
+
entryField: 'checkRunnerEntrypoint',
|
|
151
|
+
identityField: 'checkRunnerArtifactIdentity',
|
|
152
|
+
canonicalEntry: 'forge-check-runner',
|
|
153
|
+
});
|
|
154
|
+
const pluginActionSidecar = optionalRuntimeComponent({
|
|
155
|
+
value,
|
|
156
|
+
entryField: 'pluginActionSidecarEntrypoint',
|
|
157
|
+
identityField: 'pluginActionSidecarArtifactIdentity',
|
|
158
|
+
canonicalEntry: 'forge-plugin-action-sidecar',
|
|
159
|
+
});
|
|
160
|
+
const externalPluginProbe = optionalRuntimeComponent({
|
|
161
|
+
value,
|
|
162
|
+
entryField: 'externalPluginProbeEntrypoint',
|
|
163
|
+
identityField: 'externalPluginProbeArtifactIdentity',
|
|
164
|
+
canonicalEntry: 'external-unix-socket-probe.cjs',
|
|
165
|
+
});
|
|
166
|
+
const packageSnapshot = optionalRuntimeComponent({
|
|
167
|
+
value,
|
|
168
|
+
entryField: 'packageRoot',
|
|
169
|
+
identityField: 'packageArtifactIdentity',
|
|
170
|
+
canonicalEntry: 'package',
|
|
171
|
+
});
|
|
172
|
+
const controllerUi = optionalRuntimeComponent({
|
|
173
|
+
value,
|
|
174
|
+
entryField: 'controllerUiRoot',
|
|
175
|
+
identityField: 'controllerUiArtifactIdentity',
|
|
176
|
+
canonicalEntry: 'ui-dist',
|
|
177
|
+
});
|
|
65
178
|
const browserAutomationHelperFields = [
|
|
66
179
|
value.browserAutomationHelperEntrypoint,
|
|
67
180
|
value.browserAutomationHelperArtifactIdentity,
|
|
@@ -112,11 +225,11 @@ export function loadRuntimeReleaseManifest(
|
|
|
112
225
|
}
|
|
113
226
|
codeGraphRuntime = {
|
|
114
227
|
codeGraphNodeEntrypoint: 'codegraph-node',
|
|
115
|
-
codeGraphNodeArtifactIdentity:
|
|
228
|
+
codeGraphNodeArtifactIdentity: requireSha256Identity(value.codeGraphNodeArtifactIdentity, 'codeGraphNodeArtifactIdentity'),
|
|
116
229
|
codeGraphSidecarEntrypoint: 'codegraph-sidecar.cjs',
|
|
117
|
-
codeGraphSidecarArtifactIdentity:
|
|
230
|
+
codeGraphSidecarArtifactIdentity: requireSha256Identity(value.codeGraphSidecarArtifactIdentity, 'codeGraphSidecarArtifactIdentity'),
|
|
118
231
|
codeGraphLibraryRoot: 'codegraph-lib',
|
|
119
|
-
codeGraphLibraryArtifactIdentity:
|
|
232
|
+
codeGraphLibraryArtifactIdentity: requireSha256Identity(value.codeGraphLibraryArtifactIdentity, 'codeGraphLibraryArtifactIdentity'),
|
|
120
233
|
};
|
|
121
234
|
}
|
|
122
235
|
|
|
@@ -136,9 +249,17 @@ export function loadRuntimeReleaseManifest(
|
|
|
136
249
|
releaseId: requireString(value.releaseId, 'releaseId'),
|
|
137
250
|
artifactIdentity: requireString(value.artifactIdentity, 'artifactIdentity'),
|
|
138
251
|
entrypoint: 'forge-runtime',
|
|
139
|
-
...(
|
|
252
|
+
...(diagnostic ?? {}),
|
|
253
|
+
...(browserNodeBridge ?? {}),
|
|
254
|
+
...(browserHandoff ?? {}),
|
|
255
|
+
...(processRunner ?? {}),
|
|
256
|
+
...(checkRunner ?? {}),
|
|
257
|
+
...(pluginActionSidecar ?? {}),
|
|
258
|
+
...(externalPluginProbe ?? {}),
|
|
140
259
|
...(browserAutomationHelper ?? {}),
|
|
141
260
|
...(codeGraphRuntime ?? {}),
|
|
261
|
+
...(packageSnapshot ?? {}),
|
|
262
|
+
...(controllerUi ?? {}),
|
|
142
263
|
arguments: argumentsValue as string[],
|
|
143
264
|
configurationSchemaVersion: 1,
|
|
144
265
|
controllerHome,
|
|
@@ -5,6 +5,8 @@ import { dirname, join, relative, resolve } from 'path';
|
|
|
5
5
|
import { runProcess } from '../../effects/process-runner';
|
|
6
6
|
import { resolveBunExecutable } from '../shared/process-environment';
|
|
7
7
|
import { CONTROL_PLANE_SCHEMA_VERSION } from '../control-plane/persistence/sqlite-store';
|
|
8
|
+
import { loadRuntimeReleaseManifest, requireCompleteCompiledRuntimeReleaseManifest } from './release-manifest';
|
|
9
|
+
import { packageRuntimeFileIndex, stagePackageRuntimeSnapshot } from './package-runtime-release';
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* Stage one immutable Forge Runtime release below Controller Home. The staged
|
|
@@ -24,6 +26,7 @@ export interface MacOSRuntimeCodeSigning {
|
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
export interface StagedRuntimeRelease {
|
|
29
|
+
controllerHome: string;
|
|
27
30
|
releasePath: string;
|
|
28
31
|
manifestPath: string;
|
|
29
32
|
releaseId: string;
|
|
@@ -38,6 +41,7 @@ export interface StagedRuntimeRelease {
|
|
|
38
41
|
codeGraphNodeArtifactIdentity?: string;
|
|
39
42
|
codeGraphSidecarArtifactIdentity?: string;
|
|
40
43
|
codeGraphLibraryArtifactIdentity?: string;
|
|
44
|
+
packageArtifactIdentity?: string;
|
|
41
45
|
controllerUiArtifactIdentity?: string;
|
|
42
46
|
macosCodeSigning?: MacOSRuntimeCodeSigning;
|
|
43
47
|
manifestSha256: string;
|
|
@@ -309,6 +313,13 @@ export function stageRuntimeReleaseFromCandidateSource(input: {
|
|
|
309
313
|
let rawManifest: Record<string, unknown>;
|
|
310
314
|
try { rawManifest = JSON.parse(readFileSync(manifestPath, 'utf8')) as Record<string, unknown>; }
|
|
311
315
|
catch (error) { throw new Error(`RUNTIME_RELEASE_CANDIDATE_MANIFEST_INVALID: ${error instanceof Error ? error.message : String(error)}`); }
|
|
316
|
+
const manifest = loadRuntimeReleaseManifest(manifestPath, controllerHome);
|
|
317
|
+
requireCompleteCompiledRuntimeReleaseManifest(manifest);
|
|
318
|
+
if (manifest.releaseId !== receipt.releaseId
|
|
319
|
+
|| manifest.artifactIdentity !== receipt.artifactIdentity
|
|
320
|
+
|| manifest.sourceCommit !== receipt.sourceCommit) {
|
|
321
|
+
throw new Error('RUNTIME_RELEASE_CANDIDATE_MANIFEST_RECEIPT_MISMATCH');
|
|
322
|
+
}
|
|
312
323
|
const platform = dependencies.platform ?? process.platform;
|
|
313
324
|
const macosCodeSigning = parseMacOSRuntimeCodeSigning(rawManifest.macosCodeSigning, 'RUNTIME_RELEASE_CANDIDATE_SIGNING_INVALID');
|
|
314
325
|
if (platform === 'darwin') {
|
|
@@ -322,15 +333,30 @@ export function stageRuntimeReleaseFromCandidateSource(input: {
|
|
|
322
333
|
}
|
|
323
334
|
}
|
|
324
335
|
|
|
325
|
-
|
|
336
|
+
const staged: StagedRuntimeRelease = {
|
|
337
|
+
controllerHome,
|
|
326
338
|
releasePath,
|
|
327
339
|
manifestPath,
|
|
328
340
|
releaseId: receipt.releaseId,
|
|
329
341
|
artifactIdentity: receipt.artifactIdentity,
|
|
342
|
+
diagnosticArtifactIdentity: manifest.diagnosticArtifactIdentity,
|
|
343
|
+
browserNodeBridgeArtifactIdentity: manifest.browserNodeBridgeArtifactIdentity,
|
|
344
|
+
browserHandoffArtifactIdentity: manifest.browserHandoffArtifactIdentity,
|
|
345
|
+
processRunnerArtifactIdentity: manifest.processRunnerArtifactIdentity,
|
|
346
|
+
checkRunnerArtifactIdentity: manifest.checkRunnerArtifactIdentity,
|
|
347
|
+
pluginActionSidecarArtifactIdentity: manifest.pluginActionSidecarArtifactIdentity,
|
|
348
|
+
externalPluginProbeArtifactIdentity: manifest.externalPluginProbeArtifactIdentity,
|
|
349
|
+
codeGraphNodeArtifactIdentity: manifest.codeGraphNodeArtifactIdentity,
|
|
350
|
+
codeGraphSidecarArtifactIdentity: manifest.codeGraphSidecarArtifactIdentity,
|
|
351
|
+
codeGraphLibraryArtifactIdentity: manifest.codeGraphLibraryArtifactIdentity,
|
|
352
|
+
packageArtifactIdentity: manifest.packageArtifactIdentity,
|
|
353
|
+
controllerUiArtifactIdentity: manifest.controllerUiArtifactIdentity,
|
|
330
354
|
...(macosCodeSigning ? { macosCodeSigning } : {}),
|
|
331
355
|
manifestSha256: receipt.manifestSha256,
|
|
332
356
|
sourceCommit: receipt.sourceCommit,
|
|
333
357
|
};
|
|
358
|
+
assertRuntimeReleaseFiles(staged, dependencies);
|
|
359
|
+
return staged;
|
|
334
360
|
}
|
|
335
361
|
|
|
336
362
|
function defaultCompileBinary(input: { sourceRoot: string; outputPath: string; entryPath?: string }): { ok: boolean; stderr?: string; stdout?: string; error?: string } {
|
|
@@ -547,6 +573,16 @@ export function stageRuntimeRelease(input: {
|
|
|
547
573
|
cpSync(sourceControllerUiPath, controllerUiPath, { recursive: true, force: false });
|
|
548
574
|
const controllerUiArtifactIdentity = `sha256:${sha256Directory(controllerUiPath)}`;
|
|
549
575
|
|
|
576
|
+
// The persistent OAuth/Connector is source-backed even when the primary
|
|
577
|
+
// Runtime itself is compiled. Co-locate one immutable package snapshot in
|
|
578
|
+
// the same release so standalone Recovery can bind the Connector to the
|
|
579
|
+
// exact active release instead of retaining an older package release.
|
|
580
|
+
const packageRoot = 'package' as const;
|
|
581
|
+
const packagePath = join(staging, packageRoot);
|
|
582
|
+
const packageRecords = packageRuntimeFileIndex(sourceRoot);
|
|
583
|
+
stagePackageRuntimeSnapshot(sourceRoot, packagePath, packageRecords);
|
|
584
|
+
const packageArtifactIdentity = `sha256:${sha256Directory(packagePath)}`;
|
|
585
|
+
|
|
550
586
|
const manifest = {
|
|
551
587
|
schemaVersion: 1,
|
|
552
588
|
releaseId,
|
|
@@ -573,6 +609,8 @@ export function stageRuntimeRelease(input: {
|
|
|
573
609
|
codeGraphSidecarArtifactIdentity,
|
|
574
610
|
codeGraphLibraryRoot,
|
|
575
611
|
codeGraphLibraryArtifactIdentity,
|
|
612
|
+
packageRoot,
|
|
613
|
+
packageArtifactIdentity,
|
|
576
614
|
controllerUiRoot,
|
|
577
615
|
controllerUiArtifactIdentity,
|
|
578
616
|
arguments: [],
|
|
@@ -592,6 +630,7 @@ export function stageRuntimeRelease(input: {
|
|
|
592
630
|
writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, { mode: 0o600 });
|
|
593
631
|
renameSync(staging, releasePath);
|
|
594
632
|
return {
|
|
633
|
+
controllerHome: resolve(input.controllerHome),
|
|
595
634
|
releasePath,
|
|
596
635
|
manifestPath: join(releasePath, 'manifest.json'),
|
|
597
636
|
releaseId,
|
|
@@ -602,10 +641,12 @@ export function stageRuntimeRelease(input: {
|
|
|
602
641
|
browserHandoffArtifactIdentity,
|
|
603
642
|
processRunnerArtifactIdentity,
|
|
604
643
|
checkRunnerArtifactIdentity,
|
|
644
|
+
pluginActionSidecarArtifactIdentity,
|
|
605
645
|
externalPluginProbeArtifactIdentity,
|
|
606
646
|
codeGraphNodeArtifactIdentity,
|
|
607
647
|
codeGraphSidecarArtifactIdentity,
|
|
608
648
|
codeGraphLibraryArtifactIdentity,
|
|
649
|
+
packageArtifactIdentity,
|
|
609
650
|
controllerUiArtifactIdentity,
|
|
610
651
|
manifestSha256: createHash('sha256').update(`${JSON.stringify(manifest, null, 2)}\n`).digest('hex'),
|
|
611
652
|
sourceCommit,
|
|
@@ -617,13 +658,53 @@ export function stageRuntimeRelease(input: {
|
|
|
617
658
|
}
|
|
618
659
|
|
|
619
660
|
export function assertRuntimeReleaseFiles(release: StagedRuntimeRelease, dependencies: { platform?: NodeJS.Platform; inspectMacOSRuntime?: (executable: string) => MacOSRuntimeCodeSigning } = {}): void {
|
|
661
|
+
const assertRegularFile = (path: string, missingCode: string): void => {
|
|
662
|
+
if (!existsSync(path)) throw new Error(`${missingCode}: ${path}`);
|
|
663
|
+
const status = lstatSync(path);
|
|
664
|
+
if (status.isSymbolicLink() || !status.isFile()) throw new Error(`RUNTIME_RELEASE_PATH_NOT_REGULAR_FILE: ${path}`);
|
|
665
|
+
};
|
|
666
|
+
const assertExecutable = (path: string): void => {
|
|
667
|
+
if ((statSync(path).mode & 0o111) === 0) throw new Error(`RUNTIME_RELEASE_ENTRYPOINT_NOT_EXECUTABLE: ${path}`);
|
|
668
|
+
};
|
|
669
|
+
const assertFileIdentity = (path: string, expected: string): void => {
|
|
670
|
+
const actual = `sha256:${sha256(path)}`;
|
|
671
|
+
if (actual !== expected) throw new Error(`RUNTIME_RELEASE_ARTIFACT_IDENTITY_MISMATCH: ${path}`);
|
|
672
|
+
};
|
|
673
|
+
const assertDirectoryIdentity = (path: string, expected: string): void => {
|
|
674
|
+
if (!existsSync(path)) throw new Error(`RUNTIME_RELEASE_DIRECTORY_MISSING: ${path}`);
|
|
675
|
+
const status = lstatSync(path);
|
|
676
|
+
if (status.isSymbolicLink() || !status.isDirectory()) throw new Error(`RUNTIME_RELEASE_PATH_NOT_DIRECTORY: ${path}`);
|
|
677
|
+
const actual = `sha256:${sha256Directory(path)}`;
|
|
678
|
+
if (actual !== expected) throw new Error(`RUNTIME_RELEASE_ARTIFACT_IDENTITY_MISMATCH: ${path}`);
|
|
679
|
+
};
|
|
680
|
+
const assertComponentFile = (input: { path: string; identity?: string; missingCode: string; executable?: boolean }): void => {
|
|
681
|
+
if (!input.identity) return;
|
|
682
|
+
assertRegularFile(input.path, input.missingCode);
|
|
683
|
+
assertFileIdentity(input.path, input.identity);
|
|
684
|
+
if (input.executable) assertExecutable(input.path);
|
|
685
|
+
};
|
|
686
|
+
|
|
620
687
|
if (!existsSync(release.releasePath) || !existsSync(release.manifestPath)) {
|
|
621
688
|
throw new Error(`RUNTIME_RELEASE_FILES_MISSING: ${release.releasePath}`);
|
|
622
689
|
}
|
|
623
|
-
const
|
|
624
|
-
if (
|
|
625
|
-
|
|
690
|
+
const releasesRoot = join(resolve(release.controllerHome), 'runtime', 'releases');
|
|
691
|
+
if (resolve(release.releasePath) !== join(releasesRoot, release.releaseId)
|
|
692
|
+
|| resolve(release.manifestPath) !== join(release.releasePath, 'manifest.json')) {
|
|
693
|
+
throw new Error('RUNTIME_RELEASE_PATH_OUTSIDE_CONTROLLER_HOME');
|
|
694
|
+
}
|
|
695
|
+
const releaseStatus = lstatSync(release.releasePath);
|
|
696
|
+
const manifestStatus = lstatSync(release.manifestPath);
|
|
697
|
+
if (releaseStatus.isSymbolicLink() || !releaseStatus.isDirectory()
|
|
698
|
+
|| manifestStatus.isSymbolicLink() || !manifestStatus.isFile()) {
|
|
699
|
+
throw new Error(`RUNTIME_RELEASE_PATH_NOT_PHYSICAL: ${release.releasePath}`);
|
|
626
700
|
}
|
|
701
|
+
if (sha256(release.manifestPath) !== release.manifestSha256) {
|
|
702
|
+
throw new Error('RUNTIME_RELEASE_MANIFEST_IDENTITY_MISMATCH');
|
|
703
|
+
}
|
|
704
|
+
const runtimePath = join(release.releasePath, 'forge-runtime');
|
|
705
|
+
assertRegularFile(runtimePath, 'RUNTIME_RELEASE_ENTRYPOINT_MISSING');
|
|
706
|
+
assertExecutable(runtimePath);
|
|
707
|
+
assertFileIdentity(runtimePath, release.artifactIdentity);
|
|
627
708
|
const platform = dependencies.platform ?? process.platform;
|
|
628
709
|
if (platform === 'darwin' && release.macosCodeSigning) {
|
|
629
710
|
const actual = (dependencies.inspectMacOSRuntime ?? inspectMacOSRuntimeCodeSigning)(runtimePath);
|
|
@@ -634,38 +715,31 @@ export function assertRuntimeReleaseFiles(release: StagedRuntimeRelease, depende
|
|
|
634
715
|
throw new Error('RUNTIME_RELEASE_MACOS_SIGNING_MISMATCH');
|
|
635
716
|
}
|
|
636
717
|
}
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
}
|
|
646
|
-
if (release.
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
if (release.pluginActionSidecarArtifactIdentity && !existsSync(join(release.releasePath, 'forge-plugin-action-sidecar'))) {
|
|
653
|
-
throw new Error(`RUNTIME_RELEASE_PLUGIN_ACTION_SIDECAR_MISSING: ${join(release.releasePath, 'forge-plugin-action-sidecar')}`);
|
|
654
|
-
}
|
|
655
|
-
if (release.externalPluginProbeArtifactIdentity && !existsSync(join(release.releasePath, 'external-unix-socket-probe.cjs'))) {
|
|
656
|
-
throw new Error(`RUNTIME_RELEASE_EXTERNAL_PLUGIN_PROBE_MISSING: ${join(release.releasePath, 'external-unix-socket-probe.cjs')}`);
|
|
657
|
-
}
|
|
658
|
-
if (release.codeGraphNodeArtifactIdentity && !existsSync(join(release.releasePath, 'codegraph-node'))) {
|
|
659
|
-
throw new Error(`RUNTIME_RELEASE_CODEGRAPH_NODE_MISSING: ${join(release.releasePath, 'codegraph-node')}`);
|
|
660
|
-
}
|
|
661
|
-
if (release.codeGraphSidecarArtifactIdentity && !existsSync(join(release.releasePath, 'codegraph-sidecar.cjs'))) {
|
|
662
|
-
throw new Error(`RUNTIME_RELEASE_CODEGRAPH_SIDECAR_MISSING: ${join(release.releasePath, 'codegraph-sidecar.cjs')}`);
|
|
718
|
+
assertComponentFile({ path: join(release.releasePath, 'forge-cli'), identity: release.diagnosticArtifactIdentity, missingCode: 'RUNTIME_RELEASE_DIAGNOSTIC_ENTRYPOINT_MISSING', executable: true });
|
|
719
|
+
assertComponentFile({ path: join(release.releasePath, 'browser-node-bridge-host.js'), identity: release.browserNodeBridgeArtifactIdentity, missingCode: 'RUNTIME_RELEASE_BROWSER_NODE_HOST_MISSING', executable: true });
|
|
720
|
+
assertComponentFile({ path: join(release.releasePath, 'browser-handoff-host.js'), identity: release.browserHandoffArtifactIdentity, missingCode: 'RUNTIME_RELEASE_BROWSER_HANDOFF_HOST_MISSING', executable: true });
|
|
721
|
+
assertComponentFile({ path: join(release.releasePath, 'process-runner.js'), identity: release.processRunnerArtifactIdentity, missingCode: 'RUNTIME_RELEASE_PROCESS_RUNNER_MISSING', executable: true });
|
|
722
|
+
assertComponentFile({ path: join(release.releasePath, 'forge-check-runner'), identity: release.checkRunnerArtifactIdentity, missingCode: 'RUNTIME_RELEASE_CHECK_RUNNER_MISSING', executable: true });
|
|
723
|
+
assertComponentFile({ path: join(release.releasePath, 'forge-plugin-action-sidecar'), identity: release.pluginActionSidecarArtifactIdentity, missingCode: 'RUNTIME_RELEASE_PLUGIN_ACTION_SIDECAR_MISSING', executable: true });
|
|
724
|
+
assertComponentFile({ path: join(release.releasePath, 'external-unix-socket-probe.cjs'), identity: release.externalPluginProbeArtifactIdentity, missingCode: 'RUNTIME_RELEASE_EXTERNAL_PLUGIN_PROBE_MISSING', executable: true });
|
|
725
|
+
assertComponentFile({ path: join(release.releasePath, 'codegraph-node'), identity: release.codeGraphNodeArtifactIdentity, missingCode: 'RUNTIME_RELEASE_CODEGRAPH_NODE_MISSING', executable: true });
|
|
726
|
+
assertComponentFile({ path: join(release.releasePath, 'codegraph-sidecar.cjs'), identity: release.codeGraphSidecarArtifactIdentity, missingCode: 'RUNTIME_RELEASE_CODEGRAPH_SIDECAR_MISSING', executable: true });
|
|
727
|
+
if (release.codeGraphLibraryArtifactIdentity) {
|
|
728
|
+
const libraryRoot = join(release.releasePath, 'codegraph-lib');
|
|
729
|
+
if (!existsSync(join(libraryRoot, 'dist', 'index.js'))) {
|
|
730
|
+
throw new Error(`RUNTIME_RELEASE_CODEGRAPH_LIBRARY_MISSING: ${join(libraryRoot, 'dist', 'index.js')}`);
|
|
731
|
+
}
|
|
732
|
+
assertDirectoryIdentity(libraryRoot, release.codeGraphLibraryArtifactIdentity);
|
|
663
733
|
}
|
|
664
|
-
if (release.
|
|
665
|
-
|
|
734
|
+
if (release.packageArtifactIdentity) {
|
|
735
|
+
const packageRoot = join(release.releasePath, 'package');
|
|
736
|
+
assertDirectoryIdentity(packageRoot, release.packageArtifactIdentity);
|
|
666
737
|
}
|
|
667
|
-
if (release.controllerUiArtifactIdentity
|
|
668
|
-
|
|
669
|
-
|
|
738
|
+
if (release.controllerUiArtifactIdentity) {
|
|
739
|
+
const uiRoot = join(release.releasePath, 'ui-dist');
|
|
740
|
+
if (!existsSync(join(uiRoot, 'app.js')) || !existsSync(join(uiRoot, 'app.css'))) {
|
|
741
|
+
throw new Error(`RUNTIME_RELEASE_CONTROLLER_UI_MISSING: ${uiRoot}`);
|
|
742
|
+
}
|
|
743
|
+
assertDirectoryIdentity(uiRoot, release.controllerUiArtifactIdentity);
|
|
670
744
|
}
|
|
671
745
|
}
|
|
@@ -39,8 +39,14 @@ export interface RuntimeReleaseManifest {
|
|
|
39
39
|
browserNodeBridgeArtifactIdentity?: string;
|
|
40
40
|
browserHandoffEntrypoint?: 'browser-handoff-host.js';
|
|
41
41
|
browserHandoffArtifactIdentity?: string;
|
|
42
|
+
processRunnerEntrypoint?: 'process-runner.js';
|
|
43
|
+
processRunnerArtifactIdentity?: string;
|
|
44
|
+
checkRunnerEntrypoint?: 'forge-check-runner';
|
|
45
|
+
checkRunnerArtifactIdentity?: string;
|
|
42
46
|
pluginActionSidecarEntrypoint?: 'forge-plugin-action-sidecar';
|
|
43
47
|
pluginActionSidecarArtifactIdentity?: string;
|
|
48
|
+
externalPluginProbeEntrypoint?: 'external-unix-socket-probe.cjs';
|
|
49
|
+
externalPluginProbeArtifactIdentity?: string;
|
|
44
50
|
browserAutomationHelperEntrypoint?: 'browser-automation-helper';
|
|
45
51
|
browserAutomationHelperArtifactIdentity?: string;
|
|
46
52
|
browserAutomationHelperContractIdentity?: string;
|
|
@@ -50,6 +56,10 @@ export interface RuntimeReleaseManifest {
|
|
|
50
56
|
codeGraphSidecarArtifactIdentity?: string;
|
|
51
57
|
codeGraphLibraryRoot?: 'codegraph-lib';
|
|
52
58
|
codeGraphLibraryArtifactIdentity?: string;
|
|
59
|
+
packageRoot?: 'package';
|
|
60
|
+
packageArtifactIdentity?: string;
|
|
61
|
+
controllerUiRoot?: 'ui-dist';
|
|
62
|
+
controllerUiArtifactIdentity?: string;
|
|
53
63
|
arguments: string[];
|
|
54
64
|
configurationSchemaVersion: 1;
|
|
55
65
|
controllerHome: string;
|