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
@@ -5,11 +5,12 @@ import * as readline from 'readline';
5
5
  import { spawn } from 'child_process';
6
6
  import { SHELL_BUILTINS, TOP_LEVEL_COMMANDS, ROUTER_COMMANDS, BLOCKED_IN_SHELL, BLOCKED_SUBCOMMANDS_IN_SHELL, DEFAULT_COMPLETION_LIMIT, } from './types.js';
7
7
  import { applyContext } from './context-applicator.js';
8
- import { handleCc, handleUp, handlePwd, handleLs, handleShow, } from './router-commands.js';
8
+ import { handleCc, handleUp, handlePwd, handleLs, handleShow, handleA2ASend, handleHistory, } from './router-commands.js';
9
9
  import { generatePrompt, printSuccess, printError, printInfo, shortenSessionId } from './prompt.js';
10
10
  import { loadHistory, saveHistory, addToHistory } from './history.js';
11
11
  import { createCompleter } from './completer.js';
12
12
  import { EventLineStore } from '../eventline/store.js';
13
+ import { TargetsStore } from '../db/targets-store.js';
13
14
  import { ConfigManager } from '../config/index.js';
14
15
  import { getCurrentSession, clearCurrentSession, } from '../utils/state.js';
15
16
  import { handleTool, handleSend } from './tool-commands.js';
@@ -93,6 +94,35 @@ export class ShellRepl {
93
94
  this.rpcsCache.clear();
94
95
  this.poplEntriesCache = null;
95
96
  }
97
+ /**
98
+ * Get all connector IDs (MCP connectors with sessions + A2A agents)
99
+ * Note: This is synchronous for readline completer compatibility.
100
+ * Agent IDs are loaded asynchronously and cached.
101
+ */
102
+ getAllConnectorIds(configDir) {
103
+ const now = Date.now();
104
+ if (this.connectorsCache && this.connectorsCache.expiry > now) {
105
+ return this.connectorsCache.data;
106
+ }
107
+ try {
108
+ const store = new EventLineStore(configDir);
109
+ const sessionIds = store.getConnectors().map(c => c.id);
110
+ // Also include A2A agents from TargetsStore (loaded synchronously via static import)
111
+ let agentIds = [];
112
+ try {
113
+ const ts = new TargetsStore(configDir);
114
+ agentIds = ts.list({ type: 'agent' }).map((a) => a.id);
115
+ }
116
+ catch { /* ignore if TargetsStore unavailable */ }
117
+ // Merge and deduplicate
118
+ const ids = [...new Set([...sessionIds, ...agentIds])];
119
+ this.connectorsCache = { data: ids, expiry: now + CACHE_TTL_MS };
120
+ return ids;
121
+ }
122
+ catch {
123
+ return [];
124
+ }
125
+ }
96
126
  /**
97
127
  * Get data provider for configure mode completions
98
128
  */
@@ -100,21 +130,7 @@ export class ShellRepl {
100
130
  const manager = new ConfigManager(this.configPath);
101
131
  const configDir = manager.getConfigDir();
102
132
  return {
103
- getConnectorIds: () => {
104
- const now = Date.now();
105
- if (this.connectorsCache && this.connectorsCache.expiry > now) {
106
- return this.connectorsCache.data;
107
- }
108
- try {
109
- const store = new EventLineStore(configDir);
110
- const ids = store.getConnectors().map(c => c.id);
111
- this.connectorsCache = { data: ids, expiry: now + CACHE_TTL_MS };
112
- return ids;
113
- }
114
- catch {
115
- return [];
116
- }
117
- },
133
+ getConnectorIds: () => this.getAllConnectorIds(configDir),
118
134
  };
119
135
  }
