@vibecheckai/cli 3.2.6 → 3.4.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 (89) hide show
  1. package/bin/registry.js +306 -90
  2. package/bin/runners/lib/agent-firewall/change-packet/builder.js +280 -6
  3. package/bin/runners/lib/agent-firewall/critic/index.js +151 -0
  4. package/bin/runners/lib/agent-firewall/critic/judge.js +432 -0
  5. package/bin/runners/lib/agent-firewall/critic/prompts.js +305 -0
  6. package/bin/runners/lib/agent-firewall/lawbook/distributor.js +465 -0
  7. package/bin/runners/lib/agent-firewall/lawbook/evaluator.js +604 -0
  8. package/bin/runners/lib/agent-firewall/lawbook/index.js +304 -0
  9. package/bin/runners/lib/agent-firewall/lawbook/registry.js +514 -0
  10. package/bin/runners/lib/agent-firewall/lawbook/schema.js +420 -0
  11. package/bin/runners/lib/agent-firewall/logger.js +141 -0
  12. package/bin/runners/lib/agent-firewall/policy/loader.js +312 -4
  13. package/bin/runners/lib/agent-firewall/policy/rules/ghost-env.js +113 -1
  14. package/bin/runners/lib/agent-firewall/policy/rules/ghost-route.js +133 -6
  15. package/bin/runners/lib/agent-firewall/proposal/extractor.js +394 -0
  16. package/bin/runners/lib/agent-firewall/proposal/index.js +212 -0
  17. package/bin/runners/lib/agent-firewall/proposal/schema.js +251 -0
  18. package/bin/runners/lib/agent-firewall/proposal/validator.js +386 -0
  19. package/bin/runners/lib/agent-firewall/reality/index.js +332 -0
  20. package/bin/runners/lib/agent-firewall/reality/state.js +625 -0
  21. package/bin/runners/lib/agent-firewall/reality/watcher.js +322 -0
  22. package/bin/runners/lib/agent-firewall/risk/index.js +173 -0
  23. package/bin/runners/lib/agent-firewall/risk/scorer.js +328 -0
  24. package/bin/runners/lib/agent-firewall/risk/thresholds.js +321 -0
  25. package/bin/runners/lib/agent-firewall/risk/vectors.js +421 -0
  26. package/bin/runners/lib/agent-firewall/simulator/diff-simulator.js +472 -0
  27. package/bin/runners/lib/agent-firewall/simulator/import-resolver.js +346 -0
  28. package/bin/runners/lib/agent-firewall/simulator/index.js +181 -0
  29. package/bin/runners/lib/agent-firewall/simulator/route-validator.js +380 -0
  30. package/bin/runners/lib/agent-firewall/time-machine/incident-correlator.js +661 -0
  31. package/bin/runners/lib/agent-firewall/time-machine/index.js +267 -0
  32. package/bin/runners/lib/agent-firewall/time-machine/replay-engine.js +436 -0
  33. package/bin/runners/lib/agent-firewall/time-machine/state-reconstructor.js +490 -0
  34. package/bin/runners/lib/agent-firewall/time-machine/timeline-builder.js +530 -0
  35. package/bin/runners/lib/analyzers.js +136 -141
  36. package/bin/runners/lib/authority-badge.js +425 -0
  37. package/bin/runners/lib/cli-output.js +7 -1
  38. package/bin/runners/lib/entitlements-v2.js +96 -505
  39. package/bin/runners/lib/error-handler.js +16 -9
  40. package/bin/runners/lib/exit-codes.js +275 -0
  41. package/bin/runners/lib/global-flags.js +37 -0
  42. package/bin/runners/lib/help-formatter.js +413 -0
  43. package/bin/runners/lib/logger.js +38 -0
  44. package/bin/runners/lib/scan-output.js +18 -19
  45. package/bin/runners/lib/ship-output.js +18 -25
  46. package/bin/runners/lib/unified-cli-output.js +604 -0
  47. package/bin/runners/lib/upsell.js +105 -205
  48. package/bin/runners/runApprove.js +1200 -0
  49. package/bin/runners/runAuth.js +324 -95
  50. package/bin/runners/runCheckpoint.js +39 -21
  51. package/bin/runners/runClassify.js +859 -0
  52. package/bin/runners/runContext.js +136 -24
  53. package/bin/runners/runDoctor.js +108 -68
  54. package/bin/runners/runFix.js +6 -5
  55. package/bin/runners/runGuard.js +212 -118
  56. package/bin/runners/runInit.js +3 -2
  57. package/bin/runners/runMcp.js +130 -52
  58. package/bin/runners/runPolish.js +43 -20
  59. package/bin/runners/runProve.js +1 -2
  60. package/bin/runners/runReport.js +3 -2
  61. package/bin/runners/runScan.js +77 -45
  62. package/bin/runners/runShip.js +3 -4
  63. package/bin/runners/runValidate.js +19 -2
  64. package/bin/runners/runWatch.js +104 -53
  65. package/bin/vibecheck.js +103 -21
  66. package/mcp-server/HARDENING_SUMMARY.md +299 -0
  67. package/mcp-server/agent-firewall-interceptor.js +367 -31
  68. package/mcp-server/authority-tools.js +569 -0
  69. package/mcp-server/conductor/conflict-resolver.js +588 -0
  70. package/mcp-server/conductor/execution-planner.js +544 -0
  71. package/mcp-server/conductor/index.js +377 -0
  72. package/mcp-server/conductor/lock-manager.js +615 -0
  73. package/mcp-server/conductor/request-queue.js +550 -0
  74. package/mcp-server/conductor/session-manager.js +500 -0
  75. package/mcp-server/conductor/tools.js +510 -0
  76. package/mcp-server/index.js +1152 -856
  77. package/mcp-server/lib/api-client.cjs +13 -0
  78. package/mcp-server/lib/logger.cjs +30 -0
  79. package/mcp-server/logger.js +173 -0
  80. package/mcp-server/package.json +2 -2
  81. package/mcp-server/premium-tools.js +2 -2
  82. package/mcp-server/tier-auth.js +194 -383
  83. package/mcp-server/tools-v3.js +495 -533
  84. package/mcp-server/truth-firewall-tools.js +145 -15
  85. package/mcp-server/vibecheck-tools.js +2 -2
  86. package/package.json +2 -3
  87. package/mcp-server/index.old.js +0 -4137
  88. package/mcp-server/lib/api-client.js +0 -269
  89. package/mcp-server/package-lock.json +0 -165
