taist 0.1.0
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/.taistrc.json +18 -0
- package/LICENSE +20 -0
- package/README.md +471 -0
- package/index.js +147 -0
- package/instrument.js +233 -0
- package/lib/config-loader.js +102 -0
- package/lib/execution-tracer.js +350 -0
- package/lib/instrument-all.js +332 -0
- package/lib/logger.js +61 -0
- package/lib/module-hooks.js +109 -0
- package/lib/module-patcher.js +42 -0
- package/lib/output-formatter.js +151 -0
- package/lib/service-tracer.js +548 -0
- package/lib/toon-formatter.js +498 -0
- package/lib/trace-collector.js +221 -0
- package/lib/trace-context.js +80 -0
- package/lib/trace-reporter.js +329 -0
- package/lib/trace-session.js +119 -0
- package/lib/transform.js +362 -0
- package/lib/vitest-runner.js +436 -0
- package/lib/watch-handler.js +300 -0
- package/package.json +90 -0
- package/taist.js +527 -0
- package/testing.js +29 -0
package/.taistrc.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"include": ["examples/**/*.js", "src/**/*.js", "src/**/*.ts", "lib/**/*.js"],
|
|
3
|
+
"exclude": ["**/node_modules/**", "**/*.test.*", "**/*.spec.*", "**/taist/lib/**"],
|
|
4
|
+
"depth": 3,
|
|
5
|
+
"format": "toon",
|
|
6
|
+
"trace": {
|
|
7
|
+
"enabled": false,
|
|
8
|
+
"depth": 2
|
|
9
|
+
},
|
|
10
|
+
"watch": {
|
|
11
|
+
"ignore": ["node_modules", ".git", "dist", "build"],
|
|
12
|
+
"delay": 500
|
|
13
|
+
},
|
|
14
|
+
"output": {
|
|
15
|
+
"abbreviate": true,
|
|
16
|
+
"maxTokens": 1000
|
|
17
|
+
}
|
|
18
|
+
}
|
package/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Taist
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF MERCHANTABILITY,
|
|
16
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
# Taist - AI Test Runner
|
|
2
|
+
## Token-Optimized Testing Framework for AI-Assisted Development
|
|
3
|
+
|
|
4
|
+
Version: 0.1.0 | January 2025 | [Technical Specification](./SPEC.md)
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Table of Contents
|
|
9
|
+
1. [Why Taist?](#why-taist)
|
|
10
|
+
2. [Execution Tree Output](#execution-tree-output)
|
|
11
|
+
3. [Quick Start](#quick-start)
|
|
12
|
+
4. [Integration Methods](#integration-methods)
|
|
13
|
+
5. [Test Integration](#test-integration)
|
|
14
|
+
6. [Configuration Reference](#configuration-reference)
|
|
15
|
+
7. [Usage Examples](#usage-examples)
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Why Taist?
|
|
20
|
+
|
|
21
|
+
Taist solves two critical problems when using LLMs for development and testing:
|
|
22
|
+
|
|
23
|
+
### 1. Token Reduction (90%)
|
|
24
|
+
|
|
25
|
+
Traditional test output wastes tokens on verbose formatting, redundant stack traces, and decorative elements. Taist compresses output using TOON (Token-Optimized Output Notation):
|
|
26
|
+
|
|
27
|
+
**Traditional Output (450 tokens)**
|
|
28
|
+
```
|
|
29
|
+
FAIL test/calculator.test.js > Calculator > should add two numbers
|
|
30
|
+
AssertionError: expected 5 to be 6
|
|
31
|
+
Expected: 6
|
|
32
|
+
Received: 5
|
|
33
|
+
at /Users/dev/project/test/calculator.test.js:15:23
|
|
34
|
+
at processTicksAndRejections (node:internal/process/task_queues:95:5)
|
|
35
|
+
at Module._compile (node:internal/modules/cjs/loader:1376:14)
|
|
36
|
+
at Module._extensions..js (node:internal/modules/cjs/loader:1435:10)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**TOON Output (45 tokens)**
|
|
40
|
+
```
|
|
41
|
+
✗ calc.add
|
|
42
|
+
@test:15
|
|
43
|
+
exp:6 got:5
|
|
44
|
+
path:add(2,3)→5
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 2. Execution Visibility Without Code Changes
|
|
48
|
+
|
|
49
|
+
Instead of littering your code with `console.log` statements, Taist automatically traces function calls, arguments, return values, and errors. This gives LLMs the context they need to debug issues.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Execution Tree Output
|
|
54
|
+
|
|
55
|
+
The execution tree is Taist's key debugging feature. It shows the complete call hierarchy with timing, arguments, return values, and errors - all without modifying your source code.
|
|
56
|
+
|
|
57
|
+
### Example Output
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
===TESTS: 5/12===
|
|
61
|
+
|
|
62
|
+
FAILURES:
|
|
63
|
+
✗ Order Creation > should create order with valid data
|
|
64
|
+
@order.spec.ts:45
|
|
65
|
+
expected 500 to be 200 // Object.is equality
|
|
66
|
+
exp: "200"
|
|
67
|
+
got: "500"
|
|
68
|
+
|
|
69
|
+
TRACE:
|
|
70
|
+
fn:Route.POST /order/create ms:245 args:[{email:"test@..."}] ret:{status:500}
|
|
71
|
+
fn:OrderService.createOrder ms:180 ret:{status:"error"}
|
|
72
|
+
fn:ValidationService.validate ms:10 err:Invalid email format
|
|
73
|
+
fn:AllocationService.allocate ms:45 (not called - previous error)
|
|
74
|
+
fn:StripeService.createPaymentIntent ms:0 (not called)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Reading the Trace
|
|
78
|
+
|
|
79
|
+
| Field | Meaning |
|
|
80
|
+
|-------|---------|
|
|
81
|
+
| `fn:` | Function name (Module.method format) |
|
|
82
|
+
| `ms:` | Execution duration in milliseconds |
|
|
83
|
+
| `args:` | Function arguments (truncated for readability) |
|
|
84
|
+
| `ret:` | Return value (truncated) |
|
|
85
|
+
| `err:` | Error message (if function threw) |
|
|
86
|
+
|
|
87
|
+
### Depth-Based Indentation
|
|
88
|
+
|
|
89
|
+
Indentation reveals the call hierarchy:
|
|
90
|
+
- **No indent**: Entry point (e.g., route handler)
|
|
91
|
+
- **2 spaces**: Called by entry point
|
|
92
|
+
- **4 spaces**: Nested call
|
|
93
|
+
- And so on...
|
|
94
|
+
|
|
95
|
+
In the example above, you can immediately see that:
|
|
96
|
+
1. The route handler called `OrderService.createOrder`
|
|
97
|
+
2. Which called `ValidationService.validate`
|
|
98
|
+
3. Which threw "Invalid email format"
|
|
99
|
+
4. This caused `AllocationService.allocate` and `StripeService.createPaymentIntent` to never be called
|
|
100
|
+
|
|
101
|
+
**This gives LLMs exactly the context they need to fix the bug.**
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Quick Start
|
|
106
|
+
|
|
107
|
+
### Option 1: ESM Loader (Recommended)
|
|
108
|
+
```bash
|
|
109
|
+
# Run any Node.js app with automatic tracing
|
|
110
|
+
node --import taist/module-patcher your-app.js
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Option 2: Manual Instrumentation
|
|
114
|
+
```javascript
|
|
115
|
+
// Add at the top of your service
|
|
116
|
+
import 'taist/instrument';
|
|
117
|
+
import { instrumentService } from 'taist/instrument';
|
|
118
|
+
|
|
119
|
+
const myService = instrumentService(new MyService(), 'MyService');
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Option 3: Programmatic API
|
|
123
|
+
```javascript
|
|
124
|
+
import { ServiceTracer } from 'taist';
|
|
125
|
+
|
|
126
|
+
const tracer = new ServiceTracer({ enabled: true, depth: 3 });
|
|
127
|
+
tracer.instrument(MyClass, 'MyClass');
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Integration Methods
|
|
133
|
+
|
|
134
|
+
| Method | Use Case | Setup |
|
|
135
|
+
|--------|----------|-------|
|
|
136
|
+
| **ESM Loader** | Node.js apps, automatic tracing | `node --import taist/module-patcher app.js` |
|
|
137
|
+
| **Import-based** | Express apps, selective tracing | `import 'taist/instrument'` |
|
|
138
|
+
| **Programmatic** | Full control, multiple tracers | `new ServiceTracer()` |
|
|
139
|
+
|
|
140
|
+
### ESM Loader Integration (Recommended)
|
|
141
|
+
|
|
142
|
+
The ESM Loader provides automatic instrumentation for Node.js applications without requiring code changes. Configure which modules to trace via `.taistrc.json`.
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
# Run any Node.js app with automatic tracing
|
|
146
|
+
node --import taist/module-patcher your-app.js
|
|
147
|
+
|
|
148
|
+
# With environment variables
|
|
149
|
+
TAIST_ENABLED=true TAIST_DEPTH=3 node --import taist/module-patcher your-app.js
|
|
150
|
+
|
|
151
|
+
# Debug mode (shows what's being instrumented)
|
|
152
|
+
TAIST_DEBUG=1 node --import taist/module-patcher your-app.js
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**Configuration (`.taistrc.json`):**
|
|
156
|
+
```json
|
|
157
|
+
{
|
|
158
|
+
"include": ["src/**/*.js", "services/**/*.js"],
|
|
159
|
+
"exclude": ["**/node_modules/**", "**/*.test.js"],
|
|
160
|
+
"depth": 3
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
**When to use:**
|
|
165
|
+
- Node.js applications (v18.19+ or v20.6+)
|
|
166
|
+
- Quick debugging without code changes
|
|
167
|
+
- Development and testing environments
|
|
168
|
+
|
|
169
|
+
### Import-based Instrumentation
|
|
170
|
+
|
|
171
|
+
For Express apps or when you want explicit control without CLI flags:
|
|
172
|
+
|
|
173
|
+
```javascript
|
|
174
|
+
// Add at the top of your entry point
|
|
175
|
+
import 'taist/instrument';
|
|
176
|
+
import { instrumentExpress, instrumentService } from 'taist/instrument';
|
|
177
|
+
import express from 'express';
|
|
178
|
+
|
|
179
|
+
// Instrument service classes
|
|
180
|
+
class UserService {
|
|
181
|
+
async createUser(data) { /* ... */ }
|
|
182
|
+
async getUser(id) { /* ... */ }
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const userService = instrumentService(new UserService(), 'UserService');
|
|
186
|
+
|
|
187
|
+
// Instrument Express app
|
|
188
|
+
const app = express();
|
|
189
|
+
instrumentExpress(app);
|
|
190
|
+
|
|
191
|
+
// Routes are automatically traced
|
|
192
|
+
app.get('/users/:id', async (req, res) => {
|
|
193
|
+
const user = await userService.getUser(req.params.id);
|
|
194
|
+
res.json(user);
|
|
195
|
+
});
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
**Run with tracing:**
|
|
199
|
+
```bash
|
|
200
|
+
TAIST_ENABLED=true node server.js
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**When to use:**
|
|
204
|
+
- Express/Fastify applications
|
|
205
|
+
- Gradual adoption into existing projects
|
|
206
|
+
- When you can't use `--import` flag
|
|
207
|
+
|
|
208
|
+
### Programmatic API
|
|
209
|
+
|
|
210
|
+
For full control over tracing configuration:
|
|
211
|
+
|
|
212
|
+
```javascript
|
|
213
|
+
import { ServiceTracer } from 'taist';
|
|
214
|
+
|
|
215
|
+
// Create tracer with explicit configuration
|
|
216
|
+
const tracer = new ServiceTracer({
|
|
217
|
+
enabled: true,
|
|
218
|
+
depth: 3,
|
|
219
|
+
outputFormat: 'toon'
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
// Instrument classes
|
|
223
|
+
class UserService {
|
|
224
|
+
async getUser(id) { /* ... */ }
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const userService = new UserService();
|
|
228
|
+
tracer.instrument(userService, 'UserService');
|
|
229
|
+
|
|
230
|
+
// Or wrap individual functions
|
|
231
|
+
const tracedFn = tracer.wrapMethod(myFunction, 'myFunction');
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
**When to use:**
|
|
235
|
+
- Complex scenarios with multiple tracers
|
|
236
|
+
- Custom trace collection logic
|
|
237
|
+
- Maximum flexibility needed
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## Test Integration
|
|
242
|
+
|
|
243
|
+
Use `TraceSession` to collect and display execution traces in your test suites. This provides visibility into what your code is doing during tests without modifying application code.
|
|
244
|
+
|
|
245
|
+
### Vitest / Jest Integration
|
|
246
|
+
|
|
247
|
+
```javascript
|
|
248
|
+
import { describe, it, beforeAll, afterAll } from 'vitest';
|
|
249
|
+
import { spawn } from 'child_process';
|
|
250
|
+
import { TraceSession } from 'taist/testing';
|
|
251
|
+
|
|
252
|
+
let session;
|
|
253
|
+
let serverProcess;
|
|
254
|
+
|
|
255
|
+
beforeAll(async () => {
|
|
256
|
+
// Start trace session
|
|
257
|
+
session = new TraceSession();
|
|
258
|
+
await session.start();
|
|
259
|
+
|
|
260
|
+
// Start your server with tracing enabled
|
|
261
|
+
serverProcess = spawn('node', ['server.js'], {
|
|
262
|
+
env: {
|
|
263
|
+
...process.env,
|
|
264
|
+
...session.getEnv(), // Adds TAIST_ENABLED and TAIST_COLLECTOR_SOCKET
|
|
265
|
+
PORT: '3000',
|
|
266
|
+
},
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
await waitForServer();
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
afterAll(async () => {
|
|
273
|
+
// Stop server
|
|
274
|
+
serverProcess?.kill('SIGTERM');
|
|
275
|
+
|
|
276
|
+
// Print collected traces and stop session
|
|
277
|
+
session.printTraces({ maxGroups: 5 });
|
|
278
|
+
await session.stop();
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
describe('API Tests', () => {
|
|
282
|
+
it('should create user', async () => {
|
|
283
|
+
const res = await fetch('http://localhost:3000/users', {
|
|
284
|
+
method: 'POST',
|
|
285
|
+
body: JSON.stringify({ name: 'Alice' }),
|
|
286
|
+
});
|
|
287
|
+
expect(res.status).toBe(201);
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### TraceSession API
|
|
293
|
+
|
|
294
|
+
| Method | Description |
|
|
295
|
+
|--------|-------------|
|
|
296
|
+
| `start()` | Start the trace collector |
|
|
297
|
+
| `getEnv()` | Get environment variables for enabling tracing |
|
|
298
|
+
| `getTraces()` | Get collected trace objects |
|
|
299
|
+
| `printTraces(options)` | Format and print trace tree to console |
|
|
300
|
+
| `formatTraces(options)` | Format traces as string (without printing) |
|
|
301
|
+
| `stop()` | Stop the trace collector |
|
|
302
|
+
|
|
303
|
+
### Print Options
|
|
304
|
+
|
|
305
|
+
```javascript
|
|
306
|
+
session.printTraces({
|
|
307
|
+
maxGroups: 10, // Max request groups to show (default: 10)
|
|
308
|
+
showToon: true, // Also show TOON format summary (default: true)
|
|
309
|
+
toonLimit: 30, // Max traces for TOON output (default: 30)
|
|
310
|
+
});
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### Example Output
|
|
314
|
+
|
|
315
|
+
When tests complete, you'll see the execution tree grouped by HTTP request:
|
|
316
|
+
|
|
317
|
+
```
|
|
318
|
+
============================================================
|
|
319
|
+
TRACE OUTPUT
|
|
320
|
+
============================================================
|
|
321
|
+
Traces: 45 | Requests: 12
|
|
322
|
+
|
|
323
|
+
--- Route.POST /users ---
|
|
324
|
+
fn:Route.POST /users depth:0 45ms
|
|
325
|
+
fn:UserService.register depth:1 30ms
|
|
326
|
+
fn:UserService.validateEmail depth:2 5ms
|
|
327
|
+
fn:UserService._hashPassword depth:2 10ms
|
|
328
|
+
|
|
329
|
+
--- Route.GET /users/:id ---
|
|
330
|
+
fn:Route.GET /users/:id depth:0 12ms
|
|
331
|
+
fn:UserService.getUser depth:1 8ms
|
|
332
|
+
fn:Cache.get depth:2 2ms
|
|
333
|
+
|
|
334
|
+
... and 10 more requests
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
---
|
|
338
|
+
|
|
339
|
+
## Configuration Reference
|
|
340
|
+
|
|
341
|
+
### Environment Variables
|
|
342
|
+
|
|
343
|
+
| Variable | Description | Default |
|
|
344
|
+
|----------|-------------|---------|
|
|
345
|
+
| `TAIST_ENABLED` | Enable/disable tracing | `true` (when loader used) |
|
|
346
|
+
| `TAIST_DEBUG` | Show internal taist operations | `false` |
|
|
347
|
+
| `TAIST_FORMAT` | Output format: `toon`, `json`, `compact` | `toon` |
|
|
348
|
+
| `TAIST_DEPTH` | Trace depth level (1-5) | `3` |
|
|
349
|
+
| `TAIST_INCLUDE` | Only trace modules matching patterns (comma-separated) | All files |
|
|
350
|
+
| `TAIST_EXCLUDE` | Skip modules matching patterns | `node_modules` |
|
|
351
|
+
| `TAIST_OUTPUT_FILE` | Write traces to file | stdout |
|
|
352
|
+
| `TAIST_OUTPUT_INTERVAL` | Output interval in ms | `30000` |
|
|
353
|
+
| `TAIST_SLOW_THRESHOLD` | Slow operation threshold in ms | `100` |
|
|
354
|
+
|
|
355
|
+
### CLI Options
|
|
356
|
+
|
|
357
|
+
```bash
|
|
358
|
+
taist test [options] # Run tests once
|
|
359
|
+
taist watch [options] # Run tests in watch mode
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
| Option | Short | Description | Default |
|
|
363
|
+
|--------|-------|-------------|---------|
|
|
364
|
+
| `--file` | `-f` | Source file(s) to test | `./src` |
|
|
365
|
+
| `--test` | `-t` | Test file(s) to run | `./test` |
|
|
366
|
+
| `--format` | | Output format | `toon` |
|
|
367
|
+
| `--watch` | `-w` | Enable watch mode | `false` |
|
|
368
|
+
| `--trace` | | Enable execution tracing | `false` |
|
|
369
|
+
| `--depth` | `-d` | Trace depth level (1-5) | `2` |
|
|
370
|
+
| `--output` | `-o` | Output file path | `stdout` |
|
|
371
|
+
|
|
372
|
+
### Output Formats
|
|
373
|
+
|
|
374
|
+
**TOON (Default)** - Token-optimized for AI consumption
|
|
375
|
+
```
|
|
376
|
+
[TAIST] up:120s calls:5432 err:3
|
|
377
|
+
[SLOW] 12 ops >100ms
|
|
378
|
+
[TOP] getUser:234 createUser:123
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
**JSON** - Structured for tooling
|
|
382
|
+
```json
|
|
383
|
+
{
|
|
384
|
+
"stats": { "totalCalls": 5432, "totalErrors": 3 },
|
|
385
|
+
"traces": { "topFunctions": { "UserService.getUser": 234 } }
|
|
386
|
+
}
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
**Compact** - One-line summaries for CI/CD
|
|
390
|
+
|
|
391
|
+
---
|
|
392
|
+
|
|
393
|
+
## Usage Examples
|
|
394
|
+
|
|
395
|
+
### Basic Testing
|
|
396
|
+
```bash
|
|
397
|
+
# Run all tests with TOON output
|
|
398
|
+
taist test
|
|
399
|
+
|
|
400
|
+
# Test specific files
|
|
401
|
+
taist test -f ./src/email.js -t ./test/email.test.js
|
|
402
|
+
|
|
403
|
+
# JSON output for tooling
|
|
404
|
+
taist test --format json > results.json
|
|
405
|
+
|
|
406
|
+
# With execution tracing
|
|
407
|
+
taist test --trace --depth 3
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### With AI Tools
|
|
411
|
+
|
|
412
|
+
```bash
|
|
413
|
+
# Iterative development with Claude Code
|
|
414
|
+
taist watch -f ./src -t ./test
|
|
415
|
+
|
|
416
|
+
# Pipe to AI tools
|
|
417
|
+
taist test --format toon | gh copilot explain
|
|
418
|
+
|
|
419
|
+
# Generate fix suggestions
|
|
420
|
+
taist test --trace | your-ai-tool analyze
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
### CI/CD Integration
|
|
424
|
+
|
|
425
|
+
```yaml
|
|
426
|
+
# GitHub Actions
|
|
427
|
+
- name: Run AI-friendly tests
|
|
428
|
+
run: |
|
|
429
|
+
npm install -g taist
|
|
430
|
+
taist test --format compact
|
|
431
|
+
|
|
432
|
+
- name: Store detailed results on failure
|
|
433
|
+
if: failure()
|
|
434
|
+
run: taist test --trace --format json > test-results.json
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
### Integration with package.json
|
|
438
|
+
|
|
439
|
+
```json
|
|
440
|
+
{
|
|
441
|
+
"scripts": {
|
|
442
|
+
"test": "vitest",
|
|
443
|
+
"test:ai": "taist test --format toon",
|
|
444
|
+
"test:watch": "taist watch",
|
|
445
|
+
"test:trace": "taist test --trace --depth 3"
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
---
|
|
451
|
+
|
|
452
|
+
## Installation
|
|
453
|
+
|
|
454
|
+
```bash
|
|
455
|
+
# Global installation
|
|
456
|
+
npm install -g taist
|
|
457
|
+
|
|
458
|
+
# Project installation
|
|
459
|
+
npm install --save-dev taist
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
---
|
|
463
|
+
|
|
464
|
+
## License
|
|
465
|
+
|
|
466
|
+
MIT License - Open source and free for commercial use
|
|
467
|
+
|
|
468
|
+
## Support
|
|
469
|
+
|
|
470
|
+
- Issues: https://github.com/taist/taist/issues
|
|
471
|
+
- Technical Specification: [SPEC.md](./SPEC.md)
|
package/index.js
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Taist - Token-Optimized Testing Framework
|
|
3
|
+
* Main programmatic API
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { VitestRunner } from './lib/vitest-runner.js';
|
|
7
|
+
import { OutputFormatter } from './lib/output-formatter.js';
|
|
8
|
+
import { WatchHandler } from './lib/watch-handler.js';
|
|
9
|
+
import { ExecutionTracer } from './lib/execution-tracer.js';
|
|
10
|
+
import { ToonFormatter } from './lib/toon-formatter.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Main Taist class for programmatic usage
|
|
14
|
+
*/
|
|
15
|
+
export class Taist {
|
|
16
|
+
constructor(options = {}) {
|
|
17
|
+
this.options = {
|
|
18
|
+
format: options.format || 'toon',
|
|
19
|
+
trace: options.trace !== false,
|
|
20
|
+
depth: options.depth || 2,
|
|
21
|
+
...options
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
this.tracer = new ExecutionTracer({
|
|
25
|
+
enabled: this.options.trace,
|
|
26
|
+
depth: this.options.depth
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
this.runner = new VitestRunner({
|
|
30
|
+
trace: {
|
|
31
|
+
enabled: this.options.trace,
|
|
32
|
+
depth: this.options.depth
|
|
33
|
+
},
|
|
34
|
+
tracer: this.tracer
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
this.formatter = new OutputFormatter({
|
|
38
|
+
format: this.options.format,
|
|
39
|
+
...this.options.output
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
this.watchHandler = null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Run tests once
|
|
47
|
+
* @param {Object} config - Test configuration
|
|
48
|
+
* @returns {Object} Test results
|
|
49
|
+
*/
|
|
50
|
+
async run(config = {}) {
|
|
51
|
+
const results = await this.runner.run({
|
|
52
|
+
files: config.files || this.options.files,
|
|
53
|
+
tests: config.tests || this.options.tests
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
return results;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Format test results
|
|
61
|
+
* @param {Object} results - Test results
|
|
62
|
+
* @returns {string} Formatted output
|
|
63
|
+
*/
|
|
64
|
+
format(results) {
|
|
65
|
+
return this.formatter.format(results);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Run tests and get formatted output
|
|
70
|
+
* @param {Object} config - Test configuration
|
|
71
|
+
* @returns {string} Formatted test output
|
|
72
|
+
*/
|
|
73
|
+
async runAndFormat(config = {}) {
|
|
74
|
+
const results = await this.run(config);
|
|
75
|
+
return this.format(results);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Start watch mode
|
|
80
|
+
* @param {Object} config - Watch configuration
|
|
81
|
+
*/
|
|
82
|
+
async watch(config = {}) {
|
|
83
|
+
if (this.watchHandler) {
|
|
84
|
+
throw new Error('Watch mode already started');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
this.watchHandler = new WatchHandler({
|
|
88
|
+
...this.options.watch,
|
|
89
|
+
...config
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const watchPaths = config.paths || this.options.paths || ['./src', './test'];
|
|
93
|
+
|
|
94
|
+
// Set up event listeners if callbacks provided
|
|
95
|
+
if (config.onChange) {
|
|
96
|
+
this.watchHandler.on('run-complete', ({ results }) => {
|
|
97
|
+
config.onChange(results);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (config.onError) {
|
|
102
|
+
this.watchHandler.on('run-error', ({ error }) => {
|
|
103
|
+
config.onError(error);
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
await this.watchHandler.start(watchPaths, async () => {
|
|
108
|
+
return await this.run(config);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
return this.watchHandler;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Stop watch mode
|
|
116
|
+
*/
|
|
117
|
+
async stopWatch() {
|
|
118
|
+
if (this.watchHandler) {
|
|
119
|
+
await this.watchHandler.stop();
|
|
120
|
+
this.watchHandler = null;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Get execution tracer
|
|
126
|
+
*/
|
|
127
|
+
getTracer() {
|
|
128
|
+
return this.tracer;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Set output format
|
|
133
|
+
*/
|
|
134
|
+
setFormat(format) {
|
|
135
|
+
this.formatter.setFormat(format);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Named exports
|
|
140
|
+
export { VitestRunner } from './lib/vitest-runner.js';
|
|
141
|
+
export { OutputFormatter } from './lib/output-formatter.js';
|
|
142
|
+
export { WatchHandler } from './lib/watch-handler.js';
|
|
143
|
+
export { ExecutionTracer } from './lib/execution-tracer.js';
|
|
144
|
+
export { ToonFormatter } from './lib/toon-formatter.js';
|
|
145
|
+
|
|
146
|
+
// Default export
|
|
147
|
+
export default Taist;
|