@zq-silk/yui 2.0.0 → 2.2.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/README.md +4 -0
- package/dist/cli/commandCatalog.js +318 -289
- package/dist/cli/commandDiscovery.js +72 -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.js +23 -3030
- package/dist/commands/capabilityCommands.js +5 -5
- package/dist/commands/globalRoleCommands.js +2 -1
- package/dist/commands/taskCommands.js +90 -21
- package/dist/commands/taskIntegrationCommands.js +3 -1
- package/dist/commands/taskUpstreamCommands.js +3 -1
- package/dist/context/runContextPack.js +132 -5
- package/dist/context/sourceRunContext.js +4 -2
- package/dist/context/taskContext.js +12 -3
- package/dist/controlPlaneCli.js +3092 -0
- package/dist/controller/fileSchedulerStoreAdapter.js +19 -6
- package/dist/controller/jobControl.js +21 -0
- package/dist/executor/agentExecutor.js +1 -1
- package/dist/executor/effectiveLaunch.js +18 -5
- package/dist/executor/fileRoleLaunchPlanner.js +15 -19
- package/dist/integration/gitIntegrationService.js +50 -15
- package/dist/kernel/accessAssessment.js +1 -0
- package/dist/kernel/builtinCapabilities.js +28 -1
- package/dist/kernel/capabilityRegistry.js +64 -19
- package/dist/message/messageContinuation.js +7 -2
- package/dist/nativeAgent/agent.js +275 -0
- package/dist/nativeAgent/cliDemo.js +37 -0
- package/dist/nativeAgent/codingTools.js +11 -0
- package/dist/nativeAgent/commandTool.js +215 -0
- package/dist/nativeAgent/compactionDemo.js +158 -0
- package/dist/nativeAgent/composition.js +71 -0
- package/dist/nativeAgent/context/budget.js +44 -0
- package/dist/nativeAgent/context/index.js +339 -0
- package/dist/nativeAgent/context/providerCompressor.js +103 -0
- package/dist/nativeAgent/contracts.js +1 -0
- package/dist/nativeAgent/demo.js +40 -0
- package/dist/nativeAgent/evaluation/cases.js +38 -0
- package/dist/nativeAgent/evaluation/checks.js +91 -0
- package/dist/nativeAgent/evaluation/demo.js +19 -0
- package/dist/nativeAgent/evaluation/files.js +54 -0
- package/dist/nativeAgent/evaluation/fixture.js +36 -0
- package/dist/nativeAgent/evaluation/index.js +239 -0
- package/dist/nativeAgent/executionOwner.js +209 -0
- package/dist/nativeAgent/filePatterns.js +170 -0
- package/dist/nativeAgent/fileToolsSupport.js +202 -0
- package/dist/nativeAgent/index.js +16 -0
- package/dist/nativeAgent/interaction/cli.js +358 -0
- package/dist/nativeAgent/interaction/contracts.js +1 -0
- package/dist/nativeAgent/interaction/index.js +3 -0
- package/dist/nativeAgent/interaction/memoryDemo.js +115 -0
- package/dist/nativeAgent/interaction/renderer.js +34 -0
- package/dist/nativeAgent/localSafety.js +258 -0
- package/dist/nativeAgent/mockProvider.js +43 -0
- package/dist/nativeAgent/model/anthropicMessages.js +204 -0
- package/dist/nativeAgent/model/chatCompletions.js +210 -0
- package/dist/nativeAgent/model/errors.js +47 -0
- package/dist/nativeAgent/model/gateway.js +423 -0
- package/dist/nativeAgent/model/index.js +7 -0
- package/dist/nativeAgent/model/observationAdapter.js +21 -0
- package/dist/nativeAgent/model/protocols.js +19 -0
- package/dist/nativeAgent/model/responses.js +263 -0
- package/dist/nativeAgent/model/types.js +1 -0
- package/dist/nativeAgent/model/wire.js +73 -0
- package/dist/nativeAgent/observability/index.js +220 -0
- package/dist/nativeAgent/product/catalog.js +82 -0
- package/dist/nativeAgent/product/config.js +295 -0
- package/dist/nativeAgent/product/facts.js +30 -0
- package/dist/nativeAgent/product/index.js +62 -0
- package/dist/nativeAgent/product/location.js +44 -0
- package/dist/nativeAgent/product/runtime.js +276 -0
- package/dist/nativeAgent/product/storage.js +49 -0
- package/dist/nativeAgent/product/tools.js +47 -0
- package/dist/nativeAgent/product/transport.js +54 -0
- package/dist/nativeAgent/projectGuidance/index.js +425 -0
- package/dist/nativeAgent/searchTools.js +305 -0
- package/dist/nativeAgent/session/backends.js +293 -0
- package/dist/nativeAgent/session/catalog.js +97 -0
- package/dist/nativeAgent/session/catalogDemo.js +87 -0
- package/dist/nativeAgent/session/contracts.js +1 -0
- package/dist/nativeAgent/session/format.js +269 -0
- package/dist/nativeAgent/session/index.js +5 -0
- package/dist/nativeAgent/session/location.js +36 -0
- package/dist/nativeAgent/session/sqliteFormat.js +134 -0
- package/dist/nativeAgent/session/store.js +248 -0
- package/dist/nativeAgent/textTools.js +293 -0
- package/dist/nativeAgent/toolManager/executor.js +290 -0
- package/dist/nativeAgent/toolManager/index.js +4 -0
- package/dist/nativeAgent/validation.js +95 -0
- package/dist/plugins/pluginService.js +98 -8
- package/dist/resources/projectResourceService.js +23 -1
- package/dist/runtime/managedIdentity.js +6 -0
- package/dist/surface/surfaceContributions.js +3 -0
- package/dist/task/taskAuthority.js +61 -10
- package/dist/web/assets/assetManifest.js +38 -22
- package/dist/web/assets/client/api.js +115 -0
- package/dist/web/assets/client/app.js +615 -862
- 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 +1024 -791
- package/dist/web/assets/client/overview.js +118 -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 +146 -0
- package/dist/web/assets/client/theme.js +61 -22
- package/dist/web/assets/icons.js +39 -0
- package/dist/web/assets/shell.js +125 -118
- package/dist/web/assets/styles/base.js +41 -0
- package/dist/web/assets/styles/components.js +169 -0
- package/dist/web/assets/styles/layout.js +56 -77
- package/dist/web/assets/styles/markdown.js +16 -24
- package/dist/web/assets/styles/responsive.js +41 -44
- package/dist/web/assets/styles/tokens.js +65 -89
- package/dist/web/assets/styles/views.js +292 -0
- package/dist/web/webServer.js +2 -1
- package/docs/agent-result-consumption.md +16 -0
- package/docs/agent-result-consumption.zh-CN.md +13 -0
- package/docs/examples/agent-offline.mjs +194 -0
- package/docs/native-agent.md +283 -0
- package/docs/release-workflow.md +61 -0
- package/docs/release-workflow.zh-CN.md +46 -0
- package/docs/roles-and-configuration.md +32 -0
- package/docs/roles-and-configuration.zh-CN.md +26 -0
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +9 -0
- package/skills/yui-reviewer/SKILL.md +5 -0
- package/skills/yui-runtime/SKILL.md +33 -0
- 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,72 @@
|
|
|
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
|
+
const nativeSessionId = env.YUI_ADAPTER_ID === "codex"
|
|
9
|
+
? env.CODEX_THREAD_ID ?? env.YUI_NATIVE_SESSION_ID : env.YUI_NATIVE_SESSION_ID;
|
|
10
|
+
if (!env.YUI_ROLE || !nativeSessionId || nativeSessionId.trim() !== nativeSessionId
|
|
11
|
+
|| nativeSessionId.includes("\0"))
|
|
12
|
+
return "unbound";
|
|
13
|
+
if (env.YUI_SESSION_SCOPE === "global")
|
|
14
|
+
return env.YUI_ROLE === "operator" ? "operator" : "global";
|
|
15
|
+
if (env.YUI_SESSION_SCOPE === "task" && env.YUI_TASK_ID)
|
|
16
|
+
return env.YUI_ROLE === "leader" ? "leader" : "assignment";
|
|
17
|
+
return "unbound";
|
|
18
|
+
}
|
|
19
|
+
export function discoveryCommandTree(env) {
|
|
20
|
+
const audience = discoveryAudience(env);
|
|
21
|
+
const project = (node) => {
|
|
22
|
+
const children = node.children.map(project).filter((child) => child !== undefined);
|
|
23
|
+
const eligible = node.discovery?.surface !== "runtime" && node.discovery?.audiences.includes(audience);
|
|
24
|
+
if (!children.length && (!eligible || node.kind === "group") && node !== ROOT_COMMAND)
|
|
25
|
+
return undefined;
|
|
26
|
+
const executable = eligible && node.kind !== "group";
|
|
27
|
+
const kind = children.length ? executable ? "hybrid" : "group" : node.kind;
|
|
28
|
+
const template = `${node.path.join(" ")}${kind === "group" ? " <command>" : ""}`;
|
|
29
|
+
const omittedOptions = Object.entries(node.discovery?.optionAudiences ?? {})
|
|
30
|
+
.filter(([, audiences]) => !audiences.includes(audience)).map(([option]) => option);
|
|
31
|
+
const text = (value) => omittedOptions.reduce((line, option) => line.replace(new RegExp(`\\s*\\[${option}(?:\\s+[^\\]]*)?\\]`, "g"), ""), value);
|
|
32
|
+
const options = node.options.filter(option => !omittedOptions.includes(option));
|
|
33
|
+
// Group prose often contains concrete commands for several audiences.
|
|
34
|
+
// Generate its usage from the same retained children, not unfiltered text.
|
|
35
|
+
return {
|
|
36
|
+
...node, children, hidden: false, kind,
|
|
37
|
+
usage: kind === "group" ? [template] : node.usage.map(text),
|
|
38
|
+
examples: kind === "group" ? children.slice(0, 3).map(child => child.usage[0]) : node.examples.map(text),
|
|
39
|
+
options, optionValues: Object.fromEntries(Object.entries(node.optionValues).filter(([option]) => options.includes(option))),
|
|
40
|
+
sections: node.sections.map(section => ({ ...section,
|
|
41
|
+
entries: section.entries.filter(entry => children.some(child => child.name === entry) || (executable && node.values.some(value => value.name === entry)))
|
|
42
|
+
})).filter(section => section.entries.length > 0),
|
|
43
|
+
...(executable ? {} : { options: [], values: [], optionValues: {}, argumentValues: {} })
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
const tree = project(ROOT_COMMAND);
|
|
47
|
+
if (audience === "public") {
|
|
48
|
+
const sections = [
|
|
49
|
+
{ id: "start", title: "Start work", entries: ["operator", "project"] },
|
|
50
|
+
{ id: "progress", title: "Inspect progress", entries: ["task", "jobs", "execution", "telemetry"] },
|
|
51
|
+
{ id: "participate", title: "Participate and control", entries: ["role", "session"] },
|
|
52
|
+
{ id: "maintain", title: "Configure and maintain", entries: ["help", "version", "setup", "start", "doctor", "config", "web", "controller", "resources", "update", "upgrade", "release"] }
|
|
53
|
+
];
|
|
54
|
+
return { ...tree, sections: sections.map(section => ({ ...section,
|
|
55
|
+
entries: section.entries.filter(entry => tree.children.some(child => child.name === entry))
|
|
56
|
+
})) };
|
|
57
|
+
}
|
|
58
|
+
// Help accepts catalog paths, and config describe accepts only retained domains.
|
|
59
|
+
const config = findCommandNode(["config"], tree);
|
|
60
|
+
if (config) {
|
|
61
|
+
const domains = config.children.filter(child => !["show", "describe"].includes(child.name)).map(child => child.name);
|
|
62
|
+
return {
|
|
63
|
+
...tree, children: tree.children.map(child => child !== config ? child : {
|
|
64
|
+
...config, children: config.children.map(node => node.name !== "describe" ? node : {
|
|
65
|
+
...node, argumentValues: { 0: domains }, usage: ["yui config describe [domain]"],
|
|
66
|
+
examples: ["yui config describe"]
|
|
67
|
+
})
|
|
68
|
+
})
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return tree;
|
|
72
|
+
}
|
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) {
|