@softspark/ai-toolkit 4.29.0 → 4.29.2
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 +80 -0
- package/README.md +15 -18
- package/app/.claude-plugin/plugin.json +1 -1
- package/app/hooks/guard-destructive.sh +28 -10
- package/kb/reference/hooks-catalog.md +7 -0
- package/llms-full.txt +7 -0
- package/manifest.json +1 -1
- package/package.json +1 -1
- package/scripts/install_steps/ai_tools.py +7 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,86 @@ Versioning follows [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## v4.29.2 — The Codex dry-run stops hiding a surface (2026-08-21)
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- **`install --dry-run` never mentioned the Codex hook surfaces.** Selecting
|
|
15
|
+
`codex` runs `gen_codex_hooks()` unconditionally, at every profile, writing
|
|
16
|
+
`.codex/hooks.json` and the hook scripts under `.codex/hooks/` (23 files). The
|
|
17
|
+
dry-run branch in `scripts/install_steps/ai_tools.py` printed only
|
|
18
|
+
`.codex/agents/` and `.agents/skills/`. A preview that omits a whole surface is
|
|
19
|
+
worse than no preview, and this is the surface a user is asked to review and
|
|
20
|
+
trust with `/hooks` before Codex will run any of it.
|
|
21
|
+
- **The global preview named the manifest but not its scripts.** It listed
|
|
22
|
+
`$CODEX_HOME/hooks.json` and stopped there, leaving out
|
|
23
|
+
`$CODEX_HOME/ai-toolkit-hooks/`. Same defect, other branch.
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
- Four tests in `tests/test_install_profiles.bats`: the preview names both hook
|
|
28
|
+
paths, it names them at `minimal`/`standard`/`full` alike, the preview matches
|
|
29
|
+
what a live install then writes to disk, and `--dry-run` still writes nothing.
|
|
30
|
+
All four fail against v4.29.1.
|
|
31
|
+
|
|
32
|
+
### Changed
|
|
33
|
+
|
|
34
|
+
- Test count: 1671 → 1675.
|
|
35
|
+
|
|
36
|
+
**Found by:** running the Release Verification SOP against the published
|
|
37
|
+
v4.29.1. Phase 9.1 checks dry-run output for each native surface, and the Codex
|
|
38
|
+
hook lines were missing — so that SOP check would have produced a false negative
|
|
39
|
+
on a build where the surface really was gone.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## v4.29.1 — The guard stops blocking the safe branch delete (2026-08-21)
|
|
44
|
+
|
|
45
|
+
### Fixed
|
|
46
|
+
|
|
47
|
+
- **`guard-destructive.sh` no longer folds `-d` onto `-D`.** Every pattern was
|
|
48
|
+
matched by a single `grep -qEi`, so the `git\s+branch\s+-D\b` pattern also
|
|
49
|
+
caught `git branch -d`. Those are different operations: `-D` discards an
|
|
50
|
+
unmerged branch, `-d` refuses to. The safe one is what
|
|
51
|
+
`.claude/rules/ai-toolkit-git-workflow.md` tells users to run after every
|
|
52
|
+
merge, and the guard blocked it — a false positive on the toolkit's own
|
|
53
|
+
advice, in the toolkit's own safety hook.
|
|
54
|
+
- **Patterns are matched in two passes, split by whether case carries meaning.**
|
|
55
|
+
Command names and flags go through a case-sensitive `grep -qE`; POSIX flags
|
|
56
|
+
that differ only in case are different flags, and folding them together can
|
|
57
|
+
only lose information. SQL keywords and the Windows `format` command go
|
|
58
|
+
through a case-insensitive `grep -qEi`, because their casing genuinely varies
|
|
59
|
+
in the wild — `drop table`, `Truncate`, and `delete from` all still block.
|
|
60
|
+
The `-i` was presumably there for the SQL patterns all along; it was the
|
|
61
|
+
flag patterns that paid for it.
|
|
62
|
+
|
|
63
|
+
- **A cross-file race in the test suite.** `doctor --fix regenerates missing
|
|
64
|
+
llms-full.txt` deleted the artifact from the shared checkout and asserted on
|
|
65
|
+
doctor's `FIXED` line. `npm test` runs `bats --jobs 4
|
|
66
|
+
--no-parallelize-within-files`, so files run concurrently, and
|
|
67
|
+
`test_doctor_plugin_double_load.bats` also runs `doctor --fix` — which
|
|
68
|
+
regenerates that artifact. When it won, the assertion saw a present file, no
|
|
69
|
+
`FIXED` line, and a red suite; the test also left a `llms-full.txt.test-bak`
|
|
70
|
+
in the repo, because the restoring `mv` never ran. v4.29.0 added a second
|
|
71
|
+
`doctor --fix` call to the plugin test file, which is what made a latent race
|
|
72
|
+
start firing. The test now runs doctor against a private copy of the toolkit,
|
|
73
|
+
so it mutates no shared state at all.
|
|
74
|
+
|
|
75
|
+
### Changed
|
|
76
|
+
|
|
77
|
+
- `kb/reference/hooks-catalog.md` documents the two-pass matching and lists the
|
|
78
|
+
safe branch delete among the guard's exemptions.
|
|
79
|
+
- Test count: 1666 → 1671. The new cases pin both directions: the safe delete
|
|
80
|
+
and an uppercase non-flag pass, lowercase and mixed-case SQL block.
|
|
81
|
+
|
|
82
|
+
### Known gap (not addressed here)
|
|
83
|
+
|
|
84
|
+
- The guard matches `git branch -D` but not its long form, `git branch --delete
|
|
85
|
+
--force`. That gap predates this fix and closing it is a coverage change
|
|
86
|
+
rather than a case-sensitivity one, so it is left for a separate decision.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
10
90
|
## v4.29.0 — Stale plugin uploads stop hiding (2026-08-21)
|
|
11
91
|
|
|
12
92
|
### Added
|
package/README.md
CHANGED
|
@@ -6,24 +6,21 @@
|
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
[](app/skills/)
|
|
8
8
|
[](app/agents/)
|
|
9
|
-
[](tests/)
|
|
10
|
+
|
|
11
|
+
## What's New in v4.29.2
|
|
12
|
+
|
|
13
|
+
**v4.29.2** makes `install --dry-run` tell the truth about Codex hooks:
|
|
14
|
+
|
|
15
|
+
- Selecting `codex` always installs Codex lifecycle hooks -- `.codex/hooks.json`
|
|
16
|
+
plus the scripts under `.codex/hooks/` -- at every profile. The dry-run branch
|
|
17
|
+
listed only agents and skills, so the preview silently omitted a whole surface,
|
|
18
|
+
and the one you are asked to review and trust with `/hooks`.
|
|
19
|
+
- Both previews now name it: project installs announce
|
|
20
|
+
`.codex/hooks.json + .codex/hooks/`, global installs add
|
|
21
|
+
`$CODEX_HOME/ai-toolkit-hooks/` next to `$CODEX_HOME/hooks.json`.
|
|
22
|
+
- Four tests pin the preview against what the live install actually writes, so a
|
|
23
|
+
surface cannot go missing from the dry-run again. Test count: 1671 -> 1675.
|
|
27
24
|
|
|
28
25
|
## Table of Contents
|
|
29
26
|
|
|
@@ -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.29.
|
|
6
|
+
"version": "4.29.2",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "SoftSpark",
|
|
9
9
|
"url": "https://github.com/softspark"
|
|
@@ -40,7 +40,15 @@ fi
|
|
|
40
40
|
# --force or -f left behind still blocks.
|
|
41
41
|
SAFE_STRIPPED=$(printf '%s' "$NORMALIZED" | sed -E 's/--force-with-lease(=[^ ]*)?//g; s/--force-if-includes//g')
|
|
42
42
|
|
|
43
|
-
# Destructive patterns — word-boundary aware where possible
|
|
43
|
+
# Destructive patterns — word-boundary aware where possible.
|
|
44
|
+
#
|
|
45
|
+
# Two buckets, matched by two greps, because case sensitivity is not a uniform
|
|
46
|
+
# property of these patterns. POSIX command names and flags are case-SIGNIFICANT:
|
|
47
|
+
# `-d` and `-D` are different flags, and folding them together made the guard
|
|
48
|
+
# block `git branch -d` — the safe delete that refuses unmerged branches — as if
|
|
49
|
+
# it were `-D`. SQL keywords carry no such distinction and are written in every
|
|
50
|
+
# casing in the wild, so they need folding. One case-insensitive grep over both
|
|
51
|
+
# sets cannot express that, and the flag bucket is the one that loses.
|
|
44
52
|
DESTRUCTIVE_PATTERNS=(
|
|
45
53
|
# rm variants (short flags, long flags, separated flags, sudo, xargs/find piped)
|
|
46
54
|
'rm\s+(-[rRf]{2,}|-r\s+-f|-f\s+-r)'
|
|
@@ -54,18 +62,13 @@ DESTRUCTIVE_PATTERNS=(
|
|
|
54
62
|
'find\s+.*-delete'
|
|
55
63
|
'find\s+.*-exec\s+rm\b'
|
|
56
64
|
|
|
57
|
-
# SQL destructive operations
|
|
58
|
-
'DROP\s+(TABLE|DATABASE|SCHEMA|INDEX)'
|
|
59
|
-
'TRUNCATE\s+'
|
|
60
|
-
'DELETE\s+FROM\s+\S+\s*(;|$|WHERE\s+1)'
|
|
61
|
-
|
|
62
65
|
# Disk/filesystem destructive
|
|
63
|
-
'format\s+/'
|
|
64
66
|
'dd\s+if='
|
|
65
67
|
'mkfs\b'
|
|
66
68
|
'shred\b'
|
|
67
69
|
|
|
68
|
-
# Git destructive operations
|
|
70
|
+
# Git destructive operations. `-D` only: `git branch -d` refuses to delete an
|
|
71
|
+
# unmerged branch and is the documented post-merge cleanup, not a hazard.
|
|
69
72
|
'git\s+push\s+(--force|-f)\b'
|
|
70
73
|
'git\s+push\s+.*--force'
|
|
71
74
|
'git\s+reset\s+--hard'
|
|
@@ -88,10 +91,25 @@ DESTRUCTIVE_PATTERNS=(
|
|
|
88
91
|
'>\s*/dev/sd[a-z]'
|
|
89
92
|
)
|
|
90
93
|
|
|
91
|
-
#
|
|
94
|
+
# Case-insensitive bucket: patterns whose real-world casing genuinely varies.
|
|
95
|
+
# SQL is written DROP TABLE, drop table, and Drop Table with equal frequency;
|
|
96
|
+
# `format` is a Windows command and Windows command names are case-insensitive.
|
|
97
|
+
DESTRUCTIVE_PATTERNS_NOCASE=(
|
|
98
|
+
# SQL destructive operations
|
|
99
|
+
'DROP\s+(TABLE|DATABASE|SCHEMA|INDEX)'
|
|
100
|
+
'TRUNCATE\s+'
|
|
101
|
+
'DELETE\s+FROM\s+\S+\s*(;|$|WHERE\s+1)'
|
|
102
|
+
|
|
103
|
+
# Disk/filesystem destructive
|
|
104
|
+
'format\s+/'
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
# Build combined regexes
|
|
92
108
|
REGEX=$(IFS='|'; echo "${DESTRUCTIVE_PATTERNS[*]}")
|
|
109
|
+
REGEX_NOCASE=$(IFS='|'; echo "${DESTRUCTIVE_PATTERNS_NOCASE[*]}")
|
|
93
110
|
|
|
94
|
-
if echo "$SAFE_STRIPPED" | grep -
|
|
111
|
+
if echo "$SAFE_STRIPPED" | grep -qE "($REGEX)" \
|
|
112
|
+
|| echo "$SAFE_STRIPPED" | grep -qEi "($REGEX_NOCASE)"; then
|
|
95
113
|
echo "WARNING: Potentially destructive command detected. Please verify." >&2
|
|
96
114
|
exit 2
|
|
97
115
|
fi
|
|
@@ -95,8 +95,15 @@ for debugging; `AI_TOOLKIT_HOOK_QUIET=1` keeps it silent explicitly.
|
|
|
95
95
|
- `git push --force`
|
|
96
96
|
- `chmod -R 777`
|
|
97
97
|
|
|
98
|
+
**Case sensitivity:** patterns are matched in two passes. Command names and flags
|
|
99
|
+
are matched case-**sensitively**, because `-d` and `-D` are different flags —
|
|
100
|
+
`git branch -D` blocks, `git branch -d` does not. SQL keywords and the Windows
|
|
101
|
+
`format` command are matched case-**insensitively**, so `drop table` blocks the
|
|
102
|
+
same as `DROP TABLE`.
|
|
103
|
+
|
|
98
104
|
**Exemptions (avoid false positives):**
|
|
99
105
|
- `git push --force-with-lease` / `--force-if-includes` — the safe force-push variants are allowed.
|
|
106
|
+
- `git branch -d` — the safe delete refuses unmerged branches and is the post-merge cleanup the git-workflow rules prescribe. `git branch -D` still blocks.
|
|
100
107
|
- A single, non-chained `echo`/`printf`/`git commit`/`git tag` carrying a destructive token as *data* (e.g. a commit message mentioning `DROP TABLE`) is allowed. Chained commands (`&&`, `;`, `|`) are still inspected in full.
|
|
101
108
|
|
|
102
109
|
### PreToolUse (file ops) — `guard-path.sh`
|
package/llms-full.txt
CHANGED
|
@@ -12244,8 +12244,15 @@ for debugging; `AI_TOOLKIT_HOOK_QUIET=1` keeps it silent explicitly.
|
|
|
12244
12244
|
- `git push --force`
|
|
12245
12245
|
- `chmod -R 777`
|
|
12246
12246
|
|
|
12247
|
+
**Case sensitivity:** patterns are matched in two passes. Command names and flags
|
|
12248
|
+
are matched case-**sensitively**, because `-d` and `-D` are different flags —
|
|
12249
|
+
`git branch -D` blocks, `git branch -d` does not. SQL keywords and the Windows
|
|
12250
|
+
`format` command are matched case-**insensitively**, so `drop table` blocks the
|
|
12251
|
+
same as `DROP TABLE`.
|
|
12252
|
+
|
|
12247
12253
|
**Exemptions (avoid false positives):**
|
|
12248
12254
|
- `git push --force-with-lease` / `--force-if-includes` — the safe force-push variants are allowed.
|
|
12255
|
+
- `git branch -d` — the safe delete refuses unmerged branches and is the post-merge cleanup the git-workflow rules prescribe. `git branch -D` still blocks.
|
|
12249
12256
|
- A single, non-chained `echo`/`printf`/`git commit`/`git tag` carrying a destructive token as *data* (e.g. a commit message mentioning `DROP TABLE`) is allowed. Chained commands (`&&`, `;`, `|`) are still inspected in full.
|
|
12250
12257
|
|
|
12251
12258
|
### PreToolUse (file ops) — `guard-path.sh`
|
package/manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@softspark/ai-toolkit",
|
|
3
|
-
"version": "4.29.
|
|
3
|
+
"version": "4.29.2",
|
|
4
4
|
"description": "AI coding toolkit: 109 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",
|
|
@@ -173,7 +173,7 @@ def install_ai_tools(target_dir: Path, rules_dir: Path,
|
|
|
173
173
|
if "codex" in eds:
|
|
174
174
|
if dry_run:
|
|
175
175
|
print(" Would inject: $CODEX_HOME/AGENTS.md, $CODEX_HOME/agents/, "
|
|
176
|
-
"$CODEX_HOME/hooks.json")
|
|
176
|
+
"$CODEX_HOME/hooks.json + $CODEX_HOME/ai-toolkit-hooks/")
|
|
177
177
|
print(" Would generate: ~/.agents/skills/ (shared Codex skill discovery)")
|
|
178
178
|
else:
|
|
179
179
|
_install_codex_global(target_dir, rules_dir)
|
|
@@ -1224,6 +1224,12 @@ def _install_local_dry_run(reset: bool, editors: list[str] | None = None,
|
|
|
1224
1224
|
if "opencode" in eds:
|
|
1225
1225
|
print(" Would generate: .opencode/skills/ (profile=full)")
|
|
1226
1226
|
if "codex" in eds:
|
|
1227
|
+
# Hooks are not profile-gated: the live path runs gen_codex_hooks
|
|
1228
|
+
# unconditionally whenever codex is selected, so the preview must say so
|
|
1229
|
+
# at every profile. Announcing the asset directory as well as the
|
|
1230
|
+
# manifest matters here — the hook scripts are what a user reviews and
|
|
1231
|
+
# trusts with /hooks before Codex will run them.
|
|
1232
|
+
print(" Would generate: .codex/hooks.json + .codex/hooks/ (hook scripts)")
|
|
1227
1233
|
print(" Would generate: .codex/agents/ native agents")
|
|
1228
1234
|
print(" Would generate: .agents/skills/ Codex skills")
|
|
1229
1235
|
if codex_skills:
|