@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,126 @@
|
|
|
1
|
+
import { createTaskEvent } from "../../event/taskEvent.js";
|
|
2
|
+
/**
|
|
3
|
+
* Storage 18 -> 19 data step for task-32 Requirement A (submit intent & Draft
|
|
4
|
+
* auto-routing).
|
|
5
|
+
*
|
|
6
|
+
* This helper is INDEPENDENT, deterministic and idempotent. The unified 18 -> 19
|
|
7
|
+
* migration owned by the artifacts WorkItem REGISTERS it (as its `migrateData`)
|
|
8
|
+
* and bumps `CURRENT_STORAGE_VERSION`; this module neither registers a second
|
|
9
|
+
* migration nor changes any schema.
|
|
10
|
+
*
|
|
11
|
+
* Requirement A adds three optional fields inside `messages.payload`, all part of
|
|
12
|
+
* this same 18 -> 19 contract even though each is optional — "optional" governs a
|
|
13
|
+
* single record's shape, not the Home compatibility line, so the version
|
|
14
|
+
* transition is still declared here and carried by the unified migration:
|
|
15
|
+
*
|
|
16
|
+
* - `intent` (record | discuss | develop): an absent value already reads as
|
|
17
|
+
* `discuss` (never `develop`), so historical Messages need no rewrite.
|
|
18
|
+
* - `submissionKey`: the client-chosen idempotency key. Only ever set going
|
|
19
|
+
* forward; NO historical key is fabricated (task-32 §2.3, message review), so
|
|
20
|
+
* old Messages stay keyless and non-idempotent exactly as before.
|
|
21
|
+
* - `submissionReceipt`: the frozen disposition a keyed submission replays from.
|
|
22
|
+
* Written only alongside a new `submissionKey`, so it too never appears on
|
|
23
|
+
* historical data.
|
|
24
|
+
*
|
|
25
|
+
* Because none of the three needs a value backfilled onto old rows, the only data
|
|
26
|
+
* step this migration performs is the planning-entered reconstruction below.
|
|
27
|
+
*
|
|
28
|
+
* The one fact old data cannot express is "this Draft already entered planning".
|
|
29
|
+
* Before Requirement A a Leader-waking user/operator submission on a Draft WAS
|
|
30
|
+
* the planning discussion, but it left no `task.planning-entered` fact because
|
|
31
|
+
* that event type did not exist. After the upgrade `develop` auto-activates an
|
|
32
|
+
* *unplanned* Draft; without this step a Draft that was mid-discussion would be
|
|
33
|
+
* mis-read as unplanned and snatched into auto-activation (task-32 §2.2, §4).
|
|
34
|
+
*
|
|
35
|
+
* So for every Draft that received at least one legitimate historical planning
|
|
36
|
+
* submission this appends exactly one `task.planning-entered` event, which makes
|
|
37
|
+
* {@link draftHasEnteredPlanning} derive `true` and routes a later develop to
|
|
38
|
+
* manual activation. A qualifying submission is an *unaddressed* user/operator
|
|
39
|
+
* Message that was not save-only (`wakePolicy !== "none"`) — byte-for-byte the
|
|
40
|
+
* same shape the new discuss path routes through the shared submission service.
|
|
41
|
+
*
|
|
42
|
+
* This is deliberately the conservative direction: it can only ever make develop
|
|
43
|
+
* MORE cautious, never activate a Draft it should not. Save-only Messages (old
|
|
44
|
+
* `wakePolicy === "none"`, the shape `record` now names) are excluded, so a Draft
|
|
45
|
+
* that only ever recorded context stays legitimately unplanned and its first
|
|
46
|
+
* develop may still auto-activate. Non-Draft Tasks are skipped because
|
|
47
|
+
* {@link draftHasEnteredPlanning} answers only about Drafts, and Activation
|
|
48
|
+
* requests are left untouched — a legacy request's absent `origin` is the
|
|
49
|
+
* truthful marker that it stays behind explicit activation.
|
|
50
|
+
*/
|
|
51
|
+
export function migrateSubmitIntent(db) {
|
|
52
|
+
const drafts = db.prepare("SELECT task_id FROM tasks_catalog WHERE status = 'draft'").all();
|
|
53
|
+
if (drafts.length === 0)
|
|
54
|
+
return;
|
|
55
|
+
const listMessages = db.prepare("SELECT payload FROM messages WHERE task_id = ? ORDER BY seq ASC");
|
|
56
|
+
const listEventRows = db.prepare("SELECT event_id, type FROM events WHERE task_id = ?");
|
|
57
|
+
const readHighWater = db.prepare("SELECT high_water FROM id_sequences WHERE task_id = ? AND kind = 'event'");
|
|
58
|
+
// Advance the per-Task event high-water to exactly the id we just consumed, so
|
|
59
|
+
// the runtime keeps allocating strictly above every migrated event (mirrors
|
|
60
|
+
// sqliteStore's id_sequences bookkeeping).
|
|
61
|
+
const upsertHighWater = db.prepare(`INSERT INTO id_sequences (task_id, kind, high_water) VALUES (?, 'event', ?)
|
|
62
|
+
ON CONFLICT(task_id, kind) DO UPDATE SET high_water = ?`);
|
|
63
|
+
const insertEvent = db.prepare("INSERT INTO events (task_id, event_id, type, occurred_at, payload) VALUES (?, ?, ?, ?, ?)");
|
|
64
|
+
for (const { task_id: taskId } of drafts) {
|
|
65
|
+
const eventRows = listEventRows.all(taskId);
|
|
66
|
+
// Idempotent: a Draft that already carries the fact (from a prior run of this
|
|
67
|
+
// migration, or from a real runtime planning entry) is left untouched.
|
|
68
|
+
if (eventRows.some((row) => row.type === PLANNING_ENTERED_EVENT_TYPE))
|
|
69
|
+
continue;
|
|
70
|
+
const entry = firstPlanningSubmission(listMessages.all(taskId));
|
|
71
|
+
if (entry === undefined)
|
|
72
|
+
continue;
|
|
73
|
+
// Allocate the next event id from the greater of the recorded high-water and
|
|
74
|
+
// the largest event id actually present, so a fixture or historical database
|
|
75
|
+
// whose id_sequences lags the events table can never produce a colliding id.
|
|
76
|
+
const highWater = readHighWater.get(taskId)?.high_water ?? 0;
|
|
77
|
+
const maxEventSeq = eventRows.reduce((max, row) => Math.max(max, eventSequence(row.event_id)), 0);
|
|
78
|
+
const seq = Math.max(highWater, maxEventSeq) + 1;
|
|
79
|
+
// Build through the shared constructor so a migrated event is byte-identical
|
|
80
|
+
// in shape to one the shared submission service writes at runtime, and dated
|
|
81
|
+
// to the historical submission rather than the wall-clock upgrade moment.
|
|
82
|
+
const event = createTaskEvent(`event-${seq}`, taskId, PLANNING_ENTERED_EVENT_TYPE, { messageId: entry.id, intent: "discuss", derivedBy: MIGRATION_PROVENANCE }, new Date(entry.createdAt));
|
|
83
|
+
insertEvent.run(taskId, event.id, event.type, event.createdAt, JSON.stringify(event));
|
|
84
|
+
upsertHighWater.run(taskId, seq, seq);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* The never-compacted event type recording a Draft entered planning. Inlined as a
|
|
89
|
+
* literal rather than imported so this released migration stays frozen against a
|
|
90
|
+
* future runtime rename of the constant; `TASK_PLANNING_ENTERED_EVENT` is the
|
|
91
|
+
* runtime owner, and a tripwire test asserts the two never diverge.
|
|
92
|
+
*/
|
|
93
|
+
const PLANNING_ENTERED_EVENT_TYPE = "task.planning-entered";
|
|
94
|
+
/** Marks the event as reconstructed by this migration, for later audit. */
|
|
95
|
+
const MIGRATION_PROVENANCE = "submit-intent-migration";
|
|
96
|
+
/**
|
|
97
|
+
* The earliest Message on a Draft that represents a historical planning
|
|
98
|
+
* submission, or `undefined` if the Draft only ever recorded save-only context.
|
|
99
|
+
*
|
|
100
|
+
* A qualifying Message is an unaddressed (`recipient === undefined`) user or
|
|
101
|
+
* operator Message whose wake policy was not `none`. An absent wake policy
|
|
102
|
+
* qualifies: before Requirement A that was the default Leader-waking submission,
|
|
103
|
+
* exactly the shape an omitted intent normalizes to `discuss` today.
|
|
104
|
+
*/
|
|
105
|
+
function firstPlanningSubmission(rows) {
|
|
106
|
+
for (const row of rows) {
|
|
107
|
+
const message = JSON.parse(row.payload);
|
|
108
|
+
if (message.kind !== "user" && message.kind !== "operator")
|
|
109
|
+
continue;
|
|
110
|
+
if (message.recipient !== undefined)
|
|
111
|
+
continue; // an addressed continuation, not a submission
|
|
112
|
+
if (message.wakePolicy === "none")
|
|
113
|
+
continue; // old save-only == record, never planning
|
|
114
|
+
if (typeof message.id !== "string")
|
|
115
|
+
continue;
|
|
116
|
+
if (typeof message.createdAt !== "string")
|
|
117
|
+
continue;
|
|
118
|
+
return { id: message.id, createdAt: message.createdAt };
|
|
119
|
+
}
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
/** The numeric suffix of an `event-<n>` id, or 0 for any unexpected shape. */
|
|
123
|
+
function eventSequence(eventId) {
|
|
124
|
+
const match = /^event-(\d+)$/.exec(eventId);
|
|
125
|
+
return match === null ? 0 : Number.parseInt(match[1], 10);
|
|
126
|
+
}
|
|
@@ -21,10 +21,13 @@
|
|
|
21
21
|
* is a no-op; a crash mid-upgrade rolls the whole migration transaction back.
|
|
22
22
|
*/
|
|
23
23
|
import { createHash } from "node:crypto";
|
|
24
|
+
import { REMOVE_RUNTIME_GENERATION_SQL, removeRuntimeGenerationRecords } from "./migrations/removeRuntimeGeneration.js";
|
|
25
|
+
import { migrateAgentRunContract } from "./migrations/agentRunContract.js";
|
|
26
|
+
import { migrateArtifactsToGit } from "./migrations/artifactsToGit.js";
|
|
24
27
|
import { CURRENT_STORAGE_VERSION, MIN_SUPPORTED_STORAGE_VERSION } from "./storageVersions.js";
|
|
25
28
|
/** Telemetry retention bounds (§4.4). Open question 3 in §11; defaults from the design. */
|
|
26
|
-
export const
|
|
27
|
-
export const
|
|
29
|
+
export const TELEMETRY_KEEP_PER_RUN = 200;
|
|
30
|
+
export const TELEMETRY_RUN_CAP = 50_000;
|
|
28
31
|
/**
|
|
29
32
|
* Version 1 migration: creates every table and index.
|
|
30
33
|
*
|
|
@@ -697,6 +700,449 @@ ON durable_jobs(task_id, json_extract(payload, '$.operation.actorId'),
|
|
|
697
700
|
// Accepted inputs/results can use an exact attempt without a native Turn id.
|
|
698
701
|
// Preserve all valid historical records; never repair failed Turns or logs.
|
|
699
702
|
sql: "SELECT 1; -- exact attempt identity without a fabricated native Turn id"
|
|
703
|
+
},
|
|
704
|
+
{
|
|
705
|
+
version: 4,
|
|
706
|
+
name: "session-and-process-identity",
|
|
707
|
+
introducedIn: "0.15.8",
|
|
708
|
+
sql: REMOVE_RUNTIME_GENERATION_SQL,
|
|
709
|
+
migrateData: removeRuntimeGenerationRecords
|
|
710
|
+
},
|
|
711
|
+
{
|
|
712
|
+
version: 5,
|
|
713
|
+
name: "project-resource-artifacts",
|
|
714
|
+
introducedIn: "0.15.8",
|
|
715
|
+
sql: `
|
|
716
|
+
CREATE TABLE artifacts (
|
|
717
|
+
task_id TEXT NOT NULL REFERENCES tasks_catalog(task_id),
|
|
718
|
+
id TEXT NOT NULL,
|
|
719
|
+
payload TEXT NOT NULL,
|
|
720
|
+
PRIMARY KEY (task_id, id)
|
|
721
|
+
);
|
|
722
|
+
CREATE TABLE local_resources (
|
|
723
|
+
id TEXT PRIMARY KEY,
|
|
724
|
+
canonical_identity TEXT NOT NULL UNIQUE,
|
|
725
|
+
payload TEXT NOT NULL
|
|
726
|
+
);
|
|
727
|
+
CREATE TABLE environment_preparations (
|
|
728
|
+
task_id TEXT NOT NULL REFERENCES tasks_catalog(task_id),
|
|
729
|
+
id TEXT NOT NULL,
|
|
730
|
+
payload TEXT NOT NULL,
|
|
731
|
+
PRIMARY KEY (task_id, id)
|
|
732
|
+
);
|
|
733
|
+
UPDATE projects SET payload = json_set(payload,
|
|
734
|
+
'$.schemaVersion', 6, '$.resourceRefs', json('[]'),
|
|
735
|
+
'$.defaultCapabilityProviders', json('{}'));
|
|
736
|
+
`
|
|
737
|
+
},
|
|
738
|
+
{
|
|
739
|
+
version: 6,
|
|
740
|
+
name: "session-endpoint-implementation",
|
|
741
|
+
introducedIn: "0.15.8",
|
|
742
|
+
// Valid earlier Sessions used these two built-in protocols. Generation 1
|
|
743
|
+
// retains those codecs and identities behind the new execution boundary.
|
|
744
|
+
// Preserve native IDs, effective snapshots and all historical results.
|
|
745
|
+
sql: `
|
|
746
|
+
UPDATE role_session_sets SET payload = json_set(payload, '$.sessions', json((
|
|
747
|
+
SELECT json_group_object(key, json_set(value, '$.schemaVersion', 6,
|
|
748
|
+
'$.endpointImplementation', json_object(
|
|
749
|
+
'id', 'yui.agent-endpoint.' || json_extract(value, '$.adapterId'), 'generation', '1')))
|
|
750
|
+
FROM json_each(payload, '$.sessions')
|
|
751
|
+
)));
|
|
752
|
+
UPDATE role_session_sets SET payload = json_set(payload, '$.history', json((
|
|
753
|
+
SELECT json_group_array(json_set(value, '$.schemaVersion', 6,
|
|
754
|
+
'$.endpointImplementation', json_object(
|
|
755
|
+
'id', 'yui.agent-endpoint.' || json_extract(value, '$.adapterId'), 'generation', '1')))
|
|
756
|
+
FROM json_each(payload, '$.history')
|
|
757
|
+
))) WHERE json_type(payload, '$.history') = 'array';
|
|
758
|
+
UPDATE global_role_session_sets SET payload = json_set(payload, '$.sessions', json((
|
|
759
|
+
SELECT json_group_object(key, json_set(value, '$.schemaVersion', 6,
|
|
760
|
+
'$.endpointImplementation', json_object(
|
|
761
|
+
'id', 'yui.agent-endpoint.' || json_extract(value, '$.adapterId'), 'generation', '1')))
|
|
762
|
+
FROM json_each(payload, '$.sessions')
|
|
763
|
+
)));
|
|
764
|
+
UPDATE global_role_session_sets SET payload = json_set(payload, '$.history', json((
|
|
765
|
+
SELECT json_group_object(key, json_set(value, '$.schemaVersion', 6,
|
|
766
|
+
'$.endpointImplementation', json_object(
|
|
767
|
+
'id', 'yui.agent-endpoint.' || json_extract(value, '$.adapterId'), 'generation', '1')))
|
|
768
|
+
FROM json_each(payload, '$.history')
|
|
769
|
+
))) WHERE json_type(payload, '$.history') = 'object';
|
|
770
|
+
`
|
|
771
|
+
},
|
|
772
|
+
{
|
|
773
|
+
version: 7,
|
|
774
|
+
name: "task-facts-and-explicit-acceptance",
|
|
775
|
+
introducedIn: "0.15.8",
|
|
776
|
+
// Retain the complete retirement metadata/events and diagnostic facts.
|
|
777
|
+
// Only the public lifecycle changes; ordinary stores read one shape.
|
|
778
|
+
sql: `
|
|
779
|
+
UPDATE task_records SET payload = json_set(payload, '$.status', 'cancelled')
|
|
780
|
+
WHERE json_extract(payload, '$.status') = 'retired';
|
|
781
|
+
UPDATE task_records SET payload = json_set(payload, '$.retirementIsolation', json('true'))
|
|
782
|
+
WHERE json_extract(payload, '$.retiredAt') IS NOT NULL;
|
|
783
|
+
UPDATE tasks_catalog SET status = 'cancelled' WHERE status = 'retired';
|
|
784
|
+
UPDATE tasks_catalog SET lifecycle = 'cancelled' WHERE lifecycle = 'retired';
|
|
785
|
+
UPDATE task_records SET brief = json_set(brief, '$.revision', 1) WHERE brief IS NOT NULL;
|
|
786
|
+
UPDATE work_items SET payload = json_set(payload,
|
|
787
|
+
'$.historicalState', json_patch(json('{}'), json_object(
|
|
788
|
+
'status', json_extract(payload, '$.status'),
|
|
789
|
+
'outcome', json_extract(payload, '$.outcome'),
|
|
790
|
+
'endedAt', json_extract(payload, '$.endedAt'))),
|
|
791
|
+
'$.status', CASE status WHEN 'completed' THEN 'accepted' WHEN 'retired' THEN 'retired' ELSE 'open' END);
|
|
792
|
+
UPDATE work_items SET payload = json_remove(payload, '$.outcome', '$.endedAt')
|
|
793
|
+
WHERE json_extract(payload, '$.status') = 'open';
|
|
794
|
+
UPDATE work_items SET status = json_extract(payload, '$.status');
|
|
795
|
+
UPDATE work_items SET payload = json_set(payload, '$.currentCandidateId',
|
|
796
|
+
json_extract(payload, '$.candidates[#-1].id'))
|
|
797
|
+
WHERE json_extract(payload, '$.historicalState.status') = 'awaiting_acceptance';
|
|
798
|
+
UPDATE work_items SET payload = json_set(payload, '$.acceptedCandidateId',
|
|
799
|
+
json_extract(payload, '$.candidates[#-1].id'))
|
|
800
|
+
WHERE status = 'accepted' AND json_array_length(payload, '$.candidates') > 0;
|
|
801
|
+
`
|
|
802
|
+
},
|
|
803
|
+
{
|
|
804
|
+
version: 8,
|
|
805
|
+
name: "event-owned-edit-history",
|
|
806
|
+
introducedIn: "0.15.8",
|
|
807
|
+
// Move embedded histories to one immutable import event per Task.
|
|
808
|
+
// Existing events stay byte-identical; imports supply otherwise missing
|
|
809
|
+
// historical fields and are evidence only, never executable lifecycle input.
|
|
810
|
+
// Candidates may now carry optional fixed Artifact refs; absent refs remain
|
|
811
|
+
// valid for historical Candidates, so this payload addition needs no backfill.
|
|
812
|
+
sql: `
|
|
813
|
+
CREATE TEMP TABLE migrated_edit_history AS
|
|
814
|
+
SELECT records.task_id,
|
|
815
|
+
COALESCE(sequences.high_water, 0) + 1 AS sequence,
|
|
816
|
+
strftime('%Y-%m-%dT%H:%M:%fZ', 'now') AS imported_at,
|
|
817
|
+
json_object(
|
|
818
|
+
'sourceStorageVersion', '7',
|
|
819
|
+
'taskOutcomes', '' || COALESCE(json_extract(records.payload, '$.outcomeHistory'), '[]'),
|
|
820
|
+
'workAcceptances', '' || COALESCE((
|
|
821
|
+
SELECT json_group_array(json_object(
|
|
822
|
+
'workItemId', work_item_id,
|
|
823
|
+
'history', json_extract(payload, '$.acceptanceHistory')))
|
|
824
|
+
FROM (SELECT * FROM work_items
|
|
825
|
+
WHERE task_id = records.task_id
|
|
826
|
+
AND json_array_length(payload, '$.acceptanceHistory') > 0
|
|
827
|
+
ORDER BY work_item_id)
|
|
828
|
+
), '[]')
|
|
829
|
+
) AS history
|
|
830
|
+
FROM task_records AS records
|
|
831
|
+
LEFT JOIN id_sequences AS sequences
|
|
832
|
+
ON sequences.task_id = records.task_id AND sequences.kind = 'event'
|
|
833
|
+
WHERE json_array_length(records.payload, '$.outcomeHistory') > 0
|
|
834
|
+
OR EXISTS (SELECT 1 FROM work_items
|
|
835
|
+
WHERE task_id = records.task_id AND json_array_length(payload, '$.acceptanceHistory') > 0);
|
|
836
|
+
|
|
837
|
+
INSERT INTO events (task_id, event_id, type, occurred_at, payload)
|
|
838
|
+
SELECT task_id, 'event-' || sequence, 'history.imported', imported_at,
|
|
839
|
+
json_object('schemaVersion', 2, 'id', 'event-' || sequence,
|
|
840
|
+
'taskId', task_id, 'type', 'history.imported',
|
|
841
|
+
'createdAt', imported_at, 'payload', json(history))
|
|
842
|
+
FROM migrated_edit_history;
|
|
843
|
+
INSERT INTO id_sequences (task_id, kind, high_water)
|
|
844
|
+
SELECT task_id, 'event', sequence FROM migrated_edit_history WHERE true
|
|
845
|
+
ON CONFLICT(task_id, kind) DO UPDATE SET high_water = excluded.high_water;
|
|
846
|
+
DROP TABLE migrated_edit_history;
|
|
847
|
+
|
|
848
|
+
UPDATE task_records SET payload = json_remove(payload, '$.outcomeHistory'),
|
|
849
|
+
brief = CASE WHEN brief IS NULL THEN NULL ELSE json_remove(brief, '$.revision') END;
|
|
850
|
+
UPDATE work_items SET payload = json_remove(payload, '$.acceptanceHistory');
|
|
851
|
+
`
|
|
852
|
+
},
|
|
853
|
+
{
|
|
854
|
+
version: 9,
|
|
855
|
+
name: "adopted-agent-execution-environment",
|
|
856
|
+
introducedIn: "0.15.8",
|
|
857
|
+
// Optional Role selection and immutable Session/Turn effective snapshot.
|
|
858
|
+
// Existing records deliberately keep their managed-workspace execution;
|
|
859
|
+
// adopted preparations must never be inferred as an automatic binding.
|
|
860
|
+
sql: "SELECT 1; -- explicit adopted execution environment; absent means managed workspace"
|
|
861
|
+
},
|
|
862
|
+
{
|
|
863
|
+
version: 10,
|
|
864
|
+
name: "plugin-validation-evidence",
|
|
865
|
+
introducedIn: "0.15.8",
|
|
866
|
+
sql: `
|
|
867
|
+
CREATE TABLE plugin_validations (
|
|
868
|
+
task_id TEXT NOT NULL REFERENCES tasks_catalog(task_id),
|
|
869
|
+
id TEXT NOT NULL,
|
|
870
|
+
payload TEXT NOT NULL,
|
|
871
|
+
PRIMARY KEY (task_id, id)
|
|
872
|
+
);
|
|
873
|
+
`
|
|
874
|
+
},
|
|
875
|
+
{
|
|
876
|
+
version: 11,
|
|
877
|
+
name: "plugin-enable-intent",
|
|
878
|
+
introducedIn: "0.15.8",
|
|
879
|
+
// A v10 validation proves no enable/disable choice. Preserve it unchanged;
|
|
880
|
+
// never infer desired configuration from historical reports or processes.
|
|
881
|
+
sql: `
|
|
882
|
+
CREATE TABLE plugin_intents (
|
|
883
|
+
task_id TEXT NOT NULL REFERENCES tasks_catalog(task_id),
|
|
884
|
+
plugin_id TEXT NOT NULL,
|
|
885
|
+
payload TEXT NOT NULL,
|
|
886
|
+
PRIMARY KEY (task_id, plugin_id)
|
|
887
|
+
);
|
|
888
|
+
`
|
|
889
|
+
},
|
|
890
|
+
{
|
|
891
|
+
// Renumbered from 10 to 12 when this branch adopted upstream master: PR320
|
|
892
|
+
// took 10 and 11 while this work was in review. Both are already merged, so
|
|
893
|
+
// they own those numbers; this migration appends after them rather than
|
|
894
|
+
// competing for a number, and no released entry is touched.
|
|
895
|
+
version: 12,
|
|
896
|
+
name: "draft-planning-and-deferred-activation",
|
|
897
|
+
// Same unreleased release as migrations 4-11: this does not bump the version.
|
|
898
|
+
introducedIn: "0.15.8",
|
|
899
|
+
// One current-version migration for everything this change adds. No existing
|
|
900
|
+
// record is rewritten and no payload is backfilled:
|
|
901
|
+
//
|
|
902
|
+
// - the optional Task activation request: absent means activation was
|
|
903
|
+
// never explicitly requested, so a Draft is never inferred to have
|
|
904
|
+
// requested it;
|
|
905
|
+
// - its bounded settled-request history: absent means no request ever
|
|
906
|
+
// reached a terminal disposition on this Task. This is a display
|
|
907
|
+
// projection, not the authority: whether an explicitly cancelled or
|
|
908
|
+
// adopted requestId may be replayed is decided from the durable
|
|
909
|
+
// activation event ledger (never compacted), so eviction from this
|
|
910
|
+
// bounded list never resurrects a decided outcome — per-request state
|
|
911
|
+
// inside the Task that owns it, not a second scheduling or operation
|
|
912
|
+
// ledger;
|
|
913
|
+
// - the planning Turn purpose: historical Turns keep their execution or
|
|
914
|
+
// review purpose untouched.
|
|
915
|
+
//
|
|
916
|
+
// The partial indexes bound Draft planning selection and pending-activation
|
|
917
|
+
// recovery to the few rows that qualify, so no execution phase scans Task
|
|
918
|
+
// history to find them. Creating an index adds no row and rewrites no
|
|
919
|
+
// payload.
|
|
920
|
+
sql: `
|
|
921
|
+
-- explicit activation request, its bounded settled history, and planning Turn
|
|
922
|
+
-- purpose; absent means activation was never requested
|
|
923
|
+
CREATE INDEX IF NOT EXISTS idx_turns_planning_active ON turns(task_id, turn_id)
|
|
924
|
+
WHERE status = 'active' AND json_extract(payload, '$.purpose') = 'planning';
|
|
925
|
+
CREATE INDEX IF NOT EXISTS idx_tasks_activation_pending ON task_records(task_id)
|
|
926
|
+
WHERE json_extract(payload, '$.activationRequest.disposition') = 'pending';
|
|
927
|
+
`
|
|
928
|
+
},
|
|
929
|
+
{
|
|
930
|
+
version: 13,
|
|
931
|
+
name: "session-authority-and-execution-admission",
|
|
932
|
+
introducedIn: "0.15.9",
|
|
933
|
+
sql: "SELECT 1; -- AgentRun contract, notification admission and Session authority",
|
|
934
|
+
migrateData: migrateAgentRunContract
|
|
935
|
+
},
|
|
936
|
+
{
|
|
937
|
+
version: 14,
|
|
938
|
+
name: "acp-session-workspace-configuration",
|
|
939
|
+
introducedIn: "0.15.10",
|
|
940
|
+
// ACP is a new legal adapter/configuration value, including its optional
|
|
941
|
+
// additional workspace roots. The v13 baseline has no ACP bindings; existing
|
|
942
|
+
// Codex/Claude configuration and Session history remain valid unchanged.
|
|
943
|
+
// This widens the persistent contract without rewriting payloads or earlier
|
|
944
|
+
// migration checksums. Workspace delivery is negotiated at initialize, not
|
|
945
|
+
// stored as another configuration authority.
|
|
946
|
+
sql: "SELECT 1; -- ACP bindings may carry additionalDirectories; history stays valid"
|
|
947
|
+
},
|
|
948
|
+
{
|
|
949
|
+
version: 15,
|
|
950
|
+
name: "agent-execution-component",
|
|
951
|
+
introducedIn: "0.15.10",
|
|
952
|
+
// Which product executes is now its own recorded fact, separate from the
|
|
953
|
+
// connection plan that reaches it. The plan keeps its `adapterId` name and
|
|
954
|
+
// its meaning; only the product identity is new.
|
|
955
|
+
//
|
|
956
|
+
// The backfill is a total function of the stored plan, never of a command
|
|
957
|
+
// string. `codex` and `claude` each have exactly one component, so those
|
|
958
|
+
// rows gain their true value. Every `acp` row becomes `unknown-acp-agent`:
|
|
959
|
+
// a v14 Home cannot say which product answered, and an executable named
|
|
960
|
+
// `claude-agent-acp` is not evidence that it was the Claude Agent SDK. The
|
|
961
|
+
// unidentified value is the honest one and stays correctable by hand.
|
|
962
|
+
//
|
|
963
|
+
// Sessions keep their own recorded component, so a Session started before
|
|
964
|
+
// this migration continues against exactly the implementation it began on.
|
|
965
|
+
//
|
|
966
|
+
// Every persisted effective snapshot must be reached, not only the ones on
|
|
967
|
+
// Session sets: `validateEffectiveLaunchSnapshot` demands schemaVersion 4,
|
|
968
|
+
// and the upgrade verifier replays it over Runs, WorkItem ExecutionLanes
|
|
969
|
+
// and ReviewRound ExecutionLanes too. A Home holding any of those would
|
|
970
|
+
// otherwise fail the upgrade and roll back. The list below is the
|
|
971
|
+
// verifier's own reachable set, not a scan for fields that look similar.
|
|
972
|
+
sql: `
|
|
973
|
+
UPDATE configured_agents SET payload = json_set(payload,
|
|
974
|
+
'$.schemaVersion', 3,
|
|
975
|
+
'$.component', CASE json_extract(payload, '$.adapterId')
|
|
976
|
+
WHEN 'codex' THEN 'codex-cli'
|
|
977
|
+
WHEN 'claude' THEN 'claude-code-cli'
|
|
978
|
+
ELSE 'unknown-acp-agent' END)
|
|
979
|
+
WHERE json_extract(payload, '$.component') IS NULL;
|
|
980
|
+
|
|
981
|
+
UPDATE global_roles SET payload = json_set(payload, '$.agentBindings', json((
|
|
982
|
+
SELECT json_group_object(key, json_set(value, '$.component',
|
|
983
|
+
CASE json_extract(value, '$.adapterId')
|
|
984
|
+
WHEN 'codex' THEN 'codex-cli'
|
|
985
|
+
WHEN 'claude' THEN 'claude-code-cli'
|
|
986
|
+
ELSE 'unknown-acp-agent' END))
|
|
987
|
+
FROM json_each(payload, '$.agentBindings')
|
|
988
|
+
))) WHERE json_type(payload, '$.agentBindings') = 'object';
|
|
989
|
+
|
|
990
|
+
UPDATE task_roles SET payload = json_set(payload, '$.agentBindings', json((
|
|
991
|
+
SELECT json_group_object(key, json_set(value, '$.component',
|
|
992
|
+
CASE json_extract(value, '$.adapterId')
|
|
993
|
+
WHEN 'codex' THEN 'codex-cli'
|
|
994
|
+
WHEN 'claude' THEN 'claude-code-cli'
|
|
995
|
+
ELSE 'unknown-acp-agent' END))
|
|
996
|
+
FROM json_each(payload, '$.agentBindings')
|
|
997
|
+
))) WHERE json_type(payload, '$.agentBindings') = 'object';
|
|
998
|
+
|
|
999
|
+
UPDATE global_role_session_sets SET payload = json_set(payload, '$.sessions', json((
|
|
1000
|
+
SELECT json_group_object(key, json_set(value, '$.effective.schemaVersion', 4,
|
|
1001
|
+
'$.effective.component', CASE json_extract(value, '$.effective.adapterId')
|
|
1002
|
+
WHEN 'codex' THEN 'codex-cli'
|
|
1003
|
+
WHEN 'claude' THEN 'claude-code-cli'
|
|
1004
|
+
ELSE 'unknown-acp-agent' END))
|
|
1005
|
+
FROM json_each(payload, '$.sessions')
|
|
1006
|
+
))) WHERE json_type(payload, '$.sessions') = 'object';
|
|
1007
|
+
UPDATE global_role_session_sets SET payload = json_set(payload, '$.history', json((
|
|
1008
|
+
SELECT json_group_object(key, json_set(value, '$.effective.schemaVersion', 4,
|
|
1009
|
+
'$.effective.component', CASE json_extract(value, '$.effective.adapterId')
|
|
1010
|
+
WHEN 'codex' THEN 'codex-cli'
|
|
1011
|
+
WHEN 'claude' THEN 'claude-code-cli'
|
|
1012
|
+
ELSE 'unknown-acp-agent' END))
|
|
1013
|
+
FROM json_each(payload, '$.history')
|
|
1014
|
+
))) WHERE json_type(payload, '$.history') = 'object';
|
|
1015
|
+
|
|
1016
|
+
UPDATE role_session_sets SET payload = json_set(payload, '$.sessions', json((
|
|
1017
|
+
SELECT json_group_object(key, json_set(value, '$.effective.schemaVersion', 4,
|
|
1018
|
+
'$.effective.component', CASE json_extract(value, '$.effective.adapterId')
|
|
1019
|
+
WHEN 'codex' THEN 'codex-cli'
|
|
1020
|
+
WHEN 'claude' THEN 'claude-code-cli'
|
|
1021
|
+
ELSE 'unknown-acp-agent' END))
|
|
1022
|
+
FROM json_each(payload, '$.sessions')
|
|
1023
|
+
))) WHERE json_type(payload, '$.sessions') = 'object';
|
|
1024
|
+
UPDATE role_session_sets SET payload = json_set(payload, '$.history', json((
|
|
1025
|
+
SELECT json_group_array(json_set(value, '$.effective.schemaVersion', 4,
|
|
1026
|
+
'$.effective.component', CASE json_extract(value, '$.effective.adapterId')
|
|
1027
|
+
WHEN 'codex' THEN 'codex-cli'
|
|
1028
|
+
WHEN 'claude' THEN 'claude-code-cli'
|
|
1029
|
+
ELSE 'unknown-acp-agent' END))
|
|
1030
|
+
FROM json_each(payload, '$.history')
|
|
1031
|
+
))) WHERE json_type(payload, '$.history') = 'array';
|
|
1032
|
+
|
|
1033
|
+
-- A Turn records the launch it actually ran on, one snapshot per row.
|
|
1034
|
+
UPDATE turns SET payload = json_set(payload,
|
|
1035
|
+
'$.effective.schemaVersion', 4,
|
|
1036
|
+
'$.effective.component', CASE json_extract(payload, '$.effective.adapterId')
|
|
1037
|
+
WHEN 'codex' THEN 'codex-cli'
|
|
1038
|
+
WHEN 'claude' THEN 'claude-code-cli'
|
|
1039
|
+
ELSE 'unknown-acp-agent' END)
|
|
1040
|
+
WHERE json_type(payload, '$.effective') = 'object';
|
|
1041
|
+
|
|
1042
|
+
-- ExecutionLane launch facts are frozen per Lane, inside an array of Groups
|
|
1043
|
+
-- that each hold an array of Lanes. A Lane that was never dispatched has no
|
|
1044
|
+
-- effective at all, and must keep that absence: json_set would otherwise
|
|
1045
|
+
-- create a partial snapshot the Lane validator rejects as incomplete.
|
|
1046
|
+
UPDATE work_items SET payload = json_set(payload, '$.executionGroups', json((
|
|
1047
|
+
SELECT json_group_array(json_set(grp.value, '$.lanes', json((
|
|
1048
|
+
SELECT json_group_array(CASE
|
|
1049
|
+
WHEN json_type(lane.value, '$.effective') = 'object'
|
|
1050
|
+
THEN json_set(lane.value, '$.effective.schemaVersion', 4,
|
|
1051
|
+
'$.effective.component', CASE json_extract(lane.value, '$.effective.adapterId')
|
|
1052
|
+
WHEN 'codex' THEN 'codex-cli'
|
|
1053
|
+
WHEN 'claude' THEN 'claude-code-cli'
|
|
1054
|
+
ELSE 'unknown-acp-agent' END)
|
|
1055
|
+
ELSE lane.value END)
|
|
1056
|
+
FROM json_each(grp.value, '$.lanes') AS lane
|
|
1057
|
+
))))
|
|
1058
|
+
FROM json_each(payload, '$.executionGroups') AS grp
|
|
1059
|
+
))) WHERE json_type(payload, '$.executionGroups') = 'array';
|
|
1060
|
+
|
|
1061
|
+
-- A ReviewRound holds at most one Group, so only the Lane array nests here.
|
|
1062
|
+
UPDATE review_rounds SET payload = json_set(payload, '$.executionGroup.lanes', json((
|
|
1063
|
+
SELECT json_group_array(CASE
|
|
1064
|
+
WHEN json_type(lane.value, '$.effective') = 'object'
|
|
1065
|
+
THEN json_set(lane.value, '$.effective.schemaVersion', 4,
|
|
1066
|
+
'$.effective.component', CASE json_extract(lane.value, '$.effective.adapterId')
|
|
1067
|
+
WHEN 'codex' THEN 'codex-cli'
|
|
1068
|
+
WHEN 'claude' THEN 'claude-code-cli'
|
|
1069
|
+
ELSE 'unknown-acp-agent' END)
|
|
1070
|
+
ELSE lane.value END)
|
|
1071
|
+
FROM json_each(payload, '$.executionGroup.lanes') AS lane
|
|
1072
|
+
))) WHERE json_type(payload, '$.executionGroup.lanes') = 'array';
|
|
1073
|
+
`
|
|
1074
|
+
},
|
|
1075
|
+
{
|
|
1076
|
+
version: 16,
|
|
1077
|
+
name: "acp-session-run-configuration",
|
|
1078
|
+
introducedIn: "0.15.10",
|
|
1079
|
+
// An ACP Role binding may now carry a model, a reasoning effort and a
|
|
1080
|
+
// permission strategy beyond `default`, because Yui's ACP client implements
|
|
1081
|
+
// `session/set_config_option` and pushes those values to the Session before
|
|
1082
|
+
// it prompts. Previously the adapter rejected all three, so no stored
|
|
1083
|
+
// payload can contain them.
|
|
1084
|
+
//
|
|
1085
|
+
// This widens the contract without rewriting anything, and the absence of a
|
|
1086
|
+
// payload update is the substantive decision rather than an omission. A v10
|
|
1087
|
+
// ACP binding holds `permission.strategy = "default"`, which keeps exactly
|
|
1088
|
+
// the meaning it always had: Yui sends no mode, so the Agent's own default
|
|
1089
|
+
// stands. Rewriting those rows to `bypass` — or to any newly expressible
|
|
1090
|
+
// value — would grant authority the user never chose, on Homes whose owner
|
|
1091
|
+
// did nothing but upgrade. `bypass` is reachable only by asking for it.
|
|
1092
|
+
//
|
|
1093
|
+
// Effective launch snapshots need no change either. They already carry
|
|
1094
|
+
// optional `model` and `effort` on the shared base, and their ACP permission
|
|
1095
|
+
// is the same object the adapter canonicalizes, so a historical snapshot
|
|
1096
|
+
// still validates unchanged at schemaVersion 4 across Sessions, Session
|
|
1097
|
+
// history, Turns, WorkItem ExecutionLanes and ReviewRound ExecutionLanes.
|
|
1098
|
+
// A frozen snapshot therefore keeps describing the launch it actually ran,
|
|
1099
|
+
// which is what makes replaying old history honest.
|
|
1100
|
+
sql: "SELECT 1; -- ACP bindings may carry model/effort and a chosen "
|
|
1101
|
+
+ "permission mode; existing `default` bindings keep their meaning"
|
|
1102
|
+
},
|
|
1103
|
+
{
|
|
1104
|
+
version: 17,
|
|
1105
|
+
name: "session-origin-input-requests",
|
|
1106
|
+
introducedIn: "0.15.8",
|
|
1107
|
+
// Widen requester provenance: notifications originate in a current Leader
|
|
1108
|
+
// Session without an AgentRun. Existing schemaVersion-3 requests keep their
|
|
1109
|
+
// exact Run/Session origin, including frozen historical Context values.
|
|
1110
|
+
// No guessed native identity or history rewrite is needed.
|
|
1111
|
+
sql: "SELECT 1; -- InputRequest requester.runId is optional when an exact nativeSessionId is present"
|
|
1112
|
+
},
|
|
1113
|
+
{
|
|
1114
|
+
version: 18,
|
|
1115
|
+
name: "replaceable-session-process-custody",
|
|
1116
|
+
introducedIn: "0.15.8",
|
|
1117
|
+
// Existing Session/Run history remains unchanged. Runtime mailboxes may
|
|
1118
|
+
// now retain explicit replacement intent; OS owner records may identify
|
|
1119
|
+
// the dedicated execution child, independently of a disposable Host.
|
|
1120
|
+
sql: "SELECT 1; -- Replacement intent, independent retained native control evidence/process custody, and optional fixed TaskWake refs"
|
|
1121
|
+
},
|
|
1122
|
+
{
|
|
1123
|
+
version: 19,
|
|
1124
|
+
name: "task-artifacts-local-git",
|
|
1125
|
+
introducedIn: "0.16.0",
|
|
1126
|
+
// Retire the DB-owned immutable Artifact store: file/directory artifacts now
|
|
1127
|
+
// live in a per-Task local Git repository, referenced by a self-certifying
|
|
1128
|
+
// `commit + relativePath`. The whole rewrite is payload work that must READ
|
|
1129
|
+
// the `artifacts` table before it is dropped, so it runs entirely in
|
|
1130
|
+
// `migrateData` (which executes after this `sql`) — the table is dropped
|
|
1131
|
+
// there, last, once its rows have been moved. Requirement A's independent,
|
|
1132
|
+
// deterministic submit-intent backfill (events + id_sequences only) is the
|
|
1133
|
+
// final step inside that same transaction. This `sql` is intentionally a
|
|
1134
|
+
// no-op: dropping the table here would destroy the rows before they move.
|
|
1135
|
+
//
|
|
1136
|
+
// The 18->19 contract also DECLARES three optional `messages.payload` fields
|
|
1137
|
+
// added by Requirement A — `intent` (record|discuss|develop), an optional
|
|
1138
|
+
// client idempotency `submissionKey`, and a frozen `submissionReceipt`
|
|
1139
|
+
// disposition. They add no column and no table and are only ever written
|
|
1140
|
+
// going forward (absent `intent` reads as discuss; absent key is keyless;
|
|
1141
|
+
// absent receipt is a pre-19 message), so NO historical row is rewritten and
|
|
1142
|
+
// no key or receipt is ever fabricated for old data — declaring them here
|
|
1143
|
+
// satisfies "optional still requires a migration declaration".
|
|
1144
|
+
sql: "SELECT 1; -- artifacts move to per-Task local Git; see migrateArtifactsToGit",
|
|
1145
|
+
migrateData: migrateArtifactsToGit
|
|
700
1146
|
}
|
|
701
1147
|
]);
|
|
702
1148
|
for (let index = 0; index < MIGRATIONS.length; index += 1) {
|
|
@@ -713,8 +1159,9 @@ if (MIGRATIONS.at(-1)?.version !== CURRENT_STORAGE_VERSION) {
|
|
|
713
1159
|
/** Current hot-path indexes whose absence would invalidate a current Home. */
|
|
714
1160
|
const REQUIRED_SCHEMA_INDEXES = [
|
|
715
1161
|
"idx_mailboxes_ready",
|
|
716
|
-
"
|
|
717
|
-
"
|
|
1162
|
+
"idx_input_requests_open_hot",
|
|
1163
|
+
"idx_turns_planning_active",
|
|
1164
|
+
"idx_tasks_activation_pending"
|
|
718
1165
|
];
|
|
719
1166
|
function checksum(sql) {
|
|
720
1167
|
return createHash("sha256").update(sql).digest("hex");
|
|
@@ -929,7 +1376,12 @@ export function migrateSqliteSchema(db, options) {
|
|
|
929
1376
|
throw new SqliteSchemaMigrationError(`storage version ${applied.currentVersion} is older than the minimum supported `
|
|
930
1377
|
+ `${MIN_SUPPORTED_STORAGE_VERSION}`, "admission");
|
|
931
1378
|
}
|
|
932
|
-
|
|
1379
|
+
// Production callers omit `throughVersion`, so the effective target is head
|
|
1380
|
+
// and behavior is unchanged; a partial target is honored only in apply mode.
|
|
1381
|
+
const effectiveTarget = options.mode === "apply" && options.throughVersion !== undefined
|
|
1382
|
+
? options.throughVersion
|
|
1383
|
+
: CURRENT_STORAGE_VERSION;
|
|
1384
|
+
const pending = MIGRATIONS.filter((migration) => !applied.versions.has(migration.version) && migration.version <= effectiveTarget);
|
|
933
1385
|
if (!ledgerWasCreated && pending.length > 0 && options.mode === "validate") {
|
|
934
1386
|
throw new SqliteSchemaMigrationError(`Storage version ${applied.currentVersion} requires an explicit upgrade to `
|
|
935
1387
|
+ `${CURRENT_STORAGE_VERSION}`, "admission");
|
|
@@ -937,12 +1389,17 @@ export function migrateSqliteSchema(db, options) {
|
|
|
937
1389
|
const newlyApplied = [];
|
|
938
1390
|
for (const migration of pending) {
|
|
939
1391
|
db.exec(migration.sql);
|
|
1392
|
+
migration.migrateData?.(db);
|
|
940
1393
|
const appliedAt = new Date().toISOString();
|
|
941
1394
|
db.prepare(`INSERT INTO schema_migrations (version, name, applied_at, checksum)
|
|
942
1395
|
VALUES (?, ?, ?, ?)`).run(migration.version, migration.name, appliedAt, checksum(migration.sql));
|
|
943
1396
|
newlyApplied.push(migration.version);
|
|
944
1397
|
}
|
|
945
|
-
|
|
1398
|
+
// The table/index inventory describes the HEAD shape; only assert it once the
|
|
1399
|
+
// migration has actually advanced to head (a deliberate partial target stops
|
|
1400
|
+
// earlier and is validated when the real upgrade later completes it).
|
|
1401
|
+
if (effectiveTarget >= CURRENT_STORAGE_VERSION)
|
|
1402
|
+
validateSchemaObjects(db);
|
|
946
1403
|
return newlyApplied;
|
|
947
1404
|
};
|
|
948
1405
|
const newlyApplied = options.mode === "apply" && !db.inTransaction
|
|
@@ -952,6 +1409,10 @@ export function migrateSqliteSchema(db, options) {
|
|
|
952
1409
|
}
|
|
953
1410
|
/** The names of every table the schema creates (for tests/introspection). */
|
|
954
1411
|
export const SQLITE_SCHEMA_TABLES = [
|
|
1412
|
+
"plugin_intents",
|
|
1413
|
+
"plugin_validations",
|
|
1414
|
+
"local_resources",
|
|
1415
|
+
"environment_preparations",
|
|
955
1416
|
"schema_migrations",
|
|
956
1417
|
"home_meta",
|
|
957
1418
|
"config",
|
|
@@ -967,7 +1428,6 @@ export const SQLITE_SCHEMA_TABLES = [
|
|
|
967
1428
|
"coordination_locks",
|
|
968
1429
|
"integration_queue",
|
|
969
1430
|
"durable_jobs",
|
|
970
|
-
"job_caller_key_hashes",
|
|
971
1431
|
"outbox",
|
|
972
1432
|
"mailboxes",
|
|
973
1433
|
"task_records",
|