@zq-silk/yui 0.15.11 → 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 (280) hide show
  1. package/ARCHITECTURE.md +11 -6
  2. package/ARCHITECTURE.zh-CN.md +8 -4
  3. package/README.md +13 -5
  4. package/dist/agentRun/agentRun.js +3 -0
  5. package/dist/artifacts/artifactCommitLock.js +16 -55
  6. package/dist/artifacts/taskArtifactRepository.js +3 -3
  7. package/dist/cli/agentConfigurationPicker.js +1 -1
  8. package/dist/cli/commandCatalog.js +92 -48
  9. package/dist/cli/completion.js +18 -18
  10. package/dist/cli/completionWizard.js +1 -1
  11. package/dist/cli/dynamicCompletion.js +1 -1
  12. package/dist/cli/interactionPolicy.js +11 -3
  13. package/dist/cli/invocationAuthority.js +64 -0
  14. package/dist/cli/managedDiagnostics.js +2 -2
  15. package/dist/cli/parseRepeatable.js +35 -0
  16. package/dist/cli/updatePorts.js +26 -5
  17. package/dist/cli.js +1303 -1235
  18. package/dist/commands/agentCommands.js +4 -4
  19. package/dist/commands/capabilityCommands.js +1 -1
  20. package/dist/commands/configCommands.js +6 -57
  21. package/dist/commands/configOverview.js +2 -2
  22. package/dist/commands/durableJobCommands.js +12 -6
  23. package/dist/commands/executionAuditCommands.js +10 -0
  24. package/dist/commands/globalRoleCommands.js +78 -29
  25. package/dist/commands/grantCommands.js +0 -3
  26. package/dist/commands/jobCommands.js +1 -4
  27. package/dist/commands/operatorCommands.js +3 -3
  28. package/dist/commands/projectCommands.js +45 -25
  29. package/dist/commands/resourcesCommands.js +10 -40
  30. package/dist/commands/roleConfiguration.js +2 -6
  31. package/dist/commands/taskActivationCommands.js +4 -8
  32. package/dist/commands/taskAgentCapabilities.js +9 -0
  33. package/dist/commands/taskCommandSupport.js +155 -0
  34. package/dist/commands/taskCommandTypes.js +1 -0
  35. package/dist/commands/taskCommands.js +355 -732
  36. package/dist/commands/taskCompletionGate.js +1 -1
  37. package/dist/commands/taskExecutionCommands.js +1 -1
  38. package/dist/commands/taskFactCommands.js +325 -0
  39. package/dist/commands/taskInputCommands.js +12 -42
  40. package/dist/commands/taskIntegrationCommands.js +20 -58
  41. package/dist/commands/taskNextActionCommand.js +7 -6
  42. package/dist/commands/taskPublicationAdoptCommand.js +127 -0
  43. package/dist/commands/taskPublicationCommands.js +12 -3
  44. package/dist/commands/taskPublicationVerifyCommand.js +24 -40
  45. package/dist/commands/taskRemoteDeliveryCommand.js +5 -86
  46. package/dist/commands/taskUpstreamCommands.js +19 -8
  47. package/dist/commands/workflowCommands.js +6 -1
  48. package/dist/completion/completionInstaller.js +26 -26
  49. package/dist/completion/completionState.js +26 -26
  50. package/dist/completion/fileCompletionManager.js +6 -11
  51. package/dist/config/configCatalog.js +0 -2
  52. package/dist/config/timeZone.js +14 -0
  53. package/dist/config/yuiConfig.js +0 -29
  54. package/dist/context/runContextPack.js +5 -3
  55. package/dist/context/taskCatalog.js +185 -0
  56. package/dist/context/taskContext.js +152 -151
  57. package/dist/context/wakeRunReferences.js +11 -0
  58. package/dist/controller/agentCapabilities.js +58 -0
  59. package/dist/controller/agentRuntimeObserver.js +6 -11
  60. package/dist/controller/clientRuntime.js +22 -14
  61. package/dist/controller/controller.js +20 -24
  62. package/dist/controller/fileSchedulerStoreAdapter.js +191 -225
  63. package/dist/controller/globalInputDelivery.js +13 -0
  64. package/dist/controller/jobClient.js +4 -4
  65. package/dist/controller/jobControl.js +60 -25
  66. package/dist/controller/jobSupervisor.js +4 -4
  67. package/dist/controller/providerRetryAdmission.js +100 -0
  68. package/dist/controller/providerRetryDelivery.js +218 -0
  69. package/dist/controller/runtime.js +85 -43
  70. package/dist/controller/runtimeEventProcessor.js +0 -5
  71. package/dist/controller/sessionOwnerReconciliation.js +5 -0
  72. package/dist/controller/taskAgentError.js +35 -0
  73. package/dist/coordination/workMailboxQueue.js +2 -24
  74. package/dist/core/controllerClient.js +2 -2
  75. package/dist/core/fileLockOwner.js +74 -0
  76. package/dist/decision/decision.js +17 -0
  77. package/dist/doctor/doctor.js +18 -9
  78. package/dist/event/taskEvent.js +12 -0
  79. package/dist/execution/workItemExecutionProjection.js +2 -2
  80. package/dist/executor/agentCapabilityConfig.js +43 -0
  81. package/dist/executor/agentConfigurationCatalog.js +49 -11
  82. package/dist/executor/agentExecutor.js +5 -8
  83. package/dist/executor/fileRoleLaunchPlanner.js +11 -53
  84. package/dist/executor/taskAgentCapabilities.js +64 -0
  85. package/dist/integration/deliveryObligation.js +1 -69
  86. package/dist/integration/gitIntegrationService.js +79 -90
  87. package/dist/integration/integrationAttempt.js +3 -14
  88. package/dist/integration/integrationSourceApplication.js +4 -12
  89. package/dist/integration/manifestTags.js +2 -2
  90. package/dist/job/durableJob.js +4 -25
  91. package/dist/job/jobAssignmentScope.js +22 -0
  92. package/dist/job/jobOperation.js +16 -0
  93. package/dist/job/jobRunner.js +2 -1
  94. package/dist/job/stepDirectory.js +15 -0
  95. package/dist/kernel/builtinCapabilities.js +15 -11
  96. package/dist/kernel/kernelPorts.js +1 -17
  97. package/dist/lifecycle/exactRunTerminalization.js +5 -10
  98. package/dist/message/globalProviderRetry.js +15 -0
  99. package/dist/message/inputControlResolution.js +3 -4
  100. package/dist/message/message.js +17 -20
  101. package/dist/message/messageContinuation.js +1 -1
  102. package/dist/milestone/milestone.js +11 -0
  103. package/dist/observability/executionAudit.js +19 -0
  104. package/dist/observability/orchestrationMetrics.js +24 -1
  105. package/dist/observability/runtimeIdentity.js +1 -17
  106. package/dist/output/agentConfigurationPresentation.js +2 -0
  107. package/dist/output/timePresentation.js +1 -14
  108. package/dist/plugins/pluginService.js +12 -4
  109. package/dist/release/releaseWorkflowPorts.js +45 -96
  110. package/dist/release/runtimeRelease.js +9 -15
  111. package/dist/repository/gitWorkspace.js +371 -105
  112. package/dist/repository/projectMaintenanceLock.js +98 -82
  113. package/dist/repository/taskBaseFreshness.js +1 -1
  114. package/dist/repository/taskWorkspaceCoordinator.js +82 -144
  115. package/dist/repository/taskWorkspacePreparer.js +113 -47
  116. package/dist/repository/workspaceCleanupInspection.js +187 -0
  117. package/dist/resources/autoResourceGc.js +4 -77
  118. package/dist/resources/liveReferences.js +7 -54
  119. package/dist/resources/resourceDiscovery.js +5 -118
  120. package/dist/resources/resourceGc.js +233 -181
  121. package/dist/resources/resourceRegistrar.js +5 -4
  122. package/dist/resources/resourceRegistry.js +3 -37
  123. package/dist/resources/resourceRegistryStore.js +13 -36
  124. package/dist/resources/sqliteResourceRegistry.js +43 -26
  125. package/dist/review/deltaRecheck.js +1 -1
  126. package/dist/review/reviewAcceptance.js +1 -1
  127. package/dist/review/reviewDecision.js +1 -1
  128. package/dist/review/reviewRound.js +8 -7
  129. package/dist/review/taskFinalReviewContractResolution.js +1 -1
  130. package/dist/runtime/acpProtocol.js +4 -51
  131. package/dist/runtime/acpSession.js +10 -75
  132. package/dist/runtime/acpSessionConfiguration.js +1 -8
  133. package/dist/runtime/agentEndpoint.js +3 -2
  134. package/dist/runtime/agentError.js +5 -3
  135. package/dist/runtime/agentFailureContext.js +43 -0
  136. package/dist/runtime/agentHost.js +42 -25
  137. package/dist/runtime/builtinAgentErrorMappers.js +91 -0
  138. package/dist/runtime/codexAppServerRuntime.js +34 -3
  139. package/dist/runtime/codexInteractiveHost.js +2 -2
  140. package/dist/runtime/index.js +0 -1
  141. package/dist/runtime/managedCaller.js +21 -1
  142. package/dist/runtime/providerControl.js +5 -1
  143. package/dist/runtime/providerErrors.js +38 -0
  144. package/dist/runtime/providerRetry.js +198 -0
  145. package/dist/runtime/providerRuntimeIdentity.js +28 -2
  146. package/dist/runtime/runtimeObservation.js +0 -5
  147. package/dist/runtime/runtimeSessionCandidate.js +2 -3
  148. package/dist/runtime/sessionOwnerIdentity.js +1 -1
  149. package/dist/runtime/sessionTokenMetrics.js +15 -5
  150. package/dist/runtime/structuredProviderHost.js +10 -43
  151. package/dist/runtime/taskUsageMetrics.js +275 -0
  152. package/dist/runtime/tmuxAdapters.js +6 -8
  153. package/dist/scheduler/activeRoleRunDelivery.js +19 -7
  154. package/dist/scheduler/leaderWakeupProcessor.js +24 -6
  155. package/dist/scheduler/operatorEvent.js +12 -20
  156. package/dist/scheduler/operatorInputNotificationProcessor.js +1 -1
  157. package/dist/scheduler/ports.js +5 -8
  158. package/dist/scheduler/roleRunLiveness.js +4 -4
  159. package/dist/scheduler/roleRunStall.js +16 -23
  160. package/dist/scheduler/taskExecutionProjection.js +49 -36
  161. package/dist/scheduler/taskObservabilityProjection.js +6 -45
  162. package/dist/scheduler/taskWake.js +5 -10
  163. package/dist/scheduler/wakeReason.js +2 -0
  164. package/dist/scheduler/wakeupQueue.js +2 -4
  165. package/dist/setup/setupCommand.js +1 -1
  166. package/dist/storage/contextRecords.js +106 -0
  167. package/dist/storage/currentTaskStore.js +1 -1
  168. package/dist/storage/homeLayout.js +13 -17
  169. package/dist/storage/migrations/agentFailureContext.js +22 -0
  170. package/dist/storage/migrations/currentInputContract.js +86 -0
  171. package/dist/storage/migrations/currentRuntimeContract.js +228 -0
  172. package/dist/storage/migrations/historicalVerificationPlan.js +35 -0
  173. package/dist/storage/migrations/integrationContinuation.js +5 -4
  174. package/dist/storage/migrations/narrowAgentFailureContext.js +65 -0
  175. package/dist/storage/migrations/notificationOnlyWakes.js +74 -0
  176. package/dist/storage/migrations/verificationPlanV1.js +162 -0
  177. package/dist/storage/migrations/verificationPolicy.js +74 -0
  178. package/dist/storage/migrations/workItemHistory.js +46 -0
  179. package/dist/storage/persistenceWorker.js +12 -4
  180. package/dist/storage/recordValidation.js +87 -0
  181. package/dist/storage/sqliteSchema.js +173 -1
  182. package/dist/storage/sqliteStore.js +172 -161
  183. package/dist/storage/storageSchema.js +2 -14
  184. package/dist/storage/storageVersions.js +1 -1
  185. package/dist/storage/storeRpc.js +16 -7
  186. package/dist/storage/taskCatalog.js +123 -0
  187. package/dist/storage/taskStore.js +5 -7
  188. package/dist/storage/upgrade/upgradeOrchestrator.js +25 -37
  189. package/dist/task/archiveDiagnostics.js +1 -0
  190. package/dist/task/archivePreflight.js +124 -0
  191. package/dist/task/completionReadiness.js +5 -24
  192. package/dist/task/draftPlan.js +0 -53
  193. package/dist/task/nextAction.js +7 -13
  194. package/dist/task/publicationAdoption.js +56 -0
  195. package/dist/task/publicationReference.js +10 -0
  196. package/dist/task/remoteDelivery.js +31 -16
  197. package/dist/task/remoteDeliveryService.js +89 -0
  198. package/dist/task/taskActivation.js +2 -25
  199. package/dist/task/taskActivationService.js +0 -2
  200. package/dist/task/taskRecordReference.js +0 -1
  201. package/dist/task/taskSubmission.js +3 -14
  202. package/dist/telemetry/sqliteTelemetryBatch.js +29 -0
  203. package/dist/telemetry/sqliteTelemetryStore.js +49 -49
  204. package/dist/telemetry/telemetryWiring.js +4 -3
  205. package/dist/tmux/tmuxManager.js +29 -20
  206. package/dist/verification/gateArtifact.js +15 -24
  207. package/dist/verification/gateArtifactStore.js +14 -7
  208. package/dist/verification/verificationGateService.js +29 -88
  209. package/dist/verification/verificationPlan.js +27 -72
  210. package/dist/web/assets/client/app.js +92 -17
  211. package/dist/web/assets/client/components.js +55 -13
  212. package/dist/web/assets/client/i18n.js +72 -4
  213. package/dist/web/assets/client/taskSurface.js +6 -5
  214. package/dist/web/assets/client/view.js +35 -7
  215. package/dist/web/assets/shell.js +6 -0
  216. package/dist/web/assets/styles/layout.js +7 -0
  217. package/dist/web/webServer.js +12 -3
  218. package/dist/web/webSnapshot.js +14 -85
  219. package/dist/web/webTaskSurface.js +17 -46
  220. package/dist/workItem/workItem.js +1 -12
  221. package/dist/workspace/cleanupInspection.js +63 -0
  222. package/dist/workspace/workItemChangeSetManager.js +110 -50
  223. package/docs/agent-result-consumption.md +4 -0
  224. package/docs/agent-result-consumption.zh-CN.md +3 -0
  225. package/docs/agent-runtime-drivers.md +7 -0
  226. package/docs/agent-runtime-drivers.zh-CN.md +5 -0
  227. package/docs/architecture/README.md +2 -0
  228. package/docs/architecture/README.zh-CN.md +3 -1
  229. package/docs/architecture/capabilities-and-resources.md +42 -5
  230. package/docs/architecture/capabilities-and-resources.zh-CN.md +33 -3
  231. package/docs/managed-turn-and-session-runtime.md +121 -1
  232. package/docs/managed-turn-and-session-runtime.zh-CN.md +96 -2
  233. package/docs/observability/README.md +62 -0
  234. package/docs/observability/README.zh-CN.md +47 -0
  235. package/docs/plugin-sdk.md +4 -2
  236. package/docs/project-refresh.md +77 -0
  237. package/docs/project-refresh.zh-CN.md +59 -0
  238. package/docs/provider-retry.md +70 -0
  239. package/docs/provider-runtime.md +3 -1
  240. package/docs/provider-runtime.zh-CN.md +4 -2
  241. package/docs/release-workflow.md +190 -7
  242. package/docs/release-workflow.zh-CN.md +139 -5
  243. package/docs/roles-and-configuration.md +29 -0
  244. package/docs/roles-and-configuration.zh-CN.md +21 -0
  245. package/docs/sqlite-control-plane-design.md +16 -3
  246. package/docs/sqlite-control-plane-design.zh-CN.md +13 -2
  247. package/docs/task-dag-semantics.md +3 -3
  248. package/docs/task-dag-semantics.zh-CN.md +2 -2
  249. package/docs/task-delivery.md +223 -17
  250. package/docs/task-delivery.zh-CN.md +171 -14
  251. package/docs/task-discovery.md +101 -0
  252. package/docs/task-discovery.zh-CN.md +85 -0
  253. package/docs/testing/verification-levels.md +161 -9
  254. package/docs/testing/verification-levels.zh-CN.md +116 -9
  255. package/i18n/README.zh-CN.md +13 -7
  256. package/package.json +1 -1
  257. package/skills/yui-leader/SKILL.md +5 -0
  258. package/skills/yui-leader/references/execution.md +3 -2
  259. package/skills/yui-leader/references/integration.md +9 -5
  260. package/skills/yui-leader/references/planning.md +9 -3
  261. package/skills/yui-operator/SKILL.md +24 -8
  262. package/skills/yui-reviewer/SKILL.md +4 -0
  263. package/skills/yui-runtime/SKILL.md +17 -2
  264. package/skills/yui-runtime/references/publication.md +26 -4
  265. package/skills/yui-runtime/references/recovery.md +71 -0
  266. package/dist/agent/agentRegistry.js +0 -10
  267. package/dist/agentRun/runIdentity.js +0 -22
  268. package/dist/commands/deliveryGuardPreflight.js +0 -30
  269. package/dist/commands/taskIntegrationQueueCommands.js +0 -226
  270. package/dist/commands/taskOverviewCommand.js +0 -376
  271. package/dist/completion/completionWizard.js +0 -125
  272. package/dist/context/dispatchContext.js +0 -110
  273. package/dist/context/wakeNotification.js +0 -144
  274. package/dist/integration/integrationCheckEvidenceReuse.js +0 -53
  275. package/dist/integration/integrationQueueEntry.js +0 -191
  276. package/dist/integration/integrationQueueService.js +0 -810
  277. package/dist/release/fakeReleasePorts.js +0 -55
  278. package/dist/runtime/sessionOwnerRegistry.js +0 -137
  279. package/dist/task/deliveryGuard.js +0 -226
  280. /package/dist/{commands/taskActor.js → task/taskAuthority.js} +0 -0
