@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
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
import { createTaskEvent } from "../event/taskEvent.js";
|
|
2
|
+
import { enqueueWork } from "../coordination/workMailboxQueue.js";
|
|
3
|
+
import { createProjectResources } from "../resources/projectResourceService.js";
|
|
4
|
+
import { admitTaskActivationRequest, adoptTaskActivationRequest, cancelTaskActivationRequest, canonicalEnvironmentPlan, createTaskActivationRequest, describeEnvironmentPlan, failTaskActivationRequest, settledActivationFromEvents, taskActivationInputDigest, TASK_ACTIVATION_EVENT } from "./taskActivation.js";
|
|
5
|
+
import { setTaskActivationRequest, recordTaskActivationRequestEvidence } from "./task.js";
|
|
6
|
+
/**
|
|
7
|
+
* The terminal outcome already recorded for a requestId, or `undefined` if it
|
|
8
|
+
* was never cancelled or adopted.
|
|
9
|
+
*
|
|
10
|
+
* The authority is the durable activation event ledger, which is never
|
|
11
|
+
* compacted, so a decided outcome survives the bounded display payload evicting
|
|
12
|
+
* its record. The live slot is consulted first only as a fast path for the id
|
|
13
|
+
* that still occupies it; the two always agree, because every terminal
|
|
14
|
+
* transition writes its event in the same transaction that mutates the slot.
|
|
15
|
+
*/
|
|
16
|
+
function settledActivationRequest(reader, task, requestId) {
|
|
17
|
+
const current = task.activationRequest;
|
|
18
|
+
if (current?.operation.requestId === requestId
|
|
19
|
+
&& (current.disposition === "cancelled" || current.disposition === "adopted")) {
|
|
20
|
+
return {
|
|
21
|
+
disposition: current.disposition,
|
|
22
|
+
...(current.outcome === undefined ? {} : { outcome: current.outcome })
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
return settledActivationFromEvents(reader.listEvents(task.id), requestId);
|
|
26
|
+
}
|
|
27
|
+
export function taskActivationOperationRef(taskId, requestId) {
|
|
28
|
+
return `task-activation:${taskId}/${requestId}`;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Records an explicit activation request and returns its operation reference.
|
|
32
|
+
*
|
|
33
|
+
* This never prepares resources and never waits. When the caller is the Task's
|
|
34
|
+
* own running planning Turn, the request is stored with `afterPlanningRun` set
|
|
35
|
+
* to that Turn — expressing the deferral in the same operation facts the
|
|
36
|
+
* request already carries, rather than blocking a synchronous tool on the Turn
|
|
37
|
+
* it is running inside (S40).
|
|
38
|
+
*
|
|
39
|
+
* A repeated requestId with the same inputs returns the existing request
|
|
40
|
+
* unchanged, so a retried tool call cannot produce a second activation.
|
|
41
|
+
*/
|
|
42
|
+
export function requestTaskActivation(store, input, now) {
|
|
43
|
+
return store.transaction((tx) => recordTaskActivationRequestInTransaction(tx, input, now));
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The transactional core of {@link requestTaskActivation}, callable from inside
|
|
47
|
+
* a caller's own open transaction.
|
|
48
|
+
*
|
|
49
|
+
* The shared submission service (task-32 §2.3) records a develop route's
|
|
50
|
+
* activation request in the very transaction that saves the message, so the
|
|
51
|
+
* message and its activation intent commit together and no "submit then
|
|
52
|
+
* activate" two-command window exists. It reuses this exact logic rather than a
|
|
53
|
+
* second activation queue: the same idempotency, settled-id refusal and
|
|
54
|
+
* pending-collision rules apply whether the request arrives from the explicit
|
|
55
|
+
* boundary or from a develop submission. The caller owns transaction lifetime
|
|
56
|
+
* and any post-commit mailbox notification.
|
|
57
|
+
*/
|
|
58
|
+
export function recordTaskActivationRequestInTransaction(tx, input, now) {
|
|
59
|
+
const task = requireOpenDraft(tx, input.taskId);
|
|
60
|
+
const plan = canonicalEnvironmentPlan(input.environmentPlan);
|
|
61
|
+
const planningRun = resolveCallerPlanningRun(tx, task.id, input.callerRunId);
|
|
62
|
+
const startMode = planningRun === undefined
|
|
63
|
+
? "immediate"
|
|
64
|
+
: "after-planning-turn";
|
|
65
|
+
const existing = task.activationRequest;
|
|
66
|
+
// A requestId whose outcome was already decided is never re-opened, whether
|
|
67
|
+
// it still holds the slot or a later request displaced it. Cancelling A,
|
|
68
|
+
// requesting B and then retrying A must not resurrect A: the withdrawal is
|
|
69
|
+
// explicit authority, and adoption is exactly the effect it withdrew. An
|
|
70
|
+
// adopted id is equally final — its environment and status change happened.
|
|
71
|
+
// Only `failed` stays replayable, which is its documented contract.
|
|
72
|
+
//
|
|
73
|
+
// The authority is the durable activation event ledger, not the bounded
|
|
74
|
+
// display payload: the payload trims its oldest entries once it overflows,
|
|
75
|
+
// but the terminal events are never compacted, so an evicted cancellation is
|
|
76
|
+
// still refused with its original outcome instead of silently resurrecting.
|
|
77
|
+
const settled = settledActivationRequest(tx, task, input.requestId);
|
|
78
|
+
if (settled !== undefined) {
|
|
79
|
+
throw new Error(`Activation request ${input.requestId} was already ${settled.disposition} for ${task.id}`
|
|
80
|
+
+ `${settled.outcome === undefined ? "" : ` (${settled.outcome})`}. `
|
|
81
|
+
+ "Use a new requestId.");
|
|
82
|
+
}
|
|
83
|
+
if (existing?.operation.requestId === input.requestId) {
|
|
84
|
+
const digest = taskActivationInputDigest(task.id, {
|
|
85
|
+
startMode,
|
|
86
|
+
...(planningRun === undefined ? {} : { afterPlanningRun: planningRun }),
|
|
87
|
+
environmentPlan: plan
|
|
88
|
+
});
|
|
89
|
+
if (existing.operation.inputDigest !== digest) {
|
|
90
|
+
throw new Error(`Activation requestId ${input.requestId} was already used for different inputs.`);
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
operationRef: taskActivationOperationRef(task.id, existing.operation.requestId),
|
|
94
|
+
request: existing,
|
|
95
|
+
startMode: existing.startMode,
|
|
96
|
+
created: false,
|
|
97
|
+
...(existing.afterPlanningRun === undefined
|
|
98
|
+
? {}
|
|
99
|
+
: { afterPlanningRun: existing.afterPlanningRun })
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
if (existing?.disposition === "pending") {
|
|
103
|
+
throw new Error(`Task already has a pending activation request: ${task.id}/${existing.operation.requestId}. `
|
|
104
|
+
+ "Cancel it before requesting different inputs.");
|
|
105
|
+
}
|
|
106
|
+
const request = createTaskActivationRequest(task.id, {
|
|
107
|
+
requestId: input.requestId,
|
|
108
|
+
actorId: input.actorId,
|
|
109
|
+
authorityRef: input.authorityRef,
|
|
110
|
+
startMode,
|
|
111
|
+
...(input.origin === undefined ? {} : { origin: input.origin }),
|
|
112
|
+
...(planningRun === undefined ? {} : { afterPlanningRun: planningRun }),
|
|
113
|
+
environmentPlan: plan
|
|
114
|
+
}, now);
|
|
115
|
+
tx.saveTask(setTaskActivationRequest(task, request, now));
|
|
116
|
+
tx.saveEvent(task.id, createTaskEvent(tx.nextEventId(task.id), task.id, TASK_ACTIVATION_EVENT.requested, {
|
|
117
|
+
requestId: request.operation.requestId,
|
|
118
|
+
startMode: request.startMode,
|
|
119
|
+
environmentPlan: describeEnvironmentPlan(request.environmentPlan),
|
|
120
|
+
actor: request.operation.actorId,
|
|
121
|
+
...(request.origin === undefined ? {} : { origin: request.origin }),
|
|
122
|
+
...(request.afterPlanningRun === undefined
|
|
123
|
+
? {}
|
|
124
|
+
: { afterPlanningRun: request.afterPlanningRun })
|
|
125
|
+
}, now));
|
|
126
|
+
return {
|
|
127
|
+
operationRef: taskActivationOperationRef(task.id, request.operation.requestId),
|
|
128
|
+
request,
|
|
129
|
+
startMode,
|
|
130
|
+
created: true,
|
|
131
|
+
...(planningRun === undefined ? {} : { afterPlanningRun: planningRun })
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/** Explicit user or Operator cancellation. A cancelled request never adopts. */
|
|
135
|
+
export function cancelTaskActivation(store, taskId, requestId, reason, now) {
|
|
136
|
+
return store.transaction((tx) => {
|
|
137
|
+
const task = tx.getTask(taskId);
|
|
138
|
+
if (task === null)
|
|
139
|
+
throw new Error(`Task not found: ${taskId}.`);
|
|
140
|
+
const existing = task.activationRequest;
|
|
141
|
+
if (existing === undefined || existing.operation.requestId !== requestId) {
|
|
142
|
+
throw new Error(`Activation request not found: ${taskId}/${requestId}.`);
|
|
143
|
+
}
|
|
144
|
+
if (existing.disposition === "adopted") {
|
|
145
|
+
throw new Error(`Activation ${requestId} was already adopted for ${taskId}; its environment and active `
|
|
146
|
+
+ "status are established facts. Stop execution or retire the Task instead.");
|
|
147
|
+
}
|
|
148
|
+
const cancelled = cancelTaskActivationRequest(existing, reason, now);
|
|
149
|
+
if (cancelled !== existing) {
|
|
150
|
+
tx.saveTask(setTaskActivationRequest(task, cancelled, now));
|
|
151
|
+
tx.saveEvent(taskId, createTaskEvent(tx.nextEventId(taskId), taskId, TASK_ACTIVATION_EVENT.cancelled, { requestId, reason: cancelled.outcome ?? reason }, now));
|
|
152
|
+
}
|
|
153
|
+
return cancelled;
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Re-reads the stored request and decides whether it may be adopted now.
|
|
158
|
+
*
|
|
159
|
+
* Called immediately before the adoption boundary, so a Task retired, stopped,
|
|
160
|
+
* or a request cancelled while the planning Turn was still running is caught
|
|
161
|
+
* here rather than replayed as historical intent.
|
|
162
|
+
*/
|
|
163
|
+
export function admitStoredTaskActivation(store, taskId) {
|
|
164
|
+
const task = store.getTask(taskId);
|
|
165
|
+
if (task === null)
|
|
166
|
+
throw new Error(`Task not found: ${taskId}.`);
|
|
167
|
+
const admission = admitTaskActivationRequest(task, task.activationRequest, (runId) => store.getRun(taskId, runId)?.status === "active");
|
|
168
|
+
if (admission === undefined)
|
|
169
|
+
return { disposition: "absent" };
|
|
170
|
+
return admission.disposition === "ready"
|
|
171
|
+
? {
|
|
172
|
+
disposition: "ready",
|
|
173
|
+
request: admission.request,
|
|
174
|
+
plan: admission.request.environmentPlan
|
|
175
|
+
}
|
|
176
|
+
: admission;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Prepares and adopts the request's resource configuration.
|
|
180
|
+
*
|
|
181
|
+
* An empty plan is legal and adopts nothing physical. On failure the request is
|
|
182
|
+
* recorded as failed, the Task remains a continuable Draft, and only resources
|
|
183
|
+
* this call can confirm were never adopted are released — a prepared-but-not
|
|
184
|
+
* adopted scratch directory. Anything whose disposition cannot be proven is
|
|
185
|
+
* retained for its owner to inspect and reported as a `possible` effect.
|
|
186
|
+
*
|
|
187
|
+
* A successful adoption is recorded on the request immediately, against its own
|
|
188
|
+
* requestId. The resources are adopted the moment `adopt` commits, so the effect
|
|
189
|
+
* cannot wait for the Task-status transaction: a cancel or a replacement landing
|
|
190
|
+
* in between must not be able to leave an adopted environment described as
|
|
191
|
+
* `none`, nor attach it to whichever request now holds the slot.
|
|
192
|
+
*/
|
|
193
|
+
export function adoptTaskActivationResources(store, taskId, now = () => new Date()) {
|
|
194
|
+
const admission = admitStoredTaskActivation(store, taskId);
|
|
195
|
+
if (admission.disposition !== "ready") {
|
|
196
|
+
throw new Error(`Task activation is not adoptable: ${taskId}/${admission.disposition}`
|
|
197
|
+
+ (admission.disposition === "unavailable" ? ` (${admission.reason})` : "")
|
|
198
|
+
+ ".");
|
|
199
|
+
}
|
|
200
|
+
const resources = createProjectResources(store, now);
|
|
201
|
+
const plan = admission.plan;
|
|
202
|
+
const requestId = admission.request.operation.requestId;
|
|
203
|
+
if (plan.kind === "empty") {
|
|
204
|
+
// An empty plan owns no physical environment. Nothing is prepared, so
|
|
205
|
+
// nothing can be left half-adopted, and no worktree is created to satisfy
|
|
206
|
+
// the framework's own model.
|
|
207
|
+
return { request: admission.request };
|
|
208
|
+
}
|
|
209
|
+
let prepared;
|
|
210
|
+
try {
|
|
211
|
+
prepared = resources.prepare(taskId, plan);
|
|
212
|
+
const adopted = resources.adopt(taskId, prepared.id);
|
|
213
|
+
// The environment is adopted now. Persist that as a confirmed effect of this
|
|
214
|
+
// requestId before returning, so a cancellation or replacement that races
|
|
215
|
+
// the rest of activation still finds the truth on the request that caused it.
|
|
216
|
+
return {
|
|
217
|
+
request: recordTaskActivationResourceEffect(store, taskId, requestId, adopted.id, now()),
|
|
218
|
+
preparation: adopted
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
catch (error) {
|
|
222
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
223
|
+
const released = releaseUnadoptedPreparation(store, taskId, prepared, now);
|
|
224
|
+
recordFailedTaskActivation(store, taskId, admission.request, message, {
|
|
225
|
+
// Preparation that could not be confirmed unadopted is retained, and its
|
|
226
|
+
// possible effect is recorded rather than erased.
|
|
227
|
+
effect: prepared === undefined ? "none" : released ? "none" : "possible",
|
|
228
|
+
...(prepared === undefined ? {} : { partialResultRefs: [`${taskId}/${prepared.id}`] })
|
|
229
|
+
}, now());
|
|
230
|
+
throw error;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Attaches the adopted environment to the exact request that adopted it.
|
|
235
|
+
*
|
|
236
|
+
* The request keeps its `pending` disposition: resources are adopted, the Task
|
|
237
|
+
* is not active yet, and only the activation transaction may say otherwise. The
|
|
238
|
+
* effect and the preparation ref are recorded by id, so they stay with this
|
|
239
|
+
* request even if it loses the slot before activation completes.
|
|
240
|
+
*/
|
|
241
|
+
function recordTaskActivationResourceEffect(store, taskId, requestId, preparationId, now) {
|
|
242
|
+
return store.transaction((tx) => {
|
|
243
|
+
const task = tx.getTask(taskId);
|
|
244
|
+
if (task === null)
|
|
245
|
+
throw new Error(`Task not found: ${taskId}.`);
|
|
246
|
+
const updated = recordTaskActivationRequestEvidence(task, requestId, {
|
|
247
|
+
effect: "confirmed",
|
|
248
|
+
partialResultRefs: [`${taskId}/${preparationId}`]
|
|
249
|
+
}, now);
|
|
250
|
+
tx.saveTask(updated);
|
|
251
|
+
const request = updated.activationRequest?.operation.requestId === requestId
|
|
252
|
+
? updated.activationRequest
|
|
253
|
+
: updated.settledActivationRequests?.find(({ operation }) => operation.requestId === requestId);
|
|
254
|
+
if (request === undefined) {
|
|
255
|
+
throw new Error(`Activation request disappeared while adopting it: ${taskId}/${requestId}.`);
|
|
256
|
+
}
|
|
257
|
+
return request;
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Records the adopted request inside the caller's activation transaction, so
|
|
262
|
+
* the confirmed operation effect commits with the Task's active status and its
|
|
263
|
+
* environment facts. A later launch failure is reported separately and never
|
|
264
|
+
* rewrites this record.
|
|
265
|
+
*
|
|
266
|
+
* `expected` is the request identity resource adoption actually ran for. It is
|
|
267
|
+
* re-checked here because the slot can change while the workspace is being
|
|
268
|
+
* prepared: a cancelled or replaced request must fail this transaction rather
|
|
269
|
+
* than have someone else's preparation recorded against it. The plan is compared
|
|
270
|
+
* too, so an `empty` request can never inherit a directory it never asked for.
|
|
271
|
+
*
|
|
272
|
+
* Recording a `preparationId` therefore requires `expected`: a preparation only
|
|
273
|
+
* exists because some specific request produced it, so naming one without saying
|
|
274
|
+
* which request it belongs to is never a legal call. It stays optional only for
|
|
275
|
+
* the no-preparation case, where there is no environment to misattribute.
|
|
276
|
+
*/
|
|
277
|
+
export function recordAdoptedTaskActivation(store, task, evidence, now) {
|
|
278
|
+
const existing = task.activationRequest;
|
|
279
|
+
if (existing === undefined)
|
|
280
|
+
return task;
|
|
281
|
+
const expected = evidence.expected;
|
|
282
|
+
if (expected === undefined && evidence.preparationId !== undefined) {
|
|
283
|
+
throw new Error(`Activation adoption must name the request its preparation belongs to: `
|
|
284
|
+
+ `${task.id}/${evidence.preparationId}.`);
|
|
285
|
+
}
|
|
286
|
+
if (expected !== undefined) {
|
|
287
|
+
if (existing.operation.requestId !== expected.operation.requestId) {
|
|
288
|
+
throw new Error(`Activation request changed while activating ${task.id}: prepared `
|
|
289
|
+
+ `${expected.operation.requestId}, found ${existing.operation.requestId}.`);
|
|
290
|
+
}
|
|
291
|
+
if (existing.operation.inputDigest !== expected.operation.inputDigest) {
|
|
292
|
+
throw new Error(`Activation request inputs changed while activating ${task.id}: `
|
|
293
|
+
+ `${existing.operation.requestId}.`);
|
|
294
|
+
}
|
|
295
|
+
if (existing.disposition !== "pending" && existing.disposition !== "adopted") {
|
|
296
|
+
throw new Error(`Activation request is no longer adoptable for ${task.id}: `
|
|
297
|
+
+ `${existing.operation.requestId}/${existing.disposition}`
|
|
298
|
+
+ `${existing.outcome === undefined ? "" : ` (${existing.outcome})`}.`);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
const adopted = adoptTaskActivationRequest(existing, {
|
|
302
|
+
...(evidence.preparationId === undefined
|
|
303
|
+
? {}
|
|
304
|
+
: { preparationId: evidence.preparationId }),
|
|
305
|
+
receiptRefs: [taskActivationOperationRef(task.id, existing.operation.requestId)]
|
|
306
|
+
}, now);
|
|
307
|
+
store.saveEvent(task.id, createTaskEvent(store.nextEventId(task.id), task.id, TASK_ACTIVATION_EVENT.adopted, {
|
|
308
|
+
requestId: adopted.operation.requestId,
|
|
309
|
+
environmentPlan: describeEnvironmentPlan(adopted.environmentPlan),
|
|
310
|
+
...(adopted.preparationId === undefined
|
|
311
|
+
? {}
|
|
312
|
+
: { preparationId: adopted.preparationId })
|
|
313
|
+
}, now));
|
|
314
|
+
return setTaskActivationRequest(task, adopted, now);
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Records that an activation attempt did not adopt. The Task is untouched: it
|
|
318
|
+
* stays a Draft the Leader can keep planning in, with the real preparation
|
|
319
|
+
* evidence preserved.
|
|
320
|
+
*/
|
|
321
|
+
export function recordFailedTaskActivation(store, taskId, request, outcome, evidence, now) {
|
|
322
|
+
return store.transaction((tx) => {
|
|
323
|
+
const task = tx.getTask(taskId);
|
|
324
|
+
if (task === null)
|
|
325
|
+
throw new Error(`Task not found: ${taskId}.`);
|
|
326
|
+
const current = task.activationRequest;
|
|
327
|
+
if (current === undefined
|
|
328
|
+
|| current.operation.requestId !== request.operation.requestId
|
|
329
|
+
|| current.disposition === "adopted"
|
|
330
|
+
|| current.disposition === "cancelled") {
|
|
331
|
+
return current ?? request;
|
|
332
|
+
}
|
|
333
|
+
const failed = failTaskActivationRequest(current, outcome, now, evidence);
|
|
334
|
+
tx.saveTask(setTaskActivationRequest(task, failed, now));
|
|
335
|
+
tx.saveEvent(taskId, createTaskEvent(tx.nextEventId(taskId), taskId, TASK_ACTIVATION_EVENT.failed, {
|
|
336
|
+
requestId: failed.operation.requestId,
|
|
337
|
+
outcome: failed.outcome ?? outcome,
|
|
338
|
+
effect: failed.operation.effect
|
|
339
|
+
}, now));
|
|
340
|
+
if (task.status === "draft") {
|
|
341
|
+
// This is a Core operation result, not a Leader-local planning edit.
|
|
342
|
+
// The Leader must learn the failed disposition and choose a legal next
|
|
343
|
+
// action; merely stopping automatic retries would otherwise strand it.
|
|
344
|
+
enqueueWork(tx, { kind: "role", taskId, roleName: "leader" }, "activation-failed", now, [{ type: "task", id: taskId }]);
|
|
345
|
+
}
|
|
346
|
+
return failed;
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Releases a preparation only when this process can confirm it was never
|
|
351
|
+
* adopted. Returns false when the disposition is unprovable or release itself
|
|
352
|
+
* failed, so the caller records a `possible` effect instead of claiming the
|
|
353
|
+
* resource is clean.
|
|
354
|
+
*/
|
|
355
|
+
function releaseUnadoptedPreparation(store, taskId, prepared, now) {
|
|
356
|
+
if (prepared === undefined)
|
|
357
|
+
return true;
|
|
358
|
+
const current = store.getEnvironmentPreparation(taskId, prepared.id);
|
|
359
|
+
if (current === null)
|
|
360
|
+
return false;
|
|
361
|
+
if (current.disposition === "released")
|
|
362
|
+
return true;
|
|
363
|
+
if (current.disposition !== "prepared")
|
|
364
|
+
return false;
|
|
365
|
+
try {
|
|
366
|
+
createProjectResources(store, now).release(taskId, prepared.id);
|
|
367
|
+
return true;
|
|
368
|
+
}
|
|
369
|
+
catch {
|
|
370
|
+
// The directory is retained for its owner to inspect. Never force-remove
|
|
371
|
+
// an environment whose contents or use cannot be proven.
|
|
372
|
+
return false;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
function requireOpenDraft(store, taskId) {
|
|
376
|
+
const task = store.getTask(taskId);
|
|
377
|
+
if (task === null)
|
|
378
|
+
throw new Error(`Task not found: ${taskId}.`);
|
|
379
|
+
if (task.status !== "draft") {
|
|
380
|
+
throw new Error(`Only a Draft Task can request activation: ${taskId}/${task.status}.`);
|
|
381
|
+
}
|
|
382
|
+
if (task.executionGate.state !== "enabled") {
|
|
383
|
+
throw new Error(`Task execution is stopped: ${taskId}.`);
|
|
384
|
+
}
|
|
385
|
+
return task;
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Resolves the caller's own planning Turn, which is what turns this request
|
|
389
|
+
* into a deferred one. Any other Turn id is rejected rather than silently
|
|
390
|
+
* treated as immediate: a caller that names a Turn is asserting it runs inside
|
|
391
|
+
* it, and a wrong assertion must not quietly change the start mode.
|
|
392
|
+
*/
|
|
393
|
+
function resolveCallerPlanningRun(store, taskId, callerRunId) {
|
|
394
|
+
if (callerRunId === undefined)
|
|
395
|
+
return undefined;
|
|
396
|
+
const run = store.getRun(taskId, callerRunId);
|
|
397
|
+
if (run === null)
|
|
398
|
+
throw new Error(`AgentRun not found: ${taskId}/${callerRunId}.`);
|
|
399
|
+
if (run.purpose !== "planning") {
|
|
400
|
+
throw new Error(`Activation deferral requires a planning AgentRun: ${taskId}/${callerRunId}/${run.purpose}.`);
|
|
401
|
+
}
|
|
402
|
+
if (run.status !== "active") {
|
|
403
|
+
// A terminated planning Turn no longer needs deferral; the request is
|
|
404
|
+
// adoptable now and says so, rather than waiting for a finished Turn.
|
|
405
|
+
return undefined;
|
|
406
|
+
}
|
|
407
|
+
return run.id;
|
|
408
|
+
}
|
|
@@ -2,7 +2,7 @@ import { requireIdentity } from "../domain/validation.js";
|
|
|
2
2
|
export const TASK_RECORD_ID_PREFIXES = {
|
|
3
3
|
workItem: "work-item",
|
|
4
4
|
contextSnapshot: "context-snapshot",
|
|
5
|
-
|
|
5
|
+
run: "run",
|
|
6
6
|
reviewRound: "review-round",
|
|
7
7
|
changeSet: "change-set",
|
|
8
8
|
integrationAttempt: "integration",
|
|
@@ -22,8 +22,8 @@ export function formatTaskRecordReference(taskId, localId, kind) {
|
|
|
22
22
|
const reference = validateTaskRecordReference({ taskId, localId }, kind);
|
|
23
23
|
return `${reference.taskId}/${reference.localId}`;
|
|
24
24
|
}
|
|
25
|
-
export function
|
|
26
|
-
return `turn:${formatTaskRecordReference(taskId,
|
|
25
|
+
export function formatRunReceiptId(taskId, runId) {
|
|
26
|
+
return `turn:${formatTaskRecordReference(taskId, runId, "run")}`;
|
|
27
27
|
}
|
|
28
28
|
export function formatInputRequestReceiptId(taskId, requestId) {
|
|
29
29
|
return `input-request:${formatTaskRecordReference(taskId, requestId, "inputRequest")}`;
|
|
@@ -54,7 +54,8 @@ export function resolveTaskRecordReference(value, options) {
|
|
|
54
54
|
export function validateTaskRecordReference(value, kind) {
|
|
55
55
|
const taskId = requireIdentity(value.taskId, "Task id");
|
|
56
56
|
const localId = requireIdentity(value.localId, `${TASK_RECORD_ID_PREFIXES[kind]} local id`);
|
|
57
|
-
const
|
|
57
|
+
const prefix = kind === "run" ? "(?:run|turn)" : TASK_RECORD_ID_PREFIXES[kind];
|
|
58
|
+
const match = new RegExp(`^${prefix}-([1-9]\\d*)$`).exec(localId);
|
|
58
59
|
if (match === null || !Number.isSafeInteger(Number(match[1]))) {
|
|
59
60
|
throw new Error(`${TASK_RECORD_ID_PREFIXES[kind]} local id is invalid: ${localId}.`);
|
|
60
61
|
}
|