@crewx/shared 0.0.4 → 0.0.6-rc.1
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/package.json +6 -3
- package/test-tracer.js +17 -17
- package/tests/skill-tracer.test.ts +159 -0
package/package.json
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crewx/shared",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6-rc.1",
|
|
4
4
|
"main": "skill-tracer.js",
|
|
5
5
|
"description": "Shared utilities for CrewX built-in packages",
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@crewx/sdk": "
|
|
7
|
+
"@crewx/sdk": "0.8.9-rc.14"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "echo no tests"
|
|
8
11
|
}
|
|
9
|
-
}
|
|
12
|
+
}
|
package/test-tracer.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* skill-tracer
|
|
2
|
+
* skill-tracer test
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
const { trace, run, getDbPath } = require('./skill-tracer');
|
|
@@ -7,33 +7,33 @@ const { trace, run, getDbPath } = require('./skill-tracer');
|
|
|
7
7
|
console.log('=== skill-tracer PoC Test ===\n');
|
|
8
8
|
console.log('crewx.db path:', getDbPath());
|
|
9
9
|
|
|
10
|
-
//
|
|
11
|
-
console.log('\n[Test 1] trace()
|
|
10
|
+
// Test 1: manual trace() use
|
|
11
|
+
console.log('\n[Test 1] manual trace() use');
|
|
12
12
|
const t = trace('test-skill', 'manual test command', 'test-agent');
|
|
13
13
|
console.log('taskId:', t.taskId);
|
|
14
14
|
console.log('skipped:', t._skipped);
|
|
15
15
|
t.ok('test result');
|
|
16
|
-
console.log('->
|
|
16
|
+
console.log('-> done\n');
|
|
17
17
|
|
|
18
|
-
//
|
|
19
|
-
console.log('[Test 2] run()
|
|
18
|
+
// Test 2: run() wrapper success
|
|
19
|
+
console.log('[Test 2] run() wrapper - success case');
|
|
20
20
|
run('test-skill', async () => {
|
|
21
|
-
console.log('->
|
|
21
|
+
console.log('-> function running...');
|
|
22
22
|
return { status: 'success', data: 123 };
|
|
23
23
|
}).then(() => {
|
|
24
|
-
console.log('->
|
|
24
|
+
console.log('-> done\n');
|
|
25
25
|
|
|
26
|
-
//
|
|
27
|
-
console.log('[Test 3] run()
|
|
26
|
+
// Test 3: run() wrapper failure
|
|
27
|
+
console.log('[Test 3] run() wrapper - failure case');
|
|
28
28
|
return run('test-skill', async () => {
|
|
29
|
-
throw new Error('
|
|
29
|
+
throw new Error('intentional error');
|
|
30
30
|
}).catch(e => {
|
|
31
|
-
console.log('->
|
|
32
|
-
console.log('->
|
|
31
|
+
console.log('-> error captured:', e.message);
|
|
32
|
+
console.log('-> done\n');
|
|
33
33
|
});
|
|
34
34
|
}).then(() => {
|
|
35
|
-
//
|
|
36
|
-
console.log('=== crewx.db
|
|
35
|
+
// Verify results
|
|
36
|
+
console.log('=== crewx.db check ===');
|
|
37
37
|
const Database = require('better-sqlite3');
|
|
38
38
|
const db = new Database(getDbPath());
|
|
39
39
|
const rows = db.prepare(`
|
|
@@ -44,11 +44,11 @@ run('test-skill', async () => {
|
|
|
44
44
|
LIMIT 5
|
|
45
45
|
`).all();
|
|
46
46
|
|
|
47
|
-
console.log('\
|
|
47
|
+
console.log('\nRecent test-skill records:');
|
|
48
48
|
rows.forEach(r => {
|
|
49
49
|
console.log(` [${r.status}] ${r.prompt.substring(0, 50)}... (${r.duration_ms}ms)`);
|
|
50
50
|
});
|
|
51
51
|
|
|
52
52
|
db.close();
|
|
53
|
-
console.log('\n===
|
|
53
|
+
console.log('\n=== test complete ===');
|
|
54
54
|
});
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import os from 'os';
|
|
5
|
+
import Database from 'better-sqlite3';
|
|
6
|
+
|
|
7
|
+
const SPAN_ID_PATTERN = /^spn_[A-Za-z0-9]{8}$/;
|
|
8
|
+
|
|
9
|
+
describe('shared/skill-tracer', () => {
|
|
10
|
+
const sharedDir = path.resolve(__dirname, '..');
|
|
11
|
+
|
|
12
|
+
it('should be requireable from shared package', () => {
|
|
13
|
+
const tracer = require(path.join(sharedDir, 'skill-tracer.js'));
|
|
14
|
+
expect(tracer).toBeDefined();
|
|
15
|
+
expect(typeof tracer.trace).toBe('function');
|
|
16
|
+
expect(typeof tracer.run).toBe('function');
|
|
17
|
+
expect(typeof tracer.getDbPath).toBe('function');
|
|
18
|
+
expect(typeof tracer.getTracesDbPath).toBe('function');
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should have package.json with correct name', () => {
|
|
22
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(sharedDir, 'package.json'), 'utf-8'));
|
|
23
|
+
expect(pkg.name).toBe('@crewx/shared');
|
|
24
|
+
expect(pkg.main).toBe('skill-tracer.js');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('re-export wrapper at skills/lib should work', () => {
|
|
28
|
+
const wrapperPath = path.resolve(__dirname, '../../../../skills/lib/skill-tracer.js');
|
|
29
|
+
const tracer = require(wrapperPath);
|
|
30
|
+
expect(tracer).toBeDefined();
|
|
31
|
+
expect(typeof tracer.trace).toBe('function');
|
|
32
|
+
expect(typeof tracer.run).toBe('function');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('getDbPath should default to ~/.crewx/crewx.db', () => {
|
|
36
|
+
const tracer = require(path.join(sharedDir, 'skill-tracer.js'));
|
|
37
|
+
const dbPath = tracer.getDbPath();
|
|
38
|
+
expect(dbPath).toContain('.crewx');
|
|
39
|
+
expect(dbPath).toContain('crewx.db');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('uses @crewx/sdk generateId from CJS when direct traces create spans', () => {
|
|
43
|
+
const tracer = require(path.join(sharedDir, 'skill-tracer.js'));
|
|
44
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'skill-tracer-'));
|
|
45
|
+
const dbPath = path.join(tempDir, '.crewx', 'crewx.db');
|
|
46
|
+
const previousDbPath = process.env.CREWX_DB;
|
|
47
|
+
const previousTaskId = process.env.CREWX_TASK_ID;
|
|
48
|
+
|
|
49
|
+
process.env.CREWX_DB = dbPath;
|
|
50
|
+
delete process.env.CREWX_TASK_ID;
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
const trace = tracer.trace('memory', 'index core_sqa');
|
|
54
|
+
expect(trace._skipped).toBe(false);
|
|
55
|
+
expect(trace.taskId).toBeNull();
|
|
56
|
+
expect(trace.spanId).toMatch(SPAN_ID_PATTERN);
|
|
57
|
+
trace.ok('done');
|
|
58
|
+
} finally {
|
|
59
|
+
if (previousDbPath === undefined) {
|
|
60
|
+
delete process.env.CREWX_DB;
|
|
61
|
+
} else {
|
|
62
|
+
process.env.CREWX_DB = previousDbPath;
|
|
63
|
+
}
|
|
64
|
+
if (previousTaskId === undefined) {
|
|
65
|
+
delete process.env.CREWX_TASK_ID;
|
|
66
|
+
} else {
|
|
67
|
+
process.env.CREWX_TASK_ID = previousTaskId;
|
|
68
|
+
}
|
|
69
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe('shared/skill-tracer output capture', () => {
|
|
75
|
+
const sharedDir = path.resolve(__dirname, '..');
|
|
76
|
+
let tempDir: string;
|
|
77
|
+
let dbPath: string;
|
|
78
|
+
let prevDb: string | undefined;
|
|
79
|
+
let prevTaskId: string | undefined;
|
|
80
|
+
|
|
81
|
+
beforeEach(() => {
|
|
82
|
+
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'tracer-output-'));
|
|
83
|
+
dbPath = path.join(tempDir, 'crewx.db');
|
|
84
|
+
prevDb = process.env.CREWX_DB;
|
|
85
|
+
prevTaskId = process.env.CREWX_TASK_ID;
|
|
86
|
+
process.env.CREWX_DB = dbPath;
|
|
87
|
+
delete process.env.CREWX_TASK_ID;
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
afterEach(() => {
|
|
91
|
+
if (prevDb === undefined) delete process.env.CREWX_DB;
|
|
92
|
+
else process.env.CREWX_DB = prevDb;
|
|
93
|
+
if (prevTaskId === undefined) delete process.env.CREWX_TASK_ID;
|
|
94
|
+
else process.env.CREWX_TASK_ID = prevTaskId;
|
|
95
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('ok() captures output and stores in span', () => {
|
|
99
|
+
const tracer = require(path.join(sharedDir, 'skill-tracer.js'));
|
|
100
|
+
const t = tracer.trace('test', 'cmd');
|
|
101
|
+
t.ok('hello output');
|
|
102
|
+
const db = new Database(dbPath);
|
|
103
|
+
const row = db.prepare('SELECT output FROM spans ORDER BY started_at DESC LIMIT 1').get() as any;
|
|
104
|
+
db.close();
|
|
105
|
+
expect(row.output).toBe('hello output');
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('ok() truncates output > 32KB with head/tail pattern', () => {
|
|
109
|
+
const tracer = require(path.join(sharedDir, 'skill-tracer.js'));
|
|
110
|
+
const bigOutput = 'A'.repeat(40000);
|
|
111
|
+
const t = tracer.trace('test', 'cmd');
|
|
112
|
+
t.ok(bigOutput);
|
|
113
|
+
const db = new Database(dbPath);
|
|
114
|
+
const row = db.prepare('SELECT output, attributes FROM spans ORDER BY started_at DESC LIMIT 1').get() as any;
|
|
115
|
+
db.close();
|
|
116
|
+
const attrs = JSON.parse(row.attributes);
|
|
117
|
+
expect(attrs.output_truncated).toBe(true);
|
|
118
|
+
expect(attrs.output_bytes_original).toBe(40000);
|
|
119
|
+
expect(row.output).toContain('[omitted=');
|
|
120
|
+
expect(row.output.length).toBeLessThan(40000);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('ok() captures stderr in attributes', () => {
|
|
124
|
+
const tracer = require(path.join(sharedDir, 'skill-tracer.js'));
|
|
125
|
+
const t = tracer.trace('test', 'cmd');
|
|
126
|
+
t.ok('main output', { stderr: 'some error output' });
|
|
127
|
+
const db = new Database(dbPath);
|
|
128
|
+
const row = db.prepare('SELECT output, attributes FROM spans ORDER BY started_at DESC LIMIT 1').get() as any;
|
|
129
|
+
db.close();
|
|
130
|
+
expect(row.output).toBe('main output');
|
|
131
|
+
const attrs = JSON.parse(row.attributes);
|
|
132
|
+
expect(attrs.stderr).toBe('some error output');
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it('ok() truncates large stderr', () => {
|
|
136
|
+
const tracer = require(path.join(sharedDir, 'skill-tracer.js'));
|
|
137
|
+
const bigStderr = 'E'.repeat(40000);
|
|
138
|
+
const t = tracer.trace('test', 'cmd');
|
|
139
|
+
t.ok('output', { stderr: bigStderr });
|
|
140
|
+
const db = new Database(dbPath);
|
|
141
|
+
const row = db.prepare('SELECT attributes FROM spans ORDER BY started_at DESC LIMIT 1').get() as any;
|
|
142
|
+
db.close();
|
|
143
|
+
const attrs = JSON.parse(row.attributes);
|
|
144
|
+
expect(attrs.stderr_truncated).toBe(true);
|
|
145
|
+
expect(attrs.stderr_bytes_original).toBe(40000);
|
|
146
|
+
expect(attrs.stderr).toContain('[omitted=');
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('run() captures stdout when fn returns void', async () => {
|
|
150
|
+
const tracer = require(path.join(sharedDir, 'skill-tracer.js'));
|
|
151
|
+
await tracer.run('test-skill', async () => {
|
|
152
|
+
process.stdout.write('captured via run\n');
|
|
153
|
+
});
|
|
154
|
+
const db = new Database(dbPath);
|
|
155
|
+
const row = db.prepare('SELECT output FROM spans ORDER BY started_at DESC LIMIT 1').get() as any;
|
|
156
|
+
db.close();
|
|
157
|
+
expect(row.output).toBe('captured via run\n');
|
|
158
|
+
});
|
|
159
|
+
});
|