@peakinfer/cli 1.0.133

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 (367) hide show
  1. package/.claude/settings.local.json +8 -0
  2. package/.env.example +6 -0
  3. package/.github/workflows/peakinfer.yml +64 -0
  4. package/CHANGELOG.md +31 -0
  5. package/LICENSE +190 -0
  6. package/README.md +335 -0
  7. package/data/inferencemax.json +274 -0
  8. package/dist/agent-analyzer.d.ts +45 -0
  9. package/dist/agent-analyzer.d.ts.map +1 -0
  10. package/dist/agent-analyzer.js +374 -0
  11. package/dist/agent-analyzer.js.map +1 -0
  12. package/dist/agent.d.ts +76 -0
  13. package/dist/agent.d.ts.map +1 -0
  14. package/dist/agent.js +965 -0
  15. package/dist/agent.js.map +1 -0
  16. package/dist/agents/correlation-analyzer.d.ts +34 -0
  17. package/dist/agents/correlation-analyzer.d.ts.map +1 -0
  18. package/dist/agents/correlation-analyzer.js +261 -0
  19. package/dist/agents/correlation-analyzer.js.map +1 -0
  20. package/dist/agents/index.d.ts +91 -0
  21. package/dist/agents/index.d.ts.map +1 -0
  22. package/dist/agents/index.js +111 -0
  23. package/dist/agents/index.js.map +1 -0
  24. package/dist/agents/runtime-analyzer.d.ts +38 -0
  25. package/dist/agents/runtime-analyzer.d.ts.map +1 -0
  26. package/dist/agents/runtime-analyzer.js +244 -0
  27. package/dist/agents/runtime-analyzer.js.map +1 -0
  28. package/dist/analysis-types.d.ts +500 -0
  29. package/dist/analysis-types.d.ts.map +1 -0
  30. package/dist/analysis-types.js +11 -0
  31. package/dist/analysis-types.js.map +1 -0
  32. package/dist/analytics.d.ts +25 -0
  33. package/dist/analytics.d.ts.map +1 -0
  34. package/dist/analytics.js +94 -0
  35. package/dist/analytics.js.map +1 -0
  36. package/dist/analyzer.d.ts +48 -0
  37. package/dist/analyzer.d.ts.map +1 -0
  38. package/dist/analyzer.js +547 -0
  39. package/dist/analyzer.js.map +1 -0
  40. package/dist/artifacts.d.ts +44 -0
  41. package/dist/artifacts.d.ts.map +1 -0
  42. package/dist/artifacts.js +165 -0
  43. package/dist/artifacts.js.map +1 -0
  44. package/dist/benchmarks/index.d.ts +88 -0
  45. package/dist/benchmarks/index.d.ts.map +1 -0
  46. package/dist/benchmarks/index.js +205 -0
  47. package/dist/benchmarks/index.js.map +1 -0
  48. package/dist/cli.d.ts +3 -0
  49. package/dist/cli.d.ts.map +1 -0
  50. package/dist/cli.js +427 -0
  51. package/dist/cli.js.map +1 -0
  52. package/dist/commands/ci.d.ts +19 -0
  53. package/dist/commands/ci.d.ts.map +1 -0
  54. package/dist/commands/ci.js +253 -0
  55. package/dist/commands/ci.js.map +1 -0
  56. package/dist/commands/config.d.ts +16 -0
  57. package/dist/commands/config.d.ts.map +1 -0
  58. package/dist/commands/config.js +249 -0
  59. package/dist/commands/config.js.map +1 -0
  60. package/dist/commands/demo.d.ts +15 -0
  61. package/dist/commands/demo.d.ts.map +1 -0
  62. package/dist/commands/demo.js +106 -0
  63. package/dist/commands/demo.js.map +1 -0
  64. package/dist/commands/export.d.ts +14 -0
  65. package/dist/commands/export.d.ts.map +1 -0
  66. package/dist/commands/export.js +209 -0
  67. package/dist/commands/export.js.map +1 -0
  68. package/dist/commands/history.d.ts +15 -0
  69. package/dist/commands/history.d.ts.map +1 -0
  70. package/dist/commands/history.js +389 -0
  71. package/dist/commands/history.js.map +1 -0
  72. package/dist/commands/template.d.ts +14 -0
  73. package/dist/commands/template.d.ts.map +1 -0
  74. package/dist/commands/template.js +341 -0
  75. package/dist/commands/template.js.map +1 -0
  76. package/dist/commands/validate-map.d.ts +12 -0
  77. package/dist/commands/validate-map.d.ts.map +1 -0
  78. package/dist/commands/validate-map.js +274 -0
  79. package/dist/commands/validate-map.js.map +1 -0
  80. package/dist/commands/whatif.d.ts +17 -0
  81. package/dist/commands/whatif.d.ts.map +1 -0
  82. package/dist/commands/whatif.js +206 -0
  83. package/dist/commands/whatif.js.map +1 -0
  84. package/dist/comparison.d.ts +38 -0
  85. package/dist/comparison.d.ts.map +1 -0
  86. package/dist/comparison.js +223 -0
  87. package/dist/comparison.js.map +1 -0
  88. package/dist/config.d.ts +42 -0
  89. package/dist/config.d.ts.map +1 -0
  90. package/dist/config.js +158 -0
  91. package/dist/config.js.map +1 -0
  92. package/dist/connectors/helicone.d.ts +9 -0
  93. package/dist/connectors/helicone.d.ts.map +1 -0
  94. package/dist/connectors/helicone.js +106 -0
  95. package/dist/connectors/helicone.js.map +1 -0
  96. package/dist/connectors/index.d.ts +37 -0
  97. package/dist/connectors/index.d.ts.map +1 -0
  98. package/dist/connectors/index.js +65 -0
  99. package/dist/connectors/index.js.map +1 -0
  100. package/dist/connectors/langsmith.d.ts +9 -0
  101. package/dist/connectors/langsmith.d.ts.map +1 -0
  102. package/dist/connectors/langsmith.js +122 -0
  103. package/dist/connectors/langsmith.js.map +1 -0
  104. package/dist/connectors/types.d.ts +83 -0
  105. package/dist/connectors/types.d.ts.map +1 -0
  106. package/dist/connectors/types.js +98 -0
  107. package/dist/connectors/types.js.map +1 -0
  108. package/dist/cost-estimator.d.ts +46 -0
  109. package/dist/cost-estimator.d.ts.map +1 -0
  110. package/dist/cost-estimator.js +104 -0
  111. package/dist/cost-estimator.js.map +1 -0
  112. package/dist/costs.d.ts +57 -0
  113. package/dist/costs.d.ts.map +1 -0
  114. package/dist/costs.js +251 -0
  115. package/dist/costs.js.map +1 -0
  116. package/dist/counterfactuals.d.ts +29 -0
  117. package/dist/counterfactuals.d.ts.map +1 -0
  118. package/dist/counterfactuals.js +448 -0
  119. package/dist/counterfactuals.js.map +1 -0
  120. package/dist/enhancement-prompts.d.ts +41 -0
  121. package/dist/enhancement-prompts.d.ts.map +1 -0
  122. package/dist/enhancement-prompts.js +88 -0
  123. package/dist/enhancement-prompts.js.map +1 -0
  124. package/dist/envelopes.d.ts +20 -0
  125. package/dist/envelopes.d.ts.map +1 -0
  126. package/dist/envelopes.js +790 -0
  127. package/dist/envelopes.js.map +1 -0
  128. package/dist/format-normalizer.d.ts +71 -0
  129. package/dist/format-normalizer.d.ts.map +1 -0
  130. package/dist/format-normalizer.js +1331 -0
  131. package/dist/format-normalizer.js.map +1 -0
  132. package/dist/history.d.ts +79 -0
  133. package/dist/history.d.ts.map +1 -0
  134. package/dist/history.js +313 -0
  135. package/dist/history.js.map +1 -0
  136. package/dist/html.d.ts +11 -0
  137. package/dist/html.d.ts.map +1 -0
  138. package/dist/html.js +463 -0
  139. package/dist/html.js.map +1 -0
  140. package/dist/impact.d.ts +42 -0
  141. package/dist/impact.d.ts.map +1 -0
  142. package/dist/impact.js +443 -0
  143. package/dist/impact.js.map +1 -0
  144. package/dist/index.d.ts +26 -0
  145. package/dist/index.d.ts.map +1 -0
  146. package/dist/index.js +34 -0
  147. package/dist/index.js.map +1 -0
  148. package/dist/insights.d.ts +5 -0
  149. package/dist/insights.d.ts.map +1 -0
  150. package/dist/insights.js +271 -0
  151. package/dist/insights.js.map +1 -0
  152. package/dist/joiner.d.ts +9 -0
  153. package/dist/joiner.d.ts.map +1 -0
  154. package/dist/joiner.js +247 -0
  155. package/dist/joiner.js.map +1 -0
  156. package/dist/orchestrator.d.ts +34 -0
  157. package/dist/orchestrator.d.ts.map +1 -0
  158. package/dist/orchestrator.js +827 -0
  159. package/dist/orchestrator.js.map +1 -0
  160. package/dist/pdf.d.ts +26 -0
  161. package/dist/pdf.d.ts.map +1 -0
  162. package/dist/pdf.js +84 -0
  163. package/dist/pdf.js.map +1 -0
  164. package/dist/prediction.d.ts +33 -0
  165. package/dist/prediction.d.ts.map +1 -0
  166. package/dist/prediction.js +316 -0
  167. package/dist/prediction.js.map +1 -0
  168. package/dist/prompts/loader.d.ts +38 -0
  169. package/dist/prompts/loader.d.ts.map +1 -0
  170. package/dist/prompts/loader.js +60 -0
  171. package/dist/prompts/loader.js.map +1 -0
  172. package/dist/renderer.d.ts +64 -0
  173. package/dist/renderer.d.ts.map +1 -0
  174. package/dist/renderer.js +923 -0
  175. package/dist/renderer.js.map +1 -0
  176. package/dist/runid.d.ts +57 -0
  177. package/dist/runid.d.ts.map +1 -0
  178. package/dist/runid.js +199 -0
  179. package/dist/runid.js.map +1 -0
  180. package/dist/runtime.d.ts +29 -0
  181. package/dist/runtime.d.ts.map +1 -0
  182. package/dist/runtime.js +366 -0
  183. package/dist/runtime.js.map +1 -0
  184. package/dist/scanner.d.ts +11 -0
  185. package/dist/scanner.d.ts.map +1 -0
  186. package/dist/scanner.js +426 -0
  187. package/dist/scanner.js.map +1 -0
  188. package/dist/templates.d.ts +120 -0
  189. package/dist/templates.d.ts.map +1 -0
  190. package/dist/templates.js +429 -0
  191. package/dist/templates.js.map +1 -0
  192. package/dist/tools/index.d.ts +153 -0
  193. package/dist/tools/index.d.ts.map +1 -0
  194. package/dist/tools/index.js +177 -0
  195. package/dist/tools/index.js.map +1 -0
  196. package/dist/types.d.ts +3647 -0
  197. package/dist/types.d.ts.map +1 -0
  198. package/dist/types.js +703 -0
  199. package/dist/types.js.map +1 -0
  200. package/dist/version.d.ts +7 -0
  201. package/dist/version.d.ts.map +1 -0
  202. package/dist/version.js +23 -0
  203. package/dist/version.js.map +1 -0
  204. package/docs/demo-guide.md +423 -0
  205. package/docs/events-format.md +295 -0
  206. package/docs/inferencemap-spec.md +344 -0
  207. package/docs/migration-v2.md +293 -0
  208. package/fixtures/demo/precomputed.json +142 -0
  209. package/fixtures/demo-project/README.md +52 -0
  210. package/fixtures/demo-project/ai-service.ts +65 -0
  211. package/fixtures/demo-project/sample-events.jsonl +15 -0
  212. package/fixtures/demo-project/src/ai-service.ts +128 -0
  213. package/fixtures/demo-project/src/llm-client.ts +155 -0
  214. package/package.json +65 -0
  215. package/prompts/agent-analyzer.yaml +47 -0
  216. package/prompts/ci-gate.yaml +98 -0
  217. package/prompts/correlation-analyzer.yaml +178 -0
  218. package/prompts/format-normalizer.yaml +46 -0
  219. package/prompts/peak-performance.yaml +180 -0
  220. package/prompts/pr-comment.yaml +111 -0
  221. package/prompts/runtime-analyzer.yaml +189 -0
  222. package/prompts/unified-analyzer.yaml +241 -0
  223. package/schemas/inference-map.v0.1.json +215 -0
  224. package/scripts/benchmark.ts +394 -0
  225. package/scripts/demo-v1.5.sh +158 -0
  226. package/scripts/sync-from-site.sh +197 -0
  227. package/scripts/validate-sync.sh +178 -0
  228. package/src/agent-analyzer.ts +481 -0
  229. package/src/agent.ts +1232 -0
  230. package/src/agents/correlation-analyzer.ts +353 -0
  231. package/src/agents/index.ts +235 -0
  232. package/src/agents/runtime-analyzer.ts +343 -0
  233. package/src/analysis-types.ts +558 -0
  234. package/src/analytics.ts +100 -0
  235. package/src/analyzer.ts +692 -0
  236. package/src/artifacts.ts +218 -0
  237. package/src/benchmarks/index.ts +309 -0
  238. package/src/cli.ts +503 -0
  239. package/src/commands/ci.ts +336 -0
  240. package/src/commands/config.ts +288 -0
  241. package/src/commands/demo.ts +175 -0
  242. package/src/commands/export.ts +297 -0
  243. package/src/commands/history.ts +425 -0
  244. package/src/commands/template.ts +385 -0
  245. package/src/commands/validate-map.ts +324 -0
  246. package/src/commands/whatif.ts +272 -0
  247. package/src/comparison.ts +283 -0
  248. package/src/config.ts +188 -0
  249. package/src/connectors/helicone.ts +164 -0
  250. package/src/connectors/index.ts +93 -0
  251. package/src/connectors/langsmith.ts +179 -0
  252. package/src/connectors/types.ts +180 -0
  253. package/src/cost-estimator.ts +146 -0
  254. package/src/costs.ts +347 -0
  255. package/src/counterfactuals.ts +516 -0
  256. package/src/enhancement-prompts.ts +118 -0
  257. package/src/envelopes.ts +814 -0
  258. package/src/format-normalizer.ts +1486 -0
  259. package/src/history.ts +400 -0
  260. package/src/html.ts +512 -0
  261. package/src/impact.ts +522 -0
  262. package/src/index.ts +83 -0
  263. package/src/insights.ts +341 -0
  264. package/src/joiner.ts +289 -0
  265. package/src/orchestrator.ts +1015 -0
  266. package/src/pdf.ts +110 -0
  267. package/src/prediction.ts +392 -0
  268. package/src/prompts/loader.ts +88 -0
  269. package/src/renderer.ts +1045 -0
  270. package/src/runid.ts +261 -0
  271. package/src/runtime.ts +450 -0
  272. package/src/scanner.ts +508 -0
  273. package/src/templates.ts +561 -0
  274. package/src/tools/index.ts +214 -0
  275. package/src/types.ts +873 -0
  276. package/src/version.ts +24 -0
  277. package/templates/context-accumulation.yaml +23 -0
  278. package/templates/cost-concentration.yaml +20 -0
  279. package/templates/dead-code.yaml +20 -0
  280. package/templates/latency-explainer.yaml +23 -0
  281. package/templates/optimizations/ab-testing-framework.yaml +74 -0
  282. package/templates/optimizations/api-gateway-optimization.yaml +81 -0
  283. package/templates/optimizations/api-model-routing-strategy.yaml +126 -0
  284. package/templates/optimizations/auto-scaling-optimization.yaml +85 -0
  285. package/templates/optimizations/batch-utilization-diagnostic.yaml +142 -0
  286. package/templates/optimizations/comprehensive-apm.yaml +76 -0
  287. package/templates/optimizations/context-window-optimization.yaml +91 -0
  288. package/templates/optimizations/cost-sensitive-batch-processing.yaml +77 -0
  289. package/templates/optimizations/distributed-training-optimization.yaml +77 -0
  290. package/templates/optimizations/document-analysis-edge.yaml +77 -0
  291. package/templates/optimizations/document-pipeline-optimization.yaml +78 -0
  292. package/templates/optimizations/domain-specific-distillation.yaml +78 -0
  293. package/templates/optimizations/error-handling-optimization.yaml +76 -0
  294. package/templates/optimizations/gptq-4bit-quantization.yaml +96 -0
  295. package/templates/optimizations/long-context-memory-management.yaml +78 -0
  296. package/templates/optimizations/max-tokens-optimization.yaml +76 -0
  297. package/templates/optimizations/memory-bandwidth-optimization.yaml +73 -0
  298. package/templates/optimizations/multi-framework-resilience.yaml +75 -0
  299. package/templates/optimizations/multi-tenant-optimization.yaml +75 -0
  300. package/templates/optimizations/prompt-caching-optimization.yaml +143 -0
  301. package/templates/optimizations/pytorch-to-onnx-migration.yaml +109 -0
  302. package/templates/optimizations/quality-monitoring.yaml +74 -0
  303. package/templates/optimizations/realtime-budget-controls.yaml +74 -0
  304. package/templates/optimizations/realtime-latency-optimization.yaml +74 -0
  305. package/templates/optimizations/sglang-concurrency-optimization.yaml +78 -0
  306. package/templates/optimizations/smart-model-routing.yaml +96 -0
  307. package/templates/optimizations/streaming-batch-selection.yaml +167 -0
  308. package/templates/optimizations/system-prompt-optimization.yaml +75 -0
  309. package/templates/optimizations/tensorrt-llm-performance.yaml +77 -0
  310. package/templates/optimizations/vllm-high-throughput-optimization.yaml +93 -0
  311. package/templates/optimizations/vllm-migration-memory-bound.yaml +78 -0
  312. package/templates/overpowered-extraction.yaml +32 -0
  313. package/templates/overpowered-model.yaml +31 -0
  314. package/templates/prompt-bloat.yaml +24 -0
  315. package/templates/retry-explosion.yaml +28 -0
  316. package/templates/schema/insight.schema.json +113 -0
  317. package/templates/schema/optimization.schema.json +180 -0
  318. package/templates/streaming-drift.yaml +30 -0
  319. package/templates/throughput-gap.yaml +21 -0
  320. package/templates/token-underutilization.yaml +28 -0
  321. package/templates/untested-fallback.yaml +21 -0
  322. package/tests/accuracy/drift-detection.test.ts +184 -0
  323. package/tests/accuracy/false-positives.test.ts +166 -0
  324. package/tests/accuracy/templates.test.ts +205 -0
  325. package/tests/action/commands.test.ts +125 -0
  326. package/tests/action/comments.test.ts +347 -0
  327. package/tests/cli.test.ts +203 -0
  328. package/tests/comparison.test.ts +309 -0
  329. package/tests/correlation-analyzer.test.ts +534 -0
  330. package/tests/counterfactuals.test.ts +347 -0
  331. package/tests/fixtures/events/missing-id.jsonl +1 -0
  332. package/tests/fixtures/events/missing-input.jsonl +1 -0
  333. package/tests/fixtures/events/missing-latency.jsonl +1 -0
  334. package/tests/fixtures/events/missing-model.jsonl +1 -0
  335. package/tests/fixtures/events/missing-output.jsonl +1 -0
  336. package/tests/fixtures/events/missing-provider.jsonl +1 -0
  337. package/tests/fixtures/events/missing-ts.jsonl +1 -0
  338. package/tests/fixtures/events/valid.csv +3 -0
  339. package/tests/fixtures/events/valid.json +1 -0
  340. package/tests/fixtures/events/valid.jsonl +2 -0
  341. package/tests/fixtures/events/with-callsite.jsonl +1 -0
  342. package/tests/fixtures/events/with-intent.jsonl +1 -0
  343. package/tests/fixtures/events/wrong-type.jsonl +1 -0
  344. package/tests/fixtures/repos/empty/.gitkeep +0 -0
  345. package/tests/fixtures/repos/hybrid-router/router.py +35 -0
  346. package/tests/fixtures/repos/saas-anthropic/agent.ts +27 -0
  347. package/tests/fixtures/repos/saas-openai/assistant.js +33 -0
  348. package/tests/fixtures/repos/saas-openai/client.py +26 -0
  349. package/tests/fixtures/repos/self-hosted-vllm/inference.py +22 -0
  350. package/tests/github-action.test.ts +292 -0
  351. package/tests/insights.test.ts +878 -0
  352. package/tests/joiner.test.ts +168 -0
  353. package/tests/performance/action-latency.test.ts +132 -0
  354. package/tests/performance/benchmark.test.ts +189 -0
  355. package/tests/performance/cli-latency.test.ts +102 -0
  356. package/tests/pr-comment.test.ts +313 -0
  357. package/tests/prediction.test.ts +296 -0
  358. package/tests/runtime-analyzer.test.ts +375 -0
  359. package/tests/runtime.test.ts +205 -0
  360. package/tests/scanner.test.ts +122 -0
  361. package/tests/template-conformance.test.ts +526 -0
  362. package/tests/unit/cost-calculator.test.ts +303 -0
  363. package/tests/unit/credits.test.ts +180 -0
  364. package/tests/unit/inference-map.test.ts +276 -0
  365. package/tests/unit/schema.test.ts +300 -0
  366. package/tsconfig.json +20 -0
  367. package/vitest.config.ts +14 -0
