odd-studio 1.0.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.
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "odd-studio",
3
+ "description": "Outcome-Driven Development — a planning and build harness for domain experts building serious software with AI. Installs the /odd skill, safety hooks, and project scaffolding into Claude Code.",
4
+ "version": "1.0.0",
5
+ "author": {
6
+ "name": "ODD Studio"
7
+ },
8
+ "skills": [
9
+ "odd"
10
+ ],
11
+ "hooks": [
12
+ "odd-git-safety",
13
+ "odd-destructive-guard",
14
+ "odd-outcome-quality",
15
+ "odd-ui-check",
16
+ "odd-pre-build",
17
+ "odd-session-save"
18
+ ]
19
+ }
package/README.md ADDED
@@ -0,0 +1,229 @@
1
+ # ODD Studio
2
+
3
+ **Outcome-Driven Development for Claude Code.**
4
+
5
+ A planning and build harness for domain experts who are building serious software with AI — and want to understand exactly what they're doing and why.
6
+
7
+ ---
8
+
9
+ ## What this is
10
+
11
+ ODD Studio turns Claude Code into a guided coach that takes you through every stage of building a real software system: from understanding your users, to specifying what the system must do, to directing an AI to build it correctly, to verifying that what was built matches what you intended.
12
+
13
+ You don't need to write code. You need to understand your domain. That's the skill that matters now.
14
+
15
+ > *"The AI is the most capable junior engineer who ever lived. It can build anything you describe. It will build exactly what you describe. It will not tell you that what you described is the wrong thing to build. That judgement remains entirely yours."*
16
+
17
+ ODD Studio is the companion tool to **[Book Title]** — the book that teaches Outcome-Driven Development from first principles. Every step in the tool references the relevant chapter. You'll understand the method as you use it, not just follow instructions.
18
+
19
+ ---
20
+
21
+ ## Install
22
+
23
+ ```bash
24
+ npx odd-studio init my-project
25
+ ```
26
+
27
+ That's it. This single command:
28
+
29
+ - Scaffolds your project structure (`docs/`, `.odd/`, `CLAUDE.md`)
30
+ - Installs the `/odd` skill into Claude Code
31
+ - Installs six safety hooks into your Claude Code settings
32
+ - Initialises git with an initial commit
33
+ - Prints your three next steps
34
+
35
+ **Then:**
36
+
37
+ ```bash
38
+ cd my-project
39
+ claude .
40
+ ```
41
+
42
+ Inside Claude Code, type:
43
+
44
+ ```
45
+ /odd
46
+ ```
47
+
48
+ ---
49
+
50
+ ## What happens when you type `/odd`
51
+
52
+ Claude Code loads the ODD orchestrator. It checks whether you have an existing project in progress (via your local `.odd/state.json` and ruflo memory) and either:
53
+
54
+ - **New project:** Welcomes you, explains what you're about to build together, and starts with the first question: *Who uses this system, and what do they actually need?*
55
+ - **Returning project:** Shows you exactly where you left off and resumes from there. Nothing is lost between sessions.
56
+
57
+ ---
58
+
59
+ ## The five stages
60
+
61
+ ODD Studio guides you through five stages, in order. You cannot skip ahead — each stage is the foundation for the next.
62
+
63
+ ```
64
+ Stage 1 — Personas
65
+ Who uses your system? Under what constraints?
66
+ Built by: Diana (Persona Architect)
67
+ Output: docs/personas/[name].md for each user type
68
+
69
+ Stage 2 — Outcomes
70
+ What must the system make possible, for whom, when, and how?
71
+ Built by: Marcus (Outcome Writer)
72
+ Output: docs/outcomes/[name].md for each workflow
73
+
74
+ Stage 3 — Contracts
75
+ What does each outcome produce that others depend on?
76
+ Built by: Theo (Systems Mapper)
77
+ Output: docs/contract-map.md
78
+
79
+ Stage 4 — Master Implementation Plan
80
+ What gets built in what order, and why?
81
+ Built by: Rachel (Build Planner)
82
+ Output: docs/plan.md
83
+
84
+ Stage 5 — Build
85
+ Direct Claude Code to build outcome by outcome, verify each one,
86
+ and integrate them into a working system.
87
+ Powered by: ruflo swarm (parallel specialist agents)
88
+ ```
89
+
90
+ At every step, the tool explains why the step matters — not just what to do.
91
+
92
+ ---
93
+
94
+ ## The safety layer
95
+
96
+ ODD Studio installs six hooks into Claude Code that run automatically throughout your build:
97
+
98
+ | Hook | When | What it does |
99
+ |------|------|-------------|
100
+ | `odd-git-safety` | Before any bash command | Blocks force-push, hard-reset with uncommitted changes, `git checkout -- .`, `--no-verify` |
101
+ | `odd-destructive-guard` | Before any bash command | Blocks `rm -rf` on project docs, `.env` commits, database drops without warning |
102
+ | `odd-outcome-quality` | After writing to `docs/outcomes/` | Checks all 6 outcome fields are present; flags banned technical vocabulary |
103
+ | `odd-ui-check` | After editing frontend files | Surfaces accessibility reminders; prompts mobile verification |
104
+ | `odd-pre-build` | Before `npm run build` or deploy | Warns on uncommitted changes before deploy; flags unreviewed outcomes |
105
+ | `odd-session-save` | After `git commit` | Saves project state to `.odd/state.json` for session continuity |
106
+
107
+ These hooks inform and protect — they don't block legitimate work. The git hooks block genuinely destructive actions (force-push onto main, committing secrets). Everything else warns and coaches.
108
+
109
+ ---
110
+
111
+ ## The build layer (ruflo)
112
+
113
+ When you're ready to build, ODD Studio initialises a ruflo swarm — a team of parallel specialist agents that build your outcomes concurrently:
114
+
115
+ - **Coordinator** — reads your contracts, publishes shared technical contracts before parallel building begins (solves the "two architects, one door" problem)
116
+ - **Backend agent** — implements data layer and business logic per your outcome specifications
117
+ - **UI agent** — implements the frontend using shadcn/ui, Tailwind CSS v4, and Framer Motion, against WCAG 2.1 AA accessibility standards
118
+ - **QA agent** — runs your verification steps and reports failures in your language, not technical error messages
119
+
120
+ Ruflo memory ensures continuity across Claude Code sessions — every agent knows the full project state.
121
+
122
+ ---
123
+
124
+ ## Default tech stack
125
+
126
+ ODD Studio configures a considered default stack that handles 90% of projects well:
127
+
128
+ | Layer | Technology | Why |
129
+ |-------|-----------|-----|
130
+ | Framework | Next.js (App Router) + TypeScript | Server-rendered, fast, well-supported |
131
+ | Styling | Tailwind CSS v4 | Consistent design without custom CSS |
132
+ | Components | shadcn/ui | Beautiful, accessible, you own the code |
133
+ | Primitives | Radix UI | Keyboard navigation and ARIA built in |
134
+ | Animation | Framer Motion | Micro-interactions without complexity |
135
+ | Database | PostgreSQL via Prisma | Reliable, type-safe, good migrations |
136
+ | Auth | NextAuth.js | Handles the complexity you don't want to |
137
+ | Payments | Stripe | The right choice for most use cases |
138
+ | Email | Resend | Modern, reliable, developer-friendly |
139
+ | Deploy | Vercel | Zero-configuration deployment |
140
+
141
+ The AI proposes the stack based on your outcomes. You approve it based on consequences, not technical details. If your outcomes require something different (offline-capable, specific hosting requirements, existing systems to integrate with), tell the AI in domain terms and it will adapt.
142
+
143
+ ---
144
+
145
+ ## Project structure
146
+
147
+ After `odd-studio init`, your project looks like this:
148
+
149
+ ```
150
+ my-project/
151
+ ├── CLAUDE.md ← ODD build rules for Claude Code
152
+ ├── .odd/
153
+ │ └── state.json ← Project state (updated automatically)
154
+ └── docs/
155
+ ├── plan.md ← Master Implementation Plan
156
+ ├── contract-map.md ← Contracts and dependency graph
157
+ ├── personas/ ← One file per user type
158
+ │ └── example-persona.md ← Example to learn from (then delete)
159
+ ├── outcomes/ ← One file per workflow
160
+ │ └── example-outcome.md ← Example to learn from (then delete)
161
+ └── ui/ ← UI specifications per outcome
162
+ ```
163
+
164
+ ---
165
+
166
+ ## Commands inside `/odd`
167
+
168
+ ```
169
+ *plan Start or resume planning (routes to the right stage)
170
+ *build Start or resume building with ruflo swarm
171
+ *status Show full project state
172
+ *persona Jump to persona creation
173
+ *outcome Jump to outcome writing
174
+ *contracts Jump to contract mapping
175
+ *phase-plan Jump to implementation planning
176
+ *ui Load UI excellence layer briefing
177
+ *swarm Initialise ruflo swarm for parallel build
178
+ *export Generate IDE Session Brief → docs/session-brief.md
179
+ *chapter [n] Load coaching from relevant book chapter
180
+ *why Explain why the current step matters
181
+ *kb Load full ODD knowledge base
182
+ *help Show all commands
183
+ *reset Clear state and start over (asks for confirmation)
184
+ ```
185
+
186
+ ---
187
+
188
+ ## Other CLI commands
189
+
190
+ ```bash
191
+ odd-studio status # Show current planning state for this project
192
+ odd-studio upgrade # Update the /odd skill and hooks to latest version
193
+ odd-studio export # Instructions for exporting the Session Brief
194
+ ```
195
+
196
+ ---
197
+
198
+ ## What you'll learn
199
+
200
+ By the time you've built your first system with ODD Studio, you'll understand:
201
+
202
+ - Why your users' constraints — not their preferences — determine good software design
203
+ - Why the connections between features matter more than the features themselves
204
+ - How to describe what you want precisely enough that an AI builds it correctly
205
+ - How to verify that what was built matches what you intended
206
+ - How to direct a build across multiple sessions without losing context
207
+ - How to catch problems before they become expensive to fix
208
+
209
+ These are the skills that make you effective at building with AI — permanently, not just for this project.
210
+
211
+ ---
212
+
213
+ ## The book
214
+
215
+ ODD Studio implements the methodology from **[Book Title]**. Each step in the tool references the chapter that explains the underlying principle. The book and the tool are the same learning experience — you can start with either.
216
+
217
+ ---
218
+
219
+ ## Requirements
220
+
221
+ - Node.js 18+
222
+ - Claude Code installed (`npm install -g @anthropic-ai/claude-code`)
223
+ - ruflo MCP configured in Claude Code (for swarm build features)
224
+
225
+ ---
226
+
227
+ ## License
228
+
229
+ MIT
@@ -0,0 +1,212 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ import { program } from 'commander';
5
+ import chalk from 'chalk';
6
+ import ora from 'ora';
7
+ import { createRequire } from 'module';
8
+ import { fileURLToPath } from 'url';
9
+ import path from 'path';
10
+ import fs from 'fs-extra';
11
+
12
+ const __filename = fileURLToPath(import.meta.url);
13
+ const __dirname = path.dirname(__filename);
14
+ const require = createRequire(import.meta.url);
15
+ const pkg = require('../package.json');
16
+
17
+ const PACKAGE_ROOT = path.resolve(__dirname, '..');
18
+
19
+ // ─── Visual helpers ──────────────────────────────────────────────────────────
20
+
21
+ const print = {
22
+ logo: () => {
23
+ console.log(chalk.bold.cyan('\n 🎯 ODD Studio'));
24
+ console.log(chalk.dim(' Outcome-Driven Development for Claude Code\n'));
25
+ },
26
+ step: (n, total, msg) => console.log(chalk.dim(` [${n}/${total}]`) + ' ' + msg),
27
+ ok: (msg) => console.log(chalk.green(' ✓ ') + msg),
28
+ warn: (msg) => console.log(chalk.yellow(' ⚠ ') + msg),
29
+ err: (msg) => console.log(chalk.red(' ✗ ') + msg),
30
+ info: (msg) => console.log(chalk.dim(' → ') + msg),
31
+ blank: () => console.log(),
32
+ };
33
+
34
+ // ─── CLI definition ───────────────────────────────────────────────────────────
35
+
36
+ program
37
+ .name('odd-studio')
38
+ .description('Outcome-Driven Development harness for Claude Code')
39
+ .version(pkg.version);
40
+
41
+ // ── init ──────────────────────────────────────────────────────────────────────
42
+ program
43
+ .command('init [project-name]')
44
+ .description('Scaffold a new ODD project and install the /odd skill into Claude Code')
45
+ .option('--skip-skill', 'Skip installing the /odd skill globally (advanced)')
46
+ .option('--skip-hooks', 'Skip installing safety hooks (not recommended)')
47
+ .option('--yes', 'Accept all defaults without prompting')
48
+ .action(async (projectName, options) => {
49
+ print.logo();
50
+
51
+ const { default: installSkill } = await import('../scripts/install-skill.js');
52
+ const { default: setupHooks } = await import('../scripts/setup-hooks.js');
53
+ const { default: scaffoldProject } = await import('../scripts/scaffold-project.js');
54
+
55
+ // Resolve project directory
56
+ const targetDir = projectName
57
+ ? path.resolve(process.cwd(), projectName)
58
+ : process.cwd();
59
+
60
+ const resolvedName = projectName || path.basename(process.cwd());
61
+
62
+ console.log(chalk.bold(` Setting up: ${chalk.cyan(resolvedName)}\n`));
63
+
64
+ // 1. Scaffold project structure
65
+ print.step(1, 3, 'Creating project structure...');
66
+ const spinner1 = ora({ text: '', indent: 4 }).start();
67
+ try {
68
+ await scaffoldProject(targetDir, resolvedName);
69
+ spinner1.stop();
70
+ print.ok('Project scaffolded at ' + chalk.cyan(targetDir));
71
+ } catch (e) {
72
+ spinner1.stop();
73
+ print.err('Failed to scaffold project: ' + e.message);
74
+ process.exit(1);
75
+ }
76
+
77
+ // 2. Install /odd skill
78
+ if (!options.skipSkill) {
79
+ print.step(2, 3, 'Installing /odd skill into Claude Code...');
80
+ const spinner2 = ora({ text: '', indent: 4 }).start();
81
+ try {
82
+ const result = await installSkill(PACKAGE_ROOT);
83
+ spinner2.stop();
84
+ print.ok('Skill installed → ' + chalk.cyan(result.destination));
85
+ } catch (e) {
86
+ spinner2.stop();
87
+ print.warn('Could not install skill automatically: ' + e.message);
88
+ print.info('Manual install: copy ' + chalk.dim('skill/') + ' to ' + chalk.dim('~/.claude/skills/odd/'));
89
+ }
90
+ } else {
91
+ print.step(2, 3, 'Skipping skill install (--skip-skill)');
92
+ print.warn('Remember to install the skill manually for /odd to work in Claude Code.');
93
+ }
94
+
95
+ // 3. Setup hooks
96
+ if (!options.skipHooks) {
97
+ print.step(3, 3, 'Installing safety hooks into Claude Code settings...');
98
+ const spinner3 = ora({ text: '', indent: 4 }).start();
99
+ try {
100
+ const result = await setupHooks(PACKAGE_ROOT);
101
+ spinner3.stop();
102
+ print.ok('Hooks installed → ' + result.hookCount + ' hooks active');
103
+ } catch (e) {
104
+ spinner3.stop();
105
+ print.warn('Could not install hooks automatically: ' + e.message);
106
+ print.info('Manual install: add entries from ' + chalk.dim('hooks/') + ' to ~/.claude/settings.json');
107
+ }
108
+ } else {
109
+ print.step(3, 3, 'Skipping hooks (--skip-hooks)');
110
+ print.warn('Safety hooks not installed. Git guardrails and quality gates will not run.');
111
+ }
112
+
113
+ // ── Done ──
114
+ print.blank();
115
+ console.log(chalk.bold.green(' ✓ ODD Studio is ready.\n'));
116
+
117
+ console.log(chalk.bold(' Next steps:'));
118
+ console.log(chalk.dim(' ─────────────────────────────────────────'));
119
+ if (projectName) {
120
+ console.log(' 1. ' + chalk.cyan(`cd ${projectName}`));
121
+ }
122
+ console.log(' ' + (projectName ? '2' : '1') + '. Open Claude Code: ' + chalk.cyan('claude .'));
123
+ console.log(' ' + (projectName ? '3' : '2') + '. Start your ODD session: ' + chalk.cyan('/odd'));
124
+ print.blank();
125
+
126
+ console.log(chalk.dim(' ODD Studio implements Outcome-Driven Development.'));
127
+ console.log(chalk.dim(' At every step, you\'ll understand why — not just what to do.'));
128
+ print.blank();
129
+ });
130
+
131
+ // ── status ────────────────────────────────────────────────────────────────────
132
+ program
133
+ .command('status')
134
+ .description('Show the ODD planning status for the current project')
135
+ .action(async () => {
136
+ print.logo();
137
+ const stateFile = path.resolve(process.cwd(), '.odd', 'state.json');
138
+ if (!fs.existsSync(stateFile)) {
139
+ print.warn('No ODD state found in this directory.');
140
+ print.info('Run ' + chalk.cyan('odd-studio init') + ' to initialise a project, or ' + chalk.cyan('cd') + ' into an existing ODD project.');
141
+ process.exit(0);
142
+ }
143
+ const state = await fs.readJson(stateFile);
144
+ console.log(chalk.bold(' Project: ') + chalk.cyan(state.projectName || 'unnamed'));
145
+ console.log(chalk.bold(' Phase: ') + (state.currentPhase || 'Not started'));
146
+ console.log(chalk.bold(' Step: ') + (state.currentStep || 'Not started'));
147
+ print.blank();
148
+ if (state.personas?.length) {
149
+ console.log(chalk.bold(' Personas (' + state.personas.length + '):'));
150
+ state.personas.forEach(p => console.log(' ' + chalk.green('✓ ') + p));
151
+ }
152
+ if (state.outcomes?.length) {
153
+ console.log(chalk.bold(' Outcomes (' + state.outcomes.length + '):'));
154
+ state.outcomes.forEach(o => {
155
+ const icon = o.status === 'verified' ? chalk.green('✓') : o.status === 'reviewed' ? chalk.yellow('◑') : chalk.dim('○');
156
+ console.log(' ' + icon + ' ' + o.name + chalk.dim(' [' + (o.status || 'draft') + ']'));
157
+ });
158
+ }
159
+ print.blank();
160
+ console.log(chalk.dim(' Open Claude Code and type /odd to resume.'));
161
+ print.blank();
162
+ });
163
+
164
+ // ── upgrade ───────────────────────────────────────────────────────────────────
165
+ program
166
+ .command('upgrade')
167
+ .description('Upgrade the /odd skill and hooks to the latest version')
168
+ .action(async () => {
169
+ print.logo();
170
+ const { default: installSkill } = await import('../scripts/install-skill.js');
171
+ const { default: setupHooks } = await import('../scripts/setup-hooks.js');
172
+
173
+ console.log(chalk.bold(' Upgrading ODD Studio...\n'));
174
+
175
+ const s1 = ora({ text: 'Updating /odd skill...', indent: 4 }).start();
176
+ try {
177
+ await installSkill(PACKAGE_ROOT, { force: true });
178
+ s1.succeed('Skill updated');
179
+ } catch (e) {
180
+ s1.fail('Skill update failed: ' + e.message);
181
+ }
182
+
183
+ const s2 = ora({ text: 'Updating hooks...', indent: 4 }).start();
184
+ try {
185
+ await setupHooks(PACKAGE_ROOT, { force: true });
186
+ s2.succeed('Hooks updated');
187
+ } catch (e) {
188
+ s2.fail('Hooks update failed: ' + e.message);
189
+ }
190
+
191
+ print.blank();
192
+ print.ok('Upgrade complete.');
193
+ print.blank();
194
+ });
195
+
196
+ // ── export ────────────────────────────────────────────────────────────────────
197
+ program
198
+ .command('export')
199
+ .description('Export the IDE Session Brief from current project state')
200
+ .action(async () => {
201
+ print.logo();
202
+ const stateFile = path.resolve(process.cwd(), '.odd', 'state.json');
203
+ if (!fs.existsSync(stateFile)) {
204
+ print.err('No ODD state found. Run odd-studio init first.');
205
+ process.exit(1);
206
+ }
207
+ print.info('Open Claude Code and run: ' + chalk.cyan('/odd') + ' then ' + chalk.cyan('*export'));
208
+ print.info('The Session Brief will be saved to ' + chalk.cyan('docs/session-brief.md'));
209
+ print.blank();
210
+ });
211
+
212
+ program.parse();
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env bash
2
+ # odd-destructive-guard.sh
3
+ # ODD Studio — Destructive Command Guard (PreToolUse: Bash)
4
+ #
5
+ # Blocks or warns on shell commands that could cause irreversible damage:
6
+ # rm -rf, overwriting critical files, dropping databases, etc.
7
+
8
+ COMMAND="${CLAUDE_TOOL_INPUT:-}"
9
+
10
+ block() {
11
+ echo "🛡️ ODD DESTRUCTIVE GUARD: $1" >&2
12
+ echo "" >&2
13
+ echo "$2" >&2
14
+ exit 2
15
+ }
16
+
17
+ warn() {
18
+ echo "⚠️ ODD DESTRUCTIVE GUARD WARNING: $1" >&2
19
+ echo "$2" >&2
20
+ }
21
+
22
+ # ── rm -rf ────────────────────────────────────────────────────────────────────
23
+ if echo "$COMMAND" | grep -qE 'rm\s+(-[a-zA-Z]*r[a-zA-Z]*f|-[a-zA-Z]*f[a-zA-Z]*r)'; then
24
+ TARGET=$(echo "$COMMAND" | grep -oE 'rm\s+-[a-zA-Z]+\s+\S+' | awk '{print $3}')
25
+
26
+ # Always block rm -rf on common dangerous targets
27
+ if echo "$TARGET" | grep -qE '^(/|~|\$HOME|\.\.)'; then
28
+ block \
29
+ "rm -rf on root-level or parent directory: $TARGET" \
30
+ "This would recursively delete critical system or project files.
31
+ ODD Studio always blocks rm -rf on potentially dangerous paths."
32
+ fi
33
+
34
+ # Block rm -rf on the project docs/ directory
35
+ if echo "$TARGET" | grep -qE '(docs|personas|outcomes|plan\.md|contract-map)'; then
36
+ block \
37
+ "rm -rf on ODD project documentation: $TARGET" \
38
+ "This would destroy your persona, outcome, and plan documents.
39
+ These are your build specifications — deleting them means losing your planning work.
40
+ If you genuinely need to remove a file, delete it specifically by name."
41
+ fi
42
+
43
+ # Block rm -rf on .claude/
44
+ if echo "$TARGET" | grep -qE '\.claude'; then
45
+ block \
46
+ "rm -rf on .claude/ directory." \
47
+ "This would remove your Claude Code skills, hooks, and settings.
48
+ Run 'odd-studio upgrade' to update, or edit settings manually."
49
+ fi
50
+
51
+ # Warn (don't block) on other rm -rf
52
+ warn \
53
+ "rm -rf detected: $COMMAND" \
54
+ "Ensure this is intentional — recursive deletion cannot be undone."
55
+ fi
56
+
57
+ # ── Overwriting .env files ────────────────────────────────────────────────────
58
+ if echo "$COMMAND" | grep -qE '>\s*\.env(\s|$)'; then
59
+ block \
60
+ "Overwriting .env file detected." \
61
+ "ODD Studio never overwrites .env files — they contain credentials.
62
+ Edit .env manually or use a specific key: echo 'KEY=value' >> .env"
63
+ fi
64
+
65
+ # ── Committing secrets ────────────────────────────────────────────────────────
66
+ if echo "$COMMAND" | grep -qE 'git\s+(add|commit).*\.env'; then
67
+ block \
68
+ "Attempting to commit .env file." \
69
+ "ODD Studio never commits .env files — they contain credentials.
70
+ Add .env to .gitignore if it isn't already:
71
+ echo '.env' >> .gitignore"
72
+ fi
73
+
74
+ # ── Dropping databases ────────────────────────────────────────────────────────
75
+ if echo "$COMMAND" | grep -qiE '(drop\s+database|dropdb|DROP\s+TABLE.*CASCADE)'; then
76
+ warn \
77
+ "Database destructive operation detected: $COMMAND" \
78
+ "Ensure you are targeting the development database, not production.
79
+ ODD Studio recommends confirming the DATABASE_URL before destructive DB operations."
80
+ fi
81
+
82
+ # ── Killing all node processes ────────────────────────────────────────────────
83
+ if echo "$COMMAND" | grep -qE 'kill\s+-9\s+(all|-1|0)'; then
84
+ warn \
85
+ "kill -9 all processes detected." \
86
+ "This terminates all processes for your user, including any development servers.
87
+ Use kill -9 <PID> to target a specific process."
88
+ fi
89
+
90
+ # ── curl | bash (pipe to shell) ───────────────────────────────────────────────
91
+ if echo "$COMMAND" | grep -qE '(curl|wget).*\|\s*(bash|sh|zsh)'; then
92
+ warn \
93
+ "Pipe-to-shell pattern detected: $COMMAND" \
94
+ "Executing remote scripts directly is a security risk.
95
+ Consider downloading and reviewing the script before executing."
96
+ fi
97
+
98
+ exit 0