@ash-ai/shared 0.0.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/LICENSE +21 -0
- package/dist/__tests__/protocol.test.d.ts +2 -0
- package/dist/__tests__/protocol.test.d.ts.map +1 -0
- package/dist/__tests__/protocol.test.js +105 -0
- package/dist/__tests__/protocol.test.js.map +1 -0
- package/dist/__tests__/timing.test.d.ts +2 -0
- package/dist/__tests__/timing.test.d.ts.map +1 -0
- package/dist/__tests__/timing.test.js +101 -0
- package/dist/__tests__/timing.test.js.map +1 -0
- package/dist/__tests__/types.test.d.ts +2 -0
- package/dist/__tests__/types.test.d.ts.map +1 -0
- package/dist/__tests__/types.test.js +51 -0
- package/dist/__tests__/types.test.js.map +1 -0
- package/dist/constants.d.ts +31 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +51 -0
- package/dist/constants.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/protocol.d.ts +36 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +16 -0
- package/dist/protocol.js.map +1 -0
- package/dist/timing.d.ts +23 -0
- package/dist/timing.d.ts.map +1 -0
- package/dist/timing.js +30 -0
- package/dist/timing.js.map +1 -0
- package/dist/types.d.ts +149 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +87 -0
- package/dist/types.js.map +1 -0
- package/package.json +32 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Ash Contributors
|
|
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 ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/protocol.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { encode, decode } from '../index.js';
|
|
3
|
+
describe('protocol', () => {
|
|
4
|
+
describe('encode/decode round-trip', () => {
|
|
5
|
+
it('round-trips a query command', () => {
|
|
6
|
+
const cmd = { cmd: 'query', prompt: 'hello', sessionId: 's1' };
|
|
7
|
+
const decoded = decode(encode(cmd));
|
|
8
|
+
expect(decoded).toEqual(cmd);
|
|
9
|
+
});
|
|
10
|
+
it('round-trips a resume command', () => {
|
|
11
|
+
const cmd = { cmd: 'resume', sessionId: 's1' };
|
|
12
|
+
const decoded = decode(encode(cmd));
|
|
13
|
+
expect(decoded).toEqual(cmd);
|
|
14
|
+
});
|
|
15
|
+
it('round-trips an interrupt command', () => {
|
|
16
|
+
const cmd = { cmd: 'interrupt' };
|
|
17
|
+
const decoded = decode(encode(cmd));
|
|
18
|
+
expect(decoded).toEqual(cmd);
|
|
19
|
+
});
|
|
20
|
+
it('round-trips a shutdown command', () => {
|
|
21
|
+
const cmd = { cmd: 'shutdown' };
|
|
22
|
+
const decoded = decode(encode(cmd));
|
|
23
|
+
expect(decoded).toEqual(cmd);
|
|
24
|
+
});
|
|
25
|
+
it('round-trips a ready event', () => {
|
|
26
|
+
const ev = { ev: 'ready' };
|
|
27
|
+
const decoded = decode(encode(ev));
|
|
28
|
+
expect(decoded).toEqual(ev);
|
|
29
|
+
});
|
|
30
|
+
it('round-trips a message event with SDK data', () => {
|
|
31
|
+
const sdkMessage = {
|
|
32
|
+
type: 'assistant',
|
|
33
|
+
message: { role: 'assistant', content: [{ type: 'text', text: 'hi' }] },
|
|
34
|
+
session_id: 's1',
|
|
35
|
+
};
|
|
36
|
+
const ev = { ev: 'message', data: sdkMessage };
|
|
37
|
+
const decoded = decode(encode(ev));
|
|
38
|
+
expect(decoded.ev).toBe('message');
|
|
39
|
+
expect(decoded).toEqual(ev);
|
|
40
|
+
});
|
|
41
|
+
it('round-trips an error event', () => {
|
|
42
|
+
const ev = { ev: 'error', error: 'something broke' };
|
|
43
|
+
const decoded = decode(encode(ev));
|
|
44
|
+
expect(decoded).toEqual(ev);
|
|
45
|
+
});
|
|
46
|
+
it('round-trips a done event', () => {
|
|
47
|
+
const ev = { ev: 'done', sessionId: 's1' };
|
|
48
|
+
const decoded = decode(encode(ev));
|
|
49
|
+
expect(decoded).toEqual(ev);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
describe('encode', () => {
|
|
53
|
+
it('produces newline-terminated JSON', () => {
|
|
54
|
+
const encoded = encode({ cmd: 'interrupt' });
|
|
55
|
+
expect(encoded).toMatch(/\n$/);
|
|
56
|
+
expect(encoded.split('\n').length).toBe(2); // content + empty after newline
|
|
57
|
+
});
|
|
58
|
+
it('is single-line (no embedded newlines)', () => {
|
|
59
|
+
const ev = { ev: 'message', data: { text: 'line1\nline2' } };
|
|
60
|
+
const encoded = encode(ev);
|
|
61
|
+
const lines = encoded.trimEnd().split('\n');
|
|
62
|
+
expect(lines.length).toBe(1);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
describe('decode', () => {
|
|
66
|
+
it('handles leading/trailing whitespace', () => {
|
|
67
|
+
const cmd = { cmd: 'interrupt' };
|
|
68
|
+
const decoded = decode(' ' + JSON.stringify(cmd) + ' \n');
|
|
69
|
+
expect(decoded).toEqual(cmd);
|
|
70
|
+
});
|
|
71
|
+
it('throws on invalid JSON', () => {
|
|
72
|
+
expect(() => decode('not json')).toThrow();
|
|
73
|
+
});
|
|
74
|
+
it('throws on empty string', () => {
|
|
75
|
+
expect(() => decode('')).toThrow();
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
describe('SDK message passthrough', () => {
|
|
79
|
+
it('preserves complex nested SDK message structure', () => {
|
|
80
|
+
const sdkResult = {
|
|
81
|
+
type: 'result',
|
|
82
|
+
subtype: 'success',
|
|
83
|
+
session_id: 'abc-123',
|
|
84
|
+
cost_usd: 0.0042,
|
|
85
|
+
duration_ms: 1500,
|
|
86
|
+
duration_api_ms: 1200,
|
|
87
|
+
is_error: false,
|
|
88
|
+
num_turns: 3,
|
|
89
|
+
result: 'Done!',
|
|
90
|
+
};
|
|
91
|
+
const ev = { ev: 'message', data: sdkResult };
|
|
92
|
+
const decoded = decode(encode(ev));
|
|
93
|
+
expect(decoded.data).toEqual(sdkResult);
|
|
94
|
+
});
|
|
95
|
+
it('preserves unicode in SDK messages', () => {
|
|
96
|
+
const ev = {
|
|
97
|
+
ev: 'message',
|
|
98
|
+
data: { type: 'assistant', content: '你好世界 🌍 émojis' },
|
|
99
|
+
};
|
|
100
|
+
const decoded = decode(encode(ev));
|
|
101
|
+
expect(decoded.data.content).toBe('你好世界 🌍 émojis');
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
//# sourceMappingURL=protocol.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.test.js","sourceRoot":"","sources":["../../src/__tests__/protocol.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timing.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/timing.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { startTimer, logTiming, timingEnabled } from '../timing.js';
|
|
3
|
+
describe('timing', () => {
|
|
4
|
+
const originalEnv = process.env.ASH_DEBUG_TIMING;
|
|
5
|
+
afterEach(() => {
|
|
6
|
+
if (originalEnv === undefined) {
|
|
7
|
+
delete process.env.ASH_DEBUG_TIMING;
|
|
8
|
+
}
|
|
9
|
+
else {
|
|
10
|
+
process.env.ASH_DEBUG_TIMING = originalEnv;
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
describe('timingEnabled', () => {
|
|
14
|
+
it('returns false when ASH_DEBUG_TIMING is not set', () => {
|
|
15
|
+
delete process.env.ASH_DEBUG_TIMING;
|
|
16
|
+
expect(timingEnabled()).toBe(false);
|
|
17
|
+
});
|
|
18
|
+
it('returns false when ASH_DEBUG_TIMING is "0"', () => {
|
|
19
|
+
process.env.ASH_DEBUG_TIMING = '0';
|
|
20
|
+
expect(timingEnabled()).toBe(false);
|
|
21
|
+
});
|
|
22
|
+
it('returns true when ASH_DEBUG_TIMING is "1"', () => {
|
|
23
|
+
process.env.ASH_DEBUG_TIMING = '1';
|
|
24
|
+
expect(timingEnabled()).toBe(true);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
describe('startTimer', () => {
|
|
28
|
+
it('returns a function', () => {
|
|
29
|
+
const elapsed = startTimer();
|
|
30
|
+
expect(typeof elapsed).toBe('function');
|
|
31
|
+
});
|
|
32
|
+
it('returns elapsed time in milliseconds', () => {
|
|
33
|
+
const elapsed = startTimer();
|
|
34
|
+
// Spin briefly so elapsed > 0
|
|
35
|
+
const start = Date.now();
|
|
36
|
+
while (Date.now() - start < 5) {
|
|
37
|
+
// busy wait ~5ms
|
|
38
|
+
}
|
|
39
|
+
const ms = elapsed();
|
|
40
|
+
expect(ms).toBeGreaterThan(0);
|
|
41
|
+
expect(ms).toBeLessThan(1000); // sanity: less than 1 second
|
|
42
|
+
});
|
|
43
|
+
it('returns increasing values on successive calls', () => {
|
|
44
|
+
const elapsed = startTimer();
|
|
45
|
+
const first = elapsed();
|
|
46
|
+
// Tiny spin
|
|
47
|
+
const start = Date.now();
|
|
48
|
+
while (Date.now() - start < 2) {
|
|
49
|
+
// busy wait
|
|
50
|
+
}
|
|
51
|
+
const second = elapsed();
|
|
52
|
+
expect(second).toBeGreaterThan(first);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
describe('logTiming', () => {
|
|
56
|
+
let stderrWrite;
|
|
57
|
+
const calls = [];
|
|
58
|
+
beforeEach(() => {
|
|
59
|
+
calls.length = 0;
|
|
60
|
+
stderrWrite = process.stderr.write;
|
|
61
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
62
|
+
process.stderr.write = ((chunk) => {
|
|
63
|
+
calls.push(String(chunk));
|
|
64
|
+
return true;
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
afterEach(() => {
|
|
68
|
+
process.stderr.write = stderrWrite;
|
|
69
|
+
});
|
|
70
|
+
it('writes JSON line to stderr when enabled', () => {
|
|
71
|
+
process.env.ASH_DEBUG_TIMING = '1';
|
|
72
|
+
const entry = {
|
|
73
|
+
type: 'timing',
|
|
74
|
+
source: 'server',
|
|
75
|
+
sessionId: 's1',
|
|
76
|
+
lookupMs: 0.1,
|
|
77
|
+
timestamp: '2025-01-15T00:00:00.000Z',
|
|
78
|
+
};
|
|
79
|
+
logTiming(entry);
|
|
80
|
+
expect(calls.length).toBe(1);
|
|
81
|
+
const written = calls[0];
|
|
82
|
+
expect(written).toMatch(/\n$/);
|
|
83
|
+
const parsed = JSON.parse(written.trim());
|
|
84
|
+
expect(parsed.type).toBe('timing');
|
|
85
|
+
expect(parsed.source).toBe('server');
|
|
86
|
+
expect(parsed.sessionId).toBe('s1');
|
|
87
|
+
expect(parsed.lookupMs).toBe(0.1);
|
|
88
|
+
});
|
|
89
|
+
it('is a no-op when disabled', () => {
|
|
90
|
+
delete process.env.ASH_DEBUG_TIMING;
|
|
91
|
+
logTiming({
|
|
92
|
+
type: 'timing',
|
|
93
|
+
source: 'bridge',
|
|
94
|
+
sessionId: 's1',
|
|
95
|
+
timestamp: '2025-01-15T00:00:00.000Z',
|
|
96
|
+
});
|
|
97
|
+
expect(calls.length).toBe(0);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
//# sourceMappingURL=timing.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timing.test.js","sourceRoot":"","sources":["../../src/__tests__/timing.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/types.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { extractStreamDelta, extractTextFromEvent } from '../types.js';
|
|
3
|
+
describe('extractStreamDelta', () => {
|
|
4
|
+
it('returns text from a text_delta stream event', () => {
|
|
5
|
+
const data = {
|
|
6
|
+
type: 'stream_event',
|
|
7
|
+
event: {
|
|
8
|
+
type: 'content_block_delta',
|
|
9
|
+
index: 0,
|
|
10
|
+
delta: { type: 'text_delta', text: 'Hello' },
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
expect(extractStreamDelta(data)).toBe('Hello');
|
|
14
|
+
});
|
|
15
|
+
it('returns null for non-stream_event messages', () => {
|
|
16
|
+
expect(extractStreamDelta({ type: 'assistant', message: { content: [] } })).toBeNull();
|
|
17
|
+
expect(extractStreamDelta({ type: 'result' })).toBeNull();
|
|
18
|
+
});
|
|
19
|
+
it('returns null for stream events that are not content_block_delta', () => {
|
|
20
|
+
expect(extractStreamDelta({ type: 'stream_event', event: { type: 'message_start' } })).toBeNull();
|
|
21
|
+
expect(extractStreamDelta({ type: 'stream_event', event: { type: 'content_block_stop' } })).toBeNull();
|
|
22
|
+
});
|
|
23
|
+
it('returns null for content_block_delta with non-text delta type', () => {
|
|
24
|
+
const data = {
|
|
25
|
+
type: 'stream_event',
|
|
26
|
+
event: {
|
|
27
|
+
type: 'content_block_delta',
|
|
28
|
+
index: 0,
|
|
29
|
+
delta: { type: 'input_json_delta', partial_json: '{"key":' },
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
expect(extractStreamDelta(data)).toBeNull();
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
describe('extractTextFromEvent', () => {
|
|
36
|
+
it('returns null for stream_event messages', () => {
|
|
37
|
+
const data = {
|
|
38
|
+
type: 'stream_event',
|
|
39
|
+
event: { type: 'content_block_delta', delta: { type: 'text_delta', text: 'hi' } },
|
|
40
|
+
};
|
|
41
|
+
expect(extractTextFromEvent(data)).toBeNull();
|
|
42
|
+
});
|
|
43
|
+
it('returns text from assistant messages', () => {
|
|
44
|
+
const data = {
|
|
45
|
+
type: 'assistant',
|
|
46
|
+
message: { content: [{ type: 'text', text: 'Hello world' }] },
|
|
47
|
+
};
|
|
48
|
+
expect(extractTextFromEvent(data)).toBe('Hello world');
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
//# sourceMappingURL=types.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.test.js","sourceRoot":"","sources":["../../src/__tests__/types.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAEvE,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,IAAI,GAAG;YACX,IAAI,EAAE,cAAc;YACpB,KAAK,EAAE;gBACL,IAAI,EAAE,qBAAqB;gBAC3B,KAAK,EAAE,CAAC;gBACR,KAAK,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,EAAE;aAC7C;SACF,CAAC;QACF,MAAM,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,CAAC,kBAAkB,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;QACvF,MAAM,CAAC,kBAAkB,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;QACzE,MAAM,CAAC,kBAAkB,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;QAClG,MAAM,CAAC,kBAAkB,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,oBAAoB,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IACzG,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+DAA+D,EAAE,GAAG,EAAE;QACvE,MAAM,IAAI,GAAG;YACX,IAAI,EAAE,cAAc;YACpB,KAAK,EAAE;gBACL,IAAI,EAAE,qBAAqB;gBAC3B,KAAK,EAAE,CAAC;gBACR,KAAK,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE,YAAY,EAAE,SAAS,EAAE;aAC7D;SACF,CAAC;QACF,MAAM,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC9C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,MAAM,IAAI,GAAG;YACX,IAAI,EAAE,cAAc;YACpB,KAAK,EAAE,EAAE,IAAI,EAAE,qBAAqB,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;SAClF,CAAC;QACF,MAAM,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,IAAI,GAAG;YACX,IAAI,EAAE,WAAW;YACjB,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,EAAE;SAC9D,CAAC;QACF,MAAM,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export declare const DEFAULT_PORT = 4100;
|
|
2
|
+
export declare const DEFAULT_HOST = "0.0.0.0";
|
|
3
|
+
export declare const DEFAULT_DATA_DIR = "data";
|
|
4
|
+
export declare const SANDBOX_CONNECT_TIMEOUT_MS = 10000;
|
|
5
|
+
export declare const SANDBOX_SHUTDOWN_TIMEOUT_MS = 5000;
|
|
6
|
+
export declare const BRIDGE_READY_TIMEOUT_MS = 10000;
|
|
7
|
+
export declare const INSTALL_SCRIPT_TIMEOUT_MS = 120000;
|
|
8
|
+
export declare const DEFAULT_SANDBOX_LIMITS: {
|
|
9
|
+
readonly memoryMb: 2048;
|
|
10
|
+
readonly cpuPercent: 100;
|
|
11
|
+
readonly diskMb: 1024;
|
|
12
|
+
readonly maxProcesses: 64;
|
|
13
|
+
};
|
|
14
|
+
export declare const DISK_CHECK_INTERVAL_MS = 30000;
|
|
15
|
+
export declare const SSE_WRITE_TIMEOUT_MS = 30000;
|
|
16
|
+
export declare const SANDBOX_DOCKER_IMAGE = "node:20-slim";
|
|
17
|
+
export declare const ASH_CONTAINER_NAME = "ash-server";
|
|
18
|
+
export declare const ASH_DOCKER_IMAGE = "ghcr.io/ash-ai/ash";
|
|
19
|
+
export declare const ASH_DOCKER_TAG = "0.1.0";
|
|
20
|
+
export declare const ASH_DATA_DIR_CONTAINER = "/data";
|
|
21
|
+
export declare const ASH_AGENTS_SUBDIR = "agents";
|
|
22
|
+
export declare const ASH_HEALTH_POLL_INTERVAL_MS = 500;
|
|
23
|
+
export declare const ASH_HEALTH_POLL_TIMEOUT_MS = 30000;
|
|
24
|
+
export declare const DEFAULT_MAX_SANDBOXES = 1000;
|
|
25
|
+
export declare const DEFAULT_IDLE_TIMEOUT_MS: number;
|
|
26
|
+
export declare const IDLE_SWEEP_INTERVAL_MS = 60000;
|
|
27
|
+
export declare const DEFAULT_RUNNER_PORT = 4200;
|
|
28
|
+
export declare const RUNNER_HEARTBEAT_INTERVAL_MS = 10000;
|
|
29
|
+
export declare const RUNNER_LIVENESS_TIMEOUT_MS = 30000;
|
|
30
|
+
export declare const SANDBOX_ENV_ALLOWLIST: readonly ["PATH", "NODE_PATH", "HOME", "LANG", "TERM", "ANTHROPIC_API_KEY", "ASH_DEBUG_TIMING", "ASH_REAL_SDK", "CLAUDE_CODE_EXECUTABLE"];
|
|
31
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,YAAY,OAAO,CAAC;AACjC,eAAO,MAAM,YAAY,YAAY,CAAC;AACtC,eAAO,MAAM,gBAAgB,SAAS,CAAC;AAGvC,eAAO,MAAM,0BAA0B,QAAS,CAAC;AACjD,eAAO,MAAM,2BAA2B,OAAQ,CAAC;AAGjD,eAAO,MAAM,uBAAuB,QAAS,CAAC;AAG9C,eAAO,MAAM,yBAAyB,SAAU,CAAC;AAGjD,eAAO,MAAM,sBAAsB;;;;;CAKzB,CAAC;AAEX,eAAO,MAAM,sBAAsB,QAAS,CAAC;AAG7C,eAAO,MAAM,oBAAoB,QAAS,CAAC;AAG3C,eAAO,MAAM,oBAAoB,iBAAiB,CAAC;AAGnD,eAAO,MAAM,kBAAkB,eAAe,CAAC;AAC/C,eAAO,MAAM,gBAAgB,uBAAuB,CAAC;AACrD,eAAO,MAAM,cAAc,UAAU,CAAC;AACtC,eAAO,MAAM,sBAAsB,UAAU,CAAC;AAC9C,eAAO,MAAM,iBAAiB,WAAW,CAAC;AAC1C,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAC/C,eAAO,MAAM,0BAA0B,QAAS,CAAC;AAGjD,eAAO,MAAM,qBAAqB,OAAO,CAAC;AAC1C,eAAO,MAAM,uBAAuB,QAAiB,CAAC;AACtD,eAAO,MAAM,sBAAsB,QAAS,CAAC;AAG7C,eAAO,MAAM,mBAAmB,OAAO,CAAC;AACxC,eAAO,MAAM,4BAA4B,QAAS,CAAC;AACnD,eAAO,MAAM,0BAA0B,QAAS,CAAC;AAGjD,eAAO,MAAM,qBAAqB,2IAUxB,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export const DEFAULT_PORT = 4100;
|
|
2
|
+
export const DEFAULT_HOST = '0.0.0.0';
|
|
3
|
+
export const DEFAULT_DATA_DIR = 'data';
|
|
4
|
+
// Sandbox
|
|
5
|
+
export const SANDBOX_CONNECT_TIMEOUT_MS = 10_000;
|
|
6
|
+
export const SANDBOX_SHUTDOWN_TIMEOUT_MS = 5_000;
|
|
7
|
+
// Bridge
|
|
8
|
+
export const BRIDGE_READY_TIMEOUT_MS = 10_000;
|
|
9
|
+
// Agent setup
|
|
10
|
+
export const INSTALL_SCRIPT_TIMEOUT_MS = 120_000; // 2 min
|
|
11
|
+
// Resource limits
|
|
12
|
+
export const DEFAULT_SANDBOX_LIMITS = {
|
|
13
|
+
memoryMb: 2048,
|
|
14
|
+
cpuPercent: 100,
|
|
15
|
+
diskMb: 1024,
|
|
16
|
+
maxProcesses: 64,
|
|
17
|
+
};
|
|
18
|
+
export const DISK_CHECK_INTERVAL_MS = 30_000;
|
|
19
|
+
// Backpressure
|
|
20
|
+
export const SSE_WRITE_TIMEOUT_MS = 30_000;
|
|
21
|
+
// Docker sandbox image
|
|
22
|
+
export const SANDBOX_DOCKER_IMAGE = 'node:20-slim';
|
|
23
|
+
// Docker lifecycle (ash start/stop)
|
|
24
|
+
export const ASH_CONTAINER_NAME = 'ash-server';
|
|
25
|
+
export const ASH_DOCKER_IMAGE = 'ghcr.io/ash-ai/ash';
|
|
26
|
+
export const ASH_DOCKER_TAG = '0.1.0';
|
|
27
|
+
export const ASH_DATA_DIR_CONTAINER = '/data';
|
|
28
|
+
export const ASH_AGENTS_SUBDIR = 'agents';
|
|
29
|
+
export const ASH_HEALTH_POLL_INTERVAL_MS = 500;
|
|
30
|
+
export const ASH_HEALTH_POLL_TIMEOUT_MS = 30_000;
|
|
31
|
+
// Sandbox pool
|
|
32
|
+
export const DEFAULT_MAX_SANDBOXES = 1000;
|
|
33
|
+
export const DEFAULT_IDLE_TIMEOUT_MS = 30 * 60 * 1000; // 30 min
|
|
34
|
+
export const IDLE_SWEEP_INTERVAL_MS = 60_000; // 1 min
|
|
35
|
+
// Runner (multi-machine mode)
|
|
36
|
+
export const DEFAULT_RUNNER_PORT = 4200;
|
|
37
|
+
export const RUNNER_HEARTBEAT_INTERVAL_MS = 10_000;
|
|
38
|
+
export const RUNNER_LIVENESS_TIMEOUT_MS = 30_000;
|
|
39
|
+
// Env vars allowed into sandbox processes (allowlist — nothing else leaks)
|
|
40
|
+
export const SANDBOX_ENV_ALLOWLIST = [
|
|
41
|
+
'PATH',
|
|
42
|
+
'NODE_PATH',
|
|
43
|
+
'HOME',
|
|
44
|
+
'LANG',
|
|
45
|
+
'TERM',
|
|
46
|
+
'ANTHROPIC_API_KEY',
|
|
47
|
+
'ASH_DEBUG_TIMING',
|
|
48
|
+
'ASH_REAL_SDK',
|
|
49
|
+
'CLAUDE_CODE_EXECUTABLE',
|
|
50
|
+
];
|
|
51
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,CAAC;AACjC,MAAM,CAAC,MAAM,YAAY,GAAG,SAAS,CAAC;AACtC,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAEvC,UAAU;AACV,MAAM,CAAC,MAAM,0BAA0B,GAAG,MAAM,CAAC;AACjD,MAAM,CAAC,MAAM,2BAA2B,GAAG,KAAK,CAAC;AAEjD,SAAS;AACT,MAAM,CAAC,MAAM,uBAAuB,GAAG,MAAM,CAAC;AAE9C,cAAc;AACd,MAAM,CAAC,MAAM,yBAAyB,GAAG,OAAO,CAAC,CAAC,QAAQ;AAE1D,kBAAkB;AAClB,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,QAAQ,EAAE,IAAI;IACd,UAAU,EAAE,GAAG;IACf,MAAM,EAAE,IAAI;IACZ,YAAY,EAAE,EAAE;CACR,CAAC;AAEX,MAAM,CAAC,MAAM,sBAAsB,GAAG,MAAM,CAAC;AAE7C,eAAe;AACf,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC;AAE3C,uBAAuB;AACvB,MAAM,CAAC,MAAM,oBAAoB,GAAG,cAAc,CAAC;AAEnD,oCAAoC;AACpC,MAAM,CAAC,MAAM,kBAAkB,GAAG,YAAY,CAAC;AAC/C,MAAM,CAAC,MAAM,gBAAgB,GAAG,oBAAoB,CAAC;AACrD,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC;AACtC,MAAM,CAAC,MAAM,sBAAsB,GAAG,OAAO,CAAC;AAC9C,MAAM,CAAC,MAAM,iBAAiB,GAAG,QAAQ,CAAC;AAC1C,MAAM,CAAC,MAAM,2BAA2B,GAAG,GAAG,CAAC;AAC/C,MAAM,CAAC,MAAM,0BAA0B,GAAG,MAAM,CAAC;AAEjD,eAAe;AACf,MAAM,CAAC,MAAM,qBAAqB,GAAG,IAAI,CAAC;AAC1C,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAE,SAAS;AACjE,MAAM,CAAC,MAAM,sBAAsB,GAAG,MAAM,CAAC,CAAY,QAAQ;AAEjE,8BAA8B;AAC9B,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,CAAC;AACxC,MAAM,CAAC,MAAM,4BAA4B,GAAG,MAAM,CAAC;AACnD,MAAM,CAAC,MAAM,0BAA0B,GAAG,MAAM,CAAC;AAEjD,2EAA2E;AAC3E,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,MAAM;IACN,WAAW;IACX,MAAM;IACN,MAAM;IACN,MAAM;IACN,mBAAmB;IACnB,kBAAkB;IAClB,cAAc;IACd,wBAAwB;CAChB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface QueryCommand {
|
|
2
|
+
cmd: 'query';
|
|
3
|
+
prompt: string;
|
|
4
|
+
sessionId: string;
|
|
5
|
+
includePartialMessages?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface ResumeCommand {
|
|
8
|
+
cmd: 'resume';
|
|
9
|
+
sessionId: string;
|
|
10
|
+
}
|
|
11
|
+
export interface InterruptCommand {
|
|
12
|
+
cmd: 'interrupt';
|
|
13
|
+
}
|
|
14
|
+
export interface ShutdownCommand {
|
|
15
|
+
cmd: 'shutdown';
|
|
16
|
+
}
|
|
17
|
+
export type BridgeCommand = QueryCommand | ResumeCommand | InterruptCommand | ShutdownCommand;
|
|
18
|
+
export interface ReadyEvent {
|
|
19
|
+
ev: 'ready';
|
|
20
|
+
}
|
|
21
|
+
export interface MessageEvent {
|
|
22
|
+
ev: 'message';
|
|
23
|
+
data: unknown;
|
|
24
|
+
}
|
|
25
|
+
export interface ErrorEvent {
|
|
26
|
+
ev: 'error';
|
|
27
|
+
error: string;
|
|
28
|
+
}
|
|
29
|
+
export interface DoneEvent {
|
|
30
|
+
ev: 'done';
|
|
31
|
+
sessionId: string;
|
|
32
|
+
}
|
|
33
|
+
export type BridgeEvent = ReadyEvent | MessageEvent | ErrorEvent | DoneEvent;
|
|
34
|
+
export declare function encode(msg: BridgeCommand | BridgeEvent): string;
|
|
35
|
+
export declare function decode(line: string): BridgeCommand | BridgeEvent;
|
|
36
|
+
//# sourceMappingURL=protocol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,QAAQ,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,WAAW,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,UAAU,CAAC;CACjB;AAED,MAAM,MAAM,aAAa,GACrB,YAAY,GACZ,aAAa,GACb,gBAAgB,GAChB,eAAe,CAAC;AAMpB,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,OAAO,CAAC;CACb;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,SAAS,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,WAAW,GACnB,UAAU,GACV,YAAY,GACZ,UAAU,GACV,SAAS,CAAC;AAId,wBAAgB,MAAM,CAAC,GAAG,EAAE,aAAa,GAAG,WAAW,GAAG,MAAM,CAE/D;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,WAAW,CAEhE"}
|
package/dist/protocol.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// Bridge protocol: communication between server host and bridge process inside
|
|
3
|
+
// sandbox. Newline-delimited JSON over Unix socket.
|
|
4
|
+
//
|
|
5
|
+
// SDK message passthrough: bridge events carry raw SDK Message objects (from
|
|
6
|
+
// @anthropic-ai/claude-code) as opaque JSON. We do NOT define our own message
|
|
7
|
+
// types — the SDK's types are the contract. See CLAUDE.md principle 8.
|
|
8
|
+
// =============================================================================
|
|
9
|
+
// -- Wire encoding/decoding ---------------------------------------------------
|
|
10
|
+
export function encode(msg) {
|
|
11
|
+
return JSON.stringify(msg) + '\n';
|
|
12
|
+
}
|
|
13
|
+
export function decode(line) {
|
|
14
|
+
return JSON.parse(line.trim());
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=protocol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,+EAA+E;AAC/E,oDAAoD;AACpD,EAAE;AACF,6EAA6E;AAC7E,8EAA8E;AAC9E,uEAAuE;AACvE,gFAAgF;AA2DhF,gFAAgF;AAEhF,MAAM,UAAU,MAAM,CAAC,GAAgC;IACrD,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,IAAY;IACjC,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;AACjC,CAAC"}
|
package/dist/timing.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface TimingEntry {
|
|
2
|
+
type: 'timing';
|
|
3
|
+
source: 'server' | 'bridge';
|
|
4
|
+
sessionId: string;
|
|
5
|
+
[key: string]: unknown;
|
|
6
|
+
timestamp: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Returns true when timing instrumentation is enabled.
|
|
10
|
+
*/
|
|
11
|
+
export declare function timingEnabled(): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Returns a function that, when called, returns elapsed milliseconds
|
|
14
|
+
* since `startTimer()` was invoked. Uses `process.hrtime.bigint()` for
|
|
15
|
+
* sub-millisecond precision.
|
|
16
|
+
*/
|
|
17
|
+
export declare function startTimer(): () => number;
|
|
18
|
+
/**
|
|
19
|
+
* Writes a TimingEntry as a single JSON line to stderr.
|
|
20
|
+
* No-op if timing is disabled.
|
|
21
|
+
*/
|
|
22
|
+
export declare function logTiming(entry: TimingEntry): void;
|
|
23
|
+
//# sourceMappingURL=timing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timing.d.ts","sourceRoot":"","sources":["../src/timing.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAEvC;AAED;;;;GAIG;AACH,wBAAgB,UAAU,IAAI,MAAM,MAAM,CAGzC;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAGlD"}
|
package/dist/timing.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// Lightweight hot-path timing instrumentation.
|
|
3
|
+
// Gated behind ASH_DEBUG_TIMING=1. Zero overhead when off.
|
|
4
|
+
// Output: one JSON line per message to stderr.
|
|
5
|
+
// =============================================================================
|
|
6
|
+
/**
|
|
7
|
+
* Returns true when timing instrumentation is enabled.
|
|
8
|
+
*/
|
|
9
|
+
export function timingEnabled() {
|
|
10
|
+
return process.env.ASH_DEBUG_TIMING === '1';
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Returns a function that, when called, returns elapsed milliseconds
|
|
14
|
+
* since `startTimer()` was invoked. Uses `process.hrtime.bigint()` for
|
|
15
|
+
* sub-millisecond precision.
|
|
16
|
+
*/
|
|
17
|
+
export function startTimer() {
|
|
18
|
+
const start = process.hrtime.bigint();
|
|
19
|
+
return () => Number(process.hrtime.bigint() - start) / 1_000_000;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Writes a TimingEntry as a single JSON line to stderr.
|
|
23
|
+
* No-op if timing is disabled.
|
|
24
|
+
*/
|
|
25
|
+
export function logTiming(entry) {
|
|
26
|
+
if (!timingEnabled())
|
|
27
|
+
return;
|
|
28
|
+
process.stderr.write(JSON.stringify(entry) + '\n');
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=timing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timing.js","sourceRoot":"","sources":["../src/timing.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,+CAA+C;AAC/C,2DAA2D;AAC3D,+CAA+C;AAC/C,gFAAgF;AAUhF;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO,OAAO,CAAC,GAAG,CAAC,gBAAgB,KAAK,GAAG,CAAC;AAC9C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU;IACxB,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;IACtC,OAAO,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,GAAG,SAAS,CAAC;AACnE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,KAAkB;IAC1C,IAAI,CAAC,aAAa,EAAE;QAAE,OAAO;IAC7B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC;AACrD,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
export interface Agent {
|
|
2
|
+
name: string;
|
|
3
|
+
version: number;
|
|
4
|
+
path: string;
|
|
5
|
+
createdAt: string;
|
|
6
|
+
updatedAt: string;
|
|
7
|
+
}
|
|
8
|
+
export type SessionStatus = 'starting' | 'active' | 'paused' | 'ended' | 'error';
|
|
9
|
+
export interface Session {
|
|
10
|
+
id: string;
|
|
11
|
+
agentName: string;
|
|
12
|
+
sandboxId: string;
|
|
13
|
+
status: SessionStatus;
|
|
14
|
+
createdAt: string;
|
|
15
|
+
lastActiveAt: string;
|
|
16
|
+
/** Runner that owns this session's sandbox. Null in standalone mode. */
|
|
17
|
+
runnerId?: string | null;
|
|
18
|
+
}
|
|
19
|
+
export type SandboxState = 'cold' | 'warming' | 'warm' | 'waiting' | 'running';
|
|
20
|
+
export interface SandboxInfo {
|
|
21
|
+
id: string;
|
|
22
|
+
pid: number | null;
|
|
23
|
+
state: SandboxState;
|
|
24
|
+
socketPath: string;
|
|
25
|
+
workspaceDir: string;
|
|
26
|
+
createdAt: string;
|
|
27
|
+
}
|
|
28
|
+
export interface SandboxRecord {
|
|
29
|
+
id: string;
|
|
30
|
+
sessionId: string | null;
|
|
31
|
+
agentName: string;
|
|
32
|
+
state: SandboxState;
|
|
33
|
+
workspaceDir: string;
|
|
34
|
+
createdAt: string;
|
|
35
|
+
lastUsedAt: string;
|
|
36
|
+
}
|
|
37
|
+
export interface PoolStats {
|
|
38
|
+
total: number;
|
|
39
|
+
cold: number;
|
|
40
|
+
warming: number;
|
|
41
|
+
warm: number;
|
|
42
|
+
waiting: number;
|
|
43
|
+
running: number;
|
|
44
|
+
maxCapacity: number;
|
|
45
|
+
resumeWarmHits: number;
|
|
46
|
+
resumeColdHits: number;
|
|
47
|
+
}
|
|
48
|
+
export interface SandboxLimits {
|
|
49
|
+
memoryMb: number;
|
|
50
|
+
cpuPercent: number;
|
|
51
|
+
diskMb: number;
|
|
52
|
+
maxProcesses: number;
|
|
53
|
+
}
|
|
54
|
+
export interface FileEntry {
|
|
55
|
+
path: string;
|
|
56
|
+
size: number;
|
|
57
|
+
modifiedAt: string;
|
|
58
|
+
}
|
|
59
|
+
export interface ListFilesResponse {
|
|
60
|
+
files: FileEntry[];
|
|
61
|
+
/** Where the file listing was read from: 'sandbox' (live) or 'snapshot' (persisted). */
|
|
62
|
+
source: 'sandbox' | 'snapshot';
|
|
63
|
+
}
|
|
64
|
+
export interface GetFileResponse {
|
|
65
|
+
path: string;
|
|
66
|
+
content: string;
|
|
67
|
+
size: number;
|
|
68
|
+
source: 'sandbox' | 'snapshot';
|
|
69
|
+
}
|
|
70
|
+
export interface CreateSessionRequest {
|
|
71
|
+
agent: string;
|
|
72
|
+
}
|
|
73
|
+
export interface CreateSessionResponse {
|
|
74
|
+
session: Session;
|
|
75
|
+
}
|
|
76
|
+
export interface SendMessageRequest {
|
|
77
|
+
content: string;
|
|
78
|
+
/** Enable partial message streaming. When true, yields incremental StreamEvent messages with raw API deltas in addition to complete messages. */
|
|
79
|
+
includePartialMessages?: boolean;
|
|
80
|
+
}
|
|
81
|
+
export interface DeployAgentRequest {
|
|
82
|
+
name: string;
|
|
83
|
+
path: string;
|
|
84
|
+
}
|
|
85
|
+
export interface ListAgentsResponse {
|
|
86
|
+
agents: Agent[];
|
|
87
|
+
}
|
|
88
|
+
export interface ListSessionsResponse {
|
|
89
|
+
sessions: Session[];
|
|
90
|
+
}
|
|
91
|
+
export interface HealthResponse {
|
|
92
|
+
status: 'ok';
|
|
93
|
+
activeSessions: number;
|
|
94
|
+
activeSandboxes: number;
|
|
95
|
+
uptime: number;
|
|
96
|
+
pool: PoolStats;
|
|
97
|
+
}
|
|
98
|
+
export interface ApiError {
|
|
99
|
+
error: string;
|
|
100
|
+
statusCode: number;
|
|
101
|
+
}
|
|
102
|
+
export type AshSSEEventType = 'message' | 'error' | 'done';
|
|
103
|
+
export interface AshMessageEvent {
|
|
104
|
+
type: 'message';
|
|
105
|
+
data: Record<string, any>;
|
|
106
|
+
}
|
|
107
|
+
export interface AshErrorEvent {
|
|
108
|
+
type: 'error';
|
|
109
|
+
data: {
|
|
110
|
+
error: string;
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
export interface AshDoneEvent {
|
|
114
|
+
type: 'done';
|
|
115
|
+
data: {
|
|
116
|
+
sessionId: string;
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
export type AshStreamEvent = AshMessageEvent | AshErrorEvent | AshDoneEvent;
|
|
120
|
+
export type DisplayItemType = 'text' | 'tool_use' | 'tool_result';
|
|
121
|
+
export interface DisplayItem {
|
|
122
|
+
type: DisplayItemType;
|
|
123
|
+
/** For text: the text content. For tool_use: tool name. For tool_result: output. */
|
|
124
|
+
content: string;
|
|
125
|
+
/** Tool name (tool_use and tool_result only) */
|
|
126
|
+
toolName?: string;
|
|
127
|
+
/** Abbreviated tool input (tool_use only) */
|
|
128
|
+
toolInput?: string;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Extract display items from an SDK message event's data.
|
|
132
|
+
* Returns structured items for text, tool use, and tool results.
|
|
133
|
+
* Returns null for messages that shouldn't be displayed (system, result).
|
|
134
|
+
*/
|
|
135
|
+
export declare function extractDisplayItems(data: Record<string, any>): DisplayItem[] | null;
|
|
136
|
+
/**
|
|
137
|
+
* Simple text-only extraction for consumers that just want a string.
|
|
138
|
+
* Extracts text content from assistant messages, ignores tools and results.
|
|
139
|
+
*/
|
|
140
|
+
export declare function extractTextFromEvent(data: Record<string, any>): string | null;
|
|
141
|
+
/**
|
|
142
|
+
* Extract a text delta from an SDK StreamEvent message.
|
|
143
|
+
* Returns the incremental text chunk from `content_block_delta` events with `text_delta`,
|
|
144
|
+
* or null for any other event type. Use this to build real-time streaming UIs.
|
|
145
|
+
*
|
|
146
|
+
* Only yields values when `includePartialMessages` is enabled on the request.
|
|
147
|
+
*/
|
|
148
|
+
export declare function extractStreamDelta(data: Record<string, any>): string | null;
|
|
149
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// Ash-specific types. These are for orchestration concerns that Ash owns.
|
|
3
|
+
// Conversation/message types come from @anthropic-ai/claude-code — see protocol.ts.
|
|
4
|
+
// =============================================================================
|
|
5
|
+
/**
|
|
6
|
+
* Extract display items from an SDK message event's data.
|
|
7
|
+
* Returns structured items for text, tool use, and tool results.
|
|
8
|
+
* Returns null for messages that shouldn't be displayed (system, result).
|
|
9
|
+
*/
|
|
10
|
+
export function extractDisplayItems(data) {
|
|
11
|
+
// Assistant message with content blocks
|
|
12
|
+
if (data.type === 'assistant' && data.message?.content) {
|
|
13
|
+
const content = data.message.content;
|
|
14
|
+
if (!Array.isArray(content))
|
|
15
|
+
return null;
|
|
16
|
+
const items = [];
|
|
17
|
+
for (const block of content) {
|
|
18
|
+
if (block.type === 'text') {
|
|
19
|
+
items.push({ type: 'text', content: block.text });
|
|
20
|
+
}
|
|
21
|
+
else if (block.type === 'tool_use') {
|
|
22
|
+
const inputStr = block.input
|
|
23
|
+
? Object.entries(block.input)
|
|
24
|
+
.map(([k, v]) => `${k}: ${typeof v === 'string' ? v : JSON.stringify(v)}`)
|
|
25
|
+
.join(', ')
|
|
26
|
+
: '';
|
|
27
|
+
items.push({
|
|
28
|
+
type: 'tool_use',
|
|
29
|
+
content: block.name,
|
|
30
|
+
toolName: block.name,
|
|
31
|
+
toolInput: inputStr.length > 200 ? inputStr.slice(0, 200) + '...' : inputStr,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return items.length > 0 ? items : null;
|
|
36
|
+
}
|
|
37
|
+
// Tool result message
|
|
38
|
+
if (data.type === 'user' && data.tool_use_result) {
|
|
39
|
+
const r = data.tool_use_result;
|
|
40
|
+
const output = (r.stdout || '') + (r.stderr ? `\n${r.stderr}` : '');
|
|
41
|
+
if (!output.trim())
|
|
42
|
+
return null;
|
|
43
|
+
return [{
|
|
44
|
+
type: 'tool_result',
|
|
45
|
+
content: output.length > 1000 ? output.slice(0, 1000) + '\n...' : output,
|
|
46
|
+
}];
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Simple text-only extraction for consumers that just want a string.
|
|
52
|
+
* Extracts text content from assistant messages, ignores tools and results.
|
|
53
|
+
*/
|
|
54
|
+
export function extractTextFromEvent(data) {
|
|
55
|
+
if (data.type === 'assistant' && data.message?.content) {
|
|
56
|
+
const content = data.message.content;
|
|
57
|
+
if (typeof content === 'string')
|
|
58
|
+
return content;
|
|
59
|
+
if (Array.isArray(content)) {
|
|
60
|
+
const text = content
|
|
61
|
+
.filter((block) => block.type === 'text')
|
|
62
|
+
.map((block) => block.text)
|
|
63
|
+
.join('');
|
|
64
|
+
return text || null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Extract a text delta from an SDK StreamEvent message.
|
|
71
|
+
* Returns the incremental text chunk from `content_block_delta` events with `text_delta`,
|
|
72
|
+
* or null for any other event type. Use this to build real-time streaming UIs.
|
|
73
|
+
*
|
|
74
|
+
* Only yields values when `includePartialMessages` is enabled on the request.
|
|
75
|
+
*/
|
|
76
|
+
export function extractStreamDelta(data) {
|
|
77
|
+
if (data.type !== 'stream_event')
|
|
78
|
+
return null;
|
|
79
|
+
const event = data.event;
|
|
80
|
+
if (!event || event.type !== 'content_block_delta')
|
|
81
|
+
return null;
|
|
82
|
+
const delta = event.delta;
|
|
83
|
+
if (!delta || delta.type !== 'text_delta')
|
|
84
|
+
return null;
|
|
85
|
+
return delta.text ?? null;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ash-ai/shared",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "https://github.com/ash-ai/ash.git",
|
|
22
|
+
"directory": "packages/shared"
|
|
23
|
+
},
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"description": "Shared types, protocol, and constants for the Ash agent orchestration system",
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsc",
|
|
28
|
+
"clean": "rm -rf dist *.tsbuildinfo",
|
|
29
|
+
"typecheck": "tsc --noEmit",
|
|
30
|
+
"test": "vitest run"
|
|
31
|
+
}
|
|
32
|
+
}
|