@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.
- package/ARCHITECTURE.md +2 -1
- package/ARCHITECTURE.zh-CN.md +2 -1
- package/README.md +2 -0
- package/dist/cli/commandCatalog.js +344 -324
- package/dist/cli/commandDiscovery.js +69 -0
- package/dist/cli/completion.js +22 -227
- package/dist/cli/dynamicCompletion.js +12 -6
- package/dist/cli/invocationAuthority.js +2 -2
- package/dist/cli/invocationRouter.js +18 -7
- package/dist/cli/managedDiagnostics.js +2 -1
- package/dist/cli/updatePorts.js +0 -5
- package/dist/cli.js +184 -130
- package/dist/commands/capabilityCommands.js +5 -5
- package/dist/commands/controllerCommands.js +2 -1
- package/dist/commands/globalRoleCommands.js +86 -44
- package/dist/commands/grantCommands.js +48 -8
- package/dist/commands/taskCommands.js +157 -196
- package/dist/commands/taskContextCommand.js +29 -6
- package/dist/commands/taskFactCommands.js +10 -69
- package/dist/commands/taskInputCommands.js +26 -35
- package/dist/commands/taskPublicationCommands.js +2 -35
- package/dist/commands/taskPublicationVerifyCommand.js +1 -2
- package/dist/commands/taskUpstreamCommands.js +2 -1
- package/dist/context/runContextPack.js +8 -29
- package/dist/context/sessionBootstrapManifest.js +5 -101
- package/dist/context/taskContext.js +104 -41
- package/dist/controller/clientRuntime.js +16 -8
- package/dist/controller/fileSchedulerStoreAdapter.js +24 -0
- package/dist/controller/runtime.js +6 -0
- package/dist/core/controllerClient.js +46 -21
- package/dist/core/protocol.js +12 -7
- package/dist/doctor/doctor.js +4 -3
- package/dist/errors/cliError.js +4 -4
- package/dist/errors/cliFailure.js +213 -0
- package/dist/executor/fileRoleLaunchPlanner.js +1 -4
- package/dist/grant/capabilityGrant.js +13 -0
- package/dist/grant/taskAuthorization.js +127 -0
- package/dist/kernel/accessAssessment.js +1 -0
- package/dist/kernel/builtinCapabilities.js +88 -9
- package/dist/kernel/capabilityRegistry.js +64 -19
- package/dist/kernel/kernelPorts.js +2 -2
- package/dist/nativeAgent/agent.js +173 -0
- package/dist/nativeAgent/contracts.js +1 -0
- package/dist/nativeAgent/demo.js +29 -0
- package/dist/nativeAgent/index.js +3 -0
- package/dist/nativeAgent/mockProvider.js +43 -0
- package/dist/nativeAgent/textTools.js +156 -0
- package/dist/nativeAgent/validation.js +95 -0
- package/dist/output/boundedRead.js +118 -0
- package/dist/plugins/pluginService.js +98 -8
- package/dist/release/releaseWorkflowEngine.js +8 -1
- package/dist/resources/projectResourceService.js +23 -1
- package/dist/runtime/managedCaller.js +2 -2
- package/dist/runtime/managedIdentity.js +6 -0
- package/dist/runtime/runtimeCoherence.js +10 -8
- package/dist/storage/sqliteSchema.js +10 -0
- package/dist/storage/storageVersions.js +1 -1
- package/dist/storage/taskStore.js +3 -0
- package/dist/surface/surfaceContributions.js +3 -0
- package/dist/task/leaderArchive.js +111 -0
- package/dist/task/leaderArchiveAuthority.js +24 -0
- package/dist/task/taskAuthority.js +5 -10
- package/dist/tmux/commandExecutor.js +7 -5
- package/dist/web/assets/assetManifest.js +38 -22
- package/dist/web/assets/client/api.js +115 -0
- package/dist/web/assets/client/app.js +555 -863
- package/dist/web/assets/client/components.js +323 -897
- package/dist/web/assets/client/detail.js +333 -0
- package/dist/web/assets/client/dock.js +225 -0
- package/dist/web/assets/client/dom.js +55 -3
- package/dist/web/assets/client/evidence.js +172 -0
- package/dist/web/assets/client/format.js +25 -14
- package/dist/web/assets/client/forms.js +230 -0
- package/dist/web/assets/client/i18n.js +1020 -791
- package/dist/web/assets/client/overview.js +115 -0
- package/dist/web/assets/client/records.js +63 -0
- package/dist/web/assets/client/sections.js +313 -0
- package/dist/web/assets/client/sidebar.js +117 -0
- package/dist/web/assets/client/theme.js +61 -22
- package/dist/web/assets/icons.js +39 -0
- package/dist/web/assets/shell.js +124 -118
- package/dist/web/assets/styles/base.js +41 -0
- package/dist/web/assets/styles/components.js +167 -0
- package/dist/web/assets/styles/layout.js +49 -77
- package/dist/web/assets/styles/markdown.js +16 -24
- package/dist/web/assets/styles/responsive.js +33 -44
- package/dist/web/assets/styles/tokens.js +65 -89
- package/dist/web/assets/styles/views.js +289 -0
- package/dist/web/webServer.js +2 -1
- package/docs/architecture/README.md +1 -0
- package/docs/architecture/README.zh-CN.md +1 -0
- package/docs/cli-information-contract.md +107 -0
- package/docs/cli-information-contract.zh-CN.md +81 -0
- package/docs/managed-turn-and-session-runtime.md +9 -0
- package/docs/managed-turn-and-session-runtime.zh-CN.md +6 -0
- package/docs/plugin-sdk.md +7 -3
- package/docs/plugin-sdk.zh-CN.md +5 -2
- package/docs/release-workflow.md +42 -9
- package/docs/release-workflow.zh-CN.md +30 -7
- package/docs/storage-baseline.md +5 -0
- package/docs/testing/verification-levels.md +2 -2
- package/i18n/README.zh-CN.md +2 -0
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +8 -1
- package/skills/yui-leader/references/authorization.md +64 -0
- package/skills/yui-leader/references/execution.md +18 -4
- package/skills/yui-leader/references/task-plugins.md +4 -2
- package/skills/yui-operator/SKILL.md +9 -2
- package/skills/yui-runtime/SKILL.md +77 -9
- package/skills/yui-runtime/references/publication.md +3 -1
- package/dist/web/assets/client/taskSummary.js +0 -350
- package/dist/web/assets/client/taskSurface.js +0 -616
- package/dist/web/assets/client/view.js +0 -608
- package/dist/web/assets/styles/cards.js +0 -247
- 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
|
+
}
|
package/dist/cli/completion.js
CHANGED
|
@@ -1,235 +1,30 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
|
|
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
|
-
|
|
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
|
-
|
|
82
|
-
|
|
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
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
"
|
|
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
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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:
|
|
12
|
-
let node =
|
|
13
|
-
let nearestGroup =
|
|
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
|
}
|
package/dist/cli/updatePorts.js
CHANGED
|
@@ -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;
|