@rudderhq/cli 0.3.4 → 0.3.5-canary.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/dist/index.js CHANGED
@@ -1630,7 +1630,7 @@ var init_agent = __esm({
1630
1630
  init_model_fallbacks();
1631
1631
  init_secret();
1632
1632
  agentPermissionsSchema = z12.object({
1633
- canCreateAgents: z12.boolean().optional().default(false),
1633
+ canCreateAgents: z12.boolean().optional().default(true),
1634
1634
  canManageSkills: z12.boolean().optional().default(true)
1635
1635
  });
1636
1636
  agentInstructionsBundleModeSchema = z12.enum(["managed", "external"]);
@@ -7062,14 +7062,14 @@ var RUDDER_AGENT_OPERATING_CONTRACT = [
7062
7062
  "When you mention Rudder entities in any user-visible Markdown output, prefer Rudder's renderable Markdown link syntax over plain IDs, bare URLs, or backticked references so the UI can render chips and navigate correctly.",
7063
7063
  "",
7064
7064
  "- Issues: use `[<identifier-or-title>](issue://<issue-id>)`; include `?c=<comment-id>` when linking to a specific comment.",
7065
- "- Agents: use `[<agent-name>](agent://<agent-id>)` for reference-only links. Use `[<agent-name>](agent://<agent-id>?intent=wake)` only when you deliberately want an issue-composer mention to wake that agent.",
7065
+ "- Agents: use `[<agent-name>](agent://<agent-id>)` for reference-only links. In issue comments, use `[<agent-name>](agent://<agent-id>?intent=wake)` only when you intentionally want to wake that agent for attention or collaboration.",
7066
7066
  "- Projects: use `[<project-name>](project://<project-id>)` when citing a Rudder project.",
7067
7067
  "- Chat threads: use `[<chat-title>](chat://<conversation-id>)` when citing a Rudder chat conversation.",
7068
7068
  '- Library files: use the `markdownLink` returned by `rudder library file ref "$RUDDER_PROJECT_LIBRARY_PATH/<relative-file>" --json`; do not hand-write `library-entry://...` links, and treat `library-file://...` as legacy path syntax only.',
7069
7069
  "",
7070
7070
  "Write these as normal Markdown links, not inside code spans or code blocks, unless you are literally documenting the syntax.",
7071
7071
  "",
7072
- "Mention-triggered comment wakes arrive with `RUDDER_WAKE_COMMENT_ID`; read that wake comment before acting. Board/operator issue comments can wake an agent with a plain `@AgentName` token or an issue-composer agent mention serialized as `agent://agent-id?intent=wake`. Plain structured links such as `agent://agent-id` are reference-only links for rendering and navigation. Agent-authored issue comments do not fan out peer wakeups by default; use reviewer, assignment, or explicit handoff workflow instead. Mentioning an agent requests attention or collaboration; it does not transfer issue ownership unless the comment also makes an explicit handoff and normal checkout rules allow it.",
7072
+ "Mention-triggered comment wakes arrive with `RUDDER_WAKE_COMMENT_ID`; read that wake comment before acting. Issue comments can wake an agent only with an explicit wake-intent agent link serialized as `agent://agent-id?intent=wake`. Plain structured links such as `agent://agent-id` are reference-only links for rendering and navigation, and plain text agent names are not wake requests. Use wake-intent links only when you intentionally want to wake another agent for attention or collaboration; omit the wake intent for ordinary references. Mentioning an agent requests attention or collaboration; it does not transfer issue ownership unless the comment also makes an explicit handoff and normal checkout rules allow it.",
7073
7073
  "",
7074
7074
  "When an issue comment, done comment, or blocker comment cites visual evidence from a local screenshot/image path, attach the image with the Rudder CLI `--image <path>` option instead of leaving only the filesystem path in the text.",
7075
7075
  "",
@@ -7084,7 +7084,31 @@ var RUDDER_AGENT_OPERATING_CONTRACT = [
7084
7084
  "## Safety Considerations",
7085
7085
  "",
7086
7086
  "- Never exfiltrate secrets or private data.",
7087
- "- Do not perform any destructive commands unless explicitly requested by the board."
7087
+ "- Do not perform any destructive commands unless explicitly requested by the board.",
7088
+ "",
7089
+ "## Other",
7090
+ "- You can use `rudder` skill to see Agent best practise in Rudder. eg: update Agent profile, crud automation, manage library, project, org, curd agent run, chat, issue.",
7091
+ "- Before taking action, deeply analyze and research the existing information to ensure you have comprehensive context information before proceeding with the next action. You have your own goal, memory, skills, automation, library, project, org, use these resources to make better decisions.",
7092
+ "- When the user explicitly mentions previously handled issue, tasks or conversations, you need to retrieve the relevant tasks first before proceeding with the next action."
7093
+ ].join("\n");
7094
+ var RUDDER_AGENT_HEARTBEAT_INSTRUCTION = [
7095
+ "# Rudder Heartbeat Instruction",
7096
+ "",
7097
+ "This section is injected by Rudder for heartbeat scene runs. It is the platform-owned timed-wakeup pipeline, not an agent-local `HEARTBEAT.md` file.",
7098
+ "",
7099
+ "## Heartbeat Pipeline",
7100
+ "",
7101
+ "1. Identify yourself and inspect wake context, including `RUDDER_TASK_ID`, `RUDDER_WAKE_REASON`, `RUDDER_WAKE_COMMENT_ID`, and `RUDDER_APPROVAL_ID` when present.",
7102
+ "2. Handle approval follow-up first: read the approval and linked issues, then close resolved work or comment on what remains.",
7103
+ "3. Inspect your Rudder inbox. Prioritize reviewer rows in `in_review` or `blocked`, then assignee `in_progress`, then assignee `todo`. Do not look for unassigned work.",
7104
+ "4. For mention wakes, read the wake comment before acting. Mentions request attention; they do not transfer ownership unless the comment explicitly says so.",
7105
+ "5. Checkout before doing assignee task work. A `409` means another agent owns the task; do not retry it.",
7106
+ "6. Load compact issue context, do one bounded useful chunk, and preserve evidence.",
7107
+ "7. Before exiting active work, leave exactly one durable signal: progress, done, blocked, explicit handoff, or structured review decision.",
7108
+ "8. Treat passive follow-up as close-out governance, not a fresh assignment.",
7109
+ "9. Treat review close-out follow-up as review governance; free-form accept/reject text is not a durable decision.",
7110
+ "",
7111
+ "Use the Rudder control-plane interface available in this runtime. CLI-capable runtimes should use the bundled `rudder` skill for command details, Library handoff rules, organization-skill workflow, and control-plane best practices. HTTP compatibility runtimes should follow the explicit HTTP workflow in their wake text; that workflow overrides CLI command guidance."
7088
7112
  ].join("\n");
7089
7113
 
7090
7114
  // ../packages/agent-runtime-utils/dist/server-utils.cli.js
@@ -7777,6 +7801,54 @@ var AGENT_CLI_CAPABILITIES = [
7777
7801
  requiresRunId: false,
7778
7802
  attachesRunIdWhenAvailable: false
7779
7803
  },
7804
+ {
7805
+ id: "automation.triggers.create",
7806
+ command: "rudder automation triggers create <automation-id> --kind <kind>",
7807
+ category: "automation",
7808
+ description: "Create a schedule, webhook, or API trigger through the governed automation API.",
7809
+ mutating: true,
7810
+ contract: "agent-v1",
7811
+ requiresOrgId: false,
7812
+ requiresAgentId: false,
7813
+ requiresRunId: false,
7814
+ attachesRunIdWhenAvailable: true
7815
+ },
7816
+ {
7817
+ id: "automation.triggers.update",
7818
+ command: "rudder automation triggers update <trigger-id>",
7819
+ category: "automation",
7820
+ description: "Update an automation trigger through the governed automation API.",
7821
+ mutating: true,
7822
+ contract: "agent-v1",
7823
+ requiresOrgId: false,
7824
+ requiresAgentId: false,
7825
+ requiresRunId: false,
7826
+ attachesRunIdWhenAvailable: true
7827
+ },
7828
+ {
7829
+ id: "automation.triggers.delete",
7830
+ command: "rudder automation triggers delete <trigger-id>",
7831
+ category: "automation",
7832
+ description: "Delete an automation trigger through the governed automation API.",
7833
+ mutating: true,
7834
+ contract: "agent-v1",
7835
+ requiresOrgId: false,
7836
+ requiresAgentId: false,
7837
+ requiresRunId: false,
7838
+ attachesRunIdWhenAvailable: true
7839
+ },
7840
+ {
7841
+ id: "automation.triggers.rotate-secret",
7842
+ command: "rudder automation triggers rotate-secret <trigger-id>",
7843
+ category: "automation",
7844
+ description: "Rotate an automation webhook trigger secret through the governed automation API.",
7845
+ mutating: true,
7846
+ contract: "agent-v1",
7847
+ requiresOrgId: false,
7848
+ requiresAgentId: false,
7849
+ requiresRunId: false,
7850
+ attachesRunIdWhenAvailable: true
7851
+ },
7780
7852
  {
7781
7853
  id: "automation.create",
7782
7854
  command: "rudder automation create --org-id <id> --title <title> --assignee-agent-id <id>",
@@ -7925,11 +7997,11 @@ var AGENT_CLI_CAPABILITIES = [
7925
7997
  id: "chat.send",
7926
7998
  command: "rudder chat send <chat-id> --body <text>",
7927
7999
  category: "chat",
7928
- description: "Send a chat message and persist the assistant reply through the server.",
8000
+ description: "Send an agent-authored message directly to the operator in a chat.",
7929
8001
  mutating: true,
7930
8002
  contract: "agent-v1",
7931
8003
  requiresOrgId: false,
7932
- requiresAgentId: false,
8004
+ requiresAgentId: true,
7933
8005
  requiresRunId: false,
7934
8006
  attachesRunIdWhenAvailable: true
7935
8007
  },
@@ -7947,9 +8019,21 @@ var AGENT_CLI_CAPABILITIES = [
7947
8019
  },
7948
8020
  {
7949
8021
  id: "runs.list",
7950
- command: "rudder runs list --org-id <id>",
8022
+ command: "rudder runs list --org-id <id> [--used-skill <skill>] [--loaded-skill <skill>]",
8023
+ category: "runs",
8024
+ description: "List observed agent runs with filters for status, agent, issue, runtime, time, and skill evidence; used-skill means actual usage and loaded-skill is opt-in.",
8025
+ mutating: false,
8026
+ contract: "agent-v1",
8027
+ requiresOrgId: true,
8028
+ requiresAgentId: false,
8029
+ requiresRunId: false,
8030
+ attachesRunIdWhenAvailable: false
8031
+ },
8032
+ {
8033
+ id: "runs.by-skill",
8034
+ command: "rudder runs by-skill <skill> --org-id <id> [--evidence <used-or-loaded>]",
7951
8035
  category: "runs",
7952
- description: "List observed agent runs with filters for status, agent, issue, runtime, and time.",
8036
+ description: "Build a skill evidence packet from recent runs; defaults to actual usage and returns status counts, agents, issues, common errors, rows, and transcript/errors follow-up commands.",
7953
8037
  mutating: false,
7954
8038
  contract: "agent-v1",
7955
8039
  requiresOrgId: true,
@@ -8911,6 +8995,7 @@ function registerClientAuthCommands(auth) {
8911
8995
  init_dist();
8912
8996
  function registerAutomationCommands(program) {
8913
8997
  const automation = program.command("automation").description("Automation operations");
8998
+ const triggers = automation.command("triggers").description("Automation trigger operations");
8914
8999
  addCommonClientOptions(
8915
9000
  automation.command("list").description(getAgentCliCapabilityById("automation.list").description).option("-O, --org-id <id>", "Organization ID").option("--status <status>", "Filter by automation status").option("--assignee-agent-id <id>", "Filter by assignee agent ID").option("--project-id <id>", "Filter by project ID").option("--output-mode <mode>", "Filter by output mode").action(async (opts) => {
8916
9001
  try {
@@ -8953,12 +9038,68 @@ function registerAutomationCommands(program) {
8953
9038
  })
8954
9039
  );
8955
9040
  addCommonClientOptions(
8956
- automation.command("triggers").description("Automation trigger operations").command("list").description(getAgentCliCapabilityById("automation.triggers.list").description).argument("<automationId>", "Automation ID").action(async (automationId, opts) => {
9041
+ triggers.command("list").description(getAgentCliCapabilityById("automation.triggers.list").description).argument("<automationId>", "Automation ID").action(async (automationId, opts) => {
8957
9042
  try {
8958
9043
  const ctx = resolveCommandContext(opts);
8959
9044
  const row = await ctx.api.get(`/api/automations/${encodeURIComponent(automationId)}`);
8960
- const triggers = row?.triggers ?? [];
8961
- printOutput(triggers, { json: ctx.json });
9045
+ const triggers2 = row?.triggers ?? [];
9046
+ printOutput(triggers2, { json: ctx.json });
9047
+ } catch (err) {
9048
+ handleCommandError(err);
9049
+ }
9050
+ })
9051
+ );
9052
+ addCommonClientOptions(
9053
+ triggers.command("create").description(getAgentCliCapabilityById("automation.triggers.create").description).argument("<automationId>", "Automation ID").option("--payload <json>", "Raw automation trigger create payload JSON").option("--kind <kind>", "Trigger kind: schedule, webhook, or api").option("--label <label>", "Trigger label").option("--enabled", "Create the trigger enabled").option("--disabled", "Create the trigger disabled").option("--cron-expression <expr>", "Schedule cron expression").option("--timezone <timezone>", "Schedule timezone; defaults to UTC for schedule triggers").option("--signing-mode <mode>", "Webhook signing mode").option("--replay-window-sec <seconds>", "Webhook replay window in seconds").action(async (automationId, opts) => {
9054
+ try {
9055
+ const ctx = resolveCommandContext(opts);
9056
+ const payload = createAutomationTriggerSchema.parse(buildAutomationTriggerPayload(opts));
9057
+ const created = await ctx.api.post(
9058
+ `/api/automations/${encodeURIComponent(automationId)}/triggers`,
9059
+ payload
9060
+ );
9061
+ printOutput(created, { json: ctx.json });
9062
+ } catch (err) {
9063
+ handleCommandError(err);
9064
+ }
9065
+ })
9066
+ );
9067
+ addCommonClientOptions(
9068
+ triggers.command("update").description(getAgentCliCapabilityById("automation.triggers.update").description).argument("<triggerId>", "Automation trigger ID").option("--payload <json>", "Raw automation trigger update payload JSON").option("--label <label>", "Trigger label").option("--enabled", "Enable the trigger").option("--disabled", "Disable the trigger").option("--cron-expression <expr>", "Schedule cron expression").option("--timezone <timezone>", "Schedule timezone").option("--signing-mode <mode>", "Webhook signing mode").option("--replay-window-sec <seconds>", "Webhook replay window in seconds").action(async (triggerId, opts) => {
9069
+ try {
9070
+ const ctx = resolveCommandContext(opts);
9071
+ const payload = updateAutomationTriggerSchema.parse(buildAutomationTriggerPayload(opts));
9072
+ const updated = await ctx.api.patch(
9073
+ `/api/automation-triggers/${encodeURIComponent(triggerId)}`,
9074
+ payload
9075
+ );
9076
+ printOutput(updated, { json: ctx.json });
9077
+ } catch (err) {
9078
+ handleCommandError(err);
9079
+ }
9080
+ })
9081
+ );
9082
+ addCommonClientOptions(
9083
+ triggers.command("delete").description(getAgentCliCapabilityById("automation.triggers.delete").description).argument("<triggerId>", "Automation trigger ID").action(async (triggerId, opts) => {
9084
+ try {
9085
+ const ctx = resolveCommandContext(opts);
9086
+ await ctx.api.delete(`/api/automation-triggers/${encodeURIComponent(triggerId)}`);
9087
+ printOutput({ id: triggerId, deleted: true }, { json: ctx.json });
9088
+ } catch (err) {
9089
+ handleCommandError(err);
9090
+ }
9091
+ })
9092
+ );
9093
+ addCommonClientOptions(
9094
+ triggers.command("rotate-secret").description(getAgentCliCapabilityById("automation.triggers.rotate-secret").description).argument("<triggerId>", "Automation trigger ID").action(async (triggerId, opts) => {
9095
+ try {
9096
+ const ctx = resolveCommandContext(opts);
9097
+ const payload = rotateAutomationTriggerSecretSchema.parse({});
9098
+ const rotated = await ctx.api.post(
9099
+ `/api/automation-triggers/${encodeURIComponent(triggerId)}/rotate-secret`,
9100
+ payload
9101
+ );
9102
+ printOutput(rotated, { json: ctx.json });
8962
9103
  } catch (err) {
8963
9104
  handleCommandError(err);
8964
9105
  }
@@ -9052,6 +9193,36 @@ function buildAutomationPayload(opts) {
9052
9193
  })
9053
9194
  };
9054
9195
  }
9196
+ function buildAutomationTriggerPayload(opts) {
9197
+ return {
9198
+ ...parseJsonObjectOption(opts.payload, "--payload"),
9199
+ ...definedRecord({
9200
+ kind: "kind" in opts ? opts.kind : void 0,
9201
+ label: opts.label,
9202
+ enabled: parseEnabledOption(opts),
9203
+ cronExpression: opts.cronExpression,
9204
+ timezone: opts.timezone,
9205
+ signingMode: opts.signingMode,
9206
+ replayWindowSec: parseOptionalIntegerOption(opts.replayWindowSec, "--replay-window-sec")
9207
+ })
9208
+ };
9209
+ }
9210
+ function parseEnabledOption(opts) {
9211
+ if (opts.enabled && opts.disabled) {
9212
+ throw new Error("Pass only one of --enabled or --disabled");
9213
+ }
9214
+ if (opts.enabled) return true;
9215
+ if (opts.disabled) return false;
9216
+ return void 0;
9217
+ }
9218
+ function parseOptionalIntegerOption(value, label) {
9219
+ if (value === void 0) return void 0;
9220
+ const parsed = Number(value);
9221
+ if (!Number.isInteger(parsed)) {
9222
+ throw new Error(`${label} must be an integer`);
9223
+ }
9224
+ return parsed;
9225
+ }
9055
9226
  function definedRecord(record) {
9056
9227
  return Object.fromEntries(Object.entries(record).filter(([, value]) => value !== void 0));
9057
9228
  }
@@ -11615,8 +11786,9 @@ function projectPath(projectRef, orgId) {
11615
11786
  function registerRunsCommands(program) {
11616
11787
  const runs = program.command("runs").description("Run debugging operations");
11617
11788
  addCommonClientOptions(
11618
- runs.command("list").description(getAgentCliCapabilityById("runs.list").description).option("-O, --org-id <id>", "Organization ID").option("--updated-after <iso>", "Only runs updated after this timestamp").option("--run-id-prefix <prefix>", "Filter by run ID prefix").option("--agent-id <id>", "Filter by agent ID").option("--status <status>", "Filter by run status").option("--runtime <type>", "Filter by runtime type").option("--issue-id <id>", "Filter by linked issue ID").option("--created-before <iso>", "Only runs created before this timestamp").option("--limit <n>", "Maximum rows", "200").action(async (opts) => {
11789
+ runs.command("list").description(getAgentCliCapabilityById("runs.list").description).option("-O, --org-id <id>", "Organization ID").option("--updated-after <iso>", "Only runs updated after this timestamp").option("--run-id-prefix <prefix>", "Filter by run ID prefix").option("--agent-id <id>", "Filter by agent ID").option("--status <status>", "Filter by run status").option("--runtime <type>", "Filter by runtime type").option("--issue-id <id>", "Filter by linked issue ID").option("--used-skill <key-or-name>", "Filter by skill actually used during the run").option("--loaded-skill <key-or-name>", "Filter by skill loaded for the run").option("--created-before <iso>", "Only runs created before this timestamp").option("--limit <n>", "Maximum rows", "200").action(async (opts) => {
11619
11790
  try {
11791
+ assertSingleSkillFilter(opts);
11620
11792
  const ctx = resolveCommandContext(opts, { requireCompany: true });
11621
11793
  const rows = await ctx.api.get(`/api/run-intelligence/orgs/${ctx.orgId}/runs?${buildRunsListQuery(opts)}`) ?? [];
11622
11794
  printOutput(ctx.json ? rows : rows.map(formatRunListRow), { json: ctx.json });
@@ -11626,6 +11798,21 @@ function registerRunsCommands(program) {
11626
11798
  }),
11627
11799
  { includeCompany: false }
11628
11800
  );
11801
+ addCommonClientOptions(
11802
+ runs.command("by-skill").description(getAgentCliCapabilityById("runs.by-skill").description).argument("<skill>", "Skill key or display name").option("-O, --org-id <id>", "Organization ID").option("--evidence <used|loaded>", "Evidence type to match; defaults to used", "used").option("--agent-id <id>", "Filter by agent ID").option("--status <status>", "Filter by run status").option("--runtime <type>", "Filter by runtime type").option("--issue-id <id>", "Filter by linked issue ID").option("--created-before <iso>", "Only runs created before this timestamp").option("--limit <n>", "Maximum rows", "50").action(async (skill, opts) => {
11803
+ try {
11804
+ const evidenceType = parseSkillEvidenceType(opts.evidence);
11805
+ const ctx = resolveCommandContext(opts, { requireCompany: true });
11806
+ const params = buildRunsBySkillQuery(skill, opts, evidenceType);
11807
+ const rows = await ctx.api.get(`/api/run-intelligence/orgs/${ctx.orgId}/runs?${params}`) ?? [];
11808
+ const report = buildSkillRunReport(skill, evidenceType, rows);
11809
+ printOutput(ctx.json ? report : formatSkillRunReport(report), { json: ctx.json });
11810
+ } catch (err) {
11811
+ handleCommandError(err);
11812
+ }
11813
+ }),
11814
+ { includeCompany: false }
11815
+ );
11629
11816
  addCommonClientOptions(
11630
11817
  runs.command("get").description(getAgentCliCapabilityById("runs.get").description).argument("<runId>", "Run ID").action(async (runId, opts) => {
11631
11818
  try {
@@ -11728,10 +11915,33 @@ function buildRunsListQuery(opts) {
11728
11915
  if (opts.status) params.set("status", opts.status);
11729
11916
  if (opts.runtime) params.set("runtime", opts.runtime);
11730
11917
  if (opts.issueId) params.set("issueId", opts.issueId);
11918
+ if (opts.usedSkill) params.set("usedSkill", opts.usedSkill);
11919
+ if (opts.loadedSkill) params.set("loadedSkill", opts.loadedSkill);
11920
+ if (opts.createdBefore) params.set("createdBefore", opts.createdBefore);
11921
+ if (opts.limit) params.set("limit", opts.limit);
11922
+ return params.toString();
11923
+ }
11924
+ function buildRunsBySkillQuery(skill, opts, evidenceType) {
11925
+ const params = new URLSearchParams();
11926
+ params.set(evidenceType === "used" ? "usedSkill" : "loadedSkill", skill);
11927
+ if (opts.agentId) params.set("agentId", opts.agentId);
11928
+ if (opts.status) params.set("status", opts.status);
11929
+ if (opts.runtime) params.set("runtime", opts.runtime);
11930
+ if (opts.issueId) params.set("issueId", opts.issueId);
11731
11931
  if (opts.createdBefore) params.set("createdBefore", opts.createdBefore);
11732
11932
  if (opts.limit) params.set("limit", opts.limit);
11733
11933
  return params.toString();
11734
11934
  }
11935
+ function assertSingleSkillFilter(opts) {
11936
+ if (opts.usedSkill && opts.loadedSkill) {
11937
+ throw new Error("Use either --used-skill or --loaded-skill, not both.");
11938
+ }
11939
+ }
11940
+ function parseSkillEvidenceType(value) {
11941
+ const normalized = (value ?? "used").trim().toLowerCase();
11942
+ if (normalized === "used" || normalized === "loaded") return normalized;
11943
+ throw new Error("--evidence must be either 'used' or 'loaded'.");
11944
+ }
11735
11945
  function buildTranscriptQuery(opts, output) {
11736
11946
  const params = new URLSearchParams();
11737
11947
  if (opts.errorsOnly) params.set("errorsOnly", "true");
@@ -11752,10 +11962,110 @@ function formatRunListRow(row) {
11752
11962
  status: row.run.status,
11753
11963
  agent: row.agentName ?? row.run.agentId,
11754
11964
  runtime: row.bundle.agentRuntimeType,
11755
- issue: row.issue?.identifier ?? row.issue?.id ?? "-",
11756
- updatedAt: row.run.updatedAt
11965
+ issue: formatIssueRef(row.issue),
11966
+ createdAt: row.run.createdAt,
11967
+ finishedAt: row.run.finishedAt ?? "-",
11968
+ evidence: row.skillEvidence?.evidenceType ?? "-",
11969
+ skill: row.skillEvidence?.matchedSkillKey ?? "-",
11970
+ langfuse: readLangfuseTraceUrl(row.langfuse) ?? "-",
11971
+ error: row.errorSummary ?? "-",
11972
+ next: row.run.status === "failed" ? `rudder runs errors ${row.run.id}` : `rudder runs transcript ${row.run.id}`
11973
+ };
11974
+ }
11975
+ function buildSkillRunReport(skill, evidenceType, rows) {
11976
+ const statusCounts = {
11977
+ succeeded: 0,
11978
+ failed: 0,
11979
+ cancelled: 0,
11980
+ timedOut: 0,
11981
+ running: 0,
11982
+ queued: 0,
11983
+ other: 0
11984
+ };
11985
+ const agents = /* @__PURE__ */ new Map();
11986
+ const issues = /* @__PURE__ */ new Map();
11987
+ const errors = /* @__PURE__ */ new Map();
11988
+ for (const row of rows) {
11989
+ const status = row.run.status;
11990
+ if (status === "succeeded") statusCounts.succeeded += 1;
11991
+ else if (status === "failed") statusCounts.failed += 1;
11992
+ else if (status === "cancelled") statusCounts.cancelled += 1;
11993
+ else if (status === "timed_out") statusCounts.timedOut += 1;
11994
+ else if (status === "running") statusCounts.running += 1;
11995
+ else if (status === "queued") statusCounts.queued += 1;
11996
+ else statusCounts.other += 1;
11997
+ const agent = agents.get(row.run.agentId) ?? { id: row.run.agentId, name: row.agentName, count: 0 };
11998
+ agent.count += 1;
11999
+ agents.set(agent.id, agent);
12000
+ if (row.issue) {
12001
+ const issue = issues.get(row.issue.id) ?? { ...row.issue, count: 0 };
12002
+ issue.count += 1;
12003
+ issues.set(issue.id, issue);
12004
+ }
12005
+ const error = row.errorSummary?.trim();
12006
+ if (error) errors.set(error, (errors.get(error) ?? 0) + 1);
12007
+ }
12008
+ return {
12009
+ skill: { query: skill, evidenceType },
12010
+ summary: {
12011
+ total: rows.length,
12012
+ ...statusCounts,
12013
+ agents: [...agents.values()].sort((a, b) => b.count - a.count),
12014
+ issues: [...issues.values()].sort((a, b) => b.count - a.count),
12015
+ commonErrors: [...errors.entries()].map(([summary, count]) => ({ summary, count })).sort((a, b) => b.count - a.count).slice(0, 5)
12016
+ },
12017
+ rows,
12018
+ nextCommands: rows.slice(0, 5).map((row) => row.run.status === "failed" ? `rudder runs errors ${row.run.id}` : `rudder runs transcript ${row.run.id}`)
11757
12019
  };
11758
12020
  }
12021
+ function formatSkillRunReport(report) {
12022
+ const lines = [
12023
+ `skill=${report.skill.query} evidence=${report.skill.evidenceType} total=${report.summary.total} succeeded=${report.summary.succeeded} failed=${report.summary.failed} cancelled=${report.summary.cancelled} timedOut=${report.summary.timedOut}`
12024
+ ];
12025
+ if (report.summary.agents.length > 0) {
12026
+ lines.push(`agents=${report.summary.agents.map((agent) => `${agent.name ?? agent.id}:${agent.count}`).join(", ")}`);
12027
+ }
12028
+ if (report.summary.issues.length > 0) {
12029
+ lines.push(`issues=${report.summary.issues.map((issue) => `${issue.identifier ?? issue.id}:${issue.count}`).join(", ")}`);
12030
+ }
12031
+ if (report.summary.commonErrors.length > 0) {
12032
+ lines.push(`commonErrors=${report.summary.commonErrors.map((error) => `${clip2(error.summary, 80)}:${error.count}`).join(" | ")}`);
12033
+ }
12034
+ lines.push(...report.rows.map((row) => formatInlineSkillRun(row)));
12035
+ if (report.nextCommands.length > 0) {
12036
+ lines.push("next:");
12037
+ lines.push(...report.nextCommands.map((command) => ` ${command}`));
12038
+ }
12039
+ return lines;
12040
+ }
12041
+ function formatInlineSkillRun(row) {
12042
+ const issue = formatIssueRef(row.issue);
12043
+ const label = row.skillEvidence?.matchedSkillLabel && row.skillEvidence.matchedSkillLabel !== row.skillEvidence.matchedSkillKey ? ` label=${row.skillEvidence.matchedSkillLabel}` : "";
12044
+ const langfuse = readLangfuseTraceUrl(row.langfuse);
12045
+ return [
12046
+ `id=${row.run.id}`,
12047
+ `status=${row.run.status}`,
12048
+ `agent=${row.agentName ?? row.run.agentId}`,
12049
+ `issue=${issue}`,
12050
+ `runtime=${row.bundle.agentRuntimeType}`,
12051
+ `createdAt=${row.run.createdAt}`,
12052
+ `finishedAt=${row.run.finishedAt ?? "-"}`,
12053
+ `evidence=${row.skillEvidence?.evidenceType ?? "-"}`,
12054
+ `skill=${row.skillEvidence?.matchedSkillKey ?? "-"}${label}`,
12055
+ `langfuse=${langfuse ?? "-"}`,
12056
+ `error=${row.errorSummary ?? "-"}`,
12057
+ `next=${row.run.status === "failed" ? `rudder runs errors ${row.run.id}` : `rudder runs transcript ${row.run.id}`}`
12058
+ ].join(" ");
12059
+ }
12060
+ function formatIssueRef(issue) {
12061
+ if (!issue) return "-";
12062
+ return issue.identifier && issue.title ? `${issue.identifier} ${issue.title}` : issue.identifier ?? issue.title ?? issue.id;
12063
+ }
12064
+ function readLangfuseTraceUrl(value) {
12065
+ if (!value || typeof value !== "object") return null;
12066
+ const traceUrl = value.traceUrl;
12067
+ return typeof traceUrl === "string" && traceUrl.length > 0 ? traceUrl : null;
12068
+ }
11759
12069
  function formatRunEvent(row) {
11760
12070
  return {
11761
12071
  seq: row.seq,