taist 0.1.4 → 0.1.5

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.
@@ -157,13 +157,34 @@ export class TraceCollector extends EventEmitter {
157
157
  this.traceIds.clear();
158
158
  }
159
159
 
160
- async stop() {
160
+ /**
161
+ * Stop the collector gracefully.
162
+ * Sends shutdown signal to workers and waits for them to flush before closing.
163
+ * @param {number} timeout - Max time to wait for workers to disconnect (default: 2000ms)
164
+ */
165
+ async stop(timeout = 2000) {
161
166
  if (!this.started) {
162
167
  return;
163
168
  }
164
169
 
170
+ // Send shutdown signal to all connected workers
171
+ const shutdownMessage = JSON.stringify({ type: 'shutdown' }) + '\n';
172
+ for (const socket of this.connections) {
173
+ try {
174
+ socket.write(shutdownMessage);
175
+ } catch {
176
+ // Socket may already be closed
177
+ }
178
+ }
179
+
180
+ // Wait for connections to close gracefully, or timeout
181
+ const startTime = Date.now();
182
+ while (this.connections.size > 0 && (Date.now() - startTime) < timeout) {
183
+ await new Promise(resolve => setTimeout(resolve, 50));
184
+ }
185
+
165
186
  return new Promise((resolve) => {
166
- // Close all active connections
187
+ // Force close any remaining connections
167
188
  for (const socket of this.connections) {
168
189
  socket.destroy();
169
190
  }
@@ -79,6 +79,28 @@ export class TraceReporter extends EventEmitter {
79
79
  // Don't keep the process alive just for tracing
80
80
  this.socket.unref();
81
81
 
82
+ // Handle incoming messages from collector (e.g., shutdown signal)
83
+ let dataBuffer = '';
84
+ this.socket.on("data", (chunk) => {
85
+ dataBuffer += chunk.toString();
86
+ const lines = dataBuffer.split('\n');
87
+ dataBuffer = lines.pop(); // Keep incomplete line
88
+
89
+ for (const line of lines) {
90
+ if (line.trim()) {
91
+ try {
92
+ const message = JSON.parse(line);
93
+ if (message.type === 'shutdown') {
94
+ logger.debug("[reporter] Received shutdown signal, flushing...");
95
+ this._handleShutdown();
96
+ }
97
+ } catch {
98
+ // Ignore parse errors
99
+ }
100
+ }
101
+ }
102
+ });
103
+
82
104
  this.socket.on("error", (err) => {
83
105
  this.connected = false;
84
106
  this.connecting = false;
@@ -128,6 +150,35 @@ export class TraceReporter extends EventEmitter {
128
150
  }
129
151
  }
130
152
 
153
+ /**
154
+ * Handle shutdown signal from collector.
155
+ * Immediately flushes buffer and closes connection.
156
+ */
157
+ _handleShutdown() {
158
+ if (this.closed) return;
159
+
160
+ // Flush synchronously and close
161
+ if (this.buffer.length > 0 && this.socket && this.connected) {
162
+ const traces = this.buffer.splice(0, this.buffer.length);
163
+ const message = JSON.stringify({
164
+ type: "batch",
165
+ workerId: this.workerId,
166
+ data: traces,
167
+ });
168
+
169
+ try {
170
+ this.socket.write(message + "\n", () => {
171
+ logger.debug("[reporter] Shutdown flush complete, closing");
172
+ this.close();
173
+ });
174
+ } catch {
175
+ this.close();
176
+ }
177
+ } else {
178
+ this.close();
179
+ }
180
+ }
181
+
131
182
  /**
132
183
  * Report a single trace event
133
184
  */
@@ -148,16 +148,15 @@ export class TaistReporter {
148
148
  await this.collectorReady;
149
149
  }
150
150
 
151
- // Give a small delay for any final traces to arrive
152
- await new Promise(resolve => setTimeout(resolve, 100));
151
+ // Stop the collector gracefully - this sends shutdown signal to workers
152
+ // and waits for them to flush their traces before closing (up to 2s timeout)
153
+ await this.collector.stop();
153
154
 
154
- // Get collected traces
155
+ // Get collected traces (after workers have flushed)
155
156
  if (this.options.showTrace) {
156
157
  this.results.trace = this.collector.getTraces();
157
158
  }
158
159
 
159
- // Stop the collector
160
- await this.collector.stop();
161
160
  this.collector = null;
162
161
  }
163
162
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taist",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Token-Optimized Testing Framework for AI-Assisted Development",
5
5
  "main": "index.js",
6
6
  "type": "module",