@zq-silk/yui 2.20.0 → 2.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/README.md +5 -0
  2. package/dist/cli/commandCatalog.js +88 -28
  3. package/dist/cli/dynamicCompletion.js +4 -1
  4. package/dist/cli/helpRenderer.js +12 -1
  5. package/dist/cli/interactionPolicy.js +2 -0
  6. package/dist/cli/invocationAuthority.js +2 -6
  7. package/dist/cli/invocationRouter.js +5 -5
  8. package/dist/cli/managedDiagnostics.js +24 -16
  9. package/dist/cli/roleWizard.js +5 -1
  10. package/dist/commands/durableJobCommands.js +2 -3
  11. package/dist/commands/globalRoleCommands.js +33 -8
  12. package/dist/commands/inboxCommands.js +39 -12
  13. package/dist/commands/operatorCommands.js +2 -5
  14. package/dist/commands/releaseCommands.js +16 -2
  15. package/dist/commands/roleConfiguration.js +25 -2
  16. package/dist/commands/sessionCommands.js +5 -2
  17. package/dist/commands/taskCommands.js +225 -99
  18. package/dist/commands/taskContextCommand.js +26 -4
  19. package/dist/commands/taskFactCommands.js +20 -7
  20. package/dist/commands/taskIntegrationCommands.js +3 -3
  21. package/dist/commands/taskRoleRuntimeStatus.js +15 -5
  22. package/dist/commands/taskUsageCommand.js +2 -6
  23. package/dist/commands/textInput.js +2 -2
  24. package/dist/context/contextFamilies.js +10 -0
  25. package/dist/context/currentSkills.js +6 -4
  26. package/dist/context/runContextPack.js +44 -5
  27. package/dist/context/runInputContract.js +1 -1
  28. package/dist/context/sessionBootstrapManifest.js +7 -5
  29. package/dist/context/sessionSkillNotice.js +53 -0
  30. package/dist/context/taskCatalog.js +4 -13
  31. package/dist/context/taskContext.js +135 -103
  32. package/dist/context/taskSearch.js +3 -7
  33. package/dist/controlPlaneCli.js +23 -25
  34. package/dist/controller/agentRuntimeObserver.js +57 -12
  35. package/dist/controller/clientRuntime.js +37 -8
  36. package/dist/controller/controller.js +3 -1
  37. package/dist/controller/diagnosticJournal.js +10 -2
  38. package/dist/controller/fileSchedulerStoreAdapter.js +72 -24
  39. package/dist/controller/jobClient.js +2 -2
  40. package/dist/controller/jobControl.js +2 -2
  41. package/dist/controller/jobDefinitionControl.js +5 -1
  42. package/dist/controller/messageHealth.js +4 -3
  43. package/dist/controller/providerRetryAdmission.js +15 -1
  44. package/dist/controller/providerRetryDelivery.js +18 -2
  45. package/dist/controller/runtime.js +15 -5
  46. package/dist/controller/runtimeEventInbox.js +107 -13
  47. package/dist/controller/runtimeEventProcessor.js +3 -3
  48. package/dist/controller/taskRunRecovery.js +153 -0
  49. package/dist/core/controllerClient.js +16 -2
  50. package/dist/core/controllerServer.js +14 -5
  51. package/dist/core/controllerTelemetry.js +51 -5
  52. package/dist/errors/cliFailure.js +14 -5
  53. package/dist/executor/agentAdapter.js +32 -4
  54. package/dist/executor/agentConfigurationFields.js +2 -0
  55. package/dist/executor/taskAgentCapabilities.js +2 -2
  56. package/dist/integration/gitIntegrationService.js +3 -2
  57. package/dist/integration/integrationSourceApplication.js +12 -1
  58. package/dist/interaction/notificationPresentation.js +11 -16
  59. package/dist/interaction/operatorPresentation.js +1 -1
  60. package/dist/message/messageContinuation.js +3 -1
  61. package/dist/output/boundedRead.js +36 -7
  62. package/dist/output/rolePresentation.js +3 -1
  63. package/dist/runtime/agentHost.js +12 -3
  64. package/dist/runtime/codexAppServerRuntime.js +110 -24
  65. package/dist/runtime/codexInteractiveHost.js +46 -0
  66. package/dist/runtime/providerRetry.js +5 -2
  67. package/dist/runtime/providerRuntimeIdentity.js +1 -1
  68. package/dist/runtime/structuredProviderHost.js +32 -34
  69. package/dist/scheduler/wakeupQueue.js +10 -4
  70. package/dist/storage/sqliteSchema.js +9 -0
  71. package/dist/storage/storageVersions.js +1 -1
  72. package/dist/task/taskAuthority.js +7 -3
  73. package/dist/tmux/tmuxManager.js +4 -2
  74. package/dist/web/webSettings.js +2 -0
  75. package/docs/authorization.md +18 -3
  76. package/docs/cli-information-contract.md +245 -6
  77. package/docs/cli-information-contract.zh-CN.md +107 -5
  78. package/docs/managed-turn-and-session-runtime.md +82 -21
  79. package/docs/managed-turn-and-session-runtime.zh-CN.md +56 -13
  80. package/docs/provider-retry.md +11 -0
  81. package/docs/release-workflow.md +62 -0
  82. package/docs/release-workflow.zh-CN.md +46 -0
  83. package/docs/roles-and-configuration.md +28 -0
  84. package/docs/roles-and-configuration.zh-CN.md +21 -0
  85. package/docs/storage-baseline.md +4 -1
  86. package/docs/storage-baseline.zh-CN.md +1 -1
  87. package/docs/task-delivery.md +7 -0
  88. package/docs/task-delivery.zh-CN.md +5 -0
  89. package/docs/task-discovery.md +5 -5
  90. package/docs/task-discovery.zh-CN.md +4 -4
  91. package/docs/testing/review-evaluation.md +7 -7
  92. package/docs/testing/review-evaluation.zh-CN.md +7 -7
  93. package/docs/testing/verification-levels.md +45 -2
  94. package/docs/testing/verification-levels.zh-CN.md +21 -2
  95. package/i18n/README.zh-CN.md +6 -0
  96. package/package.json +1 -1
  97. package/skills/yui-leader/SKILL.md +98 -189
  98. package/skills/yui-leader/VERSION +1 -1
  99. package/skills/yui-leader/references/artifacts.md +41 -0
  100. package/skills/yui-leader/references/assignment-execution.md +140 -0
  101. package/skills/yui-leader/references/completion.md +79 -0
  102. package/skills/yui-leader/references/delivery-scope.md +26 -0
  103. package/skills/yui-leader/references/execution.md +16 -487
  104. package/skills/yui-leader/references/implementation.md +81 -0
  105. package/skills/yui-leader/references/planning.md +7 -45
  106. package/skills/yui-leader/references/review.md +90 -0
  107. package/skills/yui-leader/references/task-progress.md +23 -0
  108. package/skills/yui-leader/references/work-allocation.md +118 -0
  109. package/skills/yui-operator/SKILL.md +77 -331
  110. package/skills/yui-operator/VERSION +1 -1
  111. package/skills/yui-operator/references/body-transport.md +62 -0
  112. package/skills/yui-operator/references/configuration.md +47 -0
  113. package/skills/yui-operator/references/lifecycle.md +41 -0
  114. package/skills/yui-operator/references/progress.md +39 -0
  115. package/skills/yui-operator/references/routing.md +57 -0
  116. package/skills/yui-operator/references/submission.md +56 -0
  117. package/skills/yui-operator/references/task-delivery.md +5 -2
  118. package/skills/yui-operator/references/web-lifecycle.md +19 -0
  119. package/skills/yui-operator/scripts/verify-submission.mjs +37 -0
  120. package/skills/yui-reviewer/SKILL.md +4 -2
  121. package/skills/yui-reviewer/VERSION +1 -1
  122. package/skills/yui-runtime/SKILL.md +177 -505
  123. package/skills/yui-runtime/VERSION +1 -1
  124. package/skills/yui-runtime/references/archive.md +51 -0
  125. package/skills/yui-runtime/references/command-discovery.md +41 -0
  126. package/skills/yui-runtime/references/completed-followup.md +65 -0
  127. package/skills/yui-runtime/references/context-ordering.md +3 -34
  128. package/skills/yui-runtime/references/context-reads.md +61 -0
  129. package/skills/yui-runtime/references/dispatched-run.md +61 -0
  130. package/skills/yui-runtime/references/execution-failure.md +105 -0
  131. package/skills/yui-runtime/references/global-context.md +18 -0
  132. package/skills/yui-runtime/references/global-input-controls.md +44 -0
  133. package/skills/yui-runtime/references/host-custody.md +30 -0
  134. package/skills/yui-runtime/references/inbox-recovery.md +77 -0
  135. package/skills/yui-runtime/references/incremental-context.md +40 -0
  136. package/skills/yui-runtime/references/publication.md +4 -104
  137. package/skills/yui-runtime/references/recovery.md +32 -192
  138. package/skills/yui-runtime/references/session-identity.md +18 -0
  139. package/skills/yui-runtime/references/session-replacement.md +45 -0
  140. package/skills/yui-runtime/references/uncertain-execution.md +29 -0
  141. package/skills/yui-worker/SKILL.md +7 -4
  142. package/skills/yui-worker/VERSION +1 -1
