@sentry/junior 0.177.0 → 0.179.0

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 (102) hide show
  1. package/dist/{agent-hooks-IYHCN7CO.js → agent-hooks-32IDCLMW.js} +12 -12
  2. package/dist/api/conversations/archive.d.ts +5 -2
  3. package/dist/api/conversations/list.d.ts +0 -1
  4. package/dist/api/conversations/membership.d.ts +14 -0
  5. package/dist/api/conversations/projection.d.ts +2 -1
  6. package/dist/api/locations/detail.d.ts +1 -1
  7. package/dist/api/people/shared.d.ts +2 -2
  8. package/dist/api/schema/conversation.d.ts +4 -4
  9. package/dist/api/schema/location.d.ts +1 -1
  10. package/dist/api/schema/person.d.ts +1 -1
  11. package/dist/api/schema.js +1 -1
  12. package/dist/api.js +399 -287
  13. package/dist/app.js +573 -198
  14. package/dist/{catalog-runtime-2TD4CXSB.js → catalog-runtime-FBVA6WAQ.js} +5 -5
  15. package/dist/chat/agent/sandbox.d.ts +2 -0
  16. package/dist/chat/conversations/sql/participants.d.ts +1 -0
  17. package/dist/chat/conversations/store.d.ts +0 -1
  18. package/dist/chat/sandbox/errors.d.ts +4 -0
  19. package/dist/chat/sandbox/noninteractive-command.d.ts +1 -0
  20. package/dist/chat/sandbox/prepare-workspace.d.ts +27 -3
  21. package/dist/chat/sandbox/sandbox.d.ts +2 -0
  22. package/dist/chat/sandbox/session.d.ts +2 -0
  23. package/dist/chat/sandbox/snapshot/builder-sandbox.d.ts +5 -0
  24. package/dist/chat/sandbox/snapshot/install.d.ts +2 -2
  25. package/dist/chat/sandbox/snapshot/span.d.ts +3 -0
  26. package/dist/chat/sandbox/snapshot/store.d.ts +20 -17
  27. package/dist/chat/sandbox/snapshot/waiting-error.d.ts +15 -0
  28. package/dist/chat/sandbox/snapshot/workspace.d.ts +17 -0
  29. package/dist/chat/scheduled-tasks/personal.d.ts +5 -8
  30. package/dist/chat/scheduled-tasks/runs.d.ts +49 -0
  31. package/dist/chat/scheduled-tasks/schedule-intent.d.ts +1 -1
  32. package/dist/chat/scheduled-tasks/tasks.d.ts +27 -0
  33. package/dist/chat/scheduled-tasks/tool-support.d.ts +0 -4
  34. package/dist/chat/scheduled-tasks/tools/create.d.ts +1 -1
  35. package/dist/chat/scheduled-tasks/tools/update.d.ts +1 -1
  36. package/dist/chat/scheduled-tasks/types.d.ts +127 -78
  37. package/dist/chat/services/workspace-snapshot-wait.d.ts +27 -0
  38. package/dist/chat/workspaces/types.d.ts +1 -0
  39. package/dist/{chunk-CAWBLVBY.js → chunk-2HIPYNQI.js} +6 -6
  40. package/dist/{chunk-ZCYABD7N.js → chunk-3AFVR5UC.js} +5 -5
  41. package/dist/{chunk-PA7QDS7P.js → chunk-3I7XE3PA.js} +204 -100
  42. package/dist/{chunk-VGDOEKO2.js → chunk-3TM3FYLQ.js} +1 -1
  43. package/dist/{chunk-6NZRKJWU.js → chunk-4GWXAILB.js} +1 -1
  44. package/dist/{chunk-LFZODSAY.js → chunk-5IRROPA5.js} +4 -4
  45. package/dist/{chunk-N4YEVOEC.js → chunk-B6ECUSVX.js} +45 -276
  46. package/dist/{chunk-4TWDRU64.js → chunk-CJLBLELR.js} +5 -5
  47. package/dist/{chunk-3FWXQZJJ.js → chunk-FAS6AIMF.js} +1 -1
  48. package/dist/{chunk-I7PKGMKI.js → chunk-FIDMHAO6.js} +6 -6
  49. package/dist/{chunk-4SVAFAI2.js → chunk-FTGD2FBP.js} +1 -1
  50. package/dist/{chunk-LVL5NG5G.js → chunk-G2CAC4CV.js} +19 -19
  51. package/dist/{chunk-DLTP6TUJ.js → chunk-GENV6KF2.js} +2 -2
  52. package/dist/{chunk-FVVYHML7.js → chunk-GPLAT6H7.js} +6 -6
  53. package/dist/{chunk-7CVYXUOJ.js → chunk-HQNE5APD.js} +1 -1
  54. package/dist/{chunk-Q362TECJ.js → chunk-JMJNFEDC.js} +331 -2
  55. package/dist/{chunk-AFOFVEXP.js → chunk-JT4WMD3C.js} +124 -13
  56. package/dist/{chunk-7ZFESKJ2.js → chunk-KJLHIHFF.js} +9 -9
  57. package/dist/{chunk-QLLOX7JY.js → chunk-Q5B3WTGG.js} +8 -8
  58. package/dist/{chunk-DGGIKWYQ.js → chunk-R5NWWYIS.js} +1 -1
  59. package/dist/{chunk-WCQUKX74.js → chunk-R6U7N4FS.js} +14 -5
  60. package/dist/{chunk-WYO2HXY5.js → chunk-RTRBYSF3.js} +1 -1
  61. package/dist/{chunk-2IMQLZHS.js → chunk-RZRYOLCE.js} +1144 -136
  62. package/dist/{chunk-7B6NW4P7.js → chunk-SLGGOASN.js} +1 -1
  63. package/dist/{chunk-SNPQGTHJ.js → chunk-TIEKUH4Q.js} +1 -1
  64. package/dist/{chunk-ELEAIRTG.js → chunk-TKB25A3L.js} +2 -2
  65. package/dist/{chunk-UB5YB2ED.js → chunk-U4TKB6F6.js} +6 -6
  66. package/dist/{chunk-ORMJY4RG.js → chunk-UT6X7XN7.js} +1 -1
  67. package/dist/{chunk-LPMLAJYR.js → chunk-VP4OVRDD.js} +11 -17
  68. package/dist/{chunk-7PZDAXIK.js → chunk-XSPSCWLH.js} +1 -1
  69. package/dist/chunk-XZY6G5YZ.js +1088 -0
  70. package/dist/{chunk-J2EWL6GJ.js → chunk-YFNAMRGE.js} +1 -1
  71. package/dist/{chunk-6KGMMVHF.js → chunk-ZQMG3CL5.js} +2 -2
  72. package/dist/cli/chat.js +31 -30
  73. package/dist/cli/check.js +6 -6
  74. package/dist/cli/plugins.js +13 -13
  75. package/dist/cli/snapshot-create.js +10 -10
  76. package/dist/cli/upgrade.js +7 -7
  77. package/dist/db/schema/conversation-participants.d.ts +17 -0
  78. package/dist/db/schema/conversations.d.ts +629 -1
  79. package/dist/db/schema/scheduled-tasks.d.ts +29 -5
  80. package/dist/db/schema/snapshots.d.ts +1 -1
  81. package/dist/db/schema.d.ts +46 -5
  82. package/dist/{db-A3CB76US.js → db-EJAV7JL6.js} +7 -7
  83. package/dist/instrumentation.js +4 -4
  84. package/dist/nitro.js +2 -2
  85. package/dist/{oauth-callback-server-64QMI3IB.js → oauth-callback-server-GAVSUBTQ.js} +23 -23
  86. package/dist/{runner-EIAE2BGD.js → runner-34JL64JF.js} +15 -15
  87. package/dist/{skills-ZADWFKDG.js → skills-U545HALM.js} +6 -6
  88. package/dist/spawn-I2S4IDUQ.js +37 -0
  89. package/dist/{validation-4I6AF4CV.js → validation-EVXVGA44.js} +6 -6
  90. package/dist/version.js +1 -1
  91. package/dist/{work-BS6BZ66U.js → work-QOAUPDBU.js} +18 -18
  92. package/dist/worker-5GX2IKLZ.js +24 -0
  93. package/migrations/0033_workspace_snapshot_active_build.sql +1 -0
  94. package/migrations/0034_strong_randall.sql +31 -0
  95. package/migrations/meta/0033_snapshot.json +2914 -0
  96. package/migrations/meta/0034_snapshot.json +3038 -0
  97. package/migrations/meta/_journal.json +15 -1
  98. package/package.json +4 -4
  99. package/dist/chat/scheduled-tasks/store.d.ts +0 -78
  100. package/dist/chunk-4TRHPYTL.js +0 -1944
  101. package/dist/spawn-DVUOUFFC.js +0 -37
  102. package/dist/worker-RS5PWTCE.js +0 -24
