@zq-silk/yui 0.14.0 → 0.14.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 +64 -35
- package/README.md +258 -125
- package/dist/agent/argumentPolicy.js +2 -1
- package/dist/agent/managedRuntimeEnvironment.js +5 -8
- package/dist/cli/commandCatalog.js +74 -109
- package/dist/cli/helpRenderer.js +1 -2
- package/dist/cli/interactionCandidates.js +10 -0
- package/dist/cli/interactionPolicy.js +76 -37
- package/dist/cli/roleWizard.js +5 -6
- package/dist/cli/updateOrchestrator.js +10 -8
- package/dist/cli/updatePorts.js +17 -13
- package/dist/cli/upgradeCommand.js +2 -5
- package/dist/cli.js +268 -231
- package/dist/commands/agentCommands.js +13 -0
- package/dist/commands/configCommands.js +7 -19
- package/dist/commands/configOverview.js +3 -2
- package/dist/commands/durableJobCommands.js +1 -1
- package/dist/commands/executionAuditCommands.js +4 -9
- package/dist/commands/globalRoleCommands.js +17 -0
- package/dist/commands/profileCommands.js +200 -30
- package/dist/commands/sessionCommands.js +1 -1
- package/dist/commands/taskActor.js +29 -127
- package/dist/commands/taskChangeSetCommands.js +1 -3
- package/dist/commands/taskCommands.js +1771 -2107
- package/dist/commands/taskCompletionGate.js +27 -103
- package/dist/commands/taskContextCommand.js +47 -80
- package/dist/commands/taskExecutionCommands.js +9 -27
- package/dist/commands/taskInputCommands.js +10 -10
- package/dist/commands/taskIntegrationCommands.js +69 -61
- package/dist/commands/taskIntegrationQueueCommands.js +1 -1
- package/dist/commands/taskNextActionCommand.js +8 -29
- package/dist/commands/taskOverviewCommand.js +25 -3
- package/dist/commands/taskPublicationCommands.js +151 -85
- package/dist/commands/taskPublicationVerifyCommand.js +181 -0
- package/dist/commands/taskRemoteDeliveryCommand.js +134 -0
- package/dist/commands/taskRoleRuntimeStatus.js +5 -6
- package/dist/commands/taskUpstreamCommands.js +79 -95
- package/dist/config/configCatalog.js +1 -1
- package/dist/context/contextSnapshot.js +17 -2
- package/dist/context/sessionBootstrapManifest.js +18 -1
- package/dist/context/sourceTurnContext.js +30 -0
- package/dist/context/turnContextPack.js +107 -48
- package/dist/context/turnInputContract.js +11 -4
- package/dist/context/wakeNotification.js +84 -22
- package/dist/controller/agentRuntimeObserver.js +9 -12
- package/dist/controller/clientRuntime.js +13 -13
- package/dist/controller/controller.js +11 -11
- package/dist/controller/fileSchedulerStoreAdapter.js +262 -219
- package/dist/controller/jobControl.js +11 -10
- package/dist/controller/resourceInventory.js +6 -6
- package/dist/controller/resourceInventoryLinux.js +2 -2
- package/dist/controller/runtime.js +18 -61
- package/dist/controller/runtimeEventInbox.js +57 -34
- package/dist/controller/runtimeEventProcessor.js +36 -96
- package/dist/controller/runtimeHookTurnFence.js +33 -57
- package/dist/controller/runtimeLaunchCoordinator.js +44 -40
- package/dist/controller/runtimeObservationHook.js +18 -12
- package/dist/controller/sessionNotify.js +43 -28
- package/dist/controller/sessionOwnerReconciliation.js +21 -21
- package/dist/controller/structuredProviderObservation.js +13 -16
- package/dist/coordination/workMailboxQueue.js +132 -0
- package/dist/core/controllerServer.js +1 -0
- package/dist/domain/agentResultTransport.js +60 -0
- package/dist/execution/executionHealth.js +111 -118
- package/dist/execution/reviewMainTurn.js +161 -0
- package/dist/execution/workItemExecution.js +454 -0
- package/dist/execution/workItemExecutionProjection.js +309 -0
- package/dist/execution/workItemMainTurn.js +164 -0
- package/dist/executor/agentExecutor.js +19 -19
- package/dist/executor/executorRegistry.js +7 -28
- package/dist/executor/fileRoleLaunchPlanner.js +51 -83
- package/dist/external/githubPublicationVerifier.js +114 -0
- package/dist/external/gitlabPublicationVerifier.js +158 -0
- package/dist/external/pinnedCommandRunner.js +73 -0
- package/dist/integration/changeSetManifest.js +0 -3
- package/dist/integration/deliveryObligation.js +43 -6
- package/dist/integration/gitIntegrationService.js +284 -101
- package/dist/integration/integrationAttempt.js +64 -14
- package/dist/integration/integrationQueueEntry.js +5 -35
- package/dist/integration/integrationQueueService.js +65 -194
- package/dist/lifecycle/canonicalLifecycleEvent.js +16 -15
- package/dist/lifecycle/exactTurnTerminalization.js +100 -97
- package/dist/message/message.js +16 -0
- package/dist/observability/executionAudit.js +4 -25
- package/dist/observability/faultClassification.js +58 -70
- package/dist/observability/orchestrationMetrics.js +8 -50
- package/dist/profile/agentProfile.js +60 -15
- package/dist/profile/agentProfileRuntime.js +100 -0
- package/dist/release/releaseWorkflowPorts.js +5 -68
- package/dist/repository/executionLaneGitSnapshot.js +80 -0
- package/dist/repository/gitWorkspace.js +9 -67
- package/dist/repository/taskBaseFreshness.js +3 -1
- package/dist/repository/taskWorkspaceCoordinator.js +32 -4
- package/dist/repository/taskWorkspacePreparer.js +252 -411
- package/dist/resources/liveReferences.js +6 -55
- package/dist/resources/resourceDiscovery.js +1 -30
- package/dist/resources/resourceRegistrar.js +0 -23
- package/dist/review/deltaRecheck.js +8 -65
- package/dist/review/reviewAcceptance.js +22 -19
- package/dist/review/reviewConfig.js +0 -10
- package/dist/review/reviewDecision.js +2 -2
- package/dist/review/reviewRound.js +147 -273
- package/dist/review/reviewerAvailability.js +13 -23
- package/dist/role/role.js +3 -0
- package/dist/runtime/agentDriverObservation.js +1 -1
- package/dist/runtime/agentHost.js +51 -51
- package/dist/runtime/builtinAgentDrivers.js +9 -2
- package/dist/runtime/codexAppServerRuntime.js +23 -5
- package/dist/runtime/exactControlPlane.js +2 -267
- package/dist/runtime/firstProgressAdvisory.js +1 -1
- package/dist/runtime/index.js +1 -1
- package/dist/runtime/launchBroker.js +11 -11
- package/dist/runtime/lifecycleReservation.js +2 -2
- package/dist/runtime/managedCaller.js +111 -0
- package/dist/runtime/ports.js +16 -3
- package/dist/runtime/preallocatedNativeSession.js +2 -2
- package/dist/runtime/processExitObservation.js +3 -2
- package/dist/runtime/providerContinuationReconciliationService.js +1 -1
- package/dist/runtime/runtimeBinding.js +1 -1
- package/dist/runtime/runtimeObservation.js +33 -16
- package/dist/runtime/runtimeSessionCandidate.js +2 -2
- package/dist/runtime/runtimeStopReceipt.js +11 -11
- package/dist/runtime/sessionLaunchRequest.js +2 -2
- package/dist/runtime/sessionOwnerIdentity.js +9 -9
- package/dist/runtime/sessionOwnerRegistry.js +13 -13
- package/dist/runtime/sessionReconciliation.js +4 -4
- package/dist/runtime/sessionTerminationGuard.js +9 -9
- package/dist/runtime/sessionTokenMetrics.js +5 -7
- package/dist/runtime/structuredProviderHost.js +5 -5
- package/dist/runtime/taskRuntimeIsolation.js +24 -24
- package/dist/runtime/tmuxAdapters.js +32 -30
- package/dist/scheduler/activeRoleTurnDelivery.js +37 -15
- package/dist/scheduler/leaderWakeupProcessor.js +78 -55
- package/dist/scheduler/roleTurnLiveness.js +6 -6
- package/dist/scheduler/roleTurnStall.js +8 -9
- package/dist/scheduler/taskExecutionProjection.js +19 -41
- package/dist/scheduler/taskObservabilityProjection.js +75 -122
- package/dist/storage/sqliteSchema.js +1 -21
- package/dist/storage/sqliteStore.js +62 -47
- package/dist/storage/storageSchema.js +1 -8
- package/dist/storage/storageVersions.js +7 -4
- package/dist/storage/taskStore.js +8 -8
- package/dist/storage/upgrade/upgradeOrchestrator.js +112 -83
- package/dist/task/completionReadiness.js +17 -98
- package/dist/task/deliveryGuard.js +9 -11
- package/dist/task/draftPlan.js +142 -0
- package/dist/task/nextAction.js +179 -477
- package/dist/task/publicationVerification.js +1 -0
- package/dist/task/remoteDelivery.js +233 -0
- package/dist/task/task.js +108 -4
- package/dist/task/taskRecordReference.js +0 -1
- package/dist/turn/turn.js +109 -16
- package/dist/verification/verificationGateService.js +0 -26
- package/dist/web/assets/client/components.js +99 -121
- package/dist/web/assets/client/i18n.js +136 -58
- package/dist/web/assets/client/view.js +44 -0
- package/dist/web/assets/styles/cards.js +3 -15
- package/dist/web/assets/styles/widgets.js +4 -0
- package/dist/web/webSnapshot.js +29 -14
- package/dist/workItem/dependencyGate.js +34 -0
- package/dist/workItem/workItem.js +99 -266
- package/dist/workspace/workItemChangeSetManager.js +15 -59
- package/docs/task-local-identity.md +1 -1
- package/i18n/README.zh-CN.md +165 -59
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +272 -782
- package/skills/yui-operator/SKILL.md +190 -365
- package/skills/yui-reviewer/SKILL.md +40 -33
- package/skills/yui-runtime/SKILL.md +27 -6
- package/skills/yui-worker/SKILL.md +19 -6
- package/dist/execution/candidateConvergence.js +0 -623
- package/dist/execution/executionGroup.js +0 -854
- package/dist/execution/resourceBroker.js +0 -426
- package/dist/executor/launchPlan.js +0 -16
- package/dist/review/reviewFinding.js +0 -240
- package/dist/review/reviewFindingLedger.js +0 -550
- package/dist/review/reviewOutcomeClassifier.js +0 -255
- package/dist/scheduler/resourceQueueProjection.js +0 -71
- package/dist/task/repairWave.js +0 -150
|
@@ -5,10 +5,10 @@ import { usageError } from "../errors/cliError.js";
|
|
|
5
5
|
import { defaultTableWidth, renderTable } from "../output/table.js";
|
|
6
6
|
import { createIntegrationAttempt, recordResolutionDecision, supersedeIntegration, updateIntegrationAttempt } from "../integration/integrationAttempt.js";
|
|
7
7
|
import { GitIntegrationService } from "../integration/gitIntegrationService.js";
|
|
8
|
+
import { FileTaskWorkspacePreparer } from "../repository/taskWorkspacePreparer.js";
|
|
8
9
|
import { runTaskIntegrationQueueCommand } from "./taskIntegrationQueueCommands.js";
|
|
9
10
|
import { taskLocalActor } from "./taskActor.js";
|
|
10
11
|
import { resolveTaskRecordReference } from "../task/taskRecordReference.js";
|
|
11
|
-
import { runDeliveryGuardPreflight, withGuardWarnings } from "./deliveryGuardPreflight.js";
|
|
12
12
|
export async function runTaskIntegrationCommand(args, store, home, options = {}) {
|
|
13
13
|
const now = options.now ?? (() => new Date());
|
|
14
14
|
const [command, ...rest] = args;
|
|
@@ -44,7 +44,7 @@ async function cleanupIntegration(args, store, home, environment) {
|
|
|
44
44
|
throw usageError("Task Integration cleanup usage: yui task integration cleanup <task>/<integration>.");
|
|
45
45
|
}
|
|
46
46
|
const integration = requireIntegration(store, args[0], environment);
|
|
47
|
-
taskLocalActor(store, environment, integration.taskId
|
|
47
|
+
taskLocalActor(store, environment, integration.taskId);
|
|
48
48
|
if (integration.status !== "committed"
|
|
49
49
|
&& integration.status !== "superseded"
|
|
50
50
|
&& integration.status !== "failed") {
|
|
@@ -75,51 +75,51 @@ async function cleanupIntegration(args, store, home, environment) {
|
|
|
75
75
|
};
|
|
76
76
|
}
|
|
77
77
|
async function start(args, store, home, now, options) {
|
|
78
|
-
const usage = "Task Integration start usage: yui task integration start <task>
|
|
79
|
-
const parsed = parseRepeatable(args, new Set(["--
|
|
78
|
+
const usage = "Task Integration start usage: yui task integration start <task> --work-item <id> --strategy <ff|cherry-pick|merge|manual> [--project <project>] [--target <ref>] [--check <command> ...].";
|
|
79
|
+
const parsed = parseRepeatable(args, new Set(["--check"]), new Set(["--work-item", "--strategy", "--project", "--target"]), usage);
|
|
80
80
|
if (parsed.positionals.length !== 1)
|
|
81
81
|
throw usageError(usage);
|
|
82
|
-
|
|
82
|
+
let task = store.getTask(parsed.positionals[0]);
|
|
83
83
|
if (task === null)
|
|
84
84
|
throw usageError(`Task not found: ${parsed.positionals[0]}.`);
|
|
85
85
|
if (task.status !== "active") {
|
|
86
86
|
throw usageError(`Task is not active: ${task.id}/${task.status}.`);
|
|
87
87
|
}
|
|
88
|
-
taskLocalActor(store, options.environment, task.id
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
// review attests the frozen base itself (evidenceCommit === reviewBaseCommit),
|
|
101
|
-
// which is the candidate's own head and a legitimate source.
|
|
102
|
-
const diagnosticEvidence = new Set(store.listReviewRounds(task.id)
|
|
103
|
-
.flatMap(({ evidenceCommit, reviewBaseCommit }) => evidenceCommit !== undefined && evidenceCommit !== reviewBaseCommit
|
|
104
|
-
? [evidenceCommit]
|
|
105
|
-
: []));
|
|
106
|
-
const reviewSource = changeSets.find(({ headCommit }) => diagnosticEvidence.has(headCommit));
|
|
107
|
-
if (reviewSource !== undefined) {
|
|
108
|
-
throw usageError(`ReviewRound evidence commit cannot become an Integration source: ${reviewSource.id}.`);
|
|
88
|
+
taskLocalActor(store, options.environment, task.id);
|
|
89
|
+
await new FileTaskWorkspacePreparer(home, store, undefined, now)
|
|
90
|
+
.prepareTaskWorkspace(task.id);
|
|
91
|
+
task = store.getTask(task.id);
|
|
92
|
+
if (task === null || task.status !== "active") {
|
|
93
|
+
throw usageError(`Task is no longer active: ${parsed.positionals[0]}.`);
|
|
94
|
+
}
|
|
95
|
+
const workItemId = parsed.one.get("--work-item");
|
|
96
|
+
const strategy = parsed.one.get("--strategy");
|
|
97
|
+
if (workItemId === undefined || strategy === undefined
|
|
98
|
+
|| !["ff", "cherry-pick", "merge", "manual"].includes(strategy)) {
|
|
99
|
+
throw usageError(usage);
|
|
109
100
|
}
|
|
110
|
-
const
|
|
111
|
-
if (
|
|
112
|
-
throw usageError(
|
|
101
|
+
const workItem = store.getWorkItem(task.id, workItemId);
|
|
102
|
+
if (workItem === null)
|
|
103
|
+
throw usageError(`WorkItem not found: ${workItemId}.`);
|
|
104
|
+
const candidate = workItem.candidates.at(-1);
|
|
105
|
+
if (candidate?.gitSnapshot === undefined || candidate.workspace === undefined) {
|
|
106
|
+
throw usageError(`WorkItem has no committed result snapshot: ${workItem.id}.`);
|
|
113
107
|
}
|
|
108
|
+
const projectIds = candidate.workspace.entries
|
|
109
|
+
.filter(({ access }) => access === "write")
|
|
110
|
+
.map(({ projectId }) => projectId);
|
|
114
111
|
const requestedProject = parsed.one.get("--project");
|
|
112
|
+
if (requestedProject === undefined && projectIds.length !== 1) {
|
|
113
|
+
throw usageError("Select --project when a WorkItem result contains multiple Projects.");
|
|
114
|
+
}
|
|
115
115
|
const project = requestedProject === undefined
|
|
116
116
|
? store.getProject(projectIds[0])
|
|
117
117
|
: resolveProject(store.listProjects(), requestedProject);
|
|
118
118
|
if (project === null)
|
|
119
119
|
throw usageError(`Project not found: ${requestedProject ?? projectIds[0]}.`);
|
|
120
120
|
assertProjectActive(project, "start an Integration");
|
|
121
|
-
if (project.id
|
|
122
|
-
throw usageError(`
|
|
121
|
+
if (!projectIds.includes(project.id)) {
|
|
122
|
+
throw usageError(`WorkItem result does not contain Project: ${project.id}.`);
|
|
123
123
|
}
|
|
124
124
|
if (!task.projectBindings.some(({ projectId }) => projectId === project.id)) {
|
|
125
125
|
throw usageError(`Project does not belong to Task: ${project.id}.`);
|
|
@@ -132,35 +132,33 @@ async function start(args, store, home, now, options) {
|
|
|
132
132
|
if (targetRef === undefined) {
|
|
133
133
|
throw usageError(`Task main worktree is not ready; reconcile the Task first: ${task.id}.`);
|
|
134
134
|
}
|
|
135
|
-
const expectedHead = (await new NodeGitWorkspace().inspect(
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
135
|
+
const expectedHead = (await new NodeGitWorkspace().inspect(mainEntry.path, targetRef)).baseCommit;
|
|
136
|
+
const snapshotEntry = candidate.workspace.entries.find(({ projectId }) => projectId === project.id);
|
|
137
|
+
const resultCommit = candidate.gitSnapshot.projects.find(({ projectId }) => projectId === project.id)?.commit;
|
|
138
|
+
if (snapshotEntry === undefined || resultCommit === undefined) {
|
|
139
|
+
throw usageError(`WorkItem result Project snapshot is incomplete: ${workItem.id}/${project.id}.`);
|
|
140
|
+
}
|
|
140
141
|
const integration = store.transaction((tx) => {
|
|
141
|
-
taskLocalActor(tx, options.environment, task.id
|
|
142
|
-
const guard = runDeliveryGuardPreflight(tx, task.id, {
|
|
143
|
-
kind: "integration-start",
|
|
144
|
-
projectId: project.id,
|
|
145
|
-
changeSetIds
|
|
146
|
-
}, { environment: options.environment, budget: true });
|
|
142
|
+
taskLocalActor(tx, options.environment, task.id);
|
|
147
143
|
const created = createIntegrationAttempt({
|
|
148
144
|
id: tx.nextIntegrationAttemptId(task.id),
|
|
149
145
|
taskId: task.id,
|
|
150
146
|
projectId: project.id,
|
|
151
147
|
targetRef,
|
|
152
|
-
expectedHead,
|
|
153
|
-
|
|
148
|
+
beforeCommit: expectedHead,
|
|
149
|
+
source: {
|
|
150
|
+
kind: "work-item",
|
|
151
|
+
workItemId: workItem.id,
|
|
152
|
+
startCommit: snapshotEntry.baseCommit,
|
|
153
|
+
resultCommit,
|
|
154
|
+
strategy
|
|
155
|
+
},
|
|
154
156
|
checkCommands: parsed.many.get("--check") ?? []
|
|
155
157
|
}, now());
|
|
156
158
|
tx.saveIntegrationAttempt(task.id, created);
|
|
157
|
-
return
|
|
159
|
+
return created;
|
|
158
160
|
});
|
|
159
|
-
|
|
160
|
-
return {
|
|
161
|
-
...result,
|
|
162
|
-
output: withGuardWarnings(integration.guard, result.output)
|
|
163
|
-
};
|
|
161
|
+
return runIntegration(store, home, integration, now, options);
|
|
164
162
|
}
|
|
165
163
|
async function continueIntegration(args, store, home, now, options) {
|
|
166
164
|
const usage = "Task Integration continue usage: yui task integration continue <task>/<integration>.";
|
|
@@ -169,7 +167,7 @@ async function continueIntegration(args, store, home, now, options) {
|
|
|
169
167
|
throw usageError(usage);
|
|
170
168
|
const integration = requireIntegration(store, parsed.positionals[0], options.environment);
|
|
171
169
|
requireActiveIntegrationTask(store, integration);
|
|
172
|
-
taskLocalActor(store, options.environment, integration.taskId
|
|
170
|
+
taskLocalActor(store, options.environment, integration.taskId);
|
|
173
171
|
if (integration.status !== "validating"
|
|
174
172
|
&& integration.status !== "running"
|
|
175
173
|
&& (integration.status !== "blocked"
|
|
@@ -181,7 +179,7 @@ async function continueIntegration(args, store, home, now, options) {
|
|
|
181
179
|
async function runIntegration(store, home, integration, now, options) {
|
|
182
180
|
const result = await new GitIntegrationService(home, store, undefined, now, options.environment, undefined, options.jobPort).integrate(integration.taskId, integration.id);
|
|
183
181
|
const output = result.status === "committed"
|
|
184
|
-
? `Integrated ${result.attempt
|
|
182
|
+
? `Integrated ${integrationSourceLabel(result.attempt)} into ${result.attempt.targetRef} with CAS (${result.attempt.id})\n`
|
|
185
183
|
: result.status === "blocked"
|
|
186
184
|
? `Integration ${result.attempt.id} requires a Task Agent resolution decision in ${result.workspace.path}\n`
|
|
187
185
|
: result.status === "checks-running"
|
|
@@ -201,7 +199,7 @@ function resolveDecision(args, store, now, environment, home) {
|
|
|
201
199
|
const resolved = store.transaction((tx) => {
|
|
202
200
|
const integration = requireIntegration(tx, parsed.positionals[0], environment);
|
|
203
201
|
const task = requireActiveIntegrationTask(tx, integration);
|
|
204
|
-
const actor = taskLocalActor(tx, environment, task.id
|
|
202
|
+
const actor = taskLocalActor(tx, environment, task.id);
|
|
205
203
|
const updated = recordResolutionDecision(integration, {
|
|
206
204
|
action: selectedOption,
|
|
207
205
|
rationale
|
|
@@ -223,7 +221,7 @@ async function abortIntegration(args, store, now, options, home) {
|
|
|
223
221
|
throw usageError(usage);
|
|
224
222
|
const integration = requireIntegration(store, parsed.positionals[0], options.environment);
|
|
225
223
|
requireActiveIntegrationTask(store, integration);
|
|
226
|
-
taskLocalActor(store, options.environment, integration.taskId
|
|
224
|
+
taskLocalActor(store, options.environment, integration.taskId);
|
|
227
225
|
if (integration.status !== "running" && integration.status !== "blocked") {
|
|
228
226
|
throw usageError(`Integration cannot be aborted from ${integration.status}: ${integration.id}.`);
|
|
229
227
|
}
|
|
@@ -245,7 +243,7 @@ async function abortIntegration(args, store, now, options, home) {
|
|
|
245
243
|
if (current.status !== "running" && current.status !== "blocked") {
|
|
246
244
|
throw usageError(`Integration cannot be aborted from ${current.status}: ${current.id}.`);
|
|
247
245
|
}
|
|
248
|
-
taskLocalActor(tx, options.environment, current.taskId
|
|
246
|
+
taskLocalActor(tx, options.environment, current.taskId);
|
|
249
247
|
const aborted = updateIntegrationAttempt(current, {
|
|
250
248
|
status: "failed",
|
|
251
249
|
checks: [
|
|
@@ -275,7 +273,7 @@ function supersedeIntegrationCommand(args, store, now, environment, home) {
|
|
|
275
273
|
throw usageError(usage);
|
|
276
274
|
// Superseding a committed Integration rewrites delivery-baseline evidence
|
|
277
275
|
// and audit history, so it remains an explicit Task-control decision.
|
|
278
|
-
taskLocalActor(store, environment, integration.taskId
|
|
276
|
+
taskLocalActor(store, environment, integration.taskId);
|
|
279
277
|
// A queue-backed committed Attempt cannot be superseded: the queue entry
|
|
280
278
|
// would remain in its current status while its Attempt becomes "superseded",
|
|
281
279
|
// leaving contradictory terminal records that never converge. This covers
|
|
@@ -295,7 +293,7 @@ function supersedeIntegrationCommand(args, store, now, environment, home) {
|
|
|
295
293
|
if (current.status !== "committed") {
|
|
296
294
|
throw usageError(`Integration cannot be superseded from ${current.status}: ${current.id}.`);
|
|
297
295
|
}
|
|
298
|
-
taskLocalActor(tx, environment, current.taskId
|
|
296
|
+
taskLocalActor(tx, environment, current.taskId);
|
|
299
297
|
const superseded = supersedeIntegration(current, reason, now);
|
|
300
298
|
tx.saveIntegrationAttempt(superseded.taskId, superseded);
|
|
301
299
|
return {
|
|
@@ -326,13 +324,13 @@ function list(args, store) {
|
|
|
326
324
|
{ header: "Integration", minWidth: 11, maxWidth: 24 },
|
|
327
325
|
{ header: "Project", minWidth: 8, maxWidth: 20 },
|
|
328
326
|
{ header: "Target", minWidth: 8, maxWidth: 30 },
|
|
329
|
-
{ header: "
|
|
327
|
+
{ header: "Source", minWidth: 10, maxWidth: 28 },
|
|
330
328
|
{ header: "Status", minWidth: 7, maxWidth: 20 }
|
|
331
329
|
], integrations.map((entry) => [
|
|
332
330
|
entry.id,
|
|
333
331
|
entry.projectId,
|
|
334
332
|
entry.targetRef,
|
|
335
|
-
|
|
333
|
+
integrationSourceLabel(entry),
|
|
336
334
|
entry.status
|
|
337
335
|
]), defaultTableWidth())}\n`;
|
|
338
336
|
return { output, data: { integrations } };
|
|
@@ -347,11 +345,13 @@ function show(args, store, environment) {
|
|
|
347
345
|
`Task: ${integration.taskId}`,
|
|
348
346
|
`Project: ${integration.projectId}`,
|
|
349
347
|
`Target: ${integration.targetRef}`,
|
|
350
|
-
`
|
|
348
|
+
`Before commit: ${integration.beforeCommit}`,
|
|
351
349
|
`Candidate: ${integration.candidateCommit ?? "-"}`,
|
|
350
|
+
`After commit: ${integration.afterCommit ?? "-"}`,
|
|
352
351
|
`Job: ${integration.jobId ?? "-"}`,
|
|
353
|
-
`
|
|
352
|
+
`Source: ${integrationSourceLabel(integration)}`,
|
|
354
353
|
`Status: ${integration.status}`,
|
|
354
|
+
`Summary: ${integration.summary ?? "-"}`,
|
|
355
355
|
`Conflict: ${integration.conflict?.summary ?? "-"}`,
|
|
356
356
|
`Resolution: ${integration.resolution?.action ?? "-"}`,
|
|
357
357
|
...(integration.checks === undefined
|
|
@@ -368,6 +368,14 @@ function show(args, store, environment) {
|
|
|
368
368
|
data: { integration }
|
|
369
369
|
};
|
|
370
370
|
}
|
|
371
|
+
function integrationSourceLabel(integration) {
|
|
372
|
+
if (integration.source.kind === "work-item") {
|
|
373
|
+
return `work-item:${integration.source.workItemId}@${integration.source.resultCommit.slice(0, 12)}`;
|
|
374
|
+
}
|
|
375
|
+
return integration.source.kind === "upstream"
|
|
376
|
+
? `upstream:${integration.source.branch}@${integration.source.remoteCommit.slice(0, 12)}`
|
|
377
|
+
: `historical:${integration.source.changeSetIds.join(",")}`;
|
|
378
|
+
}
|
|
371
379
|
function requireIntegration(store, value, environment) {
|
|
372
380
|
let reference;
|
|
373
381
|
try {
|
|
@@ -222,5 +222,5 @@ function requireQueueEntry(store, value, environment) {
|
|
|
222
222
|
return entry;
|
|
223
223
|
}
|
|
224
224
|
function requireTaskControlActor(store, environment, taskId, home) {
|
|
225
|
-
return taskLocalActor(store, environment, taskId
|
|
225
|
+
return taskLocalActor(store, environment, taskId);
|
|
226
226
|
}
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
import { taskNotFound, usageError } from "../errors/cliError.js";
|
|
2
2
|
import { projectNextAction } from "../task/nextAction.js";
|
|
3
3
|
import { projectCompletionReadiness } from "../task/completionReadiness.js";
|
|
4
|
-
import { extractReviewFindings, planRepairWave } from "../task/repairWave.js";
|
|
5
4
|
import { projectTaskOrchestration } from "../observability/orchestrationMetrics.js";
|
|
6
5
|
import { operationalTaskRecords } from "../task/taskRecordRetirement.js";
|
|
7
6
|
import { buildTaskExecutionProjection } from "../scheduler/taskExecutionProjection.js";
|
|
8
7
|
import { projectReviewDecision } from "../review/reviewDecision.js";
|
|
8
|
+
import { projectTaskRemoteDeliveryFromStore, renderTaskRemoteDelivery } from "./taskRemoteDeliveryCommand.js";
|
|
9
9
|
/**
|
|
10
10
|
* Issue 07 (Leader convergence): read-only `yui task next-action <task>`.
|
|
11
11
|
* Folds the existing durable records into exactly one protocol-level next
|
|
12
12
|
* action with exact refs, preconditions, recommended command, alternatives, and
|
|
13
13
|
* the judgment that remains owned by the Leader.
|
|
14
|
-
* The command never mutates state
|
|
15
|
-
* it also prints the minimal repair wave for the failing Review.
|
|
14
|
+
* The command never mutates state and never interprets Agent result text.
|
|
16
15
|
*
|
|
17
16
|
* Issue 06: when the recommended action is `complete-task`, the output also
|
|
18
17
|
* carries the full `completionReadiness` blocker list so the Leader sees every
|
|
@@ -44,7 +43,6 @@ export function runTaskNextActionCommand(args, store, currentTaskReviewCandidate
|
|
|
44
43
|
executionGroups: execution.executionGroups
|
|
45
44
|
};
|
|
46
45
|
const action = projectNextAction(actionFacts);
|
|
47
|
-
const repairWave = repairWaveFor(action, actionFacts);
|
|
48
46
|
// Issue 12: surface pending Knowledge promotion proposals for the Task's
|
|
49
47
|
// bound Projects as a non-blocking advisory. The proposals are workflow
|
|
50
48
|
// state, not completion blockers: an Operator reviews them separately.
|
|
@@ -70,6 +68,7 @@ export function runTaskNextActionCommand(args, store, currentTaskReviewCandidate
|
|
|
70
68
|
}
|
|
71
69
|
const events = reader.listEvents(taskId);
|
|
72
70
|
const task = reader.getTask(taskId);
|
|
71
|
+
const remoteDelivery = projectTaskRemoteDeliveryFromStore(reader, task, currentTaskReviewCandidate);
|
|
73
72
|
const operationalTurns = operationalTaskRecords(reader.listTurns(taskId), events, "turn");
|
|
74
73
|
const reviewRounds = reader.listReviewRounds(taskId);
|
|
75
74
|
const reviewDecision = projectReviewDecision({
|
|
@@ -88,23 +87,21 @@ export function runTaskNextActionCommand(args, store, currentTaskReviewCandidate
|
|
|
88
87
|
workItems: reader.listWorkItems(taskId),
|
|
89
88
|
changeSets: reader.listChangeSets(taskId),
|
|
90
89
|
reviewRounds,
|
|
91
|
-
reviewFindings: reader.listReviewFindings(taskId),
|
|
92
90
|
integrations: reader.listIntegrationAttempts(taskId),
|
|
93
91
|
durableJobs: reader.listDurableJobs(taskId),
|
|
94
92
|
publications: reader.listPublicationReferences(taskId),
|
|
95
|
-
decisions: reader.listDecisions(taskId),
|
|
96
93
|
events,
|
|
97
94
|
managedWorkspaces: reader.listManagedWorkspaces(taskId)
|
|
98
95
|
});
|
|
99
96
|
return {
|
|
100
97
|
taskType: facts.task.type ?? null,
|
|
101
98
|
action,
|
|
102
|
-
repairWave,
|
|
103
99
|
completionReadiness,
|
|
104
100
|
knowledgeProposals,
|
|
105
101
|
reviewDecision,
|
|
106
102
|
execution: nextActionExecutionView(execution),
|
|
107
|
-
orchestration
|
|
103
|
+
orchestration,
|
|
104
|
+
remoteDelivery
|
|
108
105
|
};
|
|
109
106
|
});
|
|
110
107
|
if (asJson) {
|
|
@@ -116,28 +113,15 @@ export function runTaskNextActionCommand(args, store, currentTaskReviewCandidate
|
|
|
116
113
|
}
|
|
117
114
|
return {
|
|
118
115
|
kind: "output",
|
|
119
|
-
output: renderNextAction(data.action, data.taskType, data.
|
|
116
|
+
output: renderNextAction(data.action, data.taskType, data.completionReadiness, data.knowledgeProposals, data.reviewDecision, data.execution, data.orchestration.advisories, data.remoteDelivery),
|
|
120
117
|
data
|
|
121
118
|
};
|
|
122
119
|
}
|
|
123
|
-
function
|
|
124
|
-
if (action.kind !== "route-review-findings")
|
|
125
|
-
return null;
|
|
126
|
-
const reviewRef = action.refs.find((ref) => ref.kind === "review-round");
|
|
127
|
-
if (reviewRef === undefined)
|
|
128
|
-
return null;
|
|
129
|
-
const round = facts.reviewRounds.find((candidate) => candidate.id === reviewRef.id);
|
|
130
|
-
if (round === undefined)
|
|
131
|
-
return null;
|
|
132
|
-
const findings = extractReviewFindings(round);
|
|
133
|
-
if (findings.length === 0)
|
|
134
|
-
return null;
|
|
135
|
-
return planRepairWave(round.id, findings);
|
|
136
|
-
}
|
|
137
|
-
function renderNextAction(action, taskType, repairWave, completionReadiness, knowledgeProposals, reviewDecision, execution, orchestrationAdvisories) {
|
|
120
|
+
function renderNextAction(action, taskType, completionReadiness, knowledgeProposals, reviewDecision, execution, orchestrationAdvisories, remoteDelivery) {
|
|
138
121
|
const lines = [
|
|
139
122
|
`Task: ${action.taskId}`,
|
|
140
123
|
`Type: ${taskType ?? "unspecified"}`,
|
|
124
|
+
renderTaskRemoteDelivery(remoteDelivery).trimEnd(),
|
|
141
125
|
`Next action: ${action.kind}`,
|
|
142
126
|
`Reason: ${action.reason}`,
|
|
143
127
|
`Execution view: ${execution.status}; owner/action=${execution.owner}/${execution.action}; reason=${execution.reason}; ${execution.summary}`,
|
|
@@ -202,11 +186,6 @@ function renderNextAction(action, taskType, repairWave, completionReadiness, kno
|
|
|
202
186
|
+ ` — fix before archive: ${advisory.fix}`));
|
|
203
187
|
}
|
|
204
188
|
}
|
|
205
|
-
if (repairWave !== null) {
|
|
206
|
-
lines.push(`Repair wave (${repairWave.openFindingCount} open finding(s), ${repairWave.groups.length} group(s)):`, ...repairWave.groups.map((group) => ` ${group.id}: findings ${group.findingIds.join(", ")}`
|
|
207
|
-
+ ` — paths ${group.paths.length === 0 ? "none" : group.paths.join(", ")}`
|
|
208
|
-
+ ` — ${group.reason}`));
|
|
209
|
-
}
|
|
210
189
|
if (knowledgeProposals.length > 0) {
|
|
211
190
|
lines.push(`Knowledge proposals (non-blocking): ${knowledgeProposals.length} pending`, ...knowledgeProposals.map((proposal) => ` ${proposal.projectId}/${proposal.proposalId}: ${proposal.title}`
|
|
212
191
|
+ ` — review: yui project knowledge proposals list ${proposal.projectId}`));
|
|
@@ -6,6 +6,7 @@ import { defaultTableWidth, renderTable } from "../output/table.js";
|
|
|
6
6
|
import { projectTaskExecutionFromFacts } from "../scheduler/taskExecutionProjection.js";
|
|
7
7
|
import { resolveRuntimeHealth } from "../config/yuiConfig.js";
|
|
8
8
|
import { projectNextAction } from "../task/nextAction.js";
|
|
9
|
+
import { projectTaskRemoteDeliveryFromStore } from "./taskRemoteDeliveryCommand.js";
|
|
9
10
|
export function parseTaskListOptions(args) {
|
|
10
11
|
const allowed = new Set(["--all", "--verbose"]);
|
|
11
12
|
if (args.some((argument) => !allowed.has(argument))
|
|
@@ -37,6 +38,7 @@ export function renderTaskOverview(result, options, timeZone, width = defaultTab
|
|
|
37
38
|
{ header: "Work", minWidth: 8, maxWidth: 38 },
|
|
38
39
|
{ header: "Blockers", minWidth: 9, maxWidth: 42 },
|
|
39
40
|
{ header: "Execution", minWidth: 14, maxWidth: 34 },
|
|
41
|
+
{ header: "Delivery", minWidth: 12, maxWidth: 28 },
|
|
40
42
|
{ header: "Next action / owner", minWidth: 16, maxWidth: 42 }
|
|
41
43
|
], result.tasks.map((task) => [
|
|
42
44
|
task.id,
|
|
@@ -49,6 +51,7 @@ export function renderTaskOverview(result, options, timeZone, width = defaultTab
|
|
|
49
51
|
workCell(task.work.counts),
|
|
50
52
|
blockersCell(task.blockers),
|
|
51
53
|
`${task.execution.status} / ${task.execution.owner}`,
|
|
54
|
+
deliveryCell(task.remoteDelivery),
|
|
52
55
|
nextCell(task.next)
|
|
53
56
|
]), width);
|
|
54
57
|
if (!options.verbose)
|
|
@@ -137,6 +140,10 @@ function buildTaskOverviewEntry(task, store, now, runtimeHealthPolicy) {
|
|
|
137
140
|
currentTaskReviewCandidate: null,
|
|
138
141
|
executionGroups: execution.executionGroups
|
|
139
142
|
}));
|
|
143
|
+
const persistedCandidate = task.status === "active" || task.status === "retired"
|
|
144
|
+
? taskRemoteDeliveryCandidate(task)
|
|
145
|
+
: null;
|
|
146
|
+
const remoteDelivery = projectTaskRemoteDeliveryFromStore(store, task, persistedCandidate);
|
|
140
147
|
return {
|
|
141
148
|
...task,
|
|
142
149
|
brief,
|
|
@@ -155,7 +162,8 @@ function buildTaskOverviewEntry(task, store, now, runtimeHealthPolicy) {
|
|
|
155
162
|
nextAction: next?.action ?? null,
|
|
156
163
|
nextOwner: next?.owner ?? null,
|
|
157
164
|
runtime,
|
|
158
|
-
execution
|
|
165
|
+
execution,
|
|
166
|
+
remoteDelivery
|
|
159
167
|
};
|
|
160
168
|
}
|
|
161
169
|
function collectAttention(task, turns, events, failure) {
|
|
@@ -220,8 +228,7 @@ function collectBlockers(workItems, openInputRequests, attention) {
|
|
|
220
228
|
}
|
|
221
229
|
if (item.status !== "pending")
|
|
222
230
|
continue;
|
|
223
|
-
const dependencies = item.dependsOn.filter((dependency) => (workById.get(dependency)?.status !== "completed"
|
|
224
|
-
&& workById.get(dependency)?.status !== "retired"));
|
|
231
|
+
const dependencies = item.dependsOn.filter((dependency) => (workById.get(dependency)?.status !== "completed"));
|
|
225
232
|
if (dependencies.length === 0)
|
|
226
233
|
continue;
|
|
227
234
|
blockers.push({
|
|
@@ -326,6 +333,20 @@ function blockersCell(blockers) {
|
|
|
326
333
|
function nextCell(next) {
|
|
327
334
|
return next === null ? "—" : `${next.action} / ${next.owner}`;
|
|
328
335
|
}
|
|
336
|
+
function deliveryCell(delivery) {
|
|
337
|
+
if (delivery.status === "none")
|
|
338
|
+
return "none";
|
|
339
|
+
return `${delivery.status} · ${delivery.mergedProjectCount}/${delivery.codeProjectCount} merged`
|
|
340
|
+
+ (delivery.allMerged
|
|
341
|
+
? ` · ${delivery.verifiedProjectCount}/${delivery.codeProjectCount} verified`
|
|
342
|
+
: "");
|
|
343
|
+
}
|
|
344
|
+
function taskRemoteDeliveryCandidate(task) {
|
|
345
|
+
const projects = task.projectBindings.flatMap(({ projectId, currentCommit }) => (currentCommit === undefined ? [] : [{ projectId, commit: currentCommit }]));
|
|
346
|
+
return projects.length === task.projectBindings.length
|
|
347
|
+
? { projects }
|
|
348
|
+
: null;
|
|
349
|
+
}
|
|
329
350
|
function compactText(value) {
|
|
330
351
|
const oneLine = value.replace(/\s+/g, " ").trim();
|
|
331
352
|
return oneLine.length <= 240 ? oneLine : `${oneLine.slice(0, 237)}...`;
|
|
@@ -343,6 +364,7 @@ function renderVerboseDetails(tasks, timeZone) {
|
|
|
343
364
|
? "missing"
|
|
344
365
|
: formatTimestamp(task.summaryUpdatedAt, timeZone)}`,
|
|
345
366
|
` Execution: ${task.execution.status} (${task.execution.owner}); ${task.execution.summary}`,
|
|
367
|
+
` Remote delivery: ${deliveryCell(task.remoteDelivery)}; source=${task.remoteDelivery.source}${task.remoteDelivery.provisional ? " (provisional)" : ""}`,
|
|
346
368
|
` Monitoring: ${task.execution.monitoring}; attention: ${task.execution.attention.length}`,
|
|
347
369
|
` 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"}`,
|
|
348
370
|
` Cost: tokens=${task.execution.observability.cost.tokens}${task.execution.observability.cost.tokensObservable ? "" : " (partial)"}; tools=${task.execution.observability.cost.toolCalls}${task.execution.observability.cost.toolCallsObservable ? "" : " (partial)"}; wall=${task.execution.observability.cost.wallClockSeconds}s; retries=${task.execution.observability.cost.retryCount}`,
|