@@ -0,0 +1,127 @@
1
+ import { createHash } from "node:crypto";
2
+ import { isDeepStrictEqual } from "node:util";
3
+ import { parseRepeatable } from "../cli/parseRepeatable.js";
4
+ import { contextContentDigest } from "../context/contextSnapshot.js";
5
+ import { usageError } from "../errors/cliError.js";
6
+ import { createTaskEvent } from "../event/taskEvent.js";
7
+ import { NodeGitWorkspace } from "../repository/gitWorkspace.js";
8
+ import { PUBLICATION_ADOPTED_EVENT, publicationAdoption } from "../task/publicationAdoption.js";
9
+ import { publicationExternalKey } from "../task/publicationReference.js";
10
+ import { commitMap, completionEvent } from "../task/remoteDelivery.js";
11
+ import { resolveTaskRecordReference } from "../task/taskRecordReference.js";
12
+ import { assertTaskDeliveryAuthority, taskActor } from "../task/taskAuthority.js";
13
+ /** Local read -> explicit semantic adoption of those exact bytes. No Git writes,
14
+ * provider reads, completion rewrite or implicit acceptance of Integration. */
15
+ export async function runTaskPublicationAdoptCommand(args, store, options = {}) {
16
+ const [command, ...rest] = args;
17
+ const adopt = command === "adopt";
18
+ if (!adopt && command !== "diff")
19
+ throw usageError("Expected publication diff or adopt.");
20
+ const usage = adopt
21
+ ? "yui task publication adopt <task>/<publication> --reviewed-diff <sha256> --acceptance <text> [--integration <id>]"
22
+ : "yui task publication diff <task>/<publication> [--integration <id>]";
23
+ const parsed = parseRepeatable(rest, new Set(), new Set(adopt ? ["--reviewed-diff", "--acceptance", "--integration"] : ["--integration"]), usage);
24
+ if (parsed.positionals.length !== 1)
25
+ throw usageError(usage);
26
+ const ref = resolveTaskRecordReference(parsed.positionals[0], {
27
+ kind: "publicationReference", label: "Publication reference"
28
+ });
29
+ const acceptance = parsed.one.get("--acceptance")?.trim();
30
+ const reviewedDiff = parsed.one.get("--reviewed-diff");
31
+ if (adopt && (!acceptance || !/^[0-9a-f]{64}$/u.test(reviewedDiff ?? ""))) {
32
+ throw usageError(`Adoption requires a reviewed diff digest and explicit acceptance of the full delta. ${usage}`);
33
+ }
34
+ const integrationId = parsed.one.get("--integration");
35
+ const read = (reader) => {
36
+ // The reader addresses only this Task's managed Git objects. Workers and
37
+ // planning Sessions do not acquire publication-adoption authority.
38
+ const actor = adopt
39
+ ? assertTaskDeliveryAuthority(reader, options.environment, ref.taskId)
40
+ : taskActor(options.environment, ref.taskId);
41
+ const task = reader.getTask(ref.taskId);
42
+ if (task === null || task.status !== "completed") {
43
+ throw usageError("Publication candidate adoption/diff requires a completed, unarchived Task.");
44
+ }
45
+ const publication = reader.getPublicationReference(task.id, ref.localId);
46
+ if (publication === null || publication.localCommit === undefined) {
47
+ throw usageError("Publication must record an exact local candidate.");
48
+ }
49
+ const current = reader.findPublicationReferenceByExternalKey(publicationExternalKey(publication));
50
+ if (current?.taskId !== task.id || current.id !== publication.id) {
51
+ throw usageError("Publication is not the current record for its external identity.");
52
+ }
53
+ const completion = task.completedAt === undefined ? undefined
54
+ : completionEvent(reader.listEvents(task.id), task.completedAt);
55
+ const acceptedCommit = commitMap(completion?.payload.projectHeads).get(publication.projectId);
56
+ if (completion === undefined || acceptedCommit === undefined) {
57
+ throw usageError("Exact completion evidence is unavailable; it cannot be inferred or repaired by adoption.");
58
+ }
59
+ const workspace = reader.getTaskWorkspace(task.id);
60
+ const entry = workspace?.entries.find(e => e.projectId === publication.projectId);
61
+ if (workspace?.owner.type !== "task" || workspace.owner.taskId !== task.id
62
+ || entry === undefined
63
+ || !task.projectBindings.some(b => b.projectId === publication.projectId)) {
64
+ throw usageError("The Publication Project has no Task-owned workspace for local Git evidence.");
65
+ }
66
+ const integration = integrationId === undefined ? null
67
+ : reader.getIntegrationAttempt(task.id, integrationId);
68
+ if (integrationId !== undefined && (integration === null
69
+ || integration.status !== "committed"
70
+ || integration.projectId !== publication.projectId
71
+ || integration.afterCommit !== publication.localCommit)) {
72
+ throw usageError("Integration must be this Task/Project's committed exact publication candidate.");
73
+ }
74
+ return { task, publication, completion, acceptedCommit, workspace, entry, integration, actor };
75
+ };
76
+ const facts = store.transaction(read);
77
+ const git = options.git ?? new NodeGitWorkspace();
78
+ const localCommit = facts.publication.localCommit;
79
+ const [acceptedTree, candidateTree, diff] = await Promise.all([
80
+ git.resolveTree(facts.entry.path, facts.acceptedCommit),
81
+ git.resolveTree(facts.entry.path, localCommit),
82
+ git.diffTextBetween({ repositoryPath: facts.entry.path,
83
+ fromCommit: facts.acceptedCommit, toCommit: localCommit, exact: true })
84
+ ]);
85
+ // Bind both endpoints even when the text diff is empty (equal trees).
86
+ const diffDigest = createHash("sha256").update(JSON.stringify({
87
+ acceptedCommit: facts.acceptedCommit, localCommit, acceptedTree, candidateTree, diff
88
+ })).digest("hex");
89
+ const evidence = {
90
+ projectId: facts.publication.projectId,
91
+ publicationId: facts.publication.id,
92
+ completionEventId: facts.completion.id,
93
+ acceptedCommit: facts.acceptedCommit,
94
+ localCommit, acceptedTree, candidateTree, diffDigest,
95
+ ...(facts.integration === null ? {} : {
96
+ integrationId: facts.integration.id, integrationDigest: contextContentDigest(facts.integration)
97
+ })
98
+ };
99
+ // No async Git/provider work under the transaction; fixed objects cannot move.
100
+ const event = store.transaction(tx => {
101
+ if (!isDeepStrictEqual(read(tx), facts)) {
102
+ throw usageError("Task, Publication or Integration changed while reading candidate evidence.");
103
+ }
104
+ if (!adopt)
105
+ return null;
106
+ if (reviewedDiff !== diffDigest) {
107
+ throw usageError(`Reviewed diff does not match this candidate. Read publication diff ${ref.taskId}/${ref.localId}.`);
108
+ }
109
+ const existing = publicationAdoption(facts.publication, facts.completion, facts.acceptedCommit, tx.listEvents(facts.task.id), tx.listPublicationReferences(facts.task.id), tx.listIntegrationAttempts(facts.task.id)).event;
110
+ if (existing !== null && existing.payload.diffDigest === diffDigest
111
+ && existing.payload.acceptance === acceptance
112
+ && existing.payload.integrationId === integrationId)
113
+ return existing;
114
+ const saved = createTaskEvent(tx.nextEventId(facts.task.id), facts.task.id, PUBLICATION_ADOPTED_EVENT, { ...evidence, acceptance: acceptance, by: facts.actor }, options.now?.() ?? new Date());
115
+ tx.saveEvent(facts.task.id, saved);
116
+ return saved;
117
+ });
118
+ return {
119
+ output: event === null
120
+ ? `Publication candidate: ${ref.taskId}/${ref.localId}\nAccepted: ${facts.acceptedCommit}\n`
121
+ + `Candidate: ${localCommit}\nReviewed diff digest: ${diffDigest}\n`
122
+ + "Review all removals, additions and conflict resolutions against the original acceptance before adoption.\n"
123
+ + `${diff}\n`
124
+ : `Adopted Publication candidate ${ref.taskId}/${ref.localId} (${event.id}); remote verification remains separate.\n`,
125
+ data: event === null ? { ...evidence, diff } : event
126
+ };
127
+ }
@@ -1,5 +1,4 @@
1
1
  import { isDeepStrictEqual } from "node:util";