@@ -15,6 +15,7 @@ export type WorkspaceSnapshotStatus = WorkspaceSnapshotBuildStatus | "ready";
15
15
  export type WorkspaceSnapshotBuildPhase = "created" | "dependencies_installed" | "repositories_prepared";
16
16
  /** Current snapshot build for one Workspace recipe. */
17
17
  export interface WorkspaceSnapshotBuild {
18
+ id: string;
18
19
  status: WorkspaceSnapshotBuildStatus;
19
20
  phase: WorkspaceSnapshotBuildPhase;
20
21
  profileHash: string;
@@ -5,19 +5,19 @@ import {
5
5
  isDmChannel,
6
6
  normalizeSlackConversationId,
7
7
  withSlackRetries
8
- } from "./chunk-PA7QDS7P.js";
8
+ } from "./chunk-3I7XE3PA.js";
9
9
  import {
10
10
  parseDestination
11
- } from "./chunk-LPMLAJYR.js";
11
+ } from "./chunk-VP4OVRDD.js";
12
12
  import {
13
13
  getStateAdapter
14
- } from "./chunk-VGDOEKO2.js";
14
+ } from "./chunk-3TM3FYLQ.js";
15
15
  import {
16
16
  normalizeSlackEmojiName
17
- } from "./chunk-DLTP6TUJ.js";
17
+ } from "./chunk-GENV6KF2.js";
18
18
  import {
19
19
  pluginCatalogRuntime
20
- } from "./chunk-J2EWL6GJ.js";
20
+ } from "./chunk-YFNAMRGE.js";
21
21
  import {
22
22
  parseSlackMessageTs,
23
23
  parseSlackUserId
@@ -26,7 +26,7 @@ import {
26
26
  isRecord,
27
27
  logInfo,
28
28
  logWarn
29
- } from "./chunk-7CVYXUOJ.js";
29
+ } from "./chunk-HQNE5APD.js";
30
30
 
