@sentry/junior 0.77.0 → 0.79.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.
- package/dist/{agent-hooks-7P2WSR4R.js → agent-hooks-OFDNZJB2.js} +4 -2
- package/dist/api-reference.d.ts +3 -3
- package/dist/app.d.ts +27 -0
- package/dist/app.js +234 -8
- package/dist/build/copy-build-content.d.ts +2 -0
- package/dist/build/virtual-config.d.ts +3 -0
- package/dist/chat/conversations/store.d.ts +1 -1
- package/dist/chat/plugins/agent-hooks.d.ts +7 -1
- package/dist/chat/slack/dashboard-link.d.ts +9 -0
- package/dist/chat/state/session-log.d.ts +84 -0
- package/dist/chat/task-execution/state.d.ts +21 -1
- package/dist/chat/tools/advisor/tool.d.ts +1 -0
- package/dist/{chunk-NYKJ3KON.js → chunk-237T7XAN.js} +3 -3
- package/dist/{chunk-KPL4WJWA.js → chunk-LUNMJQ7D.js} +48 -2
- package/dist/{chunk-W36B5PT4.js → chunk-NNM7YQLL.js} +66 -11
- package/dist/{chunk-TO3UAY2M.js → chunk-R5T7QY3P.js} +175 -7
- package/dist/{chunk-WBSGTHNO.js → chunk-SSWBYEFH.js} +25 -1
- package/dist/cli/chat.js +4 -4
- package/dist/cli/plugins.js +2 -2
- package/dist/cli/upgrade.js +4 -4
- package/dist/{db-7A7PFRGL.js → db-NGQ3JCMF.js} +1 -1
- package/dist/nitro.d.ts +4 -0
- package/dist/nitro.js +59 -3
- package/dist/reporting/conversations.d.ts +30 -0
- package/dist/reporting.d.ts +1 -1
- package/dist/reporting.js +104 -24
- package/dist/{runner-JWLZI3EX.js → runner-GEZ5FN4R.js} +4 -4
- package/package.json +5 -5
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PluginHookDeniedError,
|
|
3
3
|
createPluginHookRunner,
|
|
4
|
+
getPluginDashboardRoutes,
|
|
4
5
|
getPluginOperationalReports,
|
|
5
6
|
getPluginRoutes,
|
|
6
7
|
getPluginSlackConversationLink,
|
|
@@ -10,9 +11,9 @@ import {
|
|
|
10
11
|
getPlugins,
|
|
11
12
|
setPlugins,
|
|
12
13
|
validatePlugins
|
|
13
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-SSWBYEFH.js";
|
|
14
15
|
import "./chunk-RARSKPVT.js";
|
|
15
|
-
import "./chunk-
|
|
16
|
+
import "./chunk-237T7XAN.js";
|
|
16
17
|
import "./chunk-G3E7SCME.js";
|
|
17
18
|
import "./chunk-LXTPBU4K.js";
|
|
18
19
|
import "./chunk-Q6XFTRV5.js";
|
|
@@ -25,6 +26,7 @@ import "./chunk-MLKGABMK.js";
|
|
|
25
26
|
export {
|
|
26
27
|
PluginHookDeniedError,
|
|
27
28
|
createPluginHookRunner,
|
|
29
|
+
getPluginDashboardRoutes,
|
|
28
30
|
getPluginOperationalReports,
|
|
29
31
|
getPluginRoutes,
|
|
30
32
|
getPluginSlackConversationLink,
|
package/dist/api-reference.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
export { createApp } from "./app";
|
|
2
|
-
export type { JuniorAppOptions } from "./app";
|
|
2
|
+
export type { JuniorAppOptions, JuniorDashboardOptions } from "./app";
|
|
3
3
|
export { initSentry } from "./instrumentation";
|
|
4
4
|
export { juniorNitro } from "./nitro";
|
|
5
|
-
export type { JuniorNitroOptions } from "./nitro";
|
|
5
|
+
export type { JuniorNitroDashboardOptions, JuniorNitroOptions } from "./nitro";
|
|
6
6
|
export { defineJuniorPlugins } from "./plugins";
|
|
7
7
|
export type { JuniorPluginInput, JuniorPluginSet, JuniorPluginSetOptions, } from "./plugins";
|
|
8
8
|
export type { PluginRunContext, PluginRunTranscriptEntry, PluginTaskContext, PluginTaskDefinition, PluginTasks, } from "@sentry/junior-plugin-api";
|
|
9
9
|
export { pluginRunContextSchema, pluginRunTranscriptEntrySchema, } from "@sentry/junior-plugin-api";
|
|
10
10
|
export { createJuniorReporting } from "./reporting";
|
|
11
|
-
export type { PluginConversationStatus, PluginConversations, PluginConversationSummary, ConversationFeed, ConversationReport, ConversationReportStatus, ConversationRunReport, ConversationStatsItem, ConversationStatsReport, ConversationSummaryReport, ConversationSurface, ConversationUsage, HealthReport, JuniorReporting, PluginOperationalReport, PluginOperationalReportFeed, PluginPackageContentItemReport, PluginPackageContentReport, PluginReport, RequesterIdentity, RuntimeInfoReport, SkillReport, TranscriptMessage, TranscriptPart, TranscriptPartType, TranscriptRole, } from "./reporting";
|
|
11
|
+
export type { PluginConversationStatus, PluginConversations, PluginConversationSummary, ConversationActivityReport, ConversationActivityStatus, ConversationFeed, ConversationReport, ConversationReportStatus, ConversationRunReport, ConversationSubagentActivityReport, ConversationStatsItem, ConversationStatsReport, ConversationSummaryReport, ConversationSurface, ConversationToolActivityReport, ConversationUsage, HealthReport, JuniorReporting, PluginOperationalReport, PluginOperationalReportFeed, PluginPackageContentItemReport, PluginPackageContentReport, PluginReport, RequesterIdentity, RuntimeInfoReport, SkillReport, TranscriptMessage, TranscriptPart, TranscriptPartType, TranscriptRole, } from "./reporting";
|
|
12
12
|
export { juniorVercelConfig } from "./vercel";
|
|
13
13
|
export type { JuniorVercelConfigOptions } from "./vercel";
|
package/dist/app.d.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
|
+
import type { JuniorReporting } from "./reporting";
|
|
2
3
|
import { type JuniorPluginSet } from "./plugins";
|
|
3
4
|
import { type VercelConversationWorkCallbackOptions } from "@/chat/task-execution/vercel-callback";
|
|
4
5
|
import type { WaitUntilFn } from "@/handlers/types";
|
|
5
6
|
export { defineJuniorPlugins } from "./plugins";
|
|
6
7
|
export type { JuniorPluginInput, JuniorPluginSet, JuniorPluginSetOptions, } from "./plugins";
|
|
7
8
|
export interface JuniorAppOptions {
|
|
9
|
+
/** Authenticated dashboard mounted by core when configured. */
|
|
10
|
+
dashboard?: JuniorDashboardOptions;
|
|
8
11
|
/** Slack-specific overrides applied after env parsing. */
|
|
9
12
|
slack?: {
|
|
10
13
|
/** Slack emoji shown while Junior is processing. Defaults to `eyes`. */
|
|
@@ -29,5 +32,29 @@ export interface JuniorAppOptions {
|
|
|
29
32
|
};
|
|
30
33
|
waitUntil?: WaitUntilFn;
|
|
31
34
|
}
|
|
35
|
+
export interface JuniorDashboardOptions {
|
|
36
|
+
/** Browser auth route prefix used by Better Auth. */
|
|
37
|
+
authPath?: string;
|
|
38
|
+
/** Require a dashboard browser session before serving dashboard pages and APIs. */
|
|
39
|
+
authRequired?: boolean;
|
|
40
|
+
/** Exact Google account emails allowed to open the dashboard. */
|
|
41
|
+
allowedEmails?: string[];
|
|
42
|
+
/** Google Workspace domains allowed to open the dashboard. */
|
|
43
|
+
allowedGoogleDomains?: string[];
|
|
44
|
+
/** Browser route prefix for the dashboard shell. */
|
|
45
|
+
basePath?: string;
|
|
46
|
+
/** Public deployment origin used for auth callbacks and external links. */
|
|
47
|
+
baseURL?: string;
|
|
48
|
+
/** Disable dashboard route mounting while preserving serializable config shape. */
|
|
49
|
+
disabled?: boolean;
|
|
50
|
+
/** Overlay dashboard visual-QA fixture conversations onto real reporting data. */
|
|
51
|
+
mockConversations?: boolean;
|
|
52
|
+
/** Reporting implementation used by dashboard APIs. Defaults to core reporting. */
|
|
53
|
+
reporting?: JuniorReporting;
|
|
54
|
+
/** Browser session lifetime in seconds. */
|
|
55
|
+
sessionMaxAgeSeconds?: number;
|
|
56
|
+
/** Additional trusted origins accepted by Better Auth. */
|
|
57
|
+
trustedOrigins?: string[];
|
|
58
|
+
}
|
|
32
59
|
/** Create a Hono app with all Junior routes. */
|
|
33
60
|
export declare function createApp(options?: JuniorAppOptions): Promise<Hono>;
|
package/dist/app.js
CHANGED
|
@@ -71,7 +71,7 @@ import {
|
|
|
71
71
|
updateConversationStats,
|
|
72
72
|
uploadFilesToThread,
|
|
73
73
|
upsertConversationMessage
|
|
74
|
-
} from "./chunk-
|
|
74
|
+
} from "./chunk-NNM7YQLL.js";
|
|
75
75
|
import {
|
|
76
76
|
CONVERSATION_WORK_CHECK_IN_INTERVAL_MS,
|
|
77
77
|
CONVERSATION_WORK_STALE_ENQUEUE_MS,
|
|
@@ -90,7 +90,7 @@ import {
|
|
|
90
90
|
requestConversationContinuation,
|
|
91
91
|
requestConversationWork,
|
|
92
92
|
startConversationWork
|
|
93
|
-
} from "./chunk-
|
|
93
|
+
} from "./chunk-LUNMJQ7D.js";
|
|
94
94
|
import {
|
|
95
95
|
JUNIOR_THREAD_STATE_TTL_MS,
|
|
96
96
|
coerceThreadConversationState
|
|
@@ -129,7 +129,7 @@ import {
|
|
|
129
129
|
recordAuthorizationCompleted,
|
|
130
130
|
splitSlackReplyText,
|
|
131
131
|
truncateStatusText
|
|
132
|
-
} from "./chunk-
|
|
132
|
+
} from "./chunk-R5T7QY3P.js";
|
|
133
133
|
import {
|
|
134
134
|
validatePluginEgressCredentialHooks,
|
|
135
135
|
validatePluginRegistrations
|
|
@@ -142,13 +142,14 @@ import {
|
|
|
142
142
|
} from "./chunk-SG5WAA7H.js";
|
|
143
143
|
import {
|
|
144
144
|
bindSlackDirectCredentialSubject,
|
|
145
|
+
getPluginDashboardRoutes,
|
|
145
146
|
getPluginRoutes,
|
|
146
147
|
getPluginSlackConversationLink,
|
|
147
148
|
getPlugins,
|
|
148
149
|
setPlugins,
|
|
149
150
|
validatePlugins,
|
|
150
151
|
verifySlackDirectCredentialSubject
|
|
151
|
-
} from "./chunk-
|
|
152
|
+
} from "./chunk-SSWBYEFH.js";
|
|
152
153
|
import {
|
|
153
154
|
createPluginLogger,
|
|
154
155
|
createPluginState
|
|
@@ -156,7 +157,7 @@ import {
|
|
|
156
157
|
import {
|
|
157
158
|
getConversationStore,
|
|
158
159
|
getDb
|
|
159
|
-
} from "./chunk-
|
|
160
|
+
} from "./chunk-237T7XAN.js";
|
|
160
161
|
import "./chunk-G3E7SCME.js";
|
|
161
162
|
import {
|
|
162
163
|
acquireActiveLock,
|
|
@@ -247,8 +248,60 @@ import {
|
|
|
247
248
|
import "./chunk-MLKGABMK.js";
|
|
248
249
|
|
|
249
250
|
// src/app.ts
|
|
251
|
+
import { createRequire } from "module";
|
|
252
|
+
import { pathToFileURL } from "url";
|
|
250
253
|
import { Hono } from "hono";
|
|
251
254
|
|
|
255
|
+
// src/chat/slack/dashboard-link.ts
|
|
256
|
+
var dashboardConversationLinkOptions;
|
|
257
|
+
function withHttps(host) {
|
|
258
|
+
return /^https?:\/\//.test(host) ? host : `https://${host}`;
|
|
259
|
+
}
|
|
260
|
+
function stripTrailingSlashes(value) {
|
|
261
|
+
let end = value.length;
|
|
262
|
+
while (end > 1 && value.charCodeAt(end - 1) === 47) {
|
|
263
|
+
end -= 1;
|
|
264
|
+
}
|
|
265
|
+
return end === value.length ? value : value.slice(0, end);
|
|
266
|
+
}
|
|
267
|
+
function normalizeDashboardPath(path2, fallback) {
|
|
268
|
+
const value = path2?.trim() || fallback;
|
|
269
|
+
const withSlash = value.startsWith("/") ? value : `/${value}`;
|
|
270
|
+
return stripTrailingSlashes(withSlash);
|
|
271
|
+
}
|
|
272
|
+
function resolveDashboardBaseURL(config) {
|
|
273
|
+
const explicit = config.baseURL ?? process.env.BETTER_AUTH_URL ?? process.env.JUNIOR_BASE_URL;
|
|
274
|
+
if (explicit?.trim()) {
|
|
275
|
+
return stripTrailingSlashes(withHttps(explicit.trim()));
|
|
276
|
+
}
|
|
277
|
+
const vercelProd = process.env.VERCEL_PROJECT_PRODUCTION_URL?.trim();
|
|
278
|
+
if (vercelProd) {
|
|
279
|
+
return stripTrailingSlashes(withHttps(vercelProd));
|
|
280
|
+
}
|
|
281
|
+
const vercelUrl = process.env.VERCEL_URL?.trim();
|
|
282
|
+
if (vercelUrl) {
|
|
283
|
+
return stripTrailingSlashes(withHttps(vercelUrl));
|
|
284
|
+
}
|
|
285
|
+
return "http://localhost:3000";
|
|
286
|
+
}
|
|
287
|
+
function setDashboardConversationLinkOptions(options) {
|
|
288
|
+
const previous = dashboardConversationLinkOptions;
|
|
289
|
+
dashboardConversationLinkOptions = options?.disabled ? void 0 : options;
|
|
290
|
+
return previous;
|
|
291
|
+
}
|
|
292
|
+
function getDashboardConversationLink(conversationId) {
|
|
293
|
+
if (!dashboardConversationLinkOptions) {
|
|
294
|
+
return void 0;
|
|
295
|
+
}
|
|
296
|
+
const baseURL = resolveDashboardBaseURL(dashboardConversationLinkOptions);
|
|
297
|
+
const basePath = normalizeDashboardPath(
|
|
298
|
+
dashboardConversationLinkOptions.basePath,
|
|
299
|
+
"/"
|
|
300
|
+
);
|
|
301
|
+
const path2 = basePath === "/" ? `/conversations/${encodeURIComponent(conversationId)}` : `${basePath}/conversations/${encodeURIComponent(conversationId)}`;
|
|
302
|
+
return `${baseURL}${path2}`;
|
|
303
|
+
}
|
|
304
|
+
|
|
252
305
|
// src/chat/slack/reply.ts
|
|
253
306
|
import { Buffer as Buffer2 } from "buffer";
|
|
254
307
|
|
|
@@ -267,7 +320,7 @@ function buildSlackReplyFooter(args) {
|
|
|
267
320
|
label: "ID",
|
|
268
321
|
value: conversationId
|
|
269
322
|
};
|
|
270
|
-
const conversationUrl = getPluginSlackConversationLink(conversationId)?.url ?? buildSentryConversationUrl(conversationId);
|
|
323
|
+
const conversationUrl = getPluginSlackConversationLink(conversationId)?.url ?? getDashboardConversationLink(conversationId) ?? buildSentryConversationUrl(conversationId);
|
|
271
324
|
if (conversationUrl) {
|
|
272
325
|
idItem.url = conversationUrl;
|
|
273
326
|
}
|
|
@@ -11158,6 +11211,7 @@ function createProductionConversationWorkOptions(options) {
|
|
|
11158
11211
|
}
|
|
11159
11212
|
|
|
11160
11213
|
// src/app.ts
|
|
11214
|
+
var DASHBOARD_PACKAGE_NAME = "@sentry/junior-dashboard";
|
|
11161
11215
|
async function defaultWaitUntil() {
|
|
11162
11216
|
try {
|
|
11163
11217
|
const { waitUntil } = await import("@vercel/functions");
|
|
@@ -11176,6 +11230,8 @@ async function resolveVirtualConfig() {
|
|
|
11176
11230
|
try {
|
|
11177
11231
|
const mod = await import("#junior/config");
|
|
11178
11232
|
return {
|
|
11233
|
+
createDashboardApp: mod.createDashboardApp,
|
|
11234
|
+
dashboard: mod.dashboard,
|
|
11179
11235
|
pluginSet: mod.pluginSet,
|
|
11180
11236
|
plugins: mod.plugins,
|
|
11181
11237
|
pluginRuntimeRegistrations: mod.pluginRuntimeRegistrations ?? []
|
|
@@ -11238,7 +11294,161 @@ function validateBuildIncludesPluginRuntimeRegistrations(runtimeRegistrations, v
|
|
|
11238
11294
|
`createApp() is missing plugin registration(s) with runtime code bundled by juniorNitro(): ${missing.join(", ")}. Pass a runtime-safe plugin module to juniorNitro({ plugins: "./plugins" }) or pass the same defineJuniorPlugins(...) set to createApp({ plugins }).`
|
|
11239
11295
|
);
|
|
11240
11296
|
}
|
|
11241
|
-
function
|
|
11297
|
+
async function createDashboardRouteRegistrations(args) {
|
|
11298
|
+
if (!args.dashboard || args.dashboard.disabled) {
|
|
11299
|
+
return [];
|
|
11300
|
+
}
|
|
11301
|
+
const createDashboardApp = args.createDashboardApp ?? await loadDashboardAppFactory();
|
|
11302
|
+
return dashboardRouteRegistrations({
|
|
11303
|
+
dashboard: args.dashboard,
|
|
11304
|
+
createDashboardApp,
|
|
11305
|
+
pluginRoutes: args.pluginRoutes
|
|
11306
|
+
});
|
|
11307
|
+
}
|
|
11308
|
+
async function loadDashboardAppFactory() {
|
|
11309
|
+
try {
|
|
11310
|
+
const appRequire = createRequire(`${process.cwd()}/package.json`);
|
|
11311
|
+
const mod = await import(pathToFileURL(appRequire.resolve(DASHBOARD_PACKAGE_NAME)).href);
|
|
11312
|
+
return dashboardAppFactoryFromModule(mod);
|
|
11313
|
+
} catch (error) {
|
|
11314
|
+
if (isMissingDashboardPackage(error)) {
|
|
11315
|
+
throw new Error(
|
|
11316
|
+
'createApp({ dashboard }) requires installing "@sentry/junior-dashboard"',
|
|
11317
|
+
{ cause: error }
|
|
11318
|
+
);
|
|
11319
|
+
}
|
|
11320
|
+
throw error;
|
|
11321
|
+
}
|
|
11322
|
+
}
|
|
11323
|
+
function dashboardAppFactoryFromModule(mod) {
|
|
11324
|
+
if (!mod || typeof mod !== "object" || typeof mod.createDashboardApp !== "function") {
|
|
11325
|
+
throw new Error(
|
|
11326
|
+
'@sentry/junior-dashboard must export a "createDashboardApp" function'
|
|
11327
|
+
);
|
|
11328
|
+
}
|
|
11329
|
+
return mod.createDashboardApp;
|
|
11330
|
+
}
|
|
11331
|
+
function isMissingDashboardPackage(error) {
|
|
11332
|
+
if (!(error instanceof Error)) {
|
|
11333
|
+
return false;
|
|
11334
|
+
}
|
|
11335
|
+
const code = error.code;
|
|
11336
|
+
return (code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND") && error.message.includes("@sentry/junior-dashboard");
|
|
11337
|
+
}
|
|
11338
|
+
function stripTrailingSlashes2(value) {
|
|
11339
|
+
let end = value.length;
|
|
11340
|
+
while (end > 1 && value.charCodeAt(end - 1) === 47) {
|
|
11341
|
+
end -= 1;
|
|
11342
|
+
}
|
|
11343
|
+
return end === value.length ? value : value.slice(0, end);
|
|
11344
|
+
}
|
|
11345
|
+
function normalizeDashboardPath2(path2, fallback) {
|
|
11346
|
+
const value = path2?.trim() || fallback;
|
|
11347
|
+
const withSlash = value.startsWith("/") ? value : `/${value}`;
|
|
11348
|
+
return stripTrailingSlashes2(withSlash);
|
|
11349
|
+
}
|
|
11350
|
+
function dashboardHostRoutePaths(dashboard) {
|
|
11351
|
+
const basePath = normalizeDashboardPath2(dashboard.basePath, "/");
|
|
11352
|
+
const authPath = normalizeDashboardPath2(dashboard.authPath, "/api/auth");
|
|
11353
|
+
const pagePaths = basePath === "/" ? [
|
|
11354
|
+
"/",
|
|
11355
|
+
"/conversations",
|
|
11356
|
+
"/conversations/*",
|
|
11357
|
+
"/plugins",
|
|
11358
|
+
"/plugins/*",
|
|
11359
|
+
"/sessions",
|
|
11360
|
+
"/sessions/*"
|
|
11361
|
+
] : [basePath, `${basePath}/*`];
|
|
11362
|
+
return [
|
|
11363
|
+
...pagePaths,
|
|
11364
|
+
"/favicon.ico",
|
|
11365
|
+
"/api/dashboard",
|
|
11366
|
+
"/api/dashboard/*",
|
|
11367
|
+
authPath,
|
|
11368
|
+
`${authPath}/*`
|
|
11369
|
+
];
|
|
11370
|
+
}
|
|
11371
|
+
function routePrefixCoversPath(routePrefix, path2) {
|
|
11372
|
+
return routePrefix === "/" || path2 === routePrefix || path2.startsWith(`${routePrefix}/`);
|
|
11373
|
+
}
|
|
11374
|
+
function routeSegments(path2) {
|
|
11375
|
+
return normalizeDashboardPath2(path2, "/").split("/").filter(Boolean);
|
|
11376
|
+
}
|
|
11377
|
+
function routeSegmentMatches(pattern, value) {
|
|
11378
|
+
return pattern === value || pattern === "*" || pattern.startsWith(":");
|
|
11379
|
+
}
|
|
11380
|
+
function routePatternMatchesConcretePath(pattern, concretePath) {
|
|
11381
|
+
const patternSegments = routeSegments(pattern);
|
|
11382
|
+
const pathSegments = routeSegments(concretePath);
|
|
11383
|
+
for (let index = 0; index < patternSegments.length; index += 1) {
|
|
11384
|
+
const segment = patternSegments[index];
|
|
11385
|
+
if (segment === "**" || segment === "*") {
|
|
11386
|
+
return true;
|
|
11387
|
+
}
|
|
11388
|
+
const value = pathSegments[index];
|
|
11389
|
+
if (!value || !routeSegmentMatches(segment, value)) {
|
|
11390
|
+
return false;
|
|
11391
|
+
}
|
|
11392
|
+
}
|
|
11393
|
+
return patternSegments.length === pathSegments.length;
|
|
11394
|
+
}
|
|
11395
|
+
function routePatternExamples(routePath) {
|
|
11396
|
+
const normalized = normalizeDashboardPath2(routePath, "/");
|
|
11397
|
+
if (!normalized.endsWith("/*") && !normalized.endsWith("/**")) {
|
|
11398
|
+
return [normalized];
|
|
11399
|
+
}
|
|
11400
|
+
const prefix = normalizeDashboardPath2(
|
|
11401
|
+
normalized.endsWith("/*") ? normalized.slice(0, -2) : normalized.slice(0, -3),
|
|
11402
|
+
"/"
|
|
11403
|
+
);
|
|
11404
|
+
return [
|
|
11405
|
+
prefix,
|
|
11406
|
+
prefix === "/" ? "/__dashboard__" : `${prefix}/__dashboard__`
|
|
11407
|
+
];
|
|
11408
|
+
}
|
|
11409
|
+
function routePatternOverlaps(ownedPath, routePath) {
|
|
11410
|
+
if (ownedPath.endsWith("/*") && routePrefixCoversPath(ownedPath.slice(0, -2), routePath)) {
|
|
11411
|
+
return true;
|
|
11412
|
+
}
|
|
11413
|
+
return routePatternExamples(ownedPath).some(
|
|
11414
|
+
(example) => routePatternMatchesConcretePath(routePath, example)
|
|
11415
|
+
);
|
|
11416
|
+
}
|
|
11417
|
+
function dashboardOwnedRoutePath(routePath, dashboard) {
|
|
11418
|
+
return dashboardHostRoutePaths(dashboard).some(
|
|
11419
|
+
(path2) => routePatternOverlaps(path2, routePath)
|
|
11420
|
+
);
|
|
11421
|
+
}
|
|
11422
|
+
function dashboardRouteRegistrations(args) {
|
|
11423
|
+
let app;
|
|
11424
|
+
const fetch2 = (request) => {
|
|
11425
|
+
app ??= args.createDashboardApp({
|
|
11426
|
+
...args.dashboard,
|
|
11427
|
+
pluginRoutes: args.pluginRoutes
|
|
11428
|
+
});
|
|
11429
|
+
if (!app || typeof app.fetch !== "function") {
|
|
11430
|
+
throw new Error("createDashboardApp() must return an app with fetch()");
|
|
11431
|
+
}
|
|
11432
|
+
return app.fetch(request);
|
|
11433
|
+
};
|
|
11434
|
+
return dashboardHostRoutePaths(args.dashboard).map((path2) => ({
|
|
11435
|
+
handler: fetch2,
|
|
11436
|
+
path: path2
|
|
11437
|
+
}));
|
|
11438
|
+
}
|
|
11439
|
+
function validateDashboardRouteOwnership(args) {
|
|
11440
|
+
if (!args.dashboard || args.dashboard.disabled) {
|
|
11441
|
+
return;
|
|
11442
|
+
}
|
|
11443
|
+
for (const route of args.routes) {
|
|
11444
|
+
if (dashboardOwnedRoutePath(route.path, args.dashboard)) {
|
|
11445
|
+
throw new Error(
|
|
11446
|
+
`Plugin "${route.pluginName}" route "${route.path}" conflicts with core dashboard routes`
|
|
11447
|
+
);
|
|
11448
|
+
}
|
|
11449
|
+
}
|
|
11450
|
+
}
|
|
11451
|
+
function mountRoutes(app, routes) {
|
|
11242
11452
|
for (const route of routes) {
|
|
11243
11453
|
const handler = (c) => route.handler(c.req.raw);
|
|
11244
11454
|
const methods = Array.isArray(route.method) ? route.method : [route.method ?? "ALL"];
|
|
@@ -11254,6 +11464,7 @@ function mountPluginRoutes(app, routes) {
|
|
|
11254
11464
|
}
|
|
11255
11465
|
async function createApp(options) {
|
|
11256
11466
|
const virtualConfig = await resolveVirtualConfig();
|
|
11467
|
+
const dashboard = options?.dashboard ?? virtualConfig?.dashboard;
|
|
11257
11468
|
const configuredPlugins = options?.plugins ?? virtualConfig?.pluginSet;
|
|
11258
11469
|
const plugins = pluginRuntimeRegistrationsFromPluginSet(configuredPlugins);
|
|
11259
11470
|
const pluginConfig = configuredPlugins ? pluginCatalogConfigFromPluginSet(configuredPlugins) : virtualConfig?.plugins ?? pluginCatalogConfigFromEnv();
|
|
@@ -11268,7 +11479,9 @@ async function createApp(options) {
|
|
|
11268
11479
|
const previousPlugins = setPlugins(plugins);
|
|
11269
11480
|
const previousConfigDefaults = getConfigDefaults();
|
|
11270
11481
|
const previousSlackReactionConfig = getSlackReactionConfig();
|
|
11482
|
+
const previousDashboardLinkOptions = setDashboardConversationLinkOptions(dashboard);
|
|
11271
11483
|
let pluginRoutes = [];
|
|
11484
|
+
let pluginDashboardRoutes = [];
|
|
11272
11485
|
let sandboxEgressTracePropagationDomains = [];
|
|
11273
11486
|
try {
|
|
11274
11487
|
sandboxEgressTracePropagationDomains = normalizeSandboxEgressTracePropagationDomains(
|
|
@@ -11286,11 +11499,16 @@ async function createApp(options) {
|
|
|
11286
11499
|
);
|
|
11287
11500
|
}
|
|
11288
11501
|
pluginRoutes = getPluginRoutes();
|
|
11502
|
+
validateDashboardRouteOwnership({ dashboard, routes: pluginRoutes });
|
|
11503
|
+
if (dashboard && !dashboard.disabled) {
|
|
11504
|
+
pluginDashboardRoutes = getPluginDashboardRoutes();
|
|
11505
|
+
}
|
|
11289
11506
|
} catch (error) {
|
|
11290
11507
|
setPluginCatalogConfig(previousPluginCatalogConfig);
|
|
11291
11508
|
setPlugins(previousPlugins);
|
|
11292
11509
|
setConfigDefaults(previousConfigDefaults);
|
|
11293
11510
|
setSlackReactionConfig(previousSlackReactionConfig);
|
|
11511
|
+
setDashboardConversationLinkOptions(previousDashboardLinkOptions);
|
|
11294
11512
|
throw error;
|
|
11295
11513
|
}
|
|
11296
11514
|
const waitUntil = options?.waitUntil ?? await defaultWaitUntil();
|
|
@@ -11318,7 +11536,15 @@ async function createApp(options) {
|
|
|
11318
11536
|
next
|
|
11319
11537
|
);
|
|
11320
11538
|
});
|
|
11321
|
-
|
|
11539
|
+
mountRoutes(app, pluginRoutes);
|
|
11540
|
+
mountRoutes(
|
|
11541
|
+
app,
|
|
11542
|
+
await createDashboardRouteRegistrations({
|
|
11543
|
+
dashboard,
|
|
11544
|
+
createDashboardApp: virtualConfig?.createDashboardApp,
|
|
11545
|
+
pluginRoutes: pluginDashboardRoutes
|
|
11546
|
+
})
|
|
11547
|
+
);
|
|
11322
11548
|
app.get("/", () => GET());
|
|
11323
11549
|
app.get("/health", () => GET());
|
|
11324
11550
|
app.get("/api/oauth/callback/mcp/:provider", (c) => {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
/** Copy app and declared plugin package content into the server output. */
|
|
2
2
|
export declare function copyAppAndPluginContent(cwd: string, serverRoot: string, packageNames?: unknown): void;
|
|
3
|
+
/** Copy dashboard browser assets when core dashboard routes are enabled. */
|
|
4
|
+
export declare function copyDashboardAssets(cwd: string, serverRoot: string): void;
|
|
3
5
|
/** Copy extra file patterns into server output for files the bundler cannot trace. */
|
|
4
6
|
export declare function copyIncludedFiles(cwd: string, serverRoot: string, patterns?: unknown): void;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Nitro } from "nitro/types";
|
|
2
2
|
import type { PluginCatalogConfig } from "@/chat/plugins/types";
|
|
3
|
+
import type { JuniorDashboardOptions } from "@/app";
|
|
3
4
|
import { type JuniorPluginSet } from "@/plugins";
|
|
4
5
|
export interface RuntimePluginModule {
|
|
5
6
|
exportName: string;
|
|
@@ -7,6 +8,7 @@ export interface RuntimePluginModule {
|
|
|
7
8
|
}
|
|
8
9
|
/** Render the virtual config module consumed by createApp(). */
|
|
9
10
|
export declare function renderVirtualConfig(options: {
|
|
11
|
+
dashboard?: Omit<JuniorDashboardOptions, "reporting">;
|
|
10
12
|
plugins?: PluginCatalogConfig;
|
|
11
13
|
pluginModule?: RuntimePluginModule;
|
|
12
14
|
pluginRuntimeRegistrations?: string[];
|
|
@@ -17,4 +19,5 @@ export declare function injectVirtualConfig(nitro: Nitro, options?: {
|
|
|
17
19
|
pluginModule?: RuntimePluginModule;
|
|
18
20
|
plugins?: PluginCatalogConfig;
|
|
19
21
|
pluginRuntimeRegistrations?: string[];
|
|
22
|
+
dashboard?: Omit<JuniorDashboardOptions, "reporting">;
|
|
20
23
|
}): void;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Destination } from "@sentry/junior-plugin-api";
|
|
2
2
|
import type { StoredSlackRequester } from "@/chat/requester";
|
|
3
3
|
export type ConversationSource = "api" | "internal" | "local" | "plugin" | "scheduler" | "slack";
|
|
4
|
-
export type ConversationStatus = "awaiting_resume" | "idle" | "pending" | "running";
|
|
4
|
+
export type ConversationStatus = "awaiting_resume" | "failed" | "idle" | "pending" | "running";
|
|
5
5
|
export interface ConversationExecution {
|
|
6
6
|
lastCheckpointAtMs?: number;
|
|
7
7
|
lastEnqueuedAtMs?: number;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PluginConversations, PluginRoute, PluginOperationalReport, SlackConversationLink, PluginRegistration } from "@sentry/junior-plugin-api";
|
|
1
|
+
import type { PluginConversations, PluginRoute, PluginOperationalReport, PluginRouteApp, SlackConversationLink, PluginRegistration } from "@sentry/junior-plugin-api";
|
|
2
2
|
import type { PluginPromptContributionContext } from "@/chat/plugins/prompt";
|
|
3
3
|
import type { ToolDefinition } from "@/chat/tools/definition";
|
|
4
4
|
import type { ToolRuntimeContext } from "@/chat/tools/types";
|
|
@@ -19,6 +19,10 @@ export interface ToolHookResult {
|
|
|
19
19
|
export interface PluginRouteRegistration extends PluginRoute {
|
|
20
20
|
pluginName: string;
|
|
21
21
|
}
|
|
22
|
+
export interface PluginDashboardRouteRegistration {
|
|
23
|
+
app: PluginRouteApp;
|
|
24
|
+
pluginName: string;
|
|
25
|
+
}
|
|
22
26
|
export interface PluginHookRunner {
|
|
23
27
|
beforeToolExecute(input: ToolHookInput): Promise<ToolHookResult>;
|
|
24
28
|
prepareSandbox(sandbox: SandboxInstance): Promise<void>;
|
|
@@ -39,6 +43,8 @@ export declare function getPluginUserPromptContributions(args: {
|
|
|
39
43
|
export declare function getPluginTools(context: ToolRuntimeContext): Record<string, ToolDefinition<any>>;
|
|
40
44
|
/** Collect route handlers exposed by plugins for app-level mounting. */
|
|
41
45
|
export declare function getPluginRoutes(): PluginRouteRegistration[];
|
|
46
|
+
/** Collect dashboard-scoped route apps exposed by plugins. */
|
|
47
|
+
export declare function getPluginDashboardRoutes(): PluginDashboardRouteRegistration[];
|
|
42
48
|
/** Resolve the first plugin conversation URL for finalized Slack footers. */
|
|
43
49
|
export declare function getPluginSlackConversationLink(conversationId: string): SlackConversationLink | undefined;
|
|
44
50
|
/** Collect read-only operational summaries exposed by plugins. */
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface DashboardConversationLinkOptions {
|
|
2
|
+
basePath?: string;
|
|
3
|
+
baseURL?: string;
|
|
4
|
+
disabled?: boolean;
|
|
5
|
+
}
|
|
6
|
+
/** Configure core dashboard links used in Slack footers. */
|
|
7
|
+
export declare function setDashboardConversationLinkOptions(options: DashboardConversationLinkOptions | undefined): DashboardConversationLinkOptions | undefined;
|
|
8
|
+
/** Build the dashboard conversation URL when the core dashboard is enabled. */
|
|
9
|
+
export declare function getDashboardConversationLink(conversationId: string): string | undefined;
|
|
@@ -2,6 +2,11 @@ import { z } from "zod";
|
|
|
2
2
|
import type { PiMessage } from "@/chat/pi/messages";
|
|
3
3
|
import { type StoredSlackRequester } from "@/chat/requester";
|
|
4
4
|
declare const authorizationKindSchema: z.ZodUnion<readonly [z.ZodLiteral<"plugin">, z.ZodLiteral<"mcp">]>;
|
|
5
|
+
declare const transcriptRefSchema: z.ZodObject<{
|
|
6
|
+
type: z.ZodLiteral<"advisor_session">;
|
|
7
|
+
parentConversationId: z.ZodString;
|
|
8
|
+
key: z.ZodString;
|
|
9
|
+
}, z.core.$strip>;
|
|
5
10
|
declare const sessionLogEntrySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
6
11
|
schemaVersion: z.ZodLiteral<1>;
|
|
7
12
|
type: z.ZodLiteral<"pi_message">;
|
|
@@ -74,10 +79,50 @@ declare const sessionLogEntrySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
74
79
|
provider: z.ZodString;
|
|
75
80
|
requesterId: z.ZodString;
|
|
76
81
|
authorizationId: z.ZodString;
|
|
82
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
83
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
84
|
+
type: z.ZodLiteral<"tool_execution_started">;
|
|
85
|
+
sessionId: z.ZodDefault<z.ZodString>;
|
|
86
|
+
createdAtMs: z.ZodNumber;
|
|
87
|
+
toolCallId: z.ZodString;
|
|
88
|
+
toolName: z.ZodString;
|
|
89
|
+
args: z.ZodOptional<z.ZodUnknown>;
|
|
90
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
91
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
92
|
+
type: z.ZodLiteral<"subagent_started">;
|
|
93
|
+
sessionId: z.ZodDefault<z.ZodString>;
|
|
94
|
+
subagentInvocationId: z.ZodString;
|
|
95
|
+
subagentKind: z.ZodString;
|
|
96
|
+
parentToolCallId: z.ZodOptional<z.ZodString>;
|
|
97
|
+
parentConversationId: z.ZodString;
|
|
98
|
+
parentSessionId: z.ZodOptional<z.ZodString>;
|
|
99
|
+
transcriptRef: z.ZodObject<{
|
|
100
|
+
type: z.ZodLiteral<"advisor_session">;
|
|
101
|
+
parentConversationId: z.ZodString;
|
|
102
|
+
key: z.ZodString;
|
|
103
|
+
}, z.core.$strip>;
|
|
104
|
+
historyMode: z.ZodLiteral<"shared">;
|
|
105
|
+
createdAtMs: z.ZodNumber;
|
|
106
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
107
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
108
|
+
type: z.ZodLiteral<"subagent_ended">;
|
|
109
|
+
sessionId: z.ZodDefault<z.ZodString>;
|
|
110
|
+
subagentInvocationId: z.ZodString;
|
|
111
|
+
outcome: z.ZodUnion<readonly [z.ZodLiteral<"success">, z.ZodLiteral<"error">, z.ZodLiteral<"aborted">]>;
|
|
112
|
+
errorCode: z.ZodOptional<z.ZodString>;
|
|
113
|
+
createdAtMs: z.ZodNumber;
|
|
77
114
|
}, z.core.$strip>], "type">;
|
|
78
115
|
/** Requester identity stored with turn-start messages for durable continuation. */
|
|
79
116
|
export type SessionLogEntry = z.infer<typeof sessionLogEntrySchema>;
|
|
80
117
|
export type AuthorizationKind = z.infer<typeof authorizationKindSchema>;
|
|
118
|
+
export type TranscriptRef = z.infer<typeof transcriptRefSchema>;
|
|
119
|
+
export type SessionActivityEntry = Extract<SessionLogEntry, {
|
|
120
|
+
type: "tool_execution_started";
|
|
121
|
+
}> | Extract<SessionLogEntry, {
|
|
122
|
+
type: "subagent_started";
|
|
123
|
+
}> | Extract<SessionLogEntry, {
|
|
124
|
+
type: "subagent_ended";
|
|
125
|
+
}>;
|
|
81
126
|
interface Scope {
|
|
82
127
|
conversationId: string;
|
|
83
128
|
}
|
|
@@ -94,6 +139,11 @@ export interface SessionProjection {
|
|
|
94
139
|
messages: PiMessage[];
|
|
95
140
|
requester?: StoredSlackRequester;
|
|
96
141
|
}
|
|
142
|
+
/** Load chronological host-only runtime activity entries for reporting. */
|
|
143
|
+
export declare function loadActivityEntries(args: Scope & {
|
|
144
|
+
store?: SessionLogStore;
|
|
145
|
+
sessionId?: string;
|
|
146
|
+
}): Promise<SessionActivityEntry[]>;
|
|
97
147
|
/** Load the committed Pi-message projection for a conversation. */
|
|
98
148
|
export declare function loadMessages(args: Scope & {
|
|
99
149
|
store?: SessionLogStore;
|
|
@@ -142,6 +192,40 @@ export declare function recordAuthorizationCompleted(args: Scope & {
|
|
|
142
192
|
authorizationId: string;
|
|
143
193
|
ttlMs: number;
|
|
144
194
|
}): Promise<void>;
|
|
195
|
+
/** Record a host-observed parent tool start without adding it to Pi replay. */
|
|
196
|
+
export declare function recordToolExecutionStarted(args: Scope & {
|
|
197
|
+
args?: unknown;
|
|
198
|
+
createdAtMs?: number;
|
|
199
|
+
sessionId?: string;
|
|
200
|
+
store?: SessionLogStore;
|
|
201
|
+
toolCallId: string;
|
|
202
|
+
toolName: string;
|
|
203
|
+
ttlMs: number;
|
|
204
|
+
}): Promise<void>;
|
|
205
|
+
/** Record that a child agent execution became visible from this parent run. */
|
|
206
|
+
export declare function recordSubagentStarted(args: Scope & {
|
|
207
|
+
createdAtMs?: number;
|
|
208
|
+
historyMode: "shared";
|
|
209
|
+
parentConversationId: string;
|
|
210
|
+
parentSessionId?: string;
|
|
211
|
+
parentToolCallId?: string;
|
|
212
|
+
sessionId?: string;
|
|
213
|
+
store?: SessionLogStore;
|
|
214
|
+
subagentInvocationId: string;
|
|
215
|
+
subagentKind: string;
|
|
216
|
+
transcriptRef: TranscriptRef;
|
|
217
|
+
ttlMs: number;
|
|
218
|
+
}): Promise<void>;
|
|
219
|
+
/** Record the terminal state for a previously-started child agent execution. */
|
|
220
|
+
export declare function recordSubagentEnded(args: Scope & {
|
|
221
|
+
createdAtMs?: number;
|
|
222
|
+
errorCode?: string;
|
|
223
|
+
outcome: "success" | "error" | "aborted";
|
|
224
|
+
sessionId?: string;
|
|
225
|
+
store?: SessionLogStore;
|
|
226
|
+
subagentInvocationId: string;
|
|
227
|
+
ttlMs: number;
|
|
228
|
+
}): Promise<void>;
|
|
145
229
|
/**
|
|
146
230
|
* Append conversation-log entries and advance the current Pi projection.
|
|
147
231
|
*
|
|
@@ -7,7 +7,7 @@ export declare const CONVERSATION_WORK_LEASE_TTL_MS = 90000;
|
|
|
7
7
|
export declare const CONVERSATION_WORK_CHECK_IN_INTERVAL_MS = 15000;
|
|
8
8
|
export declare const CONVERSATION_WORK_STALE_ENQUEUE_MS = 60000;
|
|
9
9
|
export type Source = "api" | "internal" | "local" | "plugin" | "scheduler" | "slack";
|
|
10
|
-
export type ExecutionStatus = "awaiting_resume" | "idle" | "pending" | "running";
|
|
10
|
+
export type ExecutionStatus = "awaiting_resume" | "failed" | "idle" | "pending" | "running";
|
|
11
11
|
export interface AgentInput {
|
|
12
12
|
attachments?: unknown[];
|
|
13
13
|
authorId?: string;
|
|
@@ -127,6 +127,26 @@ export declare function recordConversationActivity(args: {
|
|
|
127
127
|
state?: StateAdapter;
|
|
128
128
|
title?: string;
|
|
129
129
|
}): Promise<void>;
|
|
130
|
+
/** Store task-execution metadata for local/no-SQL reporting. */
|
|
131
|
+
export declare function recordConversationExecution(args: {
|
|
132
|
+
channelName?: string;
|
|
133
|
+
conversationId: string;
|
|
134
|
+
createdAtMs: number;
|
|
135
|
+
destination?: Destination;
|
|
136
|
+
execution: {
|
|
137
|
+
lastCheckpointAtMs?: number;
|
|
138
|
+
lastEnqueuedAtMs?: number;
|
|
139
|
+
runId?: string;
|
|
140
|
+
status: ExecutionStatus;
|
|
141
|
+
updatedAtMs?: number;
|
|
142
|
+
};
|
|
143
|
+
lastActivityAtMs: number;
|
|
144
|
+
requester?: StoredSlackRequester;
|
|
145
|
+
source?: Source;
|
|
146
|
+
state?: StateAdapter;
|
|
147
|
+
title?: string;
|
|
148
|
+
updatedAtMs: number;
|
|
149
|
+
}): Promise<void>;
|
|
130
150
|
/** Record that a wake-up nudge was accepted for the conversation. */
|
|
131
151
|
export declare function markConversationWorkEnqueued(args: {
|
|
132
152
|
conversationId: string;
|