@sentry/junior 0.165.0 → 0.167.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 (68) hide show
  1. package/dist/{agent-hooks-GSNL33UA.js → agent-hooks-KEHBR4DB.js} +9 -9
  2. package/dist/api/schema/workspace.d.ts +16 -0
  3. package/dist/api/schema.d.ts +2 -2
  4. package/dist/api/schema.js +3 -1
  5. package/dist/api.js +64 -47
  6. package/dist/app.js +58 -60
  7. package/dist/{catalog-runtime-4ERDVI7V.js → catalog-runtime-7QFMBU2Q.js} +5 -5
  8. package/dist/chat/pi/transcript.d.ts +10 -10
  9. package/dist/chat/sandbox/snapshot/resolve.d.ts +4 -0
  10. package/dist/chat/services/conversation-memory.d.ts +7 -0
  11. package/dist/chat/workspaces/store.d.ts +10 -1
  12. package/dist/chat/workspaces/types.d.ts +8 -0
  13. package/dist/{chunk-AEBF6AO2.js → chunk-2MPO25ZZ.js} +1 -1
  14. package/dist/{chunk-VDNNVTX2.js → chunk-2RSPCWAV.js} +5 -5
  15. package/dist/{chunk-5WDDWMQ7.js → chunk-4KRDL4ZD.js} +64 -7
  16. package/dist/{chunk-NPW6LM2X.js → chunk-5IR2ABRO.js} +12 -12
  17. package/dist/{chunk-BEHPIDVZ.js → chunk-5LZVDKQJ.js} +42 -17
  18. package/dist/{chunk-DKO4RRGJ.js → chunk-6SJN7JZ3.js} +1 -1
  19. package/dist/{chunk-6RZ6MMEK.js → chunk-BGRLZPMI.js} +1 -1
  20. package/dist/{chunk-HPWZ4BJJ.js → chunk-CC4EYBUO.js} +58 -54
  21. package/dist/{chunk-FNNQCHOL.js → chunk-CU7YQNZ3.js} +4 -4
  22. package/dist/{chunk-N2BRRIQZ.js → chunk-EWAG7BNE.js} +1 -1
  23. package/dist/{chunk-XOINKFDJ.js → chunk-GC3AKBNP.js} +7 -7
  24. package/dist/{chunk-6OWVPXNO.js → chunk-GIGUXRMY.js} +1 -1
  25. package/dist/{chunk-FXX4NHOM.js → chunk-HIB3XTKR.js} +6 -6
  26. package/dist/{chunk-SA5FVUWJ.js → chunk-IHSPBOWG.js} +6 -6
  27. package/dist/{chunk-6YXCG2XL.js → chunk-KE5ETKIR.js} +4 -4
  28. package/dist/{chunk-EA4UL5H2.js → chunk-KSQIE2R4.js} +40 -11
  29. package/dist/{chunk-7S2JVUWS.js → chunk-L63FA77C.js} +1 -1
  30. package/dist/{chunk-FMOFCEAA.js → chunk-MKDIEH3C.js} +2 -2
  31. package/dist/{chunk-T6BAHCT6.js → chunk-MV4LDMRG.js} +17 -17
  32. package/dist/{chunk-AQEBOQUC.js → chunk-O5J556I2.js} +9 -9
  33. package/dist/{chunk-RQQTOF3H.js → chunk-PMULUKHL.js} +3 -3
  34. package/dist/{chunk-7J26TW64.js → chunk-PRV74X7E.js} +5 -5
  35. package/dist/{chunk-3V2EIQLT.js → chunk-TZHLY42G.js} +1 -1
  36. package/dist/{chunk-5T6WPPEI.js → chunk-UFTE42ZF.js} +1 -1
  37. package/dist/{chunk-BEC542E6.js → chunk-UTMP45YM.js} +13 -2
  38. package/dist/{chunk-32CCG4WP.js → chunk-V7GGA4LW.js} +1 -1
  39. package/dist/{chunk-65B3PDY7.js → chunk-W72TSO24.js} +1 -1
  40. package/dist/{chunk-G72LBEMZ.js → chunk-WD7PVGMA.js} +1 -1
  41. package/dist/{chunk-HZDLOFO4.js → chunk-WHMDWHZX.js} +5 -5
  42. package/dist/{chunk-TCWPG5VL.js → chunk-WRBQL2AW.js} +2 -2
  43. package/dist/{chunk-ZUKU2Y3J.js → chunk-WZGOP5BZ.js} +1 -1
  44. package/dist/{chunk-IZHR2OES.js → chunk-YVW44V5Y.js} +13 -2
  45. package/dist/cli/chat.js +29 -29
  46. package/dist/cli/check.js +6 -6
  47. package/dist/cli/plugins.js +12 -12
  48. package/dist/cli/snapshot-create.js +9 -9
  49. package/dist/cli/upgrade.js +7 -7
  50. package/dist/db/schema/workspaces.d.ts +68 -0
  51. package/dist/db/schema.d.ts +68 -0
  52. package/dist/{db-5TTEPMTY.js → db-H25MZO65.js} +7 -7
  53. package/dist/instrumentation.js +4 -4
  54. package/dist/nitro.js +2 -2
  55. package/dist/{oauth-callback-server-IVFC5YHY.js → oauth-callback-server-BX334MQ6.js} +22 -22
  56. package/dist/{runner-G76TSHWO.js → runner-GRWCCCKP.js} +12 -12
  57. package/dist/{skills-F6PSLVSG.js → skills-TG76W7TS.js} +6 -6
  58. package/dist/spawn-4YBTXAR2.js +37 -0
  59. package/dist/{validation-56EJI6UQ.js → validation-JY6EXXR3.js} +6 -6
  60. package/dist/version.js +1 -1
  61. package/dist/{work-RNRQCP3Y.js → work-53J6P32F.js} +17 -17
  62. package/dist/worker-WLLGEEQS.js +24 -0
  63. package/migrations/0031_wild_phantom_reporter.sql +4 -0
  64. package/migrations/meta/0031_snapshot.json +2823 -0
  65. package/migrations/meta/_journal.json +7 -0
  66. package/package.json +5 -5
  67. package/dist/spawn-WMJPIAZL.js +0 -37
  68. package/dist/worker-FBR2WUI4.js +0 -24
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  pluginCatalogRuntime
3
- } from "./chunk-7S2JVUWS.js";
4
- import "./chunk-N2BRRIQZ.js";
3
+ } from "./chunk-L63FA77C.js";
4
+ import "./chunk-EWAG7BNE.js";
5
5
  import "./chunk-BDUENQD3.js";
