@calltelemetry/cli 0.4.6 → 0.4.8

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 (66) hide show
  1. package/dist/commands/loadtest.d.ts +3 -0
  2. package/dist/commands/loadtest.d.ts.map +1 -0
  3. package/dist/commands/loadtest.js +22 -0
  4. package/dist/commands/loadtest.js.map +1 -0
  5. package/dist/index.js +3 -1
  6. package/dist/index.js.map +1 -1
  7. package/dist/lib/curri-xml.d.ts +21 -0
  8. package/dist/lib/curri-xml.d.ts.map +1 -0
  9. package/dist/lib/curri-xml.js +53 -0
  10. package/dist/lib/curri-xml.js.map +1 -0
  11. package/dist/lib/loadtest-stats.d.ts +91 -0
  12. package/dist/lib/loadtest-stats.d.ts.map +1 -0
  13. package/dist/lib/loadtest-stats.js +23 -0
  14. package/dist/lib/loadtest-stats.js.map +1 -0
  15. package/dist/lib/loadtest.d.ts +14 -0
  16. package/dist/lib/loadtest.d.ts.map +1 -0
  17. package/dist/lib/loadtest.js +112 -0
  18. package/dist/lib/loadtest.js.map +1 -0
  19. package/dist/lib/rpc-scripts.d.ts +2 -0
  20. package/dist/lib/rpc-scripts.d.ts.map +1 -1
  21. package/dist/lib/rpc-scripts.js +29 -0
  22. package/dist/lib/rpc-scripts.js.map +1 -1
  23. package/dist/ui/components/Sparkline.d.ts +15 -0
  24. package/dist/ui/components/Sparkline.d.ts.map +1 -0
  25. package/dist/ui/components/Sparkline.js +21 -0
  26. package/dist/ui/components/Sparkline.js.map +1 -0
  27. package/dist/ui/components/index.d.ts +1 -0
  28. package/dist/ui/components/index.d.ts.map +1 -1
  29. package/dist/ui/components/index.js +1 -0
  30. package/dist/ui/components/index.js.map +1 -1
  31. package/dist/ui/context/MetricsContext.d.ts.map +1 -1
  32. package/dist/ui/context/MetricsContext.js +4 -2
  33. package/dist/ui/context/MetricsContext.js.map +1 -1
  34. package/dist/ui/hooks/index.d.ts +2 -0
  35. package/dist/ui/hooks/index.d.ts.map +1 -1
  36. package/dist/ui/hooks/index.js +1 -0
  37. package/dist/ui/hooks/index.js.map +1 -1
  38. package/dist/ui/hooks/useLoadTest.d.ts +11 -0
  39. package/dist/ui/hooks/useLoadTest.d.ts.map +1 -0
  40. package/dist/ui/hooks/useLoadTest.js +38 -0
  41. package/dist/ui/hooks/useLoadTest.js.map +1 -0
  42. package/dist/ui/views/DiagNetworkView.js +61 -54
  43. package/dist/ui/views/DiagNetworkView.js.map +1 -1
  44. package/dist/ui/views/LoadTestConfigView.d.ts +31 -0
  45. package/dist/ui/views/LoadTestConfigView.d.ts.map +1 -0
  46. package/dist/ui/views/LoadTestConfigView.js +111 -0
  47. package/dist/ui/views/LoadTestConfigView.js.map +1 -0
  48. package/dist/ui/views/LoadTestRunView.d.ts +10 -0
  49. package/dist/ui/views/LoadTestRunView.d.ts.map +1 -0
  50. package/dist/ui/views/LoadTestRunView.js +71 -0
  51. package/dist/ui/views/LoadTestRunView.js.map +1 -0
  52. package/dist/ui/views/LoadTestSummaryView.d.ts +9 -0
  53. package/dist/ui/views/LoadTestSummaryView.d.ts.map +1 -0
  54. package/dist/ui/views/LoadTestSummaryView.js +72 -0
  55. package/dist/ui/views/LoadTestSummaryView.js.map +1 -0
  56. package/dist/ui/views/LoadTestView.d.ts +8 -0
  57. package/dist/ui/views/LoadTestView.d.ts.map +1 -0
  58. package/dist/ui/views/LoadTestView.js +43 -0
  59. package/dist/ui/views/LoadTestView.js.map +1 -0
  60. package/dist/ui/views/MainMenu.d.ts.map +1 -1
  61. package/dist/ui/views/MainMenu.js +90 -21
  62. package/dist/ui/views/MainMenu.js.map +1 -1
  63. package/dist/ui/views/StatusView.d.ts.map +1 -1
  64. package/dist/ui/views/StatusView.js +134 -21
  65. package/dist/ui/views/StatusView.js.map +1 -1
  66. package/package.json +2 -1
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerLoadtestCommand(program: Command): void;
3
+ //# sourceMappingURL=loadtest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loadtest.d.ts","sourceRoot":"","sources":["../../src/commands/loadtest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,QAmBvD"}
@@ -0,0 +1,22 @@
1
+ import { render } from 'ink';
2
+ import React from 'react';
3
+ import { LoadTestView } from '../ui/views/LoadTestView.js';
4
+ export function registerLoadtestCommand(program) {
5
+ program
6
+ .command('loadtest')
7
+ .description('CURRI policy load tester with live metrics')
8
+ .option('--policy <name>', 'Policy name (skip selection)')
9
+ .option('--rate <n>', 'Target requests per second')
10
+ .option('--duration <n>', 'Test duration in seconds')
11
+ .option('--connections <n>', 'Number of connections')
12
+ .option('--calling <number>', 'Override calling number')
13
+ .option('--called <number>', 'Override called number')
14
+ .option('--device <name>', 'Override device name')
15
+ .option('--trigger <type>', 'Trigger point type')
16
+ .option('--url <url>', 'CURRI endpoint URL (auto-detected)')
17
+ .action(async (opts) => {
18
+ const { waitUntilExit } = render(React.createElement(LoadTestView, { cliOptions: opts }));
19
+ await waitUntilExit();
20
+ });
21
+ }
22
+ //# sourceMappingURL=loadtest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loadtest.js","sourceRoot":"","sources":["../../src/commands/loadtest.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAE3D,MAAM,UAAU,uBAAuB,CAAC,OAAgB;IACtD,OAAO;SACJ,OAAO,CAAC,UAAU,CAAC;SACnB,WAAW,CAAC,4CAA4C,CAAC;SACzD,MAAM,CAAC,iBAAiB,EAAE,8BAA8B,CAAC;SACzD,MAAM,CAAC,YAAY,EAAE,4BAA4B,CAAC;SAClD,MAAM,CAAC,gBAAgB,EAAE,0BAA0B,CAAC;SACpD,MAAM,CAAC,mBAAmB,EAAE,uBAAuB,CAAC;SACpD,MAAM,CAAC,oBAAoB,EAAE,yBAAyB,CAAC;SACvD,MAAM,CAAC,mBAAmB,EAAE,wBAAwB,CAAC;SACrD,MAAM,CAAC,iBAAiB,EAAE,sBAAsB,CAAC;SACjD,MAAM,CAAC,kBAAkB,EAAE,oBAAoB,CAAC;SAChD,MAAM,CAAC,aAAa,EAAE,oCAAoC,CAAC;SAC3D,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACrB,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,CAC9B,KAAK,CAAC,aAAa,CAAC,YAAY,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CACxD,CAAC;QACF,MAAM,aAAa,EAAE,CAAC;IACxB,CAAC,CAAC,CAAC;AACP,CAAC"}
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- const VERSION = '0.4.6';
2
+ const VERSION = '0.4.8';
3
3
  import { Command } from 'commander';
