@rudderhq/server 0.7.4 → 0.7.6

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.
Files changed (136) hide show
  1. package/dist/agent-runtimes/index.d.ts +1 -1
  2. package/dist/agent-runtimes/index.d.ts.map +1 -1
  3. package/dist/agent-runtimes/types.d.ts +1 -1
  4. package/dist/agent-runtimes/types.d.ts.map +1 -1
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +8 -1
  7. package/dist/index.js.map +1 -1
  8. package/dist/routes/chats.d.ts.map +1 -1
  9. package/dist/routes/chats.js +2 -4
  10. package/dist/routes/chats.js.map +1 -1
  11. package/dist/routes/orgs.d.ts.map +1 -1
  12. package/dist/routes/orgs.js +5 -0
  13. package/dist/routes/orgs.js.map +1 -1
  14. package/dist/services/index.d.ts +1 -1
  15. package/dist/services/index.d.ts.map +1 -1
  16. package/dist/services/index.js +1 -1
  17. package/dist/services/index.js.map +1 -1
  18. package/dist/services/rudder-plugins.d.ts.map +1 -1
  19. package/dist/services/rudder-plugins.js +1 -0
  20. package/dist/services/rudder-plugins.js.map +1 -1
  21. package/dist/services/rudder-plugins.test.js +10 -0
  22. package/dist/services/rudder-plugins.test.js.map +1 -1
  23. package/dist/services/runtime-kernel/assignment-run-guardrail.d.ts +65 -0
  24. package/dist/services/runtime-kernel/assignment-run-guardrail.d.ts.map +1 -0
  25. package/dist/services/runtime-kernel/assignment-run-guardrail.js +204 -0
  26. package/dist/services/runtime-kernel/assignment-run-guardrail.js.map +1 -0
  27. package/dist/services/runtime-kernel/assignment-run-guardrail.test.d.ts +2 -0
  28. package/dist/services/runtime-kernel/assignment-run-guardrail.test.d.ts.map +1 -0
  29. package/dist/services/runtime-kernel/assignment-run-guardrail.test.js +114 -0
  30. package/dist/services/runtime-kernel/assignment-run-guardrail.test.js.map +1 -0
  31. package/dist/services/runtime-kernel/heartbeat.execute.d.ts.map +1 -1
  32. package/dist/services/runtime-kernel/heartbeat.execute.js +117 -2
  33. package/dist/services/runtime-kernel/heartbeat.execute.js.map +1 -1
  34. package/dist/services/runtime-kernel/heartbeat.recovery.d.ts +1 -0
  35. package/dist/services/runtime-kernel/heartbeat.recovery.d.ts.map +1 -1
  36. package/dist/services/runtime-kernel/heartbeat.recovery.js +1 -0
  37. package/dist/services/runtime-kernel/heartbeat.recovery.js.map +1 -1
  38. package/dist/services/side-chats.d.ts +0 -2
  39. package/dist/services/side-chats.d.ts.map +1 -1
  40. package/dist/services/side-chats.js +4 -12
  41. package/dist/services/side-chats.js.map +1 -1
  42. package/dist/services/workspace-backup-v2.d.ts +127 -0
  43. package/dist/services/workspace-backup-v2.d.ts.map +1 -0
  44. package/dist/services/workspace-backup-v2.js +964 -0
  45. package/dist/services/workspace-backup-v2.js.map +1 -0
  46. package/dist/services/workspace-backup-v2.test.d.ts +2 -0
  47. package/dist/services/workspace-backup-v2.test.d.ts.map +1 -0
  48. package/dist/services/workspace-backup-v2.test.js +318 -0
  49. package/dist/services/workspace-backup-v2.test.js.map +1 -0
  50. package/dist/services/workspace-backups.d.ts +46 -1
  51. package/dist/services/workspace-backups.d.ts.map +1 -1
  52. package/dist/services/workspace-backups.js +579 -60
  53. package/dist/services/workspace-backups.js.map +1 -1
  54. package/package.json +14 -14
  55. package/ui-dist/assets/{LibraryLiveSurface-D4uCo0l0.js → LibraryLiveSurface-nSMExVEC.js} +1 -1
  56. package/ui-dist/assets/{abnfDiagram-VRR7QNED-FF2qcR6A.js → abnfDiagram-VRR7QNED-Av8TM585.js} +1 -1
  57. package/ui-dist/assets/{addon-fit-4gL7JXzc.js → addon-fit-DzFhQGnx.js} +1 -1
  58. package/ui-dist/assets/{arc-D5pLjh6B.js → arc-Bc-Gf4Fc.js} +1 -1
  59. package/ui-dist/assets/{architectureDiagram-ZJ3FMSHR-BvqY-HXg.js → architectureDiagram-ZJ3FMSHR-BOph0PHz.js} +1 -1
  60. package/ui-dist/assets/{blockDiagram-677ZJIJ3-BU6ZbJ0s.js → blockDiagram-677ZJIJ3-BCUhdmf3.js} +1 -1
  61. package/ui-dist/assets/{c4Diagram-LMCZKHZV-Cl5Gsovj.js → c4Diagram-LMCZKHZV-B_3pH6bx.js} +1 -1
  62. package/ui-dist/assets/channel-CyoUWdeD.js +1 -0
  63. package/ui-dist/assets/{chunk-2Q5K7J3B-4a2agt_p.js → chunk-2Q5K7J3B-C4gdcZxO.js} +1 -1
  64. package/ui-dist/assets/{chunk-32BRIVSS-CF0oOO2T.js → chunk-32BRIVSS-JxQV72by.js} +1 -1
  65. package/ui-dist/assets/{chunk-5VM5RSS4-CsSq2zX2.js → chunk-5VM5RSS4-f0zO1uV_.js} +1 -1
  66. package/ui-dist/assets/{chunk-EX3LRPZG-B6riETVZ.js → chunk-EX3LRPZG-Bbn2Dpmg.js} +1 -1
  67. package/ui-dist/assets/{chunk-JWPE2WC7-S-p1xu0r.js → chunk-JWPE2WC7-B118_FhP.js} +1 -1
  68. package/ui-dist/assets/{chunk-MOJQB5TN-mVE4v_LV.js → chunk-MOJQB5TN-CEcGkJ3p.js} +1 -1
  69. package/ui-dist/assets/{chunk-RYQCIY6F-CElbgpgs.js → chunk-RYQCIY6F-C-WY_ozP.js} +1 -1
  70. package/ui-dist/assets/{chunk-V7JOEXUC-8XM3povP.js → chunk-V7JOEXUC-DS5sjH7p.js} +1 -1
  71. package/ui-dist/assets/{chunk-VR4S4FIN-LrThp3ht.js → chunk-VR4S4FIN-COyRk9XW.js} +1 -1
  72. package/ui-dist/assets/{chunk-XXDRQBXY-D38vLb4t.js → chunk-XXDRQBXY-Cd2T_1Uf.js} +1 -1
  73. package/ui-dist/assets/classDiagram-OUVF2IWQ-BETmcliY.js +1 -0
  74. package/ui-dist/assets/classDiagram-v2-EOCWNBFH-BETmcliY.js +1 -0
  75. package/ui-dist/assets/{cose-bilkent-JH36ORCC-CmpZMaDV.js → cose-bilkent-JH36ORCC-iEFFQ2c7.js} +1 -1
  76. package/ui-dist/assets/{cynefin-VYW2F7L2-D3RnbBvI.js → cynefin-VYW2F7L2-Bp-sv4UP.js} +1 -1
  77. package/ui-dist/assets/{cynefinDiagram-TSTJHNR4-DZTcUojp.js → cynefinDiagram-TSTJHNR4-CET_eOH5.js} +1 -1
  78. package/ui-dist/assets/{dagre-VKFMJZFB-6jXSDi0S.js → dagre-VKFMJZFB-BkxxZr0z.js} +1 -1
  79. package/ui-dist/assets/{diagram-FQU43EPY-DIMm3mfS.js → diagram-FQU43EPY-2b0kz8hj.js} +1 -1
  80. package/ui-dist/assets/{diagram-G47NLZAW-Cyo22v0_.js → diagram-G47NLZAW-CWgvA-UY.js} +1 -1
  81. package/ui-dist/assets/{diagram-NH7WQ7WH-CHDV0nSL.js → diagram-NH7WQ7WH-DKoSLHQw.js} +1 -1
  82. package/ui-dist/assets/{diagram-OA4YK3LP-Jijx9vQO.js → diagram-OA4YK3LP-BtpJ7ObO.js} +1 -1
  83. package/ui-dist/assets/{diagram-WEI45ONY-CcL19HLE.js → diagram-WEI45ONY-cTRv44yL.js} +1 -1
  84. package/ui-dist/assets/{ebnfDiagram-CCIWWBDH-D94h-RFQ.js → ebnfDiagram-CCIWWBDH-BMwUwEZM.js} +1 -1
  85. package/ui-dist/assets/{erDiagram-Q63AITRT-B3ypUGZX.js → erDiagram-Q63AITRT-B9qW6I5c.js} +1 -1
  86. package/ui-dist/assets/{flowDiagram-23GEKE2U-DjCT6Y1o.js → flowDiagram-23GEKE2U-Cb1rJFcp.js} +1 -1
  87. package/ui-dist/assets/{ganttDiagram-NO4QXBWP-C3QVhTc9.js → ganttDiagram-NO4QXBWP-CiicdHPl.js} +1 -1
  88. package/ui-dist/assets/{gitGraphDiagram-IHSO6WYX-D0trBzU5.js → gitGraphDiagram-IHSO6WYX-Cge-AgEB.js} +1 -1
  89. package/ui-dist/assets/{graph-D1zFmVUP.js → graph-0wCGCEs4.js} +1 -1
  90. package/ui-dist/assets/{index-Bk_yesiO.js → index-5dD5l_7S.js} +1 -1
  91. package/ui-dist/assets/{index-BwutQLG1.js → index-BOnG5igl.js} +1 -1
  92. package/ui-dist/assets/{index-CiCRRUVV.js → index-BXR0UEnQ.js} +1 -1
  93. package/ui-dist/assets/{index-CB4zr_Ku.js → index-B_c6Qzui.js} +1 -1
  94. package/ui-dist/assets/{index-CFWOO6yn.js → index-BhIqb_sb.js} +1 -1
  95. package/ui-dist/assets/{index-BFktZ2tu.js → index-BjGW8ROf.js} +1 -1
  96. package/ui-dist/assets/{index-B0GEsWui.js → index-BqpG2FnL.js} +555 -555
  97. package/ui-dist/assets/{index-D8JG-IU9.js → index-C3ghnZSF.js} +1 -1
  98. package/ui-dist/assets/{index-DKCiVvJo.js → index-CB9X8t3F.js} +1 -1
  99. package/ui-dist/assets/{index-or2C22bw.js → index-CcDlhtvT.js} +1 -1
  100. package/ui-dist/assets/{index-CRolpP90.js → index-D1w6UIRX.js} +1 -1
  101. package/ui-dist/assets/{index-G2yfKEf_.js → index-DN9Yo10m.js} +1 -1
  102. package/ui-dist/assets/{index-CK8u9b07.js → index-DP30MjES.js} +1 -1
  103. package/ui-dist/assets/{index-B8bxQLfN.js → index-DXRvkZMv.js} +1 -1
  104. package/ui-dist/assets/{index-CC89UPa-.js → index-Dy-AXx6E.js} +1 -1
  105. package/ui-dist/assets/{infoDiagram-FWYZ7A6U-Co0nkcV4.js → infoDiagram-FWYZ7A6U-R2pgAXHR.js} +1 -1
  106. package/ui-dist/assets/{ishikawaDiagram-FXEZZL3T-CkIg1Jdu.js → ishikawaDiagram-FXEZZL3T-BJivveWk.js} +1 -1
  107. package/ui-dist/assets/{journeyDiagram-5HDEW3XC-AYUT6JuJ.js → journeyDiagram-5HDEW3XC-CLlN_hss.js} +1 -1
  108. package/ui-dist/assets/{kanban-definition-HUTT4EX6-C3H2XW08.js → kanban-definition-HUTT4EX6-CCRtDa5s.js} +1 -1
  109. package/ui-dist/assets/{layout-sZWyqNOu.js → layout-BgygArKO.js} +1 -1
  110. package/ui-dist/assets/{linear-BLTYou8N.js → linear-ZTGN1Bax.js} +1 -1
  111. package/ui-dist/assets/{map-zKBdHkX8.js → map-BheoFUge.js} +1 -1
  112. package/ui-dist/assets/{mermaid.core-DbjdFip8.js → mermaid.core-D4HYOaQr.js} +4 -4
  113. package/ui-dist/assets/{mindmap-definition-LN4V7U3C-DcDNQ4GQ.js → mindmap-definition-LN4V7U3C-B25TPfzP.js} +1 -1
  114. package/ui-dist/assets/{pegDiagram-2B236MQR-BGq1PngU.js → pegDiagram-2B236MQR-CWrV5tQE.js} +1 -1
  115. package/ui-dist/assets/{pieDiagram-ENE6RG2P-BfXWRzNb.js → pieDiagram-ENE6RG2P-BQTq4Jp6.js} +1 -1
  116. package/ui-dist/assets/{quadrantDiagram-ABIIQ3AL-AYMVAbo1.js → quadrantDiagram-ABIIQ3AL-C5TwZIzz.js} +1 -1
  117. package/ui-dist/assets/{railroadDiagram-RFXS5EU6-B0PoG0Ih.js → railroadDiagram-RFXS5EU6--wv7_omb.js} +1 -1
  118. package/ui-dist/assets/{requirementDiagram-TGXJPOKE-Cuuu9wfw.js → requirementDiagram-TGXJPOKE-D80O_sgV.js} +1 -1
  119. package/ui-dist/assets/{sankeyDiagram-HTMAVEWB-BceAc42f.js → sankeyDiagram-HTMAVEWB-Cz0SmDPj.js} +1 -1
  120. package/ui-dist/assets/{sequenceDiagram-DBY2YBRQ-cqJ71-Rw.js → sequenceDiagram-DBY2YBRQ-jmLYUOQ2.js} +1 -1
  121. package/ui-dist/assets/{sizeCapture-X5ZJPWSS-DQ6MibbA.js → sizeCapture-X5ZJPWSS-C1FqwoMN.js} +1 -1
  122. package/ui-dist/assets/{stateDiagram-2N3HPSRC-Bdl-XY7t.js → stateDiagram-2N3HPSRC-CZa7Dj75.js} +1 -1
  123. package/ui-dist/assets/stateDiagram-v2-6OUMAXLB-CEUECJmS.js +1 -0
  124. package/ui-dist/assets/{swimlanes-5IMT3BWC-Dpo2HDtE.js → swimlanes-5IMT3BWC-CbHndCqy.js} +2 -2
  125. package/ui-dist/assets/swimlanesDiagram-G3AALYLV-4TgYo_NT.js +8 -0
  126. package/ui-dist/assets/{timeline-definition-FHXFAJF6-BzmJ-xnC.js → timeline-definition-FHXFAJF6-CFOg8vuA.js} +1 -1
  127. package/ui-dist/assets/{vennDiagram-L72KCM5P-BF2EI7vn.js → vennDiagram-L72KCM5P-1dSr5CoN.js} +1 -1
  128. package/ui-dist/assets/{wardleyDiagram-EHGQE667-DM65x1i1.js → wardleyDiagram-EHGQE667-CAMneCxP.js} +1 -1
  129. package/ui-dist/assets/{xterm-DZP7bLZ5.js → xterm-M5ke8gUF.js} +1 -1
  130. package/ui-dist/assets/{xychartDiagram-FW5EYKEG-3Q2t9pdU.js → xychartDiagram-FW5EYKEG-DxVyl1x4.js} +1 -1
  131. package/ui-dist/index.html +1 -1
  132. package/ui-dist/assets/channel-HcmprA3I.js +0 -1
  133. package/ui-dist/assets/classDiagram-OUVF2IWQ-Dpe8LaLf.js +0 -1
  134. package/ui-dist/assets/classDiagram-v2-EOCWNBFH-Dpe8LaLf.js +0 -1
  135. package/ui-dist/assets/stateDiagram-v2-6OUMAXLB-Cjj7yPIO.js +0 -1
  136. package/ui-dist/assets/swimlanesDiagram-G3AALYLV-CPmIkNCu.js +0 -8