6
6
  import "./chunk-V7YE4WCP.js";
7
- import "./chunk-32CCG4WP.js";
7
+ import "./chunk-V7GGA4LW.js";
8
8
  import "./chunk-6GWA276C.js";
9
9
  import "./chunk-OOUNJNMR.js";
10
10
  import "./chunk-H4HBKISO.js";
11
- import "./chunk-5T6WPPEI.js";
12
- import "./chunk-6OWVPXNO.js";
11
+ import "./chunk-UFTE42ZF.js";
12
+ import "./chunk-GIGUXRMY.js";
13
13
  import "./chunk-MLKGABMK.js";
14
14
  export {
15
15
  pluginCatalogRuntime
@@ -34,16 +34,16 @@ export declare function retainRuntimeTurnContext(messages: PiMessage[]): PiMessa
34
34
  /**
35
35
  * Reduce a runtime user-turn prompt to only the current turn's instruction.
36
36
  *
37
- * Live user prompts embed prior-thread context blocks (`<thread-transcript>`,
38
- * `<recent-thread-messages>`, `<thread-compactions>`, `<thread-background>`) in
39
- * the same message that carries the `<current-instruction>` block. Those blocks
40
- * hold other participants' verbatim messages, so completed-run projections
41
- * consumed by plugins must expose only the instruction authored by this turn's
42
- * actor — otherwise per-entry provenance can be defeated by reading another
43
- * user's text out of an instruction-authority entry. Prior thread context is
44
- * projected separately as per-author context-authority entries, so dropping it
45
- * here is non-lossy for plugins. This is projection-only; it never touches what
46
- * the model sees during a live run.
37
+ * Live user prompts embed prior-thread context as `<thread-context
38
+ * authority="evidence-only">` (or legacy transcript/background blocks) beside
39
+ * the `<current-instruction>` block. Those blocks hold other participants'
40
+ * verbatim messages, so completed-run projections consumed by plugins must
41
+ * expose only the instruction authored by this turn's actor — otherwise
42
+ * per-entry provenance can be defeated by reading another user's text out of an
43
+ * instruction-authority entry. Prior thread context is projected separately as
44
+ * per-author context-authority entries, so dropping it here is non-lossy for
45
+ * plugins. This is projection-only; it never touches what the model sees during
46
+ * a live run.
47
47
  */
48
48
  export declare function instructionTextForProjection(text: string): string;
49
49
  /** Return the projected instruction text carried by one user message. */
@@ -7,6 +7,7 @@ declare const cachedSnapshotSchema: z.ZodObject<{
7
7
  runtime: z.ZodString;
8
8
  createdAtMs: z.ZodNumber;
9
9
  dependencyCount: z.ZodNumber;
10
+ buildDurationMs: z.ZodNumber;
10
11
  }, z.core.$strict>;
11
12
  type CachedSnapshot = z.output<typeof cachedSnapshotSchema>;
12
13
  export type ResolveOutcome = "no_profile" | "cache_hit" | "cache_hit_after_lock_wait" | "rebuilt" | "forced_rebuild";
@@ -19,6 +20,9 @@ export interface Snapshot {
19
20
  cacheHit: boolean;
20
21
  resolveOutcome: ResolveOutcome;
21
22
  rebuildReason?: RebuildReason;
23
+ /** Present when the Redis registry has a concrete snapshot entry. */
24
+ createdAtMs?: number;
25
+ buildDurationMs?: number;
22
26
  }
23
27
  export type ProgressPhase = "resolve_start" | "cache_hit" | "waiting_for_lock" | "building_snapshot" | "build_complete";
24
28
  /** Read one cached snapshot pointer; only a missing key is a cache miss. */
@@ -37,6 +37,13 @@ export declare function markConversationMessage(conversation: ThreadConversation
37
37
  export declare function buildConversationContext(conversation: ThreadConversationState, options?: {
38
38
  excludeMessageId?: string;
39
39
  }): string | undefined;
40
+ /**
41
+ * Keep ambient history as one evidence-only block.
42
+ *
43
+ * When durable context already ends a thread-context envelope, append message
44
+ * lines inside that envelope. Otherwise wrap the new messages in one envelope.
45
+ */
46
+ export declare function appendThreadContextMessages(baseContext: string | undefined, messageLines: string[]): string | undefined;
40
47
  /** Return the earliest human-authored message known for a thread. */
41
48
  export declare function getThreadTitleSourceMessage(conversation: ThreadConversationState): ConversationMessage | undefined;
42
49
  /** Build the service that owns durable conversation memory compaction. */
@@ -1,5 +1,5 @@
1
1
  import type { JuniorDatabase } from "@/db/db";
2
- import type { Workspace } from "./types";
2
+ import type { Workspace, WorkspaceSnapshot } from "./types";
3
3
  import { WorkspaceValidationError } from "./validation";
4
4
  /** List Workspace recipes by stable name. */
5
5
  export declare function listWorkspaces(db: JuniorDatabase): Promise<Workspace[]>;
@@ -32,4 +32,13 @@ export declare function updateWorkspace(id: string, input: {
32
32
  }): Promise<Workspace | undefined>;
33
33
  /** Delete one install-wide Workspace recipe. */
34
34
  export declare function deleteWorkspace(id: string): Promise<boolean>;
35
+ /** Record the current Sandbox snapshot after a successful Workspace prepare. */
36
+ export declare function setWorkspaceSnapshot(workspaceId: string, snapshot: WorkspaceSnapshot): Promise<void>;
37
+ /** Persist dashboard snapshot facts when resolve returned a concrete entry. */
38
+ export declare function recordResolvedWorkspaceSnapshot(workspaceId: string, snapshot: {
39
+ snapshotId?: string;
40
+ profileHash?: string;
41
+ createdAtMs?: number;
42
+ buildDurationMs?: number;
43
+ }): Promise<void>;
35
44
  export { WorkspaceValidationError };
@@ -3,10 +3,18 @@ export interface WorkspaceRepo {
3
3
  provider: string;
4
4
  repo: string;
5
5
  }
6
+ /** Last successful Sandbox snapshot recorded for one Workspace recipe. */
7
+ export interface WorkspaceSnapshot {
8
+ id: string;
9
+ generatedAt: Date;
10
+ buildDurationMs: number;
11
+ profileHash: string;
12
+ }
6
13
  /** Named recipe used to prepare reusable sandbox contents. */
7
14
  export interface Workspace {
8
15
  id: string;
9
16
  name: string;
10
17
  setupScript: string;
11
18
  repos: WorkspaceRepo[];
19
+ snapshot: WorkspaceSnapshot | null;
12
20
  }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getStateAdapter
3
- } from "./chunk-65B3PDY7.js";
3
+ } from "./chunk-W72TSO24.js";
4
4
  import {
5
5
  getClient
6
6
  } from "./chunk-6GWA276C.js";
