@zq-silk/yui 0.12.2 → 0.12.4
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/dist/cli/commandCatalog.js +2 -2
- package/dist/commands/durableJobCommands.js +5 -5
- package/dist/commands/taskActor.js +18 -0
- package/dist/commands/taskCommands.js +235 -53
- package/dist/commands/taskIntegrationCommands.js +30 -19
- package/dist/commands/taskIntegrationQueueCommands.js +14 -14
- package/dist/context/runContextPack.js +15 -0
- package/dist/controller/fileSchedulerStoreAdapter.js +17 -1
- package/dist/executor/workspacePreflightClassification.js +6 -5
- package/dist/lifecycle/exactRunTerminalization.js +146 -6
- package/dist/run/rejectedYieldAttempt.js +221 -0
- package/dist/runtime/tmuxAdapters.js +12 -3
- package/dist/scheduler/activeRoleRunDelivery.js +4 -0
- package/dist/storage/sqliteStore.js +18 -0
- package/dist/storage/upgrade/sqliteStateMigration.js +1 -1
- package/package.json +1 -1
|
@@ -7,6 +7,7 @@ import { CliError, dataError, roleNotFound, runtimeError, taskNotFound, usageErr
|
|
|
7
7
|
import { createTaskEvent } from "../event/taskEvent.js";
|
|
8
8
|
import { createTaskRecordRetirement, isTaskRecordRetired, taskRecordRetirement } from "../task/taskRecordRetirement.js";
|
|
9
9
|
import { isRoleRunStalled, RUN_PROGRESS_EVENT, RUN_RECOVERED_EVENT } from "../scheduler/roleRunStall.js";
|
|
10
|
+
import { routeRoleEvent } from "../scheduler/operatorEvent.js";
|
|
10
11
|
import { readCommandText } from "./textInput.js";
|
|
11
12
|
import { assertTaskCompletionPublishedTreeProof } from "./taskCompletionGate.js";
|
|
12
13
|
import { createRoleSessionSet, retireTaskRoleSessionsForWorkspace, updateTaskRoleProviderRuntime } from "../executor/agentExecutor.js";
|
|
@@ -18,11 +19,12 @@ import { formatTimestamp } from "../output/timePresentation.js";
|
|
|
18
19
|
import { renderRoleDetails } from "../output/rolePresentation.js";
|
|
19
20
|
import { createTaskMessage, taskMessageAuthorLabel } from "../message/message.js";
|
|
20
21
|
import { cancelInputRequest } from "../input/inputRequest.js";
|
|
21
|
-
import { recoverExactAgentRun, terminalizeExactTaskRun, validateExactRunReviewRound } from "../lifecycle/exactRunTerminalization.js";
|
|
22
|
+
import { recoverExactAgentRun, retireExactActiveAgentRun, terminalizeExactTaskRun, validateExactRunReviewRound } from "../lifecycle/exactRunTerminalization.js";
|
|
22
23
|
import { copyGlobalRoleToTaskRole, createRole, createRoleAgentBinding, switchActiveRoleAgent, unbindRoleAgent, updateRole, updateRoleStatus } from "../role/role.js";
|
|
23
24
|
import { agentRunDeliveryReceiptId, createAgentRun, withAgentRunContextSnapshot } from "../run/agentRun.js";
|
|
24
25
|
import { projectRunRecovery, readRunRecoveryFacts } from "../run/recoveryProjection.js";
|
|
25
26
|
import { matchYieldReceipt } from "../run/yieldReceipt.js";
|
|
27
|
+
import { createRejectedYieldAttempt, rejectedYieldAttemptEventPayload, rejectedYieldAttemptFromTaskEvent, RUN_YIELD_REJECTED_EVENT } from "../run/rejectedYieldAttempt.js";
|
|
26
28
|
import { createReviewRound, createTaskReviewRound, createTaskDeltaReviewRound, attachReviewExecutionGroup, deltaRecheckBlocksAcceptance, finishReviewRound, parseReviewYieldReport, recordReviewWorkspaceDisposition, retryRunningReviewExecutionLane, retryTaskReviewRound, startReviewRound, updateReviewExecutionGroup, validateTaskReviewCandidate } from "../review/reviewRound.js";
|
|
27
29
|
import { buildDeltaRecheckDispatchContext, verifyDeltaRecheckDiff } from "../review/deltaRecheck.js";
|
|
28
30
|
import { isAcceptedTaskReviewBaseline } from "../review/reviewAcceptance.js";
|
|
@@ -63,7 +65,7 @@ import { inspectTaskRoleRuntimeStatuses, renderTaskRoleRuntimeStatus, taskRoleAc
|
|
|
63
65
|
import { assertNoOpenInputRequests, isCurrentGlobalOperator, openInputRequestCount, runTaskInputCommand } from "./taskInputCommands.js";
|
|
64
66
|
import { runGrantCommand } from "./grantCommands.js";
|
|
65
67
|
import { runWorkflowCommand } from "./workflowCommands.js";
|
|
66
|
-
import {
|
|
68
|
+
import { taskLocalActor as resolveTaskLocalActor, taskLeaderActionRunId } from "./taskActor.js";
|
|
67
69
|
import { enqueueOperatorEvent } from "../scheduler/operatorEvent.js";
|
|
68
70
|
import { queueLeaderWakeup } from "../scheduler/wakeupQueue.js";
|
|
69
71
|
import { renderWakeReason, wakeReason } from "../scheduler/wakeReason.js";
|
|
@@ -164,7 +166,7 @@ export function parseTaskCompletionRequest(args, summaryOverride) {
|
|
|
164
166
|
*/
|
|
165
167
|
export function preflightTaskCompletion(taskId, store, options = {}, request = {}) {
|
|
166
168
|
const task = requireTask(store, taskId);
|
|
167
|
-
const actor = taskActor(options, task.id);
|
|
169
|
+
const actor = taskActor(store, options, task.id);
|
|
168
170
|
if (task.status === "completed") {
|
|
169
171
|
return { task, actor, completed: true, activeTaskReview: false };
|
|
170
172
|
}
|
|
@@ -379,7 +381,7 @@ function taskProjectCommand(args, store, options) {
|
|
|
379
381
|
const updated = store.transaction((tx) => {
|
|
380
382
|
const task = requireTask(tx, parsed.positionals[0]);
|
|
381
383
|
assertTaskOpen(task);
|
|
382
|
-
if (task.status === "active" && taskActor(options, task.id) !== "leader") {
|
|
384
|
+
if (task.status === "active" && taskActor(tx, options, task.id) !== "leader") {
|
|
383
385
|
throw usageError("Only the Task Leader may add a Project to an active Task.");
|
|
384
386
|
}
|
|
385
387
|
const project = resolveProject(tx.listProjects(), parsed.positionals[1]);
|
|
@@ -444,6 +446,7 @@ function updateTaskCommand(args, store, options) {
|
|
|
444
446
|
const current = requireTask(tx, parsed.positionals[0]);
|
|
445
447
|
if (current.status === "archived")
|
|
446
448
|
throw usageError(`Task is archived: ${current.id}.`);
|
|
449
|
+
taskActor(tx, options, current.id);
|
|
447
450
|
const updated = updateTaskMetadata(current, {
|
|
448
451
|
...(parsed.options.has("--title") ? { title: requiredOption(parsed.options, "--title") } : {}),
|
|
449
452
|
...(parsed.options.has("--type")
|
|
@@ -952,7 +955,7 @@ function archiveTaskCommand(args, store, options) {
|
|
|
952
955
|
const now = clock(options);
|
|
953
956
|
const result = store.transaction((tx) => {
|
|
954
957
|
const task = requireTask(tx, request.taskId);
|
|
955
|
-
const actor = taskActor(options, task.id);
|
|
958
|
+
const actor = taskActor(tx, options, task.id);
|
|
956
959
|
if (task.status === "archived")
|
|
957
960
|
return { task, changed: false };
|
|
958
961
|
if (task.status !== "completed"
|
|
@@ -1016,7 +1019,7 @@ function retireTaskCommand(args, store, options) {
|
|
|
1016
1019
|
const now = clock(options);
|
|
1017
1020
|
const result = store.transaction((tx) => {
|
|
1018
1021
|
const task = requireTask(tx, taskId);
|
|
1019
|
-
const actor = taskActor(options, task.id);
|
|
1022
|
+
const actor = taskActor(tx, options, task.id);
|
|
1020
1023
|
if (task.status === "retired") {
|
|
1021
1024
|
const same = task.retirementSummary === summary
|
|
1022
1025
|
&& task.replacementTaskId === replacementTaskId;
|
|
@@ -1144,7 +1147,7 @@ export function parseTaskArchiveArguments(args) {
|
|
|
1144
1147
|
export function validateTaskArchiveRequest(args, store, options = {}) {
|
|
1145
1148
|
const request = parseTaskArchiveArguments(args);
|
|
1146
1149
|
const task = requireTask(store, request.taskId);
|
|
1147
|
-
const actor = taskActor(options, task.id);
|
|
1150
|
+
const actor = taskActor(store, options, task.id);
|
|
1148
1151
|
if (actor === "leader") {
|
|
1149
1152
|
throw usageError("Only the global Operator may archive a Task from a managed Session.");
|
|
1150
1153
|
}
|
|
@@ -1201,7 +1204,7 @@ function taskMessageCommand(args, store, options) {
|
|
|
1201
1204
|
const result = store.transaction((tx) => {
|
|
1202
1205
|
const task = requireTask(tx, parsed.positionals[0]);
|
|
1203
1206
|
assertTaskOpen(task);
|
|
1204
|
-
const actor = taskActor(options, task.id);
|
|
1207
|
+
const actor = taskActor(tx, options, task.id);
|
|
1205
1208
|
const message = actor === "leader"
|
|
1206
1209
|
? appendMessage(tx, task.id, body, "role-result", { type: "role", roleName: LEADER_ROLE }, now)
|
|
1207
1210
|
: actor === "operator"
|
|
@@ -1296,10 +1299,7 @@ function retireMessage(args, store, options) {
|
|
|
1296
1299
|
const result = store.transaction((tx) => {
|
|
1297
1300
|
const task = requireTask(tx, reference.taskId);
|
|
1298
1301
|
assertTaskOpen(task);
|
|
1299
|
-
const actor = taskActor(options, task.id);
|
|
1300
|
-
if (actor === "leader") {
|
|
1301
|
-
throw usageError("Only the user or global Operator may retire a Task Message.");
|
|
1302
|
-
}
|
|
1302
|
+
const actor = taskActor(tx, options, task.id);
|
|
1303
1303
|
const message = tx.listMessages(task.id).find(({ id }) => id === reference.localId);
|
|
1304
1304
|
if (message === undefined) {
|
|
1305
1305
|
throw dataError(`Task Message not found: ${task.id}/${reference.localId}.`);
|
|
@@ -1405,7 +1405,7 @@ function switchTaskRoleSession(args, store, options) {
|
|
|
1405
1405
|
throw usageError(inactiveTaskMessage(task, "switching a Provider Conversation"), usage);
|
|
1406
1406
|
}
|
|
1407
1407
|
const role = requireRole(tx, task.id, parsed.positionals[1]);
|
|
1408
|
-
const requestedBy = taskActor(options, task.id);
|
|
1408
|
+
const requestedBy = taskActor(tx, options, task.id);
|
|
1409
1409
|
const leaderRunId = requestedBy === "leader"
|
|
1410
1410
|
? taskLeaderActionRunId(tx, task.id, options.environment, options.yuiHome)
|
|
1411
1411
|
: undefined;
|
|
@@ -1476,6 +1476,7 @@ function addTaskRole(args, store, options) {
|
|
|
1476
1476
|
const result = store.transaction((tx) => {
|
|
1477
1477
|
const task = requireTask(tx, taskId);
|
|
1478
1478
|
assertTaskOpen(task);
|
|
1479
|
+
taskActor(tx, options, task.id);
|
|
1479
1480
|
assertRoleRuntimeMutationAllowed(tx, {
|
|
1480
1481
|
scope: "task",
|
|
1481
1482
|
taskId: task.id,
|
|
@@ -1594,6 +1595,7 @@ function updateTaskRole(args, store, options) {
|
|
|
1594
1595
|
const updated = store.transaction((tx) => {
|
|
1595
1596
|
const task = requireTask(tx, taskId);
|
|
1596
1597
|
assertTaskOpen(task);
|
|
1598
|
+
taskActor(tx, options, task.id);
|
|
1597
1599
|
const role = requireRole(tx, task.id, roleName);
|
|
1598
1600
|
const changesLaunchContext = hasRoleLaunchContextOptions(parsed) || parsed.has("--profile");
|
|
1599
1601
|
const changesAgentConfig = hasAgentConfigOptions(parsed);
|
|
@@ -1640,6 +1642,7 @@ function removeTaskRole(args, store, options) {
|
|
|
1640
1642
|
const removed = store.transaction((tx) => {
|
|
1641
1643
|
const task = requireTask(tx, args[0]);
|
|
1642
1644
|
assertTaskOpen(task);
|
|
1645
|
+
taskActor(tx, options, task.id);
|
|
1643
1646
|
const role = requireRole(tx, task.id, args[1]);
|
|
1644
1647
|
if (role.name === LEADER_ROLE)
|
|
1645
1648
|
throw usageError("The Task Leader role cannot be removed.");
|
|
@@ -1669,6 +1672,7 @@ function bindTaskRole(args, store, options) {
|
|
|
1669
1672
|
const result = store.transaction((tx) => {
|
|
1670
1673
|
const task = requireTask(tx, args[0]);
|
|
1671
1674
|
assertTaskOpen(task);
|
|
1675
|
+
taskActor(tx, options, task.id);
|
|
1672
1676
|
const role = requireRole(tx, task.id, args[1]);
|
|
1673
1677
|
assertRoleRuntimeMutationAllowed(tx, {
|
|
1674
1678
|
scope: "task",
|
|
@@ -1722,6 +1726,8 @@ function unbindTaskRole(args, store, options) {
|
|
|
1722
1726
|
const now = clock(options);
|
|
1723
1727
|
const result = store.transaction((tx) => {
|
|
1724
1728
|
const task = requireTask(tx, args[0]);
|
|
1729
|
+
assertTaskOpen(task);
|
|
1730
|
+
taskActor(tx, options, task.id);
|
|
1725
1731
|
const role = requireRole(tx, task.id, args[1]);
|
|
1726
1732
|
try {
|
|
1727
1733
|
const unbound = unbindRoleAgent(role, tx.getTaskRoleSessionSet(task.id, role.name), args[2], now);
|
|
@@ -1772,6 +1778,7 @@ function transferTaskRoleAuthority(args, store, options, action) {
|
|
|
1772
1778
|
if (task.status !== "active") {
|
|
1773
1779
|
throw usageError(inactiveTaskMessage(task, `${action} Provider authority`));
|
|
1774
1780
|
}
|
|
1781
|
+
taskActor(tx, options, task.id);
|
|
1775
1782
|
const role = requireRole(tx, task.id, args[1]);
|
|
1776
1783
|
const sessions = tx.getTaskRoleSessionSet(task.id, role.name);
|
|
1777
1784
|
const session = sessions?.sessions[role.activeAgentId];
|
|
@@ -1887,6 +1894,7 @@ function createWork(args, store, options) {
|
|
|
1887
1894
|
const item = store.transaction((tx) => {
|
|
1888
1895
|
const task = requireTask(tx, parsed.positionals[0]);
|
|
1889
1896
|
assertTaskOpen(task);
|
|
1897
|
+
taskActor(tx, options, task.id);
|
|
1890
1898
|
for (const dependencyId of parsed.after) {
|
|
1891
1899
|
const dependency = tx.getWorkItem(task.id, dependencyId);
|
|
1892
1900
|
if (dependency === null)
|
|
@@ -1946,7 +1954,7 @@ function updateWorkScope(args, store, options) {
|
|
|
1946
1954
|
const updated = store.transaction((tx) => {
|
|
1947
1955
|
const item = requireWorkItem(tx, parsed.positionals[0], options);
|
|
1948
1956
|
const task = requireTask(tx, item.taskId);
|
|
1949
|
-
if (taskActor(options, task.id) !== "leader") {
|
|
1957
|
+
if (taskActor(tx, options, task.id) !== "leader") {
|
|
1950
1958
|
throw usageError("Only the Task Leader may change a Work Item Project scope.");
|
|
1951
1959
|
}
|
|
1952
1960
|
if (tx.getActiveAgentRun(task.id, item.assignee ?? "") !== null) {
|
|
@@ -1996,7 +2004,7 @@ function updateWork(args, store, options) {
|
|
|
1996
2004
|
const task = requireTask(tx, current.taskId);
|
|
1997
2005
|
assertTaskOpen(task);
|
|
1998
2006
|
if (current.assignee === undefined) {
|
|
1999
|
-
if (taskActor(options, task.id) !== "leader") {
|
|
2007
|
+
if (taskActor(tx, options, task.id) !== "leader") {
|
|
2000
2008
|
throw usageError(`Only the Task Leader may update unassigned Work Item execution: ${current.id}.`);
|
|
2001
2009
|
}
|
|
2002
2010
|
if (status === "running") {
|
|
@@ -2143,6 +2151,7 @@ function dispatchWork(args, store, options) {
|
|
|
2143
2151
|
if (task.status !== "active") {
|
|
2144
2152
|
throw usageError(inactiveTaskMessage(task, "dispatch"));
|
|
2145
2153
|
}
|
|
2154
|
+
taskActor(tx, options, task.id);
|
|
2146
2155
|
const currentGroup = currentWorkItemExecutionGroup(item);
|
|
2147
2156
|
const existingGroup = currentGroup?.resolution === undefined
|
|
2148
2157
|
? currentGroup
|
|
@@ -2190,7 +2199,7 @@ function dispatchWork(args, store, options) {
|
|
|
2190
2199
|
+ `The Task Leader must run "yui task work update ${item.id} running", `
|
|
2191
2200
|
+ "then execute it directly or create native subagents in the Leader Session.");
|
|
2192
2201
|
}
|
|
2193
|
-
if (expanding && taskActor(options, task.id) !== "leader") {
|
|
2202
|
+
if (expanding && taskActor(tx, options, task.id) !== "leader") {
|
|
2194
2203
|
throw usageError("Only the Task Leader may expand a running ExecutionGroup.");
|
|
2195
2204
|
}
|
|
2196
2205
|
assertWorkItemDependenciesCompleted(tx, item);
|
|
@@ -2572,7 +2581,7 @@ function resolveWorkExecutionGroup(args, store, options) {
|
|
|
2572
2581
|
const task = requireTask(tx, item.taskId);
|
|
2573
2582
|
if (task.status !== "active")
|
|
2574
2583
|
throw usageError(inactiveTaskMessage(task, "resolving an ExecutionGroup"));
|
|
2575
|
-
if (taskActor(options, task.id) !== "leader") {
|
|
2584
|
+
if (taskActor(tx, options, task.id) !== "leader") {
|
|
2576
2585
|
throw usageError("Only the Task Leader may resolve an ExecutionGroup.");
|
|
2577
2586
|
}
|
|
2578
2587
|
let group = currentWorkItemExecutionGroup(item);
|
|
@@ -2806,7 +2815,7 @@ function acceptWork(args, store, options) {
|
|
|
2806
2815
|
if (task.status !== "active") {
|
|
2807
2816
|
throw usageError(`Task is not active: ${task.id}/${task.status}.`);
|
|
2808
2817
|
}
|
|
2809
|
-
if (taskActor(options, task.id) !== "leader") {
|
|
2818
|
+
if (taskActor(tx, options, task.id) !== "leader") {
|
|
2810
2819
|
throw usageError("Only the Task Leader may accept a Work Item.");
|
|
2811
2820
|
}
|
|
2812
2821
|
if (item.status !== "awaiting_acceptance") {
|
|
@@ -2929,7 +2938,7 @@ function rejectWork(args, store, options) {
|
|
|
2929
2938
|
if (task.status !== "active") {
|
|
2930
2939
|
throw usageError(`Task is not active: ${task.id}/${task.status}.`);
|
|
2931
2940
|
}
|
|
2932
|
-
if (taskActor(options, task.id) !== "leader") {
|
|
2941
|
+
if (taskActor(tx, options, task.id) !== "leader") {
|
|
2933
2942
|
throw usageError("Only the Task Leader may reject a Work Item.");
|
|
2934
2943
|
}
|
|
2935
2944
|
if (item.status !== "awaiting_acceptance") {
|
|
@@ -2966,7 +2975,7 @@ function retireWork(args, store, options) {
|
|
|
2966
2975
|
if (task.status !== "active") {
|
|
2967
2976
|
throw usageError(`Task is not active: ${task.id}/${task.status}.`);
|
|
2968
2977
|
}
|
|
2969
|
-
const actor = taskActor(options, task.id);
|
|
2978
|
+
const actor = taskActor(tx, options, task.id);
|
|
2970
2979
|
if (replacementWorkItemId !== undefined) {
|
|
2971
2980
|
const replacement = requireWorkItem(tx, replacementWorkItemId, options);
|
|
2972
2981
|
if (replacement.taskId !== task.id) {
|
|
@@ -3088,7 +3097,7 @@ function reviewWork(args, store, options) {
|
|
|
3088
3097
|
if (task.status !== "active") {
|
|
3089
3098
|
throw usageError(`Task is not active: ${task.id}/${task.status}.`);
|
|
3090
3099
|
}
|
|
3091
|
-
if (taskActor(options, task.id) !== "leader") {
|
|
3100
|
+
if (taskActor(tx, options, task.id) !== "leader") {
|
|
3092
3101
|
throw usageError("Only the Task Leader may request a Work Item review.");
|
|
3093
3102
|
}
|
|
3094
3103
|
if (item.status !== "awaiting_acceptance") {
|
|
@@ -3281,7 +3290,7 @@ function resolveReviewExecutionGroup(args, store, options) {
|
|
|
3281
3290
|
const task = requireTask(tx, round.taskId);
|
|
3282
3291
|
if (task.status !== "active")
|
|
3283
3292
|
throw usageError(inactiveTaskMessage(task, "resolving a Review ExecutionGroup"));
|
|
3284
|
-
if (taskActor(options, task.id) !== "leader") {
|
|
3293
|
+
if (taskActor(tx, options, task.id) !== "leader") {
|
|
3285
3294
|
throw usageError("Only the Task Leader may resolve a Reviewer ExecutionGroup.");
|
|
3286
3295
|
}
|
|
3287
3296
|
const group = round.executionGroup;
|
|
@@ -3414,7 +3423,7 @@ function disposeReviewFindingCommand(args, store, options) {
|
|
|
3414
3423
|
const task = requireTask(tx, reference.taskId);
|
|
3415
3424
|
if (task.status !== "active")
|
|
3416
3425
|
throw usageError(inactiveTaskMessage(task, "dispositioning a review finding"));
|
|
3417
|
-
if (taskActor(options, task.id) !== "leader") {
|
|
3426
|
+
if (taskActor(tx, options, task.id) !== "leader") {
|
|
3418
3427
|
throw usageError("Only the Task Leader may disposition a review finding.");
|
|
3419
3428
|
}
|
|
3420
3429
|
const command = {
|
|
@@ -3451,7 +3460,7 @@ function planReviewRepairWave(args, store, options) {
|
|
|
3451
3460
|
if (currentTask.status !== "active") {
|
|
3452
3461
|
throw usageError(inactiveTaskMessage(currentTask, "creating a review repair wave"));
|
|
3453
3462
|
}
|
|
3454
|
-
if (taskActor(options, currentTask.id) !== "leader") {
|
|
3463
|
+
if (taskActor(tx, options, currentTask.id) !== "leader") {
|
|
3455
3464
|
throw usageError("Only the Task Leader may create a review repair wave.");
|
|
3456
3465
|
}
|
|
3457
3466
|
const openItems = tx.listWorkItems(currentTask.id)
|
|
@@ -3552,7 +3561,7 @@ function requestTaskReviewRound(args, store, options) {
|
|
|
3552
3561
|
const task = requireTask(tx, parsed.positionals[0]);
|
|
3553
3562
|
if (task.status !== "active")
|
|
3554
3563
|
throw usageError(`Task is not active: ${task.id}.`);
|
|
3555
|
-
if (taskActor(options, task.id) !== "leader") {
|
|
3564
|
+
if (taskActor(tx, options, task.id) !== "leader") {
|
|
3556
3565
|
throw usageError("Only the Task Leader may request a Task-final Review.");
|
|
3557
3566
|
}
|
|
3558
3567
|
if (task.projectBindings.length === 0) {
|
|
@@ -3783,7 +3792,7 @@ function forceFreshTaskReviewRound(args, store, options) {
|
|
|
3783
3792
|
const task = requireTask(tx, reference.taskId);
|
|
3784
3793
|
if (task.status !== "active")
|
|
3785
3794
|
throw usageError(`Task is not active: ${task.id}.`);
|
|
3786
|
-
if (taskActor(options, task.id) !== "leader") {
|
|
3795
|
+
if (taskActor(tx, options, task.id) !== "leader") {
|
|
3787
3796
|
throw usageError("Only the Task Leader may force a fresh Task-final ReviewRound.");
|
|
3788
3797
|
}
|
|
3789
3798
|
if ((source.scope ?? "work-item") !== "task") {
|
|
@@ -3995,7 +4004,7 @@ function retryFailedTaskReviewRound(args, store, options) {
|
|
|
3995
4004
|
const task = requireTask(tx, reference.taskId);
|
|
3996
4005
|
if (task.status !== "active")
|
|
3997
4006
|
throw usageError(`Task is not active: ${task.id}.`);
|
|
3998
|
-
if (taskActor(options, task.id) !== "leader") {
|
|
4007
|
+
if (taskActor(tx, options, task.id) !== "leader") {
|
|
3999
4008
|
throw usageError("Only the Task Leader may retry a failed Task-final ReviewRound.");
|
|
4000
4009
|
}
|
|
4001
4010
|
if ((round.scope ?? "work-item") !== "task") {
|
|
@@ -4117,8 +4126,16 @@ function taskRunCommand(args, store, options) {
|
|
|
4117
4126
|
: `Unknown command: task run ${command}`);
|
|
4118
4127
|
}
|
|
4119
4128
|
function retireRun(args, store, options) {
|
|
4120
|
-
const usage = "Task run retire usage: yui task run retire <task>/<run> --reason <text
|
|
4121
|
-
const parsed = parseTail(args, new Set([
|
|
4129
|
+
const usage = "Task run retire usage: yui task run retire <task>/<run> --reason <text> [--expected-progress-at <timestamp>] [--agent-id <id>] [--adapter-id <id>] [--native-session-id <id>] [--launch-id <id>].";
|
|
4130
|
+
const parsed = parseTail(args, new Set([
|
|
4131
|
+
"--reason",
|
|
4132
|
+
"--expected-progress-at",
|
|
4133
|
+
"--progress-at",
|
|
4134
|
+
"--agent-id",
|
|
4135
|
+
"--adapter-id",
|
|
4136
|
+
"--native-session-id",
|
|
4137
|
+
"--launch-id"
|
|
4138
|
+
]), usage);
|
|
4122
4139
|
exactPositionals(parsed.positionals, 1, usage);
|
|
4123
4140
|
const reason = requiredOption(parsed.options, "--reason");
|
|
4124
4141
|
const reference = taskRecordReference(parsed.positionals[0], "agentRun", "Agent Run reference", options);
|
|
@@ -4126,10 +4143,7 @@ function retireRun(args, store, options) {
|
|
|
4126
4143
|
const result = store.transaction((tx) => {
|
|
4127
4144
|
const task = requireTask(tx, reference.taskId);
|
|
4128
4145
|
assertTaskOpen(task);
|
|
4129
|
-
const actor = taskActor(options, task.id);
|
|
4130
|
-
if (actor === "leader") {
|
|
4131
|
-
throw usageError("Only the user or global Operator may retire an Agent Run.");
|
|
4132
|
-
}
|
|
4146
|
+
const actor = taskActor(tx, options, task.id);
|
|
4133
4147
|
let run = tx.getAgentRun(task.id, reference.localId);
|
|
4134
4148
|
if (run === null)
|
|
4135
4149
|
throw dataError(`Agent Run not found: ${task.id}/${reference.localId}.`);
|
|
@@ -4138,19 +4152,66 @@ function retireRun(args, store, options) {
|
|
|
4138
4152
|
return { task, run, changed: false };
|
|
4139
4153
|
}
|
|
4140
4154
|
if (run.status === "active") {
|
|
4141
|
-
|
|
4155
|
+
if (actor === "leader"
|
|
4156
|
+
&& taskLeaderActionRunId(tx, task.id, options.environment, options.yuiHome) === run.id) {
|
|
4157
|
+
throw usageError("A Task Leader cannot retire its own current authority Run.", usage);
|
|
4158
|
+
}
|
|
4159
|
+
const expectedProgressAt = requiredOption(parsed.options, parsed.options.has("--expected-progress-at")
|
|
4160
|
+
? "--expected-progress-at"
|
|
4161
|
+
: "--progress-at");
|
|
4162
|
+
if (parsed.options.has("--expected-progress-at") && parsed.options.has("--progress-at")) {
|
|
4163
|
+
throw usageError("--expected-progress-at and --progress-at are mutually exclusive.", usage);
|
|
4164
|
+
}
|
|
4165
|
+
const agentId = requiredOption(parsed.options, "--agent-id");
|
|
4166
|
+
const adapterId = requiredOption(parsed.options, "--adapter-id");
|
|
4167
|
+
const nativeSessionId = parsed.options.get("--native-session-id");
|
|
4168
|
+
const launchId = parsed.options.get("--launch-id");
|
|
4169
|
+
const sessions = tx.getTaskRoleSessionSet(task.id, run.roleName);
|
|
4170
|
+
const session = sessions?.sessions[run.effective.agentId];
|
|
4171
|
+
if (session?.nativeSessionId !== undefined && nativeSessionId === undefined) {
|
|
4172
|
+
throw usageError("--native-session-id is required for this active Run.", usage);
|
|
4173
|
+
}
|
|
4174
|
+
if (session?.nativeSessionId === undefined && launchId === undefined) {
|
|
4175
|
+
throw usageError("--launch-id is required for an opaque active Run.", usage);
|
|
4176
|
+
}
|
|
4177
|
+
const terminal = retireExactActiveAgentRun(tx, {
|
|
4142
4178
|
taskId: task.id,
|
|
4143
4179
|
roleName: run.roleName,
|
|
4144
|
-
agentId: run.effective.agentId,
|
|
4145
4180
|
runId: run.id,
|
|
4146
|
-
|
|
4147
|
-
|
|
4181
|
+
agentId,
|
|
4182
|
+
adapterId,
|
|
4183
|
+
...(nativeSessionId === undefined ? {} : { nativeSessionId }),
|
|
4184
|
+
...(launchId === undefined ? {} : { launchId }),
|
|
4185
|
+
expectedProgressAt,
|
|
4186
|
+
reason: `Agent Run retired: ${reason}`
|
|
4148
4187
|
}, now);
|
|
4149
4188
|
if (terminal.disposition !== "applied" || terminal.run === null) {
|
|
4150
|
-
throw usageError(
|
|
4189
|
+
throw usageError(terminal.disposition === "blocked"
|
|
4190
|
+
? `Agent Run retirement is blocked: ${run.id}/${terminal.reason ?? "unsafe"}.`
|
|
4191
|
+
: `Agent Run changed during retirement: ${run.id}/${terminal.reason ?? "obsolete"}.`);
|
|
4151
4192
|
}
|
|
4152
4193
|
run = terminal.run;
|
|
4153
4194
|
}
|
|
4195
|
+
recordTaskEvent(tx, task.id, "run.retired", {
|
|
4196
|
+
runId: run.id,
|
|
4197
|
+
reason,
|
|
4198
|
+
...(parsed.options.get("--expected-progress-at") === undefined
|
|
4199
|
+
&& parsed.options.get("--progress-at") === undefined
|
|
4200
|
+
? {}
|
|
4201
|
+
: {
|
|
4202
|
+
expectedProgressAt: parsed.options.get("--expected-progress-at")
|
|
4203
|
+
?? parsed.options.get("--progress-at")
|
|
4204
|
+
}),
|
|
4205
|
+
...(parsed.options.get("--native-session-id") === undefined
|
|
4206
|
+
? {}
|
|
4207
|
+
: { nativeSessionId: parsed.options.get("--native-session-id") }),
|
|
4208
|
+
...(parsed.options.get("--launch-id") === undefined
|
|
4209
|
+
? {}
|
|
4210
|
+
: { launchId: parsed.options.get("--launch-id") }),
|
|
4211
|
+
...(actor === "leader"
|
|
4212
|
+
? leaderActionEventPayload(tx, task.id, options)
|
|
4213
|
+
: { retiredBy: actor })
|
|
4214
|
+
}, now);
|
|
4154
4215
|
tx.saveEvent(task.id, createTaskRecordRetirement({
|
|
4155
4216
|
eventId: tx.nextEventId(task.id),
|
|
4156
4217
|
taskId: task.id,
|
|
@@ -4289,7 +4350,7 @@ function settleStaleFinalReviewRun(args, store, options) {
|
|
|
4289
4350
|
const task = requireTask(tx, run.taskId);
|
|
4290
4351
|
if (task.status !== "active")
|
|
4291
4352
|
throw usageError(`Task is not active: ${task.id}.`);
|
|
4292
|
-
if (taskActor(options, task.id) !== "leader") {
|
|
4353
|
+
if (taskActor(tx, options, task.id) !== "leader") {
|
|
4293
4354
|
throw usageError("Only the Task Leader may settle a stale final review Run.");
|
|
4294
4355
|
}
|
|
4295
4356
|
const round = tx.getReviewRound(task.id, run.reviewRoundId);
|
|
@@ -4978,7 +5039,7 @@ function retryFailedReviewRun(previous, store, options, now) {
|
|
|
4978
5039
|
throw usageError(`Review Run ${run.id} still owns an unsettled Provider continuation; `
|
|
4979
5040
|
+ "reconcile it before retrying the Lane.");
|
|
4980
5041
|
}
|
|
4981
|
-
if (taskActor(options, task.id) !== "leader") {
|
|
5042
|
+
if (taskActor(tx, options, task.id) !== "leader") {
|
|
4982
5043
|
throw usageError("Only the Task Leader may retry a failed final review Run.");
|
|
4983
5044
|
}
|
|
4984
5045
|
const round = tx.getReviewRound(task.id, run.reviewRoundId);
|
|
@@ -5205,7 +5266,7 @@ function recoverRun(args, store, options) {
|
|
|
5205
5266
|
const task = requireTask(tx, active.taskId);
|
|
5206
5267
|
if (task.status !== "active")
|
|
5207
5268
|
throw usageError(inactiveTaskMessage(task, "recovering a run"));
|
|
5208
|
-
if (taskActor(options, task.id) !== "leader") {
|
|
5269
|
+
if (taskActor(tx, options, task.id) !== "leader") {
|
|
5209
5270
|
throw usageError("Only the Task Leader may control exact Agent Run recovery.");
|
|
5210
5271
|
}
|
|
5211
5272
|
const roleName = parsed.options.get("--role") ?? active.roleName;
|
|
@@ -5308,18 +5369,27 @@ function showRun(args, store, options) {
|
|
|
5308
5369
|
const retirement = tx.listEvents(run.taskId)
|
|
5309
5370
|
.map(taskRecordRetirement)
|
|
5310
5371
|
.find((entry) => entry?.recordKind === "agent-run" && entry.recordId === run.id) ?? null;
|
|
5311
|
-
|
|
5372
|
+
const allRejectedYieldAttempts = tx.listEvents(run.taskId)
|
|
5373
|
+
.map(rejectedYieldAttemptFromTaskEvent)
|
|
5374
|
+
.filter((attempt) => (attempt !== null && attempt.runId === run.id));
|
|
5375
|
+
return {
|
|
5376
|
+
run,
|
|
5377
|
+
recovery: projectRunRecovery(facts),
|
|
5378
|
+
retirement,
|
|
5379
|
+
rejectedYieldAttemptCount: allRejectedYieldAttempts.length,
|
|
5380
|
+
rejectedYieldAttempts: allRejectedYieldAttempts.slice(-16)
|
|
5381
|
+
};
|
|
5312
5382
|
});
|
|
5313
5383
|
if (asJson) {
|
|
5314
5384
|
return { kind: "output", output: `${JSON.stringify(data, null, 2)}\n`, data };
|
|
5315
5385
|
}
|
|
5316
5386
|
return {
|
|
5317
5387
|
kind: "output",
|
|
5318
|
-
output: renderRunShow(data.run, data.recovery, data.retirement),
|
|
5388
|
+
output: renderRunShow(data.run, data.recovery, data.retirement, data.rejectedYieldAttemptCount, data.rejectedYieldAttempts),
|
|
5319
5389
|
data
|
|
5320
5390
|
};
|
|
5321
5391
|
}
|
|
5322
|
-
function renderRunShow(run, recovery, retirement) {
|
|
5392
|
+
function renderRunShow(run, recovery, retirement, rejectedYieldAttemptCount, rejectedYieldAttempts) {
|
|
5323
5393
|
const lines = [
|
|
5324
5394
|
`Run: ${run.id}`,
|
|
5325
5395
|
`Task: ${run.taskId}`,
|
|
@@ -5339,7 +5409,19 @@ function renderRunShow(run, recovery, retirement) {
|
|
|
5339
5409
|
: [`Provider accepted (durable): ${run.deliveredAt}`]),
|
|
5340
5410
|
...(run.summary === undefined || run.summary.trim().length === 0
|
|
5341
5411
|
? []
|
|
5342
|
-
: [`Summary: ${run.summary}`])
|
|
5412
|
+
: [`Summary: ${run.summary}`]),
|
|
5413
|
+
...(rejectedYieldAttemptCount === 0
|
|
5414
|
+
? []
|
|
5415
|
+
: [
|
|
5416
|
+
`Rejected yield attempts: ${rejectedYieldAttempts.length} shown of ${rejectedYieldAttemptCount} (unaccepted diagnostic evidence only)`,
|
|
5417
|
+
...rejectedYieldAttempts.slice(-5).flatMap((attempt) => [
|
|
5418
|
+
` ${attempt.attemptedAt}: ${attempt.rejectionReason} (${attempt.attemptDigest.slice(0, 16)})`,
|
|
5419
|
+
` Reviewer output: ${truncateRunShowText(attempt.summary)}`,
|
|
5420
|
+
` Checks: ${attempt.checks.length === 0
|
|
5421
|
+
? "none"
|
|
5422
|
+
: attempt.checks.map(({ name, outcome }) => `${name}:${outcome}`).join(", ")}`
|
|
5423
|
+
])
|
|
5424
|
+
])
|
|
5343
5425
|
];
|
|
5344
5426
|
if (recovery.canonicalProgressAt !== null) {
|
|
5345
5427
|
lines.push(`Canonical recovery fence (Yui durable CAS): ${recovery.canonicalProgressAt}`, ...(recovery.canonicalProgressEvidence === undefined
|
|
@@ -5370,6 +5452,10 @@ function renderRunShow(run, recovery, retirement) {
|
|
|
5370
5452
|
}
|
|
5371
5453
|
return `${lines.join("\n")}\n`;
|
|
5372
5454
|
}
|
|
5455
|
+
function truncateRunShowText(value) {
|
|
5456
|
+
const normalized = value.replaceAll(/\s+/gu, " ").trim();
|
|
5457
|
+
return normalized.length <= 400 ? normalized : `${normalized.slice(0, 399)}…`;
|
|
5458
|
+
}
|
|
5373
5459
|
/**
|
|
5374
5460
|
* Issue 04: builds the terminal yield outcome from the command inputs. The
|
|
5375
5461
|
* same construction feeds both the first commit and the idempotent replay, so
|
|
@@ -5462,6 +5548,70 @@ function yieldRunStatus(args, store, options) {
|
|
|
5462
5548
|
+ `Request: ${run.yieldReceipt.requestId}\n`
|
|
5463
5549
|
+ `Committed: ${run.yieldReceipt.committedAt}\n`, { receipt: run.yieldReceipt });
|
|
5464
5550
|
}
|
|
5551
|
+
function recordRejectedReviewYield(store, input) {
|
|
5552
|
+
if (input.run.purpose !== "review" || input.run.reviewRoundId === undefined) {
|
|
5553
|
+
throw new Error(`Only a Review Run can record rejected yield evidence: ${input.run.id}.`);
|
|
5554
|
+
}
|
|
5555
|
+
const receiptId = agentRunDeliveryReceiptId(input.run);
|
|
5556
|
+
const sessions = store.getTaskRoleSessionSet(input.run.taskId, input.run.roleName);
|
|
5557
|
+
const durableSession = sessions?.sessions[input.run.effective.agentId];
|
|
5558
|
+
const attempt = createRejectedYieldAttempt({
|
|
5559
|
+
taskId: input.run.taskId,
|
|
5560
|
+
runId: input.run.id,
|
|
5561
|
+
roleName: input.run.roleName,
|
|
5562
|
+
reviewRoundId: input.run.reviewRoundId,
|
|
5563
|
+
receiptId,
|
|
5564
|
+
rejectionReason: input.rejectionReason,
|
|
5565
|
+
summary: input.outcome.summary,
|
|
5566
|
+
...(input.outcome.reviewResult === undefined
|
|
5567
|
+
? {}
|
|
5568
|
+
: { reviewResult: input.outcome.reviewResult }),
|
|
5569
|
+
...(input.nativeSessionId === undefined
|
|
5570
|
+
? {}
|
|
5571
|
+
: { nativeSessionId: input.nativeSessionId }),
|
|
5572
|
+
...(input.launchId === undefined ? {} : { launchId: input.launchId }),
|
|
5573
|
+
...(durableSession?.nativeSessionId === undefined
|
|
5574
|
+
? {}
|
|
5575
|
+
: { durableNativeSessionId: durableSession.nativeSessionId }),
|
|
5576
|
+
...(durableSession?.launchId === undefined
|
|
5577
|
+
? {}
|
|
5578
|
+
: { durableLaunchId: durableSession.launchId }),
|
|
5579
|
+
...(sessions?.inFlight?.runId === undefined
|
|
5580
|
+
? {}
|
|
5581
|
+
: { inFlightRunId: sessions.inFlight.runId }),
|
|
5582
|
+
...(sessions?.inFlight?.receiptId === undefined
|
|
5583
|
+
? {}
|
|
5584
|
+
: { inFlightReceiptId: sessions.inFlight.receiptId }),
|
|
5585
|
+
...(input.run.assignment.contextSnapshotRef === undefined
|
|
5586
|
+
? {}
|
|
5587
|
+
: { contextSnapshot: input.run.assignment.contextSnapshotRef }),
|
|
5588
|
+
activeRun: input.activeRun === null
|
|
5589
|
+
? null
|
|
5590
|
+
: {
|
|
5591
|
+
id: input.activeRun.id,
|
|
5592
|
+
receiptId: agentRunDeliveryReceiptId(input.activeRun),
|
|
5593
|
+
...(input.activeRun.assignment.contextSnapshotRef === undefined
|
|
5594
|
+
? {}
|
|
5595
|
+
: { contextSnapshot: input.activeRun.assignment.contextSnapshotRef })
|
|
5596
|
+
},
|
|
5597
|
+
attemptedAt: input.now
|
|
5598
|
+
});
|
|
5599
|
+
const existing = store.listEvents(input.run.taskId).find((event) => (event.type === RUN_YIELD_REJECTED_EVENT
|
|
5600
|
+
&& event.payload.runId === input.run.id
|
|
5601
|
+
&& event.payload.receiptId === receiptId
|
|
5602
|
+
&& event.payload.attemptDigest === attempt.attemptDigest));
|
|
5603
|
+
if (existing !== undefined) {
|
|
5604
|
+
const persisted = rejectedYieldAttemptFromTaskEvent(existing);
|
|
5605
|
+
if (persisted === null) {
|
|
5606
|
+
throw new Error(`Rejected yield attempt is malformed: ${existing.id}.`);
|
|
5607
|
+
}
|
|
5608
|
+
return { attempt: persisted, event: existing, created: false };
|
|
5609
|
+
}
|
|
5610
|
+
const event = createTaskEvent(store.nextEventId(input.run.taskId), input.run.taskId, RUN_YIELD_REJECTED_EVENT, rejectedYieldAttemptEventPayload(attempt), input.now);
|
|
5611
|
+
store.saveEvent(input.run.taskId, event);
|
|
5612
|
+
routeRoleEvent(store, event, input.run.roleName, "run-yield-rejected", input.now);
|
|
5613
|
+
return { attempt, event, created: true };
|
|
5614
|
+
}
|
|
5465
5615
|
function yieldRun(args, store, options) {
|
|
5466
5616
|
const usage = "Task run yield usage: yui task run yield <task>/<run> (--summary <text>|--summary-file <path|->).";
|
|
5467
5617
|
const parsed = parseTail(args, new Set(["--summary", "--summary-file"]), usage);
|
|
@@ -5491,8 +5641,6 @@ function yieldRun(args, store, options) {
|
|
|
5491
5641
|
throw usageError(inactiveTaskMessage(task, "yielding a run"));
|
|
5492
5642
|
const role = requireRole(tx, task.id, active.roleName);
|
|
5493
5643
|
const pointer = activeRunPointer(tx, active);
|
|
5494
|
-
if (pointer?.id !== active.id)
|
|
5495
|
-
throw usageError(`Run is not active for ${task.id}/${role.name}: ${active.id}.`);
|
|
5496
5644
|
const taskFinalContract = active.purpose === "execution"
|
|
5497
5645
|
&& active.workItemId !== undefined
|
|
5498
5646
|
? taskFinalReviewContractForMutation(tx, task.id, options)
|
|
@@ -5545,6 +5693,27 @@ function yieldRun(args, store, options) {
|
|
|
5545
5693
|
: { reviewResult: yieldOutcome.reviewResult })
|
|
5546
5694
|
}, now);
|
|
5547
5695
|
if (terminalization.disposition !== "applied" || terminalization.run === null) {
|
|
5696
|
+
if (active.purpose === "review" && active.reviewRoundId !== undefined) {
|
|
5697
|
+
const rejected = recordRejectedReviewYield(tx, {
|
|
5698
|
+
run: active,
|
|
5699
|
+
activeRun: pointer,
|
|
5700
|
+
rejectionReason: terminalization.reason ?? "obsolete",
|
|
5701
|
+
outcome: yieldOutcome,
|
|
5702
|
+
...(options.environment?.YUI_NATIVE_SESSION_ID === undefined
|
|
5703
|
+
? {}
|
|
5704
|
+
: { nativeSessionId: options.environment.YUI_NATIVE_SESSION_ID }),
|
|
5705
|
+
...(options.environment?.YUI_LAUNCH_ID === undefined
|
|
5706
|
+
? {}
|
|
5707
|
+
: { launchId: options.environment.YUI_LAUNCH_ID }),
|
|
5708
|
+
now
|
|
5709
|
+
});
|
|
5710
|
+
return {
|
|
5711
|
+
kind: "rejected",
|
|
5712
|
+
run: active,
|
|
5713
|
+
rejected,
|
|
5714
|
+
notifyLeader: rejected.created
|
|
5715
|
+
};
|
|
5716
|
+
}
|
|
5548
5717
|
throw usageError(`Run ${active.id} no longer matches its exact execution fence: `
|
|
5549
5718
|
+ `${terminalization.reason ?? "obsolete"}.`);
|
|
5550
5719
|
}
|
|
@@ -5727,6 +5896,7 @@ function yieldRun(args, store, options) {
|
|
|
5727
5896
|
if (receipt !== null) {
|
|
5728
5897
|
tx.saveAgentRun(receipt);
|
|
5729
5898
|
return {
|
|
5899
|
+
kind: "yielded",
|
|
5730
5900
|
run: receipt,
|
|
5731
5901
|
reviewDispatch,
|
|
5732
5902
|
notifyLeader: leaderHandoff !== null
|
|
@@ -5734,11 +5904,21 @@ function yieldRun(args, store, options) {
|
|
|
5734
5904
|
}
|
|
5735
5905
|
}
|
|
5736
5906
|
return {
|
|
5907
|
+
kind: "yielded",
|
|
5737
5908
|
run: terminal,
|
|
5738
5909
|
reviewDispatch,
|
|
5739
5910
|
notifyLeader: leaderHandoff !== null
|
|
5740
5911
|
};
|
|
5741
5912
|
});
|
|
5913
|
+
if (yielded.kind === "rejected") {
|
|
5914
|
+
if (yielded.notifyLeader) {
|
|
5915
|
+
notifyMailbox(options.runtime, leaderMailbox(yielded.run.taskId), yielded.run.taskId);
|
|
5916
|
+
}
|
|
5917
|
+
throw usageError(`Run ${yielded.run.id} no longer matches its exact execution fence: `
|
|
5918
|
+
+ `${yielded.rejected.attempt.rejectionReason}. `
|
|
5919
|
+
+ `Rejected Reviewer output was recorded as ${yielded.rejected.event.id} `
|
|
5920
|
+
+ "(unaccepted diagnostic evidence only).");
|
|
5921
|
+
}
|
|
5742
5922
|
if (yielded.notifyLeader) {
|
|
5743
5923
|
notifyMailbox(options.runtime, leaderMailbox(yielded.run.taskId), yielded.run.taskId);
|
|
5744
5924
|
}
|
|
@@ -6267,6 +6447,8 @@ export function dispatchPreparedReviewRound(taskId, reviewRoundId, store, option
|
|
|
6267
6447
|
export function failPendingReviewRound(taskId, reviewRoundId, summary, store, options = {}) {
|
|
6268
6448
|
const now = clock(options);
|
|
6269
6449
|
const failed = store.transaction((tx) => {
|
|
6450
|
+
const task = requireTask(tx, taskId);
|
|
6451
|
+
taskActor(tx, options, task.id);
|
|
6270
6452
|
const round = tx.getReviewRound(taskId, reviewRoundId);
|
|
6271
6453
|
if (round === null)
|
|
6272
6454
|
throw usageError(`ReviewRound not found: ${taskId}/${reviewRoundId}.`);
|
|
@@ -6565,8 +6747,8 @@ function assertTaskOpen(task) {
|
|
|
6565
6747
|
if (task.status === "retired")
|
|
6566
6748
|
throw usageError(`Task is retired: ${task.id}.`);
|
|
6567
6749
|
}
|
|
6568
|
-
function taskActor(options, taskId) {
|
|
6569
|
-
return
|
|
6750
|
+
function taskActor(store, options, taskId) {
|
|
6751
|
+
return resolveTaskLocalActor(store, options.environment, taskId, options.yuiHome);
|
|
6570
6752
|
}
|
|
6571
6753
|
function taskRoleDispatchMode(store, taskId, roleName, sessions, agentId, effective) {
|
|
6572
6754
|
return roleSessionDispatchModeWithConversationSwitch(sessions, store.listEvents(taskId), store.getWorkMailbox({ kind: "role", taskId, roleName }), roleName, agentId, effective);
|
|
@@ -6741,7 +6923,7 @@ function taskBriefCommand(args, store, options) {
|
|
|
6741
6923
|
const task = requireTask(tx, parsed.positionals[0]);
|
|
6742
6924
|
assertTaskOpen(task);
|
|
6743
6925
|
const existing = tx.getTaskBrief(task.id);
|
|
6744
|
-
const updatedBy = taskActor(options, task.id);
|
|
6926
|
+
const updatedBy = taskActor(tx, options, task.id);
|
|
6745
6927
|
const brief = existing === null
|
|
6746
6928
|
? createTaskBrief({
|
|
6747
6929
|
objective: requiredText(parsed.options.get("--objective"), "--objective"),
|
|
@@ -6792,7 +6974,7 @@ function taskDecisionCommand(args, store, options) {
|
|
|
6792
6974
|
const result = store.transaction((tx) => {
|
|
6793
6975
|
const task = requireTask(tx, parsed.positionals[0]);
|
|
6794
6976
|
assertTaskOpen(task);
|
|
6795
|
-
const actor = taskActor(options, task.id);
|
|
6977
|
+
const actor = taskActor(tx, options, task.id);
|
|
6796
6978
|
const decision = createDecision(tx.nextDecisionId(task.id), task.id, title, rationale, now);
|
|
6797
6979
|
tx.saveDecision(task.id, decision);
|
|
6798
6980
|
recordTaskEvent(tx, task.id, "decision.recorded", {
|
|
@@ -6863,7 +7045,7 @@ function taskDecisionCommand(args, store, options) {
|
|
|
6863
7045
|
const result = store.transaction((tx) => {
|
|
6864
7046
|
const task = requireTask(tx, parsed.positionals[0]);
|
|
6865
7047
|
assertTaskOpen(task);
|
|
6866
|
-
const actor = taskActor(options, task.id);
|
|
7048
|
+
const actor = taskActor(tx, options, task.id);
|
|
6867
7049
|
const existing = tx.getDecision(task.id, parsed.positionals[1]);
|
|
6868
7050
|
if (existing === null)
|
|
6869
7051
|
throw dataError(`Decision not found: ${parsed.positionals[1]}.`);
|
|
@@ -6901,7 +7083,7 @@ function taskMilestoneCommand(args, store, options) {
|
|
|
6901
7083
|
const result = store.transaction((tx) => {
|
|
6902
7084
|
const task = requireTask(tx, parsed.positionals[0]);
|
|
6903
7085
|
assertTaskOpen(task);
|
|
6904
|
-
if (taskActor(options, task.id) !== "leader") {
|
|
7086
|
+
if (taskActor(tx, options, task.id) !== "leader") {
|
|
6905
7087
|
throw usageError("Only the Task Leader can add a Milestone.");
|
|
6906
7088
|
}
|
|
6907
7089
|
const milestone = createMilestone(tx.nextMilestoneId(task.id), task.id, title, summary, now);
|