recker 1.0.4 → 1.0.6

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 (115) hide show
  1. package/README.md +1 -1
  2. package/dist/ai/adaptive-timeout.d.ts +51 -0
  3. package/dist/ai/adaptive-timeout.d.ts.map +1 -0
  4. package/dist/ai/adaptive-timeout.js +208 -0
  5. package/dist/ai/client.d.ts +24 -0
  6. package/dist/ai/client.d.ts.map +1 -0
  7. package/dist/ai/client.js +289 -0
  8. package/dist/ai/index.d.ts +10 -0
  9. package/dist/ai/index.d.ts.map +1 -0
  10. package/dist/ai/index.js +6 -0
  11. package/dist/ai/providers/anthropic.d.ts +64 -0
  12. package/dist/ai/providers/anthropic.d.ts.map +1 -0
  13. package/dist/ai/providers/anthropic.js +367 -0
  14. package/dist/ai/providers/base.d.ts +49 -0
  15. package/dist/ai/providers/base.d.ts.map +1 -0
  16. package/dist/ai/providers/base.js +145 -0
  17. package/dist/ai/providers/index.d.ts +7 -0
  18. package/dist/ai/providers/index.d.ts.map +1 -0
  19. package/dist/ai/providers/index.js +3 -0
  20. package/dist/ai/providers/openai.d.ts +65 -0
  21. package/dist/ai/providers/openai.d.ts.map +1 -0
  22. package/dist/ai/providers/openai.js +298 -0
  23. package/dist/ai/rate-limiter.d.ts +44 -0
  24. package/dist/ai/rate-limiter.d.ts.map +1 -0
  25. package/dist/ai/rate-limiter.js +212 -0
  26. package/dist/bench/generator.d.ts +19 -0
  27. package/dist/bench/generator.d.ts.map +1 -0
  28. package/dist/bench/generator.js +86 -0
  29. package/dist/bench/stats.d.ts +35 -0
  30. package/dist/bench/stats.d.ts.map +1 -0
  31. package/dist/bench/stats.js +60 -0
  32. package/dist/cache/memory-storage.d.ts.map +1 -1
  33. package/dist/cache/memory-storage.js +0 -5
  34. package/dist/cli/handler.d.ts +11 -0
  35. package/dist/cli/handler.d.ts.map +1 -0
  36. package/dist/cli/handler.js +92 -0
  37. package/dist/cli/index.d.ts +3 -0
  38. package/dist/cli/index.d.ts.map +1 -0
  39. package/dist/cli/index.js +255 -0
  40. package/dist/cli/presets.d.ts +2 -0
  41. package/dist/cli/presets.d.ts.map +1 -0
  42. package/dist/cli/presets.js +67 -0
  43. package/dist/cli/tui/ai-chat.d.ts +3 -0
  44. package/dist/cli/tui/ai-chat.d.ts.map +1 -0
  45. package/dist/cli/tui/ai-chat.js +100 -0
  46. package/dist/cli/tui/load-dashboard.d.ts +3 -0
  47. package/dist/cli/tui/load-dashboard.d.ts.map +1 -0
  48. package/dist/cli/tui/load-dashboard.js +117 -0
  49. package/dist/cli/tui/shell.d.ts +27 -0
  50. package/dist/cli/tui/shell.d.ts.map +1 -0
  51. package/dist/cli/tui/shell.js +386 -0
  52. package/dist/cli/tui/websocket.d.ts +2 -0
  53. package/dist/cli/tui/websocket.d.ts.map +1 -0
  54. package/dist/cli/tui/websocket.js +87 -0
  55. package/dist/contract/index.d.ts +2 -2
  56. package/dist/contract/index.d.ts.map +1 -1
  57. package/dist/core/client.d.ts +1 -0
  58. package/dist/core/client.d.ts.map +1 -1
  59. package/dist/core/client.js +4 -2
  60. package/dist/core/request-promise.d.ts +1 -1
  61. package/dist/core/request-promise.d.ts.map +1 -1
  62. package/dist/mcp/contract.d.ts +1 -1
  63. package/dist/mcp/contract.d.ts.map +1 -1
  64. package/dist/plugins/cache.d.ts.map +1 -1
  65. package/dist/plugins/cache.js +0 -7
  66. package/dist/plugins/scrape.d.ts.map +1 -1
  67. package/dist/plugins/scrape.js +9 -14
  68. package/dist/protocols/ftp.d.ts +28 -5
  69. package/dist/protocols/ftp.d.ts.map +1 -1
  70. package/dist/protocols/ftp.js +549 -136
  71. package/dist/protocols/sftp.d.ts +4 -2
  72. package/dist/protocols/sftp.d.ts.map +1 -1
  73. package/dist/protocols/sftp.js +16 -2
  74. package/dist/protocols/telnet.d.ts +37 -5
  75. package/dist/protocols/telnet.d.ts.map +1 -1
  76. package/dist/protocols/telnet.js +434 -58
  77. package/dist/runner/request-runner.d.ts.map +1 -1
  78. package/dist/runner/request-runner.js +0 -1
  79. package/dist/scrape/document.d.ts +3 -2
  80. package/dist/scrape/document.d.ts.map +1 -1
  81. package/dist/scrape/document.js +15 -3
  82. package/dist/testing/index.d.ts +2 -0
  83. package/dist/testing/index.d.ts.map +1 -1
  84. package/dist/testing/index.js +1 -0
  85. package/dist/testing/mock-udp-server.d.ts +44 -0
  86. package/dist/testing/mock-udp-server.d.ts.map +1 -0
  87. package/dist/testing/mock-udp-server.js +188 -0
  88. package/dist/transport/base-udp.d.ts +36 -0
  89. package/dist/transport/base-udp.d.ts.map +1 -0
  90. package/dist/transport/base-udp.js +188 -0
  91. package/dist/transport/udp-response.d.ts +65 -0
  92. package/dist/transport/udp-response.d.ts.map +1 -0
  93. package/dist/transport/udp-response.js +269 -0
  94. package/dist/transport/udp.d.ts +22 -0
  95. package/dist/transport/udp.d.ts.map +1 -0
  96. package/dist/transport/udp.js +260 -0
  97. package/dist/types/ai.d.ts +268 -0
  98. package/dist/types/ai.d.ts.map +1 -0
  99. package/dist/types/ai.js +1 -0
  100. package/dist/types/udp.d.ts +138 -0
  101. package/dist/types/udp.d.ts.map +1 -0
  102. package/dist/types/udp.js +1 -0
  103. package/dist/udp/index.d.ts +6 -0
  104. package/dist/udp/index.d.ts.map +1 -0
  105. package/dist/udp/index.js +3 -0
  106. package/dist/utils/chart.d.ts +15 -0
  107. package/dist/utils/chart.d.ts.map +1 -0
  108. package/dist/utils/chart.js +94 -0
  109. package/dist/utils/colors.d.ts +27 -0
  110. package/dist/utils/colors.d.ts.map +1 -0
  111. package/dist/utils/colors.js +50 -0
  112. package/dist/utils/optional-require.d.ts +20 -0
  113. package/dist/utils/optional-require.d.ts.map +1 -0
  114. package/dist/utils/optional-require.js +105 -0
  115. package/package.json +53 -12