4
4
  import { registerStatusCommand } from './commands/status.js';
5
5
  import { registerUpdateCommand } from './commands/update.js';
@@ -14,6 +14,7 @@ import { registerSecretsCommand } from './commands/secrets.js';
14
14
  import { registerUsersCommand } from './commands/users.js';
15
15
  import { registerServicesCommand } from './commands/services.js';
16
16
  import { registerSelfUpdateCommand } from './commands/self-update.js';
17
+ import { registerLoadtestCommand } from './commands/loadtest.js';
17
18
  import { LOGO } from './lib/brand.js';
18
19
  import { setVerbose, setGlobalLevel } from './lib/log.js';
19
20
  import { loadPrefs } from './lib/prefs.js';
@@ -53,6 +54,7 @@ registerSecretsCommand(program);
53
54
  registerUsersCommand(program);
54
55
  registerServicesCommand(program);
55
56
  registerSelfUpdateCommand(program);
57
+ registerLoadtestCommand(program);
56
58
  // Interactive menu when `ct` is run with no arguments on a TTY
57
59
  // Flags like --debug and --verbose are not commands; only positional args count
58
60
  const nonFlagArgs = process.argv.slice(2).filter(a => !a.startsWith('-'));
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /** XACML 2.0 XML builder for CURRI load testing. */
2
+ export interface CurriXmlOptions {
3
+ callingNumber: string;
4
+ calledNumber: string;
5
+ deviceName: string;
6
+ triggerType: string;
7
+ }
8
+ /** Generate a random 10-digit US phone number. */
9
+ export declare function randomPhoneNumber(): string;
10
+ /** Generate a random Cisco device MAC name (SEP + 12 hex chars). */
11
+ export declare function randomDeviceName(): string;
12
+ /** Build XACML 2.0 XML for a CURRI policy request. */
13
+ export declare function buildCurriXml(opts: CurriXmlOptions): string;
14
+ /** Build CURRI XML with random or custom values based on config. */
15
+ export declare function buildCurriXmlFromConfig(config: {
16
+ callingNumber: string;
17
+ calledNumber: string;
18
+ deviceName: string;
19
+ triggerType: string;
20
+ }): string;
21
+ //# sourceMappingURL=curri-xml.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"curri-xml.d.ts","sourceRoot":"","sources":["../../src/lib/curri-xml.ts"],"names":[],"mappings":"AAAA,oDAAoD;AAEpD,MAAM,WAAW,eAAe;IAC9B,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,kDAAkD;AAClD,wBAAgB,iBAAiB,IAAI,MAAM,CAK1C;AAED,oEAAoE;AACpE,wBAAgB,gBAAgB,IAAI,MAAM,CAKzC;AAED,sDAAsD;AACtD,wBAAgB,aAAa,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,CA4B3D;AAED,oEAAoE;AACpE,wBAAgB,uBAAuB,CAAC,MAAM,EAAE;IAC9C,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB,GAAG,MAAM,CAOT"}
@@ -0,0 +1,53 @@
1
+ /** XACML 2.0 XML builder for CURRI load testing. */
2
+ /** Generate a random 10-digit US phone number. */
3
+ export function randomPhoneNumber() {
4
+ const areaCode = 200 + Math.floor(Math.random() * 800); // 200-999
5
+ const exchange = 200 + Math.floor(Math.random() * 800); // 200-999
6
+ const subscriber = Math.floor(Math.random() * 10000);
7
+ return `${areaCode}${exchange}${subscriber.toString().padStart(4, '0')}`;
8
+ }
9
+ /** Generate a random Cisco device MAC name (SEP + 12 hex chars). */
10
+ export function randomDeviceName() {
11
+ const hex = Array.from({ length: 12 }, () => Math.floor(Math.random() * 16).toString(16).toUpperCase()).join('');
12
+ return `SEP${hex}`;
13
+ }
14
+ /** Build XACML 2.0 XML for a CURRI policy request. */
15
+ export function buildCurriXml(opts) {
16
+ return `<?xml version="1.0" encoding="UTF-8"?>
17
+ <Request xmlns="urn:oasis:names:tc:xacml:2.0:context:schema:os">
18
+ <Subject SubjectCategory="urn:oasis:names:tc:xacml:1.0:Subject-Category:access-Subject">
19
+ <Attribute AttributeId="urn:Cisco:uc:1.0:callingnumber">
20
+ <AttributeValue>${opts.callingNumber}</AttributeValue>
21
+ </Attribute>
22
+ <Attribute AttributeId="urn:Cisco:uc:1.0:callednumber">
23
+ <AttributeValue>${opts.calledNumber}</AttributeValue>
24
+ </Attribute>
25
+ <Attribute AttributeId="urn:Cisco:uc:1.0:callingdevicename">
26
+ <AttributeValue>${opts.deviceName}</AttributeValue>
27
+ </Attribute>
28
+ <Attribute AttributeId="urn:Cisco:uc:1.0:triggerpointtype">
29
+ <AttributeValue>${opts.triggerType}</AttributeValue>
30
+ </Attribute>
31
+ </Subject>
32
+ <Resource>
33
+ <Attribute AttributeId="urn:oasis:names:tc:xacml:1.0:Resource:Resource-Id">
34
+ <AttributeValue>CISCO:UC:VoiceOrVideoCall</AttributeValue>
35
+ </Attribute>
36
+ </Resource>
37
+ <action>
38
+ <Attribute AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-Id">
39
+ <AttributeValue>any</AttributeValue>
40
+ </Attribute>
41
+ </action>
42
+ </Request>`;
43
+ }
44
+ /** Build CURRI XML with random or custom values based on config. */
45
+ export function buildCurriXmlFromConfig(config) {
46
+ return buildCurriXml({
47
+ callingNumber: config.callingNumber === 'random' ? randomPhoneNumber() : config.callingNumber,
48
+ calledNumber: config.calledNumber === 'random' ? randomPhoneNumber() : config.calledNumber,
49
+ deviceName: config.deviceName === 'random' ? randomDeviceName() : config.deviceName,
50
+ triggerType: config.triggerType,
51
+ });
52
+ }
53
+ //# sourceMappingURL=curri-xml.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"curri-xml.js","sourceRoot":"","sources":["../../src/lib/curri-xml.ts"],"names":[],"mappings":"AAAA,oDAAoD;AASpD,kDAAkD;AAClD,MAAM,UAAU,iBAAiB;IAC/B,MAAM,QAAQ,GAAG,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,UAAU;IAClE,MAAM,QAAQ,GAAG,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,UAAU;IAClE,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC;IACrD,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;AAC3E,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,gBAAgB;IAC9B,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,CAC1C,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAC1D,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACX,OAAO,MAAM,GAAG,EAAE,CAAC;AACrB,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,aAAa,CAAC,IAAqB;IACjD,OAAO;;;;wBAIe,IAAI,CAAC,aAAa;;;wBAGlB,IAAI,CAAC,YAAY;;;wBAGjB,IAAI,CAAC,UAAU;;;wBAGf,IAAI,CAAC,WAAW;;;;;;;;;;;;;WAa7B,CAAC;AACZ,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,uBAAuB,CAAC,MAKvC;IACC,OAAO,aAAa,CAAC;QACnB,aAAa,EAAE,MAAM,CAAC,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa;QAC7F,YAAY,EAAE,MAAM,CAAC,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY;QAC1F,UAAU,EAAE,MAAM,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU;QACnF,WAAW,EAAE,MAAM,CAAC,WAAW;KAChC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,91 @@
1
+ /** Types for the CURRI load testing engine. */
2
+ export interface LoadTestConfig {
3
+ /** CURRI endpoint URL (e.g., http://127.0.0.1:4080) */
4
+ url: string;
5
+ /** Policy API key for ?api_key= param */
6
+ apiKey: string;
7
+ /** Policy name for display */
8
+ policyName: string;
9
+ /** Target requests per second */
10
+ rate: number;
11
+ /** Test duration in seconds */
12
+ duration: number;
13
+ /** Number of HTTP connections */
14
+ connections: number;
15
+ /** Override calling number (or 'random') */
16
+ callingNumber: string;
17
+ /** Override called number (or 'random') */
18
+ calledNumber: string;
19
+ /** Override device name (or 'random') */
20
+ deviceName: string;
21
+ /** Trigger point type */
22
+ triggerType: string;
23
+ }
24
+ export interface LoadTestSnapshot {
25
+ /** Elapsed seconds */
26
+ elapsed: number;
27
+ /** Requests completed in this interval */
28
+ requestsInInterval: number;
29
+ /** Cumulative totals */
30
+ totalRequests: number;
31
+ successCount: number;
32
+ errorCount: number;
33
+ timeoutCount: number;
34
+ /** Latency percentiles in ms */
35
+ p50: number;
36
+ p95: number;
37
+ p99: number;
38
+ max: number;
39
+ mean: number;
40
+ /** Rate history for sparkline (last N intervals) */
41
+ rateHistory: number[];
42
+ }
43
+ export interface LoadTestResults {
44
+ config: LoadTestConfig;
45
+ duration: number;
46
+ totalRequests: number;
47
+ successCount: number;
48
+ errorCount: number;
49
+ timeoutCount: number;
50
+ bytesRead: number;
51
+ bytesSent: number;
52
+ latency: {
53
+ p50: number;
54
+ p95: number;
55
+ p99: number;
56
+ p999: number;
57
+ max: number;
58
+ mean: number;
59
+ stddev: number;
60
+ };
61
+ throughput: {
62
+ average: number;
63
+ max: number;
64
+ min: number;
65
+ };
66
+ }
67
+ export interface CurriPolicy {
68
+ id: number;
69
+ name: string;
70
+ api_key: string;
71
+ org_id: number;
72
+ org_name: string;
73
+ }
74
+ /** Maximum number of rate samples kept in the sparkline history. */
75
+ export declare const MAX_RATE_HISTORY = 30;
76
+ /** Build a LoadTestSnapshot from autocannon tick data. */
77
+ export declare function buildSnapshot(counter: {
78
+ counter: number;
79
+ bytes: number;
80
+ }, elapsed: number, rateHistory: number[], latencyData: {
81
+ p50: number;
82
+ p95: number;
83
+ p99: number;
84
+ max: number;
85
+ mean: number;
86
+ }, totals: {
87
+ requests: number;
88
+ errors: number;
89
+ timeouts: number;
90
+ }): LoadTestSnapshot;
91
+ //# sourceMappingURL=loadtest-stats.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loadtest-stats.d.ts","sourceRoot":"","sources":["../../src/lib/loadtest-stats.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAE/C,MAAM,WAAW,cAAc;IAC7B,uDAAuD;IACvD,GAAG,EAAE,MAAM,CAAC;IACZ,yCAAyC;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,8BAA8B;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,iCAAiC;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,4CAA4C;IAC5C,aAAa,EAAE,MAAM,CAAC;IACtB,2CAA2C;IAC3C,YAAY,EAAE,MAAM,CAAC;IACrB,yCAAyC;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,yBAAyB;IACzB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,sBAAsB;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,kBAAkB,EAAE,MAAM,CAAC;IAC3B,wBAAwB;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,gCAAgC;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,oDAAoD;IACpD,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,cAAc,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE;QACP,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,UAAU,EAAE;QACV,OAAO,EAAE,MAAM,CAAC;QAChB,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;CACH;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,oEAAoE;AACpE,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAEnC,0DAA0D;AAC1D,wBAAgB,aAAa,CAC3B,OAAO,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAC3C,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EAAE,EACrB,WAAW,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EACjF,MAAM,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC7D,gBAAgB,CAkBlB"}
@@ -0,0 +1,23 @@
1
+ /** Types for the CURRI load testing engine. */
2
+ /** Maximum number of rate samples kept in the sparkline history. */
3
+ export const MAX_RATE_HISTORY = 30;
4
+ /** Build a LoadTestSnapshot from autocannon tick data. */
5
+ export function buildSnapshot(counter, elapsed, rateHistory, latencyData, totals) {
6
+ const requestsInInterval = counter.counter;
7
+ const updatedHistory = [...rateHistory, requestsInInterval].slice(-MAX_RATE_HISTORY);
8
+ return {
9
+ elapsed,
10
+ requestsInInterval,
11
+ totalRequests: totals.requests,
12
+ successCount: totals.requests - totals.errors - totals.timeouts,
13
+ errorCount: totals.errors,
14
+ timeoutCount: totals.timeouts,
15
+ p50: latencyData.p50,
16
+ p95: latencyData.p95,
17
+ p99: latencyData.p99,
18
+ max: latencyData.max,
19
+ mean: latencyData.mean,
20
+ rateHistory: updatedHistory,
21
+ };
22
+ }
23
+ //# sourceMappingURL=loadtest-stats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loadtest-stats.js","sourceRoot":"","sources":["../../src/lib/loadtest-stats.ts"],"names":[],"mappings":"AAAA,+CAA+C;AA8E/C,oEAAoE;AACpE,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAEnC,0DAA0D;AAC1D,MAAM,UAAU,aAAa,CAC3B,OAA2C,EAC3C,OAAe,EACf,WAAqB,EACrB,WAAiF,EACjF,MAA8D;IAE9D,MAAM,kBAAkB,GAAG,OAAO,CAAC,OAAO,CAAC;IAC3C,MAAM,cAAc,GAAG,CAAC,GAAG,WAAW,EAAE,kBAAkB,CAAC,CAAC,KAAK,CAAC,CAAC,gBAAgB,CAAC,CAAC;IAErF,OAAO;QACL,OAAO;QACP,kBAAkB;QAClB,aAAa,EAAE,MAAM,CAAC,QAAQ;QAC9B,YAAY,EAAE,MAAM,CAAC,QAAQ,GAAG,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,QAAQ;QAC/D,UAAU,EAAE,MAAM,CAAC,MAAM;QACzB,YAAY,EAAE,MAAM,CAAC,QAAQ;QAC7B,GAAG,EAAE,WAAW,CAAC,GAAG;QACpB,GAAG,EAAE,WAAW,CAAC,GAAG;QACpB,GAAG,EAAE,WAAW,CAAC,GAAG;QACpB,GAAG,EAAE,WAAW,CAAC,GAAG;QACpB,IAAI,EAAE,WAAW,CAAC,IAAI;QACtB,WAAW,EAAE,cAAc;KAC5B,CAAC;AACJ,CAAC"}
@@ -0,0 +1,14 @@
1
+ /** CURRI load test engine wrapping autocannon. */
2
+ import type { LoadTestConfig, LoadTestResults, LoadTestSnapshot } from './loadtest-stats.js';
3
+ export type { LoadTestConfig, LoadTestResults, LoadTestSnapshot } from './loadtest-stats.js';
4
+ /** Default CURRI endpoint URL. */
5
+ export declare const DEFAULT_CURRI_URL = "http://127.0.0.1:4080";
6
+ export interface LoadTestHandle {
7
+ /** Promise that resolves when the test completes. */
8
+ promise: Promise<LoadTestResults>;
9
+ /** Stop the load test early. */
10
+ stop: () => void;
11
+ }
12
+ /** Start a CURRI load test with live progress callbacks. */
13
+ export declare function startLoadTest(config: LoadTestConfig, onProgress: (snapshot: LoadTestSnapshot) => void): LoadTestHandle;
14
+ //# sourceMappingURL=loadtest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loadtest.d.ts","sourceRoot":"","sources":["../../src/lib/loadtest.ts"],"names":[],"mappings":"AAAA,kDAAkD;AAIlD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAO7F,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE7F,kCAAkC;AAClC,eAAO,MAAM,iBAAiB,0BAA0B,CAAC;AAEzD,MAAM,WAAW,cAAc;IAC7B,qDAAqD;IACrD,OAAO,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IAClC,gCAAgC;IAChC,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB;AAED,4DAA4D;AAC5D,wBAAgB,aAAa,CAC3B,MAAM,EAAE,cAAc,EACtB,UAAU,EAAE,CAAC,QAAQ,EAAE,gBAAgB,KAAK,IAAI,GAC/C,cAAc,CA4GhB"}
@@ -0,0 +1,112 @@
1
+ /** CURRI load test engine wrapping autocannon. */
2
+ import { createRequire } from 'module';
3
+ import { buildCurriXmlFromConfig } from './curri-xml.js';
4
+ import { MAX_RATE_HISTORY } from './loadtest-stats.js';
5
+ // autocannon is CJS — use createRequire for ESM compatibility
6
+ const require = createRequire(import.meta.url);
7
+ const autocannon = require('autocannon');
8
+ /** Default CURRI endpoint URL. */
9
+ export const DEFAULT_CURRI_URL = 'http://127.0.0.1:4080';
10
+ /** Start a CURRI load test with live progress callbacks. */
11
+ export function startLoadTest(config, onProgress) {
12
+ let elapsed = 0;
13
+ let totalRequests = 0;
14
+ let totalErrors = 0;
15
+ let totalTimeouts = 0;
16
+ const rateHistory = [];
17
+ // Latest latency data from tick events
18
+ let latencyP50 = 0;
19
+ let latencyP95 = 0;
20
+ let latencyP99 = 0;
21
+ let latencyMax = 0;
22
+ let latencyMean = 0;
23
+ const instance = autocannon({
24
+ url: `${config.url}/api/policy?api_key=${config.apiKey}`,
25
+ method: 'POST',
26
+ headers: { 'content-type': 'application/xml' },
27
+ connections: config.connections,
28
+ duration: config.duration,
29
+ overallRate: config.rate,
30
+ timeout: 10,
31
+ setupRequest(req) {
32
+ req.body = buildCurriXmlFromConfig({
33
+ callingNumber: config.callingNumber,
34
+ calledNumber: config.calledNumber,
35
+ deviceName: config.deviceName,
36
+ triggerType: config.triggerType,
37
+ });
38
+ return req;
39
+ },
40
+ });
41
+ // Suppress autocannon's built-in progress output
42
+ autocannon.track(instance, {
43
+ renderProgressBar: false,
44
+ renderResultsTable: false,
45
+ renderLatencyTable: false,
46
+ });
47
+ // Track individual responses for latency info
48
+ instance.on('response', (_client, statusCode, _resBytes, responseTime) => {
49
+ totalRequests++;
50
+ if (statusCode >= 400)
51
+ totalErrors++;
52
+ // Update rolling latency estimates (rough, tick gives better data)
53
+ void responseTime;
54
+ void statusCode;
55
+ });
56
+ instance.on('tick', (value) => {
57
+ elapsed++;
58
+ const requestsInInterval = value.counter;
59
+ rateHistory.push(requestsInInterval);
60
+ if (rateHistory.length > MAX_RATE_HISTORY)
61
+ rateHistory.shift();
62
+ const snapshot = {
63
+ elapsed,
64
+ requestsInInterval,
65
+ totalRequests,
66
+ successCount: totalRequests - totalErrors - totalTimeouts,
67
+ errorCount: totalErrors,
68
+ timeoutCount: totalTimeouts,
69
+ p50: latencyP50,
70
+ p95: latencyP95,
71
+ p99: latencyP99,
72
+ max: latencyMax,
73
+ mean: latencyMean,
74
+ rateHistory: [...rateHistory],
75
+ };
76
+ onProgress(snapshot);
77
+ });
78
+ const promise = new Promise((resolve, reject) => {
79
+ instance.on('done', (result) => {
80
+ resolve({
81
+ config,
82
+ duration: result.duration,
83
+ totalRequests: result['2xx'] + result['3xx'] + result['4xx'] + result['5xx'] + result['1xx'],
84
+ successCount: result['2xx'] + result['3xx'],
85
+ errorCount: result.errors + result['4xx'] + result['5xx'],
86
+ timeoutCount: result.timeouts,
87
+ bytesRead: result.throughput.totalCount,
88
+ bytesSent: 0, // autocannon doesn't track sent bytes
89
+ latency: {
90
+ p50: result.latency.p50,
91
+ p95: result.latency.p97_5,
92
+ p99: result.latency.p99,
93
+ p999: result.latency.p99_9,
94
+ max: result.latency.max,
95
+ mean: result.latency.mean,
96
+ stddev: result.latency.stddev,
97
+ },
98
+ throughput: {
99
+ average: result.requests.average,
100
+ max: result.requests.max,
101
+ min: result.requests.min,
102
+ },
103
+ });
104
+ });
105
+ instance.on('error', reject);
106
+ });
107
+ return {
108
+ promise,
109
+ stop: () => instance.stop(),
110
+ };
111
+ }
112
+ //# sourceMappingURL=loadtest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loadtest.js","sourceRoot":"","sources":["../../src/lib/loadtest.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,5 @@
1
+ /** RPC: List all CURRI policies for all orgs (for load testing). */
2
+ export declare const CURRI_POLICIES_RPC = "\n alias Cdrcisco.Identity\n alias Cdrcisco.Policies\n\n try do\n orgs = Identity.get_all_orgs()\n\n result = Enum.flat_map(orgs, fn org ->\n Policies.list_policies_by_org(org.id)\n |> Enum.map(fn p ->\n %{\n id: p.id,\n name: p.name,\n api_key: p.api_key,\n org_id: org.id,\n org_name: org.name\n }\n end)\n end)\n\n Jason.encode!(%{policies: result, count: length(result)})\n |> IO.puts()\n rescue\n e ->\n Jason.encode!(%{error: inspect(e), policies: [], count: 0})\n |> IO.puts()\n end\n";
1
3
  /** RPC: List all greeting policies for all orgs with rules. */
