@zq-silk/yui 2.21.0 → 2.23.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 (145) hide show
  1. package/README.md +5 -0
  2. package/dist/cli/commandCatalog.js +87 -27
  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/invocationRouter.js +5 -5
  7. package/dist/cli/roleWizard.js +5 -1
  8. package/dist/cli/updateCommand.js +20 -3
  9. package/dist/cli/updateOrchestrator.js +13 -0
  10. package/dist/cli/updatePorts.js +27 -0
  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 +217 -64
  18. package/dist/commands/taskContextCommand.js +26 -4
  19. package/dist/commands/taskFactCommands.js +15 -2
  20. package/dist/commands/taskIntegrationCommands.js +3 -3
  21. package/dist/commands/taskRoleRuntimeStatus.js +19 -5
  22. package/dist/commands/textInput.js +2 -2
  23. package/dist/context/contextFamilies.js +10 -0
  24. package/dist/context/currentSkills.js +37 -4
  25. package/dist/context/runContextPack.js +44 -5
  26. package/dist/context/runInputContract.js +1 -1
  27. package/dist/context/sessionBootstrapManifest.js +21 -6
  28. package/dist/context/sessionSkillNotice.js +74 -0
  29. package/dist/context/taskContext.js +100 -16
  30. package/dist/controlPlaneCli.js +17 -7
  31. package/dist/controller/agentRuntimeObserver.js +57 -12
  32. package/dist/controller/clientRuntime.js +66 -18
  33. package/dist/controller/controller.js +19 -2
  34. package/dist/controller/diagnosticJournal.js +10 -2
  35. package/dist/controller/fileSchedulerStoreAdapter.js +74 -24
  36. package/dist/controller/hostLifecycle.js +153 -0
  37. package/dist/controller/hostLifecycleChecks.js +27 -0
  38. package/dist/controller/hostUpgrade.js +344 -0
  39. package/dist/controller/messageHealth.js +4 -3
  40. package/dist/controller/providerRetryAdmission.js +15 -1
  41. package/dist/controller/providerRetryDelivery.js +18 -2
  42. package/dist/controller/runtime.js +82 -21
  43. package/dist/controller/runtimeEventInbox.js +107 -13
  44. package/dist/controller/runtimeEventProcessor.js +3 -3
  45. package/dist/controller/sessionNotify.js +5 -46
  46. package/dist/controller/taskRunRecovery.js +153 -0
  47. package/dist/core/controllerClient.js +16 -2
  48. package/dist/core/controllerServer.js +14 -5
  49. package/dist/core/controllerTelemetry.js +51 -5
  50. package/dist/errors/cliFailure.js +14 -5
  51. package/dist/execution/codexThreadNaming.js +54 -43
  52. package/dist/executor/agentAdapter.js +32 -4
  53. package/dist/executor/agentConfigurationFields.js +2 -0
  54. package/dist/executor/fileRoleLaunchPlanner.js +18 -3
  55. package/dist/integration/gitIntegrationService.js +3 -2
  56. package/dist/integration/integrationSourceApplication.js +12 -1
  57. package/dist/interaction/notificationPresentation.js +11 -16
  58. package/dist/interaction/operatorPresentation.js +1 -1
  59. package/dist/message/messageContinuation.js +3 -1
  60. package/dist/output/boundedRead.js +36 -7
  61. package/dist/output/rolePresentation.js +3 -1
  62. package/dist/runtime/agentEndpoint.js +11 -1
  63. package/dist/runtime/agentEndpointIdentity.js +2 -0
  64. package/dist/runtime/agentHost.js +174 -40
  65. package/dist/runtime/agentHostImplementation.js +3 -1
  66. package/dist/runtime/codexAppServerRuntime.js +113 -24
  67. package/dist/runtime/codexInteractiveHost.js +102 -11
  68. package/dist/runtime/codexNativeAccess.js +1 -1
  69. package/dist/runtime/contextRecovery.js +15 -0
  70. package/dist/runtime/hostSessionLifecycle.js +83 -0
  71. package/dist/runtime/hostUpgradeGate.js +43 -0
  72. package/dist/runtime/lifecycleChecks.js +47 -0
  73. package/dist/runtime/lifecycleReservation.js +9 -1
  74. package/dist/runtime/nativeTitleReceipt.js +31 -0
  75. package/dist/runtime/nativeTitleSync.js +192 -0
  76. package/dist/runtime/providerRetry.js +9 -6
  77. package/dist/runtime/providerRuntimeIdentity.js +1 -1
  78. package/dist/runtime/structuredProviderHost.js +65 -35
  79. package/dist/scheduler/wakeupQueue.js +10 -4
  80. package/dist/storage/sqliteSchema.js +29 -0
  81. package/dist/storage/storageVersions.js +1 -1
  82. package/dist/tmux/tmuxManager.js +4 -2
  83. package/dist/web/webSettings.js +2 -0
  84. package/docs/authorization.md +18 -3
  85. package/docs/cli-information-contract.md +228 -6
  86. package/docs/cli-information-contract.zh-CN.md +95 -5
  87. package/docs/managed-turn-and-session-runtime.md +177 -21
  88. package/docs/managed-turn-and-session-runtime.zh-CN.md +126 -14
  89. package/docs/provider-retry.md +11 -0
  90. package/docs/release-workflow.md +65 -0
  91. package/docs/release-workflow.zh-CN.md +48 -0
  92. package/docs/roles-and-configuration.md +28 -0
  93. package/docs/roles-and-configuration.zh-CN.md +21 -0
  94. package/docs/storage-baseline.md +13 -1
  95. package/docs/storage-baseline.zh-CN.md +5 -1
  96. package/docs/task-delivery.md +7 -0
  97. package/docs/task-delivery.zh-CN.md +5 -0
  98. package/docs/testing/review-evaluation.md +7 -7
  99. package/docs/testing/review-evaluation.zh-CN.md +7 -7
  100. package/docs/testing/verification-levels.md +45 -2
  101. package/docs/testing/verification-levels.zh-CN.md +21 -2
  102. package/i18n/README.zh-CN.md +6 -0
  103. package/package.json +1 -1
  104. package/skills/yui-leader/SKILL.md +98 -193
  105. package/skills/yui-leader/VERSION +1 -1
  106. package/skills/yui-leader/references/artifacts.md +41 -0
  107. package/skills/yui-leader/references/assignment-execution.md +140 -0
  108. package/skills/yui-leader/references/completion.md +79 -0
  109. package/skills/yui-leader/references/delivery-scope.md +26 -0
  110. package/skills/yui-leader/references/execution.md +16 -487
  111. package/skills/yui-leader/references/implementation.md +81 -0
  112. package/skills/yui-leader/references/planning.md +7 -45
  113. package/skills/yui-leader/references/review.md +90 -0
  114. package/skills/yui-leader/references/task-progress.md +23 -0
  115. package/skills/yui-leader/references/work-allocation.md +118 -0
  116. package/skills/yui-operator/SKILL.md +77 -333
  117. package/skills/yui-operator/VERSION +1 -1
  118. package/skills/yui-operator/references/body-transport.md +62 -0
  119. package/skills/yui-operator/references/configuration.md +47 -0
  120. package/skills/yui-operator/references/lifecycle.md +41 -0
  121. package/skills/yui-operator/references/progress.md +39 -0
  122. package/skills/yui-operator/references/routing.md +57 -0
  123. package/skills/yui-operator/references/submission.md +56 -0
  124. package/skills/yui-operator/references/task-delivery.md +1 -1
  125. package/skills/yui-operator/references/web-lifecycle.md +19 -0
  126. package/skills/yui-operator/scripts/verify-submission.mjs +37 -0
  127. package/skills/yui-runtime/SKILL.md +182 -531
  128. package/skills/yui-runtime/VERSION +1 -1
  129. package/skills/yui-runtime/references/archive.md +51 -0
  130. package/skills/yui-runtime/references/command-discovery.md +41 -0
  131. package/skills/yui-runtime/references/completed-followup.md +65 -0
  132. package/skills/yui-runtime/references/context-ordering.md +3 -34
  133. package/skills/yui-runtime/references/context-reads.md +61 -0
  134. package/skills/yui-runtime/references/dispatched-run.md +61 -0
  135. package/skills/yui-runtime/references/execution-failure.md +105 -0
  136. package/skills/yui-runtime/references/global-context.md +18 -0
  137. package/skills/yui-runtime/references/global-input-controls.md +44 -0
  138. package/skills/yui-runtime/references/host-custody.md +30 -0
  139. package/skills/yui-runtime/references/inbox-recovery.md +77 -0
  140. package/skills/yui-runtime/references/incremental-context.md +40 -0
  141. package/skills/yui-runtime/references/publication.md +4 -111
  142. package/skills/yui-runtime/references/recovery.md +32 -192
  143. package/skills/yui-runtime/references/session-identity.md +18 -0
  144. package/skills/yui-runtime/references/session-replacement.md +45 -0
  145. package/skills/yui-runtime/references/uncertain-execution.md +29 -0
