oasr 0.4.0__tar.gz → 0.4.2__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.
Files changed (141) hide show
  1. {oasr-0.4.0 → oasr-0.4.2}/CHANGELOG.md +15 -2
  2. {oasr-0.4.0 → oasr-0.4.2}/PKG-INFO +1 -1
  3. {oasr-0.4.0 → oasr-0.4.2}/docs/commands/.INDEX.md +4 -2
  4. oasr-0.4.2/docs/commands/CLEAN.md +13 -0
  5. {oasr-0.4.0 → oasr-0.4.2}/docs/commands/CLONE.md +0 -1
  6. {oasr-0.4.0 → oasr-0.4.2}/docs/commands/REGISTRY.md +36 -0
  7. {oasr-0.4.0 → oasr-0.4.2}/pyproject.toml +1 -1
  8. {oasr-0.4.0 → oasr-0.4.2}/src/cli.py +1 -1
  9. oasr-0.4.2/src/commands/clean.py +30 -0
  10. {oasr-0.4.0 → oasr-0.4.2}/src/commands/exec.py +3 -8
  11. {oasr-0.4.0 → oasr-0.4.2}/src/commands/registry.py +144 -0
  12. {oasr-0.4.0 → oasr-0.4.2}/tests/test_exec.py +3 -9
  13. {oasr-0.4.0 → oasr-0.4.2}/uv.lock +1 -1
  14. oasr-0.4.0/docs/commands/CLEAN.md +0 -11
  15. oasr-0.4.0/doctor/SKILL.md +0 -35
  16. oasr-0.4.0/doctor/assets/schemas/session.schema.yaml +0 -87
  17. oasr-0.4.0/doctor/assets/schemas/treatment.schema.yaml +0 -70
  18. oasr-0.4.0/doctor/references/00_ROUTER.md +0 -104
  19. oasr-0.4.0/doctor/references/01_SUMMARY.md +0 -44
  20. oasr-0.4.0/doctor/references/02_TRIGGERS.md +0 -40
  21. oasr-0.4.0/doctor/references/03_ALWAYS.md +0 -43
  22. oasr-0.4.0/doctor/references/04_NEVER.md +0 -45
  23. oasr-0.4.0/doctor/references/05_PROCEDURE.md +0 -99
  24. oasr-0.4.0/doctor/references/06_FAILURES.md +0 -77
  25. oasr-0.4.0/doctor/scripts/include/.doctor/session.yaml +0 -11
  26. oasr-0.4.0/doctor/scripts/include/doctor_cli.py +0 -357
  27. oasr-0.4.0/doctor/scripts/include/doctor_parse.py +0 -348
  28. oasr-0.4.0/doctor/scripts/include/pyproject.toml +0 -12
  29. oasr-0.4.0/doctor/scripts/include/uv.lock +0 -78
  30. oasr-0.4.0/doctor/scripts/router_checks.sh +0 -87
  31. oasr-0.4.0/doctor/scripts/skill.ps1 +0 -65
  32. oasr-0.4.0/doctor/scripts/skill.sh +0 -57
  33. oasr-0.4.0/src/commands/clean.py +0 -155
  34. {oasr-0.4.0 → oasr-0.4.2}/.gitignore +0 -0
  35. {oasr-0.4.0 → oasr-0.4.2}/CONTRIBUTING.md +0 -0
  36. {oasr-0.4.0 → oasr-0.4.2}/LICENSE +0 -0
  37. {oasr-0.4.0 → oasr-0.4.2}/NOTICE +0 -0
  38. {oasr-0.4.0 → oasr-0.4.2}/README.md +0 -0
  39. {oasr-0.4.0 → oasr-0.4.2}/docs/.INDEX.md +0 -0
  40. {oasr-0.4.0 → oasr-0.4.2}/docs/.images/adapter.png +0 -0
  41. {oasr-0.4.0 → oasr-0.4.2}/docs/.images/add-glob.png +0 -0
  42. {oasr-0.4.0 → oasr-0.4.2}/docs/.images/add-remote.png +0 -0
  43. {oasr-0.4.0 → oasr-0.4.2}/docs/.images/add.png +0 -0
  44. {oasr-0.4.0 → oasr-0.4.2}/docs/.images/find-add.png +0 -0
  45. {oasr-0.4.0 → oasr-0.4.2}/docs/.images/find.png +0 -0
  46. {oasr-0.4.0 → oasr-0.4.2}/docs/.images/help.png +0 -0
  47. {oasr-0.4.0 → oasr-0.4.2}/docs/.images/info.png +0 -0
  48. {oasr-0.4.0 → oasr-0.4.2}/docs/.images/list.png +0 -0
  49. {oasr-0.4.0 → oasr-0.4.2}/docs/.images/rm-glob.png +0 -0
  50. {oasr-0.4.0 → oasr-0.4.2}/docs/.images/rm.png +0 -0
  51. {oasr-0.4.0 → oasr-0.4.2}/docs/.images/status.png +0 -0
  52. {oasr-0.4.0 → oasr-0.4.2}/docs/.images/sync-update.png +0 -0
  53. {oasr-0.4.0 → oasr-0.4.2}/docs/.images/sync.png +0 -0
  54. {oasr-0.4.0 → oasr-0.4.2}/docs/.images/use.png +0 -0
  55. {oasr-0.4.0 → oasr-0.4.2}/docs/QUICKSTART.md +0 -0
  56. {oasr-0.4.0 → oasr-0.4.2}/docs/commands/ADAPTER.md +0 -0
  57. {oasr-0.4.0 → oasr-0.4.2}/docs/commands/ADD.md +0 -0
  58. {oasr-0.4.0 → oasr-0.4.2}/docs/commands/CONFIG.md +0 -0
  59. {oasr-0.4.0 → oasr-0.4.2}/docs/commands/DIFF.md +0 -0
  60. {oasr-0.4.0 → oasr-0.4.2}/docs/commands/EXEC.md +0 -0
  61. {oasr-0.4.0 → oasr-0.4.2}/docs/commands/FIND.md +0 -0
  62. {oasr-0.4.0 → oasr-0.4.2}/docs/commands/HELP.md +0 -0
  63. {oasr-0.4.0 → oasr-0.4.2}/docs/commands/INFO.md +0 -0
  64. {oasr-0.4.0 → oasr-0.4.2}/docs/commands/LIST.md +0 -0
  65. {oasr-0.4.0 → oasr-0.4.2}/docs/commands/RM.md +0 -0
  66. {oasr-0.4.0 → oasr-0.4.2}/docs/commands/ROOT.md +0 -0
  67. {oasr-0.4.0 → oasr-0.4.2}/docs/commands/STATUS.md +0 -0
  68. {oasr-0.4.0 → oasr-0.4.2}/docs/commands/SYNC.md +0 -0
  69. {oasr-0.4.0 → oasr-0.4.2}/docs/commands/UPDATE.md +0 -0
  70. {oasr-0.4.0 → oasr-0.4.2}/docs/commands/USE.md +0 -0
  71. {oasr-0.4.0 → oasr-0.4.2}/docs/commands/VALIDATE.md +0 -0
  72. {oasr-0.4.0 → oasr-0.4.2}/docs/validation/.INDEX.md +0 -0
  73. {oasr-0.4.0 → oasr-0.4.2}/docs/validation/ERRORS.md +0 -0
  74. {oasr-0.4.0 → oasr-0.4.2}/docs/validation/INFO.md +0 -0
  75. {oasr-0.4.0 → oasr-0.4.2}/docs/validation/RULES.md +0 -0
  76. {oasr-0.4.0 → oasr-0.4.2}/docs/validation/WARNINGS.md +0 -0
  77. {oasr-0.4.0 → oasr-0.4.2}/install.ps1 +0 -0
  78. {oasr-0.4.0 → oasr-0.4.2}/install.sh +0 -0
  79. {oasr-0.4.0 → oasr-0.4.2}/llms.txt +0 -0
  80. {oasr-0.4.0 → oasr-0.4.2}/scripts/README.md +0 -0
  81. {oasr-0.4.0 → oasr-0.4.2}/scripts/fix.sh +0 -0
  82. {oasr-0.4.0 → oasr-0.4.2}/scripts/lint.sh +0 -0
  83. {oasr-0.4.0 → oasr-0.4.2}/scripts/test.sh +0 -0
  84. {oasr-0.4.0 → oasr-0.4.2}/src/__init__.py +0 -0
  85. {oasr-0.4.0 → oasr-0.4.2}/src/__main__.py +0 -0
  86. {oasr-0.4.0 → oasr-0.4.2}/src/adapter.py +0 -0
  87. {oasr-0.4.0 → oasr-0.4.2}/src/adapters/__init__.py +0 -0
  88. {oasr-0.4.0 → oasr-0.4.2}/src/adapters/base.py +0 -0
  89. {oasr-0.4.0 → oasr-0.4.2}/src/adapters/claude.py +0 -0
  90. {oasr-0.4.0 → oasr-0.4.2}/src/adapters/codex.py +0 -0
  91. {oasr-0.4.0 → oasr-0.4.2}/src/adapters/copilot.py +0 -0
  92. {oasr-0.4.0 → oasr-0.4.2}/src/adapters/cursor.py +0 -0
  93. {oasr-0.4.0 → oasr-0.4.2}/src/adapters/windsurf.py +0 -0
  94. {oasr-0.4.0 → oasr-0.4.2}/src/agents/__init__.py +0 -0
  95. {oasr-0.4.0 → oasr-0.4.2}/src/agents/base.py +0 -0
  96. {oasr-0.4.0 → oasr-0.4.2}/src/agents/claude.py +0 -0
  97. {oasr-0.4.0 → oasr-0.4.2}/src/agents/codex.py +0 -0
  98. {oasr-0.4.0 → oasr-0.4.2}/src/agents/copilot.py +0 -0
  99. {oasr-0.4.0 → oasr-0.4.2}/src/agents/opencode.py +0 -0
  100. {oasr-0.4.0 → oasr-0.4.2}/src/agents/registry.py +0 -0
  101. {oasr-0.4.0 → oasr-0.4.2}/src/commands/__init__.py +0 -0
  102. {oasr-0.4.0 → oasr-0.4.2}/src/commands/adapter.py +0 -0
  103. {oasr-0.4.0 → oasr-0.4.2}/src/commands/add.py +0 -0
  104. {oasr-0.4.0 → oasr-0.4.2}/src/commands/clone.py +0 -0
  105. {oasr-0.4.0 → oasr-0.4.2}/src/commands/config.py +0 -0
  106. {oasr-0.4.0 → oasr-0.4.2}/src/commands/diff.py +0 -0
  107. {oasr-0.4.0 → oasr-0.4.2}/src/commands/find.py +0 -0
  108. {oasr-0.4.0 → oasr-0.4.2}/src/commands/help.py +0 -0
  109. {oasr-0.4.0 → oasr-0.4.2}/src/commands/info.py +0 -0
  110. {oasr-0.4.0 → oasr-0.4.2}/src/commands/list.py +0 -0
  111. {oasr-0.4.0 → oasr-0.4.2}/src/commands/rm.py +0 -0
  112. {oasr-0.4.0 → oasr-0.4.2}/src/commands/status.py +0 -0
  113. {oasr-0.4.0 → oasr-0.4.2}/src/commands/sync.py +0 -0
  114. {oasr-0.4.0 → oasr-0.4.2}/src/commands/update.py +0 -0
  115. {oasr-0.4.0 → oasr-0.4.2}/src/commands/use.py +0 -0
  116. {oasr-0.4.0 → oasr-0.4.2}/src/commands/validate.py +0 -0
  117. {oasr-0.4.0 → oasr-0.4.2}/src/config/__init__.py +0 -0
  118. {oasr-0.4.0 → oasr-0.4.2}/src/config/defaults.py +0 -0
  119. {oasr-0.4.0 → oasr-0.4.2}/src/config/schema.py +0 -0
  120. {oasr-0.4.0 → oasr-0.4.2}/src/discovery.py +0 -0
  121. {oasr-0.4.0 → oasr-0.4.2}/src/manifest.py +0 -0
  122. {oasr-0.4.0 → oasr-0.4.2}/src/registry.py +0 -0
  123. {oasr-0.4.0 → oasr-0.4.2}/src/remote.py +0 -0
  124. {oasr-0.4.0 → oasr-0.4.2}/src/skillcopy/__init__.py +0 -0
  125. {oasr-0.4.0 → oasr-0.4.2}/src/skillcopy/local.py +0 -0
  126. {oasr-0.4.0 → oasr-0.4.2}/src/skillcopy/remote.py +0 -0
  127. {oasr-0.4.0 → oasr-0.4.2}/src/tracking.py +0 -0
  128. {oasr-0.4.0 → oasr-0.4.2}/src/validate.py +0 -0
  129. {oasr-0.4.0 → oasr-0.4.2}/tests/conftest.py +0 -0
  130. {oasr-0.4.0 → oasr-0.4.2}/tests/test_adapters.py +0 -0
  131. {oasr-0.4.0 → oasr-0.4.2}/tests/test_agents.py +0 -0
  132. {oasr-0.4.0 → oasr-0.4.2}/tests/test_clone.py +0 -0
  133. {oasr-0.4.0 → oasr-0.4.2}/tests/test_config.py +0 -0
  134. {oasr-0.4.0 → oasr-0.4.2}/tests/test_config_command.py +0 -0
  135. {oasr-0.4.0 → oasr-0.4.2}/tests/test_copy.py +0 -0
  136. {oasr-0.4.0 → oasr-0.4.2}/tests/test_help.py +0 -0
  137. {oasr-0.4.0 → oasr-0.4.2}/tests/test_list.py +0 -0
  138. {oasr-0.4.0 → oasr-0.4.2}/tests/test_multi_skill.py +0 -0
  139. {oasr-0.4.0 → oasr-0.4.2}/tests/test_remote.py +0 -0
  140. {oasr-0.4.0 → oasr-0.4.2}/tests/test_tracking.py +0 -0
  141. {oasr-0.4.0 → oasr-0.4.2}/tests/test_use_glob.py +0 -0
