@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
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* History Commands (v1.6)
|
|
3
|
+
*
|
|
4
|
+
* CLI commands for viewing and managing analysis history:
|
|
5
|
+
* - list: List past analysis runs
|
|
6
|
+
* - show: Show details of a specific run
|
|
7
|
+
* - export: Export history to JSON
|
|
8
|
+
* - prune: Remove old runs
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { Command } from 'commander';
|
|
12
|
+
import { writeFileSync } from 'fs';
|
|
13
|
+
import { listRuns, loadRun, pruneHistory, getHistoryDir, deleteRun, clearAllHistory } from '../history.js';
|
|
14
|
+
import { compareSnapshots, formatComparisonSummary, hasSignificantChanges, type AnalysisSnapshot } from '../comparison.js';
|
|
15
|
+
import type { HistoryManifest } from '../types.js';
|
|
16
|
+
|
|
17
|
+
// =============================================================================
|
|
18
|
+
// HELPERS
|
|
19
|
+
// =============================================================================
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Format timestamp for display
|
|
23
|
+
*/
|
|
24
|
+
function formatTimestamp(iso: string): string {
|
|
25
|
+
const date = new Date(iso);
|
|
26
|
+
return date.toLocaleString();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Format relative time
|
|
31
|
+
*/
|
|
32
|
+
function formatRelativeTime(iso: string): string {
|
|
33
|
+
const date = new Date(iso);
|
|
34
|
+
const now = new Date();
|
|
35
|
+
const diffMs = now.getTime() - date.getTime();
|
|
36
|
+
|
|
37
|
+
const seconds = Math.floor(diffMs / 1000);
|
|
38
|
+
const minutes = Math.floor(seconds / 60);
|
|
39
|
+
const hours = Math.floor(minutes / 60);
|
|
40
|
+
const days = Math.floor(hours / 24);
|
|
41
|
+
|
|
42
|
+
if (days > 0) return `${days}d ago`;
|
|
43
|
+
if (hours > 0) return `${hours}h ago`;
|
|
44
|
+
if (minutes > 0) return `${minutes}m ago`;
|
|
45
|
+
return 'just now';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Format analysis type with indicator
|
|
50
|
+
*/
|
|
51
|
+
function formatAnalysisType(type: string): string {
|
|
52
|
+
return type;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Display history list
|
|
57
|
+
*/
|
|
58
|
+
function displayHistoryList(runs: HistoryManifest[]): void {
|
|
59
|
+
if (runs.length === 0) {
|
|
60
|
+
console.log('\nNo analysis history found.');
|
|
61
|
+
console.log('Run "peakinfer analyze ." to create your first analysis.\n');
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
console.log(`\n${runs.length} analysis run${runs.length !== 1 ? 's' : ''} in history:\n`);
|
|
66
|
+
|
|
67
|
+
// Table header
|
|
68
|
+
console.log(' Run ID Type Points When Duration');
|
|
69
|
+
console.log(' ─'.repeat(35));
|
|
70
|
+
|
|
71
|
+
for (const run of runs) {
|
|
72
|
+
const type = formatAnalysisType(run.analysisType).padEnd(10);
|
|
73
|
+
const points = String(run.inferencePointCount).padStart(6);
|
|
74
|
+
const when = formatRelativeTime(run.timestamp).padEnd(12);
|
|
75
|
+
const duration = run.durationMs ? `${(run.durationMs / 1000).toFixed(1)}s` : '-';
|
|
76
|
+
|
|
77
|
+
console.log(` ${run.runId.slice(0, 18).padEnd(20)} ${type} ${points} ${when} ${duration}`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
console.log('');
|
|
81
|
+
console.log('Use "peakinfer history show <runId>" for details.');
|
|
82
|
+
console.log('');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Display run details
|
|
87
|
+
*/
|
|
88
|
+
function displayRunDetails(runId: string, manifest: HistoryManifest): void {
|
|
89
|
+
console.log(`\nAnalysis Run: ${runId}`);
|
|
90
|
+
console.log('═'.repeat(60));
|
|
91
|
+
|
|
92
|
+
console.log(` Timestamp: ${formatTimestamp(manifest.timestamp)}`);
|
|
93
|
+
console.log(` Path: ${manifest.path}`);
|
|
94
|
+
console.log(` Type: ${formatAnalysisType(manifest.analysisType)}`);
|
|
95
|
+
console.log(` Version: ${manifest.version}`);
|
|
96
|
+
console.log('');
|
|
97
|
+
|
|
98
|
+
console.log('Metrics:');
|
|
99
|
+
console.log(` Inference Points: ${manifest.inferencePointCount}`);
|
|
100
|
+
if (manifest.eventCount !== undefined) {
|
|
101
|
+
console.log(` Runtime Events: ${manifest.eventCount}`);
|
|
102
|
+
}
|
|
103
|
+
if (manifest.driftCount !== undefined) {
|
|
104
|
+
console.log(` Drift Signals: ${manifest.driftCount}`);
|
|
105
|
+
}
|
|
106
|
+
if (manifest.insightCount !== undefined) {
|
|
107
|
+
console.log(` Insights: ${manifest.insightCount}`);
|
|
108
|
+
}
|
|
109
|
+
if (manifest.durationMs !== undefined) {
|
|
110
|
+
console.log(` Duration: ${(manifest.durationMs / 1000).toFixed(2)}s`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (manifest.artifacts) {
|
|
114
|
+
console.log('');
|
|
115
|
+
console.log('Artifacts:');
|
|
116
|
+
if (manifest.artifacts.inferenceMap) {
|
|
117
|
+
console.log(` Inference Map: ${manifest.artifacts.inferenceMap}`);
|
|
118
|
+
}
|
|
119
|
+
if (manifest.artifacts.html) {
|
|
120
|
+
console.log(` HTML Report: ${manifest.artifacts.html}`);
|
|
121
|
+
}
|
|
122
|
+
if (manifest.artifacts.pdf) {
|
|
123
|
+
console.log(` PDF Report: ${manifest.artifacts.pdf}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
console.log('');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// =============================================================================
|
|
131
|
+
// COMMANDS
|
|
132
|
+
// =============================================================================
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Register history commands
|
|
136
|
+
*/
|
|
137
|
+
export function registerHistoryCommands(program: Command): void {
|
|
138
|
+
const historyCmd = program
|
|
139
|
+
.command('history')
|
|
140
|
+
.description('view and manage analysis history');
|
|
141
|
+
|
|
142
|
+
// List runs (default action)
|
|
143
|
+
historyCmd
|
|
144
|
+
.command('list', { isDefault: true })
|
|
145
|
+
.description('list past analysis runs')
|
|
146
|
+
.option('--path <path>', 'filter by analyzed path')
|
|
147
|
+
.option('--limit <n>', 'limit number of results', parseInt)
|
|
148
|
+
.action((options: { path?: string; limit?: number }) => {
|
|
149
|
+
try {
|
|
150
|
+
let runs = listRuns(options.path);
|
|
151
|
+
|
|
152
|
+
if (options.limit && options.limit > 0) {
|
|
153
|
+
runs = runs.slice(0, options.limit);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
displayHistoryList(runs);
|
|
157
|
+
} catch (error) {
|
|
158
|
+
console.error('Error:', error instanceof Error ? error.message : 'Failed to load history');
|
|
159
|
+
process.exit(1);
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// Show run details
|
|
164
|
+
historyCmd
|
|
165
|
+
.command('show')
|
|
166
|
+
.description('show details of a specific run')
|
|
167
|
+
.argument('<runId>', 'run ID to show')
|
|
168
|
+
.action((runId: string) => {
|
|
169
|
+
try {
|
|
170
|
+
const run = loadRun(runId);
|
|
171
|
+
|
|
172
|
+
if (!run) {
|
|
173
|
+
console.error(`Run not found: ${runId}`);
|
|
174
|
+
process.exit(1);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
displayRunDetails(runId, run.manifest);
|
|
178
|
+
|
|
179
|
+
// Show summary of data if available
|
|
180
|
+
if (run.data.inferenceMap) {
|
|
181
|
+
console.log('Inference Map Summary:');
|
|
182
|
+
console.log(` Total Points: ${run.data.inferenceMap.callsites.length}`);
|
|
183
|
+
console.log(` Providers: ${run.data.inferenceMap.summary.providers.join(', ') || 'none detected'}`);
|
|
184
|
+
console.log(` Models: ${run.data.inferenceMap.summary.models.join(', ') || 'none detected'}`);
|
|
185
|
+
console.log('');
|
|
186
|
+
}
|
|
187
|
+
} catch (error) {
|
|
188
|
+
console.error('Error:', error instanceof Error ? error.message : 'Failed to load run');
|
|
189
|
+
process.exit(1);
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// Compare two runs
|
|
194
|
+
historyCmd
|
|
195
|
+
.command('compare')
|
|
196
|
+
.description('compare two analysis runs')
|
|
197
|
+
.argument('<runId1>', 'first run ID (baseline)')
|
|
198
|
+
.argument('[runId2]', 'second run ID (defaults to latest)')
|
|
199
|
+
.option('--json', 'output as JSON')
|
|
200
|
+
.action((runId1: string, runId2: string | undefined, options: { json?: boolean }) => {
|
|
201
|
+
try {
|
|
202
|
+
// Load first run (baseline)
|
|
203
|
+
const run1 = loadRun(runId1);
|
|
204
|
+
if (!run1) {
|
|
205
|
+
console.error(`Run not found: ${runId1}`);
|
|
206
|
+
process.exit(1);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Load second run (or latest if not specified)
|
|
210
|
+
let run2;
|
|
211
|
+
if (runId2) {
|
|
212
|
+
run2 = loadRun(runId2);
|
|
213
|
+
if (!run2) {
|
|
214
|
+
console.error(`Run not found: ${runId2}`);
|
|
215
|
+
process.exit(1);
|
|
216
|
+
}
|
|
217
|
+
} else {
|
|
218
|
+
// Get the most recent run (excluding run1)
|
|
219
|
+
const runs = listRuns();
|
|
220
|
+
const latestRun = runs.find(r => r.runId !== runId1);
|
|
221
|
+
if (!latestRun) {
|
|
222
|
+
console.error('No other run found to compare with.');
|
|
223
|
+
process.exit(1);
|
|
224
|
+
}
|
|
225
|
+
run2 = loadRun(latestRun.runId);
|
|
226
|
+
if (!run2) {
|
|
227
|
+
console.error('Failed to load latest run.');
|
|
228
|
+
process.exit(1);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Build snapshots
|
|
233
|
+
const baseline: AnalysisSnapshot = {
|
|
234
|
+
runId: run1.manifest.runId,
|
|
235
|
+
timestamp: run1.manifest.timestamp,
|
|
236
|
+
callsites: run1.data.inferenceMap?.callsites || [],
|
|
237
|
+
insights: run1.data.insights,
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
const current: AnalysisSnapshot = {
|
|
241
|
+
runId: run2.manifest.runId,
|
|
242
|
+
timestamp: run2.manifest.timestamp,
|
|
243
|
+
callsites: run2.data.inferenceMap?.callsites || [],
|
|
244
|
+
insights: run2.data.insights,
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
// Compare
|
|
248
|
+
const comparison = compareSnapshots(baseline, current);
|
|
249
|
+
|
|
250
|
+
if (options.json) {
|
|
251
|
+
console.log(JSON.stringify(comparison, null, 2));
|
|
252
|
+
} else {
|
|
253
|
+
console.log('');
|
|
254
|
+
console.log(`Baseline: ${run1.manifest.runId} (${formatTimestamp(run1.manifest.timestamp)})`);
|
|
255
|
+
console.log(`Current: ${run2.manifest.runId} (${formatTimestamp(run2.manifest.timestamp)})`);
|
|
256
|
+
console.log('');
|
|
257
|
+
console.log(formatComparisonSummary(comparison));
|
|
258
|
+
|
|
259
|
+
// Show details for added/removed/changed
|
|
260
|
+
if (comparison.added.length > 0 && comparison.added.length <= 5) {
|
|
261
|
+
console.log('');
|
|
262
|
+
console.log('Added inference points:');
|
|
263
|
+
for (const cs of comparison.added) {
|
|
264
|
+
console.log(` + ${cs.file}:${cs.line} (${cs.provider || 'unknown'})`);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (comparison.removed.length > 0 && comparison.removed.length <= 5) {
|
|
269
|
+
console.log('');
|
|
270
|
+
console.log('Removed inference points:');
|
|
271
|
+
for (const cs of comparison.removed) {
|
|
272
|
+
console.log(` - ${cs.file}:${cs.line} (${cs.provider || 'unknown'})`);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (comparison.changed.length > 0 && comparison.changed.length <= 5) {
|
|
277
|
+
console.log('');
|
|
278
|
+
console.log('Changed inference points:');
|
|
279
|
+
for (const change of comparison.changed) {
|
|
280
|
+
const fields = change.changes.map(c => c.field).join(', ');
|
|
281
|
+
console.log(` ~ ${change.point.file}:${change.point.line} (${fields})`);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
console.log('');
|
|
286
|
+
if (hasSignificantChanges(comparison)) {
|
|
287
|
+
console.log('Result: Changes detected - review recommended before deploy.');
|
|
288
|
+
} else {
|
|
289
|
+
console.log('Result: No significant changes.');
|
|
290
|
+
}
|
|
291
|
+
console.log('');
|
|
292
|
+
}
|
|
293
|
+
} catch (error) {
|
|
294
|
+
console.error('Error:', error instanceof Error ? error.message : 'Failed to compare runs');
|
|
295
|
+
process.exit(1);
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
// Export history
|
|
300
|
+
historyCmd
|
|
301
|
+
.command('export')
|
|
302
|
+
.description('export history to JSON file')
|
|
303
|
+
.option('--output <file>', 'output file path', 'peakinfer-history.json')
|
|
304
|
+
.option('--path <path>', 'filter by analyzed path')
|
|
305
|
+
.action((options: { output: string; path?: string }) => {
|
|
306
|
+
try {
|
|
307
|
+
const runs = listRuns(options.path);
|
|
308
|
+
|
|
309
|
+
if (runs.length === 0) {
|
|
310
|
+
console.log('No history to export.');
|
|
311
|
+
process.exit(0);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Load full data for each run
|
|
315
|
+
const exportData = runs.map(manifest => {
|
|
316
|
+
const run = loadRun(manifest.runId);
|
|
317
|
+
return {
|
|
318
|
+
manifest,
|
|
319
|
+
data: run?.data || null,
|
|
320
|
+
};
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
const output = {
|
|
324
|
+
exportedAt: new Date().toISOString(),
|
|
325
|
+
runCount: runs.length,
|
|
326
|
+
runs: exportData,
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
writeFileSync(options.output, JSON.stringify(output, null, 2));
|
|
330
|
+
console.log(`Exported ${runs.length} run${runs.length !== 1 ? 's' : ''} to ${options.output}`);
|
|
331
|
+
} catch (error) {
|
|
332
|
+
console.error('Error:', error instanceof Error ? error.message : 'Failed to export history');
|
|
333
|
+
process.exit(1);
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
// Prune old runs
|
|
338
|
+
historyCmd
|
|
339
|
+
.command('prune')
|
|
340
|
+
.description('remove old runs (keeps most recent per path)')
|
|
341
|
+
.option('--keep <n>', 'number of runs to keep per path', parseInt, 10)
|
|
342
|
+
.option('--dry-run', 'show what would be deleted without deleting')
|
|
343
|
+
.action((options: { keep: number; dryRun?: boolean }) => {
|
|
344
|
+
try {
|
|
345
|
+
if (options.dryRun) {
|
|
346
|
+
// Count what would be deleted
|
|
347
|
+
const runs = listRuns();
|
|
348
|
+
const byPath = new Map<string, number>();
|
|
349
|
+
for (const run of runs) {
|
|
350
|
+
byPath.set(run.pathHash, (byPath.get(run.pathHash) || 0) + 1);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
let totalToDelete = 0;
|
|
354
|
+
for (const [, count] of byPath) {
|
|
355
|
+
if (count > options.keep) {
|
|
356
|
+
totalToDelete += count - options.keep;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
console.log(`Would delete ${totalToDelete} run${totalToDelete !== 1 ? 's' : ''} (keeping ${options.keep} per path)`);
|
|
361
|
+
} else {
|
|
362
|
+
const deleted = pruneHistory(options.keep);
|
|
363
|
+
console.log(`Pruned ${deleted} run${deleted !== 1 ? 's' : ''} from history.`);
|
|
364
|
+
}
|
|
365
|
+
} catch (error) {
|
|
366
|
+
console.error('Error:', error instanceof Error ? error.message : 'Failed to prune history');
|
|
367
|
+
process.exit(1);
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
// Delete specific run
|
|
372
|
+
historyCmd
|
|
373
|
+
.command('delete')
|
|
374
|
+
.description('delete a specific run by ID')
|
|
375
|
+
.argument('<runId>', 'run ID to delete')
|
|
376
|
+
.action((runId: string) => {
|
|
377
|
+
try {
|
|
378
|
+
const deleted = deleteRun(runId);
|
|
379
|
+
if (deleted) {
|
|
380
|
+
console.log(`Deleted run: ${runId}`);
|
|
381
|
+
} else {
|
|
382
|
+
console.error(`Run not found: ${runId}`);
|
|
383
|
+
process.exit(1);
|
|
384
|
+
}
|
|
385
|
+
} catch (error) {
|
|
386
|
+
console.error('Error:', error instanceof Error ? error.message : 'Failed to delete run');
|
|
387
|
+
process.exit(1);
|
|
388
|
+
}
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
// Clear all history
|
|
392
|
+
historyCmd
|
|
393
|
+
.command('clear')
|
|
394
|
+
.description('delete all history')
|
|
395
|
+
.option('--confirm', 'confirm deletion without prompt')
|
|
396
|
+
.action((options: { confirm?: boolean }) => {
|
|
397
|
+
try {
|
|
398
|
+
const runs = listRuns();
|
|
399
|
+
if (runs.length === 0) {
|
|
400
|
+
console.log('No history to clear.');
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
if (!options.confirm) {
|
|
405
|
+
console.log(`This will delete ${runs.length} run${runs.length !== 1 ? 's' : ''}.`);
|
|
406
|
+
console.log('Use --confirm to proceed.');
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
const deleted = clearAllHistory();
|
|
411
|
+
console.log(`Cleared ${deleted} run${deleted !== 1 ? 's' : ''} from history.`);
|
|
412
|
+
} catch (error) {
|
|
413
|
+
console.error('Error:', error instanceof Error ? error.message : 'Failed to clear history');
|
|
414
|
+
process.exit(1);
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
// Show history directory
|
|
419
|
+
historyCmd
|
|
420
|
+
.command('path')
|
|
421
|
+
.description('show history storage location')
|
|
422
|
+
.action(() => {
|
|
423
|
+
console.log(`History stored at: ${getHistoryDir()}`);
|
|
424
|
+
});
|
|
425
|
+
}
|