@@ -8,12 +8,12 @@ import { createRun, runExecutionObservation, runPurposeAdmitsTaskState } from ".
8
8
  import { isGitArtifactRefString, parseGitArtifactRef } from "../artifacts/gitArtifactRef.js";
9
9
  import { contextContentDigest, contextSnapshotRef } from "../context/contextSnapshot.js";
10
10
  import { sourceRunContextValue } from "../context/sourceRunContext.js";
11
- import { buildRunContextDelta, buildRunContextPack, runContextEntry, runContextPointerPage, contextSnapshotDeltaRefIds, expandRunContextRef, freezeReviewStageContextSnapshot, freezeRunContextSnapshot, freezeWorkItemExecutionAssignmentContextSnapshot, freezeCandidateContextSnapshot, readRunContextSnapshot, synthesisSourceRunIds } from "../context/runContextPack.js";
11
+ import { buildRunContextDelta, buildRunContextPack, runContextEntry, runContextPointerPage, contextSnapshotDeltaRefIds, expandRunContextRef, expandRunContextRefs, freezeReviewStageContextSnapshot, freezeRunContextSnapshot, freezeWorkItemExecutionAssignmentContextSnapshot, freezeCandidateContextSnapshot, readRunContextSnapshot, synthesisSourceRunIds } from "../context/runContextPack.js";
12
12
  import { createRunInput } from "../context/runInputContract.js";
13
13
  import { parseTaskCatalogOptions, readTaskCatalog, renderTaskCatalog } from "../context/taskCatalog.js";
14
- import { assertContextRecordReadable, readTaskContextResource } from "../context/taskContext.js";
14
+ import { assertTaskReadable, materialize, parseExactContextRef, readTaskContextResource, resolveContextReader } from "../context/taskContext.js";
15
15
  import { parseTaskSearchOptions, searchTaskBodies } from "../context/taskSearch.js";
16
- import { boundedDocument, readOptions, messageReceipt, recordPage } from "../output/boundedRead.js";
16
+ import { boundedDocument, readOptions, messageReceipt, recordPage, summaryText } from "../output/boundedRead.js";
17
17
  import { referencedWakeRunIds } from "../context/wakeRunReferences.js";
18
18
  import { taskMessagePresentation, wakeChangeLabels, wakeMessages } from "../interaction/notificationPresentation.js";
19
19
  import { completeProcessing, releaseProcessing } from "../coordination/workMailbox.js";
@@ -23,7 +23,7 @@ import { dispatchReviewSynthesis, selectedReviewSynthesisProducers } from "../ex
23
23
  import { createExecutionGroup, createReviewExecutionAssignment, createWorkItemExecutionAssignment, createWorkItemExecutionGroup, updateExecutionLane as updateUnifiedExecutionLane, updateWorkItemExecutionLane, workItemExecutionGroupSettled } from "../execution/workItemExecution.js";
24
24
  import { projectWorkItemExecution } from "../execution/workItemExecutionProjection.js";
25
25
  import { dispatchWorkItemSynthesis, selectedWorkItemSynthesisProducers } from "../execution/workItemMainRun.js";
26
- import { createRoleSessionSet, roleAgentSessionResumeMode, roleSessionControlTarget, updateTaskRoleProviderRuntime } from "../executor/agentExecutor.js";
26
+ import { activeRoleAgentSession, createRoleSessionSet, roleAgentSessionResumeMode, roleSessionControlTarget, updateTaskRoleProviderRuntime } from "../executor/agentExecutor.js";
27
27
  import { resolveEffectiveLaunch, effectiveLaunchWithTaskMainWorkspace } from "../executor/effectiveLaunch.js";
28
28
  import { cancelInputRequest } from "../input/inputRequest.js";
29
29
  import { retireExactActiveRun, terminalizeExactTaskRun, validateExactRunReviewRound } from "../lifecycle/exactRunTerminalization.js";
@@ -46,8 +46,9 @@ import { resolveRecordedTaskFinalReviewContract } from "../review/taskFinalRevie
46
46
  import { copyGlobalRoleToTaskRole, activeRoleAgentBinding, createRole, createRoleAgentBinding, switchActiveRoleAgent, unbindRoleAgent, updateRole } from "../role/role.js";
47
47
  import { roleLaunchEventPayload, saveTaskRoleUpdate } from "../role/taskRoleUpdate.js";
48
48
  import { RUNTIME_SESSION_REPLACE_REQUIRED_REASON, runtimeLifecycleTarget } from "../runtime/lifecycleReservation.js";
