@zq-silk/yui 0.15.12 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (236) hide show
  1. package/ARCHITECTURE.md +3 -2
  2. package/ARCHITECTURE.zh-CN.md +3 -2
  3. package/dist/artifacts/artifactCommitLock.js +16 -55
  4. package/dist/artifacts/taskArtifactRepository.js +3 -3
  5. package/dist/cli/agentConfigurationPicker.js +1 -1
  6. package/dist/cli/commandCatalog.js +57 -41
  7. package/dist/cli/completion.js +18 -18
  8. package/dist/cli/completionWizard.js +1 -1
  9. package/dist/cli/dynamicCompletion.js +1 -1
  10. package/dist/cli/interactionPolicy.js +7 -3
  11. package/dist/cli/invocationAuthority.js +64 -0
  12. package/dist/cli/managedDiagnostics.js +1 -1
  13. package/dist/cli/parseRepeatable.js +35 -0
  14. package/dist/cli/updatePorts.js +26 -5
  15. package/dist/cli.js +1280 -1243
  16. package/dist/commands/agentCommands.js +4 -4
  17. package/dist/commands/capabilityCommands.js +1 -1
  18. package/dist/commands/configCommands.js +6 -57
  19. package/dist/commands/configOverview.js +2 -2
  20. package/dist/commands/durableJobCommands.js +12 -6
  21. package/dist/commands/globalRoleCommands.js +53 -29
  22. package/dist/commands/grantCommands.js +0 -3
  23. package/dist/commands/jobCommands.js +1 -4
  24. package/dist/commands/operatorCommands.js +3 -3
  25. package/dist/commands/projectCommands.js +1 -10
  26. package/dist/commands/resourcesCommands.js +10 -40
  27. package/dist/commands/roleConfiguration.js +2 -6
  28. package/dist/commands/taskActivationCommands.js +4 -8
  29. package/dist/commands/taskAgentCapabilities.js +9 -0
  30. package/dist/commands/taskCommandSupport.js +155 -0
  31. package/dist/commands/taskCommandTypes.js +1 -0
  32. package/dist/commands/taskCommands.js +271 -710
  33. package/dist/commands/taskCompletionGate.js +1 -1
  34. package/dist/commands/taskExecutionCommands.js +1 -1
  35. package/dist/commands/taskFactCommands.js +325 -0
  36. package/dist/commands/taskInputCommands.js +12 -42
  37. package/dist/commands/taskIntegrationCommands.js +17 -57
  38. package/dist/commands/taskNextActionCommand.js +7 -6
  39. package/dist/commands/taskPublicationAdoptCommand.js +3 -3
  40. package/dist/commands/taskPublicationCommands.js +1 -1
  41. package/dist/commands/taskPublicationVerifyCommand.js +1 -1
  42. package/dist/commands/taskRemoteDeliveryCommand.js +2 -94
  43. package/dist/commands/taskUpstreamCommands.js +19 -8
  44. package/dist/commands/workflowCommands.js +6 -1
  45. package/dist/completion/completionInstaller.js +26 -26
  46. package/dist/completion/completionState.js +26 -26
  47. package/dist/completion/fileCompletionManager.js +6 -11
  48. package/dist/config/configCatalog.js +0 -2
  49. package/dist/config/timeZone.js +14 -0
  50. package/dist/config/yuiConfig.js +0 -29
  51. package/dist/context/runContextPack.js +2 -3
  52. package/dist/context/taskCatalog.js +3 -5
  53. package/dist/context/taskContext.js +139 -151
  54. package/dist/context/wakeRunReferences.js +11 -0
  55. package/dist/controller/agentCapabilities.js +58 -0
  56. package/dist/controller/agentRuntimeObserver.js +6 -11
  57. package/dist/controller/clientRuntime.js +22 -14
  58. package/dist/controller/controller.js +9 -22
  59. package/dist/controller/fileSchedulerStoreAdapter.js +117 -212
  60. package/dist/controller/jobClient.js +4 -4
  61. package/dist/controller/jobControl.js +60 -25
  62. package/dist/controller/jobSupervisor.js +4 -4
  63. package/dist/controller/providerRetryDelivery.js +7 -7
  64. package/dist/controller/runtime.js +51 -44
  65. package/dist/controller/runtimeEventProcessor.js +0 -5
  66. package/dist/controller/sessionOwnerReconciliation.js +5 -0
  67. package/dist/controller/taskAgentError.js +35 -0
  68. package/dist/coordination/workMailboxQueue.js +2 -24
  69. package/dist/core/controllerClient.js +2 -2
  70. package/dist/core/fileLockOwner.js +74 -0
  71. package/dist/decision/decision.js +17 -0
  72. package/dist/doctor/doctor.js +18 -9
  73. package/dist/event/taskEvent.js +12 -0
  74. package/dist/execution/workItemExecutionProjection.js +2 -2
  75. package/dist/executor/agentCapabilityConfig.js +43 -0
  76. package/dist/executor/agentConfigurationCatalog.js +49 -11
  77. package/dist/executor/agentExecutor.js +5 -8
  78. package/dist/executor/fileRoleLaunchPlanner.js +11 -53
  79. package/dist/executor/taskAgentCapabilities.js +64 -0
  80. package/dist/integration/deliveryObligation.js +1 -69
  81. package/dist/integration/gitIntegrationService.js +60 -84
  82. package/dist/integration/integrationAttempt.js +3 -14
  83. package/dist/integration/integrationSourceApplication.js +4 -12
  84. package/dist/integration/manifestTags.js +2 -2
  85. package/dist/job/durableJob.js +4 -25
  86. package/dist/job/jobAssignmentScope.js +22 -0
  87. package/dist/job/jobOperation.js +16 -0
  88. package/dist/job/jobRunner.js +2 -1
  89. package/dist/job/stepDirectory.js +15 -0
  90. package/dist/kernel/builtinCapabilities.js +15 -11
  91. package/dist/kernel/kernelPorts.js +1 -17
  92. package/dist/lifecycle/exactRunTerminalization.js +1 -9
  93. package/dist/message/inputControlResolution.js +3 -4
  94. package/dist/message/message.js +17 -20
  95. package/dist/message/messageContinuation.js +1 -1
  96. package/dist/milestone/milestone.js +11 -0
  97. package/dist/observability/orchestrationMetrics.js +24 -1
  98. package/dist/observability/runtimeIdentity.js +1 -17
  99. package/dist/output/agentConfigurationPresentation.js +2 -0
  100. package/dist/output/timePresentation.js +1 -14
  101. package/dist/plugins/pluginService.js +12 -4
  102. package/dist/release/releaseWorkflowPorts.js +45 -96
  103. package/dist/release/runtimeRelease.js +9 -15
  104. package/dist/repository/projectMaintenanceLock.js +23 -64
  105. package/dist/repository/taskBaseFreshness.js +1 -1
  106. package/dist/repository/taskWorkspaceCoordinator.js +13 -22
  107. package/dist/repository/taskWorkspacePreparer.js +29 -25
  108. package/dist/repository/workspaceCleanupInspection.js +5 -5
  109. package/dist/resources/autoResourceGc.js +4 -77
  110. package/dist/resources/liveReferences.js +7 -54
  111. package/dist/resources/resourceDiscovery.js +5 -118
  112. package/dist/resources/resourceGc.js +233 -181
  113. package/dist/resources/resourceRegistrar.js +5 -4
  114. package/dist/resources/resourceRegistry.js +3 -37
  115. package/dist/resources/resourceRegistryStore.js +13 -36
  116. package/dist/resources/sqliteResourceRegistry.js +43 -26
  117. package/dist/review/deltaRecheck.js +1 -1
  118. package/dist/review/reviewAcceptance.js +1 -1
  119. package/dist/review/reviewDecision.js +1 -1
  120. package/dist/review/reviewRound.js +8 -7
  121. package/dist/review/taskFinalReviewContractResolution.js +1 -1
  122. package/dist/runtime/acpProtocol.js +4 -51
  123. package/dist/runtime/acpSession.js +10 -75
  124. package/dist/runtime/acpSessionConfiguration.js +1 -8
  125. package/dist/runtime/agentEndpoint.js +3 -2
  126. package/dist/runtime/agentFailureContext.js +43 -0
  127. package/dist/runtime/agentHost.js +15 -15
  128. package/dist/runtime/codexInteractiveHost.js +2 -2
  129. package/dist/runtime/index.js +0 -1
  130. package/dist/runtime/managedCaller.js +21 -1
  131. package/dist/runtime/providerErrors.js +38 -0
  132. package/dist/runtime/runtimeObservation.js +0 -5
  133. package/dist/runtime/runtimeSessionCandidate.js +2 -3
  134. package/dist/runtime/sessionOwnerIdentity.js +1 -1
  135. package/dist/runtime/structuredProviderHost.js +4 -41
  136. package/dist/runtime/tmuxAdapters.js +6 -8
  137. package/dist/scheduler/activeRoleRunDelivery.js +7 -7
  138. package/dist/scheduler/leaderWakeupProcessor.js +19 -6
  139. package/dist/scheduler/operatorEvent.js +12 -20
  140. package/dist/scheduler/operatorInputNotificationProcessor.js +1 -1
  141. package/dist/scheduler/ports.js +5 -8
  142. package/dist/scheduler/roleRunLiveness.js +4 -4
  143. package/dist/scheduler/roleRunStall.js +16 -23
  144. package/dist/scheduler/taskExecutionProjection.js +25 -33
  145. package/dist/scheduler/taskObservabilityProjection.js +0 -1
  146. package/dist/scheduler/taskWake.js +5 -10
  147. package/dist/scheduler/wakeReason.js +2 -0
  148. package/dist/scheduler/wakeupQueue.js +2 -4
  149. package/dist/setup/setupCommand.js +1 -1
  150. package/dist/storage/contextRecords.js +106 -0
  151. package/dist/storage/currentTaskStore.js +1 -1
  152. package/dist/storage/homeLayout.js +13 -17
  153. package/dist/storage/migrations/agentFailureContext.js +22 -0
  154. package/dist/storage/migrations/currentInputContract.js +86 -0
  155. package/dist/storage/migrations/currentRuntimeContract.js +228 -0
  156. package/dist/storage/migrations/historicalVerificationPlan.js +35 -0
  157. package/dist/storage/migrations/integrationContinuation.js +5 -4
  158. package/dist/storage/migrations/narrowAgentFailureContext.js +65 -0
  159. package/dist/storage/migrations/notificationOnlyWakes.js +74 -0
  160. package/dist/storage/migrations/verificationPlanV1.js +162 -0
  161. package/dist/storage/migrations/verificationPolicy.js +74 -0
  162. package/dist/storage/migrations/workItemHistory.js +46 -0
  163. package/dist/storage/persistenceWorker.js +12 -4
  164. package/dist/storage/recordValidation.js +87 -0
  165. package/dist/storage/sqliteSchema.js +142 -1
  166. package/dist/storage/sqliteStore.js +156 -162
  167. package/dist/storage/storageSchema.js +2 -14
  168. package/dist/storage/storageVersions.js +1 -1
  169. package/dist/storage/storeRpc.js +15 -7
  170. package/dist/storage/taskStore.js +3 -7
  171. package/dist/storage/upgrade/upgradeOrchestrator.js +25 -37
  172. package/dist/task/completionReadiness.js +5 -24
  173. package/dist/task/draftPlan.js +0 -53
  174. package/dist/task/nextAction.js +7 -13
  175. package/dist/task/remoteDeliveryService.js +89 -0
  176. package/dist/task/taskActivation.js +2 -25
  177. package/dist/task/taskActivationService.js +0 -2
  178. package/dist/task/taskRecordReference.js +0 -1
  179. package/dist/task/taskSubmission.js +3 -14
  180. package/dist/telemetry/sqliteTelemetryBatch.js +29 -0
  181. package/dist/telemetry/sqliteTelemetryStore.js +49 -49
  182. package/dist/telemetry/telemetryWiring.js +4 -3
  183. package/dist/tmux/tmuxManager.js +29 -20
  184. package/dist/verification/gateArtifact.js +15 -24
  185. package/dist/verification/gateArtifactStore.js +14 -7
  186. package/dist/verification/verificationGateService.js +29 -88
  187. package/dist/verification/verificationPlan.js +27 -72
  188. package/dist/web/assets/client/app.js +1 -1
  189. package/dist/web/assets/client/taskSurface.js +4 -4
  190. package/dist/web/webServer.js +4 -6
  191. package/dist/web/webSnapshot.js +3 -83
  192. package/dist/web/webTaskSurface.js +17 -46
  193. package/dist/workItem/workItem.js +1 -12
  194. package/docs/architecture/capabilities-and-resources.md +14 -2
  195. package/docs/architecture/capabilities-and-resources.zh-CN.md +11 -1
  196. package/docs/managed-turn-and-session-runtime.md +83 -10
  197. package/docs/managed-turn-and-session-runtime.zh-CN.md +65 -11
  198. package/docs/plugin-sdk.md +4 -2
  199. package/docs/provider-runtime.md +3 -1
  200. package/docs/provider-runtime.zh-CN.md +4 -2
  201. package/docs/release-workflow.md +190 -7
  202. package/docs/release-workflow.zh-CN.md +139 -5
  203. package/docs/roles-and-configuration.md +29 -0
  204. package/docs/roles-and-configuration.zh-CN.md +21 -0
  205. package/docs/sqlite-control-plane-design.md +16 -3
  206. package/docs/sqlite-control-plane-design.zh-CN.md +13 -2
  207. package/docs/task-dag-semantics.md +3 -3
  208. package/docs/task-dag-semantics.zh-CN.md +2 -2
  209. package/docs/task-delivery.md +91 -5
  210. package/docs/task-delivery.zh-CN.md +72 -4
  211. package/docs/task-discovery.md +10 -11
  212. package/docs/task-discovery.zh-CN.md +8 -9
  213. package/docs/testing/verification-levels.md +145 -9
  214. package/docs/testing/verification-levels.zh-CN.md +103 -8
  215. package/package.json +1 -1
  216. package/skills/yui-leader/SKILL.md +5 -0
  217. package/skills/yui-leader/references/integration.md +9 -5
  218. package/skills/yui-leader/references/planning.md +9 -3
  219. package/skills/yui-operator/SKILL.md +15 -10
  220. package/skills/yui-runtime/SKILL.md +6 -6
  221. package/skills/yui-runtime/references/recovery.md +47 -0
  222. package/dist/agent/agentRegistry.js +0 -10
  223. package/dist/agentRun/runIdentity.js +0 -22
  224. package/dist/commands/deliveryGuardPreflight.js +0 -30
  225. package/dist/commands/taskIntegrationQueueCommands.js +0 -226
  226. package/dist/commands/taskOverviewCommand.js +0 -377
  227. package/dist/completion/completionWizard.js +0 -125
  228. package/dist/context/dispatchContext.js +0 -110
  229. package/dist/context/wakeNotification.js +0 -144
  230. package/dist/integration/integrationCheckEvidenceReuse.js +0 -53
  231. package/dist/integration/integrationQueueEntry.js +0 -191
  232. package/dist/integration/integrationQueueService.js +0 -810
  233. package/dist/release/fakeReleasePorts.js +0 -55
  234. package/dist/runtime/sessionOwnerRegistry.js +0 -137
  235. package/dist/task/deliveryGuard.js +0 -226
  236. /package/dist/{commands/taskActor.js → task/taskAuthority.js} +0 -0
