@softspark/ai-toolkit 4.4.0 → 4.4.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 +16 -0
- package/README.md +9 -8
- package/app/.claude-plugin/plugin.json +1 -1
- package/app/hooks/_hook-io.sh +9 -3
- package/app/hooks/track-usage.sh +2 -2
- package/app/hooks/user-prompt-submit.sh +3 -3
- package/kb/reference/codex-cli-compatibility.md +23 -8
- package/kb/reference/hooks-catalog.md +20 -3
- package/manifest.json +1 -1
- package/package.json +1 -1
- package/scripts/generate_codex_hooks.py +1 -10
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,22 @@ Versioning follows [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## v4.4.1 - Codex hook output compatibility fix (2026-05-25)
|
|
11
|
+
|
|
12
|
+
Patch release. Fixes Codex `UserPromptSubmit` hook JSON validation failures and visible hook-context noise while preserving hook side effects.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- **Codex `UserPromptSubmit` default output** - generated Codex hooks now keep `user-prompt-submit.sh` in quiet plain-text mode, preserving search-first flag side effects without emitting visible `additionalContext` in the Codex TUI.
|
|
17
|
+
- **Event-specific JSON context** - `hook_emit_context` can include `hookSpecificOutput.hookEventName`, and `user-prompt-submit.sh` emits `"UserPromptSubmit"` with `additionalContext` when JSON context mode is explicitly enabled.
|
|
18
|
+
- **Prompt hook output corruption** - `user-prompt-submit.sh` now suppresses filesystem redirection errors when search-first state writes are blocked by sandboxing or local permissions, keeping JSON output parseable.
|
|
19
|
+
- **Usage tracking tracebacks** - `track-usage.sh` now treats stats writes as best-effort and suppresses Python tracebacks when `~/.softspark/ai-toolkit/stats.json` cannot be written.
|
|
20
|
+
|
|
21
|
+
### Verification
|
|
22
|
+
|
|
23
|
+
- `bats tests/test_hooks.bats --filter 'track-usage|user-prompt-submit|post-tool-use'`
|
|
24
|
+
- `python3 scripts/validate.py --strict`
|
|
25
|
+
|
|
10
26
|
## v4.4.0 - native editor skill pointers and hook governance hardening (2026-05-25)
|
|
11
27
|
|
|
12
28
|
Minor release. Adds native skill pointer generation for more editor surfaces and hardens search-first governance so quiet hooks still inject model context without noisy transcript output.
|
package/README.md
CHANGED
|
@@ -6,16 +6,17 @@
|
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
[](app/skills/)
|
|
8
8
|
[](app/agents/)
|
|
9
|
-
[](tests/)
|
|
10
10
|
|
|
11
|
-
## What's New in v4.4.
|
|
11
|
+
## What's New in v4.4.1
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Patch release. Fixes Codex `UserPromptSubmit` hook output validation and visible hook-context noise while preserving hook side effects.
|
|
14
14
|
|
|
15
|
-
- **
|
|
16
|
-
- **
|
|
17
|
-
- **
|
|
18
|
-
- **
|
|
15
|
+
- **Codex-safe prompt hook defaults**: generated Codex hooks keep `UserPromptSubmit` side effects quiet without emitting visible `additionalContext` in the TUI.
|
|
16
|
+
- **Event-specific hook context**: JSON context output now includes `hookSpecificOutput.hookEventName` when enabled, matching Codex's event-specific schema.
|
|
17
|
+
- **Silent best-effort stats**: `track-usage.sh` no longer leaks Python tracebacks when local stats writes are blocked.
|
|
18
|
+
- **Sandbox-safe search flags**: search-first flag write failures no longer corrupt JSON hook output.
|
|
19
|
+
- **Release coverage updated**: hook regression coverage now includes blocked state and stats writes; suite count is 1151 tests.
|
|
19
20
|
|
|
20
21
|
See [CHANGELOG.md](CHANGELOG.md) for full history.
|
|
21
22
|
|
|
@@ -148,7 +149,7 @@ ai-toolkit/
|
|
|
148
149
|
│ └── ARCHITECTURE.md # Full system design
|
|
149
150
|
├── kb/ # Reference docs, procedures, plans
|
|
150
151
|
├── scripts/ # Validation, install, evaluation scripts
|
|
151
|
-
├── tests/ # Bats test suite (
|
|
152
|
+
├── tests/ # Bats test suite (1151 tests)
|
|
152
153
|
└── CHANGELOG.md
|
|
153
154
|
```
|
|
154
155
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-toolkit",
|
|
3
3
|
"description": "Professional-grade Claude Code toolkit with persona presets, skill security auditor, expanded lifecycle hooks, experimental opt-in plugin packs, benchmark harvesting, and multi-tool support.",
|
|
4
|
-
"version": "4.4.
|
|
4
|
+
"version": "4.4.1",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "SoftSpark",
|
|
7
7
|
"url": "https://github.com/softspark"
|
package/app/hooks/_hook-io.sh
CHANGED
|
@@ -57,10 +57,16 @@ hook_new_content() {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
hook_emit_context() {
|
|
60
|
-
local
|
|
60
|
+
local event="${2:+$1}"
|
|
61
|
+
local message="${2:-$1}"
|
|
61
62
|
if [ "${AI_TOOLKIT_HOOK_FORMAT:-}" = "json" ]; then
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
if [ -n "$event" ]; then
|
|
64
|
+
jq -nc --arg event "$event" --arg msg "$message" \
|
|
65
|
+
'{"hookSpecificOutput":{"hookEventName":$event,"additionalContext":$msg},"suppressOutput":true}'
|
|
66
|
+
else
|
|
67
|
+
jq -nc --arg msg "$message" \
|
|
68
|
+
'{"hookSpecificOutput":{"additionalContext":$msg},"suppressOutput":true}'
|
|
69
|
+
fi
|
|
64
70
|
elif [ "${AI_TOOLKIT_HOOK_QUIET:-0}" = "1" ]; then
|
|
65
71
|
return 0
|
|
66
72
|
elif [ "${AI_TOOLKIT_HOOK_VERBOSE:-0}" = "1" ]; then
|
package/app/hooks/track-usage.sh
CHANGED
|
@@ -22,10 +22,10 @@ SKILL_NAME=$(printf '%s' "$PROMPT_TEXT" | grep -oE '^/[a-z][a-z0-9-]*' | head -1
|
|
|
22
22
|
[ -z "$SKILL_NAME" ] && exit 0
|
|
23
23
|
|
|
24
24
|
# Ensure directory exists
|
|
25
|
-
mkdir -p "$(dirname "$STATS_FILE")"
|
|
25
|
+
mkdir -p "$(dirname "$STATS_FILE")" 2>/dev/null || true
|
|
26
26
|
|
|
27
27
|
# Atomic update via python3
|
|
28
|
-
python3 - "$STATS_FILE" "$SKILL_NAME" <<'PY'
|
|
28
|
+
python3 - "$STATS_FILE" "$SKILL_NAME" 2>/dev/null <<'PY' || true
|
|
29
29
|
import json
|
|
30
30
|
import sys
|
|
31
31
|
import os
|
|
@@ -28,9 +28,9 @@ mkdir -p "$STATE_DIR" 2>/dev/null
|
|
|
28
28
|
if [ "$PROMPT_LEN" -gt 30 ] && \
|
|
29
29
|
[ "${CLAUDE_SKIP_SEARCH_FIRST:-0}" != "1" ] && \
|
|
30
30
|
ai_toolkit_has_search_provider; then
|
|
31
|
-
printf '%s\n%s\n' "$(date -u +%s)" "$PROMPT_TEXT" > "$FLAG" 2>/dev/null
|
|
31
|
+
{ printf '%s\n%s\n' "$(date -u +%s)" "$PROMPT_TEXT" > "$FLAG"; } 2>/dev/null
|
|
32
32
|
else
|
|
33
|
-
rm -f "$FLAG" 2>/dev/null
|
|
33
|
+
{ rm -f "$FLAG"; } 2>/dev/null
|
|
34
34
|
fi
|
|
35
35
|
|
|
36
36
|
if ai_toolkit_has_search_provider; then
|
|
@@ -50,6 +50,6 @@ else
|
|
|
50
50
|
UserPromptSubmit: apply KB-first research, keep changes minimal, and update tests/docs when behavior changes."
|
|
51
51
|
fi
|
|
52
52
|
|
|
53
|
-
hook_emit_context "$CONTEXT_MSG"
|
|
53
|
+
hook_emit_context "UserPromptSubmit" "$CONTEXT_MSG"
|
|
54
54
|
|
|
55
55
|
exit 0
|
|
@@ -3,9 +3,9 @@ title: "AI Toolkit - Codex CLI Compatibility"
|
|
|
3
3
|
category: reference
|
|
4
4
|
service: ai-toolkit
|
|
5
5
|
tags: [codex, compatibility, install, skills, hooks]
|
|
6
|
-
version: "1.0.
|
|
6
|
+
version: "1.0.3"
|
|
7
7
|
created: "2026-04-12"
|
|
8
|
-
last_updated: "2026-05-
|
|
8
|
+
last_updated: "2026-05-25"
|
|
9
9
|
description: "Reference for how ai-toolkit maps Claude-oriented skills, hooks, and plugin packs to Codex CLI."
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -110,12 +110,27 @@ This means Claude-only events such as `TaskCompleted`, `TeammateIdle`,
|
|
|
110
110
|
`~/.codex/hooks.json` (global layer). Non-Codex events are silently skipped.
|
|
111
111
|
`remove-hook` cleans both Claude and Codex targets.
|
|
112
112
|
|
|
113
|
-
Generated Codex hook commands include `AI_TOOLKIT_HOOK_QUIET=1`. The
|
|
114
|
-
`UserPromptSubmit` governance hook
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
113
|
+
Generated Codex hook commands include `AI_TOOLKIT_HOOK_QUIET=1`. The generated
|
|
114
|
+
`UserPromptSubmit` governance hook does not set `AI_TOOLKIT_HOOK_FORMAT=json`
|
|
115
|
+
by default because Codex currently renders `additionalContext` as visible hook
|
|
116
|
+
context in the TUI. This keeps prompt-submit output quiet while preserving hook
|
|
117
|
+
side effects and blocking decisions such as search-first Stop enforcement.
|
|
118
|
+
|
|
119
|
+
Codex `UserPromptSubmit` JSON output is event-specific. When emitting context,
|
|
120
|
+
the hook must include the event name alongside the context:
|
|
121
|
+
|
|
122
|
+
```json
|
|
123
|
+
{
|
|
124
|
+
"hookSpecificOutput": {
|
|
125
|
+
"hookEventName": "UserPromptSubmit",
|
|
126
|
+
"additionalContext": "..."
|
|
127
|
+
},
|
|
128
|
+
"suppressOutput": true
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Older `{"hookSpecificOutput":{"additionalContext":"..."}}` output can be valid
|
|
133
|
+
JSON but fail newer Codex event-output validation.
|
|
119
134
|
|
|
120
135
|
Plain-text informational hook context is also silent by default in the shared
|
|
121
136
|
hook helper. Set `AI_TOOLKIT_HOOK_VERBOSE=1` only when debugging hook output
|
|
@@ -3,7 +3,7 @@ title: "Hooks Catalog"
|
|
|
3
3
|
category: reference
|
|
4
4
|
service: ai-toolkit
|
|
5
5
|
tags: [hooks, quality, safety, enforcement, settings.json]
|
|
6
|
-
version: "1.5.
|
|
6
|
+
version: "1.5.6"
|
|
7
7
|
created: "2026-03-27"
|
|
8
8
|
last_updated: "2026-05-25"
|
|
9
9
|
description: "Complete reference of all ai-toolkit hooks: events, scripts, installation, and runtime behavior."
|
|
@@ -114,12 +114,29 @@ work, evidence-first debugging, KB-first research, and validation expectations.
|
|
|
114
114
|
Skipped when `TOOLKIT_HOOK_PROFILE=minimal`. The bundled `app/hooks.json`
|
|
115
115
|
registers this command with `AI_TOOLKIT_HOOK_QUIET=1 AI_TOOLKIT_HOOK_FORMAT=json`.
|
|
116
116
|
This keeps the hook visually quiet (`suppressOutput: true`) while still
|
|
117
|
-
injecting
|
|
117
|
+
injecting event-specific JSON context before Claude starts working in runtimes
|
|
118
|
+
that consume hidden context:
|
|
119
|
+
|
|
120
|
+
```json
|
|
121
|
+
{
|
|
122
|
+
"hookSpecificOutput": {
|
|
123
|
+
"hookEventName": "UserPromptSubmit",
|
|
124
|
+
"additionalContext": "..."
|
|
125
|
+
},
|
|
126
|
+
"suppressOutput": true
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
118
130
|
That context is the proactive half of search-first enforcement; the paired
|
|
119
131
|
`stop-search-check.sh` remains the corrective half. In plain-text mode,
|
|
120
132
|
informational reminders are silent by default and require
|
|
121
133
|
`AI_TOOLKIT_HOOK_VERBOSE=1`.
|
|
122
134
|
|
|
135
|
+
Codex-generated hooks intentionally run this script without
|
|
136
|
+
`AI_TOOLKIT_HOOK_FORMAT=json` by default because Codex renders
|
|
137
|
+
`additionalContext` visibly in the TUI; the search-first flag side effect still
|
|
138
|
+
arms the corrective Stop hook.
|
|
139
|
+
|
|
123
140
|
### UserPromptSubmit (usage tracking) — `track-usage.sh`
|
|
124
141
|
|
|
125
142
|
| Field | Value |
|
|
@@ -129,7 +146,7 @@ informational reminders are silent by default and require
|
|
|
129
146
|
| Script | `~/.softspark/ai-toolkit/hooks/track-usage.sh` |
|
|
130
147
|
| Fires | Before Claude starts working on a submitted prompt |
|
|
131
148
|
|
|
132
|
-
**Action:** Records skill invocations (slash commands like `/commit`, `/review`) to `~/.softspark/ai-toolkit/stats.json` for local usage analytics. Non-slash prompts are ignored.
|
|
149
|
+
**Action:** Records skill invocations (slash commands like `/commit`, `/review`) to `~/.softspark/ai-toolkit/stats.json` for local usage analytics. Non-slash prompts are ignored. Stats writes are best-effort and stay silent if the local state path is not writable.
|
|
133
150
|
|
|
134
151
|
### PostToolUse (edit feedback) — `post-tool-use.sh`
|
|
135
152
|
|
package/manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@softspark/ai-toolkit",
|
|
3
|
-
"version": "4.4.
|
|
3
|
+
"version": "4.4.1",
|
|
4
4
|
"description": "AI coding toolkit: 107 skills, 44 agents, 12-editor write-through (Claude, Cursor, Windsurf, Copilot, Gemini, Cline, Roo, Aider, Augment, Antigravity, Codex, opencode), machine-enforced safety constitution, SARIF audit, signed npm provenance.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude",
|
|
@@ -25,10 +25,6 @@ from pathlib import Path
|
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
HOOKS_PREFIX = 'AI_TOOLKIT_HOOK_QUIET=1 "$HOME/.softspark/ai-toolkit/hooks/'
|
|
28
|
-
HOOKS_JSON_CONTEXT_PREFIX = (
|
|
29
|
-
'AI_TOOLKIT_HOOK_QUIET=1 AI_TOOLKIT_HOOK_FORMAT=json "$HOME/.softspark/ai-toolkit/hooks/'
|
|
30
|
-
)
|
|
31
|
-
|
|
32
28
|
# Hooks compatible with Codex, grouped by event.
|
|
33
29
|
# Format: (matcher, script_name)
|
|
34
30
|
CODEX_HOOKS: dict[str, list[tuple[str, str]]] = {
|
|
@@ -66,12 +62,7 @@ def build_hooks_json() -> dict:
|
|
|
66
62
|
for event, entries in CODEX_HOOKS.items():
|
|
67
63
|
hooks[event] = []
|
|
68
64
|
for matcher, script in entries:
|
|
69
|
-
|
|
70
|
-
HOOKS_JSON_CONTEXT_PREFIX
|
|
71
|
-
if event == "UserPromptSubmit" and script == "user-prompt-submit.sh"
|
|
72
|
-
else HOOKS_PREFIX
|
|
73
|
-
)
|
|
74
|
-
entry: dict = {"hooks": [{"type": "command", "command": f"{prefix}{script}\""}]}
|
|
65
|
+
entry: dict = {"hooks": [{"type": "command", "command": f"{HOOKS_PREFIX}{script}\""}]}
|
|
75
66
|
if matcher:
|
|
76
67
|
entry["matcher"] = matcher
|
|
77
68
|
hooks[event].append(entry)
|