@sentry/junior 0.74.1 → 0.75.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 (73) hide show
  1. package/dist/agent-hooks-2HEB4C3Q.js +33 -0
  2. package/dist/api-reference.d.ts +1 -1
  3. package/dist/app.js +5211 -5316
  4. package/dist/build/copy-build-content.d.ts +1 -1
  5. package/dist/chat/agent-dispatch/context.d.ts +2 -3
  6. package/dist/chat/agent-dispatch/types.d.ts +2 -1
  7. package/dist/chat/config.d.ts +2 -0
  8. package/dist/chat/conversations/configured.d.ts +2 -0
  9. package/dist/chat/credentials/subject.d.ts +3 -3
  10. package/dist/chat/plugins/agent-hooks.d.ts +13 -13
  11. package/dist/chat/plugins/credential-hooks.d.ts +6 -6
  12. package/dist/chat/plugins/db.d.ts +31 -0
  13. package/dist/chat/plugins/logging.d.ts +2 -2
  14. package/dist/chat/plugins/package-discovery.d.ts +2 -1
  15. package/dist/chat/plugins/registry.d.ts +4 -0
  16. package/dist/chat/plugins/state.d.ts +3 -5
  17. package/dist/chat/plugins/types.d.ts +1 -0
  18. package/dist/chat/plugins/validation.d.ts +5 -0
  19. package/dist/chat/prompt.d.ts +11 -1
  20. package/dist/chat/respond.d.ts +10 -1
  21. package/dist/chat/runtime/slack-runtime.d.ts +6 -1
  22. package/dist/chat/sandbox/egress-credentials.d.ts +8 -8
  23. package/dist/chat/sandbox/sandbox.d.ts +2 -2
  24. package/dist/chat/sql/db.d.ts +3 -0
  25. package/dist/chat/sql/executor.d.ts +7 -0
  26. package/dist/chat/sql/neon.d.ts +2 -4
  27. package/dist/chat/sql/postgres.d.ts +6 -0
  28. package/dist/chat/task-execution/state.d.ts +7 -2
  29. package/dist/chat/task-execution/worker.d.ts +1 -1
  30. package/dist/chat/tools/agent-tools.d.ts +2 -2
  31. package/dist/chat/tools/types.d.ts +3 -0
  32. package/dist/{chunk-7Q5YOUUT.js → chunk-2RWFUS5F.js} +47 -10
  33. package/dist/{chunk-YRDS7VKO.js → chunk-62FUNJYS.js} +3 -54
  34. package/dist/{chunk-M4FLLXXD.js → chunk-74HO27II.js} +1 -1
  35. package/dist/chunk-BNJIEFQC.js +115 -0
  36. package/dist/{chunk-YOHFWWBV.js → chunk-C3AM4Z4J.js} +1 -103
  37. package/dist/chunk-D7NFH5GD.js +570 -0
  38. package/dist/chunk-EE6PJWY4.js +130 -0
  39. package/dist/{chunk-CYUI7JU5.js → chunk-EIYL7I4S.js} +1 -1
  40. package/dist/{chunk-GM7HTXYC.js → chunk-FCZO7LAR.js} +13 -2
  41. package/dist/{chunk-2LUZA3LY.js → chunk-JEELK46E.js} +5 -5
  42. package/dist/chunk-MCMROINU.js +12 -0
  43. package/dist/chunk-NPVUAXUE.js +694 -0
  44. package/dist/{chunk-OR6NQJ5E.js → chunk-OJODNL2P.js} +3 -3
  45. package/dist/{chunk-3BYAPS6B.js → chunk-OK4KKR7B.js} +1 -11
  46. package/dist/chunk-OZSPLAQ4.js +71 -0
  47. package/dist/{chunk-KVZL5NZS.js → chunk-Q3XNY442.js} +17 -7
  48. package/dist/{chunk-SQGMG7OD.js → chunk-TQ74BATR.js} +100 -58
  49. package/dist/{chunk-JL2SLRAT.js → chunk-UJ7OTHPO.js} +76 -312
  50. package/dist/{chunk-HYHKTFG2.js → chunk-VNTLUFTY.js} +80 -843
  51. package/dist/chunk-WBZ4M5N5.js +59 -0
  52. package/dist/{chunk-6UP2Z2RZ.js → chunk-XJHDZUGD.js} +7 -7
  53. package/dist/chunk-Y2CM7HXH.js +111 -0
  54. package/dist/{chunk-F6HWCPOC.js → chunk-ZNNTSPNF.js} +1 -1
  55. package/dist/cli/chat.js +52 -2
  56. package/dist/cli/check.js +6 -5
  57. package/dist/cli/snapshot-warmup.js +10 -9
  58. package/dist/cli/upgrade.js +256 -16
  59. package/dist/db-A3ILH67H.js +20 -0
  60. package/dist/handlers/sandbox-egress-route.d.ts +4 -0
  61. package/dist/handlers/slack-webhook.d.ts +4 -0
  62. package/dist/handlers/webhooks.d.ts +6 -13
  63. package/dist/nitro.js +34 -89
  64. package/dist/plugin-module.d.ts +21 -0
  65. package/dist/plugins-OMJKLRJ2.js +13 -0
  66. package/dist/plugins.d.ts +6 -4
  67. package/dist/registry-NLZFIW23.js +46 -0
  68. package/dist/reporting/conversations.d.ts +3 -3
  69. package/dist/reporting.d.ts +6 -5
  70. package/dist/reporting.js +23 -17
  71. package/dist/{runner-27NP2TEO.js → runner-LUQZ5G67.js} +18 -13
  72. package/dist/validation-VMCPP3YO.js +15 -0
  73. package/package.json +11 -9