@@ -0,0 +1,385 @@
1
+ /**
2
+ * Template Commands (v1.6)
3
+ *
4
+ * CLI commands for managing insight templates:
5
+ * - list: List available templates with optional category filter
6
+ * - info: Show detailed template information
7
+ * - roi: Calculate ROI for a template
8
+ */
9
+
10
+ import { Command } from 'commander';
11
+ import { loadTemplates, getTemplate, loadOptimizationTemplates, getOptimizationTemplate } from '../templates.js';
12
+ import type { InsightTemplate, OptimizationTemplate } from '../types.js';
13
+
14
+ // =============================================================================
15
+ // HELPERS
16
+ // =============================================================================
17
+
18
+ /**
19
+ * Format category with color indicator
20
+ */
21
+ function formatCategory(category: string): string {
22
+ return `[${category}]`;
23
+ }
24
+
25
+ /**
26
+ * Format severity with indicator
27
+ */
28
+ function formatSeverity(severity: string): string {
29
+ const indicators: Record<string, string> = {
30
+ critical: '[!]',
31
+ warning: '[*]',
32
+ info: '[-]',
33
+ };
34
+ return `${indicators[severity] || '[ ]'} ${severity}`;
35
+ }
36
+
37
+ /**
38
+ * Display templates in a formatted list
39
+ */
40
+ function displayTemplateList(templates: InsightTemplate[]): void {
41
+ if (templates.length === 0) {
42
+ console.log('No templates found.');
43
+ return;
44
+ }
45
+
46
+ console.log(`\n${templates.length} template${templates.length !== 1 ? 's' : ''} available:\n`);
47
+
48
+ // Group by category
49
+ const byCategory = new Map<string, InsightTemplate[]>();
50
+ for (const t of templates) {
51
+ if (!byCategory.has(t.category)) {
52
+ byCategory.set(t.category, []);
53
+ }
54
+ byCategory.get(t.category)!.push(t);
55
+ }
56
+
57
+ for (const [category, categoryTemplates] of byCategory) {
58
+ console.log(`${formatCategory(category)}`);
59
+ for (const t of categoryTemplates) {
60
+ console.log(` ${formatSeverity(t.severity)} ${t.id}`);
61
+ console.log(` ${t.name}`);
62
+ }
63
+ console.log('');
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Display detailed template information
69
+ */
70
+ function displayTemplateInfo(template: InsightTemplate): void {
71
+ console.log(`\n${template.name} (${template.id})`);
72
+ console.log('═'.repeat(60));
73
+ console.log(`Version: ${template.version}`);
74
+ console.log(`Category: ${formatCategory(template.category)}`);
75
+ if (template.layer) {
76
+ console.log(`Layer: [${template.layer}]`);
77
+ }
78
+ console.log(`Severity: ${formatSeverity(template.severity)}`);
79
+ console.log('');
80
+ console.log('Match Scope:', template.match.scope);
81
+ console.log('Conditions:');
82
+ for (const cond of template.match.conditions) {
83
+ console.log(` - ${cond.field} ${cond.op} ${cond.value ?? cond.pattern ?? ''}`);
84
+ }
85
+ console.log('');
86
+ console.log('Output:');
87
+ console.log(` Headline: ${template.output.headline}`);
88
+ console.log(` Evidence: ${template.output.evidence}`);
89
+
90
+ if (template.defaults && Object.keys(template.defaults).length > 0) {
91
+ console.log('');
92
+ console.log('Defaults:');
93
+ for (const [key, value] of Object.entries(template.defaults)) {
94
+ console.log(` ${key}: ${value}`);
95
+ }
96
+ }
97
+ }
98
+
99
+ // =============================================================================
100
+ // OPTIMIZATION TEMPLATE DISPLAY HELPERS (v1.8 - Inference Squeeze Guide)
101
+ // =============================================================================
102
+
103
+ /**
104
+ * Display optimization templates in a formatted list
105
+ */
106
+ function displayOptimizationList(templates: OptimizationTemplate[]): void {
107
+ if (templates.length === 0) {
108
+ console.log('No optimization templates found.');
109
+ return;
110
+ }
111
+
112
+ console.log(`\n${templates.length} optimization template${templates.length !== 1 ? 's' : ''} available:\n`);
113
+
114
+ // Group by category
115
+ const byCategory = new Map<string, OptimizationTemplate[]>();
116
+ for (const t of templates) {
117
+ if (!byCategory.has(t.category)) {
118
+ byCategory.set(t.category, []);
119
+ }
120
+ byCategory.get(t.category)!.push(t);
121
+ }
122
+
123
+ for (const [category, categoryTemplates] of byCategory) {
124
+ console.log(`[${category}]`);
125
+ for (const t of categoryTemplates) {
126
+ const risk = t.optimization.risk_level === 'high' ? '[!]' : t.optimization.risk_level === 'medium' ? '[*]' : '[-]';
127
+ console.log(` ${risk} ${t.id}`);
128
+ console.log(` ${t.name}`);
129
+ if (t.optimization.expected_cost_reduction) {
130
+ console.log(` Cost: ${t.optimization.expected_cost_reduction} | Effort: ${t.optimization.effort_estimate}`);
131
+ }
132
+ }
133
+ console.log('');
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Display detailed optimization template information
139
+ */
140
+ function displayOptimizationInfo(template: OptimizationTemplate): void {
141
+ console.log(`\n${template.name} (${template.id})`);
142
+ console.log('═'.repeat(70));
143
+ console.log(`Category: [${template.category}]`);
144
+ console.log(`Confidence: ${(template.confidence * 100).toFixed(0)}%`);
145
+ if (template.success_count) {
146
+ console.log(`Success: ${template.success_count} implementations`);
147
+ }
148
+ console.log('');
149
+
150
+ console.log('Optimization:');
151
+ console.log(` Technique: ${template.optimization.technique}`);
152
+ if (template.optimization.expected_cost_reduction) {
153
+ console.log(` Cost Reduction: ${template.optimization.expected_cost_reduction}`);
154
+ }
155
+ if (template.optimization.expected_latency_improvement) {
156
+ console.log(` Latency Improvement: ${template.optimization.expected_latency_improvement}`);
157
+ }
158
+ if (template.optimization.expected_throughput_improvement) {
159
+ console.log(` Throughput Improvement: ${template.optimization.expected_throughput_improvement}`);
160
+ }
161
+ console.log(` Effort: ${template.optimization.effort_estimate}`);
162
+ console.log(` Risk: ${template.optimization.risk_level}`);
163
+ console.log('');
164
+
165
+ if (template.implementation?.prerequisites) {
166
+ console.log('Prerequisites:');
167
+ for (const prereq of template.implementation.prerequisites) {
168
+ console.log(` - ${prereq.requirement}`);
169
+ }
170
+ console.log('');
171
+ }
172
+
173
+ if (template.implementation?.automated_steps) {
174
+ console.log('Implementation Steps:');
175
+ for (const step of template.implementation.automated_steps) {
176
+ console.log(` ${step.step_id}: ${step.name}`);
177
+ }
178
+ console.log('');
179
+ }
180
+
181
+ if (template.monitoring?.key_metrics) {
182
+ console.log('Key Metrics:');
183
+ for (const metric of template.monitoring.key_metrics) {
184
+ console.log(` - ${metric.metric}: target ${metric.target}`);
185
+ }
186
+ console.log('');
187
+ }
188
+
189
+ if (template.economics?.implementation_cost) {
190
+ console.log('Implementation Cost:');
191
+ if (template.economics.implementation_cost.engineering_hours) {
192
+ console.log(` Engineering Hours: ${template.economics.implementation_cost.engineering_hours}`);
193
+ }
194
+ console.log(` Total Cost: $${template.economics.implementation_cost.total_cost.toLocaleString()}`);
195
+ console.log('');
196
+ }
197
+
198
+ console.log('Note: ROI estimates are indicative. Actual results depend on your environment.');
199
+ }
200
+
201
+ /**
202
+ * Calculate and display ROI for a template
203
+ */
204
+ function displayTemplateROI(template: InsightTemplate, monthlyCost?: number): void {
205
+ console.log(`\nROI Analysis: ${template.name}`);
206
+ console.log('═'.repeat(60));
207
+
208
+ // Use defaults or provided values
209
+ const defaults = template.defaults || {};
210
+ const baseCost = monthlyCost || defaults.monthly_cost || 10000;
211
+
212
+ // Estimate savings based on category
213
+ let savingsPercent = 0;
214
+ let savingsDescription = '';
215
+
216
+ switch (template.category) {
217
+ case 'cost':
218
+ savingsPercent = defaults.estimated_savings_percent || 20;
219
+ savingsDescription = 'Direct cost reduction';
220
+ break;
221
+ case 'latency':
222
+ savingsPercent = defaults.latency_improvement_percent || 30;
223
+ savingsDescription = 'User time saved (latency reduction)';
224
+ break;
225
+ case 'reliability':
226
+ savingsPercent = defaults.failure_reduction_percent || 15;
227
+ savingsDescription = 'Avoided failures and retries';
228
+ break;
229
+ case 'throughput':
230
+ savingsPercent = defaults.throughput_improvement_percent || 25;
231
+ savingsDescription = 'Capacity improvement';
232
+ break;
233
+ default:
234
+ savingsPercent = 10;
235
+ savingsDescription = 'General optimization';
236
+ }
237
+
238
+ const monthlySavings = Math.round(baseCost * (savingsPercent / 100));
239
+ const annualSavings = monthlySavings * 12;
240
+
241
+ console.log(`Base Monthly Cost: $${baseCost.toLocaleString()}`);
242
+ console.log(`Category: ${template.category}`);
243
+ console.log('');
244
+ console.log(`Estimated Impact: ${savingsPercent}% ${savingsDescription}`);
245
+ console.log(`Monthly Savings: $${monthlySavings.toLocaleString()}`);
246
+ console.log(`Annual Savings: $${annualSavings.toLocaleString()}`);
247
+ console.log('');
248
+ console.log('Note: Estimates based on typical scenarios. Actual results may vary.');
249
+ }
250
+
251
+ // =============================================================================
252
+ // COMMANDS
253
+ // =============================================================================
254
+
255
+ /**
256
+ * Register template commands
257
+ */
258
+ export function registerTemplateCommands(program: Command): void {
259
+ const templateCmd = program
260
+ .command('template')
261
+ .description('manage insight templates');
262
+
263
+ // List templates
264
+ templateCmd
265
+ .command('list')
266
+ .description('list available templates')
267
+ .option('--category <cat>', 'filter by category (cost, latency, reliability, throughput, drift)')
268
+ .option('--layer <layer>', 'filter by stack layer (application, api, gateway, runtime, model, hardware)')
269
+ .option('--offline', 'use cached templates only')
270
+ .action(async (options: { category?: string; layer?: string; offline?: boolean }) => {
271
+ try {
272
+ const templates = await loadTemplates({ offline: options.offline });
273
+
274
+ let filtered = templates;
275
+
276
+ // Filter by category if specified
277
+ if (options.category) {
278
+ filtered = filtered.filter(t => t.category === options.category);
279
+ }
280
+
281
+ // v1.8: Filter by layer if specified
282
+ if (options.layer) {
283
+ filtered = filtered.filter(t => t.layer === options.layer);
284
+ }
285
+
286
+ displayTemplateList(filtered);
287
+ } catch (error) {
288
+ console.error('Error:', error instanceof Error ? error.message : 'Failed to load templates');
289
+ process.exit(1);
290
+ }
291
+ });
292
+
293
+ // Template info
294
+ templateCmd
295
+ .command('info')
296
+ .description('show template details')
297
+ .argument('<id>', 'template ID')
298
+ .option('--offline', 'use cached templates only')
299
+ .action(async (id: string, options: { offline?: boolean }) => {
300
+ try {
301
+ const template = await getTemplate(id, { offline: options.offline });
302
+
303
+ if (!template) {
304
+ console.error(`Template not found: ${id}`);
305
+ console.log('\nRun "peakinfer template list" to see available templates.');
306
+ process.exit(1);
307
+ }
308
+
309
+ displayTemplateInfo(template);
310
+ } catch (error) {
311
+ console.error('Error:', error instanceof Error ? error.message : 'Failed to load template');
312
+ process.exit(1);
313
+ }
314
+ });
315
+
316
+ // Template ROI
317
+ templateCmd
318
+ .command('roi')
319
+ .description('calculate ROI for a template')
320
+ .argument('<id>', 'template ID')
321
+ .option('--monthly-cost <amount>', 'your monthly inference cost in USD', parseFloat)
322
+ .option('--offline', 'use cached templates only')
323
+ .action(async (id: string, options: { monthlyCost?: number; offline?: boolean }) => {
324
+ try {
325
+ const template = await getTemplate(id, { offline: options.offline });
326
+
327
+ if (!template) {
328
+ console.error(`Template not found: ${id}`);
329
+ process.exit(1);
330
+ }
331
+
332
+ displayTemplateROI(template, options.monthlyCost);
333
+ } catch (error) {
334
+ console.error('Error:', error instanceof Error ? error.message : 'Failed to calculate ROI');
335
+ process.exit(1);
336
+ }
337
+ });
338
+
339
+ // ==========================================================================
340
+ // OPTIMIZATION TEMPLATES (v1.8 - Inference Squeeze Guide)
341
+ // ==========================================================================
342
+
343
+ // List optimization templates
344
+ templateCmd
345
+ .command('optimizations')
346
+ .description('list community optimization templates (Inference Squeeze Guide)')
347
+ .option('--category <cat>', 'filter by category (runtime_optimization, batching_optimization, memory_optimization, application_optimization, cost_optimization, monitoring, scaling)')
348
+ .action((options: { category?: string }) => {
349
+ try {
350
+ let templates = loadOptimizationTemplates();
351
+
352
+ // Filter by category if specified
353
+ if (options.category) {
354
+ templates = templates.filter(t => t.category === options.category);
355
+ }
356
+
357
+ displayOptimizationList(templates);
358
+ } catch (error) {
359
+ console.error('Error:', error instanceof Error ? error.message : 'Failed to load optimization templates');
360
+ process.exit(1);
361
+ }
362
+ });
363
+
364
+ // Optimization template info
365
+ templateCmd
366
+ .command('optimization')
367
+ .description('show optimization template details')
368
+ .argument('<id>', 'optimization template ID')
369
+ .action((id: string) => {
370
+ try {
371
+ const template = getOptimizationTemplate(id);
372
+
373
+ if (!template) {
374
+ console.error(`Optimization template not found: ${id}`);
375
+ console.log('\nRun "peakinfer template optimizations" to see available templates.');
376
+ process.exit(1);
377
+ }
378
+
379
+ displayOptimizationInfo(template);
380
+ } catch (error) {
381
+ console.error('Error:', error instanceof Error ? error.message : 'Failed to load optimization template');
382
+ process.exit(1);
383
+ }
384
+ });
385
+ }
@@ -0,0 +1,324 @@
1
+ /**
2
+ * Validate-Map Command (v1.9.3)
3
+ *
4
+ * CLI command for validating InferenceMap JSON files against the v0.1 schema.
5
+ * Per PRD v1.9.3: `peakinfer validate-map ./analysis.json`
6
+ */
7
+
8
+ import { Command } from 'commander';
9
+ import { existsSync, readFileSync } from 'fs';
10
+ import { resolve, dirname } from 'path';
11
+ import { fileURLToPath } from 'url';
12
+
13
+ // =============================================================================
14
+ // TYPES
15
+ // =============================================================================
16
+
17
+ interface ValidationResult {
18
+ valid: boolean;
19
+ errors: ValidationError[];
20
+ warnings: ValidationWarning[];
21
+ }
22
+
23
+ interface ValidationError {
24
+ path: string;
25
+ message: string;
26
+ expected?: string;
27
+ actual?: string;
28
+ }
29
+
30
+ interface ValidationWarning {
31
+ path: string;
32
+ message: string;
33
+ }
34
+
35
+ // =============================================================================
36
+ // SCHEMA VALIDATION
37
+ // =============================================================================
38
+
39
+ /**
40
+ * Load the InferenceMap v0.1 JSON Schema
41
+ */
42
+ function loadSchema(): object {
43
+ const __filename = fileURLToPath(import.meta.url);
44
+ const __dirname = dirname(__filename);
45
+ const schemaPath = resolve(__dirname, '../../schemas/inference-map.v0.1.json');
46
+
47
+ if (!existsSync(schemaPath)) {
48
+ throw new Error(`Schema not found at ${schemaPath}`);
49
+ }
50
+
51
+ return JSON.parse(readFileSync(schemaPath, 'utf-8'));
52
+ }
53
+
54
+ /**
55
+ * Validate an InferenceMap against the v0.1 schema.
56
+ * Performs structural validation without external dependencies.
57
+ */
58
+ function validateInferenceMap(data: unknown): ValidationResult {
59
+ const errors: ValidationError[] = [];
60
+ const warnings: ValidationWarning[] = [];
61
+
62
+ // Type guard
63
+ if (typeof data !== 'object' || data === null) {
64
+ errors.push({ path: '$', message: 'InferenceMap must be an object' });
65
+ return { valid: false, errors, warnings };
66
+ }
67
+
68
+ const map = data as Record<string, unknown>;
69
+
70
+ // Required fields
71
+ const requiredFields = ['version', 'root', 'generatedAt', 'summary', 'callsites'];
72
+ for (const field of requiredFields) {
73
+ if (!(field in map)) {
74
+ errors.push({ path: `$.${field}`, message: `Missing required field: ${field}` });
75
+ }
76
+ }
77
+
78
+ // Version check
79
+ if ('version' in map && map.version !== '0.1') {
80
+ errors.push({
81
+ path: '$.version',
82
+ message: 'Invalid version',
83
+ expected: '0.1',
84
+ actual: String(map.version),
85
+ });
86
+ }
87
+
88
+ // Root validation
89
+ if ('root' in map && typeof map.root !== 'string') {
90
+ errors.push({ path: '$.root', message: 'root must be a string' });
91
+ }
92
+
93
+ // generatedAt validation (ISO 8601)
94
+ if ('generatedAt' in map) {
95
+ if (typeof map.generatedAt !== 'string') {
96
+ errors.push({ path: '$.generatedAt', message: 'generatedAt must be a string' });
97
+ } else {
98
+ const date = new Date(map.generatedAt);
99
+ if (isNaN(date.getTime())) {
100
+ errors.push({ path: '$.generatedAt', message: 'generatedAt must be a valid ISO 8601 date-time' });
101
+ }
102
+ }
103
+ }
104
+
105
+ // Summary validation
106
+ if ('summary' in map) {
107
+ if (typeof map.summary !== 'object' || map.summary === null) {
108
+ errors.push({ path: '$.summary', message: 'summary must be an object' });
109
+ } else {
110
+ const summary = map.summary as Record<string, unknown>;
111
+
112
+ // Required summary fields
113
+ const summaryRequired = ['totalCallsites', 'providers', 'models', 'patterns'];
114
+ for (const field of summaryRequired) {
115
+ if (!(field in summary)) {
116
+ errors.push({ path: `$.summary.${field}`, message: `Missing required field: ${field}` });
117
+ }
118
+ }
119
+
120
+ // Type checks
121
+ if ('totalCallsites' in summary && typeof summary.totalCallsites !== 'number') {
122
+ errors.push({ path: '$.summary.totalCallsites', message: 'totalCallsites must be a number' });
123
+ }
124
+ if ('providers' in summary && !Array.isArray(summary.providers)) {
125
+ errors.push({ path: '$.summary.providers', message: 'providers must be an array' });
126
+ }
127
+ if ('models' in summary && !Array.isArray(summary.models)) {
128
+ errors.push({ path: '$.summary.models', message: 'models must be an array' });
129
+ }
130
+ if ('patterns' in summary && (typeof summary.patterns !== 'object' || summary.patterns === null)) {
131
+ errors.push({ path: '$.summary.patterns', message: 'patterns must be an object' });
132
+ }
133
+ }
134
+ }
135
+
136
+ // Callsites validation
137
+ if ('callsites' in map) {
138
+ if (!Array.isArray(map.callsites)) {
139
+ errors.push({ path: '$.callsites', message: 'callsites must be an array' });
140
+ } else {
141
+ const callsites = map.callsites as unknown[];
142
+ for (let i = 0; i < callsites.length; i++) {
143
+ const callsite = callsites[i];
144
+ if (typeof callsite !== 'object' || callsite === null) {
145
+ errors.push({ path: `$.callsites[${i}]`, message: 'callsite must be an object' });
146
+ continue;
147
+ }
148
+
149
+ const cs = callsite as Record<string, unknown>;
150
+
151
+ // Required callsite fields
152
+ const callsiteRequired = ['id', 'file', 'line', 'patterns', 'confidence'];
153
+ for (const field of callsiteRequired) {
154
+ if (!(field in cs)) {
155
+ errors.push({ path: `$.callsites[${i}].${field}`, message: `Missing required field: ${field}` });
156
+ }
157
+ }
158
+
159
+ // Type checks
160
+ if ('id' in cs && typeof cs.id !== 'string') {
161
+ errors.push({ path: `$.callsites[${i}].id`, message: 'id must be a string' });
162
+ }
163
+ if ('file' in cs && typeof cs.file !== 'string') {
164
+ errors.push({ path: `$.callsites[${i}].file`, message: 'file must be a string' });
165
+ }
166
+ if ('line' in cs) {
167
+ if (typeof cs.line !== 'number' || !Number.isInteger(cs.line) || cs.line < 1) {
168
+ errors.push({ path: `$.callsites[${i}].line`, message: 'line must be a positive integer' });
169
+ }
170
+ }
171
+ if ('confidence' in cs) {
172
+ if (typeof cs.confidence !== 'number' || cs.confidence < 0 || cs.confidence > 1) {
173
+ errors.push({ path: `$.callsites[${i}].confidence`, message: 'confidence must be a number between 0 and 1' });
174
+ }
175
+ }
176
+ if ('patterns' in cs && (typeof cs.patterns !== 'object' || cs.patterns === null)) {
177
+ errors.push({ path: `$.callsites[${i}].patterns`, message: 'patterns must be an object' });
178
+ }
179
+
180
+ // Provider validation (known providers)
181
+ const validProviders = [
182
+ 'openai', 'anthropic', 'google', 'cohere', 'mistral',
183
+ 'bedrock', 'azure_openai', 'together', 'fireworks',
184
+ 'groq', 'replicate', 'perplexity',
185
+ 'vllm', 'sglang', 'tgi', 'ollama', 'llamacpp',
186
+ 'unknown',
187
+ ];
188
+ if ('provider' in cs && cs.provider !== null && typeof cs.provider === 'string') {
189
+ if (!validProviders.includes(cs.provider)) {
190
+ warnings.push({
191
+ path: `$.callsites[${i}].provider`,
192
+ message: `Unknown provider: ${cs.provider}. Known providers: ${validProviders.join(', ')}`,
193
+ });
194
+ }
195
+ }
196
+ }
197
+ }
198
+ }
199
+
200
+ // Metadata validation (optional)
201
+ if ('metadata' in map && map.metadata !== null) {
202
+ if (typeof map.metadata !== 'object') {
203
+ warnings.push({ path: '$.metadata', message: 'metadata should be an object' });
204
+ }
205
+ }
206
+
207
+ return {
208
+ valid: errors.length === 0,
209
+ errors,
210
+ warnings,
211
+ };
212
+ }
213
+
214
+ // =============================================================================
215
+ // OUTPUT FORMATTING
216
+ // =============================================================================
217
+
218
+ /**
219
+ * Format validation results for terminal output
220
+ */
221
+ function formatResults(result: ValidationResult, filePath: string): void {
222
+ console.log('');
223
+ console.log(`InferenceMap Validation: ${filePath}`);
224
+ console.log('─'.repeat(60));
225
+
226
+ if (result.valid) {
227
+ console.log('✓ Valid InferenceMap v0.1');
228
+ } else {
229
+ console.log('✗ Invalid InferenceMap');
230
+ }
231
+ console.log('');
232
+
233
+ if (result.errors.length > 0) {
234
+ console.log(`Errors (${result.errors.length}):`);
235
+ for (const error of result.errors) {
236
+ console.log(` ✗ ${error.path}: ${error.message}`);
237
+ if (error.expected !== undefined) {
238
+ console.log(` Expected: ${error.expected}`);
239
+ console.log(` Actual: ${error.actual}`);
240
+ }
241
+ }
242
+ console.log('');
243
+ }
244
+
245
+ if (result.warnings.length > 0) {
246
+ console.log(`Warnings (${result.warnings.length}):`);
247
+ for (const warning of result.warnings) {
248
+ console.log(` ⚠ ${warning.path}: ${warning.message}`);
249
+ }
250
+ console.log('');
251
+ }
252
+
253
+ if (result.valid && result.warnings.length === 0) {
254
+ console.log('No issues found.');
255
+ console.log('');
256
+ }
257
+ }
258
+
259
+ // =============================================================================
260
+ // COMMAND REGISTRATION
261
+ // =============================================================================
262
+
263
+ /**
264
+ * Register the validate-map command
265
+ */
266
+ export function registerValidateMapCommand(program: Command): void {
267
+ program
268
+ .command('validate-map')
269
+ .description('validate an InferenceMap JSON file against the v0.1 schema')
270
+ .argument('<file>', 'path to InferenceMap JSON file')
271
+ .option('--json', 'output validation results as JSON')
272
+ .option('--quiet', 'only output errors (exit code indicates validity)')
273
+ .action((file: string, options: { json?: boolean; quiet?: boolean }) => {
274
+ try {
275
+ // Resolve file path
276
+ const filePath = resolve(file);
277
+
278
+ // Check file exists
279
+ if (!existsSync(filePath)) {
280
+ console.error(`Error: File not found: ${filePath}`);
281
+ process.exit(1);
282
+ }
283
+
284
+ // Read and parse file
285
+ let data: unknown;
286
+ try {
287
+ const content = readFileSync(filePath, 'utf-8');
288
+ data = JSON.parse(content);
289
+ } catch (parseError) {
290
+ if (options.json) {
291
+ console.log(JSON.stringify({
292
+ valid: false,
293
+ errors: [{
294
+ path: '$',
295
+ message: `Invalid JSON: ${parseError instanceof Error ? parseError.message : 'Parse error'}`,
296
+ }],
297
+ warnings: [],
298
+ }, null, 2));
299
+ } else if (!options.quiet) {
300
+ console.error(`Error: Invalid JSON in ${file}`);
301
+ console.error(parseError instanceof Error ? parseError.message : 'Parse error');
302
+ }
303
+ process.exit(1);
304
+ }
305
+
306
+ // Validate
307
+ const result = validateInferenceMap(data);
308
+
309
+ // Output results
310
+ if (options.json) {
311
+ console.log(JSON.stringify(result, null, 2));
312
+ } else if (!options.quiet) {
313
+ formatResults(result, file);
314
+ }
315
+
316
+ // Exit with appropriate code
317
+ process.exit(result.valid ? 0 : 1);
318
+
319
+ } catch (error) {
320
+ console.error('Error:', error instanceof Error ? error.message : 'Validation failed');
321
+ process.exit(1);
322
+ }
323
+ });
324
+ }