@zq-silk/yui 1.1.2 → 2.1.0

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 (115) hide show
  1. package/ARCHITECTURE.md +2 -1
  2. package/ARCHITECTURE.zh-CN.md +2 -1
  3. package/README.md +2 -0
  4. package/dist/cli/commandCatalog.js +344 -324
  5. package/dist/cli/commandDiscovery.js +69 -0
  6. package/dist/cli/completion.js +22 -227
  7. package/dist/cli/dynamicCompletion.js +12 -6
  8. package/dist/cli/invocationAuthority.js +2 -2
  9. package/dist/cli/invocationRouter.js +18 -7
  10. package/dist/cli/managedDiagnostics.js +2 -1
  11. package/dist/cli/updatePorts.js +0 -5
  12. package/dist/cli.js +184 -130
  13. package/dist/commands/capabilityCommands.js +5 -5
  14. package/dist/commands/controllerCommands.js +2 -1
  15. package/dist/commands/globalRoleCommands.js +86 -44
  16. package/dist/commands/grantCommands.js +48 -8
  17. package/dist/commands/taskCommands.js +157 -196
  18. package/dist/commands/taskContextCommand.js +29 -6
  19. package/dist/commands/taskFactCommands.js +10 -69
  20. package/dist/commands/taskInputCommands.js +26 -35
  21. package/dist/commands/taskPublicationCommands.js +2 -35
  22. package/dist/commands/taskPublicationVerifyCommand.js +1 -2
  23. package/dist/commands/taskUpstreamCommands.js +2 -1
  24. package/dist/context/runContextPack.js +8 -29
  25. package/dist/context/sessionBootstrapManifest.js +5 -101
  26. package/dist/context/taskContext.js +104 -41
  27. package/dist/controller/clientRuntime.js +16 -8
  28. package/dist/controller/fileSchedulerStoreAdapter.js +24 -0
  29. package/dist/controller/runtime.js +6 -0
  30. package/dist/core/controllerClient.js +46 -21
  31. package/dist/core/protocol.js +12 -7
  32. package/dist/doctor/doctor.js +4 -3
  33. package/dist/errors/cliError.js +4 -4
  34. package/dist/errors/cliFailure.js +213 -0
  35. package/dist/executor/fileRoleLaunchPlanner.js +1 -4
  36. package/dist/grant/capabilityGrant.js +13 -0
  37. package/dist/grant/taskAuthorization.js +127 -0
  38. package/dist/kernel/accessAssessment.js +1 -0
  39. package/dist/kernel/builtinCapabilities.js +88 -9
  40. package/dist/kernel/capabilityRegistry.js +64 -19
  41. package/dist/kernel/kernelPorts.js +2 -2
  42. package/dist/nativeAgent/agent.js +173 -0
  43. package/dist/nativeAgent/contracts.js +1 -0
  44. package/dist/nativeAgent/demo.js +29 -0
  45. package/dist/nativeAgent/index.js +3 -0
  46. package/dist/nativeAgent/mockProvider.js +43 -0
  47. package/dist/nativeAgent/textTools.js +156 -0
  48. package/dist/nativeAgent/validation.js +95 -0
  49. package/dist/output/boundedRead.js +118 -0
  50. package/dist/plugins/pluginService.js +98 -8
  51. package/dist/release/releaseWorkflowEngine.js +8 -1
  52. package/dist/resources/projectResourceService.js +23 -1
  53. package/dist/runtime/managedCaller.js +2 -2
  54. package/dist/runtime/managedIdentity.js +6 -0
  55. package/dist/runtime/runtimeCoherence.js +10 -8
  56. package/dist/storage/sqliteSchema.js +10 -0
  57. package/dist/storage/storageVersions.js +1 -1
  58. package/dist/storage/taskStore.js +3 -0
  59. package/dist/surface/surfaceContributions.js +3 -0
  60. package/dist/task/leaderArchive.js +111 -0
  61. package/dist/task/leaderArchiveAuthority.js +24 -0
  62. package/dist/task/taskAuthority.js +5 -10
  63. package/dist/tmux/commandExecutor.js +7 -5
  64. package/dist/web/assets/assetManifest.js +38 -22
  65. package/dist/web/assets/client/api.js +115 -0
  66. package/dist/web/assets/client/app.js +555 -863
  67. package/dist/web/assets/client/components.js +323 -897
  68. package/dist/web/assets/client/detail.js +333 -0
  69. package/dist/web/assets/client/dock.js +225 -0
  70. package/dist/web/assets/client/dom.js +55 -3
  71. package/dist/web/assets/client/evidence.js +172 -0
  72. package/dist/web/assets/client/format.js +25 -14
  73. package/dist/web/assets/client/forms.js +230 -0
  74. package/dist/web/assets/client/i18n.js +1020 -791
  75. package/dist/web/assets/client/overview.js +115 -0
  76. package/dist/web/assets/client/records.js +63 -0
  77. package/dist/web/assets/client/sections.js +313 -0
  78. package/dist/web/assets/client/sidebar.js +117 -0
  79. package/dist/web/assets/client/theme.js +61 -22
  80. package/dist/web/assets/icons.js +39 -0
  81. package/dist/web/assets/shell.js +124 -118
  82. package/dist/web/assets/styles/base.js +41 -0
  83. package/dist/web/assets/styles/components.js +167 -0
  84. package/dist/web/assets/styles/layout.js +49 -77
  85. package/dist/web/assets/styles/markdown.js +16 -24
  86. package/dist/web/assets/styles/responsive.js +33 -44
  87. package/dist/web/assets/styles/tokens.js +65 -89
  88. package/dist/web/assets/styles/views.js +289 -0
  89. package/dist/web/webServer.js +2 -1
  90. package/docs/architecture/README.md +1 -0
  91. package/docs/architecture/README.zh-CN.md +1 -0
  92. package/docs/cli-information-contract.md +107 -0
  93. package/docs/cli-information-contract.zh-CN.md +81 -0
  94. package/docs/managed-turn-and-session-runtime.md +9 -0
  95. package/docs/managed-turn-and-session-runtime.zh-CN.md +6 -0
  96. package/docs/plugin-sdk.md +7 -3
  97. package/docs/plugin-sdk.zh-CN.md +5 -2
  98. package/docs/release-workflow.md +42 -9
  99. package/docs/release-workflow.zh-CN.md +30 -7
  100. package/docs/storage-baseline.md +5 -0
  101. package/docs/testing/verification-levels.md +2 -2
  102. package/i18n/README.zh-CN.md +2 -0
  103. package/package.json +1 -1
  104. package/skills/yui-leader/SKILL.md +8 -1
  105. package/skills/yui-leader/references/authorization.md +64 -0
  106. package/skills/yui-leader/references/execution.md +18 -4
  107. package/skills/yui-leader/references/task-plugins.md +4 -2
  108. package/skills/yui-operator/SKILL.md +9 -2
  109. package/skills/yui-runtime/SKILL.md +77 -9
  110. package/skills/yui-runtime/references/publication.md +3 -1
  111. package/dist/web/assets/client/taskSummary.js +0 -350
  112. package/dist/web/assets/client/taskSurface.js +0 -616
  113. package/dist/web/assets/client/view.js +0 -608
  114. package/dist/web/assets/styles/cards.js +0 -247
  115. package/dist/web/assets/styles/widgets.js +0 -168
