@zq-silk/yui 0.7.0 → 0.8.1
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/README.md +42 -23
- package/dist/cli/commandCatalog.js +234 -122
- package/dist/cli/completion.js +3 -3
- package/dist/cli/helpRenderer.js +3 -0
- package/dist/cli/interactionPolicy.js +44 -23
- package/dist/cli/interactiveSelection.js +1 -1
- package/dist/cli/invocationRouter.js +1 -1
- package/dist/cli/roleWizard.js +8 -8
- package/dist/cli.js +116 -72
- 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 +3 -6
- 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 +20 -9
- package/dist/controller/runtime.js +32 -18
- package/dist/coordination/workMailbox.js +25 -22
- package/dist/doctor/doctor.js +2 -2
- package/dist/resources/autoResourceGc.js +3 -1
- package/dist/review/reviewConfig.js +0 -2
- package/dist/run/providerRetry.js +29 -16
- package/dist/run/providerRetryConfig.js +5 -3
- package/dist/runtime/launchDiagnostics.js +1 -1
- 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 +58 -0
- package/dist/storage/sqliteStore.js +9 -2
- package/dist/storage/taskStore.js +21 -2
- 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/web/webSnapshot.js +5 -3
- package/i18n/README.zh-CN.md +37 -32
- 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
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { findCommandNode } from "./commandCatalog.js";
|
|
1
2
|
const taskTarget = (command, argumentIndex = 2, statuses) => ({
|
|
2
3
|
commandPath: ["task", command],
|
|
3
4
|
selectors: [{
|
|
@@ -47,7 +48,7 @@ export const INTERACTION_POLICIES = Object.freeze([
|
|
|
47
48
|
"--development": "value"
|
|
48
49
|
}
|
|
49
50
|
},
|
|
50
|
-
...["add", "
|
|
51
|
+
...["add", "retire", "list", "show"].map((command) => ({
|
|
51
52
|
commandPath: ["project", "knowledge", command],
|
|
52
53
|
selectors: [{
|
|
53
54
|
argumentIndex: 3,
|
|
@@ -57,26 +58,24 @@ export const INTERACTION_POLICIES = Object.freeze([
|
|
|
57
58
|
}],
|
|
58
59
|
...(command === "add"
|
|
59
60
|
? { trailingOptions: { "--body": "value" } }
|
|
60
|
-
: command === "
|
|
61
|
-
? { trailingOptions: { "--
|
|
62
|
-
:
|
|
63
|
-
? { trailingOptions: { "--all": "flag" } }
|
|
64
|
-
: {})
|
|
61
|
+
: command === "list"
|
|
62
|
+
? { trailingOptions: { "--all": "flag" } }
|
|
63
|
+
: {})
|
|
65
64
|
})),
|
|
66
65
|
...["show", "capabilities", "update", "remove"].map((command) => ({
|
|
67
|
-
commandPath: ["agent", command],
|
|
66
|
+
commandPath: ["config", "agent", command],
|
|
68
67
|
selectors: [{
|
|
69
|
-
argumentIndex:
|
|
68
|
+
argumentIndex: 3,
|
|
70
69
|
entity: "agent",
|
|
71
70
|
provider: "configured-agents",
|
|
72
71
|
actionTarget: true
|
|
73
72
|
}],
|
|
74
73
|
...(command === "remove"
|
|
75
|
-
? { confirmation: { action: "Remove Agent", targetArgumentIndex:
|
|
74
|
+
? { confirmation: { action: "Remove Agent", targetArgumentIndex: 3 } }
|
|
76
75
|
: {})
|
|
77
76
|
})),
|
|
78
77
|
{
|
|
79
|
-
commandPath: ["role", "add"],
|
|
78
|
+
commandPath: ["config", "role", "add"],
|
|
80
79
|
selectors: [{
|
|
81
80
|
option: "--agent",
|
|
82
81
|
requiredOption: true,
|
|
@@ -93,29 +92,31 @@ export const INTERACTION_POLICIES = Object.freeze([
|
|
|
93
92
|
"--search": "value"
|
|
94
93
|
}
|
|
95
94
|
},
|
|
96
|
-
...["show", "update", "remove", "enter"].map((command) => ({
|
|
97
|
-
commandPath:
|
|
95
|
+
...["show", "update", "remove", "enter", "context"].map((command) => ({
|
|
96
|
+
commandPath: command === "enter" || command === "context"
|
|
97
|
+
? ["session", command]
|
|
98
|
+
: ["config", "role", command],
|
|
98
99
|
selectors: [{
|
|
99
|
-
argumentIndex: 2,
|
|
100
|
+
argumentIndex: command === "enter" || command === "context" ? 2 : 3,
|
|
100
101
|
entity: "global-role",
|
|
101
102
|
provider: "global-roles",
|
|
102
103
|
actionTarget: true
|
|
103
104
|
}],
|
|
104
105
|
...(command === "remove"
|
|
105
|
-
? { confirmation: { action: "Remove Role", targetArgumentIndex:
|
|
106
|
+
? { confirmation: { action: "Remove Role", targetArgumentIndex: 3 } }
|
|
106
107
|
: {})
|
|
107
108
|
})),
|
|
108
109
|
...["bind", "unbind"].map((command) => ({
|
|
109
|
-
commandPath: ["role", command],
|
|
110
|
+
commandPath: ["config", "role", command],
|
|
110
111
|
selectors: [
|
|
111
|
-
{ argumentIndex:
|
|
112
|
-
{ argumentIndex:
|
|
112
|
+
{ argumentIndex: 3, entity: "global-role", provider: "global-roles", actionTarget: true },
|
|
113
|
+
{ argumentIndex: 4, entity: "agent", provider: "configured-agents", actionTarget: false }
|
|
113
114
|
]
|
|
114
115
|
})),
|
|
115
116
|
...["record", "replace"].map((command) => ({
|
|
116
|
-
commandPath: ["
|
|
117
|
+
commandPath: ["session", command],
|
|
117
118
|
selectors: [{
|
|
118
|
-
argumentIndex:
|
|
119
|
+
argumentIndex: 2,
|
|
119
120
|
entity: "global-role",
|
|
120
121
|
provider: "global-roles",
|
|
121
122
|
actionTarget: true
|
|
@@ -125,7 +126,7 @@ export const INTERACTION_POLICIES = Object.freeze([
|
|
|
125
126
|
: { "--native-id": "value" }
|
|
126
127
|
})),
|
|
127
128
|
{
|
|
128
|
-
commandPath: ["profile", "add"],
|
|
129
|
+
commandPath: ["config", "profile", "add"],
|
|
129
130
|
selectors: [],
|
|
130
131
|
trailingOptions: {
|
|
131
132
|
"--description": "value", "--instructions": "value",
|
|
@@ -133,9 +134,9 @@ export const INTERACTION_POLICIES = Object.freeze([
|
|
|
133
134
|
}
|
|
134
135
|
},
|
|
135
136
|
...["show", "update", "remove"].map((command) => ({
|
|
136
|
-
commandPath: ["profile", command],
|
|
137
|
+
commandPath: ["config", "profile", command],
|
|
137
138
|
selectors: [{
|
|
138
|
-
argumentIndex:
|
|
139
|
+
argumentIndex: 3,
|
|
139
140
|
entity: "agent-profile",
|
|
140
141
|
provider: "agent-profiles",
|
|
141
142
|
actionTarget: true
|
|
@@ -151,7 +152,7 @@ export const INTERACTION_POLICIES = Object.freeze([
|
|
|
151
152
|
}
|
|
152
153
|
: {}),
|
|
153
154
|
...(command === "remove"
|
|
154
|
-
? { confirmation: { action: "Remove Agent Profile", targetArgumentIndex:
|
|
155
|
+
? { confirmation: { action: "Remove Agent Profile", targetArgumentIndex: 3 } }
|
|
155
156
|
: {})
|
|
156
157
|
})),
|
|
157
158
|
taskTarget("show"),
|
|
@@ -630,10 +631,30 @@ export function validateInteractionPolicies(policies = INTERACTION_POLICIES) {
|
|
|
630
631
|
if (paths.has(path))
|
|
631
632
|
throw new Error(`Duplicate interaction policy: ${path}`);
|
|
632
633
|
paths.add(path);
|
|
634
|
+
const node = findCommandNode(policy.commandPath);
|
|
635
|
+
if (node === undefined || node.hidden) {
|
|
636
|
+
throw new Error(`Interaction policy references an unknown command: ${path}`);
|
|
637
|
+
}
|
|
633
638
|
for (const selector of policy.selectors) {
|
|
634
639
|
if ((selector.argumentIndex === undefined) === (selector.option === undefined)) {
|
|
635
640
|
throw new Error(`Interaction selector must declare exactly one slot: ${path}`);
|
|
636
641
|
}
|
|
642
|
+
if (selector.argumentIndex !== undefined && (!Number.isInteger(selector.argumentIndex)
|
|
643
|
+
|| selector.argumentIndex < node.path.length - 1)) {
|
|
644
|
+
throw new Error(`Interaction selector has an invalid argument index: ${path}`);
|
|
645
|
+
}
|
|
646
|
+
if (selector.option !== undefined && !node.options.includes(selector.option)) {
|
|
647
|
+
throw new Error(`Interaction selector references an unknown option: ${path} ${selector.option}`);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
for (const option of Object.keys(policy.trailingOptions ?? {})) {
|
|
651
|
+
if (!node.options.includes(option)) {
|
|
652
|
+
throw new Error(`Interaction policy references an unknown trailing option: ${path} ${option}`);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
if (policy.confirmation !== undefined && !policy.selectors.some((selector) => selector.argumentIndex === policy.confirmation?.targetArgumentIndex
|
|
656
|
+
&& selector.actionTarget)) {
|
|
657
|
+
throw new Error(`Interaction confirmation has no action target selector: ${path}`);
|
|
637
658
|
}
|
|
638
659
|
}
|
|
639
660
|
}
|
|
@@ -53,7 +53,7 @@ export async function resolveInteractiveArguments(args, node, ports, io) {
|
|
|
53
53
|
}
|
|
54
54
|
export function allowsInteractiveSelection(args, globalJson) {
|
|
55
55
|
return !globalJson && !args.includes("--json")
|
|
56
|
-
&& !(args[0] === "
|
|
56
|
+
&& !(args[0] === "config" && args[1] === "completion" && args[2] === "candidates");
|
|
57
57
|
}
|
|
58
58
|
function missingSlot(args, selector, node) {
|
|
59
59
|
if (selector.argumentIndex !== undefined) {
|
|
@@ -31,7 +31,7 @@ function resolveExecutionPath(args) {
|
|
|
31
31
|
break;
|
|
32
32
|
const child = findChild(node, args[index] ?? "");
|
|
33
33
|
const internalExecutable = child !== undefined && ((node === ROOT_COMMAND && child.name === "internal")
|
|
34
|
-
|| (node.path.join(" ") === "yui completion" && child.name === "candidates")
|
|
34
|
+
|| (node.path.join(" ") === "yui config completion" && child.name === "candidates")
|
|
35
35
|
|| (node.path.join(" ") === "yui task run" && child.name === "checkpoint")
|
|
36
36
|
|| (node.path.join(" ") === "yui controller"
|
|
37
37
|
&& (child.name === "identity" || child.name === "live-identity")));
|
package/dist/cli/roleWizard.js
CHANGED
|
@@ -20,7 +20,7 @@ export async function resolveRoleWizardArguments(commandArgs, ports, io) {
|
|
|
20
20
|
return { kind: "unchanged", args };
|
|
21
21
|
}
|
|
22
22
|
export async function resolveGlobalRoleAgentConfigurationArguments(roleName, agentId, ports, io) {
|
|
23
|
-
const args = ["role", "update", roleName];
|
|
23
|
+
const args = ["config", "role", "update", roleName];
|
|
24
24
|
if (!io.interactive || io.json)
|
|
25
25
|
return { kind: "unchanged", args };
|
|
26
26
|
const role = asRole(await ports.call("role.show", { name: roleName }));
|
|
@@ -31,7 +31,7 @@ export async function resolveGlobalRoleAgentConfigurationArguments(roleName, age
|
|
|
31
31
|
return updateAgentBindingSettings(args, role, binding, ports, io);
|
|
32
32
|
}
|
|
33
33
|
function isGlobalRoleAdd(args) {
|
|
34
|
-
return args[0] === "
|
|
34
|
+
return args[0] === "config" && args[1] === "role" && args[2] === "add";
|
|
35
35
|
}
|
|
36
36
|
function isTaskRoleAdd(args) {
|
|
37
37
|
return args[0] === "task" && args[1] === "role" && args[2] === "add";
|
|
@@ -39,18 +39,18 @@ function isTaskRoleAdd(args) {
|
|
|
39
39
|
// Explicit update options always win. This keeps scripts and deliberate
|
|
40
40
|
// non-interactive invocations out of the wizard even when run from a TTY.
|
|
41
41
|
function isGlobalRoleUpdate(args) {
|
|
42
|
-
return args.length ===
|
|
43
|
-
&& isValue(args[
|
|
42
|
+
return args.length === 4 && args[0] === "config" && args[1] === "role"
|
|
43
|
+
&& args[2] === "update" && isValue(args[3]);
|
|
44
44
|
}
|
|
45
45
|
function isTaskRoleUpdate(args) {
|
|
46
46
|
return args.length === 5 && args[0] === "task" && args[1] === "role"
|
|
47
47
|
&& args[2] === "update" && isValue(args[3]) && isValue(args[4]);
|
|
48
48
|
}
|
|
49
49
|
async function addGlobalRole(args, ports, io) {
|
|
50
|
-
const named = await ensureRoleName(args,
|
|
50
|
+
const named = await ensureRoleName(args, 3, io);
|
|
51
51
|
if (named === undefined)
|
|
52
52
|
return { kind: "cancelled", args };
|
|
53
|
-
const explicitSettings = hasExplicitAddSettings(named,
|
|
53
|
+
const explicitSettings = hasExplicitAddSettings(named, 4);
|
|
54
54
|
const agents = await loadAgentSelection(ports);
|
|
55
55
|
const explicitAgent = optionValue(named, "--agent");
|
|
56
56
|
const selected = explicitAgent ?? await selectConfiguredAgent(ports, io, "Create Global Role from Agent", agents);
|
|
@@ -236,7 +236,7 @@ async function configureNewAgentField(args, agent, ports, io) {
|
|
|
236
236
|
: { kind: "resolved", args: [...args, selected.set, value] };
|
|
237
237
|
}
|
|
238
238
|
async function updateGlobalRole(args, ports, io) {
|
|
239
|
-
const role = asRole(await ports.call("role.show", { name: args[
|
|
239
|
+
const role = asRole(await ports.call("role.show", { name: args[3] }));
|
|
240
240
|
if (role === undefined)
|
|
241
241
|
return { kind: "unchanged", args };
|
|
242
242
|
return updateRole(args, role, ports, io, false);
|
|
@@ -286,7 +286,7 @@ async function updateRoleSettings(args, role, ports, io, taskRole) {
|
|
|
286
286
|
return { kind: "cancelled", args };
|
|
287
287
|
return taskRole
|
|
288
288
|
? { kind: "resolved", args: ["task", "role", "bind", args[3] ?? "", args[4] ?? "", target] }
|
|
289
|
-
: { kind: "resolved", args: ["role", "bind", args[
|
|
289
|
+
: { kind: "resolved", args: ["config", "role", "bind", args[3] ?? "", target] };
|
|
290
290
|
}
|
|
291
291
|
if (field === "workspace") {
|
|
292
292
|
const value = (await io.question(`Workspace [${roleDisplay(role.workspace)}]: `))?.trim();
|
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";
|
|
@@ -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;
|
|
@@ -1659,7 +1703,7 @@ async function deltaRecheckPreflightForTaskCommand(args, store, actualTaskReview
|
|
|
1659
1703
|
const config = store.getReviewConfig();
|
|
1660
1704
|
if (!deltaRecheckEnabled(config)) {
|
|
1661
1705
|
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` "
|
|
1706
|
+
+ "Set `yui config workflow set review --role <role> --trigger final --delta-recheck enabled` "
|
|
1663
1707
|
+ "or request a full Review.");
|
|
1664
1708
|
}
|
|
1665
1709
|
const reviewConfig = config;
|
|
@@ -1809,7 +1853,7 @@ async function executeOperatorSessionControl(control, home, store, runtime, tmux
|
|
|
1809
1853
|
process.stdout.write("Cancelled.\n");
|
|
1810
1854
|
return;
|
|
1811
1855
|
}
|
|
1812
|
-
const updated = runGlobalRoleCommand(resolution.args.slice(
|
|
1856
|
+
const updated = runGlobalRoleCommand(resolution.args.slice(2), store, { yuiHome: home, env: process.env });
|
|
1813
1857
|
if (typeof updated !== "string") {
|
|
1814
1858
|
throw new Error("Operator Agent configuration returned an invalid control result.");
|
|
1815
1859
|
}
|
|
@@ -1865,11 +1909,11 @@ function renderControllerResult(method, value) {
|
|
|
1865
1909
|
: "Controller was already stopped.";
|
|
1866
1910
|
}
|
|
1867
1911
|
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...>");
|
|
1912
|
+
if (args[2] === "candidates") {
|
|
1913
|
+
const separator = args.indexOf("--", 4);
|
|
1914
|
+
const prefix = args[3];
|
|
1915
|
+
if (prefix === undefined || separator !== 4) {
|
|
1916
|
+
throw usageError("Completion candidates usage: yui config completion candidates <prefix> -- <words...>");
|
|
1873
1917
|
}
|
|
1874
1918
|
const candidates = await resolveCompletionCandidates({
|
|
1875
1919
|
current: prefix,
|
|
@@ -1884,9 +1928,9 @@ async function completionCommand(home, node) {
|
|
|
1884
1928
|
if (process.stdin.isTTY !== true || process.stdout.isTTY !== true) {
|
|
1885
1929
|
throw usageError("Completion configuration requires an interactive terminal.");
|
|
1886
1930
|
}
|
|
1887
|
-
const shell = completionShell(args[
|
|
1888
|
-
if (args.length > (shell === undefined ?
|
|
1889
|
-
throw usageError("Completion usage: yui completion [bash|zsh|fish]");
|
|
1931
|
+
const shell = completionShell(args[2]);
|
|
1932
|
+
if (args.length > (shell === undefined ? 2 : 3)) {
|
|
1933
|
+
throw usageError("Completion usage: yui config completion [bash|zsh|fish]");
|
|
1890
1934
|
}
|
|
1891
1935
|
const store = openCompatibleFileTaskStore(home);
|
|
1892
1936
|
const ioHandle = terminalIo();
|
|
@@ -1921,7 +1965,7 @@ async function resolveTerminalArguments(commandArgs, node, store, catalogs) {
|
|
|
1921
1965
|
// Global Role add owns its Agent choice so the configured default can be
|
|
1922
1966
|
// shown explicitly. Other commands first resolve missing positional
|
|
1923
1967
|
// targets through the generic selector, then enter the focused Role UI.
|
|
1924
|
-
if ((operatorArgs[0] === "
|
|
1968
|
+
if ((operatorArgs[0] === "config" && operatorArgs[1] === "role" && operatorArgs[2] === "add")
|
|
1925
1969
|
|| (operatorArgs[0] === "task" && operatorArgs[1] === "role" && operatorArgs[2] === "add")) {
|
|
1926
1970
|
const wizard = await resolveRoleWizardArguments(operatorArgs, ports, handle.io);
|
|
1927
1971
|
if (wizard.kind === "cancelled")
|
|
@@ -1983,7 +2027,7 @@ async function preflightAgentConfigurationMutation(commandArgs, store, catalogs)
|
|
|
1983
2027
|
});
|
|
1984
2028
|
}
|
|
1985
2029
|
function hasModelOrEffortMutation(args) {
|
|
1986
|
-
const operation = args[0] === "role"
|
|
2030
|
+
const operation = (args[0] === "config" && args[1] === "role")
|
|
1987
2031
|
|| (args[0] === "task" && args[1] === "role");
|
|
1988
2032
|
return operation && [
|
|
1989
2033
|
"--model", "--effort", "--clear-model", "--clear-effort"
|
|
@@ -1993,8 +2037,8 @@ function configurationMutationAgentId(args, store) {
|
|
|
1993
2037
|
const explicit = optionValue(args, "--agent");
|
|
1994
2038
|
if (explicit !== undefined)
|
|
1995
2039
|
return explicit;
|
|
1996
|
-
if (args[0] === "
|
|
1997
|
-
return store.getGlobalRole(args[
|
|
2040
|
+
if (args[0] === "config" && args[1] === "role" && args[2] === "update") {
|
|
2041
|
+
return store.getGlobalRole(args[3] ?? "")?.activeAgentId;
|
|
1998
2042
|
}
|
|
1999
2043
|
if (args[0] === "task" && args[1] === "role") {
|
|
2000
2044
|
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;
|