package/bin/registry.js CHANGED
@@ -1,37 +1,42 @@
1
1
  /**
2
- * Vibecheck CLI Command Registry (LOCKED)
2
+ * Vibecheck CLI Command Registry
3
3
  *
4
4
  * Single source of truth for the public CLI surface.
5
5
  * If it isn't here, it does not exist.
6
+ *
7
+ * Simple 2-tier model:
8
+ * - FREE ($0): Inspect & Observe
9
+ * - PRO ($69/mo): Fix, Prove & Enforce
6
10
  */
7
11
 
8
12
  "use strict";
9
13
 
10
14
  // ─────────────────────────────────────────────────────────────
11
- // CORE 17 COMMANDS (locked surface area)
15
+ // CLI COMMANDS (2-tier: FREE / PRO)
12
16
  // ─────────────────────────────────────────────────────────────
13
17
  const ALLOWED_COMMANDS = new Set([
14
- // FREE (8) - Core functionality to try the product
18
+ // FREE (10) - Inspect & Observe
15
19
  "init", // one-time setup
16
20
  "doctor", // health check
17
21
  "watch", // continuous mode
18
- "scan", // includes --allowlist subcommand
19
- "ship", // verdict engine
22
+ "scan", // static analysis
23
+ "report", // generate reports
24
+ "context", // generate IDE rules
25
+ "classify", // Authority: inventory (read-only)
20
26
  "login", // authenticate
21
27
  "logout", // remove credentials
22
28
  "whoami", // show current user
23
29
 
24
- // STARTER (6) - Productivity & automation
30
+ // PRO (9) - Fix, Prove & Enforce
31
+ "ship", // verdict engine (GO/NO-GO)
25
32
  "fix", // AI-powered fixes
26
- "report", // generate reports
27
- "context", // generate IDE rules
28
- "guard", // AI guardrails (prompt firewall, hallucination checking)
33
+ "prove", // runtime proof
34
+ "reality", // browser verification
35
+ "gate", // CI/CD enforcement
36
+ "guard", // AI guardrails
29
37
  "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
38
+ "checkpoint", // baseline comparison
39
+ "approve", // Authority: verdicts
35
40
  "polish", // production polish
36
41
  ]);