@@ -0,0 +1,59 @@
1
+ import {
2
+ normalizeSlackConversationId
3
+ } from "./chunk-62FUNJYS.js";
4
+ import {
5
+ isSlackConversationId,
6
+ isSlackTeamId
7
+ } from "./chunk-MCMROINU.js";
8
+
9
+ // src/chat/destination.ts
10
+ import {
11
+ destinationSchema
12
+ } from "@sentry/junior-plugin-api";
13
+ function createSlackDestination(input) {
14
+ const channelId = normalizeSlackConversationId(input.channelId);
15
+ const teamId = input.teamId?.trim();
16
+ if (!channelId || !teamId) {
17
+ return void 0;
18
+ }
19
+ if (!isSlackConversationId(channelId) || !isSlackTeamId(teamId)) {
20
+ return void 0;
21
+ }
22
+ return { platform: "slack", teamId, channelId };
23
+ }
24
+ function parseDestination(value) {
25
+ const parsed = destinationSchema.safeParse(value);
26
+ return parsed.success ? parsed.data : void 0;
27
+ }
28
+ function requireSlackDestination(destination, action) {
29
+ if (destination?.platform === "slack") {
30
+ return destination;
31
+ }
32
+ throw new Error(`${action} requires a Slack destination`);
33
+ }
34
+ function sameDestination(left, right) {
35
+ if (left.platform !== right.platform) {
36
+ return false;
37
+ }
38
+ if (left.platform === "local" && right.platform === "local") {
39
+ return left.conversationId === right.conversationId;
40
+ }
41
+ if (left.platform === "slack" && right.platform === "slack") {
42
+ return left.teamId === right.teamId && left.channelId === right.channelId;
43
+ }
44
+ return false;
45
+ }
46
+ function destinationKey(destination) {
47
+ if (destination.platform === "local") {
48
+ return destination.conversationId;
49
+ }
50
+ return `slack:${destination.teamId}:${destination.channelId}`;
51
+ }
52
+
53
+ export {
54
+ createSlackDestination,
55
+ parseDestination,
56
+ requireSlackDestination,
57
+ sameDestination,
58
+ destinationKey
59
+ };
@@ -1,19 +1,19 @@
1
1
  import {
2
2
  SANDBOX_WORKSPACE_ROOT
3
3
  } from "./chunk-G3E7SCME.js";
4
- import {
5
- getPluginRuntimeDependencies,
6
- getPluginRuntimePostinstall
7
- } from "./chunk-7Q5YOUUT.js";
8
4
  import {
9
5
  getStateAdapter
10
- } from "./chunk-F6HWCPOC.js";
6
+ } from "./chunk-ZNNTSPNF.js";
11
7
  import {
12
8
  toOptionalTrimmed
13
- } from "./chunk-GM7HTXYC.js";
9
+ } from "./chunk-FCZO7LAR.js";
10
+ import {
11
+ getPluginRuntimeDependencies,
12
+ getPluginRuntimePostinstall
13
+ } from "./chunk-2RWFUS5F.js";
14
14
  import {
15
15
  withSpan
16
- } from "./chunk-3BYAPS6B.js";
16
+ } from "./chunk-OK4KKR7B.js";
17
17
 
18
18
  // src/chat/sandbox/runtime-dependency-snapshots.ts
19
19
  import { createHash } from "crypto";