49
- import { currentManagedRuntime, resolveManagedTaskReader } from "../runtime/managedCaller.js";
50
- import { controlProviderRetry, providerRunRetry, providerRetryProjection, renderProviderRetry } from "../runtime/providerRetry.js";
49
+ import { currentManagedRuntime } from "../runtime/managedCaller.js";
50
+ import { controlProviderRetry, providerRunRetry, providerRetryProjection, providerRetrySummary, renderProviderRetry } from "../runtime/providerRetry.js";
51
+ import { taskRunRecovery } from "../controller/taskRunRecovery.js";
51
52
  import { currentProviderConversation, transferProviderAuthority } from "../runtime/providerRuntimeIdentity.js";
52
53
  import { projectProviderContinuations } from "../runtime/runtimeContinuationProjection.js";
53
54
  import { runtimeObservationFromTaskEvent } from "../runtime/runtimeObservation.js";
@@ -67,7 +68,7 @@ import { addTaskProjectBinding, archiveTask, completeTask, createTask, reopenTas
67
68
  import { recordTaskActivationRequestInTransaction, taskActivationOperationRef } from "../task/taskActivationService.js";
68
69
  import { assertTaskDeliveryAuthority, assertTaskInputControlAuthority } from "../task/taskAuthority.js";
69
70
  import { resolveTaskRecordReference } from "../task/taskRecordReference.js";
70
- import { createTaskRecordRetirement, isTaskRecordRetired, operationalTaskRecords, taskRecordRetirement } from "../task/taskRecordRetirement.js";
71
+ import { createTaskRecordRetirement, isTaskRecordRetired, operationalTaskRecords, taskRecordRetirement, TASK_RECORD_RETIRED_EVENT } from "../task/taskRecordRetirement.js";
71
72
  import { decideSubmissionRouting, describeSubmissionFeedback, draftActivationState, draftHasEnteredPlanning, normalizeSubmissionIntent, sameSubmissionTarget, TASK_PLANNING_ENTERED_EVENT } from "../task/taskSubmission.js";
72
73
  import { assertWorkItemDependenciesCompleted as assertWorkItemDependencyGate, WorkItemDependencyGateError } from "../workItem/dependencyGate.js";
73
74
  import { attachWorkItemExecutionGroup, createWorkItem, currentWorkItemCandidate, currentWorkItemExecutionGroup, editWorkItemDefinition, prepareWorkItemDispatch, retireWorkItem, submitWorkItemCandidate, updateWorkItemExecutionGroup, updateWorkItemStatus, updateWorkItemWriteProjects, workItemExecutionGroupById } from "../workItem/workItem.js";
@@ -318,7 +319,8 @@ export function runTaskCommand(args, store, options = {}) {
318
319
  || (["brief", "decision", "milestone", "event", "work", "wake", "review", "change-set"].includes(args[0] ?? "")
319
320
  && args[1] === "show")
320
321
  || (args[0] === "role" && (["show", "status"].includes(args[1] ?? "")
321
- || args[1] === "session" && args[2] === "inspect"));
322
+ || args[1] === "session" && (args[2] === "inspect"
323
+ || args[2] === "retry" && (args[5] === undefined || args[5] === "show" || args[5] === "--cursor"))));
322
324
  if (!detail)
323
325
  return executeTaskCommand(args, store, options);
324
326
  const cursorIndex = args.indexOf("--cursor");
@@ -851,7 +853,15 @@ export function submitOperatorMessage(body, taskId, store, options = {}, intent,
851
853
  const header = result.created
852
854
  ? `Created Draft task ${result.task.id}: ${result.task.title}\n`
853
855
  : "";
854
- return `${header}${renderSubmissionFeedback(result.feedback)}`;
856
+ return {
857
+ kind: "output",
858
+ output: `${header}${renderSubmissionFeedback(result.feedback)}`,
859
+ data: {
860
+ taskId: result.task.id,
861
+ message: messageReceipt(result.message),
862
+ submission: result.feedback
863
+ }
864
+ };
855
865
  }