@@ -0,0 +1,35 @@
1
+ export declare class LoadStats {
2
+ totalRequests: number;
3
+ successful: number;
4
+ failed: number;
5
+ bytesTransferred: number;
6
+ statusCodes: Record<number, number>;
7
+ errors: Record<string, number>;
8
+ latencies: number[];
9
+ private lastSnapshotTime;
10
+ private lastSnapshotRequests;
11
+ activeUsers: number;
12
+ addResult(durationMs: number, status: number, bytes: number, error?: Error): void;
13
+ getSnapshot(): {
14
+ rps: number;
15
+ p95: number;
16
+ activeUsers: number;
17
+ };
18
+ getSummary(): {
19
+ total: number;
20
+ success: number;
21
+ failed: number;
22
+ bytes: number;
23
+ rps: number;
24
+ latency: {
25
+ avg: number;
26
+ p50: number;
27
+ p95: number;
28
+ p99: number;
29
+ max: number;
30
+ };
31
+ codes: Record<number, number>;
32
+ errors: Record<string, number>;
33
+ };
34
+ }
35
+ //# sourceMappingURL=stats.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../../src/bench/stats.ts"],"names":[],"mappings":"AAAA,qBAAa,SAAS;IACpB,aAAa,SAAK;IAClB,UAAU,SAAK;IACf,MAAM,SAAK;IACX,gBAAgB,SAAK;IAErB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAM;IACzC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAM;IAGpC,SAAS,EAAE,MAAM,EAAE,CAAM;IAGzB,OAAO,CAAC,gBAAgB,CAAc;IACtC,OAAO,CAAC,oBAAoB,CAAK;IAGjC,WAAW,SAAK;IAEhB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;IAoB1E,WAAW;;;;;IAmBX,UAAU;;;;;;;;;;;;;;;;CAmBX"}
@@ -0,0 +1,60 @@
1
+ export class LoadStats {
2
+ totalRequests = 0;
3
+ successful = 0;
4
+ failed = 0;
5
+ bytesTransferred = 0;
6
+ statusCodes = {};
7
+ errors = {};
8
+ latencies = [];
9
+ lastSnapshotTime = Date.now();
10
+ lastSnapshotRequests = 0;
11
+ activeUsers = 0;
12
+ addResult(durationMs, status, bytes, error) {
13
+ this.totalRequests++;
14
+ this.bytesTransferred += bytes;
15
+ this.latencies.push(durationMs);
16
+ if (error || status >= 400) {
17
+ this.failed++;
18
+ if (error) {
19
+ const msg = error.message || 'Unknown Error';
20
+ this.errors[msg] = (this.errors[msg] || 0) + 1;
21
+ }
22
+ }
23
+ else {
24
+ this.successful++;
25
+ }
26
+ if (status) {
27
+ this.statusCodes[status] = (this.statusCodes[status] || 0) + 1;
28
+ }
29
+ }
30
+ getSnapshot() {
31
+ const now = Date.now();
32
+ const timeDiff = (now - this.lastSnapshotTime) / 1000;
33
+ const reqDiff = this.totalRequests - this.lastSnapshotRequests;
34
+ const rps = reqDiff / timeDiff;
35
+ this.lastSnapshotTime = now;
36
+ this.lastSnapshotRequests = this.totalRequests;
37
+ const recentLatencies = this.latencies.slice(-reqDiff);
38
+ recentLatencies.sort((a, b) => a - b);
39
+ const p95 = recentLatencies[Math.floor(recentLatencies.length * 0.95)] || 0;
40
+ return { rps, p95, activeUsers: this.activeUsers };
41
+ }
42
+ getSummary() {
43
+ this.latencies.sort((a, b) => a - b);
44
+ const avg = this.latencies.reduce((a, b) => a + b, 0) / this.latencies.length || 0;
45
+ const p50 = this.latencies[Math.floor(this.latencies.length * 0.50)] || 0;
46
+ const p95 = this.latencies[Math.floor(this.latencies.length * 0.95)] || 0;
47
+ const p99 = this.latencies[Math.floor(this.latencies.length * 0.99)] || 0;
48
+ const max = this.latencies[this.latencies.length - 1] || 0;
49
+ return {
50
+ total: this.totalRequests,
51
+ success: this.successful,
52
+ failed: this.failed,
53
+ bytes: this.bytesTransferred,
54
+ rps: Math.round(this.totalRequests / ((Date.now() - this.latencies[0]) / 1000) || 0),
55
+ latency: { avg, p50, p95, p99, max },
56
+ codes: this.statusCodes,
57
+ errors: this.errors
58
+ };
59
+ }
60
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"memory-storage.d.ts","sourceRoot":"","sources":["../../src/cache/memory-storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAE7D,qBAAa,aAAc,YAAW,YAAY;IAChD,OAAO,CAAC,OAAO,CAAiC;IAChD,OAAO,CAAC,IAAI,CAA6B;IAEnC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAmBjD,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQhE,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMxC,KAAK;CAIN"}
1
+ {"version":3,"file":"memory-storage.d.ts","sourceRoot":"","sources":["../../src/cache/memory-storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAE7D,qBAAa,aAAc,YAAW,YAAY;IAChD,OAAO,CAAC,OAAO,CAAiC;IAChD,OAAO,CAAC,IAAI,CAA6B;IAEnC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAejD,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOhE,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMxC,KAAK;CAIN"}
@@ -2,23 +2,18 @@ export class MemoryStorage {
2
2
  storage = new Map();
3
3
  ttls = new Map();
4
4
  async get(key) {
5
- console.log(`[DEBUG MemoryStorage] Getting key: ${key}`);
6
5
  const entry = this.storage.get(key);
7
6
  if (!entry) {
8
- console.log(`[DEBUG MemoryStorage] Key not found: ${key}`);
9
7
  return undefined;
10
8
  }
11
9
  const expiry = this.ttls.get(key);
12
10
  if (expiry && Date.now() > expiry) {
13
- console.log(`[DEBUG MemoryStorage] Key expired: ${key} (expiry: ${expiry}, now: ${Date.now()})`);
14
11
  this.delete(key);
15
12
  return undefined;
16
13
  }
17
- console.log(`[DEBUG MemoryStorage] Key found: ${key}`);
18
14
  return entry;
19
15
  }
20
16
  async set(key, entry, ttl) {
21
- console.log(`[DEBUG MemoryStorage] Setting key: ${key}, ttl: ${ttl}`);
22
17
  this.storage.set(key, entry);
23
18
  if (ttl) {
24
19
  this.ttls.set(key, Date.now() + ttl);
@@ -0,0 +1,11 @@
1
+ interface RequestOptions {
2
+ method: string;
3
+ url: string;
4
+ headers: Record<string, string>;
5
+ body?: any;
6
+ verbose?: boolean;
7
+ presetConfig?: any;
8
+ }
9
+ export declare function handleRequest(options: RequestOptions): Promise<void>;
10
+ export {};
11
+ //# sourceMappingURL=handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/cli/handler.ts"],"names":[],"mappings":"AAmBA,UAAU,cAAc;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,GAAG,CAAC;CACpB;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,cAAc,iBAqG1D"}
@@ -0,0 +1,92 @@
1
+ import { createClient } from '../core/client.js';
2
+ import { requireOptional } from '../utils/optional-require.js';
3
+ import pc from '../utils/colors.js';
4
+ import oraImport from 'ora';
5
+ let highlight;
6
+ const ora = oraImport;
7
+ async function initDependencies() {
8
+ if (!highlight) {
9
+ const cardinal = await requireOptional('cardinal', 'recker/cli');
10
+ highlight = cardinal.highlight;
11
+ }
12
+ }
13
+ export async function handleRequest(options) {
14
+ await initDependencies();
15
+ const spinner = ora({
16
+ text: `${pc.bold(options.method)} ${pc.cyan(options.url)}`,
17
+ color: 'cyan',
18
+ spinner: 'dots'
19
+ }).start();
20
+ const start = performance.now();
21
+ try {
22
+ let client;
23
+ if (options.presetConfig) {
24
+ client = createClient(options.presetConfig);
25
+ }
26
+ else {
27
+ try {
28
+ const urlObj = new URL(options.url);
29
+ client = createClient({ baseUrl: urlObj.origin });
30
+ }
31
+ catch {
32
+ client = createClient();
33
+ }
34
+ }
35
+ let requestBody = undefined;
36
+ if (options.body) {
37
+ requestBody = JSON.stringify(options.body);
38
+ if (!options.headers['Content-Type'] && !options.headers['content-type']) {
39
+ options.headers['Content-Type'] = 'application/json';
40
+ }
41
+ }
42
+ const response = await client.request(options.url, {
43
+ method: options.method,
44
+ headers: options.headers,
45
+ body: requestBody
46
+ });
47
+ const duration = Math.round(performance.now() - start);
48
+ spinner.stop();
49
+ const statusColor = response.ok ? pc.green : pc.red;
50
+ console.log(`${statusColor(pc.bold(response.status))} ${statusColor(response.statusText)} ` +
51
+ `${pc.gray(`(${duration}ms)`)}`);
52
+ if (options.verbose) {
53
+ console.log(pc.gray('\n--- Request ---'));
54
+ console.log(`${pc.bold(options.method)} ${options.url}`);
55
+ Object.entries(options.headers).forEach(([k, v]) => {
56
+ console.log(`${pc.blue(k)}: ${v}`);
57
+ });
58
+ if (options.body) {
59
+ console.log(pc.gray('Body:'), JSON.stringify(options.body, null, 2));
60
+ }
61
+ console.log(pc.gray('---------------\n'));
62
+ }
63
+ if (options.verbose) {
64
+ console.log(pc.gray('--- Response Headers ---'));
65
+ response.headers.forEach((value, key) => {
66
+ console.log(`${pc.blue(key)}: ${value}`);
67
+ });
68
+ console.log(pc.gray('------------------------\n'));
69
+ }
70
+ const contentType = response.headers.get('content-type') || '';
71
+ const text = await response.text();
72
+ if (!text)
73
+ return;
74
+ if (contentType.includes('application/json')) {
75
+ try {
76
+ const jsonObj = JSON.parse(text);
77
+ const jsonString = JSON.stringify(jsonObj, null, 2);
78
+ console.log(highlight(jsonString));
79
+ }
80
+ catch {
81
+ console.log(text);
82
+ }
83
+ }
84
+ else {
85
+ console.log(text);
86
+ }
87
+ }
88
+ catch (error) {
89
+ spinner.fail(pc.red('Request Failed'));
90
+ throw error;
91
+ }
92
+ }
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,255 @@
1
+ #!/usr/bin/env node
2
+ import { program } from 'commander';
3
+ import pc from '../utils/colors.js';
4
+ async function main() {
5
+ const { handleRequest } = await import('./handler.js');
6
+ const { resolvePreset } = await import('./presets.js');
7
+ const presets = await import('../presets/index.js');
8
+ let version = '0.0.0';
9
+ try {
10
+ const pkg = await import('../../package.json', { with: { type: 'json' } });
11
+ version = pkg.default?.version || '0.0.0';
12
+ }
13
+ catch {
14
+ }
15
+ function parseMixedArgs(args, hasPreset = false) {
16
+ const headers = {};
17
+ const data = {};
18
+ let method = 'GET';
19
+ let url = '';
20
+ const methods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'];
21
+ for (const arg of args) {
22
+ if (methods.includes(arg.toUpperCase())) {
23
+ method = arg.toUpperCase();
24
+ continue;
25
+ }
26
+ if (arg.includes(':') && !arg.includes('://') && !arg.includes('=')) {
27
+ const [key, value] = arg.split(':');
28
+ headers[key.trim()] = value.trim();
29
+ continue;
30
+ }
31
+ if (arg.includes('=')) {
32
+ if (method === 'GET')
33
+ method = 'POST';
34
+ const isTyped = arg.includes(':=');
35
+ const separator = isTyped ? ':=' : '=';
36
+ const [key, value] = arg.split(separator);
37
+ if (isTyped) {
38
+ if (value === 'true')
39
+ data[key] = true;
40
+ else if (value === 'false')
41
+ data[key] = false;
42
+ else if (!isNaN(Number(value)))
43
+ data[key] = Number(value);
44
+ else
45
+ data[key] = value;
46
+ }
47
+ else {
48
+ data[key] = value;
49
+ }
50
+ continue;
51
+ }
52
+ if (!url) {
53
+ url = arg;
54
+ if (!hasPreset && !url.startsWith('http') && !url.startsWith('ws') && !url.startsWith('udp')) {
55
+ url = `https://${url}`;
56
+ }
57
+ }
58
+ }
59
+ return { method, url, headers, data };
60
+ }
61
+ const PRESET_NAMES = Object.keys(presets).filter(k => k !== 'registry' && !k.startsWith('_'));
62
+ program
63
+ .name('rek')
64
+ .description('The HTTP Client for Humans (and Robots)')
65
+ .version(version)
66
+ .argument('[args...]', 'URL, Method, Headers (Key:Value), Data (key=value)')
67
+ .option('-v, --verbose', 'Show full request/response details')
68
+ .option('-j, --json', 'Force JSON content-type')
69
+ .addHelpText('after', `
70
+ ${pc.bold(pc.yellow('Examples:'))}
71
+ ${pc.green('$ rek httpbin.org/json')}
72
+ ${pc.green('$ rek post api.com/users name="Cyber" role="Admin"')}
73
+ ${pc.green('$ rek @github/user')}
74
+ ${pc.green('$ rek @openai/v1/chat/completions model="gpt-5.1"')}
75
+
76
+ ${pc.bold(pc.yellow('Available Presets:'))}
77
+ ${pc.cyan(PRESET_NAMES.map(p => '@' + p).join(', '))}
78
+ `)
79
+ .action(async (args, options) => {
80
+ if (args.length === 0) {
81
+ program.help();
82
+ return;
83
+ }
84
+ let argsToParse = args;
85
+ let presetConfig = undefined;
86
+ if (args[0].startsWith('@')) {
87
+ let presetName = args[0].slice(1);
88
+ let pathFromPreset = '';
89
+ if (presetName.includes('/')) {
90
+ const parts = presetName.split('/');
91
+ presetName = parts[0];
92
+ pathFromPreset = '/' + parts.slice(1).join('/');
93
+ }
94
+ presetConfig = resolvePreset(presetName);
95
+ argsToParse = args.slice(1);
96
+ if (pathFromPreset) {
97
+ argsToParse.unshift(pathFromPreset);
98
+ }
99
+ }
100
+ const { method, url, headers, data } = parseMixedArgs(argsToParse, !!presetConfig);
101
+ if (!url) {
102
+ console.error(pc.red('Error: URL/Path is required'));
103
+ process.exit(1);
104
+ }
105
+ if (options.json) {
106
+ headers['Content-Type'] = 'application/json';
107
+ headers['Accept'] = 'application/json';
108
+ }
109
+ if (url.startsWith('ws://') || url.startsWith('wss://')) {
110
+ const { startInteractiveWebSocket } = await import('./tui/websocket.js');
111
+ await startInteractiveWebSocket(url, headers);
112
+ return;
113
+ }
114
+ if (url.startsWith('udp://')) {
115
+ console.log(pc.yellow('UDP mode coming soon...'));
116
+ return;
117
+ }
118
+ try {
119
+ await handleRequest({
120
+ method,
121
+ url,
122
+ headers,
123
+ body: Object.keys(data).length > 0 ? data : undefined,
124
+ verbose: options.verbose,
125
+ presetConfig
126
+ });
127
+ }
128
+ catch (error) {
129
+ console.error(pc.red(`
130
+ Error: ${error.message}`));
131
+ if (options.verbose && error.cause) {
132
+ console.error(error.cause);
133
+ }
134
+ process.exit(1);
135
+ }
136
+ });
137
+ program
138
+ .command('completion')
139
+ .description('Generate shell completion script')
140
+ .action(() => {
141
+ const script = `
142
+ ###-begin-rek-completion-###
143
+ #
144
+ # rek command completion script
145
+ #
146
+ # Installation: rek completion >> ~/.bashrc (or ~/.zshrc)
147
+ # Or, maybe: source <(rek completion)
148
+ #
149
+
150
+ _rek_completions()
151
+ {
152
+ local cur prev words cword
153
+ _init_completion -n : || return
154
+
155
+ local presets="${PRESET_NAMES.map(p => '@' + p).join(' ')}"
156
+ local methods="GET POST PUT DELETE PATCH HEAD OPTIONS"
157
+ local opts="-v --verbose -j --json -h --help -V --version"
158
+
159
+ if [[ \\$cur == -* ]] ; then
160
+ COMPREPLY=( $(compgen -W "\\$opts" -- \\$cur) )
161
+ return 0
162
+ fi
163
+
164
+ if [[ \\$cur == @* ]] ; then
165
+ COMPREPLY=( $(compgen -W "\\$presets" -- \\$cur) )
166
+ return 0
167
+ fi
168
+
169
+ # If prev is a method, we likely want a URL next
170
+ # If prev is a preset, we might want a path (handled by generic completion)
171
+
172
+ # Suggest methods if it's the first argument (and not a preset/option)
173
+ if [[ \\$cword -eq 1 && ! \\$cur == -* && ! \\$cur == @* ]]; then
174
+ COMPREPLY=( $(compgen -W "\\$methods" -- \\$cur) )
175
+ fi
176
+
177
+ return 0
178
+ }
179
+ complete -F _rek_completions rek
180
+ ###-end-rek-completion-###
181
+ `;
182
+ console.log(script);
183
+ });
184
+ program
185
+ .command('shell')
186
+ .alias('interactive')
187
+ .alias('repl')
188
+ .description('Start the interactive Rek Shell')
189
+ .action(async () => {
190
+ const { RekShell } = await import('./tui/shell.js');
191
+ const shell = new RekShell();
192
+ shell.start();
193
+ });
194
+ const bench = program.command('bench').description('Performance benchmarking tools');
195
+ bench
196
+ .command('load')
197
+ .description('Run a load test with real-time dashboard')
198
+ .argument('[args...]', 'URL and options (users=10 duration=10s mode=throughput http2)')
199
+ .addHelpText('after', `
200
+ ${pc.bold(pc.yellow('Options (key=value):'))}
201
+ ${pc.green('users')} Number of concurrent users ${pc.gray('(default: 50)')}
202
+ ${pc.green('duration')} Test duration in seconds ${pc.gray('(default: 300)')}
203
+ ${pc.green('ramp')} Ramp-up time in seconds ${pc.gray('(default: 5)')}
204
+ ${pc.green('mode')} Test mode ${pc.gray('(default: throughput)')}
205
+ ${pc.gray('Values: throughput, stress, realistic')}
206
+ ${pc.green('http2')} Force HTTP/2 ${pc.gray('(default: false)')}
207
+
208
+ ${pc.bold(pc.yellow('Examples:'))}
209
+ ${pc.green('$ rek bench load httpbin.org/get users=100 duration=60 ramp=10')}
210
+ ${pc.green('$ rek bench load https://api.com/heavy mode=stress http2=true')}
211
+ `)
212
+ .action(async (args) => {
213
+ let url = '';
214
+ let users = 50;
215
+ let duration = 300;
216
+ let mode = 'throughput';
217
+ let http2 = false;
218
+ let rampUp = 5;
219
+ for (const arg of args) {
220
+ if (arg.includes('=')) {
221
+ const [key, val] = arg.split('=');
222
+ const k = key.toLowerCase();
223
+ if (k === 'users' || k === 'u')
224
+ users = parseInt(val);
225
+ else if (k === 'duration' || k === 'd' || k === 'time')
226
+ duration = parseInt(val);
227
+ else if (k === 'mode' || k === 'm')
228
+ mode = val;
229
+ else if (k === 'http2')
230
+ http2 = val === 'true';
231
+ else if (k === 'ramp' || k === 'rampup')
232
+ rampUp = parseInt(val);
233
+ }
234
+ else if (arg.toLowerCase() === 'http2') {
235
+ http2 = true;
236
+ }
237
+ else if (!url) {
238
+ url = arg;
239
+ if (!url.startsWith('http'))
240
+ url = `https://${url}`;
241
+ }
242
+ }
243
+ if (!url) {
244
+ console.error(pc.red('Error: URL is required. Example: rek bench load httpbin.org users=50'));
245
+ process.exit(1);
246
+ }
247
+ const { startLoadDashboard } = await import('./tui/load-dashboard.js');
248
+ await startLoadDashboard({ url, users, duration, mode, http2, rampUp });
249
+ });
250
+ program.parse();
251
+ }
252
+ main().catch((error) => {
253
+ console.error('CLI Error:', error.message);
254
+ process.exit(1);
255
+ });
@@ -0,0 +1,2 @@
1
+ export declare function resolvePreset(name: string): any;
2
+ //# sourceMappingURL=presets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../../src/cli/presets.ts"],"names":[],"mappings":"AAiBA,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,OAsCzC"}
@@ -0,0 +1,67 @@
1
+ import * as presets from '../presets/index.js';
2
+ import pc from '../utils/colors.js';
3
+ const ENV_MAPPING = {
4
+ openai: ['OPENAI_API_KEY'],
5
+ anthropic: ['ANTHROPIC_API_KEY'],
6
+ github: ['GITHUB_TOKEN'],
7
+ gitlab: ['GITLAB_TOKEN'],
8
+ stripe: ['STRIPE_SECRET_KEY'],
9
+ discord: ['DISCORD_TOKEN'],
10
+ slack: ['SLACK_TOKEN'],
11
+ vercel: ['VERCEL_TOKEN'],
12
+ supabase: ['SUPABASE_URL', 'SUPABASE_KEY'],
13
+ };
14
+ export function resolvePreset(name) {
15
+ const presetFn = presets[name];
16
+ if (!presetFn) {
17
+ console.error(pc.red(`Error: Unknown preset '@${name}'`));
18
+ process.exit(1);
19
+ }
20
+ const requiredEnvs = ENV_MAPPING[name];
21
+ const options = {};
22
+ if (requiredEnvs) {
23
+ let missing = false;
24
+ for (const envVar of requiredEnvs) {
25
+ const value = process.env[envVar];
26
+ if (!value) {
27
+ console.error(pc.yellow(`Warning: Missing env variable ${envVar} for preset @${name}`));
28
+ missing = true;
29
+ }
30
+ else {
31
+ const key = mapEnvToOption(name, envVar);
32
+ options[key] = value;
33
+ }
34
+ }
35
+ if (missing) {
36
+ console.log(pc.gray(`Tip: export ${requiredEnvs.join('=... ')}=...`));
37
+ }
38
+ }
39
+ try {
40
+ return presetFn(options);
41
+ }
42
+ catch (error) {
43
+ console.error(pc.red(`Error initializing preset @${name}: ${error.message}`));
44
+ process.exit(1);
45
+ }
46
+ }
47
+ function mapEnvToOption(preset, env) {
48
+ if (env.endsWith('_KEY') || env.endsWith('_TOKEN'))
49
+ return 'apiKey';
50
+ if (env === 'GITHUB_TOKEN')
51
+ return 'token';
52
+ if (env === 'GITLAB_TOKEN')
53
+ return 'token';
54
+ if (env === 'DISCORD_TOKEN')
55
+ return 'token';
56
+ if (env === 'SLACK_TOKEN')
57
+ return 'token';
58
+ if (env === 'VERCEL_TOKEN')
59
+ return 'token';
60
+ if (env === 'STRIPE_SECRET_KEY')
61
+ return 'secretKey';
62
+ if (env === 'SUPABASE_URL')
63
+ return 'projectUrl';
64
+ if (env === 'SUPABASE_KEY')
65
+ return 'apiKey';
66
+ return 'apiKey';
67
+ }
@@ -0,0 +1,3 @@
1
+ import readline from 'node:readline';
2
+ export declare function startAIChat(rl: readline.Interface, provider?: string, apiKey?: string, model?: string): Promise<void>;
3
+ //# sourceMappingURL=ai-chat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-chat.d.ts","sourceRoot":"","sources":["../../../src/cli/tui/ai-chat.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,eAAe,CAAC;AAKrC,wBAAsB,WAAW,CAAC,EAAE,EAAE,QAAQ,CAAC,SAAS,EAAE,QAAQ,GAAE,MAAiB,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,iBAwHrH"}