oasr 0.5.1__py3-none-any.whl → 0.5.2__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.
cli.py CHANGED
@@ -13,7 +13,7 @@ from pathlib import Path
13
13
  from commands import adapter, clean, clone, config, diff, exec, find, registry, sync, update, use, validate
14
14
  from commands import help as help_cmd
15
15
 
16
- __version__ = "0.5.1"
16
+ __version__ = "0.5.2"
17
17
 
18
18
 
19
19
  def main(argv: list[str] | None = None) -> int:
@@ -88,6 +88,11 @@ def create_parser() -> argparse.ArgumentParser:
88
88
 
89
89
  info_cmd.register(subparsers)
90
90
 
91
+ # Import and register completion command
92
+ from commands import completion as completion_cmd
93
+
94
+ completion_cmd.register_parser(subparsers)
95
+
91
96
  help_cmd.register(subparsers, parser)
92
97
 
93
98
  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)
@@ -0,0 +1 @@
1
+ """Shell completion scripts for OASR."""
completions/bash.sh ADDED
@@ -0,0 +1,197 @@
1
+ # oasr completion for bash
2
+ # This file provides tab completion for the oasr command in bash.
3
+ #
4
+ # Installation:
5
+ # Run: oasr completion install
6
+ # Or manually: source this file in your ~/.bashrc
7
+
8
+ _oasr_skills() {
9
+ # Get skill names from registry
10
+ local skills
11
+ skills=$(oasr registry list --quiet 2>/dev/null | grep "^ -" | sed 's/^ - //' | awk '{print $1}')
12
+ COMPREPLY=($(compgen -W "$skills" -- "${COMP_WORDS[COMP_CWORD]}"))
13
+ }
14
+
15
+ _oasr_agents() {
16
+ # Known agent names
17
+ COMPREPLY=($(compgen -W "codex copilot claude opencode" -- "${COMP_WORDS[COMP_CWORD]}"))
18
+ }
19
+
20
+ _oasr_profiles() {
21
+ # Get profile names from config
22
+ local profiles
23
+ profiles=$(oasr config list 2>/dev/null | grep "^profiles\." | sed 's/^profiles\.\([^=]*\)=.*/\1/' | sort -u)
24
+ COMPREPLY=($(compgen -W "$profiles" -- "${COMP_WORDS[COMP_CWORD]}"))
25
+ }
26
+
27
+ _oasr_config_keys() {
28
+ # Common config keys
29
+ COMPREPLY=($(compgen -W "agent profile adapter.default validation.strict validation.show_references oasr.completions" -- "${COMP_WORDS[COMP_CWORD]}"))
30
+ }
31
+
32
+ _oasr_completion_shells() {
33
+ COMPREPLY=($(compgen -W "bash zsh fish powershell install uninstall" -- "${COMP_WORDS[COMP_CWORD]}"))
34
+ }
35
+
36
+ _oasr() {
37
+ local cur prev words cword
38
+ _init_completion || return
39
+
40
+ # Top-level commands
41
+ if [ $COMP_CWORD -eq 1 ]; then
42
+ COMPREPLY=($(compgen -W "registry diff sync config clone exec use find validate clean adapter update info help completion" -- "$cur"))
43
+ return 0
44
+ fi
45
+
46
+ # Get the main command
47
+ local command="${COMP_WORDS[1]}"
48
+
49
+ case "$command" in
50
+ exec)
51
+ case "$prev" in
52
+ --agent)
53
+ _oasr_agents
54
+ return 0
55
+ ;;
56
+ --profile)
57
+ _oasr_profiles
58
+ return 0
59
+ ;;
60
+ --agent-flags)
61
+ # No completion for agent flags
62
+ return 0
63
+ ;;
64
+ -p|--prompt)
65
+ # File completion for prompt
66
+ _filedir
67
+ return 0
68
+ ;;
69
+ *)
70
+ # Complete skill names and flags
71
+ if [[ "$cur" == -* ]]; then
72
+ COMPREPLY=($(compgen -W "--agent --profile --agent-flags -y --yes --confirm -p --prompt" -- "$cur"))
73
+ else
74
+ _oasr_skills
75
+ fi
76
+ return 0
77
+ ;;
78
+ esac
79
+ ;;
80
+
81
+ clone)
82
+ case "$prev" in
83
+ -t|--target)
84
+ # Directory completion
85
+ _filedir -d
86
+ return 0
87
+ ;;
88
+ *)
89
+ if [[ "$cur" == -* ]]; then
90
+ COMPREPLY=($(compgen -W "-t --target" -- "$cur"))
91
+ else
92
+ _oasr_skills
93
+ fi
94
+ return 0
95
+ ;;
96
+ esac
97
+ ;;
98
+
99
+ info|validate)
100
+ if [[ "$cur" == -* ]]; then
101
+ case "$command" in
102
+ info)
103
+ COMPREPLY=($(compgen -W "--files" -- "$cur"))
104
+ ;;
105
+ esac
106
+ else
107
+ _oasr_skills
108
+ fi
109
+ return 0
110
+ ;;
111
+
112
+ config)
113
+ if [ $COMP_CWORD -eq 2 ]; then
114
+ COMPREPLY=($(compgen -W "set get list path" -- "$cur"))
115
+ return 0
116
+ fi
117
+
118
+ local subcommand="${COMP_WORDS[2]}"
119
+ case "$subcommand" in
120
+ set|get)
121
+ if [ $COMP_CWORD -eq 3 ]; then
122
+ _oasr_config_keys
123
+ elif [ $COMP_CWORD -eq 4 ] && [ "$subcommand" = "set" ]; then
124
+ # Value completion based on key
125
+ local key="${COMP_WORDS[3]}"
126
+ case "$key" in
127
+ agent)
128
+ _oasr_agents
129
+ ;;
130
+ profile)
131
+ _oasr_profiles
132
+ ;;
133
+ validation.strict|oasr.completions)
134
+ COMPREPLY=($(compgen -W "true false" -- "$cur"))
135
+ ;;
136
+ esac
137
+ fi
138
+ return 0
139
+ ;;
140
+ esac
141
+ ;;
142
+
143
+ registry)
144
+ if [ $COMP_CWORD -eq 2 ]; then
145
+ COMPREPLY=($(compgen -W "add rm sync list validate prune" -- "$cur"))
146
+ return 0
147
+ fi
148
+
149
+ local subcommand="${COMP_WORDS[2]}"
150
+ case "$subcommand" in
151
+ add)
152
+ # Directory or URL completion
153
+ if [[ "$cur" == http* ]] || [[ "$cur" == git@* ]]; then
154
+ # No completion for URLs
155
+ return 0
156
+ else
157
+ _filedir -d
158
+ fi
159
+ ;;
160
+ rm)
161
+ _oasr_skills
162
+ ;;
163
+ prune)
164
+ if [[ "$cur" == -* ]]; then
165
+ COMPREPLY=($(compgen -W "--dry-run" -- "$cur"))
166
+ fi
167
+ ;;
168
+ esac
169
+ ;;
170
+
171
+ completion)
172
+ if [ $COMP_CWORD -eq 2 ]; then
173
+ _oasr_completion_shells
174
+ return 0
175
+ fi
176
+
177
+ if [[ "$cur" == -* ]]; then
178
+ COMPREPLY=($(compgen -W "--force --dry-run" -- "$cur"))
179
+ fi
180
+ ;;
181
+
182
+ adapter)
183
+ if [ $COMP_CWORD -eq 2 ]; then
184
+ COMPREPLY=($(compgen -W "list generate" -- "$cur"))
185
+ return 0
186
+ fi
187
+ ;;
188
+
189
+ find|validate|sync|diff|clean|update|help)
190
+ # These commands have limited or no additional completion
191
+ return 0
192
+ ;;
193
+ esac
194
+ }
195
+
196
+ # Register the completion function
197
+ complete -F _oasr oasr
completions/fish.fish ADDED
@@ -0,0 +1,120 @@
1
+ # oasr completion for fish
2
+ # This file provides tab completion for the oasr command in fish.
3
+ #
4
+ # Installation:
5
+ # Run: oasr completion install
6
+ # Or manually: Copy to ~/.config/fish/completions/oasr.fish
7
+
8
+ # Helper functions for dynamic completion
9
+ function __oasr_skills
10
+ oasr registry list --quiet 2>/dev/null | grep '^ -' | sed 's/^ - //' | awk '{print $1}'
11
+ end
12
+
13
+ function __oasr_agents
14
+ echo codex
15
+ echo copilot
16
+ echo claude
17
+ echo opencode
18
+ end
19
+
20
+ function __oasr_profiles
21
+ oasr config list 2>/dev/null | grep '^profiles\.' | sed 's/^profiles\.\([^=]*\)=.*/\1/' | sort -u
22
+ end
23
+
24
+ function __oasr_config_keys
25
+ echo agent
26
+ echo profile
27
+ echo adapter.default
28
+ echo validation.strict
29
+ echo validation.show_references
30
+ echo oasr.completions
31
+ end
32
+
33
+ # Remove default completions
34
+ complete -c oasr -e
35
+
36
+ # Global options
37
+ complete -c oasr -l help -s h -d "Show help"
38
+ complete -c oasr -l version -d "Show version"
39
+ complete -c oasr -l config -d "Config file path" -r
40
+ complete -c oasr -l json -d "JSON output"
41
+ complete -c oasr -l quiet -d "Suppress warnings"
42
+
43
+ # Main commands
44
+ complete -c oasr -f -n __fish_use_subcommand -a registry -d "Manage skill registry"
45
+ complete -c oasr -f -n __fish_use_subcommand -a diff -d "Show tracked skill status"
46
+ complete -c oasr -f -n __fish_use_subcommand -a sync -d "Refresh tracked skills"
47
+ complete -c oasr -f -n __fish_use_subcommand -a config -d "Manage configuration"
48
+ complete -c oasr -f -n __fish_use_subcommand -a clone -d "Clone skills to directory"
49
+ complete -c oasr -f -n __fish_use_subcommand -a exec -d "Execute a skill"
50
+ complete -c oasr -f -n __fish_use_subcommand -a use -d "DEPRECATED - use clone"
51
+ complete -c oasr -f -n __fish_use_subcommand -a find -d "Find skills recursively"
52
+ complete -c oasr -f -n __fish_use_subcommand -a validate -d "Validate skills"
53
+ complete -c oasr -f -n __fish_use_subcommand -a clean -d "Clean up corrupted skills"
54
+ complete -c oasr -f -n __fish_use_subcommand -a adapter -d "Generate IDE files"
55
+ complete -c oasr -f -n __fish_use_subcommand -a update -d "Update OASR tool"
56
+ complete -c oasr -f -n __fish_use_subcommand -a info -d "Show skill information"
57
+ complete -c oasr -f -n __fish_use_subcommand -a help -d "Show help"
58
+ complete -c oasr -f -n __fish_use_subcommand -a completion -d "Manage shell completions"
59
+
60
+ # exec command
61
+ complete -c oasr -f -n "__fish_seen_subcommand_from exec" -l agent -d "Agent to use" -a "(__oasr_agents)"
62
+ complete -c oasr -f -n "__fish_seen_subcommand_from exec" -l profile -d "Policy profile" -a "(__oasr_profiles)"
63
+ complete -c oasr -f -n "__fish_seen_subcommand_from exec" -l agent-flags -d "Additional agent flags"
64
+ complete -c oasr -f -n "__fish_seen_subcommand_from exec" -s y -l yes -d "Skip confirmation"
65
+ complete -c oasr -f -n "__fish_seen_subcommand_from exec" -l confirm -d "Force confirmation"
66
+ complete -c oasr -f -n "__fish_seen_subcommand_from exec" -s p -l prompt -d "Prompt from file" -r
67
+ complete -c oasr -f -n "__fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from (__oasr_skills)" -a "(__oasr_skills)" -d "Skill"
68
+
69
+ # clone command
70
+ complete -c oasr -f -n "__fish_seen_subcommand_from clone" -s t -l target -d "Target directory" -r
71
+ complete -c oasr -f -n "__fish_seen_subcommand_from clone; and not __fish_seen_subcommand_from (__oasr_skills)" -a "(__oasr_skills)" -d "Skill"
72
+
73
+ # info command
74
+ complete -c oasr -f -n "__fish_seen_subcommand_from info" -l files -d "Show file list"
75
+ complete -c oasr -f -n "__fish_seen_subcommand_from info; and not __fish_seen_subcommand_from (__oasr_skills)" -a "(__oasr_skills)" -d "Skill"
76
+
77
+ # validate command
78
+ complete -c oasr -f -n "__fish_seen_subcommand_from validate; and not __fish_seen_subcommand_from (__oasr_skills)" -a "(__oasr_skills)" -d "Skill"
79
+
80
+ # config subcommands
81
+ complete -c oasr -f -n "__fish_seen_subcommand_from config; and not __fish_seen_subcommand_from set get list path" -a "set" -d "Set configuration value"
82
+ complete -c oasr -f -n "__fish_seen_subcommand_from config; and not __fish_seen_subcommand_from set get list path" -a "get" -d "Get configuration value"
83
+ complete -c oasr -f -n "__fish_seen_subcommand_from config; and not __fish_seen_subcommand_from set get list path" -a "list" -d "List all configuration"
84
+ complete -c oasr -f -n "__fish_seen_subcommand_from config; and not __fish_seen_subcommand_from set get list path" -a "path" -d "Show config file path"
85
+
86
+ # config set/get
87
+ complete -c oasr -f -n "__fish_seen_subcommand_from config; and __fish_seen_subcommand_from set get" -a "(__oasr_config_keys)" -d "Config key"
88
+ complete -c oasr -f -n "__fish_seen_subcommand_from config; and __fish_seen_subcommand_from set; and __fish_seen_subcommand_from agent" -a "(__oasr_agents)" -d "Agent"
89
+ complete -c oasr -f -n "__fish_seen_subcommand_from config; and __fish_seen_subcommand_from set; and __fish_seen_subcommand_from profile" -a "(__oasr_profiles)" -d "Profile"
90
+ complete -c oasr -f -n "__fish_seen_subcommand_from config; and __fish_seen_subcommand_from set; and __fish_seen_subcommand_from validation.strict oasr.completions" -a "true false" -d "Boolean"
91
+
92
+ # registry subcommands
93
+ complete -c oasr -f -n "__fish_seen_subcommand_from registry; and not __fish_seen_subcommand_from add rm sync list validate prune" -a "add" -d "Add skill to registry"
94
+ complete -c oasr -f -n "__fish_seen_subcommand_from registry; and not __fish_seen_subcommand_from add rm sync list validate prune" -a "rm" -d "Remove skill from registry"
95
+ complete -c oasr -f -n "__fish_seen_subcommand_from registry; and not __fish_seen_subcommand_from add rm sync list validate prune" -a "sync" -d "Sync remote skills"
96
+ complete -c oasr -f -n "__fish_seen_subcommand_from registry; and not __fish_seen_subcommand_from add rm sync list validate prune" -a "list" -d "List registry skills"
97
+ complete -c oasr -f -n "__fish_seen_subcommand_from registry; and not __fish_seen_subcommand_from add rm sync list validate prune" -a "validate" -d "Validate registry"
98
+ complete -c oasr -f -n "__fish_seen_subcommand_from registry; and not __fish_seen_subcommand_from add rm sync list validate prune" -a "prune" -d "Clean up registry"
99
+
100
+ # registry rm
101
+ complete -c oasr -f -n "__fish_seen_subcommand_from registry; and __fish_seen_subcommand_from rm" -a "(__oasr_skills)" -d "Skill"
102
+
103
+ # registry prune
104
+ complete -c oasr -f -n "__fish_seen_subcommand_from registry; and __fish_seen_subcommand_from prune" -l dry-run -d "Show what would be removed"
105
+
106
+ # completion command
107
+ complete -c oasr -f -n "__fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from bash zsh fish powershell install uninstall" -a "bash" -d "Bash completion"
108
+ complete -c oasr -f -n "__fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from bash zsh fish powershell install uninstall" -a "zsh" -d "Zsh completion"
109
+ complete -c oasr -f -n "__fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from bash zsh fish powershell install uninstall" -a "fish" -d "Fish completion"
110
+ complete -c oasr -f -n "__fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from bash zsh fish powershell install uninstall" -a "powershell" -d "PowerShell completion"
111
+ complete -c oasr -f -n "__fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from bash zsh fish powershell install uninstall" -a "install" -d "Auto-detect and install"
112
+ complete -c oasr -f -n "__fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from bash zsh fish powershell install uninstall" -a "uninstall" -d "Remove completions"
113
+
114
+ # completion flags
115
+ complete -c oasr -f -n "__fish_seen_subcommand_from completion" -l force -d "Force reinstall"
116
+ complete -c oasr -f -n "__fish_seen_subcommand_from completion" -l dry-run -d "Preview without installing"
117
+
118
+ # adapter subcommands
119
+ complete -c oasr -f -n "__fish_seen_subcommand_from adapter; and not __fish_seen_subcommand_from list generate" -a "list" -d "List adapters"
120
+ complete -c oasr -f -n "__fish_seen_subcommand_from adapter; and not __fish_seen_subcommand_from list generate" -a "generate" -d "Generate adapter files"
@@ -0,0 +1,115 @@
1
+ # oasr completion for PowerShell
2
+ # This file provides tab completion for the oasr command in PowerShell.
3
+ #
4
+ # Installation:
5
+ # Run: oasr completion install
6
+ # Or manually: Add this to your PowerShell profile ($PROFILE)
7
+
8
+ # Helper functions for dynamic completion
9
+ function Get-OasrSkills {
10
+ $skills = oasr registry list --quiet 2>$null | Select-String '^\s+-' | ForEach-Object {
11
+ $_.Line -replace '^\s+- ', '' -split ' ' | Select-Object -First 1
12
+ }
13
+ return $skills
14
+ }
15
+
16
+ function Get-OasrAgents {
17
+ return @('codex', 'copilot', 'claude', 'opencode')
18
+ }
19
+
20
+ function Get-OasrProfiles {
21
+ $profiles = oasr config list 2>$null | Select-String '^profiles\.' | ForEach-Object {
22
+ if ($_ -match '^profiles\.([^=]+)=') {
23
+ $matches[1]
24
+ }
25
+ } | Sort-Object -Unique
26
+ return $profiles
27
+ }
28
+
29
+ function Get-OasrConfigKeys {
30
+ return @(
31
+ 'agent',
32
+ 'profile',
33
+ 'adapter.default',
34
+ 'validation.strict',
35
+ 'validation.show_references',
36
+ 'oasr.completions'
37
+ )
38
+ }
39
+
40
+ # Main completion function
41
+ $oasrCompletion = {
42
+ param($wordToComplete, $commandAst, $cursorPosition)
43
+
44
+ $command = $commandAst.CommandElements[0].Value
45
+ $elements = $commandAst.CommandElements
46
+ $elementCount = $elements.Count
47
+
48
+ # First argument - main commands
49
+ if ($elementCount -eq 2) {
50
+ $commands = @(
51
+ 'registry', 'diff', 'sync', 'config', 'clone', 'exec', 'use',
52
+ 'find', 'validate', 'clean', 'adapter', 'update', 'info',
53
+ 'help', 'completion'
54
+ )
55
+ $commands | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {
56
+ [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
57
+ }
58
+ return
59
+ }
60
+
61
+ $subcommand = $elements[1].Value
62
+
63
+ switch ($subcommand) {
64
+ 'exec' {
65
+ $prevWord = if ($elementCount -gt 2) { $elements[$elementCount - 2].Value } else { '' }
66
+
67
+ switch ($prevWord) {
68
+ '--agent' {
69
+ Get-OasrAgents | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {
70
+ [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', "Agent: $_")
71
+ }
72
+ return
73
+ }
74
+ '--profile' {
75
+ Get-OasrProfiles | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {
76
+ [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', "Profile: $_")
77
+ }
78
+ return
79
+ }
80
+ default {
81
+ if ($wordToComplete -like '-*') {
82
+ @('--agent', '--profile', '--agent-flags', '-y', '--yes', '--confirm', '-p', '--prompt') |
83
+ Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {
84
+ [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
85
+ }
86
+ } else {
87
+ Get-OasrSkills | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {
88
+ [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', "Skill: $_")
89
+ }
90
+ }
91
+ return
92
+ }
93
+ }
94
+ }
95
+
96
+ 'completion' {
97
+ if ($elementCount -eq 3) {
98
+ @('bash', 'zsh', 'fish', 'powershell', 'install', 'uninstall') | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {
99
+ [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
100
+ }
101
+ return
102
+ }
103
+
104
+ if ($wordToComplete -like '-*') {
105
+ @('--force', '--dry-run') | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {
106
+ [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
107
+ }
108
+ }
109
+ return
110
+ }
111
+ }
112
+ }
113
+
114
+ # Register the completion
115
+ Register-ArgumentCompleter -Native -CommandName oasr -ScriptBlock $oasrCompletion
completions/zsh.sh ADDED
@@ -0,0 +1,259 @@
1
+ #compdef oasr
2
+ # oasr completion for zsh
3
+ # This file provides tab completion for the oasr command in zsh.
4
+ #
5
+ # Installation:
6
+ # Run: oasr completion install
7
+ # Or manually: Add this file to your fpath and run compinit
8
+
9
+ _oasr_skills() {
10
+ local skills
11
+ skills=(${(f)"$(oasr registry list --quiet 2>/dev/null | grep '^ -' | sed 's/^ - //' | awk '{print $1}')"})
12
+ _describe 'skill' skills
13
+ }
14
+
15
+ _oasr_agents() {
16
+ local agents
17
+ agents=(
18
+ 'codex:OpenAI Codex agent'
19
+ 'copilot:GitHub Copilot agent'
20
+ 'claude:Anthropic Claude agent'
21
+ 'opencode:OpenCode agent'
22
+ )
23
+ _describe 'agent' agents
24
+ }
25
+
26
+ _oasr_profiles() {
27
+ local profiles
28
+ profiles=(${(f)"$(oasr config list 2>/dev/null | grep '^profiles\.' | sed 's/^profiles\.\([^=]*\)=.*/\1/' | sort -u)"})
29
+ _describe 'profile' profiles
30
+ }
31
+
32
+ _oasr_config_keys() {
33
+ local keys
34
+ keys=(
35
+ 'agent:Default agent'
36
+ 'profile:Default policy profile'
37
+ 'adapter.default:Default adapter target'
38
+ 'validation.strict:Strict validation'
39
+ 'validation.show_references:Show references'
40
+ 'oasr.completions:Enable completions'
41
+ )
42
+ _describe 'config key' keys
43
+ }
44
+
45
+ _oasr_exec() {
46
+ _arguments \
47
+ '--agent[Agent to use]:agent:_oasr_agents' \
48
+ '--profile[Policy profile]:profile:_oasr_profiles' \
49
+ '--agent-flags[Additional agent flags]:flags:' \
50
+ '(-y --yes)'{-y,--yes}'[Skip confirmation]' \
51
+ '--confirm[Force confirmation]' \
52
+ '(-p --prompt)'{-p,--prompt}'[Prompt from file]:file:_files' \
53
+ '1:skill:_oasr_skills'
54
+ }
55
+
56
+ _oasr_clone() {
57
+ _arguments \
58
+ '(-t --target)'{-t,--target}'[Target directory]:directory:_directories' \
59
+ '*:skill:_oasr_skills'
60
+ }
61
+
62
+ _oasr_info() {
63
+ _arguments \
64
+ '--files[Show file list]' \
65
+ '1:skill:_oasr_skills'
66
+ }
67
+
68
+ _oasr_validate() {
69
+ _arguments \
70
+ '*:skill:_oasr_skills'
71
+ }
72
+
73
+ _oasr_config() {
74
+ local -a subcommands
75
+ subcommands=(
76
+ 'set:Set a configuration value'
77
+ 'get:Get a configuration value'
78
+ 'list:List all configuration'
79
+ 'path:Show config file path'
80
+ )
81
+
82
+ _arguments -C \
83
+ '1:subcommand:->subcommand' \
84
+ '*::arg:->args'
85
+
86
+ case $state in
87
+ subcommand)
88
+ _describe 'config subcommand' subcommands
89
+ ;;
90
+ args)
91
+ case ${words[1]} in
92
+ set)
93
+ if [ ${#words[@]} -eq 2 ]; then
94
+ _oasr_config_keys
95
+ elif [ ${#words[@]} -eq 3 ]; then
96
+ case ${words[2]} in
97
+ agent)
98
+ _oasr_agents
99
+ ;;
100
+ profile)
101
+ _oasr_profiles
102
+ ;;
103
+ validation.strict|oasr.completions)
104
+ _values 'boolean' true false
105
+ ;;
106
+ esac
107
+ fi
108
+ ;;
109
+ get)
110
+ _oasr_config_keys
111
+ ;;
112
+ esac
113
+ ;;
114
+ esac
115
+ }
116
+
117
+ _oasr_registry() {
118
+ local -a subcommands
119
+ subcommands=(
120
+ 'add:Add skill to registry'
121
+ 'rm:Remove skill from registry'
122
+ 'sync:Sync remote skills'
123
+ 'list:List registry skills'
124
+ 'validate:Validate registry'
125
+ 'prune:Clean up registry'
126
+ )
127
+
128
+ _arguments -C \
129
+ '1:subcommand:->subcommand' \
130
+ '*::arg:->args'
131
+
132
+ case $state in
133
+ subcommand)
134
+ _describe 'registry subcommand' subcommands
135
+ ;;
136
+ args)
137
+ case ${words[1]} in
138
+ add)
139
+ _alternative \
140
+ 'directories:directory:_directories' \
141
+ 'urls:url:(http:// https:// git@)'
142
+ ;;
143
+ rm)
144
+ _oasr_skills
145
+ ;;
146
+ prune)
147
+ _arguments '--dry-run[Show what would be removed]'
148
+ ;;
149
+ esac
150
+ ;;
151
+ esac
152
+ }
153
+
154
+ _oasr_completion() {
155
+ local -a shells
156
+ shells=(
157
+ 'bash:Bash completion'
158
+ 'zsh:Zsh completion'
159
+ 'fish:Fish completion'
160
+ 'powershell:PowerShell completion'
161
+ 'install:Auto-detect and install'
162
+ 'uninstall:Remove completions'
163
+ )
164
+
165
+ _arguments \
166
+ '--force[Force reinstall]' \
167
+ '--dry-run[Preview without installing]' \
168
+ '1:shell:->shell'
169
+
170
+ case $state in
171
+ shell)
172
+ _describe 'shell' shells
173
+ ;;
174
+ esac
175
+ }
176
+
177
+ _oasr_adapter() {
178
+ local -a subcommands
179
+ subcommands=(
180
+ 'list:List adapters'
181
+ 'generate:Generate adapter files'
182
+ )
183
+
184
+ _arguments -C \
185
+ '1:subcommand:->subcommand' \
186
+ '*::arg:->args'
187
+
188
+ case $state in
189
+ subcommand)
190
+ _describe 'adapter subcommand' subcommands
191
+ ;;
192
+ esac
193
+ }
194
+
195
+ _oasr() {
196
+ local -a commands
197
+ commands=(
198
+ 'registry:Manage skill registry'
199
+ 'diff:Show tracked skill status'
200
+ 'sync:Refresh tracked skills'
201
+ 'config:Manage configuration'
202
+ 'clone:Clone skills to directory'
203
+ 'exec:Execute a skill'
204
+ 'use:DEPRECATED - use clone instead'
205
+ 'find:Find skills recursively'
206
+ 'validate:Validate skills'
207
+ 'clean:Clean up corrupted skills'
208
+ 'adapter:Generate IDE-specific files'
209
+ 'update:Update OASR tool'
210
+ 'info:Show skill information'
211
+ 'help:Show help'
212
+ 'completion:Manage shell completions'
213
+ )
214
+
215
+ _arguments -C \
216
+ '(--help -h)'{--help,-h}'[Show help]' \
217
+ '--version[Show version]' \
218
+ '--config[Config file path]:file:_files' \
219
+ '--json[JSON output]' \
220
+ '--quiet[Suppress warnings]' \
221
+ '1:command:->command' \
222
+ '*::arg:->args'
223
+
224
+ case $state in
225
+ command)
226
+ _describe 'oasr command' commands
227
+ ;;
228
+ args)
229
+ case ${words[1]} in
230
+ exec)
231
+ _oasr_exec
232
+ ;;
233
+ clone)
234
+ _oasr_clone
235
+ ;;
236
+ info)
237
+ _oasr_info
238
+ ;;
239
+ validate)
240
+ _oasr_validate
241
+ ;;
242
+ config)
243
+ _oasr_config
244
+ ;;
245
+ registry)
246
+ _oasr_registry
247
+ ;;
248
+ completion)
249
+ _oasr_completion
250
+ ;;
251
+ adapter)
252
+ _oasr_adapter
253
+ ;;
254
+ esac
255
+ ;;
256
+ esac
257
+ }
258
+
259
+ _oasr "$@"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oasr
3
- Version: 0.5.1
3
+ Version: 0.5.2
4
4
  Summary: CLI for managing agent skills across IDE integrations
