@cat-factory/server 0.295.0 → 0.296.1
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/dist/agents/repoFiles.d.ts +30 -8
- package/dist/agents/repoFiles.d.ts.map +1 -1
- package/dist/agents/repoFiles.js +43 -14
- package/dist/agents/repoFiles.js.map +1 -1
- package/dist/agents/repoOrigin.d.ts +73 -0
- package/dist/agents/repoOrigin.d.ts.map +1 -0
- package/dist/agents/repoOrigin.js +91 -0
- package/dist/agents/repoOrigin.js.map +1 -0
- package/dist/agents/toolServers.d.ts.map +1 -1
- package/dist/agents/toolServers.js +15 -1
- package/dist/agents/toolServers.js.map +1 -1
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +10 -0
- package/dist/app.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/modules/agentKinds/AgentKindsController.d.ts +46 -0
- package/dist/modules/agentKinds/AgentKindsController.d.ts.map +1 -0
- package/dist/modules/agentKinds/AgentKindsController.js +56 -0
- package/dist/modules/agentKinds/AgentKindsController.js.map +1 -0
- package/dist/modules/persistence/PersistenceController.d.ts.map +1 -1
- package/dist/modules/persistence/PersistenceController.js +6 -161
- package/dist/modules/persistence/PersistenceController.js.map +1 -1
- package/dist/modules/persistence/dispatchScope.d.ts +16 -0
- package/dist/modules/persistence/dispatchScope.d.ts.map +1 -0
- package/dist/modules/persistence/dispatchScope.js +307 -0
- package/dist/modules/persistence/dispatchScope.js.map +1 -0
- package/dist/persistence/agentKinds.d.ts +43 -0
- package/dist/persistence/agentKinds.d.ts.map +1 -0
- package/dist/persistence/agentKinds.js +99 -0
- package/dist/persistence/agentKinds.js.map +1 -0
- package/dist/persistence/rpc-allowlist-libraries.d.ts +4 -0
- package/dist/persistence/rpc-allowlist-libraries.d.ts.map +1 -0
- package/dist/persistence/rpc-allowlist-libraries.js +209 -0
- package/dist/persistence/rpc-allowlist-libraries.js.map +1 -0
- package/dist/persistence/rpc-allowlist-vcs.d.ts +24 -0
- package/dist/persistence/rpc-allowlist-vcs.d.ts.map +1 -0
- package/dist/persistence/rpc-allowlist-vcs.js +119 -0
- package/dist/persistence/rpc-allowlist-vcs.js.map +1 -0
- package/dist/persistence/rpc-allowlist.d.ts.map +1 -1
- package/dist/persistence/rpc-allowlist.js +66 -249
- package/dist/persistence/rpc-allowlist.js.map +1 -1
- package/dist/persistence/rpc-scope.logic.d.ts +46 -0
- package/dist/persistence/rpc-scope.logic.d.ts.map +1 -1
- package/dist/persistence/rpc-scope.logic.js +109 -0
- package/dist/persistence/rpc-scope.logic.js.map +1 -1
- package/dist/persistence/rpc.d.ts +111 -0
- package/dist/persistence/rpc.d.ts.map +1 -1
- package/dist/persistence/rpc.js +42 -44
- package/dist/persistence/rpc.js.map +1 -1
- package/package.json +6 -6
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The per-request READ MEMO, plus the one registry substitution it earns.
|
|
3
|
+
*
|
|
4
|
+
* Every entity-keyed scope rule resolves a row to bind the call, and for a handful of methods that
|
|
5
|
+
* row IS what the call then dispatches. Memoising each read per request keeps those to one query,
|
|
6
|
+
* and the `memoOverrides` table points the dispatched method at the same memo. Extracted from
|
|
7
|
+
* {@link buildDispatchScope} when the batched resolvers pushed it past its function-size budget:
|
|
8
|
+
* this half is about READING ONCE, the other about what a read MEANS for scope.
|
|
9
|
+
*/
|
|
10
|
+
function buildRequestReaders(registry, request) {
|
|
11
|
+
const workspaceRepository = registry.workspaceRepository;
|
|
12
|
+
const blockRepository = registry.blockRepository;
|
|
13
|
+
const serviceRepository = registry.serviceRepository;
|
|
14
|
+
const skillSourceRepository = registry.skillSourceRepository;
|
|
15
|
+
// The owner-pair content-library source tables, keyed by the `LibrarySourceEntity` the rule
|
|
16
|
+
// names, so one resolver answers for both (and a new library is one row here). Keyed by the
|
|
17
|
+
// UNION rather than by `string`: a member added to `LibrarySourceEntity` must fail to compile
|
|
18
|
+
// here rather than resolve to nothing, which the stored-half check would otherwise be entitled
|
|
19
|
+
// to read as "no such row" and admit.
|
|
20
|
+
const librarySourceRepos = {
|
|
21
|
+
fragmentSource: registry.fragmentSourceRepository,
|
|
22
|
+
foundationalServiceSource: registry.foundationalServiceSourceRepository,
|
|
23
|
+
};
|
|
24
|
+
const resolveAccountId = (workspaceId) => workspaceRepository?.accountOf?.(workspaceId) ??
|
|
25
|
+
Promise.resolve(undefined);
|
|
26
|
+
// The BATCHED account read every list-shaped rule binds through. A registry that does not wire
|
|
27
|
+
// it answers an empty map, which fails every id closed rather than admitting one: the same
|
|
28
|
+
// disposition an unresolvable `accountOf` already has.
|
|
29
|
+
const readAccountIds = async (workspaceIds) => (await workspaceRepository?.accountIdsOf?.(workspaceIds)) ?? {};
|
|
30
|
+
// The `block`/`serviceList`/`service` scope checks resolve the owning account by reading the
|
|
31
|
+
// entity (`blockRepository.findById` / `serviceRepository.listByIds`). When the request ALSO
|
|
32
|
+
// dispatches that same read, memoise it per request so the resolver's read is reused instead
|
|
33
|
+
// of issuing a second identical query. `serviceRepository.get(id)` is the single-service form:
|
|
34
|
+
// its `service` scope resolves via `listByIds([id])`, so the dispatched `get` is routed through
|
|
35
|
+
// the same memo (a single-id `listByIds` yields the same row) rather than a second point read.
|
|
36
|
+
// (For every other `serviceList` method the dispatched method differs from the resolver's read,
|
|
37
|
+
// so there is nothing to dedupe.)
|
|
38
|
+
const memoizeRead = (fn) => {
|
|
39
|
+
const cache = new Map();
|
|
40
|
+
return (...args) => {
|
|
41
|
+
const key = JSON.stringify(args);
|
|
42
|
+
const hit = cache.get(key);
|
|
43
|
+
if (hit)
|
|
44
|
+
return hit;
|
|
45
|
+
const pending = Promise.resolve(fn(...args));
|
|
46
|
+
cache.set(key, pending);
|
|
47
|
+
return pending;
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
const installationRepository = registry.githubInstallationRepository;
|
|
51
|
+
const blockFindById = memoizeRead((blockId) => blockRepository?.findById?.(blockId));
|
|
52
|
+
// One memo per installation id, shared by the resolver and (via the override below) the
|
|
53
|
+
// dispatched point read, exactly as the source tables do. Built only when the repository is
|
|
54
|
+
// wired, so an unwired one answers `unreadable` rather than the absence an id-keyed upsert
|
|
55
|
+
// would be entitled to read as a create.
|
|
56
|
+
const installationGet = typeof installationRepository?.getByInstallationId === 'function'
|
|
57
|
+
? memoizeRead((id) => installationRepository.getByInstallationId(id))
|
|
58
|
+
: undefined;
|
|
59
|
+
const blockFindByIds = memoizeRead((ids) => blockRepository?.findByIds?.(ids));
|
|
60
|
+
// One memo per requested SET of workspace ids, shared by the resolver and (via the override
|
|
61
|
+
// below) the dispatched `accountIdsOf`, exactly as the other self-keyed reads do.
|
|
62
|
+
const accountIdsOf = memoizeRead((ids) => readAccountIds(ids));
|
|
63
|
+
const installationListByIds = memoizeRead((ids) => installationRepository?.listByInstallationIds?.(ids));
|
|
64
|
+
const serviceListByIds = memoizeRead((ids) => serviceRepository?.listByIds?.(ids));
|
|
65
|
+
const skillSourceGet = memoizeRead((id) => skillSourceRepository?.get?.(id));
|
|
66
|
+
// One memo per source TABLE, keyed by entity: the resolver and the dispatched `get` of the same
|
|
67
|
+
// library then share a read, exactly as `skillSourceGet` does for skills. A table whose `get`
|
|
68
|
+
// this deployment does not wire gets NO reader rather than one answering `undefined`, so the
|
|
69
|
+
// resolver below can report `unreadable` instead of the absence that would admit an upsert.
|
|
70
|
+
const librarySourceReader = (entity) => {
|
|
71
|
+
const repo = librarySourceRepos[entity];
|
|
72
|
+
if (typeof repo?.get !== 'function')
|
|
73
|
+
return undefined;
|
|
74
|
+
// Called through the repository so a class-implemented `get` keeps its receiver.
|
|
75
|
+
return memoizeRead((id) => repo.get(id));
|
|
76
|
+
};
|
|
77
|
+
const librarySourceGets = {
|
|
78
|
+
fragmentSource: librarySourceReader('fragmentSource'),
|
|
79
|
+
foundationalServiceSource: librarySourceReader('foundationalServiceSource'),
|
|
80
|
+
};
|
|
81
|
+
// For the self-keyed reads, point the dispatcher's own call at the memo so it hits the
|
|
82
|
+
// resolver's already-resolved result. Only the one dispatched method is overridden; the rest
|
|
83
|
+
// of the registry is untouched. Keyed `repo.method` so a new self-keyed read is one row here
|
|
84
|
+
// rather than another rung on a ternary chain.
|
|
85
|
+
const serviceGetViaMemo = async (id) => (await serviceListByIds([id]))?.[0] ?? null;
|
|
86
|
+
const memoOverrides = {
|
|
87
|
+
'blockRepository.findById': { blockRepository: { findById: blockFindById } },
|
|
88
|
+
'blockRepository.findByIds': { blockRepository: { findByIds: blockFindByIds } },
|
|
89
|
+
'serviceRepository.listByIds': { serviceRepository: { listByIds: serviceListByIds } },
|
|
90
|
+
'serviceRepository.get': { serviceRepository: { get: serviceGetViaMemo } },
|
|
91
|
+
// The two batched self-keyed reads: the `workspaceList` rule resolves the accounts of exactly
|
|
92
|
+
// the ids `accountIdsOf` is being asked for, and `installationList` resolves the owners of
|
|
93
|
+
// exactly the ids `listByInstallationIds` is being asked for.
|
|
94
|
+
'workspaceRepository.accountIdsOf': { workspaceRepository: { accountIdsOf } },
|
|
95
|
+
'githubInstallationRepository.listByInstallationIds': {
|
|
96
|
+
githubInstallationRepository: { listByInstallationIds: installationListByIds },
|
|
97
|
+
},
|
|
98
|
+
// The `skillSource` scope resolves a source's account by reading the source; when the
|
|
99
|
+
// dispatched call IS that read (the sync service's `get`), reuse the resolver's result.
|
|
100
|
+
'skillSourceRepository.get': { skillSourceRepository: { get: skillSourceGet } },
|
|
101
|
+
// The same self-keyed read for an installation: the `installation` rule resolves the row to
|
|
102
|
+
// scope the call, and the dispatched `getByInstallationId` IS that row.
|
|
103
|
+
...(installationGet
|
|
104
|
+
? {
|
|
105
|
+
'githubInstallationRepository.getByInstallationId': {
|
|
106
|
+
githubInstallationRepository: { getByInstallationId: installationGet },
|
|
107
|
+
},
|
|
108
|
+
}
|
|
109
|
+
: {}),
|
|
110
|
+
// The same self-keyed read for the two owner-pair libraries' source tables. Contributed only
|
|
111
|
+
// where a reader exists: a table whose `get` is unwired has nothing to memoise, and the
|
|
112
|
+
// dispatcher's own wiring check answers that call with `... is not wired` regardless.
|
|
113
|
+
...(librarySourceGets.fragmentSource
|
|
114
|
+
? {
|
|
115
|
+
'fragmentSourceRepository.get': {
|
|
116
|
+
fragmentSourceRepository: { get: librarySourceGets.fragmentSource },
|
|
117
|
+
},
|
|
118
|
+
}
|
|
119
|
+
: {}),
|
|
120
|
+
...(librarySourceGets.foundationalServiceSource
|
|
121
|
+
? {
|
|
122
|
+
'foundationalServiceSourceRepository.get': {
|
|
123
|
+
foundationalServiceSourceRepository: {
|
|
124
|
+
get: librarySourceGets.foundationalServiceSource,
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
}
|
|
128
|
+
: {}),
|
|
129
|
+
};
|
|
130
|
+
// Substitute ONLY for a method the real registry actually wires. `memoizeRead` returns a
|
|
131
|
+
// function unconditionally — it closes over an optional-chained call — so overriding an ABSENT
|
|
132
|
+
// repository would satisfy the dispatcher's `typeof fn !== 'function'` wiring check and answer a
|
|
133
|
+
// misconfigured deployment with a scope 404 (or a bare null) instead of the `... is not wired`
|
|
134
|
+
// that names what to fix. The key is only ever consulted after `Object.hasOwn`, so an
|
|
135
|
+
// attacker-controlled `request.repo` cannot reach an inherited member through the lookup below.
|
|
136
|
+
const memoKey = `${request.repo}.${request.method}`;
|
|
137
|
+
const override = Object.hasOwn(memoOverrides, memoKey)
|
|
138
|
+
? typeof registry[request.repo]?.[request.method] === 'function'
|
|
139
|
+
? memoOverrides[memoKey]
|
|
140
|
+
: undefined
|
|
141
|
+
: undefined;
|
|
142
|
+
const registryForDispatch = override ? { ...registry, ...override } : registry;
|
|
143
|
+
return {
|
|
144
|
+
registryForDispatch,
|
|
145
|
+
blockRepository,
|
|
146
|
+
installationRepository,
|
|
147
|
+
resolveAccountId,
|
|
148
|
+
accountIdsOf,
|
|
149
|
+
blockFindById,
|
|
150
|
+
blockFindByIds,
|
|
151
|
+
serviceListByIds,
|
|
152
|
+
skillSourceGet,
|
|
153
|
+
librarySourceGets,
|
|
154
|
+
installationGet,
|
|
155
|
+
installationListByIds,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* The per-request SCOPE RESOLUTION half of `POST /internal/persistence`: the entity readers the
|
|
160
|
+
* dispatcher binds a call through (block → workspace → account, service → account, a library
|
|
161
|
+
* source's owner pair, an installation's owner, an account's roster), over the per-request memo
|
|
162
|
+
* {@link buildRequestReaders} builds.
|
|
163
|
+
*
|
|
164
|
+
* Split out of `PersistenceController` when the surface completion pushed the handler past its
|
|
165
|
+
* function-size budget. It is the half that grows: every new entity-keyed scope rule adds a
|
|
166
|
+
* resolver here, while the controller's own job (gate, parse, dispatch, relay) does not change.
|
|
167
|
+
*/
|
|
168
|
+
export function buildDispatchScope(registry, request, scope) {
|
|
169
|
+
const { registryForDispatch, blockRepository, installationRepository, resolveAccountId, accountIdsOf, blockFindById, blockFindByIds, serviceListByIds, skillSourceGet, librarySourceGets, installationGet, installationListByIds, } = buildRequestReaders(registry, request);
|
|
170
|
+
return {
|
|
171
|
+
registry: registryForDispatch,
|
|
172
|
+
scope,
|
|
173
|
+
resolveAccountId,
|
|
174
|
+
resolveAccountIds: async (workspaceIds) => {
|
|
175
|
+
const accounts = (await accountIdsOf(workspaceIds));
|
|
176
|
+
return new Map(Object.entries(accounts));
|
|
177
|
+
},
|
|
178
|
+
// A block is keyed only by its id; resolve its home workspace, then that workspace's account.
|
|
179
|
+
resolveBlockAccountId: async (blockId) => {
|
|
180
|
+
const found = (await blockFindById(blockId));
|
|
181
|
+
const workspaceId = found?.workspaceId;
|
|
182
|
+
return typeof workspaceId === 'string' ? resolveAccountId(workspaceId) : undefined;
|
|
183
|
+
},
|
|
184
|
+
// The batched form, in exactly two reads however long the list: one `findByIds` resolves every
|
|
185
|
+
// block's home workspace, then ONE `accountIdsOf` over the deduped workspaces. A block absent
|
|
186
|
+
// from either read is absent from the map.
|
|
187
|
+
resolveBlockAccountIds: async (blockIds) => {
|
|
188
|
+
const found = (await blockFindByIds(blockIds));
|
|
189
|
+
const entries = found ?? [];
|
|
190
|
+
const accounts = (await accountIdsOf([
|
|
191
|
+
...new Set(entries.map((entry) => entry.workspaceId)),
|
|
192
|
+
]));
|
|
193
|
+
const map = new Map();
|
|
194
|
+
for (const entry of entries) {
|
|
195
|
+
map.set(entry.block.id, Object.hasOwn(accounts, entry.workspaceId) ? accounts[entry.workspaceId] : undefined);
|
|
196
|
+
}
|
|
197
|
+
return map;
|
|
198
|
+
},
|
|
199
|
+
// Services are account-owned; resolve each requested id's `accountId` for the scope check.
|
|
200
|
+
resolveServiceAccountIds: async (serviceIds) => {
|
|
201
|
+
const services = (await serviceListByIds(serviceIds));
|
|
202
|
+
const map = new Map();
|
|
203
|
+
for (const service of services ?? [])
|
|
204
|
+
map.set(service.id, service.accountId);
|
|
205
|
+
return map;
|
|
206
|
+
},
|
|
207
|
+
// Skill sources are account-owned; the sync surface's methods carry only a source id, so
|
|
208
|
+
// resolve the row and project its `accountId` for the scope check. A source that does not
|
|
209
|
+
// exist resolves to undefined, which fails closed (404) exactly like a missing block/service.
|
|
210
|
+
resolveSkillSourceAccountId: async (sourceId) => {
|
|
211
|
+
const source = (await skillSourceGet(sourceId));
|
|
212
|
+
return source?.accountId;
|
|
213
|
+
},
|
|
214
|
+
// The owner-PAIR libraries' equivalent: a fragment / foundational-service source is owned by
|
|
215
|
+
// an `(ownerKind, ownerId)` tier rather than an account, so project the pair and let the rule
|
|
216
|
+
// resolve it the way it resolves a positional owner. A source that does not exist answers
|
|
217
|
+
// `absent`, which the sourceId-keyed rules fail closed on (404) exactly like a missing
|
|
218
|
+
// block/service, and which `ownerFieldUpsert` alone reads as a create.
|
|
219
|
+
resolveLibrarySourceOwner: async (entity, sourceId) => {
|
|
220
|
+
const read = librarySourceGets[entity];
|
|
221
|
+
// No reader for that table: nothing is known about the id, so say so. Answering `absent`
|
|
222
|
+
// here would let an id-keyed upsert through on its DECLARED owner alone.
|
|
223
|
+
if (!read)
|
|
224
|
+
return { status: 'unreadable' };
|
|
225
|
+
const source = (await read(sourceId));
|
|
226
|
+
return source
|
|
227
|
+
? { status: 'found', owner: { ownerKind: source.ownerKind, ownerId: source.ownerId } }
|
|
228
|
+
: { status: 'absent' };
|
|
229
|
+
},
|
|
230
|
+
// A VCS installation binds either an ACCOUNT (a GitHub App installation, shared with every
|
|
231
|
+
// board of that account) or just its connector WORKSPACE (a per-workspace PAT, which stores
|
|
232
|
+
// no account). Resolve the effective owner so both bind the same way, and keep "no such
|
|
233
|
+
// binding" apart from "this deployment cannot read the table": the batched annotation read
|
|
234
|
+
// admits the first and must refuse the second.
|
|
235
|
+
resolveInstallationOwner: async (installationId) => {
|
|
236
|
+
if (!installationGet)
|
|
237
|
+
return { status: 'unreadable' };
|
|
238
|
+
const row = (await installationGet(installationId));
|
|
239
|
+
if (!row)
|
|
240
|
+
return { status: 'absent' };
|
|
241
|
+
if (typeof row.accountId === 'string')
|
|
242
|
+
return { status: 'found', accountId: row.accountId };
|
|
243
|
+
const workspaceId = row.workspaceId;
|
|
244
|
+
return {
|
|
245
|
+
status: 'found',
|
|
246
|
+
accountId: typeof workspaceId === 'string' ? await resolveAccountId(workspaceId) : null,
|
|
247
|
+
};
|
|
248
|
+
},
|
|
249
|
+
// The batched form: one `listByInstallationIds` plus one `accountIdsOf` over the connector
|
|
250
|
+
// workspaces of the PAT bindings that store no account. Ids with no binding are absent from
|
|
251
|
+
// the read, so the rule sees them as `absent` (the admission the annotation read needs) while
|
|
252
|
+
// an UNWIRED repository yields no map at all, which the rule fails closed on.
|
|
253
|
+
resolveInstallationOwners: async (installationIds) => {
|
|
254
|
+
const owners = new Map();
|
|
255
|
+
if (typeof installationRepository?.listByInstallationIds !== 'function') {
|
|
256
|
+
for (const id of installationIds)
|
|
257
|
+
owners.set(id, { status: 'unreadable' });
|
|
258
|
+
return owners;
|
|
259
|
+
}
|
|
260
|
+
const rows = ((await installationListByIds(installationIds)) ?? []);
|
|
261
|
+
const patWorkspaces = rows
|
|
262
|
+
.filter((row) => typeof row.accountId !== 'string' && typeof row.workspaceId === 'string')
|
|
263
|
+
.map((row) => row.workspaceId);
|
|
264
|
+
const accounts = (await accountIdsOf([...new Set(patWorkspaces)]));
|
|
265
|
+
for (const row of rows) {
|
|
266
|
+
if (typeof row.accountId === 'string') {
|
|
267
|
+
owners.set(row.installationId, { status: 'found', accountId: row.accountId });
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
const workspaceId = row.workspaceId;
|
|
271
|
+
owners.set(row.installationId, {
|
|
272
|
+
status: 'found',
|
|
273
|
+
accountId: typeof workspaceId === 'string' && Object.hasOwn(accounts, workspaceId)
|
|
274
|
+
? accounts[workspaceId]
|
|
275
|
+
: null,
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
for (const id of installationIds) {
|
|
279
|
+
if (!owners.has(id))
|
|
280
|
+
owners.set(id, { status: 'absent' });
|
|
281
|
+
}
|
|
282
|
+
return owners;
|
|
283
|
+
},
|
|
284
|
+
// A service's frame block, as the three states `serviceInsert` needs: the row is written
|
|
285
|
+
// BEFORE its block, so `absent` is the ordinary create and only `found` binds.
|
|
286
|
+
resolveFrameBlockOwner: async (frameBlockId) => {
|
|
287
|
+
if (typeof blockRepository?.findById !== 'function')
|
|
288
|
+
return { status: 'unreadable' };
|
|
289
|
+
const found = (await blockFindById(frameBlockId));
|
|
290
|
+
if (!found)
|
|
291
|
+
return { status: 'absent' };
|
|
292
|
+
const workspaceId = found.workspaceId;
|
|
293
|
+
return {
|
|
294
|
+
status: 'found',
|
|
295
|
+
accountId: typeof workspaceId === 'string' ? await resolveAccountId(workspaceId) : null,
|
|
296
|
+
};
|
|
297
|
+
},
|
|
298
|
+
// The member-display scope (`user`/`userList`): a userId is in scope iff a co-member of an
|
|
299
|
+
// in-scope account, so resolve each in-scope account's roster to userIds. Bounded by the
|
|
300
|
+
// token's account scope, not the requested user list.
|
|
301
|
+
resolveAccountMemberIds: async (accountId) => {
|
|
302
|
+
const memberships = (await registry.membershipRepository?.listByAccount?.(accountId));
|
|
303
|
+
return (memberships ?? []).map((m) => m.userId);
|
|
304
|
+
},
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
//# sourceMappingURL=dispatchScope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatchScope.js","sourceRoot":"","sources":["../../../src/modules/persistence/dispatchScope.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { AgentKindCapabilityView, AgentKindSource } from '@cat-factory/agents';
|
|
2
|
+
/**
|
|
3
|
+
* An {@link AgentKindSource} backed by the mothership's `GET /internal/agent-kinds`, presenting the
|
|
4
|
+
* node's machine token.
|
|
5
|
+
*
|
|
6
|
+
* **A failed read THROWS; it never degrades to an empty layer.** "The mothership is unreachable"
|
|
7
|
+
* and "this deployment assigns no capabilities" are the same value and opposite facts, and the
|
|
8
|
+
* second one is indistinguishable, at the agent, from a run that considered the org's playbook and
|
|
9
|
+
* chose not to follow it. That covers every way the read can fail to produce the layer: a transport
|
|
10
|
+
* error, a refusal, a 404 from a mothership older than this node, and a 200 whose payload this
|
|
11
|
+
* client cannot read.
|
|
12
|
+
*
|
|
13
|
+
* Throwing is not the same as failing the run, and the caller decides which it becomes. A skill a
|
|
14
|
+
* kind declared REQUIRED already fails its dispatch when it cannot be resolved, so the throw
|
|
15
|
+
* reaching that path is the existing contract, not a new one; the tool-server side states an
|
|
16
|
+
* unreachable layer to the agent the same way it states any capability it could not honour.
|
|
17
|
+
*
|
|
18
|
+
* There is no cache here, and the reason is NOT the one its three siblings give. Theirs is that a
|
|
19
|
+
* cache already sits in front of them (the per-workspace foundational catalog) and bounds the call
|
|
20
|
+
* volume; this read has nothing in front of it, so it is one round trip on EVERY dispatch. It stays
|
|
21
|
+
* uncached because that is the right size for what it costs: a dispatch starts a container agent
|
|
22
|
+
* that runs for minutes, the payload is the deployment's assignment table (bounded by the kinds a
|
|
23
|
+
* deployment registers capabilities for, not by tenants or runs), and the value has no invalidation
|
|
24
|
+
* path (it changes when the mothership is redeployed), so a TTL'd copy would be the homebrew cache
|
|
25
|
+
* the caching seam exists to keep out while buying a saving nothing can measure. If a caller ever
|
|
26
|
+
* puts this on a path that runs per STEP rather than per dispatch, it earns a real entry on the
|
|
27
|
+
* `AppCaches` seam, not a memo here.
|
|
28
|
+
*/
|
|
29
|
+
export declare class HttpAgentKindSource implements AgentKindSource {
|
|
30
|
+
private readonly opts;
|
|
31
|
+
constructor(opts: {
|
|
32
|
+
baseUrl: string;
|
|
33
|
+
/**
|
|
34
|
+
* The machine token to present, as a fixed string OR a provider read PER REQUEST, the same
|
|
35
|
+
* shape `HttpPersistenceRpcClient` takes, so a token cached after boot by the
|
|
36
|
+
* `/local/mothership/connect` login is picked up without a restart.
|
|
37
|
+
*/
|
|
38
|
+
token: string | (() => string | null);
|
|
39
|
+
fetchImpl?: typeof fetch;
|
|
40
|
+
});
|
|
41
|
+
capabilities(): Promise<AgentKindCapabilityView[]>;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=agentKinds.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agentKinds.d.ts","sourceRoot":"","sources":["../../src/persistence/agentKinds.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAQnF;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,mBAAoB,YAAW,eAAe;IAEvD,OAAO,CAAC,QAAQ,CAAC,IAAI;IADvB,YACmB,IAAI,EAAE;QACrB,OAAO,EAAE,MAAM,CAAA;QACf;;;;WAIG;QACH,KAAK,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,GAAG,IAAI,CAAC,CAAA;QACrC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;KACzB,EACC;IAEE,YAAY,IAAI,OAAO,CAAC,uBAAuB,EAAE,CAAC,CAqCvD;CACF"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { UnavailableError, describeError } from '@cat-factory/kernel';
|
|
2
|
+
// The client half of the mothership-mode agent-kind CAPABILITY read (see
|
|
3
|
+
// `../modules/agentKinds/AgentKindsController.ts` for why only that half of the registry crosses
|
|
4
|
+
// the machine API). The fourth sibling of `foundationalBuiltins.ts`, `binaryGenerators.ts` and
|
|
5
|
+
// `promptFragments.ts`, written to the same contract for the same reason.
|
|
6
|
+
/**
|
|
7
|
+
* An {@link AgentKindSource} backed by the mothership's `GET /internal/agent-kinds`, presenting the
|
|
8
|
+
* node's machine token.
|
|
9
|
+
*
|
|
10
|
+
* **A failed read THROWS; it never degrades to an empty layer.** "The mothership is unreachable"
|
|
11
|
+
* and "this deployment assigns no capabilities" are the same value and opposite facts, and the
|
|
12
|
+
* second one is indistinguishable, at the agent, from a run that considered the org's playbook and
|
|
13
|
+
* chose not to follow it. That covers every way the read can fail to produce the layer: a transport
|
|
14
|
+
* error, a refusal, a 404 from a mothership older than this node, and a 200 whose payload this
|
|
15
|
+
* client cannot read.
|
|
16
|
+
*
|
|
17
|
+
* Throwing is not the same as failing the run, and the caller decides which it becomes. A skill a
|
|
18
|
+
* kind declared REQUIRED already fails its dispatch when it cannot be resolved, so the throw
|
|
19
|
+
* reaching that path is the existing contract, not a new one; the tool-server side states an
|
|
20
|
+
* unreachable layer to the agent the same way it states any capability it could not honour.
|
|
21
|
+
*
|
|
22
|
+
* There is no cache here, and the reason is NOT the one its three siblings give. Theirs is that a
|
|
23
|
+
* cache already sits in front of them (the per-workspace foundational catalog) and bounds the call
|
|
24
|
+
* volume; this read has nothing in front of it, so it is one round trip on EVERY dispatch. It stays
|
|
25
|
+
* uncached because that is the right size for what it costs: a dispatch starts a container agent
|
|
26
|
+
* that runs for minutes, the payload is the deployment's assignment table (bounded by the kinds a
|
|
27
|
+
* deployment registers capabilities for, not by tenants or runs), and the value has no invalidation
|
|
28
|
+
* path (it changes when the mothership is redeployed), so a TTL'd copy would be the homebrew cache
|
|
29
|
+
* the caching seam exists to keep out while buying a saving nothing can measure. If a caller ever
|
|
30
|
+
* puts this on a path that runs per STEP rather than per dispatch, it earns a real entry on the
|
|
31
|
+
* `AppCaches` seam, not a memo here.
|
|
32
|
+
*/
|
|
33
|
+
export class HttpAgentKindSource {
|
|
34
|
+
opts;
|
|
35
|
+
constructor(opts) {
|
|
36
|
+
this.opts = opts;
|
|
37
|
+
}
|
|
38
|
+
async capabilities() {
|
|
39
|
+
const fetchImpl = this.opts.fetchImpl ?? fetch;
|
|
40
|
+
const token = typeof this.opts.token === 'function' ? this.opts.token() : this.opts.token;
|
|
41
|
+
const url = `${this.opts.baseUrl.replace(/\/$/, '')}/internal/agent-kinds`;
|
|
42
|
+
let res;
|
|
43
|
+
try {
|
|
44
|
+
res = await fetchImpl(url, { headers: { authorization: `Bearer ${token ?? ''}` } });
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
throw new UnavailableError('The agent-kind capabilities could not be read from the mothership', 'agent_kinds_unreachable',
|
|
48
|
+
// Scrubbed through `redactSecrets`, because a fetch failure routinely echoes the request
|
|
49
|
+
// URL, which here carries the mothership's address.
|
|
50
|
+
describeError(error));
|
|
51
|
+
}
|
|
52
|
+
if (!res.ok) {
|
|
53
|
+
// Includes the case that matters most: a mothership OLDER than this node, which answers 404
|
|
54
|
+
// for a route it does not serve. Reading that as "no assigned capabilities" is precisely the
|
|
55
|
+
// silent-empty-layer failure this class refuses to produce.
|
|
56
|
+
throw new UnavailableError('The mothership refused the agent-kind capability read', 'agent_kinds_unreachable', { status: res.status });
|
|
57
|
+
}
|
|
58
|
+
const body = (await res.json().catch(() => null));
|
|
59
|
+
// Shape-checked rather than cast, for the same reason every other failure here throws: a reply
|
|
60
|
+
// this code cannot read is a reply whose capability layer is unknown, and the one disposition
|
|
61
|
+
// that must never be reachable is answering an unknown layer with an empty one. An empty layer
|
|
62
|
+
// is spelled `[]`, which no honest server omits.
|
|
63
|
+
if (!body || !Array.isArray(body.kinds))
|
|
64
|
+
throw unreadable('kinds');
|
|
65
|
+
// The ELEMENTS too, and shallowly enough to matter: an entry whose `kind` is not a string can
|
|
66
|
+
// be matched against no dispatch, so a reply carrying one is a reply whose layer this node
|
|
67
|
+
// cannot apply — the very thing this class promises never to answer quietly.
|
|
68
|
+
if (!body.kinds.every(isCapabilityView))
|
|
69
|
+
throw unreadable('kinds[]');
|
|
70
|
+
return body.kinds;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/** The shape one entry must have for a dispatch to be able to apply it. */
|
|
74
|
+
function isCapabilityView(entry) {
|
|
75
|
+
if (!entry || typeof entry !== 'object')
|
|
76
|
+
return false;
|
|
77
|
+
const { kind, skills, toolServers } = entry;
|
|
78
|
+
if (typeof kind !== 'string')
|
|
79
|
+
return false;
|
|
80
|
+
const skillHalves = skills;
|
|
81
|
+
if (!skillHalves ||
|
|
82
|
+
!Array.isArray(skillHalves.bundled) ||
|
|
83
|
+
!Array.isArray(skillHalves.catalog) ||
|
|
84
|
+
!Array.isArray(skillHalves.unknown)) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
const tools = toolServers;
|
|
88
|
+
return Boolean(tools && Array.isArray(tools.servers) && Array.isArray(tools.unknown));
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* The unreadable-reply refusal. One helper rather than two literals because they are one FACT (the
|
|
92
|
+
* mothership answered with something this node cannot resolve a capability layer from), and the
|
|
93
|
+
* whole point of this class is that every route to "we do not know the org's capabilities" ends at
|
|
94
|
+
* a throw. `field` names which part failed.
|
|
95
|
+
*/
|
|
96
|
+
function unreadable(field) {
|
|
97
|
+
return new UnavailableError('The mothership returned an unreadable agent-kind capability layer', 'agent_kinds_unreachable', { field });
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=agentKinds.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agentKinds.js","sourceRoot":"","sources":["../../src/persistence/agentKinds.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { PersistenceMethodTable } from './rpc.js';
|
|
2
|
+
/** The content libraries' remote surface. See `rpc-allowlist.ts` for the table's contract. */
|
|
3
|
+
export declare const LIBRARY_PERSISTENCE_METHODS: PersistenceMethodTable;
|
|
4
|
+
//# sourceMappingURL=rpc-allowlist-libraries.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpc-allowlist-libraries.d.ts","sourceRoot":"","sources":["../../src/persistence/rpc-allowlist-libraries.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAA;AAatD,8FAA8F;AAC9F,eAAO,MAAM,2BAA2B,EAAE,sBAoMzC,CAAA"}
|