multimodel-dev-os 0.3.0 → 0.5.1

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.
Files changed (63) hide show
  1. package/README.md +103 -98
  2. package/bin/multimodel-dev-os.js +420 -35
  3. package/docs/caveman-mode.md +7 -3
  4. package/docs/cli-roadmap.md +33 -21
  5. package/docs/comparison.md +33 -0
  6. package/docs/faq.md +21 -4
  7. package/docs/installers.md +1 -1
  8. package/docs/launch-kit.md +99 -0
  9. package/docs/multimodel-workflow.md +10 -11
  10. package/docs/npm-publishing.md +2 -2
  11. package/docs/quickstart.md +42 -29
  12. package/docs/templates-guide.md +65 -0
  13. package/docs/use-cases.md +39 -0
  14. package/examples/ecommerce-store/.ai/config.yaml +7 -4
  15. package/examples/ecommerce-store/.ai/context/architecture.md +6 -0
  16. package/examples/ecommerce-store/.ai/context/context-budget.md +4 -0
  17. package/examples/ecommerce-store/.ai/context/model-map.md +4 -0
  18. package/examples/ecommerce-store/.ai/context/project-brief.md +3 -0
  19. package/examples/ecommerce-store/.ai/skills/webhook-handler.md +15 -0
  20. package/examples/ecommerce-store/AGENTS.md +15 -2
  21. package/examples/ecommerce-store/MEMORY.md +4 -3
  22. package/examples/ecommerce-store/TASKS.md +10 -0
  23. package/examples/general-app/.ai/config.yaml +7 -4
  24. package/examples/general-app/.ai/context/architecture.md +12 -0
  25. package/examples/general-app/.ai/context/context-budget.md +5 -0
  26. package/examples/general-app/.ai/context/model-map.md +7 -0
  27. package/examples/general-app/.ai/context/project-brief.md +6 -0
  28. package/examples/general-app/.ai/skills/example-skill.md +8 -0
  29. package/examples/general-app/AGENTS.md +69 -4
  30. package/examples/general-app/MEMORY.md +32 -2
  31. package/examples/general-app/TASKS.md +9 -0
  32. package/examples/nextjs-saas/.ai/config.yaml +7 -4
  33. package/examples/nextjs-saas/.ai/context/architecture.md +8 -0
  34. package/examples/nextjs-saas/.ai/context/context-budget.md +4 -0
  35. package/examples/nextjs-saas/.ai/context/model-map.md +4 -0
  36. package/examples/nextjs-saas/.ai/context/project-brief.md +5 -0
  37. package/examples/nextjs-saas/.ai/skills/nextjs-action-build.md +16 -0
  38. package/examples/nextjs-saas/AGENTS.md +8 -2
  39. package/examples/nextjs-saas/MEMORY.md +7 -4
  40. package/examples/nextjs-saas/TASKS.md +12 -0
  41. package/examples/seo-landing-page/.ai/config.yaml +7 -4
  42. package/examples/seo-landing-page/.ai/context/architecture.md +12 -0
  43. package/examples/seo-landing-page/.ai/context/context-budget.md +5 -0
  44. package/examples/seo-landing-page/.ai/context/model-map.md +7 -0
  45. package/examples/seo-landing-page/.ai/context/project-brief.md +6 -0
  46. package/examples/seo-landing-page/.ai/skills/seo-audit.md +21 -0
  47. package/examples/seo-landing-page/AGENTS.md +69 -4
  48. package/examples/seo-landing-page/MEMORY.md +33 -4
  49. package/examples/seo-landing-page/TASKS.md +9 -0
  50. package/examples/wordpress-site/.ai/config.yaml +7 -4
  51. package/examples/wordpress-site/.ai/context/architecture.md +7 -0
  52. package/examples/wordpress-site/.ai/context/context-budget.md +4 -0
  53. package/examples/wordpress-site/.ai/context/model-map.md +4 -0
  54. package/examples/wordpress-site/.ai/context/project-brief.md +3 -0
  55. package/examples/wordpress-site/.ai/skills/plugin-boilerplate.md +21 -0
  56. package/examples/wordpress-site/AGENTS.md +16 -3
  57. package/examples/wordpress-site/MEMORY.md +4 -3
  58. package/examples/wordpress-site/TASKS.md +10 -0
  59. package/package.json +3 -2
  60. package/scripts/install.ps1 +1 -1
  61. package/scripts/install.sh +1 -1
  62. package/scripts/verify.js +274 -0
  63. package/scripts/verify.sh +12 -12
@@ -2,7 +2,7 @@
2
2
 
3
3
  /**
4
4
  * multimodel-dev-os CLI
5
- * Dependency-free local initialization and validation utility.
5
+ * Dependency-free local initialization, diagnostics, and validation utility.
6
6
  */
7
7
 
8
8
  import { existsSync, mkdirSync, readFileSync, writeFileSync, readdirSync, statSync } from 'fs';
@@ -13,7 +13,7 @@ const __filename = fileURLToPath(import.meta.url);
13
13
  const __dirname = dirname(__filename);
14
14
  const sourceRoot = resolve(__dirname, '..');
