@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
@@ -130,11 +130,14 @@ export function materializeSessionBootstrap(input) {
130
130
  roleProfileRef: { digest: profileDigest, path: roleProfilePath },
131
131
  contextProtocol: input.owner.scope === "global"
132
132
  ? {
133
- loadCommand: "\"$YUI_SESSION_CLI\" session context \"$YUI_ROLE\" --json"
133
+ // A Global Session may move between Yui's remote TUI and Desktop.
134
+ // Carry its read entry in the Thread-visible Manifest instead of
135
+ // depending on the client process that happened to create it.
136
+ loadCommand: renderGlobalContextCommand(input.controlPlane, home, input.role.name)
134
137
  }
135
138
  : {
136
- loadCommand: "\"$YUI_SESSION_CLI\" task run context \"$YUI_TASK_ID/<run-id>\" --json",
137
- expandCommand: "\"$YUI_SESSION_CLI\" task run context expand \"$YUI_TASK_ID/<run-id>\" <ref-id> --store <store> --mode full --json"
139
+ loadCommand: "\"$YUI_SESSION_CLI\" task turn context \"$YUI_TASK_ID/<turn-id>\" --json",
140
+ expandCommand: "\"$YUI_SESSION_CLI\" task turn context expand \"$YUI_TASK_ID/<turn-id>\" <ref-id> --store <store> --mode full --json"
138
141
  }
139
142
  };
140
143
  const manifest = Object.freeze({ ...body, digest: digest(body) });
@@ -148,6 +151,20 @@ export function materializeSessionBootstrap(input) {
148
151
  descriptorPath
149
152
  });
150
153
  }
154
+ function renderGlobalContextCommand(controlPlane, home, roleName) {
155
+ return [
156
+ `YUI_HOME=${quoteShellWord(home)}`,
157
+ quoteShellWord(controlPlane.executable),
158
+ quoteShellWord(controlPlane.cliEntry),
159
+ "session",
160
+ "context",
161
+ quoteShellWord(roleName),
162
+ "--json"
163
+ ].join(" ");
164
+ }
165
+ function quoteShellWord(value) {
166
+ return `'${value.replaceAll("'", "'\"'\"'")}'`;
167
+ }
151
168
  /**
152
169
  * Retargets known managed wrappers to the current resolved control plane after
153
170
  * a compatible update. Only a valid Session Manifest may nominate a wrapper,
@@ -1,13 +1,12 @@
1
- import { rejectedYieldAttemptFromTaskEvent, RUN_YIELD_REJECTED_EVENT } from "../run/rejectedYieldAttempt.js";
2
1
  import { operationalTaskRecords } from "../task/taskRecordRetirement.js";
3
2
  import { TASK_COMPLETION_PUBLISHED_TREE_AUTHORIZED_EVENT } from "../task/publicationReference.js";
4
- import { RUN_BOOTSTRAP_MAX_DELTAS } from "./runContextContract.js";
3
+ import { TURN_INPUT_MAX_DELTAS } from "./turnInputContract.js";
5
4
  import { contextContentDigest, contextSnapshotRef, createContextSnapshot, validateContextSnapshot } from "./contextSnapshot.js";
6
- export const RUN_CONTEXT_PACK_SCHEMA_VERSION = 1;
7
- export const RUN_CONTEXT_PACK_MAX_REFS = 256;
8
- export const RUN_CONTEXT_PACK_MAX_BYTES = 8 * 1024 * 1024;
9
- export const RUN_CONTEXT_EXPAND_MAX_BYTES = 4 * 1024 * 1024;
10
- export function freezeRunContextSnapshot(store, run, now, frozenBy = "controller", baselineRef) {
5
+ export const TURN_CONTEXT_PACK_SCHEMA_VERSION = 1;
6
+ export const TURN_CONTEXT_PACK_MAX_REFS = 256;
7
+ export const TURN_CONTEXT_PACK_MAX_BYTES = 8 * 1024 * 1024;
8
+ export const TURN_CONTEXT_EXPAND_MAX_BYTES = 4 * 1024 * 1024;
9
+ export function freezeTurnContextSnapshot(store, run, now, frozenBy = "controller", baselineRef) {
11
10
  if (baselineRef !== undefined) {
12
11
  const baseline = store.getContextSnapshot(run.taskId, baselineRef.id);
13
12
  if (baseline === null
@@ -18,10 +17,10 @@ export function freezeRunContextSnapshot(store, run, now, frozenBy = "controller
18
17
  || baseline.scope !== "stage"
19
18
  || baselineRef.scope !== baseline.scope
20
19
  || baseline.scopeRef !== baselineRef.scopeRef) {
21
- throw new Error(`Run Context baseline is missing or drifted: ${baselineRef.id}.`);
20
+ throw new Error(`Turn Context baseline is missing or drifted: ${baselineRef.id}.`);
22
21
  }
23
22
  validateContextSnapshot(baseline);
24
- const overlays = collectRunContextOverlays(store, run);
23
+ const overlays = collectTurnContextOverlays(store, run);
25
24
  const resources = [...new Map([...baseline.resources, ...overlays].map((entry) => [
26
25
  contextRefIdentity(entry.ref),
27
26
  entry
@@ -77,7 +76,7 @@ export function freezeRunContextSnapshot(store, run, now, frozenBy = "controller
77
76
  }
78
77
  /**
79
78
  * Freeze the shared, role-neutral ContextSnapshot anchored by one WorkItem
80
- * exploration stage Group. AgentRun snapshots remain role-specific; this
79
+ * exploration stage Group. Turn snapshots remain role-specific; this
81
80
  * record is the durable stage baseline and derives from a fresh WorkItem
82
81
  * snapshot so the Group never depends on ambient latest state.
83
82
  */