@@ -1,18 +1,18 @@
1
1
  import {
2
2
  persistConversationMessages
3
- } from "./chunk-EA4UL5H2.js";
3
+ } from "./chunk-KSQIE2R4.js";
4
4
  import {
5
5
  JUNIOR_THREAD_STATE_TTL_MS
6
6
  } from "./chunk-3Y47VMHV.js";
7
7
  import {
8
8
  getDb
9
- } from "./chunk-RQQTOF3H.js";
9
+ } from "./chunk-PMULUKHL.js";
10
10
  import {
11
11
  juniorLocationConfigurations
12
- } from "./chunk-IZHR2OES.js";
12
+ } from "./chunk-YVW44V5Y.js";
13
13
  import {
14
14
  getStateAdapter
15
- } from "./chunk-65B3PDY7.js";
15
+ } from "./chunk-W72TSO24.js";
16
16
  import {
17
17
  juniorDestinations
18
18
  } from "./chunk-VFUK3X5B.js";
@@ -20,7 +20,7 @@ import {
20
20
  isRecord,
21
21
  toOptionalNumber,
22
22
  toOptionalString
23
- } from "./chunk-32CCG4WP.js";
23
+ } from "./chunk-V7GGA4LW.js";
24
24
 
25
25
  // src/chat/conversations/turn-lifecycle.ts