5
5
  Project-URL: Homepage, https://github.com/jgodau/asr
6
6
  Project-URL: Repository, https://github.com/jgodau/asr
@@ -317,6 +317,26 @@ Remote skills are fetched on-demand during `adapter` and `use` operations. The r
317
317
 
318
318
  ---
319
319
 
320
+ ## Shell Completions
321
+
322
+ OASR supports intelligent tab completion for Bash, Zsh, Fish, and PowerShell:
323
+
324
+ ```bash
325
+ # Install for your current shell
326
+ oasr completion install
327
+
328
+ # Now try it:
329
+ oasr <TAB> # Complete commands
330
+ oasr info <TAB> # Complete skill names
331
+ oasr exec --<TAB> # Complete flags
332
+ ```
333
+
334
+ Completions are **dynamic** — skill names, agents, and profiles are fetched live from your registry.
335
+
336
+ See [`oasr completion --help`](docs/commands/COMPLETION.md) for details.
337
+
338
+ ---
339
+
320
340
  ## Documentation
321
341
 
322
342
  - **[Quickstart](docs/QUICKSTART.md)** — Installation and first steps
@@ -1,7 +1,7 @@
1
1
  __init__.py,sha256=cYuwXNht5J2GDPEbHz57rmXRyWzaUgAaCXz8okR0rKE,84