2
4
  export declare const GREETING_POLICIES_RPC = "\n alias Cdrcisco.Identity\n alias Cdrcisco.JtapiGreeting.GreetingPolicies\n\n try do\n orgs = Identity.get_all_orgs()\n\n result = Enum.flat_map(orgs, fn org ->\n policies = GreetingPolicies.list_greeting_policies(org.id,\n preload: [:default_audio_file, rules: [:audio_file]]\n )\n\n Enum.map(policies, fn p ->\n %{\n org_id: org.id,\n org_name: org.name,\n id: p.id,\n name: p.name,\n description: p.description,\n enabled: p.enabled,\n injection_target: p.injection_target,\n injection_mode: p.injection_mode,\n trigger_timing: p.trigger_timing,\n max_duration_seconds: p.max_duration_seconds,\n skip_key: p.skip_key,\n call_direction: p.call_direction,\n default_audio_file: case p.default_audio_file do\n nil -> nil\n f -> %{id: f.id, name: f.name}\n end,\n rules: Enum.map(p.rules || [], fn r ->\n %{\n id: r.id,\n name: r.name,\n priority: r.priority,\n enabled: r.enabled,\n calling_pattern: r.calling_pattern,\n called_pattern: r.called_pattern,\n call_direction: r.call_direction,\n injection_target: r.injection_target,\n injection_mode: r.injection_mode,\n audio_file: case r.audio_file do\n nil -> nil\n f -> %{id: f.id, name: f.name}\n end\n }\n end),\n rules_count: length(p.rules || []),\n inserted_at: p.inserted_at,\n updated_at: p.updated_at\n }\n end)\n end)\n\n Jason.encode!(%{policies: result, count: length(result), collected_at: DateTime.utc_now()})\n |> IO.puts()\n rescue\n e ->\n Jason.encode!(%{error: inspect(e), policies: [], count: 0})\n |> IO.puts()\n end\n";
