@zq-silk/yui 0.15.7 → 0.15.8

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 (281) hide show
  1. package/ARCHITECTURE.md +192 -399
  2. package/README.md +127 -1149
  3. package/dist/agent/adapterCatalog.js +15 -2
  4. package/dist/agent/agent.js +23 -3
  5. package/dist/agent/argumentPolicy.js +7 -1
  6. package/dist/agent/connectionPlan.js +62 -0
  7. package/dist/agent/executionComponents.js +158 -0
  8. package/dist/agent/launchEnvironment.js +31 -3
  9. package/dist/agent/managedRuntimeEnvironment.js +3 -5
  10. package/dist/{turn/turn.js → agentRun/agentRun.js} +166 -109
  11. package/dist/{turn/turnIdentity.js → agentRun/runIdentity.js} +4 -4
  12. package/dist/brief/taskBrief.js +12 -0
  13. package/dist/cli/agentConfigurationPicker.js +13 -0
  14. package/dist/cli/commandCatalog.js +157 -70
  15. package/dist/cli/interactionCandidates.js +5 -5
  16. package/dist/cli/interactionPolicy.js +38 -8
  17. package/dist/cli/invocationRouter.js +1 -1
  18. package/dist/cli/managedDiagnostics.js +28 -0
  19. package/dist/cli/operatorWizard.js +1 -7
  20. package/dist/cli/roleOptionOrder.js +27 -0
  21. package/dist/cli/roleWizard.js +50 -14
  22. package/dist/cli/updateOrchestrator.js +1 -1
  23. package/dist/cli/updatePorts.js +3 -4
  24. package/dist/cli.js +178 -95
  25. package/dist/commands/agentCommands.js +72 -14
  26. package/dist/commands/capabilityCommands.js +9 -6
  27. package/dist/commands/configCommands.js +20 -20
  28. package/dist/commands/deliveryGuardPreflight.js +2 -2
  29. package/dist/commands/executionAuditCommands.js +24 -24
  30. package/dist/commands/globalRoleCommands.js +1 -1
  31. package/dist/commands/grantCommands.js +4 -4
  32. package/dist/commands/operatorCommands.js +1 -7
  33. package/dist/commands/projectCommands.js +4 -4
  34. package/dist/commands/resourcesCommands.js +2 -2
  35. package/dist/commands/roleConfiguration.js +25 -5
  36. package/dist/commands/roleRuntimeGuard.js +4 -5
  37. package/dist/commands/sessionCommands.js +3 -7
  38. package/dist/commands/taskActivationCommands.js +259 -0
  39. package/dist/commands/taskActor.js +28 -49
  40. package/dist/commands/taskCommands.js +1188 -710
  41. package/dist/commands/taskContextCommand.js +39 -583
  42. package/dist/commands/taskExecutionCommands.js +32 -32
  43. package/dist/commands/taskInputCommands.js +40 -104
  44. package/dist/commands/taskIntegrationCommands.js +3 -2
  45. package/dist/commands/taskIntegrationQueueCommands.js +1 -1
  46. package/dist/commands/taskNextActionCommand.js +8 -8
  47. package/dist/commands/taskOverviewCommand.js +33 -45
  48. package/dist/commands/taskRemoteDeliveryCommand.js +2 -2
  49. package/dist/commands/taskRoleRuntimeStatus.js +133 -102
  50. package/dist/commands/telemetryCommands.js +36 -38
  51. package/dist/config/configCatalog.js +4 -4
  52. package/dist/config/yuiConfig.js +8 -8
  53. package/dist/context/contextSnapshot.js +10 -10
  54. package/dist/context/dispatchContext.js +11 -11
  55. package/dist/context/roleSessionContext.js +6 -3
  56. package/dist/context/{turnContextPack.js → runContextPack.js} +146 -81
  57. package/dist/context/{turnInputContract.js → runInputContract.js} +73 -60
  58. package/dist/context/sessionBootstrapManifest.js +21 -2
  59. package/dist/context/sourceRunContext.js +30 -0
  60. package/dist/context/taskContext.js +458 -0
  61. package/dist/context/wakeNotification.js +27 -27
  62. package/dist/controller/agentRuntimeObserver.js +21 -24
  63. package/dist/controller/capabilityBridge.js +17 -6
  64. package/dist/controller/clientRuntime.js +65 -92
  65. package/dist/controller/controller.js +114 -188
  66. package/dist/controller/fileSchedulerStoreAdapter.js +787 -887
  67. package/dist/controller/jobControl.js +54 -85
  68. package/dist/controller/resourceInventory.js +8 -27
  69. package/dist/controller/resourceInventoryLinux.js +12 -13
  70. package/dist/controller/runtime.js +529 -479
  71. package/dist/controller/runtimeEventInbox.js +55 -25
  72. package/dist/controller/runtimeEventProcessor.js +22 -31
  73. package/dist/controller/{runtimeHookTurnFence.js → runtimeHookRunFence.js} +91 -115
  74. package/dist/controller/runtimeLaunchCoordinator.js +80 -426
  75. package/dist/controller/runtimeObservationHook.js +14 -18
  76. package/dist/controller/sessionNotify.js +16 -24
  77. package/dist/controller/sessionOwnerReconciliation.js +168 -50
  78. package/dist/controller/structuredProviderObservation.js +138 -99
  79. package/dist/coordination/workMailbox.js +3 -3
  80. package/dist/coordination/workMailboxQueue.js +36 -33
  81. package/dist/core/boundedRpc.js +8 -1
  82. package/dist/core/controllerClient.js +20 -1
  83. package/dist/core/controllerServer.js +4 -4
  84. package/dist/doctor/doctor.js +13 -2
  85. package/dist/domain/agentResultTransport.js +9 -9
  86. package/dist/execution/codexThreadNaming.js +2 -8
  87. package/dist/execution/executionHealth.js +51 -63
  88. package/dist/execution/reviewMainRun.js +137 -0
  89. package/dist/execution/workItemExecution.js +28 -29
  90. package/dist/execution/workItemExecutionProjection.js +99 -107
  91. package/dist/execution/workItemMainRun.js +141 -0
  92. package/dist/executor/agentAdapter.js +227 -20
  93. package/dist/executor/agentConfigurationCatalog.js +126 -4
  94. package/dist/executor/agentConfigurationProbe.js +162 -4
  95. package/dist/executor/agentExecutor.js +79 -78
  96. package/dist/executor/effectiveLaunch.js +105 -18
  97. package/dist/executor/executorRegistry.js +29 -44
  98. package/dist/executor/fileRoleLaunchPlanner.js +229 -154
  99. package/dist/executor/workspacePreflightClassification.js +16 -16
  100. package/dist/grant/capabilityGrant.js +6 -3
  101. package/dist/input/inputRequest.js +12 -10
  102. package/dist/integration/gitIntegrationService.js +4 -11
  103. package/dist/integration/integrationQueueService.js +4 -4
  104. package/dist/interaction/operatorPresentation.js +1 -1
  105. package/dist/kernel/builtinCapabilities.js +247 -12
  106. package/dist/kernel/capabilityRegistry.js +64 -18
  107. package/dist/kernel/instanceHost.js +12 -1
  108. package/dist/kernel/kernelPorts.js +2 -2
  109. package/dist/lifecycle/canonicalLifecycleEvent.js +44 -49
  110. package/dist/lifecycle/exactRunTerminalization.js +449 -0
  111. package/dist/message/message.js +62 -6
  112. package/dist/message/messageContinuation.js +204 -0
  113. package/dist/observability/executionAudit.js +70 -72
  114. package/dist/observability/faultClassification.js +2 -2
  115. package/dist/observability/orchestrationMetrics.js +8 -8
  116. package/dist/operator/operatorSessionHistory.js +1 -7
  117. package/dist/output/agentConfigurationPresentation.js +8 -3
  118. package/dist/output/agentRunConfigurationPresentation.js +128 -0
  119. package/dist/output/rolePresentation.js +54 -3
  120. package/dist/plugins/pluginChild.js +104 -0
  121. package/dist/plugins/pluginIntent.js +26 -0
  122. package/dist/plugins/pluginInterpreter.js +43 -0
  123. package/dist/plugins/pluginPackage.js +101 -0
  124. package/dist/plugins/pluginProcess.js +112 -0
  125. package/dist/plugins/pluginService.js +380 -0
  126. package/dist/profile/agentProfile.js +1 -1
  127. package/dist/repository/gitWorkspace.js +26 -4
  128. package/dist/repository/project.js +19 -4
  129. package/dist/repository/taskBaseFreshness.js +13 -13
  130. package/dist/repository/taskWorkspaceCoordinator.js +20 -27
  131. package/dist/repository/taskWorkspacePreparer.js +344 -83
  132. package/dist/resources/autoResourceGc.js +3 -3
  133. package/dist/resources/liveReferences.js +3 -3
  134. package/dist/resources/projectResource.js +123 -0
  135. package/dist/resources/projectResourceService.js +421 -0
  136. package/dist/resources/resourceDiscovery.js +6 -6
  137. package/dist/resources/resourceGc.js +1 -1
  138. package/dist/resources/resourceRegistrar.js +1 -1
  139. package/dist/resources/resourceTypes.js +1 -1
  140. package/dist/review/deltaRecheck.js +3 -3
  141. package/dist/review/reviewAcceptance.js +16 -16
  142. package/dist/review/reviewDecision.js +7 -7
  143. package/dist/review/reviewRound.js +21 -20
  144. package/dist/review/reviewerAvailability.js +2 -2
  145. package/dist/role/role.js +51 -7
  146. package/dist/role/taskRoleUpdate.js +30 -0
  147. package/dist/runtime/acpProtocol.js +425 -0
  148. package/dist/runtime/acpSession.js +731 -0
  149. package/dist/runtime/acpSessionConfiguration.js +260 -0
  150. package/dist/runtime/agentDriver.js +30 -11
  151. package/dist/runtime/agentEndpoint.js +278 -0
  152. package/dist/runtime/agentEndpointIdentity.js +86 -0
  153. package/dist/runtime/agentEndpointOwnership.js +239 -0
  154. package/dist/runtime/agentError.js +2 -10
  155. package/dist/runtime/agentHost.js +565 -314
  156. package/dist/runtime/agentRunConfiguration.js +258 -0
  157. package/dist/runtime/builtinAgentDrivers.js +134 -18
  158. package/dist/runtime/builtinAgentErrorMappers.js +55 -3
  159. package/dist/runtime/builtinTranscriptUsage.js +1 -1
  160. package/dist/runtime/claude-process-owner +0 -0
  161. package/dist/runtime/codexAppServerRuntime.js +38 -30
  162. package/dist/runtime/codexInteractiveHost.js +41 -6
  163. package/dist/runtime/continuationManager.js +2 -6
  164. package/dist/runtime/executionEnvironment.js +30 -0
  165. package/dist/runtime/firstProgressAdvisory.js +11 -11
  166. package/dist/runtime/index.js +4 -3
  167. package/dist/runtime/jsonLineChannel.js +109 -0
  168. package/dist/runtime/launchBroker.js +91 -16
  169. package/dist/runtime/launchDiagnostics.js +2 -2
  170. package/dist/runtime/lifecycleReservation.js +10 -18
  171. package/dist/runtime/managedCaller.js +61 -17
  172. package/dist/runtime/nativeSessionControl.js +102 -0
  173. package/dist/runtime/ports.js +6 -21
  174. package/dist/runtime/processExitObservation.js +8 -7
  175. package/dist/runtime/promptEnvelope.js +17 -6
  176. package/dist/runtime/providerContinuation.js +3 -9
  177. package/dist/runtime/providerContinuationReconciliationService.js +4 -13
  178. package/dist/runtime/providerControl.js +2 -7
  179. package/dist/runtime/providerRuntimeIdentity.js +110 -222
  180. package/dist/runtime/providerRuntimeReconciler.js +5 -9
  181. package/dist/runtime/runtimeBinding.js +0 -1
  182. package/dist/runtime/runtimeContinuationProjection.js +4 -7
  183. package/dist/runtime/runtimeDeadlines.js +9 -0
  184. package/dist/runtime/runtimeHealthPolicy.js +1 -1
  185. package/dist/runtime/runtimeObservation.js +29 -65
  186. package/dist/runtime/runtimeProjection.js +43 -51
  187. package/dist/runtime/runtimeSessionCandidate.js +1 -3
  188. package/dist/runtime/sessionLaunchRequest.js +3 -7
  189. package/dist/runtime/sessionOwnerIdentity.js +7 -54
  190. package/dist/runtime/sessionOwnerRegistry.js +22 -17
  191. package/dist/runtime/sessionReconciliation.js +4 -8
  192. package/dist/runtime/sessionTerminationGuard.js +70 -259
  193. package/dist/runtime/sessionTokenMetrics.js +5 -16
  194. package/dist/runtime/structuredProviderHost.js +237 -117
  195. package/dist/runtime/taskRuntimeIsolation.js +39 -122
  196. package/dist/runtime/tmuxAdapters.js +39 -86
  197. package/dist/scheduler/activeRoleRunDelivery.js +354 -0
  198. package/dist/scheduler/leaderWakeupProcessor.js +75 -266
  199. package/dist/scheduler/operatorInputNotificationProcessor.js +1 -1
  200. package/dist/scheduler/ports.js +80 -9
  201. package/dist/scheduler/{roleTurnLiveness.js → roleRunLiveness.js} +26 -30
  202. package/dist/scheduler/{roleTurnStall.js → roleRunStall.js} +128 -139
  203. package/dist/scheduler/taskExecutionProjection.js +120 -124
  204. package/dist/scheduler/taskObservabilityProjection.js +29 -29
  205. package/dist/scheduler/taskWake.js +11 -4
  206. package/dist/scheduler/wakeReason.js +9 -1
  207. package/dist/setup/setupCommand.js +1 -0
  208. package/dist/storage/migrations/agentRunContract.js +159 -0
  209. package/dist/storage/migrations/removeRuntimeGeneration.js +207 -0
  210. package/dist/storage/sqliteSchema.js +431 -5
  211. package/dist/storage/sqliteStore.js +375 -220
  212. package/dist/storage/storageVersions.js +1 -1
  213. package/dist/storage/storeRpc.js +10 -5
  214. package/dist/storage/taskStore.js +13 -11
  215. package/dist/storage/upgrade/upgradeOrchestrator.js +5 -7
  216. package/dist/surface/surfaceContributions.js +102 -0
  217. package/dist/task/completionReadiness.js +32 -6
  218. package/dist/task/deliveryGuard.js +16 -16
  219. package/dist/task/draftPlan.js +72 -12
  220. package/dist/task/nextAction.js +144 -128
  221. package/dist/task/remoteDelivery.js +6 -6
  222. package/dist/task/task.js +184 -18
  223. package/dist/task/taskActivation.js +301 -0
  224. package/dist/task/taskActivationService.js +392 -0
  225. package/dist/task/taskRecordReference.js +5 -4
  226. package/dist/task/taskRecordRetirement.js +1 -1
  227. package/dist/telemetry/sqliteTelemetryStore.js +55 -68
  228. package/dist/telemetry/telemetryConfig.js +14 -14
  229. package/dist/telemetry/telemetryWiring.js +2 -2
  230. package/dist/web/assets/assetManifest.js +2 -0
  231. package/dist/web/assets/client/app.js +120 -20
  232. package/dist/web/assets/client/components.js +87 -54
  233. package/dist/web/assets/client/i18n.js +83 -41
  234. package/dist/web/assets/client/markdown.js +1 -1
  235. package/dist/web/assets/client/taskSurface.js +353 -0
  236. package/dist/web/assets/client/view.js +49 -44
  237. package/dist/web/assets/shell.js +1 -1
  238. package/dist/web/assets/styles/cards.js +22 -4
  239. package/dist/web/controllerWeb.js +60 -0
  240. package/dist/web/webMutation.js +28 -0
  241. package/dist/web/webServer.js +118 -8
  242. package/dist/web/webSnapshot.js +81 -74
  243. package/dist/web/webTaskSurface.js +64 -0
  244. package/dist/workItem/dependencyGate.js +1 -1
  245. package/dist/workItem/workItem.js +80 -48
  246. package/dist/workspace/workItemChangeSetManager.js +16 -9
  247. package/docs/agent-result-consumption.md +94 -0
  248. package/docs/agent-runtime-drivers.md +91 -0
  249. package/docs/architecture/README.md +38 -0
  250. package/docs/architecture/capabilities-and-resources.md +79 -0
  251. package/docs/managed-turn-and-session-runtime.md +222 -0
  252. package/docs/observability/README.md +81 -0
  253. package/docs/plugin-sdk.md +290 -0
  254. package/docs/provider-runtime.md +163 -0
  255. package/docs/release-workflow.md +303 -0
  256. package/docs/roles-and-configuration.md +113 -0
  257. package/docs/sqlite-control-plane-design.md +76 -0
  258. package/docs/task-dag-semantics.md +57 -0
  259. package/docs/task-delivery.md +103 -0
  260. package/docs/task-local-identity.md +6 -6
  261. package/docs/testing/verification-levels.md +86 -0
  262. package/i18n/README.zh-CN.md +98 -739
  263. package/package.json +2 -2
  264. package/skills/yui-leader/SKILL.md +130 -103
  265. package/skills/yui-leader/references/integration.md +39 -0
  266. package/skills/yui-leader/references/replicated-execution.md +42 -0
  267. package/skills/yui-leader/references/task-plugins.md +33 -0
  268. package/skills/yui-operator/SKILL.md +30 -59
  269. package/skills/yui-reviewer/SKILL.md +35 -36
  270. package/skills/yui-runtime/SKILL.md +88 -24
  271. package/skills/yui-runtime/references/publication.md +22 -0
  272. package/skills/yui-runtime/references/recovery.md +64 -0
  273. package/skills/yui-worker/SKILL.md +37 -39
  274. package/dist/cli/roleOptionCatalog.js +0 -68
  275. package/dist/context/sourceTurnContext.js +0 -30
  276. package/dist/execution/reviewMainTurn.js +0 -161
  277. package/dist/execution/workItemMainTurn.js +0 -164
  278. package/dist/lifecycle/exactTurnTerminalization.js +0 -407
  279. package/dist/runtime/preallocatedNativeSession.js +0 -13
  280. package/dist/runtime/runtimeStopReceipt.js +0 -42
  281. package/dist/scheduler/activeRoleTurnDelivery.js +0 -315
