@principal-ai/principal-studio-cli 0.35.3

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 (184) hide show
  1. package/README.md +172 -0
  2. package/dist/commands/agent-session.d.ts +3 -0
  3. package/dist/commands/agent-session.d.ts.map +1 -0
  4. package/dist/commands/agent-session.js +67 -0
  5. package/dist/commands/agent-sessions.d.ts +11 -0
  6. package/dist/commands/agent-sessions.d.ts.map +1 -0
  7. package/dist/commands/agent-sessions.js +39 -0
  8. package/dist/commands/auxiliary/index.d.ts +3 -0
  9. package/dist/commands/auxiliary/index.d.ts.map +1 -0
  10. package/dist/commands/auxiliary/index.js +9 -0
  11. package/dist/commands/auxiliary/validate.d.ts +3 -0
  12. package/dist/commands/auxiliary/validate.d.ts.map +1 -0
  13. package/dist/commands/auxiliary/validate.js +123 -0
  14. package/dist/commands/collector/check.d.ts +6 -0
  15. package/dist/commands/collector/check.d.ts.map +1 -0
  16. package/dist/commands/collector/check.js +153 -0
  17. package/dist/commands/collector/diagnose.d.ts +6 -0
  18. package/dist/commands/collector/diagnose.d.ts.map +1 -0
  19. package/dist/commands/collector/diagnose.js +229 -0
  20. package/dist/commands/collector/index.d.ts +6 -0
  21. package/dist/commands/collector/index.d.ts.map +1 -0
  22. package/dist/commands/collector/index.js +16 -0
  23. package/dist/commands/collector/status.d.ts +6 -0
  24. package/dist/commands/collector/status.d.ts.map +1 -0
  25. package/dist/commands/collector/status.js +77 -0
  26. package/dist/commands/collector/utils.d.ts +92 -0
  27. package/dist/commands/collector/utils.d.ts.map +1 -0
  28. package/dist/commands/collector/utils.js +154 -0
  29. package/dist/commands/coverage.d.ts +9 -0
  30. package/dist/commands/coverage.d.ts.map +1 -0
  31. package/dist/commands/coverage.js +252 -0
  32. package/dist/commands/create.d.ts +6 -0
  33. package/dist/commands/create.d.ts.map +1 -0
  34. package/dist/commands/create.js +50 -0
  35. package/dist/commands/events/index.d.ts +3 -0
  36. package/dist/commands/events/index.d.ts.map +1 -0
  37. package/dist/commands/events/index.js +9 -0
  38. package/dist/commands/events/validate.d.ts +3 -0
  39. package/dist/commands/events/validate.d.ts.map +1 -0
  40. package/dist/commands/events/validate.js +124 -0
  41. package/dist/commands/formats.d.ts +6 -0
  42. package/dist/commands/formats.d.ts.map +1 -0
  43. package/dist/commands/formats.js +1118 -0
  44. package/dist/commands/hooks.d.ts +9 -0
  45. package/dist/commands/hooks.d.ts.map +1 -0
  46. package/dist/commands/hooks.js +295 -0
  47. package/dist/commands/inbox.d.ts +13 -0
  48. package/dist/commands/inbox.d.ts.map +1 -0
  49. package/dist/commands/inbox.js +179 -0
  50. package/dist/commands/init.d.ts +6 -0
  51. package/dist/commands/init.d.ts.map +1 -0
  52. package/dist/commands/init.js +220 -0
  53. package/dist/commands/lint.d.ts +11 -0
  54. package/dist/commands/lint.d.ts.map +1 -0
  55. package/dist/commands/lint.js +71 -0
  56. package/dist/commands/list.d.ts +6 -0
  57. package/dist/commands/list.d.ts.map +1 -0
  58. package/dist/commands/list.js +78 -0
  59. package/dist/commands/migrate-nodes.d.ts +9 -0
  60. package/dist/commands/migrate-nodes.d.ts.map +1 -0
  61. package/dist/commands/migrate-nodes.js +363 -0
  62. package/dist/commands/migrate-scopes-to-canvas.d.ts +3 -0
  63. package/dist/commands/migrate-scopes-to-canvas.d.ts.map +1 -0
  64. package/dist/commands/migrate-scopes-to-canvas.js +143 -0
  65. package/dist/commands/migration.d.ts +6 -0
  66. package/dist/commands/migration.d.ts.map +1 -0
  67. package/dist/commands/migration.js +247 -0
  68. package/dist/commands/open-studio.d.ts +10 -0
  69. package/dist/commands/open-studio.d.ts.map +1 -0
  70. package/dist/commands/open-studio.js +32 -0
  71. package/dist/commands/opencode/fetch.d.ts +3 -0
  72. package/dist/commands/opencode/fetch.d.ts.map +1 -0
  73. package/dist/commands/opencode/fetch.js +25 -0
  74. package/dist/commands/opencode/index.d.ts +3 -0
  75. package/dist/commands/opencode/index.d.ts.map +1 -0
  76. package/dist/commands/opencode/index.js +11 -0
  77. package/dist/commands/opencode/list-sessions.d.ts +3 -0
  78. package/dist/commands/opencode/list-sessions.d.ts.map +1 -0
  79. package/dist/commands/opencode/list-sessions.js +20 -0
  80. package/dist/commands/repo.d.ts +18 -0
  81. package/dist/commands/repo.d.ts.map +1 -0
  82. package/dist/commands/repo.js +233 -0
  83. package/dist/commands/schema.d.ts +6 -0
  84. package/dist/commands/schema.d.ts.map +1 -0
  85. package/dist/commands/schema.js +367 -0
  86. package/dist/commands/scopes/index.d.ts +3 -0
  87. package/dist/commands/scopes/index.d.ts.map +1 -0
  88. package/dist/commands/scopes/index.js +9 -0
  89. package/dist/commands/scopes/validate.d.ts +3 -0
  90. package/dist/commands/scopes/validate.d.ts.map +1 -0
  91. package/dist/commands/scopes/validate.js +187 -0
  92. package/dist/commands/setup.d.ts +6 -0
  93. package/dist/commands/setup.d.ts.map +1 -0
  94. package/dist/commands/setup.js +406 -0
  95. package/dist/commands/starred-collections.d.ts +12 -0
  96. package/dist/commands/starred-collections.d.ts.map +1 -0
  97. package/dist/commands/starred-collections.js +310 -0
  98. package/dist/commands/subsystem-model.d.ts +11 -0
  99. package/dist/commands/subsystem-model.d.ts.map +1 -0
  100. package/dist/commands/subsystem-model.js +249 -0
  101. package/dist/commands/topic.d.ts +15 -0
  102. package/dist/commands/topic.d.ts.map +1 -0
  103. package/dist/commands/topic.js +683 -0
  104. package/dist/commands/tour.d.ts +23 -0
  105. package/dist/commands/tour.d.ts.map +1 -0
  106. package/dist/commands/tour.js +783 -0
  107. package/dist/commands/trace/flow.d.ts +6 -0
  108. package/dist/commands/trace/flow.d.ts.map +1 -0
  109. package/dist/commands/trace/flow.js +158 -0
  110. package/dist/commands/trace/index.d.ts +6 -0
  111. package/dist/commands/trace/index.d.ts.map +1 -0
  112. package/dist/commands/trace/index.js +20 -0
  113. package/dist/commands/trace/inspect.d.ts +6 -0
  114. package/dist/commands/trace/inspect.d.ts.map +1 -0
  115. package/dist/commands/trace/inspect.js +187 -0
  116. package/dist/commands/trace/list.d.ts +6 -0
  117. package/dist/commands/trace/list.d.ts.map +1 -0
  118. package/dist/commands/trace/list.js +145 -0
  119. package/dist/commands/trace/registrations.d.ts +6 -0
  120. package/dist/commands/trace/registrations.d.ts.map +1 -0
  121. package/dist/commands/trace/registrations.js +81 -0
  122. package/dist/commands/trace/validate.d.ts +6 -0
  123. package/dist/commands/trace/validate.d.ts.map +1 -0
  124. package/dist/commands/trace/validate.js +276 -0
  125. package/dist/commands/trail.d.ts +36 -0
  126. package/dist/commands/trail.d.ts.map +1 -0
  127. package/dist/commands/trail.js +622 -0
  128. package/dist/commands/validate.d.ts +12 -0
  129. package/dist/commands/validate.d.ts.map +1 -0
  130. package/dist/commands/validate.js +3334 -0
  131. package/dist/commands/workflow/implementation.d.ts +3 -0
  132. package/dist/commands/workflow/implementation.d.ts.map +1 -0
  133. package/dist/commands/workflow/implementation.js +51 -0
  134. package/dist/commands/workflow/index.d.ts +3 -0
  135. package/dist/commands/workflow/index.d.ts.map +1 -0
  136. package/dist/commands/workflow/index.js +19 -0
  137. package/dist/commands/workflow/inspect.d.ts +3 -0
  138. package/dist/commands/workflow/inspect.d.ts.map +1 -0
  139. package/dist/commands/workflow/inspect.js +123 -0
  140. package/dist/commands/workflow/list.d.ts +3 -0
  141. package/dist/commands/workflow/list.d.ts.map +1 -0
  142. package/dist/commands/workflow/list.js +95 -0
  143. package/dist/commands/workflow/render.d.ts +3 -0
  144. package/dist/commands/workflow/render.d.ts.map +1 -0
  145. package/dist/commands/workflow/render.js +88 -0
  146. package/dist/commands/workflow/test.d.ts +3 -0
  147. package/dist/commands/workflow/test.d.ts.map +1 -0
  148. package/dist/commands/workflow/test.js +141 -0
  149. package/dist/commands/workflow/utils.d.ts +49 -0
  150. package/dist/commands/workflow/utils.d.ts.map +1 -0
  151. package/dist/commands/workflow/utils.js +164 -0
  152. package/dist/commands/workflow/validate.d.ts +3 -0
  153. package/dist/commands/workflow/validate.d.ts.map +1 -0
  154. package/dist/commands/workflow/validate.js +344 -0
  155. package/dist/file-utils.d.ts +15 -0
  156. package/dist/file-utils.d.ts.map +1 -0
  157. package/dist/file-utils.js +29 -0
  158. package/dist/index.cjs +285718 -0
  159. package/dist/index.cjs.map +7 -0
  160. package/dist/index.d.ts +8 -0
  161. package/dist/index.d.ts.map +1 -0
  162. package/dist/index.js +81 -0
  163. package/dist/lib/bridge-ipc.d.ts +29 -0
  164. package/dist/lib/bridge-ipc.d.ts.map +1 -0
  165. package/dist/lib/bridge-ipc.js +128 -0
  166. package/dist/lib/github-user.d.ts +17 -0
  167. package/dist/lib/github-user.d.ts.map +1 -0
  168. package/dist/lib/github-user.js +53 -0
  169. package/dist/lib/open-url.d.ts +11 -0
  170. package/dist/lib/open-url.d.ts.map +1 -0
  171. package/dist/lib/open-url.js +45 -0
  172. package/dist/lib/subsystem-model-store.d.ts +74 -0
  173. package/dist/lib/subsystem-model-store.d.ts.map +1 -0
  174. package/dist/lib/subsystem-model-store.js +292 -0
  175. package/dist/lib/tour-cache.d.ts +26 -0
  176. package/dist/lib/tour-cache.d.ts.map +1 -0
  177. package/dist/lib/tour-cache.js +46 -0
  178. package/dist/lib/trail-cache.d.ts +40 -0
  179. package/dist/lib/trail-cache.d.ts.map +1 -0
  180. package/dist/lib/trail-cache.js +97 -0
  181. package/dist/lib/viewer-ipc.d.ts +44 -0
  182. package/dist/lib/viewer-ipc.d.ts.map +1 -0
  183. package/dist/lib/viewer-ipc.js +68 -0
  184. package/package.json +68 -0
