@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.
Files changed (49) hide show
  1. package/README.md +42 -23
  2. package/dist/cli/commandCatalog.js +234 -122
  3. package/dist/cli/completion.js +3 -3
  4. package/dist/cli/helpRenderer.js +3 -0
  5. package/dist/cli/interactionPolicy.js +44 -23
  6. package/dist/cli/interactiveSelection.js +1 -1
  7. package/dist/cli/invocationRouter.js +1 -1
  8. package/dist/cli/roleWizard.js +8 -8
  9. package/dist/cli.js +116 -72
  10. package/dist/commands/agentCommands.js +5 -5
  11. package/dist/commands/configCommands.js +351 -104
  12. package/dist/commands/configOverview.js +60 -0
  13. package/dist/commands/deliveryGuardPreflight.js +2 -2
  14. package/dist/commands/globalRoleCommands.js +9 -9
  15. package/dist/commands/profileCommands.js +8 -8
  16. package/dist/commands/resourcesCommands.js +6 -5
  17. package/dist/commands/taskCommands.js +3 -6
  18. package/dist/commands/taskRoleRuntimeStatus.js +3 -1
  19. package/dist/commands/telemetryCommands.js +11 -6
  20. package/dist/config/configCatalog.js +42 -0
  21. package/dist/config/yuiConfig.js +80 -35
  22. package/dist/context/sessionBootstrapManifest.js +1 -1
  23. package/dist/controller/clientRuntime.js +0 -2
  24. package/dist/controller/controller.js +21 -9
  25. package/dist/controller/fileSchedulerStoreAdapter.js +20 -9
  26. package/dist/controller/runtime.js +32 -18
  27. package/dist/coordination/workMailbox.js +25 -22
  28. package/dist/doctor/doctor.js +2 -2
  29. package/dist/resources/autoResourceGc.js +3 -1
  30. package/dist/review/reviewConfig.js +0 -2
  31. package/dist/run/providerRetry.js +29 -16
  32. package/dist/run/providerRetryConfig.js +5 -3
  33. package/dist/runtime/launchDiagnostics.js +1 -1
  34. package/dist/scheduler/roleRunStall.js +12 -9
  35. package/dist/setup/setupCommand.js +153 -492
  36. package/dist/storage/compatibleTaskStore.js +9 -5
  37. package/dist/storage/migration/productionRegistry.js +58 -0
  38. package/dist/storage/sqliteStore.js +9 -2
  39. package/dist/storage/taskStore.js +21 -2
  40. package/dist/telemetry/sqliteTelemetryStore.js +9 -1
  41. package/dist/telemetry/telemetryConfig.js +1 -18
  42. package/dist/telemetry/telemetryStore.js +2 -2
  43. package/dist/telemetry/telemetryWiring.js +6 -5
  44. package/dist/web/webSnapshot.js +5 -3
  45. package/i18n/README.zh-CN.md +37 -32
  46. package/package.json +1 -1
  47. package/skills/yui-leader/SKILL.md +12 -5
  48. package/skills/yui-operator/SKILL.md +44 -6
  49. package/skills/yui-runtime/SKILL.md +1 -1
@@ -1,5 +1,5 @@
1
1
  import { supportedAgentAdapterIds } from "../agent/adapterCatalog.js";