120
136
  /**
@@ -124,21 +140,7 @@ export class ShellRepl {
124
140
  const manager = new ConfigManager(this.configPath);
125
141
  const configDir = manager.getConfigDir();
126
142
  return {
127
- getConnectorIds: () => {
128
- const now = Date.now();
129
- if (this.connectorsCache && this.connectorsCache.expiry > now) {
130
- return this.connectorsCache.data;
131
- }
132
- try {
133
- const store = new EventLineStore(configDir);
134
- const ids = store.getConnectors().map(c => c.id);
135
- this.connectorsCache = { data: ids, expiry: now + CACHE_TTL_MS };
136
- return ids;
137
- }
138
- catch {
139
- return [];
140
- }
141
- },
143
+ getConnectorIds: () => this.getAllConnectorIds(configDir),
142
144
  getSessionPrefixes: (connectorId, limit = DEFAULT_COMPLETION_LIMIT) => {
143
145
  const now = Date.now();
144
146
  const cacheKey = `${connectorId || '*'}:${limit}`;
@@ -314,13 +316,34 @@ export class ShellRepl {
314
316
  await handleTool(args, this.context, this.configPath);
315
317
  return;
316
318
  }
317
- // Handle send command (shell-native with interactive input)
319
+ // Handle history command (A2A session message history)
320
+ if (command === 'history') {
321
+ await handleHistory(args, this.context, this.configPath);
322
+ return;
323
+ }
324
+ // Handle send command (A2A or MCP tool)
318
325
  if (command === 'send') {
319
- if (!this.rl) {
320
- printError('Shell not initialized');
321
- return;
326
+ // Check if current target is an A2A agent
327
+ let isA2A = false;
328
+ if (this.context.connector) {
329
+ try {
330
+ const configDir = this.configPath.replace(/\/[^/]+$/, '');
331
+ const { TargetsStore } = await import('../db/targets-store.js');
332
+ const ts = new TargetsStore(configDir);
333
+ isA2A = ts.list({ type: 'agent' }).some(a => a.id === this.context.connector);
334
+ }
335
+ catch { /* ignore */ }
336
+ }
337
+ if (isA2A) {
338
+ await handleA2ASend(args, this.context, this.configPath);
339
+ }
340
+ else {
341
+ if (!this.rl) {
342
+ printError('Shell not initialized');
343
+ return;
344
+ }
345
+ await handleSend(args, this.context, this.configPath, this.rl);
322
346
  }
323
- await handleSend(args, this.context, this.configPath, this.rl);
324
347
  return;
325
348
  }
326
349
  // Handle ref command (shell-native)
@@ -382,6 +405,9 @@ export class ShellRepl {
382
405
  case 'find':
383
406
  await this.handleFind(args);
384
407
  break;
408
+ case 'history':
409
+ await handleHistory(args, this.context, this.configPath);
410
+ break;
385
411
  }
386
412
  }