856
866
  function findSubmissionKeyCreate(store, submissionKey) {
857
867
  let otherTarget = false;
@@ -1684,7 +1694,7 @@ function taskMessageCommand(args, store, options) {
1684
1694
  const parsed = readOptions(rest, ["--cursor"]);
1685
1695
  exactPositionals(parsed.positionals, 1, usage);
1686
1696
  const ref = taskRecordReference(parsed.positionals[0], "message", "Message reference", options);
1687
- assertContextRecordReadable(store, ref.taskId, "task-message", ref.localId, options.environment);
1697
+ assertTaskReadable(store, ref.taskId, options.environment);
1688
1698
  const message = store.queryContextRecords(ref.taskId, {
1689
1699
  family: "task-message", ids: [ref.localId], limit: 1
1690
1700
  }).records[0]?.value;
@@ -1702,7 +1712,7 @@ function taskMessageCommand(args, store, options) {
1702
1712
  const parsed = parseTail(rest, new Set(["--body-file", "--intent", "--request-id", "--to", "--work-item", "--review-round"]), usage);
1703
1713
  if (parsed.positionals.length < 1 || parsed.positionals.length > 2)
1704
1714
  throw usageError(usage);
1705
- const body = readCommandText(parsed.positionals[1], parsed.options.get("--body-file"), "--body", usage);
1715
+ const body = readCommandText(parsed.positionals[1], parsed.options.get("--body-file"), "--body", usage, { preserveFileWhitespace: true });
1706
1716
  const intent = parseSubmissionIntentOption(parsed.options.get("--intent"), usage);
1707
1717
  const submissionKey = parsed.options.get("--request-id");
1708
1718
  if (submissionKey !== undefined && submissionKey.trim().length === 0) {
@@ -1771,7 +1781,7 @@ function queueTaskMessage(args, store, options) {
1771
1781
  const parsed = parseTail(args, new Set(["--body-file", "--request-id", "--to", "--work-item", "--review-round"]), usage);
1772
1782
  if (parsed.positionals.length < 1 || parsed.positionals.length > 2)
1773
1783
  throw usageError(usage);
1774
- const body = readCommandText(parsed.positionals[1], parsed.options.get("--body-file"), "--body", usage);
1784
+ const body = readCommandText(parsed.positionals[1], parsed.options.get("--body-file"), "--body", usage, { preserveFileWhitespace: true });
1775
1785
  const requestId = requiredOption(parsed.options, "--request-id");
1776
1786
  const recipientRole = parsed.options.get("--to");
1777
1787
  const workItemId = parsed.options.get("--work-item");
@@ -1808,7 +1818,7 @@ function steerTaskMessage(args, store, options) {
1808
1818
  const parsed = parseTail(args, new Set(["--body-file", "--request-id", "--expected-target", "--to", "--work-item", "--review-round"]), usage);
1809
1819
  if (parsed.positionals.length < 1 || parsed.positionals.length > 2)
1810
1820
  throw usageError(usage);
1811
- const body = readCommandText(parsed.positionals[1], parsed.options.get("--body-file"), "--body", usage);
1821
+ const body = readCommandText(parsed.positionals[1], parsed.options.get("--body-file"), "--body", usage, { preserveFileWhitespace: true });
1812
1822
  const requestId = requiredOption(parsed.options, "--request-id");
1813
1823
  const expectedTarget = requiredOption(parsed.options, "--expected-target");
1814
1824
  const recipientRole = parsed.options.get("--to");
@@ -2084,7 +2094,7 @@ function updateMessage(args, store, options) {
2084
2094
  const parsed = parseTail(args, new Set(["--body-file"]), usage);
2085
2095
  if (parsed.positionals.length < 1 || parsed.positionals.length > 2)
2086
2096
  throw usageError(usage);
2087
- const body = readCommandText(parsed.positionals[1], parsed.options.get("--body-file"), "--body", usage);
2097
+ const body = readCommandText(parsed.positionals[1], parsed.options.get("--body-file"), "--body", usage, { preserveFileWhitespace: true });
2088
2098
  const reference = taskRecordReference(parsed.positionals[0], "message", "Message reference", options);
2089
2099
  const now = clock(options);
2090
2100
  const result = store.transaction((tx) => {
@@ -2507,19 +2517,13 @@ function taskRoleSessionCommand(args, store, options) {
2507
2517
  if (extra.length > 0 || !["show", "cancel", "disable", "enable"].includes(action)) {
2508
2518
  throw usageError("Usage: yui task role session retry <task> <role> [show|cancel|disable|enable]");
2509
2519
  }
2510
- return store.transaction(tx => {
2520
+ return store[action === "show" ? "readTransaction" : "transaction"](tx => {
2511
2521
  const task = requireTask(tx, taskId);
2512
2522
  const role = requireRole(tx, task.id, roleName);
2513
2523
  if (action !== "show")
2514
2524
  taskActor(tx, options, task.id);
2515
- else {
2516
- const reader = resolveManagedTaskReader(tx, options.environment);
2517
- if (reader === undefined)
2518
- taskActor(tx, options, task.id);
2519
- else if (reader.taskId !== task.id || reader.roleName !== "leader" && reader.roleName !== role.name) {
2520
- throw usageError("Provider retry read is outside the caller's Task/Role.");
2521
- }
2522
- }
2525
+ else
2526
+ resolveContextReader(tx, options.environment ?? {});
2523
2527
  const sessions = tx.getTaskRoleSessionSet(task.id, role.name);
2524
2528
  let binding = sessions?.providerBinding ?? null;
2525
2529
  if (action !== "show") {
@@ -2538,12 +2542,7 @@ function taskRoleSessionCommand(args, store, options) {
2538
2542
  exactPositionals(rest, 2, "Task Role Session inspect usage: yui task role session inspect <task> <role>.");
2539
2543
  const task = requireTask(store, rest[0]);
2540
2544
  const role = requireRole(store, task.id, rest[1]);
2541
- const reader = resolveManagedTaskReader(store, options.environment);
2542
- if (reader === undefined)
2543
- taskActor(store, options, task.id);
2544
- else if (reader.taskId !== task.id || (reader.roleName !== "leader" && reader.roleName !== role.name)) {
2545
- throw usageError("Session inspection is outside the caller's Task/Role.");
2546
- }
2545
+ resolveContextReader(store, options.environment ?? {});
2547
2546
  const sessions = store.getTaskRoleSessionSet(task.id, role.name);
2548
2547
  const active = sessions?.sessions[sessions.activeAgentId] ?? null;
2549
2548
  const binding = sessions?.providerBinding ?? null;
@@ -2767,28 +2766,93 @@ function listTaskRoles(args, store, options) {
2767
2766
  return output(`${JSON.stringify(data)}\n`, data);
2768
2767
  }
2769
2768
  function taskRoleStatus(args, store, options) {
2770
- exactPositionals(args, 2, "Task role status usage: yui task role status <task> <role>.");
2771
- const task = requireTask(store, args[0]);
2772
- const role = requireRole(store, task.id, args[1]);
2769
+ const parsed = readOptions(args, ["--view"]);
2770
+ exactPositionals(parsed.positionals, 2, "Task role status usage: yui task role status <task> <role> [--view current|full].");
2771
+ const view = parsed.values.get("--view") ?? "current";
2772
+ if (!["current", "full"].includes(view))
2773
+ throw usageError("Task role status --view must be current or full.");
2774
+ const task = requireTask(store, parsed.positionals[0]);
2775
+ const role = requireRole(store, task.id, parsed.positionals[1]);
2773
2776
  const [status] = inspectTaskRoleRuntimeStatuses(task.id, [role], store, options.runtime?.inspectTaskRolePanes?.(task.id) ?? [], options.now?.() ?? new Date());
2774
2777
  if (status === undefined)
2775
2778
  throw roleNotFound(role.name);
2776
2779
  const observed = withTaskRoleHostObservation(status, options.liveHostObservations?.[role.name]);
2777
- return output(renderTaskRoleRuntimeStatus(observed), { role: observed });
2780
+ if (view === "full")
2781
+ return output(renderTaskRoleRuntimeStatus(observed), { role: observed });
2782
+ // Presentation only: retain the already-computed health, live Host and
2783
+ // uncertain delivery facts. Run/WorkItem originals are not status fields.
2784
+ const currentRun = (run) => run === null ? null : ({
2785
+ id: run.id, taskId: run.taskId, roleName: run.roleName,
2786
+ purpose: run.purpose, mode: run.mode, status: run.status,
2787
+ workItemId: run.workItemId, reviewRoundId: run.reviewRoundId,
2788
+ executionGroupId: run.executionGroupId, executionLaneId: run.executionLaneId,
2789
+ sourceExecutionGroupId: run.sourceExecutionGroupId,
2790
+ createdAt: run.createdAt, updatedAt: run.updatedAt,
2791
+ result: run.result === undefined ? null : {
2792
+ available: run.result.output !== undefined,
2793
+ bytes: run.result.output === undefined ? 0 : Buffer.byteLength(run.result.output),
2794
+ completedAt: run.result.completedAt, failureReason: run.result.failureReason,
2795
+ diagnostic: run.result.diagnostic, provider: run.result.provider,
2796
+ read: `yui task run show ${run.taskId}/${run.id} --view result --json`
2797
+ },
2798
+ read: `yui task run show ${run.taskId}/${run.id} --view full --json`
2799
+ });
2800
+ const session = observed.nativeSession;
2801
+ const work = observed.activeWork;
2802
+ return output(renderTaskRoleRuntimeStatus(observed), { role: {
2803
+ ...observed,
2804
+ activeRun: currentRun(observed.activeRun), lastRun: currentRun(observed.lastRun),
2805
+ activeWork: work === null ? null : {
2806
+ id: work.id, taskId: work.taskId, title: work.title, status: work.status,
2807
+ revision: work.revision, updatedAt: work.updatedAt,
2808
+ read: `yui task work show ${work.taskId}/${work.id} --json`
2809
+ },
2810
+ nativeSession: session === null ? null : {
2811
+ agentId: session.agentId, adapterId: session.adapterId,
2812
+ nativeSessionId: session.nativeSessionId, status: session.status,
2813
+ endReason: session.endReason, policy: session.policy, effective: session.effective,
2814
+ createdAt: session.createdAt, updatedAt: session.updatedAt,
2815
+ read: `yui task role session inspect ${task.id} ${role.name} --json`
2816
+ },
2817
+ execution: observed.execution === undefined ? undefined : {
2818
+ ...observed.execution,
2819
+ retry: observed.execution.retry === null ? null : providerRetrySummary(store.getTaskRoleSessionSet(task.id, role.name)?.providerBinding, `yui task role session retry ${task.id} ${role.name} show --json`)
2820
+ }
2821
+ }, reads: { full: `yui task role status ${task.id} ${role.name} --view full --json` } });
2778
2822
  }
2779
2823
  function showTaskRole(args, store) {
2780
- exactPositionals(args, 2, "Task role show usage: yui task role show <task> <role>.");
2781
- const task = requireTask(store, args[0]);
2782
- const role = requireRole(store, task.id, args[1]);
2824
+ const parsed = readOptions(args, ["--view"]);
2825
+ exactPositionals(parsed.positionals, 2, "Task role show usage: yui task role show <task> <role> [--view current|full].");
2826
+ const view = parsed.values.get("--view") ?? "current";
2827
+ if (!["current", "full"].includes(view))
2828
+ throw usageError("Task role show --view must be current or full.");
2829
+ const task = requireTask(store, parsed.positionals[0]);
2830
+ const role = requireRole(store, task.id, parsed.positionals[1]);
2783
2831
  const sessions = store.getTaskRoleSessionSet(task.id, role.name);
2784
- return output(renderRoleDetails(`Task Role: ${role.name}`, role, {
2785
- kind: "task",
2786
- sessions
2787
- }), {
2832
+ const text = renderRoleDetails(`Task Role: ${role.name}`, role, { kind: "task", sessions });
2833
+ if (view === "full")
2834
+ return output(text, {
2835
+ role,
2836
+ sessions,
2837
+ runs: store.listRuns(task.id).filter((run) => run.roleName === role.name)
2838
+ .map((run) => ({ id: run.id, status: run.status, effective: run.effective }))
2839
+ });
2840
+ const active = activeRoleAgentSession(sessions);
2841
+ return output(text + `\nFull history: yui task role show ${task.id} ${role.name} --view full\n`, {
2788
2842
  role,
2789
- sessions,
2790
- runs: store.listRuns(task.id).filter((run) => run.roleName === role.name)
2791
- .map((run) => ({ id: run.id, status: run.status, effective: run.effective }))
2843
+ observation: "recorded-configuration-not-live-state",
2844
+ session: active === null ? null : {
2845
+ agentId: active.agentId, adapterId: active.adapterId, nativeSessionId: active.nativeSessionId,
2846
+ status: active.status, endReason: active.endReason, policy: active.policy, effective: active.effective,
2847
+ createdAt: active.createdAt, updatedAt: active.updatedAt
2848
+ },
2849
+ // A missing/ended cached Session does not prove retained execution stopped.
2850
+ controlTarget: roleSessionControlTarget(sessions) ?? null,
2851
+ reads: {
2852
+ full: `yui task role show ${task.id} ${role.name} --view full`,
2853
+ session: `yui task role session inspect ${task.id} ${role.name}`,
2854
+ status: `yui task role status ${task.id} ${role.name}`
2855
+ }
2792
2856
  });
2793
2857
  }
2794
2858
  function updateTaskRole(args, store, options) {
@@ -3745,22 +3809,19 @@ export function readDispatchContextRefs(store, taskId, selectors, environment =
3745
3809
  throw usageError("Dispatch requires at most 16 distinct --context-ref values.");
3746
3810
  }
3747
3811
  return selectors.flatMap(selector => {
3748
- const match = /^([^/]+)\/(.+)@([0-9a-f]{64})$/u.exec(selector);
3749
- if (match === null) {
3750
- throw usageError(`Invalid required Context reference: ${selector}. Use store/refId@digest from task context list/inspect.`);
3751
- }
3752
- const [, family, refId, digest] = match;
3812
+ const ref = parseExactContextRef(selector);
3753
3813
  try {
3754
- const entry = readTaskContextResource(store, taskId, {
3755
- store: family, refId: refId, digest: digest
3756
- }, environment);
3814
+ const entry = readTaskContextResource(store, taskId, ref, environment);
3757
3815
  const resources = [{
3758
- ref: { ...entry.ref, layer: "L4", evidenceOf: "dispatch-required" },
3816
+ ref: { ...entry.ref, layer: "L4", evidenceOf: "dispatch-required",
3817
+ ...(ref.store === "task-message" ? {
3818
+ summary: summaryText(`Excerpt: ${entry.value.body}`, 160)
3819
+ } : {}) },
3759
3820
  value: entry.value
3760
3821
  }];
3761
3822
  // Selecting a result Message selects its already-authorized original
3762
3823
  // result too, not just a pointer the receiving Assignment cannot expand.
3763
- if (family === "task-message" && "result" in entry) {
3824
+ if (ref.store === "task-message" && "result" in entry) {
3764
3825
  const message = entry.value;
3765
3826
  const source = store.getRun(taskId, message.resultRef.runId);
3766
3827
  const value = sourceRunContextValue(source);
@@ -4776,18 +4837,34 @@ function retireRun(args, store, options) {
4776
4837
  function runContextCommand(args, store, options) {
4777
4838
  const [first, ...rest] = args;
4778
4839
  if (first === "expand") {
4779
- const usage = "Task run context expand usage: yui task run context expand <task>/<run> <ref-id> --store <store> [--mode full].";
4780
- const parsed = parseTail(rest, new Set(["--store", "--mode", "--cursor"]), usage);
4781
- exactPositionals(parsed.positionals, 2, usage);
4782
- const refStore = requiredOption(parsed.options, "--store");
4840
+ const usage = "Task run context expand usage: yui task run context expand <task>/<run> (<ref-id> --store <store> | --context-ref <store/refId[@digest]> ...) [--mode full] [--cursor <cursor>].";
4841
+ const parsed = parseMultiValueTail(rest, new Set(["--store", "--mode", "--cursor"]), new Set(["--context-ref"]), usage);
4842
+ const batch = parsed.multiOptions.get("--context-ref");
4843
+ if (batch !== undefined && (parsed.positionals.length !== 1 || parsed.options.has("--store")))
4844
+ throw usageError("Do not combine --context-ref with a positional ref-id or --store.", usage);
4845
+ exactPositionals(parsed.positionals, batch === undefined ? 2 : 1, usage);
4846
+ const refStore = batch === undefined ? requiredOption(parsed.options, "--store") : undefined;
4847
+ const refs = batch?.map(selector => {
4848
+ if (/@[0-9a-f]{64}$/u.test(selector))
4849
+ return parseExactContextRef(selector);
4850
+ const match = /^([^/]+)\/(.+)$/u.exec(selector);
4851
+ if (match === null)
4852
+ throw usageError("Run Context reference requires store/refId, optionally followed by @digest.", usage);
4853
+ return { store: match[1], refId: match[2] };
4854
+ });
4783
4855
  const mode = parsed.options.get("--mode");
4784
4856
  if (mode !== undefined && mode !== "full") {
4785
4857
  throw usageError("AgentRun Context expansion mode must be full.", usage);
4786
4858
  }
4787
4859
  const { taskId, runId } = parseRunContextReference(parsed.positionals[0]);
4788
4860
  authorizeRunContext(store, taskId, runId, options.environment);
4789
- const expanded = store.transaction((tx) => expandRunContextRef(tx, taskId, runId, parsed.positionals[1], refStore));
4790
- const data = boundedDocument(expanded, `run:${taskId}/${runId}/${refStore}/${parsed.positionals[1]}`, parsed.options.get("--cursor"));
4861
+ const expanded = store.readTransaction((tx) => refs === undefined
4862
+ ? expandRunContextRef(tx, taskId, runId, parsed.positionals[1], refStore)
4863
+ : expandRunContextRefs(tx, taskId, runId, refs));
4864
+ const source = refs === undefined
4865
+ ? `run:${taskId}/${runId}/${refStore}/${parsed.positionals[1]}`
4866
+ : `run:${taskId}/${runId}/context-batch:${contextContentDigest(refs)}`;
4867
+ const data = boundedDocument(expanded, source, parsed.options.get("--cursor"));
4791
4868
  return output(`${JSON.stringify(data, null, 2)}\n`, { context: data });
4792
4869
  }
4793
4870
  if (first === "delta") {
@@ -4797,7 +4874,7 @@ function runContextCommand(args, store, options) {
4797
4874
  }
4798
4875
  const { taskId, runId } = parseRunContextReference(parsed.positionals[0]);
4799
4876
  authorizeRunContext(store, taskId, runId, options.environment);
4800
- const delta = store.transaction((tx) => (buildRunContextDelta(tx, taskId, runId, parsed.values.get("--after"))));
4877
+ const delta = store.readTransaction((tx) => (buildRunContextDelta(tx, taskId, runId, parsed.values.get("--after"))));
4801
4878
  const data = boundedDocument(delta, `run:${taskId}/${runId}/delta/${parsed.values.get("--after")}`, parsed.cursor);
4802
4879
  return output(`${JSON.stringify(data)}\n`, { contextDelta: data });
4803
4880
  }
@@ -4807,7 +4884,7 @@ function runContextCommand(args, store, options) {
4807
4884
  }
4808
4885
  const { taskId, runId } = parseRunContextReference(first);
4809
4886
  authorizeRunContext(store, taskId, runId, options.environment);
4810
- const pack = store.transaction((tx) => buildRunContextPack(tx, taskId, runId));
4887
+ const pack = store.readTransaction((tx) => buildRunContextPack(tx, taskId, runId));
4811
4888
  const view = parsed.values.get("--view") ?? "current";
4812
4889
  if (!["current", "full", "refs", "input"].includes(view))
4813
4890
  throw usageError("Run Context view must be current, refs, input or full.");
@@ -4823,30 +4900,14 @@ function parseRunContextReference(value) {
4823
4900
  }
4824
4901
  return { taskId, runId };
4825
4902
  }
4826
- /**
4827
- * A AgentRun Context Pack is information the Role's own runtime reads in order to
4828
- * work. Authorization is therefore scope-shaped, not schedule-shaped: the
4829
- * caller must be the current runtime of the Task Role that owns the AgentRun,
4830
- * proven by its per-Session caller key against durable state.
4831
- *
4832
- * It deliberately does not require the AgentRun to still be the active one. An
4833
- * Agent whose AgentRun has advanced must still be able to read the context it was
4834
- * given; losing read access to its own Role's history is what forces an
4835
- * otherwise healthy Agent to stop and escalate to a human.
4836
- */
4903
+ /** Frozen packs are readable evidence. Their execution authority still belongs
4904
+ * exclusively to the dispatched Run; reading does not adopt that identity. */
4837
4905
  function authorizeRunContext(store, taskId, runId, environment) {
4838
- const managed = environment?.YUI_SESSION_SCOPE !== undefined
4839
- || environment?.YUI_TASK_ID !== undefined
4840
- || environment?.YUI_ROLE !== undefined;
4841
- if (!managed)
4842
- return;
4906
+ resolveContextReader(store, environment ?? {});
4843
4907
  const run = store.getRun(taskId, runId);
4844
4908
  if (run === null) {
4845
4909
  throw usageError(`AgentRun Context access is not authorized: ${taskId}/${runId}.`);
4846
4910
  }
4847
- if (currentManagedRuntime(store, environment, taskId, run.roleName) === undefined) {
4848
- throw usageError(`AgentRun Context access requires the current runtime of ${taskId}/${run.roleName}.`);
4849
- }
4850
4911
  }
4851
4912
  function listRuns(args, store, options) {
4852
4913
  const reference = args[0];
@@ -4955,7 +5016,8 @@ function retryRun(args, store, options) {
4955
5016
  const sessions = tx.getTaskRoleSessionSet(previous.taskId, previous.roleName);
4956
5017
  const retry = options.providerRetryChainId !== undefined ? sessions?.providerBinding?.retry
4957
5018
  : sessions?.providerBinding == null ? undefined
4958
- : providerRunRetry(sessions.providerBinding, previous.id, clock(options).getTime());
5019
+ : providerRunRetry(sessions.providerBinding, previous.id, clock(options).getTime())
5020
+ ?? taskRunRecovery(tx, sessions.providerBinding, previous);
4959
5021
  if (options.providerRetryChainId !== undefined
4960
5022
  && (retry?.chainId !== options.providerRetryChainId || retry.status !== "waiting"
4961
5023
  || retry.previousRunId !== previous.id || clock(options).getTime() < Date.parse(retry.nextEligibleAt)
@@ -5789,17 +5851,49 @@ function retryFailedReviewRun(previous, store, options, now) {
5789
5851
  }
5790
5852
  /** AgentRun details are retained audit evidence; continuation uses durable Task state. */
5791
5853
  function showRun(args, store, options) {
5792
- const usage = "Task run show usage: yui task run show <task>/<run> [--json].";
5793
- const parsed = readOptions(args.filter((arg) => arg !== "--json"), ["--cursor"]);
5854
+ const usage = "Task run show usage: yui task run show <task>/<run> [--view full|status|result] [--cursor <cursor>] [--json].";
5855
+ const parsed = readOptions(args.filter((arg) => arg !== "--json"), ["--cursor", "--view"]);
5856
+ const view = parsed.values.get("--view") ?? "full";
5857
+ if (!["full", "status", "result"].includes(view))
5858
+ throw usageError(usage);
5794
5859
  const positionals = parsed.positionals;
5795
5860
  exactPositionals(positionals, 1, usage);
5796
- const data = store.transaction((tx) => {
5861
+ const data = store.readTransaction((tx) => {
5797
5862
  const run = requireRun(tx, positionals[0], options);
5798
- const retirement = tx.listEvents(run.taskId)
5863
+ const events = tx.listEventsByType(run.taskId, [TASK_RECORD_RETIRED_EVENT, "runtime.agent-error"]);
5864
+ const retirement = events
5799
5865
  .map(taskRecordRetirement)
5800
5866
  .find((entry) => entry?.recordKind === "run" && entry.recordId === run.id) ?? null;
5801
- return { run: run, retirement, execution: runExecutionObservation(run, tx.getTaskRoleSessionSet(run.taskId, run.roleName)?.providerBinding, tx.listEvents(run.taskId)) };
5867
+ const binding = tx.getTaskRoleSessionSet(run.taskId, run.roleName)?.providerBinding;
5868
+ const execution = runExecutionObservation(run, binding, events);
5869
+ return { run, retirement, execution: view === "full" ? execution : {
5870
+ ...execution, retry: execution.retry === null ? null : providerRetrySummary(binding, `yui task role session retry ${run.taskId} ${run.roleName} show --json`)
5871
+ } };
5802
5872
  });
5873
+ if (view !== "full") {
5874
+ const { run } = data;
5875
+ const status = {
5876
+ run: {
5877
+ id: run.id, taskId: run.taskId, roleName: run.roleName,
5878
+ purpose: run.purpose, mode: run.mode, status: run.status,
5879
+ workItemId: run.workItemId, reviewRoundId: run.reviewRoundId,
5880
+ createdAt: run.createdAt, updatedAt: run.updatedAt
5881
+ },
5882
+ retirement: data.retirement,
5883
+ execution: data.execution,
5884
+ result: view === "result" ? run.result ?? null : {
5885
+ available: run.result?.output !== undefined,
5886
+ bytes: run.result?.output === undefined ? 0 : Buffer.byteLength(run.result.output),
5887
+ completedAt: run.result?.completedAt,
5888
+ failureReason: run.result?.failureReason,
5889
+ diagnostic: run.result?.diagnostic,
5890
+ read: `yui task run show ${run.taskId}/${run.id} --view result --json`
5891
+ },
5892
+ reads: { full: `yui task run show ${run.taskId}/${run.id} --view full --json` }
5893
+ };
5894
+ const bounded = boundedDocument(status, `run:${run.taskId}/${run.id}:${view}`, parsed.cursor);
5895
+ return output(`${JSON.stringify(bounded, null, 2)}\n`, bounded);
5896
+ }
5803
5897
  const bounded = boundedDocument(data, `run:${data.run.taskId}/${data.run.id}`, parsed.cursor);
5804
5898
  if ("contentPage" in bounded)
5805
5899
  return output(`${JSON.stringify(bounded, null, 2)}\n`, bounded);
@@ -6941,31 +7035,45 @@ function taskWakeDispatch(args, store, options) {
6941
7035
  const target = leaderMailbox(task.id);
6942
7036
  const mailbox = tx.getWorkMailbox(target);
6943
7037
  const claim = mailbox?.processing;
6944
- if (claim === undefined || claim === null || claim.owner !== `leader-notification:${wake.id}`) {
6945
- throw usageError("This wake has no unresolved notification claim.");
7038
+ const ownsClaim = claim?.owner === `leader-notification:${wake.id}`;
7039
+ const events = tx.listEvents(task.id);
7040
+ const resolved = events.find(event => event.type === "notification.resolved"
7041
+ && event.payload.wakeId === wake.id && event.payload.outcome === "released-without-replay");
7042
+ if (resolved !== undefined) {
7043
+ return { taskId: task.id, wakeId: wake.id, outcome: "released-without-replay" };
7044
+ }
7045
+ if (wake.status === "consumed")
7046
+ throw usageError("An accepted notification uses ordinary inbox handling.");
7047
+ // Operational mailboxes may disappear on execution stop. Resolve only
7048
+ // the original durable delivery attempt, using the same exact wake
7049
+ // identity as wake inspection; missing evidence is not an unknown result.
7050
+ const previous = events.filter(event => event.type === "notification.delivery"
7051
+ && (ownsClaim ? event.payload.attemptId === claim.batchId
7052
+ : event.payload.attemptId?.startsWith(`notification:${task.id}/${wake.id}/`))).at(-1);
7053
+ if (previous?.payload.outcome !== "unknown" && previous?.payload.outcome !== "rejected") {
7054
+ throw usageError("Only an unknown or rejected notification can be resolved without replay.");
6946
7055
  }
6947
- const previous = tx.listEvents(task.id).filter((event) => event.type === "notification.delivery" && event.payload.attemptId === claim.batchId).at(-1);
6948
7056
  const sessions = tx.getTaskRoleSessionSet(task.id, "leader");
6949
7057
  const provider = sessions?.providerBinding;
6950
- if (previous?.payload.outcome !== "unknown")
6951
- throw usageError("Only an unknown notification can be resolved.");
6952
7058
  if (tx.getActiveRun(task.id, "leader") !== null
6953
7059
  || provider?.authority.owner === "human" || provider?.authority.owner === "unknown"
6954
7060
  || (provider?.run !== undefined && provider.run !== null
6955
7061
  && ["submitting", "accepted", "delivery-unknown"].includes(provider.run.status))) {
6956
7062
  throw usageError("Shared native execution is not proven quiescent; resolve that exact runtime boundary first.");
6957
7063
  }
6958
- // Preserve the original unknown outcome and the unconsumed fixed wake.
7064
+ // Rejection is not quiescence. Preserve every original delivery outcome
7065
+ // (including unknown followed by rejected) and the unconsumed fixed wake.
6959
7066
  // This releases only the scheduling claim; it never replays, claims
6960
7067
  // acceptance, or asserts that Message requirements were implemented.
6961
7068
  recordTaskEvent(tx, task.id, "notification.resolved", {
6962
- wakeId: wake.id, attemptId: claim.batchId, reason, outcome: "released-without-replay"
7069
+ wakeId: wake.id, attemptId: previous.payload.attemptId, reason, outcome: "released-without-replay"
6963
7070
  }, now);
6964
- tx.saveWorkMailbox(completeProcessing(mailbox, claim.batchId));
7071
+ if (ownsClaim)
7072
+ tx.saveWorkMailbox(completeProcessing(mailbox, claim.batchId));
6965
7073
  return { taskId: task.id, wakeId: wake.id, outcome: "released-without-replay" };
6966
7074
  });
6967
7075
  notifyMailbox(options.runtime, leaderMailbox(result.taskId));
6968
- return output(`Released ${result.wakeId} without replay; original acceptance remains unknown.\n`, result);
7076
+ return output(`Released ${result.wakeId} without replay; original delivery evidence is unchanged.\n`, result);
6969
7077
  }
6970
7078
  if (subcommand === "list" || subcommand === "show") {
6971
7079
  return taskWakeInspectionCommand(args, store);
@@ -6980,7 +7088,7 @@ function taskWakeDispatch(args, store, options) {
6980
7088
  * wake — the on-demand read the Agent uses instead of a context dump in the
6981
7089
  * wake envelope.
6982
7090
  */
6983
- function taskWakeInspectionCommand(args, store) {
7091
+ export function taskWakeInspectionCommand(args, store) {
6984
7092
  const [command, ...rest] = args;
6985
7093
  if (command === "list") {
6986
7094
  const usage = "Task wake list usage: yui task wake list <task> [--limit <n>] [--cursor <cursor>].";
@@ -7043,6 +7151,26 @@ function taskWakeInspectionCommand(args, store) {
7043
7151
  if (message.resultRef?.type === "agent-run-result")
7044
7152
  referencedRunIds.add(message.resultRef.runId);
7045
7153
  const runs = operationalTaskRecords(allRuns, allEvents, "run").filter((run) => (history && inWindow(run.createdAt) || referencedRunIds.has(run.id)));
7154
+ // The focused read is an action working set, not merely another directory.
7155
+ // Include small ordinary originals whole, with their current exact identity.
7156
+ // Reports still require their terminal-result read; a completion notice is
7157
+ // not the original report. Do not amplify diagnostic history into bodies.
7158
+ let originalBytesRemaining = 8 * 1024;
7159
+ const messageDetails = messages.map(message => {
7160
+ const original = materialize("task-message", message.id, message);
7161
+ const bytes = Buffer.byteLength(JSON.stringify(message));
7162
+ const include = !history && message.resultRef === undefined
7163
+ && bytes <= 4 * 1024 && bytes <= originalBytesRemaining;
7164
+ if (include)
7165
+ originalBytesRemaining -= bytes;
7166
+ return { id: message.id, kind: message.kind, author: message.author,
7167
+ ...taskMessagePresentation(message, (taskId, runId) => store.getRun(taskId, runId)),
7168
+ resultRef: message.resultRef,
7169
+ ...(include ? { refreshRead: `task message show ${task.id}/${message.id}` }
7170
+ : { read: `task message show ${task.id}/${message.id}` }),
7171
+ ref: original.ref, contentOmitted: !include,
7172
+ ...(include ? { value: original.value } : {}) };
7173
+ });
7046
7174
  const lines = [
7047
7175
  `Wake: ${wake.id}`,
7048
7176
  `Task: ${task.id}`,
@@ -7090,9 +7218,7 @@ function taskWakeInspectionCommand(args, store) {
7090
7218
  historyRead: `task wake show ${task.id} ${wake.id} --history`,
7091
7219
  events: events.map(event => ({ id: event.id, type: event.type, createdAt: event.createdAt,
7092
7220
  read: `task event show ${task.id} ${event.id}` })),
7093
- messages: messages.map(message => ({ id: message.id, kind: message.kind, author: message.author,
7094
- ...taskMessagePresentation(message, (taskId, runId) => store.getRun(taskId, runId)),
7095
- resultRef: message.resultRef, read: `task message show ${task.id}/${message.id}` })),
7221
+ messages: messageDetails,
7096
7222
  runs: runs.map(run => ({ id: run.id, status: run.status, purpose: run.purpose, roleName: run.roleName,
7097
7223
  read: `task run show ${task.id}/${run.id}` }))
7098
7224
  });
@@ -1,5 +1,5 @@
1
1
  import { usageError } from "../errors/cliError.js";
2
- import { inspectTaskContext, listTaskContext, readTaskContext, readTaskContextDelta } from "../context/taskContext.js";
2
+ import { inspectTaskContext, inspectTaskContextBatch, listTaskContext, parseExactContextRef, readTaskContext, readTaskContextDelta } from "../context/taskContext.js";
3
3
  import { readOptions } from "../output/boundedRead.js";
4
4
  export function taskRecordList(args, store, family, environment = {}) {
5
5
  const parsed = readOptions(args, ["--cursor", "--limit", "--status", "--after", "--work-item"]);
@@ -17,19 +17,23 @@ export function runTaskContextCommand(args, store, environment = {}) {
17
17
  const action = explicit ? args[0] : "read";
18
18
  const taskId = args[explicit ? 1 : 0];
19
19
  if (!taskId || taskId.startsWith("--"))
20
- throw usageError("Task context usage: yui task context [read|list|delta|inspect] <task> [--after <cursor|timestamp>] [--continuation <cursor>] [--cursor <cursor>] [--limit <1..100>] [--store <store> --ref <id> --digest <digest>] [--view <current|all>] [--status <status>] [--work-item <id>].");
20
+ throw usageError("Task context usage: yui task context [read|list|delta|inspect] <task> [--after <cursor|timestamp>] [--continuation <cursor>] [--cursor <cursor>] [--limit <1..100>] [--store <store> --ref <id> --digest <digest> | --refs <JSON-array> | --context-ref <store/refId@digest> ...] [--view <current|all>] [--status <status>] [--work-item <id>].");
21
21
  const options = new Map();
22
+ const contextRefs = [];
22
23
  const rest = args.slice(explicit ? 2 : 1);
23
24
  const allowed = action === "read" ? [] : action === "delta"
24
25
  ? ["--after", "--continuation", "--limit"] : action === "list"
25
- ? ["--store", "--cursor", "--limit", "--status", "--after", "--work-item", "--view"] : ["--store", "--ref", "--digest", "--cursor"];
26
+ ? ["--store", "--cursor", "--limit", "--status", "--after", "--work-item", "--view"] : ["--store", "--ref", "--digest", "--refs", "--context-ref", "--cursor"];
26
27
  for (let i = 0; i < rest.length; i += 2) {
27
28
  const flag = rest[i];
28
29
  const value = rest[i + 1];
29
30
  if (!allowed.includes(flag) || options.has(flag) || value === undefined || value.startsWith("--")) {
30
31
  throw usageError(`Invalid Context option: ${flag}.`);
31
32
  }
32
- options.set(flag, value);
33
+ if (flag === "--context-ref")
34
+ contextRefs.push(value);
35
+ else
36
+ options.set(flag, value);
33
37
  }
34
38
  let data;
35
39
  if (action === "read")
@@ -54,6 +58,24 @@ export function runTaskContextCommand(args, store, environment = {}) {
54
58
  ...(options.has("--limit") ? { limit: Number(options.get("--limit")) } : {})
55
59
  }, environment);
56
60
  }
61
+ else if (options.has("--refs") || contextRefs.length > 0) {
62
+ if (["--store", "--ref", "--digest"].some(flag => options.has(flag)))
63
+ throw usageError("Do not combine batch references with --store, --ref or --digest.");
64
+ if (options.has("--refs") && contextRefs.length > 0)
65
+ throw usageError("Do not combine --refs with --context-ref.");
66
+ let refs;
67
+ if (contextRefs.length > 0)
68
+ refs = contextRefs.map(parseExactContextRef);
69
+ else {
70
+ try {
71
+ refs = JSON.parse(options.get("--refs"));
72
+ }
73
+ catch {
74
+ throw usageError("--refs must be a JSON array of exact Context references.");
75
+ }
76
+ }
77
+ data = inspectTaskContextBatch(store, taskId, refs, options.get("--cursor"), environment);
78
+ }
57
79
  else {
58
80
  const family = options.get("--store");
59
81
  const refId = options.get("--ref");