2
2
  __main__.py,sha256=Due_Us-4KNlLZhf8MkmoP1hWS5qMWmpZvz2ZaCqPHT4,120
3
3
  adapter.py,sha256=WEpYkKDTb7We0zU9i6Z-r5ydtUdghNhxTZ5Eq58h4fU,10027
4
- cli.py,sha256=xghN20mgfEeh3vR_Vaiv0i2f1MBN6gk8J0uU3kXRK8g,2672
4
+ cli.py,sha256=LQg93XqUurMvcga2gV6sebv2RXGqfwDNvCN_UOLeTUc,2820
5
5
  discovery.py,sha256=WWF8SN2LH88mOUBJLavM7rvXcxi6uDQGpqRK20GysxA,3298
6
6
  manifest.py,sha256=feNCjkFWfhoVubevKjLtKoIEuzT1YGQn6wWgs9XM8_o,12229
7
7
  registry.py,sha256=zGutwVP39xaYqc3KDEXMWCV1tORYpqc5JISO8OaWP1Q,4470
@@ -27,6 +27,7 @@ commands/adapter.py,sha256=_68v3t-dRU0mszzL4udKs1bKennyg7RfBTaK2fDGTsE,3215
27
27
  commands/add.py,sha256=NJLQ-8-3zy7o6S9VLfL_wauP-Vz0oNGwN3nvtiwxNYM,15255