@@ -1,30 +0,0 @@
1
- import { resolveLeaderNextActionMode, resolveLeaderSemanticBudgetRuns } from "../config/yuiConfig.js";
2
- import { usageError } from "../errors/cliError.js";
3
- import { detectDeliveryDuplicates, evaluateDeliveryGuard, evaluateSemanticBudget, formatDeliveryDuplicate } from "../task/deliveryGuard.js";
4
- export function runDeliveryGuardPreflight(store, taskId, intent, options = {}) {
5
- const mode = resolveLeaderNextActionMode(store.getConfig().leaderNextActionMode);
6
- if (mode === "display")
7
- return { warnings: [] };
8
- const facts = store.readNextActionFacts(taskId);
9
- if (facts === null)
10
- return { warnings: [] };
11
- const outcome = evaluateDeliveryGuard(detectDeliveryDuplicates(facts, intent), mode);
12
- const warnings = outcome.warnings.map(formatDeliveryDuplicate);
13
- if (outcome.blocked !== null) {
14
- throw usageError(`${formatDeliveryDuplicate(outcome.blocked)} `
15
- + "Reuse the existing proof, or set leader.nextActionMode=warn to proceed with a warning.");
16
- }
17
- if (options.budget === true) {
18
- const budget = evaluateSemanticBudget(facts, resolveLeaderSemanticBudgetRuns(store.getConfig().leaderSemanticBudgetRuns));
19
- if (budget.exhausted) {
20
- warnings.push(`Semantic progress budget: ${budget.reason}`);
21
- }
22
- }
23
- return { warnings };
24
- }
25
- /** Prepend guard warnings to a command's normal output. */
26
- export function withGuardWarnings(preflight, output) {
27
- if (preflight.warnings.length === 0)
28
- return output;
29
- return `${preflight.warnings.map((warning) => `Warning: ${warning}\n`).join("")}${output}`;
30
- }
@@ -1,226 +0,0 @@
1
- import { usageError } from "../errors/cliError.js";
2
- import { defaultTableWidth, renderTable } from "../output/table.js";
3
- import { resolveProject } from "../repository/project.js";
4
- import { NodeGitWorkspace } from "../repository/gitWorkspace.js";
5
- import { enqueueIntegrationQueueEntry, processIntegrationQueue, reconcileIntegrationQueueEntry, requeueIntegrationQueueEntry, supersedeIntegrationQueueEntry } from "../integration/integrationQueueService.js";
6
- import { assertTaskDeliveryAuthority as taskLocalActor } from "./taskActor.js";
7
- import { parseRepeatable } from "./taskIntegrationCommands.js";
8
- import { resolveTaskRecordReference } from "../task/taskRecordReference.js";
9
- /**
10
- * `yui task integration queue` — the serialized merge queue. Only terminal
11
- * Candidates explicitly enqueued enter the queue; the queue never blocks
12
- * parallel development, it orders exact-commit integration.
13
- */
14
- export async function runTaskIntegrationQueueCommand(args, store, home, options = {}) {
15
- const [command, ...rest] = args;
16
- if (command === "enqueue")
17
- return enqueue(rest, store, options, home);
18
- if (command === "list")
19
- return list(rest, store);
20
- if (command === "show")
21
- return show(rest, store, options.environment);
22
- if (command === "process")
23
- return process(rest, store, home, options);
24
- if (command === "supersede")
25
- return supersede(rest, store, options, home);
26
- if (command === "requeue")
27
- return requeue(rest, store, options, home);
28
- if (command === "reconcile")
29
- return reconcile(rest, store, options, home);
30
- throw usageError(command === undefined
31
- ? "Task Integration queue command is required."
32
- : `Unknown command: task integration queue ${command}`);
33
- }
34
- async function enqueue(args, store, options, home) {
35
- const usage = "Task Integration queue enqueue usage: yui task integration queue enqueue <task> --project <project> --change-set <id> [--target <ref>] [--check <command> ...].";
36
- const parsed = parseRepeatable(args, new Set(["--check"]), new Set(["--project", "--change-set", "--target"]), usage);
37
- if (parsed.positionals.length !== 1)
38
- throw usageError(usage);
39
- const task = requireActiveTask(store, parsed.positionals[0]);
40
- requireTaskControlActor(store, options.environment, task.id, home);
41
- const projectRef = parsed.one.get("--project");
42
- const changeSetId = parsed.one.get("--change-set");
43
- if (projectRef === undefined || changeSetId === undefined)
44
- throw usageError(usage);
45
- const projectId = resolveProjectId(store, projectRef);
46
- const result = await enqueueIntegrationQueueEntry({
47
- store,
48
- taskId: task.id,
49
- projectId,
50
- changeSetId,
51
- targetRef: parsed.one.get("--target"),
52
- checkCommands: parsed.many.get("--check") ?? [],
53
- now: options.now
54
- });
55
- const label = {
56
- queued: "Enqueued",
57
- "already-queued": "Already queued",
58
- "already-committed": "Already committed",
59
- converged: "Converged"
60
- }[result.outcome];
61
- return {
62
- output: `${label} ${result.entry.changeSetId} as ${result.entry.id} (${result.entry.status})\n`,
63
- data: result
64
- };
65
- }
66
- function list(args, store) {
67
- const usage = "Task Integration queue list usage: yui task integration queue list <task> [--project <project>].";
68
- const parsed = parseRepeatable(args, new Set(), new Set(["--project"]), usage);
69
- if (parsed.positionals.length !== 1)
70
- throw usageError(usage);
71
- const task = requireActiveTask(store, parsed.positionals[0]);
72
- const projectRef = parsed.one.get("--project");
73
- const projectId = projectRef === undefined ? undefined : resolveProjectId(store, projectRef);
74
- // The store already returns entries in numeric id order; trust it instead of
75
- // re-sorting with a lexicographic compare (which yields 1, 10, 2, ...).
76
- const entries = store.listIntegrationQueueEntries(task.id)
77
- .filter((entry) => projectId === undefined || entry.projectId === projectId);
78
- const output = entries.length === 0
79
- ? "Integration queue is empty.\n"
80
- : `${renderTable(`Integration queue: ${task.id}`, [
81
- { header: "Entry", minWidth: 12, maxWidth: 24 },
82
- { header: "Project", minWidth: 8, maxWidth: 20 },
83
- { header: "ChangeSet", minWidth: 10, maxWidth: 20 },
84
- { header: "Target", minWidth: 8, maxWidth: 30 },
85
- { header: "Status", minWidth: 8, maxWidth: 16 }
86
- ], entries.map((entry) => [
87
- entry.id,
88
- entry.projectId,
89
- entry.changeSetId,
90
- entry.targetRef,
91
- entry.status
92
- ]), defaultTableWidth())}\n`;
93
- return { output, data: { entries } };
94
- }
95
- function show(args, store, environment) {
96
- const usage = "Task Integration queue show usage: yui task integration queue show <task>/<entry>.";
97
- if (args.length !== 1)
98
- throw usageError(usage);
99
- const entry = requireQueueEntry(store, args[0], environment);
100
- const lines = [
101
- `Integration queue entry: ${entry.id}`,
102
- `Task: ${entry.taskId}`,
103
- `Project: ${entry.projectId}`,
104
- `ChangeSet: ${entry.changeSetId}`,
105
- `Target: ${entry.targetRef}`,
106
- `Status: ${entry.status}`,
107
- `Target before: ${entry.targetBefore ?? "-"}`,
108
- `Target after: ${entry.targetAfter ?? "-"}`,
109
- `Integration: ${entry.integrationAttemptId ?? "-"}`,
110
- `Affected paths: ${entry.affectedPaths === undefined ? "-" : entry.affectedPaths.join(", ")}`,
111
- `Evidence: ${entry.evidenceRefs.length === 0 ? "-" : entry.evidenceRefs.join(", ")}`,
112
- `Conflict: ${entry.conflictSummary ?? "-"}`,
113
- `Superseded: ${entry.supersedeReason ?? "-"}`
114
- ];
115
- return { output: `${lines.join("\n")}\n`, data: { entry } };
116
- }
117
- async function process(args, store, home, options) {
118
- const usage = "Task Integration queue process usage: yui task integration queue process <task> [--project <project>] [--limit <n>].";
119
- const parsed = parseRepeatable(args, new Set(), new Set(["--project", "--limit"]), usage);
120
- if (parsed.positionals.length !== 1)
121
- throw usageError(usage);
122
- const task = requireActiveTask(store, parsed.positionals[0]);
123
- requireTaskControlActor(store, options.environment, task.id, home);
124
- const limitValue = parsed.one.get("--limit");
125
- const limit = limitValue === undefined ? undefined : Number.parseInt(limitValue, 10);
126
- if (limitValue !== undefined && (!Number.isSafeInteger(limit) || limit < 1)) {
127
- throw usageError(`--limit must be a positive integer: ${limitValue}.`);
128
- }
129
- const projectRef = parsed.one.get("--project");
130
- const projectId = projectRef === undefined ? undefined : resolveProjectId(store, projectRef);
131
- const processed = await processIntegrationQueue(store, home, task.id, {
132
- projectId,
133
- limit,
134
- now: options.now,
135
- environment: options.environment
136
- });
137
- const lines = processed.map(({ entry, result }) => {
138
- if (result.status === "committed") {
139
- return `${entry.id} committed ${entry.changeSetId} -> ${entry.targetAfter ?? "-"}`;
140
- }
141
- if (result.status === "blocked" || result.status === "conflicted") {
142
- return `${entry.id} conflicted ${entry.changeSetId}: ${entry.conflictSummary ?? "blocked"}`;
143
- }
144
- return `${entry.id} conflicted ${entry.changeSetId}: ${entry.conflictSummary ?? "gate failure"}`;
145
- });
146
- const output = processed.length === 0
147
- ? "Integration queue: nothing to process.\n"
148
- : `${lines.join("\n")}\n`;
149
- return { output, data: { processed } };
150
- }
151
- function supersede(args, store, options, home) {
152
- const usage = "Task Integration queue supersede usage: yui task integration queue supersede <task>/<entry> --reason <text>.";
153
- const parsed = parseRepeatable(args, new Set(), new Set(["--reason"]), usage);
154
- if (parsed.positionals.length !== 1)
155
- throw usageError(usage);
156
- const entry = requireQueueEntry(store, parsed.positionals[0], options.environment);
157
- const actor = requireTaskControlActor(store, options.environment, entry.taskId, home);
158
- const reason = parsed.one.get("--reason");
159
- if (reason === undefined)
160
- throw usageError(usage);
161
- const superseded = supersedeIntegrationQueueEntry(store, entry.taskId, entry.id, reason, actor, options.now ?? (() => new Date()));
162
- return {
163
- output: `Superseded ${superseded.id}: ${reason}\n`,
164
- data: { entry: superseded }
165
- };
166
- }
167
- function requeue(args, store, options, home) {
168
- const usage = "Task Integration queue requeue usage: yui task integration queue requeue <task>/<entry>.";
169
- if (args.length !== 1)
170
- throw usageError(usage);
171
- const entry = requireQueueEntry(store, args[0], options.environment);
172
- const actor = requireTaskControlActor(store, options.environment, entry.taskId, home);
173
- const waiting = requeueIntegrationQueueEntry(store, entry.taskId, entry.id, actor, options.now ?? (() => new Date()));
174
- return {
175
- output: `Requeued ${waiting.id}; it will be processed again on the next queue run\n`,
176
- data: { entry: waiting }
177
- };
178
- }
179
- async function reconcile(args, store, options, home) {
180
- const usage = "Task Integration queue reconcile usage: yui task integration queue reconcile <task>/<entry>.";
181
- if (args.length !== 1)
182
- throw usageError(usage);
183
- const entry = requireQueueEntry(store, args[0], options.environment);
184
- requireTaskControlActor(store, options.environment, entry.taskId, home);
185
- const committed = await reconcileIntegrationQueueEntry(store, entry.taskId, entry.id, new NodeGitWorkspace(), options.now ?? (() => new Date()));
186
- return {
187
- output: `Reconciled ${committed.id} as committed -> ${committed.targetAfter ?? "-"}\n`,
188
- data: { entry: committed }
189
- };
190
- }
191
- function requireActiveTask(store, taskId) {
192
- const task = store.getTask(taskId);
193
- if (task === null)
194
- throw usageError(`Task not found: ${taskId}.`);
195
- if (task.status !== "active") {
196
- throw usageError(`Task is not active: ${task.id}/${task.status}.`);
197
- }
198
- return task;
199
- }
200
- function resolveProjectId(store, reference) {
201
- const project = resolveProject(store.listProjects(), reference);
202
- if (project === null)
203
- throw usageError(`Project not found: ${reference}.`);
204
- return project.id;
205
- }
206
- function requireQueueEntry(store, value, environment) {
207
- let reference;
208
- try {
209
- reference = resolveTaskRecordReference(value, {
210
- kind: "integrationQueue",
211
- contextTaskId: environment?.YUI_TASK_ID,
212
- label: "Integration queue entry"
213
- });
214
- }
215
- catch (error) {
216
- throw usageError(error instanceof Error ? error.message : String(error));
217
- }
218
- const entry = store.getIntegrationQueueEntry(reference.taskId, reference.localId);
219
- if (entry === null) {
220
- throw usageError(`Integration queue entry not found: ${reference.taskId}/${reference.localId}.`);
221
- }
222
- return entry;
223
- }
224
- function requireTaskControlActor(store, environment, taskId, home) {
225
- return taskLocalActor(store, environment, taskId);
226
- }
@@ -1,377 +0,0 @@
1
- import { usageError } from "../errors/cliError.js";
2
- import { isRoleRunStalled, latestStallProgressAt } from "../scheduler/roleRunStall.js";
3
- import { formatTimestamp } from "../output/timePresentation.js";
4
- import { pendingWakeupProjection } from "../storage/taskStore.js";
5
- import { defaultTableWidth, renderTable } from "../output/table.js";
6
- import { projectTaskExecutionFromFacts } from "../scheduler/taskExecutionProjection.js";
7
- import { resolveRuntimeHealth } from "../config/yuiConfig.js";
8
- import { projectNextAction } from "../task/nextAction.js";
9
- import { projectTaskRemoteDeliveryFromStore } from "./taskRemoteDeliveryCommand.js";
10
- import { formatUsageMetric } from "../runtime/taskUsageMetrics.js";
11
- export function parseTaskListOptions(args) {
12
- const allowed = new Set(["--all", "--verbose"]);
13
- if (args.some((argument) => !allowed.has(argument))
14
- || new Set(args).size !== args.length) {
15
- throw usageError("Task list usage: yui task list [--all] [--verbose].");
16
- }
17
- return {
18
- all: args.includes("--all"),
19
- verbose: args.includes("--verbose")
20
- };
21
- }
22
- export function buildTaskOverview(store, options, now = new Date(), taskId) {
23
- const runtimeHealthPolicy = resolveRuntimeHealth(store.getConfig().runtimeHealth);
24
- const tasks = (taskId === undefined ? store.listTasks() : [store.getTask(taskId)].filter((task) => task !== null))
25
- .filter((task) => options.all || task.status !== "archived")
26
- .map((task) => buildTaskOverviewEntry(task, store, now, runtimeHealthPolicy));
27
- return { tasks };
28
- }
29
- export function renderTaskOverview(result, options, timeZone, width = defaultTableWidth()) {
30
- if (result.tasks.length === 0)
31
- return "No tasks found.\n";
32
- const title = options.all ? "Tasks (all)" : "Tasks (unarchived)";
33
- const output = renderTable(title, [
34
- { header: "Task", minWidth: 8, maxWidth: 20 },
35
- { header: "Title", minWidth: 10, maxWidth: 46 },
36
- { header: "Lifecycle", minWidth: 9, maxWidth: 14 },
37
- { header: "Leader", minWidth: 12, maxWidth: 48 },
38
- { header: "Summary updated", minWidth: 16, maxWidth: 28 },
39
- { header: "Work", minWidth: 8, maxWidth: 38 },
40
- { header: "Blockers", minWidth: 9, maxWidth: 42 },
41
- { header: "Execution", minWidth: 14, maxWidth: 34 },
42
- { header: "Delivery", minWidth: 12, maxWidth: 28 },
43
- { header: "Next action / owner", minWidth: 16, maxWidth: 42 }
44
- ], result.tasks.map((task) => [
45
- task.id,
46
- task.title,
47
- task.status,
48
- leaderCell(task),
49
- task.summaryUpdatedAt === null
50
- ? "missing"
51
- : formatTimestamp(task.summaryUpdatedAt, timeZone),
52
- workCell(task.work.counts),
53
- blockersCell(task.blockers),
54
- `${task.execution.status} / ${task.execution.owner}`,
55
- deliveryCell(task.remoteDelivery),
56
- nextCell(task.next)
57
- ]), width);
58
- if (!options.verbose)
59
- return `${output}\n`;
60
- return `${output}\n\n${renderVerboseDetails(result.tasks, timeZone)}\n`;
61
- }
62
- function buildTaskOverviewEntry(task, store, now, runtimeHealthPolicy) {
63
- const brief = store.getTaskBrief(task.id);
64
- const roles = store.listRoles(task.id);
65
- const leaderRole = roles.find((role) => role.name === "leader") ?? null;
66
- const workItems = store.listWorkItems(task.id);
67
- const inputRequests = store.listInputRequests(task.id);
68
- const openInputRequests = inputRequests.filter((request) => request.status === "open");
69
- const runs = store.listRuns(task.id);
70
- const events = store.listEvents(task.id);
71
- const leaderFailure = store.getLeaderFailure(task.id);
72
- const leaderMailbox = store.getWorkMailbox({ kind: "role", taskId: task.id, roleName: "leader" });
73
- const pendingWakeup = pendingWakeupProjection(leaderMailbox);
74
- const reviewRounds = store.listReviewRounds(task.id);
75
- const changeSets = store.listChangeSets(task.id);
76
- const integrations = store.listIntegrationAttempts(task.id);
77
- const roleSessions = roles.flatMap((role) => {
78
- const session = store.getRoleSession(task.id, role.name);
79
- return session === null ? [] : [{ roleName: role.name, ...session }];
80
- });
81
- const providerRuns = new Map(roles.map((role) => [role.name, store.getTaskRoleSessionSet(task.id, role.name)?.providerBinding?.run]));
82
- const runDelivery = Object.fromEntries(runs.map((run) => {
83
- const native = providerRuns.get(run.roleName);
84
- return [run.id, native?.runId === run.id ? native.status : "unobserved"];
85
- }));
86
- const attention = collectAttention(task, runs, events, leaderFailure);
87
- const blockers = collectBlockers(workItems, openInputRequests, attention);
88
- const leader = {
89
- role: "leader",
90
- roleStatus: leaderRole === null
91
- ? "missing"
92
- : providerRuns.get("leader")?.status === "accepted" ? "running"
93
- : roleSessions.some((session) => session.roleName === "leader") ? "unknown" : "idle",
94
- summary: brief?.leaderSummary ?? null,
95
- currentFocus: brief?.currentFocus ?? null,
96
- updatedAt: brief?.updatedAt ?? null,
97
- updatedBy: brief?.updatedBy ?? null,
98
- summaryStatus: brief === null ? "missing" : "available"
99
- };
100
- const counts = countWorkItems(workItems);
101
- const runtimeRuns = runs
102
- .filter((run) => run.status === "active")
103
- .map((run) => ({
104
- id: run.id,
105
- roleName: run.roleName,
106
- status: run.status,
107
- runtime: runDelivery[run.id],
108
- createdAt: run.createdAt,
109
- updatedAt: run.updatedAt
110
- }));
111
- const runtime = {
112
- activeRuns: runtimeRuns,
113
- activeRunCount: runtimeRuns.length,
114
- pendingDeliveryCount: runtimeRuns.filter((run) => run.runtime !== "accepted").length
115
- };
116
- // Fold the execution projection from the facts already read above instead of
117
- // reading the store a second time for the same unchanged revision.
118
- const execution = projectTaskExecutionFromFacts({
119
- task,
120
- roles,
121
- runs,
122
- runDelivery,
123
- workItems,
124
- inputRequests,
125
- reviewRounds,
126
- changeSets,
127
- integrations,
128
- events,
129
- brief,
130
- pendingWakeup,
131
- leaderMailbox,
132
- leaderFailure,
133
- roleSessions,
134
- contextSnapshots: store.listContextSnapshots(task.id),
135
- now,
136
- runtimeHealthPolicy
137
- });
138
- const nextActionFacts = store.readNextActionFacts(task.id);
139
- if (nextActionFacts === null) {
140
- throw new Error(`Task disappeared while building its overview: ${task.id}.`);
141
- }
142
- const next = overviewNextAction(task, workItems, execution, projectNextAction({
143
- ...nextActionFacts,
144
- currentTaskReviewCandidate: null,
145
- executionGroups: execution.executionGroups
146
- }));
147
- const persistedCandidate = task.status === "active" || task.status === "cancelled"
148
- ? taskRemoteDeliveryCandidate(task)
149
- : null;
150
- const remoteDelivery = projectTaskRemoteDeliveryFromStore(store, task, persistedCandidate);
151
- return {
152
- ...task,
153
- brief,
154
- leader,
155
- leaderSummary: leader.summary,
156
- currentFocus: leader.currentFocus,
157
- summaryUpdatedAt: leader.updatedAt,
158
- summaryUpdatedBy: leader.updatedBy,
159
- summaryStatus: leader.summaryStatus,
160
- work: { counts, items: workItems },
161
- input: { open: openInputRequests, openCount: openInputRequests.length },
162
- attention,
163
- attentionCount: attention.length,
164
- blockers,
165
- next,
166
- nextAction: next?.action ?? null,
167
- nextOwner: next?.owner ?? null,
168
- runtime,
169
- execution,
170
- remoteDelivery
171
- };
172
- }
173
- function collectAttention(task, runs, events, failure) {
174
- const items = [];
175
- if (failure !== null) {
176
- items.push({
177
- kind: "leader-recovery",
178
- id: `leader-recovery:${task.id}`,
179
- status: "failed",
180
- owner: "operator",
181
- summary: failure.message,
182
- updatedAt: failure.lastFailedAt
183
- });
184
- }
185
- for (const run of runs) {
186
- if (run.roleName !== "leader"
187
- || run.status !== "active"
188
- || !isRoleRunStalled(events, run.id))
189
- continue;
190
- const progressAt = latestStallProgressAt(events, run.id) ?? run.updatedAt;
191
- items.push({
192
- kind: "leader-stalled",
193
- id: `leader-stall:${run.id}:${progressAt}`,
194
- status: "needs-attention",
195
- owner: "operator",
196
- summary: `AgentRun ${run.id} for ${run.roleName} has no durable progress after ${progressAt}.`,
197
- updatedAt: progressAt,
198
- runId: run.id,
199
- roleName: run.roleName
200
- });
201
- }
202
- return items.sort((left, right) => (Date.parse(left.updatedAt) - Date.parse(right.updatedAt)
203
- || left.id.localeCompare(right.id)));
204
- }
205
- function collectBlockers(workItems, openInputRequests, attention) {
206
- const blockers = [];
207
- const workById = new Map(workItems.map((item) => [item.id, item]));
208
- for (const item of workItems) {
209
- if ((item.status === "open" && item.currentCandidateId !== undefined)) {
210
- blockers.push({
211
- kind: "work",
212
- type: "work",
213
- id: item.id,
214
- status: item.status,
215
- owner: "leader",
216
- action: "accept-work-item",
217
- summary: `Work Item ${item.id} is awaiting Leader acceptance.`
218
- });
219
- continue;
220
- }
221
- if (item.status !== "open")
222
- continue;
223
- const dependencies = item.dependsOn.filter((dependency) => (workById.get(dependency)?.status !== "accepted"));
224
- if (dependencies.length === 0)
225
- continue;
226
- blockers.push({
227
- kind: "work",
228
- type: "work",
229
- id: item.id,
230
- status: item.status,
231
- owner: item.assignee ?? "leader",
232
- action: "unblock-work-item",
233
- summary: `Work Item ${item.id} is waiting on ${dependencies.join(", ")}.`
234
- });
235
- }
236
- for (const request of openInputRequests) {
237
- blockers.push({
238
- kind: "input",
239
- type: "input",
240
- id: request.id,
241
- status: request.status,
242
- owner: "user",
243
- action: "answer-input",
244
- summary: request.question,
245
- blockedRefs: request.blockedRefs
246
- });
247
- }
248
- for (const item of attention) {
249
- blockers.push({
250
- kind: "attention",
251
- type: "attention",
252
- id: item.id,
253
- status: item.status,
254
- owner: item.owner,
255
- action: item.kind === "leader-recovery"
256
- ? "inspect-leader-recovery"
257
- : "inspect-leader-stall",
258
- summary: item.summary
259
- });
260
- }
261
- return blockers;
262
- }
263
- function overviewNextAction(task, workItems, execution, action) {
264
- if (task.status !== "active" && task.status !== "draft")
265
- return null;
266
- const primary = action.refs[0];
267
- const workItem = action.refs
268
- .filter(({ kind }) => kind === "work-item")
269
- .map(({ id }) => workItems.find((item) => item.id === id))
270
- .find((item) => item !== undefined);
271
- const kind = primary?.kind === "input-request"
272
- ? "input"
273
- : primary?.kind === "work-item"
274
- ? "work"
275
- : action.kind.includes("attention") || action.kind.includes("inconsistency")
276
- ? "attention"
277
- : "execution";
278
- return {
279
- action: action.kind,
280
- owner: action.kind === "resolve-input"
281
- ? "user"
282
- : workItem?.assignee ?? execution.owner,
283
- kind,
284
- ...(primary === undefined ? {} : { id: primary.id }),
285
- summary: action.reason
286
- };
287
- }
288
- function countWorkItems(items) {
289
- const counts = {
290
- total: items.length,
291
- open: 0,
292
- accepted: 0,
293
- retired: 0
294
- };
295
- for (const item of items)
296
- counts[item.status] += 1;
297
- return counts;
298
- }
299
- function leaderCell(task) {
300
- const status = task.leader.roleStatus;
301
- if (task.leader.summaryStatus === "missing")
302
- return `${status} · missing summary`;
303
- const values = [task.leader.summary, task.leader.currentFocus]
304
- .filter((value) => value !== null && value.length > 0);
305
- return values.length === 0
306
- ? `${status} · summary unavailable`
307
- : compactText(`${status} · ${values.join(" · ")}`);
308
- }
309
- function workCell(counts) {
310
- if (counts.total === 0)
311
- return "none";
312
- const details = Object.keys(counts)
313
- .filter((status) => status !== "total" && counts[status] > 0)
314
- .map((status) => `${status}:${counts[status]}`);
315
- return `${counts.total} total${details.length === 0 ? "" : ` (${details.join(", ")})`}`;
316
- }
317
- function blockersCell(blockers) {
318
- if (blockers.length === 0)
319
- return "none";
320
- return blockers.map((blocker) => `${blocker.kind}:${blocker.id}`).join(", ");
321
- }
322
- function nextCell(next) {
323
- return next === null ? "—" : `${next.action} / ${next.owner}`;
324
- }
325
- function deliveryCell(delivery) {
326
- if (delivery.status === "none")
327
- return "none";
328
- return `${delivery.status} · ${delivery.mergedProjectCount}/${delivery.codeProjectCount} merged`
329
- + (delivery.allMerged
330
- ? ` · ${delivery.verifiedProjectCount}/${delivery.codeProjectCount} verified`
331
- : "");
332
- }
333
- function taskRemoteDeliveryCandidate(task) {
334
- const projects = task.projectBindings.flatMap(({ projectId, currentCommit }) => (currentCommit === undefined ? [] : [{ projectId, commit: currentCommit }]));
335
- return projects.length === task.projectBindings.length
336
- ? { projects }
337
- : null;
338
- }
339
- function compactText(value) {
340
- const oneLine = value.replace(/\s+/g, " ").trim();
341
- return oneLine.length <= 240 ? oneLine : `${oneLine.slice(0, 237)}...`;
342
- }
343
- function renderVerboseDetails(tasks, timeZone) {
344
- return [
345
- "Task details",
346
- ...tasks.flatMap((task) => [
347
- `${task.id}: ${task.title}`,
348
- ` Description: ${task.description ?? "—"}`,
349
- ` Current focus: ${task.currentFocus ?? "missing"}`,
350
- ` Leader summary: ${task.leaderSummary ?? "missing"}`,
351
- ` Summary updated by: ${task.summaryUpdatedBy ?? "unknown"}`,
352
- ` Summary updated at: ${task.summaryUpdatedAt === null
353
- ? "missing"
354
- : formatTimestamp(task.summaryUpdatedAt, timeZone)}`,
355
- ` Execution: ${task.execution.status} (${task.execution.owner}); ${task.execution.summary}`,
356
- ` Remote delivery: ${deliveryCell(task.remoteDelivery)}; source=${task.remoteDelivery.source}${task.remoteDelivery.provisional ? " (provisional)" : ""}`,
357
- ` Monitoring: ${task.execution.monitoring}; attention: ${task.execution.attention.length}`,
358
- ` DAG: ${task.execution.observability.dag.nodes.length} nodes, ${task.execution.observability.dag.edges.length} edges; ready=${task.execution.observability.dag.readyIds.join(", ") || "none"}; blocked=${task.execution.observability.dag.blockedIds.join(", ") || "none"}`,
359
- ` Observed usage (Task lifetime, observed sources only): tokens=${formatUsageMetric(task.execution.observability.cost.tokens)}; tools=${formatUsageMetric(task.execution.observability.cost.toolCalls)}; elapsed=${formatUsageMetric(task.execution.observability.cost.elapsedSeconds, "s")}; native execution sum=${formatUsageMetric(task.execution.observability.cost.executionSeconds, "s")}; retries=${task.execution.observability.cost.retryCount}`,
360
- ` Context: snapshots=${task.execution.observability.context.snapshotCount}; bytes=${task.execution.observability.context.totalBytes ?? "partial"}; compression=unavailable`,
361
- ` Session tokens: ${task.execution.observability.sessionTokens.length === 0
362
- ? "unobserved"
363
- : task.execution.observability.sessionTokens.map(({ roleName, metrics }) => {
364
- const total = metrics.cumulativeTotal.status === "observed"
365
- ? metrics.cumulativeTotal.totalTokens
366
- : "unobserved";
367
- const maximum = metrics.maximumRequestInput.status === "observed"
368
- ? metrics.maximumRequestInput.inputTokens
369
- : "unobserved";
370
- return `${roleName}: total=${total}, max-request-input=${maximum}`;
371
- }).join("; ")}`,
372
- ` Projects: ${task.projectBindings.length === 0
373
- ? "none"
374
- : task.projectBindings.map(({ directory, projectId, baseRef }) => (`${directory} (${projectId} @ ${baseRef})`)).join(", ")}`
375
- ])
376
- ].join("\n");
377
- }