@rune-kit/rune 2.28.0 → 2.29.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/.codex-plugin/plugin.json +14 -0
- package/README.md +114 -41
- package/compiler/__tests__/adapter-model-mapping.test.js +22 -24
- package/compiler/__tests__/adapters.test.js +4 -1
- package/compiler/__tests__/doctor-mesh.test.js +55 -1
- package/compiler/__tests__/governance-collector.test.js +1 -0
- package/compiler/__tests__/hooks-codex.test.js +85 -0
- package/compiler/__tests__/hooks-doctor-tier.test.js +3 -5
- package/compiler/__tests__/hooks-drift.test.js +2 -2
- package/compiler/__tests__/hooks-install.test.js +2 -2
- package/compiler/__tests__/hooks-tiers.test.js +3 -4
- package/compiler/__tests__/setup.test.js +59 -0
- package/compiler/__tests__/status.test.js +7 -1
- package/compiler/__tests__/tier-override.test.js +42 -1
- package/compiler/__tests__/transforms.test.js +15 -0
- package/compiler/__tests__/update.test.js +416 -0
- package/compiler/adapters/codex.js +88 -11
- package/compiler/adapters/hooks/codex.js +178 -0
- package/compiler/adapters/hooks/index.js +10 -0
- package/compiler/adapters/openclaw.js +2 -2
- package/compiler/bin/rune.js +24 -4
- package/compiler/commands/hooks/install.js +2 -2
- package/compiler/commands/hooks/status.js +1 -1
- package/compiler/commands/setup.js +101 -28
- package/compiler/commands/update.js +354 -0
- package/compiler/doctor.js +12 -6
- package/compiler/emitter.js +46 -3
- package/compiler/governance-collector.js +3 -2
- package/compiler/status.js +4 -7
- package/compiler/transforms/branding.js +2 -2
- package/compiler/transforms/subagents.js +3 -3
- package/hooks/codex-hooks.json +96 -0
- package/hooks/context-watch/index.cjs +8 -5
- package/hooks/intent-router/index.cjs +3 -0
- package/hooks/lib/hook-output.cjs +11 -3
- package/hooks/post-session-reflect/index.cjs +65 -24
- package/hooks/pre-compact/index.cjs +10 -4
- package/hooks/pre-tool-guard/index.cjs +38 -36
- package/hooks/run-hook +1 -1
- package/hooks/run-hook.cmd +1 -1
- package/hooks/secrets-scan/index.cjs +18 -2
- package/package.json +3 -2
- package/skills/browser-pilot/SKILL.md +1 -0
- package/skills/completion-gate/SKILL.md +5 -5
- package/skills/doc-processor/SKILL.md +2 -2
- package/skills/hallucination-guard/SKILL.md +1 -0
- package/skills/journal/SKILL.md +1 -0
- package/skills/retro/SKILL.md +2 -2
- package/skills/session-bridge/SKILL.md +1 -0
- package/skills/session-bridge/scripts/load-invariants.js +1 -1
- package/skills/video-creator/SKILL.md +1 -1
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "rune",
|
|
3
|
+
"version": "2.29.1",
|
|
4
|
+
"description": "66-skill engineering mesh with Codex-native skills, subagents, synchronous lifecycle hooks, security gates, MCP-aware workflows, and project memory.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Rune Contributors"
|
|
7
|
+
},
|
|
8
|
+
"repository": "https://github.com/rune-kit/rune",
|
|
9
|
+
"homepage": "https://rune-kit.github.io/rune",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"keywords": ["skills", "hooks", "subagents", "security", "coding-agent"],
|
|
12
|
+
"skills": "./skills/",
|
|
13
|
+
"hooks": "./hooks/codex-hooks.json"
|
|
14
|
+
}
|
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<p align="center">
|
|
6
6
|
<strong>Less skills. Deeper connections.</strong><br>
|
|
7
7
|
A lean, interconnected skill ecosystem for AI coding assistants.<br>
|
|
8
|
-
66 skills ·
|
|
8
|
+
66 skills · 248 connections · 45 signals · 13 platforms · MIT
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
|
|
24
24
|
Most skill ecosystems are either **too many isolated skills** (540+ that don't talk to each other) or **rigid pipelines** (A → B → C, if B fails everything stops).
|
|
25
25
|
|
|
26
|
-
Rune is a **mesh** — 66 skills with
|
|
26
|
+
Rune is a **mesh** — 66 skills with 248 connections + 45 signals across a 5-layer architecture. Every declared outbound call is acknowledged by its target, forming resilient workflows that adapt when things go wrong.
|
|
27
27
|
|
|
28
28
|
```
|
|
29
29
|
Pipeline: A → B → C → D (B fails = stuck)
|
|
@@ -89,10 +89,10 @@ _Methodology: Claude Code CLI headless mode (`claude -p --output-format json`),
|
|
|
89
89
|
<a href="https://github.com/rune-kit/rune-pro"><img src="assets/pro-upgrade.svg" alt="Rune Pro — Autopilot + Context Intelligence · $49 lifetime" width="100%"></a>
|
|
90
90
|
</p>
|
|
91
91
|
|
|
92
|
-
Free gives
|
|
92
|
+
Free gives the agent discipline. **Pro** adds two capabilities the free tier does not:
|
|
93
93
|
|
|
94
94
|
- **Autopilot** — approve a plan once and walk away. It executes each phase autonomously (self-reviews with zero-HIGH gates, regression-checks against baselines, commits per phase) and **resumes across sessions**. `cook` gets the job done; `autopilot` gets it done while you sleep.
|
|
95
|
-
- **Context Intelligence** — a live **context cockpit**
|
|
95
|
+
- **Context Intelligence** — a live **context cockpit** with real %, active mesh layer, cost, and predictive compaction timing. Claude Code hosts the executable statusline natively; Codex uses its built-in footer plus the full Pro watcher/HUD. Hooks save decisions and progress to `.rune/` before compaction.
|
|
96
96
|
|
|
97
97
|
Plus **9 domain packs** (product, sales, data-science, support, growth, media, personal-brand, ecommerce, vietnam). **$49 lifetime, one-time — no subscription.**
|
|
98
98
|
|
|
@@ -103,11 +103,19 @@ Plus **9 domain packs** (product, sales, data-science, support, growth, media, p
|
|
|
103
103
|
|
|
104
104
|
---
|
|
105
105
|
|
|
106
|
-
## What's New (v2.
|
|
106
|
+
## What's New (v2.29.1 — One-Command Update)
|
|
107
|
+
|
|
108
|
+
> **v2.29.1 (2026-07-24):** v2.29.0 documented the update flow; this release automates it. New **`rune update`** command — one-shot updater for an already-configured project: `git pull --ff-only` any detected Pro/Business tier repos (env var → sibling dir, same detection as setup; a failed pull **aborts loudly**, never a silent half-update), re-runs the managed setup rewrite in place non-interactively (your installed platforms, preset, and tiers are detected from the existing hook config — no prompts), then verifies with doctor + hook drift and reminds Codex users to re-trust `/hooks` only when `.codex/hooks.json` actually changed. Flags: `--no-pull`, `--preset`, `--tier`, `--dry`. Plus: "Updating" sections in all three tier READMEs. Docs-and-CLI patch — no skill or mesh changes. 1,638 tests.
|
|
109
|
+
|
|
110
|
+
### Previous (v2.29.0 — Codex Native)
|
|
111
|
+
|
|
112
|
+
> **v2.29.0 (2026-07-23):** Codex stops being a compile target that happens to work and becomes a **first-class native runtime**. The Codex adapter now emits everything current Codex supports natively — `.agents/skills/`, project-scoped agent TOML (`.codex/agents/rune-{heavy,standard,fast}.toml`), a dedicated synchronous hook adapter targeting `.codex/hooks.json` (Codex silently skips async handlers), MCP config, and tier-aware compilation so Free/Pro/Business stacks resolve exactly as on Claude Code. The mesh validator was fixed at the root — `Calls (outbound)` is now the single authoritative edge inventory, acknowledged by the target's `Called By` — moving the canonical count from 209 to **248 connections** (same mesh, honest count; doctor now fails CI on any stale claim). Doctor also grew a cross-tier audit: Business metadata (28 pack skills, 4 orchestrators), $149 pricing, 13-platform count, and JSON-schema validation of the new `docs/config-schema.json` + hooks manifest schema. All XLabs remote-MCP references now go through `XLABS_MCP_TOKEN` — plaintext bearer values are forbidden. 1,615 tests pass.
|
|
113
|
+
|
|
114
|
+
#### Earlier (v2.28.0 — Reasoner's Blind Spots)
|
|
107
115
|
|
|
108
116
|
> **v2.28.0 (2026-07-22):** Completes the reasoning wave. Every addition targets one failure class: **a check that feels done because the model re-read its own work and agreed with itself.** `problem-solver` (v0.6.0) gains a **model failure-mode table** beside its human-bias table — pattern-match satisfaction, template hijack, fluent≠true, prior-as-fact, completion pressure, surface blindness — plus three tells that you are inside one right now (instant confident answer; a stated detail your draft never used; two failed attempts in the same framing). `verification` (v0.8.0) gains the **Constraint Loop** for deliverables carrying a mechanically checkable constraint on their own surface form (banned characters, exact counts, strict formats) — a class Rune had no coverage for: expand the constraint before drafting, verify with a tool, re-scan the whole artifact, ship byte-for-byte. `design` (v0.9.0) gains **render blindness** — a checklist item ticked from source is a prediction, and the imagined render is always flattering; visual items are marked 👁 and are ticked from a render or marked ASSUMED. Advisory throughout, no new skills.
|
|
109
117
|
|
|
110
|
-
|
|
118
|
+
#### Earlier (v2.27.0 — Calibrated Output)
|
|
111
119
|
|
|
112
120
|
> **v2.27.0 (2026-07-22):** Rune had one opinion about response shape — `caveman`, optimising token count — and no rule for what a style may **not** compress. That gap had teeth: caveman's "hedging dies" list auto-activates at ORANGE/RED context and deleted phrases like *"I'm assuming the migration ran"*, promoting an unverified claim into observed grammar at exactly the point in a session where the agent is most likely to be wrong. New **output-mode layer** (`context-engine`) holds every mode behind one activation contract and a five-rule precedence list — **shape is negotiable, substance is not**: calibration > evidence > a skill's `## Output Format` > safety > actionability > economy. New **`actionable` mode** optimises distance-to-doing (next action first, steps numbered, position restated each turn) and stacks with caveman. New **claim discipline** in `completion-gate` types every load-bearing statement OBSERVED / DERIVED / PRIOR / ASSUMED — *hallucination is an unverified claim wearing the grammar of an observation* — and adds a `DECLARED` verdict so an honest hedge is recorded as an open item, never scored as a lie.
|
|
113
121
|
|
|
@@ -117,7 +125,7 @@ Plus **9 domain packs** (product, sales, data-science, support, growth, media, p
|
|
|
117
125
|
|
|
118
126
|
#### Earlier (v2.26.1 — Codex Wiring)
|
|
119
127
|
|
|
120
|
-
> **v2.26.1 (2026-07-22):** Rune's runtime hooks were silently inert on **Codex CLI**. `hooks/hooks.json` is loaded by both Claude Code and Codex — Codex reads `<plugin>/hooks/hooks.json`, the same path, and maps the event names — but every tool matcher named only Claude's tools. Codex has no `Read`, `Write`, `Edit` or `Bash` tool; it issues `shell_command`, `exec`, `apply_patch`, `view_image`, `spawn_agent`. So the privacy gate and the secret scanner matched nothing and never fired. Matchers now name both platforms' tools (plain alternation — Claude behaviour is byte-for-byte unchanged), and `pre-tool-guard` reads the target path out of a Codex `apply_patch` payload (`*** Update File: <path>`), which is what makes it an actual gate there instead of a no-op.
|
|
128
|
+
> **v2.26.1 (2026-07-22):** Rune's runtime hooks were silently inert on **Codex CLI**. `hooks/hooks.json` is loaded by both Claude Code and Codex — Codex reads `<plugin>/hooks/hooks.json`, the same path, and maps the event names — but every tool matcher named only Claude's tools. Codex has no `Read`, `Write`, `Edit` or `Bash` tool; it issues `shell_command`, `exec`, `apply_patch`, `view_image`, `spawn_agent`. So the privacy gate and the secret scanner matched nothing and never fired. Matchers now name both platforms' tools (plain alternation — Claude behaviour is byte-for-byte unchanged), and `pre-tool-guard` reads the target path out of a Codex `apply_patch` payload (`*** Update File: <path>`), which is what makes it an actual gate there instead of a no-op. Codex skips `async` hooks; current releases therefore ship a separate synchronous `hooks/codex-hooks.json` through the native Codex plugin manifest.
|
|
121
129
|
|
|
122
130
|
#### Earlier (v2.26.0 — Motion Craft)
|
|
123
131
|
|
|
@@ -129,7 +137,7 @@ Plus **9 domain packs** (product, sales, data-science, support, growth, media, p
|
|
|
129
137
|
|
|
130
138
|
### Previous (v2.24.0 — Market Refresh)
|
|
131
139
|
|
|
132
|
-
> **v2.24.0 (2026-07-11):** Model lineup + platform adapters refreshed to the mid-2026 landscape. Claude tiers across the mesh → **Opus 4.8 / Sonnet 5 / Haiku 4.5**; the **Codex** adapter
|
|
140
|
+
> **v2.24.0 (2026-07-11):** Model lineup + platform adapters refreshed to the mid-2026 landscape. Claude tiers across the mesh → **Opus 4.8 / Sonnet 5 / Haiku 4.5**; the **Codex** adapter initially targeted GPT-5.6 `sol` / `terra` / `luna`. Current releases use `sol` plus `terra` at different reasoning efforts because `luna` is not a valid current Codex model. **Fable 5** is positioned as an API-only frontier **oracle** target rather than a routing tier (opus stays the ceiling). **Windsurf → Devin Desktop** rebrand documented (emission kept on `.windsurf/`, which Devin still reads). New **goal-first advisory** in `plan`/`ba` to leverage native `/goal` + Managed Agents Outcomes. CI 1572/1572.
|
|
133
141
|
|
|
134
142
|
> **v2.23.0 (2026-07-04):** Seven platform adapters move to the **Agent Skills open standard** (dir-per-skill `SKILL.md`, discovered and lazy-loaded by each platform's native loader). The headline fix: **Codex** dropped `.codex/skills/` from its scan list, so compiled skills were only findable via the AGENTS.md pointer — agents kept "re-finding" the path mid-session. Codex now emits to **`.agents/skills/`** (scanned CWD → repo root). Same treatment across the fleet: **cursor** `.cursor/rules/*.mdc` → `.cursor/skills/` (Cursor 2.4+ Skills, on-demand instead of always-on), **windsurf** → `.windsurf/skills/` (Cascade Skills), **copilot** → `.github/skills/`, **qoder** → `.qoder/skills/`, and **gemini/qwen** drop their all-skills-always-on context bombs (GEMINI.md bundle, QWEN.md `@import` wall) for native `.gemini/skills/` / `.qwen/skills/` + slim pointer files — a big context-window win on those platforms. Runtime hooks intentionally stay on `.cursor/rules` / `.windsurf/rules` (always-on is correct for hook context). Also fixes a YAML double-escaping bug that corrupted compiled frontmatter for skills with quoted descriptions on 6 platforms, and a duplicate `scripts/` copy in dir-per-skill builds. If you previously built for Codex/Cursor/Windsurf/Copilot/Gemini/Qwen/Qoder: re-run `npx @rune-kit/rune build` and delete the old output dirs. CI 1571/1571.
|
|
135
143
|
|
|
@@ -184,7 +192,7 @@ Plus **9 domain packs** (product, sales, data-science, support, growth, media, p
|
|
|
184
192
|
- **`adversary` v0.2.0 — Mode: oracle** — when `agent.stuck` fires from `debug` (3 disproved hypotheses) or `fix` (2+ failed attempts), oracle-mode dispatches a stateless second-model pass with explicit "no prior context" framing. Bundle format is regex-validated (`[SYSTEM]` invariant role-priming + `[USER]` template + `### File N`), token-capped (100k bundle, 4k per file, 12 files max), citation-required reply contract. Secrets auto-redacted. Breaks the confirmation-bias loop that scout's zoom-out (structural pivot) cannot.
|
|
185
193
|
- **`session-bridge` v0.8.0 — Detach Mode** — async escalation primitive. Heavy-model second-opinion calls (1-10 min wall time) no longer block the primary agent. `.rune/oracle-pending/<sessionId>.json` is the rendezvous file; idempotent dispatch (bundleHash-keyed); 10min default timeout; 24h orphan cleanup on session start. `cook` Phase 4 and `team` Phase 3 reattach via filesystem poll between adjacent tasks.
|
|
186
194
|
- **`context-engine` v1.1.0 — Mode: preview** — pre-flight cost gate. Caller emits `context.preview` BEFORE bundle build with file list + estimated tokens (chars × 0.25). Per-caller thresholds: adversary 50k/100k, team 30k/80k (per worker), review 40k/100k, audit 60k/120k. Action enum `proceed | warn | block`. Override via `RUNE_CONTEXT_THRESHOLDS_<CALLER>`. Stops `team` parallel workstreams from silently blowing $20 of Opus tokens.
|
|
187
|
-
- **Cross-provider model mapping** — 5 non-Anthropic adapters now translate `model: opus|sonnet|haiku` to provider-correct names. **codex** → gpt-5.6-sol / gpt-5.6-terra / gpt-5.6-
|
|
195
|
+
- **Cross-provider model mapping** — 5 non-Anthropic adapters now translate `model: opus|sonnet|haiku` to provider-correct names. **codex** → gpt-5.6-sol / gpt-5.6-terra / gpt-5.6-terra. **antigravity** → gemini-3-pro / gemini-3-flash / gemini-3-flash-lite. **opencode / openclaw / generic** → tier:heavy / tier:mid / tier:light (provider-agnostic). claude / cursor / windsurf remain no-op (Anthropic backend understands native names).
|
|
188
196
|
- **Routing clarity sweep** — all 63 SKILL.md descriptions now double-quoted (YAML safety). 13 ambiguous-name skills got explicit "Use when…" routing hints so skill-router doesn't have to guess: ba, completion-gate, constraint-check, doc-processor, integrity-check, logic-guardian, onboard, preflight, sentinel-env, watchdog, worktree, hallucination-guard, mcp-builder.
|
|
189
197
|
- **4 new mesh signals** — `oracle.dispatched`, `oracle.response`, `oracle.failed`, `context.preview`. All registered in Signal Catalog with full emit/listen mapping. `agent.stuck` listeners updated to include adversary in addition to scout.
|
|
190
198
|
- **1,331 tests** — +71 from v2.14.0 across 5 new test files: adapter-model-mapping (18), oracle-bundle-format (19), oracle-pending-schema (16), context-preview-signal (13), skill-description-quality (5).
|
|
@@ -275,19 +283,24 @@ cook ───emit:phase.complete────→ session-bridge
|
|
|
275
283
|
|
|
276
284
|
Rune started as a **Claude Code plugin** and now compiles to **every major AI IDE**. Same 66 skills, same mesh connections, same workflows — zero knowledge loss across platforms.
|
|
277
285
|
|
|
278
|
-
|
|
286
|
+
OpenAI Codex is now a first-class native runtime too: Rune ships
|
|
287
|
+
`.codex-plugin/plugin.json`, synchronous Codex lifecycle hooks, project-scoped
|
|
288
|
+
`.codex/agents/*.toml` roles, and `.agents/skills/` output. Codex hook trust is
|
|
289
|
+
still explicit; review newly installed definitions with `/hooks`.
|
|
290
|
+
|
|
291
|
+
| | Rune Provides | Agent Runtime Provides |
|
|
279
292
|
|---|---|---|
|
|
280
|
-
| **Workflows** | 8-phase TDD cycle (cook), parallel DAG execution (team), rescue pipelines |
|
|
293
|
+
| **Workflows** | 8-phase TDD cycle (cook), parallel DAG execution (team), rescue pipelines | Tool calling |
|
|
281
294
|
| **Quality Gates** | preflight + sentinel + review + completion-gate (parallel) | None built-in |
|
|
282
295
|
| **Domain Knowledge** | 14 extension packs (trading, SaaS, mobile, etc.) | General-purpose |
|
|
283
296
|
| **Cross-Session State** | .rune/ directory (decisions, conventions, progress) | Conversation only |
|
|
284
|
-
| **Mesh Resilience** |
|
|
285
|
-
| **Cost Optimization** |
|
|
297
|
+
| **Mesh Resilience** | 248 skill connections + 45 mesh signals, fail-loud-route-around | Runtime execution |
|
|
298
|
+
| **Cost Optimization** | Model-role hints and task routing | Available models |
|
|
286
299
|
| | | |
|
|
287
|
-
| **Sandbox & Permissions** | — |
|
|
288
|
-
| **Agent Spawning** |
|
|
289
|
-
| **MCP Integration** |
|
|
290
|
-
| **File System Access** | — |
|
|
300
|
+
| **Sandbox & Permissions** | — | The runtime handles this |
|
|
301
|
+
| **Agent Spawning** | Orchestration policy | Claude Task/Agent, Codex `spawn_agent`, or runtime equivalent |
|
|
302
|
+
| **MCP Integration** | Connector workflows | The runtime's MCP client |
|
|
303
|
+
| **File System Access** | — | The runtime's permissions |
|
|
291
304
|
|
|
292
305
|
### Common Misconceptions
|
|
293
306
|
|
|
@@ -297,14 +310,14 @@ Rune started as a **Claude Code plugin** and now compiles to **every major AI ID
|
|
|
297
310
|
| CI quality gates | `verification` skill: lint + typecheck + tests + build (actual commands, not LLM review) |
|
|
298
311
|
| Memory / state | `session-bridge` + `journal`: cross-session decisions, conventions, ADRs, module health |
|
|
299
312
|
| Multi-model strategy | Every skill has assigned model: haiku (scan), sonnet (code), opus (architecture) |
|
|
300
|
-
| Agent specialization |
|
|
313
|
+
| Agent specialization | 66 specialized skills plus native role definitions; Claude uses Task/Agent and Codex uses `spawn_agent` collaboration primitives |
|
|
301
314
|
| Security scanning | `sentinel`: OWASP patterns, secret scanning, dependency audit. `sast`: static analysis |
|
|
302
315
|
|
|
303
316
|
## Install
|
|
304
317
|
|
|
305
318
|
### One-Command Setup (recommended)
|
|
306
319
|
|
|
307
|
-
After installing
|
|
320
|
+
After installing Rune, run the wizard once to wire native hooks and platform-compiled skills — pick scope, runtime, and tiers:
|
|
308
321
|
|
|
309
322
|
```bash
|
|
310
323
|
npx @rune-kit/rune setup
|
|
@@ -332,13 +345,13 @@ Preset [g/s] (default g): g
|
|
|
332
345
|
Verify: rune doctor --hooks
|
|
333
346
|
```
|
|
334
347
|
|
|
335
|
-
**What does the wizard do?** It
|
|
348
|
+
**What does the wizard do?** It installs Rune-managed lifecycle hooks in the selected runtime's native configuration and installs tier skills in that runtime's native skill directory. For Claude this is `.claude/settings.json`; for Codex it is `.codex/hooks.json` plus `.agents/skills/`. With `--tier pro`, it also wires `loop-circuit-breaker` (auto-engages only in autopilot sessions).
|
|
336
349
|
|
|
337
350
|
**Non-interactive mode** (CI / scripted):
|
|
338
351
|
|
|
339
352
|
```bash
|
|
340
|
-
npx @rune-kit/rune setup --here --preset gentle --tier pro
|
|
341
|
-
npx @rune-kit/rune setup --
|
|
353
|
+
npx @rune-kit/rune setup --here --platform codex --preset gentle --tier pro
|
|
354
|
+
npx @rune-kit/rune setup --here --platform all --preset strict --tier pro,business
|
|
342
355
|
npx @rune-kit/rune setup --here --no-tier --dry # preview without writing
|
|
343
356
|
```
|
|
344
357
|
|
|
@@ -353,6 +366,20 @@ Or add manually in `~/.claude/settings.json` under `installed_plugins`.
|
|
|
353
366
|
|
|
354
367
|
Full mesh: subagents, hooks, adaptive routing, mesh analytics. **Run `npx @rune-kit/rune setup` afterward to wire hooks** (see One-Command Setup above).
|
|
355
368
|
|
|
369
|
+
### OpenAI Codex (Native Plugin)
|
|
370
|
+
|
|
371
|
+
```bash
|
|
372
|
+
# From the project that should receive Rune
|
|
373
|
+
npx @rune-kit/rune setup --here --platform codex
|
|
374
|
+
|
|
375
|
+
# Paid tiers are compiled through the Codex adapter too
|
|
376
|
+
npx @rune-kit/rune setup --here --platform codex --tier pro,business
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
Rune emits `.agents/skills/`, project-scoped `.codex/agents/rune-{heavy,standard,fast}.toml`,
|
|
380
|
+
a managed `AGENTS.md` block, and synchronous `.codex/hooks.json` definitions. Review and
|
|
381
|
+
trust newly installed hooks with `/hooks`.
|
|
382
|
+
|
|
356
383
|
### Cursor / Windsurf / Antigravity / Any IDE
|
|
357
384
|
|
|
358
385
|
```bash
|
|
@@ -369,18 +396,59 @@ This compiles all 66 skills into your IDE's rules format. Same knowledge, same w
|
|
|
369
396
|
|
|
370
397
|
### Platform Comparison
|
|
371
398
|
|
|
372
|
-
| Feature | Claude Code |
|
|
373
|
-
|
|
374
|
-
| Skills available | 66/66 | 66/66 |
|
|
375
|
-
| Mesh connections |
|
|
376
|
-
| Workflows & HARD-GATEs | Full | Full |
|
|
377
|
-
| Extension packs | 14 | 14 |
|
|
378
|
-
| Subagent parallelism | Native | Sequential fallback |
|
|
379
|
-
| Lifecycle hooks |
|
|
380
|
-
|
|
|
381
|
-
| Mesh analytics |
|
|
399
|
+
| Feature | Claude Code | OpenAI Codex | Other compiled targets |
|
|
400
|
+
|---------|-------------|--------------|------------------------|
|
|
401
|
+
| Skills available | 66/66 | 66/66 | 66/66 |
|
|
402
|
+
| Mesh connections | 248 + 45 signals | 248 + 45 signals | 248 + 45 signals as native rules/skills |
|
|
403
|
+
| Workflows & HARD-GATEs | Full | Full | Full knowledge, runtime-dependent enforcement |
|
|
404
|
+
| Extension packs | 14 | 14 | 14 |
|
|
405
|
+
| Subagent parallelism | Native Task/Agent | Native `spawn_agent` | Sequential fallback unless supported |
|
|
406
|
+
| Lifecycle hooks | Native executable hooks | Native synchronous hooks | Native where supported; inline constraints otherwise |
|
|
407
|
+
| Role/model routing | Claude model roles | Project-scoped Codex agent roles | Adapter-specific |
|
|
408
|
+
| Mesh analytics | Runtime metrics | Runtime metrics | Adapter-dependent |
|
|
409
|
+
|
|
410
|
+
**Same mesh, platform-native delivery.** Claude Code and Codex receive native agents and
|
|
411
|
+
lifecycle hooks; the remaining adapters preserve the workflows and constraints in the best
|
|
412
|
+
format each runtime supports.
|
|
413
|
+
|
|
414
|
+
## Updating
|
|
415
|
+
|
|
416
|
+
New releases are announced on [Telegram](https://t.me/xlabs_updates) and [GitHub Releases](https://github.com/rune-kit/rune/releases); see [`CHANGELOG.md`](CHANGELOG.md) for what changed.
|
|
417
|
+
|
|
418
|
+
> **One-liner alternative**: `npx @rune-kit/rune@latest update` runs the whole flow below for an already-configured project — git-pulls detected Pro/Business repos, re-runs the managed setup rewrite in place (reusing your installed platforms/preset/tiers), and verifies with doctor. The platform-specific commands below remain the canonical path.
|
|
419
|
+
|
|
420
|
+
### Claude Code (plugin)
|
|
421
|
+
|
|
422
|
+
```bash
|
|
423
|
+
claude plugin update rune
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
Restart Claude Code to load the new version, then re-run the wizard once so hooks and tier skills match the new release:
|
|
427
|
+
|
|
428
|
+
```bash
|
|
429
|
+
npx @rune-kit/rune@latest setup
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
### Codex / Cursor / Windsurf / other compiled platforms
|
|
433
|
+
|
|
434
|
+
Re-running setup with `@latest` fetches the newest compiler and rewrites everything Rune manages **in place** — it is idempotent, and never touches your own config or the human-authored parts of `AGENTS.md`:
|
|
435
|
+
|
|
436
|
+
```bash
|
|
437
|
+
# same flags you installed with, e.g.:
|
|
438
|
+
npx @rune-kit/rune@latest setup --here
|
|
439
|
+
npx @rune-kit/rune@latest setup --here --platform codex --tier pro
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
If you use the build pipeline (`rune init` route) instead of the wizard: `npx @rune-kit/rune@latest init --force` regenerates platform files without touching your `.rune/` state.
|
|
443
|
+
|
|
444
|
+
### Verify after updating
|
|
445
|
+
|
|
446
|
+
```bash
|
|
447
|
+
npx @rune-kit/rune@latest doctor # compiled output + mesh integrity
|
|
448
|
+
npx @rune-kit/rune@latest doctor --hooks # hook drift vs the canonical preset
|
|
449
|
+
```
|
|
382
450
|
|
|
383
|
-
|
|
451
|
+
On Codex, review and re-trust changed hooks with `/hooks`.
|
|
384
452
|
|
|
385
453
|
## Quick Start
|
|
386
454
|
|
|
@@ -639,15 +707,18 @@ Domain-specific skills that plug into the core mesh:
|
|
|
639
707
|
|
|
640
708
|
### Rune Pro — $49 lifetime
|
|
641
709
|
|
|
642
|
-
> *Free Rune makes
|
|
710
|
+
> *Free Rune makes the agent disciplined. Pro makes the workflow context-aware.*
|
|
643
711
|
|
|
644
|
-
**Context Intelligence** — the headline Pro feature. Claude Code
|
|
712
|
+
**Context Intelligence** — the headline Pro feature. On Claude Code, Pulse runs as an
|
|
713
|
+
executable native statusline. Codex CLI's built-in `[tui].status_line` supports its own footer
|
|
714
|
+
items but does not execute an arbitrary statusline command, so full Rune Pulse runs as the
|
|
715
|
+
Pro external watcher/HUD while Rune's hooks preserve context before compaction.
|
|
645
716
|
|
|
646
717
|
```
|
|
647
718
|
◈ Opus 4.8 │ ████████░░░ 73% WARM │ ⬡ cook·L1 │ $0.91 │ 5h ██░░ 22% 7d ███░ 61%
|
|
648
719
|
```
|
|
649
720
|
|
|
650
|
-
Three things a blind meter can't do: a **glitch-proof %** (no phantom 0%, no false "100% URGENT" during light work), a **burn-rate ETA** (*"~4m until auto-compaction"*), and **what's eating your context** (*"files 61% · mcp 22%"* → trim the biggest, don't nuke blind). At 70/80/90% real, `context-inject` writes
|
|
721
|
+
Three things a blind meter can't do: a **glitch-proof %** (no phantom 0%, no false "100% URGENT" during light work), a **burn-rate ETA** (*"~4m until auto-compaction"*), and **what's eating your context** (*"files 61% · mcp 22%"* → trim the biggest, don't nuke blind). At 70/80/90% real, `context-inject` writes pressure into the active agent context → it triggers `session-bridge` + `neural-memory`; after compaction, `session-start` reloads `.rune/`.
|
|
651
722
|
|
|
652
723
|
Free ships the blind tool-call counter; the real-% cockpit + predictive intelligence is Pro.
|
|
653
724
|
|
|
@@ -684,7 +755,9 @@ Business packs don't just add skills — they **wire departments together**. Fin
|
|
|
684
755
|
| **HR** | JD generation, resume screening, structured interviews, comp benchmarking, onboarding workflows |
|
|
685
756
|
| **Enterprise Search** | Cross-system knowledge retrieval with permission-aware filtering and knowledge graph |
|
|
686
757
|
|
|
687
|
-
4 packs,
|
|
758
|
+
4 packs, 28 pack skills, 124 reference files, 12 tracked automation scripts, plus 4
|
|
759
|
+
cross-department orchestrators. Business includes all Pro features because it depends on Pro
|
|
760
|
+
data — finance can't forecast without sales pipeline, legal can't audit without product specs.
|
|
688
761
|
|
|
689
762
|
**[Get Rune Business](https://rune-kit.github.io/rune#pricing)** — [rune-kit/rune-business](https://github.com/rune-kit/rune-business)
|
|
690
763
|
|
|
@@ -741,12 +814,12 @@ See [docs/MULTI-PLATFORM.md](docs/MULTI-PLATFORM.md) for the full architecture.
|
|
|
741
814
|
```
|
|
742
815
|
Core Skills: 66 (L0: 1 │ L1: 5 │ L2: 30 │ L3: 30)
|
|
743
816
|
Extension Packs: 14 free + 9 pro + 4 business
|
|
744
|
-
Mesh Connections:
|
|
817
|
+
Mesh Connections: 248 sync calls (rune status --json)
|
|
745
818
|
Mesh Signals: 45 signals · 55 emit/listen edges (rune doctor)
|
|
746
819
|
Connections/Skill: 3.2 avg
|
|
747
|
-
Platforms:
|
|
748
|
-
Compiler:
|
|
749
|
-
Tests: 1,
|
|
820
|
+
Platforms: 13 (Claude, Cursor, Windsurf, Antigravity, Generic, OpenClaw, Codex, OpenCode, Aider, Copilot, Gemini, Qoder, Qwen)
|
|
821
|
+
Compiler: 13 adapters plus parser, transforms, hooks, and CLI
|
|
822
|
+
Tests: 1,600+ (compiler + signals + status + visualizer + hooks + scripts + tier-hooks)
|
|
750
823
|
Pack Depth: 27 packs total (14 free + 9 pro + 4 business, all free packs rated Deep)
|
|
751
824
|
```
|
|
752
825
|
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* Anthropic-backed adapters (claude/cursor/windsurf) remain no-op.
|
|
5
5
|
*
|
|
6
6
|
* Validates:
|
|
7
|
-
* -
|
|
7
|
+
* - Codex keeps SKILL.md frontmatter portable and emits model choices via custom agents
|
|
8
|
+
* - antigravity emits concrete provider model names
|
|
8
9
|
* - opencode/openclaw/generic emit semantic tier hints (provider-agnostic)
|
|
9
10
|
* - claude/cursor/windsurf do NOT translate (no-op)
|
|
10
11
|
* - Skills without `model:` produce no model line
|
|
@@ -25,29 +26,26 @@ const baseSkill = {
|
|
|
25
26
|
describe('codex adapter model mapping', () => {
|
|
26
27
|
const codex = getAdapter('codex');
|
|
27
28
|
|
|
28
|
-
test('
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
test('sonnet translates to gpt-5.6-terra', () => {
|
|
34
|
-
const header = codex.generateHeader({ ...baseSkill, model: 'sonnet' });
|
|
35
|
-
assert.match(header, /model: gpt-5\.6-terra/);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
test('haiku translates to gpt-5.6-luna', () => {
|
|
39
|
-
const header = codex.generateHeader({ ...baseSkill, model: 'haiku' });
|
|
40
|
-
assert.match(header, /model: gpt-5\.6-luna/);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
test('omitted model produces no model line', () => {
|
|
44
|
-
const header = codex.generateHeader({ ...baseSkill });
|
|
45
|
-
assert.doesNotMatch(header, /model:/);
|
|
29
|
+
test('SKILL.md frontmatter omits unsupported per-skill model fields', () => {
|
|
30
|
+
for (const model of ['opus', 'sonnet', 'haiku', 'custom-fine-tune', undefined]) {
|
|
31
|
+
const header = codex.generateHeader({ ...baseSkill, model });
|
|
32
|
+
assert.doesNotMatch(header, /^model:/m);
|
|
33
|
+
}
|
|
46
34
|
});
|
|
47
35
|
|
|
48
|
-
test('
|
|
49
|
-
const
|
|
50
|
-
|
|
36
|
+
test('project-scoped custom agents carry provider model and effort settings', async () => {
|
|
37
|
+
const extras = await codex.generateExtraFiles({
|
|
38
|
+
stats: { skillCount: 65, crossRefsResolved: 204, packCount: 14, files: [] },
|
|
39
|
+
});
|
|
40
|
+
const heavy = extras.find((entry) => entry.path === '.codex/agents/rune-heavy.toml');
|
|
41
|
+
const standard = extras.find((entry) => entry.path === '.codex/agents/rune-standard.toml');
|
|
42
|
+
const fast = extras.find((entry) => entry.path === '.codex/agents/rune-fast.toml');
|
|
43
|
+
assert.match(heavy.content, /model = "gpt-5\.6-sol"/);
|
|
44
|
+
assert.match(heavy.content, /model_reasoning_effort = "high"/);
|
|
45
|
+
assert.match(standard.content, /model = "gpt-5\.6-terra"/);
|
|
46
|
+
assert.match(standard.content, /model_reasoning_effort = "medium"/);
|
|
47
|
+
assert.match(fast.content, /model = "gpt-5\.6-terra"/);
|
|
48
|
+
assert.match(fast.content, /model_reasoning_effort = "low"/);
|
|
51
49
|
});
|
|
52
50
|
});
|
|
53
51
|
|
|
@@ -212,8 +210,8 @@ describe('gemini adapter model mapping (Gemini family)', () => {
|
|
|
212
210
|
});
|
|
213
211
|
|
|
214
212
|
describe('cross-adapter consistency', () => {
|
|
215
|
-
test('
|
|
216
|
-
const adapterNames = ['
|
|
213
|
+
test('model-aware non-Anthropic adapters emit a model line for opus skills', () => {
|
|
214
|
+
const adapterNames = ['antigravity', 'opencode', 'openclaw', 'generic'];
|
|
217
215
|
for (const name of adapterNames) {
|
|
218
216
|
const adapter = getAdapter(name);
|
|
219
217
|
const header = adapter.generateHeader({ ...baseSkill, model: 'opus' });
|
|
@@ -171,7 +171,10 @@ test('codex AGENTS.md documents the tier→model + reasoning-effort mapping', as
|
|
|
171
171
|
// Guards against a MODEL_MAP / REASONING_EFFORT_MAP interpolation swap.
|
|
172
172
|
assert.match(agents.content, /opus → `gpt-5\.6-sol` \(`model_reasoning_effort = "high"`\)/);
|
|
173
173
|
assert.match(agents.content, /sonnet → `gpt-5\.6-terra` \(`model_reasoning_effort = "medium"`\)/);
|
|
174
|
-
assert.match(agents.content, /haiku → `gpt-5\.6-
|
|
174
|
+
assert.match(agents.content, /haiku → `gpt-5\.6-terra` \(`model_reasoning_effort = "low"`\)/);
|
|
175
|
+
assert.ok(extras.some((e) => e.path === '.codex/agents/rune-heavy.toml'));
|
|
176
|
+
assert.ok(extras.some((e) => e.path === '.codex/agents/rune-standard.toml'));
|
|
177
|
+
assert.ok(extras.some((e) => e.path === '.codex/agents/rune-fast.toml'));
|
|
175
178
|
});
|
|
176
179
|
|
|
177
180
|
// --- New v2.18 adapters: shape + generateExtraFiles contract ---
|
|
@@ -7,11 +7,65 @@ import { mkdir, rm, writeFile } from 'node:fs/promises';
|
|
|
7
7
|
import path from 'node:path';
|
|
8
8
|
import { afterEach, beforeEach, describe, test } from 'node:test';
|
|
9
9
|
import { fileURLToPath } from 'node:url';
|
|
10
|
-
import { checkMeshIntegrity, formatMeshResults } from '../doctor.js';
|
|
10
|
+
import { checkMeshIntegrity, formatMeshResults, parseSkillConnections } from '../doctor.js';
|
|
11
11
|
|
|
12
12
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
13
13
|
const TEST_ROOT = path.join(__dirname, '.test-mesh-skills');
|
|
14
14
|
|
|
15
|
+
test('parseSkillConnections supports table-form mesh declarations', () => {
|
|
16
|
+
const parsed = parseSkillConnections(
|
|
17
|
+
`## Calls (outbound)
|
|
18
|
+
|
|
19
|
+
| Phase | Sub-skill | Layer | Purpose |
|
|
20
|
+
|---|---|---|---|
|
|
21
|
+
| 1 | \`scout\` | L2 | scan |
|
|
22
|
+
| 2 | \`neural-memory\` | ext | recall |
|
|
23
|
+
|
|
24
|
+
## Called By (inbound)
|
|
25
|
+
|
|
26
|
+
| Caller | Layer | Purpose |
|
|
27
|
+
|---|---|---|
|
|
28
|
+
| \`team\` | L1 | orchestrate |
|
|
29
|
+
`,
|
|
30
|
+
'cook',
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
assert.deepStrictEqual(
|
|
34
|
+
parsed.calls.map((entry) => entry.skill),
|
|
35
|
+
['scout', 'neural-memory'],
|
|
36
|
+
);
|
|
37
|
+
assert.deepStrictEqual(
|
|
38
|
+
parsed.calledBy.map((entry) => entry.skill),
|
|
39
|
+
['team'],
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('parseSkillConnections supports legacy connection-qualified headings and CRLF', () => {
|
|
44
|
+
const parsed = parseSkillConnections(
|
|
45
|
+
[
|
|
46
|
+
'## Calls (outbound connections)',
|
|
47
|
+
'',
|
|
48
|
+
'- `scout` (L2): inspect project',
|
|
49
|
+
'',
|
|
50
|
+
'## Called By (inbound connections)',
|
|
51
|
+
'',
|
|
52
|
+
'- `cook` (L1): orchestrates',
|
|
53
|
+
'',
|
|
54
|
+
'## Returns',
|
|
55
|
+
].join('\r\n'),
|
|
56
|
+
'example',
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
assert.deepStrictEqual(
|
|
60
|
+
parsed.calls.map((entry) => entry.skill),
|
|
61
|
+
['scout'],
|
|
62
|
+
);
|
|
63
|
+
assert.deepStrictEqual(
|
|
64
|
+
parsed.calledBy.map((entry) => entry.skill),
|
|
65
|
+
['cook'],
|
|
66
|
+
);
|
|
67
|
+
});
|
|
68
|
+
|
|
15
69
|
describe('checkMeshIntegrity', () => {
|
|
16
70
|
beforeEach(async () => {
|
|
17
71
|
await mkdir(path.join(TEST_ROOT, 'skills', 'skill-a'), { recursive: true });
|
|
@@ -319,6 +319,7 @@ metadata:
|
|
|
319
319
|
(c) => c.obligation.startsWith('MUST') || c.obligation.startsWith('NEVER'),
|
|
320
320
|
);
|
|
321
321
|
assert.ok(mustItems.length >= 2, 'should extract MUST/NEVER constraints');
|
|
322
|
+
assert.ok(result.compliance.every((item) => item.pack === '@rune-pro/test-pack'));
|
|
322
323
|
|
|
323
324
|
for (const item of result.compliance) {
|
|
324
325
|
assert.ok(typeof item.pack === 'string');
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import assert from 'node:assert';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { afterEach, beforeEach, describe, test } from 'node:test';
|
|
7
|
+
import { installHooks } from '../commands/hooks/install.js';
|
|
8
|
+
import { hookStatus } from '../commands/hooks/status.js';
|
|
9
|
+
import { uninstallHooks } from '../commands/hooks/uninstall.js';
|
|
10
|
+
|
|
11
|
+
let tmpRoot;
|
|
12
|
+
const runeRoot = path.resolve('.');
|
|
13
|
+
const hooksPath = (root) => path.join(root, '.codex', 'hooks.json');
|
|
14
|
+
|
|
15
|
+
beforeEach(async () => {
|
|
16
|
+
tmpRoot = await mkdtemp(path.join(tmpdir(), 'rune-codex-hooks-'));
|
|
17
|
+
await mkdir(path.join(tmpRoot, '.codex'), { recursive: true });
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
afterEach(async () => {
|
|
21
|
+
if (tmpRoot) await rm(tmpRoot, { recursive: true, force: true });
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
describe('Codex hooks adapter', () => {
|
|
25
|
+
test('auto-detects Codex and emits executable synchronous hooks', async () => {
|
|
26
|
+
const result = await installHooks(tmpRoot, { preset: 'gentle' });
|
|
27
|
+
assert.deepStrictEqual(result.platforms, ['codex']);
|
|
28
|
+
assert.strictEqual(result.written, true);
|
|
29
|
+
|
|
30
|
+
const config = JSON.parse(await readFile(hooksPath(tmpRoot), 'utf-8'));
|
|
31
|
+
assert.ok(config.hooks.PreToolUse);
|
|
32
|
+
assert.ok(config.hooks.PostToolUse);
|
|
33
|
+
assert.ok(config.hooks.Stop);
|
|
34
|
+
assert.ok(result.results[0].notes.some((note) => note.includes('/hooks')));
|
|
35
|
+
|
|
36
|
+
for (const groups of Object.values(config.hooks)) {
|
|
37
|
+
for (const group of groups) {
|
|
38
|
+
for (const hook of group.hooks) {
|
|
39
|
+
assert.strictEqual('async' in hook, false, 'Codex skips async handlers');
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
assert.strictEqual('matcher' in config.hooks.Stop[0], false, 'Stop matchers are ignored by Codex');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test('preserves user hooks across install and uninstall', async () => {
|
|
47
|
+
const userConfig = {
|
|
48
|
+
description: 'User hooks',
|
|
49
|
+
hooks: {
|
|
50
|
+
PreToolUse: [{ matcher: 'Bash', hooks: [{ type: 'command', command: 'user-policy.cmd' }] }],
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
await writeFile(hooksPath(tmpRoot), `${JSON.stringify(userConfig, null, 2)}\n`);
|
|
54
|
+
|
|
55
|
+
await installHooks(tmpRoot, { preset: 'strict' });
|
|
56
|
+
await uninstallHooks(tmpRoot, { platform: 'codex' });
|
|
57
|
+
|
|
58
|
+
const restored = JSON.parse(await readFile(hooksPath(tmpRoot), 'utf-8'));
|
|
59
|
+
assert.deepStrictEqual(restored, userConfig);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test('status reports the active preset and wired skills', async () => {
|
|
63
|
+
await installHooks(tmpRoot, { preset: 'gentle' });
|
|
64
|
+
const result = await hookStatus(tmpRoot, runeRoot);
|
|
65
|
+
const codex = result.results.find((entry) => entry.platform === 'codex');
|
|
66
|
+
assert.strictEqual(codex.installed, true);
|
|
67
|
+
assert.strictEqual(codex.preset, 'gentle');
|
|
68
|
+
assert.ok(codex.wired.includes('sentinel'));
|
|
69
|
+
assert.ok(codex.wired.includes('completion-gate'));
|
|
70
|
+
assert.strictEqual(codex.capability.maturity, 'stable');
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test('removes Rune-only hooks.json on uninstall', async () => {
|
|
74
|
+
await installHooks(tmpRoot, { preset: 'gentle' });
|
|
75
|
+
await uninstallHooks(tmpRoot, { platform: 'codex' });
|
|
76
|
+
assert.strictEqual(existsSync(hooksPath(tmpRoot)), false);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test('rejects malformed Codex hooks config without overwriting it', async () => {
|
|
80
|
+
const malformed = '{ broken json';
|
|
81
|
+
await writeFile(hooksPath(tmpRoot), malformed);
|
|
82
|
+
await assert.rejects(installHooks(tmpRoot, { preset: 'gentle' }), /hooks\.json is not valid JSON/);
|
|
83
|
+
assert.strictEqual(await readFile(hooksPath(tmpRoot), 'utf-8'), malformed);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
@@ -26,14 +26,14 @@ const PRO_MANIFEST = {
|
|
|
26
26
|
skill: 'context-inject',
|
|
27
27
|
event: 'UserPromptSubmit',
|
|
28
28
|
matcher: '.*',
|
|
29
|
-
command:
|
|
29
|
+
command: `node "\${RUNE_PRO_ROOT}/hooks/run-hook.cjs" context-inject`,
|
|
30
30
|
},
|
|
31
31
|
{
|
|
32
32
|
id: 'context-sense',
|
|
33
33
|
skill: 'context-sense',
|
|
34
34
|
event: 'PreToolUse',
|
|
35
35
|
matcher: 'Edit|Write',
|
|
36
|
-
command:
|
|
36
|
+
command: `node "\${RUNE_PRO_ROOT}/hooks/run-hook.cjs" context-sense`,
|
|
37
37
|
},
|
|
38
38
|
],
|
|
39
39
|
};
|
|
@@ -71,9 +71,7 @@ async function seedTierHooksOn(root, platform, tier) {
|
|
|
71
71
|
UserPromptSubmit: [
|
|
72
72
|
{
|
|
73
73
|
matcher: '.*',
|
|
74
|
-
hooks: [
|
|
75
|
-
{ type: 'command', command: 'node "${RUNE_' + tier.toUpperCase() + '_ROOT}/hooks/run-hook.cjs" ctx' },
|
|
76
|
-
],
|
|
74
|
+
hooks: [{ type: 'command', command: `node "\${RUNE_${tier.toUpperCase()}_ROOT}/hooks/run-hook.cjs" ctx` }],
|
|
77
75
|
},
|
|
78
76
|
],
|
|
79
77
|
},
|
|
@@ -65,7 +65,7 @@ describe('checkHookDrift', () => {
|
|
|
65
65
|
assert.match(missing[0].expected, /completion-gate/);
|
|
66
66
|
});
|
|
67
67
|
|
|
68
|
-
test(
|
|
68
|
+
test(`ignores tier-emitted entries (\${RUNE_PRO_ROOT})`, async () => {
|
|
69
69
|
const settings = buildPreset('gentle');
|
|
70
70
|
// Inject a Pro-tier entry alongside Free preset entries
|
|
71
71
|
settings.hooks.PostToolUse.push({
|
|
@@ -73,7 +73,7 @@ describe('checkHookDrift', () => {
|
|
|
73
73
|
hooks: [
|
|
74
74
|
{
|
|
75
75
|
type: 'command',
|
|
76
|
-
command:
|
|
76
|
+
command: `node "\${RUNE_PRO_ROOT}/hooks/run-hook.cjs" context-sense`,
|
|
77
77
|
async: false,
|
|
78
78
|
},
|
|
79
79
|
],
|
|
@@ -297,8 +297,8 @@ describe('hookStatus (claude adapter)', () => {
|
|
|
297
297
|
|
|
298
298
|
test('--platform all surfaces every adapter', async () => {
|
|
299
299
|
const result = await hookStatus(tmpRoot, RUNE_ROOT, { platform: 'all' });
|
|
300
|
-
assert.strictEqual(result.results.length,
|
|
301
|
-
for (const id of ['claude', 'cursor', 'windsurf', 'antigravity']) {
|
|
300
|
+
assert.strictEqual(result.results.length, 5);
|
|
301
|
+
for (const id of ['claude', 'codex', 'cursor', 'windsurf', 'antigravity']) {
|
|
302
302
|
const r = result.results.find((x) => x.platform === id);
|
|
303
303
|
assert.ok(r, `result for ${id} must be present`);
|
|
304
304
|
assert.ok(r.capability, `capability matrix for ${id} must be present`);
|