@@ -0,0 +1,69 @@
1
+ import { ROOT_COMMAND, findCommandNode } from "./commandCatalog.js";
2
+ import { hasManagedIdentity } from "../runtime/managedIdentity.js";
3
+ /** Offline presentation hints only. Execution still authenticates the original
4
+ * caller, including stale/incomplete identities, at its existing boundary. */
5
+ export function discoveryAudience(env) {
6
+ if (!hasManagedIdentity(env))
7
+ return "public";
8
+ if (!env.YUI_ROLE || !env.YUI_NATIVE_SESSION_ID)
9
+ return "unbound";
10
+ if (env.YUI_SESSION_SCOPE === "global")
11
+ return env.YUI_ROLE === "operator" ? "operator" : "global";
12
+ if (env.YUI_SESSION_SCOPE === "task" && env.YUI_TASK_ID)
13
+ return env.YUI_ROLE === "leader" ? "leader" : "assignment";
14
+ return "unbound";
15
+ }
16
+ export function discoveryCommandTree(env) {
17
+ const audience = discoveryAudience(env);
18
+ const project = (node) => {
19
+ const children = node.children.map(project).filter((child) => child !== undefined);
20
+ const eligible = node.discovery?.surface !== "runtime" && node.discovery?.audiences.includes(audience);
21
+ if (!children.length && (!eligible || node.kind === "group") && node !== ROOT_COMMAND)
22
+ return undefined;
23
+ const executable = eligible && node.kind !== "group";
24
+ const kind = children.length ? executable ? "hybrid" : "group" : node.kind;
25
+ const template = `${node.path.join(" ")}${kind === "group" ? " <command>" : ""}`;
26
+ const omittedOptions = Object.entries(node.discovery?.optionAudiences ?? {})
27
+ .filter(([, audiences]) => !audiences.includes(audience)).map(([option]) => option);
28
+ const text = (value) => omittedOptions.reduce((line, option) => line.replace(new RegExp(`\\s*\\[${option}(?:\\s+[^\\]]*)?\\]`, "g"), ""), value);
29
+ const options = node.options.filter(option => !omittedOptions.includes(option));
30
+ // Group prose often contains concrete commands for several audiences.
31
+ // Generate its usage from the same retained children, not unfiltered text.
32
+ return {
33
+ ...node, children, hidden: false, kind,
34
+ usage: kind === "group" ? [template] : node.usage.map(text),
35
+ examples: kind === "group" ? children.slice(0, 3).map(child => child.usage[0]) : node.examples.map(text),
36
+ options, optionValues: Object.fromEntries(Object.entries(node.optionValues).filter(([option]) => options.includes(option))),
37
+ sections: node.sections.map(section => ({ ...section,
38
+ entries: section.entries.filter(entry => children.some(child => child.name === entry) || (executable && node.values.some(value => value.name === entry)))
39
+ })).filter(section => section.entries.length > 0),
40
+ ...(executable ? {} : { options: [], values: [], optionValues: {}, argumentValues: {} })
41
+ };
42
+ };
43
+ const tree = project(ROOT_COMMAND);
44
+ if (audience === "public") {
45
+ const sections = [
46
+ { id: "start", title: "Start work", entries: ["operator", "project"] },
47
+ { id: "progress", title: "Inspect progress", entries: ["task", "jobs", "execution", "telemetry"] },
48
+ { id: "participate", title: "Participate and control", entries: ["role", "session"] },
49
+ { id: "maintain", title: "Configure and maintain", entries: ["help", "version", "setup", "start", "doctor", "config", "web", "controller", "resources", "update", "upgrade", "release"] }
50
+ ];
51
+ return { ...tree, sections: sections.map(section => ({ ...section,
52
+ entries: section.entries.filter(entry => tree.children.some(child => child.name === entry))
53
+ })) };
54
+ }
55
+ // Help accepts catalog paths, and config describe accepts only retained domains.
56
+ const config = findCommandNode(["config"], tree);
57
+ if (config) {
58
+ const domains = config.children.filter(child => !["show", "describe"].includes(child.name)).map(child => child.name);
59
+ return {
60
+ ...tree, children: tree.children.map(child => child !== config ? child : {
61
+ ...config, children: config.children.map(node => node.name !== "describe" ? node : {
62
+ ...node, argumentValues: { 0: domains }, usage: ["yui config describe [domain]"],
63
+ examples: ["yui config describe"]
64
+ })
65
+ })
66
+ };
67
+ }
68
+ return tree;
69
+ }
@@ -1,235 +1,30 @@
1
- import { ROOT_COMMAND, listPublicCommandPaths, orderedImmediateTokens, visibleChildren } from "./commandCatalog.js";
2
- import { findInteractionPolicy } from "./interactionPolicy.js";
1
+ /** Resolve the current caller on every completion, never the installer's view.
2
+ * Command names are local; target selectors use authenticated scoped reads. */
3
3
  export function renderCompletion(shell) {
4
- const entries = collectEntries(ROOT_COMMAND);
5
4
  switch (shell) {
6
- case "bash": return renderBash(entries);
7
- case "zsh": return renderZsh(entries);
8
- case "fish": return renderFish(entries);
9
- default: throw new Error("Completion shell must be one of bash, zsh, fish.");
10
- }
11
- }
12
- function collectEntries(root) {
13
- const entries = [];
14
- const visit = (node) => {
15
- if (!node.hidden && !node.commandPathArguments) {
16
- const policy = findInteractionPolicy(node);
17
- entries.push({
18
- path: node.path.slice(1).join(" "),
19
- immediate: orderedImmediateTokens(node),
20
- options: node.options,
21
- dynamicArguments: policy?.selectors.flatMap((selector) => selector.argumentIndex === undefined ? [] : [selector.argumentIndex]) ?? [],
22
- dynamicOptions: policy?.selectors.flatMap((selector) => selector.option === undefined ? [] : [selector.option]) ?? []
23
- });
24
- }
25
- visibleChildren(node).forEach(visit);
26
- };
27
- visit(root);
28
- return entries;
29
- }
30
- function manifest(prefix) {
31
- return listPublicCommandPaths().map((path) => `${prefix} ${path}`).join("\n");
32
- }
33
- function renderBash(entries) {
34
- const functionName = "_yui";
35
- return `${manifest("# yui command:")}
36
- ${functionName}() {
37
- local current path previous dynamic_candidate dynamic=false
38
- local -a candidates dynamic_candidates
39
- current="\${COMP_WORDS[COMP_CWORD]}"
40
- path=""
41
- if (( COMP_CWORD > 1 )); then
42
- path="\${COMP_WORDS[*]:1:COMP_CWORD-1}"
43
- fi
44
- previous="\${COMP_WORDS[COMP_CWORD-1]}"
45
- if [[ "$current" != -* ]]; then
46
- case "$COMP_CWORD:$path" in
47
- ${bashDynamicArgumentCases(entries)}
48
- esac
49
- fi
50
- if [[ "$dynamic" == false ]]; then
51
- case "$previous:$path" in
52
- ${bashDynamicOptionCases(entries)}
53
- esac
54
- fi
55
- if [[ "$dynamic" == true ]]; then
56
- while IFS= read -r dynamic_candidate; do
57
- [[ -n "$dynamic_candidate" ]] && dynamic_candidates+=("$dynamic_candidate")
58
- done < <(command yui config completion candidates "$current" -- "\${COMP_WORDS[@]:1:COMP_CWORD-1}" 2>/dev/null)
59
- candidates=("\${dynamic_candidates[@]}")
60
- elif [[ "$current" == -* ]]; then
61
- case "$path" in
62
- ${bashStaticOptionCases(entries)}
63
- *) candidates=();;
64
- esac
65
- else
66
- case "$path" in
67
- ${entries.map((entry) => ` ${bashPattern(entry.path)}) candidates=(${[...entry.immediate, ...entry.options].map(shellQuote).join(" ")});;`).join("\n")}
68
- *) candidates=();;
69
- esac
70
- fi
71
- COMPREPLY=( $(compgen -W "\${candidates[*]}" -- "$current") )
72
- }
73
- complete -F ${functionName} yui
5
+ case "bash": return `_yui() {
6
+ local candidate current="\${COMP_WORDS[COMP_CWORD]}"
7
+ COMPREPLY=()
8
+ while IFS= read -r candidate; do
9
+ [[ -n "$candidate" ]] && COMPREPLY+=("$candidate")
10
+ done < <(command yui config completion candidates "$current" -- "\${COMP_WORDS[@]:1:COMP_CWORD-1}" 2>/dev/null)
11
+ }
12
+ complete -F _yui yui
74
13
  `;
75
- }
76
- function renderZsh(entries) {
77
- return `#compdef yui
78
- ${manifest("# yui command:")}
79
- local current command_path previous dynamic_output dynamic=false
14
+ case "zsh": return `#compdef yui
15
+ local output
80
16
  local -a candidates
81
- current="$words[CURRENT]"
82
- command_path=""
83
- if (( CURRENT > 2 )); then
84
- command_path="\${(j: :)words[2,CURRENT-1]}"
85
- fi
86
- previous="$words[CURRENT-1]"
87
- if [[ "$current" != -* ]]; then
88
- case "$CURRENT:$command_path" in
89
- ${zshDynamicArgumentCases(entries)}
90
- esac
91
- fi
92
- if [[ "$dynamic" == false ]]; then
93
- case "$previous:$command_path" in
94
- ${zshDynamicOptionCases(entries)}
95
- esac
96
- fi
97
- if [[ "$dynamic" == true ]]; then
98
- dynamic_output="$(command yui config completion candidates "$current" -- "\${(@)words[2,CURRENT-1]}" 2>/dev/null)"
99
- candidates=("\${(@f)dynamic_output}")
100
- elif [[ "$current" == -* ]]; then
101
- case "$command_path" in
102
- ${zshStaticOptionCases(entries)}
103
- *) candidates=();;
104
- esac
105
- else
106
- case "$command_path" in
107
- ${entries.map((entry) => ` ${zshPattern(entry.path)}) candidates=(${[...entry.immediate, ...entry.options].map(shellQuote).join(" ")});;`).join("\n")}
108
- *) candidates=();;
109
- esac
110
- fi
17
+ output="$(command yui config completion candidates "$words[CURRENT]" -- "\${(@)words[2,CURRENT-1]}" 2>/dev/null)"
18
+ candidates=("\${(@f)output}")
111
19
  (( \${#candidates[@]} > 0 )) && compadd -- "$candidates[@]"
112
20
  `;
