wyrm-mcp 7.2.0 → 7.2.2

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 (156) hide show
  1. package/LICENSE +26 -667
  2. package/NOTICE +14 -33
  3. package/dist/activation.d.ts.map +1 -1
  4. package/dist/activation.js +1 -44
  5. package/dist/activation.js.map +1 -1
  6. package/dist/agent-daemon.js +4 -281
  7. package/dist/agent-loop.js +7 -332
  8. package/dist/analytics.js +13 -236
  9. package/dist/attribution.js +1 -49
  10. package/dist/audit.js +2 -457
  11. package/dist/auto-capture.js +3 -138
  12. package/dist/auto-orchestrator.js +1 -325
  13. package/dist/autoconfig.js +39 -840
  14. package/dist/buddy-runner.js +1 -109
  15. package/dist/buddy.js +14 -564
  16. package/dist/build-flags.js +1 -17
  17. package/dist/capabilities.js +3 -183
  18. package/dist/capture.js +1 -56
  19. package/dist/causality.js +6 -107
  20. package/dist/cli.js +20 -281
  21. package/dist/cloud/cli.js +5 -541
  22. package/dist/cloud/client.js +1 -221
  23. package/dist/cloud/crypto.js +1 -85
  24. package/dist/cloud/machine-id.js +2 -113
  25. package/dist/cloud/recovery.js +1 -60
  26. package/dist/cloud/sync-engine.js +7 -543
  27. package/dist/cloud-backup.js +5 -579
  28. package/dist/cloud-profile.js +1 -138
  29. package/dist/cloud-sync-entrypoint.js +1 -47
  30. package/dist/cloud-sync.js +2 -309
  31. package/dist/constellation.js +12 -168
  32. package/dist/context-build-budgeted.js +4 -144
  33. package/dist/context-ranking.js +1 -69
  34. package/dist/crypto.js +1 -179
  35. package/dist/daemon-write-endpoint.js +1 -290
  36. package/dist/daemon-writer.js +2 -406
  37. package/dist/database.js +43 -1110
  38. package/dist/deprecations.js +2 -162
  39. package/dist/design.js +13 -141
  40. package/dist/event-replication.js +1 -112
  41. package/dist/events-sse.js +7 -43
  42. package/dist/events.js +6 -238
  43. package/dist/failure-patterns.js +42 -659
  44. package/dist/federation.js +12 -236
  45. package/dist/goals.js +13 -101
  46. package/dist/golden.js +3 -355
  47. package/dist/handlers/agent.js +4 -165
  48. package/dist/handlers/alias-adapters.js +1 -129
  49. package/dist/handlers/aliases.js +1 -171
  50. package/dist/handlers/audit.js +1 -87
  51. package/dist/handlers/boundary.js +1 -221
  52. package/dist/handlers/capture.js +73 -1109
  53. package/dist/handlers/causality.js +7 -114
  54. package/dist/handlers/cloud.js +85 -382
  55. package/dist/handlers/companion.js +28 -459
  56. package/dist/handlers/datalake.js +7 -187
  57. package/dist/handlers/dispatch-context.js +0 -22
  58. package/dist/handlers/entity.js +25 -256
  59. package/dist/handlers/events.js +16 -335
  60. package/dist/handlers/failure.js +13 -340
  61. package/dist/handlers/goals.js +4 -296
  62. package/dist/handlers/intelligence.js +126 -674
  63. package/dist/handlers/invoicing.js +1 -70
  64. package/dist/handlers/mcpclient.js +6 -137
  65. package/dist/handlers/orchestration.js +40 -125
  66. package/dist/handlers/output-schemas.js +1 -24
  67. package/dist/handlers/presence.js +3 -99
  68. package/dist/handlers/project.js +28 -182
  69. package/dist/handlers/prompts.js +6 -157
  70. package/dist/handlers/quest.js +4 -224
  71. package/dist/handlers/recall.js +11 -218
  72. package/dist/handlers/registry.js +1 -167
  73. package/dist/handlers/resources.js +1 -288
  74. package/dist/handlers/review.js +11 -74
  75. package/dist/handlers/run.js +17 -487
  76. package/dist/handlers/search.js +15 -326
  77. package/dist/handlers/session.js +28 -615
  78. package/dist/handlers/share.js +8 -184
  79. package/dist/handlers/shims.js +1 -464
  80. package/dist/handlers/skill.js +67 -449
  81. package/dist/handlers/survivors.js +1 -120
  82. package/dist/handlers/symbols.js +8 -109
  83. package/dist/handlers/syncops.js +4 -302
  84. package/dist/handlers/types.js +1 -27
  85. package/dist/harvest.js +5 -191
  86. package/dist/hours.js +7 -156
  87. package/dist/http-auth.js +3 -321
  88. package/dist/http-fast.js +21 -1137
  89. package/dist/icons.js +1 -47
  90. package/dist/index.js +2 -924
  91. package/dist/indexer.js +4 -145
  92. package/dist/intelligence.js +31 -261
  93. package/dist/internal-dispatch.js +3 -212
  94. package/dist/keyset.js +1 -110
  95. package/dist/knowledge-graph.js +12 -176
  96. package/dist/license.d.ts +11 -0
  97. package/dist/license.d.ts.map +1 -1
  98. package/dist/license.js +2 -414
  99. package/dist/license.js.map +1 -1
  100. package/dist/logger.js +2 -199
  101. package/dist/maintenance.js +2 -148
  102. package/dist/mcp-client.js +6 -262
  103. package/dist/memory-artifacts.js +30 -449
  104. package/dist/migrate-prompt.js +2 -124
  105. package/dist/migrations.js +40 -655
  106. package/dist/performance.js +1 -228
  107. package/dist/presence.js +11 -140
  108. package/dist/priority-embed.js +5 -164
  109. package/dist/providers/embedding-provider.js +1 -196
  110. package/dist/readonly-gate.js +1 -29
  111. package/dist/rehydration.js +9 -157
  112. package/dist/reindex.js +1 -88
  113. package/dist/render-target.js +21 -514
  114. package/dist/render.js +4 -280
  115. package/dist/repl-guard.js +1 -173
  116. package/dist/replication-daemon-entrypoint.js +1 -31
  117. package/dist/replication-daemon.js +2 -262
  118. package/dist/resilience.js +1 -591
  119. package/dist/reverse-bridge.js +5 -360
  120. package/dist/security.js +1 -244
  121. package/dist/session-seen.js +3 -51
  122. package/dist/setup.js +1 -260
  123. package/dist/skill-author.js +5 -168
  124. package/dist/spec-kit.js +1 -191
  125. package/dist/sqlite-busy.js +1 -154
  126. package/dist/statusline.js +11 -315
  127. package/dist/sub-agent.js +13 -262
  128. package/dist/summarizer.js +13 -139
  129. package/dist/symbols.js +7 -283
  130. package/dist/sync.js +5 -359
  131. package/dist/tasks-dispatch.js +1 -84
  132. package/dist/tasks.js +1 -282
  133. package/dist/token-budget.js +1 -143
  134. package/dist/tool-analytics.js +7 -129
  135. package/dist/tool-annotations.js +1 -365
  136. package/dist/tool-manifest-v2.json +1 -1
  137. package/dist/tool-manifest.json +1 -1
  138. package/dist/tool-profiles.js +1 -75
  139. package/dist/trace-harvest.js +6 -244
  140. package/dist/types.js +1 -30
  141. package/dist/ui-dashboard.js +41 -50
  142. package/dist/ulid.js +1 -81
  143. package/dist/validate.js +1 -129
  144. package/dist/vault.js +1 -534
  145. package/dist/vectors.js +3 -184
  146. package/dist/version-check.js +4 -136
  147. package/dist/visibility.js +19 -155
  148. package/dist/wyrm-cli.js +98 -2451
  149. package/dist/wyrm-cli.js.map +1 -1
  150. package/dist/wyrm-guard.js +14 -424
  151. package/dist/wyrm-loop.js +3 -150
  152. package/dist/wyrm-manifest.json +1 -1
  153. package/dist/wyrm-statusline-daemon.js +1 -11
  154. package/dist/wyrm-statusline.js +4 -56
  155. package/dist/wyrm-ui.js +9 -77
  156. package/package.json +4 -2
