@bookedsolid/rea 0.1.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/LICENSE +21 -0
- package/README.md +339 -0
- package/SECURITY.md +104 -0
- package/THREAT_MODEL.md +245 -0
- package/agents/accessibility-engineer.md +101 -0
- package/agents/backend-engineer.md +126 -0
- package/agents/code-reviewer.md +144 -0
- package/agents/codex-adversarial.md +107 -0
- package/agents/frontend-specialist.md +84 -0
- package/agents/qa-engineer.md +138 -0
- package/agents/rea-orchestrator.md +101 -0
- package/agents/security-engineer.md +108 -0
- package/agents/technical-writer.md +140 -0
- package/agents/typescript-specialist.md +111 -0
- package/commands/codex-review.md +104 -0
- package/commands/freeze.md +81 -0
- package/commands/halt-check.md +120 -0
- package/commands/rea.md +52 -0
- package/commands/review.md +79 -0
- package/dist/cli/check.d.ts +1 -0
- package/dist/cli/check.js +66 -0
- package/dist/cli/doctor.d.ts +1 -0
- package/dist/cli/doctor.js +93 -0
- package/dist/cli/freeze.d.ts +8 -0
- package/dist/cli/freeze.js +61 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +65 -0
- package/dist/cli/init.d.ts +6 -0
- package/dist/cli/init.js +237 -0
- package/dist/cli/serve.d.ts +1 -0
- package/dist/cli/serve.js +19 -0
- package/dist/cli/utils.d.ts +23 -0
- package/dist/cli/utils.js +51 -0
- package/dist/config/tier-map.d.ts +11 -0
- package/dist/config/tier-map.js +108 -0
- package/dist/config/types.d.ts +24 -0
- package/dist/config/types.js +1 -0
- package/dist/gateway/circuit-breaker.d.ts +43 -0
- package/dist/gateway/circuit-breaker.js +86 -0
- package/dist/gateway/middleware/audit-types.d.ts +16 -0
- package/dist/gateway/middleware/audit-types.js +1 -0
- package/dist/gateway/middleware/audit.d.ts +12 -0
- package/dist/gateway/middleware/audit.js +98 -0
- package/dist/gateway/middleware/blocked-paths.d.ts +12 -0
- package/dist/gateway/middleware/blocked-paths.js +117 -0
- package/dist/gateway/middleware/chain.d.ts +28 -0
- package/dist/gateway/middleware/chain.js +40 -0
- package/dist/gateway/middleware/circuit-breaker.d.ts +11 -0
- package/dist/gateway/middleware/circuit-breaker.js +43 -0
- package/dist/gateway/middleware/injection.d.ts +22 -0
- package/dist/gateway/middleware/injection.js +128 -0
- package/dist/gateway/middleware/kill-switch.d.ts +10 -0
- package/dist/gateway/middleware/kill-switch.js +58 -0
- package/dist/gateway/middleware/policy.d.ts +12 -0
- package/dist/gateway/middleware/policy.js +70 -0
- package/dist/gateway/middleware/rate-limit.d.ts +12 -0
- package/dist/gateway/middleware/rate-limit.js +31 -0
- package/dist/gateway/middleware/redact.d.ts +16 -0
- package/dist/gateway/middleware/redact.js +128 -0
- package/dist/gateway/middleware/result-size-cap.d.ts +13 -0
- package/dist/gateway/middleware/result-size-cap.js +48 -0
- package/dist/gateway/middleware/session.d.ts +10 -0
- package/dist/gateway/middleware/session.js +18 -0
- package/dist/gateway/middleware/tier.d.ts +6 -0
- package/dist/gateway/middleware/tier.js +10 -0
- package/dist/gateway/rate-limiter.d.ts +36 -0
- package/dist/gateway/rate-limiter.js +75 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -0
- package/dist/policy/loader.d.ts +80 -0
- package/dist/policy/loader.js +146 -0
- package/dist/policy/types.d.ts +34 -0
- package/dist/policy/types.js +19 -0
- package/hooks/_lib/common.sh +105 -0
- package/hooks/_lib/halt-check.sh +39 -0
- package/hooks/_lib/policy-read.sh +79 -0
- package/hooks/architecture-review-gate.sh +84 -0
- package/hooks/attribution-advisory.sh +126 -0
- package/hooks/blocked-paths-enforcer.sh +176 -0
- package/hooks/changeset-security-gate.sh +143 -0
- package/hooks/commit-review-gate.sh +166 -0
- package/hooks/dangerous-bash-interceptor.sh +362 -0
- package/hooks/dependency-audit-gate.sh +118 -0
- package/hooks/env-file-protection.sh +110 -0
- package/hooks/pr-issue-link-gate.sh +65 -0
- package/hooks/push-review-gate.sh +120 -0
- package/hooks/secret-scanner.sh +229 -0
- package/hooks/security-disclosure-gate.sh +146 -0
- package/hooks/settings-protection.sh +147 -0
- package/package.json +93 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: typescript-specialist
|
|
3
|
+
description: TypeScript specialist enforcing strict mode, type system design, declaration files, and type safety across the codebase
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# TypeScript Specialist
|
|
7
|
+
|
|
8
|
+
You are the TypeScript specialist for this project.
|
|
9
|
+
|
|
10
|
+
## Project Context Discovery
|
|
11
|
+
|
|
12
|
+
Before acting, read:
|
|
13
|
+
|
|
14
|
+
- `package.json` — TypeScript version, build scripts
|
|
15
|
+
- `tsconfig.json` — strict flags, path aliases, lib targets
|
|
16
|
+
- Framework config (`astro.config.*`, `next.config.*`, etc.)
|
|
17
|
+
- `.rea/policy.yaml` — autonomy level and constraints
|
|
18
|
+
- Existing type patterns in the codebase
|
|
19
|
+
|
|
20
|
+
Adapt to the project's actual TypeScript configuration and conventions.
|
|
21
|
+
|
|
22
|
+
## Your Role
|
|
23
|
+
|
|
24
|
+
- Enforce `"strict": true` across all code
|
|
25
|
+
- Design type interfaces for components, API responses, content collections
|
|
26
|
+
- Resolve type errors in framework frontmatter, components, and web component consumption
|
|
27
|
+
- Ensure component library types work correctly in JSX/TSX contexts
|
|
28
|
+
- Manage `HTMLElementTagNameMap` declarations for custom elements
|
|
29
|
+
|
|
30
|
+
## Standards
|
|
31
|
+
|
|
32
|
+
- Zero `any` — use `unknown` + type guards when the type is truly unknown
|
|
33
|
+
- Zero `@ts-ignore` / `@ts-expect-error` — fix the type, don't suppress
|
|
34
|
+
- Prefer `interface` over `type` for object shapes (better extension)
|
|
35
|
+
- Use `satisfies` for type-safe object literals with inference
|
|
36
|
+
- Use discriminated unions for variant types
|
|
37
|
+
- Use `readonly` for arrays/tuples that should not mutate
|
|
38
|
+
- Use `import type` for type-only imports
|
|
39
|
+
- Export types from barrel files only when consumed externally
|
|
40
|
+
|
|
41
|
+
## Common Patterns
|
|
42
|
+
|
|
43
|
+
### Framework Component Props
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
interface Props {
|
|
47
|
+
title: string;
|
|
48
|
+
description?: string;
|
|
49
|
+
class?: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const { title, description, class: className } = Astro.props;
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### React Component Props
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
interface ServiceCardProps {
|
|
59
|
+
title: string;
|
|
60
|
+
description: string;
|
|
61
|
+
icon: IconDefinition;
|
|
62
|
+
features: readonly string[];
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Custom Element Types
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
declare namespace astroHTML.JSX {
|
|
70
|
+
interface IntrinsicElements {
|
|
71
|
+
'my-button': Record<string, unknown>;
|
|
72
|
+
'my-nav': Record<string, unknown>;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Unknown Narrowing
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
function isServiceCard(value: unknown): value is ServiceCardProps {
|
|
81
|
+
return (
|
|
82
|
+
typeof value === 'object' &&
|
|
83
|
+
value !== null &&
|
|
84
|
+
'title' in value &&
|
|
85
|
+
typeof (value as { title: unknown }).title === 'string'
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Constraints
|
|
91
|
+
|
|
92
|
+
- NEVER use `any` — no exceptions
|
|
93
|
+
- NEVER use `@ts-ignore` or `@ts-expect-error` without a linked issue and sunset date
|
|
94
|
+
- NEVER use non-null assertions (`!`) without proving safety
|
|
95
|
+
- NEVER use `object` or `Function` or `{}` as types — use `Record<string, unknown>` or proper interfaces or specific signatures
|
|
96
|
+
- ALWAYS use `readonly` for arrays/tuples that shouldn't mutate
|
|
97
|
+
- ALWAYS type function parameters explicitly on public APIs
|
|
98
|
+
|
|
99
|
+
## Zero-Trust Protocol
|
|
100
|
+
|
|
101
|
+
1. Read before writing
|
|
102
|
+
2. Never trust LLM memory — verify via tools, git, file reads
|
|
103
|
+
3. Verify before claiming
|
|
104
|
+
4. Validate dependencies — `npm view` before install
|
|
105
|
+
5. Graduated autonomy — respect L0–L3 from `.rea/policy.yaml`
|
|
106
|
+
6. HALT compliance — check `.rea/HALT` before any action
|
|
107
|
+
7. Audit awareness — every tool call may be logged
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
_Part of the [rea](https://github.com/bookedsolidtech/rea) agent team._
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Run an adversarial review of the current branch via the Codex plugin (GPT-5.4). First-class step in the REA engineering process.
|
|
3
|
+
argument-hint: "[diff-target]"
|
|
4
|
+
allowed-tools:
|
|
5
|
+
- Bash(git diff:*)
|
|
6
|
+
- Bash(git log:*)
|
|
7
|
+
- Bash(git branch:*)
|
|
8
|
+
- Bash(git rev-parse:*)
|
|
9
|
+
- Read
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# /codex-review — Adversarial Review via Codex
|
|
13
|
+
|
|
14
|
+
Invokes the Codex plugin (`/codex adversarial-review`) on the current branch's diff, captures the result, and records it to the REA audit log. Adversarial review by an independent model (GPT-5.4) is a **first-class, non-optional step** in the REA engineering process — it is the counterweight to Opus-authored code.
|
|
15
|
+
|
|
16
|
+
## Why this exists
|
|
17
|
+
|
|
18
|
+
The default workflow in REA is Plan → Build → Review, with the Review leg handed to a different model than the one that wrote the code. Codex adversarial review is free, fast, and independent — it catches the mistakes the authoring model is most likely to miss: security assumptions, correctness under edge cases, and logical gaps in tests. Treat it with the same weight as a human second set of eyes.
|
|
19
|
+
|
|
20
|
+
## Arguments
|
|
21
|
+
|
|
22
|
+
- `$ARGUMENTS` (optional) — diff target, same semantics as `/review`. Defaults to `main`.
|
|
23
|
+
|
|
24
|
+
## Preflight
|
|
25
|
+
|
|
26
|
+
1. Read `.rea/policy.yaml` — confirm autonomy is at least L1
|
|
27
|
+
2. Check `.rea/HALT` — if present, stop and report FROZEN
|
|
28
|
+
3. Verify the Codex plugin is installed. If `/codex` is not available in this Claude Code install, report: "Codex plugin not installed. See https://github.com/openai/codex for install steps." and stop.
|
|
29
|
+
|
|
30
|
+
## Step 1 — Resolve the diff target
|
|
31
|
+
|
|
32
|
+
Same logic as `/review`:
|
|
33
|
+
|
|
34
|
+
- Empty `$ARGUMENTS` → `main`
|
|
35
|
+
- Otherwise → use the provided ref
|
|
36
|
+
|
|
37
|
+
Capture:
|
|
38
|
+
|
|
39
|
+
- Current branch name (`git rev-parse --abbrev-ref HEAD`)
|
|
40
|
+
- Head SHA (`git rev-parse HEAD`)
|
|
41
|
+
- Diff target SHA (`git rev-parse <target>`)
|
|
42
|
+
- Commit log from target to HEAD
|
|
43
|
+
|
|
44
|
+
If the diff is empty, stop and report: "No changes to review against `<target>`."
|
|
45
|
+
|
|
46
|
+
## Step 2 — Delegate to codex-adversarial agent
|
|
47
|
+
|
|
48
|
+
Invoke the `codex-adversarial` agent with:
|
|
49
|
+
|
|
50
|
+
- The diff target and head SHA
|
|
51
|
+
- The branch name
|
|
52
|
+
- The commit log summary
|
|
53
|
+
- The full diff text
|
|
54
|
+
|
|
55
|
+
The agent wraps `/codex adversarial-review` and returns structured findings.
|
|
56
|
+
|
|
57
|
+
## Step 3 — Record to audit log
|
|
58
|
+
|
|
59
|
+
Every Codex invocation produces an audit entry. The `codex-adversarial` agent writes it via the middleware chain automatically, but verify the entry was recorded:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
tail -n 1 .rea/audit.jsonl
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
The entry must include:
|
|
66
|
+
|
|
67
|
+
- `tool: "codex-adversarial-review"`
|
|
68
|
+
- `head_sha: <SHA>`
|
|
69
|
+
- `target: <ref>`
|
|
70
|
+
- `finding_count: <N>`
|
|
71
|
+
- `verdict: pass | concerns | blocking`
|
|
72
|
+
|
|
73
|
+
If the audit entry is missing, report it clearly — do not proceed as if the review happened.
|
|
74
|
+
|
|
75
|
+
## Step 4 — Report
|
|
76
|
+
|
|
77
|
+
Print a summary:
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
/codex-review — <branch> vs <target>
|
|
81
|
+
Head SHA: <SHA>
|
|
82
|
+
Verdict: pass | concerns | blocking
|
|
83
|
+
Findings: <total>
|
|
84
|
+
Audit: .rea/audit.jsonl:<entry-index>
|
|
85
|
+
|
|
86
|
+
<grouped findings>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
If the verdict is `blocking`, state plainly: "Do not merge until the blocking findings are addressed."
|
|
90
|
+
|
|
91
|
+
## Pre-merge usage
|
|
92
|
+
|
|
93
|
+
The recommended BST workflow runs `/codex-review` twice:
|
|
94
|
+
|
|
95
|
+
1. After implementation, on the feature branch — catches issues early
|
|
96
|
+
2. Immediately before merge, on the PR branch — records a fresh audit entry that the `push-review-gate` hook can check for freshness
|
|
97
|
+
|
|
98
|
+
Both invocations are cheap. Run both.
|
|
99
|
+
|
|
100
|
+
## Constraints
|
|
101
|
+
|
|
102
|
+
- Read-only with respect to source files. Writes only to `.rea/audit.jsonl` (via middleware).
|
|
103
|
+
- Never silently fails. If Codex is unavailable, unresponsive, or returns an error, surface it to the user and record the failure in audit.
|
|
104
|
+
- Never retries automatically on non-deterministic Codex errors — surface and let the user decide.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Activate the REA kill switch — writes .rea/HALT with a reason, blocking all governed tool calls until unfrozen
|
|
3
|
+
argument-hint: "<reason>"
|
|
4
|
+
allowed-tools:
|
|
5
|
+
- Bash(npx rea freeze:*)
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# /freeze — Activate the Kill Switch
|
|
9
|
+
|
|
10
|
+
Writes `.rea/HALT` with a timestamped reason. Once frozen, every REA-governed tool call (native MCP, proxied downstream, and hook-gated) refuses to execute until `npx rea unfreeze` is run.
|
|
11
|
+
|
|
12
|
+
Use this when:
|
|
13
|
+
|
|
14
|
+
- You see the agent doing something unexpected and you want to stop it immediately
|
|
15
|
+
- You are handing the session off and want to be sure nothing runs unattended
|
|
16
|
+
- A hook or middleware is misbehaving and you need to isolate the problem
|
|
17
|
+
- You are about to do something outside the normal governance envelope and want an obvious tripwire
|
|
18
|
+
|
|
19
|
+
## Arguments
|
|
20
|
+
|
|
21
|
+
- `$ARGUMENTS` (required) — a short reason (one sentence). If empty, prompt the user for one before proceeding. Never freeze without a reason.
|
|
22
|
+
|
|
23
|
+
## Preflight
|
|
24
|
+
|
|
25
|
+
1. Read `.rea/policy.yaml` — confirm REA is installed. If missing, report "REA not initialized" and stop.
|
|
26
|
+
2. Check whether `.rea/HALT` already exists. If it does, show the existing reason and ask whether to overwrite.
|
|
27
|
+
|
|
28
|
+
## Step 1 — Validate the reason
|
|
29
|
+
|
|
30
|
+
- If `$ARGUMENTS` is empty or whitespace, prompt: "Reason is required. Describe why you are freezing this session."
|
|
31
|
+
- If the reason is a placeholder like "test", "asdf", or "freeze", confirm with the user — the reason ends up in the audit log and should be meaningful.
|
|
32
|
+
|
|
33
|
+
## Step 2 — Invoke the freeze CLI
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npx rea freeze --reason "$ARGUMENTS"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
This command:
|
|
40
|
+
|
|
41
|
+
1. Writes `.rea/HALT` with a JSON payload: `{ reason, timestamp, invoker: "slash-command" }`
|
|
42
|
+
2. Appends an entry to `.rea/audit.jsonl`
|
|
43
|
+
3. Returns exit code 0 on success, non-zero on failure
|
|
44
|
+
|
|
45
|
+
## Step 3 — Confirm
|
|
46
|
+
|
|
47
|
+
Print the confirmation plainly:
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
REA session FROZEN
|
|
51
|
+
Reason: <reason>
|
|
52
|
+
Timestamp: <ISO-8601>
|
|
53
|
+
HALT file: .rea/HALT
|
|
54
|
+
|
|
55
|
+
All governed tool calls are now blocked. To resume: npx rea unfreeze
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Behavior under HALT
|
|
59
|
+
|
|
60
|
+
Once `.rea/HALT` is present:
|
|
61
|
+
|
|
62
|
+
- Every hook checks `hooks/_lib/halt-check.sh` at its top and exits non-zero (blocked)
|
|
63
|
+
- Every middleware invocation checks `kill-switch` first and refuses
|
|
64
|
+
- Slash commands that take actions (not read-only status commands) report FROZEN and refuse to proceed
|
|
65
|
+
- `/rea` continues to work — it is read-only and needs to be able to report the frozen state
|
|
66
|
+
|
|
67
|
+
## Unfreezing
|
|
68
|
+
|
|
69
|
+
Unfreezing is explicit and requires its own command:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npx rea unfreeze --reason "<why it is safe to resume>"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The slash-command variant is not provided on purpose — unfreezing should be a deliberate CLI action, not a one-keystroke reflex.
|
|
76
|
+
|
|
77
|
+
## Constraints
|
|
78
|
+
|
|
79
|
+
- Writes only to `.rea/HALT` and `.rea/audit.jsonl`. Never modifies policy, source files, or git state.
|
|
80
|
+
- Does not auto-unfreeze on any condition. HALT is sticky.
|
|
81
|
+
- If the CLI is unavailable, fall back to writing the HALT file directly with `printf`, but record this in the audit log as a CLI-unavailable fallback.
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Smoke test — verify every hook and middleware respects the HALT kill switch. Advisory, read-only.
|
|
3
|
+
allowed-tools:
|
|
4
|
+
- Bash(npx rea check:*)
|
|
5
|
+
- Bash(ls:*)
|
|
6
|
+
- Read
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# /halt-check — Kill Switch Smoke Test
|
|
10
|
+
|
|
11
|
+
Verifies that the REA HALT kill switch is actually enforced end-to-end: hooks check for `.rea/HALT` at their top, middleware short-circuits on kill-switch, and governed tool calls are denied when the file is present. Run this after any change to hooks, middleware, or `.claude/settings.json`. Run it at least once per release.
|
|
12
|
+
|
|
13
|
+
This command is **advisory and read-only**. It writes a temporary HALT file, observes behavior, and removes it — but the observation is all through safe, declarative checks. It never issues destructive tool calls to probe the system.
|
|
14
|
+
|
|
15
|
+
## Preflight
|
|
16
|
+
|
|
17
|
+
1. Read `.rea/policy.yaml` — confirm REA is installed
|
|
18
|
+
2. Check if `.rea/HALT` already exists. If it does, report "Session already frozen — cannot run smoke test without disturbing existing HALT. Unfreeze first." and stop.
|
|
19
|
+
3. Verify the user has permission — this is an L1+ operation because it writes `.rea/HALT` (briefly).
|
|
20
|
+
|
|
21
|
+
## Step 1 — Baseline check
|
|
22
|
+
|
|
23
|
+
Before writing HALT, capture the baseline:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npx rea check --json
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Record:
|
|
30
|
+
|
|
31
|
+
- `halt_present: false` (must be)
|
|
32
|
+
- `autonomy_level`
|
|
33
|
+
- `profile`
|
|
34
|
+
- `hook_count` from `.claude/settings.json`
|
|
35
|
+
- `middleware_enabled` list
|
|
36
|
+
|
|
37
|
+
If the baseline reports `halt_present: true`, stop — the smoke test requires a clean starting state.
|
|
38
|
+
|
|
39
|
+
## Step 2 — Write the test HALT
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
printf '{"reason":"halt-check smoke test","timestamp":"%s","invoker":"halt-check"}\n' "$(date -u +%FT%TZ)" > .rea/HALT
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Confirm the file exists and is readable:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
ls -la .rea/HALT
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Step 3 — Verify denial paths
|
|
52
|
+
|
|
53
|
+
Run the diagnostic CLI which simulates representative tool calls through the middleware without actually executing them:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npx rea check --simulate
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Expected output: each simulated call returns `denied: kill-switch`. Record the results.
|
|
60
|
+
|
|
61
|
+
Then inspect the hook library — every hook should source `hooks/_lib/halt-check.sh`:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
for hook in .claude/hooks/*.sh; do
|
|
65
|
+
if ! grep -q 'halt-check.sh' "$hook"; then
|
|
66
|
+
echo "MISSING HALT CHECK: $hook"
|
|
67
|
+
fi
|
|
68
|
+
done
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Any hook that does not source `halt-check.sh` is a finding.
|
|
72
|
+
|
|
73
|
+
## Step 4 — Remove the test HALT
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
rm .rea/HALT
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Then verify removal:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
npx rea check --json | grep halt_present
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Must report `halt_present: false`.
|
|
86
|
+
|
|
87
|
+
## Step 5 — Report
|
|
88
|
+
|
|
89
|
+
Print a structured result:
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
/halt-check — HALT smoke test
|
|
93
|
+
Baseline: clean (halt_present=false)
|
|
94
|
+
HALT written: ok
|
|
95
|
+
Middleware denial: <N of M> layers returned denied
|
|
96
|
+
Hook coverage: <N of M> hooks source halt-check.sh
|
|
97
|
+
HALT removed: ok
|
|
98
|
+
Final state: clean
|
|
99
|
+
|
|
100
|
+
Missing coverage:
|
|
101
|
+
- <list of hooks without halt-check.sh, if any>
|
|
102
|
+
|
|
103
|
+
Middleware gaps:
|
|
104
|
+
- <list of layers that did not short-circuit, if any>
|
|
105
|
+
|
|
106
|
+
Verdict: PASS | CONCERNS | FAIL
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Failure modes
|
|
110
|
+
|
|
111
|
+
- **Any hook missing halt-check.sh** → FAIL. Hooks that do not check HALT can run during a frozen session.
|
|
112
|
+
- **Any middleware layer that executes past kill-switch** → FAIL. The ordering guarantee is the whole point.
|
|
113
|
+
- **`.rea/HALT` removal fails** → FAIL loudly. Do not exit until the file is cleaned up. Instruct the user to remove it manually if needed.
|
|
114
|
+
- **CLI unavailable** → CONCERNS, not FAIL. The shell-based hook audit still runs.
|
|
115
|
+
|
|
116
|
+
## Constraints
|
|
117
|
+
|
|
118
|
+
- Never destructive. The only file written and removed is `.rea/HALT`.
|
|
119
|
+
- Never issues real tool calls during the test — only `--simulate` through the CLI. Real tool calls would pollute the audit log with denied entries and could have side effects if a hook does not correctly short-circuit.
|
|
120
|
+
- Always cleans up, even on partial failure. If cleanup fails, exit non-zero and print the cleanup instruction prominently.
|
package/commands/rea.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Print REA session status — autonomy level, HALT state, policy profile, and recent audit entries
|
|
3
|
+
allowed-tools:
|
|
4
|
+
- Bash(npx rea check:*)
|
|
5
|
+
- Read
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# /rea — Session Status
|
|
9
|
+
|
|
10
|
+
Prints a concise status overview of the REA governance layer for the current project. Use this at the start of a session, after policy changes, or whenever you need to confirm the runtime posture before acting.
|
|
11
|
+
|
|
12
|
+
## What it reports
|
|
13
|
+
|
|
14
|
+
- **Autonomy level** — current `autonomy_level` from `.rea/policy.yaml` (L0–L3) and the `max_autonomy_level` ceiling
|
|
15
|
+
- **HALT status** — whether `.rea/HALT` exists (FROZEN vs. ACTIVE) and, if frozen, the reason
|
|
16
|
+
- **Policy profile** — the active profile (e.g. `bst-internal`, `client-engagement`, `minimal`)
|
|
17
|
+
- **Blocked paths** — paths the middleware chain refuses to touch
|
|
18
|
+
- **Attribution gating** — `block_ai_attribution` on/off
|
|
19
|
+
- **Recent audit entries** — last 5 entries from `.rea/audit.jsonl` with tool name, decision, and timestamp
|
|
20
|
+
|
|
21
|
+
## Behavior
|
|
22
|
+
|
|
23
|
+
1. Invoke the CLI: `npx rea check`
|
|
24
|
+
2. Render the output verbatim — do not interpret, summarize, or add commentary unless the user asks
|
|
25
|
+
3. If `.rea/policy.yaml` is missing, report: "REA not initialized in this project. Run `npx rea init` to scaffold."
|
|
26
|
+
4. If `.rea/HALT` exists, highlight the FROZEN state prominently — the user needs to see this first
|
|
27
|
+
|
|
28
|
+
## Constraints
|
|
29
|
+
|
|
30
|
+
- Read-only. This command never writes to `.rea/` or any project file.
|
|
31
|
+
- If the CLI is not available (`npx rea check` fails), report the error and suggest `pnpm install` or `npm install -g @bookedsolid/rea`.
|
|
32
|
+
- Never print the contents of `audit.jsonl` beyond what `npx rea check` surfaces — the audit log may contain redacted payloads and should be accessed through the CLI, not directly.
|
|
33
|
+
|
|
34
|
+
## Typical output shape
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
REA Status
|
|
38
|
+
Profile: bst-internal
|
|
39
|
+
Autonomy: L1 (ceiling L2)
|
|
40
|
+
HALT: ACTIVE (unfrozen)
|
|
41
|
+
Attribution gate: enforced
|
|
42
|
+
Blocked paths: .env, .env.*, .rea/, node_modules/
|
|
43
|
+
|
|
44
|
+
Recent audit (last 5):
|
|
45
|
+
2026-04-18T10:42:11Z Bash allowed
|
|
46
|
+
2026-04-18T10:41:58Z Write allowed
|
|
47
|
+
2026-04-18T10:41:22Z Edit denied (blocked-paths)
|
|
48
|
+
2026-04-18T10:40:03Z mcp__helixir__* allowed
|
|
49
|
+
2026-04-18T10:39:47Z Bash allowed
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
If the user wants more detail, point them at `npx rea check --verbose` or `npx rea doctor`.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Run the code-reviewer agent against the current branch's diff and produce structured findings
|
|
3
|
+
argument-hint: "[diff-target]"
|
|
4
|
+
allowed-tools:
|
|
5
|
+
- Bash(git diff:*)
|
|
6
|
+
- Bash(git log:*)
|
|
7
|
+
- Bash(git branch:*)
|
|
8
|
+
- Bash(git status:*)
|
|
9
|
+
- Read
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# /review — Code Review on Current Changes
|
|
13
|
+
|
|
14
|
+
Invokes the `code-reviewer` agent on the uncommitted and/or branched changes in the current working tree. Use this as a first-pass quality gate before you open a PR.
|
|
15
|
+
|
|
16
|
+
## Arguments
|
|
17
|
+
|
|
18
|
+
- `$ARGUMENTS` (optional) — diff target. Defaults to `main`. Examples:
|
|
19
|
+
- `/review` → diff against `main`
|
|
20
|
+
- `/review staging` → diff against `staging`
|
|
21
|
+
- `/review HEAD~3` → diff against three commits back
|
|
22
|
+
- `/review --staged` → only staged changes
|
|
23
|
+
|
|
24
|
+
## Preflight
|
|
25
|
+
|
|
26
|
+
1. Read `.rea/policy.yaml` — confirm autonomy is at least L1 (review is read-only, so L0 also permitted)
|
|
27
|
+
2. Check `.rea/HALT` — if present, stop and report FROZEN
|
|
28
|
+
3. Verify you are inside a git repo: `git rev-parse --show-toplevel`
|
|
29
|
+
|
|
30
|
+
## Step 1 — Gather the diff
|
|
31
|
+
|
|
32
|
+
Resolve the diff target:
|
|
33
|
+
|
|
34
|
+
- If `$ARGUMENTS` is empty → use `main`
|
|
35
|
+
- If `$ARGUMENTS` starts with `--staged` → use `git diff --staged`
|
|
36
|
+
- Otherwise → use `git diff $ARGUMENTS...HEAD`
|
|
37
|
+
|
|
38
|
+
Run in parallel:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
git diff <target>...HEAD
|
|
42
|
+
git log <target>..HEAD --oneline
|
|
43
|
+
git status --short
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
If the diff is empty, stop and report: "No changes to review against `<target>`."
|
|
47
|
+
|
|
48
|
+
## Step 2 — Delegate to code-reviewer
|
|
49
|
+
|
|
50
|
+
Invoke the `code-reviewer` agent with:
|
|
51
|
+
|
|
52
|
+
- **Tier**: `standard` (default). For diffs over 500 lines or cross-module changes, escalate to `senior`.
|
|
53
|
+
- **Context**: the full diff, the commit log, and the current branch name
|
|
54
|
+
- **Project config**: pass paths to `package.json`, `tsconfig.json`, and `.rea/policy.yaml` so the reviewer can adapt to the project's standards
|
|
55
|
+
|
|
56
|
+
Prompt shape for the delegation:
|
|
57
|
+
|
|
58
|
+
> Review the following git diff at tier `<standard|senior>`. Produce structured findings:
|
|
59
|
+
> each finding has file, line, severity (high/medium/low), issue, and suggestion_code when applicable.
|
|
60
|
+
> Output JSON array. Empty array if no findings. Diff follows.
|
|
61
|
+
|
|
62
|
+
## Step 3 — Summarize
|
|
63
|
+
|
|
64
|
+
Print a clean summary:
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
/review — <branch> vs <target>
|
|
68
|
+
Files changed: <N>
|
|
69
|
+
Findings: <total> (<high> high, <medium> medium, <low> low)
|
|
70
|
+
|
|
71
|
+
<grouped findings by severity, most severe first>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
If the user asks "post this to a PR", invoke `/review-pr <PR#>` instead — that is the PR-posting variant and requires a PR number.
|
|
75
|
+
|
|
76
|
+
## Constraints
|
|
77
|
+
|
|
78
|
+
- Read-only. Never writes to files, never creates commits, never pushes.
|
|
79
|
+
- If `code-reviewer` returns invalid JSON, report the raw output and stop — do not retry automatically.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runCheck(): void;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { loadPolicy } from '../policy/loader.js';
|
|
3
|
+
import { AUDIT_FILE, HALT_FILE, POLICY_FILE, err, exitWithMissingPolicy, log, reaPath, } from './utils.js';
|
|
4
|
+
const AUDIT_TAIL_LINES = 5;
|
|
5
|
+
function readLastLines(filePath, n) {
|
|
6
|
+
try {
|
|
7
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
8
|
+
const lines = content.split('\n').filter((line) => line.length > 0);
|
|
9
|
+
return lines.slice(-n);
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export function runCheck() {
|
|
16
|
+
const baseDir = process.cwd();
|
|
17
|
+
const policyPath = reaPath(baseDir, POLICY_FILE);
|
|
18
|
+
const haltPath = reaPath(baseDir, HALT_FILE);
|
|
19
|
+
const auditPath = reaPath(baseDir, AUDIT_FILE);
|
|
20
|
+
if (!fs.existsSync(policyPath)) {
|
|
21
|
+
exitWithMissingPolicy(policyPath);
|
|
22
|
+
}
|
|
23
|
+
let policy;
|
|
24
|
+
try {
|
|
25
|
+
policy = loadPolicy(baseDir);
|
|
26
|
+
}
|
|
27
|
+
catch (e) {
|
|
28
|
+
err(`Failed to parse policy: ${e instanceof Error ? e.message : String(e)}`);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
console.log('');
|
|
32
|
+
log(`Status — ${baseDir}`);
|
|
33
|
+
console.log('');
|
|
34
|
+
console.log(` Profile: ${policy.profile}`);
|
|
35
|
+
console.log(` Autonomy level: ${policy.autonomy_level}`);
|
|
36
|
+
console.log(` Max autonomy: ${policy.max_autonomy_level}`);
|
|
37
|
+
console.log(` Block AI attribution: ${policy.block_ai_attribution ? 'yes' : 'no'}`);
|
|
38
|
+
console.log(` Blocked paths: ${policy.blocked_paths.length} entries`);
|
|
39
|
+
if (fs.existsSync(haltPath)) {
|
|
40
|
+
const reason = fs.readFileSync(haltPath, 'utf8').trim();
|
|
41
|
+
console.log('');
|
|
42
|
+
console.log(' HALT: ACTIVE');
|
|
43
|
+
console.log(` ${reason}`);
|
|
44
|
+
console.log(' Run `rea unfreeze` to resume.');
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
console.log(` HALT: inactive`);
|
|
48
|
+
}
|
|
49
|
+
console.log('');
|
|
50
|
+
if (fs.existsSync(auditPath)) {
|
|
51
|
+
const tail = readLastLines(auditPath, AUDIT_TAIL_LINES);
|
|
52
|
+
if (tail.length === 0) {
|
|
53
|
+
console.log(` Audit log: .rea/audit.jsonl (empty)`);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
console.log(` Audit log: last ${tail.length} entries (.rea/audit.jsonl)`);
|
|
57
|
+
for (const entry of tail) {
|
|
58
|
+
console.log(` ${entry.slice(0, 160)}${entry.length > 160 ? '…' : ''}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
console.log(` Audit log: not yet written`);
|
|
64
|
+
}
|
|
65
|
+
console.log('');
|
|
66
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runDoctor(): void;
|