113
- }
114
- function renderFish(entries) {
115
- const prefix = "__yui";
116
- const lines = [
117
- manifest("# yui command:"),
118
- `function ${prefix}_at_path`,
119
- " set -l actual (commandline -opc)",
120
- " set -e actual[1]",
121
- " test (count $actual) -eq (count $argv); or return 1",
122
- " for index in (seq (count $argv))",
123
- " test \"$actual[$index]\" = \"$argv[$index]\"; or return 1",
124
- " end",
125
- "end",
126
- `function ${prefix}_at_command_options`,
127
- " string match -q -- '-*' (commandline -ct); or return 1",
128
- " set -l actual (commandline -opc)",
129
- " set -e actual[1]",
130
- " test (count $actual) -ge (count $argv); or return 1",
131
- " for index in (seq (count $argv))",
132
- " test \"$actual[$index]\" = \"$argv[$index]\"; or return 1",
133
- " end",
134
- "end",
135
- `function ${prefix}_needs_dynamic`,
136
- " set -l mode $argv[1]",
137
- " set -l expected $argv[2]",
138
- " set -l expected_path $argv[3..-1]",
139
- " set -l actual (commandline -opc)",
140
- " set -e actual[1]",
141
- " test (count $actual) -ge (count $expected_path); or return 1",
142
- " for index in (seq (count $expected_path))",
143
- " test \"$actual[$index]\" = \"$expected_path[$index]\"; or return 1",
144
- " end",
145
- " if test \"$mode\" = argument",
146
- " string match -q -- '-*' (commandline -ct); and return 1",
147
- " test (count $actual) -eq \"$expected\"",
148
- " else",
149
- " test \"$actual[-1]\" = \"$expected\"",
150
- " end",
151
- "end",
152
- `function ${prefix}_dynamic`,
153
- " set -l words (commandline -opc)",
154
- " yui config completion candidates (commandline -ct) -- $words[2..-1] 2>/dev/null",
155
- "end"
156
- ];
157
- for (const entry of entries) {
158
- for (const argument of entry.dynamicArguments) {
159
- const condition = `${prefix}_needs_dynamic argument ${argument} ${fishPath(entry.path)}`;
160
- lines.push(`complete -c yui -f -n ${fishQuote(condition)} -a '(${prefix}_dynamic)'`);
161
- }
162
- for (const option of entry.dynamicOptions) {
163
- const condition = `${prefix}_needs_dynamic option ${option} ${fishPath(entry.path)}`;
164
- lines.push(`complete -c yui -f -n ${fishQuote(condition)} -a '(${prefix}_dynamic)'`);
165
- }
166
- }
167
- for (const entry of entries) {
168
- if (entry.immediate.length > 0) {
169
- const condition = entry.path.length === 0
170
- ? "__fish_use_subcommand"
171
- : `${prefix}_at_path ${fishPath(entry.path)}${fishInitialDynamicExclusion(entry, prefix)}`;
172
- lines.push(`complete -c yui -f -n ${fishQuote(condition)} -a '${escapeSingle(entry.immediate.join(" "))}'`);
173
- }
174
- if (entry.options.length > 0) {
175
- const path = fishPath(entry.path);
176
- const exact = `${prefix}_at_path ${path}${fishInitialDynamicExclusion(entry, prefix)}`;
177
- const condition = `begin; ${exact}; end; or ${prefix}_at_command_options ${path}`;
178
- lines.push(`complete -c yui -f -n ${fishQuote(condition)} -a '${escapeSingle(entry.options.join(" "))}'`);
179
- }
21
+ case "fish": return `function __yui_candidates
22
+ set -l words (commandline -opc)
23
+ set -l current (commandline -ct)
24
+ command yui config completion candidates "$current" -- $words[2..-1] 2>/dev/null
25
+ end
26
+ complete -c yui -f -a '(__yui_candidates)'
27
+ `;
28
+ default: throw new Error("Completion shell must be one of bash, zsh, fish.");
180
29
  }
181
- return `${lines.join("\n")}\n`;
182
- }
183
- function bashDynamicArgumentCases(entries) {
184
- return entries.flatMap((entry) => entry.dynamicArguments.map((argument) => ` ${dynamicArgumentPattern(argument + 1, entry.path)}) dynamic=true;;`)).join("\n");
185
- }
186
- function zshDynamicArgumentCases(entries) {
187
- return entries.flatMap((entry) => entry.dynamicArguments.map((argument) => ` ${dynamicArgumentPattern(argument + 2, entry.path)}) dynamic=true;;`)).join("\n");
188
- }
189
- function dynamicArgumentPattern(position, path) {
190
- return `${position}:${shellQuote(path)}|${position}:${shellQuote(`${path} `)}*`;
191
- }
192
- function bashDynamicOptionCases(entries) {
193
- return entries.flatMap((entry) => entry.dynamicOptions.map((option) => ` ${dynamicOptionPattern(option, entry.path)}) dynamic=true;;`)).join("\n");
194
- }
195
- function zshDynamicOptionCases(entries) {
196
- return entries.flatMap((entry) => entry.dynamicOptions.map((option) => ` ${dynamicOptionPattern(option, entry.path)}) dynamic=true;;`)).join("\n");
197
- }
198
- function dynamicOptionPattern(option, path) {
199
- return `${shellQuote(`${option}:${path}`)}|${shellQuote(`${option}:${path} `)}*`;
200
- }
201
- function bashStaticOptionCases(entries) {
202
- return staticOptionEntries(entries).map((entry) => ` ${commandPrefixPattern(entry.path)}) candidates=(${entry.options.map(shellQuote).join(" ")});;`).join("\n");
203
- }
204
- function zshStaticOptionCases(entries) {
205
- return staticOptionEntries(entries).map((entry) => ` ${commandPrefixPattern(entry.path)}) candidates=(${entry.options.map(shellQuote).join(" ")});;`).join("\n");
206
- }
207
- function staticOptionEntries(entries) {
208
- return entries.filter((entry) => entry.options.length > 0)
209
- .sort((left, right) => right.path.split(" ").length - left.path.split(" ").length);
210
- }
211
- function commandPrefixPattern(path) {
212
- return `${shellQuote(path)}|${shellQuote(`${path} `)}*`;
213
- }
214
- function fishInitialDynamicExclusion(entry, prefix) {
215
- const initial = entry.dynamicArguments.filter((position) => position === entry.path.split(" ").filter(Boolean).length);
216
- return initial.map((position) => `; and not ${prefix}_needs_dynamic argument ${position} ${fishPath(entry.path)}`).join("");
217
- }
218
- function fishPath(path) {
219
- return path.split(" ").filter(Boolean).join(" ");
220
- }
221
- function bashPattern(path) {
222
- return path.length === 0 ? '""' : shellQuote(path);
223
- }
224
- function zshPattern(path) {
225
- return path.length === 0 ? '""' : shellQuote(path);
226
- }
227
- function shellQuote(value) {
228
- return `'${escapeSingle(value)}'`;
229
- }
230
- function fishQuote(value) {
231
- return `'${escapeSingle(value)}'`;
232
- }
233
- function escapeSingle(value) {
234
- return value.replaceAll("'", "'\\''");
235
30
  }