@@ -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 { assertTaskReadable, readTaskContextResource, resolveContextReader } 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";
@@ -47,7 +47,8 @@ import { copyGlobalRoleToTaskRole, activeRoleAgentBinding, createRole, createRol
47
47
  import { roleLaunchEventPayload, saveTaskRoleUpdate } from "../role/taskRoleUpdate.js";
48
48
  import { RUNTIME_SESSION_REPLACE_REQUIRED_REASON, runtimeLifecycleTarget } from "../runtime/lifecycleReservation.js";
49
49
  import { currentManagedRuntime } from "../runtime/managedCaller.js";
50
- import { controlProviderRetry, providerRunRetry, providerRetryProjection, renderProviderRetry } from "../runtime/providerRetry.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;
@@ -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,7 +2517,7 @@ 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")
@@ -2756,28 +2766,93 @@ function listTaskRoles(args, store, options) {
2756
2766
  return output(`${JSON.stringify(data)}\n`, data);
2757
2767
  }
2758
2768
  function taskRoleStatus(args, store, options) {
2759
- exactPositionals(args, 2, "Task role status usage: yui task role status <task> <role>.");
2760
- const task = requireTask(store, args[0]);
2761
- 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]);
2762
2776
  const [status] = inspectTaskRoleRuntimeStatuses(task.id, [role], store, options.runtime?.inspectTaskRolePanes?.(task.id) ?? [], options.now?.() ?? new Date());