2
- import { taskActor } from "./taskActor.js";
3
2
  import { dataError, taskNotFound, usageError } from "../errors/cliError.js";
4
3
  import { createTaskEvent } from "../event/taskEvent.js";
5
4
  import { defaultTableWidth, renderTable } from "../output/table.js";
@@ -7,6 +6,7 @@ import { formatTimestamp } from "../output/timePresentation.js";
7
6
  import { resolveProject } from "../repository/project.js";
8
7
  import { createPublicationReference } from "../task/publicationReference.js";
9
8
  import { resolveTaskRecordReference } from "../task/taskRecordReference.js";
9
+ import { taskActor } from "../task/taskAuthority.js";
10
10
  const PROVIDERS = new Set(["github", "gitlab"]);
11
11
  const EXTERNAL_KINDS = new Set(["pull-request", "merge-request"]);
12
12
  const STATES = new Set(["open", "merged", "closed"]);
@@ -17,6 +17,7 @@ const INHERITED_METADATA_FIELDS = [
17
17
  "targetBranch"
18
18
  ];
19
19
  const INHERITED_EVIDENCE_FIELDS = [
20
+ "headCommit",
20
21
  "remoteCommit",
21
22
  "evidence",
22
23
  "mergedAt"
@@ -34,7 +35,7 @@ export function runPublicationCommand(args, store, options) {
34
35
  }
35
36
  }
