@agent-commons/cli 0.1.12 → 0.1.14

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.
Files changed (2) hide show
  1. package/dist/bin.js +143 -46
  2. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -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.12") {
109
+ function banner(version = "0.1.14") {
110
110
  const line = import_chalk.default.cyan(" \u2500".padEnd(2) + "\u2500".repeat(44));
111
111
  console.log("");
112
112
  console.log(line);
@@ -1257,61 +1257,105 @@ var import_fs3 = require("fs");
1257
1257
  var import_path3 = require("path");
1258
1258
  var import_child_process2 = require("child_process");
1259
1259
  var readline2 = __toESM(require("readline"));
1260
- function buildLocalToolsManifest(rootDir) {
1261
- return `## Local File System Access
1260
+ var SKIP_DIRS = /* @__PURE__ */ new Set([".git", "node_modules", ".cache", "__pycache__", ".next", "dist", "build", ".DS_Store"]);
1261
+ function buildDirSnapshot(dir, maxDepth = 2) {
1262
+ const lines = [`${dir}/`];
1263
+ function walk(d, depth, prefix) {
1264
+ if (lines.length >= 300) return;
1265
+ let entries;
1266
+ try {
1267
+ entries = (0, import_fs3.readdirSync)(d, { withFileTypes: true });
1268
+ } catch {
1269
+ return;
1270
+ }
1271
+ const sorted = entries.sort((a, b) => {
1272
+ if (a.isDirectory() !== b.isDirectory()) return a.isDirectory() ? -1 : 1;
1273
+ return a.name.localeCompare(b.name);
1274
+ });
1275
+ for (const entry of sorted) {
1276
+ if (lines.length >= 300) {
1277
+ lines.push(`${prefix}... (truncated)`);
1278
+ return;
1279
+ }
1280
+ if (entry.name.startsWith(".") || SKIP_DIRS.has(entry.name)) continue;
1281
+ const isDir = entry.isDirectory();
1282
+ lines.push(`${prefix}${entry.name}${isDir ? "/" : ""}`);
1283
+ if (isDir && depth < maxDepth) walk((0, import_path3.join)(d, entry.name), depth + 1, prefix + " ");
1284
+ }
1285
+ }
1286
+ walk(dir, 1, " ");
1287
+ return lines.join("\n");
1288
+ }
1289
+ function readFileForContext(rootDir, filePath) {
1290
+ try {
1291
+ const abs = (0, import_path3.resolve)(rootDir, filePath);
1292
+ const rel = (0, import_path3.relative)(rootDir, abs);
1293
+ if (rel.startsWith("..") || rel.startsWith("/")) return `[error: path escapes session root]`;
1294
+ for (const pat of [/\/\.ssh\//, /\/\.aws\//, /\/\.env$/, /\/\.env\./, /id_rsa/, /id_ed25519/]) {
1295
+ if (pat.test(abs)) return `[error: sensitive path blocked]`;
1296
+ }
1297
+ if (!(0, import_fs3.existsSync)(abs)) return `[error: file not found: ${filePath}]`;
1298
+ const stat = (0, import_fs3.statSync)(abs);
1299
+ if (stat.isDirectory()) return `[error: "${filePath}" is a directory \u2014 use list_directory]`;
1300
+ if (stat.size > 1e5) return `[truncated \u2014 file too large (${Math.round(stat.size / 1024)} KB). Use cli_read_file for full content]`;
1301
+ return (0, import_fs3.readFileSync)(abs, "utf8");
1302
+ } catch (err) {
1303
+ return `[error reading file: ${err?.message}]`;
1304
+ }
1305
+ }
1306
+ function buildLocalToolsManifest(rootDir, snapshot, fileContextBlocks = []) {
1307
+ const fileSection = fileContextBlocks.length ? `
1308
+ ### File contents included in this turn
1309
+
1310
+ ${fileContextBlocks.join("\n\n")}
1311
+ ` : "";
1312
+ return `
1313
+ ## CLI Local File System \u2014 ACTIVE
1262
1314
 
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.
1315
+ You are running inside a CLI session with DIRECT access to the user's local machine. The following tools are in your tool list and execute on the user's machine in real time.
1264
1316
 
1265
1317
  **Session root:** ${rootDir}
1266
- All paths are relative to the session root unless absolute.
1267
1318
 
1268
- ---
1319
+ ### Current file system (live snapshot)
1269
1320
 
1270
- ### How to call a tool
1321
+ \`\`\`
1322
+ ${snapshot}
1323
+ \`\`\`
1324
+ ${fileSection}
1271
1325
 
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:
1326
+ ### MANDATORY RULES \u2014 READ CAREFULLY
1273
1327
 
1274
- \`\`\`tool
1275
- {"tool": "<tool_name>", "args": {"<arg>": "<value>"}}
1276
- \`\`\`
1328
+ 1. **Call cli_* tools immediately and directly.** Do NOT create tasks (createTask) for local file operations. Do NOT delegate to sub-agents. Do NOT ask the user to run commands themselves.
1329
+ 2. **Always show the actual output** returned by the tool in your response. Never say "I listed the files" without showing them. Report exactly what the tool returns.
1330
+ 3. **Never fabricate results.** Wait for the real tool output before responding.
1331
+ 4. **Sensitive paths are blocked** (.ssh, .gnupg, .aws, .env, credentials). Attempting to access them will return an error.
1332
+ 5. **cli_write_file and cli_run_command require the user to confirm** before executing \u2014 you will see the result after they approve.
1277
1333
 
1278
- You may call tools multiple times in sequence. Each call will be executed and the result returned to you before you continue.
1334
+ ### Available CLI tools
1279
1335
 
1280
- ---
1336
+ | Tool | What it does |
1337
+ |------|-------------|
1338
+ | \`cli_list_directory\` | List files and folders at a path (default: session root) |
1339
+ | \`cli_read_file\` | Read the full contents of a file |
1340
+ | \`cli_write_file\` | Write or overwrite a file (user confirmation required) |
1341
+ | \`cli_search_files\` | Find files matching a pattern, e.g. "*.ts" |
1342
+ | \`cli_run_command\` | Run a shell command and return output (user confirmation required) |
1281
1343
 
1282
- ### Available tools
1344
+ ### Example \u2014 listing a directory
1283
1345
 
1284
- **read_file** \u2014 Read the full contents of a file.
1285
- \`\`\`tool
1286
- {"tool": "read_file", "args": {"path": "src/index.ts"}}
1287
- \`\`\`
1346
+ When the user asks "what's on my desktop?", call \`cli_list_directory\` with \`{"path": "Desktop"}\` immediately. Then show the result.
1288
1347
 
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
- \`\`\`
1348
+ ### Example \u2014 reading a file
1293
1349
 
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
- \`\`\`
1350
+ Call \`cli_read_file\` with \`{"path": "Desktop/notes.txt"}\`. Then quote the content in your reply.
1298
1351
 
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
- \`\`\`
1352
+ ### Example \u2014 writing a file
1303
1353
 
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
- \`\`\`
1354
+ Call \`cli_write_file\` with \`{"path": "output.txt", "content": "Hello"}\`. The user will be prompted to confirm.
1308
1355
 
1309
- ---
1356
+ ### Example \u2014 running a command
1310
1357
 
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.
1358
+ Call \`cli_run_command\` with \`{"command": "ls", "args": ["-la"]}\`. The user will be prompted to confirm.
1315
1359
  `;
1316
1360
  }
1317
1361
  var TOOL_CALL_RE = /```tool\s*\n([\s\S]*?)\n```/;
@@ -1522,9 +1566,13 @@ var HELP_TEXT = `
1522
1566
  ${c.label("Slash commands")}
1523
1567
  /help Show this help
1524
1568
  /session Print the current session ID (copy it to resume later)
1525
- /tools Show local tool status and permissions (--local mode)
1569
+ /tools Show local tool status and permissions
1526
1570
  /clear Clear the terminal screen
1527
1571
  /quit Exit (session is preserved \u2014 resume with --resume <id>)
1572
+
1573
+ ${c.label("File context")}
1574
+ Use @path/to/file in your message to inject that file's contents into context.
1575
+ Example: "review @src/index.ts and suggest improvements"
1528
1576
  `;
1529
1577
  var LOCAL_TOOLS_DISCLAIMER = `
1530
1578
  ${c.warn("\u26A0")} ${c.bold("Local file system access enabled")}
@@ -1705,14 +1753,27 @@ Session saved. Resume with: agc chat --resume ${sessionId}`));
1705
1753
  content: input,
