@rudderhq/cli 0.3.6-canary.3 → 0.3.6-canary.30

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, createMessengerCustomGroupWithEntriesSchema, updateMessengerCustomGroupSchema, reorderMessengerCustomGroupsSchema, assignMessengerCustomGroupEntrySchema, reorderMessengerCustomGroupEntriesSchema;
794
+ var chatConversationStatusSchema, chatIssueCreationModeSchema, chatMessageRoleSchema, chatMessageKindSchema, chatMessageStatusSchema, chatContextEntityTypeSchema, createChatContextLinkSchema, createChatConversationSchema, setChatProjectContextSchema, updateChatConversationSchema, forkChatConversationSchema, 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";
@@ -817,9 +824,39 @@ var init_chat = __esm({
817
824
  primaryIssueId: z4.string().uuid().optional().nullable(),
818
825
  resolvedAt: z4.string().datetime().optional().nullable()
819
826
  });
827
+ forkChatConversationSchema = z4.object({
828
+ sourceMessageId: z4.string().uuid().optional().nullable(),
829
+ title: z4.string().trim().min(1).max(200).optional()
830
+ });
820
831
  addChatMessageSchema = z4.object({
821
832
  body: z4.string().trim().min(1).max(2e4),
822
- editUserMessageId: z4.string().uuid().optional().nullable()
833
+ editUserMessageId: z4.string().uuid().optional().nullable(),
834
+ queuedMessageId: z4.string().uuid().optional().nullable()
835
+ });
836
+ chatQueuedMessagePayloadSchema = z4.object({
837
+ body: z4.string().trim().min(1).max(2e4),
838
+ attachmentIds: z4.array(z4.string().uuid()).optional().default([]),
839
+ projectId: z4.string().uuid().optional().nullable(),
840
+ skillRefs: z4.array(z4.string().trim().min(1).max(240)).optional().default([]),
841
+ accessMode: z4.string().trim().min(1).max(120).optional().nullable(),
842
+ model: z4.string().trim().min(1).max(120).optional().nullable(),
843
+ effort: z4.string().trim().min(1).max(120).optional().nullable(),
844
+ metadata: z4.record(z4.unknown()).optional().nullable()
845
+ });
846
+ createChatQueuedMessageSchema = z4.object({
847
+ clientMutationId: z4.string().trim().min(1).max(120),
848
+ expectedGenerationId: z4.string().uuid().optional().nullable(),
849
+ payload: chatQueuedMessagePayloadSchema
850
+ });
851
+ updateChatQueuedMessageSchema = z4.object({
852
+ version: z4.number().int().positive(),
853
+ payload: chatQueuedMessagePayloadSchema
854
+ });
855
+ cancelChatQueuedMessageSchema = z4.object({
856
+ version: z4.number().int().positive().optional()
857
+ });
858
+ steerChatQueuedMessageSchema = z4.object({
859
+ expectedActiveGenerationId: z4.string().uuid().optional().nullable()
823
860
  });
824
861
  chatRichReferenceDisplaySchema = z4.enum(["card", "inline"]);
825
862
  chatIssueIdentifierSchema = z4.string().trim().min(1).max(64).regex(/^[A-Z0-9][A-Z0-9-]*$/i);
@@ -978,6 +1015,7 @@ var init_chat = __esm({
978
1015
  name: z4.string().trim().min(1).max(80).optional(),
979
1016
  icon: z4.string().trim().min(1).max(24).optional().nullable(),
980
1017
  collapsed: z4.boolean().optional(),
1018
+ pinned: z4.boolean().optional(),
981
1019
  sortOrder: z4.number().int().min(0).optional()
982
1020
  });
