@polderlabs/bizar 10.7.0 → 10.7.2
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/.claude/agents/_shared/AGENT_BASELINE.md +266 -0
- package/.claude/agents/_shared/CLAUDE_TOOLS.md +412 -0
- package/.claude/agents/_shared/SKILLS.md +109 -0
- package/.claude/agents/brand-designer.md +55 -0
- package/.claude/agents/exec-assistant.md +34 -0
- package/.claude/agents/help-desk.md +44 -0
- package/.claude/agents/it-lead.md +53 -0
- package/.claude/agents/knowledge-manager.md +49 -0
- package/.claude/agents/office-coordinator.md +39 -0
- package/.claude/agents/office-greeter.md +53 -0
- package/.claude/agents/office-manager.md +287 -0
- package/.claude/agents/principal-engineer.md +58 -0
- package/.claude/agents/qa-reviewer.md +51 -0
- package/.claude/agents/research-analyst.md +53 -0
- package/.claude/agents/senior-engineer.md +55 -0
- package/.claude/agents/support-tech.md +87 -0
- package/.claude/agents/vp-engineering.md +54 -0
- package/.claude/commands/audit.md +48 -0
- package/.claude/commands/bizar.md +22 -0
- package/.claude/commands/cron.md +36 -0
- package/.claude/commands/explain.md +17 -0
- package/.claude/commands/goal.md +99 -0
- package/.claude/commands/init.md +15 -0
- package/.claude/commands/learn.md +46 -0
- package/.claude/commands/plan.md +35 -0
- package/.claude/commands/plow-through.md +50 -0
- package/.claude/commands/pr-review.md +49 -0
- package/.claude/commands/setup-provider.md +96 -0
- package/.claude/commands/spec.md +47 -0
- package/.claude/commands/sprint.md +43 -0
- package/.claude/commands/tailscale-serve.md +100 -0
- package/.claude/commands/team.md +132 -0
- package/.claude/commands/test.md +62 -0
- package/.claude/commands/validate.md +68 -0
- package/.claude/commands/visual-plan.md +24 -0
- package/.claude/hooks/README.md +108 -0
- package/.claude/hooks/__tests__/pretooluse-editwrite.test.mjs +146 -0
- package/.claude/hooks/__tests__/sessionend-recall.test.mjs +256 -0
- package/.claude/hooks/__tests__/sessionstart-prime.test.mjs +325 -0
- package/.claude/hooks/__tests__/thinking-route.test.mjs +319 -0
- package/.claude/hooks/auto-instinct.sh +81 -0
- package/.claude/hooks/learning-extract.mjs +92 -0
- package/.claude/hooks/post-merge-audit.sh +93 -0
- package/.claude/hooks/posttooluse-editwrite.mjs +91 -0
- package/.claude/hooks/pretooluse-bash.mjs +87 -0
- package/.claude/hooks/pretooluse-editwrite.mjs +117 -0
- package/.claude/hooks/sessionend-recall.mjs +384 -0
- package/.claude/hooks/sessionstart-prime.mjs +278 -0
- package/.claude/hooks/thinking-route.mjs +314 -0
- package/.claude/hooks/worker-suggest.mjs +110 -0
- package/.claude/settings.json +167 -0
- package/.claude/skills/9router/SKILL.md +80 -0
- package/.claude/skills/9router-chat/SKILL.md +73 -0
- package/.claude/skills/9router-embeddings/SKILL.md +69 -0
- package/.claude/skills/9router-image/SKILL.md +86 -0
- package/.claude/skills/9router-stt/SKILL.md +79 -0
- package/.claude/skills/9router-tts/SKILL.md +80 -0
- package/.claude/skills/9router-web-fetch/SKILL.md +99 -0
- package/.claude/skills/9router-web-search/SKILL.md +91 -0
- package/.claude/skills/agent-browser/SKILL.md +64 -0
- package/.claude/skills/bizar/README.md +9 -0
- package/.claude/skills/bizar/SKILL.md +447 -0
- package/.claude/skills/cpp-coding-standards/README.md +28 -0
- package/.claude/skills/cpp-coding-standards/SKILL.md +634 -0
- package/.claude/skills/cpp-coding-standards/references/concurrency.md +320 -0
- package/.claude/skills/cpp-coding-standards/references/error-handling.md +229 -0
- package/.claude/skills/cpp-coding-standards/references/memory-safety.md +216 -0
- package/.claude/skills/cpp-coding-standards/references/modern-idioms.md +282 -0
- package/.claude/skills/cpp-coding-standards/references/review-checklist.md +96 -0
- package/.claude/skills/cpp-testing/README.md +28 -0
- package/.claude/skills/cpp-testing/SKILL.md +304 -0
- package/.claude/skills/cpp-testing/references/coverage.md +370 -0
- package/.claude/skills/cpp-testing/references/framework-compare.md +175 -0
- package/.claude/skills/cpp-testing/references/host-test-for-embedded.md +499 -0
- package/.claude/skills/cpp-testing/references/mocking.md +364 -0
- package/.claude/skills/cpp-testing/references/tdd-workflow.md +308 -0
- package/.claude/skills/cubesandbox/SKILL.md +148 -0
- package/.claude/skills/de-sloppify/SKILL.md +38 -0
- package/.claude/skills/de-sloppify/cleanup.mjs +253 -0
- package/.claude/skills/de-sloppify/cleanup.test.mjs +189 -0
- package/.claude/skills/embedded-esp-idf/README.md +41 -0
- package/.claude/skills/embedded-esp-idf/SKILL.md +439 -0
- package/.claude/skills/embedded-esp-idf/references/freertos-patterns.md +214 -0
- package/.claude/skills/embedded-esp-idf/references/host-tests.md +164 -0
- package/.claude/skills/embedded-esp-idf/references/idf-py-commands.md +157 -0
- package/.claude/skills/embedded-esp-idf/references/kconfig.md +159 -0
- package/.claude/skills/embedded-esp-idf/references/logging-discipline.md +118 -0
- package/.claude/skills/embedded-esp-idf/references/memory-and-iram.md +137 -0
- package/.claude/skills/embedded-esp-idf/references/nvs.md +121 -0
- package/.claude/skills/embedded-esp-idf/references/packed-structs.md +192 -0
- package/.claude/skills/embedded-esp-idf/scripts/idf_env.sh +47 -0
- package/.claude/skills/embedded-esp-idf/scripts/size_check.sh +77 -0
- package/.claude/skills/glyph/SKILL.md +163 -0
- package/.claude/skills/harness-engineering/SKILL.md +142 -0
- package/.claude/skills/lightrag/SKILL.md +81 -0
- package/.claude/skills/memory-protocol/SKILL.md +105 -0
- package/.claude/skills/obsidian/SKILL.md +306 -0
- package/.claude/skills/read-the-damn-docs/SKILL.md +113 -0
- package/.claude/skills/self-improvement/SKILL.md +64 -0
- package/.claude/skills/skillopt/SKILL.md +129 -0
- package/.claude/skills/thinking-archetypes/SKILL.md +90 -0
- package/.claude/skills/thinking-bayesian/SKILL.md +267 -0
- package/.claude/skills/thinking-bounded-rationality/SKILL.md +406 -0
- package/.claude/skills/thinking-circle-of-competence/SKILL.md +216 -0
- package/.claude/skills/thinking-cynefin/SKILL.md +70 -0
- package/.claude/skills/thinking-debiasing/SKILL.md +192 -0
- package/.claude/skills/thinking-dual-process/SKILL.md +282 -0
- package/.claude/skills/thinking-effectuation/SKILL.md +366 -0
- package/.claude/skills/thinking-feedback-loops/SKILL.md +464 -0
- package/.claude/skills/thinking-fermi-estimation/SKILL.md +263 -0
- package/.claude/skills/thinking-first-principles/SKILL.md +167 -0
- package/.claude/skills/thinking-five-whys-plus/SKILL.md +139 -0
- package/.claude/skills/thinking-inversion/SKILL.md +195 -0
- package/.claude/skills/thinking-jobs-to-be-done/SKILL.md +363 -0
- package/.claude/skills/thinking-kepner-tregoe/SKILL.md +154 -0
- package/.claude/skills/thinking-leverage-points/SKILL.md +390 -0
- package/.claude/skills/thinking-lindy-effect/SKILL.md +331 -0
- package/.claude/skills/thinking-map-territory/SKILL.md +111 -0
- package/.claude/skills/thinking-margin-of-safety/SKILL.md +330 -0
- package/.claude/skills/thinking-model-combination/SKILL.md +406 -0
- package/.claude/skills/thinking-model-router/SKILL.md +360 -0
- package/.claude/skills/thinking-model-selection/SKILL.md +341 -0
- package/.claude/skills/thinking-occams-razor/SKILL.md +129 -0
- package/.claude/skills/thinking-ooda/SKILL.md +127 -0
- package/.claude/skills/thinking-opportunity-cost/SKILL.md +360 -0
- package/.claude/skills/thinking-pre-mortem/SKILL.md +170 -0
- package/.claude/skills/thinking-probabilistic/SKILL.md +324 -0
- package/.claude/skills/thinking-red-team/SKILL.md +142 -0
- package/.claude/skills/thinking-regret-minimization/SKILL.md +335 -0
- package/.claude/skills/thinking-reversibility/SKILL.md +326 -0
- package/.claude/skills/thinking-scientific-method/SKILL.md +162 -0
- package/.claude/skills/thinking-second-order/SKILL.md +184 -0
- package/.claude/skills/thinking-socratic/SKILL.md +198 -0
- package/.claude/skills/thinking-steel-manning/SKILL.md +332 -0
- package/.claude/skills/thinking-systems/SKILL.md +238 -0
- package/.claude/skills/thinking-theory-of-constraints/SKILL.md +338 -0
- package/.claude/skills/thinking-thought-experiment/SKILL.md +354 -0
- package/.claude/skills/thinking-triz/SKILL.md +171 -0
- package/.claude/skills/thinking-via-negativa/SKILL.md +358 -0
- package/bizar-dash/skills/publishing/SKILL.md +2 -1
- package/cli/install/postinstall.mjs +54 -28
- package/cli/install/postinstall.test.mjs +98 -0
- package/cli/provision.mjs +29 -0
- package/install.sh +7 -0
- package/package.json +7 -2
- package/scripts/git-hooks/__tests__/commit-msg.test.mjs +61 -0
- package/scripts/git-hooks/commit-msg +38 -0
- package/scripts/install-hooks.sh +9 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Authenticate Tailscale Serve and expose a local port on your tailnet
|
|
3
|
+
allowed-tools: Read, Bash
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Tailscale Serve Command
|
|
7
|
+
|
|
8
|
+
Authenticate and configure Tailscale Serve to expose a local service on your
|
|
9
|
+
tailnet. Auto-detects whether Serve is enabled on the tailnet and either
|
|
10
|
+
provisions HTTPS automatically or surfaces the admin-enable URL clearly.
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
/tailscale-serve # expose port 8765 (the BizarHarness dashboard default)
|
|
16
|
+
/tailscale-serve 3000 # expose port 3000
|
|
17
|
+
/tailscale-serve --status # show current serve config, no changes
|
|
18
|
+
/tailscale-serve --reset # remove the current serve config
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The full arguments are available as `$ARGUMENTS` (and `$1` for the port).
|
|
22
|
+
Parse them and route to the matching step below.
|
|
23
|
+
|
|
24
|
+
## Steps
|
|
25
|
+
|
|
26
|
+
1. **Parse the argument**: first arg is the port (default `8765`). If `--status`, run step 3 only. If `--reset`, run step 6 only.
|
|
27
|
+
|
|
28
|
+
2. **Verify the local port is listening**:
|
|
29
|
+
```bash
|
|
30
|
+
ss -lntp 2>/dev/null | grep -E ":${PORT}\b" || curl -sS -o /dev/null -w "HTTP %{http_code}\n" --max-time 2 http://127.0.0.1:${PORT}/
|
|
31
|
+
```
|
|
32
|
+
If the port is not open, tell the user clearly which command starts the
|
|
33
|
+
service (e.g. `npm run host:start` for the BizarHarness demo, or
|
|
34
|
+
`python3 -m http.server 8765` for a pam static server). Do not proceed
|
|
35
|
+
without an upstream.
|
|
36
|
+
|
|
37
|
+
3. **Check current Tailscale Serve status**:
|
|
38
|
+
```bash
|
|
39
|
+
tailscale serve status
|
|
40
|
+
tailscale status --json | jq -r '.Self.DNSName, .Self.TailscaleIPs[0]'
|
|
41
|
+
```
|
|
42
|
+
Capture the MagicDNS name and the Tailscale IP. The DNS name will look
|
|
43
|
+
like `devbox.tail2cdf4d.ts.net` (trim the trailing dot).
|
|
44
|
+
|
|
45
|
+
4. **If already configured** (status shows `https://`):
|
|
46
|
+
- Print the current config
|
|
47
|
+
- Print the existing endpoints
|
|
48
|
+
- **Stop** — do not re-configure
|
|
49
|
+
|
|
50
|
+
5. **Try to enable Serve** (with a hard timeout — it may try to open a browser):
|
|
51
|
+
```bash
|
|
52
|
+
timeout 5 tailscale serve --bg --https=443 "http://127.0.0.1:${PORT}" 2>&1
|
|
53
|
+
```
|
|
54
|
+
- **On success**: print the new config, print the `https://<dnsname>/` endpoint.
|
|
55
|
+
- **If the output contains "Serve is not enabled"**:
|
|
56
|
+
- Parse the admin-enable URL from the output (it's the
|
|
57
|
+
`https://login.tailscale.com/f/serve?node=...` line).
|
|
58
|
+
- Print it prominently with a clear message:
|
|
59
|
+
> **Tailscale Serve is not enabled on this tailnet.**
|
|
60
|
+
> An admin must visit this URL once to enable it:
|
|
61
|
+
> **<URL>**
|
|
62
|
+
> Then re-run `/tailscale-serve ${PORT}`.
|
|
63
|
+
- Do not fall back to plain HTTP automatically — the user asked for
|
|
64
|
+
authentication, not a workaround. They can run the demo's
|
|
65
|
+
`host:start` script for the HTTP fallback.
|
|
66
|
+
- **On any other error**: print the full error, suggest
|
|
67
|
+
`tailscale serve status` and `sudo tailscale up` as debug steps.
|
|
68
|
+
|
|
69
|
+
6. **For `--reset`**:
|
|
70
|
+
```bash
|
|
71
|
+
tailscale serve reset
|
|
72
|
+
```
|
|
73
|
+
Confirm the reset succeeded by re-running `tailscale serve status`.
|
|
74
|
+
|
|
75
|
+
7. **Final output** — always end with a clear status block:
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
=== Tailscale Serve ===
|
|
79
|
+
config: <status>
|
|
80
|
+
upstream: http://127.0.0.1:<port>
|
|
81
|
+
endpoints:
|
|
82
|
+
- https://<dnsname>/ (HTTPS, only if Serve is enabled)
|
|
83
|
+
- http://<dnsname>:<port>/ (HTTP fallback, only if upstream binds 0.0.0.0)
|
|
84
|
+
|
|
85
|
+
To remove: /tailscale-serve --reset
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Notes
|
|
89
|
+
|
|
90
|
+
- `tailscale serve` requires a one-time tailnet admin enable. There is no
|
|
91
|
+
per-device flag — only the admin can authorize it. The command surfaces
|
|
92
|
+
the admin URL and stops rather than silently falling back.
|
|
93
|
+
- This command does not start the upstream service. It assumes the service
|
|
94
|
+
is already running and only wires the HTTPS proxy.
|
|
95
|
+
- For the BizarHarness Demo Dashboard, the typical flow is:
|
|
96
|
+
```
|
|
97
|
+
/tailscale-serve --status # see current state
|
|
98
|
+
npm run host:start # upstream on port 8765
|
|
99
|
+
/tailscale-serve # expose it on the tailnet
|
|
100
|
+
```
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Spawn a Claude Code agent team — coordinate Thor (M2.7), Tyr (M3), Mimir (research), and Hermod (git) to complete a complex mission end-to-end.
|
|
3
|
+
allowed-tools: Read, Bash, Agent
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Team — Spawn a Claude Code Agent Team
|
|
7
|
+
|
|
8
|
+
The `/team` command spawns a **coordinated agent team** for a complex,
|
|
9
|
+
multi-step mission. The lead agent coordinates teammates; each teammate
|
|
10
|
+
owns a disjoint scope; results are synthesized and committed.
|
|
11
|
+
|
|
12
|
+
The full mission is available as `$ARGUMENTS` (or composed from `$1`).
|
|
13
|
+
|
|
14
|
+
## When to Use `/team`
|
|
15
|
+
|
|
16
|
+
Use `/team` for any non-trivial mission that benefits from **parallel
|
|
17
|
+
work + explicit coordination**. Examples:
|
|
18
|
+
|
|
19
|
+
- **Refactor** — split a module across Thor (M2.7) and Tyr (M3) in parallel.
|
|
20
|
+
- **Multi-feature build** — new feature A (Thor) + new feature B (Tyr) + tests (Heimdall).
|
|
21
|
+
- **Research + implementation** — Mimir researches, Thor implements, Forseti audits.
|
|
22
|
+
- **Migration / upgrade** — Hermod handles the git/PR lifecycle while Thor/Tyr write code.
|
|
23
|
+
- **Bug hunt** — Mimir traces the data flow while Tyr writes the fix and tests.
|
|
24
|
+
|
|
25
|
+
Do NOT use `/team` for trivial single-file edits or single-question
|
|
26
|
+
clarifications. Use `@brenda` directly for those.
|
|
27
|
+
|
|
28
|
+
## Default Team Composition
|
|
29
|
+
|
|
30
|
+
If the user does not specify a team composition, spawn this default:
|
|
31
|
+
|
|
32
|
+
| Role | Agent | Model | Job |
|
|
33
|
+
|---------------|---------|-------------------|---------------------------------------|
|
|
34
|
+
| Lead | @mike | minimax/MiniMax-M3 | Coordinate, synthesize, gate quality |
|
|
35
|
+
| Implementer 1 | @todd | minimax/MiniMax-M2.7 | Moderate-complexity implementation |
|
|
36
|
+
| Implementer 2 | @karen | minimax/MiniMax-M3 | Complex / cross-cutting work |
|
|
37
|
+
| Researcher | @greg | bizar/MiniMax-M3 | Codebase research, pattern discovery |
|
|
38
|
+
| Git ops | @steve | minimax/MiniMax-M2.7 | Branch, commit, push, PR |
|
|
39
|
+
| Reviewer | @linda| minimax/MiniMax-M3 | Audit plan + final output |
|
|
40
|
+
|
|
41
|
+
You can swap or remove any of these — but always keep at least one
|
|
42
|
+
implementer and a reviewer.
|
|
43
|
+
|
|
44
|
+
## Protocol (How Odin Runs a `/team` Invocation)
|
|
45
|
+
|
|
46
|
+
1. **Read `.bizar/PROJECT.md`** if it exists. Factor the project
|
|
47
|
+
description into the team mission.
|
|
48
|
+
2. **Read `bizar memory status`**. If the vault is reachable, run
|
|
49
|
+
`bizar memory search "<topic>"` for prior context on the mission.
|
|
50
|
+
3. **Decompose** the mission into disjoint work items. Each item
|
|
51
|
+
names:
|
|
52
|
+
- The agent that owns it
|
|
53
|
+
- The file scope (paths/globs)
|
|
54
|
+
- The deliverable (a function, a test, a commit, a doc)
|
|
55
|
+
- The exit signal ("done when X is committed")
|
|
56
|
+
4. **Launch in parallel** — use the **Agent tool** in a **single
|
|
57
|
+
message** with multiple `Agent` calls so all teammates run
|
|
58
|
+
concurrently. Each call's prompt names the Bizar agent
|
|
59
|
+
(`todd`, `karen`, `greg`, `steve`, `linda`) so the audit
|
|
60
|
+
trail stays readable. For long-running work, pass
|
|
61
|
+
`run_in_background: true`.
|
|
62
|
+
5. **Monitor** — while the team runs, return control to the user.
|
|
63
|
+
The team runs asynchronously. Check teammate progress only
|
|
64
|
+
when the user asks (use `SendMessage` to the named agent).
|
|
65
|
+
6. **Synthesize** — when teammates report back, gate through @linda
|
|
66
|
+
(audit) and @steve (commit/push). Then report the final outcome
|
|
67
|
+
to the user with file:line references.
|
|
68
|
+
|
|
69
|
+
## Pre-Dispatch Checklist (MANDATORY)
|
|
70
|
+
|
|
71
|
+
- [ ] Each teammate has a **disjoint file scope** — no two agents
|
|
72
|
+
edit the same file or directory
|
|
73
|
+
- [ ] Lockfiles, `package.json`, root configs, `tsconfig.json`,
|
|
74
|
+
`vite.config.*`, `Dockerfile`, CI configs are assigned to ONE
|
|
75
|
+
agent or marked READ-ONLY for everyone else
|
|
76
|
+
- [ ] No subagent has both `bash: allow` AND a write-level git task
|
|
77
|
+
in the same batch — Hermod is the only git writer
|
|
78
|
+
- [ ] Each teammate's scope is named in plain English
|
|
79
|
+
- [ ] You have prepended a one-paragraph sibling-awareness block to
|
|
80
|
+
every prompt (Odin baseline, "Parallel Dispatch Coordination")
|
|
81
|
+
- [ ] You have called `bizar memory status` and confirmed the vault
|
|
82
|
+
is reachable
|
|
83
|
+
|
|
84
|
+
## Example Mission Strings
|
|
85
|
+
|
|
86
|
+
**Refactor a module:**
|
|
87
|
+
```
|
|
88
|
+
Refactor src/api/auth.ts into a clean module: extract JWT validation
|
|
89
|
+
into src/auth/jwt.ts, rate-limiting into src/auth/rate-limit.ts, and
|
|
90
|
+
keep the public surface stable. Add tests for each new module. Update
|
|
91
|
+
docs/architecture.md with the new module map. Do not change the HTTP
|
|
92
|
+
route handlers.
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Multi-feature build:**
|
|
96
|
+
```
|
|
97
|
+
Add a kanban board: (1) Thor — backend API at /api/tasks with CRUD
|
|
98
|
+
endpoints and SQLite persistence. (2) Tyr — frontend React component
|
|
99
|
+
in src/components/Kanban.tsx with 5 columns. (3) Heimdall — write
|
|
100
|
+
the OpenAPI spec at docs/api/tasks.yaml. (4) Hermod — open a PR
|
|
101
|
+
named feat/kanban-board.
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Bug hunt:**
|
|
105
|
+
```
|
|
106
|
+
Mimir — trace the data flow from POST /api/checkout through to the
|
|
107
|
+
Stripe webhook handler; find any place where the order status is
|
|
108
|
+
written before the payment is confirmed. Tyr — write a regression
|
|
109
|
+
test that reproduces the race. Thor — fix the bug. Forseti —
|
|
110
|
+
audit the fix for completeness. Hermod — commit + push.
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Tool Reference (Claude Code)
|
|
114
|
+
|
|
115
|
+
- **Agent tool** — spawn one subagent per call. Use multiple
|
|
116
|
+
`Agent` calls in a single message for parallelism.
|
|
117
|
+
- `run_in_background: true` on the Agent tool — for tasks that
|
|
118
|
+
span more than a few minutes.
|
|
119
|
+
- `SendMessage` — talk to a running background agent by name.
|
|
120
|
+
|
|
121
|
+
## Failure Modes
|
|
122
|
+
|
|
123
|
+
- **Two agents write the same file** — STOP, revert one branch, reassign.
|
|
124
|
+
- **One agent stalls** — use `TaskStop` to terminate, route the
|
|
125
|
+
remaining scope to another agent.
|
|
126
|
+
- **Tests fail after team work** — dispatch `todd` to investigate;
|
|
127
|
+
do not paper over the failure.
|
|
128
|
+
- **Git conflict** — route to `steve` for `git rebase` / merge
|
|
129
|
+
resolution.
|
|
130
|
+
- **A teammate goes silent** — send a `SendMessage` to the named
|
|
131
|
+
agent for a status report; if dead, kill and re-spawn with a
|
|
132
|
+
fresh prompt.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Run the project's test suite via the Bizar test gate. Auto-detects jest/vitest/bun/pytest/cargo/go. Exits non-zero on failure.
|
|
3
|
+
allowed-tools: Read, Bash
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /test — Run the Project's Test Suite
|
|
7
|
+
|
|
8
|
+
The `/test` command is a thin wrapper around `bizar test-gate`. It
|
|
9
|
+
auto-detects the project's test runner and runs the full suite.
|
|
10
|
+
|
|
11
|
+
## What It Does
|
|
12
|
+
|
|
13
|
+
1. Detects the project stack (one of: npm, pytest, cargo, go).
|
|
14
|
+
2. Runs the matching test command:
|
|
15
|
+
- `package.json` present → `npm test`
|
|
16
|
+
- `pyproject.toml` present → `pytest`
|
|
17
|
+
- `Cargo.toml` present → `cargo test`
|
|
18
|
+
- `go.mod` present → `go test ./...`
|
|
19
|
+
3. Streams the test output to the user.
|
|
20
|
+
4. Exits non-zero on test failures.
|
|
21
|
+
|
|
22
|
+
## Exit Codes
|
|
23
|
+
|
|
24
|
+
| Code | Meaning |
|
|
25
|
+
|------|----------------------------------|
|
|
26
|
+
| 0 | All tests passed |
|
|
27
|
+
| 1 | Tests failed |
|
|
28
|
+
| 2 | No test runner detected |
|
|
29
|
+
|
|
30
|
+
## How to Use
|
|
31
|
+
|
|
32
|
+
Invoke `/test` from the project root. The test gate inspects the
|
|
33
|
+
current directory and picks the right runner.
|
|
34
|
+
|
|
35
|
+
To run a specific Bizar test scope instead, pass arguments to
|
|
36
|
+
`/test`. The arguments are forwarded to the underlying runner and
|
|
37
|
+
are available as `$ARGUMENTS` (or `$1`, `$2`, ...):
|
|
38
|
+
|
|
39
|
+
- `/test plugins/bizar` — run only the Bizar plugin tests (bun)
|
|
40
|
+
- `/test --testPathPattern=auth` — pass a flag to the runner
|
|
41
|
+
|
|
42
|
+
## When to Use
|
|
43
|
+
|
|
44
|
+
- After any non-trivial code change
|
|
45
|
+
- Before committing (`@steve` should always run `/test` first)
|
|
46
|
+
- As the final step of a `/team` mission — gate quality with tests
|
|
47
|
+
|
|
48
|
+
## Common Patterns
|
|
49
|
+
|
|
50
|
+
- **Post-implementation gate** — after Thor and Tyr finish their
|
|
51
|
+
parallel work, dispatch `todd` to run `/test`. If failures, fix
|
|
52
|
+
and re-run.
|
|
53
|
+
- **PR check** — run `/test` in CI before merging.
|
|
54
|
+
- **Debug a flaky test** — run `/test` twice; if the second run
|
|
55
|
+
passes, the test is order-dependent (fix or quarantine).
|
|
56
|
+
|
|
57
|
+
## Related
|
|
58
|
+
|
|
59
|
+
- `bizar test-gate` — the underlying CLI command
|
|
60
|
+
- `bizar doctor` — checks the Bizar install itself (not project tests)
|
|
61
|
+
- `make check` — typecheck + tests (full pipeline, dev only)
|
|
62
|
+
- `make e2e` — Bizar plugin end-to-end (dev only)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Validate the Bizar install end-to-end — settings.json parses, plugin entry resolves, all agent files are installed, all skills/rules/hooks/commands are in place, provider config is sane, and the 9router gateway is reachable.
|
|
3
|
+
allowed-tools: Read, Bash
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /validate — Validate the Bizar Install
|
|
7
|
+
|
|
8
|
+
The `/validate` command runs `bizar doctor` with the full check
|
|
9
|
+
battery. It is the fastest way to confirm the install is healthy
|
|
10
|
+
and Claude Code will see every Bizar component on the next session
|
|
11
|
+
start.
|
|
12
|
+
|
|
13
|
+
## What It Checks
|
|
14
|
+
|
|
15
|
+
1. **claude-reachable** — `claude --version` exits 0.
|
|
16
|
+
2. **claude-config-valid** — `~/.claude/settings.json` parses as JSON.
|
|
17
|
+
3. **plugin-entry-present** — `settings.json` has a Bizar plugin entry.
|
|
18
|
+
4. **plugin-path-resolves** — the plugin path on disk actually exists.
|
|
19
|
+
5. **agent-files-installed** — all agent files in `~/.claude/agents/`
|
|
20
|
+
(mike, janet, susan, pam, greg, brenda, steve, todd, brad,
|
|
21
|
+
karen, carl, linda, oscar, kevin).
|
|
22
|
+
6. **tools-available** — at least one of `semble`, `skills`
|
|
23
|
+
is on PATH.
|
|
24
|
+
7. **provider-config-sanity** — `provider.9router` has at least
|
|
25
|
+
one sane model entry.
|
|
26
|
+
8. **9router-reachable** — 9Router gateway responds at
|
|
27
|
+
`http://localhost:20128/health` (lenient — warn, don't fail).
|
|
28
|
+
9. **slash-commands-installed** — all Bizar slash commands
|
|
29
|
+
(`/audit`, `/explain`, `/init`, `/learn`, `/plan`, `/plow-through`,
|
|
30
|
+
`/pr-review`, `/tailscale-serve`, `/visual-plan`, `/bizar`,
|
|
31
|
+
`/team`, `/test`, `/validate`) are present in `~/.claude/commands/`.
|
|
32
|
+
10. **skills-installed** — every subdir of `config/skills/` is
|
|
33
|
+
mirrored to `~/.claude/skills/`.
|
|
34
|
+
11. **rules-installed** — every `.md` in `config/rules/` is mirrored
|
|
35
|
+
to `~/.claude/rules/`.
|
|
36
|
+
12. **hooks-installed** — `.claude/hooks/` scripts are installed
|
|
37
|
+
with executable permissions.
|
|
38
|
+
|
|
39
|
+
## How to Use
|
|
40
|
+
|
|
41
|
+
Invoke `/validate` (no arguments) from anywhere. It is read-only and
|
|
42
|
+
never modifies the system.
|
|
43
|
+
|
|
44
|
+
If any check fails, the user should run `bizar update` to refresh the
|
|
45
|
+
install, or `bizar repair` to fix common issues.
|
|
46
|
+
|
|
47
|
+
## Output
|
|
48
|
+
|
|
49
|
+
Each check prints ✓ or ✗ with a one-line message. The summary line
|
|
50
|
+
shows the total pass/fail count. Exits non-zero if any check fails.
|
|
51
|
+
|
|
52
|
+
For machine-readable output, the user can run `bizar doctor --json`
|
|
53
|
+
directly.
|
|
54
|
+
|
|
55
|
+
## When to Use
|
|
56
|
+
|
|
57
|
+
- After a manual config edit — confirm nothing broke.
|
|
58
|
+
- Before a `/team` mission — confirm the install is healthy so the
|
|
59
|
+
team has all the tools it needs.
|
|
60
|
+
- After `bizar install` or `bizar update` — the install already
|
|
61
|
+
calls doctor, but a manual re-run is cheap.
|
|
62
|
+
- When a user asks "why is Claude Code misbehaving?" — start here.
|
|
63
|
+
|
|
64
|
+
## Related
|
|
65
|
+
|
|
66
|
+
- `bizar doctor` — the underlying CLI command
|
|
67
|
+
- `bizar update` — refreshes the install (re-runs syncConfigExtras)
|
|
68
|
+
- `bizar repair` — fixes common issues (stale symlinks, version drift)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Toggle the Bizar visual plan canvas or check its current status.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# /visual-plan — Toggle Visual Plan Canvas
|
|
6
|
+
|
|
7
|
+
Toggle the Bizar visual plan canvas or check its current status.
|
|
8
|
+
|
|
9
|
+
The full arguments are available as `$ARGUMENTS` (and `$1`).
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
/visual-plan on — Enable the visual plan canvas in the current session
|
|
15
|
+
/visual-plan off — Disable the visual plan canvas
|
|
16
|
+
/visual-plan status — Show whether the canvas is currently enabled
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Notes
|
|
20
|
+
|
|
21
|
+
The visual plan canvas shows plans as interactive node graphs. When enabled, plan elements appear as draggable nodes on a canvas that agents can manipulate directly. This is useful for visual thinkers or when planning complex multi-step work.
|
|
22
|
+
|
|
23
|
+
This is a session-level toggle — it affects the current Claude Code
|
|
24
|
+
session only.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Bizar Harness — Claude Code Hooks
|
|
2
|
+
|
|
3
|
+
This directory contains the **Claude Code** adapter scripts that back the
|
|
4
|
+
project-scoped hooks defined in `.claude/settings.json`.
|
|
5
|
+
|
|
6
|
+
They replaced the legacy Cline hooks. The Claude Code
|
|
7
|
+
set is the only supported path on Bizar v6.3.0+; the legacy Cline hooks
|
|
8
|
+
are no longer installed.
|
|
9
|
+
|
|
10
|
+
## Adapter inventory
|
|
11
|
+
|
|
12
|
+
| File | Event | Matcher | Behaviour |
|
|
13
|
+
|------|-------|---------|-----------|
|
|
14
|
+
| `pretooluse-editwrite.mjs` | `PreToolUse` | `Write\|Edit\|MultiEdit\|Bash` | Blocks `.env`/secrets/lockfiles; warns on `console.log`/`debugger`/`.only()` in `src/`; scans `Bash` against the 36-pattern dangerous-pattern list |
|
|
15
|
+
| `posttooluse-editwrite.mjs` | `PostToolUse` | `Edit\|Write\|MultiEdit` | Logs edit/write latency + size to `~/.config/bizar/hook-logs/` |
|
|
16
|
+
| `sessionstart-prime.mjs` | `SessionStart` | (none — branches on `source`) | Reads PROGRESS.md + feature_list.json + git log + .bizar/PROJECT.md; branches on `startup`/`clear`/`resume`; WIP=1 guard |
|
|
17
|
+
| `thinking-route.mjs` | `UserPromptSubmit` | (none) | Slash-command routing (team/plow-through/test/validate/plan/audit/pr-review) + 35-bucket thinking-* mental-model router |
|
|
18
|
+
| `worker-suggest.mjs` | `UserPromptSubmit` | (none) | Calls `cli/worker-dispatcher.mjs:dispatch()` against `config/trigger-patterns.json` |
|
|
19
|
+
| `sessionend-recall.mjs` | `SessionEnd` | (none) | Reads `transcript_path`; writes `.bizar/sessions/<date>-<id>.md` + `.bizar/session-state.json` handoff |
|
|
20
|
+
|
|
21
|
+
## SessionStart ↔ SessionEnd handoff
|
|
22
|
+
|
|
23
|
+
The two lifecycle hooks form a state machine via the `.bizar/session-state.json`
|
|
24
|
+
file:
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
SessionEnd (session N)
|
|
28
|
+
↓ writes .bizar/session-state.json with {nextStep, blockers, filesTouched}
|
|
29
|
+
SessionStart (session N+1, source: "resume")
|
|
30
|
+
↑ reads it; primes the agent with "Last nextStep: …" + blockers
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
If `.bizar/session-state.json` is missing, the resume branch degrades
|
|
34
|
+
gracefully to "No prior session-state.json found — treating as fresh start."
|
|
35
|
+
|
|
36
|
+
## I/O contract
|
|
37
|
+
|
|
38
|
+
Claude Code invokes each hook as a child process, pipes JSON on
|
|
39
|
+
**stdin**, and reads JSON on **stdout**. The five adapters above all
|
|
40
|
+
read using `process.stdin` and write a single JSON object to
|
|
41
|
+
`process.stdout`.
|
|
42
|
+
|
|
43
|
+
### Stdin (varies by event)
|
|
44
|
+
|
|
45
|
+
```jsonc
|
|
46
|
+
// PreToolUse
|
|
47
|
+
{
|
|
48
|
+
"session_id": "...",
|
|
49
|
+
"transcript_path": "...",
|
|
50
|
+
"cwd": "/home/drb0rk/Projects/BizarHarness",
|
|
51
|
+
"hook_event_name": "PreToolUse",
|
|
52
|
+
"tool_name": "Write",
|
|
53
|
+
"tool_input": { "file_path": "/path", "content": "..." }
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// PostToolUse (adds tool_response)
|
|
57
|
+
// UserPromptSubmit (uses .user_prompt instead of .tool_name/.tool_input)
|
|
58
|
+
// SessionStart (uses .source = "startup" | "resume" | "clear")
|
|
59
|
+
// SessionEnd (uses .reason = "exit" | "clear" | "logout" | "prompt_input_exit")
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Stdout
|
|
63
|
+
|
|
64
|
+
```jsonc
|
|
65
|
+
// Block (PreToolUse only)
|
|
66
|
+
{
|
|
67
|
+
"hookSpecificOutput": {
|
|
68
|
+
"hookEventName": "PreToolUse",
|
|
69
|
+
"permissionDecision": "deny",
|
|
70
|
+
"permissionDecisionReason": "..."
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Inject context for the next turn (all events)
|
|
75
|
+
{
|
|
76
|
+
"hookSpecificOutput": {
|
|
77
|
+
"hookEventName": "PostToolUse", // or PreToolUse / SessionStart / UserPromptSubmit
|
|
78
|
+
"additionalContext": "..."
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
For a non-blocking `PreToolUse`, omitting `permissionDecision` and
|
|
84
|
+
emitting only `additionalContext` is a soft hint to the model — the
|
|
85
|
+
tool call still proceeds.
|
|
86
|
+
|
|
87
|
+
## Claude Code lifecycle mapping
|
|
88
|
+
|
|
89
|
+
The legacy Cline plugin used four separate events (PreToolUse,
|
|
90
|
+
PostToolUse, TaskStart, TaskResume, UserPromptSubmit). Claude Code
|
|
91
|
+
collapses "task start" and "task resume" into a single `SessionStart`
|
|
92
|
+
event that branches on `source` (`startup`, `resume`, `clear`). The
|
|
93
|
+
adapter `sessionstart-prime.mjs` reads `source` and applies the
|
|
94
|
+
appropriate priming logic for each branch.
|
|
95
|
+
|
|
96
|
+
## Disabling an individual hook
|
|
97
|
+
|
|
98
|
+
Easiest path: comment out the matching `hooks` array entry in
|
|
99
|
+
`.claude/settings.json`. Removing the executable bit
|
|
100
|
+
(`chmod -x …`) also works — Claude Code silently skips hooks it can't
|
|
101
|
+
execute.
|
|
102
|
+
|
|
103
|
+
## See also
|
|
104
|
+
|
|
105
|
+
- `cli/provision-claude.mjs` — installs Claude Code hooks to
|
|
106
|
+
`~/.claude/hooks/` and wires them via `~/.claude/settings.json`.
|
|
107
|
+
- `.claude/settings.json` — the project hook wiring
|
|
108
|
+
- `.bizar/session-state.json` — handoff artifact between SessionEnd and SessionStart
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Test suite for .claude/hooks/pretooluse-editwrite.mjs
|
|
3
|
+
//
|
|
4
|
+
// Invokes the hook with a synthetic Claude Code PreToolUse payload over
|
|
5
|
+
// stdin, captures stdout, and asserts on `permissionDecision`.
|
|
6
|
+
//
|
|
7
|
+
// Run: node --test .claude/hooks/__tests__/pretooluse-editwrite.test.mjs
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
import { test } from 'node:test';
|
|
12
|
+
import assert from 'node:assert/strict';
|
|
13
|
+
import { spawnSync } from 'node:child_process';
|
|
14
|
+
import path from 'node:path';
|
|
15
|
+
import { fileURLToPath } from 'node:url';
|
|
16
|
+
|
|
17
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
18
|
+
const HOOK = path.resolve(__dirname, '..', 'pretooluse-editwrite.mjs');
|
|
19
|
+
|
|
20
|
+
function runHook(toolName, filePath) {
|
|
21
|
+
const payload = JSON.stringify({
|
|
22
|
+
session_id: 'test-session',
|
|
23
|
+
cwd: '/tmp',
|
|
24
|
+
hook_event_name: 'PreToolUse',
|
|
25
|
+
tool_name: toolName,
|
|
26
|
+
tool_input: toolName === 'Write'
|
|
27
|
+
? { file_path: filePath, content: '' }
|
|
28
|
+
: toolName === 'Edit'
|
|
29
|
+
? { file_path: filePath, new_string: '' }
|
|
30
|
+
: { file_path: filePath, edits: [] },
|
|
31
|
+
});
|
|
32
|
+
const result = spawnSync('node', [HOOK], { input: payload, encoding: 'utf8' });
|
|
33
|
+
if (result.status !== 0) {
|
|
34
|
+
throw new Error(`hook exited ${result.status}\nstderr: ${result.stderr}`);
|
|
35
|
+
}
|
|
36
|
+
const out = result.stdout.trim();
|
|
37
|
+
if (!out || out === '{}') return { decision: null, context: null };
|
|
38
|
+
const parsed = JSON.parse(out);
|
|
39
|
+
return {
|
|
40
|
+
decision: parsed.hookSpecificOutput?.permissionDecision ?? null,
|
|
41
|
+
reason: parsed.hookSpecificOutput?.permissionDecisionReason ?? null,
|
|
42
|
+
context: parsed.hookSpecificOutput?.additionalContext ?? null,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
test('Write .env → deny', () => {
|
|
47
|
+
const r = runHook('Write', '/repo/.env');
|
|
48
|
+
assert.equal(r.decision, 'deny');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test('Write .env.local → deny', () => {
|
|
52
|
+
const r = runHook('Write', '/repo/.env.local');
|
|
53
|
+
assert.equal(r.decision, 'deny');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test('Write .env.production → deny', () => {
|
|
57
|
+
const r = runHook('Write', '/repo/.env.production');
|
|
58
|
+
assert.equal(r.decision, 'deny');
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test('Write .envrc → deny', () => {
|
|
62
|
+
const r = runHook('Write', '/repo/.envrc');
|
|
63
|
+
assert.equal(r.decision, 'deny');
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test('Write .env.example → allow (docs)', () => {
|
|
67
|
+
const r = runHook('Write', '/repo/research/gstack/.env.example');
|
|
68
|
+
assert.notEqual(r.decision, 'deny');
|
|
69
|
+
assert.match(r.context, /Bizar PreToolUse/);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test('Write .env.sample → allow (docs)', () => {
|
|
73
|
+
const r = runHook('Write', '/repo/templates/.env.sample');
|
|
74
|
+
assert.notEqual(r.decision, 'deny');
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test('Write .env.template → allow (docs)', () => {
|
|
78
|
+
const r = runHook('Write', '/repo/templates/deploy/docker/.env.template');
|
|
79
|
+
assert.notEqual(r.decision, 'deny');
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test('Write secrets/api.json → deny', () => {
|
|
83
|
+
const r = runHook('Write', '/repo/secrets/api.json');
|
|
84
|
+
assert.equal(r.decision, 'deny');
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test('Write credentials/x.json → deny', () => {
|
|
88
|
+
const r = runHook('Write', '/repo/credentials/x.json');
|
|
89
|
+
assert.equal(r.decision, 'deny');
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test('Write node_modules/x.js → deny', () => {
|
|
93
|
+
const r = runHook('Write', '/repo/node_modules/x.js');
|
|
94
|
+
assert.equal(r.decision, 'deny');
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test('Write bun.lock → allow (package-manager output)', () => {
|
|
98
|
+
const r = runHook('Write', '/repo/bun.lock');
|
|
99
|
+
assert.notEqual(r.decision, 'deny');
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test('Write bun.lockb → allow (binary lock variant)', () => {
|
|
103
|
+
const r = runHook('Write', '/repo/bun.lockb');
|
|
104
|
+
assert.notEqual(r.decision, 'deny');
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test('Write package-lock.json → allow (package-manager output)', () => {
|
|
108
|
+
const r = runHook('Write', '/repo/package-lock.json');
|
|
109
|
+
assert.notEqual(r.decision, 'deny');
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test('Write yarn.lock → allow', () => {
|
|
113
|
+
const r = runHook('Write', '/repo/yarn.lock');
|
|
114
|
+
assert.notEqual(r.decision, 'deny');
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test('Write pnpm-lock.yaml → allow', () => {
|
|
118
|
+
const r = runHook('Write', '/repo/pnpm-lock.yaml');
|
|
119
|
+
assert.notEqual(r.decision, 'deny');
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
test('Write src/index.ts → allow + neutral context', () => {
|
|
123
|
+
const r = runHook('Write', '/repo/src/index.ts');
|
|
124
|
+
assert.notEqual(r.decision, 'deny');
|
|
125
|
+
assert.match(r.context, /tool=Write/);
|
|
126
|
+
assert.match(r.context, /path=\/repo\/src\/index\.ts/);
|
|
127
|
+
// No debug-artifact warning in the hook context line anymore.
|
|
128
|
+
assert.doesNotMatch(r.context, /console\.log/);
|
|
129
|
+
assert.doesNotMatch(r.context, /Heads up/);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test('Edit .env → deny (same rule applies to Edit)', () => {
|
|
133
|
+
const r = runHook('Edit', '/repo/.env');
|
|
134
|
+
assert.equal(r.decision, 'deny');
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test('MultiEdit .env.example → allow (docs)', () => {
|
|
138
|
+
const r = runHook('MultiEdit', '/repo/.env.example');
|
|
139
|
+
assert.notEqual(r.decision, 'deny');
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test('Unknown tool → no decision (silent pass)', () => {
|
|
143
|
+
const r = runHook('Bash', '/repo/.env');
|
|
144
|
+
// PreToolUse:Bash is handled by a separate hook — this one is a no-op.
|
|
145
|
+
assert.equal(r.decision, null);
|
|
146
|
+
});
|