26
26
  var ConversationTurnLifecycleService = class {
@@ -2,7 +2,7 @@ import {
2
2
  getConversationEventStore,
3
3
  getDb,
4
4
  getSqlExecutor
5
- } from "./chunk-RQQTOF3H.js";
5
+ } from "./chunk-PMULUKHL.js";
6
6
  import {
7
7
  juniorConversationAnnotations,
8
8
  juniorConversationEvents,
@@ -10,7 +10,7 @@ import {
10
10
  juniorUsers,
11
11
  juniorWorkspaceRepos,
12
12
  juniorWorkspaces
13
- } from "./chunk-IZHR2OES.js";
13
+ } from "./chunk-YVW44V5Y.js";
14
14
  import {
15
15
  SANDBOX_WORKSPACE_ROOT,
16
16
  runNonInteractiveCommand,
@@ -18,14 +18,14 @@ import {
18
18
  } from "./chunk-BVREIWBD.js";
19
19
  import {
20
20
  getStateAdapter
21
- } from "./chunk-65B3PDY7.js";
21
+ } from "./chunk-W72TSO24.js";
22
22
  import {
23
23
  botConfig,
24
24
  completeObject,
25
25
  embedTexts,
26
26
  getSlackBotToken,
27
27
  standardModelId
28
- } from "./chunk-FMOFCEAA.js";
28
+ } from "./chunk-MKDIEH3C.js";
29
29
  import {
30
30
  isActorUserId,
31
31
  parseActorUserId,
@@ -41,7 +41,7 @@ import {
41
41
  setSpanAttributes,
42
42
  setSpanStatus,
43
43
  withSpan
44
- } from "./chunk-32CCG4WP.js";
44
+ } from "./chunk-V7GGA4LW.js";
45
45
 
46
46
  // src/chat/plugins/agent-hooks.ts
47
47
  import {
@@ -1305,6 +1305,17 @@ function normalizeWorkspaceRecipe(input) {
1305
1305
  }
1306
1306
 
1307
1307
  // src/chat/workspaces/store.ts
1308
+ function snapshotFromRow(row) {
1309
+ if (!row.snapshotId || !row.snapshotGeneratedAt || row.snapshotBuildDurationMs == null || !row.snapshotProfileHash) {
1310
+ return null;
1311
+ }
1312
+ return {
1313
+ id: row.snapshotId,
1314
+ generatedAt: row.snapshotGeneratedAt,
1315
+ buildDurationMs: row.snapshotBuildDurationMs,
1316
+ profileHash: row.snapshotProfileHash
1317
+ };
1318
+ }
1308
1319
  function workspaceFromRows(row, repos) {
1309
1320
  return {
1310
1321
  id: row.id,
@@ -1313,7 +1324,8 @@ function workspaceFromRows(row, repos) {
1313
1324
  repos: repos.map((repo) => ({
1314
1325
  provider: repo.provider,
1315
1326
  repo: repo.repo
1316
- }))
1327
+ })),
1328
+ snapshot: snapshotFromRow(row)
1317
1329
  };
