recker 1.0.15 → 1.0.17-next.9570ed5

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 (142) hide show
  1. package/README.md +86 -97
  2. package/dist/ai/providers/anthropic.d.ts.map +1 -1
  3. package/dist/ai/providers/anthropic.js +4 -1
  4. package/dist/ai/providers/base.d.ts.map +1 -1
  5. package/dist/ai/providers/base.js +7 -2
  6. package/dist/ai/rate-limiter.d.ts.map +1 -1
  7. package/dist/ai/rate-limiter.js +4 -1
  8. package/dist/bench/generator.d.ts.map +1 -1
  9. package/dist/bench/generator.js +8 -3
  10. package/dist/bench/stats.d.ts +15 -1
  11. package/dist/bench/stats.d.ts.map +1 -1
  12. package/dist/bench/stats.js +117 -5
  13. package/dist/cache/memory-storage.d.ts.map +1 -1
  14. package/dist/cache/memory-storage.js +3 -2
  15. package/dist/cli/handler.js +14 -14
  16. package/dist/cli/index.js +602 -48
  17. package/dist/cli/presets.js +5 -5
  18. package/dist/cli/tui/ai-chat.js +10 -10
  19. package/dist/cli/tui/load-dashboard.d.ts.map +1 -1
  20. package/dist/cli/tui/load-dashboard.js +127 -32
  21. package/dist/cli/tui/scroll-buffer.d.ts +43 -0
  22. package/dist/cli/tui/scroll-buffer.d.ts.map +1 -0
  23. package/dist/cli/tui/scroll-buffer.js +162 -0
  24. package/dist/cli/tui/search-panel.d.ts +41 -0
  25. package/dist/cli/tui/search-panel.d.ts.map +1 -0
  26. package/dist/cli/tui/search-panel.js +420 -0
  27. package/dist/cli/tui/shell.d.ts +14 -0
  28. package/dist/cli/tui/shell.d.ts.map +1 -1
  29. package/dist/cli/tui/shell.js +424 -46
  30. package/dist/cli/tui/websocket.js +17 -17
  31. package/dist/contract/index.d.ts.map +1 -1
  32. package/dist/contract/index.js +3 -2
  33. package/dist/core/client.d.ts.map +1 -1
  34. package/dist/core/client.js +18 -26
  35. package/dist/core/errors.d.ts +109 -1
  36. package/dist/core/errors.d.ts.map +1 -1
  37. package/dist/core/errors.js +214 -1
  38. package/dist/core/request-promise.d.ts.map +1 -1
  39. package/dist/core/request-promise.js +5 -6
  40. package/dist/core/response.d.ts.map +1 -1
  41. package/dist/core/response.js +5 -6
  42. package/dist/dns/index.d.ts +1 -0
  43. package/dist/dns/index.d.ts.map +1 -1
  44. package/dist/dns/index.js +1 -0
  45. package/dist/dns/propagation.d.ts +21 -0
  46. package/dist/dns/propagation.d.ts.map +1 -0
  47. package/dist/dns/propagation.js +169 -0
  48. package/dist/index.d.ts +3 -0
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +3 -0
  51. package/dist/mcp/client.d.ts.map +1 -1
  52. package/dist/mcp/client.js +10 -11
  53. package/dist/mcp/embeddings-loader.d.ts +18 -0
  54. package/dist/mcp/embeddings-loader.d.ts.map +1 -0
  55. package/dist/mcp/embeddings-loader.js +162 -0
  56. package/dist/mcp/geoip-loader.d.ts +11 -0
  57. package/dist/mcp/geoip-loader.d.ts.map +1 -0
  58. package/dist/mcp/geoip-loader.js +107 -0
  59. package/dist/mcp/index.d.ts +1 -0
  60. package/dist/mcp/index.d.ts.map +1 -1
  61. package/dist/mcp/index.js +1 -0
  62. package/dist/mcp/ip-intel.d.ts +28 -0
  63. package/dist/mcp/ip-intel.d.ts.map +1 -0
  64. package/dist/mcp/ip-intel.js +209 -0
  65. package/dist/mcp/search/hybrid-search.d.ts.map +1 -1
  66. package/dist/mcp/search/hybrid-search.js +59 -38
  67. package/dist/mcp/search/math.d.ts.map +1 -1
  68. package/dist/mcp/search/math.js +5 -1
  69. package/dist/mcp/server.d.ts +6 -0
  70. package/dist/mcp/server.d.ts.map +1 -1
  71. package/dist/mcp/server.js +122 -2
  72. package/dist/plugins/compression.js +4 -2
  73. package/dist/plugins/har-player.d.ts.map +1 -1
  74. package/dist/plugins/har-player.js +8 -11
  75. package/dist/plugins/odata.d.ts.map +1 -1
  76. package/dist/plugins/odata.js +5 -2
  77. package/dist/presets/index.d.ts +2 -0
  78. package/dist/presets/index.d.ts.map +1 -1
  79. package/dist/presets/index.js +2 -0
  80. package/dist/presets/mailgun.d.ts +8 -0
  81. package/dist/presets/mailgun.d.ts.map +1 -0
  82. package/dist/presets/mailgun.js +20 -0
  83. package/dist/presets/registry.d.ts.map +1 -1
  84. package/dist/presets/registry.js +20 -0
  85. package/dist/presets/sinch.d.ts +10 -0
  86. package/dist/presets/sinch.d.ts.map +1 -0
  87. package/dist/presets/sinch.js +39 -0
  88. package/dist/protocols/ftp.d.ts.map +1 -1
  89. package/dist/protocols/ftp.js +69 -16
  90. package/dist/protocols/sftp.d.ts.map +1 -1
  91. package/dist/protocols/sftp.js +13 -3
  92. package/dist/protocols/telnet.d.ts.map +1 -1
  93. package/dist/protocols/telnet.js +25 -6
  94. package/dist/recker.d.ts +47 -0
  95. package/dist/recker.d.ts.map +1 -0
  96. package/dist/recker.js +99 -0
  97. package/dist/transport/base-udp.d.ts.map +1 -1
  98. package/dist/transport/base-udp.js +7 -4
  99. package/dist/transport/udp-response.d.ts.map +1 -1
  100. package/dist/transport/udp-response.js +10 -3
  101. package/dist/transport/udp.d.ts.map +1 -1
  102. package/dist/transport/udp.js +5 -1
  103. package/dist/transport/undici.d.ts.map +1 -1
  104. package/dist/transport/undici.js +75 -63
  105. package/dist/utils/agent-manager.d.ts +1 -0
  106. package/dist/utils/agent-manager.d.ts.map +1 -1
  107. package/dist/utils/agent-manager.js +11 -0
  108. package/dist/utils/client-pool.d.ts.map +1 -1
  109. package/dist/utils/client-pool.js +4 -1
  110. package/dist/utils/colors.d.ts +16 -0
  111. package/dist/utils/colors.d.ts.map +1 -1
  112. package/dist/utils/colors.js +16 -0
  113. package/dist/utils/dns-toolkit.d.ts +88 -1
  114. package/dist/utils/dns-toolkit.d.ts.map +1 -1
  115. package/dist/utils/dns-toolkit.js +704 -6
  116. package/dist/utils/doh.d.ts.map +1 -1
  117. package/dist/utils/doh.js +13 -16
  118. package/dist/utils/download.d.ts.map +1 -1
  119. package/dist/utils/download.js +10 -11
  120. package/dist/utils/rdap.d.ts +9 -0
  121. package/dist/utils/rdap.d.ts.map +1 -1
  122. package/dist/utils/rdap.js +78 -9
  123. package/dist/utils/security-grader.d.ts +47 -0
  124. package/dist/utils/security-grader.d.ts.map +1 -0
  125. package/dist/utils/security-grader.js +637 -0
  126. package/dist/utils/sparkline.d.ts +18 -0
  127. package/dist/utils/sparkline.d.ts.map +1 -0
  128. package/dist/utils/sparkline.js +55 -0
  129. package/dist/utils/sse.d.ts.map +1 -1
  130. package/dist/utils/sse.js +5 -6
  131. package/dist/utils/system-metrics.d.ts +26 -0
  132. package/dist/utils/system-metrics.d.ts.map +1 -0
  133. package/dist/utils/system-metrics.js +81 -0
  134. package/dist/utils/tls-inspector.d.ts +6 -0
  135. package/dist/utils/tls-inspector.d.ts.map +1 -1
  136. package/dist/utils/tls-inspector.js +35 -1
  137. package/dist/webrtc/index.d.ts.map +1 -1
  138. package/dist/webrtc/index.js +21 -7
  139. package/dist/websocket/client.d.ts.map +1 -1
  140. package/dist/websocket/client.js +13 -16
  141. package/package.json +4 -3
  142. package/dist/mcp/data/embeddings.json +0 -1
