@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
@@ -187,23 +187,23 @@ function validateStartParams(store, params) {
187
187
  /**
188
188
  * rr8/rr12: Bind the declared job owner to the caller's managed identity. The
189
189
  * Controller validates the declared owner/workspace and verifies the caller
190
- * against durable Run/Session state — a self-reported role or scope is never
190
+ * against durable Turn/Session state — a self-reported role or scope is never
191
191
  * authority on its own. The rules:
192
192
  *
193
193
  * - `user` (non-managed): rejected because it has no managed Session identity.
194
194
  * - `global`: full Task authority after current Role Session verification.
195
195
  * - `task` + mismatched taskId: rejected.
196
- * - `task` + missing `runId`: rejected (a managed caller must bind to a Run).
197
- * - `task` + Run not found / not active / `roleName !== role`: rejected — the
198
- * claimed Role must be the real Role of an active Run.
199
- * - `task`: full authority inside the matching Task after active Run and
196
+ * - `task` + missing `turnId`: rejected (a managed caller must bind to a Turn).
197
+ * - `task` + Turn not found / not active / `roleName !== role`: rejected — the
198
+ * claimed Role must be the real Role of an active Turn.
199
+ * - `task`: full authority inside the matching Task after active Turn and
200
200
  * per-Session caller-key verification; Role does not narrow it.
201
201
  */
202
202
  /**
203
203
  * rr13: `job.start`/`job.cancel` caller authorization at the Controller
204
204
  * boundary. Every identity claim the Controller can verify from durable state
205
- * (role and runId) is replayable by any client in the
206
- * same Home that reads state.json. The channel itself is therefore not
205
+ * (role and turnId) is replayable by any client in the
206
+ * same authoritative Controller. The channel itself is therefore not
207
207
  * authenticated by those claims alone. A non-replayable per-Session caller key
208
208
  * closes the gap:
209
209
  *
@@ -213,10 +213,10 @@ function validateStartParams(store, params) {
213
213
  * - `task` scope: the caller must present `callerKey` — the
214
214
  * `YUI_JOB_CALLER_KEY` injected at its native Session launch. The Controller
215
215
  * hashes it (SHA-256) and compares against the durable `jobCallerKeyHashes`
216
- * map for the caller's Role + Agent. No legacy fallback: an absent hash or a
216
+ * map for the caller's Role + Agent. An absent hash or a
217
217
  * mismatched key is UNAUTHORIZED.
218
218
  *
219
- * The existing Run binding checks run after the key check, so a forged
219
+ * The existing Turn binding checks run after the key check, so a forged
220
220
  * identity that also lacks the key is rejected at the channel boundary.
221
221
  */
222
222
  function assertCallerAuthorized(store, caller, taskId) {
@@ -257,16 +257,16 @@ function assertCallerAuthorized(store, caller, taskId) {
257
257
  if (caller.taskId !== taskId) {
258
258
  throw jobControlError("UNAUTHORIZED", "A managed Task Session may not start or cancel Jobs for a different Task.");
259
259
  }
260
- if (caller.runId === undefined) {
261
- throw jobControlError("UNAUTHORIZED", "A managed Task Session must bind its request to a Run.");
260
+ if (caller.turnId === undefined) {
261
+ throw jobControlError("UNAUTHORIZED", "A managed Task Session must bind its request to a Turn.");
262
262
  }
263
- const run = store.getAgentRun(taskId, caller.runId);
263
+ const run = store.getTurn(taskId, caller.turnId);
264
264
  if (run === null || run.status !== "active" || run.roleName !== caller.role) {
265
- throw jobControlError("UNAUTHORIZED", "A managed Task Session's Role is not bound to an active Run.");
265
+ throw jobControlError("UNAUTHORIZED", "A managed Task Session's Role is not bound to an active Turn.");
266
266
  }
267
267
  // rr13: Verify the non-replayable per-Session caller key. The key is injected
268
268
  // at native Session launch and never persisted in plaintext; only its SHA-256
269
- // hash is durable. A client that reads state.json can see the hash but cannot
269
+ // hash is durable. A client with database read access can see the hash but cannot
270
270
  // recover the key.
271
271
  if (caller.callerKey === undefined) {
272
272
  throw jobControlError("UNAUTHORIZED", "job.start/job.cancel requires a managed Session caller key.");
@@ -490,7 +490,7 @@ function parseCaller(value) {
490
490
  const record = value;
491
491
  const allowed = new Set([
492
492
  "scope", "taskId", "role", "agentId", "adapterId", "launchId", "nativeSessionId",
493
- "runId", "callerKey"
493
+ "turnId", "callerKey"
494
494
  ]);
495
495
  for (const key of Object.keys(record)) {
496
496
  if (!allowed.has(key)) {
@@ -512,7 +512,7 @@ function parseCaller(value) {
512
512
  const adapterId = optionalId("adapterId");
513
513
  const launchId = optionalId("launchId");
514
514
  const nativeSessionId = optionalId("nativeSessionId");
515
- const runId = optionalId("runId");
515
+ const turnId = optionalId("turnId");
516
516
  const callerKey = record.callerKey === undefined
517
517
  ? undefined
518
518
  : requiredId(record.callerKey, "job caller callerKey");
@@ -524,7 +524,7 @@ function parseCaller(value) {
524
524
  ...(adapterId === undefined ? {} : { adapterId }),
525
525
  ...(launchId === undefined ? {} : { launchId }),
526
526
  ...(nativeSessionId === undefined ? {} : { nativeSessionId }),
527
- ...(runId === undefined ? {} : { runId }),
527
+ ...(turnId === undefined ? {} : { turnId }),
528
528
  ...(callerKey === undefined ? {} : { callerKey })
529
529
  };
530
530
  }
@@ -32,7 +32,7 @@ export function createRuntimeResourceActivityTracker() {
32
32
  || roleKey === undefined)
33
33
  return reject();
34
34
  const identityKey = JSON.stringify([
35
- identity.runId,
35
+ identity.turnId,
36
36
  identity.agentId,
37
37
  identity.adapterId,
38
38
  identity.nativeSessionId ?? null,
@@ -262,7 +262,7 @@ function roleOwner(role) {
262
262
  ...(role.adapterId === undefined ? {} : { adapterId: role.adapterId }),
263
263
  ...(role.nativeSessionId === undefined ? {} : { nativeSessionId: role.nativeSessionId }),
264
264
  ...(role.launchId === undefined ? {} : { launchId: role.launchId }),
265
- ...(role.runId === undefined ? {} : { runId: role.runId })
265
+ ...(role.turnId === undefined ? {} : { turnId: role.turnId })
266
266
  };
267
267
  }
268
268
  return {
@@ -275,7 +275,7 @@ function roleOwner(role) {
275
275
  ...(role.adapterId === undefined ? {} : { adapterId: role.adapterId }),
276
276
  ...(role.nativeSessionId === undefined ? {} : { nativeSessionId: role.nativeSessionId }),
277
277
  ...(role.launchId === undefined ? {} : { launchId: role.launchId }),
278
- ...(role.runId === undefined ? {} : { runId: role.runId })
278
+ ...(role.turnId === undefined ? {} : { turnId: role.turnId })
279
279
  };
280
280
  }
281
281
  function processTree(processes, rootPid) {
@@ -437,8 +437,8 @@ function matchesResourceIdentity(identity, owner) {
437
437
  || identity.taskId.length === 0
438
438
  || typeof identity.roleName !== "string"
439
439
  || identity.roleName.length === 0
440
- || typeof identity.runId !== "string"
441
- || identity.runId.length === 0
440
+ || typeof identity.turnId !== "string"
441
+ || identity.turnId.length === 0
442
442
  || typeof identity.agentId !== "string"
443
443
  || identity.agentId.length === 0
444
444
  || typeof identity.adapterId !== "string"
@@ -449,7 +449,7 @@ function matchesResourceIdentity(identity, owner) {
449
449
  if (owner.kind !== "task-role"
450
450
  || owner.taskId !== identity.taskId
451
451
  || owner.roleName !== identity.roleName
452
- || owner.runId !== identity.runId
452
+ || owner.turnId !== identity.turnId
453
453
  || owner.agentId !== identity.agentId
454
454
  || owner.adapterId !== identity.adapterId)
455
455
  return false;
@@ -3,7 +3,7 @@ import { existsSync, lstatSync, readFileSync, readdirSync } from "node:fs";
3
3
  import { basename, join, resolve } from "node:path";
4
4
  import { activeLiveRoleAgentSession } from "../executor/agentExecutor.js";
5
5
  import { inspectStorageSchema } from "../storage/storageSchema.js";
6
- import { openCompatibleFileTaskStore } from "../storage/compatibleTaskStore.js";
6
+ import { openCurrentTaskStore } from "../storage/currentTaskStore.js";
7
7
  import { NodeCommandExecutor } from "../tmux/commandExecutor.js";
8
8
  import { TmuxManager, yuiTmuxServerName } from "../tmux/tmuxManager.js";
9
9
  import { tmuxSocketDirectory, tmuxSocketEnvironment } from "../tmux/tmuxSocketEndpoint.js";
@@ -450,8 +450,7 @@ function inspectRuntimeDomain(home, processes, roles, storageStatus, now) {
450
450
  // A current, ordinary YUI_HOME is a real control domain, not a disposable
451
451
  // test domain. Keep it visible even when it is currently idle so a stale
452
452
  // artifact cannot acquire ephemeral cleanup authority by omission. An
453
- // uninitialized temporary directory with no runtime facts remains absent
454
- // to preserve the legacy empty-home inventory behavior.
453
+ // uninitialized temporary directory with no runtime facts remains absent.
455
454
  if (storageStatus !== "current"
456
455
  && processes.length === 0
457
456
  && roles.length === 0)
@@ -614,19 +613,14 @@ function inspectRuntimeDomain(home, processes, roles, storageStatus, now) {
614
613
  }
615
614
  function loadHomeState(home, warnings, options) {
616
615
  const schema = (options.inspectStorage ?? inspectStorageSchema)(home);
617
- const recordOnlyOlder = schema.status === "unsupported"
618
- && schema.incompatibleComponent === "record"
619
- && schema.direction === "older"
620
- && schema.currentLayoutVersion === schema.latestLayoutVersion
621
- && schema.currentAggregateSchemaVersion === schema.latestAggregateSchemaVersion;
622
- if (schema.status !== "current" && !recordOnlyOlder) {
616
+ if (schema.status !== "current") {
623
617
  return {
624
618
  storageStatus: schema.status,
625
619
  roles: []
626
620
  };
627
621
  }
628
622
  try {
629
- const store = (options.openCompatibleStore ?? openCompatibleFileTaskStore)(home);
623
+ const store = (options.openCurrentStore ?? openCurrentTaskStore)(home);
630
624
  const roles = [...store.listGlobalRoles()]
631
625
  .sort((left, right) => numericCompare(left.name, right.name))
632
626
  .map((role) => {
@@ -646,7 +640,7 @@ function loadHomeState(home, warnings, options) {
646
640
  const appendTaskRole = (task, role) => {
647
641
  const session = activeLiveRoleAgentSession(store.getRoleSessionSet(task.id, role.name));
648
642
  const binding = role.agentBindings[role.activeAgentId];
649
- const run = store.getActiveAgentRun(task.id, role.name);
643
+ const run = store.getActiveTurn(task.id, role.name);
650
644
  const agentId = session?.effective.agentId ?? role.activeAgentId;
651
645
  const adapterId = session?.effective.adapterId ?? binding?.adapterId;
652
646
  roles.push({
@@ -659,57 +653,42 @@ function loadHomeState(home, warnings, options) {
659
653
  ...(adapterId === undefined ? {} : { adapterId }),
660
654
  ...(session === null ? {} : { nativeSessionId: session.nativeSessionId }),
661
655
  ...(session?.launchId === undefined ? {} : { launchId: session.launchId }),
662
- ...(run === null ? {} : { runId: run.id })
656
+ ...(run === null ? {} : { turnId: run.id })
663
657
  });
664
658
  };
665
- // Layout-7 SQLite owns bounded active-Task and current-Session indexes.
666
- // Use those indexes only as selectors, then point-read the authoritative
667
- // Task/Role/Session/Run records so an index row cannot bypass ownership
668
- // fences. The legacy File store intentionally retains its complete
669
- // listTasks fallback because it has no equivalent active selector.
670
- const hotStore = store;
671
- const indexedTaskIds = hotStore.listActiveTaskIds === undefined
672
- ? undefined
673
- : [...new Set(hotStore.listActiveTaskIds())].sort(numericCompare);
674
- if (indexedTaskIds === undefined) {
675
- for (const task of store.listTasks()) {
676
- for (const role of [...store.listRoles(task.id)].sort((left, right) => (numericCompare(left.name, right.name)))) {
677
- appendTaskRole(task, role);
678
- }
679
- }
659
+ // The current SQLite store owns bounded active-Task and current-Session
660
+ // indexes. Use them only as selectors, then point-read the authoritative
661
+ // Task/Role/Session/Turn records so an index row cannot bypass ownership
662
+ // fences.
663
+ const indexedTaskIds = [...new Set(store.listActiveTaskIds())].sort(numericCompare);
664
+ const sessionCandidates = store.listRuntimeSessionCandidates({ scope: "task" });
665
+ const candidateRoles = new Map();
666
+ for (const candidate of sessionCandidates) {
667
+ if (candidate.owner.scope !== "task")
668
+ continue;
669
+ const roleNames = candidateRoles.get(candidate.owner.taskId) ?? new Set();
670
+ roleNames.add(candidate.owner.roleName);
671
+ candidateRoles.set(candidate.owner.taskId, roleNames);
680
672
  }
681
- else {
682
- const sessionCandidates = typeof store.listRuntimeSessionCandidates === "function"
683
- ? store.listRuntimeSessionCandidates({ scope: "task" })
684
- : [];
685
- const candidateRoles = new Map();
686
- for (const candidate of sessionCandidates) {
687
- if (candidate.owner.scope !== "task")
688
- continue;
689
- const roleNames = candidateRoles.get(candidate.owner.taskId) ?? new Set();
690
- roleNames.add(candidate.owner.roleName);
691
- candidateRoles.set(candidate.owner.taskId, roleNames);
692
- }
693
- const activeTaskSet = new Set(indexedTaskIds);
694
- const taskIds = [...new Set([
695
- ...indexedTaskIds,
696
- ...candidateRoles.keys()
697
- ])].sort(numericCompare);
698
- for (const taskId of taskIds) {
699
- const task = store.getTask(taskId);
700
- if (task === null)
701
- continue;
702
- const rolesForTask = activeTaskSet.has(taskId) && task.status === "active"
703
- ? store.listRoles(taskId)
704
- : [...(candidateRoles.get(taskId) ?? [])]
705
- .sort(numericCompare)
706
- .flatMap((roleName) => {
707
- const role = store.getRole(taskId, roleName);
708
- return role === null ? [] : [role];
709
- });
710
- for (const role of [...rolesForTask].sort((left, right) => (numericCompare(left.name, right.name)))) {
711
- appendTaskRole(task, role);
712
- }
673
+ const activeTaskSet = new Set(indexedTaskIds);
674
+ const taskIds = [...new Set([
675
+ ...indexedTaskIds,
676
+ ...candidateRoles.keys()
677
+ ])].sort(numericCompare);
678
+ for (const taskId of taskIds) {
679
+ const task = store.getTask(taskId);
680
+ if (task === null)
681
+ continue;
682
+ const rolesForTask = activeTaskSet.has(taskId) && task.status === "active"
683
+ ? store.listRoles(taskId)
684
+ : [...(candidateRoles.get(taskId) ?? [])]
685
+ .sort(numericCompare)
686
+ .flatMap((roleName) => {
687
+ const role = store.getRole(taskId, roleName);
688
+ return role === null ? [] : [role];
689
+ });
690
+ for (const role of [...rolesForTask].sort((left, right) => (numericCompare(left.name, right.name)))) {
691
+ appendTaskRole(task, role);
713
692
  }
714
693
  }
715
694
  return {
@@ -4,7 +4,7 @@
4
4
  *
5
5
  * The `/proc` scanning in `resourceInventoryLinux` is blocking IO (hundreds of
6
6
  * `readFileSync` calls per pass, `spawnSync`, tmux inspection). When the worker
7
- * backend is active (`YUI_STORE_BACKEND=sqlite` + `YUI_STORE_WORKER=1`, the same
7
+ * persistence worker is active (`YUI_STORE_WORKER=1`, the same
8
8
  * flag as the persistence worker, §6), the Controller runtime and the ephemeral
9
9
  * reaper scan through this client instead: the scan runs in the inventory
10
10
  * worker (its own thread), the main event loop stays free, and the result is
@@ -17,8 +17,8 @@
17
17
  * worker -> main: ready | result | error
18
18
  *
19
19
  * Only structured-cloneable scan options cross the port (the file-backed
20
- * `inspectStorage` / `openCompatibleStore` / `now` seams stay on the direct
21
- * path, which the file backend still uses). The inventory worker never touches
20
+ * `inspectStorage` / `openCurrentStore` / `now` seams stay on the direct
21
+ * path used without the worker). The inventory worker never touches
22
22
  * the persistence worker's database connection (§3.3): it is a separate worker
23
23
  * with a separate concern.
24
24
  */
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Runs the blocking `/proc` scanning of `resourceInventoryLinux` off the main
5
5
  * thread. The main thread asks for a scan over a `MessageChannel` port; the
6
- * worker runs the exact same `scanControllerResourceInventory` the file backend
6
+ * worker runs the exact same `scanControllerResourceInventory` as the main thread
7
7
  * calls directly and posts the inventory back. Because worker threads share the
8
8
  * process, the scanner's self-exclusion (`process.pid`, its start identity)
9
9
  * keeps excluding the Controller process exactly as on the main thread.
@@ -11,7 +11,7 @@ import { effectiveLaunchSnapshotsCompatible, effectiveLaunchSnapshotsCompatibleF
11
11
  import { AgentConfigurationCatalogService, validateAgentLaunchConfiguration } from "../executor/agentConfigurationCatalog.js";
12
12
  import { isTaskOwnedWorkspace, managedWorkspaceIdentity, sameManagedWorkspaceIdentity } from "../worktree/managedWorkspace.js";
13
13
  import { FileRoleLaunchPlanner } from "../executor/fileRoleLaunchPlanner.js";
14
- import { openCompatibleFileTaskStore } from "../storage/compatibleTaskStore.js";
14
+ import { openCurrentTaskStore } from "../storage/currentTaskStore.js";
15
15
  import { SqliteTaskStore } from "../storage/sqliteStore.js";
16
16
  import { AsyncTaskStoreClient, resolveStoreWorkerEnabledForHome } from "../storage/storeRpc.js";
17
17
  import { FileTaskWorkspacePreparer } from "../repository/taskWorkspacePreparer.js";
@@ -45,13 +45,13 @@ import { createTaskEvent } from "../event/taskEvent.js";
45
45
  export function refreshAppliedTaskRuntimeDescriptor(store, planner, input) {
46
46
  if (input.launchId === undefined)
47
47
  return;
48
- const run = input.runId === undefined
48
+ const run = input.turnId === undefined
49
49
  ? null
50
- : store.getAgentRun(input.taskId, input.runId);
51
- if (input.runId !== undefined && run === null) {
50
+ : store.getTurn(input.taskId, input.turnId);
51
+ if (input.turnId !== undefined && run === null) {
52
52
  throw new Error("Prepared Task runtime generation is not current.");
53
53
  }
54
- // A terminal completion has already settled this exact Run and no later
54
+ // A terminal completion has already settled this exact Turn and no later
55
55
  // prompt can use its descriptor. Acknowledge the applied provider fact
56
56
  // without republishing a dead generation.
57
57
  if (run !== null && run.status !== "active")
@@ -76,22 +76,18 @@ export function refreshAppliedTaskRuntimeDescriptor(store, planner, input) {
76
76
  workspace: effective.workspace.root
77
77
  });
78
78
  }
79
- /** Production composition root for the lean FileTaskStore + tmux Controller. */
79
+ /** Production composition root for the current SQLite TaskStore + tmux Controller. */
80
80
  export async function startFileTaskControllerRuntime(home, options = {}) {
81
- // The Home decides the backend (Issue 01): a layout-7 Home runs SQLite with
82
- // the persistence worker on by default; YUI_STORE_WORKER=0/false forces the
83
- // in-process SQLite connection. The non-worker path opens the Home-decided
84
- // backend through the compatibility opener (SQLite for layout 7, file store
85
- // with normalization for older layouts).
81
+ // The current Home always uses SQLite. The persistence worker is enabled by
82
+ // default; YUI_STORE_WORKER=0/false keeps the same database in-process.
86
83
  const useWorker = resolveStoreWorkerEnabledForHome(home, options.environment ?? process.env);
87
84
  const store = options.store
88
85
  ?? (useWorker
89
- // Transitional: the scheduler/planner still use a sync store. The worker
90
- // owns the event-processing hot path; the scheduler migration is the next
91
- // step (see work-item-5 remaining call sites). Both connections point at
92
- // the same WAL db and serialize via BEGIN IMMEDIATE + busy_timeout.
86
+ // The worker owns the event-processing hot path while the scheduler uses
87
+ // the synchronous connection. Both point at the same WAL database and
88
+ // serialize via BEGIN IMMEDIATE + busy_timeout.
93
89
  ? new SqliteTaskStore(home)
94
- : openCompatibleFileTaskStore(home));
90
+ : openCurrentTaskStore(home));
95
91
  const homeId = store.getHomeIdentity().homeId;
96
92
  const durableConfig = store.getConfig();
97
93
  // When the worker backend is active, the db-touching observer folds run in
@@ -259,9 +255,8 @@ export async function startFileTaskControllerRuntime(home, options = {}) {
259
255
  onCleanupRequired: signalRuntimeCleanup,
260
256
  runtimeIsolation
261
257
  });
262
- // One inventory scan per scheduler pass. When the worker backend is active
263
- // the blocking /proc scan runs in the inventory worker; otherwise it runs on
264
- // the main thread (file backend, unchanged).
258
+ // One inventory scan per scheduler pass. When the inventory worker is active
259
+ // the blocking /proc scan runs there; otherwise it runs on the main thread.
265
260
  const scanInventory = (panes) => inventoryClient !== undefined
266
261
  ? inventoryClient.scan({
267
262
  currentHome: home,
@@ -297,7 +292,7 @@ export async function startFileTaskControllerRuntime(home, options = {}) {
297
292
  && candidate.roleName === owner.roleName));
298
293
  if (input === undefined)
299
294
  return [];
300
- const identity = owner.runId === undefined
295
+ const identity = owner.turnId === undefined
301
296
  || owner.adapterId === undefined
302
297
  || (owner.nativeSessionId === undefined && owner.launchId === undefined)
303
298
  || (owner.nativeSessionId !== undefined && owner.nativeSessionId.trim().length === 0)
@@ -306,7 +301,7 @@ export async function startFileTaskControllerRuntime(home, options = {}) {
306
301
  : {
307
302
  taskId: owner.taskId,
308
303
  roleName: owner.roleName,
309
- runId: owner.runId,
304
+ turnId: owner.turnId,
310
305
  agentId: owner.agentId,
311
306
  adapterId: owner.adapterId,
312
307
  ...(owner.nativeSessionId === undefined
@@ -314,12 +309,12 @@ export async function startFileTaskControllerRuntime(home, options = {}) {
314
309
  : { nativeSessionId: owner.nativeSessionId }),
315
310
  ...(owner.launchId === undefined ? {} : { launchId: owner.launchId })
316
311
  };
317
- const changed = !active || input.runId === undefined
312
+ const changed = !active || input.turnId === undefined
318
313
  ? false
319
314
  : resourceActivity({
320
315
  taskId: input.taskId,
321
316
  roleName: input.roleName,
322
- runId: input.runId,
317
+ turnId: input.turnId,
323
318
  agentId: input.agentId,
324
319
  adapterId: input.adapterId,
325
320
  ...(input.nativeSessionId === undefined
@@ -570,7 +565,7 @@ export function createRuntimeLifecycleDispatcher(store, schedulerStore, sessionH
570
565
  schedulerStore.beginAgentHostProviderTurn({
571
566
  taskId: value.taskId,
572
567
  roleName: value.roleName,
573
- runId: value.runId,
568
+ ...(value.turnId === undefined ? {} : { turnId: value.turnId }),
574
569
  agentId: value.agentId,
575
570
  launchId: value.launchId,
576
571
  nativeSessionId: value.nativeSessionId,
@@ -602,7 +597,7 @@ export function createRuntimeLifecycleDispatcher(store, schedulerStore, sessionH
602
597
  schedulerStore.resolveAgentHostProviderTurnSubmission({
603
598
  taskId: value.taskId,
604
599
  roleName: value.roleName,
605
- runId: value.runId,
600
+ ...(value.turnId === undefined ? {} : { turnId: value.turnId }),
606
601
  attemptId: value.attemptId,
607
602
  status,
608
603
  reason,
@@ -613,9 +608,9 @@ export function createRuntimeLifecycleDispatcher(store, schedulerStore, sessionH
613
608
  }
614
609
  if (method === "runtime.process-exit-observe") {
615
610
  const observation = validateRuntimeProcessExitObservation(params);
616
- const run = observation.taskId === undefined || observation.runId === undefined
611
+ const run = observation.taskId === undefined || observation.turnId === undefined
617
612
  ? null
618
- : store.getAgentRun(observation.taskId, observation.runId);
613
+ : store.getTurn(observation.taskId, observation.turnId);
619
614
  const globalRole = observation.taskId === undefined
620
615
  ? store.getGlobalRole(observation.roleName)
621
616
  : null;
@@ -625,20 +620,20 @@ export function createRuntimeLifecycleDispatcher(store, schedulerStore, sessionH
625
620
  ? null
626
621
  : builtinAgentDriverRegistry().findByAdapterId(adapterId);
627
622
  const turnTerminalObserved = observation.taskId !== undefined
628
- && observation.runId !== undefined
623
+ && observation.turnId !== undefined
629
624
  && store.listEvents(observation.taskId).some((event) => {
630
625
  const runtime = runtimeObservationFromTaskEvent(event);
631
626
  return runtime !== null
632
- && runtime.fence.runId === observation.runId
627
+ && runtime.fence.turnId === observation.turnId
633
628
  && ["turn.completed", "turn.failed", "turn.cancelled"].includes(runtime.kind)
634
629
  && Date.parse(runtime.receivedAt) <= Date.parse(observation.observedAt);
635
630
  });
636
631
  const turnFailureObserved = observation.taskId !== undefined
637
- && observation.runId !== undefined
632
+ && observation.turnId !== undefined
638
633
  && store.listEvents(observation.taskId).some((event) => {
639
634
  const runtime = runtimeObservationFromTaskEvent(event);
640
635
  return runtime !== null
641
- && runtime.fence.runId === observation.runId
636
+ && runtime.fence.turnId === observation.turnId
642
637
  && runtime.fence.launchId === observation.launchId
643
638
  && runtime.kind === "turn.failed"
644
639
  && Date.parse(runtime.receivedAt) <= Date.parse(observation.observedAt);
@@ -750,20 +745,20 @@ export function createRuntimeLifecycleDispatcher(store, schedulerStore, sessionH
750
745
  ? `Role not found: ${request.taskId}/${request.roleName}.`
751
746
  : `Global Role not found: ${request.roleName}.`);
752
747
  }
753
- const activeRun = request.scope === "task"
754
- ? store.getActiveAgentRun(request.taskId, request.roleName)
748
+ const activeTurn = request.scope === "task"
749
+ ? store.getActiveTurn(request.taskId, request.roleName)
755
750
  : null;
756
- if (request.scope === "task" && activeRun === null) {
757
- throw applicationError("INVALID_PARAMS", "Task Role runtime attachment requires an admitted active Run; it cannot create an empty Provider Conversation.");
751
+ if (request.scope === "task" && activeTurn === null) {
752
+ throw applicationError("INVALID_PARAMS", "Task Role runtime attachment requires an admitted active Turn; it cannot create an empty Provider Conversation.");
758
753
  }
759
754
  const managedWorkspace = request.scope === "task"
760
- ? activeRun?.workspace
755
+ ? activeTurn?.workspace
761
756
  ?? currentDesiredManagedWorkspace(store, request.taskId, request.roleName)
762
757
  : undefined;
763
758
  const sessions = request.scope === "task"
764
759
  ? store.getTaskRoleSessionSet(request.taskId, request.roleName)
765
760
  : store.getGlobalRoleSessionSet(request.roleName);
766
- const effective = activeRun?.effective
761
+ const effective = activeTurn?.effective
767
762
  ?? activeLiveRoleAgentSession(sessions)?.effective
768
763
  ?? resolveRuntimeDesiredEffective(store, request, role);
769
764
  const binding = role.agentBindings[effective.agentId];
@@ -776,14 +771,12 @@ export function createRuntimeLifecycleDispatcher(store, schedulerStore, sessionH
776
771
  }
777
772
  validateLifecycleEnvironment(request.environment, agent);
778
773
  const session = sessions?.sessions[effective.agentId];
779
- const managedTurnDispatch = activeRun !== null && (activeRun.pushedAt === undefined
780
- || activeRun.controlRequest?.state === "dispatching");
781
- // An ensure call may reattach the already-admitted Run to its existing
774
+ // An ensure call may reattach the already-admitted Turn to its existing
782
775
  // Conversation, but it may not manufacture a fresh Conversation without a
783
- // pending managed Turn. Fresh replacement remains owned by Run dispatch.
784
- const mode = activeRun === null
776
+ // pending managed Turn. Fresh replacement remains owned by Turn dispatch.
777
+ const mode = activeTurn === null
785
778
  ? roleAgentSessionResumeMode(sessions, effective.agentId, effective)
786
- : managedTurnDispatch ? activeRun.mode : "resume";
779
+ : session?.nativeSessionId === undefined ? activeTurn.mode : "resume";
787
780
  if (request.scope === "task" && mode === "resume"
788
781
  && (session?.nativeSessionId === undefined
789
782
  || session.nativeSessionId.trim().length === 0)) {
@@ -799,7 +792,7 @@ export function createRuntimeLifecycleDispatcher(store, schedulerStore, sessionH
799
792
  effective,
800
793
  workspace: effective.workspace.root,
801
794
  ...(managedWorkspace === undefined ? {} : { managedWorkspace }),
802
- ...(activeRun === null ? {} : { runId: activeRun.id }),
795
+ ...(activeTurn === null ? {} : { turnId: activeTurn.id }),
803
796
  ...(request.environment === undefined
804
797
  ? {}
805
798
  : { environment: request.environment })
@@ -852,7 +845,7 @@ function resolveRuntimeDesiredEffective(store, request, role) {
852
845
  });
853
846
  }
854
847
  function assertRuntimeLaunchRequestCurrent(store, request) {
855
- let activeRun = null;
848
+ let activeTurn = null;
856
849
  if (request.owner.scope === "task") {
857
850
  const task = store.getTask(request.owner.taskId);
858
851
  if (task === null
@@ -860,10 +853,10 @@ function assertRuntimeLaunchRequestCurrent(store, request) {
860
853
  || task.executionGate.state !== "enabled") {
861
854
  throw new Error(`Task is no longer active: ${request.owner.taskId}.`);
862
855
  }
863
- activeRun = store.getActiveAgentRun(request.owner.taskId, request.owner.roleName);
864
- if (request.runId !== undefined
865
- && activeRun?.id !== request.runId) {
866
- throw new Error(`Role Run is no longer current: ${request.runId}.`);
856
+ activeTurn = store.getActiveTurn(request.owner.taskId, request.owner.roleName);
857
+ if (request.turnId !== undefined
858
+ && activeTurn?.id !== request.turnId) {
859
+ throw new Error(`Role Turn is no longer current: ${request.turnId}.`);
867
860
  }
868
861
  }
869
862
  const role = request.owner.scope === "task"
@@ -875,8 +868,8 @@ function assertRuntimeLaunchRequestCurrent(store, request) {
875
868
  const sessions = request.owner.scope === "task"
876
869
  ? store.getTaskRoleSessionSet(request.owner.taskId, request.owner.roleName)
877
870
  : store.getGlobalRoleSessionSet(request.owner.roleName);
878
- const expectedEffective = request.owner.scope === "task" && request.runId !== undefined
879
- ? activeRun?.effective
871
+ const expectedEffective = request.owner.scope === "task" && request.turnId !== undefined
872
+ ? activeTurn?.effective
880
873
  : activeLiveRoleAgentSession(sessions)?.effective
881
874
  ?? currentDesiredEffective(store, request, role);
882
875
  if (expectedEffective === undefined
@@ -887,7 +880,7 @@ function assertRuntimeLaunchRequestCurrent(store, request) {
887
880
  throw new Error(`Role launch state changed: ${request.owner.roleName}.`);
888
881
  }
889
882
  if (request.owner.scope === "task" && request.managedWorkspace !== undefined) {
890
- const expectedWorkspace = activeRun?.workspace
883
+ const expectedWorkspace = activeTurn?.workspace
891
884
  ?? currentDesiredManagedWorkspace(store, request.owner.taskId, request.owner.roleName);
892
885
  if (expectedWorkspace === undefined
893
886
  || !sameManagedWorkspaceIdentity(expectedWorkspace, request.managedWorkspace)) {
@@ -1129,7 +1122,7 @@ function providerTurnControlParams(params) {
1129
1122
  return {
1130
1123
  taskId: requiredParam(value.taskId),
1131
1124
  roleName: requiredParam(value.roleName),
1132
- runId: requiredParam(value.runId),
1125
+ ...(value.turnId === undefined ? {} : { turnId: requiredParam(value.turnId) }),
1133
1126
  agentId: requiredParam(value.agentId),
1134
1127
  launchId: requiredParam(value.launchId),
1135
1128
  nativeSessionId: requiredParam(value.nativeSessionId),