@kadi.build/core 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client.d.ts +84 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +239 -4
- package/dist/client.js.map +1 -1
- package/dist/crypto.d.ts +88 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +120 -0
- package/dist/crypto.js.map +1 -0
- package/dist/errors.d.ts +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +30 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +6 -1
- package/src/client.ts +2385 -0
- package/src/crypto.ts +153 -0
- package/src/errors.ts +292 -0
- package/src/index.ts +114 -0
- package/src/lockfile.ts +493 -0
- package/src/transports/broker.ts +682 -0
- package/src/transports/native.ts +307 -0
- package/src/transports/stdio.ts +580 -0
- package/src/types.ts +1042 -0
- package/src/zod.ts +69 -0
- package/tsconfig.json +52 -0
package/src/crypto.ts
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cryptographic utilities for KADI
|
|
3
|
+
*
|
|
4
|
+
* This module provides utilities for converting between Ed25519 signing keys
|
|
5
|
+
* and X25519 encryption keys.
|
|
6
|
+
*
|
|
7
|
+
* ## Background
|
|
8
|
+
*
|
|
9
|
+
* KADI uses Ed25519 keys for identity and authentication (signing).
|
|
10
|
+
* However, Ed25519 is a signing algorithm - it cannot encrypt data.
|
|
11
|
+
*
|
|
12
|
+
* X25519 is an encryption algorithm that allows:
|
|
13
|
+
* - Encrypting data so only the recipient can read it
|
|
14
|
+
* - Sealed boxes: sender encrypts with recipient's public key,
|
|
15
|
+
* only recipient's private key can decrypt
|
|
16
|
+
*
|
|
17
|
+
* Both algorithms use Curve25519 underneath, so an Ed25519 key
|
|
18
|
+
* can be mathematically converted to an X25519 key.
|
|
19
|
+
*
|
|
20
|
+
* @module crypto
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
// @ts-expect-error - ed2curve doesn't have type definitions
|
|
24
|
+
import ed2curve from 'ed2curve';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* X25519 encryption key pair.
|
|
28
|
+
*
|
|
29
|
+
* Used for public-key encryption (e.g., sealed boxes).
|
|
30
|
+
* Derived from Ed25519 signing keys.
|
|
31
|
+
*/
|
|
32
|
+
export interface EncryptionKeyPair {
|
|
33
|
+
/** X25519 public key (32 bytes) - share with others to receive encrypted messages */
|
|
34
|
+
publicKey: Uint8Array;
|
|
35
|
+
/** X25519 secret key (32 bytes) - keep private, used to decrypt messages */
|
|
36
|
+
secretKey: Uint8Array;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Convert an Ed25519 signing public key to an X25519 encryption public key.
|
|
41
|
+
*
|
|
42
|
+
* KADI uses Ed25519 keys for identity and authentication (signing).
|
|
43
|
+
* However, Ed25519 is a signing algorithm - it cannot encrypt data.
|
|
44
|
+
*
|
|
45
|
+
* X25519 is an encryption algorithm that allows:
|
|
46
|
+
* - Encrypting data so only the recipient can read it
|
|
47
|
+
* - Sealed boxes: sender encrypts with recipient's public key,
|
|
48
|
+
* only recipient's private key can decrypt
|
|
49
|
+
*
|
|
50
|
+
* Both algorithms use Curve25519 underneath, so an Ed25519 key
|
|
51
|
+
* can be mathematically converted to an X25519 key. This function
|
|
52
|
+
* performs that conversion.
|
|
53
|
+
*
|
|
54
|
+
* @param publicKey - Base64-encoded Ed25519 public key (SPKI DER format)
|
|
55
|
+
* @returns X25519 public key as Uint8Array (32 bytes)
|
|
56
|
+
* @throws Error if the public key is invalid
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```typescript
|
|
60
|
+
* import { convertToEncryptionKey } from '@kadi.build/core';
|
|
61
|
+
* import nacl from 'tweetnacl';
|
|
62
|
+
*
|
|
63
|
+
* // Convert agent's Ed25519 public key to X25519
|
|
64
|
+
* const encryptionKey = convertToEncryptionKey(agentPublicKey);
|
|
65
|
+
*
|
|
66
|
+
* // Now you can encrypt data for that agent using sealed box
|
|
67
|
+
* const encrypted = nacl.sealedbox.seal(message, encryptionKey);
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export function convertToEncryptionKey(publicKey: string): Uint8Array {
|
|
71
|
+
// Decode base64 SPKI DER format to raw bytes
|
|
72
|
+
const derBytes = Buffer.from(publicKey, 'base64');
|
|
73
|
+
|
|
74
|
+
// SPKI DER format for Ed25519 has a 12-byte header, raw key starts at offset 12
|
|
75
|
+
// Format: 30 2a 30 05 06 03 2b 65 70 03 21 00 [32-byte key]
|
|
76
|
+
const rawEd25519Key = derBytes.slice(12);
|
|
77
|
+
|
|
78
|
+
if (rawEd25519Key.length !== 32) {
|
|
79
|
+
throw new Error(
|
|
80
|
+
`Invalid Ed25519 public key: expected 32 bytes after SPKI header, got ${rawEd25519Key.length}`
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Convert Ed25519 public key to X25519 public key
|
|
85
|
+
const x25519Key = ed2curve.convertPublicKey(new Uint8Array(rawEd25519Key));
|
|
86
|
+
|
|
87
|
+
if (!x25519Key) {
|
|
88
|
+
throw new Error('Failed to convert Ed25519 public key to X25519');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return x25519Key;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Convert an Ed25519 signing key pair to an X25519 encryption key pair.
|
|
96
|
+
*
|
|
97
|
+
* This is used internally by KadiClient to derive encryption keys from
|
|
98
|
+
* its Ed25519 identity. The resulting key pair can be used with
|
|
99
|
+
* tweetnacl's box or sealedbox functions.
|
|
100
|
+
*
|
|
101
|
+
* @param privateKey - Ed25519 private key in PKCS8 DER format (Buffer)
|
|
102
|
+
* @param publicKey - Base64-encoded Ed25519 public key (SPKI DER format)
|
|
103
|
+
* @returns X25519 key pair for encryption/decryption
|
|
104
|
+
* @throws Error if the keys are invalid
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```typescript
|
|
108
|
+
* // Inside KadiClient
|
|
109
|
+
* const keyPair = convertToEncryptionKeyPair(this._privateKey, this._publicKeyBase64);
|
|
110
|
+
*
|
|
111
|
+
* // Decrypt a sealed box message
|
|
112
|
+
* const decrypted = nacl.sealedbox.open(encrypted, keyPair.publicKey, keyPair.secretKey);
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
export function convertToEncryptionKeyPair(
|
|
116
|
+
privateKey: Buffer,
|
|
117
|
+
publicKey: string
|
|
118
|
+
): EncryptionKeyPair {
|
|
119
|
+
// Get X25519 public key
|
|
120
|
+
const x25519PublicKey = convertToEncryptionKey(publicKey);
|
|
121
|
+
|
|
122
|
+
// PKCS8 DER format for Ed25519 has a header, raw key is at offset 16
|
|
123
|
+
// Format: 30 2e 02 01 00 30 05 06 03 2b 65 70 04 22 04 20 [32-byte seed]
|
|
124
|
+
// The seed is the first 32 bytes of the 64-byte Ed25519 secret key
|
|
125
|
+
const rawSeed = privateKey.slice(16, 48);
|
|
126
|
+
|
|
127
|
+
if (rawSeed.length !== 32) {
|
|
128
|
+
throw new Error(
|
|
129
|
+
`Invalid Ed25519 private key: expected 32-byte seed after PKCS8 header, got ${rawSeed.length}`
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Convert Ed25519 secret key (seed) to X25519 secret key
|
|
134
|
+
// ed2curve.convertSecretKey expects the 64-byte secret key, but we only have the seed
|
|
135
|
+
// We need to expand the seed first by creating the full 64-byte key
|
|
136
|
+
// The full Ed25519 secret key is: seed (32 bytes) + public key (32 bytes)
|
|
137
|
+
const derBytes = Buffer.from(publicKey, 'base64');
|
|
138
|
+
const rawPublicKey = derBytes.slice(12);
|
|
139
|
+
const fullSecretKey = new Uint8Array(64);
|
|
140
|
+
fullSecretKey.set(rawSeed, 0);
|
|
141
|
+
fullSecretKey.set(rawPublicKey, 32);
|
|
142
|
+
|
|
143
|
+
const x25519SecretKey = ed2curve.convertSecretKey(fullSecretKey);
|
|
144
|
+
|
|
145
|
+
if (!x25519SecretKey) {
|
|
146
|
+
throw new Error('Failed to convert Ed25519 secret key to X25519');
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return {
|
|
150
|
+
publicKey: x25519PublicKey,
|
|
151
|
+
secretKey: x25519SecretKey,
|
|
152
|
+
};
|
|
153
|
+
}
|
package/src/errors.ts
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error handling for kadi-core v0.1.0
|
|
3
|
+
*
|
|
4
|
+
* All errors in kadi-core use KadiError, which includes:
|
|
5
|
+
* - A human-readable message
|
|
6
|
+
* - An error code for programmatic handling
|
|
7
|
+
* - Context with additional details
|
|
8
|
+
* - Automatic formatting of hints and suggestions
|
|
9
|
+
*
|
|
10
|
+
* The goal is helpful errors that guide users to solutions.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
14
|
+
// ERROR CODES
|
|
15
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* All possible error codes.
|
|
19
|
+
* Use these for programmatic error handling.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* try {
|
|
24
|
+
* await client.connect();
|
|
25
|
+
* } catch (error) {
|
|
26
|
+
* if (error instanceof KadiError && error.code === 'CONNECTION_FAILED') {
|
|
27
|
+
* // Handle connection failure specifically
|
|
28
|
+
* }
|
|
29
|
+
* }
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export type ErrorCode =
|
|
33
|
+
// Connection errors
|
|
34
|
+
| 'CONNECTION_FAILED'
|
|
35
|
+
| 'AUTHENTICATION_FAILED'
|
|
36
|
+
| 'REGISTRATION_FAILED'
|
|
37
|
+
| 'BROKER_NOT_CONNECTED'
|
|
38
|
+
| 'BROKER_CONNECTION_FAILED'
|
|
39
|
+
| 'CONNECTION_CLOSED'
|
|
40
|
+
|
|
41
|
+
// Broker errors
|
|
42
|
+
| 'BROKER_ERROR'
|
|
43
|
+
| 'BROKER_TIMEOUT'
|
|
44
|
+
| 'BROKER_RESPONSE_ERROR'
|
|
45
|
+
| 'UNKNOWN_BROKER'
|
|
46
|
+
|
|
47
|
+
// Tool errors
|
|
48
|
+
| 'TOOL_NOT_FOUND'
|
|
49
|
+
| 'TOOL_ALREADY_REGISTERED'
|
|
50
|
+
| 'TOOL_INVOCATION_FAILED'
|
|
51
|
+
| 'TOOL_TIMEOUT'
|
|
52
|
+
| 'VALIDATION_FAILED'
|
|
53
|
+
|
|
54
|
+
// Ability errors
|
|
55
|
+
| 'ABILITY_NOT_FOUND'
|
|
56
|
+
| 'ABILITY_LOAD_FAILED'
|
|
57
|
+
| 'ABILITY_NOT_CONNECTED'
|
|
58
|
+
|
|
59
|
+
// Lock file errors
|
|
60
|
+
| 'LOCKFILE_NOT_FOUND'
|
|
61
|
+
| 'LOCKFILE_PARSE_ERROR'
|
|
62
|
+
|
|
63
|
+
// Config errors
|
|
64
|
+
| 'INVALID_CONFIG'
|
|
65
|
+
| 'INVALID_INPUT'
|
|
66
|
+
| 'PROJECT_ROOT_NOT_FOUND'
|
|
67
|
+
|
|
68
|
+
// Transport errors
|
|
69
|
+
| 'STDIO_ERROR'
|
|
70
|
+
| 'STDIO_PROCESS_FAILED'
|
|
71
|
+
| 'NATIVE_IMPORT_ERROR'
|
|
72
|
+
| 'TRANSPORT_SEND_FAILED'
|
|
73
|
+
|
|
74
|
+
// Secrets errors (Trusted Introducer pattern)
|
|
75
|
+
| 'SECRETS_NOT_CONNECTED'
|
|
76
|
+
| 'SECRETS_DECRYPTION_FAILED'
|
|
77
|
+
| 'SECRETS_REQUEST_FAILED'
|
|
78
|
+
| 'SECRETS_REJECTED'
|
|
79
|
+
| 'SECRETS_TIMEOUT'
|
|
80
|
+
|
|
81
|
+
// Generic
|
|
82
|
+
| 'TIMEOUT'
|
|
83
|
+
| 'INTERNAL_ERROR'
|
|
84
|
+
| 'UNKNOWN_ERROR'
|
|
85
|
+
| 'NOT_IMPLEMENTED';
|
|
86
|
+
|
|
87
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
88
|
+
// ERROR CONTEXT
|
|
89
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Additional context that can be attached to errors.
|
|
93
|
+
* All fields are optional - include what's helpful.
|
|
94
|
+
*/
|
|
95
|
+
export interface ErrorContext {
|
|
96
|
+
/** Hint for how to fix the error */
|
|
97
|
+
hint?: string;
|
|
98
|
+
|
|
99
|
+
/** Alternative approaches */
|
|
100
|
+
alternative?: string;
|
|
101
|
+
|
|
102
|
+
/** Path that was searched */
|
|
103
|
+
searched?: string;
|
|
104
|
+
|
|
105
|
+
/** List of available options */
|
|
106
|
+
available?: string[];
|
|
107
|
+
|
|
108
|
+
/** List of connected brokers */
|
|
109
|
+
connectedBrokers?: string[];
|
|
110
|
+
|
|
111
|
+
/** The broker name involved */
|
|
112
|
+
broker?: string;
|
|
113
|
+
|
|
114
|
+
/** The broker URL involved */
|
|
115
|
+
url?: string;
|
|
116
|
+
|
|
117
|
+
/** The tool name involved */
|
|
118
|
+
toolName?: string;
|
|
119
|
+
|
|
120
|
+
/** The ability name involved */
|
|
121
|
+
abilityName?: string;
|
|
122
|
+
|
|
123
|
+
/** The path involved */
|
|
124
|
+
path?: string;
|
|
125
|
+
|
|
126
|
+
/** The reason for the error */
|
|
127
|
+
reason?: string;
|
|
128
|
+
|
|
129
|
+
/** Any other context */
|
|
130
|
+
[key: string]: unknown;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
134
|
+
// KADI ERROR CLASS
|
|
135
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Custom error class for kadi-core.
|
|
139
|
+
*
|
|
140
|
+
* Features:
|
|
141
|
+
* - Error code for programmatic handling
|
|
142
|
+
* - Context object with additional details
|
|
143
|
+
* - Automatic formatting of helpful messages
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```typescript
|
|
147
|
+
* throw new KadiError(
|
|
148
|
+
* 'Ability "calculator" not found in agent-lock.json',
|
|
149
|
+
* 'ABILITY_NOT_FOUND',
|
|
150
|
+
* {
|
|
151
|
+
* searched: '/path/to/agent-lock.json',
|
|
152
|
+
* hint: 'Run `kadi install calculator` to install it',
|
|
153
|
+
* alternative: 'Or specify explicit path: { path: "./path" }',
|
|
154
|
+
* }
|
|
155
|
+
* );
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
158
|
+
export class KadiError extends Error {
|
|
159
|
+
/**
|
|
160
|
+
* Error code for programmatic handling.
|
|
161
|
+
*/
|
|
162
|
+
public readonly code: ErrorCode;
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Additional context about the error.
|
|
166
|
+
*/
|
|
167
|
+
public readonly context: ErrorContext;
|
|
168
|
+
|
|
169
|
+
constructor(message: string, code: ErrorCode, context: ErrorContext = {}) {
|
|
170
|
+
// Format the message with context appended
|
|
171
|
+
super(formatErrorMessage(message, context));
|
|
172
|
+
|
|
173
|
+
this.name = 'KadiError';
|
|
174
|
+
this.code = code;
|
|
175
|
+
this.context = context;
|
|
176
|
+
|
|
177
|
+
// Maintain proper stack trace in V8 environments
|
|
178
|
+
if (Error.captureStackTrace) {
|
|
179
|
+
Error.captureStackTrace(this, KadiError);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Create a KadiError from an unknown error.
|
|
185
|
+
* Useful for wrapping errors from external sources.
|
|
186
|
+
*
|
|
187
|
+
* @param error - The error to wrap
|
|
188
|
+
* @param code - Error code to use (default: 'UNKNOWN_ERROR')
|
|
189
|
+
* @param context - Additional context to add
|
|
190
|
+
*/
|
|
191
|
+
static from(
|
|
192
|
+
error: unknown,
|
|
193
|
+
code: ErrorCode = 'UNKNOWN_ERROR',
|
|
194
|
+
context: ErrorContext = {}
|
|
195
|
+
): KadiError {
|
|
196
|
+
// If it's already a KadiError, return it (don't double-wrap)
|
|
197
|
+
if (error instanceof KadiError) {
|
|
198
|
+
return error;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Extract message from various error types
|
|
202
|
+
let message: string;
|
|
203
|
+
if (error instanceof Error) {
|
|
204
|
+
message = error.message;
|
|
205
|
+
} else if (typeof error === 'string') {
|
|
206
|
+
message = error;
|
|
207
|
+
} else {
|
|
208
|
+
message = 'An unknown error occurred';
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return new KadiError(message, code, context);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Check if an error is a KadiError.
|
|
216
|
+
*/
|
|
217
|
+
static isKadiError(error: unknown): error is KadiError {
|
|
218
|
+
return error instanceof KadiError;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
223
|
+
// MESSAGE FORMATTING
|
|
224
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Format an error message with context appended.
|
|
228
|
+
* Creates a multi-line message that's easy to read in console output.
|
|
229
|
+
*
|
|
230
|
+
* @example
|
|
231
|
+
* Input:
|
|
232
|
+
* message: 'Ability "foo" not found'
|
|
233
|
+
* context: { searched: '/path', hint: 'Run kadi install foo' }
|
|
234
|
+
*
|
|
235
|
+
* Output:
|
|
236
|
+
* 'Ability "foo" not found
|
|
237
|
+
* Searched: /path
|
|
238
|
+
* Hint: Run kadi install foo'
|
|
239
|
+
*/
|
|
240
|
+
function formatErrorMessage(message: string, context: ErrorContext): string {
|
|
241
|
+
const lines: string[] = [message];
|
|
242
|
+
|
|
243
|
+
// Add context fields in a consistent order
|
|
244
|
+
if (context.searched) {
|
|
245
|
+
lines.push(` Searched: ${context.searched}`);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (context.path) {
|
|
249
|
+
lines.push(` Path: ${context.path}`);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (context.broker) {
|
|
253
|
+
lines.push(` Broker: ${context.broker}`);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (context.url) {
|
|
257
|
+
lines.push(` URL: ${context.url}`);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (context.reason) {
|
|
261
|
+
lines.push(` Reason: ${context.reason}`);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (context.connectedBrokers && context.connectedBrokers.length > 0) {
|
|
265
|
+
lines.push(` Connected brokers: ${context.connectedBrokers.join(', ')}`);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (context.available && context.available.length > 0) {
|
|
269
|
+
lines.push(` Available: ${context.available.join(', ')}`);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (context.hint) {
|
|
273
|
+
lines.push(` Hint: ${context.hint}`);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (context.alternative) {
|
|
277
|
+
lines.push(` Or: ${context.alternative}`);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return lines.join('\n');
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
284
|
+
// TYPE GUARD
|
|
285
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Check if a value is an Error object.
|
|
289
|
+
*/
|
|
290
|
+
export function isError(value: unknown): value is Error {
|
|
291
|
+
return value instanceof Error;
|
|
292
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* kadi-core v0.1.0
|
|
3
|
+
*
|
|
4
|
+
* A lean, readable SDK for building KADI agents.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { KadiClient, z } from 'kadi-core';
|
|
9
|
+
*
|
|
10
|
+
* const client = new KadiClient({
|
|
11
|
+
* name: 'my-agent',
|
|
12
|
+
* brokers: {
|
|
13
|
+
* production: 'ws://broker:8080',
|
|
14
|
+
* },
|
|
15
|
+
* defaultBroker: 'production',
|
|
16
|
+
* });
|
|
17
|
+
*
|
|
18
|
+
* client.registerTool({
|
|
19
|
+
* name: 'add',
|
|
20
|
+
* description: 'Add two numbers',
|
|
21
|
+
* input: z.object({ a: z.number(), b: z.number() }),
|
|
22
|
+
* }, async ({ a, b }) => ({ result: a + b }));
|
|
23
|
+
*
|
|
24
|
+
* await client.connect();
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
// Re-export Zod for schema definitions
|
|
29
|
+
export { z } from 'zod';
|
|
30
|
+
|
|
31
|
+
// Main client
|
|
32
|
+
export { KadiClient } from './client.js';
|
|
33
|
+
|
|
34
|
+
// Errors
|
|
35
|
+
export { KadiError } from './errors.js';
|
|
36
|
+
export type { ErrorCode, ErrorContext } from './errors.js';
|
|
37
|
+
|
|
38
|
+
// Types
|
|
39
|
+
export type {
|
|
40
|
+
// Configuration
|
|
41
|
+
ClientConfig,
|
|
42
|
+
ResolvedConfig,
|
|
43
|
+
|
|
44
|
+
// Tools
|
|
45
|
+
ToolDefinition,
|
|
46
|
+
ZodToolDefinition,
|
|
47
|
+
ToolHandler,
|
|
48
|
+
RegisteredTool,
|
|
49
|
+
JSONSchema,
|
|
50
|
+
RequestContext,
|
|
51
|
+
|
|
52
|
+
// Abilities
|
|
53
|
+
LoadedAbility,
|
|
54
|
+
InvokeOptions,
|
|
55
|
+
TransportType,
|
|
56
|
+
EventHandler,
|
|
57
|
+
|
|
58
|
+
// Options
|
|
59
|
+
RegisterToolOptions,
|
|
60
|
+
LoadOptions,
|
|
61
|
+
LoadNativeOptions,
|
|
62
|
+
LoadStdioOptions,
|
|
63
|
+
LoadBrokerOptions,
|
|
64
|
+
InvokeRemoteOptions,
|
|
65
|
+
|
|
66
|
+
// Broker
|
|
67
|
+
BrokerState,
|
|
68
|
+
BrokerStatus,
|
|
69
|
+
PendingRequest,
|
|
70
|
+
|
|
71
|
+
// Broker Events (Pub/Sub)
|
|
72
|
+
BrokerEvent,
|
|
73
|
+
BrokerEventHandler,
|
|
74
|
+
PublishOptions,
|
|
75
|
+
SubscribeOptions,
|
|
76
|
+
EmitOptions,
|
|
77
|
+
|
|
78
|
+
// JSON-RPC
|
|
79
|
+
JsonRpcRequest,
|
|
80
|
+
JsonRpcResponse,
|
|
81
|
+
JsonRpcNotification,
|
|
82
|
+
JsonRpcError,
|
|
83
|
+
JsonRpcMessage,
|
|
84
|
+
|
|
85
|
+
// Lock file
|
|
86
|
+
AgentLockFile,
|
|
87
|
+
AbilityLockEntry,
|
|
88
|
+
|
|
89
|
+
// Script resolution
|
|
90
|
+
ResolvedScript,
|
|
91
|
+
} from './types.js';
|
|
92
|
+
|
|
93
|
+
// Zod utilities
|
|
94
|
+
export { zodToJsonSchema, isZodSchema } from './zod.js';
|
|
95
|
+
|
|
96
|
+
// Lock file utilities
|
|
97
|
+
export {
|
|
98
|
+
findProjectRoot,
|
|
99
|
+
readLockFile,
|
|
100
|
+
findAbilityEntry,
|
|
101
|
+
resolveAbilityPath,
|
|
102
|
+
resolveAbilityEntry,
|
|
103
|
+
getInstalledAbilityNames,
|
|
104
|
+
} from './lockfile.js';
|
|
105
|
+
|
|
106
|
+
// Transports (for advanced use cases)
|
|
107
|
+
export { loadNativeTransport } from './transports/native.js';
|
|
108
|
+
export { loadStdioTransport } from './transports/stdio.js';
|
|
109
|
+
export { loadBrokerTransport } from './transports/broker.js';
|
|
110
|
+
export type { BrokerTransportOptions } from './transports/broker.js';
|
|
111
|
+
|
|
112
|
+
// Crypto utilities (Ed25519 to X25519 conversion)
|
|
113
|
+
export { convertToEncryptionKey, convertToEncryptionKeyPair } from './crypto.js';
|
|
114
|
+
export type { EncryptionKeyPair } from './crypto.js';
|