@agentskit/cli 0.13.37 → 0.13.40
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/bin.cjs +389 -146
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-DZKCRKFS.js → chunk-7ALDICSL.js} +396 -153
- package/dist/chunk-7ALDICSL.js.map +1 -0
- package/dist/index.cjs +390 -147
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -4
- package/dist/index.d.ts +6 -4
- package/dist/index.js +1 -1
- package/package.json +25 -21
- package/LICENSE +0 -21
- package/dist/chunk-DZKCRKFS.js.map +0 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { readdir, stat, mkdir, writeFile,
|
|
2
|
+
import { readdir, stat, glob, readFile, mkdir, lstat, mkdtemp, writeFile, rename, rm, access } from 'fs/promises';
|
|
3
3
|
import { homedir } from 'os';
|
|
4
|
-
import path, { join, resolve, isAbsolute, basename, dirname, sep } from 'path';
|
|
4
|
+
import path, { join, resolve, isAbsolute, basename, dirname, relative, sep } from 'path';
|
|
5
5
|
import { openrouter, groq, kimi, grok, deepseek, ollama, gemini, anthropic, openai } from '@agentskit/adapters';
|
|
6
|
-
import { randomBytes, createHash } from 'crypto';
|
|
7
|
-
import { writeFileSync, existsSync, readdirSync, statSync, readFileSync, mkdirSync, rmSync } from 'fs';
|
|
6
|
+
import { randomBytes, randomUUID, createHash } from 'crypto';
|
|
7
|
+
import { writeFileSync, chmodSync, existsSync, readdirSync, statSync, readFileSync, mkdirSync, rmSync } from 'fs';
|
|
8
8
|
import { spawn } from 'child_process';
|
|
9
9
|
import React2, { useMemo, useState, useEffect, useRef } from 'react';
|
|
10
10
|
import { Box, Text, render } from 'ink';
|
|
@@ -16,6 +16,7 @@ import { getIntegration, integrationToolsFromEnv } from '@agentskit/integrations
|
|
|
16
16
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
17
17
|
import { pathToFileURL } from 'url';
|
|
18
18
|
import { createRuntime, validateFlow, flowToMermaid, compileFlow, createFileStepLog } from '@agentskit/runtime';
|
|
19
|
+
import { createRequire } from 'module';
|
|
19
20
|
import chokidar from 'chokidar';
|
|
20
21
|
import kleur3 from 'kleur';
|
|
21
22
|
import { createRAG } from '@agentskit/rag';
|
|
@@ -26,20 +27,27 @@ import { parse } from 'yaml';
|
|
|
26
27
|
import { validatePIITaxonomy } from '@agentskit/core/security';
|
|
27
28
|
import { ConfigError, ErrorCodes } from '@agentskit/core';
|
|
28
29
|
|
|
29
|
-
async function loadJsonConfig(
|
|
30
|
+
async function loadJsonConfig(path6) {
|
|
30
31
|
try {
|
|
31
|
-
const raw = await readFile(
|
|
32
|
+
const raw = await readFile(path6, "utf8");
|
|
32
33
|
return JSON.parse(raw);
|
|
33
|
-
} catch {
|
|
34
|
-
return void 0;
|
|
34
|
+
} catch (err) {
|
|
35
|
+
if (err.code === "ENOENT") return void 0;
|
|
36
|
+
throw new Error(`Failed to load JSON config ${path6}: ${err instanceof Error ? err.message : String(err)}`);
|
|
35
37
|
}
|
|
36
38
|
}
|
|
37
|
-
async function loadTsConfig(
|
|
39
|
+
async function loadTsConfig(path6) {
|
|
40
|
+
try {
|
|
41
|
+
await access(path6);
|
|
42
|
+
} catch (err) {
|
|
43
|
+
if (err.code === "ENOENT") return void 0;
|
|
44
|
+
throw err;
|
|
45
|
+
}
|
|
38
46
|
try {
|
|
39
|
-
const mod = await import(
|
|
47
|
+
const mod = await import(`${path6}?agentskit_config=${Date.now()}`);
|
|
40
48
|
return mod.default ?? mod;
|
|
41
|
-
} catch {
|
|
42
|
-
|
|
49
|
+
} catch (err) {
|
|
50
|
+
throw new Error(`Failed to load TypeScript config ${path6}: ${err instanceof Error ? err.message : String(err)}`);
|
|
43
51
|
}
|
|
44
52
|
}
|
|
45
53
|
async function loadPackageJsonConfig(dir) {
|
|
@@ -50,29 +58,31 @@ async function loadPackageJsonConfig(dir) {
|
|
|
50
58
|
return pkg.agentskit;
|
|
51
59
|
}
|
|
52
60
|
return void 0;
|
|
53
|
-
} catch {
|
|
54
|
-
return void 0;
|
|
61
|
+
} catch (err) {
|
|
62
|
+
if (err.code === "ENOENT") return void 0;
|
|
63
|
+
throw new Error(`Failed to load package.json config ${dir}: ${err instanceof Error ? err.message : String(err)}`);
|
|
55
64
|
}
|
|
56
65
|
}
|
|
57
66
|
function mergeConfigs(base, override) {
|
|
58
67
|
if (!base && !override) return void 0;
|
|
59
68
|
if (!base) return override;
|
|
60
69
|
if (!override) return base;
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
70
|
+
const merge = (left, right) => {
|
|
71
|
+
if (!left || typeof left !== "object" || Array.isArray(left)) return right;
|
|
72
|
+
if (!right || typeof right !== "object" || Array.isArray(right)) return right;
|
|
73
|
+
const out = { ...left };
|
|
74
|
+
for (const [key, value] of Object.entries(right)) {
|
|
75
|
+
out[key] = key in out ? merge(out[key], value) : value;
|
|
76
|
+
}
|
|
77
|
+
return out;
|
|
68
78
|
};
|
|
79
|
+
return merge(base, override);
|
|
69
80
|
}
|
|
70
81
|
async function loadLocalConfig(cwd) {
|
|
71
82
|
const tsConfig = await loadTsConfig(join(cwd, ".agentskit.config.ts"));
|
|
72
|
-
if (tsConfig) return tsConfig;
|
|
73
83
|
const jsonConfig = await loadJsonConfig(join(cwd, ".agentskit.config.json"));
|
|
74
|
-
|
|
75
|
-
return
|
|
84
|
+
const packageConfig = await loadPackageJsonConfig(cwd);
|
|
85
|
+
return mergeConfigs(mergeConfigs(packageConfig, jsonConfig), tsConfig);
|
|
76
86
|
}
|
|
77
87
|
async function loadGlobalConfig(home) {
|
|
78
88
|
if (home === null) return void 0;
|
|
@@ -87,6 +97,21 @@ async function loadConfig(options) {
|
|
|
87
97
|
const local = await loadLocalConfig(cwd);
|
|
88
98
|
return mergeConfigs(global, local);
|
|
89
99
|
}
|
|
100
|
+
var SECRET_KEY = /^(api[-_]?key|token|secret|password|authorization|private[-_]?key)$/i;
|
|
101
|
+
var SECRET_ENV_KEY = /(?:^|_)(?:api_?key|token|secret|password|authorization|private_?key)$/i;
|
|
102
|
+
function isSecretKey(key) {
|
|
103
|
+
return SECRET_KEY.test(key) || SECRET_ENV_KEY.test(key);
|
|
104
|
+
}
|
|
105
|
+
function redactConfig(value) {
|
|
106
|
+
if (Array.isArray(value)) return value.map(redactConfig);
|
|
107
|
+
if (!value || typeof value !== "object") return value;
|
|
108
|
+
return Object.fromEntries(
|
|
109
|
+
Object.entries(value).map(([key, child]) => [
|
|
110
|
+
key,
|
|
111
|
+
isSecretKey(key) ? "[REDACTED]" : redactConfig(child)
|
|
112
|
+
])
|
|
113
|
+
);
|
|
114
|
+
}
|
|
90
115
|
var providers = {
|
|
91
116
|
openai: {
|
|
92
117
|
label: "OpenAI",
|
|
@@ -158,7 +183,7 @@ function createDemoAdapter(provider, model) {
|
|
|
158
183
|
].join(" ");
|
|
159
184
|
for (const chunk of reply.match(/.{1,18}/g) ?? []) {
|
|
160
185
|
if (cancelled) return;
|
|
161
|
-
await new Promise((
|
|
186
|
+
await new Promise((resolve8) => setTimeout(resolve8, 35));
|
|
162
187
|
yield { type: "text", content: chunk };
|
|
163
188
|
}
|
|
164
189
|
yield { type: "done" };
|
|
@@ -218,7 +243,8 @@ function dirFor(cwd = process.cwd()) {
|
|
|
218
243
|
return join(ROOT, cwdHash(cwd));
|
|
219
244
|
}
|
|
220
245
|
function ensureDir(dir) {
|
|
221
|
-
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
246
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true, mode: 448 });
|
|
247
|
+
chmodSync(dir, 448);
|
|
222
248
|
}
|
|
223
249
|
function generateSessionId() {
|
|
224
250
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
@@ -233,17 +259,19 @@ function metaPath(id, cwd = process.cwd()) {
|
|
|
233
259
|
return join(dirFor(cwd), `${id}${META_SUFFIX}`);
|
|
234
260
|
}
|
|
235
261
|
function readMeta(id, cwd = process.cwd()) {
|
|
236
|
-
const
|
|
237
|
-
if (!existsSync(
|
|
262
|
+
const path6 = metaPath(id, cwd);
|
|
263
|
+
if (!existsSync(path6)) return null;
|
|
238
264
|
try {
|
|
239
|
-
return JSON.parse(readFileSync(
|
|
265
|
+
return JSON.parse(readFileSync(path6, "utf8"));
|
|
240
266
|
} catch {
|
|
241
267
|
return null;
|
|
242
268
|
}
|
|
243
269
|
}
|
|
244
270
|
function writeSessionMeta(meta, cwd = process.cwd()) {
|
|
245
271
|
ensureDir(dirFor(cwd));
|
|
246
|
-
|
|
272
|
+
const path6 = metaPath(meta.id, cwd);
|
|
273
|
+
writeFileSync(path6, JSON.stringify(meta, null, 2), { mode: 384 });
|
|
274
|
+
chmodSync(path6, 384);
|
|
247
275
|
}
|
|
248
276
|
function derivePreview(messages) {
|
|
249
277
|
const firstUser = messages.find((m) => m.role === "user" && m.content.trim());
|
|
@@ -445,7 +473,7 @@ var HookDispatcher = class {
|
|
|
445
473
|
result = await handler.run(current);
|
|
446
474
|
} catch (err) {
|
|
447
475
|
this.onError(handler, err);
|
|
448
|
-
|
|
476
|
+
return { payload: current, blocked: true, reason: "hook failed" };
|
|
449
477
|
}
|
|
450
478
|
if (result.decision === "block") {
|
|
451
479
|
return { payload: current, blocked: true, reason: result.reason };
|
|
@@ -462,6 +490,7 @@ var HookDispatcher = class {
|
|
|
462
490
|
return handler.matcher.test(String(payload.tool ?? payload.prompt ?? ""));
|
|
463
491
|
}
|
|
464
492
|
};
|
|
493
|
+
var MAX_HOOK_STDOUT_BYTES = 64 * 1024;
|
|
465
494
|
function configHooksToHandlers(config) {
|
|
466
495
|
if (!config) return [];
|
|
467
496
|
const handlers = [];
|
|
@@ -491,8 +520,26 @@ function runShellHook(entry, payload) {
|
|
|
491
520
|
detached: true
|
|
492
521
|
});
|
|
493
522
|
let stdout = "";
|
|
523
|
+
let stdoutBytes = 0;
|
|
494
524
|
child.stdout.on("data", (chunk) => {
|
|
495
|
-
|
|
525
|
+
const text = chunk.toString();
|
|
526
|
+
const bytes = Buffer.byteLength(text);
|
|
527
|
+
if (stdoutBytes + bytes > MAX_HOOK_STDOUT_BYTES) {
|
|
528
|
+
if (child.pid !== void 0) {
|
|
529
|
+
try {
|
|
530
|
+
process.kill(-child.pid, "SIGKILL");
|
|
531
|
+
} catch {
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
try {
|
|
535
|
+
child.kill("SIGKILL");
|
|
536
|
+
} catch {
|
|
537
|
+
}
|
|
538
|
+
settle({ decision: "block", reason: `shell hook output exceeded ${MAX_HOOK_STDOUT_BYTES} bytes` });
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
stdoutBytes += bytes;
|
|
542
|
+
stdout += text;
|
|
496
543
|
});
|
|
497
544
|
const timer = setTimeout(() => {
|
|
498
545
|
if (child.pid !== void 0) {
|
|
@@ -524,9 +571,13 @@ function runShellHook(entry, payload) {
|
|
|
524
571
|
}
|
|
525
572
|
try {
|
|
526
573
|
const parsed = JSON.parse(trimmed);
|
|
527
|
-
|
|
574
|
+
if (!parsed || typeof parsed !== "object" || !("decision" in parsed) || !["continue", "block", "modify"].includes(String(parsed.decision))) {
|
|
575
|
+
settle({ decision: "block", reason: "shell hook returned an invalid decision" });
|
|
576
|
+
} else {
|
|
577
|
+
settle(parsed);
|
|
578
|
+
}
|
|
528
579
|
} catch {
|
|
529
|
-
settle({ decision: "
|
|
580
|
+
settle({ decision: "block", reason: "shell hook returned invalid JSON" });
|
|
530
581
|
}
|
|
531
582
|
});
|
|
532
583
|
child.on("error", (err) => {
|
|
@@ -980,8 +1031,9 @@ function ChatApp(options) {
|
|
|
980
1031
|
} = useRuntime(options);
|
|
981
1032
|
const mergedTools = useMemo(() => {
|
|
982
1033
|
const extra = options.extraTools ?? [];
|
|
983
|
-
|
|
984
|
-
|
|
1034
|
+
const combined = [...tools, ...extra];
|
|
1035
|
+
return options.permissionPolicy ? applyPolicyToTools(options.permissionPolicy, combined) : combined;
|
|
1036
|
+
}, [tools, options.extraTools, options.permissionPolicy]);
|
|
985
1037
|
const mergedSkills = useMemo(() => {
|
|
986
1038
|
const extra = options.extraSkills ?? [];
|
|
987
1039
|
if (!skills && extra.length === 0) return void 0;
|
|
@@ -1175,7 +1227,7 @@ async function loadPlugins(options = {}) {
|
|
|
1175
1227
|
specs = [],
|
|
1176
1228
|
pluginDirs = [],
|
|
1177
1229
|
cwd = process.cwd(),
|
|
1178
|
-
autoDiscoverUserDir =
|
|
1230
|
+
autoDiscoverUserDir = false,
|
|
1179
1231
|
onError = (spec, err) => process.stderr.write(
|
|
1180
1232
|
`[agentskit] plugin "${spec}" failed to load: ${err instanceof Error ? err.message : String(err)}
|
|
1181
1233
|
`
|
|
@@ -1266,6 +1318,8 @@ function mergePluginsIntoBundle(plugins) {
|
|
|
1266
1318
|
}
|
|
1267
1319
|
return bundle;
|
|
1268
1320
|
}
|
|
1321
|
+
var MAX_FRAME_BYTES = 1024 * 1024;
|
|
1322
|
+
var DISPOSE_GRACE_MS = 1e3;
|
|
1269
1323
|
var McpClient = class {
|
|
1270
1324
|
constructor(spec, onError = (err) => process.stderr.write(
|
|
1271
1325
|
`[agentskit] mcp[${spec.name}] error: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -1282,7 +1336,8 @@ var McpClient = class {
|
|
|
1282
1336
|
if (this.child) return;
|
|
1283
1337
|
const child = spawn(this.spec.command, this.spec.args ?? [], {
|
|
1284
1338
|
env: { ...process.env, ...this.spec.env ?? {} },
|
|
1285
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
1339
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
1340
|
+
detached: process.platform !== "win32"
|
|
1286
1341
|
});
|
|
1287
1342
|
this.child = child;
|
|
1288
1343
|
child.stdout.on("data", (chunk) => this.onStdout(chunk.toString()));
|
|
@@ -1314,7 +1369,22 @@ var McpClient = class {
|
|
|
1314
1369
|
dispose() {
|
|
1315
1370
|
if (this.disposed) return;
|
|
1316
1371
|
this.disposed = true;
|
|
1317
|
-
this.
|
|
1372
|
+
for (const pending of this.pending.values()) {
|
|
1373
|
+
pending({ jsonrpc: "2.0", id: 0, error: { code: -32800, message: "client disposed" } });
|
|
1374
|
+
}
|
|
1375
|
+
this.pending.clear();
|
|
1376
|
+
const child = this.child;
|
|
1377
|
+
if (!child || child.killed) return;
|
|
1378
|
+
const kill = (signal) => {
|
|
1379
|
+
try {
|
|
1380
|
+
if (process.platform !== "win32" && child.pid) process.kill(-child.pid, signal);
|
|
1381
|
+
else child.kill(signal);
|
|
1382
|
+
} catch {
|
|
1383
|
+
}
|
|
1384
|
+
};
|
|
1385
|
+
kill("SIGTERM");
|
|
1386
|
+
const timer = setTimeout(() => kill("SIGKILL"), DISPOSE_GRACE_MS);
|
|
1387
|
+
timer.unref();
|
|
1318
1388
|
}
|
|
1319
1389
|
request(method, params) {
|
|
1320
1390
|
return new Promise((resolvePromise, rejectPromise) => {
|
|
@@ -1342,10 +1412,20 @@ var McpClient = class {
|
|
|
1342
1412
|
}
|
|
1343
1413
|
onStdout(chunk) {
|
|
1344
1414
|
this.buffer += chunk;
|
|
1415
|
+
if (Buffer.byteLength(this.buffer, "utf8") > MAX_FRAME_BYTES && !this.buffer.includes("\n")) {
|
|
1416
|
+
this.onError(new Error(`mcp ${this.spec.name} frame exceeded ${MAX_FRAME_BYTES} bytes`));
|
|
1417
|
+
this.dispose();
|
|
1418
|
+
return;
|
|
1419
|
+
}
|
|
1345
1420
|
let newlineIndex = this.buffer.indexOf("\n");
|
|
1346
1421
|
while (newlineIndex !== -1) {
|
|
1347
1422
|
const line = this.buffer.slice(0, newlineIndex).trim();
|
|
1348
1423
|
this.buffer = this.buffer.slice(newlineIndex + 1);
|
|
1424
|
+
if (Buffer.byteLength(line, "utf8") > MAX_FRAME_BYTES) {
|
|
1425
|
+
this.onError(new Error(`mcp ${this.spec.name} frame exceeded ${MAX_FRAME_BYTES} bytes`));
|
|
1426
|
+
this.dispose();
|
|
1427
|
+
return;
|
|
1428
|
+
}
|
|
1349
1429
|
if (line) {
|
|
1350
1430
|
try {
|
|
1351
1431
|
const parsed = JSON.parse(line);
|
|
@@ -1421,8 +1501,7 @@ function formatEvent(event) {
|
|
|
1421
1501
|
}
|
|
1422
1502
|
async function runAgent(task, options) {
|
|
1423
1503
|
if (options.skill && options.skills) {
|
|
1424
|
-
|
|
1425
|
-
process.exit(1);
|
|
1504
|
+
throw new Error("--skill and --skills are mutually exclusive. Use one or the other.");
|
|
1426
1505
|
}
|
|
1427
1506
|
const { adapter } = resolveChatProvider({
|
|
1428
1507
|
provider: options.provider,
|
|
@@ -1492,6 +1571,69 @@ var PROVIDER_ENV_KEY = {
|
|
|
1492
1571
|
openrouter: "OPENROUTER_API_KEY",
|
|
1493
1572
|
demo: null
|
|
1494
1573
|
};
|
|
1574
|
+
var PACKAGE_RANGES = {
|
|
1575
|
+
"@agentskit/adapters": "^0.15.2",
|
|
1576
|
+
"@agentskit/angular": "^0.5.3",
|
|
1577
|
+
"@agentskit/ink": "^0.10.9",
|
|
1578
|
+
"@agentskit/memory": "^0.11.8",
|
|
1579
|
+
"@agentskit/react": "^0.8.3",
|
|
1580
|
+
"@agentskit/runtime": "^0.10.15",
|
|
1581
|
+
"@agentskit/skills": "^0.9.3",
|
|
1582
|
+
"@agentskit/svelte": "^0.5.3",
|
|
1583
|
+
"@agentskit/tools": "^0.13.6",
|
|
1584
|
+
"@agentskit/vue": "^0.5.3"
|
|
1585
|
+
};
|
|
1586
|
+
function align(files) {
|
|
1587
|
+
const result = { ...files };
|
|
1588
|
+
for (const file of ["package.json", "deno.json"]) {
|
|
1589
|
+
if (!files[file]) continue;
|
|
1590
|
+
const parsed = JSON.parse(files[file]);
|
|
1591
|
+
const sections = file === "package.json" ? ["dependencies", "devDependencies", "peerDependencies"] : ["imports"];
|
|
1592
|
+
for (const sectionName of sections) {
|
|
1593
|
+
const section = parsed[sectionName];
|
|
1594
|
+
if (!section || typeof section !== "object" || Array.isArray(section)) continue;
|
|
1595
|
+
for (const [name, range] of Object.entries(PACKAGE_RANGES)) if (name in section) {
|
|
1596
|
+
section[name] = file === "deno.json" ? `npm:${name}@${range}` : range;
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
result[file] = `${JSON.stringify(parsed, null, 2)}
|
|
1600
|
+
`;
|
|
1601
|
+
}
|
|
1602
|
+
return result;
|
|
1603
|
+
}
|
|
1604
|
+
async function existing(filePath) {
|
|
1605
|
+
try {
|
|
1606
|
+
return await lstat(filePath);
|
|
1607
|
+
} catch (error) {
|
|
1608
|
+
if (error.code === "ENOENT") return void 0;
|
|
1609
|
+
throw error;
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
async function writeStarterProject(options, renderers) {
|
|
1613
|
+
const ctx = { template: options.template, provider: options.provider ?? "demo", tools: options.tools ?? [], memory: options.memory ?? "none", pm: options.packageManager ?? "pnpm" };
|
|
1614
|
+
const files = align(renderers[ctx.template](ctx));
|
|
1615
|
+
await mkdir(options.targetDir, { recursive: true });
|
|
1616
|
+
const target = await lstat(options.targetDir);
|
|
1617
|
+
if (target.isSymbolicLink() || !target.isDirectory()) throw new Error(`Refusing to write starter into non-directory target: ${options.targetDir}`);
|
|
1618
|
+
if ((await readdir(options.targetDir)).length > 0 && !options.force) throw new Error(`Target directory is not empty: ${options.targetDir} (re-run with --force to overwrite generated files)`);
|
|
1619
|
+
const overwritten = [];
|
|
1620
|
+
for (const [relativePath, content] of Object.entries(files)) {
|
|
1621
|
+
const absolutePath = path.join(options.targetDir, relativePath);
|
|
1622
|
+
await mkdir(path.dirname(absolutePath), { recursive: true });
|
|
1623
|
+
const destination = await existing(absolutePath);
|
|
1624
|
+
if (destination?.isSymbolicLink()) throw new Error(`Refusing to overwrite symlink: ${absolutePath}`);
|
|
1625
|
+
if (destination) overwritten.push(relativePath);
|
|
1626
|
+
const tempDir = await mkdtemp(path.join(path.dirname(absolutePath), `.agentskit-init-${randomUUID()}-`));
|
|
1627
|
+
try {
|
|
1628
|
+
await writeFile(path.join(tempDir, path.basename(absolutePath)), content, "utf8");
|
|
1629
|
+
await rename(path.join(tempDir, path.basename(absolutePath)), absolutePath);
|
|
1630
|
+
} finally {
|
|
1631
|
+
await rm(tempDir, { recursive: true, force: true }).catch(() => {
|
|
1632
|
+
});
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
return overwritten;
|
|
1636
|
+
}
|
|
1495
1637
|
|
|
1496
1638
|
// src/init.ts
|
|
1497
1639
|
function adapterCall(provider, prefix = "process.env") {
|
|
@@ -2877,23 +3019,8 @@ var TEMPLATE_FN = {
|
|
|
2877
3019
|
"deno-deploy": denoDeployStarter,
|
|
2878
3020
|
angular: angularStarter
|
|
2879
3021
|
};
|
|
2880
|
-
async function
|
|
2881
|
-
|
|
2882
|
-
template: options.template,
|
|
2883
|
-
provider: options.provider ?? "demo",
|
|
2884
|
-
tools: options.tools ?? [],
|
|
2885
|
-
memory: options.memory ?? "none",
|
|
2886
|
-
pm: options.packageManager ?? "pnpm"
|
|
2887
|
-
};
|
|
2888
|
-
const files = TEMPLATE_FN[ctx.template](ctx);
|
|
2889
|
-
await mkdir(options.targetDir, { recursive: true });
|
|
2890
|
-
await Promise.all(
|
|
2891
|
-
Object.entries(files).map(async ([relativePath, content]) => {
|
|
2892
|
-
const absolutePath = path.join(options.targetDir, relativePath);
|
|
2893
|
-
await mkdir(path.dirname(absolutePath), { recursive: true });
|
|
2894
|
-
await writeFile(absolutePath, content, "utf8");
|
|
2895
|
-
})
|
|
2896
|
-
);
|
|
3022
|
+
async function writeStarterProject2(options) {
|
|
3023
|
+
return writeStarterProject(options, TEMPLATE_FN);
|
|
2897
3024
|
}
|
|
2898
3025
|
|
|
2899
3026
|
// src/provider-registry.ts
|
|
@@ -3140,8 +3267,8 @@ async function checkPnpm() {
|
|
|
3140
3267
|
};
|
|
3141
3268
|
}
|
|
3142
3269
|
async function checkPackageJson() {
|
|
3143
|
-
const
|
|
3144
|
-
if (!existsSync(
|
|
3270
|
+
const path6 = join(process.cwd(), "package.json");
|
|
3271
|
+
if (!existsSync(path6)) {
|
|
3145
3272
|
return {
|
|
3146
3273
|
status: "warn",
|
|
3147
3274
|
name: "package.json",
|
|
@@ -3150,7 +3277,7 @@ async function checkPackageJson() {
|
|
|
3150
3277
|
};
|
|
3151
3278
|
}
|
|
3152
3279
|
try {
|
|
3153
|
-
const pkg = JSON.parse(await readFile(
|
|
3280
|
+
const pkg = JSON.parse(await readFile(path6, "utf8"));
|
|
3154
3281
|
const deps = {
|
|
3155
3282
|
...pkg.dependencies ?? {},
|
|
3156
3283
|
...pkg.devDependencies ?? {}
|
|
@@ -3363,6 +3490,14 @@ function renderReport(report, opts = {}) {
|
|
|
3363
3490
|
lines.push("");
|
|
3364
3491
|
return lines.join("\n");
|
|
3365
3492
|
}
|
|
3493
|
+
var require2 = createRequire(import.meta.url);
|
|
3494
|
+
function resolveTsxCli() {
|
|
3495
|
+
try {
|
|
3496
|
+
return require2.resolve("tsx/cli");
|
|
3497
|
+
} catch {
|
|
3498
|
+
throw new Error("TypeScript execution requires the packaged tsx dependency");
|
|
3499
|
+
}
|
|
3500
|
+
}
|
|
3366
3501
|
var DEFAULT_WATCH = [
|
|
3367
3502
|
"**/*.ts",
|
|
3368
3503
|
"**/*.tsx",
|
|
@@ -3390,8 +3525,8 @@ function startDev(options) {
|
|
|
3390
3525
|
const stderr = options.stderr ?? process.stderr;
|
|
3391
3526
|
const debounceMs = options.debounceMs ?? 200;
|
|
3392
3527
|
const isTs = entry.endsWith(".ts") || entry.endsWith(".tsx");
|
|
3393
|
-
const cmd = isTs ?
|
|
3394
|
-
const baseArgs = [entry, ...options.scriptArgs ?? []];
|
|
3528
|
+
const cmd = isTs ? process.execPath : "node";
|
|
3529
|
+
const baseArgs = isTs ? [resolveTsxCli(), entry, ...options.scriptArgs ?? []] : [entry, ...options.scriptArgs ?? []];
|
|
3395
3530
|
const spawnFn = options.spawn ?? ((c, a) => spawn(c, a, {
|
|
3396
3531
|
stdio: ["inherit", "pipe", "pipe"],
|
|
3397
3532
|
env: { ...process.env, FORCE_COLOR: "1" }
|
|
@@ -3403,7 +3538,9 @@ function startDev(options) {
|
|
|
3403
3538
|
let child;
|
|
3404
3539
|
let restartCount = 0;
|
|
3405
3540
|
let restartTimer;
|
|
3541
|
+
let delayedStartTimer;
|
|
3406
3542
|
let stopped = false;
|
|
3543
|
+
let stdinListener;
|
|
3407
3544
|
let resolveDone;
|
|
3408
3545
|
const done = new Promise((r) => {
|
|
3409
3546
|
resolveDone = r;
|
|
@@ -3429,15 +3566,18 @@ function startDev(options) {
|
|
|
3429
3566
|
}
|
|
3430
3567
|
});
|
|
3431
3568
|
};
|
|
3432
|
-
const restart = (
|
|
3569
|
+
const restart = (path6) => {
|
|
3433
3570
|
if (restartTimer) clearTimeout(restartTimer);
|
|
3434
3571
|
restartTimer = setTimeout(() => {
|
|
3435
3572
|
restartTimer = void 0;
|
|
3436
|
-
banner(`\u21BB change detected \u2014 ${
|
|
3573
|
+
banner(`\u21BB change detected \u2014 ${path6}`, "yellow");
|
|
3437
3574
|
if (child && !child.killed && child.exitCode === null) {
|
|
3438
3575
|
child.kill("SIGTERM");
|
|
3439
3576
|
}
|
|
3440
|
-
setTimeout(
|
|
3577
|
+
delayedStartTimer = setTimeout(() => {
|
|
3578
|
+
delayedStartTimer = void 0;
|
|
3579
|
+
if (!stopped) startChild();
|
|
3580
|
+
}, 80);
|
|
3441
3581
|
}, debounceMs);
|
|
3442
3582
|
};
|
|
3443
3583
|
watcher.on("change", restart);
|
|
@@ -3448,6 +3588,9 @@ function startDev(options) {
|
|
|
3448
3588
|
if (stopped) return;
|
|
3449
3589
|
stopped = true;
|
|
3450
3590
|
if (restartTimer) clearTimeout(restartTimer);
|
|
3591
|
+
if (delayedStartTimer) clearTimeout(delayedStartTimer);
|
|
3592
|
+
if (stdinListener) process.stdin.off("data", stdinListener);
|
|
3593
|
+
if (process.stdin.isTTY && process.stdin.setRawMode) process.stdin.setRawMode(false);
|
|
3451
3594
|
if (child && !child.killed && child.exitCode === null) {
|
|
3452
3595
|
child.kill("SIGTERM");
|
|
3453
3596
|
}
|
|
@@ -3458,11 +3601,12 @@ function startDev(options) {
|
|
|
3458
3601
|
if (process.stdin.isTTY && process.stdin.setRawMode) {
|
|
3459
3602
|
process.stdin.setRawMode(true);
|
|
3460
3603
|
process.stdin.resume();
|
|
3461
|
-
|
|
3604
|
+
stdinListener = (data) => {
|
|
3462
3605
|
const key = data.toString();
|
|
3463
3606
|
if (key === "r") restart("manual");
|
|
3464
3607
|
if (key === "q" || key === "") void stop();
|
|
3465
|
-
}
|
|
3608
|
+
};
|
|
3609
|
+
process.stdin.on("data", stdinListener);
|
|
3466
3610
|
}
|
|
3467
3611
|
return {
|
|
3468
3612
|
done,
|
|
@@ -3488,6 +3632,7 @@ async function startTunnel(options) {
|
|
|
3488
3632
|
});
|
|
3489
3633
|
let requests = 0;
|
|
3490
3634
|
let stopped = false;
|
|
3635
|
+
let signalHandler;
|
|
3491
3636
|
let resolveDone;
|
|
3492
3637
|
const done = new Promise((r) => {
|
|
3493
3638
|
resolveDone = r;
|
|
@@ -3497,12 +3642,14 @@ async function startTunnel(options) {
|
|
|
3497
3642
|
});
|
|
3498
3643
|
tunnel.on("close", () => {
|
|
3499
3644
|
if (stopped) return;
|
|
3645
|
+
if (signalHandler) process.off("SIGINT", signalHandler);
|
|
3500
3646
|
banner(`tunnel closed by remote`, "yellow");
|
|
3501
3647
|
resolveDone();
|
|
3502
3648
|
});
|
|
3503
3649
|
tunnel.on("error", (...args) => {
|
|
3504
3650
|
const err = args[0];
|
|
3505
3651
|
banner(`error: ${err?.message ?? "unknown"}`, "red");
|
|
3652
|
+
resolveDone();
|
|
3506
3653
|
});
|
|
3507
3654
|
banner(`\u2713 ready`, "green");
|
|
3508
3655
|
stdout.write("\n");
|
|
@@ -3518,14 +3665,16 @@ async function startTunnel(options) {
|
|
|
3518
3665
|
const stop = async () => {
|
|
3519
3666
|
if (stopped) return;
|
|
3520
3667
|
stopped = true;
|
|
3668
|
+
if (signalHandler) process.off("SIGINT", signalHandler);
|
|
3521
3669
|
tunnel.close();
|
|
3522
3670
|
banner(`stopped \u2014 proxied ${requests} request${requests === 1 ? "" : "s"}`, "cyan");
|
|
3523
3671
|
resolveDone();
|
|
3524
3672
|
};
|
|
3525
3673
|
if (process.stdin.isTTY) {
|
|
3526
|
-
|
|
3674
|
+
signalHandler = () => {
|
|
3527
3675
|
void stop();
|
|
3528
|
-
}
|
|
3676
|
+
};
|
|
3677
|
+
process.on("SIGINT", signalHandler);
|
|
3529
3678
|
}
|
|
3530
3679
|
return {
|
|
3531
3680
|
url: tunnel.url,
|
|
@@ -3596,16 +3745,20 @@ async function indexSources(rag, config, cwd) {
|
|
|
3596
3745
|
}
|
|
3597
3746
|
}
|
|
3598
3747
|
const documents = await Promise.all(
|
|
3599
|
-
absolutePaths.map(async (
|
|
3600
|
-
id:
|
|
3601
|
-
content: await readFile(
|
|
3602
|
-
source:
|
|
3748
|
+
absolutePaths.map(async (path6) => ({
|
|
3749
|
+
id: path6,
|
|
3750
|
+
content: await readFile(path6, "utf8"),
|
|
3751
|
+
source: path6
|
|
3603
3752
|
}))
|
|
3604
3753
|
);
|
|
3605
3754
|
if (documents.length > 0) await rag.ingest(documents);
|
|
3606
3755
|
return { documentCount: documents.length, sources: absolutePaths };
|
|
3607
3756
|
}
|
|
3608
3757
|
|
|
3758
|
+
// package.json
|
|
3759
|
+
var package_default = {
|
|
3760
|
+
version: "0.13.40"};
|
|
3761
|
+
|
|
3609
3762
|
// src/commands/shared.ts
|
|
3610
3763
|
function mergeWithConfig(options, config) {
|
|
3611
3764
|
if (!config) return options;
|
|
@@ -3631,7 +3784,7 @@ function registerChatCommand(program) {
|
|
|
3631
3784
|
"Extra directory to auto-discover plugin modules from (repeatable)",
|
|
3632
3785
|
(value, prev = []) => [...prev, value],
|
|
3633
3786
|
[]
|
|
3634
|
-
).option(
|
|
3787
|
+
).option("--discover-plugins", "Also auto-discover plugins from ~/.agentskit/plugins").option(
|
|
3635
3788
|
"--mode <mode>",
|
|
3636
3789
|
"Permission mode: default | plan | acceptEdits | bypassPermissions"
|
|
3637
3790
|
).action(async (options) => {
|
|
@@ -3668,7 +3821,8 @@ function registerChatCommand(program) {
|
|
|
3668
3821
|
}
|
|
3669
3822
|
const pluginBundle = await loadPlugins({
|
|
3670
3823
|
specs: config?.plugins ?? [],
|
|
3671
|
-
pluginDirs: options.pluginDir ?? []
|
|
3824
|
+
pluginDirs: options.pluginDir ?? [],
|
|
3825
|
+
autoDiscoverUserDir: Boolean(options.discoverPlugins)
|
|
3672
3826
|
});
|
|
3673
3827
|
const configHooks = configHooksToHandlers(config?.hooks);
|
|
3674
3828
|
const hookHandlers = [...configHooks, ...pluginBundle.hooks];
|
|
@@ -4003,7 +4157,7 @@ function printNextSteps(options) {
|
|
|
4003
4157
|
|
|
4004
4158
|
// src/commands/init.ts
|
|
4005
4159
|
function registerInitCommand(program) {
|
|
4006
|
-
program.command("init").description("Generate a starter project. Run with no flags for interactive mode.").option("--template <template>", "Starter template (react|nextjs|sveltekit|nuxt|ink|vite-ink|cloudflare-workers|bun|deno-deploy|expo|angular|runtime|multi-agent)").option("--dir <directory>", "Target directory", "agentskit-app").option("--provider <provider>", "LLM provider (openai|anthropic|gemini|ollama|deepseek|grok|kimi|groq|openrouter|demo)").option("--tools <tools>", "Comma-separated tools (web_search,filesystem,shell)").option("--memory <backend>", "Memory backend (none|file|sqlite)").option("--pm <packageManager>", "Package manager (pnpm|npm|yarn|bun)").option("-y, --yes", "Skip interactive prompts; use flag values + defaults").action(async (rawOptions) => {
|
|
4160
|
+
program.command("init").description("Generate a starter project. Run with no flags for interactive mode.").option("--template <template>", "Starter template (react|nextjs|sveltekit|nuxt|ink|vite-ink|cloudflare-workers|bun|deno-deploy|expo|angular|runtime|multi-agent)").option("--dir <directory>", "Target directory", "agentskit-app").option("--provider <provider>", "LLM provider (openai|anthropic|gemini|ollama|deepseek|grok|kimi|groq|openrouter|demo)").option("--tools <tools>", "Comma-separated tools (web_search,filesystem,shell)").option("--memory <backend>", "Memory backend (none|file|sqlite)").option("--pm <packageManager>", "Package manager (pnpm|npm|yarn|bun)").option("--force", "Overwrite generated files in a non-empty target directory").option("-y, --yes", "Skip interactive prompts; use flag values + defaults").action(async (rawOptions) => {
|
|
4007
4161
|
const isCi = !process.stdout.isTTY || rawOptions.yes || rawOptions.template;
|
|
4008
4162
|
let resolved;
|
|
4009
4163
|
if (isCi) {
|
|
@@ -4014,7 +4168,8 @@ function registerInitCommand(program) {
|
|
|
4014
4168
|
provider: rawOptions.provider ?? "demo",
|
|
4015
4169
|
tools: rawOptions.tools ? rawOptions.tools.split(",").map((t) => t.trim()) : [],
|
|
4016
4170
|
memory: rawOptions.memory ?? "none",
|
|
4017
|
-
packageManager: rawOptions.pm ?? "pnpm"
|
|
4171
|
+
packageManager: rawOptions.pm ?? "pnpm",
|
|
4172
|
+
force: Boolean(rawOptions.force)
|
|
4018
4173
|
};
|
|
4019
4174
|
} else {
|
|
4020
4175
|
const result = await runInteractiveInit({
|
|
@@ -4024,17 +4179,22 @@ function registerInitCommand(program) {
|
|
|
4024
4179
|
if (result.cancelled) {
|
|
4025
4180
|
process.exit(0);
|
|
4026
4181
|
}
|
|
4027
|
-
resolved = result.options;
|
|
4182
|
+
resolved = { ...result.options, force: Boolean(rawOptions.force) };
|
|
4028
4183
|
}
|
|
4029
|
-
await
|
|
4184
|
+
const overwritten = await writeStarterProject2(resolved) ?? [];
|
|
4030
4185
|
if (isCi) {
|
|
4031
4186
|
process.stdout.write(
|
|
4032
4187
|
`Created ${resolved.template} starter in ${path.relative(process.cwd(), resolved.targetDir) || "."}
|
|
4033
|
-
|
|
4188
|
+
` + (overwritten.length > 0 ? `Overwritten: ${overwritten.join(", ")}
|
|
4189
|
+
` : "") + `\u2605 Star AgentsKit (solo-built \u2014 it helps a lot): https://github.com/AgentsKit-io/agentskit
|
|
4034
4190
|
`
|
|
4035
4191
|
);
|
|
4036
4192
|
} else {
|
|
4037
4193
|
printNextSteps(resolved);
|
|
4194
|
+
if (overwritten.length > 0) {
|
|
4195
|
+
process.stdout.write(`Overwritten: ${overwritten.join(", ")}
|
|
4196
|
+
`);
|
|
4197
|
+
}
|
|
4038
4198
|
}
|
|
4039
4199
|
});
|
|
4040
4200
|
}
|
|
@@ -4090,7 +4250,7 @@ function registerConfigCommand(program) {
|
|
|
4090
4250
|
const targetPath = isLocal ? path.join(process.cwd(), ".agentskit.config.json") : path.join(homedir(), ".agentskit", "config.json");
|
|
4091
4251
|
if (action === "show") {
|
|
4092
4252
|
const config = await loadConfig();
|
|
4093
|
-
process.stdout.write(JSON.stringify(config ?? {}, null, 2) + "\n");
|
|
4253
|
+
process.stdout.write(JSON.stringify(redactConfig(config ?? {}), null, 2) + "\n");
|
|
4094
4254
|
return;
|
|
4095
4255
|
}
|
|
4096
4256
|
if (action !== "init") {
|
|
@@ -4284,7 +4444,7 @@ function scaffoldAgent(schema) {
|
|
|
4284
4444
|
return files;
|
|
4285
4445
|
}
|
|
4286
4446
|
async function writeScaffold(files, outDir, opts = {}) {
|
|
4287
|
-
const { writeFile: writeFile5, mkdir: mkdir5, access } = await import('fs/promises');
|
|
4447
|
+
const { writeFile: writeFile5, mkdir: mkdir5, access: access2 } = await import('fs/promises');
|
|
4288
4448
|
const { dirname: dirname5, join: join11 } = await import('path');
|
|
4289
4449
|
const written = [];
|
|
4290
4450
|
for (const f of files) {
|
|
@@ -4292,7 +4452,7 @@ async function writeScaffold(files, outDir, opts = {}) {
|
|
|
4292
4452
|
await mkdir5(dirname5(full), { recursive: true });
|
|
4293
4453
|
if (!opts.overwrite) {
|
|
4294
4454
|
try {
|
|
4295
|
-
await
|
|
4455
|
+
await access2(full);
|
|
4296
4456
|
continue;
|
|
4297
4457
|
} catch {
|
|
4298
4458
|
}
|
|
@@ -4768,66 +4928,66 @@ After writing, summarise which files landed and what each one does.
|
|
|
4768
4928
|
// src/rules.ts
|
|
4769
4929
|
var CODEX_BLOCK_START = "<!-- agentskit-codex-profile:start -->";
|
|
4770
4930
|
var CODEX_BLOCK_END = "<!-- agentskit-codex-profile:end -->";
|
|
4771
|
-
async function ensureDir2(
|
|
4772
|
-
await mkdir(dirname(
|
|
4931
|
+
async function ensureDir2(path6) {
|
|
4932
|
+
await mkdir(dirname(path6), { recursive: true });
|
|
4773
4933
|
}
|
|
4774
4934
|
async function writeIfChanged(absPath, contents, force) {
|
|
4775
|
-
let
|
|
4935
|
+
let existing2;
|
|
4776
4936
|
try {
|
|
4777
|
-
|
|
4937
|
+
existing2 = await readFile(absPath, "utf8");
|
|
4778
4938
|
} catch {
|
|
4779
4939
|
}
|
|
4780
|
-
if (
|
|
4781
|
-
if (
|
|
4940
|
+
if (existing2 === contents) return "skipped";
|
|
4941
|
+
if (existing2 !== void 0 && !force) {
|
|
4782
4942
|
return "skipped";
|
|
4783
4943
|
}
|
|
4784
4944
|
await ensureDir2(absPath);
|
|
4785
4945
|
await writeFile(absPath, contents, "utf8");
|
|
4786
|
-
return
|
|
4946
|
+
return existing2 === void 0 ? "wrote" : "updated";
|
|
4787
4947
|
}
|
|
4788
4948
|
async function writeCursor(rootDir, force) {
|
|
4789
|
-
const
|
|
4790
|
-
const action = await writeIfChanged(
|
|
4791
|
-
return [{ path:
|
|
4949
|
+
const path6 = join(rootDir, ".cursor", "rules", "agentskit.mdc");
|
|
4950
|
+
const action = await writeIfChanged(path6, CURSOR_RULE, force);
|
|
4951
|
+
return [{ path: path6, action }];
|
|
4792
4952
|
}
|
|
4793
4953
|
async function writeWindsurf(rootDir, force) {
|
|
4794
|
-
const
|
|
4795
|
-
const action = await writeIfChanged(
|
|
4796
|
-
return [{ path:
|
|
4954
|
+
const path6 = join(rootDir, ".windsurfrules");
|
|
4955
|
+
const action = await writeIfChanged(path6, WINDSURF_RULE, force);
|
|
4956
|
+
return [{ path: path6, action }];
|
|
4797
4957
|
}
|
|
4798
4958
|
async function writeCodex(rootDir, force) {
|
|
4799
|
-
const
|
|
4800
|
-
let
|
|
4959
|
+
const path6 = join(rootDir, "AGENTS.md");
|
|
4960
|
+
let existing2 = "";
|
|
4801
4961
|
try {
|
|
4802
|
-
|
|
4962
|
+
existing2 = await readFile(path6, "utf8");
|
|
4803
4963
|
} catch {
|
|
4804
4964
|
}
|
|
4805
|
-
const startIdx =
|
|
4806
|
-
const endIdx = startIdx >= 0 ?
|
|
4965
|
+
const startIdx = existing2.indexOf(CODEX_BLOCK_START);
|
|
4966
|
+
const endIdx = startIdx >= 0 ? existing2.lastIndexOf(CODEX_BLOCK_END, existing2.length) : -1;
|
|
4807
4967
|
if (startIdx >= 0 && endIdx <= startIdx) {
|
|
4808
4968
|
throw new ConfigError({
|
|
4809
4969
|
code: ErrorCodes.AK_CONFIG_INVALID,
|
|
4810
|
-
message: `${
|
|
4970
|
+
message: `${path6}: found agentskit-codex-profile:start sentinel but no matching :end after it \u2014 refusing to modify a half-edited block.`,
|
|
4811
4971
|
hint: "Restore the closing sentinel or remove the partial block, then re-run."
|
|
4812
4972
|
});
|
|
4813
4973
|
}
|
|
4814
4974
|
let next;
|
|
4815
4975
|
if (startIdx >= 0 && endIdx > startIdx) {
|
|
4816
|
-
next =
|
|
4817
|
-
} else if (
|
|
4818
|
-
next = `${
|
|
4976
|
+
next = existing2.slice(0, startIdx) + CODEX_PROFILE.trimEnd() + existing2.slice(endIdx + CODEX_BLOCK_END.length);
|
|
4977
|
+
} else if (existing2) {
|
|
4978
|
+
next = `${existing2.replace(/\s+$/, "")}
|
|
4819
4979
|
|
|
4820
4980
|
${CODEX_PROFILE}`;
|
|
4821
4981
|
} else {
|
|
4822
4982
|
next = CODEX_PROFILE;
|
|
4823
4983
|
}
|
|
4824
|
-
if (next ===
|
|
4825
|
-
if (
|
|
4826
|
-
return [{ path:
|
|
4984
|
+
if (next === existing2) return [{ path: path6, action: "skipped" }];
|
|
4985
|
+
if (existing2 && !force) {
|
|
4986
|
+
return [{ path: path6, action: "skipped" }];
|
|
4827
4987
|
}
|
|
4828
|
-
await ensureDir2(
|
|
4829
|
-
await writeFile(
|
|
4830
|
-
return [{ path:
|
|
4988
|
+
await ensureDir2(path6);
|
|
4989
|
+
await writeFile(path6, next, "utf8");
|
|
4990
|
+
return [{ path: path6, action: existing2 ? "updated" : "wrote" }];
|
|
4831
4991
|
}
|
|
4832
4992
|
async function writeClaudeCode(rootDir, force) {
|
|
4833
4993
|
const out = [];
|
|
@@ -4915,17 +5075,78 @@ rules failed: ${message}
|
|
|
4915
5075
|
}
|
|
4916
5076
|
var RAW_BASE = "https://raw.githubusercontent.com/AgentsKit-io/agentskit-registry/main";
|
|
4917
5077
|
var HOSTED_BASE = `${RAW_BASE}/public/r`;
|
|
5078
|
+
var FETCH_TIMEOUT_MS = 15e3;
|
|
5079
|
+
var MAX_RESPONSE_BYTES = 2 * 1024 * 1024;
|
|
5080
|
+
var MAX_AGENT_FILES = 100;
|
|
5081
|
+
var SAFE_ID = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
5082
|
+
function assertSafeId(id) {
|
|
5083
|
+
if (!SAFE_ID.test(id)) throw new Error(`Invalid registry agent id: ${JSON.stringify(id)}`);
|
|
5084
|
+
}
|
|
5085
|
+
function assertSafeRelativePath(filePath) {
|
|
5086
|
+
if (!filePath || isAbsolute(filePath) || filePath.includes("\0")) {
|
|
5087
|
+
throw new Error(`Invalid registry file path: ${JSON.stringify(filePath)}`);
|
|
5088
|
+
}
|
|
5089
|
+
const normalized = filePath.replace(/\\/g, "/");
|
|
5090
|
+
if (normalized.split("/").some((part) => part === ".." || part === "")) {
|
|
5091
|
+
throw new Error(`Registry file path must stay relative: ${JSON.stringify(filePath)}`);
|
|
5092
|
+
}
|
|
5093
|
+
}
|
|
5094
|
+
function assertInside(parent, child) {
|
|
5095
|
+
const rel = relative(resolve(parent), resolve(child));
|
|
5096
|
+
if (rel === ".." || rel.startsWith(`..${sep}`) || isAbsolute(rel)) {
|
|
5097
|
+
throw new Error(`Registry destination escapes target directory: ${child}`);
|
|
5098
|
+
}
|
|
5099
|
+
}
|
|
5100
|
+
async function assertNoSymlinkAncestors(targetDir, baseDir) {
|
|
5101
|
+
for (const path6 of [targetDir, baseDir]) {
|
|
5102
|
+
try {
|
|
5103
|
+
if ((await lstat(resolve(path6))).isSymbolicLink()) {
|
|
5104
|
+
throw new Error(`Registry destination contains a symlink ancestor: ${resolve(path6)}`);
|
|
5105
|
+
}
|
|
5106
|
+
} catch (error) {
|
|
5107
|
+
if (error.code !== "ENOENT") throw error;
|
|
5108
|
+
}
|
|
5109
|
+
}
|
|
5110
|
+
let current = resolve(baseDir);
|
|
5111
|
+
while (true) {
|
|
5112
|
+
try {
|
|
5113
|
+
if ((await lstat(current)).isSymbolicLink()) {
|
|
5114
|
+
throw new Error(`Registry destination contains a symlink ancestor: ${current}`);
|
|
5115
|
+
}
|
|
5116
|
+
return;
|
|
5117
|
+
} catch (error) {
|
|
5118
|
+
if (error.code !== "ENOENT") throw error;
|
|
5119
|
+
}
|
|
5120
|
+
const parent = dirname(current);
|
|
5121
|
+
if (parent === current) return;
|
|
5122
|
+
current = parent;
|
|
5123
|
+
}
|
|
5124
|
+
}
|
|
5125
|
+
async function fetchWithLimits(url, fetchImpl) {
|
|
5126
|
+
const controller = new AbortController();
|
|
5127
|
+
const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
5128
|
+
try {
|
|
5129
|
+
const response = await fetchImpl(url, { signal: controller.signal });
|
|
5130
|
+
if (!response.ok) throw new Error(`${response.status} ${response.statusText}`);
|
|
5131
|
+
const body = await response.arrayBuffer();
|
|
5132
|
+
if (body.byteLength > MAX_RESPONSE_BYTES) {
|
|
5133
|
+
throw new Error(`Registry response exceeded ${MAX_RESPONSE_BYTES} bytes`);
|
|
5134
|
+
}
|
|
5135
|
+
return new Response(body, { status: response.status, headers: response.headers });
|
|
5136
|
+
} finally {
|
|
5137
|
+
clearTimeout(timer);
|
|
5138
|
+
}
|
|
5139
|
+
}
|
|
4918
5140
|
async function getJson(url, fetchImpl) {
|
|
4919
|
-
const res = await
|
|
4920
|
-
|
|
4921
|
-
return res.json();
|
|
5141
|
+
const res = await fetchWithLimits(url, fetchImpl);
|
|
5142
|
+
return JSON.parse(await res.text());
|
|
4922
5143
|
}
|
|
4923
5144
|
async function getText(url, fetchImpl) {
|
|
4924
|
-
const res = await
|
|
4925
|
-
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
|
|
5145
|
+
const res = await fetchWithLimits(url, fetchImpl);
|
|
4926
5146
|
return res.text();
|
|
4927
5147
|
}
|
|
4928
5148
|
async function fetchAgent(id, options = {}) {
|
|
5149
|
+
assertSafeId(id);
|
|
4929
5150
|
const fetchImpl = options.fetchImpl ?? globalThis.fetch;
|
|
4930
5151
|
try {
|
|
4931
5152
|
const hosted = await getJson(`${HOSTED_BASE}/${id}.json`, fetchImpl);
|
|
@@ -4933,6 +5154,10 @@ async function fetchAgent(id, options = {}) {
|
|
|
4933
5154
|
throw new Error("hosted entry missing sources");
|
|
4934
5155
|
} catch {
|
|
4935
5156
|
const meta = await getJson(`${RAW_BASE}/registry/${id}/meta.json`, fetchImpl);
|
|
5157
|
+
if (!Array.isArray(meta.files) || meta.files.length > MAX_AGENT_FILES) {
|
|
5158
|
+
throw new Error(`Registry agent contains too many files (maximum ${MAX_AGENT_FILES})`);
|
|
5159
|
+
}
|
|
5160
|
+
for (const rel of meta.files) assertSafeRelativePath(rel);
|
|
4936
5161
|
const sources = await Promise.all(
|
|
4937
5162
|
meta.files.map(async (rel) => ({
|
|
4938
5163
|
path: rel,
|
|
@@ -4949,10 +5174,10 @@ function resolveSystemPrompt(agent) {
|
|
|
4949
5174
|
const m = src.match(/systemPrompt:\s*`((?:\\.|[^`\\])*)`/);
|
|
4950
5175
|
return m ? m[1].replace(/\\`/g, "`").replace(/\\\$\{/g, "${") : null;
|
|
4951
5176
|
}
|
|
4952
|
-
async function defaultExists(
|
|
4953
|
-
const { access } = await import('fs/promises');
|
|
5177
|
+
async function defaultExists(path6) {
|
|
5178
|
+
const { access: access2 } = await import('fs/promises');
|
|
4954
5179
|
try {
|
|
4955
|
-
await
|
|
5180
|
+
await access2(path6);
|
|
4956
5181
|
return true;
|
|
4957
5182
|
} catch {
|
|
4958
5183
|
return false;
|
|
@@ -4976,17 +5201,24 @@ async function addAgent(id, options = {}) {
|
|
|
4976
5201
|
assertInstallable(agent);
|
|
4977
5202
|
const baseDir = options.outDir ?? "agents";
|
|
4978
5203
|
const targetDir = join(baseDir, id);
|
|
5204
|
+
assertInside(baseDir, targetDir);
|
|
5205
|
+
await assertNoSymlinkAncestors(targetDir, baseDir);
|
|
4979
5206
|
const exists = options.existsImpl ?? defaultExists;
|
|
4980
|
-
const write = options.writeFileImpl ?? (async (
|
|
4981
|
-
await mkdir(dirname(
|
|
4982
|
-
await writeFile(
|
|
5207
|
+
const write = options.writeFileImpl ?? (async (path6, content) => {
|
|
5208
|
+
await mkdir(dirname(path6), { recursive: true });
|
|
5209
|
+
await writeFile(path6, content, "utf8");
|
|
4983
5210
|
});
|
|
4984
5211
|
const written = [];
|
|
4985
5212
|
for (const file of agent.sources) {
|
|
5213
|
+
assertSafeRelativePath(file.path);
|
|
4986
5214
|
const dest = join(targetDir, file.path);
|
|
5215
|
+
assertInside(targetDir, dest);
|
|
4987
5216
|
if (!options.force && await exists(dest)) {
|
|
4988
5217
|
throw new Error(`${dest} already exists (re-run with --force to overwrite)`);
|
|
4989
5218
|
}
|
|
5219
|
+
}
|
|
5220
|
+
for (const file of agent.sources) {
|
|
5221
|
+
const dest = join(targetDir, file.path);
|
|
4990
5222
|
await write(dest, file.content);
|
|
4991
5223
|
written.push(dest);
|
|
4992
5224
|
}
|
|
@@ -5049,8 +5281,8 @@ function allDeps(pkg) {
|
|
|
5049
5281
|
if (!pkg) return {};
|
|
5050
5282
|
return { ...pkg.peerDependencies, ...pkg.devDependencies, ...pkg.dependencies };
|
|
5051
5283
|
}
|
|
5052
|
-
function readJson(fs,
|
|
5053
|
-
const raw = fs.readFile(
|
|
5284
|
+
function readJson(fs, path6) {
|
|
5285
|
+
const raw = fs.readFile(path6);
|
|
5054
5286
|
if (raw == null) return null;
|
|
5055
5287
|
try {
|
|
5056
5288
|
return JSON.parse(raw);
|
|
@@ -5234,13 +5466,13 @@ function readConfig(io, root = ".") {
|
|
|
5234
5466
|
return raw == null ? null : parseConfig(raw);
|
|
5235
5467
|
}
|
|
5236
5468
|
function writeConfig(io, config, root = ".") {
|
|
5237
|
-
const
|
|
5238
|
-
io.write(
|
|
5239
|
-
return
|
|
5469
|
+
const path6 = join(root, CONFIG_PATH);
|
|
5470
|
+
io.write(path6, serializeConfig(config));
|
|
5471
|
+
return path6;
|
|
5240
5472
|
}
|
|
5241
5473
|
function resolveConfig(io, scan, root = ".") {
|
|
5242
|
-
const
|
|
5243
|
-
if (
|
|
5474
|
+
const existing2 = readConfig(io, root);
|
|
5475
|
+
if (existing2) return { config: existing2, fromDisk: true };
|
|
5244
5476
|
return { config: buildConfig(scan), fromDisk: false };
|
|
5245
5477
|
}
|
|
5246
5478
|
var IntegrityError = class extends Error {
|
|
@@ -5325,7 +5557,18 @@ function resolveAuthHeader(base, config, env = {}) {
|
|
|
5325
5557
|
const map = config?.registryAuth;
|
|
5326
5558
|
if (!map) return {};
|
|
5327
5559
|
for (const [registryBase, envVar] of Object.entries(map)) {
|
|
5328
|
-
|
|
5560
|
+
let configured;
|
|
5561
|
+
let target;
|
|
5562
|
+
try {
|
|
5563
|
+
configured = new URL(registryBase);
|
|
5564
|
+
target = new URL(base);
|
|
5565
|
+
} catch {
|
|
5566
|
+
continue;
|
|
5567
|
+
}
|
|
5568
|
+
const configuredPath = configured.pathname.replace(/\/+$/, "") || "/";
|
|
5569
|
+
const targetPath = target.pathname.replace(/\/+$/, "") || "/";
|
|
5570
|
+
const samePathBoundary = configuredPath === "/" || targetPath === configuredPath || targetPath.startsWith(`${configuredPath}/`);
|
|
5571
|
+
if (target.origin === configured.origin && samePathBoundary) {
|
|
5329
5572
|
const token = env[envVar];
|
|
5330
5573
|
if (token) return { authorization: `Bearer ${token}` };
|
|
5331
5574
|
}
|
|
@@ -5344,8 +5587,8 @@ function verifyChecksums(files) {
|
|
|
5344
5587
|
function manifestUrl(ref) {
|
|
5345
5588
|
return `${ref.base}/r/${ref.itemId}.json`;
|
|
5346
5589
|
}
|
|
5347
|
-
function fileUrl(ref,
|
|
5348
|
-
return `${ref.base}/r/${ref.itemId}/${
|
|
5590
|
+
function fileUrl(ref, path6) {
|
|
5591
|
+
return `${ref.base}/r/${ref.itemId}/${path6}`;
|
|
5349
5592
|
}
|
|
5350
5593
|
async function getText2(fetchImpl, url, headers) {
|
|
5351
5594
|
const res = await fetchImpl(url, { headers });
|
|
@@ -5682,44 +5925,44 @@ async function addComponent(options, deps) {
|
|
|
5682
5925
|
}
|
|
5683
5926
|
function nodeScanFs() {
|
|
5684
5927
|
return {
|
|
5685
|
-
readFile(
|
|
5928
|
+
readFile(path6) {
|
|
5686
5929
|
try {
|
|
5687
|
-
return readFileSync(
|
|
5930
|
+
return readFileSync(path6, "utf8");
|
|
5688
5931
|
} catch {
|
|
5689
5932
|
return null;
|
|
5690
5933
|
}
|
|
5691
5934
|
},
|
|
5692
|
-
exists(
|
|
5693
|
-
return existsSync(
|
|
5935
|
+
exists(path6) {
|
|
5936
|
+
return existsSync(path6);
|
|
5694
5937
|
}
|
|
5695
5938
|
};
|
|
5696
5939
|
}
|
|
5697
5940
|
function nodeWriteFs() {
|
|
5698
5941
|
return {
|
|
5699
|
-
exists(
|
|
5700
|
-
return existsSync(
|
|
5942
|
+
exists(path6) {
|
|
5943
|
+
return existsSync(path6);
|
|
5701
5944
|
},
|
|
5702
|
-
write(
|
|
5703
|
-
mkdirSync(dirname(
|
|
5704
|
-
writeFileSync(
|
|
5945
|
+
write(path6, content) {
|
|
5946
|
+
mkdirSync(dirname(path6), { recursive: true });
|
|
5947
|
+
writeFileSync(path6, content, "utf8");
|
|
5705
5948
|
},
|
|
5706
|
-
remove(
|
|
5707
|
-
rmSync(
|
|
5949
|
+
remove(path6) {
|
|
5950
|
+
rmSync(path6, { force: true });
|
|
5708
5951
|
}
|
|
5709
5952
|
};
|
|
5710
5953
|
}
|
|
5711
5954
|
function nodeConfigIo() {
|
|
5712
5955
|
return {
|
|
5713
|
-
read(
|
|
5956
|
+
read(path6) {
|
|
5714
5957
|
try {
|
|
5715
|
-
return readFileSync(
|
|
5958
|
+
return readFileSync(path6, "utf8");
|
|
5716
5959
|
} catch {
|
|
5717
5960
|
return null;
|
|
5718
5961
|
}
|
|
5719
5962
|
},
|
|
5720
|
-
write(
|
|
5721
|
-
mkdirSync(dirname(
|
|
5722
|
-
writeFileSync(
|
|
5963
|
+
write(path6, content) {
|
|
5964
|
+
mkdirSync(dirname(path6), { recursive: true });
|
|
5965
|
+
writeFileSync(path6, content, "utf8");
|
|
5723
5966
|
}
|
|
5724
5967
|
};
|
|
5725
5968
|
}
|
|
@@ -5939,7 +6182,7 @@ update failed: ${err instanceof Error ? err.message : String(err)}
|
|
|
5939
6182
|
// src/commands/index.ts
|
|
5940
6183
|
function createCli() {
|
|
5941
6184
|
const program = new Command();
|
|
5942
|
-
program.name("agentskit").description("AgentsKit CLI for chat demos and project bootstrapping.");
|
|
6185
|
+
program.name("agentskit").description("AgentsKit CLI for chat demos and project bootstrapping.").version(package_default.version);
|
|
5943
6186
|
registerChatCommand(program);
|
|
5944
6187
|
registerRunCommand(program);
|
|
5945
6188
|
registerInitCommand(program);
|
|
@@ -5958,6 +6201,6 @@ function createCli() {
|
|
|
5958
6201
|
return program;
|
|
5959
6202
|
}
|
|
5960
6203
|
|
|
5961
|
-
export { ChatApp, HookDispatcher, McpClient, applyPolicyToTool, applyPolicyToTools, bridgeMcpServers, buildRagFromConfig, computeCost, configHooksToHandlers, createCli, createOpenAiEmbedder, defaultPolicy, derivePreview, disposeMcpClients, evaluatePolicy, findLatestSession, findSession, forkSession, generateSessionId, getPricing, indexSources, listSessions, loadConfig, loadPlugins, mergePluginsIntoBundle, registerPricing, renameSession, renderChatHeader, renderReport, resolveChatProvider, resolveSession, runAgent, runDoctor, sessionFilePath, startDev, startTunnel, writeSessionMeta, writeStarterProject };
|
|
5962
|
-
//# sourceMappingURL=chunk-
|
|
5963
|
-
//# sourceMappingURL=chunk-
|
|
6204
|
+
export { ChatApp, HookDispatcher, McpClient, applyPolicyToTool, applyPolicyToTools, bridgeMcpServers, buildRagFromConfig, computeCost, configHooksToHandlers, createCli, createOpenAiEmbedder, defaultPolicy, derivePreview, disposeMcpClients, evaluatePolicy, findLatestSession, findSession, forkSession, generateSessionId, getPricing, indexSources, listSessions, loadConfig, loadPlugins, mergePluginsIntoBundle, registerPricing, renameSession, renderChatHeader, renderReport, resolveChatProvider, resolveSession, runAgent, runDoctor, sessionFilePath, startDev, startTunnel, writeSessionMeta, writeStarterProject2 as writeStarterProject };
|
|
6205
|
+
//# sourceMappingURL=chunk-7ALDICSL.js.map
|
|
6206
|
+
//# sourceMappingURL=chunk-7ALDICSL.js.map
|