@kraken-ai/platform 0.0.4 → 0.0.7
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/{chunk-PPT6GGYL.js → chunk-FTLOWV2N.js} +244 -67
- package/dist/chunk-FTLOWV2N.js.map +1 -0
- package/dist/cli.js +1103 -374
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +416 -240
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1107 -368
- package/dist/index.d.ts +1107 -368
- package/dist/index.js +183 -172
- package/dist/index.js.map +1 -1
- package/dist/server.cjs +220 -45
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +265 -28
- package/dist/server.d.ts +265 -28
- package/dist/server.js +15 -20
- package/dist/server.js.map +1 -1
- package/package.json +20 -16
- package/dist/chunk-PPT6GGYL.js.map +0 -1
- package/dist/types-_lfbhFJH.d.cts +0 -451
- package/dist/types-_lfbhFJH.d.ts +0 -451
package/dist/cli.js
CHANGED
|
@@ -1,39 +1,328 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
|
-
import
|
|
4
|
+
import { execFile } from "child_process";
|
|
5
|
+
import { promisify } from "util";
|
|
6
|
+
import * as z11 from "zod";
|
|
7
|
+
|
|
8
|
+
// src/internal/secret-string.ts
|
|
9
|
+
import { inspect } from "util";
|
|
10
|
+
var SecretString = class {
|
|
11
|
+
#value;
|
|
12
|
+
constructor(value) {
|
|
13
|
+
this.#value = value;
|
|
14
|
+
}
|
|
15
|
+
unmasked() {
|
|
16
|
+
return this.#value;
|
|
17
|
+
}
|
|
18
|
+
toJSON() {
|
|
19
|
+
return "[REDACTED]";
|
|
20
|
+
}
|
|
21
|
+
toString() {
|
|
22
|
+
return "[REDACTED]";
|
|
23
|
+
}
|
|
24
|
+
[Symbol.toPrimitive]() {
|
|
25
|
+
return "[REDACTED]";
|
|
26
|
+
}
|
|
27
|
+
[inspect.custom]() {
|
|
28
|
+
return "SecretString([REDACTED])";
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
var unwrapSecret = (value) => value instanceof SecretString ? value.unmasked() : value;
|
|
32
|
+
|
|
33
|
+
// src/cli/api-keys.ts
|
|
34
|
+
var DURATION_RE = /^(\d+)(h|d|y)$/;
|
|
35
|
+
var parseDuration = (input) => {
|
|
36
|
+
const match = DURATION_RE.exec(input);
|
|
37
|
+
if (!match) return null;
|
|
38
|
+
const amount = Number(match[1]);
|
|
39
|
+
const unit = match[2];
|
|
40
|
+
const now = /* @__PURE__ */ new Date();
|
|
41
|
+
switch (unit) {
|
|
42
|
+
case "h":
|
|
43
|
+
return new Date(now.getTime() + amount * 36e5);
|
|
44
|
+
case "d":
|
|
45
|
+
return new Date(now.getTime() + amount * 864e5);
|
|
46
|
+
case "y":
|
|
47
|
+
return new Date(now.getTime() + amount * 365.25 * 864e5);
|
|
48
|
+
default:
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
var VALID_ENVIRONMENTS = /* @__PURE__ */ new Set(["dev", "staging", "prod"]);
|
|
53
|
+
var getAuthHeaders = (apiKey) => {
|
|
54
|
+
const secret = new SecretString(apiKey);
|
|
55
|
+
return { Authorization: `Bearer ${unwrapSecret(secret)}`, "Content-Type": "application/json" };
|
|
56
|
+
};
|
|
57
|
+
var collectErrorMessages = (err) => {
|
|
58
|
+
const parts = [];
|
|
59
|
+
let current = err;
|
|
60
|
+
while (current instanceof Error) {
|
|
61
|
+
if (current.message) parts.push(current.message);
|
|
62
|
+
current = current.cause;
|
|
63
|
+
}
|
|
64
|
+
return parts.join(": ");
|
|
65
|
+
};
|
|
66
|
+
var formatNetworkError = (err, baseUrl) => {
|
|
67
|
+
const msg = collectErrorMessages(err);
|
|
68
|
+
if (msg.includes("unknown scheme")) {
|
|
69
|
+
return `Invalid platform URL "${baseUrl}" \u2014 must start with https:// (or http:// for local dev).
|
|
70
|
+
Run \`kraken login\` to update your credentials.`;
|
|
71
|
+
}
|
|
72
|
+
if (msg.includes("ECONNREFUSED")) {
|
|
73
|
+
return `Could not connect to ${baseUrl} \u2014 is the platform running?
|
|
74
|
+
Check the URL or run \`kraken login\` to update it.`;
|
|
75
|
+
}
|
|
76
|
+
if (msg.includes("ENOTFOUND")) {
|
|
77
|
+
return `Could not resolve hostname for ${baseUrl} \u2014 check the URL.
|
|
78
|
+
Run \`kraken login\` to update your credentials.`;
|
|
79
|
+
}
|
|
80
|
+
if (msg.includes("abort") || msg.includes("TIMEOUT")) {
|
|
81
|
+
return `Request to ${baseUrl} timed out.
|
|
82
|
+
Check your network connection or try again.`;
|
|
83
|
+
}
|
|
84
|
+
return `Could not reach ${baseUrl}. Check that the platform is running and the URL is correct.
|
|
85
|
+
Run \`kraken login\` to update your credentials.`;
|
|
86
|
+
};
|
|
87
|
+
var normalizeBaseUrl = (baseUrl) => {
|
|
88
|
+
if (!/^https?:\/\//.test(baseUrl)) {
|
|
89
|
+
return `https://${baseUrl}`;
|
|
90
|
+
}
|
|
91
|
+
return baseUrl;
|
|
92
|
+
};
|
|
93
|
+
var fetchApi = async (deps, url, baseUrl, init) => {
|
|
94
|
+
const normalizedBase = normalizeBaseUrl(baseUrl);
|
|
95
|
+
const normalizedUrl = baseUrl !== normalizedBase ? url.replace(baseUrl, normalizedBase) : url;
|
|
96
|
+
try {
|
|
97
|
+
return await deps.fetch(normalizedUrl, init);
|
|
98
|
+
} catch (err) {
|
|
99
|
+
deps.log(`Error: ${formatNetworkError(err, normalizedBase)}`);
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
var handleCreate = async (parsed, deps) => {
|
|
104
|
+
const creds = deps.loadCredentials();
|
|
105
|
+
if (!creds?.apiKey || !creds?.baseUrl) {
|
|
106
|
+
deps.log("Error: not logged in. Run `kraken login` first.");
|
|
107
|
+
return 1;
|
|
108
|
+
}
|
|
109
|
+
const name = parsed.flags.name;
|
|
110
|
+
if (!name) {
|
|
111
|
+
deps.log(
|
|
112
|
+
"Error: --name is required.\n Usage: kraken api-keys create --name <name> [--env dev] [--expires 90d]"
|
|
113
|
+
);
|
|
114
|
+
return 1;
|
|
115
|
+
}
|
|
116
|
+
const environment = parsed.flags.env ?? "dev";
|
|
117
|
+
if (!VALID_ENVIRONMENTS.has(environment)) {
|
|
118
|
+
deps.log(`Error: invalid environment "${environment}". Must be one of: dev, staging, prod.`);
|
|
119
|
+
return 1;
|
|
120
|
+
}
|
|
121
|
+
let expiresAt;
|
|
122
|
+
if (parsed.flags.expires) {
|
|
123
|
+
const date = parseDuration(parsed.flags.expires);
|
|
124
|
+
if (!date) {
|
|
125
|
+
deps.log(
|
|
126
|
+
`Error: invalid duration "${parsed.flags.expires}". Use format like 90d, 24h, or 1y.`
|
|
127
|
+
);
|
|
128
|
+
return 1;
|
|
129
|
+
}
|
|
130
|
+
expiresAt = date.toISOString();
|
|
131
|
+
}
|
|
132
|
+
const res = await fetchApi(deps, `${creds.baseUrl}/api/v1/api-keys`, creds.baseUrl, {
|
|
133
|
+
method: "POST",
|
|
134
|
+
headers: getAuthHeaders(creds.apiKey),
|
|
135
|
+
body: JSON.stringify({ name, environment, expiresAt })
|
|
136
|
+
});
|
|
137
|
+
if (!res) return 1;
|
|
138
|
+
if (!res.ok) {
|
|
139
|
+
const body = await res.json();
|
|
140
|
+
deps.log(`Error: ${body.error ?? `request failed (${String(res.status)})`}`);
|
|
141
|
+
return 1;
|
|
142
|
+
}
|
|
143
|
+
const data = await res.json();
|
|
144
|
+
deps.log(`
|
|
145
|
+
API Key created successfully.
|
|
146
|
+
`);
|
|
147
|
+
deps.log(` Name: ${data.name}`);
|
|
148
|
+
deps.log(` Env: ${data.environment}`);
|
|
149
|
+
deps.log(` Key: ${data.key}`);
|
|
150
|
+
if (data.expiresAt) {
|
|
151
|
+
deps.log(` Expires: ${data.expiresAt}`);
|
|
152
|
+
}
|
|
153
|
+
deps.log(`
|
|
154
|
+
Copy this key now \u2014 it will not be shown again.
|
|
155
|
+
`);
|
|
156
|
+
return 0;
|
|
157
|
+
};
|
|
158
|
+
var handleList = async (parsed, deps) => {
|
|
159
|
+
const creds = deps.loadCredentials();
|
|
160
|
+
if (!creds?.apiKey || !creds?.baseUrl) {
|
|
161
|
+
deps.log("Error: not logged in. Run `kraken login` first.");
|
|
162
|
+
return 1;
|
|
163
|
+
}
|
|
164
|
+
const envFilter = parsed.flags.env;
|
|
165
|
+
const query = envFilter ? `?environment=${encodeURIComponent(envFilter)}` : "";
|
|
166
|
+
const res = await fetchApi(deps, `${creds.baseUrl}/api/v1/api-keys${query}`, creds.baseUrl, {
|
|
167
|
+
headers: getAuthHeaders(creds.apiKey)
|
|
168
|
+
});
|
|
169
|
+
if (!res) return 1;
|
|
170
|
+
if (!res.ok) {
|
|
171
|
+
const body = await res.json();
|
|
172
|
+
deps.log(`Error: ${body.error ?? `request failed (${String(res.status)})`}`);
|
|
173
|
+
return 1;
|
|
174
|
+
}
|
|
175
|
+
const keys = await res.json();
|
|
176
|
+
if (keys.length === 0) {
|
|
177
|
+
deps.log("No API keys found. Create one with: kraken api-keys create --name <name>");
|
|
178
|
+
return 0;
|
|
179
|
+
}
|
|
180
|
+
deps.log("\n API Keys:\n");
|
|
181
|
+
deps.log(
|
|
182
|
+
" ID Name Env Key Created Last Used Expires"
|
|
183
|
+
);
|
|
184
|
+
deps.log(` ${"\u2500".repeat(150)}`);
|
|
185
|
+
for (const k of keys) {
|
|
186
|
+
const expired = k.expired ? " (expired)" : "";
|
|
187
|
+
const lastUsed = k.lastUsed ? k.lastUsed.slice(0, 10) : "never";
|
|
188
|
+
const expires = k.expiresAt ? `${k.expiresAt.slice(0, 10)}${expired}` : "never";
|
|
189
|
+
deps.log(
|
|
190
|
+
` ${k.id} ${k.name.padEnd(16)}${k.environment.padEnd(10)}${k.prefix.padEnd(23)}${k.createdAt.slice(0, 10).padEnd(20)}${lastUsed.padEnd(20)}${expires}`
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
deps.log("");
|
|
194
|
+
return 0;
|
|
195
|
+
};
|
|
196
|
+
var handleRevoke = async (parsed, deps) => {
|
|
197
|
+
const creds = deps.loadCredentials();
|
|
198
|
+
if (!creds?.apiKey || !creds?.baseUrl) {
|
|
199
|
+
deps.log("Error: not logged in. Run `kraken login` first.");
|
|
200
|
+
return 1;
|
|
201
|
+
}
|
|
202
|
+
const id = parsed.positional[1];
|
|
203
|
+
if (!id) {
|
|
204
|
+
deps.log("Error: key ID is required.\n Usage: kraken api-keys revoke <id>");
|
|
205
|
+
return 1;
|
|
206
|
+
}
|
|
207
|
+
const res = await fetchApi(
|
|
208
|
+
deps,
|
|
209
|
+
`${creds.baseUrl}/api/v1/api-keys/${encodeURIComponent(id)}`,
|
|
210
|
+
creds.baseUrl,
|
|
211
|
+
{
|
|
212
|
+
method: "DELETE",
|
|
213
|
+
headers: getAuthHeaders(creds.apiKey)
|
|
214
|
+
}
|
|
215
|
+
);
|
|
216
|
+
if (!res) return 1;
|
|
217
|
+
if (res.status === 404) {
|
|
218
|
+
deps.log("Error: API key not found.");
|
|
219
|
+
return 1;
|
|
220
|
+
}
|
|
221
|
+
if (!res.ok) {
|
|
222
|
+
const body = await res.json();
|
|
223
|
+
deps.log(`Error: ${body.error ?? `request failed (${String(res.status)})`}`);
|
|
224
|
+
return 1;
|
|
225
|
+
}
|
|
226
|
+
deps.log("API key revoked successfully.");
|
|
227
|
+
return 0;
|
|
228
|
+
};
|
|
229
|
+
var handleApiKeys = async (parsed, deps) => {
|
|
230
|
+
const subcommand = parsed.positional[0];
|
|
231
|
+
switch (subcommand) {
|
|
232
|
+
case "create":
|
|
233
|
+
return handleCreate(parsed, deps);
|
|
234
|
+
case "list":
|
|
235
|
+
return handleList(parsed, deps);
|
|
236
|
+
case "revoke":
|
|
237
|
+
return handleRevoke(parsed, deps);
|
|
238
|
+
default:
|
|
239
|
+
deps.log(
|
|
240
|
+
`kraken api-keys \u2014 Manage API keys
|
|
241
|
+
|
|
242
|
+
Commands:
|
|
243
|
+
create --name <name> [--env dev] [--expires 90d] Create a new API key
|
|
244
|
+
list [--env dev|staging|prod] List API keys
|
|
245
|
+
revoke <id> Revoke an API key
|
|
246
|
+
`
|
|
247
|
+
);
|
|
248
|
+
return 0;
|
|
249
|
+
}
|
|
250
|
+
};
|
|
5
251
|
|
|
6
252
|
// src/cli/codegen.ts
|
|
7
253
|
import fs from "fs";
|
|
8
254
|
import path from "path";
|
|
9
255
|
|
|
10
|
-
//
|
|
11
|
-
var
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
256
|
+
// ../../../private-packages/platform-core/dist/qualified-name.js
|
|
257
|
+
var parse = (qualified) => {
|
|
258
|
+
const slashIndex = qualified.indexOf("/");
|
|
259
|
+
if (slashIndex === -1) {
|
|
260
|
+
throw new Error(`Expected qualified name with "/" separator, got: "${qualified}"`);
|
|
261
|
+
}
|
|
262
|
+
if (qualified.indexOf("/", slashIndex + 1) !== -1) {
|
|
263
|
+
throw new Error(`Expected exactly one "/" in qualified name, got: "${qualified}"`);
|
|
264
|
+
}
|
|
265
|
+
const repoName = qualified.slice(0, slashIndex);
|
|
266
|
+
const primitiveName = qualified.slice(slashIndex + 1);
|
|
267
|
+
if (!repoName || !primitiveName) {
|
|
268
|
+
throw new Error(`Both repo and primitive segments must be non-empty, got: "${qualified}"`);
|
|
269
|
+
}
|
|
270
|
+
return { repoName, primitiveName };
|
|
16
271
|
};
|
|
17
|
-
var
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
var cyan = code(36, 39);
|
|
23
|
-
var warn = (msg) => {
|
|
24
|
-
process.stderr.write(` ${dim("[kraken-ai:")} ${yellow("warn")}${dim("]")} ${msg}
|
|
25
|
-
`);
|
|
272
|
+
var isQualified = (name) => {
|
|
273
|
+
const slashIndex = name.indexOf("/");
|
|
274
|
+
if (slashIndex === -1 || slashIndex === 0 || slashIndex === name.length - 1)
|
|
275
|
+
return false;
|
|
276
|
+
return name.indexOf("/", slashIndex + 1) === -1;
|
|
26
277
|
};
|
|
27
278
|
|
|
28
|
-
//
|
|
29
|
-
|
|
30
|
-
var
|
|
279
|
+
// ../../../private-packages/platform-core/dist/types/environment.js
|
|
280
|
+
import * as z from "zod";
|
|
281
|
+
var environmentSchema = z.enum(["dev", "staging", "prod"]);
|
|
282
|
+
|
|
283
|
+
// ../../../private-packages/platform-core/dist/types/identity.js
|
|
284
|
+
import * as z2 from "zod";
|
|
285
|
+
var jitPolicySchema = z2.enum(["auto-approve", "policy-based", "require-approval"]);
|
|
286
|
+
var identityConfigSchema = z2.object({
|
|
287
|
+
basePermissions: z2.array(z2.string()),
|
|
288
|
+
requestablePermissions: z2.array(z2.string()).optional(),
|
|
289
|
+
jitPolicy: jitPolicySchema.optional(),
|
|
290
|
+
maxJitDurationMinutes: z2.number().int().positive().optional()
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
// ../../../private-packages/platform-core/dist/types/notifications.js
|
|
294
|
+
import * as z3 from "zod";
|
|
295
|
+
var notificationConfigSchema = z3.object({
|
|
296
|
+
slack: z3.string().optional(),
|
|
297
|
+
onSuccess: z3.boolean().optional(),
|
|
298
|
+
onFailure: z3.boolean().optional(),
|
|
299
|
+
onTimeout: z3.boolean().optional()
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
// ../../../private-packages/platform-core/dist/types/platform-agent.js
|
|
303
|
+
import * as z7 from "zod";
|
|
304
|
+
|
|
305
|
+
// ../../../private-packages/platform-core/dist/validate.js
|
|
306
|
+
var PRIMITIVE_NAME_REGEX = /^[a-z0-9][a-z0-9-]{0,62}[a-z0-9]$/;
|
|
307
|
+
var isValidPrimitiveName = (name) => name.length === 1 ? /^[a-z0-9]$/.test(name) : PRIMITIVE_NAME_REGEX.test(name);
|
|
31
308
|
var SKILL_NAME_REGEX = /^[a-zA-Z0-9][a-zA-Z0-9-]{0,62}[a-zA-Z0-9]$/;
|
|
32
309
|
var isValidSkillName = (basename) => basename.length === 1 ? /^[a-zA-Z0-9]$/.test(basename) : SKILL_NAME_REGEX.test(basename);
|
|
33
310
|
var isValidSkillId = (id) => {
|
|
34
311
|
const base = id.endsWith(".md") ? id.slice(0, -3) : id;
|
|
35
312
|
return isValidSkillName(base);
|
|
36
313
|
};
|
|
314
|
+
var isValidQualifiedName = (name) => {
|
|
315
|
+
if (!isQualified(name))
|
|
316
|
+
return false;
|
|
317
|
+
const { repoName, primitiveName } = parse(name);
|
|
318
|
+
return isValidPrimitiveName(repoName) && isValidPrimitiveName(primitiveName);
|
|
319
|
+
};
|
|
320
|
+
var isValidQualifiedSkillId = (id) => {
|
|
321
|
+
if (!isQualified(id))
|
|
322
|
+
return false;
|
|
323
|
+
const { repoName, primitiveName } = parse(id);
|
|
324
|
+
return isValidPrimitiveName(repoName) && isValidSkillId(primitiveName);
|
|
325
|
+
};
|
|
37
326
|
var TOOL_NAME_REGEX = /^[a-z][a-z0-9_-]{0,62}[a-z0-9]$/;
|
|
38
327
|
var isValidToolName = (name) => name.length === 1 ? /^[a-z]$/.test(name) : TOOL_NAME_REGEX.test(name);
|
|
39
328
|
var PROPERTY_NAME_REGEX = /^[a-zA-Z_$][a-zA-Z0-9_$]{0,254}$/;
|
|
@@ -47,38 +336,169 @@ var FORBIDDEN_PROPS = /* @__PURE__ */ new Set([
|
|
|
47
336
|
"__lookupSetter__"
|
|
48
337
|
]);
|
|
49
338
|
var isValidPropertyName = (name) => PROPERTY_NAME_REGEX.test(name) && !FORBIDDEN_PROPS.has(name);
|
|
339
|
+
|
|
340
|
+
// ../../../private-packages/platform-core/dist/types/resources.js
|
|
341
|
+
import * as z4 from "zod";
|
|
342
|
+
var resourceLimitsSchema = z4.object({
|
|
343
|
+
maxTokens: z4.number().int().positive().optional(),
|
|
344
|
+
maxCostUsd: z4.number().positive().optional(),
|
|
345
|
+
timeoutSeconds: z4.number().int().positive().optional()
|
|
346
|
+
});
|
|
347
|
+
var retryPolicySchema = z4.object({
|
|
348
|
+
maxAttempts: z4.number().int().min(1).optional(),
|
|
349
|
+
backoffSeconds: z4.number().positive().optional()
|
|
350
|
+
});
|
|
351
|
+
var concurrencyPolicySchema = z4.object({
|
|
352
|
+
maxParallelRuns: z4.number().int().min(1).optional()
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
// ../../../private-packages/platform-core/dist/types/team.js
|
|
356
|
+
import * as z5 from "zod";
|
|
357
|
+
var teamConfigSchema = z5.object({
|
|
358
|
+
members: z5.array(z5.string()).min(1),
|
|
359
|
+
maxConcurrentWorkers: z5.number().int().min(1).optional(),
|
|
360
|
+
maxTokenBudgetPerWorker: z5.number().int().positive().optional(),
|
|
361
|
+
maxDurationPerWorker: z5.number().positive().optional()
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
// ../../../private-packages/platform-core/dist/types/trigger.js
|
|
365
|
+
import * as z6 from "zod";
|
|
366
|
+
var cronTriggerSchema = z6.object({
|
|
367
|
+
type: z6.literal("cron"),
|
|
368
|
+
expression: z6.string(),
|
|
369
|
+
timezone: z6.string().optional()
|
|
370
|
+
});
|
|
371
|
+
var webhookTriggerSchema = z6.object({
|
|
372
|
+
type: z6.literal("webhook"),
|
|
373
|
+
path: z6.string().startsWith("/"),
|
|
374
|
+
method: z6.enum(["POST", "GET"]).optional()
|
|
375
|
+
});
|
|
376
|
+
var eventTriggerSchema = z6.object({
|
|
377
|
+
type: z6.literal("event"),
|
|
378
|
+
source: z6.string(),
|
|
379
|
+
event: z6.string()
|
|
380
|
+
});
|
|
381
|
+
var apiTriggerSchema = z6.object({ type: z6.literal("api") });
|
|
382
|
+
var manualTriggerSchema = z6.object({ type: z6.literal("manual") });
|
|
383
|
+
var triggerConfigSchema = z6.discriminatedUnion("type", [
|
|
384
|
+
cronTriggerSchema,
|
|
385
|
+
webhookTriggerSchema,
|
|
386
|
+
eventTriggerSchema,
|
|
387
|
+
apiTriggerSchema,
|
|
388
|
+
manualTriggerSchema
|
|
389
|
+
]);
|
|
390
|
+
|
|
391
|
+
// ../../../private-packages/platform-core/dist/types/platform-agent.js
|
|
392
|
+
var thinkingLevelSchema = z7.enum(["low", "medium", "high"]);
|
|
393
|
+
var logLevelSchema = z7.enum(["silent", "debug", "info", "warn", "error"]);
|
|
394
|
+
var agentDefinitionSchema = z7.object({
|
|
395
|
+
name: z7.string().min(1),
|
|
396
|
+
model: z7.string().min(1),
|
|
397
|
+
instructions: z7.string().min(1),
|
|
398
|
+
description: z7.string().optional(),
|
|
399
|
+
skills: z7.array(z7.string()).optional(),
|
|
400
|
+
temperature: z7.number().min(0).max(2).optional(),
|
|
401
|
+
allowTemperatureOverride: z7.boolean().optional(),
|
|
402
|
+
maxOutputTokens: z7.number().int().positive().optional(),
|
|
403
|
+
thinkingLevel: thinkingLevelSchema.optional(),
|
|
404
|
+
logLevel: logLevelSchema.optional()
|
|
405
|
+
}).strict();
|
|
406
|
+
var platformAgentConfigSchema = z7.object({
|
|
407
|
+
agent: agentDefinitionSchema,
|
|
408
|
+
connectors: z7.array(z7.string()).optional(),
|
|
409
|
+
triggers: z7.array(triggerConfigSchema),
|
|
410
|
+
identity: identityConfigSchema.optional(),
|
|
411
|
+
resources: resourceLimitsSchema.optional(),
|
|
412
|
+
retries: retryPolicySchema.optional(),
|
|
413
|
+
concurrency: concurrencyPolicySchema.optional(),
|
|
414
|
+
fast: z7.boolean().optional(),
|
|
415
|
+
team: teamConfigSchema.optional(),
|
|
416
|
+
notifications: notificationConfigSchema.optional(),
|
|
417
|
+
environment: environmentSchema.optional(),
|
|
418
|
+
actions: z7.array(z7.string()).optional()
|
|
419
|
+
}).strict().superRefine((data, ctx) => {
|
|
420
|
+
for (const member of data.team?.members ?? []) {
|
|
421
|
+
const valid = isQualified(member) ? isValidQualifiedName(member) : isValidPrimitiveName(member);
|
|
422
|
+
if (!valid) {
|
|
423
|
+
ctx.addIssue({
|
|
424
|
+
code: z7.ZodIssueCode.custom,
|
|
425
|
+
path: ["team", "members"],
|
|
426
|
+
message: `Invalid team member name: "${member}"`
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
for (const connector of data.connectors ?? []) {
|
|
431
|
+
const valid = isQualified(connector) ? isValidQualifiedName(connector) : isValidPrimitiveName(connector);
|
|
432
|
+
if (!valid) {
|
|
433
|
+
ctx.addIssue({
|
|
434
|
+
code: z7.ZodIssueCode.custom,
|
|
435
|
+
path: ["connectors"],
|
|
436
|
+
message: `Invalid connector name: "${connector}"`
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
for (const skill of data.agent.skills ?? []) {
|
|
441
|
+
const valid = isQualified(skill) ? isValidQualifiedSkillId(skill) : isValidSkillId(skill);
|
|
442
|
+
if (!valid) {
|
|
443
|
+
ctx.addIssue({
|
|
444
|
+
code: z7.ZodIssueCode.custom,
|
|
445
|
+
path: ["agent", "skills"],
|
|
446
|
+
message: `Invalid skill ID: "${skill}"`
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
for (const action of data.actions ?? []) {
|
|
451
|
+
const valid = isQualified(action) ? isValidQualifiedName(action) : isValidPrimitiveName(action);
|
|
452
|
+
if (!valid) {
|
|
453
|
+
ctx.addIssue({
|
|
454
|
+
code: z7.ZodIssueCode.custom,
|
|
455
|
+
path: ["actions"],
|
|
456
|
+
message: `Invalid action name: "${action}"`
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
// ../../../private-packages/platform-core/dist/types/skill.js
|
|
463
|
+
import * as z8 from "zod";
|
|
464
|
+
var platformSkillInputSchema = z8.object({
|
|
465
|
+
name: z8.string().min(1),
|
|
466
|
+
description: z8.string().optional()
|
|
467
|
+
}).strict();
|
|
468
|
+
|
|
469
|
+
// src/cli/validate.ts
|
|
50
470
|
var MAX_SCHEMA_DEPTH = 20;
|
|
51
471
|
var MAX_OBJECT_BREADTH = 200;
|
|
52
472
|
var validateSchemaBundle = (bundle) => {
|
|
53
473
|
for (const agent of bundle.agents) {
|
|
54
|
-
|
|
474
|
+
assertValidPrimitive("agent id", agent.id);
|
|
55
475
|
validateJsonSchemaProperties("agent input schema", agent.input, 0);
|
|
56
476
|
validateJsonSchemaProperties("agent output schema", agent.output, 0);
|
|
57
477
|
if (agent.actions) {
|
|
58
478
|
for (const [actionName, actionSchema] of Object.entries(agent.actions)) {
|
|
59
|
-
|
|
479
|
+
assertValidPrimitive("agent action name", actionName);
|
|
60
480
|
validateJsonSchemaProperties("agent action schema", actionSchema, 0);
|
|
61
481
|
}
|
|
62
482
|
}
|
|
63
483
|
}
|
|
64
484
|
for (const query of bundle.queries) {
|
|
65
|
-
|
|
485
|
+
assertValidPrimitive("query name", query.name);
|
|
66
486
|
validateJsonSchemaProperties("query params schema", query.params, 0);
|
|
67
487
|
for (const col of query.columns) {
|
|
68
488
|
assertValidProperty("query column name", col.name);
|
|
69
489
|
}
|
|
70
490
|
}
|
|
71
491
|
for (const connector of bundle.connectors) {
|
|
72
|
-
|
|
492
|
+
assertValidPrimitive("connector id", connector.id);
|
|
73
493
|
for (const tool of connector.tools) {
|
|
74
494
|
assertValidTool("connector tool name", tool.name);
|
|
75
495
|
validateJsonSchemaProperties("connector tool parameters", tool.parameters, 0);
|
|
76
496
|
}
|
|
77
497
|
}
|
|
78
498
|
for (const pipeline of bundle.pipelines) {
|
|
79
|
-
|
|
499
|
+
assertValidPrimitive("pipeline name", pipeline.pipeline);
|
|
80
500
|
for (const query of pipeline.queries) {
|
|
81
|
-
|
|
501
|
+
assertValidPrimitive("pipeline query name", query.name);
|
|
82
502
|
validatePipelineSchema("pipeline query params", query.params, 0);
|
|
83
503
|
validatePipelineSchema("pipeline query returns", query.returns, 0);
|
|
84
504
|
}
|
|
@@ -86,32 +506,34 @@ var validateSchemaBundle = (bundle) => {
|
|
|
86
506
|
for (const skill of bundle.skills) {
|
|
87
507
|
assertValidSkill("skill id", skill.id);
|
|
88
508
|
}
|
|
509
|
+
for (const action of bundle.actions) {
|
|
510
|
+
assertValidPrimitive("action id", action.id);
|
|
511
|
+
validateJsonSchemaProperties("action schema", action.schema, 0);
|
|
512
|
+
}
|
|
89
513
|
};
|
|
90
|
-
var
|
|
91
|
-
if (!
|
|
514
|
+
var assertValidPrimitive = (label, value) => {
|
|
515
|
+
if (!isValidPrimitiveName(value) && !isValidQualifiedName(value)) {
|
|
92
516
|
throw new Error(
|
|
93
|
-
`Invalid remote schema: ${
|
|
517
|
+
`Invalid remote schema: ${label} "${value}". Must match ${PRIMITIVE_NAME_REGEX} or repo/primitive format`
|
|
94
518
|
);
|
|
95
519
|
}
|
|
96
520
|
};
|
|
97
|
-
var assertValidTool = (
|
|
521
|
+
var assertValidTool = (label, value) => {
|
|
98
522
|
if (!isValidToolName(value)) {
|
|
99
|
-
throw new Error(
|
|
100
|
-
`Invalid remote schema: ${entityType} "${value}". Must match ${TOOL_NAME_REGEX}`
|
|
101
|
-
);
|
|
523
|
+
throw new Error(`Invalid remote schema: ${label} "${value}". Must match ${TOOL_NAME_REGEX}`);
|
|
102
524
|
}
|
|
103
525
|
};
|
|
104
|
-
var assertValidProperty = (
|
|
526
|
+
var assertValidProperty = (label, value) => {
|
|
105
527
|
if (!isValidPropertyName(value)) {
|
|
106
528
|
throw new Error(
|
|
107
|
-
`Invalid remote schema: ${
|
|
529
|
+
`Invalid remote schema: ${label} "${value}". Must match ${PROPERTY_NAME_REGEX} and not be a forbidden property`
|
|
108
530
|
);
|
|
109
531
|
}
|
|
110
532
|
};
|
|
111
|
-
var assertValidSkill = (
|
|
112
|
-
if (!isValidSkillId(value)) {
|
|
533
|
+
var assertValidSkill = (label, value) => {
|
|
534
|
+
if (!isValidSkillId(value) && !isValidQualifiedSkillId(value)) {
|
|
113
535
|
throw new Error(
|
|
114
|
-
`Invalid remote schema: ${
|
|
536
|
+
`Invalid remote schema: ${label} "${value}". Must match ${SKILL_NAME_REGEX} (with optional .md extension) or repo/skill format`
|
|
115
537
|
);
|
|
116
538
|
}
|
|
117
539
|
};
|
|
@@ -197,14 +619,10 @@ var generateTypes = (schemas, projectRoot) => {
|
|
|
197
619
|
if (!fs.existsSync(outDir)) {
|
|
198
620
|
fs.mkdirSync(outDir, { recursive: true });
|
|
199
621
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
"Migrated: removed .kraken-ai/pipelines.ts. Pipeline schemas now in pipelines.json + pipelines.d.ts."
|
|
205
|
-
);
|
|
206
|
-
}
|
|
207
|
-
fs.writeFileSync(path.join(outDir, "agents.d.ts"), generateAgentsDts(schemas.agents));
|
|
622
|
+
fs.writeFileSync(
|
|
623
|
+
path.join(outDir, "agents.d.ts"),
|
|
624
|
+
generateAgentsDts(schemas.agents, schemas.actions)
|
|
625
|
+
);
|
|
208
626
|
fs.writeFileSync(path.join(outDir, "queries.d.ts"), generateQueriesDts(schemas.queries));
|
|
209
627
|
const connectorsDtsPath = path.join(outDir, "connectors.d.ts");
|
|
210
628
|
if (schemas.connectors.length > 0) {
|
|
@@ -212,13 +630,20 @@ var generateTypes = (schemas, projectRoot) => {
|
|
|
212
630
|
} else if (fs.existsSync(connectorsDtsPath)) {
|
|
213
631
|
fs.rmSync(connectorsDtsPath);
|
|
214
632
|
}
|
|
633
|
+
const actionsDtsPath = path.join(outDir, "actions.d.ts");
|
|
634
|
+
if (schemas.actions.length > 0) {
|
|
635
|
+
fs.writeFileSync(actionsDtsPath, generateActionsDts(schemas.actions));
|
|
636
|
+
} else if (fs.existsSync(actionsDtsPath)) {
|
|
637
|
+
fs.rmSync(actionsDtsPath);
|
|
638
|
+
}
|
|
215
639
|
fs.writeFileSync(path.join(outDir, "pipelines.json"), generatePipelinesJson(schemas.pipelines));
|
|
216
640
|
fs.writeFileSync(path.join(outDir, "pipelines.d.ts"), generatePipelinesDts(schemas.pipelines));
|
|
217
641
|
const platformTypesDtsPath = path.join(outDir, "platform-types.d.ts");
|
|
218
642
|
const platformTypesDts = generatePlatformTypesDts(
|
|
219
643
|
schemas.agents,
|
|
220
644
|
schemas.connectors,
|
|
221
|
-
schemas.skills
|
|
645
|
+
schemas.skills,
|
|
646
|
+
schemas.actions
|
|
222
647
|
);
|
|
223
648
|
if (platformTypesDts) {
|
|
224
649
|
fs.writeFileSync(platformTypesDtsPath, platformTypesDts);
|
|
@@ -229,21 +654,25 @@ var generateTypes = (schemas, projectRoot) => {
|
|
|
229
654
|
path.join(outDir, "index.d.ts"),
|
|
230
655
|
generateIndexDts(
|
|
231
656
|
schemas.connectors.length > 0,
|
|
657
|
+
schemas.actions.length > 0,
|
|
232
658
|
schemas.pipelines.length > 0,
|
|
233
659
|
platformTypesDts != null
|
|
234
660
|
)
|
|
235
661
|
);
|
|
236
662
|
fs.writeFileSync(path.join(outDir, "manifest.json"), JSON.stringify(schemas, null, 2));
|
|
237
663
|
};
|
|
238
|
-
var generateAgentsDts = (agents) => {
|
|
664
|
+
var generateAgentsDts = (agents, actions) => {
|
|
665
|
+
const actionsByName = new Map(actions.map((a) => [a.name, a]));
|
|
239
666
|
const entries = agents.map((a) => {
|
|
240
667
|
const input = jsonSchemaToTsType(a.input);
|
|
241
668
|
const output = jsonSchemaToTsType(a.output);
|
|
242
|
-
const
|
|
669
|
+
const hasInlineActions = a.actions && Object.keys(a.actions).length > 0;
|
|
670
|
+
const agentActions = hasInlineActions ? a.actions : buildAgentActionsFromRefs(a, actionsByName);
|
|
671
|
+
const actionsType = generateActionsType(agentActions);
|
|
243
672
|
return ` "${a.id}": {
|
|
244
673
|
input: ${input}
|
|
245
674
|
output: ${output}
|
|
246
|
-
actions: ${
|
|
675
|
+
actions: ${actionsType}
|
|
247
676
|
}`;
|
|
248
677
|
}).join("\n");
|
|
249
678
|
return [
|
|
@@ -258,6 +687,19 @@ var generateAgentsDts = (agents) => {
|
|
|
258
687
|
``
|
|
259
688
|
].join("\n");
|
|
260
689
|
};
|
|
690
|
+
var buildAgentActionsFromRefs = (agent, actionsByName) => {
|
|
691
|
+
const actionNames = agent.config?.actions;
|
|
692
|
+
if (!actionNames || actionNames.length === 0) return void 0;
|
|
693
|
+
const result = {};
|
|
694
|
+
for (const name of actionNames) {
|
|
695
|
+
const bareName = name.includes("/") ? name.slice(name.indexOf("/") + 1) : name;
|
|
696
|
+
const actionSchema = actionsByName.get(bareName) ?? actionsByName.get(name);
|
|
697
|
+
if (actionSchema) {
|
|
698
|
+
result[name] = actionSchema.schema;
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
return Object.keys(result).length > 0 ? result : void 0;
|
|
702
|
+
};
|
|
261
703
|
var generateActionsType = (actions) => {
|
|
262
704
|
if (!actions || Object.keys(actions).length === 0) {
|
|
263
705
|
return "Record<string, never>";
|
|
@@ -265,6 +707,20 @@ var generateActionsType = (actions) => {
|
|
|
265
707
|
const entries = Object.entries(actions).map(([name, schema]) => `"${name}": ${jsonSchemaToTsType(schema)}`).join("; ");
|
|
266
708
|
return `{ ${entries} }`;
|
|
267
709
|
};
|
|
710
|
+
var generateActionsDts = (actions) => {
|
|
711
|
+
const entries = actions.map((a) => ` "${a.name}": ${jsonSchemaToTsType(a.schema)}`).join("\n");
|
|
712
|
+
return [
|
|
713
|
+
`// Auto-generated by \`kraken generate\` \u2014 do not edit manually`,
|
|
714
|
+
`export {};`,
|
|
715
|
+
``,
|
|
716
|
+
`declare module "@kraken-ai/platform" {`,
|
|
717
|
+
` interface ActionRegistry {`,
|
|
718
|
+
entries,
|
|
719
|
+
` }`,
|
|
720
|
+
`}`,
|
|
721
|
+
``
|
|
722
|
+
].join("\n");
|
|
723
|
+
};
|
|
268
724
|
var generateQueriesDts = (queries) => {
|
|
269
725
|
const entries = queries.map((q) => {
|
|
270
726
|
const params = jsonSchemaToTsType(q.params);
|
|
@@ -301,7 +757,7 @@ ${entries}
|
|
|
301
757
|
}
|
|
302
758
|
`;
|
|
303
759
|
};
|
|
304
|
-
var generateIndexDts = (hasConnectors, hasPipelines, hasPlatformTypes) => {
|
|
760
|
+
var generateIndexDts = (hasConnectors, hasActions, hasPipelines, hasPlatformTypes) => {
|
|
305
761
|
let content = `// Auto-generated by \`kraken generate\` \u2014 do not edit manually
|
|
306
762
|
|
|
307
763
|
/// <reference path="./agents.d.ts" />
|
|
@@ -309,6 +765,10 @@ export type { QueryRegistry } from "./queries"
|
|
|
309
765
|
`;
|
|
310
766
|
if (hasConnectors) {
|
|
311
767
|
content += `export type { ConnectorId, ConnectorTools } from "./connectors"
|
|
768
|
+
`;
|
|
769
|
+
}
|
|
770
|
+
if (hasActions) {
|
|
771
|
+
content += `/// <reference path="./actions.d.ts" />
|
|
312
772
|
`;
|
|
313
773
|
}
|
|
314
774
|
if (hasPipelines) {
|
|
@@ -321,7 +781,7 @@ export type { QueryRegistry } from "./queries"
|
|
|
321
781
|
}
|
|
322
782
|
return content;
|
|
323
783
|
};
|
|
324
|
-
var generatePlatformTypesDts = (agents, connectors, skills) => {
|
|
784
|
+
var generatePlatformTypesDts = (agents, connectors, skills, actions) => {
|
|
325
785
|
const entries = [];
|
|
326
786
|
if (agents.length > 0) {
|
|
327
787
|
const ids = agents.map((a) => `"${a.id}"`).join(" | ");
|
|
@@ -335,6 +795,10 @@ var generatePlatformTypesDts = (agents, connectors, skills) => {
|
|
|
335
795
|
const ids = skills.map((s) => `"${s.id}"`).join(" | ");
|
|
336
796
|
entries.push(` skillId: ${ids};`);
|
|
337
797
|
}
|
|
798
|
+
if (actions.length > 0) {
|
|
799
|
+
const ids = actions.map((a) => `"${a.name}"`).join(" | ");
|
|
800
|
+
entries.push(` actionId: ${ids};`);
|
|
801
|
+
}
|
|
338
802
|
if (entries.length === 0) return null;
|
|
339
803
|
return [
|
|
340
804
|
`// Auto-generated by \`kraken generate\` \u2014 do not edit manually`,
|
|
@@ -514,168 +978,127 @@ var clearCredentials = () => {
|
|
|
514
978
|
|
|
515
979
|
// src/cli/discover.ts
|
|
516
980
|
import fs3 from "fs";
|
|
981
|
+
import { createRequire } from "module";
|
|
517
982
|
import path3 from "path";
|
|
518
983
|
import { pathToFileURL } from "url";
|
|
519
|
-
import * as
|
|
520
|
-
|
|
521
|
-
// src/agents/types/action.ts
|
|
522
|
-
import * as z from "zod";
|
|
523
|
-
var actionVariantConfigSchema = z.object({
|
|
524
|
-
schema: z.record(z.string(), z.unknown()),
|
|
525
|
-
webhook: z.string().url().optional(),
|
|
526
|
-
hasHandler: z.boolean()
|
|
527
|
-
});
|
|
528
|
-
var actionsConfigSchema = z.object({
|
|
529
|
-
variants: z.record(z.string(), actionVariantConfigSchema)
|
|
530
|
-
}).strict();
|
|
531
|
-
|
|
532
|
-
// src/agents/types/environment.ts
|
|
533
|
-
import * as z2 from "zod";
|
|
534
|
-
var environmentSchema = z2.enum(["dev", "staging", "prod"]);
|
|
535
|
-
|
|
536
|
-
// src/agents/types/identity.ts
|
|
537
|
-
import * as z3 from "zod";
|
|
538
|
-
var jitPolicySchema = z3.enum(["auto-approve", "policy-based", "require-approval"]);
|
|
539
|
-
var identityConfigSchema = z3.object({
|
|
540
|
-
basePermissions: z3.array(z3.string()),
|
|
541
|
-
requestablePermissions: z3.array(z3.string()).optional(),
|
|
542
|
-
jitPolicy: jitPolicySchema.optional(),
|
|
543
|
-
maxJitDurationMinutes: z3.number().int().positive().optional()
|
|
544
|
-
});
|
|
545
|
-
|
|
546
|
-
// src/agents/types/notifications.ts
|
|
547
|
-
import * as z4 from "zod";
|
|
548
|
-
var notificationConfigSchema = z4.object({
|
|
549
|
-
slack: z4.string().optional(),
|
|
550
|
-
onSuccess: z4.boolean().optional(),
|
|
551
|
-
onFailure: z4.boolean().optional(),
|
|
552
|
-
onTimeout: z4.boolean().optional()
|
|
553
|
-
});
|
|
984
|
+
import * as z9 from "zod";
|
|
554
985
|
|
|
555
|
-
// src/
|
|
556
|
-
|
|
986
|
+
// src/cli/log.ts
|
|
987
|
+
var supportsColor = !("NO_COLOR" in process.env) && process.env.FORCE_COLOR !== "0" && (process.stderr.isTTY ?? false);
|
|
988
|
+
var code = (open, close) => {
|
|
989
|
+
const openStr = `\x1B[${open}m`;
|
|
990
|
+
const closeStr = `\x1B[${close}m`;
|
|
991
|
+
return (s) => supportsColor ? `${openStr}${s}${closeStr}` : s;
|
|
992
|
+
};
|
|
993
|
+
var bold = code(1, 22);
|
|
994
|
+
var dim = code(2, 22);
|
|
995
|
+
var red = code(31, 39);
|
|
996
|
+
var yellow = code(33, 39);
|
|
997
|
+
var green = code(32, 39);
|
|
998
|
+
var cyan = code(36, 39);
|
|
999
|
+
var warn = (msg) => {
|
|
1000
|
+
process.stderr.write(` ${dim("[kraken-ai:")} ${yellow("warn")}${dim("]")} ${msg}
|
|
1001
|
+
`);
|
|
1002
|
+
};
|
|
557
1003
|
|
|
558
|
-
// src/
|
|
559
|
-
|
|
560
|
-
var
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
1004
|
+
// src/cli/discover.ts
|
|
1005
|
+
var MANIFEST_START = "---KRAKEN-MANIFEST-START---";
|
|
1006
|
+
var MANIFEST_END = "---KRAKEN-MANIFEST-END---";
|
|
1007
|
+
var skillEntrySchema = z9.object({
|
|
1008
|
+
name: z9.string().min(1),
|
|
1009
|
+
path: z9.string().min(1),
|
|
1010
|
+
content: z9.string()
|
|
564
1011
|
});
|
|
565
|
-
var
|
|
566
|
-
|
|
567
|
-
|
|
1012
|
+
var toolSpecSchema = z9.object({
|
|
1013
|
+
name: z9.string(),
|
|
1014
|
+
description: z9.string(),
|
|
1015
|
+
parameters: z9.record(z9.string(), z9.unknown()).default({}),
|
|
1016
|
+
annotations: z9.object({
|
|
1017
|
+
readOnlyHint: z9.boolean().optional(),
|
|
1018
|
+
destructiveHint: z9.boolean().optional(),
|
|
1019
|
+
idempotentHint: z9.boolean().optional()
|
|
1020
|
+
}).optional()
|
|
568
1021
|
});
|
|
569
|
-
var
|
|
570
|
-
|
|
1022
|
+
var resourceSpecSchema = z9.object({
|
|
1023
|
+
name: z9.string(),
|
|
1024
|
+
uri: z9.string(),
|
|
1025
|
+
description: z9.string(),
|
|
1026
|
+
mimeType: z9.string().optional()
|
|
571
1027
|
});
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
1028
|
+
var promptSpecSchema = z9.object({
|
|
1029
|
+
name: z9.string(),
|
|
1030
|
+
description: z9.string(),
|
|
1031
|
+
arguments: z9.array(
|
|
1032
|
+
z9.object({
|
|
1033
|
+
name: z9.string(),
|
|
1034
|
+
description: z9.string().optional(),
|
|
1035
|
+
required: z9.boolean().optional()
|
|
1036
|
+
})
|
|
1037
|
+
).optional()
|
|
580
1038
|
});
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
timezone: z7.string().optional()
|
|
588
|
-
});
|
|
589
|
-
var webhookTriggerSchema = z7.object({
|
|
590
|
-
type: z7.literal("webhook"),
|
|
591
|
-
path: z7.string().startsWith("/"),
|
|
592
|
-
method: z7.enum(["POST", "GET"]).optional()
|
|
593
|
-
});
|
|
594
|
-
var eventTriggerSchema = z7.object({
|
|
595
|
-
type: z7.literal("event"),
|
|
596
|
-
source: z7.string(),
|
|
597
|
-
event: z7.string()
|
|
1039
|
+
var connectorEntrySchema = z9.object({
|
|
1040
|
+
name: z9.string().min(1),
|
|
1041
|
+
path: z9.string().min(1),
|
|
1042
|
+
toolSpecs: z9.array(toolSpecSchema).default([]),
|
|
1043
|
+
resourceSpecs: z9.array(resourceSpecSchema).default([]),
|
|
1044
|
+
promptSpecs: z9.array(promptSpecSchema).default([])
|
|
598
1045
|
});
|
|
599
|
-
var
|
|
600
|
-
var manualTriggerSchema = z7.object({ type: z7.literal("manual") });
|
|
601
|
-
var triggerConfigSchema = z7.discriminatedUnion("type", [
|
|
602
|
-
cronTriggerSchema,
|
|
603
|
-
webhookTriggerSchema,
|
|
604
|
-
eventTriggerSchema,
|
|
605
|
-
apiTriggerSchema,
|
|
606
|
-
manualTriggerSchema
|
|
607
|
-
]);
|
|
608
|
-
|
|
609
|
-
// src/agents/types/platform-agent.ts
|
|
610
|
-
var thinkingLevelSchema = z8.enum(["low", "medium", "high"]);
|
|
611
|
-
var logLevelSchema = z8.enum(["silent", "debug", "info", "warn", "error"]);
|
|
612
|
-
var agentDefinitionSchema = z8.object({
|
|
613
|
-
name: z8.string().min(1),
|
|
614
|
-
model: z8.string().min(1),
|
|
615
|
-
instructions: z8.string().min(1),
|
|
616
|
-
description: z8.string().optional(),
|
|
617
|
-
skills: z8.array(z8.string()).optional(),
|
|
618
|
-
temperature: z8.number().min(0).max(2).optional(),
|
|
619
|
-
allowTemperatureOverride: z8.boolean().optional(),
|
|
620
|
-
maxOutputTokens: z8.number().int().positive().optional(),
|
|
621
|
-
thinkingLevel: thinkingLevelSchema.optional(),
|
|
622
|
-
logLevel: logLevelSchema.optional()
|
|
623
|
-
}).strict();
|
|
624
|
-
var platformAgentConfigSchema = z8.object({
|
|
625
|
-
agent: agentDefinitionSchema,
|
|
626
|
-
connectors: z8.array(z8.string()).optional(),
|
|
627
|
-
triggers: z8.array(triggerConfigSchema),
|
|
628
|
-
identity: identityConfigSchema.optional(),
|
|
629
|
-
resources: resourceLimitsSchema.optional(),
|
|
630
|
-
retries: retryPolicySchema.optional(),
|
|
631
|
-
concurrency: concurrencyPolicySchema.optional(),
|
|
632
|
-
team: teamConfigSchema.optional(),
|
|
633
|
-
notifications: notificationConfigSchema.optional(),
|
|
634
|
-
environment: environmentSchema.optional(),
|
|
635
|
-
actions: actionsConfigSchema.optional()
|
|
636
|
-
}).strict();
|
|
637
|
-
|
|
638
|
-
// src/agents/types/skill.ts
|
|
639
|
-
import * as z9 from "zod";
|
|
640
|
-
var platformSkillInputSchema = z9.object({
|
|
1046
|
+
var agentEntrySchema = z9.object({
|
|
641
1047
|
name: z9.string().min(1),
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
// src/cli/discover.ts
|
|
646
|
-
var MANIFEST_START = "---KRAKEN-MANIFEST-START---";
|
|
647
|
-
var MANIFEST_END = "---KRAKEN-MANIFEST-END---";
|
|
648
|
-
var skillEntrySchema = z10.object({
|
|
649
|
-
name: z10.string().min(1),
|
|
650
|
-
path: z10.string().min(1),
|
|
651
|
-
content: z10.string()
|
|
1048
|
+
entryPoint: z9.string().min(1),
|
|
1049
|
+
config: platformAgentConfigSchema
|
|
652
1050
|
});
|
|
653
|
-
var
|
|
654
|
-
|
|
655
|
-
|
|
1051
|
+
var actionConfigSchema = z9.object({
|
|
1052
|
+
schema: z9.record(z9.string(), z9.unknown()),
|
|
1053
|
+
webhook: z9.string().url().optional(),
|
|
1054
|
+
hasHandler: z9.boolean()
|
|
656
1055
|
});
|
|
657
|
-
var
|
|
658
|
-
name:
|
|
659
|
-
entryPoint:
|
|
660
|
-
config:
|
|
1056
|
+
var actionEntrySchema = z9.object({
|
|
1057
|
+
name: z9.string().min(1),
|
|
1058
|
+
entryPoint: z9.string().min(1),
|
|
1059
|
+
config: actionConfigSchema
|
|
661
1060
|
});
|
|
662
|
-
var projectManifestSchema =
|
|
663
|
-
agents:
|
|
664
|
-
skills:
|
|
665
|
-
connectors:
|
|
1061
|
+
var projectManifestSchema = z9.object({
|
|
1062
|
+
agents: z9.array(agentEntrySchema),
|
|
1063
|
+
skills: z9.array(skillEntrySchema),
|
|
1064
|
+
connectors: z9.array(connectorEntrySchema),
|
|
1065
|
+
actions: z9.array(actionEntrySchema).default([])
|
|
666
1066
|
});
|
|
667
1067
|
var isTsxAvailable = () => process.env.NODE_OPTIONS?.includes("tsx") === true;
|
|
1068
|
+
var tsxLoaded = false;
|
|
1069
|
+
var ensureTsxLoader = async (projectRoot) => {
|
|
1070
|
+
if (isTsxAvailable() || tsxLoaded) return true;
|
|
1071
|
+
if (!fs3.existsSync(path3.join(projectRoot, "node_modules", "tsx"))) return false;
|
|
1072
|
+
try {
|
|
1073
|
+
const require2 = createRequire(path3.join(projectRoot, "package.json"));
|
|
1074
|
+
const tsxEsmPath = require2.resolve("tsx/esm");
|
|
1075
|
+
await import(pathToFileURL(tsxEsmPath).href);
|
|
1076
|
+
tsxLoaded = true;
|
|
1077
|
+
return true;
|
|
1078
|
+
} catch {
|
|
1079
|
+
return false;
|
|
1080
|
+
}
|
|
1081
|
+
};
|
|
668
1082
|
var isPlatformAgentExport = (value) => value != null && typeof value === "object" && value.__type === "PlatformAgent" && "config" in value;
|
|
669
1083
|
var discoverAgents = async (projectRoot) => {
|
|
670
1084
|
const distAgentsDir = path3.join(projectRoot, "dist", "agents");
|
|
671
1085
|
const useDistAgents = fs3.existsSync(distAgentsDir) && fs3.statSync(distAgentsDir).isDirectory();
|
|
672
|
-
const agentsDir = useDistAgents ? distAgentsDir : path3.join(projectRoot, "agents");
|
|
673
|
-
const agentsDirPrefix = useDistAgents ? "dist/agents" : "agents";
|
|
1086
|
+
const agentsDir = useDistAgents ? distAgentsDir : path3.join(projectRoot, "src", "agents");
|
|
1087
|
+
const agentsDirPrefix = useDistAgents ? "dist/agents" : "src/agents";
|
|
674
1088
|
if (!fs3.existsSync(agentsDir) || !fs3.statSync(agentsDir).isDirectory()) {
|
|
675
1089
|
return [];
|
|
676
1090
|
}
|
|
677
|
-
const tsxEnabled =
|
|
678
|
-
const
|
|
1091
|
+
const tsxEnabled = await ensureTsxLoader(projectRoot);
|
|
1092
|
+
const allFiles = fs3.readdirSync(agentsDir);
|
|
1093
|
+
const files = allFiles.filter((f) => f.endsWith(".js") || f.endsWith(".mjs") || tsxEnabled && f.endsWith(".ts")).sort();
|
|
1094
|
+
if (!tsxEnabled) {
|
|
1095
|
+
const skippedTs = allFiles.filter((f) => f.endsWith(".ts"));
|
|
1096
|
+
if (skippedTs.length > 0) {
|
|
1097
|
+
warn(
|
|
1098
|
+
`Found ${String(skippedTs.length)} .ts agent file(s) but tsx is not available. Install tsx as a devDependency or build your project first.`
|
|
1099
|
+
);
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
679
1102
|
const seen = /* @__PURE__ */ new Map();
|
|
680
1103
|
for (const file of files) {
|
|
681
1104
|
const filePath = path3.join(agentsDir, file);
|
|
@@ -698,7 +1121,7 @@ var discoverAgents = async (projectRoot) => {
|
|
|
698
1121
|
};
|
|
699
1122
|
var MAX_SKILL_SIZE = 100 * 1024;
|
|
700
1123
|
var discoverSkills = (projectRoot) => {
|
|
701
|
-
const skillsDir = path3.join(projectRoot, "skills");
|
|
1124
|
+
const skillsDir = path3.join(projectRoot, "src", "skills");
|
|
702
1125
|
if (!fs3.existsSync(skillsDir) || !fs3.statSync(skillsDir).isDirectory()) {
|
|
703
1126
|
return [];
|
|
704
1127
|
}
|
|
@@ -706,41 +1129,111 @@ var discoverSkills = (projectRoot) => {
|
|
|
706
1129
|
const skills = [];
|
|
707
1130
|
for (const file of files) {
|
|
708
1131
|
if (!file.endsWith(".md")) {
|
|
709
|
-
warn(`Skipping skills/${file}: skill files must have a .md extension.`);
|
|
1132
|
+
warn(`Skipping src/skills/${file}: skill files must have a .md extension.`);
|
|
710
1133
|
continue;
|
|
711
1134
|
}
|
|
712
1135
|
const basename = file.replace(/\.md$/, "");
|
|
713
1136
|
if (!isValidSkillName(basename)) {
|
|
714
1137
|
warn(
|
|
715
|
-
`Skipping skills/${file}: name must match [a-zA-Z0-9-] (letters, digits, hyphens only).`
|
|
1138
|
+
`Skipping src/skills/${file}: name must match [a-zA-Z0-9-] (letters, digits, hyphens only).`
|
|
716
1139
|
);
|
|
717
1140
|
continue;
|
|
718
1141
|
}
|
|
719
1142
|
const filePath = path3.join(skillsDir, file);
|
|
720
1143
|
const stat = fs3.statSync(filePath);
|
|
721
1144
|
if (stat.size > MAX_SKILL_SIZE) {
|
|
722
|
-
warn(`Skipping skills/${file}: exceeds ${MAX_SKILL_SIZE} byte limit.`);
|
|
1145
|
+
warn(`Skipping src/skills/${file}: exceeds ${MAX_SKILL_SIZE} byte limit.`);
|
|
723
1146
|
continue;
|
|
724
1147
|
}
|
|
725
1148
|
const content = fs3.readFileSync(filePath, "utf-8");
|
|
726
|
-
skills.push({ name: file, path: `skills/${file}`, content });
|
|
1149
|
+
skills.push({ name: file, path: `src/skills/${file}`, content });
|
|
727
1150
|
}
|
|
728
1151
|
return skills;
|
|
729
1152
|
};
|
|
730
|
-
var
|
|
1153
|
+
var isPlatformConnectorExport = (value) => value != null && typeof value === "object" && value.__type === "PlatformConnector";
|
|
1154
|
+
var serializeToolParameters = (input) => {
|
|
1155
|
+
try {
|
|
1156
|
+
return z9.toJSONSchema(input, { target: "draft-2020-12" });
|
|
1157
|
+
} catch {
|
|
1158
|
+
warn("Failed to serialize tool parameters via z.toJSONSchema(); falling back to {}");
|
|
1159
|
+
return {};
|
|
1160
|
+
}
|
|
1161
|
+
};
|
|
1162
|
+
var extractConnectorSpecs = (conn) => {
|
|
1163
|
+
const toolSpecs = [];
|
|
1164
|
+
if (conn.tools) {
|
|
1165
|
+
for (const [name, tool] of Object.entries(conn.tools)) {
|
|
1166
|
+
const spec = {
|
|
1167
|
+
name,
|
|
1168
|
+
description: tool.description,
|
|
1169
|
+
parameters: serializeToolParameters(tool.input)
|
|
1170
|
+
};
|
|
1171
|
+
if (tool.annotations) {
|
|
1172
|
+
const { readOnlyHint, destructiveHint, idempotentHint } = tool.annotations;
|
|
1173
|
+
if (readOnlyHint !== void 0 || destructiveHint !== void 0 || idempotentHint !== void 0) {
|
|
1174
|
+
spec.annotations = {
|
|
1175
|
+
...readOnlyHint !== void 0 ? { readOnlyHint } : {},
|
|
1176
|
+
...destructiveHint !== void 0 ? { destructiveHint } : {},
|
|
1177
|
+
...idempotentHint !== void 0 ? { idempotentHint } : {}
|
|
1178
|
+
};
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
toolSpecs.push(spec);
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
const resourceSpecs = [];
|
|
1185
|
+
if (conn.resources) {
|
|
1186
|
+
for (const [name, resource] of Object.entries(conn.resources)) {
|
|
1187
|
+
const spec = {
|
|
1188
|
+
name,
|
|
1189
|
+
uri: resource.uri,
|
|
1190
|
+
description: resource.description
|
|
1191
|
+
};
|
|
1192
|
+
if (resource.mimeType) {
|
|
1193
|
+
spec.mimeType = resource.mimeType;
|
|
1194
|
+
}
|
|
1195
|
+
resourceSpecs.push(spec);
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
const promptSpecs = [];
|
|
1199
|
+
if (conn.prompts) {
|
|
1200
|
+
for (const [name, prompt] of Object.entries(conn.prompts)) {
|
|
1201
|
+
const spec = {
|
|
1202
|
+
name,
|
|
1203
|
+
description: prompt.description
|
|
1204
|
+
};
|
|
1205
|
+
if (prompt.arguments) {
|
|
1206
|
+
spec.arguments = [...prompt.arguments];
|
|
1207
|
+
}
|
|
1208
|
+
promptSpecs.push(spec);
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
return { toolSpecs, resourceSpecs, promptSpecs };
|
|
1212
|
+
};
|
|
1213
|
+
var findConnectorEntryPoint = (connDir, tsxEnabled) => {
|
|
1214
|
+
const candidates = ["index.js", "index.mjs"];
|
|
1215
|
+
if (tsxEnabled) candidates.push("index.ts");
|
|
1216
|
+
for (const candidate of candidates) {
|
|
1217
|
+
const filePath = path3.join(connDir, candidate);
|
|
1218
|
+
if (fs3.existsSync(filePath)) return filePath;
|
|
1219
|
+
}
|
|
1220
|
+
return void 0;
|
|
1221
|
+
};
|
|
1222
|
+
var discoverConnectors = async (projectRoot) => {
|
|
731
1223
|
const distConnectorsDir = path3.join(projectRoot, "dist", "connectors");
|
|
732
1224
|
const useDistConnectors = fs3.existsSync(distConnectorsDir) && fs3.statSync(distConnectorsDir).isDirectory();
|
|
733
|
-
const connectorsDir = useDistConnectors ? distConnectorsDir : path3.join(projectRoot, "connectors");
|
|
734
|
-
const connectorsDirPrefix = useDistConnectors ? "dist/connectors" : "connectors";
|
|
1225
|
+
const connectorsDir = useDistConnectors ? distConnectorsDir : path3.join(projectRoot, "src", "connectors");
|
|
1226
|
+
const connectorsDirPrefix = useDistConnectors ? "dist/connectors" : "src/connectors";
|
|
735
1227
|
if (!fs3.existsSync(connectorsDir) || !fs3.statSync(connectorsDir).isDirectory()) {
|
|
736
1228
|
return [];
|
|
737
1229
|
}
|
|
1230
|
+
const tsxEnabled = await ensureTsxLoader(projectRoot);
|
|
738
1231
|
const entries = fs3.readdirSync(connectorsDir, { withFileTypes: true });
|
|
739
1232
|
const connectors = [];
|
|
740
1233
|
for (const entry of entries) {
|
|
741
1234
|
if (!entry.isDirectory()) continue;
|
|
742
1235
|
const name = entry.name;
|
|
743
|
-
if (!
|
|
1236
|
+
if (!isValidPrimitiveName(name)) {
|
|
744
1237
|
warn(
|
|
745
1238
|
`Skipping ${connectorsDirPrefix}/${name}: name must match [a-z0-9-] (lowercase, digits, hyphens only).`
|
|
746
1239
|
);
|
|
@@ -755,23 +1248,109 @@ var discoverConnectors = (projectRoot) => {
|
|
|
755
1248
|
if (!hasPackageJson && !hasDockerfile && !hasIndexJs && !hasIndexMjs && !hasIndexTs) {
|
|
756
1249
|
continue;
|
|
757
1250
|
}
|
|
758
|
-
|
|
1251
|
+
const connectorPath = `${connectorsDirPrefix}/${name}/`;
|
|
1252
|
+
const entryPoint = findConnectorEntryPoint(connDir, tsxEnabled);
|
|
1253
|
+
if (!entryPoint) {
|
|
1254
|
+
connectors.push({
|
|
1255
|
+
name,
|
|
1256
|
+
path: connectorPath,
|
|
1257
|
+
toolSpecs: [],
|
|
1258
|
+
resourceSpecs: [],
|
|
1259
|
+
promptSpecs: []
|
|
1260
|
+
});
|
|
1261
|
+
continue;
|
|
1262
|
+
}
|
|
1263
|
+
try {
|
|
1264
|
+
const mod = await import(pathToFileURL(entryPoint).href);
|
|
1265
|
+
const exported = mod.default;
|
|
1266
|
+
if (isPlatformConnectorExport(exported)) {
|
|
1267
|
+
const specs = extractConnectorSpecs(exported);
|
|
1268
|
+
connectors.push({ name, path: connectorPath, ...specs });
|
|
1269
|
+
} else {
|
|
1270
|
+
connectors.push({
|
|
1271
|
+
name,
|
|
1272
|
+
path: connectorPath,
|
|
1273
|
+
toolSpecs: [],
|
|
1274
|
+
resourceSpecs: [],
|
|
1275
|
+
promptSpecs: []
|
|
1276
|
+
});
|
|
1277
|
+
}
|
|
1278
|
+
} catch (err) {
|
|
1279
|
+
warn(
|
|
1280
|
+
`Skipping introspection for ${connectorsDirPrefix}/${name}: ${err instanceof Error ? err.message : String(err)}`
|
|
1281
|
+
);
|
|
1282
|
+
connectors.push({
|
|
1283
|
+
name,
|
|
1284
|
+
path: connectorPath,
|
|
1285
|
+
toolSpecs: [],
|
|
1286
|
+
resourceSpecs: [],
|
|
1287
|
+
promptSpecs: []
|
|
1288
|
+
});
|
|
1289
|
+
}
|
|
759
1290
|
}
|
|
760
1291
|
return connectors.sort((a, b) => a.name.localeCompare(b.name));
|
|
761
1292
|
};
|
|
1293
|
+
var isPlatformActionExport = (value) => value != null && typeof value === "object" && value.__type === "PlatformAction" && "name" in value && "config" in value;
|
|
1294
|
+
var discoverActions = async (projectRoot) => {
|
|
1295
|
+
const distActionsDir = path3.join(projectRoot, "dist", "actions");
|
|
1296
|
+
const useDistActions = fs3.existsSync(distActionsDir) && fs3.statSync(distActionsDir).isDirectory();
|
|
1297
|
+
const actionsDir = useDistActions ? distActionsDir : path3.join(projectRoot, "src", "actions");
|
|
1298
|
+
const actionsDirPrefix = useDistActions ? "dist/actions" : "src/actions";
|
|
1299
|
+
if (!fs3.existsSync(actionsDir) || !fs3.statSync(actionsDir).isDirectory()) {
|
|
1300
|
+
return [];
|
|
1301
|
+
}
|
|
1302
|
+
const tsxEnabled = await ensureTsxLoader(projectRoot);
|
|
1303
|
+
const allFiles = fs3.readdirSync(actionsDir);
|
|
1304
|
+
const files = allFiles.filter((f) => f.endsWith(".js") || f.endsWith(".mjs") || tsxEnabled && f.endsWith(".ts")).sort();
|
|
1305
|
+
if (!tsxEnabled) {
|
|
1306
|
+
const skippedTs = allFiles.filter((f) => f.endsWith(".ts"));
|
|
1307
|
+
if (skippedTs.length > 0) {
|
|
1308
|
+
warn(
|
|
1309
|
+
`Found ${String(skippedTs.length)} .ts action file(s) but tsx is not available. Install tsx as a devDependency or build your project first.`
|
|
1310
|
+
);
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
const seen = /* @__PURE__ */ new Map();
|
|
1314
|
+
for (const file of files) {
|
|
1315
|
+
const filePath = path3.join(actionsDir, file);
|
|
1316
|
+
try {
|
|
1317
|
+
const mod = await import(pathToFileURL(filePath).href);
|
|
1318
|
+
const exported = mod.default;
|
|
1319
|
+
if (isPlatformActionExport(exported) && !seen.has(exported.name)) {
|
|
1320
|
+
if (!isValidPrimitiveName(exported.name)) {
|
|
1321
|
+
warn(
|
|
1322
|
+
`Skipping ${actionsDirPrefix}/${file}: action name "${exported.name}" must match [a-z0-9-] (lowercase, digits, hyphens only).`
|
|
1323
|
+
);
|
|
1324
|
+
continue;
|
|
1325
|
+
}
|
|
1326
|
+
seen.set(exported.name, {
|
|
1327
|
+
name: exported.name,
|
|
1328
|
+
entryPoint: `${actionsDirPrefix}/${file}`,
|
|
1329
|
+
config: exported.config
|
|
1330
|
+
});
|
|
1331
|
+
}
|
|
1332
|
+
} catch (err) {
|
|
1333
|
+
warn(
|
|
1334
|
+
`Skipping ${actionsDirPrefix}/${file}: ${err instanceof Error ? err.message : String(err)}`
|
|
1335
|
+
);
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
return [...seen.values()];
|
|
1339
|
+
};
|
|
762
1340
|
var discoverProject = async (projectRoot) => {
|
|
763
1341
|
const discovered = await discoverAgents(projectRoot);
|
|
764
1342
|
const agents = [];
|
|
765
1343
|
for (const { config, entryPoint } of discovered) {
|
|
766
1344
|
const name = config.agent.name;
|
|
767
|
-
if (!
|
|
768
|
-
throw new Error(`Invalid agent name: "${name}". Names must match ${
|
|
1345
|
+
if (!isValidPrimitiveName(name)) {
|
|
1346
|
+
throw new Error(`Invalid agent name: "${name}". Names must match ${PRIMITIVE_NAME_REGEX}`);
|
|
769
1347
|
}
|
|
770
1348
|
agents.push({ name, entryPoint, config });
|
|
771
1349
|
}
|
|
772
1350
|
const skills = discoverSkills(projectRoot);
|
|
773
|
-
const connectors = discoverConnectors(projectRoot);
|
|
774
|
-
|
|
1351
|
+
const connectors = await discoverConnectors(projectRoot);
|
|
1352
|
+
const actions = await discoverActions(projectRoot);
|
|
1353
|
+
return { agents, skills, connectors, actions };
|
|
775
1354
|
};
|
|
776
1355
|
var emitManifest = (manifest) => {
|
|
777
1356
|
process.stdout.write(`${MANIFEST_START}
|
|
@@ -840,52 +1419,58 @@ var pick = async (label, items) => {
|
|
|
840
1419
|
};
|
|
841
1420
|
|
|
842
1421
|
// src/platform/types.ts
|
|
843
|
-
import * as
|
|
844
|
-
var jsonSchemaValue =
|
|
845
|
-
var agentSchemaValidator =
|
|
846
|
-
id:
|
|
847
|
-
name:
|
|
1422
|
+
import * as z10 from "zod";
|
|
1423
|
+
var jsonSchemaValue = z10.record(z10.string(), z10.unknown());
|
|
1424
|
+
var agentSchemaValidator = z10.object({
|
|
1425
|
+
id: z10.string(),
|
|
1426
|
+
name: z10.string(),
|
|
848
1427
|
input: jsonSchemaValue,
|
|
849
1428
|
output: jsonSchemaValue,
|
|
850
|
-
actions:
|
|
1429
|
+
actions: z10.record(z10.string(), jsonSchemaValue).optional()
|
|
851
1430
|
}).passthrough();
|
|
852
|
-
var queryColumnValidator =
|
|
853
|
-
name:
|
|
854
|
-
type:
|
|
855
|
-
description:
|
|
1431
|
+
var queryColumnValidator = z10.object({
|
|
1432
|
+
name: z10.string(),
|
|
1433
|
+
type: z10.string(),
|
|
1434
|
+
description: z10.string().optional()
|
|
856
1435
|
}).passthrough();
|
|
857
|
-
var querySchemaValidator =
|
|
858
|
-
name:
|
|
1436
|
+
var querySchemaValidator = z10.object({
|
|
1437
|
+
name: z10.string(),
|
|
859
1438
|
params: jsonSchemaValue,
|
|
860
|
-
columns:
|
|
1439
|
+
columns: z10.array(queryColumnValidator)
|
|
861
1440
|
}).passthrough();
|
|
862
|
-
var connectorToolValidator =
|
|
863
|
-
name:
|
|
864
|
-
description:
|
|
1441
|
+
var connectorToolValidator = z10.object({
|
|
1442
|
+
name: z10.string(),
|
|
1443
|
+
description: z10.string(),
|
|
865
1444
|
parameters: jsonSchemaValue
|
|
866
1445
|
}).passthrough();
|
|
867
|
-
var connectorSchemaValidator =
|
|
868
|
-
id:
|
|
869
|
-
tools:
|
|
1446
|
+
var connectorSchemaValidator = z10.object({
|
|
1447
|
+
id: z10.string(),
|
|
1448
|
+
tools: z10.array(connectorToolValidator)
|
|
870
1449
|
}).passthrough();
|
|
871
|
-
var skillSchemaValidator =
|
|
872
|
-
id:
|
|
873
|
-
name:
|
|
874
|
-
description:
|
|
1450
|
+
var skillSchemaValidator = z10.object({
|
|
1451
|
+
id: z10.string(),
|
|
1452
|
+
name: z10.string(),
|
|
1453
|
+
description: z10.string().optional()
|
|
875
1454
|
}).passthrough();
|
|
876
|
-
var
|
|
877
|
-
|
|
878
|
-
|
|
1455
|
+
var actionSchemaValidator = z10.object({
|
|
1456
|
+
id: z10.string(),
|
|
1457
|
+
name: z10.string(),
|
|
1458
|
+
schema: z10.record(z10.string(), z10.unknown()),
|
|
1459
|
+
hasHandler: z10.boolean()
|
|
1460
|
+
}).passthrough();
|
|
1461
|
+
var pipelineQuerySchemaValidator = z10.object({
|
|
1462
|
+
name: z10.string(),
|
|
1463
|
+
description: z10.string(),
|
|
879
1464
|
params: jsonSchemaValue,
|
|
880
1465
|
returns: jsonSchemaValue
|
|
881
1466
|
}).passthrough();
|
|
882
|
-
var pipelineSchemaValidator =
|
|
883
|
-
pipeline:
|
|
884
|
-
queries:
|
|
1467
|
+
var pipelineSchemaValidator = z10.object({
|
|
1468
|
+
pipeline: z10.string(),
|
|
1469
|
+
queries: z10.array(pipelineQuerySchemaValidator)
|
|
885
1470
|
}).passthrough();
|
|
886
1471
|
|
|
887
1472
|
// src/cli.ts
|
|
888
|
-
var COMMANDS = /* @__PURE__ */ new Set(["login", "generate", "logout", "discover", "
|
|
1473
|
+
var COMMANDS = /* @__PURE__ */ new Set(["login", "generate", "logout", "discover", "dev", "api-keys"]);
|
|
889
1474
|
var parseArgs = (args) => {
|
|
890
1475
|
const command = args[0];
|
|
891
1476
|
if (!command || command === "--help" || !COMMANDS.has(command)) {
|
|
@@ -915,16 +1500,15 @@ var parseArgs = (args) => {
|
|
|
915
1500
|
var runCommand = async (parsed, deps) => {
|
|
916
1501
|
switch (parsed.command) {
|
|
917
1502
|
case "login":
|
|
918
|
-
|
|
919
|
-
return 0;
|
|
1503
|
+
return handleLogin(parsed, deps);
|
|
920
1504
|
case "generate":
|
|
921
1505
|
return handleGenerate(parsed, deps);
|
|
922
1506
|
case "dev":
|
|
923
1507
|
return handleDev(parsed, deps);
|
|
1508
|
+
case "api-keys":
|
|
1509
|
+
return handleApiKeys(parsed, deps);
|
|
924
1510
|
case "discover":
|
|
925
1511
|
return handleDiscover(parsed, deps);
|
|
926
|
-
case "init":
|
|
927
|
-
return handleInit(parsed, deps);
|
|
928
1512
|
case "logout":
|
|
929
1513
|
handleLogout(deps);
|
|
930
1514
|
return 0;
|
|
@@ -935,29 +1519,131 @@ var runCommand = async (parsed, deps) => {
|
|
|
935
1519
|
return 0;
|
|
936
1520
|
}
|
|
937
1521
|
};
|
|
1522
|
+
var DEVICE_CODE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
|
|
1523
|
+
var LOGIN_TIMEOUT_MS = 16 * 60 * 1e3;
|
|
1524
|
+
var MAX_TRANSIENT_FAILURES = 3;
|
|
938
1525
|
var handleLogin = async (parsed, deps) => {
|
|
939
|
-
const
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
return;
|
|
1526
|
+
const baseUrl = parsed.flags.url ?? await deps.prompt("Platform URL: ");
|
|
1527
|
+
if (!baseUrl || !/^https?:\/\//.test(baseUrl)) {
|
|
1528
|
+
deps.log("Error: a valid HTTP(S) URL is required.");
|
|
1529
|
+
return 1;
|
|
944
1530
|
}
|
|
945
|
-
|
|
946
|
-
|
|
1531
|
+
let deviceCodeRes;
|
|
1532
|
+
try {
|
|
1533
|
+
const res = await deps.fetch(`${baseUrl}/api/cli/device-code`, { method: "POST" });
|
|
1534
|
+
if (!res.ok) {
|
|
1535
|
+
deps.log(`Error: device code request failed (HTTP ${String(res.status)})`);
|
|
1536
|
+
return 1;
|
|
1537
|
+
}
|
|
1538
|
+
deviceCodeRes = await res.json();
|
|
1539
|
+
} catch (err) {
|
|
1540
|
+
deps.log(
|
|
1541
|
+
`Error: could not reach ${baseUrl} \u2014 ${err instanceof Error ? err.message : String(err)}`
|
|
1542
|
+
);
|
|
1543
|
+
return 1;
|
|
1544
|
+
}
|
|
1545
|
+
const { deviceCode, verificationUri, userCode } = deviceCodeRes;
|
|
1546
|
+
if (!deviceCode || !verificationUri || !userCode || deviceCodeRes.interval == null) {
|
|
1547
|
+
deps.log("Error: invalid device code response from server.");
|
|
1548
|
+
return 1;
|
|
1549
|
+
}
|
|
1550
|
+
deps.log(`
|
|
1551
|
+
Your device code: ${bold(userCode)}
|
|
1552
|
+
`);
|
|
1553
|
+
deps.log(` Opening ${verificationUri}`);
|
|
1554
|
+
deps.log(` ${dim("If the browser doesn't open, visit the URL manually.")}
|
|
1555
|
+
`);
|
|
1556
|
+
void deps.openUrl(verificationUri).catch(() => {
|
|
1557
|
+
});
|
|
1558
|
+
let interval = deviceCodeRes.interval;
|
|
1559
|
+
const deadline = Date.now() + LOGIN_TIMEOUT_MS;
|
|
1560
|
+
let transientFailures = 0;
|
|
1561
|
+
while (Date.now() < deadline) {
|
|
1562
|
+
await sleep(interval * 1e3);
|
|
1563
|
+
let tokenRes;
|
|
1564
|
+
try {
|
|
1565
|
+
const res = await deps.fetch(`${baseUrl}/api/cli/token`, {
|
|
1566
|
+
method: "POST",
|
|
1567
|
+
headers: { "Content-Type": "application/json" },
|
|
1568
|
+
body: JSON.stringify({ deviceCode, grant_type: DEVICE_CODE_GRANT_TYPE })
|
|
1569
|
+
});
|
|
1570
|
+
if (res.status >= 500) {
|
|
1571
|
+
transientFailures++;
|
|
1572
|
+
if (transientFailures >= MAX_TRANSIENT_FAILURES) {
|
|
1573
|
+
deps.log("Error: server returned repeated errors. Please try again later.");
|
|
1574
|
+
return 1;
|
|
1575
|
+
}
|
|
1576
|
+
continue;
|
|
1577
|
+
}
|
|
1578
|
+
const contentType = res.headers.get("content-type") ?? "";
|
|
1579
|
+
if (!contentType.includes("json")) {
|
|
1580
|
+
transientFailures++;
|
|
1581
|
+
if (transientFailures >= MAX_TRANSIENT_FAILURES) {
|
|
1582
|
+
deps.log("Error: server returned unexpected response format.");
|
|
1583
|
+
return 1;
|
|
1584
|
+
}
|
|
1585
|
+
continue;
|
|
1586
|
+
}
|
|
1587
|
+
tokenRes = await res.json();
|
|
1588
|
+
transientFailures = 0;
|
|
1589
|
+
} catch {
|
|
1590
|
+
transientFailures++;
|
|
1591
|
+
if (transientFailures >= MAX_TRANSIENT_FAILURES) {
|
|
1592
|
+
deps.log("Error: could not reach server. Please check your network and try again.");
|
|
1593
|
+
return 1;
|
|
1594
|
+
}
|
|
1595
|
+
continue;
|
|
1596
|
+
}
|
|
1597
|
+
if (tokenRes.error === "authorization_pending") {
|
|
1598
|
+
continue;
|
|
1599
|
+
}
|
|
1600
|
+
if (tokenRes.error === "slow_down") {
|
|
1601
|
+
interval += 5;
|
|
1602
|
+
continue;
|
|
1603
|
+
}
|
|
1604
|
+
if (tokenRes.error === "access_denied") {
|
|
1605
|
+
deps.log("Authorization denied.");
|
|
1606
|
+
return 1;
|
|
1607
|
+
}
|
|
1608
|
+
if (tokenRes.error === "expired_token") {
|
|
1609
|
+
deps.log("Device code expired. Please run `kraken login` again.");
|
|
1610
|
+
return 1;
|
|
1611
|
+
}
|
|
1612
|
+
if (tokenRes.accessToken) {
|
|
1613
|
+
deps.saveCredentials({ apiKey: tokenRes.accessToken, baseUrl });
|
|
1614
|
+
const who = tokenRes.user?.email ? ` as ${tokenRes.user.email}` : "";
|
|
1615
|
+
deps.log(`Logged in${who}. Credentials saved.`);
|
|
1616
|
+
return 0;
|
|
1617
|
+
}
|
|
1618
|
+
deps.log(`Error: ${tokenRes.error ?? "unknown error"}`);
|
|
1619
|
+
return 1;
|
|
1620
|
+
}
|
|
1621
|
+
deps.log("Error: login timed out. Please try again.");
|
|
1622
|
+
return 1;
|
|
947
1623
|
};
|
|
1624
|
+
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
948
1625
|
var emptySchemaBundle = {
|
|
949
1626
|
agents: [],
|
|
950
1627
|
queries: [],
|
|
951
1628
|
connectors: [],
|
|
952
1629
|
pipelines: [],
|
|
953
|
-
skills: []
|
|
1630
|
+
skills: [],
|
|
1631
|
+
actions: []
|
|
954
1632
|
};
|
|
955
1633
|
var fetchRemoteSchemas = async (creds, deps) => {
|
|
956
|
-
const
|
|
1634
|
+
const apiKey = new SecretString(creds.apiKey);
|
|
1635
|
+
const headers = { Authorization: `Bearer ${unwrapSecret(apiKey)}` };
|
|
957
1636
|
const controller = new AbortController();
|
|
958
1637
|
const timeout = setTimeout(() => controller.abort(), 1e4);
|
|
959
1638
|
try {
|
|
960
|
-
const endpoints = [
|
|
1639
|
+
const endpoints = [
|
|
1640
|
+
"agents",
|
|
1641
|
+
"queries",
|
|
1642
|
+
"connectors",
|
|
1643
|
+
"pipelines",
|
|
1644
|
+
"skills",
|
|
1645
|
+
"actions"
|
|
1646
|
+
];
|
|
961
1647
|
const responses = await Promise.all(
|
|
962
1648
|
endpoints.map(
|
|
963
1649
|
(ep) => deps.fetch(`${creds.baseUrl}/api/v1/schema/${ep}`, { headers, signal: controller.signal }).then(async (res) => {
|
|
@@ -968,26 +1654,27 @@ var fetchRemoteSchemas = async (creds, deps) => {
|
|
|
968
1654
|
}).catch(() => null)
|
|
969
1655
|
)
|
|
970
1656
|
);
|
|
971
|
-
const [agentsRes, queriesRes, connectorsRes, pipelinesRes, skillsRes] = responses;
|
|
1657
|
+
const [agentsRes, queriesRes, connectorsRes, pipelinesRes, skillsRes, actionsRes] = responses;
|
|
972
1658
|
const allFailed = responses.every((r) => !r?.ok);
|
|
973
1659
|
if (allFailed) {
|
|
974
1660
|
warn(`Could not reach platform at ${creds.baseUrl}. Generating from local definitions only.`);
|
|
975
|
-
return emptySchemaBundle;
|
|
1661
|
+
return { bundle: emptySchemaBundle, reachable: false };
|
|
976
1662
|
}
|
|
977
|
-
const agents = parseEndpointData(agentsRes,
|
|
978
|
-
const queries = parseEndpointData(queriesRes,
|
|
1663
|
+
const agents = parseEndpointData(agentsRes, z11.array(agentSchemaValidator), "agents");
|
|
1664
|
+
const queries = parseEndpointData(queriesRes, z11.array(querySchemaValidator), "queries");
|
|
979
1665
|
const connectors = parseEndpointData(
|
|
980
1666
|
connectorsRes,
|
|
981
|
-
|
|
1667
|
+
z11.array(connectorSchemaValidator),
|
|
982
1668
|
"connectors"
|
|
983
1669
|
);
|
|
984
1670
|
const pipelines = parseEndpointData(
|
|
985
1671
|
pipelinesRes,
|
|
986
|
-
|
|
1672
|
+
z11.array(pipelineSchemaValidator),
|
|
987
1673
|
"pipelines"
|
|
988
1674
|
);
|
|
989
|
-
const skills = parseEndpointData(skillsRes,
|
|
990
|
-
|
|
1675
|
+
const skills = parseEndpointData(skillsRes, z11.array(skillSchemaValidator), "skills");
|
|
1676
|
+
const actions = parseEndpointData(actionsRes, z11.array(actionSchemaValidator), "actions");
|
|
1677
|
+
return { bundle: { agents, queries, connectors, pipelines, skills, actions }, reachable: true };
|
|
991
1678
|
} finally {
|
|
992
1679
|
clearTimeout(timeout);
|
|
993
1680
|
}
|
|
@@ -998,24 +1685,85 @@ var parseEndpointData = (res, validator, endpointName) => {
|
|
|
998
1685
|
const result = validator.safeParse(data);
|
|
999
1686
|
if (!result.success) {
|
|
1000
1687
|
throw new Error(
|
|
1001
|
-
`Invalid remote schema from ${endpointName} endpoint: ${
|
|
1688
|
+
`Invalid remote schema from ${endpointName} endpoint: ${z11.prettifyError(result.error)}`
|
|
1002
1689
|
);
|
|
1003
1690
|
}
|
|
1004
1691
|
return result.data;
|
|
1005
1692
|
};
|
|
1006
|
-
var
|
|
1007
|
-
|
|
1008
|
-
const
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1693
|
+
var execFileAsync = promisify(execFile);
|
|
1694
|
+
var parseGitRemoteFullName = (url) => {
|
|
1695
|
+
const match = url.match(/[:/]([^/:]+\/[^/.]+?)(?:\.git)?\s*$/);
|
|
1696
|
+
return match?.[1] ?? null;
|
|
1697
|
+
};
|
|
1698
|
+
var getGitRemoteFullName = async (cwd) => {
|
|
1699
|
+
try {
|
|
1700
|
+
const { stdout } = await execFileAsync("git", ["remote", "get-url", "origin"], { cwd });
|
|
1701
|
+
return parseGitRemoteFullName(stdout.trim());
|
|
1702
|
+
} catch {
|
|
1703
|
+
return null;
|
|
1704
|
+
}
|
|
1705
|
+
};
|
|
1706
|
+
var resolveRepoName = async (fullName, creds, deps) => {
|
|
1707
|
+
const apiKey = new SecretString(creds.apiKey);
|
|
1708
|
+
try {
|
|
1709
|
+
const res = await deps.fetch(
|
|
1710
|
+
`${creds.baseUrl}/api/v1/schema/repo-name?fullName=${encodeURIComponent(fullName)}`,
|
|
1711
|
+
{ headers: { Authorization: `Bearer ${unwrapSecret(apiKey)}` } }
|
|
1712
|
+
);
|
|
1713
|
+
if (!res.ok) return null;
|
|
1714
|
+
const data = await res.json();
|
|
1715
|
+
return data.name;
|
|
1716
|
+
} catch {
|
|
1717
|
+
return null;
|
|
1718
|
+
}
|
|
1719
|
+
};
|
|
1720
|
+
var mergeLocalAndRemote = (local, remote, repoName) => {
|
|
1721
|
+
const localAgentNames = new Set(local.agents.map((a) => a.name));
|
|
1722
|
+
const localConnectorNames = new Set(local.connectors.map((c) => c.name));
|
|
1723
|
+
const localSkillNames = new Set(local.skills.map((s) => s.name));
|
|
1724
|
+
const localActionNames = new Set(local.actions.map((a) => a.name));
|
|
1725
|
+
const localAgents = local.agents.map((a) => ({
|
|
1726
|
+
id: a.name,
|
|
1727
|
+
name: a.name,
|
|
1728
|
+
input: {},
|
|
1729
|
+
output: {},
|
|
1730
|
+
config: a.config
|
|
1731
|
+
}));
|
|
1732
|
+
const localSkills = local.skills.map((s) => ({
|
|
1733
|
+
id: s.name,
|
|
1734
|
+
name: s.name
|
|
1735
|
+
}));
|
|
1736
|
+
const localConnectors = local.connectors.map((c) => ({
|
|
1737
|
+
id: c.name,
|
|
1738
|
+
tools: []
|
|
1739
|
+
}));
|
|
1740
|
+
const localActions = local.actions.map((a) => ({
|
|
1741
|
+
id: a.name,
|
|
1742
|
+
name: a.name,
|
|
1743
|
+
schema: a.config.schema,
|
|
1744
|
+
hasHandler: a.config.hasHandler
|
|
1745
|
+
}));
|
|
1746
|
+
const isSameRepoLocal = (remoteId, localNames) => {
|
|
1747
|
+
const slashIdx = remoteId.indexOf("/");
|
|
1748
|
+
if (slashIdx === -1) return localNames.has(remoteId);
|
|
1749
|
+
const remoteRepo = remoteId.slice(0, slashIdx);
|
|
1750
|
+
const bareName = remoteId.slice(slashIdx + 1);
|
|
1751
|
+
if (!localNames.has(bareName)) return false;
|
|
1752
|
+
return repoName !== null && remoteRepo === repoName;
|
|
1753
|
+
};
|
|
1754
|
+
const remoteOnlyAgents = remote.agents.filter((a) => !isSameRepoLocal(a.id, localAgentNames));
|
|
1755
|
+
const remoteOnlyConnectors = remote.connectors.filter(
|
|
1756
|
+
(c) => !isSameRepoLocal(c.id, localConnectorNames)
|
|
1757
|
+
);
|
|
1758
|
+
const remoteOnlySkills = remote.skills.filter((s) => !isSameRepoLocal(s.id, localSkillNames));
|
|
1759
|
+
const remoteOnlyActions = remote.actions.filter((a) => !isSameRepoLocal(a.id, localActionNames));
|
|
1013
1760
|
return {
|
|
1014
|
-
agents: [...
|
|
1761
|
+
agents: [...localAgents, ...remoteOnlyAgents],
|
|
1015
1762
|
queries: remote.queries,
|
|
1016
|
-
connectors: [...
|
|
1763
|
+
connectors: [...localConnectors, ...remoteOnlyConnectors],
|
|
1017
1764
|
pipelines: remote.pipelines,
|
|
1018
|
-
skills: [...
|
|
1765
|
+
skills: [...localSkills, ...remoteOnlySkills],
|
|
1766
|
+
actions: [...localActions, ...remoteOnlyActions]
|
|
1019
1767
|
};
|
|
1020
1768
|
};
|
|
1021
1769
|
var handleGenerate = async (parsed, deps) => {
|
|
@@ -1029,22 +1777,30 @@ var handleGenerate = async (parsed, deps) => {
|
|
|
1029
1777
|
}
|
|
1030
1778
|
const creds = deps.loadCredentials();
|
|
1031
1779
|
let remote;
|
|
1780
|
+
let remoteReachable = false;
|
|
1781
|
+
let repoName = null;
|
|
1032
1782
|
if (creds?.apiKey && creds?.baseUrl) {
|
|
1033
1783
|
try {
|
|
1034
|
-
|
|
1784
|
+
const result = await fetchRemoteSchemas(creds, deps);
|
|
1785
|
+
remote = result.bundle;
|
|
1786
|
+
remoteReachable = result.reachable;
|
|
1035
1787
|
} catch (err) {
|
|
1036
1788
|
deps.log(
|
|
1037
1789
|
`Error fetching remote schemas: ${err instanceof Error ? err.message : String(err)}`
|
|
1038
1790
|
);
|
|
1039
1791
|
return 1;
|
|
1040
1792
|
}
|
|
1793
|
+
const fullName = await getGitRemoteFullName(outDir);
|
|
1794
|
+
if (fullName) {
|
|
1795
|
+
repoName = await resolveRepoName(fullName, creds, deps);
|
|
1796
|
+
}
|
|
1041
1797
|
} else {
|
|
1042
1798
|
warn(
|
|
1043
1799
|
"Not logged in. Generating from local definitions only. Run `kraken login` to sync with the platform."
|
|
1044
1800
|
);
|
|
1045
1801
|
remote = emptySchemaBundle;
|
|
1046
1802
|
}
|
|
1047
|
-
const bundle = mergeLocalAndRemote(manifest, remote);
|
|
1803
|
+
const bundle = mergeLocalAndRemote(manifest, remote, repoName);
|
|
1048
1804
|
if ("check" in parsed.flags) {
|
|
1049
1805
|
const { mkdtempSync, readFileSync, rmSync } = await import("fs");
|
|
1050
1806
|
const { join } = await import("path");
|
|
@@ -1061,11 +1817,10 @@ var handleGenerate = async (parsed, deps) => {
|
|
|
1061
1817
|
const files = [
|
|
1062
1818
|
"pipelines.json",
|
|
1063
1819
|
"pipelines.d.ts",
|
|
1064
|
-
"pipelines.ts",
|
|
1065
|
-
// stale file detection — should not exist after migration
|
|
1066
1820
|
"agents.d.ts",
|
|
1067
1821
|
"queries.d.ts",
|
|
1068
1822
|
"connectors.d.ts",
|
|
1823
|
+
"actions.d.ts",
|
|
1069
1824
|
"platform-types.d.ts",
|
|
1070
1825
|
"index.d.ts",
|
|
1071
1826
|
"manifest.json"
|
|
@@ -1097,9 +1852,49 @@ var handleGenerate = async (parsed, deps) => {
|
|
|
1097
1852
|
deps.log(`Error generating types: ${err instanceof Error ? err.message : String(err)}`);
|
|
1098
1853
|
return 1;
|
|
1099
1854
|
}
|
|
1100
|
-
const
|
|
1101
|
-
|
|
1102
|
-
|
|
1855
|
+
const localNames = {
|
|
1856
|
+
agents: new Set(manifest.agents.map((a) => a.name)),
|
|
1857
|
+
connectors: new Set(manifest.connectors.map((c) => c.name)),
|
|
1858
|
+
skills: new Set(manifest.skills.map((s) => s.name)),
|
|
1859
|
+
actions: new Set(manifest.actions.map((a) => a.name))
|
|
1860
|
+
};
|
|
1861
|
+
const matchesLocalSummary = (remoteId, names) => {
|
|
1862
|
+
const slashIdx = remoteId.indexOf("/");
|
|
1863
|
+
if (slashIdx !== -1) {
|
|
1864
|
+
return names.has(remoteId.slice(slashIdx + 1));
|
|
1865
|
+
}
|
|
1866
|
+
return names.has(remoteId);
|
|
1867
|
+
};
|
|
1868
|
+
const remoteOnlyAgents = remote.agents.filter(
|
|
1869
|
+
(a) => !matchesLocalSummary(a.id, localNames.agents)
|
|
1870
|
+
);
|
|
1871
|
+
const remoteOnlyConnectors = remote.connectors.filter(
|
|
1872
|
+
(c) => !matchesLocalSummary(c.id, localNames.connectors)
|
|
1873
|
+
);
|
|
1874
|
+
const remoteOnlySkills = remote.skills.filter(
|
|
1875
|
+
(s) => !matchesLocalSummary(s.id, localNames.skills)
|
|
1876
|
+
);
|
|
1877
|
+
const remoteOnlyActions = remote.actions.filter(
|
|
1878
|
+
(a) => !matchesLocalSummary(a.id, localNames.actions)
|
|
1879
|
+
);
|
|
1880
|
+
const lines = [];
|
|
1881
|
+
lines.push(` ${dim("[kraken-ai]")} ${bold("Generated types:")}`);
|
|
1882
|
+
for (const a of manifest.agents) lines.push(` agent ${a.name}`);
|
|
1883
|
+
for (const a of remoteOnlyAgents) lines.push(` agent ${a.id} (remote)`);
|
|
1884
|
+
for (const c of manifest.connectors) lines.push(` connector ${c.name}`);
|
|
1885
|
+
for (const c of remoteOnlyConnectors) lines.push(` connector ${c.id} (remote)`);
|
|
1886
|
+
for (const s of manifest.skills) lines.push(` skill ${s.name}`);
|
|
1887
|
+
for (const s of remoteOnlySkills) lines.push(` skill ${s.id} (remote)`);
|
|
1888
|
+
for (const a of manifest.actions) lines.push(` action ${a.name}`);
|
|
1889
|
+
for (const a of remoteOnlyActions) lines.push(` action ${a.id} (remote)`);
|
|
1890
|
+
if (bundle.queries.length > 0) lines.push(` queries ${String(bundle.queries.length)}`);
|
|
1891
|
+
if (bundle.pipelines.length > 0) lines.push(` pipelines ${String(bundle.pipelines.length)}`);
|
|
1892
|
+
const hasRemote = remoteOnlyAgents.length + remoteOnlyConnectors.length + remoteOnlySkills.length + remoteOnlyActions.length > 0;
|
|
1893
|
+
if (!hasRemote && remoteReachable) {
|
|
1894
|
+
lines.push("");
|
|
1895
|
+
lines.push(" All platform entities are defined locally. No remote-only dependencies.");
|
|
1896
|
+
}
|
|
1897
|
+
deps.log(lines.join("\n"));
|
|
1103
1898
|
return 0;
|
|
1104
1899
|
};
|
|
1105
1900
|
var safeReadFile = (readFileSync, filePath) => {
|
|
@@ -1123,7 +1918,7 @@ var buildDevBootstrap = (fileUrl, file) => [
|
|
|
1123
1918
|
].join("\n");
|
|
1124
1919
|
var discoverAgentFiles = async () => {
|
|
1125
1920
|
const { readdirSync, existsSync } = await import("fs");
|
|
1126
|
-
const agentsDir = "agents";
|
|
1921
|
+
const agentsDir = "src/agents";
|
|
1127
1922
|
if (!existsSync(agentsDir)) return [];
|
|
1128
1923
|
return readdirSync(agentsDir).filter((f) => f.endsWith(".ts") || f.endsWith(".js") || f.endsWith(".mjs")).sort();
|
|
1129
1924
|
};
|
|
@@ -1132,7 +1927,9 @@ var handleDev = async (parsed, deps) => {
|
|
|
1132
1927
|
if (!name) {
|
|
1133
1928
|
const agents = await discoverAgentFiles();
|
|
1134
1929
|
if (agents.length === 0) {
|
|
1135
|
-
deps.log(
|
|
1930
|
+
deps.log(
|
|
1931
|
+
"No agent files found in src/agents/. Create one or pass a name: kraken dev <agent>"
|
|
1932
|
+
);
|
|
1136
1933
|
return 1;
|
|
1137
1934
|
}
|
|
1138
1935
|
if (agents.length === 1) {
|
|
@@ -1144,7 +1941,7 @@ var handleDev = async (parsed, deps) => {
|
|
|
1144
1941
|
}
|
|
1145
1942
|
}
|
|
1146
1943
|
if (!name) return 1;
|
|
1147
|
-
const file = name.includes("/") ? name : `agents/${name}`;
|
|
1944
|
+
const file = name.includes("/") ? name : `src/agents/${name}`;
|
|
1148
1945
|
const { spawn } = await import("child_process");
|
|
1149
1946
|
const { resolve } = await import("path");
|
|
1150
1947
|
const { pathToFileURL: pathToFileURL2 } = await import("url");
|
|
@@ -1161,9 +1958,11 @@ var handleDev = async (parsed, deps) => {
|
|
|
1161
1958
|
var handleDiscover = async (parsed, deps) => {
|
|
1162
1959
|
const dir = parsed.flags.dir ?? process.cwd();
|
|
1163
1960
|
const manifest = await deps.discoverProject(dir);
|
|
1164
|
-
const total = manifest.agents.length + manifest.skills.length + manifest.connectors.length;
|
|
1961
|
+
const total = manifest.agents.length + manifest.skills.length + manifest.connectors.length + manifest.actions.length;
|
|
1165
1962
|
if (total === 0) {
|
|
1166
|
-
deps.log(
|
|
1963
|
+
deps.log(
|
|
1964
|
+
"No entities found in src/agents/, src/skills/, src/connectors/, or src/actions/ directories."
|
|
1965
|
+
);
|
|
1167
1966
|
return 1;
|
|
1168
1967
|
}
|
|
1169
1968
|
if ("emit" in parsed.flags) {
|
|
@@ -1173,89 +1972,6 @@ var handleDiscover = async (parsed, deps) => {
|
|
|
1173
1972
|
}
|
|
1174
1973
|
return 0;
|
|
1175
1974
|
};
|
|
1176
|
-
var handleInit = async (parsed, deps) => {
|
|
1177
|
-
const name = parsed.flags.name ?? await deps.prompt("Project name: ");
|
|
1178
|
-
if (!name) {
|
|
1179
|
-
deps.log("Error: project name is required.");
|
|
1180
|
-
return 1;
|
|
1181
|
-
}
|
|
1182
|
-
const { writeFileSync, mkdirSync } = await import("fs");
|
|
1183
|
-
const { join } = await import("path");
|
|
1184
|
-
const root = join(process.cwd(), name);
|
|
1185
|
-
mkdirSync(join(root, "agents"), { recursive: true });
|
|
1186
|
-
mkdirSync(join(root, "skills"), { recursive: true });
|
|
1187
|
-
mkdirSync(join(root, "connectors"), { recursive: true });
|
|
1188
|
-
writeFileSync(
|
|
1189
|
-
join(root, "package.json"),
|
|
1190
|
-
JSON.stringify(
|
|
1191
|
-
{
|
|
1192
|
-
name,
|
|
1193
|
-
private: true,
|
|
1194
|
-
type: "module",
|
|
1195
|
-
scripts: { build: "tsc" },
|
|
1196
|
-
dependencies: {
|
|
1197
|
-
"kraken-ai": "latest",
|
|
1198
|
-
"@kraken-ai/platform": "latest"
|
|
1199
|
-
},
|
|
1200
|
-
devDependencies: {
|
|
1201
|
-
typescript: "^5"
|
|
1202
|
-
}
|
|
1203
|
-
},
|
|
1204
|
-
null,
|
|
1205
|
-
2
|
|
1206
|
-
)
|
|
1207
|
-
);
|
|
1208
|
-
writeFileSync(
|
|
1209
|
-
join(root, "tsconfig.json"),
|
|
1210
|
-
JSON.stringify(
|
|
1211
|
-
{
|
|
1212
|
-
compilerOptions: {
|
|
1213
|
-
target: "ES2022",
|
|
1214
|
-
module: "NodeNext",
|
|
1215
|
-
moduleResolution: "nodenext",
|
|
1216
|
-
resolveJsonModule: true,
|
|
1217
|
-
strict: true,
|
|
1218
|
-
outDir: "dist",
|
|
1219
|
-
rootDir: ".",
|
|
1220
|
-
declaration: true,
|
|
1221
|
-
esModuleInterop: true,
|
|
1222
|
-
skipLibCheck: true
|
|
1223
|
-
},
|
|
1224
|
-
include: ["agents", "skills", "connectors"]
|
|
1225
|
-
},
|
|
1226
|
-
null,
|
|
1227
|
-
2
|
|
1228
|
-
)
|
|
1229
|
-
);
|
|
1230
|
-
writeFileSync(
|
|
1231
|
-
join(root, "agents", "my-agent.ts"),
|
|
1232
|
-
`import { definePlatformAgent } from "@kraken-ai/platform";
|
|
1233
|
-
|
|
1234
|
-
export default definePlatformAgent({
|
|
1235
|
-
agent: {
|
|
1236
|
-
name: "my-agent",
|
|
1237
|
-
model: "google/gemini-2.5-flash-preview-05-20",
|
|
1238
|
-
instructions: "You are a helpful assistant.",
|
|
1239
|
-
},
|
|
1240
|
-
triggers: [{ type: "manual" }],
|
|
1241
|
-
});
|
|
1242
|
-
`
|
|
1243
|
-
);
|
|
1244
|
-
writeFileSync(join(root, ".gitignore"), `node_modules/
|
|
1245
|
-
dist/
|
|
1246
|
-
.kraken-ai/
|
|
1247
|
-
data/
|
|
1248
|
-
.env
|
|
1249
|
-
`);
|
|
1250
|
-
deps.log(`Created project at ${root}/`);
|
|
1251
|
-
deps.log(`
|
|
1252
|
-
cd ${name}
|
|
1253
|
-
pnpm install
|
|
1254
|
-
kraken login
|
|
1255
|
-
kraken generate
|
|
1256
|
-
`);
|
|
1257
|
-
return 0;
|
|
1258
|
-
};
|
|
1259
1975
|
var handleLogout = (deps) => {
|
|
1260
1976
|
deps.clearCredentials();
|
|
1261
1977
|
deps.log("Credentials cleared.");
|
|
@@ -1267,23 +1983,20 @@ kraken \u2014 Kraken AI Platform CLI
|
|
|
1267
1983
|
|
|
1268
1984
|
Commands:
|
|
1269
1985
|
dev Run an agent locally with an interactive REPL
|
|
1270
|
-
[agent] Agent filename, e.g. researcher.ts (optional \u2014 picks from agents/ if omitted)
|
|
1986
|
+
[agent] Agent filename, e.g. researcher.ts (optional \u2014 picks from src/agents/ if omitted)
|
|
1271
1987
|
|
|
1272
|
-
login
|
|
1988
|
+
login Authenticate via browser-based device authorization
|
|
1273
1989
|
--url <platform-url> Platform instance URL
|
|
1274
|
-
|
|
1990
|
+
|
|
1991
|
+
api-keys Manage API keys for server-side SDK authentication
|
|
1992
|
+
create --name <name> [--expires 90d] Create a new API key
|
|
1993
|
+
list List all API keys
|
|
1994
|
+
revoke <id> Revoke an API key
|
|
1275
1995
|
|
|
1276
1996
|
generate Discover local entities and fetch remote schemas to generate types
|
|
1277
1997
|
--dir <path> Project root / output directory (default: cwd)
|
|
1278
1998
|
--check Check if types are up-to-date (exit 1 if stale)
|
|
1279
1999
|
|
|
1280
|
-
discover Scan agents/, skills/, connectors/ and output project manifest
|
|
1281
|
-
--dir <path> Project root (default: cwd)
|
|
1282
|
-
--emit Output with sentinel markers (for orchestrator)
|
|
1283
|
-
|
|
1284
|
-
init Create a new Kraken project
|
|
1285
|
-
--name <project-name> Project name
|
|
1286
|
-
|
|
1287
2000
|
logout Clear stored credentials
|
|
1288
2001
|
|
|
1289
2002
|
Environment variables:
|
|
@@ -1302,6 +2015,21 @@ var readlinePrompt = async (question) => {
|
|
|
1302
2015
|
});
|
|
1303
2016
|
});
|
|
1304
2017
|
};
|
|
2018
|
+
var openUrlImpl = async (url) => {
|
|
2019
|
+
if (!/^https?:\/\//.test(url)) return;
|
|
2020
|
+
const { platform } = await import("os");
|
|
2021
|
+
try {
|
|
2022
|
+
const p = platform();
|
|
2023
|
+
if (p === "darwin") {
|
|
2024
|
+
await execFileAsync("open", [url]);
|
|
2025
|
+
} else if (p === "win32") {
|
|
2026
|
+
await execFileAsync("cmd", ["/c", "start", "", url]);
|
|
2027
|
+
} else {
|
|
2028
|
+
await execFileAsync("xdg-open", [url]);
|
|
2029
|
+
}
|
|
2030
|
+
} catch {
|
|
2031
|
+
}
|
|
2032
|
+
};
|
|
1305
2033
|
var main = async () => {
|
|
1306
2034
|
const parsed = parseArgs(process.argv.slice(2));
|
|
1307
2035
|
const exitCode = await runCommand(parsed, {
|
|
@@ -1312,7 +2040,8 @@ var main = async () => {
|
|
|
1312
2040
|
discoverProject,
|
|
1313
2041
|
fetch: globalThis.fetch,
|
|
1314
2042
|
prompt: readlinePrompt,
|
|
1315
|
-
log: console.log
|
|
2043
|
+
log: console.log,
|
|
2044
|
+
openUrl: openUrlImpl
|
|
1316
2045
|
});
|
|
1317
2046
|
if (exitCode !== 0) process.exit(exitCode);
|
|
1318
2047
|
};
|