@olives/devos 2.1.1 → 4.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.
- package/.agents/AGENTS.md +59 -0
- package/.agents/agents/dba.md +1 -0
- package/.agents/agents/developer.md +1 -0
- package/.agents/agents/eval-engineer.md +26 -0
- package/.agents/agents/executive-proxy.md +60 -0
- package/.agents/agents/orchestrator.md +30 -5
- package/.agents/agents/qa.md +9 -4
- package/.agents/agents/release-manager.md +5 -0
- package/.agents/agents/telemetry.md +36 -0
- package/.agents/agents/tester.md +3 -0
- package/.agents/agents/ui-designer.md +46 -0
- package/.agents/commands/auto.md +18 -0
- package/.agents/commands/design.md +15 -0
- package/.agents/commands/humanize.md +19 -0
- package/.agents/commands/task.md +16 -0
- package/.agents/commands/telemetry.md +14 -0
- package/.agents/hooks/pre-tool-use.sh +93 -0
- package/.agents/hooks/session-end.sh +28 -0
- package/.agents/hooks/session-start.sh +30 -0
- package/.agents/manifest.json +20 -0
- package/.agents/memory/context.json +7 -0
- package/.agents/memory/decisions/ADR-000-template.md +34 -0
- package/.agents/memory/handoffs/handoff-template.md +27 -0
- package/.agents/packs.json +118 -0
- package/.agents/scripts/humanize-check.sh +86 -0
- package/.agents/skills/autonomous-sdlc/SKILL.md +102 -0
- package/.agents/skills/humanizer/SKILL.md +135 -0
- package/.agents/skills/shared-memory/SKILL.md +38 -0
- package/.agents/skills/task-board/SKILL.md +26 -0
- package/.agents/skills/telemetry/SKILL.md +81 -0
- package/.agents/skills/testing-guide/SKILL.md +105 -0
- package/.agents/telemetry/.gitkeep +0 -0
- package/VERSION +1 -1
- package/bin/devos.js +1048 -74
- package/docs/2026-09-03-devos-ecc-gap-analysis.md +187 -0
- package/docs/2026-09-12-devos-v4-roadmap-research.md +314 -0
- package/docs/ARCHITECTURE.md +88 -6
- package/docs/CHANGELOG.md +13 -0
- package/docs/CURRENT_STATE.md +29 -23
- package/docs/PLAN_RUNTIME_HARNESS_PACKS.md +71 -0
- package/docs/SLASH_COMMANDS.md +35 -0
- package/docs/TASK_BOARD.md +50 -0
- package/docs/TUTORIAL.md +1 -1
- package/package.json +4 -1
- package/scripts/smoke-test.js +103 -0
package/bin/devos.js
CHANGED
|
@@ -14,9 +14,11 @@ const readline = require('readline');
|
|
|
14
14
|
const TEMPLATE_DIR = path.resolve(__dirname, '..');
|
|
15
15
|
const TARGET_DIR = process.cwd();
|
|
16
16
|
const PKG_PATH = path.join(TEMPLATE_DIR, 'package.json');
|
|
17
|
-
const PKG = fs.existsSync(PKG_PATH) ? JSON.parse(fs.readFileSync(PKG_PATH, 'utf8')) : { version: '
|
|
17
|
+
const PKG = fs.existsSync(PKG_PATH) ? JSON.parse(fs.readFileSync(PKG_PATH, 'utf8')) : { version: '3.0.0' };
|
|
18
18
|
|
|
19
19
|
const STACKS = ['nextjs', 'laravel', 'django', 'react-native', 'express', 'fastapi', 'universal'];
|
|
20
|
+
const HARNESSES = ['claude', 'cursor', 'opencode', 'antigravity', 'gemini', 'codex'];
|
|
21
|
+
const PLATFORMS = ['claude', 'antigravity', 'cursor', 'opencode', 'codex', 'all'];
|
|
20
22
|
|
|
21
23
|
// ANSI color formatting — disabled when piped, in CI, or when NO_COLOR is set
|
|
22
24
|
const useColor = Boolean(process.stdout.isTTY) && !process.env.NO_COLOR && process.env.TERM !== 'dumb';
|
|
@@ -36,17 +38,51 @@ Object.keys(PALETTE).forEach((k) => { colors[k] = useColor ? PALETTE[k] : ''; })
|
|
|
36
38
|
const BANNER_WIDTH = 48;
|
|
37
39
|
const RULE = '─'.repeat(BANNER_WIDTH);
|
|
38
40
|
|
|
41
|
+
// Core Rules and Protocols
|
|
42
|
+
const DEVOS_RULES_DIGEST = [
|
|
43
|
+
'1. Zero Destructive Actions: Never delete, drop, or truncate without an approved dry-run plan.',
|
|
44
|
+
'2. Zero Secrets Stored or Logged: API keys & credentials must NEVER be hardcoded. Use `process.env.*`.',
|
|
45
|
+
'3. Mechanical Commit Gate: Raw `git commit` is BLOCKED. Always commit via `.agents/scripts/commit.sh`.',
|
|
46
|
+
'4. Staged Review: Agents write code but NEVER auto-commit. Present summaries for human review first.',
|
|
47
|
+
'5. Circuit Breaker: Halt after 3 failed agent loop iterations and escalate to the human.',
|
|
48
|
+
'6. Verify Before Implementing: Confirm actual library APIs and patterns before authoring code.',
|
|
49
|
+
'7. No Heavy Dependencies: Packages >5MB or >50 dependencies require explicit human approval.',
|
|
50
|
+
'8. Documentation in /docs: All plans, PRDs, architecture notes, and reports belong in `/docs/`.',
|
|
51
|
+
'9. Session-Start Freshness: Run `git fetch --all --prune` and check `git status -sb` before scoping work.',
|
|
52
|
+
'10. Session-End State Obligation: Update `docs/CURRENT_STATE.md` before concluding any session modifying code.',
|
|
53
|
+
'11. Shared Memory Synchronization: Maintain architectural records in `.agents/memory/` (ADRs & handoffs).',
|
|
54
|
+
'12. Task Board Governance: Keep task states in `docs/TASK_BOARD.md` aligned with current execution.'
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
const SOLO_SESSION_PROTOCOL = [
|
|
58
|
+
'- Step 1: Check freshness via `git fetch --all --prune` and `git status -sb`.',
|
|
59
|
+
'- Step 2: Implement following `CODING_STANDARDS.md`.',
|
|
60
|
+
'- Step 3: Self-verify with typecheck (`tsc --noEmit` or equivalent) and automated tests.',
|
|
61
|
+
'- Step 4: Present staged review summary to human.',
|
|
62
|
+
'- Step 5: Route commit through `.agents/scripts/commit.sh`.',
|
|
63
|
+
'- Step 6: Update `docs/CURRENT_STATE.md` and log incidents in `docs/LESSONS.md`.',
|
|
64
|
+
'- Escalation: DB schema changes (DBA), security alterations (Security), or loops exceeding 3 attempts must escalate to human.'
|
|
65
|
+
];
|
|
66
|
+
|
|
39
67
|
// Flags parser helper
|
|
40
68
|
function parseArgs(args) {
|
|
41
69
|
const flags = {
|
|
42
70
|
stack: null,
|
|
71
|
+
platform: null,
|
|
43
72
|
fresh: false,
|
|
44
73
|
existing: false,
|
|
45
74
|
json: false,
|
|
46
75
|
quiet: false,
|
|
47
76
|
claude: true,
|
|
48
77
|
help: false,
|
|
49
|
-
version: false
|
|
78
|
+
version: false,
|
|
79
|
+
allSkills: false,
|
|
80
|
+
allHarnesses: false,
|
|
81
|
+
harness: null,
|
|
82
|
+
hooks: true,
|
|
83
|
+
telemetry: true,
|
|
84
|
+
mode: null,
|
|
85
|
+
skills: false
|
|
50
86
|
};
|
|
51
87
|
|
|
52
88
|
const positional = [];
|
|
@@ -67,6 +103,27 @@ function parseArgs(args) {
|
|
|
67
103
|
flags.quiet = true;
|
|
68
104
|
} else if (arg === '--no-claude') {
|
|
69
105
|
flags.claude = false;
|
|
106
|
+
} else if (arg === '--no-hooks') {
|
|
107
|
+
flags.hooks = false;
|
|
108
|
+
} else if (arg === '--all-skills') {
|
|
109
|
+
flags.allSkills = true;
|
|
110
|
+
} else if (arg === '--all-harnesses') {
|
|
111
|
+
flags.allHarnesses = true;
|
|
112
|
+
} else if (arg === '--no-telemetry') {
|
|
113
|
+
flags.telemetry = false;
|
|
114
|
+
} else if (arg === '--telemetry') {
|
|
115
|
+
flags.telemetry = true;
|
|
116
|
+
} else if (arg === '--skills') {
|
|
117
|
+
flags.skills = true;
|
|
118
|
+
} else if (arg === '--mode' || arg === '-m') {
|
|
119
|
+
flags.mode = args[i + 1] || null;
|
|
120
|
+
i++;
|
|
121
|
+
} else if (arg === '--platform' || arg === '-p') {
|
|
122
|
+
flags.platform = args[i + 1] || null;
|
|
123
|
+
i++;
|
|
124
|
+
} else if (arg === '--harness') {
|
|
125
|
+
flags.harness = args[i + 1] || null;
|
|
126
|
+
i++;
|
|
70
127
|
} else if (arg === '--stack' || arg === '-s') {
|
|
71
128
|
flags.stack = args[i + 1] || null;
|
|
72
129
|
i++;
|
|
@@ -114,15 +171,28 @@ function printHelp() {
|
|
|
114
171
|
|
|
115
172
|
console.log(`${colors.bold}CORE COMMANDS${colors.reset}`);
|
|
116
173
|
console.log(` ${colors.green}init${colors.reset}, ${colors.green}setup${colors.reset} Initialize Dev-OS multi-agent environment in target project`);
|
|
117
|
-
console.log(` ${colors.green}update${colors.reset}, ${colors.green}upgrade${colors.reset} Safely refresh .agents/, skills, commands, and hooks`);
|
|
118
|
-
console.log(` ${colors.green}
|
|
174
|
+
console.log(` ${colors.green}update${colors.reset}, ${colors.green}upgrade${colors.reset} Safely refresh .agents/, skills, commands, harnesses, and hooks`);
|
|
175
|
+
console.log(` ${colors.green}run${colors.reset}, ${colors.green}auto${colors.reset} Launch autonomous hands-off SDLC mode (devos run "<product idea>")`);
|
|
176
|
+
console.log(` ${colors.green}telemetry${colors.reset} Manage anonymous failure telemetry (status, report, enable, disable)`);
|
|
177
|
+
console.log(` ${colors.green}doctor${colors.reset}, ${colors.green}check${colors.reset} Diagnose setup, hooks, memory vault, task board, and health`);
|
|
178
|
+
console.log(` ${colors.green}pack${colors.reset}, ${colors.green}packs${colors.reset} Manage composable capability packs (pack list, pack add <name>)`);
|
|
179
|
+
console.log(` ${colors.green}skill${colors.reset}, ${colors.green}skills${colors.reset} Manage agent skills from skills.sh (skill list, add <repo>, update, find)`);
|
|
180
|
+
console.log(` ${colors.green}memory${colors.reset} Shared memory vault operations (memory list, memory handoff, memory doctor)`);
|
|
119
181
|
console.log(` ${colors.green}list${colors.reset}, ${colors.green}agents${colors.reset} Display active agent personas and installed specialist skills`);
|
|
120
182
|
console.log(` ${colors.green}status${colors.reset} Show active project configuration, detected stack, and health summary`);
|
|
121
183
|
console.log(` ${colors.green}version${colors.reset} Print Dev-OS CLI version, Node runtime, and environment information`);
|
|
122
184
|
console.log(` ${colors.green}help${colors.reset} Display this command reference\n`);
|
|
123
185
|
|
|
124
186
|
console.log(`${colors.bold}FLAGS${colors.reset}`);
|
|
125
|
-
console.log(` ${colors.cyan}-s, --stack <name>${colors.reset}
|
|
187
|
+
console.log(` ${colors.cyan}-s, --stack <name>${colors.reset} Target stack (${STACKS.join(', ')})`);
|
|
188
|
+
console.log(` ${colors.cyan}-p, --platform <name>${colors.reset} Target AI platform (${PLATFORMS.join(', ')})`);
|
|
189
|
+
console.log(` ${colors.cyan}-m, --mode <name>${colors.reset} SDLC execution mode (interactive, guided, auto, audit)`);
|
|
190
|
+
console.log(` ${colors.cyan}--telemetry / --no-telemetry${colors.reset} Enable or disable anonymous failure telemetry (default: on)`);
|
|
191
|
+
console.log(` ${colors.cyan}--harness <list>${colors.reset} Target AI harnesses: ${HARNESSES.join(', ')}`);
|
|
192
|
+
console.log(` ${colors.cyan}--all-harnesses${colors.reset} Generate configurations for all supported AI harnesses`);
|
|
193
|
+
console.log(` ${colors.cyan}--all-skills${colors.reset} Install all skills instead of lean stack pack`);
|
|
194
|
+
console.log(` ${colors.cyan}--skills${colors.reset} Update or sync installed skills from upstream registry`);
|
|
195
|
+
console.log(` ${colors.cyan}--no-hooks${colors.reset} Skip wiring runtime lifecycle hooks (.claude/hooks.json)`);
|
|
126
196
|
console.log(` ${colors.cyan}--fresh${colors.reset} Non-interactive fresh project initialization`);
|
|
127
197
|
console.log(` ${colors.cyan}--existing${colors.reset} Non-interactive existing project initialization`);
|
|
128
198
|
console.log(` ${colors.cyan}--no-claude${colors.reset} Skip generating .claude/ (Claude Code commands & agents)`);
|
|
@@ -134,8 +204,9 @@ function printHelp() {
|
|
|
134
204
|
console.log(`${colors.bold}EXAMPLES${colors.reset}`);
|
|
135
205
|
console.log(` $ ${colors.cyan}npx @olives/devos init${colors.reset}`);
|
|
136
206
|
console.log(` $ ${colors.cyan}npx @olives/devos init --stack nextjs --existing${colors.reset}`);
|
|
137
|
-
console.log(` $ ${colors.cyan}npx @olives/devos
|
|
138
|
-
console.log(` $ ${colors.cyan}npx @olives/devos
|
|
207
|
+
console.log(` $ ${colors.cyan}npx @olives/devos pack list${colors.reset}`);
|
|
208
|
+
console.log(` $ ${colors.cyan}npx @olives/devos memory handoff${colors.reset}`);
|
|
209
|
+
console.log(` $ ${colors.cyan}npx @olives/devos doctor${colors.reset}\n`);
|
|
139
210
|
|
|
140
211
|
console.log(`${colors.gray}Documentation & Guides: https://github.com/olitech1010/dev-os${colors.reset}\n`);
|
|
141
212
|
}
|
|
@@ -206,11 +277,23 @@ function hintFor(err) {
|
|
|
206
277
|
async function promptInitOptions(flags) {
|
|
207
278
|
let isFresh = false;
|
|
208
279
|
let stack = flags.stack || 'universal';
|
|
280
|
+
let platform = flags.platform || flags.harness || (flags.allHarnesses ? 'all' : null);
|
|
209
281
|
|
|
210
282
|
if (flags.stack && !STACKS.includes(flags.stack.toLowerCase())) {
|
|
211
283
|
throw new Error(`Unknown stack '${flags.stack}'. Valid stacks: ${STACKS.join(', ')}`);
|
|
212
284
|
}
|
|
213
285
|
|
|
286
|
+
if (platform && platform !== 'all') {
|
|
287
|
+
const list = platform.split(',').map((s) => s.trim().toLowerCase());
|
|
288
|
+
for (let item of list) {
|
|
289
|
+
if (item === 'gemini') item = 'antigravity';
|
|
290
|
+
if (item === 'windsurf') item = 'codex';
|
|
291
|
+
if (!HARNESSES.includes(item) && !PLATFORMS.includes(item)) {
|
|
292
|
+
throw new Error(`Unknown platform/harness '${item}'. Valid options: ${PLATFORMS.join(', ')}`);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
214
297
|
if (flags.fresh) {
|
|
215
298
|
isFresh = true;
|
|
216
299
|
} else if (flags.existing) {
|
|
@@ -250,14 +333,66 @@ async function promptInitOptions(flags) {
|
|
|
250
333
|
default: stack = 'universal'; break;
|
|
251
334
|
}
|
|
252
335
|
}
|
|
336
|
+
|
|
337
|
+
if (!platform) {
|
|
338
|
+
console.log(`\n${colors.bold}Step 3 · AI Coding Platform / Harness${colors.reset}`);
|
|
339
|
+
console.log(` 1) Claude Code (Anthropic Claude CLI, .claude/ commands & agents)`);
|
|
340
|
+
console.log(` 2) Google Antigravity / Gemini (ANTIGRAVITY.md, GEMINI.md)`);
|
|
341
|
+
console.log(` 3) Cursor (.cursor/rules/devos.mdc, .cursorrules)`);
|
|
342
|
+
console.log(` 4) OpenCode (.opencode/rules/, OPENCODE.md)`);
|
|
343
|
+
console.log(` 5) Codex / Windsurf (.codex/instructions.md, .windsurfrules)`);
|
|
344
|
+
console.log(` 6) All Platforms (Universal Multi-Platform Setup) [Default]`);
|
|
345
|
+
|
|
346
|
+
const platAns = await ask(`\n${colors.cyan}Select option [1-6] (default 6): ${colors.reset}`);
|
|
347
|
+
switch (platAns.trim()) {
|
|
348
|
+
case '1': platform = 'claude'; break;
|
|
349
|
+
case '2': platform = 'antigravity'; break;
|
|
350
|
+
case '3': platform = 'cursor'; break;
|
|
351
|
+
case '4': platform = 'opencode'; break;
|
|
352
|
+
case '5': platform = 'codex'; break;
|
|
353
|
+
default: platform = 'all'; break;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
let telemetry = flags.telemetry;
|
|
358
|
+
if (flags.telemetry === undefined || flags.telemetry === null) {
|
|
359
|
+
console.log(`\n${colors.bold}Step 4 · Anonymous Failure Telemetry${colors.reset}`);
|
|
360
|
+
console.log(` 1) On (Recommended) — Anonymously captures execution errors & RCA reports to improve Dev-OS`);
|
|
361
|
+
console.log(` 2) Off — Completely disable anonymous failure logging`);
|
|
362
|
+
const telemAns = await ask(`\n${colors.cyan}Select option [1-2] (default 1): ${colors.reset}`);
|
|
363
|
+
telemetry = telemAns.trim() !== '2';
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
let mode = flags.mode || 'interactive';
|
|
367
|
+
if (!flags.mode) {
|
|
368
|
+
console.log(`\n${colors.bold}Step 5 · Default SDLC Execution Mode${colors.reset}`);
|
|
369
|
+
console.log(` 1) Interactive (Default pair-programming with staged human reviews)`);
|
|
370
|
+
console.log(` 2) Guided (Step-by-step confirmation checkpoints at each SDLC stage)`);
|
|
371
|
+
console.log(` 3) Auto (Hands-off MVP builder for founders/CEOs — idea to full working MVP)`);
|
|
372
|
+
console.log(` 4) Audit (Read-only security, architecture, and code health evaluation)`);
|
|
373
|
+
const modeAns = await ask(`\n${colors.cyan}Select option [1-4] (default 1): ${colors.reset}`);
|
|
374
|
+
switch (modeAns.trim()) {
|
|
375
|
+
case '2': mode = 'guided'; break;
|
|
376
|
+
case '3': mode = 'auto'; break;
|
|
377
|
+
case '4': mode = 'audit'; break;
|
|
378
|
+
default: mode = 'interactive'; break;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
253
382
|
rl.close();
|
|
254
383
|
}
|
|
255
384
|
|
|
256
|
-
return {
|
|
385
|
+
return {
|
|
386
|
+
isFresh,
|
|
387
|
+
stack: stack.toLowerCase(),
|
|
388
|
+
platform: (platform || 'all').toLowerCase(),
|
|
389
|
+
telemetry: flags.telemetry !== false,
|
|
390
|
+
mode: (flags.mode || 'interactive').toLowerCase()
|
|
391
|
+
};
|
|
257
392
|
}
|
|
258
393
|
|
|
259
394
|
// ---------------------------------------------------------------------------
|
|
260
|
-
//
|
|
395
|
+
// Multi-Harness Generators
|
|
261
396
|
// ---------------------------------------------------------------------------
|
|
262
397
|
|
|
263
398
|
const AGENT_DESCRIPTIONS = {
|
|
@@ -271,7 +406,11 @@ const AGENT_DESCRIPTIONS = {
|
|
|
271
406
|
architect: 'Dev-OS system architect. Runs project inception (grill-me), designs architecture, and produces requirements documents.',
|
|
272
407
|
researcher: 'Dev-OS research specialist. Investigates libraries, APIs, compatibility, and best practices; returns concise verdicts.',
|
|
273
408
|
'memory-manager': 'Dev-OS memory custodian. Maintains docs/CURRENT_STATE.md and docs/LESSONS.md, compacts context, and manages session handoffs.',
|
|
274
|
-
'release-manager': 'Dev-OS release specialist. Owns semantic versioning, changelog entries, and release notes.'
|
|
409
|
+
'release-manager': 'Dev-OS release specialist. Owns semantic versioning, changelog entries, and release notes.',
|
|
410
|
+
'ui-designer': 'Dev-OS UI/UX design specialist. Formulates design systems, extracts tokens from ui-ux-pro-max, and authors docs/DESIGN.md to satisfy the Mandatory Design Gate.',
|
|
411
|
+
'executive-proxy': 'Dev-OS autonomous tech lead proxy. Oversees hands-off MVP delivery from idea to working software across all 10 SDLC stages.',
|
|
412
|
+
telemetry: 'Dev-OS observability specialist. Tracks runtime errors, failure logs in .agents/telemetry/, and drafts RCA reports.',
|
|
413
|
+
'eval-engineer': 'Dev-OS evaluation engineer. Measures capability benchmarks, pass@k, and prevents workflow regressions.'
|
|
275
414
|
};
|
|
276
415
|
|
|
277
416
|
function generateClaudeCommands(destAgents, destClaude) {
|
|
@@ -352,29 +491,16 @@ function bootstrapClaudeMd(targetDir) {
|
|
|
352
491
|
'This project uses Dev-OS by Olives Technologies.',
|
|
353
492
|
'',
|
|
354
493
|
'### Hard Rules Digest (Must be strictly obeyed at all times)',
|
|
355
|
-
|
|
356
|
-
'2. Zero Secrets Stored or Logged: API keys & credentials must NEVER be hardcoded. Use `process.env.*`.',
|
|
357
|
-
'3. Mechanical Commit Gate: Raw `git commit` is BLOCKED. Always commit via `.agents/scripts/commit.sh`.',
|
|
358
|
-
'4. Staged Review: Agents write code but NEVER auto-commit. Present summaries for human review first.',
|
|
359
|
-
'5. Circuit Breaker: Halt after 3 failed agent loop iterations and escalate to the human.',
|
|
360
|
-
'6. Verify Before Implementing: Confirm actual library APIs and patterns before authoring code.',
|
|
361
|
-
'7. No Heavy Dependencies: Packages >5MB or >50 dependencies require explicit human approval.',
|
|
362
|
-
'8. Documentation in /docs: All plans, PRDs, architecture notes, and reports belong in `/docs/`.',
|
|
363
|
-
'9. Session-Start Freshness: Run `git fetch --all --prune` and check `git status -sb` before scoping work.',
|
|
364
|
-
'10. Session-End State Obligation: Update `docs/CURRENT_STATE.md` before concluding any session modifying code.',
|
|
494
|
+
...DEVOS_RULES_DIGEST,
|
|
365
495
|
'',
|
|
366
496
|
'### Solo Session Protocol (Single-Agent Work)',
|
|
367
|
-
|
|
368
|
-
'- Step 2: Implement following `CODING_STANDARDS.md`.',
|
|
369
|
-
'- Step 3: Self-verify with typecheck (`tsc --noEmit` or equivalent) and automated tests.',
|
|
370
|
-
'- Step 4: Present staged review summary to human.',
|
|
371
|
-
'- Step 5: Route commit through `.agents/scripts/commit.sh`.',
|
|
372
|
-
'- Step 6: Update `docs/CURRENT_STATE.md` and log incidents in `docs/LESSONS.md`.',
|
|
373
|
-
'- Escalation: DB schema changes (DBA), security alterations (Security), or loops exceeding 3 attempts must escalate to human.',
|
|
497
|
+
...SOLO_SESSION_PROTOCOL,
|
|
374
498
|
'',
|
|
375
499
|
'### Tooling & Personas',
|
|
376
500
|
'- Slash commands: `.claude/commands/` (generated from `.agents/commands/` — refresh with `devos update`).',
|
|
377
501
|
'- Agent personas: `.claude/agents/` (generated from `.agents/agents/`).',
|
|
502
|
+
'- Task Board: `docs/TASK_BOARD.md` (active DAG state).',
|
|
503
|
+
'- Memory Vault: `.agents/memory/` (ADRs in `decisions/`, handoffs in `handoffs/`).',
|
|
378
504
|
'- Coding standards: `CODING_STANDARDS.md`.',
|
|
379
505
|
'- Master roster & full rules: `.agents/AGENTS.md`.',
|
|
380
506
|
endMarker,
|
|
@@ -396,6 +522,245 @@ function bootstrapClaudeMd(targetDir) {
|
|
|
396
522
|
return 'created';
|
|
397
523
|
}
|
|
398
524
|
|
|
525
|
+
function generateCursorConfig(targetDir) {
|
|
526
|
+
const cursorDir = path.join(targetDir, '.cursor', 'rules');
|
|
527
|
+
fs.mkdirSync(cursorDir, { recursive: true });
|
|
528
|
+
const mdcPath = path.join(cursorDir, 'devos.mdc');
|
|
529
|
+
const mdcContent = [
|
|
530
|
+
'---',
|
|
531
|
+
'description: Dev-OS Autonomous Multi-Agent Engineering rules, Hard Rules, and solo session protocols',
|
|
532
|
+
'globs: *',
|
|
533
|
+
'alwaysApply: true',
|
|
534
|
+
'---',
|
|
535
|
+
'',
|
|
536
|
+
'# Dev-OS — Multi-Agent Engineering OS (Cursor Rules)',
|
|
537
|
+
'',
|
|
538
|
+
'This project uses Dev-OS by Olives Technologies.',
|
|
539
|
+
'',
|
|
540
|
+
'### Hard Rules Digest (Must be strictly obeyed at all times)',
|
|
541
|
+
...DEVOS_RULES_DIGEST,
|
|
542
|
+
'',
|
|
543
|
+
'### Solo Session Protocol',
|
|
544
|
+
...SOLO_SESSION_PROTOCOL,
|
|
545
|
+
'',
|
|
546
|
+
'### Mechanical Commit Gate',
|
|
547
|
+
'Raw `git commit` is strictly blocked. Always commit through `.agents/scripts/commit.sh`.',
|
|
548
|
+
''
|
|
549
|
+
].join('\n');
|
|
550
|
+
fs.writeFileSync(mdcPath, mdcContent, 'utf8');
|
|
551
|
+
|
|
552
|
+
const cursorrulesPath = path.join(targetDir, '.cursorrules');
|
|
553
|
+
const cursorrulesContent = [
|
|
554
|
+
'# Dev-OS Cursor Rules',
|
|
555
|
+
'Follow all Hard Rules defined in .agents/AGENTS.md and .cursor/rules/devos.mdc.',
|
|
556
|
+
'Always use .agents/scripts/commit.sh for committing changes.',
|
|
557
|
+
''
|
|
558
|
+
].join('\n');
|
|
559
|
+
fs.writeFileSync(cursorrulesPath, cursorrulesContent, 'utf8');
|
|
560
|
+
|
|
561
|
+
return 'rules/devos.mdc + .cursorrules';
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
function generateOpenCodeConfig(targetDir) {
|
|
565
|
+
const opencodeDir = path.join(targetDir, '.opencode');
|
|
566
|
+
const rulesDir = path.join(opencodeDir, 'rules');
|
|
567
|
+
fs.mkdirSync(rulesDir, { recursive: true });
|
|
568
|
+
|
|
569
|
+
const rulesPath = path.join(rulesDir, 'devos-rules.md');
|
|
570
|
+
const rulesContent = [
|
|
571
|
+
'# OpenCode Dev-OS Rules',
|
|
572
|
+
'',
|
|
573
|
+
'## Hard Rules Digest',
|
|
574
|
+
...DEVOS_RULES_DIGEST,
|
|
575
|
+
'',
|
|
576
|
+
'## Solo Session Protocol',
|
|
577
|
+
...SOLO_SESSION_PROTOCOL,
|
|
578
|
+
'',
|
|
579
|
+
'## Team Roster & Routing',
|
|
580
|
+
'Read `.agents/AGENTS.md` for agent roles (Orchestrator, Developer, QA, Tester, Security, DevOps, etc.).',
|
|
581
|
+
'Route all git commits through `.agents/scripts/commit.sh`.',
|
|
582
|
+
''
|
|
583
|
+
].join('\n');
|
|
584
|
+
fs.writeFileSync(rulesPath, rulesContent, 'utf8');
|
|
585
|
+
|
|
586
|
+
const openCodeMdPath = path.join(targetDir, 'OPENCODE.md');
|
|
587
|
+
const openCodeMdContent = [
|
|
588
|
+
'# Dev-OS — OpenCode Instructions',
|
|
589
|
+
'',
|
|
590
|
+
'This project uses Dev-OS by Olives Technologies.',
|
|
591
|
+
'',
|
|
592
|
+
'### Hard Rules Digest',
|
|
593
|
+
...DEVOS_RULES_DIGEST,
|
|
594
|
+
'',
|
|
595
|
+
'### Solo Session Protocol',
|
|
596
|
+
...SOLO_SESSION_PROTOCOL,
|
|
597
|
+
'',
|
|
598
|
+
'### Core Resources',
|
|
599
|
+
'- Personas: `.agents/agents/`',
|
|
600
|
+
'- Skills: `.agents/skills/`',
|
|
601
|
+
'- Task Board: `docs/TASK_BOARD.md`',
|
|
602
|
+
'- Memory Vault: `.agents/memory/`',
|
|
603
|
+
'- Commit Gate: `.agents/scripts/commit.sh`',
|
|
604
|
+
''
|
|
605
|
+
].join('\n');
|
|
606
|
+
fs.writeFileSync(openCodeMdPath, openCodeMdContent, 'utf8');
|
|
607
|
+
|
|
608
|
+
const configPath = path.join(opencodeDir, 'opencode.json');
|
|
609
|
+
const configContent = JSON.stringify({
|
|
610
|
+
name: 'Dev-OS',
|
|
611
|
+
version: PKG.version,
|
|
612
|
+
rules: ['.opencode/rules/devos-rules.md'],
|
|
613
|
+
manifest: '.agents/manifest.json'
|
|
614
|
+
}, null, 2) + '\n';
|
|
615
|
+
fs.writeFileSync(configPath, configContent, 'utf8');
|
|
616
|
+
|
|
617
|
+
return 'OPENCODE.md + .opencode/rules/devos-rules.md';
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
function generateAntigravityConfig(targetDir) {
|
|
621
|
+
const antigravityMdPath = path.join(targetDir, 'ANTIGRAVITY.md');
|
|
622
|
+
const geminiMdPath = path.join(targetDir, 'GEMINI.md');
|
|
623
|
+
const content = [
|
|
624
|
+
'# Dev-OS — Google Antigravity & Gemini Instructions',
|
|
625
|
+
'',
|
|
626
|
+
'This project uses Dev-OS by Olives Technologies.',
|
|
627
|
+
'',
|
|
628
|
+
'### Hard Rules Digest (Must be strictly obeyed at all times)',
|
|
629
|
+
...DEVOS_RULES_DIGEST,
|
|
630
|
+
'',
|
|
631
|
+
'### Solo Session Protocol',
|
|
632
|
+
...SOLO_SESSION_PROTOCOL,
|
|
633
|
+
'',
|
|
634
|
+
'### Core Resources',
|
|
635
|
+
'- Personas: `.agents/agents/`',
|
|
636
|
+
'- Specialist Skills: `.agents/skills/`',
|
|
637
|
+
'- Task Board: `docs/TASK_BOARD.md`',
|
|
638
|
+
'- Shared Memory Vault: `.agents/memory/`',
|
|
639
|
+
'',
|
|
640
|
+
'### Mechanical Commit Gate',
|
|
641
|
+
'Never execute raw `git commit`. Always commit through `.agents/scripts/commit.sh`.',
|
|
642
|
+
''
|
|
643
|
+
].join('\n');
|
|
644
|
+
fs.writeFileSync(antigravityMdPath, content, 'utf8');
|
|
645
|
+
fs.writeFileSync(geminiMdPath, content, 'utf8');
|
|
646
|
+
return 'ANTIGRAVITY.md + GEMINI.md';
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
function generateGeminiConfig(targetDir) {
|
|
650
|
+
return generateAntigravityConfig(targetDir);
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
function generateCodexConfig(targetDir) {
|
|
654
|
+
const codexDir = path.join(targetDir, '.codex');
|
|
655
|
+
fs.mkdirSync(codexDir, { recursive: true });
|
|
656
|
+
const instructionsPath = path.join(codexDir, 'instructions.md');
|
|
657
|
+
const content = [
|
|
658
|
+
'# Dev-OS — Codex Instructions',
|
|
659
|
+
'',
|
|
660
|
+
'### Hard Rules Digest',
|
|
661
|
+
...DEVOS_RULES_DIGEST,
|
|
662
|
+
'',
|
|
663
|
+
'### Solo Session Protocol',
|
|
664
|
+
...SOLO_SESSION_PROTOCOL,
|
|
665
|
+
'',
|
|
666
|
+
'Always use `.agents/scripts/commit.sh` for commits.',
|
|
667
|
+
''
|
|
668
|
+
].join('\n');
|
|
669
|
+
fs.writeFileSync(instructionsPath, content, 'utf8');
|
|
670
|
+
|
|
671
|
+
const windsurfPath = path.join(targetDir, '.windsurfrules');
|
|
672
|
+
fs.writeFileSync(windsurfPath, '# Dev-OS Windsurf Rules\nFollow rules in .agents/AGENTS.md and .codex/instructions.md.\n', 'utf8');
|
|
673
|
+
return '.codex/instructions.md + .windsurfrules';
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
function wireHooks(destAgents, destClaude) {
|
|
677
|
+
const hooksDir = path.join(destAgents, 'hooks');
|
|
678
|
+
if (fs.existsSync(hooksDir)) {
|
|
679
|
+
fs.readdirSync(hooksDir).forEach((file) => {
|
|
680
|
+
if (file.endsWith('.sh')) {
|
|
681
|
+
fs.chmodSync(path.join(hooksDir, file), '755');
|
|
682
|
+
}
|
|
683
|
+
});
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
if (destClaude) {
|
|
687
|
+
fs.mkdirSync(destClaude, { recursive: true });
|
|
688
|
+
const claudeHooksPath = path.join(destClaude, 'hooks.json');
|
|
689
|
+
const hooksConfig = {
|
|
690
|
+
hooks: {
|
|
691
|
+
SessionStart: [{ command: '.agents/hooks/session-start.sh' }],
|
|
692
|
+
PreToolUse: [{ matcher: 'bash', command: '.agents/hooks/pre-tool-use.sh' }],
|
|
693
|
+
SessionEnd: [{ command: '.agents/hooks/session-end.sh' }]
|
|
694
|
+
}
|
|
695
|
+
};
|
|
696
|
+
fs.writeFileSync(claudeHooksPath, JSON.stringify(hooksConfig, null, 2) + '\n', 'utf8');
|
|
697
|
+
return 'executable hooks + .claude/hooks.json';
|
|
698
|
+
}
|
|
699
|
+
return 'executable hooks (.agents/hooks/)';
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
// ---------------------------------------------------------------------------
|
|
703
|
+
// Capability Packs & Skills Copying Helper
|
|
704
|
+
// ---------------------------------------------------------------------------
|
|
705
|
+
|
|
706
|
+
function installSkillsAndPacks(srcAgents, destAgents, stack, allSkills, telemetry = true, mode = 'interactive') {
|
|
707
|
+
const srcSkills = path.join(srcAgents, 'skills');
|
|
708
|
+
const destSkills = path.join(destAgents, 'skills');
|
|
709
|
+
const packsPath = path.join(srcAgents, 'packs.json');
|
|
710
|
+
const manifestPath = path.join(destAgents, 'manifest.json');
|
|
711
|
+
fs.mkdirSync(destSkills, { recursive: true });
|
|
712
|
+
|
|
713
|
+
const packsData = fs.existsSync(packsPath) ? JSON.parse(fs.readFileSync(packsPath, 'utf8')) : null;
|
|
714
|
+
|
|
715
|
+
if (allSkills || !packsData) {
|
|
716
|
+
copyRecursiveSync(srcSkills, destSkills);
|
|
717
|
+
const installed = packsData ? Object.keys(packsData.packs) : ['all'];
|
|
718
|
+
const manifest = {
|
|
719
|
+
version: PKG.version,
|
|
720
|
+
installedPacks: installed,
|
|
721
|
+
hooksEnabled: true,
|
|
722
|
+
telemetry: telemetry ? 'on' : 'off',
|
|
723
|
+
mode: mode || 'interactive',
|
|
724
|
+
updatedAt: new Date().toISOString()
|
|
725
|
+
};
|
|
726
|
+
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n', 'utf8');
|
|
727
|
+
return { count: countSkills(destSkills), packs: installed };
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
// Lean pack installation
|
|
731
|
+
const installedPacks = ['core'];
|
|
732
|
+
const skillsToInstall = new Set(packsData.packs.core ? packsData.packs.core.skills : []);
|
|
733
|
+
|
|
734
|
+
// Check if stack matches a pack
|
|
735
|
+
Object.keys(packsData.packs).forEach((pKey) => {
|
|
736
|
+
const p = packsData.packs[pKey];
|
|
737
|
+
if (p.stack === stack || pKey === stack) {
|
|
738
|
+
installedPacks.push(pKey);
|
|
739
|
+
p.skills.forEach((s) => skillsToInstall.add(s));
|
|
740
|
+
}
|
|
741
|
+
});
|
|
742
|
+
|
|
743
|
+
skillsToInstall.forEach((skillName) => {
|
|
744
|
+
const src = path.join(srcSkills, skillName);
|
|
745
|
+
const dest = path.join(destSkills, skillName);
|
|
746
|
+
if (fs.existsSync(src)) {
|
|
747
|
+
copyRecursiveSync(src, dest);
|
|
748
|
+
}
|
|
749
|
+
});
|
|
750
|
+
|
|
751
|
+
const manifest = {
|
|
752
|
+
version: PKG.version,
|
|
753
|
+
installedPacks,
|
|
754
|
+
hooksEnabled: true,
|
|
755
|
+
telemetry: telemetry ? 'on' : 'off',
|
|
756
|
+
mode: mode || 'interactive',
|
|
757
|
+
updatedAt: new Date().toISOString()
|
|
758
|
+
};
|
|
759
|
+
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n', 'utf8');
|
|
760
|
+
|
|
761
|
+
return { count: countSkills(destSkills), packs: installedPacks };
|
|
762
|
+
}
|
|
763
|
+
|
|
399
764
|
// ---------------------------------------------------------------------------
|
|
400
765
|
// init
|
|
401
766
|
// ---------------------------------------------------------------------------
|
|
@@ -408,11 +773,39 @@ async function runInit(flags) {
|
|
|
408
773
|
console.log(`${colors.yellow}[ WARN ] You are running init inside the Dev-OS source repository itself. Template copy steps will be skipped.${colors.reset}\n`);
|
|
409
774
|
}
|
|
410
775
|
|
|
411
|
-
const { isFresh, stack } = await promptInitOptions(flags);
|
|
776
|
+
const { isFresh, stack, platform, telemetry, mode } = await promptInitOptions(flags);
|
|
777
|
+
|
|
778
|
+
// Determine target AI harnesses
|
|
779
|
+
const selectedHarnesses = new Set();
|
|
780
|
+
const rawChoice = flags.harness || flags.platform || platform || (flags.allHarnesses ? 'all' : null);
|
|
781
|
+
|
|
782
|
+
if (rawChoice === 'all' || flags.allHarnesses) {
|
|
783
|
+
selectedHarnesses.add('claude');
|
|
784
|
+
selectedHarnesses.add('antigravity');
|
|
785
|
+
selectedHarnesses.add('cursor');
|
|
786
|
+
selectedHarnesses.add('opencode');
|
|
787
|
+
selectedHarnesses.add('codex');
|
|
788
|
+
} else if (rawChoice) {
|
|
789
|
+
rawChoice.split(',').map((h) => h.trim().toLowerCase()).forEach((h) => {
|
|
790
|
+
if (h === 'gemini') h = 'antigravity';
|
|
791
|
+
if (h === 'windsurf') h = 'codex';
|
|
792
|
+
if (h === 'all') {
|
|
793
|
+
['claude', 'antigravity', 'cursor', 'opencode', 'codex'].forEach((p) => selectedHarnesses.add(p));
|
|
794
|
+
} else if (HARNESSES.includes(h) || PLATFORMS.includes(h)) {
|
|
795
|
+
selectedHarnesses.add(h);
|
|
796
|
+
}
|
|
797
|
+
});
|
|
798
|
+
} else {
|
|
799
|
+
['claude', 'antigravity', 'cursor', 'opencode', 'codex'].forEach((p) => selectedHarnesses.add(p));
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
if (flags.claude === false) {
|
|
803
|
+
selectedHarnesses.delete('claude');
|
|
804
|
+
}
|
|
412
805
|
|
|
413
806
|
console.log(`\n${colors.cyan}[ INFO ] Initializing Dev-OS in target directory...${colors.reset}`);
|
|
414
807
|
console.log(`${colors.gray}Target Path: ${TARGET_DIR}${colors.reset}`);
|
|
415
|
-
console.log(`${colors.gray}Mode: ${isFresh ? 'Fresh Project' : 'Existing Project'} | Stack: [${stack.toUpperCase()}]${colors.reset}\n`);
|
|
808
|
+
console.log(`${colors.gray}Mode: ${isFresh ? 'Fresh Project' : 'Existing Project'} | Stack: [${stack.toUpperCase()}] | Platform: [${platform.toUpperCase()}]${colors.reset}\n`);
|
|
416
809
|
|
|
417
810
|
const srcAgents = path.join(TEMPLATE_DIR, '.agents');
|
|
418
811
|
const destAgents = path.join(TARGET_DIR, '.agents');
|
|
@@ -429,7 +822,8 @@ async function runInit(flags) {
|
|
|
429
822
|
}
|
|
430
823
|
};
|
|
431
824
|
|
|
432
|
-
// Step 1: Back up any existing .agents/, then copy
|
|
825
|
+
// Step 1: Back up any existing .agents/, then copy components
|
|
826
|
+
let packSummary = null;
|
|
433
827
|
if (!insideSource) {
|
|
434
828
|
if (fs.existsSync(destAgents)) {
|
|
435
829
|
step('Backing up existing .agents/ to .agents/_backup/', () => {
|
|
@@ -439,14 +833,34 @@ async function runInit(flags) {
|
|
|
439
833
|
return `saved (${path.relative(TARGET_DIR, backupDir)})`;
|
|
440
834
|
});
|
|
441
835
|
}
|
|
442
|
-
|
|
443
|
-
|
|
836
|
+
|
|
837
|
+
step('Installing agent roster, hooks, and memory templates', () => {
|
|
838
|
+
// Copy core structure excluding skills
|
|
839
|
+
const subdirs = ['agents', 'commands', 'hooks', 'memory', 'scripts', 'templates'];
|
|
840
|
+
subdirs.forEach((dir) => {
|
|
841
|
+
const src = path.join(srcAgents, dir);
|
|
842
|
+
const dest = path.join(destAgents, dir);
|
|
843
|
+
if (fs.existsSync(src)) copyRecursiveSync(src, dest);
|
|
844
|
+
});
|
|
845
|
+
['AGENTS.md', 'README.md', 'packs.json'].forEach((file) => {
|
|
846
|
+
const src = path.join(srcAgents, file);
|
|
847
|
+
const dest = path.join(destAgents, file);
|
|
848
|
+
if (fs.existsSync(src)) fs.copyFileSync(src, dest);
|
|
849
|
+
});
|
|
850
|
+
});
|
|
851
|
+
|
|
852
|
+
step('Installing specialist skills and capability packs', () => {
|
|
853
|
+
packSummary = installSkillsAndPacks(srcAgents, destAgents, stack, flags.allSkills, telemetry, mode);
|
|
854
|
+
return `${packSummary.count} skills (packs: ${packSummary.packs.join(', ')})`;
|
|
444
855
|
});
|
|
445
856
|
}
|
|
446
857
|
|
|
447
|
-
//
|
|
448
|
-
|
|
449
|
-
|
|
858
|
+
// Ensure telemetry buffer directory exists
|
|
859
|
+
fs.mkdirSync(path.join(destAgents, 'telemetry'), { recursive: true });
|
|
860
|
+
|
|
861
|
+
// Step 2: Ensure script permissions (commit gate, hook installer, humanizer check)
|
|
862
|
+
step('Configuring commit gate and verification scripts', () => {
|
|
863
|
+
const scripts = ['commit.sh', 'install-hooks.sh', 'humanize-check.sh'];
|
|
450
864
|
const missing = [];
|
|
451
865
|
scripts.forEach((name) => {
|
|
452
866
|
const scriptPath = path.join(destAgents, 'scripts', name);
|
|
@@ -456,11 +870,19 @@ async function runInit(flags) {
|
|
|
456
870
|
missing.push(name);
|
|
457
871
|
}
|
|
458
872
|
});
|
|
459
|
-
if (missing.length === scripts.length) throw new Error('
|
|
873
|
+
if (missing.length === scripts.length) throw new Error('critical scripts are missing from .agents/scripts/');
|
|
460
874
|
return missing.length ? `partial (missing: ${missing.join(', ')})` : 'executable (755)';
|
|
461
875
|
});
|
|
462
876
|
|
|
463
|
-
// Step 2b:
|
|
877
|
+
// Step 2b: Wire runtime lifecycle hooks
|
|
878
|
+
if (flags.hooks) {
|
|
879
|
+
step('Wiring runtime lifecycle hooks (.agents/hooks/)', () => {
|
|
880
|
+
const claudeDest = selectedHarnesses.has('claude') ? path.join(TARGET_DIR, '.claude') : null;
|
|
881
|
+
return wireHooks(destAgents, claudeDest);
|
|
882
|
+
});
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
// Step 2c: Install git pre-commit hook automatically if inside a git repository
|
|
464
886
|
const gitDir = path.join(TARGET_DIR, '.git');
|
|
465
887
|
if (fs.existsSync(gitDir)) {
|
|
466
888
|
step('Installing mechanical pre-commit hook (.git/hooks/pre-commit)', () => {
|
|
@@ -475,14 +897,22 @@ async function runInit(flags) {
|
|
|
475
897
|
});
|
|
476
898
|
}
|
|
477
899
|
|
|
478
|
-
// Step 3: Copy docs directory if fresh or missing
|
|
900
|
+
// Step 3: Copy docs directory and TASK_BOARD.md if fresh or missing
|
|
479
901
|
const destDocs = path.join(TARGET_DIR, 'docs');
|
|
480
902
|
if (!insideSource && (isFresh || !fs.existsSync(destDocs))) {
|
|
481
903
|
step('Installing project documentation into docs/', () => {
|
|
482
904
|
copyRecursiveSync(path.join(TEMPLATE_DIR, 'docs'), destDocs);
|
|
483
905
|
});
|
|
484
906
|
} else {
|
|
485
|
-
|
|
907
|
+
// Ensure docs/TASK_BOARD.md exists
|
|
908
|
+
const srcBoard = path.join(TEMPLATE_DIR, 'docs', 'TASK_BOARD.md');
|
|
909
|
+
const destBoard = path.join(destDocs, 'TASK_BOARD.md');
|
|
910
|
+
if (fs.existsSync(srcBoard) && !fs.existsSync(destBoard)) {
|
|
911
|
+
step('Installing deterministic task board (docs/TASK_BOARD.md)', () => {
|
|
912
|
+
fs.mkdirSync(destDocs, { recursive: true });
|
|
913
|
+
fs.copyFileSync(srcBoard, destBoard);
|
|
914
|
+
});
|
|
915
|
+
}
|
|
486
916
|
}
|
|
487
917
|
|
|
488
918
|
// Step 4: Handle CODING_STANDARDS.md
|
|
@@ -499,13 +929,11 @@ async function runInit(flags) {
|
|
|
499
929
|
if (!fs.existsSync(srcStandards)) return 'skipped (template not found)';
|
|
500
930
|
fs.copyFileSync(srcStandards, targetStandards);
|
|
501
931
|
});
|
|
502
|
-
} else {
|
|
503
|
-
console.log(`${colors.gray}Preserving existing CODING_STANDARDS.md${colors.reset}`);
|
|
504
932
|
}
|
|
505
933
|
|
|
506
|
-
// Step 5: Claude Code
|
|
934
|
+
// Step 5: Multi-Harness Integration (Claude Code, Antigravity/Gemini, Cursor, OpenCode, Codex)
|
|
507
935
|
let claudeSummary = null;
|
|
508
|
-
if (
|
|
936
|
+
if (selectedHarnesses.has('claude')) {
|
|
509
937
|
step('Wiring Claude Code integration (.claude/, CLAUDE.md)', () => {
|
|
510
938
|
const destClaude = path.join(TARGET_DIR, '.claude');
|
|
511
939
|
const cmdCount = generateClaudeCommands(destAgents, destClaude);
|
|
@@ -514,27 +942,59 @@ async function runInit(flags) {
|
|
|
514
942
|
claudeSummary = { cmdCount, agentCount, claudeMd };
|
|
515
943
|
return `${cmdCount} commands, ${agentCount} agents (CLAUDE.md ${claudeMd})`;
|
|
516
944
|
});
|
|
517
|
-
}
|
|
518
|
-
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
if (selectedHarnesses.has('antigravity') || selectedHarnesses.has('gemini')) {
|
|
948
|
+
step('Wiring Google Antigravity / Gemini integration (ANTIGRAVITY.md, GEMINI.md)', () => {
|
|
949
|
+
return generateAntigravityConfig(TARGET_DIR);
|
|
950
|
+
});
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
if (selectedHarnesses.has('cursor')) {
|
|
954
|
+
step('Wiring Cursor integration (.cursor/rules/devos.mdc, .cursorrules)', () => {
|
|
955
|
+
return generateCursorConfig(TARGET_DIR);
|
|
956
|
+
});
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
if (selectedHarnesses.has('opencode')) {
|
|
960
|
+
step('Wiring OpenCode integration (OPENCODE.md, .opencode/)', () => {
|
|
961
|
+
return generateOpenCodeConfig(TARGET_DIR);
|
|
962
|
+
});
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
if (selectedHarnesses.has('codex')) {
|
|
966
|
+
step('Wiring Codex / Windsurf integration (.codex/, .windsurfrules)', () => {
|
|
967
|
+
return generateCodexConfig(TARGET_DIR);
|
|
968
|
+
});
|
|
519
969
|
}
|
|
520
970
|
|
|
521
971
|
// Step 6: Update .gitignore
|
|
522
972
|
step('Updating .gitignore rules', () => {
|
|
523
973
|
const gitignorePath = path.join(TARGET_DIR, '.gitignore');
|
|
524
974
|
let gitignoreContent = fs.existsSync(gitignorePath) ? fs.readFileSync(gitignorePath, 'utf8') : '';
|
|
525
|
-
|
|
526
|
-
gitignoreContent
|
|
527
|
-
|
|
528
|
-
|
|
975
|
+
let updated = false;
|
|
976
|
+
if (!gitignoreContent.includes('.agents/_backup')) {
|
|
977
|
+
gitignoreContent += `\n# Dev-OS temporary backups\n.agents/_backup/\n`;
|
|
978
|
+
updated = true;
|
|
979
|
+
}
|
|
980
|
+
if (updated) {
|
|
981
|
+
fs.writeFileSync(gitignorePath, gitignoreContent.trim() + '\n', 'utf8');
|
|
982
|
+
return 'updated';
|
|
983
|
+
}
|
|
984
|
+
return 'already up to date';
|
|
529
985
|
});
|
|
530
986
|
|
|
531
987
|
// Summary card
|
|
532
988
|
const agentCount = countAgents(path.join(destAgents, 'agents'));
|
|
533
989
|
const skillCount = countSkills(path.join(destAgents, 'skills'));
|
|
990
|
+
const harnessesList = Array.from(selectedHarnesses);
|
|
534
991
|
|
|
535
992
|
const rows = [
|
|
536
993
|
['.agents/agents/', `${agentCount} Agent Personas (Orchestrator, Developer, QA, DBA, Security...)`],
|
|
537
|
-
['.agents/skills/', `${skillCount} Specialist
|
|
994
|
+
['.agents/skills/', `${skillCount} Specialist Skills (Packs: ${(packSummary ? packSummary.packs : ['core']).join(', ')})`],
|
|
995
|
+
['.agents/hooks/', 'Runtime Lifecycle Hooks (SessionStart, PreToolUse, SessionEnd)'],
|
|
996
|
+
['.agents/memory/', 'Shared Memory Vault (ADRs in decisions/, session handoffs)'],
|
|
997
|
+
['docs/TASK_BOARD.md', 'Deterministic Task Board & DAG Workflow State'],
|
|
538
998
|
['.agents/scripts/', 'Commit Checkpoint Gate (commit.sh) + Hook Installer'],
|
|
539
999
|
['.agents/AGENTS.md', 'Team Roster & Triage Rules'],
|
|
540
1000
|
['CODING_STANDARDS.md', `Stack Standards [${stack.toUpperCase()}]`]
|
|
@@ -542,6 +1002,7 @@ async function runInit(flags) {
|
|
|
542
1002
|
if (claudeSummary) {
|
|
543
1003
|
rows.push(['.claude/', `${claudeSummary.cmdCount} Slash Commands + ${claudeSummary.agentCount} Subagents (Claude Code)`]);
|
|
544
1004
|
}
|
|
1005
|
+
rows.push(['Harnesses', harnessesList.join(', ')]);
|
|
545
1006
|
|
|
546
1007
|
console.log(`\n${colors.green}${colors.bold}[ OK ] Dev-OS Environment Initialized Successfully${colors.reset}\n`);
|
|
547
1008
|
const labelWidth = Math.max(...rows.map((r) => r[0].length)) + 2;
|
|
@@ -559,9 +1020,9 @@ async function runInit(flags) {
|
|
|
559
1020
|
|
|
560
1021
|
if (!flags.quiet) {
|
|
561
1022
|
console.log(`\n${colors.bold}NEXT STEPS${colors.reset}`);
|
|
562
|
-
console.log(` 1.
|
|
563
|
-
console.log(` 2.
|
|
564
|
-
console.log(` 3.
|
|
1023
|
+
console.log(` 1. Open your AI engineering environment (${harnessesList.join(', ')}).`);
|
|
1024
|
+
console.log(` 2. Prompt the Orchestrator: ${colors.yellow}"Use your grill-me skill to brainstorm our project requirements."${colors.reset}`);
|
|
1025
|
+
console.log(` 3. Track tasks with: ${colors.cyan}/task${colors.reset} or inspect ${colors.cyan}docs/TASK_BOARD.md${colors.reset}.`);
|
|
565
1026
|
console.log(` 4. Run ${colors.cyan}devos doctor${colors.reset} anytime to verify system health.\n`);
|
|
566
1027
|
}
|
|
567
1028
|
}
|
|
@@ -607,34 +1068,91 @@ async function runUpdate(flags) {
|
|
|
607
1068
|
return `saved (${path.relative(TARGET_DIR, backupDir)})`;
|
|
608
1069
|
});
|
|
609
1070
|
|
|
610
|
-
// 2. Refresh .agents/
|
|
611
|
-
step('Refreshing agent personas,
|
|
612
|
-
|
|
1071
|
+
// 2. Refresh .agents/ subdirectories
|
|
1072
|
+
step('Refreshing agent personas, hooks, memory, and scripts', () => {
|
|
1073
|
+
['agents', 'commands', 'hooks', 'scripts', 'templates'].forEach((dir) => {
|
|
1074
|
+
const src = path.join(srcAgents, dir);
|
|
1075
|
+
const dest = path.join(destAgents, dir);
|
|
1076
|
+
if (fs.existsSync(src)) copyRecursiveSync(src, dest);
|
|
1077
|
+
});
|
|
1078
|
+
// Refresh memory templates without deleting user ADRs
|
|
1079
|
+
const srcMemDec = path.join(srcAgents, 'memory', 'decisions', 'ADR-000-template.md');
|
|
1080
|
+
const destMemDec = path.join(destAgents, 'memory', 'decisions');
|
|
1081
|
+
fs.mkdirSync(destMemDec, { recursive: true });
|
|
1082
|
+
if (fs.existsSync(srcMemDec)) fs.copyFileSync(srcMemDec, path.join(destMemDec, 'ADR-000-template.md'));
|
|
1083
|
+
|
|
1084
|
+
const srcMemHand = path.join(srcAgents, 'memory', 'handoffs', 'handoff-template.md');
|
|
1085
|
+
const destMemHand = path.join(destAgents, 'memory', 'handoffs');
|
|
1086
|
+
fs.mkdirSync(destMemHand, { recursive: true });
|
|
1087
|
+
if (fs.existsSync(srcMemHand)) fs.copyFileSync(srcMemHand, path.join(destMemHand, 'handoff-template.md'));
|
|
1088
|
+
|
|
1089
|
+
['AGENTS.md', 'README.md', 'packs.json'].forEach((file) => {
|
|
1090
|
+
const src = path.join(srcAgents, file);
|
|
1091
|
+
const dest = path.join(destAgents, file);
|
|
1092
|
+
if (fs.existsSync(src)) fs.copyFileSync(src, dest);
|
|
1093
|
+
});
|
|
613
1094
|
});
|
|
614
1095
|
}
|
|
615
1096
|
|
|
616
|
-
// 3. Ensure executable permissions
|
|
617
|
-
step('Verifying script permissions (commit.sh, install-hooks.sh)', () => {
|
|
618
|
-
const scripts = ['commit.sh', 'install-hooks.sh'];
|
|
1097
|
+
// 3. Ensure executable script permissions
|
|
1098
|
+
step('Verifying script permissions (commit.sh, install-hooks.sh, humanize-check.sh, hooks/*.sh)', () => {
|
|
1099
|
+
const scripts = ['commit.sh', 'install-hooks.sh', 'humanize-check.sh'];
|
|
619
1100
|
scripts.forEach((name) => {
|
|
620
1101
|
const p = path.join(destAgents, 'scripts', name);
|
|
621
1102
|
if (fs.existsSync(p)) fs.chmodSync(p, '755');
|
|
622
1103
|
});
|
|
1104
|
+
const hooksDir = path.join(destAgents, 'hooks');
|
|
1105
|
+
if (fs.existsSync(hooksDir)) {
|
|
1106
|
+
fs.readdirSync(hooksDir).forEach((file) => {
|
|
1107
|
+
if (file.endsWith('.sh')) fs.chmodSync(path.join(hooksDir, file), '755');
|
|
1108
|
+
});
|
|
1109
|
+
}
|
|
623
1110
|
return 'executable (755)';
|
|
624
1111
|
});
|
|
625
1112
|
|
|
626
|
-
// 4.
|
|
627
|
-
if (flags.
|
|
628
|
-
step('Refreshing
|
|
629
|
-
|
|
630
|
-
const cmdCount = generateClaudeCommands(destAgents, destClaude);
|
|
631
|
-
const agentCount = generateClaudeAgents(destAgents, destClaude);
|
|
632
|
-
const claudeMd = bootstrapClaudeMd(TARGET_DIR);
|
|
633
|
-
return `${cmdCount} commands, ${agentCount} agents (CLAUDE.md ${claudeMd})`;
|
|
1113
|
+
// 4. Update runtime lifecycle hooks
|
|
1114
|
+
if (flags.hooks) {
|
|
1115
|
+
step('Refreshing runtime lifecycle hooks', () => {
|
|
1116
|
+
return wireHooks(destAgents, path.join(TARGET_DIR, '.claude'));
|
|
634
1117
|
});
|
|
635
1118
|
}
|
|
636
1119
|
|
|
637
|
-
// 5.
|
|
1120
|
+
// 5. Multi-Harness refresh
|
|
1121
|
+
step('Refreshing AI harness configurations (Claude Code, Cursor, OpenCode, Antigravity, Codex)', () => {
|
|
1122
|
+
const destClaude = path.join(TARGET_DIR, '.claude');
|
|
1123
|
+
generateClaudeCommands(destAgents, destClaude);
|
|
1124
|
+
generateClaudeAgents(destAgents, destClaude);
|
|
1125
|
+
bootstrapClaudeMd(TARGET_DIR);
|
|
1126
|
+
generateCursorConfig(TARGET_DIR);
|
|
1127
|
+
generateOpenCodeConfig(TARGET_DIR);
|
|
1128
|
+
generateAntigravityConfig(TARGET_DIR);
|
|
1129
|
+
generateCodexConfig(TARGET_DIR);
|
|
1130
|
+
return 'Claude Code, Cursor, OpenCode, Antigravity/Gemini, Codex synchronized';
|
|
1131
|
+
});
|
|
1132
|
+
|
|
1133
|
+
// 5b. Refresh skills if requested
|
|
1134
|
+
if (flags.skills || flags.allSkills) {
|
|
1135
|
+
step('Refreshing specialist skills and capability packs', () => {
|
|
1136
|
+
const srcSkills = path.join(srcAgents, 'skills');
|
|
1137
|
+
const destSkills = path.join(destAgents, 'skills');
|
|
1138
|
+
let msg = 'skipped';
|
|
1139
|
+
if (fs.existsSync(srcSkills)) {
|
|
1140
|
+
copyRecursiveSync(srcSkills, destSkills);
|
|
1141
|
+
msg = `${countSkills(destSkills)} skills synchronized`;
|
|
1142
|
+
}
|
|
1143
|
+
try {
|
|
1144
|
+
const { spawnSync } = require('child_process');
|
|
1145
|
+
spawnSync('npx', ['skills', 'update', '-y'], {
|
|
1146
|
+
cwd: TARGET_DIR,
|
|
1147
|
+
stdio: 'ignore',
|
|
1148
|
+
env: { ...process.env, CI: '1' }
|
|
1149
|
+
});
|
|
1150
|
+
} catch (e) {}
|
|
1151
|
+
return msg;
|
|
1152
|
+
});
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
// 6. Pre-commit hook
|
|
638
1156
|
const gitDir = path.join(TARGET_DIR, '.git');
|
|
639
1157
|
if (fs.existsSync(gitDir)) {
|
|
640
1158
|
step('Updating mechanical pre-commit hook', () => {
|
|
@@ -652,6 +1170,180 @@ async function runUpdate(flags) {
|
|
|
652
1170
|
console.log(`\n${colors.green}${colors.bold}[ OK ] Dev-OS updated to v${PKG.version} successfully.${colors.reset}\n`);
|
|
653
1171
|
}
|
|
654
1172
|
|
|
1173
|
+
// ---------------------------------------------------------------------------
|
|
1174
|
+
// pack
|
|
1175
|
+
// ---------------------------------------------------------------------------
|
|
1176
|
+
|
|
1177
|
+
function runPack(flags, positional) {
|
|
1178
|
+
const subCmd = positional[0] || 'list';
|
|
1179
|
+
const manifestPath = path.join(TARGET_DIR, '.agents', 'manifest.json');
|
|
1180
|
+
const packsPath = path.join(TEMPLATE_DIR, '.agents', 'packs.json');
|
|
1181
|
+
if (!fs.existsSync(packsPath)) {
|
|
1182
|
+
console.error(`${colors.red}[ FAIL ] Capability packs registry (.agents/packs.json) not found.${colors.reset}`);
|
|
1183
|
+
process.exit(1);
|
|
1184
|
+
}
|
|
1185
|
+
const packsData = JSON.parse(fs.readFileSync(packsPath, 'utf8'));
|
|
1186
|
+
const manifest = fs.existsSync(manifestPath) ? JSON.parse(fs.readFileSync(manifestPath, 'utf8')) : { installedPacks: [] };
|
|
1187
|
+
|
|
1188
|
+
if (subCmd === 'list') {
|
|
1189
|
+
if (!flags.quiet && !flags.json) printBanner();
|
|
1190
|
+
if (flags.json) {
|
|
1191
|
+
console.log(JSON.stringify({ availablePacks: packsData.packs, installedPacks: manifest.installedPacks || [] }, null, 2));
|
|
1192
|
+
return;
|
|
1193
|
+
}
|
|
1194
|
+
console.log(`${colors.bold}DEV-OS CAPABILITY PACKS${colors.reset}`);
|
|
1195
|
+
console.log(`${colors.gray}${RULE}${colors.reset}\n`);
|
|
1196
|
+
Object.keys(packsData.packs).forEach((key) => {
|
|
1197
|
+
const p = packsData.packs[key];
|
|
1198
|
+
const isInstalled = (manifest.installedPacks || []).includes(key);
|
|
1199
|
+
const tag = isInstalled ? `${colors.green}[installed]${colors.reset}` : `${colors.gray}[available]${colors.reset}`;
|
|
1200
|
+
console.log(` ${colors.cyan}${colors.bold}${key.padEnd(12)}${colors.reset} ${tag} ${p.name}`);
|
|
1201
|
+
console.log(` ${colors.gray}${p.description}${colors.reset}`);
|
|
1202
|
+
console.log(` ${colors.dim}Skills (${p.skills.length}): ${p.skills.join(', ')}${colors.reset}\n`);
|
|
1203
|
+
});
|
|
1204
|
+
console.log(`Add a pack: ${colors.cyan}devos pack add <name>${colors.reset}\n`);
|
|
1205
|
+
return;
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
if (subCmd === 'add') {
|
|
1209
|
+
const packName = positional[1];
|
|
1210
|
+
if (!packName || !packsData.packs[packName]) {
|
|
1211
|
+
console.error(`${colors.red}[ FAIL ] Unknown pack '${packName}'. Available: ${Object.keys(packsData.packs).join(', ')}${colors.reset}`);
|
|
1212
|
+
process.exit(1);
|
|
1213
|
+
}
|
|
1214
|
+
const pack = packsData.packs[packName];
|
|
1215
|
+
const destSkills = path.join(TARGET_DIR, '.agents', 'skills');
|
|
1216
|
+
fs.mkdirSync(destSkills, { recursive: true });
|
|
1217
|
+
|
|
1218
|
+
let addedCount = 0;
|
|
1219
|
+
pack.skills.forEach((skillName) => {
|
|
1220
|
+
const srcSkill = path.join(TEMPLATE_DIR, '.agents', 'skills', skillName);
|
|
1221
|
+
const destSkill = path.join(destSkills, skillName);
|
|
1222
|
+
if (fs.existsSync(srcSkill)) {
|
|
1223
|
+
copyRecursiveSync(srcSkill, destSkill);
|
|
1224
|
+
addedCount++;
|
|
1225
|
+
}
|
|
1226
|
+
});
|
|
1227
|
+
|
|
1228
|
+
if (!manifest.installedPacks) manifest.installedPacks = [];
|
|
1229
|
+
if (!manifest.installedPacks.includes(packName)) manifest.installedPacks.push(packName);
|
|
1230
|
+
manifest.updatedAt = new Date().toISOString();
|
|
1231
|
+
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n', 'utf8');
|
|
1232
|
+
|
|
1233
|
+
console.log(`${colors.green}[ OK ] Pack '${packName}' added successfully (${addedCount} skills installed).${colors.reset}`);
|
|
1234
|
+
return;
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
console.error(`${colors.red}[ FAIL ] Unknown pack subcommand '${subCmd}'. Use 'devos pack list' or 'devos pack add <name>'.${colors.reset}`);
|
|
1238
|
+
process.exit(1);
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
// ---------------------------------------------------------------------------
|
|
1242
|
+
// memory
|
|
1243
|
+
// ---------------------------------------------------------------------------
|
|
1244
|
+
|
|
1245
|
+
function runMemory(flags, positional) {
|
|
1246
|
+
const subCmd = positional[0] || 'list';
|
|
1247
|
+
const memoryDir = path.join(TARGET_DIR, '.agents', 'memory');
|
|
1248
|
+
|
|
1249
|
+
if (subCmd === 'list') {
|
|
1250
|
+
if (!flags.quiet && !flags.json) printBanner();
|
|
1251
|
+
const decisionsDir = path.join(memoryDir, 'decisions');
|
|
1252
|
+
const handoffsDir = path.join(memoryDir, 'handoffs');
|
|
1253
|
+
const adrs = fs.existsSync(decisionsDir) ? fs.readdirSync(decisionsDir).filter((f) => f.endsWith('.md')) : [];
|
|
1254
|
+
const handoffs = fs.existsSync(handoffsDir) ? fs.readdirSync(handoffsDir).filter((f) => f.endsWith('.md')) : [];
|
|
1255
|
+
const contextPath = path.join(memoryDir, 'context.json');
|
|
1256
|
+
const context = fs.existsSync(contextPath) ? JSON.parse(fs.readFileSync(contextPath, 'utf8')) : null;
|
|
1257
|
+
|
|
1258
|
+
if (flags.json) {
|
|
1259
|
+
console.log(JSON.stringify({ adrs, handoffs, context }, null, 2));
|
|
1260
|
+
return;
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
console.log(`${colors.bold}DEV-OS SHARED MEMORY VAULT${colors.reset} ${colors.gray}(Target: ${TARGET_DIR})${colors.reset}`);
|
|
1264
|
+
console.log(`${colors.gray}${RULE}${colors.reset}\n`);
|
|
1265
|
+
if (context) {
|
|
1266
|
+
console.log(`${colors.bold}Active Context:${colors.reset} Milestone: ${colors.cyan}${context.currentMilestone || 'N/A'}${colors.reset} | Branch: ${colors.yellow}${context.activeBranch || 'N/A'}${colors.reset}\n`);
|
|
1267
|
+
}
|
|
1268
|
+
console.log(`${colors.bold}Architecture Decision Records (${adrs.length}):${colors.reset}`);
|
|
1269
|
+
if (adrs.length === 0) {
|
|
1270
|
+
console.log(` ${colors.gray}No ADRs recorded yet.${colors.reset}`);
|
|
1271
|
+
} else {
|
|
1272
|
+
adrs.forEach((f) => console.log(` ${colors.green}• ${f}${colors.reset}`));
|
|
1273
|
+
}
|
|
1274
|
+
console.log(`\n${colors.bold}Session Handoffs (${handoffs.length}):${colors.reset}`);
|
|
1275
|
+
if (handoffs.length === 0) {
|
|
1276
|
+
console.log(` ${colors.gray}No session handoffs recorded yet.${colors.reset}`);
|
|
1277
|
+
} else {
|
|
1278
|
+
handoffs.slice(-5).forEach((f) => console.log(` ${colors.cyan}• ${f}${colors.reset}`));
|
|
1279
|
+
}
|
|
1280
|
+
console.log();
|
|
1281
|
+
return;
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
if (subCmd === 'handoff') {
|
|
1285
|
+
const handoffsDir = path.join(memoryDir, 'handoffs');
|
|
1286
|
+
fs.mkdirSync(handoffsDir, { recursive: true });
|
|
1287
|
+
const now = new Date();
|
|
1288
|
+
const dateStr = now.toISOString().slice(0, 10);
|
|
1289
|
+
const timeStr = now.toISOString().slice(11, 16).replace(':', '');
|
|
1290
|
+
const filename = `handoff-${dateStr}-${timeStr}.md`;
|
|
1291
|
+
const targetFile = path.join(handoffsDir, filename);
|
|
1292
|
+
|
|
1293
|
+
let branch = 'unknown';
|
|
1294
|
+
let gitStatus = 'clean';
|
|
1295
|
+
try {
|
|
1296
|
+
const { execSync } = require('child_process');
|
|
1297
|
+
branch = execSync('git branch --show-current', { encoding: 'utf8', cwd: TARGET_DIR }).trim();
|
|
1298
|
+
gitStatus = execSync('git status -s', { encoding: 'utf8', cwd: TARGET_DIR }).trim() || 'clean';
|
|
1299
|
+
} catch (e) {}
|
|
1300
|
+
|
|
1301
|
+
const template = [
|
|
1302
|
+
`# Session Handoff: ${dateStr} ${timeStr}`,
|
|
1303
|
+
'',
|
|
1304
|
+
'## Executive Summary',
|
|
1305
|
+
`- **Active Branch:** \`${branch}\``,
|
|
1306
|
+
`- **Git Status:** ${gitStatus === 'clean' ? 'Clean' : 'Modified files present'}`,
|
|
1307
|
+
'- **Status:** [IN_PROGRESS | READY_FOR_REVIEW | DONE]',
|
|
1308
|
+
'',
|
|
1309
|
+
'## Completed in This Session',
|
|
1310
|
+
'- [ ] Summary of completed items',
|
|
1311
|
+
'',
|
|
1312
|
+
'## In-Progress / Blockers',
|
|
1313
|
+
'- [ ] Unfinished work',
|
|
1314
|
+
'',
|
|
1315
|
+
'## Immediate Next Steps',
|
|
1316
|
+
'1. Resume item 1',
|
|
1317
|
+
''
|
|
1318
|
+
].join('\n');
|
|
1319
|
+
|
|
1320
|
+
fs.writeFileSync(targetFile, template, 'utf8');
|
|
1321
|
+
console.log(`${colors.green}[ OK ] Created session handoff template: ${colors.cyan}${path.relative(TARGET_DIR, targetFile)}${colors.reset}`);
|
|
1322
|
+
return;
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
if (subCmd === 'doctor') {
|
|
1326
|
+
const checks = [
|
|
1327
|
+
{ name: 'Memory directory (.agents/memory/)', ok: fs.existsSync(memoryDir) },
|
|
1328
|
+
{ name: 'Decisions folder (.agents/memory/decisions/)', ok: fs.existsSync(path.join(memoryDir, 'decisions')) },
|
|
1329
|
+
{ name: 'Handoffs folder (.agents/memory/handoffs/)', ok: fs.existsSync(path.join(memoryDir, 'handoffs')) },
|
|
1330
|
+
{ name: 'Context manifest (.agents/memory/context.json)', ok: fs.existsSync(path.join(memoryDir, 'context.json')) }
|
|
1331
|
+
];
|
|
1332
|
+
let allOk = true;
|
|
1333
|
+
console.log(`${colors.bold}MEMORY VAULT HEALTH${colors.reset}`);
|
|
1334
|
+
console.log(`${colors.gray}${RULE}${colors.reset}`);
|
|
1335
|
+
checks.forEach((c) => {
|
|
1336
|
+
if (c.ok) console.log(` [ ${colors.green}PASS${colors.reset} ] ${c.name}`);
|
|
1337
|
+
else { console.log(` [ ${colors.red}FAIL${colors.reset} ] ${c.name}`); allOk = false; }
|
|
1338
|
+
});
|
|
1339
|
+
if (!allOk) process.exit(1);
|
|
1340
|
+
return;
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
console.error(`${colors.red}[ FAIL ] Unknown memory subcommand '${subCmd}'. Use 'list', 'handoff', or 'doctor'.${colors.reset}`);
|
|
1344
|
+
process.exit(1);
|
|
1345
|
+
}
|
|
1346
|
+
|
|
655
1347
|
// ---------------------------------------------------------------------------
|
|
656
1348
|
// list
|
|
657
1349
|
// ---------------------------------------------------------------------------
|
|
@@ -696,7 +1388,7 @@ function runList(flags) {
|
|
|
696
1388
|
console.log(` ${colors.cyan}• ${agent.padEnd(16)}${colors.reset} ${colors.gray}(.agents/agents/${agent}.md)${colors.reset}`);
|
|
697
1389
|
});
|
|
698
1390
|
|
|
699
|
-
console.log(`\n${colors.bold}SPECIALIST SKILLS (${skills.length})${colors.reset}`);
|
|
1391
|
+
console.log(`\n${colors.bold}INSTALLED SPECIALIST SKILLS (${skills.length})${colors.reset}`);
|
|
700
1392
|
console.log(`${colors.gray}${RULE}${colors.reset}`);
|
|
701
1393
|
const columns = 3;
|
|
702
1394
|
let line = '';
|
|
@@ -710,6 +1402,225 @@ function runList(flags) {
|
|
|
710
1402
|
console.log();
|
|
711
1403
|
}
|
|
712
1404
|
|
|
1405
|
+
// ---------------------------------------------------------------------------
|
|
1406
|
+
// skill / skills
|
|
1407
|
+
// ---------------------------------------------------------------------------
|
|
1408
|
+
|
|
1409
|
+
function runSkill(flags, positional) {
|
|
1410
|
+
const subCmd = positional[0] || 'list';
|
|
1411
|
+
const { spawnSync } = require('child_process');
|
|
1412
|
+
|
|
1413
|
+
if (subCmd === 'list') {
|
|
1414
|
+
runList(flags);
|
|
1415
|
+
return;
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
if (subCmd === 'add' || subCmd === 'install') {
|
|
1419
|
+
const pkg = positional[1];
|
|
1420
|
+
if (!pkg) {
|
|
1421
|
+
console.error(`${colors.red}[ FAIL ] Missing skill package or repository name.${colors.reset}`);
|
|
1422
|
+
console.log(`\nUsage: ${colors.cyan}devos skill add <owner/repo>${colors.reset}`);
|
|
1423
|
+
console.log(`Example: ${colors.cyan}devos skill add vercel-labs/agent-skills${colors.reset}`);
|
|
1424
|
+
console.log(`Browse skills: https://skills.sh\n`);
|
|
1425
|
+
process.exit(1);
|
|
1426
|
+
}
|
|
1427
|
+
console.log(`${colors.bold}INSTALLING AGENT SKILL${colors.reset}`);
|
|
1428
|
+
console.log(`${colors.gray}${RULE}${colors.reset}\n`);
|
|
1429
|
+
console.log(`Fetching from skills.sh / GitHub (${colors.cyan}npx skills add ${pkg}${colors.reset})...\n`);
|
|
1430
|
+
const res = spawnSync('npx', ['skills', 'add', pkg, '--yes'], {
|
|
1431
|
+
cwd: TARGET_DIR,
|
|
1432
|
+
stdio: 'inherit',
|
|
1433
|
+
env: { ...process.env, CI: '1' }
|
|
1434
|
+
});
|
|
1435
|
+
if (res.status !== 0) {
|
|
1436
|
+
console.error(`\n${colors.red}[ FAIL ] Failed to install skill '${pkg}'. Check package name or network connectivity.${colors.reset}`);
|
|
1437
|
+
process.exit(res.status || 1);
|
|
1438
|
+
}
|
|
1439
|
+
console.log(`\n${colors.green}[ OK ] Skill '${pkg}' successfully installed into .agents/skills/.${colors.reset}\n`);
|
|
1440
|
+
return;
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
if (subCmd === 'update' || subCmd === 'upgrade') {
|
|
1444
|
+
console.log(`${colors.bold}UPDATING AGENT SKILLS${colors.reset}`);
|
|
1445
|
+
console.log(`${colors.gray}${RULE}${colors.reset}\n`);
|
|
1446
|
+
console.log(`Checking upstream repositories (${colors.cyan}npx skills update${colors.reset})...\n`);
|
|
1447
|
+
const res = spawnSync('npx', ['skills', 'update', '-y'], {
|
|
1448
|
+
cwd: TARGET_DIR,
|
|
1449
|
+
stdio: 'inherit',
|
|
1450
|
+
env: { ...process.env, CI: '1' }
|
|
1451
|
+
});
|
|
1452
|
+
if (res.status === 0) {
|
|
1453
|
+
console.log(`\n${colors.green}[ OK ] Upstream skills updated successfully.${colors.reset}`);
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1456
|
+
const srcSkills = path.join(TEMPLATE_DIR, '.agents', 'skills');
|
|
1457
|
+
const destSkills = path.join(TARGET_DIR, '.agents', 'skills');
|
|
1458
|
+
if (fs.existsSync(srcSkills)) {
|
|
1459
|
+
copyRecursiveSync(srcSkills, destSkills);
|
|
1460
|
+
console.log(`${colors.green}[ OK ] Dev-OS core skills synchronized (${countSkills(destSkills)} total).${colors.reset}\n`);
|
|
1461
|
+
}
|
|
1462
|
+
return;
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
if (subCmd === 'find' || subCmd === 'search') {
|
|
1466
|
+
const query = positional.slice(1).join(' ');
|
|
1467
|
+
console.log(`${colors.bold}SEARCHING AGENT SKILLS (skills.sh)${colors.reset}`);
|
|
1468
|
+
console.log(`${colors.gray}${RULE}${colors.reset}\n`);
|
|
1469
|
+
const args = ['skills', 'find'];
|
|
1470
|
+
if (query) args.push(query);
|
|
1471
|
+
spawnSync('npx', args, {
|
|
1472
|
+
cwd: TARGET_DIR,
|
|
1473
|
+
stdio: 'inherit',
|
|
1474
|
+
env: process.env
|
|
1475
|
+
});
|
|
1476
|
+
return;
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
if (subCmd === 'check') {
|
|
1480
|
+
console.log(`${colors.bold}CHECKING SKILL UPDATES${colors.reset}`);
|
|
1481
|
+
console.log(`${colors.gray}${RULE}${colors.reset}\n`);
|
|
1482
|
+
spawnSync('npx', ['skills', 'check'], {
|
|
1483
|
+
cwd: TARGET_DIR,
|
|
1484
|
+
stdio: 'inherit',
|
|
1485
|
+
env: { ...process.env, CI: '1' }
|
|
1486
|
+
});
|
|
1487
|
+
return;
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1490
|
+
console.error(`${colors.red}[ FAIL ] Unknown skill subcommand '${subCmd}'. Use 'list', 'add', 'update', 'check', or 'find'.${colors.reset}`);
|
|
1491
|
+
process.exit(1);
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
// ---------------------------------------------------------------------------
|
|
1495
|
+
// run / auto
|
|
1496
|
+
// ---------------------------------------------------------------------------
|
|
1497
|
+
|
|
1498
|
+
function runAuto(flags, positional) {
|
|
1499
|
+
if (!flags.quiet && !flags.json) printBanner();
|
|
1500
|
+
const idea = positional.join(' ').trim();
|
|
1501
|
+
|
|
1502
|
+
console.log(`${colors.bold}AUTONOMOUS SDLC RUNNER (devos run / devos auto)${colors.reset}`);
|
|
1503
|
+
console.log(`${colors.gray}${RULE}${colors.reset}`);
|
|
1504
|
+
console.log(` Execution Mode: ${colors.green}Autonomous (Founder / Executive Proxy)${colors.reset}`);
|
|
1505
|
+
if (idea) {
|
|
1506
|
+
console.log(` Target Goal: ${colors.cyan}"${idea}"${colors.reset}\n`);
|
|
1507
|
+
} else {
|
|
1508
|
+
console.log(` Target Goal: ${colors.cyan}Continuous Autonomous Delivery${colors.reset}\n`);
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
console.log(`${colors.bold}10-Stage Professional SDLC Execution Pipeline:${colors.reset}`);
|
|
1512
|
+
console.log(` ${colors.cyan}1. Inception:${colors.reset} Architect (grill-me) → docs/PROJECT_REQUIREMENTS.md`);
|
|
1513
|
+
console.log(` ${colors.cyan}2. Design Gate:${colors.reset} UI Designer (ui-ux-pro-max) → docs/DESIGN.md`);
|
|
1514
|
+
console.log(` ${colors.cyan}3. Architecture & DB:${colors.reset} DBA → Migrations + Seed Fixtures (test password: devos123)`);
|
|
1515
|
+
console.log(` ${colors.cyan}4. Task Decomposition:${colors.reset} Orchestrator → docs/TASK_BOARD.md DAG`);
|
|
1516
|
+
console.log(` ${colors.cyan}5. Implementation:${colors.reset} Developer → Code authoring (dynamic subagents)`);
|
|
1517
|
+
console.log(` ${colors.cyan}6. Test Suite:${colors.reset} Tester → Automated unit & integration tests`);
|
|
1518
|
+
console.log(` ${colors.cyan}7. Testing Guide:${colors.reset} Tester → Interactive docs/TESTING_GUIDE.md`);
|
|
1519
|
+
console.log(` ${colors.cyan}8. Quality Assurance:${colors.reset} QA → Lint, types, standards & Design Gate audit`);
|
|
1520
|
+
console.log(` ${colors.cyan}9. Security Audit:${colors.reset} Security → OWASP, auth & secret scan`);
|
|
1521
|
+
console.log(` ${colors.cyan}10. Humanizer Audit:${colors.reset} Release Manager → Scrub AI tells from docs & copy\n`);
|
|
1522
|
+
|
|
1523
|
+
console.log(`${colors.bold}Next Action:${colors.reset}`);
|
|
1524
|
+
console.log(` To trigger this autonomous run in your AI coding harness, use:`);
|
|
1525
|
+
console.log(` $ ${colors.green}/auto ${idea || '<your product idea>'}${colors.reset}`);
|
|
1526
|
+
console.log(` Or hand off to the Executive Proxy:`);
|
|
1527
|
+
console.log(` "Executive Proxy, run autonomous SDLC mode for: ${idea || '<your product idea>'}"\n`);
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1530
|
+
// ---------------------------------------------------------------------------
|
|
1531
|
+
// telemetry
|
|
1532
|
+
// ---------------------------------------------------------------------------
|
|
1533
|
+
|
|
1534
|
+
function runTelemetry(flags, positional) {
|
|
1535
|
+
if (!flags.quiet && !flags.json) printBanner();
|
|
1536
|
+
const sub = positional[0] || 'status';
|
|
1537
|
+
const manifestPath = path.join(TARGET_DIR, '.agents', 'manifest.json');
|
|
1538
|
+
const manifest = fs.existsSync(manifestPath) ? JSON.parse(fs.readFileSync(manifestPath, 'utf8')) : { telemetry: 'on' };
|
|
1539
|
+
const telemetryDir = path.join(TARGET_DIR, '.agents', 'telemetry');
|
|
1540
|
+
const eventsPath = path.join(telemetryDir, 'events.jsonl');
|
|
1541
|
+
|
|
1542
|
+
if (sub === 'enable') {
|
|
1543
|
+
manifest.telemetry = 'on';
|
|
1544
|
+
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n', 'utf8');
|
|
1545
|
+
console.log(`${colors.green}[ OK ] Anonymous failure telemetry enabled.${colors.reset}\n`);
|
|
1546
|
+
return;
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
if (sub === 'disable') {
|
|
1550
|
+
manifest.telemetry = 'off';
|
|
1551
|
+
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n', 'utf8');
|
|
1552
|
+
console.log(`${colors.yellow}[ OK ] Anonymous failure telemetry disabled.${colors.reset}\n`);
|
|
1553
|
+
return;
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
if (sub === 'clear') {
|
|
1557
|
+
if (fs.existsSync(eventsPath)) {
|
|
1558
|
+
fs.writeFileSync(eventsPath, '', 'utf8');
|
|
1559
|
+
}
|
|
1560
|
+
console.log(`${colors.green}[ OK ] Telemetry event buffer cleared.${colors.reset}\n`);
|
|
1561
|
+
return;
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1564
|
+
const isEnabled = manifest.telemetry !== 'off';
|
|
1565
|
+
let eventCount = 0;
|
|
1566
|
+
let lines = [];
|
|
1567
|
+
if (fs.existsSync(eventsPath)) {
|
|
1568
|
+
const raw = fs.readFileSync(eventsPath, 'utf8').trim();
|
|
1569
|
+
if (raw.length > 0) {
|
|
1570
|
+
lines = raw.split('\n').filter(Boolean);
|
|
1571
|
+
eventCount = lines.length;
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
if (sub === 'report') {
|
|
1576
|
+
console.log(`${colors.bold}TELEMETRY & ROOT CAUSE ANALYSIS (RCA) REPORT${colors.reset}`);
|
|
1577
|
+
console.log(`${colors.gray}${RULE}${colors.reset}`);
|
|
1578
|
+
console.log(` Status: ${isEnabled ? colors.green + 'Enabled (on)' : colors.yellow + 'Disabled (off)'}${colors.reset}`);
|
|
1579
|
+
console.log(` Event Buffer: ${colors.cyan}${eventCount} events recorded${colors.reset}\n`);
|
|
1580
|
+
|
|
1581
|
+
if (eventCount === 0) {
|
|
1582
|
+
console.log(` ${colors.green}✓ Zero failure events recorded. All runtime hooks and gates are operating cleanly.${colors.reset}\n`);
|
|
1583
|
+
return;
|
|
1584
|
+
}
|
|
1585
|
+
|
|
1586
|
+
const rules = {};
|
|
1587
|
+
lines.forEach((l) => {
|
|
1588
|
+
try {
|
|
1589
|
+
const parsed = JSON.parse(l);
|
|
1590
|
+
const rule = parsed.rule || parsed.eventType || 'UNKNOWN';
|
|
1591
|
+
rules[rule] = (rules[rule] || 0) + 1;
|
|
1592
|
+
} catch (e) {}
|
|
1593
|
+
});
|
|
1594
|
+
|
|
1595
|
+
console.log(`${colors.bold}Failure Breakdown:${colors.reset}`);
|
|
1596
|
+
Object.keys(rules).forEach((r) => {
|
|
1597
|
+
console.log(` - ${colors.yellow}${r}${colors.reset}: ${rules[r]} occurrences`);
|
|
1598
|
+
});
|
|
1599
|
+
|
|
1600
|
+
console.log(`\n${colors.bold}Recent Events (Last 3):${colors.reset}`);
|
|
1601
|
+
lines.slice(-3).forEach((l) => {
|
|
1602
|
+
try {
|
|
1603
|
+
const p = JSON.parse(l);
|
|
1604
|
+
console.log(` ${colors.gray}[${p.timestamp || 'N/A'}]${colors.reset} ${colors.cyan}${p.rule || p.eventType}${colors.reset} — ${p.detail || ''}`);
|
|
1605
|
+
} catch (e) {}
|
|
1606
|
+
});
|
|
1607
|
+
console.log(`\nTo clear the buffer: ${colors.cyan}devos telemetry clear${colors.reset}\n`);
|
|
1608
|
+
return;
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1611
|
+
// default 'status'
|
|
1612
|
+
console.log(`${colors.bold}DEV-OS TELEMETRY STATUS${colors.reset}`);
|
|
1613
|
+
console.log(`${colors.gray}${RULE}${colors.reset}`);
|
|
1614
|
+
console.log(` Status: ${isEnabled ? colors.green + 'Enabled (on - recommended)' : colors.yellow + 'Disabled (off)'}${colors.reset}`);
|
|
1615
|
+
console.log(` Log Buffer: ${path.relative(TARGET_DIR, eventsPath)}`);
|
|
1616
|
+
console.log(` Total Events: ${eventCount}`);
|
|
1617
|
+
console.log(`\nCommands:`);
|
|
1618
|
+
console.log(` $ ${colors.cyan}devos telemetry report${colors.reset} View RCA failure breakdown`);
|
|
1619
|
+
console.log(` $ ${colors.cyan}devos telemetry enable${colors.reset} Enable anonymous failure logging`);
|
|
1620
|
+
console.log(` $ ${colors.cyan}devos telemetry disable${colors.reset} Disable failure logging`);
|
|
1621
|
+
console.log(` $ ${colors.cyan}devos telemetry clear${colors.reset} Clear local event buffer\n`);
|
|
1622
|
+
}
|
|
1623
|
+
|
|
713
1624
|
// ---------------------------------------------------------------------------
|
|
714
1625
|
// doctor
|
|
715
1626
|
// ---------------------------------------------------------------------------
|
|
@@ -723,11 +1634,23 @@ function runDoctor(flags) {
|
|
|
723
1634
|
{ name: 'Specialist skills (.agents/skills/)', path: path.join(TARGET_DIR, '.agents', 'skills'), type: 'dir' },
|
|
724
1635
|
{ name: 'Human commit script (.agents/scripts/commit.sh)', path: path.join(TARGET_DIR, '.agents', 'scripts', 'commit.sh'), type: 'file', exec: true },
|
|
725
1636
|
{ name: 'Hook installer (.agents/scripts/install-hooks.sh)', path: path.join(TARGET_DIR, '.agents', 'scripts', 'install-hooks.sh'), type: 'file', exec: true },
|
|
1637
|
+
{ name: 'Humanizer scanner (.agents/scripts/humanize-check.sh)', path: path.join(TARGET_DIR, '.agents', 'scripts', 'humanize-check.sh'), type: 'file', exec: true },
|
|
1638
|
+
{ name: 'Runtime lifecycle hooks (.agents/hooks/)', path: path.join(TARGET_DIR, '.agents', 'hooks'), type: 'dir', optional: true },
|
|
1639
|
+
{ name: 'Shared memory vault (.agents/memory/)', path: path.join(TARGET_DIR, '.agents', 'memory'), type: 'dir', optional: true },
|
|
1640
|
+
{ name: 'Task board (docs/TASK_BOARD.md)', path: path.join(TARGET_DIR, 'docs', 'TASK_BOARD.md'), type: 'file', optional: true },
|
|
1641
|
+
{ name: 'Telemetry buffer (.agents/telemetry/)', path: path.join(TARGET_DIR, '.agents', 'telemetry'), type: 'dir', optional: true },
|
|
1642
|
+
{ name: 'Mandatory Design Gate (docs/DESIGN.md)', path: path.join(TARGET_DIR, 'docs', 'DESIGN.md'), type: 'file', optional: true },
|
|
1643
|
+
{ name: 'Interactive Testing Guide (docs/TESTING_GUIDE.md)', path: path.join(TARGET_DIR, 'docs', 'TESTING_GUIDE.md'), type: 'file', optional: true },
|
|
726
1644
|
{ name: 'Team roster (.agents/AGENTS.md)', path: path.join(TARGET_DIR, '.agents', 'AGENTS.md'), type: 'file' },
|
|
727
1645
|
{ name: 'Coding standards (CODING_STANDARDS.md)', path: path.join(TARGET_DIR, 'CODING_STANDARDS.md'), type: 'file' },
|
|
728
1646
|
{ name: 'Documentation (docs/)', path: path.join(TARGET_DIR, 'docs'), type: 'dir' },
|
|
729
1647
|
{ name: 'Claude Code commands (.claude/commands/)', path: path.join(TARGET_DIR, '.claude', 'commands'), type: 'dir', optional: true },
|
|
730
1648
|
{ name: 'Claude Code agents (.claude/agents/)', path: path.join(TARGET_DIR, '.claude', 'agents'), type: 'dir', optional: true },
|
|
1649
|
+
{ name: 'Claude Code hooks (.claude/hooks.json)', path: path.join(TARGET_DIR, '.claude', 'hooks.json'), type: 'file', optional: true },
|
|
1650
|
+
{ name: 'Cursor rules (.cursor/rules/devos.mdc)', path: path.join(TARGET_DIR, '.cursor', 'rules', 'devos.mdc'), type: 'file', optional: true },
|
|
1651
|
+
{ name: 'OpenCode rules (.opencode/rules/devos-rules.md)', path: path.join(TARGET_DIR, '.opencode', 'rules', 'devos-rules.md'), type: 'file', optional: true },
|
|
1652
|
+
{ name: 'Antigravity / Gemini instructions (ANTIGRAVITY.md)', path: path.join(TARGET_DIR, 'ANTIGRAVITY.md'), type: 'file', optional: true },
|
|
1653
|
+
{ name: 'Codex instructions (.codex/instructions.md)', path: path.join(TARGET_DIR, '.codex', 'instructions.md'), type: 'file', optional: true },
|
|
731
1654
|
{ name: 'Mechanical pre-commit hook (.git/hooks/pre-commit)', path: path.join(TARGET_DIR, '.git', 'hooks', 'pre-commit'), type: 'file', optional: true }
|
|
732
1655
|
];
|
|
733
1656
|
|
|
@@ -787,7 +1710,7 @@ function runDoctor(flags) {
|
|
|
787
1710
|
console.log(`${colors.green}${colors.bold}[ OK ] Dev-OS environment is fully operational.${colors.reset}`);
|
|
788
1711
|
const warns = results.filter((r) => r.status === 'WARN');
|
|
789
1712
|
if (warns.length) {
|
|
790
|
-
console.log(`${colors.yellow}[ WARN ] ${warns.length} optional item(s) not set up
|
|
1713
|
+
console.log(`${colors.yellow}[ WARN ] ${warns.length} optional item(s) not set up.${colors.reset}`);
|
|
791
1714
|
if (warns.some((w) => w.name.includes('pre-commit'))) {
|
|
792
1715
|
console.log(`${colors.gray} Install the commit gate: ./.agents/scripts/install-hooks.sh${colors.reset}`);
|
|
793
1716
|
}
|
|
@@ -811,6 +1734,16 @@ function runStatus(flags) {
|
|
|
811
1734
|
const hasCommitScript = fs.existsSync(path.join(TARGET_DIR, '.agents', 'scripts', 'commit.sh'));
|
|
812
1735
|
const hasHook = fs.existsSync(path.join(TARGET_DIR, '.git', 'hooks', 'pre-commit'));
|
|
813
1736
|
const hasClaude = fs.existsSync(path.join(TARGET_DIR, '.claude', 'commands'));
|
|
1737
|
+
const hasCursor = fs.existsSync(path.join(TARGET_DIR, '.cursor', 'rules', 'devos.mdc'));
|
|
1738
|
+
const hasOpenCode = fs.existsSync(path.join(TARGET_DIR, 'OPENCODE.md'));
|
|
1739
|
+
const hasAntigravity = fs.existsSync(path.join(TARGET_DIR, 'ANTIGRAVITY.md')) || fs.existsSync(path.join(TARGET_DIR, 'GEMINI.md'));
|
|
1740
|
+
const hasCodex = fs.existsSync(path.join(TARGET_DIR, '.codex', 'instructions.md')) || fs.existsSync(path.join(TARGET_DIR, '.windsurfrules'));
|
|
1741
|
+
const hasMemory = fs.existsSync(path.join(TARGET_DIR, '.agents', 'memory'));
|
|
1742
|
+
const hasTaskBoard = fs.existsSync(path.join(TARGET_DIR, 'docs', 'TASK_BOARD.md'));
|
|
1743
|
+
const hasDesign = fs.existsSync(path.join(TARGET_DIR, 'docs', 'DESIGN.md'));
|
|
1744
|
+
const hasTestingGuide = fs.existsSync(path.join(TARGET_DIR, 'docs', 'TESTING_GUIDE.md'));
|
|
1745
|
+
const manifestPath = path.join(TARGET_DIR, '.agents', 'manifest.json');
|
|
1746
|
+
const manifest = fs.existsSync(manifestPath) ? JSON.parse(fs.readFileSync(manifestPath, 'utf8')) : null;
|
|
814
1747
|
|
|
815
1748
|
if (flags.json) {
|
|
816
1749
|
console.log(JSON.stringify({
|
|
@@ -819,7 +1752,18 @@ function runStatus(flags) {
|
|
|
819
1752
|
standards: hasStandards,
|
|
820
1753
|
commitGate: hasCommitScript,
|
|
821
1754
|
preCommitHook: hasHook,
|
|
822
|
-
|
|
1755
|
+
memoryVault: hasMemory,
|
|
1756
|
+
taskBoard: hasTaskBoard,
|
|
1757
|
+
designGate: hasDesign,
|
|
1758
|
+
testingGuide: hasTestingGuide,
|
|
1759
|
+
manifest,
|
|
1760
|
+
harnesses: {
|
|
1761
|
+
claude: hasClaude,
|
|
1762
|
+
antigravity: hasAntigravity,
|
|
1763
|
+
cursor: hasCursor,
|
|
1764
|
+
openCode: hasOpenCode,
|
|
1765
|
+
codex: hasCodex
|
|
1766
|
+
}
|
|
823
1767
|
}, null, 2));
|
|
824
1768
|
return;
|
|
825
1769
|
}
|
|
@@ -828,10 +1772,19 @@ function runStatus(flags) {
|
|
|
828
1772
|
console.log(`${colors.gray}${RULE}${colors.reset}`);
|
|
829
1773
|
console.log(` Target Path: ${colors.cyan}${TARGET_DIR}${colors.reset}`);
|
|
830
1774
|
console.log(` Dev-OS Status: ${hasAgents ? colors.green + 'Initialized' : colors.yellow + 'Not Initialized'}${colors.reset}`);
|
|
1775
|
+
console.log(` Telemetry: ${manifest && manifest.telemetry === 'off' ? colors.gray + 'Off' : colors.green + 'Active (on - recommended)'}${colors.reset}`);
|
|
1776
|
+
console.log(` SDLC Mode: ${manifest && manifest.mode ? colors.cyan + manifest.mode : colors.cyan + 'interactive'}${colors.reset}`);
|
|
1777
|
+
console.log(` Design Gate: ${hasDesign ? colors.green + 'Ready (docs/DESIGN.md)' : colors.yellow + 'Pending docs/DESIGN.md'}${colors.reset}`);
|
|
1778
|
+
console.log(` Testing Guide: ${hasTestingGuide ? colors.green + 'Ready (docs/TESTING_GUIDE.md)' : colors.gray + 'None'}${colors.reset}`);
|
|
831
1779
|
console.log(` Standards: ${hasStandards ? colors.green + 'Present' : colors.gray + 'None'}${colors.reset}`);
|
|
832
1780
|
console.log(` Commit Gate: ${hasCommitScript ? colors.green + 'Active' : colors.gray + 'Disabled'}${colors.reset}`);
|
|
833
1781
|
console.log(` Git Hook: ${hasHook ? colors.green + 'Installed' : colors.gray + 'Not Installed'}${colors.reset}`);
|
|
834
|
-
console.log(`
|
|
1782
|
+
console.log(` Memory Vault: ${hasMemory ? colors.green + 'Active (.agents/memory/)' : colors.gray + 'None'}${colors.reset}`);
|
|
1783
|
+
console.log(` Task Board: ${hasTaskBoard ? colors.green + 'Active (docs/TASK_BOARD.md)' : colors.gray + 'None'}${colors.reset}`);
|
|
1784
|
+
if (manifest && manifest.installedPacks) {
|
|
1785
|
+
console.log(` Active Packs: ${colors.cyan}${manifest.installedPacks.join(', ')}${colors.reset}`);
|
|
1786
|
+
}
|
|
1787
|
+
console.log(` Harnesses: Claude (${hasClaude ? '✓' : '✗'}), Antigravity (${hasAntigravity ? '✓' : '✗'}), Cursor (${hasCursor ? '✓' : '✗'}), OpenCode (${hasOpenCode ? '✓' : '✗'}), Codex (${hasCodex ? '✓' : '✗'})\n`);
|
|
835
1788
|
|
|
836
1789
|
if (!hasAgents) {
|
|
837
1790
|
console.log(`Run ${colors.cyan}npx @olives/devos init${colors.reset} to install Dev-OS in this project.\n`);
|
|
@@ -840,7 +1793,7 @@ function runStatus(flags) {
|
|
|
840
1793
|
|
|
841
1794
|
// Main CLI Entrypoint
|
|
842
1795
|
async function main() {
|
|
843
|
-
const { command, flags } = parseArgs(process.argv.slice(2));
|
|
1796
|
+
const { command, positional, flags } = parseArgs(process.argv.slice(2));
|
|
844
1797
|
|
|
845
1798
|
if (flags.version) {
|
|
846
1799
|
printVersion();
|
|
@@ -861,15 +1814,36 @@ async function main() {
|
|
|
861
1814
|
case 'upgrade':
|
|
862
1815
|
await runUpdate(flags);
|
|
863
1816
|
break;
|
|
1817
|
+
case 'run':
|
|
1818
|
+
case 'auto':
|
|
1819
|
+
runAuto(flags, positional);
|
|
1820
|
+
break;
|
|
1821
|
+
case 'telemetry':
|
|
1822
|
+
runTelemetry(flags, positional);
|
|
1823
|
+
break;
|
|
864
1824
|
case 'doctor':
|
|
865
1825
|
case 'check':
|
|
866
1826
|
runDoctor(flags);
|
|
867
1827
|
break;
|
|
1828
|
+
case 'pack':
|
|
1829
|
+
case 'packs':
|
|
1830
|
+
runPack(flags, positional);
|
|
1831
|
+
break;
|
|
1832
|
+
case 'memory':
|
|
1833
|
+
runMemory(flags, positional);
|
|
1834
|
+
break;
|
|
868
1835
|
case 'list':
|
|
869
1836
|
case 'agents':
|
|
870
|
-
case 'skills':
|
|
871
1837
|
runList(flags);
|
|
872
1838
|
break;
|
|
1839
|
+
case 'skill':
|
|
1840
|
+
case 'skills':
|
|
1841
|
+
if (positional.length > 0 && ['add', 'install', 'update', 'upgrade', 'check', 'find', 'search'].includes(positional[0])) {
|
|
1842
|
+
runSkill(flags, positional);
|
|
1843
|
+
} else {
|
|
1844
|
+
runList(flags);
|
|
1845
|
+
}
|
|
1846
|
+
break;
|
|
873
1847
|
case 'status':
|
|
874
1848
|
runStatus(flags);
|
|
875
1849
|
break;
|