fraim-framework 2.0.124 → 2.0.127

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 (46) hide show
  1. package/bin/fraim.js +1 -1
  2. package/dist/src/ai-hub/catalog.js +280 -44
  3. package/dist/src/ai-hub/desktop-main.js +2 -2
  4. package/dist/src/ai-hub/hosts.js +384 -10
  5. package/dist/src/ai-hub/server.js +255 -9
  6. package/dist/src/cli/commands/add-ide.js +4 -3
  7. package/dist/src/cli/commands/first-run.js +61 -0
  8. package/dist/src/cli/commands/hub.js +4 -4
  9. package/dist/src/cli/commands/init-project.js +4 -4
  10. package/dist/src/cli/commands/setup.js +4 -3
  11. package/dist/src/cli/commands/sync.js +21 -2
  12. package/dist/src/cli/doctor/checks/ide-config-checks.js +20 -2
  13. package/dist/src/cli/fraim.js +2 -0
  14. package/dist/src/cli/mcp/ide-formats.js +29 -1
  15. package/dist/src/cli/mcp/mcp-server-registry.js +1 -0
  16. package/dist/src/cli/setup/auto-mcp-setup.js +14 -8
  17. package/dist/src/cli/setup/ide-detector.js +32 -1
  18. package/dist/src/cli/setup/ide-global-integration.js +5 -1
  19. package/dist/src/cli/setup/ide-invocation-surfaces.js +70 -17
  20. package/dist/src/cli/setup/mcp-config-generator.js +12 -1
  21. package/dist/src/cli/utils/agent-adapters.js +12 -2
  22. package/dist/src/cli/utils/project-bootstrap.js +4 -3
  23. package/dist/src/core/quality-evidence.js +81 -8
  24. package/dist/src/core/utils/git-utils.js +32 -7
  25. package/dist/src/core/utils/job-aliases.js +47 -0
  26. package/dist/src/core/utils/workflow-parser.js +3 -5
  27. package/dist/src/first-run/install-state.js +68 -0
  28. package/dist/src/first-run/server.js +153 -0
  29. package/dist/src/first-run/session-service.js +302 -0
  30. package/dist/src/first-run/types.js +40 -0
  31. package/dist/src/local-mcp-server/agent-token-prices.js +114 -0
  32. package/dist/src/local-mcp-server/codex-token-adapter.js +232 -0
  33. package/dist/src/local-mcp-server/learning-context-builder.js +21 -8
  34. package/dist/src/local-mcp-server/otlp-metrics-receiver.js +7 -1
  35. package/dist/src/local-mcp-server/stdio-server.js +70 -17
  36. package/dist/src/local-mcp-server/token-adapter-registry.js +64 -0
  37. package/dist/src/local-mcp-server/usage-collector.js +25 -0
  38. package/index.js +83 -83
  39. package/package.json +7 -1
  40. package/public/ai-hub/index.html +149 -102
  41. package/public/ai-hub/script.js +1154 -271
  42. package/public/ai-hub/styles.css +753 -450
  43. package/public/first-run/index.html +221 -0
  44. package/public/first-run/script.js +361 -0
  45. package/dist/src/cli/services/device-flow-service.js +0 -83
  46. package/dist/src/local-mcp-server/prometheus-scraper.js +0 -152