@@ -0,0 +1,111 @@
1
+ // src/plugin-module.ts
2
+ import { statSync } from "fs";
3
+ import { createRequire } from "module";
4
+ import path from "path";
5
+ import { pathToFileURL } from "url";
6
+ var PLUGIN_MODULE_EXTENSIONS = [
7
+ "",
8
+ ".ts",
9
+ ".tsx",
10
+ ".mts",
11
+ ".mjs",
12
+ ".js",
13
+ ".cjs"
14
+ ];
15
+ function resolveRelativePluginModule(cwd, specifier) {
16
+ const basePath = path.resolve(cwd, specifier);
17
+ for (const extension of PLUGIN_MODULE_EXTENSIONS) {
18
+ const candidate = `${basePath}${extension}`;
19
+ try {
20
+ if (statSync(candidate).isFile()) {
21
+ return candidate;
22
+ }
23
+ } catch {
24
+ }
25
+ }
26
+ for (const extension of PLUGIN_MODULE_EXTENSIONS) {
27
+ const candidate = path.join(basePath, `index${extension}`);
28
+ try {
29
+ if (statSync(candidate).isFile()) {
30
+ return candidate;
31
+ }
32
+ } catch {
33
+ }
34
+ }
35
+ throw new Error(`Plugin module "${specifier}" could not be resolved`);
36
+ }
37
+ function resolvePluginModule(cwd, input) {
38
+ const moduleSpecifier = typeof input === "string" ? input : input.module;
39
+ const exportName = typeof input === "string" ? "plugins" : input.exportName ?? "plugins";
40
+ if (!moduleSpecifier.trim()) {
41
+ throw new Error("Plugin module specifier must not be empty");
42
+ }
43
+ if (moduleSpecifier.startsWith(".") || path.isAbsolute(moduleSpecifier)) {
44
+ const resolvedPath2 = resolveRelativePluginModule(cwd, moduleSpecifier);
45
+ return {
46
+ exportName,
47
+ importPath: resolvedPath2,
48
+ importUrl: pathToFileURL(resolvedPath2).href,
49
+ kind: "file",
50
+ sourceSpecifier: moduleSpecifier
51
+ };
52
+ }
53
+ const requireFromApp = createRequire(path.join(cwd, "package.json"));
54
+ const resolvedPath = requireFromApp.resolve(moduleSpecifier);
55
+ return {
56
+ exportName,
57
+ importPath: resolvedPath,
58
+ importUrl: pathToFileURL(resolvedPath).href,
59
+ kind: "package",
60
+ sourceSpecifier: moduleSpecifier
61
+ };
62
+ }
63
+ function assertPluginSet(value, source) {
64
+ if (!value || typeof value !== "object" || !Array.isArray(value.packageNames) || !Array.isArray(value.registrations)) {
65
+ throw new Error(
66
+ `Plugin module ${source} must export a defineJuniorPlugins(...) set`
67
+ );
68
+ }
69
+ const pluginSet = value;
70
+ const invalidPackageName = pluginSet.packageNames?.find(
71
+ (packageName) => typeof packageName !== "string"
72
+ );
73
+ if (invalidPackageName !== void 0) {
74
+ throw new Error(`Plugin module ${source} must export string package names`);
75
+ }
76
+ const invalidRegistration = pluginSet.registrations?.find(
77
+ (registration) => !registration || typeof registration !== "object" || !("manifest" in registration) || !registration.manifest || typeof registration.manifest !== "object" || !("name" in registration.manifest) || typeof registration.manifest.name !== "string"
78
+ );
79
+ if (invalidRegistration) {
80
+ throw new Error(
81
+ `Plugin module ${source} must export plugin registrations with manifest names`
82
+ );
83
+ }
84
+ return value;
85
+ }
86
+ async function loadPluginSetFromModule(moduleRef, importModule = async (ref) => await import(ref.importUrl)) {
87
+ const mod = await importModule(moduleRef);
88
+ const value = moduleRef.exportName === "default" ? mod.default : mod[moduleRef.exportName];
89
+ return assertPluginSet(
90
+ value,
91
+ `${moduleRef.importUrl}#${moduleRef.exportName}`
92
+ );
93
+ }
94
+ async function loadAppPluginSet(cwd, importModule) {
95
+ let pluginModule;
96
+ try {
97
+ pluginModule = resolvePluginModule(cwd, "./plugins");
98
+ } catch (error) {
99
+ if (error instanceof Error && error.message === 'Plugin module "./plugins" could not be resolved') {
100
+ return void 0;
101
+ }
102
+ throw error;
103
+ }
104
+ return await loadPluginSetFromModule(pluginModule, importModule);
105
+ }
106
+
107
+ export {
108
+ resolvePluginModule,
109
+ loadPluginSetFromModule,
110
+ loadAppPluginSet
111
+ };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getChatConfig
3
- } from "./chunk-GM7HTXYC.js";
3
+ } from "./chunk-FCZO7LAR.js";
4
4
 