983
1021
  reorderMessengerCustomGroupsSchema = z4.object({
@@ -1771,7 +1809,7 @@ var init_agent = __esm({
1771
1809
 
1772
1810
  // ../packages/shared/dist/validators/agent-integration.js
1773
1811
  import { z as z13 } from "zod";
1774
- var agentIntegrationProviderSchema, agentIntegrationStatusSchema, agentIntegrationTransportSchema, agentIntegrationProviderRegionSchema, agentIntegrationChatTypeSchema, agentIntegrationDropReasonSchema, agentIntegrationOutboundStatusSchema, createAgentIntegrationSchema, feishuEventHeaderSchema, feishuSenderIdSchema, feishuMessageMentionSchema, feishuMessageSchema, feishuEventSchema, mockFeishuInboundEventSchema;
1812
+ var agentIntegrationProviderSchema, agentIntegrationStatusSchema, agentIntegrationTransportSchema, agentIntegrationProviderRegionSchema, agentIntegrationChatTypeSchema, agentIntegrationDropReasonSchema, agentIntegrationOutboundStatusSchema, createAgentIntegrationSchema, connectAgentIntegrationSchema, feishuEventHeaderSchema, feishuSenderIdSchema, feishuMessageMentionSchema, feishuMessageSchema, feishuEventSchema, mockFeishuInboundEventSchema;
1775
1813
  var init_agent_integration = __esm({
1776
1814
  "../packages/shared/dist/validators/agent-integration.js"() {
1777
1815
  "use strict";
@@ -1795,9 +1833,11 @@ var init_agent_integration = __esm({
1795
1833
  installerUserId: z13.string().min(1).optional().nullable(),
1796
1834
  manageUrl: z13.string().url().optional().nullable()
1797
1835
  });
1836
+ connectAgentIntegrationSchema = createAgentIntegrationSchema.omit({ agentId: true });
1798
1837
  feishuEventHeaderSchema = z13.object({
1799
1838
  event_id: z13.string().min(1).optional(),
1800
1839
  app_id: z13.string().min(1).optional(),
1840
+ token: z13.string().min(1).optional(),
1801
1841
  create_time: z13.string().min(1).optional()
1802
1842
  }).passthrough();
1803
1843
  feishuSenderIdSchema = z13.object({
@@ -1824,6 +1864,11 @@ var init_agent_integration = __esm({
1824
1864
  message: feishuMessageSchema.optional()
1825
1865
  }).passthrough();
1826
1866
  mockFeishuInboundEventSchema = z13.object({
1867
+ type: z13.string().min(1).optional(),
1868
+ token: z13.string().min(1).optional(),
1869
+ challenge: z13.string().min(1).optional(),
1870
+ mockVerificationToken: z13.string().min(1).optional(),
1871
+ mockEncryptKey: z13.string().min(1).optional(),
1827
1872
  eventId: z13.string().min(1).optional(),
1828
1873
  appId: z13.string().min(1).optional(),
1829
1874
  botOpenId: z13.string().min(1).optional().nullable(),
@@ -2978,6 +3023,7 @@ var init_api = __esm({
2978
3023
  secrets: `${API_PREFIX}/secrets`,
2979
3024
  costs: `${API_PREFIX}/costs`,
2980
3025
  activity: `${API_PREFIX}/activity`,
3026
+ agentRuns: `${API_PREFIX}/agent-runs`,
2981
3027
  dashboard: `${API_PREFIX}/dashboard`,
2982
3028
  sidebarBadges: `${API_PREFIX}/sidebar-badges`,
2983
3029
  invites: `${API_PREFIX}/invites`,
@@ -3036,6 +3082,19 @@ var init_project_url_key = __esm({
3036
3082
  }
3037
3083
  });
3038
3084
 
3085
+ // ../packages/shared/dist/short-refs.js
3086
+ var SHORT_REF_PREFIX_BY_KIND, SHORT_REF_KIND_BY_PREFIX;
3087
+ var init_short_refs = __esm({
3088
+ "../packages/shared/dist/short-refs.js"() {
3089
+ "use strict";
3090
+ SHORT_REF_PREFIX_BY_KIND = {
3091
+ agent: "agt",
3092
+ issue_comment: "cmt"
3093
+ };
3094
+ SHORT_REF_KIND_BY_PREFIX = Object.fromEntries(Object.entries(SHORT_REF_PREFIX_BY_KIND).map(([kind, prefix]) => [prefix, kind]));
3095
+ }
3096
+ });
3097
+
3039
3098
  // ../packages/shared/dist/token-usage.js
3040
3099
  var init_token_usage = __esm({
3041
3100
  "../packages/shared/dist/token-usage.js"() {
@@ -3240,6 +3299,7 @@ var init_dist = __esm({
3240
3299
  "../packages/shared/dist/index.js"() {
3241
3300
  "use strict";
3242
3301
  init_constants();
3302
+ init_agent_run();
3243
3303
  init_observability();
3244
3304
  init_workspace_backup();
3245
3305
  init_validators();
@@ -3251,6 +3311,7 @@ var init_dist = __esm({
3251
3311
  init_organization_url_key();
3252
3312
  init_project_mentions();
3253
3313
  init_project_url_key();
3314
+ init_short_refs();
3254
3315
  init_token_usage();
3255
3316
  init_issue_activity();
3256
3317
  init_config_schema();
@@ -7015,7 +7076,7 @@ function printOutput(data, opts = {}) {
7015
7076
  }
7016
7077
  function formatInlineRecord(record, opts = {}) {
7017
7078
  const displayRecord = shouldShowFullIds(opts.fullIds) ? record : toCliShortIdOutput(record);
7018
- const keyOrder = ["identifier", "id", "name", "status", "priority", "title", "action"];
7079
+ const keyOrder = ["identifier", "shortRef", "id", "name", "status", "priority", "title", "action"];
7019
7080
  const seen = /* @__PURE__ */ new Set();
7020
7081
  const parts = [];
7021
7082
  for (const key of keyOrder) {
@@ -7272,7 +7333,7 @@ var RUDDER_AGENT_OPERATING_CONTRACT = [
7272
7333
  "- `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.",
7273
7334
  '- 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.',
7274
7335
  '- 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.',
7275
- "- Use `/tmp` only for transient scratch files and temporary verification files; do not put durable work product there.",
7336
+ "- 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.",
7276
7337
  "- 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.",
7277
7338
  "",
7278
7339
  "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.",
@@ -7302,7 +7363,7 @@ var RUDDER_AGENT_OPERATING_CONTRACT = [
7302
7363
  "",
7303
7364
  "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.",
7304
7365
  "",
7305
- "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.",
7366
+ "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.",
7306
7367
  "",
7307
7368
  "Invoke it whenever you need to remember, retrieve, or organize anything.",
7308
7369
  "",
@@ -7326,9 +7387,9 @@ var RUDDER_AGENT_HEARTBEAT_INSTRUCTION = [
7326
7387
  "1. Identify yourself and inspect wake context, including `RUDDER_TASK_ID`, `RUDDER_WAKE_REASON`, `RUDDER_WAKE_COMMENT_ID`, and `RUDDER_APPROVAL_ID` when present.",
7327
7388
  "2. Local Planning Check:",
7328
7389
  " ",
7329
- " 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.",
7330
- " 2. Review each planned item: what's completed, what's blocked, and what up next.",
7331
- " 3. Record progress updates in the daily notes.",
7390
+ "- 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.",
7391
+ "- Review each planned item: what's completed, what's blocked, and what up next.",
7392
+ "- Record progress updates in the daily notes.",
7332
7393
  " ",
7333
7394
  "3.Then handle approval follow-up: read the approval and linked issues, then close resolved work or comment on what remains.",
7334
7395
  "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.",
@@ -7446,9 +7507,9 @@ var AGENT_CLI_CAPABILITIES = [
7446
7507
  },
7447
7508
  {
7448
7509
  id: "agent.get",
7449
- command: "rudder agent get <agent-id-or-shortname>",
7510
+ command: "rudder agent get <agent-id-or-shortname-or-agt-ref>",
7450
7511
  category: "agent",
7451
- description: "Read one agent by id or shortname.",
7512
+ description: "Read one agent by id, shortname, or agt_<uuid-prefix> short ref.",
7452
7513
  mutating: false,
7453
7514
  contract: "compat",
7454
7515
  requiresOrgId: false,
@@ -7602,9 +7663,9 @@ var AGENT_CLI_CAPABILITIES = [
7602
7663
  },
7603
7664
  {
7604
7665
  id: "issue.context",
7605
- command: "rudder issue context <issue>",
7666
+ command: "rudder issue context <issue> [--wake-comment-id <comment-id-or-cmt-ref>]",
7606
7667
  category: "issue",
7607
- description: "Read the compact heartbeat context for an issue.",
7668
+ description: "Read the compact heartbeat context for an issue; wake comments may be addressed by full id or cmt_<uuid-prefix>.",
7608
7669
  mutating: false,
7609
7670
  contract: "agent-v1",
7610
7671
  requiresOrgId: false,
@@ -7638,9 +7699,9 @@ var AGENT_CLI_CAPABILITIES = [
7638
7699
  },
7639
7700
  {
7640
7701
  id: "issue.comments.list",
7641
- command: "rudder issue comments list <issue>",
7702
+ command: "rudder issue comments list <issue> [--after <comment-id-or-cmt-ref>]",
7642
7703
  category: "issue",
7643
- description: "List issue comments, optionally only newer comments after a cursor.",
7704
+ description: "List issue comments, optionally only newer comments after a full comment id or cmt_<uuid-prefix> with --after.",
7644
7705
  mutating: false,
7645
7706
  contract: "agent-v1",
7646
7707
  requiresOrgId: false,
@@ -7650,9 +7711,9 @@ var AGENT_CLI_CAPABILITIES = [
7650
7711
  },
7651
7712
  {
7652
7713
  id: "issue.comments.get",
7653
- command: "rudder issue comments get <issue> <comment-id>",
7714
+ command: "rudder issue comments get <issue> <comment-id-or-cmt-ref>",
7654
7715
  category: "issue",
7655
- description: "Read one issue comment by id.",
7716
+ description: "Read one issue comment by full id or cmt_<uuid-prefix> scoped to the issue.",
7656
7717
  mutating: false,
7657
7718
  contract: "agent-v1",
7658
7719
  requiresOrgId: false,
@@ -8613,6 +8674,7 @@ function registerAgentCommands(program) {
8613
8674
  for (const row of rows) {
8614
8675
  console.log(
8615
8676
  formatInlineRecord({
8677
+ shortRef: row.shortRef,
8616
8678
  id: row.id,
8617
8679
  name: row.name,
8618
8680
  role: row.role,
@@ -11514,7 +11576,7 @@ function registerIssueCommands(program) {
11514
11576
  );
11515
11577
  const comments = issue.command("comments").description("Issue comment operations");
11516
11578
  addCommonClientOptions(
11517
- 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) => {
11579
+ 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) => {
11518
11580
  try {
11519
11581
  const ctx = resolveCommandContext(opts);
11520
11582
  const params = new URLSearchParams();
@@ -11531,7 +11593,7 @@ function registerIssueCommands(program) {
11531
11593
  })
11532
11594
  );
11533
11595
  addCommonClientOptions(
11534
- comments.command("get").description(getAgentCliCapabilityById("issue.comments.get").description).argument("<issueId>", "Issue ID").argument("<commentId>", "Comment ID").action(async (issueId, commentId, opts) => {
11596
+ 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) => {
11535
11597
  try {
11536
11598
  const ctx = resolveCommandContext(opts);
11537
11599
  const row = await ctx.api.get(`/api/issues/${issueId}/comments/${commentId}`);
@@ -13766,6 +13828,7 @@ function createByteProgress(label, options = {}) {
13766
13828
  init_version();
13767
13829
  var DEFAULT_DESKTOP_RELEASE_REPO = "Undertone0809/rudder";
13768
13830
  var DESKTOP_UPDATE_QUIT_ARG = "--rudder-update-quit";
13831
+ var DESKTOP_UPDATE_FORCE_ARG = "--rudder-update-force";
13769
13832
  var STABLE_SEMVER_RE = /^[0-9]+\.[0-9]+\.[0-9]+$/;
13770
13833
  var CANARY_SEMVER_RE = /^[0-9]+\.[0-9]+\.[0-9]+-canary\.[0-9]+$/;
13771
13834
  var CLI_REGISTRY_LATEST_URL = "https://registry.npmjs.org/@rudderhq%2fcli/latest";
@@ -13849,7 +13912,7 @@ function createDesktopProgressFactory() {
13849
13912
  async function waitForDesktopApplySignal() {
13850
13913
  process.stdin.setEncoding("utf8");
13851
13914
  process.stdin.resume();
13852
- await new Promise((resolve, reject) => {
13915
+ return await new Promise((resolve, reject) => {
13853
13916
  let buffer = "";
13854
13917
  const cleanup = () => {
13855
13918
  process.stdin.off("data", onData);
@@ -13860,9 +13923,15 @@ async function waitForDesktopApplySignal() {
13860
13923
  buffer += chunk;
13861
13924
  const lines = buffer.split(/\r?\n/);
13862
13925
  buffer = lines.pop() ?? "";
13863
- if (lines.some((line) => line.trim() === "apply")) {
13926
+ const commands = lines.map((line) => line.trim());
13927
+ if (commands.includes("force-apply")) {
13928
+ cleanup();
13929
+ resolve({ force: true });
13930
+ return;
13931
+ }
13932
+ if (commands.includes("apply")) {
13864
13933
  cleanup();
13865
- resolve();
13934
+ resolve({ force: false });
13866
13935
  }
13867
13936
  };
13868
13937
  const onEnd = () => {
@@ -14575,14 +14644,6 @@ function isInstalledDesktopCurrent(metadata, releaseTag, assetName, assetChecksu
14575
14644
  metadata && metadata.releaseTag === releaseTag && metadata.assetName === assetName && metadata.assetChecksum === assetChecksum
14576
14645
  );
14577
14646
  }
14578
- function buildForceQuitCommand(target) {
14579
- if (target.platform === "windows") return { command: "taskkill.exe", args: ["/IM", `${DESKTOP_APP_NAME}.exe`, "/T", "/F"] };
14580
- return { command: "pkill", args: ["-x", DESKTOP_APP_NAME] };
14581
- }
14582
- function forceQuitDesktopProcesses(target) {
14583
- const command = buildForceQuitCommand(target);
14584
- spawnSync3(command.command, command.args, { stdio: "ignore" });
14585
- }
14586
14647
  function forceQuitDesktopProcess(pid, target) {
14587
14648
  if (target.platform === "windows") {
14588
14649
  spawnSync3("taskkill.exe", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore" });
@@ -14593,8 +14654,35 @@ function forceQuitDesktopProcess(pid, target) {
14593
14654
  } catch {
14594
14655
  }
14595
14656
  }
14596
- function isRunningInsideDesktopExecutable() {
14597
- return path21.basename(process.execPath).toLowerCase().startsWith(DESKTOP_APP_NAME.toLowerCase());
14657
+ function quotePowerShellString(value) {
14658
+ return `'${value.replaceAll("'", "''")}'`;
14659
+ }
14660
+ function findDesktopExecutablePids(executablePath, target) {
14661
+ if (target.platform === "windows") {
14662
+ const result2 = spawnSync3("powershell.exe", [
14663
+ "-NoProfile",
14664
+ "-Command",
14665
+ `Get-CimInstance Win32_Process | Where-Object { $_.ExecutablePath -eq ${quotePowerShellString(executablePath)} } | Select-Object -ExpandProperty ProcessId`
14666
+ ], {
14667
+ encoding: "utf8",
14668
+ stdio: ["ignore", "pipe", "ignore"]
14669
+ });
14670
+ if (result2.status !== 0) return [];
14671
+ return result2.stdout.split(/\r?\n/).map((line) => Number.parseInt(line.trim(), 10)).filter((pid) => Number.isInteger(pid) && pid > 0 && pid !== process.pid);
14672
+ }
14673
+ const result = spawnSync3("ps", ["-eo", "pid=,args="], {
14674
+ encoding: "utf8",
14675
+ stdio: ["ignore", "pipe", "ignore"]
14676
+ });
14677
+ if (result.status !== 0) return [];
14678
+ return result.stdout.split(/\r?\n/).flatMap((line) => {
14679
+ const match = line.match(/^\s*(\d+)\s+(.+)$/);
14680
+ if (!match) return [];
14681
+ const pid = Number.parseInt(match[1], 10);
14682
+ const commandLine = match[2];
14683
+ const matchesExecutable = commandLine === executablePath || commandLine.startsWith(`${executablePath} `);
14684
+ return matchesExecutable && pid !== process.pid ? [pid] : [];
14685
+ });
14598
14686
  }
14599
14687
  async function waitForUpdateQuitResponse(responsePath, timeoutMs = 8e3) {
14600
14688
  const startedAt = Date.now();
@@ -14606,10 +14694,13 @@ async function waitForUpdateQuitResponse(responsePath, timeoutMs = 8e3) {
14606
14694
  }
14607
14695
  return null;
14608
14696
  }
14609
- async function requestDesktopQuit(executablePath, target) {
14697
+ async function requestDesktopQuit(executablePath, target, options = {}) {
14610
14698
  if (!await pathExists2(executablePath)) return { ok: true, status: "not_running" };
14611
14699
  const responsePath = path21.join(tmpdir(), `rudder-update-quit-${process.pid}-${Date.now()}.json`);
14612
- const result = spawnSync3(executablePath, [`${DESKTOP_UPDATE_QUIT_ARG}=${responsePath}`], {
14700
+ const result = spawnSync3(executablePath, [
14701
+ `${DESKTOP_UPDATE_QUIT_ARG}=${responsePath}`,
14702
+ ...options.forceUpdate ? [DESKTOP_UPDATE_FORCE_ARG] : []
14703
+ ], {
14613
14704
  stdio: "ignore",
14614
14705
  timeout: 5e3
14615
14706
  });
@@ -14617,7 +14708,7 @@ async function requestDesktopQuit(executablePath, target) {
14617
14708
  return null;
14618
14709
  }
14619
14710
  try {
14620
- return await waitForUpdateQuitResponse(responsePath);
14711
+ return await waitForUpdateQuitResponse(responsePath, options.responseTimeoutMs);
14621
14712
  } finally {
14622
14713
  await rm2(responsePath, { force: true });
14623
14714
  }
@@ -14646,6 +14737,12 @@ async function waitForProcessExit(pid, timeoutMs = 2e4, intervalMs = 250) {
14646
14737
  }
14647
14738
  return !processExists(pid);
14648
14739
  }
14740
+ async function waitForProcessesExit(pids, waitForExit) {
14741
+ const uniquePids = [...new Set(pids)];
14742
+ if (uniquePids.length === 0) return true;
14743
+ const results = await Promise.all(uniquePids.map((pid) => waitForExit(pid)));
14744
+ return results.every(Boolean);
14745
+ }
14649
14746
  async function removePathWithRetry(targetPath, attempts = 5) {
14650
14747
  for (let attempt = 0; attempt < attempts; attempt += 1) {
14651
14748
  try {
@@ -14658,50 +14755,98 @@ async function removePathWithRetry(targetPath, attempts = 5) {
14658
14755
  return false;
14659
14756
  }
14660
14757
  async function prepareForDesktopReplace(paths, target, options = {}) {
14661
- const forceQuit = options.forceQuitDesktopProcesses ?? forceQuitDesktopProcesses;
14662
14758
  const forceQuitPid = options.forceQuitDesktopProcess ?? forceQuitDesktopProcess;
14663
14759
  const waitForExit = options.waitForDesktopProcessExit ?? waitForProcessExit;
14760
+ const findPids = options.findDesktopExecutablePids ?? findDesktopExecutablePids;
14761
+ async function forceQuitPidAndConfirm(pid) {
14762
+ forceQuitPid(pid, target);
14763
+ await delay2(options.updateQuitForceDelayMs ?? UPDATE_QUIT_FORCE_DELAY_MS);
14764
+ if (!await waitForExit(pid)) {
14765
+ throw new Error(`Rudder Desktop process ${pid} did not exit after force-quit fallback. Close Rudder and rerun start.`);
14766
+ }
14767
+ }
14768
+ async function forceQuitPidsAndConfirm(pids) {
14769
+ const uniquePids = [...new Set(pids)];
14770
+ for (const pid of uniquePids) {
14771
+ forceQuitPid(pid, target);
14772
+ }
14773
+ await delay2(options.updateQuitForceDelayMs ?? UPDATE_QUIT_FORCE_DELAY_MS);
14774
+ if (!await waitForProcessesExit(uniquePids, waitForExit)) {
14775
+ throw new Error(`Rudder Desktop process${uniquePids.length === 1 ? "" : "es"} ${uniquePids.join(", ")} did not exit after force-quit fallback. Close Rudder and rerun start.`);
14776
+ }
14777
+ }
14778
+ let quitPid = null;
14779
+ let managedExecutablePids = [];
14664
14780
  const hasManagedExecutable = await pathExists2(paths.executablePath);
14665
14781
  if (hasManagedExecutable) {
14666
- let quitResponse = await requestDesktopQuit(paths.executablePath, target);
14667
- while (quitResponse && !quitResponse.ok && quitResponse.status === "active_runs" && options.waitForActiveRuns) {
14782
+ managedExecutablePids = findPids(paths.executablePath, target);
14783
+ const requestQuit = () => requestDesktopQuit(paths.executablePath, target, {
14784
+ forceUpdate: options.forceUpdate,
14785
+ responseTimeoutMs: options.updateQuitResponseTimeoutMs
14786
+ });
14787
+ let quitResponse = await requestQuit();
14788
+ while (quitResponse && !quitResponse.ok && quitResponse.status === "active_runs" && options.waitForActiveRuns && !options.forceUpdate) {
14668
14789
  p15.log.warn(
14669
14790
  `Rudder Desktop has ${quitResponse.totalRuns} active run${quitResponse.totalRuns === 1 ? "" : "s"}; waiting before replacing Desktop.`
14670
14791
  );
14671
14792
  await delay2(options.activeRunPollIntervalMs ?? 15e3);
14672
- quitResponse = await requestDesktopQuit(paths.executablePath, target);
14793
+ quitResponse = await requestQuit();
14673
14794
  }
14674
14795
  if (quitResponse && !quitResponse.ok && quitResponse.status === "active_runs") {
14796
+ if (!options.forceUpdate) {
14797
+ throw new Error(
14798
+ `Rudder Desktop has ${quitResponse.totalRuns} active run${quitResponse.totalRuns === 1 ? "" : "s"}. Stop active work, then rerun start.`
14799
+ );
14800
+ }
14675
14801
  throw new Error(
14676
- `Rudder Desktop has ${quitResponse.totalRuns} active run${quitResponse.totalRuns === 1 ? "" : "s"}. Stop active work, then rerun start.`
14802
+ `Rudder Desktop still has ${quitResponse.totalRuns} active run${quitResponse.totalRuns === 1 ? "" : "s"} after the force-update request. Stop active work, then rerun start.`
14677
14803
  );
14678
14804
  }
14679
- const quitPid = readUpdateQuitPid(quitResponse);
14805
+ if (quitResponse && !quitResponse.ok && quitResponse.status === "failed") {
14806
+ throw new Error(quitResponse.message);
14807
+ }
14808
+ quitPid = readUpdateQuitPid(quitResponse);
14680
14809
  if (quitPid) {
14681
14810
  p15.log.info(`Waiting for existing Rudder Desktop process ${quitPid} to exit before replacing it.`);
14682
14811
  if (!await waitForExit(quitPid)) {
14683
14812
  p15.log.warn(`Rudder Desktop process ${quitPid} did not exit in time; attempting force-quit fallback.`);
14684
- forceQuitPid(quitPid, target);
14685
- await delay2(options.updateQuitForceDelayMs ?? UPDATE_QUIT_FORCE_DELAY_MS);
14813
+ await forceQuitPidAndConfirm(quitPid);
14686
14814
  }
14687
14815
  } else if (isLegacyUnconfirmedUpdateQuit(quitResponse)) {
14688
14816
  const graceMs = options.legacyUpdateQuitGraceMs ?? LEGACY_UPDATE_QUIT_GRACE_MS;
14689
14817
  p15.log.warn(
14690
- `Existing Rudder Desktop acknowledged update quit without a process id; waiting ${Math.ceil(graceMs / 1e3)}s before force-quit fallback.`
14818
+ `Existing Rudder Desktop acknowledged update quit without a process id; waiting ${Math.ceil(graceMs / 1e3)}s before replacement.`
14691
14819
  );
14692
14820
  await delay2(graceMs);
14693
- forceQuit(target);
14694
- await delay2(options.updateQuitForceDelayMs ?? UPDATE_QUIT_FORCE_DELAY_MS);
14821
+ if (managedExecutablePids.length > 0 && !await waitForProcessesExit(managedExecutablePids, waitForExit)) {
14822
+ p15.log.warn(
14823
+ `Existing Rudder Desktop did not exit after acknowledging update quit; attempting path-scoped force-quit for process${managedExecutablePids.length === 1 ? "" : "es"} ${managedExecutablePids.join(", ")}.`
14824
+ );
14825
+ await forceQuitPidsAndConfirm(managedExecutablePids);
14826
+ }
14827
+ } else if (!quitResponse) {
14828
+ if (options.forceUpdate && managedExecutablePids.length > 0) {
14829
+ p15.log.warn(
14830
+ `Existing Rudder Desktop did not respond to the update quit request; attempting path-scoped force-quit for process${managedExecutablePids.length === 1 ? "" : "es"} ${managedExecutablePids.join(", ")}.`
14831
+ );
14832
+ await forceQuitPidsAndConfirm(managedExecutablePids);
14833
+ } else {
14834
+ throw new Error("Existing Rudder Desktop did not respond to the update quit request. Close Rudder and rerun start.");
14835
+ }
14695
14836
  } else {
14696
14837
  await delay2(options.updateQuitForceDelayMs ?? UPDATE_QUIT_FORCE_DELAY_MS);
14697
14838
  }
14698
- } else if (!isRunningInsideDesktopExecutable()) {
14699
- forceQuit(target);
14700
14839
  }
14701
14840
  const replacePath = target.platform === "windows" ? paths.installRoot : paths.appPath;
14702
14841
  if (await removePathWithRetry(replacePath)) return;
14703
- forceQuit(target);
14704
- await delay2(options.updateQuitForceDelayMs ?? UPDATE_QUIT_FORCE_DELAY_MS);
14842
+ if (!quitPid) {
14843
+ if (managedExecutablePids.length > 0) {
14844
+ await forceQuitPidsAndConfirm(managedExecutablePids);
14845
+ if (await removePathWithRetry(replacePath, 6)) return;
14846
+ }
14847
+ throw new Error(`Failed to replace existing Rudder Desktop at ${replacePath}. Close Rudder and rerun start.`);
14848
+ }
14849
+ await forceQuitPidAndConfirm(quitPid);
14705
14850
  if (await removePathWithRetry(replacePath, 6)) return;
14706
14851
  throw new Error(`Failed to replace existing Rudder Desktop at ${replacePath}. Close Rudder and rerun start.`);
14707
14852
  }
@@ -15034,22 +15179,26 @@ async function startCommand(opts) {
15034
15179
  () => assertChecksumMatch(cachedAsset.path, expectedChecksum),
15035
15180
  desktopProgressJson ? "verifying_checksum" : null
15036
15181
  );
15182
+ let applySignal = null;
15037
15183
  if (desktopProgressJson && opts.desktopWaitForApply === true) {
15038
15184
  writeDesktopProgress({
15039
15185
  phase: "ready_to_install",
15040
15186
  message: "Desktop update is downloaded and verified.",
15041
15187
  percent: 100
15042
15188
  });
15043
- await waitForDesktopApplySignal();
15189
+ applySignal = await waitForDesktopApplySignal();
15044
15190
  writeDesktopProgress({
15045
15191
  phase: "preparing_restart",
15046
- message: "Applying Desktop update..."
15192
+ message: applySignal.force ? "Applying Desktop update and quitting active runs..." : "Applying Desktop update..."
15047
15193
  });
15048
15194
  }
15049
15195
  await runStartPhase(
15050
15196
  "Replacing existing Rudder Desktop if needed...",
15051
15197
  "Existing Desktop install is ready for replacement.",
15052
- () => prepareForDesktopReplace(installPaths, target, { waitForActiveRuns: opts.waitForActiveRuns === true }),
15198
+ () => prepareForDesktopReplace(installPaths, target, {
15199
+ waitForActiveRuns: opts.waitForActiveRuns === true,
15200
+ forceUpdate: applySignal?.force === true
15201
+ }),
15053
15202
  desktopProgressJson ? opts.waitForActiveRuns === true ? "waiting_for_active_runs" : "preparing_restart" : null
15054
15203
  );
15055
15204
  await runStartPhase(