@opengeni/db 5.0.1 → 6.0.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/dist/automations.d.ts +0 -2
- package/dist/canonical-human-identities.d.ts +4 -0
- package/dist/canonical-human-identities.js +3 -3
- package/dist/capability-components.d.ts +5 -13
- package/dist/capability-integrations.d.ts +23 -8
- package/dist/capability-reconciliation.d.ts +5 -0
- package/dist/capability-reconciliation.js +21 -0
- package/dist/capability-reconciliation.js.map +1 -0
- package/dist/{chunk-6T2GGYWE.js → chunk-4UJCXBR2.js} +4 -5800
- package/dist/chunk-4UJCXBR2.js.map +1 -0
- package/dist/{chunk-MWMXWHJD.js → chunk-7JCDSMX2.js} +2 -2
- package/dist/chunk-AJA2ZIUW.js +219 -0
- package/dist/chunk-AJA2ZIUW.js.map +1 -0
- package/dist/chunk-CDAT6EKW.js +247 -0
- package/dist/chunk-CDAT6EKW.js.map +1 -0
- package/dist/{chunk-DPONPYJD.js → chunk-CJI6G254.js} +70 -18
- package/dist/chunk-CJI6G254.js.map +1 -0
- package/dist/chunk-G32NVMRJ.js +276 -0
- package/dist/chunk-G32NVMRJ.js.map +1 -0
- package/dist/chunk-GABXCG3N.js +5811 -0
- package/dist/chunk-GABXCG3N.js.map +1 -0
- package/dist/{chunk-ERKVSPDX.js → chunk-LVY33EWL.js} +3 -3
- package/dist/{chunk-45CP2YKY.js → chunk-MAMBI2HR.js} +9 -3
- package/dist/{chunk-45CP2YKY.js.map → chunk-MAMBI2HR.js.map} +1 -1
- package/dist/{chunk-F73UKJY6.js → chunk-MN5PZMEK.js} +91 -108
- package/dist/chunk-MN5PZMEK.js.map +1 -0
- package/dist/chunk-PJI4MUZ7.js +131 -0
- package/dist/chunk-PJI4MUZ7.js.map +1 -0
- package/dist/{chunk-T6BWIGWJ.js → chunk-RIYHP2WU.js} +2 -2
- package/dist/{chunk-7HMK3B45.js → chunk-RL2MUXM3.js} +16 -7
- package/dist/chunk-RL2MUXM3.js.map +1 -0
- package/dist/{chunk-HQDVI2DB.js → chunk-SYKHLPTK.js} +4 -3
- package/dist/{chunk-HQDVI2DB.js.map → chunk-SYKHLPTK.js.map} +1 -1
- package/dist/{chunk-T6YLHJLS.js → chunk-XIXVVBW2.js} +198 -51
- package/dist/chunk-XIXVVBW2.js.map +1 -0
- package/dist/chunk-ZPJ6V2VG.js +156 -0
- package/dist/chunk-ZPJ6V2VG.js.map +1 -0
- package/dist/codex-capacity-recovery.d.ts +12 -0
- package/dist/codex-failure-eligibility.d.ts +9 -0
- package/dist/company-profile-schema.d.ts +4 -2
- package/dist/connect-attempts.d.ts +15 -0
- package/dist/connect-attempts.js +25 -0
- package/dist/connect-attempts.js.map +1 -0
- package/dist/connection-authority.d.ts +7 -63
- package/dist/connection-refresh-lock.d.ts +4 -0
- package/dist/connection-token-resolver.d.ts +8 -43
- package/dist/database-timing.d.ts +10 -0
- package/dist/database.d.ts +4 -0
- package/dist/editable-artifact-durable-export.js +2 -2
- package/dist/editable-artifacts.d.ts +9 -0
- package/dist/editable-artifacts.js +7 -5
- package/dist/index.d.ts +447 -78
- package/dist/index.js +12705 -12872
- package/dist/index.js.map +1 -1
- package/dist/insights-usage-bundle.d.ts +3 -0
- package/dist/integration-bindings.d.ts +1 -1
- package/dist/integration-facets.d.ts +18 -1
- package/dist/knowledge-entries-schema.d.ts +2 -0
- package/dist/knowledge-entries.d.ts +1 -0
- package/dist/knowledge-indexing.d.ts +1 -0
- package/dist/live-session-attempt.d.ts +35 -137
- package/dist/managed-auth-session-sets.js +3 -3
- package/dist/mcp-account-bindings.d.ts +4 -0
- package/dist/mcp-oauth.d.ts +11 -0
- package/dist/mcp-operations.js +2 -2
- package/dist/migrate.js +1 -1
- package/dist/organization-integration-policy.d.ts +51 -0
- package/dist/organization-integration-policy.js +18 -0
- package/dist/organization-integration-policy.js.map +1 -0
- package/dist/organization-usage.d.ts +20 -0
- package/dist/plugin-packages.d.ts +9 -12
- package/dist/pr-review.d.ts +0 -11
- package/dist/preference-registry-schema.d.ts +17 -0
- package/dist/provision-roles.js +1 -1
- package/dist/retained-provider-commands.d.ts +124 -6
- package/dist/retained-provider-commands.js +29 -97
- package/dist/retained-provider-commands.js.map +1 -1
- package/dist/retired-session-create-metadata.d.ts +4 -0
- package/dist/runtime-posture.d.ts +7 -5
- package/dist/schema.d.ts +876 -656
- package/dist/schema.js +5 -7
- package/dist/session-admission-block.d.ts +32 -0
- package/dist/session-attempt-writers.d.ts +4 -0
- package/dist/session-background-commands.js +5 -4
- package/dist/session-command-output.js +8 -126
- package/dist/session-command-output.js.map +1 -1
- package/dist/session-control.d.ts +5 -1
- package/dist/session-event-slices.d.ts +10 -0
- package/dist/session-event-slices.js +8 -222
- package/dist/session-event-slices.js.map +1 -1
- package/dist/session-file-attachments.d.ts +28 -0
- package/dist/session-goal-reports.d.ts +43 -0
- package/dist/session-mcp-approval.d.ts +4 -0
- package/dist/session-mcp-credential-rotation.js +5 -4
- package/dist/session-mcp-credential-rotation.js.map +1 -1
- package/dist/session-message-search.d.ts +22 -0
- package/dist/session-queue-commands.d.ts +2 -6
- package/dist/session-retry.d.ts +36 -0
- package/dist/session-tenancy.js +3 -3
- package/dist/skill-source-release-impact.d.ts +18 -0
- package/dist/skill-source-release.d.ts +9 -0
- package/dist/skills.d.ts +7 -1
- package/dist/user-resource-authority.d.ts +0 -8
- package/dist/video-generation.js +3 -3
- package/dist/workspace-tool-defaults.js +5 -4
- package/dist/workspace-tool-defaults.js.map +1 -1
- package/drizzle/0468_knowledge_relationship_projection.sql +30 -0
- package/drizzle/0469_knowledge_source_discovery.sql +85 -0
- package/drizzle/0470_organization_integration_policy.sql +151 -0
- package/drizzle/0471_usage_events_account_recent_index.sql +4 -0
- package/drizzle/0472_usage_events_workspace_recent_index.sql +4 -0
- package/drizzle/0473_organization_usage_analytical_capability.sql +237 -0
- package/drizzle/0474_goal_report_requirements.sql +156 -0
- package/drizzle/0475_session_event_history_statistics.sql +15 -0
- package/drizzle/0476_session_event_history_policy_planning.sql +29 -0
- package/drizzle/0477_managed_sign_in_methods.sql +303 -0
- package/drizzle/0478_sender_owned_connections.sql +2772 -0
- package/drizzle/0479_connection_create_idempotency.sql +16 -0
- package/drizzle/0480_private_session_organization_key_administration.sql +154 -0
- package/drizzle/0481_personal_connection_visibility_cleanup.sql +45 -0
- package/drizzle/0482_remove_packs.sql +417 -0
- package/drizzle/0483_preclaim_admission_block.sql +85 -0
- package/drizzle/0484_insights_usage_projection.sql +211 -0
- package/drizzle/0485_inherited_mcp_approval_policies.sql +6 -0
- package/drizzle/0486_reasoning_configuration_message_forks.sql +35 -0
- package/drizzle/0487_skill_catalog_message_forks.sql +26 -0
- package/drizzle/0488_permanent_skill_removal.sql +207 -0
- package/drizzle/0489_modal_command_byte_offsets.sql +17 -0
- package/drizzle/0490_periodic_capture_attempt_cadence.sql +6 -0
- package/drizzle/0491_warm_capture_holder_reclamation.sql +57 -0
- package/drizzle/0492_codex_accepted_source_authority.sql +249 -0
- package/drizzle/0493_stopping_command_error_containment.sql +58 -0
- package/drizzle/0494_mcp_account_bindings.sql +334 -0
- package/drizzle/0495_consented_sandbox_recovery.sql +220 -0
- package/drizzle/0496_supervised_command_settlement.sql +386 -0
- package/drizzle/0497_modal_inventory_owner_read_capability.sql +112 -0
- package/drizzle/0498_enrollment_membership_fence.sql +87 -0
- package/drizzle/0499_session_attachment_access.sql +224 -0
- package/drizzle/0500_session_execution_epoch.sql +37 -0
- package/drizzle/0501_session_sharing_execution.sql +591 -0
- package/drizzle/0502_active_message_boundary_forks.sql +30 -0
- package/package.json +17 -5
- package/src/automations.ts +17 -73
- package/src/canonical-human-identities.ts +17 -5
- package/src/capability-components.ts +7 -24
- package/src/capability-integrations.ts +301 -21
- package/src/capability-reconciliation.ts +19 -0
- package/src/codex-capacity-recovery.ts +47 -0
- package/src/codex-failure-eligibility.ts +93 -0
- package/src/connect-attempts.ts +49 -18
- package/src/connection-authority.ts +12 -158
- package/src/connection-refresh-lock.ts +22 -0
- package/src/connection-token-resolver.ts +58 -530
- package/src/database-timing.ts +43 -0
- package/src/database.ts +61 -26
- package/src/editable-artifacts.ts +1 -1
- package/src/index.ts +3578 -1273
- package/src/insights-model-bundle.ts +19 -7
- package/src/insights-usage-bundle.ts +16 -19
- package/src/integration-bindings.ts +2 -7
- package/src/integration-facets.ts +73 -6
- package/src/knowledge-entries.ts +8 -1
- package/src/live-session-attempt.ts +0 -22
- package/src/mcp-account-bindings.ts +12 -0
- package/src/mcp-oauth.ts +26 -0
- package/src/organization-integration-policy.ts +235 -0
- package/src/organization-usage.ts +83 -0
- package/src/plugin-packages.ts +226 -42
- package/src/pr-review.ts +7 -69
- package/src/preference-registry-schema.ts +1 -0
- package/src/provision-roles.ts +50 -37
- package/src/retained-provider-commands.ts +286 -9
- package/src/retired-session-create-metadata.ts +16 -0
- package/src/runtime-posture.ts +217 -13
- package/src/schema.ts +104 -120
- package/src/session-admission-block.ts +29 -0
- package/src/session-attempt-writers.ts +48 -0
- package/src/session-control.ts +21 -5
- package/src/session-event-slices.ts +76 -26
- package/src/session-file-attachments.ts +66 -0
- package/src/session-goal-reports.ts +255 -0
- package/src/session-mcp-approval.ts +30 -0
- package/src/session-message-search.ts +348 -0
- package/src/session-queue-commands.ts +60 -36
- package/src/session-retry.ts +319 -0
- package/src/skill-config-migration.ts +11 -2
- package/src/skill-source-release-impact.ts +33 -0
- package/src/skill-source-release.ts +67 -26
- package/src/skills.ts +44 -6
- package/src/user-resource-authority.ts +0 -56
- package/dist/chunk-6T2GGYWE.js.map +0 -1
- package/dist/chunk-7HMK3B45.js.map +0 -1
- package/dist/chunk-DPONPYJD.js.map +0 -1
- package/dist/chunk-F73UKJY6.js.map +0 -1
- package/dist/chunk-T6YLHJLS.js.map +0 -1
- package/dist/host-mcp-binding-match.d.ts +0 -5
- package/dist/host-mcp-bindings.d.ts +0 -79
- package/dist/host-mcp-resolvers.d.ts +0 -47
- package/dist/host-mcp-task-authority.d.ts +0 -43
- package/dist/host-selection-identity.d.ts +0 -6
- package/dist/pack-components.d.ts +0 -83
- package/dist/pack-installations.d.ts +0 -86
- package/src/host-mcp-binding-match.ts +0 -34
- package/src/host-mcp-bindings.ts +0 -777
- package/src/host-mcp-resolvers.ts +0 -266
- package/src/host-mcp-task-authority.ts +0 -384
- package/src/host-selection-identity.ts +0 -29
- package/src/pack-components.ts +0 -980
- package/src/pack-installations.ts +0 -950
- /package/dist/{chunk-MWMXWHJD.js.map → chunk-7JCDSMX2.js.map} +0 -0
- /package/dist/{chunk-ERKVSPDX.js.map → chunk-LVY33EWL.js.map} +0 -0
- /package/dist/{chunk-T6BWIGWJ.js.map → chunk-RIYHP2WU.js.map} +0 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import {
|
|
2
|
+
OrganizationUsageQuery,
|
|
3
|
+
OrganizationUsageSummary,
|
|
4
|
+
OrganizationUsageWorkspacePage,
|
|
5
|
+
OrganizationUsageWorkspacePageQuery,
|
|
6
|
+
type OrganizationUsagePeriod,
|
|
7
|
+
} from "@opengeni/contracts";
|
|
8
|
+
import { sql } from "drizzle-orm";
|
|
9
|
+
import { withAccountRls, type Database } from "./database";
|
|
10
|
+
|
|
11
|
+
/** Same UTC semantics as Insights: week is today and the previous six days. */
|
|
12
|
+
export function organizationUsageWindow(period: OrganizationUsagePeriod, now = new Date()) {
|
|
13
|
+
const until = new Date(now);
|
|
14
|
+
const since = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
|
|
15
|
+
if (period === "week") since.setUTCDate(since.getUTCDate() - 6);
|
|
16
|
+
if (period === "month") since.setUTCDate(1);
|
|
17
|
+
if (period === "ytd") since.setUTCMonth(0, 1);
|
|
18
|
+
if (!Number.isFinite(until.getTime())) throw new Error("Invalid usage window");
|
|
19
|
+
return {
|
|
20
|
+
since: since.toISOString(),
|
|
21
|
+
until: until.toISOString(),
|
|
22
|
+
granularity: period === "today" ? ("hour" as const) : ("day" as const),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
type UsageInput = { accountId: string; period?: OrganizationUsagePeriod | undefined };
|
|
27
|
+
|
|
28
|
+
/** One set-based, actor-visible aggregate. Must use the writable primary. */
|
|
29
|
+
export async function getOrganizationUsageSummary(
|
|
30
|
+
db: Database,
|
|
31
|
+
input: UsageInput,
|
|
32
|
+
now = new Date(),
|
|
33
|
+
): Promise<OrganizationUsageSummary> {
|
|
34
|
+
const query = OrganizationUsageQuery.parse(input);
|
|
35
|
+
const window = organizationUsageWindow(query.period, now);
|
|
36
|
+
const result = await readOrganizationUsage(db, input.accountId, window, true);
|
|
37
|
+
return OrganizationUsageSummary.parse({
|
|
38
|
+
...result,
|
|
39
|
+
accountId: input.accountId,
|
|
40
|
+
period: query.period,
|
|
41
|
+
...window,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Bounded page-only scan; never recomputes organization-wide totals/buckets. */
|
|
46
|
+
export async function getOrganizationUsageWorkspacePage(
|
|
47
|
+
db: Database,
|
|
48
|
+
input: UsageInput & { until: string; afterWorkspaceId?: string | undefined },
|
|
49
|
+
): Promise<OrganizationUsageWorkspacePage> {
|
|
50
|
+
const query = OrganizationUsageWorkspacePageQuery.parse(input);
|
|
51
|
+
const window = organizationUsageWindow(query.period, new Date(query.until));
|
|
52
|
+
const result = await readOrganizationUsage(
|
|
53
|
+
db,
|
|
54
|
+
input.accountId,
|
|
55
|
+
window,
|
|
56
|
+
false,
|
|
57
|
+
query.afterWorkspaceId,
|
|
58
|
+
);
|
|
59
|
+
return OrganizationUsageWorkspacePage.parse({
|
|
60
|
+
...result,
|
|
61
|
+
accountId: input.accountId,
|
|
62
|
+
period: query.period,
|
|
63
|
+
...window,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function readOrganizationUsage(
|
|
68
|
+
db: Database,
|
|
69
|
+
accountId: string,
|
|
70
|
+
window: ReturnType<typeof organizationUsageWindow>,
|
|
71
|
+
includePeriod: boolean,
|
|
72
|
+
afterWorkspaceId?: string,
|
|
73
|
+
) {
|
|
74
|
+
return await withAccountRls(db, accountId, async (scopedDb) => {
|
|
75
|
+
await scopedDb.execute(sql`select set_config('statement_timeout', '10s', true)`);
|
|
76
|
+
const result = await scopedDb.execute(sql`select opengeni_private.organization_usage_summary(
|
|
77
|
+
${accountId}::uuid, ${window.since}::timestamptz, ${window.until}::timestamptz,
|
|
78
|
+
${window.granularity}::text, ${afterWorkspaceId ?? null}::uuid, ${includePeriod}::boolean
|
|
79
|
+
) as summary`);
|
|
80
|
+
const rows = Array.isArray(result) ? result : (result as { rows: unknown[] }).rows;
|
|
81
|
+
return (rows[0] as { summary: Record<string, unknown> }).summary;
|
|
82
|
+
});
|
|
83
|
+
}
|
package/src/plugin-packages.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
stableJson,
|
|
5
|
+
type CapabilityCatalogAuthKind,
|
|
6
|
+
type SkillActor,
|
|
7
|
+
type PluginUninstallComponentImpact,
|
|
8
|
+
type PluginUninstallPreview,
|
|
9
|
+
} from "@opengeni/contracts";
|
|
4
10
|
import { and, asc, eq, inArray, ne, or, sql } from "drizzle-orm";
|
|
5
11
|
|
|
6
12
|
import {
|
|
@@ -8,8 +14,19 @@ import {
|
|
|
8
14
|
cleanupOrphanedCapabilityComponents,
|
|
9
15
|
lockCapabilityComponentIdentity,
|
|
10
16
|
} from "./capability-components";
|
|
11
|
-
import {
|
|
12
|
-
|
|
17
|
+
import {
|
|
18
|
+
rawRows,
|
|
19
|
+
setSubjectRlsContext,
|
|
20
|
+
withRlsContext,
|
|
21
|
+
withWorkspaceRls,
|
|
22
|
+
type Database,
|
|
23
|
+
} from "./database";
|
|
24
|
+
import {
|
|
25
|
+
readSkillSourceReleaseHeads,
|
|
26
|
+
SkillSourceReleaseSnapshotChangedError,
|
|
27
|
+
type SkillSourceReleaseReceipt,
|
|
28
|
+
} from "./skill-source-release";
|
|
29
|
+
import { classifySkillSourceRelease } from "./skill-source-release-impact";
|
|
13
30
|
import {
|
|
14
31
|
removeIntegrationFacetBindingOwner,
|
|
15
32
|
removeIntegrationFacetBindingOwnersForOwner,
|
|
@@ -21,6 +38,8 @@ import {
|
|
|
21
38
|
readSkillPublications,
|
|
22
39
|
} from "./skill-publication";
|
|
23
40
|
import type { SkillPublicationReceipt } from "@opengeni/contracts";
|
|
41
|
+
import { withOrganizationIntegrationAcquisition } from "./organization-integration-policy";
|
|
42
|
+
import { nestedPostgresSqlState } from "./persistence-errors";
|
|
24
43
|
|
|
25
44
|
export type PluginBomComponent = {
|
|
26
45
|
key: string;
|
|
@@ -70,6 +89,14 @@ export class PluginInstallationVersionConflictError extends Error {
|
|
|
70
89
|
readonly name = "PluginInstallationVersionConflictError";
|
|
71
90
|
}
|
|
72
91
|
|
|
92
|
+
export class PluginUninstallPreviewChangedError extends Error {
|
|
93
|
+
readonly code = "plugin_uninstall_preview_changed";
|
|
94
|
+
constructor(readonly preview?: PluginUninstallPreview) {
|
|
95
|
+
super("Plugin removal impact changed. Review the refreshed preview before confirming again.");
|
|
96
|
+
this.name = "PluginUninstallPreviewChangedError";
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
73
100
|
export class PluginInstallationVersionRequiredError extends Error {
|
|
74
101
|
readonly name = "PluginInstallationVersionRequiredError";
|
|
75
102
|
}
|
|
@@ -626,6 +653,16 @@ export async function installPluginMcpReference(
|
|
|
626
653
|
authKind: CapabilityCatalogAuthKind;
|
|
627
654
|
digest: string;
|
|
628
655
|
},
|
|
656
|
+
): Promise<{ capabilityId: string; facetInstallationId: string }> {
|
|
657
|
+
const snapshot = structuredClone(input);
|
|
658
|
+
return withOrganizationIntegrationAcquisition(db, snapshot, ["custom:mcp"], (tx) =>
|
|
659
|
+
installPluginMcpReferenceInScope(tx, snapshot),
|
|
660
|
+
);
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
async function installPluginMcpReferenceInScope(
|
|
664
|
+
db: Database,
|
|
665
|
+
input: Parameters<typeof installPluginMcpReference>[1],
|
|
629
666
|
): Promise<{ capabilityId: string; facetInstallationId: string }> {
|
|
630
667
|
const capabilityId = `mcp:configured:${input.serverId}`;
|
|
631
668
|
const pluginKey = `plugin-mcp/${input.serverId}`;
|
|
@@ -898,31 +935,21 @@ export async function getPluginPackageUninstallPreview(
|
|
|
898
935
|
db: Database,
|
|
899
936
|
workspaceId: string,
|
|
900
937
|
pluginKey: string,
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
version: string | null;
|
|
904
|
-
installationVersion: number | null;
|
|
905
|
-
components: Array<{
|
|
906
|
-
capabilityId: string;
|
|
907
|
-
kind: "skill" | "integration" | "mcp";
|
|
908
|
-
retainedByOtherOwners: boolean;
|
|
909
|
-
}>;
|
|
910
|
-
}> {
|
|
938
|
+
subjectId?: string,
|
|
939
|
+
): Promise<Omit<PluginUninstallPreview, "pluginKey">> {
|
|
911
940
|
return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {
|
|
941
|
+
if (subjectId) await setSubjectRlsContext(scopedDb, subjectId);
|
|
912
942
|
const plugin = await pluginPackageInScope(scopedDb, workspaceId, pluginKey);
|
|
913
943
|
if (!plugin || plugin.status === "disabled") {
|
|
914
944
|
return { installed: false, version: null, installationVersion: null, components: [] };
|
|
915
945
|
}
|
|
916
|
-
const
|
|
917
|
-
scopedDb,
|
|
918
|
-
workspaceId,
|
|
919
|
-
plugin.pluginInstallationId,
|
|
920
|
-
);
|
|
946
|
+
const impact = await pluginOwnedComponents(scopedDb, workspaceId, plugin.pluginInstallationId);
|
|
921
947
|
return {
|
|
922
948
|
installed: true,
|
|
923
949
|
version: plugin.version,
|
|
924
950
|
installationVersion: plugin.installationVersion,
|
|
925
|
-
components,
|
|
951
|
+
components: impact.components,
|
|
952
|
+
previewToken: pluginUninstallPreviewToken(plugin, impact.stateToken),
|
|
926
953
|
};
|
|
927
954
|
});
|
|
928
955
|
}
|
|
@@ -935,6 +962,7 @@ export async function uninstallPluginPackage(
|
|
|
935
962
|
subjectId: string;
|
|
936
963
|
pluginKey: string;
|
|
937
964
|
expectedInstallationVersion: number;
|
|
965
|
+
expectedPreviewToken?: string;
|
|
938
966
|
idempotencyKey: string;
|
|
939
967
|
skillActor?: SkillActor;
|
|
940
968
|
},
|
|
@@ -947,6 +975,7 @@ export async function uninstallPluginPackage(
|
|
|
947
975
|
stableJson({
|
|
948
976
|
pluginKey: input.pluginKey,
|
|
949
977
|
expectedInstallationVersion: input.expectedInstallationVersion,
|
|
978
|
+
...(input.expectedPreviewToken ? { expectedPreviewToken: input.expectedPreviewToken } : {}),
|
|
950
979
|
}),
|
|
951
980
|
);
|
|
952
981
|
return await withRlsContext(
|
|
@@ -956,6 +985,7 @@ export async function uninstallPluginPackage(
|
|
|
956
985
|
await setSubjectRlsContext(scopedDb, input.subjectId);
|
|
957
986
|
return await scopedDb.transaction(async (txRaw) => {
|
|
958
987
|
const tx = txRaw as unknown as Database;
|
|
988
|
+
await lockSkillPublication(tx, input.workspaceId);
|
|
959
989
|
await tx.execute(
|
|
960
990
|
sql`select pg_advisory_xact_lock(hashtextextended(${`capability-operation:${input.workspaceId}:${input.idempotencyKey}`}, 0))`,
|
|
961
991
|
);
|
|
@@ -1004,11 +1034,78 @@ export async function uninstallPluginPackage(
|
|
|
1004
1034
|
if (plugin.installationVersion !== input.expectedInstallationVersion) {
|
|
1005
1035
|
throw new PluginInstallationVersionConflictError("Plugin installation changed");
|
|
1006
1036
|
}
|
|
1007
|
-
|
|
1037
|
+
// Match cleanup/source-refresh ordering: child installations, then canonical
|
|
1038
|
+
// registry heads. Hold these locks through token comparison AND release.
|
|
1039
|
+
await tx.execute(sql`SELECT p.id FROM capability_plugin_installations p
|
|
1040
|
+
WHERE p.workspace_id=${input.workspaceId}::uuid AND p.id IN (
|
|
1041
|
+
SELECT fi.plugin_installation_id FROM capability_facet_installations fi
|
|
1042
|
+
JOIN capability_component_owners o ON o.facet_installation_id=fi.id
|
|
1043
|
+
WHERE o.workspace_id=${input.workspaceId}::uuid AND o.owner_kind='plugin'
|
|
1044
|
+
AND o.owner_id=${plugin.pluginInstallationId}
|
|
1045
|
+
) ORDER BY p.id FOR UPDATE`);
|
|
1046
|
+
try {
|
|
1047
|
+
// Facet FK locks fence new owners; owner row locks fence releases by
|
|
1048
|
+
|
|
1049
|
+
// Those paths may remove an owner before acquiring the child lock, so
|
|
1050
|
+
// fail for a refreshed preview rather than creating a lock-order cycle.
|
|
1051
|
+
await tx.execute(sql`SELECT fi.id FROM capability_facet_installations fi
|
|
1052
|
+
WHERE fi.workspace_id=${input.workspaceId}::uuid AND EXISTS (
|
|
1053
|
+
SELECT 1 FROM capability_component_owners own
|
|
1054
|
+
WHERE own.facet_installation_id=fi.id AND own.owner_kind='plugin'
|
|
1055
|
+
AND own.owner_id=${plugin.pluginInstallationId}
|
|
1056
|
+
) ORDER BY fi.id FOR UPDATE NOWAIT`);
|
|
1057
|
+
await tx.execute(sql`SELECT o.id FROM capability_component_owners o
|
|
1058
|
+
WHERE o.workspace_id=${input.workspaceId}::uuid AND EXISTS (
|
|
1059
|
+
SELECT 1 FROM capability_component_owners own
|
|
1060
|
+
WHERE own.facet_installation_id=o.facet_installation_id
|
|
1061
|
+
AND own.owner_kind='plugin' AND own.owner_id=${plugin.pluginInstallationId}
|
|
1062
|
+
) ORDER BY o.id FOR UPDATE NOWAIT`);
|
|
1063
|
+
} catch (error) {
|
|
1064
|
+
if (nestedPostgresSqlState(error) === "55P03")
|
|
1065
|
+
throw new PluginUninstallPreviewChangedError();
|
|
1066
|
+
throw error;
|
|
1067
|
+
}
|
|
1068
|
+
const skillBindings = await rawRows<{ id: string }>(
|
|
1069
|
+
tx,
|
|
1070
|
+
sql`
|
|
1071
|
+
SELECT DISTINCT h.id FROM skill_source_bindings b
|
|
1072
|
+
JOIN capability_facet_installations fi ON fi.facet_id=b.skill_facet_id
|
|
1073
|
+
AND fi.account_id=b.account_id AND fi.workspace_id=b.workspace_id
|
|
1074
|
+
JOIN capability_component_owners o ON o.facet_installation_id=fi.id
|
|
1075
|
+
JOIN preference_registry_preferences h ON h.id=b.preference_id AND h.account_id=b.account_id
|
|
1076
|
+
WHERE b.workspace_id=${input.workspaceId}::uuid AND o.owner_kind='plugin'
|
|
1077
|
+
AND o.owner_id=${plugin.pluginInstallationId} ORDER BY h.id`,
|
|
1078
|
+
);
|
|
1079
|
+
for (const head of skillBindings) {
|
|
1080
|
+
try {
|
|
1081
|
+
await tx.execute(
|
|
1082
|
+
sql`SELECT preference_id FROM preference_registry_lock_heads(ARRAY[${head.id}::uuid])`,
|
|
1083
|
+
);
|
|
1084
|
+
} catch (error) {
|
|
1085
|
+
// A concurrent scope move can make the selected head invisible while
|
|
1086
|
+
// this lock waits. Roll back and obtain the refreshed preview outside
|
|
1087
|
+
// the failed transaction, without disclosing the hidden head.
|
|
1088
|
+
if (nestedPostgresSqlState(error) === "42501")
|
|
1089
|
+
throw new PluginUninstallPreviewChangedError();
|
|
1090
|
+
throw error;
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
const impact = await pluginOwnedComponents(
|
|
1008
1094
|
tx,
|
|
1009
1095
|
input.workspaceId,
|
|
1010
1096
|
plugin.pluginInstallationId,
|
|
1011
1097
|
);
|
|
1098
|
+
const previewToken = pluginUninstallPreviewToken(plugin, impact.stateToken);
|
|
1099
|
+
if (input.expectedPreviewToken && input.expectedPreviewToken !== previewToken) {
|
|
1100
|
+
throw new PluginUninstallPreviewChangedError({
|
|
1101
|
+
pluginKey: input.pluginKey,
|
|
1102
|
+
installed: true,
|
|
1103
|
+
version: plugin.version,
|
|
1104
|
+
installationVersion: plugin.installationVersion,
|
|
1105
|
+
previewToken,
|
|
1106
|
+
components: impact.components,
|
|
1107
|
+
});
|
|
1108
|
+
}
|
|
1012
1109
|
await removeIntegrationFacetBindingOwnersForOwner(tx, {
|
|
1013
1110
|
workspaceId: input.workspaceId,
|
|
1014
1111
|
owner: { kind: "plugin", id: plugin.pluginInstallationId },
|
|
@@ -1023,12 +1120,20 @@ export async function uninstallPluginPackage(
|
|
|
1023
1120
|
),
|
|
1024
1121
|
)
|
|
1025
1122
|
.returning({ facetInstallationId: schema.capabilityComponentOwners.facetInstallationId });
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1123
|
+
let skillReleases: SkillSourceReleaseReceipt[];
|
|
1124
|
+
try {
|
|
1125
|
+
skillReleases = await cleanupOrphanedCapabilityComponents(
|
|
1126
|
+
tx,
|
|
1127
|
+
input.workspaceId,
|
|
1128
|
+
owned.map((row) => row.facetInstallationId),
|
|
1129
|
+
input.skillActor,
|
|
1130
|
+
skillBindings.map((head) => head.id),
|
|
1131
|
+
);
|
|
1132
|
+
} catch (error) {
|
|
1133
|
+
if (error instanceof SkillSourceReleaseSnapshotChangedError)
|
|
1134
|
+
throw new PluginUninstallPreviewChangedError();
|
|
1135
|
+
throw error;
|
|
1136
|
+
}
|
|
1032
1137
|
await tx
|
|
1033
1138
|
.update(schema.capabilityPluginInstallations)
|
|
1034
1139
|
.set({
|
|
@@ -1037,8 +1142,8 @@ export async function uninstallPluginPackage(
|
|
|
1037
1142
|
updatedAt: new Date(),
|
|
1038
1143
|
})
|
|
1039
1144
|
.where(eq(schema.capabilityPluginInstallations.id, plugin.pluginInstallationId));
|
|
1040
|
-
const retainedComponents = components
|
|
1041
|
-
.filter((component) => component.
|
|
1145
|
+
const retainedComponents = impact.components
|
|
1146
|
+
.filter((component) => component.disposition === "retained")
|
|
1042
1147
|
.map((component) => component.capabilityId);
|
|
1043
1148
|
await completeInlineOperation(tx, input, requestDigest, {
|
|
1044
1149
|
status: "uninstalled",
|
|
@@ -1097,18 +1202,13 @@ async function pluginOwnedComponents(
|
|
|
1097
1202
|
db: Database,
|
|
1098
1203
|
workspaceId: string,
|
|
1099
1204
|
ownerPluginInstallationId: string,
|
|
1100
|
-
): Promise<
|
|
1101
|
-
Array<{
|
|
1102
|
-
capabilityId: string;
|
|
1103
|
-
kind: "skill" | "integration" | "mcp";
|
|
1104
|
-
retainedByOtherOwners: boolean;
|
|
1105
|
-
}>
|
|
1106
|
-
> {
|
|
1205
|
+
): Promise<{ components: PluginUninstallComponentImpact[]; stateToken: string }> {
|
|
1107
1206
|
const rows = await db
|
|
1108
1207
|
.select({
|
|
1109
1208
|
facetInstallationId: schema.capabilityFacetInstallations.id,
|
|
1110
1209
|
facetKind: schema.capabilityFacets.kind,
|
|
1111
1210
|
skillCapabilityId: schema.capabilitySkillFacets.capabilityId,
|
|
1211
|
+
name: schema.capabilityPlugins.name,
|
|
1112
1212
|
manifest: schema.capabilityPluginVersions.manifest,
|
|
1113
1213
|
})
|
|
1114
1214
|
.from(schema.capabilityComponentOwners)
|
|
@@ -1134,6 +1234,10 @@ async function pluginOwnedComponents(
|
|
|
1134
1234
|
schema.capabilityPluginVersions,
|
|
1135
1235
|
eq(schema.capabilityPluginVersions.id, schema.capabilityPluginInstallations.pluginVersionId),
|
|
1136
1236
|
)
|
|
1237
|
+
.innerJoin(
|
|
1238
|
+
schema.capabilityPlugins,
|
|
1239
|
+
eq(schema.capabilityPlugins.id, schema.capabilityPluginInstallations.pluginId),
|
|
1240
|
+
)
|
|
1137
1241
|
.leftJoin(
|
|
1138
1242
|
schema.capabilitySkillFacets,
|
|
1139
1243
|
eq(schema.capabilitySkillFacets.facetId, schema.capabilityFacets.id),
|
|
@@ -1148,7 +1252,12 @@ async function pluginOwnedComponents(
|
|
|
1148
1252
|
.orderBy(asc(schema.capabilityFacets.kind), asc(schema.capabilityFacets.facetKey));
|
|
1149
1253
|
const components = new Map<
|
|
1150
1254
|
string,
|
|
1151
|
-
{
|
|
1255
|
+
{
|
|
1256
|
+
capabilityId: string;
|
|
1257
|
+
name: string;
|
|
1258
|
+
kind: "skill" | "integration" | "mcp";
|
|
1259
|
+
facetIds: string[];
|
|
1260
|
+
}
|
|
1152
1261
|
>();
|
|
1153
1262
|
for (const row of rows) {
|
|
1154
1263
|
const manifest = objectValue(row.manifest);
|
|
@@ -1164,15 +1273,26 @@ async function pluginOwnedComponents(
|
|
|
1164
1273
|
if (!capabilityId || !kind) continue;
|
|
1165
1274
|
const existing = components.get(capabilityId);
|
|
1166
1275
|
if (existing) existing.facetIds.push(row.facetInstallationId);
|
|
1167
|
-
else
|
|
1276
|
+
else
|
|
1277
|
+
components.set(capabilityId, {
|
|
1278
|
+
capabilityId,
|
|
1279
|
+
kind,
|
|
1280
|
+
name: row.name,
|
|
1281
|
+
facetIds: [row.facetInstallationId],
|
|
1282
|
+
});
|
|
1168
1283
|
}
|
|
1169
|
-
const result = [];
|
|
1284
|
+
const result: PluginUninstallComponentImpact[] = [];
|
|
1285
|
+
const state: unknown[] = [];
|
|
1170
1286
|
for (const component of components.values()) {
|
|
1171
|
-
const
|
|
1172
|
-
.select({
|
|
1287
|
+
const owners = await db
|
|
1288
|
+
.select({
|
|
1289
|
+
kind: schema.capabilityComponentOwners.ownerKind,
|
|
1290
|
+
id: schema.capabilityComponentOwners.ownerId,
|
|
1291
|
+
})
|
|
1173
1292
|
.from(schema.capabilityComponentOwners)
|
|
1174
1293
|
.where(
|
|
1175
1294
|
and(
|
|
1295
|
+
eq(schema.capabilityComponentOwners.workspaceId, workspaceId),
|
|
1176
1296
|
inArray(schema.capabilityComponentOwners.facetInstallationId, component.facetIds),
|
|
1177
1297
|
// Retention is deliberately physical, not runtime-effective. A Plugin
|
|
1178
1298
|
// in needs_attention may be resumable and must keep shared component
|
|
@@ -1185,13 +1305,77 @@ async function pluginOwnedComponents(
|
|
|
1185
1305
|
),
|
|
1186
1306
|
),
|
|
1187
1307
|
);
|
|
1308
|
+
const remainingOwners: PluginUninstallComponentImpact["remainingOwners"] = [];
|
|
1309
|
+
for (const owner of owners.sort((a, b) =>
|
|
1310
|
+
`${a.kind}:${a.id}`.localeCompare(`${b.kind}:${b.id}`),
|
|
1311
|
+
)) {
|
|
1312
|
+
let name =
|
|
1313
|
+
owner.kind === "direct"
|
|
1314
|
+
? "Direct installation"
|
|
1315
|
+
: owner.kind === "migration"
|
|
1316
|
+
? "Migrated installation"
|
|
1317
|
+
: "Another installed owner";
|
|
1318
|
+
if (owner.kind === "plugin") {
|
|
1319
|
+
const [named] = await db
|
|
1320
|
+
.select({ manifest: schema.capabilityPluginVersions.manifest })
|
|
1321
|
+
.from(schema.capabilityPluginInstallations)
|
|
1322
|
+
.innerJoin(
|
|
1323
|
+
schema.capabilityPluginVersions,
|
|
1324
|
+
eq(
|
|
1325
|
+
schema.capabilityPluginVersions.id,
|
|
1326
|
+
schema.capabilityPluginInstallations.pluginVersionId,
|
|
1327
|
+
),
|
|
1328
|
+
)
|
|
1329
|
+
.where(
|
|
1330
|
+
and(
|
|
1331
|
+
eq(schema.capabilityPluginInstallations.workspaceId, workspaceId),
|
|
1332
|
+
sql`${schema.capabilityPluginInstallations.id}::text = ${owner.id}`,
|
|
1333
|
+
),
|
|
1334
|
+
);
|
|
1335
|
+
name = stringValue(objectValue(named?.manifest).name) ?? name;
|
|
1336
|
+
}
|
|
1337
|
+
if (!remainingOwners.some((item) => item.kind === owner.kind && item.name === name))
|
|
1338
|
+
remainingOwners.push({
|
|
1339
|
+
kind: owner.kind as PluginUninstallComponentImpact["remainingOwners"][number]["kind"],
|
|
1340
|
+
name,
|
|
1341
|
+
});
|
|
1342
|
+
}
|
|
1343
|
+
const heads =
|
|
1344
|
+
component.kind === "skill"
|
|
1345
|
+
? await readSkillSourceReleaseHeads(db, workspaceId, component.facetIds)
|
|
1346
|
+
: [];
|
|
1347
|
+
const head = heads[0];
|
|
1348
|
+
const skillImpact = head ? classifySkillSourceRelease(head, workspaceId) : null;
|
|
1349
|
+
const retainedByOtherOwners = owners.length > 0;
|
|
1350
|
+
const retentionReasons: PluginUninstallComponentImpact["retentionReasons"] = [];
|
|
1351
|
+
if (retainedByOtherOwners) retentionReasons.push("other_owners");
|
|
1352
|
+
if (skillImpact) retentionReasons.push(...skillImpact.retentionReasons);
|
|
1353
|
+
else if (component.kind === "skill") retentionReasons.push("registry_unavailable");
|
|
1354
|
+
state.push({ facetIds: component.facetIds, owners, heads });
|
|
1188
1355
|
result.push({
|
|
1189
1356
|
capabilityId: component.capabilityId,
|
|
1190
1357
|
kind: component.kind,
|
|
1191
|
-
|
|
1358
|
+
name: head?.title ?? component.name,
|
|
1359
|
+
retainedByOtherOwners,
|
|
1360
|
+
disposition: retainedByOtherOwners
|
|
1361
|
+
? "retained"
|
|
1362
|
+
: (skillImpact?.disposition ?? (component.kind === "skill" ? "retained" : "removed")),
|
|
1363
|
+
retentionReasons,
|
|
1364
|
+
remainingOwners,
|
|
1365
|
+
...(head ? { skillId: head.id } : {}),
|
|
1192
1366
|
});
|
|
1193
1367
|
}
|
|
1194
|
-
return result;
|
|
1368
|
+
return { components: result, stateToken: sha256(stableJson({ state, components: result })) };
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
function pluginUninstallPreviewToken(plugin: InstalledPluginPackage, stateToken: string): string {
|
|
1372
|
+
return sha256(
|
|
1373
|
+
stableJson({
|
|
1374
|
+
installationId: plugin.pluginInstallationId,
|
|
1375
|
+
version: plugin.installationVersion,
|
|
1376
|
+
stateToken,
|
|
1377
|
+
}),
|
|
1378
|
+
);
|
|
1195
1379
|
}
|
|
1196
1380
|
|
|
1197
1381
|
async function completeInlineOperation(
|
package/src/pr-review.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AutomationSessionTemplate,
|
|
3
|
-
OPENGENI_PR_REVIEW_PACK_ID,
|
|
4
3
|
OPENGENI_PR_REVIEW_SESSION_ROLE,
|
|
5
4
|
type PrReviewAppRegistration,
|
|
6
5
|
type GitHubRepository,
|
|
@@ -43,8 +42,6 @@ export async function createPrReviewAppRegistration(
|
|
|
43
42
|
webhookSecretEncrypted: string;
|
|
44
43
|
webhookUsername: string | null;
|
|
45
44
|
createdBySubjectId: string;
|
|
46
|
-
packInstallationId: string;
|
|
47
|
-
packConnectorId: string;
|
|
48
45
|
},
|
|
49
46
|
): Promise<PrReviewAppRegistration> {
|
|
50
47
|
return await withRlsContext(db, input, async (scopedDb) => {
|
|
@@ -64,8 +61,7 @@ export async function createPrReviewAppRegistration(
|
|
|
64
61
|
webhookUsername: input.webhookUsername,
|
|
65
62
|
},
|
|
66
63
|
webhookSecretEncrypted: input.webhookSecretEncrypted,
|
|
67
|
-
|
|
68
|
-
packConnectorId: input.packConnectorId,
|
|
64
|
+
|
|
69
65
|
createdBySubjectId: input.createdBySubjectId,
|
|
70
66
|
})
|
|
71
67
|
.returning();
|
|
@@ -312,8 +308,7 @@ export async function createPrReviewRepositoryBinding(
|
|
|
312
308
|
additionalInstructions: string | null;
|
|
313
309
|
status: "active" | "disabled";
|
|
314
310
|
createdBySubjectId: string;
|
|
315
|
-
|
|
316
|
-
packTemplateId: string;
|
|
311
|
+
|
|
317
312
|
adapterId: string;
|
|
318
313
|
eventTypes: string[];
|
|
319
314
|
configuration: Record<string, unknown>;
|
|
@@ -357,8 +352,7 @@ export async function createPrReviewRepositoryBinding(
|
|
|
357
352
|
sourceId: registration.sourceId,
|
|
358
353
|
name: `Review ${input.repositoryFullName}`,
|
|
359
354
|
status: input.status,
|
|
360
|
-
|
|
361
|
-
packTemplateId: input.packTemplateId,
|
|
355
|
+
|
|
362
356
|
createdBySubjectId: input.createdBySubjectId,
|
|
363
357
|
})
|
|
364
358
|
.returning();
|
|
@@ -401,10 +395,6 @@ export async function createPrReviewRepositoryBinding(
|
|
|
401
395
|
});
|
|
402
396
|
}
|
|
403
397
|
|
|
404
|
-
/** Atomically converge one owner-authorized installation of the deployment
|
|
405
|
-
* review App onto the Pack's ordinary source/trigger/binding model. Re-running
|
|
406
|
-
* the browser flow repairs disabled rows, follows GitHub repository selection,
|
|
407
|
-
* and removes shared-webhook routes for repositories no longer selected. */
|
|
408
398
|
export async function syncManagedGitHubPrReviewInstallation(
|
|
409
399
|
db: Database,
|
|
410
400
|
input: {
|
|
@@ -422,9 +412,7 @@ export async function syncManagedGitHubPrReviewInstallation(
|
|
|
422
412
|
webhookSecretEncrypted: string;
|
|
423
413
|
repositories: GitHubRepository[];
|
|
424
414
|
createdBySubjectId: string;
|
|
425
|
-
|
|
426
|
-
packConnectorId: string;
|
|
427
|
-
packTemplateId: string;
|
|
415
|
+
|
|
428
416
|
adapterId: string;
|
|
429
417
|
eventTypes: string[];
|
|
430
418
|
configuration: Record<string, unknown>;
|
|
@@ -439,22 +427,6 @@ export async function syncManagedGitHubPrReviewInstallation(
|
|
|
439
427
|
input,
|
|
440
428
|
async (scopedDb) =>
|
|
441
429
|
await scopedDb.transaction(async (tx) => {
|
|
442
|
-
const [packInstallation] = await tx
|
|
443
|
-
.select({ id: schema.packInstallations.id })
|
|
444
|
-
.from(schema.packInstallations)
|
|
445
|
-
.where(
|
|
446
|
-
and(
|
|
447
|
-
eq(schema.packInstallations.workspaceId, input.workspaceId),
|
|
448
|
-
eq(schema.packInstallations.id, input.packInstallationId),
|
|
449
|
-
eq(schema.packInstallations.packId, OPENGENI_PR_REVIEW_PACK_ID),
|
|
450
|
-
eq(schema.packInstallations.status, "active"),
|
|
451
|
-
),
|
|
452
|
-
)
|
|
453
|
-
.limit(1)
|
|
454
|
-
.for("update");
|
|
455
|
-
if (!packInstallation) {
|
|
456
|
-
throw new PrReviewDispatchAuthorityError("OpenGeni Review Bot Pack is not active");
|
|
457
|
-
}
|
|
458
430
|
const installationId = String(input.installationId);
|
|
459
431
|
const [nonceReceipt] = await tx
|
|
460
432
|
.insert(schema.prReviewManagedGithubAuthorityNonces)
|
|
@@ -507,8 +479,7 @@ export async function syncManagedGitHubPrReviewInstallation(
|
|
|
507
479
|
configuration: nextSourceConfiguration,
|
|
508
480
|
webhookSecretEncrypted: input.webhookSecretEncrypted,
|
|
509
481
|
status: "active",
|
|
510
|
-
|
|
511
|
-
packConnectorId: input.packConnectorId,
|
|
482
|
+
|
|
512
483
|
version: sql`${schema.automationSources.version} + 1`,
|
|
513
484
|
updatedAt: new Date(),
|
|
514
485
|
})
|
|
@@ -559,8 +530,7 @@ export async function syncManagedGitHubPrReviewInstallation(
|
|
|
559
530
|
webhookUsername: null,
|
|
560
531
|
},
|
|
561
532
|
webhookSecretEncrypted: input.webhookSecretEncrypted,
|
|
562
|
-
|
|
563
|
-
packConnectorId: input.packConnectorId,
|
|
533
|
+
|
|
564
534
|
createdBySubjectId: input.createdBySubjectId,
|
|
565
535
|
})
|
|
566
536
|
.returning();
|
|
@@ -655,8 +625,7 @@ export async function syncManagedGitHubPrReviewInstallation(
|
|
|
655
625
|
sourceId: source.id,
|
|
656
626
|
name: `Review ${repository.fullName}`,
|
|
657
627
|
status: "active",
|
|
658
|
-
|
|
659
|
-
packTemplateId: input.packTemplateId,
|
|
628
|
+
|
|
660
629
|
createdBySubjectId: input.createdBySubjectId,
|
|
661
630
|
})
|
|
662
631
|
.returning();
|
|
@@ -1079,10 +1048,6 @@ export async function resolvePrReviewGitCredential(
|
|
|
1079
1048
|
runSessionId: schema.automationRuns.sessionId,
|
|
1080
1049
|
triggerStatus: schema.automationTriggers.status,
|
|
1081
1050
|
sourceStatus: schema.automationSources.status,
|
|
1082
|
-
sourcePackInstallationId: schema.automationSources.packInstallationId,
|
|
1083
|
-
sourcePackConnectorId: schema.automationSources.packConnectorId,
|
|
1084
|
-
packInstallationId: schema.packInstallations.id,
|
|
1085
|
-
packStatus: schema.packInstallations.status,
|
|
1086
1051
|
bindingStatus: schema.prReviewRepositoryBindings.status,
|
|
1087
1052
|
registrationStatus: schema.prReviewAppRegistrations.status,
|
|
1088
1053
|
})
|
|
@@ -1116,13 +1081,6 @@ export async function resolvePrReviewGitCredential(
|
|
|
1116
1081
|
eq(schema.prReviewAppRegistrations.sourceId, schema.automationRuns.sourceId),
|
|
1117
1082
|
),
|
|
1118
1083
|
)
|
|
1119
|
-
.innerJoin(
|
|
1120
|
-
schema.packInstallations,
|
|
1121
|
-
and(
|
|
1122
|
-
eq(schema.packInstallations.workspaceId, schema.automationRuns.workspaceId),
|
|
1123
|
-
eq(schema.packInstallations.id, schema.automationTriggers.packInstallationId),
|
|
1124
|
-
),
|
|
1125
|
-
)
|
|
1126
1084
|
.where(
|
|
1127
1085
|
and(
|
|
1128
1086
|
eq(schema.automationRuns.workspaceId, input.workspaceId),
|
|
@@ -1131,7 +1089,6 @@ export async function resolvePrReviewGitCredential(
|
|
|
1131
1089
|
eq(schema.automationRuns.sessionId, input.sessionId),
|
|
1132
1090
|
eq(schema.prReviewRepositoryBindings.id, bindingId),
|
|
1133
1091
|
eq(schema.prReviewAppRegistrations.id, input.registrationId),
|
|
1134
|
-
eq(schema.packInstallations.packId, OPENGENI_PR_REVIEW_PACK_ID),
|
|
1135
1092
|
),
|
|
1136
1093
|
)
|
|
1137
1094
|
.limit(1);
|
|
@@ -1141,9 +1098,6 @@ export async function resolvePrReviewGitCredential(
|
|
|
1141
1098
|
execution.runSessionId !== input.sessionId ||
|
|
1142
1099
|
execution.triggerStatus !== "active" ||
|
|
1143
1100
|
execution.sourceStatus !== "active" ||
|
|
1144
|
-
execution.sourcePackInstallationId !== execution.packInstallationId ||
|
|
1145
|
-
execution.sourcePackConnectorId !== prReviewProviderPackConnectorId(input.provider) ||
|
|
1146
|
-
execution.packStatus !== "active" ||
|
|
1147
1101
|
execution.bindingStatus !== "active" ||
|
|
1148
1102
|
execution.registrationStatus !== "active"
|
|
1149
1103
|
) {
|
|
@@ -1194,18 +1148,6 @@ export async function resolvePrReviewGitCredential(
|
|
|
1194
1148
|
"PR Review credential is not authorized for this repository",
|
|
1195
1149
|
);
|
|
1196
1150
|
}
|
|
1197
|
-
const [pack] = await scopedDb
|
|
1198
|
-
.select({ status: schema.packInstallations.status })
|
|
1199
|
-
.from(schema.packInstallations)
|
|
1200
|
-
.where(
|
|
1201
|
-
and(
|
|
1202
|
-
eq(schema.packInstallations.workspaceId, input.workspaceId),
|
|
1203
|
-
eq(schema.packInstallations.packId, OPENGENI_PR_REVIEW_PACK_ID),
|
|
1204
|
-
),
|
|
1205
|
-
)
|
|
1206
|
-
.limit(1);
|
|
1207
|
-
if (pack?.status !== "active")
|
|
1208
|
-
throw new PrReviewDispatchAuthorityError("OpenGeni Review Bot Pack is not active");
|
|
1209
1151
|
return {
|
|
1210
1152
|
credentialKind: registration.credentialKind as
|
|
1211
1153
|
| "github_app"
|
|
@@ -1218,10 +1160,6 @@ export async function resolvePrReviewGitCredential(
|
|
|
1218
1160
|
});
|
|
1219
1161
|
}
|
|
1220
1162
|
|
|
1221
|
-
function prReviewProviderPackConnectorId(provider: PrReviewProvider): string {
|
|
1222
|
-
return provider === "azure_devops" ? "azure-devops" : provider;
|
|
1223
|
-
}
|
|
1224
|
-
|
|
1225
1163
|
function prReviewMetadataText(metadata: unknown, key: string): string | null {
|
|
1226
1164
|
if (typeof metadata !== "object" || metadata === null || Array.isArray(metadata)) return null;
|
|
1227
1165
|
const value = (metadata as Record<string, unknown>)[key];
|
|
@@ -80,6 +80,7 @@ export const preferenceRegistryRevisions = pgTable(
|
|
|
80
80
|
contentHash: text("content_hash").notNull(),
|
|
81
81
|
skillFiles: jsonb("skill_files").$type<Array<{ path: string; content: string }> | null>(),
|
|
82
82
|
skillActivationMode: text("skill_activation_mode"),
|
|
83
|
+
skillRemovalOperationId: uuid("skill_removal_operation_id"),
|
|
83
84
|
precedenceRank: integer("precedence_rank").notNull().default(0),
|
|
84
85
|
conflictStrategy: text("conflict_strategy").notNull(),
|
|
85
86
|
conflictsWith: jsonb("conflicts_with").$type<string[]>().notNull().default([]),
|