@zq-silk/yui 0.13.9 → 0.14.0
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 +69 -428
- package/README.md +108 -298
- package/dist/agent/managedRuntimeEnvironment.js +2 -2
- package/dist/cli/commandCatalog.js +39 -77
- package/dist/cli/interactionCandidates.js +4 -4
- package/dist/cli/interactionPolicy.js +7 -10
- package/dist/cli/invocationRouter.js +1 -1
- package/dist/cli/updateCommand.js +6 -27
- package/dist/cli/updateOrchestrator.js +63 -484
- package/dist/cli/updatePorts.js +15 -333
- package/dist/cli/upgradeCommand.js +8 -65
- package/dist/cli.js +57 -242
- package/dist/commands/configCommands.js +11 -62
- package/dist/commands/executionAuditCommands.js +23 -23
- package/dist/commands/globalRoleCommands.js +2 -7
- package/dist/commands/jobCommands.js +1 -4
- package/dist/commands/projectCommands.js +5 -5
- package/dist/commands/releaseCommands.js +3 -10
- package/dist/commands/resourcesCommands.js +2 -2
- package/dist/commands/sessionCommands.js +2 -2
- package/dist/commands/taskActor.js +31 -39
- package/dist/commands/taskChangeSetCommands.js +5 -12
- package/dist/commands/taskCommands.js +464 -1249
- package/dist/commands/taskContextCommand.js +35 -36
- package/dist/commands/taskExecutionCommands.js +33 -46
- package/dist/commands/taskInputCommands.js +20 -42
- package/dist/commands/taskNextActionCommand.js +9 -9
- package/dist/commands/taskOverviewCommand.js +56 -95
- package/dist/commands/taskRoleRuntimeStatus.js +77 -107
- package/dist/commands/taskUpstreamCommands.js +3 -3
- package/dist/commands/taskWorkspaceCommands.js +7 -79
- package/dist/commands/telemetryCommands.js +32 -124
- package/dist/commands/workflowCommands.js +3 -3
- package/dist/completion/fileCompletionManager.js +1 -1
- package/dist/config/configCatalog.js +4 -6
- package/dist/config/yuiConfig.js +6 -43
- package/dist/context/dispatchContext.js +14 -30
- package/dist/context/roleSessionContext.js +2 -2
- package/dist/context/sessionBootstrapManifest.js +2 -2
- package/dist/context/{runContextPack.js → turnContextPack.js} +58 -73
- package/dist/context/turnInputContract.js +204 -0
- package/dist/context/wakeNotification.js +2 -2
- package/dist/controller/agentRuntimeObserver.js +18 -18
- package/dist/controller/clientRuntime.js +13 -20
- package/dist/controller/controller.js +89 -116
- package/dist/controller/fileSchedulerStoreAdapter.js +511 -742
- package/dist/controller/jobControl.js +17 -17
- package/dist/controller/resourceInventory.js +6 -6
- package/dist/controller/resourceInventoryLinux.js +38 -59
- package/dist/controller/resourceInventoryRpc.js +3 -3
- package/dist/controller/resourceInventoryWorker.js +1 -1
- package/dist/controller/runtime.js +46 -53
- package/dist/controller/runtimeEventInbox.js +23 -31
- package/dist/controller/runtimeEventProcessor.js +15 -15
- package/dist/controller/{runtimeHookRunFence.js → runtimeHookTurnFence.js} +87 -81
- package/dist/controller/runtimeLaunchCoordinator.js +3 -3
- package/dist/controller/runtimeObservationHook.js +11 -8
- package/dist/controller/sessionNotify.js +11 -11
- package/dist/controller/structuredProviderObservation.js +89 -16
- package/dist/coordination/workMailbox.js +309 -579
- package/dist/coordination/workMailboxQueue.js +5 -6
- package/dist/core/controllerClient.js +1 -91
- package/dist/core/controllerServer.js +3 -6
- package/dist/doctor/doctor.js +51 -314
- package/dist/execution/candidateConvergence.js +3 -3
- package/dist/execution/executionGroup.js +32 -33
- package/dist/execution/executionHealth.js +36 -38
- package/dist/execution/resourceBroker.js +12 -12
- package/dist/executor/agentExecutor.js +30 -265
- package/dist/executor/effectiveLaunch.js +9 -19
- package/dist/executor/executorRegistry.js +43 -17
- package/dist/executor/fileRoleLaunchPlanner.js +56 -56
- package/dist/executor/launchPlan.js +3 -3
- package/dist/executor/workspacePreflightClassification.js +16 -16
- package/dist/grant/capabilityGrant.js +20 -25
- package/dist/input/inputRequest.js +12 -12
- package/dist/integration/changeSet.js +9 -13
- package/dist/integration/changeSetManifest.js +1 -1
- package/dist/integration/gitIntegrationService.js +2 -2
- package/dist/integration/integrationQueueService.js +5 -21
- package/dist/integration/overlapDiagnostics.js +2 -2
- package/dist/interaction/operatorPresentation.js +1 -1
- package/dist/job/jobRunner.js +1 -1
- package/dist/lifecycle/canonicalLifecycleEvent.js +25 -25
- package/dist/lifecycle/{exactRunTerminalization.js → exactTurnTerminalization.js} +116 -232
- package/dist/message/message.js +6 -6
- package/dist/observability/executionAudit.js +74 -86
- package/dist/observability/faultClassification.js +7 -24
- package/dist/observability/orchestrationMetrics.js +5 -5
- package/dist/observability/runtimeIdentity.js +34 -101
- package/dist/profile/agentProfile.js +1 -1
- package/dist/release/cliHomeReleaseFence.js +3 -3
- package/dist/release/releaseWorkflowEngine.js +6 -10
- package/dist/release/releaseWorkflowPorts.js +2 -2
- package/dist/release/workflowFileLock.js +1 -1
- package/dist/repository/checkoutSwap.js +1 -1
- package/dist/repository/gitWorkspace.js +0 -13
- package/dist/repository/project.js +1 -1
- package/dist/repository/projectMaintenanceLock.js +1 -2
- package/dist/repository/taskBaseFreshness.js +13 -13
- package/dist/repository/taskWorkspaceCoordinator.js +21 -25
- package/dist/repository/taskWorkspaceIdentity.js +8 -21
- package/dist/repository/taskWorkspacePreparer.js +63 -620
- package/dist/resources/autoResourceGc.js +3 -3
- package/dist/resources/liveReferences.js +1 -1
- package/dist/resources/resourceGc.js +1 -1
- package/dist/resources/sqliteResourceRegistry.js +1 -1
- package/dist/review/reviewDecision.js +7 -7
- package/dist/review/reviewFindingLedger.js +1 -1
- package/dist/review/reviewOutcomeClassifier.js +35 -50
- package/dist/review/reviewRound.js +14 -25
- package/dist/review/reviewerAvailability.js +4 -4
- package/dist/review/taskFinalReviewContractResolution.js +41 -0
- package/dist/role/role.js +6 -3
- package/dist/runtime/agentDriver.js +4 -0
- package/dist/runtime/agentHost.js +151 -36
- package/dist/runtime/builtinAgentDrivers.js +79 -2
- package/dist/runtime/codexAppServerRuntime.js +122 -0
- package/dist/runtime/continuationManager.js +3 -5
- package/dist/runtime/exactControlPlane.js +17 -42
- package/dist/runtime/firstProgressAdvisory.js +1 -1
- package/dist/runtime/index.js +2 -2
- package/dist/runtime/launchDiagnostics.js +2 -2
- package/dist/runtime/lifecycleReservation.js +4 -4
- package/dist/runtime/processExitObservation.js +1 -1
- package/dist/runtime/processExitOutbox.js +0 -32
- package/dist/runtime/promptEnvelope.js +9 -9
- package/dist/runtime/providerContinuation.js +2 -2
- package/dist/runtime/providerContinuationReconciliationService.js +2 -2
- package/dist/runtime/providerRuntimeIdentity.js +76 -24
- package/dist/runtime/recentTurnIds.js +38 -0
- package/dist/runtime/runtimeContinuationProjection.js +2 -2
- package/dist/runtime/runtimeHealthPolicy.js +1 -1
- package/dist/runtime/runtimeObservation.js +58 -21
- package/dist/runtime/runtimeProjection.js +19 -27
- package/dist/runtime/sessionLaunchRequest.js +2 -2
- package/dist/runtime/structuredProviderHost.js +177 -12
- package/dist/runtime/tmuxAdapters.js +46 -11
- package/dist/scheduler/activeRoleTurnDelivery.js +245 -0
- package/dist/scheduler/leaderWakeupProcessor.js +147 -445
- package/dist/scheduler/operatorEvent.js +4 -6
- package/dist/scheduler/resourceQueueProjection.js +71 -0
- package/dist/scheduler/{roleRunLiveness.js → roleTurnLiveness.js} +24 -28
- package/dist/scheduler/{roleRunStall.js → roleTurnStall.js} +162 -247
- package/dist/scheduler/taskExecutionProjection.js +99 -99
- package/dist/scheduler/taskObservabilityProjection.js +10 -10
- package/dist/scheduler/taskWake.js +4 -4
- package/dist/scheduler/wakeReason.js +6 -10
- package/dist/scheduler/wakeupQueue.js +0 -9
- package/dist/setup/setupCommand.js +2 -2
- package/dist/storage/currentTaskStore.js +46 -0
- package/dist/storage/persistenceWorker.js +1 -1
- package/dist/storage/sqliteSchema.js +81 -485
- package/dist/storage/sqliteStore.js +206 -365
- package/dist/storage/storageSchema.js +1 -15
- package/dist/storage/storageVersions.js +8 -9
- package/dist/storage/storeRpc.js +10 -34
- package/dist/storage/taskStore.js +63 -3415
- package/dist/storage/upgrade/recordVersions.js +55 -149
- package/dist/storage/upgrade/upgradeOrchestrator.js +89 -1752
- package/dist/task/completionReadiness.js +5 -5
- package/dist/task/deliveryGuard.js +10 -10
- package/dist/task/nextAction.js +74 -77
- package/dist/task/task.js +2 -4
- package/dist/task/taskRecordReference.js +3 -3
- package/dist/task/taskRecordRetirement.js +1 -1
- package/dist/telemetry/sqliteTelemetryStore.js +53 -53
- package/dist/telemetry/telemetryConfig.js +14 -14
- package/dist/telemetry/telemetryWiring.js +8 -14
- package/dist/turn/turn.js +356 -0
- package/dist/{run/runIdentity.js → turn/turnIdentity.js} +4 -4
- package/dist/verification/gateArtifactStore.js +2 -2
- package/dist/web/assets/client/app.js +1 -1
- package/dist/web/assets/client/components.js +29 -54
- package/dist/web/assets/client/i18n.js +17 -37
- package/dist/web/assets/client/view.js +37 -37
- package/dist/web/assets/shell.js +1 -1
- package/dist/web/assets/styles/cards.js +5 -5
- package/dist/web/assets/styles/widgets.js +1 -2
- package/dist/web/webSnapshot.js +65 -60
- package/dist/workItem/workItem.js +11 -11
- package/dist/workspace/workItemChangeSetManager.js +1 -1
- package/docs/task-local-identity.md +5 -5
- package/i18n/README.zh-CN.md +41 -54
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +85 -83
- package/skills/yui-operator/SKILL.md +16 -16
- package/skills/yui-reviewer/SKILL.md +10 -10
- package/skills/yui-runtime/SKILL.md +17 -18
- package/skills/yui-worker/SKILL.md +16 -18
- package/dist/context/runContextContract.js +0 -162
- package/dist/executor/turnCompletion.js +0 -126
- package/dist/review/taskFinalReviewContractEvent.js +0 -1
- package/dist/review/taskFinalReviewContractRebind.js +0 -367
- package/dist/run/agentRun.js +0 -356
- package/dist/run/rejectedYieldAttempt.js +0 -221
- package/dist/run/runControlRequest.js +0 -50
- package/dist/run/yieldReceipt.js +0 -65
- package/dist/runtime/turnCompletion.js +0 -3
- package/dist/scheduler/actionability.js +0 -323
- package/dist/scheduler/activeRoleRunDelivery.js +0 -868
- package/dist/scheduler/activeTaskProgress.js +0 -126
- package/dist/storage/compatibleTaskStore.js +0 -248
- package/dist/storage/migration/baseline.js +0 -78
- package/dist/storage/migration/classifier.js +0 -51
- package/dist/storage/migration/compatibleCodec.js +0 -53
- package/dist/storage/migration/engine.js +0 -147
- package/dist/storage/migration/index.js +0 -33
- package/dist/storage/migration/planner.js +0 -154
- package/dist/storage/migration/productionRegistry.js +0 -3931
- package/dist/storage/migration/registry.js +0 -169
- package/dist/storage/migration/report.js +0 -54
- package/dist/storage/migration/types.js +0 -31
- package/dist/storage/upgrade/homeClassification.js +0 -353
- package/dist/storage/upgrade/homeMigrationTarget.js +0 -595
- package/dist/storage/upgrade/migrationReceipt.js +0 -67
- package/dist/storage/upgrade/offlineUpgradeInventory.js +0 -453
- package/dist/storage/upgrade/productionMigrationRegistry.js +0 -6
- package/dist/storage/upgrade/pseudoLayoutRepair.js +0 -241
- package/dist/storage/upgrade/recordVersionScan.js +0 -176
- package/dist/storage/upgrade/sqliteFileSet.js +0 -50
- package/dist/storage/upgrade/sqliteMigrationTarget.js +0 -375
- package/dist/storage/upgrade/sqliteRecordMigrationTarget.js +0 -305
- package/dist/storage/upgrade/sqliteStateMigration.js +0 -918
- package/dist/storage/upgrade/switchProgress.js +0 -80
- package/dist/storage/upgrade/upgradeReceipt.js +0 -161
- package/dist/storage/upgradeCoordination.js +0 -187
- package/dist/storage/upgradeFence.js +0 -366
- package/dist/telemetry/telemetryCompaction.js +0 -252
|
@@ -1,453 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
2
|
-
import { join } from "node:path";
|
|
3
|
-
import Database from "better-sqlite3";
|
|
4
|
-
import { scanControllerResourceInventory } from "../../controller/resourceInventoryLinux.js";
|
|
5
|
-
import { STORAGE_STATE_FILE } from "../taskStore.js";
|
|
6
|
-
import { SQLITE_LAYOUT_VERSION } from "../sqliteSchema.js";
|
|
7
|
-
import { inspectStorageSchema } from "../storageSchema.js";
|
|
8
|
-
/** Pure blocker policy shared by synthetic tests and the real read-only scan. */
|
|
9
|
-
export function classifyOfflineUpgradeFacts(facts) {
|
|
10
|
-
const blockers = [];
|
|
11
|
-
for (const run of facts.runs) {
|
|
12
|
-
if (run.status !== "active")
|
|
13
|
-
continue;
|
|
14
|
-
blockers.push(identity(run, "active-run"));
|
|
15
|
-
}
|
|
16
|
-
for (const session of facts.sessions) {
|
|
17
|
-
if (session.processState === "live") {
|
|
18
|
-
blockers.push(identity(session, "native-session-live"));
|
|
19
|
-
}
|
|
20
|
-
else if (session.processState === "unknown") {
|
|
21
|
-
blockers.push(identity(session, "native-session-unknown"));
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
for (const inFlight of facts.inFlight) {
|
|
25
|
-
blockers.push(identity(inFlight, "in-flight-run"));
|
|
26
|
-
}
|
|
27
|
-
for (const completion of facts.pendingCompletions) {
|
|
28
|
-
blockers.push(identity(completion, "pending-completion"));
|
|
29
|
-
}
|
|
30
|
-
for (const lifecycle of facts.lifecycle) {
|
|
31
|
-
blockers.push(identity(lifecycle, lifecycle.reason));
|
|
32
|
-
}
|
|
33
|
-
for (const unknown of facts.unknownRuntime ?? []) {
|
|
34
|
-
blockers.push(identity(unknown, "native-session-unknown"));
|
|
35
|
-
}
|
|
36
|
-
return { total: blockers.length, blockers };
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Re-read durable Run/RoleSessionSet/lifecycle facts and the native process
|
|
40
|
-
* inventory without mutating, stopping, acknowledging, or quarantining them.
|
|
41
|
-
*/
|
|
42
|
-
export async function inspectOfflineUpgradeInventory(home, environment = process.env) {
|
|
43
|
-
const inventory = await scanControllerResourceInventory({
|
|
44
|
-
currentHome: home,
|
|
45
|
-
scope: "current",
|
|
46
|
-
environment
|
|
47
|
-
});
|
|
48
|
-
const raw = readRawFacts(home, inventory);
|
|
49
|
-
return classifyOfflineUpgradeFacts(raw);
|
|
50
|
-
}
|
|
51
|
-
function readRawFacts(home, inventory, state = readDurableStateObject(home), conservativeDurableSessions = false) {
|
|
52
|
-
const runs = [];
|
|
53
|
-
const sessions = [];
|
|
54
|
-
const inFlight = [];
|
|
55
|
-
const pendingCompletions = [];
|
|
56
|
-
const lifecycle = [];
|
|
57
|
-
const unknownRuntime = [];
|
|
58
|
-
// Failure to enumerate processes, panes, or sockets means absence cannot be
|
|
59
|
-
// proven. Ownership-load warnings are expected for an old record shape and
|
|
60
|
-
// are handled by the raw durable scan plus unowned live-pane check below.
|
|
61
|
-
if (inventory.warnings.some(isUndeterminableNativeInventoryWarning)) {
|
|
62
|
-
unknownRuntime.push({});
|
|
63
|
-
}
|
|
64
|
-
for (const [taskId, aggregateValue] of Object.entries(record(state.tasks))) {
|
|
65
|
-
const aggregate = record(aggregateValue);
|
|
66
|
-
if (text(record(aggregate.task).status) === "retired")
|
|
67
|
-
continue;
|
|
68
|
-
for (const runValue of Object.values(record(aggregate.agentRuns))) {
|
|
69
|
-
const run = record(runValue);
|
|
70
|
-
const roleName = text(run.roleName);
|
|
71
|
-
const runId = text(run.id);
|
|
72
|
-
if (roleName === undefined || runId === undefined)
|
|
73
|
-
continue;
|
|
74
|
-
runs.push({ taskId, roleName, runId, status: text(run.status) ?? "unknown" });
|
|
75
|
-
}
|
|
76
|
-
for (const [roleName, setValue] of Object.entries(record(aggregate.roleSessionSets))) {
|
|
77
|
-
collectSessionSet({
|
|
78
|
-
taskId,
|
|
79
|
-
roleName,
|
|
80
|
-
set: record(setValue),
|
|
81
|
-
inventory,
|
|
82
|
-
conservativeDurableSessions,
|
|
83
|
-
sessions,
|
|
84
|
-
inFlight,
|
|
85
|
-
pendingCompletions
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
for (const [roleName, setValue] of Object.entries(record(state.globalRoleSessionSets))) {
|
|
90
|
-
collectSessionSet({
|
|
91
|
-
roleName,
|
|
92
|
-
set: record(setValue),
|
|
93
|
-
inventory,
|
|
94
|
-
conservativeDurableSessions,
|
|
95
|
-
sessions,
|
|
96
|
-
inFlight,
|
|
97
|
-
pendingCompletions
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
for (const mailboxValue of Object.values(record(state.mailboxes))) {
|
|
101
|
-
const mailbox = record(mailboxValue);
|
|
102
|
-
const target = record(mailbox.target);
|
|
103
|
-
const kind = text(target.kind);
|
|
104
|
-
if (kind !== "role-runtime" && kind !== "global-role-runtime")
|
|
105
|
-
continue;
|
|
106
|
-
if (!mailboxHasRuntimeWork(mailbox))
|
|
107
|
-
continue;
|
|
108
|
-
lifecycle.push({
|
|
109
|
-
...(text(target.taskId) === undefined ? {} : { taskId: text(target.taskId) }),
|
|
110
|
-
...(text(target.roleName) === undefined ? {} : { roleName: text(target.roleName) }),
|
|
111
|
-
reason: "pending-mailbox"
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
for (let index = 0; index < countPendingInbox(home); index += 1) {
|
|
115
|
-
lifecycle.push({ reason: "pending-inbox" });
|
|
116
|
-
}
|
|
117
|
-
// Any live native pane/process the durable session sets could not identify is
|
|
118
|
-
// still a blocker: its exact owner cannot be proven stopped.
|
|
119
|
-
for (const resource of inventory.resources) {
|
|
120
|
-
if (resource.kind !== "agent-session"
|
|
121
|
-
|| (resource.processes.length === 0 && resource.paneDead !== false))
|
|
122
|
-
continue;
|
|
123
|
-
const owner = resource.owner;
|
|
124
|
-
const known = sessions.some((session) => resourceMatchesSession(resource, session));
|
|
125
|
-
if (known)
|
|
126
|
-
continue;
|
|
127
|
-
const pane = parseManagedPaneTarget(resource.target);
|
|
128
|
-
sessions.push({
|
|
129
|
-
...(owner.kind === "task-role"
|
|
130
|
-
? { taskId: owner.taskId }
|
|
131
|
-
: pane?.taskId === undefined ? {} : { taskId: pane.taskId }),
|
|
132
|
-
roleName: owner.kind === "task-role" || owner.kind === "global-role"
|
|
133
|
-
? owner.roleName
|
|
134
|
-
: pane?.roleName ?? "unknown",
|
|
135
|
-
...(owner.kind === "task-role" || owner.kind === "global-role"
|
|
136
|
-
? {
|
|
137
|
-
...(owner.nativeSessionId === undefined
|
|
138
|
-
? {}
|
|
139
|
-
: { nativeSessionId: owner.nativeSessionId }),
|
|
140
|
-
...(owner.launchId === undefined ? {} : { launchId: owner.launchId })
|
|
141
|
-
}
|
|
142
|
-
: {}),
|
|
143
|
-
status: "unknown",
|
|
144
|
-
processState: "unknown",
|
|
145
|
-
history: false
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
for (let index = 0; index < runs.length; index += 1) {
|
|
149
|
-
const run = runs[index];
|
|
150
|
-
const session = activeCurrentSession(sessions, run.taskId, run.roleName);
|
|
151
|
-
if (session !== undefined) {
|
|
152
|
-
runs[index] = {
|
|
153
|
-
...run,
|
|
154
|
-
...(session.nativeSessionId === undefined
|
|
155
|
-
? {}
|
|
156
|
-
: { nativeSessionId: session.nativeSessionId }),
|
|
157
|
-
...(session.launchId === undefined ? {} : { launchId: session.launchId })
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
return { runs, sessions, inFlight, pendingCompletions, lifecycle, unknownRuntime };
|
|
162
|
-
}
|
|
163
|
-
function parseManagedPaneTarget(target) {
|
|
164
|
-
if (target === undefined)
|
|
165
|
-
return undefined;
|
|
166
|
-
const match = /^yui-[a-f0-9]{12}-(.+):([^:]+)$/u.exec(target);
|
|
167
|
-
if (match === null)
|
|
168
|
-
return undefined;
|
|
169
|
-
return match[1] === "operator"
|
|
170
|
-
? { roleName: match[2] }
|
|
171
|
-
: { taskId: match[1], roleName: match[2] };
|
|
172
|
-
}
|
|
173
|
-
function isUndeterminableNativeInventoryWarning(warning) {
|
|
174
|
-
return warning.startsWith("Cannot enumerate Linux processes")
|
|
175
|
-
|| warning.startsWith("Cannot inspect tmux")
|
|
176
|
-
|| warning.startsWith("Cannot inspect Unix sockets");
|
|
177
|
-
}
|
|
178
|
-
function collectSessionSet(options) {
|
|
179
|
-
const { taskId, roleName, set, inventory, conservativeDurableSessions } = options;
|
|
180
|
-
const currentSessions = Object.entries(record(set.sessions));
|
|
181
|
-
const activeAgentId = text(set.activeAgentId);
|
|
182
|
-
const historyValue = set.history;
|
|
183
|
-
const historySessions = Array.isArray(historyValue)
|
|
184
|
-
? historyValue
|
|
185
|
-
: Object.values(record(historyValue));
|
|
186
|
-
for (const { history, value, active } of [
|
|
187
|
-
...currentSessions.map(([agentId, session]) => ({
|
|
188
|
-
history: false,
|
|
189
|
-
value: session,
|
|
190
|
-
active: activeAgentId !== undefined && agentId === activeAgentId
|
|
191
|
-
})),
|
|
192
|
-
...historySessions.map((session) => ({ history: true, value: session, active: false }))
|
|
193
|
-
]) {
|
|
194
|
-
const session = record(value);
|
|
195
|
-
const nativeSessionId = text(session.nativeSessionId);
|
|
196
|
-
const launchId = text(session.launchId);
|
|
197
|
-
const base = {
|
|
198
|
-
...(taskId === undefined ? {} : { taskId }),
|
|
199
|
-
roleName,
|
|
200
|
-
...(nativeSessionId === undefined ? {} : { nativeSessionId }),
|
|
201
|
-
...(launchId === undefined ? {} : { launchId }),
|
|
202
|
-
status: text(session.status) ?? "unknown",
|
|
203
|
-
history,
|
|
204
|
-
active
|
|
205
|
-
};
|
|
206
|
-
options.sessions.push({
|
|
207
|
-
...base,
|
|
208
|
-
processState: processState(inventory, base, conservativeDurableSessions)
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
const flight = record(set.inFlight);
|
|
212
|
-
const runId = text(flight.runId);
|
|
213
|
-
if (taskId !== undefined && runId !== undefined) {
|
|
214
|
-
const session = activeCurrentSession(options.sessions, taskId, roleName);
|
|
215
|
-
options.inFlight.push({
|
|
216
|
-
taskId,
|
|
217
|
-
roleName,
|
|
218
|
-
runId,
|
|
219
|
-
...(session?.nativeSessionId === undefined
|
|
220
|
-
? {}
|
|
221
|
-
: { nativeSessionId: session.nativeSessionId }),
|
|
222
|
-
...(session?.launchId === undefined ? {} : { launchId: session.launchId })
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
const completion = record(set.pendingTurnCompletion);
|
|
226
|
-
const completionTask = text(completion.taskId) ?? taskId;
|
|
227
|
-
if (completionTask !== undefined && Object.keys(completion).length > 0) {
|
|
228
|
-
const completionRole = text(completion.roleName) ?? roleName;
|
|
229
|
-
const completionNativeSessionId = text(completion.nativeSessionId);
|
|
230
|
-
const completionSession = options.sessions.find((candidate) => (candidate.taskId === completionTask
|
|
231
|
-
&& candidate.roleName === completionRole
|
|
232
|
-
&& completionNativeSessionId !== undefined
|
|
233
|
-
&& candidate.nativeSessionId === completionNativeSessionId));
|
|
234
|
-
options.pendingCompletions.push({
|
|
235
|
-
taskId: completionTask,
|
|
236
|
-
roleName: completionRole,
|
|
237
|
-
...(text(completion.runId) === undefined ? {} : { runId: text(completion.runId) }),
|
|
238
|
-
...(completionNativeSessionId === undefined
|
|
239
|
-
? {}
|
|
240
|
-
: { nativeSessionId: completionNativeSessionId }),
|
|
241
|
-
...(completionSession?.launchId === undefined
|
|
242
|
-
? {}
|
|
243
|
-
: { launchId: completionSession.launchId })
|
|
244
|
-
});
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
function activeCurrentSession(sessions, taskId, roleName) {
|
|
248
|
-
const current = sessions.filter((candidate) => (candidate.taskId === taskId
|
|
249
|
-
&& candidate.roleName === roleName
|
|
250
|
-
&& !candidate.history));
|
|
251
|
-
return current.find(({ active }) => active === true)
|
|
252
|
-
?? (current.length === 1 ? current[0] : undefined);
|
|
253
|
-
}
|
|
254
|
-
function processState(inventory, session, conservativeDurableSessions) {
|
|
255
|
-
const matching = inventory.resources.filter((resource) => (resource.kind === "agent-session" && resourceMatchesSession(resource, session)));
|
|
256
|
-
if (matching.some((resource) => resource.processes.length > 0))
|
|
257
|
-
return "live";
|
|
258
|
-
if (matching.some((resource) => resource.paneDead === false))
|
|
259
|
-
return "unknown";
|
|
260
|
-
// The final SQLite gate runs after BEGIN IMMEDIATE, so no older writer can
|
|
261
|
-
// commit another Session record behind it. Treat every current non-terminal
|
|
262
|
-
// durable Session as active even when the earlier native-process snapshot
|
|
263
|
-
// did not contain it; this closes the inventory-scan -> transaction race.
|
|
264
|
-
if (conservativeDurableSessions
|
|
265
|
-
&& !session.history
|
|
266
|
-
&& session.status !== "stopped"
|
|
267
|
-
&& session.status !== "broken") {
|
|
268
|
-
return "unknown";
|
|
269
|
-
}
|
|
270
|
-
return "stopped";
|
|
271
|
-
}
|
|
272
|
-
function resourceMatchesSession(resource, session) {
|
|
273
|
-
const owner = resource.owner;
|
|
274
|
-
if (owner.kind !== "task-role" && owner.kind !== "global-role")
|
|
275
|
-
return false;
|
|
276
|
-
if (session.taskId === undefined) {
|
|
277
|
-
if (owner.kind !== "global-role")
|
|
278
|
-
return false;
|
|
279
|
-
}
|
|
280
|
-
else if (owner.kind !== "task-role" || owner.taskId !== session.taskId)
|
|
281
|
-
return false;
|
|
282
|
-
if (owner.roleName !== session.roleName)
|
|
283
|
-
return false;
|
|
284
|
-
if (session.nativeSessionId !== undefined && owner.nativeSessionId !== session.nativeSessionId) {
|
|
285
|
-
return false;
|
|
286
|
-
}
|
|
287
|
-
if (session.launchId !== undefined && owner.launchId !== session.launchId)
|
|
288
|
-
return false;
|
|
289
|
-
return true;
|
|
290
|
-
}
|
|
291
|
-
function readDurableStateObject(home) {
|
|
292
|
-
const databasePath = join(home, "yui.db");
|
|
293
|
-
const schema = inspectStorageSchema(home);
|
|
294
|
-
const sqliteIsAuthoritative = (schema.status === "current" || schema.status === "unsupported")
|
|
295
|
-
&& schema.currentLayoutVersion >= SQLITE_LAYOUT_VERSION;
|
|
296
|
-
if (sqliteIsAuthoritative && existsSync(databasePath)) {
|
|
297
|
-
return readSqliteStateObject(databasePath);
|
|
298
|
-
}
|
|
299
|
-
const path = join(home, STORAGE_STATE_FILE);
|
|
300
|
-
if (!existsSync(path))
|
|
301
|
-
return {};
|
|
302
|
-
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
303
|
-
return record(parsed);
|
|
304
|
-
}
|
|
305
|
-
/**
|
|
306
|
-
* Read only the durable runtime families needed by the offline gate. This raw
|
|
307
|
-
* adapter deliberately does not open SqliteTaskStore: a valid pending schema
|
|
308
|
-
* prefix is exactly the state the explicit upgrader must be able to inspect.
|
|
309
|
-
*/
|
|
310
|
-
function readSqliteStateObject(databasePath) {
|
|
311
|
-
const db = new Database(databasePath, { readonly: true, fileMustExist: true });
|
|
312
|
-
try {
|
|
313
|
-
db.pragma("query_only = ON");
|
|
314
|
-
return readSqliteStateObjectFromDatabase(db);
|
|
315
|
-
}
|
|
316
|
-
finally {
|
|
317
|
-
db.close();
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
/**
|
|
321
|
-
* Re-check the authoritative SQLite runtime families on an already-open
|
|
322
|
-
* connection. The in-place upgrader calls this inside its write transaction,
|
|
323
|
-
* after every older writer has either committed or rolled back.
|
|
324
|
-
*/
|
|
325
|
-
export function inspectSqliteDurableUpgradeInventory(home, db) {
|
|
326
|
-
return classifyOfflineUpgradeFacts(readRawFacts(home, { resources: [], warnings: [] }, readSqliteStateObjectFromDatabase(db), true));
|
|
327
|
-
}
|
|
328
|
-
function readSqliteStateObjectFromDatabase(db) {
|
|
329
|
-
const taskRows = db.prepare("SELECT task_id, status FROM tasks_catalog").all();
|
|
330
|
-
// Explicit retirement is the only isolation boundary for anomalous
|
|
331
|
-
// historical runtime state. Completed/archived/draft Tasks still fail
|
|
332
|
-
// closed if they retain an active Run or unfinished lifecycle record.
|
|
333
|
-
const retiredTaskIds = new Set(taskRows.filter(({ status }) => status === "retired").map(({ task_id }) => task_id));
|
|
334
|
-
const tasks = Object.fromEntries(taskRows
|
|
335
|
-
.filter(({ task_id }) => !retiredTaskIds.has(task_id))
|
|
336
|
-
.map(({ task_id, status }) => [task_id, {
|
|
337
|
-
task: { status },
|
|
338
|
-
agentRuns: {},
|
|
339
|
-
roleSessionSets: {}
|
|
340
|
-
}]));
|
|
341
|
-
const taskAggregate = (taskId) => {
|
|
342
|
-
const existing = tasks[taskId];
|
|
343
|
-
if (existing !== undefined)
|
|
344
|
-
return existing;
|
|
345
|
-
const created = { task: {}, agentRuns: {}, roleSessionSets: {} };
|
|
346
|
-
tasks[taskId] = created;
|
|
347
|
-
return created;
|
|
348
|
-
};
|
|
349
|
-
for (const row of db.prepare("SELECT task_id, run_id, role_name, status, payload FROM agent_runs").all()) {
|
|
350
|
-
if (retiredTaskIds.has(row.task_id))
|
|
351
|
-
continue;
|
|
352
|
-
const aggregate = taskAggregate(row.task_id);
|
|
353
|
-
record(aggregate.agentRuns)[row.run_id] = {
|
|
354
|
-
...parseJsonRecord(row.payload, "agent_runs.payload"),
|
|
355
|
-
id: row.run_id,
|
|
356
|
-
roleName: row.role_name,
|
|
357
|
-
status: row.status
|
|
358
|
-
};
|
|
359
|
-
}
|
|
360
|
-
for (const row of db.prepare("SELECT task_id, role_name, payload FROM role_session_sets").all()) {
|
|
361
|
-
if (retiredTaskIds.has(row.task_id))
|
|
362
|
-
continue;
|
|
363
|
-
const aggregate = taskAggregate(row.task_id);
|
|
364
|
-
record(aggregate.roleSessionSets)[row.role_name] = parseJsonRecord(row.payload, "role_session_sets.payload");
|
|
365
|
-
}
|
|
366
|
-
const globalRoleSessionSets = {};
|
|
367
|
-
for (const row of db.prepare("SELECT name, payload FROM global_role_session_sets").all()) {
|
|
368
|
-
globalRoleSessionSets[row.name] = parseJsonRecord(row.payload, "global_role_session_sets.payload");
|
|
369
|
-
}
|
|
370
|
-
const mailboxColumns = new Set(db.pragma("table_info(mailboxes)").map(({ name }) => name));
|
|
371
|
-
const hasInputDelivery = mailboxColumns.has("input_delivery");
|
|
372
|
-
const mailboxes = {};
|
|
373
|
-
for (const row of db.prepare(`SELECT target_key, target_kind, task_id, role_name, processing, pending${hasInputDelivery ? ", input_delivery" : ""} FROM mailboxes`).all()) {
|
|
374
|
-
if (row.task_id !== null && retiredTaskIds.has(row.task_id))
|
|
375
|
-
continue;
|
|
376
|
-
mailboxes[row.target_key] = {
|
|
377
|
-
target: {
|
|
378
|
-
kind: row.target_kind,
|
|
379
|
-
...(row.task_id === null ? {} : { taskId: row.task_id }),
|
|
380
|
-
...(row.role_name === null ? {} : { roleName: row.role_name })
|
|
381
|
-
},
|
|
382
|
-
processing: parseNullableJson(row.processing, "mailboxes.processing"),
|
|
383
|
-
pending: parseNullableJson(row.pending, "mailboxes.pending"),
|
|
384
|
-
inputDelivery: parseNullableJson(row.input_delivery ?? null, "mailboxes.input_delivery")
|
|
385
|
-
};
|
|
386
|
-
}
|
|
387
|
-
return { tasks, globalRoleSessionSets, mailboxes };
|
|
388
|
-
}
|
|
389
|
-
function mailboxHasRuntimeWork(mailbox) {
|
|
390
|
-
if (mailbox.processing !== null && mailbox.processing !== undefined)
|
|
391
|
-
return true;
|
|
392
|
-
if (mailbox.inputDelivery !== null && mailbox.inputDelivery !== undefined)
|
|
393
|
-
return true;
|
|
394
|
-
if (mailbox.pending === null || mailbox.pending === undefined)
|
|
395
|
-
return false;
|
|
396
|
-
const pending = record(mailbox.pending);
|
|
397
|
-
if (Object.hasOwn(pending, "normal") || Object.hasOwn(pending, "userCorrection")) {
|
|
398
|
-
return pending.normal !== null || pending.userCorrection !== null;
|
|
399
|
-
}
|
|
400
|
-
// Pre-v14 mailboxes store one pending batch directly.
|
|
401
|
-
return Object.keys(pending).length > 0;
|
|
402
|
-
}
|
|
403
|
-
function parseJsonRecord(raw, label) {
|
|
404
|
-
const parsed = JSON.parse(raw);
|
|
405
|
-
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
406
|
-
throw new Error(`${label} is not a JSON object.`);
|
|
407
|
-
}
|
|
408
|
-
return parsed;
|
|
409
|
-
}
|
|
410
|
-
function parseNullableJson(raw, label) {
|
|
411
|
-
if (raw === null)
|
|
412
|
-
return null;
|
|
413
|
-
try {
|
|
414
|
-
return JSON.parse(raw);
|
|
415
|
-
}
|
|
416
|
-
catch (error) {
|
|
417
|
-
throw new Error(`${label} is not valid JSON.`, { cause: error });
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
function countPendingInbox(home) {
|
|
421
|
-
return [join(home, "runtime", "inbox"), join(home, "runtime", "inbox-invalid")]
|
|
422
|
-
.reduce((total, directory) => total + countDirectory(directory), 0);
|
|
423
|
-
}
|
|
424
|
-
function countDirectory(directory) {
|
|
425
|
-
try {
|
|
426
|
-
return readdirSync(directory).filter((name) => (name.endsWith(".json") || name.includes(".tmp-") || !name.startsWith("."))).length;
|
|
427
|
-
}
|
|
428
|
-
catch (error) {
|
|
429
|
-
if (error instanceof Error && "code" in error && error.code === "ENOENT")
|
|
430
|
-
return 0;
|
|
431
|
-
return 1;
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
function identity(value, reason) {
|
|
435
|
-
return {
|
|
436
|
-
...(value.taskId === undefined ? {} : { taskId: value.taskId }),
|
|
437
|
-
...(value.roleName === undefined ? {} : { roleName: value.roleName }),
|
|
438
|
-
...(value.runId === undefined ? {} : { runId: value.runId }),
|
|
439
|
-
...(value.nativeSessionId === undefined
|
|
440
|
-
? {}
|
|
441
|
-
: { nativeSessionId: value.nativeSessionId }),
|
|
442
|
-
...(value.launchId === undefined ? {} : { launchId: value.launchId }),
|
|
443
|
-
reason
|
|
444
|
-
};
|
|
445
|
-
}
|
|
446
|
-
function record(value) {
|
|
447
|
-
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
448
|
-
? value
|
|
449
|
-
: {};
|
|
450
|
-
}
|
|
451
|
-
function text(value) {
|
|
452
|
-
return typeof value === "string" && value.trim().length > 0 ? value : undefined;
|
|
453
|
-
}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Backward-compatible import path for the one production storage registry.
|
|
3
|
-
* Compatible loading and offline migration share the declaration graph owned by
|
|
4
|
-
* `storage/migration/productionRegistry.ts`.
|
|
5
|
-
*/
|
|
6
|
-
export { createProductionStorageRegistry as createProductionMigrationRegistry } from "../migration/productionRegistry.js";
|