@@ -1,152 +0,0 @@
1
- "use strict";
2
- /**
3
- * Prometheus Scraper for Claude Code OTel Token Usage Metrics
4
- *
5
- * Scrapes Claude Code's local Prometheus endpoint to capture cumulative
6
- * token usage counters. Returns raw snapshot values — delta computation
7
- * happens server-side per architecture constraint 15.2.
8
- */
9
- Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.parsePrometheusText = parsePrometheusText;
11
- exports.extractTokenSnapshot = extractTokenSnapshot;
12
- exports.scrapeTokenSnapshot = scrapeTokenSnapshot;
13
- /** Candidate Prometheus endpoint ports (OTel SDK defaults) */
14
- const CANDIDATE_PORTS = [9464, 8888];
15
- /** Candidate metric names for token usage (OTel dots→underscores, optional suffixes) */
16
- const TOKEN_METRIC_CANDIDATES = [
17
- 'claude_code_token_usage_total',
18
- 'claude_code_token_usage',
19
- 'claude_code_token_usage_tokens_total',
20
- 'claude_code_token_usage_tokens',
21
- ];
22
- /** Candidate metric names for cost usage */
23
- const COST_METRIC_CANDIDATES = [
24
- 'claude_code_cost_usage_total',
25
- 'claude_code_cost_usage',
26
- 'claude_code_cost_usage_usd_total',
27
- 'claude_code_cost_usage_usd',
28
- ];
29
- /**
30
- * Parse Prometheus text exposition format into structured metrics.
31
- *
32
- * Format per line: metric_name{label1="val1",label2="val2"} value [timestamp]
33
- * Lines starting with # are comments (HELP, TYPE). Empty lines are skipped.
34
- */
35
- function parsePrometheusText(text) {
36
- const results = [];
37
- for (const line of text.split('\n')) {
38
- if (line.startsWith('#') || line.trim() === '')
39
- continue;
40
- // Match: metric_name{labels} value
41
- const labeledMatch = line.match(/^([a-zA-Z_:][a-zA-Z0-9_:]*)\{([^}]*)\}\s+([\d.eE+-]+)/);
42
- if (labeledMatch) {
43
- const [, name, labelsStr, valueStr] = labeledMatch;
44
- const labels = {};
45
- for (const pair of labelsStr.matchAll(/(\w+)="([^"]*)"/g)) {
46
- labels[pair[1]] = pair[2];
47
- }
48
- results.push({ name, labels, value: parseFloat(valueStr) });
49
- continue;
50
- }
51
- // Match: metric_name value (no labels)
52
- const noLabelMatch = line.match(/^([a-zA-Z_:][a-zA-Z0-9_:]*)\s+([\d.eE+-]+)/);
53
- if (noLabelMatch) {
54
- const [, name, valueStr] = noLabelMatch;
55
- results.push({ name, labels: {}, value: parseFloat(valueStr) });
56
- }
57
- }
58
- return results;
59
- }
60
- /**
61
- * Extract a TokenSnapshot from parsed Prometheus metrics.
62
- * Tries multiple candidate metric names for resilience to SDK version changes.
63
- */
64
- function extractTokenSnapshot(metrics) {
65
- const snapshot = {
66
- inputTokens: 0,
67
- outputTokens: 0,
68
- cacheReadTokens: 0,
69
- cacheCreationTokens: 0,
70
- costUsd: 0,
71
- claudeSessionId: null,
72
- model: null,
73
- capturedAt: new Date(),
74
- };
75
- for (const m of metrics) {
76
- if (TOKEN_METRIC_CANDIDATES.includes(m.name)) {
77
- const type = m.labels['type'];
78
- switch (type) {
79
- case 'input':
80
- snapshot.inputTokens = m.value;
81
- break;
82
- case 'output':
83
- snapshot.outputTokens = m.value;
84
- break;
85
- case 'cacheRead':
86
- snapshot.cacheReadTokens = m.value;
87
- break;
88
- case 'cacheCreation':
89
- snapshot.cacheCreationTokens = m.value;
90
- break;
91
- }
92
- snapshot.claudeSessionId = m.labels['session_id'] || snapshot.claudeSessionId;
93
- snapshot.model = m.labels['model'] || snapshot.model;
94
- }
95
- if (COST_METRIC_CANDIDATES.includes(m.name)) {
96
- snapshot.costUsd += m.value;
97
- snapshot.claudeSessionId = m.labels['session_id'] || snapshot.claudeSessionId;
98
- }
99
- }
100
- return snapshot;
101
- }
102
- /**
103
- * Attempt to fetch Prometheus metrics from a candidate endpoint.
104
- * Returns response text or null on failure.
105
- */
106
- async function tryFetch(port, timeoutMs) {
107
- try {
108
- const controller = new AbortController();
109
- const timeout = setTimeout(() => controller.abort(), timeoutMs);
110
- const resp = await fetch(`http://localhost:${port}/metrics`, {
111
- signal: controller.signal,
112
- });
113
- clearTimeout(timeout);
114
- if (resp.ok) {
115
- return await resp.text();
116
- }
117
- return null;
118
- }
119
- catch {
120
- return null;
121
- }
122
- }
123
- /**
124
- * Scrape Claude Code's Prometheus endpoint and return a TokenSnapshot.
125
- *
126
- * Returns null if:
127
- * - Prometheus endpoint is not available (OTel not enabled)
128
- * - Scrape times out (>2s by default)
129
- * - No matching token metrics found
130
- *
131
- * @param log Optional logging function for debug output
132
- */
133
- async function scrapeTokenSnapshot(log) {
134
- const configuredPort = process.env.FRAIM_PROMETHEUS_PORT;
135
- const ports = configuredPort ? [parseInt(configuredPort, 10)] : CANDIDATE_PORTS;
136
- const timeoutMs = 2000;
137
- for (const port of ports) {
138
- const text = await tryFetch(port, timeoutMs);
139
- if (text && text.includes('#')) {
140
- const metrics = parsePrometheusText(text);
141
- const snapshot = extractTokenSnapshot(metrics);
142
- // Only return if we actually found token metrics
143
- if (snapshot.inputTokens > 0 || snapshot.outputTokens > 0) {
144
- log?.(`Captured token snapshot from localhost:${port} (input=${snapshot.inputTokens}, output=${snapshot.outputTokens})`);
145
- return snapshot;
146
- }
147
- log?.(`Prometheus endpoint found at localhost:${port} but no token metrics matched`);
148
- }
149
- }
150
- log?.('No Prometheus endpoint available — token snapshot skipped');
151
- return null;
152
- }