5
5
  // src/chat/state/adapter.ts
6
6
  import { createMemoryState } from "@chat-adapter/state-memory";
package/dist/cli/chat.js CHANGED
@@ -1,3 +1,6 @@
1
+ import {
2
+ loadAppPluginSet
3
+ } from "../chunk-Y2CM7HXH.js";
1
4
  import "../chunk-2KG3PWR4.js";
2
5
 
3
6
  // src/cli/chat.ts
@@ -8,6 +11,7 @@ import {
8
11
  } from "process";
9
12
  import { randomUUID } from "crypto";
10
13
  import * as readline from "readline/promises";
14
+ import { createJiti } from "jiti";
11
15
 
12
16
  // src/chat/local/conversation.ts
13
17
  import { createHash } from "crypto";
@@ -40,6 +44,7 @@ var DEFAULT_IO = {
40
44
  output: defaultStdout,
41
45
  write: (text) => writeStream(defaultStdout, text)
42
46
  };
47
+ var localPluginLoader = createJiti(import.meta.url, { moduleCache: false });
43
48
  var ChatOutputError = class extends Error {
44
49
  constructor(error) {
45
50
  super(errorMessage(error));
@@ -87,6 +92,49 @@ function defaultStateAdapterForLocalChat() {
87
92
  }
88
93
  process.env.JUNIOR_STATE_ADAPTER = "memory";
89
94
  }
95
+ async function loadLocalPluginSet() {
96
+ return await loadAppPluginSet(
97
+ process.cwd(),
98
+ async (moduleRef) => localPluginLoader.import(moduleRef.importPath)
99
+ );
100
+ }
101
+ async function configureLocalChatPlugins() {
102
+ const [
103
+ pluginsModule,
104
+ agentHooksModule,
105
+ registryModule,
106
+ validationModule,
107
+ databaseModule
108
+ ] = await Promise.all([
109
+ import("../plugins-OMJKLRJ2.js"),
110
+ import("../agent-hooks-2HEB4C3Q.js"),
111
+ import("../registry-NLZFIW23.js"),
112
+ import("../validation-VMCPP3YO.js"),
113
+ import("../db-A3ILH67H.js")
114
+ ]);
115
+ const pluginSet = await loadLocalPluginSet();
116
+ const plugins = pluginsModule.pluginHookRegistrationsFromPluginSet(pluginSet);
117
+ const pluginConfig = pluginSet ? pluginsModule.pluginCatalogConfigFromPluginSet(pluginSet) : pluginsModule.pluginCatalogConfigFromEnv();
118
+ const shouldValidatePluginCatalog = Boolean(pluginConfig) || Boolean(pluginSet?.registrations.length);
119
+ agentHooksModule.validatePlugins(plugins);
120
+ const previousPluginCatalogConfig = registryModule.setPluginCatalogConfig(pluginConfig);
121
+ try {
122
+ if (shouldValidatePluginCatalog) {
123
+ registryModule.getPluginCatalogSignature();
124
+ validationModule.validatePluginRegistrations(
125
+ pluginSet?.registrations ?? []
126
+ );
127
+ validationModule.validatePluginEgressCredentialHooks(
128
+ pluginSet?.registrations ?? []
129
+ );
130
+ }
131
+ databaseModule.validatePluginDatabaseRequirements(plugins);
132
+ agentHooksModule.setPlugins(plugins);
133
+ } catch (error) {
134
+ registryModule.setPluginCatalogConfig(previousPluginCatalogConfig);
135
+ throw error;
136
+ }
137
+ }
90
138
  function parseChatArgs(argv) {
91
139
  if (argv.length === 0) {
92
140
  return { mode: "interactive" };
@@ -120,8 +168,9 @@ function newRunConversationId() {
120
168
  }
121
169
  async function runPrompt(options, io) {
122
170
  defaultStateAdapterForLocalChat();
171
+ await configureLocalChatPlugins();
123
172
  const conversationId = newRunConversationId();
124
- const { runLocalAgentTurn } = await import("../runner-27NP2TEO.js");
173
+ const { runLocalAgentTurn } = await import("../runner-LUQZ5G67.js");
125
174
  const result = await runLocalAgentTurn(
126
175
  {
127
176
  conversationId,
@@ -140,8 +189,9 @@ async function runPrompt(options, io) {
140
189
  }
141
190
  async function runInteractive(io) {
142
191
  defaultStateAdapterForLocalChat();
192
+ await configureLocalChatPlugins();
143
193
  const conversationId = newRunConversationId();
144
- const { runLocalAgentTurn } = await import("../runner-27NP2TEO.js");
194
+ const { runLocalAgentTurn } = await import("../runner-LUQZ5G67.js");
145
195
  const rl = readline.createInterface({
146
196
  input: io.input,
147
197
  output: io.output,
package/dist/cli/check.js CHANGED
@@ -1,13 +1,14 @@
1
1
  import {
2
2
  parseSkillFile
3
- } from "../chunk-OR6NQJ5E.js";
3
+ } from "../chunk-OJODNL2P.js";
4
4
  import {
5
5
  parseInlinePluginManifest,
6
6
  parsePluginManifest
7
- } from "../chunk-7Q5YOUUT.js";
8
- import "../chunk-KVZL5NZS.js";
9
- import "../chunk-CYUI7JU5.js";
10
- import "../chunk-3BYAPS6B.js";
7
+ } from "../chunk-2RWFUS5F.js";
8
+ import "../chunk-Q3XNY442.js";
9
+ import "../chunk-EIYL7I4S.js";
10
+ import "../chunk-MCMROINU.js";
11
+ import "../chunk-OK4KKR7B.js";
11
12
  import {
12
13
  JUNIOR_CONVERSATION_WORK_CALLBACK_ROUTE,
13
14
  JUNIOR_HEARTBEAT_ROUTE,
@@ -1,19 +1,20 @@
1
1
  import {
2
2
  resolveRuntimeDependencySnapshot
3
- } from "../chunk-6UP2Z2RZ.js";
3
+ } from "../chunk-XJHDZUGD.js";
4
4
  import "../chunk-G3E7SCME.js";
5
+ import {
6
+ disconnectStateAdapter
7
+ } from "../chunk-ZNNTSPNF.js";
8
+ import "../chunk-FCZO7LAR.js";
5
9
  import {
6
10
  getPluginProviders,
7
11
  getPluginRuntimeDependencies,
8
12
  getPluginRuntimePostinstall
9
- } from "../chunk-7Q5YOUUT.js";
10
- import "../chunk-KVZL5NZS.js";
11
- import {
12
- disconnectStateAdapter
13
- } from "../chunk-F6HWCPOC.js";
14
- import "../chunk-GM7HTXYC.js";
15
- import "../chunk-CYUI7JU5.js";
16
- import "../chunk-3BYAPS6B.js";
13
+ } from "../chunk-2RWFUS5F.js";
14
+ import "../chunk-Q3XNY442.js";
15
+ import "../chunk-EIYL7I4S.js";
16
+ import "../chunk-MCMROINU.js";
17
+ import "../chunk-OK4KKR7B.js";
17
18
  import "../chunk-SJHUF3DP.js";
18
19
  import "../chunk-2KG3PWR4.js";
19
20
 
@@ -1,34 +1,63 @@
1
1
  import {
2
2
  coerceThreadConversationState
3
- } from "../chunk-M4FLLXXD.js";
3
+ } from "../chunk-74HO27II.js";
4
+ import {
5
+ defineJuniorPlugins,
6
+ pluginCatalogConfigFromEnv,
7
+ pluginCatalogConfigFromPluginSet,
8
+ pluginHookRegistrationsFromPluginSet
9
+ } from "../chunk-EE6PJWY4.js";
4
10
  import {
5
11
  JUNIOR_THREAD_STATE_TTL_MS,
6
- createNeonJuniorSqlExecutor,
7
12
  createSqlStore,
8
13
  createStateConversationStore,
9
14
  getConversation,
10
15
  requestConversationWork
11
- } from "../chunk-JL2SLRAT.js";
16
+ } from "../chunk-UJ7OTHPO.js";
12
17
  import {
13
18
  parseDestination,
14
19
  sameDestination
15
- } from "../chunk-YRDS7VKO.js";
20
+ } from "../chunk-WBZ4M5N5.js";
21
+ import {
22
+ createPluginLogger,
23
+ createPluginState
24
+ } from "../chunk-BNJIEFQC.js";
25
+ import "../chunk-62FUNJYS.js";
26
+ import {
27
+ createJuniorSqlExecutor,
28
+ createPluginDbForExecutor,
29
+ getPluginDbForRegistration,
30
+ migratePluginSchemas,
31
+ readPluginMigrations
32
+ } from "../chunk-D7NFH5GD.js";
33
+ import {
34
+ loadAppPluginSet
35
+ } from "../chunk-Y2CM7HXH.js";
16
36
  import {
17
37
  disconnectStateAdapter,
18
38
  getConnectedStateContext
19
- } from "../chunk-F6HWCPOC.js";
39
+ } from "../chunk-ZNNTSPNF.js";
20
40
  import {
21
41
  getChatConfig
22
- } from "../chunk-GM7HTXYC.js";
23
- import "../chunk-CYUI7JU5.js";
42
+ } from "../chunk-FCZO7LAR.js";
43
+ import {
44
+ getPluginMigrationRoots,
45
+ setPluginCatalogConfig
46
+ } from "../chunk-2RWFUS5F.js";
47
+ import "../chunk-Q3XNY442.js";
48
+ import "../chunk-EIYL7I4S.js";
49
+ import "../chunk-MCMROINU.js";
24
50
  import {
25
51
  isRecord,
26
52
  toOptionalNumber,
27
53
  toOptionalString
28
- } from "../chunk-3BYAPS6B.js";
54
+ } from "../chunk-OK4KKR7B.js";
29
55
  import "../chunk-SJHUF3DP.js";
