@softspark/ai-toolkit 4.32.1 → 4.32.3
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 +39 -0
- package/README.md +23 -18
- package/app/.claude-plugin/plugin.json +1 -1
- package/app/hooks/user-prompt-submit.sh +21 -0
- package/app/surface.json +5 -0
- package/bin/ai-toolkit.js +5 -1
- package/kb/reference/cli-reference.md +1 -1
- package/llms-full.txt +1 -1
- package/manifest.json +1 -1
- package/package.json +1 -1
- package/scripts/antigravity_plugin.py +2 -1
- package/scripts/claude_app.py +2 -1
- package/scripts/codex_plugin.py +2 -1
- package/scripts/paths.py +18 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,45 @@ Versioning follows [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## v4.32.3 — Search-first stops firing on things nobody asked (2026-09-04)
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- **A background task finishing no longer demands a KB search.**
|
|
15
|
+
`user-prompt-submit.sh` set the search-required flag on any stdin longer
|
|
16
|
+
than 30 characters. The harness delivers background-task notifications, CI
|
|
17
|
+
events and replayed slash-command output on the same channel as a prompt, so
|
|
18
|
+
a task completing blocked `Stop` and asked for a search over text nobody
|
|
19
|
+
wrote. Harness event envelopes no longer set the flag.
|
|
20
|
+
- **A pasted credential no longer becomes a search query.** A 43-character API
|
|
21
|
+
key on its own line cleared the length gate, and the block message names the
|
|
22
|
+
prompt as the thing to search for — so the enforcement path asked for a live
|
|
23
|
+
secret to be sent to a retrieval service. Single-token prompts no longer set
|
|
24
|
+
the flag; a genuine one-word prompt is under the length gate anyway, so
|
|
25
|
+
nothing that was enforced before stops being enforced. Prose that merely
|
|
26
|
+
mentions a task notification still sets it, and that case is now a test.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## v4.32.2 - Plugin exports land where you run the command (2026-09-04)
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- **`claude-app export`, `codex-plugin export`, `antigravity-plugin export`
|
|
35
|
+
write to the shell's directory.** `bin/ai-toolkit.js` runs these three with
|
|
36
|
+
`cwd` inside the installed package so their asset paths resolve, which also
|
|
37
|
+
made every relative `--output`, and therefore every default
|
|
38
|
+
(`ai-toolkit-claude-app.zip`, `*-global-instructions.md`), appear next to
|
|
39
|
+
`node_modules/@softspark/ai-toolkit`. The wrapper now passes the user's
|
|
40
|
+
directory as `AI_TOOLKIT_USER_CWD` and `paths.user_path()` resolves relative
|
|
41
|
+
outputs against it; absolute paths and direct `python3 scripts/...` runs
|
|
42
|
+
are unchanged. Found the first time the v4.32.1 README instruction was
|
|
43
|
+
followed from `~/Downloads`.
|
|
44
|
+
- `.gitignore` ignores root-level `*.zip` and `*-global-instructions.md` so an
|
|
45
|
+
export run from the repository cannot be committed by accident.
|
|
46
|
+
- **Test count.** Bats increased from 1972 to 1974 (relative `--output` from
|
|
47
|
+
a foreign cwd for `claude-app` and `codex-plugin`).
|
|
48
|
+
|
|
10
49
|
## v4.32.1 - Plugin removal leaves nothing behind (2026-09-04)
|
|
11
50
|
|
|
12
51
|
Both fixes come from running the post-release SOPs on v4.32.0 in an isolated
|
package/README.md
CHANGED
|
@@ -6,24 +6,29 @@
|
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
[](app/skills/)
|
|
8
8
|
[](app/agents/)
|
|
9
|
-
[](tests/)
|
|
10
|
+
|
|
11
|
+
## What's New in v4.32.3
|
|
12
|
+
|
|
13
|
+
**v4.32.3** stops search-first enforcement firing on things nobody asked:
|
|
14
|
+
|
|
15
|
+
- **A background task finishing no longer blocks `Stop`.** The search-required
|
|
16
|
+
flag was set on any stdin over 30 characters, and the harness delivers
|
|
17
|
+
background-task notifications, CI events and replayed slash-command output
|
|
18
|
+
on the same channel as a prompt. Event envelopes no longer set it.
|
|
19
|
+
- **A pasted credential no longer becomes a search query.** A 43-character API
|
|
20
|
+
key on its own line cleared the length gate, and the block message names the
|
|
21
|
+
prompt as the thing to search for — so the enforcement path asked for a live
|
|
22
|
+
secret to be sent to a retrieval service. Single-token prompts no longer set
|
|
23
|
+
the flag.
|
|
24
|
+
- Nothing that was enforced before stops being enforced: a genuine one-word
|
|
25
|
+
prompt is under the length gate anyway, and prose that merely mentions a task
|
|
26
|
+
notification still sets the flag. That case is now a test.
|
|
27
|
+
- Still in this train: exports land in the directory you ran the command in
|
|
28
|
+
(v4.32.2); `plugin remove` leaves nothing behind, every skill script answers
|
|
29
|
+
`--help` (v4.32.1); path-scoped common rules, project-scoped language skills,
|
|
30
|
+
`doctor` context-budget and permission checks, one strict frontmatter parser,
|
|
31
|
+
`git-team` for `--profile strict` (v4.32.0). Test count: 1974 -> 1978 bats +
|
|
27
32
|
348 pytest.
|
|
28
33
|
|
|
29
34
|
See [CHANGELOG.md](CHANGELOG.md) for full history.
|
|
@@ -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.32.
|
|
6
|
+
"version": "4.32.3",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "SoftSpark",
|
|
9
9
|
"url": "https://github.com/softspark"
|
|
@@ -29,7 +29,28 @@ PROMPT_LEN=${#PROMPT_TEXT}
|
|
|
29
29
|
STATE_DIR="$HOME/.softspark/ai-toolkit/state"
|
|
30
30
|
FLAG="$STATE_DIR/search-required-$(hook_session_id).flag"
|
|
31
31
|
mkdir -p "$STATE_DIR" 2>/dev/null
|
|
32
|
+
|
|
33
|
+
# The flag means "somebody asked a question the KB might answer". Length alone
|
|
34
|
+
# does not establish that. The harness delivers background-task notifications,
|
|
35
|
+
# CI events and replayed slash-command output on the same channel as a prompt,
|
|
36
|
+
# and a 43-character API key pasted on its own line clears the length gate too.
|
|
37
|
+
# Both were observed in one session: the first demanded a KB search for text
|
|
38
|
+
# nobody asked about, the second would have sent a live credential to a
|
|
39
|
+
# retrieval service as the query. Neither is a prompt.
|
|
40
|
+
PROMPT_HEAD="${PROMPT_TEXT#"${PROMPT_TEXT%%[![:space:]]*}"}"
|
|
41
|
+
PROMPT_IS_QUESTION=1
|
|
42
|
+
case "$PROMPT_HEAD" in
|
|
43
|
+
'<task-notification'*|'<ci-monitor-event'*|'<system-reminder'*|\
|
|
44
|
+
'<local-command-'*|'<command-name'*|'<command-message'*) PROMPT_IS_QUESTION=0 ;;
|
|
45
|
+
esac
|
|
46
|
+
# A single opaque token — API key, hash, URL, path — carries no question. A
|
|
47
|
+
# genuine one-word prompt is under the length gate anyway, so nothing is lost.
|
|
48
|
+
if [ "$(printf '%s' "$PROMPT_TEXT" | wc -w | tr -d ' ')" -le 1 ]; then
|
|
49
|
+
PROMPT_IS_QUESTION=0
|
|
50
|
+
fi
|
|
51
|
+
|
|
32
52
|
if [ "$PROMPT_LEN" -gt 30 ] && \
|
|
53
|
+
[ "$PROMPT_IS_QUESTION" -eq 1 ] && \
|
|
33
54
|
[ "${CLAUDE_SKIP_SEARCH_FIRST:-0}" != "1" ] && \
|
|
34
55
|
ai_toolkit_has_search_provider; then
|
|
35
56
|
{ printf '%s\n%s\n' "$(date -u +%s)" "$PROMPT_TEXT" > "$FLAG"; } 2>/dev/null
|
package/app/surface.json
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"chaos",
|
|
17
17
|
"ci",
|
|
18
18
|
"ci-cd-patterns",
|
|
19
|
+
"claude-toolkit-rules",
|
|
19
20
|
"clean-code",
|
|
20
21
|
"command-creator",
|
|
21
22
|
"commit",
|
|
@@ -36,12 +37,14 @@
|
|
|
36
37
|
"docs",
|
|
37
38
|
"documentation-standards",
|
|
38
39
|
"ecommerce-patterns",
|
|
40
|
+
"edit-discipline",
|
|
39
41
|
"evaluate",
|
|
40
42
|
"evolve",
|
|
41
43
|
"explain",
|
|
42
44
|
"explore",
|
|
43
45
|
"fix",
|
|
44
46
|
"flutter-patterns",
|
|
47
|
+
"git-conventions",
|
|
45
48
|
"git-mastery",
|
|
46
49
|
"golang-rules",
|
|
47
50
|
"grill-me",
|
|
@@ -68,6 +71,7 @@
|
|
|
68
71
|
"observability-patterns",
|
|
69
72
|
"onboard",
|
|
70
73
|
"orchestrate",
|
|
74
|
+
"output-mode",
|
|
71
75
|
"panic",
|
|
72
76
|
"performance-profiling",
|
|
73
77
|
"persona",
|
|
@@ -81,6 +85,7 @@
|
|
|
81
85
|
"prompt-caching-patterns",
|
|
82
86
|
"python-rules",
|
|
83
87
|
"qa-session",
|
|
88
|
+
"quality-gates",
|
|
84
89
|
"rag-patterns",
|
|
85
90
|
"refactor",
|
|
86
91
|
"refactor-plan",
|
package/bin/ai-toolkit.js
CHANGED
|
@@ -222,10 +222,14 @@ function runGenerator(scriptName, extraArgs = []) {
|
|
|
222
222
|
*/
|
|
223
223
|
function run(script, args = [], opts = {}) {
|
|
224
224
|
requirePython();
|
|
225
|
+
// Commands flagged toolkitCwd run with cwd inside the installed package so
|
|
226
|
+
// their relative asset paths resolve; the user's own directory travels in
|
|
227
|
+
// AI_TOOLKIT_USER_CWD so a relative --output still lands where they typed
|
|
228
|
+
// the command, not inside node_modules (v4.32.2).
|
|
225
229
|
const result = spawnSync('python3', [script, ...args], {
|
|
226
230
|
stdio: 'inherit',
|
|
227
231
|
cwd: opts.cwd || CWD,
|
|
228
|
-
env: { ...process.env },
|
|
232
|
+
env: { ...process.env, AI_TOOLKIT_USER_CWD: CWD },
|
|
229
233
|
});
|
|
230
234
|
if (result.status !== 0) {
|
|
231
235
|
process.exit(result.status || 1);
|
|
@@ -30,7 +30,7 @@ Usage: ai-toolkit <command> [options]
|
|
|
30
30
|
| `doctor` | Diagnose install health, hooks, quick-win assets, artifact drift, context budget (est. resident tokens of the skill/agent listings and user rules, plus skills with zero recorded use; read-only, prints the `skillOverrides` key to paste), and permission rules (`permissions.allow` wildcards on interpreters, task runners, package installs, `gh api`, `curl`, `git fetch`, destructive commands; warns only, never edits) |
|
|
31
31
|
| `doctor --fix` | Auto-repair broken symlinks, missing hooks, stale artifacts |
|
|
32
32
|
| `eject [dir]` | Export standalone config (no symlinks, no toolkit dependency) |
|
|
33
|
-
| `claude-app export [--output FILE] [--no-custom-rules] [--verify]` | Build an uploadable Claude Chat/Desktop/Cowork plugin ZIP and global-instructions file |
|
|
33
|
+
| `claude-app export [--output FILE] [--no-custom-rules] [--verify]` | Writes to the directory you run the command in (relative `--output` and the default `ai-toolkit-claude-app.zip` + `*-global-instructions.md`; before v4.32.2 they landed inside `node_modules/@softspark/ai-toolkit`). Build an uploadable Claude Chat/Desktop/Cowork plugin ZIP and global-instructions file |
|
|
34
34
|
| `claude-app verify` | Validate a clean staged plugin with structural checks and the official Claude plugin validator |
|
|
35
35
|
| `codex-plugin export [--output FILE]` | Build a deterministic native Codex plugin ZIP with skills and self-contained hooks |
|
|
36
36
|
| `codex-plugin verify` | Validate a clean native Codex plugin stage without installing it or changing user configuration |
|
package/llms-full.txt
CHANGED
|
@@ -10482,7 +10482,7 @@ Usage: ai-toolkit <command> [options]
|
|
|
10482
10482
|
| `doctor` | Diagnose install health, hooks, quick-win assets, artifact drift, context budget (est. resident tokens of the skill/agent listings and user rules, plus skills with zero recorded use; read-only, prints the `skillOverrides` key to paste), and permission rules (`permissions.allow` wildcards on interpreters, task runners, package installs, `gh api`, `curl`, `git fetch`, destructive commands; warns only, never edits) |
|
|
10483
10483
|
| `doctor --fix` | Auto-repair broken symlinks, missing hooks, stale artifacts |
|
|
10484
10484
|
| `eject [dir]` | Export standalone config (no symlinks, no toolkit dependency) |
|
|
10485
|
-
| `claude-app export [--output FILE] [--no-custom-rules] [--verify]` | Build an uploadable Claude Chat/Desktop/Cowork plugin ZIP and global-instructions file |
|
|
10485
|
+
| `claude-app export [--output FILE] [--no-custom-rules] [--verify]` | Writes to the directory you run the command in (relative `--output` and the default `ai-toolkit-claude-app.zip` + `*-global-instructions.md`; before v4.32.2 they landed inside `node_modules/@softspark/ai-toolkit`). Build an uploadable Claude Chat/Desktop/Cowork plugin ZIP and global-instructions file |
|
|
10486
10486
|
| `claude-app verify` | Validate a clean staged plugin with structural checks and the official Claude plugin validator |
|
|
10487
10487
|
| `codex-plugin export [--output FILE]` | Build a deterministic native Codex plugin ZIP with skills and self-contained hooks |
|
|
10488
10488
|
| `codex-plugin verify` | Validate a clean native Codex plugin stage without installing it or changing user configuration |
|
package/manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@softspark/ai-toolkit",
|
|
3
|
-
"version": "4.32.
|
|
3
|
+
"version": "4.32.3",
|
|
4
4
|
"description": "AI coding toolkit: 109 skills, 44 agents, 14 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",
|
|
@@ -22,6 +22,7 @@ from typing import Any
|
|
|
22
22
|
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
23
23
|
|
|
24
24
|
from dir_rules_shared import STANDARD_RULES
|
|
25
|
+
from paths import user_path
|
|
25
26
|
from emission import agents_dir
|
|
26
27
|
from generate_antigravity_agents import render_agent
|
|
27
28
|
from generate_antigravity_hooks import (
|
|
@@ -550,7 +551,7 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
550
551
|
or args.output_path
|
|
551
552
|
or "ai-toolkit-antigravity-plugin.zip"
|
|
552
553
|
)
|
|
553
|
-
path = export(output)
|
|
554
|
+
path = export(user_path(output))
|
|
554
555
|
print(f"Created: {path}")
|
|
555
556
|
print(
|
|
556
557
|
"Install under .agents/plugins/ai-toolkit/ (workspace), "
|
package/scripts/claude_app.py
CHANGED
|
@@ -29,6 +29,7 @@ from pathlib import Path
|
|
|
29
29
|
|
|
30
30
|
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
31
31
|
from frontmatter import split_frontmatter # noqa: E402
|
|
32
|
+
from paths import user_path # noqa: E402
|
|
32
33
|
|
|
33
34
|
|
|
34
35
|
TOOLKIT_DIR = Path(__file__).resolve().parent.parent
|
|
@@ -347,7 +348,7 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
347
348
|
return 0 if verify_plugin() else 1
|
|
348
349
|
if args.action == "export":
|
|
349
350
|
return 0 if export_plugin(
|
|
350
|
-
|
|
351
|
+
user_path(args.output),
|
|
351
352
|
include_custom_rules=not args.no_custom_rules,
|
|
352
353
|
verify=args.verify,
|
|
353
354
|
) else 1
|
package/scripts/codex_plugin.py
CHANGED
|
@@ -26,6 +26,7 @@ from typing import Any
|
|
|
26
26
|
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
27
27
|
|
|
28
28
|
from codex_skill_adapter import build_codex_skill_text
|
|
29
|
+
from paths import user_path
|
|
29
30
|
from generate_codex_hooks import (
|
|
30
31
|
CODEX_HOOKS,
|
|
31
32
|
_asset_names,
|
|
@@ -754,7 +755,7 @@ def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
|
|
|
754
755
|
def main(argv: list[str] | None = None) -> int:
|
|
755
756
|
args = parse_args(argv)
|
|
756
757
|
if args.action == "export":
|
|
757
|
-
return 0 if export_plugin(
|
|
758
|
+
return 0 if export_plugin(user_path(args.output)) else 1
|
|
758
759
|
if args.action == "verify":
|
|
759
760
|
return 0 if verify_plugin() else 1
|
|
760
761
|
return 2
|
package/scripts/paths.py
CHANGED
|
@@ -55,3 +55,21 @@ LEGACY_PROJECT_LOCK = ".ai-toolkit.lock.json"
|
|
|
55
55
|
|
|
56
56
|
# Base config filename (published in npm packages — unchanged)
|
|
57
57
|
BASE_CONFIG_FILENAME = "ai-toolkit.config.json"
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def user_path(raw: "str | os.PathLike[str]") -> Path:
|
|
61
|
+
"""Resolve a user-supplied path against the directory the user ran the CLI in.
|
|
62
|
+
|
|
63
|
+
``bin/ai-toolkit.js`` runs some commands (``claude-app``, ``codex-plugin``,
|
|
64
|
+
``antigravity-plugin``) with ``cwd`` inside the installed package so their
|
|
65
|
+
relative asset paths resolve, and passes the shell's own directory as
|
|
66
|
+
``AI_TOOLKIT_USER_CWD``. Before v4.32.2 a relative ``--output`` (including
|
|
67
|
+
every default) was written next to ``node_modules/@softspark/ai-toolkit``.
|
|
68
|
+
Absolute paths pass through; direct ``python3 scripts/...`` runs, where the
|
|
69
|
+
variable is unset, resolve against the real cwd as before.
|
|
70
|
+
"""
|
|
71
|
+
path = Path(raw).expanduser()
|
|
72
|
+
if path.is_absolute():
|
|
73
|
+
return path
|
|
74
|
+
base = os.environ.get("AI_TOOLKIT_USER_CWD", "").strip()
|
|
75
|
+
return (Path(base) if base else Path.cwd()) / path
|