@@ -5,7 +5,16 @@ export async function resolveCompletionCandidates(input) {
5
5
  const words = input.words[0] === "yui"
6
6
  ? input.words.slice(1)
7
7
  : [...input.words];
8
- const { node, consumed } = resolveCommand(words);
8
+ const root = input.root ?? ROOT_COMMAND;
9
+ if (words[0] === "help") {
10
+ const { node, consumed } = resolveCommand(words.slice(1), root);
11
+ return consumed === words.length - 1 ? prefix(visibleChildren(node).map(child => child.name), input.current) : [];
12
+ }
13
+ const { node, consumed } = resolveCommand(words, root);
14
+ if (node.kind === "group" && consumed < words.length)
15
+ return [];
16
+ if (input.current.startsWith("-"))
17
+ return prefix(node.options, input.current);
9
18
  if (consumed === words.length && node.children.length > 0) {
10
19
  return prefix(visibleChildren(node).map((child) => child.name), input.current);
11
20
  }
@@ -13,9 +22,6 @@ export async function resolveCompletionCandidates(input) {
13
22
  if (previous !== undefined && Object.hasOwn(node.optionValues, previous)) {
14
23
  return prefix(node.optionValues[previous] ?? [], input.current);
15
24
  }
16
- if (input.current.startsWith("-")) {
17
- return prefix(node.options, input.current);
18
- }
19
25
  const argumentPosition = words.length;
20
26
  const policy = findInteractionPolicy(node);
21
27
  const selector = policy?.selectors.find((candidate) => selectorApplies(candidate, previous, argumentPosition));
@@ -31,8 +37,8 @@ function selectorApplies(selector, previous, argumentPosition) {
31
37
  return selector.option === previous;
32
38
  return selector.argumentIndex === argumentPosition;
33
39
  }
34
- function resolveCommand(words) {
35
- let node = ROOT_COMMAND;
40
+ function resolveCommand(words, root) {
41
+ let node = root;
36
42
  let consumed = 0;
37
43
  while (consumed < words.length && node.kind !== "leaf") {
38
44
  const child = findChild(node, words[consumed] ?? "");
@@ -1,4 +1,5 @@
1
1
  import { usageError } from "../errors/cliError.js";
2
+ import { hasManagedIdentity } from "../runtime/managedIdentity.js";
2
3
  import { requireManagedGlobalCaller } from "../runtime/managedCaller.js";
3
4
  import { routeInvocation } from "./invocationRouter.js";
4
5
  import { findInteractionPolicy } from "./interactionPolicy.js";
@@ -17,8 +18,7 @@ export function assertConfigurationAuthority(args, store, env) {
17
18
  requireManagedGlobalCaller(store, env);
18
19
  return;
19
20
  }
20
- if (env.YUI_SESSION_SCOPE !== undefined || env.YUI_ROLE !== undefined
21
- || env.YUI_AGENT_ID !== undefined || env.YUI_NATIVE_SESSION_ID !== undefined) {
21
+ if (hasManagedIdentity(env)) {
22
22
  throw usageError("Home configuration and resource mutations require the user or current Operator, not a Task Assignment.");
23
23
  }
24
24
  }
@@ -1,16 +1,27 @@
1
1
  import { findChild, ROOT_COMMAND } from "./commandCatalog.js";
2
- export function routeInvocation(args) {
2
+ export function routeInvocation(args, discoveryRoot = ROOT_COMMAND) {
3
3
  if (args.length === 0)
4
4
  return { kind: "execute", node: ROOT_COMMAND };
5
5
  if (args[0] === "help")
6
- return resolveHelpPath(args.slice(1));
7
- return resolveExecutionPath(args);
6
+ return resolveHelpPath(args.slice(1), discoveryRoot);
7
+ const result = resolveExecutionPath(args);
8
+ if (result.kind === "execute" || result.kind === "help")
9
+ return result;
10
+ const path = result.helpNode.path.slice(1);
11
+ let helpNode = discoveryRoot;
12
+ for (const segment of path) {
13
+ const child = findChild(helpNode, segment);
14
+ if (!child)
15
+ break;
16
+ helpNode = child;
17
+ }
18
+ return { ...result, helpNode };
8
19
  }
9
- function resolveHelpPath(path) {
20
+ function resolveHelpPath(path, root) {
10
21
  if (path.length === 0)
11
- return { kind: "help", node: ROOT_COMMAND };
12
- let node = ROOT_COMMAND;
13
- let nearestGroup = ROOT_COMMAND;
22
+ return { kind: "help", node: root };
23
+ let node = root;
24
+ let nearestGroup = root;
14
25
  for (const segment of path) {
15
26
  const child = findChild(node, segment);
16
27
  if (child === undefined || child.hidden) {
@@ -4,7 +4,7 @@ export function taskDiagnosticTarget(args) {
4
4
  if (args[0] !== "task")
5
5
  return undefined;
6
6
  if (["show", "context", "next-action", "archive-preflight"].includes(args[1] ?? "")) {
7
- return args[1] === "context" && ["read", "inspect", "delta"].includes(args[2] ?? "")
7
+ return args[1] === "context" && ["read", "list", "inspect", "delta"].includes(args[2] ?? "")
8
8
  ? args[3] : args[2];
9
9
  }
10
10
  if (args[1] === "role" && ["list", "status", "show"].includes(args[2] ?? ""))
@@ -23,6 +23,7 @@ export function operatorOfflineCommand(args) {
23
23
  || (args[0] === "execution" && args[1] === "audit")
24
24
  || (args[0] === "operator" && ["status", "list"].includes(args[1] ?? ""))
25
25
  || (args[0] === "session" && ["context", "reconcile"].includes(args[1] ?? ""))
26
+ || (args[0] === "role" && args[1] === "message" && ["list", "show"].includes(args[2] ?? ""))
26
27
  || (args[0] === "task" && args[1] === "list")
27
28
  || taskDiagnosticTarget(args) !== undefined;
28
29
  }
@@ -203,11 +203,6 @@ export function createUpdatePorts(environment, spawn = spawnSync, stagingRoot =
203
203
  + `but the staged/verified artifact was ${staged.version}. Refusing to trust a `
204
204
  + "different build than the one that passed preflight.");
205
205
  }
206
- // Retarget current Manifest-referenced wrappers to the activated
207
- // installation before the replacement Controller starts. This relocates
208
- // the current shell form; it does not convert historical Session wrappers.
209
- const sessionCliRefresh = run(activeBinary, ["--json", "internal", "session-cli-refresh"], { cwd: process.cwd(), env: { ...environment, YUI_HOME: home }, shell: false });
210
- assertSpawnOk(sessionCliRefresh, "refresh managed Session CLI wrappers");
211
206
  // Retain the exact path used by both doctor and version verification. The
212
207
  // replacement start must not resolve UPDATE_CLI_PATH or npm again.
213
208
  verifiedActivatedBinary = activeBinary;