@sentry/junior 0.204.0 → 0.206.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 (66) hide show
  1. package/dist/{agent-CMyTD4DD.js → agent-C9yuiZUF.js} +277 -85
  2. package/dist/{agent-hooks-Bbcp9e33.js → agent-hooks-DNjlz2A-.js} +1084 -16
  3. package/dist/{agent-runner-DNb1A49M.js → agent-runner-E67lFrDG.js} +5 -5
  4. package/dist/api/schema.d.ts +85 -0
  5. package/dist/api/schema.js +2 -2
  6. package/dist/api.js +44 -511
  7. package/dist/{app-B1TOqBI8.d.ts → app-AxGmJHwK.d.ts} +8 -0
  8. package/dist/app.d.ts +1 -1
  9. package/dist/app.js +56 -84
  10. package/dist/{auth-pause-state-DosEalIG.js → auth-pause-state-MVZ6xvEK.js} +6 -6
  11. package/dist/briefs-CvJFQvhJ.js +398 -0
  12. package/dist/{catalog-runtime-BReos-D4.js → catalog-runtime-TBR8n4e1.js} +1 -1
  13. package/dist/{checkpoint-CNrPyRJN.js → checkpoint-BY47jJCB.js} +7 -6
  14. package/dist/cli/chat.js +14 -12
  15. package/dist/cli/check.js +3 -3
  16. package/dist/cli/init.js +1 -0
  17. package/dist/cli/main.js +5 -1
  18. package/dist/cli/plugins.js +3 -3
  19. package/dist/cli/run.d.ts +2 -1
  20. package/dist/cli/run.js +2 -1
  21. package/dist/cli/snapshot-create.js +3 -3
  22. package/dist/cli/upgrade.js +3 -3
  23. package/dist/{config-nGCW1OTG.js → client-ceE7NtvC.js} +4 -367
  24. package/dist/config-CIE83sR2.js +386 -0
  25. package/dist/{schema-Rn8-XEaN.js → conversation-AA4R1VUn.js} +580 -558
  26. package/dist/{conversation-privacy-B4voFRSm.js → conversation-privacy-Auyq26XQ.js} +1 -1
  27. package/dist/{credential-sync-kXr1hvO1.js → credential-sync-BO33aNQd.js} +22 -20
  28. package/dist/{execution-stats-DWfSihcH.js → execution-stats-SiS2FLcv.js} +4 -4
  29. package/dist/{executor-DcMSlI5c.js → executor-BfbYPW63.js} +31 -3
  30. package/dist/instrumentation.js +2 -2
  31. package/dist/{job-queue-Drn_LXlM.js → job-queue-CyTc24Es.js} +1 -1
  32. package/dist/{logging-BzAk1S_s.js → logging-D37bayDc.js} +1 -1
  33. package/dist/nitro.d.ts +1 -1
  34. package/dist/nitro.js +3 -3
  35. package/dist/{oauth-callback-server-JiftokvA.js → oauth-callback-server-BtfOeHTZ.js} +2 -2
  36. package/dist/{pending-auth-CWmSdZVg.js → pending-auth-BPUzcs7n.js} +2 -2
  37. package/dist/{profile-CrT5nXbw.js → profile-CSixooTi.js} +4 -3
  38. package/dist/prompt-3gqNY1Ka.js +552 -0
  39. package/dist/{registry-DH1xUo2N.js → registry-DiR0-xRg.js} +1 -1
  40. package/dist/{resolve-CZHnfxaS.js → resolve-Bn5q__9b.js} +2 -2
  41. package/dist/{runner-CZV2sC46.js → runner-DFx3dIJH.js} +9 -9
  42. package/dist/{sandbox-egress-signals-bHZfmhbd.js → sandbox-egress-signals-bwvjihxA.js} +1 -1
  43. package/dist/schema-8GXFfclK.js +559 -0
  44. package/dist/{skills-CIcDQSgM.js → skills-BhM5qyCF.js} +2 -2
  45. package/dist/{spawn-DdkUFRmq.js → spawn-Dk0PqdH6.js} +2 -2
  46. package/dist/{stats-DTUbAb88.js → stats-DKRP4rsY.js} +26 -12
  47. package/dist/{task-queue-CJIR4RF7.js → task-queue-CdpTvu4R.js} +3 -3
  48. package/dist/{task-runner-D-O3A-Cp.js → task-runner-alpjVSxQ.js} +10 -10
  49. package/dist/{thread-state-CRc9jTJS.js → thread-state-CRK7aA41.js} +5 -5
  50. package/dist/{turn-execution-BkinIdJF.js → turn-execution-XtyzIHog.js} +3 -3
  51. package/dist/{turn-lifecycle-DQV19VTW.js → turn-lifecycle-VbwZLfBv.js} +1 -1
  52. package/dist/{usage-D3EbSO7w.js → usage-D4A48Bdl.js} +4 -125
  53. package/dist/{validation-C2CR-OX3.js → validation-jn_46o4U.js} +1 -1
  54. package/dist/{version-DxcWdoKa.js → version-DcfJxB4z.js} +1 -1
  55. package/dist/version.js +1 -1
  56. package/dist/web-authorization-CsfLSfEs.js +38 -0
  57. package/dist/{web-input-3EPfpf55.js → web-input-BPp_sc7t.js} +6 -6
  58. package/dist/{work-fGofI7Op.js → work-Di-ubSGg.js} +9 -9
  59. package/dist/{worker-CsOLq-mR.js → worker-Cu_D5Mr8.js} +5 -4
  60. package/migrations/0040_conversation_briefs.sql +17 -0
  61. package/migrations/meta/0040_snapshot.json +3516 -0
  62. package/migrations/meta/_journal.json +7 -0
  63. package/package.json +4 -4
  64. package/dist/history-CqTuSAdI.js +0 -441
  65. package/dist/usage-schema-CKaDkH_j.js +0 -20
  66. package/dist/web-authorization-RMBxAR_t.js +0 -76
