agent-common 1.0.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.
Files changed (48) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/LICENSE +21 -0
  3. package/README.md +23 -0
  4. package/dist/dashboard.d.ts +29 -0
  5. package/dist/dashboard.d.ts.map +1 -0
  6. package/dist/dashboard.js +71 -0
  7. package/dist/dashboard.js.map +1 -0
  8. package/dist/domain/cleanup.d.ts +30 -0
  9. package/dist/domain/cleanup.d.ts.map +1 -0
  10. package/dist/domain/cleanup.js +54 -0
  11. package/dist/domain/cleanup.js.map +1 -0
  12. package/dist/domain/events.d.ts +13 -0
  13. package/dist/domain/events.d.ts.map +1 -0
  14. package/dist/domain/events.js +61 -0
  15. package/dist/domain/events.js.map +1 -0
  16. package/dist/index.d.ts +11 -0
  17. package/dist/index.d.ts.map +1 -0
  18. package/dist/index.js +14 -0
  19. package/dist/index.js.map +1 -0
  20. package/dist/package-meta.d.ts +22 -0
  21. package/dist/package-meta.d.ts.map +1 -0
  22. package/dist/package-meta.js +48 -0
  23. package/dist/package-meta.js.map +1 -0
  24. package/dist/storage/database.d.ts +27 -0
  25. package/dist/storage/database.d.ts.map +1 -0
  26. package/dist/storage/database.js +73 -0
  27. package/dist/storage/database.js.map +1 -0
  28. package/dist/storage/fts.d.ts +27 -0
  29. package/dist/storage/fts.d.ts.map +1 -0
  30. package/dist/storage/fts.js +57 -0
  31. package/dist/storage/fts.js.map +1 -0
  32. package/dist/transport/mcp.d.ts +16 -0
  33. package/dist/transport/mcp.d.ts.map +1 -0
  34. package/dist/transport/mcp.js +111 -0
  35. package/dist/transport/mcp.js.map +1 -0
  36. package/dist/transport/rest.d.ts +18 -0
  37. package/dist/transport/rest.d.ts.map +1 -0
  38. package/dist/transport/rest.js +185 -0
  39. package/dist/transport/rest.js.map +1 -0
  40. package/dist/transport/ws.d.ts +28 -0
  41. package/dist/transport/ws.d.ts.map +1 -0
  42. package/dist/transport/ws.js +143 -0
  43. package/dist/transport/ws.js.map +1 -0
  44. package/dist/types.d.ts +33 -0
  45. package/dist/types.d.ts.map +1 -0
  46. package/dist/types.js +26 -0
  47. package/dist/types.js.map +1 -0
  48. package/package.json +71 -0