1318
1330
  }
1319
1331
  async function loadWorkspaceRepos(db, workspaceId) {
@@ -1333,6 +1345,13 @@ async function replaceWorkspaceRepos(db, workspaceId, repos) {
1333
1345
  }))
1334
1346
  );
1335
1347
  }
1348
+ function sameWorkspaceRepos(current, next) {
1349
+ if (current.length !== next.length) return false;
1350
+ const identity = (repo) => `${repo.provider}:${repo.repo.toLowerCase()}`;
1351
+ const currentIds = current.map(identity).sort();
1352
+ const nextIds = next.map(identity).sort();
1353
+ return currentIds.every((value, index) => value === nextIds[index]);
1354
+ }
1336
1355
  function isUniqueViolation(error) {
1337
1356
  let current = error;
1338
1357
  for (let depth = 0; current && depth < 6; depth += 1) {
@@ -1426,12 +1445,22 @@ async function updateWorkspace(id, input) {
1426
1445
  try {
1427
1446
  const updated = await executor.transaction(async () => {
1428
1447
  const db = executor.db();
1448
+ const existingRows = await db.select().from(juniorWorkspaces).where(eq4(juniorWorkspaces.id, id)).limit(1);
1449
+ const existing = existingRows[0];
1450
+ if (!existing) return void 0;
1451
+ const existingRepos = await loadWorkspaceRepos(db, id);
1452
+ const snapshotChanged = existing.setupScript !== recipe.setupScript || !sameWorkspaceRepos(existingRepos, recipe.repos);
1429
1453
  const rows = await db.update(juniorWorkspaces).set({
1430
1454
  name: recipe.name,
1431
1455
  setupScript: recipe.setupScript,
1456
+ ...snapshotChanged ? {
1457
+ snapshotId: null,
1458
+ snapshotGeneratedAt: null,
1459
+ snapshotBuildDurationMs: null,
1460
+ snapshotProfileHash: null
1461
+ } : {},
1432
1462
  updatedAt: now
1433
1463
  }).where(eq4(juniorWorkspaces.id, id)).returning();
1434
- if (!rows[0]) return void 0;
1435
1464
  await replaceWorkspaceRepos(db, id, recipe.repos);
1436
1465
  return rows[0];
1437
1466
  });
@@ -1453,6 +1482,33 @@ async function deleteWorkspace(id) {
1453
1482
  return rows.length > 0;
1454
1483
  });
1455
1484
  }
1485
+ async function setWorkspaceSnapshot(workspaceId, snapshot) {
1486
+ const executor = getSqlExecutor();
1487
+ await executor.db().update(juniorWorkspaces).set({
1488
+ snapshotId: snapshot.id,
1489
+ snapshotGeneratedAt: snapshot.generatedAt,
1490
+ snapshotBuildDurationMs: snapshot.buildDurationMs,
1491
+ snapshotProfileHash: snapshot.profileHash,
1492
+ updatedAt: /* @__PURE__ */ new Date()
1493
+ }).where(eq4(juniorWorkspaces.id, workspaceId));
1494
+ }
1495
+ async function recordResolvedWorkspaceSnapshot(workspaceId, snapshot) {
1496
+ if (!snapshot.snapshotId || !snapshot.profileHash || snapshot.createdAtMs == null || snapshot.buildDurationMs == null) {
1497
+ return;
1498
+ }
1499
+ try {
1500
+ await setWorkspaceSnapshot(workspaceId, {
1501
+ id: snapshot.snapshotId,
1502
+ generatedAt: new Date(snapshot.createdAtMs),
1503
+ buildDurationMs: snapshot.buildDurationMs,
1504
+ profileHash: snapshot.profileHash
1505
+ });
1506
+ } catch (error) {
1507
+ logException(error, "sandbox.workspace_snapshot.persist.failed", {
1508
+ "app.workspace.id": workspaceId
1509
+ });
1510
+ }
1511
+ }
1456
1512
 
1457
1513
  // src/chat/plugins/agent-hooks.ts
1458
1514
  var PluginHookDeniedError = class extends Error {
@@ -2685,6 +2741,7 @@ export {
2685
2741
  createWorkspace,
2686
2742
  updateWorkspace,
2687
2743
  deleteWorkspace,
2744
+ recordResolvedWorkspaceSnapshot,
2688
2745
  PluginHookDeniedError,
2689
2746
  validatePlugins,
2690
2747
  setPlugins,
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  createWebAuthorization,
3
3
  deleteWebAuthorization
4
- } from "./chunk-AEBF6AO2.js";
4
+ } from "./chunk-2MPO25ZZ.js";
5
5
  import {
6
6
  appendAndEnqueueInboundMessage
7
- } from "./chunk-6YXCG2XL.js";
7
+ } from "./chunk-KE5ETKIR.js";
8
8
  import {
9
9
  buildDeliveredTurnStatePatch,
10
10
  completeAuthPauseTurn,
@@ -12,20 +12,20 @@ import {
12
12
  getTurnUserMessage,
13
13
  processPluginTask,
14
14
  scheduleSessionCompletedPluginTasks
15
- } from "./chunk-AQEBOQUC.js";
15
+ } from "./chunk-O5J556I2.js";
16
16
  import {
17
17
  ConversationTurnLifecycleService,
18
18
  coerceThreadConversationState,
19
19
  getPersistedSandboxState,
20
20
  getPersistedThreadState,
21
21
  persistThreadStateById
22
- } from "./chunk-VDNNVTX2.js";
22
+ } from "./chunk-2RSPCWAV.js";
23
23
  import {
24
24
  healthReportSchema
25
25
  } from "./chunk-UTL3MHPC.js";
