@sentry/junior 0.132.0 → 0.134.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 (83) hide show
  1. package/dist/{agent-hooks-ONXOJDR6.js → agent-hooks-HGXNYOOD.js} +9 -9
  2. package/dist/api/schema/task.d.ts +60 -0
  3. package/dist/api/schema.d.ts +2 -2
  4. package/dist/api/schema.js +3 -1
  5. package/dist/api.js +90 -20
  6. package/dist/app.js +110 -39
  7. package/dist/{catalog-runtime-BATAY4R7.js → catalog-runtime-P6QHU6XE.js} +5 -5
  8. package/dist/chat/agent/prompt.d.ts +7 -5
  9. package/dist/chat/agent/repository-context.d.ts +20 -0
  10. package/dist/chat/agent/sandbox.d.ts +8 -0
  11. package/dist/chat/agent/tools.d.ts +3 -0
  12. package/dist/chat/config.d.ts +2 -0
  13. package/dist/chat/conversations/projection.d.ts +3 -1
  14. package/dist/chat/conversations/sql/bindings.d.ts +13 -0
  15. package/dist/chat/conversations/sql/store.d.ts +3 -0
  16. package/dist/chat/conversations/store.d.ts +15 -0
  17. package/dist/chat/plugins/agent-hooks.d.ts +2 -2
  18. package/dist/chat/repository-instructions.d.ts +44 -0
  19. package/dist/chat/runtime/reply-executor.d.ts +1 -0
  20. package/dist/chat/runtime/slack-runtime.d.ts +2 -0
  21. package/dist/chat/sandbox/noninteractive-command.d.ts +2 -0
  22. package/dist/chat/sandbox/sandbox.d.ts +3 -0
  23. package/dist/chat/sandbox/session.d.ts +1 -0
  24. package/dist/chat/services/context-compaction.d.ts +1 -0
  25. package/dist/chat/slack/dispatch-turn.d.ts +1 -0
  26. package/dist/chat/slack/reply.d.ts +1 -1
  27. package/dist/chat/slack/tools/user-lookup.d.ts +2 -6
  28. package/dist/chat/tasks/execution-stats.d.ts +29 -0
  29. package/dist/chat/tasks/registered.d.ts +3 -0
  30. package/dist/chat/tools/index.d.ts +2 -0
  31. package/dist/chat/tools/sandbox/bash.d.ts +1 -0
  32. package/dist/chat/tools/system-time.d.ts +11 -1
  33. package/dist/{chunk-O2UXPUVQ.js → chunk-52DIKFJV.js} +14 -6
  34. package/dist/{chunk-GOEZU33G.js → chunk-6T3AYZT7.js} +1 -1
  35. package/dist/{chunk-GPXVDJML.js → chunk-7GKQ7UIO.js} +449 -39
  36. package/dist/{chunk-QVEXYYFM.js → chunk-7UTBPDXK.js} +24 -1
  37. package/dist/{chunk-U76PS7AT.js → chunk-AS3I7OIL.js} +2 -2
  38. package/dist/{chunk-HX236W2U.js → chunk-CDQ4YIZM.js} +9 -0
  39. package/dist/{chunk-ODIP5CEM.js → chunk-FDNAUM7X.js} +32 -32
  40. package/dist/{chunk-GTKNPQNN.js → chunk-FL466XX5.js} +36 -24
  41. package/dist/{chunk-2425Q4OR.js → chunk-GSP5SMZJ.js} +1 -1
  42. package/dist/{chunk-XN656LB4.js → chunk-KWGJG4HO.js} +6 -12
  43. package/dist/{chunk-ISNRPCPG.js → chunk-LKK4XMUV.js} +1 -1
  44. package/dist/{chunk-G3WYA2RS.js → chunk-MFERLE3G.js} +1 -1
  45. package/dist/{chunk-ZMV2YBT6.js → chunk-NF2TNZPD.js} +788 -674
  46. package/dist/chunk-NOA34AJY.js +122 -0
  47. package/dist/{chunk-JYQAE2ZU.js → chunk-NYWSCJVW.js} +1 -1
  48. package/dist/{chunk-KB2M27DL.js → chunk-QLEKAO7O.js} +130 -40
  49. package/dist/{chunk-BKE47OOW.js → chunk-S6DMTEOM.js} +2 -2
  50. package/dist/{chunk-ALDPUN3Z.js → chunk-TR6UEEYD.js} +8 -6
  51. package/dist/{chunk-WEJIS7OC.js → chunk-U3ZI7CCW.js} +1 -1
  52. package/dist/{chunk-B7IY6SVJ.js → chunk-VEGF62FV.js} +1 -1
  53. package/dist/{chunk-SKWIIUS7.js → chunk-VGXJMECA.js} +7 -7
  54. package/dist/{chunk-V44FFBO3.js → chunk-VP6NCPRS.js} +1 -1
  55. package/dist/{chunk-WYQP7QSB.js → chunk-VPYKNCTN.js} +101 -61
  56. package/dist/{chunk-NNHUGGO4.js → chunk-XG5PHKPM.js} +19 -3
  57. package/dist/{chunk-AW5Z3T7V.js → chunk-YNLQQ622.js} +9 -8
  58. package/dist/cli/chat.js +25 -25
  59. package/dist/cli/check.js +6 -6
  60. package/dist/cli/init.js +1 -1
  61. package/dist/cli/plugins.js +12 -12
  62. package/dist/cli/snapshot-create.js +9 -9
  63. package/dist/cli/upgrade.js +9 -8
  64. package/dist/db/executor.d.ts +2 -1
  65. package/dist/db/neon.d.ts +1 -0
  66. package/dist/db/postgres.d.ts +1 -0
  67. package/dist/db/schema/conversation-bindings.d.ts +110 -0
  68. package/dist/db/schema/task-executions.d.ts +110 -0
  69. package/dist/db/schema.d.ts +221 -1
  70. package/dist/{db-QFFZACXF.js → db-GFK4NHWJ.js} +7 -7
  71. package/dist/instrumentation.js +4 -4
  72. package/dist/nitro.js +2 -2
  73. package/dist/{oauth-callback-server-5WXLD533.js → oauth-callback-server-HUJLAQ5N.js} +19 -18
  74. package/dist/{runner-Y3LTUNAA.js → runner-T77AFAH4.js} +13 -12
  75. package/dist/{skills-7M5C24GM.js → skills-3KUFJOOR.js} +6 -6
  76. package/dist/{validation-MRILMYDI.js → validation-FMWDHKYU.js} +6 -6
  77. package/dist/version.js +1 -1
  78. package/migrations/0018_curvy_excalibur.sql +12 -0
  79. package/migrations/0019_lowly_valkyrie.sql +14 -0
  80. package/migrations/meta/0018_snapshot.json +1756 -0
  81. package/migrations/meta/0019_snapshot.json +1904 -0
  82. package/migrations/meta/_journal.json +15 -1
  83. package/package.json +5 -5