@@ -102,7 +101,7 @@ export function freezeExecutionStageContextSnapshot(store, input, now) {
102
101
  for (const binding of task.projectBindings) {
103
102
  const project = store.getProject(binding.projectId);
104
103
  if (project === null)
105
- throw new Error(`Run Project not found: ${binding.projectId}.`);
104
+ throw new Error(`Turn Project not found: ${binding.projectId}.`);
106
105
  const { knowledge, ...projectPolicy } = project;
107
106
  materialized.push(materialize("L1", "project-policy", project.id, projectPolicy));
108
107
  for (const entry of knowledge.filter(({ status }) => status === "active")) {
@@ -217,27 +216,27 @@ export function contextSnapshotDeltaRefIds(store, snapshot) {
217
216
  || before.store !== ref.store
218
217
  || before.layer !== ref.layer;
219
218
  }).map(({ refId }) => refId);
220
- return Object.freeze([...new Set(changed)].sort().slice(0, RUN_BOOTSTRAP_MAX_DELTAS));
219
+ return Object.freeze([...new Set(changed)].sort().slice(0, TURN_INPUT_MAX_DELTAS));
221
220
  }
222
- export function buildRunContextPack(store, taskId, runId) {
223
- const run = requireExactRun(store, taskId, runId);
221
+ export function buildTurnContextPack(store, taskId, turnId) {
222
+ const run = requireExactTurn(store, taskId, turnId);
224
223
  const current = collectAuthorizedContext(store, run);
225
224
  let pointers = current.map(({ ref }) => ref);
226
225
  let snapshotRef;
227
- if (run.assignment.contextSnapshotRef !== undefined) {
228
- const expected = run.assignment.contextSnapshotRef;
226
+ if (run.inputs[0].input.contextSnapshotRef !== undefined) {
227
+ const expected = run.inputs[0].input.contextSnapshotRef;
229
228
  const snapshot = store.getContextSnapshot(taskId, expected.id);
230
229
  if (snapshot === null)
231
- throw new Error(`Run Context Snapshot is missing: ${expected.id}.`);
230
+ throw new Error(`Turn Context Snapshot is missing: ${expected.id}.`);
232
231
  validateContextSnapshot(snapshot);
233
232
  if (snapshot.digest !== expected.digest || snapshot.taskId !== taskId) {
234
- throw new Error(`Run Context Snapshot identity drifted: ${expected.id}.`);
233
+ throw new Error(`Turn Context Snapshot identity drifted: ${expected.id}.`);
235
234
  }
236
235
  pointers = snapshot.refs;
237
236
  snapshotRef = contextSnapshotRef(snapshot);
238
237
  }
239
- if (pointers.length > RUN_CONTEXT_PACK_MAX_REFS) {
240
- throw new Error(`Run Context exceeds ${RUN_CONTEXT_PACK_MAX_REFS} authorized refs.`);
238
+ if (pointers.length > TURN_CONTEXT_PACK_MAX_REFS) {
239
+ throw new Error(`Turn Context exceeds ${TURN_CONTEXT_PACK_MAX_REFS} authorized refs.`);
241
240
  }
242
241
  const view = contextView(run);
243
242
  const writableProjectIds = writableProjects(store, run, view);
@@ -248,10 +247,10 @@ export function buildRunContextPack(store, taskId, runId) {
248
247
  digest: ref.digest
249
248
  }));
250
249
  const body = {
251
- schemaVersion: RUN_CONTEXT_PACK_SCHEMA_VERSION,
250
+ schemaVersion: TURN_CONTEXT_PACK_SCHEMA_VERSION,
252
251
  identity: Object.freeze({
253
252
  taskId,
254
- runId,
253
+ turnId: turnId,
255
254
  roleName: run.roleName,
256
255
  purpose: run.purpose,
257
256
  agentId: run.effective.agentId,
@@ -259,27 +258,27 @@ export function buildRunContextPack(store, taskId, runId) {
259
258
  workspace: run.effective.workspace.root
260
259
  }),
261
260
  ...(snapshotRef === undefined ? {} : { snapshot: snapshotRef }),
262
- assignment: run.assignment,
261
+ input: run.inputs[0].input,
263
262
  authority: Object.freeze({ view, readableRefs: pointers, writableProjectIds }),
264
263
  pointers,
265
264
  summaries,
266
- deltas: pointers.filter((ref) => run.assignment.deltaRefIds.includes(ref.refId)),
265
+ deltas: pointers.filter((ref) => run.inputs[0].input.deltaRefIds.includes(ref.refId)),
267
266
  completion: Object.freeze({
268
267
  allowedActions: completionActions(view),
269
- exactRunRef: `${taskId}/${runId}`
268
+ exactTurnRef: `${taskId}/${turnId}`
270
269
  })
271
270
  };
272
271
  const digest = contextContentDigest(body);
273
272
  const preliminaryBytes = Buffer.byteLength(JSON.stringify({ ...body, digest }), "utf8");
274
- if (preliminaryBytes > RUN_CONTEXT_PACK_MAX_BYTES) {
275
- throw new Error(`Run Context Pack exceeds ${RUN_CONTEXT_PACK_MAX_BYTES} bytes.`);
273
+ if (preliminaryBytes > TURN_CONTEXT_PACK_MAX_BYTES) {
274
+ throw new Error(`Turn Context Pack exceeds ${TURN_CONTEXT_PACK_MAX_BYTES} bytes.`);
276
275
  }
277
276
  const pack = Object.freeze({
278
277
  ...body,
279
278
  budget: Object.freeze({
280
- maxRefs: RUN_CONTEXT_PACK_MAX_REFS,
279
+ maxRefs: TURN_CONTEXT_PACK_MAX_REFS,
281
280
  returnedRefs: pointers.length,
282
- maxBytes: RUN_CONTEXT_PACK_MAX_BYTES,
281
+ maxBytes: TURN_CONTEXT_PACK_MAX_BYTES,
283
282
  returnedBytes: preliminaryBytes,
284
283
  truncated: false
285
284
  }),
@@ -287,24 +286,24 @@ export function buildRunContextPack(store, taskId, runId) {
287
286
  });
288
287
  return pack;
289
288
  }
290
- export function expandRunContextRef(store, taskId, runId, refId, refStore) {
291
- const pack = buildRunContextPack(store, taskId, runId);
289
+ export function expandTurnContextRef(store, taskId, turnId, refId, refStore) {
290
+ const pack = buildTurnContextPack(store, taskId, turnId);
292
291
  const authorized = pack.pointers.filter((ref) => (ref.refId === refId && (refStore === undefined || ref.store === refStore)));
293
292
  const selector = refStore === undefined ? refId : `${refStore}/${refId}`;
294
293
  if (authorized.length !== 1) {
295
- throw new Error(`Run Context ref is not uniquely authorized: ${selector}.`);
294
+ throw new Error(`Turn Context ref is not uniquely authorized: ${selector}.`);
296
295
  }
297
- const run = requireExactRun(store, taskId, runId);
298
- const snapshotRef = run.assignment.contextSnapshotRef;
296
+ const run = requireExactTurn(store, taskId, turnId);
297
+ const snapshotRef = run.inputs[0].input.contextSnapshotRef;
299
298
  const materialized = snapshotRef === undefined
300
299
  ? collectAuthorizedContext(store, run).find(({ ref }) => (contextRefIdentity(ref) === contextRefIdentity(authorized[0])))
301
300
  : store.getContextSnapshot(taskId, snapshotRef.id)?.resources.find(({ ref }) => (contextRefIdentity(ref) === contextRefIdentity(authorized[0])));
302
301
  if (materialized === undefined || materialized.ref.digest !== authorized[0].digest) {
303
- throw new Error(`Run Context ref is unavailable or drifted: ${selector}.`);
302
+ throw new Error(`Turn Context ref is unavailable or drifted: ${selector}.`);
304
303
  }
305
304
  const bytes = Buffer.byteLength(JSON.stringify(materialized.value), "utf8");
306
- if (bytes > RUN_CONTEXT_EXPAND_MAX_BYTES) {
307
- throw new Error(`Run Context expansion exceeds ${RUN_CONTEXT_EXPAND_MAX_BYTES} bytes.`);
305
+ if (bytes > TURN_CONTEXT_EXPAND_MAX_BYTES) {
306
+ throw new Error(`Turn Context expansion exceeds ${TURN_CONTEXT_EXPAND_MAX_BYTES} bytes.`);
308
307
  }
309
308
  return Object.freeze({
310
309
  ref: materialized.ref,
@@ -312,21 +311,21 @@ export function expandRunContextRef(store, taskId, runId, refId, refStore) {
312
311
  digest: contextContentDigest({ ref: materialized.ref, value: materialized.value })
313
312
  });
314
313
  }
315
- /** Fail-closed delta cursor resolution for one immutable Run lineage. */
316
- export function buildRunContextDelta(store, taskId, runId, after) {
317
- const pack = buildRunContextPack(store, taskId, runId);
314
+ /** Fail-closed delta cursor resolution for one immutable Turn lineage. */
315
+ export function buildTurnContextDelta(store, taskId, turnId, after) {
316
+ const pack = buildTurnContextPack(store, taskId, turnId);
318
317
  if (after === pack.digest || after === pack.snapshot?.digest) {
319
318
  return Object.freeze({ schemaVersion: 1, after, cursor: pack.digest, refs: [] });
320
319
  }
321
- const run = requireExactRun(store, taskId, runId);
322
- const snapshotRef = run.assignment.contextSnapshotRef;
320
+ const run = requireExactTurn(store, taskId, turnId);
321
+ const snapshotRef = run.inputs[0].input.contextSnapshotRef;
323
322
  const snapshot = snapshotRef === undefined
324
323
  ? null
325
324
  : store.getContextSnapshot(taskId, snapshotRef.id);
326
325
  const parentDigest = snapshot?.parentRef?.digest;
327
326
  if (!((parentDigest !== undefined && after === parentDigest)
328
327
  || (parentDigest === undefined && after === "none"))) {
329
- throw new Error("Run Context delta cursor is outside the frozen Snapshot lineage.");
328
+ throw new Error("Turn Context delta cursor is outside the frozen Snapshot lineage.");
330
329
  }
331
330
  return Object.freeze({
332
331
  schemaVersion: 1,
@@ -335,10 +334,10 @@ export function buildRunContextDelta(store, taskId, runId, after) {
335
334
  refs: pack.deltas
336
335
  });
337
336
  }
338
- function requireExactRun(store, taskId, runId) {
339
- const run = store.getAgentRun(taskId, runId);
340
- if (run === null || run.taskId !== taskId || run.id !== runId) {
341
- throw new Error(`Agent Run not found: ${taskId}/${runId}.`);
337
+ function requireExactTurn(store, taskId, turnId) {
338
+ const run = store.getTurn(taskId, turnId);
339
+ if (run === null || run.taskId !== taskId || run.id !== turnId) {
340
+ throw new Error(`Turn not found: ${taskId}/${turnId}.`);
342
341
  }
343
342
  return run;
344
343
  }
@@ -352,18 +351,18 @@ function collectAuthorizedContext(store, run) {
352
351
  if (brief !== null && view === "leader") {
353
352
  result.push(materialize("L2", "task-brief", task.id, brief));
354
353
  }
355
- result.push(...collectRunContextOverlays(store, run));
354
+ result.push(...collectTurnContextOverlays(store, run));
356
355
  if (run.workItemId !== undefined) {
357
356
  const item = store.getWorkItem(task.id, run.workItemId);
358
357
  if (item === null)
359
- throw new Error(`Run WorkItem not found: ${run.workItemId}.`);
358
+ throw new Error(`Turn WorkItem not found: ${run.workItemId}.`);
360
359
  result.push(materialize("L3", "work-item", item.id, item));
361
360
  if (view === "worker") {
362
361
  for (const dependencyId of item.dependsOn) {
363
362
  const dependency = store.getWorkItem(task.id, dependencyId);
364
363
  if (dependency === null
365
364
  || (dependency.status !== "completed" && dependency.status !== "retired")) {
366
- throw new Error(`Run WorkItem dependency is not accepted: ${dependencyId}.`);
365
+ throw new Error(`Turn WorkItem dependency is not accepted: ${dependencyId}.`);
367
366
  }
368
367
  if (dependency.status === "retired")
369
368
  continue;
@@ -374,7 +373,7 @@ function collectAuthorizedContext(store, run) {
374
373
  if (run.reviewRoundId !== undefined) {
375
374
  const round = store.getReviewRound(task.id, run.reviewRoundId);
376
375
  if (round === null)
377
- throw new Error(`Run ReviewRound not found: ${run.reviewRoundId}.`);
376
+ throw new Error(`Turn ReviewRound not found: ${run.reviewRoundId}.`);
378
377
  result.push(materialize("L3", "review-round", round.id, round));
379
378
  for (const finding of store.listReviewFindings(task.id).filter((candidate) => (candidate.firstReviewRoundId === round.id
380
379
  || candidate.lastReviewRoundId === round.id
@@ -385,7 +384,7 @@ function collectAuthorizedContext(store, run) {
385
384
  for (const binding of task.projectBindings) {
386
385
  const project = store.getProject(binding.projectId);
387
386
  if (project === null)
388
- throw new Error(`Run Project not found: ${binding.projectId}.`);
387
+ throw new Error(`Turn Project not found: ${binding.projectId}.`);
389
388
  const { knowledge, ...projectPolicy } = project;
390
389
  result.push(materialize("L1", "project-policy", project.id, projectPolicy));
391
390
  for (const entry of knowledge.filter(({ status }) => status === "active")) {
@@ -409,8 +408,8 @@ function collectAuthorizedContext(store, run) {
409
408
  for (const finding of store.listReviewFindings(task.id)) {
410
409
  result.push(materialize("L3", "review-finding", finding.id, finding));
411
410
  }
412
- for (const agentRun of operationalTaskRecords(store.listAgentRuns(task.id), events, "agent-run").slice(-24)) {
413
- result.push(materialize("L4", "agent-run", agentRun.id, agentRun));
411
+ for (const turn of operationalTaskRecords(store.listTurns(task.id), events, "turn").slice(-24)) {
412
+ result.push(materialize("L4", "turn", turn.id, turn));
414
413
  }
415
414
  for (const message of operationalTaskRecords(store.listMessages(task.id), events, "message").slice(-16)) {
416
415
  result.push(materialize("L4", "task-message", message.id, message));
@@ -427,20 +426,6 @@ function collectAuthorizedContext(store, run) {
427
426
  for (const event of publishedTreeAuthorizations.reverse().slice(-16)) {
428
427
  result.push(materialize("L4", "task-event", event.id, event));
429
428
  }
430
- for (const event of events.filter(({ type }) => (type === RUN_YIELD_REJECTED_EVENT)).slice(-16)) {
431
- result.push(materialize("L4", "task-event", event.id, event));
432
- const attempt = rejectedYieldAttemptFromTaskEvent(event);
433
- if (attempt === null)
434
- continue;
435
- const rejectedRun = store.getAgentRun(task.id, attempt.runId);
436
- if (rejectedRun !== null) {
437
- result.push(materialize("L4", "agent-run", rejectedRun.id, rejectedRun));
438
- }
439
- const rejectedRound = store.getReviewRound(task.id, attempt.reviewRoundId);
440
- if (rejectedRound !== null) {
441
- result.push(materialize("L3", "review-round", rejectedRound.id, rejectedRound));
442
- }
443
- }
444
429
  for (const request of store.listOpenInputRequests([task.id])) {
445
430
  result.push(materialize("L4", "input-request", request.id, request));
446
431
  }
@@ -449,10 +434,10 @@ function collectAuthorizedContext(store, run) {
449
434
  return [...unique.values()].sort((left, right) => (contextRefIdentity(left.ref).localeCompare(contextRefIdentity(right.ref))));
450
435
  }
451
436
  /** Lane-specific context that may be layered over an immutable stage base. */
452
- function collectRunContextOverlays(store, run) {
437
+ function collectTurnContextOverlays(store, run) {
453
438
  const role = store.getRole(run.taskId, run.roleName);
454
439
  if (role === null)
455
- throw new Error(`Run Role not found: ${run.taskId}/${run.roleName}.`);
440
+ throw new Error(`Turn Role not found: ${run.taskId}/${run.roleName}.`);
456
441
  return [
457
442
  materialize("L1", "role-profile", role.name, {
458
443
  name: role.name,
@@ -514,10 +499,10 @@ function writableProjects(store, run, view) {
514
499
  }
515
500
  function completionActions(view) {
516
501
  if (view === "leader")
517
- return Object.freeze(["yield", "complete-task", "request-input"]);
502
+ return Object.freeze(["finish-turn", "complete-task", "request-input"]);
518
503
  if (view === "reviewer")
519
- return Object.freeze(["checkpoint", "yield-review"]);
504
+ return Object.freeze(["checkpoint", "finish-turn"]);
520
505
  if (view === "operator")
521
506
  return Object.freeze(["answer-input", "recover"]);
522
- return Object.freeze(["checkpoint", "yield"]);
507
+ return Object.freeze(["checkpoint", "finish-turn"]);
523
508
  }
@@ -0,0 +1,204 @@
1
+ import { normalizedUniqueIdentities, requireIdentity, requireText } from "../domain/validation.js";
2
+ import { validateContextSnapshotRef } from "./contextSnapshot.js";
3
+ export const TURN_INPUT_PROTOCOL_VERSION = 1;
4
+ export const TURN_INPUT_PROTOCOL = "yui-turn/v1";
5
+ export const TURN_INPUT_MAX_BYTES = 4 * 1024;
6
+ export const TURN_INPUT_MAX_DELTAS = 16;
7
+ export const YUI_TURN_INPUT_CHANNELS = [
8
+ "user-message",
9
+ "input-response",
10
+ "task-dispatch",
11
+ "workitem-dispatch",
12
+ "leader-wakeup",
13
+ "leader-forced-wakeup"
14
+ ];
15
+ export function createTurnInput(input) {
16
+ const common = normalizeInput(input);
17
+ return Object.freeze({
18
+ schemaVersion: TURN_INPUT_PROTOCOL_VERSION,
19
+ ...common,
20
+ ...(input.directive === undefined
21
+ ? {}
22
+ : { directive: requireText(input.directive, "Turn input directive") })
23
+ });
24
+ }
25
+ export function validateTurnInput(value) {
26
+ if (value.schemaVersion !== TURN_INPUT_PROTOCOL_VERSION) {
27
+ throw new Error("Turn input must use schemaVersion 1.");
28
+ }
29
+ const normalized = createTurnInput(value);
30
+ if (JSON.stringify(normalized) !== JSON.stringify(value)) {
31
+ throw new Error("Turn input is not canonical.");
32
+ }
33
+ return value;
34
+ }
35
+ export function createTurnInputEnvelope(context, input) {
36
+ validateTurnInput(input);
37
+ const normalized = normalizeEnvelopeContext(context, input);
38
+ return Object.freeze({
39
+ protocol: TURN_INPUT_PROTOCOL,
40
+ turnId: normalized.turnId,
41
+ source: input.source,
42
+ roleName: normalized.roleName,
43
+ purpose: normalized.purpose,
44
+ subject: normalized.subject,
45
+ ...(input.contextSnapshotRef === undefined
46
+ ? {}
47
+ : { contextSnapshotRef: input.contextSnapshotRef }),
48
+ deltaRefIds: input.deltaRefIds
49
+ });
50
+ }
51
+ export function validateTurnInputEnvelope(value) {
52
+ if (value.protocol !== TURN_INPUT_PROTOCOL) {
53
+ throw new Error("Turn input protocol is unsupported.");
54
+ }
55
+ normalizeEnvelope(value);
56
+ const serialized = serializeTurnInputEnvelope(value);
57
+ if (Buffer.byteLength(serialized, "utf8") > TURN_INPUT_MAX_BYTES) {
58
+ throw new Error("Turn input envelope exceeds its protocol byte limit.");
59
+ }
60
+ return value;
61
+ }
62
+ export function serializeTurnInputEnvelope(value) {
63
+ if (value.protocol !== TURN_INPUT_PROTOCOL) {
64
+ throw new Error("Turn input protocol is unsupported.");
65
+ }
66
+ const normalized = normalizeEnvelope(value);
67
+ const subject = Object.entries(normalized.subject)
68
+ .map(([key, id]) => `${key}:${id}`)
69
+ .join(",");
70
+ const snapshot = normalized.contextSnapshotRef;
71
+ const lines = [
72
+ "Yui Turn input. Follow the Session Manifest and injected Skills.",
73
+ `${normalized.subject.taskId === undefined ? "" : `task=${normalized.subject.taskId} `}turn=${normalized.turnId} role=${normalized.roleName}`,
74
+ `source=${normalized.source.type}/${normalized.source.channel} purpose=${normalized.purpose} subject=${subject || "global"} snapshot=${snapshot === undefined ? "none" : `${snapshot.id}@${snapshot.digest}`}`,
75
+ normalized.deltaRefIds.length === 0
76
+ ? "delta=none"
77
+ : `delta=${normalized.deltaRefIds.join(",")}`,
78
+ "Load the exact Turn context before acting; fail closed if it is unavailable or mismatched."
79
+ ];
80
+ const serialized = lines.join("\n");
81
+ if (Buffer.byteLength(serialized, "utf8") > TURN_INPUT_MAX_BYTES) {
82
+ throw new Error("Turn input envelope exceeds its protocol byte limit.");
83
+ }
84
+ return serialized;
85
+ }
86
+ /**
87
+ * Bounded infrastructure-recovery input for an already-submitted Turn. It resumes
88
+ * the provider-native transcript after Host/child replacement and never
89
+ * replays the Assignment or its directive.
90
+ */
91
+ export function serializeTurnHostRecoveryEnvelope(value) {
92
+ const normalized = normalizeEnvelope(value);
93
+ const serialized = [
94
+ "Yui Host recovery for an existing Turn.",
95
+ `${normalized.subject.taskId === undefined ? "" : `task=${normalized.subject.taskId} `}turn=${normalized.turnId} role=${normalized.roleName}`,
96
+ "Resume the same native conversation from its latest durable state. Do not repeat completed work or replay the original input.",
97
+ "Load the exact Turn context or delta only if needed, then continue the same Turn."
98
+ ].join("\n");
99
+ if (Buffer.byteLength(serialized, "utf8") > TURN_INPUT_MAX_BYTES) {
100
+ throw new Error("Turn Host recovery envelope exceeds its protocol byte limit.");
101
+ }
102
+ return serialized;
103
+ }
104
+ function normalizeInput(input) {
105
+ const source = normalizeSource(input.source);
106
+ const snapshot = input.contextSnapshotRef === undefined
107
+ ? undefined
108
+ : validateContextSnapshotRef(input.contextSnapshotRef);
109
+ const deltaRefIds = normalizedUniqueIdentities(input.deltaRefIds, "Turn input delta ref");
110
+ if (deltaRefIds.length > TURN_INPUT_MAX_DELTAS) {
111
+ throw new Error(`Turn input supports at most ${TURN_INPUT_MAX_DELTAS} delta refs.`);
112
+ }
113
+ return {
114
+ source,
115
+ ...(snapshot === undefined ? {} : { contextSnapshotRef: snapshot }),
116
+ deltaRefIds
117
+ };
118
+ }
119
+ function normalizeEnvelopeContext(context, input) {
120
+ const normalized = normalizeEnvelope({
121
+ protocol: TURN_INPUT_PROTOCOL,
122
+ turnId: context.turnId,
123
+ source: input.source,
124
+ roleName: context.roleName,
125
+ purpose: context.purpose,
126
+ subject: context.subject,
127
+ ...(input.contextSnapshotRef === undefined
128
+ ? {}
129
+ : { contextSnapshotRef: input.contextSnapshotRef }),
130
+ deltaRefIds: input.deltaRefIds
131
+ });
132
+ return {
133
+ turnId: normalized.turnId,
134
+ roleName: normalized.roleName,
135
+ purpose: normalized.purpose,
136
+ subject: normalized.subject
137
+ };
138
+ }
139
+ function normalizeEnvelope(input) {
140
+ if (!["execution", "review", "global"].includes(input.purpose)) {
141
+ throw new Error("Turn input purpose is invalid.");
142
+ }
143
+ const normalizedInput = normalizeInput(input);
144
+ const subject = normalizeSubject(input.subject);
145
+ if (normalizedInput.contextSnapshotRef !== undefined
146
+ && normalizedInput.contextSnapshotRef.taskId !== subject.taskId) {
147
+ throw new Error("Turn input Context Snapshot belongs to another Task.");
148
+ }
149
+ if (input.purpose !== "global" && subject.taskId === undefined) {
150
+ throw new Error("A Task Turn input requires a Task subject.");
151
+ }
152
+ if (input.purpose === "review" && subject.reviewRoundId === undefined) {
153
+ throw new Error("A review Turn input requires a ReviewRound subject.");
154
+ }
155
+ return {
156
+ protocol: TURN_INPUT_PROTOCOL,
157
+ turnId: requireIdentity(input.turnId, "Turn input Turn id"),
158
+ source: normalizedInput.source,
159
+ roleName: requireIdentity(input.roleName, "Turn input Role name"),
160
+ purpose: input.purpose,
161
+ subject,
162
+ ...(normalizedInput.contextSnapshotRef === undefined
163
+ ? {}
164
+ : { contextSnapshotRef: normalizedInput.contextSnapshotRef }),
165
+ deltaRefIds: normalizedInput.deltaRefIds
166
+ };
167
+ }
168
+ function normalizeSubject(subject) {
169
+ const normalized = Object.fromEntries(Object.entries(subject).map(([key, value]) => [
170
+ key,
171
+ requireIdentity(value, `Turn input ${key}`)
172
+ ]));
173
+ const allowed = [
174
+ "taskId",
175
+ "workItemId",
176
+ "reviewRoundId",
177
+ "executionGroupId",
178
+ "executionLaneId"
179
+ ];
180
+ if (Object.keys(normalized).some((key) => !allowed.includes(key))) {
181
+ throw new Error("Turn input subject contains an unknown field.");
182
+ }
183
+ if ((normalized.executionGroupId === undefined) !== (normalized.executionLaneId === undefined)) {
184
+ throw new Error("Turn input execution lineage is incomplete.");
185
+ }
186
+ if (normalized.taskId === undefined
187
+ && (normalized.workItemId !== undefined || normalized.reviewRoundId !== undefined
188
+ || normalized.executionGroupId !== undefined)) {
189
+ throw new Error("Turn input child subject requires a Task id.");
190
+ }
191
+ return Object.freeze(normalized);
192
+ }
193
+ function normalizeSource(source) {
194
+ if (source.type === "yui" && YUI_TURN_INPUT_CHANNELS.includes(source.channel)) {
195
+ return Object.freeze({ type: "yui", channel: source.channel });
196
+ }
197
+ if (source.type === "user" && source.channel === "direct") {
198
+ return Object.freeze({ type: "user", channel: "direct" });
199
+ }
200
+ if (source.type === "provider" && source.channel === "goal-continuation") {
201
+ return Object.freeze({ type: "provider", channel: "goal-continuation" });
202
+ }
203
+ throw new Error("Turn input source is invalid.");
204
+ }
@@ -33,7 +33,7 @@ export function buildTaskWakeEnvelope(reader, request) {
33
33
  .filter((record) => Date.parse(record.createdAt) > fromTime).length,
34
34
  messages: operationalTaskRecords(reader.listMessages(request.taskId), events, "message")
35
35
  .filter((record) => Date.parse(record.createdAt) > fromTime).length,
36
- runs: operationalTaskRecords(reader.listAgentRuns(request.taskId), events, "agent-run")
36
+ turns: operationalTaskRecords(reader.listTurns(request.taskId), events, "turn")
37
37
  .filter((record) => Date.parse(record.createdAt) > fromTime).length
38
38
  };
39
39
  const activeReviews = reader.listReviewRounds(request.taskId).filter((round) => ((round.scope ?? "work-item") === "task"
@@ -50,7 +50,7 @@ export function buildTaskWakeEnvelope(reader, request) {
50
50
  const lines = [
51
51
  `Wake: ${request.wakeId} — delta since ${request.fromCursor}`,
52
52
  ` Reasons: ${renderReasons(request.reasons)}`,
53
- ` Changed: ${counts.events} events, ${counts.messages} messages, ${counts.runs} runs`
53
+ ` Changed: ${counts.events} events, ${counts.messages} messages, ${counts.turns} Turns`
54
54
  + ` → yui task wake show ${request.taskId} ${request.wakeId}`,
55
55
  ` Active Task Reviews: ${activeReviews.length === 0
56
56
  ? "none"