@rudderhq/cli 0.3.6-canary.1 → 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, feishuEventHeaderSchema, feishuSenderIdSchema, feishuMessageMentionSchema, feishuMessageSchema, feishuEventSchema, mockFeishuInboundEventSchema;
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,9 +1802,11 @@ 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 });
1795
1806
  feishuEventHeaderSchema = z13.object({
1796
1807
  event_id: z13.string().min(1).optional(),
1797
1808
  app_id: z13.string().min(1).optional(),
1809
+ token: z13.string().min(1).optional(),
1798
1810
  create_time: z13.string().min(1).optional()
1799
1811
  }).passthrough();
1800
1812
  feishuSenderIdSchema = z13.object({
@@ -1821,6 +1833,11 @@ var init_agent_integration = __esm({
1821
1833
  message: feishuMessageSchema.optional()
1822
1834
  }).passthrough();
1823
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(),
1824
1841
  eventId: z13.string().min(1).optional(),
1825
1842
  appId: z13.string().min(1).optional(),
1826
1843
  botOpenId: z13.string().min(1).optional().nullable(),
@@ -2975,6 +2992,7 @@ var init_api = __esm({
2975
2992
  secrets: `${API_PREFIX}/secrets`,
2976
2993
  costs: `${API_PREFIX}/costs`,
2977
2994
  activity: `${API_PREFIX}/activity`,
2995
+ agentRuns: `${API_PREFIX}/agent-runs`,
2978
2996
  dashboard: `${API_PREFIX}/dashboard`,
2979
2997
  sidebarBadges: `${API_PREFIX}/sidebar-badges`,
2980
2998
  invites: `${API_PREFIX}/invites`,
@@ -3033,6 +3051,19 @@ var init_project_url_key = __esm({
3033
3051
  }
3034
3052
  });
3035
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
+
3036
3067
  // ../packages/shared/dist/token-usage.js
3037
3068
  var init_token_usage = __esm({
3038
3069
  "../packages/shared/dist/token-usage.js"() {
@@ -3237,6 +3268,7 @@ var init_dist = __esm({
3237
3268
  "../packages/shared/dist/index.js"() {
3238
3269
  "use strict";
3239
3270
  init_constants();
3271
+ init_agent_run();
3240
3272
  init_observability();
3241
3273
  init_workspace_backup();
3242
3274
  init_validators();
@@ -3248,6 +3280,7 @@ var init_dist = __esm({
3248
3280
  init_organization_url_key();
3249
3281
  init_project_mentions();
3250
3282
  init_project_url_key();
3283
+ init_short_refs();
3251
3284
  init_token_usage();
3252
3285
  init_issue_activity();
3253
3286
  init_config_schema();
@@ -7012,7 +7045,7 @@ function printOutput(data, opts = {}) {
7012
7045
  }
7013
7046
  function formatInlineRecord(record, opts = {}) {
7014
7047
  const displayRecord = shouldShowFullIds(opts.fullIds) ? record : toCliShortIdOutput(record);
7015
- const keyOrder = ["identifier", "id", "name", "status", "priority", "title", "action"];
7048
+ const keyOrder = ["identifier", "shortRef", "id", "name", "status", "priority", "title", "action"];
7016
7049
  const seen = /* @__PURE__ */ new Set();
7017
7050
  const parts = [];
7018
7051
  for (const key of keyOrder) {
@@ -7283,6 +7316,7 @@ var RUDDER_AGENT_OPERATING_CONTRACT = [
7283
7316
  "",
7284
7317
  "- Issues: use `[](issue://<issue-id>)`; include `?c=<comment-id>` when linking to a specific comment.",
7285
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.",
7286
7320
  "- Projects: use `[](project://<project-id>)` when citing a Rudder project.",
7287
7321
  "- Chat threads: use `[](chat://<conversation-id>)` when citing a Rudder chat conversation.",
7288
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.",
@@ -7298,7 +7332,7 @@ var RUDDER_AGENT_OPERATING_CONTRACT = [
7298
7332
  "",
7299
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.",
7300
7334
  "",
7301
- "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.",
7302
7336
  "",
7303
7337
  "Invoke it whenever you need to remember, retrieve, or organize anything.",
7304
7338
  "",
@@ -7315,19 +7349,25 @@ var RUDDER_AGENT_OPERATING_CONTRACT = [
7315
7349
  var RUDDER_AGENT_HEARTBEAT_INSTRUCTION = [
7316
7350
  "# Rudder Heartbeat Instruction",
7317
7351
  "",
7318
- "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.",
7319
7353
  "",
7320
7354
  "## Heartbeat Pipeline",
7321
7355
  "",
7322
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.",
7323
- "2. Handle approval follow-up first: read the approval and linked issues, then close resolved work or comment on what remains.",
7324
- "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.",
7325
- "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.",
7326
- "5. Checkout before doing assignee task work. A `409` means another agent owns the task; do not retry it.",
7327
- "6. Load compact issue context, do one bounded useful chunk, and preserve evidence.",
7328
- "7. Before exiting active work, leave exactly one durable signal: progress, done, blocked, explicit handoff, or structured review decision.",
7329
- "8. Treat passive follow-up as close-out governance, not a fresh assignment.",
7330
- "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.",
7331
7371
  "",
7332
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."
7333
7373
  ].join("\n");
@@ -7436,9 +7476,9 @@ var AGENT_CLI_CAPABILITIES = [
7436
7476
  },
7437
7477
  {
7438
7478
  id: "agent.get",
7439
- command: "rudder agent get <agent-id-or-shortname>",
7479
+ command: "rudder agent get <agent-id-or-shortname-or-agt-ref>",
7440
7480
  category: "agent",
7441
- description: "Read one agent by id or shortname.",
7481
+ description: "Read one agent by id, shortname, or agt_<uuid-prefix> short ref.",
7442
7482
  mutating: false,
7443
7483
  contract: "compat",
7444
7484
  requiresOrgId: false,
@@ -7592,9 +7632,9 @@ var AGENT_CLI_CAPABILITIES = [
7592
7632
  },
7593
7633
  {
7594
7634
  id: "issue.context",
7595
- command: "rudder issue context <issue>",
7635
+ command: "rudder issue context <issue> [--wake-comment-id <comment-id-or-cmt-ref>]",
7596
7636
  category: "issue",
7597
- 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>.",
7598
7638
  mutating: false,
7599
7639
  contract: "agent-v1",
7600
7640
  requiresOrgId: false,
@@ -7628,9 +7668,9 @@ var AGENT_CLI_CAPABILITIES = [
7628
7668
  },
7629
7669
  {
7630
7670
  id: "issue.comments.list",
7631
- command: "rudder issue comments list <issue>",
7671
+ command: "rudder issue comments list <issue> [--after <comment-id-or-cmt-ref>]",
7632
7672
  category: "issue",
7633
- 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.",
7634
7674
  mutating: false,
7635
7675
  contract: "agent-v1",
7636
7676
  requiresOrgId: false,
@@ -7640,9 +7680,9 @@ var AGENT_CLI_CAPABILITIES = [
7640
7680
  },
7641
7681
  {
7642
7682
  id: "issue.comments.get",
7643
- command: "rudder issue comments get <issue> <comment-id>",
7683
+ command: "rudder issue comments get <issue> <comment-id-or-cmt-ref>",
7644
7684
  category: "issue",
7645
- description: "Read one issue comment by id.",
7685
+ description: "Read one issue comment by full id or cmt_<uuid-prefix> scoped to the issue.",
7646
7686
  mutating: false,
7647
7687
  contract: "agent-v1",
7648
7688
  requiresOrgId: false,
@@ -8423,7 +8463,7 @@ function formatAgentCliCapabilitiesHumanReadable(capabilities = getAgentCliCapab
8423
8463
  function formatExamplesAndCautions(notes) {
8424
8464
  const sections = [];
8425
8465
  if (notes.examples?.length) {
8426
- sections.push(["Examples:", ...notes.examples.map((example) => ` ${example}`)].join("\n"));
8466
+ sections.push(["Examples:", ...notes.examples.map(formatHelpExample)].join("\n"));
8427
8467
  }
8428
8468
  if (notes.cautions?.length) {
8429
8469
  sections.push(["Cautions:", ...notes.cautions.map((caution) => ` - ${caution}`)].join("\n"));
@@ -8431,6 +8471,13 @@ function formatExamplesAndCautions(notes) {
8431
8471
  return sections.length > 0 ? `
8432
8472
  ${sections.join("\n\n")}` : "";
8433
8473
  }
8474
+ function formatHelpExample(example) {
8475
+ if (typeof example === "string") {
8476
+ return ` ${example}`;
8477
+ }
8478
+ return ` ${example.description}
8479
+ ${example.command}`;
8480
+ }
8434
8481
 
8435
8482
  // src/commands/client/agent.ts
8436
8483
  var __moduleDir = path10.dirname(fileURLToPath3(import.meta.url));
@@ -8596,6 +8643,7 @@ function registerAgentCommands(program) {
8596
8643
  for (const row of rows) {
8597
8644
  console.log(
8598
8645
  formatInlineRecord({
8646
+ shortRef: row.shortRef,
8599
8647
  id: row.id,
8600
8648
  name: row.name,
8601
8649
  role: row.role,
@@ -8750,8 +8798,14 @@ function registerAgentCommands(program) {
8750
8798
  addCommonClientOptions(
8751
8799
  skills.command("enable").description(getAgentCliCapabilityById("agent.skills.enable").description).argument("<agentId>", "Agent ID").argument("<selectionRefs...>", "Skill selection refs to enable").addHelpText("after", formatExamplesAndCautions({
8752
8800
  examples: [
8753
- "rudder agent skills enable <agent-id> rudder/rudder local/abc123/custom-skill",
8754
- "rudder agent skills enable <agent-id> <selection-ref> --json"
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
+ }
8755
8809
  ],
8756
8810
  cautions: [
8757
8811
  "This is additive and preserves existing enabled optional skills.",
@@ -8775,8 +8829,14 @@ function registerAgentCommands(program) {
8775
8829
  "Comma-separated desired skill refs (for example rudder/rudder)"
8776
8830
  ).addHelpText("after", formatExamplesAndCautions({
8777
8831
  examples: [
8778
- 'rudder agent skills sync <agent-id> --desired-skills "rudder/rudder,local/abc123/custom-skill"',
8779
- 'rudder agent skills sync <agent-id> --desired-skills "" --json'
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
+ }
8780
8840
  ],
8781
8841
  cautions: [
8782
8842
  "Sync replaces the full optional enabled-skill set; use enable for additive changes.",
@@ -9073,8 +9133,14 @@ function registerApprovalCommands(program) {
9073
9133
  addCommonClientOptions(
9074
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({
9075
9135
  examples: [
9076
- "rudder approval get <approval-id> --json",
9077
- 'rudder approval approve <approval-id> --decision-note "Approved after reviewing linked issues" --json'
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
+ }
9078
9144
  ],
9079
9145
  cautions: [
9080
9146
  "Read the approval and linked issues before approving; this is a governed mutation.",
@@ -9141,8 +9207,14 @@ function registerApprovalCommands(program) {
9141
9207
  addCommonClientOptions(
9142
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({
9143
9209
  examples: [
9144
- "rudder approval comment <approval-id> --body-file ./approval-note.md --json",
9145
- "printf '%s\\n' 'Need one more linked issue checked.' | rudder approval comment <approval-id> --body-file -"
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
+ }
9146
9218
  ],
9147
9219
  cautions: [
9148
9220
  "Comments do not approve or reject; use approve/reject/request-revision for the durable decision.",
@@ -9442,8 +9514,14 @@ function registerAutomationCommands(program) {
9442
9514
  addCommonClientOptions(
9443
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({
9444
9516
  examples: [
9445
- `rudder automation run <automation-id> --payload '{"manual":true}' --json`,
9446
- "rudder automation run <automation-id> --trigger-id <trigger-id> --idempotency-key zst-123-smoke"
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
+ }
9447
9525
  ],
9448
9526
  cautions: [
9449
9527
  "Confirm the automation and trigger target before running; manual runs can create tracked issues or chats.",
@@ -9641,8 +9719,14 @@ function registerChatCommands(program) {
9641
9719
  addCommonClientOptions(
9642
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({
9643
9721
  examples: [
9644
- "rudder chat read <chat-id> --turn-limit 20 --include-output",
9645
- "rudder chat read <chat-id> --cursor <nextCursor> --json"
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
+ }
9646
9730
  ],
9647
9731
  cautions: [
9648
9732
  "Read bounded pages first; long chats can include large transcript payloads.",
@@ -9698,8 +9782,14 @@ function registerChatCommands(program) {
9698
9782
  addCommonClientOptions(
9699
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({
9700
9784
  examples: [
9701
- 'rudder chat send <chat-id> --body "Status: validation is running"',
9702
- "printf '%s\\n' 'Multiline note' | rudder chat send <chat-id>"
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
+ }
9703
9793
  ],
9704
9794
  cautions: [
9705
9795
  "chat send accepts --body or stdin; it does not support --body-file.",
@@ -11301,8 +11391,14 @@ function registerIssueCommands(program) {
11301
11391
  addCommonClientOptions(
11302
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({
11303
11393
  examples: [
11304
- "rudder issue comment ZST-123 --body-file ./progress.md --image ./screenshot.png --json",
11305
- "printf '%s\\n' 'Short status' | rudder issue comment ZST-123 --body-file -"
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
+ }
11306
11402
  ],
11307
11403
  cautions: [
11308
11404
  "Use --body-file for multiline Markdown; the old --body option is intentionally rejected.",
@@ -11338,8 +11434,14 @@ function registerIssueCommands(program) {
11338
11434
  "Review decision: approve, request_changes, needs_followup, or blocked"
11339
11435
  ).option("--comment-file <path>", "Read required review comment from a file, or '-' for stdin").addHelpText("after", formatExamplesAndCautions({
11340
11436
  examples: [
11341
- "rudder issue review ZST-123 --decision request_changes --comment-file ./review.md --json",
11342
- "rudder issue review ZST-123 --decision approve --comment-file ./review.md"
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
+ }
11343
11445
  ],
11344
11446
  cautions: [
11345
11447
  "Free-form comments are not durable review decisions; use this command for approve/request_changes/etc.",
@@ -11387,8 +11489,14 @@ function registerIssueCommands(program) {
11387
11489
  addCommonClientOptions(
11388
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({
11389
11491
  examples: [
11390
- "rudder issue done ZST-123 --comment-file ./done.md --image ./screenshot.png --json",
11391
- "rudder issue done ZST-123 --comment-file - < ./done.md"
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
+ }
11392
11500
  ],
11393
11501
  cautions: [
11394
11502
  "Include validation evidence and commit/push status in the completion comment.",
@@ -11437,7 +11545,7 @@ function registerIssueCommands(program) {
11437
11545
  );
11438
11546
  const comments = issue.command("comments").description("Issue comment operations");
11439
11547
  addCommonClientOptions(
11440
- 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) => {
11441
11549
  try {
11442
11550
  const ctx = resolveCommandContext(opts);
11443
11551
  const params = new URLSearchParams();
@@ -11454,7 +11562,7 @@ function registerIssueCommands(program) {
11454
11562
  })
11455
11563
  );
11456
11564
  addCommonClientOptions(
11457
- 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) => {
11458
11566
  try {
11459
11567
  const ctx = resolveCommandContext(opts);
11460
11568
  const row = await ctx.api.get(`/api/issues/${issueId}/comments/${commentId}`);
@@ -11775,8 +11883,14 @@ function registerLibraryCommands(program) {
11775
11883
  addCommonClientOptions(
11776
11884
  file.command("ref").description(getAgentCliCapabilityById("library.file.ref").description).argument("<filePath>", "Library file path").addHelpText("after", formatExamplesAndCautions({
11777
11885
  examples: [
11778
- "rudder library file ref projects/rudder/proposals/plan.md --json",
11779
- 'rudder library file ref "$RUDDER_PROJECT_LIBRARY_PATH/proposals/plan.md" --json'
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
+ }
11780
11894
  ],
11781
11895
  cautions: [
11782
11896
  "Pass the Library-relative path, not an absolute filesystem path.",
@@ -11794,8 +11908,14 @@ function registerLibraryCommands(program) {
11794
11908
  addCommonClientOptions(
11795
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({
11796
11910
  examples: [
11797
- "rudder library file put projects/rudder/proposals/plan.md --body-file ./plan.md --json",
11798
- "printf '%s\\n' '# Plan' | rudder library file put projects/rudder/proposals/plan.md --body-file -"
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
+ }
11799
11919
  ],
11800
11920
  cautions: [
11801
11921
  "Use --body-file for content; the old --body option is intentionally rejected.",
@@ -12090,8 +12210,14 @@ function registerProjectCommands(program) {
12090
12210
  addCommonClientOptions(
12091
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({
12092
12212
  examples: [
12093
- 'rudder project create --org-id <org-id> --name "Rudder dev" --status in_progress --json',
12094
- 'rudder project create --org-id <org-id> --name "Release" --goal-id <goal-id> --lead-agent-id <agent-id>'
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
+ }
12095
12221
  ],
12096
12222
  cautions: [
12097
12223
  "Project mutations are organization-scoped; pass --org-id when context might be ambiguous.",
@@ -12121,8 +12247,14 @@ function registerProjectCommands(program) {
12121
12247
  addCommonClientOptions(
12122
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({
12123
12249
  examples: [
12124
- "rudder project update rudder-dev --org-id <org-id> --status in_progress --json",
12125
- "rudder project update <project-id> --archived-at null"
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
+ }
12126
12258
  ],
12127
12259
  cautions: [
12128
12260
  "Shortname resolution needs the intended organization; include --org-id for cross-org local contexts.",
@@ -12173,8 +12305,14 @@ function registerRunsCommands(program) {
12173
12305
  addCommonClientOptions(
12174
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({
12175
12307
  examples: [
12176
- "rudder runs list --org-id <org-id> --agent-id <agent-id> --status failed --limit 20",
12177
- "rudder runs list --org-id <org-id> --issue-id ZST-123 --used-skill release-maintainer --json"
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
+ }
12178
12316
  ],
12179
12317
  cautions: [
12180
12318
  "Filter first by org, agent, issue, status, skill, or time; do not start by dumping broad run history.",
@@ -12247,8 +12385,14 @@ function registerRunsCommands(program) {
12247
12385
  addCommonClientOptions(
12248
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({
12249
12387
  examples: [
12250
- "rudder runs transcript <run-id> --around-error step-12 --context-turns 2",
12251
- "rudder runs transcript <run-id> --chronological --turn-limit 30 --include-output"
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
+ }
12252
12396
  ],
12253
12397
  cautions: [
12254
12398
  "Human output is compact and clipped by default; use --json only when a script needs the full payload.",
@@ -12275,8 +12419,14 @@ function registerRunsCommands(program) {
12275
12419
  addCommonClientOptions(
12276
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({
12277
12421
  examples: [
12278
- "rudder runs errors <run-id>",
12279
- "rudder runs errors <run-id> --max-chars 4000 --json"
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
+ }
12280
12430
  ],
12281
12431
  cautions: [
12282
12432
  "Start here for failed runs, then follow the transcript context command returned for the relevant step.",
@@ -12579,8 +12729,14 @@ function registerSkillCommands(program) {
12579
12729
  addCommonClientOptions(
12580
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({
12581
12731
  examples: [
12582
- "rudder skill file <skill-uuid> --path SKILL.md --org-id <org-id>",
12583
- "rudder skill file <skill-uuid> --path references/usage.md --json"
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
+ }
12584
12740
  ],
12585
12741
  cautions: [
12586
12742
  "Prefer the skill UUID for slashful keys such as local/<hash>/<slug>.",
@@ -12603,8 +12759,14 @@ function registerSkillCommands(program) {
12603
12759
  addCommonClientOptions(
12604
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({
12605
12761
  examples: [
12606
- "rudder skill import --org-id <org-id> --source /abs/path/to/skill --json",
12607
- "rudder skill list --org-id <org-id> --json"
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
+ }
12608
12770
  ],
12609
12771
  cautions: [
12610
12772
  "Import organization-shared skills from durable shared paths, not disposable agent-private work directories.",
@@ -13635,6 +13797,7 @@ function createByteProgress(label, options = {}) {
13635
13797
  init_version();
13636
13798
  var DEFAULT_DESKTOP_RELEASE_REPO = "Undertone0809/rudder";
13637
13799
  var DESKTOP_UPDATE_QUIT_ARG = "--rudder-update-quit";
13800
+ var DESKTOP_UPDATE_FORCE_ARG = "--rudder-update-force";
13638
13801
  var STABLE_SEMVER_RE = /^[0-9]+\.[0-9]+\.[0-9]+$/;
13639
13802
  var CANARY_SEMVER_RE = /^[0-9]+\.[0-9]+\.[0-9]+-canary\.[0-9]+$/;
13640
13803
  var CLI_REGISTRY_LATEST_URL = "https://registry.npmjs.org/@rudderhq%2fcli/latest";
@@ -13718,7 +13881,7 @@ function createDesktopProgressFactory() {
13718
13881
  async function waitForDesktopApplySignal() {
13719
13882
  process.stdin.setEncoding("utf8");
13720
13883
  process.stdin.resume();
13721
- await new Promise((resolve, reject) => {
13884
+ return await new Promise((resolve, reject) => {
13722
13885
  let buffer = "";
13723
13886
  const cleanup = () => {
13724
13887
  process.stdin.off("data", onData);
@@ -13729,9 +13892,15 @@ async function waitForDesktopApplySignal() {
13729
13892
  buffer += chunk;
13730
13893
  const lines = buffer.split(/\r?\n/);
13731
13894
  buffer = lines.pop() ?? "";
13732
- if (lines.some((line) => line.trim() === "apply")) {
13895
+ const commands = lines.map((line) => line.trim());
13896
+ if (commands.includes("force-apply")) {
13897
+ cleanup();
13898
+ resolve({ force: true });
13899
+ return;
13900
+ }
13901
+ if (commands.includes("apply")) {
13733
13902
  cleanup();
13734
- resolve();
13903
+ resolve({ force: false });
13735
13904
  }
13736
13905
  };
13737
13906
  const onEnd = () => {
@@ -14444,14 +14613,6 @@ function isInstalledDesktopCurrent(metadata, releaseTag, assetName, assetChecksu
14444
14613
  metadata && metadata.releaseTag === releaseTag && metadata.assetName === assetName && metadata.assetChecksum === assetChecksum
14445
14614
  );
14446
14615
  }
14447
- function buildForceQuitCommand(target) {
14448
- if (target.platform === "windows") return { command: "taskkill.exe", args: ["/IM", `${DESKTOP_APP_NAME}.exe`, "/T", "/F"] };
14449
- return { command: "pkill", args: ["-x", DESKTOP_APP_NAME] };
14450
- }
14451
- function forceQuitDesktopProcesses(target) {
14452
- const command = buildForceQuitCommand(target);
14453
- spawnSync3(command.command, command.args, { stdio: "ignore" });
14454
- }
14455
14616
  function forceQuitDesktopProcess(pid, target) {
14456
14617
  if (target.platform === "windows") {
14457
14618
  spawnSync3("taskkill.exe", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore" });
@@ -14462,8 +14623,35 @@ function forceQuitDesktopProcess(pid, target) {
14462
14623
  } catch {
14463
14624
  }
14464
14625
  }
14465
- function isRunningInsideDesktopExecutable() {
14466
- 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
+ });
14467
14655
  }
14468
14656
  async function waitForUpdateQuitResponse(responsePath, timeoutMs = 8e3) {
14469
14657
  const startedAt = Date.now();
@@ -14475,10 +14663,13 @@ async function waitForUpdateQuitResponse(responsePath, timeoutMs = 8e3) {
14475
14663
  }
14476
14664
  return null;
14477
14665
  }
14478
- async function requestDesktopQuit(executablePath, target) {
14666
+ async function requestDesktopQuit(executablePath, target, options = {}) {
14479
14667
  if (!await pathExists2(executablePath)) return { ok: true, status: "not_running" };
14480
14668
  const responsePath = path21.join(tmpdir(), `rudder-update-quit-${process.pid}-${Date.now()}.json`);
14481
- 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
+ ], {
14482
14673
  stdio: "ignore",
14483
14674
  timeout: 5e3
14484
14675
  });
@@ -14486,7 +14677,7 @@ async function requestDesktopQuit(executablePath, target) {
14486
14677
  return null;
14487
14678
  }
14488
14679
  try {
14489
- return await waitForUpdateQuitResponse(responsePath);
14680
+ return await waitForUpdateQuitResponse(responsePath, options.responseTimeoutMs);
14490
14681
  } finally {
14491
14682
  await rm2(responsePath, { force: true });
14492
14683
  }
@@ -14515,6 +14706,12 @@ async function waitForProcessExit(pid, timeoutMs = 2e4, intervalMs = 250) {
14515
14706
  }
14516
14707
  return !processExists(pid);
14517
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
+ }
14518
14715
  async function removePathWithRetry(targetPath, attempts = 5) {
14519
14716
  for (let attempt = 0; attempt < attempts; attempt += 1) {
14520
14717
  try {
@@ -14527,50 +14724,98 @@ async function removePathWithRetry(targetPath, attempts = 5) {
14527
14724
  return false;
14528
14725
  }
14529
14726
  async function prepareForDesktopReplace(paths, target, options = {}) {
14530
- const forceQuit = options.forceQuitDesktopProcesses ?? forceQuitDesktopProcesses;
14531
14727
  const forceQuitPid = options.forceQuitDesktopProcess ?? forceQuitDesktopProcess;
14532
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 = [];
14533
14749
  const hasManagedExecutable = await pathExists2(paths.executablePath);
14534
14750
  if (hasManagedExecutable) {
14535
- let quitResponse = await requestDesktopQuit(paths.executablePath, target);
14536
- 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) {
14537
14758
  p15.log.warn(
14538
14759
  `Rudder Desktop has ${quitResponse.totalRuns} active run${quitResponse.totalRuns === 1 ? "" : "s"}; waiting before replacing Desktop.`
14539
14760
  );
14540
14761
  await delay2(options.activeRunPollIntervalMs ?? 15e3);
14541
- quitResponse = await requestDesktopQuit(paths.executablePath, target);
14762
+ quitResponse = await requestQuit();
14542
14763
  }
14543
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
+ }
14544
14770
  throw new Error(
14545
- `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.`
14546
14772
  );
14547
14773
  }
14548
- const quitPid = readUpdateQuitPid(quitResponse);
14774
+ if (quitResponse && !quitResponse.ok && quitResponse.status === "failed") {
14775
+ throw new Error(quitResponse.message);
14776
+ }
14777
+ quitPid = readUpdateQuitPid(quitResponse);
14549
14778
  if (quitPid) {
14550
14779
  p15.log.info(`Waiting for existing Rudder Desktop process ${quitPid} to exit before replacing it.`);
14551
14780
  if (!await waitForExit(quitPid)) {
14552
14781
  p15.log.warn(`Rudder Desktop process ${quitPid} did not exit in time; attempting force-quit fallback.`);
14553
- forceQuitPid(quitPid, target);
14554
- await delay2(options.updateQuitForceDelayMs ?? UPDATE_QUIT_FORCE_DELAY_MS);
14782
+ await forceQuitPidAndConfirm(quitPid);
14555
14783
  }
14556
14784
  } else if (isLegacyUnconfirmedUpdateQuit(quitResponse)) {
14557
14785
  const graceMs = options.legacyUpdateQuitGraceMs ?? LEGACY_UPDATE_QUIT_GRACE_MS;
14558
14786
  p15.log.warn(
14559
- `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.`
14560
14788
  );
14561
14789
  await delay2(graceMs);
14562
- forceQuit(target);
14563
- 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
+ }
14564
14805
  } else {
14565
14806
  await delay2(options.updateQuitForceDelayMs ?? UPDATE_QUIT_FORCE_DELAY_MS);
14566
14807
  }
14567
- } else if (!isRunningInsideDesktopExecutable()) {
14568
- forceQuit(target);
14569
14808
  }
14570
14809
  const replacePath = target.platform === "windows" ? paths.installRoot : paths.appPath;
14571
14810
  if (await removePathWithRetry(replacePath)) return;
14572
- forceQuit(target);
14573
- 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);
14574
14819
  if (await removePathWithRetry(replacePath, 6)) return;
14575
14820
  throw new Error(`Failed to replace existing Rudder Desktop at ${replacePath}. Close Rudder and rerun start.`);
14576
14821
  }
@@ -14903,22 +15148,26 @@ async function startCommand(opts) {
14903
15148
  () => assertChecksumMatch(cachedAsset.path, expectedChecksum),
14904
15149
  desktopProgressJson ? "verifying_checksum" : null
14905
15150
  );
15151
+ let applySignal = null;
14906
15152
  if (desktopProgressJson && opts.desktopWaitForApply === true) {
14907
15153
  writeDesktopProgress({
14908
15154
  phase: "ready_to_install",
14909
15155
  message: "Desktop update is downloaded and verified.",
14910
15156
  percent: 100
14911
15157
  });
14912
- await waitForDesktopApplySignal();
15158
+ applySignal = await waitForDesktopApplySignal();
14913
15159
  writeDesktopProgress({
14914
15160
  phase: "preparing_restart",
14915
- message: "Applying Desktop update..."
15161
+ message: applySignal.force ? "Applying Desktop update and quitting active runs..." : "Applying Desktop update..."
14916
15162
  });
14917
15163
  }
14918
15164
  await runStartPhase(
14919
15165
  "Replacing existing Rudder Desktop if needed...",
14920
15166
  "Existing Desktop install is ready for replacement.",
14921
- () => prepareForDesktopReplace(installPaths, target, { waitForActiveRuns: opts.waitForActiveRuns === true }),
15167
+ () => prepareForDesktopReplace(installPaths, target, {
15168
+ waitForActiveRuns: opts.waitForActiveRuns === true,
15169
+ forceUpdate: applySignal?.force === true
15170
+ }),
14922
15171
  desktopProgressJson ? opts.waitForActiveRuns === true ? "waiting_for_active_runs" : "preparing_restart" : null
14923
15172
  );
14924
15173
  await runStartPhase(