@opengeni/db 4.4.0-canary.0 → 4.4.0-canary.2

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 (105) hide show
  1. package/dist/canonical-human-identities.js +4 -3
  2. package/dist/{chunk-2ZMTQVTR.js → chunk-2KOLL33E.js} +2 -2
  3. package/dist/chunk-45CP2YKY.js +1062 -0
  4. package/dist/chunk-45CP2YKY.js.map +1 -0
  5. package/dist/{chunk-6TKL3GQO.js → chunk-5UUWZDAV.js} +6531 -6480
  6. package/dist/chunk-5UUWZDAV.js.map +1 -0
  7. package/dist/{chunk-QLA3UQNX.js → chunk-6IJD3XXF.js} +17 -3
  8. package/dist/chunk-6IJD3XXF.js.map +1 -0
  9. package/dist/{chunk-232VC2LW.js → chunk-6V3HDEMR.js} +2 -2
  10. package/dist/{chunk-M7PSMVFF.js → chunk-CHBLBEU6.js} +2 -2
  11. package/dist/chunk-M4PKBJRS.js +20318 -0
  12. package/dist/chunk-M4PKBJRS.js.map +1 -0
  13. package/dist/chunk-S2TZ3F4L.js +237 -0
  14. package/dist/chunk-S2TZ3F4L.js.map +1 -0
  15. package/dist/{chunk-UK57QA2H.js → chunk-UOXWVP3T.js} +2 -2
  16. package/dist/{chunk-GVZJ7XSR.js → chunk-WFU6PS54.js} +11 -4
  17. package/dist/chunk-WFU6PS54.js.map +1 -0
  18. package/dist/{chunk-THJGMEK5.js → chunk-XJP7KJ6U.js} +121 -66
  19. package/dist/chunk-XJP7KJ6U.js.map +1 -0
  20. package/dist/connection-token-resolver.d.ts +2 -0
  21. package/dist/database.d.ts +2 -0
  22. package/dist/editable-artifact-durable-export.js +3 -2
  23. package/dist/editable-artifact-durable-export.js.map +1 -1
  24. package/dist/editable-artifacts.js +4 -3
  25. package/dist/external-identities.d.ts +1 -0
  26. package/dist/external-membership-operations.d.ts +44 -0
  27. package/dist/governed-learning-evaluator.d.ts +1 -14
  28. package/dist/host-mcp-bindings.d.ts +4 -0
  29. package/dist/host-mcp-resolvers.d.ts +47 -0
  30. package/dist/host-mcp-task-authority.d.ts +2 -6
  31. package/dist/index.d.ts +29 -31
  32. package/dist/index.js +8616 -8321
  33. package/dist/index.js.map +1 -1
  34. package/dist/knowledge-document-preparation.d.ts +56 -0
  35. package/dist/knowledge-entries-schema.d.ts +2479 -0
  36. package/dist/knowledge-entries.d.ts +421 -0
  37. package/dist/knowledge-indexing.d.ts +99 -0
  38. package/dist/knowledge-migration.d.ts +6 -0
  39. package/dist/managed-auth-session-sets.js +4 -3
  40. package/dist/mcp-operations.js +3 -2
  41. package/dist/mcp-operations.js.map +1 -1
  42. package/dist/migrate.js +2 -1
  43. package/dist/provision-roles.js +1 -1
  44. package/dist/retained-provider-commands.js +3 -2
  45. package/dist/retained-provider-commands.js.map +1 -1
  46. package/dist/runtime-posture.d.ts +7 -7
  47. package/dist/schema.d.ts +115 -12
  48. package/dist/schema.js +26 -1
  49. package/dist/session-background-commands.js +5 -4
  50. package/dist/session-command-output.js +8 -6
  51. package/dist/session-command-output.js.map +1 -1
  52. package/dist/session-event-slices.js +6 -4
  53. package/dist/session-event-slices.js.map +1 -1
  54. package/dist/session-mcp-credential-rotation.js +5 -4
  55. package/dist/session-mcp-credential-rotation.js.map +1 -1
  56. package/dist/session-tenancy.js +4 -3
  57. package/dist/video-generation.js +4 -3
  58. package/dist/workspace-artifacts.d.ts +1 -0
  59. package/dist/workspace-instruction-policies-schema.d.ts +21 -2
  60. package/dist/workspace-instruction-policies.d.ts +1 -1
  61. package/dist/workspace-membership-access.d.ts +11 -0
  62. package/dist/workspace-tool-defaults.js +5 -4
  63. package/dist/workspace-tool-defaults.js.map +1 -1
  64. package/drizzle/0461_unified_knowledge.sql +2859 -0
  65. package/drizzle/0462_agent_instruction_non_destructive_edits.sql +212 -0
  66. package/drizzle/0463_host_mcp_resolver_registration.sql +111 -0
  67. package/drizzle/0464_external_workspace_membership_operations.sql +166 -0
  68. package/package.json +6 -6
  69. package/src/connection-token-resolver.ts +75 -6
  70. package/src/database.ts +12 -1
  71. package/src/external-identities.ts +1 -0
  72. package/src/external-membership-operations.ts +134 -0
  73. package/src/governed-learning-evaluator.ts +0 -69
  74. package/src/host-mcp-binding-match.ts +1 -0
  75. package/src/host-mcp-bindings.ts +24 -1
  76. package/src/host-mcp-resolvers.ts +266 -0
  77. package/src/host-mcp-task-authority.ts +11 -10
  78. package/src/index.ts +307 -128
  79. package/src/knowledge-document-preparation.ts +90 -0
  80. package/src/knowledge-entries-schema.ts +264 -0
  81. package/src/knowledge-entries.ts +860 -0
  82. package/src/knowledge-indexing.ts +126 -0
  83. package/src/knowledge-migration.ts +761 -0
  84. package/src/knowledge-source-sync.ts +46 -7
  85. package/src/migrate.ts +19 -0
  86. package/src/provision-roles.ts +23 -57
  87. package/src/runtime-posture.ts +103 -7
  88. package/src/schema.ts +15 -3
  89. package/src/skills.ts +4 -0
  90. package/src/video-generation.ts +14 -0
  91. package/src/workspace-artifacts.ts +2 -0
  92. package/src/workspace-instruction-policies-schema.ts +1 -0
  93. package/src/workspace-membership-access.ts +61 -0
  94. package/dist/chunk-6TKL3GQO.js.map +0 -1
  95. package/dist/chunk-EYF6MH6C.js +0 -4772
  96. package/dist/chunk-EYF6MH6C.js.map +0 -1
  97. package/dist/chunk-GSBONN55.js +0 -533
  98. package/dist/chunk-GSBONN55.js.map +0 -1
  99. package/dist/chunk-GVZJ7XSR.js.map +0 -1
  100. package/dist/chunk-QLA3UQNX.js.map +0 -1
  101. package/dist/chunk-THJGMEK5.js.map +0 -1
  102. /package/dist/{chunk-2ZMTQVTR.js.map → chunk-2KOLL33E.js.map} +0 -0
  103. /package/dist/{chunk-232VC2LW.js.map → chunk-6V3HDEMR.js.map} +0 -0
  104. /package/dist/{chunk-M7PSMVFF.js.map → chunk-CHBLBEU6.js.map} +0 -0
  105. /package/dist/{chunk-UK57QA2H.js.map → chunk-UOXWVP3T.js.map} +0 -0