@@ -1,12 +1,14 @@
1
1
  import {
2
2
  JUNIOR_NATIVE_EVENT_NAMESPACE,
3
+ ToolInputError,
3
4
  addAgentTurnUsage,
4
5
  agentTurnUsageSchema,
5
6
  authenticationLinkedEvent,
6
7
  authenticationUnlinkedEvent
7
- } from "./chunk-HX236W2U.js";
8
+ } from "./chunk-CDQ4YIZM.js";
8
9
  import {
9
10
  agentHistoryItemSchema,
11
+ bindProviderConversation,
10
12
  contextProvenance,
11
13
  createSqlConversationEventStore,
12
14
  getConversationEventStore,
@@ -16,17 +18,18 @@ import {
16
18
  instructionProvenanceFor,
17
19
  sanitizePostgresJson,
18
20
  withConversationEventLock
19
- } from "./chunk-WYQP7QSB.js";
21
+ } from "./chunk-VPYKNCTN.js";
20
22
  import {
23
+ SANDBOX_WORKSPACE_ROOT,
21
24
  getStateAdapter,
22
25
  sleep
23
- } from "./chunk-ODIP5CEM.js";
26
+ } from "./chunk-FDNAUM7X.js";
24
27
  import {
25
28
  botConfig,
26
29
  escapeXml,
27
30
  resolveGatewayModel,
28
31
  unwrapCurrentInstruction
29
- } from "./chunk-NNHUGGO4.js";
32
+ } from "./chunk-XG5PHKPM.js";
30
33
  import {
31
34
  toStoredSlackActor
32
35
  } from "./chunk-HZF5P5UN.js";
@@ -41,19 +44,35 @@ import {
41
44
  setSpanAttributes,
42
45
  toOptionalNumber,
43
46
  toOptionalString
44
- } from "./chunk-GOEZU33G.js";
47
+ } from "./chunk-6T3AYZT7.js";
45
48
 
46
49
  // src/chat/turn-context-tag.ts
47
50
  var TURN_CONTEXT_TAG = "runtime-turn-context";
48
51
 
49
52
  // src/chat/pi/transcript.ts
50
53
  var RUNTIME_TURN_CONTEXT_START = `<${TURN_CONTEXT_TAG}>`;
54
+ var AGENTS_INSTRUCTIONS_START = "# AGENTS.md instructions";
51
55
  function userMessageContent(message) {
52
56
  const record = message;
53
57
  return record.role === "user" && Array.isArray(record.content) ? record.content : void 0;
54
58
  }