30
56
  import "../chunk-2KG3PWR4.js";
31
57
 
58
+ // src/cli/upgrade.ts
59
+ import { createJiti } from "jiti";
60
+
32
61
  // src/chat/conversations/sql/backfill.ts
33
62
  async function backfillToSql(args) {
34
63
  const limit = Math.max(0, args.limit ?? 500);
@@ -60,8 +89,9 @@ async function migrateConversationsToSql(context, options = {}) {
60
89
  let closeTarget;
61
90
  if (!target) {
62
91
  const databaseUrl = requireConversationSqlDatabaseUrl(context);
63
- const executor = createNeonJuniorSqlExecutor({
64
- connectionString: databaseUrl
92
+ const executor = createJuniorSqlExecutor({
93
+ connectionString: databaseUrl,
94
+ driver: context.sqlDriver ?? getChatConfig().sql.driver
65
95
  });
66
96
  target = createSqlStore(executor);
67
97
  closeTarget = () => executor.close();
@@ -88,6 +118,183 @@ var sqlConversationMigration = {
88
118
  run: migrateConversationsToSql
89
119
  };
90
120
 
121
+ // src/cli/upgrade/migrations/upgrade-plugins.ts
122
+ function unique(values) {
123
+ return [...new Set(values)];
124
+ }
125
+ function baseCatalogConfig(context) {
126
+ return context.pluginCatalogConfig ?? (context.pluginSet ? pluginCatalogConfigFromPluginSet(context.pluginSet) : pluginCatalogConfigFromEnv());
127
+ }
128
+ function inlinePluginName(definition) {
129
+ return definition.manifest.name;
130
+ }
131
+ function mergeInlineManifests(left, right) {
132
+ const merged = /* @__PURE__ */ new Map();
133
+ for (const definition of [...left ?? [], ...right ?? []]) {
134
+ merged.set(inlinePluginName(definition), definition);
135
+ }
136
+ return merged.size > 0 ? [...merged.values()] : void 0;
137
+ }
138
+ function mergeCatalogConfig(base, added) {
139
+ if (!base) {
140
+ return added;
141
+ }
142
+ if (!added) {
143
+ return base;
144
+ }
145
+ const inlineManifests = mergeInlineManifests(
146
+ base.inlineManifests,
147
+ added.inlineManifests
148
+ );
149
+ const packages = unique([
150
+ ...base.packages ?? [],
151
+ ...added.packages ?? []
152
+ ]);
153
+ const manifests = base.manifests || added.manifests ? { ...base.manifests, ...added.manifests } : void 0;
154
+ return {
155
+ ...inlineManifests ? { inlineManifests } : {},
156
+ ...packages.length > 0 ? { packages } : {},
157
+ ...manifests ? { manifests } : {}
158
+ };
159
+ }
160
+ function packageNamesFromContext(context, catalog) {
161
+ return unique([
162
+ ...context.pluginSet?.packageNames ?? [],
163
+ ...catalog?.packages ?? []
164
+ ]);
165
+ }
166
+ async function resolveUpgradePlugins(context) {
167
+ const catalog = baseCatalogConfig(context);
168
+ const packageNames = packageNamesFromContext(context, catalog);
169
+ const registrations = context.pluginSet?.registrations ?? [];
170
+ const manifests = context.pluginSet?.manifests || catalog?.manifests ? {
171
+ ...catalog?.manifests,
172
+ ...context.pluginSet?.manifests
173
+ } : void 0;
174
+ const pluginSet = packageNames.length > 0 || registrations.length > 0 || context.pluginSet ? defineJuniorPlugins(
175
+ [...packageNames, ...registrations],
176
+ manifests ? { manifests } : {}
177
+ ) : void 0;
178
+ return {
179
+ pluginCatalogConfig: mergeCatalogConfig(
180
+ catalog,
181
+ pluginCatalogConfigFromPluginSet(pluginSet)
182
+ ),
183
+ ...pluginSet ? { pluginSet } : {}
184
+ };
185
+ }
186
+
187
+ // src/cli/upgrade/migrations/plugin-storage.ts
188
+ function emptyResult() {
189
+ return {
190
+ existing: 0,
191
+ migrated: 0,
192
+ missing: 0,
193
+ scanned: 0
194
+ };
195
+ }
196
+ function addResult(left, right) {
197
+ return {
198
+ existing: left.existing + right.existing,
199
+ migrated: left.migrated + right.migrated,
200
+ missing: left.missing + right.missing,
201
+ scanned: left.scanned + right.scanned,
202
+ ...left.skipped !== void 0 || right.skipped !== void 0 ? { skipped: (left.skipped ?? 0) + (right.skipped ?? 0) } : {}
203
+ };
204
+ }
205
+ function dbForPlugin(context, plugin, sqlUrlDb) {
206
+ if (!plugin.database) {
207
+ return void 0;
208
+ }
209
+ return context.pluginDb ?? sqlUrlDb ?? getPluginDbForRegistration(plugin);
210
+ }
211
+ async function runPluginStorageMigrations(context) {
212
+ const { pluginCatalogConfig, pluginSet } = await resolveUpgradePlugins(context);
213
+ if (!pluginSet) {
214
+ return emptyResult();
215
+ }
216
+ const previousConfig = setPluginCatalogConfig(pluginCatalogConfig);
217
+ const ownedExecutor = context.pluginDb || !context.sqlDatabaseUrl ? void 0 : createJuniorSqlExecutor({
218
+ connectionString: context.sqlDatabaseUrl,
219
+ driver: context.sqlDriver ?? getChatConfig().sql.driver
220
+ });
221
+ const sqlUrlDb = ownedExecutor ? createPluginDbForExecutor(ownedExecutor) : void 0;
222
+ try {
223
+ let result = emptyResult();
224
+ const plugins = pluginHookRegistrationsFromPluginSet(pluginSet).filter((plugin) => plugin.hooks?.migrateStorage).sort(
225
+ (left, right) => left.manifest.name.localeCompare(right.manifest.name)
226
+ );
227
+ for (const plugin of plugins) {
228
+ const pluginName = plugin.manifest.name;
229
+ const hook = plugin.hooks?.migrateStorage;
230
+ if (!hook) {
231
+ continue;
232
+ }
233
+ const db = dbForPlugin(context, plugin, sqlUrlDb);
234
+ if (!db) {
235
+ throw new Error(
236
+ `Plugin "${pluginName}" storage migration requires database access`
237
+ );
238
+ }
239
+ const pluginResult = await hook({
240
+ db,
241
+ log: createPluginLogger(pluginName),
242
+ plugin: { name: pluginName },
243
+ state: createPluginState(pluginName, context.stateAdapter)
244
+ });
245
+ if (pluginResult) {
246
+ result = addResult(result, pluginResult);
247
+ }
248
+ }
249
+ return result;
250
+ } finally {
251
+ setPluginCatalogConfig(previousConfig);
252
+ await ownedExecutor?.close();
253
+ }
254
+ }
255
+ var pluginStorageMigration = {
256
+ name: "run-plugin-storage-migrations",
257
+ run: runPluginStorageMigrations
258
+ };
259
+
260
+ // src/cli/upgrade/migrations/plugin-sql.ts
261
+ var REQUIRED_SQL_DATABASE_URL_MESSAGE2 = "Junior SQL database URL is required for plugin schema migration. Set JUNIOR_DATABASE_URL or DATABASE_URL.";
262
+ function requirePluginSqlDatabaseUrl(context) {
263
+ const databaseUrl = context.sqlDatabaseUrl ?? getChatConfig().sql.databaseUrl;
264
+ if (!databaseUrl) {
265
+ throw new Error(REQUIRED_SQL_DATABASE_URL_MESSAGE2);
266
+ }
267
+ return databaseUrl;
268
+ }
269
+ async function migratePluginsToSql(context) {
270
+ const databaseUrl = requirePluginSqlDatabaseUrl(context);
271
+ const { pluginCatalogConfig } = await resolveUpgradePlugins(context);
272
+ const previousConfig = setPluginCatalogConfig(pluginCatalogConfig);
273
+ const executor = createJuniorSqlExecutor({
274
+ connectionString: databaseUrl,
275
+ driver: context.sqlDriver ?? getChatConfig().sql.driver
276
+ });
277
+ try {
278
+ const migrations = getPluginMigrationRoots().flatMap(
279
+ (root) => readPluginMigrations(root)
280
+ );
281
+ const result = await migratePluginSchemas(executor, migrations);
282
+ return {
283
+ existing: result.existing,
284
+ migrated: result.migrated,
285
+ missing: 0,
286
+ scanned: result.scanned
287
+ };
288
+ } finally {
289
+ setPluginCatalogConfig(previousConfig);
290
+ await executor.close();
291
+ }
292
+ }
293
+ var sqlPluginMigration = {
294
+ name: "migrate-plugin-sql",
295
+ run: migratePluginsToSql
296
+ };
297
+
91
298
  // src/cli/upgrade/migrations/redis-conversation-state.ts
92
299
  var CONVERSATION_PREFIX = "junior:conversation";
93
300
  var CONVERSATION_SCHEMA_VERSION = 1;
@@ -624,10 +831,34 @@ var redisConversationStateMigration = {
624
831
  var DEFAULT_IO = {
625
832
  info: console.log
626
833
  };
834
+ var localPluginLoader = createJiti(import.meta.url, { moduleCache: false });
627
835
  var MIGRATIONS = [
628
836
  redisConversationStateMigration,
629
- sqlConversationMigration
837
+ sqlConversationMigration,
838
+ sqlPluginMigration,
839
+ pluginStorageMigration
630
840
  ];
841
+ function isMissingVirtualConfig(error) {
842
+ if (!(error instanceof Error)) {
843
+ return false;
844
+ }
845
+ const code = error.code;
846
+ return (code === "ERR_PACKAGE_IMPORT_NOT_DEFINED" || code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND") && error.message.includes("#junior/config");
847
+ }
848
+ async function resolveUpgradePluginSet() {
849
+ try {
850
+ const mod = await import("#junior/config");
851
+ return mod.pluginSet;
852
+ } catch (error) {
853
+ if (!isMissingVirtualConfig(error)) {
854
+ throw error;
855
+ }
856
+ }
857
+ return await loadAppPluginSet(
858
+ process.cwd(),
859
+ async (moduleRef) => localPluginLoader.import(moduleRef.importPath)
860
+ );
861
+ }
631
862
  function formatMigrationResult(result) {
632
863
  const fields = [
633
864
  `scanned=${result.scanned}`,
@@ -641,12 +872,14 @@ function formatMigrationResult(result) {
641
872
  return fields.join(" ");
642
873
  }
643
874
  async function runUpgradeMigrations(context) {
644
- requireConversationSqlDatabaseUrl(context);
875
+ const plugins = await resolveUpgradePlugins(context);
876
+ const migrationContext = { ...context, ...plugins };
877
+ migrationContext.sqlDatabaseUrl ??= requireConversationSqlDatabaseUrl(migrationContext);
645
878
  const results = [];
646
879
  for (const migration of MIGRATIONS) {
647
- context.io.info(`Running migration ${migration.name}...`);
648
- const result = await migration.run(context);
649
- context.io.info(
880
+ migrationContext.io.info(`Running migration ${migration.name}...`);
881
+ const result = await migration.run(migrationContext);
882
+ migrationContext.io.info(
650
883
  `Finished migration ${migration.name}: ${formatMigrationResult(result)}`
651
884
  );
652
885
  results.push(result);
@@ -656,14 +889,21 @@ async function runUpgradeMigrations(context) {
656
889
  async function runUpgrade(io = DEFAULT_IO) {
657
890
  try {
658
891
  const { redisStateAdapter, stateAdapter } = await getConnectedStateContext();
892
+ const pluginSet = await resolveUpgradePluginSet();
659
893
  io.info("Running Junior upgrade migrations...");
660
- await runUpgradeMigrations({ io, redisStateAdapter, stateAdapter });
894
+ await runUpgradeMigrations({
895
+ io,
896
+ pluginSet,
897
+ redisStateAdapter,
898
+ stateAdapter
899
+ });
661
900
  io.info("Junior upgrade complete.");
662
901
  } finally {
663
902
  await disconnectStateAdapter();
664
903
  }
665
904
  }
666
905
  export {
906
+ resolveUpgradePluginSet,
667
907
  runUpgrade,
668
908
  runUpgradeMigrations
669
909
  };