@rudderhq/cli 0.3.6-canary.0 → 0.3.6-canary.10

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
@@ -572,6 +572,13 @@ var init_constants = __esm({
572
572
  }
573
573
  });
574
574
 
575
+ // ../packages/shared/dist/agent-run.js
576
+ var init_agent_run = __esm({
577
+ "../packages/shared/dist/agent-run.js"() {
578
+ "use strict";
579
+ }
580
+ });
581
+
575
582
  // ../packages/shared/dist/types/observability.js
576
583
  var init_observability = __esm({
577
584
  "../packages/shared/dist/types/observability.js"() {
@@ -784,7 +791,7 @@ var init_adapter_skills = __esm({
784
791
 
785
792
  // ../packages/shared/dist/validators/chat.js
786
793
  import { z as z4 } from "zod";
787
- var chatConversationStatusSchema, chatIssueCreationModeSchema, chatMessageRoleSchema, chatMessageKindSchema, chatMessageStatusSchema, chatContextEntityTypeSchema, createChatContextLinkSchema, createChatConversationSchema, setChatProjectContextSchema, updateChatConversationSchema, addChatMessageSchema, chatRichReferenceDisplaySchema, chatIssueIdentifierSchema, chatAskUserIdentifierSchema, chatAskUserOptionSchema, chatAskUserQuestionSchema, chatAskUserRequestSchema, chatIssueRichReferenceSchema, chatIssueCommentRichReferenceSchema, chatRichReferenceSchema, chatRichReferencesSchema, chatAutomationCreateSchema, createChatAttachmentMetadataSchema, chatIssueProposalSchema, convertChatToIssueSchema, chatOperationProposalSchema, resolveChatOperationProposalSchema, updateChatConversationUserStateSchema, updateMessengerThreadUserStateSchema, createMessengerCustomGroupSchema, updateMessengerCustomGroupSchema, reorderMessengerCustomGroupsSchema, assignMessengerCustomGroupEntrySchema, reorderMessengerCustomGroupEntriesSchema;
794
+ var chatConversationStatusSchema, chatIssueCreationModeSchema, chatMessageRoleSchema, chatMessageKindSchema, chatMessageStatusSchema, chatContextEntityTypeSchema, createChatContextLinkSchema, createChatConversationSchema, setChatProjectContextSchema, updateChatConversationSchema, addChatMessageSchema, chatRichReferenceDisplaySchema, chatIssueIdentifierSchema, chatAskUserIdentifierSchema, chatAskUserOptionSchema, chatAskUserQuestionSchema, chatAskUserRequestSchema, chatIssueRichReferenceSchema, chatIssueCommentRichReferenceSchema, chatRichReferenceSchema, chatRichReferencesSchema, chatAutomationCreateSchema, createChatAttachmentMetadataSchema, chatIssueProposalSchema, convertChatToIssueSchema, chatOperationProposalSchema, resolveChatOperationProposalSchema, updateChatConversationUserStateSchema, updateMessengerThreadUserStateSchema, createMessengerCustomGroupSchema, createMessengerCustomGroupWithEntriesSchema, updateMessengerCustomGroupSchema, reorderMessengerCustomGroupsSchema, assignMessengerCustomGroupEntrySchema, reorderMessengerCustomGroupEntriesSchema;
788
795
  var init_chat = __esm({
789
796
  "../packages/shared/dist/validators/chat.js"() {
790
797
  "use strict";
@@ -971,6 +978,9 @@ var init_chat = __esm({
971
978
  name: z4.string().trim().min(1).max(80),
972
979
  icon: z4.string().trim().min(1).max(24).optional().nullable()
973
980
  });
981
+ createMessengerCustomGroupWithEntriesSchema = createMessengerCustomGroupSchema.extend({
982
+ threadKeys: z4.array(z4.string().trim().min(1).max(240)).min(1).max(50)
983
+ });
974
984
  updateMessengerCustomGroupSchema = z4.object({
975
985
  name: z4.string().trim().min(1).max(80).optional(),
976
986
  icon: z4.string().trim().min(1).max(24).optional().nullable(),
@@ -1768,7 +1778,7 @@ var init_agent = __esm({
1768
1778
 
1769
1779
  // ../packages/shared/dist/validators/agent-integration.js
1770
1780
  import { z as z13 } from "zod";
1771
- var agentIntegrationProviderSchema, agentIntegrationStatusSchema, agentIntegrationTransportSchema, agentIntegrationProviderRegionSchema, agentIntegrationChatTypeSchema, agentIntegrationDropReasonSchema, agentIntegrationOutboundStatusSchema, createAgentIntegrationSchema;
1781
+ var agentIntegrationProviderSchema, agentIntegrationStatusSchema, agentIntegrationTransportSchema, agentIntegrationProviderRegionSchema, agentIntegrationChatTypeSchema, agentIntegrationDropReasonSchema, agentIntegrationOutboundStatusSchema, createAgentIntegrationSchema, connectAgentIntegrationSchema, feishuEventHeaderSchema, feishuSenderIdSchema, feishuMessageMentionSchema, feishuMessageSchema, feishuEventSchema, mockFeishuInboundEventSchema;
1772
1782
  var init_agent_integration = __esm({
1773
1783
  "../packages/shared/dist/validators/agent-integration.js"() {
1774
1784
  "use strict";
@@ -1792,6 +1802,59 @@ var init_agent_integration = __esm({
1792
1802
  installerUserId: z13.string().min(1).optional().nullable(),
1793
1803
  manageUrl: z13.string().url().optional().nullable()
1794
1804
  });
1805
+ connectAgentIntegrationSchema = createAgentIntegrationSchema.omit({ agentId: true });
1806
+ feishuEventHeaderSchema = z13.object({
1807
+ event_id: z13.string().min(1).optional(),
1808
+ app_id: z13.string().min(1).optional(),
1809
+ token: z13.string().min(1).optional(),
1810
+ create_time: z13.string().min(1).optional()
1811
+ }).passthrough();
1812
+ feishuSenderIdSchema = z13.object({
1813
+ open_id: z13.string().min(1).optional(),
1814
+ union_id: z13.string().min(1).optional()
1815
+ }).passthrough();
1816
+ feishuMessageMentionSchema = z13.object({
1817
+ key: z13.string().optional(),
1818
+ id: feishuSenderIdSchema.optional()
1819
+ }).passthrough();
1820
+ feishuMessageSchema = z13.object({
1821
+ message_id: z13.string().min(1).optional(),
1822
+ chat_id: z13.string().min(1).optional(),
1823
+ chat_type: agentIntegrationChatTypeSchema.optional(),
1824
+ message_type: z13.string().min(1).optional(),
1825
+ content: z13.string().optional(),
1826
+ mentions: z13.array(feishuMessageMentionSchema).optional(),
1827
+ parent_id: z13.string().min(1).optional().nullable()
1828
+ }).passthrough();
1829
+ feishuEventSchema = z13.object({
1830
+ sender: z13.object({
1831
+ sender_id: feishuSenderIdSchema.optional()
1832
+ }).passthrough().optional(),
1833
+ message: feishuMessageSchema.optional()
1834
+ }).passthrough();
1835
+ mockFeishuInboundEventSchema = z13.object({
1836
+ type: z13.string().min(1).optional(),
1837
+ token: z13.string().min(1).optional(),
1838
+ challenge: z13.string().min(1).optional(),
1839
+ mockVerificationToken: z13.string().min(1).optional(),
1840
+ mockEncryptKey: z13.string().min(1).optional(),
1841
+ eventId: z13.string().min(1).optional(),
1842
+ appId: z13.string().min(1).optional(),
1843
+ botOpenId: z13.string().min(1).optional().nullable(),
1844
+ chatId: z13.string().min(1).optional(),
1845
+ chatType: agentIntegrationChatTypeSchema.optional(),
1846
+ messageId: z13.string().min(1).optional(),
1847
+ senderOpenId: z13.string().min(1).optional(),
1848
+ senderUnionId: z13.string().min(1).optional().nullable(),
1849
+ body: z13.string().optional(),
1850
+ commandBody: z13.string().optional(),
1851
+ addressedToBot: z13.boolean().optional(),
1852
+ messageType: z13.string().min(1).optional(),
1853
+ parentMessageId: z13.string().min(1).optional().nullable(),
1854
+ receivedAt: z13.string().datetime().optional(),
1855
+ header: feishuEventHeaderSchema.optional(),
1856
+ event: feishuEventSchema.optional()
1857
+ }).passthrough();
1795
1858
  }
1796
1859
  });
1797
1860
 
@@ -2929,6 +2992,7 @@ var init_api = __esm({
2929
2992
  secrets: `${API_PREFIX}/secrets`,
2930
2993
  costs: `${API_PREFIX}/costs`,
2931
2994
  activity: `${API_PREFIX}/activity`,
2995
+ agentRuns: `${API_PREFIX}/agent-runs`,
2932
2996
  dashboard: `${API_PREFIX}/dashboard`,
2933
2997
  sidebarBadges: `${API_PREFIX}/sidebar-badges`,
2934
2998
  invites: `${API_PREFIX}/invites`,
@@ -2987,6 +3051,19 @@ var init_project_url_key = __esm({
2987
3051
  }
2988
3052
  });
2989
3053
 
3054
+ // ../packages/shared/dist/short-refs.js
3055
+ var SHORT_REF_PREFIX_BY_KIND, SHORT_REF_KIND_BY_PREFIX;
3056
+ var init_short_refs = __esm({
3057
+ "../packages/shared/dist/short-refs.js"() {
3058
+ "use strict";
3059
+ SHORT_REF_PREFIX_BY_KIND = {
3060
+ agent: "agt",
3061
+ issue_comment: "cmt"
3062
+ };
3063
+ SHORT_REF_KIND_BY_PREFIX = Object.fromEntries(Object.entries(SHORT_REF_PREFIX_BY_KIND).map(([kind, prefix]) => [prefix, kind]));
3064
+ }
3065
+ });
3066
+
2990
3067
  // ../packages/shared/dist/token-usage.js
2991
3068
  var init_token_usage = __esm({
2992
3069
  "../packages/shared/dist/token-usage.js"() {
@@ -3191,6 +3268,7 @@ var init_dist = __esm({
3191
3268
  "../packages/shared/dist/index.js"() {
3192
3269
  "use strict";
3193
3270
  init_constants();
3271
+ init_agent_run();
3194
3272
  init_observability();
3195
3273
  init_workspace_backup();
3196
3274
  init_validators();
@@ -3202,6 +3280,7 @@ var init_dist = __esm({
3202
3280
  init_organization_url_key();
3203
3281
  init_project_mentions();
3204
3282
  init_project_url_key();
3283
+ init_short_refs();
3205
3284
  init_token_usage();
3206
3285
  init_issue_activity();
3207
3286
  init_config_schema();
@@ -6966,7 +7045,7 @@ function printOutput(data, opts = {}) {
6966
7045
  }
6967
7046
  function formatInlineRecord(record, opts = {}) {
6968
7047
  const displayRecord = shouldShowFullIds(opts.fullIds) ? record : toCliShortIdOutput(record);
6969
- const keyOrder = ["identifier", "id", "name", "status", "priority", "title", "action"];
7048
+ const keyOrder = ["identifier", "shortRef", "id", "name", "status", "priority", "title", "action"];
6970
7049
  const seen = /* @__PURE__ */ new Set();
6971
7050
  const parts = [];
6972
7051
  for (const key of keyOrder) {
@@ -7237,6 +7316,7 @@ var RUDDER_AGENT_OPERATING_CONTRACT = [
7237
7316
  "",
7238
7317
  "- Issues: use `[](issue://<issue-id>)`; include `?c=<comment-id>` when linking to a specific comment.",
7239
7318
  "- Agents: use `[](agent://<agent-id>)` for reference-only links. In issue comments, use `[](agent://<agent-id>?intent=wake)` only when you intentionally want to wake that agent for attention or collaboration.",
7319
+ "- Automations: use `[](automation://<automation-id>)` when citing a Rudder automation.",
7240
7320
  "- Projects: use `[](project://<project-id>)` when citing a Rudder project.",
7241
7321
  "- Chat threads: use `[](chat://<conversation-id>)` when citing a Rudder chat conversation.",
7242
7322
  "- Skills: use `[](skill://<skill-ref>)` when citing a Rudder skill reference. The skill ref may be an org skill, agent skill, bundled Rudder skill, or local-machine skill ref; the UI resolves the display label when metadata is available.",
@@ -7252,7 +7332,7 @@ var RUDDER_AGENT_OPERATING_CONTRACT = [
7252
7332
  "",
7253
7333
  "You MUST use the `para-memory-files` skill for all memory operations: storing facts, writing daily notes, creating entities, running weekly synthesis, recalling past context, and managing shared work notes. The skill defines your three-layer memory system (knowledge graph, daily notes, tacit knowledge), the PARA folder structure, atomic fact schemas, memory decay rules, and recall conventions.",
7254
7334
  "",
7255
- "Keep stable preferences and operating lessons in `$AGENT_HOME/instructions/MEMORY.md`. Use `$AGENT_HOME/memory/YYYY-MM-DD.md` for daily notes and `$AGENT_HOME/life/` for structured long-term memory; those files are not auto-loaded.",
7335
+ "Keep stable preferences and operating lessons in `$AGENT_HOME/instructions/MEMORY.md`. Use `$AGENT_HOME/memory/YYYY-MM-DD.md` for daily notes and `$AGENT_HOME/life/` for structured long-term memory. Rudder injects bounded today/yesterday daily-memory excerpts in the startup context bundle; open the files directly when you need full detail.",
7256
7336
  "",
7257
7337
  "Invoke it whenever you need to remember, retrieve, or organize anything.",
7258
7338
  "",
@@ -7269,19 +7349,25 @@ var RUDDER_AGENT_OPERATING_CONTRACT = [
7269
7349
  var RUDDER_AGENT_HEARTBEAT_INSTRUCTION = [
7270
7350
  "# Rudder Heartbeat Instruction",
7271
7351
  "",
7272
- "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.",
7352
+ "This section is injected by Rudder for heartbeat scene runs. It is the platform-owned timed-wakeup pipeline.",
7273
7353
  "",
7274
7354
  "## Heartbeat Pipeline",
7275
7355
  "",
7276
7356
  "1. Identify yourself and inspect wake context, including `RUDDER_TASK_ID`, `RUDDER_WAKE_REASON`, `RUDDER_WAKE_COMMENT_ID`, and `RUDDER_APPROVAL_ID` when present.",
7277
- "2. Handle approval follow-up first: read the approval and linked issues, then close resolved work or comment on what remains.",
7278
- "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.",
7279
- "4. For mention wakes, read the wake comment before acting. Mentions request attention; they do not transfer ownership unless the comment explicitly says so. If the issue is not assigned to you, including user-owned or unassigned issues, and the comment does not explicitly ask you to implement, modify files, close the issue, or take ownership, respond to the comment itself instead of executing the whole issue.",
7280
- "5. Checkout before doing assignee task work. A `409` means another agent owns the task; do not retry it.",
7281
- "6. Load compact issue context, do one bounded useful chunk, and preserve evidence.",
7282
- "7. Before exiting active work, leave exactly one durable signal: progress, done, blocked, explicit handoff, or structured review decision.",
7283
- "8. Treat passive follow-up as close-out governance, not a fresh assignment.",
7284
- "9. Treat review close-out follow-up as review governance; free-form accept/reject text is not a durable decision.",
7357
+ "2. Local Planning Check:",
7358
+ " ",
7359
+ " 1. Read today's plan from `$AGENT_HOME/memory/YYYY-MM-DD.md` under \"## Today's Plan\". You need to clearly know your work plan for today, and work according to the plan.",
7360
+ " 2. Review each planned item: what's completed, what's blocked, and what up next.",
7361
+ " 3. Record progress updates in the daily notes.",
7362
+ " ",
7363
+ "3.Then handle approval follow-up: read the approval and linked issues, then close resolved work or comment on what remains.",
7364
+ "4. 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.",
7365
+ "5. For mention wakes, read the wake comment before acting. Mentions request attention; they do not transfer ownership unless the comment explicitly says so. If the issue is not assigned to you, including user-owned or unassigned issues, and the comment does not explicitly ask you to implement, modify files, close the issue, or take ownership, respond to the comment itself instead of executing the whole issue.",
7366
+ "6. Checkout before doing assignee task work. A `409` means another agent owns the task; do not retry it.",
7367
+ "7. Load compact issue context, do one bounded useful chunk, and preserve evidence.",
7368
+ "8. Before exiting active work, leave exactly one durable signal: progress, done, blocked, explicit handoff, or structured review decision.",
7369
+ "9. Treat passive follow-up as close-out governance, not a fresh assignment.",
7370
+ "10. Treat review close-out follow-up as review governance; free-form accept/reject text is not a durable decision.",
7285
7371
  "",
7286
7372
  "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."
7287
7373
  ].join("\n");
@@ -7390,9 +7476,9 @@ var AGENT_CLI_CAPABILITIES = [
7390
7476
  },
7391
7477
  {
7392
7478
  id: "agent.get",
7393
- command: "rudder agent get <agent-id-or-shortname>",
7479
+ command: "rudder agent get <agent-id-or-shortname-or-agt-ref>",
7394
7480
  category: "agent",
7395
- description: "Read one agent by id or shortname.",
7481
+ description: "Read one agent by id, shortname, or agt_<uuid-prefix> short ref.",
7396
7482
  mutating: false,
7397
7483
  contract: "compat",
7398
7484
  requiresOrgId: false,
@@ -7546,9 +7632,9 @@ var AGENT_CLI_CAPABILITIES = [
7546
7632
  },
7547
7633
  {
7548
7634
  id: "issue.context",
7549
- command: "rudder issue context <issue>",
7635
+ command: "rudder issue context <issue> [--wake-comment-id <comment-id-or-cmt-ref>]",
7550
7636
  category: "issue",
7551
- description: "Read the compact heartbeat context for an issue.",
7637
+ description: "Read the compact heartbeat context for an issue; wake comments may be addressed by full id or cmt_<uuid-prefix>.",
7552
7638
  mutating: false,
7553
7639
  contract: "agent-v1",
7554
7640
  requiresOrgId: false,
@@ -7582,9 +7668,9 @@ var AGENT_CLI_CAPABILITIES = [
7582
7668
  },
7583
7669
  {
7584
7670
  id: "issue.comments.list",
7585
- command: "rudder issue comments list <issue>",
7671
+ command: "rudder issue comments list <issue> [--after <comment-id-or-cmt-ref>]",
7586
7672
  category: "issue",
7587
- description: "List issue comments, optionally only newer comments after a cursor.",
7673
+ description: "List issue comments, optionally only newer comments after a full comment id or cmt_<uuid-prefix> with --after.",
7588
7674
  mutating: false,
7589
7675
  contract: "agent-v1",
7590
7676
  requiresOrgId: false,
@@ -7594,9 +7680,9 @@ var AGENT_CLI_CAPABILITIES = [
7594
7680
  },
7595
7681
  {
7596
7682
  id: "issue.comments.get",
7597
- command: "rudder issue comments get <issue> <comment-id>",
7683
+ command: "rudder issue comments get <issue> <comment-id-or-cmt-ref>",
7598
7684
  category: "issue",
7599
- description: "Read one issue comment by id.",
7685
+ description: "Read one issue comment by full id or cmt_<uuid-prefix> scoped to the issue.",
7600
7686
  mutating: false,
7601
7687
  contract: "agent-v1",
7602
7688
  requiresOrgId: false,
@@ -8373,6 +8459,26 @@ function formatAgentCliCapabilitiesHumanReadable(capabilities = getAgentCliCapab
8373
8459
  return lines.join("\n").trimEnd();
8374
8460
  }
8375
8461
 
8462
+ // src/commands/client/help.ts
8463
+ function formatExamplesAndCautions(notes) {
8464
+ const sections = [];
8465
+ if (notes.examples?.length) {
8466
+ sections.push(["Examples:", ...notes.examples.map(formatHelpExample)].join("\n"));
8467
+ }
8468
+ if (notes.cautions?.length) {
8469
+ sections.push(["Cautions:", ...notes.cautions.map((caution) => ` - ${caution}`)].join("\n"));
8470
+ }
8471
+ return sections.length > 0 ? `
8472
+ ${sections.join("\n\n")}` : "";
8473
+ }
8474
+ function formatHelpExample(example) {
8475
+ if (typeof example === "string") {
8476
+ return ` ${example}`;
8477
+ }
8478
+ return ` ${example.description}
8479
+ ${example.command}`;
8480
+ }
8481
+
8376
8482
  // src/commands/client/agent.ts
8377
8483
  var __moduleDir = path10.dirname(fileURLToPath3(import.meta.url));
8378
8484
  function codexSkillsHome() {
@@ -8537,6 +8643,7 @@ function registerAgentCommands(program) {
8537
8643
  for (const row of rows) {
8538
8644
  console.log(
8539
8645
  formatInlineRecord({
8646
+ shortRef: row.shortRef,
8540
8647
  id: row.id,
8541
8648
  name: row.name,
8542
8649
  role: row.role,
@@ -8689,7 +8796,22 @@ function registerAgentCommands(program) {
8689
8796
  })
8690
8797
  );
8691
8798
  addCommonClientOptions(
8692
- skills.command("enable").description(getAgentCliCapabilityById("agent.skills.enable").description).argument("<agentId>", "Agent ID").argument("<selectionRefs...>", "Skill selection refs to enable").action(async (agentId, selectionRefs, opts) => {
8799
+ skills.command("enable").description(getAgentCliCapabilityById("agent.skills.enable").description).argument("<agentId>", "Agent ID").argument("<selectionRefs...>", "Skill selection refs to enable").addHelpText("after", formatExamplesAndCautions({
8800
+ examples: [
8801
+ {
8802
+ description: "Add skills while preserving the agent's existing enabled set:",
8803
+ command: "rudder agent skills enable <agent-id> rudder/rudder local/abc123/custom-skill"
8804
+ },
8805
+ {
8806
+ description: "Enable one newly created private skill and inspect the resulting snapshot:",
8807
+ command: "rudder agent skills enable <agent-id> <selection-ref> --json"
8808
+ }
8809
+ ],
8810
+ cautions: [
8811
+ "This is additive and preserves existing enabled optional skills.",
8812
+ "After creating or copying a private skill, enable it before claiming future runs will load it."
8813
+ ]
8814
+ })).action(async (agentId, selectionRefs, opts) => {
8693
8815
  try {
8694
8816
  const ctx = resolveCommandContext(opts);
8695
8817
  const snapshot = await ctx.api.post(`/api/agents/${agentId}/skills/enable`, {
@@ -8705,7 +8827,22 @@ function registerAgentCommands(program) {
8705
8827
  skills.command("sync").description(getAgentCliCapabilityById("agent.skills.sync").description).argument("<agentId>", "Agent ID").requiredOption(
8706
8828
  "--desired-skills <csv>",
8707
8829
  "Comma-separated desired skill refs (for example rudder/rudder)"
8708
- ).action(async (agentId, opts) => {
8830
+ ).addHelpText("after", formatExamplesAndCautions({
8831
+ examples: [
8832
+ {
8833
+ description: "Replace the optional enabled set with an explicitly preserved CSV:",
8834
+ command: 'rudder agent skills sync <agent-id> --desired-skills "rudder/rudder,local/abc123/custom-skill"'
8835
+ },
8836
+ {
8837
+ description: "Clear optional skills only when that is the intended final state:",
8838
+ command: 'rudder agent skills sync <agent-id> --desired-skills "" --json'
8839
+ }
8840
+ ],
8841
+ cautions: [
8842
+ "Sync replaces the full optional enabled-skill set; use enable for additive changes.",
8843
+ "Preserve every existing desired skill in the CSV unless you intentionally want to disable it."
8844
+ ]
8845
+ })).action(async (agentId, opts) => {
8709
8846
  try {
8710
8847
  const ctx = resolveCommandContext(opts);
8711
8848
  const snapshot = await ctx.api.post(`/api/agents/${agentId}/skills/sync`, {
@@ -8994,7 +9131,22 @@ function registerApprovalCommands(program) {
8994
9131
  { includeCompany: false }
8995
9132
  );
8996
9133
  addCommonClientOptions(
8997
- approval.command("approve").description("Approve an approval request").argument("<approvalId>", "Approval ID").option("--decision-note <text>", "Decision note").option("--decided-by-user-id <id>", "Decision actor user ID").action(async (approvalId, opts) => {
9134
+ approval.command("approve").description("Approve an approval request").argument("<approvalId>", "Approval ID").option("--decision-note <text>", "Decision note").option("--decided-by-user-id <id>", "Decision actor user ID").addHelpText("after", formatExamplesAndCautions({
9135
+ examples: [
9136
+ {
9137
+ description: "Read the approval payload before deciding:",
9138
+ command: "rudder approval get <approval-id> --json"
9139
+ },
9140
+ {
9141
+ description: "Record the durable approval decision with concise context:",
9142
+ command: 'rudder approval approve <approval-id> --decision-note "Approved after reviewing linked issues" --json'
9143
+ }
9144
+ ],
9145
+ cautions: [
9146
+ "Read the approval and linked issues before approving; this is a governed mutation.",
9147
+ "approval approve/reject use --decision-note, while approval comment uses --body-file."
9148
+ ]
9149
+ })).action(async (approvalId, opts) => {
8998
9150
  try {
8999
9151
  const ctx = resolveCommandContext(opts);
9000
9152
  const payload = resolveApprovalSchema.parse({
@@ -9053,7 +9205,22 @@ function registerApprovalCommands(program) {
9053
9205
  })
9054
9206
  );
9055
9207
  addCommonClientOptions(
9056
- approval.command("comment").description(getAgentCliCapabilityById("approval.comment").description).argument("<approvalId>", "Approval ID").option("--body-file <path>", "Read comment body from a file, or '-' for stdin").action(async (approvalId, opts) => {
9208
+ approval.command("comment").description(getAgentCliCapabilityById("approval.comment").description).argument("<approvalId>", "Approval ID").option("--body-file <path>", "Read comment body from a file, or '-' for stdin").addHelpText("after", formatExamplesAndCautions({
9209
+ examples: [
9210
+ {
9211
+ description: "Add a longer Markdown discussion note without deciding:",
9212
+ command: "rudder approval comment <approval-id> --body-file ./approval-note.md --json"
9213
+ },
9214
+ {
9215
+ description: "Ask a short follow-up from stdin:",
9216
+ command: "printf '%s\\n' 'Need one more linked issue checked.' | rudder approval comment <approval-id> --body-file -"
9217
+ }
9218
+ ],
9219
+ cautions: [
9220
+ "Comments do not approve or reject; use approve/reject/request-revision for the durable decision.",
9221
+ "Use --body-file for multiline Markdown. Do not pass decision notes here."
9222
+ ]
9223
+ })).action(async (approvalId, opts) => {
9057
9224
  try {
9058
9225
  const ctx = resolveCommandContext(opts);
9059
9226
  const body = await resolveBodyFile(opts.bodyFile);
@@ -9345,7 +9512,22 @@ function registerAutomationCommands(program) {
9345
9512
  })
9346
9513
  );
9347
9514
  addCommonClientOptions(
9348
- automation.command("run").description(getAgentCliCapabilityById("automation.run").description).argument("<automationId>", "Automation ID").option("--trigger-id <id>", "Trigger ID").option("--payload <json>", "Manual run payload JSON").option("--idempotency-key <key>", "Idempotency key").option("--source <source>", "Run source", "manual").action(async (automationId, opts) => {
9515
+ automation.command("run").description(getAgentCliCapabilityById("automation.run").description).argument("<automationId>", "Automation ID").option("--trigger-id <id>", "Trigger ID").option("--payload <json>", "Manual run payload JSON").option("--idempotency-key <key>", "Idempotency key").option("--source <source>", "Run source", "manual").addHelpText("after", formatExamplesAndCautions({
9516
+ examples: [
9517
+ {
9518
+ description: "Run a verified automation manually with an explicit payload:",
9519
+ command: `rudder automation run <automation-id> --payload '{"manual":true}' --json`
9520
+ },
9521
+ {
9522
+ description: "Retry a trigger-specific smoke run with duplicate protection:",
9523
+ command: "rudder automation run <automation-id> --trigger-id <trigger-id> --idempotency-key zst-123-smoke"
9524
+ }
9525
+ ],
9526
+ cautions: [
9527
+ "Confirm the automation and trigger target before running; manual runs can create tracked issues or chats.",
9528
+ "Use an idempotency key for retried manual invocations so duplicate work is easier to detect."
9529
+ ]
9530
+ })).action(async (automationId, opts) => {
9349
9531
  try {
9350
9532
  const ctx = resolveCommandContext(opts);
9351
9533
  const payload = runAutomationSchema.parse({
@@ -9535,7 +9717,22 @@ function registerChatCommands(program) {
9535
9717
  })
9536
9718
  );
9537
9719
  addCommonClientOptions(
9538
- chat.command("read").description(getAgentCliCapabilityById("chat.read").description).argument("<chatId>", "Chat conversation ID").option("--include-transcript", "Include assistant transcript entries").option("--include-output", "Alias for --include-transcript").option("--include-outputs", "Alias for --include-transcript").option("--limit <n>", "Maximum recent messages", "20").option("--turn-limit <n>", "Alias for --limit for chat turn snapshots").option("--cursor <cursor>", "Stable message cursor returned in page.nextCursor").option("--max-output-chars <n>", "Maximum transcript output chars for human output", "1200").action(async (chatId, opts) => {
9720
+ chat.command("read").description(getAgentCliCapabilityById("chat.read").description).argument("<chatId>", "Chat conversation ID").option("--include-transcript", "Include assistant transcript entries").option("--include-output", "Alias for --include-transcript").option("--include-outputs", "Alias for --include-transcript").option("--limit <n>", "Maximum recent messages", "20").option("--turn-limit <n>", "Alias for --limit for chat turn snapshots").option("--cursor <cursor>", "Stable message cursor returned in page.nextCursor").option("--max-output-chars <n>", "Maximum transcript output chars for human output", "1200").addHelpText("after", formatExamplesAndCautions({
9721
+ examples: [
9722
+ {
9723
+ description: "Read a bounded conversation page with transcript output when needed:",
9724
+ command: "rudder chat read <chat-id> --turn-limit 20 --include-output"
9725
+ },
9726
+ {
9727
+ description: "Continue from a stable cursor in scripts:",
9728
+ command: "rudder chat read <chat-id> --cursor <nextCursor> --json"
9729
+ }
9730
+ ],
9731
+ cautions: [
9732
+ "Read bounded pages first; long chats can include large transcript payloads.",
9733
+ "Use --include-output only when transcript output is needed for diagnosis."
9734
+ ]
9735
+ })).action(async (chatId, opts) => {
9539
9736
  try {
9540
9737
  const ctx = resolveCommandContext(opts);
9541
9738
  const [conversation, page] = await Promise.all([
@@ -9583,7 +9780,22 @@ function registerChatCommands(program) {
9583
9780
  { includeCompany: false }
9584
9781
  );
9585
9782
  addCommonClientOptions(
9586
- chat.command("send").description(getAgentCliCapabilityById("chat.send").description).argument("<chatId>", "Chat conversation ID").option("--body <text>", "Message body").option("--edit-user-message-id <id>", "Regenerate/edit from a prior user message").action(async (chatId, opts) => {
9783
+ chat.command("send").description(getAgentCliCapabilityById("chat.send").description).argument("<chatId>", "Chat conversation ID").option("--body <text>", "Message body").option("--edit-user-message-id <id>", "Regenerate/edit from a prior user message").addHelpText("after", formatExamplesAndCautions({
9784
+ examples: [
9785
+ {
9786
+ description: "Append a short agent-authored status note:",
9787
+ command: 'rudder chat send <chat-id> --body "Status: validation is running"'
9788
+ },
9789
+ {
9790
+ description: "Send a longer or multiline note through stdin:",
9791
+ command: "printf '%s\\n' 'Multiline note' | rudder chat send <chat-id>"
9792
+ }
9793
+ ],
9794
+ cautions: [
9795
+ "chat send accepts --body or stdin; it does not support --body-file.",
9796
+ "Agent-authenticated sends append an agent-authored message and do not start a new assistant reply."
9797
+ ]
9798
+ })).action(async (chatId, opts) => {
9587
9799
  try {
9588
9800
  const ctx = resolveCommandContext(opts);
9589
9801
  const body = opts.body ?? await readStdin();
@@ -11177,7 +11389,22 @@ function registerIssueCommands(program) {
11177
11389
  })
11178
11390
  );
11179
11391
  addCommonClientOptions(
11180
- issue.command("comment").description(getAgentCliCapabilityById("issue.comment").description).argument("<issueId>", "Issue ID").option("--body-file <path>", "Read comment body from a file, or '-' for stdin").option("--image <path>", "Image file to upload and append to the comment; may be repeated", collectImagePath, []).option("--reopen", "Reopen if issue is done/cancelled").action(async (issueId, opts) => {
11392
+ issue.command("comment").description(getAgentCliCapabilityById("issue.comment").description).argument("<issueId>", "Issue ID").option("--body-file <path>", "Read comment body from a file, or '-' for stdin").option("--image <path>", "Image file to upload and append to the comment; may be repeated", collectImagePath, []).option("--reopen", "Reopen if issue is done/cancelled").addHelpText("after", formatExamplesAndCautions({
11393
+ examples: [
11394
+ {
11395
+ description: "Progress update with attached screenshot evidence:",
11396
+ command: "rudder issue comment ZST-123 --body-file ./progress.md --image ./screenshot.png --json"
11397
+ },
11398
+ {
11399
+ description: "Short stdin status when a separate file is unnecessary:",
11400
+ command: "printf '%s\\n' 'Short status' | rudder issue comment ZST-123 --body-file -"
11401
+ }
11402
+ ],
11403
+ cautions: [
11404
+ "Use --body-file for multiline Markdown; the old --body option is intentionally rejected.",
11405
+ "Attach local visual evidence with --image instead of leaving only a filesystem path in the comment."
11406
+ ]
11407
+ })).action(async (issueId, opts) => {
11181
11408
  try {
11182
11409
  const ctx = resolveCommandContext(opts);
11183
11410
  const bodyText = await resolveFileTextInput({
@@ -11205,7 +11432,22 @@ function registerIssueCommands(program) {
11205
11432
  issue.command("review").description(getAgentCliCapabilityById("issue.review").description).argument("<issueId>", "Issue ID").requiredOption(
11206
11433
  "--decision <decision>",
11207
11434
  "Review decision: approve, request_changes, needs_followup, or blocked"
11208
- ).option("--comment-file <path>", "Read required review comment from a file, or '-' for stdin").action(async (issueId, opts) => {
11435
+ ).option("--comment-file <path>", "Read required review comment from a file, or '-' for stdin").addHelpText("after", formatExamplesAndCautions({
11436
+ examples: [
11437
+ {
11438
+ description: "Return implementation work with durable review feedback:",
11439
+ command: "rudder issue review ZST-123 --decision request_changes --comment-file ./review.md --json"
11440
+ },
11441
+ {
11442
+ description: "Approve after reading the issue evidence and validation:",
11443
+ command: "rudder issue review ZST-123 --decision approve --comment-file ./review.md"
11444
+ }
11445
+ ],
11446
+ cautions: [
11447
+ "Free-form comments are not durable review decisions; use this command for approve/request_changes/etc.",
11448
+ "Approving an implementation issue can move it to done, so use request_changes when returning it for fixes."
11449
+ ]
11450
+ })).action(async (issueId, opts) => {
11209
11451
  try {
11210
11452
  const ctx = resolveCommandContext(opts);
11211
11453
  const decision = parseReviewDecision(opts.decision);
@@ -11245,7 +11487,22 @@ function registerIssueCommands(program) {
11245
11487
  })
11246
11488
  );
11247
11489
  addCommonClientOptions(
11248
- issue.command("done").description(getAgentCliCapabilityById("issue.done").description).argument("<issueId>", "Issue ID").option("--comment-file <path>", "Read required completion comment from a file, or '-' for stdin").option("--image <path>", "Image file to upload and append to the completion comment; may be repeated", collectImagePath, []).action(async (issueId, opts) => {
11490
+ issue.command("done").description(getAgentCliCapabilityById("issue.done").description).argument("<issueId>", "Issue ID").option("--comment-file <path>", "Read required completion comment from a file, or '-' for stdin").option("--image <path>", "Image file to upload and append to the completion comment; may be repeated", collectImagePath, []).addHelpText("after", formatExamplesAndCautions({
11491
+ examples: [
11492
+ {
11493
+ description: "Close out with validation summary and visual evidence:",
11494
+ command: "rudder issue done ZST-123 --comment-file ./done.md --image ./screenshot.png --json"
11495
+ },
11496
+ {
11497
+ description: "Read the completion note from stdin in scripts:",
11498
+ command: "rudder issue done ZST-123 --comment-file - < ./done.md"
11499
+ }
11500
+ ],
11501
+ cautions: [
11502
+ "Include validation evidence and commit/push status in the completion comment.",
11503
+ "If the server reports a run ownership conflict, stop and inspect the issue/run instead of retrying blindly."
11504
+ ]
11505
+ })).action(async (issueId, opts) => {
11249
11506
  try {
11250
11507
  const ctx = resolveCommandContext(opts);
11251
11508
  const commentText = await resolveFileTextInput({
@@ -11288,7 +11545,7 @@ function registerIssueCommands(program) {
11288
11545
  );
11289
11546
  const comments = issue.command("comments").description("Issue comment operations");
11290
11547
  addCommonClientOptions(
11291
- comments.command("list").description(getAgentCliCapabilityById("issue.comments.list").description).argument("<issueId>", "Issue ID").option("--after <commentId>", "Only return comments after this comment ID").option("--order <order>", "Comment ordering (asc or desc)", "desc").action(async (issueId, opts) => {
11548
+ comments.command("list").description(getAgentCliCapabilityById("issue.comments.list").description).argument("<issueId>", "Issue ID").option("--after <commentId>", "Only return comments after this full comment ID or cmt_<uuid-prefix>").option("--order <order>", "Comment ordering (asc or desc)", "desc").action(async (issueId, opts) => {
11292
11549
  try {
11293
11550
  const ctx = resolveCommandContext(opts);
11294
11551
  const params = new URLSearchParams();
@@ -11305,7 +11562,7 @@ function registerIssueCommands(program) {
11305
11562
  })
11306
11563
  );
11307
11564
  addCommonClientOptions(
11308
- comments.command("get").description(getAgentCliCapabilityById("issue.comments.get").description).argument("<issueId>", "Issue ID").argument("<commentId>", "Comment ID").action(async (issueId, commentId, opts) => {
11565
+ comments.command("get").description(getAgentCliCapabilityById("issue.comments.get").description).argument("<issueId>", "Issue ID").argument("<commentId>", "Full comment ID or cmt_<uuid-prefix>").action(async (issueId, commentId, opts) => {
11309
11566
  try {
11310
11567
  const ctx = resolveCommandContext(opts);
11311
11568
  const row = await ctx.api.get(`/api/issues/${issueId}/comments/${commentId}`);
@@ -11624,7 +11881,22 @@ function registerLibraryCommands(program) {
11624
11881
  { includeCompany: true }
11625
11882
  );
11626
11883
  addCommonClientOptions(
11627
- file.command("ref").description(getAgentCliCapabilityById("library.file.ref").description).argument("<filePath>", "Library file path").action(async (filePath, opts) => {
11884
+ file.command("ref").description(getAgentCliCapabilityById("library.file.ref").description).argument("<filePath>", "Library file path").addHelpText("after", formatExamplesAndCautions({
11885
+ examples: [
11886
+ {
11887
+ description: "Return the renderable Markdown link for a known Library file:",
11888
+ command: "rudder library file ref projects/rudder/proposals/plan.md --json"
11889
+ },
11890
+ {
11891
+ description: "Reference a file under the current project Library path:",
11892
+ command: 'rudder library file ref "$RUDDER_PROJECT_LIBRARY_PATH/proposals/plan.md" --json'
11893
+ }
11894
+ ],
11895
+ cautions: [
11896
+ "Pass the Library-relative path, not an absolute filesystem path.",
11897
+ "Use the returned markdownLink in issue comments instead of hand-writing library-entry URLs."
11898
+ ]
11899
+ })).action(async (filePath, opts) => {
11628
11900
  try {
11629
11901
  await printLibraryFileReference(filePath, opts);
11630
11902
  } catch (err) {
@@ -11634,7 +11906,22 @@ function registerLibraryCommands(program) {
11634
11906
  { includeCompany: true }
11635
11907
  );
11636
11908
  addCommonClientOptions(
11637
- file.command("put").description(getAgentCliCapabilityById("library.file.put").description).argument("<filePath>", "Library file path").option("--body-file <path>", "Read file content from a file, or '-' for stdin").action(async (filePath, opts) => {
11909
+ file.command("put").description(getAgentCliCapabilityById("library.file.put").description).argument("<filePath>", "Library file path").option("--body-file <path>", "Read file content from a file, or '-' for stdin").addHelpText("after", formatExamplesAndCautions({
11910
+ examples: [
11911
+ {
11912
+ description: "Upload a durable Markdown artifact from a local file:",
11913
+ command: "rudder library file put projects/rudder/proposals/plan.md --body-file ./plan.md --json"
11914
+ },
11915
+ {
11916
+ description: "Write a small generated artifact from stdin:",
11917
+ command: "printf '%s\\n' '# Plan' | rudder library file put projects/rudder/proposals/plan.md --body-file -"
11918
+ }
11919
+ ],
11920
+ cautions: [
11921
+ "Use --body-file for content; the old --body option is intentionally rejected.",
11922
+ "For local trusted runs, prefer writing durable files under the project Library root, then use file ref for the renderable link."
11923
+ ]
11924
+ })).action(async (filePath, opts) => {
11638
11925
  try {
11639
11926
  const ctx = resolveCommandContext(opts, { requireCompany: true });
11640
11927
  const body = await resolveBodyFileInput(opts.bodyFile);
@@ -11921,7 +12208,22 @@ function registerProjectCommands(program) {
11921
12208
  { includeCompany: false }
11922
12209
  );
11923
12210
  addCommonClientOptions(
11924
- project.command("create").description(getAgentCliCapabilityById("project.create").description).option("-O, --org-id <id>", "Organization ID").requiredOption("--name <name>", "Project name").option("--description <text>", "Project description").option("--status <status>", "Project status").option("--goal-id <id>", "Primary goal ID").option("--goal-ids <csv>", "Comma-separated goal IDs").option("--lead-agent-id <id>", "Lead agent ID").option("--target-date <date>", "Target date").option("--color <value>", "Project color or supported gradient token").action(async (opts) => {
12211
+ project.command("create").description(getAgentCliCapabilityById("project.create").description).option("-O, --org-id <id>", "Organization ID").requiredOption("--name <name>", "Project name").option("--description <text>", "Project description").option("--status <status>", "Project status").option("--goal-id <id>", "Primary goal ID").option("--goal-ids <csv>", "Comma-separated goal IDs").option("--lead-agent-id <id>", "Lead agent ID").option("--target-date <date>", "Target date").option("--color <value>", "Project color or supported gradient token").addHelpText("after", formatExamplesAndCautions({
12212
+ examples: [
12213
+ {
12214
+ description: "Create a new active workstream after confirming it does not already exist:",
12215
+ command: 'rudder project create --org-id <org-id> --name "Rudder dev" --status in_progress --json'
12216
+ },
12217
+ {
12218
+ description: "Create a project tied to a goal and responsible agent:",
12219
+ command: 'rudder project create --org-id <org-id> --name "Release" --goal-id <goal-id> --lead-agent-id <agent-id>'
12220
+ }
12221
+ ],
12222
+ cautions: [
12223
+ "Project mutations are organization-scoped; pass --org-id when context might be ambiguous.",
12224
+ "Use existing project IDs/shortnames for updates instead of creating duplicate project containers."
12225
+ ]
12226
+ })).action(async (opts) => {
11925
12227
  try {
11926
12228
  const ctx = resolveCommandContext(opts, { requireCompany: true });
11927
12229
  const payload = createProjectSchema.parse({
@@ -11943,7 +12245,22 @@ function registerProjectCommands(program) {
11943
12245
  { includeCompany: false }
11944
12246
  );
11945
12247
  addCommonClientOptions(
11946
- project.command("update").description(getAgentCliCapabilityById("project.update").description).argument("<projectIdOrShortname>", "Project ID or shortname").option("-O, --org-id <id>", "Organization ID for shortname resolution").option("--name <name>", "Project name").option("--description <text>", "Project description").option("--status <status>", "Project status").option("--goal-id <id>", "Primary goal ID").option("--goal-ids <csv>", "Comma-separated goal IDs").option("--lead-agent-id <id>", "Lead agent ID").option("--target-date <date>", "Target date").option("--color <value>", "Project color or supported gradient token").option("--archived-at <iso8601|null>", "Set archivedAt timestamp or literal 'null'").action(async (projectRef, opts) => {
12248
+ project.command("update").description(getAgentCliCapabilityById("project.update").description).argument("<projectIdOrShortname>", "Project ID or shortname").option("-O, --org-id <id>", "Organization ID for shortname resolution").option("--name <name>", "Project name").option("--description <text>", "Project description").option("--status <status>", "Project status").option("--goal-id <id>", "Primary goal ID").option("--goal-ids <csv>", "Comma-separated goal IDs").option("--lead-agent-id <id>", "Lead agent ID").option("--target-date <date>", "Target date").option("--color <value>", "Project color or supported gradient token").option("--archived-at <iso8601|null>", "Set archivedAt timestamp or literal 'null'").addHelpText("after", formatExamplesAndCautions({
12249
+ examples: [
12250
+ {
12251
+ description: "Move a known project shortname under the intended org:",
12252
+ command: "rudder project update rudder-dev --org-id <org-id> --status in_progress --json"
12253
+ },
12254
+ {
12255
+ description: "Unarchive a verified project id:",
12256
+ command: "rudder project update <project-id> --archived-at null"
12257
+ }
12258
+ ],
12259
+ cautions: [
12260
+ "Shortname resolution needs the intended organization; include --org-id for cross-org local contexts.",
12261
+ "Archiving and unarchiving changes project visibility, so verify the target with project get first."
12262
+ ]
12263
+ })).action(async (projectRef, opts) => {
11947
12264
  try {
11948
12265
  const ctx = resolveCommandContext(opts);
11949
12266
  const payload = updateProjectSchema.parse({
@@ -11986,7 +12303,22 @@ function projectPath(projectRef, orgId) {
11986
12303
  function registerRunsCommands(program) {
11987
12304
  const runs = program.command("runs").description("Run debugging operations");
11988
12305
  addCommonClientOptions(
11989
- 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) => {
12306
+ 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").addHelpText("after", formatExamplesAndCautions({
12307
+ examples: [
12308
+ {
12309
+ description: "Find recent failures for one agent before opening transcripts:",
12310
+ command: "rudder runs list --org-id <org-id> --agent-id <agent-id> --status failed --limit 20"
12311
+ },
12312
+ {
12313
+ description: "Collect skill-specific evidence for a linked issue:",
12314
+ command: "rudder runs list --org-id <org-id> --issue-id ZST-123 --used-skill release-maintainer --json"
12315
+ }
12316
+ ],
12317
+ cautions: [
12318
+ "Filter first by org, agent, issue, status, skill, or time; do not start by dumping broad run history.",
12319
+ "Use runs errors or runs transcript for detail instead of expecting list to return full debug payloads."
12320
+ ]
12321
+ })).action(async (opts) => {
11990
12322
  try {
11991
12323
  assertSingleSkillFilter(opts);
11992
12324
  const ctx = resolveCommandContext(opts, { requireCompany: true });
@@ -12051,7 +12383,22 @@ function registerRunsCommands(program) {
12051
12383
  })
12052
12384
  );
12053
12385
  addCommonClientOptions(
12054
- runs.command("transcript").description(getAgentCliCapabilityById("runs.transcript").description).argument("<runId>", "Run ID or short run ID").option("--errors-only", "Show only error transcript rows").option("--around-error <id>", "Show context around a run error id such as step-12").option("--context-turns <n>", "Turns around --around-error", "1").option("--cursor <cursor>", "Stable transcript cursor returned in page.nextCursor").option("--turn-limit <n>", "Maximum turns to return", "20").option("--chronological", "Show oldest-first instead of default newest-first").option("--narrative", "Use a narrative human layout").option("--max-chars <n>", "Maximum output characters per row", "1200").option("--max-output-chars <n>", "Alias for --max-chars").option("--include-output", "Include row output in compact human transcript rows").option("--include-outputs", "Alias for --include-output").action(async (runId, opts) => {
12386
+ runs.command("transcript").description(getAgentCliCapabilityById("runs.transcript").description).argument("<runId>", "Run ID or short run ID").option("--errors-only", "Show only error transcript rows").option("--around-error <id>", "Show context around a run error id such as step-12").option("--context-turns <n>", "Turns around --around-error", "1").option("--cursor <cursor>", "Stable transcript cursor returned in page.nextCursor").option("--turn-limit <n>", "Maximum turns to return", "20").option("--chronological", "Show oldest-first instead of default newest-first").option("--narrative", "Use a narrative human layout").option("--max-chars <n>", "Maximum output characters per row", "1200").option("--max-output-chars <n>", "Alias for --max-chars").option("--include-output", "Include row output in compact human transcript rows").option("--include-outputs", "Alias for --include-output").addHelpText("after", formatExamplesAndCautions({
12387
+ examples: [
12388
+ {
12389
+ description: "Inspect the neighborhood around a failing step:",
12390
+ command: "rudder runs transcript <run-id> --around-error step-12 --context-turns 2"
12391
+ },
12392
+ {
12393
+ description: "Reconstruct a bounded chronological decision trail:",
12394
+ command: "rudder runs transcript <run-id> --chronological --turn-limit 30 --include-output"
12395
+ }
12396
+ ],
12397
+ cautions: [
12398
+ "Human output is compact and clipped by default; use --json only when a script needs the full payload.",
12399
+ "Use --around-error from runs errors when investigating a failure instead of reading the entire run first."
12400
+ ]
12401
+ })).action(async (runId, opts) => {
12055
12402
  try {
12056
12403
  const ctx = resolveCommandContext(opts);
12057
12404
  const payload = await ctx.api.get(
@@ -12070,7 +12417,22 @@ function registerRunsCommands(program) {
12070
12417
  })
12071
12418
  );
12072
12419
  addCommonClientOptions(
12073
- runs.command("errors").description(getAgentCliCapabilityById("runs.errors").description).argument("<runId>", "Run ID or short run ID").option("--max-chars <n>", "Maximum output characters per error", "1200").action(async (runId, opts) => {
12420
+ runs.command("errors").description(getAgentCliCapabilityById("runs.errors").description).argument("<runId>", "Run ID or short run ID").option("--max-chars <n>", "Maximum output characters per error", "1200").addHelpText("after", formatExamplesAndCautions({
12421
+ examples: [
12422
+ {
12423
+ description: "Start failed-run investigation with error summaries:",
12424
+ command: "rudder runs errors <run-id>"
12425
+ },
12426
+ {
12427
+ description: "Increase clipped error output for scripts or reports:",
12428
+ command: "rudder runs errors <run-id> --max-chars 4000 --json"
12429
+ }
12430
+ ],
12431
+ cautions: [
12432
+ "Start here for failed runs, then follow the transcript context command returned for the relevant step.",
12433
+ "Increase --max-chars deliberately; large tool outputs can be noisy and expensive to inspect."
12434
+ ]
12435
+ })).action(async (runId, opts) => {
12074
12436
  try {
12075
12437
  const ctx = resolveCommandContext(opts);
12076
12438
  const params = new URLSearchParams();
@@ -12365,7 +12727,22 @@ function registerSkillCommands(program) {
12365
12727
  { includeCompany: false }
12366
12728
  );
12367
12729
  addCommonClientOptions(
12368
- skill.command("file").description(getAgentCliCapabilityById("skill.file").description).argument("<skillId>", "Skill ID").option("-O, --org-id <id>", "Organization ID").option("--path <path>", "Skill package file path", "SKILL.md").action(async (skillId, opts) => {
12730
+ skill.command("file").description(getAgentCliCapabilityById("skill.file").description).argument("<skillId>", "Skill ID").option("-O, --org-id <id>", "Organization ID").option("--path <path>", "Skill package file path", "SKILL.md").addHelpText("after", formatExamplesAndCautions({
12731
+ examples: [
12732
+ {
12733
+ description: "Read the main skill trigger and workflow instructions:",
12734
+ command: "rudder skill file <skill-uuid> --path SKILL.md --org-id <org-id>"
12735
+ },
12736
+ {
12737
+ description: "Inspect a specific reference file in the skill package:",
12738
+ command: "rudder skill file <skill-uuid> --path references/usage.md --json"
12739
+ }
12740
+ ],
12741
+ cautions: [
12742
+ "Prefer the skill UUID for slashful keys such as local/<hash>/<slug>.",
12743
+ "Read SKILL.md before assuming a skill's trigger or workflow behavior."
12744
+ ]
12745
+ })).action(async (skillId, opts) => {
12369
12746
  try {
12370
12747
  const ctx = resolveCommandContext(opts, { requireCompany: true });
12371
12748
  const query = new URLSearchParams({ path: opts.path ?? "SKILL.md" });
@@ -12380,7 +12757,22 @@ function registerSkillCommands(program) {
12380
12757
  { includeCompany: false }
12381
12758
  );
12382
12759
  addCommonClientOptions(
12383
- skill.command("import").description(getAgentCliCapabilityById("skill.import").description).option("-O, --org-id <id>", "Organization ID").requiredOption("--source <source>", "Skill source (local path, URL, or repo ref)").action(async (opts) => {
12760
+ skill.command("import").description(getAgentCliCapabilityById("skill.import").description).option("-O, --org-id <id>", "Organization ID").requiredOption("--source <source>", "Skill source (local path, URL, or repo ref)").addHelpText("after", formatExamplesAndCautions({
12761
+ examples: [
12762
+ {
12763
+ description: "Import a durable organization-shared skill package:",
12764
+ command: "rudder skill import --org-id <org-id> --source /abs/path/to/skill --json"
12765
+ },
12766
+ {
12767
+ description: "List imported skills afterward to get stable ids:",
12768
+ command: "rudder skill list --org-id <org-id> --json"
12769
+ }
12770
+ ],
12771
+ cautions: [
12772
+ "Import organization-shared skills from durable shared paths, not disposable agent-private work directories.",
12773
+ "Importing a skill does not automatically enable it for every agent; update agent skill selections separately."
12774
+ ]
12775
+ })).action(async (opts) => {
12384
12776
  try {
12385
12777
  const ctx = resolveCommandContext(opts, { requireCompany: true });
12386
12778
  const payload = organizationSkillImportSchema.parse({ source: opts.source });
@@ -13405,6 +13797,7 @@ function createByteProgress(label, options = {}) {
13405
13797
  init_version();
13406
13798
  var DEFAULT_DESKTOP_RELEASE_REPO = "Undertone0809/rudder";
13407
13799
  var DESKTOP_UPDATE_QUIT_ARG = "--rudder-update-quit";
13800
+ var DESKTOP_UPDATE_FORCE_ARG = "--rudder-update-force";
13408
13801
  var STABLE_SEMVER_RE = /^[0-9]+\.[0-9]+\.[0-9]+$/;
13409
13802
  var CANARY_SEMVER_RE = /^[0-9]+\.[0-9]+\.[0-9]+-canary\.[0-9]+$/;
13410
13803
  var CLI_REGISTRY_LATEST_URL = "https://registry.npmjs.org/@rudderhq%2fcli/latest";
@@ -13488,7 +13881,7 @@ function createDesktopProgressFactory() {
13488
13881
  async function waitForDesktopApplySignal() {
13489
13882
  process.stdin.setEncoding("utf8");
13490
13883
  process.stdin.resume();
13491
- await new Promise((resolve, reject) => {
13884
+ return await new Promise((resolve, reject) => {
13492
13885
  let buffer = "";
13493
13886
  const cleanup = () => {
13494
13887
  process.stdin.off("data", onData);
@@ -13499,9 +13892,15 @@ async function waitForDesktopApplySignal() {
13499
13892
  buffer += chunk;
13500
13893
  const lines = buffer.split(/\r?\n/);
13501
13894
  buffer = lines.pop() ?? "";
13502
- if (lines.some((line) => line.trim() === "apply")) {
13895
+ const commands = lines.map((line) => line.trim());
13896
+ if (commands.includes("force-apply")) {
13503
13897
  cleanup();
13504
- resolve();
13898
+ resolve({ force: true });
13899
+ return;
13900
+ }
13901
+ if (commands.includes("apply")) {
13902
+ cleanup();
13903
+ resolve({ force: false });
13505
13904
  }
13506
13905
  };
13507
13906
  const onEnd = () => {
@@ -14214,14 +14613,6 @@ function isInstalledDesktopCurrent(metadata, releaseTag, assetName, assetChecksu
14214
14613
  metadata && metadata.releaseTag === releaseTag && metadata.assetName === assetName && metadata.assetChecksum === assetChecksum
14215
14614
  );
14216
14615
  }
14217
- function buildForceQuitCommand(target) {
14218
- if (target.platform === "windows") return { command: "taskkill.exe", args: ["/IM", `${DESKTOP_APP_NAME}.exe`, "/T", "/F"] };
14219
- return { command: "pkill", args: ["-x", DESKTOP_APP_NAME] };
14220
- }
14221
- function forceQuitDesktopProcesses(target) {
14222
- const command = buildForceQuitCommand(target);
14223
- spawnSync3(command.command, command.args, { stdio: "ignore" });
14224
- }
14225
14616
  function forceQuitDesktopProcess(pid, target) {
14226
14617
  if (target.platform === "windows") {
14227
14618
  spawnSync3("taskkill.exe", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore" });
@@ -14232,8 +14623,35 @@ function forceQuitDesktopProcess(pid, target) {
14232
14623
  } catch {
14233
14624
  }
14234
14625
  }
14235
- function isRunningInsideDesktopExecutable() {
14236
- return path21.basename(process.execPath).toLowerCase().startsWith(DESKTOP_APP_NAME.toLowerCase());
14626
+ function quotePowerShellString(value) {
14627
+ return `'${value.replaceAll("'", "''")}'`;
14628
+ }
14629
+ function findDesktopExecutablePids(executablePath, target) {
14630
+ if (target.platform === "windows") {
14631
+ const result2 = spawnSync3("powershell.exe", [
14632
+ "-NoProfile",
14633
+ "-Command",
14634
+ `Get-CimInstance Win32_Process | Where-Object { $_.ExecutablePath -eq ${quotePowerShellString(executablePath)} } | Select-Object -ExpandProperty ProcessId`
14635
+ ], {
14636
+ encoding: "utf8",
14637
+ stdio: ["ignore", "pipe", "ignore"]
14638
+ });
14639
+ if (result2.status !== 0) return [];
14640
+ return result2.stdout.split(/\r?\n/).map((line) => Number.parseInt(line.trim(), 10)).filter((pid) => Number.isInteger(pid) && pid > 0 && pid !== process.pid);
14641
+ }
14642
+ const result = spawnSync3("ps", ["-eo", "pid=,args="], {
14643
+ encoding: "utf8",
14644
+ stdio: ["ignore", "pipe", "ignore"]
14645
+ });
14646
+ if (result.status !== 0) return [];
14647
+ return result.stdout.split(/\r?\n/).flatMap((line) => {
14648
+ const match = line.match(/^\s*(\d+)\s+(.+)$/);
14649
+ if (!match) return [];
14650
+ const pid = Number.parseInt(match[1], 10);
14651
+ const commandLine = match[2];
14652
+ const matchesExecutable = commandLine === executablePath || commandLine.startsWith(`${executablePath} `);
14653
+ return matchesExecutable && pid !== process.pid ? [pid] : [];
14654
+ });
14237
14655
  }
14238
14656
  async function waitForUpdateQuitResponse(responsePath, timeoutMs = 8e3) {
14239
14657
  const startedAt = Date.now();
@@ -14245,10 +14663,13 @@ async function waitForUpdateQuitResponse(responsePath, timeoutMs = 8e3) {
14245
14663
  }
14246
14664
  return null;
14247
14665
  }
14248
- async function requestDesktopQuit(executablePath, target) {
14666
+ async function requestDesktopQuit(executablePath, target, options = {}) {
14249
14667
  if (!await pathExists2(executablePath)) return { ok: true, status: "not_running" };
14250
14668
  const responsePath = path21.join(tmpdir(), `rudder-update-quit-${process.pid}-${Date.now()}.json`);
14251
- const result = spawnSync3(executablePath, [`${DESKTOP_UPDATE_QUIT_ARG}=${responsePath}`], {
14669
+ const result = spawnSync3(executablePath, [
14670
+ `${DESKTOP_UPDATE_QUIT_ARG}=${responsePath}`,
14671
+ ...options.forceUpdate ? [DESKTOP_UPDATE_FORCE_ARG] : []
14672
+ ], {
14252
14673
  stdio: "ignore",
14253
14674
  timeout: 5e3
14254
14675
  });
@@ -14256,7 +14677,7 @@ async function requestDesktopQuit(executablePath, target) {
14256
14677
  return null;
14257
14678
  }
14258
14679
  try {
14259
- return await waitForUpdateQuitResponse(responsePath);
14680
+ return await waitForUpdateQuitResponse(responsePath, options.responseTimeoutMs);
14260
14681
  } finally {
14261
14682
  await rm2(responsePath, { force: true });
14262
14683
  }
@@ -14285,6 +14706,12 @@ async function waitForProcessExit(pid, timeoutMs = 2e4, intervalMs = 250) {
14285
14706
  }
14286
14707
  return !processExists(pid);
14287
14708
  }
14709
+ async function waitForProcessesExit(pids, waitForExit) {
14710
+ const uniquePids = [...new Set(pids)];
14711
+ if (uniquePids.length === 0) return true;
14712
+ const results = await Promise.all(uniquePids.map((pid) => waitForExit(pid)));
14713
+ return results.every(Boolean);
14714
+ }
14288
14715
  async function removePathWithRetry(targetPath, attempts = 5) {
14289
14716
  for (let attempt = 0; attempt < attempts; attempt += 1) {
14290
14717
  try {
@@ -14297,50 +14724,98 @@ async function removePathWithRetry(targetPath, attempts = 5) {
14297
14724
  return false;
14298
14725
  }
14299
14726
  async function prepareForDesktopReplace(paths, target, options = {}) {
14300
- const forceQuit = options.forceQuitDesktopProcesses ?? forceQuitDesktopProcesses;
14301
14727
  const forceQuitPid = options.forceQuitDesktopProcess ?? forceQuitDesktopProcess;
14302
14728
  const waitForExit = options.waitForDesktopProcessExit ?? waitForProcessExit;
14729
+ const findPids = options.findDesktopExecutablePids ?? findDesktopExecutablePids;
14730
+ async function forceQuitPidAndConfirm(pid) {
14731
+ forceQuitPid(pid, target);
14732
+ await delay2(options.updateQuitForceDelayMs ?? UPDATE_QUIT_FORCE_DELAY_MS);
14733
+ if (!await waitForExit(pid)) {
14734
+ throw new Error(`Rudder Desktop process ${pid} did not exit after force-quit fallback. Close Rudder and rerun start.`);
14735
+ }
14736
+ }
14737
+ async function forceQuitPidsAndConfirm(pids) {
14738
+ const uniquePids = [...new Set(pids)];
14739
+ for (const pid of uniquePids) {
14740
+ forceQuitPid(pid, target);
14741
+ }
14742
+ await delay2(options.updateQuitForceDelayMs ?? UPDATE_QUIT_FORCE_DELAY_MS);
14743
+ if (!await waitForProcessesExit(uniquePids, waitForExit)) {
14744
+ throw new Error(`Rudder Desktop process${uniquePids.length === 1 ? "" : "es"} ${uniquePids.join(", ")} did not exit after force-quit fallback. Close Rudder and rerun start.`);
14745
+ }
14746
+ }
14747
+ let quitPid = null;
14748
+ let managedExecutablePids = [];
14303
14749
  const hasManagedExecutable = await pathExists2(paths.executablePath);
14304
14750
  if (hasManagedExecutable) {
14305
- let quitResponse = await requestDesktopQuit(paths.executablePath, target);
14306
- while (quitResponse && !quitResponse.ok && quitResponse.status === "active_runs" && options.waitForActiveRuns) {
14751
+ managedExecutablePids = findPids(paths.executablePath, target);
14752
+ const requestQuit = () => requestDesktopQuit(paths.executablePath, target, {
14753
+ forceUpdate: options.forceUpdate,
14754
+ responseTimeoutMs: options.updateQuitResponseTimeoutMs
14755
+ });
14756
+ let quitResponse = await requestQuit();
14757
+ while (quitResponse && !quitResponse.ok && quitResponse.status === "active_runs" && options.waitForActiveRuns && !options.forceUpdate) {
14307
14758
  p15.log.warn(
14308
14759
  `Rudder Desktop has ${quitResponse.totalRuns} active run${quitResponse.totalRuns === 1 ? "" : "s"}; waiting before replacing Desktop.`
14309
14760
  );
14310
14761
  await delay2(options.activeRunPollIntervalMs ?? 15e3);
14311
- quitResponse = await requestDesktopQuit(paths.executablePath, target);
14762
+ quitResponse = await requestQuit();
14312
14763
  }
14313
14764
  if (quitResponse && !quitResponse.ok && quitResponse.status === "active_runs") {
14765
+ if (!options.forceUpdate) {
14766
+ throw new Error(
14767
+ `Rudder Desktop has ${quitResponse.totalRuns} active run${quitResponse.totalRuns === 1 ? "" : "s"}. Stop active work, then rerun start.`
14768
+ );
14769
+ }
14314
14770
  throw new Error(
14315
- `Rudder Desktop has ${quitResponse.totalRuns} active run${quitResponse.totalRuns === 1 ? "" : "s"}. Stop active work, then rerun start.`
14771
+ `Rudder Desktop still has ${quitResponse.totalRuns} active run${quitResponse.totalRuns === 1 ? "" : "s"} after the force-update request. Stop active work, then rerun start.`
14316
14772
  );
14317
14773
  }
14318
- const quitPid = readUpdateQuitPid(quitResponse);
14774
+ if (quitResponse && !quitResponse.ok && quitResponse.status === "failed") {
14775
+ throw new Error(quitResponse.message);
14776
+ }
14777
+ quitPid = readUpdateQuitPid(quitResponse);
14319
14778
  if (quitPid) {
14320
14779
  p15.log.info(`Waiting for existing Rudder Desktop process ${quitPid} to exit before replacing it.`);
14321
14780
  if (!await waitForExit(quitPid)) {
14322
14781
  p15.log.warn(`Rudder Desktop process ${quitPid} did not exit in time; attempting force-quit fallback.`);
14323
- forceQuitPid(quitPid, target);
14324
- await delay2(options.updateQuitForceDelayMs ?? UPDATE_QUIT_FORCE_DELAY_MS);
14782
+ await forceQuitPidAndConfirm(quitPid);
14325
14783
  }
14326
14784
  } else if (isLegacyUnconfirmedUpdateQuit(quitResponse)) {
14327
14785
  const graceMs = options.legacyUpdateQuitGraceMs ?? LEGACY_UPDATE_QUIT_GRACE_MS;
14328
14786
  p15.log.warn(
14329
- `Existing Rudder Desktop acknowledged update quit without a process id; waiting ${Math.ceil(graceMs / 1e3)}s before force-quit fallback.`
14787
+ `Existing Rudder Desktop acknowledged update quit without a process id; waiting ${Math.ceil(graceMs / 1e3)}s before replacement.`
14330
14788
  );
14331
14789
  await delay2(graceMs);
14332
- forceQuit(target);
14333
- await delay2(options.updateQuitForceDelayMs ?? UPDATE_QUIT_FORCE_DELAY_MS);
14790
+ if (managedExecutablePids.length > 0 && !await waitForProcessesExit(managedExecutablePids, waitForExit)) {
14791
+ p15.log.warn(
14792
+ `Existing Rudder Desktop did not exit after acknowledging update quit; attempting path-scoped force-quit for process${managedExecutablePids.length === 1 ? "" : "es"} ${managedExecutablePids.join(", ")}.`
14793
+ );
14794
+ await forceQuitPidsAndConfirm(managedExecutablePids);
14795
+ }
14796
+ } else if (!quitResponse) {
14797
+ if (options.forceUpdate && managedExecutablePids.length > 0) {
14798
+ p15.log.warn(
14799
+ `Existing Rudder Desktop did not respond to the update quit request; attempting path-scoped force-quit for process${managedExecutablePids.length === 1 ? "" : "es"} ${managedExecutablePids.join(", ")}.`
14800
+ );
14801
+ await forceQuitPidsAndConfirm(managedExecutablePids);
14802
+ } else {
14803
+ throw new Error("Existing Rudder Desktop did not respond to the update quit request. Close Rudder and rerun start.");
14804
+ }
14334
14805
  } else {
14335
14806
  await delay2(options.updateQuitForceDelayMs ?? UPDATE_QUIT_FORCE_DELAY_MS);
14336
14807
  }
14337
- } else if (!isRunningInsideDesktopExecutable()) {
14338
- forceQuit(target);
14339
14808
  }
14340
14809
  const replacePath = target.platform === "windows" ? paths.installRoot : paths.appPath;
14341
14810
  if (await removePathWithRetry(replacePath)) return;
14342
- forceQuit(target);
14343
- await delay2(options.updateQuitForceDelayMs ?? UPDATE_QUIT_FORCE_DELAY_MS);
14811
+ if (!quitPid) {
14812
+ if (managedExecutablePids.length > 0) {
14813
+ await forceQuitPidsAndConfirm(managedExecutablePids);
14814
+ if (await removePathWithRetry(replacePath, 6)) return;
14815
+ }
14816
+ throw new Error(`Failed to replace existing Rudder Desktop at ${replacePath}. Close Rudder and rerun start.`);
14817
+ }
14818
+ await forceQuitPidAndConfirm(quitPid);
14344
14819
  if (await removePathWithRetry(replacePath, 6)) return;
14345
14820
  throw new Error(`Failed to replace existing Rudder Desktop at ${replacePath}. Close Rudder and rerun start.`);
14346
14821
  }
@@ -14673,22 +15148,26 @@ async function startCommand(opts) {
14673
15148
  () => assertChecksumMatch(cachedAsset.path, expectedChecksum),
14674
15149
  desktopProgressJson ? "verifying_checksum" : null
14675
15150
  );
15151
+ let applySignal = null;
14676
15152
  if (desktopProgressJson && opts.desktopWaitForApply === true) {
14677
15153
  writeDesktopProgress({
14678
15154
  phase: "ready_to_install",
14679
15155
  message: "Desktop update is downloaded and verified.",
14680
15156
  percent: 100
14681
15157
  });
14682
- await waitForDesktopApplySignal();
15158
+ applySignal = await waitForDesktopApplySignal();
14683
15159
  writeDesktopProgress({
14684
15160
  phase: "preparing_restart",
14685
- message: "Applying Desktop update..."
15161
+ message: applySignal.force ? "Applying Desktop update and quitting active runs..." : "Applying Desktop update..."
14686
15162
  });
14687
15163
  }
14688
15164
  await runStartPhase(
14689
15165
  "Replacing existing Rudder Desktop if needed...",
14690
15166
  "Existing Desktop install is ready for replacement.",
14691
- () => prepareForDesktopReplace(installPaths, target, { waitForActiveRuns: opts.waitForActiveRuns === true }),
15167
+ () => prepareForDesktopReplace(installPaths, target, {
15168
+ waitForActiveRuns: opts.waitForActiveRuns === true,
15169
+ forceUpdate: applySignal?.force === true
15170
+ }),
14692
15171
  desktopProgressJson ? opts.waitForActiveRuns === true ? "waiting_for_active_runs" : "preparing_restart" : null
14693
15172
  );
14694
15173
  await runStartPhase(