@agentic-kit/pi 0.9.2 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/context.js +7 -5
- package/db-probe.d.ts +1 -0
- package/db-probe.js +1 -1
- package/esm/context.js +7 -5
- package/esm/db-probe.d.ts +1 -0
- package/esm/db-probe.js +1 -1
- package/esm/host.d.ts +40 -0
- package/esm/index.d.ts +1 -1
- package/esm/index.js +5 -1
- package/esm/provision-database/credential.d.ts +1 -1
- package/esm/provision-database/credential.js +2 -2
- package/esm/tools/create-api-key.d.ts +18 -0
- package/esm/tools/create-api-key.js +216 -0
- package/esm/tools/manage-entity-types.d.ts +41 -0
- package/esm/tools/manage-entity-types.js +203 -0
- package/esm/tools/provision-database.js +2 -1
- package/host.d.ts +40 -0
- package/index.d.ts +1 -1
- package/index.js +6 -1
- package/package.json +5 -5
- package/provision-database/credential.d.ts +1 -1
- package/provision-database/credential.js +2 -2
- package/tools/create-api-key.d.ts +18 -0
- package/tools/create-api-key.js +222 -0
- package/tools/manage-entity-types.d.ts +41 -0
- package/tools/manage-entity-types.js +208 -0
- package/tools/provision-database.js +2 -1
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.manageEntityTypesTool = void 0;
|
|
4
|
+
exports.defaultPrefix = defaultPrefix;
|
|
5
|
+
exports.validateManageEntityTypes = validateManageEntityTypes;
|
|
6
|
+
const zod_1 = require("zod");
|
|
7
|
+
const context_1 = require("../context");
|
|
8
|
+
const tool_schema_1 = require("../tool-schema");
|
|
9
|
+
const ManageEntityTypesZod = zod_1.z.object({
|
|
10
|
+
action: zod_1.z
|
|
11
|
+
.enum(['list', 'create', 'delete'])
|
|
12
|
+
.describe('list: show the entity types provisioned in this database. create: provision a new entity type (creates its entity table + membership wiring). delete: remove the provision registration. Registrations are immutable once provisioned — there is no update; to change one, delete it and create a new one.'),
|
|
13
|
+
name: zod_1.z.string().describe('Entity type name. Required for create.').optional(),
|
|
14
|
+
entity_type_id: zod_1.z
|
|
15
|
+
.string()
|
|
16
|
+
.describe('Entity type provision id. Required for delete — get it from action "list".')
|
|
17
|
+
.optional(),
|
|
18
|
+
description: zod_1.z
|
|
19
|
+
.string()
|
|
20
|
+
.describe('Human-readable description of the entity type. Create only.')
|
|
21
|
+
.optional(),
|
|
22
|
+
prefix: zod_1.z
|
|
23
|
+
.string()
|
|
24
|
+
.describe('Table-name prefix for the provisioned tables (e.g. "org" → org table, org_memberships). Create only; defaults to the snake_case of name.')
|
|
25
|
+
.optional(),
|
|
26
|
+
parent_entity: zod_1.z
|
|
27
|
+
.string()
|
|
28
|
+
.describe('Parent entity table name, for hierarchical types (e.g. a "team" under an "org"). Create only; the backend defaults it to the root entity (org).')
|
|
29
|
+
.optional(),
|
|
30
|
+
is_visible: zod_1.z
|
|
31
|
+
.boolean()
|
|
32
|
+
.describe('Whether the type shows up in end-user entity listings. Create only.')
|
|
33
|
+
.optional(),
|
|
34
|
+
has_invites: zod_1.z
|
|
35
|
+
.boolean()
|
|
36
|
+
.describe('Provision an invites module ({prefix}_invites + claimed invites). Create only.')
|
|
37
|
+
.optional(),
|
|
38
|
+
has_profiles: zod_1.z
|
|
39
|
+
.boolean()
|
|
40
|
+
.describe('Provision a profiles table for members of this type. Create only.')
|
|
41
|
+
.optional(),
|
|
42
|
+
has_limits: zod_1.z
|
|
43
|
+
.boolean()
|
|
44
|
+
.describe('Provision usage-limits tracking for this type. Create only.')
|
|
45
|
+
.optional(),
|
|
46
|
+
has_levels: zod_1.z
|
|
47
|
+
.boolean()
|
|
48
|
+
.describe('Provision levels/achievements support for this type. Create only.')
|
|
49
|
+
.optional(),
|
|
50
|
+
has_storage: zod_1.z
|
|
51
|
+
.boolean()
|
|
52
|
+
.describe('Provision a storage module (files + buckets tables) for this type. Create only.')
|
|
53
|
+
.optional(),
|
|
54
|
+
});
|
|
55
|
+
const ManageEntityTypesSchema = (0, tool_schema_1.toolSchema)(ManageEntityTypesZod);
|
|
56
|
+
const SUMMARY_SELECT = {
|
|
57
|
+
id: true,
|
|
58
|
+
name: true,
|
|
59
|
+
description: true,
|
|
60
|
+
prefix: true,
|
|
61
|
+
parentEntity: true,
|
|
62
|
+
isVisible: true,
|
|
63
|
+
outEntityTableName: true,
|
|
64
|
+
outInstalledModules: true,
|
|
65
|
+
};
|
|
66
|
+
function toSummary(row) {
|
|
67
|
+
return {
|
|
68
|
+
id: row.id,
|
|
69
|
+
name: row.name,
|
|
70
|
+
description: row.description,
|
|
71
|
+
prefix: row.prefix,
|
|
72
|
+
parentEntity: row.parentEntity,
|
|
73
|
+
isVisible: row.isVisible,
|
|
74
|
+
entityTableName: row.outEntityTableName,
|
|
75
|
+
installedModules: row.outInstalledModules,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function formatSummary(s) {
|
|
79
|
+
const parts = [
|
|
80
|
+
`- ${s.name ?? '?'} (id: ${s.id})`,
|
|
81
|
+
` table: ${s.entityTableName ?? '?'}, prefix: ${s.prefix ?? '?'}`,
|
|
82
|
+
];
|
|
83
|
+
if (s.parentEntity)
|
|
84
|
+
parts.push(` parent: ${s.parentEntity}`);
|
|
85
|
+
if (s.description)
|
|
86
|
+
parts.push(` description: ${s.description}`);
|
|
87
|
+
if (s.installedModules?.length)
|
|
88
|
+
parts.push(` modules: ${s.installedModules.join(', ')}`);
|
|
89
|
+
return parts.join('\n');
|
|
90
|
+
}
|
|
91
|
+
function defaultPrefix(name) {
|
|
92
|
+
return name
|
|
93
|
+
.trim()
|
|
94
|
+
.toLowerCase()
|
|
95
|
+
.replace(/[^a-z0-9]+/g, '_')
|
|
96
|
+
.replace(/^_+|_+$/g, '');
|
|
97
|
+
}
|
|
98
|
+
function validateManageEntityTypes(params) {
|
|
99
|
+
switch (params.action) {
|
|
100
|
+
case 'create':
|
|
101
|
+
if (!params.name?.trim())
|
|
102
|
+
return 'create requires "name".';
|
|
103
|
+
if (params.entity_type_id)
|
|
104
|
+
return 'create does not take "entity_type_id" — it mints a new one.';
|
|
105
|
+
return null;
|
|
106
|
+
case 'delete':
|
|
107
|
+
if (!params.entity_type_id)
|
|
108
|
+
return 'delete requires "entity_type_id" (use action "list" to find it).';
|
|
109
|
+
return null;
|
|
110
|
+
default:
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
exports.manageEntityTypesTool = {
|
|
115
|
+
name: 'manage_entity_types',
|
|
116
|
+
label: 'Manage entity types',
|
|
117
|
+
description: 'List, create, or delete entity types in the project database. An entity type (e.g. organization, team, project) provisions its own entity table plus membership wiring, and is the unit that API keys can be scoped to. Registrations are immutable once provisioned — to change one, delete it and create a new one. Deleting removes the registration; the already-provisioned entity table stays in the API schema.',
|
|
118
|
+
promptSnippet: 'manage_entity_types: list/create/delete entity types (orgs, teams, …) in the project database. list is free; create/delete are gated.',
|
|
119
|
+
parameters: ManageEntityTypesSchema,
|
|
120
|
+
async execute(_id, params, _signal, _onUpdate, ctx) {
|
|
121
|
+
const resolved = await (0, context_1.resolveProjectContext)(ctx.cwd);
|
|
122
|
+
if (!resolved.context) {
|
|
123
|
+
return {
|
|
124
|
+
content: [{ type: 'text', text: resolved.reason }],
|
|
125
|
+
details: { success: false, message: resolved.reason },
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
const invalid = validateManageEntityTypes(params);
|
|
129
|
+
if (invalid) {
|
|
130
|
+
return {
|
|
131
|
+
content: [{ type: 'text', text: invalid }],
|
|
132
|
+
details: { success: false, message: invalid },
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
const { modules, databaseId } = resolved.context;
|
|
136
|
+
try {
|
|
137
|
+
switch (params.action) {
|
|
138
|
+
case 'list': {
|
|
139
|
+
const result = await modules.entityTypeProvision
|
|
140
|
+
.findMany({
|
|
141
|
+
where: { databaseId: { equalTo: databaseId } },
|
|
142
|
+
select: SUMMARY_SELECT,
|
|
143
|
+
})
|
|
144
|
+
.unwrap();
|
|
145
|
+
const entityTypes = result.entityTypeProvisions.nodes.map((row) => toSummary(row));
|
|
146
|
+
const message = entityTypes.length === 0
|
|
147
|
+
? 'No entity types are provisioned in this database yet.'
|
|
148
|
+
: `${entityTypes.length} entity type${entityTypes.length === 1 ? '' : 's'}:\n${entityTypes.map(formatSummary).join('\n')}`;
|
|
149
|
+
return {
|
|
150
|
+
content: [{ type: 'text', text: message }],
|
|
151
|
+
details: { success: true, message, entityTypes },
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
case 'create': {
|
|
155
|
+
const name = params.name.trim();
|
|
156
|
+
const result = await modules.entityTypeProvision
|
|
157
|
+
.create({
|
|
158
|
+
data: {
|
|
159
|
+
databaseId,
|
|
160
|
+
name,
|
|
161
|
+
prefix: params.prefix?.trim() || defaultPrefix(name),
|
|
162
|
+
...(params.description !== undefined && { description: params.description }),
|
|
163
|
+
...(params.parent_entity !== undefined && { parentEntity: params.parent_entity }),
|
|
164
|
+
...(params.is_visible !== undefined && { isVisible: params.is_visible }),
|
|
165
|
+
...(params.has_invites !== undefined && { hasInvites: params.has_invites }),
|
|
166
|
+
...(params.has_profiles !== undefined && { hasProfiles: params.has_profiles }),
|
|
167
|
+
...(params.has_limits !== undefined && { hasLimits: params.has_limits }),
|
|
168
|
+
...(params.has_levels !== undefined && { hasLevels: params.has_levels }),
|
|
169
|
+
...(params.has_storage && {
|
|
170
|
+
storage: [{}],
|
|
171
|
+
}),
|
|
172
|
+
},
|
|
173
|
+
select: SUMMARY_SELECT,
|
|
174
|
+
})
|
|
175
|
+
.unwrap();
|
|
176
|
+
const row = result.createEntityTypeProvision?.entityTypeProvision;
|
|
177
|
+
if (!row)
|
|
178
|
+
throw new Error('createEntityTypeProvision returned no row.');
|
|
179
|
+
const summary = toSummary(row);
|
|
180
|
+
const message = `Created entity type "${summary.name}" (id: ${summary.id}) — entity table "${summary.entityTableName}"${summary.installedModules?.length ? `, modules: ${summary.installedModules.join(', ')}` : ''}. Run run_codegen to pull it into the typed SDK.`;
|
|
181
|
+
return {
|
|
182
|
+
content: [{ type: 'text', text: message }],
|
|
183
|
+
details: { success: true, message, entityTypes: [summary] },
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
case 'delete': {
|
|
187
|
+
const result = await modules.entityTypeProvision
|
|
188
|
+
.delete({
|
|
189
|
+
where: { id: params.entity_type_id },
|
|
190
|
+
select: { id: true, name: true, outEntityTableName: true },
|
|
191
|
+
})
|
|
192
|
+
.unwrap();
|
|
193
|
+
const row = result.deleteEntityTypeProvision?.entityTypeProvision;
|
|
194
|
+
const name = row?.name ?? params.entity_type_id;
|
|
195
|
+
const message = `Deleted entity type registration "${name}". Note: the provisioned entity table${row?.outEntityTableName ? ` "${row.outEntityTableName}"` : ''} remains in the API schema with its data.`;
|
|
196
|
+
return {
|
|
197
|
+
content: [{ type: 'text', text: message }],
|
|
198
|
+
details: { success: true, message },
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
catch (err) {
|
|
204
|
+
const message = err instanceof Error ? err.message : 'Failed to manage entity types';
|
|
205
|
+
return { content: [{ type: 'text', text: message }], details: { success: false, message } };
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
};
|
|
@@ -115,7 +115,7 @@ exports.provisionDatabaseTool = {
|
|
|
115
115
|
// with no usable bearer errors out here rather than silently minting a
|
|
116
116
|
// throwaway owner. Gate BEFORE prewarm so an error return doesn't leak a
|
|
117
117
|
// detached background scaffold/install.
|
|
118
|
-
const credential = (0, credential_1.selectProvisionCredential)(host.account());
|
|
118
|
+
const credential = (0, credential_1.selectProvisionCredential)(host.account(), host.signInHint);
|
|
119
119
|
if (credential.mode === 'error') {
|
|
120
120
|
return fail(`Cannot provision a database: ${credential.reason}`);
|
|
121
121
|
}
|
|
@@ -135,6 +135,7 @@ exports.provisionDatabaseTool = {
|
|
|
135
135
|
endpoint: apiEndpoint,
|
|
136
136
|
bearer: credential.bearer,
|
|
137
137
|
databaseId: existingEnv.DATABASE_ID,
|
|
138
|
+
signInHint: host.signInHint,
|
|
138
139
|
});
|
|
139
140
|
if (probe.outcome === 'unreachable') {
|
|
140
141
|
return fail(`Cannot verify the existing database binding: backend unreachable (${probe.detail}). Check the Constructive backend is running, then retry — do not reprovision on an unreachable backend.`);
|