36
37
  function upsertPublication(args, store, options) {
37
- const usage = "Task publication upsert usage: yui task publication upsert <task> --project <project> --provider <github|gitlab> --repository <owner/name> --kind <pull-request|merge-request> --id <external-id> [--url <url>] [--title <text>] [--source-branch <branch>] [--target-branch <branch>] [--local-commit <sha>] [--remote-commit <sha>] [--state <open|merged|closed>] [--reported|--verified] [--evidence <text>] [--merged-at <iso-timestamp>].";
38
+ const usage = "Task publication upsert usage: yui task publication upsert <task> --project <project> --provider <github|gitlab> --repository <owner/name> --kind <pull-request|merge-request> --id <external-id> [--url <url>] [--title <text>] [--source-branch <branch>] [--target-branch <branch>] [--local-commit <sha>] [--head-commit <sha>] [--remote-commit <sha>] [--state <open|merged|closed>] [--reported|--verified] [--evidence <text>] [--merged-at <iso-timestamp>].";
38
39
  const parsed = parseUpsertArgs(args, usage);
39
40
  exactPositionals(parsed.positionals, 1, usage);
40
41
  const task = requireTask(store, parsed.positionals[0]);
@@ -72,6 +73,9 @@ function upsertPublication(args, store, options) {
72
73
  ...(parsed.options.has("--remote-commit")
73
74
  ? { remoteCommit: requiredOption(parsed.options, "--remote-commit", usage) }
74
75
  : {}),
76
+ ...(parsed.options.has("--head-commit")
77
+ ? { headCommit: requiredOption(parsed.options, "--head-commit", usage) }
78
+ : {}),
75
79
  ...(state === undefined ? {} : { state }),
76
80
  ...(verification === undefined ? {} : { verification }),
77
81
  ...(parsed.options.has("--evidence")
@@ -181,6 +185,7 @@ function renderPublication(reference, timeZone) {
181
185
  : [`Branches: ${reference.sourceBranch ?? "unknown"} -> ${reference.targetBranch ?? "unknown"}`]),
182
186
  `State: ${reference.state}`,
183
187
  `Verification: ${reference.verification}`,
188
+ ...(reference.headCommit === undefined ? [] : [`Remote head: ${reference.headCommit}`]),
184
189
  `Lineage: ${reference.localCommit ?? "unknown"} -> ${reference.externalId} -> ${reference.remoteCommit ?? "unknown"}`,
185
190
  ...(reference.mergedAt === undefined
186
191
  ? []
@@ -234,6 +239,10 @@ function inheritPublicationInput(existing, input) {
234
239
  const mergedAtChanged = input.mergedAt !== undefined
235
240
  && input.mergedAt !== existing.mergedAt;
236
241
  const evidenceContextChanged = localCommitChanged
242
+ || (input.headCommit !== undefined
243
+ && normalizeCommitForComparison(input.headCommit) !== existing.headCommit)
244
+ || input.projectId !== existing.projectId
245
+ || input.externalKind !== existing.externalKind
237
246
  || stateChanged
238
247
  || remoteCommitChanged
239
248
  || evidenceChanged
@@ -321,7 +330,7 @@ function parseUpsertArgs(args, usage) {
321
330
  const valueOptions = new Set([
322
331
  "--project", "--provider", "--repository", "--kind", "--id", "--url",
323
332
  "--title", "--source-branch", "--target-branch", "--local-commit",
324
- "--remote-commit", "--state", "--evidence", "--merged-at"
333
+ "--remote-commit", "--head-commit", "--state", "--evidence", "--merged-at"
325
334
  ]);
326
335
  const flags = new Set(["--reported", "--verified"]);
327
336
  const positionals = [];
@@ -1,7 +1,6 @@
1
1
  import { isDeepStrictEqual } from "node:util";
2
- import { taskActor } from "./taskActor.js";
2
+ import { taskActor } from "../task/taskAuthority.js";
3
3
  import { upsertTaskPublication } from "./taskPublicationCommands.js";
4
- import { projectTaskRemoteDeliveryFromStore } from "./taskRemoteDeliveryCommand.js";
5
4
  import { dataError, runtimeError, taskNotFound, usageError, CliError } from "../errors/cliError.js";
6
5
  import { publicationExternalKey } from "../task/publicationReference.js";
7
6
  import { resolveTaskRecordReference } from "../task/taskRecordReference.js";
@@ -14,8 +13,7 @@ export async function runTaskPublicationVerifyCommand(args, store, options) {
14
13
  throw usageError(`Archived Task Publication cannot be verified: ${task.id}.`);
15
14
  }
16
15
  taskActor(options.environment, task.id);
17
- const initialCandidate = await options.candidateForTask?.(reference.taskId) ?? null;
18
- const request = preparePublicationVerification(store, reference.taskId, reference.localId, initialCandidate, options.environment);
16
+ const request = preparePublicationVerification(store, reference.taskId, reference.localId, options.environment);
19
17
  const verifier = options.verifiers[request.publication.provider];
20
18
  if (verifier === undefined) {
21
19
  throw usageError(`Publication verification is not supported for provider `
@@ -42,19 +40,22 @@ export async function runTaskPublicationVerifyCommand(args, store, options) {
42
40
  + `${error instanceof Error ? error.message : String(error)}`);
43
41
  }
44
42
  assertVerificationObservation(request, observation);
45
- const finalCandidate = await options.candidateForTask?.(reference.taskId) ?? null;
46
- const result = commitPublicationVerification(store, request, observation, finalCandidate, options.now?.() ?? new Date());
43
+ const result = commitPublicationVerification(store, request, observation, options.now?.() ?? new Date());
47
44
  return {
48
45
  kind: "output",
49
- output: result.idempotent
50
- ? `Publication ${result.reference.id} is already verified for `
51
- + `${result.reference.repository}#${result.reference.externalId}.\n`
52
- : `Verified publication ${result.reference.id} for `
53
- + `${result.reference.repository}#${result.reference.externalId}.\n`,
46
+ output: result.reference.verification !== "verified"
47
+ ? `Recorded Publication ${result.reference.id}: remote state=${observation.state}; `
48
+ + `head=${observation.headCommit}; local=${request.expectedLocalCommit}. `
49
+ + "Not verified; prior verification is no longer current.\n"
50
+ : result.idempotent
51
+ ? `Publication ${result.reference.id} is already verified for `
52
+ + `${result.reference.repository}#${result.reference.externalId}.\n`
53
+ : `Verified publication ${result.reference.id} for `
54
+ + `${result.reference.repository}#${result.reference.externalId}.\n`,
54
55
  data: { publication: result.reference, observation }
55
56
  };
56
57
  }
57
- function preparePublicationVerification(store, taskId, publicationId, currentCandidate, environment) {
58
+ function preparePublicationVerification(store, taskId, publicationId, environment) {
58
59
  return store.transaction((reader) => {
59
60
  const task = reader.getTask(taskId);
60
61
  if (task === null)
@@ -72,27 +73,19 @@ function preparePublicationVerification(store, taskId, publicationId, currentCan
72
73
  throw usageError(`Publication ${publication.id} is not the current unsuperseded record `
73
74
  + `for ${publicationExternalKey(publication)}.`);
74
75
  }
75
- const delivery = projectTaskRemoteDeliveryFromStore(reader, task, currentCandidate);
76
- const project = delivery.projects.find(({ projectId }) => (projectId === publication.projectId));
76
+ const project = task.projectBindings.find(({ projectId }) => (projectId === publication.projectId));
77
77
  if (project === undefined) {
78
78
  throw usageError(`Publication ${publication.id} Project is not bound to Task ${task.id}: `
79
79
  + `${publication.projectId}.`);
80
80
  }
81
- if (project.expectedLocalCommit === null) {
82
- throw usageError(`Task delivery head is unavailable for Publication ${publication.id}.`);
83
- }
84
81
  if (publication.localCommit === undefined) {
85
82
  throw usageError(`Publication ${publication.id} must record a local commit before verification.`);
86
83
  }
87
- if (publication.localCommit !== project.expectedLocalCommit) {
88
- throw usageError(`Publication ${publication.id} local commit ${publication.localCommit} `
89
- + `does not match Task delivery head ${project.expectedLocalCommit}.`);
90
- }
91
84
  return {
92
85
  task: taskVerificationInvariant(task),
93
86
  actor,
94
87
  publication,
95
- expectedLocalCommit: project.expectedLocalCommit
88
+ expectedLocalCommit: publication.localCommit
96
89
  };
97
90
  });
98
91
  }
@@ -104,22 +97,17 @@ function assertVerificationObservation(request, observation) {
104
97
  || observation.externalId !== publication.externalId) {
105
98
  throw usageError(`Provider returned mismatched Publication identity for ${publication.id}.`);
106
99
  }
107
- if (observation.state !== "merged") {
108
- throw usageError(`Remote ${publication.externalKind} ${publication.repository}#`
109
- + `${publication.externalId} is ${observation.state}, not merged.`);
100
+ if (!/^[0-9a-f]{40}$/u.test(observation.headCommit)) {
101
+ throw usageError("Provider observation requires an exact remote head.");
110
102
  }
111
- if (observation.headCommit !== request.expectedLocalCommit) {
112
- throw usageError(`Remote ${publication.externalKind} head ${observation.headCommit} `
113
- + `does not match Task delivery head ${request.expectedLocalCommit}.`);
114
- }
115
- if (observation.remoteCommit === undefined) {
103
+ if (observation.state === "merged" && observation.remoteCommit === undefined) {
116
104
  throw usageError(`Merged remote ${publication.externalKind} did not expose a remote commit.`);
117
105
  }
118
106
  if (observation.evidence.trim().length === 0) {
119
107
  throw usageError("Provider verification evidence is required.");
120
108
  }
121
109
  }
122
- function commitPublicationVerification(store, request, observation, currentCandidate, now) {
110
+ function commitPublicationVerification(store, request, observation, now) {
123
111
  return store.transaction((tx) => {
124
112
  const task = tx.getTask(request.task.id);
125
113
  if (task === null)
@@ -134,12 +122,6 @@ function commitPublicationVerification(store, request, observation, currentCandi
134
122
  throw usageError(`Publication evidence changed during verification: `
135
123
  + `${task.id}/${request.publication.id}.`);
136
124
  }
137
- const delivery = projectTaskRemoteDeliveryFromStore(tx, task, currentCandidate);
138
- const expectedLocalCommit = delivery.projects.find(({ projectId }) => (projectId === request.publication.projectId))?.expectedLocalCommit;
139
- if (expectedLocalCommit !== request.expectedLocalCommit) {
140
- throw usageError(`Task delivery head changed during Publication verification: `
141
- + `${request.publication.projectId}@${expectedLocalCommit ?? "unavailable"}.`);
142
- }
143
125
  return upsertTaskPublication(tx, task, {
144
126
  projectId: request.publication.projectId,
145
127
  provider: request.publication.provider,
@@ -150,9 +132,11 @@ function commitPublicationVerification(store, request, observation, currentCandi
150
132
  ? {}
151
133
  : { externalUrl: observation.externalUrl }),
152
134
  localCommit: request.expectedLocalCommit,
153
- remoteCommit: observation.remoteCommit,
154
- state: "merged",
155
- verification: "verified",
135
+ headCommit: observation.headCommit,
136
+ ...(observation.remoteCommit === undefined ? {} : { remoteCommit: observation.remoteCommit }),
137
+ state: observation.state,
138
+ verification: observation.state === "merged"
139
+ && observation.headCommit === request.expectedLocalCommit ? "verified" : "reported",
156
140
  evidence: observation.evidence,
157
141
  ...(observation.mergedAt === undefined
158
142
  ? {}
@@ -1,6 +1,5 @@
1
- import { isDeepStrictEqual } from "node:util";
2
1
  import { taskNotFound, usageError } from "../errors/cliError.js";
3
- import { projectTaskRemoteDelivery } from "../task/remoteDelivery.js";
2
+ import { projectTaskRemoteDeliveryFromStore } from "../task/remoteDeliveryService.js";
4
3
  export function runTaskRemoteDeliveryCommand(args, store, currentCandidate = null) {
5
4
  const usage = "Task remote-delivery usage: yui task remote-delivery <task> [--json].";
6
5
  const asJson = args.includes("--json");
@@ -9,7 +8,7 @@ export function runTaskRemoteDeliveryCommand(args, store, currentCandidate = nul
9
8
  throw usageError(usage);
10
9
  }
11
10
  const taskId = positionals[0].trim();
12
- const data = store.transaction((reader) => {
11
+ const data = store.readTransaction((reader) => {
13
12
  const task = reader.getTask(taskId);
14
13
  if (task === null)
15
14
  throw taskNotFound(taskId);
@@ -23,76 +22,6 @@ export function runTaskRemoteDeliveryCommand(args, store, currentCandidate = nul
23
22
  data
24
23
  };
25
24
  }
26
- export function projectTaskRemoteDeliveryFromStore(store, task, currentCandidate = null) {
27
- return projectTaskRemoteDelivery({
28
- task,
29
- events: store.listEvents(task.id),
30
- publications: store.listPublicationReferences(task.id),
31
- managedWorkspaces: store.listManagedWorkspaces(task.id),
32
- runs: store.listRuns(task.id),
33
- currentCandidate
34
- });
35
- }
36
- export function createTaskRemoteDeliveryProof(store, task, currentCandidate = null) {
37
- const publications = store.listPublicationReferences(task.id);
38
- const delivery = projectTaskRemoteDelivery({
39
- task,
40
- events: store.listEvents(task.id),
41
- publications,
42
- managedWorkspaces: store.listManagedWorkspaces(task.id),
43
- runs: store.listRuns(task.id),
44
- currentCandidate
45
- });
46
- return {
47
- schemaVersion: 1,
48
- task: taskRemoteDeliveryProofTask(task),
49
- publications,
50
- delivery
51
- };
52
- }
53
- export function assertTaskRemoteDeliveryProof(store, task, proof) {
54
- if (proof === undefined || proof.schemaVersion !== 1) {
55
- throw usageError(`Task remote-delivery preflight proof is required: ${task.id}.`);
56
- }
57
- if (!isDeepStrictEqual(proof.task, taskRemoteDeliveryProofTask(task))) {
58
- throw usageError(`Task changed after remote-delivery preflight: ${task.id}.`);
59
- }
60
- if (!isDeepStrictEqual(proof.publications, store.listPublicationReferences(task.id))) {
61
- throw usageError(`Task Publication evidence changed after remote-delivery preflight: ${task.id}.`);
62
- }
63
- assertTaskRemoteDeliveryIntegrated(proof.delivery);
64
- return proof.delivery;
65
- }
66
- export function assertTaskRemoteDeliveryIntegrated(delivery) {
67
- if (!delivery.allMerged) {
68
- const headUnavailable = delivery.projects.filter((project) => (project.codeDelivery !== "none"
69
- && project.coverage === "head-unavailable"));
70
- if (headUnavailable.length > 0 && delivery.source === "task-completed") {
71
- throw usageError(`Task ${delivery.taskId} has no frozen completion heads for: ${headUnavailable.map(({ projectId }) => projectId).join(", ")}. Reopen and complete it again to record exact heads before archiving; `
72
- + "An explicitly authorized --force archive retains this evidence gap.");
73
- }
74
- const uncovered = delivery.projects
75
- .filter((project) => project.codeDelivery !== "none" && !project.merged)
76
- .map((project) => (`${project.projectId}/${project.coverage}`
77
- + (project.publication === null ? "" : `/${project.publication.id}`)))
78
- .join(", ");
79
- throw usageError(`Task ${delivery.taskId} is not fully merged into remote delivery: ${uncovered || "expected Project heads are unavailable"}. Record confirmed current-head evidence with task publication upsert, `
80
- + "or use task archive --abandon for an intentional non-merge.");
81
- }
82
- if (delivery.allVerified)
83
- return;
84
- const unverified = delivery.projects
85
- .filter((project) => (project.codeDelivery !== "none"
86
- && project.merged
87
- && !project.verified))
88
- .map((project) => (`${project.projectId}/${project.coverage}`
89
- + (project.publication === null ? "" : `/${project.publication.id}`)))
90
- .join(", ");
91
- throw usageError(`Task ${delivery.taskId} has merged Publication evidence that is not verified: `
92
- + `${unverified || "verification evidence is unavailable"}. Run task publication verify `
93
- + "for each Publication, or repeat task archive --integrated --force to explicitly "
94
- + "archive despite evidence gaps, retaining the original delivery facts.");
95
- }
96
25
  export function renderTaskRemoteDelivery(delivery, indent = "") {
97
26
  const source = `${delivery.source}${delivery.provisional ? " (provisional)" : ""}`;
98
27
  const lines = [
@@ -108,27 +37,17 @@ export function renderTaskRemoteDelivery(delivery, indent = "") {
108
37
  `${indent}Projects:${delivery.projects.length === 0 ? " none" : ""}`,
109
38
  ...delivery.projects.map((project) => (`${indent}- ${project.directory} (${project.projectId}): `
110
39
  + `expected=${shortCommit(project.expectedLocalCommit)}; `
40
+ + `candidate=${shortCommit(project.deliveryLocalCommit)}; `
41
+ + `adoption=${project.adoption?.id ?? "none"}; `
111
42
  + `base=${shortCommit(project.baseCommit)}; `
112
43
  + `publication=${project.publication?.id ?? "none"}; `
113
44
  + `state=${project.state ?? "none"}; `
114
45
  + `verification=${project.verification ?? "none"}; `
115
46
  + `remote=${shortCommit(project.remoteCommit)}; `
116
- + `coverage=${project.coverage}`))
47
+ + `coverage=${project.coverage}\n${indent} ${project.reason}`))
117
48
  ];
118
49
  return `${lines.join("\n")}\n`;
119
50
  }
120
51
  function shortCommit(commit) {
121
52
  return commit === null ? "unknown" : commit.slice(0, 12);
122
53
  }
123
- function taskRemoteDeliveryProofTask(task) {
124
- return {
125
- id: task.id,
126
- status: task.status,
127
- projectBindings: task.projectBindings,
128
- ...(task.workspaceIdentity === undefined
129
- ? {}
130
- : { workspaceIdentity: task.workspaceIdentity }),
131
- ...(task.completedAt === undefined ? {} : { completedAt: task.completedAt }),
132
- ...(task.retiredAt === undefined ? {} : { retiredAt: task.retiredAt })
133
- };
134
- }
@@ -1,11 +1,11 @@
1
+ import { parseRepeatable } from "../cli/parseRepeatable.js";
1
2
  import { usageError } from "../errors/cliError.js";
2
3
  import { GitIntegrationService } from "../integration/gitIntegrationService.js";
3
4
  import { createIntegrationAttempt } from "../integration/integrationAttempt.js";
4
5
  import { NodeGitWorkspace } from "../repository/gitWorkspace.js";
5
6
  import { FileTaskWorkspacePreparer } from "../repository/taskWorkspacePreparer.js";
6
7
  import { workspaceProjectEntry } from "../worktree/managedWorkspace.js";
7
- import { parseRepeatable } from "./taskIntegrationCommands.js";
8
- import { taskLocalActor } from "./taskActor.js";
8
+ import { taskLocalActor } from "../task/taskAuthority.js";
9
9
  export async function runTaskUpstreamCommand(args, store, home, options = {}) {
10
10
  const [command, ...rest] = args;
11
11
  if (command === "integrate")
@@ -15,7 +15,7 @@ export async function runTaskUpstreamCommand(args, store, home, options = {}) {
15
15
  : `Unknown command: task upstream ${command}`);
16
16
  }
17
17
  async function integrateUpstream(args, store, home, options) {
18
- const usage = "Task upstream integrate usage: yui task upstream integrate <task> (--latest|--project <project>) [--check <command> ...].";
18
+ const usage = "Task upstream integrate usage: yui task upstream integrate <task> (--latest|--project <project>) [--check <command> ...] [--rerun-checks].";
19
19
  let latest = false;
20
20
  const normalized = [];
21
21
  for (const arg of args) {
@@ -29,7 +29,7 @@ async function integrateUpstream(args, store, home, options) {
29
29
  ? ["--project", arg.slice("--project=".length)]
30
30
  : [arg]));
31
31
  }
32
- const parsed = parseRepeatable(normalized, new Set(["--check"]), new Set(["--project"]), usage);
32
+ const parsed = parseRepeatable(normalized, new Set(["--check"]), new Set(["--project"]), usage, new Set(["--rerun-checks"]));
33
33
  if (parsed.positionals.length !== 1)
34
34
  throw usageError(usage);
35
35
  const taskId = parsed.positionals[0];
@@ -59,7 +59,7 @@ async function integrateUpstream(args, store, home, options) {
59
59
  if (workspace === null || workspace.owner.type !== "task") {
60
60
  throw usageError(`Task has no authoritative main clone: ${task.id}.`);
61
61
  }
62
- const service = new GitIntegrationService(store.rootDirectory(), store, git, now);
62
+ const service = new GitIntegrationService(store.rootDirectory(), store, git, now, options.environment, undefined, options.jobPort);
63
63
  const results = [];
64
64
  for (const binding of task.projectBindings) {
65
65
  if (projectRef !== undefined && binding.projectId !== projectRef)
@@ -99,20 +99,31 @@ async function integrateUpstream(args, store, home, options) {
99
99
  taskBaseCommit: binding.baseCommit,
100
100
  strategy: "rebase"
101
101
  },
102
- checkCommands: parsed.many.get("--check") ?? []
102
+ checkCommands: parsed.many.get("--check") ?? [],
103
+ rerunChecks: parsed.one.has("--rerun-checks")
103
104
  }, now());
104
105
  tx.saveIntegrationAttempt(task.id, created);
105
106
  return created;
106
107
  });
107
108
  const result = await service.integrate(task.id, attempt.id);
108
109
  results.push(result);
109
- if (result.status !== "committed")
110
+ // Each Project has an independent candidate and Job. --latest admits all
111
+ // requested Projects, then the Agent continues the returned exact attempts.
112
+ if (result.status !== "committed" && result.status !== "checks-running")
110
113
  break;
111
114
  }
112
115
  if (projectRef !== undefined && results.length === 0) {
113
116
  throw usageError(`Task Project not found: ${task.id}/${projectRef}.`);
114
117
  }
115
- const lines = results.map(({ attempt, status }) => (` ${attempt.projectId}: ${attempt.beforeCommit.slice(0, 12)} -> ${(attempt.afterCommit ?? attempt.candidateCommit ?? attempt.beforeCommit).slice(0, 12)} (${status})`));
118
+ const lines = results.flatMap(result => {
119
+ const { attempt, status } = result;
120
+ return [
121
+ ` ${attempt.id} ${attempt.projectId}: ${attempt.beforeCommit.slice(0, 12)} -> ${(attempt.afterCommit ?? attempt.candidateCommit ?? attempt.beforeCommit).slice(0, 12)} (${status})`,
122
+ ...(status === "checks-running" ? [
123
+ ` Job ${result.job.id}; continue with yui task integration continue ${task.id}/${attempt.id}`
124
+ ] : [])
125
+ ];
126
+ });
116
127
  return {
117
128
  output: `Upstream Integration results for Task ${task.id}:\n${lines.join("\n")}\n`,
118
129
  data: { taskId: task.id, integrations: results }
@@ -103,7 +103,12 @@ export async function runWorkflowCommandAsync(args, store, options) {
103
103
  // failure so the caller knows this path was compromised.
104
104
  if (typeof store.rootDirectory === "function") {
105
105
  const auditStore = openConfiguredTaskStore(store.rootDirectory());
106
- recordTaskEvent(auditStore, taskId, "release-workflow.run", eventPayload, eventNow);
106
+ try {
107
+ recordTaskEvent(auditStore, taskId, "release-workflow.run", eventPayload, eventNow);
108
+ }
109
+ finally {
110
+ auditStore.close();
111
+ }
107
112
  }
108
113
  throw error;
109
114
  }