26
26
  import {
27
27
  parseSlackThreadId
28
- } from "./chunk-3V2EIQLT.js";
28
+ } from "./chunk-TZHLY42G.js";
29
29
  import {
30
30
  TurnInputCommitLostError,
31
31
  abandonTurnRecord,
@@ -49,31 +49,31 @@ import {
49
49
  saveTurnCheckpoint,
50
50
  startActiveTurn,
51
51
  upsertConversationMessage
52
- } from "./chunk-EA4UL5H2.js";
52
+ } from "./chunk-KSQIE2R4.js";
53
53
  import {
54
54
  normalizeSlackConversationId
55
- } from "./chunk-5WDDWMQ7.js";
55
+ } from "./chunk-4KRDL4ZD.js";
56
56
  import {
57
57
  getConversationEventStore,
58
58
  getConversationStore,
59
59
  getDb
60
- } from "./chunk-RQQTOF3H.js";
60
+ } from "./chunk-PMULUKHL.js";
61
61
  import {
62
62
  juniorApiTokens,
63
63
  juniorConversationParticipants,
64
64
  juniorConversations,
65
65
  juniorIdentities,
66
66
  juniorUsers
67
- } from "./chunk-IZHR2OES.js";
67
+ } from "./chunk-YVW44V5Y.js";
68
68
  import {
69
69
  getSlackBotToken
70
- } from "./chunk-FMOFCEAA.js";
70
+ } from "./chunk-MKDIEH3C.js";
71
71
  import {
72
72
  juniorDestinations
73
73
  } from "./chunk-VFUK3X5B.js";
74
74
  import {
75
75
  canExposeConversationPayload
76
- } from "./chunk-ZUKU2Y3J.js";
76
+ } from "./chunk-WZGOP5BZ.js";
77
77
  import {
78
78
  credentialContextForActor
79
79
  } from "./chunk-BDUENQD3.js";
@@ -82,7 +82,7 @@ import {
82
82
  logWarn,
83
83
  setTags,
84
84
  withLogContext
85
- } from "./chunk-32CCG4WP.js";
85
+ } from "./chunk-V7GGA4LW.js";
86
86
 
87
87
  // src/handlers/health.ts