@@ -0,0 +1,458 @@
1
+ import { usageError, taskNotFound } from "../errors/cliError.js";
2
+ import { resolveManagedTaskReader } from "../runtime/managedCaller.js";
3
+ import { contextContentDigest } from "./contextSnapshot.js";
4
+ import { buildRunContextPack } from "./runContextPack.js";
5
+ import { sourceRunContextValue } from "./sourceRunContext.js";
6
+ import { expandTaskMessageResult } from "../message/message.js";
7
+ import { managedWorkspaceKey } from "../worktree/managedWorkspace.js";
8
+ import { runExecutionObservation } from "../agentRun/agentRun.js";
9
+ const MAX_RECORDS = 256;
10
+ const MAX_VALUE_BYTES = 4096;
11
+ const MAX_PAGE_BYTES = 128 * 1024;
12
+ const MAX_INSPECT_BYTES = 4 * 1024 * 1024;
13
+ const MAX_EVENTS = 100;
14
+ const MAX_ATTENTION_REFS = 8;
15
+ /** A current read model, not a second snapshot store or a delivery receipt.
16
+ * Every public path checks the same scope before reading, counting or paging.
17
+ */
18
+ export function readTaskContext(store, taskId, environment = {}) {
19
+ return store.transaction((reader) => {
20
+ const entries = authorizedEntries(reader, taskId, environment);
21
+ const cursor = currentCursor(reader, taskId);
22
+ // Reserve a small, classified view before ordinary history consumes the
23
+ // page. Counts and samples come from the exact same authorized read.
24
+ const attention = summarizeAttention(entries);
25
+ let bytes = Buffer.byteLength(JSON.stringify(attention));
26
+ const records = [];
27
+ const runtimeEvents = entries.some((entry) => entry.ref.store === "run") ? reader.listEvents(taskId) : [];
28
+ for (const entry of entries) {
29
+ const valueBytes = Buffer.byteLength(JSON.stringify(entry.value));
30
+ const content = valueBytes > MAX_VALUE_BYTES
31
+ ? { ref: entry.ref, summary: summarize(entry.value), omitted: true }
32
+ : { ...entry, omitted: false };
33
+ const record = { ...content, ...(entry.ref.store === "run" ? {
34
+ execution: runExecutionObservation(entry.value, reader.getTaskRoleSessionSet(taskId, entry.value.roleName)?.providerBinding, runtimeEvents)
35
+ } : {}) };
36
+ const size = Buffer.byteLength(JSON.stringify(record));
37
+ if (records.length >= MAX_RECORDS || bytes + size > MAX_PAGE_BYTES)
38
+ break;
39
+ records.push(record);
40
+ bytes += size;
41
+ }
42
+ return {
43
+ taskId, coreCursor: encode(cursor), throughCursor: encode(cursor),
44
+ attention,
45
+ records, count: entries.length,
46
+ omitted: { records: entries.length - records.length, values: records.filter((r) => r.omitted).length },
47
+ observations: [],
48
+ limits: { records: MAX_RECORDS, valueBytes: MAX_VALUE_BYTES, pageBytes: MAX_PAGE_BYTES,
49
+ attentionRefsPerCategory: MAX_ATTENTION_REFS, attentionRefBytesPerCategory: MAX_VALUE_BYTES }
50
+ };
51
+ });
52
+ }
53
+ function summarizeAttention(entries) {
54
+ const group = () => ({ count: 0, refs: [], omittedRefs: 0 });
55
+ const attention = {
56
+ openInputs: group(), pendingOperations: group(), unknownOperations: group()
57
+ };
58
+ const bytes = { openInputs: 0, pendingOperations: 0, unknownOperations: 0 };
59
+ for (const entry of entries) {
60
+ const status = entry.value.status;
61
+ const category = entry.ref.store === "input-request" && status === "open" ? "openInputs"
62
+ : entry.ref.store === "job" && status === "unknown-needs-attention" ? "unknownOperations"
63
+ : entry.ref.store === "job" && (status === "queued" || status === "running") ? "pendingOperations"
64
+ : undefined;
65
+ if (category === undefined)
66
+ continue;
67
+ const summary = attention[category];
68
+ summary.count++;
69
+ const size = Buffer.byteLength(JSON.stringify(entry.ref)) + 1;
70
+ if (summary.refs.length < MAX_ATTENTION_REFS && bytes[category] + size <= MAX_VALUE_BYTES) {
71
+ summary.refs.push(entry.ref);
72
+ bytes[category] += size;
73
+ }
74
+ else {
75
+ summary.omittedRefs++;
76
+ }
77
+ }
78
+ return attention;
79
+ }
80
+ /** Delta is immutable Task event history, not latest mutable record contents
81
+ * mislabeled as an old snapshot. Inspect/read explicitly obtains current facts.
82
+ * A continuation carries the first page's fixed upper event bound.
83
+ */
84
+ export function readTaskContextDelta(store, taskId, input, environment = {}) {
85
+ return store.transaction((reader) => {
86
+ const { allow } = authorizeContext(reader, taskId, environment);
87
+ const history = reader.listEvents(taskId);
88
+ const start = decode(input.after, taskId);
89
+ const now = currentCursor(reader, taskId, history);
90
+ const continuation = input.continuation === undefined ? undefined : decodePage(input.continuation, taskId);
91
+ const bound = continuation ?? now;
92
+ const after = continuation?.after ?? start.sequence;
93
+ if (start.sequence > bound.sequence || after < start.sequence || after > bound.sequence
94
+ || bound.sequence > now.sequence || start.revision > now.revision || bound.revision > now.revision) {
95
+ throw usageError("Context cursor is outside the current Task history.");
96
+ }
97
+ const limit = input.limit ?? MAX_EVENTS;
98
+ if (!Number.isSafeInteger(limit) || limit < 1 || limit > MAX_EVENTS) {
99
+ throw usageError(`Context delta limit must be between 1 and ${MAX_EVENTS}.`);
100
+ }
101
+ const events = history
102
+ .filter((event) => isAllowed(allow, "task-event", event.id)
103
+ && sequence(event.id) > after && sequence(event.id) <= bound.sequence)
104
+ .sort((a, b) => sequence(a.id) - sequence(b.id));
105
+ const page = [];
106
+ let bytes = 0;
107
+ for (const event of events) {
108
+ const entry = materialize("task-event", event.id, event);
109
+ const record = Buffer.byteLength(JSON.stringify(event)) > MAX_VALUE_BYTES
110
+ ? { ref: entry.ref, omitted: true }
111
+ : { ...entry, omitted: false };
112
+ const size = Buffer.byteLength(JSON.stringify(record));
113
+ if (page.length >= limit || bytes + size > MAX_PAGE_BYTES)
114
+ break;
115
+ page.push(record);
116
+ bytes += size;
117
+ }
118
+ const last = page.at(-1)?.ref.refId;
119
+ const more = events.length > page.length;
120
+ const through = { taskId, sequence: bound.sequence, revision: bound.revision };
121
+ return {
122
+ taskId, events: page, count: events.length, throughCursor: encode(through),
123
+ ...(more && last !== undefined
124
+ ? { continuation: encode({ ...through, after: sequence(last) }) } : {}),
125
+ observations: []
126
+ };
127
+ });
128
+ }
129
+ export function inspectTaskContext(store, taskId, selector, environment = {}) {
130
+ return store.transaction((reader) => {
131
+ const scope = authorizeContext(reader, taskId, environment);
132
+ const value = isAllowed(scope.allow, selector.store, selector.refId)
133
+ ? inspectValue(reader, scope, selector) : null;
134
+ if (value === null)
135
+ throw usageError("Context reference is unavailable in the caller's current scope.");
136
+ const entry = materialize(selector.store, selector.refId, value);
137
+ if (selector.digest !== undefined && entry.ref.digest !== selector.digest) {
138
+ throw usageError("Context reference changed; read its current reference before inspecting again.", undefined, {
139
+ currentRef: entry.ref
140
+ });
141
+ }
142
+ if (Buffer.byteLength(JSON.stringify(entry.value)) > MAX_INSPECT_BYTES) {
143
+ throw usageError("Context value exceeds the bounded inspect limit.", undefined, { ref: entry.ref, maxBytes: MAX_INSPECT_BYTES });
144
+ }
145
+ const expansion = selector.store === "task-message"
146
+ ? expandTaskMessageResult(value, (task, run) => reader.getRun(task, run))
147
+ : undefined;
148
+ const response = { ...entry, ...(expansion !== undefined && "result" in expansion
149
+ ? { result: expansion.result } : {}),
150
+ ...(selector.store === "run" ? { execution: runExecutionObservation(value, reader.getTaskRoleSessionSet(taskId, value.roleName)?.providerBinding, reader.listEvents(taskId)) } : {}),
151
+ coreCursor: encode(currentCursor(reader, taskId)) };
152
+ if (Buffer.byteLength(JSON.stringify(response)) > MAX_INSPECT_BYTES) {
153
+ throw usageError("Expanded Context exceeds the bounded inspect limit.", undefined, { ref: entry.ref, maxBytes: MAX_INSPECT_BYTES });
154
+ }
155
+ return response;
156
+ });
157
+ }
158
+ export function listContextMessages(store, taskId, environment = {}) {
159
+ return store.transaction((reader) => {
160
+ const { allow } = authorizeContext(reader, taskId, environment);
161
+ return reader.listMessages(taskId)
162
+ .filter((message) => isAllowed(allow, "task-message", message.id))
163
+ .sort((a, b) => a.createdAt.localeCompare(b.createdAt) || a.id.localeCompare(b.id));
164
+ });
165
+ }
166
+ /** Optional read-only providers receive only the caller's bounded core view.
167
+ * No Store, credentials or mutation port is exposed. An unavailable provider
168
+ * cannot prevent returning the core. This is a trusted in-process port, not a
169
+ * JavaScript sandbox; executable plugin admission belongs to its owner.
170
+ */
171
+ export async function withContextObservations(core, providers, timeoutMs = 250) {
172
+ if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 1000 || providers.length > 8) {
173
+ throw usageError("Optional Context providers exceed the bounded observation budget.");
174
+ }
175
+ const observations = await Promise.all(providers.map(async (provider) => {
176
+ const controller = new AbortController();
177
+ let timer;
178
+ try {
179
+ const value = await Promise.race([
180
+ Promise.resolve().then(() => provider.read(freeze(JSON.parse(JSON.stringify(core))), controller.signal)),
181
+ new Promise((_, reject) => {
182
+ timer = setTimeout(() => { controller.abort(); reject(new Error("timeout")); }, timeoutMs);
183
+ })
184
+ ]);
185
+ if (!["known", "partial", "unknown"].includes(value.coverage)
186
+ || Buffer.byteLength(JSON.stringify(value)) > MAX_VALUE_BYTES)
187
+ throw new Error("unbounded observation");
188
+ return { source: provider.source.slice(0, 200), observedAt: new Date().toISOString(),
189
+ coverage: value.coverage, status: "available", value: JSON.parse(JSON.stringify(value.value)) };
190
+ }
191
+ catch {
192
+ return { source: provider.source.slice(0, 200), observedAt: new Date().toISOString(),
193
+ coverage: "unknown", status: "unavailable" };
194
+ }
195
+ finally {
196
+ if (timer !== undefined)
197
+ clearTimeout(timer);
198
+ controller.abort();
199
+ }
200
+ }));
201
+ return { ...core, observations };
202
+ }
203
+ function authorizeContext(store, taskId, environment) {
204
+ const caller = resolveManagedTaskReader(store, environment);
205
+ if (caller !== undefined && caller.taskId !== taskId)
206
+ throw usageError("Context is outside the caller's Task.");
207
+ if (caller === undefined && environment.YUI_SESSION_SCOPE === "global" && environment.YUI_ROLE !== "operator") {
208
+ throw usageError("Only Operator may read Task context from a global Session.");
209
+ }
210
+ if (caller === undefined && environment.YUI_SESSION_SCOPE === undefined
211
+ && (environment.YUI_ROLE !== undefined || environment.YUI_NATIVE_SESSION_ID !== undefined
212
+ || environment.YUI_TASK_ID !== undefined || environment.YUI_AGENT_ID !== undefined)) {
213
+ throw usageError("Incomplete managed Context caller identity.");
214
+ }
215
+ if (environment.YUI_SESSION_SCOPE !== undefined && !["task", "global"].includes(environment.YUI_SESSION_SCOPE)) {
216
+ throw usageError("Incomplete managed Context caller identity.");
217
+ }
218
+ const task = store.getTask(taskId);
219
+ if (task === null)
220
+ throw taskNotFound(taskId);
221
+ let allow;
222
+ if (caller !== undefined && caller.roleName !== "leader") {
223
+ if (caller.currentRunId === undefined)
224
+ throw usageError("A managed Role needs a current AgentRun to read its scoped Context.");
225
+ const pack = buildRunContextPack(store, taskId, caller.currentRunId);
226
+ allow = new Set(pack.authority.readableRefs.map((ref) => `${ref.store}:${ref.refId}`));
227
+ allow.add(`role:${caller.roleName}`);
228
+ allow.add(`turn:${caller.currentRunId}`);
229
+ // A frozen Assignment is not a cutoff for the Task's current user intent.
230
+ // Untargeted human/Operator messages are shared Task requirements; scoped
231
+ // messages and other Roles' results still require the Assignment's refs.
232
+ const sharedMessageIds = new Set(store.listMessages(taskId)
233
+ .filter(message => (message.kind === "user" || message.kind === "operator")
234
+ && message.recipient === undefined && message.workItemId === undefined
235
+ && message.runId === undefined)
236
+ .map(message => message.id));
237
+ for (const id of sharedMessageIds)
238
+ allow.add(`task-message:${id}`);
239
+ for (const event of store.listEvents(taskId)) {
240
+ if (event.type.startsWith("message.") && sharedMessageIds.has(event.payload.messageId)) {
241
+ allow.add(`task-event:${event.id}`);
242
+ }
243
+ }
244
+ }
245
+ return { task, allow, caller };
246
+ }
247
+ function isAllowed(allow, family, id) {
248
+ return allow === undefined || allow.has(`${family}:${id}`);
249
+ }
250
+ function roleProfile(role) {
251
+ return {
252
+ name: role.name, defaultAccess: role.defaultAccess, description: role.description,
253
+ responsibilities: role.responsibilities ?? [], constraints: role.constraints ?? [],
254
+ skills: role.skills ?? [], launchRevision: role.launchRevision
255
+ };
256
+ }
257
+ /** Resolve just the requested family. Families without a singular Store read
258
+ * use their existing list primitive, without constructing unrelated Context.
259
+ */
260
+ function inspectValue(store, { task, allow, caller }, { store: family, refId }) {
261
+ const taskId = task.id;
262
+ switch (family) {
263
+ case "task": return refId === taskId ? task : null;
264
+ case "task-brief": return refId === taskId ? store.getTaskBrief(taskId) : null;
265
+ case "role": return store.getRole(taskId, refId);
266
+ case "role-profile": {
267
+ const role = store.getRole(taskId, refId);
268
+ return role === null ? null : roleProfile(role);
269
+ }
270
+ case "project-policy":
271
+ case "project-knowledge": {
272
+ const binding = task.projectBindings.find(({ projectId }) => family === "project-policy"
273
+ ? projectId === refId : refId.startsWith(`${projectId}:`));
274
+ if (binding === undefined)
275
+ return null;
276
+ const project = store.getProject(binding.projectId);
277
+ if (project === null)
278
+ return null;
279
+ const { knowledge, ...policy } = project;
280
+ if (family === "project-policy")
281
+ return policy;
282
+ const entry = knowledge.find((item) => item.status === "active" && `${project.id}:${item.id}` === refId);
283
+ return entry === undefined ? null : { projectId: project.id, ...entry };
284
+ }
285
+ case "input-request": return store.getInputRequest(taskId, refId);
286
+ case "work-item": return store.getWorkItem(taskId, refId);
287
+ case "accepted-work-item":
288
+ return allow?.has(`accepted-work-item:${refId}`) ? store.getWorkItem(taskId, refId) : null;
289
+ case "candidate": {
290
+ const parts = refId.split("/");
291
+ if (parts.length !== 2)
292
+ return null;
293
+ return store.getWorkItem(taskId, parts[0])?.candidates
294
+ .find((candidate) => candidate.id === parts[1]) ?? null;
295
+ }
296
+ case "task-message": return store.listMessages(taskId).find((message) => message.id === refId) ?? null;
297
+ case "run": return store.getRun(taskId, refId);
298
+ case "source-run": {
299
+ if (!allow?.has(`source-turn:${refId}`))
300
+ return null;
301
+ const run = store.getRun(taskId, refId);
302
+ return run === null ? null : sourceRunContextValue(run);
303
+ }
304
+ case "review-round": return store.getReviewRound(taskId, refId);
305
+ case "artifact": return store.getArtifact(taskId, refId);
306
+ case "environment-preparation": return store.getEnvironmentPreparation(taskId, refId);
307
+ case "change-set": return store.getChangeSet(taskId, refId);
308
+ case "managed-workspace": {
309
+ // Existing frozen AgentRun overlays use the Task/Role alias; owner keys
310
+ // identify the durable workspace in current Task reads.
311
+ if (caller?.currentRunId !== undefined && refId === `${taskId}/${caller.roleName}`) {
312
+ return store.getRun(taskId, caller.currentRunId)?.workspace ?? null;
313
+ }
314
+ return store.listManagedWorkspaces(taskId)
315
+ .find((workspace) => managedWorkspaceKey(workspace.owner) === refId) ?? null;
316
+ }
317
+ case "mailbox": {
318
+ if (allow !== undefined)
319
+ return null;
320
+ if (refId === "task")
321
+ return store.getWorkMailbox({ kind: "task", taskId });
322
+ const roleName = refId.startsWith("role:") ? refId.slice("role:".length) : undefined;
323
+ return roleName !== undefined && store.getRole(taskId, roleName) !== null
324
+ ? store.getWorkMailbox({ kind: "role", taskId, roleName }) : null;
325
+ }
326
+ case "task-decision": return store.getDecision(taskId, refId);
327
+ case "task-milestone": return store.getMilestone(taskId, refId);
328
+ case "job": return store.getDurableJob(taskId, refId);
329
+ case "publication": return store.listPublicationReferences(taskId).find((item) => item.id === refId) ?? null;
330
+ case "task-event": return store.listEvents(taskId).find((event) => event.id === refId) ?? null;
331
+ default: return null;
332
+ }
333
+ }
334
+ function authorizedEntries(store, taskId, environment) {
335
+ const { task, allow, caller } = authorizeContext(store, taskId, environment);
336
+ const entries = [];
337
+ const add = (family, id, value) => {
338
+ if (value !== null && isAllowed(allow, family, id)) {
339
+ entries.push(materialize(family, id, value));
340
+ }
341
+ };
342
+ add("task", taskId, task);
343
+ add("task-brief", taskId, store.getTaskBrief(taskId));
344
+ for (const role of store.listRoles(taskId)) {
345
+ add("role", role.name, role);
346
+ add("role-profile", role.name, roleProfile(role));
347
+ }
348
+ for (const binding of task.projectBindings) {
349
+ const project = store.getProject(binding.projectId);
350
+ if (project === null)
351
+ continue;
352
+ const { knowledge, ...policy } = project;
353
+ add("project-policy", project.id, policy);
354
+ for (const entry of knowledge.filter((k) => k.status === "active")) {
355
+ add("project-knowledge", `${project.id}:${entry.id}`, { projectId: project.id, ...entry });
356
+ }
357
+ }
358
+ // Current responsibilities and unanswered inputs precede historical bulk.
359
+ for (const request of store.listInputRequests(taskId).filter((r) => r.status === "open"))
360
+ add("input-request", request.id, request);
361
+ for (const item of store.listWorkItems(taskId).sort((a, b) => b.updatedAt.localeCompare(a.updatedAt))) {
362
+ add("work-item", item.id, item);
363
+ if (allow?.has(`accepted-work-item:${item.id}`))
364
+ add("accepted-work-item", item.id, item);
365
+ for (const candidate of [...item.candidates].reverse())
366
+ add("candidate", `${item.id}/${candidate.id}`, candidate);
367
+ }
368
+ for (const artifact of store.listArtifacts(taskId))
369
+ add("artifact", artifact.id, artifact);
370
+ for (const preparation of store.listEnvironmentPreparations(taskId))
371
+ add("environment-preparation", preparation.id, preparation);
372
+ for (const workspace of store.listManagedWorkspaces(taskId))
373
+ add("managed-workspace", managedWorkspaceKey(workspace.owner), workspace);
374
+ if (caller?.currentRunId !== undefined) {
375
+ add("managed-workspace", `${taskId}/${caller.roleName}`, store.getRun(taskId, caller.currentRunId)?.workspace ?? null);
376
+ }
377
+ for (const changeSet of store.listChangeSets(taskId))
378
+ add("change-set", changeSet.id, changeSet);
379
+ for (const message of store.listMessages(taskId).reverse())
380
+ add("task-message", message.id, message);
381
+ for (const run of store.listRuns(taskId).reverse()) {
382
+ add("run", run.id, run);
383
+ if (allow?.has(`source-turn:${run.id}`))
384
+ add("source-run", run.id, sourceRunContextValue(run));
385
+ }
386
+ for (const round of store.listReviewRounds(taskId).reverse())
387
+ add("review-round", round.id, round);
388
+ for (const request of store.listInputRequests(taskId).filter((r) => r.status !== "open"))
389
+ add("input-request", request.id, request);
390
+ if (allow === undefined) {
391
+ add("mailbox", "task", store.getWorkMailbox({ kind: "task", taskId }));
392
+ for (const role of store.listRoles(taskId)) {
393
+ add("mailbox", `role:${role.name}`, store.getWorkMailbox({ kind: "role", taskId, roleName: role.name }));
394
+ }
395
+ }
396
+ for (const decision of store.listDecisions(taskId))
397
+ add("task-decision", decision.id, decision);
398
+ for (const milestone of store.listMilestones(taskId))
399
+ add("task-milestone", milestone.id, milestone);
400
+ for (const job of store.listDurableJobs(taskId))
401
+ add("job", job.id, job);
402
+ for (const publication of store.listPublicationReferences(taskId))
403
+ add("publication", publication.id, publication);
404
+ for (const event of store.listEvents(taskId).reverse())
405
+ add("task-event", event.id, event);
406
+ return entries;
407
+ }
408
+ function materialize(store, refId, value) {
409
+ const digest = contextContentDigest(value);
410
+ const record = value;
411
+ return { ref: { store, refId, revision: String(record.revision ?? record.updatedAt ?? record.createdAt ?? digest), digest }, value };
412
+ }
413
+ function currentCursor(store, taskId, events = store.listEvents(taskId)) {
414
+ return { taskId, sequence: events.reduce((max, e) => Math.max(max, sequence(e.id)), 0), revision: store.getStateRevision() };
415
+ }
416
+ function sequence(id) {
417
+ const result = /^event-(\d+)$/.exec(id);
418
+ if (result === null || !Number.isSafeInteger(Number(result[1])))
419
+ throw usageError("Task event has an invalid sequence.");
420
+ return Number(result[1]);
421
+ }
422
+ function encode(value) {
423
+ return Buffer.from(JSON.stringify(value)).toString("base64url");
424
+ }
425
+ function decode(value, taskId) {
426
+ try {
427
+ if (value.length > 1024)
428
+ throw new Error("size");
429
+ const cursor = JSON.parse(Buffer.from(value, "base64url").toString());
430
+ if (cursor.taskId !== taskId || !Number.isSafeInteger(cursor.sequence) || cursor.sequence < 0
431
+ || !Number.isSafeInteger(cursor.revision) || cursor.revision < 0)
432
+ throw new Error("shape");
433
+ return cursor;
434
+ }
435
+ catch {
436
+ throw usageError("Invalid Context cursor for this Task.");
437
+ }
438
+ }
439
+ function decodePage(value, taskId) {
440
+ const cursor = decode(value, taskId);
441
+ if (!Number.isSafeInteger(cursor.after) || cursor.after < 0)
442
+ throw usageError("Invalid Context continuation.");
443
+ return cursor;
444
+ }
445
+ function freeze(value) {
446
+ if (value !== null && typeof value === "object") {
447
+ for (const entry of Object.values(value))
448
+ freeze(entry);
449
+ Object.freeze(value);
450
+ }
451
+ return value;
452
+ }
453
+ function summarize(value) {
454
+ const record = value;
455
+ return ["title", "objective", "summary", "body", "status"]
456
+ .flatMap((key) => typeof record[key] === "string" ? [`${key}: ${record[key]}`] : [])
457
+ .join("; ").slice(0, 400);
458
+ }
@@ -10,7 +10,7 @@ import { operationalTaskRecords } from "../task/taskRecordRetirement.js";
10
10
  * `yui task wake show <wake-id>` and the full projection with
