@sentry/junior 0.63.0 → 0.64.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/README.md CHANGED
@@ -25,7 +25,11 @@ export default app;
25
25
 
26
26
  Run `junior init my-bot` to scaffold a complete project including `vercel.json` for Vercel deployment.
27
27
 
28
- Use `juniorNitro({ plugins: { packages: [...] } })` in `nitro.config.ts` to declare which plugin packages to bundle and load at runtime. Packages with trusted runtime hooks, such as `@sentry/junior-github`, also need to be registered in app code with `createApp({ plugins: [...] })`.
28
+ Use `defineJuniorPlugins([...])` in a runtime-safe plugin module, then point
29
+ `juniorNitro({ plugins: "./plugins" })` at that module. `createApp()` reads the
30
+ same enabled set from Nitro's virtual module. Manifest-only packages use
31
+ package-name strings; trusted factories such as `githubPlugin()` register their
32
+ manifest and in-process hooks together.
29
33
 
30
34
  ## Full docs
31
35
 
@@ -3,5 +3,7 @@ export type { JuniorAppOptions } from "./app";
3
3
  export { initSentry } from "./instrumentation";
4
4
  export { juniorNitro } from "./nitro";
5
5
  export type { JuniorNitroOptions } from "./nitro";
6
+ export { defineJuniorPlugins } from "./plugins";
7
+ export type { JuniorPluginInput, JuniorPluginSet, JuniorPluginSetOptions, } from "./plugins";
6
8
  export { juniorVercelConfig } from "./vercel";
7
9
  export type { JuniorVercelConfigOptions } from "./vercel";
package/dist/app.d.ts CHANGED
@@ -1,18 +1,13 @@
1
1
  import { Hono } from "hono";
2
- import type { PluginConfig } from "@/chat/plugins/types";
3
- import type { JuniorPlugin } from "@sentry/junior-plugin-api";
2
+ import { type JuniorPluginSet } from "@/plugins";
4
3
  import type { WaitUntilFn } from "@/handlers/types";
4
+ export { defineJuniorPlugins } from "@/plugins";
5
+ export type { JuniorPluginInput, JuniorPluginSet, JuniorPluginSetOptions, } from "@/plugins";
5
6
  export interface JuniorAppOptions {
6
7
  /** Install-wide provider defaults (`provider.key` format). Channel overrides take precedence. */
7
8
  configDefaults?: Record<string, unknown>;
8
- /**
9
- * Plugin packages/overrides, or trusted plugin instances loaded by this app.
10
- *
11
- * Use `PluginConfig` for declarative package lists and manifest overrides.
12
- * Use `JuniorPlugin[]` for trusted plugin factories such as `githubPlugin()`;
13
- * their package config is merged with the catalog bundled by `juniorNitro()`.
14
- */
15
- plugins?: PluginConfig | JuniorPlugin[];
9
+ /** Direct plugin set override. Usually omitted when `juniorNitro()` uses a plugin module. */
10
+ plugins?: JuniorPluginSet;
16
11
  waitUntil?: WaitUntilFn;
17
12
  }
18
13
  /** Create a Hono app with all Junior routes. */
package/dist/app.js CHANGED
@@ -22,13 +22,13 @@ import {
22
22
  splitSlackReplyText,
23
23
  truncateStatusText,
24
24
  upsertAgentTurnSessionRecord
25
- } from "./chunk-ITZ2F7UE.js";
25
+ } from "./chunk-4CRYMG7M.js";
26
26
  import {
27
27
  discoverSkills,
28
28
  findSkillByName,
29
29
  loadSkillsByName,
30
30
  parseSkillInvocation
31
- } from "./chunk-ITOW4DED.js";
31
+ } from "./chunk-D23WCM66.js";
32
32
  import {
33
33
  buildNonInteractiveShellScript,
34
34
  createSandboxInstance,
@@ -37,7 +37,7 @@ import {
37
37
  isSnapshotMissingError,
38
38
  resolveRuntimeDependencySnapshot,
39
39
  runNonInteractiveCommand
40
- } from "./chunk-LRVKJAR2.js";
40
+ } from "./chunk-WZFQQ6SP.js";
41
41
  import {
42
42
  ACTIVE_LOCK_TTL_MS,
43
43
  GEN_AI_PROVIDER_NAME,
@@ -70,7 +70,7 @@ import {
70
70
  toGenAiPayloadMetadata,
71
71
  toGenAiPayloadTraceAttributes,
72
72
  toGenAiTextMetadata
73
- } from "./chunk-PEF6UXTY.js";
73
+ } from "./chunk-IGVHCX2U.js";
74
74
  import {
75
75
  CredentialUnavailableError,
76
76
  buildOAuthTokenRequest,
@@ -101,7 +101,8 @@ import {
101
101
  resolveAuthTokenPlaceholder,
102
102
  resolvePluginCommandEnv,
103
103
  serializeGenAiAttribute,
104
- setPluginConfig,
104
+ setPluginCatalogConfig,
105
+ setSentryUser,
105
106
  setSpanAttributes,
106
107
  setSpanStatus,
107
108
  setTags,
@@ -109,14 +110,19 @@ import {
109
110
  toOptionalString,
110
111
  withContext,
111
112
  withSpan
112
- } from "./chunk-H652GMDH.js";
113
+ } from "./chunk-WDPWFMCE.js";
113
114
  import {
114
115
  sentry_exports
115
116
  } from "./chunk-Z3YD6NHK.js";
117
+ import {
118
+ defineJuniorPlugins,
119
+ pluginCatalogConfigFromPluginSet,
120
+ trustedPluginRegistrationsFromPluginSet
121
+ } from "./chunk-5VDO6LSG.js";
116
122
  import {
117
123
  homeDir,
118
124
  listReferenceFiles
119
- } from "./chunk-5LUISFEY.js";
125
+ } from "./chunk-KVZL5NZS.js";
120
126
  import "./chunk-2KG3PWR4.js";