@@ -4,9 +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
- ## [Unreleased]
7
+ ## [0.4.2] - 2026-02-01
8
8
 
9
- ## [0.4.0] - TBD
9
+ ### Added
10
+ - **registry prune subcommand**: Added `oasr registry prune` to align with registry command taxonomy
11
+
12
+ ### Changed
13
+ - **clean command**: Deprecated `oasr clean` in favor of `oasr registry prune` (will be removed in v0.6.0)
14
+ - **documentation**: Updated REGISTRY.md with prune subcommand documentation and usage examples
15
+
16
+ ## [0.4.1] - 2026-02-01
17
+
18
+ ### Fixed
19
+ - **exec command**: Fixed `CompletedProcess` attribute error where code incorrectly referenced `.success`, `.output`, and `.error` attributes that don't exist. Now correctly uses `.returncode`
20
+ - **clone documentation**: Removed non-existent `-r, --recursive` flag from CLONE.md documentation
21
+
22
+ ## [0.4.0] - 2026-01-31
10
23
 
11
24
  ### Added
12
25
  - **🚀 `oasr exec` command** — Execute skills as CLI tools from anywhere
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oasr
3
- Version: 0.4.0
3
+ Version: 0.4.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
@@ -3,7 +3,7 @@
3
3
  ## Core Commands (v0.4.0)
