proofscan 0.10.62 → 0.11.1

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 (199) hide show
  1. package/README.ja.md +1 -0
  2. package/README.md +2 -0
  3. package/dist/a2a/agent-card.d.ts +2 -0
  4. package/dist/a2a/agent-card.d.ts.map +1 -1
  5. package/dist/a2a/agent-card.js +2 -2
  6. package/dist/a2a/agent-card.js.map +1 -1
  7. package/dist/a2a/client.d.ts +74 -12
  8. package/dist/a2a/client.d.ts.map +1 -1
  9. package/dist/a2a/client.js +228 -29
  10. package/dist/a2a/client.js.map +1 -1
  11. package/dist/a2a/normalizer.d.ts +4 -0
  12. package/dist/a2a/normalizer.d.ts.map +1 -1
  13. package/dist/a2a/normalizer.js +7 -4
  14. package/dist/a2a/normalizer.js.map +1 -1
  15. package/dist/a2a/session-manager.d.ts +81 -0
  16. package/dist/a2a/session-manager.d.ts.map +1 -0
  17. package/dist/a2a/session-manager.js +176 -0
  18. package/dist/a2a/session-manager.js.map +1 -0
  19. package/dist/a2a/types.d.ts +60 -0
  20. package/dist/a2a/types.d.ts.map +1 -1
  21. package/dist/cli.d.ts +2 -1
  22. package/dist/cli.d.ts.map +1 -1
  23. package/dist/cli.js +6 -3
  24. package/dist/cli.js.map +1 -1
  25. package/dist/commands/agent.d.ts.map +1 -1
  26. package/dist/commands/agent.js +35 -10
  27. package/dist/commands/agent.js.map +1 -1
  28. package/dist/commands/analyze.d.ts.map +1 -1
  29. package/dist/commands/analyze.js +12 -10
  30. package/dist/commands/analyze.js.map +1 -1
  31. package/dist/commands/connectors.js +2 -2
  32. package/dist/commands/connectors.js.map +1 -1
  33. package/dist/commands/index.d.ts +1 -0
  34. package/dist/commands/index.d.ts.map +1 -1
  35. package/dist/commands/index.js +1 -0
  36. package/dist/commands/index.js.map +1 -1
  37. package/dist/commands/plans.js +1 -1
  38. package/dist/commands/plans.js.map +1 -1
  39. package/dist/commands/record.js +5 -4
  40. package/dist/commands/record.js.map +1 -1
  41. package/dist/commands/rpc.d.ts.map +1 -1
  42. package/dist/commands/rpc.js +90 -28
  43. package/dist/commands/rpc.js.map +1 -1
  44. package/dist/commands/scan.d.ts.map +1 -1
  45. package/dist/commands/scan.js +8 -10
  46. package/dist/commands/scan.js.map +1 -1
  47. package/dist/commands/secrets.d.ts.map +1 -1
  48. package/dist/commands/secrets.js +11 -10
  49. package/dist/commands/secrets.js.map +1 -1
  50. package/dist/commands/sessions.js +2 -2
  51. package/dist/commands/sessions.js.map +1 -1
  52. package/dist/commands/summary.d.ts.map +1 -1
  53. package/dist/commands/summary.js +4 -2
  54. package/dist/commands/summary.js.map +1 -1
  55. package/dist/commands/task.d.ts +14 -0
  56. package/dist/commands/task.d.ts.map +1 -0
  57. package/dist/commands/task.js +520 -0
  58. package/dist/commands/task.js.map +1 -0
  59. package/dist/db/connection.d.ts.map +1 -1
  60. package/dist/db/connection.js +68 -21
  61. package/dist/db/connection.js.map +1 -1
  62. package/dist/db/events-store.d.ts +307 -8
  63. package/dist/db/events-store.d.ts.map +1 -1
  64. package/dist/db/events-store.js +620 -26
  65. package/dist/db/events-store.js.map +1 -1
  66. package/dist/db/proofs-store.d.ts +8 -1
  67. package/dist/db/proofs-store.d.ts.map +1 -1
  68. package/dist/db/proofs-store.js +18 -8
  69. package/dist/db/proofs-store.js.map +1 -1
  70. package/dist/db/schema.d.ts +15 -3
  71. package/dist/db/schema.d.ts.map +1 -1
  72. package/dist/db/schema.js +150 -5
  73. package/dist/db/schema.js.map +1 -1
  74. package/dist/db/tool-analysis.d.ts +15 -3
  75. package/dist/db/tool-analysis.d.ts.map +1 -1
  76. package/dist/db/tool-analysis.js +35 -17
  77. package/dist/db/tool-analysis.js.map +1 -1
  78. package/dist/db/types.d.ts +64 -1
  79. package/dist/db/types.d.ts.map +1 -1
  80. package/dist/filter/fields.d.ts.map +1 -1
  81. package/dist/filter/fields.js +22 -0
  82. package/dist/filter/fields.js.map +1 -1
  83. package/dist/filter/parser.js +2 -2
  84. package/dist/filter/parser.js.map +1 -1
  85. package/dist/filter/types.d.ts +1 -1
  86. package/dist/filter/types.d.ts.map +1 -1
  87. package/dist/html/analytics.test.ts +682 -0
  88. package/dist/html/analytics.ts +499 -0
  89. package/dist/html/browser.ts +39 -0
  90. package/dist/html/index.ts +97 -0
  91. package/dist/html/rpc-inspector.test.ts +529 -0
  92. package/dist/html/rpc-inspector.ts +1700 -0
  93. package/dist/html/templates.js +4 -4
  94. package/dist/html/templates.js.map +1 -1
  95. package/dist/html/templates.test.ts +861 -0
  96. package/dist/html/templates.ts +3163 -0
  97. package/dist/html/trace-viewer.html +624 -0
  98. package/dist/html/types.d.ts +3 -3
  99. package/dist/html/types.d.ts.map +1 -1
  100. package/dist/html/types.ts +491 -0
  101. package/dist/html/utils.ts +107 -0
  102. package/dist/monitor/data/connectors.d.ts.map +1 -1
  103. package/dist/monitor/data/connectors.js +113 -8
  104. package/dist/monitor/data/connectors.js.map +1 -1
  105. package/dist/monitor/data/popl.js +2 -2
  106. package/dist/monitor/data/popl.js.map +1 -1
  107. package/dist/monitor/routes/api.js +2 -2
  108. package/dist/monitor/routes/api.js.map +1 -1
  109. package/dist/monitor/routes/connectors.js +15 -15
  110. package/dist/monitor/routes/connectors.js.map +1 -1
  111. package/dist/monitor/routes/popl.js +5 -5
  112. package/dist/monitor/routes/popl.js.map +1 -1
  113. package/dist/monitor/templates/components.js +2 -2
  114. package/dist/monitor/templates/components.js.map +1 -1
  115. package/dist/monitor/templates/popl.js +4 -4
  116. package/dist/monitor/templates/popl.js.map +1 -1
  117. package/dist/monitor/types.d.ts +2 -2
  118. package/dist/monitor/types.d.ts.map +1 -1
  119. package/dist/proxy/bridge-utils.d.ts +41 -0
  120. package/dist/proxy/bridge-utils.d.ts.map +1 -0
  121. package/dist/proxy/bridge-utils.js +60 -0
  122. package/dist/proxy/bridge-utils.js.map +1 -0
  123. package/dist/proxy/ipc-client.d.ts.map +1 -1
  124. package/dist/proxy/ipc-client.js +1 -2
  125. package/dist/proxy/ipc-client.js.map +1 -1
  126. package/dist/proxy/ipc-server.d.ts.map +1 -1
  127. package/dist/proxy/ipc-server.js +4 -2
  128. package/dist/proxy/ipc-server.js.map +1 -1
  129. package/dist/proxy/mcp-server.d.ts +31 -0
  130. package/dist/proxy/mcp-server.d.ts.map +1 -1
  131. package/dist/proxy/mcp-server.js +393 -4
  132. package/dist/proxy/mcp-server.js.map +1 -1
  133. package/dist/proxy/types.d.ts +95 -0
  134. package/dist/proxy/types.d.ts.map +1 -1
  135. package/dist/secrets/management.d.ts +2 -2
  136. package/dist/secrets/management.d.ts.map +1 -1
  137. package/dist/secrets/management.js +7 -7
  138. package/dist/secrets/management.js.map +1 -1
  139. package/dist/shell/completer.d.ts.map +1 -1
  140. package/dist/shell/completer.js +16 -0
  141. package/dist/shell/completer.js.map +1 -1
  142. package/dist/shell/context-applicator.d.ts.map +1 -1
  143. package/dist/shell/context-applicator.js +32 -0
  144. package/dist/shell/context-applicator.js.map +1 -1
  145. package/dist/shell/filter-mappers.d.ts +5 -1
  146. package/dist/shell/filter-mappers.d.ts.map +1 -1
  147. package/dist/shell/filter-mappers.js +12 -0
  148. package/dist/shell/filter-mappers.js.map +1 -1
  149. package/dist/shell/find-command.js +13 -13
  150. package/dist/shell/find-command.js.map +1 -1
  151. package/dist/shell/inscribe-commands.js +5 -5
  152. package/dist/shell/inscribe-commands.js.map +1 -1
  153. package/dist/shell/pager/less-pager.d.ts +1 -1
  154. package/dist/shell/pager/less-pager.d.ts.map +1 -1
  155. package/dist/shell/pager/less-pager.js +5 -2
  156. package/dist/shell/pager/less-pager.js.map +1 -1
  157. package/dist/shell/pager/more-pager.d.ts +1 -1
  158. package/dist/shell/pager/more-pager.d.ts.map +1 -1
  159. package/dist/shell/pager/more-pager.js +3 -2
  160. package/dist/shell/pager/more-pager.js.map +1 -1
  161. package/dist/shell/pager/renderer.d.ts.map +1 -1
  162. package/dist/shell/pager/renderer.js +66 -15
  163. package/dist/shell/pager/renderer.js.map +1 -1
  164. package/dist/shell/pager/types.d.ts +5 -2
  165. package/dist/shell/pager/types.d.ts.map +1 -1
  166. package/dist/shell/pager/utils.d.ts +5 -2
  167. package/dist/shell/pager/utils.d.ts.map +1 -1
  168. package/dist/shell/pager/utils.js +14 -17
  169. package/dist/shell/pager/utils.js.map +1 -1
  170. package/dist/shell/pipeline-types.d.ts +12 -4
  171. package/dist/shell/pipeline-types.d.ts.map +1 -1
  172. package/dist/shell/ref-commands.js +7 -7
  173. package/dist/shell/ref-commands.js.map +1 -1
  174. package/dist/shell/ref-resolver.d.ts +15 -15
  175. package/dist/shell/ref-resolver.d.ts.map +1 -1
  176. package/dist/shell/ref-resolver.js +34 -20
  177. package/dist/shell/ref-resolver.js.map +1 -1
  178. package/dist/shell/repl.d.ts +25 -0
  179. package/dist/shell/repl.d.ts.map +1 -1
  180. package/dist/shell/repl.js +285 -51
  181. package/dist/shell/repl.js.map +1 -1
  182. package/dist/shell/router-commands.d.ts +30 -0
  183. package/dist/shell/router-commands.d.ts.map +1 -1
  184. package/dist/shell/router-commands.js +1011 -62
  185. package/dist/shell/router-commands.js.map +1 -1
  186. package/dist/shell/selector.d.ts +1 -1
  187. package/dist/shell/selector.d.ts.map +1 -1
  188. package/dist/shell/selector.js +1 -1
  189. package/dist/shell/selector.js.map +1 -1
  190. package/dist/shell/types.d.ts.map +1 -1
  191. package/dist/shell/types.js +3 -1
  192. package/dist/shell/types.js.map +1 -1
  193. package/dist/shell/where-command.d.ts.map +1 -1
  194. package/dist/shell/where-command.js +19 -3
  195. package/dist/shell/where-command.js.map +1 -1
  196. package/dist/utils/output.d.ts.map +1 -1
  197. package/dist/utils/output.js +7 -1
  198. package/dist/utils/output.js.map +1 -1
  199. package/package.json +2 -2