28
28
  commands/clean.py,sha256=RQBAfe6iCLsjMqUyVR55JdYX9MBqgrUuIrA8rFKs1J0,1102
29
29
  commands/clone.py,sha256=4APH34-yHjiXQIQwBnKOSEQ_sxV24_GKypcOJMfncvs,5912
30
+ commands/completion.py,sha256=Y2KshaJ64vI1fcTR5z2KTJT7u9PPK_w8qMf5HK_q9ns,8570
30
31
  commands/config.py,sha256=4kzDEjVpwrmMPK_DPYePdQe2lGh_b8waYORZDHCDYZw,6976
31
32
  commands/diff.py,sha256=37JMjvfAEfvK7-4X5iFbD-IGkS8ae4YSY7ZDIZF5B9E,5766
32
33
  commands/exec.py,sha256=zFmxxclpHQF39sqDpR5436XQiEYo334BGcQ5a8gbR9I,8711
@@ -41,6 +42,11 @@ commands/sync.py,sha256=ZQoB5hBqrzvM6LUQVlKqHQVJib4dB5qe5M-pVG2vtGM,4946
41
42
  commands/update.py,sha256=bOWjdTNyeYg-hvXv5GfUzEtsTA7gU9JLM592GI9Oq68,11939
42
43
  commands/use.py,sha256=ggB28g2BDg3Lv3nF40wnDAJ7p0mo6C1pc1KgahvQYXM,1452
