@zq-silk/yui 0.2.0 → 0.4.2
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/ARCHITECTURE.md +603 -133
- package/README.md +806 -31
- package/dist/agent/agent.js +2 -1
- package/dist/agent/argumentPolicy.js +3 -1
- package/dist/agent/launchEnvironment.js +106 -0
- package/dist/agent/managedRuntimeEnvironment.js +34 -0
- package/dist/brief/taskBrief.js +11 -1
- package/dist/cli/agentConfigurationPicker.js +287 -0
- package/dist/cli/commandCatalog.js +488 -60
- package/dist/cli/completion.js +146 -22
- package/dist/cli/helpRenderer.js +3 -1
- package/dist/cli/interactionCandidates.js +53 -15
- package/dist/cli/interactionPolicy.js +267 -30
- package/dist/cli/interactiveSelection.js +6 -2
- package/dist/cli/invocationRouter.js +5 -1
- package/dist/cli/operatorWizard.js +87 -0
- package/dist/cli/roleOptionCatalog.js +1 -0
- package/dist/cli/roleWizard.js +185 -21
- package/dist/cli/updateCommand.js +62 -19
- package/dist/cli/updateOrchestrator.js +539 -0
- package/dist/cli/updatePorts.js +1119 -0
- package/dist/cli/upgradeCommand.js +112 -0
- package/dist/cli.js +1420 -86
- package/dist/commands/agentCommands.js +146 -3
- package/dist/commands/configCommands.js +126 -0
- package/dist/commands/controllerCommands.js +365 -0
- package/dist/commands/globalRoleCommands.js +168 -126
- package/dist/commands/jobCommands.js +18 -8
- package/dist/commands/operatorCommands.js +159 -9
- package/dist/commands/profileCommands.js +203 -0
- package/dist/commands/projectCommands.js +650 -0
- package/dist/commands/roleConfiguration.js +85 -24
- package/dist/commands/roleRuntimeGuard.js +12 -0
- package/dist/commands/roleSkillValidation.js +47 -0
- package/dist/commands/taskActor.js +127 -0
- package/dist/commands/taskCommands.js +4201 -313
- package/dist/commands/taskCompletionGate.js +131 -0
- package/dist/commands/taskContextCommand.js +244 -30
- package/dist/commands/taskInputCommands.js +177 -59
- package/dist/commands/taskIntegrationCommands.js +303 -0
- package/dist/commands/taskOverviewCommand.js +363 -0
- package/dist/commands/taskRoleRuntimeStatus.js +125 -19
- package/dist/commands/textInput.js +15 -0
- package/dist/completion/completionInstaller.js +26 -22
- package/dist/config/yuiConfig.js +4 -3
- package/dist/context/dispatchContext.js +90 -38
- package/dist/context/roleSessionContext.js +119 -0
- package/dist/controller/claudeLifecycleHook.js +203 -0
- package/dist/controller/clientRuntime.js +408 -56
- package/dist/controller/codexLifecycleHook.js +108 -0
- package/dist/controller/controller.js +1089 -32
- package/dist/controller/domainIdentity.js +505 -0
- package/dist/controller/ephemeralResourceReaper.js +131 -0
- package/dist/controller/fileSchedulerStoreAdapter.js +2153 -103
- package/dist/controller/providerHookRunFence.js +127 -0
- package/dist/controller/resourceCleanupLinux.js +286 -0
- package/dist/controller/resourceInventory.js +531 -0
- package/dist/controller/resourceInventoryLinux.js +610 -0
- package/dist/controller/runtime.js +629 -10
- package/dist/controller/runtimeEventInbox.js +564 -0
- package/dist/controller/runtimeEventProcessor.js +248 -0
- package/dist/controller/runtimeLaunchCoordinator.js +477 -0
- package/dist/controller/sessionNotify.js +121 -78
- package/dist/coordination/deadlineScheduler.js +15 -0
- package/dist/coordination/mailboxScheduler.js +108 -0
- package/dist/coordination/workMailbox.js +329 -0
- package/dist/coordination/workMailboxQueue.js +86 -0
- package/dist/core/controllerClient.js +19 -5
- package/dist/core/controllerEndpoint.js +37 -0
- package/dist/core/controllerServer.js +218 -10
- package/dist/core/protocol.js +6 -2
- package/dist/decision/decision.js +2 -1
- package/dist/doctor/doctor.js +681 -32
- package/dist/domain/validation.js +53 -0
- package/dist/errors/cliError.js +5 -3
- package/dist/event/taskEvent.js +7 -3
- package/dist/execution/codexThreadNaming.js +160 -0
- package/dist/execution/executionGroup.js +579 -0
- package/dist/executor/agentAdapter.js +255 -40
- package/dist/executor/agentConfigurationCatalog.js +326 -0
- package/dist/executor/agentConfigurationProbe.js +506 -0
- package/dist/executor/agentExecutor.js +625 -10
- package/dist/executor/codexConfigConflict.js +290 -0
- package/dist/executor/effectiveLaunch.js +340 -0
- package/dist/executor/executorRegistry.js +238 -36
- package/dist/executor/fileRoleLaunchPlanner.js +550 -40
- package/dist/executor/turnCompletion.js +126 -0
- package/dist/input/inputRequest.js +30 -9
- package/dist/integration/changeSet.js +36 -0
- package/dist/integration/checkResult.js +24 -0
- package/dist/integration/gitIntegrationService.js +695 -0
- package/dist/integration/integrationAttempt.js +142 -0
- package/dist/interaction/operatorPresentation.js +96 -0
- package/dist/lifecycle/canonicalLifecycleEvent.js +342 -0
- package/dist/lifecycle/exactRunTerminalization.js +572 -0
- package/dist/lifecycle/providerLifecycleMapping.js +190 -0
- package/dist/lifecycle/taskRoleSessionReset.js +124 -0
- package/dist/message/message.js +23 -7
- package/dist/milestone/milestone.js +2 -1
- package/dist/operator/operatorSessionHistory.js +124 -0
- package/dist/output/agentConfigurationPresentation.js +43 -0
- package/dist/output/rolePresentation.js +34 -10
- package/dist/output/terminal.js +8 -0
- package/dist/output/timePresentation.js +55 -0
- package/dist/profile/agentProfile.js +128 -0
- package/dist/repository/gitWorkspace.js +578 -24
- package/dist/repository/project.js +213 -0
- package/dist/repository/taskWorkspaceCoordinator.js +392 -0
- package/dist/repository/taskWorkspacePreparer.js +1688 -191
- package/dist/review/reviewConfig.js +11 -0
- package/dist/review/reviewRound.js +399 -0
- package/dist/review/taskFinalReviewContract.js +90 -0
- package/dist/role/role.js +124 -23
- package/dist/run/agentRun.js +155 -12
- package/dist/run/runIdentity.js +82 -0
- package/dist/runtime/exactControlPlane.js +472 -0
- package/dist/runtime/index.js +8 -0
- package/dist/runtime/lifecycleReservation.js +38 -0
- package/dist/runtime/ports.js +11 -0
- package/dist/runtime/preallocatedNativeSession.js +13 -0
- package/dist/runtime/promptEnvelope.js +30 -0
- package/dist/runtime/runtimeBinding.js +31 -0
- package/dist/runtime/runtimeOwner.js +14 -0
- package/dist/runtime/sessionLaunchRequest.js +62 -0
- package/dist/runtime/sessionTitle.js +54 -0
- package/dist/runtime/taskRuntimeIsolation.js +643 -0
- package/dist/runtime/tmuxAdapters.js +315 -0
- package/dist/runtime/turnCompletion.js +3 -0
- package/dist/runtime/validation.js +23 -0
- package/dist/scheduler/activeRoleRunDelivery.js +342 -32
- package/dist/scheduler/activeTaskProgress.js +63 -0
- package/dist/scheduler/leaderFailure.js +2 -1
- package/dist/scheduler/leaderWakeupProcessor.js +307 -66
- package/dist/scheduler/operatorInputNotificationProcessor.js +109 -46
- package/dist/scheduler/operatorNotification.js +44 -2
- package/dist/scheduler/ports.js +28 -1
- package/dist/scheduler/roleRunLiveness.js +131 -25
- package/dist/scheduler/roleRunStall.js +951 -0
- package/dist/scheduler/taskExecutionProjection.js +544 -0
- package/dist/scheduler/wakeupQueue.js +3 -0
- package/dist/setup/setupCommand.js +302 -52
- package/dist/storage/compatibleTaskStore.js +102 -0
- package/dist/storage/migration/baseline.js +78 -0
- package/dist/storage/migration/classifier.js +51 -0
- package/dist/storage/migration/compatibleCodec.js +53 -0
- package/dist/storage/migration/engine.js +147 -0
- package/dist/storage/migration/index.js +33 -0
- package/dist/storage/migration/planner.js +154 -0
- package/dist/storage/migration/productionRegistry.js +486 -0
- package/dist/storage/migration/registry.js +169 -0
- package/dist/storage/migration/report.js +54 -0
- package/dist/storage/migration/types.js +31 -0
- package/dist/storage/storageSchema.js +147 -123
- package/dist/storage/storageVersions.js +11 -0
- package/dist/storage/taskStore.js +1793 -197
- package/dist/storage/upgrade/homeClassification.js +156 -0
- package/dist/storage/upgrade/homeMigrationTarget.js +595 -0
- package/dist/storage/upgrade/offlineUpgradeInventory.js +315 -0
- package/dist/storage/upgrade/productionMigrationRegistry.js +6 -0
- package/dist/storage/upgrade/recordVersionScan.js +176 -0
- package/dist/storage/upgrade/recordVersions.js +159 -0
- package/dist/storage/upgrade/switchProgress.js +80 -0
- package/dist/storage/upgrade/upgradeOrchestrator.js +948 -0
- package/dist/storage/upgrade/upgradeReceipt.js +161 -0
- package/dist/storage/upgradeCoordination.js +186 -0
- package/dist/storage/upgradeFence.js +366 -0
- package/dist/task/task.js +132 -26
- package/dist/task/taskRecordReference.js +66 -0
- package/dist/tmux/commandExecutor.js +75 -2
- package/dist/tmux/tmuxManager.js +747 -49
- package/dist/version.js +23 -0
- package/dist/web/assets/assetManifest.js +62 -0
- package/dist/web/assets/client/app.js +631 -0
- package/dist/web/assets/client/components.js +605 -0
- package/dist/web/assets/client/dom.js +14 -0
- package/dist/web/assets/client/format.js +28 -0
- package/dist/web/assets/client/i18n.js +494 -0
- package/dist/web/assets/client/markdown.js +114 -0
- package/dist/web/assets/client/theme.js +32 -0
- package/dist/web/assets/client/view.js +458 -0
- package/dist/web/assets/fontData.js +12 -0
- package/dist/web/assets/fonts.js +12 -0
- package/dist/web/assets/shell.js +114 -0
- package/dist/web/assets/styles/cards.js +135 -0
- package/dist/web/assets/styles/layout.js +47 -0
- package/dist/web/assets/styles/markdown.js +29 -0
- package/dist/web/assets/styles/responsive.js +39 -0
- package/dist/web/assets/styles/tokens.js +101 -0
- package/dist/web/assets/styles/widgets.js +147 -0
- package/dist/web/tmuxWebTerminal.js +158 -0
- package/dist/web/webServer.js +463 -0
- package/dist/web/webSnapshot.js +148 -0
- package/dist/workItem/workItem.js +642 -23
- package/dist/workspace/gitChangeSetCapture.js +86 -0
- package/dist/workspace/workItemChangeSetManager.js +445 -0
- package/dist/worktree/managedWorkspace.js +202 -0
- package/docs/task-local-identity.md +62 -0
- package/i18n/README.zh-CN.md +406 -31
- package/package.json +10 -2
- package/skills/yui-leader/SKILL.md +601 -39
- package/skills/yui-operator/SKILL.md +255 -34
- package/skills/yui-reviewer/SKILL.md +57 -0
- package/skills/yui-worker/SKILL.md +214 -17
- package/dist/commands/repositoryCommands.js +0 -86
- package/dist/operator/operatorContext.js +0 -66
- package/dist/repository/repository.js +0 -55
- package/dist/scheduler/archivedTaskRuntime.js +0 -12
- package/dist/worktree/roleWorkspace.js +0 -62
|
@@ -1,11 +1,53 @@
|
|
|
1
|
+
export const CURRENT_OPERATOR_NOTIFICATION_SCHEMA_VERSION = 1;
|
|
1
2
|
export function createLeaderRecoveryNotification(taskId, message, now, existing) {
|
|
2
3
|
const timestamp = now.toISOString();
|
|
3
4
|
return {
|
|
4
|
-
schemaVersion:
|
|
5
|
+
schemaVersion: CURRENT_OPERATOR_NOTIFICATION_SCHEMA_VERSION,
|
|
5
6
|
taskId: requiredText(taskId, "Task id"),
|
|
6
7
|
type: "leader-recovery-failed",
|
|
7
8
|
message: requiredText(message, "Operator notification message"),
|
|
8
|
-
createdAt: existing?.
|
|
9
|
+
createdAt: existing?.type === "leader-recovery-failed"
|
|
10
|
+
? existing.createdAt
|
|
11
|
+
: timestamp,
|
|
12
|
+
updatedAt: timestamp
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export function createTaskTerminalNotification(taskId, status, by, summary, now) {
|
|
16
|
+
const timestamp = now.toISOString();
|
|
17
|
+
return {
|
|
18
|
+
schemaVersion: CURRENT_OPERATOR_NOTIFICATION_SCHEMA_VERSION,
|
|
19
|
+
taskId: requiredText(taskId, "Task id"),
|
|
20
|
+
type: "task-terminal",
|
|
21
|
+
status,
|
|
22
|
+
by,
|
|
23
|
+
summary: requiredText(summary, "Task terminal summary"),
|
|
24
|
+
createdAt: timestamp,
|
|
25
|
+
updatedAt: timestamp
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export function createLeaderStallNotification(taskId, runId, progressAt, evidenceKey, now, existing) {
|
|
29
|
+
const timestamp = now.toISOString();
|
|
30
|
+
const previous = existing?.type === "leader-stalled"
|
|
31
|
+
&& existing.runId === runId
|
|
32
|
+
&& existing.progressAt === progressAt
|
|
33
|
+
? existing
|
|
34
|
+
: undefined;
|
|
35
|
+
return {
|
|
36
|
+
schemaVersion: CURRENT_OPERATOR_NOTIFICATION_SCHEMA_VERSION,
|
|
37
|
+
taskId: requiredText(taskId, "Task id"),
|
|
38
|
+
type: "leader-stalled",
|
|
39
|
+
message: requiredText([
|
|
40
|
+
`Leader Run ${runId} is truly stalled for Task ${taskId}.`,
|
|
41
|
+
`lastProgressAt=${progressAt}`,
|
|
42
|
+
`classification=truly-stalled`,
|
|
43
|
+
`evidence=${evidenceKey}`,
|
|
44
|
+
"Inspect the Task context and decide whether to continue, reset, retry, change Agent, or request user input; Controller performed no automatic action."
|
|
45
|
+
].join(" "), "Operator notification message"),
|
|
46
|
+
runId: requiredText(runId, "Leader Run id"),
|
|
47
|
+
progressAt: requiredText(progressAt, "Leader progress timestamp"),
|
|
48
|
+
classification: "truly-stalled",
|
|
49
|
+
evidenceKey: requiredText(evidenceKey, "Leader stall evidence"),
|
|
50
|
+
createdAt: previous?.createdAt ?? timestamp,
|
|
9
51
|
updatedAt: timestamp
|
|
10
52
|
};
|
|
11
53
|
}
|
package/dist/scheduler/ports.js
CHANGED
|
@@ -1 +1,28 @@
|
|
|
1
|
-
|
|
1
|
+
import { isTaskOwnedWorkspace } from "../worktree/managedWorkspace.js";
|
|
2
|
+
export function isSchedulerTaskWorkspaceReady(task, workspace) {
|
|
3
|
+
return isTaskOwnedWorkspace(workspace, task.id, task.cwd, task.projectBindings.map(({ projectId, directory }) => ({ projectId, directory })));
|
|
4
|
+
}
|
|
5
|
+
/** Resolves Tasks without a global scan for a dirty reconciliation pass. */
|
|
6
|
+
export function selectedSchedulerTasks(store, selection) {
|
|
7
|
+
if (selection === undefined || selection.full)
|
|
8
|
+
return [...store.listTasks()];
|
|
9
|
+
return [...selection.taskIds].flatMap((taskId) => {
|
|
10
|
+
const task = store.getTask(taskId);
|
|
11
|
+
return task === null ? [] : [task];
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
/** Resolves either every Role in a selected Task or only explicit Role keys. */
|
|
15
|
+
export function selectedSchedulerRoles(store, taskId, selection) {
|
|
16
|
+
if (selection === undefined
|
|
17
|
+
|| selection.full
|
|
18
|
+
|| selection.allRoleTaskIds.has(taskId)) {
|
|
19
|
+
return [...store.listRoles(taskId)];
|
|
20
|
+
}
|
|
21
|
+
const names = selection.rolesByTask.get(taskId);
|
|
22
|
+
if (names === undefined)
|
|
23
|
+
return [];
|
|
24
|
+
return [...names].flatMap((roleName) => {
|
|
25
|
+
const role = store.getRole(taskId, roleName);
|
|
26
|
+
return role === null ? [] : [role];
|
|
27
|
+
});
|
|
28
|
+
}
|
|
@@ -1,41 +1,147 @@
|
|
|
1
|
+
import { selectedSchedulerRoles, selectedSchedulerTasks } from "./ports.js";
|
|
2
|
+
import { formatTaskRecordReference } from "../task/taskRecordReference.js";
|
|
1
3
|
import { queueLeaderWakeup } from "./wakeupQueue.js";
|
|
4
|
+
import { currentRoleRunProgressAt, DEFAULT_EXECUTION_STALL_CANDIDATE_AGE_MS } from "./roleRunStall.js";
|
|
2
5
|
export const EXITED_ROLE_RUN_SUMMARY = "The role's tmux session exited before the run yielded.";
|
|
3
6
|
/**
|
|
4
7
|
* Lightweight liveness only: an active AgentRun whose tmux role is absent is
|
|
5
8
|
* failed, then the Leader is durably queued. No TTL, cooldown, or schedules.
|
|
6
9
|
*/
|
|
7
|
-
export async function reconcileExitedRoleRuns(store, delivery, now) {
|
|
10
|
+
export async function reconcileExitedRoleRuns(store, delivery, now, selection, excludedRunRefs = new Set(), liveStatuses, resourceEvidence) {
|
|
8
11
|
const failed = [];
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const status = await delivery.inspectRole({
|
|
16
|
-
taskId: task.id,
|
|
17
|
-
roleName: role.name,
|
|
18
|
-
agentId: role.activeAgentId,
|
|
19
|
-
adapterId: role.adapterId,
|
|
20
|
-
...(session?.nativeSessionId === undefined
|
|
21
|
-
? {}
|
|
22
|
-
: { nativeSessionId: session.nativeSessionId })
|
|
23
|
-
});
|
|
24
|
-
if (status === "present")
|
|
25
|
-
continue;
|
|
26
|
-
store.saveExitedRoleRun({
|
|
12
|
+
const candidates = selectedSchedulerTasks(store, selection).flatMap((task) => (selectedSchedulerRoles(store, task.id, selection).flatMap((role) => {
|
|
13
|
+
const run = store.getActiveAgentRun(task.id, role.name);
|
|
14
|
+
if (run === null)
|
|
15
|
+
return [];
|
|
16
|
+
const session = store.getRoleSession(task.id, role.name, run.effective.agentId);
|
|
17
|
+
return [{
|
|
27
18
|
task,
|
|
28
19
|
role,
|
|
29
20
|
run,
|
|
30
21
|
session,
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
22
|
+
inspection: {
|
|
23
|
+
taskId: task.id,
|
|
24
|
+
roleName: role.name,
|
|
25
|
+
agentId: run.effective.agentId,
|
|
26
|
+
adapterId: run.effective.adapterId,
|
|
27
|
+
runId: run.id,
|
|
28
|
+
progressAt: run.deliveredAt ?? run.createdAt,
|
|
29
|
+
...(session?.launchId === undefined ? {} : { launchId: session.launchId }),
|
|
30
|
+
...(session?.nativeSessionId === undefined
|
|
31
|
+
? {}
|
|
32
|
+
: { nativeSessionId: session.nativeSessionId })
|
|
33
|
+
}
|
|
34
|
+
}];
|
|
35
|
+
})));
|
|
36
|
+
if (candidates.length === 0)
|
|
37
|
+
return failed;
|
|
38
|
+
const completing = new Set(store.listPendingRuntimeTurnCompletions().map((completion) => (`${completion.taskId}\0${completion.roleName}\0${completion.runId}`)));
|
|
39
|
+
const eligible = candidates.filter(({ task, role, run }) => (!excludedRunRefs.has(formatTaskRecordReference(task.id, run.id, "agentRun"))
|
|
40
|
+
&& !completing.has(`${task.id}\0${role.name}\0${run.id}`)));
|
|
41
|
+
// Build one complete provider inventory for every active Run, including
|
|
42
|
+
// delivery-uncertain and completion-pending Runs. The stall phase reuses
|
|
43
|
+
// this snapshot so one scheduler pass never probes the same pane twice.
|
|
44
|
+
const batchSnapshot = liveStatuses !== undefined
|
|
45
|
+
&& candidates.every(({ task, role }) => liveStatuses.has(`${task.id}\0${role.name}`))
|
|
46
|
+
? {
|
|
47
|
+
statuses: liveStatuses,
|
|
48
|
+
resources: resourceEvidence ?? new Map()
|
|
49
|
+
}
|
|
50
|
+
: await inspectRoleStatuses(delivery, candidates, candidates.flatMap(({ task, role, run, session }) => (isResourceCandidate(task, run, now)
|
|
51
|
+
? [{
|
|
52
|
+
taskId: task.id,
|
|
53
|
+
roleName: role.name,
|
|
54
|
+
runId: run.id,
|
|
55
|
+
agentId: run.effective.agentId,
|
|
56
|
+
adapterId: run.effective.adapterId,
|
|
57
|
+
progressAt: currentRoleRunProgressAt(store, task.id, role.name, run).progressAt,
|
|
58
|
+
...(session?.nativeSessionId === undefined
|
|
59
|
+
? {}
|
|
60
|
+
: { nativeSessionId: session.nativeSessionId }),
|
|
61
|
+
...(session?.launchId === undefined ? {} : { launchId: session.launchId })
|
|
62
|
+
}]
|
|
63
|
+
: [])));
|
|
64
|
+
if (liveStatuses !== undefined) {
|
|
65
|
+
for (const [key, status] of batchSnapshot.statuses)
|
|
66
|
+
liveStatuses.set(key, status);
|
|
67
|
+
}
|
|
68
|
+
if (resourceEvidence !== undefined) {
|
|
69
|
+
for (const [key, resource] of batchSnapshot.resources) {
|
|
70
|
+
const candidate = candidates.find(({ task, role }) => (`${task.id}\0${role.name}` === key));
|
|
71
|
+
if (candidate !== undefined) {
|
|
72
|
+
// Keep only the exact Run key. A task/role or bare-Run fallback can
|
|
73
|
+
// bridge an asynchronous sample from a prior generation.
|
|
74
|
+
resourceEvidence.set(`${key}\0${candidate.run.id}`, resource);
|
|
37
75
|
}
|
|
38
76
|
}
|
|
39
77
|
}
|
|
78
|
+
for (const { task, role, run, session, inspection } of eligible) {
|
|
79
|
+
const status = batchSnapshot.statuses.get(`${task.id}\0${role.name}`);
|
|
80
|
+
if (status === undefined)
|
|
81
|
+
throw new Error("Role liveness snapshot is incomplete.");
|
|
82
|
+
if (status === "present")
|
|
83
|
+
continue;
|
|
84
|
+
const persisted = store.saveExitedRoleRun({
|
|
85
|
+
task,
|
|
86
|
+
role,
|
|
87
|
+
run,
|
|
88
|
+
session,
|
|
89
|
+
summary: EXITED_ROLE_RUN_SUMMARY,
|
|
90
|
+
now
|
|
91
|
+
});
|
|
92
|
+
if (persisted === "state-changed")
|
|
93
|
+
continue;
|
|
94
|
+
delivery.forgetPrepared?.({
|
|
95
|
+
taskId: task.id,
|
|
96
|
+
roleName: role.name,
|
|
97
|
+
runId: run.id
|
|
98
|
+
});
|
|
99
|
+
failed.push(formatTaskRecordReference(task.id, run.id, "agentRun"));
|
|
100
|
+
// Compatibility for narrow in-memory/custom ports that predate the
|
|
101
|
+
// adapter's atomic failure+wake transition. Production returns
|
|
102
|
+
// "failed" and already enqueued this wake in the same transaction.
|
|
103
|
+
if (persisted === undefined && task.status === "active") {
|
|
104
|
+
queueLeaderWakeup(store, task.id, role.name === "leader" ? "leader-run-failed" : "role-run-failed", now);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
40
107
|
return failed;
|
|
41
108
|
}
|
|
109
|
+
async function inspectRoleStatuses(delivery, candidates, resourceInputs) {
|
|
110
|
+
if (delivery.inspectRoles !== undefined) {
|
|
111
|
+
return exactBatchInventory(await delivery.inspectRoles(candidates.map(({ inspection }) => inspection), resourceInputs), candidates);
|
|
112
|
+
}
|
|
113
|
+
const entries = [];
|
|
114
|
+
for (const candidate of candidates) {
|
|
115
|
+
entries.push([
|
|
116
|
+
`${candidate.task.id}\0${candidate.role.name}`,
|
|
117
|
+
await delivery.inspectRole(candidate.inspection)
|
|
118
|
+
]);
|
|
119
|
+
}
|
|
120
|
+
return { statuses: new Map(entries), resources: new Map() };
|
|
121
|
+
}
|
|
122
|
+
function exactBatchInventory(batch, candidates) {
|
|
123
|
+
const expected = new Set(candidates.map(({ task, role }) => `${task.id}\0${role.name}`));
|
|
124
|
+
const statuses = new Map();
|
|
125
|
+
const resources = new Map();
|
|
126
|
+
for (const entry of batch) {
|
|
127
|
+
const key = `${entry.taskId}\0${entry.roleName}`;
|
|
128
|
+
if (!expected.has(key) || statuses.has(key)) {
|
|
129
|
+
throw new Error("Tmux Role batch liveness snapshot is invalid.");
|
|
130
|
+
}
|
|
131
|
+
statuses.set(key, entry.status);
|
|
132
|
+
if (entry.resource !== undefined)
|
|
133
|
+
resources.set(key, entry.resource);
|
|
134
|
+
}
|
|
135
|
+
if (statuses.size !== expected.size) {
|
|
136
|
+
throw new Error("Tmux Role batch liveness snapshot is incomplete.");
|
|
137
|
+
}
|
|
138
|
+
return { statuses, resources };
|
|
139
|
+
}
|
|
140
|
+
function isResourceCandidate(task, run, now) {
|
|
141
|
+
if (task.status !== "active" || run.status !== "active" || run.deliveredAt === undefined) {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
const deliveredAt = Date.parse(run.deliveredAt);
|
|
145
|
+
return Number.isFinite(deliveredAt)
|
|
146
|
+
&& now.getTime() - deliveredAt >= DEFAULT_EXECUTION_STALL_CANDIDATE_AGE_MS;
|
|
147
|
+
}
|