1706
1754
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
1707
1755
  });
1756
+ let userMessage = input;
1757
+ let cliContext;
1758
+ if (localToolsCfg) {
1759
+ const rootDir = localToolsCfg.rootDir;
1760
+ const atRefs = [...input.matchAll(/@([\S]+)/g)].map((m) => m[1]);
1761
+ const fileContextBlocks = [];
1762
+ for (const ref of atRefs) {
1763
+ const content = readFileForContext(rootDir, ref);
1764
+ fileContextBlocks.push(`**${ref}**
1765
+ \`\`\`
1766
+ ${content}
1767
+ \`\`\``);
1768
+ }
1769
+ const snapshot = buildDirSnapshot(rootDir, 2);
1770
+ cliContext = buildLocalToolsManifest(rootDir, snapshot, fileContextBlocks);
1771
+ }
1708
1772
  const params = {
1709
1773
  agentId,
1710
1774
  sessionId,
1711
- messages: [{ role: "user", content: input }],
1712
- // Inject the tool manifest into the agent's system prompt server-side so
1713
- // the LLM receives it as part of its actual instructions, not as a stray
1714
- // second system message appended after the conversation history.
1715
- ...localToolsCfg && { cliContext: buildLocalToolsManifest(localToolsCfg.rootDir) }
1775
+ messages: [{ role: "user", content: userMessage }],
1776
+ ...cliContext && { cliContext }
1716
1777
  };
