oasr 0.5.1__py3-none-any.whl → 0.6.0__py3-none-any.whl
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.
- agents/base.py +17 -3
- agents/claude.py +12 -2
- agents/codex.py +12 -2
- agents/copilot.py +12 -2
- agents/opencode.py +12 -2
- cli.py +8 -2
- commands/completion.py +345 -0
- commands/config.py +284 -37
- commands/exec.py +21 -1
- commands/profile.py +84 -0
- commands/update.py +89 -7
- completions/__init__.py +1 -0
- completions/bash.sh +210 -0
- completions/fish.fish +134 -0
- completions/powershell.ps1 +184 -0
- completions/zsh.sh +285 -0
- config/__init__.py +11 -0
- config/defaults.py +4 -21
- config/schema.py +3 -29
- {oasr-0.5.1.dist-info → oasr-0.6.0.dist-info}/METADATA +51 -21
- {oasr-0.5.1.dist-info → oasr-0.6.0.dist-info}/RECORD +34 -20
- policy/defaults.py +3 -19
- policy/profile.py +5 -7
- profiles/__init__.py +23 -0
- profiles/builtins.py +63 -0
- profiles/loader.py +74 -0
- profiles/paths.py +22 -0
- profiles/registry.py +19 -0
- profiles/summary.py +23 -0
- profiles/validation.py +34 -0
- {oasr-0.5.1.dist-info → oasr-0.6.0.dist-info}/WHEEL +0 -0
- {oasr-0.5.1.dist-info → oasr-0.6.0.dist-info}/entry_points.txt +0 -0
- {oasr-0.5.1.dist-info → oasr-0.6.0.dist-info}/licenses/LICENSE +0 -0
- {oasr-0.5.1.dist-info → oasr-0.6.0.dist-info}/licenses/NOTICE +0 -0
agents/base.py
CHANGED
|
@@ -34,25 +34,39 @@ class AgentDriver(ABC):
|
|
|
34
34
|
return shutil.which(self.get_binary_name()) is not None
|
|
35
35
|
|
|
36
36
|
@abstractmethod
|
|
37
|
-
def build_command(
|
|
37
|
+
def build_command(
|
|
38
|
+
self,
|
|
39
|
+
skill_content: str,
|
|
40
|
+
user_prompt: str,
|
|
41
|
+
cwd: Path,
|
|
42
|
+
extra_args: list[str] | None = None,
|
|
43
|
+
) -> list[str]:
|
|
38
44
|
"""Build the command to execute.
|
|
39
45
|
|
|
40
46
|
Args:
|
|
41
47
|
skill_content: Full SKILL.md content.
|
|
42
48
|
user_prompt: User's prompt/request.
|
|
43
49
|
cwd: Current working directory.
|
|
50
|
+
extra_args: Additional CLI arguments for the agent (optional).
|
|
44
51
|
|
|
45
52
|
Returns:
|
|
46
53
|
Command as list of strings (for subprocess).
|
|
47
54
|
"""
|
|
48
55
|
|
|
49
|
-
def execute(
|
|
56
|
+
def execute(
|
|
57
|
+
self,
|
|
58
|
+
skill_content: str,
|
|
59
|
+
user_prompt: str,
|
|
60
|
+
cwd: Path | None = None,
|
|
61
|
+
extra_args: list[str] | None = None,
|
|
62
|
+
) -> subprocess.CompletedProcess:
|
|
50
63
|
"""Execute skill with agent.
|
|
51
64
|
|
|
52
65
|
Args:
|
|
53
66
|
skill_content: Full SKILL.md content.
|
|
54
67
|
user_prompt: User's prompt/request.
|
|
55
68
|
cwd: Working directory for execution (defaults to current dir).
|
|
69
|
+
extra_args: Additional CLI arguments for the agent (optional).
|
|
56
70
|
|
|
57
71
|
Returns:
|
|
58
72
|
CompletedProcess with stdout/stderr/returncode.
|
|
@@ -64,7 +78,7 @@ class AgentDriver(ABC):
|
|
|
64
78
|
raise FileNotFoundError(f"{self.get_name()} binary '{self.get_binary_name()}' not found in PATH")
|
|
65
79
|
|
|
66
80
|
working_dir = cwd or Path.cwd()
|
|
67
|
-
cmd = self.build_command(skill_content, user_prompt, working_dir)
|
|
81
|
+
cmd = self.build_command(skill_content, user_prompt, working_dir, extra_args=extra_args)
|
|
68
82
|
|
|
69
83
|
return subprocess.run(
|
|
70
84
|
cmd,
|
agents/claude.py
CHANGED
|
@@ -16,10 +16,20 @@ class ClaudeDriver(AgentDriver):
|
|
|
16
16
|
"""Get the CLI binary name."""
|
|
17
17
|
return "claude"
|
|
18
18
|
|
|
19
|
-
def build_command(
|
|
19
|
+
def build_command(
|
|
20
|
+
self,
|
|
21
|
+
skill_content: str,
|
|
22
|
+
user_prompt: str,
|
|
23
|
+
cwd: Path,
|
|
24
|
+
extra_args: list[str] | None = None,
|
|
25
|
+
) -> list[str]:
|
|
20
26
|
"""Build claude command.
|
|
21
27
|
|
|
22
28
|
Claude syntax: claude <prompt> -p
|
|
23
29
|
"""
|
|
24
30
|
injected_prompt = self.format_injected_prompt(skill_content, user_prompt, cwd)
|
|
25
|
-
|
|
31
|
+
cmd = ["claude"]
|
|
32
|
+
if extra_args:
|
|
33
|
+
cmd.extend(extra_args)
|
|
34
|
+
cmd.extend([injected_prompt, "-p"])
|
|
35
|
+
return cmd
|
agents/codex.py
CHANGED
|
@@ -16,10 +16,20 @@ class CodexDriver(AgentDriver):
|
|
|
16
16
|
"""Get the CLI binary name."""
|
|
17
17
|
return "codex"
|
|
18
18
|
|
|
19
|
-
def build_command(
|
|
19
|
+
def build_command(
|
|
20
|
+
self,
|
|
21
|
+
skill_content: str,
|
|
22
|
+
user_prompt: str,
|
|
23
|
+
cwd: Path,
|
|
24
|
+
extra_args: list[str] | None = None,
|
|
25
|
+
) -> list[str]:
|
|
20
26
|
"""Build codex exec command.
|
|
21
27
|
|
|
22
28
|
Codex syntax: codex exec "<prompt>"
|
|
23
29
|
"""
|
|
24
30
|
injected_prompt = self.format_injected_prompt(skill_content, user_prompt, cwd)
|
|
25
|
-
|
|
31
|
+
cmd = ["codex", "exec"]
|
|
32
|
+
if extra_args:
|
|
33
|
+
cmd.extend(extra_args)
|
|
34
|
+
cmd.append(injected_prompt)
|
|
35
|
+
return cmd
|
agents/copilot.py
CHANGED
|
@@ -16,10 +16,20 @@ class CopilotDriver(AgentDriver):
|
|
|
16
16
|
"""Get the CLI binary name."""
|
|
17
17
|
return "copilot"
|
|
18
18
|
|
|
19
|
-
def build_command(
|
|
19
|
+
def build_command(
|
|
20
|
+
self,
|
|
21
|
+
skill_content: str,
|
|
22
|
+
user_prompt: str,
|
|
23
|
+
cwd: Path,
|
|
24
|
+
extra_args: list[str] | None = None,
|
|
25
|
+
) -> list[str]:
|
|
20
26
|
"""Build copilot command.
|
|
21
27
|
|
|
22
28
|
Copilot syntax: copilot -p "<prompt>"
|
|
23
29
|
"""
|
|
24
30
|
injected_prompt = self.format_injected_prompt(skill_content, user_prompt, cwd)
|
|
25
|
-
|
|
31
|
+
cmd = ["copilot"]
|
|
32
|
+
if extra_args:
|
|
33
|
+
cmd.extend(extra_args)
|
|
34
|
+
cmd.extend(["-p", injected_prompt])
|
|
35
|
+
return cmd
|
agents/opencode.py
CHANGED
|
@@ -16,10 +16,20 @@ class OpenCodeDriver(AgentDriver):
|
|
|
16
16
|
"""Get the CLI binary name."""
|
|
17
17
|
return "opencode"
|
|
18
18
|
|
|
19
|
-
def build_command(
|
|
19
|
+
def build_command(
|
|
20
|
+
self,
|
|
21
|
+
skill_content: str,
|
|
22
|
+
user_prompt: str,
|
|
23
|
+
cwd: Path,
|
|
24
|
+
extra_args: list[str] | None = None,
|
|
25
|
+
) -> list[str]:
|
|
20
26
|
"""Build opencode run command.
|
|
21
27
|
|
|
22
28
|
OpenCode syntax: opencode run "<prompt>"
|
|
23
29
|
"""
|
|
24
30
|
injected_prompt = self.format_injected_prompt(skill_content, user_prompt, cwd)
|
|
25
|
-
|
|
31
|
+
cmd = ["opencode", "run"]
|
|
32
|
+
if extra_args:
|
|
33
|
+
cmd.extend(extra_args)
|
|
34
|
+
cmd.append(injected_prompt)
|
|
35
|
+
return cmd
|
cli.py
CHANGED
|
@@ -10,10 +10,10 @@ import json
|
|
|
10
10
|
import sys
|
|
11
11
|
from pathlib import Path
|
|
12
12
|
|
|
13
|
-
from commands import adapter, clean, clone, config, diff, exec, find, registry, sync, update, use, validate
|
|
13
|
+
from commands import adapter, clean, clone, config, diff, exec, find, profile, registry, sync, update, use, validate
|
|
14
14
|
from commands import help as help_cmd
|
|
15
15
|
|
|
16
|
-
__version__ = "0.
|
|
16
|
+
__version__ = "0.6.0"
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
def main(argv: list[str] | None = None) -> int:
|
|
@@ -72,6 +72,7 @@ def create_parser() -> argparse.ArgumentParser:
|
|
|
72
72
|
diff.register(subparsers) # Show tracked skill status
|
|
73
73
|
sync.register(subparsers) # Refresh tracked skills
|
|
74
74
|
config.register(subparsers) # Configuration management
|
|
75
|
+
profile.register(subparsers) # Profile selection
|
|
75
76
|
clone.register(subparsers) # Clone skills to directory
|
|
76
77
|
exec.register(subparsers) # Execute skills with agent CLI
|
|
77
78
|
|
|
@@ -88,6 +89,11 @@ def create_parser() -> argparse.ArgumentParser:
|
|
|
88
89
|
|
|
89
90
|
info_cmd.register(subparsers)
|
|
90
91
|
|
|
92
|
+
# Import and register completion command
|
|
93
|
+
from commands import completion as completion_cmd
|
|
94
|
+
|
|
95
|
+
completion_cmd.register_parser(subparsers)
|
|
96
|
+
|
|
91
97
|
help_cmd.register(subparsers, parser)
|
|
92
98
|
|
|
93
99
|
return parser
|
commands/completion.py
ADDED
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
"""Shell completion management for OASR."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import platform
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from config import load_config
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def register_parser(subparsers):
|
|
12
|
+
"""Register the completion subcommand."""
|
|
13
|
+
parser = subparsers.add_parser(
|
|
14
|
+
"completion",
|
|
15
|
+
help="Generate and install shell completions",
|
|
16
|
+
description="Generate shell completion scripts for bash, zsh, fish, and PowerShell.",
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
parser.add_argument(
|
|
20
|
+
"shell",
|
|
21
|
+
nargs="?",
|
|
22
|
+
choices=["bash", "zsh", "fish", "powershell", "install", "uninstall"],
|
|
23
|
+
help="Shell type or action (install/uninstall)",
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
parser.add_argument(
|
|
27
|
+
"--force",
|
|
28
|
+
action="store_true",
|
|
29
|
+
help="Force installation even if already installed",
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
parser.add_argument(
|
|
33
|
+
"--dry-run",
|
|
34
|
+
action="store_true",
|
|
35
|
+
help="Show what would be done without doing it",
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
parser.set_defaults(func=run)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def detect_shell():
|
|
42
|
+
"""
|
|
43
|
+
Auto-detect the user's shell based on platform and environment.
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
str: Shell name (bash, zsh, fish, powershell)
|
|
47
|
+
"""
|
|
48
|
+
if platform.system() == "Windows":
|
|
49
|
+
shell_env = os.environ.get("SHELL", "").lower()
|
|
50
|
+
if "bash" in shell_env:
|
|
51
|
+
return "bash"
|
|
52
|
+
# Check for PowerShell
|
|
53
|
+
if "PSModulePath" in os.environ or "POWERSHELL" in os.environ.get("SHELL", "").upper():
|
|
54
|
+
return "powershell"
|
|
55
|
+
if "zsh" in shell_env:
|
|
56
|
+
return "zsh"
|
|
57
|
+
if "fish" in shell_env:
|
|
58
|
+
return "fish"
|
|
59
|
+
# Default to PowerShell on Windows
|
|
60
|
+
return "powershell"
|
|
61
|
+
else:
|
|
62
|
+
# Linux/macOS
|
|
63
|
+
shell = os.environ.get("SHELL", "")
|
|
64
|
+
if "zsh" in shell:
|
|
65
|
+
return "zsh"
|
|
66
|
+
elif "fish" in shell:
|
|
67
|
+
return "fish"
|
|
68
|
+
else:
|
|
69
|
+
# Default to bash on Unix
|
|
70
|
+
return "bash"
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def get_completion_script(shell):
|
|
74
|
+
"""
|
|
75
|
+
Get the completion script content for the specified shell.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
shell: Shell name (bash, zsh, fish, powershell)
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
str: Completion script content
|
|
82
|
+
"""
|
|
83
|
+
# Map shell names to completion files
|
|
84
|
+
script_files = {
|
|
85
|
+
"bash": "bash.sh",
|
|
86
|
+
"zsh": "zsh.sh",
|
|
87
|
+
"fish": "fish.fish",
|
|
88
|
+
"powershell": "powershell.ps1",
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if shell not in script_files:
|
|
92
|
+
return ""
|
|
93
|
+
|
|
94
|
+
# Get the path to the completion script
|
|
95
|
+
completion_file = Path(__file__).parent.parent / "completions" / script_files[shell]
|
|
96
|
+
|
|
97
|
+
if not completion_file.exists():
|
|
98
|
+
return f"# {shell} completion script not found"
|
|
99
|
+
|
|
100
|
+
return completion_file.read_text()
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def get_completion_path(shell, system=False):
|
|
104
|
+
"""
|
|
105
|
+
Get the installation path for completion script.
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
shell: Shell name
|
|
109
|
+
system: If True, use system-wide path (requires root)
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
Path: Installation path
|
|
113
|
+
"""
|
|
114
|
+
paths = {
|
|
115
|
+
"bash": {
|
|
116
|
+
"user": Path.home() / ".bash_completion.d" / "oasr",
|
|
117
|
+
"system": Path("/etc/bash_completion.d/oasr"),
|
|
118
|
+
},
|
|
119
|
+
"zsh": {
|
|
120
|
+
"user": Path.home() / ".zsh" / "completion" / "_oasr",
|
|
121
|
+
"system": Path("/usr/local/share/zsh/site-functions/_oasr"),
|
|
122
|
+
},
|
|
123
|
+
"fish": {
|
|
124
|
+
"user": Path.home() / ".config" / "fish" / "completions" / "oasr.fish",
|
|
125
|
+
"system": Path("/usr/share/fish/vendor_completions.d/oasr.fish"),
|
|
126
|
+
},
|
|
127
|
+
"powershell": {
|
|
128
|
+
"user": Path.home() / ".config" / "powershell" / "oasr_completion.ps1",
|
|
129
|
+
"system": Path.home() / ".config" / "powershell" / "oasr_completion.ps1",
|
|
130
|
+
},
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
level = "system" if system else "user"
|
|
134
|
+
return paths.get(shell, {}).get(level)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def print_activation_instructions(shell, path):
|
|
138
|
+
"""
|
|
139
|
+
Print instructions for activating completions.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
shell: Shell name
|
|
143
|
+
path: Installation path
|
|
144
|
+
"""
|
|
145
|
+
instructions = {
|
|
146
|
+
"bash": f"""
|
|
147
|
+
✓ Completions installed for bash
|
|
148
|
+
|
|
149
|
+
To activate, add this to your ~/.bashrc:
|
|
150
|
+
source {path}
|
|
151
|
+
|
|
152
|
+
Or run:
|
|
153
|
+
echo 'source {path}' >> ~/.bashrc
|
|
154
|
+
|
|
155
|
+
Then restart your shell or run:
|
|
156
|
+
source ~/.bashrc
|
|
157
|
+
""",
|
|
158
|
+
"zsh": f"""
|
|
159
|
+
✓ Completions installed for zsh
|
|
160
|
+
|
|
161
|
+
To activate, add this to your ~/.zshrc:
|
|
162
|
+
fpath=({path.parent} $fpath)
|
|
163
|
+
autoload -Uz compinit && compinit
|
|
164
|
+
|
|
165
|
+
Then restart your shell or run:
|
|
166
|
+
source ~/.zshrc
|
|
167
|
+
""",
|
|
168
|
+
"fish": f"""
|
|
169
|
+
✓ Completions installed for fish
|
|
170
|
+
|
|
171
|
+
Completions will be active in new fish shells.
|
|
172
|
+
To activate now, run:
|
|
173
|
+
source {path}
|
|
174
|
+
""",
|
|
175
|
+
"powershell": f"""
|
|
176
|
+
✓ Completions installed for PowerShell
|
|
177
|
+
|
|
178
|
+
To activate, add this to your PowerShell profile ($PROFILE):
|
|
179
|
+
. {path}
|
|
180
|
+
|
|
181
|
+
Or run:
|
|
182
|
+
echo '. {path}' >> $PROFILE
|
|
183
|
+
|
|
184
|
+
Then restart PowerShell or run:
|
|
185
|
+
. $PROFILE
|
|
186
|
+
""",
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
print(instructions.get(shell, ""))
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def is_already_installed(shell):
|
|
193
|
+
"""
|
|
194
|
+
Check if completions are already installed for the shell.
|
|
195
|
+
|
|
196
|
+
Args:
|
|
197
|
+
shell: Shell name
|
|
198
|
+
|
|
199
|
+
Returns:
|
|
200
|
+
bool: True if already installed
|
|
201
|
+
"""
|
|
202
|
+
path = get_completion_path(shell)
|
|
203
|
+
if not path or not path.exists():
|
|
204
|
+
return False
|
|
205
|
+
|
|
206
|
+
# Check for our signature
|
|
207
|
+
with open(path) as f:
|
|
208
|
+
content = f.read()
|
|
209
|
+
return "# oasr completion" in content.lower()
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def run_output(shell):
|
|
213
|
+
"""
|
|
214
|
+
Output the completion script to stdout.
|
|
215
|
+
|
|
216
|
+
Args:
|
|
217
|
+
shell: Shell name
|
|
218
|
+
|
|
219
|
+
Returns:
|
|
220
|
+
int: Exit code
|
|
221
|
+
"""
|
|
222
|
+
script = get_completion_script(shell)
|
|
223
|
+
print(script)
|
|
224
|
+
return 0
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def run_install(args):
|
|
228
|
+
"""
|
|
229
|
+
Install completion script.
|
|
230
|
+
|
|
231
|
+
Args:
|
|
232
|
+
args: Parsed arguments
|
|
233
|
+
|
|
234
|
+
Returns:
|
|
235
|
+
int: Exit code
|
|
236
|
+
"""
|
|
237
|
+
shell = args.shell if args.shell != "install" else detect_shell()
|
|
238
|
+
|
|
239
|
+
# Check config
|
|
240
|
+
config = load_config()
|
|
241
|
+
if not config.get("oasr", {}).get("completions", True):
|
|
242
|
+
print("Completions are disabled in config (oasr.completions = false)")
|
|
243
|
+
return 1
|
|
244
|
+
|
|
245
|
+
# Check if already installed
|
|
246
|
+
if is_already_installed(shell) and not args.force:
|
|
247
|
+
print(f"✓ Completions already installed for {shell}")
|
|
248
|
+
print(" Use --force to reinstall")
|
|
249
|
+
return 0
|
|
250
|
+
|
|
251
|
+
# Get paths
|
|
252
|
+
path = get_completion_path(shell)
|
|
253
|
+
if not path:
|
|
254
|
+
print(f"Error: Unsupported shell: {shell}", file=sys.stderr)
|
|
255
|
+
return 1
|
|
256
|
+
|
|
257
|
+
# Dry run
|
|
258
|
+
if args.dry_run:
|
|
259
|
+
print(f"Would install completion to: {path}")
|
|
260
|
+
print_activation_instructions(shell, path)
|
|
261
|
+
return 0
|
|
262
|
+
|
|
263
|
+
# Get script
|
|
264
|
+
script = get_completion_script(shell)
|
|
265
|
+
|
|
266
|
+
# Create directory
|
|
267
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
268
|
+
|
|
269
|
+
# Backup existing
|
|
270
|
+
if path.exists() and not is_already_installed(shell):
|
|
271
|
+
import time
|
|
272
|
+
|
|
273
|
+
backup = path.parent / f"{path.name}.backup.{int(time.time())}"
|
|
274
|
+
path.rename(backup)
|
|
275
|
+
print(f"Backed up existing file to: {backup}")
|
|
276
|
+
|
|
277
|
+
# Write script
|
|
278
|
+
path.write_text(script)
|
|
279
|
+
|
|
280
|
+
# Success message
|
|
281
|
+
print_activation_instructions(shell, path)
|
|
282
|
+
|
|
283
|
+
return 0
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def run_uninstall(args):
|
|
287
|
+
"""
|
|
288
|
+
Uninstall completion script.
|
|
289
|
+
|
|
290
|
+
Args:
|
|
291
|
+
args: Parsed arguments
|
|
292
|
+
|
|
293
|
+
Returns:
|
|
294
|
+
int: Exit code
|
|
295
|
+
"""
|
|
296
|
+
shell = args.shell if args.shell != "uninstall" else detect_shell()
|
|
297
|
+
|
|
298
|
+
path = get_completion_path(shell)
|
|
299
|
+
if not path or not path.exists():
|
|
300
|
+
print(f"No completions installed for {shell}")
|
|
301
|
+
return 0
|
|
302
|
+
|
|
303
|
+
# Dry run
|
|
304
|
+
if args.dry_run:
|
|
305
|
+
print(f"Would remove: {path}")
|
|
306
|
+
return 0
|
|
307
|
+
|
|
308
|
+
# Remove file
|
|
309
|
+
path.unlink()
|
|
310
|
+
print(f"✓ Removed completions for {shell}")
|
|
311
|
+
|
|
312
|
+
return 0
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def run(args):
|
|
316
|
+
"""
|
|
317
|
+
Execute completion command.
|
|
318
|
+
|
|
319
|
+
Args:
|
|
320
|
+
args: Parsed arguments
|
|
321
|
+
|
|
322
|
+
Returns:
|
|
323
|
+
int: Exit code
|
|
324
|
+
"""
|
|
325
|
+
# No shell specified - show help
|
|
326
|
+
if not args.shell:
|
|
327
|
+
detected = detect_shell()
|
|
328
|
+
print(f"Detected shell: {detected}")
|
|
329
|
+
print("\nUsage:")
|
|
330
|
+
print(" oasr completion bash # Output bash completion script")
|
|
331
|
+
print(" oasr completion zsh # Output zsh completion script")
|
|
332
|
+
print(" oasr completion fish # Output fish completion script")
|
|
333
|
+
print(" oasr completion powershell # Output PowerShell completion script")
|
|
334
|
+
print(" oasr completion install # Auto-detect and install")
|
|
335
|
+
print(" oasr completion uninstall # Remove installed completions")
|
|
336
|
+
return 0
|
|
337
|
+
|
|
338
|
+
# Handle actions
|
|
339
|
+
if args.shell == "install":
|
|
340
|
+
return run_install(args)
|
|
341
|
+
elif args.shell == "uninstall":
|
|
342
|
+
return run_uninstall(args)
|
|
343
|
+
else:
|
|
344
|
+
# Output script to stdout
|
|
345
|
+
return run_output(args.shell)
|