odd-studio 2.0.0 → 2.2.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/bin/odd-studio.js +47 -5
- package/package.json +1 -1
- package/scripts/postinstall.js +10 -7
- package/scripts/setup-mcp.js +68 -0
- package/skill/SKILL.md +57 -2
- package/skill/docs/build/build-protocol.md +7 -1
package/bin/odd-studio.js
CHANGED
|
@@ -62,7 +62,7 @@ program
|
|
|
62
62
|
console.log(chalk.bold(` Setting up: ${chalk.cyan(resolvedName)}\n`));
|
|
63
63
|
|
|
64
64
|
// 1. Scaffold project structure
|
|
65
|
-
print.step(1,
|
|
65
|
+
print.step(1, 4, 'Creating project structure...');
|
|
66
66
|
const spinner1 = ora({ text: '', indent: 4 }).start();
|
|
67
67
|
try {
|
|
68
68
|
await scaffoldProject(targetDir, resolvedName);
|
|
@@ -76,7 +76,7 @@ program
|
|
|
76
76
|
|
|
77
77
|
// 2. Install /odd skill
|
|
78
78
|
if (!options.skipSkill) {
|
|
79
|
-
print.step(2,
|
|
79
|
+
print.step(2, 4, 'Installing /odd skill into Claude Code...');
|
|
80
80
|
const spinner2 = ora({ text: '', indent: 4 }).start();
|
|
81
81
|
try {
|
|
82
82
|
const result = await installSkill(PACKAGE_ROOT);
|
|
@@ -88,13 +88,13 @@ program
|
|
|
88
88
|
print.info('Manual install: copy ' + chalk.dim('skill/') + ' to ' + chalk.dim('~/.claude/skills/odd/'));
|
|
89
89
|
}
|
|
90
90
|
} else {
|
|
91
|
-
print.step(2,
|
|
91
|
+
print.step(2, 4, 'Skipping skill install (--skip-skill)');
|
|
92
92
|
print.warn('Remember to install the skill manually for /odd to work in Claude Code.');
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
// 3. Setup hooks
|
|
96
96
|
if (!options.skipHooks) {
|
|
97
|
-
print.step(3,
|
|
97
|
+
print.step(3, 4, 'Installing safety hooks into Claude Code settings...');
|
|
98
98
|
const spinner3 = ora({ text: '', indent: 4 }).start();
|
|
99
99
|
try {
|
|
100
100
|
const result = await setupHooks(PACKAGE_ROOT);
|
|
@@ -106,10 +106,43 @@ program
|
|
|
106
106
|
print.info('Manual install: add entries from ' + chalk.dim('hooks/') + ' to ~/.claude/settings.json');
|
|
107
107
|
}
|
|
108
108
|
} else {
|
|
109
|
-
print.step(3,
|
|
109
|
+
print.step(3, 4, 'Skipping hooks (--skip-hooks)');
|
|
110
110
|
print.warn('Safety hooks not installed. Git guardrails and quality gates will not run.');
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
// 4. Install Checkpoint security scanning tools
|
|
114
|
+
print.step(4, 5, 'Installing Checkpoint security scanning tools...');
|
|
115
|
+
const spinner4a = ora({ text: '', indent: 4 }).start();
|
|
116
|
+
try {
|
|
117
|
+
const { execSync } = await import('child_process');
|
|
118
|
+
execSync('npx @darrenjcoxon/vibeguard --install-tools --quiet 2>/dev/null', { stdio: 'ignore', timeout: 60000 });
|
|
119
|
+
spinner4a.stop();
|
|
120
|
+
print.ok('Checkpoint security tools installed');
|
|
121
|
+
} catch (e) {
|
|
122
|
+
spinner4a.stop();
|
|
123
|
+
print.warn('Checkpoint tools could not be installed automatically');
|
|
124
|
+
print.info('Run: npx @darrenjcoxon/vibeguard --install-tools to enable security scanning');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// 5. Configure ruflo MCP server (cross-session memory)
|
|
128
|
+
print.step(5, 5, 'Configuring ruflo memory server...');
|
|
129
|
+
const spinner5 = ora({ text: '', indent: 4 }).start();
|
|
130
|
+
try {
|
|
131
|
+
const { default: setupMcp } = await import('../scripts/setup-mcp.js');
|
|
132
|
+
const mcpResult = await setupMcp();
|
|
133
|
+
spinner5.stop();
|
|
134
|
+
if (mcpResult.mcpJsonUpdated || mcpResult.settingsUpdated) {
|
|
135
|
+
print.ok('Ruflo MCP server configured — cross-session memory enabled');
|
|
136
|
+
} else {
|
|
137
|
+
print.ok('Ruflo MCP server already configured');
|
|
138
|
+
}
|
|
139
|
+
} catch (e) {
|
|
140
|
+
spinner5.stop();
|
|
141
|
+
print.warn('Could not configure ruflo automatically: ' + e.message);
|
|
142
|
+
print.info('Manual setup: add ruflo to ~/.mcp.json and enable in ~/.claude/settings.json');
|
|
143
|
+
print.info('See: https://github.com/ruvnet/ruflo for installation instructions');
|
|
144
|
+
}
|
|
145
|
+
|
|
113
146
|
// ── Done ──
|
|
114
147
|
print.blank();
|
|
115
148
|
console.log(chalk.bold.green(' ✓ ODD Studio is ready.\n'));
|
|
@@ -188,6 +221,15 @@ program
|
|
|
188
221
|
s2.fail('Hooks update failed: ' + e.message);
|
|
189
222
|
}
|
|
190
223
|
|
|
224
|
+
const s3 = ora({ text: 'Checking ruflo MCP configuration...', indent: 4 }).start();
|
|
225
|
+
try {
|
|
226
|
+
const { default: setupMcp } = await import('../scripts/setup-mcp.js');
|
|
227
|
+
const mcpResult = await setupMcp();
|
|
228
|
+
s3.succeed(mcpResult.mcpJsonUpdated || mcpResult.settingsUpdated ? 'Ruflo MCP configured' : 'Ruflo MCP already configured');
|
|
229
|
+
} catch (e) {
|
|
230
|
+
s3.fail('Ruflo MCP check failed: ' + e.message);
|
|
231
|
+
}
|
|
232
|
+
|
|
191
233
|
print.blank();
|
|
192
234
|
print.ok('Upgrade complete.');
|
|
193
235
|
print.blank();
|
package/package.json
CHANGED
package/scripts/postinstall.js
CHANGED
|
@@ -13,16 +13,19 @@ if (!isGlobal && !isNpx) {
|
|
|
13
13
|
process.exit(0);
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
})
|
|
16
|
+
const pkg = new URL('..', import.meta.url).pathname.replace(/\/$/, '');
|
|
17
|
+
|
|
18
|
+
Promise.all([
|
|
19
|
+
import('./install-skill.js').then(({ default: installSkill }) => installSkill(pkg)),
|
|
20
|
+
import('./setup-hooks.js').then(({ default: setupHooks }) => setupHooks(pkg)),
|
|
21
|
+
import('./setup-mcp.js').then(({ default: setupMcp }) => setupMcp()),
|
|
22
|
+
])
|
|
21
23
|
.then(() => {
|
|
22
|
-
console.log('✓ ODD Studio: /odd skill installed into Claude Code');
|
|
24
|
+
console.log('✓ ODD Studio: /odd skill, safety hooks, and ruflo memory installed into Claude Code');
|
|
25
|
+
console.log(' Run: npx odd-studio init [project-name] to scaffold your first project.');
|
|
23
26
|
})
|
|
24
27
|
.catch((e) => {
|
|
25
28
|
// Non-fatal — user can run odd-studio init manually
|
|
26
|
-
console.log('⚠ ODD Studio: Could not
|
|
29
|
+
console.log('⚠ ODD Studio: Could not complete setup (' + e.message + ')');
|
|
27
30
|
console.log(' Run: npx odd-studio init to complete setup.');
|
|
28
31
|
});
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import os from 'os';
|
|
5
|
+
|
|
6
|
+
const MCP_JSON_PATH = path.join(os.homedir(), '.mcp.json');
|
|
7
|
+
const SETTINGS_PATH = path.join(os.homedir(), '.claude', 'settings.json');
|
|
8
|
+
|
|
9
|
+
const RUFLO_SERVER_ENTRY = {
|
|
10
|
+
type: 'stdio',
|
|
11
|
+
command: 'npx',
|
|
12
|
+
args: ['ruflo@latest', 'mcp', 'start'],
|
|
13
|
+
env: {},
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Configures the ruflo MCP server so that cross-session memory works.
|
|
18
|
+
*
|
|
19
|
+
* Two writes required:
|
|
20
|
+
* 1. ~/.mcp.json — defines the server (npx ruflo@latest mcp start)
|
|
21
|
+
* 2. ~/.claude/settings.json — adds "ruflo" to enabledMcpjsonServers
|
|
22
|
+
*
|
|
23
|
+
* Both are idempotent: existing entries are left untouched.
|
|
24
|
+
*/
|
|
25
|
+
export default async function setupMcp() {
|
|
26
|
+
const result = { mcpJsonUpdated: false, settingsUpdated: false };
|
|
27
|
+
|
|
28
|
+
// ── 1. Add ruflo to ~/.mcp.json ────────────────────────────────────────────
|
|
29
|
+
let mcpConfig = { mcpServers: {} };
|
|
30
|
+
if (fs.existsSync(MCP_JSON_PATH)) {
|
|
31
|
+
try {
|
|
32
|
+
mcpConfig = await fs.readJson(MCP_JSON_PATH);
|
|
33
|
+
} catch {
|
|
34
|
+
// Corrupt file — start fresh but preserve any valid content
|
|
35
|
+
mcpConfig = { mcpServers: {} };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (!mcpConfig.mcpServers) mcpConfig.mcpServers = {};
|
|
39
|
+
|
|
40
|
+
if (!mcpConfig.mcpServers.ruflo) {
|
|
41
|
+
mcpConfig.mcpServers.ruflo = RUFLO_SERVER_ENTRY;
|
|
42
|
+
await fs.writeJson(MCP_JSON_PATH, mcpConfig, { spaces: 2 });
|
|
43
|
+
result.mcpJsonUpdated = true;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// ── 2. Enable ruflo in ~/.claude/settings.json ─────────────────────────────
|
|
47
|
+
await fs.ensureDir(path.join(os.homedir(), '.claude'));
|
|
48
|
+
let settings = {};
|
|
49
|
+
if (fs.existsSync(SETTINGS_PATH)) {
|
|
50
|
+
try {
|
|
51
|
+
settings = await fs.readJson(SETTINGS_PATH);
|
|
52
|
+
} catch {
|
|
53
|
+
settings = {};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (!Array.isArray(settings.enabledMcpjsonServers)) {
|
|
58
|
+
settings.enabledMcpjsonServers = [];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (!settings.enabledMcpjsonServers.includes('ruflo')) {
|
|
62
|
+
settings.enabledMcpjsonServers.push('ruflo');
|
|
63
|
+
await fs.writeJson(SETTINGS_PATH, settings, { spaces: 2 });
|
|
64
|
+
result.settingsUpdated = true;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return result;
|
|
68
|
+
}
|
package/skill/SKILL.md
CHANGED
|
@@ -192,7 +192,59 @@ After collecting the description, call `mcp__ruflo__agent_spawn` with the custom
|
|
|
192
192
|
|
|
193
193
|
---
|
|
194
194
|
|
|
195
|
-
###
|
|
195
|
+
### `confirm`
|
|
196
|
+
|
|
197
|
+
The domain expert types `confirm` when all verification steps for the current outcome have passed on a single complete run.
|
|
198
|
+
|
|
199
|
+
Execute the following steps in order:
|
|
200
|
+
|
|
201
|
+
**1. Run Checkpoint.**
|
|
202
|
+
|
|
203
|
+
Execute via Bash: `npx @darrenjcoxon/vibeguard --security-only -o json 2>/dev/null`
|
|
204
|
+
|
|
205
|
+
Display to the domain expert: "Checkpoint running..."
|
|
206
|
+
|
|
207
|
+
Parse the JSON output. Look for findings with severity `critical`, `high`, or `secret`.
|
|
208
|
+
|
|
209
|
+
**If Checkpoint is not installed** (command fails or returns an error): skip silently and display "Checkpoint not installed — type `npx @darrenjcoxon/vibeguard --install-tools` in your terminal to enable security scanning." Then proceed to step 3.
|
|
210
|
+
|
|
211
|
+
**2. If Checkpoint finds critical, high, or secret findings:**
|
|
212
|
+
|
|
213
|
+
Do NOT advance to the next outcome.
|
|
214
|
+
|
|
215
|
+
Translate each finding from technical language to a plain-language fix instruction. Do not show raw scanner output to the domain expert.
|
|
216
|
+
|
|
217
|
+
Brief the build agent directly with the fix instructions. Do not ask the domain expert to review them.
|
|
218
|
+
|
|
219
|
+
Display: "Checkpoint found [N] security issue(s) in this outcome. The build agent is fixing them now. This does not affect your verification — the outcome behaves correctly. Once the security fix is complete, Checkpoint will run again automatically."
|
|
220
|
+
|
|
221
|
+
After the build agent applies fixes, re-run Checkpoint automatically (repeat step 1). Repeat until Checkpoint is clear. Then proceed to step 3.
|
|
222
|
+
|
|
223
|
+
**3. If Checkpoint is clear:**
|
|
224
|
+
|
|
225
|
+
Display: "Checkpoint clear."
|
|
226
|
+
|
|
227
|
+
Commit the verified state via git with message: `feat: verified [outcome name] — [phase]`
|
|
228
|
+
|
|
229
|
+
Call `mcp__ruflo__memory_store` key `odd-outcome-[name]` with status `verified`, namespace `odd-project`.
|
|
230
|
+
|
|
231
|
+
Update `.odd/state.json`: mark outcome as verified, set `nextStep` to the next outcome in the phase.
|
|
232
|
+
|
|
233
|
+
Display:
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
**[Outcome name] — verified and committed.**
|
|
238
|
+
|
|
239
|
+
Checkpoint: clear.
|
|
240
|
+
|
|
241
|
+
**Next:** [next outcome name and one-sentence description]
|
|
242
|
+
|
|
243
|
+
Type `*build` to begin, or `*status` to see the full phase progress.
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
---
|
|
196
248
|
|
|
197
249
|
Generate the IDE Session Brief. This is a standalone document that a developer or AI coding agent can use to execute a build session without needing to ask planning questions.
|
|
198
250
|
|
|
@@ -428,8 +480,11 @@ At key moments in the methodology, proactively explain why the current step matt
|
|
|
428
480
|
**Plan signed off:**
|
|
429
481
|
"The Master Implementation Plan is approved. You have a sequenced, dependency-respecting build order, anchored to real personas and verified outcomes. This is the document that turns a vision into an executable build. You are ready."
|
|
430
482
|
|
|
483
|
+
**Checkpoint clear (first time):**
|
|
484
|
+
"Checkpoint runs automatically every time you confirm an outcome. It scans what was just built for security issues — exposed secrets, missing authentication checks, injection vulnerabilities — and briefs the build agent to fix anything it finds before you move on. You do not need to understand what it found or how it was fixed. Security is not a separate concern in ODD Studio. It is built into the rhythm of the build."
|
|
485
|
+
|
|
431
486
|
**Phase complete:**
|
|
432
|
-
"Phase complete. All outcomes in this phase have been verified. The contracts they exposed are now available to the next phase. Well done — this is exactly how a well-planned build should progress."
|
|
487
|
+
"Phase complete. All outcomes in this phase have been verified and cleared by Checkpoint. The contracts they exposed are now available to the next phase. Well done — this is exactly how a well-planned build should progress."
|
|
433
488
|
|
|
434
489
|
---
|
|
435
490
|
|
|
@@ -61,7 +61,13 @@ Collect all failures from the verification run and send them in a single message
|
|
|
61
61
|
|
|
62
62
|
When all steps pass on a single complete run, type `confirm`.
|
|
63
63
|
|
|
64
|
-
ODD Studio
|
|
64
|
+
ODD Studio runs Checkpoint — a security scan of everything built in this outcome. The domain expert does not trigger this, read the results, or action any findings. It happens automatically.
|
|
65
|
+
|
|
66
|
+
If Checkpoint finds no issues, ODD Studio commits the verified state, updates ruflo memory, and presents the next outcome.
|
|
67
|
+
|
|
68
|
+
If Checkpoint finds security issues, ODD Studio briefs the build agent with the findings and triggers a fix. The domain expert waits. Once the fix is complete, Checkpoint runs again. When it is clear, the outcome is committed and the next outcome is presented.
|
|
69
|
+
|
|
70
|
+
The domain expert did not write a commit message, update a status file, identify security issues, or decide what comes next. The tool handled all of that.
|
|
65
71
|
|
|
66
72
|
---
|
|
67
73
|
|