4
4
 
5
5
  - [oasr](ROOT.md) - Global flags and options
6
- - [oasr registry](REGISTRY.md) - Manage skill registry (validate, add, remove, list, sync)
6
+ - [oasr registry](REGISTRY.md) - Manage skill registry (validate, add, remove, list, sync, prune)
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)
@@ -11,7 +11,6 @@
11
11
  - [oasr exec](EXEC.md) - Execute skills as CLI tools (NEW in v0.4.0)
12
12
  - [oasr find](FIND.md) - Find/discover skills in your file system
13
13
  - [oasr validate](VALIDATE.md) - Validate a skill
14
- - [oasr clean](CLEAN.md) - Clean up the registry
15
14
  - [oasr adapter](ADAPTER.md) - Generate IDE/Tooling adapters
16
15
  - [oasr update](UPDATE.md) - Update the `oasr` CLI
17
16
  - [oasr info](INFO.md) - Show detailed information about a skill
@@ -19,6 +18,9 @@
19
18
 
20
19
  ## Deprecated Commands
21
20
 
21
+ ### v0.4.1 Deprecations
22
+ - [oasr clean](CLEAN.md) - **Deprecated**, use `oasr registry prune` instead (will be removed in v0.6.0)
23
+
22
24
  ### v0.4.0 Deprecations
