@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.
- package/.claude/settings.local.json +8 -0
- package/.env.example +6 -0
- package/.github/workflows/peakinfer.yml +64 -0
- package/CHANGELOG.md +31 -0
- package/LICENSE +190 -0
- package/README.md +335 -0
- package/data/inferencemax.json +274 -0
- package/dist/agent-analyzer.d.ts +45 -0
- package/dist/agent-analyzer.d.ts.map +1 -0
- package/dist/agent-analyzer.js +374 -0
- package/dist/agent-analyzer.js.map +1 -0
- package/dist/agent.d.ts +76 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +965 -0
- package/dist/agent.js.map +1 -0
- package/dist/agents/correlation-analyzer.d.ts +34 -0
- package/dist/agents/correlation-analyzer.d.ts.map +1 -0
- package/dist/agents/correlation-analyzer.js +261 -0
- package/dist/agents/correlation-analyzer.js.map +1 -0
- package/dist/agents/index.d.ts +91 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/index.js +111 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/runtime-analyzer.d.ts +38 -0
- package/dist/agents/runtime-analyzer.d.ts.map +1 -0
- package/dist/agents/runtime-analyzer.js +244 -0
- package/dist/agents/runtime-analyzer.js.map +1 -0
- package/dist/analysis-types.d.ts +500 -0
- package/dist/analysis-types.d.ts.map +1 -0
- package/dist/analysis-types.js +11 -0
- package/dist/analysis-types.js.map +1 -0
- package/dist/analytics.d.ts +25 -0
- package/dist/analytics.d.ts.map +1 -0
- package/dist/analytics.js +94 -0
- package/dist/analytics.js.map +1 -0
- package/dist/analyzer.d.ts +48 -0
- package/dist/analyzer.d.ts.map +1 -0
- package/dist/analyzer.js +547 -0
- package/dist/analyzer.js.map +1 -0
- package/dist/artifacts.d.ts +44 -0
- package/dist/artifacts.d.ts.map +1 -0
- package/dist/artifacts.js +165 -0
- package/dist/artifacts.js.map +1 -0
- package/dist/benchmarks/index.d.ts +88 -0
- package/dist/benchmarks/index.d.ts.map +1 -0
- package/dist/benchmarks/index.js +205 -0
- package/dist/benchmarks/index.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +427 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/ci.d.ts +19 -0
- package/dist/commands/ci.d.ts.map +1 -0
- package/dist/commands/ci.js +253 -0
- package/dist/commands/ci.js.map +1 -0
- package/dist/commands/config.d.ts +16 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +249 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/demo.d.ts +15 -0
- package/dist/commands/demo.d.ts.map +1 -0
- package/dist/commands/demo.js +106 -0
- package/dist/commands/demo.js.map +1 -0
- package/dist/commands/export.d.ts +14 -0
- package/dist/commands/export.d.ts.map +1 -0
- package/dist/commands/export.js +209 -0
- package/dist/commands/export.js.map +1 -0
- package/dist/commands/history.d.ts +15 -0
- package/dist/commands/history.d.ts.map +1 -0
- package/dist/commands/history.js +389 -0
- package/dist/commands/history.js.map +1 -0
- package/dist/commands/template.d.ts +14 -0
- package/dist/commands/template.d.ts.map +1 -0
- package/dist/commands/template.js +341 -0
- package/dist/commands/template.js.map +1 -0
- package/dist/commands/validate-map.d.ts +12 -0
- package/dist/commands/validate-map.d.ts.map +1 -0
- package/dist/commands/validate-map.js +274 -0
- package/dist/commands/validate-map.js.map +1 -0
- package/dist/commands/whatif.d.ts +17 -0
- package/dist/commands/whatif.d.ts.map +1 -0
- package/dist/commands/whatif.js +206 -0
- package/dist/commands/whatif.js.map +1 -0
- package/dist/comparison.d.ts +38 -0
- package/dist/comparison.d.ts.map +1 -0
- package/dist/comparison.js +223 -0
- package/dist/comparison.js.map +1 -0
- package/dist/config.d.ts +42 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +158 -0
- package/dist/config.js.map +1 -0
- package/dist/connectors/helicone.d.ts +9 -0
- package/dist/connectors/helicone.d.ts.map +1 -0
- package/dist/connectors/helicone.js +106 -0
- package/dist/connectors/helicone.js.map +1 -0
- package/dist/connectors/index.d.ts +37 -0
- package/dist/connectors/index.d.ts.map +1 -0
- package/dist/connectors/index.js +65 -0
- package/dist/connectors/index.js.map +1 -0
- package/dist/connectors/langsmith.d.ts +9 -0
- package/dist/connectors/langsmith.d.ts.map +1 -0
- package/dist/connectors/langsmith.js +122 -0
- package/dist/connectors/langsmith.js.map +1 -0
- package/dist/connectors/types.d.ts +83 -0
- package/dist/connectors/types.d.ts.map +1 -0
- package/dist/connectors/types.js +98 -0
- package/dist/connectors/types.js.map +1 -0
- package/dist/cost-estimator.d.ts +46 -0
- package/dist/cost-estimator.d.ts.map +1 -0
- package/dist/cost-estimator.js +104 -0
- package/dist/cost-estimator.js.map +1 -0
- package/dist/costs.d.ts +57 -0
- package/dist/costs.d.ts.map +1 -0
- package/dist/costs.js +251 -0
- package/dist/costs.js.map +1 -0
- package/dist/counterfactuals.d.ts +29 -0
- package/dist/counterfactuals.d.ts.map +1 -0
- package/dist/counterfactuals.js +448 -0
- package/dist/counterfactuals.js.map +1 -0
- package/dist/enhancement-prompts.d.ts +41 -0
- package/dist/enhancement-prompts.d.ts.map +1 -0
- package/dist/enhancement-prompts.js +88 -0
- package/dist/enhancement-prompts.js.map +1 -0
- package/dist/envelopes.d.ts +20 -0
- package/dist/envelopes.d.ts.map +1 -0
- package/dist/envelopes.js +790 -0
- package/dist/envelopes.js.map +1 -0
- package/dist/format-normalizer.d.ts +71 -0
- package/dist/format-normalizer.d.ts.map +1 -0
- package/dist/format-normalizer.js +1331 -0
- package/dist/format-normalizer.js.map +1 -0
- package/dist/history.d.ts +79 -0
- package/dist/history.d.ts.map +1 -0
- package/dist/history.js +313 -0
- package/dist/history.js.map +1 -0
- package/dist/html.d.ts +11 -0
- package/dist/html.d.ts.map +1 -0
- package/dist/html.js +463 -0
- package/dist/html.js.map +1 -0
- package/dist/impact.d.ts +42 -0
- package/dist/impact.d.ts.map +1 -0
- package/dist/impact.js +443 -0
- package/dist/impact.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/insights.d.ts +5 -0
- package/dist/insights.d.ts.map +1 -0
- package/dist/insights.js +271 -0
- package/dist/insights.js.map +1 -0
- package/dist/joiner.d.ts +9 -0
- package/dist/joiner.d.ts.map +1 -0
- package/dist/joiner.js +247 -0
- package/dist/joiner.js.map +1 -0
- package/dist/orchestrator.d.ts +34 -0
- package/dist/orchestrator.d.ts.map +1 -0
- package/dist/orchestrator.js +827 -0
- package/dist/orchestrator.js.map +1 -0
- package/dist/pdf.d.ts +26 -0
- package/dist/pdf.d.ts.map +1 -0
- package/dist/pdf.js +84 -0
- package/dist/pdf.js.map +1 -0
- package/dist/prediction.d.ts +33 -0
- package/dist/prediction.d.ts.map +1 -0
- package/dist/prediction.js +316 -0
- package/dist/prediction.js.map +1 -0
- package/dist/prompts/loader.d.ts +38 -0
- package/dist/prompts/loader.d.ts.map +1 -0
- package/dist/prompts/loader.js +60 -0
- package/dist/prompts/loader.js.map +1 -0
- package/dist/renderer.d.ts +64 -0
- package/dist/renderer.d.ts.map +1 -0
- package/dist/renderer.js +923 -0
- package/dist/renderer.js.map +1 -0
- package/dist/runid.d.ts +57 -0
- package/dist/runid.d.ts.map +1 -0
- package/dist/runid.js +199 -0
- package/dist/runid.js.map +1 -0
- package/dist/runtime.d.ts +29 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +366 -0
- package/dist/runtime.js.map +1 -0
- package/dist/scanner.d.ts +11 -0
- package/dist/scanner.d.ts.map +1 -0
- package/dist/scanner.js +426 -0
- package/dist/scanner.js.map +1 -0
- package/dist/templates.d.ts +120 -0
- package/dist/templates.d.ts.map +1 -0
- package/dist/templates.js +429 -0
- package/dist/templates.js.map +1 -0
- package/dist/tools/index.d.ts +153 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +177 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/types.d.ts +3647 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +703 -0
- package/dist/types.js.map +1 -0
- package/dist/version.d.ts +7 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +23 -0
- package/dist/version.js.map +1 -0
- package/docs/demo-guide.md +423 -0
- package/docs/events-format.md +295 -0
- package/docs/inferencemap-spec.md +344 -0
- package/docs/migration-v2.md +293 -0
- package/fixtures/demo/precomputed.json +142 -0
- package/fixtures/demo-project/README.md +52 -0
- package/fixtures/demo-project/ai-service.ts +65 -0
- package/fixtures/demo-project/sample-events.jsonl +15 -0
- package/fixtures/demo-project/src/ai-service.ts +128 -0
- package/fixtures/demo-project/src/llm-client.ts +155 -0
- package/package.json +65 -0
- package/prompts/agent-analyzer.yaml +47 -0
- package/prompts/ci-gate.yaml +98 -0
- package/prompts/correlation-analyzer.yaml +178 -0
- package/prompts/format-normalizer.yaml +46 -0
- package/prompts/peak-performance.yaml +180 -0
- package/prompts/pr-comment.yaml +111 -0
- package/prompts/runtime-analyzer.yaml +189 -0
- package/prompts/unified-analyzer.yaml +241 -0
- package/schemas/inference-map.v0.1.json +215 -0
- package/scripts/benchmark.ts +394 -0
- package/scripts/demo-v1.5.sh +158 -0
- package/scripts/sync-from-site.sh +197 -0
- package/scripts/validate-sync.sh +178 -0
- package/src/agent-analyzer.ts +481 -0
- package/src/agent.ts +1232 -0
- package/src/agents/correlation-analyzer.ts +353 -0
- package/src/agents/index.ts +235 -0
- package/src/agents/runtime-analyzer.ts +343 -0
- package/src/analysis-types.ts +558 -0
- package/src/analytics.ts +100 -0
- package/src/analyzer.ts +692 -0
- package/src/artifacts.ts +218 -0
- package/src/benchmarks/index.ts +309 -0
- package/src/cli.ts +503 -0
- package/src/commands/ci.ts +336 -0
- package/src/commands/config.ts +288 -0
- package/src/commands/demo.ts +175 -0
- package/src/commands/export.ts +297 -0
- package/src/commands/history.ts +425 -0
- package/src/commands/template.ts +385 -0
- package/src/commands/validate-map.ts +324 -0
- package/src/commands/whatif.ts +272 -0
- package/src/comparison.ts +283 -0
- package/src/config.ts +188 -0
- package/src/connectors/helicone.ts +164 -0
- package/src/connectors/index.ts +93 -0
- package/src/connectors/langsmith.ts +179 -0
- package/src/connectors/types.ts +180 -0
- package/src/cost-estimator.ts +146 -0
- package/src/costs.ts +347 -0
- package/src/counterfactuals.ts +516 -0
- package/src/enhancement-prompts.ts +118 -0
- package/src/envelopes.ts +814 -0
- package/src/format-normalizer.ts +1486 -0
- package/src/history.ts +400 -0
- package/src/html.ts +512 -0
- package/src/impact.ts +522 -0
- package/src/index.ts +83 -0
- package/src/insights.ts +341 -0
- package/src/joiner.ts +289 -0
- package/src/orchestrator.ts +1015 -0
- package/src/pdf.ts +110 -0
- package/src/prediction.ts +392 -0
- package/src/prompts/loader.ts +88 -0
- package/src/renderer.ts +1045 -0
- package/src/runid.ts +261 -0
- package/src/runtime.ts +450 -0
- package/src/scanner.ts +508 -0
- package/src/templates.ts +561 -0
- package/src/tools/index.ts +214 -0
- package/src/types.ts +873 -0
- package/src/version.ts +24 -0
- package/templates/context-accumulation.yaml +23 -0
- package/templates/cost-concentration.yaml +20 -0
- package/templates/dead-code.yaml +20 -0
- package/templates/latency-explainer.yaml +23 -0
- package/templates/optimizations/ab-testing-framework.yaml +74 -0
- package/templates/optimizations/api-gateway-optimization.yaml +81 -0
- package/templates/optimizations/api-model-routing-strategy.yaml +126 -0
- package/templates/optimizations/auto-scaling-optimization.yaml +85 -0
- package/templates/optimizations/batch-utilization-diagnostic.yaml +142 -0
- package/templates/optimizations/comprehensive-apm.yaml +76 -0
- package/templates/optimizations/context-window-optimization.yaml +91 -0
- package/templates/optimizations/cost-sensitive-batch-processing.yaml +77 -0
- package/templates/optimizations/distributed-training-optimization.yaml +77 -0
- package/templates/optimizations/document-analysis-edge.yaml +77 -0
- package/templates/optimizations/document-pipeline-optimization.yaml +78 -0
- package/templates/optimizations/domain-specific-distillation.yaml +78 -0
- package/templates/optimizations/error-handling-optimization.yaml +76 -0
- package/templates/optimizations/gptq-4bit-quantization.yaml +96 -0
- package/templates/optimizations/long-context-memory-management.yaml +78 -0
- package/templates/optimizations/max-tokens-optimization.yaml +76 -0
- package/templates/optimizations/memory-bandwidth-optimization.yaml +73 -0
- package/templates/optimizations/multi-framework-resilience.yaml +75 -0
- package/templates/optimizations/multi-tenant-optimization.yaml +75 -0
- package/templates/optimizations/prompt-caching-optimization.yaml +143 -0
- package/templates/optimizations/pytorch-to-onnx-migration.yaml +109 -0
- package/templates/optimizations/quality-monitoring.yaml +74 -0
- package/templates/optimizations/realtime-budget-controls.yaml +74 -0
- package/templates/optimizations/realtime-latency-optimization.yaml +74 -0
- package/templates/optimizations/sglang-concurrency-optimization.yaml +78 -0
- package/templates/optimizations/smart-model-routing.yaml +96 -0
- package/templates/optimizations/streaming-batch-selection.yaml +167 -0
- package/templates/optimizations/system-prompt-optimization.yaml +75 -0
- package/templates/optimizations/tensorrt-llm-performance.yaml +77 -0
- package/templates/optimizations/vllm-high-throughput-optimization.yaml +93 -0
- package/templates/optimizations/vllm-migration-memory-bound.yaml +78 -0
- package/templates/overpowered-extraction.yaml +32 -0
- package/templates/overpowered-model.yaml +31 -0
- package/templates/prompt-bloat.yaml +24 -0
- package/templates/retry-explosion.yaml +28 -0
- package/templates/schema/insight.schema.json +113 -0
- package/templates/schema/optimization.schema.json +180 -0
- package/templates/streaming-drift.yaml +30 -0
- package/templates/throughput-gap.yaml +21 -0
- package/templates/token-underutilization.yaml +28 -0
- package/templates/untested-fallback.yaml +21 -0
- package/tests/accuracy/drift-detection.test.ts +184 -0
- package/tests/accuracy/false-positives.test.ts +166 -0
- package/tests/accuracy/templates.test.ts +205 -0
- package/tests/action/commands.test.ts +125 -0
- package/tests/action/comments.test.ts +347 -0
- package/tests/cli.test.ts +203 -0
- package/tests/comparison.test.ts +309 -0
- package/tests/correlation-analyzer.test.ts +534 -0
- package/tests/counterfactuals.test.ts +347 -0
- package/tests/fixtures/events/missing-id.jsonl +1 -0
- package/tests/fixtures/events/missing-input.jsonl +1 -0
- package/tests/fixtures/events/missing-latency.jsonl +1 -0
- package/tests/fixtures/events/missing-model.jsonl +1 -0
- package/tests/fixtures/events/missing-output.jsonl +1 -0
- package/tests/fixtures/events/missing-provider.jsonl +1 -0
- package/tests/fixtures/events/missing-ts.jsonl +1 -0
- package/tests/fixtures/events/valid.csv +3 -0
- package/tests/fixtures/events/valid.json +1 -0
- package/tests/fixtures/events/valid.jsonl +2 -0
- package/tests/fixtures/events/with-callsite.jsonl +1 -0
- package/tests/fixtures/events/with-intent.jsonl +1 -0
- package/tests/fixtures/events/wrong-type.jsonl +1 -0
- package/tests/fixtures/repos/empty/.gitkeep +0 -0
- package/tests/fixtures/repos/hybrid-router/router.py +35 -0
- package/tests/fixtures/repos/saas-anthropic/agent.ts +27 -0
- package/tests/fixtures/repos/saas-openai/assistant.js +33 -0
- package/tests/fixtures/repos/saas-openai/client.py +26 -0
- package/tests/fixtures/repos/self-hosted-vllm/inference.py +22 -0
- package/tests/github-action.test.ts +292 -0
- package/tests/insights.test.ts +878 -0
- package/tests/joiner.test.ts +168 -0
- package/tests/performance/action-latency.test.ts +132 -0
- package/tests/performance/benchmark.test.ts +189 -0
- package/tests/performance/cli-latency.test.ts +102 -0
- package/tests/pr-comment.test.ts +313 -0
- package/tests/prediction.test.ts +296 -0
- package/tests/runtime-analyzer.test.ts +375 -0
- package/tests/runtime.test.ts +205 -0
- package/tests/scanner.test.ts +122 -0
- package/tests/template-conformance.test.ts +526 -0
- package/tests/unit/cost-calculator.test.ts +303 -0
- package/tests/unit/credits.test.ts +180 -0
- package/tests/unit/inference-map.test.ts +276 -0
- package/tests/unit/schema.test.ts +300 -0
- package/tsconfig.json +20 -0
- package/vitest.config.ts +14 -0
package/src/cli.ts
ADDED
|
@@ -0,0 +1,503 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import 'dotenv/config';
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import { existsSync, writeFileSync } from 'fs';
|
|
5
|
+
import { exec } from 'child_process';
|
|
6
|
+
import * as readline from 'readline';
|
|
7
|
+
import { Agent } from './agent.js';
|
|
8
|
+
import { createRenderer, renderCostEstimate, renderMaxCostExceeded } from './renderer.js';
|
|
9
|
+
import { estimateAnalysisCost, exceedsMaxCost } from './cost-estimator.js';
|
|
10
|
+
import { VERSION } from './version.js';
|
|
11
|
+
|
|
12
|
+
// v1.6 Command imports
|
|
13
|
+
import { registerTemplateCommands } from './commands/template.js';
|
|
14
|
+
import { registerConfigCommands } from './commands/config.js';
|
|
15
|
+
import { registerHistoryCommands } from './commands/history.js';
|
|
16
|
+
import { registerCICommand } from './commands/ci.js';
|
|
17
|
+
import { registerExportCommand } from './commands/export.js';
|
|
18
|
+
import { registerWhatIfCommand } from './commands/whatif.js';
|
|
19
|
+
|
|
20
|
+
// v2.0 Demo command (works offline, no API key needed)
|
|
21
|
+
import { registerDemoCommand } from './commands/demo.js';
|
|
22
|
+
|
|
23
|
+
// v1.9.3 Validate-map command (InferenceMap schema validation)
|
|
24
|
+
import { registerValidateMapCommand } from './commands/validate-map.js';
|
|
25
|
+
|
|
26
|
+
// v1.8 Analytics (respects DO_NOT_TRACK)
|
|
27
|
+
import { initAnalytics, track, flush } from './analytics.js';
|
|
28
|
+
|
|
29
|
+
// Initialize analytics at startup
|
|
30
|
+
initAnalytics();
|
|
31
|
+
|
|
32
|
+
// =============================================================================
|
|
33
|
+
// CONSTANTS
|
|
34
|
+
// =============================================================================
|
|
35
|
+
|
|
36
|
+
const DESCRIPTION = 'llm inference performance optimization';
|
|
37
|
+
|
|
38
|
+
// =============================================================================
|
|
39
|
+
// MAIN
|
|
40
|
+
// =============================================================================
|
|
41
|
+
|
|
42
|
+
const program = new Command()
|
|
43
|
+
.name('peakinfer')
|
|
44
|
+
.description(DESCRIPTION)
|
|
45
|
+
.version(VERSION);
|
|
46
|
+
|
|
47
|
+
// Analyze command: peakinfer analyze <path>
|
|
48
|
+
program
|
|
49
|
+
.command('analyze')
|
|
50
|
+
.description('analyze codebase or runtime events')
|
|
51
|
+
.argument('[path]', 'path to repository or events file', '.')
|
|
52
|
+
.option('--events <file>', 'add runtime telemetry to static analysis')
|
|
53
|
+
.option('--events-url <url>', 'URL to fetch runtime events')
|
|
54
|
+
.option('--html', 'generate html report')
|
|
55
|
+
.option('--pdf', 'generate pdf report')
|
|
56
|
+
.option('--open', 'open report in browser/viewer')
|
|
57
|
+
.option('--output <format>', 'output format: text (default), json, or inference-map')
|
|
58
|
+
.option('--out <file>', 'write output to file')
|
|
59
|
+
.option('--cached', 'view previous analysis (offline, no API key needed)')
|
|
60
|
+
.option('--verbose', 'show detailed task progress')
|
|
61
|
+
// Format detection options (PRD §6.4)
|
|
62
|
+
.option('--format <type>', 'specify runtime format: jsonl, json, csv, otel, jaeger, zipkin, langsmith, litellm')
|
|
63
|
+
.option('--map <mappings...>', 'field mappings: --map latency_ms=duration model=model_name')
|
|
64
|
+
.option('--events-map <mappings...>', 'alias for --map (field mappings for non-standard event formats)')
|
|
65
|
+
.option('--lenient', 'accept low-confidence field mappings')
|
|
66
|
+
.option('--strict', 'fail on missing required fields or unknown formats')
|
|
67
|
+
.option('--redact', 'redact code snippets from artifacts')
|
|
68
|
+
// Fix suggestions (v1.8)
|
|
69
|
+
.option('--fixes', 'show code fix suggestions for issues')
|
|
70
|
+
// Runtime connectors (v1.9.5)
|
|
71
|
+
.option('--runtime <source>', 'runtime data source: helicone, langsmith')
|
|
72
|
+
.option('--runtime-key <key>', 'API key for runtime source (or use env var)')
|
|
73
|
+
.option('--runtime-days <days>', 'days of runtime data to fetch', '7')
|
|
74
|
+
// Benchmark comparison (v1.9.5)
|
|
75
|
+
.option('--benchmark', 'compare to InferenceMAX benchmarks')
|
|
76
|
+
// Cost estimation options (v1.9.3)
|
|
77
|
+
.option('--estimate', 'show cost estimate before analysis')
|
|
78
|
+
.option('--yes', 'auto-proceed without confirmation (use with --estimate)')
|
|
79
|
+
.option('--max-cost <dollars>', 'skip analysis if estimated cost exceeds threshold')
|
|
80
|
+
// History options (v1.5)
|
|
81
|
+
.option('--no-history', 'skip saving run to history (disables comparison/prediction)')
|
|
82
|
+
.option('--compare [runId]', 'compare with previous run (default: latest)')
|
|
83
|
+
.option('--predict', 'generate deploy-time latency predictions')
|
|
84
|
+
.option('--target-p95 <ms>', 'target p95 latency for budget calculation (use with --predict)')
|
|
85
|
+
.action(async (path: string, options: {
|
|
86
|
+
events?: string;
|
|
87
|
+
eventsUrl?: string; // --events-url
|
|
88
|
+
html?: boolean;
|
|
89
|
+
pdf?: boolean;
|
|
90
|
+
open?: boolean;
|
|
91
|
+
output?: string;
|
|
92
|
+
out?: string; // --out
|
|
93
|
+
cached?: boolean;
|
|
94
|
+
verbose?: boolean;
|
|
95
|
+
// Format detection options
|
|
96
|
+
format?: string;
|
|
97
|
+
map?: string[];
|
|
98
|
+
eventsMap?: string[]; // --events-map alias for --map
|
|
99
|
+
lenient?: boolean;
|
|
100
|
+
strict?: boolean;
|
|
101
|
+
redact?: boolean;
|
|
102
|
+
// Fix suggestions (v1.8)
|
|
103
|
+
fixes?: boolean;
|
|
104
|
+
// Runtime connectors (v1.9.5)
|
|
105
|
+
runtime?: string;
|
|
106
|
+
runtimeKey?: string;
|
|
107
|
+
runtimeDays?: string;
|
|
108
|
+
// Benchmark comparison (v1.9.5)
|
|
109
|
+
benchmark?: boolean;
|
|
110
|
+
// Cost estimation options (v1.9.3)
|
|
111
|
+
estimate?: boolean;
|
|
112
|
+
yes?: boolean;
|
|
113
|
+
maxCost?: string;
|
|
114
|
+
// History options (v1.5)
|
|
115
|
+
history?: boolean; // Commander negates --no-history to history: false
|
|
116
|
+
compare?: string | boolean; // --compare or --compare <runId>
|
|
117
|
+
predict?: boolean; // --predict flag
|
|
118
|
+
targetP95?: string; // --target-p95 <ms>
|
|
119
|
+
}) => {
|
|
120
|
+
try {
|
|
121
|
+
// Validate path exists
|
|
122
|
+
if (!existsSync(path)) {
|
|
123
|
+
console.error(`Error: Path not found: ${path}`);
|
|
124
|
+
process.exit(1);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Validate events file if provided
|
|
128
|
+
if (options.events && !existsSync(options.events)) {
|
|
129
|
+
console.error(`Error: Events file not found: ${options.events}`);
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Cost estimation (v1.9.3) - PRD Section 2.3
|
|
134
|
+
// Handle --estimate and --max-cost before running analysis
|
|
135
|
+
const maxCost = options.maxCost ? parseFloat(options.maxCost) : undefined;
|
|
136
|
+
|
|
137
|
+
if (options.estimate || maxCost !== undefined) {
|
|
138
|
+
try {
|
|
139
|
+
const estimate = await estimateAnalysisCost(path);
|
|
140
|
+
|
|
141
|
+
// Check --max-cost threshold first
|
|
142
|
+
if (maxCost !== undefined && exceedsMaxCost(estimate, maxCost)) {
|
|
143
|
+
renderMaxCostExceeded(estimate, maxCost);
|
|
144
|
+
process.exit(0); // Exit gracefully, not an error
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Show estimate if --estimate flag is used
|
|
148
|
+
if (options.estimate) {
|
|
149
|
+
renderCostEstimate(estimate);
|
|
150
|
+
|
|
151
|
+
// If --yes flag, auto-proceed
|
|
152
|
+
if (!options.yes) {
|
|
153
|
+
// Prompt user for confirmation
|
|
154
|
+
const proceed = await promptUserConfirmation('Proceed? [y/N] ');
|
|
155
|
+
if (!proceed) {
|
|
156
|
+
console.log('Analysis cancelled.');
|
|
157
|
+
process.exit(0);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
} catch (error) {
|
|
162
|
+
// If estimation fails, warn but continue (don't block analysis)
|
|
163
|
+
if (options.verbose) {
|
|
164
|
+
console.warn(`Warning: Cost estimation failed: ${error instanceof Error ? error.message : 'unknown error'}`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const renderer = createRenderer({ verbose: options.verbose, showFixes: options.fixes });
|
|
170
|
+
renderer.renderHeader();
|
|
171
|
+
|
|
172
|
+
// Track analysis start (v1.8)
|
|
173
|
+
track('analysis_started', {
|
|
174
|
+
has_events: !!options.events,
|
|
175
|
+
has_runtime: !!options.runtime,
|
|
176
|
+
runtime_source: options.runtime,
|
|
177
|
+
has_benchmark: !!options.benchmark,
|
|
178
|
+
html: options.html,
|
|
179
|
+
pdf: options.pdf,
|
|
180
|
+
predict: options.predict,
|
|
181
|
+
compare: options.compare !== undefined,
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
const agent = new Agent({
|
|
185
|
+
onResumed: (runId) => renderer.renderResumed(runId),
|
|
186
|
+
onPlanReady: (plan) => renderer.renderPlan(plan),
|
|
187
|
+
onTaskStart: (task) => renderer.renderTaskStart(task),
|
|
188
|
+
onTaskComplete: (task, result) => renderer.renderTaskComplete(task, result),
|
|
189
|
+
onProgress: (data) => renderer.renderProgress(data),
|
|
190
|
+
onPartial: (warnings) => renderer.renderPartial(warnings),
|
|
191
|
+
onComplete: (results) => {
|
|
192
|
+
// Handle --output inference-map: output only InferenceMap JSON
|
|
193
|
+
if (options.output === 'inference-map') {
|
|
194
|
+
if (!results.inferenceMap) {
|
|
195
|
+
console.error('No InferenceMap data available');
|
|
196
|
+
process.exit(1);
|
|
197
|
+
}
|
|
198
|
+
const output = JSON.stringify(results.inferenceMap, null, 2);
|
|
199
|
+
if (options.out) {
|
|
200
|
+
writeFileSync(options.out, output);
|
|
201
|
+
console.error(`InferenceMap written to ${options.out}`);
|
|
202
|
+
} else {
|
|
203
|
+
console.log(output);
|
|
204
|
+
}
|
|
205
|
+
} else if (options.output === 'json') {
|
|
206
|
+
// Handle --output json: output full results as JSON
|
|
207
|
+
const output = JSON.stringify({
|
|
208
|
+
inferenceMap: results.inferenceMap,
|
|
209
|
+
insights: results.insights,
|
|
210
|
+
runtime: results.runtimeSummary,
|
|
211
|
+
joined: results.joined,
|
|
212
|
+
}, null, 2);
|
|
213
|
+
if (options.out) {
|
|
214
|
+
writeFileSync(options.out, output);
|
|
215
|
+
console.error(`Results written to ${options.out}`);
|
|
216
|
+
} else {
|
|
217
|
+
console.log(output);
|
|
218
|
+
}
|
|
219
|
+
} else {
|
|
220
|
+
// Default: render text output
|
|
221
|
+
renderer.renderResults(results);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Benchmark comparison (v1.9.5)
|
|
225
|
+
// Note: Requires runtime events with latency data to compare against benchmarks
|
|
226
|
+
if (options.benchmark && results.inferenceMap?.callsites) {
|
|
227
|
+
import('./benchmarks/index.js').then(({ compareToBenchmark, formatBenchmarkComparison }) => {
|
|
228
|
+
console.log('\n' + '─'.repeat(60));
|
|
229
|
+
console.log('\nBENCHMARK COMPARISON (InferenceMAX)');
|
|
230
|
+
console.log('');
|
|
231
|
+
|
|
232
|
+
let hasComparisons = false;
|
|
233
|
+
for (const point of results.inferenceMap!.callsites) {
|
|
234
|
+
// Static analysis provides model info; latency requires runtime events
|
|
235
|
+
if (point.model) {
|
|
236
|
+
const comparison = compareToBenchmark(
|
|
237
|
+
point.id,
|
|
238
|
+
point.model,
|
|
239
|
+
{} // Latency data comes from runtime events
|
|
240
|
+
);
|
|
241
|
+
if (comparison) {
|
|
242
|
+
hasComparisons = true;
|
|
243
|
+
console.log(`[${point.file}:${point.line}]`);
|
|
244
|
+
console.log(formatBenchmarkComparison(comparison));
|
|
245
|
+
console.log('');
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (!hasComparisons) {
|
|
251
|
+
console.log('No benchmark data available for the detected models.');
|
|
252
|
+
console.log('Tip: Benchmarks are available for GPT-4o, Claude 3.5, Gemini, Llama, Mistral, etc.');
|
|
253
|
+
}
|
|
254
|
+
}).catch(() => {
|
|
255
|
+
console.error('Warning: Could not load benchmark data');
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Track analysis completion (v1.8)
|
|
260
|
+
track('analysis_completed', {
|
|
261
|
+
inference_points: results.inferenceMap?.summary?.totalCallsites || 0,
|
|
262
|
+
insights_count: results.insights?.length || 0,
|
|
263
|
+
has_runtime: !!results.events,
|
|
264
|
+
providers: results.inferenceMap?.summary?.providers || [],
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
// Open report if requested (prefer PDF if generated, else HTML)
|
|
268
|
+
if (options.open) {
|
|
269
|
+
if (results.pdfPath) {
|
|
270
|
+
openInBrowser(results.pdfPath);
|
|
271
|
+
} else if (results.htmlPath) {
|
|
272
|
+
openInBrowser(results.htmlPath);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
onError: (error) => renderer.renderError(error),
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
// Parse field mappings from --map or --events-map option
|
|
280
|
+
// (--events-map is an alias for --map, consistent with GitHub Action input naming)
|
|
281
|
+
const fieldHints: Record<string, string> = {};
|
|
282
|
+
// Merge if both are provided (--map takes precedence for conflicts)
|
|
283
|
+
if (options.eventsMap) {
|
|
284
|
+
for (const mapping of options.eventsMap) {
|
|
285
|
+
const [target, source] = mapping.split('=');
|
|
286
|
+
if (target && source) {
|
|
287
|
+
fieldHints[target.trim()] = source.trim();
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
if (options.map) {
|
|
292
|
+
for (const mapping of options.map) {
|
|
293
|
+
const [target, source] = mapping.split('=');
|
|
294
|
+
if (target && source) {
|
|
295
|
+
fieldHints[target.trim()] = source.trim();
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Runtime connector integration (v1.9.5)
|
|
301
|
+
// If --runtime is provided, fetch events from the API
|
|
302
|
+
let runtimeEventsFile = options.events;
|
|
303
|
+
let runtimeResult: { events: unknown[]; summary: unknown } | undefined;
|
|
304
|
+
|
|
305
|
+
if (options.runtime) {
|
|
306
|
+
const { fetchRuntimeData, getApiKeyFromEnv, isValidSource } = await import('./connectors/index.js');
|
|
307
|
+
|
|
308
|
+
if (!isValidSource(options.runtime)) {
|
|
309
|
+
console.error(`Error: Unknown runtime source: ${options.runtime}. Supported: helicone, langsmith`);
|
|
310
|
+
process.exit(1);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const apiKey = options.runtimeKey || getApiKeyFromEnv(options.runtime);
|
|
314
|
+
if (!apiKey) {
|
|
315
|
+
const envVarName = options.runtime === 'helicone' ? 'HELICONE_API_KEY' : 'LANGSMITH_API_KEY';
|
|
316
|
+
console.error(`Error: API key required for --runtime ${options.runtime}`);
|
|
317
|
+
console.error(`Provide via --runtime-key or set ${envVarName} environment variable`);
|
|
318
|
+
process.exit(1);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
try {
|
|
322
|
+
const days = parseInt(options.runtimeDays || '7', 10);
|
|
323
|
+
const startDate = new Date();
|
|
324
|
+
startDate.setDate(startDate.getDate() - days);
|
|
325
|
+
|
|
326
|
+
if (options.verbose) {
|
|
327
|
+
console.log(`Fetching runtime data from ${options.runtime} (last ${days} days)...`);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
runtimeResult = await fetchRuntimeData({
|
|
331
|
+
source: options.runtime,
|
|
332
|
+
apiKey,
|
|
333
|
+
startDate: startDate.toISOString(),
|
|
334
|
+
limit: 1000,
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
if (options.verbose) {
|
|
338
|
+
console.log(`Fetched ${runtimeResult.events.length} events from ${options.runtime}`);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Write events to a temp file for the agent
|
|
342
|
+
const { tmpdir } = await import('os');
|
|
343
|
+
const { join } = await import('path');
|
|
344
|
+
const tempFile = join(tmpdir(), `peakinfer-runtime-${Date.now()}.jsonl`);
|
|
345
|
+
const eventsJsonl = (runtimeResult.events as unknown[]).map(e => JSON.stringify(e)).join('\n');
|
|
346
|
+
writeFileSync(tempFile, eventsJsonl);
|
|
347
|
+
runtimeEventsFile = tempFile;
|
|
348
|
+
} catch (error) {
|
|
349
|
+
console.error(`Error fetching from ${options.runtime}: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
350
|
+
process.exit(1);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
await agent.run({
|
|
355
|
+
path,
|
|
356
|
+
events: runtimeEventsFile,
|
|
357
|
+
eventsUrl: options.eventsUrl, // --events-url
|
|
358
|
+
html: options.html || options.pdf || options.open, // Generate HTML if PDF or open requested
|
|
359
|
+
pdf: options.pdf,
|
|
360
|
+
open: options.open,
|
|
361
|
+
out: options.out, // --out
|
|
362
|
+
offline: false,
|
|
363
|
+
noCache: !options.cached, // --cached means use cache
|
|
364
|
+
verbose: options.verbose,
|
|
365
|
+
// Format detection options
|
|
366
|
+
formatHint: options.format,
|
|
367
|
+
fieldHints: Object.keys(fieldHints).length > 0 ? fieldHints : undefined,
|
|
368
|
+
lenient: options.lenient,
|
|
369
|
+
strict: options.strict,
|
|
370
|
+
redact: options.redact,
|
|
371
|
+
// History options (v1.5)
|
|
372
|
+
noHistory: options.history === false, // --no-history sets history to false
|
|
373
|
+
compare: options.compare !== undefined, // --compare flag was used
|
|
374
|
+
compareRunId: typeof options.compare === 'string' ? options.compare : undefined, // specific run ID
|
|
375
|
+
predict: options.predict, // --predict flag
|
|
376
|
+
targetP95: options.targetP95 ? parseInt(options.targetP95, 10) : undefined, // --target-p95 <ms>
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
// Flush analytics before exit (v1.8)
|
|
380
|
+
await flush();
|
|
381
|
+
} catch (error) {
|
|
382
|
+
// Track error and flush analytics (v1.8)
|
|
383
|
+
track('analysis_error', {
|
|
384
|
+
error_type: error instanceof Error ? error.constructor.name : 'unknown',
|
|
385
|
+
});
|
|
386
|
+
await flush();
|
|
387
|
+
|
|
388
|
+
if (error instanceof Error) {
|
|
389
|
+
console.error(`Error: ${error.message}`);
|
|
390
|
+
if (options.verbose && error.stack) {
|
|
391
|
+
console.error(error.stack);
|
|
392
|
+
}
|
|
393
|
+
} else {
|
|
394
|
+
console.error('An unexpected error occurred');
|
|
395
|
+
}
|
|
396
|
+
process.exit(1);
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
// =============================================================================
|
|
401
|
+
// REGISTER v1.6 COMMANDS
|
|
402
|
+
// =============================================================================
|
|
403
|
+
|
|
404
|
+
registerTemplateCommands(program);
|
|
405
|
+
registerConfigCommands(program);
|
|
406
|
+
registerHistoryCommands(program);
|
|
407
|
+
registerCICommand(program);
|
|
408
|
+
registerExportCommand(program);
|
|
409
|
+
registerWhatIfCommand(program);
|
|
410
|
+
|
|
411
|
+
// =============================================================================
|
|
412
|
+
// REGISTER v2.0 COMMANDS
|
|
413
|
+
// =============================================================================
|
|
414
|
+
|
|
415
|
+
registerDemoCommand(program);
|
|
416
|
+
|
|
417
|
+
// =============================================================================
|
|
418
|
+
// REGISTER v1.9.3 COMMANDS
|
|
419
|
+
// =============================================================================
|
|
420
|
+
|
|
421
|
+
registerValidateMapCommand(program);
|
|
422
|
+
|
|
423
|
+
// Custom help text (PRD-aligned, Julie Zhou style)
|
|
424
|
+
program.addHelpText('after', `
|
|
425
|
+
quick start:
|
|
426
|
+
peakinfer demo # see it in action (no API key needed)
|
|
427
|
+
peakinfer analyze . # analyze your codebase
|
|
428
|
+
|
|
429
|
+
analyze modes:
|
|
430
|
+
peakinfer analyze . # static: scan codebase for LLM calls
|
|
431
|
+
peakinfer analyze events.jsonl # runtime: analyze inference telemetry
|
|
432
|
+
peakinfer analyze . --events prod.jsonl # combined: static + runtime
|
|
433
|
+
peakinfer analyze . --events-url https://api.example.com/events # fetch events from URL
|
|
434
|
+
peakinfer analyze . --out results.json # write output to file
|
|
435
|
+
peakinfer analyze . --output inference-map # output only InferenceMap v0.1 JSON
|
|
436
|
+
|
|
437
|
+
runtime connectors (v1.9.5):
|
|
438
|
+
peakinfer analyze . --runtime helicone # fetch from Helicone
|
|
439
|
+
peakinfer analyze . --runtime langsmith # fetch from LangSmith
|
|
440
|
+
peakinfer analyze . --runtime helicone --runtime-days 30 # last 30 days
|
|
441
|
+
|
|
442
|
+
benchmarks (v1.9.5):
|
|
443
|
+
peakinfer analyze . --benchmark # compare to InferenceMAX benchmarks
|
|
444
|
+
|
|
445
|
+
cost estimation:
|
|
446
|
+
peakinfer analyze . --estimate # show cost estimate before analysis
|
|
447
|
+
peakinfer analyze . --estimate --yes # estimate + auto-proceed (for CI)
|
|
448
|
+
peakinfer analyze . --max-cost 10 # skip if estimated cost > $10
|
|
449
|
+
|
|
450
|
+
more commands:
|
|
451
|
+
peakinfer template list # browse optimization templates
|
|
452
|
+
peakinfer config show # view configuration
|
|
453
|
+
peakinfer history # view analysis history
|
|
454
|
+
peakinfer history compare <id1> [id2] # compare two analysis runs
|
|
455
|
+
peakinfer export # export results (json, prometheus)
|
|
456
|
+
peakinfer whatif --model gpt-4o-mini # counterfactual analysis
|
|
457
|
+
peakinfer ci ./src --baseline base.json # CI/CD integration
|
|
458
|
+
peakinfer validate-map ./map.json # validate InferenceMap schema
|
|
459
|
+
`);
|
|
460
|
+
|
|
461
|
+
// Parse and run
|
|
462
|
+
program.parse();
|
|
463
|
+
|
|
464
|
+
// =============================================================================
|
|
465
|
+
// HELPERS
|
|
466
|
+
// =============================================================================
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Prompt user for Y/N confirmation.
|
|
470
|
+
* Returns true if user enters 'y' or 'Y', false otherwise.
|
|
471
|
+
*/
|
|
472
|
+
function promptUserConfirmation(prompt: string): Promise<boolean> {
|
|
473
|
+
return new Promise((resolve) => {
|
|
474
|
+
const rl = readline.createInterface({
|
|
475
|
+
input: process.stdin,
|
|
476
|
+
output: process.stdout,
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
rl.question(prompt, (answer) => {
|
|
480
|
+
rl.close();
|
|
481
|
+
resolve(answer.toLowerCase() === 'y');
|
|
482
|
+
});
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
function openInBrowser(filePath: string): void {
|
|
487
|
+
const platform = process.platform;
|
|
488
|
+
let command: string;
|
|
489
|
+
|
|
490
|
+
if (platform === 'darwin') {
|
|
491
|
+
command = `open "${filePath}"`;
|
|
492
|
+
} else if (platform === 'win32') {
|
|
493
|
+
command = `start "" "${filePath}"`;
|
|
494
|
+
} else {
|
|
495
|
+
command = `xdg-open "${filePath}"`;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
exec(command, (error) => {
|
|
499
|
+
if (error) {
|
|
500
|
+
console.error(`Could not open browser: ${error.message}`);
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
}
|