15
15
 
16
- let version = '0.3.0';
16
+ let version = '0.5.1';
17
17
  try {
18
18
  const pkgData = JSON.parse(readFileSync(resolve(sourceRoot, 'package.json'), 'utf8'));
19
19
  version = pkgData.version;
@@ -60,6 +60,44 @@ function parseArgs(args) {
60
60
  const params = parseArgs(ARGS);
61
61
  const COMMAND = params.command;
62
62
 
63
+ const TEMPLATES = {
64
+ 'nextjs-saas': {
65
+ name: 'nextjs-saas',
66
+ description: 'Next.js App Router starter with TypeScript, Prisma database, Tailwind CSS, and Stripe subscription setup.',
67
+ stack: 'Next.js 14, React 18, TypeScript, Tailwind CSS, Prisma ORM, Stripe payments',
68
+ skill: 'nextjs-action-build.md',
69
+ skillDesc: 'React Server Actions secure implementation conventions.'
70
+ },
71
+ 'wordpress-site': {
72
+ name: 'wordpress-site',
73
+ description: 'WordPress custom block theme and plugin development profile with secure PHP database query rules.',
74
+ stack: 'WordPress Core, PHP, Gutenberg Block APIs, theme customization hooks',
75
+ skill: 'plugin-boilerplate.md',
76
+ skillDesc: 'PHP hook registrations and sanitization gates boilerplate.'
77
+ },
78
+ 'ecommerce-store': {
79
+ name: 'ecommerce-store',
80
+ description: 'PCI-compliant headless e-commerce store with secure checkout loops, card state validations, and Stripe webhooks.',
81
+ stack: 'Headless Store API, cart states, secure payment webhooks, order database triggers',
82
+ skill: 'webhook-handler.md',
83
+ skillDesc: 'Stripe order checkout webhook secure listener verification rules.'
84
+ },
85
+ 'seo-landing-page': {
86
+ name: 'seo-landing-page',
87
+ description: 'Ultra-fast static landing page layout optimized for Astro, high Core Web Vitals scores, and JSON-LD schema markup.',
88
+ stack: 'Astro, HTML5, structured JSON-LD SEO markup, asset minification frameworks',
89
+ skill: 'seo-audit.md',
90
+ skillDesc: 'Lighthouse audits optimization guidelines and Core Web Vitals targets.'
91
+ },
92
+ 'general-app': {
93
+ name: 'general-app',
94
+ description: 'Baseline generic fallback profile for standard backend systems (Python, Go, Node, Rust) and universal git workflows.',
95
+ stack: 'Universal backends baseline structure, default git flow parameters',
96
+ skill: 'example-skill.md',
97
+ skillDesc: 'Generic baseline instructions and coding standards.'
98
+ }
99
+ };
100
+
63
101
  if (params.help || !COMMAND) {
64
102
  showHelp();
65
103
  process.exit(0);
@@ -69,6 +107,19 @@ if (COMMAND === 'init') {
69
107
  handleInit(params);
70
108
  } else if (COMMAND === 'verify') {
71
109
  handleVerify(params);
110
+ } else if (COMMAND === 'templates' || COMMAND === 'list-templates') {
111
+ handleListTemplates();
112
+ } else if (COMMAND === 'show-template') {
113
+ const tName = ARGS[1];
114
+ if (!tName || tName.startsWith('-')) {
115
+ console.error('\x1b[31mError: Please specify a template name. Example: node bin/multimodel-dev-os.js show-template nextjs-saas\x1b[0m');
116
+ process.exit(1);
117
+ }
118
+ handleShowTemplate(tName);
119
+ } else if (COMMAND === 'doctor') {
120
+ handleDoctor(params);
121
+ } else if (COMMAND === 'validate') {
122
+ handleValidate(params);
72
123
  } else {
73
124
  console.error(`\x1b[31mUnknown command: ${COMMAND}\x1b[0m`);
74
125
  showHelp();
@@ -80,8 +131,13 @@ function showHelp() {
80
131
  console.log('====================================');
81
132
  console.log('Usage: node bin/multimodel-dev-os.js <command> [options]\n');
82
133
  console.log('Commands:');
83
- console.log(' init Initialize a project with configs and adapters');
84
- console.log(' verify Validate structural integrity of an existing project\n');
134
+ console.log(' init Initialize a project with configs and adapters');
135
+ console.log(' verify Validate structural integrity of an existing project');
136
+ console.log(' templates List all built-in template profiles with details');
137
+ console.log(' list-templates Alias for templates command');
138
+ console.log(' show-template <t> Inspect detailed stack specifications of template <t>');
139
+ console.log(' doctor Advisory checkup of project compatibility loops and ignored folders');
140
+ console.log(' validate Strict validation checks to verify directory schema compliance\n');
85
141
  console.log('Options:');
86
142
  console.log(' -t, --target <path> Target folder destination (default: current working directory)');
87
143
  console.log(' --template <name> Template profile: nextjs-saas, wordpress-site, ecommerce-store,');
@@ -92,6 +148,48 @@ function showHelp() {
92
148
  console.log(' -f, --force Overwrite existing files without prompting\n');
93
149
  }
94
150
 
151
+ function handleListTemplates() {
152
+ console.log(`\n🧠 \x1b[36mBuilt-in Template Profiles [v${version}]\x1b[0m`);
153
+ console.log('==================================================');
154
+ Object.keys(TEMPLATES).forEach(key => {
155
+ const t = TEMPLATES[key];
156
+ console.log(`\n\x1b[32m* ${t.name}\x1b[0m`);
157
+ console.log(` \x1b[33mStack:\x1b[0m ${t.stack}`);
158
+ console.log(` \x1b[37mDescription:\x1b[0m ${t.description}`);
159
+ });
160
+ console.log('\nUse \x1b[36mshow-template <template-name>\x1b[0m to view detailed layout specifications.\n');
161
+ }
162
+
163
+ function handleShowTemplate(name) {
164
+ const t = TEMPLATES[name];
165
+ if (!t) {
166
+ console.error(`\n\x1b[31mError: Template '${name}' does not exist. Available: nextjs-saas, wordpress-site, ecommerce-store, seo-landing-page, general-app\x1b[0m\n`);
167
+ process.exit(1);
168
+ }
169
+
170
+ console.log(`\n🔍 \x1b[36mTemplate Profile: ${t.name}\x1b[0m`);
171
+ console.log('==================================================');
172
+ console.log(`\x1b[33mStack Blueprint:\x1b[0m ${t.stack}`);
173
+ console.log(`\x1b[33mOverview:\x1b[0m ${t.description}`);
174
+ console.log(`\x1b[33mHighlighted Skill:\x1b[0m .ai/skills/${t.skill}`);
175
+ console.log(` └─> ${t.skillDesc}`);
176
+ console.log('\n\x1b[33mScaffolding Directory Layout:\x1b[0m');
177
+ console.log(' ├── AGENTS.md (Stack building conventions)');
178
+ console.log(' ├── MEMORY.md (Architectural constraints record)');
179
+ console.log(' ├── TASKS.md (Pre-populated first project tasks)');
180
+ console.log(' ├── RUNBOOK.md (Default operations guide)');
181
+ console.log(' └── .ai/');
182
+ console.log(' ├── config.yaml (Enabled adapter options)');
183
+ console.log(' ├── context/');
184
+ console.log(' │ ├── project-brief.md (Scaffolding baseline brief)');
185
+ console.log(' │ ├── architecture.md (Stack specific architecture map)');
186
+ console.log(' │ ├── model-map.md (AI routing specifications)');
187
+ console.log(' │ └── context-budget.md (Token allocation guidelines)');
188
+ console.log(` └── skills/`);
189
+ console.log(` └── ${t.skill} (Custom template skills code boiler)`);
190
+ console.log('\nUse \x1b[32minit --template ' + t.name + '\x1b[0m to bootstrap this profile.\n');
191
+ }
192
+
95
193
  function handleInit(options) {
96
194
  console.log(`\n\x1b[34mInitializing multimodel-dev-os in: ${options.target}\x1b[0m`);
97
195
  console.log(`Template profile: \x1b[32m${options.template}\x1b[0m`);
@@ -101,23 +199,18 @@ function handleInit(options) {
101
199
  const operations = [];
102
200
  const conflicts = [];
103
201
 
104
- // Determine core source files based on template and mode
105
- let agentsSrc = join(sourceRoot, 'AGENTS.md');
106
- let memorySrc = join(sourceRoot, 'MEMORY.md');
107
- let tasksSrc = join(sourceRoot, 'TASKS.md');
108
- let runbookSrc = join(sourceRoot, 'RUNBOOK.md');
109
- let configSrc = join(sourceRoot, '.ai', 'config.yaml');
110
-
111
- // Load custom template directories if selected
112
- if (options.template !== 'general-app') {
113
- const templateDir = join(sourceRoot, 'examples', options.template);
114
- if (existsSync(templateDir)) {
115
- agentsSrc = join(templateDir, 'AGENTS.md');
116
- memorySrc = join(templateDir, 'MEMORY.md');
117
- configSrc = join(templateDir, '.ai', 'config.yaml');
118
- }
202
+ // Source path mapping for core files
203
+ let templateDir = join(sourceRoot, 'examples', options.template);
204
+ if (!existsSync(templateDir)) {
205
+ templateDir = join(sourceRoot, 'examples', 'general-app');
119
206
  }
120
207
 
208
+ let agentsSrc = join(templateDir, 'AGENTS.md');
209
+ let memorySrc = join(templateDir, 'MEMORY.md');
210
+ let tasksSrc = join(templateDir, 'TASKS.md');
211
+ let runbookSrc = join(sourceRoot, 'RUNBOOK.md'); // Global operational runbook fallback
212
+ let configSrc = join(templateDir, '.ai', 'config.yaml');
213
+
121
214
  // Handle Caveman Mode overrides
122
215
  if (options.caveman) {
123
216
  agentsSrc = join(sourceRoot, '.ai', 'templates', 'AGENTS.caveman.md');
@@ -126,32 +219,55 @@ function handleInit(options) {
126
219
  runbookSrc = join(sourceRoot, '.ai', 'templates', 'RUNBOOK.caveman.md');
127
220
  }
128
221
 
129
- // 1. Core Root Files
130
222
  operations.push({ dest: 'AGENTS.md', src: agentsSrc });
131
223
  operations.push({ dest: 'MEMORY.md', src: memorySrc });
132
224
  operations.push({ dest: 'TASKS.md', src: tasksSrc });
133
225
  operations.push({ dest: 'RUNBOOK.md', src: runbookSrc });
134
226
  operations.push({ dest: '.ai/config.yaml', src: configSrc });
135
227
 
136
- // 2. .ai/ Subdirectories & Core Specification Files
137
- const aiSubdirs = ['context', 'agents', 'skills', 'prompts', 'checks', 'templates', 'session-logs'];
138
- aiSubdirs.forEach(sub => {
139
- const srcDir = join(sourceRoot, '.ai', sub);
140
- if (existsSync(srcDir)) {
141
- readdirSync(srcDir).forEach(file => {
142
- operations.push({
143
- dest: join('.ai', sub, file),
144
- src: join(srcDir, file)
228
+ // Add all files from template-specific context and skills folders if they exist
229
+ const templateAiDir = join(templateDir, '.ai');
230
+ if (existsSync(templateAiDir) && !options.caveman) {
231
+ const subdirs = ['context', 'skills'];
232
+ subdirs.forEach(sub => {
233
+ const subPath = join(templateAiDir, sub);
234
+ if (existsSync(subPath)) {
235
+ readdirSync(subPath).forEach(file => {
236
+ operations.push({
237
+ dest: join('.ai', sub, file),
238
+ src: join(subPath, file)
239
+ });
145
240
  });
241
+ }
242
+ });
243
+ }
244
+
245
+ // Fallback to copy default global folders if files aren't already included by template
246
+ const globalAiSubdirs = ['context', 'agents', 'skills', 'prompts', 'checks', 'templates', 'session-logs'];
247
+ globalAiSubdirs.forEach(sub => {
248
+ const globalPath = join(sourceRoot, '.ai', sub);
249
+ if (existsSync(globalPath)) {
250
+ readdirSync(globalPath).forEach(file => {
251
+ const destRel = join('.ai', sub, file);
252
+ // Only push if not already loaded from the template specific directory overrides
253
+ if (!operations.some(op => op.dest === destRel)) {
254
+ // If --caveman is active, skip regular context/skills to save token files
255
+ if (options.caveman && (sub === 'context' || sub === 'skills' || sub === 'prompts' || sub === 'checks')) {
256
+ return;
257
+ }
258
+ operations.push({
259
+ dest: destRel,
260
+ src: join(globalPath, file)
261
+ });
262
+ }
146
263
  });
147
264
  }
148
265
  });
149
266
 
150
- // 3. Selected Adapters
267
+ // Selected Adapters
151
268
  options.adapters.forEach(adapter => {
152
269
  const adapterDir = join(sourceRoot, 'adapters', adapter);
153
270
  if (existsSync(adapterDir)) {
154
- // Helper function to read recursive files in adapter
155
271
  const copyRecursive = (currSrc, currRel) => {
156
272
  if (statSync(currSrc).isDirectory()) {
157
273
  readdirSync(currSrc).forEach(file => {
@@ -172,7 +288,7 @@ function handleInit(options) {
172
288
  }
173
289
  });
174
290
 
175
- // Check for conflicts
291
+ // Audit conflicts
176
292
  operations.forEach(op => {
177
293
  const targetFile = join(options.target, op.dest);
178
294
  if (existsSync(targetFile)) {
@@ -207,6 +323,83 @@ function handleInit(options) {
207
323
  }
208
324
  });
209
325
 
326
+ // Ensure crucial directories exist (e.g. for --caveman or missing folders check compliance)
327
+ const dirsToEnsure = ['.ai/context', '.ai/skills', '.ai/session-logs'];
328
+ dirsToEnsure.forEach(d => {
329
+ const fullPath = join(options.target, d);
330
+ if (!options.dryRun && !existsSync(fullPath)) {
331
+ mkdirSync(fullPath, { recursive: true });
332
+ console.log(` \x1b[32mCREATE DIR:\x1b[0m ${d}`);
333
+ }
334
+ });
335
+
336
+ // Copy root-level adapter rule files if selected
337
+ if (!options.dryRun) {
338
+ options.adapters.forEach(adapter => {
339
+ if (adapter === 'cursor') {
340
+ const srcFile = join(sourceRoot, 'adapters/cursor/.cursorrules');
341
+ const destFile = join(options.target, '.cursorrules');
342
+ if (existsSync(srcFile)) {
343
+ writeFileSync(destFile, readFileSync(srcFile));
344
+ console.log(` \x1b[32mCREATE ROOT ADAPTER FILE:\x1b[0m .cursorrules`);
345
+ }
346
+ } else if (adapter === 'claude') {
347
+ const srcFile = join(sourceRoot, 'adapters/claude/CLAUDE.md');
348
+ const destFile = join(options.target, 'CLAUDE.md');
349
+ if (existsSync(srcFile)) {
350
+ writeFileSync(destFile, readFileSync(srcFile));
351
+ console.log(` \x1b[32mCREATE ROOT ADAPTER FILE:\x1b[0m CLAUDE.md`);
352
+ }
353
+ } else if (adapter === 'vscode') {
354
+ const srcFile = join(sourceRoot, 'adapters/vscode/.vscode/settings.json');
355
+ const destDir = join(options.target, '.vscode');
356
+ const destFile = join(destDir, 'settings.json');
357
+ if (existsSync(srcFile)) {
358
+ if (!existsSync(destDir)) mkdirSync(destDir, { recursive: true });
359
+ writeFileSync(destFile, readFileSync(srcFile));
360
+ console.log(` \x1b[32mCREATE ROOT ADAPTER FILE:\x1b[0m .vscode/settings.json`);
361
+ }
362
+ } else if (adapter === 'gemini') {
363
+ const srcFile = join(sourceRoot, 'adapters/gemini/GEMINI.md');
364
+ const destFile = join(options.target, 'GEMINI.md');
365
+ if (existsSync(srcFile)) {
366
+ writeFileSync(destFile, readFileSync(srcFile));
367
+ console.log(` \x1b[32mCREATE ROOT ADAPTER FILE:\x1b[0m GEMINI.md`);
368
+ }
369
+ } else if (adapter === 'antigravity') {
370
+ const srcFile = join(sourceRoot, 'adapters/antigravity/.gemini/settings.json');
371
+ const destDir = join(options.target, '.gemini');
372
+ const destFile = join(destDir, 'settings.json');
373
+ if (existsSync(srcFile)) {
374
+ if (!existsSync(destDir)) mkdirSync(destDir, { recursive: true });
375
+ writeFileSync(destFile, readFileSync(srcFile));
376
+ console.log(` \x1b[32mCREATE ROOT ADAPTER FILE:\x1b[0m .gemini/settings.json`);
377
+ }
378
+ }
379
+ });
380
+
381
+ // Dynamically enable selected adapters in the target .ai/config.yaml
382
+ const targetConfigPath = join(options.target, '.ai/config.yaml');
383
+ if (existsSync(targetConfigPath) && options.adapters.length > 0) {
384
+ let configContent = readFileSync(targetConfigPath, 'utf8');
385
+ options.adapters.forEach(adapter => {
386
+ const regex = new RegExp(`${adapter}:\\s*false`, 'g');
387
+ configContent = configContent.replace(regex, `${adapter}: true`);
388
+ });
389
+ writeFileSync(targetConfigPath, configContent, 'utf8');
390
+ console.log(` \x1b[32mUPDATE CONFIG:\x1b[0m Enabled selected adapters [${options.adapters.join(', ')}] in .ai/config.yaml`);
391
+ }
392
+ } else {
393
+ // Dry run notes
394
+ options.adapters.forEach(adapter => {
395
+ if (adapter === 'cursor') console.log(` \x1b[36m[DRY-RUN] WOULD CREATE ROOT ADAPTER FILE:\x1b[0m .cursorrules`);
396
+ else if (adapter === 'claude') console.log(` \x1b[36m[DRY-RUN] WOULD CREATE ROOT ADAPTER FILE:\x1b[0m CLAUDE.md`);
397
+ else if (adapter === 'vscode') console.log(` \x1b[36m[DRY-RUN] WOULD CREATE ROOT ADAPTER FILE:\x1b[0m .vscode/settings.json`);
398
+ else if (adapter === 'gemini') console.log(` \x1b[36m[DRY-RUN] WOULD CREATE ROOT ADAPTER FILE:\x1b[0m GEMINI.md`);
399
+ else if (adapter === 'antigravity') console.log(` \x1b[36m[DRY-RUN] WOULD CREATE ROOT ADAPTER FILE:\x1b[0m .gemini/settings.json`);
400
+ });
401
+ }
402
+
210
403
  console.log(`\n\x1b[32m✔ Project initialized successfully! [Total Operations: ${operations.length}]\x1b[0m\n`);
211
404
  }
212
405
 
@@ -227,11 +420,9 @@ function handleVerify(options) {
227
420
  }
228
421
  };
229
422
 
230
- // 1. Core Files
231
423
  const rootFiles = ['AGENTS.md', 'MEMORY.md', 'TASKS.md', 'RUNBOOK.md', '.ai/config.yaml'];
232
424
  rootFiles.forEach(assertFile);
233
425
 
234
- // 2. .ai/context
235
426
  const contextFiles = [
236
427
  '.ai/context/project-brief.md',
237
428
  '.ai/context/architecture.md',
@@ -243,7 +434,6 @@ function handleVerify(options) {
243
434
  ];
244
435
  contextFiles.forEach(assertFile);
245
436
 
246
- // 3. .ai/agents
247
437
  const agentFiles = [
248
438
  '.ai/agents/multimodel-orchestrator.md',
249
439
  '.ai/agents/planner.md',
@@ -265,3 +455,198 @@ function handleVerify(options) {
265
455
  process.exit(0);
266
456
  }
267
457
  }
458
+
459
+ function handleDoctor(options) {
460
+ console.log(`\n🩺 \x1b[36mRunning advisory doctor checkup in: ${options.target}\x1b[0m\n`);
461
+
462
+ let warnings = 0;
463
+
464
+ const warn = (msg) => {
465
+ console.warn(` \x1b[33m[WARNING]\x1b[0m ${msg}`);
466
+ warnings++;
467
+ };
468
+
469
+ // 1. .gitignore checks
470
+ const gitignorePath = join(options.target, '.gitignore');
471
+ if (existsSync(gitignorePath)) {
472
+ const content = readFileSync(gitignorePath, 'utf8');
473
+ if (!content.includes('node_modules')) {
474
+ warn('.gitignore is missing node_modules! This will cause AI tools to choke by scanning dependencies.');
475
+ }
476
+ if (!content.includes('.env')) {
477
+ warn('.gitignore is missing .env config boundaries! Secret tokens might get exposed to models.');
478
+ }
479
+ } else {
480
+ warn('Missing .gitignore file in target workspace! AI tools might read large build artifacts.');
481
+ }
482
+
483
+ // 2. Build/test/lint presence inside AGENTS.md
484
+ const agentsPath = join(options.target, 'AGENTS.md');
485
+ if (existsSync(agentsPath)) {
486
+ const content = readFileSync(agentsPath, 'utf8');
487
+ if (!content.includes('build:') && !content.includes('build')) {
488
+ warn('AGENTS.md is missing build command specifications.');
489
+ }
490
+ if (!content.includes('test:') && !content.includes('test')) {
491
+ warn('AGENTS.md is missing test command specifications.');
492
+ }
493
+ if (!content.includes('lint:') && !content.includes('lint')) {
494
+ warn('AGENTS.md is missing lint command specifications.');
495
+ }
496
+ } else {
497
+ warn('AGENTS.md is missing from project root.');
498
+ }
499
+
500
+ // 3. Null placeholders check in MEMORY.md
501
+ const memoryPath = join(options.target, 'MEMORY.md');
502
+ if (existsSync(memoryPath)) {
503
+ const content = readFileSync(memoryPath, 'utf8');
504
+ const placeholdersCount = (content.match(/null/g) || []).length;
505
+ if (placeholdersCount > 3) {
506
+ warn(`MEMORY.md contains ${placeholdersCount} empty 'null' placeholders. Update project constraints.`);
507
+ }
508
+ }
509
+
510
+ // 4. Tasks checklist status
511
+ const tasksPath = join(options.target, 'TASKS.md');
512
+ if (existsSync(tasksPath)) {
513
+ const content = readFileSync(tasksPath, 'utf8');
514
+ if (!content.includes('- [ ]') && !content.includes('- [/]')) {
515
+ warn('TASKS.md has no active task section (no tasks marked as - [ ] or - [/]).');
516
+ }
517
+ } else {
518
+ warn('TASKS.md is missing from project root.');
519
+ }
520
+
521
+ // 5. Active adapters files audit
522
+ const configPath = join(options.target, '.ai', 'config.yaml');
523
+ if (existsSync(configPath)) {
524
+ const content = readFileSync(configPath, 'utf8');
525
+ const checkAdapter = (adapterName, filename) => {
526
+ const regex = new RegExp(`${adapterName}:\\s*true`);
527
+ if (regex.test(content)) {
528
+ const filePath = join(options.target, filename);
529
+ if (!existsSync(filePath)) {
530
+ warn(`Adapter '${adapterName}' is enabled in .ai/config.yaml but matching adapter file '${filename}' is missing from root.`);
531
+ }
532
+ }
533
+ };
534
+ checkAdapter('cursor', '.cursorrules');
535
+ checkAdapter('claude', 'CLAUDE.md');
536
+ checkAdapter('gemini', 'GEMINI.md');
537
+ checkAdapter('vscode', '.vscode/settings.json');
538
+ checkAdapter('antigravity', '.gemini/settings.json');
539
+ } else {
540
+ warn('.ai/config.yaml is missing from project. Active adapters could not be audited.');
541
+ }
542
+
543
+ // 6. Token sinks audit
544
+ const sinkFolders = ['node_modules', 'dist', 'build', '.next', '.git'];
545
+ sinkFolders.forEach(folder => {
546
+ const fullPath = join(options.target, folder);
547
+ if (existsSync(fullPath)) {
548
+ const gitignore = existsSync(gitignorePath) ? readFileSync(gitignorePath, 'utf8') : '';
549
+ if (!gitignore.includes(folder)) {
550
+ warn(`Large token-sink directory '${folder}/' is present in workspace but not ignored in .gitignore. AI tools may read it.`);
551
+ }
552
+ }
553
+ });
554
+
555
+ console.log('\n==================================================');
556
+ if (warnings > 0) {
557
+ console.log(`\x1b[33mDoctor checkup complete. Found ${warnings} advisory warnings.\x1b[0m\n`);
558
+ } else {
559
+ console.log('\x1b[32m✔ Doctor checkup complete. Your project context layout is pristine!\x1b[0m\n');
560
+ }
561
+ }
562
+
563
+ function handleValidate(options) {
564
+ console.log(`\n🛡 \x1b[34mRunning strict schema validation in: ${options.target}\x1b[0m\n`);
565
+
566
+ let errors = 0;
567
+
568
+ const assertPath = (relPath, type) => {
569
+ const fullPath = join(options.target, relPath);
570
+ if (existsSync(fullPath)) {
571
+ const stat = statSync(fullPath);
572
+ const isOk = (type === 'file') ? stat.isFile() : stat.isDirectory();
573
+ if (isOk) {
574
+ console.log(` \x1b[32m✓\x1b[0m ${relPath} (${type})`);
575
+ } else {
576
+ console.error(` \x1b[31m✗ ${relPath} (expected to be a ${type})\x1b[0m`);
577
+ errors++;
578
+ }
579
+ } else {
580
+ console.error(` \x1b[31m✗ ${relPath} (missing)\x1b[0m`);
581
+ errors++;
582
+ }
583
+ };
584
+
585
+ // 1. Assert Core files
586
+ const core = ['AGENTS.md', 'MEMORY.md', 'TASKS.md', 'RUNBOOK.md', '.ai/config.yaml'];
587
+ core.forEach(f => assertPath(f, 'file'));
588
+
589
+ // 2. Assert Core folders (excluding agents first)
590
+ const dirs = ['.ai/context', '.ai/skills', '.ai/session-logs'];
591
+ dirs.forEach(d => assertPath(d, 'dir'));
592
+
593
+ // 3. Assert .ai/agents exists OR global agent use is explained in AGENTS.md
594
+ const agentsPath = join(options.target, '.ai/agents');
595
+ const agentsExist = existsSync(agentsPath) && statSync(agentsPath).isDirectory();
596
+ if (agentsExist) {
597
+ console.log(` \x1b[32m✓\x1b[0m .ai/agents (dir)`);
598
+ } else {
599
+ const agentsMdPath = join(options.target, 'AGENTS.md');
600
+ let explained = false;
601
+ if (existsSync(agentsMdPath)) {
602
+ const agentsMdContent = readFileSync(agentsMdPath, 'utf8');
603
+ if (
604
+ agentsMdContent.includes('multimodel') ||
605
+ agentsMdContent.includes('orchestrator') ||
606
+ agentsMdContent.includes('global') ||
607
+ agentsMdContent.includes('role') ||
608
+ agentsMdContent.includes('Agent Roles')
609
+ ) {
610
+ explained = true;
611
+ }
612
+ }
613
+ if (explained) {
614
+ console.log(` \x1b[32m✓\x1b[0m .ai/agents (missing, but global agent/orchestrator usage explained in AGENTS.md)`);
615
+ } else {
616
+ console.error(` \x1b[31m✗ .ai/agents (missing and global agent use is not explained in AGENTS.md)\x1b[0m`);
617
+ errors++;
618
+ }
619
+ }
620
+
621
+ // 4. Assert Active adapters files (adapter references are not broken)
622
+ const configPath = join(options.target, '.ai', 'config.yaml');
623
+ if (existsSync(configPath)) {
624
+ const content = readFileSync(configPath, 'utf8');
625
+ const assertAdapter = (adapterName, filename) => {
626
+ const regex = new RegExp(`${adapterName}:\\s*true`);
627
+ if (regex.test(content)) {
628
+ const fullPath = join(options.target, filename);
629
+ if (existsSync(fullPath)) {
630
+ console.log(` \x1b[32m✓\x1b[0m ${filename} (enabled adapter rules file verified)`);
631
+ } else {
632
+ console.error(` \x1b[31m✗ ${filename} (adapter '${adapterName}' is enabled in .ai/config.yaml, but rule file is missing!)\x1b[0m`);
633
+ errors++;
634
+ }
635
+ }
636
+ };
637
+ assertAdapter('cursor', '.cursorrules');
638
+ assertAdapter('claude', 'CLAUDE.md');
639
+ assertAdapter('gemini', 'GEMINI.md');
640
+ assertAdapter('vscode', '.vscode/settings.json');
641
+ assertAdapter('antigravity', '.gemini/settings.json');
642
+ }
643
+
644
+ console.log('\n==================================================');
645
+ if (errors > 0) {
646
+ console.error(` \x1b[31mValidation FAILED. Found ${errors} strict structural compliance errors.\x1b[0m\n`);
647
+ process.exit(1);
648
+ } else {
649
+ console.log(' \x1b[32m✔ Validation PASSED. Your project context structure is strictly compliant!\x1b[0m\n');
650
+ process.exit(0);
651
+ }
652
+ }
@@ -21,12 +21,16 @@ AI agents consume tokens for every file they read. In large projects, context wi
21
21
  | `RUNBOOK.md` | ~400 tokens | ~80 tokens | 80% |
22
22
  | **Total** | **~1,600** | **~340** | **~79%** |
23
23
 
24
- ## How to Use
25
-
26
24
  ### Fresh Install
27
25
 
26
+ **Via npx (Recommended):**
27
+ ```bash
28
+ npx multimodel-dev-os@latest init --caveman
29
+ ```
30
+
31
+ **Via shell script installer:**
28
32
  ```bash
29
- curl -fsSL .../install.sh | bash -s -- --caveman
33
+ curl -fsSL https://raw.githubusercontent.com/rizvee/multimodel-dev-os/main/scripts/install.sh | bash -s -- --caveman
30
34
  ```
31
35
 
32
36
  ### Convert Existing Project
@@ -1,44 +1,56 @@
1
1
  # CLI Roadmap
2
2
 
3
- > The local `node bin/multimodel-dev-os.js` CLI tool is fully implemented in v0.2.0!
3
+ > The zero-dependency CLI utility is fully integrated with `npm` and `npx` in v0.3.0!
4
4
 
5
5
  ## Current CLI Usage
6
6
 
7
+ Recommended way to execute the CLI globally via npx:
8
+
7
9
  ```bash
8
- # Initialize project with configurations
9
- node bin/multimodel-dev-os.js init
10
+ # Initialize standard configuration in current directory
11
+ npx multimodel-dev-os@latest init
10
12
 
11
13
  # Initialize with specific template and adapters
12
- node bin/multimodel-dev-os.js init --template nextjs-saas --adapter cursor --adapter claude
14
+ npx multimodel-dev-os@latest init --template nextjs-saas --adapter cursor --adapter claude
13
15
 
14
- # Run dry-run preview
15
- node bin/multimodel-dev-os.js init --dry-run
16
+ # Run dry-run preview before executing file writes
17
+ npx multimodel-dev-os@latest init --dry-run
16
18
 
17
19
  # Force overwrite existing files
18
- node bin/multimodel-dev-os.js init --force
20
+ npx multimodel-dev-os@latest init --force
19
21
 
20
22
  # Check structural health of target directory
21
- node bin/multimodel-dev-os.js verify
23
+ npx multimodel-dev-os@latest verify
22
24
  ```
23
25
 
24
- ## CLI Roadmap & Commands Status
26
+ Alternatively, you can run the CLI locally within a cloned workspace:
27
+ ```bash
28
+ node bin/multimodel-dev-os.js init
29
+ node bin/multimodel-dev-os.js verify
30
+ ```
25
31
 
26
32
  | Command | Purpose | Target Version | Status |
27
33
  |---------|---------|----------------|--------|
28
34
  | `init` | Scaffold multimodel-dev-os into a project | v0.2.0 | ✅ Completed |
29
35
  | `verify` | Check that all required files exist and are valid | v0.2.0 | ✅ Completed |
30
- | `sync` | Regenerate adapter files from root AGENTS.md | v0.3.0 | 📋 Planned |
31
- | `add-adapter` | Add a new adapter to the project | v0.3.0 | 📋 Planned |
36
+ | `templates` | List all built-in template profiles with details | v0.5.0 | Completed |
37
+ | `show-template` | Inspect stack specifications of a template | v0.5.0 | Completed |
38
+ | `doctor` | Advisory checkup of workspace compatibility | v0.5.0 | ✅ Completed |
39
+ | `validate` | Strict directory schema compliance checks | v0.5.0 | ✅ Completed |
40
+ | `sync` | Regenerate adapter files from root AGENTS.md | v0.6.0 | 📋 Planned |
41
+ | `add-adapter` | Add a new adapter to the project | v0.6.0 | 📋 Planned |
42
+
43
+ ## Requirements Completed in v0.5.0
44
+
45
+ - [x] Implemented strict `validate` CLI command for structural directory validation.
46
+ - [x] Implemented advisory `doctor` command for project compatibility warnings.
47
+ - [x] Implemented `templates` and `show-template` commands for built-in profiles inspection.
48
+ - [x] Upgraded all 5 built-in template profiles with practical real-world contents.
49
+ - [x] Implemented dynamic context budgetary constraints and skills validation.
50
+ - [x] Preserved zero-dependency pure Node CLI implementations.
32
51
 
33
- ## Requirements Completed in v0.2.0
52
+ ## Future Releases (v0.6.0+)
34
53
 
35
- - [x] `package.json` with `bin` entry
36
- - [x] CLI argument parser (implemented purely with Node.js built-ins)
37
- - [x] Template profile injection (Next.js SaaS, WordPress, etc.)
38
- - [x] Conflict protection and `--force` overrides
39
- - [x] Dry-run preview mode
40
- - [x] Tested on Node 18+ and Windows/macOS/Linux
54
+ * **Adapter Autoregeneration (`sync`):** Parse custom override boundaries inside adapters and automatically synchronize them with updates in the root markdown source of truth.
55
+ * **Interactive Mode:** Provide step-by-step CLI options if run without arguments.
41
56
 
42
- ## Future Releases (v0.3.0+)
43
- - Publish package to npm as `multimodel-dev-os` to support `npx` execution.
44
- - Implement the `sync` subcommand to parse custom override markers inside adapters and align them with changes in root instructions.