88
88
  function readHealthReport() {
@@ -5,18 +5,18 @@ import {
5
5
  } from "./chunk-BVREIWBD.js";
6
6
  import {
7
7
  getStateAdapter
8
- } from "./chunk-65B3PDY7.js";
8
+ } from "./chunk-W72TSO24.js";
9
9
  import {
10
10
  toOptionalTrimmed
11
- } from "./chunk-FMOFCEAA.js";
11
+ } from "./chunk-MKDIEH3C.js";
12
12
  import {
13
13
  pluginCatalogRuntime
14
- } from "./chunk-7S2JVUWS.js";
14
+ } from "./chunk-L63FA77C.js";
15
15
  import {
16
16
  setSpanAttributes,
17
17
  setSpanStatus,
18
18
  withSpan
19
- } from "./chunk-32CCG4WP.js";
19
+ } from "./chunk-V7GGA4LW.js";
20
20
 
21
21
  // src/chat/sandbox/resources.ts
22
22
  var configuredResources;
@@ -882,7 +882,7 @@ async function stopSession(session) {
882
882
  }
883
883
 
884
884
  // src/chat/sandbox/snapshot/resolve.ts
885
- var SNAPSHOT_CACHE_PREFIX = "junior:sandbox_snapshot_profile";
885
+ var SNAPSHOT_CACHE_PREFIX = "junior:sandbox_snapshot_profile:v2";
886
886
  var SNAPSHOT_LOCK_PREFIX = "junior:sandbox_snapshot_lock";
887
887
  var SNAPSHOT_CACHE_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
888
888
  var SNAPSHOT_BUILD_LOCK_BUFFER_MS = 30 * 1e3;
@@ -892,7 +892,8 @@ var cachedSnapshotSchema = z.object({
892
892
  snapshotId: z.string(),
893
893
  runtime: z.string(),
894
894
  createdAtMs: z.number(),
895
- dependencyCount: z.number()
895
+ dependencyCount: z.number(),
896
+ buildDurationMs: z.number().int().nonnegative()
896
897
  }).strict();
