@zq-silk/yui 2.21.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.
- package/README.md +5 -0
- package/dist/cli/commandCatalog.js +85 -25
- package/dist/cli/dynamicCompletion.js +4 -1
- package/dist/cli/helpRenderer.js +12 -1
- package/dist/cli/interactionPolicy.js +2 -0
- package/dist/cli/invocationRouter.js +5 -5
- package/dist/cli/roleWizard.js +5 -1
- package/dist/commands/globalRoleCommands.js +33 -8
- package/dist/commands/inboxCommands.js +39 -12
- package/dist/commands/operatorCommands.js +2 -5
- package/dist/commands/releaseCommands.js +16 -2
- package/dist/commands/roleConfiguration.js +25 -2
- package/dist/commands/sessionCommands.js +5 -2
- package/dist/commands/taskCommands.js +217 -64
- package/dist/commands/taskContextCommand.js +26 -4
- package/dist/commands/taskFactCommands.js +15 -2
- package/dist/commands/taskIntegrationCommands.js +3 -3
- package/dist/commands/taskRoleRuntimeStatus.js +15 -5
- package/dist/commands/textInput.js +2 -2
- package/dist/context/contextFamilies.js +10 -0
- package/dist/context/currentSkills.js +6 -4
- package/dist/context/runContextPack.js +44 -5
- package/dist/context/runInputContract.js +1 -1
- package/dist/context/sessionBootstrapManifest.js +7 -5
- package/dist/context/sessionSkillNotice.js +53 -0
- package/dist/context/taskContext.js +100 -16
- package/dist/controlPlaneCli.js +17 -7
- package/dist/controller/agentRuntimeObserver.js +57 -12
- package/dist/controller/clientRuntime.js +37 -8
- package/dist/controller/controller.js +3 -1
- package/dist/controller/diagnosticJournal.js +10 -2
- package/dist/controller/fileSchedulerStoreAdapter.js +72 -24
- package/dist/controller/messageHealth.js +4 -3
- package/dist/controller/providerRetryAdmission.js +15 -1
- package/dist/controller/providerRetryDelivery.js +18 -2
- package/dist/controller/runtime.js +15 -5
- package/dist/controller/runtimeEventInbox.js +107 -13
- package/dist/controller/runtimeEventProcessor.js +3 -3
- package/dist/controller/taskRunRecovery.js +153 -0
- package/dist/core/controllerClient.js +16 -2
- package/dist/core/controllerServer.js +14 -5
- package/dist/core/controllerTelemetry.js +51 -5
- package/dist/errors/cliFailure.js +14 -5
- package/dist/executor/agentAdapter.js +32 -4
- package/dist/executor/agentConfigurationFields.js +2 -0
- package/dist/integration/gitIntegrationService.js +3 -2
- package/dist/integration/integrationSourceApplication.js +12 -1
- package/dist/interaction/notificationPresentation.js +11 -16
- package/dist/interaction/operatorPresentation.js +1 -1
- package/dist/message/messageContinuation.js +3 -1
- package/dist/output/boundedRead.js +36 -7
- package/dist/output/rolePresentation.js +3 -1
- package/dist/runtime/agentHost.js +12 -3
- package/dist/runtime/codexAppServerRuntime.js +110 -24
- package/dist/runtime/codexInteractiveHost.js +46 -0
- package/dist/runtime/providerRetry.js +5 -2
- package/dist/runtime/providerRuntimeIdentity.js +1 -1
- package/dist/runtime/structuredProviderHost.js +32 -34
- package/dist/scheduler/wakeupQueue.js +10 -4
- package/dist/storage/sqliteSchema.js +9 -0
- package/dist/storage/storageVersions.js +1 -1
- package/dist/tmux/tmuxManager.js +4 -2
- package/dist/web/webSettings.js +2 -0
- package/docs/authorization.md +18 -3
- package/docs/cli-information-contract.md +228 -6
- package/docs/cli-information-contract.zh-CN.md +95 -5
- package/docs/managed-turn-and-session-runtime.md +82 -21
- package/docs/managed-turn-and-session-runtime.zh-CN.md +56 -13
- package/docs/provider-retry.md +11 -0
- package/docs/release-workflow.md +37 -0
- package/docs/release-workflow.zh-CN.md +28 -0
- package/docs/roles-and-configuration.md +28 -0
- package/docs/roles-and-configuration.zh-CN.md +21 -0
- package/docs/storage-baseline.md +4 -1
- package/docs/storage-baseline.zh-CN.md +1 -1
- package/docs/task-delivery.md +7 -0
- package/docs/task-delivery.zh-CN.md +5 -0
- package/docs/testing/review-evaluation.md +7 -7
- package/docs/testing/review-evaluation.zh-CN.md +7 -7
- package/docs/testing/verification-levels.md +45 -2
- package/docs/testing/verification-levels.zh-CN.md +21 -2
- package/i18n/README.zh-CN.md +6 -0
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +98 -193
- package/skills/yui-leader/VERSION +1 -1
- package/skills/yui-leader/references/artifacts.md +41 -0
- package/skills/yui-leader/references/assignment-execution.md +140 -0
- package/skills/yui-leader/references/completion.md +79 -0
- package/skills/yui-leader/references/delivery-scope.md +26 -0
- package/skills/yui-leader/references/execution.md +16 -487
- package/skills/yui-leader/references/implementation.md +81 -0
- package/skills/yui-leader/references/planning.md +7 -45
- package/skills/yui-leader/references/review.md +90 -0
- package/skills/yui-leader/references/task-progress.md +23 -0
- package/skills/yui-leader/references/work-allocation.md +118 -0
- package/skills/yui-operator/SKILL.md +77 -333
- package/skills/yui-operator/VERSION +1 -1
- package/skills/yui-operator/references/body-transport.md +62 -0
- package/skills/yui-operator/references/configuration.md +47 -0
- package/skills/yui-operator/references/lifecycle.md +41 -0
- package/skills/yui-operator/references/progress.md +39 -0
- package/skills/yui-operator/references/routing.md +57 -0
- package/skills/yui-operator/references/submission.md +56 -0
- package/skills/yui-operator/references/task-delivery.md +1 -1
- package/skills/yui-operator/references/web-lifecycle.md +19 -0
- package/skills/yui-operator/scripts/verify-submission.mjs +37 -0
- package/skills/yui-runtime/SKILL.md +177 -531
- package/skills/yui-runtime/VERSION +1 -1
- package/skills/yui-runtime/references/archive.md +51 -0
- package/skills/yui-runtime/references/command-discovery.md +41 -0
- package/skills/yui-runtime/references/completed-followup.md +65 -0
- package/skills/yui-runtime/references/context-ordering.md +3 -34
- package/skills/yui-runtime/references/context-reads.md +61 -0
- package/skills/yui-runtime/references/dispatched-run.md +61 -0
- package/skills/yui-runtime/references/execution-failure.md +105 -0
- package/skills/yui-runtime/references/global-context.md +18 -0
- package/skills/yui-runtime/references/global-input-controls.md +44 -0
- package/skills/yui-runtime/references/host-custody.md +30 -0
- package/skills/yui-runtime/references/inbox-recovery.md +77 -0
- package/skills/yui-runtime/references/incremental-context.md +40 -0
- package/skills/yui-runtime/references/publication.md +4 -111
- package/skills/yui-runtime/references/recovery.md +32 -192
- package/skills/yui-runtime/references/session-identity.md +18 -0
- package/skills/yui-runtime/references/session-replacement.md +45 -0
- package/skills/yui-runtime/references/uncertain-execution.md +29 -0
|
@@ -24,6 +24,8 @@ const AGENT_VALUE_OPTIONS = [
|
|
|
24
24
|
["--permission-strategy", "value"],
|
|
25
25
|
["--sandbox", "value"],
|
|
26
26
|
["--approval", "value"],
|
|
27
|
+
["--exclude-tmpdir-env-var", "value"],
|
|
28
|
+
["--exclude-slash-tmp", "value"],
|
|
27
29
|
["--permission-mode", "value"],
|
|
28
30
|
["--search", "value"]
|
|
29
31
|
];
|
|
@@ -37,6 +39,8 @@ const AGENT_CLEAR_OPTIONS = [
|
|
|
37
39
|
["--clear-allowed-tools", "flag"],
|
|
38
40
|
["--clear-disallowed-tools", "flag"],
|
|
39
41
|
["--clear-search", "flag"],
|
|
42
|
+
["--clear-exclude-tmpdir-env-var", "flag"],
|
|
43
|
+
["--clear-exclude-slash-tmp", "flag"],
|
|
40
44
|
["--clear-agent-config", "flag"]
|
|
41
45
|
];
|
|
42
46
|
const AGENT_CONFIG_OPTIONS = new Set([
|
|
@@ -196,6 +200,8 @@ function permissionPatch(binding, parsed) {
|
|
|
196
200
|
: undefined;
|
|
197
201
|
const nativeOptions = [
|
|
198
202
|
"--sandbox", "--approval", "--permission-mode",
|
|
203
|
+
"--exclude-tmpdir-env-var", "--exclude-slash-tmp",
|
|
204
|
+
"--clear-exclude-tmpdir-env-var", "--clear-exclude-slash-tmp",
|
|
199
205
|
"--allowed-tool", "--clear-allowed-tools",
|
|
200
206
|
"--disallowed-tool", "--clear-disallowed-tools"
|
|
201
207
|
].some((option) => parsed.has(option));
|
|
@@ -219,6 +225,19 @@ function permissionPatch(binding, parsed) {
|
|
|
219
225
|
permission.sandbox = requiredText(parsed.one("--sandbox"));
|
|
220
226
|
if (parsed.has("--approval"))
|
|
221
227
|
permission.approval = requiredText(parsed.one("--approval"));
|
|
228
|
+
for (const [option, key] of [
|
|
229
|
+
["exclude-tmpdir-env-var", "excludeTmpdirEnvVar"],
|
|
230
|
+
["exclude-slash-tmp", "excludeSlashTmp"]
|
|
231
|
+
]) {
|
|
232
|
+
if (parsed.has(`--${option}`)) {
|
|
233
|
+
const value = parsed.one(`--${option}`);
|
|
234
|
+
if (value !== "true" && value !== "false")
|
|
235
|
+
throw usageError(`--${option} requires true or false.`);
|
|
236
|
+
permission[key] = value === "true";
|
|
237
|
+
}
|
|
238
|
+
if (parsed.has(`--clear-${option}`))
|
|
239
|
+
delete permission[key];
|
|
240
|
+
}
|
|
222
241
|
}
|
|
223
242
|
else if (binding.adapterId === "acp") {
|
|
224
243
|
// An ACP Session's configured permission is exactly one mode id, matched
|
|
@@ -263,7 +282,9 @@ function assertAgentOptionConflicts(parsed) {
|
|
|
263
282
|
["--effort", "--clear-effort"],
|
|
264
283
|
["--allowed-tool", "--clear-allowed-tools"],
|
|
265
284
|
["--disallowed-tool", "--clear-disallowed-tools"],
|
|
266
|
-
["--search", "--clear-search"]
|
|
285
|
+
["--search", "--clear-search"],
|
|
286
|
+
["--exclude-tmpdir-env-var", "--clear-exclude-tmpdir-env-var"],
|
|
287
|
+
["--exclude-slash-tmp", "--clear-exclude-slash-tmp"]
|
|
267
288
|
]);
|
|
268
289
|
if (parsed.has("--clear-agent-config")
|
|
269
290
|
&& [...parsed.seen].some((option) => option !== "--clear-agent-config" && AGENT_CONFIG_OPTIONS.has(option))) {
|
|
@@ -271,7 +292,9 @@ function assertAgentOptionConflicts(parsed) {
|
|
|
271
292
|
}
|
|
272
293
|
}
|
|
273
294
|
function assertAdapterOptions(adapterId, parsed) {
|
|
274
|
-
const codex = ["--sandbox", "--approval", "--search", "--clear-search"
|
|
295
|
+
const codex = ["--sandbox", "--approval", "--search", "--clear-search",
|
|
296
|
+
"--exclude-tmpdir-env-var", "--exclude-slash-tmp",
|
|
297
|
+
"--clear-exclude-tmpdir-env-var", "--clear-exclude-slash-tmp"];
|
|
275
298
|
const tools = [
|
|
276
299
|
"--allowed-tool", "--clear-allowed-tools",
|
|
277
300
|
"--disallowed-tool", "--clear-disallowed-tools"
|
|
@@ -27,7 +27,10 @@ export async function runSessionStopCommand(input) {
|
|
|
27
27
|
// Leader dispatch. The explicit full pass settles pending runtime inbox and
|
|
28
28
|
// lifecycle work that may exist without a current Session candidate.
|
|
29
29
|
await input.runtime.drainController();
|
|
30
|
-
await input.runtime.stopController();
|
|
30
|
+
const stoppedController = await input.runtime.stopController();
|
|
31
|
+
if (stoppedController.stopped !== true && stoppedController.alreadyStopped !== true) {
|
|
32
|
+
throw new Error("Controller stop was not confirmed; no Session was stopped.");
|
|
33
|
+
}
|
|
31
34
|
// Re-read the authoritative facts after the drain because a AgentRun that was
|
|
32
35
|
// already inside a pass may have changed state meanwhile.
|
|
33
36
|
const settled = input.runtime.snapshot();
|
|
@@ -80,7 +83,7 @@ function blockedSessions(input) {
|
|
|
80
83
|
});
|
|
81
84
|
}
|
|
82
85
|
function blockedStopResult(blocked) {
|
|
83
|
-
const details = blocked.map(({ session }) => (`- ${renderSessionOwner(session)} (an active AgentRun or lifecycle operation is still pending)`));
|
|
86
|
+
const details = blocked.map(({ session }) => (`- ${renderSessionOwner(session)} (native execution, an active AgentRun or lifecycle operation is still pending)`));
|
|
84
87
|
return {
|
|
85
88
|
output: [
|
|
86
89
|
`Cannot stop managed Sessions: ${blocked.length} Session(s) are still busy.`,
|
|
@@ -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
|
|
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
|
|
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
|
-
|
|
2760
|
-
|
|
2761
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
2770
|
-
|
|
2771
|
-
const
|
|
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
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
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
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
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
|
|
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 (
|
|
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 =
|
|
4770
|
-
|
|
4771
|
-
|
|
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.
|
|
4779
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
5861
|
+
const data = store.readTransaction((tx) => {
|
|
5770
5862
|
const run = requireRun(tx, positionals[0], options);
|
|
5771
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
6918
|
-
|
|
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
|
-
//
|
|
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:
|
|
7069
|
+
wakeId: wake.id, attemptId: previous.payload.attemptId, reason, outcome: "released-without-replay"
|
|
6936
7070
|
}, now);
|
|
6937
|
-
|
|
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
|
|
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:
|
|
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
|
-
|
|
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");
|