@zq-silk/yui 0.2.0 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +603 -133
- package/README.md +806 -31
- package/dist/agent/agent.js +2 -1
- package/dist/agent/argumentPolicy.js +3 -1
- package/dist/agent/launchEnvironment.js +106 -0
- package/dist/agent/managedRuntimeEnvironment.js +34 -0
- package/dist/brief/taskBrief.js +11 -1
- package/dist/cli/agentConfigurationPicker.js +287 -0
- package/dist/cli/commandCatalog.js +488 -60
- package/dist/cli/completion.js +146 -22
- package/dist/cli/helpRenderer.js +3 -1
- package/dist/cli/interactionCandidates.js +53 -15
- package/dist/cli/interactionPolicy.js +267 -30
- package/dist/cli/interactiveSelection.js +6 -2
- package/dist/cli/invocationRouter.js +5 -1
- package/dist/cli/operatorWizard.js +87 -0
- package/dist/cli/roleOptionCatalog.js +1 -0
- package/dist/cli/roleWizard.js +185 -21
- package/dist/cli/updateCommand.js +62 -19
- package/dist/cli/updateOrchestrator.js +539 -0
- package/dist/cli/updatePorts.js +1119 -0
- package/dist/cli/upgradeCommand.js +112 -0
- package/dist/cli.js +1420 -86
- package/dist/commands/agentCommands.js +146 -3
- package/dist/commands/configCommands.js +126 -0
- package/dist/commands/controllerCommands.js +365 -0
- package/dist/commands/globalRoleCommands.js +168 -126
- package/dist/commands/jobCommands.js +18 -8
- package/dist/commands/operatorCommands.js +159 -9
- package/dist/commands/profileCommands.js +203 -0
- package/dist/commands/projectCommands.js +650 -0
- package/dist/commands/roleConfiguration.js +85 -24
- package/dist/commands/roleRuntimeGuard.js +12 -0
- package/dist/commands/roleSkillValidation.js +47 -0
- package/dist/commands/taskActor.js +127 -0
- package/dist/commands/taskCommands.js +4201 -313
- package/dist/commands/taskCompletionGate.js +131 -0
- package/dist/commands/taskContextCommand.js +244 -30
- package/dist/commands/taskInputCommands.js +177 -59
- package/dist/commands/taskIntegrationCommands.js +303 -0
- package/dist/commands/taskOverviewCommand.js +363 -0
- package/dist/commands/taskRoleRuntimeStatus.js +125 -19
- package/dist/commands/textInput.js +15 -0
- package/dist/completion/completionInstaller.js +26 -22
- package/dist/config/yuiConfig.js +4 -3
- package/dist/context/dispatchContext.js +90 -38
- package/dist/context/roleSessionContext.js +119 -0
- package/dist/controller/claudeLifecycleHook.js +203 -0
- package/dist/controller/clientRuntime.js +408 -56
- package/dist/controller/codexLifecycleHook.js +108 -0
- package/dist/controller/controller.js +1089 -32
- package/dist/controller/domainIdentity.js +505 -0
- package/dist/controller/ephemeralResourceReaper.js +131 -0
- package/dist/controller/fileSchedulerStoreAdapter.js +2153 -103
- package/dist/controller/providerHookRunFence.js +127 -0
- package/dist/controller/resourceCleanupLinux.js +286 -0
- package/dist/controller/resourceInventory.js +531 -0
- package/dist/controller/resourceInventoryLinux.js +610 -0
- package/dist/controller/runtime.js +629 -10
- package/dist/controller/runtimeEventInbox.js +564 -0
- package/dist/controller/runtimeEventProcessor.js +248 -0
- package/dist/controller/runtimeLaunchCoordinator.js +477 -0
- package/dist/controller/sessionNotify.js +121 -78
- package/dist/coordination/deadlineScheduler.js +15 -0
- package/dist/coordination/mailboxScheduler.js +108 -0
- package/dist/coordination/workMailbox.js +329 -0
- package/dist/coordination/workMailboxQueue.js +86 -0
- package/dist/core/controllerClient.js +19 -5
- package/dist/core/controllerEndpoint.js +37 -0
- package/dist/core/controllerServer.js +218 -10
- package/dist/core/protocol.js +6 -2
- package/dist/decision/decision.js +2 -1
- package/dist/doctor/doctor.js +681 -32
- package/dist/domain/validation.js +53 -0
- package/dist/errors/cliError.js +5 -3
- package/dist/event/taskEvent.js +7 -3
- package/dist/execution/codexThreadNaming.js +160 -0
- package/dist/execution/executionGroup.js +579 -0
- package/dist/executor/agentAdapter.js +255 -40
- package/dist/executor/agentConfigurationCatalog.js +326 -0
- package/dist/executor/agentConfigurationProbe.js +506 -0
- package/dist/executor/agentExecutor.js +625 -10
- package/dist/executor/codexConfigConflict.js +290 -0
- package/dist/executor/effectiveLaunch.js +340 -0
- package/dist/executor/executorRegistry.js +238 -36
- package/dist/executor/fileRoleLaunchPlanner.js +550 -40
- package/dist/executor/turnCompletion.js +126 -0
- package/dist/input/inputRequest.js +30 -9
- package/dist/integration/changeSet.js +36 -0
- package/dist/integration/checkResult.js +24 -0
- package/dist/integration/gitIntegrationService.js +695 -0
- package/dist/integration/integrationAttempt.js +142 -0
- package/dist/interaction/operatorPresentation.js +96 -0
- package/dist/lifecycle/canonicalLifecycleEvent.js +342 -0
- package/dist/lifecycle/exactRunTerminalization.js +572 -0
- package/dist/lifecycle/providerLifecycleMapping.js +190 -0
- package/dist/lifecycle/taskRoleSessionReset.js +124 -0
- package/dist/message/message.js +23 -7
- package/dist/milestone/milestone.js +2 -1
- package/dist/operator/operatorSessionHistory.js +124 -0
- package/dist/output/agentConfigurationPresentation.js +43 -0
- package/dist/output/rolePresentation.js +34 -10
- package/dist/output/terminal.js +8 -0
- package/dist/output/timePresentation.js +55 -0
- package/dist/profile/agentProfile.js +128 -0
- package/dist/repository/gitWorkspace.js +578 -24
- package/dist/repository/project.js +213 -0
- package/dist/repository/taskWorkspaceCoordinator.js +392 -0
- package/dist/repository/taskWorkspacePreparer.js +1688 -191
- package/dist/review/reviewConfig.js +11 -0
- package/dist/review/reviewRound.js +399 -0
- package/dist/review/taskFinalReviewContract.js +90 -0
- package/dist/role/role.js +124 -23
- package/dist/run/agentRun.js +155 -12
- package/dist/run/runIdentity.js +82 -0
- package/dist/runtime/exactControlPlane.js +472 -0
- package/dist/runtime/index.js +8 -0
- package/dist/runtime/lifecycleReservation.js +38 -0
- package/dist/runtime/ports.js +11 -0
- package/dist/runtime/preallocatedNativeSession.js +13 -0
- package/dist/runtime/promptEnvelope.js +30 -0
- package/dist/runtime/runtimeBinding.js +31 -0
- package/dist/runtime/runtimeOwner.js +14 -0
- package/dist/runtime/sessionLaunchRequest.js +62 -0
- package/dist/runtime/sessionTitle.js +54 -0
- package/dist/runtime/taskRuntimeIsolation.js +643 -0
- package/dist/runtime/tmuxAdapters.js +315 -0
- package/dist/runtime/turnCompletion.js +3 -0
- package/dist/runtime/validation.js +23 -0
- package/dist/scheduler/activeRoleRunDelivery.js +342 -32
- package/dist/scheduler/activeTaskProgress.js +63 -0
- package/dist/scheduler/leaderFailure.js +2 -1
- package/dist/scheduler/leaderWakeupProcessor.js +307 -66
- package/dist/scheduler/operatorInputNotificationProcessor.js +109 -46
- package/dist/scheduler/operatorNotification.js +44 -2
- package/dist/scheduler/ports.js +28 -1
- package/dist/scheduler/roleRunLiveness.js +131 -25
- package/dist/scheduler/roleRunStall.js +951 -0
- package/dist/scheduler/taskExecutionProjection.js +544 -0
- package/dist/scheduler/wakeupQueue.js +3 -0
- package/dist/setup/setupCommand.js +302 -52
- package/dist/storage/compatibleTaskStore.js +102 -0
- package/dist/storage/migration/baseline.js +78 -0
- package/dist/storage/migration/classifier.js +51 -0
- package/dist/storage/migration/compatibleCodec.js +53 -0
- package/dist/storage/migration/engine.js +147 -0
- package/dist/storage/migration/index.js +33 -0
- package/dist/storage/migration/planner.js +154 -0
- package/dist/storage/migration/productionRegistry.js +486 -0
- package/dist/storage/migration/registry.js +169 -0
- package/dist/storage/migration/report.js +54 -0
- package/dist/storage/migration/types.js +31 -0
- package/dist/storage/storageSchema.js +147 -123
- package/dist/storage/storageVersions.js +11 -0
- package/dist/storage/taskStore.js +1793 -197
- package/dist/storage/upgrade/homeClassification.js +156 -0
- package/dist/storage/upgrade/homeMigrationTarget.js +595 -0
- package/dist/storage/upgrade/offlineUpgradeInventory.js +315 -0
- package/dist/storage/upgrade/productionMigrationRegistry.js +6 -0
- package/dist/storage/upgrade/recordVersionScan.js +176 -0
- package/dist/storage/upgrade/recordVersions.js +159 -0
- package/dist/storage/upgrade/switchProgress.js +80 -0
- package/dist/storage/upgrade/upgradeOrchestrator.js +948 -0
- package/dist/storage/upgrade/upgradeReceipt.js +161 -0
- package/dist/storage/upgradeCoordination.js +186 -0
- package/dist/storage/upgradeFence.js +366 -0
- package/dist/task/task.js +132 -26
- package/dist/task/taskRecordReference.js +66 -0
- package/dist/tmux/commandExecutor.js +75 -2
- package/dist/tmux/tmuxManager.js +747 -49
- package/dist/version.js +23 -0
- package/dist/web/assets/assetManifest.js +62 -0
- package/dist/web/assets/client/app.js +631 -0
- package/dist/web/assets/client/components.js +605 -0
- package/dist/web/assets/client/dom.js +14 -0
- package/dist/web/assets/client/format.js +28 -0
- package/dist/web/assets/client/i18n.js +494 -0
- package/dist/web/assets/client/markdown.js +114 -0
- package/dist/web/assets/client/theme.js +32 -0
- package/dist/web/assets/client/view.js +458 -0
- package/dist/web/assets/fontData.js +12 -0
- package/dist/web/assets/fonts.js +12 -0
- package/dist/web/assets/shell.js +114 -0
- package/dist/web/assets/styles/cards.js +135 -0
- package/dist/web/assets/styles/layout.js +47 -0
- package/dist/web/assets/styles/markdown.js +29 -0
- package/dist/web/assets/styles/responsive.js +39 -0
- package/dist/web/assets/styles/tokens.js +101 -0
- package/dist/web/assets/styles/widgets.js +147 -0
- package/dist/web/tmuxWebTerminal.js +158 -0
- package/dist/web/webServer.js +463 -0
- package/dist/web/webSnapshot.js +148 -0
- package/dist/workItem/workItem.js +642 -23
- package/dist/workspace/gitChangeSetCapture.js +86 -0
- package/dist/workspace/workItemChangeSetManager.js +445 -0
- package/dist/worktree/managedWorkspace.js +202 -0
- package/docs/task-local-identity.md +62 -0
- package/i18n/README.zh-CN.md +406 -31
- package/package.json +10 -2
- package/skills/yui-leader/SKILL.md +601 -39
- package/skills/yui-operator/SKILL.md +255 -34
- package/skills/yui-reviewer/SKILL.md +57 -0
- package/skills/yui-worker/SKILL.md +214 -17
- package/dist/commands/repositoryCommands.js +0 -86
- package/dist/operator/operatorContext.js +0 -66
- package/dist/repository/repository.js +0 -55
- package/dist/scheduler/archivedTaskRuntime.js +0 -12
- package/dist/worktree/roleWorkspace.js +0 -62
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { usageError } from "../errors/cliError.js";
|
|
2
|
+
import { GitIntegrationService } from "../integration/gitIntegrationService.js";
|
|
3
|
+
import { createIntegrationAttempt } from "../integration/integrationAttempt.js";
|
|
4
|
+
import { NodeGitWorkspace } from "../repository/gitWorkspace.js";
|
|
5
|
+
import { workspaceProjectEntry } from "../worktree/managedWorkspace.js";
|
|
6
|
+
/**
|
|
7
|
+
* Reconcile configured remote baselines before a Task completion attempt.
|
|
8
|
+
*
|
|
9
|
+
* Remote resolution and fetches happen from the Task's managed worktree. A
|
|
10
|
+
* moved remote is represented by a new Integration Attempt that reuses the
|
|
11
|
+
* already integrated ChangeSets, runs the existing Project checks, and lets
|
|
12
|
+
* the normal target CAS advance the Task branch. Stable Project checkouts
|
|
13
|
+
* are never refreshed or otherwise mutated here.
|
|
14
|
+
*/
|
|
15
|
+
export async function reconcileTaskRemoteBaselines(taskId, store, home, options = {}) {
|
|
16
|
+
const task = store.getTask(taskId);
|
|
17
|
+
if (task === null)
|
|
18
|
+
throw usageError(`Task not found: ${taskId}.`);
|
|
19
|
+
// The delivery contract opts Project-backed Tasks into committed
|
|
20
|
+
// Integration evidence. Metadata-only Tasks retain their existing local
|
|
21
|
+
// completion semantics and have no remote baseline to reconcile here.
|
|
22
|
+
if (task.projectBindings.length === 0 || task.requireIntegration !== true)
|
|
23
|
+
return [];
|
|
24
|
+
const workspace = requireTaskWorkspace(store, task);
|
|
25
|
+
const git = options.git ?? new NodeGitWorkspace();
|
|
26
|
+
if (git.fetchRemoteHeadIntoWorktree === undefined
|
|
27
|
+
|| git.mergeRemoteIntoWorktree === undefined) {
|
|
28
|
+
throw usageError(`Task ${task.id} cannot verify remote baselines: managed Git workspace support is unavailable.`);
|
|
29
|
+
}
|
|
30
|
+
const plans = [];
|
|
31
|
+
for (const binding of task.projectBindings) {
|
|
32
|
+
const project = store.getProject(binding.projectId);
|
|
33
|
+
if (project === null) {
|
|
34
|
+
throw usageError(`Project not found for Task ${task.id}: ${binding.projectId}.`);
|
|
35
|
+
}
|
|
36
|
+
if (project.remoteUrl === undefined)
|
|
37
|
+
continue;
|
|
38
|
+
const entry = workspaceProjectEntry(workspace, project.id);
|
|
39
|
+
if (entry === undefined || entry.access !== "write") {
|
|
40
|
+
throw usageError(`Task ${task.id} has no writable managed main workspace for remote Project ${project.id}.`);
|
|
41
|
+
}
|
|
42
|
+
const currentCommit = (await git.inspect(entry.path, "HEAD")).baseCommit;
|
|
43
|
+
const previousIntegration = latestCommittedIntegration(store, task.id, project.id);
|
|
44
|
+
// Let the existing exact-head Task-final gate report local post-
|
|
45
|
+
// Integration drift before attempting any network operation. This keeps
|
|
46
|
+
// completion read-only for an already-invalid candidate and preserves its
|
|
47
|
+
// precise recovery guidance.
|
|
48
|
+
if (previousIntegration !== undefined
|
|
49
|
+
&& previousIntegration.candidateCommit !== currentCommit) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
const remote = await fetchRemote(git, entry, project);
|
|
53
|
+
if (remote.commit === currentCommit)
|
|
54
|
+
continue;
|
|
55
|
+
if (await git.isAncestor(entry.path, remote.commit, currentCommit))
|
|
56
|
+
continue;
|
|
57
|
+
if (previousIntegration === undefined) {
|
|
58
|
+
throw usageError(`Project ${project.id} remote target moved to ${remote.commit}, but no committed `
|
|
59
|
+
+ "Integration can establish a safe Task baseline.");
|
|
60
|
+
}
|
|
61
|
+
if (previousIntegration.candidateCommit !== currentCommit) {
|
|
62
|
+
throw usageError(`Project ${project.id} Task head ${currentCommit} does not match its latest committed `
|
|
63
|
+
+ `Integration ${previousIntegration.id}; settle that drift before remote reconciliation.`);
|
|
64
|
+
}
|
|
65
|
+
if (!await git.isClean(entry.path)) {
|
|
66
|
+
throw usageError(`Project ${project.id} managed Task workspace is dirty; commit or clean it before remote reconciliation.`);
|
|
67
|
+
}
|
|
68
|
+
plans.push({ project, entry, remote, currentCommit, previousIntegration });
|
|
69
|
+
}
|
|
70
|
+
const reconciled = [];
|
|
71
|
+
for (const plan of plans) {
|
|
72
|
+
const attempt = store.transaction((tx) => {
|
|
73
|
+
const created = createIntegrationAttempt({
|
|
74
|
+
id: tx.nextIntegrationAttemptId(task.id),
|
|
75
|
+
taskId: task.id,
|
|
76
|
+
projectId: plan.project.id,
|
|
77
|
+
targetRef: plan.entry.branch,
|
|
78
|
+
expectedHead: plan.currentCommit,
|
|
79
|
+
changeSetIds: plan.previousIntegration.changeSetIds,
|
|
80
|
+
checkCommands: plan.previousIntegration.checkCommands
|
|
81
|
+
}, options.now?.() ?? new Date());
|
|
82
|
+
tx.saveIntegrationAttempt(task.id, created);
|
|
83
|
+
return created;
|
|
84
|
+
});
|
|
85
|
+
const baseline = {
|
|
86
|
+
remoteUrl: plan.project.remoteUrl,
|
|
87
|
+
branch: plan.remote.branch
|
|
88
|
+
};
|
|
89
|
+
const result = await new GitIntegrationService(home, store, git, options.now ?? (() => new Date()), options.environment).integrate(task.id, attempt.id, { remoteBaseline: baseline });
|
|
90
|
+
if (result.status !== "committed" || result.attempt.candidateCommit === undefined) {
|
|
91
|
+
const detail = result.attempt.checks?.find(({ outcome }) => outcome === "failed")?.details
|
|
92
|
+
?? result.attempt.conflict?.summary
|
|
93
|
+
?? result.attempt.status;
|
|
94
|
+
throw usageError(`Remote baseline reconciliation failed for ${task.id}/${plan.project.id}: ${detail}`);
|
|
95
|
+
}
|
|
96
|
+
reconciled.push({
|
|
97
|
+
projectId: plan.project.id,
|
|
98
|
+
remote: plan.remote,
|
|
99
|
+
fromCommit: plan.currentCommit,
|
|
100
|
+
toCommit: result.attempt.candidateCommit,
|
|
101
|
+
integrationId: attempt.id
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
return reconciled;
|
|
105
|
+
}
|
|
106
|
+
async function fetchRemote(git, entry, project) {
|
|
107
|
+
try {
|
|
108
|
+
return await git.fetchRemoteHeadIntoWorktree({
|
|
109
|
+
repositoryPath: entry.path,
|
|
110
|
+
remoteUrl: project.remoteUrl,
|
|
111
|
+
branch: project.developmentBranch
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
throw usageError(`Project ${project.id} remote target could not be resolved; completion is fail-closed: `
|
|
116
|
+
+ `${error instanceof Error ? error.message : String(error)}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function requireTaskWorkspace(store, task) {
|
|
120
|
+
const workspace = store.getTaskWorkspace(task.id);
|
|
121
|
+
if (workspace === null || workspace.owner.type !== "task") {
|
|
122
|
+
throw usageError(`Task ${task.id} has no authoritative managed main workspace.`);
|
|
123
|
+
}
|
|
124
|
+
return workspace;
|
|
125
|
+
}
|
|
126
|
+
function latestCommittedIntegration(store, taskId, projectId) {
|
|
127
|
+
return store.listIntegrationAttempts(taskId)
|
|
128
|
+
.filter((attempt) => attempt.projectId === projectId && attempt.status === "committed")
|
|
129
|
+
.sort((left, right) => left.id.localeCompare(right.id, undefined, { numeric: true }))
|
|
130
|
+
.at(-1);
|
|
131
|
+
}
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
import { taskNotFound, usageError } from "../errors/cliError.js";
|
|
2
2
|
import { taskMessageAuthorLabel } from "../message/message.js";
|
|
3
|
+
import { formatTimestamp } from "../output/timePresentation.js";
|
|
4
|
+
import { isRoleRunStalled, latestStallProgressAt } from "../scheduler/roleRunStall.js";
|
|
5
|
+
import { buildTaskExecutionProjection } from "../scheduler/taskExecutionProjection.js";
|
|
6
|
+
import { inspectTaskRoleSessionRecovery } from "./taskRoleRuntimeStatus.js";
|
|
7
|
+
import { summarizeExecutionGroup } from "../execution/executionGroup.js";
|
|
8
|
+
import { currentWorkItemExecutionGroup } from "../workItem/workItem.js";
|
|
3
9
|
const RECENT_RECORD_LIMIT = 5;
|
|
4
10
|
const RELATED_RECORD_LIMIT = 5;
|
|
5
11
|
const SUMMARY_TEXT_LIMIT = 400;
|
|
6
12
|
const TERMINAL_WORK_ITEM_STATUSES = new Set([
|
|
7
13
|
"completed",
|
|
8
14
|
"failed",
|
|
9
|
-
"
|
|
10
|
-
"superseded"
|
|
15
|
+
"retired"
|
|
11
16
|
]);
|
|
12
17
|
export function runTaskContextCommand(args, store) {
|
|
13
18
|
if (args.length !== 1 || args[0]?.trim().length === 0) {
|
|
@@ -19,29 +24,45 @@ export function runTaskContextCommand(args, store) {
|
|
|
19
24
|
if (task === null)
|
|
20
25
|
throw taskNotFound(taskId);
|
|
21
26
|
const workItems = reader.listWorkItems(task.id);
|
|
22
|
-
const workItemIds = new Set(workItems.map((item) => item.id));
|
|
23
27
|
const inputRequests = reader.listInputRequests(task.id);
|
|
28
|
+
const roles = reader.listRoles(task.id);
|
|
29
|
+
const execution = buildTaskExecutionProjection(reader, task.id, task);
|
|
30
|
+
if (execution === null) {
|
|
31
|
+
throw new Error(`Task execution projection disappeared: ${task.id}.`);
|
|
32
|
+
}
|
|
33
|
+
const roleSessionSets = reader.listRoleSessionSets(task.id);
|
|
24
34
|
return {
|
|
25
35
|
task,
|
|
36
|
+
execution,
|
|
37
|
+
reviewConfig: reader.getReviewConfig(),
|
|
26
38
|
brief: reader.getTaskBrief(task.id),
|
|
27
39
|
activeDecisions: reader.listDecisions(task.id)
|
|
28
40
|
.filter((decision) => decision.status === "active"),
|
|
29
41
|
milestones: reader.listMilestones(task.id),
|
|
30
|
-
roles
|
|
42
|
+
roles,
|
|
43
|
+
managedWorkspaces: reader.listManagedWorkspaces(task.id),
|
|
44
|
+
roleSessionSets,
|
|
45
|
+
roleSessionRecoveries: roles.map((role) => (inspectTaskRoleSessionRecovery(task.id, role.name, reader))),
|
|
31
46
|
workItems,
|
|
32
|
-
|
|
33
|
-
|
|
47
|
+
agentRuns: chronological(reader.listAgentRuns(task.id)),
|
|
48
|
+
reviewRounds: chronological(reader.listReviewRounds(task.id)),
|
|
49
|
+
changeSets: chronological(reader.listChangeSets(task.id)),
|
|
50
|
+
integrations: chronological(reader.listIntegrationAttempts(task.id)),
|
|
34
51
|
messages: reader.listMessages(task.id),
|
|
35
52
|
openInputRequests: inputRequests.filter((request) => request.status === "open"),
|
|
36
53
|
resolvedInputRequests: inputRequests.filter((request) => request.status !== "open"),
|
|
37
54
|
events: reader.listEvents(task.id)
|
|
38
55
|
};
|
|
39
56
|
});
|
|
40
|
-
const { task, brief, activeDecisions, milestones, roles, workItems,
|
|
57
|
+
const { task, execution, reviewConfig, brief, activeDecisions, milestones, roles, managedWorkspaces, roleSessionSets, roleSessionRecoveries, workItems, agentRuns, reviewRounds, changeSets, integrations, messages, openInputRequests, resolvedInputRequests, events } = data;
|
|
58
|
+
const timeZone = store.getConfig().timeZone;
|
|
41
59
|
const displayedActiveDecisions = activeDecisions.slice(-RECENT_RECORD_LIMIT);
|
|
42
60
|
const displayedWorkItems = currentAndRecentWorkItems(workItems);
|
|
43
61
|
const displayedOpenInputRequests = openInputRequests.slice(-RECENT_RECORD_LIMIT);
|
|
44
62
|
const displayedResolvedInputRequests = resolvedInputRequests.slice(-RECENT_RECORD_LIMIT);
|
|
63
|
+
const displayedExecutionCarriers = execution.monitoring === "active"
|
|
64
|
+
? execution.activeRuns
|
|
65
|
+
: [];
|
|
45
66
|
const lines = [
|
|
46
67
|
`Task context: ${task.id}`,
|
|
47
68
|
`Title: ${compactText(task.title)}`,
|
|
@@ -49,12 +70,41 @@ export function runTaskContextCommand(args, store) {
|
|
|
49
70
|
...(task.description === undefined ? [] : [`Description: ${compactText(task.description)}`]),
|
|
50
71
|
...(task.priority === undefined ? [] : [`Priority: ${task.priority}`]),
|
|
51
72
|
...(task.tags === undefined ? [] : [`Tags: ${task.tags.join(", ")}`]),
|
|
52
|
-
...(task.dueAt === undefined ? [] : [`Due: ${task.dueAt}`]),
|
|
73
|
+
...(task.dueAt === undefined ? [] : [`Due: ${formatTimestamp(task.dueAt, timeZone)}`]),
|
|
53
74
|
...(task.completionSummary === undefined ? [] : [`Completion summary: ${task.completionSummary}`]),
|
|
75
|
+
...(task.retirementSummary === undefined ? [] : [`Retirement summary: ${task.retirementSummary}`]),
|
|
76
|
+
...(task.replacementTaskId === undefined ? [] : [`Replacement Task: ${task.replacementTaskId}`]),
|
|
54
77
|
...(task.archiveSummary === undefined ? [] : [`Archive summary: ${task.archiveSummary}`]),
|
|
55
|
-
|
|
56
|
-
|
|
78
|
+
"Execution:",
|
|
79
|
+
` Status: ${execution.status}`,
|
|
80
|
+
` Owner/action: ${execution.owner}/${execution.action}`,
|
|
81
|
+
` Monitoring: ${execution.monitoring}`,
|
|
82
|
+
` Fail-closed: ${execution.failClosed ? "yes" : "no"}`,
|
|
83
|
+
` Reason: ${execution.reason}`,
|
|
84
|
+
` Attention: ${execution.attention.length === 0
|
|
85
|
+
? "none"
|
|
86
|
+
: execution.attention.map(({ kind, owner }) => `${kind}/${owner}`).join(", ")}`,
|
|
87
|
+
` Active execution carriers (${displayedExecutionCarriers.length}):`,
|
|
88
|
+
...(displayedExecutionCarriers.length === 0
|
|
89
|
+
? [" None."]
|
|
90
|
+
: displayedExecutionCarriers.map((run) => (` ${run.roleName}: ${run.id} [${run.status}; ${run.delivered ? "accepted" : "delivery-pending"}]`))),
|
|
91
|
+
...(task.projectBindings.length === 0
|
|
92
|
+
? []
|
|
93
|
+
: [
|
|
94
|
+
"Projects:",
|
|
95
|
+
...task.projectBindings.map((binding) => (`- ${binding.directory}: ${binding.projectId} @ ${binding.baseRef}`))
|
|
96
|
+
]),
|
|
57
97
|
...(task.cwd === undefined ? [] : [`Workspace: ${task.cwd}`]),
|
|
98
|
+
`Managed Workspaces (${managedWorkspaces.length}):`,
|
|
99
|
+
...(managedWorkspaces.length === 0
|
|
100
|
+
? [" None."]
|
|
101
|
+
: managedWorkspaces.map((workspace) => (` ${managedWorkspaceLabel(workspace)}: ${workspace.root} (${workspace.entries.filter(({ access }) => access === "write").length} writable / ${workspace.entries.length} Projects)`))),
|
|
102
|
+
`Completion evidence: ${task.requireIntegration
|
|
103
|
+
? "WorkItem, ChangeSet, and committed Integration required"
|
|
104
|
+
: "delivery integration not required"}`,
|
|
105
|
+
`Global review: ${reviewConfig === null
|
|
106
|
+
? "disabled"
|
|
107
|
+
: `${reviewConfig.roleName} (${reviewConfig.trigger})`}`,
|
|
58
108
|
"",
|
|
59
109
|
"Brief:",
|
|
60
110
|
...(brief === null
|
|
@@ -65,9 +115,12 @@ export function runTaskContextCommand(args, store) {
|
|
|
65
115
|
...(brief.boundaries.length === 0
|
|
66
116
|
? [" None."]
|
|
67
117
|
: brief.boundaries.map((boundary) => ` - ${compactText(boundary)}`)),
|
|
118
|
+
` Technical approach: ${brief.technicalApproach.length === 0
|
|
119
|
+
? "Not defined."
|
|
120
|
+
: compactText(brief.technicalApproach)}`,
|
|
68
121
|
` Current focus: ${compactText(brief.currentFocus)}`,
|
|
69
122
|
` Leader summary: ${compactText(brief.leaderSummary)}`,
|
|
70
|
-
` Updated by ${brief.updatedBy} at ${brief.updatedAt}`
|
|
123
|
+
` Updated by ${brief.updatedBy} at ${formatTimestamp(brief.updatedAt, timeZone)}`
|
|
71
124
|
]),
|
|
72
125
|
"",
|
|
73
126
|
`Active decisions (${displayedActiveDecisions.length}${activeDecisions.length > displayedActiveDecisions.length ? ` of ${activeDecisions.length}` : ""}):`,
|
|
@@ -79,55 +132,133 @@ export function runTaskContextCommand(args, store) {
|
|
|
79
132
|
])),
|
|
80
133
|
"",
|
|
81
134
|
...recentSection("milestones", milestones, (milestone) => [
|
|
82
|
-
` ${milestone.id}: ${compactText(milestone.title)} (${milestone.createdAt})`,
|
|
135
|
+
` ${milestone.id}: ${compactText(milestone.title)} (${formatTimestamp(milestone.createdAt, timeZone)})`,
|
|
83
136
|
` ${compactText(milestone.summary)}`
|
|
84
137
|
]),
|
|
85
138
|
"",
|
|
86
|
-
`Roles (${roles.length}):`,
|
|
139
|
+
`Task Roles (${roles.length}):`,
|
|
87
140
|
...(roles.length === 0
|
|
88
141
|
? [" None."]
|
|
89
|
-
: roles.
|
|
142
|
+
: roles.flatMap((role) => {
|
|
143
|
+
const binding = role.agentBindings[role.activeAgentId];
|
|
144
|
+
const activeRun = agentRuns.find((run) => (run.roleName === role.name && run.status === "active"));
|
|
145
|
+
const sessions = roleSessionSets.find((set) => set.owner.roleName === role.name);
|
|
146
|
+
const activeSession = sessions?.sessions[sessions.activeAgentId];
|
|
147
|
+
const effective = activeRun?.effective ?? activeSession?.effective;
|
|
148
|
+
const effectiveSource = activeRun === undefined ? "Session" : "Run";
|
|
149
|
+
const recovery = roleSessionRecoveries.find((entry) => entry.roleName === role.name);
|
|
150
|
+
const creation = [...events].reverse().find((event) => (event.type === "role.added" && event.payload.role === role.name));
|
|
151
|
+
return [
|
|
152
|
+
` ${role.name} [${role.status}]: ${role.activeAgentId}/${binding.adapterId}`,
|
|
153
|
+
` Desired: r${role.launchRevision}; Profile intent: ${role.defaultAccess}; Model: ${binding.config.model ?? "default"}; effort: ${binding.config.effort ?? "default"}; permission: ${binding.config.permission.strategy}`,
|
|
154
|
+
` Effective: ${effective === undefined
|
|
155
|
+
? "not started"
|
|
156
|
+
: `${effectiveSource} ${effective.agentId}/${effective.adapterId}; r${effective.sourceDesiredRevision}; Profile intent: ${effective.profileAccess}; permission: ${effective.permission.strategy}`}`,
|
|
157
|
+
` Desired drift: ${effective === undefined
|
|
158
|
+
? "-"
|
|
159
|
+
: effective.sourceDesiredRevision === role.launchRevision
|
|
160
|
+
? "none"
|
|
161
|
+
: "pending next launch"}`,
|
|
162
|
+
...(creation?.payload.runtimeSource === undefined
|
|
163
|
+
? []
|
|
164
|
+
: [` Runtime source at creation: ${creation.payload.runtimeSource}`]),
|
|
165
|
+
...(recovery === undefined ? [] : [
|
|
166
|
+
` Runtime cleanup: ${recovery.runtimeCleanupPending ? "pending" : "none"}`,
|
|
167
|
+
` Fresh launch: ${recovery.freshLaunchAllowed ? "allowed" : "blocked"}`
|
|
168
|
+
])
|
|
169
|
+
];
|
|
170
|
+
})),
|
|
90
171
|
"",
|
|
91
172
|
`Current and recent work items (${displayedWorkItems.length}${workItems.length > displayedWorkItems.length ? ` of ${workItems.length}` : ""}):`,
|
|
92
173
|
...(displayedWorkItems.length === 0
|
|
93
174
|
? [" None."]
|
|
94
175
|
: displayedWorkItems.flatMap((item) => {
|
|
95
|
-
const itemRuns =
|
|
176
|
+
const itemRuns = agentRuns.filter((run) => run.workItemId === item.id);
|
|
96
177
|
const latestRun = itemRuns.at(-1);
|
|
97
178
|
return [
|
|
98
|
-
` ${item.id} [${item.status}]
|
|
99
|
-
|
|
179
|
+
` ${item.id} [${item.status}]: ${compactText(item.title)}`,
|
|
180
|
+
` Objective: ${compactText(item.objective)}`,
|
|
181
|
+
` Writable Projects: ${item.writeProjectIds.length === 0
|
|
182
|
+
? "none"
|
|
183
|
+
: item.writeProjectIds.join(", ")}`,
|
|
184
|
+
...(currentWorkItemExecutionGroup(item) === undefined
|
|
185
|
+
? []
|
|
186
|
+
: renderExecutionGroup(currentWorkItemExecutionGroup(item))),
|
|
187
|
+
...(item.acceptance.length === 0
|
|
188
|
+
? []
|
|
189
|
+
: [` Acceptance: ${item.acceptance.map(compactText).join("; ")}`]),
|
|
190
|
+
...(item.candidates.length === 0
|
|
100
191
|
? []
|
|
101
|
-
:
|
|
192
|
+
: item.candidates.flatMap((candidate) => [
|
|
193
|
+
` Candidate ${candidate.sequence}: ${candidate.id}${item.status === "awaiting_acceptance" && candidate === item.candidates.at(-1) ? " [current]" : ""} (${candidate.source.type === "run" ? candidate.source.runId : "direct"})`,
|
|
194
|
+
` Review policy: ${candidate.reviewPolicy === undefined ? "none" : `${candidate.reviewPolicy.roleName} (${candidate.reviewPolicy.trigger})`}`,
|
|
195
|
+
` Task-final contract: ${candidate.taskFinalReviewContract === undefined
|
|
196
|
+
? "none"
|
|
197
|
+
: `${candidate.taskFinalReviewContract.digest} via control ${candidate.taskFinalReviewContract.controlPlaneDigest}`}`,
|
|
198
|
+
` Frozen Git: ${candidate.gitSnapshot === undefined
|
|
199
|
+
? "unavailable"
|
|
200
|
+
: `${candidate.gitSnapshot.reviewBaseCommit} (${candidate.gitSnapshot.projects.length} Projects)`}`,
|
|
201
|
+
` Summary: ${compactText(candidate.summary)}`
|
|
202
|
+
])),
|
|
102
203
|
...(latestRun === undefined
|
|
103
|
-
? ["
|
|
204
|
+
? [" AgentRuns: none."]
|
|
104
205
|
: [
|
|
105
|
-
`
|
|
206
|
+
` AgentRuns: ${itemRuns.length}; latest ${latestRun.id} [${latestRun.status}] ${latestRun.effective.agentId}/${latestRun.effective.adapterId} · effective r${latestRun.effective.sourceDesiredRevision}/${latestRun.effective.profileAccess}/${latestRun.effective.permission.strategy}`,
|
|
106
207
|
` Input: ${compactText(latestRun.input)}`,
|
|
107
208
|
...(latestRun.summary === undefined
|
|
108
209
|
? []
|
|
109
210
|
: [` Summary: ${compactText(latestRun.summary)}`])
|
|
110
|
-
])
|
|
211
|
+
]),
|
|
212
|
+
...renderWorkItemReviews(reviewRounds.filter((round) => round.workItemId === item.id))
|
|
111
213
|
];
|
|
112
214
|
})),
|
|
113
215
|
"",
|
|
216
|
+
...recentSection("AgentRuns", agentRuns, (run) => [
|
|
217
|
+
` ${run.id} [${run.status}/${run.purpose}] ${run.roleName} via ${run.effective.agentId}/${run.effective.adapterId}`,
|
|
218
|
+
` 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"}`,
|
|
219
|
+
...(run.summary === undefined ? [] : [` Result: ${compactText(run.summary)}`])
|
|
220
|
+
]),
|
|
221
|
+
"",
|
|
222
|
+
"Runtime health:",
|
|
223
|
+
...(() => {
|
|
224
|
+
const stalled = agentRuns.filter((run) => (run.status === "active" && isRoleRunStalled(events, run.id)));
|
|
225
|
+
return stalled.length === 0
|
|
226
|
+
? [" No needs-attention Runs."]
|
|
227
|
+
: stalled.flatMap((run) => [
|
|
228
|
+
` ${run.id} [needs-attention] ${run.roleName}`,
|
|
229
|
+
` Durable progress: ${formatTimestamp(latestStallProgressAt(events, run.id) ?? run.updatedAt, timeZone)}`,
|
|
230
|
+
` Cause: ${latestStallKind(events, run.id)} with no new semantic Run evidence in the stall window`,
|
|
231
|
+
" Next: inspect Task context/Role status; no automatic retry or Session replacement was performed."
|
|
232
|
+
]);
|
|
233
|
+
})(),
|
|
234
|
+
"",
|
|
235
|
+
`ChangeSets (${changeSets.length}):`,
|
|
236
|
+
...(changeSets.length === 0
|
|
237
|
+
? [" None."]
|
|
238
|
+
: changeSets.slice(-RECENT_RECORD_LIMIT).map((changeSet) => (` ${changeSet.id} [${changeSet.projectId}]: ${changeSet.baseCommit.slice(0, 12)}..${changeSet.headCommit.slice(0, 12)} (${changeSet.changedPaths.length} paths; WorkItem ${changeSet.workItemId})`))),
|
|
239
|
+
"",
|
|
240
|
+
`Integration Attempts (${integrations.length}):`,
|
|
241
|
+
...(integrations.length === 0
|
|
242
|
+
? [" None."]
|
|
243
|
+
: integrations.slice(-RECENT_RECORD_LIMIT).map((integration) => (` ${integration.id} [${integration.status}/${integration.projectId}] — ${integration.targetRef}; ${integration.changeSetIds.join(", ")}`))),
|
|
244
|
+
"",
|
|
114
245
|
...recentSection("messages", messages, (message) => [
|
|
115
|
-
` ${message.id} [${taskMessageAuthorLabel(message.author)}] ${message.createdAt}`,
|
|
246
|
+
` ${message.id} [${taskMessageAuthorLabel(message.author)}] ${formatTimestamp(message.createdAt, timeZone)}`,
|
|
116
247
|
` ${compactText(message.body)}`
|
|
117
248
|
]),
|
|
118
249
|
"",
|
|
119
250
|
`Open input requests (${displayedOpenInputRequests.length}${openInputRequests.length > displayedOpenInputRequests.length ? ` of ${openInputRequests.length}` : ""}):`,
|
|
120
251
|
...(displayedOpenInputRequests.length === 0
|
|
121
252
|
? [" None."]
|
|
122
|
-
: displayedOpenInputRequests.flatMap(renderOpenInputRequest)),
|
|
253
|
+
: displayedOpenInputRequests.flatMap((request) => renderOpenInputRequest(request, timeZone))),
|
|
123
254
|
"",
|
|
124
255
|
`Recent resolved input requests (${displayedResolvedInputRequests.length}${resolvedInputRequests.length > displayedResolvedInputRequests.length ? ` of ${resolvedInputRequests.length}` : ""}):`,
|
|
125
256
|
...(displayedResolvedInputRequests.length === 0
|
|
126
257
|
? [" None."]
|
|
127
|
-
: displayedResolvedInputRequests.flatMap(renderResolvedInputRequest)),
|
|
258
|
+
: displayedResolvedInputRequests.flatMap((request) => renderResolvedInputRequest(request, timeZone))),
|
|
128
259
|
"",
|
|
129
260
|
...recentSection("events", events, (event) => [
|
|
130
|
-
` ${event.id} ${event.type} (${event.createdAt})`,
|
|
261
|
+
` ${event.id} ${event.type} (${formatTimestamp(event.createdAt, timeZone)})`,
|
|
131
262
|
...(Object.keys(event.payload).length === 0
|
|
132
263
|
? []
|
|
133
264
|
: [` ${Object.entries(event.payload)
|
|
@@ -141,7 +272,43 @@ export function runTaskContextCommand(args, store) {
|
|
|
141
272
|
data
|
|
142
273
|
};
|
|
143
274
|
}
|
|
144
|
-
function
|
|
275
|
+
function latestStallKind(events, runId) {
|
|
276
|
+
const event = [...events]
|
|
277
|
+
.filter((candidate) => candidate.type === "run.stalled" && candidate.payload.runId === runId)
|
|
278
|
+
.sort((left, right) => Date.parse(right.createdAt) - Date.parse(left.createdAt))[0];
|
|
279
|
+
return event?.payload.kind ?? "execution-stalled";
|
|
280
|
+
}
|
|
281
|
+
function renderWorkItemReviews(rounds) {
|
|
282
|
+
const latest = rounds.at(-1);
|
|
283
|
+
if (latest === undefined)
|
|
284
|
+
return [" ReviewRounds: none."];
|
|
285
|
+
return [
|
|
286
|
+
` ReviewRounds: ${rounds.length}; latest ${latest.id} [${latest.status}] ${latest.scope === "task" ? "Task-final" : "WorkItem"} for ${latest.candidateId} via ${latest.reviewerRoleName} (${latest.requestedBy})`,
|
|
287
|
+
` Review base: ${latest.reviewBaseCommit}`,
|
|
288
|
+
...(latest.scope === "task"
|
|
289
|
+
? [
|
|
290
|
+
` Frozen integrated Task heads: ${latest.taskCandidate?.projects
|
|
291
|
+
.map(({ projectId, commit }) => `${projectId}@${commit}`).join(", ") ?? "unavailable"}`,
|
|
292
|
+
` Task-final contract: ${latest.taskFinalReviewContract?.digest ?? "global policy"}`
|
|
293
|
+
]
|
|
294
|
+
: []),
|
|
295
|
+
` Review workspace: ${latest.workspace === undefined
|
|
296
|
+
? "not prepared"
|
|
297
|
+
: `${latest.workspace.root} (${latest.workspace.entries.length} writable Projects)`}`,
|
|
298
|
+
` Workspace disposition: ${latest.workspaceDisposition?.kind ?? "pending"}`,
|
|
299
|
+
` Diagnostic evidence: ${latest.evidenceCommit ?? "none"}`,
|
|
300
|
+
` Checks: ${latest.checks === undefined || latest.checks.length === 0
|
|
301
|
+
? "none"
|
|
302
|
+
: latest.checks.map(({ name, outcome }) => `${name}=${outcome}`).join(", ")}`,
|
|
303
|
+
...(latest.summary === undefined
|
|
304
|
+
? []
|
|
305
|
+
: [` Review summary: ${compactText(latest.summary)}`]),
|
|
306
|
+
...(latest.executionGroup === undefined
|
|
307
|
+
? []
|
|
308
|
+
: renderExecutionGroup(latest.executionGroup).map((line) => ` ${line.trimStart()}`))
|
|
309
|
+
];
|
|
310
|
+
}
|
|
311
|
+
function renderResolvedInputRequest(request, timeZone) {
|
|
145
312
|
if (request.status === "open")
|
|
146
313
|
return [];
|
|
147
314
|
return [
|
|
@@ -150,15 +317,15 @@ function renderResolvedInputRequest(request) {
|
|
|
150
317
|
...(request.status === "answered"
|
|
151
318
|
? [
|
|
152
319
|
` Answer: ${compactText(request.resolution.answer.text)}`,
|
|
153
|
-
` Answered by ${request.resolution.answeredBy} at ${request.resolution.answeredAt}`
|
|
320
|
+
` Answered by ${request.resolution.answeredBy} at ${formatTimestamp(request.resolution.answeredAt, timeZone)}`
|
|
154
321
|
]
|
|
155
322
|
: [
|
|
156
323
|
` Cancelled: ${compactText(request.cancellation.reason)}`,
|
|
157
|
-
` Cancelled at: ${request.cancellation.cancelledAt}`
|
|
324
|
+
` Cancelled at: ${formatTimestamp(request.cancellation.cancelledAt, timeZone)}`
|
|
158
325
|
])
|
|
159
326
|
];
|
|
160
327
|
}
|
|
161
|
-
function renderOpenInputRequest(request) {
|
|
328
|
+
function renderOpenInputRequest(request, timeZone) {
|
|
162
329
|
const choices = request.choices.slice(0, RELATED_RECORD_LIMIT);
|
|
163
330
|
const blockedRefs = request.blockedRefs.slice(0, RELATED_RECORD_LIMIT);
|
|
164
331
|
const recommendedChoiceKey = request.policy.kind === "recommended"
|
|
@@ -179,7 +346,7 @@ function renderOpenInputRequest(request) {
|
|
|
179
346
|
...(request.policy.kind === "recommended"
|
|
180
347
|
? [
|
|
181
348
|
` Recommended choice: ${request.policy.recommendedChoiceKey}: ${compactText(recommendedChoice?.label ?? request.policy.recommendedChoiceKey)}`,
|
|
182
|
-
` Timeout at: ${request.policy.timeoutAt}`
|
|
349
|
+
` Timeout at: ${formatTimestamp(request.policy.timeoutAt, timeZone)}`
|
|
183
350
|
]
|
|
184
351
|
: []),
|
|
185
352
|
...(request.blockedRefs.length === 0
|
|
@@ -207,9 +374,56 @@ function currentAndRecentWorkItems(records) {
|
|
|
207
374
|
const selected = new Set([...current, ...recentTerminal]);
|
|
208
375
|
return records.filter((record) => selected.has(record));
|
|
209
376
|
}
|
|
377
|
+
function chronological(records) {
|
|
378
|
+
return [...records].sort((left, right) => (Date.parse(left.createdAt) - Date.parse(right.createdAt)
|
|
379
|
+
|| left.id.localeCompare(right.id)));
|
|
380
|
+
}
|
|
210
381
|
function compactText(value) {
|
|
211
382
|
const oneLine = value.replace(/\s+/g, " ").trim();
|
|
212
383
|
return oneLine.length <= SUMMARY_TEXT_LIMIT
|
|
213
384
|
? oneLine
|
|
214
385
|
: `${oneLine.slice(0, SUMMARY_TEXT_LIMIT - 3)}...`;
|
|
215
386
|
}
|
|
387
|
+
function managedWorkspaceLabel(workspace) {
|
|
388
|
+
switch (workspace.owner.type) {
|
|
389
|
+
case "task":
|
|
390
|
+
return "task";
|
|
391
|
+
case "work-item":
|
|
392
|
+
return `work-item ${workspace.owner.workItemId}`;
|
|
393
|
+
case "review-round":
|
|
394
|
+
return `review-round ${workspace.owner.reviewRoundId}`;
|
|
395
|
+
case "integration-attempt":
|
|
396
|
+
return `integration-attempt ${workspace.owner.integrationAttemptId}`;
|
|
397
|
+
case "execution-lane":
|
|
398
|
+
return `execution-lane ${workspace.owner.executionGroupId}/${workspace.owner.executionLaneId}`;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
function renderExecutionGroup(group) {
|
|
402
|
+
const summary = summarizeExecutionGroup(group);
|
|
403
|
+
return [
|
|
404
|
+
` Execution Group ${summary.groupId} [${summary.purpose}/${summary.strategy.mode}]: ${summary.activeLaneCount} active / ${summary.terminalLaneCount} terminal; ${summary.failedLaneCount} failed`,
|
|
405
|
+
...summary.laneSummaries.flatMap((lane) => [
|
|
406
|
+
` Lane ${lane.laneId} (#${lane.ordinal}, ${lane.roleName}) [${lane.status}]${lane.summary === undefined ? "" : `: ${compactText(lane.summary)}`}`,
|
|
407
|
+
...(lane.report === undefined ? [] : [` Report: ${compactText(lane.report)}`]),
|
|
408
|
+
...(lane.checks === undefined || lane.checks.length === 0
|
|
409
|
+
? []
|
|
410
|
+
: [` Checks: ${lane.checks.map(({ name, outcome }) => `${name}:${outcome}`).join(", ")}`]),
|
|
411
|
+
...(lane.findings === undefined || lane.findings.length === 0
|
|
412
|
+
? []
|
|
413
|
+
: [` Findings: ${lane.findings.map(({ id, severity, status }) => `${id}:${severity}/${status}`).join(", ")}`]),
|
|
414
|
+
...(lane.evidence === undefined || lane.evidence.length === 0
|
|
415
|
+
? []
|
|
416
|
+
: [` Evidence: ${lane.evidence.length} item(s)`]),
|
|
417
|
+
...(lane.evidenceCommit === undefined
|
|
418
|
+
? []
|
|
419
|
+
: [` Evidence commit: ${lane.evidenceCommit}`]),
|
|
420
|
+
...(lane.decision === undefined ? [] : [` Decision: ${lane.decision}`])
|
|
421
|
+
]),
|
|
422
|
+
...(summary.openHighPriorityFindingIds.length === 0
|
|
423
|
+
? []
|
|
424
|
+
: [` Open high findings: ${summary.openHighPriorityFindingIds.join(", ")}`]),
|
|
425
|
+
...(summary.resolution === undefined
|
|
426
|
+
? []
|
|
427
|
+
: [` Resolution: ${summary.resolution.decision} — ${compactText(summary.resolution.summary)}`])
|
|
428
|
+
];
|
|
429
|
+
}
|