2
- import { CONFIG_KEYS } from "../commands/configCommands.js";
2
+ import { CONFIG_DEFINITIONS, CONFIG_DOMAINS, configDefinitionsForDomain } from "../config/configCatalog.js";
3
3
  function buildNode(input, parentPath = []) {
4
4
  const path = [...parentPath, input.name];
5
5
  const children = (input.children ?? []).map((child) => buildNode(child, path));
@@ -7,12 +7,16 @@ function buildNode(input, parentPath = []) {
7
7
  const usage = input.usage === undefined
8
8
  ? [`${path.join(" ")}${children.length > 0 && !executable ? " <command>" : ""}`]
9
9
  : typeof input.usage === "string" ? [input.usage] : [...input.usage];
10
+ const examples = input.examples === undefined
11
+ ? usage
12
+ : typeof input.examples === "string" ? [input.examples] : [...input.examples];
10
13
  return Object.freeze({
11
14
  name: input.name,
12
15
  path: Object.freeze(path),
13
16
  summary: input.summary,
14
17
  kind: children.length === 0 ? "leaf" : executable ? "hybrid" : "group",
15
18
  usage: Object.freeze(usage),
19
+ examples: Object.freeze(examples),
16
20
  sections: Object.freeze((input.sections ?? []).map((section) => Object.freeze({
17
21
  ...section,
18
22
  entries: Object.freeze([...section.entries])
@@ -37,49 +41,91 @@ function buildNode(input, parentPath = []) {
37
41
  function freezeRecord(record) {
38
42
  return Object.freeze(Object.fromEntries(Object.entries(record ?? {}).map(([key, values]) => [key, Object.freeze([...values])])));
39
43
  }
40
- const CONFIG_KEY_VALUES = [
41
- { name: "time-zone", summary: "IANA timezone for human-facing timestamps (default: Asia/Shanghai)." },
42
- { name: "reconciliation-interval-seconds", summary: "Recovery reconciliation interval, 5-300 seconds (default: 120)." },
43
- { name: "leader-next-action", summary: "Leader next-action mode: display, warn, or enforce (default: display)." },
44
- { name: "context-budget", summary: "Per-Session context token budget; set with --soft-tokens <n> --hard-tokens <n> (default: soft 100000 / hard 120000)." },
45
- { name: "resources-gc-mode", summary: "Resource GC mode: report or quarantine (default: report)." },
46
- { name: "resources-gc-auto-quarantine", summary: "Auto-quarantine terminal Task resources: true or false (default: false)." },
47
- { name: "provider-retry-mode", summary: "Provider retry mode: off, shadow, or enforce (default: enforce)." },
48
- { name: "provider-retry-adapters", summary: "Adapters with in-place retry: all, comma-separated adapter ids, or off (default: all)." },
49
- { name: "provider-retry-max-window-ms", summary: "Total retry budget per Run lineage in milliseconds (default: 600000)." },
50
- { name: "yield-receipt-replay", summary: "Replay committed yield receipts on resend: true or false (default: true)." },
51
- { name: "tmux-bin", summary: "Path to the tmux binary (default: tmux)." },
52
- { name: "git-bin", summary: "Path to the git binary (default: git)." },
53
- { name: "telemetry-mode", summary: "Telemetry mode: legacy, dual, or bounded (default: legacy)." },
54
- { name: "telemetry-terminal-keep", summary: "Telemetry terminal retention count (default: 200)." },
55
- { name: "telemetry-run-cap", summary: "Telemetry per-run row cap (default: 50000)." },
56
- { name: "review", summary: "Global WorkItem review rule; set with --role <global-role> --trigger <always|leader|final> [--finding-ledger <shadow|enforce>] [--delta-recheck <enabled|disabled>] (default: disabled)." }
57
- ];
44
+ const CONFIG_KEY_VALUES = CONFIG_DEFINITIONS.map((definition) => ({
45
+ name: definition.key,
46
+ summary: definition.summary,
47
+ takesEffect: definition.takesEffect
48
+ }));
49
+ const CONFIG_DOMAIN_SUMMARIES = {
50
+ system: "Configure Home-wide defaults and human-facing presentation.",
51
+ runtime: "Configure Controller recovery, concurrency, health, launch, delivery, and Provider retry policy.",
52
+ workflow: "Configure Leader convergence, context, and optional review policy.",
53
+ resources: "Configure resource garbage collection and quarantine policy.",
54
+ tools: "Configure tmux and optional diagnostic telemetry."
55
+ };
56
+ function durableConfigDomainNode(domain) {
57
+ const definitions = configDefinitionsForDomain(domain);
58
+ const keys = definitions.map(({ key }) => key);
59
+ const values = CONFIG_KEY_VALUES.filter(({ name }) => keys.includes(name));
60
+ const options = domain === "workflow"
61
+ ? [
62
+ "--soft-tokens", "--hard-tokens", "--role", "--trigger", "--finding-ledger",
63
+ "--delta-recheck", "--delta-recheck-max-lines", "--delta-recheck-max-files"
64
+ ]
65
+ : domain === "runtime"
66
+ ? ["--quiet-after-seconds", "--diagnostic-after-seconds", "--stall-after-seconds"]
67
+ : [];
68
+ return {
69
+ name: domain,
70
+ summary: CONFIG_DOMAIN_SUMMARIES[domain],
71
+ examples: [
72
+ `yui config ${domain} show`,
73
+ `yui config ${domain} set ${keys[0]} <value>`,
74
+ `yui config ${domain} clear ${keys[0]}`
75
+ ],
76
+ sections: [{ id: "manage", title: "Commands", entries: ["show", "set", "clear"] }],
77
+ children: [
78
+ { name: "show", summary: `Show effective ${domain} configuration.` },
79
+ {
80
+ name: "set",
81
+ summary: `Set one ${domain} configuration key.`,
82
+ usage: `yui config ${domain} set <key> <value...>`,
83
+ sections: [{ id: "keys", title: "Configuration keys", entries: keys }],
84
+ values,
85
+ options,
86
+ optionValues: domain === "workflow"
87
+ ? {
88
+ "--trigger": ["always", "leader", "final"],
89
+ "--finding-ledger": ["shadow", "enforce"],
90
+ "--delta-recheck": ["enabled", "disabled"]
91
+ }
92
+ : {}
93
+ },
94
+ {
95
+ name: "clear",
96
+ summary: `Reset one ${domain} configuration key to its default.`,
97
+ usage: `yui config ${domain} clear <key>`,
98
+ sections: [{ id: "keys", title: "Configuration keys", entries: keys }],
99
+ values
100
+ }
101
+ ]
102
+ };
103
+ }
58
104
  const agentChildren = [
59
105
  {
60
106
  name: "add",
61
107
  summary: "Add a configured native Agent CLI.",
62
- usage: "yui agent add <id> [--adapter <adapter>] --command <command> [--arg <arg> ...] [--env TARGET=PROCESS_NAME ...]",
108
+ usage: "yui config agent add <id> [--adapter <adapter>] --command <command> [--arg <arg> ...] [--env TARGET=PROCESS_NAME ...]",
63
109
  options: ["--adapter", "--command", "--arg", "--env"],
64
110
  optionValues: { "--adapter": supportedAgentAdapterIds() },
65
111
  executableOptions: ["--command"]
66
112
  },
67
113
  { name: "list", summary: "List configured Agents." },
68
- { name: "show", summary: "Show one configured Agent.", usage: "yui agent show <id>" },
114
+ { name: "show", summary: "Show one configured Agent.", usage: "yui config agent show <id>" },
69
115
  {
70
116
  name: "capabilities",
71
117
  summary: "Probe one Agent CLI for runtime configuration options.",
72
- usage: "yui agent capabilities <id>"
118
+ usage: "yui config agent capabilities <id>"
73
119
  },
74
120
  {
75
121
  name: "update",
76
122
  summary: "Update a configured Agent.",
77
- usage: "yui agent update <id> [--adapter <adapter>] [--command <command>] [--arg <arg> ... | --clear-args] [--env TARGET=PROCESS_NAME ... | --clear-env]",
123
+ usage: "yui config agent update <id> [--adapter <adapter>] [--command <command>] [--arg <arg> ... | --clear-args] [--env TARGET=PROCESS_NAME ... | --clear-env]",
78
124
  options: ["--adapter", "--command", "--arg", "--clear-args", "--env", "--clear-env"],
79
125
  optionValues: { "--adapter": supportedAgentAdapterIds() },
80
126
  executableOptions: ["--command"]
81
127
  },
82
- { name: "remove", summary: "Remove a configured Agent.", usage: "yui agent remove <id>" }
128
+ { name: "remove", summary: "Remove a configured Agent.", usage: "yui config agent remove <id>" }
83
129
  ];
84
130
  const roleProfileOptions = [
85
131
  "--description", "--responsibility", "--constraint",
@@ -114,67 +160,83 @@ const roleChildren = [
114
160
  {
115
161
  name: "add",
116
162
  summary: "Add a reusable global Role.",
117
- usage: "yui role add <name> --agent <id> [Role and Agent settings]",
163
+ usage: "yui config role add <name> --agent <id> [Role and Agent settings]",
118
164
  options: ["--agent", "--workspace", ...roleProfileOptions, ...roleAgentOptions],
119
165
  optionValues: roleAgentOptionValues,
120
166
  fileOptions: ["--workspace"]
121
167
  },
122
168
  { name: "list", summary: "List global Roles." },
123
- { name: "show", summary: "Show one global Role.", usage: "yui role show <name>" },
124
- { name: "context", summary: "Load the exact authorized global Role context.", usage: "yui role context <name>" },
169
+ { name: "show", summary: "Show one global Role.", usage: "yui config role show <name>" },
125
170
  {
126
171
  name: "update",
127
172
  summary: "Update a global Role.",
128
- usage: "yui role update <name> [profile options] [clear options]",
173
+ usage: "yui config role update <name> [profile options] [clear options]",
129
174
  options: ["--agent", "--workspace", ...roleProfileOptions, ...roleAgentOptions,
130
175
  ...roleProfileClearOptions, ...roleAgentClearOptions],
131
176
  optionValues: roleAgentOptionValues,
132
177
  fileOptions: ["--workspace"]
133
178
  },
134
- { name: "remove", summary: "Remove a global Role.", usage: "yui role remove <name>" },
135
- { name: "bind", summary: "Bind and activate an Agent for a global Role.", usage: "yui role bind <role> <agent-id>" },
136
- { name: "unbind", summary: "Unbind a dormant Agent from a global Role.", usage: "yui role unbind <role> <agent-id>" },
137
- { name: "enter", summary: "Enter a global Role's native session.", usage: "yui role enter <role>" },
179
+ { name: "remove", summary: "Remove a global Role.", usage: "yui config role remove <name>" },
180
+ { name: "bind", summary: "Bind and activate an Agent for a global Role.", usage: "yui config role bind <role> <agent-id>" },
181
+ { name: "unbind", summary: "Unbind a dormant Agent from a global Role.", usage: "yui config role unbind <role> <agent-id>" }
182
+ ];
183
+ const globalSessionChildren = [
184
+ { name: "enter", summary: "Enter a global Role's native session.", usage: "yui session enter <role>" },
138
185
  {
139
- name: "session",
140
- summary: "Manage native session IDs for a global Role.",
141
- sections: [{ id: "manage", title: "Commands", entries: ["record", "replace"] }],
142
- children: [
143
- {
144
- name: "record",
145
- summary: "Record the active Agent's native session ID.",
146
- usage: "yui role session record <role> --native-id <id>",
147
- options: ["--native-id"]
148
- },
149
- {
150
- name: "replace",
151
- summary: "Explicitly replace the active Agent's native session ID.",
152
- usage: "yui role session replace <role> --native-id <id> --reason <text>",
153
- options: ["--native-id", "--reason"]
154
- }
155
- ]
186
+ name: "context",
187
+ summary: "Load the exact authorized global Role context.",
188
+ usage: "yui session context <role>"
189
+ },
190
+ {
191
+ name: "record",
192
+ summary: "Record the active Agent's native session ID.",
193
+ usage: "yui session record <role> --native-id <id>",
194
+ options: ["--native-id"]
195
+ },
196
+ {
197
+ name: "replace",
198
+ summary: "Explicitly replace the active Agent's native session ID.",
199
+ usage: "yui session replace <role> --native-id <id> --reason <text>",
200
+ options: ["--native-id", "--reason"]
201
+ },
202
+ {
203
+ name: "reconcile",
204
+ summary: "Reconcile durable Session owners with native sessions.",
205
+ usage: "yui session reconcile [--report] [--cleanup]",
206
+ options: ["--report", "--cleanup"]
156
207
  }
157
208
  ];
158
209
  const profileChildren = [
159
210
  {
160
211
  name: "add",
161
212
  summary: "Add a reusable Agent Profile.",
162
- usage: "yui profile add <id> [--access <read|write>] [Profile settings]",
213
+ usage: "yui config profile add <id> [--access <read|write>] [Profile settings]",
163
214
  options: ["--access", ...agentProfileOptions],
164
215
  optionValues: { "--access": ["read", "write"] }
165
216
  },
166
217
  { name: "list", summary: "List Agent Profiles." },
167
- { name: "show", summary: "Show one Agent Profile.", usage: "yui profile show <id>" },
218
+ { name: "show", summary: "Show one Agent Profile.", usage: "yui config profile show <id>" },
168
219
  {
169
220
  name: "update",
170
221
  summary: "Update an Agent Profile.",
171
- usage: "yui profile update <id> [--access <read|write>] [Profile settings]",
222
+ usage: "yui config profile update <id> [--access <read|write>] [Profile settings]",
172
223
  options: ["--access", ...agentProfileOptions, ...agentProfileClearOptions],
173
224
  optionValues: { "--access": ["read", "write"] }
174
225
  },
175
- { name: "remove", summary: "Remove a custom Agent Profile.", usage: "yui profile remove <id>" },
226
+ { name: "remove", summary: "Remove a custom Agent Profile.", usage: "yui config profile remove <id>" },
176
227
  { name: "reset", summary: "Reset all built-in Agent Profiles." }
177
228
  ];
229
+ const completionChildren = [
230
+ { name: "bash", summary: "Interactively configure Bash completion." },
231
+ { name: "zsh", summary: "Interactively configure Zsh completion." },
232
+ { name: "fish", summary: "Interactively configure Fish completion." },
233
+ {
234
+ name: "candidates",
235
+ summary: "Resolve internal dynamic completion candidates.",
236
+ usage: "yui config completion candidates <prefix> -- <words...>",
237
+ hidden: true
238
+ }
239
+ ];
178
240
  const taskChildren = [
179
241
  {
180
242
  name: "create",
@@ -889,13 +951,14 @@ export const ROOT_COMMAND = buildNode({
889
951
  name: "yui",
890
952
  summary: "Coordinate durable, isolated Agent work.",
891
953
  usage: "yui [--json] <command>",
954
+ examples: ["yui setup", "yui operator enter", "yui config show", "yui task list"],
892
955
  sections: [
893
956
  { id: "general", title: "General", entries: [
894
- "help", "version", "update", "upgrade", "setup", "doctor", "completion"
957
+ "help", "version", "update", "upgrade", "setup", "doctor"
895
958
  ] },
896
959
  { id: "workflow", title: "Workflow", entries: ["operator", "project", "task"] },
897
- { id: "configuration", title: "Configuration", entries: ["config", "agent", "profile", "role"] },
898
- { id: "operations", title: "Operations", entries: ["web", "controller", "execution", "job", "jobs", "telemetry", "release"] },
960
+ { id: "configuration", title: "Configuration", entries: ["config"] },
961
+ { id: "operations", title: "Operations", entries: ["web", "controller", "session", "execution", "job", "jobs", "telemetry", "release"] },
899
962
  { id: "resources", title: "Resources", entries: ["resources"] },
900
963
  { id: "internal", title: "Internal", entries: ["internal"] }
901
964
  ],
@@ -909,7 +972,11 @@ export const ROOT_COMMAND = buildNode({
909
972
  usage: "yui upgrade [--dry-run]",
910
973
  options: ["--dry-run"]
911
974
  },
912
- { name: "setup", summary: "Initialize or update Yui configuration." },
975
+ {
976
+ name: "setup",
977
+ summary: "Initialize the minimum Operator and Leader configuration required to execute Tasks.",
978
+ examples: "yui setup"
979
+ },
913
980
  { name: "doctor", summary: "Check Yui dependencies and file state." },
914
981
  {
915
982
  name: "web",
@@ -917,28 +984,6 @@ export const ROOT_COMMAND = buildNode({
917
984
  usage: "yui web [--host <loopback>] [--port <port>]",
918
985
  options: ["--host", "--port"]
919
986
  },
920
- {
921
- name: "completion",
922
- summary: "Interactively configure shell completion.",
923
- executable: true,
924
- acceptsArguments: false,
925
- usage: ["yui completion", "yui completion <bash|zsh|fish>"],
926
- sections: [
927
- { id: "shells", title: "Shells", entries: ["bash", "zsh", "fish"] },
928
- { id: "internal", title: "Internal", entries: ["candidates"] }
929
- ],
930
- children: [
931
- { name: "bash", summary: "Interactively configure Bash completion." },
932
- { name: "zsh", summary: "Interactively configure Zsh completion." },
933
- { name: "fish", summary: "Interactively configure Fish completion." },
934
- {
935
- name: "candidates",
936
- summary: "Resolve internal dynamic completion candidates.",
937
- usage: "yui completion candidates <prefix> -- <words...>",
938
- hidden: true
939
- }
940
- ]
941
- },
942
987
  {
943
988
  name: "controller",
944
989
  summary: "Inspect and recover local Controller runtime resources.",
@@ -1028,29 +1073,78 @@ export const ROOT_COMMAND = buildNode({
1028
1073
  },
1029
1074
  {
1030
1075
  name: "config",
1031
- summary: "Inspect or update Yui configuration.",
1032
- sections: [{ id: "manage", title: "Commands", entries: ["show", "set", "clear"] }],
1076
+ summary: "Inspect, understand, and update all persistent Yui configuration.",
1077
+ examples: [
1078
+ "yui config show",
1079
+ "yui config describe runtime",
1080
+ "yui config workflow show",
1081
+ "yui config agent list",
1082
+ "yui config role show operator",
1083
+ "yui config profile list",
1084
+ "yui config completion"
1085
+ ],
1086
+ sections: [
1087
+ { id: "inspect", title: "Inspect", entries: ["show", "describe"] },
1088
+ { id: "domains", title: "Configuration domains", entries: [
1089
+ ...CONFIG_DOMAINS, "agent", "role", "profile", "completion"
1090
+ ] }
1091
+ ],
1033
1092
  children: [
1034
- { name: "show", summary: "Show effective Yui configuration." },
1035
1093
  {
1036
- name: "set",
1037
- summary: "Set one Yui configuration key.",
1038
- usage: "yui config set <key> <value...>",
1039
- sections: [{ id: "keys", title: "Configuration keys", entries: [...CONFIG_KEYS] }],
1040
- values: CONFIG_KEY_VALUES,
1041
- options: ["--role", "--trigger", "--finding-ledger", "--delta-recheck", "--delta-recheck-max-lines", "--delta-recheck-max-files"],
1042
- optionValues: {
1043
- "--trigger": ["always", "leader", "final"],
1044
- "--finding-ledger": ["shadow", "enforce"],
1045
- "--delta-recheck": ["enabled", "disabled"]
1046
- }
1094
+ name: "show",
1095
+ summary: "Show the complete effective Yui configuration.",
1096
+ examples: ["yui config show", "yui --json config show"]
1047
1097
  },
1048
1098
  {
1049
- name: "clear",
1050
- summary: "Reset one Yui configuration key to its default.",
1051
- usage: "yui config clear <key>",
1052
- sections: [{ id: "keys", title: "Configuration keys", entries: [...CONFIG_KEYS] }],
1053
- values: CONFIG_KEY_VALUES
1099
+ name: "describe",
1100
+ summary: "Explain configuration effects, defaults, choices, and activation behavior.",
1101
+ usage: `yui config describe [${[...CONFIG_DOMAINS, "agent", "role", "profile", "completion"].join("|")}]`,
1102
+ examples: ["yui config describe", "yui --json config describe role"],
1103
+ argumentValues: { 0: [...CONFIG_DOMAINS, "agent", "role", "profile", "completion"] }
1104
+ },
1105
+ ...CONFIG_DOMAINS.map(durableConfigDomainNode),
1106
+ {
1107
+ name: "agent",
1108
+ summary: "Manage configured native Agent CLIs; launch-setting changes require affected Sessions to be stopped.",
1109
+ examples: ["yui config agent list", "yui config agent capabilities codex"],
1110
+ sections: [
1111
+ { id: "inspect", title: "Inspect", entries: ["list", "show", "capabilities"] },
1112
+ { id: "manage", title: "Manage", entries: ["add", "update", "remove"] }
1113
+ ],
1114
+ children: agentChildren
1115
+ },
1116
+ {
1117
+ name: "profile",
1118
+ summary: "Manage reusable Agent Profiles; updates affect future copies and do not rewrite existing Task Roles.",
1119
+ examples: ["yui config profile list", "yui config profile show implementer"],
1120
+ sections: [
1121
+ { id: "inspect", title: "Inspect", entries: ["list", "show"] },
1122
+ { id: "manage", title: "Manage", entries: ["add", "update", "remove", "reset"] }
1123
+ ],
1124
+ children: profileChildren
1125
+ },
1126
+ {
1127
+ name: "role",
1128
+ summary: "Manage reusable global Roles and desired Agent launch configuration for the next compatible Session.",
1129
+ examples: ["yui config role list", "yui config role show operator"],
1130
+ sections: [
1131
+ { id: "inspect", title: "Inspect", entries: ["list", "show"] },
1132
+ { id: "manage", title: "Manage", entries: ["add", "update", "remove", "bind", "unbind"] }
1133
+ ],
1134
+ children: roleChildren
1135
+ },
1136
+ {
1137
+ name: "completion",
1138
+ summary: "Interactively configure shell completion after confirming generated files and startup-file changes.",
1139
+ executable: true,
1140
+ acceptsArguments: false,
1141
+ usage: ["yui config completion", "yui config completion <bash|zsh|fish>"],
1142
+ examples: ["yui config completion", "yui config completion zsh"],
1143
+ sections: [
1144
+ { id: "shells", title: "Shells", entries: ["bash", "zsh", "fish"] },
1145
+ { id: "internal", title: "Internal", entries: ["candidates"] }
1146
+ ],
1147
+ children: completionChildren
1054
1148
  }
1055
1149
  ]
1056
1150
  },
@@ -1207,32 +1301,18 @@ export const ROOT_COMMAND = buildNode({
1207
1301
  ]
1208
1302
  },
1209
1303
  {
1210
- name: "agent",
1211
- summary: "Manage configured native Agent CLIs.",
1212
- sections: [
1213
- { id: "inspect", title: "Inspect", entries: ["list", "show", "capabilities"] },
1214
- { id: "manage", title: "Manage", entries: ["add", "update", "remove"] }
1215
- ],
1216
- children: agentChildren
1217
- },
1218
- {
1219
- name: "profile",
1220
- summary: "Manage reusable Agent Profiles.",
1221
- sections: [
1222
- { id: "inspect", title: "Inspect", entries: ["list", "show"] },
1223
- { id: "manage", title: "Manage", entries: ["add", "update", "remove", "reset"] }
1304
+ name: "session",
1305
+ summary: "Load and enter global Role sessions, and reconcile their durable identities.",
1306
+ examples: [
1307
+ "yui session context operator --json",
1308
+ "yui session enter operator",
1309
+ "yui session reconcile --report"
1224
1310
  ],
1225
- children: profileChildren
1226
- },
1227
- {
1228
- name: "role",
1229
- summary: "Manage reusable global Roles and their native sessions.",
1230
1311
  sections: [
1231
- { id: "inspect", title: "Inspect", entries: ["list", "show", "context"] },
1232
- { id: "manage", title: "Manage", entries: ["add", "update", "remove", "bind", "unbind"] },
1233
- { id: "sessions", title: "Sessions", entries: ["enter", "session"] }
1312
+ { id: "global", title: "Global Role sessions", entries: ["context", "enter", "record", "replace"] },
1313
+ { id: "recovery", title: "Recovery", entries: ["reconcile"] }
1234
1314
  ],
1235
- children: roleChildren
1315
+ children: globalSessionChildren
1236
1316
  },
1237
1317
  {
1238
1318
  name: "task",
@@ -1333,6 +1413,20 @@ export function findCommandNode(path) {
1333
1413
  return node;
1334
1414
  }
1335
1415
  export const findCommand = findCommandNode;
1416
+ /** Structured help projection consumed by `config describe --json` and Operator. */
1417
+ export function describeCommandTree(node) {
1418
+ return {
1419
+ path: node.path.slice(1).join(" "),
1420
+ summary: node.summary,
1421
+ usage: node.usage,
1422
+ examples: node.examples,
1423
+ options: node.options,
1424
+ optionValues: node.optionValues,
1425
+ argumentValues: node.argumentValues,
1426
+ values: node.values,
1427
+ children: visibleChildren(node).map(describeCommandTree)
1428
+ };
1429
+ }
1336
1430
  export function validateCommandCatalog(root) {
1337
1431
  const reservedAliases = new Set(["-h", "--help", "-help", "-v", "--version"]);
1338
1432
  const commandPathProviders = [];
@@ -1341,6 +1435,16 @@ export function validateCommandCatalog(root) {
1341
1435
  throw new Error(`Command summary is required: ${node.path.join(" ")}`);
1342
1436
  if (node.usage.length === 0)
1343
1437
  throw new Error(`Command usage is required: ${node.path.join(" ")}`);
1438
+ if (node.examples.length === 0 || node.examples.some((example) => example.trim().length === 0)) {
1439
+ throw new Error(`Command examples are required: ${node.path.join(" ")}`);
1440
+ }
1441
+ const canonicalPath = node.path.join(" ");
1442
+ for (const example of node.examples) {
1443
+ const normalized = example.replace(/^yui --json(?=\s|$)/, "yui");
1444
+ if (normalized !== canonicalPath && !normalized.startsWith(`${canonicalPath} `)) {
1445
+ throw new Error(`Command example does not match its path: ${canonicalPath}: ${example}`);
1446
+ }
1447
+ }
1344
1448
  if (node.commandPathArguments) {
1345
1449
  commandPathProviders.push(node);
1346
1450
  const ownsOtherCompletionMetadata = node.kind !== "leaf"
@@ -1432,10 +1536,18 @@ export function validateCommandCatalog(root) {
1432
1536
  if (!options.has(option))
1433
1537
  throw new Error(`Executable completion references unknown option: ${[...node.path, option].join(" ")}`);
1434
1538
  }
1539
+ if (new Set(node.workspaceMapOptions).size !== node.workspaceMapOptions.length) {
1540
+ throw new Error(`Duplicate workspace-map completion option: ${node.path.join(" ")}`);
1541
+ }
1542
+ for (const option of node.workspaceMapOptions) {
1543
+ if (!options.has(option))
1544
+ throw new Error(`Workspace-map completion references unknown option: ${[...node.path, option].join(" ")}`);
1545
+ }
1435
1546
  for (const option of options) {
1436
1547
  const owners = Number(Object.hasOwn(node.optionValues, option))
1437
1548
  + Number(node.fileOptions.includes(option))
1438
- + Number(node.executableOptions.includes(option));
1549
+ + Number(node.executableOptions.includes(option))
1550
+ + Number(node.workspaceMapOptions.includes(option));
1439
1551
  if (owners > 1)
1440
1552
  throw new Error(`Multiple completion owners for option: ${[...node.path, option].join(" ")}`);
1441
1553
  }
@@ -55,7 +55,7 @@ ${bashDynamicOptionCases(entries)}
55
55
  if [[ "$dynamic" == true ]]; then
56
56
  while IFS= read -r dynamic_candidate; do
57
57
  [[ -n "$dynamic_candidate" ]] && dynamic_candidates+=("$dynamic_candidate")
58
- done < <(command ${identity} completion candidates "$current" -- "\${COMP_WORDS[@]:1:COMP_CWORD-1}" 2>/dev/null)
58
+ done < <(command ${identity} config completion candidates "$current" -- "\${COMP_WORDS[@]:1:COMP_CWORD-1}" 2>/dev/null)
59
59
  candidates=("\${dynamic_candidates[@]}")
60
60
  elif [[ "$current" == -* ]]; then
61
61
  case "$path" in
@@ -95,7 +95,7 @@ ${zshDynamicOptionCases(entries)}
95
95
  esac
96
96
  fi
97
97
  if [[ "$dynamic" == true ]]; then
98
- dynamic_output="$(command ${identity} completion candidates "$current" -- "\${(@)words[2,CURRENT-1]}" 2>/dev/null)"
98
+ dynamic_output="$(command ${identity} config completion candidates "$current" -- "\${(@)words[2,CURRENT-1]}" 2>/dev/null)"
99
99
  candidates=("\${(@f)dynamic_output}")
100
100
  elif [[ "$current" == -* ]]; then
101
101
  case "$command_path" in
@@ -151,7 +151,7 @@ function renderFish(entries, identity) {
151
151
  "end",
152
152
  `function ${prefix}_dynamic`,
153
153
  " set -l words (commandline -opc)",
154
- ` ${identity} completion candidates (commandline -ct) -- $words[2..-1] 2>/dev/null`,
154
+ ` ${identity} config completion candidates (commandline -ct) -- $words[2..-1] 2>/dev/null`,
155
155
  "end"
156
156
  ];
157
157
  for (const entry of entries) {
@@ -15,6 +15,9 @@ export function renderCommandHelp(node, version) {
15
15
  const width = Math.max(...node.options.map((option) => option.length));
16
16
  lines.push("", "Options:", ...node.options.map((option) => ` ${option.padEnd(width)} ${describeOption(option)}`));
17
17
  }
18
+ if (node.examples.length > 0) {
19
+ lines.push("", "Examples:", ...node.examples.map((example) => ` ${example}`));
20
+ }
18
21
  return `${lines.join("\n")}\n`;
19
22
  }
20
23
  function describeOption(option) {