37
42
 
@@ -43,63 +48,128 @@ function assertAllowedOnly(obj) {
43
48
  }
44
49
 
45
50
  // ─────────────────────────────────────────────────────────────
46
- // COMMANDS (ALLOWED ONLY)
51
+ // COMMANDS - 2-Tier: FREE and PRO ($69/mo)
47
52
  // ─────────────────────────────────────────────────────────────
48
53
  const COMMANDS = {
49
54
  // ══════════════════════════════════════════════════════════════
50
- // FREE TIER (8 commands) - Core functionality to try the product
55
+ // FREE TIER - Inspect & Observe
51
56
  // ══════════════════════════════════════════════════════════════
52
57
 
53
- // ── SETUP ───────────────────────────────────────────────────
54
58
  init: {
55
59
  description: "One-time setup (config + contracts + scripts)",
60
+ longDescription: "Initialize vibecheck in your project. Creates configuration files, sets up IDE rules, and optionally connects to the dashboard.",
56
61
  tier: "free",
57
62
  category: "setup",
58
63
  aliases: ["setup", "configure"],
59
64
  runner: () => require("./runners/runInit").runInit,
65
+ examples: [
66
+ { command: "vibecheck init", description: "Interactive setup wizard" },
67
+ { command: "vibecheck init --local", description: "Quick local-only setup" },
68
+ { command: "vibecheck init --quick", description: "Non-interactive defaults" },
69
+ ],
70
+ related: ["doctor", "scan"],
60
71
  },
61
72
 
62
73
  doctor: {
63
74
  description: "Environment + dependency + config health check",
75
+ longDescription: "Comprehensive diagnostics for your development environment.",
64
76
  tier: "free",
65
77
  category: "setup",
66
78
  aliases: ["health", "diag"],
67
79
  runner: () => require("./runners/runDoctor").runDoctor,
80
+ examples: [
81
+ { command: "vibecheck doctor", description: "Run all health checks" },
82
+ { command: "vibecheck doctor --fix", description: "Auto-fix detected issues" },
83
+ { command: "vibecheck doctor --json", description: "Output as JSON" },
84
+ ],
85
+ related: ["init", "scan"],
68
86
  },
69
87
 
70
88
  watch: {
71
89
  description: "Continuous mode - re-runs on changes",
90
+ longDescription: "File watcher that automatically re-runs scans when your code changes.",
72
91
  tier: "free",
73
92
  category: "setup",
74
93
  aliases: ["w", "dev"],
75
94
  runner: () => require("./runners/runWatch").runWatch,
95
+ examples: [
96
+ { command: "vibecheck watch", description: "Start watching" },
97
+ { command: "vibecheck watch --path ./src", description: "Watch specific directory" },
98
+ ],
99
+ related: ["scan"],
76
100
  },
77
101
 
78
- // ── CORE LOOP ───────────────────────────────────────────────
79
102
  scan: {
80
- description: "Route integrity & code analysis; use --allowlist for false positive management",
103
+ description: "Static code analysis; use --allowlist for false positives",
104
+ longDescription: "Scan your codebase for route integrity issues, security vulnerabilities, and code quality problems.",
81
105
  tier: "free",
82
106
  category: "proof",
83
107
  aliases: ["s", "check"],
84
108
  runner: () => require("./runners/runScan").runScan,
109
+ examples: [
110
+ { command: "vibecheck scan", description: "Quick scan" },
111
+ { command: "vibecheck scan --profile full", description: "Full scan" },
112
+ { command: "vibecheck scan --allowlist list", description: "View suppressed findings" },
113
+ ],
114
+ related: ["ship", "fix", "report"],
85
115
  },
86
116
 
87
- ship: {
88
- description: "Verdict engine - SHIP / WARN / BLOCK",
117
+ report: {
118
+ description: "Generate HTML/MD/SARIF reports",
119
+ longDescription: "Create shareable reports from scan results.",
89
120
  tier: "free",
90
- category: "proof",
91
- aliases: ["verdict", "go"],
92
- runner: () => require("./runners/runShip").runShip,
121
+ category: "output",
122
+ aliases: ["html", "artifact"],
123
+ runner: () => require("./runners/runReport").runReport,
124
+ examples: [
125
+ { command: "vibecheck report", description: "Generate HTML report" },
126
+ { command: "vibecheck report --format md", description: "Markdown report" },
127
+ { command: "vibecheck report --format sarif", description: "SARIF for GitHub" },
128
+ ],
129
+ related: ["scan"],
130
+ },
131
+
132
+ context: {
133
+ description: "Generate IDE rules (.cursorrules, MDC, Copilot)",
134
+ longDescription: "Generate project-aware AI coding rules for your IDE.",
135
+ tier: "free",
136
+ category: "truth",
137
+ aliases: ["rules", "ai-rules", "mdc", "ctx"],
138
+ runner: () => require("./runners/runContext").runContext,
139
+ examples: [
140
+ { command: "vibecheck context", description: "Generate all IDE rules" },
141
+ { command: "vibecheck context --format cursor", description: ".cursorrules only" },
142
+ ],
143
+ related: ["scan", "guard"],
144
+ },
145
+
146
+ classify: {
147
+ description: "Inventory authority - duplication & legacy code maps",
148
+ longDescription: "Read-only inventory of your codebase including duplication maps and legacy code detection.",
149
+ tier: "free",
150
+ category: "authority",
151
+ aliases: ["inventory", "audit"],
152
+ runner: () => require("./runners/runClassify").runClassify,
153
+ examples: [
154
+ { command: "vibecheck classify", description: "Quick inventory" },
155
+ { command: "vibecheck classify --json", description: "JSON output" },
156
+ ],
157
+ related: ["approve", "scan"],
93
158
  },
94
159
 
95
- // ── ACCOUNT (skipAuth) ────────────────────────────────────
96
160
  login: {
97
161
  description: "Authenticate with API key",
162
+ longDescription: "Connect your CLI to the vibecheck API.",
98
163
  tier: "free",
99
164
  category: "account",
100
165
  aliases: ["auth", "signin"],
101
166
  runner: () => require("./runners/runAuth").runLogin,
102
167
  skipAuth: true,
168
+ examples: [
169
+ { command: "vibecheck login", description: "Interactive login" },
170
+ { command: "vibecheck login --key YOUR_API_KEY", description: "Login with key" },
171
+ ],
172
+ related: ["logout", "whoami"],
103
173
  },
104
174
 
105
175
  logout: {
@@ -109,6 +179,10 @@ const COMMANDS = {
109
179
  aliases: ["signout"],
110
180
  runner: () => require("./runners/runAuth").runLogout,
111
181
  skipAuth: true,
182
+ examples: [
183
+ { command: "vibecheck logout", description: "Clear credentials" },
184
+ ],
185
+ related: ["login", "whoami"],
112
186
  },
113
187
 
114
188
  whoami: {
@@ -118,138 +192,280 @@ const COMMANDS = {
118
192
  aliases: ["me", "user"],
119
193
  runner: () => require("./runners/runAuth").runWhoami,
120
194
  skipAuth: true,
195
+ examples: [
196
+ { command: "vibecheck whoami", description: "Show user info" },
197
+ ],
198
+ related: ["login", "logout"],
121
199
  },
122
200
 
123
201
  // ══════════════════════════════════════════════════════════════
124
- // STARTER TIER (6 commands) - Productivity & automation
202
+ // PRO TIER ($69/mo) - Fix, Prove & Enforce
125
203
  // ══════════════════════════════════════════════════════════════
126
204
 
205
+ ship: {
206
+ description: "Verdict engine - SHIP / WARN / BLOCK",
207
+ longDescription: "The final word on whether your code is ready to ship. Combines all scan results and generates a clear verdict.",
208
+ tier: "pro",
209
+ category: "proof",
210
+ aliases: ["verdict", "go"],
211
+ runner: () => require("./runners/runShip").runShip,
212
+ examples: [
213
+ { command: "vibecheck ship", description: "Get shipping verdict" },
214
+ { command: "vibecheck ship --strict", description: "Fail on warnings" },
215
+ { command: "vibecheck ship --badge", description: "Generate status badge" },
216
+ ],
217
+ related: ["scan", "prove", "fix"],
218
+ },
219
+
127
220
  fix: {
128
221
  description: "AI-powered auto-fix for findings",
129
- tier: "starter",
222
+ longDescription: "Generate AI prompts to fix detected issues. Use --apply to let AI make changes directly.",
223
+ tier: "pro",
130
224
  category: "proof",
131
225
  aliases: ["f", "repair"],
132
226
  runner: () => require("./runners/runFix").runFix,
227
+ examples: [
228
+ { command: "vibecheck fix", description: "Generate fix missions" },
229
+ { command: "vibecheck fix --apply", description: "Apply AI fixes" },
230
+ { command: "vibecheck fix --loop", description: "Fix loop until clean" },
231
+ ],
232
+ related: ["scan", "ship"],
133
233
  },
134
234
 
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,
235
+ prove: {
236
+ description: "Full proof loop with runtime verification",
237
+ longDescription: "Complete verification cycle with runtime testing and evidence generation.",
238
+ tier: "pro",
239
+ category: "proof",
240
+ aliases: ["p", "verify"],
241
+ runner: () => require("./runners/runProve").runProve,
242
+ examples: [
243
+ { command: "vibecheck prove", description: "Run full proof loop" },
244
+ { command: "vibecheck prove --url http://localhost:3000", description: "With runtime testing" },
245
+ { command: "vibecheck prove --bundle", description: "Generate evidence pack" },
246
+ ],
247
+ related: ["ship", "reality"],
141
248
  },
142
249
 
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,
250
+ reality: {
251
+ description: "Browser-based runtime verification",
252
+ longDescription: "Verify your app's runtime behavior with Playwright-powered browser testing.",
253
+ tier: "pro",
254
+ category: "proof",
255
+ aliases: ["browser", "e2e"],
256
+ runner: () => require("./runners/runReality").runReality,
257
+ examples: [
258
+ { command: "vibecheck reality --url http://localhost:3000", description: "Test localhost" },
259
+ { command: "vibecheck reality --auth email:pass", description: "With authentication" },
260
+ { command: "vibecheck reality --agent", description: "AI agent testing" },
261
+ ],
262
+ related: ["prove", "ship"],
263
+ },
264
+
265
+ gate: {
266
+ description: "CI/CD enforcement - fail builds on issues",
267
+ longDescription: "Enforce quality gates in your CI/CD pipeline.",
268
+ tier: "pro",
269
+ category: "automation",
270
+ aliases: ["ci", "enforce"],
271
+ runner: () => require("./runners/runGuard").runGate,
272
+ examples: [
273
+ { command: "vibecheck gate", description: "Run CI gate check" },
274
+ { command: "vibecheck gate --strict", description: "Strict mode" },
275
+ ],
276
+ related: ["ship", "scan"],
149
277
  },
150
278
 
151
279
  guard: {
152
280
  description: "AI guardrails - prompt firewall & hallucination checking",
153
- tier: "starter",
281
+ longDescription: "Validate AI-generated code and prompts. Detects prompt injection and verifies claims.",
282
+ tier: "pro",
154
283
  category: "truth",
155
284
  aliases: ["ai-guard", "firewall", "validate"],
156
285
  runner: () => require("./runners/runGuard").runGuard,
286
+ examples: [
287
+ { command: "vibecheck guard", description: "Run all guardrail checks" },
288
+ { command: "vibecheck guard --claims", description: "Verify AI claims" },
289
+ ],
290
+ related: ["context", "fix"],
157
291
  },
158
292
 
159
293
  mcp: {
160
294
  description: "Start MCP server for AI IDEs",
161
- tier: "starter",
295
+ longDescription: "Launch an MCP server for AI IDE integration.",
296
+ tier: "pro",
162
297
  category: "automation",
163
298
  aliases: [],
164
299
  runner: () => require("./runners/runMcp").runMcp,
300
+ examples: [
301
+ { command: "vibecheck mcp", description: "Start MCP server" },
302
+ { command: "vibecheck mcp --port 3099", description: "Custom port" },
303
+ ],
304
+ related: ["context"],
165
305
  },
166
306
 
167
307
  checkpoint: {
168
308
  description: "Compare baseline vs current, hallucination scoring",
169
- tier: "starter",
309
+ longDescription: "Track changes between scan runs. Detects new issues, resolved issues, and regressions.",
310
+ tier: "pro",
170
311
  category: "analysis",
171
312
  aliases: ["cp", "compare", "diff"],
172
313
  runner: () => require("./runners/runCheckpoint").runCheckpoint,
314
+ examples: [
315
+ { command: "vibecheck checkpoint", description: "Compare against baseline" },
316
+ { command: "vibecheck checkpoint --set", description: "Save new baseline" },
317
+ ],
318
+ related: ["scan", "fix"],
173
319
  },
174
320
 
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",
321
+ approve: {
322
+ description: "Authority verdicts - PROCEED/STOP/DEFER with proofs",
323
+ longDescription: "Execute authorities to get structured verdicts with proofs.",
181
324
  tier: "pro",
182
- category: "proof",
183
- caps: "--agent for AI autonomous testing",
184
- aliases: ["r", "test", "e2e"],
185
- runner: () => async (args, ctx) => {
186
- const { runRuntime } = require("./runners/runRuntime");
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);
191
- }
192
- return await runRuntime(["crawl", ...args], ctx);
193
- },
194
- },
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,
325
+ category: "authority",
326
+ aliases: ["auth-verdict", "authority"],
327
+ runner: () => require("./runners/runApprove").runApprove,
328
+ examples: [
329
+ { command: "vibecheck approve safe-consolidation", description: "Run authority" },
330
+ { command: "vibecheck approve --list", description: "List authorities" },
331
+ ],
332
+ related: ["classify", "ship"],
203
333
  },
204
334
 
205
335
  polish: {
206
- description: "Production polish analyzer - finds missing essentials",
336
+ description: "Production polish - final cleanup before deploy",
337
+ longDescription: "Final production readiness checks and cleanup.",
207
338
  tier: "pro",
208
- category: "quality",
209
- aliases: ["quality", "finalize", "ready"],
339
+ category: "proof",
340
+ aliases: ["prod", "final"],
210
341
  runner: () => require("./runners/runPolish").runPolish,
342
+ examples: [
343
+ { command: "vibecheck polish", description: "Run polish checks" },
344
+ ],
345
+ related: ["ship", "prove"],
211
346
  },
212
347
  };