3
5
  /** Generate RPC code for policy history with a time window in minutes. */
@@ -1 +1 @@
1
- {"version":3,"file":"rpc-scripts.d.ts","sourceRoot":"","sources":["../../src/lib/rpc-scripts.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,eAAO,MAAM,qBAAqB,s6DA6DjC,CAAC;AAEF,0EAA0E;AAC1E,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CA6CxD;AAED,eAAO,MAAM,oBAAoB,urDAqDhC,CAAC"}
1
+ {"version":3,"file":"rpc-scripts.d.ts","sourceRoot":"","sources":["../../src/lib/rpc-scripts.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,eAAO,MAAM,kBAAkB,2lBA2B9B,CAAC;AAEF,+DAA+D;AAC/D,eAAO,MAAM,qBAAqB,s6DA6DjC,CAAC;AAEF,0EAA0E;AAC1E,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CA6CxD;AAED,eAAO,MAAM,oBAAoB,urDAqDhC,CAAC"}
@@ -1,3 +1,32 @@
1
+ /** RPC: List all CURRI policies for all orgs (for load testing). */
2
+ export const CURRI_POLICIES_RPC = `
3
+ alias Cdrcisco.Identity
4
+ alias Cdrcisco.Policies
5
+
6
+ try do
7
+ orgs = Identity.get_all_orgs()
8
+
9
+ result = Enum.flat_map(orgs, fn org ->
10
+ Policies.list_policies_by_org(org.id)
11
+ |> Enum.map(fn p ->
12
+ %{
13
+ id: p.id,
14
+ name: p.name,
15
+ api_key: p.api_key,
16
+ org_id: org.id,
17
+ org_name: org.name
18
+ }
19
+ end)
20
+ end)
21
+
22
+ Jason.encode!(%{policies: result, count: length(result)})
23
+ |> IO.puts()
24
+ rescue
25
+ e ->
26
+ Jason.encode!(%{error: inspect(e), policies: [], count: 0})
27
+ |> IO.puts()
28
+ end
29
+ `;
1
30
  /** RPC: List all greeting policies for all orgs with rules. */
2
31
  export const GREETING_POLICIES_RPC = `
3
32
  alias Cdrcisco.Identity
@@ -1 +1 @@
1
- {"version":3,"file":"rpc-scripts.js","sourceRoot":"","sources":["../../src/lib/rpc-scripts.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,MAAM,CAAC,MAAM,qBAAqB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6DpC,CAAC;AAEF,0EAA0E;AAC1E,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,OAAO;;;;;;qDAM4C,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BA4BhC,OAAO;;;;;;mFAMgD,OAAO;;;GAGvF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqDnC,CAAC"}
1
+ {"version":3,"file":"rpc-scripts.js","sourceRoot":"","sources":["../../src/lib/rpc-scripts.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,MAAM,CAAC,MAAM,kBAAkB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BjC,CAAC;AAEF,+DAA+D;AAC/D,MAAM,CAAC,MAAM,qBAAqB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6DpC,CAAC;AAEF,0EAA0E;AAC1E,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,OAAO;;;;;;qDAM4C,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BA4BhC,OAAO;;;;;;mFAMgD,OAAO;;;GAGvF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqDnC,CAAC"}
@@ -0,0 +1,15 @@
1
+ interface SparklineProps {
2
+ /** Array of numeric values to visualize. */
3
+ data: number[];
4
+ /** Width in characters (pads or truncates data). Default 24. */
5
+ width?: number;
6
+ /** Label shown before the sparkline. */
7
+ label?: string;
8
+ /** Right-side detail text (e.g., "avg 198 req/s"). */
9
+ detail?: string;
10
+ /** Sparkline color. Default 'cyan'. */
11
+ color?: string;
12
+ }
13
+ export declare function Sparkline({ data, width, label, detail, color }: SparklineProps): import("react/jsx-runtime").JSX.Element;
14
+ export {};
15
+ //# sourceMappingURL=Sparkline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Sparkline.d.ts","sourceRoot":"","sources":["../../../src/ui/components/Sparkline.tsx"],"names":[],"mappings":"AAIA,UAAU,cAAc;IACtB,4CAA4C;IAC5C,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uCAAuC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,SAAS,CAAC,EAAE,IAAI,EAAE,KAAU,EAAE,KAAK,EAAE,MAAM,EAAE,KAAc,EAAE,EAAE,cAAc,2CAwB5F"}
@@ -0,0 +1,21 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from 'ink';
3
+ const BLOCKS = ['▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'];
4
+ export function Sparkline({ data, width = 24, label, detail, color = 'cyan' }) {
5
+ // Take last `width` data points, pad with zeros if shorter
6
+ const visible = data.length > width ? data.slice(-width) : data;
7
+ const padded = visible.length < width
8
+ ? [...Array(width - visible.length).fill(0), ...visible]
9
+ : visible;
10
+ const min = Math.min(...padded);
11
+ const max = Math.max(...padded);
12
+ const range = max - min;
13
+ const bars = padded.map((v) => {
14
+ if (range === 0)
15
+ return BLOCKS[3]; // uniform data → mid-height
16
+ const idx = Math.round(((v - min) / range) * (BLOCKS.length - 1));
17
+ return BLOCKS[Math.min(idx, BLOCKS.length - 1)];
18
+ }).join('');
19
+ return (_jsxs(Box, { children: [label && _jsx(Text, { bold: true, children: label.padEnd(11) }), _jsx(Text, { color: color, children: bars }), detail && _jsx(Text, { dimColor: true, children: ` ${detail}` })] }));
20
+ }
21
+ //# sourceMappingURL=Sparkline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Sparkline.js","sourceRoot":"","sources":["../../../src/ui/components/Sparkline.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAEhC,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAexD,MAAM,UAAU,SAAS,CAAC,EAAE,IAAI,EAAE,KAAK,GAAG,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,GAAG,MAAM,EAAkB;IAC3F,2DAA2D;IAC3D,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAChE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,KAAK;QACnC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAS,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC;QAChE,CAAC,CAAC,OAAO,CAAC;IAEZ,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;IAChC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;IAChC,MAAM,KAAK,GAAG,GAAG,GAAG,GAAG,CAAC;IAExB,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QAC5B,IAAI,KAAK,KAAK,CAAC;YAAE,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,4BAA4B;QAC/D,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QAClE,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEZ,OAAO,CACL,MAAC,GAAG,eACD,KAAK,IAAI,KAAC,IAAI,IAAC,IAAI,kBAAE,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,GAAQ,EAC9C,KAAC,IAAI,IAAC,KAAK,EAAE,KAAK,YAAG,IAAI,GAAQ,EAChC,MAAM,IAAI,KAAC,IAAI,IAAC,QAAQ,kBAAE,KAAK,MAAM,EAAE,GAAQ,IAC5C,CACP,CAAC;AACJ,CAAC"}
@@ -19,4 +19,5 @@ export { LogLevelBadge } from './LogLevelBadge.js';
19
19
  export { ErrorBoundary } from './ErrorBoundary.js';
20
20
  export { TabBar } from './TabBar.js';
21
21
  export type { Tab } from './TabBar.js';
22
+ export { Sparkline } from './Sparkline.js';
22
23
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,YAAY,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,YAAY,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC"}
@@ -17,4 +17,5 @@ export { MetricsFooter } from './MetricsFooter.js';
17
17
  export { LogLevelBadge } from './LogLevelBadge.js';
18
18
  export { ErrorBoundary } from './ErrorBoundary.js';
19
19
  export { TabBar } from './TabBar.js';
20
+ export { Sparkline } from './Sparkline.js';
20
21
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/ui/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/ui/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"MetricsContext.d.ts","sourceRoot":"","sources":["../../../src/ui/context/MetricsContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoC,MAAM,OAAO,CAAC;AAGzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAQzD,wBAAgB,eAAe,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,2CAO1E;AAED,wBAAgB,UAAU,IAAI,aAAa,GAAG,SAAS,CAEtD"}
1
+ {"version":3,"file":"MetricsContext.d.ts","sourceRoot":"","sources":["../../../src/ui/context/MetricsContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA6C,MAAM,OAAO,CAAC;AAGlE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAQzD,wBAAgB,eAAe,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,2CAS1E;AAED,wBAAgB,UAAU,IAAI,aAAa,GAAG,SAAS,CAEtD"}
@@ -1,11 +1,13 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { createContext, useContext } from 'react';
2
+ import { createContext, useContext, useMemo } from 'react';
3
3
  import { usePolling } from '../hooks/usePolling.js';
4
4
  import { getSystemMetrics } from '../../lib/system.js';
5
5
  const MetricsContext = createContext({ metrics: undefined });
6
6
  export function MetricsProvider({ children }) {
7
7
  const { data: metrics } = usePolling(getSystemMetrics, 10_000, true);
8
- return (_jsx(MetricsContext.Provider, { value: { metrics }, children: children }));
8
+ // Memoize the context value to prevent unnecessary consumer re-renders
9
+ const value = useMemo(() => ({ metrics }), [metrics]);
10
+ return (_jsx(MetricsContext.Provider, { value: value, children: children }));
9
11
  }
10
12
  export function useMetrics() {
11
13
  return useContext(MetricsContext).metrics;
@@ -1 +1 @@
1
- {"version":3,"file":"MetricsContext.js","sourceRoot":"","sources":["../../../src/ui/context/MetricsContext.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAOvD,MAAM,cAAc,GAAG,aAAa,CAAsB,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC;AAElF,MAAM,UAAU,eAAe,CAAC,EAAE,QAAQ,EAAiC;IACzE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,UAAU,CAAgB,gBAAgB,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IACpF,OAAO,CACL,KAAC,cAAc,CAAC,QAAQ,IAAC,KAAK,EAAE,EAAE,OAAO,EAAE,YACxC,QAAQ,GACe,CAC3B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO,UAAU,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC;AAC5C,CAAC"}
1
+ {"version":3,"file":"MetricsContext.js","sourceRoot":"","sources":["../../../src/ui/context/MetricsContext.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,aAAa,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAOvD,MAAM,cAAc,GAAG,aAAa,CAAsB,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC;AAElF,MAAM,UAAU,eAAe,CAAC,EAAE,QAAQ,EAAiC;IACzE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,UAAU,CAAgB,gBAAgB,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IACpF,uEAAuE;IACvE,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IACtD,OAAO,CACL,KAAC,cAAc,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YAClC,QAAQ,GACe,CAC3B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO,UAAU,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC;AAC5C,CAAC"}
@@ -7,4 +7,6 @@ export { usePolling } from "./usePolling.js";
7
7
  export { useComposeLogs } from "./useComposeLogs.js";
8
8
  export { useFinish } from "./useFinish.js";
9
9
  export { useLogLevel } from "./useLogLevel.js";
10
+ export { useLoadTest } from "./useLoadTest.js";
11
+ export type { LoadTestPhase } from "./useLoadTest.js";
10
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC"}
@@ -5,4 +5,5 @@ export { usePolling } from "./usePolling.js";
5
5
  export { useComposeLogs } from "./useComposeLogs.js";
6
6
  export { useFinish } from "./useFinish.js";
7
7
  export { useLogLevel } from "./useLogLevel.js";
8
+ export { useLoadTest } from "./useLoadTest.js";
8
9
  //# sourceMappingURL=index.js.map