@@ -1,533 +0,0 @@
1
- // src/migrate.ts
2
- import { readdir, readFile } from "fs/promises";
3
- import { dirname, join } from "path";
4
- import { fileURLToPath } from "url";
5
- import postgres from "postgres";
6
-
7
- // src/skill-config-migration.ts
8
- import { createHash } from "crypto";
9
- import {
10
- StoredCapabilityPack,
11
- StoredSessionSkills,
12
- validateSkillTextFiles
13
- } from "@opengeni/contracts";
14
-
15
- // src/skill-metadata-migration.ts
16
- import { readSkillMetadata } from "@opengeni/contracts";
17
- var SKILL_METADATA_MIGRATION_MARKER = "-- opengeni:skill-metadata-stage-v1";
18
- function prepareLegacySkillFolder(files, legacy) {
19
- const main = files.find((file) => file.path === "SKILL.md");
20
- if (!main) throw new Error(`Skill ${legacy.id} requires SKILL.md before migration`);
21
- let content = main.content;
22
- if (!/^\s*---(?:\r?\n|$)/u.test(content)) {
23
- const slug = legacy.title.normalize("NFKD").toLowerCase().replace(/[^a-z0-9]+/gu, "-").replace(/^-|-$/gu, "");
24
- const name = slug && slug.length <= 64 ? slug : `legacy-${legacy.id.replaceAll("-", "")}`;
25
- content = `---
26
- name: ${JSON.stringify(name)}
27
- description: ${JSON.stringify(legacy.description)}
28
- ---
29
- ${content}`;
30
- }
31
- const metadata = readSkillMetadata(content);
32
- return {
33
- files: files.map((file) => file.path === "SKILL.md" ? { ...file, content } : file),
34
- ...metadata
35
- };
36
- }
37
- async function createSkillMetadataMigrationStage(tx) {
38
- await tx`CREATE TEMP TABLE skill_metadata_0426 (
39
- source_kind text NOT NULL, source_id uuid NOT NULL, account_id uuid NOT NULL,
40
- workspace_id uuid, files jsonb NOT NULL, name text NOT NULL, description text NOT NULL
41
- ) ON COMMIT DROP`;
42
- }
43
- async function stageSkillMetadataMigration(tx) {
44
- const sources = await tx`
45
- SELECT 'installed' AS source_kind,sf.facet_id AS source_id,i.account_id,i.workspace_id,
46
- sf.name AS title,sf.description,
47
- coalesce(jsonb_agg(jsonb_build_object('path',ff.path,'content',ff.content) ORDER BY ff.path COLLATE "C")
48
- FILTER (WHERE ff.id IS NOT NULL),'[]'::jsonb) AS files
49
- FROM capability_plugin_installations i JOIN capability_facets f ON f.plugin_version_id=i.plugin_version_id
50
- JOIN capability_skill_facets sf ON sf.facet_id=f.id LEFT JOIN capability_skill_files ff ON ff.skill_facet_id=sf.facet_id
51
- WHERE i.status='active'
52
- GROUP BY i.account_id,i.workspace_id,sf.facet_id
53
- UNION ALL
54
- SELECT 'authored',h.id,h.account_id,h.scope_workspace_id,r.title,r.description,
55
- coalesce(r.skill_files,jsonb_build_array(jsonb_build_object('path','SKILL.md','content',r.content)))
56
- FROM preference_registry_preferences h JOIN preference_registry_revisions r
57
- ON r.id=h.active_revision_id AND r.preference_id=h.id AND r.account_id=h.account_id
58
- WHERE h.status='active'
59
- `;
60
- for (const source of sources) {
61
- let folder;
62
- try {
63
- folder = prepareLegacySkillFolder(source.files, {
64
- id: source.source_id,
65
- title: source.title,
66
- description: source.description
67
- });
68
- } catch (cause) {
69
- throw new Error(
70
- `Skill ${source.source_kind}:${source.source_id} needs explicit frontmatter repair before 0433`,
71
- { cause }
72
- );
73
- }
74
- const [valid] = await tx`SELECT skill_files_valid(${tx.json(folder.files)}) AS valid`;
75
- if (!valid?.valid)
76
- throw new Error(
77
- `Skill ${source.source_id} exceeds the valid folder limits after metadata migration`
78
- );
79
- await tx`INSERT INTO pg_temp.skill_metadata_0426(source_kind,source_id,account_id,workspace_id,files,name,description)
80
- VALUES(${source.source_kind},${source.source_id},${source.account_id},${source.workspace_id},${tx.json(folder.files)},${folder.name},${folder.description})`;
81
- }
82
- }
83
-
84
- // src/skill-config-migration.ts
85
- function object(value) {
86
- if (!value || typeof value !== "object" || Array.isArray(value))
87
- throw new Error("Expected stored configuration object");
88
- return value;
89
- }
90
- function convertLegacyConfigSkills(value, identity) {
91
- if (!Array.isArray(value)) throw new Error("Expected stored Skill array");
92
- const names = /* @__PURE__ */ new Set();
93
- const converted = value.map((entry, index) => {
94
- const skill = object(entry);
95
- if (!Array.isArray(skill.files)) throw new Error("Expected stored Skill folder");
96
- const files = skill.files.map((fileEntry) => {
97
- const file = object(fileEntry);
98
- if (typeof file.path !== "string" || typeof file.content !== "string")
99
- throw new Error("Invalid stored Skill text file");
100
- if (Object.keys(file).some((key) => key !== "path" && key !== "content"))
101
- throw new Error("Unexpected stored Skill file fields");
102
- return { path: file.path, content: file.content };
103
- });
104
- const main = files.find((file) => file.path === "SKILL.md");
105
- const plain = main && !/^\s*---(?:\r?\n|$)/u.test(main.content);
106
- if (plain && (typeof skill.name !== "string" || typeof skill.description !== "string"))
107
- throw new Error("Plain Skill requires historical name and description");
108
- const folder = prepareLegacySkillFolder(files, {
109
- id: createHash("sha256").update(`${identity}:${index}`).digest("hex").slice(0, 32),
110
- title: typeof skill.name === "string" ? skill.name : "",
111
- description: typeof skill.description === "string" ? skill.description : ""
112
- });
113
- validateSkillTextFiles(folder.files);
114
- if (names.has(folder.name)) throw new Error(`Canonical Skill name collision: ${folder.name}`);
115
- names.add(folder.name);
116
- return plain ? { ...skill, ...folder } : entry;
117
- });
118
- StoredSessionSkills.parse(converted);
119
- return converted;
120
- }
121
- function convertLegacyPackConfig(value, identity) {
122
- const pack = object(value);
123
- const converted = { ...pack };
124
- if (pack.skills !== void 0)
125
- converted.skills = convertLegacyConfigSkills(pack.skills, identity);
126
- if (Array.isArray(pack.automationTemplates))
127
- converted.automationTemplates = pack.automationTemplates.map((entry, index) => {
128
- const template = object(entry);
129
- const sessionTemplate = object(template.sessionTemplate);
130
- return {
131
- ...template,
132
- sessionTemplate: {
133
- ...sessionTemplate,
134
- ...sessionTemplate.skills !== void 0 ? {
135
- skills: convertLegacyConfigSkills(
136
- sessionTemplate.skills,
137
- `${identity}:template:${index}`
138
- )
139
- } : {}
140
- }
141
- };
142
- });
143
- StoredCapabilityPack.parse(converted);
144
- return converted;
145
- }
146
- async function assertSkillConfigurationMaintenanceWindow(tx) {
147
- const rows = await tx`SELECT c.oid FROM pg_class c
148
- WHERE c.oid='sessions'::regclass AND pg_get_userbyid(c.relowner)=current_user
149
- AND c.relrowsecurity AND NOT c.relforcerowsecurity
150
- AND to_regclass('pg_temp.skill_metadata_0426') IS NOT NULL`;
151
- if (rows.length !== 1)
152
- throw new Error(
153
- "Skill configuration conversion requires the parser-backed maintenance owner window"
154
- );
155
- }
156
- async function migrateLegacySkillConfigurations(tx) {
157
- await assertSkillConfigurationMaintenanceWindow(tx);
158
- await tx`SELECT pg_advisory_xact_lock(hashtextextended('session-tenancy:'||workspace_id::text,0))
159
- FROM (SELECT DISTINCT workspace_id FROM sessions ORDER BY workspace_id) workspaces`;
160
- await tx`LOCK TABLE sessions, workspace_packs, session_turns, automation_triggers,
161
- automation_trigger_revisions, automation_runs, automation_trigger_events, automation_run_event_links, pack_installations IN SHARE ROW EXCLUSIVE MODE`;
162
- const pinned = await tx`
163
- SELECT 'pack-installation' AS kind,id::text,manifest_snapshot AS value FROM pack_installations
164
- WHERE status <> 'disabled' AND manifest_snapshot IS NOT NULL
165
- UNION ALL SELECT 'automation-current',t.id::text,jsonb_build_object('skills',r.session_template->'skills')
166
- FROM automation_triggers t JOIN automation_trigger_revisions r ON r.trigger_id=t.id AND r.revision=t.current_revision
167
- WHERE t.status IN ('active','paused') AND r.session_template ? 'skills'
168
- UNION ALL SELECT 'automation-run',id::text,jsonb_build_object('skills',accepted_execution->'sessionTemplate'->'skills')
169
- FROM automation_runs WHERE status IN ('queued','dispatching') AND accepted_execution->'sessionTemplate' ? 'skills'
170
- UNION ALL SELECT 'automation-event',e.id::text,jsonb_build_object('skills',r.session_template->'skills')
171
- FROM automation_trigger_events e CROSS JOIN LATERAL jsonb_array_elements(e.matched_trigger_revisions) matched
172
- JOIN automation_trigger_revisions r ON r.trigger_id=(matched->>'triggerId')::uuid AND r.revision=(matched->>'revision')::integer
173
- WHERE e.status='accepted' AND r.session_template ? 'skills'
174
- AND NOT EXISTS (SELECT 1 FROM automation_runs run WHERE run.event_id=e.id AND run.trigger_id=r.trigger_id AND run.trigger_revision=r.revision)
175
- AND NOT EXISTS (SELECT 1 FROM automation_run_event_links link WHERE link.event_id=e.id AND link.trigger_id=r.trigger_id)
176
- `;
177
- const blockers = [];
178
- for (const source of pinned) {
179
- try {
180
- const original = object(source.value);
181
- const converted = source.kind === "pack-installation" ? convertLegacyPackConfig(original, source.id) : { ...original, skills: convertLegacyConfigSkills(original.skills, source.id) };
182
- if (JSON.stringify(converted) !== JSON.stringify(original))
183
- blockers.push(`${source.kind}:${source.id} (plain content)`);
184
- } catch {
185
- blockers.push(`${source.kind}:${source.id} (invalid content)`);
186
- }
187
- }
188
- const candidates = await tx`
189
- SELECT 'session' AS kind,s.id::text,s.account_id,s.workspace_id,s.skills AS original,
190
- (s.active_turn_id IS NOT NULL OR EXISTS(SELECT 1 FROM session_turns t WHERE t.session_id=s.id AND t.status NOT IN ('completed','failed','cancelled'))) AS pinned
191
- FROM sessions s WHERE s.skills <> '[]'::jsonb
192
- UNION ALL SELECT 'workspace-pack',id::text,account_id,workspace_id,manifest,false FROM workspace_packs
193
- `;
194
- const changes = [];
195
- for (const source of candidates) {
196
- try {
197
- const converted = source.kind === "session" ? convertLegacyConfigSkills(source.original, source.id) : convertLegacyPackConfig(source.original, source.id);
198
- if (source.kind === "session") StoredSessionSkills.parse(converted);
199
- if (JSON.stringify(source.original) !== JSON.stringify(converted)) {
200
- if (source.pinned) blockers.push(`${source.kind}:${source.id} (runnable accepted turn)`);
201
- else changes.push({ source, converted });
202
- }
203
- } catch {
204
- blockers.push(`${source.kind}:${source.id} (invalid content or canonical collision)`);
205
- }
206
- }
207
- if (blockers.length)
208
- throw new Error(
209
- `0433 Skill configuration preflight: ${blockers.length} repair-required sources; drain or explicitly replace pinned sources before retry: ${blockers.slice(0, 30).join(", ")}`
210
- );
211
- for (const { source, converted } of changes) {
212
- const original = tx.json(source.original);
213
- const replacement = tx.json(converted);
214
- await tx`INSERT INTO skill_config_conversion_receipts(account_id,workspace_id,source_kind,source_id,original_configuration,original_hash,replacement_hash)
215
- VALUES(${source.account_id},${source.workspace_id},${source.kind},${source.id},${original},
216
- encode(sha256(convert_to(${original}::jsonb::text,'UTF8')),'hex'),encode(sha256(convert_to(${replacement}::jsonb::text,'UTF8')),'hex'))`;
217
- const updated = source.kind === "session" ? await tx`UPDATE sessions SET skills=${replacement} WHERE id=${source.id} AND account_id=${source.account_id} AND workspace_id=${source.workspace_id} AND skills=${original} RETURNING id` : await tx`UPDATE workspace_packs SET manifest=${replacement} WHERE id=${source.id} AND account_id=${source.account_id} AND workspace_id=${source.workspace_id} AND manifest=${original} RETURNING id`;
218
- if (updated.length !== 1)
219
- throw new Error(`0433 Skill configuration CAS conflict: ${source.kind}:${source.id}`);
220
- }
221
- }
222
-
223
- // src/migration-runner-settings.ts
224
- function batchedBackfillTransactionLocalSetting(file) {
225
- if (file === "0411_new_session_draft_project_provenance_backfill.sql") {
226
- return {
227
- guc: "opengeni.new_session_draft_project_provenance_backfill_v1",
228
- value: "1"
229
- };
230
- }
231
- return null;
232
- }
233
-
234
- // src/migrate.ts
235
- var DEFAULT_DATABASE_URL = "postgres://opengeni:opengeni@127.0.0.1:5432/opengeni";
236
- var DEFAULT_MAX_NESTED_AGENT_DEPTH = 3;
237
- var MAX_NESTED_AGENT_DEPTH = 2147483647;
238
- var DEFAULT_APPLICATION_DATABASE_ROLE = "opengeni_app";
239
- var MIGRATION_APPLICATION_ROLES_SETTING = "opengeni.migration_application_roles";
240
- var MAX_MIGRATION_APPLICATION_ROLES = 16;
241
- var batchedBackfillDirective = /^-- opengeni:batched-backfill batch-size=(\d+) lock-timeout=(\d+(?:ms|s|min)) statement-timeout=(\d+(?:ms|s|min))$/;
242
- var concurrentIndexDirective = /^-- opengeni:concurrent-index lock-timeout=(\d+(?:ms|s|min))$/;
243
- var concurrentIndexStatement = /^CREATE\s+(?:UNIQUE\s+)?INDEX\s+CONCURRENTLY\s+(?:(IF\s+NOT\s+EXISTS)\s+)?(?:"((?:[^"]|"")+)"|([A-Za-z_][A-Za-z0-9_]*))\s+ON\b/is;
244
- var governedLegacyConcurrentIndexMigrations = /* @__PURE__ */ new Set([
245
- "0066_session_interruption_attempt_lookup.sql",
246
- "0070_session_event_type_sequence_lookup.sql",
247
- "0071_session_event_monitoring_tail.sql",
248
- "0072_sessions_workspace_created_id_idx.sql",
249
- "0073_sessions_workspace_updated_id_idx.sql",
250
- "0075_sessions_workspace_activity_revision_idx.sql",
251
- "0077_session_attempt_latest_lookup.sql"
252
- ]);
253
- function assertIdentifier(name, value) {
254
- if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(value)) {
255
- throw new Error(`${name} is not a valid Postgres identifier: ${value}`);
256
- }
257
- return value;
258
- }
259
- function parseConcurrentIndexMigration(file, sqlText) {
260
- const lines = sqlText.replaceAll("\r\n", "\n").split("\n");
261
- const firstLine = lines[0]?.trim() ?? "";
262
- const deploymentPrefixed = /^-- deployment-mode: (?:rolling|maintenance)$/.test(firstLine);
263
- const directiveIndex = deploymentPrefixed ? 1 : 0;
264
- const directiveLine = lines[directiveIndex]?.trim() ?? "";
265
- const directive = concurrentIndexDirective.exec(directiveLine);
266
- if (!directive) {
267
- if (directiveLine.startsWith("-- opengeni:")) {
268
- throw new Error(`Unsupported OpenGeni migration directive in ${file}`);
269
- }
270
- return null;
271
- }
272
- const lockTimeout = directive[1];
273
- const statement = lines.slice(directiveIndex + 1).join("\n").trim();
274
- const withoutTrailingSemicolon = statement.endsWith(";") ? statement.slice(0, -1).trimEnd() : statement;
275
- const parsedStatement = concurrentIndexStatement.exec(withoutTrailingSemicolon);
276
- if (!parsedStatement || withoutTrailingSemicolon.includes(";")) {
277
- throw new Error(
278
- `${file}: opengeni:concurrent-index requires exactly one CREATE [UNIQUE] INDEX CONCURRENTLY IF NOT EXISTS statement with an unqualified index name`
279
- );
280
- }
281
- const idempotentInSql = parsedStatement[1] !== void 0;
282
- if (!idempotentInSql && !governedLegacyConcurrentIndexMigrations.has(file)) {
283
- throw new Error(
284
- `${file}: opengeni:concurrent-index requires IF NOT EXISTS; bare statements are supported only for governed historical migrations`
285
- );
286
- }
287
- return {
288
- indexName: (parsedStatement[2] ?? parsedStatement[3]).replaceAll('""', '"'),
289
- lockTimeout,
290
- skipWhenValid: !idempotentInSql,
291
- statement
292
- };
293
- }
294
- function parseBatchedBackfillMigration(file, sqlText) {
295
- const lines = sqlText.replaceAll("\r\n", "\n").split("\n");
296
- const directiveIndex = /^-- deployment-mode: (?:rolling|maintenance)$/.test(
297
- lines[0]?.trim() ?? ""
298
- ) ? 1 : 0;
299
- const directive = batchedBackfillDirective.exec(lines[directiveIndex]?.trim() ?? "");
300
- if (!directive) return null;
301
- const statement = lines.slice(directiveIndex + 1).filter((line) => !line.trim().startsWith("--")).join("\n").trim();
302
- const withoutTrailingSemicolon = statement.endsWith(";") ? statement.slice(0, -1).trimEnd() : statement;
303
- const batchSize = Number(directive[1]);
304
- if (!Number.isSafeInteger(batchSize) || batchSize < 1 || batchSize > 1e4 || !/^WITH\b/is.test(withoutTrailingSemicolon) || !/\bUPDATE\b/is.test(withoutTrailingSemicolon) || !/\bRETURNING\b/is.test(withoutTrailingSemicolon) || !new RegExp(`\\bLIMIT\\s+${batchSize}\\b`, "i").test(withoutTrailingSemicolon) || withoutTrailingSemicolon.includes(";")) {
305
- throw new Error(
306
- `${file}: opengeni:batched-backfill requires one bounded WITH ... UPDATE ... RETURNING statement whose LIMIT matches batch-size`
307
- );
308
- }
309
- return {
310
- batchSize,
311
- lockTimeout: directive[2],
312
- statementTimeout: directive[3],
313
- statement
314
- };
315
- }
316
- async function executeMigrationFile(sql, file, sqlText) {
317
- if (sqlText.includes(SKILL_METADATA_MIGRATION_MARKER)) {
318
- if (file !== "0433_unified_skill_lifecycle.sql")
319
- throw new Error("Skill metadata stage is restricted to migration 0433");
320
- const parts = sqlText.split(SKILL_METADATA_MIGRATION_MARKER);
321
- if (parts.length !== 2) throw new Error("0433 requires exactly one Skill metadata stage");
322
- await sql.begin(async (transaction) => {
323
- await createSkillMetadataMigrationStage(transaction);
324
- await transaction`SELECT
325
- pg_catalog.set_config('opengeni.sandbox_recovery_protocol_v2','1',true),
326
- pg_catalog.set_config('opengeni.session_variable_set_attachments_v1','1',true)`;
327
- await transaction.unsafe(parts[0]);
328
- await stageSkillMetadataMigration(transaction);
329
- await migrateLegacySkillConfigurations(transaction);
330
- await transaction.unsafe(parts[1]);
331
- await transaction`INSERT INTO schema_migrations(name) VALUES(${file}) ON CONFLICT DO NOTHING`;
332
- });
333
- return;
334
- }
335
- const batchedBackfill = parseBatchedBackfillMigration(file, sqlText);
336
- if (batchedBackfill) {
337
- await sql`select set_config('lock_timeout', ${batchedBackfill.lockTimeout}, false)`;
338
- await sql`select set_config('statement_timeout', ${batchedBackfill.statementTimeout}, false)`;
339
- try {
340
- for (; ; ) {
341
- const result = await sql.begin(async (transaction) => {
342
- const transactionLocalSetting = batchedBackfillTransactionLocalSetting(file);
343
- await transaction`select
344
- pg_catalog.set_config('opengeni.sandbox_recovery_protocol_v2', '1', true),
345
- pg_catalog.set_config(
346
- 'opengeni.session_variable_set_attachments_v1',
347
- '1',
348
- true
349
- )`;
350
- if (transactionLocalSetting) {
351
- await transaction`select pg_catalog.set_config(
352
- ${transactionLocalSetting.guc},
353
- ${transactionLocalSetting.value},
354
- true
355
- )`;
356
- }
357
- return await transaction.unsafe(batchedBackfill.statement);
358
- });
359
- if (result.length === 0) break;
360
- }
361
- } finally {
362
- await sql`select set_config('statement_timeout', '0', false)`;
363
- await sql`select set_config('lock_timeout', '0', false)`;
364
- }
365
- return;
366
- }
367
- const concurrentIndex = parseConcurrentIndexMigration(file, sqlText);
368
- if (!concurrentIndex) {
369
- await sql.unsafe(
370
- `SELECT
371
- pg_catalog.set_config('opengeni.sandbox_recovery_protocol_v2', '1', true),
372
- pg_catalog.set_config('opengeni.session_variable_set_attachments_v1', '1', true);
373
- ${file === "0434_ordered_model_history.sql" ? "SET CONSTRAINTS ALL IMMEDIATE;\n" : ""}${sqlText}`
374
- );
375
- return;
376
- }
377
- await sql`select set_config('lock_timeout', ${concurrentIndex.lockTimeout}, false)`;
378
- try {
379
- const [existing] = await sql`
380
- select i.indisvalid as valid, i.indisready as ready
381
- from pg_catalog.pg_class c
382
- join pg_catalog.pg_namespace n on n.oid = c.relnamespace
383
- join pg_catalog.pg_index i on i.indexrelid = c.oid
384
- where n.nspname = current_schema() and c.relname = ${concurrentIndex.indexName}
385
- `;
386
- if (existing && (!existing.valid || !existing.ready)) {
387
- const quotedIndexName = `"${concurrentIndex.indexName.replaceAll('"', '""')}"`;
388
- await sql.unsafe(`DROP INDEX CONCURRENTLY ${quotedIndexName}`);
389
- } else if (existing && concurrentIndex.skipWhenValid) {
390
- return;
391
- }
392
- await sql.unsafe(concurrentIndex.statement);
393
- } finally {
394
- await sql`select set_config('lock_timeout', '0', false)`;
395
- }
396
- }
397
- function deploymentDepthPolicy(options) {
398
- const raw = options === void 0 ? process.env.OPENGENI_MAX_NESTED_AGENT_DEPTH?.trim() || void 0 : options.maxNestedAgentDepth;
399
- if (raw === void 0) {
400
- return { maxNestedAgentDepth: DEFAULT_MAX_NESTED_AGENT_DEPTH, source: "default" };
401
- }
402
- const value = typeof raw === "number" ? raw : Number(raw);
403
- if (!Number.isSafeInteger(value) || value < 0 || value > MAX_NESTED_AGENT_DEPTH || typeof raw === "string" && !/^(0|[1-9][0-9]*)$/.test(raw)) {
404
- throw new Error(
405
- `OPENGENI_MAX_NESTED_AGENT_DEPTH must be a non-negative 32-bit integer: ${raw}`
406
- );
407
- }
408
- return { maxNestedAgentDepth: value, source: "deployment" };
409
- }
410
- function migrationApplicationRoles(schema, options) {
411
- const configured = options?.applicationDatabaseRoles;
412
- const environment = process.env.OPENGENI_MIGRATION_APPLICATION_DATABASE_ROLES?.trim();
413
- const explicit = configured !== void 0 ? configured : environment ? environment.split(",").map((role) => role.trim()) : void 0;
414
- if (!explicit) {
415
- const configuredRuntimeRoles = [
416
- process.env.OPENGENI_APP_DATABASE_USER?.trim(),
417
- process.env.OPENGENI_RUNTIME_DATABASE_ROLE?.trim()
418
- ].filter((role) => Boolean(role) && role !== DEFAULT_APPLICATION_DATABASE_ROLE);
419
- if (schema || configuredRuntimeRoles.length > 0) {
420
- throw new Error(
421
- "Pending migrations require the exact application database roles via MigrationRuntimeOptions.applicationDatabaseRoles or OPENGENI_MIGRATION_APPLICATION_DATABASE_ROLES for dedicated-schema or custom-role deployments"
422
- );
423
- }
424
- return [DEFAULT_APPLICATION_DATABASE_ROLE];
425
- }
426
- if (configured !== void 0 && configured.some((role) => typeof role !== "string" || role !== role.trim())) {
427
- throw new Error(
428
- "MigrationRuntimeOptions.applicationDatabaseRoles must contain canonical Postgres role names without surrounding whitespace"
429
- );
430
- }
431
- if (explicit.length < 1 || explicit.length > MAX_MIGRATION_APPLICATION_ROLES) {
432
- throw new Error(
433
- `Migration application database roles must contain 1-${MAX_MIGRATION_APPLICATION_ROLES} entries`
434
- );
435
- }
436
- const normalized = [...new Set(explicit)].sort(
437
- (left, right) => Buffer.compare(Buffer.from(left, "utf8"), Buffer.from(right, "utf8"))
438
- );
439
- if (normalized.length !== explicit.length || normalized.some((role) => role.length === 0 || Buffer.byteLength(role, "utf8") > 63)) {
440
- throw new Error(
441
- "Migration application database roles must be unique, non-empty Postgres role names of at most 63 UTF-8 bytes"
442
- );
443
- }
444
- return normalized;
445
- }
446
- async function persistDeploymentDepthPolicy(sql, policy) {
447
- const [relation] = await sql`
448
- select to_regclass('nested_agent_depth_configuration') is not null as exists
449
- `;
450
- if (!relation?.exists) return;
451
- await sql`
452
- insert into "nested_agent_depth_configuration" (
453
- "singleton", "max_nested_agent_depth", "policy_source", "updated_at"
454
- ) values (true, ${policy.maxNestedAgentDepth}, ${policy.source}, now())
455
- on conflict ("singleton") do update
456
- set "max_nested_agent_depth" = excluded."max_nested_agent_depth",
457
- "policy_source" = excluded."policy_source",
458
- "updated_at" = now()
459
- where "nested_agent_depth_configuration"."max_nested_agent_depth"
460
- is distinct from excluded."max_nested_agent_depth"
461
- or "nested_agent_depth_configuration"."policy_source"
462
- is distinct from excluded."policy_source"
463
- `;
464
- }
465
- async function migrate(databaseUrl = process.env.OPENGENI_MIGRATIONS_DATABASE_URL ?? process.env.OPENGENI_DATABASE_URL ?? DEFAULT_DATABASE_URL, schema = process.env.OPENGENI_DB_SCHEMA?.trim() || void 0, runtimeOptions) {
466
- const migrationsDir = join(dirname(fileURLToPath(import.meta.url)), "../drizzle");
467
- const files = (await readdir(migrationsDir)).filter((file) => file.endsWith(".sql")).sort();
468
- const depthPolicy = deploymentDepthPolicy(runtimeOptions);
469
- const sql = postgres(databaseUrl, { max: 1 });
470
- try {
471
- await sql`SELECT pg_advisory_lock(727458)`;
472
- if (schema) {
473
- assertIdentifier("OPENGENI_DB_SCHEMA", schema);
474
- await sql.unsafe(`CREATE SCHEMA IF NOT EXISTS "${schema}"`);
475
- await sql.unsafe(`CREATE SCHEMA IF NOT EXISTS "opengeni_private"`);
476
- await sql.unsafe(`SET search_path = "${schema}", "opengeni_private", "public"`);
477
- }
478
- await sql`select set_config('opengeni.max_nested_agent_depth', ${String(depthPolicy.maxNestedAgentDepth)}, false)`;
479
- await sql`select set_config('opengeni.nested_agent_depth_policy_source', ${depthPolicy.source}, false)`;
480
- await sql.unsafe(
481
- `CREATE TABLE IF NOT EXISTS "schema_migrations" ("name" text PRIMARY KEY, "applied_at" timestamptz NOT NULL DEFAULT now())`
482
- );
483
- const appliedRows = await sql`SELECT "name" FROM "schema_migrations"`;
484
- const applied = new Set(appliedRows.map((row) => row.name));
485
- const pendingMigrationSources = /* @__PURE__ */ new Map();
486
- for (const file of files) {
487
- if (!applied.has(file)) {
488
- pendingMigrationSources.set(file, await readFile(join(migrationsDir, file), "utf8"));
489
- }
490
- }
491
- if (Array.from(pendingMigrationSources.values()).some(
492
- (source) => source.includes(MIGRATION_APPLICATION_ROLES_SETTING)
493
- )) {
494
- const applicationRoles = migrationApplicationRoles(schema, runtimeOptions);
495
- await sql`select set_config(
496
- ${MIGRATION_APPLICATION_ROLES_SETTING},
497
- ${JSON.stringify(applicationRoles)},
498
- false
499
- )`;
500
- }
501
- for (const file of files) {
502
- if (applied.has(file)) {
503
- continue;
504
- }
505
- const sqlText = pendingMigrationSources.get(file);
506
- if (sqlText === void 0) {
507
- throw new Error(`Pending migration source was not loaded: ${file}`);
508
- }
509
- await executeMigrationFile(sql, file, sqlText);
510
- await sql`INSERT INTO "schema_migrations" ("name") VALUES (${file}) ON CONFLICT DO NOTHING`;
511
- }
512
- await persistDeploymentDepthPolicy(sql, depthPolicy);
513
- } finally {
514
- await sql.end();
515
- }
516
- }
517
- async function runMigrations(adminConnection, targetSchema, runtimeOptions) {
518
- await migrate(adminConnection, targetSchema, runtimeOptions);
519
- }
520
- if (import.meta.main) {
521
- await migrate();
522
- console.log("Applied Drizzle SQL migrations.");
523
- }
524
-
525
- export {
526
- parseConcurrentIndexMigration,
527
- parseBatchedBackfillMigration,
528
- executeMigrationFile,
529
- migrationApplicationRoles,
530
- migrate,
531
- runMigrations
532
- };
533
- //# sourceMappingURL=chunk-GSBONN55.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/migrate.ts","../src/skill-config-migration.ts","../src/skill-metadata-migration.ts","../src/migration-runner-settings.ts"],"sourcesContent":["import { readdir, readFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport postgres from \"postgres\";\nimport { migrateLegacySkillConfigurations } from \"./skill-config-migration\";\nimport { batchedBackfillTransactionLocalSetting } from \"./migration-runner-settings\";\nimport {\n SKILL_METADATA_MIGRATION_MARKER,\n createSkillMetadataMigrationStage,\n stageSkillMetadataMigration,\n} from \"./skill-metadata-migration\";\n\nconst DEFAULT_DATABASE_URL = \"postgres://opengeni:opengeni@127.0.0.1:5432/opengeni\";\nconst DEFAULT_MAX_NESTED_AGENT_DEPTH = 3;\nconst MAX_NESTED_AGENT_DEPTH = 2_147_483_647;\nconst DEFAULT_APPLICATION_DATABASE_ROLE = \"opengeni_app\";\nconst MIGRATION_APPLICATION_ROLES_SETTING = \"opengeni.migration_application_roles\";\nconst MAX_MIGRATION_APPLICATION_ROLES = 16;\nconst batchedBackfillDirective =\n /^-- opengeni:batched-backfill batch-size=(\\d+) lock-timeout=(\\d+(?:ms|s|min)) statement-timeout=(\\d+(?:ms|s|min))$/;\nconst concurrentIndexDirective = /^-- opengeni:concurrent-index lock-timeout=(\\d+(?:ms|s|min))$/;\nconst concurrentIndexStatement =\n /^CREATE\\s+(?:UNIQUE\\s+)?INDEX\\s+CONCURRENTLY\\s+(?:(IF\\s+NOT\\s+EXISTS)\\s+)?(?:\"((?:[^\"]|\"\")+)\"|([A-Za-z_][A-Za-z0-9_]*))\\s+ON\\b/is;\nconst governedLegacyConcurrentIndexMigrations = new Set([\n \"0066_session_interruption_attempt_lookup.sql\",\n \"0070_session_event_type_sequence_lookup.sql\",\n \"0071_session_event_monitoring_tail.sql\",\n \"0072_sessions_workspace_created_id_idx.sql\",\n \"0073_sessions_workspace_updated_id_idx.sql\",\n \"0075_sessions_workspace_activity_revision_idx.sql\",\n \"0077_session_attempt_latest_lookup.sql\",\n]);\nexport interface ConcurrentIndexMigration {\n indexName: string;\n lockTimeout: string;\n skipWhenValid: boolean;\n statement: string;\n}\n\nexport type MigrationRuntimeOptions = {\n maxNestedAgentDepth?: number;\n /**\n * Exact database login roles that may run an OpenGeni API or worker against\n * this target. Maintenance cutovers use this list to reject a live mixed-\n * version fleet, and rolling ACL migrations use it to preserve old-binary\n * readiness until later role provisioning converges. Dedicated-schema and\n * custom-role deployments must supply it.\n */\n applicationDatabaseRoles?: string[];\n};\n\ntype DeploymentDepthPolicy = {\n maxNestedAgentDepth: number;\n source: \"deployment\" | \"default\";\n};\n\n/** A bare Postgres identifier (schema/role name) safe to interpolate into DDL. */\nfunction assertIdentifier(name: string, value: string): string {\n if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(value)) {\n throw new Error(`${name} is not a valid Postgres identifier: ${value}`);\n }\n return value;\n}\n\n/**\n * Most migration files intentionally execute as one implicit transaction.\n * PostgreSQL forbids CREATE INDEX CONCURRENTLY there, so a migration may opt\n * into one narrowly validated transactionless statement with:\n *\n * -- opengeni:concurrent-index lock-timeout=5s\n * CREATE [UNIQUE] INDEX CONCURRENTLY IF NOT EXISTS ...;\n *\n * The directive is deliberately not a generic \"no transaction\" escape hatch:\n * only one idempotent concurrent-index statement is accepted, lock acquisition\n * is always bounded, and an invalid artifact left by a failed concurrent build\n * is removed before retry. Seven governed historical migrations predate the\n * IF NOT EXISTS rule; only those exact filenames may use their immutable bare\n * statements, and the runner makes their retries idempotent by skipping an\n * already-valid index. This keeps additive large-table indexes online without\n * rewriting shipped history or making arbitrary partially-applied migration\n * scripts possible.\n */\nexport function parseConcurrentIndexMigration(\n file: string,\n sqlText: string,\n): ConcurrentIndexMigration | null {\n const lines = sqlText.replaceAll(\"\\r\\n\", \"\\n\").split(\"\\n\");\n const firstLine = lines[0]?.trim() ?? \"\";\n const deploymentPrefixed = /^-- deployment-mode: (?:rolling|maintenance)$/.test(firstLine);\n const directiveIndex = deploymentPrefixed ? 1 : 0;\n const directiveLine = lines[directiveIndex]?.trim() ?? \"\";\n const directive = concurrentIndexDirective.exec(directiveLine);\n if (!directive) {\n if (directiveLine.startsWith(\"-- opengeni:\")) {\n throw new Error(`Unsupported OpenGeni migration directive in ${file}`);\n }\n return null;\n }\n\n const lockTimeout = directive[1]!;\n const statement = lines\n .slice(directiveIndex + 1)\n .join(\"\\n\")\n .trim();\n const withoutTrailingSemicolon = statement.endsWith(\";\")\n ? statement.slice(0, -1).trimEnd()\n : statement;\n const parsedStatement = concurrentIndexStatement.exec(withoutTrailingSemicolon);\n if (!parsedStatement || withoutTrailingSemicolon.includes(\";\")) {\n throw new Error(\n `${file}: opengeni:concurrent-index requires exactly one CREATE [UNIQUE] INDEX CONCURRENTLY IF NOT EXISTS statement with an unqualified index name`,\n );\n }\n const idempotentInSql = parsedStatement[1] !== undefined;\n if (!idempotentInSql && !governedLegacyConcurrentIndexMigrations.has(file)) {\n throw new Error(\n `${file}: opengeni:concurrent-index requires IF NOT EXISTS; bare statements are supported only for governed historical migrations`,\n );\n }\n return {\n indexName: (parsedStatement[2] ?? parsedStatement[3]!).replaceAll('\"\"', '\"'),\n lockTimeout,\n skipWhenValid: !idempotentInSql,\n statement,\n };\n}\n\nexport function parseBatchedBackfillMigration(\n file: string,\n sqlText: string,\n): { batchSize: number; lockTimeout: string; statementTimeout: string; statement: string } | null {\n const lines = sqlText.replaceAll(\"\\r\\n\", \"\\n\").split(\"\\n\");\n const directiveIndex = /^-- deployment-mode: (?:rolling|maintenance)$/.test(\n lines[0]?.trim() ?? \"\",\n )\n ? 1\n : 0;\n const directive = batchedBackfillDirective.exec(lines[directiveIndex]?.trim() ?? \"\");\n if (!directive) return null;\n const statement = lines\n .slice(directiveIndex + 1)\n .filter((line) => !line.trim().startsWith(\"--\"))\n .join(\"\\n\")\n .trim();\n const withoutTrailingSemicolon = statement.endsWith(\";\")\n ? statement.slice(0, -1).trimEnd()\n : statement;\n const batchSize = Number(directive[1]!);\n if (\n !Number.isSafeInteger(batchSize) ||\n batchSize < 1 ||\n batchSize > 10_000 ||\n !/^WITH\\b/is.test(withoutTrailingSemicolon) ||\n !/\\bUPDATE\\b/is.test(withoutTrailingSemicolon) ||\n !/\\bRETURNING\\b/is.test(withoutTrailingSemicolon) ||\n !new RegExp(`\\\\bLIMIT\\\\s+${batchSize}\\\\b`, \"i\").test(withoutTrailingSemicolon) ||\n withoutTrailingSemicolon.includes(\";\")\n ) {\n throw new Error(\n `${file}: opengeni:batched-backfill requires one bounded WITH ... UPDATE ... RETURNING statement whose LIMIT matches batch-size`,\n );\n }\n return {\n batchSize,\n lockTimeout: directive[2]!,\n statementTimeout: directive[3]!,\n statement,\n };\n}\n\nexport async function executeMigrationFile(\n sql: postgres.Sql,\n file: string,\n sqlText: string,\n): Promise<void> {\n if (sqlText.includes(SKILL_METADATA_MIGRATION_MARKER)) {\n if (file !== \"0433_unified_skill_lifecycle.sql\")\n throw new Error(\"Skill metadata stage is restricted to migration 0433\");\n const parts = sqlText.split(SKILL_METADATA_MIGRATION_MARKER);\n if (parts.length !== 2) throw new Error(\"0433 requires exactly one Skill metadata stage\");\n await sql.begin(async (transaction) => {\n await createSkillMetadataMigrationStage(transaction);\n await transaction`SELECT\n pg_catalog.set_config('opengeni.sandbox_recovery_protocol_v2','1',true),\n pg_catalog.set_config('opengeni.session_variable_set_attachments_v1','1',true)`;\n await transaction.unsafe(parts[0]!);\n await stageSkillMetadataMigration(transaction);\n await migrateLegacySkillConfigurations(transaction);\n await transaction.unsafe(parts[1]!);\n // Unlike historical one-query migrations, include this hook's ledger\n // receipt in the same transaction so retry cannot rerun committed DDL.\n await transaction`INSERT INTO schema_migrations(name) VALUES(${file}) ON CONFLICT DO NOTHING`;\n });\n return;\n }\n const batchedBackfill = parseBatchedBackfillMigration(file, sqlText);\n if (batchedBackfill) {\n await sql`select set_config('lock_timeout', ${batchedBackfill.lockTimeout}, false)`;\n await sql`select set_config('statement_timeout', ${batchedBackfill.statementTimeout}, false)`;\n try {\n for (;;) {\n const result = await sql.begin(async (transaction) => {\n const transactionLocalSetting = batchedBackfillTransactionLocalSetting(file);\n await transaction`select\n pg_catalog.set_config('opengeni.sandbox_recovery_protocol_v2', '1', true),\n pg_catalog.set_config(\n 'opengeni.session_variable_set_attachments_v1',\n '1',\n true\n )`;\n if (transactionLocalSetting) {\n await transaction`select pg_catalog.set_config(\n ${transactionLocalSetting.guc},\n ${transactionLocalSetting.value},\n true\n )`;\n }\n return await transaction.unsafe(batchedBackfill.statement);\n });\n if (result.length === 0) break;\n }\n } finally {\n await sql`select set_config('statement_timeout', '0', false)`;\n await sql`select set_config('lock_timeout', '0', false)`;\n }\n return;\n }\n const concurrentIndex = parseConcurrentIndexMigration(file, sqlText);\n if (!concurrentIndex) {\n // Migration SQL is the only writer allowed to cross protocol generations.\n // Keep the authority transaction-local and inside the same PostgreSQL simple\n // query as the migration body: setting it in a prior statement would end\n // that implicit transaction and silently lose the LOCAL value. This also\n // makes a fresh database capable of applying maintenance migration 0138\n // and later migrations capable of crossing the 0352 sessions policy\n // without a process-global PGOPTIONS escape hatch.\n await sql.unsafe(\n `SELECT\n pg_catalog.set_config('opengeni.sandbox_recovery_protocol_v2', '1', true),\n pg_catalog.set_config('opengeni.session_variable_set_attachments_v1', '1', true);\\n${file === \"0434_ordered_model_history.sql\" ? \"SET CONSTRAINTS ALL IMMEDIATE;\\n\" : \"\"}${sqlText}`,\n );\n return;\n }\n\n await sql`select set_config('lock_timeout', ${concurrentIndex.lockTimeout}, false)`;\n try {\n const [existing] = await sql<Array<{ valid: boolean; ready: boolean }>>`\n select i.indisvalid as valid, i.indisready as ready\n from pg_catalog.pg_class c\n join pg_catalog.pg_namespace n on n.oid = c.relnamespace\n join pg_catalog.pg_index i on i.indexrelid = c.oid\n where n.nspname = current_schema() and c.relname = ${concurrentIndex.indexName}\n `;\n if (existing && (!existing.valid || !existing.ready)) {\n const quotedIndexName = `\"${concurrentIndex.indexName.replaceAll('\"', '\"\"')}\"`;\n await sql.unsafe(`DROP INDEX CONCURRENTLY ${quotedIndexName}`);\n } else if (existing && concurrentIndex.skipWhenValid) {\n return;\n }\n await sql.unsafe(concurrentIndex.statement);\n } finally {\n await sql`select set_config('lock_timeout', '0', false)`;\n }\n}\n\nfunction deploymentDepthPolicy(\n options: MigrationRuntimeOptions | undefined,\n): DeploymentDepthPolicy {\n const raw =\n options === undefined\n ? process.env.OPENGENI_MAX_NESTED_AGENT_DEPTH?.trim() || undefined\n : options.maxNestedAgentDepth;\n if (raw === undefined) {\n return { maxNestedAgentDepth: DEFAULT_MAX_NESTED_AGENT_DEPTH, source: \"default\" };\n }\n const value = typeof raw === \"number\" ? raw : Number(raw);\n if (\n !Number.isSafeInteger(value) ||\n value < 0 ||\n value > MAX_NESTED_AGENT_DEPTH ||\n (typeof raw === \"string\" && !/^(0|[1-9][0-9]*)$/.test(raw))\n ) {\n throw new Error(\n `OPENGENI_MAX_NESTED_AGENT_DEPTH must be a non-negative 32-bit integer: ${raw}`,\n );\n }\n return { maxNestedAgentDepth: value, source: \"deployment\" };\n}\n\nexport function migrationApplicationRoles(\n schema: string | undefined,\n options: MigrationRuntimeOptions | undefined,\n): string[] {\n const configured = options?.applicationDatabaseRoles;\n const environment = process.env.OPENGENI_MIGRATION_APPLICATION_DATABASE_ROLES?.trim();\n const explicit =\n configured !== undefined\n ? configured\n : environment\n ? environment.split(\",\").map((role) => role.trim())\n : undefined;\n\n if (!explicit) {\n const configuredRuntimeRoles = [\n process.env.OPENGENI_APP_DATABASE_USER?.trim(),\n process.env.OPENGENI_RUNTIME_DATABASE_ROLE?.trim(),\n ].filter((role): role is string => Boolean(role) && role !== DEFAULT_APPLICATION_DATABASE_ROLE);\n if (schema || configuredRuntimeRoles.length > 0) {\n throw new Error(\n \"Pending migrations require the exact application database roles via \" +\n \"MigrationRuntimeOptions.applicationDatabaseRoles or \" +\n \"OPENGENI_MIGRATION_APPLICATION_DATABASE_ROLES for dedicated-schema or custom-role deployments\",\n );\n }\n return [DEFAULT_APPLICATION_DATABASE_ROLE];\n }\n\n if (\n configured !== undefined &&\n configured.some((role) => typeof role !== \"string\" || role !== role.trim())\n ) {\n throw new Error(\n \"MigrationRuntimeOptions.applicationDatabaseRoles must contain canonical Postgres role names without surrounding whitespace\",\n );\n }\n if (explicit.length < 1 || explicit.length > MAX_MIGRATION_APPLICATION_ROLES) {\n throw new Error(\n `Migration application database roles must contain 1-${MAX_MIGRATION_APPLICATION_ROLES} entries`,\n );\n }\n const normalized = [...new Set(explicit)].sort((left, right) =>\n Buffer.compare(Buffer.from(left, \"utf8\"), Buffer.from(right, \"utf8\")),\n );\n if (\n normalized.length !== explicit.length ||\n normalized.some((role) => role.length === 0 || Buffer.byteLength(role, \"utf8\") > 63)\n ) {\n throw new Error(\n \"Migration application database roles must be unique, non-empty Postgres role names of at most 63 UTF-8 bytes\",\n );\n }\n return normalized;\n}\n\nasync function persistDeploymentDepthPolicy(\n sql: postgres.Sql,\n policy: DeploymentDepthPolicy,\n): Promise<void> {\n const [relation] = await sql<{ exists: boolean }[]>`\n select to_regclass('nested_agent_depth_configuration') is not null as exists\n `;\n if (!relation?.exists) return;\n await sql`\n insert into \"nested_agent_depth_configuration\" (\n \"singleton\", \"max_nested_agent_depth\", \"policy_source\", \"updated_at\"\n ) values (true, ${policy.maxNestedAgentDepth}, ${policy.source}, now())\n on conflict (\"singleton\") do update\n set \"max_nested_agent_depth\" = excluded.\"max_nested_agent_depth\",\n \"policy_source\" = excluded.\"policy_source\",\n \"updated_at\" = now()\n where \"nested_agent_depth_configuration\".\"max_nested_agent_depth\"\n is distinct from excluded.\"max_nested_agent_depth\"\n or \"nested_agent_depth_configuration\".\"policy_source\"\n is distinct from excluded.\"policy_source\"\n `;\n}\n\n/**\n * Apply the OpenGeni SQL migration chain.\n *\n * STANDALONE (default, unchanged): `migrate()` / `migrate(databaseUrl)` runs the\n * whole chain with NO search_path manipulation, so every unqualified\n * table/index/policy lands in the server default schema (`public`). This is the\n * byte-for-byte historical behavior — the migration test suite calls\n * `migrate(DB_URL)` and is unaffected.\n *\n * EMBEDDED SCHEMA MODE: pass a `schema` (or set\n * `OPENGENI_DB_SCHEMA`). The migrate session then `CREATE SCHEMA IF NOT EXISTS`\n * for both `<schema>` and `opengeni_private`, and sets\n * `search_path = \"<schema>\", \"opengeni_private\", \"public\"`, so EVERY unqualified\n * DDL statement lands in the dedicated schema with NO per-statement SQL rewrite\n * (the schema-isolation contract). Two things make this work and stay idempotent:\n * 1. The policy-existence guards in the migration SQL use `current_schema()`\n * (not a hardcoded `'public'`) — so a re-run finds the policy it already\n * created in `<schema>` and DROP/CREATEs idempotently instead of failing\n * with \"policy already exists\". (This guard substitution is the migrate-\n * time enabler for the runtime search_path approach; without it the SDK\n * entry point silently fails on re-run — the migration replay hazard.)\n * 2. `public` stays LAST on the path so `gen_random_uuid()` (pgcrypto) and the\n * `vector` type — both installed into `public` by 0000 — still resolve. The\n * `opengeni_private.*` helpers are always called with an absolute prefix.\n * Dedicated-schema callers must also pass the exact API/worker database login\n * identities in `applicationDatabaseRoles`; maintenance cutovers cannot infer\n * host-managed or scoped runtime roles from the admin connection.\n *\n * `OPENGENI_DB_SCHEMA` defaults UNSET → `public` → standalone, so the default\n * binding never regresses.\n */\nexport async function migrate(\n databaseUrl = process.env.OPENGENI_MIGRATIONS_DATABASE_URL ??\n process.env.OPENGENI_DATABASE_URL ??\n DEFAULT_DATABASE_URL,\n schema: string | undefined = process.env.OPENGENI_DB_SCHEMA?.trim() || undefined,\n runtimeOptions?: MigrationRuntimeOptions,\n): Promise<void> {\n const migrationsDir = join(dirname(fileURLToPath(import.meta.url)), \"../drizzle\");\n const files = (await readdir(migrationsDir)).filter((file) => file.endsWith(\".sql\")).sort();\n const depthPolicy = deploymentDepthPolicy(runtimeOptions);\n const sql = postgres(databaseUrl, { max: 1 });\n try {\n // Serialize concurrent migrate() runs; the session-level lock is released\n // when the connection closes.\n await sql`SELECT pg_advisory_lock(727458)`;\n if (schema) {\n assertIdentifier(\"OPENGENI_DB_SCHEMA\", schema);\n await sql.unsafe(`CREATE SCHEMA IF NOT EXISTS \"${schema}\"`);\n // opengeni_private is also created by 0001 with an absolute prefix, but the\n // session search_path must already resolve it for the policy predicates\n // and the SECURITY DEFINER functions that inherit the caller's path.\n await sql.unsafe(`CREATE SCHEMA IF NOT EXISTS \"opengeni_private\"`);\n await sql.unsafe(`SET search_path = \"${schema}\", \"opengeni_private\", \"public\"`);\n }\n await sql`select set_config('opengeni.max_nested_agent_depth', ${String(depthPolicy.maxNestedAgentDepth)}, false)`;\n await sql`select set_config('opengeni.nested_agent_depth_policy_source', ${depthPolicy.source}, false)`;\n await sql.unsafe(\n `CREATE TABLE IF NOT EXISTS \"schema_migrations\" (\"name\" text PRIMARY KEY, \"applied_at\" timestamptz NOT NULL DEFAULT now())`,\n );\n const appliedRows = await sql`SELECT \"name\" FROM \"schema_migrations\"`;\n const applied = new Set(appliedRows.map((row) => row.name as string));\n const pendingMigrationSources = new Map<string, string>();\n for (const file of files) {\n if (!applied.has(file)) {\n pendingMigrationSources.set(file, await readFile(join(migrationsDir, file), \"utf8\"));\n }\n }\n // Initialize this session GUC for every pending migration that consumes it,\n // instead of maintaining a second filename list that can silently lag the\n // shipped migration chain. The conservative source marker is intentional:\n // setting the bounded role list for a migration that only mentions the GUC\n // is harmless, while omitting it makes an otherwise valid upgrade fail.\n if (\n Array.from(pendingMigrationSources.values()).some((source) =>\n source.includes(MIGRATION_APPLICATION_ROLES_SETTING),\n )\n ) {\n const applicationRoles = migrationApplicationRoles(schema, runtimeOptions);\n await sql`select set_config(\n ${MIGRATION_APPLICATION_ROLES_SETTING},\n ${JSON.stringify(applicationRoles)},\n false\n )`;\n }\n for (const file of files) {\n if (applied.has(file)) {\n continue;\n }\n const sqlText = pendingMigrationSources.get(file);\n if (sqlText === undefined) {\n throw new Error(`Pending migration source was not loaded: ${file}`);\n }\n await executeMigrationFile(sql, file, sqlText);\n await sql`INSERT INTO \"schema_migrations\" (\"name\") VALUES (${file}) ON CONFLICT DO NOTHING`;\n }\n // Reconcile even when all migration names were already recorded. This is\n // the only supported way to change deployment policy in a live database.\n await persistDeploymentDepthPolicy(sql, depthPolicy);\n } finally {\n await sql.end();\n }\n}\n\n/**\n * SDK entry point (Step I): run the migration chain over a host-supplied admin\n * connection string against an explicit target schema. This is the embedded\n * topology's named entry — a host calls `runMigrations(adminConnection,\n * targetSchema, { applicationDatabaseRoles })` from its own provisioning code\n * instead of relying on env vars.\n * `targetSchema` undefined → `public` → standalone behavior. Thin wrapper over\n * `migrate` so there is one migration engine.\n */\nexport async function runMigrations(\n adminConnection: string,\n targetSchema?: string,\n runtimeOptions?: MigrationRuntimeOptions,\n): Promise<void> {\n await migrate(adminConnection, targetSchema, runtimeOptions);\n}\n\nif (import.meta.main) {\n await migrate();\n console.log(\"Applied Drizzle SQL migrations.\");\n}\n","import { createHash } from \"node:crypto\";\nimport {\n StoredCapabilityPack,\n StoredSessionSkills,\n validateSkillTextFiles,\n type SkillFile,\n} from \"@opengeni/contracts\";\nimport type postgres from \"postgres\";\nimport { prepareLegacySkillFolder } from \"./skill-metadata-migration\";\n\ntype ObjectValue = Record<string, unknown>;\nfunction object(value: unknown): ObjectValue {\n if (!value || typeof value !== \"object\" || Array.isArray(value))\n throw new Error(\"Expected stored configuration object\");\n return value as ObjectValue;\n}\n\n/** Only known execution fields, never arbitrary metadata or archived payloads. */\nexport function convertLegacyConfigSkills(value: unknown, identity: string): unknown[] {\n if (!Array.isArray(value)) throw new Error(\"Expected stored Skill array\");\n const names = new Set<string>();\n const converted = value.map((entry, index) => {\n const skill = object(entry);\n if (!Array.isArray(skill.files)) throw new Error(\"Expected stored Skill folder\");\n const files = skill.files.map((fileEntry) => {\n const file = object(fileEntry);\n if (typeof file.path !== \"string\" || typeof file.content !== \"string\")\n throw new Error(\"Invalid stored Skill text file\");\n if (Object.keys(file).some((key) => key !== \"path\" && key !== \"content\"))\n throw new Error(\"Unexpected stored Skill file fields\");\n return { path: file.path, content: file.content };\n });\n const main = files.find((file) => file.path === \"SKILL.md\");\n const plain = main && !/^\\s*---(?:\\r?\\n|$)/u.test(main.content);\n if (plain && (typeof skill.name !== \"string\" || typeof skill.description !== \"string\"))\n throw new Error(\"Plain Skill requires historical name and description\");\n const folder = prepareLegacySkillFolder(files as SkillFile[], {\n id: createHash(\"sha256\").update(`${identity}:${index}`).digest(\"hex\").slice(0, 32),\n title: typeof skill.name === \"string\" ? skill.name : \"\",\n description: typeof skill.description === \"string\" ? skill.description : \"\",\n });\n validateSkillTextFiles(folder.files);\n if (names.has(folder.name)) throw new Error(`Canonical Skill name collision: ${folder.name}`);\n names.add(folder.name);\n // Valid YAML requires no persistence change: cached descriptors are handled\n // by the stored read projection. Preserve unknown fields and exact JSON.\n return plain ? { ...skill, ...folder } : entry;\n });\n StoredSessionSkills.parse(converted);\n return converted;\n}\n\nexport function convertLegacyPackConfig(value: unknown, identity: string): ObjectValue {\n const pack = object(value);\n const converted = { ...pack };\n if (pack.skills !== undefined)\n converted.skills = convertLegacyConfigSkills(pack.skills, identity);\n if (Array.isArray(pack.automationTemplates))\n converted.automationTemplates = pack.automationTemplates.map((entry, index) => {\n const template = object(entry);\n const sessionTemplate = object(template.sessionTemplate);\n return {\n ...template,\n sessionTemplate: {\n ...sessionTemplate,\n ...(sessionTemplate.skills !== undefined\n ? {\n skills: convertLegacyConfigSkills(\n sessionTemplate.skills,\n `${identity}:template:${index}`,\n ),\n }\n : {}),\n },\n };\n });\n StoredCapabilityPack.parse(converted);\n return converted;\n}\n\nasync function assertSkillConfigurationMaintenanceWindow(\n tx: postgres.TransactionSql,\n): Promise<void> {\n const rows = await tx`SELECT c.oid FROM pg_class c\n WHERE c.oid='sessions'::regclass AND pg_get_userbyid(c.relowner)=current_user\n AND c.relrowsecurity AND NOT c.relforcerowsecurity\n AND to_regclass('pg_temp.skill_metadata_0426') IS NOT NULL`;\n if (rows.length !== 1)\n throw new Error(\n \"Skill configuration conversion requires the parser-backed maintenance owner window\",\n );\n}\n\n/** Maintenance-only: caller holds the 0433 owner window and drained runtime fence. */\nexport async function migrateLegacySkillConfigurations(tx: postgres.TransactionSql): Promise<void> {\n await assertSkillConfigurationMaintenanceWindow(tx);\n await tx`SELECT pg_advisory_xact_lock(hashtextextended('session-tenancy:'||workspace_id::text,0))\n FROM (SELECT DISTINCT workspace_id FROM sessions ORDER BY workspace_id) workspaces`;\n // All candidates are read under table locks, preventing changes between\n // inventory, archival, and replacement, including owner-side maintenance.\n await tx`LOCK TABLE sessions, workspace_packs, session_turns, automation_triggers,\n automation_trigger_revisions, automation_runs, automation_trigger_events, automation_run_event_links, pack_installations IN SHARE ROW EXCLUSIVE MODE`;\n const pinned = await tx<Array<{ kind: string; id: string; value: unknown }>>`\n SELECT 'pack-installation' AS kind,id::text,manifest_snapshot AS value FROM pack_installations\n WHERE status <> 'disabled' AND manifest_snapshot IS NOT NULL\n UNION ALL SELECT 'automation-current',t.id::text,jsonb_build_object('skills',r.session_template->'skills')\n FROM automation_triggers t JOIN automation_trigger_revisions r ON r.trigger_id=t.id AND r.revision=t.current_revision\n WHERE t.status IN ('active','paused') AND r.session_template ? 'skills'\n UNION ALL SELECT 'automation-run',id::text,jsonb_build_object('skills',accepted_execution->'sessionTemplate'->'skills')\n FROM automation_runs WHERE status IN ('queued','dispatching') AND accepted_execution->'sessionTemplate' ? 'skills'\n UNION ALL SELECT 'automation-event',e.id::text,jsonb_build_object('skills',r.session_template->'skills')\n FROM automation_trigger_events e CROSS JOIN LATERAL jsonb_array_elements(e.matched_trigger_revisions) matched\n JOIN automation_trigger_revisions r ON r.trigger_id=(matched->>'triggerId')::uuid AND r.revision=(matched->>'revision')::integer\n WHERE e.status='accepted' AND r.session_template ? 'skills'\n AND NOT EXISTS (SELECT 1 FROM automation_runs run WHERE run.event_id=e.id AND run.trigger_id=r.trigger_id AND run.trigger_revision=r.revision)\n AND NOT EXISTS (SELECT 1 FROM automation_run_event_links link WHERE link.event_id=e.id AND link.trigger_id=r.trigger_id)\n `;\n const blockers: string[] = [];\n for (const source of pinned) {\n try {\n const original = object(source.value);\n const converted =\n source.kind === \"pack-installation\"\n ? convertLegacyPackConfig(original, source.id)\n : { ...original, skills: convertLegacyConfigSkills(original.skills, source.id) };\n if (JSON.stringify(converted) !== JSON.stringify(original))\n blockers.push(`${source.kind}:${source.id} (plain content)`);\n } catch {\n blockers.push(`${source.kind}:${source.id} (invalid content)`);\n }\n }\n const candidates = await tx<\n Array<{\n kind: string;\n id: string;\n account_id: string;\n workspace_id: string;\n original: unknown;\n pinned: boolean;\n }>\n >`\n SELECT 'session' AS kind,s.id::text,s.account_id,s.workspace_id,s.skills AS original,\n (s.active_turn_id IS NOT NULL OR EXISTS(SELECT 1 FROM session_turns t WHERE t.session_id=s.id AND t.status NOT IN ('completed','failed','cancelled'))) AS pinned\n FROM sessions s WHERE s.skills <> '[]'::jsonb\n UNION ALL SELECT 'workspace-pack',id::text,account_id,workspace_id,manifest,false FROM workspace_packs\n `;\n const changes: Array<{ source: (typeof candidates)[number]; converted: unknown }> = [];\n for (const source of candidates) {\n try {\n const converted =\n source.kind === \"session\"\n ? convertLegacyConfigSkills(source.original, source.id)\n : convertLegacyPackConfig(source.original, source.id);\n if (source.kind === \"session\") StoredSessionSkills.parse(converted);\n if (JSON.stringify(source.original) !== JSON.stringify(converted)) {\n if (source.pinned) blockers.push(`${source.kind}:${source.id} (runnable accepted turn)`);\n else changes.push({ source, converted });\n }\n } catch {\n blockers.push(`${source.kind}:${source.id} (invalid content or canonical collision)`);\n }\n }\n if (blockers.length)\n throw new Error(\n `0433 Skill configuration preflight: ${blockers.length} repair-required sources; drain or explicitly replace pinned sources before retry: ${blockers.slice(0, 30).join(\", \")}`,\n );\n for (const { source, converted } of changes) {\n const original = tx.json(source.original as never);\n const replacement = tx.json(converted as never);\n await tx`INSERT INTO skill_config_conversion_receipts(account_id,workspace_id,source_kind,source_id,original_configuration,original_hash,replacement_hash)\n VALUES(${source.account_id},${source.workspace_id},${source.kind},${source.id},${original},\n encode(sha256(convert_to(${original}::jsonb::text,'UTF8')),'hex'),encode(sha256(convert_to(${replacement}::jsonb::text,'UTF8')),'hex'))`;\n const updated =\n source.kind === \"session\"\n ? await tx`UPDATE sessions SET skills=${replacement} WHERE id=${source.id} AND account_id=${source.account_id} AND workspace_id=${source.workspace_id} AND skills=${original} RETURNING id`\n : await tx`UPDATE workspace_packs SET manifest=${replacement} WHERE id=${source.id} AND account_id=${source.account_id} AND workspace_id=${source.workspace_id} AND manifest=${original} RETURNING id`;\n if (updated.length !== 1)\n throw new Error(`0433 Skill configuration CAS conflict: ${source.kind}:${source.id}`);\n }\n}\n","import { readSkillMetadata, type SkillFile } from \"@opengeni/contracts\";\nimport type postgres from \"postgres\";\n\n/** Exact runner seam for 0433, not a general callback or runtime capability. */\nexport const SKILL_METADATA_MIGRATION_MARKER = \"-- opengeni:skill-metadata-stage-v1\";\n\nexport function prepareLegacySkillFolder(\n files: SkillFile[],\n legacy: { id: string; title: string; description: string },\n): { files: SkillFile[]; name: string; description: string } {\n const main = files.find((file) => file.path === \"SKILL.md\");\n if (!main) throw new Error(`Skill ${legacy.id} requires SKILL.md before migration`);\n let content = main.content;\n // A header-looking document is never silently wrapped/repaired: missing end\n // markers, invalid YAML, invalid metadata and duplicate keys must fail closed.\n if (!/^\\s*---(?:\\r?\\n|$)/u.test(content)) {\n const slug = legacy.title\n .normalize(\"NFKD\")\n .toLowerCase()\n .replace(/[^a-z0-9]+/gu, \"-\")\n .replace(/^-|-$/gu, \"\");\n const name = slug && slug.length <= 64 ? slug : `legacy-${legacy.id.replaceAll(\"-\", \"\")}`;\n content = `---\\nname: ${JSON.stringify(name)}\\ndescription: ${JSON.stringify(legacy.description)}\\n---\\n${content}`;\n }\n const metadata = readSkillMetadata(content);\n return {\n files: files.map((file) => (file.path === \"SKILL.md\" ? { ...file, content } : file)),\n ...metadata,\n };\n}\n\nexport async function createSkillMetadataMigrationStage(\n tx: postgres.TransactionSql,\n): Promise<void> {\n await tx`CREATE TEMP TABLE skill_metadata_0426 (\n source_kind text NOT NULL, source_id uuid NOT NULL, account_id uuid NOT NULL,\n workspace_id uuid, files jsonb NOT NULL, name text NOT NULL, description text NOT NULL\n ) ON COMMIT DROP`;\n}\n\nexport async function stageSkillMetadataMigration(tx: postgres.TransactionSql): Promise<void> {\n const sources = await tx<\n Array<{\n source_kind: string;\n source_id: string;\n account_id: string;\n workspace_id: string | null;\n title: string;\n description: string;\n files: SkillFile[];\n }>\n >`\n SELECT 'installed' AS source_kind,sf.facet_id AS source_id,i.account_id,i.workspace_id,\n sf.name AS title,sf.description,\n coalesce(jsonb_agg(jsonb_build_object('path',ff.path,'content',ff.content) ORDER BY ff.path COLLATE \"C\")\n FILTER (WHERE ff.id IS NOT NULL),'[]'::jsonb) AS files\n FROM capability_plugin_installations i JOIN capability_facets f ON f.plugin_version_id=i.plugin_version_id\n JOIN capability_skill_facets sf ON sf.facet_id=f.id LEFT JOIN capability_skill_files ff ON ff.skill_facet_id=sf.facet_id\n WHERE i.status='active'\n GROUP BY i.account_id,i.workspace_id,sf.facet_id\n UNION ALL\n SELECT 'authored',h.id,h.account_id,h.scope_workspace_id,r.title,r.description,\n coalesce(r.skill_files,jsonb_build_array(jsonb_build_object('path','SKILL.md','content',r.content)))\n FROM preference_registry_preferences h JOIN preference_registry_revisions r\n ON r.id=h.active_revision_id AND r.preference_id=h.id AND r.account_id=h.account_id\n WHERE h.status='active'\n `;\n for (const source of sources) {\n let folder: ReturnType<typeof prepareLegacySkillFolder>;\n try {\n folder = prepareLegacySkillFolder(source.files, {\n id: source.source_id,\n title: source.title,\n description: source.description,\n });\n } catch (cause) {\n throw new Error(\n `Skill ${source.source_kind}:${source.source_id} needs explicit frontmatter repair before 0433`,\n { cause },\n );\n }\n const [valid] = await tx`SELECT skill_files_valid(${tx.json(folder.files)}) AS valid`;\n if (!valid?.valid)\n throw new Error(\n `Skill ${source.source_id} exceeds the valid folder limits after metadata migration`,\n );\n await tx`INSERT INTO pg_temp.skill_metadata_0426(source_kind,source_id,account_id,workspace_id,files,name,description)\n VALUES(${source.source_kind},${source.source_id},${source.account_id},${source.workspace_id},${tx.json(folder.files)},${folder.name},${folder.description})`;\n }\n}\n","export type BatchedBackfillTransactionLocalSetting = {\n guc: `opengeni.${string}`;\n value: string;\n};\n\n/**\n * Exact owner-capability settings established before one governed batched\n * backfill statement. Keep this closed by migration filename: these GUCs may\n * open a FORCE-RLS policy arm and must never become ambient migration state.\n */\nexport function batchedBackfillTransactionLocalSetting(\n file: string,\n): BatchedBackfillTransactionLocalSetting | null {\n if (file === \"0411_new_session_draft_project_provenance_backfill.sql\") {\n return {\n guc: \"opengeni.new_session_draft_project_provenance_backfill_v1\",\n value: \"1\",\n };\n }\n return null;\n}\n"],"mappings":"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","names":[]}