@zq-silk/yui 0.8.3 → 0.8.6
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 +40 -22
- package/README.md +46 -16
- package/dist/cli/commandCatalog.js +23 -11
- package/dist/cli/operatorWizard.js +10 -20
- package/dist/cli.js +154 -16
- package/dist/commands/executionAuditCommands.js +30 -0
- package/dist/commands/operatorCommands.js +42 -1
- package/dist/commands/taskCommands.js +386 -138
- package/dist/commands/taskCompletionGate.js +36 -24
- package/dist/commands/taskContextCommand.js +6 -1
- package/dist/commands/taskInputCommands.js +48 -10
- package/dist/commands/taskNextActionCommand.js +36 -3
- package/dist/context/sessionBootstrapManifest.js +82 -1
- package/dist/controller/clientRuntime.js +7 -7
- package/dist/controller/controller.js +16 -8
- package/dist/controller/fileSchedulerStoreAdapter.js +64 -5
- package/dist/controller/handoverCandidate.js +10 -3
- package/dist/controller/sessionNotify.js +4 -22
- package/dist/executor/agentAdapter.js +2 -2
- package/dist/executor/agentExecutor.js +25 -5
- package/dist/executor/fileRoleLaunchPlanner.js +16 -11
- package/dist/integration/gitIntegrationService.js +50 -2
- package/dist/integration/integrationCheckEvidenceReuse.js +53 -0
- package/dist/observability/executionAudit.js +47 -1
- package/dist/observability/faultClassification.js +6 -4
- package/dist/observability/orchestrationMetrics.js +196 -0
- package/dist/operator/operatorSessionHistory.js +36 -0
- package/dist/release/releaseHandover.js +7 -5
- package/dist/release/runtimeRelease.js +15 -0
- package/dist/repository/taskWorkspaceCoordinator.js +13 -10
- package/dist/review/deltaRecheck.js +3 -2
- package/dist/review/reviewFindingLedger.js +5 -4
- package/dist/review/reviewOutcomeClassifier.js +252 -54
- package/dist/review/taskFinalReviewContractEvent.js +1 -0
- package/dist/review/taskFinalReviewContractRebind.js +350 -0
- package/dist/run/runIdentity.js +10 -70
- package/dist/runtime/agentHost.js +3 -4
- package/dist/runtime/codexAppServerRuntime.js +6 -0
- package/dist/runtime/firstProgressStopLoss.js +52 -0
- package/dist/runtime/launchBroker.js +10 -2
- package/dist/runtime/runtimeDeadlines.js +14 -0
- package/dist/runtime/sessionTitle.js +24 -12
- package/dist/runtime/structuredProviderHost.js +7 -1
- package/dist/runtime/tmuxAdapters.js +10 -3
- package/dist/scheduler/activeRoleRunDelivery.js +20 -18
- package/dist/scheduler/leaderWakeupProcessor.js +33 -2
- package/dist/scheduler/wakeReason.js +1 -0
- package/dist/storage/sqliteStore.js +8 -1
- package/dist/storage/taskStore.js +10 -1
- package/dist/task/completionReadiness.js +48 -19
- package/dist/task/deliveryGuard.js +3 -1
- package/dist/task/nextAction.js +145 -52
- package/dist/task/repairWave.js +14 -1
- package/dist/task/task.js +10 -0
- package/dist/web/webSnapshot.js +7 -1
- package/i18n/README.zh-CN.md +28 -8
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +73 -31
- package/skills/yui-operator/SKILL.md +51 -10
- package/skills/yui-reviewer/SKILL.md +23 -0
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { readFileSync } from "node:fs";
|
|
3
|
-
import { resolve } from "node:path";
|
|
3
|
+
import { join, resolve } from "node:path";
|
|
4
4
|
import { createInterface } from "node:readline/promises";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { isDeepStrictEqual } from "node:util";
|
|
@@ -36,8 +36,9 @@ import { runResourcesCommand } from "./commands/resourcesCommands.js";
|
|
|
36
36
|
import { applyOperatorSessionControl, runOperatorCommand } from "./commands/operatorCommands.js";
|
|
37
37
|
import { runProjectCommand } from "./commands/projectCommands.js";
|
|
38
38
|
import { runProfileCommand } from "./commands/profileCommands.js";
|
|
39
|
-
import { dispatchPreparedReviewRound, failPendingReviewRound, RESUMED_PENDING_FINAL_REVIEW, TERMINALIZED_LEADER_BEFORE_FINAL_REVIEW, TaskFinalReviewDispatchDriftError, preserveReviewRoundWorkspace, parseTaskCompletionRequest, preflightTaskCompletion, runTaskCommand, normalizedExecutionLanePlan, validateTaskArchiveRequest } from "./commands/taskCommands.js";
|
|
39
|
+
import { dispatchPreparedReviewRound, failPendingReviewRound, RESUMED_PENDING_FINAL_REVIEW, TERMINALIZED_LEADER_BEFORE_FINAL_REVIEW, TaskFinalReviewDispatchDriftError, preserveReviewRoundWorkspace, parseTaskCompletionRequest, parseTaskFinalReviewContractRebindRequest, preflightTaskCompletion, runTaskCommand, normalizedExecutionLanePlan, validateTaskArchiveRequest } from "./commands/taskCommands.js";
|
|
40
40
|
import { taskActor } from "./commands/taskActor.js";
|
|
41
|
+
import { isCurrentGlobalOperator } from "./commands/taskInputCommands.js";
|
|
41
42
|
import { runTaskIntegrationCommand } from "./commands/taskIntegrationCommands.js";
|
|
42
43
|
import { runTaskChangeSetCommand } from "./commands/taskChangeSetCommands.js";
|
|
43
44
|
import { runTaskOverlapCommand } from "./commands/taskOverlapCommands.js";
|
|
@@ -46,7 +47,7 @@ import { runTaskWorkspaceCommand } from "./commands/taskWorkspaceCommands.js";
|
|
|
46
47
|
import { runWorkflowCommandAsync } from "./commands/workflowCommands.js";
|
|
47
48
|
import { createUpdatePorts } from "./cli/updatePorts.js";
|
|
48
49
|
import { createReleaseWorkflowPorts } from "./release/releaseWorkflowPorts.js";
|
|
49
|
-
import { readRuntimeIdentity } from "./release/runtimeRelease.js";
|
|
50
|
+
import { acquireHandoverLock, readRuntimeIdentity } from "./release/runtimeRelease.js";
|
|
50
51
|
import { renderReleaseActivateResult, renderReleaseInstallResult, renderReleaseList, runReleaseActivate, runReleaseInstall, runReleaseList } from "./commands/releaseCommands.js";
|
|
51
52
|
import { reconcileTaskRemoteBaselines, verifyTaskCompletionPublishedTree } from "./commands/taskCompletionGate.js";
|
|
52
53
|
import { runTaskBaseStatusCommand } from "./commands/taskBaseCommands.js";
|
|
@@ -81,8 +82,10 @@ import { TmuxWebTerminalService } from "./web/tmuxWebTerminal.js";
|
|
|
81
82
|
import { listOperatorSessions, operatorSessionRef } from "./operator/operatorSessionHistory.js";
|
|
82
83
|
import { YUI_VERSION, yuiVersionIdentity } from "./version.js";
|
|
83
84
|
import { YUI_CONTROL_PLANE_DESCRIPTOR, YUI_TASK_RUNTIME_DESCRIPTOR, assertExactControlPlanePreflight, assertExactTaskRuntimeEnvironment, assertExactTaskRuntimeState, exactControlPlaneDigest, extractExactControlArgument, parseExactControlPlaneDescriptor } from "./runtime/exactControlPlane.js";
|
|
85
|
+
import { readSessionBootstrapManifest } from "./context/sessionBootstrapManifest.js";
|
|
84
86
|
import { builtinAgentDriverRegistry } from "./runtime/builtinAgentDrivers.js";
|
|
85
87
|
import { createTaskFinalReviewContract, extractTaskFinalReviewRequest } from "./review/taskFinalReviewContract.js";
|
|
88
|
+
import { prepareTaskFinalReviewContractRebindProof, resolveRecordedTaskFinalReviewContract } from "./review/taskFinalReviewContractRebind.js";
|
|
86
89
|
import { assessDeltaRecheck } from "./review/deltaRecheck.js";
|
|
87
90
|
import { deltaRecheckEnabled } from "./review/reviewConfig.js";
|
|
88
91
|
import { NodeGitWorkspace } from "./repository/gitWorkspace.js";
|
|
@@ -109,7 +112,7 @@ void main().catch((error) => {
|
|
|
109
112
|
process.exitCode = 5;
|
|
110
113
|
});
|
|
111
114
|
export async function main() {
|
|
112
|
-
const { contract: taskFinalReviewContract, verifiedStore } = await preflightManagedTaskControlPlane();
|
|
115
|
+
const { contract: taskFinalReviewContract, verifiedStore, controlPlane: exactCurrentControlPlane } = await preflightManagedTaskControlPlane();
|
|
113
116
|
if (args.length === 0) {
|
|
114
117
|
emit(renderCommandHelp((await import("./cli/commandCatalog.js")).ROOT_COMMAND, VERSION));
|
|
115
118
|
return;
|
|
@@ -988,6 +991,59 @@ export async function main() {
|
|
|
988
991
|
}
|
|
989
992
|
}
|
|
990
993
|
}
|
|
994
|
+
let taskFinalReviewRebindProof;
|
|
995
|
+
let taskFinalReviewRebindRequest;
|
|
996
|
+
let releaseTaskFinalReviewHandoverLock;
|
|
997
|
+
if (resolved[1] === "review" && resolved[2] === "rebind") {
|
|
998
|
+
if (!isCurrentGlobalOperator(store, process.env)) {
|
|
999
|
+
throw usageError("Task-final Review contract rebind requires the authenticated global Operator session.");
|
|
1000
|
+
}
|
|
1001
|
+
if (exactCurrentControlPlane === undefined) {
|
|
1002
|
+
throw usageError("Task-final Review contract rebind requires the exact current global Session CLI.");
|
|
1003
|
+
}
|
|
1004
|
+
taskFinalReviewRebindRequest = parseTaskFinalReviewContractRebindRequest(resolved.slice(3));
|
|
1005
|
+
}
|
|
1006
|
+
if ((resolved[1] === "review"
|
|
1007
|
+
&& ["request", "force-fresh", "retry", "rebind"].includes(resolved[2] ?? ""))
|
|
1008
|
+
|| resolved[1] === "complete") {
|
|
1009
|
+
const handoverLock = acquireHandoverLock(home);
|
|
1010
|
+
releaseTaskFinalReviewHandoverLock = handoverLock.release;
|
|
1011
|
+
}
|
|
1012
|
+
if (taskFinalReviewRebindRequest !== undefined) {
|
|
1013
|
+
const request = taskFinalReviewRebindRequest;
|
|
1014
|
+
try {
|
|
1015
|
+
taskFinalReviewRebindProof = prepareTaskFinalReviewContractRebindProof({
|
|
1016
|
+
home,
|
|
1017
|
+
taskId: request.taskId,
|
|
1018
|
+
fromControlPlaneDigest: request.fromControlPlaneDigest,
|
|
1019
|
+
toControlPlaneDigest: request.toControlPlaneDigest,
|
|
1020
|
+
fromReleaseId: request.fromReleaseId,
|
|
1021
|
+
toReleaseId: request.toReleaseId,
|
|
1022
|
+
currentControlPlane: exactCurrentControlPlane.descriptor
|
|
1023
|
+
});
|
|
1024
|
+
const workItems = store.listWorkItems(request.taskId);
|
|
1025
|
+
const reviewRounds = store.listReviewRounds(request.taskId);
|
|
1026
|
+
const resolution = resolveRecordedTaskFinalReviewContract(request.taskId, workItems, reviewRounds, store.listEvents(request.taskId));
|
|
1027
|
+
const activeRound = reviewRounds.find((round) => ((round.scope ?? "work-item") === "task"
|
|
1028
|
+
&& (round.status === "pending" || round.status === "running")));
|
|
1029
|
+
// An exact replay is a true no-op, even when the target Leader is live.
|
|
1030
|
+
// Invalid/stale source tuples also reach the command unchanged so its
|
|
1031
|
+
// transactional diagnosis cannot stop a healthy target runtime.
|
|
1032
|
+
if (resolution?.effective.controlPlaneDigest === request.fromControlPlaneDigest
|
|
1033
|
+
&& activeRound === undefined) {
|
|
1034
|
+
// The contract event and wake must never target a Provider
|
|
1035
|
+
// Conversation launched by the source release. Active Runs fail
|
|
1036
|
+
// closed; otherwise stop and retire that runtime under the handover
|
|
1037
|
+
// lock before the transactional event+wake commit.
|
|
1038
|
+
await workspaceCoordinator.cleanupTaskRoleRuntime(request.taskId, "leader");
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
catch (error) {
|
|
1042
|
+
releaseTaskFinalReviewHandoverLock();
|
|
1043
|
+
releaseTaskFinalReviewHandoverLock = undefined;
|
|
1044
|
+
throw error;
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
991
1047
|
let candidateMaterialization;
|
|
992
1048
|
let candidateMaterializationCommitted = false;
|
|
993
1049
|
try {
|
|
@@ -1002,7 +1058,7 @@ export async function main() {
|
|
|
1002
1058
|
? await candidateSnapshotForTaskCommand(resolved, store, workspacePreparer, process.env, taskFinalReviewContract)
|
|
1003
1059
|
: candidateMaterialization.snapshot;
|
|
1004
1060
|
const directTaskMainSnapshot = await directTaskMainSnapshotForTaskCommand(resolved, store, workspacePreparer, process.env, taskFinalReviewContract);
|
|
1005
|
-
const actualTaskReviewCandidate = await actualTaskReviewCandidateForTaskCommand(resolved, store, workspacePreparer, process.env
|
|
1061
|
+
const actualTaskReviewCandidate = await actualTaskReviewCandidateForTaskCommand(resolved, store, workspacePreparer, process.env);
|
|
1006
1062
|
const deltaRecheckPreflight = await deltaRecheckPreflightForTaskCommand(resolved.slice(1), store, actualTaskReviewCandidate);
|
|
1007
1063
|
const reviewWorkspaceResult = await reviewWorkspaceResultForTaskCommand(resolved, store, workspacePreparer, process.env);
|
|
1008
1064
|
const executionLaneGitSnapshot = await executionLaneGitSnapshotForTaskCommand(resolved, store, workspacePreparer, process.env);
|
|
@@ -1016,6 +1072,9 @@ export async function main() {
|
|
|
1016
1072
|
...(taskFinalReviewContract === undefined
|
|
1017
1073
|
? {}
|
|
1018
1074
|
: { taskFinalReviewContract }),
|
|
1075
|
+
...(taskFinalReviewRebindProof === undefined
|
|
1076
|
+
? {}
|
|
1077
|
+
: { taskFinalReviewRebindProof }),
|
|
1019
1078
|
...(completionSummary === undefined ? {} : { completionSummary }),
|
|
1020
1079
|
...(completionPublishedTreeProof === undefined
|
|
1021
1080
|
? {}
|
|
@@ -1260,6 +1319,12 @@ export async function main() {
|
|
|
1260
1319
|
}
|
|
1261
1320
|
throw error;
|
|
1262
1321
|
}
|
|
1322
|
+
finally {
|
|
1323
|
+
if (releaseTaskFinalReviewHandoverLock !== undefined) {
|
|
1324
|
+
releaseTaskFinalReviewHandoverLock();
|
|
1325
|
+
releaseTaskFinalReviewHandoverLock = undefined;
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1263
1328
|
}
|
|
1264
1329
|
if (resolved[0] === "jobs") {
|
|
1265
1330
|
emit(runJobCommand(resolved.slice(1), store, { runtime }));
|
|
@@ -1300,12 +1365,12 @@ async function preflightManagedTaskControlPlane() {
|
|
|
1300
1365
|
}
|
|
1301
1366
|
if (!exactRuntime) {
|
|
1302
1367
|
if (exactControlInvocation.digest !== undefined) {
|
|
1303
|
-
|
|
1368
|
+
return await preflightManagedGlobalControlPlane(exactControlInvocation.digest);
|
|
1304
1369
|
}
|
|
1305
1370
|
if (taskFinalReviewInvocation.request !== undefined) {
|
|
1306
1371
|
throw new Error("Task final-review contract requires a verified exact Task control-plane invocation.");
|
|
1307
1372
|
}
|
|
1308
|
-
return { contract: undefined, verifiedStore: undefined };
|
|
1373
|
+
return { contract: undefined, controlPlane: undefined, verifiedStore: undefined };
|
|
1309
1374
|
}
|
|
1310
1375
|
if (process.env.YUI_SESSION_SCOPE !== "task") {
|
|
1311
1376
|
throw new Error("Exact Task control-plane invocation requires a managed Task runtime.");
|
|
@@ -1349,8 +1414,13 @@ async function preflightManagedTaskControlPlane() {
|
|
|
1349
1414
|
}
|
|
1350
1415
|
: {});
|
|
1351
1416
|
const request = taskFinalReviewInvocation.request;
|
|
1352
|
-
if (request === undefined)
|
|
1353
|
-
return {
|
|
1417
|
+
if (request === undefined) {
|
|
1418
|
+
return {
|
|
1419
|
+
contract: undefined,
|
|
1420
|
+
controlPlane: { digest, descriptor: control },
|
|
1421
|
+
verifiedStore
|
|
1422
|
+
};
|
|
1423
|
+
}
|
|
1354
1424
|
if (runtime.roleName !== "leader") {
|
|
1355
1425
|
throw new Error("Only the exact Task Leader invocation may establish a final-review contract.");
|
|
1356
1426
|
}
|
|
@@ -1363,9 +1433,50 @@ async function preflightManagedTaskControlPlane() {
|
|
|
1363
1433
|
reviewerRoleName: request.reviewerRoleName,
|
|
1364
1434
|
controlPlaneDigest: digest
|
|
1365
1435
|
}),
|
|
1436
|
+
controlPlane: { digest, descriptor: control },
|
|
1366
1437
|
verifiedStore
|
|
1367
1438
|
};
|
|
1368
1439
|
}
|
|
1440
|
+
async function preflightManagedGlobalControlPlane(digest) {
|
|
1441
|
+
if (process.env.YUI_SESSION_SCOPE !== "global") {
|
|
1442
|
+
throw new Error("Exact Task control-plane invocation requires its frozen runtime descriptors.");
|
|
1443
|
+
}
|
|
1444
|
+
if (taskFinalReviewInvocation.request !== undefined) {
|
|
1445
|
+
throw new Error("Task final-review contract establishment requires a verified exact Task control-plane invocation.");
|
|
1446
|
+
}
|
|
1447
|
+
const manifestPath = process.env.YUI_SESSION_MANIFEST;
|
|
1448
|
+
const sessionCliPath = process.env.YUI_SESSION_CLI;
|
|
1449
|
+
if (manifestPath === undefined || sessionCliPath === undefined) {
|
|
1450
|
+
throw new Error("Exact global control-plane invocation requires its Session Manifest and CLI.");
|
|
1451
|
+
}
|
|
1452
|
+
const manifest = readSessionBootstrapManifest(manifestPath);
|
|
1453
|
+
const expectedRoleKind = process.env.YUI_ROLE === "operator" ? "operator" : "global";
|
|
1454
|
+
if (manifest.owner.scope !== "global"
|
|
1455
|
+
|| manifest.roleKind !== expectedRoleKind
|
|
1456
|
+
|| resolve(manifest.controlPlane.sessionCliPath) !== resolve(sessionCliPath)
|
|
1457
|
+
|| manifest.controlPlane.digest !== digest) {
|
|
1458
|
+
throw new Error("Exact global control-plane invocation does not match its Session Manifest.");
|
|
1459
|
+
}
|
|
1460
|
+
const serializedDescriptor = readFileSync(manifest.controlPlane.descriptorPath, "utf8");
|
|
1461
|
+
const descriptor = parseExactControlPlaneDescriptor(serializedDescriptor);
|
|
1462
|
+
if (exactControlPlaneDigest(descriptor) !== digest
|
|
1463
|
+
|| resolve(manifest.controlPlane.descriptorPath) !== resolve(join(descriptor.yuiHome, "runtime", "control-plane", `${digest}.json`))
|
|
1464
|
+
|| resolve(manifestPath) !== resolve(join(descriptor.yuiHome, "runtime", "session-manifests", `${manifest.digest}.json`))) {
|
|
1465
|
+
throw new Error("Exact global Session Manifest does not match its control-plane descriptor.");
|
|
1466
|
+
}
|
|
1467
|
+
await assertExactControlPlanePreflight({
|
|
1468
|
+
serializedDescriptor,
|
|
1469
|
+
digest,
|
|
1470
|
+
actualExecutable: process.execPath,
|
|
1471
|
+
actualCliEntry: fileURLToPath(import.meta.url),
|
|
1472
|
+
actualHome: resolveYuiHome(process.env)
|
|
1473
|
+
});
|
|
1474
|
+
return {
|
|
1475
|
+
contract: undefined,
|
|
1476
|
+
controlPlane: { digest, descriptor },
|
|
1477
|
+
verifiedStore: openCompatibleFileTaskStore(descriptor.yuiHome)
|
|
1478
|
+
};
|
|
1479
|
+
}
|
|
1369
1480
|
function cleanupCliError(error, fallbackResource) {
|
|
1370
1481
|
if (error instanceof WorkspaceCleanupBlockedError) {
|
|
1371
1482
|
return usageError(error.message, undefined, cleanupBlockedDetails(error.reason, error.resource, error.retryable));
|
|
@@ -1630,6 +1741,36 @@ async function prepareReviewLaneWorkspaces(taskId, reviewRoundId, store, prepare
|
|
|
1630
1741
|
return map;
|
|
1631
1742
|
}
|
|
1632
1743
|
async function directTaskMainSnapshotForTaskCommand(args, store, preparer, environment, taskFinalReviewContract) {
|
|
1744
|
+
const deliveryOption = args.indexOf("--delivery", 3);
|
|
1745
|
+
const deliveryPromotion = args[0] === "task"
|
|
1746
|
+
&& args[1] === "update"
|
|
1747
|
+
&& args[2] !== undefined
|
|
1748
|
+
&& (args.includes("--require-integration", 3)
|
|
1749
|
+
|| (deliveryOption >= 0 && args[deliveryOption + 1] === "integrated"));
|
|
1750
|
+
if (deliveryPromotion) {
|
|
1751
|
+
const task = store.getTask(args[2]);
|
|
1752
|
+
if (task === null
|
|
1753
|
+
|| (task.status !== "active" && task.status !== "draft")
|
|
1754
|
+
|| task.requireIntegration === true
|
|
1755
|
+
|| task.projectBindings.length === 0) {
|
|
1756
|
+
return undefined;
|
|
1757
|
+
}
|
|
1758
|
+
const workspace = store.getTaskWorkspace(task.id);
|
|
1759
|
+
if (task.status === "draft" && workspace === null)
|
|
1760
|
+
return undefined;
|
|
1761
|
+
if (workspace === null
|
|
1762
|
+
|| workspace.owner.type !== "task"
|
|
1763
|
+
|| workspace.owner.taskId !== task.id) {
|
|
1764
|
+
throw usageError(`Task has no authoritative main workspace: ${task.id}.`);
|
|
1765
|
+
}
|
|
1766
|
+
try {
|
|
1767
|
+
return await preparer.snapshotDirectTaskMain(workspace, task.projectBindings.map(({ projectId }) => projectId));
|
|
1768
|
+
}
|
|
1769
|
+
catch (error) {
|
|
1770
|
+
throw usageError(`Delivery promotion Task-main verification failed for ${task.id}: `
|
|
1771
|
+
+ `${error instanceof Error ? error.message : String(error)}`);
|
|
1772
|
+
}
|
|
1773
|
+
}
|
|
1633
1774
|
if (taskFinalReviewContract === undefined
|
|
1634
1775
|
|| args[0] !== "task"
|
|
1635
1776
|
|| args[1] !== "work"
|
|
@@ -1660,7 +1801,7 @@ async function directTaskMainSnapshotForTaskCommand(args, store, preparer, envir
|
|
|
1660
1801
|
throw usageError(error instanceof Error ? error.message : String(error));
|
|
1661
1802
|
}
|
|
1662
1803
|
}
|
|
1663
|
-
async function actualTaskReviewCandidateForTaskCommand(args, store, preparer, environment
|
|
1804
|
+
async function actualTaskReviewCandidateForTaskCommand(args, store, preparer, environment) {
|
|
1664
1805
|
if (args[0] !== "task")
|
|
1665
1806
|
return undefined;
|
|
1666
1807
|
let taskId;
|
|
@@ -1669,12 +1810,9 @@ async function actualTaskReviewCandidateForTaskCommand(args, store, preparer, en
|
|
|
1669
1810
|
if (task === null || task.status !== "active" || task.projectBindings.length === 0) {
|
|
1670
1811
|
return undefined;
|
|
1671
1812
|
}
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
&& !establishedFinalRound) {
|
|
1676
|
-
return undefined;
|
|
1677
|
-
}
|
|
1813
|
+
// Every Project-backed completion, including direct delivery, must freeze
|
|
1814
|
+
// a clean committed Task-main snapshot. Review policy only decides whether
|
|
1815
|
+
// that head also needs an independent ReviewRound.
|
|
1678
1816
|
taskId = task.id;
|
|
1679
1817
|
}
|
|
1680
1818
|
else if (args[1] === "review"
|
|
@@ -213,6 +213,36 @@ export function renderExecutionAudit(report, width = defaultTableWidth()) {
|
|
|
213
213
|
else {
|
|
214
214
|
lines.push("", ...sectionError("workItems", report));
|
|
215
215
|
}
|
|
216
|
+
if (report.orchestration.status === "ok" && report.orchestration.data !== undefined) {
|
|
217
|
+
const orchestration = report.orchestration.data;
|
|
218
|
+
lines.push("", `Orchestration: ${orchestration.tasks.length} Task(s) · ${orchestration.advisoryCount} advisory finding(s)`);
|
|
219
|
+
if (orchestration.tasks.length > 0) {
|
|
220
|
+
lines.push(renderTable("Task orchestration metrics", [
|
|
221
|
+
{ header: "Task", minWidth: 7, maxWidth: 14 },
|
|
222
|
+
{ header: "Delivery", minWidth: 8, maxWidth: 10 },
|
|
223
|
+
{ header: "Runs", minWidth: 4, maxWidth: 6 },
|
|
224
|
+
{ header: "WIs", minWidth: 3, maxWidth: 5 },
|
|
225
|
+
{ header: "Review F/D/N", minWidth: 12, maxWidth: 16 },
|
|
226
|
+
{ header: "Integration A/F/R", minWidth: 17, maxWidth: 20 },
|
|
227
|
+
{ header: "Pre-progress gen", minWidth: 12, maxWidth: 16 },
|
|
228
|
+
{ header: "Terminal ws", minWidth: 10, maxWidth: 12 },
|
|
229
|
+
{ header: "Advice", minWidth: 6, maxWidth: 8 }
|
|
230
|
+
], orchestration.tasks.map((task) => [
|
|
231
|
+
task.taskId,
|
|
232
|
+
task.deliveryPath,
|
|
233
|
+
String(task.runs.total),
|
|
234
|
+
String(task.workItems),
|
|
235
|
+
`${task.reviews.full}/${task.reviews.delta}/${task.reviews.nonSemantic}`,
|
|
236
|
+
`${task.integrations.attempts}/${task.integrations.failed}/${task.integrations.repeatedIdentities}`,
|
|
237
|
+
String(task.providerGenerationsBeforeFirstProgress),
|
|
238
|
+
String(task.terminalWorkspaceCount),
|
|
239
|
+
String(task.advisories.length)
|
|
240
|
+
]), width));
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
lines.push("", ...sectionError("orchestration", report));
|
|
245
|
+
}
|
|
216
246
|
if (report.storage.status === "ok" && report.storage.data !== undefined) {
|
|
217
247
|
const storage = report.storage.data;
|
|
218
248
|
lines.push("", `Storage: backend ${storage.backend} · state.json ${formatBytes(storage.stateJsonBytes)} · yui.db ${formatBytes(storage.databaseBytes)}`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { usageError } from "../errors/cliError.js";
|
|
2
2
|
import { createRoleSessionSet } from "../executor/agentExecutor.js";
|
|
3
|
-
import { listOperatorSessions, prepareOperatorNewSession, prepareOperatorResumeSession } from "../operator/operatorSessionHistory.js";
|
|
3
|
+
import { listOperatorSessions, projectOperatorStatus, prepareOperatorNewSession, prepareOperatorResumeSession } from "../operator/operatorSessionHistory.js";
|
|
4
4
|
import { defaultTableWidth, renderTable } from "../output/table.js";
|
|
5
5
|
import { formatRelativeTimestamp } from "../output/timePresentation.js";
|
|
6
6
|
import { updateGlobalRole } from "../role/role.js";
|
|
@@ -11,6 +11,7 @@ export function runOperatorCommand(args, store, options = {}) {
|
|
|
11
11
|
const [command, ...rest] = args;
|
|
12
12
|
switch (command) {
|
|
13
13
|
case "list": return listSessions(rest, store, options);
|
|
14
|
+
case "status": return status(rest, store, options);
|
|
14
15
|
case "new": return newSession(rest, store);
|
|
15
16
|
case "resume": return resumeSession(rest, store);
|
|
16
17
|
case "submit": return submit(rest, store, options);
|
|
@@ -20,6 +21,46 @@ export function runOperatorCommand(args, store, options = {}) {
|
|
|
20
21
|
: `Unknown command: operator ${command}`);
|
|
21
22
|
}
|
|
22
23
|
}
|
|
24
|
+
function status(args, store, options) {
|
|
25
|
+
if (args.length !== 0)
|
|
26
|
+
throw usageError("Operator status usage: yui operator status.");
|
|
27
|
+
const role = requireOperator(store);
|
|
28
|
+
const activeBinding = role.agentBindings[role.activeAgentId];
|
|
29
|
+
if (activeBinding === undefined) {
|
|
30
|
+
throw usageError(`Operator active Agent is not bound: ${role.activeAgentId}.`);
|
|
31
|
+
}
|
|
32
|
+
const projection = projectOperatorStatus(store.getGlobalRoleSessionSet(role.name), role.activeAgentId, activeBinding.adapterId);
|
|
33
|
+
const writer = projection.writer;
|
|
34
|
+
const writerLines = [
|
|
35
|
+
"Operator status",
|
|
36
|
+
"Active writer:",
|
|
37
|
+
` State: ${writer.state}`,
|
|
38
|
+
` Agent: ${writer.agentId}`,
|
|
39
|
+
` Adapter: ${adapterLabel(writer.adapterId)}`,
|
|
40
|
+
` Conversation: ${writer.sessionRef ?? "-"}`,
|
|
41
|
+
` Native session: ${writer.nativeSessionId ?? "-"}`,
|
|
42
|
+
` Session state: ${writer.sessionStatus ?? "-"}`
|
|
43
|
+
];
|
|
44
|
+
const history = projection.historicalConversations;
|
|
45
|
+
const historyOutput = history.length === 0
|
|
46
|
+
? "Historical conversations: none"
|
|
47
|
+
: renderTable("Historical conversations", [
|
|
48
|
+
{ header: "Updated", minWidth: 7, maxWidth: 12 },
|
|
49
|
+
{ header: "Agent", minWidth: 6, maxWidth: 16 },
|
|
50
|
+
{ header: "Conversation", minWidth: 20, maxWidth: 72 },
|
|
51
|
+
{ header: "State", minWidth: 7, maxWidth: 10 }
|
|
52
|
+
], history.map((session) => [
|
|
53
|
+
formatRelativeTimestamp(session.updatedAt, options.now?.() ?? new Date()),
|
|
54
|
+
adapterLabel(session.adapterId),
|
|
55
|
+
session.displayTitle,
|
|
56
|
+
session.state
|
|
57
|
+
]), options.width ?? defaultTableWidth());
|
|
58
|
+
return {
|
|
59
|
+
kind: "output",
|
|
60
|
+
output: `${writerLines.join("\n")}\n\n${historyOutput}\n`,
|
|
61
|
+
data: projection
|
|
62
|
+
};
|
|
63
|
+
}
|
|
23
64
|
function submit(rest, store, options) {
|
|
24
65
|
const usage = "Operator submit usage: yui operator submit (<body>|--body-file <path|->) [--task <id>].";
|
|
25
66
|
const positionals = [];
|