387
413
  /**
@@ -480,6 +506,12 @@ Session Control:
480
506
  clear Clear screen
481
507
  exit Exit shell
482
508
 
509
+ A2A Session Commands:
510
+ history Show message history (A2A sessions only)
511
+ history -n 20 Show last 20 messages
512
+ history --role user Show only user messages
513
+ history --search <query> Search messages
514
+
483
515
  CLI Commands (also available here):
484
516
  view, tree, scan, summary, rpc, analyze, tool
485
517
  config, connectors, secrets, catalog, archive, doctor
@@ -589,6 +621,13 @@ Session Control:
589
621
  clear Clear screen
590
622
  exit, quit Exit shell
591
623
 
624
+ A2A Session Commands (history):
625
+ history Show A2A message history
626
+ history -n <count> Show last N messages (default: 100)
627
+ history --role user Show only user messages
628
+ history --role assistant Show only assistant messages
629
+ history --search <query> Search messages by text
630
+
592
631
  CLI Commands (passthrough to pfscan):
593
632
  view (v) View recent events timeline (use -f for follow mode)
594
633
  tree (t) Show connector/session/RPC structure
@@ -655,6 +694,38 @@ Tips:
655
694
  rest: trimmed.slice(spaceIdx + 1), // Keep rest as raw string
656
695
  };
657
696
  }
697
+ /**
698
+ * Check if an expression is a simple text (not a filter expression)
699
+ * Returns true if expression does not contain filter operators with proper context.
700
+ * Uses regex to avoid false positives like "<script>" or "a!=b" in text.
701
+ */
702
+ isSimpleTextSearch(expr) {
703
+ const trimmed = expr.trim();
704
+ // Pattern matches operators surrounded by whitespace or at string boundaries
705
+ // This prevents false positives like "<script>" or "5==5" in search text
706
+ const operatorPattern = /(?:^|\s)(==|!=|~=|>=?|<=?)(?:\s|$)/;
707
+ return !operatorPattern.test(trimmed);
708
+ }
709
+ /**
710
+ * Convert simple text search to appropriate filter expression based on row type
711
+ */
712
+ textToFilterExpr(text, rowType) {
713
+ const trimmed = text.trim();
714
+ // Escape backslashes first, then quotes (order matters!)
715
+ const escaped = trimmed.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
716
+ switch (rowType) {
717
+ case 'a2a-message':
718
+ return `message.content ~= "${escaped}"`;
719
+ case 'rpc':
720
+ // For now, search in method name (could be expanded later)
721
+ return `rpc.method ~= "${escaped}"`;
722
+ case 'session':
723
+ return `session.id ~= "${escaped}"`;
724
+ default:
725
+ // Default to searching in common text fields
726
+ return `message.content ~= "${escaped}"`;
727
+ }
728
+ }
658
729
  /**
659
730
  * Handle piped commands
660
731
  * Supports:
@@ -671,8 +742,13 @@ Tips:
671
742
  }
672
743
  // Extract command name from right side (preserving raw args for where/grep)
673
744
  const { cmd: rightCommand, rest: rawArgs } = this.extractCommand(rightCmd);
674
- // Handle: ls | where <filter-expr> or ls | grep <filter-expr>
675
- if (rightCommand === 'where' || rightCommand === 'grep') {
745
+ // Handle: ls | grep <text> (text search with auto-conversion)
746
+ if (rightCommand === 'grep') {
747
+ await this.handlePipeToGrep(leftCmd, rawArgs);
748
+ return;
749
+ }
750
+ // Handle: ls | where <filter-expr>
751
+ if (rightCommand === 'where') {
676
752
  await this.handlePipeToWhere(leftCmd, rawArgs);
677
753
  return;
678
754
  }
@@ -698,6 +774,7 @@ Tips:
698
774
  printInfo(' pwd --json | ref add <name>');
699
775
  printInfo(' show @rpc:<id> --json | inscribe');
700
776
  printInfo(' ls | where <filter-expr>');
777
+ printInfo(' ls | grep <text>');
701
778
  printInfo(' find rpc | where <filter-expr>');
702
779
  printInfo(' ls | less');
703
780
  printInfo(' find rpc | more');
@@ -740,11 +817,18 @@ Tips:
740
817
  input = findResult.result;
741
818
  statsLabel = `rows (across ${findResult.stats.sessions} sessions)`;
742
819
  }
820
+ else if (leftCommand === 'history') {
821
+ // Get history rows
822
+ const { getHistoryRows } = await import('./router-commands.js');
823
+ input = getHistoryRows(this.context, this.configPath);
824
+ statsLabel = 'messages';
825
+ }
743
826
  else {
744
- printError('where/grep only supports "ls" or "find" as input');
827
+ printError('where/grep only supports "ls", "find", or "history" as input');
745
828
  printInfo('Examples:');
746
829
  printInfo(' ls | where rpc.method == "tools/call"');
747
830
  printInfo(' find rpc | where tools.name ~= "read"');
831
+ printInfo(' history | where role == "user"');
748
832
  return;
749
833
  }
750
834
  // Apply where filter
@@ -761,6 +845,79 @@ Tips:
761
845
  this.renderPipelineOutput(result.result);
762
846
  printInfo(`${statsLabel}: ${result.stats.matched} / ${result.stats.total}`);
763
847
  }
848
+ /**
849
+ * Handle: ls | grep <text> or history | grep <text>
850
+ * Auto-converts simple text to appropriate filter expression based on row type
851
+ */
852
+ async handlePipeToGrep(leftCmd, expr) {
853
+ const leftTokens = leftCmd.trim().split(/\s+/);
854
+ const leftCommand = leftTokens[0];
855
+ // Get pipeline input based on left command
856
+ let input;
857
+ let statsLabel;
858
+ if (leftCommand === 'ls') {
859
+ // Get ls rows
860
+ const { getLsRows } = await import('./router-commands.js');
861
+ input = getLsRows(this.context, this.configPath);
862
+ // Connector level is not supported for ls
863
+ if (input.kind === 'rows' && input.rowType === 'connector') {
864
+ printError('grep is not supported for connectors');
865
+ printInfo('Navigate to a connector first: cd <connector-id>');
866
+ return;
867
+ }
868
+ statsLabel = 'rows';
869
+ }
870
+ else if (leftCommand === 'find') {
871
+ // Parse find args
872
+ const findArgs = leftTokens.slice(1);
873
+ const parseResult = parseFindArgs(findArgs);
874
+ if (!parseResult.ok) {
875
+ printError(parseResult.error);
876
+ return;
877
+ }
878
+ const findResult = executeFind(this.context, this.configPath, parseResult.options);
879
+ if (!findResult.ok) {
880
+ printError(findResult.error);
881
+ return;
882
+ }
883
+ input = findResult.result;
884
+ statsLabel = `rows (across ${findResult.stats.sessions} sessions)`;
885
+ }
886
+ else if (leftCommand === 'history') {
887
+ // Get history rows
888
+ const { getHistoryRows } = await import('./router-commands.js');
889
+ input = getHistoryRows(this.context, this.configPath);
890
+ statsLabel = 'messages';
891
+ }
892
+ else {
893
+ printError('grep only supports "ls", "find", or "history" as input');
894
+ printInfo('Examples:');
895
+ printInfo(' ls | grep "tools/call"');
896
+ printInfo(' find rpc | grep "read"');
897
+ printInfo(' history | grep "d20"');
898
+ return;
899
+ }
900
+ // Convert simple text to filter expression if needed
901
+ let filterExpr = expr;
902
+ if (this.isSimpleTextSearch(expr)) {
903
+ if (input.kind === 'rows') {
904
+ filterExpr = this.textToFilterExpr(expr, input.rowType);
905
+ }
906
+ }
907
+ // Apply where filter
908
+ const { applyWhere } = await import('./where-command.js');
909
+ const result = applyWhere(input, filterExpr);
910
+ if (!result.ok) {
911
+ printError(`Filter error: ${result.error}`);
912
+ if (result.position !== undefined) {
913
+ printError(` at position ${result.position + 1}`);
914
+ }
915
+ return;
916
+ }
917
+ // Render output
918
+ this.renderPipelineOutput(result.result);
919
+ printInfo(`${statsLabel}: ${result.stats.matched} / ${result.stats.total}`);
920
+ }
764
921
  /**
765
922
  * Handle: ls | less or find rpc | more
766
923
  */
