@softspark/ai-toolkit 4.7.0 → 4.8.0
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 +14 -0
- package/README.md +8 -9
- package/app/.claude-plugin/plugin.json +1 -1
- package/kb/reference/hooks-catalog.md +27 -2
- package/kb/reference/supported-tools-registry.md +7 -6
- package/llms-full.txt +34 -8
- package/manifest.json +1 -1
- package/package.json +1 -1
- package/scripts/ecosystem_tools.json +4 -2
- package/scripts/generate_devin_hooks.py +149 -0
- package/scripts/install_steps/ai_tools.py +4 -1
- package/scripts/validate.py +6 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,20 @@ Versioning follows [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## v4.8.0 - Devin CLI hooks (Cascade migration) (2026-06-10)
|
|
11
|
+
|
|
12
|
+
Minor release. Migrates the deprecated Windsurf Cascade hooks onto the Devin CLI surface ahead of the 2026-07-01 Cascade sunset. Class D/F ecosystem change per `kb/procedures/ecosystem-sync-sop.md`. No skill/agent count change; no new broad-access skills.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- **Devin CLI hooks** — new `scripts/generate_devin_hooks.py` emits `.devin/hooks.v1.json` in the Claude-compatible hook format Devin CLI uses (docs.devin.ai/cli/extensibility/hooks). Wired into `ai-toolkit install --local --editors windsurf --profile full` alongside the existing (now deprecated) Cascade generator. Events are Claude-style (`PreToolUse`/`PostToolUse`/`UserPromptSubmit`/`Stop`/`SessionStart`) with matchers on Devin tool names (`read`/`edit`/`exec`/`mcp__*`); blocking uses the flat `{"decision":"block","reason":...}` shape + exit 2 (no `AI_TOOLKIT_HOOK_FORMAT=json`). Reuses the existing `~/.softspark/ai-toolkit/hooks/*.sh` scripts; `_hook-io.sh` already parses Devin's flat `hook_event_name`/`tool_name`/`tool_input` payload, so no normalizer change was needed. Test count: 1186 → 1196.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
- **Cascade hooks deprecation** — `scripts/generate_windsurf_hooks.py` (`.windsurf/hooks.json`) is marked deprecated: the Cascade agent and its hook surface stop working 2026-07-01, and Devin Local / Devin CLI do not read `.windsurf/hooks.json` as a fallback. Both generators run during the transition; `generate_windsurf_hooks.py` will be dropped in the first release after the sunset.
|
|
19
|
+
- **Global hooks reach Devin for free** — documented that Devin CLI reads `~/.claude/settings.json` + `.claude/settings.json` hooks directly (`read_config_from.claude` default on), so a global `ai-toolkit install` already covers Devin even without the project-local file.
|
|
20
|
+
- Registry: `.devin/hooks.v1.json` + `generate_devin_hooks.py` added to the windsurf entry in `scripts/ecosystem_tools.json` and `kb/reference/supported-tools-registry.md`; new "Per-Editor Native Hooks" section in `kb/reference/hooks-catalog.md`. `validate.py` maps the `devin` hook-generator stem back to the windsurf README platform key.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
10
24
|
## v4.7.0 - Devin Desktop .devin tree + Antigravity CLI surfaces (2026-06-10)
|
|
11
25
|
|
|
12
26
|
Minor release. Ecosystem sync per `kb/procedures/ecosystem-sync-sop.md` (window 2026-06-05 → 2026-06-10, doctor run + per-tool docs review with adversarial verification). No skill/agent count change; no new broad-access skills.
|
package/README.md
CHANGED
|
@@ -6,17 +6,16 @@
|
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
[](app/skills/)
|
|
8
8
|
[](app/agents/)
|
|
9
|
-
[](tests/)
|
|
10
10
|
|
|
11
|
-
## What's New in v4.
|
|
11
|
+
## What's New in v4.8.0
|
|
12
12
|
|
|
13
|
-
v4.
|
|
13
|
+
v4.8.0 migrates the deprecated Windsurf Cascade hooks onto the Devin CLI surface before Cascade sunsets on 2026-07-01.
|
|
14
14
|
|
|
15
|
-
- **Devin
|
|
16
|
-
- **
|
|
17
|
-
- **
|
|
18
|
-
-
|
|
19
|
-
- **Troubleshooting**: maintenance SOP gains the `claude --safe-mode` (v2.1.169) isolation step.
|
|
15
|
+
- **Devin CLI hooks**: new `generate_devin_hooks.py` emits `.devin/hooks.v1.json` in the Claude-compatible format Devin CLI uses — Claude-style events (`PreToolUse`/`PostToolUse`/`UserPromptSubmit`/`Stop`/`SessionStart`) with matchers on Devin tool names (`read`/`edit`/`exec`/`mcp__*`), reusing the existing toolkit hook scripts.
|
|
16
|
+
- **Cascade deprecation**: `.windsurf/hooks.json` is Cascade-scoped and dies 2026-07-01 with no Devin fallback; both generators run during the transition, the Cascade one drops in the first release after the sunset.
|
|
17
|
+
- **Global hooks reach Devin for free**: Devin CLI reads `~/.claude/settings.json` hooks directly, so a global `ai-toolkit install` already covers Devin even without the project-local file.
|
|
18
|
+
- No normalizer change needed: `_hook-io.sh` already parses Devin's flat `hook_event_name`/`tool_name`/`tool_input` payload.
|
|
20
19
|
|
|
21
20
|
See [CHANGELOG.md](CHANGELOG.md) for full history.
|
|
22
21
|
|
|
@@ -149,7 +148,7 @@ ai-toolkit/
|
|
|
149
148
|
│ └── ARCHITECTURE.md # Full system design
|
|
150
149
|
├── kb/ # Reference docs, procedures, plans
|
|
151
150
|
├── scripts/ # Validation, install, evaluation scripts
|
|
152
|
-
├── tests/ # Bats test suite (
|
|
151
|
+
├── tests/ # Bats test suite (1196 tests)
|
|
153
152
|
└── CHANGELOG.md
|
|
154
153
|
```
|
|
155
154
|
|
|
@@ -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
|
+
"version": "4.8.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "SoftSpark",
|
|
7
7
|
"url": "https://github.com/softspark"
|
|
@@ -3,9 +3,9 @@ title: "Hooks Catalog"
|
|
|
3
3
|
category: reference
|
|
4
4
|
service: ai-toolkit
|
|
5
5
|
tags: [hooks, quality, safety, enforcement, settings.json]
|
|
6
|
-
version: "1.
|
|
6
|
+
version: "1.6.0"
|
|
7
7
|
created: "2026-03-27"
|
|
8
|
-
last_updated: "2026-
|
|
8
|
+
last_updated: "2026-06-10"
|
|
9
9
|
description: "Complete reference of all ai-toolkit hooks: events, scripts, installation, and runtime behavior."
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -571,6 +571,31 @@ commands explicitly silent, and Codex-generated hooks plus Claude's bundled
|
|
|
571
571
|
- `_source: "ai-toolkit"` tag on every entry — allows idempotent merge/strip
|
|
572
572
|
- Hooks are **global only** — `--local` does not install hooks into project settings
|
|
573
573
|
|
|
574
|
+
## Per-Editor Native Hooks (profile=full)
|
|
575
|
+
|
|
576
|
+
Beyond the global Claude Code hooks above, full-profile project installs emit native hook files for editors that support their own hook lifecycle. All reuse the same `~/.softspark/ai-toolkit/hooks/*.sh` scripts and the `_source: ai-toolkit` merge tag.
|
|
577
|
+
|
|
578
|
+
| Editor | File | Generator | Format |
|
|
579
|
+
|--------|------|-----------|--------|
|
|
580
|
+
| Cursor | `.cursor/hooks.json` | `generate_cursor_hooks.py` | Cursor hooks schema |
|
|
581
|
+
| Windsurf (Cascade) | `.windsurf/hooks.json` | `generate_windsurf_hooks.py` | Cascade `agent_action_name`/`tool_info` — **deprecated, dies 2026-07-01** |
|
|
582
|
+
| Devin CLI | `.devin/hooks.v1.json` | `generate_devin_hooks.py` | Claude-compatible (the replacement for Cascade) |
|
|
583
|
+
| Gemini CLI | `.gemini/settings.json` (hooks block) | `generate_gemini_hooks.py` | Gemini `BeforeTool`/`AfterTool` events |
|
|
584
|
+
| Augment | `.augment/settings.json` (hooks block) | `generate_augment_hooks.py` | Claude-style events |
|
|
585
|
+
|
|
586
|
+
### Devin CLI hooks (`.devin/hooks.v1.json`)
|
|
587
|
+
|
|
588
|
+
Windsurf rebranded to Devin Desktop (2026-06-02); the Cascade agent — and its `.windsurf/hooks.json` surface — is available only through **2026-07-01**. Devin Local / Devin CLI do **not** read `.windsurf/hooks.json` as a fallback, so hooks must be regenerated onto the Devin CLI format.
|
|
589
|
+
|
|
590
|
+
Devin CLI uses a **Claude-compatible** hook format (docs.devin.ai/cli/extensibility/hooks). Key facts driving the generator:
|
|
591
|
+
|
|
592
|
+
- **Standalone file shape:** in `.devin/hooks.v1.json` the entire file IS the hooks object — no top-level `"hooks"` wrapper key (unlike `.claude/settings.json`).
|
|
593
|
+
- **Events:** Claude-style PascalCase — `PreToolUse`, `PostToolUse`, `UserPromptSubmit`, `Stop`, `SessionStart`. `post_setup_worktree` has no Devin equivalent (`session-context.sh` moves to `SessionStart`); `post_cascade_response` maps to `Stop` (which carries no response text on stdin).
|
|
594
|
+
- **Matchers:** regex against the Devin **tool name** (`read`, `edit`, `exec`, `grep`, `glob`, `mcp__<server>__<tool>`) — NOT Claude's `Bash`/`Edit`, so the shared guards reliably fire.
|
|
595
|
+
- **Block contract:** the guard scripts emit `{"decision":"block","reason":...}` on stdout (plain mode) AND exit 2 — Devin honors both. Hooks run **without** `AI_TOOLKIT_HOOK_FORMAT=json` because Devin expects the flat `{"decision","reason"}` shape, not Claude's `hookSpecificOutput` envelope.
|
|
596
|
+
- **Stdin payload:** flat `{ "hook_event_name", "tool_name", "tool_input" }` — already handled by `_hook-io.sh` via its `.tool_name` / `.tool_input.*` branches, so no normalizer change was needed.
|
|
597
|
+
- **Global bonus:** Devin CLI reads `~/.claude/settings.json` + `.claude/settings.json` hooks directly (`read_config_from.claude` default on, since CLI `2026.3.20-2`), so a global `ai-toolkit install` already covers Devin even without the project-local file.
|
|
598
|
+
|
|
574
599
|
## Troubleshooting
|
|
575
600
|
|
|
576
601
|
**Hooks not loading:**
|
|
@@ -3,9 +3,9 @@ title: "Supported Tools Registry"
|
|
|
3
3
|
category: reference
|
|
4
4
|
service: ai-toolkit
|
|
5
5
|
tags: [editors, platforms, generators, integration, ecosystem]
|
|
6
|
-
version: "1.
|
|
6
|
+
version: "1.6.0"
|
|
7
7
|
created: "2026-04-23"
|
|
8
|
-
last_updated: "2026-06-
|
|
8
|
+
last_updated: "2026-06-10"
|
|
9
9
|
description: "Human-readable view of scripts/ecosystem_tools.json — the canonical list of tools ai-toolkit integrates with (Claude Code + 11 editors), their documentation URLs, config paths, our generators, and tracked capability markers."
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -62,12 +62,13 @@ The canonical data lives in **`scripts/ecosystem_tools.json`** and is consumed b
|
|
|
62
62
|
| Docs | https://docs.devin.ai/desktop (Windsurf rebranded to Devin Desktop ~2026-06-02; docs.windsurf.com resolves here) |
|
|
63
63
|
| Changelog | https://docs.devin.ai/desktop/changelog (windsurf.com/changelog 308-permanent-redirects here) |
|
|
64
64
|
| Stable docs mirror | https://docs.devin.ai/desktop/... per-page .md twins; legacy `.windsurf/`, `.windsurfrules`, `~/.codeium/windsurf/` paths still read as fallback (new canonical: `.devin/`) |
|
|
65
|
-
| Config paths | **Primary (Devin Desktop):** `.devin/rules/*.md`, `.devin/workflows/*.md`, `.devin/skills/*/SKILL.md`, `.devin/config.json`, `.devin/config.local.json`, `~/.config/devin/config.json` (Devin Local MCP/permissions). **Legacy fallback:** `.windsurfrules`, `.windsurf/rules/*.md`, `.windsurf/workflows/*.md`, `.windsurf/skills/*/SKILL.md`, `~/.codeium/windsurf/memories/global_rules.md`, `~/.codeium/windsurf/skills/*/SKILL.md`, `~/.codeium/windsurf/mcp_config.json`. Plus `AGENTS.md`. |
|
|
66
|
-
| Compat read paths | `.agents/skills/`, `~/.agents/skills/`, (with Claude Code config-reading) `.claude/skills/`, `~/.claude/skills
|
|
67
|
-
| Our generators | `scripts/generate_windsurf.py`, `scripts/generate_windsurf_rules.py` (dual-emits `.devin/` + `.windsurf/`), `scripts/generate_windsurf_hooks.py` (profile=full; **Cascade-scoped, deprecated**), `scripts/generate_windsurf_skills.py` (global + profile=full pointer, dual-emits) |
|
|
65
|
+
| Config paths | **Primary (Devin Desktop):** `.devin/rules/*.md`, `.devin/workflows/*.md`, `.devin/skills/*/SKILL.md`, `.devin/hooks.v1.json` (Devin CLI hooks, Claude format), `.devin/config.json`, `.devin/config.local.json`, `~/.config/devin/config.json` (Devin Local MCP/permissions). **Legacy fallback:** `.windsurfrules`, `.windsurf/rules/*.md`, `.windsurf/workflows/*.md`, `.windsurf/skills/*/SKILL.md`, `~/.codeium/windsurf/memories/global_rules.md`, `~/.codeium/windsurf/skills/*/SKILL.md`, `~/.codeium/windsurf/mcp_config.json`. Plus `AGENTS.md`. |
|
|
66
|
+
| Compat read paths | skills: `.agents/skills/`, `~/.agents/skills/`, (with Claude Code config-reading) `.claude/skills/`, `~/.claude/skills/`. **Hooks: Devin CLI reads `.claude/settings.json` + `~/.claude/settings.json` hooks directly (`read_config_from.claude` default on), so globally-installed toolkit hooks work under Devin with no project-local file.** |
|
|
67
|
+
| Our generators | `scripts/generate_windsurf.py`, `scripts/generate_windsurf_rules.py` (dual-emits `.devin/` + `.windsurf/`), `scripts/generate_windsurf_hooks.py` (profile=full; **Cascade-scoped, deprecated, drop after 2026-07-01**), `scripts/generate_devin_hooks.py` (profile=full; `.devin/hooks.v1.json`, Claude-format Devin CLI hooks), `scripts/generate_windsurf_skills.py` (global + profile=full pointer, dual-emits) |
|
|
68
68
|
| Tracked capabilities | Cascade, `windsurfrules`, `AGENTS.md`, activation triggers (`always_on`/`glob`/`model_decision`), workflows, skills, MCP, memories, hooks |
|
|
69
69
|
| Activation modes emitted | always_on (agents/security/quality), glob (testing + language rules), model_decision (code-style/workflow) |
|
|
70
|
-
|
|
|
70
|
+
| Hooks migration | **Done.** Cascade `.windsurf/hooks.json` (`agent_action_name`/`tool_info` format) dies 2026-07-01 with no Devin fallback. `generate_devin_hooks.py` emits `.devin/hooks.v1.json` in the Claude-compatible format Devin CLI uses: Claude-style events (PreToolUse/PostToolUse/UserPromptSubmit/Stop/SessionStart), matchers on Devin tool names (`read`/`edit`/`exec`/`mcp__*`), blocking via flat `{"decision":"block","reason":...}` + exit 2 (no `AI_TOOLKIT_HOOK_FORMAT=json` — Devin does not use Claude's `hookSpecificOutput` envelope). `post_setup_worktree`→`SessionStart`; `post_cascade_response`→`Stop` (no response text on stdin). Both hook generators run at profile=full during the transition; drop `generate_windsurf_hooks.py` in the first release after 2026-07-01. |
|
|
71
|
+
| Sunset notes | Cascade agent is available only through **2026-07-01**; Devin Local is the default agent since 2026-06-02. Devin CLI ("Devin for Terminal") shares the Devin Local harness, reads `AGENTS.md`, the standard `SKILL.md` format, and Claude-format hooks; not yet a separate registry entry. |
|
|
71
72
|
|
|
72
73
|
### GitHub Copilot
|
|
73
74
|
|
package/llms-full.txt
CHANGED
|
@@ -8900,9 +8900,9 @@ title: "Hooks Catalog"
|
|
|
8900
8900
|
category: reference
|
|
8901
8901
|
service: ai-toolkit
|
|
8902
8902
|
tags: [hooks, quality, safety, enforcement, settings.json]
|
|
8903
|
-
version: "1.
|
|
8903
|
+
version: "1.6.0"
|
|
8904
8904
|
created: "2026-03-27"
|
|
8905
|
-
last_updated: "2026-
|
|
8905
|
+
last_updated: "2026-06-10"
|
|
8906
8906
|
description: "Complete reference of all ai-toolkit hooks: events, scripts, installation, and runtime behavior."
|
|
8907
8907
|
---
|
|
8908
8908
|
|
|
@@ -9468,6 +9468,31 @@ commands explicitly silent, and Codex-generated hooks plus Claude's bundled
|
|
|
9468
9468
|
- `_source: "ai-toolkit"` tag on every entry — allows idempotent merge/strip
|
|
9469
9469
|
- Hooks are **global only** — `--local` does not install hooks into project settings
|
|
9470
9470
|
|
|
9471
|
+
## Per-Editor Native Hooks (profile=full)
|
|
9472
|
+
|
|
9473
|
+
Beyond the global Claude Code hooks above, full-profile project installs emit native hook files for editors that support their own hook lifecycle. All reuse the same `~/.softspark/ai-toolkit/hooks/*.sh` scripts and the `_source: ai-toolkit` merge tag.
|
|
9474
|
+
|
|
9475
|
+
| Editor | File | Generator | Format |
|
|
9476
|
+
|--------|------|-----------|--------|
|
|
9477
|
+
| Cursor | `.cursor/hooks.json` | `generate_cursor_hooks.py` | Cursor hooks schema |
|
|
9478
|
+
| Windsurf (Cascade) | `.windsurf/hooks.json` | `generate_windsurf_hooks.py` | Cascade `agent_action_name`/`tool_info` — **deprecated, dies 2026-07-01** |
|
|
9479
|
+
| Devin CLI | `.devin/hooks.v1.json` | `generate_devin_hooks.py` | Claude-compatible (the replacement for Cascade) |
|
|
9480
|
+
| Gemini CLI | `.gemini/settings.json` (hooks block) | `generate_gemini_hooks.py` | Gemini `BeforeTool`/`AfterTool` events |
|
|
9481
|
+
| Augment | `.augment/settings.json` (hooks block) | `generate_augment_hooks.py` | Claude-style events |
|
|
9482
|
+
|
|
9483
|
+
### Devin CLI hooks (`.devin/hooks.v1.json`)
|
|
9484
|
+
|
|
9485
|
+
Windsurf rebranded to Devin Desktop (2026-06-02); the Cascade agent — and its `.windsurf/hooks.json` surface — is available only through **2026-07-01**. Devin Local / Devin CLI do **not** read `.windsurf/hooks.json` as a fallback, so hooks must be regenerated onto the Devin CLI format.
|
|
9486
|
+
|
|
9487
|
+
Devin CLI uses a **Claude-compatible** hook format (docs.devin.ai/cli/extensibility/hooks). Key facts driving the generator:
|
|
9488
|
+
|
|
9489
|
+
- **Standalone file shape:** in `.devin/hooks.v1.json` the entire file IS the hooks object — no top-level `"hooks"` wrapper key (unlike `.claude/settings.json`).
|
|
9490
|
+
- **Events:** Claude-style PascalCase — `PreToolUse`, `PostToolUse`, `UserPromptSubmit`, `Stop`, `SessionStart`. `post_setup_worktree` has no Devin equivalent (`session-context.sh` moves to `SessionStart`); `post_cascade_response` maps to `Stop` (which carries no response text on stdin).
|
|
9491
|
+
- **Matchers:** regex against the Devin **tool name** (`read`, `edit`, `exec`, `grep`, `glob`, `mcp__<server>__<tool>`) — NOT Claude's `Bash`/`Edit`, so the shared guards reliably fire.
|
|
9492
|
+
- **Block contract:** the guard scripts emit `{"decision":"block","reason":...}` on stdout (plain mode) AND exit 2 — Devin honors both. Hooks run **without** `AI_TOOLKIT_HOOK_FORMAT=json` because Devin expects the flat `{"decision","reason"}` shape, not Claude's `hookSpecificOutput` envelope.
|
|
9493
|
+
- **Stdin payload:** flat `{ "hook_event_name", "tool_name", "tool_input" }` — already handled by `_hook-io.sh` via its `.tool_name` / `.tool_input.*` branches, so no normalizer change was needed.
|
|
9494
|
+
- **Global bonus:** Devin CLI reads `~/.claude/settings.json` + `.claude/settings.json` hooks directly (`read_config_from.claude` default on, since CLI `2026.3.20-2`), so a global `ai-toolkit install` already covers Devin even without the project-local file.
|
|
9495
|
+
|
|
9471
9496
|
## Troubleshooting
|
|
9472
9497
|
|
|
9473
9498
|
**Hooks not loading:**
|
|
@@ -11770,9 +11795,9 @@ title: "Supported Tools Registry"
|
|
|
11770
11795
|
category: reference
|
|
11771
11796
|
service: ai-toolkit
|
|
11772
11797
|
tags: [editors, platforms, generators, integration, ecosystem]
|
|
11773
|
-
version: "1.
|
|
11798
|
+
version: "1.6.0"
|
|
11774
11799
|
created: "2026-04-23"
|
|
11775
|
-
last_updated: "2026-06-
|
|
11800
|
+
last_updated: "2026-06-10"
|
|
11776
11801
|
description: "Human-readable view of scripts/ecosystem_tools.json — the canonical list of tools ai-toolkit integrates with (Claude Code + 11 editors), their documentation URLs, config paths, our generators, and tracked capability markers."
|
|
11777
11802
|
---
|
|
11778
11803
|
|
|
@@ -11829,12 +11854,13 @@ The canonical data lives in **`scripts/ecosystem_tools.json`** and is consumed b
|
|
|
11829
11854
|
| Docs | https://docs.devin.ai/desktop (Windsurf rebranded to Devin Desktop ~2026-06-02; docs.windsurf.com resolves here) |
|
|
11830
11855
|
| Changelog | https://docs.devin.ai/desktop/changelog (windsurf.com/changelog 308-permanent-redirects here) |
|
|
11831
11856
|
| Stable docs mirror | https://docs.devin.ai/desktop/... per-page .md twins; legacy `.windsurf/`, `.windsurfrules`, `~/.codeium/windsurf/` paths still read as fallback (new canonical: `.devin/`) |
|
|
11832
|
-
| Config paths | **Primary (Devin Desktop):** `.devin/rules/*.md`, `.devin/workflows/*.md`, `.devin/skills/*/SKILL.md`, `.devin/config.json`, `.devin/config.local.json`, `~/.config/devin/config.json` (Devin Local MCP/permissions). **Legacy fallback:** `.windsurfrules`, `.windsurf/rules/*.md`, `.windsurf/workflows/*.md`, `.windsurf/skills/*/SKILL.md`, `~/.codeium/windsurf/memories/global_rules.md`, `~/.codeium/windsurf/skills/*/SKILL.md`, `~/.codeium/windsurf/mcp_config.json`. Plus `AGENTS.md`. |
|
|
11833
|
-
| Compat read paths | `.agents/skills/`, `~/.agents/skills/`, (with Claude Code config-reading) `.claude/skills/`, `~/.claude/skills
|
|
11834
|
-
| Our generators | `scripts/generate_windsurf.py`, `scripts/generate_windsurf_rules.py` (dual-emits `.devin/` + `.windsurf/`), `scripts/generate_windsurf_hooks.py` (profile=full; **Cascade-scoped, deprecated**), `scripts/generate_windsurf_skills.py` (global + profile=full pointer, dual-emits) |
|
|
11857
|
+
| Config paths | **Primary (Devin Desktop):** `.devin/rules/*.md`, `.devin/workflows/*.md`, `.devin/skills/*/SKILL.md`, `.devin/hooks.v1.json` (Devin CLI hooks, Claude format), `.devin/config.json`, `.devin/config.local.json`, `~/.config/devin/config.json` (Devin Local MCP/permissions). **Legacy fallback:** `.windsurfrules`, `.windsurf/rules/*.md`, `.windsurf/workflows/*.md`, `.windsurf/skills/*/SKILL.md`, `~/.codeium/windsurf/memories/global_rules.md`, `~/.codeium/windsurf/skills/*/SKILL.md`, `~/.codeium/windsurf/mcp_config.json`. Plus `AGENTS.md`. |
|
|
11858
|
+
| Compat read paths | skills: `.agents/skills/`, `~/.agents/skills/`, (with Claude Code config-reading) `.claude/skills/`, `~/.claude/skills/`. **Hooks: Devin CLI reads `.claude/settings.json` + `~/.claude/settings.json` hooks directly (`read_config_from.claude` default on), so globally-installed toolkit hooks work under Devin with no project-local file.** |
|
|
11859
|
+
| Our generators | `scripts/generate_windsurf.py`, `scripts/generate_windsurf_rules.py` (dual-emits `.devin/` + `.windsurf/`), `scripts/generate_windsurf_hooks.py` (profile=full; **Cascade-scoped, deprecated, drop after 2026-07-01**), `scripts/generate_devin_hooks.py` (profile=full; `.devin/hooks.v1.json`, Claude-format Devin CLI hooks), `scripts/generate_windsurf_skills.py` (global + profile=full pointer, dual-emits) |
|
|
11835
11860
|
| Tracked capabilities | Cascade, `windsurfrules`, `AGENTS.md`, activation triggers (`always_on`/`glob`/`model_decision`), workflows, skills, MCP, memories, hooks |
|
|
11836
11861
|
| Activation modes emitted | always_on (agents/security/quality), glob (testing + language rules), model_decision (code-style/workflow) |
|
|
11837
|
-
|
|
|
11862
|
+
| Hooks migration | **Done.** Cascade `.windsurf/hooks.json` (`agent_action_name`/`tool_info` format) dies 2026-07-01 with no Devin fallback. `generate_devin_hooks.py` emits `.devin/hooks.v1.json` in the Claude-compatible format Devin CLI uses: Claude-style events (PreToolUse/PostToolUse/UserPromptSubmit/Stop/SessionStart), matchers on Devin tool names (`read`/`edit`/`exec`/`mcp__*`), blocking via flat `{"decision":"block","reason":...}` + exit 2 (no `AI_TOOLKIT_HOOK_FORMAT=json` — Devin does not use Claude's `hookSpecificOutput` envelope). `post_setup_worktree`→`SessionStart`; `post_cascade_response`→`Stop` (no response text on stdin). Both hook generators run at profile=full during the transition; drop `generate_windsurf_hooks.py` in the first release after 2026-07-01. |
|
|
11863
|
+
| Sunset notes | Cascade agent is available only through **2026-07-01**; Devin Local is the default agent since 2026-06-02. Devin CLI ("Devin for Terminal") shares the Devin Local harness, reads `AGENTS.md`, the standard `SKILL.md` format, and Claude-format hooks; not yet a separate registry entry. |
|
|
11838
11864
|
|
|
11839
11865
|
### GitHub Copilot
|
|
11840
11866
|
|
package/manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@softspark/ai-toolkit",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.8.0",
|
|
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",
|
|
@@ -135,6 +135,7 @@
|
|
|
135
135
|
".devin/rules/*.md",
|
|
136
136
|
".devin/workflows/*.md",
|
|
137
137
|
".devin/skills/*/SKILL.md",
|
|
138
|
+
".devin/hooks.v1.json",
|
|
138
139
|
".devin/config.json",
|
|
139
140
|
".devin/config.local.json",
|
|
140
141
|
"~/.config/devin/config.json",
|
|
@@ -152,9 +153,10 @@
|
|
|
152
153
|
"scripts/generate_windsurf.py",
|
|
153
154
|
"scripts/generate_windsurf_rules.py",
|
|
154
155
|
"scripts/generate_windsurf_skills.py",
|
|
155
|
-
"scripts/generate_windsurf_hooks.py"
|
|
156
|
+
"scripts/generate_windsurf_hooks.py",
|
|
157
|
+
"scripts/generate_devin_hooks.py"
|
|
156
158
|
],
|
|
157
|
-
"status_note": "Windsurf rebranded to Devin Desktop on 2026-06-02. .devin/ is the primary read+write workspace tree; .windsurfrules, .windsurf/* and ~/.codeium/windsurf/* are legacy read-only fallbacks. Our generators dual-emit .devin/* + .windsurf/*. Cascade agent is available only through 2026-07-01 (Devin Local
|
|
159
|
+
"status_note": "Windsurf rebranded to Devin Desktop on 2026-06-02. .devin/ is the primary read+write workspace tree; .windsurfrules, .windsurf/* and ~/.codeium/windsurf/* are legacy read-only fallbacks. Our generators dual-emit .devin/* + .windsurf/*. HOOKS MIGRATION (done): Cascade agent is available only through 2026-07-01 (Devin Local default since 2026-06-02), and the Cascade-scoped .windsurf/hooks.json (generate_windsurf_hooks.py, agent_action_name/tool_info format) dies with it — Devin CLI/Local do NOT read it as a fallback. generate_devin_hooks.py now emits .devin/hooks.v1.json in the Claude-compatible hook format Devin CLI uses (docs.devin.ai/cli/extensibility/hooks): Claude-style events (PreToolUse/PostToolUse/UserPromptSubmit/Stop/SessionStart) with matchers on Devin tool names (read/edit/exec/mcp__*), flat {decision,reason} block contract + exit 2. Globally-installed users ALSO inherit ~/.claude/settings.json hooks automatically (Devin read_config_from.claude defaults on). Both hook generators run at profile=full; drop generate_windsurf_hooks.py in the first release after 2026-07-01. Devin CLI ('Devin for Terminal', launched 2026-04-29) shares the Devin Local harness, reads AGENTS.md and the same SKILL.md standard; not yet tracked as a separate registry entry.",
|
|
158
160
|
"capability_markers": [
|
|
159
161
|
"Cascade",
|
|
160
162
|
"windsurfrules",
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Generate ``.devin/hooks.v1.json`` for the Devin CLI (formerly Windsurf).
|
|
3
|
+
|
|
4
|
+
Devin CLI uses a hook format **compatible with Claude Code hooks**
|
|
5
|
+
(docs.devin.ai/cli/extensibility/hooks/overview). This generator is the
|
|
6
|
+
replacement for the deprecated Cascade ``.windsurf/hooks.json`` surface,
|
|
7
|
+
which stops working when Cascade sunsets on 2026-07-01. Devin Local / Devin
|
|
8
|
+
CLI do NOT read ``.windsurf/hooks.json`` as a fallback, so the hooks must be
|
|
9
|
+
regenerated onto this new file.
|
|
10
|
+
|
|
11
|
+
Output file: ``<target>/.devin/hooks.v1.json``. Per the Devin docs the
|
|
12
|
+
standalone ``hooks.v1.json`` file's entire contents ARE the hooks object —
|
|
13
|
+
there is **no** top-level ``"hooks"`` wrapper key (unlike
|
|
14
|
+
``.claude/settings.json`` or ``.devin/config.json``).
|
|
15
|
+
|
|
16
|
+
Events use Claude-style PascalCase names. Matchers are regexes against the
|
|
17
|
+
Devin **tool name** (``read``, ``edit``, ``exec``, ``grep``, ``glob``,
|
|
18
|
+
``mcp__<server>__<tool>``) — NOT Claude's ``Bash``/``Edit`` names — so the
|
|
19
|
+
shared guard scripts reliably fire under Devin.
|
|
20
|
+
|
|
21
|
+
Blocking contract: the shared guard scripts emit ``{"decision":"block",
|
|
22
|
+
"reason":...}`` on stdout (plain mode) AND exit 2 — Devin honors both (docs:
|
|
23
|
+
exit 2 = deny; JSON ``{"decision":"block"}`` = deny). Hooks therefore run
|
|
24
|
+
WITHOUT ``AI_TOOLKIT_HOOK_FORMAT=json`` because Devin expects the flat
|
|
25
|
+
``{"decision","reason"}`` shape, not Claude's ``hookSpecificOutput`` envelope.
|
|
26
|
+
|
|
27
|
+
Existing user hook entries are preserved; only entries tagged
|
|
28
|
+
``_source: ai-toolkit`` are replaced on regeneration.
|
|
29
|
+
|
|
30
|
+
Usage:
|
|
31
|
+
python3 scripts/generate_devin_hooks.py [target-dir]
|
|
32
|
+
"""
|
|
33
|
+
from __future__ import annotations
|
|
34
|
+
|
|
35
|
+
import json
|
|
36
|
+
import sys
|
|
37
|
+
from pathlib import Path
|
|
38
|
+
|
|
39
|
+
HOOKS_PREFIX = '"$HOME/.softspark/ai-toolkit/hooks/'
|
|
40
|
+
SOURCE_TAG = "ai-toolkit"
|
|
41
|
+
|
|
42
|
+
# event -> list of (matcher_regex, [script names]).
|
|
43
|
+
# Matchers target Devin tool names: read, edit, exec, mcp__<server>__<tool>.
|
|
44
|
+
# An empty matcher fires for every tool name (Devin: omitted/empty = match all).
|
|
45
|
+
DEVIN_HOOKS: dict[str, list[tuple[str, list[str]]]] = {
|
|
46
|
+
"PreToolUse": [
|
|
47
|
+
("^(read|edit)$", ["guard-path.sh"]),
|
|
48
|
+
("^edit$", ["guard-config.sh"]),
|
|
49
|
+
("^exec$", ["guard-destructive.sh", "commit-quality.sh", "revert-guard.sh"]),
|
|
50
|
+
("^mcp__", ["guard-config.sh"]),
|
|
51
|
+
],
|
|
52
|
+
"PostToolUse": [
|
|
53
|
+
("^edit$", ["post-tool-use.sh", "governance-capture.sh", "test-cohesion.sh"]),
|
|
54
|
+
("^exec$", ["governance-capture.sh"]),
|
|
55
|
+
("^mcp__.*__(smart_query|hybrid_search_kb|crag_search|multi_hop_search|verify_answer)$",
|
|
56
|
+
["search-tracker.sh"]),
|
|
57
|
+
],
|
|
58
|
+
"UserPromptSubmit": [
|
|
59
|
+
("", ["user-prompt-submit.sh", "track-usage.sh"]),
|
|
60
|
+
],
|
|
61
|
+
"Stop": [
|
|
62
|
+
("", ["quality-check.sh", "save-session.sh", "stop-search-check.sh"]),
|
|
63
|
+
],
|
|
64
|
+
# Cascade's post_setup_worktree has no Devin equivalent; session-context
|
|
65
|
+
# moves to SessionStart (Devin fires SessionStart when a session begins).
|
|
66
|
+
"SessionStart": [
|
|
67
|
+
("", ["session-context.sh"]),
|
|
68
|
+
],
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def build_hook_entry(matcher: str, scripts: list[str]) -> dict:
|
|
73
|
+
"""Build one Devin matcher-group: ``{matcher, hooks:[{type,command}]}``."""
|
|
74
|
+
return {
|
|
75
|
+
"_source": SOURCE_TAG,
|
|
76
|
+
"matcher": matcher,
|
|
77
|
+
"hooks": [
|
|
78
|
+
{"type": "command", "command": f'{HOOKS_PREFIX}{s}"'}
|
|
79
|
+
for s in scripts
|
|
80
|
+
],
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def build_toolkit_hooks() -> dict[str, list[dict]]:
|
|
85
|
+
return {
|
|
86
|
+
event: [build_hook_entry(matcher, scripts) for matcher, scripts in groups]
|
|
87
|
+
for event, groups in DEVIN_HOOKS.items()
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _is_toolkit_entry(entry: dict) -> bool:
|
|
92
|
+
return isinstance(entry, dict) and entry.get("_source") == SOURCE_TAG
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def strip_toolkit_hooks(hooks: dict) -> dict:
|
|
96
|
+
"""Drop ai-toolkit matcher-groups; keep user-authored entries."""
|
|
97
|
+
kept: dict = {}
|
|
98
|
+
for event, entries in hooks.items():
|
|
99
|
+
if not isinstance(entries, list):
|
|
100
|
+
kept[event] = entries
|
|
101
|
+
continue
|
|
102
|
+
survivors = [e for e in entries if not _is_toolkit_entry(e)]
|
|
103
|
+
if survivors:
|
|
104
|
+
kept[event] = survivors
|
|
105
|
+
return kept
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def merge_hooks(existing: dict, toolkit: dict) -> dict:
|
|
109
|
+
merged = strip_toolkit_hooks(existing)
|
|
110
|
+
for event, entries in toolkit.items():
|
|
111
|
+
merged.setdefault(event, []).extend(entries)
|
|
112
|
+
return merged
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def generate(target_dir: Path) -> Path:
|
|
116
|
+
devin_dir = target_dir / ".devin"
|
|
117
|
+
devin_dir.mkdir(parents=True, exist_ok=True)
|
|
118
|
+
path = devin_dir / "hooks.v1.json"
|
|
119
|
+
|
|
120
|
+
# The standalone hooks.v1.json file IS the hooks object (no wrapper key).
|
|
121
|
+
existing: dict = {}
|
|
122
|
+
if path.is_file():
|
|
123
|
+
try:
|
|
124
|
+
with open(path, encoding="utf-8") as f:
|
|
125
|
+
existing = json.load(f)
|
|
126
|
+
if not isinstance(existing, dict):
|
|
127
|
+
existing = {}
|
|
128
|
+
except (json.JSONDecodeError, OSError):
|
|
129
|
+
existing = {}
|
|
130
|
+
|
|
131
|
+
merged = merge_hooks(existing, build_toolkit_hooks())
|
|
132
|
+
|
|
133
|
+
with open(path, "w", encoding="utf-8") as f:
|
|
134
|
+
json.dump(merged, f, indent=4, ensure_ascii=False, sort_keys=True)
|
|
135
|
+
f.write("\n")
|
|
136
|
+
return path
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def main() -> None:
|
|
140
|
+
target = Path(sys.argv[1]) if len(sys.argv) > 1 else Path.cwd()
|
|
141
|
+
path = generate(target)
|
|
142
|
+
total = sum(len(scripts) for groups in DEVIN_HOOKS.values()
|
|
143
|
+
for _, scripts in groups)
|
|
144
|
+
rel = path.relative_to(target) if path.is_relative_to(target) else path
|
|
145
|
+
print(f"Generated: {rel} ({total} hooks across {len(DEVIN_HOOKS)} events)")
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
if __name__ == "__main__":
|
|
149
|
+
main()
|
|
@@ -748,7 +748,7 @@ def _install_local_dry_run(reset: bool, editors: list[str] | None = None,
|
|
|
748
748
|
if "cursor" in eds:
|
|
749
749
|
print(" Would generate: .cursor/hooks.json + .cursor/agents/ + .cursor/skills/ (profile=full)")
|
|
750
750
|
if "windsurf" in eds:
|
|
751
|
-
print(" Would generate: .windsurf/hooks.json + .devin/skills/ + .windsurf/skills/ (profile=full)")
|
|
751
|
+
print(" Would generate: .devin/hooks.v1.json + .windsurf/hooks.json (Cascade, deprecated) + .devin/skills/ + .windsurf/skills/ (profile=full)")
|
|
752
752
|
if "cline" in eds:
|
|
753
753
|
print(" Would generate: .cline/skills/ (profile=full)")
|
|
754
754
|
if "augment" in eds:
|
|
@@ -980,7 +980,10 @@ def _create_local_ai_tool_configs(cwd: Path, rules_dir: Path,
|
|
|
980
980
|
gen_windsurf_rules(cwd, language_modules=language_modules,
|
|
981
981
|
rules_dir=rules_dir)
|
|
982
982
|
if add_native_surfaces:
|
|
983
|
+
# .windsurf/hooks.json is Cascade-scoped and dies 2026-07-01;
|
|
984
|
+
# .devin/hooks.v1.json is the Devin CLI replacement (Claude format).
|
|
983
985
|
_try_generator("generate_windsurf_hooks", cwd)
|
|
986
|
+
_try_generator("generate_devin_hooks", cwd)
|
|
984
987
|
# Windsurf pointer stays unconditional (its .claude scan is gated).
|
|
985
988
|
_try_generator("generate_windsurf_skills", cwd)
|
|
986
989
|
|
package/scripts/validate.py
CHANGED
|
@@ -846,6 +846,9 @@ def _validate_version_sync(tk_dir: Path, vr: ValidationResult) -> None:
|
|
|
846
846
|
# generators come and go.
|
|
847
847
|
_NATIVE_HOOK_EDITORS = {"claude", "opencode"}
|
|
848
848
|
|
|
849
|
+
# generate_<stem>_hooks.py stems that belong to an existing README platform key.
|
|
850
|
+
_HOOK_STEM_ALIAS = {"devin": "windsurf"}
|
|
851
|
+
|
|
849
852
|
# README platform label (lowercased) -> canonical editor key.
|
|
850
853
|
_README_PLATFORM_KEY = {
|
|
851
854
|
"claude code": "claude",
|
|
@@ -877,10 +880,12 @@ def _validate_editor_hooks_honesty(tk_dir: Path, vr: ValidationResult) -> None:
|
|
|
877
880
|
return # installed copy without source — nothing to cross-check
|
|
878
881
|
|
|
879
882
|
# Actual hook-enabled editors: native set + generate_<editor>_hooks.py stems.
|
|
883
|
+
# Some stems map back to a README platform key (e.g. the Devin CLI hooks
|
|
884
|
+
# generator is part of the windsurf/Devin-Desktop integration).
|
|
880
885
|
actual = set(_NATIVE_HOOK_EDITORS)
|
|
881
886
|
for gen in scripts_dir.glob("generate_*_hooks.py"):
|
|
882
887
|
stem = gen.name[len("generate_"):-len("_hooks.py")]
|
|
883
|
-
actual.add(stem)
|
|
888
|
+
actual.add(_HOOK_STEM_ALIAS.get(stem, stem))
|
|
884
889
|
|
|
885
890
|
content = readme.read_text(encoding="utf-8")
|
|
886
891
|
if "| Hooks |" not in content:
|