213
348
 
349
+ // Validate that only allowed commands are defined
214
350
  assertAllowedOnly(COMMANDS);
215
351
 
216
352
  // ─────────────────────────────────────────────────────────────
217
- // DERIVED MAPS
353
+ // TIER HELPERS
218
354
  // ─────────────────────────────────────────────────────────────
355
+ function isPro(tier) {
356
+ return tier === "pro";
357
+ }
358
+
359
+ function requiresPro(commandName) {
360
+ const cmd = COMMANDS[commandName];
361
+ return cmd && cmd.tier === "pro";
362
+ }
363
+
364
+ function getFreeCommands() {
365
+ return Object.entries(COMMANDS)
366
+ .filter(([, cmd]) => cmd.tier === "free")
367
+ .map(([name]) => name);
368
+ }
369
+
370
+ function getProCommands() {
371
+ return Object.entries(COMMANDS)
372
+ .filter(([, cmd]) => cmd.tier === "pro")
373
+ .map(([name]) => name);
374
+ }
375
+
376
+ // ─────────────────────────────────────────────────────────────
377
+ // BUILD DERIVED DATA STRUCTURES
378
+ // ─────────────────────────────────────────────────────────────
379
+
380
+ // Build alias map: { alias -> command }
219
381
  const ALIAS_MAP = {};
