@zq-silk/yui 0.13.10 → 0.14.1

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