@@ -0,0 +1,6 @@
1
+ /**
2
+ * trace flow - Check end-to-end trace flow through the pipeline
3
+ */
4
+ import { Command } from 'commander';
5
+ export declare function createFlowCommand(): Command;
6
+ //# sourceMappingURL=flow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flow.d.ts","sourceRoot":"","sources":["../../../src/commands/trace/flow.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgCpC,wBAAgB,iBAAiB,IAAI,OAAO,CA4B3C"}
@@ -0,0 +1,158 @@
1
+ /**
2
+ * trace flow - Check end-to-end trace flow through the pipeline
3
+ */
4
+ import { Command } from 'commander';
5
+ import chalk from 'chalk';
6
+ import { checkHealth, getServiceStats, DEFAULT_COLLECTOR_PORT, } from '../collector/utils.js';
7
+ const DEFAULT_APP_PORT = 3043;
8
+ export function createFlowCommand() {
9
+ const command = new Command('flow');
10
+ command
11
+ .description('Check end-to-end trace flow through the pipeline')
12
+ .option('-p, --port <port>', 'Electron-app port (default: 3043, dev: 3045)')
13
+ .option('--json', 'Output as JSON')
14
+ .action(async (options) => {
15
+ try {
16
+ const appPort = options.port ? parseInt(options.port, 10) : DEFAULT_APP_PORT;
17
+ const diagnostic = await runFlowDiagnostic(appPort);
18
+ if (options.json) {
19
+ console.log(JSON.stringify(diagnostic, null, 2));
20
+ }
21
+ else {
22
+ printFlowDiagnostic(diagnostic);
23
+ }
24
+ if (!diagnostic.healthy) {
25
+ process.exit(1);
26
+ }
27
+ }
28
+ catch (error) {
29
+ console.error(chalk.red('Error:'), error.message);
30
+ process.exit(1);
31
+ }
32
+ });
33
+ return command;
34
+ }
35
+ async function runFlowDiagnostic(appPort) {
36
+ const issues = [];
37
+ // Check collector
38
+ const collectorHealth = await checkHealth(DEFAULT_COLLECTOR_PORT);
39
+ const collectorHealthy = collectorHealth !== null;
40
+ const collectorStats = collectorHealthy
41
+ ? await getServiceStats(DEFAULT_COLLECTOR_PORT)
42
+ : null;
43
+ const collector = {
44
+ healthy: collectorHealthy,
45
+ traceCount: collectorStats?.summary?.totalTraces ?? 0,
46
+ serviceCount: collectorStats?.summary?.totalServices ?? 0,
47
+ aliveServices: collectorStats?.summary?.aliveServices ?? 0,
48
+ endpoint: `http://localhost:${DEFAULT_COLLECTOR_PORT}`,
49
+ };
50
+ if (!collectorHealthy) {
51
+ issues.push('Collector is not reachable');
52
+ }
53
+ // Check electron-app
54
+ let appHealthy = false;
55
+ let appTraceCount = 0;
56
+ try {
57
+ const response = await fetch(`http://localhost:${appPort}/health`, {
58
+ signal: AbortSignal.timeout(2000),
59
+ });
60
+ appHealthy = response.ok;
61
+ // Try to get trace count from the app
62
+ if (appHealthy) {
63
+ try {
64
+ const tracesResponse = await fetch(`http://localhost:${appPort}/otel/traces?limit=1`, {
65
+ signal: AbortSignal.timeout(2000),
66
+ });
67
+ if (tracesResponse.ok) {
68
+ const data = (await tracesResponse.json());
69
+ appTraceCount = data.count ?? 0;
70
+ }
71
+ }
72
+ catch {
73
+ // Endpoint may not be available
74
+ }
75
+ }
76
+ }
77
+ catch {
78
+ appHealthy = false;
79
+ }
80
+ const app = {
81
+ healthy: appHealthy,
82
+ traceCount: appTraceCount,
83
+ endpoint: `http://localhost:${appPort}`,
84
+ };
85
+ if (!appHealthy) {
86
+ issues.push('Electron-app is not reachable');
87
+ }
88
+ // Determine overall health
89
+ const healthy = collectorHealthy && appHealthy;
90
+ if (collectorHealthy && collector.traceCount > 0 && !appHealthy) {
91
+ issues.push('Traces reaching collector but electron-app is unreachable');
92
+ }
93
+ return {
94
+ collector,
95
+ app,
96
+ healthy,
97
+ issues,
98
+ };
99
+ }
100
+ function printFlowDiagnostic(diagnostic) {
101
+ console.log(chalk.bold('\nTrace Flow Diagnostic'));
102
+ console.log('━'.repeat(60));
103
+ // Step 1: Collector
104
+ console.log(chalk.bold('\n 1. Collector'));
105
+ if (diagnostic.collector.healthy) {
106
+ console.log(` Status: ${chalk.green('✓')} healthy`);
107
+ console.log(` Traces: ${diagnostic.collector.traceCount} received`);
108
+ console.log(` Services: ${diagnostic.collector.serviceCount} total, ${diagnostic.collector.aliveServices} active`);
109
+ }
110
+ else {
111
+ console.log(` Status: ${chalk.red('✗')} unreachable`);
112
+ }
113
+ // Step 2: Electron-app
114
+ console.log(chalk.bold('\n 2. Electron-app'));
115
+ if (diagnostic.app.healthy) {
116
+ console.log(` Status: ${chalk.green('✓')} healthy`);
117
+ if (diagnostic.app.traceCount > 0) {
118
+ console.log(` Traces: ${diagnostic.app.traceCount} stored`);
119
+ }
120
+ else {
121
+ console.log(chalk.gray(' Traces: 0 stored (buffer may be empty)'));
122
+ }
123
+ }
124
+ else {
125
+ console.log(` Status: ${chalk.red('✗')} unreachable`);
126
+ }
127
+ // Step 3: Flow summary
128
+ console.log(chalk.bold('\n 3. Pipeline'));
129
+ if (diagnostic.healthy) {
130
+ console.log(` Status: ${chalk.green('✓')} both endpoints reachable`);
131
+ }
132
+ else {
133
+ console.log(` Status: ${chalk.red('✗')} issues detected`);
134
+ }
135
+ // Issues
136
+ if (diagnostic.issues.length > 0) {
137
+ console.log(chalk.bold('\n Issues:'));
138
+ for (const issue of diagnostic.issues) {
139
+ console.log(chalk.yellow(` • ${issue}`));
140
+ }
141
+ console.log(chalk.bold('\n Troubleshooting:'));
142
+ if (diagnostic.issues.some((i) => i.toLowerCase().includes('collector'))) {
143
+ console.log(chalk.gray(' • Run: principal-ai collector status'));
144
+ console.log(chalk.gray(' • Run: principal-ai collector diagnose'));
145
+ }
146
+ if (diagnostic.issues.some((i) => i.toLowerCase().includes('electron'))) {
147
+ console.log(chalk.gray(' • Check if the Principal desktop app is running'));
148
+ }
149
+ }
150
+ console.log('\n' + '━'.repeat(60));
151
+ if (diagnostic.healthy) {
152
+ console.log(chalk.green('✓ Pipeline is healthy.'));
153
+ }
154
+ else {
155
+ console.log(chalk.red(`${diagnostic.issues.length} issue(s) detected.`));
156
+ }
157
+ console.log();
158
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Trace commands - List, inspect, and validate traces
3
+ */
4
+ import { Command } from 'commander';
5
+ export declare function createTraceCommand(): Command;
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/trace/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,wBAAgB,kBAAkB,IAAI,OAAO,CAY5C"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Trace commands - List, inspect, and validate traces
3
+ */
4
+ import { Command } from 'commander';
5
+ import { createListCommand } from './list.js';
6
+ import { createFlowCommand } from './flow.js';
7
+ import { createValidateCommand } from './validate.js';
8
+ import { createInspectCommand } from './inspect.js';
9
+ import { createRegistrationsCommand } from './registrations.js';
10
+ export function createTraceCommand() {
11
+ const command = new Command('trace');
12
+ command
13
+ .description('List, inspect, and validate traces from collector and electron-app')
14
+ .addCommand(createListCommand())
15
+ .addCommand(createFlowCommand())
16
+ .addCommand(createValidateCommand())
17
+ .addCommand(createInspectCommand())
18
+ .addCommand(createRegistrationsCommand());
19
+ return command;
20
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * trace inspect - Show detailed trace information
3
+ */
4
+ import { Command } from 'commander';
5
+ export declare function createInspectCommand(): Command;
6
+ //# sourceMappingURL=inspect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inspect.d.ts","sourceRoot":"","sources":["../../../src/commands/trace/inspect.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAyDpC,wBAAgB,oBAAoB,IAAI,OAAO,CA6B9C"}
@@ -0,0 +1,187 @@
1
+ /**
2
+ * trace inspect - Show detailed trace information
3
+ */
4
+ import { Command } from 'commander';
5
+ import chalk from 'chalk';
6
+ const DEFAULT_APP_PORT = 3043;
7
+ const SPAN_KINDS = {
8
+ 0: 'UNSPECIFIED',
9
+ 1: 'INTERNAL',
10
+ 2: 'SERVER',
11
+ 3: 'CLIENT',
12
+ 4: 'PRODUCER',
13
+ 5: 'CONSUMER',
14
+ };
15
+ const STATUS_CODES = {
16
+ 0: 'UNSET',
17
+ 1: 'OK',
18
+ 2: 'ERROR',
19
+ };
20
+ export function createInspectCommand() {
21
+ const command = new Command('inspect');
22
+ command
23
+ .description('Show detailed information about a specific trace')
24
+ .argument('<traceId>', 'Trace ID to inspect')
25
+ .option('-p, --port <port>', 'Electron-app port (default: 3043, dev: 3045)')
26
+ .option('--json', 'Output as JSON')
27
+ .option('-e, --events', 'Show all events')
28
+ .option('-a, --attributes', 'Show all attributes')
29
+ .action(async (traceId, options) => {
30
+ try {
31
+ const appPort = options.port ? parseInt(options.port, 10) : DEFAULT_APP_PORT;
32
+ // Fetch the specific trace
33
+ const trace = await fetchTrace(appPort, traceId);
34
+ if (options.json) {
35
+ console.log(JSON.stringify(trace, null, 2));
36
+ }
37
+ else {
38
+ outputText(trace, options);
39
+ }
40
+ }
41
+ catch (error) {
42
+ console.error(chalk.red('Error:'), error.message);
43
+ process.exit(1);
44
+ }
45
+ });
46
+ return command;
47
+ }
48
+ async function fetchTrace(port, traceId) {
49
+ const url = `http://localhost:${port}/otel/traces/${traceId}`;
50
+ try {
51
+ const response = await fetch(url, { signal: AbortSignal.timeout(5000) });
52
+ if (!response.ok) {
53
+ throw new Error(`Failed to fetch trace: ${response.statusText}`);
54
+ }
55
+ const data = (await response.json());
56
+ if (!data.success || !data.trace) {
57
+ throw new Error(data.error || 'Trace not found');
58
+ }
59
+ return data.trace;
60
+ }
61
+ catch (error) {
62
+ if (error.name === 'AbortError') {
63
+ throw new Error('Request timeout - electron-app not responding');
64
+ }
65
+ throw error;
66
+ }
67
+ }
68
+ function outputText(trace, options) {
69
+ console.log(chalk.bold('\nTrace Inspection'));
70
+ console.log('━'.repeat(60));
71
+ console.log(chalk.gray('Trace ID:'), chalk.cyan(trace.traceId));
72
+ const resourceSpans = trace.data.resourceSpans ?? [];
73
+ for (const rs of resourceSpans) {
74
+ // Resource info
75
+ const resourceAttrs = rs.resource?.attributes ?? [];
76
+ const serviceName = getAttrValue(resourceAttrs, 'service.name') ?? 'unknown';
77
+ const serviceVersion = getAttrValue(resourceAttrs, 'service.version');
78
+ console.log();
79
+ console.log(chalk.bold('Resource:'), chalk.yellow(serviceName));
80
+ if (serviceVersion) {
81
+ console.log(chalk.gray(' Version:'), serviceVersion);
82
+ }
83
+ if (options.attributes) {
84
+ console.log(chalk.gray(' Attributes:'));
85
+ for (const attr of resourceAttrs) {
86
+ console.log(chalk.gray(` ${attr.key}:`), formatAttrValue(attr.value));
87
+ }
88
+ }
89
+ // Scope spans
90
+ const scopeSpans = rs.scopeSpans ?? [];
91
+ for (const ss of scopeSpans) {
92
+ const scopeName = ss.scope?.name ?? 'unknown';
93
+ const scopeVersion = ss.scope?.version;
94
+ console.log();
95
+ console.log(chalk.bold(' Scope:'), chalk.magenta(scopeName));
96
+ if (scopeVersion) {
97
+ console.log(chalk.gray(' Version:'), scopeVersion);
98
+ }
99
+ // Spans
100
+ const spans = ss.spans ?? [];
101
+ for (const span of spans) {
102
+ const duration = calculateDuration(span.startTimeUnixNano, span.endTimeUnixNano);
103
+ const kind = SPAN_KINDS[span.kind] ?? 'UNKNOWN';
104
+ const status = STATUS_CODES[span.status?.code ?? 0] ?? 'UNKNOWN';
105
+ const statusColor = span.status?.code === 2 ? chalk.red : span.status?.code === 1 ? chalk.green : chalk.gray;
106
+ console.log();
107
+ console.log(chalk.bold(' Span:'), chalk.blue(span.name));
108
+ console.log(chalk.gray(' Span ID:'), span.spanId);
109
+ if (span.parentSpanId) {
110
+ console.log(chalk.gray(' Parent:'), span.parentSpanId);
111
+ }
112
+ console.log(chalk.gray(' Kind:'), kind);
113
+ console.log(chalk.gray(' Status:'), statusColor(status));
114
+ console.log(chalk.gray(' Duration:'), formatDuration(duration));
115
+ console.log(chalk.gray(' Start:'), formatTimestamp(span.startTimeUnixNano));
116
+ // Span attributes
117
+ const spanAttrs = span.attributes ?? [];
118
+ if (spanAttrs.length > 0 && options.attributes) {
119
+ console.log(chalk.gray(' Attributes:'));
120
+ for (const attr of spanAttrs) {
121
+ console.log(chalk.gray(` ${attr.key}:`), formatAttrValue(attr.value));
122
+ }
123
+ }
124
+ // Events
125
+ const events = span.events ?? [];
126
+ if (events.length > 0) {
127
+ console.log(chalk.gray(` Events (${events.length}):`));
128
+ const displayEvents = options.events ? events : events.slice(0, 5);
129
+ for (const event of displayEvents) {
130
+ const eventTime = formatTimestamp(event.timeUnixNano);
131
+ console.log(chalk.green(` • ${event.name}`) + chalk.gray(` @ ${eventTime}`));
132
+ if (options.attributes && event.attributes) {
133
+ for (const attr of event.attributes) {
134
+ console.log(chalk.gray(` ${attr.key}:`), formatAttrValue(attr.value));
135
+ }
136
+ }
137
+ }
138
+ if (!options.events && events.length > 5) {
139
+ console.log(chalk.gray(` ... and ${events.length - 5} more (use --events to see all)`));
140
+ }
141
+ }
142
+ }
143
+ }
144
+ }
145
+ console.log('\n' + '━'.repeat(60));
146
+ console.log();
147
+ }
148
+ function getAttrValue(attrs, key) {
149
+ const attr = attrs.find((a) => a.key === key);
150
+ if (!attr)
151
+ return undefined;
152
+ const value = attr.value;
153
+ return value.stringValue ?? value.intValue?.toString() ?? value.boolValue?.toString();
154
+ }
155
+ function formatAttrValue(value) {
156
+ if (typeof value === 'object' && value !== null) {
157
+ const v = value;
158
+ if (v.stringValue !== undefined)
159
+ return `"${v.stringValue}"`;
160
+ if (v.intValue !== undefined)
161
+ return String(v.intValue);
162
+ if (v.boolValue !== undefined)
163
+ return String(v.boolValue);
164
+ if (v.arrayValue)
165
+ return JSON.stringify(v.arrayValue.values);
166
+ return JSON.stringify(value);
167
+ }
168
+ return String(value);
169
+ }
170
+ function calculateDuration(startNano, endNano) {
171
+ const start = BigInt(startNano);
172
+ const end = BigInt(endNano);
173
+ return Number((end - start) / BigInt(1_000_000)); // Convert to ms
174
+ }
175
+ function formatDuration(ms) {
176
+ if (ms < 1) {
177
+ return `${(ms * 1000).toFixed(0)}µs`;
178
+ }
179
+ if (ms < 1000) {
180
+ return `${ms.toFixed(2)}ms`;
181
+ }
182
+ return `${(ms / 1000).toFixed(2)}s`;
183
+ }
184
+ function formatTimestamp(nanoStr) {
185
+ const ms = Number(BigInt(nanoStr) / BigInt(1_000_000));
186
+ return new Date(ms).toISOString();
187
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * trace list - List recent traces from electron-app
3
+ */
4
+ import { Command } from 'commander';
5
+ export declare function createListCommand(): Command;
6
+ //# sourceMappingURL=list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/commands/trace/list.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAqCpC,wBAAgB,iBAAiB,IAAI,OAAO,CAqI3C"}
@@ -0,0 +1,145 @@
1
+ /**
2
+ * trace list - List recent traces from electron-app
3
+ */
4
+ import { Command } from 'commander';
5
+ import chalk from 'chalk';
6
+ import { checkHealth, getServiceStats, DEFAULT_COLLECTOR_PORT } from '../collector/utils.js';
7
+ const DEFAULT_APP_PORT = 3043;
8
+ export function createListCommand() {
9
+ const command = new Command('list');
10
+ command
11
+ .description('List recent traces from electron-app')
12
+ .option('-n, --limit <count>', 'Number of traces to show (default: 10)')
13
+ .option('-p, --port <port>', 'Electron-app port (default: 3043, dev: 3045)')
14
+ .option('--json', 'Output as JSON')
15
+ .action(async (options) => {
16
+ try {
17
+ const limit = options.limit ? parseInt(options.limit, 10) : 10;
18
+ const appPort = options.port ? parseInt(options.port, 10) : DEFAULT_APP_PORT;
19
+ // Check if electron-app is reachable
20
+ let appHealthy = false;
21
+ try {
22
+ const response = await fetch(`http://localhost:${appPort}/health`, {
23
+ signal: AbortSignal.timeout(2000),
24
+ });
25
+ appHealthy = response.ok;
26
+ }
27
+ catch {
28
+ appHealthy = false;
29
+ }
30
+ // Get collector stats for context
31
+ const collectorHealth = await checkHealth(DEFAULT_COLLECTOR_PORT);
32
+ const collectorHealthy = collectorHealth !== null;
33
+ const collectorStats = collectorHealthy ? await getServiceStats(DEFAULT_COLLECTOR_PORT) : null;
34
+ // Try to fetch traces from electron-app
35
+ let tracesResponse = null;
36
+ if (appHealthy) {
37
+ try {
38
+ const response = await fetch(`http://localhost:${appPort}/otel/traces?limit=${limit}`, { signal: AbortSignal.timeout(5000) });
39
+ if (response.ok) {
40
+ tracesResponse = (await response.json());
41
+ }
42
+ }
43
+ catch {
44
+ // Endpoint may not be implemented yet
45
+ }
46
+ }
47
+ if (options.json) {
48
+ console.log(JSON.stringify({
49
+ success: tracesResponse?.success ?? false,
50
+ traces: tracesResponse?.traces ?? [],
51
+ count: tracesResponse?.count ?? 0,
52
+ collector: {
53
+ healthy: collectorHealthy,
54
+ totalTraces: collectorStats?.summary?.totalTraces ?? 0,
55
+ services: Object.keys(collectorStats?.services ?? {}),
56
+ },
57
+ app: {
58
+ healthy: appHealthy,
59
+ endpoint: `http://localhost:${appPort}/otel/traces`,
60
+ },
61
+ }, null, 2));
62
+ return;
63
+ }
64
+ console.log(chalk.bold('\nTrace List'));
65
+ console.log('━'.repeat(60));
66
+ // Show current pipeline status
67
+ console.log(chalk.bold('\n Pipeline Status:'));
68
+ if (collectorHealthy && collectorStats) {
69
+ const serviceCount = Object.keys(collectorStats.services).length;
70
+ console.log(` Collector: ${chalk.green('✓')} receiving traces (${collectorStats.summary.totalTraces} total, ${serviceCount} services)`);
71
+ }
72
+ else {
73
+ console.log(` Collector: ${chalk.red('✗')} not reachable`);
74
+ }
75
+ if (appHealthy) {
76
+ console.log(` Electron-app: ${chalk.green('✓')} running`);
77
+ }
78
+ else {
79
+ console.log(` Electron-app: ${chalk.red('✗')} not reachable`);
80
+ }
81
+ // Show traces if available
82
+ if (tracesResponse?.success && tracesResponse.traces.length > 0) {
83
+ console.log(chalk.bold(`\n Recent Traces (${tracesResponse.count}):`));
84
+ for (const trace of tracesResponse.traces) {
85
+ const serviceName = extractServiceName(trace);
86
+ const spanCount = countSpans(trace);
87
+ const timestamp = extractTimestamp(trace);
88
+ console.log(` ${chalk.cyan(trace.traceId.slice(0, 16))}...`);
89
+ console.log(` Service: ${serviceName}`);
90
+ console.log(` Spans: ${spanCount}`);
91
+ if (timestamp) {
92
+ console.log(` Time: ${timestamp}`);
93
+ }
94
+ console.log();
95
+ }
96
+ }
97
+ else if (tracesResponse?.success && tracesResponse.traces.length === 0) {
98
+ console.log(chalk.bold('\n Recent Traces:'));
99
+ console.log(chalk.gray(' No traces stored yet.'));
100
+ console.log(chalk.gray(' Traces will appear here once your instrumented'));
101
+ console.log(chalk.gray(' application sends data to the collector.'));
102
+ }
103
+ else if (appHealthy && !tracesResponse) {
104
+ // Endpoint not implemented
105
+ console.log(chalk.bold('\n Trace Retrieval:'));
106
+ console.log(chalk.yellow(' Endpoint not available.'));
107
+ console.log();
108
+ console.log(chalk.gray(' The electron-app needs to be restarted to'));
109
+ console.log(chalk.gray(' enable the /otel/traces endpoint.'));
110
+ }
111
+ else {
112
+ console.log(chalk.bold('\n Trace Retrieval:'));
113
+ console.log(chalk.red(' Cannot connect to electron-app.'));
114
+ }
115
+ console.log('\n' + '━'.repeat(60));
116
+ console.log();
117
+ }
118
+ catch (error) {
119
+ console.error(chalk.red('Error:'), error.message);
120
+ process.exit(1);
121
+ }
122
+ });
123
+ return command;
124
+ }
125
+ function extractServiceName(trace) {
126
+ const attrs = trace.data.resourceSpans?.[0]?.resource?.attributes ?? [];
127
+ const serviceAttr = attrs.find((a) => a.key === 'service.name');
128
+ return serviceAttr?.value?.stringValue ?? 'unknown';
129
+ }
130
+ function countSpans(trace) {
131
+ let count = 0;
132
+ for (const rs of trace.data.resourceSpans ?? []) {
133
+ for (const ss of rs.scopeSpans ?? []) {
134
+ count += ss.spans?.length ?? 0;
135
+ }
136
+ }
137
+ return count;
138
+ }
139
+ function extractTimestamp(trace) {
140
+ const startNano = trace.data.resourceSpans?.[0]?.scopeSpans?.[0]?.spans?.[0]?.startTimeUnixNano;
141
+ if (!startNano)
142
+ return null;
143
+ const ms = parseInt(startNano, 10) / 1_000_000;
144
+ return new Date(ms).toISOString();
145
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * trace registrations - Show active port registrations for trace routing
3
+ */
4
+ import { Command } from 'commander';
5
+ export declare function createRegistrationsCommand(): Command;
6
+ //# sourceMappingURL=registrations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registrations.d.ts","sourceRoot":"","sources":["../../../src/commands/trace/registrations.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAwBpC,wBAAgB,0BAA0B,IAAI,OAAO,CAyBpD"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * trace registrations - Show active port registrations for trace routing
3
+ */
4
+ import { Command } from 'commander';
5
+ import chalk from 'chalk';
6
+ const DEFAULT_APP_PORT = 3043;
7
+ export function createRegistrationsCommand() {
8
+ const command = new Command('registrations');
9
+ command
10
+ .description('Show active port registrations for trace routing')
11
+ .option('-p, --port <port>', 'Electron-app port (default: 3043, dev: 3045)')
12
+ .option('--json', 'Output as JSON')
13
+ .action(async (options) => {
14
+ try {
15
+ const appPort = options.port ? parseInt(options.port, 10) : DEFAULT_APP_PORT;
16
+ const data = await fetchRegistrations(appPort);
17
+ if (options.json) {
18
+ console.log(JSON.stringify(data, null, 2));
19
+ }
20
+ else {
21
+ outputText(data);
22
+ }
23
+ }
24
+ catch (error) {
25
+ console.error(chalk.red('Error:'), error.message);
26
+ process.exit(1);
27
+ }
28
+ });
29
+ return command;
30
+ }
31
+ async function fetchRegistrations(port) {
32
+ const url = `http://localhost:${port}/otel/registrations`;
33
+ try {
34
+ const response = await fetch(url, { signal: AbortSignal.timeout(5000) });
35
+ if (!response.ok) {
36
+ throw new Error(`Failed to fetch registrations: ${response.statusText}`);
37
+ }
38
+ return (await response.json());
39
+ }
40
+ catch (error) {
41
+ if (error.name === 'AbortError') {
42
+ throw new Error('Request timeout - electron-app not responding');
43
+ }
44
+ throw error;
45
+ }
46
+ }
47
+ function outputText(data) {
48
+ console.log(chalk.bold('\nPort Registrations'));
49
+ console.log('━'.repeat(60));
50
+ if (data.registrations.length === 0) {
51
+ console.log(chalk.yellow('\nNo active registrations found.'));
52
+ console.log(chalk.gray('Windows register when they start listening for traces from a service.'));
53
+ console.log();
54
+ return;
55
+ }
56
+ // Group by window
57
+ const byWindow = new Map();
58
+ for (const reg of data.registrations) {
59
+ const existing = byWindow.get(reg.windowId) || [];
60
+ existing.push(reg);
61
+ byWindow.set(reg.windowId, existing);
62
+ }
63
+ // Output by window
64
+ for (const [windowId, regs] of byWindow) {
65
+ console.log();
66
+ console.log(chalk.cyan(`Window: ${windowId}`));
67
+ for (const reg of regs) {
68
+ const time = new Date(reg.registeredAt).toLocaleTimeString();
69
+ const isWildcard = reg.serviceName === '*';
70
+ const serviceName = isWildcard ? chalk.yellow('* (all services)') : reg.serviceName;
71
+ console.log(chalk.gray(` └─ ${serviceName}`) + chalk.gray(` @ ${time}`));
72
+ }
73
+ }
74
+ // Summary
75
+ console.log();
76
+ console.log('━'.repeat(60));
77
+ console.log(chalk.gray(`Windows: ${byWindow.size}`));
78
+ console.log(chalk.gray(`Registrations: ${data.registrations.length}`));
79
+ console.log(chalk.gray(`Active services: ${data.services.join(', ') || 'none'}`));
80
+ console.log();
81
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * trace validate - Validate traces against workflow.json definitions
3
+ */
4
+ import { Command } from 'commander';
5
+ export declare function createValidateCommand(): Command;
6
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../src/commands/trace/validate.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAsCpC,wBAAgB,qBAAqB,IAAI,OAAO,CAqD/C"}