220
- for (const [cmd, def] of Object.entries(COMMANDS)) {
221
- for (const alias of def.aliases || []) ALIAS_MAP[alias] = cmd;
382
+ for (const [cmdName, cmd] of Object.entries(COMMANDS)) {
383
+ if (cmd.aliases) {
384
+ for (const alias of cmd.aliases) {
385
+ ALIAS_MAP[alias] = cmdName;
386
+ }
387
+ }
222
388
  }
223
389
 
224
- const ALL_COMMANDS = [
390
+ // All command names including aliases
391
+ const ALL_COMMANDS = new Set([
225
392
  ...Object.keys(COMMANDS),
226
- ...Object.values(COMMANDS).flatMap((c) => c.aliases || []),
227
- ];
393
+ ...Object.keys(ALIAS_MAP),
394
+ ]);
228
395
 
229
396
  // ─────────────────────────────────────────────────────────────
230
- // RUNNER LOADER
397
+ // GETTERS
231
398
  // ─────────────────────────────────────────────────────────────
232
- function getRunner(cmd, styles = {}) {
233
- const def = COMMANDS[cmd];
234
- if (!def) return null;
235
-
236
- const red = styles.red || "";
237
- const reset = styles.reset || "";
238
- const errorSym = styles.errorSymbol || "✗";
239
399
 
400
+ function getRunner(cmd, opts = {}) {
401
+ // Resolve alias to canonical command
402
+ const canonicalCmd = ALIAS_MAP[cmd] || cmd;
403
+ const def = COMMANDS[canonicalCmd];
404
+
405
+ if (!def) {
406
+ return null;
407
+ }
408
+
409
+ if (!def.runner) {
410
+ return null;
411
+ }
412
+
240
413
  try {
241
414
  return def.runner();
242
415
  } catch (e) {
243
- return async () => {
244
- console.error(`${red}${errorSym}${reset} Failed to load ${cmd}: ${e.message}`);
245
- return 1;
246
- };
416
+ if (opts.red && opts.reset) {
417
+ console.error(`${opts.red}${opts.errorSymbol || '×'} Failed to load runner for ${cmd}: ${e.message}${opts.reset}`);
418
+ }
419
+ return null;
247
420
  }
248
421
  }
249
422
 
423
+ function getCommand(name) {
424
+ // Check direct name
425
+ if (COMMANDS[name]) return COMMANDS[name];
426
+
427
+ // Check alias map
428
+ const canonical = ALIAS_MAP[name];
429
+ if (canonical && COMMANDS[canonical]) {
430
+ return { ...COMMANDS[canonical], _resolvedFrom: name, _canonicalName: canonical };
431
+ }
432
+
433
+ return null;
434
+ }
435
+
436
+ function resolveCommand(name) {
437
+ return ALIAS_MAP[name] || name;
438
+ }
439
+
440
+ // ─────────────────────────────────────────────────────────────
441
+ // EXPORTS
442
+ // ─────────────────────────────────────────────────────────────
250
443
  module.exports = {
444
+ // Core data
251
445
  COMMANDS,
446
+ ALLOWED_COMMANDS,
252
447
  ALIAS_MAP,
253
448
  ALL_COMMANDS,
449
+
450
+ // Tier helpers
451
+ isPro,
452
+ requiresPro,
453
+ getFreeCommands,
454
+ getProCommands,
455
+
456
+ // Getters
254
457
  getRunner,
458
+ getCommand,
459
+ resolveCommand,
460
+ listCommands: () => Object.keys(COMMANDS),
461
+
462
+ getCommandsByTier: (tier) =>
463
+ Object.entries(COMMANDS)
464
+ .filter(([, cmd]) => cmd.tier === tier)
465
+ .map(([name, cmd]) => ({ name, ...cmd })),
466
+
467
+ getCommandsByCategory: (category) =>
468
+ Object.entries(COMMANDS)
469
+ .filter(([, cmd]) => cmd.category === category)
470
+ .map(([name, cmd]) => ({ name, ...cmd })),
255
471
  };