@opengeni/core 0.24.1 → 0.28.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/canonical-human-identities.d.ts +12 -0
- package/dist/canonical-human-identities.js +23 -0
- package/dist/canonical-human-identities.js.map +1 -0
- package/dist/chunk-IBOEYG6N.js +34 -0
- package/dist/chunk-IBOEYG6N.js.map +1 -0
- package/dist/dependencies.d.ts +5 -1
- package/dist/domain/conversation-integrations.d.ts +225 -0
- package/dist/domain/fiken.d.ts +35 -0
- package/dist/domain/sessions.d.ts +11 -3
- package/dist/domain/video-generation-capabilities.d.ts +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1667 -664
- package/dist/index.js.map +1 -1
- package/dist/managed-session.d.ts +5 -1
- package/dist/sandbox/fleet.d.ts +8 -5
- package/dist/session-authorization.d.ts +3 -1
- package/dist/transcription.d.ts +5 -0
- package/package.json +14 -10
- package/src/access/index.ts +14 -2
- package/src/canonical-human-identities.ts +27 -0
- package/src/dependencies.ts +5 -1
- package/src/domain/capabilities.ts +220 -283
- package/src/domain/conversation-integrations.ts +1238 -0
- package/src/domain/fiken.ts +88 -0
- package/src/domain/insights.ts +27 -17
- package/src/domain/scheduled-tasks.ts +16 -0
- package/src/domain/sessions.ts +122 -18
- package/src/domain/video-generation-capabilities.ts +37 -2
- package/src/index.ts +2 -0
- package/src/managed-session.ts +19 -2
- package/src/sandbox/fleet.ts +72 -66
- package/src/session-authorization.ts +187 -55
- package/src/transcription.ts +5 -0
|
@@ -5,10 +5,13 @@ import { environmentsEncryptionKeyBytes, type Settings } from "@opengeni/config"
|
|
|
5
5
|
import {
|
|
6
6
|
CapabilityCatalogItem,
|
|
7
7
|
capabilityCatalogItemIsTrustedForExposure,
|
|
8
|
+
FIKEN_PROVIDER_DOMAIN,
|
|
9
|
+
FIRST_PARTY_MCP_TOOL_NAMES,
|
|
8
10
|
type AccessGrant,
|
|
9
11
|
type CapabilityAction,
|
|
10
12
|
type CapabilityCatalogResponse,
|
|
11
13
|
type CapabilityInstallation,
|
|
14
|
+
type ConnectionMetadata,
|
|
12
15
|
type CreateCapabilityCatalogItemRequest,
|
|
13
16
|
type EnableCapabilityRequest,
|
|
14
17
|
type McpServerConnectionRef,
|
|
@@ -26,45 +29,33 @@ import {
|
|
|
26
29
|
decryptedCapabilityHeaders,
|
|
27
30
|
disableCapabilityInstallation,
|
|
28
31
|
enableCapabilityInstallation,
|
|
29
|
-
enablePackInstallation,
|
|
30
32
|
encryptVariableSetValue,
|
|
31
33
|
getCapabilityCatalogItem,
|
|
32
34
|
getCapabilityInstallation,
|
|
33
35
|
getConnectionMetadata,
|
|
34
36
|
getCodexAppsCredentialAuthorizationForRun,
|
|
35
37
|
getWorkspaceGrant,
|
|
36
|
-
getPackInstallation,
|
|
37
38
|
getStoredCapabilityHeaderCiphertext,
|
|
38
|
-
getVariableSet,
|
|
39
39
|
listCapabilityCatalogItems,
|
|
40
40
|
listCapabilityInstallations,
|
|
41
41
|
listConnectionsMetadata,
|
|
42
42
|
listEnabledMcpCapabilityServers,
|
|
43
43
|
listInstalledApiIntegrations,
|
|
44
|
+
listInstalledSkills,
|
|
44
45
|
listPackInstallations,
|
|
45
46
|
listSocialConnections,
|
|
46
47
|
mcpServerIdForCapability,
|
|
47
|
-
updatePackInstallationStatus,
|
|
48
48
|
upsertCapabilityCatalogItem,
|
|
49
49
|
type Database,
|
|
50
50
|
type ApiIntegrationRuntime,
|
|
51
51
|
type EnabledMcpCapabilityServer,
|
|
52
|
+
type InstalledSkillSummary,
|
|
52
53
|
} from "@opengeni/db";
|
|
53
54
|
import { HTTPException } from "hono/http-exception";
|
|
54
55
|
import { hasPermission } from "../access";
|
|
55
|
-
import {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
type SkillLibraryEntry,
|
|
59
|
-
} from "@opengeni/runtime/skill-library";
|
|
60
|
-
import { validateVariableSetAttachment } from "./environments";
|
|
61
|
-
import {
|
|
62
|
-
assertPackSandboxImageCompatible,
|
|
63
|
-
capabilityPackRequiresInstallationPlan,
|
|
64
|
-
listCapabilityPacks,
|
|
65
|
-
listWorkspaceCapabilityPacks,
|
|
66
|
-
resolveCapabilityPack,
|
|
67
|
-
} from "./packs";
|
|
56
|
+
import { isFikenConnection, preferredFikenConnection } from "./fiken";
|
|
57
|
+
import { listSkillLibraryEntries, type SkillLibraryEntry } from "@opengeni/runtime/skill-library";
|
|
58
|
+
import { listCapabilityPacks, listWorkspaceCapabilityPacks } from "./packs";
|
|
68
59
|
|
|
69
60
|
const officialMcpRegistryUrl = "https://registry.modelcontextprotocol.io";
|
|
70
61
|
const firstPartyMcpServerIds = new Set(["opengeni", "files", "docs"]);
|
|
@@ -89,7 +80,9 @@ export async function buildCapabilityCatalog(input: {
|
|
|
89
80
|
packInstallations,
|
|
90
81
|
workspacePacks,
|
|
91
82
|
socialConnections,
|
|
83
|
+
workspaceConnections,
|
|
92
84
|
curatedLibrarySkills,
|
|
85
|
+
installedSkills,
|
|
93
86
|
codexAppsCredentialId,
|
|
94
87
|
] = await Promise.all([
|
|
95
88
|
listCapabilityCatalogItems(input.db, input.workspaceId),
|
|
@@ -97,13 +90,23 @@ export async function buildCapabilityCatalog(input: {
|
|
|
97
90
|
listPackInstallations(input.db, input.workspaceId),
|
|
98
91
|
listWorkspaceCapabilityPacks(input.db, input.workspaceId),
|
|
99
92
|
listSocialConnections(input.db, input.workspaceId, 500, input.subjectId),
|
|
93
|
+
listConnectionsMetadata(input.db, input.workspaceId, null),
|
|
100
94
|
discoverCuratedSkillLibraryItems(),
|
|
95
|
+
listInstalledSkills(input.db, input.workspaceId),
|
|
101
96
|
input.settings.codexConnectedAppsEnabled
|
|
102
97
|
? resolveCodexAppsCredentialIdForRun(input.db, input.workspaceId)
|
|
103
98
|
: Promise.resolve(null),
|
|
104
99
|
]);
|
|
100
|
+
const catalogInstallations = capabilityInstallations.filter(
|
|
101
|
+
(installation) => installation.kind === "mcp",
|
|
102
|
+
);
|
|
105
103
|
const capabilityInstallationById = new Map(
|
|
106
|
-
|
|
104
|
+
catalogInstallations.map((installation) => [installation.capabilityId, installation]),
|
|
105
|
+
);
|
|
106
|
+
const installedSkillById = new Map(
|
|
107
|
+
installedSkills
|
|
108
|
+
.filter((skill) => skill.owners.some((owner) => owner.kind === "direct"))
|
|
109
|
+
.map((skill) => [skill.capabilityId, skill]),
|
|
107
110
|
);
|
|
108
111
|
const activePackIds = new Set(
|
|
109
112
|
packInstallations
|
|
@@ -117,69 +120,42 @@ export async function buildCapabilityCatalog(input: {
|
|
|
117
120
|
),
|
|
118
121
|
...configuredMcpCatalogItems(input.settings),
|
|
119
122
|
...providerIntegrationCatalogItems(socialConnections),
|
|
123
|
+
fikenCatalogItem(workspaceConnections.filter(isFikenConnection)),
|
|
120
124
|
...curatedLibrarySkills,
|
|
125
|
+
...installedSkills
|
|
126
|
+
.filter(
|
|
127
|
+
(skill) =>
|
|
128
|
+
skill.source !== "library" && skill.owners.some((owner) => owner.kind === "direct"),
|
|
129
|
+
)
|
|
130
|
+
.map(installedSkillCatalogItem),
|
|
121
131
|
];
|
|
122
132
|
const codexApps = input.settings.codexConnectedAppsEnabled
|
|
123
133
|
? codexAppsCatalogItem(codexAppsCredentialId !== null)
|
|
124
134
|
: null;
|
|
125
135
|
const items = dedupeCatalogItems([
|
|
126
136
|
...builtIns,
|
|
127
|
-
...persistedItems.filter(
|
|
137
|
+
...persistedItems.filter(
|
|
138
|
+
(item) =>
|
|
139
|
+
item.kind !== "skill" &&
|
|
140
|
+
item.kind !== "api" &&
|
|
141
|
+
item.kind !== "plugin" &&
|
|
142
|
+
!isReservedCodexAppsCatalogItem(item),
|
|
143
|
+
),
|
|
128
144
|
// Keep the reserved, server-derived item authoritative over any stale
|
|
129
145
|
// legacy catalog row with the same id.
|
|
130
146
|
...(codexApps ? [codexApps] : []),
|
|
131
147
|
])
|
|
132
148
|
.map((item) => {
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
activePackIds,
|
|
138
|
-
);
|
|
149
|
+
const projected =
|
|
150
|
+
item.kind === "skill"
|
|
151
|
+
? applyInstalledSkillEnablement(item, installedSkillById.get(item.id))
|
|
152
|
+
: applyCapabilityEnablement(item, capabilityInstallationById.get(item.id), activePackIds);
|
|
139
153
|
return applyCapabilityLifecycle(projected);
|
|
140
154
|
})
|
|
141
155
|
.sort(compareCatalogItems);
|
|
142
156
|
return {
|
|
143
157
|
items,
|
|
144
|
-
installations:
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
function applyInstalledArtifactRuntime(item: CapabilityCatalogItem): CapabilityCatalogItem {
|
|
149
|
-
if (
|
|
150
|
-
item.kind === "api" &&
|
|
151
|
-
item.metadata.platformVersion === 2 &&
|
|
152
|
-
typeof item.metadata.pluginVersionId === "string" &&
|
|
153
|
-
typeof item.metadata.apiFacetId === "string" &&
|
|
154
|
-
typeof item.metadata.revisionId === "string" &&
|
|
155
|
-
typeof item.metadata.serverId === "string"
|
|
156
|
-
) {
|
|
157
|
-
return {
|
|
158
|
-
...item,
|
|
159
|
-
runtime: {
|
|
160
|
-
available: true,
|
|
161
|
-
mcpServerId: item.metadata.serverId,
|
|
162
|
-
transport: "local-adapter",
|
|
163
|
-
notes: "Available through an immutable workspace API Integration revision.",
|
|
164
|
-
},
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
if (
|
|
168
|
-
item.kind !== "skill" ||
|
|
169
|
-
item.metadata.platformVersion !== 2 ||
|
|
170
|
-
typeof item.metadata.pluginVersionId !== "string" ||
|
|
171
|
-
typeof item.metadata.facetId !== "string" ||
|
|
172
|
-
typeof item.metadata.sourceCommit !== "string" ||
|
|
173
|
-
typeof item.metadata.contentSha256 !== "string"
|
|
174
|
-
) {
|
|
175
|
-
return item;
|
|
176
|
-
}
|
|
177
|
-
return {
|
|
178
|
-
...item,
|
|
179
|
-
runtime: {
|
|
180
|
-
available: true,
|
|
181
|
-
notes: "Installed from an immutable workspace Skill artifact.",
|
|
182
|
-
},
|
|
158
|
+
installations: catalogInstallations,
|
|
183
159
|
};
|
|
184
160
|
}
|
|
185
161
|
|
|
@@ -197,7 +173,17 @@ export async function createCatalogItem(input: {
|
|
|
197
173
|
}
|
|
198
174
|
if (id.startsWith("skill:")) {
|
|
199
175
|
throw new HTTPException(422, {
|
|
200
|
-
message: "
|
|
176
|
+
message: "Skills are installed through the Skill library or source import flow",
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
if (id.startsWith("api:")) {
|
|
180
|
+
throw new HTTPException(422, {
|
|
181
|
+
message: "API Integrations are installed from typed Integration Definitions",
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
if (id.startsWith("plugin:")) {
|
|
185
|
+
throw new HTTPException(422, {
|
|
186
|
+
message: "Plugins are installed through the Plugin Package flow",
|
|
201
187
|
});
|
|
202
188
|
}
|
|
203
189
|
if (
|
|
@@ -259,6 +245,26 @@ export async function enableCapability(input: {
|
|
|
259
245
|
input.settings,
|
|
260
246
|
input.capabilityId,
|
|
261
247
|
);
|
|
248
|
+
if (item.kind === "skill") {
|
|
249
|
+
throw new HTTPException(409, {
|
|
250
|
+
message: "Install Skills through the Skill library or source import flow",
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
if (item.kind === "api") {
|
|
254
|
+
throw new HTTPException(409, {
|
|
255
|
+
message: "Install API Integrations through the Integration Definitions flow",
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
if (item.kind === "plugin") {
|
|
259
|
+
throw new HTTPException(409, {
|
|
260
|
+
message: "Install Plugins through the Plugin Package flow",
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
if (item.kind === "pack") {
|
|
264
|
+
throw new HTTPException(409, {
|
|
265
|
+
message: "Install Packs through the Pack installation preview flow",
|
|
266
|
+
});
|
|
267
|
+
}
|
|
262
268
|
if (item.kind === "mcp" && !item.runtime.available) {
|
|
263
269
|
throw new HTTPException(422, {
|
|
264
270
|
message: "MCP capabilities need a remote streamable HTTP endpoint before they can be enabled",
|
|
@@ -273,44 +279,6 @@ export async function enableCapability(input: {
|
|
|
273
279
|
delete installationConfig.headersEncrypted;
|
|
274
280
|
delete installationConfig.headerNames;
|
|
275
281
|
delete installationConfig.connectionRef;
|
|
276
|
-
if (item.kind === "skill" && item.source === "library") {
|
|
277
|
-
const libraryId = stringMetadata(item.metadata.libraryId);
|
|
278
|
-
const catalogVersion = stringMetadata(item.metadata.version);
|
|
279
|
-
if (!libraryId || !catalogVersion) {
|
|
280
|
-
throw new HTTPException(422, {
|
|
281
|
-
message: `skill library metadata is incomplete for ${item.id}`,
|
|
282
|
-
});
|
|
283
|
-
}
|
|
284
|
-
const requestedVersion = input.payload.config.version;
|
|
285
|
-
if (requestedVersion !== undefined && typeof requestedVersion !== "string") {
|
|
286
|
-
throw new HTTPException(422, {
|
|
287
|
-
message: "skill activation config.version must be a string",
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
|
-
const normalizedVersion = requestedVersion?.trim() || catalogVersion;
|
|
291
|
-
if (normalizedVersion !== catalogVersion) {
|
|
292
|
-
throw new HTTPException(422, {
|
|
293
|
-
message: `skill ${libraryId} only supports immutable version ${catalogVersion}`,
|
|
294
|
-
});
|
|
295
|
-
}
|
|
296
|
-
const entry = getSkillLibraryEntry(libraryId, normalizedVersion);
|
|
297
|
-
if (!entry) {
|
|
298
|
-
throw new HTTPException(422, {
|
|
299
|
-
message: `skill library entry is unavailable: ${libraryId}@${normalizedVersion}`,
|
|
300
|
-
});
|
|
301
|
-
}
|
|
302
|
-
// Skill activation has a deliberately narrow config surface. In
|
|
303
|
-
// particular, no variable-set, connection, credential-header, MCP, or
|
|
304
|
-
// provider-routing input is persisted or consulted for a library skill.
|
|
305
|
-
installationConfig = { version: entry.version };
|
|
306
|
-
installationMetadata = {
|
|
307
|
-
libraryId: entry.id,
|
|
308
|
-
libraryVersion: entry.version,
|
|
309
|
-
contentSha256: entry.contentSha256,
|
|
310
|
-
sourceCommit: entry.sourceCommit,
|
|
311
|
-
provenance: entry.provenance,
|
|
312
|
-
};
|
|
313
|
-
}
|
|
314
282
|
if (item.kind === "mcp") {
|
|
315
283
|
const headers = await resolveMcpCredentialHeaders(input, item);
|
|
316
284
|
const connectionRef = input.payload.connectionRef
|
|
@@ -333,87 +301,6 @@ export async function enableCapability(input: {
|
|
|
333
301
|
);
|
|
334
302
|
}
|
|
335
303
|
}
|
|
336
|
-
if (item.kind === "pack") {
|
|
337
|
-
const packId = packIdFromCapabilityId(item.id);
|
|
338
|
-
const pack = await resolveCapabilityPack(input.db, input.workspaceId, packId);
|
|
339
|
-
if (!pack) {
|
|
340
|
-
throw new HTTPException(404, { message: "pack not found" });
|
|
341
|
-
}
|
|
342
|
-
if (capabilityPackRequiresInstallationPlan(pack)) {
|
|
343
|
-
throw new HTTPException(409, {
|
|
344
|
-
message:
|
|
345
|
-
"This Pack uses component or Rig requirements. Preview and install it through the Pack installation flow.",
|
|
346
|
-
});
|
|
347
|
-
}
|
|
348
|
-
await assertPackSandboxImageCompatible(input.db, input.workspaceId, pack);
|
|
349
|
-
// The unified capability-enable path accepts an initial variableSet
|
|
350
|
-
// attachment (`payload.variableSetId`), mirroring POST /packs/:id/enable:
|
|
351
|
-
// a request-supplied id is validated as a fresh attachment, otherwise the
|
|
352
|
-
// attachment stored by a previous enable is preserved and re-validated.
|
|
353
|
-
const existing = await getPackInstallation(input.db, input.workspaceId, packId);
|
|
354
|
-
const storedVariableSetId =
|
|
355
|
-
typeof existing?.metadata.variableSetId === "string"
|
|
356
|
-
? existing.metadata.variableSetId
|
|
357
|
-
: typeof existing?.metadata.environmentId === "string"
|
|
358
|
-
? existing.metadata.environmentId
|
|
359
|
-
: undefined;
|
|
360
|
-
const requestedVariableSetId = input.payload.variableSetId;
|
|
361
|
-
const variableSetId = requestedVariableSetId ?? storedVariableSetId;
|
|
362
|
-
if (pack.variableSet?.required && !variableSetId) {
|
|
363
|
-
throw new HTTPException(422, {
|
|
364
|
-
message: `pack ${packId} requires an variableSet attachment; pass variableSetId`,
|
|
365
|
-
});
|
|
366
|
-
}
|
|
367
|
-
if (variableSetId) {
|
|
368
|
-
if (requestedVariableSetId) {
|
|
369
|
-
// A fresh attachment: validate it like the packs enable endpoint does.
|
|
370
|
-
// The grant holds workspace:admin here, which implies variable-sets:use,
|
|
371
|
-
// so the attachment authorization succeeds for this caller.
|
|
372
|
-
const variableSet = await validateVariableSetAttachment(
|
|
373
|
-
{ settings: input.settings, db: input.db },
|
|
374
|
-
input.grant,
|
|
375
|
-
input.workspaceId,
|
|
376
|
-
requestedVariableSetId,
|
|
377
|
-
);
|
|
378
|
-
const missing = (pack.variableSet?.requiredVariables ?? []).filter(
|
|
379
|
-
(name) => !variableSet.variables.some((variable) => variable.name === name),
|
|
380
|
-
);
|
|
381
|
-
if (missing.length > 0) {
|
|
382
|
-
throw new HTTPException(422, {
|
|
383
|
-
message: `variable set is missing required variable(s): ${missing.join(", ")}`,
|
|
384
|
-
});
|
|
385
|
-
}
|
|
386
|
-
} else {
|
|
387
|
-
// The stored attachment was authorized at pack-enable time, but the
|
|
388
|
-
// variableSet may have been deleted or its variables changed since;
|
|
389
|
-
// re-validate it like the packs enable endpoint does.
|
|
390
|
-
const variableSet = await getVariableSet(input.db, input.workspaceId, variableSetId);
|
|
391
|
-
if (!variableSet) {
|
|
392
|
-
throw new HTTPException(422, {
|
|
393
|
-
message: `the stored variableSet attachment for pack ${packId} no longer exists; re-enable it with variableSetId`,
|
|
394
|
-
});
|
|
395
|
-
}
|
|
396
|
-
const missing = (pack.variableSet?.requiredVariables ?? []).filter(
|
|
397
|
-
(name) => !variableSet.variables.some((variable) => variable.name === name),
|
|
398
|
-
);
|
|
399
|
-
if (missing.length > 0) {
|
|
400
|
-
throw new HTTPException(422, {
|
|
401
|
-
message: `variable set is missing required variable(s): ${missing.join(", ")}`,
|
|
402
|
-
});
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
await enablePackInstallation(input.db, {
|
|
407
|
-
accountId: input.accountId,
|
|
408
|
-
workspaceId: input.workspaceId,
|
|
409
|
-
packId,
|
|
410
|
-
metadata: {
|
|
411
|
-
...input.payload.metadata,
|
|
412
|
-
packVersion: pack.version,
|
|
413
|
-
...(variableSetId ? { variableSetId } : {}),
|
|
414
|
-
},
|
|
415
|
-
});
|
|
416
|
-
}
|
|
417
304
|
return await enableCapabilityInstallation(input.db, {
|
|
418
305
|
accountId: input.accountId,
|
|
419
306
|
workspaceId: input.workspaceId,
|
|
@@ -785,44 +672,33 @@ export async function disableCapability(input: {
|
|
|
785
672
|
input.settings,
|
|
786
673
|
input.capabilityId,
|
|
787
674
|
);
|
|
788
|
-
if (
|
|
675
|
+
if (item.kind === "skill") {
|
|
676
|
+
throw new HTTPException(409, {
|
|
677
|
+
message: "Uninstall Skills through the Skill uninstall preview flow",
|
|
678
|
+
});
|
|
679
|
+
}
|
|
680
|
+
if (item.kind === "api") {
|
|
681
|
+
throw new HTTPException(409, {
|
|
682
|
+
message: "Remove API Integrations through the Integration instance flow",
|
|
683
|
+
});
|
|
684
|
+
}
|
|
685
|
+
if (item.kind === "plugin") {
|
|
686
|
+
throw new HTTPException(409, {
|
|
687
|
+
message: "Remove Plugins through the Plugin Package flow",
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
if (item.kind === "pack") {
|
|
691
|
+
throw new HTTPException(409, {
|
|
692
|
+
message: "Uninstall Packs through the Pack uninstall preview flow",
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
if (item.source === "built_in" || item.source === "configured") {
|
|
789
696
|
throw new HTTPException(409, {
|
|
790
697
|
message:
|
|
791
698
|
"built-in and configured capabilities are always available; remove them from configuration to disable them",
|
|
792
699
|
});
|
|
793
700
|
}
|
|
794
|
-
if (
|
|
795
|
-
const packInstallation = await getPackInstallation(
|
|
796
|
-
input.db,
|
|
797
|
-
input.workspaceId,
|
|
798
|
-
packIdFromCapabilityId(item.id),
|
|
799
|
-
);
|
|
800
|
-
if (
|
|
801
|
-
packInstallation &&
|
|
802
|
-
(packInstallation.manifestDigest !== null || packInstallation.manifestSnapshot !== null)
|
|
803
|
-
) {
|
|
804
|
-
throw new HTTPException(409, {
|
|
805
|
-
message:
|
|
806
|
-
"This Pack owns explicit components. Uninstall it through the Pack uninstall preview flow.",
|
|
807
|
-
});
|
|
808
|
-
}
|
|
809
|
-
await updatePackInstallationStatus(
|
|
810
|
-
input.db,
|
|
811
|
-
input.workspaceId,
|
|
812
|
-
packIdFromCapabilityId(item.id),
|
|
813
|
-
"disabled",
|
|
814
|
-
).catch(() => undefined);
|
|
815
|
-
if (!(await getCapabilityInstallation(input.db, input.workspaceId, item.id))) {
|
|
816
|
-
await enableCapabilityInstallation(input.db, {
|
|
817
|
-
accountId: input.accountId,
|
|
818
|
-
workspaceId: input.workspaceId,
|
|
819
|
-
capabilityId: item.id,
|
|
820
|
-
kind: "pack",
|
|
821
|
-
metadata: {},
|
|
822
|
-
config: {},
|
|
823
|
-
});
|
|
824
|
-
}
|
|
825
|
-
} else if (!(await getCapabilityInstallation(input.db, input.workspaceId, item.id))) {
|
|
701
|
+
if (!(await getCapabilityInstallation(input.db, input.workspaceId, item.id))) {
|
|
826
702
|
throw new HTTPException(409, {
|
|
827
703
|
message: "capability is not currently enabled",
|
|
828
704
|
});
|
|
@@ -1332,6 +1208,51 @@ const SOCIAL_PROVIDER_TOOL_NAMES = {
|
|
|
1332
1208
|
],
|
|
1333
1209
|
} as const;
|
|
1334
1210
|
|
|
1211
|
+
/**
|
|
1212
|
+
* The first-party Fiken accounting connector tile. Enablement is derived from
|
|
1213
|
+
* the workspace-shared verified Fiken connection (either lane), mirroring how
|
|
1214
|
+
* the social provider tiles derive theirs from social connections.
|
|
1215
|
+
*/
|
|
1216
|
+
function fikenCatalogItem(fikenConnections: ConnectionMetadata[]): CapabilityCatalogItem {
|
|
1217
|
+
const fikenConnection = preferredFikenConnection(fikenConnections);
|
|
1218
|
+
const fikenEnabled =
|
|
1219
|
+
fikenConnection?.status === "active" || fikenConnection?.status === "needs_reauth";
|
|
1220
|
+
return CapabilityCatalogItem.parse({
|
|
1221
|
+
id: "api:fiken",
|
|
1222
|
+
kind: "api",
|
|
1223
|
+
source: "built_in",
|
|
1224
|
+
name: "Fiken",
|
|
1225
|
+
description:
|
|
1226
|
+
"Connect Fiken accounting for contacts, products, invoices, invoice drafts, purchases, sales, and bank accounts.",
|
|
1227
|
+
category: "finance",
|
|
1228
|
+
tags: ["api", "fiken", "accounting", "invoicing", "norway"],
|
|
1229
|
+
homepageUrl: "https://fiken.no",
|
|
1230
|
+
authModel: "personal_api_token",
|
|
1231
|
+
providerDomain: FIKEN_PROVIDER_DOMAIN,
|
|
1232
|
+
surfaceType: "first_party_fiken",
|
|
1233
|
+
authKind: "api_key",
|
|
1234
|
+
tools: [{ kind: "mcp", id: "opengeni" }],
|
|
1235
|
+
runtime: {
|
|
1236
|
+
available: true,
|
|
1237
|
+
mcpServerId: "opengeni",
|
|
1238
|
+
notes: "Fiken access is provided through OpenGeni's first-party fiken tools.",
|
|
1239
|
+
},
|
|
1240
|
+
enabled: fikenEnabled,
|
|
1241
|
+
enabledReason: fikenEnabled
|
|
1242
|
+
? fikenConnection.status === "active"
|
|
1243
|
+
? "workspace Fiken connection active"
|
|
1244
|
+
: "workspace Fiken connection needs reconnection"
|
|
1245
|
+
: null,
|
|
1246
|
+
metadata: {
|
|
1247
|
+
connectorMode: "first_party_fiken",
|
|
1248
|
+
ownership: "workspace",
|
|
1249
|
+
// Derived from the contracts catalog so a new fiken_* tool cannot be
|
|
1250
|
+
// registered without also appearing on the capability tile.
|
|
1251
|
+
firstPartyMcpTools: FIRST_PARTY_MCP_TOOL_NAMES.filter((name) => name.startsWith("fiken_")),
|
|
1252
|
+
},
|
|
1253
|
+
});
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1335
1256
|
function providerIntegrationCatalogItems(
|
|
1336
1257
|
socialConnections: SocialConnection[],
|
|
1337
1258
|
): CapabilityCatalogItem[] {
|
|
@@ -1488,6 +1409,53 @@ function curatedSkillCatalogItem(entry: SkillLibraryEntry): CapabilityCatalogIte
|
|
|
1488
1409
|
});
|
|
1489
1410
|
}
|
|
1490
1411
|
|
|
1412
|
+
function installedSkillCatalogItem(skill: InstalledSkillSummary): CapabilityCatalogItem {
|
|
1413
|
+
return CapabilityCatalogItem.parse({
|
|
1414
|
+
id: skill.capabilityId,
|
|
1415
|
+
kind: "skill",
|
|
1416
|
+
source: skill.source === "library" ? "library" : "manual",
|
|
1417
|
+
name: skill.name,
|
|
1418
|
+
description: skill.description,
|
|
1419
|
+
category: skill.category,
|
|
1420
|
+
tags: skill.tags,
|
|
1421
|
+
homepageUrl: skill.repositoryUrl,
|
|
1422
|
+
installUrl: skill.sourceUrl,
|
|
1423
|
+
provenance: skill.provenance,
|
|
1424
|
+
tier: skill.source === "library" ? "verified" : "community",
|
|
1425
|
+
runtime: {
|
|
1426
|
+
available: true,
|
|
1427
|
+
notes: "Available from an immutable Skill installation.",
|
|
1428
|
+
},
|
|
1429
|
+
metadata: {
|
|
1430
|
+
version: skill.version,
|
|
1431
|
+
contentSha256: skill.contentSha256,
|
|
1432
|
+
sourceCommit: skill.sourceCommit,
|
|
1433
|
+
sourcePath: skill.sourcePath,
|
|
1434
|
+
sourceUrl: skill.sourceUrl,
|
|
1435
|
+
repositoryUrl: skill.repositoryUrl,
|
|
1436
|
+
provenance: skill.provenance,
|
|
1437
|
+
license: skill.license,
|
|
1438
|
+
installedSkill: installedSkillMetadata(skill),
|
|
1439
|
+
},
|
|
1440
|
+
});
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
function installedSkillMetadata(skill: InstalledSkillSummary): Record<string, unknown> {
|
|
1444
|
+
return {
|
|
1445
|
+
pluginKey: skill.pluginKey,
|
|
1446
|
+
installationVersion: skill.installationVersion,
|
|
1447
|
+
source: skill.source,
|
|
1448
|
+
version: skill.version,
|
|
1449
|
+
sourceCommit: skill.sourceCommit,
|
|
1450
|
+
contentSha256: skill.contentSha256,
|
|
1451
|
+
fileCount: skill.fileCount,
|
|
1452
|
+
totalBytes: skill.totalBytes,
|
|
1453
|
+
installedAt: skill.installedAt,
|
|
1454
|
+
updatedAt: skill.updatedAt,
|
|
1455
|
+
owners: skill.owners.map((owner) => ({ ...owner })),
|
|
1456
|
+
};
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1491
1459
|
function stringMetadata(value: unknown): string | null {
|
|
1492
1460
|
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
1493
1461
|
}
|
|
@@ -1528,11 +1496,11 @@ export function applyCapabilityEnablement(
|
|
|
1528
1496
|
installation: CapabilityInstallation | undefined,
|
|
1529
1497
|
activePackIds: Set<string>,
|
|
1530
1498
|
): CapabilityCatalogItem {
|
|
1499
|
+
if (item.kind === "skill" || item.kind === "api" || item.kind === "plugin") {
|
|
1500
|
+
return { ...item, enabled: false, enabledReason: null, connectionRef: null };
|
|
1501
|
+
}
|
|
1531
1502
|
if (item.kind === "pack") {
|
|
1532
|
-
|
|
1533
|
-
// pack is built in or registered from a workspace manifest.
|
|
1534
|
-
const enabled =
|
|
1535
|
-
activePackIds.has(packIdFromCapabilityId(item.id)) || installation?.status === "active";
|
|
1503
|
+
const enabled = activePackIds.has(packIdFromCapabilityId(item.id));
|
|
1536
1504
|
return {
|
|
1537
1505
|
...item,
|
|
1538
1506
|
enabled,
|
|
@@ -1545,6 +1513,12 @@ export function applyCapabilityEnablement(
|
|
|
1545
1513
|
// publishes a personal connection UUID or collapses many accounts to one.
|
|
1546
1514
|
return { ...item, connectionRef: null };
|
|
1547
1515
|
}
|
|
1516
|
+
if (item.surfaceType === "first_party_fiken") {
|
|
1517
|
+
// Fiken connector state is derived from the authoritative workspace
|
|
1518
|
+
// connection row while the catalog is built; browseable never means an
|
|
1519
|
+
// account is already connected.
|
|
1520
|
+
return { ...item, connectionRef: null };
|
|
1521
|
+
}
|
|
1548
1522
|
if (item.surfaceType === "codex_apps") {
|
|
1549
1523
|
// Unlike ordinary built-ins, Apps availability is derived from the exact
|
|
1550
1524
|
// active workspace designation above. Do not overwrite it with the
|
|
@@ -1565,37 +1539,8 @@ export function applyCapabilityEnablement(
|
|
|
1565
1539
|
// state explicitly above rather than becoming enabled by taxonomy.
|
|
1566
1540
|
return { ...item, connectionRef: null };
|
|
1567
1541
|
}
|
|
1568
|
-
if (item.source === "library") {
|
|
1569
|
-
const enabled =
|
|
1570
|
-
installation?.status === "active" && skillLibraryInstallationRuntimeReady(item, installation);
|
|
1571
|
-
return {
|
|
1572
|
-
...item,
|
|
1573
|
-
enabled,
|
|
1574
|
-
enabledReason: enabled ? "explicitly selected" : null,
|
|
1575
|
-
connectionRef: null,
|
|
1576
|
-
};
|
|
1577
|
-
}
|
|
1578
1542
|
const activeInstallation = installation?.status === "active";
|
|
1579
1543
|
const enabled = !!activeInstallation && capabilityInstallationRuntimeReady(item, installation);
|
|
1580
|
-
if (item.kind === "api" && item.metadata.platformVersion === 2) {
|
|
1581
|
-
const connectionBound = installation?.metadata.connectionBound === true;
|
|
1582
|
-
const providerDomain = stringMetadata(installation?.metadata.providerDomain);
|
|
1583
|
-
const connectionKind = stringMetadata(installation?.metadata.connectionKind);
|
|
1584
|
-
const connectionOwnership = stringMetadata(installation?.metadata.connectionOwnership);
|
|
1585
|
-
return {
|
|
1586
|
-
...item,
|
|
1587
|
-
enabled,
|
|
1588
|
-
enabledReason: enabled ? "installed immutable Integration revision" : null,
|
|
1589
|
-
connectionRef:
|
|
1590
|
-
enabled && connectionBound && providerDomain && connectionKind
|
|
1591
|
-
? {
|
|
1592
|
-
providerDomain,
|
|
1593
|
-
kind: connectionKind,
|
|
1594
|
-
...(connectionOwnership === "subject" ? { subjectScope: "subject" as const } : {}),
|
|
1595
|
-
}
|
|
1596
|
-
: null,
|
|
1597
|
-
};
|
|
1598
|
-
}
|
|
1599
1544
|
return {
|
|
1600
1545
|
...item,
|
|
1601
1546
|
enabled,
|
|
@@ -1688,40 +1633,32 @@ function applyCapabilityLifecycle(item: CapabilityCatalogItem): CapabilityCatalo
|
|
|
1688
1633
|
};
|
|
1689
1634
|
}
|
|
1690
1635
|
|
|
1691
|
-
function
|
|
1636
|
+
function applyInstalledSkillEnablement(
|
|
1692
1637
|
item: CapabilityCatalogItem,
|
|
1693
|
-
installation:
|
|
1694
|
-
):
|
|
1695
|
-
if (
|
|
1696
|
-
return false;
|
|
1697
|
-
}
|
|
1698
|
-
const
|
|
1699
|
-
const
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
}
|
|
1717
|
-
return (
|
|
1718
|
-
installation.config.version === entry.version &&
|
|
1719
|
-
stringMetadata(installation.metadata.libraryId) === entry.id &&
|
|
1720
|
-
stringMetadata(installation.metadata.libraryVersion) === entry.version &&
|
|
1721
|
-
stringMetadata(installation.metadata.contentSha256) === entry.contentSha256 &&
|
|
1722
|
-
stringMetadata(installation.metadata.sourceCommit) === entry.sourceCommit &&
|
|
1723
|
-
stringMetadata(installation.metadata.provenance) === entry.provenance
|
|
1724
|
-
);
|
|
1638
|
+
installation: InstalledSkillSummary | undefined,
|
|
1639
|
+
): CapabilityCatalogItem {
|
|
1640
|
+
if (!installation) {
|
|
1641
|
+
return { ...item, enabled: false, enabledReason: null, connectionRef: null };
|
|
1642
|
+
}
|
|
1643
|
+
const catalogVersion = stringMetadata(item.metadata.version);
|
|
1644
|
+
const current =
|
|
1645
|
+
catalogVersion === null ||
|
|
1646
|
+
(catalogVersion === installation.version &&
|
|
1647
|
+
stringMetadata(item.metadata.contentSha256) === installation.contentSha256 &&
|
|
1648
|
+
stringMetadata(item.metadata.sourceCommit) === installation.sourceCommit);
|
|
1649
|
+
return {
|
|
1650
|
+
...item,
|
|
1651
|
+
enabled: true,
|
|
1652
|
+
enabledReason: current
|
|
1653
|
+
? "explicitly installed"
|
|
1654
|
+
: `version ${installation.version} installed; update available`,
|
|
1655
|
+
connectionRef: null,
|
|
1656
|
+
metadata: {
|
|
1657
|
+
...item.metadata,
|
|
1658
|
+
installedSkill: installedSkillMetadata(installation),
|
|
1659
|
+
updateAvailable: !current,
|
|
1660
|
+
},
|
|
1661
|
+
};
|
|
1725
1662
|
}
|
|
1726
1663
|
|
|
1727
1664
|
/**
|