@@ -13,8 +13,9 @@ export class EventsStore {
13
13
  return getEventsDb(this.configDir);
14
14
  }
15
15
  // ==================== Sessions ====================
16
- createSession(connectorId, options) {
17
- const targetId = options?.targetId || connectorId;
16
+ createSession(targetId, options) {
17
+ // Support legacy connectorId for backward compatibility
18
+ const connectorId = options?.connectorId || targetId;
18
19
  const session = {
19
20
  session_id: randomUUID(),
20
21
  connector_id: connectorId,
@@ -46,20 +47,26 @@ export class EventsStore {
46
47
  const stmt = this.db.prepare(`SELECT * FROM sessions WHERE session_id = ?`);
47
48
  return stmt.get(sessionId);
48
49
  }
49
- getSessionsByConnector(connectorId, limit) {
50
+ getSessionsByTarget(targetId, limit) {
50
51
  let sql = `
51
52
  SELECT s.*,
52
53
  (SELECT COUNT(*) FROM events WHERE session_id = s.session_id) as event_count,
53
54
  (SELECT COUNT(*) FROM rpc_calls WHERE session_id = s.session_id) as rpc_count
54
55
  FROM sessions s
55
- WHERE s.connector_id = ?
56
+ WHERE s.target_id = ?
56
57
  ORDER BY s.started_at DESC
57
58
  `;
58
59
  if (limit) {
59
60
  sql += ` LIMIT ${limit}`;
60
61
  }
61
62
  const stmt = this.db.prepare(sql);
62
- return stmt.all(connectorId);
63
+ return stmt.all(targetId);
64
+ }
65
+ /**
66
+ * @deprecated Use getSessionsByTarget instead
67
+ */
68
+ getSessionsByConnector(connectorId, limit) {
69
+ return this.getSessionsByTarget(connectorId, limit);
63
70
  }
64
71
  getAllSessions(limit) {
65
72
  let sql = `
@@ -155,17 +162,57 @@ export class EventsStore {
155
162
  const stmt = this.db.prepare(sql);
156
163
  return stmt.all(sessionId);
157
164
  }
158
- getRecentEventsByConnector(connectorId, limit = 20) {
165
+ /**
166
+ * Get events with pagination support (Phase 6.2)
167
+ *
168
+ * @param sessionId - Session ID
169
+ * @param options - Pagination options
170
+ * @param options.limit - Maximum number of events to return (default: 50, max: 200)
171
+ * @param options.before - Event ID for pagination cursor (exclusive)
172
+ * @returns Events in descending order (newest first)
173
+ */
174
+ getEvents(sessionId, options = {}) {
175
+ // Enforce max limit of 200
176
+ let limit = options.limit ?? 50;
177
+ if (limit > 200) {
178
+ limit = 200;
179
+ }
180
+ let sql = `SELECT * FROM events WHERE session_id = ?`;
181
+ const params = [sessionId];
182
+ // Exclusive cursor: get events older than the specified event_id
183
+ // Use composite cursor (ts, event_id) for stable pagination with same-timestamp events
184
+ if (options.before) {
185
+ const cursorStmt = this.db.prepare(`SELECT ts, event_id FROM events WHERE event_id = ?`);
186
+ const cursorEvent = cursorStmt.get(options.before);
187
+ if (cursorEvent) {
188
+ // Events with earlier timestamp, OR same timestamp but earlier event_id
189
+ sql += ` AND (ts < ? OR (ts = ? AND event_id < ?))`;
190
+ params.push(cursorEvent.ts, cursorEvent.ts, cursorEvent.event_id);
191
+ }
192
+ }
193
+ // Order by ts DESC, event_id DESC for deterministic ordering with same-timestamp events
194
+ sql += ` ORDER BY ts DESC, event_id DESC LIMIT ?`;
195
+ params.push(limit);
196
+ const stmt = this.db.prepare(sql);
197
+ return stmt.all(...params);
198
+ }
199
+ getRecentEventsByTarget(targetId, limit = 20) {
159
200
  const stmt = this.db.prepare(`
160
201
  SELECT e.* FROM events e
161
202
  JOIN sessions s ON e.session_id = s.session_id
162
- WHERE s.connector_id = ?
203
+ WHERE s.target_id = ?
163
204
  ORDER BY e.ts DESC
164
205
  LIMIT ?
165
206
  `);
166
- const events = stmt.all(connectorId, limit);
207
+ const events = stmt.all(targetId, limit);
167
208
  return events.reverse(); // Return in chronological order
168
209
  }
210
+ /**
211
+ * @deprecated Use getRecentEventsByTarget instead
212
+ */
213
+ getRecentEventsByConnector(connectorId, limit = 20) {
214
+ return this.getRecentEventsByTarget(connectorId, limit);
215
+ }
169
216
  // ==================== RPC Calls ====================
170
217
  saveRpcCall(sessionId, rpcId, method) {
171
218
  const rpcCall = {
@@ -203,19 +250,21 @@ export class EventsStore {
203
250
  * Get sessions that can be pruned (not protected)
204
251
  */
205
252
  getPruneCandidates(options = {}) {
206
- const { keepLast, before, connectorId } = options;
253
+ const { keepLast, before, targetId, connectorId } = options;
207
254
  const candidates = [];
255
+ // Use targetId if provided, otherwise fall back to connectorId
256
+ const filterId = targetId || connectorId;
208
257
  // Get all unprotected sessions
209
258
  let sql = `
210
- SELECT s.session_id, s.connector_id, s.started_at, s.protected,
259
+ SELECT s.session_id, s.target_id as connector_id, s.started_at, s.protected,
211
260
  (SELECT COUNT(*) FROM events WHERE session_id = s.session_id) as event_count
212
261
  FROM sessions s
213
262
  WHERE s.protected = 0
214
263
  `;
215
264
  const params = [];
216
- if (connectorId) {
217
- sql += ` AND s.connector_id = ?`;
218
- params.push(connectorId);
265
+ if (filterId) {
266
+ sql += ` AND s.target_id = ?`;
267
+ params.push(filterId);
219
268
  }
220
269
  if (before) {
221
270
  sql += ` AND s.started_at < ?`;
@@ -429,15 +478,15 @@ export class EventsStore {
429
478
  });
430
479
  }
431
480
  /**
432
- * Get latest session (optionally for a specific connector)
481
+ * Get latest session (optionally for a specific target)
433
482
  * Used by RefResolver
434
483
  */
435
- getLatestSession(connectorId) {
436
- let sql = `SELECT session_id, connector_id FROM sessions`;
484
+ getLatestSession(targetId) {
485
+ let sql = `SELECT session_id, target_id FROM sessions`;
437
486
  const params = [];
438
- if (connectorId) {
439
- sql += ` WHERE connector_id = ?`;
440
- params.push(connectorId);
487
+ if (targetId) {
488
+ sql += ` WHERE target_id = ?`;
489
+ params.push(targetId);
441
490
  }
442
491
  sql += ` ORDER BY started_at DESC LIMIT 1`;
443
492
  const stmt = this.db.prepare(sql);
@@ -474,23 +523,23 @@ export class EventsStore {
474
523
  * Get session by ID or prefix
475
524
  * Used by RefResolver
476
525
  */
477
- getSessionByPrefix(prefix, connectorId) {
526
+ getSessionByPrefix(prefix, targetId) {
478
527
  // Try exact match first
479
- let stmt = this.db.prepare(`SELECT session_id, connector_id FROM sessions WHERE session_id = ?`);
528
+ let stmt = this.db.prepare(`SELECT session_id, target_id FROM sessions WHERE session_id = ?`);
480
529
  let result = stmt.get(prefix);
481
530
  if (result) {
482
- if (connectorId && result.connector_id !== connectorId) {
531
+ if (targetId && result.target_id !== targetId) {
483
532
  return null; // Wrong connector
484
533
  }
485
534
  return result;
486
535
  }
487
536
  // Try prefix match (escape SQL wildcards in user input)
488
537
  const escapedPrefix = prefix.replace(/[%_]/g, '\\$&');
489
- let sql = `SELECT session_id, connector_id FROM sessions WHERE session_id LIKE ? ESCAPE '\\'`;
538
+ let sql = `SELECT session_id, target_id FROM sessions WHERE session_id LIKE ? ESCAPE '\\'`;
490
539
  const params = [escapedPrefix + '%'];
491
- if (connectorId) {
492
- sql += ` AND connector_id = ?`;
493
- params.push(connectorId);
540
+ if (targetId) {
541
+ sql += ` AND target_id = ?`;
542
+ params.push(targetId);
494
543
  }
495
544
  sql += ` ORDER BY started_at DESC LIMIT 1`;
496
545
  stmt = this.db.prepare(sql);
@@ -536,5 +585,550 @@ export class EventsStore {
536
585
  response: response || undefined,
537
586
  };
538
587
  }
588
+ // ==================== A2A Sessions (Phase 7.0) ====================
589
+ /**
590
+ * Get A2A sessions for a target
591
+ *
592
+ * A2A sessions are sessions with actor_kind = 'agent'
593
+ *
594
+ * @param targetId - Target ID (agent ID)
595
+ * @param limit - Maximum number of sessions to return
596
+ * @returns Array of sessions with message count and last activity
597
+ */
598
+ getA2ASessions(targetId, limit = 50) {
599
+ const sql = `
600
+ SELECT
601
+ s.session_id,
602
+ (SELECT COUNT(*) FROM events WHERE session_id = s.session_id AND (normalized_json LIKE '%"actor":"user"%' OR normalized_json LIKE '%"actor":"assistant"%')) as message_count,
603
+ COALESCE(
604
+ (SELECT ts FROM events WHERE session_id = s.session_id ORDER BY ts DESC LIMIT 1),
605
+ s.started_at
606
+ ) as last_activity
607
+ FROM sessions s
608
+ WHERE s.target_id = ? AND s.actor_kind = 'agent'
609
+ ORDER BY last_activity DESC
610
+ LIMIT ?
611
+ `;
612
+ const stmt = this.db.prepare(sql);
613
+ return stmt.all(targetId, limit);
614
+ }
615
+ /**
616
+ * Get A2A messages for a session
617
+ *
618
+ * Returns messages with role, content, and timestamp from normalized_json
619
+ *
620
+ * @param sessionId - Session ID
621
+ * @param limit - Maximum number of messages to return
622
+ * @returns Array of A2A messages
623
+ */
624
+ getA2AMessages(sessionId, limit = 100) {
625
+ const sql = `
626
+ SELECT
627
+ e.event_id,
628
+ e.normalized_json,
629
+ e.raw_json,
630
+ e.ts
631
+ FROM events e
632
+ WHERE e.session_id = ?
633
+ AND e.normalized_json IS NOT NULL
634
+ AND (e.normalized_json LIKE '%"actor":"user"%' OR e.normalized_json LIKE '%"actor":"assistant"%')
635
+ ORDER BY e.ts ASC
636
+ LIMIT ?
637
+ `;
638
+ const stmt = this.db.prepare(sql);
639
+ const events = stmt.all(sessionId, limit);
640
+ const messages = [];
641
+ for (let i = 0; i < events.length; i++) {
642
+ const event = events[i];
643
+ let role = 'user';
644
+ let content = '';
645
+ if (event.normalized_json) {
646
+ try {
647
+ const normalized = JSON.parse(event.normalized_json);
648
+ if (normalized.actor === 'assistant') {
649
+ role = 'assistant';
650
+ }
651
+ if (normalized.content && normalized.content.type === 'text') {
652
+ content = normalized.content.text || '';
653
+ }
654
+ }
655
+ catch {
656
+ // If parsing fails, try raw_json
657
+ if (event.raw_json) {
658
+ try {
659
+ const raw = JSON.parse(event.raw_json);
660
+ // Raw format: { jsonrpc: '2.0', id: '...', result: { role: '...', parts: [...] } }
661
+ const result = raw.result || raw;
662
+ if (result.role === 'assistant') {
663
+ role = 'assistant';
664
+ }
665
+ if (result.parts && Array.isArray(result.parts)) {
666
+ content = result.parts
667
+ .filter((p) => p && typeof p === 'object' && 'text' in p)
668
+ .map((p) => p.text)
669
+ .join('');
670
+ }
671
+ }
672
+ catch {
673
+ // Parsing failed, use summary or empty
674
+ content = '';
675
+ }
676
+ }
677
+ }
678
+ }
679
+ messages.push({
680
+ id: i + 1,
681
+ role,
682
+ content,
683
+ timestamp: event.ts,
684
+ rawJson: event.raw_json,
685
+ });
686
+ }
687
+ return messages;
688
+ }
689
+ /**
690
+ * Get A2A message detail by index
691
+ *
692
+ * @param sessionId - Session ID
693
+ * @param index - Message index (1-based)
694
+ * @returns Message detail or null if not found
695
+ */
696
+ getA2AMessageByIndex(sessionId, index) {
697
+ const messages = this.getA2AMessages(sessionId, index);
698
+ return messages[index - 1] || null;
699
+ }
700
+ /**
701
+ * Get A2A session by session ID (with metadata)
702
+ *
703
+ * @param sessionId - Session ID (or prefix)
704
+ * @param targetId - Optional target ID for filtering
705
+ * @returns Session or null
706
+ */
707
+ getA2ASessionById(sessionId, targetId) {
708
+ let sql = `
709
+ SELECT
710
+ s.session_id,
711
+ s.target_id,
712
+ s.started_at,
713
+ (SELECT COUNT(*) FROM events WHERE session_id = s.session_id AND (normalized_json LIKE '%"actor":"user"%' OR normalized_json LIKE '%"actor":"assistant"%')) as message_count,
714
+ COALESCE(
715
+ (SELECT ts FROM events WHERE session_id = s.session_id ORDER BY ts DESC LIMIT 1),
716
+ s.started_at
717
+ ) as last_activity
718
+ FROM sessions s
719
+ WHERE s.session_id LIKE ? AND s.actor_kind = 'agent'
720
+ `;
721
+ const params = [sessionId + '%'];
722
+ if (targetId) {
723
+ sql += ` AND s.target_id = ?`;
724
+ params.push(targetId);
725
+ }
726
+ sql += ` ORDER BY s.started_at DESC LIMIT 1`;
727
+ const stmt = this.db.prepare(sql);
728
+ return stmt.get(...params);
729
+ }
730
+ /**
731
+ * Get A2A messages across all sessions for a target (agent)
732
+ *
733
+ * Phase 2.3.1: Cross-session history search
734
+ *
735
+ * Returns messages in descending timestamp order (newest first)
736
+ *
737
+ * @param targetId - Target ID (agent ID)
738
+ * @param limit - Maximum number of messages to return
739
+ * @returns Array of A2A messages with session ID
740
+ */
741
+ getA2AMessagesForTarget(targetId, limit) {
742
+ const sql = `
743
+ SELECT
744
+ e.session_id,
745
+ e.ts,
746
+ json_extract(e.normalized_json, '$.actor') as role,
747
+ json_extract(e.normalized_json, '$.content.text') as content
748
+ FROM events e
749
+ JOIN sessions s ON e.session_id = s.session_id
750
+ WHERE s.target_id = ?
751
+ AND e.normalized_json IS NOT NULL
752
+ AND (json_extract(e.normalized_json, '$.actor') = 'user'
753
+ OR json_extract(e.normalized_json, '$.actor') = 'assistant')
754
+ ORDER BY e.ts DESC
755
+ LIMIT ?
756
+ `;
757
+ const stmt = this.db.prepare(sql);
758
+ const rows = stmt.all(targetId, limit);
759
+ const messages = [];
760
+ for (let i = 0; i < rows.length; i++) {
761
+ const row = rows[i];
762
+ messages.push({
763
+ id: i + 1,
764
+ sessionId: row.session_id,
765
+ role: (row.role === 'assistant' ? 'assistant' : 'user'),
766
+ content: row.content || '',
767
+ timestamp: row.ts,
768
+ });
769
+ }
770
+ // Return in descending order (newest first)
771
+ return messages;
772
+ }
773
+ // ==================== Task Events (Phase 2.4) ====================
774
+ /**
775
+ * Normalize task status string to TaskStatus
776
+ * @private
777
+ */
778
+ normalizeTaskStatus(status) {
779
+ if (typeof status !== 'string')
780
+ return 'pending';
781
+ const validStatuses = [
782
+ 'pending',
783
+ 'working',
784
+ 'input_required',
785
+ 'completed',
786
+ 'failed',
787
+ 'canceled',
788
+ 'rejected',
789
+ ];
790
+ if (validStatuses.includes(status)) {
791
+ return status;
792
+ }
793
+ return 'pending';
794
+ }
795
+ /**
796
+ * Save a task event
797
+ *
798
+ * @param sessionId - Session ID
799
+ * @param taskEventKind - Task event kind
800
+ * @param payload - Task event payload
801
+ * @returns Task event record
802
+ */
803
+ saveTaskEvent(sessionId, taskEventKind, payload) {
804
+ const event = {
805
+ event_id: randomUUID(),
806
+ session_id: sessionId,
807
+ task_id: payload.taskId,
808
+ event_kind: taskEventKind,
809
+ ts: new Date().toISOString(),
810
+ payload_json: JSON.stringify(payload),
811
+ };
812
+ const stmt = this.db.prepare(`
813
+ INSERT INTO task_events (event_id, session_id, task_id, event_kind, ts, payload_json)
814
+ VALUES (?, ?, ?, ?, ?, ?)
815
+ `);
816
+ stmt.run(event.event_id, event.session_id, event.task_id, event.event_kind, event.ts, event.payload_json);
817
+ return event;
818
+ }
819
+ /**
820
+ * Get task events for a session
821
+ *
822
+ * @param sessionId - Session ID
823
+ * @param limit - Maximum number of events to return
824
+ * @returns Task events in chronological order
825
+ */
826
+ getTaskEventsBySession(sessionId, limit) {
827
+ let sql = `SELECT * FROM task_events WHERE session_id = ? ORDER BY ts ASC`;
828
+ if (limit) {
829
+ sql += ` LIMIT ${limit}`;
830
+ }
831
+ const stmt = this.db.prepare(sql);
832
+ return stmt.all(sessionId);
833
+ }
834
+ /**
835
+ * Get task events for a specific task
836
+ *
837
+ * @param taskId - Task ID
838
+ * @returns Task events for the task in chronological order
839
+ */
840
+ getTaskEventsByTaskId(taskId) {
841
+ const stmt = this.db.prepare(`
842
+ SELECT * FROM task_events WHERE task_id = ? ORDER BY ts ASC
843
+ `);
844
+ return stmt.all(taskId);
845
+ }
846
+ /**
847
+ * Get recent task events across all sessions
848
+ *
849
+ * @param limit - Maximum number of events to return
850
+ * @returns Task events in descending order (newest first)
851
+ */
852
+ getRecentTaskEvents(limit = 20) {
853
+ const stmt = this.db.prepare(`
854
+ SELECT * FROM task_events ORDER BY ts DESC LIMIT ?
855
+ `);
856
+ const events = stmt.all(limit);
857
+ return events.reverse(); // Return in chronological order (oldest first)
858
+ }
859
+ /**
860
+ * Get all task events for a target (agent)
861
+ *
862
+ * @param targetId - Target ID (agent ID)
863
+ * @param limit - Maximum number of events to return
864
+ * @returns Task events in chronological order
865
+ */
866
+ getTaskEventsByTarget(targetId, limit = 100) {
867
+ const stmt = this.db.prepare(`
868
+ SELECT te.* FROM task_events te
869
+ JOIN sessions s ON te.session_id = s.session_id
870
+ WHERE s.target_id = ?
871
+ ORDER BY te.ts ASC
872
+ LIMIT ?
873
+ `);
874
+ return stmt.all(targetId, limit);
875
+ }
876
+ /**
877
+ * Get the last recorded status for a task
878
+ *
879
+ * @param taskId - Task ID
880
+ * @returns Last task event or null if not found
881
+ */
882
+ getLastTaskEvent(taskId) {
883
+ const stmt = this.db.prepare(`
884
+ SELECT * FROM task_events
885
+ WHERE task_id = ?
886
+ ORDER BY ts DESC
887
+ LIMIT 1
888
+ `);
889
+ return stmt.get(taskId);
890
+ }
891
+ /**
892
+ * Record task creation event
893
+ *
894
+ * @param sessionId - Session ID
895
+ * @param taskId - Task ID
896
+ * @param rawStatus - Raw status string from response
897
+ */
898
+ recordTaskCreated(sessionId, taskId, rawStatus) {
899
+ const status = this.normalizeTaskStatus(rawStatus);
900
+ this.saveTaskEvent(sessionId, 'a2a:task:created', {
901
+ taskId,
902
+ rawStatus,
903
+ status,
904
+ });
905
+ }
906
+ /**
907
+ * Record task status update event
908
+ *
909
+ * Only records if status actually changed (no duplicate status events)
910
+ *
911
+ * @param sessionId - Session ID
912
+ * @param taskId - Task ID
913
+ * @param rawStatus - New raw status string
914
+ * @returns True if event was recorded, false if status unchanged
915
+ */
916
+ recordTaskUpdated(sessionId, taskId, rawStatus) {
917
+ const status = this.normalizeTaskStatus(rawStatus);
918
+ // Check last recorded status to avoid duplicate events
919
+ const lastEvent = this.getLastTaskEvent(taskId);
920
+ if (lastEvent) {
921
+ const lastPayload = JSON.parse(lastEvent.payload_json);
922
+ if (lastPayload.status === status) {
923
+ // Status unchanged, don't record
924
+ return false;
925
+ }
926
+ }
927
+ this.saveTaskEvent(sessionId, 'a2a:task:updated', {
928
+ taskId,
929
+ rawStatus,
930
+ status,
931
+ previousStatus: lastEvent
932
+ ? JSON.parse(lastEvent.payload_json).status
933
+ : undefined,
934
+ });
935
+ return true;
936
+ }
937
+ /**
938
+ * Record task completion event
939
+ *
940
+ * @param sessionId - Session ID
941
+ * @param taskId - Task ID
942
+ * @param rawStatus - Raw status string
943
+ * @param messages - Messages (optional)
944
+ * @param artifacts - Artifacts (optional)
945
+ */
946
+ recordTaskCompleted(sessionId, taskId, rawStatus, messages, artifacts) {
947
+ this.saveTaskEvent(sessionId, 'a2a:task:completed', {
948
+ taskId,
949
+ rawStatus,
950
+ status: 'completed',
951
+ messages,
952
+ artifacts,
953
+ });
954
+ }
955
+ /**
956
+ * Record task failure event
957
+ *
958
+ * @param sessionId - Session ID
959
+ * @param taskId - Task ID
960
+ * @param rawStatus - Raw status string
961
+ * @param error - Error message
962
+ */
963
+ recordTaskFailed(sessionId, taskId, rawStatus, error) {
964
+ this.saveTaskEvent(sessionId, 'a2a:task:failed', {
965
+ taskId,
966
+ rawStatus,
967
+ status: 'failed',
968
+ error,
969
+ });
970
+ }
971
+ /**
972
+ * Record task cancellation event
973
+ *
974
+ * @param sessionId - Session ID
975
+ * @param taskId - Task ID
976
+ * @param rawStatus - Raw status string
977
+ */
978
+ recordTaskCanceled(sessionId, taskId, rawStatus) {
979
+ this.saveTaskEvent(sessionId, 'a2a:task:canceled', {
980
+ taskId,
981
+ rawStatus,
982
+ status: 'canceled',
983
+ });
984
+ }
985
+ /**
986
+ * Record task wait timeout event
987
+ *
988
+ * @param sessionId - Session ID
989
+ * @param taskId - Task ID
990
+ * @param error - Error message
991
+ */
992
+ recordTaskWaitTimeout(sessionId, taskId, error) {
993
+ this.saveTaskEvent(sessionId, 'a2a:task:wait_timeout', {
994
+ taskId,
995
+ rawStatus: 'timeout',
996
+ status: 'failed',
997
+ error: error || 'Task wait timeout',
998
+ });
999
+ }
1000
+ /**
1001
+ * Record task poll error event
1002
+ *
1003
+ * @param sessionId - Session ID
1004
+ * @param taskId - Task ID
1005
+ * @param error - Error message
1006
+ */
1007
+ recordTaskPollError(sessionId, taskId, error) {
1008
+ this.saveTaskEvent(sessionId, 'a2a:task:poll_error', {
1009
+ taskId,
1010
+ rawStatus: 'poll_error',
1011
+ status: 'failed',
1012
+ error: error || 'Task poll error',
1013
+ });
1014
+ }
1015
+ // ==================== UI Events (Phase 6.2) ====================
1016
+ /**
1017
+ * Save a UI tool request event
1018
+ *
1019
+ * @param uiSessionId - UI session ID (derived from sessionToken)
1020
+ * @param uiRpcId - UI RPC ID
1021
+ * @param correlationId - Correlation ID
1022
+ * @param toolCallFingerprint - Tool call fingerprint
1023
+ * @param toolName - Tool name
1024
+ * @param payload - Event payload (arguments, sessionToken, etc.)
1025
+ * @returns UI event record
1026
+ */
1027
+ saveUiToolRequestEvent(uiSessionId, uiRpcId, correlationId, toolCallFingerprint, toolName, payload) {
1028
+ const event = {
1029
+ event_id: randomUUID(),
1030
+ ui_session_id: uiSessionId,
1031
+ ui_rpc_id: uiRpcId,
1032
+ correlation_id: correlationId,
1033
+ tool_call_fingerprint: toolCallFingerprint,
1034
+ event_type: 'ui_tool_request',
1035
+ tool_name: toolName,
1036
+ ts: Date.now(),
1037
+ payload_json: JSON.stringify(payload),
1038
+ };
1039
+ const stmt = this.db.prepare(`
1040
+ INSERT INTO ui_events (event_id, ui_session_id, ui_rpc_id, correlation_id, tool_call_fingerprint, event_type, tool_name, ts, payload_json)
1041
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
1042
+ `);
1043
+ stmt.run(event.event_id, event.ui_session_id, event.ui_rpc_id, event.correlation_id, event.tool_call_fingerprint, event.event_type, event.tool_name, event.ts, event.payload_json);
1044
+ return { event_id: event.event_id, ts: event.ts };
1045
+ }
1046
+ /**
1047
+ * Save a UI tool result event
1048
+ *
1049
+ * @param uiSessionId - UI session ID
1050
+ * @param uiRpcId - UI RPC ID
1051
+ * @param correlationId - Correlation ID
1052
+ * @param toolCallFingerprint - Tool call fingerprint
1053
+ * @param payload - Event payload (result, duration_ms, etc.)
1054
+ * @returns UI event record
1055
+ */
1056
+ saveUiToolResultEvent(uiSessionId, uiRpcId, correlationId, toolCallFingerprint, payload) {
1057
+ const event = {
1058
+ event_id: randomUUID(),
1059
+ ui_session_id: uiSessionId,
1060
+ ui_rpc_id: uiRpcId,
1061
+ correlation_id: correlationId,
1062
+ tool_call_fingerprint: toolCallFingerprint,
1063
+ event_type: 'ui_tool_result',
1064
+ tool_name: null,
1065
+ ts: Date.now(),
1066
+ payload_json: JSON.stringify(payload),
1067
+ };
1068
+ const stmt = this.db.prepare(`
1069
+ INSERT INTO ui_events (event_id, ui_session_id, ui_rpc_id, correlation_id, tool_call_fingerprint, event_type, tool_name, ts, payload_json)
1070
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
1071
+ `);
1072
+ stmt.run(event.event_id, event.ui_session_id, event.ui_rpc_id, event.correlation_id, event.tool_call_fingerprint, event.event_type, event.tool_name, event.ts, event.payload_json);
1073
+ return { event_id: event.event_id, ts: event.ts };
1074
+ }
1075
+ /**
1076
+ * Save a UI tool delivered event (sent to UI)
1077
+ *
1078
+ * @param uiSessionId - UI session ID
1079
+ * @param uiRpcId - UI RPC ID
1080
+ * @param correlationId - Correlation ID
1081
+ * @param toolCallFingerprint - Tool call fingerprint
1082
+ * @param payload - Event payload (result)
1083
+ * @returns UI event record
1084
+ */
1085
+ saveUiToolDeliveredEvent(uiSessionId, uiRpcId, correlationId, toolCallFingerprint, payload) {
1086
+ const event = {
1087
+ event_id: randomUUID(),
1088
+ ui_session_id: uiSessionId,
1089
+ ui_rpc_id: uiRpcId,
1090
+ correlation_id: correlationId,
1091
+ tool_call_fingerprint: toolCallFingerprint,
1092
+ event_type: 'ui_tool_delivered',
1093
+ tool_name: null,
1094
+ ts: Date.now(),
1095
+ payload_json: JSON.stringify(payload),
1096
+ };
1097
+ const stmt = this.db.prepare(`
1098
+ INSERT INTO ui_events (event_id, ui_session_id, ui_rpc_id, correlation_id, tool_call_fingerprint, event_type, tool_name, ts, payload_json)
1099
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
1100
+ `);
1101
+ stmt.run(event.event_id, event.ui_session_id, event.ui_rpc_id, event.correlation_id, event.tool_call_fingerprint, event.event_type, event.tool_name, event.ts, event.payload_json);
1102
+ return { event_id: event.event_id, ts: event.ts };
1103
+ }
1104
+ /**
1105
+ * Get UI events by correlation ID
1106
+ *
1107
+ * @param correlationId - Correlation ID
1108
+ * @returns UI events with matching correlation ID
1109
+ */
1110
+ getUiEventsByCorrelationId(correlationId) {
1111
+ const stmt = this.db.prepare(`
1112
+ SELECT * FROM ui_events WHERE correlation_id = ? ORDER BY ts ASC
1113
+ `);
1114
+ return stmt.all(correlationId);
1115
+ }
1116
+ /**
1117
+ * Get UI events by session ID
1118
+ *
1119
+ * @param uiSessionId - UI session ID
1120
+ * @param limit - Maximum number of events to return
1121
+ * @returns UI events for the session
1122
+ */
1123
+ getUiEventsBySession(uiSessionId, limit = 100) {
1124
+ const sql = `
1125
+ SELECT * FROM ui_events
1126
+ WHERE ui_session_id = ?
1127
+ ORDER BY ts DESC
1128
+ LIMIT ?
1129
+ `;
1130
+ const stmt = this.db.prepare(sql);
1131
+ return stmt.all(uiSessionId, limit);
1132
+ }
539
1133
  }
540
1134
  //# sourceMappingURL=events-store.js.map