@softspark/ai-toolkit 4.16.0 → 4.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/README.md +6 -5
- package/app/.claude-plugin/plugin.json +1 -1
- package/manifest.json +1 -1
- package/package.json +1 -1
- package/scripts/generate_copilot.py +35 -4
- package/scripts/install.py +5 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,15 @@ Versioning follows [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## v4.16.1 — Copilot skill remnant recovery (2026-07-24)
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- **Legacy Copilot skill remnants no longer abort local updates** — `.github/skills/ai-toolkit-*` directories left behind by pre-manifest cleanups (assets without `SKILL.md`) are rebuilt in place instead of raising `Refusing user-owned Copilot skill collision`, which aborted the entire `install --local` / `update` run on affected projects. User files inside a remnant that do not collide with generated output are preserved; any directory that still contains a `SKILL.md` stays protected and is never reclaimed.
|
|
15
|
+
- **Readable installer errors** — `scripts/install.py` reports fail-closed `RuntimeError` conditions as a single `ERROR:` line instead of a raw traceback.
|
|
16
|
+
|
|
17
|
+
Test count: 1477 → 1479.
|
|
18
|
+
|
|
10
19
|
## v4.16.0 — Native tool-output filtering (2026-07-24)
|
|
11
20
|
|
|
12
21
|
Minor release. Adds a dependency-free, opt-in native tool-output filter for Claude Code and hardens the enterprise configuration, session-isolation, and editor-adapter surfaces around it. The filter ships disabled; `observe` and `safe` are per-project opt-ins. No source catalog count change (44 agents, 108 skills).
|
package/README.md
CHANGED
|
@@ -6,17 +6,18 @@
|
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
[](app/skills/)
|
|
8
8
|
[](app/agents/)
|
|
9
|
-
[](tests/)
|
|
10
10
|
|
|
11
|
-
## What's New in v4.16.
|
|
11
|
+
## What's New in v4.16.1
|
|
12
12
|
|
|
13
|
-
v4.16.
|
|
13
|
+
v4.16.1 ships the native tool-output filter introduced in v4.16.0 and fixes local updates crashing on legacy Copilot skill remnants.
|
|
14
14
|
|
|
15
15
|
- **Native tool-output filter**: opt-in `PostToolUse` filter with `off`, `observe`, and `safe` modes; ships disabled, handles only allowlisted successful Bash test/validation output.
|
|
16
16
|
- **Exact ephemeral recovery**: every safe replacement keeps a private, bounded, session-scoped copy of the original response, recoverable via `ai-toolkit output-filter recover`.
|
|
17
17
|
- **Output-filter CLI**: `ai-toolkit output-filter status|inspect|recover|clean` plus a deterministic benchmark for the built-in profiles.
|
|
18
18
|
- **Stricter config validation**: unknown top-level config keys are rejected, plugin manifests must declare `requires`, and lock files go stale on toolkit version bumps.
|
|
19
19
|
- **GitHub Copilot compatibility reference**: new `kb/reference/copilot-compatibility.md` documenting the Copilot integration surface.
|
|
20
|
+
- **Copilot remnant recovery**: asset-only `.github/skills/ai-toolkit-*` leftovers from older cleanups are rebuilt in place instead of aborting `install --local` / `update`.
|
|
20
21
|
|
|
21
22
|
See [CHANGELOG.md](CHANGELOG.md) for full history.
|
|
22
23
|
|
|
@@ -126,7 +127,7 @@ See [CLI Reference](kb/reference/cli-reference.md) for all commands and options.
|
|
|
126
127
|
| Gemini CLI | `~/.gemini/GEMINI.md` | ✅ | global |
|
|
127
128
|
| GitHub Copilot | Project: `AGENTS.md` + `.github/copilot-instructions.md` + `.github/{instructions,prompts,agents,skills,hooks}/` + `.github/mcp.json`; user: `$COPILOT_HOME/copilot-instructions.md` + `$COPILOT_HOME/{instructions,agents,skills,hooks}/` + `$COPILOT_HOME/mcp-config.json` | ✅ | project + user |
|
|
128
129
|
| Cline | `~/Documents/Cline/Rules/*.md` + `~/.cline/skills/*` + `.clinerules/*.md` | — | global + project |
|
|
129
|
-
| Roo Code | `~/.roo/rules/*.md` + `.roomodes` + `.roo/rules/*.md` | — | global rules + project |
|
|
130
|
+
| Roo Code / [Zoo Code](https://zoocode.dev/) | `~/.roo/rules/*.md` + `.roomodes` + `.roo/rules/*.md` | — | global rules + project |
|
|
130
131
|
| Aider | `~/.aider.conf.yml` + `.aider.conf.yml` + `CONVENTIONS.md` | — | global + project |
|
|
131
132
|
| Augment | `~/.augment/rules/*.md` + `.augment/rules/ai-toolkit-*.md` | ✅ | global + project |
|
|
132
133
|
| Google Antigravity | `.agents/rules/*.md` + `.agents/workflows/*.md` + skill pointer in `.agent/skills/*` (IDE) and `.agents/skills/*` (CLI) | — | project |
|
|
@@ -169,7 +170,7 @@ ai-toolkit/
|
|
|
169
170
|
│ └── ARCHITECTURE.md # Full system design
|
|
170
171
|
├── kb/ # Reference docs, procedures, plans
|
|
171
172
|
├── scripts/ # Validation, install, evaluation scripts
|
|
172
|
-
├── tests/ # Bats and Python test suite (
|
|
173
|
+
├── tests/ # Bats and Python test suite (1479 tests)
|
|
173
174
|
└── CHANGELOG.md
|
|
174
175
|
```
|
|
175
176
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "ai-toolkit",
|
|
4
4
|
"displayName": "AI Toolkit",
|
|
5
5
|
"description": "Professional-grade engineering skills, agents, rules, and lifecycle guardrails for Claude Code, Claude Chat, and Cowork.",
|
|
6
|
-
"version": "4.16.
|
|
6
|
+
"version": "4.16.1",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "SoftSpark",
|
|
9
9
|
"url": "https://github.com/softspark"
|
package/manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@softspark/ai-toolkit",
|
|
3
|
-
"version": "4.16.
|
|
3
|
+
"version": "4.16.1",
|
|
4
4
|
"description": "AI coding toolkit: 108 skills, 44 agents, 12 developer-tool integrations, recoverable native tool-output filtering, Claude Chat/Cowork export, safety constitution, SARIF audit, and signed npm provenance.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude",
|
|
@@ -974,6 +974,23 @@ def _is_managed_skill_dir(path: Path) -> bool:
|
|
|
974
974
|
return path.is_dir() and not path.is_symlink() and _is_managed(skill_file)
|
|
975
975
|
|
|
976
976
|
|
|
977
|
+
def _is_skill_remnant(path: Path) -> bool:
|
|
978
|
+
"""Asset-only leftover of a legacy managed skill.
|
|
979
|
+
|
|
980
|
+
Pre-manifest toolkit versions tracked only SKILL.md as managed, so their
|
|
981
|
+
cleanup removed SKILL.md and left reference/ and scripts/ assets behind.
|
|
982
|
+
Without SKILL.md the directory is not a functional Copilot skill, so it is
|
|
983
|
+
safe to rebuild in place; a directory that still has any SKILL.md (managed
|
|
984
|
+
or not) is never classified as a remnant.
|
|
985
|
+
"""
|
|
986
|
+
return (
|
|
987
|
+
path.is_dir()
|
|
988
|
+
and not path.is_symlink()
|
|
989
|
+
and not (path / "SKILL.md").exists()
|
|
990
|
+
and not (path / "SKILL.md").is_symlink()
|
|
991
|
+
)
|
|
992
|
+
|
|
993
|
+
|
|
977
994
|
def _managed_skill_paths(path: Path) -> set[Path]:
|
|
978
995
|
manifest = path / SKILL_MANIFEST
|
|
979
996
|
if not manifest.is_file() or manifest.is_symlink():
|
|
@@ -999,7 +1016,8 @@ def _has_user_skill_extras(path: Path) -> bool:
|
|
|
999
1016
|
|
|
1000
1017
|
|
|
1001
1018
|
def _copy_user_skill_extras(existing: Path, staging: Path,
|
|
1002
|
-
generated_paths: set[Path]
|
|
1019
|
+
generated_paths: set[Path],
|
|
1020
|
+
*, skip_stale_assets: bool = False) -> None:
|
|
1003
1021
|
"""Preserve files a user added inside a previously managed skill."""
|
|
1004
1022
|
old_managed = _managed_skill_paths(existing)
|
|
1005
1023
|
for source in sorted(existing.rglob("*")):
|
|
@@ -1011,6 +1029,8 @@ def _copy_user_skill_extras(existing: Path, staging: Path,
|
|
|
1011
1029
|
if not source.is_file():
|
|
1012
1030
|
continue
|
|
1013
1031
|
if relative in generated_paths:
|
|
1032
|
+
if skip_stale_assets:
|
|
1033
|
+
continue
|
|
1014
1034
|
raise RuntimeError(
|
|
1015
1035
|
f"Copilot skill update would overwrite a user asset: {source}"
|
|
1016
1036
|
)
|
|
@@ -1046,7 +1066,10 @@ def _stage_skill(skills_root: Path, source_dir: Path,
|
|
|
1046
1066
|
encoding="utf-8",
|
|
1047
1067
|
)
|
|
1048
1068
|
if existing is not None:
|
|
1049
|
-
_copy_user_skill_extras(
|
|
1069
|
+
_copy_user_skill_extras(
|
|
1070
|
+
existing, staging, generated_paths,
|
|
1071
|
+
skip_stale_assets=_is_skill_remnant(existing),
|
|
1072
|
+
)
|
|
1050
1073
|
return staging, name
|
|
1051
1074
|
except Exception:
|
|
1052
1075
|
shutil.rmtree(staging, ignore_errors=True)
|
|
@@ -1058,7 +1081,10 @@ def _replace_skill_dir(staging: Path, destination: Path) -> None:
|
|
|
1058
1081
|
backup: Path | None = None
|
|
1059
1082
|
try:
|
|
1060
1083
|
if destination.exists():
|
|
1061
|
-
if destination.is_symlink() or not
|
|
1084
|
+
if destination.is_symlink() or not (
|
|
1085
|
+
_is_managed_skill_dir(destination)
|
|
1086
|
+
or _is_skill_remnant(destination)
|
|
1087
|
+
):
|
|
1062
1088
|
raise RuntimeError(
|
|
1063
1089
|
f"Refusing user-owned Copilot skill collision: {destination}"
|
|
1064
1090
|
)
|
|
@@ -1125,7 +1151,12 @@ def _sync_copilot_skills(customization_root: Path, *, label: str) -> None:
|
|
|
1125
1151
|
expected_dirs.add(destination_name)
|
|
1126
1152
|
existing = destination if destination.exists() else None
|
|
1127
1153
|
if existing is not None and not _is_managed_skill_dir(existing):
|
|
1128
|
-
|
|
1154
|
+
if not _is_skill_remnant(existing):
|
|
1155
|
+
raise RuntimeError(f"Refusing user-owned Copilot skill collision: {destination}")
|
|
1156
|
+
print(
|
|
1157
|
+
f"Note: rebuilding asset-only Copilot skill remnant '{destination}'",
|
|
1158
|
+
file=sys.stderr,
|
|
1159
|
+
)
|
|
1129
1160
|
staging, rendered_name = _stage_skill(skill_root, source_dir, existing)
|
|
1130
1161
|
if rendered_name != logical_name:
|
|
1131
1162
|
shutil.rmtree(staging, ignore_errors=True)
|
package/scripts/install.py
CHANGED