@kadi.build/core 0.0.1-alpha.10 → 0.0.1-alpha.12

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 (71) hide show
  1. package/README.md +269 -1311
  2. package/dist/abilities/AbilityLoader.d.ts +26 -0
  3. package/dist/abilities/AbilityLoader.d.ts.map +1 -1
  4. package/dist/abilities/AbilityLoader.js +141 -18
  5. package/dist/abilities/AbilityLoader.js.map +1 -1
  6. package/dist/abilities/AbilityProxy.d.ts +33 -0
  7. package/dist/abilities/AbilityProxy.d.ts.map +1 -1
  8. package/dist/abilities/AbilityProxy.js +40 -0
  9. package/dist/abilities/AbilityProxy.js.map +1 -1
  10. package/dist/abilities/index.d.ts +1 -1
  11. package/dist/abilities/index.d.ts.map +1 -1
  12. package/dist/abilities/types.d.ts +67 -0
  13. package/dist/abilities/types.d.ts.map +1 -1
  14. package/dist/broker/BrokerProtocol.js +11 -11
  15. package/dist/broker/BrokerProtocol.js.map +1 -1
  16. package/dist/client/KadiClient.d.ts +191 -2
  17. package/dist/client/KadiClient.d.ts.map +1 -1
  18. package/dist/client/KadiClient.js +412 -2
  19. package/dist/client/KadiClient.js.map +1 -1
  20. package/dist/index.d.ts +3 -2
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +5 -1
  23. package/dist/index.js.map +1 -1
  24. package/dist/messages/index.d.ts +1 -1
  25. package/dist/messages/index.js +1 -1
  26. package/dist/messages/index.js.map +1 -1
  27. package/dist/schemas/index.d.ts +3 -0
  28. package/dist/schemas/index.d.ts.map +1 -1
  29. package/dist/schemas/index.js +2 -0
  30. package/dist/schemas/index.js.map +1 -1
  31. package/dist/schemas/zod-helpers.d.ts +129 -0
  32. package/dist/schemas/zod-helpers.d.ts.map +1 -0
  33. package/dist/schemas/zod-helpers.js +225 -0
  34. package/dist/schemas/zod-helpers.js.map +1 -0
  35. package/dist/schemas/zod-to-json-schema.d.ts +159 -0
  36. package/dist/schemas/zod-to-json-schema.d.ts.map +1 -0
  37. package/dist/schemas/zod-to-json-schema.js +154 -0
  38. package/dist/schemas/zod-to-json-schema.js.map +1 -0
  39. package/dist/transports/NativeTransport.d.ts +29 -0
  40. package/dist/transports/NativeTransport.d.ts.map +1 -1
  41. package/dist/transports/NativeTransport.js +98 -3
  42. package/dist/transports/NativeTransport.js.map +1 -1
  43. package/dist/transports/StdioTransport.d.ts +141 -63
  44. package/dist/transports/StdioTransport.d.ts.map +1 -1
  45. package/dist/transports/StdioTransport.js +309 -232
  46. package/dist/transports/StdioTransport.js.map +1 -1
  47. package/dist/types/broker.d.ts +0 -22
  48. package/dist/types/broker.d.ts.map +1 -1
  49. package/dist/types/broker.js +0 -27
  50. package/dist/types/broker.js.map +1 -1
  51. package/dist/types/index.d.ts +3 -1
  52. package/dist/types/index.d.ts.map +1 -1
  53. package/dist/types/index.js +1 -1
  54. package/dist/types/index.js.map +1 -1
  55. package/dist/types/zod-tools.d.ts +198 -0
  56. package/dist/types/zod-tools.d.ts.map +1 -0
  57. package/dist/types/zod-tools.js +14 -0
  58. package/dist/types/zod-tools.js.map +1 -0
  59. package/dist/utils/LockfileResolver.d.ts +108 -0
  60. package/dist/utils/LockfileResolver.d.ts.map +1 -0
  61. package/dist/utils/LockfileResolver.js +230 -0
  62. package/dist/utils/LockfileResolver.js.map +1 -0
  63. package/dist/utils/StdioMessageReader.d.ts +122 -0
  64. package/dist/utils/StdioMessageReader.d.ts.map +1 -0
  65. package/dist/utils/StdioMessageReader.js +209 -0
  66. package/dist/utils/StdioMessageReader.js.map +1 -0
  67. package/dist/utils/StdioMessageWriter.d.ts +104 -0
  68. package/dist/utils/StdioMessageWriter.d.ts.map +1 -0
  69. package/dist/utils/StdioMessageWriter.js +162 -0
  70. package/dist/utils/StdioMessageWriter.js.map +1 -0
  71. package/package.json +2 -1