23
25
  - [oasr use](USE.md) - **Deprecated**, use `oasr clone` instead (will be removed in v0.5.0)
24
26
 
@@ -0,0 +1,13 @@
1
+ # `oasr clean` (DEPRECATED)
2
+
3
+ > **⚠️ Warning: This command is deprecated and will be removed in v0.6.0.**
4
+ > Use `oasr registry prune` instead.
5
+
6
+ Remove orphaned manifests and entries for missing skills.
7
+
8
+ ```bash
9
+ oasr clean # Shows deprecation warning
10
+ oasr registry prune # New command (recommended)
11
+ ```
12
+
13
+ This command now delegates to `oasr registry prune`. See [REGISTRY.md](./REGISTRY.md#oasr-registry-prune) for full documentation.
@@ -17,7 +17,6 @@ oasr clone skill-one skill-two # Multiple skills
17
17
  ## Options
18
18
 
19
19
  - `-d, --dest DIR` — Destination directory (default: current directory)
20
- - `-r, --recursive` — Create destination directory if it doesn't exist
21
20
  - `--quiet` — Suppress informational output
22
21
  - `--json` — Output results in JSON format
23
22
 
@@ -105,6 +105,40 @@ Syncing remote skills...
105
105
  Synced: 2 skills
106
106
  ```
107
107
 
108
+ ### `oasr registry prune`
109
+
110
+ Clean up corrupted/missing skills and orphaned artifacts:
111
+
112
+ ```bash
113
+ oasr registry prune # Interactive cleanup
114
+ oasr registry prune -y # Skip confirmation
115
+ oasr registry prune --dry-run # Show what would be cleaned
116
+ oasr registry prune --json # JSON output
117
+ ```
118
+
119
+ This command:
120
+ - Removes skills whose source files/URLs are no longer accessible
121
+ - Removes orphaned manifest files not in the registry
122
+ - Requires confirmation unless `-y` flag is used
123
+
124
+ **Example output:**
125
+ ```bash
126
+ $ oasr registry prune
127
+ Checking 3 remote skill(s)...
128
+ ↓ python-analyzer (checking GitHub...)
129
+ ✓ python-analyzer (checked)
130
+
131
+ The following will be cleaned:
132
+
133
+ Skills with missing sources:
134
+ ✗ old-skill (/path/to/missing)
135
+
136
+ Proceed with cleanup? [y/N] y
137
+ Removed skill: old-skill
138
+
139
+ Cleaned 1 skill(s), 0 manifest(s)
140
+ ```
141
+
108
142
  ## Migration from v0.2.0
109
143
 
110
144
  The v0.3.0 CLI taxonomy reorganizes commands under the `registry` subcommand:
@@ -117,3 +151,5 @@ The v0.3.0 CLI taxonomy reorganizes commands under the `registry` subcommand:
117
151
  | `oasr status` | `oasr registry -v` |
118
152
  | `oasr sync` (manifest validation) | `oasr registry` |
119
153
  | `oasr sync --update` (remote sync) | `oasr registry sync` |
154
+
155
+ **v0.4.1 update:** `oasr clean` → `oasr registry prune`
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "oasr"
7
- version = "0.4.0"
7
+ version = "0.4.2"
8
8
  description = "CLI for managing agent skills across IDE integrations"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -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.4.0"
16
+ __version__ = "0.4.2"
17
17
 
18
18
 
19
19
  def main(argv: list[str] | None = None) -> int:
@@ -0,0 +1,30 @@
1
+ """`asr clean` command - DEPRECATED, use `oasr registry prune` instead."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import sys
7
+
8
+
9
+ def register(subparsers) -> None:
10
+ p = subparsers.add_parser(
11
+ "clean",
12
+ help="(Deprecated) Clean up corrupted/missing skills - use 'oasr registry prune'",
13
+ )
14
+ p.add_argument("-y", "--yes", action="store_true", help="Skip confirmation prompt")
15
+ p.add_argument("--json", action="store_true", help="Output in JSON format")
16
+ p.add_argument("--dry-run", action="store_true", help="Show what would be cleaned without doing it")
17
+ p.set_defaults(func=run)
18
+
19
+
20
+ def run(args: argparse.Namespace) -> int:
21
+ """Delegate to registry prune with deprecation warning."""
22
+ # Show deprecation warning unless --json or --quiet
23
+ if not args.json:
24
+ print("⚠ Warning: 'oasr clean' is deprecated. Use 'oasr registry prune' instead.", file=sys.stderr)
25
+ print(" This command will be removed in v0.6.0.\n", file=sys.stderr)
26
+
27
+ # Delegate to registry prune
28
+ from commands.registry import run_prune
29
+
30
+ return run_prune(args)
@@ -104,14 +104,9 @@ def run(args: argparse.Namespace) -> int:
104
104
 
105
105
  try:
106
106
  result = driver.execute(skill_content, user_prompt)
107
- if result.success:
108
- # Print agent output to stdout (this is the actual result)
109
- print(result.output)
110
- return 0
111
- else:
112
- print("\nError executing skill:", file=sys.stderr)
113
- print(result.error, file=sys.stderr)
114
- return 1
107
+ # CompletedProcess has returncode attribute (0 = success)
108
+ # Output was already streamed to stdout since capture_output=False
109
+ return result.returncode
115
110
  except Exception as e:
116
111
  print(f"\nUnexpected error: {e}", file=sys.stderr)
117
112
  return 1
@@ -64,6 +64,13 @@ def register(subparsers) -> None:
64
64
  sync_p.add_argument("--config", type=Path, help="Override config file path")
65
65
  sync_p.set_defaults(func=run_sync)
66
66
 
67
+ # registry prune
68
+ prune_p = registry_subparsers.add_parser("prune", help="Clean up corrupted/missing skills and orphaned artifacts")
69
+ prune_p.add_argument("-y", "--yes", action="store_true", help="Skip confirmation prompt")
70
+ prune_p.add_argument("--json", action="store_true", help="Output in JSON format")
71
+ prune_p.add_argument("--dry-run", action="store_true", help="Show what would be cleaned without doing it")
72
+ prune_p.set_defaults(func=run_prune)
73
+
67
74
 
68
75
  def run_validate(args: argparse.Namespace) -> int:
69
76
  """Validate registry manifests (default oasr registry behavior)."""
@@ -301,3 +308,140 @@ def run_sync(args: argparse.Namespace) -> int:
301
308
  print(f"{len(pruned)} skill(s) pruned")
302
309
 
303
310
  return 1 if missing_count > 0 else 0
311
+
312
+
313
+ def run_prune(args: argparse.Namespace) -> int:
314
+ """Clean up corrupted/missing skills and orphaned artifacts (oasr registry prune)."""
315
+ from manifest import delete_manifest, list_manifests
316
+
317
+ entries = load_registry()
318
+ registered_names = {e.name for e in entries}
319
+ manifest_names = set(list_manifests())
320
+
321
+ to_remove_skills = []
322
+ to_remove_manifests = []
323
+
324
+ # Check for remote skills and show progress header
325
+ remote_count = 0
326
+ for entry in entries:
327
+ manifest = load_manifest(entry.name)
328
+ if manifest and is_remote_source(manifest.source_path):
329
+ remote_count += 1
330
+
331
+ if remote_count > 0 and not args.json:
332
+ print(f"Checking {remote_count} remote skill(s)...", file=sys.stderr)
333
+
334
+ for entry in entries:
335
+ manifest = load_manifest(entry.name)
336
+ if manifest:
337
+ # Show progress for remote skills
338
+ is_remote = is_remote_source(manifest.source_path)
339
+ if is_remote and not args.json:
340
+ platform = (
341
+ "GitHub"
342
+ if "github.com" in manifest.source_path
343
+ else "GitLab"
344
+ if "gitlab.com" in manifest.source_path
345
+ else "remote"
346
+ )
347
+ print(f" ↓ {entry.name} (checking {platform}...)", file=sys.stderr, flush=True)
348
+
349
+ status = check_manifest(manifest)
350
+
351
+ if is_remote and not args.json:
352
+ print(f" ✓ {entry.name} (checked)", file=sys.stderr)
353
+
354
+ if status.status == "missing":
355
+ to_remove_skills.append(
356
+ {
357
+ "name": entry.name,
358
+ "reason": "source missing",
359
+ "path": entry.path,
360
+ }
361
+ )
362
+
363
+ orphaned = manifest_names - registered_names
364
+ for name in orphaned:
365
+ to_remove_manifests.append(
366
+ {
367
+ "name": name,
368
+ "reason": "orphaned manifest (not in registry)",
369
+ }
370
+ )
371
+
372
+ if not to_remove_skills and not to_remove_manifests:
373
+ if args.json:
374
+ print(json.dumps({"cleaned": 0, "message": "nothing to clean"}))
375
+ else:
376
+ print("Nothing to clean.")
377
+ return 0
378
+
379
+ if args.json:
380
+ result = {
381
+ "skills_to_remove": to_remove_skills,
382
+ "manifests_to_remove": to_remove_manifests,
383
+ "dry_run": args.dry_run,
384
+ }
385
+ if not args.dry_run and not args.yes:
386
+ result["requires_confirmation"] = True
387
+ print(json.dumps(result, indent=2))
388
+ if args.dry_run:
389
+ return 0
390
+ else:
391
+ print("The following will be cleaned:\n")
392
+
393
+ if to_remove_skills:
394
+ print("Skills with missing sources:")
395
+ for s in to_remove_skills:
396
+ print(f" ✗ {s['name']} ({s['path']})")
397
+
398
+ if to_remove_manifests:
399
+ print("\nOrphaned manifests:")
400
+ for m in to_remove_manifests:
401
+ print(f" ✗ {m['name']}")
402
+
403
+ print()
404
+
405
+ if args.dry_run:
406
+ print("(dry run - no changes made)")
407
+ return 0
408
+
409
+ if not args.yes and not args.json:
410
+ try:
411
+ response = input("Proceed with cleanup? [y/N] ").strip().lower()
412
+ if response not in ("y", "yes"):
413
+ print("Aborted.")
414
+ return 1
415
+ except (EOFError, KeyboardInterrupt):
416
+ print("\nAborted.")
417
+ return 1
418
+
419
+ removed_skills = []
420
+ removed_manifests = []
421
+
422
+ for s in to_remove_skills:
423
+ remove_skill(s["name"])
424
+ removed_skills.append(s["name"])
425
+
426
+ for m in to_remove_manifests:
427
+ delete_manifest(m["name"])
428
+ removed_manifests.append(m["name"])
429
+
430
+ if args.json:
431
+ print(
432
+ json.dumps(
433
+ {
434
+ "removed_skills": removed_skills,
435
+ "removed_manifests": removed_manifests,
436
+ },
437
+ indent=2,
438
+ )
439
+ )
440
+ else:
441
+ for name in removed_skills:
442
+ print(f"Removed skill: {name}")
443
+ for name in removed_manifests:
444
+ print(f"Removed manifest: {name}")
445
+ print(f"\nCleaned {len(removed_skills)} skill(s), {len(removed_manifests)} manifest(s)")
446
+
447
+ return 0
@@ -107,8 +107,7 @@ class TestExecCommand:
107
107
  )
108
108
 
109
109
  mock_result = mock.Mock()
110
- mock_result.success = True
111
- mock_result.output = "Agent output here"
110
+ mock_result.returncode = 0 # Success
112
111
 
113
112
  mock_driver = mock.Mock()
114
113
  mock_driver.execute.return_value = mock_result
@@ -122,7 +121,6 @@ class TestExecCommand:
122
121
 
123
122
  assert result == 0
124
123
  captured = capsys.readouterr()
125
- assert "Agent output here" in captured.out
126
124
  assert "Executing skill 'test-skill' with codex" in captured.err
127
125
 
128
126
  # Verify driver was called with skill content and prompt
@@ -143,8 +141,7 @@ class TestExecCommand:
143
141
  )
144
142
 
145
143
  mock_result = mock.Mock()
146
- mock_result.success = False
147
- mock_result.error = "Agent failed with error"
144
+ mock_result.returncode = 1 # Failure
148
145
 
149
146
  mock_driver = mock.Mock()
150
147
  mock_driver.execute.return_value = mock_result
@@ -157,8 +154,6 @@ class TestExecCommand:
157
154
  result = exec_cmd.run(args)
158
155
 
159
156
  assert result == 1
160
- captured = capsys.readouterr()
161
- assert "Agent failed with error" in captured.err
162
157
 
163
158
  def test_exec_with_explicit_agent(self, capsys, mock_registry):
164
159
  """Test exec with explicit agent flag."""
@@ -172,8 +167,7 @@ class TestExecCommand:
172
167
  )
173
168
 
174
169
  mock_result = mock.Mock()
175
- mock_result.success = True
176
- mock_result.output = "Success"
170
+ mock_result.returncode = 0 # Success
177
171
 
178
172
  mock_driver = mock.Mock()
179
173
  mock_driver.execute.return_value = mock_result
@@ -138,7 +138,7 @@ wheels = [
138
138
 
139
139
  [[package]]
140
140
  name = "oasr"
141
- version = "0.4.0"
141
+ version = "0.4.2"
142
142
  source = { editable = "." }
143
143
  dependencies = [
144
144
  { name = "pyyaml" },
@@ -1,11 +0,0 @@
1
- # `oasr clean`
2
-
3
- Remove orphaned manifests and entries for missing skills.
4
-
5
- ```bash
6
- oasr clean
7
- oasr clean --dry-run
8
- ```
9
-
10
- > **note**
11
- > The same behaviour can be achieved using `oasr sync --prune`
@@ -1,35 +0,0 @@
1
- ---
2
- name: doctor
3
- license: MIT
4
- description: 'Diagnoses software failures by combining deterministic evidence gathering
5
- with agent judgment. Models failures as medical cases. Idempotent — run repeatedly
6
- until confident diagnosis, then generate schema-based treatment.
7
-
8
- '
9
- metadata:
10
- author: Jordan Godau
11
- version: 0.2.0
12
- references:
13
- - 00_ROUTER.md
14
- - 01_SUMMARY.md
15
- - 02_TRIGGERS.md
16
- - 03_ALWAYS.md
17
- - 04_NEVER.md
18
- - 05_PROCEDURE.md
19
- - 06_FAILURES.md
20
- keywords:
21
- - diagnose
22
- - debug
23
- - investigate
24
- - evidence
25
- - hypothesis
26
- - treatment
27
- oasr:
28
- hash: sha256:f9fda45b7797923e9379e36c1b519c40b09f05f78bfa172a9d006c14b7283535
29
- source: /home/jgodau/work/personal/skills/doctor/doctor
30
- synced: '2026-02-01T06:35:54.685306Z'
31
- ---
32
-
33
- # INSTRUCTIONS
34
-
35
- 1. Refer to `metadata.references`.
@@ -1,87 +0,0 @@
1
- # Doctor Session Schema
2
- # Artifact: .doctor/session.yaml
3
-
4
- type: object
5
- required:
6
- - status
7
- - created_at
8
-
9
- properties:
10
- status:
11
- type: string
12
- enum: [investigating, diagnosed, treated, abandoned]
13
- description: Current session status
14
-
15
- created_at:
16
- type: string
17
- format: date-time
18
- description: RFC3339 UTC timestamp
19
-
20
- updated_at:
21
- type: string
22
- format: date-time
23
- description: RFC3339 UTC timestamp of last update
24
-
25
- patient:
26
- type: string
27
- description: Repository or system name
28
-
29
- symptoms:
30
- type: array
31
- items:
32
- type: object
33
- properties:
34
- description:
35
- type: string
36
- category:
37
- type: string
38
- enum: [error, timeout, crash, wrong_output, performance, unknown]
39
- evidence:
40
- type: string
41
- description: Observed symptoms
42
-
43
- hypotheses:
44
- type: array
45
- items:
46
- type: object
47
- properties:
48
- description:
49
- type: string
50
- confidence:
51
- type: integer
52
- minimum: 0
53
- maximum: 100
54
- evidence_for:
55
- type: array
56
- items:
57
- type: string
58
- evidence_against:
59
- type: array
60
- items:
61
- type: string
62
- falsifiable_by:
63
- type: string
64
- description: Working hypotheses with confidence
65
-
66
- diagnosis:
67
- type: object
68
- properties:
69
- summary:
70
- type: string
71
- confidence:
72
- type: integer
73
- minimum: 0
74
- maximum: 100
75
- root_cause:
76
- type: string
77
- contributing_factors:
78
- type: array
79
- items:
80
- type: string
81
- description: Final diagnosis (when confident)
82
-
83
- evidence_files:
84
- type: array
85
- items:
86
- type: string
87
- description: Paths to evidence snapshots in .doctor/evidence/
@@ -1,70 +0,0 @@
1
- # Treatment Plan Schema
2
- # Artifact: .doctor/treatment.md (generated from this schema)
3
-
4
- type: object
5
- required:
6
- - diagnosis_summary
7
- - confidence
8
- - options
9
-
10
- properties:
11
- diagnosis_summary:
12
- type: string
13
- description: One-line diagnosis
14
-
15
- confidence:
16
- type: integer
17
- minimum: 0
18
- maximum: 100
19
- description: Diagnosis confidence percentage
20
-
21
- root_cause:
22
- type: string
23
- description: Identified root cause
24
-
25
- options:
26
- type: array
27
- minItems: 1
28
- items:
29
- type: object
30
- required:
31
- - name
32
- - description
33
- - risk
34
- properties:
35
- name:
36
- type: string
37
- description: Short option name
38
- description:
39
- type: string
40
- description: What this option does
41
- risk:
42
- type: string
43
- enum: [low, medium, high]
44
- effort:
45
- type: string
46
- enum: [trivial, small, medium, large]
47
- reversible:
48
- type: boolean
49
- steps:
50
- type: array
51
- items:
52
- type: string
53
- description: Ordered implementation steps
54
- description: Treatment options (at least one required)
55
-
56
- recommended:
57
- type: string
58
- description: Name of recommended option
59
-
60
- caveats:
61
- type: array
62
- items:
63
- type: string
64
- description: Warnings or considerations
65
-
66
- follow_up:
67
- type: array
68
- items:
69
- type: string
70
- description: Suggested follow-up actions