taist 0.1.1 → 0.1.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.
package/instrument.js CHANGED
@@ -49,6 +49,14 @@ import {
49
49
  instrumentClassWithContext
50
50
  } from './lib/instrument-all.js';
51
51
 
52
+ // Initialize global reporter for cross-process trace collection
53
+ // This must happen BEFORE any instrumentation so traces are sent to collector
54
+ const reporter = getGlobalReporter();
55
+ if (process.env.TAIST_COLLECTOR_SOCKET) {
56
+ logger.log(`Connecting to trace collector: ${process.env.TAIST_COLLECTOR_SOCKET}`);
57
+ reporter.connectEager();
58
+ }
59
+
52
60
  // Initialize global tracer from environment variables
53
61
  const tracer = new ServiceTracer({
54
62
  enabled: process.env.TAIST_ENABLED !== 'false',
@@ -62,7 +70,18 @@ const tracer = new ServiceTracer({
62
70
  });
63
71
 
64
72
  // Export for manual instrumentation
65
- export { tracer, autoInstrument };
73
+ export { tracer, autoInstrument, reporter };
74
+
75
+ /**
76
+ * Flush any buffered traces to the collector.
77
+ * Call this before process exit if you want to ensure all traces are sent.
78
+ * @returns {Promise<void>}
79
+ */
80
+ export async function flushTraces() {
81
+ if (reporter) {
82
+ await reporter.flush();
83
+ }
84
+ }
66
85
 
67
86
  // Log initialization
68
87
  if (tracer.options.enabled) {
@@ -45,10 +45,22 @@ export class ToonFormatter {
45
45
  */
46
46
  format(results) {
47
47
  const lines = [];
48
+ const total = results.stats?.total || 0;
49
+ const tests = results.tests || [];
48
50
 
49
51
  // Header
50
52
  lines.push(this.formatHeader(results));
51
53
 
54
+ // Show passing tests when running small batches (≤10 tests)
55
+ if (total > 0 && total <= 10) {
56
+ const passingTests = tests.filter(t => t.state === 'pass');
57
+ for (const test of passingTests) {
58
+ const duration = Math.round(test.duration);
59
+ const shortName = this.shortenTestName(test.name);
60
+ lines.push(`✓ ${shortName} (${duration}ms)`);
61
+ }
62
+ }
63
+
52
64
  // Failures
53
65
  if (results.failures && results.failures.length > 0) {
54
66
  lines.push('');
@@ -76,8 +88,19 @@ export class ToonFormatter {
76
88
  return lines.join('\n');
77
89
  }
78
90
 
91
+ /**
92
+ * Shorten a test name for display
93
+ * "Suite > Nested > actual test name" -> "actual test name"
94
+ */
95
+ shortenTestName(name) {
96
+ if (!name) return '';
97
+ const parts = name.split(' > ');
98
+ return parts[parts.length - 1] || name;
99
+ }
100
+
79
101
  /**
80
102
  * Format test result header
103
+ * Note: total represents tests that actually ran, not discovered
81
104
  */
82
105
  formatHeader(results) {
83
106
  const passed = results.stats?.passed || 0;
@@ -59,6 +59,7 @@ export class TaistReporter {
59
59
  this.taskResults = new Map(); // Map task id to result
60
60
  this.results = {
61
61
  stats: { total: 0, passed: 0, failed: 0, skipped: 0 },
62
+ tests: [], // Individual test results for enhanced output
62
63
  failures: [],
63
64
  duration: 0,
64
65
  trace: []
@@ -117,6 +118,7 @@ export class TaistReporter {
117
118
 
118
119
  // Reset stats
119
120
  this.results.stats = { total: 0, passed: 0, failed: 0, skipped: 0 };
121
+ this.results.tests = [];
120
122
  this.results.failures = [];
121
123
 
122
124
  // Process all test files
@@ -181,17 +183,30 @@ export class TaistReporter {
181
183
  */
182
184
  _processTask(task, file) {
183
185
  if (task.type === 'test') {
184
- this.results.stats.total++;
185
-
186
186
  const state = task.result?.state;
187
+
188
+ // Only count tests that actually ran (have a pass/fail result)
187
189
  if (state === 'pass') {
190
+ this.results.stats.total++;
188
191
  this.results.stats.passed++;
192
+ this.results.tests.push({
193
+ name: this._getTestName(task),
194
+ duration: task.result?.duration || 0,
195
+ state: 'pass'
196
+ });
189
197
  } else if (state === 'fail') {
198
+ this.results.stats.total++;
190
199
  this.results.stats.failed++;
191
200
  this.results.failures.push(this._formatFailure(task, file));
201
+ this.results.tests.push({
202
+ name: this._getTestName(task),
203
+ duration: task.result?.duration || 0,
204
+ state: 'fail'
205
+ });
192
206
  } else if (state === 'skip') {
193
207
  this.results.stats.skipped++;
194
208
  }
209
+ // Tests without state (filtered out) are not counted
195
210
  } else if (task.type === 'suite' && task.tasks) {
196
211
  // Process nested tasks
197
212
  for (const subtask of task.tasks) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taist",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Token-Optimized Testing Framework for AI-Assisted Development",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -13,6 +13,7 @@
13
13
  */
14
14
 
15
15
  import type { Application as ExpressApp } from 'express';
16
+ import type { TraceReporter } from './trace-collector';
16
17
 
17
18
  export interface TraceContext {
18
19
  /** Call depth (0 = root) */
@@ -85,6 +86,19 @@ export declare class ServiceTracer {
85
86
  */
86
87
  export declare const tracer: ServiceTracer;
87
88
 
89
+ /**
90
+ * Global reporter instance for cross-process trace collection.
91
+ * Automatically connects to TAIST_COLLECTOR_SOCKET if set.
92
+ */
93
+ export declare const reporter: TraceReporter;
94
+
95
+ /**
96
+ * Flush any buffered traces to the collector.
97
+ * Call this before process exit to ensure all traces are sent.
98
+ * @returns Promise that resolves when flush completes
99
+ */
100
+ export declare function flushTraces(): Promise<void>;
101
+
88
102
  /**
89
103
  * Auto-instrument a module's exports
90
104
  * @param moduleExports Module exports object
@@ -126,3 +126,89 @@ export declare function createDefaultFilter(
126
126
  ): (trace: TraceObject) => boolean;
127
127
 
128
128
  export default TraceCollector;
129
+
130
+ /**
131
+ * TraceReporter Options
132
+ */
133
+ export interface TraceReporterOptions {
134
+ /** Socket path to connect to (defaults to TAIST_COLLECTOR_SOCKET env var) */
135
+ socketPath?: string;
136
+ /** Number of traces to buffer before auto-flush (default: 100) */
137
+ batchSize?: number;
138
+ /** Flush interval in ms (default: 1000) */
139
+ flushInterval?: number;
140
+ /** Max connection retries (default: 3) */
141
+ maxRetries?: number;
142
+ /** Retry delay in ms (default: 100) */
143
+ retryDelay?: number;
144
+ /** Worker ID for identifying trace source */
145
+ workerId?: string | number;
146
+ }
147
+
148
+ /**
149
+ * TraceReporter - Client that runs in worker processes to send traces to the collector.
150
+ *
151
+ * Features:
152
+ * - Connects to collector via Unix domain socket
153
+ * - Buffers traces locally for batched sending
154
+ * - Auto-flushes on process exit
155
+ * - Handles connection failures gracefully
156
+ */
157
+ export declare class TraceReporter extends EventEmitter {
158
+ constructor(options?: TraceReporterOptions);
159
+
160
+ /**
161
+ * Connect to the collector socket
162
+ */
163
+ connect(): Promise<void>;
164
+
165
+ /**
166
+ * Start connection eagerly (call at module init time)
167
+ */
168
+ connectEager(): this;
169
+
170
+ /**
171
+ * Report a single trace event
172
+ */
173
+ report(trace: TraceObject): void;
174
+
175
+ /**
176
+ * Async flush - sends buffered traces to collector
177
+ */
178
+ flush(): Promise<void>;
179
+
180
+ /**
181
+ * Synchronous flush for process exit - best effort
182
+ */
183
+ flushSync(): void;
184
+
185
+ /**
186
+ * Close the reporter connection
187
+ */
188
+ close(): void;
189
+
190
+ /**
191
+ * Check if connected to collector
192
+ */
193
+ isConnected(): boolean;
194
+
195
+ /**
196
+ * Get current buffer size
197
+ */
198
+ getBufferSize(): number;
199
+ }
200
+
201
+ /**
202
+ * Get or create the global reporter instance
203
+ */
204
+ export declare function getGlobalReporter(options?: TraceReporterOptions): TraceReporter;
205
+
206
+ /**
207
+ * Report a trace using the global reporter
208
+ */
209
+ export declare function report(trace: TraceObject): void;
210
+
211
+ /**
212
+ * Flush the global reporter
213
+ */
214
+ export declare function flush(): Promise<void>;