@rudderhq/cli 0.3.6-canary.2 → 0.3.6-canary.21

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, chatQueuedMessagePayloadSchema, createChatQueuedMessageSchema, updateChatQueuedMessageSchema, cancelChatQueuedMessageSchema, steerChatQueuedMessageSchema, 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";
@@ -819,7 +826,33 @@ var init_chat = __esm({
819
826
  });
820
827
  addChatMessageSchema = z4.object({
821
828
  body: z4.string().trim().min(1).max(2e4),
822
- editUserMessageId: z4.string().uuid().optional().nullable()
829
+ editUserMessageId: z4.string().uuid().optional().nullable(),
830
+ queuedMessageId: z4.string().uuid().optional().nullable()
831
+ });
832
+ chatQueuedMessagePayloadSchema = z4.object({
833
+ body: z4.string().trim().min(1).max(2e4),
834
+ attachmentIds: z4.array(z4.string().uuid()).optional().default([]),
835
+ projectId: z4.string().uuid().optional().nullable(),
836
+ skillRefs: z4.array(z4.string().trim().min(1).max(240)).optional().default([]),
837
+ accessMode: z4.string().trim().min(1).max(120).optional().nullable(),
838
+ model: z4.string().trim().min(1).max(120).optional().nullable(),
839
+ effort: z4.string().trim().min(1).max(120).optional().nullable(),
840
+ metadata: z4.record(z4.unknown()).optional().nullable()
841
+ });
842
+ createChatQueuedMessageSchema = z4.object({
843
+ clientMutationId: z4.string().trim().min(1).max(120),
844
+ expectedGenerationId: z4.string().uuid().optional().nullable(),
845
+ payload: chatQueuedMessagePayloadSchema
846
+ });
847
+ updateChatQueuedMessageSchema = z4.object({
848
+ version: z4.number().int().positive(),
849
+ payload: chatQueuedMessagePayloadSchema
850
+ });
851
+ cancelChatQueuedMessageSchema = z4.object({
852
+ version: z4.number().int().positive().optional()
853
+ });
854
+ steerChatQueuedMessageSchema = z4.object({
855
+ expectedActiveGenerationId: z4.string().uuid().optional().nullable()
823
856
  });
824
857
  chatRichReferenceDisplaySchema = z4.enum(["card", "inline"]);
825
858
  chatIssueIdentifierSchema = z4.string().trim().min(1).max(64).regex(/^[A-Z0-9][A-Z0-9-]*$/i);
@@ -971,10 +1004,14 @@ var init_chat = __esm({
971
1004
  name: z4.string().trim().min(1).max(80),
972
1005
  icon: z4.string().trim().min(1).max(24).optional().nullable()
973
1006
  });
1007
+ createMessengerCustomGroupWithEntriesSchema = createMessengerCustomGroupSchema.extend({
1008
+ threadKeys: z4.array(z4.string().trim().min(1).max(240)).min(1).max(50)
1009
+ });
974
1010
  updateMessengerCustomGroupSchema = z4.object({
975
1011
  name: z4.string().trim().min(1).max(80).optional(),
976
1012
  icon: z4.string().trim().min(1).max(24).optional().nullable(),
977
1013
  collapsed: z4.boolean().optional(),
1014
+ pinned: z4.boolean().optional(),
978
1015
  sortOrder: z4.number().int().min(0).optional()
979
1016
  });
