@agent-commons/cli 0.4.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -0
- package/dist/bin.js +997 -301
- package/package.json +2 -2
package/dist/bin.js
CHANGED
|
@@ -24,7 +24,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
));
|
|
25
25
|
|
|
26
26
|
// src/bin.ts
|
|
27
|
-
var
|
|
27
|
+
var import_commander24 = require("commander");
|
|
28
28
|
var import_child_process3 = require("child_process");
|
|
29
29
|
|
|
30
30
|
// src/commands/login.ts
|
|
@@ -178,7 +178,7 @@ var sym = {
|
|
|
178
178
|
bullet: import_chalk.default.dim("\u2022"),
|
|
179
179
|
dot: import_chalk.default.dim("\xB7")
|
|
180
180
|
};
|
|
181
|
-
function banner(version = "0.
|
|
181
|
+
function banner(version = "0.6.1") {
|
|
182
182
|
console.log("");
|
|
183
183
|
console.log(import_chalk.default.cyan(" \u25C7"));
|
|
184
184
|
console.log(import_chalk.default.cyan(" \u256D\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E"));
|
|
@@ -664,11 +664,11 @@ function agentsCommand() {
|
|
|
664
664
|
process.exit(1);
|
|
665
665
|
}
|
|
666
666
|
});
|
|
667
|
-
cmd.command("get <agentId>").description("Show details for an agent").option("--json", "Output as JSON").action(async (
|
|
667
|
+
cmd.command("get <agentId>").description("Show details for an agent").option("--json", "Output as JSON").action(async (agentId3, opts) => {
|
|
668
668
|
const spinner = spin("Fetching agent\u2026");
|
|
669
669
|
try {
|
|
670
670
|
const client = makeClient();
|
|
671
|
-
const res = await client.agents.get(
|
|
671
|
+
const res = await client.agents.get(agentId3);
|
|
672
672
|
const agent = res?.data ?? res;
|
|
673
673
|
spinner.stop();
|
|
674
674
|
if (opts.json) return jsonOut(agent);
|
|
@@ -747,10 +747,10 @@ ${sym.ok} Agent created`);
|
|
|
747
747
|
}
|
|
748
748
|
});
|
|
749
749
|
const runtime = cmd.command("runtime").description("Manage an agent runtime");
|
|
750
|
-
runtime.command("status <agentId>").description("Show managed runtime status and capabilities").option("--json", "Output as JSON").action(async (
|
|
750
|
+
runtime.command("status <agentId>").description("Show managed runtime status and capabilities").option("--json", "Output as JSON").action(async (agentId3, opts) => {
|
|
751
751
|
const spinner = spin("Fetching runtime status\u2026");
|
|
752
752
|
try {
|
|
753
|
-
const result = await makeClient().agents.getRuntime(
|
|
753
|
+
const result = await makeClient().agents.getRuntime(agentId3);
|
|
754
754
|
spinner.stop();
|
|
755
755
|
if (opts.json) return jsonOut(result.data);
|
|
756
756
|
detail([
|
|
@@ -768,13 +768,13 @@ ${sym.ok} Agent created`);
|
|
|
768
768
|
for (const action of ["deploy", "restart", "sleep"]) {
|
|
769
769
|
runtime.command(`${action} <agentId>`).description(
|
|
770
770
|
`${action[0].toUpperCase()}${action.slice(1)} the managed agent runtime`
|
|
771
|
-
).action(async (
|
|
771
|
+
).action(async (agentId3) => {
|
|
772
772
|
const spinner = spin(
|
|
773
773
|
`${action[0].toUpperCase()}${action.slice(1)}ing runtime\u2026`
|
|
774
774
|
);
|
|
775
775
|
try {
|
|
776
776
|
const client = makeClient();
|
|
777
|
-
const result = action === "deploy" ? await client.agents.deployRuntime(
|
|
777
|
+
const result = action === "deploy" ? await client.agents.deployRuntime(agentId3) : action === "restart" ? await client.agents.restartRuntime(agentId3) : await client.agents.sleepRuntime(agentId3);
|
|
778
778
|
spinner.stop();
|
|
779
779
|
console.log(`
|
|
780
780
|
${sym.ok} Runtime ${result.data.status}`);
|
|
@@ -887,12 +887,12 @@ function sessionsCommand() {
|
|
|
887
887
|
const spinner = spin("Fetching sessions\u2026");
|
|
888
888
|
try {
|
|
889
889
|
const client = makeClient();
|
|
890
|
-
const
|
|
891
|
-
const res =
|
|
890
|
+
const agentId3 = opts.agent;
|
|
891
|
+
const res = agentId3 ? await client.sessions.list(agentId3, cfg.initiator) : await client.sessions.listByUser(cfg.initiator);
|
|
892
892
|
const sessions = res?.data ?? res ?? [];
|
|
893
893
|
spinner.stop();
|
|
894
894
|
if (opts.json) return jsonOut(sessions);
|
|
895
|
-
section(`Sessions (${sessions.length})${
|
|
895
|
+
section(`Sessions (${sessions.length})${agentId3 ? ` \u2014 agent ${agentId3.slice(0, 8)}\u2026` : " \u2014 all agents"}`);
|
|
896
896
|
table(
|
|
897
897
|
sessions.map((s) => ({
|
|
898
898
|
ID: s.sessionId.slice(0, 8) + "\u2026",
|
|
@@ -933,8 +933,8 @@ function sessionsCommand() {
|
|
|
933
933
|
});
|
|
934
934
|
cmd.command("create").description("Create a new session").option("--agent <agentId>", "Agent ID").option("--title <title>", "Session title").option("--model <id>", "Model ID (e.g. gpt-5.4-mini, claude-sonnet-4-6)").option("--provider <provider>", "Model provider").option("--json", "Output as JSON").action(async (opts) => {
|
|
935
935
|
const cfg = loadConfig();
|
|
936
|
-
const
|
|
937
|
-
if (!
|
|
936
|
+
const agentId3 = opts.agent ?? cfg.defaultAgentId;
|
|
937
|
+
if (!agentId3) {
|
|
938
938
|
console.error(c.error("Specify --agent <agentId> or set defaultAgentId"));
|
|
939
939
|
process.exit(1);
|
|
940
940
|
}
|
|
@@ -946,7 +946,7 @@ function sessionsCommand() {
|
|
|
946
946
|
try {
|
|
947
947
|
const client = makeClient();
|
|
948
948
|
const res = await client.sessions.create({
|
|
949
|
-
agentId:
|
|
949
|
+
agentId: agentId3,
|
|
950
950
|
initiator: cfg.initiator,
|
|
951
951
|
title: opts.title,
|
|
952
952
|
...opts.model && { model: { modelId: opts.model, provider: opts.provider } }
|
|
@@ -1102,8 +1102,8 @@ ${sym.ok} Tool created`);
|
|
|
1102
1102
|
});
|
|
1103
1103
|
cmd.command("exec <toolName>").description("Execute a tool directly by name").option("--agent <agentId>", "Agent context for tool execution").option("--args <json>", "Tool arguments as JSON object", "{}").option("--json", "Output result as JSON").action(async (toolName, opts) => {
|
|
1104
1104
|
const cfg = loadConfig();
|
|
1105
|
-
const
|
|
1106
|
-
if (!
|
|
1105
|
+
const agentId3 = opts.agent ?? cfg.defaultAgentId;
|
|
1106
|
+
if (!agentId3) {
|
|
1107
1107
|
console.error(c.error("Specify --agent <agentId> or set defaultAgentId with `agc config set defaultAgentId <id>`"));
|
|
1108
1108
|
process.exit(1);
|
|
1109
1109
|
}
|
|
@@ -1119,7 +1119,7 @@ ${sym.ok} Tool created`);
|
|
|
1119
1119
|
try {
|
|
1120
1120
|
const client = makeClient();
|
|
1121
1121
|
const result = await client.run.once({
|
|
1122
|
-
agentId:
|
|
1122
|
+
agentId: agentId3,
|
|
1123
1123
|
messages: [{ role: "user", content: prompt }],
|
|
1124
1124
|
...cfg.initiator && { initiatorId: cfg.initiator }
|
|
1125
1125
|
});
|
|
@@ -1241,7 +1241,10 @@ ${sym.ok} Authorize the connection in your browser:`);
|
|
|
1241
1241
|
["Account", connection.providerUserEmail ?? connection.providerUserName ?? ""],
|
|
1242
1242
|
["Status", connection.status],
|
|
1243
1243
|
["Scopes", connection.scopes.join(", ")],
|
|
1244
|
-
[
|
|
1244
|
+
[
|
|
1245
|
+
"Expires",
|
|
1246
|
+
connection.accessTokenExpiresAt ?? connection.expiresAt ?? c.dim("(does not expire)")
|
|
1247
|
+
]
|
|
1245
1248
|
]);
|
|
1246
1249
|
} catch (err) {
|
|
1247
1250
|
spinner.stop();
|
|
@@ -1445,8 +1448,8 @@ ${sym.ok} Workflow created`);
|
|
|
1445
1448
|
}
|
|
1446
1449
|
const templateName = templateNameRaw;
|
|
1447
1450
|
const needsAgent = templateName === "agent-research-summary" || templateName === "multi-agent-field-report";
|
|
1448
|
-
const
|
|
1449
|
-
if (needsAgent && !
|
|
1451
|
+
const agentId3 = opts.agent ?? cfg.defaultAgentId;
|
|
1452
|
+
if (needsAgent && !agentId3) {
|
|
1450
1453
|
console.error(c.error("This template requires --agent <agentId> or a configured defaultAgentId."));
|
|
1451
1454
|
process.exit(1);
|
|
1452
1455
|
}
|
|
@@ -1470,7 +1473,7 @@ ${sym.ok} Workflow created`);
|
|
|
1470
1473
|
const ctx = {
|
|
1471
1474
|
ownerId: cfg.initiator,
|
|
1472
1475
|
prefix,
|
|
1473
|
-
agentId:
|
|
1476
|
+
agentId: agentId3,
|
|
1474
1477
|
reviewerAgentId: opts.reviewerAgent,
|
|
1475
1478
|
childWorkflowId
|
|
1476
1479
|
};
|
|
@@ -1490,7 +1493,7 @@ ${sym.ok} Workflow created`);
|
|
|
1490
1493
|
}
|
|
1491
1494
|
}
|
|
1492
1495
|
execution = await makeClient().workflows.execute(result.workflow.workflowId, {
|
|
1493
|
-
agentId:
|
|
1496
|
+
agentId: agentId3,
|
|
1494
1497
|
inputData,
|
|
1495
1498
|
userId: cfg.initiator
|
|
1496
1499
|
});
|
|
@@ -1561,7 +1564,7 @@ ${sym.ok} Execution started: ${c.id(execution.executionId)}`);
|
|
|
1561
1564
|
});
|
|
1562
1565
|
cmd.command("run <workflowId>").description("Execute a workflow").option("--agent <agentId>", "Agent context").option("--session <sessionId>", "Session context").option("--input <json>", "Input data as JSON string", "{}").option("--watch", "Stream execution progress via SSE").option("--json", "Output result as JSON").action(async (workflowId, opts) => {
|
|
1563
1566
|
const cfg = loadConfig();
|
|
1564
|
-
const
|
|
1567
|
+
const agentId3 = opts.agent ?? cfg.defaultAgentId;
|
|
1565
1568
|
let inputData = {};
|
|
1566
1569
|
try {
|
|
1567
1570
|
inputData = JSON.parse(opts.input);
|
|
@@ -1573,7 +1576,7 @@ ${sym.ok} Execution started: ${c.id(execution.executionId)}`);
|
|
|
1573
1576
|
try {
|
|
1574
1577
|
const client = makeClient();
|
|
1575
1578
|
const execution = await client.workflows.execute(workflowId, {
|
|
1576
|
-
agentId:
|
|
1579
|
+
agentId: agentId3,
|
|
1577
1580
|
sessionId: opts.session,
|
|
1578
1581
|
inputData
|
|
1579
1582
|
});
|
|
@@ -1718,12 +1721,12 @@ function taskCommand() {
|
|
|
1718
1721
|
const cmd = new import_commander7.Command("task").description("Manage and execute tasks").alias("t");
|
|
1719
1722
|
cmd.command("list").description("List tasks").option("--agent <agentId>", "Filter by agent ID").option("--session <sessionId>", "Filter by session ID").option("--json", "Output as JSON").action(async (opts) => {
|
|
1720
1723
|
const cfg = loadConfig();
|
|
1721
|
-
const
|
|
1724
|
+
const agentId3 = opts.agent ?? cfg.defaultAgentId;
|
|
1722
1725
|
const spinner = spin("Fetching tasks\u2026");
|
|
1723
1726
|
try {
|
|
1724
1727
|
const client = makeClient();
|
|
1725
1728
|
const filter = {};
|
|
1726
|
-
if (
|
|
1729
|
+
if (agentId3) filter.agentId = agentId3;
|
|
1727
1730
|
if (opts.session) filter.sessionId = opts.session;
|
|
1728
1731
|
if (cfg.initiator) {
|
|
1729
1732
|
filter.ownerId = cfg.initiator;
|
|
@@ -1779,8 +1782,8 @@ function taskCommand() {
|
|
|
1779
1782
|
});
|
|
1780
1783
|
cmd.command("create").description("Create a new task").requiredOption("--title <title>", "Task title").option("--agent <agentId>", "Agent ID").option("--session <sessionId>", "Session ID").option("--workflow <workflowId>", "Workflow ID to attach").option("--input <json>", "Input data as JSON", "{}").option("--timeout <ms>", "Execution timeout in milliseconds").option("--execute", "Execute immediately after creation").option("--watch", "Stream execution progress (implies --execute)").option("--json", "Output as JSON").action(async (opts) => {
|
|
1781
1784
|
const cfg = loadConfig();
|
|
1782
|
-
const
|
|
1783
|
-
if (!
|
|
1785
|
+
const agentId3 = opts.agent ?? cfg.defaultAgentId;
|
|
1786
|
+
if (!agentId3) {
|
|
1784
1787
|
console.error(c.error("Specify --agent <agentId> or set defaultAgentId with `agc config set defaultAgentId <id>`"));
|
|
1785
1788
|
process.exit(1);
|
|
1786
1789
|
}
|
|
@@ -1796,7 +1799,7 @@ function taskCommand() {
|
|
|
1796
1799
|
const client = makeClient();
|
|
1797
1800
|
const res = await client.tasks.create({
|
|
1798
1801
|
title: opts.title,
|
|
1799
|
-
agentId:
|
|
1802
|
+
agentId: agentId3,
|
|
1800
1803
|
sessionId: opts.session,
|
|
1801
1804
|
workflowId: opts.workflow,
|
|
1802
1805
|
inputData,
|
|
@@ -1902,14 +1905,237 @@ ${sym.fail} ${c.error(event.message ?? event.type)}`);
|
|
|
1902
1905
|
// src/commands/run.ts
|
|
1903
1906
|
var import_commander8 = require("commander");
|
|
1904
1907
|
var readline2 = __toESM(require("readline"));
|
|
1908
|
+
var import_fs6 = require("fs");
|
|
1909
|
+
var import_path4 = require("path");
|
|
1905
1910
|
|
|
1906
1911
|
// src/local-tools.ts
|
|
1907
1912
|
var import_fs5 = require("fs");
|
|
1908
1913
|
var import_path3 = require("path");
|
|
1909
1914
|
var import_child_process2 = require("child_process");
|
|
1915
|
+
var import_crypto = require("crypto");
|
|
1910
1916
|
var readline = __toESM(require("readline"));
|
|
1917
|
+
|
|
1918
|
+
// src/edit-preview.ts
|
|
1919
|
+
function editPreview(before, after, limit = 12e3) {
|
|
1920
|
+
if (before === after) return "(no content change)";
|
|
1921
|
+
const oldLines = before ? before.split("\n") : [];
|
|
1922
|
+
const newLines = after ? after.split("\n") : [];
|
|
1923
|
+
let start = 0;
|
|
1924
|
+
while (start < oldLines.length && start < newLines.length && oldLines[start] === newLines[start]) start++;
|
|
1925
|
+
let oldEnd = oldLines.length, newEnd = newLines.length;
|
|
1926
|
+
while (oldEnd > start && newEnd > start && oldLines[oldEnd - 1] === newLines[newEnd - 1]) {
|
|
1927
|
+
oldEnd--;
|
|
1928
|
+
newEnd--;
|
|
1929
|
+
}
|
|
1930
|
+
const lines = [
|
|
1931
|
+
`@@ -${start + 1},${oldEnd - start} +${start + 1},${newEnd - start} @@`,
|
|
1932
|
+
...oldLines.slice(Math.max(0, start - 3), start).map((line) => ` ${line}`),
|
|
1933
|
+
...oldLines.slice(start, oldEnd).map((line) => `-${line}`),
|
|
1934
|
+
...newLines.slice(start, newEnd).map((line) => `+${line}`),
|
|
1935
|
+
...newLines.slice(newEnd, newEnd + 3).map((line) => ` ${line}`)
|
|
1936
|
+
];
|
|
1937
|
+
const preview = lines.join("\n").replace(/[\x00-\x08\x0b-\x1f\x7f-\x9f]/g, "?");
|
|
1938
|
+
return preview.length > limit ? preview.slice(0, limit) + "\n\u2026 (preview truncated)" : preview;
|
|
1939
|
+
}
|
|
1940
|
+
|
|
1941
|
+
// src/disk-usage.ts
|
|
1942
|
+
var import_node_fs = require("fs");
|
|
1943
|
+
var import_node_path = require("path");
|
|
1944
|
+
async function scanDiskUsage(root, signal, allowPath) {
|
|
1945
|
+
if (!(await import_node_fs.promises.lstat(root)).isDirectory()) throw new Error("disk_usage requires a directory");
|
|
1946
|
+
const deadline = Date.now() + 15e3;
|
|
1947
|
+
const limit = 5e4;
|
|
1948
|
+
let scanned = 0;
|
|
1949
|
+
let skipped = 0;
|
|
1950
|
+
let incomplete = false;
|
|
1951
|
+
const measure = async (start) => {
|
|
1952
|
+
let bytes = 0;
|
|
1953
|
+
const pending = [start];
|
|
1954
|
+
while (pending.length) {
|
|
1955
|
+
if (signal?.aborted) throw new Error("Disk usage scan cancelled");
|
|
1956
|
+
if (scanned >= limit || Date.now() >= deadline) {
|
|
1957
|
+
incomplete = true;
|
|
1958
|
+
break;
|
|
1959
|
+
}
|
|
1960
|
+
const path = pending.pop();
|
|
1961
|
+
try {
|
|
1962
|
+
allowPath(path);
|
|
1963
|
+
const item = await import_node_fs.promises.lstat(path);
|
|
1964
|
+
scanned += 1;
|
|
1965
|
+
if (item.isSymbolicLink()) {
|
|
1966
|
+
skipped += 1;
|
|
1967
|
+
continue;
|
|
1968
|
+
}
|
|
1969
|
+
if (item.isDirectory()) {
|
|
1970
|
+
for await (const child of await import_node_fs.promises.opendir(path)) {
|
|
1971
|
+
if (pending.length + scanned >= limit || Date.now() >= deadline) {
|
|
1972
|
+
incomplete = true;
|
|
1973
|
+
break;
|
|
1974
|
+
}
|
|
1975
|
+
pending.push((0, import_node_path.join)(path, child.name));
|
|
1976
|
+
}
|
|
1977
|
+
} else if (item.isFile()) bytes += item.size;
|
|
1978
|
+
} catch {
|
|
1979
|
+
skipped += 1;
|
|
1980
|
+
}
|
|
1981
|
+
}
|
|
1982
|
+
return bytes;
|
|
1983
|
+
};
|
|
1984
|
+
const entries = [];
|
|
1985
|
+
for await (const child of await import_node_fs.promises.opendir(root)) {
|
|
1986
|
+
if (incomplete) break;
|
|
1987
|
+
if (child.isSymbolicLink()) {
|
|
1988
|
+
skipped += 1;
|
|
1989
|
+
continue;
|
|
1990
|
+
}
|
|
1991
|
+
const path = (0, import_node_path.join)(root, child.name);
|
|
1992
|
+
try {
|
|
1993
|
+
allowPath(path);
|
|
1994
|
+
} catch {
|
|
1995
|
+
skipped += 1;
|
|
1996
|
+
continue;
|
|
1997
|
+
}
|
|
1998
|
+
entries.push({ path: child.name, kind: child.isDirectory() ? "directory" : "file", sizeBytes: await measure(path) });
|
|
1999
|
+
}
|
|
2000
|
+
entries.sort((left, right) => right.sizeBytes - left.sizeBytes);
|
|
2001
|
+
return {
|
|
2002
|
+
scope: root,
|
|
2003
|
+
unit: "logical file bytes",
|
|
2004
|
+
entries: entries.slice(0, 30),
|
|
2005
|
+
scanned,
|
|
2006
|
+
skipped,
|
|
2007
|
+
incomplete,
|
|
2008
|
+
note: incomplete ? "The bounded scan stopped early. Sizes may be underestimates; narrow the path and scan again." : "Sizes cover this selected folder only, not the whole computer."
|
|
2009
|
+
};
|
|
2010
|
+
}
|
|
2011
|
+
|
|
2012
|
+
// src/office-text.ts
|
|
2013
|
+
var import_zlib = require("zlib");
|
|
2014
|
+
var MAX_ENTRY_BYTES = 4e7;
|
|
2015
|
+
function readEntries(buffer) {
|
|
2016
|
+
const floor = Math.max(0, buffer.length - 65557);
|
|
2017
|
+
let end = -1;
|
|
2018
|
+
for (let index = buffer.length - 22; index >= floor; index -= 1) {
|
|
2019
|
+
if (buffer.readUInt32LE(index) === 101010256) {
|
|
2020
|
+
end = index;
|
|
2021
|
+
break;
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
2024
|
+
if (end < 0) throw new Error("Not a zip archive");
|
|
2025
|
+
const count = buffer.readUInt16LE(end + 10);
|
|
2026
|
+
let cursor = buffer.readUInt32LE(end + 16);
|
|
2027
|
+
const entries = [];
|
|
2028
|
+
for (let index = 0; index < count && cursor + 46 <= buffer.length; index += 1) {
|
|
2029
|
+
if (buffer.readUInt32LE(cursor) !== 33639248) break;
|
|
2030
|
+
const method = buffer.readUInt16LE(cursor + 10);
|
|
2031
|
+
const compressedSize = buffer.readUInt32LE(cursor + 20);
|
|
2032
|
+
const nameLength = buffer.readUInt16LE(cursor + 28);
|
|
2033
|
+
const extraLength = buffer.readUInt16LE(cursor + 30);
|
|
2034
|
+
const commentLength = buffer.readUInt16LE(cursor + 32);
|
|
2035
|
+
const offset = buffer.readUInt32LE(cursor + 42);
|
|
2036
|
+
const name = buffer.toString("utf8", cursor + 46, cursor + 46 + nameLength);
|
|
2037
|
+
entries.push({ name, method, compressedSize, offset });
|
|
2038
|
+
cursor += 46 + nameLength + extraLength + commentLength;
|
|
2039
|
+
}
|
|
2040
|
+
return entries;
|
|
2041
|
+
}
|
|
2042
|
+
function readEntry(buffer, entry) {
|
|
2043
|
+
if (buffer.readUInt32LE(entry.offset) !== 67324752) throw new Error("Corrupt zip entry");
|
|
2044
|
+
const nameLength = buffer.readUInt16LE(entry.offset + 26);
|
|
2045
|
+
const extraLength = buffer.readUInt16LE(entry.offset + 28);
|
|
2046
|
+
const start = entry.offset + 30 + nameLength + extraLength;
|
|
2047
|
+
const data = buffer.subarray(start, start + entry.compressedSize);
|
|
2048
|
+
if (entry.method === 0) return data.toString("utf8");
|
|
2049
|
+
if (entry.method === 8) {
|
|
2050
|
+
return (0, import_zlib.inflateRawSync)(data, { maxOutputLength: MAX_ENTRY_BYTES }).toString("utf8");
|
|
2051
|
+
}
|
|
2052
|
+
throw new Error(`Unsupported zip compression method ${entry.method}`);
|
|
2053
|
+
}
|
|
2054
|
+
function decodeXml(value) {
|
|
2055
|
+
return value.replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/&#(\d+);/g, (_, code) => String.fromCodePoint(Number(code))).replace(/&#x([0-9a-f]+);/gi, (_, code) => String.fromCodePoint(parseInt(code, 16))).replace(/&/g, "&");
|
|
2056
|
+
}
|
|
2057
|
+
function docxText(xml) {
|
|
2058
|
+
const paragraphs = xml.match(/<w:p[\s>][\s\S]*?<\/w:p>/g) ?? [];
|
|
2059
|
+
const lines = paragraphs.map((paragraph) => {
|
|
2060
|
+
const style = /<w:pStyle w:val="([^"]+)"/.exec(paragraph)?.[1] ?? "";
|
|
2061
|
+
const heading = /^(?:Heading|heading)\s?(\d)$/.exec(style)?.[1] ?? (style === "Title" ? "1" : "");
|
|
2062
|
+
const listItem = /<w:numPr>/.test(paragraph);
|
|
2063
|
+
const text = paragraph.replace(/<w:tab\/>/g, " ").replace(/<w:(?:br|cr)\/>/g, "\n").match(/<w:t(?:\s[^>]*)?>[\s\S]*?<\/w:t>|\t|\n/g)?.map((part) => part === " " || part === "\n" ? part : decodeXml(part.replace(/<[^>]+>/g, ""))).join("") ?? "";
|
|
2064
|
+
if (!text.trim()) return "";
|
|
2065
|
+
if (heading) return `${"#".repeat(Math.min(6, Number(heading)))} ${text.trim()}`;
|
|
2066
|
+
return listItem ? `- ${text.trim()}` : text;
|
|
2067
|
+
});
|
|
2068
|
+
return lines.join("\n").replace(/\n{3,}/g, "\n\n").trim();
|
|
2069
|
+
}
|
|
2070
|
+
function drawingText(xml) {
|
|
2071
|
+
const paragraphs = xml.match(/<a:p[\s>][\s\S]*?<\/a:p>/g) ?? [];
|
|
2072
|
+
return paragraphs.map(
|
|
2073
|
+
(paragraph) => (paragraph.match(/<a:t>[\s\S]*?<\/a:t>/g) ?? []).map((part) => decodeXml(part.replace(/<[^>]+>/g, ""))).join("")
|
|
2074
|
+
).filter((line) => line.trim()).join("\n");
|
|
2075
|
+
}
|
|
2076
|
+
function slideNumber(name) {
|
|
2077
|
+
return Number(/(\d+)\.xml$/.exec(name)?.[1] ?? 0);
|
|
2078
|
+
}
|
|
2079
|
+
function extractOfficeOpenXmlText(buffer, extension) {
|
|
2080
|
+
let entries;
|
|
2081
|
+
try {
|
|
2082
|
+
entries = readEntries(buffer);
|
|
2083
|
+
} catch {
|
|
2084
|
+
return null;
|
|
2085
|
+
}
|
|
2086
|
+
const find = (name) => entries.find((entry) => entry.name === name);
|
|
2087
|
+
try {
|
|
2088
|
+
if (extension === ".docx") {
|
|
2089
|
+
const document = find("word/document.xml");
|
|
2090
|
+
return document ? docxText(readEntry(buffer, document)) : null;
|
|
2091
|
+
}
|
|
2092
|
+
if (extension === ".pptx") {
|
|
2093
|
+
const slides = entries.filter((entry) => /^ppt\/slides\/slide\d+\.xml$/.test(entry.name)).sort((left, right) => slideNumber(left.name) - slideNumber(right.name));
|
|
2094
|
+
if (!slides.length) return null;
|
|
2095
|
+
return slides.map((slide) => `## Slide ${slideNumber(slide.name)}
|
|
2096
|
+
${drawingText(readEntry(buffer, slide))}`).join("\n\n").trim();
|
|
2097
|
+
}
|
|
2098
|
+
if (extension === ".xlsx") {
|
|
2099
|
+
const shared = find("xl/sharedStrings.xml");
|
|
2100
|
+
const strings = shared ? (readEntry(buffer, shared).match(/<si>[\s\S]*?<\/si>/g) ?? []).map(
|
|
2101
|
+
(item) => (item.match(/<t(?:\s[^>]*)?>[\s\S]*?<\/t>/g) ?? []).map((part) => decodeXml(part.replace(/<[^>]+>/g, ""))).join("")
|
|
2102
|
+
) : [];
|
|
2103
|
+
const sheets = entries.filter((entry) => /^xl\/worksheets\/sheet\d+\.xml$/.test(entry.name)).sort((left, right) => slideNumber(left.name) - slideNumber(right.name));
|
|
2104
|
+
if (!sheets.length) return null;
|
|
2105
|
+
return sheets.map((sheet) => {
|
|
2106
|
+
const rows = (readEntry(buffer, sheet).match(/<row[\s\S]*?<\/row>/g) ?? []).slice(0, 2e3).map(
|
|
2107
|
+
(row) => (row.match(/<c[\s\S]*?<\/c>|<c[^>]*\/>/g) ?? []).map((cell) => {
|
|
2108
|
+
const value = /<v>([\s\S]*?)<\/v>/.exec(cell)?.[1] ?? /<t(?:\s[^>]*)?>([\s\S]*?)<\/t>/.exec(cell)?.[1] ?? "";
|
|
2109
|
+
return /\bt="s"/.test(cell) ? strings[Number(value)] ?? "" : decodeXml(value);
|
|
2110
|
+
}).join(" ")
|
|
2111
|
+
);
|
|
2112
|
+
return `## Sheet ${slideNumber(sheet.name)}
|
|
2113
|
+
${rows.join("\n")}`;
|
|
2114
|
+
}).join("\n\n").trim();
|
|
2115
|
+
}
|
|
2116
|
+
} catch {
|
|
2117
|
+
return null;
|
|
2118
|
+
}
|
|
2119
|
+
return null;
|
|
2120
|
+
}
|
|
2121
|
+
|
|
2122
|
+
// src/local-tools.ts
|
|
1911
2123
|
var pdfParse = require("pdf-parse/lib/pdf-parse.js");
|
|
1912
2124
|
var managedProcesses = /* @__PURE__ */ new Map();
|
|
2125
|
+
function stopProcessTree(proc) {
|
|
2126
|
+
const pid = proc.child.pid;
|
|
2127
|
+
if (!pid) return;
|
|
2128
|
+
if (process.platform === "win32") {
|
|
2129
|
+
const killer = (0, import_child_process2.spawn)("taskkill", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore", windowsHide: true });
|
|
2130
|
+
killer.on("error", () => proc.child.kill("SIGTERM"));
|
|
2131
|
+
} else {
|
|
2132
|
+
try {
|
|
2133
|
+
process.kill(-pid, "SIGTERM");
|
|
2134
|
+
} catch {
|
|
2135
|
+
proc.child.kill("SIGTERM");
|
|
2136
|
+
}
|
|
2137
|
+
}
|
|
2138
|
+
}
|
|
1913
2139
|
function capBuffer(existing, chunk, maxBytes) {
|
|
1914
2140
|
const joined = existing + chunk;
|
|
1915
2141
|
if (joined.length <= maxBytes) return joined;
|
|
@@ -1946,12 +2172,8 @@ function buildDirSnapshot(dir, maxDepth = 2) {
|
|
|
1946
2172
|
}
|
|
1947
2173
|
function readFileForContext(rootDir, filePath) {
|
|
1948
2174
|
try {
|
|
1949
|
-
const abs = (
|
|
1950
|
-
|
|
1951
|
-
if (rel.startsWith("..") || rel.startsWith("/")) return `[error: path escapes session root]`;
|
|
1952
|
-
for (const pat of [/\/\.ssh\//, /\/\.aws\//, /\/\.env$/, /\/\.env\./, /id_rsa/, /id_ed25519/]) {
|
|
1953
|
-
if (pat.test(abs)) return `[error: sensitive path blocked]`;
|
|
1954
|
-
}
|
|
2175
|
+
const abs = safePath(rootDir, filePath);
|
|
2176
|
+
assertNotSensitive(abs);
|
|
1955
2177
|
if (!(0, import_fs5.existsSync)(abs)) return `[error: file not found: ${filePath}]`;
|
|
1956
2178
|
const stat = (0, import_fs5.statSync)(abs);
|
|
1957
2179
|
if (stat.isDirectory()) return `[error: "${filePath}" is a directory \u2014 use list_directory]`;
|
|
@@ -1996,9 +2218,11 @@ ${fileSection}
|
|
|
1996
2218
|
| Tool | What it does |
|
|
1997
2219
|
|------|-------------|
|
|
1998
2220
|
| \`cli_list_directory\` | List files and folders at a path |
|
|
1999
|
-
| \`cli_read_file\` | Read a file (PDF and Word docs are extracted to text) |
|
|
2221
|
+
| \`cli_read_file\` | Read a bounded part of a file (PDF and Word docs are extracted to text) |
|
|
2222
|
+
| \`cli_search_file\` | Find passages and character offsets inside one large document |
|
|
2000
2223
|
| \`cli_write_file\` | Write or overwrite a file (user confirmation required) |
|
|
2001
2224
|
| \`cli_search_files\` | Find files matching a pattern |
|
|
2225
|
+
| \`cli_disk_usage\` | Measure and rank file and folder sizes inside the selected root (read only; bounded scan) |
|
|
2002
2226
|
| \`cli_run_command\` | Run a short command and return its output (user confirmation required) |
|
|
2003
2227
|
| \`cli_start_process\` | Start a long-running command in the background; returns a processId immediately |
|
|
2004
2228
|
| \`cli_wait_for_process\` | Block up to N seconds for a background process, then return current output |
|
|
@@ -2057,102 +2281,50 @@ function extractToolCall(text) {
|
|
|
2057
2281
|
}
|
|
2058
2282
|
return null;
|
|
2059
2283
|
}
|
|
2060
|
-
function injectAgcTrailer(command, args,
|
|
2284
|
+
function injectAgcTrailer(command, args, agentId3, agentName) {
|
|
2061
2285
|
if (command !== "git") return args;
|
|
2062
2286
|
if (!args.some((a) => a === "commit")) return args;
|
|
2063
2287
|
if (args.some((a) => a.includes("Co-Authored-By: agc"))) return args;
|
|
2064
|
-
const identity = agentName ? `${agentName} (agc)` :
|
|
2288
|
+
const identity = agentName ? `${agentName} (agc)` : agentId3 ? `agc/${agentId3}` : "agc agent";
|
|
2065
2289
|
return [...args, "--trailer", `Co-Authored-By: ${identity} <agc-agent@users.noreply.github.com>`];
|
|
2066
2290
|
}
|
|
2067
|
-
var AGC_HOOK_MARKER = "# agc-session:";
|
|
2068
|
-
var HOOK_BACKUP_SUFFIX = ".agc-backup";
|
|
2069
|
-
function findGitDir(rootDir) {
|
|
2070
|
-
const gitPath = (0, import_path3.join)(rootDir, ".git");
|
|
2071
|
-
if (!(0, import_fs5.existsSync)(gitPath)) return null;
|
|
2072
|
-
const s = (0, import_fs5.statSync)(gitPath);
|
|
2073
|
-
if (s.isDirectory()) return gitPath;
|
|
2074
|
-
if (s.isFile()) {
|
|
2075
|
-
const content = (0, import_fs5.readFileSync)(gitPath, "utf8");
|
|
2076
|
-
const match = content.match(/^gitdir:\s*(.+)$/m);
|
|
2077
|
-
if (match) return match[1].trim();
|
|
2078
|
-
}
|
|
2079
|
-
return null;
|
|
2080
|
-
}
|
|
2081
|
-
function installGitHook(rootDir, sessionId, agentId2, agentName) {
|
|
2082
|
-
const gitDir = findGitDir(rootDir);
|
|
2083
|
-
if (!gitDir) return;
|
|
2084
|
-
const hooksDir = (0, import_path3.join)(gitDir, "hooks");
|
|
2085
|
-
(0, import_fs5.mkdirSync)(hooksDir, { recursive: true });
|
|
2086
|
-
const hookPath = (0, import_path3.join)(hooksDir, "prepare-commit-msg");
|
|
2087
|
-
if ((0, import_fs5.existsSync)(hookPath)) {
|
|
2088
|
-
const existing = (0, import_fs5.readFileSync)(hookPath, "utf8");
|
|
2089
|
-
if (!existing.includes(AGC_HOOK_MARKER)) {
|
|
2090
|
-
(0, import_fs5.writeFileSync)(hookPath + HOOK_BACKUP_SUFFIX, existing, { mode: 493 });
|
|
2091
|
-
}
|
|
2092
|
-
}
|
|
2093
|
-
const identity = agentName ? `${agentName} (agc)` : agentId2 ? `agc/${agentId2}` : "agc agent";
|
|
2094
|
-
const trailer = `Co-Authored-By: ${identity} <agc-agent@users.noreply.github.com>`;
|
|
2095
|
-
const chainLine = (0, import_fs5.existsSync)(hookPath + HOOK_BACKUP_SUFFIX) ? `
|
|
2096
|
-
# chain pre-existing hook
|
|
2097
|
-
"$(dirname "$0")/prepare-commit-msg${HOOK_BACKUP_SUFFIX}" "$@" 2>/dev/null || true
|
|
2098
|
-
` : "";
|
|
2099
|
-
const hook = `#!/bin/sh
|
|
2100
|
-
${AGC_HOOK_MARKER}${sessionId}
|
|
2101
|
-
COMMIT_MSG_FILE="$1"
|
|
2102
|
-
COMMIT_SOURCE="$2"
|
|
2103
|
-
${chainLine}
|
|
2104
|
-
case "$COMMIT_SOURCE" in merge|squash) exit 0 ;; esac
|
|
2105
|
-
TRAILER="${trailer}"
|
|
2106
|
-
grep -qF "$TRAILER" "$COMMIT_MSG_FILE" 2>/dev/null && exit 0
|
|
2107
|
-
printf '\\n%s\\n' "$TRAILER" >> "$COMMIT_MSG_FILE"
|
|
2108
|
-
`;
|
|
2109
|
-
(0, import_fs5.writeFileSync)(hookPath, hook, { mode: 493 });
|
|
2110
|
-
}
|
|
2111
|
-
function removeGitHook(rootDir) {
|
|
2112
|
-
const gitDir = findGitDir(rootDir);
|
|
2113
|
-
if (!gitDir) return;
|
|
2114
|
-
const hookPath = (0, import_path3.join)(gitDir, "hooks", "prepare-commit-msg");
|
|
2115
|
-
if (!(0, import_fs5.existsSync)(hookPath)) return;
|
|
2116
|
-
const content = (0, import_fs5.readFileSync)(hookPath, "utf8");
|
|
2117
|
-
if (!content.includes(AGC_HOOK_MARKER)) return;
|
|
2118
|
-
const backupPath = hookPath + HOOK_BACKUP_SUFFIX;
|
|
2119
|
-
if ((0, import_fs5.existsSync)(backupPath)) {
|
|
2120
|
-
(0, import_fs5.writeFileSync)(hookPath, (0, import_fs5.readFileSync)(backupPath, "utf8"), { mode: 493 });
|
|
2121
|
-
(0, import_fs5.unlinkSync)(backupPath);
|
|
2122
|
-
} else {
|
|
2123
|
-
(0, import_fs5.unlinkSync)(hookPath);
|
|
2124
|
-
}
|
|
2125
|
-
}
|
|
2126
2291
|
function safePath(root, userPath) {
|
|
2127
|
-
const
|
|
2128
|
-
const
|
|
2129
|
-
|
|
2130
|
-
|
|
2292
|
+
const canonicalRoot = (0, import_fs5.realpathSync)(root);
|
|
2293
|
+
const abs = (0, import_path3.resolve)(canonicalRoot, userPath);
|
|
2294
|
+
const inside = (path) => {
|
|
2295
|
+
const rel = (0, import_path3.relative)(canonicalRoot, path);
|
|
2296
|
+
return rel !== ".." && !rel.startsWith(`..${import_path3.sep}`) && !(0, import_path3.isAbsolute)(rel);
|
|
2297
|
+
};
|
|
2298
|
+
if (!inside(abs) && !(0, import_path3.isAbsolute)(userPath)) throw new Error(`Path "${userPath}" escapes the session root. Access denied.`);
|
|
2299
|
+
let ancestor = abs;
|
|
2300
|
+
while (!(0, import_fs5.existsSync)(ancestor)) {
|
|
2301
|
+
try {
|
|
2302
|
+
if ((0, import_fs5.lstatSync)(ancestor).isSymbolicLink()) throw new Error("Dangling symlink is not allowed.");
|
|
2303
|
+
} catch (error) {
|
|
2304
|
+
if (error.code !== "ENOENT") throw error;
|
|
2305
|
+
}
|
|
2306
|
+
const parent = (0, import_path3.dirname)(ancestor);
|
|
2307
|
+
if (parent === ancestor) throw new Error("Cannot resolve path.");
|
|
2308
|
+
ancestor = parent;
|
|
2131
2309
|
}
|
|
2132
|
-
|
|
2310
|
+
const canonicalAncestor = (0, import_fs5.realpathSync)(ancestor);
|
|
2311
|
+
if (!inside(canonicalAncestor)) throw new Error(`Path "${userPath}" resolves outside the session root. Access denied.`);
|
|
2312
|
+
assertNotSensitive(abs);
|
|
2313
|
+
assertNotSensitive(canonicalAncestor);
|
|
2314
|
+
return (0, import_path3.resolve)(canonicalAncestor, (0, import_path3.relative)(ancestor, abs));
|
|
2133
2315
|
}
|
|
2134
|
-
var BLOCKED_PATTERNS = [
|
|
2135
|
-
/\/\.ssh\//,
|
|
2136
|
-
/\/\.gnupg\//,
|
|
2137
|
-
/\/\.agc\//,
|
|
2138
|
-
/\/\.aws\//,
|
|
2139
|
-
/\/\.env$/,
|
|
2140
|
-
/\/\.env\./,
|
|
2141
|
-
/id_rsa/,
|
|
2142
|
-
/id_ed25519/
|
|
2143
|
-
];
|
|
2144
2316
|
function assertNotSensitive(abs) {
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
}
|
|
2317
|
+
const segments = abs.split(/[\\/]/);
|
|
2318
|
+
if (segments.some((part) => /^(?:\.ssh|\.gnupg|\.agc|\.aws|\.env(?:\..*)?|id_rsa|id_ed25519)$/i.test(part))) {
|
|
2319
|
+
throw new Error(`Access to "${abs}" is blocked for security reasons.`);
|
|
2149
2320
|
}
|
|
2150
2321
|
}
|
|
2151
2322
|
async function confirm(message, config, permissionKey) {
|
|
2152
|
-
if (config.autoApprove) return true;
|
|
2153
2323
|
const cached = config.permissions.get(permissionKey);
|
|
2154
2324
|
if (cached === "allow") return true;
|
|
2155
2325
|
if (cached === "deny") return false;
|
|
2326
|
+
if (config.autoApprove) return true;
|
|
2327
|
+
if (config.confirm) return config.confirm(message, permissionKey);
|
|
2156
2328
|
return new Promise((resolve2) => {
|
|
2157
2329
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
2158
2330
|
process.stdout.write(
|
|
@@ -2161,22 +2333,23 @@ async function confirm(message, config, permissionKey) {
|
|
|
2161
2333
|
\x1B[2m[y] Yes [n] No [A] Always allow this type [N] Never allow this type\x1B[0m
|
|
2162
2334
|
\x1B[36m?\x1B[0m `
|
|
2163
2335
|
);
|
|
2336
|
+
rl.once("close", () => resolve2(false));
|
|
2164
2337
|
rl.once("line", (answer) => {
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
if (a === "a") {
|
|
2338
|
+
const a = answer.trim();
|
|
2339
|
+
if (a === "A") {
|
|
2168
2340
|
config.permissions.set(permissionKey, "allow");
|
|
2169
2341
|
resolve2(true);
|
|
2170
|
-
} else if (a === "
|
|
2342
|
+
} else if (a === "N") {
|
|
2171
2343
|
config.permissions.set(permissionKey, "deny");
|
|
2172
2344
|
resolve2(false);
|
|
2173
2345
|
} else {
|
|
2174
|
-
resolve2(a === "y" || a === "yes"
|
|
2346
|
+
resolve2(a.toLowerCase() === "y" || a.toLowerCase() === "yes");
|
|
2175
2347
|
}
|
|
2348
|
+
rl.close();
|
|
2176
2349
|
});
|
|
2177
2350
|
});
|
|
2178
2351
|
}
|
|
2179
|
-
var OFFICE_EXTS = /* @__PURE__ */ new Set([".docx", ".doc", ".rtf", ".odt", ".pages"]);
|
|
2352
|
+
var OFFICE_EXTS = /* @__PURE__ */ new Set([".docx", ".doc", ".rtf", ".odt", ".pages", ".pptx", ".xlsx"]);
|
|
2180
2353
|
var PDF_EXTS = /* @__PURE__ */ new Set([".pdf"]);
|
|
2181
2354
|
var UNREADABLE_BINARY_EXTS = /* @__PURE__ */ new Set([
|
|
2182
2355
|
".png",
|
|
@@ -2208,9 +2381,7 @@ var UNREADABLE_BINARY_EXTS = /* @__PURE__ */ new Set([
|
|
|
2208
2381
|
".ai",
|
|
2209
2382
|
".sketch",
|
|
2210
2383
|
".figma",
|
|
2211
|
-
".xlsx",
|
|
2212
2384
|
".xls",
|
|
2213
|
-
".pptx",
|
|
2214
2385
|
".ppt"
|
|
2215
2386
|
]);
|
|
2216
2387
|
function extractViaCommand(cmd, cmdArgs) {
|
|
@@ -2221,17 +2392,16 @@ function extractViaCommand(cmd, cmdArgs) {
|
|
|
2221
2392
|
});
|
|
2222
2393
|
});
|
|
2223
2394
|
}
|
|
2224
|
-
async function extractPdfText(abs) {
|
|
2395
|
+
async function extractPdfText(abs, maxChars = 15e4) {
|
|
2225
2396
|
try {
|
|
2226
2397
|
const buffer = (0, import_fs5.readFileSync)(abs);
|
|
2227
2398
|
const data = await pdfParse(buffer);
|
|
2228
2399
|
const text2 = data.text?.trim();
|
|
2229
2400
|
if (text2) {
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
return text2.slice(0, MAX_CHARS) + `
|
|
2401
|
+
if (text2.length > maxChars) {
|
|
2402
|
+
return text2.slice(0, maxChars) + `
|
|
2233
2403
|
|
|
2234
|
-
[\u2026truncated \u2014 showing first ${
|
|
2404
|
+
[\u2026truncated \u2014 showing first ${maxChars.toLocaleString()} characters of ${text2.length.toLocaleString()} total]`;
|
|
2235
2405
|
}
|
|
2236
2406
|
return text2;
|
|
2237
2407
|
}
|
|
@@ -2242,47 +2412,129 @@ async function extractPdfText(abs) {
|
|
|
2242
2412
|
return `[Cannot extract PDF text: the file may be scanned/image-only or password-protected]`;
|
|
2243
2413
|
}
|
|
2244
2414
|
async function extractOfficeText(abs, ext) {
|
|
2415
|
+
const openXml = extractOfficeOpenXmlText((0, import_fs5.readFileSync)(abs), ext);
|
|
2416
|
+
if (openXml) return openXml;
|
|
2245
2417
|
const text = await extractViaCommand("textutil", ["-stdout", "-cat", "txt", abs]);
|
|
2246
2418
|
if (text) return text;
|
|
2247
|
-
return `[Cannot extract ${ext} text:
|
|
2419
|
+
return `[Cannot extract ${ext} text: this document format is not supported on this system]`;
|
|
2420
|
+
}
|
|
2421
|
+
var documentTextCache = /* @__PURE__ */ new Map();
|
|
2422
|
+
async function cachedDocumentText(abs, stat, ext) {
|
|
2423
|
+
const cached = documentTextCache.get(abs);
|
|
2424
|
+
if (cached?.size === stat.size && cached.mtimeMs === stat.mtimeMs) return cached.text;
|
|
2425
|
+
const text = PDF_EXTS.has(ext) ? await extractPdfText(abs, Number.MAX_SAFE_INTEGER) : await extractOfficeText(abs, ext);
|
|
2426
|
+
documentTextCache.delete(abs);
|
|
2427
|
+
if (text.length <= 2e6) documentTextCache.set(abs, { size: stat.size, mtimeMs: stat.mtimeMs, text });
|
|
2428
|
+
while (documentTextCache.size > 4) documentTextCache.delete(documentTextCache.keys().next().value);
|
|
2429
|
+
return text;
|
|
2248
2430
|
}
|
|
2249
2431
|
async function toolReadFile(args, cfg) {
|
|
2250
2432
|
const { path: userPath } = args;
|
|
2251
2433
|
if (!userPath) throw new Error('read_file requires a "path" argument');
|
|
2252
2434
|
const abs = safePath(cfg.rootDir, userPath);
|
|
2253
2435
|
assertNotSensitive(abs);
|
|
2254
|
-
if (!(0, import_fs5.existsSync)(abs)) throw new Error(`File not found: ${userPath}
|
|
2436
|
+
if (!(0, import_fs5.existsSync)(abs)) throw new Error(`File not found: ${userPath} (resolved to ${abs}). List the parent directory and use a path relative to the selected workspace root: ${cfg.rootDir}.`);
|
|
2255
2437
|
const stat = (0, import_fs5.statSync)(abs);
|
|
2256
2438
|
if (stat.isDirectory()) throw new Error(`"${userPath}" is a directory, not a file`);
|
|
2257
2439
|
const ext = (0, import_path3.extname)(abs).toLowerCase();
|
|
2258
2440
|
if (PDF_EXTS.has(ext)) {
|
|
2259
2441
|
if (stat.size > 5e7) throw new Error(`PDF too large to read (${Math.round(stat.size / 1e6)} MB). Max 50 MB.`);
|
|
2260
|
-
return
|
|
2442
|
+
return pageFileText(await cachedDocumentText(abs, stat, ext), args.offset, userPath, true);
|
|
2261
2443
|
}
|
|
2262
2444
|
if (OFFICE_EXTS.has(ext)) {
|
|
2263
2445
|
if (stat.size > 2e7) throw new Error(`Document too large to read (${Math.round(stat.size / 1e6)} MB). Max 20 MB.`);
|
|
2264
|
-
return
|
|
2446
|
+
return pageFileText(await cachedDocumentText(abs, stat, ext), args.offset, userPath, true);
|
|
2265
2447
|
}
|
|
2266
2448
|
if (UNREADABLE_BINARY_EXTS.has(ext)) {
|
|
2267
2449
|
throw new Error(`Cannot read binary file "${userPath}" (${ext} format). Only text, PDF, and Office documents are supported.`);
|
|
2268
2450
|
}
|
|
2269
2451
|
if (stat.size > 5e5) throw new Error(`File too large to read (${Math.round(stat.size / 1024)} KB). Max 500 KB.`);
|
|
2270
|
-
return (0, import_fs5.readFileSync)(abs, "utf8");
|
|
2452
|
+
return pageFileText((0, import_fs5.readFileSync)(abs, "utf8"), args.offset, userPath, false);
|
|
2453
|
+
}
|
|
2454
|
+
async function toolSearchFile(args, cfg) {
|
|
2455
|
+
const path = String(args.path ?? "").trim();
|
|
2456
|
+
const query = String(args.query ?? "").trim().slice(0, 120);
|
|
2457
|
+
if (!path || !query) throw new Error("search_file requires a path and search query");
|
|
2458
|
+
const abs = safePath(cfg.rootDir, path);
|
|
2459
|
+
assertNotSensitive(abs);
|
|
2460
|
+
if (!(0, import_fs5.existsSync)(abs)) throw new Error(`File not found: ${path}`);
|
|
2461
|
+
const stat = (0, import_fs5.statSync)(abs);
|
|
2462
|
+
if (!stat.isFile()) throw new Error(`"${path}" is not a file`);
|
|
2463
|
+
const ext = (0, import_path3.extname)(abs).toLowerCase();
|
|
2464
|
+
if (PDF_EXTS.has(ext) && stat.size > 5e7) throw new Error("PDF exceeds the 50 MB Local read limit");
|
|
2465
|
+
if (OFFICE_EXTS.has(ext) && stat.size > 2e7) throw new Error("Document exceeds the 20 MB Local read limit");
|
|
2466
|
+
if (UNREADABLE_BINARY_EXTS.has(ext)) throw new Error(`Cannot search binary file "${path}"`);
|
|
2467
|
+
if (!PDF_EXTS.has(ext) && !OFFICE_EXTS.has(ext) && stat.size > 5e5) throw new Error("Text file exceeds the 500 KB Local read limit");
|
|
2468
|
+
const text = PDF_EXTS.has(ext) || OFFICE_EXTS.has(ext) ? await cachedDocumentText(abs, stat, ext) : (0, import_fs5.readFileSync)(abs, "utf8");
|
|
2469
|
+
return JSON.stringify(searchTextPassages(text, path, query, "Use cli_read_file with a matching offset for more context."));
|
|
2470
|
+
}
|
|
2471
|
+
function searchTextPassages(text, path, rawQuery, hint) {
|
|
2472
|
+
const query = rawQuery.trim().slice(0, 120);
|
|
2473
|
+
if (!query) throw new Error("A search query is required");
|
|
2474
|
+
const lower = text.toLowerCase();
|
|
2475
|
+
const phrase = query.toLowerCase();
|
|
2476
|
+
const terms = [...new Set(phrase.match(/[\p{L}\p{N}]{3,}/gu) ?? [])].slice(0, 8);
|
|
2477
|
+
const positions = [];
|
|
2478
|
+
const collect2 = (needle) => {
|
|
2479
|
+
let offset = 0;
|
|
2480
|
+
while (positions.length < 5e3) {
|
|
2481
|
+
const found = lower.indexOf(needle, offset);
|
|
2482
|
+
if (found < 0) break;
|
|
2483
|
+
positions.push(found);
|
|
2484
|
+
offset = found + Math.max(needle.length, 1);
|
|
2485
|
+
}
|
|
2486
|
+
};
|
|
2487
|
+
collect2(phrase);
|
|
2488
|
+
if (!positions.length) for (const term of terms) collect2(term);
|
|
2489
|
+
const ranked = positions.map((offset) => {
|
|
2490
|
+
const start = Math.max(0, offset - 180);
|
|
2491
|
+
const end = Math.min(text.length, offset + 320);
|
|
2492
|
+
const excerpt = text.slice(start, end).replace(/\s+/g, " ").trim();
|
|
2493
|
+
const score = terms.filter((term) => excerpt.toLowerCase().includes(term)).length;
|
|
2494
|
+
return { offset, score, excerpt };
|
|
2495
|
+
}).sort((a, b) => b.score - a.score || b.offset - a.offset);
|
|
2496
|
+
const selected = [];
|
|
2497
|
+
for (const match of ranked) {
|
|
2498
|
+
if (selected.some((entry) => Math.abs(entry.offset - match.offset) < 250)) continue;
|
|
2499
|
+
selected.push(match);
|
|
2500
|
+
if (selected.length >= 8) break;
|
|
2501
|
+
}
|
|
2502
|
+
return { path, query, totalChars: text.length, matches: selected.map(({ offset, excerpt }) => ({ offset, excerpt })), hint };
|
|
2503
|
+
}
|
|
2504
|
+
function pageFileText(text, rawOffset, path, includeTail) {
|
|
2505
|
+
const offset = rawOffset === void 0 ? 0 : Number(rawOffset);
|
|
2506
|
+
if (!Number.isSafeInteger(offset) || offset < 0 || offset > text.length) throw new Error("read_file offset must be a character position within the file");
|
|
2507
|
+
if (offset === 0 && text.length <= 7e3) return text;
|
|
2508
|
+
const end = Math.min(text.length, offset + 6e3);
|
|
2509
|
+
const next = end < text.length ? ` Use cli_read_file with path ${JSON.stringify(path)} and offset ${end} to continue.` : "";
|
|
2510
|
+
const tail = includeTail && offset === 0 && end < text.length - 1500 ? `
|
|
2511
|
+
|
|
2512
|
+
[Final 1,500 characters of document]
|
|
2513
|
+
${text.slice(-1500)}` : "";
|
|
2514
|
+
return `[Showing characters ${offset}-${end} of ${text.length}.${next}]
|
|
2515
|
+
${text.slice(offset, end)}${tail}`;
|
|
2271
2516
|
}
|
|
2272
2517
|
async function toolWriteFile(args, cfg) {
|
|
2273
2518
|
const { path: userPath, content } = args;
|
|
2274
2519
|
if (!userPath) throw new Error('write_file requires a "path" argument');
|
|
2275
|
-
if (content
|
|
2520
|
+
if (typeof content !== "string") throw new Error('write_file requires a string "content" argument');
|
|
2276
2521
|
const abs = safePath(cfg.rootDir, userPath);
|
|
2277
2522
|
assertNotSensitive(abs);
|
|
2523
|
+
const before = (0, import_fs5.existsSync)(abs) ? (0, import_fs5.readFileSync)(abs, "utf8") : "";
|
|
2524
|
+
const preview = editPreview(before, content);
|
|
2278
2525
|
const ok = await confirm(
|
|
2279
|
-
`Agent wants to write file: \x1B[1m${abs}\x1B[0m (${String(content).length} chars)
|
|
2526
|
+
`Agent wants to write file: \x1B[1m${abs}\x1B[0m (${String(content).length} chars)
|
|
2527
|
+
${preview}`,
|
|
2280
2528
|
cfg,
|
|
2281
2529
|
"write_file"
|
|
2282
2530
|
);
|
|
2283
2531
|
if (!ok) return "User denied write operation.";
|
|
2284
|
-
|
|
2285
|
-
(0, import_fs5.
|
|
2532
|
+
const checked = safePath(cfg.rootDir, userPath);
|
|
2533
|
+
if (((0, import_fs5.existsSync)(checked) ? (0, import_fs5.readFileSync)(checked, "utf8") : "") !== before) {
|
|
2534
|
+
return "Error: file changed during approval. Read it again before retrying.";
|
|
2535
|
+
}
|
|
2536
|
+
(0, import_fs5.mkdirSync)((0, import_path3.dirname)(checked), { recursive: true });
|
|
2537
|
+
(0, import_fs5.writeFileSync)(checked, content, "utf8");
|
|
2286
2538
|
return `Written ${String(content).length} bytes to ${userPath}`;
|
|
2287
2539
|
}
|
|
2288
2540
|
async function toolListDirectory(args, cfg) {
|
|
@@ -2297,6 +2549,10 @@ async function toolListDirectory(args, cfg) {
|
|
|
2297
2549
|
});
|
|
2298
2550
|
return lines.join("\n") || "(empty directory)";
|
|
2299
2551
|
}
|
|
2552
|
+
async function toolDiskUsage(args, cfg) {
|
|
2553
|
+
const root = safePath(cfg.rootDir, String(args.path ?? "."));
|
|
2554
|
+
return JSON.stringify(await scanDiskUsage(root, cfg.signal, assertNotSensitive));
|
|
2555
|
+
}
|
|
2300
2556
|
async function toolSearchFiles(args, cfg) {
|
|
2301
2557
|
const { pattern, directory } = args;
|
|
2302
2558
|
if (!pattern) throw new Error('search_files requires a "pattern" argument');
|
|
@@ -2356,9 +2612,10 @@ async function toolRunCommand(args, cfg) {
|
|
|
2356
2612
|
});
|
|
2357
2613
|
}
|
|
2358
2614
|
return new Promise((resolve2) => {
|
|
2359
|
-
(0, import_child_process2.execFile)(command, injectedArgs.map(String), { cwd: workDir, timeout: timeoutMs, maxBuffer: 1024 * 1024 }, (err, stdout, stderr) => {
|
|
2615
|
+
(0, import_child_process2.execFile)(command, injectedArgs.map(String), { cwd: workDir, timeout: timeoutMs, maxBuffer: 1024 * 1024, signal: cfg.signal }, (err, stdout, stderr) => {
|
|
2360
2616
|
const out = [stdout, stderr].filter(Boolean).join("\n--- stderr ---\n");
|
|
2361
|
-
if (err
|
|
2617
|
+
if (err) return resolve2(`Error: command failed (${err.code ?? "unknown"}): ${err.message}
|
|
2618
|
+
${out}`);
|
|
2362
2619
|
resolve2(out || "(no output)");
|
|
2363
2620
|
});
|
|
2364
2621
|
});
|
|
@@ -2376,11 +2633,14 @@ async function toolStartProcess(args, cfg) {
|
|
|
2376
2633
|
"start_process"
|
|
2377
2634
|
);
|
|
2378
2635
|
if (!ok) return JSON.stringify({ error: "User denied process start." });
|
|
2379
|
-
const
|
|
2636
|
+
const finished = [...managedProcesses.values()].filter((proc2) => proc2.status !== "running");
|
|
2637
|
+
for (const proc2 of finished.slice(0, Math.max(0, finished.length - 99))) managedProcesses.delete(proc2.id);
|
|
2638
|
+
const id = `proc_${(0, import_crypto.randomUUID)()}`;
|
|
2380
2639
|
const child = (0, import_child_process2.spawn)(command, cmdArgs.map(String), {
|
|
2381
2640
|
cwd: workDir,
|
|
2382
2641
|
stdio: ["ignore", "pipe", "pipe"],
|
|
2383
|
-
detached:
|
|
2642
|
+
detached: process.platform !== "win32",
|
|
2643
|
+
windowsHide: true
|
|
2384
2644
|
});
|
|
2385
2645
|
const proc = {
|
|
2386
2646
|
id,
|
|
@@ -2393,6 +2653,10 @@ async function toolStartProcess(args, cfg) {
|
|
|
2393
2653
|
endedAt: null,
|
|
2394
2654
|
child
|
|
2395
2655
|
};
|
|
2656
|
+
if (cfg.signal) {
|
|
2657
|
+
if (cfg.signal.aborted) stopProcessTree(proc);
|
|
2658
|
+
else cfg.signal.addEventListener("abort", () => stopProcessTree(proc), { once: true });
|
|
2659
|
+
}
|
|
2396
2660
|
child.stdout?.on("data", (chunk) => {
|
|
2397
2661
|
proc.stdout = capBuffer(proc.stdout, chunk.toString(), 2e5);
|
|
2398
2662
|
});
|
|
@@ -2400,7 +2664,7 @@ async function toolStartProcess(args, cfg) {
|
|
|
2400
2664
|
proc.stderr = capBuffer(proc.stderr, chunk.toString(), 5e4);
|
|
2401
2665
|
});
|
|
2402
2666
|
child.on("close", (code) => {
|
|
2403
|
-
proc.status = code === 0 ? "done" : "error";
|
|
2667
|
+
if (proc.status !== "killed") proc.status = code === 0 ? "done" : "error";
|
|
2404
2668
|
proc.exitCode = code;
|
|
2405
2669
|
proc.endedAt = /* @__PURE__ */ new Date();
|
|
2406
2670
|
});
|
|
@@ -2440,7 +2704,8 @@ async function toolWaitForProcess(args, _cfg) {
|
|
|
2440
2704
|
const proc = managedProcesses.get(processId);
|
|
2441
2705
|
if (!proc) return JSON.stringify({ error: `No process found with id "${processId}"` });
|
|
2442
2706
|
if (proc.status !== "running") return processSnapshot(proc);
|
|
2443
|
-
const
|
|
2707
|
+
const requested = typeof wait_seconds === "number" && Number.isFinite(wait_seconds) ? wait_seconds : 60;
|
|
2708
|
+
const maxWait = Math.max(0, Math.min(requested, 60)) * 1e3;
|
|
2444
2709
|
const deadline = Date.now() + maxWait;
|
|
2445
2710
|
await new Promise((resolve2) => {
|
|
2446
2711
|
const tick = setInterval(() => {
|
|
@@ -2458,7 +2723,7 @@ async function toolKillProcess(args, cfg) {
|
|
|
2458
2723
|
const proc = managedProcesses.get(processId);
|
|
2459
2724
|
if (!proc) return JSON.stringify({ error: `No process found with id "${processId}"` });
|
|
2460
2725
|
if (proc.status !== "running") return JSON.stringify({ error: `Process "${processId}" is not running (status: ${proc.status})` });
|
|
2461
|
-
proc
|
|
2726
|
+
stopProcessTree(proc);
|
|
2462
2727
|
proc.status = "killed";
|
|
2463
2728
|
proc.endedAt = /* @__PURE__ */ new Date();
|
|
2464
2729
|
cfg.appendLog({ type: "process_killed", processId, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
@@ -2474,6 +2739,15 @@ async function toolListProcesses(_args, _cfg) {
|
|
|
2474
2739
|
}));
|
|
2475
2740
|
return JSON.stringify(list);
|
|
2476
2741
|
}
|
|
2742
|
+
function stopLocalProcesses() {
|
|
2743
|
+
for (const proc of managedProcesses.values()) {
|
|
2744
|
+
if (proc.status === "running") {
|
|
2745
|
+
stopProcessTree(proc);
|
|
2746
|
+
proc.status = "killed";
|
|
2747
|
+
proc.endedAt = /* @__PURE__ */ new Date();
|
|
2748
|
+
}
|
|
2749
|
+
}
|
|
2750
|
+
}
|
|
2477
2751
|
async function runLocalTool(call, cfg) {
|
|
2478
2752
|
const { tool, args } = call;
|
|
2479
2753
|
cfg.appendLog({
|
|
@@ -2488,6 +2762,9 @@ async function runLocalTool(call, cfg) {
|
|
|
2488
2762
|
case "read_file":
|
|
2489
2763
|
result = await toolReadFile(args, cfg);
|
|
2490
2764
|
break;
|
|
2765
|
+
case "search_file":
|
|
2766
|
+
result = await toolSearchFile(args, cfg);
|
|
2767
|
+
break;
|
|
2491
2768
|
case "write_file":
|
|
2492
2769
|
result = await toolWriteFile(args, cfg);
|
|
2493
2770
|
break;
|
|
@@ -2497,6 +2774,9 @@ async function runLocalTool(call, cfg) {
|
|
|
2497
2774
|
case "search_files":
|
|
2498
2775
|
result = await toolSearchFiles(args, cfg);
|
|
2499
2776
|
break;
|
|
2777
|
+
case "disk_usage":
|
|
2778
|
+
result = await toolDiskUsage(args, cfg);
|
|
2779
|
+
break;
|
|
2500
2780
|
case "run_command":
|
|
2501
2781
|
result = await toolRunCommand(args, cfg);
|
|
2502
2782
|
break;
|
|
@@ -2516,7 +2796,7 @@ async function runLocalTool(call, cfg) {
|
|
|
2516
2796
|
result = await toolListProcesses(args, cfg);
|
|
2517
2797
|
break;
|
|
2518
2798
|
default:
|
|
2519
|
-
result = `Unknown tool: "${tool}". Available: read_file, write_file, list_directory, search_files, run_command, start_process, wait_for_process, process_status, kill_process, list_processes`;
|
|
2799
|
+
result = `Unknown tool: "${tool}". Available: read_file, search_file, write_file, list_directory, search_files, disk_usage, run_command, start_process, wait_for_process, process_status, kill_process, list_processes`;
|
|
2520
2800
|
}
|
|
2521
2801
|
} catch (err) {
|
|
2522
2802
|
result = `Error: ${err?.message ?? String(err)}`;
|
|
@@ -2533,19 +2813,72 @@ async function runLocalTool(call, cfg) {
|
|
|
2533
2813
|
|
|
2534
2814
|
// src/commands/run.ts
|
|
2535
2815
|
function runCommand() {
|
|
2536
|
-
|
|
2816
|
+
const append = (value, previous) => [...previous, value];
|
|
2817
|
+
return new import_commander8.Command("run").description("Send a single prompt to an agent and stream the response").argument("<prompt>", "Prompt text to send").option("--agent <agentId>", "Agent ID").option("--file <path>", "Upload and attach a file (repeatable, up to 25 MB each)", append, []).option("--attach <fileId>", "Attach an existing Library file ID (repeatable)", append, []).option("--session <sessionId>", "Resume an existing session by ID").option(
|
|
2818
|
+
"--new-session",
|
|
2819
|
+
"Create a new session and print its ID for future use"
|
|
2820
|
+
).option(
|
|
2821
|
+
"--computer",
|
|
2822
|
+
"Give the agent access to its persistent cloud computer"
|
|
2823
|
+
).option(
|
|
2824
|
+
"--local",
|
|
2825
|
+
"Enable local file system access (with permission prompts)"
|
|
2826
|
+
).option(
|
|
2827
|
+
"-y, --yes",
|
|
2828
|
+
"Enable local file system access and auto-approve all operations"
|
|
2829
|
+
).option("--no-stream", "Disable streaming (wait for full response)").option("--json", "Output raw event stream as JSON lines").option(
|
|
2830
|
+
"--provenance <mode>",
|
|
2831
|
+
"Provenance capture: off, metadata, or full",
|
|
2832
|
+
"metadata"
|
|
2833
|
+
).option(
|
|
2834
|
+
"--onchain-provenance",
|
|
2835
|
+
"Request an optional on-chain anchor for this run"
|
|
2836
|
+
).action(async (prompt, opts) => {
|
|
2537
2837
|
const cfg = loadConfig();
|
|
2538
|
-
const
|
|
2539
|
-
if (!
|
|
2540
|
-
console.error(
|
|
2838
|
+
const agentId3 = opts.agent ?? cfg.defaultAgentId;
|
|
2839
|
+
if (!agentId3) {
|
|
2840
|
+
console.error(
|
|
2841
|
+
c.error(
|
|
2842
|
+
"Specify --agent <agentId> or set defaultAgentId with `agc config set defaultAgentId <id>`"
|
|
2843
|
+
)
|
|
2844
|
+
);
|
|
2541
2845
|
process.exit(1);
|
|
2542
2846
|
}
|
|
2543
2847
|
if (opts.session && opts.newSession) {
|
|
2544
|
-
console.error(
|
|
2848
|
+
console.error(
|
|
2849
|
+
c.error("Cannot use --session and --new-session together.")
|
|
2850
|
+
);
|
|
2851
|
+
process.exit(1);
|
|
2852
|
+
}
|
|
2853
|
+
if (!["off", "metadata", "full"].includes(opts.provenance)) {
|
|
2854
|
+
console.error(c.error("--provenance must be off, metadata, or full."));
|
|
2855
|
+
process.exit(1);
|
|
2856
|
+
}
|
|
2857
|
+
if (opts.onchainProvenance && opts.provenance === "off") {
|
|
2858
|
+
console.error(
|
|
2859
|
+
c.error("--onchain-provenance requires metadata or full capture.")
|
|
2860
|
+
);
|
|
2545
2861
|
process.exit(1);
|
|
2546
2862
|
}
|
|
2547
2863
|
const client = makeClient();
|
|
2548
2864
|
let sessionId = opts.session;
|
|
2865
|
+
const filePaths = opts.file;
|
|
2866
|
+
const attachmentIds = opts.attach;
|
|
2867
|
+
if (filePaths.length + attachmentIds.length > 10) {
|
|
2868
|
+
console.error(c.error("Attach no more than 10 files to a run."));
|
|
2869
|
+
process.exit(1);
|
|
2870
|
+
}
|
|
2871
|
+
try {
|
|
2872
|
+
for (const path of filePaths) {
|
|
2873
|
+
const stat = (0, import_fs6.statSync)(path);
|
|
2874
|
+
if (!stat.isFile() || stat.size < 1 || stat.size > 25 * 1024 * 1024) {
|
|
2875
|
+
throw new Error(`Choose a non-empty file up to 25 MB: ${path}`);
|
|
2876
|
+
}
|
|
2877
|
+
}
|
|
2878
|
+
} catch (error) {
|
|
2879
|
+
printError(error);
|
|
2880
|
+
process.exit(1);
|
|
2881
|
+
}
|
|
2549
2882
|
if (opts.session) {
|
|
2550
2883
|
const spinner = spin("Loading session\u2026");
|
|
2551
2884
|
try {
|
|
@@ -2561,7 +2894,7 @@ function runCommand() {
|
|
|
2561
2894
|
const spinner = spin("Creating session\u2026");
|
|
2562
2895
|
try {
|
|
2563
2896
|
const res = await client.sessions.create({
|
|
2564
|
-
agentId:
|
|
2897
|
+
agentId: agentId3,
|
|
2565
2898
|
initiator: cfg.initiator ?? "",
|
|
2566
2899
|
title: `agc run ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 16)}`,
|
|
2567
2900
|
source: "cli"
|
|
@@ -2575,6 +2908,24 @@ function runCommand() {
|
|
|
2575
2908
|
process.exit(1);
|
|
2576
2909
|
}
|
|
2577
2910
|
}
|
|
2911
|
+
const attachments = attachmentIds.map((fileId) => ({ fileId }));
|
|
2912
|
+
for (const path of filePaths) {
|
|
2913
|
+
const spinner = spin(`Uploading ${(0, import_path4.basename)(path)}\u2026`);
|
|
2914
|
+
try {
|
|
2915
|
+
const result = await client.files.upload(
|
|
2916
|
+
[{ data: new Blob([new Uint8Array((0, import_fs6.readFileSync)(path))]), name: (0, import_path4.basename)(path) }],
|
|
2917
|
+
{ agentId: agentId3, sessionId }
|
|
2918
|
+
);
|
|
2919
|
+
const fileId = result.data[0]?.fileId;
|
|
2920
|
+
if (!fileId) throw new Error(`The upload did not return a file ID for ${path}.`);
|
|
2921
|
+
attachments.push({ fileId });
|
|
2922
|
+
spinner.stop();
|
|
2923
|
+
} catch (error) {
|
|
2924
|
+
spinner.stop();
|
|
2925
|
+
printError(error);
|
|
2926
|
+
process.exit(1);
|
|
2927
|
+
}
|
|
2928
|
+
}
|
|
2578
2929
|
const localEnabled = opts.yes || opts.local;
|
|
2579
2930
|
const autoApprove = !!opts.yes;
|
|
2580
2931
|
let localToolsCfg = null;
|
|
@@ -2587,11 +2938,16 @@ function runCommand() {
|
|
|
2587
2938
|
appendLog: () => {
|
|
2588
2939
|
},
|
|
2589
2940
|
permissions: /* @__PURE__ */ new Map(),
|
|
2590
|
-
agentId:
|
|
2941
|
+
agentId: agentId3,
|
|
2591
2942
|
autoApprove
|
|
2592
2943
|
};
|
|
2593
2944
|
const snapshot = buildDirSnapshot(rootDir, 2);
|
|
2594
|
-
cliContext = buildLocalToolsManifest(
|
|
2945
|
+
cliContext = buildLocalToolsManifest(
|
|
2946
|
+
rootDir,
|
|
2947
|
+
snapshot,
|
|
2948
|
+
[],
|
|
2949
|
+
autoApprove
|
|
2950
|
+
);
|
|
2595
2951
|
}
|
|
2596
2952
|
if (!opts.json) {
|
|
2597
2953
|
const rows = [];
|
|
@@ -2600,10 +2956,16 @@ function runCommand() {
|
|
|
2600
2956
|
rows.push(["Session", label]);
|
|
2601
2957
|
}
|
|
2602
2958
|
if (localEnabled) {
|
|
2603
|
-
rows.push([
|
|
2959
|
+
rows.push([
|
|
2960
|
+
"Local tools",
|
|
2961
|
+
autoApprove ? c.warn("enabled (auto-approve on)") : c.success("enabled")
|
|
2962
|
+
]);
|
|
2604
2963
|
}
|
|
2605
2964
|
if (opts.computer) {
|
|
2606
|
-
rows.push([
|
|
2965
|
+
rows.push([
|
|
2966
|
+
"Cloud computer",
|
|
2967
|
+
c.success("enabled") + c.dim(" (persistent, remote)")
|
|
2968
|
+
]);
|
|
2607
2969
|
}
|
|
2608
2970
|
if (rows.length) {
|
|
2609
2971
|
detail(rows);
|
|
@@ -2611,12 +2973,17 @@ function runCommand() {
|
|
|
2611
2973
|
}
|
|
2612
2974
|
}
|
|
2613
2975
|
const params = {
|
|
2614
|
-
agentId:
|
|
2976
|
+
agentId: agentId3,
|
|
2615
2977
|
sessionId,
|
|
2616
2978
|
messages: [{ role: "user", content: prompt }],
|
|
2979
|
+
...attachments.length && { attachments },
|
|
2617
2980
|
...cfg.initiator && { initiatorId: cfg.initiator },
|
|
2618
2981
|
...opts.computer && { computerRequest: { enabled: true } },
|
|
2619
|
-
...cliContext && { cliContext }
|
|
2982
|
+
...cliContext && { cliContext },
|
|
2983
|
+
provenance: {
|
|
2984
|
+
mode: opts.provenance,
|
|
2985
|
+
onchain: Boolean(opts.onchainProvenance)
|
|
2986
|
+
}
|
|
2620
2987
|
};
|
|
2621
2988
|
if (opts.noStream && !localEnabled) {
|
|
2622
2989
|
const spinner = spin("Running\u2026");
|
|
@@ -2626,8 +2993,13 @@ function runCommand() {
|
|
|
2626
2993
|
if (opts.json) return jsonOut(result);
|
|
2627
2994
|
const text = result?.content ?? result?.text ?? result?.message ?? JSON.stringify(result);
|
|
2628
2995
|
console.log(text);
|
|
2629
|
-
if (sessionId)
|
|
2630
|
-
|
|
2996
|
+
if (sessionId)
|
|
2997
|
+
console.log(
|
|
2998
|
+
c.dim(
|
|
2999
|
+
`
|
|
3000
|
+
Session: ${sessionId} (resume with: agc run --session ${sessionId} "<prompt>")`
|
|
3001
|
+
)
|
|
3002
|
+
);
|
|
2631
3003
|
} catch (err) {
|
|
2632
3004
|
spinner.stop();
|
|
2633
3005
|
printError(err);
|
|
@@ -2659,7 +3031,10 @@ Session: ${sessionId} (resume with: agc run --session ${sessionId} "<prompt>")`
|
|
|
2659
3031
|
let result;
|
|
2660
3032
|
let toolOk = true;
|
|
2661
3033
|
try {
|
|
2662
|
-
result = await runLocalTool(
|
|
3034
|
+
result = await runLocalTool(
|
|
3035
|
+
{ tool: displayName, args: args ?? {} },
|
|
3036
|
+
localToolsCfg
|
|
3037
|
+
);
|
|
2663
3038
|
} catch (err) {
|
|
2664
3039
|
result = `Error: ${err?.message ?? String(err)}`;
|
|
2665
3040
|
toolOk = false;
|
|
@@ -2667,8 +3042,10 @@ Session: ${sessionId} (resume with: agc run --session ${sessionId} "<prompt>")`
|
|
|
2667
3042
|
const elapsed = ((Date.now() - startMs) / 1e3).toFixed(1);
|
|
2668
3043
|
readline2.cursorTo(process.stdout, 0);
|
|
2669
3044
|
readline2.clearLine(process.stdout, 0);
|
|
2670
|
-
process.stdout.write(
|
|
2671
|
-
`)
|
|
3045
|
+
process.stdout.write(
|
|
3046
|
+
` ${c.dim("\u2500")} ${c.bold(displayName)} ${toolOk ? sym.ok : sym.fail} ${c.dim("(" + elapsed + "s)")}
|
|
3047
|
+
`
|
|
3048
|
+
);
|
|
2672
3049
|
try {
|
|
2673
3050
|
await client.agents.submitCliToolResult(requestId, result);
|
|
2674
3051
|
} catch {
|
|
@@ -2685,20 +3062,29 @@ Session: ${sessionId} (resume with: agc run --session ${sessionId} "<prompt>")`
|
|
|
2685
3062
|
const elapsed = ((Date.now() - toolStartMs) / 1e3).toFixed(1);
|
|
2686
3063
|
readline2.cursorTo(process.stdout, 0);
|
|
2687
3064
|
readline2.clearLine(process.stdout, 0);
|
|
2688
|
-
process.stdout.write(
|
|
2689
|
-
`)
|
|
3065
|
+
process.stdout.write(
|
|
3066
|
+
` ${c.dim("\u2500")} ${c.bold(lastToolName)} ${sym.ok} ${c.dim("(" + elapsed + "s)")}
|
|
3067
|
+
`
|
|
3068
|
+
);
|
|
2690
3069
|
} else if (event.type === "final") {
|
|
2691
3070
|
if (hasOutput) process.stdout.write("\n");
|
|
2692
3071
|
const e = event;
|
|
2693
3072
|
const finalText = e.content ?? e.payload?.content ?? e.payload?.text ?? e.payload?.message;
|
|
2694
3073
|
if (finalText && !hasOutput) console.log(finalText);
|
|
2695
|
-
if (sessionId)
|
|
2696
|
-
|
|
3074
|
+
if (sessionId)
|
|
3075
|
+
console.log(
|
|
3076
|
+
c.dim(
|
|
3077
|
+
`
|
|
3078
|
+
Session: ${sessionId} (resume with: agc run --session ${sessionId} "<prompt>")`
|
|
3079
|
+
)
|
|
3080
|
+
);
|
|
2697
3081
|
break;
|
|
2698
3082
|
} else if (event.type === "error") {
|
|
2699
3083
|
if (hasOutput) process.stdout.write("\n");
|
|
2700
|
-
console.error(
|
|
2701
|
-
|
|
3084
|
+
console.error(
|
|
3085
|
+
`
|
|
3086
|
+
${sym.fail} ${c.error(event.message ?? "Error")}`
|
|
3087
|
+
);
|
|
2702
3088
|
process.exit(1);
|
|
2703
3089
|
}
|
|
2704
3090
|
}
|
|
@@ -2713,18 +3099,19 @@ ${sym.fail} ${c.error(event.message ?? "Error")}`);
|
|
|
2713
3099
|
// src/commands/chat.ts
|
|
2714
3100
|
var import_commander9 = require("commander");
|
|
2715
3101
|
var readline3 = __toESM(require("readline"));
|
|
2716
|
-
var
|
|
2717
|
-
var
|
|
3102
|
+
var import_fs7 = require("fs");
|
|
3103
|
+
var import_path5 = require("path");
|
|
2718
3104
|
var import_os3 = require("os");
|
|
2719
|
-
var SESSIONS_DIR = (0,
|
|
3105
|
+
var SESSIONS_DIR = (0, import_path5.join)((0, import_os3.homedir)(), ".agc", "sessions");
|
|
2720
3106
|
function ensureSessionsDir() {
|
|
2721
|
-
if (!(0,
|
|
3107
|
+
if (!(0, import_fs7.existsSync)(SESSIONS_DIR)) (0, import_fs7.mkdirSync)(SESSIONS_DIR, { recursive: true });
|
|
2722
3108
|
}
|
|
2723
3109
|
function appendSessionLog(sessionId, record) {
|
|
2724
3110
|
try {
|
|
3111
|
+
if (!/^[a-zA-Z0-9_-]{1,128}$/.test(sessionId)) return;
|
|
2725
3112
|
ensureSessionsDir();
|
|
2726
|
-
const file = (0,
|
|
2727
|
-
(0,
|
|
3113
|
+
const file = (0, import_path5.join)(SESSIONS_DIR, `${sessionId}.jsonl`);
|
|
3114
|
+
(0, import_fs7.appendFileSync)(file, JSON.stringify(record) + "\n", { mode: 384 });
|
|
2728
3115
|
} catch {
|
|
2729
3116
|
}
|
|
2730
3117
|
}
|
|
@@ -2747,27 +3134,35 @@ var LOCAL_TOOLS_DISCLAIMER = `
|
|
|
2747
3134
|
${c.dim("and execute shell commands on your machine.")}
|
|
2748
3135
|
|
|
2749
3136
|
${c.dim("Rules:")}
|
|
2750
|
-
${sym.bullet} ${c.dim("
|
|
3137
|
+
${sym.bullet} ${c.dim("File tools are restricted to:")} ${c.primary(process.cwd())}
|
|
2751
3138
|
${sym.bullet} ${c.dim("Sensitive paths (.ssh, .env, .aws, credentials) are always blocked")}
|
|
2752
3139
|
${sym.bullet} ${c.dim("Write and run_command operations require your confirmation")}
|
|
2753
|
-
${sym.bullet} ${c.dim("
|
|
3140
|
+
${sym.bullet} ${c.dim("Approved commands run with your operating-system permissions; they are not sandboxed")}
|
|
2754
3141
|
|
|
2755
3142
|
${c.dim("Session activity is logged to")} ${c.primary("~/.agc/sessions/")}
|
|
2756
3143
|
`;
|
|
2757
3144
|
function chatCommand() {
|
|
2758
|
-
return new import_commander9.Command("chat").description("Start an interactive
|
|
3145
|
+
return new import_commander9.Command("chat").alias("code").description("Start an interactive coding session with an agent").argument("[prompt]", "Initial task to send when the session opens").option("--prompt-file <path>", "Read the initial task from a UTF-8 file (maximum 100 KB)").option("--read-only", "Allow local reads but deny local edits and commands").option("--agent <agentId>", "Agent ID (or set defaultAgentId in config)").option("--resume <sessionId>", "Resume an existing session by ID").option("--computer", "Give the agent access to its persistent cloud computer").option("--no-stream", "Disable token streaming (wait for full response)").option("--no-local", "Disable local file system access for the agent").action(async (prompt, opts) => {
|
|
3146
|
+
let initialPrompt = prompt;
|
|
3147
|
+
if (opts.promptFile) {
|
|
3148
|
+
if (prompt) throw new Error("Use either a prompt argument or --prompt-file, not both.");
|
|
3149
|
+
if ((0, import_fs7.statSync)(opts.promptFile).size > 1e5) throw new Error("Prompt file exceeds 100 KB.");
|
|
3150
|
+
initialPrompt = (0, import_fs7.readFileSync)(opts.promptFile, "utf8").trim();
|
|
3151
|
+
}
|
|
3152
|
+
if (!process.stdin.isTTY) throw new Error("Interactive coding requires a terminal. Use `agc run` for scripts.");
|
|
2759
3153
|
const localEnabled = opts.local !== false;
|
|
3154
|
+
if (localEnabled && opts.stream === false) throw new Error("Local tools require streaming. Use --no-local with --no-stream.");
|
|
2760
3155
|
const cfg = loadConfig();
|
|
2761
|
-
let
|
|
2762
|
-
if (!
|
|
3156
|
+
let agentId3 = opts.agent ?? cfg.defaultAgentId;
|
|
3157
|
+
if (!agentId3 && cfg.initiator) {
|
|
2763
3158
|
try {
|
|
2764
3159
|
const listed = await makeClient().agents.list(cfg.initiator);
|
|
2765
3160
|
const agents = listed?.data ?? listed ?? [];
|
|
2766
|
-
|
|
3161
|
+
agentId3 = agents.find((agent) => agent.isDefault)?.agentId ?? agents[0]?.agentId;
|
|
2767
3162
|
} catch {
|
|
2768
3163
|
}
|
|
2769
3164
|
}
|
|
2770
|
-
if (!
|
|
3165
|
+
if (!agentId3) {
|
|
2771
3166
|
console.error(c.error("No default agent is available. Specify --agent <agentId> or run `agc agents list`."));
|
|
2772
3167
|
process.exit(1);
|
|
2773
3168
|
}
|
|
@@ -2783,7 +3178,7 @@ function chatCommand() {
|
|
|
2783
3178
|
const spinner = spin("Creating session\u2026");
|
|
2784
3179
|
try {
|
|
2785
3180
|
const res = await client.sessions.create({
|
|
2786
|
-
agentId:
|
|
3181
|
+
agentId: agentId3,
|
|
2787
3182
|
initiator,
|
|
2788
3183
|
title: `agc chat ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 16)}`,
|
|
2789
3184
|
source: "cli"
|
|
@@ -2794,7 +3189,7 @@ function chatCommand() {
|
|
|
2794
3189
|
appendSessionLog(sessionId, {
|
|
2795
3190
|
type: "session_start",
|
|
2796
3191
|
sessionId,
|
|
2797
|
-
agentId:
|
|
3192
|
+
agentId: agentId3,
|
|
2798
3193
|
initiator,
|
|
2799
3194
|
source: "cli",
|
|
2800
3195
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -2809,12 +3204,8 @@ function chatCommand() {
|
|
|
2809
3204
|
try {
|
|
2810
3205
|
const res = await client.sessions.get(sessionId);
|
|
2811
3206
|
const session = res?.data ?? res;
|
|
2812
|
-
if (session.agentId
|
|
2813
|
-
|
|
2814
|
-
console.log(c.warn(` Note: session ${sessionId} was created with agent ${session.agentId}, not ${agentId2}`));
|
|
2815
|
-
} else {
|
|
2816
|
-
spinner.stop();
|
|
2817
|
-
}
|
|
3207
|
+
if (session.agentId) agentId3 = session.agentId;
|
|
3208
|
+
spinner.stop();
|
|
2818
3209
|
} catch {
|
|
2819
3210
|
spinner.stop();
|
|
2820
3211
|
console.error(c.error(`Session "${sessionId}" not found.`));
|
|
@@ -2824,10 +3215,10 @@ function chatCommand() {
|
|
|
2824
3215
|
let agentName;
|
|
2825
3216
|
let walletLine = "";
|
|
2826
3217
|
await Promise.allSettled([
|
|
2827
|
-
client.agents.get(
|
|
3218
|
+
client.agents.get(agentId3).then((res) => {
|
|
2828
3219
|
agentName = (res?.data ?? res)?.name;
|
|
2829
3220
|
}),
|
|
2830
|
-
client.wallets.primary(
|
|
3221
|
+
client.wallets.primary(agentId3).then(async (primary) => {
|
|
2831
3222
|
const w = primary?.data ?? primary;
|
|
2832
3223
|
if (w?.id) {
|
|
2833
3224
|
const bal = await client.wallets.balance(w.id).catch(() => null);
|
|
@@ -2839,9 +3230,9 @@ function chatCommand() {
|
|
|
2839
3230
|
})
|
|
2840
3231
|
]);
|
|
2841
3232
|
console.log(`
|
|
2842
|
-
${c.bold("Agent Commons
|
|
3233
|
+
${c.bold("Agent Commons \xB7 Code")}`);
|
|
2843
3234
|
const headerRows = [
|
|
2844
|
-
["Agent", agentName ? `${agentName} ${c.dim(
|
|
3235
|
+
["Agent", agentName ? `${agentName} ${c.dim(agentId3)}` : agentId3],
|
|
2845
3236
|
["Session", c.id(sessionId) + (isResume ? c.dim(" (resumed)") : c.dim(" (new)"))]
|
|
2846
3237
|
];
|
|
2847
3238
|
if (walletLine) headerRows.push(["Wallet", walletLine]);
|
|
@@ -2850,17 +3241,16 @@ ${c.bold("Agent Commons Chat")}`);
|
|
|
2850
3241
|
detail(headerRows);
|
|
2851
3242
|
let localToolsCfg = null;
|
|
2852
3243
|
if (localEnabled) {
|
|
2853
|
-
console.log(LOCAL_TOOLS_DISCLAIMER);
|
|
3244
|
+
console.log(opts.readOnly ? c.dim(" Local read-only mode: edits and commands are denied.\n") : LOCAL_TOOLS_DISCLAIMER);
|
|
2854
3245
|
const rootDir = process.cwd();
|
|
2855
3246
|
localToolsCfg = {
|
|
2856
3247
|
rootDir,
|
|
2857
3248
|
sessionId,
|
|
2858
|
-
agentId:
|
|
3249
|
+
agentId: agentId3,
|
|
2859
3250
|
agentName,
|
|
2860
3251
|
appendLog: (record) => appendSessionLog(sessionId, record),
|
|
2861
|
-
permissions:
|
|
3252
|
+
permissions: new Map(opts.readOnly ? ["write_file", "run_command", "start_process"].map((key) => [key, "deny"]) : [])
|
|
2862
3253
|
};
|
|
2863
|
-
installGitHook(rootDir, sessionId, agentId2, agentName);
|
|
2864
3254
|
appendSessionLog(sessionId, {
|
|
2865
3255
|
type: "local_tools_enabled",
|
|
2866
3256
|
rootDir,
|
|
@@ -2874,8 +3264,10 @@ ${c.bold("Agent Commons Chat")}`);
|
|
|
2874
3264
|
terminal: true,
|
|
2875
3265
|
prompt: c.primary("you") + c.dim(" \u203A ")
|
|
2876
3266
|
});
|
|
2877
|
-
|
|
3267
|
+
let busy = false;
|
|
3268
|
+
if (!initialPrompt) rl.prompt();
|
|
2878
3269
|
rl.on("line", async (line) => {
|
|
3270
|
+
if (busy) return;
|
|
2879
3271
|
const input = line.trim();
|
|
2880
3272
|
if (!input) {
|
|
2881
3273
|
rl.prompt();
|
|
@@ -2928,6 +3320,7 @@ Session saved. Resume with: agc chat --resume ${sessionId}`));
|
|
|
2928
3320
|
rl.prompt();
|
|
2929
3321
|
return;
|
|
2930
3322
|
}
|
|
3323
|
+
busy = true;
|
|
2931
3324
|
rl.pause();
|
|
2932
3325
|
appendSessionLog(sessionId, {
|
|
2933
3326
|
type: "message",
|
|
@@ -2941,6 +3334,11 @@ Session saved. Resume with: agc chat --resume ${sessionId}`));
|
|
|
2941
3334
|
const rootDir = localToolsCfg.rootDir;
|
|
2942
3335
|
const atRefs = [...input.matchAll(/@([\S]+)/g)].map((m) => m[1]);
|
|
2943
3336
|
const fileContextBlocks = [];
|
|
3337
|
+
if ((0, import_fs7.existsSync)((0, import_path5.join)(rootDir, "AGENTS.md"))) {
|
|
3338
|
+
fileContextBlocks.push(`Project instructions (AGENTS.md):
|
|
3339
|
+
${readFileForContext(rootDir, "AGENTS.md")}`);
|
|
3340
|
+
}
|
|
3341
|
+
if (opts.readOnly) fileContextBlocks.push("Local read-only mode: do not write files or execute commands. Local reads are available.");
|
|
2944
3342
|
for (const ref of atRefs) {
|
|
2945
3343
|
const content = readFileForContext(rootDir, ref);
|
|
2946
3344
|
fileContextBlocks.push(`**${ref}**
|
|
@@ -2952,13 +3350,13 @@ ${content}
|
|
|
2952
3350
|
cliContext = buildLocalToolsManifest(rootDir, snapshot, fileContextBlocks);
|
|
2953
3351
|
}
|
|
2954
3352
|
const params = {
|
|
2955
|
-
agentId:
|
|
3353
|
+
agentId: agentId3,
|
|
2956
3354
|
sessionId,
|
|
2957
3355
|
messages: [{ role: "user", content: userMessage }],
|
|
2958
3356
|
...opts.computer && { computerRequest: { enabled: true } },
|
|
2959
3357
|
...cliContext && { cliContext }
|
|
2960
3358
|
};
|
|
2961
|
-
if (opts.
|
|
3359
|
+
if (opts.stream === false) {
|
|
2962
3360
|
process.stdout.write(c.primary("agent") + c.dim(" \u203A "));
|
|
2963
3361
|
const spinner = spin("thinking\u2026");
|
|
2964
3362
|
try {
|
|
@@ -2979,12 +3377,12 @@ ${content}
|
|
|
2979
3377
|
${sym.fail} ${c.error(err.message ?? String(err))}`);
|
|
2980
3378
|
}
|
|
2981
3379
|
} else {
|
|
3380
|
+
const thinkingSpinner = spin("thinking\u2026");
|
|
2982
3381
|
try {
|
|
2983
3382
|
let hasOutput = false;
|
|
2984
3383
|
let agentContent = "";
|
|
2985
3384
|
let toolStartMs = 0;
|
|
2986
3385
|
let lastToolName = "";
|
|
2987
|
-
const thinkingSpinner = spin("thinking\u2026");
|
|
2988
3386
|
for await (const event of client.agents.stream(params)) {
|
|
2989
3387
|
if (event.type === "token") {
|
|
2990
3388
|
if (thinkingSpinner.isSpinning) {
|
|
@@ -3113,36 +3511,53 @@ ${sym.fail} ${c.error(event.message ?? "Stream error")}`);
|
|
|
3113
3511
|
if (thinkingSpinner.isSpinning) thinkingSpinner.stop();
|
|
3114
3512
|
process.stdout.write("\n");
|
|
3115
3513
|
if (localToolsCfg && agentContent) {
|
|
3116
|
-
await handleLocalToolLoop(agentContent, localToolsCfg, client,
|
|
3514
|
+
await handleLocalToolLoop(agentContent, localToolsCfg, client, agentId3, sessionId, appendSessionLog, !!opts.computer);
|
|
3117
3515
|
}
|
|
3118
3516
|
} catch (err) {
|
|
3119
3517
|
process.stdout.write("\n");
|
|
3120
3518
|
console.error(`${sym.fail} ${c.error(err.message ?? String(err))}`);
|
|
3519
|
+
} finally {
|
|
3520
|
+
thinkingSpinner.stop();
|
|
3121
3521
|
}
|
|
3122
3522
|
}
|
|
3123
3523
|
console.log();
|
|
3124
3524
|
readline3.cursorTo(process.stdout, 0);
|
|
3125
3525
|
readline3.clearLine(process.stdout, 0);
|
|
3526
|
+
busy = false;
|
|
3126
3527
|
rl.resume();
|
|
3127
3528
|
rl.prompt();
|
|
3128
3529
|
});
|
|
3129
3530
|
const cleanup = () => {
|
|
3130
|
-
|
|
3531
|
+
stopLocalProcesses();
|
|
3131
3532
|
};
|
|
3132
3533
|
rl.on("close", () => {
|
|
3133
3534
|
cleanup();
|
|
3134
3535
|
process.exit(0);
|
|
3135
3536
|
});
|
|
3537
|
+
rl.on("SIGINT", () => {
|
|
3538
|
+
cleanup();
|
|
3539
|
+
console.log(c.dim(`
|
|
3540
|
+
Session preserved. Resume with: agc code --resume ${sessionId}`));
|
|
3541
|
+
process.exit(130);
|
|
3542
|
+
});
|
|
3136
3543
|
process.on("SIGINT", () => {
|
|
3137
3544
|
cleanup();
|
|
3138
3545
|
console.log(c.dim(`
|
|
3139
3546
|
Session preserved. Resume with: agc chat --resume ${sessionId}`));
|
|
3140
3547
|
process.exit(130);
|
|
3141
3548
|
});
|
|
3549
|
+
process.on("SIGTERM", () => {
|
|
3550
|
+
cleanup();
|
|
3551
|
+
process.exit(143);
|
|
3552
|
+
});
|
|
3553
|
+
if (initialPrompt) {
|
|
3554
|
+
console.log(c.primary("you") + c.dim(" \u203A ") + initialPrompt);
|
|
3555
|
+
rl.emit("line", initialPrompt);
|
|
3556
|
+
}
|
|
3142
3557
|
});
|
|
3143
3558
|
}
|
|
3144
3559
|
var MAX_TOOL_DEPTH = 10;
|
|
3145
|
-
async function handleLocalToolLoop(agentText, cfg, client,
|
|
3560
|
+
async function handleLocalToolLoop(agentText, cfg, client, agentId3, sessionId, appendLog, computerEnabled = false, depth = 0) {
|
|
3146
3561
|
if (depth >= MAX_TOOL_DEPTH) {
|
|
3147
3562
|
console.log(c.dim(`
|
|
3148
3563
|
[local] Max tool depth reached (${MAX_TOOL_DEPTH}). Stopping tool loop.
|
|
@@ -3189,7 +3604,7 @@ ${result}
|
|
|
3189
3604
|
let loopToolName = "";
|
|
3190
3605
|
let loopToolStartMs = 0;
|
|
3191
3606
|
for await (const evt of client.agents.stream({
|
|
3192
|
-
agentId:
|
|
3607
|
+
agentId: agentId3,
|
|
3193
3608
|
sessionId,
|
|
3194
3609
|
messages: [{ role: "user", content: resultMsg }],
|
|
3195
3610
|
...computerEnabled && { computerRequest: { enabled: true } }
|
|
@@ -3235,7 +3650,7 @@ ${sym.fail} ${c.error(evt.message ?? "Stream error")}`);
|
|
|
3235
3650
|
console.error(`${sym.fail} ${c.error(err?.message ?? String(err))}`);
|
|
3236
3651
|
return;
|
|
3237
3652
|
}
|
|
3238
|
-
await handleLocalToolLoop(followContent, cfg, client,
|
|
3653
|
+
await handleLocalToolLoop(followContent, cfg, client, agentId3, sessionId, appendLog, computerEnabled, depth + 1);
|
|
3239
3654
|
}
|
|
3240
3655
|
function truncate(s, max) {
|
|
3241
3656
|
const str = String(s ?? "");
|
|
@@ -3245,6 +3660,8 @@ function toolArgSummary(toolName, args) {
|
|
|
3245
3660
|
switch (toolName) {
|
|
3246
3661
|
case "read_file":
|
|
3247
3662
|
return truncate(args.path ?? "", 60);
|
|
3663
|
+
case "search_file":
|
|
3664
|
+
return truncate(`${args.path ?? ""} \xB7 ${args.query ?? ""}`, 60);
|
|
3248
3665
|
case "write_file":
|
|
3249
3666
|
return truncate(args.path ?? "", 60);
|
|
3250
3667
|
case "delete_file":
|
|
@@ -3280,6 +3697,14 @@ function toolResultPreview(toolName, result) {
|
|
|
3280
3697
|
const lines = result.split("\n").length;
|
|
3281
3698
|
return `${lines} lines`;
|
|
3282
3699
|
}
|
|
3700
|
+
case "search_file": {
|
|
3701
|
+
try {
|
|
3702
|
+
const matches = JSON.parse(result)?.matches;
|
|
3703
|
+
return Array.isArray(matches) ? `${matches.length} passage${matches.length === 1 ? "" : "s"}` : "";
|
|
3704
|
+
} catch {
|
|
3705
|
+
return "";
|
|
3706
|
+
}
|
|
3707
|
+
}
|
|
3283
3708
|
case "write_file":
|
|
3284
3709
|
return "written";
|
|
3285
3710
|
case "delete_file":
|
|
@@ -3882,19 +4307,19 @@ function walletCommand() {
|
|
|
3882
4307
|
const cmd = new import_commander12.Command("wallet").description("Manage agent wallets");
|
|
3883
4308
|
cmd.command("list").description("List all wallets for an agent").option("--agent <agentId>", "Agent ID (or use defaultAgentId from config)").option("--json", "Output as JSON").action(async (opts) => {
|
|
3884
4309
|
const cfg = loadConfig();
|
|
3885
|
-
const
|
|
3886
|
-
if (!
|
|
4310
|
+
const agentId3 = opts.agent ?? cfg.defaultAgentId;
|
|
4311
|
+
if (!agentId3) {
|
|
3887
4312
|
console.error(c.error("Specify --agent <agentId> or set defaultAgentId with `agc config set defaultAgentId <id>`"));
|
|
3888
4313
|
process.exit(1);
|
|
3889
4314
|
}
|
|
3890
4315
|
const spinner = spin("Fetching wallets\u2026");
|
|
3891
4316
|
try {
|
|
3892
4317
|
const client = makeClient();
|
|
3893
|
-
const wallets = await client.wallets.list(
|
|
4318
|
+
const wallets = await client.wallets.list(agentId3);
|
|
3894
4319
|
spinner.stop();
|
|
3895
4320
|
if (opts.json) return jsonOut(wallets);
|
|
3896
4321
|
const list = wallets?.data ?? wallets ?? [];
|
|
3897
|
-
section(`Wallets for agent ${
|
|
4322
|
+
section(`Wallets for agent ${agentId3.slice(0, 8)}\u2026 (${list.length})`);
|
|
3898
4323
|
table(
|
|
3899
4324
|
list.map((w) => ({
|
|
3900
4325
|
ID: w.id.slice(0, 8) + "\u2026",
|
|
@@ -3914,19 +4339,19 @@ function walletCommand() {
|
|
|
3914
4339
|
});
|
|
3915
4340
|
cmd.command("show").description("Show the agent's primary wallet address").option("--agent <agentId>", "Agent ID (or use defaultAgentId from config)").option("--json", "Output as JSON").action(async (opts) => {
|
|
3916
4341
|
const cfg = loadConfig();
|
|
3917
|
-
const
|
|
3918
|
-
if (!
|
|
4342
|
+
const agentId3 = opts.agent ?? cfg.defaultAgentId;
|
|
4343
|
+
if (!agentId3) {
|
|
3919
4344
|
console.error(c.error("Specify --agent <agentId> or set defaultAgentId with `agc config set defaultAgentId <id>`"));
|
|
3920
4345
|
process.exit(1);
|
|
3921
4346
|
}
|
|
3922
4347
|
const spinner = spin("Fetching primary wallet\u2026");
|
|
3923
4348
|
try {
|
|
3924
4349
|
const client = makeClient();
|
|
3925
|
-
const wallet = await client.wallets.primary(
|
|
4350
|
+
const wallet = await client.wallets.primary(agentId3);
|
|
3926
4351
|
spinner.stop();
|
|
3927
4352
|
if (!wallet) {
|
|
3928
|
-
console.log(c.warn(` No wallet found for agent ${
|
|
3929
|
-
console.log(c.dim(` Run: agc wallet create --agent ${
|
|
4353
|
+
console.log(c.warn(` No wallet found for agent ${agentId3}`));
|
|
4354
|
+
console.log(c.dim(` Run: agc wallet create --agent ${agentId3}`));
|
|
3930
4355
|
return;
|
|
3931
4356
|
}
|
|
3932
4357
|
const w = wallet?.data ?? wallet;
|
|
@@ -3947,8 +4372,8 @@ function walletCommand() {
|
|
|
3947
4372
|
});
|
|
3948
4373
|
cmd.command("balance").description("Show the agent's wallet USDC and ETH balance").option("--agent <agentId>", "Agent ID (or use defaultAgentId from config)").option("--wallet <walletId>", "Specific wallet ID (defaults to primary)").option("--json", "Output as JSON").action(async (opts) => {
|
|
3949
4374
|
const cfg = loadConfig();
|
|
3950
|
-
const
|
|
3951
|
-
if (!
|
|
4375
|
+
const agentId3 = opts.agent ?? cfg.defaultAgentId;
|
|
4376
|
+
if (!agentId3) {
|
|
3952
4377
|
console.error(c.error("Specify --agent <agentId> or set defaultAgentId with `agc config set defaultAgentId <id>`"));
|
|
3953
4378
|
process.exit(1);
|
|
3954
4379
|
}
|
|
@@ -3957,11 +4382,11 @@ function walletCommand() {
|
|
|
3957
4382
|
const client = makeClient();
|
|
3958
4383
|
let walletId = opts.wallet;
|
|
3959
4384
|
if (!walletId) {
|
|
3960
|
-
const primary = await client.wallets.primary(
|
|
4385
|
+
const primary = await client.wallets.primary(agentId3);
|
|
3961
4386
|
const w = primary?.data ?? primary;
|
|
3962
4387
|
if (!w) {
|
|
3963
4388
|
spinner.stop();
|
|
3964
|
-
console.log(c.warn(` No wallet found. Run: agc wallet create --agent ${
|
|
4389
|
+
console.log(c.warn(` No wallet found. Run: agc wallet create --agent ${agentId3}`));
|
|
3965
4390
|
return;
|
|
3966
4391
|
}
|
|
3967
4392
|
walletId = w.id;
|
|
@@ -3988,8 +4413,8 @@ function walletCommand() {
|
|
|
3988
4413
|
});
|
|
3989
4414
|
cmd.command("create").description("Create a new wallet for an agent").option("--agent <agentId>", "Agent ID (or use defaultAgentId from config)").option("--type <type>", "Wallet type: eoa | external (default: eoa)", "eoa").option("--label <label>", "Wallet label (default: Primary)", "Primary").option("--address <address>", "For --type external: owner-provided address").option("--json", "Output as JSON").action(async (opts) => {
|
|
3990
4415
|
const cfg = loadConfig();
|
|
3991
|
-
const
|
|
3992
|
-
if (!
|
|
4416
|
+
const agentId3 = opts.agent ?? cfg.defaultAgentId;
|
|
4417
|
+
if (!agentId3) {
|
|
3993
4418
|
console.error(c.error("Specify --agent <agentId> or set defaultAgentId with `agc config set defaultAgentId <id>`"));
|
|
3994
4419
|
process.exit(1);
|
|
3995
4420
|
}
|
|
@@ -4001,7 +4426,7 @@ function walletCommand() {
|
|
|
4001
4426
|
try {
|
|
4002
4427
|
const client = makeClient();
|
|
4003
4428
|
const wallet = await client.wallets.create({
|
|
4004
|
-
agentId:
|
|
4429
|
+
agentId: agentId3,
|
|
4005
4430
|
walletType: opts.type,
|
|
4006
4431
|
label: opts.label,
|
|
4007
4432
|
externalAddress: opts.address
|
|
@@ -4159,22 +4584,22 @@ function memoryCommand() {
|
|
|
4159
4584
|
const cmd = new import_commander14.Command("memory").description("View and manage agent memories");
|
|
4160
4585
|
cmd.command("list").description("List memories for an agent").option("--agent <agentId>", "Agent ID (defaults to configured agent)").option("--type <type>", "Filter by type: episodic | semantic | procedural").option("--limit <n>", "Max results", "50").option("--json", "Output as JSON").action(async (opts) => {
|
|
4161
4586
|
const cfg = loadConfig();
|
|
4162
|
-
const
|
|
4163
|
-
if (!
|
|
4587
|
+
const agentId3 = opts.agent ?? cfg.defaultAgentId;
|
|
4588
|
+
if (!agentId3) {
|
|
4164
4589
|
console.error(c.error("Specify --agent <agentId> or set defaultAgentId"));
|
|
4165
4590
|
process.exit(1);
|
|
4166
4591
|
}
|
|
4167
4592
|
const spinner = spin("Fetching memories\u2026");
|
|
4168
4593
|
try {
|
|
4169
4594
|
const client = makeClient();
|
|
4170
|
-
const res = await client.memory.list(
|
|
4595
|
+
const res = await client.memory.list(agentId3, {
|
|
4171
4596
|
type: opts.type,
|
|
4172
4597
|
limit: parseInt(opts.limit, 10)
|
|
4173
4598
|
});
|
|
4174
4599
|
const memories = res?.data ?? res ?? [];
|
|
4175
4600
|
spinner.stop();
|
|
4176
4601
|
if (opts.json) return jsonOut(memories);
|
|
4177
|
-
section(`Memories for ${
|
|
4602
|
+
section(`Memories for ${agentId3.slice(0, 12)}\u2026 (${memories.length})`);
|
|
4178
4603
|
if (memories.length === 0) {
|
|
4179
4604
|
console.log(c.dim(" No memories yet"));
|
|
4180
4605
|
return;
|
|
@@ -4196,15 +4621,15 @@ function memoryCommand() {
|
|
|
4196
4621
|
});
|
|
4197
4622
|
cmd.command("stats").description("Show memory statistics for an agent").option("--agent <agentId>", "Agent ID").option("--json", "Output as JSON").action(async (opts) => {
|
|
4198
4623
|
const cfg = loadConfig();
|
|
4199
|
-
const
|
|
4200
|
-
if (!
|
|
4624
|
+
const agentId3 = opts.agent ?? cfg.defaultAgentId;
|
|
4625
|
+
if (!agentId3) {
|
|
4201
4626
|
console.error(c.error("Specify --agent <agentId>"));
|
|
4202
4627
|
process.exit(1);
|
|
4203
4628
|
}
|
|
4204
4629
|
const spinner = spin("Fetching stats\u2026");
|
|
4205
4630
|
try {
|
|
4206
4631
|
const client = makeClient();
|
|
4207
|
-
const res = await client.memory.stats(
|
|
4632
|
+
const res = await client.memory.stats(agentId3);
|
|
4208
4633
|
const stats = res?.data ?? res;
|
|
4209
4634
|
spinner.stop();
|
|
4210
4635
|
if (opts.json) return jsonOut(stats);
|
|
@@ -4264,15 +4689,15 @@ ${sym.ok} Memory ${c.id(memoryId)} deleted`);
|
|
|
4264
4689
|
});
|
|
4265
4690
|
cmd.command("search <query>").description("Semantic search over agent memories").option("--agent <agentId>", "Agent ID").option("--limit <n>", "Max results", "10").option("--json", "Output as JSON").action(async (query, opts) => {
|
|
4266
4691
|
const cfg = loadConfig();
|
|
4267
|
-
const
|
|
4268
|
-
if (!
|
|
4692
|
+
const agentId3 = opts.agent ?? cfg.defaultAgentId;
|
|
4693
|
+
if (!agentId3) {
|
|
4269
4694
|
console.error(c.error("Specify --agent <agentId>"));
|
|
4270
4695
|
process.exit(1);
|
|
4271
4696
|
}
|
|
4272
4697
|
const spinner = spin("Searching memories\u2026");
|
|
4273
4698
|
try {
|
|
4274
4699
|
const client = makeClient();
|
|
4275
|
-
const res = await client.memory.retrieve(
|
|
4700
|
+
const res = await client.memory.retrieve(agentId3, query, parseInt(opts.limit, 10));
|
|
4276
4701
|
const memories = res?.data ?? res ?? [];
|
|
4277
4702
|
spinner.stop();
|
|
4278
4703
|
if (opts.json) return jsonOut(memories);
|
|
@@ -4361,18 +4786,18 @@ function usageCommand() {
|
|
|
4361
4786
|
process.exit(1);
|
|
4362
4787
|
}
|
|
4363
4788
|
});
|
|
4364
|
-
cmd.command("agent <agentId>").description("Show detailed usage for a specific agent").option("--from <date>", "Start date (ISO)").option("--to <date>", "End date (ISO)").option("--json", "Output as JSON").action(async (
|
|
4789
|
+
cmd.command("agent <agentId>").description("Show detailed usage for a specific agent").option("--from <date>", "Start date (ISO)").option("--to <date>", "End date (ISO)").option("--json", "Output as JSON").action(async (agentId3, opts) => {
|
|
4365
4790
|
const spinner = spin("Fetching usage\u2026");
|
|
4366
4791
|
try {
|
|
4367
4792
|
const client = makeClient();
|
|
4368
|
-
const res = await client.usage.getAgentUsage(
|
|
4793
|
+
const res = await client.usage.getAgentUsage(agentId3, {
|
|
4369
4794
|
from: opts.from,
|
|
4370
4795
|
to: opts.to
|
|
4371
4796
|
});
|
|
4372
4797
|
const data = res?.data ?? res;
|
|
4373
4798
|
spinner.stop();
|
|
4374
4799
|
if (opts.json) return jsonOut(data);
|
|
4375
|
-
section(`Usage \u2014 ${
|
|
4800
|
+
section(`Usage \u2014 ${agentId3.slice(0, 12)}\u2026`);
|
|
4376
4801
|
detail([
|
|
4377
4802
|
["Calls", (data.callCount ?? 0).toLocaleString()],
|
|
4378
4803
|
["Input tokens", (data.totalInputTokens ?? 0).toLocaleString()],
|
|
@@ -4509,15 +4934,15 @@ function logsCommand() {
|
|
|
4509
4934
|
const cmd = new import_commander17.Command("logs").description("View agent activity logs");
|
|
4510
4935
|
cmd.command("list").alias("ls").description("List recent log entries for an agent").option("--agent <agentId>", "Agent ID (defaults to configured agent)").option("--session <sessionId>", "Filter by session ID").option("--status <status>", "Filter: success | error | warning").option("--limit <n>", "Max entries to show", "50").option("--json", "Output as JSON").action(async (opts) => {
|
|
4511
4936
|
const cfg = loadConfig();
|
|
4512
|
-
const
|
|
4513
|
-
if (!
|
|
4937
|
+
const agentId3 = opts.agent ?? cfg.defaultAgentId;
|
|
4938
|
+
if (!agentId3) {
|
|
4514
4939
|
console.error(c.error("Specify --agent <agentId> or set defaultAgentId"));
|
|
4515
4940
|
process.exit(1);
|
|
4516
4941
|
}
|
|
4517
4942
|
const spinner = spin("Fetching logs\u2026");
|
|
4518
4943
|
try {
|
|
4519
4944
|
const client = makeClient();
|
|
4520
|
-
const res = await client.logs.list(
|
|
4945
|
+
const res = await client.logs.list(agentId3, {
|
|
4521
4946
|
limit: Number(opts.limit),
|
|
4522
4947
|
sessionId: opts.session
|
|
4523
4948
|
});
|
|
@@ -4525,7 +4950,7 @@ function logsCommand() {
|
|
|
4525
4950
|
if (opts.status) logs = logs.filter((l) => l.status === opts.status);
|
|
4526
4951
|
spinner.stop();
|
|
4527
4952
|
if (opts.json) return jsonOut(logs);
|
|
4528
|
-
section(`Logs \u2014 ${
|
|
4953
|
+
section(`Logs \u2014 ${agentId3.slice(0, 12)}\u2026 (${logs.length})`);
|
|
4529
4954
|
if (logs.length === 0) {
|
|
4530
4955
|
console.log(c.dim(" No logs yet"));
|
|
4531
4956
|
return;
|
|
@@ -4550,21 +4975,21 @@ function logsCommand() {
|
|
|
4550
4975
|
});
|
|
4551
4976
|
cmd.command("errors").description("Show only error log entries for an agent").option("--agent <agentId>", "Agent ID").option("--limit <n>", "Max entries", "20").option("--json", "Output as JSON").action(async (opts) => {
|
|
4552
4977
|
const cfg = loadConfig();
|
|
4553
|
-
const
|
|
4554
|
-
if (!
|
|
4978
|
+
const agentId3 = opts.agent ?? cfg.defaultAgentId;
|
|
4979
|
+
if (!agentId3) {
|
|
4555
4980
|
console.error(c.error("Specify --agent <agentId>"));
|
|
4556
4981
|
process.exit(1);
|
|
4557
4982
|
}
|
|
4558
4983
|
const spinner = spin("Fetching error logs\u2026");
|
|
4559
4984
|
try {
|
|
4560
4985
|
const client = makeClient();
|
|
4561
|
-
const res = await client.logs.list(
|
|
4986
|
+
const res = await client.logs.list(agentId3, {
|
|
4562
4987
|
limit: Number(opts.limit)
|
|
4563
4988
|
});
|
|
4564
4989
|
const errors = (res?.data ?? []).filter((l) => l.status === "error");
|
|
4565
4990
|
spinner.stop();
|
|
4566
4991
|
if (opts.json) return jsonOut(errors);
|
|
4567
|
-
section(`Errors \u2014 ${
|
|
4992
|
+
section(`Errors \u2014 ${agentId3.slice(0, 12)}\u2026 (${errors.length})`);
|
|
4568
4993
|
if (errors.length === 0) {
|
|
4569
4994
|
console.log(`${sym.ok} No errors found`);
|
|
4570
4995
|
return;
|
|
@@ -4593,13 +5018,13 @@ var RESOURCE_PROFILES = [
|
|
|
4593
5018
|
];
|
|
4594
5019
|
var RESOURCE_MODES = ["fixed", "elastic"];
|
|
4595
5020
|
function resolveAgentId(opts) {
|
|
4596
|
-
const
|
|
4597
|
-
if (!
|
|
5021
|
+
const agentId3 = opts.agent ?? loadConfig().defaultAgentId;
|
|
5022
|
+
if (!agentId3) {
|
|
4598
5023
|
throw new Error(
|
|
4599
5024
|
"Specify --agent <agentId> or set defaultAgentId with `agc config set defaultAgentId <id>`."
|
|
4600
5025
|
);
|
|
4601
5026
|
}
|
|
4602
|
-
return
|
|
5027
|
+
return agentId3;
|
|
4603
5028
|
}
|
|
4604
5029
|
function unwrap(response) {
|
|
4605
5030
|
return response?.data ?? response;
|
|
@@ -4650,17 +5075,17 @@ function parseNumber(value, name, options) {
|
|
|
4650
5075
|
}
|
|
4651
5076
|
return parsed;
|
|
4652
5077
|
}
|
|
4653
|
-
async function changeEnabled(
|
|
5078
|
+
async function changeEnabled(agentId3, enabled, json) {
|
|
4654
5079
|
const spinner = spin(`${enabled ? "Enabling" : "Disabling"} persistent cloud computer\u2026`);
|
|
4655
5080
|
try {
|
|
4656
|
-
const response = await makeClient().agents.updateComputerConfig(
|
|
5081
|
+
const response = await makeClient().agents.updateComputerConfig(agentId3, { enabled });
|
|
4657
5082
|
const config = unwrap(response);
|
|
4658
5083
|
spinner.stop();
|
|
4659
5084
|
if (json) return jsonOut(config);
|
|
4660
5085
|
console.log(`
|
|
4661
|
-
${sym.ok} Persistent cloud computer ${enabled ? "enabled" : "disabled"} for agent ${c.id(
|
|
5086
|
+
${sym.ok} Persistent cloud computer ${enabled ? "enabled" : "disabled"} for agent ${c.id(agentId3)}`);
|
|
4662
5087
|
if (enabled) {
|
|
4663
|
-
console.log(c.dim(` Wake it now with: agc computer wake --agent ${
|
|
5088
|
+
console.log(c.dim(` Wake it now with: agc computer wake --agent ${agentId3}`));
|
|
4664
5089
|
}
|
|
4665
5090
|
} catch (error) {
|
|
4666
5091
|
spinner.stop();
|
|
@@ -4668,12 +5093,12 @@ ${sym.ok} Persistent cloud computer ${enabled ? "enabled" : "disabled"} for agen
|
|
|
4668
5093
|
process.exitCode = 1;
|
|
4669
5094
|
}
|
|
4670
5095
|
}
|
|
4671
|
-
async function lifecycleAction(action,
|
|
5096
|
+
async function lifecycleAction(action, agentId3, reason, json) {
|
|
4672
5097
|
const verb = action === "wake" ? "Waking" : action === "sleep" ? "Sleeping" : "Restarting";
|
|
4673
5098
|
const spinner = spin(`${verb} persistent cloud computer\u2026`);
|
|
4674
5099
|
try {
|
|
4675
5100
|
const client = makeClient();
|
|
4676
|
-
const response = action === "wake" ? await client.agents.wakeComputer(
|
|
5101
|
+
const response = action === "wake" ? await client.agents.wakeComputer(agentId3, reason ? { reason } : void 0) : action === "sleep" ? await client.agents.sleepComputer(agentId3, reason ? { reason } : void 0) : await client.agents.restartComputer(agentId3, reason ? { reason } : void 0);
|
|
4677
5102
|
const computer = unwrap(response);
|
|
4678
5103
|
spinner.stop();
|
|
4679
5104
|
if (json) return jsonOut(computer);
|
|
@@ -4692,9 +5117,9 @@ function addAgentOption(command) {
|
|
|
4692
5117
|
function computerCommand() {
|
|
4693
5118
|
const command = new import_commander18.Command("computer").description("Manage an agent's one persistent cloud computer");
|
|
4694
5119
|
addAgentOption(command.command("status").description("Show persistent cloud computer status")).option("--json", "Output as JSON").action(async (opts) => {
|
|
4695
|
-
let
|
|
5120
|
+
let agentId3;
|
|
4696
5121
|
try {
|
|
4697
|
-
|
|
5122
|
+
agentId3 = resolveAgentId(opts);
|
|
4698
5123
|
} catch (error) {
|
|
4699
5124
|
printError(error);
|
|
4700
5125
|
process.exitCode = 1;
|
|
@@ -4702,7 +5127,7 @@ function computerCommand() {
|
|
|
4702
5127
|
}
|
|
4703
5128
|
const spinner = spin("Fetching persistent cloud computer\u2026");
|
|
4704
5129
|
try {
|
|
4705
|
-
const computer = unwrap(await makeClient().agents.getComputer(
|
|
5130
|
+
const computer = unwrap(await makeClient().agents.getComputer(agentId3));
|
|
4706
5131
|
spinner.stop();
|
|
4707
5132
|
if (opts.json) return jsonOut(computer);
|
|
4708
5133
|
displayComputer(computer);
|
|
@@ -4744,10 +5169,10 @@ function computerCommand() {
|
|
|
4744
5169
|
});
|
|
4745
5170
|
}
|
|
4746
5171
|
addAgentOption(command.command("resize").description("Resize the persistent cloud computer")).option("--profile <profile>", `Resource profile: ${RESOURCE_PROFILES.join(" | ")}`).option("--mode <mode>", `Resource mode: ${RESOURCE_MODES.join(" | ")}`).option("--vcpu <count>", "Requested virtual CPU count").option("--cpu <count>", "Alias for --vcpu").option("--memory <gib>", "Requested memory in GiB").option("--storage <gib>", "Requested persistent storage in GiB").option("--gpu-type <type>", "GPU type, such as nvidia-h100").option("--gpu-count <count>", "GPU count (0 removes GPU allocation)").option("--json", "Output as JSON").action(async (opts) => {
|
|
4747
|
-
let
|
|
5172
|
+
let agentId3;
|
|
4748
5173
|
let resize;
|
|
4749
5174
|
try {
|
|
4750
|
-
|
|
5175
|
+
agentId3 = resolveAgentId(opts);
|
|
4751
5176
|
if (opts.profile && !RESOURCE_PROFILES.includes(opts.profile)) {
|
|
4752
5177
|
throw new Error(`--profile must be one of: ${RESOURCE_PROFILES.join(", ")}.`);
|
|
4753
5178
|
}
|
|
@@ -4784,7 +5209,7 @@ function computerCommand() {
|
|
|
4784
5209
|
}
|
|
4785
5210
|
const spinner = spin("Resizing persistent cloud computer\u2026");
|
|
4786
5211
|
try {
|
|
4787
|
-
const computer = unwrap(await makeClient().agents.resizeComputer(
|
|
5212
|
+
const computer = unwrap(await makeClient().agents.resizeComputer(agentId3, resize));
|
|
4788
5213
|
spinner.stop();
|
|
4789
5214
|
if (opts.json) return jsonOut(computer);
|
|
4790
5215
|
console.log(`
|
|
@@ -4799,10 +5224,10 @@ ${sym.ok} Persistent cloud computer resize requested`);
|
|
|
4799
5224
|
addAgentOption(
|
|
4800
5225
|
command.command("exec").description("Run a command in the persistent cloud computer").argument("<command...>", "Command and arguments to run")
|
|
4801
5226
|
).option("--cwd <path>", "Working directory").option("--timeout <seconds>", "Command timeout in seconds", "120").option("--json", "Output as JSON").action(async (commandParts, opts) => {
|
|
4802
|
-
let
|
|
5227
|
+
let agentId3;
|
|
4803
5228
|
let timeoutSeconds;
|
|
4804
5229
|
try {
|
|
4805
|
-
|
|
5230
|
+
agentId3 = resolveAgentId(opts);
|
|
4806
5231
|
timeoutSeconds = parseNumber(opts.timeout, "Timeout");
|
|
4807
5232
|
} catch (error) {
|
|
4808
5233
|
printError(error);
|
|
@@ -4811,7 +5236,7 @@ ${sym.ok} Persistent cloud computer resize requested`);
|
|
|
4811
5236
|
}
|
|
4812
5237
|
const spinner = spin("Running command in persistent cloud computer\u2026");
|
|
4813
5238
|
try {
|
|
4814
|
-
const result = unwrap(await makeClient().agents.execComputer(
|
|
5239
|
+
const result = unwrap(await makeClient().agents.execComputer(agentId3, {
|
|
4815
5240
|
command: commandParts.join(" "),
|
|
4816
5241
|
...opts.cwd && { cwd: opts.cwd },
|
|
4817
5242
|
...timeoutSeconds !== void 0 && { timeoutSeconds }
|
|
@@ -4831,10 +5256,10 @@ ${sym.ok} Persistent cloud computer resize requested`);
|
|
|
4831
5256
|
}
|
|
4832
5257
|
});
|
|
4833
5258
|
addAgentOption(command.command("events").description("List recent persistent cloud computer events")).option("--limit <count>", "Maximum events", "50").option("--json", "Output as JSON").action(async (opts) => {
|
|
4834
|
-
let
|
|
5259
|
+
let agentId3;
|
|
4835
5260
|
let limit;
|
|
4836
5261
|
try {
|
|
4837
|
-
|
|
5262
|
+
agentId3 = resolveAgentId(opts);
|
|
4838
5263
|
limit = parseNumber(opts.limit, "Limit", { integer: true });
|
|
4839
5264
|
} catch (error) {
|
|
4840
5265
|
printError(error);
|
|
@@ -4843,7 +5268,7 @@ ${sym.ok} Persistent cloud computer resize requested`);
|
|
|
4843
5268
|
}
|
|
4844
5269
|
const spinner = spin("Fetching persistent cloud computer events\u2026");
|
|
4845
5270
|
try {
|
|
4846
|
-
const events = unwrap(await makeClient().agents.listComputerEvents(
|
|
5271
|
+
const events = unwrap(await makeClient().agents.listComputerEvents(agentId3, limit));
|
|
4847
5272
|
spinner.stop();
|
|
4848
5273
|
if (opts.json) return jsonOut(events);
|
|
4849
5274
|
section(`Cloud computer events (${events.length})`);
|
|
@@ -4867,8 +5292,8 @@ ${sym.ok} Persistent cloud computer resize requested`);
|
|
|
4867
5292
|
|
|
4868
5293
|
// src/commands/library.ts
|
|
4869
5294
|
var import_commander19 = require("commander");
|
|
4870
|
-
var
|
|
4871
|
-
var
|
|
5295
|
+
var import_fs8 = require("fs");
|
|
5296
|
+
var import_path6 = require("path");
|
|
4872
5297
|
function libraryCommand() {
|
|
4873
5298
|
const command = new import_commander19.Command("library").alias("files").description("Upload, find, and manage files in your Commons library");
|
|
4874
5299
|
command.command("list", { isDefault: true }).alias("ls").description("List library items").option("--query <text>", "Search names and descriptions").option("--source <source>", "Filter by source").option("--session <sessionId>", "Filter by session").option("--favorites", "Show favorites only").option("--limit <n>", "Maximum items", "50").option("--json", "Output as JSON").action(async (opts) => {
|
|
@@ -4930,8 +5355,8 @@ function libraryCommand() {
|
|
|
4930
5355
|
throw new Error("--storage must be either s3 or ipfs.");
|
|
4931
5356
|
}
|
|
4932
5357
|
const files = paths.map((path) => ({
|
|
4933
|
-
data: new Blob([new Uint8Array((0,
|
|
4934
|
-
name: (0,
|
|
5358
|
+
data: new Blob([new Uint8Array((0, import_fs8.readFileSync)(path))]),
|
|
5359
|
+
name: (0, import_path6.basename)(path)
|
|
4935
5360
|
}));
|
|
4936
5361
|
const result = await makeClient().files.upload(files, {
|
|
4937
5362
|
agentId: opts.agent,
|
|
@@ -4990,7 +5415,7 @@ ${sym.ok} Uploaded ${result.data.length} file${result.data.length === 1 ? "" : "
|
|
|
4990
5415
|
|
|
4991
5416
|
// src/commands/projects.ts
|
|
4992
5417
|
var import_commander20 = require("commander");
|
|
4993
|
-
var
|
|
5418
|
+
var import_fs9 = require("fs");
|
|
4994
5419
|
function agentId(value) {
|
|
4995
5420
|
const resolved = value ?? loadConfig().defaultAgentId;
|
|
4996
5421
|
if (!resolved) {
|
|
@@ -5002,7 +5427,7 @@ function agentId(value) {
|
|
|
5002
5427
|
}
|
|
5003
5428
|
function projectFiles(path) {
|
|
5004
5429
|
if (!path) return void 0;
|
|
5005
|
-
const parsed = JSON.parse((0,
|
|
5430
|
+
const parsed = JSON.parse((0, import_fs9.readFileSync)(path, "utf8"));
|
|
5006
5431
|
const files = Array.isArray(parsed) ? parsed : parsed.files;
|
|
5007
5432
|
if (!Array.isArray(files)) {
|
|
5008
5433
|
throw new Error("The files document must be an array or an object with a files array.");
|
|
@@ -5163,8 +5588,160 @@ ${sym.ok} Project published.`);
|
|
|
5163
5588
|
return command;
|
|
5164
5589
|
}
|
|
5165
5590
|
|
|
5166
|
-
// src/commands/
|
|
5591
|
+
// src/commands/arcade.ts
|
|
5167
5592
|
var import_commander21 = require("commander");
|
|
5593
|
+
var import_fs10 = require("fs");
|
|
5594
|
+
var import_path7 = require("path");
|
|
5595
|
+
function agentId2(value) {
|
|
5596
|
+
const resolved = value ?? loadConfig().defaultAgentId;
|
|
5597
|
+
if (!resolved) {
|
|
5598
|
+
throw new Error(
|
|
5599
|
+
"Specify --agent <agentId> or set a default with `agc config set defaultAgentId <id>`."
|
|
5600
|
+
);
|
|
5601
|
+
}
|
|
5602
|
+
return resolved;
|
|
5603
|
+
}
|
|
5604
|
+
var SOURCE_EXTENSIONS = /\.(html|css|js|mjs|cjs|ts|tsx|jsx|json|svg|md|txt)$/i;
|
|
5605
|
+
function readGameDirectory(root) {
|
|
5606
|
+
const files = [];
|
|
5607
|
+
const walk = (directory) => {
|
|
5608
|
+
for (const name of (0, import_fs10.readdirSync)(directory)) {
|
|
5609
|
+
if (name.startsWith(".") || name === "node_modules" || name === "dist") continue;
|
|
5610
|
+
const full = (0, import_path7.join)(directory, name);
|
|
5611
|
+
if ((0, import_fs10.statSync)(full).isDirectory()) walk(full);
|
|
5612
|
+
else if (SOURCE_EXTENSIONS.test(name)) {
|
|
5613
|
+
files.push({
|
|
5614
|
+
path: (0, import_path7.relative)(root, full).split(import_path7.sep).join("/"),
|
|
5615
|
+
content: (0, import_fs10.readFileSync)(full, "utf8")
|
|
5616
|
+
});
|
|
5617
|
+
}
|
|
5618
|
+
}
|
|
5619
|
+
};
|
|
5620
|
+
walk(root);
|
|
5621
|
+
if (!files.length) throw new Error(`No game source files found in ${root}.`);
|
|
5622
|
+
return files;
|
|
5623
|
+
}
|
|
5624
|
+
async function run(label, work) {
|
|
5625
|
+
const spinner = spin(label);
|
|
5626
|
+
try {
|
|
5627
|
+
const result = await work();
|
|
5628
|
+
spinner.stop();
|
|
5629
|
+
return result;
|
|
5630
|
+
} catch (error) {
|
|
5631
|
+
spinner.stop();
|
|
5632
|
+
printError(error);
|
|
5633
|
+
process.exit(1);
|
|
5634
|
+
}
|
|
5635
|
+
}
|
|
5636
|
+
function arcadeCommand() {
|
|
5637
|
+
const command = new import_commander21.Command("arcade").description(
|
|
5638
|
+
"Build, test, and publish Common Arcade games in your agent owner's account"
|
|
5639
|
+
);
|
|
5640
|
+
command.command("status").description("Check whether this platform is connected to Common Arcade").option("--agent <agentId>", "Agent ID").option("--json", "Output as JSON").action(async (opts) => {
|
|
5641
|
+
const result = await run(
|
|
5642
|
+
"Checking Arcade connection\u2026",
|
|
5643
|
+
() => makeClient().arcade.status(agentId2(opts.agent))
|
|
5644
|
+
);
|
|
5645
|
+
if (opts.json) return jsonOut(result.data);
|
|
5646
|
+
console.log(
|
|
5647
|
+
result.data.connected ? `${sym.ok} Connected to Common Arcade.` : `${sym.fail} Common Arcade is not connected on this deployment.`
|
|
5648
|
+
);
|
|
5649
|
+
});
|
|
5650
|
+
command.command("list", { isDefault: true }).alias("ls").description("List Arcade game projects").option("--agent <agentId>", "Agent ID").option("--json", "Output as JSON").action(async (opts) => {
|
|
5651
|
+
const result = await run(
|
|
5652
|
+
"Fetching Arcade projects\u2026",
|
|
5653
|
+
() => makeClient().arcade.list(agentId2(opts.agent))
|
|
5654
|
+
);
|
|
5655
|
+
if (opts.json) return jsonOut(result.data);
|
|
5656
|
+
section(`Arcade projects (${result.data.length})`);
|
|
5657
|
+
table(
|
|
5658
|
+
result.data.map((project) => ({
|
|
5659
|
+
ID: project.projectId,
|
|
5660
|
+
Title: project.title ?? "",
|
|
5661
|
+
Published: project.isPublished ? "yes" : "no",
|
|
5662
|
+
Studio: project.studioUrl
|
|
5663
|
+
})),
|
|
5664
|
+
["ID", "Title", "Published", "Studio"]
|
|
5665
|
+
);
|
|
5666
|
+
});
|
|
5667
|
+
command.command("get <projectId>").description("Show an Arcade game project").option("--agent <agentId>", "Agent ID").option("--json", "Output as JSON").action(async (projectId, opts) => {
|
|
5668
|
+
const result = await run(
|
|
5669
|
+
"Fetching Arcade project\u2026",
|
|
5670
|
+
() => makeClient().arcade.get(agentId2(opts.agent), projectId)
|
|
5671
|
+
);
|
|
5672
|
+
if (opts.json) return jsonOut(result.data);
|
|
5673
|
+
const project = result.data;
|
|
5674
|
+
section(project.title ?? project.projectId);
|
|
5675
|
+
detail([
|
|
5676
|
+
["Project ID", c.id(project.projectId)],
|
|
5677
|
+
["Revision", String(project.revision)],
|
|
5678
|
+
["Files", project.document.files.map((file) => file.path).join(", ")],
|
|
5679
|
+
["Published", project.isPublished ? "yes" : "no"],
|
|
5680
|
+
["Thumbnail", project.hasThumbnail ? "yes" : "no"],
|
|
5681
|
+
["Studio", project.studioUrl]
|
|
5682
|
+
]);
|
|
5683
|
+
});
|
|
5684
|
+
command.command("create").description("Create an Arcade game project").requiredOption("--title <title>", "Game title").option("--description <text>", "How to play").option("--agent <agentId>", "Agent ID").option("--json", "Output as JSON").action(async (opts) => {
|
|
5685
|
+
const result = await run(
|
|
5686
|
+
"Creating Arcade project\u2026",
|
|
5687
|
+
() => makeClient().arcade.create(agentId2(opts.agent), {
|
|
5688
|
+
title: opts.title,
|
|
5689
|
+
description: opts.description
|
|
5690
|
+
})
|
|
5691
|
+
);
|
|
5692
|
+
if (opts.json) return jsonOut(result.data);
|
|
5693
|
+
console.log(`
|
|
5694
|
+
${sym.ok} Arcade project created.`);
|
|
5695
|
+
detail([
|
|
5696
|
+
["Project ID", c.id(result.data.projectId)],
|
|
5697
|
+
["Studio", result.data.studioUrl]
|
|
5698
|
+
]);
|
|
5699
|
+
});
|
|
5700
|
+
command.command("push <projectId> <directory>").description("Upload a local game directory to an Arcade project").option("--agent <agentId>", "Agent ID").option("--entry <file>", "HTML entry file (default: index.html)").option("--runtime <file>", "Authoritative rules file, required to publish").option("--thumbnail <url>", "HTTPS thumbnail URL, required to publish").option("--replace", "Remove project files that are not in the directory").option("--json", "Output as JSON").action(async (projectId, directory, opts) => {
|
|
5701
|
+
const files = readGameDirectory(directory);
|
|
5702
|
+
const result = await run(
|
|
5703
|
+
`Uploading ${files.length} files\u2026`,
|
|
5704
|
+
() => makeClient().arcade.write(agentId2(opts.agent), projectId, {
|
|
5705
|
+
files,
|
|
5706
|
+
replaceFiles: Boolean(opts.replace),
|
|
5707
|
+
entryFile: opts.entry,
|
|
5708
|
+
thumbnail: opts.thumbnail,
|
|
5709
|
+
runtime: opts.runtime ? { entryFile: opts.runtime } : void 0
|
|
5710
|
+
})
|
|
5711
|
+
);
|
|
5712
|
+
if (opts.json) return jsonOut(result.data);
|
|
5713
|
+
console.log(`${sym.ok} Saved revision ${result.data.revision}.`);
|
|
5714
|
+
detail([["Studio", result.data.studioUrl]]);
|
|
5715
|
+
});
|
|
5716
|
+
command.command("test <projectId>").description("Run Arcade's validation and runtime harness").option("--agent <agentId>", "Agent ID").option("--steps <n>", "Steps to simulate", (value) => Number(value)).option("--seed <seed>", "Deterministic seed").action(async (projectId, opts) => {
|
|
5717
|
+
const result = await run(
|
|
5718
|
+
"Testing game\u2026",
|
|
5719
|
+
() => makeClient().arcade.test(agentId2(opts.agent), projectId, {
|
|
5720
|
+
steps: opts.steps,
|
|
5721
|
+
seed: opts.seed
|
|
5722
|
+
})
|
|
5723
|
+
);
|
|
5724
|
+
jsonOut(result.data);
|
|
5725
|
+
});
|
|
5726
|
+
command.command("publish <projectId>").description("Publish an Arcade game as an immutable release").option("--agent <agentId>", "Agent ID").option("--json", "Output as JSON").action(async (projectId, opts) => {
|
|
5727
|
+
const result = await run(
|
|
5728
|
+
"Publishing game\u2026",
|
|
5729
|
+
() => makeClient().arcade.publish(agentId2(opts.agent), projectId)
|
|
5730
|
+
);
|
|
5731
|
+
if (opts.json) return jsonOut(result.data);
|
|
5732
|
+
console.log(`
|
|
5733
|
+
${sym.ok} Game published.`);
|
|
5734
|
+
detail([
|
|
5735
|
+
["Release", result.data.releaseId],
|
|
5736
|
+
["Play", result.data.gameUrl],
|
|
5737
|
+
["Studio", result.data.studioUrl]
|
|
5738
|
+
]);
|
|
5739
|
+
});
|
|
5740
|
+
return command;
|
|
5741
|
+
}
|
|
5742
|
+
|
|
5743
|
+
// src/commands/api-keys.ts
|
|
5744
|
+
var import_commander22 = require("commander");
|
|
5168
5745
|
async function resolveProject(projectId) {
|
|
5169
5746
|
const projects = (await makeClient().developer.listProjects()).data;
|
|
5170
5747
|
const project = projectId ? projects.find((candidate) => candidate.id === projectId) : projects[0];
|
|
@@ -5176,7 +5753,7 @@ async function resolveProject(projectId) {
|
|
|
5176
5753
|
return project;
|
|
5177
5754
|
}
|
|
5178
5755
|
function apiKeysCommand() {
|
|
5179
|
-
const command = new
|
|
5756
|
+
const command = new import_commander22.Command("keys").alias("api-keys").description("Create and manage project-scoped developer API keys");
|
|
5180
5757
|
command.command("list", { isDefault: true }).alias("ls").description("List API keys for a developer project").option("--project <projectId>", "Developer project ID (defaults to newest)").option("--json", "Output as JSON").action(async (opts) => {
|
|
5181
5758
|
const spinner = spin("Fetching developer keys\u2026");
|
|
5182
5759
|
try {
|
|
@@ -5330,6 +5907,96 @@ ${sym.ok} Developer project created.`);
|
|
|
5330
5907
|
return command;
|
|
5331
5908
|
}
|
|
5332
5909
|
|
|
5910
|
+
// src/commands/provenance.ts
|
|
5911
|
+
var import_commander23 = require("commander");
|
|
5912
|
+
function printTrajectory(trajectory) {
|
|
5913
|
+
const sources = trajectory.events.flatMap(
|
|
5914
|
+
(event) => event.metadata?.lineage?.sources ?? []
|
|
5915
|
+
);
|
|
5916
|
+
const delegates = trajectory.events.flatMap(
|
|
5917
|
+
(event) => event.metadata?.lineage?.delegation ? [event.metadata.lineage.delegation] : []
|
|
5918
|
+
);
|
|
5919
|
+
const matches = trajectory.events.flatMap(
|
|
5920
|
+
(event) => event.metadata?.lineage?.library?.results ?? []
|
|
5921
|
+
);
|
|
5922
|
+
section("Provenance report");
|
|
5923
|
+
detail([
|
|
5924
|
+
["Runs", String(trajectory.summary?.runs ?? trajectory.runs?.length ?? 0)],
|
|
5925
|
+
[
|
|
5926
|
+
"Events",
|
|
5927
|
+
String(trajectory.summary?.events ?? trajectory.events?.length ?? 0)
|
|
5928
|
+
],
|
|
5929
|
+
[
|
|
5930
|
+
"Model / tool calls",
|
|
5931
|
+
`${trajectory.summary?.modelCalls ?? 0} / ${trajectory.summary?.toolCalls ?? 0}`
|
|
5932
|
+
],
|
|
5933
|
+
["Sources", String(sources.length)],
|
|
5934
|
+
["Agent delegations", String(delegates.length)],
|
|
5935
|
+
["Library matches", String(matches.length)],
|
|
5936
|
+
["Dropped events", String(trajectory.summary?.droppedEvents ?? 0)]
|
|
5937
|
+
]);
|
|
5938
|
+
if (sources.length) {
|
|
5939
|
+
section("Web sources");
|
|
5940
|
+
for (const source of sources)
|
|
5941
|
+
console.log(
|
|
5942
|
+
` ${c.primary(source.domain)} ${source.title ?? ""}
|
|
5943
|
+
${c.dim(source.url)}`
|
|
5944
|
+
);
|
|
5945
|
+
}
|
|
5946
|
+
if (delegates.length) {
|
|
5947
|
+
section("Agent contributions");
|
|
5948
|
+
for (const item of delegates)
|
|
5949
|
+
console.log(
|
|
5950
|
+
` ${item.fromAgentId ?? "workflow"} \u2192 ${c.primary(item.toAgentId)} ${c.dim(item.role ?? "")}`
|
|
5951
|
+
);
|
|
5952
|
+
}
|
|
5953
|
+
if (matches.length) {
|
|
5954
|
+
section("Library matches");
|
|
5955
|
+
for (const item of matches)
|
|
5956
|
+
console.log(
|
|
5957
|
+
` ${c.primary(`${item.percentageMatch}%`)} ${item.name ?? item.itemId} ${c.dim(`#${item.rank}`)}`
|
|
5958
|
+
);
|
|
5959
|
+
}
|
|
5960
|
+
}
|
|
5961
|
+
function provenanceCommand() {
|
|
5962
|
+
const cmd = new import_commander23.Command("provenance").description(
|
|
5963
|
+
"Inspect and export provenance and attribution trails"
|
|
5964
|
+
);
|
|
5965
|
+
cmd.command("session <sessionId>").description("Show a plain-language sources and contributors report").option("--json", "Output the complete machine-readable trajectory").action(async (sessionId, opts) => {
|
|
5966
|
+
const spinner = spin("Building provenance report\u2026");
|
|
5967
|
+
try {
|
|
5968
|
+
const { data } = await makeClient().provenance.session(sessionId);
|
|
5969
|
+
spinner.stop();
|
|
5970
|
+
if (opts.json) return jsonOut(data);
|
|
5971
|
+
printTrajectory(data);
|
|
5972
|
+
} catch (error) {
|
|
5973
|
+
spinner.stop();
|
|
5974
|
+
printError(error);
|
|
5975
|
+
process.exitCode = 1;
|
|
5976
|
+
}
|
|
5977
|
+
});
|
|
5978
|
+
cmd.command("workflow <executionId>").description("Show provenance for a workflow execution").option("--json", "Output the complete machine-readable trajectory").action(async (executionId, opts) => {
|
|
5979
|
+
const spinner = spin("Building workflow provenance report\u2026");
|
|
5980
|
+
try {
|
|
5981
|
+
const { data } = await makeClient().provenance.scope(
|
|
5982
|
+
"workflow",
|
|
5983
|
+
executionId
|
|
5984
|
+
);
|
|
5985
|
+
spinner.stop();
|
|
5986
|
+
if (opts.json) return jsonOut(data);
|
|
5987
|
+
printTrajectory(data);
|
|
5988
|
+
} catch (error) {
|
|
5989
|
+
spinner.stop();
|
|
5990
|
+
printError(error);
|
|
5991
|
+
process.exitCode = 1;
|
|
5992
|
+
}
|
|
5993
|
+
});
|
|
5994
|
+
cmd.command("bundle <traceId>").description("Export the standards-based EAA provenance bundle as JSON").action(
|
|
5995
|
+
async (traceId) => jsonOut((await makeClient().provenance.bundle(traceId)).data)
|
|
5996
|
+
);
|
|
5997
|
+
return cmd;
|
|
5998
|
+
}
|
|
5999
|
+
|
|
5333
6000
|
// src/bin.ts
|
|
5334
6001
|
async function interactiveMenu() {
|
|
5335
6002
|
banner();
|
|
@@ -5337,9 +6004,15 @@ async function interactiveMenu() {
|
|
|
5337
6004
|
const isSetup = !!((cfg.accessToken || cfg.apiKey || cfg.sessionToken) && (cfg.userId || cfg.initiator));
|
|
5338
6005
|
if (!isSetup) {
|
|
5339
6006
|
console.log(c.bold(" Welcome to Agent Commons CLI!"));
|
|
5340
|
-
console.log(
|
|
5341
|
-
|
|
5342
|
-
|
|
6007
|
+
console.log(
|
|
6008
|
+
c.dim(
|
|
6009
|
+
" Looks like this is your first time here \u2014 let's get you set up.\n"
|
|
6010
|
+
)
|
|
6011
|
+
);
|
|
6012
|
+
console.log(
|
|
6013
|
+
` ${sym.arrow} Running ${c.bold("agc login")} to configure your credentials\u2026
|
|
6014
|
+
`
|
|
6015
|
+
);
|
|
5343
6016
|
runSubcommand(["login"]);
|
|
5344
6017
|
return;
|
|
5345
6018
|
}
|
|
@@ -5350,7 +6023,11 @@ async function interactiveMenu() {
|
|
|
5350
6023
|
const action = await select("What would you like to do?", [
|
|
5351
6024
|
{ label: "Chat with an agent", value: "chat", hint: "agc chat" },
|
|
5352
6025
|
{ label: "Run an agent (one-shot)", value: "run", hint: "agc run" },
|
|
5353
|
-
{
|
|
6026
|
+
{
|
|
6027
|
+
label: "Manage an agent cloud computer",
|
|
6028
|
+
value: "computer",
|
|
6029
|
+
hint: "agc computer status"
|
|
6030
|
+
},
|
|
5354
6031
|
{ label: "View sessions", value: "sessions", hint: "agc sessions list" },
|
|
5355
6032
|
{ label: "Manage agents", value: "agents", hint: "agc agents list" },
|
|
5356
6033
|
{ label: "Tasks", value: "tasks", hint: "agc task list" },
|
|
@@ -5370,19 +6047,19 @@ async function interactiveMenu() {
|
|
|
5370
6047
|
process.exit(0);
|
|
5371
6048
|
}
|
|
5372
6049
|
const needsAgent = action === "chat" || action === "run" || action === "computer";
|
|
5373
|
-
const
|
|
5374
|
-
if (needsAgent && !
|
|
6050
|
+
const agentId3 = needsAgent ? cfg.defaultAgentId ?? await pickAgentInteractively(action) : void 0;
|
|
6051
|
+
if (needsAgent && !agentId3) return;
|
|
5375
6052
|
if (action === "run") {
|
|
5376
6053
|
const prompt = await askPrompt("Enter your prompt:");
|
|
5377
6054
|
if (!prompt) return;
|
|
5378
|
-
runSubcommand(["run", "--agent",
|
|
6055
|
+
runSubcommand(["run", "--agent", agentId3, prompt]);
|
|
5379
6056
|
return;
|
|
5380
6057
|
}
|
|
5381
6058
|
const commandMap = {
|
|
5382
|
-
chat: ["chat", "--agent",
|
|
6059
|
+
chat: ["chat", "--agent", agentId3],
|
|
5383
6060
|
run: [],
|
|
5384
6061
|
// handled above
|
|
5385
|
-
computer: ["computer", "status", "--agent",
|
|
6062
|
+
computer: ["computer", "status", "--agent", agentId3],
|
|
5386
6063
|
sessions: ["sessions", "list"],
|
|
5387
6064
|
agents: ["agents", "list"],
|
|
5388
6065
|
tasks: ["task", "list"],
|
|
@@ -5403,7 +6080,10 @@ async function interactiveMenu() {
|
|
|
5403
6080
|
async function askPrompt(question) {
|
|
5404
6081
|
const { createInterface: createInterface3 } = await import("readline");
|
|
5405
6082
|
return new Promise((resolve2) => {
|
|
5406
|
-
const rl = createInterface3({
|
|
6083
|
+
const rl = createInterface3({
|
|
6084
|
+
input: process.stdin,
|
|
6085
|
+
output: process.stdout
|
|
6086
|
+
});
|
|
5407
6087
|
process.stdout.write(`
|
|
5408
6088
|
${c.bold(question)}
|
|
5409
6089
|
${c.primary("\u203A")} `);
|
|
@@ -5431,26 +6111,35 @@ async function pickAgentInteractively(action) {
|
|
|
5431
6111
|
spinner.stop();
|
|
5432
6112
|
} catch {
|
|
5433
6113
|
spinner.stop();
|
|
5434
|
-
console.log(
|
|
6114
|
+
console.log(
|
|
6115
|
+
`
|
|
5435
6116
|
${c.warn("\u26A0")} Could not fetch agents. Check your sign-in and connection.
|
|
5436
|
-
`
|
|
6117
|
+
`
|
|
6118
|
+
);
|
|
5437
6119
|
return null;
|
|
5438
6120
|
}
|
|
5439
6121
|
if (agents.length === 0) {
|
|
5440
6122
|
console.log(`
|
|
5441
6123
|
${c.warn("\u26A0")} You don't have any agents yet.
|
|
5442
6124
|
`);
|
|
5443
|
-
const choice = await select(
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
|
|
6125
|
+
const choice = await select(
|
|
6126
|
+
"What would you like to do?",
|
|
6127
|
+
[
|
|
6128
|
+
{
|
|
6129
|
+
label: "Create a new agent now",
|
|
6130
|
+
value: "create",
|
|
6131
|
+
hint: "agc agents create"
|
|
6132
|
+
},
|
|
6133
|
+
{ label: "Go back", value: "cancel" }
|
|
6134
|
+
]
|
|
6135
|
+
);
|
|
5447
6136
|
if (choice === "create") {
|
|
5448
6137
|
runSubcommand(["agents", "create"]);
|
|
5449
6138
|
}
|
|
5450
6139
|
return null;
|
|
5451
6140
|
}
|
|
5452
6141
|
console.log();
|
|
5453
|
-
const
|
|
6142
|
+
const agentId3 = await select(
|
|
5454
6143
|
action === "computer" ? "Choose the agent whose cloud computer you want to manage:" : `Choose an agent to ${action} with:`,
|
|
5455
6144
|
agents.map((a) => ({
|
|
5456
6145
|
label: a.name,
|
|
@@ -5463,15 +6152,17 @@ async function pickAgentInteractively(action) {
|
|
|
5463
6152
|
{ label: "No \u2014 just this once", value: false }
|
|
5464
6153
|
]);
|
|
5465
6154
|
if (saveDefault) {
|
|
5466
|
-
saveConfig({ defaultAgentId:
|
|
5467
|
-
const chosen = agents.find((a) => a.agentId ===
|
|
5468
|
-
console.log(
|
|
5469
|
-
`)
|
|
6155
|
+
saveConfig({ defaultAgentId: agentId3 });
|
|
6156
|
+
const chosen = agents.find((a) => a.agentId === agentId3);
|
|
6157
|
+
console.log(
|
|
6158
|
+
` ${sym.ok} ${c.dim("Default agent set to")} ${c.bold(chosen?.name ?? agentId3)}
|
|
6159
|
+
`
|
|
6160
|
+
);
|
|
5470
6161
|
}
|
|
5471
|
-
return
|
|
6162
|
+
return agentId3;
|
|
5472
6163
|
}
|
|
5473
|
-
var program = new
|
|
5474
|
-
program.name("agc").description("Agent Commons CLI \u2014 interact with the Agent Commons platform").version("0.
|
|
6164
|
+
var program = new import_commander24.Command();
|
|
6165
|
+
program.name("agc").description("Agent Commons CLI \u2014 interact with the Agent Commons platform").version("0.6.1", "-v, --version").showHelpAfterError("(run `agc --help` for usage)").configureHelp({
|
|
5475
6166
|
sortOptions: true,
|
|
5476
6167
|
sortSubcommands: true
|
|
5477
6168
|
}).addHelpText(
|
|
@@ -5489,7 +6180,8 @@ Docs: https://docs.agentcommons.io/docs/cli
|
|
|
5489
6180
|
await interactiveMenu();
|
|
5490
6181
|
});
|
|
5491
6182
|
program.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
5492
|
-
if (actionCommand.name() === "login" || actionCommand.name() === "logout")
|
|
6183
|
+
if (actionCommand.name() === "login" || actionCommand.name() === "logout")
|
|
6184
|
+
return;
|
|
5493
6185
|
await ensureAccessToken();
|
|
5494
6186
|
});
|
|
5495
6187
|
program.addCommand(loginCommand());
|
|
@@ -5502,7 +6194,9 @@ program.addCommand(toolsCommand());
|
|
|
5502
6194
|
program.addCommand(connectionsCommand());
|
|
5503
6195
|
program.addCommand(libraryCommand());
|
|
5504
6196
|
program.addCommand(projectsCommand());
|
|
6197
|
+
program.addCommand(arcadeCommand());
|
|
5505
6198
|
program.addCommand(apiKeysCommand());
|
|
6199
|
+
program.addCommand(provenanceCommand());
|
|
5506
6200
|
program.addCommand(workflowCommand());
|
|
5507
6201
|
program.addCommand(taskCommand());
|
|
5508
6202
|
program.addCommand(runCommand());
|
|
@@ -5527,8 +6221,10 @@ program.on("command:*", () => {
|
|
|
5527
6221
|
process.exit(1);
|
|
5528
6222
|
});
|
|
5529
6223
|
program.parseAsync(process.argv).catch((error) => {
|
|
5530
|
-
console.error(
|
|
6224
|
+
console.error(
|
|
6225
|
+
`
|
|
5531
6226
|
${sym.fail} ${c.error(error instanceof Error ? error.message : String(error))}
|
|
5532
|
-
`
|
|
6227
|
+
`
|
|
6228
|
+
);
|
|
5533
6229
|
process.exitCode = 1;
|
|
5534
6230
|
});
|