@@ -0,0 +1,57 @@
1
+ // =============================================================================
2
+ // agent-kit — FTS5 helpers
3
+ //
4
+ // Boilerplate for creating an FTS5 virtual table mirroring a content table,
5
+ // with insert/update/delete triggers, and a search helper that falls back to
6
+ // LIKE if the FTS query fails (e.g. on malformed user input).
7
+ // =============================================================================
8
+ /** Create an FTS5 virtual table + insert/update/delete triggers idempotently. */
9
+ export function createFtsTable(db, opts) {
10
+ const { ftsTable, contentTable, column } = opts;
11
+ db.raw.exec(`
12
+ CREATE VIRTUAL TABLE IF NOT EXISTS ${ftsTable} USING fts5(
13
+ ${column},
14
+ content=${contentTable},
15
+ content_rowid=id
16
+ );
17
+
18
+ CREATE TRIGGER IF NOT EXISTS ${ftsTable}_insert AFTER INSERT ON ${contentTable} BEGIN
19
+ INSERT INTO ${ftsTable}(rowid, ${column}) VALUES (new.id, new.${column});
20
+ END;
21
+
22
+ CREATE TRIGGER IF NOT EXISTS ${ftsTable}_update AFTER UPDATE OF ${column} ON ${contentTable} BEGIN
23
+ INSERT INTO ${ftsTable}(${ftsTable}, rowid, ${column}) VALUES ('delete', old.id, old.${column});
24
+ INSERT INTO ${ftsTable}(rowid, ${column}) VALUES (new.id, new.${column});
25
+ END;
26
+
27
+ CREATE TRIGGER IF NOT EXISTS ${ftsTable}_delete AFTER DELETE ON ${contentTable} BEGIN
28
+ INSERT INTO ${ftsTable}(${ftsTable}, rowid, ${column}) VALUES ('delete', old.id, old.${column});
29
+ END;
30
+ `);
31
+ }
32
+ /**
33
+ * FTS5 MATCH search with LIKE fallback. Returns matching content rows.
34
+ * If the FTS query parses incorrectly, falls back to a LIKE wildcard scan.
35
+ */
36
+ export function ftsSearch(db, opts) {
37
+ const { ftsTable, contentTable, column, query, limit = 20, extraWhere, extraParams } = opts;
38
+ const limitClause = `LIMIT ${Math.max(1, Math.min(500, limit))}`;
39
+ const extra = extraWhere ? ` AND ${extraWhere}` : '';
40
+ const params = [query, ...(extraParams ?? [])];
41
+ try {
42
+ return db.queryAll(`SELECT ${contentTable}.* FROM ${contentTable}
43
+ JOIN ${ftsTable} ON ${ftsTable}.rowid = ${contentTable}.id
44
+ WHERE ${ftsTable} MATCH ?${extra}
45
+ ORDER BY ${contentTable}.id DESC
46
+ ${limitClause}`, params);
47
+ }
48
+ catch {
49
+ const likeParam = `%${query}%`;
50
+ const fallbackParams = [likeParam, ...(extraParams ?? [])];
51
+ return db.queryAll(`SELECT * FROM ${contentTable}
52
+ WHERE ${column} LIKE ?${extra}
53
+ ORDER BY id DESC
54
+ ${limitClause}`, fallbackParams);
55
+ }
56
+ }
57
+ //# sourceMappingURL=fts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fts.js","sourceRoot":"","sources":["../../src/storage/fts.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,2BAA2B;AAC3B,EAAE;AACF,4EAA4E;AAC5E,6EAA6E;AAC7E,8DAA8D;AAC9D,gFAAgF;AAahF,iFAAiF;AACjF,MAAM,UAAU,cAAc,CAAC,EAAM,EAAE,IAAgB;IACrD,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAChD,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;yCAC2B,QAAQ;QACzC,MAAM;gBACE,YAAY;;;;mCAIO,QAAQ,2BAA2B,YAAY;oBAC9D,QAAQ,WAAW,MAAM,yBAAyB,MAAM;;;mCAGzC,QAAQ,2BAA2B,MAAM,OAAO,YAAY;oBAC3E,QAAQ,IAAI,QAAQ,YAAY,MAAM,mCAAmC,MAAM;oBAC/E,QAAQ,WAAW,MAAM,yBAAyB,MAAM;;;mCAGzC,QAAQ,2BAA2B,YAAY;oBAC9D,QAAQ,IAAI,QAAQ,YAAY,MAAM,mCAAmC,MAAM;;GAEhG,CAAC,CAAC;AACL,CAAC;AAaD;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAI,EAAM,EAAE,IAAsB;IACzD,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;IAC5F,MAAM,WAAW,GAAG,SAAS,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC;IACjE,MAAM,KAAK,GAAG,UAAU,CAAC,CAAC,CAAC,QAAQ,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACrD,MAAM,MAAM,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,CAAC;IAE/C,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,QAAQ,CAChB,UAAU,YAAY,WAAW,YAAY;cACrC,QAAQ,OAAO,QAAQ,YAAY,YAAY;eAC9C,QAAQ,WAAW,KAAK;kBACrB,YAAY;SACrB,WAAW,EAAE,EAChB,MAAM,CACP,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,SAAS,GAAG,IAAI,KAAK,GAAG,CAAC;QAC/B,MAAM,cAAc,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,CAAC;QAC3D,OAAO,EAAE,CAAC,QAAQ,CAChB,iBAAiB,YAAY;eACpB,MAAM,UAAU,KAAK;;SAE3B,WAAW,EAAE,EAChB,cAAc,CACf,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { ToolDefinition } from '../types.js';
2
+ export interface McpServerOptions {
3
+ serverInfo: {
4
+ name: string;
5
+ version: string;
6
+ };
7
+ tools: ToolDefinition[];
8
+ handleTool: (name: string, args: Record<string, unknown>) => unknown;
9
+ onInitialize?: () => void;
10
+ protocolVersion?: string;
11
+ }
12
+ export interface McpServerHandle {
13
+ close(): void;
14
+ }
15
+ export declare function startMcpServer(opts: McpServerOptions): McpServerHandle;
16
+ //# sourceMappingURL=mcp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../src/transport/mcp.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAmC,cAAc,EAAE,MAAM,aAAa,CAAC;AAEnF,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9C,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC;IACrE,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,IAAI,IAAI,CAAC;CACf;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,gBAAgB,GAAG,eAAe,CA6GtE"}
@@ -0,0 +1,111 @@
1
+ // =============================================================================
2
+ // agent-kit — MCP transport
3
+ //
4
+ // Generic JSON-RPC over stdio dispatcher. The consumer provides:
5
+ // - tools: ToolDefinition[]
6
+ // - handleTool(name, args): unknown (the per-tool dispatcher)
7
+ // - serverInfo: { name, version }
8
+ // - onInitialize(): optional hook (e.g. to start the dashboard)
9
+ // =============================================================================
10
+ import { createInterface } from 'readline';
11
+ import { KitError } from '../types.js';
12
+ export function startMcpServer(opts) {
13
+ const protocolVersion = opts.protocolVersion ?? '2024-11-05';
14
+ const capabilities = { tools: {} };
15
+ function writeResponse(response) {
16
+ process.stdout.write(JSON.stringify(response) + '\n');
17
+ }
18
+ function handleRequest(request) {
19
+ const { method, params, id } = request;
20
+ switch (method) {
21
+ case 'initialize':
22
+ if (opts.onInitialize) {
23
+ try {
24
+ opts.onInitialize();
25
+ }
26
+ catch (err) {
27
+ process.stderr.write('[agent-kit] onInitialize error: ' +
28
+ (err instanceof Error ? err.message : String(err)) +
29
+ '\n');
30
+ }
31
+ }
32
+ return {
33
+ jsonrpc: '2.0',
34
+ id,
35
+ result: {
36
+ protocolVersion,
37
+ serverInfo: opts.serverInfo,
38
+ capabilities,
39
+ },
40
+ };
41
+ case 'notifications/initialized':
42
+ return null;
43
+ case 'tools/list':
44
+ return { jsonrpc: '2.0', id, result: { tools: opts.tools } };
45
+ case 'tools/call': {
46
+ const toolName = String(params?.name ?? '');
47
+ const rawArgs = params?.arguments;
48
+ const toolArgs = typeof rawArgs === 'object' && rawArgs !== null && !Array.isArray(rawArgs)
49
+ ? rawArgs
50
+ : {};
51
+ try {
52
+ const result = opts.handleTool(toolName, toolArgs);
53
+ return {
54
+ jsonrpc: '2.0',
55
+ id,
56
+ result: {
57
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
58
+ },
59
+ };
60
+ }
61
+ catch (err) {
62
+ const message = err instanceof Error ? err.message : String(err);
63
+ const code = err instanceof KitError ? err.code : 'UNKNOWN_ERROR';
64
+ return {
65
+ jsonrpc: '2.0',
66
+ id,
67
+ result: {
68
+ content: [{ type: 'text', text: `Error [${code}]: ${message}` }],
69
+ isError: true,
70
+ },
71
+ };
72
+ }
73
+ }
74
+ case 'ping':
75
+ return { jsonrpc: '2.0', id, result: {} };
76
+ default:
77
+ return {
78
+ jsonrpc: '2.0',
79
+ id,
80
+ error: { code: -32601, message: `Method not found: ${method}` },
81
+ };
82
+ }
83
+ }
84
+ const rl = createInterface({ input: process.stdin, terminal: false });
85
+ rl.on('line', (line) => {
86
+ if (!line.trim())
87
+ return;
88
+ try {
89
+ const request = JSON.parse(line);
90
+ const response = handleRequest(request);
91
+ if (response)
92
+ writeResponse(response);
93
+ }
94
+ catch (err) {
95
+ process.stderr.write('[agent-kit] JSON-RPC parse error: ' +
96
+ (err instanceof Error ? err.message : String(err)) +
97
+ '\n');
98
+ writeResponse({
99
+ jsonrpc: '2.0',
100
+ id: null,
101
+ error: { code: -32700, message: 'Parse error' },
102
+ });
103
+ }
104
+ });
105
+ return {
106
+ close() {
107
+ rl.close();
108
+ },
109
+ };
110
+ }
111
+ //# sourceMappingURL=mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/transport/mcp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { IncomingMessage, ServerResponse } from 'http';
2
+ export declare const MIME_TYPES: Record<string, string>;
3
+ export type RouteHandler = (req: IncomingMessage, res: ServerResponse, params: Record<string, string>) => void | Promise<void>;
4
+ export interface Router {
5
+ route(method: string, path: string, handler: RouteHandler): void;
6
+ handle(req: IncomingMessage, res: ServerResponse): Promise<void>;
7
+ }
8
+ export interface RouterOptions {
9
+ /** Optional static directory to serve when no API route matches. */
10
+ staticDir?: string;
11
+ /** Logger for handler errors (default: process.stderr). */
12
+ logError?: (err: unknown) => void;
13
+ }
14
+ export declare function json(res: ServerResponse, data: unknown, status?: number): void;
15
+ export declare function readBody(req: IncomingMessage, maxBytes?: number): Promise<Record<string, unknown>>;
16
+ export declare function createRouter(options?: RouterOptions): Router;
17
+ export declare function serveStatic(res: ServerResponse, baseDir: string, pathname: string): void;
18
+ //# sourceMappingURL=rest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rest.d.ts","sourceRoot":"","sources":["../../src/transport/rest.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,MAAM,CAAC;AAK5D,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAQ7C,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,CACzB,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAC3B,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAS1B,MAAM,WAAW,MAAM;IACrB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;IACjE,MAAM,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAClE;AAED,MAAM,WAAW,aAAa;IAC5B,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;CACnC;AAED,wBAAgB,IAAI,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,SAAM,GAAG,IAAI,CAO3E;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,eAAe,EAAE,QAAQ,SAAY,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CA2BrG;AAED,wBAAgB,YAAY,CAAC,OAAO,GAAE,aAAkB,GAAG,MAAM,CAoEhE;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CA8DxF"}
@@ -0,0 +1,185 @@
1
+ // =============================================================================
2
+ // agent-kit — REST transport
3
+ //
4
+ // Lightweight HTTP router using only node:http. Provides:
5
+ // - route(method, path, handler) with :param matching
6
+ // - json() helper with CORS + nosniff headers
7
+ // - readBody() with size limit + JSON object validation
8
+ // - serveStatic() with traversal + symlink protection
9
+ // - createRouter() returns a request handler that dispatches routes
10
+ // and falls back to a static file root.
11
+ // =============================================================================
12
+ import { readFileSync, realpathSync } from 'fs';
13
+ import { join, extname, resolve } from 'path';
14
+ import { KitError, ValidationError } from '../types.js';
15
+ export const MIME_TYPES = {
16
+ '.html': 'text/html; charset=utf-8',
17
+ '.css': 'text/css; charset=utf-8',
18
+ '.js': 'application/javascript; charset=utf-8',
19
+ '.json': 'application/json; charset=utf-8',
20
+ '.svg': 'image/svg+xml',
21
+ '.png': 'image/png',
22
+ '.ico': 'image/x-icon',
23
+ };
24
+ export function json(res, data, status = 200) {
25
+ res.writeHead(status, {
26
+ 'Content-Type': 'application/json',
27
+ 'Access-Control-Allow-Origin': '*',
28
+ 'X-Content-Type-Options': 'nosniff',
29
+ });
30
+ res.end(JSON.stringify(data));
31
+ }
32
+ export function readBody(req, maxBytes = 64 * 1024) {
33
+ return new Promise((resolveBody, reject) => {
34
+ const chunks = [];
35
+ let size = 0;
36
+ req.on('data', (chunk) => {
37
+ size += chunk.length;
38
+ if (size > maxBytes) {
39
+ reject(new ValidationError('Request body too large'));
40
+ req.destroy();
41
+ return;
42
+ }
43
+ chunks.push(chunk);
44
+ });
45
+ req.on('end', () => {
46
+ try {
47
+ const body = JSON.parse(Buffer.concat(chunks).toString());
48
+ if (typeof body !== 'object' || body === null || Array.isArray(body)) {
49
+ reject(new ValidationError('Request body must be a JSON object'));
50
+ }
51
+ else {
52
+ resolveBody(body);
53
+ }
54
+ }
55
+ catch {
56
+ reject(new ValidationError('Invalid JSON in request body'));
57
+ }
58
+ });
59
+ req.on('error', reject);
60
+ });
61
+ }
62
+ export function createRouter(options = {}) {
63
+ const routes = [];
64
+ const logError = options.logError ?? ((err) => {
65
+ process.stderr.write('[agent-kit] REST handler error: ' + (err instanceof Error ? err.message : String(err)) + '\n');
66
+ });
67
+ function route(method, path, handler) {
68
+ const paramNames = [];
69
+ const pattern = path.replace(/:(\w+)/g, (_match, name) => {
70
+ paramNames.push(name);
71
+ return '([^/]+)';
72
+ });
73
+ routes.push({ method, pattern: new RegExp(`^${pattern}$`), paramNames, handler });
74
+ }
75
+ async function handle(req, res) {
76
+ if (req.method === 'OPTIONS') {
77
+ res.writeHead(204, {
78
+ 'Access-Control-Allow-Origin': '*',
79
+ 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
80
+ 'Access-Control-Allow-Headers': 'Content-Type',
81
+ });
82
+ res.end();
83
+ return;
84
+ }
85
+ const url = new URL(req.url ?? '/', `http://${req.headers.host}`);
86
+ const pathname = url.pathname;
87
+ for (const r of routes) {
88
+ if (req.method !== r.method)
89
+ continue;
90
+ const match = pathname.match(r.pattern);
91
+ if (!match)
92
+ continue;
93
+ const params = {};
94
+ r.paramNames.forEach((name, i) => {
95
+ params[name] = decodeURIComponent(match[i + 1]);
96
+ });
97
+ try {
98
+ await r.handler(req, res, params);
99
+ }
100
+ catch (err) {
101
+ if (err instanceof KitError) {
102
+ json(res, { error: err.message, code: err.code }, err.statusCode);
103
+ }
104
+ else {
105
+ logError(err);
106
+ json(res, { error: 'Internal server error' }, 500);
107
+ }
108
+ }
109
+ return;
110
+ }
111
+ if (pathname.startsWith('/api/')) {
112
+ json(res, { error: 'Not found' }, 404);
113
+ return;
114
+ }
115
+ if (options.staticDir) {
116
+ serveStatic(res, options.staticDir, pathname === '/' ? '/index.html' : pathname);
117
+ return;
118
+ }
119
+ json(res, { error: 'Not found' }, 404);
120
+ }
121
+ return { route, handle };
122
+ }
123
+ export function serveStatic(res, baseDir, pathname) {
124
+ let decoded;
125
+ try {
126
+ decoded = decodeURIComponent(pathname);
127
+ }
128
+ catch {
129
+ res.writeHead(400);
130
+ res.end('Bad request');
131
+ return;
132
+ }
133
+ if (decoded.includes('\0') || /(?:^|[\\/])\.\.(?:[\\/]|$)/.test(decoded)) {
134
+ res.writeHead(400);
135
+ res.end('Bad request');
136
+ return;
137
+ }
138
+ let realBase;
139
+ try {
140
+ realBase = realpathSync(baseDir);
141
+ }
142
+ catch {
143
+ res.writeHead(404);
144
+ res.end('Not found');
145
+ return;
146
+ }
147
+ const filePath = resolve(join(baseDir, decoded));
148
+ if (!filePath.startsWith(realBase)) {
149
+ res.writeHead(403);
150
+ res.end('Forbidden');
151
+ return;
152
+ }
153
+ let realFilePath;
154
+ try {
155
+ realFilePath = realpathSync(filePath);
156
+ }
157
+ catch {
158
+ realFilePath = filePath;
159
+ }
160
+ if (!realFilePath.startsWith(realBase)) {
161
+ res.writeHead(403);
162
+ res.end('Forbidden');
163
+ return;
164
+ }
165
+ try {
166
+ const content = readFileSync(realFilePath);
167
+ const ext = extname(realFilePath);
168
+ const mime = MIME_TYPES[ext] ?? 'application/octet-stream';
169
+ res.writeHead(200, { 'Content-Type': mime, 'Cache-Control': 'no-cache' });
170
+ res.end(content);
171
+ }
172
+ catch {
173
+ try {
174
+ const indexPath = join(baseDir, 'index.html');
175
+ const indexContent = readFileSync(indexPath);
176
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
177
+ res.end(indexContent);
178
+ }
179
+ catch {
180
+ res.writeHead(404);
181
+ res.end('Not found');
182
+ }
183
+ }
184
+ }
185
+ //# sourceMappingURL=rest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rest.js","sourceRoot":"","sources":["../../src/transport/rest.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,6BAA6B;AAC7B,EAAE;AACF,0DAA0D;AAC1D,wDAAwD;AACxD,gDAAgD;AAChD,0DAA0D;AAC1D,wDAAwD;AACxD,sEAAsE;AACtE,4CAA4C;AAC5C,gFAAgF;AAGhF,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAExD,MAAM,CAAC,MAAM,UAAU,GAA2B;IAChD,OAAO,EAAE,0BAA0B;IACnC,MAAM,EAAE,yBAAyB;IACjC,KAAK,EAAE,uCAAuC;IAC9C,OAAO,EAAE,iCAAiC;IAC1C,MAAM,EAAE,eAAe;IACvB,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,cAAc;CACvB,CAAC;AA2BF,MAAM,UAAU,IAAI,CAAC,GAAmB,EAAE,IAAa,EAAE,MAAM,GAAG,GAAG;IACnE,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE;QACpB,cAAc,EAAE,kBAAkB;QAClC,6BAA6B,EAAE,GAAG;QAClC,wBAAwB,EAAE,SAAS;KACpC,CAAC,CAAC;IACH,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,GAAoB,EAAE,QAAQ,GAAG,EAAE,GAAG,IAAI;IACjE,OAAO,IAAI,OAAO,CAAC,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE;QACzC,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,IAAI,IAAI,GAAG,CAAC,CAAC;QACb,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YAC/B,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC;YACrB,IAAI,IAAI,GAAG,QAAQ,EAAE,CAAC;gBACpB,MAAM,CAAC,IAAI,eAAe,CAAC,wBAAwB,CAAC,CAAC,CAAC;gBACtD,GAAG,CAAC,OAAO,EAAE,CAAC;gBACd,OAAO;YACT,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACjB,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;gBAC1D,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;oBACrE,MAAM,CAAC,IAAI,eAAe,CAAC,oCAAoC,CAAC,CAAC,CAAC;gBACpE,CAAC;qBAAM,CAAC;oBACN,WAAW,CAAC,IAA+B,CAAC,CAAC;gBAC/C,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,MAAM,CAAC,IAAI,eAAe,CAAC,8BAA8B,CAAC,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,UAAyB,EAAE;IACtD,MAAM,MAAM,GAAY,EAAE,CAAC;IAC3B,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;QAC5C,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,kCAAkC,GAAG,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAC/F,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,SAAS,KAAK,CAAC,MAAc,EAAE,IAAY,EAAE,OAAqB;QAChE,MAAM,UAAU,GAAa,EAAE,CAAC;QAChC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE;YACvD,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACtB,OAAO,SAAS,CAAC;QACnB,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,MAAM,CAAC,IAAI,OAAO,GAAG,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC;IACpF,CAAC;IAED,KAAK,UAAU,MAAM,CAAC,GAAoB,EAAE,GAAmB;QAC7D,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC7B,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;gBACjB,6BAA6B,EAAE,GAAG;gBAClC,8BAA8B,EAAE,iCAAiC;gBACjE,8BAA8B,EAAE,cAAc;aAC/C,CAAC,CAAC;YACH,GAAG,CAAC,GAAG,EAAE,CAAC;YACV,OAAO;QACT,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,UAAU,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QAClE,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;QAE9B,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;YACvB,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;gBAAE,SAAS;YACtC,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;YACxC,IAAI,CAAC,KAAK;gBAAE,SAAS;YAErB,MAAM,MAAM,GAA2B,EAAE,CAAC;YAC1C,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;gBAC/B,MAAM,CAAC,IAAI,CAAC,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAClD,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC;gBACH,MAAM,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;YACpC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,GAAG,YAAY,QAAQ,EAAE,CAAC;oBAC5B,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC;gBACpE,CAAC;qBAAM,CAAC;oBACN,QAAQ,CAAC,GAAG,CAAC,CAAC;oBACd,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,uBAAuB,EAAE,EAAE,GAAG,CAAC,CAAC;gBACrD,CAAC;YACH,CAAC;YACD,OAAO;QACT,CAAC;QAED,IAAI,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YACjC,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,GAAG,CAAC,CAAC;YACvC,OAAO;QACT,CAAC;QAED,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;YACtB,WAAW,CAAC,GAAG,EAAE,OAAO,CAAC,SAAS,EAAE,QAAQ,KAAK,GAAG,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;YACjF,OAAO;QACT,CAAC;QAED,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,GAAG,CAAC,CAAC;IACzC,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAmB,EAAE,OAAe,EAAE,QAAgB;IAChF,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACnB,GAAG,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QACvB,OAAO;IACT,CAAC;IAED,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,4BAA4B,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACzE,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACnB,GAAG,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QACvB,OAAO;IACT,CAAC;IAED,IAAI,QAAgB,CAAC;IACrB,IAAI,CAAC;QACH,QAAQ,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACnB,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IACjD,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACnC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACnB,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,IAAI,YAAoB,CAAC;IACzB,IAAI,CAAC;QACH,YAAY,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,YAAY,GAAG,QAAQ,CAAC;IAC1B,CAAC;IAED,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACvC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACnB,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,YAAY,CAAC,YAAY,CAAC,CAAC;QAC3C,MAAM,GAAG,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;QAClC,MAAM,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,0BAA0B,CAAC;QAC3D,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE,eAAe,EAAE,UAAU,EAAE,CAAC,CAAC;QAC1E,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;YAC9C,MAAM,YAAY,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;YAC7C,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,0BAA0B,EAAE,CAAC,CAAC;YACnE,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QACxB,CAAC;QAAC,MAAM,CAAC;YACP,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YACnB,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,28 @@
1
+ import { WebSocketServer } from 'ws';
2
+ import type { Server } from 'http';
3
+ export interface WsHandle {
4
+ wss: WebSocketServer;
5
+ close(): void;
6
+ }
7
+ export interface WsOptions<F extends Record<string, string>> {
8
+ /** HTTP server to attach to. */
9
+ httpServer: Server;
10
+ /** Compute current fingerprints. Cheap query — runs every poll interval. */
11
+ getFingerprints: () => F;
12
+ /** Fetch fresh data for a single changed category. */
13
+ getCategoryData: (category: keyof F) => unknown;
14
+ /** Fetch full state payload (sent on connect and on client `refresh`). */
15
+ getFullState: () => Record<string, unknown>;
16
+ /** Max concurrent connections (default: 50). */
17
+ maxConnections?: number;
18
+ /** Max single message size in bytes (default: 4096). */
19
+ maxMessageSize?: number;
20
+ /** Ping interval in ms (default: 30s). */
21
+ pingIntervalMs?: number;
22
+ /** DB poll interval in ms (default: 2s). */
23
+ pollIntervalMs?: number;
24
+ /** Logger for errors. */
25
+ logError?: (err: unknown) => void;
26
+ }
27
+ export declare function setupWebSocket<F extends Record<string, string>>(opts: WsOptions<F>): WsHandle;
28
+ //# sourceMappingURL=ws.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ws.d.ts","sourceRoot":"","sources":["../../src/transport/ws.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,eAAe,EAAa,MAAM,IAAI,CAAC;AAChD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAEnC,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,eAAe,CAAC;IACrB,KAAK,IAAI,IAAI,CAAC;CACf;AAED,MAAM,WAAW,SAAS,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IACzD,gCAAgC;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,4EAA4E;IAC5E,eAAe,EAAE,MAAM,CAAC,CAAC;IACzB,sDAAsD;IACtD,eAAe,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,OAAO,CAAC;IAChD,0EAA0E;IAC1E,YAAY,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5C,gDAAgD;IAChD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,wDAAwD;IACxD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,0CAA0C;IAC1C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,4CAA4C;IAC5C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,yBAAyB;IACzB,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;CACnC;AAOD,wBAAgB,cAAc,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,QAAQ,CAyI7F"}
@@ -0,0 +1,143 @@
1
+ // =============================================================================
2
+ // agent-kit — WebSocket transport
3
+ //
4
+ // Generic delta-streaming WebSocket server. The consumer provides:
5
+ // - getFingerprints(): an object whose keys are categories and values are
6
+ // short fingerprint strings derived from the DB. Polled every interval.
7
+ // - getCategoryData(category): returns the current data for a category.
8
+ // - getFullState(): returns the full state payload sent on connect.
9
+ // The server diffs fingerprints between polls and only sends the changed
10
+ // categories to each client.
11
+ // =============================================================================
12
+ import { WebSocketServer, WebSocket } from 'ws';
13
+ export function setupWebSocket(opts) {
14
+ const maxConnections = opts.maxConnections ?? 50;
15
+ const maxMessageSize = opts.maxMessageSize ?? 4096;
16
+ const pingIntervalMs = opts.pingIntervalMs ?? 30_000;
17
+ const pollIntervalMs = opts.pollIntervalMs ?? 2_000;
18
+ const logError = opts.logError ??
19
+ ((err) => {
20
+ process.stderr.write('[agent-kit] WS error: ' + (err instanceof Error ? err.message : String(err)) + '\n');
21
+ });
22
+ const wss = new WebSocketServer({ server: opts.httpServer, maxPayload: maxMessageSize });
23
+ const clients = new Map();
24
+ function sendFull(ws) {
25
+ try {
26
+ const fp = opts.getFingerprints();
27
+ const state = clients.get(ws);
28
+ if (state)
29
+ state.fingerprints = { ...fp };
30
+ ws.send(JSON.stringify({ type: 'state', ...opts.getFullState() }));
31
+ }
32
+ catch (err) {
33
+ logError(err);
34
+ }
35
+ }
36
+ function sendDelta(ws, state, currentFp) {
37
+ const prev = state.fingerprints;
38
+ const changed = {};
39
+ let hasChanges = false;
40
+ for (const key of Object.keys(currentFp)) {
41
+ if (prev[key] !== currentFp[key]) {
42
+ changed[key] = opts.getCategoryData(key);
43
+ hasChanges = true;
44
+ }
45
+ }
46
+ if (!hasChanges)
47
+ return;
48
+ state.fingerprints = { ...currentFp };
49
+ try {
50
+ ws.send(JSON.stringify({ type: 'state', delta: true, ...changed }));
51
+ }
52
+ catch (err) {
53
+ logError(err);
54
+ }
55
+ }
56
+ wss.on('connection', (ws) => {
57
+ if (wss.clients.size > maxConnections) {
58
+ ws.close(1013, 'Too many connections');
59
+ return;
60
+ }
61
+ clients.set(ws, { alive: true, fingerprints: null });
62
+ sendFull(ws);
63
+ ws.on('pong', () => {
64
+ const state = clients.get(ws);
65
+ if (state)
66
+ state.alive = true;
67
+ });
68
+ ws.on('message', (raw) => {
69
+ let parsed;
70
+ try {
71
+ parsed = JSON.parse(raw.toString());
72
+ }
73
+ catch {
74
+ ws.send(JSON.stringify({ type: 'error', message: 'Invalid JSON' }));
75
+ return;
76
+ }
77
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
78
+ ws.send(JSON.stringify({ type: 'error', message: 'Message must be a JSON object' }));
79
+ return;
80
+ }
81
+ const msg = parsed;
82
+ if (msg.type === 'refresh') {
83
+ const state = clients.get(ws);
84
+ if (state)
85
+ state.fingerprints = null;
86
+ sendFull(ws);
87
+ }
88
+ else {
89
+ const safeType = String(msg.type ?? '')
90
+ .slice(0, 64)
91
+ .replace(/[<>&"']/g, '');
92
+ ws.send(JSON.stringify({ type: 'error', message: `Unknown message type: ${safeType}` }));
93
+ }
94
+ });
95
+ ws.on('error', () => clients.delete(ws));
96
+ ws.on('close', () => clients.delete(ws));
97
+ });
98
+ const pingTimer = setInterval(() => {
99
+ for (const [ws, state] of clients) {
100
+ if (!state.alive) {
101
+ ws.terminate();
102
+ clients.delete(ws);
103
+ continue;
104
+ }
105
+ state.alive = false;
106
+ ws.ping();
107
+ }
108
+ }, pingIntervalMs);
109
+ pingTimer.unref();
110
+ const pollTimer = setInterval(() => {
111
+ if (clients.size === 0)
112
+ return;
113
+ try {
114
+ const currentFp = opts.getFingerprints();
115
+ for (const [ws, state] of clients) {
116
+ if (ws.readyState !== WebSocket.OPEN)
117
+ continue;
118
+ if (!state.fingerprints) {
119
+ sendFull(ws);
120
+ continue;
121
+ }
122
+ sendDelta(ws, state, currentFp);
123
+ }
124
+ }
125
+ catch (err) {
126
+ logError(err);
127
+ }
128
+ }, pollIntervalMs);
129
+ pollTimer.unref();
130
+ return {
131
+ wss,
132
+ close() {
133
+ clearInterval(pingTimer);
134
+ clearInterval(pollTimer);
135
+ for (const [ws] of clients) {
136
+ ws.close(1001, 'Server shutting down');
137
+ }
138
+ clients.clear();
139
+ wss.close();
140
+ },
141
+ };
142
+ }
143
+ //# sourceMappingURL=ws.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ws.js","sourceRoot":"","sources":["../../src/transport/ws.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ export declare class KitError extends Error {
2
+ readonly code: string;
3
+ readonly statusCode: number;
4
+ constructor(message: string, code?: string, statusCode?: number);
5
+ }
6
+ export declare class ValidationError extends KitError {
7
+ constructor(message: string);
8
+ }
9
+ export declare class NotFoundError extends KitError {
10
+ constructor(resource: string, identifier?: string);
11
+ }
12
+ export interface ToolDefinition {
13
+ name: string;
14
+ description: string;
15
+ inputSchema: Record<string, unknown>;
16
+ }
17
+ export interface JsonRpcRequest {
18
+ jsonrpc: '2.0';
19
+ id?: number | string | null;
20
+ method: string;
21
+ params?: Record<string, unknown>;
22
+ }
23
+ export interface JsonRpcResponse {
24
+ jsonrpc: '2.0';
25
+ id: number | string | null | undefined;
26
+ result?: unknown;
27
+ error?: {
28
+ code: number;
29
+ message: string;
30
+ data?: unknown;
31
+ };
32
+ }
33
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAIA,qBAAa,QAAS,SAAQ,KAAK;aAGf,IAAI,EAAE,MAAM;aACZ,UAAU,EAAE,MAAM;gBAFlC,OAAO,EAAE,MAAM,EACC,IAAI,GAAE,MAAoB,EAC1B,UAAU,GAAE,MAAY;CAK3C;AAED,qBAAa,eAAgB,SAAQ,QAAQ;gBAC/B,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,aAAc,SAAQ,QAAQ;gBAC7B,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM;CAQlD;AAMD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,KAAK,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,KAAK,CAAC;IACf,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACvC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CAC3D"}