@kadi.build/core 0.0.1-alpha.9 → 0.1.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/README.md +362 -1305
- package/dist/client.d.ts +573 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +1673 -0
- package/dist/client.js.map +1 -0
- package/dist/errors.d.ts +107 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +147 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +37 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +40 -23
- package/dist/index.js.map +1 -1
- package/dist/lockfile.d.ts +190 -0
- package/dist/lockfile.d.ts.map +1 -0
- package/dist/lockfile.js +373 -0
- package/dist/lockfile.js.map +1 -0
- package/dist/transports/broker.d.ts +75 -0
- package/dist/transports/broker.d.ts.map +1 -0
- package/dist/transports/broker.js +383 -0
- package/dist/transports/broker.js.map +1 -0
- package/dist/transports/native.d.ts +39 -0
- package/dist/transports/native.d.ts.map +1 -0
- package/dist/transports/native.js +189 -0
- package/dist/transports/native.js.map +1 -0
- package/dist/transports/stdio.d.ts +46 -0
- package/dist/transports/stdio.d.ts.map +1 -0
- package/dist/transports/stdio.js +460 -0
- package/dist/transports/stdio.js.map +1 -0
- package/dist/types.d.ts +664 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +16 -0
- package/dist/types.js.map +1 -0
- package/dist/zod.d.ts +34 -0
- package/dist/zod.d.ts.map +1 -0
- package/dist/zod.js +60 -0
- package/dist/zod.js.map +1 -0
- package/package.json +13 -28
- package/dist/KadiClient.d.ts +0 -470
- package/dist/KadiClient.d.ts.map +0 -1
- package/dist/KadiClient.js +0 -1572
- package/dist/KadiClient.js.map +0 -1
- package/dist/errors/error-codes.d.ts +0 -985
- package/dist/errors/error-codes.d.ts.map +0 -1
- package/dist/errors/error-codes.js +0 -638
- package/dist/errors/error-codes.js.map +0 -1
- package/dist/loadAbility.d.ts +0 -105
- package/dist/loadAbility.d.ts.map +0 -1
- package/dist/loadAbility.js +0 -370
- package/dist/loadAbility.js.map +0 -1
- package/dist/messages/BrokerMessages.d.ts +0 -84
- package/dist/messages/BrokerMessages.d.ts.map +0 -1
- package/dist/messages/BrokerMessages.js +0 -125
- package/dist/messages/BrokerMessages.js.map +0 -1
- package/dist/messages/MessageBuilder.d.ts +0 -83
- package/dist/messages/MessageBuilder.d.ts.map +0 -1
- package/dist/messages/MessageBuilder.js +0 -144
- package/dist/messages/MessageBuilder.js.map +0 -1
- package/dist/schemas/events.schemas.d.ts +0 -177
- package/dist/schemas/events.schemas.d.ts.map +0 -1
- package/dist/schemas/events.schemas.js +0 -265
- package/dist/schemas/events.schemas.js.map +0 -1
- package/dist/schemas/index.d.ts +0 -3
- package/dist/schemas/index.d.ts.map +0 -1
- package/dist/schemas/index.js +0 -4
- package/dist/schemas/index.js.map +0 -1
- package/dist/schemas/kadi.schemas.d.ts +0 -70
- package/dist/schemas/kadi.schemas.d.ts.map +0 -1
- package/dist/schemas/kadi.schemas.js +0 -120
- package/dist/schemas/kadi.schemas.js.map +0 -1
- package/dist/transports/BrokerTransport.d.ts +0 -102
- package/dist/transports/BrokerTransport.d.ts.map +0 -1
- package/dist/transports/BrokerTransport.js +0 -177
- package/dist/transports/BrokerTransport.js.map +0 -1
- package/dist/transports/NativeTransport.d.ts +0 -82
- package/dist/transports/NativeTransport.d.ts.map +0 -1
- package/dist/transports/NativeTransport.js +0 -263
- package/dist/transports/NativeTransport.js.map +0 -1
- package/dist/transports/StdioTransport.d.ts +0 -112
- package/dist/transports/StdioTransport.d.ts.map +0 -1
- package/dist/transports/StdioTransport.js +0 -450
- package/dist/transports/StdioTransport.js.map +0 -1
- package/dist/transports/Transport.d.ts +0 -93
- package/dist/transports/Transport.d.ts.map +0 -1
- package/dist/transports/Transport.js +0 -13
- package/dist/transports/Transport.js.map +0 -1
- package/dist/types/broker.d.ts +0 -31
- package/dist/types/broker.d.ts.map +0 -1
- package/dist/types/broker.js +0 -6
- package/dist/types/broker.js.map +0 -1
- package/dist/types/core.d.ts +0 -139
- package/dist/types/core.d.ts.map +0 -1
- package/dist/types/core.js +0 -26
- package/dist/types/core.js.map +0 -1
- package/dist/types/events.d.ts +0 -186
- package/dist/types/events.d.ts.map +0 -1
- package/dist/types/events.js +0 -16
- package/dist/types/events.js.map +0 -1
- package/dist/types/index.d.ts +0 -9
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js +0 -13
- package/dist/types/index.js.map +0 -1
- package/dist/types/protocol.d.ts +0 -160
- package/dist/types/protocol.d.ts.map +0 -1
- package/dist/types/protocol.js +0 -5
- package/dist/types/protocol.js.map +0 -1
- package/dist/utils/agentUtils.d.ts +0 -187
- package/dist/utils/agentUtils.d.ts.map +0 -1
- package/dist/utils/agentUtils.js +0 -185
- package/dist/utils/agentUtils.js.map +0 -1
- package/dist/utils/commandUtils.d.ts +0 -45
- package/dist/utils/commandUtils.d.ts.map +0 -1
- package/dist/utils/commandUtils.js +0 -145
- package/dist/utils/commandUtils.js.map +0 -1
- package/dist/utils/configUtils.d.ts +0 -55
- package/dist/utils/configUtils.d.ts.map +0 -1
- package/dist/utils/configUtils.js +0 -100
- package/dist/utils/configUtils.js.map +0 -1
- package/dist/utils/logger.d.ts +0 -59
- package/dist/utils/logger.d.ts.map +0 -1
- package/dist/utils/logger.js +0 -122
- package/dist/utils/logger.js.map +0 -1
- package/dist/utils/pathUtils.d.ts +0 -48
- package/dist/utils/pathUtils.d.ts.map +0 -1
- package/dist/utils/pathUtils.js +0 -128
- package/dist/utils/pathUtils.js.map +0 -1
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lock file resolution for kadi-core v0.1.0
|
|
3
|
+
*
|
|
4
|
+
* This module handles reading agent-lock.json and resolving ability paths.
|
|
5
|
+
* The lock file is generated by kadi-install and contains:
|
|
6
|
+
* - Exact versions of installed abilities
|
|
7
|
+
* - Paths where abilities are installed
|
|
8
|
+
* - Integrity hashes for verification
|
|
9
|
+
*
|
|
10
|
+
* Flow:
|
|
11
|
+
* 1. Find project root (where agent.json lives)
|
|
12
|
+
* 2. Read agent-lock.json from project root
|
|
13
|
+
* 3. Look up ability by name to get its installed path
|
|
14
|
+
*/
|
|
15
|
+
import type { AgentLockFile, AbilityLockEntry, ResolvedScript } from './types.js';
|
|
16
|
+
/**
|
|
17
|
+
* Find the project root by walking up the directory tree.
|
|
18
|
+
* Looks for agent.json, which marks the root of a KADI project.
|
|
19
|
+
*
|
|
20
|
+
* @param startDir - Directory to start searching from (default: process.cwd())
|
|
21
|
+
* @returns Absolute path to the project root
|
|
22
|
+
* @throws KadiError if no agent.json is found
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* const root = await findProjectRoot();
|
|
27
|
+
* // '/Users/kassi/my-project'
|
|
28
|
+
*
|
|
29
|
+
* const root = await findProjectRoot('/Users/kassi/my-project/src/deep/folder');
|
|
30
|
+
* // '/Users/kassi/my-project'
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export declare function findProjectRoot(startDir?: string): Promise<string>;
|
|
34
|
+
/**
|
|
35
|
+
* Read and parse agent-lock.json from a project root.
|
|
36
|
+
*
|
|
37
|
+
* @param projectRoot - Absolute path to the project root
|
|
38
|
+
* @returns Parsed lock file contents
|
|
39
|
+
* @throws KadiError if lock file doesn't exist or is invalid
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* const lockFile = await readLockFile('/Users/kassi/my-project');
|
|
44
|
+
* console.log(lockFile.abilities);
|
|
45
|
+
* // { 'calculator@1.0.0': { resolved: 'abilities/calculator@1.0.0', ... } }
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export declare function readLockFile(projectRoot: string): Promise<AgentLockFile>;
|
|
49
|
+
/**
|
|
50
|
+
* Find an ability entry in the lock file by name.
|
|
51
|
+
* Keys in the lock file are "name@version", this function matches by name only.
|
|
52
|
+
*
|
|
53
|
+
* @param lockFile - The parsed lock file
|
|
54
|
+
* @param name - Ability name to find (without version)
|
|
55
|
+
* @returns The ability entry, or null if not found
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```typescript
|
|
59
|
+
* const entry = findAbilityEntry(lockFile, 'calculator');
|
|
60
|
+
* // Returns entry for 'calculator@1.0.0' (or whatever version is installed)
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export declare function findAbilityEntry(lockFile: AgentLockFile, name: string): AbilityLockEntry | null;
|
|
64
|
+
/**
|
|
65
|
+
* Get all installed ability names from the lock file.
|
|
66
|
+
* Useful for error messages listing available abilities.
|
|
67
|
+
*
|
|
68
|
+
* @param lockFile - The parsed lock file
|
|
69
|
+
* @returns Array of ability names (without versions)
|
|
70
|
+
*/
|
|
71
|
+
export declare function getInstalledAbilityNames(lockFile: AgentLockFile): string[];
|
|
72
|
+
/**
|
|
73
|
+
* Resolve the absolute path to an installed ability.
|
|
74
|
+
* This is the main function used by loadNative() and loadStdio().
|
|
75
|
+
*
|
|
76
|
+
* Flow:
|
|
77
|
+
* 1. Find project root (if not provided)
|
|
78
|
+
* 2. Read agent-lock.json
|
|
79
|
+
* 3. Look up ability by name
|
|
80
|
+
* 4. Return absolute path to the ability
|
|
81
|
+
*
|
|
82
|
+
* @param name - Ability name to resolve
|
|
83
|
+
* @param projectRoot - Project root (will be auto-detected if not provided)
|
|
84
|
+
* @returns Absolute path to the ability directory
|
|
85
|
+
* @throws KadiError if ability not found
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```typescript
|
|
89
|
+
* const path = await resolveAbilityPath('calculator');
|
|
90
|
+
* // '/Users/kassi/my-project/abilities/calculator@1.0.0'
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
export declare function resolveAbilityPath(name: string, projectRoot?: string): Promise<string>;
|
|
94
|
+
/**
|
|
95
|
+
* Get full ability entry with resolved path.
|
|
96
|
+
* Returns more information than resolveAbilityPath() for cases where
|
|
97
|
+
* you need the version, type, or other metadata.
|
|
98
|
+
*
|
|
99
|
+
* @param name - Ability name to resolve
|
|
100
|
+
* @param projectRoot - Project root (will be auto-detected if not provided)
|
|
101
|
+
* @returns Ability entry with absolute path added
|
|
102
|
+
*/
|
|
103
|
+
export declare function resolveAbilityEntry(name: string, projectRoot?: string): Promise<AbilityLockEntry & {
|
|
104
|
+
absolutePath: string;
|
|
105
|
+
}>;
|
|
106
|
+
/**
|
|
107
|
+
* Parsed script command ready for spawning a child process.
|
|
108
|
+
*/
|
|
109
|
+
interface ParsedScript {
|
|
110
|
+
/** The command to execute (e.g., 'python3', 'node') */
|
|
111
|
+
command: string;
|
|
112
|
+
/** Arguments to pass to the command */
|
|
113
|
+
args: string[];
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Parse a script string into command and arguments.
|
|
117
|
+
*
|
|
118
|
+
* This is a simple parser that splits on whitespace.
|
|
119
|
+
* For most use cases (e.g., "python3 main.py --debug"), this works fine.
|
|
120
|
+
*
|
|
121
|
+
* Note: Does not handle quoted arguments with spaces (e.g., "node 'my file.js'").
|
|
122
|
+
* For complex cases, users should use explicit command/args.
|
|
123
|
+
*
|
|
124
|
+
* @param script - Script string from agent.json (e.g., "python3 main.py --verbose")
|
|
125
|
+
* @returns Parsed command and arguments
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* ```typescript
|
|
129
|
+
* parseScriptCommand('python3 main.py --debug')
|
|
130
|
+
* // → { command: 'python3', args: ['main.py', '--debug'] }
|
|
131
|
+
*
|
|
132
|
+
* parseScriptCommand('node dist/server.js')
|
|
133
|
+
* // → { command: 'node', args: ['dist/server.js'] }
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
export declare function parseScriptCommand(script: string): ParsedScript;
|
|
137
|
+
/**
|
|
138
|
+
* Minimal agent.json structure for script resolution.
|
|
139
|
+
* We only need the scripts section.
|
|
140
|
+
*/
|
|
141
|
+
interface AbilityAgentJson {
|
|
142
|
+
name?: string;
|
|
143
|
+
scripts?: Record<string, string>;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Read an ability's agent.json file.
|
|
147
|
+
*
|
|
148
|
+
* @param abilityPath - Absolute path to the ability directory
|
|
149
|
+
* @returns Parsed agent.json contents
|
|
150
|
+
* @throws KadiError if agent.json doesn't exist or is invalid
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* ```typescript
|
|
154
|
+
* const agentJson = await readAbilityAgentJson('/path/to/ability');
|
|
155
|
+
* console.log(agentJson.scripts?.start);
|
|
156
|
+
* // → "python3 main.py"
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
export declare function readAbilityAgentJson(abilityPath: string): Promise<AbilityAgentJson>;
|
|
160
|
+
/**
|
|
161
|
+
* Resolve a script command for an ability.
|
|
162
|
+
*
|
|
163
|
+
* This is the main function used by loadStdio() when in script resolution mode.
|
|
164
|
+
*
|
|
165
|
+
* Flow:
|
|
166
|
+
* 1. Resolve ability path from agent-lock.json
|
|
167
|
+
* 2. Read ability's agent.json
|
|
168
|
+
* 3. Get the requested script (default: 'start')
|
|
169
|
+
* 4. Parse the script into command and args
|
|
170
|
+
* 5. Resolve paths relative to ability directory
|
|
171
|
+
*
|
|
172
|
+
* @param name - Ability name to resolve
|
|
173
|
+
* @param scriptName - Which script to use (default: 'start')
|
|
174
|
+
* @param projectRoot - Project root (auto-detected if not provided)
|
|
175
|
+
* @returns Command, args, and working directory for spawning the process
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```typescript
|
|
179
|
+
* // Uses scripts.start by default
|
|
180
|
+
* const { command, args, cwd } = await resolveAbilityScript('image-processor');
|
|
181
|
+
* // → { command: 'python3', args: ['main.py'], cwd: '/path/to/ability' }
|
|
182
|
+
*
|
|
183
|
+
* // Use a specific script
|
|
184
|
+
* const { command, args, cwd } = await resolveAbilityScript('image-processor', 'dev');
|
|
185
|
+
* // → { command: 'python3', args: ['main.py', '--debug'], cwd: '/path/to/ability' }
|
|
186
|
+
* ```
|
|
187
|
+
*/
|
|
188
|
+
export declare function resolveAbilityScript(name: string, scriptName?: string, projectRoot?: string): Promise<ResolvedScript>;
|
|
189
|
+
export {};
|
|
190
|
+
//# sourceMappingURL=lockfile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lockfile.d.ts","sourceRoot":"","sources":["../src/lockfile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAOlF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,eAAe,CAAC,QAAQ,GAAE,MAAsB,GAAG,OAAO,CAAC,MAAM,CAAC,CA0BvF;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CA+B9E;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,aAAa,EACvB,IAAI,EAAE,MAAM,GACX,gBAAgB,GAAG,IAAI,CAsBzB;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,EAAE,CAW1E;AAMD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EACZ,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,CAAC,CA6BjB;AAED;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,MAAM,EACZ,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,gBAAgB,GAAG;IAAE,YAAY,EAAE,MAAM,CAAA;CAAE,CAAC,CAyBtD;AAMD;;GAEG;AACH,UAAU,YAAY;IACpB,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAC;IAEhB,uCAAuC;IACvC,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,CAoC/D;AAED;;;GAGG;AACH,UAAU,gBAAgB;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA6BzF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,MAAM,EACZ,UAAU,GAAE,MAAgB,EAC5B,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,cAAc,CAAC,CAiDzB"}
|
package/dist/lockfile.js
ADDED
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lock file resolution for kadi-core v0.1.0
|
|
3
|
+
*
|
|
4
|
+
* This module handles reading agent-lock.json and resolving ability paths.
|
|
5
|
+
* The lock file is generated by kadi-install and contains:
|
|
6
|
+
* - Exact versions of installed abilities
|
|
7
|
+
* - Paths where abilities are installed
|
|
8
|
+
* - Integrity hashes for verification
|
|
9
|
+
*
|
|
10
|
+
* Flow:
|
|
11
|
+
* 1. Find project root (where agent.json lives)
|
|
12
|
+
* 2. Read agent-lock.json from project root
|
|
13
|
+
* 3. Look up ability by name to get its installed path
|
|
14
|
+
*/
|
|
15
|
+
import { readFile } from 'fs/promises';
|
|
16
|
+
import { join, dirname } from 'path';
|
|
17
|
+
import { KadiError } from './errors.js';
|
|
18
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
19
|
+
// PROJECT ROOT DISCOVERY
|
|
20
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
21
|
+
/**
|
|
22
|
+
* Find the project root by walking up the directory tree.
|
|
23
|
+
* Looks for agent.json, which marks the root of a KADI project.
|
|
24
|
+
*
|
|
25
|
+
* @param startDir - Directory to start searching from (default: process.cwd())
|
|
26
|
+
* @returns Absolute path to the project root
|
|
27
|
+
* @throws KadiError if no agent.json is found
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* const root = await findProjectRoot();
|
|
32
|
+
* // '/Users/kassi/my-project'
|
|
33
|
+
*
|
|
34
|
+
* const root = await findProjectRoot('/Users/kassi/my-project/src/deep/folder');
|
|
35
|
+
* // '/Users/kassi/my-project'
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export async function findProjectRoot(startDir = process.cwd()) {
|
|
39
|
+
let current = startDir;
|
|
40
|
+
// Walk up the directory tree looking for agent.json
|
|
41
|
+
while (current !== dirname(current)) {
|
|
42
|
+
const agentJsonPath = join(current, 'agent.json');
|
|
43
|
+
try {
|
|
44
|
+
// Try to read agent.json - if it exists, this is the project root
|
|
45
|
+
await readFile(agentJsonPath);
|
|
46
|
+
return current;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// File doesn't exist, try parent directory
|
|
50
|
+
current = dirname(current);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// Reached filesystem root without finding agent.json
|
|
54
|
+
throw new KadiError('Could not find project root', 'PROJECT_ROOT_NOT_FOUND', {
|
|
55
|
+
searched: startDir,
|
|
56
|
+
hint: 'Make sure you are in a KADI project directory with an agent.json file',
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
60
|
+
// LOCK FILE READING
|
|
61
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
62
|
+
/**
|
|
63
|
+
* Read and parse agent-lock.json from a project root.
|
|
64
|
+
*
|
|
65
|
+
* @param projectRoot - Absolute path to the project root
|
|
66
|
+
* @returns Parsed lock file contents
|
|
67
|
+
* @throws KadiError if lock file doesn't exist or is invalid
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```typescript
|
|
71
|
+
* const lockFile = await readLockFile('/Users/kassi/my-project');
|
|
72
|
+
* console.log(lockFile.abilities);
|
|
73
|
+
* // { 'calculator@1.0.0': { resolved: 'abilities/calculator@1.0.0', ... } }
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export async function readLockFile(projectRoot) {
|
|
77
|
+
const lockPath = join(projectRoot, 'agent-lock.json');
|
|
78
|
+
let content;
|
|
79
|
+
try {
|
|
80
|
+
content = await readFile(lockPath, 'utf-8');
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
throw new KadiError('agent-lock.json not found', 'LOCKFILE_NOT_FOUND', {
|
|
84
|
+
searched: lockPath,
|
|
85
|
+
hint: 'Run `kadi install` to generate the lock file',
|
|
86
|
+
alternative: 'Or specify an explicit path when loading abilities',
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
90
|
+
return JSON.parse(content);
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
throw new KadiError('Failed to parse agent-lock.json', 'LOCKFILE_PARSE_ERROR', {
|
|
94
|
+
path: lockPath,
|
|
95
|
+
reason: error instanceof Error ? error.message : 'Invalid JSON',
|
|
96
|
+
hint: 'The lock file may be corrupted. Try running `kadi install` again',
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
101
|
+
// ABILITY LOOKUP
|
|
102
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
103
|
+
/**
|
|
104
|
+
* Find an ability entry in the lock file by name.
|
|
105
|
+
* Keys in the lock file are "name@version", this function matches by name only.
|
|
106
|
+
*
|
|
107
|
+
* @param lockFile - The parsed lock file
|
|
108
|
+
* @param name - Ability name to find (without version)
|
|
109
|
+
* @returns The ability entry, or null if not found
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```typescript
|
|
113
|
+
* const entry = findAbilityEntry(lockFile, 'calculator');
|
|
114
|
+
* // Returns entry for 'calculator@1.0.0' (or whatever version is installed)
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
export function findAbilityEntry(lockFile, name) {
|
|
118
|
+
// Lock file keys are "name@version", we need to match by name only
|
|
119
|
+
for (const [key, entry] of Object.entries(lockFile.abilities)) {
|
|
120
|
+
// Find the last @ to split name from version
|
|
121
|
+
// (handles scoped packages like @kadi.build/ability@1.0.0)
|
|
122
|
+
const lastAtIndex = key.lastIndexOf('@');
|
|
123
|
+
if (lastAtIndex === -1) {
|
|
124
|
+
// No @ in key - shouldn't happen, but check anyway
|
|
125
|
+
if (key === name) {
|
|
126
|
+
return entry;
|
|
127
|
+
}
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
const abilityName = key.substring(0, lastAtIndex);
|
|
131
|
+
if (abilityName === name) {
|
|
132
|
+
return entry;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Get all installed ability names from the lock file.
|
|
139
|
+
* Useful for error messages listing available abilities.
|
|
140
|
+
*
|
|
141
|
+
* @param lockFile - The parsed lock file
|
|
142
|
+
* @returns Array of ability names (without versions)
|
|
143
|
+
*/
|
|
144
|
+
export function getInstalledAbilityNames(lockFile) {
|
|
145
|
+
const names = [];
|
|
146
|
+
for (const key of Object.keys(lockFile.abilities)) {
|
|
147
|
+
const lastAtIndex = key.lastIndexOf('@');
|
|
148
|
+
if (lastAtIndex !== -1) {
|
|
149
|
+
names.push(key.substring(0, lastAtIndex));
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return names;
|
|
153
|
+
}
|
|
154
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
155
|
+
// PATH RESOLUTION
|
|
156
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
157
|
+
/**
|
|
158
|
+
* Resolve the absolute path to an installed ability.
|
|
159
|
+
* This is the main function used by loadNative() and loadStdio().
|
|
160
|
+
*
|
|
161
|
+
* Flow:
|
|
162
|
+
* 1. Find project root (if not provided)
|
|
163
|
+
* 2. Read agent-lock.json
|
|
164
|
+
* 3. Look up ability by name
|
|
165
|
+
* 4. Return absolute path to the ability
|
|
166
|
+
*
|
|
167
|
+
* @param name - Ability name to resolve
|
|
168
|
+
* @param projectRoot - Project root (will be auto-detected if not provided)
|
|
169
|
+
* @returns Absolute path to the ability directory
|
|
170
|
+
* @throws KadiError if ability not found
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
* ```typescript
|
|
174
|
+
* const path = await resolveAbilityPath('calculator');
|
|
175
|
+
* // '/Users/kassi/my-project/abilities/calculator@1.0.0'
|
|
176
|
+
* ```
|
|
177
|
+
*/
|
|
178
|
+
export async function resolveAbilityPath(name, projectRoot) {
|
|
179
|
+
// Find project root if not provided
|
|
180
|
+
const root = projectRoot ?? await findProjectRoot();
|
|
181
|
+
// Read lock file
|
|
182
|
+
const lockFile = await readLockFile(root);
|
|
183
|
+
// Find ability entry
|
|
184
|
+
const entry = findAbilityEntry(lockFile, name);
|
|
185
|
+
if (!entry) {
|
|
186
|
+
// Build helpful error message with available abilities
|
|
187
|
+
const available = getInstalledAbilityNames(lockFile);
|
|
188
|
+
throw new KadiError(`Ability "${name}" not found in agent-lock.json`, 'ABILITY_NOT_FOUND', {
|
|
189
|
+
abilityName: name,
|
|
190
|
+
searched: join(root, 'agent-lock.json'),
|
|
191
|
+
available: available.length > 0 ? available : undefined,
|
|
192
|
+
hint: `Run \`kadi install ${name}\` to install it`,
|
|
193
|
+
alternative: 'Or specify an explicit path: { path: "./path/to/ability" }',
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
// Build absolute path from project root + relative path in lock file
|
|
197
|
+
return join(root, entry.resolved);
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Get full ability entry with resolved path.
|
|
201
|
+
* Returns more information than resolveAbilityPath() for cases where
|
|
202
|
+
* you need the version, type, or other metadata.
|
|
203
|
+
*
|
|
204
|
+
* @param name - Ability name to resolve
|
|
205
|
+
* @param projectRoot - Project root (will be auto-detected if not provided)
|
|
206
|
+
* @returns Ability entry with absolute path added
|
|
207
|
+
*/
|
|
208
|
+
export async function resolveAbilityEntry(name, projectRoot) {
|
|
209
|
+
const root = projectRoot ?? await findProjectRoot();
|
|
210
|
+
const lockFile = await readLockFile(root);
|
|
211
|
+
const entry = findAbilityEntry(lockFile, name);
|
|
212
|
+
if (!entry) {
|
|
213
|
+
const available = getInstalledAbilityNames(lockFile);
|
|
214
|
+
throw new KadiError(`Ability "${name}" not found in agent-lock.json`, 'ABILITY_NOT_FOUND', {
|
|
215
|
+
abilityName: name,
|
|
216
|
+
searched: join(root, 'agent-lock.json'),
|
|
217
|
+
available: available.length > 0 ? available : undefined,
|
|
218
|
+
hint: `Run \`kadi install ${name}\` to install it`,
|
|
219
|
+
alternative: 'Or specify an explicit path: { path: "./path/to/ability" }',
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
return {
|
|
223
|
+
...entry,
|
|
224
|
+
absolutePath: join(root, entry.resolved),
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Parse a script string into command and arguments.
|
|
229
|
+
*
|
|
230
|
+
* This is a simple parser that splits on whitespace.
|
|
231
|
+
* For most use cases (e.g., "python3 main.py --debug"), this works fine.
|
|
232
|
+
*
|
|
233
|
+
* Note: Does not handle quoted arguments with spaces (e.g., "node 'my file.js'").
|
|
234
|
+
* For complex cases, users should use explicit command/args.
|
|
235
|
+
*
|
|
236
|
+
* @param script - Script string from agent.json (e.g., "python3 main.py --verbose")
|
|
237
|
+
* @returns Parsed command and arguments
|
|
238
|
+
*
|
|
239
|
+
* @example
|
|
240
|
+
* ```typescript
|
|
241
|
+
* parseScriptCommand('python3 main.py --debug')
|
|
242
|
+
* // → { command: 'python3', args: ['main.py', '--debug'] }
|
|
243
|
+
*
|
|
244
|
+
* parseScriptCommand('node dist/server.js')
|
|
245
|
+
* // → { command: 'node', args: ['dist/server.js'] }
|
|
246
|
+
* ```
|
|
247
|
+
*/
|
|
248
|
+
export function parseScriptCommand(script) {
|
|
249
|
+
// Check for quotes — we can't handle these properly with simple split
|
|
250
|
+
// Users with complex commands should use explicit command/args
|
|
251
|
+
if (script.includes("'") || script.includes('"')) {
|
|
252
|
+
throw new KadiError('Script contains quotes which are not supported', 'INVALID_CONFIG', {
|
|
253
|
+
script,
|
|
254
|
+
hint: 'Scripts with quoted arguments cannot be parsed. Provide command and args separately.',
|
|
255
|
+
example: '{ command: "node", args: ["my file.js"] }',
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
// Trim and split on whitespace
|
|
259
|
+
const parts = script.trim().split(/\s+/);
|
|
260
|
+
// Extract command (first element)
|
|
261
|
+
const command = parts[0];
|
|
262
|
+
if (!command) {
|
|
263
|
+
throw new KadiError('Script is empty', 'INVALID_CONFIG', {
|
|
264
|
+
script,
|
|
265
|
+
hint: 'The script should contain a command (e.g., "python3 main.py")',
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
return {
|
|
269
|
+
command,
|
|
270
|
+
args: parts.slice(1),
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Read an ability's agent.json file.
|
|
275
|
+
*
|
|
276
|
+
* @param abilityPath - Absolute path to the ability directory
|
|
277
|
+
* @returns Parsed agent.json contents
|
|
278
|
+
* @throws KadiError if agent.json doesn't exist or is invalid
|
|
279
|
+
*
|
|
280
|
+
* @example
|
|
281
|
+
* ```typescript
|
|
282
|
+
* const agentJson = await readAbilityAgentJson('/path/to/ability');
|
|
283
|
+
* console.log(agentJson.scripts?.start);
|
|
284
|
+
* // → "python3 main.py"
|
|
285
|
+
* ```
|
|
286
|
+
*/
|
|
287
|
+
export async function readAbilityAgentJson(abilityPath) {
|
|
288
|
+
const agentJsonPath = join(abilityPath, 'agent.json');
|
|
289
|
+
let content;
|
|
290
|
+
try {
|
|
291
|
+
content = await readFile(agentJsonPath, 'utf-8');
|
|
292
|
+
}
|
|
293
|
+
catch (error) {
|
|
294
|
+
throw new KadiError(`Ability is missing agent.json`, 'ABILITY_LOAD_FAILED', {
|
|
295
|
+
path: agentJsonPath,
|
|
296
|
+
hint: 'The ability directory must contain an agent.json file with a scripts section',
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
try {
|
|
300
|
+
return JSON.parse(content);
|
|
301
|
+
}
|
|
302
|
+
catch (error) {
|
|
303
|
+
throw new KadiError(`Failed to parse ability's agent.json`, 'ABILITY_LOAD_FAILED', {
|
|
304
|
+
path: agentJsonPath,
|
|
305
|
+
reason: error instanceof Error ? error.message : 'Invalid JSON',
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Resolve a script command for an ability.
|
|
311
|
+
*
|
|
312
|
+
* This is the main function used by loadStdio() when in script resolution mode.
|
|
313
|
+
*
|
|
314
|
+
* Flow:
|
|
315
|
+
* 1. Resolve ability path from agent-lock.json
|
|
316
|
+
* 2. Read ability's agent.json
|
|
317
|
+
* 3. Get the requested script (default: 'start')
|
|
318
|
+
* 4. Parse the script into command and args
|
|
319
|
+
* 5. Resolve paths relative to ability directory
|
|
320
|
+
*
|
|
321
|
+
* @param name - Ability name to resolve
|
|
322
|
+
* @param scriptName - Which script to use (default: 'start')
|
|
323
|
+
* @param projectRoot - Project root (auto-detected if not provided)
|
|
324
|
+
* @returns Command, args, and working directory for spawning the process
|
|
325
|
+
*
|
|
326
|
+
* @example
|
|
327
|
+
* ```typescript
|
|
328
|
+
* // Uses scripts.start by default
|
|
329
|
+
* const { command, args, cwd } = await resolveAbilityScript('image-processor');
|
|
330
|
+
* // → { command: 'python3', args: ['main.py'], cwd: '/path/to/ability' }
|
|
331
|
+
*
|
|
332
|
+
* // Use a specific script
|
|
333
|
+
* const { command, args, cwd } = await resolveAbilityScript('image-processor', 'dev');
|
|
334
|
+
* // → { command: 'python3', args: ['main.py', '--debug'], cwd: '/path/to/ability' }
|
|
335
|
+
* ```
|
|
336
|
+
*/
|
|
337
|
+
export async function resolveAbilityScript(name, scriptName = 'start', projectRoot) {
|
|
338
|
+
// Step 1: Resolve ability path from agent-lock.json
|
|
339
|
+
const abilityPath = await resolveAbilityPath(name, projectRoot);
|
|
340
|
+
// Step 2: Read ability's agent.json
|
|
341
|
+
const agentJson = await readAbilityAgentJson(abilityPath);
|
|
342
|
+
// Step 3: Get the requested script
|
|
343
|
+
const scripts = agentJson.scripts;
|
|
344
|
+
if (!scripts) {
|
|
345
|
+
throw new KadiError(`Ability "${name}" has no scripts section in agent.json`, 'INVALID_CONFIG', {
|
|
346
|
+
abilityName: name,
|
|
347
|
+
agentJsonPath: join(abilityPath, 'agent.json'),
|
|
348
|
+
hint: 'Add a "scripts" section with a "start" script to agent.json',
|
|
349
|
+
example: '{ "scripts": { "start": "python3 main.py" } }',
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
const script = scripts[scriptName];
|
|
353
|
+
if (!script) {
|
|
354
|
+
// Build helpful error with available scripts
|
|
355
|
+
const availableScripts = Object.keys(scripts).filter(k => scripts[k]); // Filter out empty scripts
|
|
356
|
+
throw new KadiError(`Script "${scriptName}" not found in ability "${name}"`, 'INVALID_CONFIG', {
|
|
357
|
+
abilityName: name,
|
|
358
|
+
requestedScript: scriptName,
|
|
359
|
+
availableScripts: availableScripts.length > 0 ? availableScripts : undefined,
|
|
360
|
+
hint: availableScripts.length > 0
|
|
361
|
+
? `Available scripts: ${availableScripts.join(', ')}`
|
|
362
|
+
: 'Add scripts to the ability\'s agent.json',
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
// Step 4: Parse the script into command and args
|
|
366
|
+
const parsed = parseScriptCommand(script);
|
|
367
|
+
// Step 5: Return with ability path as working directory
|
|
368
|
+
return {
|
|
369
|
+
...parsed,
|
|
370
|
+
cwd: abilityPath,
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
//# sourceMappingURL=lockfile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lockfile.js","sourceRoot":"","sources":["../src/lockfile.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Broker transport for kadi-core v0.1.0
|
|
3
|
+
*
|
|
4
|
+
* Loads abilities that run on REMOTE agents connected to a broker.
|
|
5
|
+
* Communication happens via WebSocket using JSON-RPC.
|
|
6
|
+
*
|
|
7
|
+
* Protocol flow for invoking a remote tool:
|
|
8
|
+
* 1. Client sends kadi.ability.request → broker returns { status: 'pending', requestId }
|
|
9
|
+
* 2. Broker forwards request to provider agent
|
|
10
|
+
* 3. Provider executes tool and sends result back to broker
|
|
11
|
+
* 4. Broker sends kadi.ability.response notification with the actual result
|
|
12
|
+
*
|
|
13
|
+
* This transport doesn't manage the broker connection itself.
|
|
14
|
+
* It receives a BrokerState from KadiClient and uses it for communication.
|
|
15
|
+
*
|
|
16
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
17
|
+
* WORKAROUND NOTE: Ability Discovery
|
|
18
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
19
|
+
*
|
|
20
|
+
* The current broker is TOOL-CENTRIC (tracks tools, not abilities). There's no
|
|
21
|
+
* direct API to ask "What tools does agent X provide?"
|
|
22
|
+
*
|
|
23
|
+
* CURRENT WORKAROUND:
|
|
24
|
+
* 1. Call kadi.ability.list with includeProviders: true (fetches ALL tools)
|
|
25
|
+
* 2. Filter tools where provider.displayName matches the ability name
|
|
26
|
+
* 3. Use the provider's agentId for routing via _kadi hints
|
|
27
|
+
*
|
|
28
|
+
* FUTURE: When the broker implements kadi.agent.discover (see design doc at
|
|
29
|
+
* kadi-broker/docs/design/ABILITY_CENTRIC_DISCOVERY.md), replace the
|
|
30
|
+
* discoverAbilityWorkaround() function with a direct API call.
|
|
31
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
32
|
+
*/
|
|
33
|
+
import type { LoadedAbility, BrokerState } from '../types.js';
|
|
34
|
+
/**
|
|
35
|
+
* Options for creating a broker transport.
|
|
36
|
+
*/
|
|
37
|
+
export interface BrokerTransportOptions {
|
|
38
|
+
/** The broker connection to use */
|
|
39
|
+
broker: BrokerState;
|
|
40
|
+
/** Timeout for requests in milliseconds (default: 30000) */
|
|
41
|
+
requestTimeout?: number;
|
|
42
|
+
/** Networks to filter by when discovering (default: all) */
|
|
43
|
+
networks?: string[];
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Load a remote ability via broker.
|
|
47
|
+
*
|
|
48
|
+
* This discovers an agent providing the ability and returns a LoadedAbility
|
|
49
|
+
* interface that invokes tools via the broker, consistently routing to that
|
|
50
|
+
* specific agent.
|
|
51
|
+
*
|
|
52
|
+
* @param abilityName - Name of the ability to load (matches agent's displayName)
|
|
53
|
+
* @param options - Broker connection and options
|
|
54
|
+
* @returns LoadedAbility that can invoke tools remotely
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* // The broker state comes from KadiClient
|
|
59
|
+
* const brokerState = client.getBrokerState('production');
|
|
60
|
+
*
|
|
61
|
+
* // Load a remote ability
|
|
62
|
+
* const analyzer = await loadBrokerTransport('text-analyzer', {
|
|
63
|
+
* broker: brokerState,
|
|
64
|
+
* requestTimeout: 60000,
|
|
65
|
+
* });
|
|
66
|
+
*
|
|
67
|
+
* // Invoke tools on the remote agent
|
|
68
|
+
* const result = await analyzer.invoke('analyze', { text: 'hello' });
|
|
69
|
+
*
|
|
70
|
+
* // All invocations go to the same agent (consistent routing)
|
|
71
|
+
* const result2 = await analyzer.invoke('summarize', { text: 'world' });
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export declare function loadBrokerTransport(abilityName: string, options: BrokerTransportOptions): Promise<LoadedAbility>;
|
|
75
|
+
//# sourceMappingURL=broker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"broker.d.ts","sourceRoot":"","sources":["../../src/transports/broker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EACV,aAAa,EAEb,WAAW,EAGZ,MAAM,aAAa,CAAC;AAoDrB;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,mCAAmC;IACnC,MAAM,EAAE,WAAW,CAAC;IAEpB,4DAA4D;IAC5D,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAkUD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,aAAa,CAAC,CAoGxB"}
|