@@ -793,11 +950,16 @@ Tips:
793
950
  }
794
951
  input = findResult.result;
795
952
  }
953
+ else if (leftCommand === 'history') {
954
+ const { getHistoryRows } = await import('./router-commands.js');
955
+ input = getHistoryRows(this.context, this.configPath);
956
+ }
796
957
  else {
797
- printError(`${pagerCmd} only supports "ls" or "find" as input`);
958
+ printError(`${pagerCmd} only supports "ls", "find", or "history" as input`);
798
959
  printInfo('Examples:');
799
960
  printInfo(' ls | less');
800
961
  printInfo(' find rpc | less');
962
+ printInfo(' history | less');
801
963
  return;
802
964
  }
803
965
  // Text input is an error
@@ -805,17 +967,25 @@ Tips:
805
967
  printError(`${pagerCmd} expects structured rows; got text`);
806
968
  return;
807
969
  }
808
- // Close readline before pager to avoid stdin conflicts
809
- // External pager uses stdio: ['pipe', inherit, inherit] so no stdin conflict,
810
- // but built-in fallback uses raw mode which conflicts with readline
811
- this.rl?.close();
812
- this.rl = null;
970
+ // Empty rows - print message and return without pager
971
+ if (input.rows.length === 0) {
972
+ printInfo('No results');
973
+ return;
974
+ }
975
+ // Pause readline instead of closing it to avoid listener conflicts
976
+ // This prevents the race condition between old and new readline listeners
977
+ if (this.rl) {
978
+ this.rl.pause();
979
+ }
813
980
  // Run pager