43
44
  commands/validate.py,sha256=Y8TLHxW4Z98onmzu-h-kDIET-48lVaIdQXOvuyBemLw,2361
45
+ completions/__init__.py,sha256=cLGMHifEf91ElOIMSVffVWcifjGZ7oStb0Ot4ivLmmE,41
46
+ completions/bash.sh,sha256=gqwuOqUDayPQ5_fHUtttJ_AK-Jef-vgSkUATbbtJBic,6169
47
+ completions/fish.fish,sha256=LXUPp3Ad8aJ7j9m_xlX9Ej9H-3xLUhhMSzsB02oH8Vw,8042
48
+ completions/powershell.ps1,sha256=dRtY-w8Hd3EmmJTtoDdkYzFN6tYiUtCeuu0pufUFsps,4210
49
+ completions/zsh.sh,sha256=Pt-jfSHy8Q5kRtn314ejmP3_VCQGzcHAmK_buOKE4JI,6751
44
50
  config/__init__.py,sha256=glSjT1_y4aOfhZ8odrUWCGF1hBbY_huTjVp6suepHDY,3647
45
51
  config/defaults.py,sha256=JfCltQYoE7EqBYlxsNrSITLmwifTvRrJe5lqL0Ys7Cs,986
46
52
  config/env.py,sha256=WgnQXjhfvV7m1oxZCK9WdIX_rqLy_-BOSuPjbpjdI1c,7163
