create-smash-os 0.1.2 → 0.1.4
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/install.mjs +379 -4
- package/package.json +1 -1
package/install.mjs
CHANGED
|
@@ -3,23 +3,31 @@
|
|
|
3
3
|
* smash-os-install — Install the SmashOS Claude Code harness into any repo.
|
|
4
4
|
*
|
|
5
5
|
* Usage (inside your repo root):
|
|
6
|
-
* npx smash-os-install
|
|
6
|
+
* npx smash-os-install — connected mode (requires SmashOS web app)
|
|
7
|
+
* npx smash-os-install --local — local-only mode (no web app, no API keys)
|
|
7
8
|
*
|
|
8
|
-
* What it does:
|
|
9
|
+
* What it does (connected):
|
|
9
10
|
* 1. Prompts for your SmashOS URL, Repo ID, and API key
|
|
10
11
|
* 2. Validates credentials against the SmashOS API
|
|
11
12
|
* 3. Fetches the generated harness files for your repo
|
|
12
13
|
* 4. Writes CLAUDE.md, .claude/hooks/, .claude/skills/, .env.smash-os
|
|
13
14
|
* 5. Merges hooks into existing .claude/settings.json (if present)
|
|
14
15
|
* 6. Adds .env.smash-os to .gitignore
|
|
16
|
+
*
|
|
17
|
+
* What it does (--local):
|
|
18
|
+
* 1. Prompts for project name and tech stack only
|
|
19
|
+
* 2. Writes CLAUDE.md + /ai/ skeleton + 2 skills locally
|
|
20
|
+
* 3. No web app connection required
|
|
15
21
|
*/
|
|
16
22
|
|
|
17
23
|
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
18
|
-
import { join, dirname } from 'path';
|
|
24
|
+
import { join, dirname, basename } from 'path';
|
|
25
|
+
import { homedir } from 'os';
|
|
19
26
|
import prompts from 'prompts';
|
|
20
27
|
import chalk from 'chalk';
|
|
21
28
|
|
|
22
29
|
const cwd = process.cwd();
|
|
30
|
+
const isLocal = process.argv.includes('--local');
|
|
23
31
|
|
|
24
32
|
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
25
33
|
|
|
@@ -82,9 +90,376 @@ function ensureGitignore(entry) {
|
|
|
82
90
|
|
|
83
91
|
console.log('');
|
|
84
92
|
console.log(chalk.bold(' SmashOS Harness Installer'));
|
|
85
|
-
console.log(chalk.dim(' Installs the Claude Code harness into your repo'));
|
|
93
|
+
console.log(chalk.dim(isLocal ? ' Local-only mode — no web app required' : ' Installs the Claude Code harness into your repo'));
|
|
86
94
|
console.log('');
|
|
87
95
|
|
|
96
|
+
// ─── Local-only mode ──────────────────────────────────────────────────────────
|
|
97
|
+
|
|
98
|
+
if (isLocal) {
|
|
99
|
+
const onCancel = () => { console.log(chalk.yellow('\n Cancelled.')); process.exit(0); };
|
|
100
|
+
|
|
101
|
+
const baseAnswers = await prompts([
|
|
102
|
+
{
|
|
103
|
+
type: 'text',
|
|
104
|
+
name: 'projectName',
|
|
105
|
+
message: 'Project name',
|
|
106
|
+
initial: basename(cwd),
|
|
107
|
+
validate: (v) => (v.trim().length > 0 ? true : 'Required'),
|
|
108
|
+
},
|
|
109
|
+
], { onCancel });
|
|
110
|
+
|
|
111
|
+
const { projectName } = baseAnswers;
|
|
112
|
+
|
|
113
|
+
console.log('');
|
|
114
|
+
console.log(chalk.bold(' Tech Stack'));
|
|
115
|
+
console.log(chalk.dim(' Select your tools — choose "Other" to enter a custom value'));
|
|
116
|
+
console.log('');
|
|
117
|
+
|
|
118
|
+
const O = '__other__';
|
|
119
|
+
const o = (prev) => prev === O ? 'text' : null;
|
|
120
|
+
const req = (v) => v.trim().length > 0 ? true : 'Required';
|
|
121
|
+
|
|
122
|
+
const stackAnswers = await prompts([
|
|
123
|
+
// ── Frontend Framework ─────────────────────────────────────────────────
|
|
124
|
+
{
|
|
125
|
+
type: 'select',
|
|
126
|
+
name: 'frontend',
|
|
127
|
+
message: 'Frontend framework',
|
|
128
|
+
choices: [
|
|
129
|
+
{ title: 'Next.js', value: 'Next.js' },
|
|
130
|
+
{ title: 'React Router v7', value: 'React Router v7' },
|
|
131
|
+
{ title: 'Remix', value: 'Remix' },
|
|
132
|
+
{ title: 'Vite + React (SPA)', value: 'Vite + React' },
|
|
133
|
+
{ title: 'SvelteKit', value: 'SvelteKit' },
|
|
134
|
+
{ title: 'Nuxt (Vue 3)', value: 'Nuxt' },
|
|
135
|
+
{ title: 'Astro', value: 'Astro' },
|
|
136
|
+
{ title: 'Angular', value: 'Angular' },
|
|
137
|
+
{ title: 'Solid Start', value: 'Solid Start' },
|
|
138
|
+
{ title: 'Other…', value: O },
|
|
139
|
+
],
|
|
140
|
+
},
|
|
141
|
+
{ type: o, name: 'frontendCustom', message: 'Specify your frontend framework', validate: req },
|
|
142
|
+
|
|
143
|
+
// ── Backend / API ──────────────────────────────────────────────────────
|
|
144
|
+
{
|
|
145
|
+
type: 'select',
|
|
146
|
+
name: 'backend',
|
|
147
|
+
message: 'Backend / API layer',
|
|
148
|
+
choices: [
|
|
149
|
+
{ title: 'Fullstack (handled by framework)', value: 'Fullstack (framework handles API)' },
|
|
150
|
+
{ title: 'Node.js + Express', value: 'Node.js + Express' },
|
|
151
|
+
{ title: 'Node.js + Hono', value: 'Node.js + Hono' },
|
|
152
|
+
{ title: 'Node.js + Fastify', value: 'Node.js + Fastify' },
|
|
153
|
+
{ title: 'Node.js + NestJS', value: 'Node.js + NestJS' },
|
|
154
|
+
{ title: 'Python + FastAPI', value: 'Python + FastAPI' },
|
|
155
|
+
{ title: 'Python + Django / Flask', value: 'Python + Django/Flask' },
|
|
156
|
+
{ title: 'Go (Gin / Chi)', value: 'Go' },
|
|
157
|
+
{ title: 'Bun + Elysia', value: 'Bun + Elysia' },
|
|
158
|
+
{ title: 'Other…', value: O },
|
|
159
|
+
],
|
|
160
|
+
},
|
|
161
|
+
{ type: o, name: 'backendCustom', message: 'Specify your backend/API layer', validate: req },
|
|
162
|
+
|
|
163
|
+
// ── Database ───────────────────────────────────────────────────────────
|
|
164
|
+
{
|
|
165
|
+
type: 'select',
|
|
166
|
+
name: 'database',
|
|
167
|
+
message: 'Database',
|
|
168
|
+
choices: [
|
|
169
|
+
{ title: 'Supabase (Postgres)', value: 'Supabase (Postgres)' },
|
|
170
|
+
{ title: 'Neon (Postgres)', value: 'Neon (Postgres)' },
|
|
171
|
+
{ title: 'MongoDB Atlas', value: 'MongoDB Atlas' },
|
|
172
|
+
{ title: 'PlanetScale / Vitess (MySQL)', value: 'PlanetScale (MySQL)' },
|
|
173
|
+
{ title: 'Firebase Firestore', value: 'Firebase Firestore' },
|
|
174
|
+
{ title: 'Turso (SQLite / libSQL)', value: 'Turso (SQLite)' },
|
|
175
|
+
{ title: 'Prisma + PostgreSQL', value: 'Prisma + PostgreSQL' },
|
|
176
|
+
{ title: 'Drizzle + D1 (SQLite)', value: 'Drizzle + Cloudflare D1' },
|
|
177
|
+
{ title: 'Upstash Redis', value: 'Upstash Redis' },
|
|
178
|
+
{ title: 'Other…', value: O },
|
|
179
|
+
],
|
|
180
|
+
},
|
|
181
|
+
{ type: o, name: 'databaseCustom', message: 'Specify your database', validate: req },
|
|
182
|
+
|
|
183
|
+
// ── Authentication ─────────────────────────────────────────────────────
|
|
184
|
+
{
|
|
185
|
+
type: 'select',
|
|
186
|
+
name: 'auth',
|
|
187
|
+
message: 'Authentication',
|
|
188
|
+
choices: [
|
|
189
|
+
{ title: 'None / Custom', value: 'None' },
|
|
190
|
+
{ title: 'Clerk', value: 'Clerk' },
|
|
191
|
+
{ title: 'Supabase Auth', value: 'Supabase Auth' },
|
|
192
|
+
{ title: 'Auth.js (NextAuth.js)', value: 'Auth.js (NextAuth)' },
|
|
193
|
+
{ title: 'Better Auth', value: 'Better Auth' },
|
|
194
|
+
{ title: 'Firebase Auth', value: 'Firebase Auth' },
|
|
195
|
+
{ title: 'Auth0', value: 'Auth0' },
|
|
196
|
+
{ title: 'Lucia Auth', value: 'Lucia Auth' },
|
|
197
|
+
{ title: 'Kinde', value: 'Kinde' },
|
|
198
|
+
{ title: 'Other…', value: O },
|
|
199
|
+
],
|
|
200
|
+
},
|
|
201
|
+
{ type: o, name: 'authCustom', message: 'Specify your auth provider', validate: req },
|
|
202
|
+
|
|
203
|
+
// ── Deployment ─────────────────────────────────────────────────────────
|
|
204
|
+
{
|
|
205
|
+
type: 'select',
|
|
206
|
+
name: 'deployment',
|
|
207
|
+
message: 'Deployment target',
|
|
208
|
+
choices: [
|
|
209
|
+
{ title: 'Vercel', value: 'Vercel' },
|
|
210
|
+
{ title: 'Cloudflare Workers / Pages', value: 'Cloudflare Workers/Pages' },
|
|
211
|
+
{ title: 'Netlify', value: 'Netlify' },
|
|
212
|
+
{ title: 'Railway', value: 'Railway' },
|
|
213
|
+
{ title: 'Fly.io', value: 'Fly.io' },
|
|
214
|
+
{ title: 'Render', value: 'Render' },
|
|
215
|
+
{ title: 'AWS (Lambda / ECS)', value: 'AWS' },
|
|
216
|
+
{ title: 'Google Cloud Run', value: 'Google Cloud Run' },
|
|
217
|
+
{ title: 'Self-hosted / VPS', value: 'Self-hosted / VPS' },
|
|
218
|
+
{ title: 'Other…', value: O },
|
|
219
|
+
],
|
|
220
|
+
},
|
|
221
|
+
{ type: o, name: 'deploymentCustom', message: 'Specify your deployment target', validate: req },
|
|
222
|
+
|
|
223
|
+
// ── Styling / UI ───────────────────────────────────────────────────────
|
|
224
|
+
{
|
|
225
|
+
type: 'select',
|
|
226
|
+
name: 'styling',
|
|
227
|
+
message: 'Styling / UI library',
|
|
228
|
+
choices: [
|
|
229
|
+
{ title: 'Tailwind CSS', value: 'Tailwind CSS' },
|
|
230
|
+
{ title: 'shadcn/ui + Tailwind', value: 'shadcn/ui + Tailwind CSS' },
|
|
231
|
+
{ title: 'CSS Modules', value: 'CSS Modules' },
|
|
232
|
+
{ title: 'Material UI (MUI)', value: 'Material UI (MUI)' },
|
|
233
|
+
{ title: 'Chakra UI', value: 'Chakra UI' },
|
|
234
|
+
{ title: 'Styled Components / Emotion', value: 'Styled Components' },
|
|
235
|
+
{ title: 'Mantine', value: 'Mantine' },
|
|
236
|
+
{ title: 'Radix UI + Tailwind', value: 'Radix UI + Tailwind CSS' },
|
|
237
|
+
{ title: 'UnoCSS', value: 'UnoCSS' },
|
|
238
|
+
{ title: 'Other…', value: O },
|
|
239
|
+
],
|
|
240
|
+
},
|
|
241
|
+
{ type: o, name: 'stylingCustom', message: 'Specify your styling/UI library', validate: req },
|
|
242
|
+
], { onCancel });
|
|
243
|
+
|
|
244
|
+
function pick(val, custom) { return val === O ? (custom || 'Other') : val; }
|
|
245
|
+
|
|
246
|
+
const techStack = [
|
|
247
|
+
`- Frontend: ${pick(stackAnswers.frontend, stackAnswers.frontendCustom)}`,
|
|
248
|
+
`- Backend: ${pick(stackAnswers.backend, stackAnswers.backendCustom)}`,
|
|
249
|
+
`- Database: ${pick(stackAnswers.database, stackAnswers.databaseCustom)}`,
|
|
250
|
+
`- Auth: ${pick(stackAnswers.auth, stackAnswers.authCustom)}`,
|
|
251
|
+
`- Deployment: ${pick(stackAnswers.deployment, stackAnswers.deploymentCustom)}`,
|
|
252
|
+
`- Styling: ${pick(stackAnswers.styling, stackAnswers.stylingCustom)}`,
|
|
253
|
+
].join('\n');
|
|
254
|
+
|
|
255
|
+
console.log('');
|
|
256
|
+
const today = new Date().toISOString().split('T')[0];
|
|
257
|
+
|
|
258
|
+
const claudeMd = `# ${projectName} — SmashOS Harness Active
|
|
259
|
+
|
|
260
|
+
You are operating inside the SmashOS AI Workflow Harness.
|
|
261
|
+
You are not a single assistant. You are a coordinated AI engineering organisation.
|
|
262
|
+
|
|
263
|
+
## On Session Start
|
|
264
|
+
1. Read \`ai/context/product.md\` (if it exists)
|
|
265
|
+
2. Read \`ai/context/architecture.md\` (if it exists)
|
|
266
|
+
3. Read \`ai/context/coding-standards.md\` (if it exists)
|
|
267
|
+
4. Read \`ai/memory/decisions.md\` — last 20 entries (if it exists)
|
|
268
|
+
5. Adopt the role: Staff Engineer
|
|
269
|
+
|
|
270
|
+
## Cognitive Mode Rules
|
|
271
|
+
THINKING → Staff Engineer, Product Manager (no file writes)
|
|
272
|
+
EXECUTION → Senior Developer, DevOps (no specs or decisions)
|
|
273
|
+
VALIDATION → Security Engineer, QA Engineer (no production code)
|
|
274
|
+
|
|
275
|
+
## Golden Rules
|
|
276
|
+
- Never skip architecture review
|
|
277
|
+
- Never write code without an approved spec
|
|
278
|
+
- Never deploy without QA + Security validation
|
|
279
|
+
- Output structured results only
|
|
280
|
+
- Save decisions to memory after every significant choice
|
|
281
|
+
|
|
282
|
+
## Slash Commands
|
|
283
|
+
- /smash-os:role [name] — switch cognitive mode + load role definition
|
|
284
|
+
|
|
285
|
+
## Tech Stack
|
|
286
|
+
${techStack}
|
|
287
|
+
`;
|
|
288
|
+
|
|
289
|
+
const aiFiles = {
|
|
290
|
+
'ai/orchestrator.md': `# ${projectName} — SmashOS Orchestrator
|
|
291
|
+
**Generated:** ${today}
|
|
292
|
+
**Version:** 1.0
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
## Overview
|
|
297
|
+
|
|
298
|
+
You are operating inside the SmashOS AI Workflow Harness for **${projectName}**.
|
|
299
|
+
You are not a single assistant. You are a coordinated AI engineering organisation.
|
|
300
|
+
|
|
301
|
+
This orchestrator.md is your master boot document. Read it fully at the start of every session.
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
## On Session Start
|
|
306
|
+
|
|
307
|
+
1. Read \`/ai/context/product.md\` — understand what you are building and for whom
|
|
308
|
+
2. Read \`/ai/context/architecture.md\` — understand the technical system
|
|
309
|
+
3. Read \`/ai/context/coding-standards.md\` — know the rules before touching any file
|
|
310
|
+
4. Read \`/ai/memory/decisions.md\` (last 20 entries) — know what has been decided and why
|
|
311
|
+
5. Adopt the role: Staff Engineer
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## Cognitive Mode Rules
|
|
316
|
+
|
|
317
|
+
| Mode | Roles | Permitted | Forbidden |
|
|
318
|
+
|---|---|---|---|
|
|
319
|
+
| THINKING | Staff Engineer, Product Manager | Specs, decisions, architecture docs | File writes, commits |
|
|
320
|
+
| EXECUTION | Senior Developer, DevOps Engineer | Code, commits, branches, PRs | Specs, decisions |
|
|
321
|
+
| VALIDATION | Security Engineer, QA Engineer | Scores, test results, audit reports | Production code |
|
|
322
|
+
|
|
323
|
+
The orchestrator hard-blocks mode mixing. Never mix thinking and execution in the same phase.
|
|
324
|
+
|
|
325
|
+
---
|
|
326
|
+
|
|
327
|
+
## Golden Rules
|
|
328
|
+
|
|
329
|
+
1. Never skip architecture review
|
|
330
|
+
2. Never write code without an approved spec
|
|
331
|
+
3. Never deploy without QA + Security validation
|
|
332
|
+
4. Output structured results only — every phase output is a typed JSON object
|
|
333
|
+
5. Save decisions to memory after every significant architectural choice
|
|
334
|
+
6. Revenue risk outranks technical purity
|
|
335
|
+
7. Block automation when stability drops below 40
|
|
336
|
+
|
|
337
|
+
---
|
|
338
|
+
|
|
339
|
+
## Active Role Definitions
|
|
340
|
+
|
|
341
|
+
| Role | Mode | Primary Skill |
|
|
342
|
+
|---|---|---|
|
|
343
|
+
| Staff Engineer | THINKING | architecture-review |
|
|
344
|
+
| Product Manager | THINKING | — |
|
|
345
|
+
| Senior Developer | EXECUTION | code-generation |
|
|
346
|
+
| Security Engineer | VALIDATION | security-audit |
|
|
347
|
+
| QA Engineer | VALIDATION | qa-validation |
|
|
348
|
+
| DevOps Engineer | EXECUTION | — |
|
|
349
|
+
|
|
350
|
+
Full role definitions: \`/ai/roles/{role-name}.md\`
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
## Selective Context Loading
|
|
355
|
+
|
|
356
|
+
Load only what your role requires. Never load the full context bundle.
|
|
357
|
+
|
|
358
|
+
| Role | Load |
|
|
359
|
+
|---|---|
|
|
360
|
+
| Product Manager | product.md + database.md + trigger payload |
|
|
361
|
+
| Staff Engineer | architecture.md + coding-standards.md + decisions.md + previous phase output |
|
|
362
|
+
| Senior Developer | architecture.md + coding-standards.md + approved spec |
|
|
363
|
+
| Security Engineer | database.md + auth section of architecture.md + file diff |
|
|
364
|
+
| QA Engineer | coding-standards.md + acceptance criteria + file diff |
|
|
365
|
+
| DevOps Engineer | architecture.md + PR metadata + score summary |
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
## Product Summary
|
|
370
|
+
|
|
371
|
+
*Context not yet generated. Fill in \`/ai/context/product.md\` with your project details.*
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
|
|
375
|
+
## Architecture Summary
|
|
376
|
+
|
|
377
|
+
*Context not yet generated. Fill in \`/ai/context/architecture.md\` with your architecture.*
|
|
378
|
+
|
|
379
|
+
---
|
|
380
|
+
|
|
381
|
+
## Coding Standards Summary
|
|
382
|
+
|
|
383
|
+
*Context not yet generated. Fill in \`/ai/context/coding-standards.md\` with your coding standards.*
|
|
384
|
+
|
|
385
|
+
---
|
|
386
|
+
|
|
387
|
+
## Database Summary
|
|
388
|
+
|
|
389
|
+
*Context not yet generated. Fill in \`/ai/context/database.md\` with your database details.*
|
|
390
|
+
|
|
391
|
+
---
|
|
392
|
+
|
|
393
|
+
## Memory
|
|
394
|
+
|
|
395
|
+
- Architecture decisions: \`/ai/memory/decisions.md\`
|
|
396
|
+
- Lessons learned: \`/ai/memory/lessons.md\`
|
|
397
|
+
|
|
398
|
+
After every completed session, append decisions and lessons to the relevant memory file.
|
|
399
|
+
|
|
400
|
+
---
|
|
401
|
+
|
|
402
|
+
## Workflow References
|
|
403
|
+
|
|
404
|
+
- Feature: \`/ai/workflows/feature.md\`
|
|
405
|
+
- Bug Fix: \`/ai/workflows/bug-fix.md\`
|
|
406
|
+
- Weekly Improvement: \`/ai/workflows/weekly-improvement.md\`
|
|
407
|
+
|
|
408
|
+
---
|
|
409
|
+
|
|
410
|
+
*Generated by smash-os-install (local mode) — fill in the /ai/context/ files to activate full context.*
|
|
411
|
+
`,
|
|
412
|
+
'ai/context/product.md': `# Product Context — ${projectName}\n\n## What is this project?\n<!-- Describe what this project does -->\n\n## Who uses it?\n<!-- Describe the users -->\n\n## Core goals\n<!-- List the main goals -->\n\n## Tech Stack\n${techStack}\n`,
|
|
413
|
+
'ai/context/architecture.md': `# Architecture — ${projectName}\n\n## Overview\n<!-- Describe the high-level architecture -->\n\n## Key decisions\n<!-- List major architectural decisions and why they were made -->\n\n## Constraints\n<!-- List things that must not change -->\n`,
|
|
414
|
+
'ai/context/coding-standards.md': `# Coding Standards — ${projectName}\n\n## Language & formatting\n<!-- ESLint config, prettier, etc. -->\n\n## Naming conventions\n<!-- Variables, files, functions -->\n\n## Patterns to follow\n<!-- e.g. always use server actions, never bypass RLS -->\n\n## Patterns to avoid\n<!-- e.g. no raw SQL, no any types -->\n`,
|
|
415
|
+
'ai/memory/decisions.md': `# Decisions Log\n\n<!-- SmashOS writes here after each session. Format: -->\n<!-- ## YYYY-MM-DD — Decision title -->\n<!-- **Rationale:** why this was chosen -->\n<!-- **Outcome:** what changed -->\n`,
|
|
416
|
+
'ai/memory/lessons.md': `# Lessons Learned\n\n<!-- SmashOS writes here after bugs and incidents. Format: -->\n<!-- ## YYYY-MM-DD — Lesson title -->\n<!-- **What happened:** -->\n<!-- **What to do differently:** -->\n`,
|
|
417
|
+
};
|
|
418
|
+
|
|
419
|
+
const localSkills = {
|
|
420
|
+
'smash-os-role': `---\nname: smash-os-role\ndescription: Switch cognitive mode and load a SmashOS role definition. Use when the user says "act as X", "switch to X role", "be the X", or names a SmashOS role (Staff Engineer, Product Manager, Senior Developer, Security Engineer, QA Engineer, DevOps Engineer).\n---\n\n# /smash-os:role\n\nSwitch to the named role and adopt its cognitive mode.\n\n## Roles\n\n| Role | Mode | Allowed |\n|---|---|---|\n| Staff Engineer | THINKING | Architecture, decisions, reviews |\n| Product Manager | THINKING | Specs, user stories, acceptance criteria |\n| Senior Developer | EXECUTION | Writing code, editing files |\n| Security Engineer | VALIDATION | Security review only, no code changes |\n| QA Engineer | VALIDATION | Testing and verification only |\n| DevOps Engineer | EXECUTION | Infrastructure, deployment |\n\n## Steps\n1. Read the role name from the argument (default: Staff Engineer)\n2. Announce: "Switching to [Role] — [Mode] mode"\n3. Load \`ai/roles/<role-slug>.md\` if it exists\n4. Apply the cognitive mode restrictions for the rest of the session\n`,
|
|
421
|
+
'smash-os-memory': `---\nname: smash-os-memory\ndescription: Show recent SmashOS decisions and lessons from the ai/memory/ folder. Use when the user says "show memory", "what decisions were made", "show lessons", or "smash-os memory".\n---\n\n# /smash-os:memory\n\nRead and display the local SmashOS memory files.\n\n## Steps\n1. Read \`ai/memory/decisions.md\` (last 20 entries)\n2. Read \`ai/memory/lessons.md\` (last 10 entries)\n3. Display them clearly — decisions first, then lessons\n4. If either file is empty or missing, say so\n`,
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
let written = 0;
|
|
425
|
+
|
|
426
|
+
writeFile('CLAUDE.md', claudeMd);
|
|
427
|
+
console.log(' ' + chalk.green('✓') + ' ' + chalk.white('CLAUDE.md'));
|
|
428
|
+
written++;
|
|
429
|
+
|
|
430
|
+
for (const [relPath, content] of Object.entries(aiFiles)) {
|
|
431
|
+
if (!existsSync(join(cwd, relPath))) {
|
|
432
|
+
writeFile(relPath, content);
|
|
433
|
+
console.log(' ' + chalk.green('✓') + ' ' + chalk.white(relPath));
|
|
434
|
+
written++;
|
|
435
|
+
} else {
|
|
436
|
+
console.log(' ' + chalk.dim('↷') + ' ' + chalk.dim(`${relPath} (already exists — skipped)`));
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
console.log('');
|
|
441
|
+
for (const [skillName, skillContent] of Object.entries(localSkills)) {
|
|
442
|
+
const skillDir = join(homedir(), '.claude', 'skills', skillName);
|
|
443
|
+
mkdirSync(skillDir, { recursive: true });
|
|
444
|
+
writeFileSync(join(skillDir, 'SKILL.md'), skillContent, 'utf8');
|
|
445
|
+
console.log(' ' + chalk.green('✓') + ' ' + chalk.white(`/smash-os:${skillName.replace('smash-os-', '')}`) + chalk.dim(' → ~/.claude/skills/'));
|
|
446
|
+
written++;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
console.log('');
|
|
450
|
+
console.log(chalk.bold.green(' SmashOS harness installed!') + chalk.dim(` (${written} files — local mode)`));
|
|
451
|
+
console.log('');
|
|
452
|
+
console.log(chalk.dim(' Open Claude Code in this directory and start working:'));
|
|
453
|
+
console.log(' ' + chalk.white(' claude .'));
|
|
454
|
+
console.log('');
|
|
455
|
+
console.log(chalk.dim(' Fill in the ai/context/ files with your project details,'));
|
|
456
|
+
console.log(chalk.dim(' then Claude Code will load them automatically every session.'));
|
|
457
|
+
console.log('');
|
|
458
|
+
process.exit(0);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// ─── Connected mode ────────────────────────────────────────────────────────────
|
|
462
|
+
|
|
88
463
|
const answers = await prompts(
|
|
89
464
|
[
|
|
90
465
|
{
|