@vibecheckai/cli 3.1.6 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/README.md +27 -32
  2. package/bin/registry.js +208 -343
  3. package/bin/runners/context/generators/mcp.js +18 -0
  4. package/bin/runners/context/index.js +72 -4
  5. package/bin/runners/context/proof-context.js +293 -1
  6. package/bin/runners/context/security-scanner.js +311 -73
  7. package/bin/runners/lib/analyzers.js +607 -20
  8. package/bin/runners/lib/detectors-v2.js +172 -15
  9. package/bin/runners/lib/entitlements-v2.js +48 -1
  10. package/bin/runners/lib/evidence-pack.js +678 -0
  11. package/bin/runners/lib/html-proof-report.js +913 -0
  12. package/bin/runners/lib/missions/plan.js +231 -41
  13. package/bin/runners/lib/missions/templates.js +125 -0
  14. package/bin/runners/lib/scan-output.js +492 -253
  15. package/bin/runners/lib/ship-output.js +901 -641
  16. package/bin/runners/runCheckpoint.js +44 -3
  17. package/bin/runners/runContext.d.ts +4 -0
  18. package/bin/runners/runContext.js +2 -3
  19. package/bin/runners/runDoctor.js +11 -4
  20. package/bin/runners/runFix.js +51 -341
  21. package/bin/runners/runInit.js +37 -20
  22. package/bin/runners/runPolish.d.ts +4 -0
  23. package/bin/runners/runPolish.js +608 -29
  24. package/bin/runners/runProve.js +210 -25
  25. package/bin/runners/runReality.js +861 -107
  26. package/bin/runners/runScan.js +238 -4
  27. package/bin/runners/runShip.js +19 -3
  28. package/bin/runners/runWatch.js +25 -5
  29. package/bin/vibecheck.js +35 -47
  30. package/mcp-server/consolidated-tools.js +408 -42
  31. package/mcp-server/index.js +152 -15
  32. package/mcp-server/package.json +1 -1
  33. package/mcp-server/proof-tools.js +571 -0
  34. package/mcp-server/tier-auth.js +22 -19
  35. package/mcp-server/tools-v3.js +744 -0
  36. package/mcp-server/truth-firewall-tools.js +190 -4
  37. package/package.json +3 -1
  38. package/bin/runners/runBadge.js +0 -916
  39. package/bin/runners/runContracts.js +0 -105
  40. package/bin/runners/runCtx.js +0 -680
  41. package/bin/runners/runCtxDiff.js +0 -301
  42. package/bin/runners/runCtxGuard.js +0 -176
  43. package/bin/runners/runCtxSync.js +0 -116
  44. package/bin/runners/runExport.js +0 -93
  45. package/bin/runners/runGraph.js +0 -454
  46. package/bin/runners/runInstall.js +0 -273
  47. package/bin/runners/runLabs.js +0 -341
  48. package/bin/runners/runLaunch.js +0 -181
  49. package/bin/runners/runPR.js +0 -255
  50. package/bin/runners/runPermissions.js +0 -310
  51. package/bin/runners/runPreflight.js +0 -580
  52. package/bin/runners/runReplay.js +0 -499
  53. package/bin/runners/runSecurity.js +0 -92
  54. package/bin/runners/runShare.js +0 -212
  55. package/bin/runners/runStatus.js +0 -102
  56. package/bin/runners/runVerify.js +0 -272
package/bin/registry.js CHANGED
@@ -1,387 +1,252 @@
1
1
  /**
2
- * Vibecheck CLI Command Registry
3
- *
4
- * Single source of truth for all CLI commands.
5
- * Tiers match entitlements-v2.js EXACTLY.
6
- *
7
- * @module bin/registry
2
+ * Vibecheck CLI Command Registry (LOCKED)
3
+ *
4
+ * Single source of truth for the public CLI surface.
5
+ * If it isn't here, it does not exist.
8
6
  */
9
7
 
10
8
  "use strict";
11
9
 
