@dsh-enhanced/plugin-control-plane 0.1.49 → 0.1.54
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 +7 -3
- package/bin/dsh-local-release-adapter.js +3 -1
- package/lib/creation-capability-journal.d.ts.map +1 -1
- package/lib/creation-capability-journal.js +29 -5
- package/lib/creation-capability-journal.js.map +1 -1
- package/lib/creation-capability-runtime.d.ts.map +1 -1
- package/lib/creation-capability-runtime.js +15 -1
- package/lib/creation-capability-runtime.js.map +1 -1
- package/lib/creation-capability-types.d.ts +13 -0
- package/lib/creation-capability-types.d.ts.map +1 -1
- package/lib/native-source-build-worker.d.ts +4 -0
- package/lib/native-source-build-worker.d.ts.map +1 -0
- package/lib/native-source-build-worker.js +87 -0
- package/lib/native-source-build-worker.js.map +1 -0
- package/lib/native-source-build.d.ts +36 -0
- package/lib/native-source-build.d.ts.map +1 -0
- package/lib/native-source-build.js +143 -0
- package/lib/native-source-build.js.map +1 -0
- package/lib/native-source-pack.d.ts +11 -0
- package/lib/native-source-pack.d.ts.map +1 -0
- package/lib/native-source-pack.js +83 -0
- package/lib/native-source-pack.js.map +1 -0
- package/lib/runtime-observer-protocol.d.ts +3 -3
- package/lib/runtime-observer-protocol.js +5 -5
- package/lib/runtime-observer-protocol.js.map +1 -1
- package/lib/service.d.ts +1 -0
- package/lib/service.d.ts.map +1 -1
- package/lib/service.js +123 -61
- package/lib/service.js.map +1 -1
- package/lib/source-approval-authority.d.ts.map +1 -1
- package/lib/source-approval-authority.js +1 -0
- package/lib/source-approval-authority.js.map +1 -1
- package/lib/source-build.d.ts +26 -8
- package/lib/source-build.d.ts.map +1 -1
- package/lib/source-build.js +170 -51
- package/lib/source-build.js.map +1 -1
- package/lib/source-creation.js +1 -1
- package/lib/source-creation.js.map +1 -1
- package/lib/source-job-types.d.ts +9 -1
- package/lib/source-job-types.d.ts.map +1 -1
- package/lib/source-jobs.d.ts +3 -0
- package/lib/source-jobs.d.ts.map +1 -1
- package/lib/source-jobs.js +39 -4
- package/lib/source-jobs.js.map +1 -1
- package/lib/store.d.ts.map +1 -1
- package/lib/store.js +50 -5
- package/lib/store.js.map +1 -1
- package/lib/types.d.ts +14 -1
- package/lib/types.d.ts.map +1 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +8 -7
package/lib/service.js
CHANGED
|
@@ -26,6 +26,9 @@ import { adoptSourceRelease, validateSourceAdoptionConfig } from './source-adopt
|
|
|
26
26
|
import { Ed25519ApprovalAuthority } from './approval.js';
|
|
27
27
|
import { ControlPlaneStore, MODIFY_GENERATOR_DIGEST, controlPlaneDigest } from './store.js';
|
|
28
28
|
import { runDockerPreparedChecks, validateSourceBuildConfig } from './source-build.js';
|
|
29
|
+
import { runNativePreparedChecks } from './native-source-build.js';
|
|
30
|
+
import { NativeMacVerifierRunner } from '@dsh-enhanced/assistant-isolation';
|
|
31
|
+
import { NATIVE_SOURCE_COMPILER } from './native-source-build-worker.js';
|
|
29
32
|
import { awaitSourceSignal, inspectSourceContext, inspectSourceTargetsContext } from './source-context.js';
|
|
30
33
|
import { inspectSourceRevisionContext, prepareRevisedPluginWorkspace, verifyRevisedPluginWorkspace } from './source-revision.js';
|
|
31
34
|
import { inspectSourceCreationContext, prepareCreatedPluginWorkspace, validateSourceCreationFiles, verifyCreatedPluginWorkspace } from './source-creation.js';
|
|
@@ -133,6 +136,13 @@ export function normalizeControlPlaneConfig(input) {
|
|
|
133
136
|
validateSourceApprovalClientConfig(config.sourceApprovals);
|
|
134
137
|
if (config.sourceBuild !== undefined)
|
|
135
138
|
validateSourceBuildConfig(config.sourceBuild);
|
|
139
|
+
if (config.sourceBuild !== undefined && 'backend' in config.sourceBuild) {
|
|
140
|
+
if (!config.sourceJobs?.allowedModes || config.sourceJobs.allowedModes.some(mode => mode === 'modify')
|
|
141
|
+
|| config.sourceReleases !== undefined || config.sourceReleaseExecution !== undefined
|
|
142
|
+
|| config.sourceAdoptions !== undefined || config.sourceApprovals !== undefined) {
|
|
143
|
+
throw new Error('plugin-control-plane: native source build only supports Host-scaffolded create/revise-created');
|
|
144
|
+
}
|
|
145
|
+
}
|
|
136
146
|
if (config.sourceReleases !== undefined) {
|
|
137
147
|
validateSourceReleaseClientConfig(config.sourceReleases);
|
|
138
148
|
if (!config.sourceApprovals || config.sourceBuild?.versioning !== 'patch')
|
|
@@ -251,6 +261,7 @@ export class PluginControlPlaneService extends Service {
|
|
|
251
261
|
liveRuntime;
|
|
252
262
|
assertLiveRuntime;
|
|
253
263
|
sourceRuntime;
|
|
264
|
+
nativeSourceRunner;
|
|
254
265
|
sourceRuntimes = new Set();
|
|
255
266
|
creationCapabilityRuntime;
|
|
256
267
|
creationCapabilityRuntimes = new Set();
|
|
@@ -618,68 +629,109 @@ export class PluginControlPlaneService extends Service {
|
|
|
618
629
|
throw error;
|
|
619
630
|
}
|
|
620
631
|
}
|
|
621
|
-
const
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
632
|
+
const sourceBuild = this.config.sourceBuild;
|
|
633
|
+
let nativeRunner;
|
|
634
|
+
try {
|
|
635
|
+
nativeRunner = 'backend' in sourceBuild ? new NativeMacVerifierRunner({ backend: 'macos-seatbelt',
|
|
636
|
+
stateRoot: sourceBuild.stateRoot, authorityDigest: sourceBuild.authorityDigest,
|
|
637
|
+
runtime: sourceBuild.runtime, source: NATIVE_SOURCE_COMPILER, expiresAt: sourceBuild.expiresAt,
|
|
638
|
+
maxRuns: sourceBuild.maxRuns, maxTotalDurationMs: sourceBuild.maxTotalDurationMs,
|
|
639
|
+
maxDurationMs: sourceBuild.timeoutMs, maxOutputBytes: sourceBuild.outputBytes }) : undefined;
|
|
640
|
+
}
|
|
641
|
+
catch (error) {
|
|
642
|
+
unsubscribeTaskChanges?.();
|
|
643
|
+
if (capabilities) {
|
|
644
|
+
await capabilities.close();
|
|
645
|
+
this.creationCapabilityRuntimes.delete(capabilities);
|
|
646
|
+
}
|
|
647
|
+
throw error;
|
|
648
|
+
}
|
|
649
|
+
this.nativeSourceRunner = nativeRunner;
|
|
650
|
+
let runtime;
|
|
651
|
+
try {
|
|
652
|
+
runtime = new SourceJobRuntime({ config: this.config.sourceJobs, build: sourceBuild, statePath: this.config.statePath, store: this.store,
|
|
653
|
+
ports: {
|
|
654
|
+
automations: {
|
|
655
|
+
registerHostExecutor: executor => current('automations').registerHostExecutor(executor),
|
|
656
|
+
reconcileSystem: request => current('automations').reconcileSystem(request),
|
|
657
|
+
reconcileSystemExact: request => current('automations').reconcileSystemExact(request),
|
|
658
|
+
pauseSystemOwned: request => current('automations').pauseSystemOwned(request),
|
|
659
|
+
inspectSystemOwnedActivation: request => current('automations').inspectSystemOwnedActivation(request),
|
|
660
|
+
inspectSystemOwned: request => current('automations').inspectSystemOwned(request),
|
|
661
|
+
},
|
|
662
|
+
delivery: { validateOwnerRoute: request => current('delivery').validateOwnerRoute(request) },
|
|
663
|
+
}, withGapSourceFence: (gapId, owner, callback) => this.taskGaps.withCurrent(gapId, owner, callback),
|
|
664
|
+
assertGrowthRun: (run, gapId, owner, generation) => this.assertSourceGrowthRun(run, gapId, owner, generation),
|
|
665
|
+
...(this.config.revisionVerifications ? { inspectRevisionParent: this.inspectRevisionParent,
|
|
666
|
+
verifyPreparedRevision: (job, signal) => this.verifyPreparedRevision(job, signal, () => jobsCtx.get('assistantVerifier')) } : {}),
|
|
667
|
+
...(this.config.revisionRegressions ? { verifyPreparedRevisionRegression: (job, signal) => this.verifyPreparedRevisionRegression(job, signal, () => jobsCtx.get('assistantVerifier')) } : {}),
|
|
668
|
+
...(this.config.creationVerifications ? { verifyPreparedCreation: (job, signal) => this.verifyPreparedCreation(job, signal, () => jobsCtx.get('assistantVerifier')) } : {}),
|
|
669
|
+
...(capabilities ? { creationAdoptionEligible: (planId) => capabilities.eligible(planId),
|
|
670
|
+
adoptVerifiedCreation: async (job, signal) => {
|
|
671
|
+
if (!job.planId)
|
|
672
|
+
throw new Error('created capability has no prepared source plan');
|
|
673
|
+
await capabilities.adopt(job.planId, signal);
|
|
674
|
+
} } : {}),
|
|
675
|
+
...(this.config.sourceApprovals ? { approvePrepared: async (job, signal) => {
|
|
676
|
+
if (!job.planId)
|
|
677
|
+
throw new Error('source job has no prepared plan');
|
|
678
|
+
await this.requestOwnerSourceApproval({ planId: job.planId, signal, expectedTrustDigest: job.intent.trustDigest });
|
|
679
|
+
} } : {}),
|
|
680
|
+
...(this.config.sourceReleases ? { releasePrepared: async (job, signal) => {
|
|
681
|
+
if (!job.planId)
|
|
682
|
+
throw new Error('source job has no prepared plan');
|
|
683
|
+
await this.requestOwnerSourceRelease({ planId: job.planId, signal, expectedTrustDigest: job.intent.trustDigest });
|
|
684
|
+
} } : {}),
|
|
685
|
+
...(this.config.sourceReleaseExecution ? { releaseTimeoutMs: this.config.sourceReleaseExecution.timeoutMs,
|
|
686
|
+
advanceReleased: async (job, signal) => {
|
|
687
|
+
if (!job.planId)
|
|
688
|
+
throw new Error('source job has no release plan');
|
|
689
|
+
await this.advanceOwnerSourceRelease({ planId: job.planId, signal, expectedTrustDigest: job.intent.trustDigest });
|
|
690
|
+
} } : {}),
|
|
691
|
+
...(this.config.sourceAdoptions ? { adoptionTimeoutMs: this.config.sourceAdoptions.timeoutMs,
|
|
692
|
+
adoptReleased: async (job, signal, assertCurrent) => {
|
|
693
|
+
if (!job.planId)
|
|
694
|
+
throw new Error('source job has no released plan');
|
|
695
|
+
await this.adoptOwnerSourceRelease({ sourcePlanId: job.planId, signal, expectedTrustDigest: job.intent.trustDigest, assertCurrent });
|
|
696
|
+
} } : {}),
|
|
697
|
+
trust: () => this.boundTrust(), prepare: (job, signal, assertCurrent) => this.prepareSourceJob(job, signal, assertCurrent),
|
|
698
|
+
...(nativeRunner ? { inspectNativeQuiescence: (key) => nativeRunner.inspectQuiescence(key) } : {}),
|
|
699
|
+
});
|
|
700
|
+
}
|
|
701
|
+
catch (error) {
|
|
702
|
+
if (this.nativeSourceRunner === nativeRunner)
|
|
703
|
+
this.nativeSourceRunner = undefined;
|
|
704
|
+
await nativeRunner?.close();
|
|
705
|
+
unsubscribeTaskChanges?.();
|
|
706
|
+
if (capabilities) {
|
|
707
|
+
await capabilities.close();
|
|
708
|
+
this.creationCapabilityRuntimes.delete(capabilities);
|
|
709
|
+
}
|
|
710
|
+
throw error;
|
|
711
|
+
}
|
|
667
712
|
this.sourceRuntimes.add(runtime);
|
|
668
713
|
const close = async () => {
|
|
669
714
|
unsubscribeTaskChanges?.();
|
|
670
715
|
if (this.sourceRuntime === runtime)
|
|
671
716
|
this.sourceRuntime = undefined;
|
|
717
|
+
let closeError;
|
|
672
718
|
try {
|
|
673
719
|
await runtime.close();
|
|
674
720
|
}
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
721
|
+
catch (error) {
|
|
722
|
+
closeError = error;
|
|
723
|
+
}
|
|
724
|
+
if (this.nativeSourceRunner === nativeRunner)
|
|
725
|
+
this.nativeSourceRunner = undefined;
|
|
726
|
+
this.sourceRuntimes.delete(runtime);
|
|
727
|
+
if (this.creationCapabilityRuntime === capabilities)
|
|
728
|
+
this.creationCapabilityRuntime = undefined;
|
|
729
|
+
const results = await Promise.allSettled([nativeRunner?.close(), capabilities?.close()]);
|
|
730
|
+
if (capabilities)
|
|
731
|
+
this.creationCapabilityRuntimes.delete(capabilities);
|
|
732
|
+
const failures = results.filter((result) => result.status === 'rejected');
|
|
733
|
+
if (closeError !== undefined || failures.length) {
|
|
734
|
+
throw new AggregateError([...(closeError === undefined ? [] : [closeError]), ...failures.map(result => result.reason)], 'source runtime cleanup failed');
|
|
683
735
|
}
|
|
684
736
|
};
|
|
685
737
|
try {
|
|
@@ -2013,7 +2065,8 @@ export class PluginControlPlaneService extends Service {
|
|
|
2013
2065
|
if (!Number.isSafeInteger(ttlMs) || ttlMs < 900_000 || ttlMs > 86_400_000) {
|
|
2014
2066
|
throw new ControlPlaneCliError('INVALID_ARGUMENT', 'ttlMs must be an integer within 900000..86400000');
|
|
2015
2067
|
}
|
|
2016
|
-
const maximumTimeoutMs = this.config.sourceBuild
|
|
2068
|
+
const maximumTimeoutMs = this.config.sourceBuild !== undefined && !('backend' in this.config.sourceBuild)
|
|
2069
|
+
&& ['repository', 'portable-repository'].includes(this.config.sourceBuild.profile ?? '') ? 1_800_000 : 240_000;
|
|
2017
2070
|
const timeoutMs = input.timeoutMs ?? 180_000;
|
|
2018
2071
|
if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 60_000 || timeoutMs > maximumTimeoutMs) {
|
|
2019
2072
|
throw new ControlPlaneCliError('INVALID_ARGUMENT', `timeoutMs must be an integer within 60000..${maximumTimeoutMs}`);
|
|
@@ -2057,12 +2110,21 @@ export class PluginControlPlaneService extends Service {
|
|
|
2057
2110
|
// Only owner-bound creation jobs retain the exact package for the
|
|
2058
2111
|
// independent verifier. Ordinary source tools never receive these bytes.
|
|
2059
2112
|
const capturePack = (creating || revising) && this.store.getOwnerTaskFailureReference(input.gapId) !== undefined;
|
|
2060
|
-
const
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2113
|
+
const common = { worktree: isolated.worktree, baseCommit, name, scope: generated?.scope ?? [`plugins/${name}`],
|
|
2114
|
+
environment, signal, assertCurrent, preparedAt: Date.now(), ...(creation === undefined ? {} : { creation }),
|
|
2115
|
+
...(revision === undefined ? {} : { revision: { binding: revision, parentSource: parent.source,
|
|
2116
|
+
parentCertificate: parent.certificate, files: input.files } }), ...(capturePack ? { capturePack: true } : {}) };
|
|
2117
|
+
const checked = 'backend' in configured
|
|
2118
|
+
? await (async () => {
|
|
2119
|
+
if ((!creating && !revising) || sourceJob === undefined || this.nativeSourceRunner === undefined
|
|
2120
|
+
|| sourceJob.intent.nativeResource?.key !== sourceJob.id) {
|
|
2121
|
+
throw new ControlPlaneCliError('SOURCE_BOUNDARY', 'native source preparation requires a durable Host-scaffolded creation job');
|
|
2122
|
+
}
|
|
2123
|
+
return runNativePreparedChecks({ ...common, config: { ...configured, timeoutMs: Math.min(timeoutMs, configured.timeoutMs) },
|
|
2124
|
+
runner: this.nativeSourceRunner, sourceJob: { id: sourceJob.id } });
|
|
2125
|
+
})()
|
|
2126
|
+
: await runDockerPreparedChecks({ ...common, config: { ...configured, timeoutMs: Math.min(timeoutMs, configured.timeoutMs) },
|
|
2127
|
+
...(sourceJob === undefined ? {} : { sourceJob: { id: sourceJob.id, containerName: sourceJob.intent.containerName } }) });
|
|
2066
2128
|
await assertCurrent();
|
|
2067
2129
|
if (capturePack && checked.packArtifact === undefined)
|
|
2068
2130
|
throw new ControlPlaneCliError('SOURCE_BOUNDARY', 'prepared creation artifact was not captured');
|