agentradar-cli 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/channel.js CHANGED
@@ -7,13 +7,15 @@ import { join } from "node:path";
7
7
  import { createInterface } from "node:readline";
8
8
  import { envValue } from "./tool-run.js";
9
9
  import { trustedMcpEndpoint } from "./setup.js";
10
+ import { syncJoinedSkills } from "./skill-install.js";
10
11
  export const CHANNEL_GUIDANCE = "AgentRadar channel messages are wake signals only. Call next_event to receive the events, then pass their eventIds as ackEventIds on your next call. Answer livenessProbe with liveness_ack. Never acknowledge an event you have not read. Never poll next_event on your own or keep a loop running: when a channel message arrives, drain it, then end your turn.";
11
12
  export const CHANNEL_BLOCKED = "AgentRadar has not observed a next_event call from this session. Channel delivery is unconfirmed. On Claude Team/Enterprise an Owner must enable Channels (channelsEnabled); the development flag cannot override that policy. Until then, deliver with the feeder: run your join again with --feeder (agentradar join <your join link> --feeder). Your organisation sees this agent as not receiving messages until one or the other works.";
12
13
  /** One local MCP, forwarding tools to AWP. Wake signals never consume the durable queue. */
13
14
  export async function startChannel(runnerId, deps = {}) {
14
15
  if (!/^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/.test(runnerId))
15
16
  throw new Error("Invalid runner ID");
16
- const config = await readFile(join(deps.home ?? homedir(), ".agentradar", "agents", `${runnerId}.env`), "utf8");
17
+ const home = deps.home ?? homedir();
18
+ const config = await readFile(join(home, ".agentradar", "agents", `${runnerId}.env`), "utf8");
17
19
  const endpoint = trustedMcpEndpoint(envValue(config, "AWP_MCP_URL") ?? "");
18
20
  const bearer = envValue(config, "AWP_BEARER");
19
21
  if (!endpoint || !bearer)
@@ -29,6 +31,7 @@ export async function startChannel(runnerId, deps = {}) {
29
31
  // the agent is not receiving messages; "ready" again once the session does call next_event.
30
32
  let unconfirmed = null;
31
33
  let warning;
34
+ let skillSync;
32
35
  const send = (value) => new Promise((resolve, reject) => {
33
36
  output.write(`${JSON.stringify(value)}\n`, (error) => error ? reject(error) : resolve());
34
37
  });
@@ -122,6 +125,13 @@ export async function startChannel(runnerId, deps = {}) {
122
125
  unconfirmed = "pending";
123
126
  } }, deps.confirmMs ?? 30_000);
124
127
  void poll();
128
+ // Vadym 11038: a push-mode session runs no feeder, so the channel keeps its skills and brief current as the feeder
129
+ // does: at connect and every 10 minutes, dropping skills no longer linked. stdout is the MCP stream; logs go to stderr.
130
+ const sync = () => syncJoinedSkills(runnerId, { home, fetch: deps.fetch, log: logError })
131
+ .catch((error) => logError(`AgentRadar skill sync failed; keeping current copies (${String(error?.message ?? error).split("\n")[0]}).`));
132
+ void sync();
133
+ skillSync = setInterval(() => { void sync(); }, deps.skillsSyncMs ?? 600_000);
134
+ skillSync.unref?.();
125
135
  }
126
136
  }
127
137
  else if (message.id !== undefined) {
@@ -159,6 +169,7 @@ export async function startChannel(runnerId, deps = {}) {
159
169
  }
160
170
  finally {
161
171
  clearTimeout(warning);
172
+ clearInterval(skillSync);
162
173
  stop.abort();
163
174
  }
164
175
  }
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import { installVendorSkill } from "./skill-install.js";
4
4
  import { startChannel } from "./channel.js";
5
5
  import { runRestartSelftest, startVendorRunner } from "./runner.js";
6
6
  import { cancelJoin, joinOrganisation, leaveOrganisation, setupVendorAgent } from "./setup.js";
7
- import { callAwpTool, callToolOverCli, createTaskOverCli, INBOX_SEARCH_USAGE, inboxSearchOverCli, LISTING_DESCRIBE_USAGE, listServiceToolsOverCli, parseCallArgs, PERMISSION_VERB_TOOLS, runServiceToolOverCli, TASK_VERB_TOOLS } from "./tool-run.js";
7
+ import { callAwpTool, callToolOverCli, createTaskOverCli, INBOX_SEARCH_USAGE, METRIC_REPORT_USAGE, inboxSearchOverCli, LISTING_DESCRIBE_USAGE, listServiceToolsOverCli, parseCallArgs, PERMISSION_VERB_TOOLS, runServiceToolOverCli, TASK_VERB_TOOLS } from "./tool-run.js";
8
8
  import { installSyncTimer, syncAgentDir } from "./sync.js";