@@ -0,0 +1,398 @@
1
+ import { r as completeObject } from "./client-ceE7NtvC.js";
2
+ import { n as defaultModelId } from "./model-profile-CZmVoGdX.js";
3
+ import { N as parseBriefInput, d as conversationDetailReportSchema, k as briefCodeChangeSchema, p as conversationEventPageSchema } from "./conversation-AA4R1VUn.js";
4
+ import { n as briefEntriesFromReportEvents, s as generateBrief, t as BRIEF_PROMPT } from "./prompt-3gqNY1Ka.js";
5
+ import { CLI_USAGE } from "./cli/run.js";
6
+ import path from "node:path";
7
+ import { z } from "zod";
8
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
9
+ //#region src/chat/briefs/render.ts
10
+ function list(items, empty) {
11
+ return items.length > 0 ? items.map((item) => `- ${item}`).join("\n") : empty;
12
+ }
13
+ function escapeLabel(label) {
14
+ return label.replaceAll("[", "\\[").replaceAll("]", "\\]");
15
+ }
16
+ function formatCost(costUsd) {
17
+ return costUsd === void 0 ? "not reported" : `$${costUsd.toFixed(6)}`;
18
+ }
19
+ function formatCount(count, noun) {
20
+ return `${count} ${noun}${count === 1 ? "" : "s"}`;
21
+ }
22
+ function formatRecordCodeChange(change) {
23
+ const dates = [
24
+ change.openedAt ? `opened ${change.openedAt}` : void 0,
25
+ change.mergedAt ? `merged ${change.mergedAt}` : void 0,
26
+ change.closedAt ? `closed ${change.closedAt}` : void 0
27
+ ].filter((value) => Boolean(value));
28
+ return `[${escapeLabel(`${change.repository}#${change.number}${change.title ? ` · ${change.title}` : ""}`)}](${change.url}) · ${change.state}${dates.length ? ` · ${dates.join(" · ")}` : ""}`;
29
+ }
30
+ /** Render the final Brief and its local evidence check as readable Markdown. */
31
+ function renderBriefMarkdown(args) {
32
+ const { brief, evidence } = args.generation;
33
+ const links = brief.links.map((link) => `[${escapeLabel(link.label)}](${link.url}) · ${link.kind}${link.status ? ` · ${link.status}` : ""}`);
34
+ const dropped = evidence.droppedUrls.length ? evidence.droppedUrls.map((url) => `raw \`${url.raw}\` · normalized \`${url.normalized}\``) : ["None"];
35
+ const record = brief.record;
36
+ const location = record.location ? `${record.location.provider}${record.location.channelName ? ` · ${record.location.channelName}` : ""}` : "None";
37
+ return [
38
+ `# ${args.input.title ?? `Brief ${args.input.conversationId}`}`,
39
+ "",
40
+ "## Record",
41
+ "",
42
+ `- Started: ${record.startedAt}`,
43
+ `- Last activity: ${record.lastActivityAt}`,
44
+ `- Duration: ${record.durationMs} ms`,
45
+ `- Location: ${location}`,
46
+ `- Messages: ${formatCount(record.userMessages, "user message")} · ${formatCount(record.assistantMessages, "assistant message")} · ${formatCount(record.toolResults, "tool result")}`,
47
+ `- Events: ${record.events}`,
48
+ `- Turns: ${record.turns ?? "not reported"}`,
49
+ "- Participants:",
50
+ ...list(record.participants.map((participant) => `${participant.name} · ${participant.messages} message${participant.messages === 1 ? "" : "s"}`), "None.").split("\n").map((line) => ` ${line}`),
51
+ "- Code changes:",
52
+ ...list(record.codeChanges.map(formatRecordCodeChange), "None.").split("\n").map((line) => ` ${line}`),
53
+ "",
54
+ "## Summary",
55
+ "",
56
+ brief.summary,
57
+ "",
58
+ "## Intent",
59
+ "",
60
+ brief.intent,
61
+ "",
62
+ `## Outcome · ${brief.outcome.status}`,
63
+ "",
64
+ brief.outcome.text,
65
+ "",
66
+ "## Decisions",
67
+ "",
68
+ "### Stated",
69
+ "",
70
+ list(brief.decisions.filter((decision) => decision.kind === "stated").map((decision) => `${decision.text}${decision.by ? ` — ${decision.by}` : ""}`), "None."),
71
+ "",
72
+ "### Confirmed",
73
+ "",
74
+ list(brief.decisions.filter((decision) => decision.kind === "confirmed").map((decision) => `${decision.text}${decision.by ? ` — ${decision.by}` : ""}`), "None."),
75
+ "",
76
+ "### Assumed by Junior (not confirmed)",
77
+ "",
78
+ list(brief.decisions.filter((decision) => decision.kind === "assumed").map((decision) => `${decision.text}${decision.by ? ` — ${decision.by}` : ""}`), "None."),
79
+ "",
80
+ "## Open decisions",
81
+ "",
82
+ list(brief.openDecisions.map((decision) => `${decision.text}${decision.owner ? ` — ${decision.owner}` : ""}`), "None."),
83
+ "",
84
+ "## Facts",
85
+ "",
86
+ list(brief.facts, "None."),
87
+ "",
88
+ "## Links",
89
+ "",
90
+ list(links, "None."),
91
+ "",
92
+ "## Keywords",
93
+ "",
94
+ brief.keywords.join(", ") || "None.",
95
+ "",
96
+ "---",
97
+ "",
98
+ "### Evidence check",
99
+ "",
100
+ `- Conversation: \`${args.input.conversationId}\``,
101
+ `- Through index: ${args.generation.throughIndex}`,
102
+ `- Versions generated: ${args.versionCount}`,
103
+ `- Model: \`${args.model}\``,
104
+ `- Code changes: ${evidence.codeChangeCount}`,
105
+ `- Resources: ${evidence.resourceCount}`,
106
+ `- Model URLs: ${evidence.keptUrlCount} kept of ${evidence.citedUrlCount}`,
107
+ `- Coerced decision kinds: ${evidence.coercedDecisionKinds}`,
108
+ `- Dropped attributions: ${evidence.droppedAttributionCount}`,
109
+ `- Dropped runtime-marker items: ${evidence.droppedRuntimeMarkerCount}`,
110
+ `- Merged claim without evidence: ${evidence.mergedClaimWithoutEvidence ? "yes" : "no"}`,
111
+ `- Cost: ${formatCost(args.totalCostUsd)}`,
112
+ "- Dropped URLs:",
113
+ ...dropped.map((url) => ` - ${url}`),
114
+ ""
115
+ ].join("\n");
116
+ }
117
+ //#endregion
118
+ //#region src/chat/briefs/snapshot.ts
119
+ const conversationSnapshotSchema = z.object({
120
+ schemaVersion: z.literal(1),
121
+ pulledAt: z.string().datetime(),
122
+ detail: conversationDetailReportSchema,
123
+ eventPages: z.array(conversationEventPageSchema),
124
+ codeChanges: z.array(briefCodeChangeSchema)
125
+ }).strict();
126
+ /** Create the self-contained wire snapshot used for local Brief replay. */
127
+ function createConversationSnapshot(args) {
128
+ return conversationSnapshotSchema.parse({
129
+ schemaVersion: 1,
130
+ pulledAt: args.pulledAt ?? (/* @__PURE__ */ new Date()).toISOString(),
131
+ detail: args.detail,
132
+ eventPages: args.eventPages,
133
+ codeChanges: args.codeChanges ?? []
134
+ });
135
+ }
136
+ function allEvents(snapshot) {
137
+ const bySequence = /* @__PURE__ */ new Map();
138
+ for (const event of [...snapshot.eventPages.flatMap((page) => page.events), ...snapshot.detail.events]) bySequence.set(event.seq, event);
139
+ return [...bySequence.values()].sort((left, right) => left.seq - right.seq);
140
+ }
141
+ function assertAvailableHistory(snapshot) {
142
+ if ([snapshot.detail.eventHistory, ...snapshot.eventPages.map((page) => page.eventHistory)].some((history) => history.status !== "available")) throw new Error("A Brief snapshot requires available event history");
143
+ }
144
+ function codeChangeAt(change, boundaryMs) {
145
+ if (change.openedAt && Date.parse(change.openedAt) > boundaryMs) return;
146
+ const mergedAt = change.mergedAt && Date.parse(change.mergedAt) <= boundaryMs ? change.mergedAt : void 0;
147
+ const closedAt = change.closedAt && Date.parse(change.closedAt) <= boundaryMs ? change.closedAt : void 0;
148
+ const { mergedAt: _mergedAt, closedAt: _closedAt, ...rest } = change;
149
+ return {
150
+ ...rest,
151
+ state: mergedAt ? "merged" : closedAt ? "closed" : "open",
152
+ ...mergedAt ? { mergedAt } : void 0,
153
+ ...closedAt ? { closedAt } : void 0
154
+ };
155
+ }
156
+ /**
157
+ * Project a downloaded conversation snapshot into generator input. Evidence
158
+ * is limited to what existed at the `throughIndex` event, so a replayed
159
+ * earlier version cannot cite a later pull request or resource.
160
+ */
161
+ function briefInputFromSnapshot(snapshot, throughIndex) {
162
+ assertAvailableHistory(snapshot);
163
+ const detail = snapshot.detail;
164
+ const boundary = allEvents(snapshot).filter((event) => event.seq <= throughIndex).at(-1);
165
+ if (!boundary) throw new Error(`Snapshot has no event at or before index ${throughIndex}`);
166
+ const boundaryMs = Date.parse(boundary.createdAt);
167
+ const channelName = detail.channelName?.trim() || detail.channel?.trim();
168
+ const hasLocation = Boolean(channelName || detail.locationId);
169
+ return parseBriefInput({
170
+ conversationId: detail.conversationId,
171
+ ...detail.displayTitle.trim() ? { title: detail.displayTitle.trim() } : void 0,
172
+ visibility: detail.visibility ?? "public",
173
+ ...hasLocation ? { location: {
174
+ provider: "slack",
175
+ ...channelName ? { channelName } : void 0
176
+ } } : void 0,
177
+ entries: briefEntriesFromReportEvents(allEvents(snapshot)),
178
+ codeChanges: snapshot.codeChanges.flatMap((change) => {
179
+ const bounded = codeChangeAt(change, boundaryMs);
180
+ return bounded ? [bounded] : [];
181
+ }),
182
+ resources: (detail.annotations ?? []).filter((annotation) => Date.parse(annotation.createdAt) <= boundaryMs).map((annotation) => ({
183
+ label: annotation.label,
184
+ url: annotation.url,
185
+ ...annotation.status ? { status: annotation.status } : void 0
186
+ }))
187
+ });
188
+ }
189
+ /** Return the last event index included in a conversation snapshot. */
190
+ function throughIndexFromSnapshot(snapshot) {
191
+ return allEvents(snapshot).at(-1)?.seq;
192
+ }
193
+ /** Return event indexes for turns that reached a successful terminal state. */
194
+ function completedTurnIndexesFromSnapshot(snapshot) {
195
+ return allEvents(snapshot).filter((event) => event.data.type === "turn_lifecycle" && (event.data.state === "succeeded" || event.data.state === "no_reply")).map((event) => event.seq);
196
+ }
197
+ //#endregion
198
+ //#region src/cli/briefs.ts
199
+ /**
200
+ * Local Brief snapshot and replay CLI.
201
+ *
202
+ * This module owns dashboard download pagination and local files. The Brief
203
+ * module owns projection, generation, evidence checks, and rendering.
204
+ */
205
+ function optionValue(argv, index, option) {
206
+ const value = argv[index + 1];
207
+ if (!value || value.startsWith("--")) throw new Error(`${option} requires a value`);
208
+ return value;
209
+ }
210
+ function parsePullOptions(argv) {
211
+ const conversationIds = [];
212
+ let baseUrl;
213
+ let token = process.env.JUNIOR_API_TOKEN?.trim();
214
+ let out;
215
+ for (let index = 0; index < argv.length; index += 1) {
216
+ const argument = argv[index];
217
+ if (argument === "--base-url") {
218
+ baseUrl = optionValue(argv, index, argument);
219
+ index += 1;
220
+ } else if (argument === "--token") {
221
+ token = optionValue(argv, index, argument);
222
+ index += 1;
223
+ } else if (argument === "--out") {
224
+ out = optionValue(argv, index, argument);
225
+ index += 1;
226
+ } else if (argument.startsWith("-")) throw new Error(`Unknown option: ${argument}`);
227
+ else conversationIds.push(argument);
228
+ }
229
+ if (!baseUrl || !token || !out || conversationIds.length === 0) throw new Error(CLI_USAGE);
230
+ return {
231
+ baseUrl,
232
+ conversationIds,
233
+ out,
234
+ token
235
+ };
236
+ }
237
+ async function parseRunOptions(argv) {
238
+ const snapshots = [];
239
+ let model;
240
+ let promptFile;
241
+ let out = process.cwd();
242
+ let turnByTurn = false;
243
+ for (let index = 0; index < argv.length; index += 1) {
244
+ const argument = argv[index];
245
+ if (argument === "--model") {
246
+ model = optionValue(argv, index, argument);
247
+ index += 1;
248
+ } else if (argument === "--prompt") {
249
+ promptFile = optionValue(argv, index, argument);
250
+ index += 1;
251
+ } else if (argument === "--out") {
252
+ out = optionValue(argv, index, argument);
253
+ index += 1;
254
+ } else if (argument === "--turn-by-turn") turnByTurn = true;
255
+ else if (argument.startsWith("-")) throw new Error(`Unknown option: ${argument}`);
256
+ else snapshots.push(argument);
257
+ }
258
+ if (snapshots.length === 0) throw new Error(CLI_USAGE);
259
+ return {
260
+ model: model ?? await configuredDefaultModelId(),
261
+ out,
262
+ promptFile,
263
+ snapshots,
264
+ turnByTurn
265
+ };
266
+ }
267
+ /**
268
+ * Read the app default model only when a run needs it. `chat/config` reads
269
+ * `DATABASE_URL` at import, and `briefs pull` must work with only a token.
270
+ */
271
+ async function configuredDefaultModelId() {
272
+ const { botConfig } = await import("./config-CIE83sR2.js").then((n) => n.r);
273
+ return defaultModelId(botConfig);
274
+ }
275
+ function apiUrl(baseUrl, pathname) {
276
+ const base = new URL(baseUrl);
277
+ base.pathname = `${base.pathname.replace(/\/*$/, "")}/`;
278
+ base.search = "";
279
+ base.hash = "";
280
+ return new URL(pathname.replace(/^\//, ""), base);
281
+ }
282
+ async function fetchJson(url, token) {
283
+ const response = await fetch(url, { headers: {
284
+ accept: "application/json",
285
+ authorization: `Bearer ${token}`
286
+ } });
287
+ if (!response.ok) {
288
+ const body = (await response.text()).trim().slice(0, 500);
289
+ throw new Error(`Dashboard request failed (${response.status} ${response.statusText})${body ? `: ${body}` : ""}`);
290
+ }
291
+ return await response.json();
292
+ }
293
+ async function pullSnapshot(options, conversationId) {
294
+ const detailUrl = apiUrl(options.baseUrl, `api/conversations/${encodeURIComponent(conversationId)}`);
295
+ detailUrl.searchParams.set("limit", "1000");
296
+ const detail = conversationDetailReportSchema.parse(await fetchJson(detailUrl, options.token));
297
+ const eventPages = [];
298
+ const seenCursors = /* @__PURE__ */ new Set();
299
+ let cursor = detail.previousCursor;
300
+ while (cursor) {
301
+ if (seenCursors.has(cursor)) throw new Error(`Conversation ${conversationId} repeated an event cursor`);
302
+ seenCursors.add(cursor);
303
+ const eventsUrl = apiUrl(options.baseUrl, `api/conversations/${encodeURIComponent(conversationId)}/events`);
304
+ eventsUrl.searchParams.set("before", cursor);
305
+ eventsUrl.searchParams.set("limit", "1000");
306
+ const page = conversationEventPageSchema.parse(await fetchJson(eventsUrl, options.token));
307
+ eventPages.push(page);
308
+ cursor = page.previousCursor;
309
+ }
310
+ return createConversationSnapshot({
311
+ detail,
312
+ eventPages
313
+ });
314
+ }
315
+ function fileStem(conversationId) {
316
+ const stem = conversationId.replaceAll(/[\\/\0]/g, "_");
317
+ if (!stem || stem === "." || stem === "..") throw new Error("Conversation id cannot be used as a file name");
318
+ return stem;
319
+ }
320
+ async function pullAll(options) {
321
+ await mkdir(options.out, { recursive: true });
322
+ for (const conversationId of options.conversationIds) {
323
+ const snapshot = await pullSnapshot(options, conversationId);
324
+ const output = path.join(options.out, `${fileStem(snapshot.detail.conversationId)}.snapshot.json`);
325
+ await writeFile(output, `${JSON.stringify(snapshot, void 0, 2)}\n`);
326
+ console.log(output);
327
+ }
328
+ }
329
+ function generationIndexes(snapshot, turnByTurn, throughIndex) {
330
+ if (!turnByTurn) return [throughIndex];
331
+ const indexes = completedTurnIndexesFromSnapshot(snapshot);
332
+ if (indexes.length === 0) throw new Error("Snapshot has no completed turns");
333
+ return indexes;
334
+ }
335
+ async function runSnapshot(snapshotPath, options, prompt) {
336
+ const snapshot = conversationSnapshotSchema.parse(JSON.parse(await readFile(snapshotPath, "utf8")));
337
+ const finalThroughIndex = throughIndexFromSnapshot(snapshot);
338
+ if (finalThroughIndex === void 0) throw new Error(`Snapshot ${snapshotPath} has no Conversation events`);
339
+ const input = briefInputFromSnapshot(snapshot, finalThroughIndex);
340
+ const versions = [];
341
+ for (const throughIndex of generationIndexes(snapshot, options.turnByTurn, finalThroughIndex)) versions.push(await generateBrief({
342
+ completeObject: (request) => completeObject({
343
+ ...request,
344
+ modelId: options.model
345
+ }),
346
+ input: briefInputFromSnapshot(snapshot, throughIndex),
347
+ previous: versions.at(-1)?.brief,
348
+ prompt,
349
+ throughIndex
350
+ }));
351
+ const costs = versions.flatMap((version) => version.costUsd === void 0 ? [] : [version.costUsd]);
352
+ const totalCostUsd = costs.length > 0 ? costs.reduce((sum, cost) => sum + cost, 0) : void 0;
353
+ const stem = fileStem(input.conversationId);
354
+ const jsonPath = path.join(options.out, `${stem}.brief.json`);
355
+ const markdownPath = path.join(options.out, `${stem}.brief.md`);
356
+ const report = {
357
+ schemaVersion: 1,
358
+ conversationId: input.conversationId,
359
+ model: options.model,
360
+ versions,
361
+ ...totalCostUsd !== void 0 ? { totalCostUsd } : void 0
362
+ };
363
+ await Promise.all([writeFile(jsonPath, `${JSON.stringify(report, void 0, 2)}\n`), writeFile(markdownPath, renderBriefMarkdown({
364
+ generation: versions.at(-1),
365
+ input,
366
+ model: options.model,
367
+ totalCostUsd,
368
+ versionCount: versions.length
369
+ }))]);
370
+ console.log(jsonPath);
371
+ console.log(markdownPath);
372
+ }
373
+ async function runAll(options) {
374
+ const prompt = options.promptFile ? await readFile(options.promptFile, "utf8") : BRIEF_PROMPT;
375
+ if (!prompt.trim()) throw new Error("Brief prompt must not be empty");
376
+ await mkdir(options.out, { recursive: true });
377
+ for (const snapshot of options.snapshots) await runSnapshot(snapshot, options, prompt);
378
+ }
379
+ /** Run `junior briefs pull` or `junior briefs run`. */
380
+ async function runBriefs(argv) {
381
+ try {
382
+ const [subcommand, ...rest] = argv;
383
+ if (subcommand === "pull") {
384
+ await pullAll(parsePullOptions(rest));
385
+ return 0;
386
+ }
387
+ if (subcommand === "run") {
388
+ await runAll(await parseRunOptions(rest));
389
+ return 0;
390
+ }
391
+ throw new Error(CLI_USAGE);
392
+ } catch (error) {
393
+ console.error(error instanceof Error ? error.message : String(error));
394
+ return 1;
395
+ }
396
+ }
397
+ //#endregion
398
+ export { runBriefs };
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-B4FMCO8f.js";
2
- import { t as createPluginCatalogRuntime } from "./registry-DH1xUo2N.js";
2
+ import { t as createPluginCatalogRuntime } from "./registry-DiR0-xRg.js";
3
3
  //#region src/chat/plugins/catalog-runtime.ts
4
4
  var catalog_runtime_exports = /* @__PURE__ */ __exportAll({ pluginCatalogRuntime: () => pluginCatalogRuntime });
5
5
  const pluginCatalogRuntime = createPluginCatalogRuntime();
@@ -1,10 +1,11 @@
1
- import { D as unwrapCurrentInstruction, O as escapeXml, b as resolveGatewayModel, n as botConfig, v as completeText } from "./config-nGCW1OTG.js";
2
- import { _ as setSpanAttributes, f as logWarn, o as getActiveTraceId, t as buildTurnFailureResponse, u as logException } from "./logging-BzAk1S_s.js";
1
+ import { i as completeText, m as escapeXml, o as resolveGatewayModel, p as unwrapCurrentInstruction } from "./client-ceE7NtvC.js";
2
+ import { _ as setSpanAttributes, f as logWarn, o as getActiveTraceId, t as buildTurnFailureResponse, u as logException } from "./logging-D37bayDc.js";
3
+ import { n as botConfig } from "./config-CIE83sR2.js";
3
4
  import { _ as parseSlackMessageTs, f as toStoredSlackActor } from "./context-B45_WqVX.js";
4
- import { At as sanitizePostgresJson, Ct as getConversationEventStore, Dt as getSqlExecutor, Nt as bindProviderConversation, Ot as createSqlConversationEventStore, Tt as getConversationStore, kt as withConversationEventLock } from "./agent-hooks-Bbcp9e33.js";
5
- import { d as instructionProvenanceFor, l as contextProvenance, n as agentHistoryItemSchema, u as instructionActors } from "./history-CqTuSAdI.js";
6
- import { c as generateShortTitle, d as agentsInstructionsUpdatedEvent, f as authenticationLinkedEvent, o as ToolInputError, p as authenticationUnlinkedEvent, s as fallbackShortTitle, t as addAgentTurnUsage, u as JUNIOR_NATIVE_EVENT_NAMESPACE } from "./usage-D3EbSO7w.js";
7
- import { A as sleep, D as fenceLock, M as SANDBOX_REPOS_ROOT, P as SANDBOX_WORKSPACE_ROOT, T as MUTATION_LOCK_TTL_MS, k as withLock, w as getStateAdapter } from "./profile-CrT5nXbw.js";
5
+ import { At as authenticationLinkedEvent, Bt as sanitizePostgresJson, Ft as getConversationStore, Lt as getSqlExecutor, Nt as getConversationEventStore, Ot as JUNIOR_NATIVE_EVENT_NAMESPACE, Rt as createSqlConversationEventStore, Ut as bindProviderConversation, jt as authenticationUnlinkedEvent, kt as agentsInstructionsUpdatedEvent, zt as withConversationEventLock } from "./agent-hooks-DNjlz2A-.js";
6
+ import { G as instructionProvenanceFor, I as agentHistoryItemSchema, U as contextProvenance, W as instructionActors } from "./conversation-AA4R1VUn.js";
7
+ import { c as generateShortTitle, o as ToolInputError, s as fallbackShortTitle, t as addAgentTurnUsage } from "./usage-D4A48Bdl.js";
8
+ import { A as sleep, D as fenceLock, M as SANDBOX_REPOS_ROOT, P as SANDBOX_WORKSPACE_ROOT, T as MUTATION_LOCK_TTL_MS, k as withLock, w as getStateAdapter } from "./profile-CSixooTi.js";
8
9
  import path from "node:path";
9
10
  import { isDeepStrictEqual } from "node:util";
10
11
  import { z } from "zod";
package/dist/cli/chat.js CHANGED
@@ -1,5 +1,5 @@
1
- import { t as executeAgentRun } from "../agent-CMyTD4DD.js";
2
- import { t as createAgentRunner } from "../agent-runner-DNb1A49M.js";
1
+ import { t as executeAgentRun } from "../agent-C9yuiZUF.js";
2
+ import { t as createAgentRunner } from "../agent-runner-E67lFrDG.js";
3
3
  import { t as loadAppPluginSet } from "../plugin-module-BKGOXca2.js";
4
4
  import path from "node:path";
5
5
  import { createHash, randomUUID } from "node:crypto";
@@ -101,10 +101,10 @@ async function loadLocalPluginSet() {
101
101
  async function configureLocalChatPlugins(pluginSet) {
102
102
  const [pluginsModule, agentHooksModule, catalogRuntimeModule, validationModule, databaseModule] = await Promise.all([
103
103
  import("../plugins-egKWjgue.js").then((n) => n.o),
104
- import("../agent-hooks-Bbcp9e33.js").then((n) => n.t),
105
- import("../catalog-runtime-BReos-D4.js").then((n) => n.t),
106
- import("../validation-C2CR-OX3.js").then((n) => n.r),
107
- import("../agent-hooks-Bbcp9e33.js").then((n) => n.St)
104
+ import("../agent-hooks-DNjlz2A-.js").then((n) => n.t),
105
+ import("../catalog-runtime-TBR8n4e1.js").then((n) => n.t),
106
+ import("../validation-jn_46o4U.js").then((n) => n.r),
107
+ import("../agent-hooks-DNjlz2A-.js").then((n) => n.Mt)
108
108
  ]);
109
109
  const resolvedPluginSet = pluginSet === void 0 ? await loadLocalPluginSet() : pluginSet ?? void 0;
110
110
  const plugins = pluginsModule.pluginRuntimeRegistrationsFromPluginSet(resolvedPluginSet);
@@ -156,14 +156,16 @@ async function prepareLocalChatRun(io, pluginSet) {
156
156
  await configureLocalChatPlugins(pluginSet);
157
157
  const { setExperimentalFeatures } = await import("../experimental-CIXf7Uye.js").then((n) => n.t);
158
158
  setExperimentalFeatures({ subagents: true });
159
- const { runLocalAgentTurn } = await import("../runner-CZV2sC46.js");
160
- const { startLocalOAuthCallbackServer } = await import("../oauth-callback-server-JiftokvA.js");
159
+ const { setBriefsConfig } = await import("../agent-hooks-DNjlz2A-.js").then((n) => n.m);
160
+ setBriefsConfig({ enabled: true });
161
+ const { runLocalAgentTurn } = await import("../runner-DFx3dIJH.js");
162
+ const { startLocalOAuthCallbackServer } = await import("../oauth-callback-server-BtfOeHTZ.js");
161
163
  const { createLocalOAuthState } = await import("../oauth-relay-CdCnu80W.js").then((n) => n.t);
162
- const { createLocalSandboxEgressSignalTransport } = await import("../sandbox-egress-signals-bHZfmhbd.js");
163
- const { bindSpawnAgent } = await import("../spawn-DdkUFRmq.js").then((n) => n.n);
164
- const { createAgentInvocationWorker, routeAgentInvocationWork } = await import("../work-fGofI7Op.js").then((n) => n.a);
164
+ const { createLocalSandboxEgressSignalTransport } = await import("../sandbox-egress-signals-bwvjihxA.js");
165
+ const { bindSpawnAgent } = await import("../spawn-Dk0PqdH6.js").then((n) => n.n);
166
+ const { createAgentInvocationWorker, routeAgentInvocationWork } = await import("../work-Di-ubSGg.js").then((n) => n.a);
165
167
  const { createLocalConversationWork } = await import("../conversation-work-C6y3T5Hx.js");
166
- const { processConversationWork } = await import("../worker-CsOLq-mR.js").then((n) => n.n);
168
+ const { processConversationWork } = await import("../worker-Cu_D5Mr8.js").then((n) => n.n);
167
169
  let agentRunner;
168
170
  const localConversationWork = createLocalConversationWork(async (message) => {
169
171
  if (!agentRunner) throw new Error("Local agent runner is not ready");
package/dist/cli/check.js CHANGED
@@ -1,6 +1,6 @@
1
- import { E as JUNIOR_HEARTBEAT_ROUTE, j as LEGACY_JUNIOR_CONVERSATION_WORK_FUNCTION, w as JUNIOR_CONVERSATION_WORK_CALLBACK_ROUTE } from "../logging-BzAk1S_s.js";
2
- import { d as parseInlinePluginManifest, f as parsePluginManifest } from "../registry-DH1xUo2N.js";
3
- import { i as parseSkillFile } from "../skills-CIcDQSgM.js";
1
+ import { E as JUNIOR_HEARTBEAT_ROUTE, j as LEGACY_JUNIOR_CONVERSATION_WORK_FUNCTION, w as JUNIOR_CONVERSATION_WORK_CALLBACK_ROUTE } from "../logging-D37bayDc.js";
2
+ import { d as parseInlinePluginManifest, f as parsePluginManifest } from "../registry-DiR0-xRg.js";
3
+ import { i as parseSkillFile } from "../skills-BhM5qyCF.js";
4
4
  import { pathToFileURL } from "node:url";
5
5
  import path from "node:path";
6
6
  import fs from "node:fs/promises";
package/dist/cli/init.js CHANGED
@@ -16,6 +16,7 @@ const [
16
16
  ]);
17
17
 
18
18
  const app = await createApp({
19
+ briefs: { enabled: true },
19
20
  plugins,
20
21
  });
21
22
 
package/dist/cli/main.js CHANGED
@@ -24,6 +24,9 @@ async function runUpgrade(pluginSet) {
24
24
  async function runChat(argv, pluginSet) {
25
25
  return await (await import("./chat.js")).runChat(argv, void 0, { pluginSet });
26
26
  }
27
+ async function runBriefs(argv) {
28
+ return await (await import("../briefs-CvJFQvhJ.js")).runBriefs(argv);
29
+ }
27
30
  function topLevelCommand(argv) {
28
31
  return (argv[0] === "--" ? argv.slice(1) : argv)[0];
29
32
  }
@@ -33,10 +36,11 @@ async function runMain(argv, options = {}) {
33
36
  const instrument = options.instrument ?? true;
34
37
  if (instrument) await initSentry();
35
38
  const command = topLevelCommand(argv);
36
- const cliPluginsModule = command && command !== "init" ? await import("./plugins.js") : void 0;
39
+ const cliPluginsModule = command && command !== "init" && command !== "briefs" ? await import("./plugins.js") : void 0;
37
40
  const pluginSet = cliPluginsModule ? await cliPluginsModule.loadCliPluginSet() ?? null : void 0;
38
41
  const pluginCommands = cliPluginsModule ? await cliPluginsModule.loadCliPluginCommands(pluginSet) : void 0;
39
42
  const exitCode = await runCli(argv, {
43
+ runBriefs,
40
44
  runChat: async (chatArgv) => await runChat(chatArgv, pluginSet),
41
45
  runInit,
42
46
  runSnapshotCreate,
@@ -1,6 +1,6 @@
1
- import { Et as getDb, _t as createPluginLogger, d as setPlugins, f as validatePlugins } from "../agent-hooks-Bbcp9e33.js";
2
- import { n as pluginCatalogRuntime } from "../catalog-runtime-BReos-D4.js";
3
- import { n as validatePluginRegistrations, t as validatePluginEgressCredentialHooks } from "../validation-C2CR-OX3.js";
1
+ import { It as getDb, bt as createPluginLogger, d as setPlugins, f as validatePlugins } from "../agent-hooks-DNjlz2A-.js";
2
+ import { n as pluginCatalogRuntime } from "../catalog-runtime-TBR8n4e1.js";
3
+ import { n as validatePluginRegistrations, t as validatePluginEgressCredentialHooks } from "../validation-jn_46o4U.js";
4
4
  import { a as pluginRuntimeRegistrationsFromPluginSet, i as pluginCliRegistrationsFromPluginSet, r as pluginCatalogConfigFromPluginSet } from "../plugins-egKWjgue.js";
5
5
  import { t as loadAppPluginSet } from "../plugin-module-BKGOXca2.js";
6
6
  import { stderr, stdout } from "node:process";
package/dist/cli/run.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  //#region src/cli/run.d.ts
2
- export declare const CLI_USAGE = "usage: junior init <dir>\n junior snapshot create\n junior check [dir]\n junior upgrade\n junior chat\n junior chat -p <message>";
2
+ export declare const CLI_USAGE = "usage: junior init <dir>\n junior snapshot create\n junior check [dir]\n junior upgrade\n junior chat\n junior chat -p <message>\n junior briefs pull <conversationId...> --base-url <url> [--token <token>] --out <dir>\n junior briefs run <snapshot...> [--model <id>] [--prompt <file>] [--turn-by-turn] [--out <dir>]";
3
3
  interface CliHandlers {
4
+ runBriefs: (argv: string[]) => Promise<number>;
4
5
  runChat: (argv: string[]) => Promise<number>;
5
6
  runInit: (dir: string) => Promise<void>;
6
7
  runSnapshotCreate: () => Promise<void>;
package/dist/cli/run.js CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region src/cli/run.ts
2
- const CLI_USAGE = "usage: junior init <dir>\n junior snapshot create\n junior check [dir]\n junior upgrade\n junior chat\n junior chat -p <message>";
2
+ const CLI_USAGE = "usage: junior init <dir>\n junior snapshot create\n junior check [dir]\n junior upgrade\n junior chat\n junior chat -p <message>\n junior briefs pull <conversationId...> --base-url <url> [--token <token>] --out <dir>\n junior briefs run <snapshot...> [--model <id>] [--prompt <file>] [--turn-by-turn] [--out <dir>]";
3
3
  const DEFAULT_IO = { error: console.error };
4
4
  /** Strip Node's leading argv separator while preserving command-level flags. */
5
5
  function normalizeCliArgv(argv) {
@@ -9,6 +9,7 @@ function normalizeCliArgv(argv) {
9
9
  async function runCli(argv, handlers, io = DEFAULT_IO) {
10
10
  const [command, subcommand, ...rest] = normalizeCliArgv(argv);
11
11
  if (command === "chat") return await handlers.runChat(subcommand === void 0 ? [] : [subcommand, ...rest]);
12
+ if (command === "briefs") return await handlers.runBriefs(subcommand === void 0 ? [] : [subcommand, ...rest]);
12
13
  if (command === "init") {
13
14
  if (!subcommand || rest.length > 0) {
14
15
  io.error(CLI_USAGE);
@@ -1,6 +1,6 @@
1
- import { n as pluginCatalogRuntime } from "../catalog-runtime-BReos-D4.js";
2
- import { S as disconnectStateAdapter, t as create } from "../profile-CrT5nXbw.js";
3
- import { r as resolve } from "../resolve-CZHnfxaS.js";
1
+ import { n as pluginCatalogRuntime } from "../catalog-runtime-TBR8n4e1.js";
2
+ import { S as disconnectStateAdapter, t as create } from "../profile-CSixooTi.js";
3
+ import { r as resolve } from "../resolve-Bn5q__9b.js";
4
4
  //#region src/cli/snapshot-create.ts
5
5
  const DEFAULT_RUNTIME = "node22";
6
6
  const DEFAULT_TIMEOUT_MS = 6e5;
@@ -1,6 +1,6 @@
1
- import { i as getChatConfig } from "../config-nGCW1OTG.js";
2
- import { t as createJuniorSqlExecutor } from "../executor-DcMSlI5c.js";
3
- import { t as createPluginCatalogRuntime } from "../registry-DH1xUo2N.js";
1
+ import { a as getChatConfig } from "../config-CIE83sR2.js";
2
+ import { t as createJuniorSqlExecutor } from "../executor-BfbYPW63.js";
3
+ import { t as createPluginCatalogRuntime } from "../registry-DiR0-xRg.js";
4
4
  import { n as pluginCatalogConfigFromEnv, r as pluginCatalogConfigFromPluginSet, t as defineJuniorPlugins } from "../plugins-egKWjgue.js";
5
5
  import { t as loadAppPluginSet } from "../plugin-module-BKGOXca2.js";
6
6
  import { fileURLToPath } from "node:url";