@@ -52,9 +58,9 @@ policy/profile.py,sha256=WDKaUagsWnBPGz5a_OOcxTsdZ66WjaIaR0R7ITVqy8g,6790
52
58
  skillcopy/__init__.py,sha256=YUglUkDzKfnCt4ar_DU33ksI9fGyn2UYbV7qn2c_BcU,2322
53
59
  skillcopy/local.py,sha256=QH6484dCenjg8pfNOyTRbQQBklEWhkkTnfQok5ssf_4,1049
54
60
  skillcopy/remote.py,sha256=83jRA2VfjtSDGO-YM1x3WGJjKvWzK1RmSTL7SdUOz8s,3155
55
- oasr-0.5.1.dist-info/METADATA,sha256=fAfdWjbFnZGfRpQ7gJx1IgpKLbaXgpFZz6ddjdzumxc,17924
56
- oasr-0.5.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
57
- oasr-0.5.1.dist-info/entry_points.txt,sha256=VnMuOi6XYMbzAD2bP0X5uV1sQXjOqoDWJ33Lsxwq8u8,52
58
- oasr-0.5.1.dist-info/licenses/LICENSE,sha256=nQ1j9Ldb8FlJ-z7y2WuXPIlyfnYC7YPasjGdOBgcfP4,10561
59
- oasr-0.5.1.dist-info/licenses/NOTICE,sha256=EsfkCN0ZRDS0oj3ADvMKeKrAXaPlC8YfpSjvjGVv9jE,207
60
- oasr-0.5.1.dist-info/RECORD,,
61
+ oasr-0.5.2.dist-info/METADATA,sha256=SQ26Gtaa3LH-7f5CSHfM1yLUzNmizhYEuWO9lqTqSVM,18413
62
+ oasr-0.5.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
63
+ oasr-0.5.2.dist-info/entry_points.txt,sha256=VnMuOi6XYMbzAD2bP0X5uV1sQXjOqoDWJ33Lsxwq8u8,52
64
+ oasr-0.5.2.dist-info/licenses/LICENSE,sha256=nQ1j9Ldb8FlJ-z7y2WuXPIlyfnYC7YPasjGdOBgcfP4,10561
65
+ oasr-0.5.2.dist-info/licenses/NOTICE,sha256=EsfkCN0ZRDS0oj3ADvMKeKrAXaPlC8YfpSjvjGVv9jE,207
66
+ oasr-0.5.2.dist-info/RECORD,,
File without changes