@agentic-kit/db-tools 0.2.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 (131) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +138 -0
  3. package/app-workspace.d.ts +16 -0
  4. package/app-workspace.js +145 -0
  5. package/context.d.ts +62 -0
  6. package/context.js +282 -0
  7. package/db-probe.d.ts +30 -0
  8. package/db-probe.js +50 -0
  9. package/esm/app-workspace.d.ts +16 -0
  10. package/esm/app-workspace.js +134 -0
  11. package/esm/context.d.ts +62 -0
  12. package/esm/context.js +270 -0
  13. package/esm/db-probe.d.ts +30 -0
  14. package/esm/db-probe.js +47 -0
  15. package/esm/host.d.ts +115 -0
  16. package/esm/host.js +23 -0
  17. package/esm/index.d.ts +20 -0
  18. package/esm/index.js +52 -0
  19. package/esm/policy/add-policies-to-table.d.ts +26 -0
  20. package/esm/policy/add-policies-to-table.js +66 -0
  21. package/esm/policy/provision-helpers.d.ts +38 -0
  22. package/esm/policy/provision-helpers.js +50 -0
  23. package/esm/provision-database/credential.d.ts +14 -0
  24. package/esm/provision-database/credential.js +19 -0
  25. package/esm/provision-database/env-file.d.ts +37 -0
  26. package/esm/provision-database/env-file.js +85 -0
  27. package/esm/provision-database/manifest.d.ts +10 -0
  28. package/esm/provision-database/manifest.js +48 -0
  29. package/esm/provision-database/pg-fixups.d.ts +16 -0
  30. package/esm/provision-database/pg-fixups.js +132 -0
  31. package/esm/provision-database/preset-match.d.ts +13 -0
  32. package/esm/provision-database/preset-match.js +66 -0
  33. package/esm/provision-database/presets.d.ts +4 -0
  34. package/esm/provision-database/presets.js +13 -0
  35. package/esm/provision-database/request-database.d.ts +61 -0
  36. package/esm/provision-database/request-database.js +130 -0
  37. package/esm/provision-database/resolve.d.ts +27 -0
  38. package/esm/provision-database/resolve.js +49 -0
  39. package/esm/records/meta.d.ts +41 -0
  40. package/esm/records/meta.js +167 -0
  41. package/esm/run-codegen/barrels.d.ts +3 -0
  42. package/esm/run-codegen/barrels.js +48 -0
  43. package/esm/run-codegen/endpoints.d.ts +8 -0
  44. package/esm/run-codegen/endpoints.js +46 -0
  45. package/esm/schema-resolve.d.ts +23 -0
  46. package/esm/schema-resolve.js +69 -0
  47. package/esm/tool-schema.d.ts +3 -0
  48. package/esm/tool-schema.js +10 -0
  49. package/esm/tools/add-policies.d.ts +24 -0
  50. package/esm/tools/add-policies.js +94 -0
  51. package/esm/tools/add-records.d.ts +18 -0
  52. package/esm/tools/add-records.js +122 -0
  53. package/esm/tools/add-relation-schema.d.ts +29 -0
  54. package/esm/tools/add-relation-schema.js +56 -0
  55. package/esm/tools/add-relation.d.ts +10 -0
  56. package/esm/tools/add-relation.js +91 -0
  57. package/esm/tools/create-api-key.d.ts +25 -0
  58. package/esm/tools/create-api-key.js +214 -0
  59. package/esm/tools/describe-schema.d.ts +19 -0
  60. package/esm/tools/describe-schema.js +130 -0
  61. package/esm/tools/manage-entity-types.d.ts +40 -0
  62. package/esm/tools/manage-entity-types.js +201 -0
  63. package/esm/tools/mutations.d.ts +35 -0
  64. package/esm/tools/mutations.js +230 -0
  65. package/esm/tools/provision-blueprint.d.ts +21 -0
  66. package/esm/tools/provision-blueprint.js +109 -0
  67. package/esm/tools/provision-database.d.ts +18 -0
  68. package/esm/tools/provision-database.js +260 -0
  69. package/esm/tools/run-codegen.d.ts +12 -0
  70. package/esm/tools/run-codegen.js +137 -0
  71. package/esm/tools/templates.d.ts +71 -0
  72. package/esm/tools/templates.js +331 -0
  73. package/host.d.ts +115 -0
  74. package/host.js +28 -0
  75. package/index.d.ts +20 -0
  76. package/index.js +76 -0
  77. package/package.json +49 -0
  78. package/policy/add-policies-to-table.d.ts +26 -0
  79. package/policy/add-policies-to-table.js +71 -0
  80. package/policy/provision-helpers.d.ts +38 -0
  81. package/policy/provision-helpers.js +58 -0
  82. package/provision-database/credential.d.ts +14 -0
  83. package/provision-database/credential.js +22 -0
  84. package/provision-database/env-file.d.ts +37 -0
  85. package/provision-database/env-file.js +91 -0
  86. package/provision-database/manifest.d.ts +10 -0
  87. package/provision-database/manifest.js +56 -0
  88. package/provision-database/pg-fixups.d.ts +16 -0
  89. package/provision-database/pg-fixups.js +170 -0
  90. package/provision-database/preset-match.d.ts +13 -0
  91. package/provision-database/preset-match.js +70 -0
  92. package/provision-database/presets.d.ts +4 -0
  93. package/provision-database/presets.js +17 -0
  94. package/provision-database/request-database.d.ts +61 -0
  95. package/provision-database/request-database.js +134 -0
  96. package/provision-database/resolve.d.ts +27 -0
  97. package/provision-database/resolve.js +53 -0
  98. package/records/meta.d.ts +41 -0
  99. package/records/meta.js +172 -0
  100. package/run-codegen/barrels.d.ts +3 -0
  101. package/run-codegen/barrels.js +54 -0
  102. package/run-codegen/endpoints.d.ts +8 -0
  103. package/run-codegen/endpoints.js +51 -0
  104. package/schema-resolve.d.ts +23 -0
  105. package/schema-resolve.js +75 -0
  106. package/tool-schema.d.ts +3 -0
  107. package/tool-schema.js +13 -0
  108. package/tools/add-policies.d.ts +24 -0
  109. package/tools/add-policies.js +97 -0
  110. package/tools/add-records.d.ts +18 -0
  111. package/tools/add-records.js +125 -0
  112. package/tools/add-relation-schema.d.ts +29 -0
  113. package/tools/add-relation-schema.js +60 -0
  114. package/tools/add-relation.d.ts +10 -0
  115. package/tools/add-relation.js +94 -0
  116. package/tools/create-api-key.d.ts +25 -0
  117. package/tools/create-api-key.js +220 -0
  118. package/tools/describe-schema.d.ts +19 -0
  119. package/tools/describe-schema.js +133 -0
  120. package/tools/manage-entity-types.d.ts +40 -0
  121. package/tools/manage-entity-types.js +206 -0
  122. package/tools/mutations.d.ts +35 -0
  123. package/tools/mutations.js +233 -0
  124. package/tools/provision-blueprint.d.ts +21 -0
  125. package/tools/provision-blueprint.js +112 -0
  126. package/tools/provision-database.d.ts +18 -0
  127. package/tools/provision-database.js +266 -0
  128. package/tools/run-codegen.d.ts +12 -0
  129. package/tools/run-codegen.js +141 -0
  130. package/tools/templates.d.ts +71 -0
  131. package/tools/templates.js +335 -0