31
31
  // src/chat/slack/outbound.ts
32
32
  var MAX_SLACK_MESSAGE_TEXT_CHARS = 4e4;
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  formatProviderLabel,
6
6
  startOAuthFlow
7
- } from "./chunk-CAWBLVBY.js";
7
+ } from "./chunk-2HIPYNQI.js";
8
8
  import {
9
9
  parseSandboxEgressAuthRequiredSignal
10
10
  } from "./chunk-6ZWRNC4D.js";
@@ -12,16 +12,16 @@ import {
12
12
  abandonReplacedPendingAuth,
13
13
  canReusePendingAuthLink,
14
14
  recordAuthorizationRequested
15
- } from "./chunk-I7PKGMKI.js";
15
+ } from "./chunk-FIDMHAO6.js";
16
16
  import {
17
17
  AGENT_INVOCATION_MAILBOX_STATUSES
18
- } from "./chunk-WCQUKX74.js";
18
+ } from "./chunk-R6U7N4FS.js";
19
19
  import {
20
20
  TURN_REASONING_LEVELS
21
- } from "./chunk-DLTP6TUJ.js";
21
+ } from "./chunk-GENV6KF2.js";
22
22
  import {
23
23
  pluginCatalogRuntime
24
- } from "./chunk-J2EWL6GJ.js";
24
+ } from "./chunk-YFNAMRGE.js";
25
25
  import {
26
26
  credentialContextSchema
27
27
  } from "./chunk-CGA4ERJ5.js";
@@ -5,7 +5,7 @@ import {
5
5
  getConversationEventStore,
6
6
  getDb,
7
7
  getSqlExecutor
8
- } from "./chunk-LPMLAJYR.js";
8
+ } from "./chunk-VP4OVRDD.js";
9
9
  import {
10
10
  juniorConversationAnnotations,
11
11
  juniorConversationEvents,
@@ -14,23 +14,25 @@ import {
14
14
  juniorUsers,
15
15
  juniorWorkspaceRepos,
16
16
  juniorWorkspaces
17
- } from "./chunk-WCQUKX74.js";
17
+ } from "./chunk-R6U7N4FS.js";
18
18
  import {
19
19
  SANDBOX_WORKSPACE_ROOT,
20
+ getVercelSandboxCredentials,
20
21
  hash,
22
+ isSandboxMissingError,
21
23
  runNonInteractiveCommand,
22
24
  sleep
23
- } from "./chunk-Q362TECJ.js";
25
+ } from "./chunk-JMJNFEDC.js";
24
26
  import {
25
27
  getStateAdapter
26
- } from "./chunk-VGDOEKO2.js";
28
+ } from "./chunk-3TM3FYLQ.js";
27
29
  import {
28
30
  botConfig,
29
31
  completeObject,
30
32
  embedTexts,
31
33
  getSlackBotToken,
32
34
  standardModelId
33
- } from "./chunk-DLTP6TUJ.js";
35
+ } from "./chunk-GENV6KF2.js";
34
36
  import {
35
37
  isActorUserId,
36
38
  parseActorUserId,
@@ -46,7 +48,7 @@ import {
46
48
  setSpanAttributes,
47
49
  setSpanStatus,
48
50
  withSpan
49
- } from "./chunk-7CVYXUOJ.js";
51
+ } from "./chunk-HQNE5APD.js";
50
52
 
