@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.
Files changed (229) hide show
  1. package/ARCHITECTURE.md +69 -428
  2. package/README.md +108 -298
  3. package/dist/agent/managedRuntimeEnvironment.js +2 -2
  4. package/dist/cli/commandCatalog.js +39 -77
  5. package/dist/cli/interactionCandidates.js +4 -4
  6. package/dist/cli/interactionPolicy.js +7 -10
  7. package/dist/cli/invocationRouter.js +1 -1
  8. package/dist/cli/updateCommand.js +6 -27
  9. package/dist/cli/updateOrchestrator.js +63 -484
  10. package/dist/cli/updatePorts.js +15 -333
  11. package/dist/cli/upgradeCommand.js +8 -65
  12. package/dist/cli.js +57 -242
  13. package/dist/commands/configCommands.js +11 -62
  14. package/dist/commands/executionAuditCommands.js +23 -23
  15. package/dist/commands/globalRoleCommands.js +2 -7
  16. package/dist/commands/jobCommands.js +1 -4
  17. package/dist/commands/projectCommands.js +5 -5
  18. package/dist/commands/releaseCommands.js +3 -10
  19. package/dist/commands/resourcesCommands.js +2 -2
  20. package/dist/commands/sessionCommands.js +2 -2
  21. package/dist/commands/taskActor.js +31 -39
  22. package/dist/commands/taskChangeSetCommands.js +5 -12
  23. package/dist/commands/taskCommands.js +464 -1249
  24. package/dist/commands/taskContextCommand.js +35 -36
  25. package/dist/commands/taskExecutionCommands.js +33 -46
  26. package/dist/commands/taskInputCommands.js +20 -42
  27. package/dist/commands/taskNextActionCommand.js +9 -9
  28. package/dist/commands/taskOverviewCommand.js +56 -95
  29. package/dist/commands/taskRoleRuntimeStatus.js +77 -107
  30. package/dist/commands/taskUpstreamCommands.js +3 -3
  31. package/dist/commands/taskWorkspaceCommands.js +7 -79
  32. package/dist/commands/telemetryCommands.js +32 -124
  33. package/dist/commands/workflowCommands.js +3 -3
  34. package/dist/completion/fileCompletionManager.js +1 -1
  35. package/dist/config/configCatalog.js +4 -6
  36. package/dist/config/yuiConfig.js +6 -43
  37. package/dist/context/dispatchContext.js +14 -30
  38. package/dist/context/roleSessionContext.js +2 -2
  39. package/dist/context/sessionBootstrapManifest.js +2 -2
  40. package/dist/context/{runContextPack.js → turnContextPack.js} +58 -73
  41. package/dist/context/turnInputContract.js +204 -0
  42. package/dist/context/wakeNotification.js +2 -2
  43. package/dist/controller/agentRuntimeObserver.js +18 -18
  44. package/dist/controller/clientRuntime.js +13 -20
  45. package/dist/controller/controller.js +89 -116
  46. package/dist/controller/fileSchedulerStoreAdapter.js +511 -742
  47. package/dist/controller/jobControl.js +17 -17
  48. package/dist/controller/resourceInventory.js +6 -6
  49. package/dist/controller/resourceInventoryLinux.js +38 -59
  50. package/dist/controller/resourceInventoryRpc.js +3 -3
  51. package/dist/controller/resourceInventoryWorker.js +1 -1
  52. package/dist/controller/runtime.js +46 -53
  53. package/dist/controller/runtimeEventInbox.js +23 -31
  54. package/dist/controller/runtimeEventProcessor.js +15 -15
  55. package/dist/controller/{runtimeHookRunFence.js → runtimeHookTurnFence.js} +87 -81
  56. package/dist/controller/runtimeLaunchCoordinator.js +3 -3
  57. package/dist/controller/runtimeObservationHook.js +11 -8
  58. package/dist/controller/sessionNotify.js +11 -11
  59. package/dist/controller/structuredProviderObservation.js +89 -16
  60. package/dist/coordination/workMailbox.js +309 -579
  61. package/dist/coordination/workMailboxQueue.js +5 -6
  62. package/dist/core/controllerClient.js +1 -91
  63. package/dist/core/controllerServer.js +3 -6
  64. package/dist/doctor/doctor.js +51 -314
  65. package/dist/execution/candidateConvergence.js +3 -3
  66. package/dist/execution/executionGroup.js +32 -33
  67. package/dist/execution/executionHealth.js +36 -38
  68. package/dist/execution/resourceBroker.js +12 -12
  69. package/dist/executor/agentExecutor.js +30 -265
  70. package/dist/executor/effectiveLaunch.js +9 -19
  71. package/dist/executor/executorRegistry.js +43 -17
  72. package/dist/executor/fileRoleLaunchPlanner.js +56 -56
  73. package/dist/executor/launchPlan.js +3 -3
  74. package/dist/executor/workspacePreflightClassification.js +16 -16
  75. package/dist/grant/capabilityGrant.js +20 -25
  76. package/dist/input/inputRequest.js +12 -12
  77. package/dist/integration/changeSet.js +9 -13
  78. package/dist/integration/changeSetManifest.js +1 -1
  79. package/dist/integration/gitIntegrationService.js +2 -2
  80. package/dist/integration/integrationQueueService.js +5 -21
  81. package/dist/integration/overlapDiagnostics.js +2 -2
  82. package/dist/interaction/operatorPresentation.js +1 -1
  83. package/dist/job/jobRunner.js +1 -1
  84. package/dist/lifecycle/canonicalLifecycleEvent.js +25 -25
  85. package/dist/lifecycle/{exactRunTerminalization.js → exactTurnTerminalization.js} +116 -232
  86. package/dist/message/message.js +6 -6
  87. package/dist/observability/executionAudit.js +74 -86
  88. package/dist/observability/faultClassification.js +7 -24
  89. package/dist/observability/orchestrationMetrics.js +5 -5
  90. package/dist/observability/runtimeIdentity.js +34 -101
  91. package/dist/profile/agentProfile.js +1 -1
  92. package/dist/release/cliHomeReleaseFence.js +3 -3
  93. package/dist/release/releaseWorkflowEngine.js +6 -10
  94. package/dist/release/releaseWorkflowPorts.js +2 -2
  95. package/dist/release/workflowFileLock.js +1 -1
  96. package/dist/repository/checkoutSwap.js +1 -1
  97. package/dist/repository/gitWorkspace.js +0 -13
  98. package/dist/repository/project.js +1 -1
  99. package/dist/repository/projectMaintenanceLock.js +1 -2
  100. package/dist/repository/taskBaseFreshness.js +13 -13
  101. package/dist/repository/taskWorkspaceCoordinator.js +21 -25
  102. package/dist/repository/taskWorkspaceIdentity.js +8 -21
  103. package/dist/repository/taskWorkspacePreparer.js +63 -620
  104. package/dist/resources/autoResourceGc.js +3 -3
  105. package/dist/resources/liveReferences.js +1 -1
  106. package/dist/resources/resourceGc.js +1 -1
  107. package/dist/resources/sqliteResourceRegistry.js +1 -1
  108. package/dist/review/reviewDecision.js +7 -7
  109. package/dist/review/reviewFindingLedger.js +1 -1
  110. package/dist/review/reviewOutcomeClassifier.js +35 -50
  111. package/dist/review/reviewRound.js +14 -25
  112. package/dist/review/reviewerAvailability.js +4 -4
  113. package/dist/review/taskFinalReviewContractResolution.js +41 -0
  114. package/dist/role/role.js +6 -3
  115. package/dist/runtime/agentDriver.js +4 -0
  116. package/dist/runtime/agentHost.js +151 -36
  117. package/dist/runtime/builtinAgentDrivers.js +79 -2
  118. package/dist/runtime/codexAppServerRuntime.js +122 -0
  119. package/dist/runtime/continuationManager.js +3 -5
  120. package/dist/runtime/exactControlPlane.js +17 -42
  121. package/dist/runtime/firstProgressAdvisory.js +1 -1
  122. package/dist/runtime/index.js +2 -2
  123. package/dist/runtime/launchDiagnostics.js +2 -2
  124. package/dist/runtime/lifecycleReservation.js +4 -4
  125. package/dist/runtime/processExitObservation.js +1 -1
  126. package/dist/runtime/processExitOutbox.js +0 -32
  127. package/dist/runtime/promptEnvelope.js +9 -9
  128. package/dist/runtime/providerContinuation.js +2 -2
  129. package/dist/runtime/providerContinuationReconciliationService.js +2 -2
  130. package/dist/runtime/providerRuntimeIdentity.js +76 -24
  131. package/dist/runtime/recentTurnIds.js +38 -0
  132. package/dist/runtime/runtimeContinuationProjection.js +2 -2
  133. package/dist/runtime/runtimeHealthPolicy.js +1 -1
  134. package/dist/runtime/runtimeObservation.js +58 -21
  135. package/dist/runtime/runtimeProjection.js +19 -27
  136. package/dist/runtime/sessionLaunchRequest.js +2 -2
  137. package/dist/runtime/structuredProviderHost.js +177 -12
  138. package/dist/runtime/tmuxAdapters.js +46 -11
  139. package/dist/scheduler/activeRoleTurnDelivery.js +245 -0
  140. package/dist/scheduler/leaderWakeupProcessor.js +147 -445
  141. package/dist/scheduler/operatorEvent.js +4 -6
  142. package/dist/scheduler/resourceQueueProjection.js +71 -0
  143. package/dist/scheduler/{roleRunLiveness.js → roleTurnLiveness.js} +24 -28
  144. package/dist/scheduler/{roleRunStall.js → roleTurnStall.js} +162 -247
  145. package/dist/scheduler/taskExecutionProjection.js +99 -99
  146. package/dist/scheduler/taskObservabilityProjection.js +10 -10
  147. package/dist/scheduler/taskWake.js +4 -4
  148. package/dist/scheduler/wakeReason.js +6 -10
  149. package/dist/scheduler/wakeupQueue.js +0 -9
  150. package/dist/setup/setupCommand.js +2 -2
  151. package/dist/storage/currentTaskStore.js +46 -0
  152. package/dist/storage/persistenceWorker.js +1 -1
  153. package/dist/storage/sqliteSchema.js +81 -485
  154. package/dist/storage/sqliteStore.js +206 -365
  155. package/dist/storage/storageSchema.js +1 -15
  156. package/dist/storage/storageVersions.js +8 -9
  157. package/dist/storage/storeRpc.js +10 -34
  158. package/dist/storage/taskStore.js +63 -3415
  159. package/dist/storage/upgrade/recordVersions.js +55 -149
  160. package/dist/storage/upgrade/upgradeOrchestrator.js +89 -1752
  161. package/dist/task/completionReadiness.js +5 -5
  162. package/dist/task/deliveryGuard.js +10 -10
  163. package/dist/task/nextAction.js +74 -77
  164. package/dist/task/task.js +2 -4
  165. package/dist/task/taskRecordReference.js +3 -3
  166. package/dist/task/taskRecordRetirement.js +1 -1
  167. package/dist/telemetry/sqliteTelemetryStore.js +53 -53
  168. package/dist/telemetry/telemetryConfig.js +14 -14
  169. package/dist/telemetry/telemetryWiring.js +8 -14
  170. package/dist/turn/turn.js +356 -0
  171. package/dist/{run/runIdentity.js → turn/turnIdentity.js} +4 -4
  172. package/dist/verification/gateArtifactStore.js +2 -2
  173. package/dist/web/assets/client/app.js +1 -1
  174. package/dist/web/assets/client/components.js +29 -54
  175. package/dist/web/assets/client/i18n.js +17 -37
  176. package/dist/web/assets/client/view.js +37 -37
  177. package/dist/web/assets/shell.js +1 -1
  178. package/dist/web/assets/styles/cards.js +5 -5
  179. package/dist/web/assets/styles/widgets.js +1 -2
  180. package/dist/web/webSnapshot.js +65 -60
  181. package/dist/workItem/workItem.js +11 -11
  182. package/dist/workspace/workItemChangeSetManager.js +1 -1
  183. package/docs/task-local-identity.md +5 -5
  184. package/i18n/README.zh-CN.md +41 -54
  185. package/package.json +1 -1
  186. package/skills/yui-leader/SKILL.md +85 -83
  187. package/skills/yui-operator/SKILL.md +16 -16
  188. package/skills/yui-reviewer/SKILL.md +10 -10
  189. package/skills/yui-runtime/SKILL.md +17 -18
  190. package/skills/yui-worker/SKILL.md +16 -18
  191. package/dist/context/runContextContract.js +0 -162
  192. package/dist/executor/turnCompletion.js +0 -126
  193. package/dist/review/taskFinalReviewContractEvent.js +0 -1
  194. package/dist/review/taskFinalReviewContractRebind.js +0 -367
  195. package/dist/run/agentRun.js +0 -356
  196. package/dist/run/rejectedYieldAttempt.js +0 -221
  197. package/dist/run/runControlRequest.js +0 -50
  198. package/dist/run/yieldReceipt.js +0 -65
  199. package/dist/runtime/turnCompletion.js +0 -3
  200. package/dist/scheduler/actionability.js +0 -323
  201. package/dist/scheduler/activeRoleRunDelivery.js +0 -868
  202. package/dist/scheduler/activeTaskProgress.js +0 -126
  203. package/dist/storage/compatibleTaskStore.js +0 -248
  204. package/dist/storage/migration/baseline.js +0 -78
  205. package/dist/storage/migration/classifier.js +0 -51
  206. package/dist/storage/migration/compatibleCodec.js +0 -53
  207. package/dist/storage/migration/engine.js +0 -147
  208. package/dist/storage/migration/index.js +0 -33
  209. package/dist/storage/migration/planner.js +0 -154
  210. package/dist/storage/migration/productionRegistry.js +0 -3931
  211. package/dist/storage/migration/registry.js +0 -169
  212. package/dist/storage/migration/report.js +0 -54
  213. package/dist/storage/migration/types.js +0 -31
  214. package/dist/storage/upgrade/homeClassification.js +0 -353
  215. package/dist/storage/upgrade/homeMigrationTarget.js +0 -595
  216. package/dist/storage/upgrade/migrationReceipt.js +0 -67
  217. package/dist/storage/upgrade/offlineUpgradeInventory.js +0 -453
  218. package/dist/storage/upgrade/productionMigrationRegistry.js +0 -6
  219. package/dist/storage/upgrade/pseudoLayoutRepair.js +0 -241
  220. package/dist/storage/upgrade/recordVersionScan.js +0 -176
  221. package/dist/storage/upgrade/sqliteFileSet.js +0 -50
  222. package/dist/storage/upgrade/sqliteMigrationTarget.js +0 -375
  223. package/dist/storage/upgrade/sqliteRecordMigrationTarget.js +0 -305
  224. package/dist/storage/upgrade/sqliteStateMigration.js +0 -918
  225. package/dist/storage/upgrade/switchProgress.js +0 -80
  226. package/dist/storage/upgrade/upgradeReceipt.js +0 -161
  227. package/dist/storage/upgradeCoordination.js +0 -187
  228. package/dist/storage/upgradeFence.js +0 -366
  229. 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";