12
- // ═══════════════════════════════════════════════════════════════════════════════
13
- // COMMAND REGISTRY - The 14-Command Vibecheck CLI
14
- // Tiers match entitlements-v2.js EXACTLY
15
- // ═══════════════════════════════════════════════════════════════════════════════
10
+ // ─────────────────────────────────────────────────────────────
11
+ // CORE 17 COMMANDS (locked surface area)
12
+ // ─────────────────────────────────────────────────────────────
13
+ const ALLOWED_COMMANDS = new Set([
14
+ // FREE (8) - Core functionality to try the product
15
+ "init", // one-time setup
16
+ "doctor", // health check
17
+ "watch", // continuous mode
18
+ "scan", // includes --allowlist subcommand
19
+ "ship", // verdict engine
20
+ "login", // authenticate
21
+ "logout", // remove credentials
22
+ "whoami", // show current user
23
+
24
+ // STARTER (6) - Productivity & automation
25
+ "fix", // AI-powered fixes
26
+ "report", // generate reports
27
+ "context", // generate IDE rules
28
+ "guard", // AI guardrails (prompt firewall, hallucination checking)
29
+ "mcp", // MCP server
30
+ "checkpoint", // baseline comparison & hallucination scoring
31
+
32
+ // PRO (3) - Advanced proof & AI testing
33
+ "prove", // includes --bundle for evidence packs
34
+ "reality", // includes --agent for AI testing
35
+ "polish", // production polish
36
+ ]);
37
+
38
+ function assertAllowedOnly(obj) {
39
+ const extras = Object.keys(obj).filter((k) => !ALLOWED_COMMANDS.has(k));
40
+ if (extras.length) {
41
+ throw new Error(`Registry contains non-allowed commands: ${extras.join(", ")}`);
42
+ }
43
+ }
44
+
45
+ // ─────────────────────────────────────────────────────────────
46
+ // COMMANDS (ALLOWED ONLY)
47
+ // ─────────────────────────────────────────────────────────────
16
48
  const COMMANDS = {
17
- // ═══════════════════════════════════════════════════════════════════════════════
18
- // SETUP COMMANDS (2)
19
- // ═══════════════════════════════════════════════════════════════════════════════
20
-
21
- // 1) init - One-time setup (config + contracts + scripts)
22
- init: {
23
- description: "One-time setup (config + contracts + scripts)",
24
- tier: "free",
25
- category: "setup",
26
- aliases: ["setup", "configure"],
27
- runner: () => require("./runners/runInit").runInit
28
- },
29
-
30
- // 2) doctor - Environment + dependency + config health check
31
- doctor: {
32
- description: "Environment + dependency + config health check",
33
- tier: "free",
34
- category: "setup",
35
- aliases: ["health", "diag"],
36
- runner: () => require("./runners/runDoctor").runDoctor
37
- },
38
-
39
- // ═══════════════════════════════════════════════════════════════════════════════
40
- // AI TRUTH LANE (4) - Context engine, guardrails, MDC
41
- // ═══════════════════════════════════════════════════════════════════════════════
42
-
43
- // 3) ctx - Generate/update truthpack (core truth engine)
44
- ctx: {
45
- description: "Truthpack generation - core truth engine",
46
- tier: "free",
47
- category: "truth",
48
- aliases: ["truthpack", "tp"],
49
- subcommands: ["build", "diff", "sync", "search"],
50
- runner: () => require("./runners/runCtx").runCtx
51
- },
52
-
53
- // 4) context - MDC + IDE rules + memory engine outputs
54
- context: {
55
- description: "Generate IDE rules (.cursorrules, MDC, Windsurf, Copilot)",
56
- tier: "free",
57
- category: "truth",
58
- aliases: ["rules", "ai-rules", "mdc"],
59
- runner: () => require("./runners/runContext").runContext
60
- },
61
-
62
- // 5) guard - AI guardrails (prompt firewall, hallucination checking)
63
- guard: {
64
- description: "AI guardrails - prompt firewall & hallucination checking",
65
- tier: "free",
66
- category: "truth",
67
- aliases: ["ai-guard", "firewall", "validate"],
68
- runner: () => require("./runners/runGuard").runGuard
49
+ // ══════════════════════════════════════════════════════════════
50
+ // FREE TIER (8 commands) - Core functionality to try the product
51
+ // ══════════════════════════════════════════════════════════════
52
+
53
+ // ── SETUP ───────────────────────────────────────────────────
54
+ init: {
55
+ description: "One-time setup (config + contracts + scripts)",
56
+ tier: "free",
57
+ category: "setup",
58
+ aliases: ["setup", "configure"],
59
+ runner: () => require("./runners/runInit").runInit,
69
60
  },
70
-
71
- // 6) contracts - CI gate for contract drift / invariants
72
- contracts: {
73
- description: "CI gate for contract drift / invariants",
74
- tier: "free",
75
- category: "truth",
76
- aliases: ["drift"],
77
- runner: () => require("./runners/runContracts").runContracts
61
+
62
+ doctor: {
63
+ description: "Environment + dependency + config health check",
64
+ tier: "free",
65
+ category: "setup",
66
+ aliases: ["health", "diag"],
67
+ runner: () => require("./runners/runDoctor").runDoctor,
78
68
  },
79
-
80
- // ═══════════════════════════════════════════════════════════════════════════════
81
- // PROOF LOOP (5) - The main verification commands
82
- // ═══════════════════════════════════════════════════════════════════════════════
83
-
84
- // 7) ship - The only verdict command. Static + (optional) runtime merge
85
- ship: {
86
- description: "Verdict engine - SHIP / WARN / BLOCK",
87
- tier: "free",
88
- category: "proof",
89
- aliases: ["verdict", "go"],
90
- caps: "static-only on FREE",
91
- runner: () => require("./runners/runShip").runShip
69
+
70
+ watch: {
71
+ description: "Continuous mode - re-runs on changes",
72
+ tier: "free",
73
+ category: "setup",
74
+ aliases: ["w", "dev"],
75
+ runner: () => require("./runners/runWatch").runWatch,
92
76
  },
93
-
94
- // 8) runtime - Everything Playwright / browser-based
95
- runtime: {
96
- description: "Browser-based runtime verification",
97
- tier: "free",
98
- category: "proof",
99
- aliases: [],
100
- subcommands: ["crawl", "agent", "record", "play"],
101
- caps: "preview mode on FREE (5 pages, no auth)",
102
- runner: () => require("./runners/runRuntime").runRuntime
77
+
78
+ // ── CORE LOOP ───────────────────────────────────────────────
79
+ scan: {
80
+ description: "Route integrity & code analysis; use --allowlist for false positive management",
81
+ tier: "free",
82
+ category: "proof",
83
+ aliases: ["s", "check"],
84
+ runner: () => require("./runners/runScan").runScan,
103
85
  },
104
-
105
- // 9) fix - Mission planning + patching
106
- fix: {
107
- description: "AI-powered auto-fix",
108
- tier: "free",
109
- category: "proof",
110
- caps: "--plan-only on FREE",
111
- aliases: ["f", "repair"],
112
- runner: () => require("./runners/runFix").runFix
86
+
87
+ ship: {
88
+ description: "Verdict engine - SHIP / WARN / BLOCK",
89
+ tier: "free",
90
+ category: "proof",
91
+ aliases: ["verdict", "go"],
92
+ runner: () => require("./runners/runShip").runShip,
113
93
  },
114
-
115
- // 10) prove - The one command users actually run before launch
116
- prove: {
117
- description: "Full proof loop - ctx → runtime → ship → fix",
118
- tier: "pro",
119
- category: "proof",
120
- aliases: ["p", "full", "all"],
121
- runner: () => require("./runners/runProve").runProve
94
+
95
+ // ── ACCOUNT (skipAuth) ────────────────────────────────────
96
+ login: {
97
+ description: "Authenticate with API key",
98
+ tier: "free",
99
+ category: "account",
100
+ aliases: ["auth", "signin"],
101
+ runner: () => require("./runners/runAuth").runLogin,
102
+ skipAuth: true,
122
103
  },
123
-
124
- // 11) security - AuthZ + IDOR + sensitive security proofs
125
- security: {
126
- description: "AuthZ matrix & IDOR detection",
127
- tier: "pro",
128
- category: "proof",
129
- aliases: [],
130
- subcommands: ["model", "matrix", "idor", "prove"],
131
- runner: () => require("./runners/runSecurity").runSecurity
104
+
105
+ logout: {
106
+ description: "Remove stored credentials",
107
+ tier: "free",
108
+ category: "account",
109
+ aliases: ["signout"],
110
+ runner: () => require("./runners/runAuth").runLogout,
111
+ skipAuth: true,
132
112
  },
133
-
134
- // ═══════════════════════════════════════════════════════════════════════════════
135
- // OUTPUT & AUTOMATION (3)
136
- // ═══════════════════════════════════════════════════════════════════════════════
137
-
138
- // 12) report - Render artifacts (HTML/MD/SARIF/CSV/etc)
139
- report: {
140
- description: "Generate HTML/MD/SARIF reports",
141
- tier: "free",
142
- category: "output",
143
- caps: "HTML/MD only on FREE",
144
- aliases: ["html", "artifact"],
145
- runner: () => require("./runners/runReport").runReport
113
+
114
+ whoami: {
115
+ description: "Show current user and plan",
116
+ tier: "free",
117
+ category: "account",
118
+ aliases: ["me", "user"],
119
+ runner: () => require("./runners/runAuth").runWhoami,
120
+ skipAuth: true,
146
121
  },
147
-
148
- // 13) export - Lightweight collab outputs from latest results
149
- export: {
150
- description: "Generate collaboration outputs",
151
- tier: "free",
152
- category: "output",
153
- aliases: [],
154
- subcommands: ["pr", "badge", "bundle"],
155
- runner: () => require("./runners/runExport").runExport
122
+
123
+ // ══════════════════════════════════════════════════════════════
124
+ // STARTER TIER (6 commands) - Productivity & automation
125
+ // ══════════════════════════════════════════════════════════════
126
+
127
+ fix: {
128
+ description: "AI-powered auto-fix for findings",
129
+ tier: "starter",
130
+ category: "proof",
131
+ aliases: ["f", "repair"],
132
+ runner: () => require("./runners/runFix").runFix,
156
133
  },
157
-
158
- // 14) mcp - Start MCP server for AI IDEs
159
- mcp: {
160
- description: "Start MCP server for AI IDEs",
161
- tier: "starter",
162
- category: "automation",
163
- aliases: [],
164
- runner: () => require("./runners/runMcp").runMcp
134
+
135
+ report: {
136
+ description: "Generate HTML/MD/SARIF reports",
137
+ tier: "starter",
138
+ category: "output",
139
+ aliases: ["html", "artifact"],
140
+ runner: () => require("./runners/runReport").runReport,
165
141
  },
166
-
167
- // ═══════════════════════════════════════════════════════════════════════════════
168
- // BACKWARD COMPATIBILITY ALIASES (old commands still work)
169
- // ═══════════════════════════════════════════════════════════════════════════════
170
-
171
- // install init --quick
172
- install: {
173
- description: "Zero-friction onboarding (alias: init --quick)",
174
- tier: "free",
175
- category: "setup",
176
- aliases: ["i", "bootstrap"],
177
- runner: () => async (args) => {
178
- const { runInit } = require("./runners/runInit");
179
- return await runInit(["--quick", ...args]);
180
- }
142
+
143
+ context: {
144
+ description: "Generate IDE rules (.cursorrules, MDC, Windsurf, Copilot)",
145
+ tier: "starter",
146
+ category: "truth",
147
+ aliases: ["rules", "ai-rules", "mdc"],
148
+ runner: () => require("./runners/runContext").runContext,
181
149
  },
182
-
183
- // scan - Enhanced route integrity scanner with terminal UI
184
- scan: {
185
- description: "Route integrity & code analysis scanner",
186
- tier: "free",
187
- category: "proof",
188
- aliases: ["s", "check"],
189
- runner: () => require("./runners/runScan").runScan
150
+
151
+ guard: {
152
+ description: "AI guardrails - prompt firewall & hallucination checking",
153
+ tier: "starter",
154
+ category: "truth",
155
+ aliases: ["ai-guard", "firewall", "validate"],
156
+ runner: () => require("./runners/runGuard").runGuard,
190
157
  },
191
-
192
- // gate → ship --ci
193
- gate: {
194
- description: "CI/CD gate (alias: ship --ci)",
195
- tier: "starter",
196
- category: "ci",
197
- aliases: ["ci", "block"],
198
- runner: () => async (args) => {
199
- const { runShip } = require("./runners/runShip");
200
- return await runShip(["--ci", ...args]);
201
- }
158
+
159
+ mcp: {
160
+ description: "Start MCP server for AI IDEs",
161
+ tier: "starter",
162
+ category: "automation",
163
+ aliases: [],
164
+ runner: () => require("./runners/runMcp").runMcp,
202
165
  },
203
-
204
- // reality → runtime crawl
205
- reality: {
206
- description: "Runtime proof (alias: runtime crawl)",
207
- tier: "free",
208
- category: "proof",
209
- aliases: ["r", "test", "e2e"],
210
- caps: "preview mode on FREE (5 pages, no auth)",
211
- runner: () => async (args) => {
212
- const { runRuntime } = require("./runners/runRuntime");
213
- return await runRuntime(["crawl", ...args]);
214
- }
166
+
167
+ checkpoint: {
168
+ description: "Compare baseline vs current, hallucination scoring",
169
+ tier: "starter",
170
+ category: "analysis",
171
+ aliases: ["cp", "compare", "diff"],
172
+ runner: () => require("./runners/runCheckpoint").runCheckpoint,
215
173
  },
216
-
217
- // ai-test → runtime agent
218
- "ai-test": {
219
- description: "AI autonomous test (alias: runtime agent)",
220
- tier: "pro",
221
- category: "automation",
222
- aliases: ["ai", "agent"],
223
- runner: () => async (args) => {
174
+
175
+ // ══════════════════════════════════════════════════════════════
176
+ // PRO TIER (3 commands) - Advanced proof & AI testing
177
+ // ══════════════════════════════════════════════════════════════
178
+
179
+ reality: {
180
+ description: "Runtime proof (browser crawl); use --agent for AI testing",
181
+ tier: "pro",
182
+ category: "proof",
183
+ caps: "--agent for AI autonomous testing",
184
+ aliases: ["r", "test", "e2e"],
185
+ runner: () => async (args, ctx) => {
224
186
  const { runRuntime } = require("./runners/runRuntime");
225
- return await runRuntime(["agent", ...args]);
226
- }
227
- },
228
-
229
- // replay → runtime record/play
230
- replay: {
231
- description: "Record/replay sessions (alias: runtime record/play)",
232
- tier: "pro",
233
- category: "proof",
234
- aliases: ["record", "playback"],
235
- runner: () => async (args) => {
236
- // If first arg is record or play, delegate to runtime
237
- if (args[0] === "record" || args[0] === "play") {
238
- const { runRuntime } = require("./runners/runRuntime");
239
- return await runRuntime(args);
240
- }
241
- // Otherwise delegate to original replay handler
242
- try {
243
- const { runReplay } = require("./runners/runReplay");
244
- return await runReplay(args);
245
- } catch (e) {
246
- if (args && (args.includes("--help") || args.includes("-h") || args.length === 0)) {
247
- console.log("\n vibecheck replay - Record and replay user sessions\n\n Subcommands:\n record <url> Record a user session\n play <capsule> Replay a recorded session\n list List available replay capsules\n show <id> Show details of a replay capsule\n delete <id> Delete a replay capsule\n export <id> Export a replay capsule\n import <file> Import a replay capsule\n\n Note: Requires 'chalk' and 'playwright' dependencies.\n Install: npm install chalk playwright\n");
248
- return 0;
249
- }
250
- console.error("Replay runner error:", e.message);
251
- return 1;
187
+ // Check if --agent flag is present to route to agent subcommand
188
+ if (args.includes("--agent") || args.includes("-a")) {
189
+ const filteredArgs = args.filter(a => a !== "--agent" && a !== "-a");
190
+ return await runRuntime(["agent", ...filteredArgs], ctx);
252
191
  }
253
- }
254
- },
255
-
256
- // pr → export pr
257
- pr: {
258
- description: "Generate PR comment (alias: export pr)",
259
- tier: "starter",
260
- category: "ci",
261
- aliases: ["pull-request"],
262
- runner: () => async (args) => {
263
- const { runExport } = require("./runners/runExport");
264
- return await runExport(["pr", ...args]);
265
- }
266
- },
267
-
268
- // badge → export badge
269
- badge: {
270
- description: "Generate ship badge (alias: export badge)",
271
- tier: "starter",
272
- category: "ci",
273
- aliases: ["b"],
274
- runner: () => async (args) => {
275
- const { runExport } = require("./runners/runExport");
276
- return await runExport(["badge", ...args]);
277
- }
278
- },
279
-
280
- // share → export bundle
281
- share: {
282
- description: "Generate share pack (alias: export bundle)",
283
- tier: "pro",
284
- category: "automation",
285
- aliases: [],
286
- runner: () => async (args) => {
287
- const { runExport } = require("./runners/runExport");
288
- return await runExport(["bundle", ...args]);
289
- }
192
+ return await runRuntime(["crawl", ...args], ctx);
193
+ },
290
194
  },
291
-
292
- // permissions → security model
293
- permissions: {
294
- description: "AuthZ & IDOR (alias: security model)",
295
- tier: "pro",
296
- category: "proof",
297
- aliases: ["authz", "idor"],
298
- runner: () => async (args) => {
299
- const { runSecurity } = require("./runners/runSecurity");
300
- // If no subcommand, default to "model"
301
- if (!args[0] || args[0].startsWith("--")) {
302
- return await runSecurity(["model", ...args]);
303
- }
304
- return await runSecurity(args);
305
- }
306
- },
307
-
308
- // ═══════════════════════════════════════════════════════════════════════════════
309
- // QUALITY & CHECKPOINT COMMANDS
310
- // ═══════════════════════════════════════════════════════════════════════════════
311
-
312
- // 15) polish - Production polish analyzer
313
- polish: {
314
- description: "Production polish analyzer - finds missing essentials",
315
- tier: "free",
316
- category: "quality",
317
- aliases: ["quality", "finalize", "ready"],
318
- runner: () => require("./runners/runPolish").runPolish
195
+
196
+ prove: {
197
+ description: "One command reality proof - video + network evidence that your app works",
198
+ tier: "pro",
199
+ category: "proof",
200
+ aliases: ["p", "full", "all"],
201
+ caps: "video, trace, HAR recording; use --bundle for evidence pack",
202
+ runner: () => require("./runners/runProve").runProve,
319
203
  },
320
-
321
- // 16) checkpoint - Compare baseline vs current
322
- checkpoint: {
323
- description: "Compare baseline vs current, hallucination scoring",
324
- tier: "free",
325
- category: "analysis",
326
- aliases: ["cp", "compare", "diff"],
327
- caps: "basic on FREE, hallucination scoring on PRO",
328
- runner: () => require("./runners/runCheckpoint").runCheckpoint
204
+
205
+ polish: {
206
+ description: "Production polish analyzer - finds missing essentials",
207
+ tier: "pro",
208
+ category: "quality",
209
+ aliases: ["quality", "finalize", "ready"],
210
+ runner: () => require("./runners/runPolish").runPolish,
329
211
  },
330
-
331
- status: { description: "Project health dashboard", tier: "free", category: "setup", aliases: ["st"], runner: () => require("./runners/runStatus").runStatus },
332
- watch: { description: "Continuous mode - re-runs on changes", tier: "free", category: "setup", aliases: ["w", "dev"], runner: () => require("./runners/runWatch").runWatch },
333
- launch: { description: "Pre-launch checklist wizard", tier: "starter", category: "setup", aliases: ["checklist"], runner: () => require("./runners/runLaunch").runLaunch },
334
- preflight: { description: "Deployment validation checks", tier: "free", category: "setup", aliases: ["deploy-check"], runner: () => require("./runners/runPreflight").runPreflight },
335
- verify: { description: "Verify AI-generated code output", tier: "free", category: "truth", aliases: ["v", "check-output"], runner: () => require("./runners/runVerify").main },
336
- graph: { description: "Reality proof graph visualization", tier: "pro", category: "proof", aliases: ["graphviz", "causal"], runner: () => require("./runners/runGraph").runGraph },
337
-
338
- // ACCOUNT (always free)
339
- login: { description: "Authenticate with API key", tier: "free", category: "account", aliases: ["auth", "signin"], runner: () => require("./runners/runAuth").runLogin, skipAuth: true },
340
- logout: { description: "Remove stored credentials", tier: "free", category: "account", aliases: ["signout"], runner: () => require("./runners/runAuth").runLogout, skipAuth: true },
341
- whoami: { description: "Show current user and plan", tier: "free", category: "account", aliases: ["me", "user"], runner: () => require("./runners/runAuth").runWhoami, skipAuth: true },
342
-
343
- // EXTRAS
344
- labs: { description: "Experimental features", tier: "free", category: "extras", aliases: ["experimental", "beta"], runner: () => require("./runners/runLabs").runLabs },
345
212
  };
346
213
 
347
- // ═══════════════════════════════════════════════════════════════════════════════
348
- // DERIVED DATA STRUCTURES
349
- // ═══════════════════════════════════════════════════════════════════════════════
214
+ assertAllowedOnly(COMMANDS);
215
+
216
+ // ─────────────────────────────────────────────────────────────
217
+ // DERIVED MAPS
218
+ // ─────────────────────────────────────────────────────────────
350
219
  const ALIAS_MAP = {};
351
- for (const [cmd, def] of Object.entries(COMMANDS)) {
352
- for (const alias of def.aliases || []) ALIAS_MAP[alias] = cmd;
220
+ for (const [cmd, def] of Object.entries(COMMANDS)) {
221
+ for (const alias of def.aliases || []) ALIAS_MAP[alias] = cmd;
353
222
  }
354
223
 
355
- const ALL_COMMANDS = [...Object.keys(COMMANDS), ...Object.values(COMMANDS).flatMap(c => c.aliases || [])];
224
+ const ALL_COMMANDS = [
225
+ ...Object.keys(COMMANDS),
226
+ ...Object.values(COMMANDS).flatMap((c) => c.aliases || []),
227
+ ];
356
228
 
357
- // ═══════════════════════════════════════════════════════════════════════════════
229
+ // ─────────────────────────────────────────────────────────────
358
230
  // RUNNER LOADER
359
- // ═══════════════════════════════════════════════════════════════════════════════
360
- /**
361
- * Get runner function for a command
362
- * @param {string} cmd - Command name
363
- * @param {object} styles - Optional styling object with { red, reset, errorSymbol }
364
- * @returns {Function|null} Runner function or null if not found
365
- */
231
+ // ─────────────────────────────────────────────────────────────
366
232
  function getRunner(cmd, styles = {}) {
367
233
  const def = COMMANDS[cmd];
368
234
  if (!def) return null;
235
+
369
236
  const red = styles.red || "";
370
237
  const reset = styles.reset || "";
371
238
  const errorSym = styles.errorSymbol || "✗";
372
- try {
373
- return def.runner();
374
- } catch (e) {
375
- return async () => {
376
- console.error(`${red}${errorSym}${reset} Failed to load ${cmd}: ${e.message}`);
377
- return 1;
378
- };
239
+
240
+ try {
241
+ return def.runner();
242
+ } catch (e) {
243
+ return async () => {
244
+ console.error(`${red}${errorSym}${reset} Failed to load ${cmd}: ${e.message}`);
245
+ return 1;
246
+ };
379
247
  }
380
248
  }
381
249
 
382
- // ═══════════════════════════════════════════════════════════════════════════════
383
- // EXPORTS
384
- // ═══════════════════════════════════════════════════════════════════════════════
385
250
  module.exports = {
386
251
  COMMANDS,
387
252
  ALIAS_MAP,