@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 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: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
7
7
  [![Skills](https://img.shields.io/badge/skills-107-brightgreen)](app/skills/)
8
8
  [![Agents](https://img.shields.io/badge/agents-44-blue)](app/agents/)
9
- [![Tests](https://img.shields.io/badge/tests-1149%20passing-success)](tests/)
9
+ [![Tests](https://img.shields.io/badge/tests-1151%20passing-success)](tests/)
10
10
 
11
- ## What's New in v4.4.0
11
+ ## What's New in v4.4.1
12
12
 
13
- Minor release. Adds native skill pointers for more editor surfaces and hardens quiet hook governance for Claude and Codex.
13
+ Patch release. Fixes Codex `UserPromptSubmit` hook output validation and visible hook-context noise while preserving hook side effects.
14
14
 
15
- - **Native editor skills**: Cursor, Windsurf, and Cline now get generated skill pointer catalogs alongside existing rule surfaces.
16
- - **Quiet JSON governance**: `UserPromptSubmit` keeps output quiet while still injecting `additionalContext` for search-first and workflow reminders.
17
- - **Codex search-first hardening**: Stop enforcement recognizes current Codex MCP log shapes and tolerates noisy skill-loader output.
18
- - **Release coverage updated**: generator, install, Codex, hook, and search-first tests cover the new behavior; suite count is 1149 tests.
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 (1149 tests)
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.0",
4
+ "version": "4.4.1",
5
5
  "author": {
6
6
  "name": "SoftSpark",
7
7
  "url": "https://github.com/softspark"
@@ -57,10 +57,16 @@ hook_new_content() {
57
57
  }
58
58
 
59
59
  hook_emit_context() {
60
- local message="$1"
60
+ local event="${2:+$1}"
61
+ local message="${2:-$1}"
61
62
  if [ "${AI_TOOLKIT_HOOK_FORMAT:-}" = "json" ]; then
62
- jq -nc --arg msg "$message" \
63
- '{"hookSpecificOutput":{"additionalContext":$msg},"suppressOutput":true}'
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
@@ -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.2"
6
+ version: "1.0.3"
7
7
  created: "2026-04-12"
8
- last_updated: "2026-05-21"
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 additionally sets `AI_TOOLKIT_HOOK_FORMAT=json`
115
- so it can pass quiet `additionalContext` before the model responds. This keeps
116
- non-blocking reminders and startup context out of visible hook output while
117
- preserving hook side effects, proactive search-first context, and blocking
118
- decisions such as search-first Stop enforcement.
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.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 `hookSpecificOutput.additionalContext` before Claude starts working.
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
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "4.4.0",
2
+ "version": "4.4.1",
3
3
  "components": {
4
4
  "agents": {
5
5
  "description": "44 specialized agents (orchestrator, backend, frontend, security, devops, etc.)",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softspark/ai-toolkit",
3
- "version": "4.4.0",
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
- prefix = (
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)