@@ -0,0 +1,204 @@
1
+ import { execFile } from "node:child_process";
2
+ import fs from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { promisify } from "node:util";
5
+ export const ASSIGNMENT_RUN_CONSECUTIVE_FAILURE_LIMIT = 3;
6
+ export const ASSIGNMENT_RUN_TOTAL_FAILURE_LIMIT = 25;
7
+ const execFileAsync = promisify(execFile);
8
+ export function resolveProjectWorkingSetCwd(resources) {
9
+ const workingSet = resources.find((entry) => entry.role === "working_set"
10
+ && entry.resource?.kind === "directory"
11
+ && entry.resource.sourceType === "external"
12
+ && typeof entry.resource.locator === "string"
13
+ && path.isAbsolute(entry.resource.locator));
14
+ return workingSet?.resource?.locator?.trim() || null;
15
+ }
16
+ function compactFailureText(value) {
17
+ return value
18
+ .replace(/\x1b\[[0-9;]*m/g, "")
19
+ .replace(/\b[0-9a-f]{8}-[0-9a-f-]{27,}\b/gi, "<uuid>")
20
+ .replace(/\b\d{4}-\d{2}-\d{2}T\S+\b/g, "<timestamp>")
21
+ .replace(/\/[^\s:'\"]+/g, "<path>")
22
+ .replace(/\b\d+\b/g, "<n>")
23
+ .replace(/\s+/g, " ")
24
+ .trim()
25
+ .toLowerCase();
26
+ }
27
+ function commandIdentity(entry, toolUseId) {
28
+ if (!entry)
29
+ return `tool-use:${toolUseId}`;
30
+ return compactFailureText(JSON.stringify(entry.input)).slice(0, 500);
31
+ }
32
+ export function fingerprintToolFailure(entry, call) {
33
+ return `${entry.toolName ?? call?.name ?? "unknown"}:${commandIdentity(call, entry.toolUseId)}:${compactFailureText(entry.content).slice(0, 500)}`;
34
+ }
35
+ function inferRecoveryCommand(entry) {
36
+ const content = entry.content.toLowerCase();
37
+ if (content.includes("node_modules") || content.includes("cannot find module") || content.includes("module not found")) {
38
+ return "pnpm install --frozen-lockfile";
39
+ }
40
+ if (content.includes("unexpected store") || content.includes("virtual store") || content.includes("store-dir")) {
41
+ return "pnpm install --force";
42
+ }
43
+ return null;
44
+ }
45
+ export function createAssignmentRunFailureBudget() {
46
+ let failureCount = 0;
47
+ let lastFingerprint = null;
48
+ let consecutiveFailureCount = 0;
49
+ let processedEntryCount = 0;
50
+ let checkpoint = null;
51
+ const callsById = new Map();
52
+ return {
53
+ observe(entries) {
54
+ if (checkpoint)
55
+ return checkpoint;
56
+ const nextEntries = entries.slice(processedEntryCount);
57
+ processedEntryCount = entries.length;
58
+ for (const entry of nextEntries) {
59
+ if (entry.kind === "tool_call" && entry.toolUseId) {
60
+ callsById.set(entry.toolUseId, entry);
61
+ continue;
62
+ }
63
+ if (entry.kind !== "tool_result")
64
+ continue;
65
+ if (!entry.isError) {
66
+ lastFingerprint = null;
67
+ consecutiveFailureCount = 0;
68
+ continue;
69
+ }
70
+ failureCount += 1;
71
+ const fingerprint = fingerprintToolFailure(entry, callsById.get(entry.toolUseId));
72
+ consecutiveFailureCount = fingerprint === lastFingerprint ? consecutiveFailureCount + 1 : 1;
73
+ lastFingerprint = fingerprint;
74
+ const reason = consecutiveFailureCount >= ASSIGNMENT_RUN_CONSECUTIVE_FAILURE_LIMIT
75
+ ? "repeated_failure"
76
+ : failureCount >= ASSIGNMENT_RUN_TOTAL_FAILURE_LIMIT
77
+ ? "total_failure_budget"
78
+ : null;
79
+ if (reason) {
80
+ checkpoint = {
81
+ reason,
82
+ failureCount,
83
+ consecutiveFailureCount,
84
+ fingerprint,
85
+ toolName: entry.toolName ?? "unknown",
86
+ unresolvedError: entry.content.slice(0, 2_000),
87
+ nextRecoveryCommand: inferRecoveryCommand(entry),
88
+ };
89
+ return checkpoint;
90
+ }
91
+ }
92
+ return null;
93
+ },
94
+ snapshot() {
95
+ return { failureCount, consecutiveFailureCount, checkpoint };
96
+ },
97
+ };
98
+ }
99
+ async function pathExists(candidate) {
100
+ return fs.access(candidate).then(() => true, () => false);
101
+ }
102
+ async function readText(candidate) {
103
+ return fs.readFile(candidate, "utf8").catch(() => "");
104
+ }
105
+ function parseJsonObject(contents) {
106
+ try {
107
+ const parsed = JSON.parse(contents);
108
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed)
109
+ ? parsed
110
+ : {};
111
+ }
112
+ catch {
113
+ return {};
114
+ }
115
+ }
116
+ function yamlScalar(contents, key) {
117
+ const match = contents.match(new RegExp(`^${key}:\\s*(.+?)\\s*$`, "m"));
118
+ return match?.[1]?.replace(/^['"]|['"]$/g, "").trim() || null;
119
+ }
120
+ async function runPreflightCommand(command, args, cwd) {
121
+ return execFileAsync(command, args, {
122
+ cwd,
123
+ timeout: 10_000,
124
+ maxBuffer: 512 * 1024,
125
+ env: { ...process.env, CI: "1" },
126
+ }).then(({ stdout }) => ({ ok: true, output: stdout.trim().slice(0, 500) }), (error) => ({
127
+ ok: false,
128
+ output: error instanceof Error ? error.message.slice(0, 500) : String(error).slice(0, 500),
129
+ }));
130
+ }
131
+ export async function inspectAssignmentRunWorkspace(input) {
132
+ const packageJsonPath = path.join(input.actualCwd, "package.json");
133
+ const pnpmLockPath = path.join(input.actualCwd, "pnpm-lock.yaml");
134
+ const virtualStorePath = path.join(input.actualCwd, "node_modules", ".pnpm");
135
+ const modulesManifestPath = path.join(input.actualCwd, "node_modules", ".modules.yaml");
136
+ const [cwdPresent, projectWorkingSetPresent, packageJsonPresent, pnpmLockPresent, nodeModulesPresent, pnpmVirtualStorePresent] = await Promise.all([
137
+ fs.stat(input.actualCwd).then((stat) => stat.isDirectory(), () => false),
138
+ fs.stat(input.projectWorkingSetCwd).then((stat) => stat.isDirectory(), () => false),
139
+ pathExists(packageJsonPath),
140
+ pathExists(pnpmLockPath),
141
+ pathExists(path.join(input.actualCwd, "node_modules")),
142
+ pathExists(virtualStorePath),
143
+ ]);
144
+ const packageJson = packageJsonPresent ? parseJsonObject(await readText(packageJsonPath)) : {};
145
+ const expectedPackageManager = typeof packageJson.packageManager === "string" ? packageJson.packageManager : null;
146
+ const modulesManifest = nodeModulesPresent ? await readText(modulesManifestPath) : "";
147
+ const installedPackageManager = yamlScalar(modulesManifest, "packageManager");
148
+ const configuredStoreDir = yamlScalar(modulesManifest, "storeDir");
149
+ const configuredVirtualStoreDir = yamlScalar(modulesManifest, "virtualStoreDir");
150
+ const nodeCommand = packageJsonPresent ? await runPreflightCommand("node", ["--version"], input.actualCwd) : null;
151
+ const pnpmCommand = pnpmLockPresent ? await runPreflightCommand("pnpm", ["--version"], input.actualCwd) : null;
152
+ const dependencyGraph = pnpmLockPresent && nodeModulesPresent && pnpmVirtualStorePresent
153
+ ? await runPreflightCommand("pnpm", ["list", "--depth", "-1", "--offline", "--json"], input.actualCwd)
154
+ : null;
155
+ const packageManagerMatches = !expectedPackageManager
156
+ || !installedPackageManager
157
+ || expectedPackageManager === installedPackageManager;
158
+ const storeDirPresent = !configuredStoreDir || await pathExists(path.isAbsolute(configuredStoreDir) ? configuredStoreDir : path.join(input.actualCwd, configuredStoreDir));
159
+ const virtualStoreMatches = !configuredVirtualStoreDir || configuredVirtualStoreDir === ".pnpm";
160
+ const ready = cwdPresent
161
+ && projectWorkingSetPresent
162
+ && (!packageJsonPresent || Boolean(nodeCommand?.ok))
163
+ && (!pnpmLockPresent || Boolean(pnpmCommand?.ok))
164
+ && (!packageJsonPresent || nodeModulesPresent)
165
+ && (!pnpmLockPresent || pnpmVirtualStorePresent)
166
+ && packageManagerMatches
167
+ && storeDirPresent
168
+ && virtualStoreMatches
169
+ && (!dependencyGraph || dependencyGraph.ok);
170
+ const recoveryCommand = ready
171
+ ? null
172
+ : pnpmLockPresent
173
+ ? (packageManagerMatches && storeDirPresent && virtualStoreMatches
174
+ ? "pnpm install --frozen-lockfile"
175
+ : "pnpm install --force")
176
+ : packageJsonPresent
177
+ ? "npm install"
178
+ : null;
179
+ return {
180
+ actualCwd: input.actualCwd,
181
+ projectWorkingSetCwd: input.projectWorkingSetCwd,
182
+ cwdPresent,
183
+ projectWorkingSetPresent,
184
+ cwdMatchesProjectWorkingSet: path.resolve(input.actualCwd) === path.resolve(input.projectWorkingSetCwd),
185
+ packageManager: pnpmLockPresent ? "pnpm" : packageJsonPresent ? "unknown" : "none",
186
+ packageJsonPresent,
187
+ pnpmLockPresent,
188
+ nodeModulesPresent,
189
+ pnpmVirtualStorePresent,
190
+ expectedPackageManager,
191
+ installedPackageManager,
192
+ configuredStoreDir,
193
+ configuredVirtualStoreDir,
194
+ packageManagerMatches,
195
+ storeDirPresent,
196
+ virtualStoreMatches,
197
+ nodeCommandAvailable: nodeCommand?.ok ?? null,
198
+ pnpmCommandAvailable: pnpmCommand?.ok ?? null,
199
+ dependencyGraphAvailable: dependencyGraph?.ok ?? null,
200
+ ready,
201
+ recoveryCommand,
202
+ };
203
+ }
204
+ //# sourceMappingURL=assignment-run-guardrail.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assignment-run-guardrail.js","sourceRoot":"","sources":["../../../src/services/runtime-kernel/assignment-run-guardrail.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=assignment-run-guardrail.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assignment-run-guardrail.test.d.ts","sourceRoot":"","sources":["../../../src/services/runtime-kernel/assignment-run-guardrail.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,114 @@
1
+ import fs from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { afterEach, describe, expect, it } from "vitest";
5
+ import { ASSIGNMENT_RUN_TOTAL_FAILURE_LIMIT, createAssignmentRunFailureBudget, fingerprintToolFailure, inspectAssignmentRunWorkspace, resolveProjectWorkingSetCwd, } from "./assignment-run-guardrail.js";
6
+ const tempDirs = [];
7
+ afterEach(async () => {
8
+ await Promise.all(tempDirs.splice(0).map((dir) => fs.rm(dir, { recursive: true, force: true })));
9
+ });
10
+ function failure(content, toolUseId = "tool-1", toolName = "exec_command") {
11
+ return {
12
+ kind: "tool_result",
13
+ ts: new Date().toISOString(),
14
+ toolUseId,
15
+ toolName,
16
+ content,
17
+ isError: true,
18
+ };
19
+ }
20
+ function call(command, toolUseId = "tool-1") {
21
+ return {
22
+ kind: "tool_call",
23
+ ts: new Date().toISOString(),
24
+ name: "exec_command",
25
+ toolUseId,
26
+ input: { cmd: command },
27
+ };
28
+ }
29
+ describe("assignment run guardrail", () => {
30
+ it("normalizes dynamic paths, timestamps, ids, and numbers in failure fingerprints", () => {
31
+ const first = failure("2026-08-13T01:02:03Z /tmp/run-123 failed with code 1");
32
+ const second = failure("2026-08-13T02:03:04Z /private/run-456 failed with code 2");
33
+ expect(fingerprintToolFailure(first, call("pnpm test", "tool-1"))).toBe(fingerprintToolFailure(second, call("pnpm test", "tool-2")));
34
+ });
35
+ it("checkpoints after the same failure fingerprint occurs three times", () => {
36
+ const budget = createAssignmentRunFailureBudget();
37
+ expect(budget.observe([call("pnpm test", "tool-1"), failure("Cannot find module /tmp/a", "tool-1")])).toBeNull();
38
+ expect(budget.observe([
39
+ call("pnpm test", "tool-1"),
40
+ failure("Cannot find module /tmp/a", "tool-1"),
41
+ call("pnpm test", "tool-2"),
42
+ failure("Cannot find module /tmp/b", "tool-2"),
43
+ ])).toBeNull();
44
+ expect(budget.observe([
45
+ call("pnpm test", "tool-1"),
46
+ failure("Cannot find module /tmp/a", "tool-1"),
47
+ call("pnpm test", "tool-2"),
48
+ failure("Cannot find module /tmp/b", "tool-2"),
49
+ call("pnpm test", "tool-3"),
50
+ failure("Cannot find module /tmp/c", "tool-3"),
51
+ ])).toMatchObject({
52
+ reason: "repeated_failure",
53
+ failureCount: 3,
54
+ consecutiveFailureCount: 3,
55
+ nextRecoveryCommand: "pnpm install --frozen-lockfile",
56
+ });
57
+ });
58
+ it("resets repeated failure streaks after a successful tool result", () => {
59
+ const budget = createAssignmentRunFailureBudget();
60
+ const entries = [
61
+ call("pnpm test", "tool-1"), failure("same error", "tool-1"),
62
+ call("pnpm test", "tool-ok"), { ...failure("ok", "tool-ok"), isError: false },
63
+ call("pnpm test", "tool-2"), failure("same error", "tool-2"),
64
+ call("pnpm test", "tool-3"), failure("same error", "tool-3"),
65
+ ];
66
+ expect(budget.observe(entries)).toBeNull();
67
+ expect(budget.snapshot()).toMatchObject({ consecutiveFailureCount: 2 });
68
+ });
69
+ it("does not combine identical errors from different commands", () => {
70
+ const budget = createAssignmentRunFailureBudget();
71
+ const entries = [
72
+ call("pnpm test", "tool-1"), failure("same error", "tool-1"),
73
+ call("pnpm typecheck", "tool-2"), failure("same error", "tool-2"),
74
+ call("pnpm test", "tool-3"), failure("same error", "tool-3"),
75
+ ];
76
+ expect(budget.observe(entries)).toBeNull();
77
+ expect(budget.snapshot()).toMatchObject({ consecutiveFailureCount: 1 });
78
+ });
79
+ it("checkpoints at the total failure budget when fingerprints vary", () => {
80
+ const budget = createAssignmentRunFailureBudget();
81
+ const entries = Array.from({ length: ASSIGNMENT_RUN_TOTAL_FAILURE_LIMIT }, (_, index) => [
82
+ call(`tool-${index}`, `tool-${index}`),
83
+ failure(`distinct failure marker-${String.fromCharCode(65 + index)} value`, `tool-${index}`, `tool-${index}`),
84
+ ]).flat();
85
+ expect(budget.observe(entries)).toMatchObject({
86
+ reason: "total_failure_budget",
87
+ failureCount: ASSIGNMENT_RUN_TOTAL_FAILURE_LIMIT,
88
+ });
89
+ });
90
+ it("reports workspace and package-manager readiness without mutating the repo", async () => {
91
+ const cwd = await fs.mkdtemp(path.join(os.tmpdir(), "assignment-preflight-"));
92
+ tempDirs.push(cwd);
93
+ await fs.writeFile(path.join(cwd, "package.json"), "{}", "utf8");
94
+ await fs.writeFile(path.join(cwd, "pnpm-lock.yaml"), "lockfileVersion: '9.0'", "utf8");
95
+ await expect(inspectAssignmentRunWorkspace({ actualCwd: cwd, projectWorkingSetCwd: cwd })).resolves.toMatchObject({
96
+ cwdMatchesProjectWorkingSet: true,
97
+ packageManager: "pnpm",
98
+ packageJsonPresent: true,
99
+ nodeModulesPresent: false,
100
+ recoveryCommand: "pnpm install --frozen-lockfile",
101
+ });
102
+ });
103
+ it("resolves only an external directory working set as the project repo root", () => {
104
+ expect(resolveProjectWorkingSetCwd([
105
+ { role: "reference", resource: { kind: "directory", sourceType: "external", locator: "/tmp/reference" } },
106
+ { role: "working_set", resource: { kind: "file", sourceType: "external", locator: "/tmp/readme.md" } },
107
+ { role: "working_set", resource: { kind: "directory", sourceType: "external", locator: "/tmp/repo" } },
108
+ ])).toBe("/tmp/repo");
109
+ expect(resolveProjectWorkingSetCwd([
110
+ { role: "working_set", resource: { kind: "directory", sourceType: "library", locator: "projects/rudder" } },
111
+ ])).toBeNull();
112
+ });
113
+ });
114
+ //# sourceMappingURL=assignment-run-guardrail.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assignment-run-guardrail.test.js","sourceRoot":"","sources":["../../../src/services/runtime-kernel/assignment-run-guardrail.test.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"heartbeat.execute.d.ts","sourceRoot":"","sources":["../../../src/services/runtime-kernel/heartbeat.execute.ts"],"names":[],"mappings":"AA0DA,OAAO,EAAE,0CAA0C,EAAE,KAAK,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAsCnH,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,GAAG;wBA2CxB,MAAM,SAAS;QAAE,iBAAiB,CAAC,EAAE,OAAO,CAAA;KAAE;EAwwChF"}
1
+ {"version":3,"file":"heartbeat.execute.d.ts","sourceRoot":"","sources":["../../../src/services/runtime-kernel/heartbeat.execute.ts"],"names":[],"mappings":"AAiEA,OAAO,EAAE,0CAA0C,EAAE,KAAK,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAsCnH,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,GAAG;wBA2CxB,MAAM,SAAS;QAAE,iBAAiB,CAAC,EAAE,OAAO,CAAA;KAAE;EA83ChF"}
@@ -11,7 +11,9 @@ import { buildExecutionWorkspaceAdapterConfig, issueExecutionWorkspaceModeForPer
11
11
  import { summarizeHeartbeatRunResultJson } from "../heartbeat-run-summary.js";
12
12
  import { publishLiveEvent } from "../live-events.js";
13
13
  import { isManagedWorkspaceConfigurationError, isWorkspacePermissionPreflightError, preflightManagedAgentWorkspace, } from "../managed-workspace-preflight.js";
14
+ import { listProjectResourceAttachments } from "../resource-catalog.js";
14
15
  import { buildWorkspaceReadyComment, cleanupExecutionWorkspaceArtifacts, ensureRuntimeServicesForRun, persistAdapterManagedRuntimeServices, realizeExecutionWorkspace, releaseRuntimeServicesForRun } from "../workspace-runtime.js";
16
+ import { createAssignmentRunFailureBudget, inspectAssignmentRunWorkspace, resolveProjectWorkingSetCwd, } from "./assignment-run-guardrail.js";
15
17
  import { executeAdapterWithModelFallbacks } from "./model-fallback.js";
16
18
  export { prioritizeProjectWorkspaceCandidatesForRun } from "../agent-run-context.js";
17
19
  import * as heartbeatCore from "./heartbeat.core.js";
@@ -196,6 +198,12 @@ export function createHeartbeatExecuteHandlers(context) {
196
198
  await ensureRuntimeState(agent);
197
199
  const context = parseObject(run.contextSnapshot);
198
200
  delete context.rudderGitIdentity;
201
+ const assignmentContinuationAttempt = Math.max(0, Math.floor(Number(context.assignmentGuardrailContinuationAttempt) || 0));
202
+ const assignmentGuardrailEnabled = run.invocationSource === "assignment"
203
+ || context.wakeSource === "assignment"
204
+ || assignmentContinuationAttempt > 0;
205
+ const assignmentFailureBudget = assignmentGuardrailEnabled ? createAssignmentRunFailureBudget() : null;
206
+ let assignmentGuardrailCheckpoint = null;
199
207
  const taskKey = deriveTaskKey(context, null);
200
208
  const sessionCodec = getAgentRuntimeSessionCodec(agent.agentRuntimeType);
201
209
  const issueId = readNonEmptyString(context.issueId);
@@ -290,7 +298,27 @@ export function createHeartbeatExecuteHandlers(context) {
290
298
  issueSettings: issueExecutionWorkspaceSettings,
291
299
  legacyUseProjectWorkspace: runtimeOverrides?.useProjectWorkspace ?? null,
292
300
  });
293
- const resolvedWorkspace = await runContextSvc.resolveWorkspaceForRun(agent, context, previousSessionParams, { useProjectWorkspace: executionWorkspaceMode !== "agent_default" });
301
+ let resolvedWorkspace = await runContextSvc.resolveWorkspaceForRun(agent, context, previousSessionParams, { useProjectWorkspace: executionWorkspaceMode !== "agent_default" });
302
+ let configuredProjectWorkingSetCwd = null;
303
+ if (assignmentGuardrailEnabled && executionProjectId) {
304
+ const projectResources = await listProjectResourceAttachments(db, agent.orgId, executionProjectId);
305
+ const projectWorkingSetCwd = resolveProjectWorkingSetCwd(projectResources);
306
+ configuredProjectWorkingSetCwd = projectWorkingSetCwd;
307
+ if (projectWorkingSetCwd) {
308
+ const workingSetAvailable = await inspectAssignmentRunWorkspace({
309
+ actualCwd: projectWorkingSetCwd,
310
+ projectWorkingSetCwd,
311
+ }).then((result) => result.cwdPresent);
312
+ if (workingSetAvailable) {
313
+ resolvedWorkspace = {
314
+ ...resolvedWorkspace,
315
+ cwd: projectWorkingSetCwd,
316
+ source: "project_primary",
317
+ projectId: executionProjectId,
318
+ };
319
+ }
320
+ }
321
+ }
294
322
  const workspaceManagedConfig = buildExecutionWorkspaceAdapterConfig({
295
323
  agentConfig: config,
296
324
  projectPolicy: projectExecutionWorkspacePolicy,
@@ -616,6 +644,26 @@ export function createHeartbeatExecuteHandlers(context) {
616
644
  level: "info",
617
645
  message: "run started",
618
646
  });
647
+ if (assignmentGuardrailEnabled) {
648
+ const workspacePreflight = await inspectAssignmentRunWorkspace({
649
+ actualCwd: executionWorkspace.cwd,
650
+ projectWorkingSetCwd: configuredProjectWorkingSetCwd ?? resolvedWorkspace.cwd,
651
+ });
652
+ await appendRunEvent(currentRun, {
653
+ eventType: "runtime.assignment_preflight",
654
+ stream: "system",
655
+ level: workspacePreflight.cwdMatchesProjectWorkingSet ? "info" : "warn",
656
+ message: workspacePreflight.cwdMatchesProjectWorkingSet
657
+ ? "assignment run workspace preflight passed"
658
+ : "assignment run workspace differs from project working set",
659
+ payload: workspacePreflight,
660
+ });
661
+ if (!workspacePreflight.ready) {
662
+ throw new Error(workspacePreflight.recoveryCommand
663
+ ? `Assignment startup preflight failed in ${workspacePreflight.actualCwd}. Run this recovery command once before retrying: ${workspacePreflight.recoveryCommand}`
664
+ : `Assignment project working set is not available: ${workspacePreflight.projectWorkingSetCwd}. Restore or remount that directory before retrying.`);
665
+ }
666
+ }
619
667
  handle = await runLogStore.begin({
620
668
  orgId: run.orgId,
621
669
  agentId: run.agentId,
@@ -677,6 +725,28 @@ export function createHeartbeatExecuteHandlers(context) {
677
725
  parser: stdoutTranscriptParser,
678
726
  kind: "stdout",
679
727
  });
728
+ const checkpoint = assignmentFailureBudget?.observe(executionTranscript) ?? null;
729
+ if (checkpoint && !assignmentGuardrailCheckpoint) {
730
+ const completedWorkSummary = [...executionTranscript]
731
+ .reverse()
732
+ .find((entry) => entry.kind === "assistant" && entry.text.trim())?.text
733
+ .trim()
734
+ .slice(0, 2_000)
735
+ ?? "No reliable completed-work summary was emitted before the guardrail stopped this run.";
736
+ assignmentGuardrailCheckpoint = { ...checkpoint, completedWorkSummary };
737
+ const continuationRequired = assignmentContinuationAttempt < 1;
738
+ await appendRunEvent(currentRun, {
739
+ eventType: "runtime.assignment_guardrail",
740
+ stream: "system",
741
+ level: "warn",
742
+ message: "assignment run failure budget reached; checkpoint requested",
743
+ payload: {
744
+ ...assignmentGuardrailCheckpoint,
745
+ continuationRequired,
746
+ },
747
+ });
748
+ executionAbortController.abort("assignment_run_failure_budget");
749
+ }
680
750
  return;
681
751
  }
682
752
  stderrTranscriptBuffer = appendTranscriptEntriesFromChunk({
@@ -799,7 +869,10 @@ export function createHeartbeatExecuteHandlers(context) {
799
869
  runId: run.id,
800
870
  agent,
801
871
  runtime: runtimeForAdapter,
802
- config: runtimeConfig,
872
+ config: {
873
+ ...runtimeConfig,
874
+ cwd: executionWorkspace.cwd,
875
+ },
803
876
  context,
804
877
  onLog,
805
878
  onMeta: onAdapterMeta,
@@ -817,6 +890,15 @@ export function createHeartbeatExecuteHandlers(context) {
817
890
  stdoutTranscriptParser = attemptAdapter.parseStdoutLine ?? null;
818
891
  },
819
892
  });
893
+ if (assignmentGuardrailCheckpoint) {
894
+ adapterResult.errorMessage = "Assignment run stopped after reaching its tool failure budget";
895
+ adapterResult.errorCode = "assignment_run_failure_budget";
896
+ adapterResult.exitCode = adapterResult.exitCode ?? 1;
897
+ adapterResult.resultJson = {
898
+ ...(adapterResult.resultJson ?? {}),
899
+ assignmentGuardrailCheckpoint,
900
+ };
901
+ }
820
902
  const adapterManagedRuntimeServices = adapterResult.runtimeServices
821
903
  ? await persistAdapterManagedRuntimeServices({
822
904
  db,
@@ -1081,6 +1163,39 @@ export function createHeartbeatExecuteHandlers(context) {
1081
1163
  if (ownsTerminalState || finalizedRun.terminalEffectsPending) {
1082
1164
  shouldCompleteTerminalEffects = true;
1083
1165
  }
1166
+ if (ownsTerminalState && assignmentGuardrailCheckpoint) {
1167
+ const continuationRequired = assignmentContinuationAttempt < 1;
1168
+ await appendRunEvent(finalizedRun, {
1169
+ eventType: "runtime.assignment_checkpoint",
1170
+ stream: "system",
1171
+ level: "warn",
1172
+ message: "assignment run checkpoint created",
1173
+ payload: {
1174
+ completed: assignmentGuardrailCheckpoint.completedWorkSummary,
1175
+ unresolvedError: assignmentGuardrailCheckpoint.unresolvedError,
1176
+ nextRecoveryCommand: assignmentGuardrailCheckpoint.nextRecoveryCommand,
1177
+ continuationRequired,
1178
+ failureCount: assignmentGuardrailCheckpoint.failureCount,
1179
+ fingerprint: assignmentGuardrailCheckpoint.fingerprint,
1180
+ },
1181
+ });
1182
+ if (continuationRequired) {
1183
+ await enqueueRecoveryRun(finalizedRun, agent, {
1184
+ recoveryTrigger: "automatic",
1185
+ source: "automation",
1186
+ triggerDetail: "system",
1187
+ wakeReason: "assignment_failure_budget_continuation",
1188
+ requestedByActorType: "system",
1189
+ requestedByActorId: null,
1190
+ contextPatch: {
1191
+ assignmentGuardrailContinuationAttempt: assignmentContinuationAttempt + 1,
1192
+ assignmentGuardrailCheckpoint,
1193
+ },
1194
+ startImmediately: false,
1195
+ now: new Date(),
1196
+ });
1197
+ }
1198
+ }
1084
1199
  }
1085
1200
  }
1086
1201
  catch (err) {