814
981
  const { LessPager, MorePager } = await import('./pager/index.js');
815
982
  const pager = pagerCmd === 'less' ? new LessPager() : new MorePager();
816
983
  await pager.run(input);
817
- // Recreate readline after pager exits
818
- this.resetReadline();
984
+ // Resume readline after pager completes
985
+ if (this.rl) {
986
+ this.rl.resume();
987
+ this.rl.prompt();
988
+ }
819
989
  }
820
990
  /**
821
991
  * Reset readline interface (recreate after pager or other stdin-consuming operations)
@@ -823,9 +993,24 @@ Tips:
823
993
  resetReadline() {
824
994
  // Close existing readline interface to prevent duplicate input
825
995
  if (this.rl) {
996
+ // Remove close listener to prevent "Goodbye!" message when closing for reset
997
+ this.rl.removeAllListeners('close');
826
998
  this.rl.removeAllListeners();
827
999
  this.rl.close();
828
1000
  }
1001
+ // Ensure stdin is in correct state before creating new readline
1002
+ if (process.stdin.isPaused()) {
1003
+ process.stdin.resume();
1004
+ }
1005
+ // Ensure stdin is not in raw mode
1006
+ if (process.stdin.isTTY && process.stdin.setRawMode) {
1007
+ try {
1008
+ process.stdin.setRawMode(false);
1009
+ }
1010
+ catch {
1011
+ // Ignore errors if already not in raw mode
1012
+ }
1013
+ }
829
1014
  // Choose completer based on mode
830
1015
  const completer = this.configureMode?.isActive()
831
1016
  ? createConfigureCompleter(this.configureMode, this.getConfigureDataProvider())
@@ -901,6 +1086,55 @@ Tips:
901
1086
  else if (output.rowType === 'session') {
902
1087
  this.renderSessionTable(output.rows, isTTY);
903
1088
  }
1089
+ else if (output.rowType === 'a2a-message') {
1090
+ this.renderA2AMessageTable(output.rows, isTTY);
1091
+ }
1092
+ }
1093
+ /**
1094
+ * Render A2A message rows as table
1095
+ */
1096
+ renderA2AMessageTable(rows, isTTY) {
1097
+ const dimText = (text) => isTTY ? `\x1b[2m${text}\x1b[0m` : text;
1098
+ const roleColor = (role) => {
1099
+ if (!isTTY)
1100
+ return role;
1101
+ return role === 'assistant' ? `\x1b[36m${role}\x1b[0m` : role;
1102
+ };
1103
+ // Check if rows have session_id (connector level)
1104
+ const hasSession = rows.some(r => r.session_id);
1105
+ console.log();
1106
+ if (hasSession) {
1107
+ console.log(dimText('#'.padEnd(4)) + ' ' +
1108
+ dimText('Session'.padEnd(10)) + ' ' +
1109
+ dimText('Time'.padEnd(10)) + ' ' +
1110
+ dimText('Role'.padEnd(12)) + ' ' +
1111
+ dimText('Content'));
1112
+ console.log(dimText('-'.repeat(80)));
1113
+ rows.forEach(row => {
1114
+ const sessionPrefix = row.session_id ? row.session_id.slice(0, 8) : '';
1115
+ const timeStr = row.timestamp ? row.timestamp.slice(11, 19) : '--:--:--';
1116
+ console.log(String(row.id).padEnd(4) + ' ' +
1117
+ sessionPrefix.padEnd(10) + ' ' +
1118
+ timeStr.padEnd(10) + ' ' +
1119
+ roleColor(row.role).padEnd(isTTY ? 21 : 12) + ' ' +
1120
+ row.content);
1121
+ });
1122
+ }
1123
+ else {
1124
+ console.log(dimText('#'.padEnd(4)) + ' ' +
1125
+ dimText('Time'.padEnd(10)) + ' ' +
1126
+ dimText('Role'.padEnd(12)) + ' ' +
1127
+ dimText('Content'));
1128
+ console.log(dimText('-'.repeat(70)));
1129
+ rows.forEach(row => {
1130
+ const timeStr = row.timestamp ? row.timestamp.slice(11, 19) : '--:--:--';
1131
+ console.log(String(row.id).padEnd(4) + ' ' +
1132
+ timeStr.padEnd(10) + ' ' +
1133
+ roleColor(row.role).padEnd(isTTY ? 21 : 12) + ' ' +
1134
+ row.content);
1135
+ });
1136
+ }
1137
+ console.log();
904
1138
  }