121
127
 
122
128
  // src/app.ts
@@ -298,7 +304,7 @@ var AGENT_PLUGIN_ROUTE_METHODS = /* @__PURE__ */ new Set([
298
304
  "ALL"
299
305
  ]);
300
306
  function validateLegacyStatePrefixes(plugin) {
301
- const prefixes = plugin.pluginConfig?.legacyStatePrefixes;
307
+ const prefixes = plugin.legacyStatePrefixes;
302
308
  if (prefixes === void 0) {
303
309
  return;
304
310
  }
@@ -367,7 +373,7 @@ function getAgentPluginTools(context) {
367
373
  threadTs: context.threadTs,
368
374
  userText: context.userText,
369
375
  state: createPluginState(plugin.name, {
370
- legacyStatePrefixes: plugin.pluginConfig?.legacyStatePrefixes
376
+ legacyStatePrefixes: plugin.legacyStatePrefixes
371
377
  })
372
378
  });
373
379
  for (const [name, tool2] of Object.entries(pluginTools)) {
@@ -10703,6 +10709,8 @@ Note: No file was attached in this turn. I need to attach the file before claimi
10703
10709
  // src/chat/services/turn-result.ts
10704
10710
  var POST_CANVAS_REPLY_MAX_CHARS = 700;
10705
10711
  var POST_CANVAS_REPLY_MAX_LINES = 8;
10712
+ var THINKING_XML_BLOCK_PATTERN = /[ \t]*<thinking\b[^>]*>[\s\S]*?<\/thinking>[ \t]*(?:\r?\n)?/gi;
10713
+ var FENCED_CODE_BLOCK_PATTERN = /```[\s\S]*?```/g;
10706
10714
  function isVerbosePostCanvasReply(text) {
10707
10715
  const lines = text.split(/\r?\n/).filter((line) => line.trim().length > 0);
10708
10716
  return text.length > POST_CANVAS_REPLY_MAX_CHARS || lines.length > POST_CANVAS_REPLY_MAX_LINES;
@@ -10717,6 +10725,21 @@ function buildBriefPostCanvasReply(artifactStatePatch) {
10717
10725
  const canvasUrl = getCreatedCanvasUrl(artifactStatePatch);
10718
10726
  return canvasUrl ? `I created a canvas with the full reference: ${canvasUrl}` : "I created a canvas with the full reference.";
10719
10727
  }
10728
+ function stripThinkingXmlBlocks(text) {
10729
+ let result = "";
10730
+ let cursor = 0;
10731
+ for (const match of text.matchAll(FENCED_CODE_BLOCK_PATTERN)) {
10732
+ const start = match.index;
10733
+ if (start === void 0) {
10734
+ continue;
10735
+ }
10736
+ result += text.slice(cursor, start).replace(THINKING_XML_BLOCK_PATTERN, "");
10737
+ result += match[0];
10738
+ cursor = start + match[0].length;
10739
+ }
10740
+ result += text.slice(cursor).replace(THINKING_XML_BLOCK_PATTERN, "");
10741
+ return result;
10742
+ }
10720
10743
  function buildTurnResult(input) {
10721
10744
  const {
10722
10745
  newMessages,
@@ -10737,7 +10760,9 @@ function buildTurnResult(input) {
10737
10760
  const toolResults = newMessages.filter(isToolResultMessage);
10738
10761
  const assistantMessages = newMessages.filter(isAssistantMessage);
10739
10762
  const terminalAssistantMessages = getTerminalAssistantMessages(newMessages);
10740
- const primaryText = terminalAssistantMessages.map((message) => extractAssistantText(message)).join("\n\n").trim();
10763
+ const primaryText = stripThinkingXmlBlocks(
10764
+ terminalAssistantMessages.map((message) => extractAssistantText(message)).join("\n\n")
10765
+ ).trim();
10741
10766
  const toolErrorCount = toolResults.filter((result) => result.isError).length;
10742
10767
  const explicitChannelPostIntent = isExplicitChannelPostIntent(userInput);
10743
10768
  const successfulToolNames = new Set(
@@ -14449,7 +14474,7 @@ async function runTrustedPluginHeartbeats(args) {
14449
14474
  Promise.resolve(
14450
14475
  heartbeat(
14451
14476
  createHeartbeatContext({
14452
- legacyStatePrefixes: plugin.pluginConfig?.legacyStatePrefixes,
14477
+ legacyStatePrefixes: plugin.legacyStatePrefixes,
14453
14478
  plugin: plugin.name,
14454
14479
  nowMs: args.nowMs
14455
14480
  })
@@ -19559,6 +19584,13 @@ function createReplyToThread(deps) {
19559
19584
  conversation: preparedState.conversation
19560
19585
  });
19561
19586
  const resolvedUserName = message.author.userName ?? fallbackIdentity?.userName;
19587
+ if (message.author.userId) {
19588
+ setSentryUser({
19589
+ id: message.author.userId,
19590
+ ...resolvedUserName ? { username: resolvedUserName } : {},
19591
+ ...fallbackIdentity?.email ? { email: fallbackIdentity.email } : {}
19592
+ });
19593
+ }
19562
19594
  if (resolvedUserName) {
19563
19595
  setTags({ slackUserName: resolvedUserName });
19564
19596
  }
@@ -21135,10 +21167,14 @@ async function defaultWaitUntil() {
21135
21167
  };
21136
21168
  }
21137
21169
  }
21138
- async function resolveVirtualPluginConfig() {
21170
+ async function resolveVirtualConfig() {
21139
21171
  try {
21140
21172
  const mod = await import("#junior/config");
21141
- return mod.plugins;
21173
+ return {
21174
+ pluginSet: mod.pluginSet,
21175
+ plugins: mod.plugins,
21176
+ trustedPluginRegistrations: mod.trustedPluginRegistrations ?? []
21177
+ };
21142
21178
  } catch (error) {
21143
21179
  if (!isMissingVirtualConfig(error)) {
21144
21180
  throw error;
@@ -21146,11 +21182,7 @@ async function resolveVirtualPluginConfig() {
21146
21182
  return void 0;
21147
21183
  }
21148
21184
  }
21149
- async function resolveBuildPluginConfig() {
21150
- const virtualConfig = await resolveVirtualPluginConfig();
21151
- if (virtualConfig) {
21152
- return virtualConfig;
21153
- }
21185
+ function resolveEnvPluginCatalogConfig() {
21154
21186
  const packages = readEnvPluginPackages();
21155
21187
  if (packages) {
21156
21188
  return { packages };
@@ -21189,38 +21221,55 @@ function hasConfiguredPluginCatalog(config) {
21189
21221
  return false;
21190
21222
  }
21191
21223
  return Boolean(
21192
- config.packages?.length || Object.keys(config.manifests ?? {}).length
21224
+ config.inlineManifests?.length || config.packages?.length || Object.keys(config.manifests ?? {}).length
21193
21225
  );
21194
21226
  }
21195
- function isJuniorPluginArray(plugins) {
21196
- return Array.isArray(plugins);
21227
+ function pluginPackageNames(config) {
21228
+ return config?.packages ?? [];
21197
21229
  }
21198
- function mergePluginConfig(base, next) {
21199
- if (!base) return next;
21200
- if (!next) return base;
21201
- return {
21202
- packages: [
21203
- .../* @__PURE__ */ new Set([...base.packages ?? [], ...next.packages ?? []])
21204
- ],
21205
- manifests: base.manifests || next.manifests ? {
21206
- ...base.manifests ?? {},
21207
- ...next.manifests ?? {}
21208
- } : void 0
21209
- };
21230
+ function validateBuildIncludesPluginPackages(pluginConfig, virtualConfig) {
21231
+ if (!virtualConfig?.plugins) {
21232
+ return;
21233
+ }
21234
+ const bundled = new Set(pluginPackageNames(virtualConfig.plugins));
21235
+ const missing = pluginPackageNames(pluginConfig).filter(
21236
+ (packageName) => !bundled.has(packageName)
21237
+ );
21238
+ if (missing.length === 0) {
21239
+ return;
21240
+ }
21241
+ throw new Error(
21242
+ `createApp() registered plugin package(s) not bundled by juniorNitro(): ${missing.join(", ")}. Point juniorNitro({ plugins: "./plugins" }) at the runtime plugin module or pass the same defineJuniorPlugins(...) set to juniorNitro({ plugins }) and createApp({ plugins }).`
21243
+ );
21210
21244
  }
21211
- function pluginConfigFromAgentPlugins(plugins) {
21212
- const packages = [
21213
- ...new Set(
21214
- plugins.flatMap((plugin) => plugin.pluginConfig?.packages ?? [])
21215
- )
21216
- ];
21217
- return packages.length ? { packages } : void 0;
21245
+ function validateBuildIncludesTrustedRegistrations(trustedRegistrations, virtualConfig) {
21246
+ const bundledTrustedRegistrations = virtualConfig?.trustedPluginRegistrations ?? [];
21247
+ if (bundledTrustedRegistrations.length === 0) {
21248
+ return;
21249
+ }
21250
+ const registered = new Set(trustedRegistrations.map((plugin) => plugin.name));
21251
+ const missing = bundledTrustedRegistrations.filter(
21252
+ (pluginName) => !registered.has(pluginName)
21253
+ );
21254
+ if (missing.length === 0) {
21255
+ return;
21256
+ }
21257
+ throw new Error(
21258
+ `createApp() is missing trusted plugin registration(s) bundled by juniorNitro(): ${missing.join(", ")}. Pass a runtime-safe plugin module to juniorNitro({ plugins: "./plugins" }) or pass the same defineJuniorPlugins(...) set to createApp({ plugins }).`
21259
+ );
21218
21260
  }
21219
- async function resolveAgentPluginBaseConfig(plugins) {
21220
- if (plugins.length === 0) {
21221
- return resolveVirtualPluginConfig();
21261
+ function validatePluginRegistrations(registrations) {
21262
+ const loadedPlugins = getPluginProviders();
21263
+ const loadedNames = new Set(
21264
+ loadedPlugins.map((plugin) => plugin.manifest.name)
21265
+ );
21266
+ for (const registration of registrations) {
21267
+ if (!loadedNames.has(registration.name)) {
21268
+ throw new Error(
21269
+ `Plugin registration "${registration.name}" does not have a matching plugin manifest. Add an inline manifest, packageName, or app-local plugin.yaml with the same name.`
21270
+ );
21271
+ }
21222
21272
  }
21223
- return resolveBuildPluginConfig();
21224
21273
  }
21225
21274
  function mountAgentPluginRoutes(app, routes) {
21226
21275
  for (const route of routes) {
@@ -21237,15 +21286,17 @@ function mountAgentPluginRoutes(app, routes) {
21237
21286
  }
21238
21287
  }
21239
21288
  async function createApp(options) {
21240
- const configuredPlugins = options?.plugins;
21241
- const agentPlugins2 = isJuniorPluginArray(configuredPlugins) ? configuredPlugins : [];
21242
- const pluginConfig = isJuniorPluginArray(configuredPlugins) ? mergePluginConfig(
21243
- await resolveAgentPluginBaseConfig(configuredPlugins),
21244
- pluginConfigFromAgentPlugins(configuredPlugins)
21245
- ) : configuredPlugins ?? await resolveBuildPluginConfig();
21289
+ const virtualConfig = await resolveVirtualConfig();
21290
+ const configuredPlugins = options?.plugins ?? virtualConfig?.pluginSet;
21291
+ const agentPlugins2 = trustedPluginRegistrationsFromPluginSet(configuredPlugins);
21292
+ const pluginConfig = configuredPlugins ? pluginCatalogConfigFromPluginSet(configuredPlugins) : virtualConfig?.plugins ?? resolveEnvPluginCatalogConfig();
21293
+ if (configuredPlugins) {
21294
+ validateBuildIncludesPluginPackages(pluginConfig, virtualConfig);
21295
+ }
21296
+ validateBuildIncludesTrustedRegistrations(agentPlugins2, virtualConfig);
21246
21297
  validateAgentPlugins(agentPlugins2);
21247
- const shouldValidatePluginCatalog = hasConfiguredPluginCatalog(pluginConfig) || Boolean(Object.keys(options?.configDefaults ?? {}).length);
21248
- const previousPluginConfig = setPluginConfig(pluginConfig);
21298
+ const shouldValidatePluginCatalog = hasConfiguredPluginCatalog(pluginConfig) || Boolean(configuredPlugins?.registrations.length) || Boolean(Object.keys(options?.configDefaults ?? {}).length);
21299
+ const previousPluginCatalogConfig = setPluginCatalogConfig(pluginConfig);
21249
21300
  const previousAgentPlugins = setAgentPlugins(agentPlugins2);
21250
21301
  const previousConfigDefaults = getConfigDefaults();
21251
21302
  let agentPluginRoutes = [];
@@ -21253,10 +21304,11 @@ async function createApp(options) {
21253
21304
  setConfigDefaults(options?.configDefaults);
21254
21305
  if (shouldValidatePluginCatalog) {
21255
21306
  getPluginCatalogSignature();
21307
+ validatePluginRegistrations(configuredPlugins?.registrations ?? []);
21256
21308
  }
21257
21309
  agentPluginRoutes = getAgentPluginRoutes();
21258
21310
  } catch (error) {
21259
- setPluginConfig(previousPluginConfig);
21311
+ setPluginCatalogConfig(previousPluginCatalogConfig);
21260
21312
  setAgentPlugins(previousAgentPlugins);
21261
21313
  setConfigDefaults(previousConfigDefaults);
21262
21314
  throw error;
@@ -21297,5 +21349,6 @@ async function createApp(options) {
21297
21349
  return app;
21298
21350
  }
21299
21351
  export {
21300
- createApp
21352
+ createApp,
21353
+ defineJuniorPlugins
21301
21354
  };
@@ -1,4 +1,20 @@
1
1
  import type { Nitro } from "nitro/types";
2
- import type { PluginConfig } from "@/chat/plugins/types";
2
+ import type { PluginCatalogConfig } from "@/chat/plugins/types";
3
+ import { type JuniorPluginSet } from "@/plugins";
4
+ export interface RuntimePluginModule {
5
+ exportName: string;
6
+ specifier: string;
7
+ }
8
+ /** Render the virtual config module consumed by createApp(). */
9
+ export declare function renderVirtualConfig(options: {
10
+ plugins?: PluginCatalogConfig;
11
+ pluginModule?: RuntimePluginModule;
12
+ trustedPluginRegistrations?: string[];
13
+ }): string;
3
14
  /** Inject a virtual module so createApp() can read the plugin list at runtime. */
4
- export declare function injectVirtualConfig(nitro: Nitro, plugins?: PluginConfig): void;
15
+ export declare function injectVirtualConfig(nitro: Nitro, options?: {
16
+ loadPluginSet?: () => Promise<JuniorPluginSet | undefined>;
17
+ pluginModule?: RuntimePluginModule;
18
+ plugins?: PluginCatalogConfig;
19
+ trustedPluginRegistrations?: string[];
20
+ }): void;
@@ -18,6 +18,7 @@ export interface LogContext {
18
18
  slackThreadId?: string;
19
19
  slackUserId?: string;
20
20
  slackUserName?: string;
21
+ slackUserEmail?: string;
21
22
  slackChannelId?: string;
22
23
  runId?: string;
23
24
  actorType?: string;
@@ -30,6 +31,11 @@ export interface LogContext {
30
31
  urlFull?: string;
31
32
  userAgent?: string;
32
33
  }
34
+ interface SentryUserIdentity {
35
+ id: string | number;
36
+ email?: string;
37
+ username?: string;
38
+ }
33
39
  /** Normalize runtime finish reasons to the telemetry spelling we emit. */
34
40
  export declare function normalizeGenAiFinishReason(reason: string): string;
35
41
  export declare const log: {
@@ -37,7 +43,7 @@ export declare const log: {
37
43
  info(eventName: string, attrs?: Record<string, unknown>, body?: string): void;
38
44
  warn(eventName: string, attrs?: Record<string, unknown>, body?: string): void;
39
45
  error(eventName: string, attrs?: Record<string, unknown>, body?: string): void;
40
- exception(eventName: string, error: unknown, attrs?: Record<string, unknown>, body?: string): string | undefined;
46
+ exception(eventName: string, error: unknown, attrs?: Record<string, unknown>, body?: string, context?: LogContext): string | undefined;
41
47
  };
42
48
  /** Create a Chat SDK logger that routes records through Junior's logging backend. */
43
49
  export declare function createChatSdkLogger(): ChatSdkLogger;
@@ -47,7 +53,11 @@ export declare function getLogContextAttributes(): LogAttributes;
47
53
  export declare function registerLogRecordSink(sink: (record: EmittedLogRecord) => void): () => void;
48
54
  export declare function createLogContextFromRequest(request: Request, context?: Partial<LogContext>): LogContext;
49
55
  export declare function toSpanAttributes(context: LogContext): Record<string, string>;
56
+ /** Attach filterable non-user context tags to Sentry. */
50
57
  export declare function setSentryTagsFromContext(context: LogContext): void;
58
+ /** Bind requester identity to Sentry's native user fields. */
59
+ export declare function setSentryUser(identity: SentryUserIdentity | undefined): void;
60
+ /** Attach scoped Sentry context for isolated exception capture. */
51
61
  export declare function setSentryScopeContext(scope: Sentry.Scope, context: LogContext): void;
52
62
  /** Capture an error to Sentry and emit an error log record. */
53
63
  export declare function captureException(error: unknown, context?: LogContext): void;
@@ -59,7 +69,7 @@ export declare function logWarn(eventName: string, context?: LogContext, attribu
59
69
  export declare function logError(eventName: string, context?: LogContext, attributes?: Record<string, unknown>, body?: string): void;
60
70
  /** Log an error with exception capture; returns the Sentry event ID if available. */
61
71
  export declare function logException(error: unknown, eventName: string, context?: LogContext, attributes?: Record<string, unknown>, body?: string): string | undefined;
62
- /** Set log context and Sentry tags for the current scope. */
72
+ /** Set log context and Sentry scope metadata for the current request. */
63
73
  export declare function setTags(context?: LogContext): void;
64
74
  /** Create a LogContext from an incoming HTTP request. */
65
75
  export declare function createRequestContext(request: Request, context?: Partial<LogContext>): LogContext;
@@ -1,4 +1,4 @@
1
- import type { AgentPluginRequester, AgentPluginRoute, SlackConversationLink, JuniorPlugin } from "@sentry/junior-plugin-api";
1
+ import type { AgentPluginRequester, AgentPluginRoute, SlackConversationLink, JuniorPluginRegistration } from "@sentry/junior-plugin-api";
2
2
  import type { ToolDefinition } from "@/chat/tools/definition";
3
3
  import type { ToolRuntimeContext } from "@/chat/tools/types";
4
4
  import type { SandboxInstance } from "@/chat/sandbox/workspace";
@@ -22,11 +22,11 @@ export interface AgentPluginHookRunner {
22
22
  prepareSandbox(sandbox: SandboxInstance): Promise<void>;
23
23
  }
24
24
  /** Validate trusted plugin identity before it can affect process-wide hooks. */
25
- export declare function validateAgentPlugins(plugins: JuniorPlugin[]): void;
25
+ export declare function validateAgentPlugins(plugins: JuniorPluginRegistration[]): void;
26
26
  /** Replace trusted agent plugins and return the previous list for rollback. */
27
- export declare function setAgentPlugins(plugins: JuniorPlugin[]): JuniorPlugin[];
27
+ export declare function setAgentPlugins(plugins: JuniorPluginRegistration[]): JuniorPluginRegistration[];
28
28
  /** Return the current trusted agent plugins without exposing mutable state. */
29
- export declare function getAgentPlugins(): JuniorPlugin[];
29
+ export declare function getAgentPlugins(): JuniorPluginRegistration[];
30
30
  /** Collect turn-scoped tools exposed by trusted plugins. */
31
31
  export declare function getAgentPluginTools(context: ToolRuntimeContext): Record<string, ToolDefinition<any>>;
32
32
  /** Collect route handlers exposed by trusted plugins for app-level mounting. */
@@ -0,0 +1,5 @@
1
+ import type { PluginManifest } from "./types";
2
+ type ManifestSource = Record<string, unknown>;
3
+ /** Convert inline JavaScript plugin manifests to the canonical source shape. */
4
+ export declare function inlineManifestSource(manifest: PluginManifest): ManifestSource;
5
+ export {};
@@ -1,3 +1,5 @@
1
- import type { PluginConfig, PluginManifest } from "./types";
2
- /** Parse one plugin manifest after applying install-level plugin config. */
3
- export declare function parsePluginManifest(raw: string, dir: string, config?: PluginConfig): PluginManifest;
1
+ import type { PluginCatalogConfig, PluginManifest } from "./types";
2
+ /** Parse one plugin.yaml manifest after applying install-level plugin config. */
3
+ export declare function parsePluginManifest(raw: string, dir: string, config?: PluginCatalogConfig): PluginManifest;
4
+ /** Parse one inline JavaScript manifest through the same effective manifest pipeline as plugin.yaml. */
5
+ export declare function parseInlinePluginManifest(manifest: PluginManifest, dir: string, config?: PluginCatalogConfig): PluginManifest;
@@ -1,5 +1,10 @@
1
1
  export interface InstalledPluginPackageContent {
2
2
  packageNames: string[];
3
+ packages: {
4
+ dir: string;
5
+ hasSkillsDir: boolean;
6
+ name: string;
7
+ }[];
3
8
  manifestRoots: string[];
4
9
  skillRoots: string[];
5
10
  tracingIncludes: string[];
@@ -1,9 +1,9 @@
1
1
  import type { CapabilityProviderDefinition } from "@/chat/capabilities/catalog";
2
2
  import type { CredentialBroker } from "@/chat/credentials/broker";
3
3
  import { type InstalledPluginPackageContent } from "./package-discovery";
4
- import type { PluginBrokerDeps, PluginConfig, PluginDefinition, OAuthProviderConfig, PluginRuntimeDependency, PluginRuntimePostinstallCommand } from "./types";
4
+ import type { PluginBrokerDeps, PluginCatalogConfig, PluginDefinition, OAuthProviderConfig, PluginRuntimeDependency, PluginRuntimePostinstallCommand } from "./types";
5
5
  /** Set install-wide plugin configuration and return the previous value for rollback. */
6
- export declare function setPluginConfig(config: PluginConfig | undefined): PluginConfig | undefined;
6
+ export declare function setPluginCatalogConfig(config: PluginCatalogConfig | undefined): PluginCatalogConfig | undefined;
7
7
  /** Return installed plugin package content from the active plugin configuration. */
8
8
  export declare function getPluginPackageContent(): InstalledPluginPackageContent;
9
9
  /** Return the current plugin catalog signature used for cache invalidation. */
@@ -130,8 +130,9 @@ export interface PluginManifestConfig {
130
130
  commandFlags?: string[] | null;
131
131
  } | null;
132
132
  }
133
- /** Install-level plugin package list and manifest configuration. */
134
- export interface PluginConfig {
133
+ /** Install-level plugin package list and manifest override catalog. */
134
+ export interface PluginCatalogConfig {
135
+ inlineManifests?: InlinePluginManifestDefinition[];
135
136
  packages?: string[];
136
137
  manifests?: Record<string, PluginManifestConfig>;
137
138
  }
@@ -141,6 +142,10 @@ export interface PluginBrokerDeps {
141
142
  export interface PluginDefinition {
142
143
  manifest: PluginManifest;
143
144
  dir: string;
144
- skillsDir: string;
145
+ skillsDir?: string;
146
+ }
147
+ export interface InlinePluginManifestDefinition {
148
+ manifest: PluginManifest;
149
+ packageName?: string;
145
150
  }
146
151
  export {};
@@ -13,7 +13,7 @@ export interface AgentTurnSessionRecord {
13
13
  conversationTitle?: string;
14
14
  version: number;
15
15
  conversationId: string;
16
- cumulativeDurationMs?: number;
16
+ cumulativeDurationMs: number;
17
17
  cumulativeUsage?: AgentTurnUsage;
18
18
  errorMessage?: string;
19
19
  lastProgressAtMs: number;
@@ -6,12 +6,12 @@ import {
6
6
  getConnectedStateContext,
7
7
  getStateAdapter,
8
8
  sandboxSkillDir
9
- } from "./chunk-PEF6UXTY.js";
9
+ } from "./chunk-IGVHCX2U.js";
10
10
  import {
11
11
  isRecord,
12
12
  logInfo,
13
13
  logWarn
14
- } from "./chunk-H652GMDH.js";
14
+ } from "./chunk-WDPWFMCE.js";
15
15
  import {
16
16
  sentry_exports
17
17
  } from "./chunk-Z3YD6NHK.js";
@@ -19,7 +19,7 @@ import {
19
19
  listReferenceFiles,
20
20
  soulPathCandidates,
21
21
  worldPathCandidates
22
- } from "./chunk-5LUISFEY.js";
22
+ } from "./chunk-KVZL5NZS.js";
23
23
 
24
24
  // src/handlers/health.ts
25
25
  function GET() {
@@ -1251,9 +1251,7 @@ function parseAgentTurnSessionFields(parsed) {
1251
1251
  const sliceId = toFiniteNonNegativeNumber(parsed.sliceId);
1252
1252
  const version = toFiniteNonNegativeNumber(parsed.version);
1253
1253
  const updatedAtMs = toFiniteNonNegativeNumber(parsed.updatedAtMs);
1254
- const cumulativeDurationMs = toFiniteNonNegativeNumber(
1255
- parsed.cumulativeDurationMs
1256
- );
1254
+ const cumulativeDurationMs = toFiniteNonNegativeNumber(parsed.cumulativeDurationMs) ?? 0;
1257
1255
  const cumulativeUsage = parseAgentTurnUsage(parsed.cumulativeUsage);
1258
1256
  const lastProgressAtMs = toFiniteNonNegativeNumber(parsed.lastProgressAtMs);
1259
1257
  const logSessionId = typeof parsed.logSessionId === "string" ? parsed.logSessionId : void 0;
@@ -1273,8 +1271,8 @@ function parseAgentTurnSessionFields(parsed) {
1273
1271
  startedAtMs: startedAtMs ?? updatedAtMs,
1274
1272
  lastProgressAtMs: lastProgressAtMs ?? updatedAtMs,
1275
1273
  updatedAtMs,
1274
+ cumulativeDurationMs,
1276
1275
  ...logSessionId ? { logSessionId } : {},
1277
- ...cumulativeDurationMs !== void 0 ? { cumulativeDurationMs } : {},
1278
1276
  ...cumulativeUsage ? { cumulativeUsage } : {},
1279
1277
  ...requester ? { requester } : {},
1280
1278
  ...Array.isArray(parsed.loadedSkillNames) ? {
@@ -1363,7 +1361,7 @@ function materializeAgentTurnSessionRecord(stored, piMessages) {
1363
1361
  lastProgressAtMs: stored.lastProgressAtMs,
1364
1362
  updatedAtMs: stored.updatedAtMs,
1365
1363
  piMessages,
1366
- ...stored.cumulativeDurationMs !== void 0 ? { cumulativeDurationMs: stored.cumulativeDurationMs } : {},
1364
+ cumulativeDurationMs: stored.cumulativeDurationMs,
1367
1365
  ...stored.cumulativeUsage ? { cumulativeUsage: stored.cumulativeUsage } : {},
1368
1366
  ...stored.resumeReason ? { resumeReason: stored.resumeReason } : {},
1369
1367
  ...stored.errorMessage ? { errorMessage: stored.errorMessage } : {},
@@ -1424,12 +1422,7 @@ function buildStoredRecord(args) {
1424
1422
  updatedAtMs: nowMs,
1425
1423
  committedMessageCount: args.committedMessageCount,
1426
1424
  ...args.logSessionId ? { logSessionId: args.logSessionId } : {},
1427
- ...typeof args.cumulativeDurationMs === "number" && Number.isFinite(args.cumulativeDurationMs) ? {
1428
- cumulativeDurationMs: Math.max(
1429
- 0,
1430
- Math.floor(args.cumulativeDurationMs)
1431
- )
1432
- } : {},
1425
+ cumulativeDurationMs: args.cumulativeDurationMs,
1433
1426
  ...args.cumulativeUsage ? { cumulativeUsage: args.cumulativeUsage } : {},
1434
1427
  ...args.requester ? { requester: args.requester } : {},
1435
1428
  ...Array.isArray(args.loadedSkillNames) ? {
@@ -1483,7 +1476,7 @@ async function updateAgentTurnSessionState(args) {
1483
1476
  lastProgressAtMs: parsed.lastProgressAtMs,
1484
1477
  previousVersion: parsed.version,
1485
1478
  ...parsed.logSessionId ? { logSessionId: parsed.logSessionId } : {},
1486
- ...args.existing.cumulativeDurationMs !== void 0 ? { cumulativeDurationMs: args.existing.cumulativeDurationMs } : {},
1479
+ cumulativeDurationMs: args.existing.cumulativeDurationMs,
1487
1480
  ...args.existing.cumulativeUsage ? { cumulativeUsage: args.existing.cumulativeUsage } : {},
1488
1481
  ...args.existing.loadedSkillNames ? { loadedSkillNames: args.existing.loadedSkillNames } : {},
1489
1482
  ...args.existing.requester ? { requester: args.existing.requester } : {},
@@ -1522,7 +1515,7 @@ async function upsertAgentTurnSessionRecord(args) {
1522
1515
  committedMessageCount: args.piMessages.length,
1523
1516
  logSessionId: commit.sessionId,
1524
1517
  previousVersion: existingRecord?.version,
1525
- ...args.cumulativeDurationMs !== void 0 ? { cumulativeDurationMs: args.cumulativeDurationMs } : {},
1518
+ cumulativeDurationMs: toFiniteNonNegativeNumber(args.cumulativeDurationMs) ?? existingRecord?.cumulativeDurationMs ?? 0,
1526
1519
  ...args.cumulativeUsage ? { cumulativeUsage: args.cumulativeUsage } : {},
1527
1520
  ...args.loadedSkillNames ? { loadedSkillNames: args.loadedSkillNames } : {},
1528
1521
  ...args.requester ?? existingRecord?.requester ? { requester: args.requester ?? existingRecord?.requester } : {},
@@ -1554,12 +1547,7 @@ async function recordAgentTurnSessionSummary(args) {
1554
1547
  lastProgressAtMs: args.lastProgressAtMs ?? nowMs,
1555
1548
  state: args.state,
1556
1549
  updatedAtMs: nowMs,
1557
- ...typeof args.cumulativeDurationMs === "number" && Number.isFinite(args.cumulativeDurationMs) ? {
1558
- cumulativeDurationMs: Math.max(
1559
- 0,
1560
- Math.floor(args.cumulativeDurationMs)
1561
- )
1562
- } : existing?.cumulativeDurationMs !== void 0 ? { cumulativeDurationMs: existing.cumulativeDurationMs } : {},
1550
+ cumulativeDurationMs: toFiniteNonNegativeNumber(args.cumulativeDurationMs) ?? existing?.cumulativeDurationMs ?? 0,
1563
1551
  ...args.cumulativeUsage ?? existing?.cumulativeUsage ? { cumulativeUsage: args.cumulativeUsage ?? existing?.cumulativeUsage } : {},
1564
1552
  ...args.requester ?? existing?.requester ? { requester: args.requester ?? existing?.requester } : {},
1565
1553
  ...Array.isArray(args.loadedSkillNames) ? {