11
11
  * `yui task context <task>`.
12
12
  *
13
- * The envelope is mode-agnostic: fresh generations and resumed generations
13
+ * The envelope is mode-agnostic: fresh Sessions and resumed Sessions
14
14
  * receive the same minimal text. The native Session is a disposable cache of
15
15
  * working context; Yui's durable Task records (including the wake ledger) are
16
16
  * the checkpoint.
@@ -29,19 +29,19 @@ export function buildTaskWakeEnvelope(reader, request) {
29
29
  const fromTime = Date.parse(request.fromCursor);
30
30
  const events = reader.listEvents(request.taskId);
31
31
  const deltaEvents = events.filter((record) => Date.parse(record.createdAt) > fromTime);
32
- const turns = operationalTaskRecords(reader.listTurns(request.taskId), events, "turn");
33
- const referencedTurnIds = referencedWakeTurnIds(turns, events, deltaEvents);
34
- const changedTurnIds = new Set([
35
- ...turns
32
+ const runs = operationalTaskRecords(reader.listRuns(request.taskId), events, "run");
33
+ const referencedRunIds = referencedWakeRunIds(runs, events, deltaEvents);
34
+ const changedRunIds = new Set([
35
+ ...runs
36
36
  .filter((record) => Date.parse(record.createdAt) > fromTime)
37
37
  .map(({ id }) => id),
38
- ...referencedTurnIds
38
+ ...referencedRunIds
39
39
  ]);
40
40
  const counts = {
41
41
  events: deltaEvents.length,
42
42
  messages: operationalTaskRecords(reader.listMessages(request.taskId), events, "message")
43
43
  .filter((record) => Date.parse(record.createdAt) > fromTime).length,
44
- turns: changedTurnIds.size
44
+ runs: changedRunIds.size
45
45
  };
46
46
  const activeReviews = reader.listReviewRounds(request.taskId).filter((round) => ((round.scope ?? "work-item") === "task"
47
47
  && (round.status === "pending" || round.status === "running")));
@@ -54,14 +54,14 @@ export function buildTaskWakeEnvelope(reader, request) {
54
54
  + `@${heads || round.reviewBaseCommit.slice(0, 12)}`
55
55
  + `${projects.length > 2 ? `+${projects.length - 2}` : ""}`;
56
56
  }).join(", ");
57
- const render = (reasonLimit, resultTurnLimit, reviewLimit) => {
57
+ const render = (reasonLimit, resultRunLimit, reviewLimit) => {
58
58
  const reviewOrientation = renderReviewOrientation(reviewLimit);
59
59
  return [
60
60
  `Wake: ${request.wakeId} — delta since ${request.fromCursor}`,
61
61
  ` Reasons: ${renderReasons(request.reasons, reasonLimit)}`,
62
- ` Changed: ${counts.events} events, ${counts.messages} messages, ${counts.turns} Turns`
62
+ ` Changed: ${counts.events} events, ${counts.messages} messages, ${counts.runs} AgentRuns`
63
63
  + ` → yui task wake show ${request.taskId} ${request.wakeId}`,
64
- ` Result Turns: ${renderResultTurns(request.taskId, referencedTurnIds, resultTurnLimit)}`,
64
+ ` Result AgentRuns: ${renderResultRuns(request.taskId, referencedRunIds, resultRunLimit)}`,
65
65
  ` Active Task Reviews: ${activeReviews.length === 0
66
66
  ? "none"
67
67
  : reviewLimit === 0
@@ -73,19 +73,19 @@ export function buildTaskWakeEnvelope(reader, request) {
73
73
  ].join("\n");
74
74
  };
75
75
  let reasonLimit = Math.min(REASON_DISPLAY_LIMIT, request.reasons.length);
76
- let resultTurnLimit = Math.min(4, referencedTurnIds.length);
76
+ let resultRunLimit = Math.min(4, referencedRunIds.length);
77
77
  let reviewLimit = Math.min(3, activeReviews.length);
78
- let body = render(reasonLimit, resultTurnLimit, reviewLimit);
78
+ let body = render(reasonLimit, resultRunLimit, reviewLimit);
79
79
  while (byteLength(body) + 1 > WAKE_ENVELOPE_HARD_BYTES) {
80
- if (resultTurnLimit > 0)
81
- resultTurnLimit -= 1;
80
+ if (resultRunLimit > 0)
81
+ resultRunLimit -= 1;
82
82
  else if (reasonLimit > 0)
83
83
  reasonLimit -= 1;
84
84
  else if (reviewLimit > 0)
85
85
  reviewLimit -= 1;
86
86
  else
87
87
  break;
88
- body = render(reasonLimit, resultTurnLimit, reviewLimit);
88
+ body = render(reasonLimit, resultRunLimit, reviewLimit);
89
89
  }
90
90
  if (byteLength(body) + 1 > WAKE_ENVELOPE_HARD_BYTES) {
91
91
  body = fitUtf8([
@@ -99,18 +99,18 @@ export function buildTaskWakeEnvelope(reader, request) {
99
99
  taskId: request.taskId,
100
100
  wakeId: request.wakeId,
101
101
  fromCursor: request.fromCursor,
102
- referencedTurnIds: Object.freeze(referencedTurnIds),
102
+ referencedRunIds: Object.freeze(referencedRunIds),
103
103
  totalBytes,
104
104
  text: `${body}\n`
105
105
  });
106
106
  }
107
- export function referencedWakeTurnIds(turns, allEvents, terminalEvents) {
108
- const turnsById = new Map(operationalTaskRecords(turns, allEvents, "turn").map((turn) => [turn.id, turn]));
107
+ export function referencedWakeRunIds(runs, allEvents, terminalEvents) {
108
+ const turnsById = new Map(operationalTaskRecords(runs, allEvents, "run").map((run) => [run.id, run]));
109
109
  return [...new Set(terminalEvents.flatMap((event) => {
110
- if (!["turn.completed", "turn.failed", "turn.cancelled"].includes(event.type))
110
+ if (!["run.completed", "run.failed", "run.cancelled"].includes(event.type))
111
111
  return [];
112
- const turnId = event.payload.turnId;
113
- return turnId !== undefined && turnsById.has(turnId) ? [turnId] : [];
112
+ const runId = event.payload.runId;
113
+ return runId !== undefined && turnsById.has(runId) ? [runId] : [];
114
114
  }))];
115
115
  }
116
116
  function renderReasons(reasons, limit) {
@@ -121,14 +121,14 @@ function renderReasons(reasons, limit) {
121
121
  const rendered = selected.map(renderWakeReason).join(", ");
122
122
  return elided === 0 ? rendered : `${rendered}, … (+${elided} more)`;
123
123
  }
124
- function renderResultTurns(taskId, turnIds, limit) {
125
- if (turnIds.length === 0)
124
+ function renderResultRuns(taskId, runIds, limit) {
125
+ if (runIds.length === 0)
126
126
  return "none";
127
127
  if (limit === 0)
128
- return `${turnIds.length} → inspect the wake delta`;
129
- return `${turnIds.slice(0, limit)
130
- .map((turnId) => `${turnId} → yui task turn show ${taskId}/${turnId}`)
131
- .join(", ")}${turnIds.length > limit ? `, … (+${turnIds.length - limit})` : ""}`;
128
+ return `${runIds.length} → inspect the wake delta`;
129
+ return `${runIds.slice(0, limit)
130
+ .map((runId) => `${runId} → yui task run show ${taskId}/${runId}`)
131
+ .join(", ")}${runIds.length > limit ? `, … (+${runIds.length - limit})` : ""}`;
132
132
  }
133
133
  function fitUtf8(value, maxBytes) {
134
134
  let fitted = "";