@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 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: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)
7
7
  [![Skills](https://img.shields.io/badge/skills-114-brightgreen)](app/skills/)
8
8
  [![Agents](https://img.shields.io/badge/agents-44-blue)](app/agents/)
9
- [![Tests](https://img.shields.io/badge/tests-1972%20passing-success)](tests/)
10
-
11
- ## What's New in v4.32.1
12
-
13
- **v4.32.1** fixes two defects the post-release SOPs found on v4.32.0 (both
14
- older than that release):
15
-
16
- - `ai-toolkit plugin remove` now deletes the hooks and scripts a pack
17
- installed under `~/.softspark/ai-toolkit`. Install records what it copied;
18
- removal deletes only unchanged, unshared files and names anything it
19
- preserves. Every pack used to leave 4-5 files behind.
20
- - Five skill scripts (`doc-inventory`, `dependency-graph`, `migration-status`,
21
- `refactor-scan`, `complexity`) answer `--help` instead of treating it as a
22
- path; a new test probes every documented skill script with `--help`.
23
- - Still in this train from v4.32.0: path-scoped common rules, language skills
24
- scoped to your registered projects (`--language-skills`), `doctor` Context
25
- Budget and Permission Rules checks, one strict frontmatter parser, and the
26
- `git-team` rule for `--profile strict`. Test count: 1966 -> 1972 bats +
9
+ [![Tests](https://img.shields.io/badge/tests-1978%20passing-success)](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.1",
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
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "4.32.1",
2
+ "version": "4.32.3",
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.32.1",
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), "
@@ -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
- Path(args.output),
351
+ user_path(args.output),
351
352
  include_custom_rules=not args.no_custom_rules,
352
353
  verify=args.verify,
353
354
  ) else 1
@@ -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(Path(args.output)) else 1
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