55
59
  function isRuntimeTurnContextPart(part) {
56
- return part !== null && typeof part === "object" && part.type === "text" && typeof part.text === "string" && part.text.startsWith(RUNTIME_TURN_CONTEXT_START);
60
+ return part !== null && typeof part === "object" && part.type === "text" && typeof part.text === "string" && (part.text.startsWith(RUNTIME_TURN_CONTEXT_START) || part.text.startsWith(AGENTS_INSTRUCTIONS_START));
61
+ }
62
+ function hasCurrentInstruction(message) {
63
+ return userMessageContent(message)?.some(
64
+ (part) => part !== null && typeof part === "object" && part.type === "text" && typeof part.text === "string" && part.text.includes("<current-instruction")
65
+ ) ?? false;
66
+ }
67
+ function messageTimestamp(message) {
68
+ return message.timestamp;
69
+ }
70
+ function isStandaloneRuntimeContextMessage(messages, index) {
71
+ const message = messages[index];
72
+ const next = messages[index + 1];
73
+ return Boolean(
74
+ message && next && userMessageContent(message) && userMessageContent(next) && messageTimestamp(message) === messageTimestamp(next) && !hasCurrentInstruction(message) && hasCurrentInstruction(next)
75
+ );
57
76
  }
58
77
  var EMBEDDED_THREAD_CONTEXT_TAGS = [
59
78
  "recent-thread-messages",
@@ -122,11 +141,14 @@ function trimTrailingAssistantMessages(messages) {
122
141
  }
123
142
  function hasRuntimeTurnContext(messages) {
124
143
  return messages.some(
125
- (message) => userMessageContent(message)?.some(isRuntimeTurnContextPart)
144
+ (message, index) => isStandaloneRuntimeContextMessage(messages, index) || userMessageContent(message)?.some(isRuntimeTurnContextPart)
126
145
  );
127
146
  }
128
147
  function retainRuntimeTurnContext(messages) {
129
- return messages.flatMap((message) => {
148
+ return messages.flatMap((message, index) => {
149
+ if (isStandaloneRuntimeContextMessage(messages, index)) {
150
+ return [message];
151
+ }
130
152
  const runtimeContent = userMessageContent(message)?.filter(isRuntimeTurnContextPart) ?? [];
131
153
  return runtimeContent.length > 0 ? [{ ...message, content: runtimeContent }] : [];
132
154
  });
@@ -146,7 +168,10 @@ function getUserMessageInstructionText(message) {
146
168
  return instructionTextForProjection(text).trim();
147
169
  }
148
170
  function stripRuntimeTurnContext(messages) {
149
- return messages.flatMap((message) => {
171
+ return messages.flatMap((message, index) => {
172
+ if (isStandaloneRuntimeContextMessage(messages, index)) {
173
+ return [];
174
+ }
150
175
  const content = userMessageContent(message);
151
176
  if (!content) return [message];
152
177
  const nextContent = content.filter(
@@ -977,7 +1002,7 @@ async function loadConnectedMcpProviders(args) {
977
1002
  );
978
1003
  return connectedMcpProvidersFromEvents(events);
979
1004
  }
980
- function messageTimestamp(message) {
1005
+ function messageTimestamp2(message) {
981
1006
  const timestamp = message.timestamp;
982
1007
  return typeof timestamp === "number" ? timestamp : Date.now();
983
1008
  }
@@ -997,17 +1022,19 @@ async function commitAcceptedReply(args) {
997
1022
  executor,
998
1023
  args.conversationId,
999
1024
  async () => executor.transaction(async () => {
1000
- const agentMessage = normalizeDurableMessage(args.agentMessage);
1001
- await createSqlConversationEventStore(executor).append(
1002
- args.conversationId,
1003
- [
1004
- {
1005
- idempotencyKey: `message:${args.conversationMessageId}:agent`,
1006
- data: historyItemFromPiMessage(agentMessage, contextProvenance),
1007
- createdAtMs: messageTimestamp(agentMessage)
1008
- }
1009
- ]
1010
- );
1025
+ if (args.agentMessage) {
1026
+ const agentMessage = normalizeDurableMessage(args.agentMessage);
1027
+ await createSqlConversationEventStore(executor).append(
1028
+ args.conversationId,
1029
+ [
1030
+ {
1031
+ idempotencyKey: `message:${args.conversationMessageId}:agent`,
1032
+ data: historyItemFromPiMessage(agentMessage, contextProvenance),
1033
+ createdAtMs: messageTimestamp2(agentMessage)
1034
+ }
1035
+ ]
1036
+ );
1037
+ }
1011
1038
  await appendConversationMessages(
1012
1039
  createSqlConversationEventStore(executor),
1013
1040
  {
@@ -1016,6 +1043,12 @@ async function commitAcceptedReply(args) {
1016
1043
  ...args.repliedAtMs === void 0 ? {} : { repliedAtMs: args.repliedAtMs }
1017
1044
  }
1018
1045
  );
1046
+ for (const binding of args.providerConversationBindings ?? []) {
1047
+ await bindProviderConversation(executor, {
1048
+ conversationId: args.conversationId,
1049
+ ...binding
1050
+ });
1051
+ }
1019
1052
  })
1020
1053
  );
1021
1054
  }
@@ -1061,7 +1094,7 @@ async function commitMessagesLocked(args, executor) {
1061
1094
  message,
1062
1095
  nextLocalProvenance[matchingPrefix + index]
1063
1096
  ),
1064
- createdAtMs: messageTimestamp(message)
1097
+ createdAtMs: messageTimestamp2(message)
1065
1098
  })),
1066
1099
  ...turnContextEvents
1067
1100
  ]);
@@ -1390,6 +1423,354 @@ import {
1390
1423
  } from "@sentry/junior-plugin-api";
1391
1424
  import { z as z2 } from "zod";
1392
1425
 
1426
+ // src/chat/repository-instructions.ts
1427
+ import { createHash as createHash2 } from "crypto";
1428
+ import path2 from "path";
1429
+
1430
+ // src/chat/tools/sandbox/file-utils.ts
1431
+ import path from "path";
1432
+ var MAX_TEXT_CHARS = 6e4;
1433
+ var RIPGREP_EXCLUDED_GLOBS = [
1434
+ "!**/.git/**",
1435
+ "!**/node_modules/**"
1436
+ ];
1437
+ var DEFAULT_SEARCH_COMMAND_TIMEOUT_MS = 3e4;
1438
+ var SKIPPED_DIRECTORIES = /* @__PURE__ */ new Set([".git", "node_modules"]);
1439
+ function positiveInteger2(value) {
1440
+ if (typeof value !== "number" || !Number.isFinite(value)) {
1441
+ return void 0;
1442
+ }
1443
+ const integer = Math.floor(value);
1444
+ return integer > 0 ? integer : void 0;
1445
+ }
1446
+ function normalizeToLf(value) {
1447
+ return value.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
1448
+ }
1449
+ function truncateText(value, maxChars = MAX_TEXT_CHARS) {
1450
+ if (value.length <= maxChars) {
1451
+ return { content: value, truncated: false };
1452
+ }
1453
+ const removed = value.length - maxChars;
1454
+ return {
1455
+ content: `${value.slice(0, maxChars)}
1456
+
1457
+ [output truncated: ${removed} characters removed]`,
1458
+ truncated: true
1459
+ };
1460
+ }
1461
+ function isMissingPathError(error) {
1462
+ if (!error || typeof error !== "object") {
1463
+ return false;
1464
+ }
1465
+ const candidate = error;
1466
+ if (candidate.code === "ENOENT") {
1467
+ return true;
1468
+ }
1469
+ return typeof candidate.message === "string" && candidate.message.startsWith("File not found:");
1470
+ }
1471
+ function missingPathSearchResult(params) {
1472
+ const textPath = params.displayPath ?? params.missingPath ?? params.path;
1473
+ throw new ToolInputError(`Path not found: ${textPath}`);
1474
+ }
1475
+ function escapeRegExp(value) {
1476
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1477
+ }
1478
+ function globToRegExp(pattern) {
1479
+ let source = "";
1480
+ for (let index = 0; index < pattern.length; index += 1) {
1481
+ const char = pattern[index];
1482
+ const next = pattern[index + 1];
1483
+ if (char === "*" && next === "*") {
1484
+ if (pattern[index + 2] === "/") {
1485
+ source += "(?:.*/)?";
1486
+ index += 2;
1487
+ continue;
1488
+ }
1489
+ source += ".*";
1490
+ index += 1;
1491
+ continue;
1492
+ }
1493
+ if (char === "*") {
1494
+ source += "[^/]*";
1495
+ continue;
1496
+ }
1497
+ if (char === "?") {
1498
+ source += "[^/]";
1499
+ continue;
1500
+ }
1501
+ source += escapeRegExp(char);
1502
+ }
1503
+ return new RegExp(`^${source}$`);
1504
+ }
1505
+ function matchesGlob(relativePath, pattern) {
1506
+ const matcher = globToRegExp(pattern);
1507
+ if (matcher.test(relativePath)) {
1508
+ return true;
1509
+ }
1510
+ if (pattern.startsWith("**/") && matchesGlob(relativePath, pattern.slice(3))) {
1511
+ return true;
1512
+ }
1513
+ return !pattern.includes("/") && matcher.test(path.posix.basename(relativePath));
1514
+ }
1515
+ function resolveWorkspacePath(input, fallback = ".") {
1516
+ const requested = (input ?? "").trim() || fallback;
1517
+ const absolute = requested.startsWith("/") ? requested : path.posix.join(SANDBOX_WORKSPACE_ROOT, requested);
1518
+ const normalized = path.posix.normalize(absolute);
1519
+ if (normalized !== SANDBOX_WORKSPACE_ROOT && !normalized.startsWith(`${SANDBOX_WORKSPACE_ROOT}/`)) {
1520
+ throw new ToolInputError(
1521
+ `Path must stay within ${SANDBOX_WORKSPACE_ROOT}: ${requested}`
1522
+ );
1523
+ }
1524
+ return normalized;
1525
+ }
1526
+ function getRipgrepSearchLocation(root, rootIsDirectory) {
1527
+ if (rootIsDirectory) {
1528
+ return { cwd: root, target: "." };
1529
+ }
1530
+ return {
1531
+ cwd: path.posix.dirname(root),
1532
+ target: path.posix.basename(root)
1533
+ };
1534
+ }
1535
+ async function collectFiles(params) {
1536
+ const files = [];
1537
+ let limitReached = false;
1538
+ let missingPath;
1539
+ const visit = async (dirPath) => {
1540
+ if (missingPath) {
1541
+ return;
1542
+ }
1543
+ let entries;
1544
+ try {
1545
+ entries = (await params.fs.readdir(dirPath)).sort(
1546
+ (a, b) => a.toLowerCase().localeCompare(b.toLowerCase())
1547
+ );
1548
+ } catch (error) {
1549
+ if (isMissingPathError(error)) {
1550
+ missingPath = dirPath;
1551
+ return;
1552
+ }
1553
+ throw error;
1554
+ }
1555
+ for (const entry of entries) {
1556
+ const fullPath = path.posix.join(dirPath, entry);
1557
+ let stat2;
1558
+ try {
1559
+ stat2 = await params.fs.stat(fullPath);
1560
+ } catch (error) {
1561
+ if (isMissingPathError(error)) {
1562
+ missingPath = fullPath;
1563
+ return;
1564
+ }
1565
+ throw error;
1566
+ }
1567
+ if (stat2.isDirectory()) {
1568
+ if (!SKIPPED_DIRECTORIES.has(entry)) {
1569
+ await visit(fullPath);
1570
+ }
1571
+ if (limitReached) return;
1572
+ continue;
1573
+ }
1574
+ const relativePath = path.posix.relative(params.root, fullPath);
1575
+ if (!params.pattern || matchesGlob(relativePath, params.pattern)) {
1576
+ files.push(fullPath);
1577
+ if (params.limit && files.length >= params.limit) {
1578
+ limitReached = true;
1579
+ return;
1580
+ }
1581
+ }
1582
+ }
1583
+ };
1584
+ let stat;
1585
+ try {
1586
+ stat = await params.fs.stat(params.root);
1587
+ } catch (error) {
1588
+ if (isMissingPathError(error)) {
1589
+ return {
1590
+ files,
1591
+ limitReached: false,
1592
+ missingPath: params.root,
1593
+ missingRoot: true
1594
+ };
1595
+ }
1596
+ throw error;
1597
+ }
1598
+ if (!stat.isDirectory()) {
1599
+ const relativePath = path.posix.basename(params.root);
1600
+ return {
1601
+ files: !params.pattern || matchesGlob(relativePath, params.pattern) ? [params.root] : [],
1602
+ limitReached: false,
1603
+ missingRoot: false
1604
+ };
1605
+ }
1606
+ await visit(params.root);
1607
+ return {
1608
+ files,
1609
+ limitReached,
1610
+ missingPath,
1611
+ missingRoot: missingPath === params.root
1612
+ };
1613
+ }
1614
+
1615
+ // src/chat/repository-instructions.ts
1616
+ var AGENTS_FILENAME = "AGENTS.md";
1617
+ var MAX_REPOSITORY_INSTRUCTIONS_BYTES = 32 * 1024;
1618
+ var AGENTS_REPLACEMENT_NOTICE = "These AGENTS.md instructions replace all previously provided AGENTS.md instructions.";
1619
+ var AGENTS_REMOVAL_NOTICE = "The previously provided AGENTS.md instructions no longer apply.";
1620
+ async function pathExists(fs, target) {
1621
+ try {
1622
+ await fs.stat(target);
1623
+ return true;
1624
+ } catch (error) {
1625
+ if (isMissingPathError(error)) {
1626
+ return false;
1627
+ }
1628
+ throw error;
1629
+ }
1630
+ }
1631
+ async function directoryExists(fs, target) {
1632
+ try {
1633
+ return (await fs.stat(target)).isDirectory();
1634
+ } catch (error) {
1635
+ if (isMissingPathError(error)) {
1636
+ return false;
1637
+ }
1638
+ throw error;
1639
+ }
1640
+ }
1641
+ async function findGitRoot(fs, cwd) {
1642
+ let current = cwd;
1643
+ for (; ; ) {
1644
+ if (await pathExists(fs, path2.posix.join(current, ".git"))) {
1645
+ return current;
1646
+ }
1647
+ if (current === SANDBOX_WORKSPACE_ROOT) {
1648
+ return void 0;
1649
+ }
1650
+ const parent = path2.posix.dirname(current);
1651
+ if (parent === current || parent !== SANDBOX_WORKSPACE_ROOT && !parent.startsWith(`${SANDBOX_WORKSPACE_ROOT}/`)) {
1652
+ return void 0;
1653
+ }
1654
+ current = parent;
1655
+ }
1656
+ }
1657
+ async function findSingleRepositoryDirectory(fs) {
1658
+ const entries = await fs.readdir(SANDBOX_WORKSPACE_ROOT);
1659
+ const repositories = [];
1660
+ for (const entry of entries) {
1661
+ const candidate = path2.posix.join(SANDBOX_WORKSPACE_ROOT, entry);
1662
+ if (await directoryExists(fs, candidate) && await pathExists(fs, path2.posix.join(candidate, ".git"))) {
1663
+ repositories.push(candidate);
1664
+ if (repositories.length > 1) {
1665
+ return void 0;
1666
+ }
1667
+ }
1668
+ }
1669
+ return repositories[0];
1670
+ }
1671
+ async function readInstructionFile(fs, filePath) {
1672
+ try {
1673
+ const content = await fs.readFile(filePath, { encoding: "utf8" });
1674
+ return content.trim() ? content : void 0;
1675
+ } catch (error) {
1676
+ if (isMissingPathError(error)) {
1677
+ return void 0;
1678
+ }
1679
+ throw error;
1680
+ }
1681
+ }
1682
+ async function resolveRepositoryInstructions(args) {
1683
+ const gitRoot = await findGitRoot(args.fs, args.cwd);
1684
+ if (!gitRoot) {
1685
+ return void 0;
1686
+ }
1687
+ const directories = [];
1688
+ let current = args.cwd;
1689
+ for (; ; ) {
1690
+ directories.push(current);
1691
+ if (current === gitRoot) {
1692
+ break;
1693
+ }
1694
+ current = path2.posix.dirname(current);
1695
+ }
1696
+ directories.reverse();
1697
+ const sources = [];
1698
+ let remaining = MAX_REPOSITORY_INSTRUCTIONS_BYTES;
1699
+ for (const directory of directories) {
1700
+ if (remaining <= 0) {
1701
+ break;
1702
+ }
1703
+ const filePath = path2.posix.join(directory, AGENTS_FILENAME);
1704
+ const content = await readInstructionFile(args.fs, filePath);
1705
+ if (!content) {
1706
+ continue;
1707
+ }
1708
+ const bytes = Buffer.from(content, "utf8");
1709
+ const bounded = bytes.length <= remaining ? content : bytes.subarray(0, remaining).toString("utf8");
1710
+ sources.push({ content: bounded, path: filePath });
1711
+ remaining -= Buffer.byteLength(bounded, "utf8");
1712
+ }
1713
+ if (sources.length === 0) {
1714
+ return void 0;
1715
+ }
1716
+ const text = sources.map((source) => source.content).join("\n\n");
1717
+ const fingerprint = createHash2("sha256").update(JSON.stringify({ directory: args.cwd, sources })).digest("hex");
1718
+ return { directory: args.cwd, fingerprint, sources, text };
1719
+ }
1720
+ function renderAgentsInstructions(args) {
1721
+ const directory = args.directory ? ` for ${args.directory}` : "";
1722
+ return `# AGENTS.md instructions${directory}
1723
+
1724
+ <INSTRUCTIONS>
1725
+ ${args.text}
1726
+ </INSTRUCTIONS>`;
1727
+ }
1728
+ function buildAgentsInstructionsMessage(args) {
1729
+ return {
1730
+ role: "user",
1731
+ content: [{ type: "text", text: renderAgentsInstructions(args) }],
1732
+ timestamp: args.timestamp ?? Date.now()
1733
+ };
1734
+ }
1735
+ function findVisibleAgentsInstructions(messages) {
1736
+ for (let messageIndex = messages.length - 1; messageIndex >= 0; messageIndex -= 1) {
1737
+ const message = messages[messageIndex];
1738
+ if (message.role !== "user" || !Array.isArray(message.content)) {
1739
+ continue;
1740
+ }
1741
+ for (let partIndex = message.content.length - 1; partIndex >= 0; partIndex -= 1) {
1742
+ const part = message.content[partIndex];
1743
+ if (part.type !== "text" || typeof part.text !== "string" || !part.text.startsWith("# AGENTS.md instructions")) {
1744
+ continue;
1745
+ }
1746
+ const match = part.text.match(
1747
+ /^# AGENTS\.md instructions(?: for ([^\n]+))?\n\n<INSTRUCTIONS>\n([\s\S]*)\n<\/INSTRUCTIONS>$/
1748
+ );
1749
+ if (!match) {
1750
+ continue;
1751
+ }
1752
+ let text = match[2];
1753
+ if (text === AGENTS_REMOVAL_NOTICE) {
1754
+ return { active: false };
1755
+ }
1756
+ if (text.startsWith(`${AGENTS_REPLACEMENT_NOTICE}
1757
+
1758
+ `)) {
1759
+ text = text.slice(AGENTS_REPLACEMENT_NOTICE.length + 2);
1760
+ }
1761
+ return {
1762
+ active: true,
1763
+ ...match[1] ? { directory: match[1] } : {},
1764
+ text
1765
+ };
1766
+ }
1767
+ }
1768
+ return void 0;
1769
+ }
1770
+ function isAgentsInstructionsMessage(message) {
1771
+ return Boolean(findVisibleAgentsInstructions([message]));
1772
+ }
1773
+
1393
1774
  // src/chat/state/turn-session-keys.ts
1394
1775
  var AGENT_TURN_SESSION_PREFIX = "junior:agent_turn_session";
1395
1776
  function agentTurnSessionKey(conversationId, sessionId) {
@@ -1521,7 +1902,7 @@ async function recordConversationActivityMetadata(args) {
1521
1902
  });
1522
1903
  }
1523
1904
  function materializeAgentTurnSessionRecord(stored, piProjection, turnStartMessageIndex, restoreVolatileContext = true) {
1524
- const piMessages = restoreVolatileContext && (stored.state === "running" || stored.state === "awaiting_resume") ? restoreRuntimeContext(piProjection.messages, stored.runtimeContext) : piProjection.messages;
1905
+ const restoredProjection = restoreVolatileContext && (stored.state === "running" || stored.state === "awaiting_resume") ? restoreRuntimeContext(piProjection, stored.runtimeContext) : piProjection;
1525
1906
  return {
1526
1907
  version: stored.version,
1527
1908
  ...stored.channelName ? { channelName: stored.channelName } : {},
@@ -1532,8 +1913,8 @@ function materializeAgentTurnSessionRecord(stored, piProjection, turnStartMessag
1532
1913
  startedAtMs: stored.startedAtMs,
1533
1914
  lastProgressAtMs: stored.lastProgressAtMs,
1534
1915
  updatedAtMs: stored.updatedAtMs,
1535
- piMessages,
1536
- piMessageProvenance: piProjection.provenance,
1916
+ piMessages: restoredProjection.messages,
1917
+ piMessageProvenance: restoredProjection.provenance,
1537
1918
  actors: stored.actors ?? instructionActors(piProjection.provenance),
1538
1919
  cumulativeDurationMs: stored.cumulativeDurationMs,
1539
1920
  ...stored.destination ? { destination: stored.destination } : {},
@@ -1554,30 +1935,41 @@ function materializeAgentTurnSessionRecord(stored, piProjection, turnStartMessag
1554
1935
  ...turnStartMessageIndex !== void 0 ? { turnStartMessageIndex } : {}
1555
1936
  };
1556
1937
  }
1557
- function restoreRuntimeContext(messages, runtimeContext) {
1558
- if (!runtimeContext || runtimeContext.length === 0) return messages;
1559
- const restored = [...messages];
1938
+ function restoreRuntimeContext(projection, runtimeContext) {
1939
+ if (!runtimeContext || runtimeContext.length === 0) return projection;
1940
+ const restoredMessages = [...projection.messages];
1941
+ const restoredProvenance = [...projection.provenance];
1560
1942
  const unmatchedRuntimeContext = [];
1561
1943
  for (const runtimeMessage of runtimeContext) {
1562
1944
  const runtime = runtimeMessage;
1563
- const targetIndex = restored.findIndex((message) => {
1945
+ const targetIndex = restoredMessages.findIndex((message) => {
1564
1946
  const candidate = message;
1565
1947
  return candidate.role === "user" && candidate.timestamp === runtime.timestamp;
1566
1948
  });
1567
1949
  if (targetIndex < 0) {
1568
- unmatchedRuntimeContext.push(runtimeMessage);
1950
+ if (isAgentsInstructionsMessage(runtimeMessage)) {
1951
+ const followingIndex = restoredMessages.findIndex((message) => {
1952
+ const timestamp = message.timestamp;
1953
+ return typeof runtime.timestamp === "number" && typeof timestamp === "number" && timestamp > runtime.timestamp;
1954
+ });
1955
+ const insertionIndex = followingIndex < 0 ? restoredMessages.length : followingIndex;
1956
+ restoredMessages.splice(insertionIndex, 0, runtimeMessage);
1957
+ restoredProvenance.splice(insertionIndex, 0, contextProvenance);
1958
+ } else {
1959
+ unmatchedRuntimeContext.push(runtimeMessage);
1960
+ }
1569
1961
  continue;
1570
1962
  }
1571
- const target = restored[targetIndex];
1572
- restored[targetIndex] = {
1573
- ...restored[targetIndex],
1574
- content: [
1575
- ...Array.isArray(runtime.content) ? runtime.content : [],
1576
- ...Array.isArray(target.content) ? target.content : []
1577
- ]
1578
- };
1963
+ restoredMessages.splice(targetIndex, 0, runtimeMessage);
1964
+ restoredProvenance.splice(targetIndex, 0, contextProvenance);
1579
1965
  }
1580
- return [...unmatchedRuntimeContext, ...restored];
1966
+ return {
1967
+ messages: [...unmatchedRuntimeContext, ...restoredMessages],
1968
+ provenance: [
1969
+ ...unmatchedRuntimeContext.map(() => contextProvenance),
1970
+ ...restoredProvenance
1971
+ ]
1972
+ };
1581
1973
  }
1582
1974
  async function getStoredAgentTurnSessionRecord(conversationId, sessionId) {
1583
1975
  const stateAdapter = getStateAdapter();
@@ -2935,6 +3327,24 @@ export {
2935
3327
  recordTurnRoute,
2936
3328
  recordToolExecutionStarted,
2937
3329
  recordGuardianActionReviewed,
3330
+ MAX_TEXT_CHARS,
3331
+ RIPGREP_EXCLUDED_GLOBS,
3332
+ DEFAULT_SEARCH_COMMAND_TIMEOUT_MS,
3333
+ positiveInteger2 as positiveInteger,
3334
+ normalizeToLf,
3335
+ truncateText,
3336
+ isMissingPathError,
3337
+ missingPathSearchResult,
3338
+ resolveWorkspacePath,
3339
+ getRipgrepSearchLocation,
3340
+ collectFiles,
3341
+ AGENTS_REPLACEMENT_NOTICE,
3342
+ AGENTS_REMOVAL_NOTICE,
3343
+ findSingleRepositoryDirectory,
3344
+ resolveRepositoryInstructions,
3345
+ renderAgentsInstructions,
3346
+ buildAgentsInstructionsMessage,
3347
+ findVisibleAgentsInstructions,
2938
3348
  buildDeterministicTurnId,
2939
3349
  buildDeterministicAssistantMessageId,
2940
3350
  ConversationTurnBoundaryError,
@@ -604,7 +604,11 @@ var taskSummaryBaseSchema = z7.object({
604
604
  destination: taskDestinationSchema,
605
605
  id: z7.string().min(1),
606
606
  instruction: z7.string().min(1),
607
- ownedByViewer: z7.boolean()
607
+ lastConversationId: z7.string().min(1).optional(),
608
+ lastRunAt: z7.string().datetime().optional(),
609
+ ownedByViewer: z7.boolean(),
610
+ runsLast7Days: z7.number().int().nonnegative(),
611
+ totalRuns: z7.number().int().nonnegative()
608
612
  });
609
613
  var scheduledTaskSummarySchema = taskSummaryBaseSchema.extend({
610
614
  kind: z7.literal("scheduled"),
@@ -623,7 +627,25 @@ var taskSummarySchema = z7.discriminatedUnion("kind", [
623
627
  scheduledTaskSummarySchema,
624
628
  eventTaskSummarySchema
625
629
  ]);
630
+ var registeredTaskSummarySchema = z7.object({
631
+ id: z7.string().min(1),
632
+ lastConversationId: z7.string().min(1).optional(),
633
+ lastRunAt: z7.string().datetime().optional(),
634
+ name: z7.string().min(1),
635
+ pluginDisplayName: z7.string().min(1),
636
+ pluginName: z7.string().min(1),
637
+ runsLast7Days: z7.number().int().nonnegative(),
638
+ totalRuns: z7.number().int().nonnegative()
639
+ }).strict();
640
+ var taskExecutionDaySchema = z7.object({
641
+ date: z7.string().min(1),
642
+ event: z7.number().int().nonnegative(),
643
+ registered: z7.number().int().nonnegative(),
644
+ scheduled: z7.number().int().nonnegative()
645
+ }).strict();
626
646
  var taskListSchema = z7.object({
647
+ executionDays: z7.array(taskExecutionDaySchema),
648
+ registeredTasks: z7.array(registeredTaskSummarySchema),
627
649
  tasks: z7.array(taskSummarySchema),
628
650
  truncated: z7.boolean()
629
651
  }).strict();
@@ -684,6 +706,7 @@ export {
684
706
  scheduledTaskSummarySchema,
685
707
  eventTaskSummarySchema,
686
708
  taskSummarySchema,
709
+ registeredTaskSummarySchema,
687
710
  taskListSchema,
688
711
  taskParamsSchema,
689
712
  statSchema,
@@ -3,10 +3,10 @@ import {
3
3
  } from "./chunk-UTL3MHPC.js";
4
4
  import {
5
5
  parseSlackThreadId
6
- } from "./chunk-G3WYA2RS.js";
6
+ } from "./chunk-MFERLE3G.js";
7
7
  import {
8
8
  normalizeSlackConversationId
9
- } from "./chunk-ALDPUN3Z.js";
9
+ } from "./chunk-TR6UEEYD.js";
10
10
 
11
11
  // src/handlers/health.ts
12
12
  function readHealthReport() {
@@ -164,11 +164,20 @@ function addAgentTurnUsage(...usages) {
164
164
  return hasAgentTurnUsage(result) ? result : void 0;
165
165
  }
166
166
 
167
+ // src/chat/tools/execution/tool-input-error.ts
168
+ var ToolInputError = class extends Error {
169
+ constructor(message, options) {
170
+ super(message, options);
171
+ this.name = "ToolInputError";
172
+ }
173
+ };
174
+
167
175
  export {
168
176
  JUNIOR_NATIVE_EVENT_NAMESPACE,
169
177
  authenticationLinkedEvent,
170
178
  authenticationUnlinkedEvent,
171
179
  renderJuniorNativeConversationEvent,
180
+ ToolInputError,
172
181
  agentTurnUsageSchema,
173
182
  hasAgentTurnUsage,
174
183
  addAgentTurnUsage