@agent-commons/cli 0.1.18 → 0.2.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.
Files changed (2) hide show
  1. package/dist/bin.js +498 -63
  2. package/package.json +2 -2
package/dist/bin.js CHANGED
@@ -45,10 +45,14 @@ var CONFIG_DIR = (0, import_path.join)((0, import_os.homedir)(), ".agc");
45
45
  var CONFIG_FILE = (0, import_path.join)(CONFIG_DIR, "config.json");
46
46
  var DEFAULT_API_URL = process.env.AGC_API_URL ?? "https://api.agentcommons.io";
47
47
  var DEFAULT_APP_URL = "https://www.agentcommons.io";
48
+ var DEFAULT_IDENTITY_URL = process.env.COMMONS_IDENTITY_URL ?? "https://auth.agentcommons.io";
49
+ var DEFAULT_IDENTITY_CLIENT_ID = process.env.COMMONS_IDENTITY_CLIENT_ID ?? "commons-cli";
48
50
  function loadConfig() {
49
51
  const fromEnv = {
50
52
  ...process.env.AGC_API_URL && { apiUrl: process.env.AGC_API_URL },
51
53
  ...process.env.AGC_API_KEY && { apiKey: process.env.AGC_API_KEY },
54
+ ...process.env.COMMONS_ACCESS_TOKEN && { accessToken: process.env.COMMONS_ACCESS_TOKEN },
55
+ ...process.env.COMMONS_IDENTITY_URL && { identityUrl: process.env.COMMONS_IDENTITY_URL },
52
56
  ...process.env.AGC_INITIATOR && { initiator: process.env.AGC_INITIATOR },
53
57
  ...process.env.AGC_AGENT_ID && { defaultAgentId: process.env.AGC_AGENT_ID }
54
58
  };
@@ -61,6 +65,8 @@ function loadConfig() {
61
65
  }
62
66
  return {
63
67
  apiUrl: DEFAULT_API_URL,
68
+ identityUrl: DEFAULT_IDENTITY_URL,
69
+ identityClientId: DEFAULT_IDENTITY_CLIENT_ID,
64
70
  ...fromFile,
65
71
  ...fromEnv
66
72
  };
@@ -73,17 +79,65 @@ function saveConfig(updates) {
73
79
  }
74
80
  function clearConfig() {
75
81
  if ((0, import_fs.existsSync)(CONFIG_FILE)) {
76
- (0, import_fs.writeFileSync)(CONFIG_FILE, JSON.stringify({ apiUrl: DEFAULT_API_URL }, null, 2));
82
+ (0, import_fs.writeFileSync)(
83
+ CONFIG_FILE,
84
+ JSON.stringify(
85
+ {
86
+ apiUrl: DEFAULT_API_URL,
87
+ identityUrl: DEFAULT_IDENTITY_URL,
88
+ identityClientId: DEFAULT_IDENTITY_CLIENT_ID
89
+ },
90
+ null,
91
+ 2
92
+ ),
93
+ { mode: 384 }
94
+ );
77
95
  }
78
96
  }
79
97
  function makeClient(overrides) {
80
98
  const cfg = { ...loadConfig(), ...overrides };
81
99
  return new import_sdk.CommonsClient({
82
100
  baseUrl: cfg.apiUrl,
83
- apiKey: cfg.apiKey,
84
- initiator: cfg.initiator
101
+ apiKey: cfg.accessToken ?? cfg.apiKey,
102
+ initiator: cfg.userId ?? cfg.initiator
85
103
  });
86
104
  }
105
+ function decodeJwtPayload(token) {
106
+ const [, payload] = token.split(".");
107
+ if (!payload) return {};
108
+ try {
109
+ return JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
110
+ } catch {
111
+ return {};
112
+ }
113
+ }
114
+ async function ensureAccessToken() {
115
+ const cfg = loadConfig();
116
+ if (cfg.apiKey && !cfg.sessionToken) return cfg;
117
+ if (cfg.accessToken && cfg.accessTokenExpiresAt && cfg.accessTokenExpiresAt > Date.now() + 3e4) {
118
+ return cfg;
119
+ }
120
+ if (!cfg.sessionToken || !cfg.identityUrl) return cfg;
121
+ const response = await fetch(
122
+ `${cfg.identityUrl.replace(/\/$/, "")}/api/auth/token`,
123
+ { headers: { Authorization: `Bearer ${cfg.sessionToken}` } }
124
+ );
125
+ if (!response.ok) {
126
+ throw new Error("Your Commons login has expired. Run `agc login` again.");
127
+ }
128
+ const data = await response.json();
129
+ if (!data.token) throw new Error("Commons Identity did not return an access token.");
130
+ const claims = decodeJwtPayload(data.token);
131
+ const updates = {
132
+ accessToken: data.token,
133
+ accessTokenExpiresAt: typeof claims.exp === "number" ? claims.exp * 1e3 : Date.now() + 10 * 60 * 1e3,
134
+ userId: typeof claims.sub === "string" ? claims.sub : cfg.userId,
135
+ workspaceId: typeof claims.workspace_id === "string" ? claims.workspace_id : cfg.workspaceId,
136
+ initiator: typeof claims.sub === "string" ? claims.sub : cfg.initiator
137
+ };
138
+ saveConfig(updates);
139
+ return { ...cfg, ...updates };
140
+ }
87
141
 
88
142
  // src/ui.ts
89
143
  var import_chalk = __toESM(require("chalk"));
@@ -106,7 +160,7 @@ var sym = {
106
160
  bullet: import_chalk.default.dim("\u2022"),
107
161
  dot: import_chalk.default.dim("\xB7")
108
162
  };
109
- function banner(version = "0.1.18") {
163
+ function banner(version = "0.2.1") {
110
164
  const line = import_chalk.default.cyan(" \u2500".padEnd(2) + "\u2500".repeat(44));
111
165
  console.log("");
112
166
  console.log(line);
@@ -282,14 +336,14 @@ function prompt(question, hidden = false) {
282
336
  }
283
337
  function loginCommand() {
284
338
  const cmd = new import_commander.Command("login").description("Configure API credentials");
285
- cmd.option("--api-url <url>", "API base URL", DEFAULT_API_URL).option("--api-key <key>", "API key (or set AGC_API_KEY env var)").option("--initiator <id>", "User/initiator ID (advanced \u2014 usually auto-detected)").action(async (opts) => {
339
+ cmd.option("--api-url <url>", "API base URL", DEFAULT_API_URL).option("--identity-url <url>", "Commons Identity URL", DEFAULT_IDENTITY_URL).option("--api-key <key>", "API key (or set AGC_API_KEY env var)").option("--initiator <id>", "User/initiator ID (advanced \u2014 usually auto-detected)").action(async (opts) => {
286
340
  try {
287
341
  const current = loadConfig();
288
342
  const isFirstRun = !(0, import_fs2.existsSync)(CONFIG_FILE2);
289
343
  banner();
290
344
  if (isFirstRun) {
291
345
  console.log(c.bold(" Welcome to Agent Commons CLI!"));
292
- console.log(c.dim(" You just need an API key to get started.\n"));
346
+ console.log(c.dim(" Sign in once with your Commons account to get started.\n"));
293
347
  } else {
294
348
  console.log(c.bold(" Update your credentials"));
295
349
  console.log(c.dim(" Press Enter to keep existing values.\n"));
@@ -308,7 +362,74 @@ function loginCommand() {
308
362
  }
309
363
  const appUrl = apiUrl.includes("localhost") ? "http://localhost:3000" : DEFAULT_APP_URL;
310
364
  const apiKeysUrl = `${appUrl}/settings/api-keys`;
311
- step(1, 1, "API Key");
365
+ if (!opts.apiKey) {
366
+ step(1, 1, "Commons account");
367
+ const identityUrl = String(opts.identityUrl).replace(/\/$/, "");
368
+ const clientId = DEFAULT_IDENTITY_CLIENT_ID;
369
+ const deviceResponse = await fetch(`${identityUrl}/api/auth/device/code`, {
370
+ method: "POST",
371
+ headers: { "Content-Type": "application/json" },
372
+ body: JSON.stringify({
373
+ client_id: clientId,
374
+ scope: "openid profile email offline_access agents:read agents:write agents:run compute:read compute:write activity:read usage:read"
375
+ })
376
+ });
377
+ const device = await deviceResponse.json();
378
+ if (!deviceResponse.ok || !device.device_code || !device.user_code) {
379
+ throw new Error(device.error_description || "Could not start Commons login.");
380
+ }
381
+ const verificationUrl = device.verification_uri_complete ?? `${identityUrl}/device?user_code=${encodeURIComponent(device.user_code)}`;
382
+ console.log(` ${c.dim("Authorize this CLI in your browser:")}`);
383
+ console.log(` ${c.primary(verificationUrl)}`);
384
+ console.log(` ${c.dim("Code:")} ${c.bold(device.user_code)}
385
+ `);
386
+ openBrowser(verificationUrl);
387
+ const deadline = Date.now() + (device.expires_in ?? 600) * 1e3;
388
+ let intervalMs = Math.max(device.interval ?? 5, 1) * 1e3;
389
+ let sessionToken;
390
+ while (Date.now() < deadline) {
391
+ await new Promise((resolve2) => setTimeout(resolve2, intervalMs));
392
+ const tokenResponse = await fetch(`${identityUrl}/api/auth/device/token`, {
393
+ method: "POST",
394
+ headers: { "Content-Type": "application/json" },
395
+ body: JSON.stringify({
396
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code",
397
+ device_code: device.device_code,
398
+ client_id: clientId
399
+ })
400
+ });
401
+ const token = await tokenResponse.json();
402
+ if (tokenResponse.ok && token.access_token) {
403
+ sessionToken = token.access_token;
404
+ break;
405
+ }
406
+ if (token.error === "slow_down") {
407
+ intervalMs += 1e3;
408
+ continue;
409
+ }
410
+ if (token.error === "authorization_pending") continue;
411
+ throw new Error(token.error_description || token.error || "Commons login failed.");
412
+ }
413
+ if (!sessionToken) throw new Error("Commons login expired before approval.");
414
+ saveConfig({
415
+ apiUrl,
416
+ identityUrl,
417
+ identityClientId: clientId,
418
+ sessionToken,
419
+ accessToken: void 0,
420
+ accessTokenExpiresAt: void 0,
421
+ apiKey: void 0
422
+ });
423
+ const authenticated = await ensureAccessToken();
424
+ console.log(
425
+ ` ${sym.ok} ${c.success("Signed in")} as ${c.id(authenticated.userId ?? "Commons user")}`
426
+ );
427
+ console.log(`
428
+ ${sym.ok} ${c.success("All set!")} Credentials saved to ${c.dim("~/.agc/config.json")}
429
+ `);
430
+ return;
431
+ }
432
+ step(1, 1, "Legacy API Key");
312
433
  let apiKey = opts.apiKey;
313
434
  if (!apiKey) {
314
435
  console.log(` ${c.dim("You'll need an API key from your Agent Commons account.")}`);
@@ -377,15 +498,22 @@ function whoamiCommand() {
377
498
  return new import_commander.Command("whoami").description("Show current configuration and verify API connectivity").option("--json", "Output as JSON").action(async (opts) => {
378
499
  const cfg = loadConfig();
379
500
  if (opts.json) {
380
- console.log(JSON.stringify({ apiUrl: cfg.apiUrl, initiator: cfg.initiator, hasApiKey: !!cfg.apiKey }, null, 2));
501
+ console.log(JSON.stringify({
502
+ apiUrl: cfg.apiUrl,
503
+ identityUrl: cfg.identityUrl,
504
+ userId: cfg.userId ?? cfg.initiator,
505
+ workspaceId: cfg.workspaceId,
506
+ authenticated: Boolean(cfg.sessionToken || cfg.apiKey)
507
+ }, null, 2));
381
508
  return;
382
509
  }
383
510
  console.log(`
384
511
  ${c.bold("Current configuration")}`);
385
512
  detail([
386
513
  ["API URL", cfg.apiUrl],
387
- ["Initiator", cfg.initiator ?? c.dim("(not set)")],
388
- ["API Key", cfg.apiKey ? `****${cfg.apiKey.slice(-4)}` : c.dim("(not set)")],
514
+ ["Identity", cfg.userId ?? cfg.initiator ?? c.dim("(not set)")],
515
+ ["Workspace", cfg.workspaceId ?? c.dim("(not set)")],
516
+ ["Auth", cfg.sessionToken ? "Commons account" : cfg.apiKey ? "Legacy API key" : c.dim("(not set)")],
389
517
  ["Agent ID", cfg.defaultAgentId ?? c.dim("(not set)")]
390
518
  ]);
391
519
  try {
@@ -482,7 +610,7 @@ function agentsCommand() {
482
610
  process.exit(1);
483
611
  }
484
612
  });
485
- cmd.command("create").description("Create a new agent").requiredOption("--name <name>", "Agent name").option("--instructions <text>", "System instructions").option("--provider <provider>", "Model provider (openai|anthropic|google|groq)", "openai").option("--model <id>", "Model ID", "gpt-4o").option("--json", "Output as JSON").action(async (opts) => {
613
+ cmd.command("create").description("Create a new agent").requiredOption("--name <name>", "Agent name").option("--instructions <text>", "System instructions").option("--provider <provider>", "Model provider (openai|anthropic|google|groq|openrouter|xai|ollama|custom)", "openai").option("--model <id>", "Model ID", "gpt-5.4-mini").option("--model-api-key <key>", "Provider API key (BYOK)").option("--model-base-url <url>", "Base URL for custom or local OpenAI-compatible providers").option("--json", "Output as JSON").action(async (opts) => {
486
614
  const cfg = loadConfig();
487
615
  if (!cfg.initiator) {
488
616
  console.error(c.error("No initiator set. Run `agc login` first."));
@@ -496,7 +624,9 @@ function agentsCommand() {
496
624
  instructions: opts.instructions,
497
625
  owner: cfg.initiator,
498
626
  modelProvider: opts.provider,
499
- modelId: opts.model
627
+ modelId: opts.model,
628
+ modelApiKey: opts.modelApiKey,
629
+ modelBaseUrl: opts.modelBaseUrl
500
630
  });
501
631
  const agent = res?.data ?? res;
502
632
  spinner.stop();
@@ -645,7 +775,7 @@ function sessionsCommand() {
645
775
  process.exit(1);
646
776
  }
647
777
  });
648
- 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-4o, claude-sonnet-4-6)").option("--provider <provider>", "Model provider").option("--json", "Output as JSON").action(async (opts) => {
778
+ 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) => {
649
779
  const cfg = loadConfig();
650
780
  const agentId = opts.agent ?? cfg.defaultAgentId;
651
781
  if (!agentId) {
@@ -685,8 +815,50 @@ ${sym.ok} Session created`);
685
815
 
686
816
  // src/commands/tools.ts
687
817
  var import_commander4 = require("commander");
818
+ var import_fs3 = require("fs");
688
819
  function toolsCommand() {
689
820
  const cmd = new import_commander4.Command("tools").description("Discover and manage tools");
821
+ cmd.command("create").description("Create a tool from a JSON file").requiredOption("--file <path>", "Path to a JSON tool definition").option("--json", "Output as JSON").action(async (opts) => {
822
+ const cfg = loadConfig();
823
+ if (!cfg.initiator) {
824
+ console.error(c.error("No initiator set. Run `agc login` first."));
825
+ process.exit(1);
826
+ }
827
+ let payload;
828
+ try {
829
+ payload = JSON.parse((0, import_fs3.readFileSync)(opts.file, "utf8"));
830
+ } catch (error) {
831
+ console.error(c.error(`Could not read tool file: ${error.message}`));
832
+ process.exit(1);
833
+ }
834
+ if (!payload.name || !payload.schema) {
835
+ console.error(c.error('Tool file must include at least "name" and "schema".'));
836
+ process.exit(1);
837
+ }
838
+ const spinner = spin("Creating tool\u2026");
839
+ try {
840
+ const client = makeClient();
841
+ const res = await client.tools.create({
842
+ ...payload,
843
+ owner: cfg.initiator,
844
+ ownerType: payload.ownerType ?? "user"
845
+ });
846
+ const tool = res?.data ?? res;
847
+ spinner.stop();
848
+ if (opts.json) return jsonOut(tool);
849
+ console.log(`
850
+ ${sym.ok} Tool created`);
851
+ detail([
852
+ ["Tool ID", c.id(tool.toolId)],
853
+ ["Name", tool.name],
854
+ ["Visibility", tool.visibility ?? payload.visibility ?? "private"]
855
+ ]);
856
+ } catch (err) {
857
+ spinner.stop();
858
+ printError(err);
859
+ process.exit(1);
860
+ }
861
+ });
690
862
  cmd.command("list").description("List available tools").option("--owner <id>", "Filter by owner ID").option("--json", "Output as JSON").action(async (opts) => {
691
863
  const cfg = loadConfig();
692
864
  const spinner = spin("Fetching tools\u2026");
@@ -784,8 +956,37 @@ ${sym.ok} ${c.label(toolName)}`);
784
956
 
785
957
  // src/commands/workflow.ts
786
958
  var import_commander5 = require("commander");
959
+ var import_fs4 = require("fs");
960
+ var import_sdk2 = require("@agent-commons/sdk");
787
961
  function workflowCommand() {
788
962
  const cmd = new import_commander5.Command("workflow").description("Run and monitor workflows").alias("wf");
963
+ async function createTemplateWorkflow(params) {
964
+ const client = makeClient();
965
+ const template = (0, import_sdk2.buildWorkflowTemplate)(params.templateName, params.ctx);
966
+ const toolIds = {};
967
+ const createdTools = [];
968
+ for (const tool of template.tools) {
969
+ const created = await client.tools.create({
970
+ ...tool.payload,
971
+ owner: params.ctx.ownerId,
972
+ ownerType: "user"
973
+ });
974
+ const createdTool = created?.data ?? created;
975
+ toolIds[tool.key] = createdTool.toolId;
976
+ createdTools.push(createdTool);
977
+ }
978
+ const workflow = await client.workflows.create({
979
+ name: template.name,
980
+ description: template.description,
981
+ ownerId: params.ctx.ownerId,
982
+ ownerType: "user",
983
+ isPublic: params.isPublic,
984
+ category: template.category,
985
+ tags: template.tags,
986
+ definition: template.buildDefinition(toolIds, params.ctx)
987
+ });
988
+ return { template, workflow, createdTools };
989
+ }
789
990
  cmd.command("list").description("List workflows owned by the current initiator").option("--json", "Output as JSON").action(async (opts) => {
790
991
  const cfg = loadConfig();
791
992
  if (!cfg.initiator) {
@@ -815,6 +1016,166 @@ function workflowCommand() {
815
1016
  process.exit(1);
816
1017
  }
817
1018
  });
1019
+ cmd.command("create").description("Create a workflow from a JSON file").requiredOption("--file <path>", "Path to a workflow payload or definition JSON file").option("--name <name>", "Workflow name").option("--description <text>", "Workflow description").option("--public", "Make workflow public").option("--json", "Output as JSON").action(async (opts) => {
1020
+ const cfg = loadConfig();
1021
+ if (!cfg.initiator) {
1022
+ console.error(c.error("No initiator set. Run `agc login` first."));
1023
+ process.exit(1);
1024
+ }
1025
+ let fileJson;
1026
+ try {
1027
+ fileJson = JSON.parse((0, import_fs4.readFileSync)(opts.file, "utf8"));
1028
+ } catch (error) {
1029
+ console.error(c.error(`Could not read workflow file: ${error.message}`));
1030
+ process.exit(1);
1031
+ }
1032
+ const definition = fileJson.definition ?? fileJson;
1033
+ if (!Array.isArray(definition.nodes) || !Array.isArray(definition.edges)) {
1034
+ console.error(c.error('Workflow file must include a definition with "nodes" and "edges".'));
1035
+ process.exit(1);
1036
+ }
1037
+ const spinner = spin("Creating workflow\u2026");
1038
+ try {
1039
+ const client = makeClient();
1040
+ const workflow = await client.workflows.create({
1041
+ name: opts.name ?? fileJson.name ?? "CLI Workflow",
1042
+ description: opts.description ?? fileJson.description,
1043
+ definition,
1044
+ ownerId: cfg.initiator,
1045
+ ownerType: "user",
1046
+ isPublic: opts.public ?? fileJson.isPublic,
1047
+ category: fileJson.category,
1048
+ tags: fileJson.tags
1049
+ });
1050
+ spinner.stop();
1051
+ if (opts.json) return jsonOut(workflow);
1052
+ console.log(`
1053
+ ${sym.ok} Workflow created`);
1054
+ detail([
1055
+ ["Workflow ID", c.id(workflow.workflowId)],
1056
+ ["Name", workflow.name],
1057
+ ["Nodes", String((workflow.definition?.nodes ?? []).length)]
1058
+ ]);
1059
+ } catch (err) {
1060
+ spinner.stop();
1061
+ printError(err);
1062
+ process.exit(1);
1063
+ }
1064
+ });
1065
+ const templates = cmd.command("templates").description("Create workflows from built-in templates");
1066
+ templates.command("list").description("List built-in workflow templates").option("--json", "Output as JSON").action((opts) => {
1067
+ const rows = (0, import_sdk2.listWorkflowTemplates)();
1068
+ if (opts.json) return jsonOut(rows);
1069
+ section(`Workflow Templates (${rows.length})`);
1070
+ table(
1071
+ rows.map((template) => ({
1072
+ Name: template.name,
1073
+ Description: template.description
1074
+ })),
1075
+ ["Name", "Description"]
1076
+ );
1077
+ });
1078
+ templates.command("create <templateName>").description("Create a workflow template and its required API tools").option("--prefix <prefix>", "Stable prefix for generated tool/workflow names").option("--agent <agentId>", "Agent ID for agent_processor nodes").option("--reviewer-agent <agentId>", "Second agent ID for multi-agent templates").option("--child-workflow <workflowId>", "Child workflow ID for workflow-invocation-smoke").option("--public", "Make workflow public").option("--run", "Run the workflow after creating it").option("--input <json>", "Run input JSON; defaults to template sample input").option("--json", "Output as JSON").action(async (templateNameRaw, opts) => {
1079
+ const cfg = loadConfig();
1080
+ if (!cfg.initiator) {
1081
+ console.error(c.error("No initiator set. Run `agc login` first."));
1082
+ process.exit(1);
1083
+ }
1084
+ const templateNames = (0, import_sdk2.listWorkflowTemplates)().map((item) => item.name);
1085
+ if (!templateNames.includes(templateNameRaw)) {
1086
+ console.error(c.error(`Unknown template "${templateNameRaw}".`));
1087
+ console.error(c.dim(`Available: ${templateNames.join(", ")}`));
1088
+ process.exit(1);
1089
+ }
1090
+ const templateName = templateNameRaw;
1091
+ const needsAgent = templateName === "agent-research-summary" || templateName === "multi-agent-field-report";
1092
+ const agentId = opts.agent ?? cfg.defaultAgentId;
1093
+ if (needsAgent && !agentId) {
1094
+ console.error(c.error("This template requires --agent <agentId> or a configured defaultAgentId."));
1095
+ process.exit(1);
1096
+ }
1097
+ const prefix = opts.prefix ?? `cli_${templateName.replace(/[^a-z0-9]+/gi, "_")}_${Date.now().toString(36)}`;
1098
+ const spinner = spin("Creating workflow template\u2026");
1099
+ try {
1100
+ let childWorkflowId = opts.childWorkflow;
1101
+ let childResult;
1102
+ if (templateName === "workflow-invocation-smoke" && !childWorkflowId) {
1103
+ const childCtx = {
1104
+ ownerId: cfg.initiator,
1105
+ prefix: `${prefix}_child`
1106
+ };
1107
+ childResult = await createTemplateWorkflow({
1108
+ templateName: "country-weather-brief",
1109
+ ctx: childCtx,
1110
+ isPublic: opts.public
1111
+ });
1112
+ childWorkflowId = childResult.workflow.workflowId;
1113
+ }
1114
+ const ctx = {
1115
+ ownerId: cfg.initiator,
1116
+ prefix,
1117
+ agentId,
1118
+ reviewerAgentId: opts.reviewerAgent,
1119
+ childWorkflowId
1120
+ };
1121
+ const result = await createTemplateWorkflow({
1122
+ templateName,
1123
+ ctx,
1124
+ isPublic: opts.public
1125
+ });
1126
+ let execution;
1127
+ if (opts.run) {
1128
+ let inputData = result.template.sampleInput;
1129
+ if (opts.input) {
1130
+ try {
1131
+ inputData = JSON.parse(opts.input);
1132
+ } catch {
1133
+ throw new Error("--input must be valid JSON");
1134
+ }
1135
+ }
1136
+ execution = await makeClient().workflows.execute(result.workflow.workflowId, {
1137
+ agentId,
1138
+ inputData,
1139
+ userId: cfg.initiator
1140
+ });
1141
+ }
1142
+ spinner.stop();
1143
+ const output = { ...result, child: childResult, execution };
1144
+ if (opts.json) return jsonOut(output);
1145
+ console.log(`
1146
+ ${sym.ok} Workflow template created`);
1147
+ if (childResult) {
1148
+ detail([
1149
+ ["Child workflow", c.id(childResult.workflow.workflowId)],
1150
+ ["Parent workflow", c.id(result.workflow.workflowId)],
1151
+ ["Template", templateName]
1152
+ ]);
1153
+ } else {
1154
+ detail([
1155
+ ["Workflow ID", c.id(result.workflow.workflowId)],
1156
+ ["Template", templateName],
1157
+ ["Tools created", String(result.createdTools.length)]
1158
+ ]);
1159
+ }
1160
+ if (execution) {
1161
+ console.log(`
1162
+ ${sym.ok} Execution started: ${c.id(execution.executionId)}`);
1163
+ console.log(` Status: ${statusBadge(execution.status)}`);
1164
+ const resultData = execution.result ?? execution.outputData;
1165
+ if (resultData !== void 0) {
1166
+ console.log("\n" + c.label("Result"));
1167
+ console.log(" " + JSON.stringify(resultData, null, 2).replace(/\n/g, "\n "));
1168
+ }
1169
+ } else {
1170
+ console.log(c.dim(`
1171
+ Run it with: agc workflow run ${result.workflow.workflowId} --input '${JSON.stringify(result.template.sampleInput)}'`));
1172
+ }
1173
+ } catch (err) {
1174
+ spinner.stop();
1175
+ printError(err);
1176
+ process.exit(1);
1177
+ }
1178
+ });
818
1179
  cmd.command("get <workflowId>").description("Show workflow details").option("--json", "Output as JSON").action(async (workflowId, opts) => {
819
1180
  const spinner = spin("Fetching workflow\u2026");
820
1181
  try {
@@ -1187,7 +1548,7 @@ var import_commander7 = require("commander");
1187
1548
  var readline3 = __toESM(require("readline"));
1188
1549
 
1189
1550
  // src/local-tools.ts
1190
- var import_fs3 = require("fs");
1551
+ var import_fs5 = require("fs");
1191
1552
  var import_path3 = require("path");
1192
1553
  var import_child_process2 = require("child_process");
1193
1554
  var readline2 = __toESM(require("readline"));
@@ -1205,7 +1566,7 @@ function buildDirSnapshot(dir, maxDepth = 2) {
1205
1566
  if (lines.length >= 300) return;
1206
1567
  let entries;
1207
1568
  try {
1208
- entries = (0, import_fs3.readdirSync)(d, { withFileTypes: true });
1569
+ entries = (0, import_fs5.readdirSync)(d, { withFileTypes: true });
1209
1570
  } catch {
1210
1571
  return;
1211
1572
  }
@@ -1235,11 +1596,11 @@ function readFileForContext(rootDir, filePath) {
1235
1596
  for (const pat of [/\/\.ssh\//, /\/\.aws\//, /\/\.env$/, /\/\.env\./, /id_rsa/, /id_ed25519/]) {
1236
1597
  if (pat.test(abs)) return `[error: sensitive path blocked]`;
1237
1598
  }
1238
- if (!(0, import_fs3.existsSync)(abs)) return `[error: file not found: ${filePath}]`;
1239
- const stat = (0, import_fs3.statSync)(abs);
1599
+ if (!(0, import_fs5.existsSync)(abs)) return `[error: file not found: ${filePath}]`;
1600
+ const stat = (0, import_fs5.statSync)(abs);
1240
1601
  if (stat.isDirectory()) return `[error: "${filePath}" is a directory \u2014 use list_directory]`;
1241
1602
  if (stat.size > 1e5) return `[truncated \u2014 file too large (${Math.round(stat.size / 1024)} KB). Use cli_read_file for full content]`;
1242
- return (0, import_fs3.readFileSync)(abs, "utf8");
1603
+ return (0, import_fs5.readFileSync)(abs, "utf8");
1243
1604
  } catch (err) {
1244
1605
  return `[error reading file: ${err?.message}]`;
1245
1606
  }
@@ -1267,11 +1628,12 @@ ${fileSection}
1267
1628
  ### MANDATORY RULES \u2014 READ CAREFULLY
1268
1629
 
1269
1630
  1. **Call cli_* tools immediately and directly.** Do NOT create tasks (createTask) for local file operations. Do NOT delegate to sub-agents. Do NOT ask the user to run commands themselves.
1270
- 2. **Always show the actual output** returned by the tool in your response. Never say "I listed the files" without showing them. Report exactly what the tool returns.
1271
- 3. **Never fabricate results.** Wait for the real tool output before responding.
1272
- 4. **Sensitive paths are blocked** (.ssh, .gnupg, .aws, .env, credentials). Attempting to access them will return an error.
1273
- 5. ${autoApprove ? "**cli_write_file and cli_run_command execute immediately** \u2014 auto-approve is active, no user confirmation is required." : "**cli_write_file and cli_run_command require the user to confirm** before executing \u2014 you will see the result after they approve."}
1274
- 6. **Git commits must carry the agc co-author trailer.** Always include \`--trailer "Co-Authored-By: <AgentName> (agc) <agc-agent@users.noreply.github.com>"\` when running \`git commit\`. The CLI injects this automatically \u2014 do not omit it or pass \`--no-trailer\`.
1631
+ 2. **Own the request through completion.** Continue across tool calls, process polling, retries, debugging, and verification. Do not stop after describing a plan or asking whether to proceed when the request is already clear.
1632
+ 3. **Use actual tool output as evidence.** Summarize the important result; do not fabricate success or dump noisy logs unless they help diagnose a failure.
1633
+ 4. **Never fabricate results.** Wait for the real tool output before responding.
1634
+ 5. **Sensitive paths are blocked** (.ssh, .gnupg, .aws, .env, credentials). Attempting to access them will return an error.
1635
+ 6. ${autoApprove ? "**cli_write_file and cli_run_command execute immediately** \u2014 auto-approve is active, no user confirmation is required." : "**cli_write_file and cli_run_command require the user to confirm** before executing \u2014 you will see the result after they approve."}
1636
+ 7. **Git commits must carry the agc co-author trailer.** Always include \`--trailer "Co-Authored-By: <AgentName> (agc) <agc-agent@users.noreply.github.com>"\` when running \`git commit\`. The CLI injects this automatically \u2014 do not omit it or pass \`--no-trailer\`.
1275
1637
 
1276
1638
  ### Available CLI tools
1277
1639
 
@@ -1304,12 +1666,12 @@ ${fileSection}
1304
1666
 
1305
1667
  For long commands like \`npx create-next-app@latest my-app --yes\`:
1306
1668
 
1307
- 1. Call \`cli_start_process\` \u2014 returns \`{processId, status: "running"}\` immediately. Tell the user it has started.
1308
- 2. Call \`cli_wait_for_process\` with \`{"processId": "...", "wait_seconds": 60}\` \u2014 blocks up to 60s then returns current stdout/status. Report progress to the user.
1309
- 3. Repeat step 2 until \`status\` is \`"done"\` or \`"error"\`.
1310
- 4. Report the final output to the user.
1669
+ 1. Call \`cli_start_process\` \u2014 it returns \`{processId, status: "running"}\` immediately.
1670
+ 2. Call \`cli_wait_for_process\` with \`{"processId": "...", "wait_seconds": 60}\`.
1671
+ 3. Repeat step 2 until \`status\` is \`"done"\` or \`"error"\`; diagnose and repair errors when possible.
1672
+ 4. Continue with the rest of the assignment and verify the final outcome before responding.
1311
1673
 
1312
- Never hold the user in silence. Between each \`cli_wait_for_process\` call, tell them what you saw so far.
1674
+ Do not end the turn merely because a process is still running. Keep polling within the same run. Progress events may be streamed by the client, but the final answer comes only after completion or a genuine blocker.
1313
1675
 
1314
1676
  ### Example \u2014 scaffolding a Next.js project
1315
1677
 
@@ -1317,18 +1679,14 @@ Never hold the user in silence. Between each \`cli_wait_for_process\` call, tell
1317
1679
  cli_start_process: {"command": "npx", "args": ["create-next-app@latest", "my-app", "--yes"], "cwd": "Desktop"}
1318
1680
  \u2192 {processId: "proc_1a2b", status: "running"}
1319
1681
 
1320
- Tell user: "Started! Installing dependencies, this takes a minute or two. Checking in 60s\u2026"
1321
-
1322
1682
  cli_wait_for_process: {"processId": "proc_1a2b", "wait_seconds": 60}
1323
1683
  \u2192 {status: "running", elapsedSec: 60, stdout: "Creating project...
1324
1684
  Installing packages\u2026"}
1325
1685
 
1326
- Tell user: "Still installing \u2014 here's output so far: [stdout]. Checking again\u2026"
1327
-
1328
1686
  cli_wait_for_process: {"processId": "proc_1a2b", "wait_seconds": 60}
1329
1687
  \u2192 {status: "done", exitCode: 0, elapsedSec: 93, stdout: "Success! Created my-app"}
1330
1688
 
1331
- Tell user: "Done! Project created in Desktop/my-app"
1689
+ Continue by running the requested checks and opening/inspecting the app when the assignment requires it.
1332
1690
  \`\`\`
1333
1691
  `;
1334
1692
  }
@@ -1350,6 +1708,65 @@ function injectAgcTrailer(command, args, agentId, agentName) {
1350
1708
  const identity = agentName ? `${agentName} (agc)` : agentId ? `agc/${agentId}` : "agc agent";
1351
1709
  return [...args, "--trailer", `Co-Authored-By: ${identity} <agc-agent@users.noreply.github.com>`];
1352
1710
  }
1711
+ var AGC_HOOK_MARKER = "# agc-session:";
1712
+ var HOOK_BACKUP_SUFFIX = ".agc-backup";
1713
+ function findGitDir(rootDir) {
1714
+ const gitPath = (0, import_path3.join)(rootDir, ".git");
1715
+ if (!(0, import_fs5.existsSync)(gitPath)) return null;
1716
+ const s = (0, import_fs5.statSync)(gitPath);
1717
+ if (s.isDirectory()) return gitPath;
1718
+ if (s.isFile()) {
1719
+ const content = (0, import_fs5.readFileSync)(gitPath, "utf8");
1720
+ const match = content.match(/^gitdir:\s*(.+)$/m);
1721
+ if (match) return match[1].trim();
1722
+ }
1723
+ return null;
1724
+ }
1725
+ function installGitHook(rootDir, sessionId, agentId, agentName) {
1726
+ const gitDir = findGitDir(rootDir);
1727
+ if (!gitDir) return;
1728
+ const hooksDir = (0, import_path3.join)(gitDir, "hooks");
1729
+ (0, import_fs5.mkdirSync)(hooksDir, { recursive: true });
1730
+ const hookPath = (0, import_path3.join)(hooksDir, "prepare-commit-msg");
1731
+ if ((0, import_fs5.existsSync)(hookPath)) {
1732
+ const existing = (0, import_fs5.readFileSync)(hookPath, "utf8");
1733
+ if (!existing.includes(AGC_HOOK_MARKER)) {
1734
+ (0, import_fs5.writeFileSync)(hookPath + HOOK_BACKUP_SUFFIX, existing, { mode: 493 });
1735
+ }
1736
+ }
1737
+ const identity = agentName ? `${agentName} (agc)` : agentId ? `agc/${agentId}` : "agc agent";
1738
+ const trailer = `Co-Authored-By: ${identity} <agc-agent@users.noreply.github.com>`;
1739
+ const chainLine = (0, import_fs5.existsSync)(hookPath + HOOK_BACKUP_SUFFIX) ? `
1740
+ # chain pre-existing hook
1741
+ "$(dirname "$0")/prepare-commit-msg${HOOK_BACKUP_SUFFIX}" "$@" 2>/dev/null || true
1742
+ ` : "";
1743
+ const hook = `#!/bin/sh
1744
+ ${AGC_HOOK_MARKER}${sessionId}
1745
+ COMMIT_MSG_FILE="$1"
1746
+ COMMIT_SOURCE="$2"
1747
+ ${chainLine}
1748
+ case "$COMMIT_SOURCE" in merge|squash) exit 0 ;; esac
1749
+ TRAILER="${trailer}"
1750
+ grep -qF "$TRAILER" "$COMMIT_MSG_FILE" 2>/dev/null && exit 0
1751
+ printf '\\n%s\\n' "$TRAILER" >> "$COMMIT_MSG_FILE"
1752
+ `;
1753
+ (0, import_fs5.writeFileSync)(hookPath, hook, { mode: 493 });
1754
+ }
1755
+ function removeGitHook(rootDir) {
1756
+ const gitDir = findGitDir(rootDir);
1757
+ if (!gitDir) return;
1758
+ const hookPath = (0, import_path3.join)(gitDir, "hooks", "prepare-commit-msg");
1759
+ if (!(0, import_fs5.existsSync)(hookPath)) return;
1760
+ const content = (0, import_fs5.readFileSync)(hookPath, "utf8");
1761
+ if (!content.includes(AGC_HOOK_MARKER)) return;
1762
+ const backupPath = hookPath + HOOK_BACKUP_SUFFIX;
1763
+ if ((0, import_fs5.existsSync)(backupPath)) {
1764
+ (0, import_fs5.writeFileSync)(hookPath, (0, import_fs5.readFileSync)(backupPath, "utf8"), { mode: 493 });
1765
+ (0, import_fs5.unlinkSync)(backupPath);
1766
+ } else {
1767
+ (0, import_fs5.unlinkSync)(hookPath);
1768
+ }
1769
+ }
1353
1770
  function safePath(root, userPath) {
1354
1771
  const abs = (0, import_path3.resolve)(root, userPath);
1355
1772
  const rel = (0, import_path3.relative)(root, abs);
@@ -1450,7 +1867,7 @@ function extractViaCommand(cmd, cmdArgs) {
1450
1867
  }
1451
1868
  async function extractPdfText(abs) {
1452
1869
  try {
1453
- const buffer = (0, import_fs3.readFileSync)(abs);
1870
+ const buffer = (0, import_fs5.readFileSync)(abs);
1454
1871
  const data = await pdfParse(buffer);
1455
1872
  const text2 = data.text?.trim();
1456
1873
  if (text2) {
@@ -1478,8 +1895,8 @@ async function toolReadFile(args, cfg) {
1478
1895
  if (!userPath) throw new Error('read_file requires a "path" argument');
1479
1896
  const abs = safePath(cfg.rootDir, userPath);
1480
1897
  assertNotSensitive(abs);
1481
- if (!(0, import_fs3.existsSync)(abs)) throw new Error(`File not found: ${userPath}`);
1482
- const stat = (0, import_fs3.statSync)(abs);
1898
+ if (!(0, import_fs5.existsSync)(abs)) throw new Error(`File not found: ${userPath}`);
1899
+ const stat = (0, import_fs5.statSync)(abs);
1483
1900
  if (stat.isDirectory()) throw new Error(`"${userPath}" is a directory, not a file`);
1484
1901
  const ext = (0, import_path3.extname)(abs).toLowerCase();
1485
1902
  if (PDF_EXTS.has(ext)) {
@@ -1494,7 +1911,7 @@ async function toolReadFile(args, cfg) {
1494
1911
  throw new Error(`Cannot read binary file "${userPath}" (${ext} format). Only text, PDF, and Office documents are supported.`);
1495
1912
  }
1496
1913
  if (stat.size > 5e5) throw new Error(`File too large to read (${Math.round(stat.size / 1024)} KB). Max 500 KB.`);
1497
- return (0, import_fs3.readFileSync)(abs, "utf8");
1914
+ return (0, import_fs5.readFileSync)(abs, "utf8");
1498
1915
  }
1499
1916
  async function toolWriteFile(args, cfg) {
1500
1917
  const { path: userPath, content } = args;
@@ -1508,16 +1925,16 @@ async function toolWriteFile(args, cfg) {
1508
1925
  "write_file"
1509
1926
  );
1510
1927
  if (!ok) return "User denied write operation.";
1511
- (0, import_fs3.mkdirSync)((0, import_path3.dirname)(abs), { recursive: true });
1512
- (0, import_fs3.writeFileSync)(abs, content, "utf8");
1928
+ (0, import_fs5.mkdirSync)((0, import_path3.dirname)(abs), { recursive: true });
1929
+ (0, import_fs5.writeFileSync)(abs, content, "utf8");
1513
1930
  return `Written ${String(content).length} bytes to ${userPath}`;
1514
1931
  }
1515
1932
  async function toolListDirectory(args, cfg) {
1516
1933
  const userPath = args.path ?? ".";
1517
1934
  const abs = safePath(cfg.rootDir, userPath);
1518
1935
  assertNotSensitive(abs);
1519
- if (!(0, import_fs3.existsSync)(abs)) throw new Error(`Directory not found: ${userPath}`);
1520
- const entries = (0, import_fs3.readdirSync)(abs, { withFileTypes: true });
1936
+ if (!(0, import_fs5.existsSync)(abs)) throw new Error(`Directory not found: ${userPath}`);
1937
+ const entries = (0, import_fs5.readdirSync)(abs, { withFileTypes: true });
1521
1938
  const lines = entries.map((e) => {
1522
1939
  const type = e.isDirectory() ? "d" : e.isSymbolicLink() ? "l" : "f";
1523
1940
  return `[${type}] ${e.name}`;
@@ -1537,7 +1954,7 @@ async function toolSearchFiles(args, cfg) {
1537
1954
  function walk(dir, depth = 0) {
1538
1955
  if (results.length >= 50 || depth > 10) return;
1539
1956
  try {
1540
- for (const entry of (0, import_fs3.readdirSync)(dir, { withFileTypes: true })) {
1957
+ for (const entry of (0, import_fs5.readdirSync)(dir, { withFileTypes: true })) {
1541
1958
  if (entry.name.startsWith(".") && depth > 0) continue;
1542
1959
  const full = (0, import_path3.join)(dir, entry.name);
1543
1960
  const rel = (0, import_path3.relative)(cfg.rootDir, full);
@@ -1841,7 +2258,7 @@ function runCommand() {
1841
2258
  ...cfg.initiator && { initiatorId: cfg.initiator },
1842
2259
  ...cliContext && { cliContext }
1843
2260
  };
1844
- if (opts.noStream) {
2261
+ if (opts.noStream && !localEnabled) {
1845
2262
  const spinner = spin("Running\u2026");
1846
2263
  try {
1847
2264
  const result = await client.run.once(params);
@@ -1917,7 +2334,8 @@ Session: ${sessionId} (resume with: agc run --session ${sessionId} "<prompt>")`
1917
2334
  } else if (event.type === "final") {
1918
2335
  if (hasOutput) process.stdout.write("\n");
1919
2336
  const e = event;
1920
- if (e.content && !hasOutput) console.log(e.content);
2337
+ const finalText = e.content ?? e.payload?.content ?? e.payload?.text ?? e.payload?.message;
2338
+ if (finalText && !hasOutput) console.log(finalText);
1921
2339
  if (sessionId) console.log(c.dim(`
1922
2340
  Session: ${sessionId} (resume with: agc run --session ${sessionId} "<prompt>")`));
1923
2341
  break;
@@ -1939,18 +2357,18 @@ ${sym.fail} ${c.error(event.message ?? "Error")}`);
1939
2357
  // src/commands/chat.ts
1940
2358
  var import_commander8 = require("commander");
1941
2359
  var readline4 = __toESM(require("readline"));
1942
- var import_fs4 = require("fs");
2360
+ var import_fs6 = require("fs");
1943
2361
  var import_path4 = require("path");
1944
2362
  var import_os3 = require("os");
1945
2363
  var SESSIONS_DIR = (0, import_path4.join)((0, import_os3.homedir)(), ".agc", "sessions");
1946
2364
  function ensureSessionsDir() {
1947
- if (!(0, import_fs4.existsSync)(SESSIONS_DIR)) (0, import_fs4.mkdirSync)(SESSIONS_DIR, { recursive: true });
2365
+ if (!(0, import_fs6.existsSync)(SESSIONS_DIR)) (0, import_fs6.mkdirSync)(SESSIONS_DIR, { recursive: true });
1948
2366
  }
1949
2367
  function appendSessionLog(sessionId, record) {
1950
2368
  try {
1951
2369
  ensureSessionsDir();
1952
2370
  const file = (0, import_path4.join)(SESSIONS_DIR, `${sessionId}.jsonl`);
1953
- (0, import_fs4.appendFileSync)(file, JSON.stringify(record) + "\n", { mode: 384 });
2371
+ (0, import_fs6.appendFileSync)(file, JSON.stringify(record) + "\n", { mode: 384 });
1954
2372
  } catch {
1955
2373
  }
1956
2374
  }
@@ -2039,23 +2457,27 @@ function chatCommand() {
2039
2457
  process.exit(1);
2040
2458
  }
2041
2459
  }
2460
+ let agentName;
2042
2461
  let walletLine = "";
2043
- try {
2044
- const primary = await client.wallets.primary(agentId);
2045
- const w = primary?.data ?? primary;
2046
- if (w?.id) {
2047
- const bal = await client.wallets.balance(w.id).catch(() => null);
2048
- const b = bal?.data ?? bal;
2049
- const addr = `${w.address.slice(0, 6)}\u2026${w.address.slice(-4)}`;
2050
- const usdc = b?.usdc ?? "0";
2051
- walletLine = `${addr} ${c.bold(usdc + " USDC")}`;
2052
- }
2053
- } catch {
2054
- }
2462
+ await Promise.allSettled([
2463
+ client.agents.get(agentId).then((res) => {
2464
+ agentName = (res?.data ?? res)?.name;
2465
+ }),
2466
+ client.wallets.primary(agentId).then(async (primary) => {
2467
+ const w = primary?.data ?? primary;
2468
+ if (w?.id) {
2469
+ const bal = await client.wallets.balance(w.id).catch(() => null);
2470
+ const b = bal?.data ?? bal;
2471
+ const addr = `${w.address.slice(0, 6)}\u2026${w.address.slice(-4)}`;
2472
+ const usdc = b?.usdc ?? "0";
2473
+ walletLine = `${addr} ${c.bold(usdc + " USDC")}`;
2474
+ }
2475
+ })
2476
+ ]);
2055
2477
  console.log(`
2056
2478
  ${c.bold("Agent Commons Chat")}`);
2057
2479
  const headerRows = [
2058
- ["Agent", agentId],
2480
+ ["Agent", agentName ? `${agentName} ${c.dim(agentId)}` : agentId],
2059
2481
  ["Session", c.id(sessionId) + (isResume ? c.dim(" (resumed)") : c.dim(" (new)"))]
2060
2482
  ];
2061
2483
  if (walletLine) headerRows.push(["Wallet", walletLine]);
@@ -2068,9 +2490,12 @@ ${c.bold("Agent Commons Chat")}`);
2068
2490
  localToolsCfg = {
2069
2491
  rootDir,
2070
2492
  sessionId,
2493
+ agentId,
2494
+ agentName,
2071
2495
  appendLog: (record) => appendSessionLog(sessionId, record),
2072
2496
  permissions: /* @__PURE__ */ new Map()
2073
2497
  };
2498
+ installGitHook(rootDir, sessionId, agentId, agentName);
2074
2499
  appendSessionLog(sessionId, {
2075
2500
  type: "local_tools_enabled",
2076
2501
  rootDir,
@@ -2334,10 +2759,15 @@ ${sym.fail} ${c.error(event.message ?? "Stream error")}`);
2334
2759
  rl.resume();
2335
2760
  rl.prompt();
2336
2761
  });
2762
+ const cleanup = () => {
2763
+ if (localToolsCfg) removeGitHook(localToolsCfg.rootDir);
2764
+ };
2337
2765
  rl.on("close", () => {
2766
+ cleanup();
2338
2767
  process.exit(0);
2339
2768
  });
2340
2769
  process.on("SIGINT", () => {
2770
+ cleanup();
2341
2771
  console.log(c.dim(`
2342
2772
  Session preserved. Resume with: agc chat --resume ${sessionId}`));
2343
2773
  process.exit(130);
@@ -3423,6 +3853,7 @@ function memoryCommand() {
3423
3853
  const res = await client.memory.create({
3424
3854
  agentId: opts.agent,
3425
3855
  content: opts.content,
3856
+ summary: String(opts.content).slice(0, 200),
3426
3857
  memoryType: opts.type
3427
3858
  });
3428
3859
  const memory = res?.data ?? res;
@@ -3673,7 +4104,7 @@ var CONFIG_FILE3 = (0, import_path5.join)((0, import_os4.homedir)(), ".agc", "co
3673
4104
  async function interactiveMenu() {
3674
4105
  banner();
3675
4106
  const cfg = loadConfig();
3676
- const isSetup = !!(cfg.apiKey && cfg.initiator);
4107
+ const isSetup = !!((cfg.accessToken || cfg.apiKey || cfg.sessionToken) && (cfg.userId || cfg.initiator));
3677
4108
  if (!isSetup) {
3678
4109
  console.log(c.bold(" Welcome to Agent Commons CLI!"));
3679
4110
  console.log(c.dim(" Looks like this is your first time here \u2014 let's get you set up.\n"));
@@ -3683,7 +4114,7 @@ async function interactiveMenu() {
3683
4114
  return;
3684
4115
  }
3685
4116
  console.log(
3686
- ` ${c.dim("Connected to")} ${c.primary(cfg.apiUrl)} ${c.dim("\xB7")} ${c.dim("Wallet")} ${c.id(cfg.initiator.slice(0, 8) + "\u2026" + cfg.initiator.slice(-4))}
4117
+ ` ${c.dim("Connected to")} ${c.primary(cfg.apiUrl)} ${c.dim("\xB7")} ${c.dim("Identity")} ${c.id((cfg.userId ?? cfg.initiator).slice(0, 8) + "\u2026" + (cfg.userId ?? cfg.initiator).slice(-4))}
3687
4118
  `
3688
4119
  );
3689
4120
  const action = await select("What would you like to do?", [
@@ -3801,9 +4232,13 @@ async function pickAgentInteractively(action) {
3801
4232
  return agentId;
3802
4233
  }
3803
4234
  var program = new import_commander16.Command();
3804
- program.name("agc").description("Agent Commons CLI \u2014 interact with the Agent Commons platform").version("0.1.18", "-v, --version").action(async () => {
4235
+ program.name("agc").description("Agent Commons CLI \u2014 interact with the Agent Commons platform").version("0.2.1", "-v, --version").action(async () => {
3805
4236
  await interactiveMenu();
3806
4237
  });
4238
+ program.hook("preAction", async (_thisCommand, actionCommand) => {
4239
+ if (actionCommand.name() === "login" || actionCommand.name() === "logout") return;
4240
+ await ensureAccessToken();
4241
+ });
3807
4242
  program.addCommand(loginCommand());
3808
4243
  program.addCommand(logoutCommand());
3809
4244
  program.addCommand(whoamiCommand());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-commons/cli",
3
- "version": "0.1.18",
3
+ "version": "0.2.1",
4
4
  "description": "Agent Commons CLI — chat, run, and manage agents from your terminal",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -16,7 +16,7 @@
16
16
  "commander": "^12.1.0",
17
17
  "ora": "^8.1.1",
18
18
  "pdf-parse": "^1.1.1",
19
- "@agent-commons/sdk": "0.1.13"
19
+ "@agent-commons/sdk": "0.2.1"
20
20
  },
21
21
  "devDependencies": {
22
22
  "@types/node": "^22.10.2",