1717
1778
  process.stdout.write(c.primary("agent") + c.dim(" \u203A "));
1718
1779
  if (opts.noStream) {
@@ -1743,6 +1804,42 @@ ${sym.fail} ${c.error(err.message ?? String(err))}`);
1743
1804
  process.stdout.write(tok);
1744
1805
  agentContent += tok;
1745
1806
  hasOutput = true;
1807
+ } else if (event.type === "cli_tool_request" && localToolsCfg) {
1808
+ const { requestId, tool: toolName, args } = event;
1809
+ const displayName = String(toolName).replace("cli_", "");
1810
+ if (hasOutput) {
1811
+ process.stdout.write("\n");
1812
+ hasOutput = false;
1813
+ }
1814
+ process.stdout.write(c.dim(` [local] ${displayName}\u2026`));
1815
+ let result;
1816
+ try {
1817
+ const localToolName = String(toolName).replace("cli_", "");
1818
+ result = await runLocalTool({ tool: localToolName, args: args ?? {} }, localToolsCfg);
1819
+ process.stdout.write(c.dim(" \u2713\n"));
1820
+ } catch (err) {
1821
+ result = `Error: ${err?.message ?? String(err)}`;
1822
+ process.stdout.write(c.dim(" \u2717\n"));
1823
+ }
1824
+ appendSessionLog(sessionId, {
1825
+ type: "local_tool_result",
1826
+ tool: toolName,
1827
+ result: result.slice(0, 4e3),
1828
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1829
+ });
1830
+ try {
1831
+ await fetch(`${cfg.apiUrl}/v1/agents/cli-tool-result`, {
1832
+ method: "POST",
1833
+ headers: {
1834
+ "Content-Type": "application/json",
1835
+ "Authorization": `Bearer ${cfg.apiKey}`
1836
+ },
1837
+ body: JSON.stringify({ requestId, result })
1838
+ });
1839
+ } catch (postErr) {
1840
+ console.error(c.warn(`
1841
+ [local] Failed to submit tool result: ${postErr?.message}`));
1842
+ }
1746
1843
  } else if (event.type === "toolStart") {
1747
1844
  const name = event.toolName ?? "";
1748
1845
  if (hasOutput) process.stdout.write("\n");
@@ -3182,7 +3279,7 @@ async function pickAgentInteractively(action) {
3182
3279
  return agentId;
3183
3280
  }
3184
3281
  var program = new import_commander16.Command();
3185
- program.name("agc").description("Agent Commons CLI \u2014 interact with the Agent Commons platform").version("0.1.12", "-v, --version").action(async () => {
3282
+ program.name("agc").description("Agent Commons CLI \u2014 interact with the Agent Commons platform").version("0.1.14", "-v, --version").action(async () => {
3186
3283
  await interactiveMenu();
3187
3284
  });
3188
3285
  program.addCommand(loginCommand());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-commons/cli",
3
- "version": "0.1.12",
3
+ "version": "0.1.14",
4
4
  "description": "Agent Commons CLI — chat, run, and manage agents from your terminal",
5
5
  "license": "MIT",
6
6
  "bin": {