@@ -0,0 +1,230 @@
1
+ /**
2
+ * Lockfile Resolver
3
+ *
4
+ * Utilities for resolving ability paths from agent-lock.json
5
+ * Integrates kadi-core with kadi-install's global cache architecture
6
+ *
7
+ * @module utils/LockfileResolver
8
+ */
9
+ import fs from 'fs';
10
+ import path from 'path';
11
+ import { KadiError, ErrorCode } from '../errors/index.js';
12
+ /**
13
+ * Find project root by looking for agent.json
14
+ *
15
+ * Walks up directory tree from cwd until finding agent.json
16
+ *
17
+ * @param startDir - Directory to start search from (defaults to cwd)
18
+ * @returns Absolute path to project root
19
+ * @throws {KadiError} If no project root found
20
+ */
21
+ export function findProjectRoot(startDir = process.cwd()) {
22
+ let current = path.resolve(startDir);
23
+ const root = path.parse(current).root;
24
+ while (current !== root) {
25
+ const agentJsonPath = path.join(current, 'agent.json');
26
+ if (fs.existsSync(agentJsonPath)) {
27
+ return current;
28
+ }
29
+ // Move up one directory
30
+ current = path.dirname(current);
31
+ }
32
+ throw new KadiError('No KADI project found - could not locate agent.json', ErrorCode.INVALID_CONFIG, 404, {
33
+ searchedFrom: startDir,
34
+ reason: 'No agent.json found in current directory or parent directories',
35
+ suggestion: 'Make sure you are running from within a KADI project',
36
+ alternatives: [
37
+ 'Run from a directory containing agent.json',
38
+ 'Initialize a new KADI project: kadi init',
39
+ 'Provide explicit path when loading ability'
40
+ ]
41
+ });
42
+ }
43
+ /**
44
+ * Read agent-lock.json from project root
45
+ *
46
+ * @param projectRoot - Project root directory
47
+ * @returns Parsed lockfile
48
+ * @throws {KadiError} If lockfile not found or invalid
49
+ */
50
+ export function readLockfile(projectRoot) {
51
+ const lockfilePath = path.join(projectRoot, 'agent-lock.json');
52
+ // Check if lockfile exists
53
+ if (!fs.existsSync(lockfilePath)) {
54
+ throw new KadiError('No agent-lock.json found - cannot auto-resolve ability paths', ErrorCode.INVALID_CONFIG, 404, {
55
+ projectRoot,
56
+ lockfilePath,
57
+ reason: 'agent-lock.json not found in project root',
58
+ suggestion: 'Run `kadi install` to generate lockfile',
59
+ alternatives: [
60
+ 'Run: kadi install (to install all abilities from agent.json)',
61
+ 'Run: kadi install <ability-name> (to install specific ability)',
62
+ 'Provide explicit path: client.load("ability", "native", { path: "./abilities/..." })'
63
+ ],
64
+ hint: 'agent-lock.json is created by running `kadi install`'
65
+ });
66
+ }
67
+ // Read and parse lockfile
68
+ try {
69
+ const content = fs.readFileSync(lockfilePath, 'utf-8');
70
+ const lockfile = JSON.parse(content);
71
+ // Basic validation
72
+ if (!lockfile.abilities || typeof lockfile.abilities !== 'object') {
73
+ throw new Error('Invalid lockfile format: missing or invalid "abilities" field');
74
+ }
75
+ return lockfile;
76
+ }
77
+ catch (error) {
78
+ if (error instanceof SyntaxError) {
79
+ throw new KadiError('Invalid agent-lock.json - malformed JSON', ErrorCode.INVALID_CONFIG, 400, {
80
+ lockfilePath,
81
+ parseError: error.message,
82
+ suggestion: 'Delete agent-lock.json and run `kadi install` to regenerate'
83
+ });
84
+ }
85
+ throw new KadiError('Failed to read agent-lock.json', ErrorCode.INTERNAL_ERROR, 500, {
86
+ lockfilePath,
87
+ error: error instanceof Error ? error.message : String(error)
88
+ });
89
+ }
90
+ }
91
+ /**
92
+ * Resolve ability path from lockfile
93
+ *
94
+ * @param abilityName - Name of ability to resolve
95
+ * @param projectRoot - Project root directory
96
+ * @returns Resolved ability entry from lockfile
97
+ * @throws {KadiError} If ability not found in lockfile or path doesn't exist
98
+ */
99
+ export function resolveAbilityPath(abilityName, projectRoot) {
100
+ const lockfile = readLockfile(projectRoot);
101
+ // Check if ability exists in lockfile
102
+ const abilityEntry = lockfile.abilities[abilityName];
103
+ if (!abilityEntry) {
104
+ // Ability not in lockfile - show helpful error
105
+ const installedAbilities = Object.keys(lockfile.abilities);
106
+ throw new KadiError(`Ability '${abilityName}' not found in agent-lock.json`, ErrorCode.ABILITY_NOT_FOUND, 404, {
107
+ abilityName,
108
+ projectRoot,
109
+ installedAbilities,
110
+ installedCount: installedAbilities.length,
111
+ reason: `'${abilityName}' is not installed in this project`,
112
+ suggestion: `Run: kadi install ${abilityName}`,
113
+ alternatives: [
114
+ `Install ability: kadi install ${abilityName}`,
115
+ 'View installed abilities in agent-lock.json',
116
+ 'Provide explicit path when loading ability'
117
+ ],
118
+ hint: installedAbilities.length === 0
119
+ ? 'No abilities installed yet. Run `kadi install` to install from agent.json'
120
+ : `Currently installed: ${installedAbilities.slice(0, 5).join(', ')}${installedAbilities.length > 5 ? '...' : ''}`
121
+ });
122
+ }
123
+ // Resolve path (may be relative to project root)
124
+ const absolutePath = path.isAbsolute(abilityEntry.resolved)
125
+ ? abilityEntry.resolved
126
+ : path.resolve(projectRoot, abilityEntry.resolved);
127
+ // Verify the resolved path exists
128
+ if (!fs.existsSync(absolutePath)) {
129
+ throw new KadiError(`Ability '${abilityName}@${abilityEntry.version}' is in lockfile but directory not found`, ErrorCode.ABILITY_NOT_FOUND, 404, {
130
+ abilityName,
131
+ version: abilityEntry.version,
132
+ expectedPath: absolutePath,
133
+ reason: 'Directory listed in lockfile does not exist',
134
+ possibleCauses: [
135
+ 'Ability was manually deleted',
136
+ 'Project was moved without abilities/ folder',
137
+ 'File system error or permissions issue'
138
+ ],
139
+ suggestion: `Run: kadi install --force ${abilityName}`,
140
+ alternatives: [
141
+ `Reinstall ability: kadi install --force ${abilityName}`,
142
+ 'Check if abilities/ folder exists',
143
+ 'Run `kadi install` to restore all abilities'
144
+ ]
145
+ });
146
+ }
147
+ // Return entry with absolute path
148
+ return {
149
+ ...abilityEntry,
150
+ resolved: absolutePath
151
+ };
152
+ }
153
+ /**
154
+ * Read ability's agent.json manifest
155
+ *
156
+ * @param abilityPath - Path to ability directory
157
+ * @returns Parsed ability manifest
158
+ * @throws {KadiError} If manifest not found or invalid
159
+ */
160
+ export function readAbilityManifest(abilityPath) {
161
+ const manifestPath = path.join(abilityPath, 'agent.json');
162
+ if (!fs.existsSync(manifestPath)) {
163
+ throw new KadiError('Ability agent.json not found', ErrorCode.INVALID_CONFIG, 404, {
164
+ abilityPath,
165
+ manifestPath,
166
+ reason: 'agent.json not found in ability directory',
167
+ suggestion: 'Reinstall the ability: kadi install --force <ability-name>'
168
+ });
169
+ }
170
+ try {
171
+ const content = fs.readFileSync(manifestPath, 'utf-8');
172
+ const manifest = JSON.parse(content);
173
+ // Basic validation
174
+ if (!manifest.name || !manifest.version) {
175
+ throw new Error('Invalid manifest: missing name or version');
176
+ }
177
+ return manifest;
178
+ }
179
+ catch (error) {
180
+ if (error instanceof SyntaxError) {
181
+ throw new KadiError('Invalid ability agent.json - malformed JSON', ErrorCode.INVALID_CONFIG, 400, {
182
+ manifestPath,
183
+ parseError: error.message
184
+ });
185
+ }
186
+ throw new KadiError('Failed to read ability agent.json', ErrorCode.INTERNAL_ERROR, 500, {
187
+ manifestPath,
188
+ error: error instanceof Error ? error.message : String(error)
189
+ });
190
+ }
191
+ }
192
+ /**
193
+ * Auto-resolve ability configuration for loading
194
+ *
195
+ * Combines lockfile lookup with manifest reading to provide
196
+ * all information needed to load an ability.
197
+ *
198
+ * @param abilityName - Name of ability
199
+ * @param projectRoot - Project root directory (optional, will search if not provided)
200
+ * @returns Resolved ability configuration
201
+ *
202
+ * @example
203
+ * ```typescript
204
+ * const config = resolveAbilityConfig('math-lib');
205
+ * // Returns:
206
+ * // {
207
+ * // path: '/path/to/project/abilities/math-lib@1.0.0',
208
+ * // version: '1.0.0',
209
+ * // entry: 'service.js',
210
+ * // manifest: { ... }
211
+ * // }
212
+ * ```
213
+ */
214
+ export function resolveAbilityConfig(abilityName, projectRoot) {
215
+ // Find project root if not provided
216
+ const root = projectRoot || findProjectRoot();
217
+ // Resolve ability from lockfile
218
+ const entry = resolveAbilityPath(abilityName, root);
219
+ // Read ability manifest
220
+ const manifest = readAbilityManifest(entry.resolved);
221
+ // Get entry point (default to 'index.js' if not specified)
222
+ const entryPoint = manifest.entry || 'index.js';
223
+ return {
224
+ path: entry.resolved,
225
+ version: entry.version,
226
+ entry: entryPoint,
227
+ manifest
228
+ };
229
+ }
230
+ //# sourceMappingURL=LockfileResolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LockfileResolver.js","sourceRoot":"","sources":["../../src/utils/LockfileResolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Stdio Message Reader
3
+ *
4
+ * Reads Content-Length framed messages from a stream (LSP-style).
5
+ * Handles partial messages across multiple chunks and ignores non-framed output.
6
+ *
7
+ * Message format:
8
+ * ```
9
+ * Content-Length: 67\r\n
10
+ * \r\n
11
+ * {"jsonrpc":"2.0","id":1,"method":"invoke","params":{...}}
12
+ * ```
13
+ *
14
+ * @module utils/StdioMessageReader
15
+ */
16
+ import { EventEmitter } from 'events';
17
+ /**
18
+ * Message reader for Content-Length framed messages
19
+ *
20
+ * Implements the LSP (Language Server Protocol) message framing format.
21
+ * This allows reliable JSON-RPC communication over stdio even when the
22
+ * ability writes logs or debug output to stdout.
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * const reader = new StdioMessageReader();
27
+ *
28
+ * reader.on('message', (message) => {
29
+ * console.log('Received:', message);
30
+ * });
31
+ *
32
+ * reader.on('error', (error) => {
33
+ * console.error('Parse error:', error);
34
+ * });
35
+ *
36
+ * // Feed data chunks
37
+ * process.stdout.on('data', (chunk) => {
38
+ * reader.onData(chunk);
39
+ * });
40
+ * ```
41
+ */
42
+ export declare class StdioMessageReader extends EventEmitter {
43
+ /**
44
+ * Buffer for accumulating incoming data
45
+ */
46
+ private buffer;
47
+ /**
48
+ * Whether the reader has been destroyed
49
+ */
50
+ private destroyed;
51
+ /**
52
+ * Header end marker
53
+ */
54
+ private static readonly HEADER_END;
55
+ /**
56
+ * Content-Length header regex
57
+ * Note: No multiline flag - header must be clean (no garbage before it)
58
+ */
59
+ private static readonly CONTENT_LENGTH_PATTERN;
60
+ /**
61
+ * Process incoming data chunk
62
+ *
63
+ * Appends chunk to buffer and attempts to parse complete messages.
64
+ * May emit multiple 'message' events if buffer contains multiple messages.
65
+ *
66
+ * @param chunk - Incoming data chunk
67
+ *
68
+ * @example
69
+ * ```typescript
70
+ * stream.on('data', (chunk) => {
71
+ * reader.onData(chunk);
72
+ * });
73
+ * ```
74
+ */
75
+ onData(chunk: Buffer): void;
76
+ /**
77
+ * Attempt to read and emit complete messages from buffer
78
+ *
79
+ * Continues reading until no complete message can be extracted.
80
+ * Handles multiple messages in a single buffer.
81
+ */
82
+ private tryReadMessages;
83
+ /**
84
+ * Attempt to read a single complete message
85
+ *
86
+ * @returns Parsed message object, or null if no complete message available
87
+ * @throws {Error} If header is malformed or JSON is invalid
88
+ */
89
+ private tryReadSingleMessage;
90
+ /**
91
+ * Skip to next potential header in buffer
92
+ *
93
+ * Used for error recovery when a malformed message is encountered.
94
+ * Searches for the next "Content-Length:" pattern.
95
+ */
96
+ private skipToNextHeader;
97
+ /**
98
+ * Get current buffer size (for debugging/monitoring)
99
+ *
100
+ * @returns Number of bytes in buffer
101
+ */
102
+ getBufferSize(): number;
103
+ /**
104
+ * Clear the internal buffer
105
+ *
106
+ * Useful for resetting state after errors or for cleanup.
107
+ */
108
+ clearBuffer(): void;
109
+ /**
110
+ * Destroy the reader
111
+ *
112
+ * Cleans up resources and prevents further processing.
113
+ */
114
+ destroy(): void;
115
+ /**
116
+ * Check if reader is destroyed
117
+ *
118
+ * @returns true if destroyed
119
+ */
120
+ isDestroyed(): boolean;
121
+ }
122
+ //# sourceMappingURL=StdioMessageReader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StdioMessageReader.d.ts","sourceRoot":"","sources":["../../src/utils/StdioMessageReader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAEtC;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,kBAAmB,SAAQ,YAAY;IAClD;;OAEG;IACH,OAAO,CAAC,MAAM,CAAmB;IAEjC;;OAEG;IACH,OAAO,CAAC,SAAS,CAAS;IAE1B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAc;IAEhD;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,sBAAsB,CAAmC;IAEjF;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAY3B;;;;;OAKG;IACH,OAAO,CAAC,eAAe;IAqBvB;;;;;OAKG;IACH,OAAO,CAAC,oBAAoB;IAmD5B;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB;IAaxB;;;;OAIG;IACH,aAAa,IAAI,MAAM;IAIvB;;;;OAIG;IACH,WAAW,IAAI,IAAI;IAInB;;;;OAIG;IACH,OAAO,IAAI,IAAI;IAMf;;;;OAIG;IACH,WAAW,IAAI,OAAO;CAGvB"}
@@ -0,0 +1,209 @@
1
+ /**
2
+ * Stdio Message Reader
3
+ *
4
+ * Reads Content-Length framed messages from a stream (LSP-style).
5
+ * Handles partial messages across multiple chunks and ignores non-framed output.
6
+ *
7
+ * Message format:
8
+ * ```
9
+ * Content-Length: 67\r\n
10
+ * \r\n
11
+ * {"jsonrpc":"2.0","id":1,"method":"invoke","params":{...}}
12
+ * ```
13
+ *
14
+ * @module utils/StdioMessageReader
15
+ */
16
+ import { EventEmitter } from 'events';
17
+ /**
18
+ * Message reader for Content-Length framed messages
19
+ *
20
+ * Implements the LSP (Language Server Protocol) message framing format.
21
+ * This allows reliable JSON-RPC communication over stdio even when the
22
+ * ability writes logs or debug output to stdout.
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * const reader = new StdioMessageReader();
27
+ *
28
+ * reader.on('message', (message) => {
29
+ * console.log('Received:', message);
30
+ * });
31
+ *
32
+ * reader.on('error', (error) => {
33
+ * console.error('Parse error:', error);
34
+ * });
35
+ *
36
+ * // Feed data chunks
37
+ * process.stdout.on('data', (chunk) => {
38
+ * reader.onData(chunk);
39
+ * });
40
+ * ```
41
+ */
42
+ export class StdioMessageReader extends EventEmitter {
43
+ /**
44
+ * Buffer for accumulating incoming data
45
+ */
46
+ buffer = Buffer.alloc(0);
47
+ /**
48
+ * Whether the reader has been destroyed
49
+ */
50
+ destroyed = false;
51
+ /**
52
+ * Header end marker
53
+ */
54
+ static HEADER_END = '\r\n\r\n';
55
+ /**
56
+ * Content-Length header regex
57
+ * Note: No multiline flag - header must be clean (no garbage before it)
58
+ */
59
+ static CONTENT_LENGTH_PATTERN = /^Content-Length:\s*(\d+)\s*$/i;
60
+ /**
61
+ * Process incoming data chunk
62
+ *
63
+ * Appends chunk to buffer and attempts to parse complete messages.
64
+ * May emit multiple 'message' events if buffer contains multiple messages.
65
+ *
66
+ * @param chunk - Incoming data chunk
67
+ *
68
+ * @example
69
+ * ```typescript
70
+ * stream.on('data', (chunk) => {
71
+ * reader.onData(chunk);
72
+ * });
73
+ * ```
74
+ */
75
+ onData(chunk) {
76
+ if (this.destroyed) {
77
+ return;
78
+ }
79
+ // Append to buffer
80
+ this.buffer = Buffer.concat([this.buffer, chunk]);
81
+ // Try to extract messages
82
+ this.tryReadMessages();
83
+ }
84
+ /**
85
+ * Attempt to read and emit complete messages from buffer
86
+ *
87
+ * Continues reading until no complete message can be extracted.
88
+ * Handles multiple messages in a single buffer.
89
+ */
90
+ tryReadMessages() {
91
+ while (true) {
92
+ try {
93
+ const message = this.tryReadSingleMessage();
94
+ if (!message) {
95
+ // No complete message available
96
+ break;
97
+ }
98
+ // Emit the message
99
+ this.emit('message', message);
100
+ }
101
+ catch (error) {
102
+ // Emit error but continue processing
103
+ this.emit('error', error);
104
+ // Try to recover by skipping to next potential header
105
+ this.skipToNextHeader();
106
+ }
107
+ }
108
+ }
109
+ /**
110
+ * Attempt to read a single complete message
111
+ *
112
+ * @returns Parsed message object, or null if no complete message available
113
+ * @throws {Error} If header is malformed or JSON is invalid
114
+ */
115
+ tryReadSingleMessage() {
116
+ // Look for header end marker
117
+ const headerEndIndex = this.buffer.indexOf(StdioMessageReader.HEADER_END);
118
+ if (headerEndIndex === -1) {
119
+ // No complete header yet
120
+ return null;
121
+ }
122
+ // Extract header
123
+ const headerBytes = this.buffer.slice(0, headerEndIndex);
124
+ const header = headerBytes.toString('utf8');
125
+ // Parse Content-Length
126
+ const match = header.match(StdioMessageReader.CONTENT_LENGTH_PATTERN);
127
+ if (!match || !match[1]) {
128
+ throw new Error(`Invalid message header: missing or malformed Content-Length\nHeader: ${header}`);
129
+ }
130
+ const contentLength = parseInt(match[1], 10);
131
+ if (isNaN(contentLength) || contentLength < 0) {
132
+ throw new Error(`Invalid Content-Length value: ${match[1]}`);
133
+ }
134
+ // Check if we have the complete message
135
+ const messageStart = headerEndIndex + StdioMessageReader.HEADER_END.length;
136
+ const messageEnd = messageStart + contentLength;
137
+ if (this.buffer.length < messageEnd) {
138
+ // Need more data - message is incomplete
139
+ return null;
140
+ }
141
+ // Extract message bytes
142
+ const messageBytes = this.buffer.slice(messageStart, messageEnd);
143
+ const messageJson = messageBytes.toString('utf8');
144
+ // Parse JSON
145
+ let message;
146
+ try {
147
+ message = JSON.parse(messageJson);
148
+ }
149
+ catch (error) {
150
+ throw new Error(`Invalid JSON in message body: ${error instanceof Error ? error.message : String(error)}\nJSON: ${messageJson.substring(0, 200)}`);
151
+ }
152
+ // Remove processed data from buffer
153
+ this.buffer = this.buffer.slice(messageEnd);
154
+ return message;
155
+ }
156
+ /**
157
+ * Skip to next potential header in buffer
158
+ *
159
+ * Used for error recovery when a malformed message is encountered.
160
+ * Searches for the next "Content-Length:" pattern.
161
+ */
162
+ skipToNextHeader() {
163
+ const searchString = this.buffer.toString('utf8');
164
+ const nextHeaderIndex = searchString.indexOf('Content-Length:', 1);
165
+ if (nextHeaderIndex === -1) {
166
+ // No next header found - clear buffer
167
+ this.buffer = Buffer.alloc(0);
168
+ }
169
+ else {
170
+ // Skip to next header
171
+ this.buffer = this.buffer.slice(nextHeaderIndex);
172
+ }
173
+ }
174
+ /**
175
+ * Get current buffer size (for debugging/monitoring)
176
+ *
177
+ * @returns Number of bytes in buffer
178
+ */
179
+ getBufferSize() {
180
+ return this.buffer.length;
181
+ }
182
+ /**
183
+ * Clear the internal buffer
184
+ *
185
+ * Useful for resetting state after errors or for cleanup.
186
+ */
187
+ clearBuffer() {
188
+ this.buffer = Buffer.alloc(0);
189
+ }
190
+ /**
191
+ * Destroy the reader
192
+ *
193
+ * Cleans up resources and prevents further processing.
194
+ */
195
+ destroy() {
196
+ this.destroyed = true;
197
+ this.buffer = Buffer.alloc(0);
198
+ this.removeAllListeners();
199
+ }
200
+ /**
201
+ * Check if reader is destroyed
202
+ *
203
+ * @returns true if destroyed
204
+ */
205
+ isDestroyed() {
206
+ return this.destroyed;
207
+ }
208
+ }
209
+ //# sourceMappingURL=StdioMessageReader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StdioMessageReader.js","sourceRoot":"","sources":["../../src/utils/StdioMessageReader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Stdio Message Writer
3
+ *
4
+ * Writes Content-Length framed messages to a stream (LSP-style).
5
+ * Ensures reliable message delivery even when other output is written to the stream.
6
+ *
7
+ * Message format:
8
+ * ```
9
+ * Content-Length: 67\r\n
10
+ * \r\n
11
+ * {"jsonrpc":"2.0","id":1,"result":{"value":42}}
12
+ * ```
13
+ *
14
+ * @module utils/StdioMessageWriter
15
+ */
16
+ import type { Writable } from 'stream';
17
+ /**
18
+ * Message writer for Content-Length framed messages
19
+ *
20
+ * Implements the LSP (Language Server Protocol) message framing format.
21
+ * Automatically calculates content length and formats headers.
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * const writer = new StdioMessageWriter(process.stdout);
26
+ *
27
+ * // Write a JSON-RPC message
28
+ * await writer.write({
29
+ * jsonrpc: '2.0',
30
+ * id: 1,
31
+ * result: { value: 42 }
32
+ * });
33
+ * ```
34
+ */
35
+ export declare class StdioMessageWriter {
36
+ /**
37
+ * Output stream
38
+ */
39
+ private readonly stream;
40
+ /**
41
+ * Whether the writer has been destroyed
42
+ */
43
+ private destroyed;
44
+ /**
45
+ * Header separator
46
+ */
47
+ private static readonly HEADER_SEPARATOR;
48
+ /**
49
+ * Create a new message writer
50
+ *
51
+ * @param stream - Output stream (typically stdout)
52
+ */
53
+ constructor(stream: Writable);
54
+ /**
55
+ * Write a framed message to the stream
56
+ *
57
+ * Serializes the message to JSON, calculates byte length, formats
58
+ * Content-Length header, and writes everything to the stream.
59
+ *
60
+ * @param message - Message object to write (will be JSON-stringified)
61
+ * @returns Promise that resolves when message is fully written
62
+ *
63
+ * @throws {Error} If writer is destroyed or write fails
64
+ *
65
+ * @example
66
+ * ```typescript
67
+ * await writer.write({
68
+ * jsonrpc: '2.0',
69
+ * id: 1,
70
+ * method: 'invoke',
71
+ * params: { toolName: 'add', toolInput: { a: 5, b: 3 } }
72
+ * });
73
+ * ```
74
+ */
75
+ write(message: Record<string, unknown>): Promise<void>;
76
+ /**
77
+ * Flush the stream
78
+ *
79
+ * Ensures all buffered data is written to the underlying stream.
80
+ *
81
+ * @returns Promise that resolves when flush is complete
82
+ */
83
+ flush(): Promise<void>;
84
+ /**
85
+ * Destroy the writer
86
+ *
87
+ * Cleans up resources. After calling destroy(), the writer cannot be used.
88
+ * Note: This does NOT close the underlying stream.
89
+ */
90
+ destroy(): void;
91
+ /**
92
+ * Check if writer is destroyed
93
+ *
94
+ * @returns true if destroyed
95
+ */
96
+ isDestroyed(): boolean;
97
+ /**
98
+ * Get the underlying stream
99
+ *
100
+ * @returns The writable stream
101
+ */
102
+ getStream(): Writable;
103
+ }
104
+ //# sourceMappingURL=StdioMessageWriter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StdioMessageWriter.d.ts","sourceRoot":"","sources":["../../src/utils/StdioMessageWriter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAEvC;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,kBAAkB;IAC7B;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAW;IAElC;;OAEG;IACH,OAAO,CAAC,SAAS,CAAS;IAE1B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAU;IAElD;;;;OAIG;gBACS,MAAM,EAAE,QAAQ;IAI5B;;;;;;;;;;;;;;;;;;;;OAoBG;IACG,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAqC5D;;;;;;OAMG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAwB5B;;;;;OAKG;IACH,OAAO,IAAI,IAAI;IAIf;;;;OAIG;IACH,WAAW,IAAI,OAAO;IAItB;;;;OAIG;IACH,SAAS,IAAI,QAAQ;CAGtB"}