oasr 0.5.2__tar.gz → 0.6.0__tar.gz
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.
- {oasr-0.5.2 → oasr-0.6.0}/CHANGELOG.md +21 -0
- {oasr-0.5.2 → oasr-0.6.0}/PKG-INFO +31 -21
- {oasr-0.5.2 → oasr-0.6.0}/README.md +29 -20
- {oasr-0.5.2 → oasr-0.6.0}/docs/commands/.INDEX.md +2 -1
- {oasr-0.5.2 → oasr-0.6.0}/docs/commands/CLONE.md +4 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/commands/CONFIG.md +117 -33
- {oasr-0.5.2 → oasr-0.6.0}/docs/commands/EXEC.md +36 -1
- {oasr-0.5.2 → oasr-0.6.0}/docs/commands/HELP.md +1 -0
- oasr-0.6.0/docs/commands/PROFILE.md +25 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/commands/UPDATE.md +3 -2
- {oasr-0.5.2 → oasr-0.6.0}/docs/configuration/README.md +17 -3
- {oasr-0.5.2 → oasr-0.6.0}/docs/configuration/environment-variables.md +1 -1
- {oasr-0.5.2 → oasr-0.6.0}/docs/configuration/profiles.md +34 -2
- {oasr-0.5.2 → oasr-0.6.0}/pyproject.toml +2 -1
- {oasr-0.5.2 → oasr-0.6.0}/src/agents/base.py +17 -3
- {oasr-0.5.2 → oasr-0.6.0}/src/agents/claude.py +12 -2
- {oasr-0.5.2 → oasr-0.6.0}/src/agents/codex.py +12 -2
- {oasr-0.5.2 → oasr-0.6.0}/src/agents/copilot.py +12 -2
- {oasr-0.5.2 → oasr-0.6.0}/src/agents/opencode.py +12 -2
- {oasr-0.5.2 → oasr-0.6.0}/src/cli.py +3 -2
- oasr-0.6.0/src/commands/config.py +462 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/commands/exec.py +21 -1
- oasr-0.6.0/src/commands/profile.py +84 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/commands/update.py +89 -7
- {oasr-0.5.2 → oasr-0.6.0}/src/completions/bash.sh +19 -6
- {oasr-0.5.2 → oasr-0.6.0}/src/completions/fish.fish +21 -7
- {oasr-0.5.2 → oasr-0.6.0}/src/completions/powershell.ps1 +77 -8
- {oasr-0.5.2 → oasr-0.6.0}/src/completions/zsh.sh +31 -5
- {oasr-0.5.2 → oasr-0.6.0}/src/config/__init__.py +11 -0
- oasr-0.6.0/src/config/defaults.py +23 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/config/schema.py +3 -29
- oasr-0.6.0/src/policy/defaults.py +11 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/policy/profile.py +5 -7
- oasr-0.6.0/src/profiles/__init__.py +23 -0
- oasr-0.6.0/src/profiles/builtins.py +63 -0
- oasr-0.6.0/src/profiles/loader.py +74 -0
- oasr-0.6.0/src/profiles/paths.py +22 -0
- oasr-0.6.0/src/profiles/registry.py +19 -0
- oasr-0.6.0/src/profiles/summary.py +23 -0
- oasr-0.6.0/src/profiles/validation.py +34 -0
- {oasr-0.5.2 → oasr-0.6.0}/tests/test_config.py +31 -0
- {oasr-0.5.2 → oasr-0.6.0}/tests/test_config_command.py +35 -3
- {oasr-0.5.2 → oasr-0.6.0}/tests/test_exec.py +178 -3
- {oasr-0.5.2 → oasr-0.6.0}/tests/test_policy_profile.py +1 -1
- oasr-0.6.0/tests/test_profile_command.py +78 -0
- oasr-0.5.2/src/commands/config.py +0 -215
- oasr-0.5.2/src/config/defaults.py +0 -40
- oasr-0.5.2/src/policy/defaults.py +0 -27
- {oasr-0.5.2 → oasr-0.6.0}/.gitignore +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/CONTRIBUTING.md +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/LICENSE +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/NOTICE +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/.INDEX.md +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/.images/adapter.png +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/.images/add-glob.png +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/.images/add-remote.png +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/.images/add.png +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/.images/find-add.png +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/.images/find.png +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/.images/help.png +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/.images/info.png +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/.images/list.png +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/.images/rm-glob.png +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/.images/rm.png +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/.images/status.png +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/.images/sync-update.png +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/.images/sync.png +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/.images/use.png +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/QUICKSTART.md +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/commands/ADAPTER.md +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/commands/ADD.md +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/commands/CLEAN.md +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/commands/COMPLETION.md +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/commands/DIFF.md +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/commands/FIND.md +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/commands/INFO.md +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/commands/LIST.md +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/commands/REGISTRY.md +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/commands/RM.md +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/commands/ROOT.md +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/commands/STATUS.md +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/commands/SYNC.md +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/commands/USE.md +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/commands/VALIDATE.md +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/config.example.toml +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/configuration/.INDEX +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/configuration/adapter.md +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/configuration/agent.md +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/configuration/examples/ci-cd.toml +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/configuration/examples/development.toml +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/configuration/examples/minimal.toml +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/configuration/examples/production.toml +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/configuration/precedence.md +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/configuration/validation.md +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/validation/.INDEX.md +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/validation/ERRORS.md +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/validation/INFO.md +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/validation/RULES.md +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/docs/validation/WARNINGS.md +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/install.ps1 +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/install.sh +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/llms.txt +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/scripts/README.md +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/scripts/fix.sh +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/scripts/lint.sh +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/scripts/test.sh +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/__init__.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/__main__.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/adapter.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/adapters/__init__.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/adapters/base.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/adapters/claude.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/adapters/codex.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/adapters/copilot.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/adapters/cursor.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/adapters/windsurf.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/agents/__init__.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/agents/registry.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/commands/__init__.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/commands/adapter.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/commands/add.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/commands/clean.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/commands/clone.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/commands/completion.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/commands/diff.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/commands/find.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/commands/help.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/commands/info.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/commands/list.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/commands/registry.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/commands/rm.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/commands/status.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/commands/sync.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/commands/use.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/commands/validate.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/completions/__init__.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/config/env.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/discovery.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/manifest.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/policy/__init__.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/policy/enforcement.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/registry.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/remote.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/skillcopy/__init__.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/skillcopy/local.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/skillcopy/remote.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/tracking.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/src/validate.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/tests/conftest.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/tests/test_adapters.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/tests/test_agents.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/tests/test_clone.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/tests/test_completion.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/tests/test_config_env.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/tests/test_config_integration.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/tests/test_copy.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/tests/test_e2e_commands.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/tests/test_help.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/tests/test_list.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/tests/test_multi_skill.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/tests/test_policy_enforcement.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/tests/test_remote.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/tests/test_tracking.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/tests/test_use_glob.py +0 -0
- {oasr-0.5.2 → oasr-0.6.0}/uv.lock +0 -0
|
@@ -4,6 +4,22 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [0.6.0] - 2026-02-03
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- **🧭 Profile selection command** — New `oasr profile` command with interactive selector or explicit profile selection.
|
|
11
|
+
- **📄 Profile file support** — Auto-load `~/.oasr/profile/*.toml` profiles with inline config overrides.
|
|
12
|
+
- **🔧 Config subcommands** — `oasr config agent|validation|adapter|oasr|profiles` for focused views.
|
|
13
|
+
- **✅ Config validation and reference** — `oasr config validate` and `oasr config man` helpers.
|
|
14
|
+
- **Default profiles** — New built-ins: `strict`, `dev`, `unsafe`.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
- **Profiles subsystem** — New `profiles` subpackage with loaders, validation, and summary helpers.
|
|
18
|
+
- **Config listing** — Lists profiles with compact capability summaries and completions setting.
|
|
19
|
+
|
|
20
|
+
### Documentation
|
|
21
|
+
- **Config + profile docs** — Updated configuration guides and new `docs/commands/PROFILE.md`.
|
|
22
|
+
|
|
7
23
|
## [0.5.2] - 2026-02-02
|
|
8
24
|
|
|
9
25
|
### Added
|
|
@@ -25,6 +41,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
25
41
|
- Adapter, find, help commands
|
|
26
42
|
- Total test count: 282 tests (all passing)
|
|
27
43
|
- Ensures no regressions in existing functionality
|
|
44
|
+
- **⚠️ Exec Unsafe Pass-through** — Optional unsafe mode forwarding for agent CLIs
|
|
45
|
+
- `oasr exec --unsafe` forwards `--skip-git-repo-check` to Codex
|
|
46
|
+
- `oasr exec --unsafe` forwards `--dangerously-skip-permissions` to Claude
|
|
47
|
+
- Unsupported agents (Copilot/OpenCode) emit a warning with guidance
|
|
28
48
|
|
|
29
49
|
### Documentation
|
|
30
50
|
- **[docs/commands/COMPLETION.md](docs/commands/COMPLETION.md)**: Complete completion command reference
|
|
@@ -34,6 +54,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
34
54
|
- Examples and usage patterns
|
|
35
55
|
- **[README.md](README.md)**: Added Shell Completions section with quickstart
|
|
36
56
|
- **[docs/commands/.INDEX.md](docs/commands/.INDEX.md)**: Added completion to command index
|
|
57
|
+
- **[docs/commands/EXEC.md](docs/commands/EXEC.md)**: Documented `--unsafe` and trusted directory guidance
|
|
37
58
|
|
|
38
59
|
### Technical
|
|
39
60
|
- **New module**: `src/commands/completion.py` (259 lines) with shell detection and installation
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: oasr
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
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
|
|
@@ -210,6 +210,7 @@ Classifier: Topic :: Software Development :: Build Tools
|
|
|
210
210
|
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
211
211
|
Requires-Python: >=3.10
|
|
212
212
|
Requires-Dist: pyyaml>=6.0
|
|
213
|
+
Requires-Dist: questionary>=2.0.1
|
|
213
214
|
Requires-Dist: tomli-w>=1.0.0
|
|
214
215
|
Requires-Dist: tomli>=2.0.0; python_version < '3.11'
|
|
215
216
|
Provides-Extra: dev
|
|
@@ -219,7 +220,7 @@ Description-Content-Type: text/markdown
|
|
|
219
220
|
|
|
220
221
|
# OASR
|
|
221
222
|
|
|
222
|
-
**Open Agent Skill Registry** —
|
|
223
|
+
**Open Agent Skill Registry** — Register, sync, and reuse AI agent skills across IDEs with a single source of truth.
|
|
223
224
|
|
|
224
225
|
---
|
|
225
226
|
|
|
@@ -229,16 +230,22 @@ You've built useful skills for your AI coding assistant. They work great in Curs
|
|
|
229
230
|
|
|
230
231
|
Each tool expects skills in different locations with different formats:
|
|
231
232
|
|
|
232
|
-
- Cursor: `.cursor/
|
|
233
|
-
- Windsurf: `.windsurf/
|
|
233
|
+
- Cursor: `.cursor/commands/`
|
|
234
|
+
- Windsurf: `.windsurf/workflows/`
|
|
234
235
|
- Claude: `.claude/commands/`
|
|
235
|
-
- Copilot: `.github
|
|
236
|
+
- Copilot: `.github/prompts/`
|
|
236
237
|
|
|
237
238
|
So you copy your skills everywhere. Then you improve one. Now the copies are stale. You forget which version is current. Some break silently. This is **skill drift**.
|
|
238
239
|
|
|
239
240
|
## The Solution
|
|
240
241
|
|
|
241
|
-
ASR keeps your skills in
|
|
242
|
+
ASR keeps your skills in a registry, syncs local and remote sources, and generates thin adapters for each IDE.
|
|
243
|
+
It also lets you execute skills safely with policy profiles.
|
|
244
|
+
|
|
245
|
+
Key capabilities:
|
|
246
|
+
- Register skills once (local folders or GitHub/GitLab URLs)
|
|
247
|
+
- Sync and track drift across sources
|
|
248
|
+
- Generate IDE adapters and run skills via `oasr exec`
|
|
242
249
|
|
|
243
250
|
```text
|
|
244
251
|
┌─────────────────────────────────────────────────────────┐
|
|
@@ -267,12 +274,15 @@ No copying. No drift. One source of truth.
|
|
|
267
274
|
|
|
268
275
|
```bash
|
|
269
276
|
# Register local skills
|
|
270
|
-
oasr add ~/skills/git-commit
|
|
271
|
-
oasr add ~/skills/code-review
|
|
277
|
+
oasr registry add ~/skills/git-commit
|
|
278
|
+
oasr registry add ~/skills/code-review
|
|
279
|
+
|
|
280
|
+
# List registered skills
|
|
281
|
+
oasr registry list
|
|
272
282
|
|
|
273
283
|
# Register remote skills from GitHub/GitLab
|
|
274
|
-
oasr add https://github.com/user/skills-repo/tree/main/my-skill
|
|
275
|
-
oasr add https://gitlab.com/org/project/tree/main/cool-skill
|
|
284
|
+
oasr registry add https://github.com/user/skills-repo/tree/main/my-skill
|
|
285
|
+
oasr registry add https://gitlab.com/org/project/tree/main/cool-skill
|
|
276
286
|
|
|
277
287
|
# Generate adapters for a project
|
|
278
288
|
oasr adapter --output-dir ~/projects/my-app
|
|
@@ -294,16 +304,16 @@ ASR supports registering skills directly from GitHub and GitLab repositories:
|
|
|
294
304
|
|
|
295
305
|
```bash
|
|
296
306
|
# Add a skill from GitHub
|
|
297
|
-
oasr add https://github.com/user/repo/tree/main/skills/my-skill
|
|
307
|
+
oasr registry add https://github.com/user/repo/tree/main/skills/my-skill
|
|
298
308
|
|
|
299
309
|
# Add a skill from GitLab
|
|
300
|
-
oasr add https://gitlab.com/org/project/tree/dev/cool-skill
|
|
310
|
+
oasr registry add https://gitlab.com/org/project/tree/dev/cool-skill
|
|
301
311
|
|
|
302
312
|
# Sync remote skills (check for updates)
|
|
303
|
-
oasr sync
|
|
313
|
+
oasr registry sync
|
|
304
314
|
|
|
305
315
|
# Use remote skills
|
|
306
|
-
oasr
|
|
316
|
+
oasr clone my-skill -d ./output
|
|
307
317
|
```
|
|
308
318
|
|
|
309
319
|
**Authentication** (optional, for private repos and higher rate limits):
|
|
@@ -313,7 +323,7 @@ export GITHUB_TOKEN=ghp_your_token_here
|
|
|
313
323
|
export GITLAB_TOKEN=glpat_your_token_here
|
|
314
324
|
```
|
|
315
325
|
|
|
316
|
-
Remote skills are fetched on-demand during `adapter` and `
|
|
326
|
+
Remote skills are fetched on-demand during `adapter` and `clone` operations. The registry stores the URL, and `oasr registry sync` checks if the remote source has changed.
|
|
317
327
|
|
|
318
328
|
---
|
|
319
329
|
|
|
@@ -345,7 +355,7 @@ See [`oasr completion --help`](docs/commands/COMPLETION.md) for details.
|
|
|
345
355
|
|
|
346
356
|
---
|
|
347
357
|
|
|
348
|
-
## Supported `
|
|
358
|
+
## Supported `oasr adapter` IDEs
|
|
349
359
|
|
|
350
360
|
| IDE | Adapter | Output |
|
|
351
361
|
|----------------|------------|-------------------------------|
|
|
@@ -367,11 +377,11 @@ See [LICENSE](LICENSE).
|
|
|
367
377
|
|
|
368
378
|
| Command | Screenshot |
|
|
369
379
|
|---------|-----------|
|
|
370
|
-
| **oasr list** |  |
|
|
371
|
-
| **oasr add** (local) |  |
|
|
372
|
-
| **oasr add** (remote) |  |
|
|
373
|
-
| **oasr sync** |  |
|
|
374
|
-
| **oasr
|
|
380
|
+
| **oasr registry list** |  |
|
|
381
|
+
| **oasr registry add** (local) |  |
|
|
382
|
+
| **oasr registry add** (remote) |  |
|
|
383
|
+
| **oasr registry sync** |  |
|
|
384
|
+
| **oasr registry -v** |  |
|
|
375
385
|
| **oasr find** |  |
|
|
376
386
|
| **oasr adapter** |  |
|
|
377
387
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# OASR
|
|
2
2
|
|
|
3
|
-
**Open Agent Skill Registry** —
|
|
3
|
+
**Open Agent Skill Registry** — Register, sync, and reuse AI agent skills across IDEs with a single source of truth.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -10,16 +10,22 @@ You've built useful skills for your AI coding assistant. They work great in Curs
|
|
|
10
10
|
|
|
11
11
|
Each tool expects skills in different locations with different formats:
|
|
12
12
|
|
|
13
|
-
- Cursor: `.cursor/
|
|
14
|
-
- Windsurf: `.windsurf/
|
|
13
|
+
- Cursor: `.cursor/commands/`
|
|
14
|
+
- Windsurf: `.windsurf/workflows/`
|
|
15
15
|
- Claude: `.claude/commands/`
|
|
16
|
-
- Copilot: `.github
|
|
16
|
+
- Copilot: `.github/prompts/`
|
|
17
17
|
|
|
18
18
|
So you copy your skills everywhere. Then you improve one. Now the copies are stale. You forget which version is current. Some break silently. This is **skill drift**.
|
|
19
19
|
|
|
20
20
|
## The Solution
|
|
21
21
|
|
|
22
|
-
ASR keeps your skills in
|
|
22
|
+
ASR keeps your skills in a registry, syncs local and remote sources, and generates thin adapters for each IDE.
|
|
23
|
+
It also lets you execute skills safely with policy profiles.
|
|
24
|
+
|
|
25
|
+
Key capabilities:
|
|
26
|
+
- Register skills once (local folders or GitHub/GitLab URLs)
|
|
27
|
+
- Sync and track drift across sources
|
|
28
|
+
- Generate IDE adapters and run skills via `oasr exec`
|
|
23
29
|
|
|
24
30
|
```text
|
|
25
31
|
┌─────────────────────────────────────────────────────────┐
|
|
@@ -48,12 +54,15 @@ No copying. No drift. One source of truth.
|
|
|
48
54
|
|
|
49
55
|
```bash
|
|
50
56
|
# Register local skills
|
|
51
|
-
oasr add ~/skills/git-commit
|
|
52
|
-
oasr add ~/skills/code-review
|
|
57
|
+
oasr registry add ~/skills/git-commit
|
|
58
|
+
oasr registry add ~/skills/code-review
|
|
59
|
+
|
|
60
|
+
# List registered skills
|
|
61
|
+
oasr registry list
|
|
53
62
|
|
|
54
63
|
# Register remote skills from GitHub/GitLab
|
|
55
|
-
oasr add https://github.com/user/skills-repo/tree/main/my-skill
|
|
56
|
-
oasr add https://gitlab.com/org/project/tree/main/cool-skill
|
|
64
|
+
oasr registry add https://github.com/user/skills-repo/tree/main/my-skill
|
|
65
|
+
oasr registry add https://gitlab.com/org/project/tree/main/cool-skill
|
|
57
66
|
|
|
58
67
|
# Generate adapters for a project
|
|
59
68
|
oasr adapter --output-dir ~/projects/my-app
|
|
@@ -75,16 +84,16 @@ ASR supports registering skills directly from GitHub and GitLab repositories:
|
|
|
75
84
|
|
|
76
85
|
```bash
|
|
77
86
|
# Add a skill from GitHub
|
|
78
|
-
oasr add https://github.com/user/repo/tree/main/skills/my-skill
|
|
87
|
+
oasr registry add https://github.com/user/repo/tree/main/skills/my-skill
|
|
79
88
|
|
|
80
89
|
# Add a skill from GitLab
|
|
81
|
-
oasr add https://gitlab.com/org/project/tree/dev/cool-skill
|
|
90
|
+
oasr registry add https://gitlab.com/org/project/tree/dev/cool-skill
|
|
82
91
|
|
|
83
92
|
# Sync remote skills (check for updates)
|
|
84
|
-
oasr sync
|
|
93
|
+
oasr registry sync
|
|
85
94
|
|
|
86
95
|
# Use remote skills
|
|
87
|
-
oasr
|
|
96
|
+
oasr clone my-skill -d ./output
|
|
88
97
|
```
|
|
89
98
|
|
|
90
99
|
**Authentication** (optional, for private repos and higher rate limits):
|
|
@@ -94,7 +103,7 @@ export GITHUB_TOKEN=ghp_your_token_here
|
|
|
94
103
|
export GITLAB_TOKEN=glpat_your_token_here
|
|
95
104
|
```
|
|
96
105
|
|
|
97
|
-
Remote skills are fetched on-demand during `adapter` and `
|
|
106
|
+
Remote skills are fetched on-demand during `adapter` and `clone` operations. The registry stores the URL, and `oasr registry sync` checks if the remote source has changed.
|
|
98
107
|
|
|
99
108
|
---
|
|
100
109
|
|
|
@@ -126,7 +135,7 @@ See [`oasr completion --help`](docs/commands/COMPLETION.md) for details.
|
|
|
126
135
|
|
|
127
136
|
---
|
|
128
137
|
|
|
129
|
-
## Supported `
|
|
138
|
+
## Supported `oasr adapter` IDEs
|
|
130
139
|
|
|
131
140
|
| IDE | Adapter | Output |
|
|
132
141
|
|----------------|------------|-------------------------------|
|
|
@@ -148,11 +157,11 @@ See [LICENSE](LICENSE).
|
|
|
148
157
|
|
|
149
158
|
| Command | Screenshot |
|
|
150
159
|
|---------|-----------|
|
|
151
|
-
| **oasr list** |  |
|
|
152
|
-
| **oasr add** (local) |  |
|
|
153
|
-
| **oasr add** (remote) |  |
|
|
154
|
-
| **oasr sync** |  |
|
|
155
|
-
| **oasr
|
|
160
|
+
| **oasr registry list** |  |
|
|
161
|
+
| **oasr registry add** (local) |  |
|
|
162
|
+
| **oasr registry add** (remote) |  |
|
|
163
|
+
| **oasr registry sync** |  |
|
|
164
|
+
| **oasr registry -v** |  |
|
|
156
165
|
| **oasr find** |  |
|
|
157
166
|
| **oasr adapter** |  |
|
|
158
167
|
|
|
@@ -7,9 +7,10 @@
|
|
|
7
7
|
- [oasr diff](DIFF.md) - Show status of tracked skills
|
|
8
8
|
- [oasr sync](SYNC.md) - Refresh outdated tracked skills
|
|
9
9
|
- [oasr config](CONFIG.md) - Manage configuration (NEW in v0.4.0)
|
|
10
|
+
- [oasr profile](PROFILE.md) - Select execution profile (NEW in v0.6.0)
|
|
10
11
|
- [oasr clone](CLONE.md) - Clone skill(s) to target directory (NEW in v0.4.0)
|
|
11
12
|
- [oasr exec](EXEC.md) - Execute skills as CLI tools (NEW in v0.4.0)
|
|
12
|
-
- [oasr completion](COMPLETION.md) - Shell tab completion (NEW in v0.
|
|
13
|
+
- [oasr completion](COMPLETION.md) - Shell tab completion (NEW in v0.6.0)
|
|
13
14
|
- [oasr find](FIND.md) - Find/discover skills in your file system
|
|
14
15
|
- [oasr validate](VALIDATE.md) - Validate a skill
|
|
15
16
|
- [oasr adapter](ADAPTER.md) - Generate IDE/Tooling adapters
|
|
@@ -11,6 +11,7 @@ Clone skills from the registry to a target directory. Supports glob patterns and
|
|
|
11
11
|
oasr clone skill-name
|
|
12
12
|
oasr clone skill-name -d /path/to/project
|
|
13
13
|
oasr clone "git-*" # Glob pattern
|
|
14
|
+
oasr clone "*" # Clone all skills (quote to avoid shell expansion)
|
|
14
15
|
oasr clone skill-one skill-two # Multiple skills
|
|
15
16
|
```
|
|
16
17
|
|
|
@@ -28,8 +29,11 @@ Clone multiple skills matching a pattern:
|
|
|
28
29
|
```bash
|
|
29
30
|
oasr clone "python-*" # All Python-related skills
|
|
30
31
|
oasr clone "*-api" # All API-related skills
|
|
32
|
+
oasr clone "*" # All skills in registry
|
|
31
33
|
```
|
|
32
34
|
|
|
35
|
+
> **Note:** Always quote `*` or glob patterns to prevent your shell from expanding them before OASR receives the pattern.
|
|
36
|
+
|
|
33
37
|
### Remote Skill Fetching
|
|
34
38
|
|
|
35
39
|
Remote skills are automatically fetched during clone:
|
|
@@ -10,6 +10,13 @@ Manage OASR configuration settings.
|
|
|
10
10
|
oasr config set <key> <value> # Set a config value
|
|
11
11
|
oasr config get <key> # Get a config value
|
|
12
12
|
oasr config list # Show all configuration
|
|
13
|
+
oasr config agent # Show agent configuration
|
|
14
|
+
oasr config validation # Show validation settings
|
|
15
|
+
oasr config adapter # Show adapter settings
|
|
16
|
+
oasr config oasr # Show core OASR settings
|
|
17
|
+
oasr config profiles # Show available profiles
|
|
18
|
+
oasr config man # Show config reference
|
|
19
|
+
oasr config validate # Validate config file
|
|
13
20
|
oasr config path # Show config file location
|
|
14
21
|
```
|
|
15
22
|
|
|
@@ -27,6 +34,13 @@ oasr config path # Show config file location
|
|
|
27
34
|
oasr config set <key> <value> # Set a config value
|
|
28
35
|
oasr config get <key> # Get a config value
|
|
29
36
|
oasr config list # Show all configuration
|
|
37
|
+
oasr config agent # Show agent configuration
|
|
38
|
+
oasr config validation # Show validation settings
|
|
39
|
+
oasr config adapter # Show adapter settings
|
|
40
|
+
oasr config oasr # Show core OASR settings
|
|
41
|
+
oasr config profiles # Show available profiles
|
|
42
|
+
oasr config man # Show config reference
|
|
43
|
+
oasr config validate # Validate config file
|
|
30
44
|
oasr config path # Show config file location
|
|
31
45
|
```
|
|
32
46
|
|
|
@@ -59,44 +73,62 @@ Returns the value or indicates if not set:
|
|
|
59
73
|
codex
|
|
60
74
|
```
|
|
61
75
|
|
|
62
|
-
### `config
|
|
76
|
+
### `config agent`
|
|
63
77
|
|
|
64
|
-
|
|
78
|
+
Show default agent and availability:
|
|
65
79
|
|
|
66
80
|
```bash
|
|
67
|
-
oasr config
|
|
81
|
+
oasr config agent
|
|
68
82
|
```
|
|
69
83
|
|
|
70
|
-
|
|
84
|
+
### `config validation`
|
|
85
|
+
|
|
86
|
+
Show validation configuration:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
oasr config validation
|
|
71
90
|
```
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
│ Default: codex │
|
|
80
|
-
│ │
|
|
81
|
-
│ Available Agents │
|
|
82
|
-
│ ✓ codex │
|
|
83
|
-
│ ✓ copilot │
|
|
84
|
-
│ ✗ claude │
|
|
85
|
-
│ ✗ opencode │
|
|
86
|
-
│ │
|
|
87
|
-
│ Validation Settings │
|
|
88
|
-
│ Reference max lines: 500 │
|
|
89
|
-
│ Strict mode: false │
|
|
90
|
-
│ │
|
|
91
|
-
│ Adapter Settings │
|
|
92
|
-
│ Default targets: cursor, windsurf │
|
|
93
|
-
│ │
|
|
94
|
-
╰─────────────────────────────────────────╯
|
|
91
|
+
|
|
92
|
+
### `config adapter`
|
|
93
|
+
|
|
94
|
+
Show adapter configuration:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
oasr config adapter
|
|
95
98
|
```
|
|
96
99
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
+
### `config oasr`
|
|
101
|
+
|
|
102
|
+
Show core OASR settings:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
oasr config oasr
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### `config profiles`
|
|
109
|
+
|
|
110
|
+
Show available profiles (built-in + custom + profile files):
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
oasr config profiles
|
|
114
|
+
oasr config profiles --names
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### `config man`
|
|
118
|
+
|
|
119
|
+
Show a concise configuration reference:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
oasr config man
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### `config validate`
|
|
126
|
+
|
|
127
|
+
Validate your config file (creates default if missing):
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
oasr config validate
|
|
131
|
+
```
|
|
100
132
|
|
|
101
133
|
### `config path`
|
|
102
134
|
|
|
@@ -106,11 +138,45 @@ Show the location of the configuration file:
|
|
|
106
138
|
oasr config path
|
|
107
139
|
```
|
|
108
140
|
|
|
109
|
-
|
|
141
|
+
### `config list`
|
|
142
|
+
|
|
143
|
+
Display all configuration with formatted output:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
oasr config list
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**Example output:**
|
|
110
150
|
```
|
|
111
|
-
|
|
151
|
+
Configuration:
|
|
152
|
+
|
|
153
|
+
[agent]
|
|
154
|
+
default = codex ✓
|
|
155
|
+
|
|
156
|
+
Available agents: codex, copilot
|
|
157
|
+
|
|
158
|
+
[validation]
|
|
159
|
+
reference_max_lines = 500
|
|
160
|
+
strict = false
|
|
161
|
+
|
|
162
|
+
[adapter]
|
|
163
|
+
default_targets = cursor, windsurf
|
|
164
|
+
|
|
165
|
+
[oasr]
|
|
166
|
+
default_profile = safe
|
|
167
|
+
completions = true
|
|
168
|
+
|
|
169
|
+
[profiles]
|
|
170
|
+
safe network=off env=off shell=off
|
|
171
|
+
strict network=off env=off shell=off
|
|
172
|
+
dev network=on env=on shell=on
|
|
173
|
+
unsafe network=on env=on shell=on
|
|
112
174
|
```
|
|
113
175
|
|
|
176
|
+
**Agent Availability Indicators:**
|
|
177
|
+
- ✓ — Agent CLI binary found in PATH
|
|
178
|
+
- ✗ — Agent CLI binary not installed
|
|
179
|
+
|
|
114
180
|
## Configuration Structure
|
|
115
181
|
|
|
116
182
|
The config file uses TOML format:
|
|
@@ -125,6 +191,13 @@ strict = false
|
|
|
125
191
|
|
|
126
192
|
[adapter]
|
|
127
193
|
default_targets = ["cursor", "windsurf"]
|
|
194
|
+
|
|
195
|
+
[oasr]
|
|
196
|
+
default_profile = "safe"
|
|
197
|
+
completions = true
|
|
198
|
+
|
|
199
|
+
[profiles.safe]
|
|
200
|
+
# built-in safe profile (override if desired)
|
|
128
201
|
```
|
|
129
202
|
|
|
130
203
|
## Agent Configuration
|
|
@@ -234,7 +307,7 @@ oasr config set agent unknown-agent
|
|
|
234
307
|
|
|
235
308
|
Output:
|
|
236
309
|
```
|
|
237
|
-
Error: 'unknown-agent'
|
|
310
|
+
Error: Invalid agent 'unknown-agent'
|
|
238
311
|
Valid agents: codex, copilot, claude, opencode
|
|
239
312
|
```
|
|
240
313
|
|
|
@@ -260,6 +333,12 @@ Configure a different agent:
|
|
|
260
333
|
oasr config set agent copilot
|
|
261
334
|
```
|
|
262
335
|
|
|
336
|
+
### Config Validation
|
|
337
|
+
|
|
338
|
+
```bash
|
|
339
|
+
oasr config validate
|
|
340
|
+
```
|
|
341
|
+
|
|
263
342
|
## Execution Policy Profiles (v0.5.0+)
|
|
264
343
|
|
|
265
344
|
Policy profiles define security boundaries for `oasr exec`. They control what agents can do during skill execution.
|
|
@@ -270,6 +349,7 @@ Set the default execution policy profile:
|
|
|
270
349
|
|
|
271
350
|
```bash
|
|
272
351
|
oasr config set oasr.default_profile safe
|
|
352
|
+
oasr profile dev
|
|
273
353
|
```
|
|
274
354
|
|
|
275
355
|
This determines which profile is used unless overridden with `--profile`.
|
|
@@ -317,6 +397,10 @@ allow_env = true
|
|
|
317
397
|
|
|
318
398
|
See [`oasr exec` documentation](EXEC.md#security-model) for detailed security model explanation.
|
|
319
399
|
|
|
400
|
+
### Profile Files
|
|
401
|
+
|
|
402
|
+
Place profile files under `~/.oasr/profile/<name>.toml` (body keys only). Inline profiles override files with the same name.
|
|
403
|
+
|
|
320
404
|
## Advanced Usage
|
|
321
405
|
|
|
322
406
|
### Direct Config File Editing
|
|
@@ -15,9 +15,10 @@ oasr exec <skill-name> [options]
|
|
|
15
15
|
- `-p, --prompt TEXT` — Inline prompt/instructions for the agent
|
|
16
16
|
- `-i, --instructions FILE` — Read prompt from a file
|
|
17
17
|
- `-a, --agent AGENT` — Override the default agent (codex, copilot, claude, opencode)
|
|
18
|
-
- `--profile PROFILE` — Use a specific execution policy profile (default: from config)
|
|
18
|
+
- `--profile PROFILE` — Use a specific execution policy profile (default: from config; built-ins: safe, strict, dev, unsafe)
|
|
19
19
|
- `-y, --yes` — Skip confirmation prompt for risky operations
|
|
20
20
|
- `--confirm` — Force confirmation even for safe operations
|
|
21
|
+
- `--unsafe` — Pass unsafe mode flags to the agent CLI (see [Unsafe Mode](#unsafe-mode))
|
|
21
22
|
|
|
22
23
|
## Features
|
|
23
24
|
|
|
@@ -80,6 +81,40 @@ oasr exec my-skill -p "Do something"
|
|
|
80
81
|
oasr exec my-skill --agent copilot -p "Generate code"
|
|
81
82
|
```
|
|
82
83
|
|
|
84
|
+
### Unsafe Mode
|
|
85
|
+
|
|
86
|
+
If your agent refuses to run outside a trusted directory or Git repo, you can pass `--unsafe` to forward the agent's unsafe-mode flags.
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# Codex: skip git repo trust check
|
|
90
|
+
oasr exec my-skill --unsafe -p "Run in this folder"
|
|
91
|
+
|
|
92
|
+
# Claude: bypass permission prompts
|
|
93
|
+
oasr exec my-skill --agent claude --unsafe -p "Analyze this project"
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**Agent behavior:**
|
|
97
|
+
|
|
98
|
+
- **Codex**: adds `--skip-git-repo-check` (Codex CLI requires git repo by default; see Codex non-interactive docs)
|
|
99
|
+
- **Claude**: adds `--dangerously-skip-permissions` (bypasses Claude permission prompts)
|
|
100
|
+
- **Copilot / OpenCode**: `--unsafe` is not forwarded; configure permissions in their own configs
|
|
101
|
+
|
|
102
|
+
**Trusted directory guidance:**
|
|
103
|
+
|
|
104
|
+
- **Codex**: You can avoid `--unsafe` by initializing a git repo (`git init`) or adding trusted directories via Codex config (`--add-dir`).
|
|
105
|
+
- **Claude**: Use `--add-dir` or configure allowed tools/permissions in Claude settings.
|
|
106
|
+
- **OpenCode**: Use `permission.external_directory` in `opencode.json` to allow external paths.
|
|
107
|
+
|
|
108
|
+
### Profile Selection
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
# Set default profile
|
|
112
|
+
oasr profile dev
|
|
113
|
+
|
|
114
|
+
# Override per execution
|
|
115
|
+
oasr exec my-skill --profile strict -p "prompt"
|
|
116
|
+
```
|
|
117
|
+
|
|
83
118
|
### Skill Execution Flow
|
|
84
119
|
|
|
85
120
|
1. **Load skill** from registry by name
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# `oasr profile`
|
|
2
|
+
|
|
3
|
+
List and select execution policy profiles.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
oasr profile # Interactive selector (TTY only)
|
|
7
|
+
oasr profile <name> # Set default profile
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
**Non-interactive behavior:** prints profiles and exits with a hint.
|
|
11
|
+
|
|
12
|
+
## Examples
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
# List and select interactively
|
|
16
|
+
oasr profile
|
|
17
|
+
|
|
18
|
+
# Set default profile
|
|
19
|
+
oasr profile dev
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Related
|
|
23
|
+
|
|
24
|
+
- [Policy Profiles](../configuration/profiles.md)
|
|
25
|
+
- [Config command](CONFIG.md)
|
|
@@ -17,8 +17,8 @@ oasr update --quiet # Suppress info messages
|
|
|
17
17
|
- Remote must be configured (typically GitHub)
|
|
18
18
|
|
|
19
19
|
> **NOTE**
|
|
20
|
-
>
|
|
21
|
-
>
|
|
20
|
+
> `oasr update` targets git installs. For PyPI installs, use:
|
|
21
|
+
> `pip install --upgrade oasr`
|
|
22
22
|
|
|
23
23
|
**Behavior:**
|
|
24
24
|
|
|
@@ -27,6 +27,7 @@ oasr update --quiet # Suppress info messages
|
|
|
27
27
|
- Displays truncated changelog with commit count
|
|
28
28
|
- Reinstalls package with `uv pip install -e .` or falls back to `pip`
|
|
29
29
|
- Suppresses verbose git output
|
|
30
|
+
- If already up to date, checks PyPI and prints update hints to **stderr** when a newer version exists (to preserve stdout for piping)
|
|
30
31
|
|
|
31
32
|
**JSON Output:**
|
|
32
33
|
|