897
898
  function profileCacheKey(profileHash) {
898
899
  return `${SNAPSHOT_CACHE_PREFIX}:${profileHash}`;
@@ -937,6 +938,7 @@ async function build(value, runtime, timeoutMs, signal, prepare) {
937
938
  "app.sandbox.snapshot.dependency_count": value.dependencyCount
938
939
  },
939
940
  async () => {
941
+ const startedAtMs = Date.now();
940
942
  const sandboxCredentials = getVercelSandboxCredentials();
941
943
  const resources = getSandboxResources();
942
944
  const sandbox = createSandboxSession(
@@ -952,7 +954,7 @@ async function build(value, runtime, timeoutMs, signal, prepare) {
952
954
  await dependencies(sandbox, value.dependencies, signal);
953
955
  await postinstall(sandbox, value.postinstall, signal);
954
956
  await prepare?.(sandbox);
955
- return await trace(
957
+ const snapshotId = await trace(
956
958
  "sandbox.snapshot.capture",
957
959
  "sandbox.snapshot.capture",
958
960
  {
@@ -963,6 +965,10 @@ async function build(value, runtime, timeoutMs, signal, prepare) {
963
965
  return snapshot.snapshotId;
964
966
  }
965
967
  );
968
+ return {
969
+ snapshotId,
970
+ buildDurationMs: Math.max(0, Date.now() - startedAtMs)
971
+ };
966
972
  } finally {
967
973
  try {
968
974
  await sandbox.stop();
@@ -1002,7 +1008,9 @@ async function withBuildLock(profileHash, timeoutMs, callback, canUseCachedSnaps
1002
1008
  if (cached2?.snapshotId && canUseCachedSnapshot(cached2)) {
1003
1009
  return {
1004
1010
  snapshotId: cached2.snapshotId,
1005
- source: "cache_hit_after_lock_wait"
1011
+ source: "cache_hit_after_lock_wait",
1012
+ createdAtMs: cached2.createdAtMs,
1013
+ buildDurationMs: cached2.buildDurationMs
1006
1014
  };
1007
1015
  }
1008
1016
  lock = await tryAcquireLock();
@@ -1011,7 +1019,9 @@ async function withBuildLock(profileHash, timeoutMs, callback, canUseCachedSnaps
1011
1019
  const result = await callback();
1012
1020
  return {
1013
1021
  snapshotId: result.snapshotId,
1014
- source: result.source === "built" ? "built" : "cache_hit_after_lock_wait"
1022
+ source: result.source === "built" ? "built" : "cache_hit_after_lock_wait",
1023
+ createdAtMs: result.createdAtMs,
1024
+ buildDurationMs: result.buildDurationMs
1015
1025
  };
1016
1026
  } finally {
1017
1027
  await state.releaseLock(lock);
@@ -1024,7 +1034,9 @@ async function withBuildLock(profileHash, timeoutMs, callback, canUseCachedSnaps
1024
1034
  if (cached?.snapshotId && canUseCachedSnapshot(cached)) {
1025
1035
  return {
1026
1036
  snapshotId: cached.snapshotId,
1027
- source: "cache_hit_after_lock_wait"
1037
+ source: "cache_hit_after_lock_wait",
1038
+ createdAtMs: cached.createdAtMs,
1039
+ buildDurationMs: cached.buildDurationMs
1028
1040
  };
1029
1041
  }
1030
1042
  throw new Error("Timed out waiting for snapshot build lock");
@@ -1079,7 +1091,9 @@ async function resolve(params) {
1079
1091
  profileHash: currentProfile.hash,
1080
1092
  dependencyCount: currentProfile.dependencyCount,
1081
1093
  cacheHit: true,
1082
- resolveOutcome: "cache_hit"
1094
+ resolveOutcome: "cache_hit",
1095
+ createdAtMs: cached.createdAtMs,
1096
+ buildDurationMs: cached.buildDurationMs
1083
1097
  };
1084
1098
  }
1085
1099
  const rebuildReason = getRebuildReason({
@@ -1106,26 +1120,35 @@ async function resolve(params) {
1106
1120
  await params.onProgress?.("cache_hit");
1107
1121
  return {
1108
1122
  snapshotId: latest.snapshotId,
1109
- source: "cache_hit"
1123
+ source: "cache_hit",
1124
+ createdAtMs: latest.createdAtMs,
1125
+ buildDurationMs: latest.buildDurationMs
1110
1126
  };
1111
1127
  }
1112
1128
  await params.onProgress?.("building_snapshot");
1113
- const nextSnapshotId = await build(
1129
+ const built = await build(
1114
1130
  currentProfile,
1115
1131
  params.runtime,
1116
1132
  params.timeoutMs,
1117
1133
  params.signal,
1118
1134
  params.prepareWorkspace
1119
1135
  );
1136
+ const createdAtMs = Date.now();
1120
1137
  await setCachedSnapshot({
1121
1138
  profileHash: currentProfile.hash,
1122
- snapshotId: nextSnapshotId,
1139
+ snapshotId: built.snapshotId,
1123
1140
  runtime: params.runtime,
1124
- createdAtMs: Date.now(),
1125
- dependencyCount: currentProfile.dependencyCount
1141
+ createdAtMs,
1142
+ dependencyCount: currentProfile.dependencyCount,
1143
+ buildDurationMs: built.buildDurationMs
1126
1144
  });
1127
1145
  await params.onProgress?.("build_complete");
1128
- return { snapshotId: nextSnapshotId, source: "built" };
1146
+ return {
1147
+ snapshotId: built.snapshotId,
1148
+ source: "built",
1149
+ createdAtMs,
1150
+ buildDurationMs: built.buildDurationMs
1151
+ };
1129
1152
  },
1130
1153
  canUseCachedSnapshot,
1131
1154
  async () => {
@@ -1142,6 +1165,8 @@ async function resolve(params) {
1142
1165
  Boolean(params.forceRebuild),
1143
1166
  lockResult.source
1144
1167
  ),
1168
+ createdAtMs: lockResult.createdAtMs,
1169
+ buildDurationMs: lockResult.buildDurationMs,
1145
1170
  ...rebuildReason ? { rebuildReason } : {}
1146
1171
  };
1147
1172
  }
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  FUNCTION_TIMEOUT_BUFFER_SECONDS,
3
3
  getChatConfig
4
- } from "./chunk-FMOFCEAA.js";
4
+ } from "./chunk-MKDIEH3C.js";
5
5
 
6
6
  // src/chat/runtime/request-deadline.ts
7
7
  import { AsyncLocalStorage } from "async_hooks";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createAndEnqueueAgentInvocation
3
- } from "./chunk-SA5FVUWJ.js";
3
+ } from "./chunk-IHSPBOWG.js";
4
4
  import {
5
5
  actorFromRun,
6
6
  toolInvocationDestination