@zq-silk/yui 0.15.7 → 0.15.9
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/ARCHITECTURE.md +194 -399
- package/ARCHITECTURE.zh-CN.md +151 -0
- package/README.md +306 -1131
- package/dist/agent/adapterCatalog.js +15 -2
- package/dist/agent/agent.js +23 -3
- package/dist/agent/argumentPolicy.js +7 -1
- package/dist/agent/connectionPlan.js +62 -0
- package/dist/agent/executionComponents.js +158 -0
- package/dist/agent/launchEnvironment.js +31 -3
- package/dist/agent/managedRuntimeEnvironment.js +3 -5
- package/dist/{turn/turn.js → agentRun/agentRun.js} +166 -109
- package/dist/{turn/turnIdentity.js → agentRun/runIdentity.js} +4 -4
- package/dist/artifacts/artifactCapability.js +74 -0
- package/dist/artifacts/artifactCommitLock.js +249 -0
- package/dist/artifacts/artifactPaths.js +151 -0
- package/dist/artifacts/gitArtifactRef.js +146 -0
- package/dist/artifacts/managedGit.js +332 -0
- package/dist/artifacts/taskArtifactRepository.js +277 -0
- package/dist/brief/taskBrief.js +12 -0
- package/dist/cli/agentConfigurationPicker.js +13 -0
- package/dist/cli/commandCatalog.js +165 -74
- package/dist/cli/interactionCandidates.js +5 -5
- package/dist/cli/interactionPolicy.js +38 -8
- package/dist/cli/invocationRouter.js +1 -1
- package/dist/cli/managedDiagnostics.js +28 -0
- package/dist/cli/operatorWizard.js +1 -7
- package/dist/cli/roleOptionOrder.js +27 -0
- package/dist/cli/roleWizard.js +50 -14
- package/dist/cli/updateOrchestrator.js +1 -1
- package/dist/cli/updatePorts.js +3 -4
- package/dist/cli.js +245 -95
- package/dist/commands/agentCommands.js +72 -14
- package/dist/commands/capabilityCommands.js +9 -6
- package/dist/commands/configCommands.js +20 -20
- package/dist/commands/deliveryGuardPreflight.js +2 -2
- package/dist/commands/executionAuditCommands.js +24 -24
- package/dist/commands/globalRoleCommands.js +1 -1
- package/dist/commands/grantCommands.js +4 -4
- package/dist/commands/operatorCommands.js +34 -9
- package/dist/commands/projectCommands.js +4 -4
- package/dist/commands/resourcesCommands.js +2 -2
- package/dist/commands/roleConfiguration.js +25 -5
- package/dist/commands/roleRuntimeGuard.js +4 -5
- package/dist/commands/sessionCommands.js +3 -7
- package/dist/commands/taskActivationCommands.js +281 -0
- package/dist/commands/taskActor.js +28 -49
- package/dist/commands/taskCommands.js +1461 -720
- package/dist/commands/taskContextCommand.js +39 -583
- package/dist/commands/taskExecutionCommands.js +32 -32
- package/dist/commands/taskInputCommands.js +40 -104
- package/dist/commands/taskIntegrationCommands.js +3 -2
- package/dist/commands/taskIntegrationQueueCommands.js +1 -1
- package/dist/commands/taskNextActionCommand.js +8 -8
- package/dist/commands/taskOverviewCommand.js +33 -45
- package/dist/commands/taskRemoteDeliveryCommand.js +2 -2
- package/dist/commands/taskRoleRuntimeStatus.js +133 -102
- package/dist/commands/telemetryCommands.js +36 -38
- package/dist/config/configCatalog.js +4 -4
- package/dist/config/yuiConfig.js +8 -8
- package/dist/context/contextSnapshot.js +10 -10
- package/dist/context/dispatchContext.js +11 -11
- package/dist/context/roleSessionContext.js +6 -3
- package/dist/context/{turnContextPack.js → runContextPack.js} +158 -81
- package/dist/context/{turnInputContract.js → runInputContract.js} +73 -60
- package/dist/context/sessionBootstrapManifest.js +21 -2
- package/dist/context/sourceRunContext.js +30 -0
- package/dist/context/taskContext.js +481 -0
- package/dist/context/wakeNotification.js +27 -27
- package/dist/controller/agentRuntimeObserver.js +21 -24
- package/dist/controller/capabilityBridge.js +17 -6
- package/dist/controller/clientRuntime.js +65 -92
- package/dist/controller/controller.js +120 -188
- package/dist/controller/fileSchedulerStoreAdapter.js +787 -887
- package/dist/controller/jobControl.js +54 -85
- package/dist/controller/resourceInventory.js +8 -27
- package/dist/controller/resourceInventoryLinux.js +12 -13
- package/dist/controller/runtime.js +529 -479
- package/dist/controller/runtimeEventInbox.js +55 -25
- package/dist/controller/runtimeEventProcessor.js +22 -31
- package/dist/controller/{runtimeHookTurnFence.js → runtimeHookRunFence.js} +91 -115
- package/dist/controller/runtimeLaunchCoordinator.js +80 -426
- package/dist/controller/runtimeObservationHook.js +14 -18
- package/dist/controller/sessionNotify.js +16 -24
- package/dist/controller/sessionOwnerReconciliation.js +168 -50
- package/dist/controller/structuredProviderObservation.js +138 -99
- package/dist/coordination/workMailbox.js +3 -3
- package/dist/coordination/workMailboxQueue.js +36 -33
- package/dist/core/boundedRpc.js +8 -1
- package/dist/core/controllerClient.js +20 -1
- package/dist/core/controllerServer.js +4 -4
- package/dist/doctor/doctor.js +13 -2
- package/dist/domain/agentResultTransport.js +9 -9
- package/dist/execution/codexThreadNaming.js +2 -8
- package/dist/execution/executionHealth.js +51 -63
- package/dist/execution/reviewMainRun.js +137 -0
- package/dist/execution/workItemExecution.js +28 -29
- package/dist/execution/workItemExecutionProjection.js +99 -107
- package/dist/execution/workItemMainRun.js +141 -0
- package/dist/executor/agentAdapter.js +227 -20
- package/dist/executor/agentConfigurationCatalog.js +126 -4
- package/dist/executor/agentConfigurationProbe.js +162 -4
- package/dist/executor/agentExecutor.js +79 -78
- package/dist/executor/effectiveLaunch.js +105 -18
- package/dist/executor/executorRegistry.js +29 -44
- package/dist/executor/fileRoleLaunchPlanner.js +229 -154
- package/dist/executor/workspacePreflightClassification.js +16 -16
- package/dist/grant/capabilityGrant.js +6 -3
- package/dist/input/inputRequest.js +12 -10
- package/dist/integration/gitIntegrationService.js +4 -11
- package/dist/integration/integrationQueueService.js +4 -4
- package/dist/interaction/operatorPresentation.js +1 -1
- package/dist/kernel/builtinCapabilities.js +255 -12
- package/dist/kernel/capabilityRegistry.js +64 -18
- package/dist/kernel/instanceHost.js +12 -1
- package/dist/kernel/kernelPorts.js +2 -2
- package/dist/lifecycle/canonicalLifecycleEvent.js +44 -49
- package/dist/lifecycle/exactRunTerminalization.js +449 -0
- package/dist/message/message.js +118 -6
- package/dist/message/messageContinuation.js +204 -0
- package/dist/observability/executionAudit.js +70 -72
- package/dist/observability/faultClassification.js +2 -2
- package/dist/observability/orchestrationMetrics.js +8 -8
- package/dist/operator/operatorSessionHistory.js +1 -7
- package/dist/output/agentConfigurationPresentation.js +8 -3
- package/dist/output/agentRunConfigurationPresentation.js +128 -0
- package/dist/output/rolePresentation.js +54 -3
- package/dist/plugins/pluginChild.js +104 -0
- package/dist/plugins/pluginIntent.js +26 -0
- package/dist/plugins/pluginInterpreter.js +43 -0
- package/dist/plugins/pluginPackage.js +101 -0
- package/dist/plugins/pluginProcess.js +112 -0
- package/dist/plugins/pluginService.js +388 -0
- package/dist/profile/agentProfile.js +1 -1
- package/dist/repository/gitWorkspace.js +26 -4
- package/dist/repository/project.js +19 -4
- package/dist/repository/taskBaseFreshness.js +13 -13
- package/dist/repository/taskWorkspaceCoordinator.js +20 -27
- package/dist/repository/taskWorkspacePreparer.js +344 -83
- package/dist/resources/autoResourceGc.js +3 -3
- package/dist/resources/liveReferences.js +3 -3
- package/dist/resources/projectResource.js +75 -0
- package/dist/resources/projectResourceService.js +343 -0
- package/dist/resources/resourceDiscovery.js +6 -6
- package/dist/resources/resourceGc.js +1 -1
- package/dist/resources/resourceRegistrar.js +1 -1
- package/dist/resources/resourceTypes.js +1 -1
- package/dist/review/deltaRecheck.js +3 -3
- package/dist/review/reviewAcceptance.js +16 -16
- package/dist/review/reviewDecision.js +7 -7
- package/dist/review/reviewRound.js +21 -20
- package/dist/review/reviewerAvailability.js +2 -2
- package/dist/role/role.js +51 -7
- package/dist/role/taskRoleUpdate.js +30 -0
- package/dist/runtime/acpProtocol.js +425 -0
- package/dist/runtime/acpSession.js +731 -0
- package/dist/runtime/acpSessionConfiguration.js +260 -0
- package/dist/runtime/agentDriver.js +30 -11
- package/dist/runtime/agentEndpoint.js +278 -0
- package/dist/runtime/agentEndpointIdentity.js +86 -0
- package/dist/runtime/agentEndpointOwnership.js +239 -0
- package/dist/runtime/agentError.js +2 -10
- package/dist/runtime/agentHost.js +565 -314
- package/dist/runtime/agentRunConfiguration.js +258 -0
- package/dist/runtime/builtinAgentDrivers.js +134 -18
- package/dist/runtime/builtinAgentErrorMappers.js +55 -3
- package/dist/runtime/builtinTranscriptUsage.js +1 -1
- package/dist/runtime/claude-process-owner +0 -0
- package/dist/runtime/codexAppServerRuntime.js +38 -30
- package/dist/runtime/codexInteractiveHost.js +41 -6
- package/dist/runtime/continuationManager.js +2 -6
- package/dist/runtime/executionEnvironment.js +30 -0
- package/dist/runtime/firstProgressAdvisory.js +11 -11
- package/dist/runtime/index.js +4 -3
- package/dist/runtime/jsonLineChannel.js +109 -0
- package/dist/runtime/launchBroker.js +91 -16
- package/dist/runtime/launchDiagnostics.js +2 -2
- package/dist/runtime/lifecycleReservation.js +10 -18
- package/dist/runtime/managedCaller.js +61 -17
- package/dist/runtime/nativeSessionControl.js +102 -0
- package/dist/runtime/ports.js +6 -21
- package/dist/runtime/processExitObservation.js +8 -7
- package/dist/runtime/promptEnvelope.js +17 -6
- package/dist/runtime/providerContinuation.js +3 -9
- package/dist/runtime/providerContinuationReconciliationService.js +4 -13
- package/dist/runtime/providerControl.js +2 -7
- package/dist/runtime/providerRuntimeIdentity.js +110 -222
- package/dist/runtime/providerRuntimeReconciler.js +5 -9
- package/dist/runtime/runtimeBinding.js +0 -1
- package/dist/runtime/runtimeContinuationProjection.js +4 -7
- package/dist/runtime/runtimeDeadlines.js +9 -0
- package/dist/runtime/runtimeHealthPolicy.js +1 -1
- package/dist/runtime/runtimeObservation.js +29 -65
- package/dist/runtime/runtimeProjection.js +43 -51
- package/dist/runtime/runtimeSessionCandidate.js +1 -3
- package/dist/runtime/sessionLaunchRequest.js +3 -7
- package/dist/runtime/sessionOwnerIdentity.js +7 -54
- package/dist/runtime/sessionOwnerRegistry.js +22 -17
- package/dist/runtime/sessionReconciliation.js +4 -8
- package/dist/runtime/sessionTerminationGuard.js +70 -259
- package/dist/runtime/sessionTokenMetrics.js +5 -16
- package/dist/runtime/structuredProviderHost.js +237 -117
- package/dist/runtime/taskRuntimeIsolation.js +39 -122
- package/dist/runtime/tmuxAdapters.js +39 -86
- package/dist/scheduler/activeRoleRunDelivery.js +354 -0
- package/dist/scheduler/leaderWakeupProcessor.js +75 -266
- package/dist/scheduler/operatorInputNotificationProcessor.js +1 -1
- package/dist/scheduler/ports.js +80 -9
- package/dist/scheduler/{roleTurnLiveness.js → roleRunLiveness.js} +26 -30
- package/dist/scheduler/{roleTurnStall.js → roleRunStall.js} +128 -139
- package/dist/scheduler/taskExecutionProjection.js +120 -124
- package/dist/scheduler/taskObservabilityProjection.js +29 -29
- package/dist/scheduler/taskWake.js +11 -4
- package/dist/scheduler/wakeReason.js +9 -1
- package/dist/setup/setupCommand.js +3 -7
- package/dist/storage/migrations/agentRunContract.js +159 -0
- package/dist/storage/migrations/artifactsToGit.js +338 -0
- package/dist/storage/migrations/removeRuntimeGeneration.js +207 -0
- package/dist/storage/migrations/submitIntent.js +126 -0
- package/dist/storage/sqliteSchema.js +467 -7
- package/dist/storage/sqliteStore.js +355 -220
- package/dist/storage/storageVersions.js +1 -1
- package/dist/storage/storeRpc.js +10 -5
- package/dist/storage/taskStore.js +13 -11
- package/dist/storage/upgrade/upgradeOrchestrator.js +5 -7
- package/dist/surface/surfaceContributions.js +102 -0
- package/dist/task/completionReadiness.js +32 -6
- package/dist/task/deliveryGuard.js +16 -16
- package/dist/task/draftPlan.js +72 -12
- package/dist/task/nextAction.js +144 -128
- package/dist/task/remoteDelivery.js +6 -6
- package/dist/task/task.js +184 -18
- package/dist/task/taskActivation.js +327 -0
- package/dist/task/taskActivationService.js +408 -0
- package/dist/task/taskRecordReference.js +5 -4
- package/dist/task/taskRecordRetirement.js +1 -1
- package/dist/task/taskSubmission.js +236 -0
- package/dist/telemetry/sqliteTelemetryStore.js +55 -68
- package/dist/telemetry/telemetryConfig.js +14 -14
- package/dist/telemetry/telemetryWiring.js +2 -2
- package/dist/web/assets/assetManifest.js +2 -0
- package/dist/web/assets/client/app.js +121 -20
- package/dist/web/assets/client/components.js +87 -54
- package/dist/web/assets/client/i18n.js +83 -41
- package/dist/web/assets/client/markdown.js +1 -1
- package/dist/web/assets/client/taskSurface.js +442 -0
- package/dist/web/assets/client/view.js +49 -44
- package/dist/web/assets/shell.js +1 -1
- package/dist/web/assets/styles/cards.js +22 -4
- package/dist/web/controllerWeb.js +60 -0
- package/dist/web/webMutation.js +28 -0
- package/dist/web/webServer.js +133 -8
- package/dist/web/webSnapshot.js +81 -74
- package/dist/web/webTaskSurface.js +64 -0
- package/dist/workItem/dependencyGate.js +1 -1
- package/dist/workItem/workItem.js +84 -48
- package/dist/workspace/workItemChangeSetManager.js +16 -9
- package/docs/agent-result-consumption.md +96 -0
- package/docs/agent-result-consumption.zh-CN.md +81 -0
- package/docs/agent-runtime-drivers.md +93 -0
- package/docs/agent-runtime-drivers.zh-CN.md +77 -0
- package/docs/architecture/README.md +50 -0
- package/docs/architecture/README.zh-CN.md +43 -0
- package/docs/architecture/capabilities-and-resources.md +118 -0
- package/docs/architecture/capabilities-and-resources.zh-CN.md +83 -0
- package/docs/managed-turn-and-session-runtime.md +224 -0
- package/docs/managed-turn-and-session-runtime.zh-CN.md +180 -0
- package/docs/observability/README.md +83 -0
- package/docs/observability/README.zh-CN.md +71 -0
- package/docs/plugin-sdk.md +393 -0
- package/docs/plugin-sdk.zh-CN.md +293 -0
- package/docs/provider-runtime.md +165 -0
- package/docs/provider-runtime.zh-CN.md +132 -0
- package/docs/release-workflow.md +305 -0
- package/docs/release-workflow.zh-CN.md +237 -0
- package/docs/roles-and-configuration.md +115 -0
- package/docs/roles-and-configuration.zh-CN.md +96 -0
- package/docs/sqlite-control-plane-design.md +78 -0
- package/docs/sqlite-control-plane-design.zh-CN.md +62 -0
- package/docs/task-dag-semantics.md +80 -0
- package/docs/task-dag-semantics.zh-CN.md +59 -0
- package/docs/task-delivery.md +105 -0
- package/docs/task-delivery.zh-CN.md +82 -0
- package/docs/task-local-identity.md +8 -6
- package/docs/task-local-identity.zh-CN.md +58 -0
- package/docs/testing/verification-levels.md +88 -0
- package/docs/testing/verification-levels.zh-CN.md +69 -0
- package/i18n/README.zh-CN.md +270 -722
- package/package.json +3 -2
- package/skills/yui-leader/SKILL.md +88 -304
- package/skills/yui-leader/references/execution.md +303 -0
- package/skills/yui-leader/references/integration.md +39 -0
- package/skills/yui-leader/references/planning.md +109 -0
- package/skills/yui-leader/references/replicated-execution.md +42 -0
- package/skills/yui-leader/references/task-plugins.md +37 -0
- package/skills/yui-operator/SKILL.md +46 -62
- package/skills/yui-reviewer/SKILL.md +35 -36
- package/skills/yui-runtime/SKILL.md +88 -24
- package/skills/yui-runtime/references/publication.md +22 -0
- package/skills/yui-runtime/references/recovery.md +64 -0
- package/skills/yui-worker/SKILL.md +37 -39
- package/dist/cli/roleOptionCatalog.js +0 -68
- package/dist/context/sourceTurnContext.js +0 -30
- package/dist/execution/reviewMainTurn.js +0 -161
- package/dist/execution/workItemMainTurn.js +0 -164
- package/dist/lifecycle/exactTurnTerminalization.js +0 -407
- package/dist/runtime/preallocatedNativeSession.js +0 -13
- package/dist/runtime/runtimeStopReceipt.js +0 -42
- package/dist/scheduler/activeRoleTurnDelivery.js +0 -315
|
@@ -20,7 +20,7 @@ function ownerLabel(owner) {
|
|
|
20
20
|
* This is a read-only check: it never mutates Git state, creates Sessions, or
|
|
21
21
|
* writes recovery records.
|
|
22
22
|
*/
|
|
23
|
-
export function classifyWorkspacePreflight(store, task, roleName,
|
|
23
|
+
export function classifyWorkspacePreflight(store, task, roleName, activeRun, inspectPhysical) {
|
|
24
24
|
const main = store.getTaskWorkspace(task.id);
|
|
25
25
|
const bindings = task.projectBindings.map(({ projectId, directory }) => ({ projectId, directory }));
|
|
26
26
|
// 1. Owner validation: the Task main workspace must be a durable,
|
|
@@ -41,26 +41,26 @@ export function classifyWorkspacePreflight(store, task, roleName, activeTurn, in
|
|
|
41
41
|
actual
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
|
-
// 2.
|
|
44
|
+
// 2. AgentRun snapshot validation: when the active AgentRun carries a workspace
|
|
45
45
|
// snapshot its launch-stable identity must match the durable
|
|
46
46
|
// ManagedWorkspace. Audit timestamps may change without changing the
|
|
47
|
-
// owner, root, or Project entries authorized for the
|
|
48
|
-
if (
|
|
49
|
-
const durableRunWorkspace = store.getManagedWorkspace(
|
|
47
|
+
// owner, root, or Project entries authorized for the AgentRun.
|
|
48
|
+
if (activeRun?.workspace !== undefined) {
|
|
49
|
+
const durableRunWorkspace = store.getManagedWorkspace(activeRun.workspace.owner);
|
|
50
50
|
if (durableRunWorkspace === null
|
|
51
|
-
|| !sameManagedWorkspaceIdentity(durableRunWorkspace,
|
|
51
|
+
|| !sameManagedWorkspaceIdentity(durableRunWorkspace, activeRun.workspace)) {
|
|
52
52
|
const diff = [];
|
|
53
53
|
if (durableRunWorkspace === null) {
|
|
54
|
-
diff.push(`durable ManagedWorkspace for owner ${JSON.stringify(
|
|
54
|
+
diff.push(`durable ManagedWorkspace for owner ${JSON.stringify(activeRun.workspace.owner)} is missing`);
|
|
55
55
|
}
|
|
56
56
|
else {
|
|
57
|
-
if (durableRunWorkspace.root !==
|
|
58
|
-
diff.push(`root: durable=${durableRunWorkspace.root} run=${
|
|
57
|
+
if (durableRunWorkspace.root !== activeRun.workspace.root) {
|
|
58
|
+
diff.push(`root: durable=${durableRunWorkspace.root} run=${activeRun.workspace.root}`);
|
|
59
59
|
}
|
|
60
|
-
if (durableRunWorkspace.entries.length !==
|
|
61
|
-
diff.push(`entries: durable=${durableRunWorkspace.entries.length} run=${
|
|
60
|
+
if (durableRunWorkspace.entries.length !== activeRun.workspace.entries.length) {
|
|
61
|
+
diff.push(`entries: durable=${durableRunWorkspace.entries.length} run=${activeRun.workspace.entries.length}`);
|
|
62
62
|
}
|
|
63
|
-
for (const [index, entry] of
|
|
63
|
+
for (const [index, entry] of activeRun.workspace.entries.entries()) {
|
|
64
64
|
const durableEntry = durableRunWorkspace.entries[index];
|
|
65
65
|
if (durableEntry === undefined) {
|
|
66
66
|
diff.push(`entry[${index}] ${entry.projectId}: missing from durable`);
|
|
@@ -76,10 +76,10 @@ export function classifyWorkspacePreflight(store, task, roleName, activeTurn, in
|
|
|
76
76
|
}
|
|
77
77
|
return {
|
|
78
78
|
kind: "workspace-stale",
|
|
79
|
-
reason: `Role
|
|
79
|
+
reason: `Role AgentRun workspace is not the durable owner: ${task.id}/${roleName}.`,
|
|
80
80
|
taskId: task.id,
|
|
81
81
|
roleName,
|
|
82
|
-
|
|
82
|
+
runId: activeRun.id,
|
|
83
83
|
diff
|
|
84
84
|
};
|
|
85
85
|
}
|
|
@@ -89,7 +89,7 @@ export function classifyWorkspacePreflight(store, task, roleName, activeTurn, in
|
|
|
89
89
|
// from that immutable boundary. A reset/repoint outside the lineage is
|
|
90
90
|
// physical drift and must fail before Provider launch.
|
|
91
91
|
if (inspectPhysical !== undefined) {
|
|
92
|
-
const effective =
|
|
92
|
+
const effective = activeRun?.workspace ?? main;
|
|
93
93
|
for (const entry of effective.entries) {
|
|
94
94
|
const physical = inspectPhysical(entry);
|
|
95
95
|
if (!physical.recordedBaseIsAncestor) {
|
|
@@ -121,7 +121,7 @@ export function formatWorkspacePreflightError(classification) {
|
|
|
121
121
|
+ "` to inspect the binding, ManagedWorkspace, and physical HEAD.");
|
|
122
122
|
break;
|
|
123
123
|
case "workspace-stale":
|
|
124
|
-
lines.push(`
|
|
124
|
+
lines.push(` AgentRun ${classification.runId} snapshot differs from the durable ManagedWorkspace:`);
|
|
125
125
|
for (const entry of classification.diff) {
|
|
126
126
|
lines.push(` - ${entry}`);
|
|
127
127
|
}
|
|
@@ -68,8 +68,8 @@ export function grantUseReservations(grant) {
|
|
|
68
68
|
}
|
|
69
69
|
/**
|
|
70
70
|
* Record one use against the grant, failing closed once the limit is reached.
|
|
71
|
-
*
|
|
72
|
-
*
|
|
71
|
+
* Supply a reservation key when a later resume must recognize the attempt.
|
|
72
|
+
* Non-resumable calls only advance the counter; historical keys stay intact.
|
|
73
73
|
*/
|
|
74
74
|
export function recordGrantUse(grant, now, reservationKey) {
|
|
75
75
|
validateCapabilityGrant(grant);
|
|
@@ -79,7 +79,10 @@ export function recordGrantUse(grant, now, reservationKey) {
|
|
|
79
79
|
return validateCapabilityGrant({
|
|
80
80
|
...grant,
|
|
81
81
|
usesUsed: grant.usesUsed + 1,
|
|
82
|
-
useReservations: Object.freeze([
|
|
82
|
+
useReservations: Object.freeze([
|
|
83
|
+
...grantUseReservations(grant),
|
|
84
|
+
...(reservationKey === undefined ? [] : [reservationKey])
|
|
85
|
+
]),
|
|
83
86
|
updatedAt: now.toISOString()
|
|
84
87
|
});
|
|
85
88
|
}
|
|
@@ -89,12 +89,11 @@ export function validateInputRequest(value) {
|
|
|
89
89
|
updatedAt: requireTimestamp(request.updatedAt, "Input request updatedAt")
|
|
90
90
|
};
|
|
91
91
|
validateTaskRecordReference({ taskId: base.taskId, localId: base.id }, "inputRequest");
|
|
92
|
-
|
|
93
|
-
taskId: base.requester.taskId,
|
|
94
|
-
|
|
95
|
-
}, "turn");
|
|
92
|
+
if (base.requester.runId !== undefined) {
|
|
93
|
+
validateTaskRecordReference({ taskId: base.requester.taskId, localId: base.requester.runId }, "run");
|
|
94
|
+
}
|
|
96
95
|
for (const reference of base.blockedRefs) {
|
|
97
|
-
validateTaskRecordReference({ taskId: reference.taskId, localId: reference.id }, reference.type === "
|
|
96
|
+
validateTaskRecordReference({ taskId: reference.taskId, localId: reference.id }, reference.type === "run" ? "run" : "workItem");
|
|
98
97
|
}
|
|
99
98
|
if (base.requester.taskId !== base.taskId
|
|
100
99
|
|| base.blockedRefs.some(({ taskId }) => taskId !== base.taskId)) {
|
|
@@ -175,7 +174,7 @@ function normalizeBlockedRefs(value) {
|
|
|
175
174
|
const references = value.map((reference) => {
|
|
176
175
|
const item = record(reference, "Input blocked reference");
|
|
177
176
|
exact(item, ["type", "taskId", "id"], "Input blocked reference");
|
|
178
|
-
if (item.type !== "work-item" && item.type !== "
|
|
177
|
+
if (item.type !== "work-item" && item.type !== "run") {
|
|
179
178
|
throw new Error("Input blocked reference type must be work-item or turn.");
|
|
180
179
|
}
|
|
181
180
|
return {
|
|
@@ -223,16 +222,19 @@ function validateBlockedRefs(value) {
|
|
|
223
222
|
}
|
|
224
223
|
function normalizeRequester(value) {
|
|
225
224
|
const requester = record(value, "Input requester");
|
|
226
|
-
exact(requester,
|
|
227
|
-
? [
|
|
228
|
-
|
|
225
|
+
exact(requester, ["taskId", "roleName", "agentId",
|
|
226
|
+
...(requester.runId === undefined ? [] : ["runId"]),
|
|
227
|
+
...(requester.nativeSessionId === undefined ? [] : ["nativeSessionId"])], "Input requester");
|
|
229
228
|
if (requester.roleName !== "leader")
|
|
230
229
|
throw new Error("Input requester must be the Task Leader.");
|
|
230
|
+
if (requester.runId === undefined && requester.nativeSessionId === undefined) {
|
|
231
|
+
throw new Error("Input requester requires an originating Run or native Session.");
|
|
232
|
+
}
|
|
231
233
|
return {
|
|
232
234
|
taskId: requireIdentity(requester.taskId, "Input requester Task id"),
|
|
233
235
|
roleName: "leader",
|
|
234
236
|
agentId: requireIdentity(requester.agentId, "Input requester Agent id"),
|
|
235
|
-
|
|
237
|
+
...(requester.runId === undefined ? {} : { runId: requireIdentity(requester.runId, "Input requester AgentRun id") }),
|
|
236
238
|
...(requester.nativeSessionId === undefined
|
|
237
239
|
? {}
|
|
238
240
|
: { nativeSessionId: requireIdentity(requester.nativeSessionId, "Input requester native session id") })
|
|
@@ -549,8 +549,6 @@ export class GitIntegrationService {
|
|
|
549
549
|
#runtimePreparation(attempt, workspace) {
|
|
550
550
|
return this.runtimeIsolation.preflight({
|
|
551
551
|
workspace,
|
|
552
|
-
runtimeGenerationId: integrationRuntimeRuntimeGenerationId(this.home, attempt.id),
|
|
553
|
-
generationId: "integration-checks",
|
|
554
552
|
allowExactActive: true
|
|
555
553
|
});
|
|
556
554
|
}
|
|
@@ -1083,7 +1081,7 @@ function isNodeCode(error, code) {
|
|
|
1083
1081
|
function defaultIntegrationRuntimeIsolation(home, homeId) {
|
|
1084
1082
|
const controlHome = resolve(home);
|
|
1085
1083
|
return new FileTaskRuntimeIsolation({
|
|
1086
|
-
runtimeRoot: integrationRuntimeRoot(),
|
|
1084
|
+
runtimeRoot: integrationRuntimeRoot(controlHome),
|
|
1087
1085
|
pathLayout: "compact",
|
|
1088
1086
|
controlPlane: {
|
|
1089
1087
|
yuiHome: controlHome,
|
|
@@ -1093,15 +1091,10 @@ function defaultIntegrationRuntimeIsolation(home, homeId) {
|
|
|
1093
1091
|
}
|
|
1094
1092
|
});
|
|
1095
1093
|
}
|
|
1096
|
-
function integrationRuntimeRoot() {
|
|
1094
|
+
function integrationRuntimeRoot(home) {
|
|
1097
1095
|
const uid = typeof process.getuid === "function" ? process.getuid() : 0;
|
|
1098
|
-
|
|
1099
|
-
}
|
|
1100
|
-
function integrationRuntimeRuntimeGenerationId(home, integrationId) {
|
|
1101
|
-
const homeDigest = createHash("sha256")
|
|
1102
|
-
.update(resolve(home))
|
|
1103
|
-
.digest("hex");
|
|
1104
|
-
return `${integrationId}-${homeDigest}`;
|
|
1096
|
+
const homeDigest = createHash("sha256").update(resolve(home)).digest("hex").slice(0, 16);
|
|
1097
|
+
return join("/tmp", `yi-${uid.toString(36)}-${homeDigest}`);
|
|
1105
1098
|
}
|
|
1106
1099
|
/**
|
|
1107
1100
|
* Reuse is enabled only for an immutable installed release. Development
|
|
@@ -3,6 +3,7 @@ import { workspaceProjectEntry } from "../worktree/managedWorkspace.js";
|
|
|
3
3
|
import { createIntegrationAttempt, recordResolutionDecision, updateIntegrationAttempt } from "./integrationAttempt.js";
|
|
4
4
|
import { createConvergedIntegrationQueueEntry, createIntegrationQueueEntry, markIntegrationQueueBlocked, markIntegrationQueueCommitted, markIntegrationQueueRequeued, markIntegrationQueueRunning, markIntegrationQueueSuperseded, recordIntegrationQueueAffectedPaths, recordIntegrationQueueAttempt } from "./integrationQueueEntry.js";
|
|
5
5
|
import { GitIntegrationService } from "./gitIntegrationService.js";
|
|
6
|
+
import { governingWorkItemCandidate } from "../workItem/workItem.js";
|
|
6
7
|
/**
|
|
7
8
|
* Producer WorkItem statuses that close the WorkItem lifecycle. A ChangeSet
|
|
8
9
|
* captured from a WorkItem that reached one of these without ever producing a
|
|
@@ -11,8 +12,7 @@ import { GitIntegrationService } from "./gitIntegrationService.js";
|
|
|
11
12
|
* Candidate.
|
|
12
13
|
*/
|
|
13
14
|
const TERMINAL_PRODUCER_STATUSES = new Set([
|
|
14
|
-
"
|
|
15
|
-
"failed",
|
|
15
|
+
"accepted",
|
|
16
16
|
"retired"
|
|
17
17
|
]);
|
|
18
18
|
/**
|
|
@@ -59,11 +59,11 @@ function assertCurrentCandidateInStore(store, taskId, changeSet) {
|
|
|
59
59
|
throw new Error(`ChangeSet producer WorkItem not found: ${changeSet.workItemId}.`);
|
|
60
60
|
}
|
|
61
61
|
// A running WorkItem has no current Candidate: a new one is expected.
|
|
62
|
-
if (workItem.status === "
|
|
62
|
+
if (workItem.status === "open" && workItem.currentCandidateId === undefined) {
|
|
63
63
|
throw new Error(`ChangeSet ${changeSet.id} has no current Candidate: `
|
|
64
64
|
+ `WorkItem ${workItem.id} is running.`);
|
|
65
65
|
}
|
|
66
|
-
const latestCandidate = workItem
|
|
66
|
+
const latestCandidate = governingWorkItemCandidate(workItem);
|
|
67
67
|
if (latestCandidate !== undefined) {
|
|
68
68
|
const snapshotHead = candidateHeadCommit(latestCandidate, changeSet.projectId);
|
|
69
69
|
if (snapshotHead !== undefined && snapshotHead !== changeSet.headCommit) {
|
|
@@ -34,7 +34,7 @@ function eventLabel(event) {
|
|
|
34
34
|
case "task.completed": return "Task completed";
|
|
35
35
|
case "task.retired": return "Task retired";
|
|
36
36
|
case "leader.attention-required": return "Task Leader needs attention";
|
|
37
|
-
case "
|
|
37
|
+
case "run.stalled": return "Task Leader stalled";
|
|
38
38
|
default: return `Task event ${event.type}`;
|
|
39
39
|
}
|
|
40
40
|
}
|
|
@@ -1,21 +1,119 @@
|
|
|
1
|
-
import { updateTaskMetadataCommand } from "../commands/taskCommands.js";
|
|
1
|
+
import { updateTaskMetadataCommand, sendTaskMessageCommand } from "../commands/taskCommands.js";
|
|
2
2
|
import { runConfigCommand } from "../commands/configCommands.js";
|
|
3
|
+
import { readTaskContext, readTaskContextDelta, inspectTaskContext, withContextObservations } from "../context/taskContext.js";
|
|
3
4
|
import { CONFIG_DOMAINS } from "../config/configCatalog.js";
|
|
4
5
|
import { createJobCallAuthority, parseDurableJobStartParams } from "../controller/jobControl.js";
|
|
5
6
|
import { inspectJobOperation } from "./kernelPorts.js";
|
|
6
7
|
import { CapabilityRegistry, } from "./capabilityRegistry.js";
|
|
8
|
+
import { createProjectResources } from "../resources/projectResourceService.js";
|
|
9
|
+
import { saveArtifactCapability, readArtifactCapability, listArtifactsCapability } from "../artifacts/artifactCapability.js";
|
|
10
|
+
import { createPluginService } from "../plugins/pluginService.js";
|
|
7
11
|
const text = { type: "string", minLength: 1 };
|
|
8
12
|
const strings = { type: "object", additionalProperties: { type: "string" } };
|
|
9
13
|
const object = (properties, required = Object.keys(properties)) => ({
|
|
10
14
|
type: "object", properties, required, additionalProperties: false
|
|
11
15
|
});
|
|
12
16
|
const taskInput = object({ taskId: text });
|
|
17
|
+
const recordOutput = { type: "object" };
|
|
13
18
|
const taskOutput = { type: "object", required: ["id", "status", "title"], properties: {
|
|
14
19
|
id: text, status: text, title: text
|
|
15
20
|
} };
|
|
16
21
|
const provider = Object.freeze({ id: "yui:builtin-capabilities", generation: "1" });
|
|
17
22
|
/** Source locators identify the existing semantic owner, not a new Store. */
|
|
18
23
|
const definitions = [
|
|
24
|
+
{
|
|
25
|
+
name: "message.send", summary: "Save collaboration for Leader or continue the same dispatched work owner.",
|
|
26
|
+
effect: "local-mutation", requiredPermissions: ["task:read"], source: "sendTaskMessageCommand",
|
|
27
|
+
inputSchema: object({ taskId: text, body: text,
|
|
28
|
+
intent: { enum: ["record", "discuss", "develop"] },
|
|
29
|
+
wakePolicy: { enum: ["leader", "none"] },
|
|
30
|
+
recipient: object({ roleName: text, workItemId: text, reviewRoundId: text }, ["roleName"])
|
|
31
|
+
}, ["taskId", "body"]), outputSchema: recordOutput
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: "context.read", summary: "Read a bounded authorized Task working set and atomic core cursor.",
|
|
35
|
+
effect: "query", requiredPermissions: ["task:read"], source: "readTaskContext",
|
|
36
|
+
inputSchema: taskInput, outputSchema: { type: "object", required: ["records", "coreCursor", "omitted"] }
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: "context.delta", summary: "Read immutable Task events with a fixed pagination upper bound.",
|
|
40
|
+
effect: "query", requiredPermissions: ["task:read"], source: "readTaskContextDelta",
|
|
41
|
+
inputSchema: object({ taskId: text, after: text, continuation: text, limit: { type: "integer" } }, ["taskId", "after"]),
|
|
42
|
+
outputSchema: { type: "object", required: ["events", "throughCursor"] }
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: "context.inspect", summary: "Expand an authorized current record; optionally require its exact digest.",
|
|
46
|
+
effect: "query", requiredPermissions: ["task:read"], source: "inspectTaskContext",
|
|
47
|
+
inputSchema: object({ taskId: text, store: text, refId: text, digest: text }, ["taskId", "store", "refId"]),
|
|
48
|
+
outputSchema: { type: "object", required: ["ref", "value", "coreCursor"] }
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: "artifact.save", summary: "Save a file artifact by relativePath into the Task's local Git repository; returns a commit-pinned reference.",
|
|
52
|
+
effect: "local-mutation", requiredPermissions: ["task:read"], source: "artifacts.saveArtifactCapability",
|
|
53
|
+
inputSchema: object({ taskId: text, relativePath: text, content: { type: "string" }, message: text, expectedHead: text }, ["taskId", "relativePath", "content"]),
|
|
54
|
+
outputSchema: { type: "object", required: ["taskId", "commit", "relativePath"] }
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: "artifact.read", summary: "Read a file artifact at HEAD, or at a pinned commit for frozen evidence, without starting a Runtime or plugin.",
|
|
58
|
+
effect: "query", requiredPermissions: ["task:read"], source: "artifacts.readArtifactCapability",
|
|
59
|
+
inputSchema: object({ taskId: text, relativePath: text, commit: text }, ["taskId", "relativePath"]),
|
|
60
|
+
outputSchema: { type: "object", required: ["taskId", "relativePath", "commit", "content"] }
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: "artifact.list", summary: "List this Task's tracked file artifacts at HEAD.",
|
|
64
|
+
effect: "query", requiredPermissions: ["task:read"], source: "artifacts.listArtifactsCapability",
|
|
65
|
+
inputSchema: taskInput, outputSchema: { type: "array", items: recordOutput }
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: "environment.prepare", summary: "Prepare empty, Task-owned scratch, or explicitly granted trusted-local directory; does not adopt it or create a sandbox.",
|
|
69
|
+
effect: "local-mutation", requiredPermissions: ["task:manage"], source: "ProjectResources.prepare",
|
|
70
|
+
inputSchema: object({ taskId: text, plan: { anyOf: [
|
|
71
|
+
object({ kind: { const: "empty" } }), object({ kind: { const: "scratch" } }),
|
|
72
|
+
object({ kind: { const: "local" }, resourceId: text, access: { enum: ["read", "write"] } })
|
|
73
|
+
] } }), outputSchema: recordOutput
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
name: "environment.adopt", summary: "Recheck current resource intent, grants and conflicts, then record Task ownership.",
|
|
77
|
+
effect: "local-mutation", requiredPermissions: ["task:manage"], source: "ProjectResources.adopt",
|
|
78
|
+
inputSchema: object({ taskId: text, preparationId: text }), outputSchema: recordOutput
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: "environment.bind", summary: "Select an adopted environment for a Role's next native Session; null restores managed workspace. Active Sessions keep their environment.",
|
|
82
|
+
effect: "local-mutation", requiredPermissions: ["task:manage"], source: "ProjectResources.bindEnvironment",
|
|
83
|
+
inputSchema: object({ taskId: text, roleName: text, preparationId: { anyOf: [text, { const: null }] } }),
|
|
84
|
+
outputSchema: recordOutput
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: "environment.release", summary: "Release exact preparation; adopted resources need actual quiescence evidence. Never deletes user directories.",
|
|
88
|
+
effect: "local-mutation", requiredPermissions: ["task:manage"], source: "ProjectResources.release",
|
|
89
|
+
inputSchema: object({ taskId: text, preparationId: text, quiescence: text }, ["taskId", "preparationId"]), outputSchema: recordOutput
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
name: "environment.list", summary: "Read preparation/adoption facts, not inferred process state.",
|
|
93
|
+
effect: "query", requiredPermissions: ["task:read"], source: "TaskStore.listEnvironmentPreparations",
|
|
94
|
+
inputSchema: taskInput, outputSchema: { type: "array", items: recordOutput }
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: "resource.local.register", summary: "Register a user-owned local directory by canonical identity (Operator); registration does not grant use.",
|
|
98
|
+
effect: "local-mutation", requiredPermissions: ["resource:register"], source: "ProjectResources.registerLocalDirectory",
|
|
99
|
+
inputSchema: object({ displayName: text, path: text }), outputSchema: recordOutput
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
name: "resource.local.read", summary: "Read an explicitly granted local resource.",
|
|
103
|
+
effect: "query", requiredPermissions: ["task:read"], source: "ProjectResources.readLocalResource",
|
|
104
|
+
inputSchema: object({ taskId: text, resourceId: text }), outputSchema: recordOutput
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
name: "project.context", summary: "Read Project Knowledge, resource references and default Provider references; no credential grant.",
|
|
108
|
+
effect: "query", requiredPermissions: ["task:read"], source: "TaskStore.getProject",
|
|
109
|
+
inputSchema: object({ taskId: text, projectId: text }), outputSchema: recordOutput
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
name: "project.resources.configure", summary: "Configure existing Project resource and Provider references (Operator).",
|
|
113
|
+
effect: "local-mutation", requiredPermissions: ["resource:register"], source: "ProjectResources.configureProject",
|
|
114
|
+
inputSchema: object({ projectId: text, resourceRefs: { type: "array", items: text }, defaultCapabilityProviders: strings }),
|
|
115
|
+
outputSchema: recordOutput
|
|
116
|
+
},
|
|
19
117
|
{
|
|
20
118
|
name: "task.read", summary: "Read the current Task record.", effect: "query",
|
|
21
119
|
inputSchema: taskInput, outputSchema: taskOutput, requiredPermissions: ["task:read"],
|
|
@@ -41,6 +139,11 @@ const definitions = [
|
|
|
41
139
|
inputSchema: object({ domain: { enum: CONFIG_DOMAINS } }),
|
|
42
140
|
outputSchema: { type: "object" }
|
|
43
141
|
},
|
|
142
|
+
{
|
|
143
|
+
name: "resource.git.result", summary: "Read an original fixed Git ChangeSet and its external-version reference.",
|
|
144
|
+
effect: "query", requiredPermissions: ["task:read"], source: "TaskStore.getChangeSet",
|
|
145
|
+
inputSchema: object({ taskId: text, changeSetId: text }), outputSchema: recordOutput
|
|
146
|
+
},
|
|
44
147
|
{
|
|
45
148
|
name: "resource.workspaces", summary: "Read the Task's managed workspace resources.",
|
|
46
149
|
effect: "query", requiredPermissions: ["task:read"],
|
|
@@ -73,23 +176,58 @@ const definitions = [
|
|
|
73
176
|
}, ["taskId", "projectId", "head", "workspace", "owner", "env", "steps"]),
|
|
74
177
|
outputSchema: { type: "object", required: ["job", "created", "operation"], properties: { created: { type: "boolean" } } }
|
|
75
178
|
},
|
|
76
|
-
...[
|
|
77
|
-
|
|
179
|
+
...[
|
|
180
|
+
{ action: "create", summary: "Create an independent data or trusted-local package in an adopted environment; executes no author code.",
|
|
181
|
+
inputSchema: object({ preparationId: text, id: text, kind: { enum: ["declarative", "trusted-local"] } }) },
|
|
182
|
+
{ action: "validate", summary: "Validate captured package bytes in an explicit environment; author build/test code needs a separate execution grant.",
|
|
183
|
+
inputSchema: object({ preparationId: text, directory: text }) },
|
|
184
|
+
{ action: "activate", summary: "Recheck validated bytes, current authority and dependencies; publish one complete Task-local provider.",
|
|
185
|
+
inputSchema: object({ validationId: text }) },
|
|
186
|
+
{ action: "disable", summary: "Stop new plugin calls and drain the exact Host instance before disposal.",
|
|
187
|
+
inputSchema: object({ id: text }) }
|
|
188
|
+
].map(({ action, summary, inputSchema }) => ({
|
|
189
|
+
name: `plugin.${action}`, summary, inputSchema,
|
|
78
190
|
effect: "local-mutation", requiredPermissions: ["plugin:manage"],
|
|
79
|
-
source: "
|
|
80
|
-
|
|
81
|
-
|
|
191
|
+
source: "PluginService", outputSchema: recordOutput
|
|
192
|
+
})),
|
|
193
|
+
{
|
|
194
|
+
name: "plugin.scan", summary: "Data-only package digest and manifest inspection; never executes author code.",
|
|
195
|
+
effect: "query", requiredPermissions: ["plugin:manage"], source: "PluginService.scan",
|
|
196
|
+
inputSchema: object({ preparationId: text, directory: text }), outputSchema: recordOutput
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
name: "plugin.validation", summary: "Read immutable validation evidence without starting the plugin.",
|
|
200
|
+
effect: "query", requiredPermissions: ["task:read"], source: "PluginService.inspect",
|
|
201
|
+
inputSchema: object({ validationId: text }), outputSchema: recordOutput
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
name: "plugin.inspect", summary: "Read durable desired selection, actual Host selection/references and latest intent failure; never activates code.",
|
|
205
|
+
effect: "query", requiredPermissions: ["task:read"], source: "PluginService.current",
|
|
206
|
+
inputSchema: object({ id: text }), outputSchema: recordOutput
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
name: "plugin.list", summary: "List this Task's explicit plugin choices and current Host observations without executing code.",
|
|
210
|
+
effect: "query", requiredPermissions: ["task:read"], source: "PluginService.list",
|
|
211
|
+
inputSchema: object({}), outputSchema: { type: "array", items: recordOutput }
|
|
212
|
+
}
|
|
82
213
|
];
|
|
83
214
|
export const BUILTIN_CAPABILITIES = definitions.map((entry) => ({
|
|
84
215
|
...entry, contractVersion: "1", provider, scope: { kind: "global" }
|
|
85
216
|
}));
|
|
86
|
-
/**
|
|
87
|
-
*
|
|
88
|
-
|
|
89
|
-
export function createBuiltinCapabilities(host, store, jobs, signal = () => undefined) {
|
|
217
|
+
/** One registry with separate managed credentials and in-process Web query
|
|
218
|
+
* issuance. Socket possession or caller-scope JSON never issues a Web context. */
|
|
219
|
+
export function createBuiltinCapabilities(host, store, jobs, signal = () => undefined, contextProviders = []) {
|
|
90
220
|
const authority = createJobCallAuthority(store);
|
|
221
|
+
const resources = createProjectResources(store);
|
|
91
222
|
const callers = new WeakMap();
|
|
223
|
+
// Issued only by the Controller's in-process, token-authenticated Web root.
|
|
224
|
+
// This is not accepted by the managed RPC credential adapter.
|
|
225
|
+
const webQueries = new WeakSet();
|
|
92
226
|
const current = (context) => {
|
|
227
|
+
if (webQueries.has(context)) {
|
|
228
|
+
requireTask(store, context.targetId);
|
|
229
|
+
return { scope: "user" };
|
|
230
|
+
}
|
|
93
231
|
authority.authorize(context, context.targetId);
|
|
94
232
|
const caller = callers.get(context);
|
|
95
233
|
if (!caller)
|
|
@@ -104,10 +242,92 @@ export function createBuiltinCapabilities(host, store, jobs, signal = () => unde
|
|
|
104
242
|
throw new Error("Capability target is outside the authenticated Task.");
|
|
105
243
|
}
|
|
106
244
|
const taskId = invocation.context.targetId;
|
|
245
|
+
if (name === "message.send") {
|
|
246
|
+
// A managed Task Session resolves to Leader/role authority and never
|
|
247
|
+
// gains develop from an intent argument; only a global Operator Session
|
|
248
|
+
// (user-authority) may carry one. sendTaskMessageCommand enforces this,
|
|
249
|
+
// so the capability just forwards the optional intent unchanged.
|
|
250
|
+
const result = sendTaskMessageCommand(store, taskId, params.body, params.wakePolicy, { environment: callerEnvironment(caller) }, params.recipient, params.intent);
|
|
251
|
+
signal(taskId);
|
|
252
|
+
return result.message;
|
|
253
|
+
}
|
|
254
|
+
if (name === "plugin.create")
|
|
255
|
+
return plugins.create(taskId, params.preparationId, params.id, params.kind);
|
|
256
|
+
if (name === "plugin.scan")
|
|
257
|
+
return plugins.scan(taskId, params.preparationId, params.directory);
|
|
258
|
+
if (name === "plugin.validate")
|
|
259
|
+
return plugins.validate(invocation.context, params.preparationId, params.directory);
|
|
260
|
+
if (name === "plugin.validation")
|
|
261
|
+
return plugins.inspect(taskId, params.validationId);
|
|
262
|
+
if (name === "plugin.inspect")
|
|
263
|
+
return plugins.current(taskId, params.id);
|
|
264
|
+
if (name === "plugin.list")
|
|
265
|
+
return plugins.list(taskId);
|
|
266
|
+
if (name === "plugin.activate")
|
|
267
|
+
return plugins.activate(invocation.context, params.validationId);
|
|
268
|
+
if (name === "plugin.disable")
|
|
269
|
+
return plugins.disable(taskId, params.id);
|
|
270
|
+
if (name === "context.read") {
|
|
271
|
+
const core = readTaskContext(store, taskId, callerEnvironment(caller));
|
|
272
|
+
return withContextObservations(core, contextProviders);
|
|
273
|
+
}
|
|
274
|
+
if (name === "context.delta")
|
|
275
|
+
return readTaskContextDelta(store, taskId, {
|
|
276
|
+
after: params.after, continuation: params.continuation,
|
|
277
|
+
limit: params.limit
|
|
278
|
+
}, callerEnvironment(caller));
|
|
279
|
+
if (name === "context.inspect")
|
|
280
|
+
return inspectTaskContext(store, taskId, {
|
|
281
|
+
store: params.store, refId: params.refId, digest: params.digest
|
|
282
|
+
}, callerEnvironment(caller));
|
|
283
|
+
// File/directory artifacts live in the Task's local Git repository, not
|
|
284
|
+
// the DB. Save commits exactly one path and returns a self-certifying
|
|
285
|
+
// commit-pinned reference; read/list are ordinary current reads. These
|
|
286
|
+
// are the async Git path (the capability layer awaits invoke()).
|
|
287
|
+
if (name === "artifact.save")
|
|
288
|
+
return saveArtifactCapability(store.rootDirectory(), taskId, {
|
|
289
|
+
relativePath: params.relativePath, content: params.content,
|
|
290
|
+
...(params.message === undefined ? {} : { message: params.message }),
|
|
291
|
+
...(params.expectedHead === undefined ? {} : { expectedHead: params.expectedHead })
|
|
292
|
+
});
|
|
293
|
+
if (name === "artifact.read")
|
|
294
|
+
return readArtifactCapability(store.rootDirectory(), taskId, {
|
|
295
|
+
relativePath: params.relativePath,
|
|
296
|
+
...(params.commit === undefined ? {} : { commit: params.commit })
|
|
297
|
+
});
|
|
298
|
+
if (name === "artifact.list")
|
|
299
|
+
return listArtifactsCapability(store.rootDirectory(), taskId);
|
|
300
|
+
if (name === "environment.prepare")
|
|
301
|
+
return resources.prepare(taskId, params.plan);
|
|
302
|
+
if (name === "environment.adopt")
|
|
303
|
+
return resources.adopt(taskId, params.preparationId);
|
|
304
|
+
if (name === "environment.bind") {
|
|
305
|
+
const role = resources.bindEnvironment(taskId, params.roleName, params.preparationId, {
|
|
306
|
+
source: name, actorId: invocation.context.actorId, requestId: invocation.requestId
|
|
307
|
+
});
|
|
308
|
+
signal(taskId);
|
|
309
|
+
return role;
|
|
310
|
+
}
|
|
311
|
+
if (name === "environment.release") {
|
|
312
|
+
plugins.assertEnvironmentUnused(taskId, params.preparationId);
|
|
313
|
+
return resources.release(taskId, params.preparationId, params.quiescence === undefined ? undefined : { quiescence: params.quiescence });
|
|
314
|
+
}
|
|
315
|
+
if (name === "environment.list")
|
|
316
|
+
return store.listEnvironmentPreparations(taskId);
|
|
317
|
+
if (name === "resource.local.register")
|
|
318
|
+
return resources.registerLocalDirectory(params.displayName, params.path);
|
|
319
|
+
if (name === "resource.local.read")
|
|
320
|
+
return resources.readLocalResource(taskId, params.resourceId);
|
|
321
|
+
if (name === "project.context")
|
|
322
|
+
return resources.projectContext(taskId, params.projectId);
|
|
323
|
+
if (name === "project.resources.configure")
|
|
324
|
+
return resources.configureProject(params.projectId, params.resourceRefs, params.defaultCapabilityProviders);
|
|
107
325
|
if (name === "task.read")
|
|
108
326
|
return requireTask(store, taskId);
|
|
109
327
|
if (name === "resource.workspaces")
|
|
110
328
|
return store.listManagedWorkspaces(taskId);
|
|
329
|
+
if (name === "resource.git.result")
|
|
330
|
+
return resources.gitResult(taskId, params.changeSetId);
|
|
111
331
|
if (name === "config.read")
|
|
112
332
|
return runConfigCommand(params.domain, ["show"], store).data;
|
|
113
333
|
if (name === "task.update") {
|
|
@@ -147,24 +367,45 @@ export function createBuiltinCapabilities(host, store, jobs, signal = () => unde
|
|
|
147
367
|
const registry = new CapabilityRegistry(host, (context, descriptor, input) => {
|
|
148
368
|
const caller = current(context);
|
|
149
369
|
const task = requireTask(store, context.targetId);
|
|
370
|
+
if (caller.scope === "user" && descriptor !== undefined && descriptor.effect !== "query") {
|
|
371
|
+
throw new Error("Web panels may only query capabilities.");
|
|
372
|
+
}
|
|
150
373
|
if (typeof input === "object" && input !== null && "taskId" in input && input.taskId !== task.id) {
|
|
151
374
|
throw new Error("Capability target is outside the authenticated Task.");
|
|
152
375
|
}
|
|
153
376
|
for (const permission of descriptor?.requiredPermissions ?? []) {
|
|
377
|
+
if (permission === "job:start" && caller.scope === "task") {
|
|
378
|
+
const sessions = store.getTaskRoleSessionSet(task.id, caller.role);
|
|
379
|
+
if (sessions?.sessions[sessions.activeAgentId]?.effective.executionAuthority !== "delivery") {
|
|
380
|
+
throw new Error("Planning Sessions cannot start delivery Jobs.");
|
|
381
|
+
}
|
|
382
|
+
}
|
|
154
383
|
if (permission === "task:read" || permission === "job:start")
|
|
155
384
|
continue;
|
|
156
385
|
if (permission === "task:manage" && ((caller.scope === "task" && caller.role === "leader")
|
|
157
386
|
|| (caller.scope === "global" && caller.role === "operator")))
|
|
158
387
|
continue;
|
|
159
|
-
|
|
388
|
+
// PluginService binds every management target to this authenticated
|
|
389
|
+
// Task. This admits package management, not author-code execution:
|
|
390
|
+
// adopted environments and exact plugin.execute grants remain separate.
|
|
391
|
+
if (permission === "plugin:manage" && caller.scope === "task" && caller.role === "leader")
|
|
392
|
+
continue;
|
|
393
|
+
if ((permission === "config:read" || permission === "plugin:manage" || permission === "resource:register")
|
|
160
394
|
&& caller.scope === "global" && caller.role === "operator")
|
|
161
395
|
continue;
|
|
162
396
|
throw new Error(`Permission unavailable: ${permission}.`);
|
|
163
397
|
}
|
|
164
398
|
return { taskIds: [task.id], projectIds: task.projectBindings.map((binding) => binding.projectId) };
|
|
165
399
|
}, BUILTIN_CAPABILITIES);
|
|
400
|
+
const plugins = createPluginService(store, host, registry);
|
|
166
401
|
return {
|
|
167
402
|
registry,
|
|
403
|
+
authenticateWebQuery(taskId) {
|
|
404
|
+
requireTask(store, taskId);
|
|
405
|
+
const context = Object.freeze({ actorId: "local-web-user", targetId: taskId });
|
|
406
|
+
webQueries.add(context);
|
|
407
|
+
return context;
|
|
408
|
+
},
|
|
168
409
|
authenticate(caller, taskId) {
|
|
169
410
|
const credential = Object.freeze({ ...caller });
|
|
170
411
|
const context = authority.authenticate(credential, taskId);
|
|
@@ -180,9 +421,11 @@ function requireTask(store, taskId) {
|
|
|
180
421
|
return task;
|
|
181
422
|
}
|
|
182
423
|
function callerEnvironment(caller) {
|
|
424
|
+
if (caller.scope === "user")
|
|
425
|
+
return {};
|
|
183
426
|
return {
|
|
184
427
|
YUI_SESSION_SCOPE: caller.scope, YUI_TASK_ID: caller.taskId,
|
|
185
428
|
YUI_ROLE: caller.role, YUI_AGENT_ID: caller.agentId,
|
|
186
|
-
YUI_ADAPTER_ID: caller.adapterId,
|
|
429
|
+
YUI_ADAPTER_ID: caller.adapterId, YUI_NATIVE_SESSION_ID: caller.nativeSessionId
|
|
187
430
|
};
|
|
188
431
|
}
|