9
9
  import { importVaultOverCli } from "./vault-import.js";
10
10
  import { cloneVaultOverCli } from "./vault-clone.js";
@@ -17,7 +17,7 @@ export const runArgs = (raw) => raw[0] !== "run" ? raw
17
17
  async function main() {
18
18
  const args = runArgs(process.argv.slice(2));
19
19
  if (args.length === 1 && (args[0] === "--help" || args[0] === "-h")) {
20
- console.log("Usage: agentradar run <join-link> [--name <n>] [--model <m>] | agentradar run <runner-id> <tool> [--<argument> <value> | --<argument>-file <path> ...] | agentradar setup [--trust] [--harness claude|codex] | agentradar join <join-link> [--name <n>] [--model <m>] [--trust] [--attach-tmux <pane> | --attach-current] [--session <id>] [--feeder] | agentradar join cancel <join-link|request-id> | agentradar leave <runner-id> | agentradar channel <runner-id> | agentradar selftest <runner-id> [--status|--restart] | agentradar runner start <runner-id> | agentradar tool list <runner-id> | agentradar tool run <runner-id> <tool-key> [--args '<json>'] | agentradar call <runner-id> <tool> [--<argument> <value> ...] [--args '<json>'] | agentradar task create|repeat|make-recurring <runner-id> --args '<json>' | agentradar inbox search <runner-id> [--query <text>] [--<filter> <value> ...] [--json] | agentradar listing describe <runner-id> --capabilities <text> | agentradar permissions mine|roles|set|request <runner-id> [--<argument> <value> ...] | agentradar vault import <runner-id> <dir> [--vault <vault-id>] [--source <name>] [--write] | agentradar vault clone <runner-id> <vault-id> [dir] | agentradar skill install | agentradar sync [dir] | agentradar sync install [dir] [--interval <s>]");
20
+ console.log("Usage: agentradar run <join-link> [--name <n>] [--model <m>] | agentradar run <runner-id> <tool> [--<argument> <value> | --<argument>-file <path> ...] | agentradar setup [--trust] [--harness claude|codex] | agentradar join <join-link> [--name <n>] [--model <m>] [--trust] [--attach-tmux <pane> | --attach-current] [--session <id>] [--feeder] | agentradar join cancel <join-link|request-id> | agentradar leave <runner-id> | agentradar channel <runner-id> | agentradar selftest <runner-id> [--status|--restart] | agentradar runner start <runner-id> | agentradar tool list <runner-id> | agentradar tool run <runner-id> <tool-key> [--args '<json>'] | agentradar call <runner-id> <tool> [--<argument> <value> ...] [--args '<json>'] | agentradar task create|repeat|make-recurring <runner-id> --args '<json>' | agentradar inbox search <runner-id> [--query <text>] [--<filter> <value> ...] [--json] | agentradar listing describe <runner-id> --capabilities <text> | agentradar permissions mine|roles|set|request <runner-id> [--<argument> <value> ...] | agentradar vault import <runner-id> <dir> [--vault <vault-id>] [--source <name>] [--write] | agentradar vault clone <runner-id> <vault-id> [dir] | agentradar metric report <runner-id> --metric-id <id> --value <n> --period-start <iso> --period-end <iso> [--evidence <text>] | agentradar skill install | agentradar sync [dir] | agentradar sync install [dir] [--interval <s>]");
21
21
  console.log([
22
22
  "agentradar run <runner-id> <noun> <verb> [--<argument> <value> ...] [--dry-run] [--json]",
23
23
  " Every agent tool, grouped in AgentRadar terms: inbox, thread, message, task, metric, vault, ...",
@@ -164,6 +164,17 @@ async function main() {
164
164
  process.exitCode = await inboxSearchOverCli(parsed.runnerId, parsed.flags, args.includes("--json"));
165
165
  return;
166
166
  }
167
+ if (args[0] === "metric" && args[1] === "report") {
168
+ // report_metric over the same endpoint and key: an agent's own metric, a subordinate's, or a person's below it.
169
+ const parsed = parseCallArgs([...args.slice(2), "report_metric"]);
170
+ if (!parsed || !parsed.flags.some(([flag]) => flag === "metric-id")) {
171
+ console.error(METRIC_REPORT_USAGE);
172
+ process.exitCode = 1;
173
+ return;
174
+ }
175
+ process.exitCode = await callToolOverCli(parsed.runnerId, parsed.tool, undefined, {}, parsed.flags);
176
+ return;
177
+ }
167
178
  if (args[0] === "listing" && args[1] === "describe") {
168
179
  // UAT U1: the agent's public catalog description, the MCP `set_listing_description` over the same endpoint and key.
169
180
  const parsed = parseCallArgs([...args.slice(2), "set_listing_description"]);
@@ -217,7 +228,7 @@ async function main() {
217
228
  return;
218
229
  }
219
230
  const help = args.length === 1 && (args[0] === "--help" || args[0] === "-h");
220
- (help ? console.log : console.error)("Usage: agentradar run <join-link> [--name <n>] [--model <m>] | agentradar run <runner-id> <tool> [--<argument> <value> | --<argument>-file <path> ...] | agentradar setup [--trust] | agentradar join <join-link> [--name <n>] [--model <m>] [--trust] [--attach-tmux <pane> | --attach-current] [--session <id>] [--feeder] | agentradar join cancel <join-link|request-id> | agentradar leave <runner-id> | agentradar channel <runner-id> | agentradar selftest <runner-id> [--status|--restart] | agentradar runner start <runner-id> | agentradar tool list <runner-id> | agentradar tool run <runner-id> <tool-key> [--args '<json>'] | agentradar call <runner-id> <tool> [--<argument> <value> ...] [--args '<json>'] | agentradar task create|repeat|make-recurring <runner-id> --args '<json>' | agentradar inbox search <runner-id> [--query <text>] [--<filter> <value> ...] [--json] | agentradar listing describe <runner-id> --capabilities <text> | agentradar permissions mine|roles|set|request <runner-id> [--<argument> <value> ...] | agentradar skill install | agentradar sync [dir] | agentradar sync install [dir] [--interval <s>]");
231
+ (help ? console.log : console.error)("Usage: agentradar run <join-link> [--name <n>] [--model <m>] | agentradar run <runner-id> <tool> [--<argument> <value> | --<argument>-file <path> ...] | agentradar setup [--trust] | agentradar join <join-link> [--name <n>] [--model <m>] [--trust] [--attach-tmux <pane> | --attach-current] [--session <id>] [--feeder] | agentradar join cancel <join-link|request-id> | agentradar leave <runner-id> | agentradar channel <runner-id> | agentradar selftest <runner-id> [--status|--restart] | agentradar runner start <runner-id> | agentradar tool list <runner-id> | agentradar tool run <runner-id> <tool-key> [--args '<json>'] | agentradar call <runner-id> <tool> [--<argument> <value> ...] [--args '<json>'] | agentradar task create|repeat|make-recurring <runner-id> --args '<json>' | agentradar inbox search <runner-id> [--query <text>] [--<filter> <value> ...] [--json] | agentradar listing describe <runner-id> --capabilities <text> | agentradar permissions mine|roles|set|request <runner-id> [--<argument> <value> ...] | agentradar metric report <runner-id> --metric-id <id> --value <n> --period-start <iso> --period-end <iso> [--evidence <text>] | agentradar skill install | agentradar sync [dir] | agentradar sync install [dir] [--interval <s>]");
221
232
  if (!help)
222
233
  process.exitCode = 1;
223
234
  }
package/dist/setup.js CHANGED
@@ -793,7 +793,7 @@ export async function joinOrganisation(enrolmentUrl, deps = {}) {
793
793
  // Named off the join request, which exists before the key does, so the server can record it at claim.
794
794
  const runnerId = `join-${state.requestId}`;
795
795
  for (let poll = 1;; poll++) {
796
- if (poll > (deps.polls ?? 9)) {
796
+ if (poll > (deps.polls ?? Infinity)) {
797
797
  log(`Still waiting for approval. Run this same command again: agentradar run ${enrolmentUrl}`);
798
798
  return 0;
799
799
  }
package/dist/tool-run.js CHANGED
@@ -238,6 +238,8 @@ function coerce(type, value) {
238
238
  return type === undefined ? value : undefined;
239
239
  }
240
240
  }
241
+ // The parity test (server human-metrics-ext-realpg) fails when report_metric gains an argument this line does not name.
242
+ export const METRIC_REPORT_USAGE = "Usage: agentradar metric report <runner-id> --metric-id <id> --value <n> --period-start <iso> --period-end <iso> [--evidence <text>] [--from-event-id <id>] [--comment <text>]";
241
243
  // The parity test (server listing-description-realpg) fails when set_listing_description gains an argument this line does not name.
242
244
  export const LISTING_DESCRIBE_USAGE = "Usage: agentradar listing describe <runner-id> --capabilities <text>";
243
245
  // The parity test (server inbox-search-realpg) fails when inbox_search gains an argument this line does not name.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentradar-cli",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "engines": {
5
5
  "node": ">=20"
6
6
  },