@zq-silk/yui 0.7.1 → 0.8.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 +27 -28
- package/README.md +79 -71
- package/dist/cli/commandCatalog.js +283 -136
- package/dist/cli/completion.js +3 -3
- package/dist/cli/helpRenderer.js +3 -0
- package/dist/cli/interactionPolicy.js +48 -33
- package/dist/cli/interactiveSelection.js +1 -1
- package/dist/cli/invocationRouter.js +3 -2
- package/dist/cli/roleWizard.js +8 -8
- package/dist/cli.js +189 -93
- package/dist/commands/agentCommands.js +5 -5
- package/dist/commands/configCommands.js +351 -104
- package/dist/commands/configOverview.js +60 -0
- package/dist/commands/deliveryGuardPreflight.js +2 -2
- package/dist/commands/globalRoleCommands.js +9 -9
- package/dist/commands/profileCommands.js +8 -8
- package/dist/commands/resourcesCommands.js +6 -5
- package/dist/commands/taskCommands.js +111 -59
- package/dist/commands/taskRoleRuntimeStatus.js +3 -1
- package/dist/commands/telemetryCommands.js +11 -6
- package/dist/config/configCatalog.js +42 -0
- package/dist/config/yuiConfig.js +80 -35
- package/dist/context/sessionBootstrapManifest.js +1 -1
- package/dist/controller/clientRuntime.js +0 -2
- package/dist/controller/controller.js +21 -9
- package/dist/controller/fileSchedulerStoreAdapter.js +409 -79
- package/dist/controller/resourceInventory.js +9 -5
- package/dist/controller/runtime.js +112 -25
- package/dist/controller/runtimeLaunchCoordinator.js +18 -78
- package/dist/controller/structuredProviderObservation.js +273 -0
- package/dist/doctor/doctor.js +2 -2
- package/dist/executor/agentAdapter.js +40 -0
- package/dist/executor/agentExecutor.js +31 -7
- package/dist/executor/executorRegistry.js +11 -49
- package/dist/executor/fileRoleLaunchPlanner.js +115 -37
- package/dist/lifecycle/canonicalLifecycleEvent.js +5 -2
- package/dist/resources/autoResourceGc.js +3 -1
- package/dist/review/reviewConfig.js +0 -2
- package/dist/run/agentRun.js +2 -2
- package/dist/run/providerRetry.js +29 -16
- package/dist/run/providerRetryConfig.js +5 -3
- package/dist/runtime/agentHost.js +767 -158
- package/dist/runtime/builtinAgentDrivers.js +1 -5
- package/dist/runtime/codexAppServerRuntime.js +67 -60
- package/dist/runtime/exactControlPlane.js +7 -2
- package/dist/runtime/index.js +6 -2
- package/dist/runtime/launchBroker.js +30 -8
- package/dist/runtime/launchDiagnostics.js +1 -1
- package/dist/runtime/providerAuthorityFence.js +24 -0
- package/dist/runtime/providerControl.js +63 -0
- package/dist/runtime/providerRecoveryDecision.js +55 -0
- package/dist/runtime/providerRuntimeIdentity.js +269 -19
- package/dist/runtime/runtimeBinding.js +20 -11
- package/dist/runtime/structuredProviderHost.js +476 -0
- package/dist/runtime/tmuxAdapters.js +143 -42
- package/dist/scheduler/activeRoleRunDelivery.js +206 -120
- package/dist/scheduler/leaderWakeupProcessor.js +141 -16
- package/dist/scheduler/roleRunStall.js +12 -9
- package/dist/setup/setupCommand.js +153 -492
- package/dist/storage/compatibleTaskStore.js +9 -5
- package/dist/storage/migration/productionRegistry.js +169 -0
- package/dist/storage/taskStore.js +22 -3
- package/dist/telemetry/sqliteTelemetryStore.js +9 -1
- package/dist/telemetry/telemetryConfig.js +1 -18
- package/dist/telemetry/telemetryStore.js +2 -2
- package/dist/telemetry/telemetryWiring.js +6 -5
- package/dist/tmux/tmuxManager.js +1 -1
- package/dist/web/webSnapshot.js +5 -3
- package/i18n/README.zh-CN.md +48 -40
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +12 -5
- package/skills/yui-operator/SKILL.md +44 -6
- package/skills/yui-runtime/SKILL.md +1 -1
package/dist/cli.js
CHANGED
|
@@ -5,6 +5,7 @@ import { createInterface } from "node:readline/promises";
|
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { isDeepStrictEqual } from "node:util";
|
|
7
7
|
import { renderCommandHelp } from "./cli/helpRenderer.js";
|
|
8
|
+
import { describeCommandTree, findCommandNode } from "./cli/commandCatalog.js";
|
|
8
9
|
import { routeInvocation } from "./cli/invocationRouter.js";
|
|
9
10
|
import { renderCompletion } from "./cli/completion.js";
|
|
10
11
|
import { resolveCompletionCandidates } from "./cli/dynamicCompletion.js";
|
|
@@ -16,12 +17,14 @@ import { resolveOperatorWizardArguments } from "./cli/operatorWizard.js";
|
|
|
16
17
|
import { runUpdateCommand } from "./cli/updateCommand.js";
|
|
17
18
|
import { runUpgradeCommand } from "./cli/upgradeCommand.js";
|
|
18
19
|
import { formatTimestamp } from "./output/timePresentation.js";
|
|
19
|
-
import { resolveTmuxBin } from "./config/yuiConfig.js";
|
|
20
|
+
import { resolveTmuxBin, resolveTmuxHistoryLimit } from "./config/yuiConfig.js";
|
|
20
21
|
import { renderAgentConfigurationCatalog } from "./output/agentConfigurationPresentation.js";
|
|
21
22
|
import { nativeAgentEnvironmentNames } from "./agent/launchEnvironment.js";
|
|
22
23
|
import { runAgentCommand } from "./commands/agentCommands.js";
|
|
23
24
|
import { runGlobalRoleCommand } from "./commands/globalRoleCommands.js";
|
|
24
25
|
import { runConfigCommand } from "./commands/configCommands.js";
|
|
26
|
+
import { CONFIG_DOMAINS } from "./config/configCatalog.js";
|
|
27
|
+
import { runConfigOverview } from "./commands/configOverview.js";
|
|
25
28
|
import { parseControllerCleanupOptions, parseControllerStatusOptions, parseControllerRuntimeSnapshot, renderControllerResourceStatus, renderRuntimeIdentitySection, summarizeDurablePhysicalMismatch, runInteractiveControllerCleanup } from "./commands/controllerCommands.js";
|
|
26
29
|
import { parseExecutionAuditOptions, runExecutionAuditCommand } from "./commands/executionAuditCommands.js";
|
|
27
30
|
import { parseSessionReconcileOptions, runSessionReconcileCommand } from "./commands/sessionCommands.js";
|
|
@@ -33,7 +36,7 @@ import { runResourcesCommand } from "./commands/resourcesCommands.js";
|
|
|
33
36
|
import { applyOperatorSessionControl, runOperatorCommand } from "./commands/operatorCommands.js";
|
|
34
37
|
import { runProjectCommand } from "./commands/projectCommands.js";
|
|
35
38
|
import { runProfileCommand } from "./commands/profileCommands.js";
|
|
36
|
-
import { dispatchPreparedReviewRound, failPendingReviewRound,
|
|
39
|
+
import { dispatchPreparedReviewRound, failPendingReviewRound, RESUMED_PENDING_FINAL_REVIEW, TERMINALIZED_LEADER_BEFORE_FINAL_REVIEW, TaskFinalReviewDispatchDriftError, preserveReviewRoundWorkspace, parseTaskCompletionRequest, preflightTaskCompletion, runTaskCommand, normalizedExecutionLanePlan, validateTaskArchiveRequest } from "./commands/taskCommands.js";
|
|
37
40
|
import { taskActor } from "./commands/taskActor.js";
|
|
38
41
|
import { runTaskIntegrationCommand } from "./commands/taskIntegrationCommands.js";
|
|
39
42
|
import { runTaskChangeSetCommand } from "./commands/taskChangeSetCommands.js";
|
|
@@ -58,9 +61,9 @@ import { runSessionNotifyCommand } from "./controller/sessionNotify.js";
|
|
|
58
61
|
import { openSchedulerTelemetry } from "./telemetry/telemetryWiring.js";
|
|
59
62
|
import { runRuntimeObservationHookCommand } from "./controller/runtimeObservationHook.js";
|
|
60
63
|
import { buildDoctorReport, renderDoctor, runDoctorCommand } from "./doctor/doctor.js";
|
|
61
|
-
import { agentNotFound, CliError, usageError } from "./errors/cliError.js";
|
|
64
|
+
import { agentNotFound, CliError, runtimeError, usageError } from "./errors/cliError.js";
|
|
62
65
|
import { FileRoleLaunchPlanner } from "./executor/fileRoleLaunchPlanner.js";
|
|
63
|
-
import { runAgentHost } from "./runtime/agentHost.js";
|
|
66
|
+
import { AGENT_HOST_CONTROL_PROTOCOL, runAgentHost, sendAgentHostAuthorityControl } from "./runtime/agentHost.js";
|
|
64
67
|
import { TaskWorkspaceCoordinator, WorkspaceCleanupBlockedError } from "./repository/taskWorkspaceCoordinator.js";
|
|
65
68
|
import { FileTaskWorkspacePreparer, ReviewRoundWorkspaceEvidenceError } from "./repository/taskWorkspacePreparer.js";
|
|
66
69
|
import { inspectStorageSchema } from "./storage/storageSchema.js";
|
|
@@ -168,10 +171,25 @@ export async function main() {
|
|
|
168
171
|
}
|
|
169
172
|
throw usageError("Release usage: yui release install <source-dir> | list | activate [release-id].");
|
|
170
173
|
}
|
|
171
|
-
if (args[0] === "completion") {
|
|
174
|
+
if (args[0] === "config" && args[1] === "completion") {
|
|
172
175
|
await completionCommand(home, invocation.node);
|
|
173
176
|
return;
|
|
174
177
|
}
|
|
178
|
+
if (args[0] === "config" && args[1] === "describe") {
|
|
179
|
+
const describeNode = findCommandNode(["config", "describe"]);
|
|
180
|
+
if (describeNode === undefined)
|
|
181
|
+
throw new Error("Config describe command is missing from the catalog.");
|
|
182
|
+
const domain = args[2];
|
|
183
|
+
const domains = describeNode.argumentValues[0] ?? [];
|
|
184
|
+
if (args.length > 3 || (domain !== undefined && !domains.includes(domain))) {
|
|
185
|
+
throw usageError(`Config describe usage: ${describeNode.usage.join(" | ")}.`);
|
|
186
|
+
}
|
|
187
|
+
const target = findCommandNode(domain === undefined ? ["config"] : ["config", domain]);
|
|
188
|
+
if (target === undefined)
|
|
189
|
+
throw new Error(`Config domain is missing from the catalog: ${domain}.`);
|
|
190
|
+
emit(renderCommandHelp(target, VERSION), false, describeCommandTree(target));
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
175
193
|
if (args[0] === "setup") {
|
|
176
194
|
if (jsonOutput)
|
|
177
195
|
throw usageError("Setup does not support --json.");
|
|
@@ -261,13 +279,13 @@ export async function main() {
|
|
|
261
279
|
}
|
|
262
280
|
throw usageError("Internal lifecycle callback usage is invalid.");
|
|
263
281
|
}
|
|
264
|
-
if (args[0] === "session") {
|
|
265
|
-
if (args[1] !== "reconcile") {
|
|
266
|
-
throw usageError("Session usage: yui session reconcile [--report] [--cleanup].");
|
|
267
|
-
}
|
|
282
|
+
if (args[0] === "session" && args[1] === "reconcile") {
|
|
268
283
|
const options = parseSessionReconcileOptions(args.slice(2));
|
|
269
284
|
const store = openCompatibleFileTaskStore(home);
|
|
270
|
-
const tmux = new TmuxManager(resolveTmuxBin(store.getConfig().tmuxBin), new NodeCommandExecutor(), {
|
|
285
|
+
const tmux = new TmuxManager(resolveTmuxBin(store.getConfig().tmuxBin), new NodeCommandExecutor(), {
|
|
286
|
+
yuiHome: home,
|
|
287
|
+
historyLimit: resolveTmuxHistoryLimit(store.getConfig().tmuxHistoryLimit)
|
|
288
|
+
});
|
|
271
289
|
const reconciliation = new SessionOwnerReconciliation({
|
|
272
290
|
home,
|
|
273
291
|
store,
|
|
@@ -474,6 +492,7 @@ export async function main() {
|
|
|
474
492
|
const executor = new NodeCommandExecutor();
|
|
475
493
|
const tmux = new TmuxManager(resolveTmuxBin(store.getConfig().tmuxBin), executor, {
|
|
476
494
|
yuiHome: home,
|
|
495
|
+
historyLimit: resolveTmuxHistoryLimit(store.getConfig().tmuxHistoryLimit),
|
|
477
496
|
terminalInput: process.stdin,
|
|
478
497
|
onWarning: (message) => process.stderr.write(`Warning: ${message}\n`)
|
|
479
498
|
});
|
|
@@ -531,77 +550,102 @@ export async function main() {
|
|
|
531
550
|
process.stdout.write(`Yui web control room: http://${displayHost}:${options.port}\n`);
|
|
532
551
|
return;
|
|
533
552
|
}
|
|
534
|
-
if (resolved[0] === "
|
|
535
|
-
const
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
553
|
+
if (resolved[0] === "config") {
|
|
554
|
+
const domain = resolved[1];
|
|
555
|
+
const roleOptions = {
|
|
556
|
+
yuiHome: home,
|
|
557
|
+
env: process.env
|
|
558
|
+
};
|
|
559
|
+
if (domain === "show") {
|
|
560
|
+
const result = runConfigOverview(resolved.slice(2), store, process.env, resolveCliIdentity(process.env), roleOptions);
|
|
561
|
+
emit(result.output, false, result.data);
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
if (CONFIG_DOMAINS.includes(domain ?? "")) {
|
|
565
|
+
const configDomain = domain;
|
|
566
|
+
const domainArgs = resolved.slice(2);
|
|
567
|
+
const result = runConfigCommand(configDomain, domainArgs, store);
|
|
568
|
+
if (domainArgs[0] === "set"
|
|
569
|
+
&& domainArgs[1] === "reconciliation-interval-seconds") {
|
|
570
|
+
const refresh = await refreshRunningFileTaskControllerConfiguration(home, { environment: process.env });
|
|
571
|
+
emit(withControllerRefreshWarning(result.output, refresh, "Controller configuration"));
|
|
572
|
+
return;
|
|
539
573
|
}
|
|
540
|
-
|
|
541
|
-
if (agent === null)
|
|
542
|
-
throw agentNotFound(agentArgs[1] ?? "");
|
|
543
|
-
const result = await catalogs.resolve({
|
|
544
|
-
agent,
|
|
545
|
-
cwd: store.getConfig().defaultWorkspace ?? process.cwd()
|
|
546
|
-
});
|
|
547
|
-
emit(renderAgentConfigurationCatalog(result), false, result);
|
|
574
|
+
emit(result.output, false, result.data);
|
|
548
575
|
return;
|
|
549
576
|
}
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
577
|
+
if (domain === "agent") {
|
|
578
|
+
const agentArgs = resolved.slice(2);
|
|
579
|
+
if (agentArgs[0] === "capabilities") {
|
|
580
|
+
if (agentArgs.length !== 2) {
|
|
581
|
+
throw usageError("Agent capabilities usage: yui config agent capabilities <agent-id>");
|
|
582
|
+
}
|
|
583
|
+
const agent = store.getConfiguredAgent(agentArgs[1] ?? "");
|
|
584
|
+
if (agent === null)
|
|
585
|
+
throw agentNotFound(agentArgs[1] ?? "");
|
|
586
|
+
const result = await catalogs.resolve({
|
|
587
|
+
agent,
|
|
588
|
+
cwd: store.getConfig().defaultWorkspace ?? process.cwd()
|
|
589
|
+
});
|
|
590
|
+
emit(renderAgentConfigurationCatalog(result), false, result);
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
const affectedAgentId = agentArgs[1];
|
|
594
|
+
const previousAgent = typeof affectedAgentId === "string"
|
|
559
595
|
? store.getConfiguredAgent(affectedAgentId)
|
|
560
596
|
: null;
|
|
561
|
-
const
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
597
|
+
const output = runAgentCommand(agentArgs, store);
|
|
598
|
+
if (agentArgs[0] === "add"
|
|
599
|
+
|| agentArgs[0] === "update"
|
|
600
|
+
|| agentArgs[0] === "remove") {
|
|
601
|
+
const currentAgent = typeof affectedAgentId === "string"
|
|
602
|
+
? store.getConfiguredAgent(affectedAgentId)
|
|
603
|
+
: null;
|
|
604
|
+
const capabilityNotice = currentAgent !== null
|
|
605
|
+
&& (agentArgs[0] === "add" || agentArgs[0] === "update")
|
|
606
|
+
? renderAgentConfigurationResolutionNotice(await catalogs.resolve({
|
|
607
|
+
agent: currentAgent,
|
|
608
|
+
cwd: store.getConfig().defaultWorkspace ?? process.cwd()
|
|
609
|
+
}))
|
|
610
|
+
: "";
|
|
611
|
+
const scope = agentEnvironmentRefreshScope(previousAgent, currentAgent, store.listConfiguredAgents());
|
|
612
|
+
const refresh = await refreshRunningFileTaskControllerEnvironment(home, store, process.env, scope);
|
|
613
|
+
emit(withControllerRefreshWarning(`${output.trimEnd()}${capabilityNotice.length === 0 ? "\n" : `\n${capabilityNotice}`}`, refresh, "Agent environment"));
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
emit(output);
|
|
571
617
|
return;
|
|
572
618
|
}
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
if (resolved[0] === "config") {
|
|
577
|
-
const configArgs = resolved.slice(1);
|
|
578
|
-
const result = runConfigCommand(configArgs, store);
|
|
579
|
-
if (configArgs[0] === "set"
|
|
580
|
-
&& configArgs[1] === "reconciliation-interval-seconds") {
|
|
581
|
-
const refresh = await refreshRunningFileTaskControllerConfiguration(home, { environment: process.env });
|
|
582
|
-
emit(withControllerRefreshWarning(result.output, refresh, "Controller configuration"));
|
|
619
|
+
if (domain === "profile") {
|
|
620
|
+
const result = runProfileCommand(resolved.slice(2), store);
|
|
621
|
+
emit(result.output, false, result.data);
|
|
583
622
|
return;
|
|
584
623
|
}
|
|
585
|
-
|
|
586
|
-
|
|
624
|
+
if (domain === "role") {
|
|
625
|
+
const result = runGlobalRoleCommand(resolved.slice(2), store, roleOptions);
|
|
626
|
+
if (typeof result !== "string") {
|
|
627
|
+
throw new Error("Config Role commands cannot enter a runtime Session.");
|
|
628
|
+
}
|
|
629
|
+
emit(result);
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
632
|
+
throw usageError(`Unknown configuration domain: ${domain ?? ""}.`);
|
|
587
633
|
}
|
|
588
634
|
if (resolved[0] === "project") {
|
|
589
635
|
const result = await runProjectCommand(resolved.slice(1), store, { environment: process.env });
|
|
590
636
|
emit(result.output, false, result.data);
|
|
591
637
|
return;
|
|
592
638
|
}
|
|
593
|
-
if (resolved[0] === "
|
|
594
|
-
const result = runProfileCommand(resolved.slice(1), store);
|
|
595
|
-
emit(result.output, false, result.data);
|
|
596
|
-
return;
|
|
597
|
-
}
|
|
598
|
-
if (resolved[0] === "role") {
|
|
639
|
+
if (resolved[0] === "session") {
|
|
599
640
|
const roleOptions = {
|
|
600
641
|
yuiHome: home,
|
|
601
642
|
env: process.env,
|
|
602
643
|
jsonOutput
|
|
603
644
|
};
|
|
604
|
-
const
|
|
645
|
+
const sessionArgs = resolved[1] === "enter" || resolved[1] === "context"
|
|
646
|
+
? [resolved[1], ...resolved.slice(2)]
|
|
647
|
+
: ["session", resolved[1] ?? "", ...resolved.slice(2)];
|
|
648
|
+
const result = runGlobalRoleCommand(sessionArgs, store, roleOptions);
|
|
605
649
|
if (typeof result === "string") {
|
|
606
650
|
emit(result);
|
|
607
651
|
return;
|
|
@@ -1104,30 +1148,82 @@ export async function main() {
|
|
|
1104
1148
|
: { command: result.data, ...reviewData });
|
|
1105
1149
|
return;
|
|
1106
1150
|
}
|
|
1107
|
-
if (
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1151
|
+
if (jsonOutput) {
|
|
1152
|
+
throw usageError("Task Role view/takeover requires an interactive terminal.");
|
|
1153
|
+
}
|
|
1154
|
+
if (result.kind === "view") {
|
|
1155
|
+
if (result.output !== undefined)
|
|
1156
|
+
emit(result.output);
|
|
1157
|
+
tmux.attachRole(result.taskId, result.roleName, "read-only");
|
|
1158
|
+
return;
|
|
1159
|
+
}
|
|
1160
|
+
const syncAuthority = async (authorityResult) => {
|
|
1161
|
+
let control;
|
|
1162
|
+
try {
|
|
1163
|
+
control = await sendAgentHostAuthorityControl({
|
|
1164
|
+
home,
|
|
1165
|
+
scope: "task",
|
|
1166
|
+
taskId: authorityResult.taskId,
|
|
1167
|
+
roleName: authorityResult.roleName,
|
|
1168
|
+
control: {
|
|
1169
|
+
protocol: AGENT_HOST_CONTROL_PROTOCOL,
|
|
1170
|
+
type: "set-authority",
|
|
1171
|
+
nativeSessionId: authorityResult.nativeSessionId,
|
|
1172
|
+
authority: authorityResult.authority
|
|
1118
1173
|
}
|
|
1119
|
-
|
|
1174
|
+
});
|
|
1175
|
+
}
|
|
1176
|
+
catch (error) {
|
|
1177
|
+
throw runtimeError(`Agent Host authority synchronization failed at epoch ${authorityResult.authority.epoch}: `
|
|
1178
|
+
+ `${error instanceof Error ? error.message : String(error)}. `
|
|
1179
|
+
+ `Durable authority is ${authorityResult.authority.owner}-owned; retry `
|
|
1180
|
+
+ `'yui task role release ${authorityResult.taskId} ${authorityResult.roleName}' `
|
|
1181
|
+
+ "to reconcile the Host.");
|
|
1182
|
+
}
|
|
1183
|
+
if (control.outcome !== "accepted"
|
|
1184
|
+
|| control.snapshot.nativeSessionId !== authorityResult.nativeSessionId
|
|
1185
|
+
|| control.snapshot.authorityEpoch !== authorityResult.authority.epoch
|
|
1186
|
+
|| control.snapshot.authorityOwner !== authorityResult.authority.owner
|
|
1187
|
+
|| control.snapshot.authorityHolderId !== authorityResult.authority.holderId) {
|
|
1188
|
+
throw runtimeError(`Agent Host did not accept Provider authority epoch ${authorityResult.authority.epoch}: `
|
|
1189
|
+
+ (control.snapshot.detail ?? control.outcome)
|
|
1190
|
+
+ `. Durable authority is ${authorityResult.authority.owner}-owned; `
|
|
1191
|
+
+ "retry 'yui task role release "
|
|
1192
|
+
+ `${authorityResult.taskId} ${authorityResult.roleName}' to reconcile the Host.`);
|
|
1193
|
+
}
|
|
1194
|
+
return control;
|
|
1195
|
+
};
|
|
1196
|
+
await syncAuthority(result);
|
|
1197
|
+
emit(result.output);
|
|
1198
|
+
if (result.action === "release") {
|
|
1199
|
+
runtime.notifyMailboxChanged({
|
|
1200
|
+
kind: "role",
|
|
1201
|
+
taskId: result.taskId,
|
|
1202
|
+
roleName: result.roleName
|
|
1120
1203
|
});
|
|
1204
|
+
return;
|
|
1205
|
+
}
|
|
1206
|
+
process.stdout.write("Provider input is now routed through the Agent Host PTY gateway. "
|
|
1207
|
+
+ "Use tmux detach (Ctrl-b d) to return authority to the Controller.\n");
|
|
1208
|
+
try {
|
|
1209
|
+
tmux.attachRole(result.taskId, result.roleName, "read-write");
|
|
1121
1210
|
}
|
|
1122
1211
|
finally {
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1212
|
+
const currentTask = store.getTask(result.taskId);
|
|
1213
|
+
// Completing or retiring the Task from inside the takeover Turn owns
|
|
1214
|
+
// Provider shutdown and clears the live binding. Do not turn that
|
|
1215
|
+
// successful terminal transition into a failing best-effort release.
|
|
1216
|
+
if (currentTask?.status === "active") {
|
|
1217
|
+
const released = runTaskCommand(["role", "release", result.taskId, result.roleName], store, { runtime, environment: process.env, yuiHome: home });
|
|
1218
|
+
if (released.kind !== "authority" || released.action !== "release") {
|
|
1219
|
+
throw runtimeError("Provider authority release returned an invalid result.");
|
|
1220
|
+
}
|
|
1221
|
+
await syncAuthority(released);
|
|
1222
|
+
emit(released.output);
|
|
1127
1223
|
runtime.notifyMailboxChanged({
|
|
1128
1224
|
kind: "role",
|
|
1129
|
-
taskId:
|
|
1130
|
-
roleName:
|
|
1225
|
+
taskId: released.taskId,
|
|
1226
|
+
roleName: released.roleName
|
|
1131
1227
|
});
|
|
1132
1228
|
}
|
|
1133
1229
|
}
|
|
@@ -1659,7 +1755,7 @@ async function deltaRecheckPreflightForTaskCommand(args, store, actualTaskReview
|
|
|
1659
1755
|
const config = store.getReviewConfig();
|
|
1660
1756
|
if (!deltaRecheckEnabled(config)) {
|
|
1661
1757
|
throw usageError("Delta-recheck is not enabled for this Project's review policy. "
|
|
1662
|
-
+ "Set `yui config set review --role <role> --trigger final --delta-recheck enabled` "
|
|
1758
|
+
+ "Set `yui config workflow set review --role <role> --trigger final --delta-recheck enabled` "
|
|
1663
1759
|
+ "or request a full Review.");
|
|
1664
1760
|
}
|
|
1665
1761
|
const reviewConfig = config;
|
|
@@ -1809,7 +1905,7 @@ async function executeOperatorSessionControl(control, home, store, runtime, tmux
|
|
|
1809
1905
|
process.stdout.write("Cancelled.\n");
|
|
1810
1906
|
return;
|
|
1811
1907
|
}
|
|
1812
|
-
const updated = runGlobalRoleCommand(resolution.args.slice(
|
|
1908
|
+
const updated = runGlobalRoleCommand(resolution.args.slice(2), store, { yuiHome: home, env: process.env });
|
|
1813
1909
|
if (typeof updated !== "string") {
|
|
1814
1910
|
throw new Error("Operator Agent configuration returned an invalid control result.");
|
|
1815
1911
|
}
|
|
@@ -1865,11 +1961,11 @@ function renderControllerResult(method, value) {
|
|
|
1865
1961
|
: "Controller was already stopped.";
|
|
1866
1962
|
}
|
|
1867
1963
|
async function completionCommand(home, node) {
|
|
1868
|
-
if (args[
|
|
1869
|
-
const separator = args.indexOf("--");
|
|
1870
|
-
const prefix = args[
|
|
1871
|
-
if (prefix === undefined || separator !==
|
|
1872
|
-
throw usageError("Completion candidates usage: yui completion candidates <prefix> -- <words...>");
|
|
1964
|
+
if (args[2] === "candidates") {
|
|
1965
|
+
const separator = args.indexOf("--", 4);
|
|
1966
|
+
const prefix = args[3];
|
|
1967
|
+
if (prefix === undefined || separator !== 4) {
|
|
1968
|
+
throw usageError("Completion candidates usage: yui config completion candidates <prefix> -- <words...>");
|
|
1873
1969
|
}
|
|
1874
1970
|
const candidates = await resolveCompletionCandidates({
|
|
1875
1971
|
current: prefix,
|
|
@@ -1884,9 +1980,9 @@ async function completionCommand(home, node) {
|
|
|
1884
1980
|
if (process.stdin.isTTY !== true || process.stdout.isTTY !== true) {
|
|
1885
1981
|
throw usageError("Completion configuration requires an interactive terminal.");
|
|
1886
1982
|
}
|
|
1887
|
-
const shell = completionShell(args[
|
|
1888
|
-
if (args.length > (shell === undefined ?
|
|
1889
|
-
throw usageError("Completion usage: yui completion [bash|zsh|fish]");
|
|
1983
|
+
const shell = completionShell(args[2]);
|
|
1984
|
+
if (args.length > (shell === undefined ? 2 : 3)) {
|
|
1985
|
+
throw usageError("Completion usage: yui config completion [bash|zsh|fish]");
|
|
1890
1986
|
}
|
|
1891
1987
|
const store = openCompatibleFileTaskStore(home);
|
|
1892
1988
|
const ioHandle = terminalIo();
|
|
@@ -1921,7 +2017,7 @@ async function resolveTerminalArguments(commandArgs, node, store, catalogs) {
|
|
|
1921
2017
|
// Global Role add owns its Agent choice so the configured default can be
|
|
1922
2018
|
// shown explicitly. Other commands first resolve missing positional
|
|
1923
2019
|
// targets through the generic selector, then enter the focused Role UI.
|
|
1924
|
-
if ((operatorArgs[0] === "
|
|
2020
|
+
if ((operatorArgs[0] === "config" && operatorArgs[1] === "role" && operatorArgs[2] === "add")
|
|
1925
2021
|
|| (operatorArgs[0] === "task" && operatorArgs[1] === "role" && operatorArgs[2] === "add")) {
|
|
1926
2022
|
const wizard = await resolveRoleWizardArguments(operatorArgs, ports, handle.io);
|
|
1927
2023
|
if (wizard.kind === "cancelled")
|
|
@@ -1983,7 +2079,7 @@ async function preflightAgentConfigurationMutation(commandArgs, store, catalogs)
|
|
|
1983
2079
|
});
|
|
1984
2080
|
}
|
|
1985
2081
|
function hasModelOrEffortMutation(args) {
|
|
1986
|
-
const operation = args[0] === "role"
|
|
2082
|
+
const operation = (args[0] === "config" && args[1] === "role")
|
|
1987
2083
|
|| (args[0] === "task" && args[1] === "role");
|
|
1988
2084
|
return operation && [
|
|
1989
2085
|
"--model", "--effort", "--clear-model", "--clear-effort"
|
|
@@ -1993,8 +2089,8 @@ function configurationMutationAgentId(args, store) {
|
|
|
1993
2089
|
const explicit = optionValue(args, "--agent");
|
|
1994
2090
|
if (explicit !== undefined)
|
|
1995
2091
|
return explicit;
|
|
1996
|
-
if (args[0] === "
|
|
1997
|
-
return store.getGlobalRole(args[
|
|
2092
|
+
if (args[0] === "config" && args[1] === "role" && args[2] === "update") {
|
|
2093
|
+
return store.getGlobalRole(args[3] ?? "")?.activeAgentId;
|
|
1998
2094
|
}
|
|
1999
2095
|
if (args[0] === "task" && args[1] === "role") {
|
|
2000
2096
|
if (args[2] === "add")
|
|
@@ -15,7 +15,7 @@ export function runAgentCommand(args, store) {
|
|
|
15
15
|
default:
|
|
16
16
|
throw usageError(command === undefined
|
|
17
17
|
? "Agent command is required."
|
|
18
|
-
: `Unknown command: agent ${command}`);
|
|
18
|
+
: `Unknown command: config agent ${command}`);
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
function addAgent(args, store) {
|
|
@@ -38,12 +38,12 @@ function addAgent(args, store) {
|
|
|
38
38
|
}
|
|
39
39
|
const created = store.createConfiguredAgentIfAbsent(agent);
|
|
40
40
|
if (created === null) {
|
|
41
|
-
throw usageError(`Agent already exists: ${id}. Use yui agent update to change it.`);
|
|
41
|
+
throw usageError(`Agent already exists: ${id}. Use yui config agent update to change it.`);
|
|
42
42
|
}
|
|
43
43
|
return renderAgent(`Added agent ${id}`, created);
|
|
44
44
|
}
|
|
45
45
|
function listAgents(args, store) {
|
|
46
|
-
assertNoArguments(args, "Agent list usage: yui agent list");
|
|
46
|
+
assertNoArguments(args, "Agent list usage: yui config agent list");
|
|
47
47
|
const agents = store.listConfiguredAgents();
|
|
48
48
|
if (agents.length === 0)
|
|
49
49
|
return "No agents configured.\n";
|
|
@@ -62,7 +62,7 @@ function listAgents(args, store) {
|
|
|
62
62
|
function showAgent(args, store) {
|
|
63
63
|
const [rawId, ...rest] = args;
|
|
64
64
|
const id = agentId(rawId);
|
|
65
|
-
assertNoArguments(rest, "Agent show usage: yui agent show <agent-id>");
|
|
65
|
+
assertNoArguments(rest, "Agent show usage: yui config agent show <agent-id>");
|
|
66
66
|
const agent = store.getConfiguredAgent(id);
|
|
67
67
|
if (agent === null)
|
|
68
68
|
throw agentNotFound(id);
|
|
@@ -137,7 +137,7 @@ function updateAgent(args, store) {
|
|
|
137
137
|
function removeAgent(args, store) {
|
|
138
138
|
const [rawId, ...rest] = args;
|
|
139
139
|
const id = agentId(rawId);
|
|
140
|
-
assertNoArguments(rest, "Agent remove usage: yui agent remove <agent-id>");
|
|
140
|
+
assertNoArguments(rest, "Agent remove usage: yui config agent remove <agent-id>");
|
|
141
141
|
const removed = store.transaction((tx) => {
|
|
142
142
|
if (tx.getConfiguredAgent(id) === null)
|
|
143
143
|
return false;
|