@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
|
@@ -3,7 +3,7 @@ import { GitIntegrationService } from "../integration/gitIntegrationService.js";
|
|
|
3
3
|
import { createIntegrationAttempt } from "../integration/integrationAttempt.js";
|
|
4
4
|
import { NodeGitWorkspace } from "../repository/gitWorkspace.js";
|
|
5
5
|
import { publicationExternalKey } from "../task/publicationReference.js";
|
|
6
|
-
import {
|
|
6
|
+
import { isCompletedTaskReviewEvidence } from "../review/reviewAcceptance.js";
|
|
7
7
|
import { workspaceProjectEntry } from "../worktree/managedWorkspace.js";
|
|
8
8
|
/**
|
|
9
9
|
* Verify the one supported ancestry waiver before `task complete` mutates any
|
|
@@ -113,7 +113,7 @@ export function assertTaskCompletionPublishedTreeProof(store, task, publicationI
|
|
|
113
113
|
if (proof.reviewRoundId !== undefined) {
|
|
114
114
|
const review = store.getReviewRound(task.id, proof.reviewRoundId);
|
|
115
115
|
if (review === null
|
|
116
|
-
|| !
|
|
116
|
+
|| !isCompletedTaskReviewEvidence(store, review)
|
|
117
117
|
|| review.taskCandidate === undefined
|
|
118
118
|
|| !sameTaskCandidate(review.taskCandidate, actualCandidate)) {
|
|
119
119
|
throw usageError(`Task-final Review evidence changed before published-tree completion: ${task.id}.`);
|
|
@@ -142,7 +142,7 @@ function requireCurrentVerifiedPublication(store, taskId, publicationId) {
|
|
|
142
142
|
}
|
|
143
143
|
function acceptedTaskFinalReviews(store, taskId) {
|
|
144
144
|
return store.listReviewRounds(taskId)
|
|
145
|
-
.filter((round) =>
|
|
145
|
+
.filter((round) => isCompletedTaskReviewEvidence(store, round))
|
|
146
146
|
.sort((left, right) => (right.id.localeCompare(left.id, undefined, { numeric: true })));
|
|
147
147
|
}
|
|
148
148
|
function sameTaskCandidate(left, right) {
|
|
@@ -154,35 +154,22 @@ function sameTaskCandidate(left, right) {
|
|
|
154
154
|
* Reconcile configured remote baselines before a Task completion attempt.
|
|
155
155
|
*
|
|
156
156
|
* Remote resolution and fetches happen from the Task's managed worktree. A
|
|
157
|
-
* moved remote is represented by a
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
* are never refreshed or otherwise mutated here.
|
|
157
|
+
* moved remote is represented by a normal upstream Integration Attempt. The
|
|
158
|
+
* normal check and CAS path advances only the Task clone; stable Project
|
|
159
|
+
* checkouts are never refreshed or otherwise mutated here.
|
|
161
160
|
*/
|
|
162
161
|
export async function reconcileTaskRemoteBaselines(taskId, store, home, options = {}) {
|
|
163
162
|
const task = store.getTask(taskId);
|
|
164
163
|
if (task === null)
|
|
165
164
|
throw usageError(`Task not found: ${taskId}.`);
|
|
166
|
-
|
|
167
|
-
// Integration evidence. Metadata-only Tasks retain their existing local
|
|
168
|
-
// completion semantics and have no remote baseline to reconcile here.
|
|
169
|
-
if (task.projectBindings.length === 0
|
|
170
|
-
|| !store.listIntegrationAttempts(task.id).some(({ status }) => status === "committed")) {
|
|
165
|
+
if (task.projectBindings.length === 0) {
|
|
171
166
|
return [];
|
|
172
167
|
}
|
|
173
168
|
const workspace = requireTaskWorkspace(store, task);
|
|
174
169
|
const git = options.git ?? new NodeGitWorkspace();
|
|
175
|
-
if (git.fetchRemoteHeadIntoWorktree === undefined
|
|
176
|
-
|| git.mergeRemoteIntoWorktree === undefined) {
|
|
170
|
+
if (git.fetchRemoteHeadIntoWorktree === undefined) {
|
|
177
171
|
throw usageError(`Task ${task.id} cannot verify remote baselines: managed Git workspace support is unavailable.`);
|
|
178
172
|
}
|
|
179
|
-
// A completed Task-final Review that exactly covers the current frozen heads
|
|
180
|
-
// is the final review evidence. Do not reconcile the remote after a clean
|
|
181
|
-
// review, as merging a moved remote would change the reviewed head and
|
|
182
|
-
// invalidate the review.
|
|
183
|
-
if (await hasCompletedTaskFinalReviewForCurrentCandidate(store, task, workspace, git)) {
|
|
184
|
-
return [];
|
|
185
|
-
}
|
|
186
173
|
const plans = [];
|
|
187
174
|
for (const binding of task.projectBindings) {
|
|
188
175
|
const project = store.getProject(binding.projectId);
|
|
@@ -196,69 +183,47 @@ export async function reconcileTaskRemoteBaselines(taskId, store, home, options
|
|
|
196
183
|
throw usageError(`Task ${task.id} has no writable managed main workspace for remote Project ${project.id}.`);
|
|
197
184
|
}
|
|
198
185
|
const currentCommit = (await git.inspect(entry.path, "HEAD")).baseCommit;
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
// Task baseline: the delivery has been reviewed and approved, so the
|
|
202
|
-
// completion gate must not merge remote changes that would invalidate
|
|
203
|
-
// the review evidence.
|
|
204
|
-
if (hasFrozenTaskBaseline(store, task.id, project.id, currentCommit)) {
|
|
205
|
-
continue;
|
|
206
|
-
}
|
|
207
|
-
// Let the existing exact-head Task-final gate report local post-
|
|
208
|
-
// Integration drift before attempting any network operation. This keeps
|
|
209
|
-
// completion read-only for an already-invalid candidate and preserves its
|
|
210
|
-
// precise recovery guidance.
|
|
211
|
-
if (previousIntegration !== undefined
|
|
212
|
-
&& previousIntegration.candidateCommit !== currentCommit) {
|
|
213
|
-
continue;
|
|
186
|
+
if (binding.currentCommit !== currentCommit || binding.baseCommit === undefined) {
|
|
187
|
+
throw usageError(`Project ${project.id} Task commit record does not match its authoritative main clone.`);
|
|
214
188
|
}
|
|
215
189
|
const remote = await fetchRemote(git, entry, project);
|
|
216
190
|
if (remote.commit === currentCommit)
|
|
217
191
|
continue;
|
|
218
192
|
if (await git.isAncestor(entry.path, remote.commit, currentCommit))
|
|
219
193
|
continue;
|
|
220
|
-
if (previousIntegration === undefined) {
|
|
221
|
-
throw usageError(`Project ${project.id} remote target moved to ${remote.commit}, but no committed `
|
|
222
|
-
+ "Integration can establish a safe Task baseline.");
|
|
223
|
-
}
|
|
224
|
-
if (previousIntegration.candidateCommit !== currentCommit) {
|
|
225
|
-
throw usageError(`Project ${project.id} Task head ${currentCommit} does not match its latest committed `
|
|
226
|
-
+ `Integration ${previousIntegration.id}; settle that drift before remote reconciliation.`);
|
|
227
|
-
}
|
|
228
194
|
if (!await git.isClean(entry.path)) {
|
|
229
195
|
throw usageError(`Project ${project.id} managed Task workspace is dirty; commit or clean it before remote reconciliation.`);
|
|
230
196
|
}
|
|
231
|
-
plans.push({
|
|
197
|
+
plans.push({
|
|
198
|
+
project,
|
|
199
|
+
entry,
|
|
200
|
+
remote,
|
|
201
|
+
currentCommit,
|
|
202
|
+
taskBaseCommit: binding.baseCommit
|
|
203
|
+
});
|
|
232
204
|
}
|
|
233
205
|
const reconciled = [];
|
|
234
206
|
for (const plan of plans) {
|
|
235
207
|
const attempt = store.transaction((tx) => {
|
|
236
|
-
// Re-check the frozen baseline inside the transaction: a Task-final
|
|
237
|
-
// Review may have completed during the async remote fetch, freezing
|
|
238
|
-
// the head after the initial check. Creating a new Integration here
|
|
239
|
-
// would move the reviewed head and invalidate the review evidence.
|
|
240
|
-
if (hasFrozenTaskBaseline(tx, task.id, plan.project.id, plan.currentCommit)) {
|
|
241
|
-
return null;
|
|
242
|
-
}
|
|
243
208
|
const created = createIntegrationAttempt({
|
|
244
209
|
id: tx.nextIntegrationAttemptId(task.id),
|
|
245
210
|
taskId: task.id,
|
|
246
211
|
projectId: plan.project.id,
|
|
247
212
|
targetRef: plan.entry.branch,
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
213
|
+
beforeCommit: plan.currentCommit,
|
|
214
|
+
source: {
|
|
215
|
+
kind: "upstream",
|
|
216
|
+
branch: plan.remote.branch,
|
|
217
|
+
remoteCommit: plan.remote.commit,
|
|
218
|
+
taskBaseCommit: plan.taskBaseCommit,
|
|
219
|
+
strategy: "rebase"
|
|
220
|
+
},
|
|
221
|
+
checkCommands: []
|
|
251
222
|
}, options.now?.() ?? new Date());
|
|
252
223
|
tx.saveIntegrationAttempt(task.id, created);
|
|
253
224
|
return created;
|
|
254
225
|
});
|
|
255
|
-
|
|
256
|
-
continue;
|
|
257
|
-
const baseline = {
|
|
258
|
-
remoteUrl: plan.project.remoteUrl,
|
|
259
|
-
branch: plan.remote.branch
|
|
260
|
-
};
|
|
261
|
-
const result = await new GitIntegrationService(home, store, git, options.now ?? (() => new Date()), options.environment, undefined, options.jobPort).integrate(task.id, attempt.id, { remoteBaseline: baseline });
|
|
226
|
+
const result = await new GitIntegrationService(home, store, git, options.now ?? (() => new Date()), options.environment, undefined, options.jobPort).integrate(task.id, attempt.id);
|
|
262
227
|
// rr6/f3: A moved remote with non-empty checks spawns a DurableJob. This
|
|
263
228
|
// is a pending completion outcome, not a failure: name the exact
|
|
264
229
|
// Integration and Job and the exact continuation command (mirroring the
|
|
@@ -307,44 +272,3 @@ function requireTaskWorkspace(store, task) {
|
|
|
307
272
|
}
|
|
308
273
|
return workspace;
|
|
309
274
|
}
|
|
310
|
-
/**
|
|
311
|
-
* Check whether an accepted Task-final ReviewRound is completed and its
|
|
312
|
-
* immutable candidate exactly matches the current actual heads for every
|
|
313
|
-
* Project in the Task. When this holds, the reviewed head is the final
|
|
314
|
-
* head and remote reconciliation must not change it.
|
|
315
|
-
*/
|
|
316
|
-
async function hasCompletedTaskFinalReviewForCurrentCandidate(store, task, workspace, git) {
|
|
317
|
-
const actualProjects = [];
|
|
318
|
-
for (const binding of task.projectBindings) {
|
|
319
|
-
const entry = workspaceProjectEntry(workspace, binding.projectId);
|
|
320
|
-
if (entry === undefined || entry.access !== "write")
|
|
321
|
-
return false;
|
|
322
|
-
const actualHead = (await git.inspect(entry.path, "HEAD")).baseCommit;
|
|
323
|
-
actualProjects.push({ projectId: binding.projectId, commit: actualHead });
|
|
324
|
-
}
|
|
325
|
-
const actualCandidate = {
|
|
326
|
-
schemaVersion: 1,
|
|
327
|
-
projects: actualProjects
|
|
328
|
-
};
|
|
329
|
-
return acceptedTaskFinalReviews(store, task.id).some((round) => (round.taskCandidate !== undefined
|
|
330
|
-
&& sameTaskCandidate(round.taskCandidate, actualCandidate)));
|
|
331
|
-
}
|
|
332
|
-
function latestCommittedIntegration(store, taskId, projectId) {
|
|
333
|
-
return store.listIntegrationAttempts(taskId)
|
|
334
|
-
.filter((attempt) => attempt.projectId === projectId && attempt.status === "committed")
|
|
335
|
-
.sort((left, right) => left.id.localeCompare(right.id, undefined, { numeric: true }))
|
|
336
|
-
.at(-1);
|
|
337
|
-
}
|
|
338
|
-
/**
|
|
339
|
-
* A Task baseline is frozen when a completed (clean) Task-final ReviewRound
|
|
340
|
-
* reviewed the exact current head for the given Project. Once frozen, the
|
|
341
|
-
* completion gate skips remote baseline reconciliation to prevent merging
|
|
342
|
-
* unreviewed remote changes into the approved delivery.
|
|
343
|
-
*/
|
|
344
|
-
function hasFrozenTaskBaseline(store, taskId, projectId, currentCommit) {
|
|
345
|
-
return store.listReviewRounds(taskId)
|
|
346
|
-
.some((round) => ((round.scope ?? "work-item") === "task"
|
|
347
|
-
&& isAcceptedTaskReviewBaseline(store, round)
|
|
348
|
-
&& round.taskCandidate !== undefined
|
|
349
|
-
&& round.taskCandidate.projects.some((entry) => (entry.projectId === projectId && entry.commit === currentCommit))));
|
|
350
|
-
}
|
|
@@ -4,10 +4,10 @@ import { formatTimestamp } from "../output/timePresentation.js";
|
|
|
4
4
|
import { isRoleTurnStalled, latestStallProgressAt } from "../scheduler/roleTurnStall.js";
|
|
5
5
|
import { buildTaskExecutionProjection } from "../scheduler/taskExecutionProjection.js";
|
|
6
6
|
import { projectNextAction } from "../task/nextAction.js";
|
|
7
|
-
import {
|
|
8
|
-
import { currentWorkItemExecutionGroup } from "../workItem/workItem.js";
|
|
7
|
+
import { projectWorkItemExecution } from "../execution/workItemExecutionProjection.js";
|
|
9
8
|
import { operationalTaskRecords } from "../task/taskRecordRetirement.js";
|
|
10
9
|
import { projectReviewDecision } from "../review/reviewDecision.js";
|
|
10
|
+
import { projectTaskRemoteDeliveryFromStore, renderTaskRemoteDelivery } from "./taskRemoteDeliveryCommand.js";
|
|
11
11
|
const RECENT_RECORD_LIMIT = 5;
|
|
12
12
|
const RELATED_RECORD_LIMIT = 5;
|
|
13
13
|
const SUMMARY_TEXT_LIMIT = 400;
|
|
@@ -49,6 +49,7 @@ export function runTaskContextCommand(args, store, currentTaskReviewCandidate =
|
|
|
49
49
|
const changeSets = chronological(reader.listChangeSets(task.id));
|
|
50
50
|
const integrations = chronological(reader.listIntegrationAttempts(task.id));
|
|
51
51
|
const publications = chronological(reader.listPublicationReferences(task.id));
|
|
52
|
+
const remoteDelivery = projectTaskRemoteDeliveryFromStore(reader, task, currentTaskReviewCandidate);
|
|
52
53
|
const nextActionFacts = reader.readNextActionFacts(task.id);
|
|
53
54
|
if (nextActionFacts === null) {
|
|
54
55
|
throw new Error(`Task next-action facts disappeared: ${task.id}.`);
|
|
@@ -80,6 +81,7 @@ export function runTaskContextCommand(args, store, currentTaskReviewCandidate =
|
|
|
80
81
|
changeSets,
|
|
81
82
|
integrations,
|
|
82
83
|
publications,
|
|
84
|
+
remoteDelivery,
|
|
83
85
|
messages: operationalTaskRecords(reader.listMessages(task.id), events, "message"),
|
|
84
86
|
openInputRequests: inputRequests.filter((request) => request.status === "open"),
|
|
85
87
|
resolvedInputRequests: inputRequests.filter((request) => request.status !== "open"),
|
|
@@ -91,10 +93,11 @@ export function runTaskContextCommand(args, store, currentTaskReviewCandidate =
|
|
|
91
93
|
})
|
|
92
94
|
};
|
|
93
95
|
});
|
|
94
|
-
const { task, execution, reviewConfig, reviewDecision, brief, activeDecisions, milestones, roles, managedWorkspaces, roleSessionSets, coordinationMailboxes, workItems, turns, reviewRounds, changeSets, integrations, publications, messages, openInputRequests, resolvedInputRequests, events, nextAction } = data;
|
|
96
|
+
const { task, execution, reviewConfig, reviewDecision, brief, activeDecisions, milestones, roles, managedWorkspaces, roleSessionSets, coordinationMailboxes, workItems, turns, reviewRounds, changeSets, integrations, publications, remoteDelivery, messages, openInputRequests, resolvedInputRequests, events, nextAction } = data;
|
|
95
97
|
const timeZone = store.getConfig().timeZone;
|
|
96
98
|
const displayedActiveDecisions = activeDecisions.slice(-RECENT_RECORD_LIMIT);
|
|
97
99
|
const displayedWorkItems = currentAndRecentWorkItems(workItems);
|
|
100
|
+
const currentWorkItems = workItems.filter(({ status }) => status !== "retired");
|
|
98
101
|
const displayedOpenInputRequests = openInputRequests.slice(-RECENT_RECORD_LIMIT);
|
|
99
102
|
const displayedResolvedInputRequests = resolvedInputRequests.slice(-RECENT_RECORD_LIMIT);
|
|
100
103
|
const displayedActiveTurns = execution.activeTurns;
|
|
@@ -132,6 +135,7 @@ export function runTaskContextCommand(args, store, currentTaskReviewCandidate =
|
|
|
132
135
|
...(task.retirementSummary === undefined ? [] : [`Retirement summary: ${task.retirementSummary}`]),
|
|
133
136
|
...(task.replacementTaskId === undefined ? [] : [`Replacement Task: ${task.replacementTaskId}`]),
|
|
134
137
|
...(task.archiveSummary === undefined ? [] : [`Archive summary: ${task.archiveSummary}`]),
|
|
138
|
+
renderTaskRemoteDelivery(remoteDelivery).trimEnd(),
|
|
135
139
|
"Execution:",
|
|
136
140
|
` Status: ${execution.status}`,
|
|
137
141
|
` Owner/action: ${execution.owner}/${execution.action}`,
|
|
@@ -173,12 +177,12 @@ export function runTaskContextCommand(args, store, currentTaskReviewCandidate =
|
|
|
173
177
|
? [" None."]
|
|
174
178
|
: managedWorkspaces.map((workspace) => (` ${managedWorkspaceLabel(workspace)}: ${workspace.root} (${workspace.entries.filter(({ access }) => access === "write").length} writable / ${workspace.entries.length} Projects)`))),
|
|
175
179
|
`Type: ${task.type ?? "unspecified"}`,
|
|
176
|
-
`Execution topology: ${
|
|
180
|
+
`Execution topology: ${currentWorkItems.length === 0
|
|
177
181
|
? "Leader-owned Task main"
|
|
178
|
-
: `${
|
|
182
|
+
: `${currentWorkItems.length} independently owned WorkItem(s), integrated on Task main`}`,
|
|
179
183
|
`Completion evidence: ${task.projectBindings.length === 0
|
|
180
184
|
? "no Project evidence required"
|
|
181
|
-
:
|
|
185
|
+
: currentWorkItems.length === 0
|
|
182
186
|
? "clean committed Task main required"
|
|
183
187
|
: "each delivered WorkItem requires a ChangeSet and committed Integration"}`,
|
|
184
188
|
`Global review: ${reviewConfig === null
|
|
@@ -285,9 +289,7 @@ export function runTaskContextCommand(args, store, currentTaskReviewCandidate =
|
|
|
285
289
|
...(observability.workItems.find(({ workItemId }) => workItemId === item.id) === undefined
|
|
286
290
|
? []
|
|
287
291
|
: [renderWorkItemObservability(observability.workItems.find(({ workItemId }) => workItemId === item.id))]),
|
|
288
|
-
...(
|
|
289
|
-
? []
|
|
290
|
-
: renderExecutionGroup(currentWorkItemExecutionGroup(item), executionGroupsById.get(currentWorkItemExecutionGroup(item).id))),
|
|
292
|
+
...renderWorkItemExecution(projectWorkItemExecution(item, turns, roleSessionSets)),
|
|
291
293
|
...(item.acceptance.length === 0
|
|
292
294
|
? []
|
|
293
295
|
: [` Acceptance: ${item.acceptance.map(compactText).join("; ")}`]),
|
|
@@ -309,9 +311,12 @@ export function runTaskContextCommand(args, store, currentTaskReviewCandidate =
|
|
|
309
311
|
: [
|
|
310
312
|
` Turns: ${itemRuns.length}; latest ${latestTurn.id} [${latestTurn.status}] ${latestTurn.effective.agentId}/${latestTurn.effective.adapterId} · effective r${latestTurn.effective.sourceDesiredRevision}/${latestTurn.effective.profileAccess}/${latestTurn.effective.permission.strategy}`,
|
|
311
313
|
` Assignment: ${latestTurn.inputs[0].input.source.channel}${latestTurn.inputs[0].input.directive === undefined ? "" : ` · ${compactText(latestTurn.inputs[0].input.directive)}`}`,
|
|
312
|
-
...(latestTurn.result === undefined
|
|
314
|
+
...(latestTurn.result?.output === undefined
|
|
315
|
+
? []
|
|
316
|
+
: [` Result: ${compactText(latestTurn.result.output)}`]),
|
|
317
|
+
...(latestTurn.result?.diagnostic === undefined
|
|
313
318
|
? []
|
|
314
|
-
: [`
|
|
319
|
+
: [` Failure: ${compactText(latestTurn.result.diagnostic)}`])
|
|
315
320
|
]),
|
|
316
321
|
...renderReviewRounds(reviewRounds.filter((round) => round.workItemId === item.id), executionGroupsById)
|
|
317
322
|
];
|
|
@@ -323,7 +328,10 @@ export function runTaskContextCommand(args, store, currentTaskReviewCandidate =
|
|
|
323
328
|
...recentSection("Turns", turns, (run) => [
|
|
324
329
|
` ${run.id} [${run.status}/${run.purpose}] ${run.roleName} via ${run.effective.agentId}/${run.effective.adapterId}`,
|
|
325
330
|
` Effective: r${run.effective.sourceDesiredRevision}; Profile intent: ${run.effective.profileAccess}; permission: ${run.effective.permission.strategy}; model: ${run.effective.model ?? "default"}; effort: ${run.effective.effort ?? "default"}`,
|
|
326
|
-
...(run.result === undefined ? [] : [` Result: ${compactText(run.result.output)}`])
|
|
331
|
+
...(run.result?.output === undefined ? [] : [` Result: ${compactText(run.result.output)}`]),
|
|
332
|
+
...(run.result?.diagnostic === undefined
|
|
333
|
+
? []
|
|
334
|
+
: [` Failure: ${compactText(run.result.diagnostic)}`])
|
|
327
335
|
]),
|
|
328
336
|
"",
|
|
329
337
|
"Runtime health:",
|
|
@@ -347,7 +355,11 @@ export function runTaskContextCommand(args, store, currentTaskReviewCandidate =
|
|
|
347
355
|
`Integration Attempts (${integrations.length}):`,
|
|
348
356
|
...(integrations.length === 0
|
|
349
357
|
? [" None."]
|
|
350
|
-
: integrations.slice(-RECENT_RECORD_LIMIT).map((integration) => (` ${integration.id} [${integration.status}/${integration.projectId}] — ${integration.targetRef}; ${integration.
|
|
358
|
+
: integrations.slice(-RECENT_RECORD_LIMIT).map((integration) => (` ${integration.id} [${integration.status}/${integration.projectId}] — ${integration.targetRef}; ${integration.source.kind === "work-item"
|
|
359
|
+
? `WorkItem ${integration.source.workItemId}@${integration.source.resultCommit.slice(0, 12)}`
|
|
360
|
+
: integration.source.kind === "upstream"
|
|
361
|
+
? `upstream ${integration.source.branch}@${integration.source.remoteCommit.slice(0, 12)}`
|
|
362
|
+
: `historical ChangeSets ${integration.source.changeSetIds.join(", ")}`}`))),
|
|
351
363
|
"",
|
|
352
364
|
`Publication references (${publications.length}):`,
|
|
353
365
|
...(publications.length === 0
|
|
@@ -435,15 +447,7 @@ function renderReviewRounds(rounds, executionGroupsById = new Map()) {
|
|
|
435
447
|
? [` Review mode: full`]
|
|
436
448
|
: [
|
|
437
449
|
` Review mode: delta-recheck (rechecks ${latest.deltaRecheck.previousReviewRoundId}@${latest.deltaRecheck.previousBaseCommit.slice(0, 12)})`,
|
|
438
|
-
` Delta: ${latest.deltaRecheck.changedFiles.length} file(s), +${latest.deltaRecheck.addedLines}/-${latest.deltaRecheck.deletedLines}, digest ${latest.deltaRecheck.diffDigest.slice(0, 12)}
|
|
439
|
-
...(latest.deltaRecheck.disposition === undefined
|
|
440
|
-
? []
|
|
441
|
-
: [
|
|
442
|
-
` Delta disposition: ${latest.deltaRecheck.disposition}`,
|
|
443
|
-
...(latest.deltaRecheck.escalatedToReviewRoundId === undefined
|
|
444
|
-
? []
|
|
445
|
-
: [` Escalated to: ${latest.deltaRecheck.escalatedToReviewRoundId}`])
|
|
446
|
-
])
|
|
450
|
+
` Delta: ${latest.deltaRecheck.changedFiles.length} file(s), +${latest.deltaRecheck.addedLines}/-${latest.deltaRecheck.deletedLines}, digest ${latest.deltaRecheck.diffDigest.slice(0, 12)}`
|
|
447
451
|
])
|
|
448
452
|
]
|
|
449
453
|
: []),
|
|
@@ -451,16 +455,18 @@ function renderReviewRounds(rounds, executionGroupsById = new Map()) {
|
|
|
451
455
|
? "not prepared"
|
|
452
456
|
: `${latest.workspace.root} (${latest.workspace.entries.length} writable Projects)`}`,
|
|
453
457
|
` Workspace disposition: ${latest.workspaceDisposition?.kind ?? "pending"}`,
|
|
454
|
-
`
|
|
455
|
-
|
|
456
|
-
? "none"
|
|
457
|
-
: latest.checks.map(({ name, outcome }) => `${name}=${outcome}`).join(", ")}`,
|
|
458
|
-
...(latest.summary === undefined
|
|
458
|
+
` Main Reviewer Turn: ${latest.reviewerTurnId ?? "not dispatched"}`,
|
|
459
|
+
...(latest.failure === undefined
|
|
459
460
|
? []
|
|
460
|
-
: [`
|
|
461
|
+
: [` Core failure: ${latest.failure.kind} · ${compactText(latest.failure.message)}`]),
|
|
461
462
|
...(latest.executionGroup === undefined
|
|
462
463
|
? []
|
|
463
|
-
:
|
|
464
|
+
: [
|
|
465
|
+
` Execution shape: replicated`,
|
|
466
|
+
` Execution Group: ${latest.executionGroup.id}`,
|
|
467
|
+
...latest.executionGroup.lanes.map((lane) => (` Producer ${lane.id} (#${lane.ordinal}, ${lane.roleName}): `
|
|
468
|
+
+ `${lane.disposition}; turn=${lane.currentTurnId ?? "not dispatched"}`))
|
|
469
|
+
])
|
|
464
470
|
];
|
|
465
471
|
}
|
|
466
472
|
function renderResolvedInputRequest(request, timeZone) {
|
|
@@ -553,57 +559,19 @@ function managedWorkspaceLabel(workspace) {
|
|
|
553
559
|
return `execution-lane ${workspace.owner.executionGroupId}/${workspace.owner.executionLaneId}`;
|
|
554
560
|
}
|
|
555
561
|
}
|
|
556
|
-
function
|
|
557
|
-
const summary = projected
|
|
558
|
-
?? summarizeExecutionGroup(group);
|
|
559
|
-
const health = projected?.health;
|
|
560
|
-
const resources = projected?.resources;
|
|
562
|
+
function renderWorkItemExecution(projection) {
|
|
561
563
|
return [
|
|
562
|
-
`
|
|
563
|
-
...(
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
...(
|
|
570
|
-
? []
|
|
571
|
-
: [
|
|
572
|
-
` Resources: tokens=${resourceUsageLabel(resources.tokens, resources.tokensRemaining, resources.tokensObservable)}; tools=${resourceUsageLabel(resources.toolCalls, resources.toolCallsRemaining, resources.toolCallsObservable)}; wall=${resources.wallClockSeconds}s${resources.wallClockSecondsRemaining === undefined ? "" : `, remaining=${resources.wallClockSecondsRemaining}s`}`,
|
|
573
|
-
` Completion: usable=${resources.usableLaneCount}/${group.stage?.resources?.quorum ?? "legacy"}; quorum=${resources.quorumMet ? "met" : "open"}; deadline=${resources.deadlineReached ? "reached" : "open"}; budgets=${resources.exhaustedBudgets.join(",") || "open"}; queued=${resources.pendingLaneIds.length}; stragglers=${resources.stragglerLaneIds.length}`
|
|
574
|
-
]),
|
|
575
|
-
...summary.laneSummaries.flatMap((lane) => {
|
|
576
|
-
const laneHealth = projected?.laneSummaries.find(({ laneId }) => laneId === lane.laneId);
|
|
577
|
-
return [
|
|
578
|
-
` Lane ${lane.laneId} (#${lane.ordinal}, ${lane.roleName}${lane.turnId === undefined ? "" : `, run ${lane.turnId}`}) [${lane.status}${laneHealth?.runtimeHealth === undefined ? "" : `/${laneHealth.runtimeHealth}`}]${lane.summary === undefined ? "" : `: ${compactText(lane.summary)}`}`,
|
|
579
|
-
...(lane.effective === undefined
|
|
580
|
-
? []
|
|
581
|
-
: [` Config: ${lane.effective.adapterId}/${lane.effective.model ?? "default"}/${lane.effective.effort ?? "default"}; profile=${lane.effective.profileAccess}`]),
|
|
582
|
-
...(laneHealth !== undefined && laneHealth.recovery !== "none"
|
|
583
|
-
? [` Recovery: ${laneHealth.recovery}; ${compactText(laneHealth.reason)}`]
|
|
584
|
-
: []),
|
|
585
|
-
...(lane.report === undefined ? [] : [` Report: ${compactText(lane.report)}`]),
|
|
586
|
-
...(lane.checks === undefined || lane.checks.length === 0
|
|
587
|
-
? []
|
|
588
|
-
: [` Checks: ${lane.checks.map(({ name, outcome }) => `${name}:${outcome}`).join(", ")}`]),
|
|
589
|
-
...(lane.findings === undefined || lane.findings.length === 0
|
|
590
|
-
? []
|
|
591
|
-
: [` Findings: ${lane.findings.map(({ id, severity, status }) => `${id}:${severity}/${status}`).join(", ")}`]),
|
|
592
|
-
...(lane.evidence === undefined || lane.evidence.length === 0
|
|
593
|
-
? []
|
|
594
|
-
: [` Evidence: ${lane.evidence.length} item(s)`]),
|
|
595
|
-
...(lane.evidenceCommit === undefined
|
|
596
|
-
? []
|
|
597
|
-
: [` Evidence commit: ${lane.evidenceCommit}`]),
|
|
598
|
-
...(lane.decision === undefined ? [] : [` Decision: ${lane.decision}`])
|
|
599
|
-
];
|
|
600
|
-
}),
|
|
601
|
-
...(summary.openHighPriorityFindingIds.length === 0
|
|
602
|
-
? []
|
|
603
|
-
: [` Open high findings: ${summary.openHighPriorityFindingIds.join(", ")}`]),
|
|
604
|
-
...(summary.resolution === undefined
|
|
564
|
+
` WorkItem execution [${projection.shape}]${projection.groupId === undefined ? "" : `: ${projection.groupId}`}`,
|
|
565
|
+
...projection.lanes.map((lane) => (` Lane ${lane.laneId} (#${lane.ordinal}, ${lane.roleName}) [${lane.status}]: `
|
|
566
|
+
+ `turn=${lane.currentTurnId ?? "unknown"}; session=${lane.session}; `
|
|
567
|
+
+ `retry=${lane.retryTurnId ?? "none"}; settle=${lane.settleTurnId ?? "none"}`)),
|
|
568
|
+
` Synthesis: ${projection.synthesis.status} (${projection.synthesis.successfulLaneCount}/${projection.synthesis.requiredSuccessfulLaneCount} successful)`,
|
|
569
|
+
` Main Turn: ${projection.mainTurn.turnId ?? "unobserved"} [${projection.mainTurn.status}]; session=${projection.mainTurn.session}`,
|
|
570
|
+
` Candidate source: ${projection.candidate.candidateId ?? "none"} [${projection.candidate.status}]; main=${projection.candidate.mainTurnId ?? "unobserved"}`,
|
|
571
|
+
...(projection.candidate.sourceExecutionGroupId === undefined
|
|
605
572
|
? []
|
|
606
|
-
: [`
|
|
573
|
+
: [` Provenance: ${projection.candidate.mainTurnId ?? "unobserved"} -> ${projection.candidate.sourceExecutionGroupId} -> ${projection.candidate.successfulLaneTurns.map(({ laneId, successfulTurnId }) => `${laneId} -> ${successfulTurnId}`).join(", ") || "unobserved"}`]),
|
|
574
|
+
` Next: ${projection.nextAction.kind}; owner=${projection.nextAction.owners.join(", ") || "none"}; target=${projection.nextAction.targetIds.join(", ") || "none"}`
|
|
607
575
|
];
|
|
608
576
|
}
|
|
609
577
|
function resourceUsageLabel(used, remaining, observable) {
|
|
@@ -612,6 +580,5 @@ function resourceUsageLabel(used, remaining, observable) {
|
|
|
612
580
|
return `${used}${remaining === undefined ? "" : `, remaining=${remaining}`}`;
|
|
613
581
|
}
|
|
614
582
|
function renderWorkItemObservability(item) {
|
|
615
|
-
|
|
616
|
-
return ` Observability: stages=${stages || "none"}; tokens=${item.cost.tokens}; tools=${item.cost.toolCalls}; wall=${item.cost.wallClockSeconds}s; retries=${item.cost.retryCount}; snapshots=${item.context.snapshotCount}; evidence=${item.evidenceCount}; open-findings=${item.openFindingCount}; compression=${item.context.compressionStatus}`;
|
|
583
|
+
return ` Observability (read-only): tokens=${item.cost.tokensObservable ? item.cost.tokens : "unobserved"}; tools=${item.cost.toolCallsObservable ? item.cost.toolCalls : "unobserved"}; wall=${item.cost.wallClockSeconds}s; retries=${item.cost.retryCount}; snapshots=${item.context.snapshotCount}; agent-results=${item.resultCount ?? "unobserved"}; compression=${item.context.compressionStatus}`;
|
|
617
584
|
}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { createTaskEvent } from "../event/taskEvent.js";
|
|
2
|
-
import {
|
|
2
|
+
import { updateExecutionLane } from "../execution/workItemExecution.js";
|
|
3
3
|
import { usageError } from "../errors/cliError.js";
|
|
4
4
|
import { requestDurableJobCancel } from "../job/durableJob.js";
|
|
5
5
|
import { finishReviewRound, updateReviewExecutionGroup } from "../review/reviewRound.js";
|
|
6
6
|
import { failTurn } from "../turn/turn.js";
|
|
7
7
|
import { queueLeaderWakeup } from "../scheduler/wakeupQueue.js";
|
|
8
8
|
import { startTaskExecution, stopTaskExecution } from "../task/task.js";
|
|
9
|
-
import { updateWorkItemExecutionGroup, workItemExecutionGroupById } from "../workItem/workItem.js";
|
|
10
9
|
import { taskActor } from "./taskActor.js";
|
|
11
10
|
export function parseTaskExecutionStopRequest(args) {
|
|
12
11
|
const taskId = args[0];
|
|
@@ -183,44 +182,27 @@ function taskRuntimeRoleNames(store, taskId, turns) {
|
|
|
183
182
|
}
|
|
184
183
|
function failExecutionAttempts(store, taskId, turns, reason, now) {
|
|
185
184
|
const summary = `Task execution stopped: ${reason}`;
|
|
186
|
-
const workItems = new Map(store.listWorkItems(taskId).map((item) => [item.id, item]));
|
|
187
185
|
const reviewRounds = new Map(store.listReviewRounds(taskId).map((round) => [round.id, round]));
|
|
188
186
|
const affectedReviewRoundIds = new Set();
|
|
189
187
|
for (const turn of turns) {
|
|
190
|
-
if (turn.executionGroupId === undefined || turn.executionLaneId === undefined)
|
|
191
|
-
continue;
|
|
192
|
-
if (turn.workItemId !== undefined) {
|
|
193
|
-
const item = workItems.get(turn.workItemId);
|
|
194
|
-
const group = item === undefined
|
|
195
|
-
? undefined
|
|
196
|
-
: workItemExecutionGroupById(item, turn.executionGroupId);
|
|
197
|
-
const lane = group?.lanes.find(({ id }) => id === turn.executionLaneId);
|
|
198
|
-
if (item !== undefined && group !== undefined && lane !== undefined
|
|
199
|
-
&& item.currentExecutionGroupId === group.id
|
|
200
|
-
&& !["completed", "failed", "skipped"].includes(lane.status)) {
|
|
201
|
-
const updated = updateWorkItemExecutionGroup(item, recordExecutionLaneResult(group, lane.id, { summary }, "failed", now), now);
|
|
202
|
-
workItems.set(item.id, updated);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
188
|
if (turn.reviewRoundId !== undefined) {
|
|
206
189
|
affectedReviewRoundIds.add(turn.reviewRoundId);
|
|
190
|
+
if (turn.executionGroupId === undefined || turn.executionLaneId === undefined)
|
|
191
|
+
continue;
|
|
207
192
|
const round = reviewRounds.get(turn.reviewRoundId);
|
|
208
193
|
const group = round?.executionGroup?.id === turn.executionGroupId
|
|
209
194
|
? round.executionGroup
|
|
210
195
|
: undefined;
|
|
211
196
|
const lane = group?.lanes.find(({ id }) => id === turn.executionLaneId);
|
|
212
197
|
if (round !== undefined && group !== undefined && lane !== undefined
|
|
213
|
-
&&
|
|
214
|
-
reviewRounds.set(round.id, updateReviewExecutionGroup(round,
|
|
198
|
+
&& lane.disposition === "open") {
|
|
199
|
+
reviewRounds.set(round.id, updateReviewExecutionGroup(round, updateExecutionLane(group, lane.id, {
|
|
200
|
+
currentTurnId: turn.id,
|
|
201
|
+
disposition: "failed"
|
|
202
|
+
}, now)));
|
|
215
203
|
}
|
|
216
204
|
}
|
|
217
205
|
}
|
|
218
|
-
for (const item of workItems.values()) {
|
|
219
|
-
const original = store.getWorkItem(item.taskId, item.id);
|
|
220
|
-
if (original !== null && original.revision !== item.revision) {
|
|
221
|
-
store.saveWorkItem(item.taskId, item);
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
206
|
for (const reviewRoundId of affectedReviewRoundIds) {
|
|
225
207
|
const round = reviewRounds.get(reviewRoundId);
|
|
226
208
|
const original = store.getReviewRound(round.taskId, round.id);
|
|
@@ -228,7 +210,7 @@ function failExecutionAttempts(store, taskId, turns, reason, now) {
|
|
|
228
210
|
continue;
|
|
229
211
|
const changed = JSON.stringify(original.executionGroup) !== JSON.stringify(round.executionGroup);
|
|
230
212
|
const terminal = round.status === "pending" || round.status === "running"
|
|
231
|
-
? finishReviewRound(round, "failed",
|
|
213
|
+
? finishReviewRound(round, "failed", now, { kind: "execution", message: summary })
|
|
232
214
|
: round;
|
|
233
215
|
if (changed || terminal !== round)
|
|
234
216
|
store.saveReviewRound(round.taskId, terminal);
|
|
@@ -255,12 +255,12 @@ export function isCurrentGlobalOperator(store, environment) {
|
|
|
255
255
|
return false;
|
|
256
256
|
const agentId = exactIdentity(environment.YUI_AGENT_ID);
|
|
257
257
|
const adapterId = exactIdentity(environment.YUI_ADAPTER_ID);
|
|
258
|
-
const
|
|
258
|
+
const runtimeGenerationId = exactIdentity(environment.YUI_RUNTIME_GENERATION_ID);
|
|
259
259
|
const nativeSessionId = exactIdentity(environment.YUI_NATIVE_SESSION_ID);
|
|
260
260
|
const binding = role.agentBindings[role.activeAgentId];
|
|
261
261
|
if (agentId === undefined
|
|
262
262
|
|| adapterId === undefined
|
|
263
|
-
||
|
|
263
|
+
|| runtimeGenerationId === undefined
|
|
264
264
|
|| binding === undefined
|
|
265
265
|
|| binding.agentId !== agentId
|
|
266
266
|
|| binding.adapterId !== adapterId)
|
|
@@ -277,7 +277,7 @@ export function isCurrentGlobalOperator(store, environment) {
|
|
|
277
277
|
roleName: role.name,
|
|
278
278
|
agentId,
|
|
279
279
|
adapterId,
|
|
280
|
-
|
|
280
|
+
runtimeGenerationId
|
|
281
281
|
});
|
|
282
282
|
}
|
|
283
283
|
// A fresh Codex launch discovers its native Session asynchronously. Its
|
|
@@ -290,14 +290,14 @@ export function isCurrentGlobalOperator(store, environment) {
|
|
|
290
290
|
|| (nativeSessionId === undefined
|
|
291
291
|
&& binding.adapterId === "codex"
|
|
292
292
|
&& session.adapterId === "codex"
|
|
293
|
-
&& session.
|
|
294
|
-
&& session.
|
|
293
|
+
&& session.runtimeGenerationId !== undefined
|
|
294
|
+
&& session.runtimeGenerationId === runtimeGenerationId));
|
|
295
295
|
return binding.agentId === session.agentId
|
|
296
296
|
&& binding.adapterId === session.adapterId
|
|
297
297
|
&& session.agentId === agentId
|
|
298
298
|
&& session.adapterId === adapterId
|
|
299
|
-
&& session.
|
|
300
|
-
&& session.
|
|
299
|
+
&& session.runtimeGenerationId !== undefined
|
|
300
|
+
&& session.runtimeGenerationId === runtimeGenerationId
|
|
301
301
|
&& nativeSessionMatches;
|
|
302
302
|
}
|
|
303
303
|
function currentProcessBelongsToReservedGlobalLaunch(store, input) {
|
|
@@ -307,16 +307,16 @@ function currentProcessBelongsToReservedGlobalLaunch(store, input) {
|
|
|
307
307
|
scope: "global",
|
|
308
308
|
roleName: input.roleName
|
|
309
309
|
}));
|
|
310
|
-
if (!isRuntimeLaunchReservation(mailbox?.processing, input.
|
|
310
|
+
if (!isRuntimeLaunchReservation(mailbox?.processing, input.runtimeGenerationId)
|
|
311
311
|
|| hasRuntimeCleanupObligation(mailbox))
|
|
312
312
|
return false;
|
|
313
|
-
const owner = store.getSessionOwner(input.
|
|
313
|
+
const owner = store.getSessionOwner(input.runtimeGenerationId);
|
|
314
314
|
if (owner === null
|
|
315
315
|
|| owner.owner.scope !== "global"
|
|
316
316
|
|| owner.owner.roleName !== input.roleName
|
|
317
317
|
|| owner.agentId !== input.agentId
|
|
318
318
|
|| owner.adapterId !== input.adapterId
|
|
319
|
-
|| owner.
|
|
319
|
+
|| owner.runtimeGenerationId !== input.runtimeGenerationId
|
|
320
320
|
|| owner.providerRoot.attribution !== "launch-env"
|
|
321
321
|
|| !isLinuxProcessLive(owner.providerRoot.pid, owner.providerRoot.startIdentity)) {
|
|
322
322
|
return false;
|