905
1139
  /**
906
1140
  * Render RPC rows as table
@@ -917,7 +1151,7 @@ Tips:
917
1151
  }
918
1152
  };
919
1153
  // Check if rows have connector_id (find results have it, ls does not)
920
- const hasConnector = rows.some(r => r.connector_id);
1154
+ const hasConnector = rows.some(r => r.target_id);
921
1155
  console.log();
922
1156
  if (hasConnector) {
923
1157
  // Extended format for find results: Connector, Session, Method, Status, Latency, Time
@@ -929,7 +1163,7 @@ Tips:
929
1163
  dimText('Time'));
930
1164
  console.log(dimText('-'.repeat(90)));
931
1165
  rows.forEach((row) => {
932
- const connector = (row.connector_id ?? '').slice(0, 10).padEnd(10);
1166
+ const connector = (row.target_id ?? '').slice(0, 10).padEnd(10);
933
1167
  const sessionShort = shortenSessionId(row.session_id);
934
1168
  const method = row.method.slice(0, 16).padEnd(16);
935
1169
  const status = statusColor(row.status).padEnd(isTTY ? 16 : 8);
@@ -962,7 +1196,7 @@ Tips:
962
1196
  renderSessionTable(rows, isTTY) {
963
1197
  const dimText = (text) => isTTY ? `\x1b[2m${text}\x1b[0m` : text;
964
1198
  // Check if rows span multiple connectors (find at root level)
965
- const connectorIds = new Set(rows.map(r => r.connector_id));
1199
+ const connectorIds = new Set(rows.map(r => r.target_id));
966
1200
  const multiConnector = connectorIds.size > 1;
967
1201
  console.log();
968
1202
  if (multiConnector) {
@@ -973,7 +1207,7 @@ Tips:
973
1207
  dimText('Started'));
974
1208
  console.log(dimText('-'.repeat(55)));
975
1209
  rows.forEach((row) => {
976
- const connector = (row.connector_id ?? '').slice(0, 12).padEnd(12);
1210
+ const connector = (row.target_id ?? '').slice(0, 12).padEnd(12);
977
1211
  const sessionShort = shortenSessionId(row.session_id);
978
1212
  const rpcs = String(row.rpc_count).padEnd(6);
979
1213
  const started = row.started_at ? row.started_at.slice(0, 19).replace('T', ' ') : '-';