@@ -0,0 +1,331 @@
1
+ import { filterInternalPolicies } from '@agentic-kit/harness';
2
+ import { z } from 'zod';
3
+ import { resolveProjectContext } from '../context';
4
+ // A stored blueprint field's `type` is an expanded object (`{ name: 'text' }`),
5
+ // not the bare string the agent passes to provision_blueprint. Flatten it to the
6
+ // type name so the renderer gets a string, never an object (which React can't
7
+ // render as a child).
8
+ function fieldTypeName(raw) {
9
+ if (typeof raw === 'string')
10
+ return raw;
11
+ if (raw && typeof raw === 'object' && typeof raw.name === 'string') {
12
+ return raw.name;
13
+ }
14
+ return '';
15
+ }
16
+ // A template's definition is a stored blueprint (see BlueprintDefinitionSchema):
17
+ // { tables: [{ table_name, fields, policies }], relations: [{ source_table, … }] }.
18
+ // Parse it into the same table shape provision_blueprint surfaces so the renderer
19
+ // can reuse TableCard. Defensive throughout — it's untyped JSON from the catalog.
20
+ function parseTemplateTables(definition) {
21
+ if (!definition || typeof definition !== 'object')
22
+ return [];
23
+ const def = definition;
24
+ const tables = Array.isArray(def.tables) ? def.tables : [];
25
+ const relations = Array.isArray(def.relations) ? def.relations : [];
26
+ return tables.map((raw) => {
27
+ const table = raw;
28
+ const fields = Array.isArray(table.fields) ? table.fields : [];
29
+ const policies = Array.isArray(table.policies) ? table.policies : [];
30
+ return {
31
+ name: table.table_name ?? '',
32
+ fields: fields.map((rawField) => {
33
+ const field = rawField;
34
+ return {
35
+ name: field.name ?? '',
36
+ type: fieldTypeName(field.type),
37
+ isRequired: field.is_required ?? false,
38
+ defaultValue: typeof field.default === 'string' ? field.default : null,
39
+ };
40
+ }),
41
+ policies: filterInternalPolicies(policies.map((policy) => policy.$type ?? '').filter(Boolean)),
42
+ relationCount: relations.filter((relation) => relation.source_table === table.table_name).length,
43
+ };
44
+ });
45
+ }
46
+ function formatTemplatesText(templates) {
47
+ if (templates.length === 0)
48
+ return 'No blueprint templates available.';
49
+ const lines = [`Available blueprint templates (${templates.length}):`];
50
+ for (const template of templates) {
51
+ const cats = template.categories.length ? ` [${template.categories.join(', ')}]` : '';
52
+ lines.push(` ${template.displayName} — ${template.tables.length} tables${cats}`);
53
+ for (const table of template.tables) {
54
+ lines.push(` - ${table.name} (${table.fields.length} field${table.fields.length === 1 ? '' : 's'})`);
55
+ }
56
+ }
57
+ return lines.join('\n');
58
+ }
59
+ // The latest project blueprint (or a named one) — the definition source for
60
+ // create_template, and for the confirm preview of the tables it will template.
61
+ // A blueprintName is a best-effort hint: if it matches nothing (the agent often
62
+ // guesses casing/wording), fall back to the most recent blueprint so the confirm
63
+ // still previews real tables and execute templates the same one it previewed.
64
+ async function fetchLatestBlueprint(context, blueprintName) {
65
+ const found = await context.modules.blueprint
66
+ .findMany({
67
+ select: { displayName: true, definition: true },
68
+ where: {
69
+ databaseId: { equalTo: context.databaseId },
70
+ ...(blueprintName ? { displayName: { equalTo: blueprintName } } : {}),
71
+ },
72
+ orderBy: ['CREATED_AT_DESC'],
73
+ first: 1,
74
+ })
75
+ .unwrap();
76
+ return found.blueprints?.nodes?.[0];
77
+ }
78
+ async function findProjectBlueprint(context, blueprintName) {
79
+ let node = await fetchLatestBlueprint(context, blueprintName);
80
+ if (!node && blueprintName)
81
+ node = await fetchLatestBlueprint(context, undefined);
82
+ return node?.definition ? { displayName: node.displayName ?? '', definition: node.definition } : null;
83
+ }
84
+ // The create_template confirm preview — the source blueprint's name and its
85
+ // tables, parsed into the shape the renderer's TableCard reuses. Best-effort: any
86
+ // failure yields no tables rather than blocking the confirm.
87
+ export async function createTemplatePreviewTables(context, blueprintName) {
88
+ try {
89
+ const blueprint = await findProjectBlueprint(context, blueprintName);
90
+ if (!blueprint)
91
+ return { blueprintName: '', tables: [] };
92
+ return {
93
+ blueprintName: blueprint.displayName,
94
+ tables: parseTemplateTables(blueprint.definition),
95
+ };
96
+ }
97
+ catch (err) {
98
+ console.warn('[db-tools] create_template preview lookup failed:', err);
99
+ return { blueprintName: '', tables: [] };
100
+ }
101
+ }
102
+ async function resolveTemplateId(client, displayName) {
103
+ const result = await client.blueprintTemplate
104
+ .findMany({
105
+ select: { id: true, displayName: true },
106
+ where: { displayName: { equalTo: displayName } },
107
+ first: 1,
108
+ })
109
+ .unwrap();
110
+ const template = result.blueprintTemplates?.nodes?.[0];
111
+ if (!template?.id)
112
+ throw new Error(`Template "${displayName}" not found`);
113
+ return template.id;
114
+ }
115
+ function done(success, message) {
116
+ return { content: [{ type: 'text', text: message }], details: { success, message } };
117
+ }
118
+ // ── list_templates ────────────────────────────────────────────────────────
119
+ const ListTemplatesZod = z.object({});
120
+ export const listTemplatesTool = {
121
+ name: 'list_templates',
122
+ label: 'List templates',
123
+ description: 'List the blueprint templates available to provision into the project database (display name, description, categories, table count). Read-only — these are a global catalog, not the project schema.',
124
+ promptSnippet: 'list_templates: list the available blueprint templates to apply. Read-only — call before apply_template.',
125
+ parameters: ListTemplatesZod,
126
+ async execute(_params, ctx) {
127
+ const resolved = await resolveProjectContext(ctx.cwd);
128
+ if (!resolved.context) {
129
+ return { content: [{ type: 'text', text: resolved.reason }], details: { templates: [] } };
130
+ }
131
+ const result = await resolved.context.modules.blueprintTemplate
132
+ .findMany({
133
+ select: {
134
+ displayName: true,
135
+ description: true,
136
+ categories: true,
137
+ definition: true,
138
+ },
139
+ orderBy: ['NAME_ASC'],
140
+ })
141
+ .execute();
142
+ if (!result.ok) {
143
+ const message = result.errors.map((e) => e.message).join('; ');
144
+ return {
145
+ content: [{ type: 'text', text: `Failed to read templates: ${message}` }],
146
+ details: { templates: [] },
147
+ };
148
+ }
149
+ const templates = (result.data.blueprintTemplates?.nodes ?? []).map((template) => ({
150
+ displayName: template.displayName ?? '',
151
+ description: template.description ?? null,
152
+ categories: Array.isArray(template.categories) ? template.categories : [],
153
+ tables: parseTemplateTables(template.definition),
154
+ }));
155
+ return {
156
+ content: [{ type: 'text', text: formatTemplatesText(templates) }],
157
+ details: { templates },
158
+ };
159
+ },
160
+ };
161
+ // ── create_template ───────────────────────────────────────────────────────
162
+ const CreateTemplateZod = z.object({
163
+ displayName: z.string().describe('Display name for the new blueprint template'),
164
+ blueprintName: z
165
+ .string()
166
+ .describe('Display name of an existing project blueprint to save as the template. Defaults to the most recently provisioned blueprint.')
167
+ .optional(),
168
+ description: z.string().describe('Description shown in the template catalog').optional(),
169
+ categories: z
170
+ .array(z.string())
171
+ .describe('Categories for catalog grouping and discovery')
172
+ .optional(),
173
+ });
174
+ export const createTemplateTool = {
175
+ name: 'create_template',
176
+ label: 'Create template',
177
+ description: 'Save an existing project blueprint into the global template catalog as a reusable blueprint template. Defaults to the most recently provisioned blueprint; pass blueprintName to pick a specific one by display name. Gated.',
178
+ promptSnippet: 'create_template: save a project blueprint to the reusable template catalog. Gated.',
179
+ parameters: CreateTemplateZod,
180
+ async execute(params, ctx) {
181
+ const resolved = await resolveProjectContext(ctx.cwd);
182
+ if (!resolved.context)
183
+ return done(false, resolved.reason);
184
+ const { modules, ownerId } = resolved.context;
185
+ if (!ownerId)
186
+ return done(false, 'Not authenticated (missing OWNER_ID in .env).');
187
+ try {
188
+ const blueprint = await findProjectBlueprint(resolved.context, params.blueprintName);
189
+ if (!blueprint) {
190
+ const which = params.blueprintName ? `"${params.blueprintName}"` : 'any blueprint';
191
+ return done(false, `No project blueprint found (${which}). Provision a blueprint first.`);
192
+ }
193
+ const base = params.displayName.toLowerCase().replace(/\s+/g, '_');
194
+ await modules.blueprintTemplate
195
+ .create({
196
+ data: {
197
+ ownerId,
198
+ name: `${base}_${Date.now()}`,
199
+ displayName: params.displayName,
200
+ description: params.description,
201
+ categories: params.categories,
202
+ definition: blueprint.definition,
203
+ },
204
+ select: { id: true, displayName: true },
205
+ })
206
+ .unwrap();
207
+ const message = `Created template "${params.displayName}"`;
208
+ return {
209
+ content: [{ type: 'text', text: message }],
210
+ details: {
211
+ success: true,
212
+ message,
213
+ displayName: params.displayName,
214
+ blueprintName: blueprint.displayName,
215
+ tables: parseTemplateTables(blueprint.definition),
216
+ },
217
+ };
218
+ }
219
+ catch (err) {
220
+ return done(false, err instanceof Error ? err.message : 'Failed to create template');
221
+ }
222
+ },
223
+ };
224
+ // ── apply_template ────────────────────────────────────────────────────────
225
+ const ApplyTemplateZod = z.object({
226
+ templateName: z.string().describe('The display name of the blueprint template to apply'),
227
+ nameOverride: z
228
+ .string()
229
+ .describe('Optional name override for the created blueprint (snake_case). Defaults to template name.')
230
+ .optional(),
231
+ });
232
+ export const applyTemplateTool = {
233
+ name: 'apply_template',
234
+ label: 'Apply template',
235
+ description: 'Apply an existing blueprint template to the project database, creating its tables. Use the template display name (from list_templates).',
236
+ promptSnippet: 'apply_template: provision a saved blueprint template by display name. Gated.',
237
+ parameters: ApplyTemplateZod,
238
+ async execute(params, ctx) {
239
+ const resolved = await resolveProjectContext(ctx.cwd);
240
+ if (!resolved.context)
241
+ return done(false, resolved.reason);
242
+ const { modules, databaseId, schemaId, ownerId } = resolved.context;
243
+ if (!ownerId)
244
+ return done(false, 'Not authenticated (missing OWNER_ID in .env).');
245
+ try {
246
+ const templateId = await resolveTemplateId(modules, params.templateName);
247
+ const base = params.nameOverride ?? params.templateName.toLowerCase().replace(/\s+/g, '_');
248
+ const nameOverride = `${base}_${Date.now()}`;
249
+ const copyResult = await modules.mutation
250
+ .copyTemplateToBlueprint({ input: { templateId, databaseId, ownerId, nameOverride } }, { select: { result: true } })
251
+ .unwrap();
252
+ const blueprintId = copyResult.copyTemplateToBlueprint?.result;
253
+ if (!blueprintId)
254
+ throw new Error('Failed to copy template');
255
+ const constructResult = await modules.mutation
256
+ .constructBlueprint({ input: { blueprintId, schemaId } }, { select: { result: true } })
257
+ .unwrap();
258
+ const refMap = constructResult.constructBlueprint?.result;
259
+ if (!refMap)
260
+ return done(false, `Construction failed for template "${params.templateName}"`);
261
+ const createdCount = Object.keys(refMap).length;
262
+ return done(true, `Applied template "${params.templateName}" — created ${createdCount} table${createdCount === 1 ? '' : 's'}`);
263
+ }
264
+ catch (err) {
265
+ return done(false, err instanceof Error ? err.message : 'Failed to apply template');
266
+ }
267
+ },
268
+ };
269
+ // ── update_template ───────────────────────────────────────────────────────
270
+ const UpdateTemplateZod = z.object({
271
+ templateName: z.string().describe('The display name of the blueprint template to update'),
272
+ patch: z.object({
273
+ displayName: z.string().describe('New display name').optional(),
274
+ description: z.string().describe('New description').optional(),
275
+ categories: z.array(z.string()).describe('New categories').optional(),
276
+ tags: z.array(z.string()).describe('New tags').optional(),
277
+ visibility: z.enum(['private', 'public']).describe('New visibility').optional(),
278
+ }),
279
+ });
280
+ export const updateTemplateTool = {
281
+ name: 'update_template',
282
+ label: 'Update template',
283
+ description: 'Update a blueprint template’s metadata (display name, description, categories, tags, visibility).',
284
+ promptSnippet: 'update_template: edit a saved template’s metadata by display name. Gated.',
285
+ parameters: UpdateTemplateZod,
286
+ async execute(params, ctx) {
287
+ const resolved = await resolveProjectContext(ctx.cwd);
288
+ if (!resolved.context)
289
+ return done(false, resolved.reason);
290
+ try {
291
+ const templateId = await resolveTemplateId(resolved.context.modules, params.templateName);
292
+ await resolved.context.modules.blueprintTemplate
293
+ .update({
294
+ where: { id: templateId },
295
+ data: params.patch,
296
+ select: { id: true, displayName: true },
297
+ })
298
+ .unwrap();
299
+ return done(true, `Updated template "${params.templateName}"`);
300
+ }
301
+ catch (err) {
302
+ return done(false, err instanceof Error ? err.message : 'Failed to update template');
303
+ }
304
+ },
305
+ };
306
+ // ── delete_template ───────────────────────────────────────────────────────
307
+ const DeleteTemplateZod = z.object({
308
+ templateName: z.string().describe('The display name of the blueprint template to delete'),
309
+ });
310
+ export const deleteTemplateTool = {
311
+ name: 'delete_template',
312
+ label: 'Delete template',
313
+ description: 'Permanently delete a blueprint template by its display name.',
314
+ promptSnippet: 'delete_template: remove a saved template by display name. Destructive — gated.',
315
+ parameters: DeleteTemplateZod,
316
+ async execute(params, ctx) {
317
+ const resolved = await resolveProjectContext(ctx.cwd);
318
+ if (!resolved.context)
319
+ return done(false, resolved.reason);
320
+ try {
321
+ const templateId = await resolveTemplateId(resolved.context.modules, params.templateName);
322
+ await resolved.context.modules.blueprintTemplate
323
+ .delete({ where: { id: templateId }, select: { id: true } })
324
+ .unwrap();
325
+ return done(true, `Deleted template "${params.templateName}"`);
326
+ }
327
+ catch (err) {
328
+ return done(false, err instanceof Error ? err.message : 'Failed to delete template');
329
+ }
330
+ },
331
+ };
package/host.d.ts ADDED
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Host contract for the Constructive database tools.
3
+ *
4
+ * The typed db tools were extracted from Constructive Desktop, where they read
5
+ * an Electron-side `runtime` singleton (account store, backend config, data-auth
6
+ * broker, preview token). Hosts now inject the same surface here once at
7
+ * startup (`configureHost`); the tool modules stay module-level `HarnessTool`
8
+ * consts and read it lazily via `getHost()`.
9
+ *
10
+ * Nothing here is harness-specific: the host is the *application* a tool acts
11
+ * on behalf of, so the same contract serves whichever adapter runs the tools.
12
+ */
13
+ export type HostAccount = {
14
+ userId: string;
15
+ accessToken: string;
16
+ apiKey?: string;
17
+ };
18
+ export type HostBackendConfig = {
19
+ apiEndpoint?: string;
20
+ modulesEndpoint?: string;
21
+ };
22
+ export type ActiveDataToken = {
23
+ token: string;
24
+ userId?: string;
25
+ expiresAt: number;
26
+ origin?: string;
27
+ };
28
+ /**
29
+ * Optional data-plane token broker: remembers per-database end-user tokens
30
+ * across tool calls and invalidates declined/expired ones. Hosts without a
31
+ * broker fall back to the preview-token harvest on every call.
32
+ */
33
+ export interface DataAuthBroker {
34
+ getActiveToken(databaseId: string): ActiveDataToken | undefined | null;
35
+ isInvalidToken(databaseId: string, token: string): boolean;
36
+ adoptToken(databaseId: string, token: ActiveDataToken): void;
37
+ }
38
+ /** Token harvested from the host's app preview (end-user sign-in). */
39
+ export type PreviewToken = {
40
+ accessToken: string;
41
+ accessTokenExpiresAt?: string;
42
+ userId?: string;
43
+ };
44
+ /**
45
+ * Overlay layered over the pinned base preset when provisioning a database.
46
+ * Structurally the `ProvisionOverlay` from `provision-database/resolve`; typed
47
+ * loosely here to keep `host.ts` free of provision-internal imports.
48
+ */
49
+ export interface HostProvisionOverlay {
50
+ preset?: string;
51
+ add?: (string | [string, Record<string, unknown>])[];
52
+ remove?: string[];
53
+ }
54
+ /**
55
+ * A minted secret handed to the host for out-of-band delivery (.env write +
56
+ * one-time reveal). The plaintext never enters tool results or the transcript;
57
+ * the harness forgets it after this call.
58
+ */
59
+ export type SecretDelivery = {
60
+ databaseId: string;
61
+ /** Project directory whose `.env` receives the key. */
62
+ cwd: string;
63
+ envVar: string;
64
+ plaintext: string;
65
+ keyId: string;
66
+ expiresAt?: string;
67
+ };
68
+ /**
69
+ * Context for a host-side step-up: enough to derive the per-database auth
70
+ * endpoint and look up the app session without re-resolving the project.
71
+ */
72
+ export type StepUpRequest = {
73
+ databaseId: string;
74
+ databaseName: string;
75
+ apiEndpoint: string;
76
+ };
77
+ export interface ToolsHost {
78
+ /** Signed-in platform account, or null/undefined when signed out. */
79
+ account(): HostAccount | null | undefined;
80
+ /** Host-configured backend endpoints (env-aware). */
81
+ backendConfig(): HostBackendConfig | null | undefined;
82
+ /** Optional data-plane token broker (see DataAuthBroker). */
83
+ dataAuthBroker?: DataAuthBroker;
84
+ /**
85
+ * Host-specific sign-in instruction, substituted into signed-out failure
86
+ * reasons (e.g. the CLI's "Run `agent login` to sign in."). Absent hosts get
87
+ * the desktop wording.
88
+ */
89
+ signInHint?: string;
90
+ /** Harvest an end-user token from the host's app preview, if it has one. */
91
+ previewToken?(): Promise<PreviewToken | null>;
92
+ /** Treat tokens expiring within this window as already expired. Default 30s. */
93
+ dataTokenSkewMs?: number;
94
+ /**
95
+ * Optional provision overlay: pick a base preset and/or layer module
96
+ * add/remove on top of it. The base module list always comes from the pinned
97
+ * `node-type-registry` preset — this only customizes it. Distributed as data
98
+ * (e.g. materialized from appstash / a pinned git ref), never as code.
99
+ */
100
+ provisionOverlay?(): HostProvisionOverlay | null | undefined | Promise<HostProvisionOverlay | null | undefined>;
101
+ /**
102
+ * Complete MFA step-up for the database's app session in the host's own
103
+ * process (password dialog + verifyPassword). The password never passes
104
+ * through the harness or the model. Resolve true when step-up succeeded.
105
+ */
106
+ requestStepUp?(request: StepUpRequest): Promise<boolean>;
107
+ /**
108
+ * Deliver a minted secret to the user (.env write + one-time reveal).
109
+ * Required for create_api_key — without it the tool refuses to mint.
110
+ */
111
+ deliverSecret?(delivery: SecretDelivery): Promise<void>;
112
+ }
113
+ export declare const DEFAULT_DATA_TOKEN_SKEW_MS = 30000;
114
+ export declare function configureHost(host: ToolsHost): void;
115
+ export declare function getHost(): ToolsHost;
package/host.js ADDED
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ /**
3
+ * Host contract for the Constructive database tools.
4
+ *
5
+ * The typed db tools were extracted from Constructive Desktop, where they read
6
+ * an Electron-side `runtime` singleton (account store, backend config, data-auth
7
+ * broker, preview token). Hosts now inject the same surface here once at
8
+ * startup (`configureHost`); the tool modules stay module-level `HarnessTool`
9
+ * consts and read it lazily via `getHost()`.
10
+ *
11
+ * Nothing here is harness-specific: the host is the *application* a tool acts
12
+ * on behalf of, so the same contract serves whichever adapter runs the tools.
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.DEFAULT_DATA_TOKEN_SKEW_MS = void 0;
16
+ exports.configureHost = configureHost;
17
+ exports.getHost = getHost;
18
+ exports.DEFAULT_DATA_TOKEN_SKEW_MS = 30_000;
19
+ let currentHost = null;
20
+ function configureHost(host) {
21
+ currentHost = host;
22
+ }
23
+ function getHost() {
24
+ if (!currentHost) {
25
+ throw new Error('@agentic-kit/db-tools host not configured. Call configureHost() (or createDbTools(host)) before using the db tools.');
26
+ }
27
+ return currentHost;
28
+ }
package/index.d.ts ADDED
@@ -0,0 +1,20 @@
1
+ import type { AnyHarnessTool } from '@agentic-kit/harness';
2
+ import { type ToolsHost } from './host';
3
+ /**
4
+ * The Constructive database tools, in registration order.
5
+ *
6
+ * Plain `HarnessTool`s: a harness gets them by mapping them into its own tool
7
+ * shape, which is the adapter's job, so this package stays free of any harness
8
+ * dependency (see `toPiTool` in `@agentic-kit/pi` for that binding).
9
+ */
10
+ export declare const constructiveDbTools: readonly AnyHarnessTool[];
11
+ /** Configure the host and get the tools in one call. */
12
+ export declare function createConstructiveDbTools(host: ToolsHost): readonly AnyHarnessTool[];
13
+ export { CONTEXT_ENV_KEYS, CONTEXT_ENV_PREFIX, type ContextEnvKey, type ContextSource, deriveSubdomainEndpoint, fromEnvFile, fromEnvironment, type ModulesClient, type ProjectContext, type ProjectContextFailureCode, resolveDataToken, resolveProjectContext, } from './context';
14
+ export { type ActiveDataToken, configureHost, type DataAuthBroker, DEFAULT_DATA_TOKEN_SKEW_MS, getHost, type HostAccount, type HostBackendConfig, type HostProvisionOverlay, type PreviewToken, type SecretDelivery, type StepUpRequest, type ToolsHost, } from './host';
15
+ export { loadProvisionManifest, parseProvisionManifest, PROVISION_MANIFEST_FILE, type ProvisionManifest, } from './provision-database/manifest';
16
+ export { allModulePresets, DEFAULT_PROVISION_PRESET, getModulePreset, type ModulePreset, type ProvisionModule, } from './provision-database/presets';
17
+ export { moduleKey, type ProvisionOverlay, resolveProvisionModules, } from './provision-database/resolve';
18
+ export { toolSchema } from './tool-schema';
19
+ export { createTemplatePreviewTables } from './tools/templates';
20
+ export default constructiveDbTools;
package/index.js ADDED
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createTemplatePreviewTables = exports.toolSchema = exports.resolveProvisionModules = exports.moduleKey = exports.getModulePreset = exports.DEFAULT_PROVISION_PRESET = exports.allModulePresets = exports.PROVISION_MANIFEST_FILE = exports.parseProvisionManifest = exports.loadProvisionManifest = exports.getHost = exports.DEFAULT_DATA_TOKEN_SKEW_MS = exports.configureHost = exports.resolveProjectContext = exports.resolveDataToken = exports.fromEnvironment = exports.fromEnvFile = exports.deriveSubdomainEndpoint = exports.CONTEXT_ENV_PREFIX = exports.CONTEXT_ENV_KEYS = exports.constructiveDbTools = void 0;
4
+ exports.createConstructiveDbTools = createConstructiveDbTools;
5
+ const host_1 = require("./host");
6
+ const add_policies_1 = require("./tools/add-policies");
7
+ const add_records_1 = require("./tools/add-records");
8
+ const add_relation_1 = require("./tools/add-relation");
9
+ const create_api_key_1 = require("./tools/create-api-key");
10
+ const describe_schema_1 = require("./tools/describe-schema");
11
+ const manage_entity_types_1 = require("./tools/manage-entity-types");
12
+ const mutations_1 = require("./tools/mutations");
13
+ const provision_blueprint_1 = require("./tools/provision-blueprint");
14
+ const provision_database_1 = require("./tools/provision-database");
15
+ const run_codegen_1 = require("./tools/run-codegen");
16
+ const templates_1 = require("./tools/templates");
17
+ /**
18
+ * The Constructive database tools, in registration order.
19
+ *
20
+ * Plain `HarnessTool`s: a harness gets them by mapping them into its own tool
21
+ * shape, which is the adapter's job, so this package stays free of any harness
22
+ * dependency (see `toPiTool` in `@agentic-kit/pi` for that binding).
23
+ */
24
+ exports.constructiveDbTools = [
25
+ provision_database_1.provisionDatabaseTool,
26
+ describe_schema_1.describeSchemaTool,
27
+ templates_1.listTemplatesTool,
28
+ provision_blueprint_1.provisionBlueprintTool,
29
+ add_relation_1.addRelationTool,
30
+ mutations_1.deleteTableTool,
31
+ mutations_1.createFieldTool,
32
+ mutations_1.updateFieldTool,
33
+ mutations_1.deleteFieldTool,
34
+ add_policies_1.addPoliciesTool,
35
+ templates_1.applyTemplateTool,
36
+ templates_1.createTemplateTool,
37
+ templates_1.updateTemplateTool,
38
+ templates_1.deleteTemplateTool,
39
+ add_records_1.addRecordsTool,
40
+ manage_entity_types_1.manageEntityTypesTool,
41
+ create_api_key_1.createApiKeyTool,
42
+ run_codegen_1.runCodegenTool,
43
+ ];
44
+ /** Configure the host and get the tools in one call. */
45
+ function createConstructiveDbTools(host) {
46
+ (0, host_1.configureHost)(host);
47
+ return exports.constructiveDbTools;
48
+ }
49
+ var context_1 = require("./context");
50
+ Object.defineProperty(exports, "CONTEXT_ENV_KEYS", { enumerable: true, get: function () { return context_1.CONTEXT_ENV_KEYS; } });
51
+ Object.defineProperty(exports, "CONTEXT_ENV_PREFIX", { enumerable: true, get: function () { return context_1.CONTEXT_ENV_PREFIX; } });
52
+ Object.defineProperty(exports, "deriveSubdomainEndpoint", { enumerable: true, get: function () { return context_1.deriveSubdomainEndpoint; } });
53
+ Object.defineProperty(exports, "fromEnvFile", { enumerable: true, get: function () { return context_1.fromEnvFile; } });
54
+ Object.defineProperty(exports, "fromEnvironment", { enumerable: true, get: function () { return context_1.fromEnvironment; } });
55
+ Object.defineProperty(exports, "resolveDataToken", { enumerable: true, get: function () { return context_1.resolveDataToken; } });
56
+ Object.defineProperty(exports, "resolveProjectContext", { enumerable: true, get: function () { return context_1.resolveProjectContext; } });
57
+ var host_2 = require("./host");
58
+ Object.defineProperty(exports, "configureHost", { enumerable: true, get: function () { return host_2.configureHost; } });
59
+ Object.defineProperty(exports, "DEFAULT_DATA_TOKEN_SKEW_MS", { enumerable: true, get: function () { return host_2.DEFAULT_DATA_TOKEN_SKEW_MS; } });
60
+ Object.defineProperty(exports, "getHost", { enumerable: true, get: function () { return host_2.getHost; } });
61
+ var manifest_1 = require("./provision-database/manifest");
62
+ Object.defineProperty(exports, "loadProvisionManifest", { enumerable: true, get: function () { return manifest_1.loadProvisionManifest; } });
63
+ Object.defineProperty(exports, "parseProvisionManifest", { enumerable: true, get: function () { return manifest_1.parseProvisionManifest; } });
64
+ Object.defineProperty(exports, "PROVISION_MANIFEST_FILE", { enumerable: true, get: function () { return manifest_1.PROVISION_MANIFEST_FILE; } });
65
+ var presets_1 = require("./provision-database/presets");
66
+ Object.defineProperty(exports, "allModulePresets", { enumerable: true, get: function () { return presets_1.allModulePresets; } });
67
+ Object.defineProperty(exports, "DEFAULT_PROVISION_PRESET", { enumerable: true, get: function () { return presets_1.DEFAULT_PROVISION_PRESET; } });
68
+ Object.defineProperty(exports, "getModulePreset", { enumerable: true, get: function () { return presets_1.getModulePreset; } });
69
+ var resolve_1 = require("./provision-database/resolve");
70
+ Object.defineProperty(exports, "moduleKey", { enumerable: true, get: function () { return resolve_1.moduleKey; } });
71
+ Object.defineProperty(exports, "resolveProvisionModules", { enumerable: true, get: function () { return resolve_1.resolveProvisionModules; } });
72
+ var tool_schema_1 = require("./tool-schema");
73
+ Object.defineProperty(exports, "toolSchema", { enumerable: true, get: function () { return tool_schema_1.toolSchema; } });
74
+ var templates_2 = require("./tools/templates");
75
+ Object.defineProperty(exports, "createTemplatePreviewTables", { enumerable: true, get: function () { return templates_2.createTemplatePreviewTables; } });
76
+ exports.default = exports.constructiveDbTools;
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@agentic-kit/db-tools",
3
+ "version": "0.2.0",
4
+ "author": "Constructive <developers@constructive.io>",
5
+ "description": "harness-neutral Constructive database tools — provisioning, schema, policies, records, templates and codegen as HarnessTools any adapter can bind",
6
+ "main": "index.js",
7
+ "module": "esm/index.js",
8
+ "types": "index.d.ts",
9
+ "homepage": "https://github.com/constructive-io/constructive",
10
+ "license": "SEE LICENSE IN LICENSE",
11
+ "publishConfig": {
12
+ "access": "public",
13
+ "directory": "dist"
14
+ },
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/constructive-io/constructive"
18
+ },
19
+ "bugs": {
20
+ "url": "https://github.com/constructive-io/constructive/issues"
21
+ },
22
+ "scripts": {
23
+ "clean": "makage clean",
24
+ "prepack": "npm run build",
25
+ "build": "makage build",
26
+ "build:dev": "makage build --dev",
27
+ "lint": "eslint . --fix",
28
+ "test": "jest",
29
+ "test:watch": "jest --watch"
30
+ },
31
+ "dependencies": {
32
+ "12factor-env": "^1.32.0",
33
+ "@agentic-kit/harness": "^0.15.0",
34
+ "@constructive-io/graphql-query": "^4.14.1",
35
+ "@constructive-io/sdk": "^1.14.1",
36
+ "node-type-registry": "^1.17.0",
37
+ "zod": "^4.4.3"
38
+ },
39
+ "devDependencies": {
40
+ "typebox": "^1.0.0"
41
+ },
42
+ "keywords": [
43
+ "agentic-kit",
44
+ "tools",
45
+ "database",
46
+ "constructive"
47
+ ],
48
+ "gitHead": "d4bb5506059e1dfb28f2766e6d18e8d946db632d"
49
+ }
@@ -0,0 +1,26 @@
1
+ import { type PolicyProvisioningCategory } from '@agentic-kit/harness';
2
+ import type { ModulesClient } from '../context';
3
+ import { type CrudOperation, type CrudPolicyConfigs } from './provision-helpers';
4
+ export interface AddPoliciesToTablePolicyEntry {
5
+ policyType: string;
6
+ dataNodeType?: string;
7
+ nodeData?: Record<string, unknown>;
8
+ sharedPolicyData: Record<string, unknown>;
9
+ operations: CrudPolicyConfigs;
10
+ enabledOperations?: CrudOperation[];
11
+ }
12
+ export interface AddPoliciesToTableInput {
13
+ client: ModulesClient;
14
+ databaseId: string;
15
+ schemaId: string;
16
+ tableId: string;
17
+ policies: AddPoliciesToTablePolicyEntry[];
18
+ }
19
+ export declare class UnsupportedPolicyCategoryError extends Error {
20
+ readonly policyType: string;
21
+ readonly category: PolicyProvisioningCategory;
22
+ constructor(policyType: string, category: PolicyProvisioningCategory);
23
+ }
24
+ export declare function addPoliciesToExistingTable(input: AddPoliciesToTableInput): Promise<{
25
+ success: true;
26
+ }>;