@@ -12,6 +12,8 @@ import { rdap } from '../../utils/rdap.js';
12
12
  import { ScrapeDocument } from '../../scrape/document.js';
13
13
  import colors from '../../utils/colors.js';
14
14
  import { getShellSearch } from './shell-search.js';
15
+ import { openSearchPanel } from './search-panel.js';
16
+ import { ScrollBuffer, parseScrollKey, parseMouseScroll, enableMouseReporting, disableMouseReporting } from './scroll-buffer.js';
15
17
  let highlight;
16
18
  async function initDependencies() {
17
19
  if (!highlight) {
@@ -36,11 +38,16 @@ export class RekShell {
36
38
  initialized = false;
37
39
  currentDoc = null;
38
40
  currentDocUrl = '';
41
+ scrollBuffer;
42
+ originalStdoutWrite = null;
43
+ inScrollMode = false;
39
44
  constructor() {
40
45
  this.client = createClient({
41
46
  baseUrl: 'http://localhost',
42
- checkHooks: false
47
+ checkHooks: false,
48
+ http2: true
43
49
  });
50
+ this.scrollBuffer = new ScrollBuffer({ maxLines: 10000 });
44
51
  }
45
52
  async ensureInitialized() {
46
53
  if (this.initialized)
@@ -85,7 +92,7 @@ export class RekShell {
85
92
  const commands = [
86
93
  'get', 'post', 'put', 'delete', 'patch', 'head', 'options',
87
94
  'ws', 'udp', 'load', 'chat', 'ai',
88
- 'whois', 'tls', 'ssl', 'dns', 'rdap', 'ping',
95
+ 'whois', 'tls', 'ssl', 'security', 'ip', 'dns', 'dns:propagate', 'dns:email', 'rdap', 'ping',
89
96
  'scrap', '$', '$text', '$attr', '$html', '$links', '$images', '$scripts', '$css', '$sourcemaps', '$unmap', '$unmap:view', '$unmap:save', '$beautify', '$beautify:save', '$table',
90
97
  '?', 'search', 'suggest', 'example',
91
98
  'help', 'clear', 'exit', 'set', 'url', 'vars', 'env'
@@ -95,9 +102,11 @@ export class RekShell {
95
102
  }
96
103
  async start() {
97
104
  await this.ensureInitialized();
105
+ this.setupScrollCapture();
98
106
  console.clear();
99
107
  console.log(colors.bold(colors.cyan('Rek Console')));
100
108
  console.log(colors.gray('Chat with your APIs. Type "help" for magic.'));
109
+ console.log(colors.gray('Page Up/Down or mouse scroll to view history.'));
101
110
  console.log(colors.gray('--------------------------------------------\n'));
102
111
  this.prompt();
103
112
  this.rl.on('line', async (line) => {
@@ -112,15 +121,185 @@ export class RekShell {
112
121
  this.rl.close();
113
122
  });
114
123
  this.rl.on('close', () => {
124
+ this.cleanupScrollCapture();
115
125
  console.log(colors.gray('\nSee ya.'));
116
126
  process.exit(0);
117
127
  });
128
+ process.stdout.on('resize', () => {
129
+ this.scrollBuffer.updateViewport();
130
+ });
131
+ this.setupScrollKeyHandler();
132
+ }
133
+ setupScrollCapture() {
134
+ this.originalStdoutWrite = process.stdout.write.bind(process.stdout);
135
+ const self = this;
136
+ process.stdout.write = function (chunk, encodingOrCallback, callback) {
137
+ const content = typeof chunk === 'string' ? chunk : chunk.toString();
138
+ self.scrollBuffer.write(content);
139
+ if (!self.inScrollMode && self.originalStdoutWrite) {
140
+ return self.originalStdoutWrite(chunk, encodingOrCallback, callback);
141
+ }
142
+ return true;
143
+ };
144
+ }
145
+ cleanupScrollCapture() {
146
+ if (this.originalStdoutWrite) {
147
+ process.stdout.write = this.originalStdoutWrite;
148
+ this.originalStdoutWrite = null;
149
+ }
150
+ disableMouseReporting();
151
+ }
152
+ setupScrollKeyHandler() {
153
+ enableMouseReporting();
154
+ if (process.stdin.isTTY) {
155
+ const originalEmit = process.stdin.emit.bind(process.stdin);
156
+ const self = this;
157
+ process.stdin.emit = function (event, ...args) {
158
+ if (event === 'data') {
159
+ const data = args[0];
160
+ const str = data.toString();
161
+ if (str.includes('\x1b[<')) {
162
+ const mouseScroll = parseMouseScroll(data);
163
+ if (mouseScroll) {
164
+ self.handleScrollKey(mouseScroll);
165
+ }
166
+ return true;
167
+ }
168
+ if (data.length >= 6 && data[0] === 0x1b && data[1] === 0x5b && data[2] === 0x4d) {
169
+ const mouseScroll = parseMouseScroll(data);
170
+ if (mouseScroll) {
171
+ self.handleScrollKey(mouseScroll);
172
+ }
173
+ return true;
174
+ }
175
+ const scrollKey = parseScrollKey(data);
176
+ if (scrollKey) {
177
+ if (scrollKey === 'quit') {
178
+ if (self.inScrollMode) {
179
+ self.exitScrollMode();
180
+ return true;
181
+ }
182
+ return originalEmit(event, ...args);
183
+ }
184
+ self.handleScrollKey(scrollKey);
185
+ return true;
186
+ }
187
+ if (self.inScrollMode) {
188
+ return true;
189
+ }
190
+ }
191
+ return originalEmit(event, ...args);
192
+ };
193
+ }
194
+ }
195
+ handleScrollKey(key) {
196
+ let needsRedraw = false;
197
+ switch (key) {
198
+ case 'pageUp':
199
+ if (!this.inScrollMode) {
200
+ this.enterScrollMode();
201
+ }
202
+ needsRedraw = this.scrollBuffer.pageUp();
203
+ break;
204
+ case 'pageDown':
205
+ needsRedraw = this.scrollBuffer.pageDown();
206
+ if (!this.scrollBuffer.isScrolledUp && this.inScrollMode) {
207
+ this.exitScrollMode();
208
+ return;
209
+ }
210
+ break;
211
+ case 'scrollUp':
212
+ if (!this.inScrollMode) {
213
+ this.enterScrollMode();
214
+ }
215
+ needsRedraw = this.scrollBuffer.scrollUp(3);
216
+ break;
217
+ case 'scrollDown':
218
+ needsRedraw = this.scrollBuffer.scrollDown(3);
219
+ if (!this.scrollBuffer.isScrolledUp && this.inScrollMode) {
220
+ this.exitScrollMode();
221
+ return;
222
+ }
223
+ break;
224
+ case 'home':
225
+ if (!this.inScrollMode) {
226
+ this.enterScrollMode();
227
+ }
228
+ this.scrollBuffer.scrollToTop();
229
+ needsRedraw = true;
230
+ break;
231
+ case 'end':
232
+ this.scrollBuffer.scrollToBottom();
233
+ if (this.inScrollMode) {
234
+ this.exitScrollMode();
235
+ return;
236
+ }
237
+ break;
238
+ case 'quit':
239
+ if (this.inScrollMode) {
240
+ this.exitScrollMode();
241
+ return;
242
+ }
243
+ break;
244
+ }
245
+ if (needsRedraw && this.inScrollMode) {
246
+ this.renderScrollView();
247
+ }
248
+ }
249
+ enterScrollMode() {
250
+ if (this.inScrollMode)
251
+ return;
252
+ this.inScrollMode = true;
253
+ this.rl.pause();
254
+ if (this.originalStdoutWrite) {
255
+ this.originalStdoutWrite('\x1b[?25l');
256
+ }
257
+ this.renderScrollView();
258
+ }
259
+ exitScrollMode() {
260
+ if (!this.inScrollMode)
261
+ return;
262
+ this.inScrollMode = false;
263
+ if (this.originalStdoutWrite) {
264
+ this.originalStdoutWrite('\x1b[?25h');
265
+ this.originalStdoutWrite('\x1b[2J\x1b[H');
266
+ }
267
+ const recentLines = this.scrollBuffer.getVisibleLines();
268
+ if (this.originalStdoutWrite) {
269
+ this.originalStdoutWrite(recentLines.join('\n') + '\n');
270
+ }
271
+ this.rl.resume();
272
+ this.prompt();
273
+ }
274
+ renderScrollView() {
275
+ if (!this.originalStdoutWrite)
276
+ return;
277
+ const rows = process.stdout.rows || 24;
278
+ const cols = process.stdout.columns || 80;
279
+ const visibleLines = this.scrollBuffer.getVisibleLines();
280
+ const info = this.scrollBuffer.getScrollInfo();
281
+ this.originalStdoutWrite('\x1b[2J\x1b[H');
282
+ for (let i = 0; i < visibleLines.length && i < rows - 1; i++) {
283
+ const line = visibleLines[i] || '';
284
+ const truncated = line.length > cols ? line.slice(0, cols - 1) + '…' : line;
285
+ this.originalStdoutWrite(truncated + '\n');
286
+ }
287
+ const scrollInfo = this.scrollBuffer.isScrolledUp
288
+ ? colors.yellow(`↑ ${this.scrollBuffer.position} lines | ${info.percent}% | `)
289
+ : '';
290
+ const helpText = colors.gray('Page Up/Down • Home/End • Q to exit');
291
+ const statusBar = `\x1b[${rows};1H\x1b[7m ${scrollInfo}${helpText} \x1b[0m`;
292
+ this.originalStdoutWrite(statusBar);
118
293
  }
119
294
  prompt() {
120
295
  this.rl.setPrompt(this.getPrompt());
121
296
  this.rl.prompt();
122
297
  }
123
298
  async handleCommand(input) {
299
+ if (input.endsWith('?') && !input.startsWith('?') && input.length > 1) {
300
+ await this.runSearch(input.slice(0, -1).trim());
301
+ return;
302
+ }
124
303
  if (input.includes('=') && !input.includes(' ') && !input.startsWith('http')) {
125
304
  }
126
305
  const parts = this.parseLine(input);
@@ -162,9 +341,21 @@ export class RekShell {
162
341
  case 'ssl':
163
342
  await this.runTLS(parts[1], parts[2] ? parseInt(parts[2]) : 443);
164
343
  return;
344
+ case 'security':
345
+ await this.runSecurityGrader(parts[1]);
346
+ return;
347
+ case 'ip':
348
+ await this.runIpIntelligence(parts[1]);
349
+ return;
165
350
  case 'dns':
166
351
  await this.runDNS(parts[1]);
167
352
  return;
353
+ case 'dns:propagate':
354
+ await this.runDNSPropagation(parts[1], parts[2]);
355
+ return;
356
+ case 'dns:email':
357
+ await this.runDnsEmailCheck(parts[1], parts[2]);
358
+ return;
168
359
  case 'rdap':
169
360
  await this.runRDAP(parts[1]);
170
361
  return;
@@ -650,25 +841,56 @@ export class RekShell {
650
841
  const duration = Math.round(performance.now() - startTime);
651
842
  const statusIcon = info.valid ? colors.green('✔') : colors.red('✖');
652
843
  const statusText = info.valid ? colors.green('Valid') : colors.red('Invalid/Expired');
653
- console.log(`${statusIcon} Certificate ${statusText}` + colors.gray(` (${duration}ms)\n`));
654
- console.log(colors.bold(' Certificate:'));
655
- console.log(` ${colors.cyan('Subject')}: ${info.subject?.CN || info.subject?.O || 'N/A'}`);
656
- console.log(` ${colors.cyan('Issuer')}: ${info.issuer?.CN || info.issuer?.O || 'N/A'}`);
657
- console.log(` ${colors.cyan('Valid From')}: ${info.validFrom.toISOString()}`);
658
- console.log(` ${colors.cyan('Valid To')}: ${info.validTo.toISOString()}`);
659
844
  const daysColor = info.daysRemaining < 30 ? colors.red : info.daysRemaining < 90 ? colors.yellow : colors.green;
660
- console.log(` ${colors.cyan('Days Remaining')}: ${daysColor(String(info.daysRemaining))}`);
661
- console.log(colors.bold('\n Connection:'));
662
- console.log(` ${colors.cyan('Protocol')}: ${info.protocol || 'N/A'}`);
663
- console.log(` ${colors.cyan('Cipher')}: ${info.cipher?.name || 'N/A'}`);
664
- console.log(` ${colors.cyan('Authorized')}: ${info.authorized ? colors.green('Yes') : colors.red('No')}`);
845
+ console.log(`\n${colors.bold(colors.cyan('🔒 TLS/SSL Report'))}`);
846
+ console.log(`${statusIcon} Certificate ${statusText}` + colors.gray(` (${duration}ms)\n`));
847
+ console.log(colors.bold('Certificate:'));
848
+ console.log(` ${colors.gray('Subject:')}`);
849
+ for (const key of Object.keys(info.subject || {})) {
850
+ console.log(` ${colors.gray(key.padEnd(10))}: ${info.subject[key]}`);
851
+ }
852
+ console.log(` ${colors.gray('Issuer:')}`);
853
+ for (const key of Object.keys(info.issuer || {})) {
854
+ console.log(` ${colors.gray(key.padEnd(10))}: ${info.issuer[key]}`);
855
+ }
856
+ console.log(` ${colors.gray('Expires:')} ${daysColor(info.daysRemaining + ' days')} (${info.validTo.toISOString().split('T')[0]})`);
857
+ console.log(` ${colors.gray('Valid From:')} ${info.validFrom.toISOString().split('T')[0]}`);
858
+ console.log(` ${colors.gray('Valid To:')} ${info.validTo.toISOString().split('T')[0]}`);
859
+ console.log(` ${colors.gray('Valid:')} ${info.valid ? colors.green('Yes') : colors.red('No')}`);
860
+ if (info.altNames && info.altNames.length > 0) {
861
+ console.log(colors.bold('\nSubject Alternative Names (SANs):'));
862
+ for (const name of info.altNames) {
863
+ console.log(` ${colors.cyan('→')} ${name}`);
864
+ }
865
+ }
866
+ console.log(colors.bold('\nPublic Key:'));
867
+ if (info.pubkey) {
868
+ console.log(` ${colors.gray('Algorithm:')} ${info.pubkey.algo}`);
869
+ console.log(` ${colors.gray('Size:')} ${info.pubkey.size} bits`);
870
+ }
871
+ else {
872
+ console.log(' Not available');
873
+ }
874
+ console.log(colors.bold('\nExtended Key Usage:'));
875
+ if (info.extKeyUsage && info.extKeyUsage.length > 0) {
876
+ for (const oid of info.extKeyUsage) {
877
+ console.log(` ${colors.cyan('→')} ${oid}`);
878
+ }
879
+ }
880
+ else {
881
+ console.log(' None');
882
+ }
883
+ console.log(colors.bold('\nConnection:'));
884
+ console.log(` ${colors.gray('Protocol:')} ${info.protocol || 'N/A'}`);
885
+ console.log(` ${colors.gray('Cipher:')} ${info.cipher?.name || 'N/A'}`);
886
+ console.log(` ${colors.gray('Auth:')} ${info.authorized ? colors.green('Trusted') : colors.red('Untrusted')}`);
665
887
  if (info.authorizationError) {
666
- console.log(` ${colors.cyan('Auth Error')}: ${colors.red(String(info.authorizationError))}`);
888
+ console.log(` ${colors.gray('Auth Error:')} ${colors.red(String(info.authorizationError))}`);
667
889
  }
668
- console.log(colors.bold('\n Fingerprints:'));
669
- console.log(` ${colors.cyan('SHA1')}: ${info.fingerprint}`);
670
- console.log(` ${colors.cyan('SHA256')}: ${info.fingerprint256}`);
671
- console.log(` ${colors.cyan('Serial')}: ${info.serialNumber}`);
890
+ console.log(colors.bold('\nFingerprints:'));
891
+ console.log(` ${colors.gray('SHA1:')} ${info.fingerprint}`);
892
+ console.log(` ${colors.gray('SHA256:')} ${info.fingerprint256}`);
893
+ console.log(` ${colors.gray('Serial:')} ${info.serialNumber}`);
672
894
  this.lastResponse = info;
673
895
  }
674
896
  catch (error) {
@@ -676,6 +898,96 @@ export class RekShell {
676
898
  }
677
899
  console.log('');
678
900
  }
901
+ async runSecurityGrader(url) {
902
+ if (!url) {
903
+ url = this.baseUrl || '';
904
+ if (!url) {
905
+ console.log(colors.yellow('Usage: security <url>'));
906
+ console.log(colors.gray(' Examples: security google.com | security https://example.com'));
907
+ console.log(colors.gray(' Or set a base URL first: url https://example.com'));
908
+ return;
909
+ }
910
+ }
911
+ else if (!url.startsWith('http')) {
912
+ url = `https://${url}`;
913
+ }
914
+ console.log(colors.gray(`Analyzing security headers for ${url}...`));
915
+ try {
916
+ const { analyzeSecurityHeaders } = await import('../../utils/security-grader.js');
917
+ const res = await this.client.get(url);
918
+ const report = analyzeSecurityHeaders(res.headers);
919
+ let gradeColor = colors.red;
920
+ if (report.grade.startsWith('A'))
921
+ gradeColor = colors.green;
922
+ else if (report.grade.startsWith('B'))
923
+ gradeColor = colors.blue;
924
+ else if (report.grade.startsWith('C'))
925
+ gradeColor = colors.yellow;
926
+ console.log(`
927
+ ${colors.bold(colors.cyan('🛡️ Security Headers Report'))}
928
+ Grade: ${gradeColor(colors.bold(report.grade))} (${report.score}/100)
929
+
930
+ ${colors.bold('Details:')}`);
931
+ report.details.forEach(item => {
932
+ const icon = item.status === 'pass' ? colors.green('✔') : item.status === 'warn' ? colors.yellow('⚠') : colors.red('✖');
933
+ const headerName = colors.bold(item.header);
934
+ const value = item.value ? colors.gray(`= ${item.value.length > 50 ? item.value.slice(0, 47) + '...' : item.value}`) : colors.gray('(missing)');
935
+ console.log(` ${icon} ${headerName} ${value}`);
936
+ if (item.status !== 'pass') {
937
+ console.log(` ${colors.red('→')} ${item.message}`);
938
+ }
939
+ });
940
+ console.log('');
941
+ this.lastResponse = report;
942
+ }
943
+ catch (error) {
944
+ console.error(colors.red(`Analysis failed: ${error.message}`));
945
+ }
946
+ console.log('');
947
+ }
948
+ async runIpIntelligence(address) {
949
+ if (!address) {
950
+ console.log(colors.yellow('Usage: ip <address>'));
951
+ console.log(colors.gray(' Examples: ip 8.8.8.8 | ip 192.168.1.1'));
952
+ return;
953
+ }
954
+ console.log(colors.gray(`Looking up ${address} using local GeoLite2 database...`));
955
+ try {
956
+ const { getIpInfo, isGeoIPAvailable } = await import('../../mcp/ip-intel.js');
957
+ if (!isGeoIPAvailable()) {
958
+ console.log(colors.gray(`Downloading GeoLite2 database...`));
959
+ }
960
+ const info = await getIpInfo(address);
961
+ if (info.bogon) {
962
+ console.log(colors.yellow(`\n⚠ ${address} is a Bogon/Private IP.`));
963
+ console.log(colors.gray(` Type: ${info.bogonType}`));
964
+ this.lastResponse = info;
965
+ return;
966
+ }
967
+ console.log(`
968
+ ${colors.bold(colors.cyan('🌍 IP Intelligence Report'))}
969
+
970
+ ${colors.bold('Location:')}
971
+ ${colors.gray('City:')} ${info.city || 'N/A'}
972
+ ${colors.gray('Region:')} ${info.region || 'N/A'}
973
+ ${colors.gray('Country:')} ${info.country || 'N/A'} ${info.countryCode ? `(${info.countryCode})` : ''}
974
+ ${colors.gray('Continent:')} ${info.continent || 'N/A'}
975
+ ${colors.gray('Timezone:')} ${info.timezone || 'N/A'}
976
+ ${colors.gray('Coords:')} ${info.loc ? colors.cyan(info.loc) : 'N/A'}
977
+ ${colors.gray('Accuracy:')} ${info.accuracy ? `~${info.accuracy} km` : 'N/A'}
978
+
979
+ ${colors.bold('Network:')}
980
+ ${colors.gray('IP:')} ${info.ip}
981
+ ${colors.gray('Type:')} ${info.isIPv6 ? 'IPv6' : 'IPv4'}
982
+ ${colors.gray('Postal:')} ${info.postal || 'N/A'}
983
+ `);
984
+ this.lastResponse = info;
985
+ }
986
+ catch (error) {
987
+ console.error(colors.red(`IP Lookup Failed: ${error.message}`));
988
+ }
989
+ console.log('');
990
+ }
679
991
  async runDNS(domain) {
680
992
  if (!domain) {
681
993
  domain = this.getBaseDomain() || '';
@@ -736,6 +1048,90 @@ export class RekShell {
736
1048
  }
737
1049
  console.log('');
738
1050
  }
1051
+ async runDNSPropagation(domain, type = 'A') {
1052
+ if (!domain) {
1053
+ domain = this.getBaseDomain() || '';
1054
+ if (!domain) {
1055
+ console.log(colors.yellow('Usage: dns:propagate <domain> [type]'));
1056
+ console.log(colors.gray(' Examples: dns:propagate google.com | dns:propagate github.com TXT'));
1057
+ console.log(colors.gray(' Or set a base URL first: url https://example.com'));
1058
+ return;
1059
+ }
1060
+ }
1061
+ console.log(colors.gray(`Checking DNS propagation for ${domain} (${type})...`));
1062
+ try {
1063
+ const { checkPropagation, formatPropagationReport } = await import('../../dns/propagation.js');
1064
+ const results = await checkPropagation(domain, type);
1065
+ console.log(formatPropagationReport(results, domain, type));
1066
+ this.lastResponse = results;
1067
+ }
1068
+ catch (error) {
1069
+ console.error(colors.red(`Propagation check failed: ${error.message}`));
1070
+ }
1071
+ }
1072
+ async runDnsEmailCheck(domain, selector) {
1073
+ if (!domain) {
1074
+ domain = this.getBaseDomain() || '';
1075
+ if (!domain) {
1076
+ console.log(colors.yellow('Usage: dns:email <domain> [dkim-selector]'));
1077
+ console.log(colors.gray(' Examples: dns:email google.com | dns:email github.com google'));
1078
+ console.log(colors.gray(' Or set a base URL first: url https://example.com'));
1079
+ return;
1080
+ }
1081
+ }
1082
+ console.log(colors.gray(`Checking email security for ${domain}...`));
1083
+ const startTime = performance.now();
1084
+ try {
1085
+ const { validateSpf, validateDmarc, checkDkim } = await import('../../utils/dns-toolkit.js');
1086
+ const [spf, dmarc, dkim] = await Promise.all([
1087
+ validateSpf(domain),
1088
+ validateDmarc(domain),
1089
+ checkDkim(domain, selector || 'default')
1090
+ ]);
1091
+ const duration = Math.round(performance.now() - startTime);
1092
+ console.log(colors.green(`✔ Email security check completed`) + colors.gray(` (${duration}ms)\n`));
1093
+ console.log(colors.bold('SPF:'));
1094
+ if (spf.valid) {
1095
+ console.log(` ${colors.green('✔')} ${spf.record || 'No record'}`);
1096
+ }
1097
+ else {
1098
+ console.log(` ${colors.red('✖')} ${spf.errors?.join(', ') || 'Invalid'}`);
1099
+ }
1100
+ if (spf.warnings?.length) {
1101
+ spf.warnings.forEach((w) => console.log(` ${colors.yellow('⚠')} ${w}`));
1102
+ }
1103
+ console.log(colors.bold('\nDMARC:'));
1104
+ if (dmarc.valid) {
1105
+ console.log(` ${colors.green('✔')} Policy: ${dmarc.policy || 'none'}`);
1106
+ if (dmarc.percentage !== undefined && dmarc.percentage < 100) {
1107
+ console.log(` ${colors.yellow('⚠')} Only ${dmarc.percentage}% of emails affected`);
1108
+ }
1109
+ }
1110
+ else {
1111
+ console.log(` ${colors.red('✖')} No DMARC record found`);
1112
+ }
1113
+ if (dmarc.warnings?.length) {
1114
+ dmarc.warnings.forEach((w) => console.log(` ${colors.yellow('⚠')} ${w}`));
1115
+ }
1116
+ console.log(colors.bold(`\nDKIM (${selector || 'default'}):`));
1117
+ if (dkim.found) {
1118
+ console.log(` ${colors.green('✔')} Record found`);
1119
+ if (dkim.publicKey) {
1120
+ const keyPreview = dkim.publicKey.substring(0, 40) + '...';
1121
+ console.log(` ${colors.gray('Key:')} ${keyPreview}`);
1122
+ }
1123
+ }
1124
+ else {
1125
+ console.log(` ${colors.yellow('⚠')} No DKIM record for selector "${selector || 'default'}"`);
1126
+ console.log(` ${colors.gray('Try: dns:email ' + domain + ' <selector>')}`);
1127
+ }
1128
+ console.log('');
1129
+ this.lastResponse = { spf, dmarc, dkim };
1130
+ }
1131
+ catch (error) {
1132
+ console.error(colors.red(`Email security check failed: ${error.message}`));
1133
+ }
1134
+ }
739
1135
  async runRDAP(domain) {
740
1136
  if (!domain) {
741
1137
  domain = this.getRootDomain() || '';
@@ -1660,38 +2056,14 @@ export class RekShell {
1660
2056
  console.log('');
1661
2057
  }
1662
2058
  async runSearch(query) {
1663
- if (!query.trim()) {
1664
- console.log(colors.yellow('Usage: ? <query> or search <query>'));
1665
- console.log(colors.gray(' Examples:'));
1666
- console.log(colors.gray(' ? retry exponential backoff'));
1667
- console.log(colors.gray(' search cache configuration'));
1668
- return;
1669
- }
1670
- console.log(colors.gray('Searching documentation...'));
1671
2059
  try {
1672
- const search = getShellSearch();
1673
- const results = await search.search(query, { limit: 5 });
1674
- if (results.length === 0) {
1675
- console.log(colors.yellow(`No results for: "${query}"`));
1676
- console.log(colors.gray('Try different keywords like: retry, cache, streaming, websocket, pagination'));
1677
- return;
1678
- }
1679
- console.log(colors.bold(colors.cyan(`\nFound ${results.length} results for "${query}":\n`)));
1680
- for (let i = 0; i < results.length; i++) {
1681
- const result = results[i];
1682
- const score = Math.round(result.score * 100);
1683
- console.log(` ${colors.green(`${i + 1}.`)} ${colors.bold(result.title)} ${colors.gray(`(${score}%)`)}`);
1684
- console.log(` ${colors.gray(result.path)}`);
1685
- if (result.snippet) {
1686
- const snippet = result.snippet.slice(0, 120).replace(/\n/g, ' ');
1687
- console.log(` ${colors.gray(snippet)}${result.snippet.length > 120 ? '...' : ''}`);
1688
- }
1689
- console.log('');
1690
- }
1691
- console.log(colors.gray(' Tip: Use "get_doc <path>" to read full documentation'));
2060
+ this.rl.pause();
2061
+ await openSearchPanel(query.trim() || undefined);
2062
+ this.rl.resume();
1692
2063
  }
1693
2064
  catch (error) {
1694
2065
  console.error(colors.red(`Search failed: ${error.message}`));
2066
+ this.rl.resume();
1695
2067
  }
1696
2068
  }
1697
2069
  async runSuggest(useCase) {
@@ -1834,6 +2206,12 @@ export class RekShell {
1834
2206
  ${colors.green('suggest <use-case>')} Get implementation suggestions.
1835
2207
  ${colors.green('example <feature>')} Get code examples for a feature.
1836
2208
 
2209
+ ${colors.bold('Navigation:')}
2210
+ ${colors.green('Page Up/Down')} Scroll through command history.
2211
+ ${colors.green('Home/End')} Jump to top/bottom of history.
2212
+ ${colors.green('Mouse Scroll')} Scroll with mouse wheel.
2213
+ ${colors.green('Escape')} Exit scroll mode.
2214
+
1837
2215
  ${colors.bold('Examples:')}
1838
2216
  › url httpbin.org
1839
2217
  › get /json
@@ -1,24 +1,24 @@
1
1
  import readline from 'node:readline';
2
2
  import { createClient } from '../../core/client.js';
3
- import pc from '../../utils/colors.js';
3
+ import colors from '../../utils/colors.js';
4
4
  export async function startInteractiveWebSocket(url, headers) {
5
- console.log(pc.gray('--------------------------------------------------'));
6
- console.log(pc.cyan(`Connecting to ${pc.bold(url)}...`));
7
- console.log(pc.gray('Commands: /quit to exit, /ping to send heartbeat'));
8
- console.log(pc.gray('--------------------------------------------------\n'));
5
+ console.log(colors.gray('--------------------------------------------------'));
6
+ console.log(colors.cyan(`Connecting to ${colors.bold(url)}...`));
7
+ console.log(colors.gray('Commands: /quit to exit, /ping to send heartbeat'));
8
+ console.log(colors.gray('--------------------------------------------------\n'));
9
9
  const client = createClient();
10
10
  let ws;
11
11
  try {
12
12
  ws = client.websocket(url, { headers });
13
13
  }
14
14
  catch (error) {
15
- console.error(pc.red(`Error creating WebSocket: ${error.message}`));
15
+ console.error(colors.red(`Error creating WebSocket: ${error.message}`));
16
16
  return;
17
17
  }
18
18
  const rl = readline.createInterface({
19
19
  input: process.stdin,
20
20
  output: process.stdout,
21
- prompt: pc.green('>> '),
21
+ prompt: colors.green('>> '),
22
22
  });
23
23
  const printIncoming = (text) => {
24
24
  readline.cursorTo(process.stdout, 0);
@@ -27,37 +27,37 @@ export async function startInteractiveWebSocket(url, headers) {
27
27
  rl.prompt(true);
28
28
  };
29
29
  ws.on('open', () => {
30
- printIncoming(pc.green('✔ Connected!'));
30
+ printIncoming(colors.green('✔ Connected!'));
31
31
  rl.prompt();
32
32
  });
33
33
  ws.on('close', (code, reason) => {
34
- printIncoming(pc.red(`✖ Disconnected (Code: ${code}${reason ? `, Reason: ${reason}` : ''})`));
34
+ printIncoming(colors.red(`✖ Disconnected (Code: ${code}${reason ? `, Reason: ${reason}` : ''})`));
35
35
  rl.close();
36
36
  process.exit(0);
37
37
  });
38
38
  ws.on('error', (err) => {
39
- printIncoming(pc.red(`⚠ Error: ${err.message}`));
39
+ printIncoming(colors.red(`⚠ Error: ${err.message}`));
40
40
  });
41
41
  ws.on('message', (msg) => {
42
42
  const content = msg.isBinary
43
- ? pc.yellow(`<Binary ${msg.data.length} bytes>`)
43
+ ? colors.yellow(`<Binary ${msg.data.length} bytes>`)
44
44
  : msg.data.toString();
45
- printIncoming(`${pc.cyan('<<')} ${content}`);
45
+ printIncoming(`${colors.cyan('<<')} ${content}`);
46
46
  });
47
47
  rl.on('line', (line) => {
48
48
  const input = line.trim();
49
49
  readline.moveCursor(process.stdout, 0, -1);
50
50
  readline.clearLine(process.stdout, 0);
51
- console.log(`${pc.green('>>')} ${input}`);
51
+ console.log(`${colors.green('>>')} ${input}`);
52
52
  if (input === '/quit' || input === '/exit') {
53
- console.log(pc.gray('Closing connection...'));
53
+ console.log(colors.gray('Closing connection...'));
54
54
  ws.close();
55
55
  rl.close();
56
56
  return;
57
57
  }
58
58
  if (input === '/ping') {
59
59
  ws.ping();
60
- console.log(pc.gray('(ping sent)'));
60
+ console.log(colors.gray('(ping sent)'));
61
61
  rl.prompt();
62
62
  return;
63
63
  }
@@ -66,11 +66,11 @@ export async function startInteractiveWebSocket(url, headers) {
66
66
  ws.send(input);
67
67
  }
68
68
  catch (err) {
69
- console.error(pc.red(`Failed to send: ${err.message}`));
69
+ console.error(colors.red(`Failed to send: ${err.message}`));
70
70
  }
71
71
  }
72
72
  else if (input && !ws.isConnected) {
73
- console.log(pc.yellow('Not connected.'));
73
+ console.log(colors.yellow('Not connected.'));
74
74
  }
75
75
  rl.prompt();
76
76
  });
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/contract/index.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,MAAM,KAAK,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE9C,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CACpC;AAED,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;AAMlE,KAAK,gBAAgB,CAAC,CAAC,SAAS,gBAAgB,IAAI,CAClD,IAAI,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,SAAS,GAAG;IAAE,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;CAAE,GAAG,EAAE,CAAC,GACvE,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,SAAS,GAAG;IAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;CAAE,GAAG,EAAE,CAAC,GACjE;IAAE,OAAO,CAAC,EAAE,WAAW,CAAA;CAAE,KAC5B,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC;AAGjF,MAAM,MAAM,cAAc,CAAC,CAAC,SAAS,kBAAkB,IAAI;KACxD,CAAC,IAAI,MAAM,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACvC,CAAC;AAEF,qBAAa,aAAc,SAAQ,KAAK;IACnB,MAAM,EAAE,MAAM;IAAS,IAAI,EAAE,GAAG;IAAS,aAAa,EAAE,SAAS;gBAAjE,MAAM,EAAE,MAAM,EAAS,IAAI,EAAE,GAAG,EAAS,aAAa,EAAE,SAAS;CAIrF;AAED,wBAAgB,cAAc,CAAC,CAAC,SAAS,kBAAkB,EACzD,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,CAAC,GACV,cAAc,CAAC,CAAC,CAAC,CAqEnB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/contract/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,MAAM,KAAK,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE9C,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CACpC;AAED,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;AAMlE,KAAK,gBAAgB,CAAC,CAAC,SAAS,gBAAgB,IAAI,CAClD,IAAI,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,SAAS,GAAG;IAAE,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;CAAE,GAAG,EAAE,CAAC,GACvE,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,SAAS,GAAG;IAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;CAAE,GAAG,EAAE,CAAC,GACjE;IAAE,OAAO,CAAC,EAAE,WAAW,CAAA;CAAE,KAC5B,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC;AAGjF,MAAM,MAAM,cAAc,CAAC,CAAC,SAAS,kBAAkB,IAAI;KACxD,CAAC,IAAI,MAAM,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACvC,CAAC;AAEF,qBAAa,aAAc,SAAQ,KAAK;IACnB,MAAM,EAAE,MAAM;IAAS,IAAI,EAAE,GAAG;IAAS,aAAa,EAAE,SAAS;gBAAjE,MAAM,EAAE,MAAM,EAAS,IAAI,EAAE,GAAG,EAAS,aAAa,EAAE,SAAS;CAIrF;AAED,wBAAgB,cAAc,CAAC,CAAC,SAAS,kBAAkB,EACzD,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,CAAC,GACV,cAAc,CAAC,CAAC,CAAC,CAqEnB"}