51
53
  // src/chat/plugins/agent-hooks.ts
52
54
  import {
@@ -1664,15 +1666,65 @@ function workspaceRepoCheckoutPath(repo) {
1664
1666
  }
1665
1667
 
1666
1668
  // src/chat/workspaces/store.ts
1667
- import { randomUUID as randomUUID3 } from "crypto";
1668
- import { and as and5, asc as asc2, eq as eq5, sql as sql2 } from "drizzle-orm";
1669
+ import { randomUUID as randomUUID2 } from "crypto";
1670
+ import { and as and5, asc as asc3, eq as eq5, sql as sql2 } from "drizzle-orm";
1671
+
1672
+ // src/chat/sandbox/snapshot/builder-sandbox.ts
1673
+ import { Sandbox } from "@vercel/sandbox";
1674
+ async function getWorkspaceSnapshotBuilder(name, signal) {
1675
+ const credentials = getVercelSandboxCredentials();
1676
+ return await Sandbox.get({
1677
+ name,
1678
+ resume: true,
1679
+ signal,
1680
+ ...credentials ?? {}
1681
+ });
1682
+ }
1683
+ async function deleteWorkspaceSnapshotBuilders(names) {
1684
+ const credentials = getVercelSandboxCredentials();
1685
+ let hasError = false;
1686
+ let firstError;
1687
+ for (const name of new Set(names)) {
1688
+ try {
1689
+ const sandbox = await Sandbox.get({
1690
+ name,
1691
+ resume: false,
1692
+ ...credentials ?? {}
1693
+ });
1694
+ await sandbox.delete();
1695
+ } catch (error) {
1696
+ if (!isSandboxMissingError(error)) {
1697
+ if (!hasError) firstError = error;
1698
+ hasError = true;
1699
+ }
1700
+ }
1701
+ }
1702
+ if (hasError) throw firstError;
1703
+ }
1669
1704
 
1670
1705
  // src/chat/sandbox/snapshot/runtime.ts
1671
1706
  var SANDBOX_RUNTIME = "node22";
1672
1707
 
1673
1708
  // src/chat/sandbox/snapshot/store.ts
1674
- import { randomUUID as randomUUID2 } from "crypto";
1675
- import { and as and4, desc as desc2, eq as eq4, ne } from "drizzle-orm";
1709
+ import { and as and4, asc as asc2, desc as desc2, eq as eq4, ne, or } from "drizzle-orm";
1710
+ function builderNames(rows) {
1711
+ return [
1712
+ ...new Set(
1713
+ rows.map((row) => row.sandboxName).filter((name) => Boolean(name))
1714
+ )
1715
+ ];
1716
+ }
1717
+ function sameWorkspaceRecipe(stored, expected) {
1718
+ if (stored.setupScript !== expected.setupScript || stored.repos.length !== expected.repos.length) {
1719
+ return false;
1720
+ }
1721
+ const expectedRepos = new Set(
1722
+ expected.repos.map((repo) => JSON.stringify([repo.provider, repo.repo]))
1723
+ );
1724
+ return stored.repos.every(
1725
+ (repo) => expectedRepos.has(JSON.stringify([repo.provider, repo.repo]))
1726
+ );
1727
+ }
1676
1728
  function snapshotFromRow(row) {
1677
1729
  if (row.status !== "ready" || !row.snapshotId || !row.generatedAt || row.buildDurationMs == null) {
1678
1730
  throw new Error(`Invalid ready Workspace snapshot row: ${row.id}`);
@@ -1689,6 +1741,7 @@ function snapshotBuildFromRow(row) {
1689
1741
  throw new Error(`Invalid Workspace snapshot build row: ${row.id}`);
1690
1742
  }
1691
1743
  return {
1744
+ id: row.id,
1692
1745
  status: row.status,
1693
1746
  phase: row.buildPhase,
1694
1747
  profileHash: row.profileHash,
@@ -1710,99 +1763,131 @@ async function loadSnapshotsForProfile(db, workspaceId, profileHash) {
1710
1763
  ];
1711
1764
  const [readyRows, buildRows] = await Promise.all([
1712
1765
  db.select().from(juniorSnapshots).where(and4(profile, eq4(juniorSnapshots.status, "ready"))).orderBy(...order).limit(1),
1713
- db.select().from(juniorSnapshots).where(and4(profile, ne(juniorSnapshots.status, "ready"))).orderBy(...order).limit(1)
1766
+ db.select().from(juniorSnapshots).where(and4(profile, ne(juniorSnapshots.status, "ready"))).orderBy(asc2(juniorSnapshots.status), ...order).limit(1)
1714
1767
  ]);
1715
1768
  return {
1716
1769
  ready: readyRows[0] ? snapshotFromRow(readyRows[0]) : null,
1717
1770
  build: buildRows[0] ? snapshotBuildFromRow(buildRows[0]) : null
1718
1771
  };
1719
1772
  }
1720
- async function clearNonReadySnapshots(db, workspaceId) {
1721
- const deleted = await db.delete(juniorSnapshots).where(
1722
- and4(
1723
- eq4(juniorSnapshots.workspaceId, workspaceId),
1724
- ne(juniorSnapshots.status, "ready")
1725
- )
1726
- ).returning({
1727
- sandboxName: juniorSnapshots.buildSandboxName
1728
- });
1729
- return deleted.map((row) => row.sandboxName).filter((name) => Boolean(name));
1773
+ async function clearWorkspaceSnapshots(db, workspaceId) {
1774
+ await db.select({ id: juniorWorkspaces.id }).from(juniorWorkspaces).where(eq4(juniorWorkspaces.id, workspaceId)).for("update");
1775
+ const deleted = await db.delete(juniorSnapshots).where(eq4(juniorSnapshots.workspaceId, workspaceId)).returning({ sandboxName: juniorSnapshots.buildSandboxName });
1776
+ return builderNames(deleted);
1730
1777
  }
1731
- async function setWorkspaceSnapshot(workspaceId, snapshot) {
1778
+ async function invalidateReadySnapshot(params) {
1732
1779
  const executor = getSqlExecutor();
1733
- await executor.transaction(async () => {
1780
+ return await executor.transaction(async () => {
1734
1781
  const db = executor.db();
1735
- const workspaceRows = await db.select({ id: juniorWorkspaces.id }).from(juniorWorkspaces).where(eq4(juniorWorkspaces.id, workspaceId)).limit(1);
1736
- if (!workspaceRows[0]) return;
1737
- const now = /* @__PURE__ */ new Date();
1738
- const existing = await db.select().from(juniorSnapshots).where(
1782
+ const deleted = await db.delete(juniorSnapshots).where(
1739
1783
  and4(
1740
- eq4(juniorSnapshots.workspaceId, workspaceId),
1741
- eq4(juniorSnapshots.profileHash, snapshot.profileHash)
1784
+ eq4(juniorSnapshots.workspaceId, params.workspaceId),
1785
+ eq4(juniorSnapshots.profileHash, params.profileHash),
1786
+ eq4(juniorSnapshots.status, "ready"),
1787
+ eq4(juniorSnapshots.snapshotId, params.snapshotId)
1742
1788
  )
1743
- ).orderBy(desc2(juniorSnapshots.updatedAt), desc2(juniorSnapshots.createdAt)).limit(1);
1744
- const current = existing[0];
1745
- if (current && current.status !== "ready") {
1746
- await db.update(juniorSnapshots).set({
1747
- status: "ready",
1748
- snapshotId: snapshot.id,
1749
- buildDurationMs: snapshot.buildDurationMs,
1750
- generatedAt: snapshot.generatedAt,
1751
- buildStartedAt: null,
1752
- buildPhase: null,
1753
- buildSandboxName: null,
1754
- buildCommandId: null,
1755
- buildError: null,
1756
- updatedAt: now
1757
- }).where(eq4(juniorSnapshots.id, current.id));
1758
- return;
1759
- }
1760
- if (current && current.status === "ready" && current.snapshotId === snapshot.id) {
1761
- await db.update(juniorSnapshots).set({
1762
- buildDurationMs: snapshot.buildDurationMs,
1763
- generatedAt: snapshot.generatedAt,
1764
- buildStartedAt: null,
1765
- buildPhase: null,
1766
- buildSandboxName: null,
1767
- buildCommandId: null,
1768
- buildError: null,
1769
- updatedAt: now
1770
- }).where(eq4(juniorSnapshots.id, current.id));
1771
- return;
1772
- }
1773
- await db.insert(juniorSnapshots).values({
1774
- id: randomUUID2(),
1775
- workspaceId,
1776
- profileHash: snapshot.profileHash,
1789
+ ).returning({ sandboxName: juniorSnapshots.buildSandboxName });
1790
+ return deleted[0]?.sandboxName ?? null;
1791
+ });
1792
+ }
1793
+ async function setWorkspaceSnapshot(workspaceId, snapshot, options) {
1794
+ const executor = getSqlExecutor();
1795
+ return await executor.transaction(async () => {
1796
+ const db = executor.db();
1797
+ const now = /* @__PURE__ */ new Date();
1798
+ const updated = await db.update(juniorSnapshots).set({
1777
1799
  status: "ready",
1778
1800
  snapshotId: snapshot.id,
1779
1801
  buildDurationMs: snapshot.buildDurationMs,
1780
1802
  generatedAt: snapshot.generatedAt,
1781
1803
  buildStartedAt: null,
1782
- buildSandboxName: null,
1804
+ buildPhase: null,
1783
1805
  buildCommandId: null,
1784
1806
  buildError: null,
1785
- createdAt: now,
1786
1807
  updatedAt: now
1787
- });
1808
+ }).where(
1809
+ and4(
1810
+ eq4(juniorSnapshots.id, options.buildId),
1811
+ eq4(juniorSnapshots.workspaceId, workspaceId),
1812
+ eq4(juniorSnapshots.profileHash, snapshot.profileHash),
1813
+ eq4(juniorSnapshots.status, "building")
1814
+ )
1815
+ ).returning({ id: juniorSnapshots.id });
1816
+ if (updated.length === 0) {
1817
+ return { written: false, replacedBuilderNames: [] };
1818
+ }
1819
+ const replaced = await db.delete(juniorSnapshots).where(
1820
+ and4(
1821
+ eq4(juniorSnapshots.workspaceId, workspaceId),
1822
+ eq4(juniorSnapshots.profileHash, snapshot.profileHash),
1823
+ ne(juniorSnapshots.id, options.buildId),
1824
+ or(
1825
+ eq4(juniorSnapshots.status, "failed"),
1826
+ eq4(juniorSnapshots.status, "ready")
1827
+ )
1828
+ )
1829
+ ).returning({ sandboxName: juniorSnapshots.buildSandboxName });
1830
+ return {
1831
+ written: true,
1832
+ replacedBuilderNames: builderNames(replaced)
1833
+ };
1788
1834
  });
1789
1835
  }
1790
- async function recordResolvedWorkspaceSnapshot(workspaceId, snapshot) {
1791
- if (!snapshot.snapshotId || !snapshot.profileHash || snapshot.createdAtMs == null || snapshot.buildDurationMs == null) {
1792
- return;
1793
- }
1794
- try {
1795
- await setWorkspaceSnapshot(workspaceId, {
1796
- id: snapshot.snapshotId,
1797
- generatedAt: new Date(snapshot.createdAtMs),
1798
- buildDurationMs: snapshot.buildDurationMs,
1799
- profileHash: snapshot.profileHash
1800
- });
1801
- } catch (error) {
1802
- logException(error, "sandbox.workspace_snapshot.persist.failed", {
1803
- "app.workspace.id": workspaceId
1804
- });
1805
- }
1836
+ async function setWorkspaceSnapshotBuild(workspaceId, build, options = {}) {
1837
+ const executor = getSqlExecutor();
1838
+ return await executor.transaction(async () => {
1839
+ const db = executor.db();
1840
+ const now = /* @__PURE__ */ new Date();
1841
+ const updated = await db.update(juniorSnapshots).set({
1842
+ status: build.status,
1843
+ buildStartedAt: build.startedAt,
1844
+ buildPhase: build.phase,
1845
+ buildSandboxName: build.sandboxName,
1846
+ buildCommandId: build.commandId,
1847
+ buildError: build.error,
1848
+ updatedAt: now
1849
+ }).where(
1850
+ and4(
1851
+ eq4(juniorSnapshots.id, build.id),
1852
+ eq4(juniorSnapshots.workspaceId, workspaceId),
1853
+ eq4(juniorSnapshots.profileHash, build.profileHash),
1854
+ eq4(juniorSnapshots.status, "building")
1855
+ )
1856
+ ).returning({ id: juniorSnapshots.id });
1857
+ if (updated.length > 0) {
1858
+ return true;
1859
+ }
1860
+ if (!options.insertIfMissing) return false;
1861
+ const workspaceRows = await db.select({ setupScript: juniorWorkspaces.setupScript }).from(juniorWorkspaces).where(eq4(juniorWorkspaces.id, workspaceId)).for("update");
1862
+ const workspace = workspaceRows[0];
1863
+ if (!workspace) return false;
1864
+ if (options.expectedRecipe) {
1865
+ const repos = await db.select({
1866
+ provider: juniorWorkspaceRepos.provider,
1867
+ repo: juniorWorkspaceRepos.repo
1868
+ }).from(juniorWorkspaceRepos).where(eq4(juniorWorkspaceRepos.workspaceId, workspaceId));
1869
+ if (!sameWorkspaceRecipe({ ...workspace, repos }, options.expectedRecipe)) {
1870
+ return false;
1871
+ }
1872
+ }
1873
+ const inserted = await db.insert(juniorSnapshots).values({
1874
+ id: build.id,
1875
+ workspaceId,
1876
+ profileHash: build.profileHash,
1877
+ status: build.status,
1878
+ snapshotId: null,
1879
+ buildDurationMs: null,
1880
+ generatedAt: null,
1881
+ buildStartedAt: build.startedAt,
1882
+ buildPhase: build.phase,
1883
+ buildSandboxName: build.sandboxName,
1884
+ buildCommandId: build.commandId,
1885
+ buildError: build.error,
1886
+ createdAt: now,
1887
+ updatedAt: now
1888
+ }).onConflictDoNothing().returning({ id: juniorSnapshots.id });
1889
+ return inserted.length > 0;
1890
+ });
1806
1891
  }
1807
1892
 
1808
1893
  // src/chat/workspaces/validation.ts
@@ -1914,8 +1999,8 @@ async function workspaceWithSnapshot(db, row, repos) {
1914
1999
  }
1915
2000
  async function loadWorkspaceRepos(db, workspaceId) {
1916
2001
  return await db.select().from(juniorWorkspaceRepos).where(eq5(juniorWorkspaceRepos.workspaceId, workspaceId)).orderBy(
1917
- asc2(juniorWorkspaceRepos.provider),
1918
- asc2(juniorWorkspaceRepos.repo)
2002
+ asc3(juniorWorkspaceRepos.provider),
2003
+ asc3(juniorWorkspaceRepos.repo)
1919
2004
  );
1920
2005
  }
1921
2006
  async function replaceWorkspaceRepos(db, workspaceId, repos) {
@@ -1946,13 +2031,24 @@ function isUniqueViolation(error) {
1946
2031
  }
1947
2032
  return false;
1948
2033
  }
2034
+ async function cleanupSnapshotBuilders(workspaceId, names) {
2035
+ if (names.length === 0) return;
2036
+ try {
2037
+ await deleteWorkspaceSnapshotBuilders(names);
2038
+ } catch (error) {
2039
+ logException(error, "sandbox.workspace_snapshot.builder.delete_failed", {
2040
+ "app.workspace.id": workspaceId,
2041
+ "app.sandbox.snapshot.builder_count": names.length
2042
+ });
2043
+ }
2044
+ }
1949
2045
  async function listWorkspaces(db) {
1950
2046
  const [workspaces, repos] = await Promise.all([
1951
- db.select().from(juniorWorkspaces).orderBy(asc2(juniorWorkspaces.name)),
2047
+ db.select().from(juniorWorkspaces).orderBy(asc3(juniorWorkspaces.name)),
1952
2048
  db.select().from(juniorWorkspaceRepos).orderBy(
1953
- asc2(juniorWorkspaceRepos.workspaceId),
1954
- asc2(juniorWorkspaceRepos.provider),
1955
- asc2(juniorWorkspaceRepos.repo)
2049
+ asc3(juniorWorkspaceRepos.workspaceId),
2050
+ asc3(juniorWorkspaceRepos.provider),
2051
+ asc3(juniorWorkspaceRepos.repo)
1956
2052
  )
1957
2053
  ]);
1958
2054
  return workspaces.map(
@@ -1975,7 +2071,7 @@ async function listWorkspaceNamesByRepository(db, input) {
1975
2071
  // Recipes store the provided repo casing; identity is case-insensitive.
1976
2072
  sql2`lower(${juniorWorkspaceRepos.repo}) = lower(${repo})`
1977
2073
  )
1978
- ).orderBy(asc2(juniorWorkspaces.name));
2074
+ ).orderBy(asc3(juniorWorkspaces.name));
1979
2075
  return rows.map((row) => row.name);
1980
2076
  }
1981
2077
  async function getWorkspaceByName(db, name) {
@@ -2002,7 +2098,7 @@ async function createWorkspace(input) {
2002
2098
  const recipe = normalizeWorkspaceRecipe(input);
2003
2099
  const executor = getSqlExecutor();
2004
2100
  const now = /* @__PURE__ */ new Date();
2005
- const id = randomUUID3();
2101
+ const id = randomUUID2();
2006
2102
  try {
2007
2103
  await executor.transaction(async () => {
2008
2104
  const db = executor.db();
@@ -2030,7 +2126,7 @@ async function updateWorkspace(id, input) {
2030
2126
  const executor = getSqlExecutor();
2031
2127
  const now = /* @__PURE__ */ new Date();
2032
2128
  try {
2033
- const updated = await executor.transaction(async () => {
2129
+ const result = await executor.transaction(async () => {
2034
2130
  const db = executor.db();
2035
2131
  const existingRows = await db.select().from(juniorWorkspaces).where(eq5(juniorWorkspaces.id, id)).limit(1);
2036
2132
  const existing = existingRows[0];
@@ -2043,12 +2139,11 @@ async function updateWorkspace(id, input) {
2043
2139
  updatedAt: now
2044
2140
  }).where(eq5(juniorWorkspaces.id, id)).returning();
2045
2141
  await replaceWorkspaceRepos(db, id, recipe.repos);
2046
- if (snapshotChanged) {
2047
- await clearNonReadySnapshots(db, id);
2048
- }
2049
- return rows[0];
2142
+ const builderNames2 = snapshotChanged ? await clearWorkspaceSnapshots(db, id) : [];
2143
+ return { builderNames: builderNames2, workspace: rows[0] };
2050
2144
  });
2051
- if (!updated) return void 0;
2145
+ if (!result) return void 0;
2146
+ await cleanupSnapshotBuilders(id, result.builderNames);
2052
2147
  } catch (error) {
2053
2148
  if (isUniqueViolation(error)) {
2054
2149
  throw new WorkspaceValidationError(
@@ -2061,10 +2156,14 @@ async function updateWorkspace(id, input) {
2061
2156
  }
2062
2157
  async function deleteWorkspace(id) {
2063
2158
  const executor = getSqlExecutor();
2064
- return await executor.transaction(async () => {
2065
- const rows = await executor.db().delete(juniorWorkspaces).where(eq5(juniorWorkspaces.id, id)).returning({ id: juniorWorkspaces.id });
2066
- return rows.length > 0;
2159
+ const result = await executor.transaction(async () => {
2160
+ const db = executor.db();
2161
+ const builderNames2 = await clearWorkspaceSnapshots(db, id);
2162
+ const rows = await db.delete(juniorWorkspaces).where(eq5(juniorWorkspaces.id, id)).returning({ id: juniorWorkspaces.id });
2163
+ return { builderNames: builderNames2, deleted: rows.length > 0 };
2067
2164
  });
2165
+ await cleanupSnapshotBuilders(id, result.builderNames);
2166
+ return result.deleted;
2068
2167
  }
2069
2168
 
2070
2169
  // src/chat/plugins/agent-hooks.ts
@@ -3341,8 +3440,13 @@ export {
3341
3440
  resolveChannelCapabilities,
3342
3441
  tryWorkspaceRepoCheckoutPath,
3343
3442
  workspaceRepoCheckoutPath,
3443
+ getWorkspaceSnapshotBuilder,
3444
+ deleteWorkspaceSnapshotBuilders,
3344
3445
  SANDBOX_RUNTIME,
3345
- recordResolvedWorkspaceSnapshot,
3446
+ loadSnapshotsForProfile,
3447
+ invalidateReadySnapshot,
3448
+ setWorkspaceSnapshot,
3449
+ setWorkspaceSnapshotBuild,
3346
3450
  WorkspaceValidationError,
3347
3451
  listWorkspaces,
3348
3452
  getWorkspaceByName,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getChatConfig
3
- } from "./chunk-DLTP6TUJ.js";
3
+ } from "./chunk-GENV6KF2.js";
4
4
 
5
5
  // src/chat/state/adapter.ts
6
6
  import { createMemoryState } from "@chat-adapter/state-memory";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  FUNCTION_TIMEOUT_BUFFER_SECONDS,
3
3
  getChatConfig
4
- } from "./chunk-DLTP6TUJ.js";
4
+ } from "./chunk-GENV6KF2.js";
5
5
 
6
6
  // src/chat/runtime/request-deadline.ts
7
7
  import { AsyncLocalStorage } from "async_hooks";
@@ -8,14 +8,14 @@ import {
8
8
  getConversationStore,
9
9
  parseDestination,
10
10
  sameDestination
11
- } from "./chunk-LPMLAJYR.js";
11
+ } from "./chunk-VP4OVRDD.js";
12
12
  import {
13
13
  getDefaultRedisStateAdapterFor,
14
14
  getStateAdapter
15
- } from "./chunk-VGDOEKO2.js";
15
+ } from "./chunk-3TM3FYLQ.js";
16
16
  import {
17
17
  getChatConfig
18
- } from "./chunk-DLTP6TUJ.js";
18
+ } from "./chunk-GENV6KF2.js";
19
19
  import {
20
20
  parseStoredSlackActor
21
21
  } from "./chunk-M63DETLL.js";
@@ -23,7 +23,7 @@ import {
23
23
  isRecord,
24
24
  toOptionalNumber,
25
25
  toOptionalString
26
- } from "./chunk-7CVYXUOJ.js";
26
+ } from "./chunk-HQNE5APD.js";
27
27
 
28
28
  // src/chat/task-execution/state.ts
29
29
  import { randomUUID } from "crypto";