980
1017
  reorderMessengerCustomGroupsSchema = z4.object({
@@ -1768,7 +1805,7 @@ var init_agent = __esm({
1768
1805
 
1769
1806
  // ../packages/shared/dist/validators/agent-integration.js
1770
1807
  import { z as z13 } from "zod";
1771
- var agentIntegrationProviderSchema, agentIntegrationStatusSchema, agentIntegrationTransportSchema, agentIntegrationProviderRegionSchema, agentIntegrationChatTypeSchema, agentIntegrationDropReasonSchema, agentIntegrationOutboundStatusSchema, createAgentIntegrationSchema, feishuEventHeaderSchema, feishuSenderIdSchema, feishuMessageMentionSchema, feishuMessageSchema, feishuEventSchema, mockFeishuInboundEventSchema;
1808
+ var agentIntegrationProviderSchema, agentIntegrationStatusSchema, agentIntegrationTransportSchema, agentIntegrationProviderRegionSchema, agentIntegrationChatTypeSchema, agentIntegrationDropReasonSchema, agentIntegrationOutboundStatusSchema, createAgentIntegrationSchema, connectAgentIntegrationSchema, feishuEventHeaderSchema, feishuSenderIdSchema, feishuMessageMentionSchema, feishuMessageSchema, feishuEventSchema, mockFeishuInboundEventSchema;
1772
1809
  var init_agent_integration = __esm({
1773
1810
  "../packages/shared/dist/validators/agent-integration.js"() {
1774
1811
  "use strict";
@@ -1792,9 +1829,11 @@ var init_agent_integration = __esm({
1792
1829
  installerUserId: z13.string().min(1).optional().nullable(),
1793
1830
  manageUrl: z13.string().url().optional().nullable()
1794
1831
  });
1832
+ connectAgentIntegrationSchema = createAgentIntegrationSchema.omit({ agentId: true });
1795
1833
  feishuEventHeaderSchema = z13.object({
1796
1834
  event_id: z13.string().min(1).optional(),
1797
1835
  app_id: z13.string().min(1).optional(),
1836
+ token: z13.string().min(1).optional(),
1798
1837
  create_time: z13.string().min(1).optional()
1799
1838
  }).passthrough();
1800
1839
  feishuSenderIdSchema = z13.object({
@@ -1821,6 +1860,11 @@ var init_agent_integration = __esm({
1821
1860
  message: feishuMessageSchema.optional()
1822
1861
  }).passthrough();
1823
1862
  mockFeishuInboundEventSchema = z13.object({
1863
+ type: z13.string().min(1).optional(),
1864
+ token: z13.string().min(1).optional(),
1865
+ challenge: z13.string().min(1).optional(),
1866
+ mockVerificationToken: z13.string().min(1).optional(),
1867
+ mockEncryptKey: z13.string().min(1).optional(),
1824
1868
  eventId: z13.string().min(1).optional(),
1825
1869
  appId: z13.string().min(1).optional(),
1826
1870
  botOpenId: z13.string().min(1).optional().nullable(),
@@ -2975,6 +3019,7 @@ var init_api = __esm({
2975
3019
  secrets: `${API_PREFIX}/secrets`,
2976
3020
  costs: `${API_PREFIX}/costs`,
2977
3021
  activity: `${API_PREFIX}/activity`,
3022
+ agentRuns: `${API_PREFIX}/agent-runs`,
2978
3023
  dashboard: `${API_PREFIX}/dashboard`,
2979
3024
  sidebarBadges: `${API_PREFIX}/sidebar-badges`,
2980
3025
  invites: `${API_PREFIX}/invites`,
@@ -3033,6 +3078,19 @@ var init_project_url_key = __esm({
3033
3078
  }
3034
3079
  });
3035
3080
 
3081
+ // ../packages/shared/dist/short-refs.js
3082
+ var SHORT_REF_PREFIX_BY_KIND, SHORT_REF_KIND_BY_PREFIX;
3083
+ var init_short_refs = __esm({
3084
+ "../packages/shared/dist/short-refs.js"() {
3085
+ "use strict";
3086
+ SHORT_REF_PREFIX_BY_KIND = {
3087
+ agent: "agt",
3088
+ issue_comment: "cmt"
3089
+ };
3090
+ SHORT_REF_KIND_BY_PREFIX = Object.fromEntries(Object.entries(SHORT_REF_PREFIX_BY_KIND).map(([kind, prefix]) => [prefix, kind]));
3091
+ }
3092
+ });
3093
+
3036
3094
  // ../packages/shared/dist/token-usage.js
3037
3095
  var init_token_usage = __esm({
3038
3096
  "../packages/shared/dist/token-usage.js"() {
@@ -3237,6 +3295,7 @@ var init_dist = __esm({
3237
3295
  "../packages/shared/dist/index.js"() {
3238
3296
  "use strict";
3239
3297
  init_constants();
3298
+ init_agent_run();
3240
3299
  init_observability();
3241
3300
  init_workspace_backup();
3242
3301
  init_validators();
@@ -3248,6 +3307,7 @@ var init_dist = __esm({
3248
3307
  init_organization_url_key();
3249
3308
  init_project_mentions();
3250
3309
  init_project_url_key();
3310
+ init_short_refs();
3251
3311
  init_token_usage();
3252
3312
  init_issue_activity();
3253
3313
  init_config_schema();
@@ -7012,7 +7072,7 @@ function printOutput(data, opts = {}) {
7012
7072
  }
7013
7073
  function formatInlineRecord(record, opts = {}) {
7014
7074
  const displayRecord = shouldShowFullIds(opts.fullIds) ? record : toCliShortIdOutput(record);
7015
- const keyOrder = ["identifier", "id", "name", "status", "priority", "title", "action"];
7075
+ const keyOrder = ["identifier", "shortRef", "id", "name", "status", "priority", "title", "action"];
7016
7076
  const seen = /* @__PURE__ */ new Set();
7017
7077
  const parts = [];
7018
7078
  for (const key of keyOrder) {
@@ -7269,7 +7329,7 @@ var RUDDER_AGENT_OPERATING_CONTRACT = [
7269
7329
  "- `library:projects/<project-key>/...` is the Rudder product locator for those files, not the Markdown link syntax and not a reason to route ordinary local edits through the CLI.",
7270
7330
  '- When you create or update a durable Library file, always include a user-visible Markdown link to that file in your final chat reply or issue comment. Use `rudder library file ref "$RUDDER_PROJECT_LIBRARY_PATH/<relative-file>" --json` and paste the returned `markdownLink`; do not pass the absolute `$RUDDER_PROJECT_LIBRARY_ROOT/...` path to `ref`, and do not hand-write `library-entry://...` or `library-file://...` links.',
7271
7331
  '- If `$RUDDER_PROJECT_LIBRARY_ROOT` is unset or inaccessible, use `rudder library file get/put "$RUDDER_PROJECT_LIBRARY_PATH/<relative-file>"` as the remote or restricted runtime fallback.',
7272
- "- Use `/tmp` only for transient scratch files and temporary verification files; do not put durable work product there.",
7332
+ "- Use `$RUDDER_RUNTIME_TMPDIR` for transient scratch files and temporary verification files when it is set; otherwise use `/tmp`. Do not put durable work product there.",
7273
7333
  "- Local trusted runtimes may expose the host operator home as `$RUDDER_OPERATOR_HOME`; use it only when a local skill or script intentionally needs operator-owned desktop app or CLI state. Do not replace `$HOME` with it.",
7274
7334
  "",
7275
7335
  "When you create or copy a skill under `$AGENT_HOME/skills/<slug>/`, check the agent's Skills snapshot before claiming it will load in future runs. If it is installed but not enabled, say exactly that future runs will not load it until enabled, and offer to enable it with `rudder agent skills enable <agent-id> <selection-ref>` when you have permission.",
@@ -7283,6 +7343,7 @@ var RUDDER_AGENT_OPERATING_CONTRACT = [
7283
7343
  "",
7284
7344
  "- Issues: use `[](issue://<issue-id>)`; include `?c=<comment-id>` when linking to a specific comment.",
7285
7345
  "- 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.",
7346
+ "- Automations: use `[](automation://<automation-id>)` when citing a Rudder automation.",
7286
7347
  "- Projects: use `[](project://<project-id>)` when citing a Rudder project.",
7287
7348
  "- Chat threads: use `[](chat://<conversation-id>)` when citing a Rudder chat conversation.",
7288
7349
  "- 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 +7359,7 @@ var RUDDER_AGENT_OPERATING_CONTRACT = [
7298
7359
  "",
7299
7360
  "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
7361
  "",
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.",
7362
+ "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
7363
  "",
7303
7364
  "Invoke it whenever you need to remember, retrieve, or organize anything.",
7304
7365
  "",
@@ -7315,19 +7376,25 @@ var RUDDER_AGENT_OPERATING_CONTRACT = [
7315
7376
  var RUDDER_AGENT_HEARTBEAT_INSTRUCTION = [
7316
7377
  "# Rudder Heartbeat Instruction",
7317
7378
  "",
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.",
7379
+ "This section is injected by Rudder for heartbeat scene runs. It is the platform-owned timed-wakeup pipeline.",
7319
7380
  "",
7320
7381
  "## Heartbeat Pipeline",
7321
7382
  "",
7322
7383
  "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.",
7384
+ "2. Local Planning Check:",
7385
+ " ",
7386
+ "- 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.",
7387
+ "- Review each planned item: what's completed, what's blocked, and what up next.",
7388
+ "- Record progress updates in the daily notes.",
7389
+ " ",
7390
+ "3.Then handle approval follow-up: read the approval and linked issues, then close resolved work or comment on what remains.",
7391
+ "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.",
7392
+ "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.",
7393
+ "6. Checkout before doing assignee task work. A `409` means another agent owns the task; do not retry it.",
7394
+ "7. Load compact issue context, do one bounded useful chunk, and preserve evidence.",
7395
+ "8. Before exiting active work, leave exactly one durable signal: progress, done, blocked, explicit handoff, or structured review decision.",
7396
+ "9. Treat passive follow-up as close-out governance, not a fresh assignment.",
7397
+ "10. Treat review close-out follow-up as review governance; free-form accept/reject text is not a durable decision.",
7331
7398
  "",
7332
7399
  "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
7400
  ].join("\n");
@@ -7436,9 +7503,9 @@ var AGENT_CLI_CAPABILITIES = [
7436
7503
  },
7437
7504
  {
7438
7505
  id: "agent.get",
7439
- command: "rudder agent get <agent-id-or-shortname>",
7506
+ command: "rudder agent get <agent-id-or-shortname-or-agt-ref>",
7440
7507
  category: "agent",
7441
- description: "Read one agent by id or shortname.",
7508
+ description: "Read one agent by id, shortname, or agt_<uuid-prefix> short ref.",
7442
7509
  mutating: false,
7443
7510
  contract: "compat",
7444
7511
  requiresOrgId: false,
@@ -7592,9 +7659,9 @@ var AGENT_CLI_CAPABILITIES = [
7592
7659
  },
7593
7660
  {
7594
7661
  id: "issue.context",
7595
- command: "rudder issue context <issue>",
7662
+ command: "rudder issue context <issue> [--wake-comment-id <comment-id-or-cmt-ref>]",
7596
7663
  category: "issue",
7597
- description: "Read the compact heartbeat context for an issue.",
7664
+ description: "Read the compact heartbeat context for an issue; wake comments may be addressed by full id or cmt_<uuid-prefix>.",
7598
7665
  mutating: false,
7599
7666
  contract: "agent-v1",
7600
7667
  requiresOrgId: false,
@@ -7628,9 +7695,9 @@ var AGENT_CLI_CAPABILITIES = [
7628
7695
  },
7629
7696
  {
7630
7697
  id: "issue.comments.list",
7631
- command: "rudder issue comments list <issue>",
7698
+ command: "rudder issue comments list <issue> [--after <comment-id-or-cmt-ref>]",
7632
7699
  category: "issue",
7633
- description: "List issue comments, optionally only newer comments after a cursor.",
7700
+ description: "List issue comments, optionally only newer comments after a full comment id or cmt_<uuid-prefix> with --after.",
7634
7701
  mutating: false,
7635
7702
  contract: "agent-v1",
7636
7703
  requiresOrgId: false,
@@ -7640,9 +7707,9 @@ var AGENT_CLI_CAPABILITIES = [
7640
7707
  },
7641
7708
  {
7642
7709
  id: "issue.comments.get",
7643
- command: "rudder issue comments get <issue> <comment-id>",
7710
+ command: "rudder issue comments get <issue> <comment-id-or-cmt-ref>",
7644
7711
  category: "issue",
7645
- description: "Read one issue comment by id.",
7712
+ description: "Read one issue comment by full id or cmt_<uuid-prefix> scoped to the issue.",
7646
7713
  mutating: false,
7647
7714
  contract: "agent-v1",
7648
7715
  requiresOrgId: false,
@@ -8603,6 +8670,7 @@ function registerAgentCommands(program) {
8603
8670
  for (const row of rows) {
8604
8671
  console.log(
8605
8672
  formatInlineRecord({
8673
+ shortRef: row.shortRef,
8606
8674
  id: row.id,
8607
8675
  name: row.name,
8608
8676
  role: row.role,
@@ -11504,7 +11572,7 @@ function registerIssueCommands(program) {
11504
11572
  );
11505
11573
  const comments = issue.command("comments").description("Issue comment operations");
11506
11574
  addCommonClientOptions(
11507
- 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) => {
11575
+ 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) => {
11508
11576
  try {
11509
11577
  const ctx = resolveCommandContext(opts);
11510
11578
  const params = new URLSearchParams();
@@ -11521,7 +11589,7 @@ function registerIssueCommands(program) {
11521
11589
  })
11522
11590
  );
11523
11591
  addCommonClientOptions(
11524
- comments.command("get").description(getAgentCliCapabilityById("issue.comments.get").description).argument("<issueId>", "Issue ID").argument("<commentId>", "Comment ID").action(async (issueId, commentId, opts) => {
11592
+ 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) => {
11525
11593
  try {
11526
11594
  const ctx = resolveCommandContext(opts);
11527
11595
  const row = await ctx.api.get(`/api/issues/${issueId}/comments/${commentId}`);
@@ -13756,6 +13824,7 @@ function createByteProgress(label, options = {}) {
13756
13824
  init_version();
13757
13825
  var DEFAULT_DESKTOP_RELEASE_REPO = "Undertone0809/rudder";
13758
13826
  var DESKTOP_UPDATE_QUIT_ARG = "--rudder-update-quit";
13827
+ var DESKTOP_UPDATE_FORCE_ARG = "--rudder-update-force";
13759
13828
  var STABLE_SEMVER_RE = /^[0-9]+\.[0-9]+\.[0-9]+$/;
13760
13829
  var CANARY_SEMVER_RE = /^[0-9]+\.[0-9]+\.[0-9]+-canary\.[0-9]+$/;
13761
13830
  var CLI_REGISTRY_LATEST_URL = "https://registry.npmjs.org/@rudderhq%2fcli/latest";
@@ -13839,7 +13908,7 @@ function createDesktopProgressFactory() {
13839
13908
  async function waitForDesktopApplySignal() {
13840
13909
  process.stdin.setEncoding("utf8");
13841
13910
  process.stdin.resume();
13842
- await new Promise((resolve, reject) => {
13911
+ return await new Promise((resolve, reject) => {
13843
13912
  let buffer = "";
13844
13913
  const cleanup = () => {
13845
13914
  process.stdin.off("data", onData);
@@ -13850,9 +13919,15 @@ async function waitForDesktopApplySignal() {
13850
13919
  buffer += chunk;
13851
13920
  const lines = buffer.split(/\r?\n/);
13852
13921
  buffer = lines.pop() ?? "";
13853
- if (lines.some((line) => line.trim() === "apply")) {
13922
+ const commands = lines.map((line) => line.trim());
13923
+ if (commands.includes("force-apply")) {
13924
+ cleanup();
13925
+ resolve({ force: true });
13926
+ return;
13927
+ }
13928
+ if (commands.includes("apply")) {
13854
13929
  cleanup();
13855
- resolve();
13930
+ resolve({ force: false });
13856
13931
  }
13857
13932
  };
13858
13933
  const onEnd = () => {
@@ -14565,14 +14640,6 @@ function isInstalledDesktopCurrent(metadata, releaseTag, assetName, assetChecksu
14565
14640
  metadata && metadata.releaseTag === releaseTag && metadata.assetName === assetName && metadata.assetChecksum === assetChecksum
14566
14641
  );
14567
14642
  }
14568
- function buildForceQuitCommand(target) {
14569
- if (target.platform === "windows") return { command: "taskkill.exe", args: ["/IM", `${DESKTOP_APP_NAME}.exe`, "/T", "/F"] };
14570
- return { command: "pkill", args: ["-x", DESKTOP_APP_NAME] };
14571
- }
14572
- function forceQuitDesktopProcesses(target) {
14573
- const command = buildForceQuitCommand(target);
14574
- spawnSync3(command.command, command.args, { stdio: "ignore" });
14575
- }
14576
14643
  function forceQuitDesktopProcess(pid, target) {
14577
14644
  if (target.platform === "windows") {
14578
14645
  spawnSync3("taskkill.exe", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore" });
@@ -14583,8 +14650,35 @@ function forceQuitDesktopProcess(pid, target) {
14583
14650
  } catch {
14584
14651
  }
14585
14652
  }
14586
- function isRunningInsideDesktopExecutable() {
14587
- return path21.basename(process.execPath).toLowerCase().startsWith(DESKTOP_APP_NAME.toLowerCase());
14653
+ function quotePowerShellString(value) {
14654
+ return `'${value.replaceAll("'", "''")}'`;
14655
+ }
14656
+ function findDesktopExecutablePids(executablePath, target) {
14657
+ if (target.platform === "windows") {
14658
+ const result2 = spawnSync3("powershell.exe", [
14659
+ "-NoProfile",
14660
+ "-Command",
14661
+ `Get-CimInstance Win32_Process | Where-Object { $_.ExecutablePath -eq ${quotePowerShellString(executablePath)} } | Select-Object -ExpandProperty ProcessId`
14662
+ ], {
14663
+ encoding: "utf8",
14664
+ stdio: ["ignore", "pipe", "ignore"]
14665
+ });
14666
+ if (result2.status !== 0) return [];
14667
+ return result2.stdout.split(/\r?\n/).map((line) => Number.parseInt(line.trim(), 10)).filter((pid) => Number.isInteger(pid) && pid > 0 && pid !== process.pid);
14668
+ }
14669
+ const result = spawnSync3("ps", ["-eo", "pid=,args="], {
14670
+ encoding: "utf8",
14671
+ stdio: ["ignore", "pipe", "ignore"]
14672
+ });
14673
+ if (result.status !== 0) return [];
14674
+ return result.stdout.split(/\r?\n/).flatMap((line) => {
14675
+ const match = line.match(/^\s*(\d+)\s+(.+)$/);
14676
+ if (!match) return [];
14677
+ const pid = Number.parseInt(match[1], 10);
14678
+ const commandLine = match[2];
14679
+ const matchesExecutable = commandLine === executablePath || commandLine.startsWith(`${executablePath} `);
14680
+ return matchesExecutable && pid !== process.pid ? [pid] : [];
14681
+ });
14588
14682
  }
14589
14683
  async function waitForUpdateQuitResponse(responsePath, timeoutMs = 8e3) {
14590
14684
  const startedAt = Date.now();
@@ -14596,10 +14690,13 @@ async function waitForUpdateQuitResponse(responsePath, timeoutMs = 8e3) {
14596
14690
  }
14597
14691
  return null;
14598
14692
  }
14599
- async function requestDesktopQuit(executablePath, target) {
14693
+ async function requestDesktopQuit(executablePath, target, options = {}) {
14600
14694
  if (!await pathExists2(executablePath)) return { ok: true, status: "not_running" };
14601
14695
  const responsePath = path21.join(tmpdir(), `rudder-update-quit-${process.pid}-${Date.now()}.json`);
14602
- const result = spawnSync3(executablePath, [`${DESKTOP_UPDATE_QUIT_ARG}=${responsePath}`], {
14696
+ const result = spawnSync3(executablePath, [
14697
+ `${DESKTOP_UPDATE_QUIT_ARG}=${responsePath}`,
14698
+ ...options.forceUpdate ? [DESKTOP_UPDATE_FORCE_ARG] : []
14699
+ ], {
14603
14700
  stdio: "ignore",
14604
14701
  timeout: 5e3
14605
14702
  });
@@ -14607,7 +14704,7 @@ async function requestDesktopQuit(executablePath, target) {
14607
14704
  return null;
14608
14705
  }
14609
14706
  try {
14610
- return await waitForUpdateQuitResponse(responsePath);
14707
+ return await waitForUpdateQuitResponse(responsePath, options.responseTimeoutMs);
14611
14708
  } finally {
14612
14709
  await rm2(responsePath, { force: true });
14613
14710
  }
@@ -14636,6 +14733,12 @@ async function waitForProcessExit(pid, timeoutMs = 2e4, intervalMs = 250) {
14636
14733
  }
14637
14734
  return !processExists(pid);
14638
14735
  }
14736
+ async function waitForProcessesExit(pids, waitForExit) {
14737
+ const uniquePids = [...new Set(pids)];
14738
+ if (uniquePids.length === 0) return true;
14739
+ const results = await Promise.all(uniquePids.map((pid) => waitForExit(pid)));
14740
+ return results.every(Boolean);
14741
+ }
14639
14742
  async function removePathWithRetry(targetPath, attempts = 5) {
14640
14743
  for (let attempt = 0; attempt < attempts; attempt += 1) {
14641
14744
  try {
@@ -14648,50 +14751,98 @@ async function removePathWithRetry(targetPath, attempts = 5) {
14648
14751
  return false;
14649
14752
  }
14650
14753
  async function prepareForDesktopReplace(paths, target, options = {}) {
14651
- const forceQuit = options.forceQuitDesktopProcesses ?? forceQuitDesktopProcesses;
14652
14754
  const forceQuitPid = options.forceQuitDesktopProcess ?? forceQuitDesktopProcess;
14653
14755
  const waitForExit = options.waitForDesktopProcessExit ?? waitForProcessExit;
14756
+ const findPids = options.findDesktopExecutablePids ?? findDesktopExecutablePids;
14757
+ async function forceQuitPidAndConfirm(pid) {
14758
+ forceQuitPid(pid, target);
14759
+ await delay2(options.updateQuitForceDelayMs ?? UPDATE_QUIT_FORCE_DELAY_MS);
14760
+ if (!await waitForExit(pid)) {
14761
+ throw new Error(`Rudder Desktop process ${pid} did not exit after force-quit fallback. Close Rudder and rerun start.`);
14762
+ }
14763
+ }
14764
+ async function forceQuitPidsAndConfirm(pids) {
14765
+ const uniquePids = [...new Set(pids)];
14766
+ for (const pid of uniquePids) {
14767
+ forceQuitPid(pid, target);
14768
+ }
14769
+ await delay2(options.updateQuitForceDelayMs ?? UPDATE_QUIT_FORCE_DELAY_MS);
14770
+ if (!await waitForProcessesExit(uniquePids, waitForExit)) {
14771
+ throw new Error(`Rudder Desktop process${uniquePids.length === 1 ? "" : "es"} ${uniquePids.join(", ")} did not exit after force-quit fallback. Close Rudder and rerun start.`);
14772
+ }
14773
+ }
14774
+ let quitPid = null;
14775
+ let managedExecutablePids = [];
14654
14776
  const hasManagedExecutable = await pathExists2(paths.executablePath);
14655
14777
  if (hasManagedExecutable) {
14656
- let quitResponse = await requestDesktopQuit(paths.executablePath, target);
14657
- while (quitResponse && !quitResponse.ok && quitResponse.status === "active_runs" && options.waitForActiveRuns) {
14778
+ managedExecutablePids = findPids(paths.executablePath, target);
14779
+ const requestQuit = () => requestDesktopQuit(paths.executablePath, target, {
14780
+ forceUpdate: options.forceUpdate,
14781
+ responseTimeoutMs: options.updateQuitResponseTimeoutMs
14782
+ });
14783
+ let quitResponse = await requestQuit();
14784
+ while (quitResponse && !quitResponse.ok && quitResponse.status === "active_runs" && options.waitForActiveRuns && !options.forceUpdate) {
14658
14785
  p15.log.warn(
14659
14786
  `Rudder Desktop has ${quitResponse.totalRuns} active run${quitResponse.totalRuns === 1 ? "" : "s"}; waiting before replacing Desktop.`
14660
14787
  );
14661
14788
  await delay2(options.activeRunPollIntervalMs ?? 15e3);
14662
- quitResponse = await requestDesktopQuit(paths.executablePath, target);
14789
+ quitResponse = await requestQuit();
14663
14790
  }
14664
14791
  if (quitResponse && !quitResponse.ok && quitResponse.status === "active_runs") {
14792
+ if (!options.forceUpdate) {
14793
+ throw new Error(
14794
+ `Rudder Desktop has ${quitResponse.totalRuns} active run${quitResponse.totalRuns === 1 ? "" : "s"}. Stop active work, then rerun start.`
14795
+ );
14796
+ }
14665
14797
  throw new Error(
14666
- `Rudder Desktop has ${quitResponse.totalRuns} active run${quitResponse.totalRuns === 1 ? "" : "s"}. Stop active work, then rerun start.`
14798
+ `Rudder Desktop still has ${quitResponse.totalRuns} active run${quitResponse.totalRuns === 1 ? "" : "s"} after the force-update request. Stop active work, then rerun start.`
14667
14799
  );
14668
14800
  }
14669
- const quitPid = readUpdateQuitPid(quitResponse);
14801
+ if (quitResponse && !quitResponse.ok && quitResponse.status === "failed") {
14802
+ throw new Error(quitResponse.message);
14803
+ }
14804
+ quitPid = readUpdateQuitPid(quitResponse);
14670
14805
  if (quitPid) {
14671
14806
  p15.log.info(`Waiting for existing Rudder Desktop process ${quitPid} to exit before replacing it.`);
14672
14807
  if (!await waitForExit(quitPid)) {
14673
14808
  p15.log.warn(`Rudder Desktop process ${quitPid} did not exit in time; attempting force-quit fallback.`);
14674
- forceQuitPid(quitPid, target);
14675
- await delay2(options.updateQuitForceDelayMs ?? UPDATE_QUIT_FORCE_DELAY_MS);
14809
+ await forceQuitPidAndConfirm(quitPid);
14676
14810
  }
14677
14811
  } else if (isLegacyUnconfirmedUpdateQuit(quitResponse)) {
14678
14812
  const graceMs = options.legacyUpdateQuitGraceMs ?? LEGACY_UPDATE_QUIT_GRACE_MS;
14679
14813
  p15.log.warn(
14680
- `Existing Rudder Desktop acknowledged update quit without a process id; waiting ${Math.ceil(graceMs / 1e3)}s before force-quit fallback.`
14814
+ `Existing Rudder Desktop acknowledged update quit without a process id; waiting ${Math.ceil(graceMs / 1e3)}s before replacement.`
14681
14815
  );
14682
14816
  await delay2(graceMs);
14683
- forceQuit(target);
14684
- await delay2(options.updateQuitForceDelayMs ?? UPDATE_QUIT_FORCE_DELAY_MS);
14817
+ if (managedExecutablePids.length > 0 && !await waitForProcessesExit(managedExecutablePids, waitForExit)) {
14818
+ p15.log.warn(
14819
+ `Existing Rudder Desktop did not exit after acknowledging update quit; attempting path-scoped force-quit for process${managedExecutablePids.length === 1 ? "" : "es"} ${managedExecutablePids.join(", ")}.`
14820
+ );
14821
+ await forceQuitPidsAndConfirm(managedExecutablePids);
14822
+ }
14823
+ } else if (!quitResponse) {
14824
+ if (options.forceUpdate && managedExecutablePids.length > 0) {
14825
+ p15.log.warn(
14826
+ `Existing Rudder Desktop did not respond to the update quit request; attempting path-scoped force-quit for process${managedExecutablePids.length === 1 ? "" : "es"} ${managedExecutablePids.join(", ")}.`
14827
+ );
14828
+ await forceQuitPidsAndConfirm(managedExecutablePids);
14829
+ } else {
14830
+ throw new Error("Existing Rudder Desktop did not respond to the update quit request. Close Rudder and rerun start.");
14831
+ }
14685
14832
  } else {
14686
14833
  await delay2(options.updateQuitForceDelayMs ?? UPDATE_QUIT_FORCE_DELAY_MS);
14687
14834
  }
14688
- } else if (!isRunningInsideDesktopExecutable()) {
14689
- forceQuit(target);
14690
14835
  }
14691
14836
  const replacePath = target.platform === "windows" ? paths.installRoot : paths.appPath;
14692
14837
  if (await removePathWithRetry(replacePath)) return;
14693
- forceQuit(target);
14694
- await delay2(options.updateQuitForceDelayMs ?? UPDATE_QUIT_FORCE_DELAY_MS);
14838
+ if (!quitPid) {
14839
+ if (managedExecutablePids.length > 0) {
14840
+ await forceQuitPidsAndConfirm(managedExecutablePids);
14841
+ if (await removePathWithRetry(replacePath, 6)) return;
14842
+ }
14843
+ throw new Error(`Failed to replace existing Rudder Desktop at ${replacePath}. Close Rudder and rerun start.`);
14844
+ }
14845
+ await forceQuitPidAndConfirm(quitPid);
14695
14846
  if (await removePathWithRetry(replacePath, 6)) return;
14696
14847
  throw new Error(`Failed to replace existing Rudder Desktop at ${replacePath}. Close Rudder and rerun start.`);
14697
14848
  }
@@ -15024,22 +15175,26 @@ async function startCommand(opts) {
15024
15175
  () => assertChecksumMatch(cachedAsset.path, expectedChecksum),
15025
15176
  desktopProgressJson ? "verifying_checksum" : null
15026
15177
  );
15178
+ let applySignal = null;
15027
15179
  if (desktopProgressJson && opts.desktopWaitForApply === true) {
15028
15180
  writeDesktopProgress({
15029
15181
  phase: "ready_to_install",
15030
15182
  message: "Desktop update is downloaded and verified.",
15031
15183
  percent: 100
15032
15184
  });
15033
- await waitForDesktopApplySignal();
15185
+ applySignal = await waitForDesktopApplySignal();
15034
15186
  writeDesktopProgress({
15035
15187
  phase: "preparing_restart",
15036
- message: "Applying Desktop update..."
15188
+ message: applySignal.force ? "Applying Desktop update and quitting active runs..." : "Applying Desktop update..."
15037
15189
  });
15038
15190
  }
15039
15191
  await runStartPhase(
15040
15192
  "Replacing existing Rudder Desktop if needed...",
15041
15193
  "Existing Desktop install is ready for replacement.",
15042
- () => prepareForDesktopReplace(installPaths, target, { waitForActiveRuns: opts.waitForActiveRuns === true }),
15194
+ () => prepareForDesktopReplace(installPaths, target, {
15195
+ waitForActiveRuns: opts.waitForActiveRuns === true,
15196
+ forceUpdate: applySignal?.force === true
15197
+ }),
15043
15198
  desktopProgressJson ? opts.waitForActiveRuns === true ? "waiting_for_active_runs" : "preparing_restart" : null
15044
15199
  );
15045
15200
  await runStartPhase(