2763
2777
  if (status === undefined)
2764
2778
  throw roleNotFound(role.name);
2765
2779
  const observed = withTaskRoleHostObservation(status, options.liveHostObservations?.[role.name]);
2766
- 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` } });
2767
2822
  }
2768
2823
  function showTaskRole(args, store) {
2769
- exactPositionals(args, 2, "Task role show usage: yui task role show <task> <role>.");
2770
- const task = requireTask(store, args[0]);
2771
- 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]);
2772
2831
  const sessions = store.getTaskRoleSessionSet(task.id, role.name);
2773
- return output(renderRoleDetails(`Task Role: ${role.name}`, role, {
2774
- kind: "task",
2775
- sessions
2776
- }), {
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`, {
2777
2842
  role,
2778
- sessions,
2779
- runs: store.listRuns(task.id).filter((run) => run.roleName === role.name)
2780
- .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
+ }
2781
2856
  });
2782
2857
  }
2783
2858
  function updateTaskRole(args, store, options) {
@@ -3734,22 +3809,19 @@ export function readDispatchContextRefs(store, taskId, selectors, environment =
3734
3809
  throw usageError("Dispatch requires at most 16 distinct --context-ref values.");
3735
3810
  }
3736
3811
  return selectors.flatMap(selector => {
3737
- const match = /^([^/]+)\/(.+)@([0-9a-f]{64})$/u.exec(selector);
3738
- if (match === null) {
3739
- throw usageError(`Invalid required Context reference: ${selector}. Use store/refId@digest from task context list/inspect.`);
3740
- }
3741
- const [, family, refId, digest] = match;
3812
+ const ref = parseExactContextRef(selector);
3742
3813
  try {
3743
- const entry = readTaskContextResource(store, taskId, {
3744
- store: family, refId: refId, digest: digest
3745
- }, environment);
3814
+ const entry = readTaskContextResource(store, taskId, ref, environment);
3746
3815
  const resources = [{
3747
- 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
+ } : {}) },
3748
3820
  value: entry.value
3749
3821
  }];
3750
3822
  // Selecting a result Message selects its already-authorized original
3751
3823
  // result too, not just a pointer the receiving Assignment cannot expand.
3752
- if (family === "task-message" && "result" in entry) {
3824
+ if (ref.store === "task-message" && "result" in entry) {
3753
3825
  const message = entry.value;
3754
3826
  const source = store.getRun(taskId, message.resultRef.runId);
3755
3827
  const value = sourceRunContextValue(source);
@@ -4765,18 +4837,34 @@ function retireRun(args, store, options) {
4765
4837
  function runContextCommand(args, store, options) {
4766
4838
  const [first, ...rest] = args;
4767
4839
  if (first === "expand") {
4768
- const usage = "Task run context expand usage: yui task run context expand <task>/<run> <ref-id> --store <store> [--mode full].";
4769
- const parsed = parseTail(rest, new Set(["--store", "--mode", "--cursor"]), usage);
4770
- exactPositionals(parsed.positionals, 2, usage);
4771
- 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
+ });
4772
4855
  const mode = parsed.options.get("--mode");
4773
4856
  if (mode !== undefined && mode !== "full") {
4774
4857
  throw usageError("AgentRun Context expansion mode must be full.", usage);
4775
4858
  }
4776
4859
  const { taskId, runId } = parseRunContextReference(parsed.positionals[0]);
4777
4860
  authorizeRunContext(store, taskId, runId, options.environment);
4778
- const expanded = store.transaction((tx) => expandRunContextRef(tx, taskId, runId, parsed.positionals[1], refStore));
4779
- 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"));
4780
4868
  return output(`${JSON.stringify(data, null, 2)}\n`, { context: data });
4781
4869
  }
4782
4870
  if (first === "delta") {
@@ -4786,7 +4874,7 @@ function runContextCommand(args, store, options) {
4786
4874
  }
4787
4875
  const { taskId, runId } = parseRunContextReference(parsed.positionals[0]);
4788
4876
  authorizeRunContext(store, taskId, runId, options.environment);
4789
- 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"))));
4790
4878
  const data = boundedDocument(delta, `run:${taskId}/${runId}/delta/${parsed.values.get("--after")}`, parsed.cursor);
4791
4879
  return output(`${JSON.stringify(data)}\n`, { contextDelta: data });
4792
4880
  }
@@ -4796,7 +4884,7 @@ function runContextCommand(args, store, options) {
4796
4884
  }
4797
4885
  const { taskId, runId } = parseRunContextReference(first);
4798
4886
  authorizeRunContext(store, taskId, runId, options.environment);
4799
- const pack = store.transaction((tx) => buildRunContextPack(tx, taskId, runId));
4887
+ const pack = store.readTransaction((tx) => buildRunContextPack(tx, taskId, runId));
4800
4888
  const view = parsed.values.get("--view") ?? "current";
4801
4889
  if (!["current", "full", "refs", "input"].includes(view))
4802
4890
  throw usageError("Run Context view must be current, refs, input or full.");
@@ -4928,7 +5016,8 @@ function retryRun(args, store, options) {
4928
5016
  const sessions = tx.getTaskRoleSessionSet(previous.taskId, previous.roleName);
4929
5017
  const retry = options.providerRetryChainId !== undefined ? sessions?.providerBinding?.retry
4930
5018
  : sessions?.providerBinding == null ? undefined
4931
- : providerRunRetry(sessions.providerBinding, previous.id, clock(options).getTime());
5019
+ : providerRunRetry(sessions.providerBinding, previous.id, clock(options).getTime())
5020
+ ?? taskRunRecovery(tx, sessions.providerBinding, previous);
4932
5021
  if (options.providerRetryChainId !== undefined
4933
5022
  && (retry?.chainId !== options.providerRetryChainId || retry.status !== "waiting"
4934
5023
  || retry.previousRunId !== previous.id || clock(options).getTime() < Date.parse(retry.nextEligibleAt)
@@ -5762,17 +5851,49 @@ function retryFailedReviewRun(previous, store, options, now) {
5762
5851
  }
5763
5852
  /** AgentRun details are retained audit evidence; continuation uses durable Task state. */
5764
5853
  function showRun(args, store, options) {
5765
- const usage = "Task run show usage: yui task run show <task>/<run> [--json].";
5766
- 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);
5767
5859
  const positionals = parsed.positionals;
5768
5860
  exactPositionals(positionals, 1, usage);
5769
- const data = store.transaction((tx) => {
5861
+ const data = store.readTransaction((tx) => {
5770
5862
  const run = requireRun(tx, positionals[0], options);
5771
- const retirement = tx.listEvents(run.taskId)
5863
+ const events = tx.listEventsByType(run.taskId, [TASK_RECORD_RETIRED_EVENT, "runtime.agent-error"]);
5864
+ const retirement = events
5772
5865
  .map(taskRecordRetirement)
5773
5866
  .find((entry) => entry?.recordKind === "run" && entry.recordId === run.id) ?? null;
5774
- 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
+ } };
5775
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
+ }
5776
5897
  const bounded = boundedDocument(data, `run:${data.run.taskId}/${data.run.id}`, parsed.cursor);
5777
5898
  if ("contentPage" in bounded)
5778
5899
  return output(`${JSON.stringify(bounded, null, 2)}\n`, bounded);
@@ -6914,31 +7035,45 @@ function taskWakeDispatch(args, store, options) {
6914
7035
  const target = leaderMailbox(task.id);
6915
7036
  const mailbox = tx.getWorkMailbox(target);
6916
7037
  const claim = mailbox?.processing;
6917
- if (claim === undefined || claim === null || claim.owner !== `leader-notification:${wake.id}`) {
6918
- 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.");
6919
7055
  }
6920
- const previous = tx.listEvents(task.id).filter((event) => event.type === "notification.delivery" && event.payload.attemptId === claim.batchId).at(-1);
6921
7056
  const sessions = tx.getTaskRoleSessionSet(task.id, "leader");
6922
7057
  const provider = sessions?.providerBinding;
6923
- if (previous?.payload.outcome !== "unknown")
6924
- throw usageError("Only an unknown notification can be resolved.");
6925
7058
  if (tx.getActiveRun(task.id, "leader") !== null
6926
7059
  || provider?.authority.owner === "human" || provider?.authority.owner === "unknown"
6927
7060
  || (provider?.run !== undefined && provider.run !== null
6928
7061
  && ["submitting", "accepted", "delivery-unknown"].includes(provider.run.status))) {
6929
7062
  throw usageError("Shared native execution is not proven quiescent; resolve that exact runtime boundary first.");
6930
7063
  }
6931
- // 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.
6932
7066
  // This releases only the scheduling claim; it never replays, claims
6933
7067
  // acceptance, or asserts that Message requirements were implemented.
6934
7068
  recordTaskEvent(tx, task.id, "notification.resolved", {
6935
- wakeId: wake.id, attemptId: claim.batchId, reason, outcome: "released-without-replay"
7069
+ wakeId: wake.id, attemptId: previous.payload.attemptId, reason, outcome: "released-without-replay"
6936
7070
  }, now);
6937
- tx.saveWorkMailbox(completeProcessing(mailbox, claim.batchId));
7071
+ if (ownsClaim)
7072
+ tx.saveWorkMailbox(completeProcessing(mailbox, claim.batchId));
6938
7073
  return { taskId: task.id, wakeId: wake.id, outcome: "released-without-replay" };
6939
7074
  });
6940
7075
  notifyMailbox(options.runtime, leaderMailbox(result.taskId));
6941
- 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);
6942
7077
  }
6943
7078
  if (subcommand === "list" || subcommand === "show") {
6944
7079
  return taskWakeInspectionCommand(args, store);
@@ -6953,7 +7088,7 @@ function taskWakeDispatch(args, store, options) {
6953
7088
  * wake — the on-demand read the Agent uses instead of a context dump in the
6954
7089
  * wake envelope.
6955
7090
  */
6956
- function taskWakeInspectionCommand(args, store) {
7091
+ export function taskWakeInspectionCommand(args, store) {
6957
7092
  const [command, ...rest] = args;
6958
7093
  if (command === "list") {
6959
7094
  const usage = "Task wake list usage: yui task wake list <task> [--limit <n>] [--cursor <cursor>].";
@@ -7016,6 +7151,26 @@ function taskWakeInspectionCommand(args, store) {
7016
7151
  if (message.resultRef?.type === "agent-run-result")
7017
7152
  referencedRunIds.add(message.resultRef.runId);
7018
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
+ });
7019
7174
  const lines = [
7020
7175
  `Wake: ${wake.id}`,
7021
7176
  `Task: ${task.id}`,
@@ -7063,9 +7218,7 @@ function taskWakeInspectionCommand(args, store) {
7063
7218
  historyRead: `task wake show ${task.id} ${wake.id} --history`,
7064
7219
  events: events.map(event => ({ id: event.id, type: event.type, createdAt: event.createdAt,
7065
7220
  read: `task event show ${task.id} ${event.id}` })),
7066
- messages: messages.map(message => ({ id: message.id, kind: message.kind, author: message.author,
7067
- ...taskMessagePresentation(message, (taskId, runId) => store.getRun(taskId, runId)),
7068
- resultRef: message.resultRef, read: `task message show ${task.id}/${message.id}` })),
7221
+ messages: messageDetails,
7069
7222
  runs: runs.map(run => ({ id: run.id, status: run.status, purpose: run.purpose, roleName: run.roleName,
7070
7223
  read: `task run show ${task.id}/${run.id}` }))
7071
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");
@@ -4,6 +4,7 @@ import { taskRecordList } from "./taskContextCommand.js";
4
4
  import { materialize } from "../context/taskContext.js";
5
5
  import { enqueueWork } from "../coordination/workMailboxQueue.js";
6
6
  import { createDecision, supersedeDecision } from "../decision/decision.js";
7
+ import { readDigest } from "../output/boundedRead.js";
7
8
  import { dataError, usageError } from "../errors/cliError.js";
8
9
  import { createMilestone } from "../milestone/milestone.js";
9
10
  import { assertTaskOpen, clock, exactPositionals, leaderActionEventPayload, leaderMailbox, notifyMailbox, output, parseMultiValueTail, parseTail, presentTime, recordTaskEvent, requiredOption, requiredText, requireTask, taskActor, taskMailbox, taskRef } from "./taskCommandSupport.js";
@@ -107,6 +108,18 @@ export function taskBriefCommand(args, store, options) {
107
108
  ? "Task brief command is required."
108
109
  : `Unknown command: task brief ${command}`);
109
110
  }
111
+ function decisionReceipt(decision) {
112
+ // A short saved value lets the caller inspect the actual effect without
113
+ // another read. Bound the complete JSON record, including title/reason.
114
+ const contentOmitted = Buffer.byteLength(JSON.stringify(decision)) > 2048;
115
+ const value = contentOmitted ? {
116
+ id: decision.id, taskId: decision.taskId, status: decision.status,
117
+ createdAt: decision.createdAt, updatedAt: decision.updatedAt
118
+ } : decision;
119
+ return { taskId: decision.taskId, effect: "saved", contentOmitted, decision: { ...value,
120
+ digest: readDigest(decision), rationaleBytes: Buffer.byteLength(decision.rationale)
121
+ }, ...(contentOmitted ? { read: `yui task decision show ${decision.taskId} ${decision.id} --json` } : {}) };
122
+ }
110
123
  export function taskDecisionCommand(args, store, options) {
111
124
  const [command, ...rest] = args;
112
125
  if (command === "record") {
@@ -136,7 +149,7 @@ export function taskDecisionCommand(args, store, options) {
136
149
  notifyMailbox(options.runtime, taskMailbox(result.task.id));
137
150
  if (result.task.status === "active")
138
151
  notifyMailbox(options.runtime, leaderMailbox(result.task.id));
139
- return output(`Recorded decision ${result.decision.id} for ${result.task.id}\n`);
152
+ return output(`Recorded decision ${result.decision.id} for ${result.task.id}\n`, decisionReceipt(result.decision));
140
153
  }
141
154
  if (command === "list") {
142
155
  return taskRecordList(rest, store, "task-decision", options.environment);
@@ -190,7 +203,7 @@ export function taskDecisionCommand(args, store, options) {
190
203
  notifyMailbox(options.runtime, taskMailbox(result.task.id));
191
204
  if (result.task.status === "active")
192
205
  notifyMailbox(options.runtime, leaderMailbox(result.task.id));
193
- return output(`Superseded decision ${result.decision.id} for ${result.task.id}\n`);
206
+ return output(`Superseded decision ${result.decision.id} for ${result.task.id}\n`, decisionReceipt(result.decision));
194
207
  }
195
208
  throw usageError(command === undefined
196
209
  ? "Task decision command is required."
@@ -167,10 +167,10 @@ async function continueIntegration(args, store, home, now, options) {
167
167
  || integration.resolution?.action !== "manual-resolution")) {
168
168
  throw usageError(`Integration is not ready to continue: ${integration.id}/${integration.status}.`);
169
169
  }
170
- return runIntegration(store, home, integration, now, options);
170
+ return runIntegration(store, home, integration, now, options, "continue");
171
171
  }
172
- async function runIntegration(store, home, integration, now, options) {
173
- const result = await new GitIntegrationService(home, store, undefined, now, options.environment, undefined, options.jobPort).integrate(integration.taskId, integration.id);
172
+ async function runIntegration(store, home, integration, now, options, intent) {
173
+ const result = await new GitIntegrationService(home, store, undefined, now, options.environment, undefined, options.jobPort).integrate(integration.taskId, integration.id, undefined, intent);
174
174
  const output = result.status === "committed"
175
175
  ? `Integrated ${integrationSourceLabel(result.attempt)} into ${result.attempt.targetRef} with CAS (${result.attempt.id})\n`
176
176
  : result.status === "conflicted"