package/dist/analytics.js CHANGED
@@ -1,43 +1,7 @@
1
- /**
2
- * Wyrm Analytics — Persistent Usage Tracking & Cost Monitoring
3
- *
4
- * @copyright 2026 Ghost Protocol (Pvt) Ltd.
5
- * @license AGPL-3.0-or-later — dual-licensed; commercial terms: ghosts.lk@proton.me. See LICENSE.
6
- * @module analytics
7
- * @version 3.2.0
8
- */
9
- // ==================== CONSTANTS ====================
10
- /** Claude Sonnet pricing per 1M tokens */
11
- const COST_PER_MILLION_INPUT = 3;
12
- const COST_PER_MILLION_OUTPUT = 15;
13
- const BUFFER_FLUSH_THRESHOLD = 50;
14
- const FLUSH_INTERVAL_MS = 30_000;
15
- const DEFAULT_RETAIN_DAYS = 90;
16
- // ==================== ANALYTICS CLASS ====================
17
- export class WyrmAnalytics {
18
- db;
19
- insertStmt;
20
- batchBuffer;
21
- flushInterval;
22
- constructor(db) {
23
- this.db = db;
24
- this.batchBuffer = [];
25
- this.initTables();
26
- this.insertStmt = this.db.prepare(`
1
+ const S=3,p=15,h=50,A=3e4,N=90;class k{db;insertStmt;batchBuffer;flushInterval;constructor(_){this.db=_,this.batchBuffer=[],this.initTables(),this.insertStmt=this.db.prepare(`
27
2
  INSERT INTO usage_events (tool_name, tokens_in, tokens_out, cached, response_ms, success, error_message, timestamp)
28
3
  VALUES (@tool_name, @tokens_in, @tokens_out, @cached, @response_ms, @success, @error_message, @timestamp)
29
- `);
30
- this.flushInterval = setInterval(() => {
31
- this.flush();
32
- }, FLUSH_INTERVAL_MS);
33
- // Don't let the timer keep the process alive
34
- if (this.flushInterval.unref) {
35
- this.flushInterval.unref();
36
- }
37
- }
38
- // ==================== SCHEMA ====================
39
- initTables() {
40
- this.db.exec(`
4
+ `),this.flushInterval=setInterval(()=>{this.flush()},3e4),this.flushInterval.unref&&this.flushInterval.unref()}initTables(){this.db.exec(`
41
5
  CREATE TABLE IF NOT EXISTS usage_events (
42
6
  id INTEGER PRIMARY KEY AUTOINCREMENT,
43
7
  tool_name TEXT NOT NULL,
@@ -68,59 +32,7 @@ export class WyrmAnalytics {
68
32
  CREATE INDEX IF NOT EXISTS idx_usage_events_tool ON usage_events(tool_name);
69
33
  CREATE INDEX IF NOT EXISTS idx_usage_events_ts ON usage_events(timestamp);
70
34
  CREATE INDEX IF NOT EXISTS idx_cost_tracking_period ON cost_tracking(period);
71
- `);
72
- }
73
- // ==================== RECORDING ====================
74
- /** Record a single tool usage event */
75
- record(event) {
76
- this.batchBuffer.push(event);
77
- if (this.batchBuffer.length >= BUFFER_FLUSH_THRESHOLD) {
78
- this.flush();
79
- }
80
- }
81
- /** Flush buffered events to disk */
82
- flush() {
83
- if (this.batchBuffer.length === 0)
84
- return;
85
- const events = this.batchBuffer.splice(0);
86
- const insertMany = this.db.transaction((batch) => {
87
- for (const event of batch) {
88
- this.insertStmt.run({
89
- tool_name: event.tool,
90
- tokens_in: event.tokens_in,
91
- tokens_out: event.tokens_out,
92
- cached: event.cached ? 1 : 0,
93
- response_ms: event.ms,
94
- success: event.success !== false ? 1 : 0,
95
- error_message: event.error ?? null,
96
- timestamp: event.timestamp,
97
- });
98
- }
99
- });
100
- insertMany(events);
101
- this.updateCostTracking(events);
102
- }
103
- /** Update cost_tracking aggregates from a batch of events */
104
- updateCostTracking(events) {
105
- const groups = new Map();
106
- for (const event of events) {
107
- const period = event.timestamp.slice(0, 7); // YYYY-MM
108
- const key = `${period}:${event.tool}`;
109
- let group = groups.get(key);
110
- if (!group) {
111
- group = { tool: event.tool, period, calls: 0, tokens_in: 0, tokens_out: 0, cached: 0, total_ms: 0, errors: 0 };
112
- groups.set(key, group);
113
- }
114
- group.calls++;
115
- group.tokens_in += event.tokens_in;
116
- group.tokens_out += event.tokens_out;
117
- if (event.cached)
118
- group.cached++;
119
- group.total_ms += event.ms;
120
- if (event.success === false)
121
- group.errors++;
122
- }
123
- const upsertStmt = this.db.prepare(`
35
+ `)}record(_){this.batchBuffer.push(_),this.batchBuffer.length>=50&&this.flush()}flush(){if(this.batchBuffer.length===0)return;const _=this.batchBuffer.splice(0);this.db.transaction(n=>{for(const o of n)this.insertStmt.run({tool_name:o.tool,tokens_in:o.tokens_in,tokens_out:o.tokens_out,cached:o.cached?1:0,response_ms:o.ms,success:o.success!==!1?1:0,error_message:o.error??null,timestamp:o.timestamp})})(_),this.updateCostTracking(_)}updateCostTracking(_){const s=new Map;for(const t of _){const e=t.timestamp.slice(0,7),r=`${e}:${t.tool}`;let a=s.get(r);a||(a={tool:t.tool,period:e,calls:0,tokens_in:0,tokens_out:0,cached:0,total_ms:0,errors:0},s.set(r,a)),a.calls++,a.tokens_in+=t.tokens_in,a.tokens_out+=t.tokens_out,t.cached&&a.cached++,a.total_ms+=t.ms,t.success===!1&&a.errors++}const n=this.db.prepare(`
124
36
  INSERT INTO cost_tracking (period, tool_name, call_count, total_tokens_in, total_tokens_out, cached_count, avg_response_ms, error_count, estimated_cost_usd, updated_at)
125
37
  VALUES (@period, @tool_name, @call_count, @total_tokens_in, @total_tokens_out, @cached_count, @avg_response_ms, @error_count, @estimated_cost_usd, datetime('now'))
126
38
  ON CONFLICT(period, tool_name) DO UPDATE SET
@@ -132,35 +44,7 @@ export class WyrmAnalytics {
132
44
  error_count = error_count + @error_count,
133
45
  estimated_cost_usd = estimated_cost_usd + @estimated_cost_usd,
134
46
  updated_at = datetime('now')
135
- `);
136
- const upsertMany = this.db.transaction((entries) => {
137
- for (const group of entries.values()) {
138
- const cost = this.estimateCost(group.tokens_in, group.tokens_out);
139
- upsertStmt.run({
140
- period: group.period,
141
- tool_name: group.tool,
142
- call_count: group.calls,
143
- total_tokens_in: group.tokens_in,
144
- total_tokens_out: group.tokens_out,
145
- cached_count: group.cached,
146
- avg_response_ms: group.calls > 0 ? group.total_ms / group.calls : 0,
147
- error_count: group.errors,
148
- estimated_cost_usd: cost,
149
- });
150
- }
151
- });
152
- upsertMany(groups);
153
- }
154
- // ==================== QUERIES ====================
155
- /** Get dashboard summary for a time period */
156
- dashboard(days = 30) {
157
- // Ensure buffered data is included
158
- this.flush();
159
- const start = new Date();
160
- start.setDate(start.getDate() - days);
161
- const startStr = start.toISOString().slice(0, 10);
162
- const endStr = new Date().toISOString().slice(0, 10);
163
- const summary = this.db.prepare(`
47
+ `);this.db.transaction(t=>{for(const e of t.values()){const r=this.estimateCost(e.tokens_in,e.tokens_out);n.run({period:e.period,tool_name:e.tool,call_count:e.calls,total_tokens_in:e.tokens_in,total_tokens_out:e.tokens_out,cached_count:e.cached,avg_response_ms:e.calls>0?e.total_ms/e.calls:0,error_count:e.errors,estimated_cost_usd:r})}})(s)}dashboard(_=30){this.flush();const s=new Date;s.setDate(s.getDate()-_);const n=s.toISOString().slice(0,10),o=new Date().toISOString().slice(0,10),t=this.db.prepare(`
164
48
  SELECT
165
49
  COUNT(*) AS total_calls,
166
50
  COUNT(DISTINCT tool_name) AS unique_tools,
@@ -177,8 +61,7 @@ export class WyrmAnalytics {
177
61
  END AS error_rate
178
62
  FROM usage_events
179
63
  WHERE timestamp >= @start
180
- `).get({ start: startStr });
181
- const top_tools = this.db.prepare(`
64
+ `).get({start:n}),e=this.db.prepare(`
182
65
  SELECT
183
66
  tool_name AS tool,
184
67
  COUNT(*) AS calls,
@@ -188,8 +71,7 @@ export class WyrmAnalytics {
188
71
  GROUP BY tool_name
189
72
  ORDER BY calls DESC
190
73
  LIMIT 10
191
- `).all({ start: startStr });
192
- const daily = this.db.prepare(`
74
+ `).all({start:n}),r=this.db.prepare(`
193
75
  SELECT
194
76
  DATE(timestamp) AS date,
195
77
  COUNT(*) AS calls,
@@ -199,31 +81,7 @@ export class WyrmAnalytics {
199
81
  WHERE timestamp >= @start
200
82
  GROUP BY DATE(timestamp)
201
83
  ORDER BY date ASC
202
- `).all({ start: startStr });
203
- const estimated_cost_usd = this.estimateCost(summary.total_tokens_in, summary.total_tokens_out);
204
- return {
205
- period: { start: startStr, end: endStr },
206
- summary: {
207
- total_calls: summary.total_calls,
208
- unique_tools: summary.unique_tools,
209
- total_tokens_in: summary.total_tokens_in,
210
- total_tokens_out: summary.total_tokens_out,
211
- cache_hit_rate: summary.cache_hit_rate,
212
- avg_response_ms: summary.avg_response_ms,
213
- error_rate: summary.error_rate,
214
- estimated_cost_usd,
215
- },
216
- top_tools,
217
- daily,
218
- };
219
- }
220
- /** Get per-tool breakdown */
221
- toolBreakdown(toolName, days = 30) {
222
- this.flush();
223
- const start = new Date();
224
- start.setDate(start.getDate() - days);
225
- const startStr = start.toISOString().slice(0, 10);
226
- const stats = this.db.prepare(`
84
+ `).all({start:n}),a=this.estimateCost(t.total_tokens_in,t.total_tokens_out);return{period:{start:n,end:o},summary:{total_calls:t.total_calls,unique_tools:t.unique_tools,total_tokens_in:t.total_tokens_in,total_tokens_out:t.total_tokens_out,cache_hit_rate:t.cache_hit_rate,avg_response_ms:t.avg_response_ms,error_rate:t.error_rate,estimated_cost_usd:a},top_tools:e,daily:r}}toolBreakdown(_,s=30){this.flush();const n=new Date;n.setDate(n.getDate()-s);const o=n.toISOString().slice(0,10),t=this.db.prepare(`
227
85
  SELECT
228
86
  COUNT(*) AS total_calls,
229
87
  COALESCE(ROUND(AVG(tokens_in), 2), 0) AS avg_tokens_in,
@@ -239,8 +97,7 @@ export class WyrmAnalytics {
239
97
  END AS error_rate
240
98
  FROM usage_events
241
99
  WHERE tool_name = @tool AND timestamp >= @start
242
- `).get({ tool: toolName, start: startStr });
243
- const daily = this.db.prepare(`
100
+ `).get({tool:_,start:o}),e=this.db.prepare(`
244
101
  SELECT
245
102
  DATE(timestamp) AS date,
246
103
  COUNT(*) AS calls
@@ -248,23 +105,7 @@ export class WyrmAnalytics {
248
105
  WHERE tool_name = @tool AND timestamp >= @start
249
106
  GROUP BY DATE(timestamp)
250
107
  ORDER BY date ASC
251
- `).all({ tool: toolName, start: startStr });
252
- return {
253
- tool: toolName,
254
- total_calls: stats.total_calls,
255
- avg_tokens_in: stats.avg_tokens_in,
256
- avg_tokens_out: stats.avg_tokens_out,
257
- avg_response_ms: stats.avg_response_ms,
258
- cache_hit_rate: stats.cache_hit_rate,
259
- error_rate: stats.error_rate,
260
- daily,
261
- };
262
- }
263
- /** Get cost estimate for a period */
264
- costReport(period) {
265
- this.flush();
266
- const targetPeriod = period ?? new Date().toISOString().slice(0, 7);
267
- const tools = this.db.prepare(`
108
+ `).all({tool:_,start:o});return{tool:_,total_calls:t.total_calls,avg_tokens_in:t.avg_tokens_in,avg_tokens_out:t.avg_tokens_out,avg_response_ms:t.avg_response_ms,cache_hit_rate:t.cache_hit_rate,error_rate:t.error_rate,daily:e}}costReport(_){this.flush();const s=_??new Date().toISOString().slice(0,7),n=this.db.prepare(`
268
109
  SELECT
269
110
  tool_name AS tool,
270
111
  call_count AS calls,
@@ -274,35 +115,7 @@ export class WyrmAnalytics {
274
115
  FROM cost_tracking
275
116
  WHERE period = @period
276
117
  ORDER BY estimated_cost_usd DESC
277
- `).all({ period: targetPeriod });
278
- const total_cost_usd = tools.reduce((sum, t) => sum + t.cost_usd, 0);
279
- // Project monthly cost based on days elapsed in the period
280
- const now = new Date();
281
- const periodYear = parseInt(targetPeriod.slice(0, 4), 10);
282
- const periodMonth = parseInt(targetPeriod.slice(5, 7), 10) - 1;
283
- const periodStart = new Date(periodYear, periodMonth, 1);
284
- const periodEnd = new Date(periodYear, periodMonth + 1, 0); // last day of month
285
- const totalDaysInMonth = periodEnd.getDate();
286
- const elapsed = Math.max(1, Math.ceil((now.getTime() - periodStart.getTime()) / (1000 * 60 * 60 * 24)));
287
- const daysToProject = Math.min(elapsed, totalDaysInMonth);
288
- const projected_monthly_usd = totalDaysInMonth > 0
289
- ? Math.round(((total_cost_usd / daysToProject) * totalDaysInMonth) * 100) / 100
290
- : total_cost_usd;
291
- return {
292
- period: targetPeriod,
293
- tools,
294
- total_cost_usd: Math.round(total_cost_usd * 100) / 100,
295
- projected_monthly_usd,
296
- };
297
- }
298
- /** Clean up old events (retention policy) */
299
- cleanup(retainDays = DEFAULT_RETAIN_DAYS) {
300
- this.flush();
301
- const cutoff = new Date();
302
- cutoff.setDate(cutoff.getDate() - retainDays);
303
- const cutoffStr = cutoff.toISOString().slice(0, 10);
304
- // Aggregate old events into cost_tracking before deleting
305
- const oldEvents = this.db.prepare(`
118
+ `).all({period:s}),o=n.reduce((d,T)=>d+T.cost_usd,0),t=new Date,e=parseInt(s.slice(0,4),10),r=parseInt(s.slice(5,7),10)-1,a=new Date(e,r,1),l=new Date(e,r+1,0).getDate(),u=Math.max(1,Math.ceil((t.getTime()-a.getTime())/(1e3*60*60*24))),E=Math.min(u,l),i=l>0?Math.round(o/E*l*100)/100:o;return{period:s,tools:n,total_cost_usd:Math.round(o*100)/100,projected_monthly_usd:i}}cleanup(_=90){this.flush();const s=new Date;s.setDate(s.getDate()-_);const n=s.toISOString().slice(0,10),o=this.db.prepare(`
306
119
  SELECT
307
120
  STRFTIME('%Y-%m', timestamp) AS period,
308
121
  tool_name,
@@ -315,8 +128,7 @@ export class WyrmAnalytics {
315
128
  FROM usage_events
316
129
  WHERE timestamp < @cutoff
317
130
  GROUP BY STRFTIME('%Y-%m', timestamp), tool_name
318
- `).all({ cutoff: cutoffStr });
319
- const upsertStmt = this.db.prepare(`
131
+ `).all({cutoff:n}),t=this.db.prepare(`
320
132
  INSERT INTO cost_tracking (period, tool_name, call_count, total_tokens_in, total_tokens_out, cached_count, avg_response_ms, error_count, estimated_cost_usd, updated_at)
321
133
  VALUES (@period, @tool_name, @call_count, @total_tokens_in, @total_tokens_out, @cached_count, @avg_response_ms, @error_count, @estimated_cost_usd, datetime('now'))
322
134
  ON CONFLICT(period, tool_name) DO UPDATE SET
@@ -328,41 +140,6 @@ export class WyrmAnalytics {
328
140
  error_count = error_count + @error_count,
329
141
  estimated_cost_usd = estimated_cost_usd + @estimated_cost_usd,
330
142
  updated_at = datetime('now')
331
- `);
332
- const cleanupTxn = this.db.transaction(() => {
333
- for (const row of oldEvents) {
334
- const cost = this.estimateCost(row.total_tokens_in, row.total_tokens_out);
335
- upsertStmt.run({
336
- period: row.period,
337
- tool_name: row.tool_name,
338
- call_count: row.call_count,
339
- total_tokens_in: row.total_tokens_in,
340
- total_tokens_out: row.total_tokens_out,
341
- cached_count: row.cached_count,
342
- avg_response_ms: row.avg_response_ms,
343
- error_count: row.error_count,
344
- estimated_cost_usd: cost,
345
- });
346
- }
347
- const result = this.db.prepare(`
143
+ `);return{deleted:this.db.transaction(()=>{for(const c of o){const l=this.estimateCost(c.total_tokens_in,c.total_tokens_out);t.run({period:c.period,tool_name:c.tool_name,call_count:c.call_count,total_tokens_in:c.total_tokens_in,total_tokens_out:c.total_tokens_out,cached_count:c.cached_count,avg_response_ms:c.avg_response_ms,error_count:c.error_count,estimated_cost_usd:l})}return this.db.prepare(`
348
144
  DELETE FROM usage_events WHERE timestamp < @cutoff
349
- `).run({ cutoff: cutoffStr });
350
- return result.changes;
351
- });
352
- const deleted = cleanupTxn();
353
- return { deleted };
354
- }
355
- /** Shutdown: flush remaining buffer and clear timer */
356
- shutdown() {
357
- clearInterval(this.flushInterval);
358
- this.flush();
359
- }
360
- // ==================== HELPERS ====================
361
- /** Estimate USD cost from token counts (Claude Sonnet rates) */
362
- estimateCost(tokensIn, tokensOut) {
363
- const inputCost = (tokensIn / 1_000_000) * COST_PER_MILLION_INPUT;
364
- const outputCost = (tokensOut / 1_000_000) * COST_PER_MILLION_OUTPUT;
365
- return Math.round((inputCost + outputCost) * 1_000_000) / 1_000_000;
366
- }
367
- }
368
- //# sourceMappingURL=analytics.js.map
145
+ `).run({cutoff:n}).changes})()}}shutdown(){clearInterval(this.flushInterval),this.flush()}estimateCost(_,s){const n=_/1e6*3,o=s/1e6*15;return Math.round((n+o)*1e6)/1e6}}export{k as WyrmAnalytics};
@@ -1,49 +1 @@
1
- /**
2
- * Wyrm attribution read helpers (v7 F2, T008).
3
- *
4
- * @copyright 2026 Ghost Protocol (Pvt) Ltd.
5
- * @license AGPL-3.0-or-later — dual-licensed; commercial terms: ghosts.lk@proton.me. See LICENSE.
6
- *
7
- * Migration 20 adds nullable `agent_id`/`run_id` attribution columns to 9
8
- * tables. Every row written before v7 — and any v7 row written outside a fleet
9
- * run — carries NULL attribution. Article VI: a v6.x DB must open under v7
10
- * with 100% of its rows, and that history must stay legibly attributed, so at
11
- * every READ SITE that surfaces attribution, NULL reads as actor='legacy'.
12
- *
13
- * Precedence when rendering "who did this" (the same order is documented in
14
- * migration 20 next to the events.agent_id column):
15
- * 1. agent_id — machine identity (v7 fleet writes)
16
- * 2. actor — display identity (the existing 6.x column on
17
- * events/audit_log; it is EXTENDED, never replaced)
18
- * 3. LEGACY_ACTOR — 'legacy' (neither set: a pre-v7 row)
19
- *
20
- * Wire paths (eventsForPush, ingestRemoteEvent, replication) intentionally do
21
- * NOT coalesce: NULL stays NULL in storage and on the wire so replication
22
- * round-trips are byte-faithful. 'legacy' is a READ-TIME presentation value
23
- * only — it is never written back to the database.
24
- */
25
- /** What NULL attribution reads as at attribution-surfacing read sites. */
26
- export const LEGACY_ACTOR = 'legacy';
27
- /**
28
- * Read a display actor from a nullable actor column.
29
- * NULL/undefined/blank -> 'legacy'; anything else passes through trimmed.
30
- */
31
- export function readActor(actor) {
32
- const a = typeof actor === 'string' ? actor.trim() : '';
33
- return a !== '' ? a : LEGACY_ACTOR;
34
- }
35
- /**
36
- * Resolve the full attribution for one row using the documented precedence.
37
- * Use this at any read site that surfaces who/which-run produced a row
38
- * (failure_check verdicts, wyrm_stats view=failures, event displays).
39
- */
40
- export function resolveAttribution(row) {
41
- const agentId = row.agent_id ?? null;
42
- const runId = row.run_id ?? null;
43
- return {
44
- actor: agentId ?? readActor(row.actor),
45
- agent_id: agentId,
46
- run_id: runId,
47
- };
48
- }
49
- //# sourceMappingURL=attribution.js.map
1
+ const e="legacy";function o(t){const n=typeof t=="string"?t.trim():"";return n!==""?n:e}function i(t){const n=t.agent_id??null,r=t.run_id??null;return{actor:n??o(t.actor),agent_id:n,run_id:r}}export{e as LEGACY_ACTOR,o as readActor,i as resolveAttribution};