@agent-commons/cli 0.1.6 → 0.1.10
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.js +570 -72
- package/package.json +9 -9
package/dist/bin.js
CHANGED
|
@@ -25,9 +25,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
25
25
|
|
|
26
26
|
// src/bin.ts
|
|
27
27
|
var import_commander16 = require("commander");
|
|
28
|
-
var
|
|
29
|
-
var
|
|
30
|
-
var
|
|
28
|
+
var import_path5 = require("path");
|
|
29
|
+
var import_os4 = require("os");
|
|
30
|
+
var import_child_process3 = require("child_process");
|
|
31
31
|
|
|
32
32
|
// src/commands/login.ts
|
|
33
33
|
var import_commander = require("commander");
|
|
@@ -106,7 +106,7 @@ var sym = {
|
|
|
106
106
|
bullet: import_chalk.default.dim("\u2022"),
|
|
107
107
|
dot: import_chalk.default.dim("\xB7")
|
|
108
108
|
};
|
|
109
|
-
function banner(version = "0.1.
|
|
109
|
+
function banner(version = "0.1.10") {
|
|
110
110
|
const line = import_chalk.default.cyan(" \u2500".padEnd(2) + "\u2500".repeat(44));
|
|
111
111
|
console.log("");
|
|
112
112
|
console.log(line);
|
|
@@ -145,7 +145,7 @@ async function select(prompt2, choices) {
|
|
|
145
145
|
}
|
|
146
146
|
};
|
|
147
147
|
render(true);
|
|
148
|
-
return new Promise((
|
|
148
|
+
return new Promise((resolve2) => {
|
|
149
149
|
process.stdin.setRawMode(true);
|
|
150
150
|
process.stdin.resume();
|
|
151
151
|
process.stdin.setEncoding("utf8");
|
|
@@ -160,7 +160,7 @@ async function select(prompt2, choices) {
|
|
|
160
160
|
} else if (key === "\r" || key === "\n" || key === " ") {
|
|
161
161
|
cleanup();
|
|
162
162
|
process.stdout.write("\n");
|
|
163
|
-
|
|
163
|
+
resolve2(choices[idx].value);
|
|
164
164
|
} else if (key === "") {
|
|
165
165
|
cleanup();
|
|
166
166
|
process.stdout.write("\n");
|
|
@@ -258,7 +258,7 @@ function statusBadge(status) {
|
|
|
258
258
|
// src/commands/login.ts
|
|
259
259
|
var CONFIG_FILE2 = (0, import_path2.join)((0, import_os2.homedir)(), ".agc", "config.json");
|
|
260
260
|
function prompt(question, hidden = false) {
|
|
261
|
-
return new Promise((
|
|
261
|
+
return new Promise((resolve2) => {
|
|
262
262
|
const rl = readline.createInterface({
|
|
263
263
|
input: process.stdin,
|
|
264
264
|
output: hidden ? void 0 : process.stdout,
|
|
@@ -269,85 +269,96 @@ function prompt(question, hidden = false) {
|
|
|
269
269
|
process.stdin.once("data", (data) => {
|
|
270
270
|
process.stdout.write("\n");
|
|
271
271
|
rl.close();
|
|
272
|
-
|
|
272
|
+
resolve2(data.toString().trim());
|
|
273
273
|
});
|
|
274
274
|
process.stdin.setRawMode?.(false);
|
|
275
275
|
} else {
|
|
276
276
|
rl.question(question, (ans) => {
|
|
277
277
|
rl.close();
|
|
278
|
-
|
|
278
|
+
resolve2(ans.trim());
|
|
279
279
|
});
|
|
280
280
|
}
|
|
281
281
|
});
|
|
282
282
|
}
|
|
283
283
|
function loginCommand() {
|
|
284
284
|
const cmd = new import_commander.Command("login").description("Configure API credentials");
|
|
285
|
-
cmd.option("--api-url <url>", "API base URL", DEFAULT_API_URL).option("--api-key <key>", "API key (or set AGC_API_KEY env var)").option("--initiator <id>", "
|
|
285
|
+
cmd.option("--api-url <url>", "API base URL", DEFAULT_API_URL).option("--api-key <key>", "API key (or set AGC_API_KEY env var)").option("--initiator <id>", "User/initiator ID (advanced \u2014 usually auto-detected)").action(async (opts) => {
|
|
286
286
|
try {
|
|
287
287
|
const current = loadConfig();
|
|
288
288
|
const isFirstRun = !(0, import_fs2.existsSync)(CONFIG_FILE2);
|
|
289
289
|
banner();
|
|
290
290
|
if (isFirstRun) {
|
|
291
291
|
console.log(c.bold(" Welcome to Agent Commons CLI!"));
|
|
292
|
-
console.log(c.dim("
|
|
292
|
+
console.log(c.dim(" You just need an API key to get started.\n"));
|
|
293
293
|
} else {
|
|
294
294
|
console.log(c.bold(" Update your credentials"));
|
|
295
295
|
console.log(c.dim(" Press Enter to keep existing values.\n"));
|
|
296
296
|
}
|
|
297
|
-
step(1, 3, "API Endpoint");
|
|
298
|
-
const defaultUrl = current.apiUrl ?? DEFAULT_API_URL;
|
|
299
297
|
let apiUrl;
|
|
300
298
|
if (opts.apiUrl !== DEFAULT_API_URL) {
|
|
301
299
|
apiUrl = opts.apiUrl;
|
|
302
|
-
console.log(` ${c.dim("Using:")} ${apiUrl}
|
|
300
|
+
console.log(` ${c.dim("Using API endpoint:")} ${apiUrl}
|
|
301
|
+
`);
|
|
302
|
+
} else if (current.apiUrl && current.apiUrl !== DEFAULT_API_URL) {
|
|
303
|
+
apiUrl = current.apiUrl;
|
|
304
|
+
console.log(` ${c.dim("Using existing endpoint:")} ${apiUrl}
|
|
305
|
+
`);
|
|
303
306
|
} else {
|
|
304
|
-
|
|
305
|
-
` ${c.dim("URL")} [${c.dim(defaultUrl)}]: `
|
|
306
|
-
);
|
|
307
|
-
apiUrl = answer || defaultUrl;
|
|
307
|
+
apiUrl = DEFAULT_API_URL;
|
|
308
308
|
}
|
|
309
|
-
console.log(` ${sym.ok} ${c.dim("Endpoint:")} ${c.primary(apiUrl)}`);
|
|
310
309
|
const appUrl = apiUrl.includes("localhost") ? "http://localhost:3000" : DEFAULT_APP_URL;
|
|
311
|
-
const
|
|
312
|
-
step(
|
|
310
|
+
const apiKeysUrl = `${appUrl}/settings/api-keys`;
|
|
311
|
+
step(1, 1, "API Key");
|
|
313
312
|
let apiKey = opts.apiKey;
|
|
314
313
|
if (!apiKey) {
|
|
315
|
-
console.log(` ${
|
|
316
|
-
console.log(` ${c.dim(
|
|
314
|
+
console.log(` ${c.dim("You'll need an API key from your Agent Commons account.")}`);
|
|
315
|
+
console.log(` ${c.dim("We'll open the API Keys page in your browser.")}
|
|
316
|
+
`);
|
|
317
|
+
console.log(` ${c.dim("On that page:")}`);
|
|
318
|
+
console.log(` ${sym.bullet} ${c.dim("Click")} ${c.bold('"Generate new key"')}`);
|
|
319
|
+
console.log(` ${sym.bullet} ${c.dim("Copy the key (it starts with")} ${c.bold("sk-ac-\u2026")}${c.dim(")")}`);
|
|
320
|
+
console.log(` ${sym.bullet} ${c.dim("Paste it here when prompted")}
|
|
321
|
+
`);
|
|
322
|
+
const openNow = await prompt(` ${c.dim("Open browser now? [Y/n]:")} `);
|
|
323
|
+
if (!openNow || openNow.toLowerCase() !== "n") {
|
|
324
|
+
openBrowser(apiKeysUrl);
|
|
325
|
+
console.log(` ${sym.ok} ${c.dim("Opened:")} ${c.primary(apiKeysUrl)}
|
|
317
326
|
`);
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
327
|
+
} else {
|
|
328
|
+
console.log(` ${c.dim("You can open it manually:")} ${c.primary(apiKeysUrl)}
|
|
329
|
+
`);
|
|
330
|
+
}
|
|
331
|
+
console.log(c.dim(" Paste your API key below (input is hidden):"));
|
|
332
|
+
apiKey = await prompt(` ${c.dim("API Key:")} `, true);
|
|
322
333
|
if (!apiKey) apiKey = current.apiKey;
|
|
323
334
|
}
|
|
324
335
|
if (!apiKey) {
|
|
325
336
|
console.log(`
|
|
326
|
-
${c.warn("\u26A0")} No API key provided \u2014
|
|
337
|
+
${c.warn("\u26A0")} No API key provided \u2014 set one later with ${c.bold("agc config set apiKey <key>")}`);
|
|
327
338
|
} else {
|
|
328
339
|
console.log(` ${sym.ok} ${c.dim("Key saved:")} ****${apiKey.slice(-4)}`);
|
|
329
340
|
}
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
341
|
+
let initiator = opts.initiator ?? current.initiator;
|
|
342
|
+
if (!initiator && apiKey) {
|
|
343
|
+
try {
|
|
344
|
+
const { CommonsClient: CommonsClient2 } = await import("@agent-commons/sdk");
|
|
345
|
+
const client = new CommonsClient2({ baseUrl: apiUrl, apiKey });
|
|
346
|
+
const me = await client.auth.me();
|
|
347
|
+
if (me?.principalId && me.principalType === "user") {
|
|
348
|
+
initiator = me.principalId;
|
|
349
|
+
console.log(` ${sym.ok} ${c.dim("Identity detected:")} ${c.id(initiator.slice(0, 10) + "\u2026" + initiator.slice(-6))}`);
|
|
350
|
+
}
|
|
351
|
+
} catch {
|
|
352
|
+
}
|
|
342
353
|
}
|
|
343
|
-
saveConfig({ apiUrl, apiKey, initiator });
|
|
354
|
+
saveConfig({ apiUrl, apiKey, ...initiator ? { initiator } : {} });
|
|
344
355
|
console.log(`
|
|
345
356
|
${sym.ok} ${c.success("All set!")} Credentials saved to ${c.dim("~/.agc/config.json")}`);
|
|
346
357
|
console.log(`
|
|
347
358
|
${c.dim("Next steps:")}`);
|
|
348
|
-
console.log(` ${sym.arrow} ${c.dim("Run")} ${c.bold("agc")} ${c.dim("
|
|
349
|
-
console.log(` ${sym.arrow} ${c.dim("Run")} ${c.bold("agc
|
|
350
|
-
console.log(` ${sym.arrow} ${c.dim("Run")} ${c.bold("agc chat
|
|
359
|
+
console.log(` ${sym.arrow} ${c.dim("Run")} ${c.bold("agc")} ${c.dim("to open the interactive menu")}`);
|
|
360
|
+
console.log(` ${sym.arrow} ${c.dim("Run")} ${c.bold("agc agents list")} ${c.dim("to see your agents")}`);
|
|
361
|
+
console.log(` ${sym.arrow} ${c.dim("Run")} ${c.bold("agc chat")} ${c.dim("to start chatting with an agent")}
|
|
351
362
|
`);
|
|
352
363
|
} catch (err) {
|
|
353
364
|
printError(err);
|
|
@@ -426,10 +437,6 @@ function agentsCommand() {
|
|
|
426
437
|
const cmd = new import_commander2.Command("agents").description("Manage agents");
|
|
427
438
|
cmd.command("list").description("List agents owned by the current initiator").option("--json", "Output as JSON").action(async (opts) => {
|
|
428
439
|
const cfg = loadConfig();
|
|
429
|
-
if (!cfg.initiator) {
|
|
430
|
-
console.error(c.error("No initiator set. Run `agc login` first."));
|
|
431
|
-
process.exit(1);
|
|
432
|
-
}
|
|
433
440
|
const spinner = spin("Fetching agents\u2026");
|
|
434
441
|
try {
|
|
435
442
|
const client = makeClient();
|
|
@@ -1240,16 +1247,301 @@ ${sym.fail} ${c.error(event.message ?? "Error")}`);
|
|
|
1240
1247
|
|
|
1241
1248
|
// src/commands/chat.ts
|
|
1242
1249
|
var import_commander8 = require("commander");
|
|
1250
|
+
var readline3 = __toESM(require("readline"));
|
|
1251
|
+
var import_fs4 = require("fs");
|
|
1252
|
+
var import_path4 = require("path");
|
|
1253
|
+
var import_os3 = require("os");
|
|
1254
|
+
|
|
1255
|
+
// src/local-tools.ts
|
|
1256
|
+
var import_fs3 = require("fs");
|
|
1257
|
+
var import_path3 = require("path");
|
|
1258
|
+
var import_child_process2 = require("child_process");
|
|
1243
1259
|
var readline2 = __toESM(require("readline"));
|
|
1260
|
+
function buildLocalToolsManifest(rootDir) {
|
|
1261
|
+
return `## Local File System Access
|
|
1262
|
+
|
|
1263
|
+
You have direct access to the user's local machine file system. Use these tools freely to complete tasks \u2014 do not ask the user to run commands themselves.
|
|
1264
|
+
|
|
1265
|
+
**Session root:** ${rootDir}
|
|
1266
|
+
All paths are relative to the session root unless absolute.
|
|
1267
|
+
|
|
1268
|
+
---
|
|
1269
|
+
|
|
1270
|
+
### How to call a tool
|
|
1271
|
+
|
|
1272
|
+
When you need to use a local tool, output ONLY the following JSON block \u2014 nothing else in that message. After receiving the result, continue your response:
|
|
1273
|
+
|
|
1274
|
+
\`\`\`tool
|
|
1275
|
+
{"tool": "<tool_name>", "args": {"<arg>": "<value>"}}
|
|
1276
|
+
\`\`\`
|
|
1277
|
+
|
|
1278
|
+
You may call tools multiple times in sequence. Each call will be executed and the result returned to you before you continue.
|
|
1279
|
+
|
|
1280
|
+
---
|
|
1281
|
+
|
|
1282
|
+
### Available tools
|
|
1283
|
+
|
|
1284
|
+
**read_file** \u2014 Read the full contents of a file.
|
|
1285
|
+
\`\`\`tool
|
|
1286
|
+
{"tool": "read_file", "args": {"path": "src/index.ts"}}
|
|
1287
|
+
\`\`\`
|
|
1288
|
+
|
|
1289
|
+
**write_file** \u2014 Write content to a file (creates directories as needed). User must confirm.
|
|
1290
|
+
\`\`\`tool
|
|
1291
|
+
{"tool": "write_file", "args": {"path": "output.txt", "content": "Hello world"}}
|
|
1292
|
+
\`\`\`
|
|
1293
|
+
|
|
1294
|
+
**list_directory** \u2014 List files and directories at a path. Defaults to session root.
|
|
1295
|
+
\`\`\`tool
|
|
1296
|
+
{"tool": "list_directory", "args": {"path": "src"}}
|
|
1297
|
+
\`\`\`
|
|
1298
|
+
|
|
1299
|
+
**search_files** \u2014 Find files matching a name/path pattern (glob-style, up to 50 results).
|
|
1300
|
+
\`\`\`tool
|
|
1301
|
+
{"tool": "search_files", "args": {"pattern": "*.ts", "directory": "src"}}
|
|
1302
|
+
\`\`\`
|
|
1303
|
+
|
|
1304
|
+
**run_command** \u2014 Execute a shell command and return stdout/stderr. User must confirm. 30s timeout.
|
|
1305
|
+
\`\`\`tool
|
|
1306
|
+
{"tool": "run_command", "args": {"command": "node", "args": ["--version"]}}
|
|
1307
|
+
\`\`\`
|
|
1308
|
+
|
|
1309
|
+
---
|
|
1310
|
+
|
|
1311
|
+
**Important:**
|
|
1312
|
+
- Never fabricate tool results. Always wait for the actual output.
|
|
1313
|
+
- Sensitive paths (.ssh, .env, .aws, credentials) are blocked by the system.
|
|
1314
|
+
- Write and run_command operations require explicit user approval before executing.
|
|
1315
|
+
`;
|
|
1316
|
+
}
|
|
1317
|
+
var TOOL_CALL_RE = /```tool\s*\n([\s\S]*?)\n```/;
|
|
1318
|
+
function extractToolCall(text) {
|
|
1319
|
+
const match = text.match(TOOL_CALL_RE);
|
|
1320
|
+
if (!match) return null;
|
|
1321
|
+
try {
|
|
1322
|
+
const parsed = JSON.parse(match[1].trim());
|
|
1323
|
+
if (typeof parsed.tool === "string") return parsed;
|
|
1324
|
+
} catch {
|
|
1325
|
+
}
|
|
1326
|
+
return null;
|
|
1327
|
+
}
|
|
1328
|
+
function safePath(root, userPath) {
|
|
1329
|
+
const abs = (0, import_path3.resolve)(root, userPath);
|
|
1330
|
+
const rel = (0, import_path3.relative)(root, abs);
|
|
1331
|
+
if (rel.startsWith("..") || rel.startsWith("/")) {
|
|
1332
|
+
throw new Error(`Path "${userPath}" escapes the session root. Access denied.`);
|
|
1333
|
+
}
|
|
1334
|
+
return abs;
|
|
1335
|
+
}
|
|
1336
|
+
var BLOCKED_PATTERNS = [
|
|
1337
|
+
/\/\.ssh\//,
|
|
1338
|
+
/\/\.gnupg\//,
|
|
1339
|
+
/\/\.agc\//,
|
|
1340
|
+
/\/\.aws\//,
|
|
1341
|
+
/\/\.env$/,
|
|
1342
|
+
/\/\.env\./,
|
|
1343
|
+
/id_rsa/,
|
|
1344
|
+
/id_ed25519/
|
|
1345
|
+
];
|
|
1346
|
+
function assertNotSensitive(abs) {
|
|
1347
|
+
for (const pat of BLOCKED_PATTERNS) {
|
|
1348
|
+
if (pat.test(abs)) {
|
|
1349
|
+
throw new Error(`Access to "${abs}" is blocked for security reasons.`);
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
async function confirm(message, config, permissionKey) {
|
|
1354
|
+
const cached = config.permissions.get(permissionKey);
|
|
1355
|
+
if (cached === "allow") return true;
|
|
1356
|
+
if (cached === "deny") return false;
|
|
1357
|
+
return new Promise((resolve2) => {
|
|
1358
|
+
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
1359
|
+
process.stdout.write(
|
|
1360
|
+
`
|
|
1361
|
+
\x1B[33m\u26A0\x1B[0m ${message}
|
|
1362
|
+
\x1B[2m[y] Yes [n] No [A] Always allow this type [N] Never allow this type\x1B[0m
|
|
1363
|
+
\x1B[36m?\x1B[0m `
|
|
1364
|
+
);
|
|
1365
|
+
rl.once("line", (answer) => {
|
|
1366
|
+
rl.close();
|
|
1367
|
+
const a = answer.trim().toLowerCase();
|
|
1368
|
+
if (a === "a") {
|
|
1369
|
+
config.permissions.set(permissionKey, "allow");
|
|
1370
|
+
resolve2(true);
|
|
1371
|
+
} else if (a === "n" || a === "nn") {
|
|
1372
|
+
config.permissions.set(permissionKey, "deny");
|
|
1373
|
+
resolve2(false);
|
|
1374
|
+
} else {
|
|
1375
|
+
resolve2(a === "y" || a === "yes" || a === "");
|
|
1376
|
+
}
|
|
1377
|
+
});
|
|
1378
|
+
});
|
|
1379
|
+
}
|
|
1380
|
+
async function toolReadFile(args, cfg) {
|
|
1381
|
+
const { path: userPath } = args;
|
|
1382
|
+
if (!userPath) throw new Error('read_file requires a "path" argument');
|
|
1383
|
+
const abs = safePath(cfg.rootDir, userPath);
|
|
1384
|
+
assertNotSensitive(abs);
|
|
1385
|
+
if (!(0, import_fs3.existsSync)(abs)) throw new Error(`File not found: ${userPath}`);
|
|
1386
|
+
const stat = (0, import_fs3.statSync)(abs);
|
|
1387
|
+
if (stat.isDirectory()) throw new Error(`"${userPath}" is a directory, not a file`);
|
|
1388
|
+
if (stat.size > 5e5) throw new Error(`File too large to read (${Math.round(stat.size / 1024)} KB). Max 500 KB.`);
|
|
1389
|
+
return (0, import_fs3.readFileSync)(abs, "utf8");
|
|
1390
|
+
}
|
|
1391
|
+
async function toolWriteFile(args, cfg) {
|
|
1392
|
+
const { path: userPath, content } = args;
|
|
1393
|
+
if (!userPath) throw new Error('write_file requires a "path" argument');
|
|
1394
|
+
if (content === void 0) throw new Error('write_file requires a "content" argument');
|
|
1395
|
+
const abs = safePath(cfg.rootDir, userPath);
|
|
1396
|
+
assertNotSensitive(abs);
|
|
1397
|
+
const ok = await confirm(
|
|
1398
|
+
`Agent wants to write file: \x1B[1m${abs}\x1B[0m (${String(content).length} chars)`,
|
|
1399
|
+
cfg,
|
|
1400
|
+
"write_file"
|
|
1401
|
+
);
|
|
1402
|
+
if (!ok) return "User denied write operation.";
|
|
1403
|
+
(0, import_fs3.mkdirSync)((0, import_path3.dirname)(abs), { recursive: true });
|
|
1404
|
+
(0, import_fs3.writeFileSync)(abs, content, "utf8");
|
|
1405
|
+
return `Written ${String(content).length} bytes to ${userPath}`;
|
|
1406
|
+
}
|
|
1407
|
+
async function toolListDirectory(args, cfg) {
|
|
1408
|
+
const userPath = args.path ?? ".";
|
|
1409
|
+
const abs = safePath(cfg.rootDir, userPath);
|
|
1410
|
+
assertNotSensitive(abs);
|
|
1411
|
+
if (!(0, import_fs3.existsSync)(abs)) throw new Error(`Directory not found: ${userPath}`);
|
|
1412
|
+
const entries = (0, import_fs3.readdirSync)(abs, { withFileTypes: true });
|
|
1413
|
+
const lines = entries.map((e) => {
|
|
1414
|
+
const type = e.isDirectory() ? "d" : e.isSymbolicLink() ? "l" : "f";
|
|
1415
|
+
return `[${type}] ${e.name}`;
|
|
1416
|
+
});
|
|
1417
|
+
return lines.join("\n") || "(empty directory)";
|
|
1418
|
+
}
|
|
1419
|
+
async function toolSearchFiles(args, cfg) {
|
|
1420
|
+
const { pattern, directory } = args;
|
|
1421
|
+
if (!pattern) throw new Error('search_files requires a "pattern" argument');
|
|
1422
|
+
const baseDir = safePath(cfg.rootDir, directory ?? ".");
|
|
1423
|
+
assertNotSensitive(baseDir);
|
|
1424
|
+
const results = [];
|
|
1425
|
+
const pat = new RegExp(
|
|
1426
|
+
pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, "."),
|
|
1427
|
+
"i"
|
|
1428
|
+
);
|
|
1429
|
+
function walk(dir, depth = 0) {
|
|
1430
|
+
if (results.length >= 50 || depth > 10) return;
|
|
1431
|
+
try {
|
|
1432
|
+
for (const entry of (0, import_fs3.readdirSync)(dir, { withFileTypes: true })) {
|
|
1433
|
+
if (entry.name.startsWith(".") && depth > 0) continue;
|
|
1434
|
+
const full = (0, import_path3.join)(dir, entry.name);
|
|
1435
|
+
const rel = (0, import_path3.relative)(cfg.rootDir, full);
|
|
1436
|
+
if (pat.test(entry.name) || pat.test(rel)) results.push(rel);
|
|
1437
|
+
if (entry.isDirectory()) walk(full, depth + 1);
|
|
1438
|
+
}
|
|
1439
|
+
} catch {
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
walk(baseDir);
|
|
1443
|
+
return results.length ? results.join("\n") : "No files found matching: " + pattern;
|
|
1444
|
+
}
|
|
1445
|
+
async function toolRunCommand(args, cfg) {
|
|
1446
|
+
const { command, args: cmdArgs = [], cwd } = args;
|
|
1447
|
+
if (!command || typeof command !== "string") throw new Error('run_command requires a "command" string');
|
|
1448
|
+
if (!Array.isArray(cmdArgs)) throw new Error('"args" must be an array of strings');
|
|
1449
|
+
const workDir = cwd ? safePath(cfg.rootDir, cwd) : cfg.rootDir;
|
|
1450
|
+
const preview = [command, ...cmdArgs].join(" ");
|
|
1451
|
+
const ok = await confirm(
|
|
1452
|
+
`Agent wants to run: \x1B[1m${preview}\x1B[0m
|
|
1453
|
+
\x1B[2min: ${workDir}\x1B[0m`,
|
|
1454
|
+
cfg,
|
|
1455
|
+
"run_command"
|
|
1456
|
+
);
|
|
1457
|
+
if (!ok) return "User denied command execution.";
|
|
1458
|
+
return new Promise((resolve2) => {
|
|
1459
|
+
(0, import_child_process2.execFile)(command, cmdArgs.map(String), { cwd: workDir, timeout: 3e4, maxBuffer: 1024 * 1024 }, (err, stdout, stderr) => {
|
|
1460
|
+
const out = [stdout, stderr].filter(Boolean).join("\n--- stderr ---\n");
|
|
1461
|
+
if (err && !out) return resolve2(`Error: ${err.message}`);
|
|
1462
|
+
resolve2(out || "(no output)");
|
|
1463
|
+
});
|
|
1464
|
+
});
|
|
1465
|
+
}
|
|
1466
|
+
async function runLocalTool(call, cfg) {
|
|
1467
|
+
const { tool, args } = call;
|
|
1468
|
+
cfg.appendLog({
|
|
1469
|
+
type: "local_tool_call",
|
|
1470
|
+
tool,
|
|
1471
|
+
args,
|
|
1472
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1473
|
+
});
|
|
1474
|
+
let result;
|
|
1475
|
+
try {
|
|
1476
|
+
switch (tool) {
|
|
1477
|
+
case "read_file":
|
|
1478
|
+
result = await toolReadFile(args, cfg);
|
|
1479
|
+
break;
|
|
1480
|
+
case "write_file":
|
|
1481
|
+
result = await toolWriteFile(args, cfg);
|
|
1482
|
+
break;
|
|
1483
|
+
case "list_directory":
|
|
1484
|
+
result = await toolListDirectory(args, cfg);
|
|
1485
|
+
break;
|
|
1486
|
+
case "search_files":
|
|
1487
|
+
result = await toolSearchFiles(args, cfg);
|
|
1488
|
+
break;
|
|
1489
|
+
case "run_command":
|
|
1490
|
+
result = await toolRunCommand(args, cfg);
|
|
1491
|
+
break;
|
|
1492
|
+
default:
|
|
1493
|
+
result = `Unknown tool: "${tool}". Available: read_file, write_file, list_directory, search_files, run_command`;
|
|
1494
|
+
}
|
|
1495
|
+
} catch (err) {
|
|
1496
|
+
result = `Error: ${err?.message ?? String(err)}`;
|
|
1497
|
+
}
|
|
1498
|
+
cfg.appendLog({
|
|
1499
|
+
type: "local_tool_result",
|
|
1500
|
+
tool,
|
|
1501
|
+
result: result.slice(0, 2e3),
|
|
1502
|
+
// cap log size
|
|
1503
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1504
|
+
});
|
|
1505
|
+
return result;
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
// src/commands/chat.ts
|
|
1509
|
+
var SESSIONS_DIR = (0, import_path4.join)((0, import_os3.homedir)(), ".agc", "sessions");
|
|
1510
|
+
function ensureSessionsDir() {
|
|
1511
|
+
if (!(0, import_fs4.existsSync)(SESSIONS_DIR)) (0, import_fs4.mkdirSync)(SESSIONS_DIR, { recursive: true });
|
|
1512
|
+
}
|
|
1513
|
+
function appendSessionLog(sessionId, record) {
|
|
1514
|
+
try {
|
|
1515
|
+
ensureSessionsDir();
|
|
1516
|
+
const file = (0, import_path4.join)(SESSIONS_DIR, `${sessionId}.jsonl`);
|
|
1517
|
+
(0, import_fs4.appendFileSync)(file, JSON.stringify(record) + "\n", { mode: 384 });
|
|
1518
|
+
} catch {
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1244
1521
|
var HELP_TEXT = `
|
|
1245
1522
|
${c.label("Slash commands")}
|
|
1246
1523
|
/help Show this help
|
|
1247
1524
|
/session Print the current session ID (copy it to resume later)
|
|
1525
|
+
/tools Show local tool status and permissions (--local mode)
|
|
1248
1526
|
/clear Clear the terminal screen
|
|
1249
1527
|
/quit Exit (session is preserved \u2014 resume with --resume <id>)
|
|
1250
1528
|
`;
|
|
1529
|
+
var LOCAL_TOOLS_DISCLAIMER = `
|
|
1530
|
+
${c.warn("\u26A0")} ${c.bold("Local file system access enabled")}
|
|
1531
|
+
|
|
1532
|
+
${c.dim("The agent can read and write files, list directories, search files,")}
|
|
1533
|
+
${c.dim("and execute shell commands on your machine.")}
|
|
1534
|
+
|
|
1535
|
+
${c.dim("Rules:")}
|
|
1536
|
+
${sym.bullet} ${c.dim("All paths are restricted to:")} ${c.primary(process.cwd())}
|
|
1537
|
+
${sym.bullet} ${c.dim("Sensitive paths (.ssh, .env, .aws, credentials) are always blocked")}
|
|
1538
|
+
${sym.bullet} ${c.dim("Write and run_command operations require your confirmation")}
|
|
1539
|
+
${sym.bullet} ${c.dim("You can deny any individual request")}
|
|
1540
|
+
|
|
1541
|
+
${c.dim("Session activity is logged to")} ${c.primary("~/.agc/sessions/")}
|
|
1542
|
+
`;
|
|
1251
1543
|
function chatCommand() {
|
|
1252
|
-
return new import_commander8.Command("chat").description("Start an interactive chat REPL with an agent").option("--agent <agentId>", "Agent ID (or set defaultAgentId in config)").option("--resume <sessionId>", "Resume an existing session by ID").option("--no-stream", "Disable token streaming (wait for full response)").action(async (opts) => {
|
|
1544
|
+
return new import_commander8.Command("chat").description("Start an interactive chat REPL with an agent").option("--agent <agentId>", "Agent ID (or set defaultAgentId in config)").option("--resume <sessionId>", "Resume an existing session by ID").option("--no-stream", "Disable token streaming (wait for full response)").option("--local", "Enable local file system access for the agent (see disclaimer)").action(async (opts) => {
|
|
1253
1545
|
const cfg = loadConfig();
|
|
1254
1546
|
const agentId = opts.agent ?? cfg.defaultAgentId;
|
|
1255
1547
|
if (!agentId) {
|
|
@@ -1263,17 +1555,27 @@ function chatCommand() {
|
|
|
1263
1555
|
const client = makeClient();
|
|
1264
1556
|
let sessionId = opts.resume ?? "";
|
|
1265
1557
|
const isResume = !!opts.resume;
|
|
1558
|
+
const initiator = cfg.initiator ?? "";
|
|
1266
1559
|
if (!isResume) {
|
|
1267
1560
|
const spinner = spin("Creating session\u2026");
|
|
1268
1561
|
try {
|
|
1269
1562
|
const res = await client.sessions.create({
|
|
1270
1563
|
agentId,
|
|
1271
|
-
initiator
|
|
1272
|
-
title: `agc chat ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 16)}
|
|
1564
|
+
initiator,
|
|
1565
|
+
title: `agc chat ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 16)}`,
|
|
1566
|
+
source: "cli"
|
|
1273
1567
|
});
|
|
1274
1568
|
const session = res?.data ?? res;
|
|
1275
1569
|
sessionId = session.sessionId;
|
|
1276
1570
|
spinner.stop();
|
|
1571
|
+
appendSessionLog(sessionId, {
|
|
1572
|
+
type: "session_start",
|
|
1573
|
+
sessionId,
|
|
1574
|
+
agentId,
|
|
1575
|
+
initiator,
|
|
1576
|
+
source: "cli",
|
|
1577
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1578
|
+
});
|
|
1277
1579
|
} catch (err) {
|
|
1278
1580
|
spinner.stop();
|
|
1279
1581
|
printError(err);
|
|
@@ -1316,9 +1618,26 @@ ${c.bold("Agent Commons Chat")}`);
|
|
|
1316
1618
|
["Session", c.id(sessionId) + (isResume ? c.dim(" (resumed)") : c.dim(" (new)"))]
|
|
1317
1619
|
];
|
|
1318
1620
|
if (walletLine) headerRows.push(["Wallet", walletLine]);
|
|
1621
|
+
if (opts.local) headerRows.push(["Local tools", c.success("enabled") + c.dim(" (read, write, search, run)")]);
|
|
1319
1622
|
detail(headerRows);
|
|
1623
|
+
let localToolsCfg = null;
|
|
1624
|
+
if (opts.local) {
|
|
1625
|
+
console.log(LOCAL_TOOLS_DISCLAIMER);
|
|
1626
|
+
const rootDir = process.cwd();
|
|
1627
|
+
localToolsCfg = {
|
|
1628
|
+
rootDir,
|
|
1629
|
+
sessionId,
|
|
1630
|
+
appendLog: (record) => appendSessionLog(sessionId, record),
|
|
1631
|
+
permissions: /* @__PURE__ */ new Map()
|
|
1632
|
+
};
|
|
1633
|
+
appendSessionLog(sessionId, {
|
|
1634
|
+
type: "local_tools_enabled",
|
|
1635
|
+
rootDir,
|
|
1636
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1637
|
+
});
|
|
1638
|
+
}
|
|
1320
1639
|
console.log(c.dim("\nType your message and press Enter. Type /help for commands.\n"));
|
|
1321
|
-
const rl =
|
|
1640
|
+
const rl = readline3.createInterface({
|
|
1322
1641
|
input: process.stdin,
|
|
1323
1642
|
output: process.stdout,
|
|
1324
1643
|
terminal: true,
|
|
@@ -1342,6 +1661,26 @@ Session saved. Resume with: agc chat --resume ${sessionId}`));
|
|
|
1342
1661
|
rl.prompt();
|
|
1343
1662
|
return;
|
|
1344
1663
|
}
|
|
1664
|
+
if (input === "/tools") {
|
|
1665
|
+
if (!localToolsCfg) {
|
|
1666
|
+
console.log(c.dim(` Local tools are disabled. Restart with ${c.bold("agc chat --local")} to enable them.`));
|
|
1667
|
+
} else {
|
|
1668
|
+
console.log(`
|
|
1669
|
+
${c.bold("Local tools")} ${c.success("enabled")}`);
|
|
1670
|
+
console.log(` ${c.dim("Root directory:")} ${c.primary(localToolsCfg.rootDir)}`);
|
|
1671
|
+
const perms = [...localToolsCfg.permissions.entries()];
|
|
1672
|
+
if (perms.length) {
|
|
1673
|
+
console.log(` ${c.dim("Cached permissions:")}`);
|
|
1674
|
+
for (const [k, v] of perms) {
|
|
1675
|
+
const badge = v === "allow" ? c.success("allow") : c.error("deny");
|
|
1676
|
+
console.log(` ${sym.bullet} ${k}: ${badge}`);
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
console.log();
|
|
1681
|
+
rl.prompt();
|
|
1682
|
+
return;
|
|
1683
|
+
}
|
|
1345
1684
|
if (input === "/session") {
|
|
1346
1685
|
console.log(c.dim(` ${sessionId}`));
|
|
1347
1686
|
console.log(c.dim(` Resume with: agc chat --resume ${sessionId}`));
|
|
@@ -1359,10 +1698,20 @@ Session saved. Resume with: agc chat --resume ${sessionId}`));
|
|
|
1359
1698
|
return;
|
|
1360
1699
|
}
|
|
1361
1700
|
rl.pause();
|
|
1701
|
+
appendSessionLog(sessionId, {
|
|
1702
|
+
type: "message",
|
|
1703
|
+
role: "user",
|
|
1704
|
+
content: input,
|
|
1705
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1706
|
+
});
|
|
1707
|
+
const outgoingMessages = localToolsCfg ? [
|
|
1708
|
+
{ role: "system", content: buildLocalToolsManifest(localToolsCfg.rootDir) },
|
|
1709
|
+
{ role: "user", content: input }
|
|
1710
|
+
] : [{ role: "user", content: input }];
|
|
1362
1711
|
const params = {
|
|
1363
1712
|
agentId,
|
|
1364
1713
|
sessionId,
|
|
1365
|
-
messages:
|
|
1714
|
+
messages: outgoingMessages
|
|
1366
1715
|
};
|
|
1367
1716
|
process.stdout.write(c.primary("agent") + c.dim(" \u203A "));
|
|
1368
1717
|
if (opts.noStream) {
|
|
@@ -1372,6 +1721,12 @@ Session saved. Resume with: agc chat --resume ${sessionId}`));
|
|
|
1372
1721
|
spinner.stop();
|
|
1373
1722
|
const text = extractText(result);
|
|
1374
1723
|
console.log(text);
|
|
1724
|
+
appendSessionLog(sessionId, {
|
|
1725
|
+
type: "message",
|
|
1726
|
+
role: "assistant",
|
|
1727
|
+
content: text,
|
|
1728
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1729
|
+
});
|
|
1375
1730
|
} catch (err) {
|
|
1376
1731
|
spinner.stop();
|
|
1377
1732
|
console.error(`
|
|
@@ -1380,9 +1735,12 @@ ${sym.fail} ${c.error(err.message ?? String(err))}`);
|
|
|
1380
1735
|
} else {
|
|
1381
1736
|
try {
|
|
1382
1737
|
let hasOutput = false;
|
|
1738
|
+
let agentContent = "";
|
|
1383
1739
|
for await (const event of client.agents.stream(params)) {
|
|
1384
1740
|
if (event.type === "token") {
|
|
1385
|
-
|
|
1741
|
+
const tok = event.content ?? "";
|
|
1742
|
+
process.stdout.write(tok);
|
|
1743
|
+
agentContent += tok;
|
|
1386
1744
|
hasOutput = true;
|
|
1387
1745
|
} else if (event.type === "toolStart") {
|
|
1388
1746
|
const name = event.toolName ?? "";
|
|
@@ -1396,13 +1754,34 @@ ${sym.fail} ${c.error(err.message ?? String(err))}`);
|
|
|
1396
1754
|
} else if (event.type === "final") {
|
|
1397
1755
|
const e = event;
|
|
1398
1756
|
const text = extractText(e?.payload);
|
|
1399
|
-
if (text && !hasOutput)
|
|
1757
|
+
if (text && !hasOutput) {
|
|
1758
|
+
process.stdout.write(text);
|
|
1759
|
+
agentContent += text;
|
|
1760
|
+
}
|
|
1400
1761
|
const usage = e?.payload?.usage;
|
|
1401
1762
|
if (usage) {
|
|
1402
|
-
const
|
|
1763
|
+
const inputTok = usage.inputTokens ?? 0;
|
|
1764
|
+
const outputTok = usage.outputTokens ?? 0;
|
|
1765
|
+
const cachedTok = usage.cachedTokens ?? 0;
|
|
1766
|
+
const total = usage.totalTokens ?? inputTok + outputTok;
|
|
1403
1767
|
const cost = typeof usage.costUsd === "number" ? `$${usage.costUsd.toFixed(4)}` : "";
|
|
1404
|
-
const parts = [
|
|
1768
|
+
const parts = [total ? `${total.toLocaleString()} tokens` : "", cost].filter(Boolean);
|
|
1405
1769
|
if (parts.length) process.stdout.write("\n" + c.dim(` \u21B3 ${parts.join(" \xB7 ")}`));
|
|
1770
|
+
if (cachedTok > 0) process.stdout.write(c.dim(` (${cachedTok.toLocaleString()} cached)`));
|
|
1771
|
+
appendSessionLog(sessionId, {
|
|
1772
|
+
type: "message",
|
|
1773
|
+
role: "assistant",
|
|
1774
|
+
content: agentContent,
|
|
1775
|
+
usage: { inputTokens: inputTok, outputTokens: outputTok, cachedTokens: cachedTok, totalTokens: total, costUsd: usage.costUsd },
|
|
1776
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1777
|
+
});
|
|
1778
|
+
} else {
|
|
1779
|
+
appendSessionLog(sessionId, {
|
|
1780
|
+
type: "message",
|
|
1781
|
+
role: "assistant",
|
|
1782
|
+
content: agentContent,
|
|
1783
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1784
|
+
});
|
|
1406
1785
|
}
|
|
1407
1786
|
break;
|
|
1408
1787
|
} else if (event.type === "error") {
|
|
@@ -1413,6 +1792,9 @@ ${sym.fail} ${c.error(event.message ?? "Stream error")}`);
|
|
|
1413
1792
|
}
|
|
1414
1793
|
}
|
|
1415
1794
|
process.stdout.write("\n");
|
|
1795
|
+
if (localToolsCfg && agentContent) {
|
|
1796
|
+
await handleLocalToolLoop(agentContent, localToolsCfg, client, agentId, sessionId, appendSessionLog);
|
|
1797
|
+
}
|
|
1416
1798
|
} catch (err) {
|
|
1417
1799
|
process.stdout.write("\n");
|
|
1418
1800
|
console.error(`${sym.fail} ${c.error(err.message ?? String(err))}`);
|
|
@@ -1432,6 +1814,78 @@ Session preserved. Resume with: agc chat --resume ${sessionId}`));
|
|
|
1432
1814
|
});
|
|
1433
1815
|
});
|
|
1434
1816
|
}
|
|
1817
|
+
var MAX_TOOL_DEPTH = 10;
|
|
1818
|
+
async function handleLocalToolLoop(agentText, cfg, client, agentId, sessionId, appendLog, depth = 0) {
|
|
1819
|
+
if (depth >= MAX_TOOL_DEPTH) {
|
|
1820
|
+
console.log(c.dim(`
|
|
1821
|
+
[local] Max tool depth reached (${MAX_TOOL_DEPTH}). Stopping tool loop.
|
|
1822
|
+
`));
|
|
1823
|
+
return;
|
|
1824
|
+
}
|
|
1825
|
+
const toolCall = extractToolCall(agentText);
|
|
1826
|
+
if (!toolCall) return;
|
|
1827
|
+
process.stdout.write(c.dim(`
|
|
1828
|
+
[local] ${toolCall.tool}`));
|
|
1829
|
+
let result;
|
|
1830
|
+
try {
|
|
1831
|
+
result = await runLocalTool(toolCall, cfg);
|
|
1832
|
+
process.stdout.write(c.dim(" \u2713\n"));
|
|
1833
|
+
} catch (err) {
|
|
1834
|
+
result = `Error: ${err?.message ?? String(err)}`;
|
|
1835
|
+
process.stdout.write(c.dim(" \u2717\n"));
|
|
1836
|
+
}
|
|
1837
|
+
const resultMsg = `[Tool result: ${toolCall.tool}]
|
|
1838
|
+
\`\`\`
|
|
1839
|
+
${result}
|
|
1840
|
+
\`\`\``;
|
|
1841
|
+
appendLog(sessionId, {
|
|
1842
|
+
type: "message",
|
|
1843
|
+
role: "tool",
|
|
1844
|
+
tool: toolCall.tool,
|
|
1845
|
+
result: result.slice(0, 4e3),
|
|
1846
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1847
|
+
});
|
|
1848
|
+
process.stdout.write(c.primary("agent") + c.dim(" \u203A "));
|
|
1849
|
+
let followContent = "";
|
|
1850
|
+
try {
|
|
1851
|
+
for await (const evt of client.agents.stream({
|
|
1852
|
+
agentId,
|
|
1853
|
+
sessionId,
|
|
1854
|
+
messages: [{ role: "user", content: resultMsg }]
|
|
1855
|
+
})) {
|
|
1856
|
+
if (evt.type === "token") {
|
|
1857
|
+
const tok = evt.content ?? "";
|
|
1858
|
+
process.stdout.write(tok);
|
|
1859
|
+
followContent += tok;
|
|
1860
|
+
} else if (evt.type === "toolStart") {
|
|
1861
|
+
const name = evt.toolName ?? "";
|
|
1862
|
+
if (followContent) process.stdout.write("\n");
|
|
1863
|
+
process.stdout.write(c.dim(` [tool] ${name}\u2026`));
|
|
1864
|
+
} else if (evt.type === "toolEnd") {
|
|
1865
|
+
process.stdout.write(c.dim(" done\n"));
|
|
1866
|
+
process.stdout.write(c.primary("agent") + c.dim(" \u203A "));
|
|
1867
|
+
} else if (evt.type === "final") {
|
|
1868
|
+
const txt = extractText(evt?.payload);
|
|
1869
|
+
if (txt && !followContent) {
|
|
1870
|
+
process.stdout.write(txt);
|
|
1871
|
+
followContent += txt;
|
|
1872
|
+
}
|
|
1873
|
+
appendLog(sessionId, { type: "message", role: "assistant", content: followContent, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
1874
|
+
break;
|
|
1875
|
+
} else if (evt.type === "error") {
|
|
1876
|
+
console.error(`
|
|
1877
|
+
${sym.fail} ${c.error(evt.message ?? "Stream error")}`);
|
|
1878
|
+
break;
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
process.stdout.write("\n");
|
|
1882
|
+
} catch (err) {
|
|
1883
|
+
process.stdout.write("\n");
|
|
1884
|
+
console.error(`${sym.fail} ${c.error(err?.message ?? String(err))}`);
|
|
1885
|
+
return;
|
|
1886
|
+
}
|
|
1887
|
+
await handleLocalToolLoop(followContent, cfg, client, agentId, sessionId, appendLog, depth + 1);
|
|
1888
|
+
}
|
|
1435
1889
|
function extractText(payload) {
|
|
1436
1890
|
if (!payload) return "";
|
|
1437
1891
|
if (typeof payload === "string") return payload;
|
|
@@ -1970,10 +2424,10 @@ function skillsCommand() {
|
|
|
1970
2424
|
});
|
|
1971
2425
|
cmd.command("delete <slug>").description("Permanently delete a skill").option("--yes", "Skip confirmation prompt").option("--json", "Output result as JSON").action(async (slug, opts) => {
|
|
1972
2426
|
if (!opts.yes) {
|
|
1973
|
-
const
|
|
1974
|
-
const rl =
|
|
2427
|
+
const readline4 = await import("readline");
|
|
2428
|
+
const rl = readline4.createInterface({ input: process.stdin, output: process.stdout });
|
|
1975
2429
|
const answer = await new Promise(
|
|
1976
|
-
(
|
|
2430
|
+
(resolve2) => rl.question(c.warn(`Delete skill "${slug}"? This cannot be undone. [y/N] `), resolve2)
|
|
1977
2431
|
);
|
|
1978
2432
|
rl.close();
|
|
1979
2433
|
if (!["y", "yes"].includes(answer.trim().toLowerCase())) {
|
|
@@ -2595,7 +3049,7 @@ function logsCommand() {
|
|
|
2595
3049
|
}
|
|
2596
3050
|
|
|
2597
3051
|
// src/bin.ts
|
|
2598
|
-
var CONFIG_FILE3 = (0,
|
|
3052
|
+
var CONFIG_FILE3 = (0, import_path5.join)((0, import_os4.homedir)(), ".agc", "config.json");
|
|
2599
3053
|
async function interactiveMenu() {
|
|
2600
3054
|
banner();
|
|
2601
3055
|
const cfg = loadConfig();
|
|
@@ -2646,27 +3100,71 @@ async function interactiveMenu() {
|
|
|
2646
3100
|
exit: []
|
|
2647
3101
|
};
|
|
2648
3102
|
if ((action === "chat" || action === "run") && !cfg.defaultAgentId) {
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
${sym.arrow} ${c.dim("Run")} ${c.bold("agc agents list")} ${c.dim("to find an agent ID, then")}
|
|
2653
|
-
${sym.arrow} ${c.dim("Run")} ${c.bold("agc config set defaultAgentId <id>")} ${c.dim("to set a default.")}
|
|
2654
|
-
`
|
|
2655
|
-
);
|
|
2656
|
-
console.log(` ${c.dim("Or pass it directly: ")}${c.bold(`agc ${action} --agent <id>`)}
|
|
2657
|
-
`);
|
|
3103
|
+
const pickedId = await pickAgentInteractively(action);
|
|
3104
|
+
if (!pickedId) return;
|
|
3105
|
+
runSubcommand([action, "--agent", pickedId]);
|
|
2658
3106
|
return;
|
|
2659
3107
|
}
|
|
2660
3108
|
runSubcommand(commandMap[action]);
|
|
2661
3109
|
}
|
|
2662
3110
|
function runSubcommand(args) {
|
|
2663
|
-
const child = (0,
|
|
3111
|
+
const child = (0, import_child_process3.spawn)(process.argv[0], [process.argv[1], ...args], {
|
|
2664
3112
|
stdio: "inherit"
|
|
2665
3113
|
});
|
|
2666
3114
|
child.on("exit", (code) => process.exit(code ?? 0));
|
|
2667
3115
|
}
|
|
3116
|
+
async function pickAgentInteractively(action) {
|
|
3117
|
+
const cfg = loadConfig();
|
|
3118
|
+
const spinner = spin("Fetching your agents\u2026");
|
|
3119
|
+
let agents = [];
|
|
3120
|
+
try {
|
|
3121
|
+
const client = makeClient();
|
|
3122
|
+
const res = await client.agents.list(cfg.initiator);
|
|
3123
|
+
agents = res?.data ?? (Array.isArray(res) ? res : []);
|
|
3124
|
+
spinner.stop();
|
|
3125
|
+
} catch {
|
|
3126
|
+
spinner.stop();
|
|
3127
|
+
console.log(`
|
|
3128
|
+
${c.warn("\u26A0")} Could not fetch agents. Check your API key and connection.
|
|
3129
|
+
`);
|
|
3130
|
+
return null;
|
|
3131
|
+
}
|
|
3132
|
+
if (agents.length === 0) {
|
|
3133
|
+
console.log(`
|
|
3134
|
+
${c.warn("\u26A0")} You don't have any agents yet.
|
|
3135
|
+
`);
|
|
3136
|
+
const choice = await select("What would you like to do?", [
|
|
3137
|
+
{ label: "Create a new agent now", value: "create", hint: "agc agents create" },
|
|
3138
|
+
{ label: "Go back", value: "cancel" }
|
|
3139
|
+
]);
|
|
3140
|
+
if (choice === "create") {
|
|
3141
|
+
runSubcommand(["agents", "create"]);
|
|
3142
|
+
}
|
|
3143
|
+
return null;
|
|
3144
|
+
}
|
|
3145
|
+
console.log();
|
|
3146
|
+
const agentId = await select(
|
|
3147
|
+
`Choose an agent to ${action} with:`,
|
|
3148
|
+
agents.map((a) => ({
|
|
3149
|
+
label: a.name,
|
|
3150
|
+
value: a.agentId,
|
|
3151
|
+
hint: `${a.modelProvider}/${a.modelId}`
|
|
3152
|
+
}))
|
|
3153
|
+
);
|
|
3154
|
+
const saveDefault = await select("Set as your default agent?", [
|
|
3155
|
+
{ label: "Yes \u2014 remember this agent for next time", value: true },
|
|
3156
|
+
{ label: "No \u2014 just this once", value: false }
|
|
3157
|
+
]);
|
|
3158
|
+
if (saveDefault) {
|
|
3159
|
+
saveConfig({ defaultAgentId: agentId });
|
|
3160
|
+
const chosen = agents.find((a) => a.agentId === agentId);
|
|
3161
|
+
console.log(` ${sym.ok} ${c.dim("Default agent set to")} ${c.bold(chosen?.name ?? agentId)}
|
|
3162
|
+
`);
|
|
3163
|
+
}
|
|
3164
|
+
return agentId;
|
|
3165
|
+
}
|
|
2668
3166
|
var program = new import_commander16.Command();
|
|
2669
|
-
program.name("agc").description("Agent Commons CLI \u2014 interact with the Agent Commons platform").version("0.1.
|
|
3167
|
+
program.name("agc").description("Agent Commons CLI \u2014 interact with the Agent Commons platform").version("0.1.10", "-v, --version").action(async () => {
|
|
2670
3168
|
await interactiveMenu();
|
|
2671
3169
|
});
|
|
2672
3170
|
program.addCommand(loginCommand());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-commons/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"description": "Agent Commons CLI — chat, run, and manage agents from your terminal",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
|
@@ -10,11 +10,16 @@
|
|
|
10
10
|
"files": [
|
|
11
11
|
"dist"
|
|
12
12
|
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsup",
|
|
15
|
+
"dev": "tsup --watch",
|
|
16
|
+
"typecheck": "tsc --noEmit"
|
|
17
|
+
},
|
|
13
18
|
"dependencies": {
|
|
19
|
+
"@agent-commons/sdk": "workspace:*",
|
|
14
20
|
"commander": "^12.1.0",
|
|
15
21
|
"chalk": "^5.3.0",
|
|
16
|
-
"ora": "^8.1.1"
|
|
17
|
-
"@agent-commons/sdk": "0.1.6"
|
|
22
|
+
"ora": "^8.1.1"
|
|
18
23
|
},
|
|
19
24
|
"devDependencies": {
|
|
20
25
|
"tsup": "^8.3.5",
|
|
@@ -26,10 +31,5 @@
|
|
|
26
31
|
},
|
|
27
32
|
"publishConfig": {
|
|
28
33
|
"access": "public"
|
|
29
|
-
},
|
|
30
|
-
"scripts": {
|
|
31
|
-
"build": "tsup",
|
|
32
|
-
"dev": "tsup --watch",
|
|
33
|
-
"typecheck": "tsc --noEmit"
|
|
34
34
|
}
|
|
35
|
-
}
|
|
35
|
+
}
|