@cogenta/plugins 0.1.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/guest/sandbox-entry.mjs +155 -0
- package/dist/host/capabilities.d.ts +46 -0
- package/dist/host/capabilities.d.ts.map +1 -0
- package/dist/host/capabilities.js +105 -0
- package/dist/host/capabilities.js.map +1 -0
- package/dist/host/protocol.d.ts +58 -0
- package/dist/host/protocol.d.ts.map +1 -0
- package/dist/host/protocol.js +10 -0
- package/dist/host/protocol.js.map +1 -0
- package/dist/host/worker-runner.d.ts +92 -0
- package/dist/host/worker-runner.d.ts.map +1 -0
- package/dist/host/worker-runner.js +196 -0
- package/dist/host/worker-runner.js.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/loader.d.ts +81 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +190 -0
- package/dist/loader.js.map +1 -0
- package/dist/manifest.d.ts +93 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +197 -0
- package/dist/manifest.js.map +1 -0
- package/dist/permissions/describe.d.ts +22 -0
- package/dist/permissions/describe.d.ts.map +1 -0
- package/dist/permissions/describe.js +158 -0
- package/dist/permissions/describe.js.map +1 -0
- package/dist/permissions/disabled.d.ts +25 -0
- package/dist/permissions/disabled.d.ts.map +1 -0
- package/dist/permissions/disabled.js +29 -0
- package/dist/permissions/disabled.js.map +1 -0
- package/dist/permissions/grants.d.ts +22 -0
- package/dist/permissions/grants.d.ts.map +1 -0
- package/dist/permissions/grants.js +31 -0
- package/dist/permissions/grants.js.map +1 -0
- package/dist/permissions/resolve.d.ts +47 -0
- package/dist/permissions/resolve.d.ts.map +1 -0
- package/dist/permissions/resolve.js +51 -0
- package/dist/permissions/resolve.js.map +1 -0
- package/dist/permissions/review.d.ts +50 -0
- package/dist/permissions/review.d.ts.map +1 -0
- package/dist/permissions/review.js +46 -0
- package/dist/permissions/review.js.map +1 -0
- package/dist/permissions/tables.d.ts +18 -0
- package/dist/permissions/tables.d.ts.map +1 -0
- package/dist/permissions/tables.js +48 -0
- package/dist/permissions/tables.js.map +1 -0
- package/dist/registries/plugins.d.ts +74 -0
- package/dist/registries/plugins.d.ts.map +1 -0
- package/dist/registries/plugins.js +127 -0
- package/dist/registries/plugins.js.map +1 -0
- package/dist/registries/skills.d.ts +54 -0
- package/dist/registries/skills.d.ts.map +1 -0
- package/dist/registries/skills.js +113 -0
- package/dist/registries/skills.js.map +1 -0
- package/dist/registries/skins.d.ts +33 -0
- package/dist/registries/skins.d.ts.map +1 -0
- package/dist/registries/skins.js +65 -0
- package/dist/registries/skins.js.map +1 -0
- package/dist/registries/tables.d.ts +44 -0
- package/dist/registries/tables.d.ts.map +1 -0
- package/dist/registries/tables.js +118 -0
- package/dist/registries/tables.js.map +1 -0
- package/dist/registries/themes.d.ts +59 -0
- package/dist/registries/themes.d.ts.map +1 -0
- package/dist/registries/themes.js +82 -0
- package/dist/registries/themes.js.map +1 -0
- package/dist/semver.d.ts +24 -0
- package/dist/semver.d.ts.map +1 -0
- package/dist/semver.js +93 -0
- package/dist/semver.js.map +1 -0
- package/dist/signing/keys.d.ts +18 -0
- package/dist/signing/keys.d.ts.map +1 -0
- package/dist/signing/keys.js +15 -0
- package/dist/signing/keys.js.map +1 -0
- package/dist/signing/sign.d.ts +35 -0
- package/dist/signing/sign.d.ts.map +1 -0
- package/dist/signing/sign.js +63 -0
- package/dist/signing/sign.js.map +1 -0
- package/dist/signing/verify.d.ts +40 -0
- package/dist/signing/verify.d.ts.map +1 -0
- package/dist/signing/verify.js +73 -0
- package/dist/signing/verify.js.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { PluginManifest } from '../manifest.js';
|
|
2
|
+
import type { PluginGrant } from './grants.js';
|
|
3
|
+
/**
|
|
4
|
+
* "Traduction capacités → objet SDK, avec absence des méthodes non
|
|
5
|
+
* accordées" (docs/lots/L7-extensibilite.md, task 5) — the real reconciliation
|
|
6
|
+
* between what a manifest DECLARES (task 1) and what has actually been
|
|
7
|
+
* APPROVED (`./grants.js`). The result is the INTERSECTION of the two, by
|
|
8
|
+
* exact capability string:
|
|
9
|
+
*
|
|
10
|
+
* - A grant for a capability the current manifest no longer declares is
|
|
11
|
+
* excluded (a stale grant left over from an old manifest version never
|
|
12
|
+
* leaks through).
|
|
13
|
+
* - A declared-but-never-granted capability is excluded (nothing is
|
|
14
|
+
* granted just because a plugin asked for it).
|
|
15
|
+
* - `http.fetch:api.exemple.com` being granted does NOT cover
|
|
16
|
+
* `http.fetch:evil.com` even though both share the bare name
|
|
17
|
+
* `http.fetch` — grants are exact-string, never prefix- or
|
|
18
|
+
* name-matched.
|
|
19
|
+
*
|
|
20
|
+
* This is the ONLY list that may ever reach `buildSdk`
|
|
21
|
+
* (`../guest/sandbox-entry.mjs` via `runIsolated`'s `grantedCapabilities`
|
|
22
|
+
* option) — never the manifest's raw `capabilities` array, and never a
|
|
23
|
+
* caller-supplied list task 4 originally accepted as a placeholder.
|
|
24
|
+
*/
|
|
25
|
+
export declare function resolveGrantedCapabilities(manifest: PluginManifest, grants: readonly PluginGrant[]): readonly string[];
|
|
26
|
+
/**
|
|
27
|
+
* "## Les mises à jour de plugins" (docs/lots/L7-extensibilite.md, lines
|
|
28
|
+
* 192-193, quoted in full): "Une nouvelle version demandant plus de
|
|
29
|
+
* permissions ne doit **jamais** s'installer automatiquement. Nouvelle
|
|
30
|
+
* approbation exigée."
|
|
31
|
+
*
|
|
32
|
+
* Chosen operational semantics: the new manifest version MAY be resolved and
|
|
33
|
+
* run immediately (it is not blocked from activating) — but
|
|
34
|
+
* `resolveGrantedCapabilities` above already, structurally, excludes any
|
|
35
|
+
* capability the grant store has no exact-string row for. A capability the
|
|
36
|
+
* new manifest declares for the first time therefore has no matching grant
|
|
37
|
+
* yet and is silently absent from the SDK (task 4's "absent, not refused"
|
|
38
|
+
* property) until someone calls `PluginGrantStore.grant` for it — there is
|
|
39
|
+
* no separate "block activation" state machine to build, because the
|
|
40
|
+
* reconciliation function itself already never auto-grants. This function
|
|
41
|
+
* exists to make that property VISIBLE and TESTABLE as its own concern (a
|
|
42
|
+
* permission screen, task 7, needs exactly this list to prompt the user for
|
|
43
|
+
* fresh approval), not to add a second enforcement mechanism alongside
|
|
44
|
+
* `resolveGrantedCapabilities`.
|
|
45
|
+
*/
|
|
46
|
+
export declare function detectCapabilitiesNeedingApproval(newManifest: PluginManifest, previouslyGrantedCapabilities: readonly string[]): readonly string[];
|
|
47
|
+
//# sourceMappingURL=resolve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/permissions/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAE9C;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,cAAc,EACxB,MAAM,EAAE,SAAS,WAAW,EAAE,GAC7B,SAAS,MAAM,EAAE,CAKnB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,iCAAiC,CAC/C,WAAW,EAAE,cAAc,EAC3B,6BAA6B,EAAE,SAAS,MAAM,EAAE,GAC/C,SAAS,MAAM,EAAE,CAGnB"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* "Traduction capacités → objet SDK, avec absence des méthodes non
|
|
3
|
+
* accordées" (docs/lots/L7-extensibilite.md, task 5) — the real reconciliation
|
|
4
|
+
* between what a manifest DECLARES (task 1) and what has actually been
|
|
5
|
+
* APPROVED (`./grants.js`). The result is the INTERSECTION of the two, by
|
|
6
|
+
* exact capability string:
|
|
7
|
+
*
|
|
8
|
+
* - A grant for a capability the current manifest no longer declares is
|
|
9
|
+
* excluded (a stale grant left over from an old manifest version never
|
|
10
|
+
* leaks through).
|
|
11
|
+
* - A declared-but-never-granted capability is excluded (nothing is
|
|
12
|
+
* granted just because a plugin asked for it).
|
|
13
|
+
* - `http.fetch:api.exemple.com` being granted does NOT cover
|
|
14
|
+
* `http.fetch:evil.com` even though both share the bare name
|
|
15
|
+
* `http.fetch` — grants are exact-string, never prefix- or
|
|
16
|
+
* name-matched.
|
|
17
|
+
*
|
|
18
|
+
* This is the ONLY list that may ever reach `buildSdk`
|
|
19
|
+
* (`../guest/sandbox-entry.mjs` via `runIsolated`'s `grantedCapabilities`
|
|
20
|
+
* option) — never the manifest's raw `capabilities` array, and never a
|
|
21
|
+
* caller-supplied list task 4 originally accepted as a placeholder.
|
|
22
|
+
*/
|
|
23
|
+
export function resolveGrantedCapabilities(manifest, grants) {
|
|
24
|
+
const grantedSet = new Set(grants.filter((grant) => grant.pluginName === manifest.name).map((grant) => grant.capability));
|
|
25
|
+
return manifest.capabilities.filter((capability) => grantedSet.has(capability));
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* "## Les mises à jour de plugins" (docs/lots/L7-extensibilite.md, lines
|
|
29
|
+
* 192-193, quoted in full): "Une nouvelle version demandant plus de
|
|
30
|
+
* permissions ne doit **jamais** s'installer automatiquement. Nouvelle
|
|
31
|
+
* approbation exigée."
|
|
32
|
+
*
|
|
33
|
+
* Chosen operational semantics: the new manifest version MAY be resolved and
|
|
34
|
+
* run immediately (it is not blocked from activating) — but
|
|
35
|
+
* `resolveGrantedCapabilities` above already, structurally, excludes any
|
|
36
|
+
* capability the grant store has no exact-string row for. A capability the
|
|
37
|
+
* new manifest declares for the first time therefore has no matching grant
|
|
38
|
+
* yet and is silently absent from the SDK (task 4's "absent, not refused"
|
|
39
|
+
* property) until someone calls `PluginGrantStore.grant` for it — there is
|
|
40
|
+
* no separate "block activation" state machine to build, because the
|
|
41
|
+
* reconciliation function itself already never auto-grants. This function
|
|
42
|
+
* exists to make that property VISIBLE and TESTABLE as its own concern (a
|
|
43
|
+
* permission screen, task 7, needs exactly this list to prompt the user for
|
|
44
|
+
* fresh approval), not to add a second enforcement mechanism alongside
|
|
45
|
+
* `resolveGrantedCapabilities`.
|
|
46
|
+
*/
|
|
47
|
+
export function detectCapabilitiesNeedingApproval(newManifest, previouslyGrantedCapabilities) {
|
|
48
|
+
const previouslyGranted = new Set(previouslyGrantedCapabilities);
|
|
49
|
+
return newManifest.capabilities.filter((capability) => !previouslyGranted.has(capability));
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=resolve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/permissions/resolve.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,0BAA0B,CACxC,QAAwB,EACxB,MAA8B;IAE9B,MAAM,UAAU,GAAG,IAAI,GAAG,CACxB,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,UAAU,KAAK,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,CAC9F,CAAA;IACD,OAAO,QAAQ,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAA;AACjF,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,iCAAiC,CAC/C,WAA2B,EAC3B,6BAAgD;IAEhD,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,6BAA6B,CAAC,CAAA;IAChE,OAAO,WAAW,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,iBAAiB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAA;AAC5F,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { PluginManifest } from '../manifest.js';
|
|
2
|
+
import { type PluginCapabilityDescription } from './describe.js';
|
|
3
|
+
import type { PluginGrantStore } from './grants.js';
|
|
4
|
+
/**
|
|
5
|
+
* "Les permissions sont révisables après installation, et révocables"
|
|
6
|
+
* (docs/lots/L7-extensibilite.md, task 7's own text — this is task 8's job).
|
|
7
|
+
* One currently-active grant, already translated via `describeCapability`
|
|
8
|
+
* (task 7) — never a raw capability string reaching a caller that renders
|
|
9
|
+
* a review screen.
|
|
10
|
+
*/
|
|
11
|
+
export interface GrantedCapabilityReview {
|
|
12
|
+
readonly capability: string;
|
|
13
|
+
readonly description: PluginCapabilityDescription;
|
|
14
|
+
readonly grantedAt: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The real listing this task builds: every currently-active grant for
|
|
18
|
+
* `pluginName`, translated. Reuses `PluginGrantStore.listGrants` (task 5)
|
|
19
|
+
* and `describeCapability` (task 7) as-is — no new persistence, no new
|
|
20
|
+
* translation table.
|
|
21
|
+
*/
|
|
22
|
+
export declare function listGrantedCapabilities(pluginName: string, grantStore: PluginGrantStore): Promise<readonly GrantedCapabilityReview[]>;
|
|
23
|
+
/**
|
|
24
|
+
* Revokes `capability` for `pluginName` and reports whether it is now
|
|
25
|
+
* genuinely absent from the plugin's SDK — not merely "marked revoked in a
|
|
26
|
+
* table somewhere". Callers that only need the write can call
|
|
27
|
+
* `PluginGrantStore.revoke` directly; this wrapper exists for the one place
|
|
28
|
+
* that needs the end-to-end confirmation (a UI action that wants to know
|
|
29
|
+
* the revocation actually took effect before saying so to the user).
|
|
30
|
+
*/
|
|
31
|
+
export declare function revokeCapability(manifest: PluginManifest, capability: string, grantStore: PluginGrantStore): Promise<{
|
|
32
|
+
readonly stillGranted: boolean;
|
|
33
|
+
}>;
|
|
34
|
+
/** One capability a manifest update newly declares, not yet approved — translated, with the exact string a caller needs to actually grant it. */
|
|
35
|
+
export interface PendingCapabilityReview {
|
|
36
|
+
readonly capability: string;
|
|
37
|
+
readonly description: PluginCapabilityDescription;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* "## Les mises à jour de plugins": `detectCapabilitiesNeedingApproval`
|
|
41
|
+
* (task 5) already computes WHICH capabilities a new manifest declares
|
|
42
|
+
* beyond what was previously granted — this is that same list, translated,
|
|
43
|
+
* for a real "new permissions requested" section next to the plugin's
|
|
44
|
+
* existing granted-permissions review (never re-approving is the SDK's job,
|
|
45
|
+
* already handled structurally by `resolveGrantedCapabilities`; this is
|
|
46
|
+
* only about making the pending set visible to a human, and giving them the
|
|
47
|
+
* exact capability strings a real approval action needs).
|
|
48
|
+
*/
|
|
49
|
+
export declare function describePendingApproval(newManifest: PluginManifest, grantStore: PluginGrantStore): Promise<readonly PendingCapabilityReview[]>;
|
|
50
|
+
//# sourceMappingURL=review.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review.d.ts","sourceRoot":"","sources":["../../src/permissions/review.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AACpD,OAAO,EAAsB,KAAK,2BAA2B,EAAE,MAAM,eAAe,CAAA;AACpF,OAAO,KAAK,EAAe,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAGhE;;;;;;GAMG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,WAAW,EAAE,2BAA2B,CAAA;IACjD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B;AAED;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAC3C,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,gBAAgB,GAC3B,OAAO,CAAC,SAAS,uBAAuB,EAAE,CAAC,CAO7C;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,cAAc,EACxB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,gBAAgB,GAC3B,OAAO,CAAC;IAAE,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAA;CAAE,CAAC,CAK7C;AAED,iJAAiJ;AACjJ,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,WAAW,EAAE,2BAA2B,CAAA;CAClD;AAED;;;;;;;;;GASG;AACH,wBAAsB,uBAAuB,CAC3C,WAAW,EAAE,cAAc,EAC3B,UAAU,EAAE,gBAAgB,GAC3B,OAAO,CAAC,SAAS,uBAAuB,EAAE,CAAC,CAO7C"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { describeCapability } from './describe.js';
|
|
2
|
+
import { detectCapabilitiesNeedingApproval } from './resolve.js';
|
|
3
|
+
/**
|
|
4
|
+
* The real listing this task builds: every currently-active grant for
|
|
5
|
+
* `pluginName`, translated. Reuses `PluginGrantStore.listGrants` (task 5)
|
|
6
|
+
* and `describeCapability` (task 7) as-is — no new persistence, no new
|
|
7
|
+
* translation table.
|
|
8
|
+
*/
|
|
9
|
+
export async function listGrantedCapabilities(pluginName, grantStore) {
|
|
10
|
+
const grants = await grantStore.listGrants(pluginName);
|
|
11
|
+
return grants.map((grant) => ({
|
|
12
|
+
capability: grant.capability,
|
|
13
|
+
description: describeCapability(grant.capability),
|
|
14
|
+
grantedAt: grant.grantedAt,
|
|
15
|
+
}));
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Revokes `capability` for `pluginName` and reports whether it is now
|
|
19
|
+
* genuinely absent from the plugin's SDK — not merely "marked revoked in a
|
|
20
|
+
* table somewhere". Callers that only need the write can call
|
|
21
|
+
* `PluginGrantStore.revoke` directly; this wrapper exists for the one place
|
|
22
|
+
* that needs the end-to-end confirmation (a UI action that wants to know
|
|
23
|
+
* the revocation actually took effect before saying so to the user).
|
|
24
|
+
*/
|
|
25
|
+
export async function revokeCapability(manifest, capability, grantStore) {
|
|
26
|
+
await grantStore.revoke(manifest.name, capability);
|
|
27
|
+
const remaining = await grantStore.listGrants(manifest.name);
|
|
28
|
+
const stillGranted = remaining.some((grant) => grant.capability === capability);
|
|
29
|
+
return { stillGranted };
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* "## Les mises à jour de plugins": `detectCapabilitiesNeedingApproval`
|
|
33
|
+
* (task 5) already computes WHICH capabilities a new manifest declares
|
|
34
|
+
* beyond what was previously granted — this is that same list, translated,
|
|
35
|
+
* for a real "new permissions requested" section next to the plugin's
|
|
36
|
+
* existing granted-permissions review (never re-approving is the SDK's job,
|
|
37
|
+
* already handled structurally by `resolveGrantedCapabilities`; this is
|
|
38
|
+
* only about making the pending set visible to a human, and giving them the
|
|
39
|
+
* exact capability strings a real approval action needs).
|
|
40
|
+
*/
|
|
41
|
+
export async function describePendingApproval(newManifest, grantStore) {
|
|
42
|
+
const currentGrants = await grantStore.listGrants(newManifest.name);
|
|
43
|
+
const pending = detectCapabilitiesNeedingApproval(newManifest, currentGrants.map((grant) => grant.capability));
|
|
44
|
+
return pending.map((capability) => ({ capability, description: describeCapability(capability) }));
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=review.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review.js","sourceRoot":"","sources":["../../src/permissions/review.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAoC,MAAM,eAAe,CAAA;AAEpF,OAAO,EAAE,iCAAiC,EAAE,MAAM,cAAc,CAAA;AAehE;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,UAAkB,EAClB,UAA4B;IAE5B,MAAM,MAAM,GAA2B,MAAM,UAAU,CAAC,UAAU,CAAC,UAAU,CAAC,CAAA;IAC9E,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC5B,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,WAAW,EAAE,kBAAkB,CAAC,KAAK,CAAC,UAAU,CAAC;QACjD,SAAS,EAAE,KAAK,CAAC,SAAS;KAC3B,CAAC,CAAC,CAAA;AACL,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,QAAwB,EACxB,UAAkB,EAClB,UAA4B;IAE5B,MAAM,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC,CAAA;IAClD,MAAM,SAAS,GAAG,MAAM,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;IAC5D,MAAM,YAAY,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,UAAU,KAAK,UAAU,CAAC,CAAA;IAC/E,OAAO,EAAE,YAAY,EAAE,CAAA;AACzB,CAAC;AAQD;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,WAA2B,EAC3B,UAA4B;IAE5B,MAAM,aAAa,GAAG,MAAM,UAAU,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;IACnE,MAAM,OAAO,GAAG,iCAAiC,CAC/C,WAAW,EACX,aAAa,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,CAC/C,CAAA;IACD,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,WAAW,EAAE,kBAAkB,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAA;AACnG,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type DatabaseHandle } from '@cogenta/core';
|
|
2
|
+
export declare const PERMISSION_TABLES: {
|
|
3
|
+
readonly grants: 'cogenta_plugin_grants';
|
|
4
|
+
readonly disabled: 'cogenta_plugin_disabled';
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Owned by `@cogenta/plugins`, following `@cogenta/channels`'s
|
|
8
|
+
* `ensureChannelTables` pattern exactly (itself following `@cogenta/auth`'s
|
|
9
|
+
* `ensureAuthTables`): `create table if not exists`, run once at startup, no
|
|
10
|
+
* separate migration file.
|
|
11
|
+
*
|
|
12
|
+
* A grant is keyed to the EXACT capability string (`http.fetch:api.exemple.com`,
|
|
13
|
+
* not just the bare name `http.fetch`) — task 1's grammar already makes the
|
|
14
|
+
* parameter part of the capability's identity, so a grant never implicitly
|
|
15
|
+
* covers a different parameter of the same bare name.
|
|
16
|
+
*/
|
|
17
|
+
export declare function ensurePluginTables(db: DatabaseHandle): Promise<void>;
|
|
18
|
+
//# sourceMappingURL=tables.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tables.d.ts","sourceRoot":"","sources":["../../src/permissions/tables.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EAKpB,MAAM,eAAe,CAAA;AAEtB,eAAO,MAAM,iBAAiB;aAC5B,MAAM,EAAE,uBAAuB;aAC/B,QAAQ,EAAE,yBAAyB;CAC3B,CAAA;AAMV;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,CAAC,EAAE,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CA8B1E"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { identifier, sql, unsafeRaw, } from '@cogenta/core';
|
|
2
|
+
export const PERMISSION_TABLES = {
|
|
3
|
+
grants: 'cogenta_plugin_grants',
|
|
4
|
+
disabled: 'cogenta_plugin_disabled',
|
|
5
|
+
};
|
|
6
|
+
function textColumn(dialect, length) {
|
|
7
|
+
return unsafeRaw(dialect === 'sqlite' ? 'text' : `varchar(${length})`);
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Owned by `@cogenta/plugins`, following `@cogenta/channels`'s
|
|
11
|
+
* `ensureChannelTables` pattern exactly (itself following `@cogenta/auth`'s
|
|
12
|
+
* `ensureAuthTables`): `create table if not exists`, run once at startup, no
|
|
13
|
+
* separate migration file.
|
|
14
|
+
*
|
|
15
|
+
* A grant is keyed to the EXACT capability string (`http.fetch:api.exemple.com`,
|
|
16
|
+
* not just the bare name `http.fetch`) — task 1's grammar already makes the
|
|
17
|
+
* parameter part of the capability's identity, so a grant never implicitly
|
|
18
|
+
* covers a different parameter of the same bare name.
|
|
19
|
+
*/
|
|
20
|
+
export async function ensurePluginTables(db) {
|
|
21
|
+
const d = db.dialect;
|
|
22
|
+
const grants = identifier(PERMISSION_TABLES.grants, d);
|
|
23
|
+
const t255 = textColumn(d, 255);
|
|
24
|
+
const t512 = textColumn(d, 512);
|
|
25
|
+
await db.query(sql `
|
|
26
|
+
create table if not exists ${grants} (
|
|
27
|
+
id ${t255} not null primary key,
|
|
28
|
+
plugin_name ${t255} not null,
|
|
29
|
+
capability ${t512} not null,
|
|
30
|
+
granted_at ${t255} not null,
|
|
31
|
+
revoked_at ${t255}
|
|
32
|
+
)`);
|
|
33
|
+
await createIndexIfMissing(db, 'cogenta_plugin_grants_lookup', grants, sql `(plugin_name, capability)`);
|
|
34
|
+
const disabled = identifier(PERMISSION_TABLES.disabled, d);
|
|
35
|
+
await db.query(sql `
|
|
36
|
+
create table if not exists ${disabled} (
|
|
37
|
+
plugin_name ${t255} not null primary key,
|
|
38
|
+
reason ${t255} not null,
|
|
39
|
+
details ${t512},
|
|
40
|
+
disabled_at ${t255} not null
|
|
41
|
+
)`);
|
|
42
|
+
}
|
|
43
|
+
async function createIndexIfMissing(db, name, table, columns) {
|
|
44
|
+
await db
|
|
45
|
+
.query(sql `create index ${identifier(name, db.dialect)} on ${table} ${columns}`)
|
|
46
|
+
.catch(() => undefined); // already there — no portable "if not exists" for indexes
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=tables.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tables.js","sourceRoot":"","sources":["../../src/permissions/tables.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,UAAU,EAEV,GAAG,EACH,SAAS,GACV,MAAM,eAAe,CAAA;AAEtB,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,MAAM,EAAE,uBAAuB;IAC/B,QAAQ,EAAE,yBAAyB;CAC3B,CAAA;AAEV,SAAS,UAAU,CAAC,OAAwB,EAAE,MAAc;IAC1D,OAAO,SAAS,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,MAAM,GAAG,CAAC,CAAA;AACxE,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,EAAkB;IACzD,MAAM,CAAC,GAAG,EAAE,CAAC,OAAO,CAAA;IACpB,MAAM,MAAM,GAAG,UAAU,CAAC,iBAAiB,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;IACtD,MAAM,IAAI,GAAG,UAAU,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;IAC/B,MAAM,IAAI,GAAG,UAAU,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;IAE/B,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,CAAA;iCACa,MAAM;WAC5B,IAAI;oBACK,IAAI;mBACL,IAAI;mBACJ,IAAI;mBACJ,IAAI;MACjB,CAAC,CAAA;IAEL,MAAM,oBAAoB,CACxB,EAAE,EACF,8BAA8B,EAC9B,MAAM,EACN,GAAG,CAAA,2BAA2B,CAC/B,CAAA;IAED,MAAM,QAAQ,GAAG,UAAU,CAAC,iBAAiB,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAA;IAC1D,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,CAAA;iCACa,QAAQ;oBACrB,IAAI;eACT,IAAI;gBACH,IAAI;oBACA,IAAI;MAClB,CAAC,CAAA;AACP,CAAC;AAED,KAAK,UAAU,oBAAoB,CACjC,EAAkB,EAClB,IAAY,EACZ,KAAkB,EAClB,OAAoB;IAEpB,MAAM,EAAE;SACL,KAAK,CAAC,GAAG,CAAA,gBAAgB,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,KAAK,IAAI,OAAO,EAAE,CAAC;SAC/E,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAA,CAAC,0DAA0D;AACtF,CAAC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { type DatabaseHandle } from '@cogenta/core';
|
|
2
|
+
export type PluginSubmissionStatus = 'pending' | 'accepted' | 'rejected';
|
|
3
|
+
export interface PluginSubmissionInput {
|
|
4
|
+
readonly submitterId: string;
|
|
5
|
+
readonly displayName: string;
|
|
6
|
+
readonly description?: string;
|
|
7
|
+
/** Raw manifest input, unvalidated until `submit()` runs it through `definePlugin`. */
|
|
8
|
+
readonly manifest: unknown;
|
|
9
|
+
/** Base64 Ed25519 signature over the manifest's canonical content, or `null` for none. */
|
|
10
|
+
readonly signatureBase64: string | null;
|
|
11
|
+
}
|
|
12
|
+
export interface PluginSubmissionEntry {
|
|
13
|
+
readonly id: string;
|
|
14
|
+
readonly submitterId: string;
|
|
15
|
+
readonly displayName: string;
|
|
16
|
+
readonly description: string | null;
|
|
17
|
+
readonly status: PluginSubmissionStatus;
|
|
18
|
+
/** From the validated manifest — `null` when an automatic gate rejected the submission. */
|
|
19
|
+
readonly pluginName: string | null;
|
|
20
|
+
readonly pluginVersion: string | null;
|
|
21
|
+
/** Set only for an automatic-gate rejection (signature or manifest) — never for a human decision. */
|
|
22
|
+
readonly rejectionCode: string | null;
|
|
23
|
+
readonly rejectionReason: string | null;
|
|
24
|
+
readonly reviewedBy: string | null;
|
|
25
|
+
readonly reviewedAt: string | null;
|
|
26
|
+
readonly submittedAt: string;
|
|
27
|
+
}
|
|
28
|
+
export type PluginReviewDecision = 'accept' | 'reject';
|
|
29
|
+
export type PluginReviewResult = {
|
|
30
|
+
readonly ok: true;
|
|
31
|
+
readonly entry: PluginSubmissionEntry;
|
|
32
|
+
} | {
|
|
33
|
+
readonly ok: false;
|
|
34
|
+
readonly reason: 'not_found';
|
|
35
|
+
} | {
|
|
36
|
+
readonly ok: false;
|
|
37
|
+
readonly reason: 'already_decided';
|
|
38
|
+
readonly entry: PluginSubmissionEntry;
|
|
39
|
+
};
|
|
40
|
+
export interface PluginRegistryOptions {
|
|
41
|
+
readonly trustedPublicKeys?: readonly string[];
|
|
42
|
+
}
|
|
43
|
+
export interface PluginRegistry {
|
|
44
|
+
/**
|
|
45
|
+
* Runs the submission through the lot's own three named gates
|
|
46
|
+
* ("Signature, manifeste, revue" — docs/lots/L7-extensibilite.md § Registres),
|
|
47
|
+
* in order:
|
|
48
|
+
*
|
|
49
|
+
* (1) **Signature** — checked first, against the raw, not-yet-validated
|
|
50
|
+
* manifest content. Signature is the more fundamental trust question: a
|
|
51
|
+
* submission with no valid signature from a trusted registry key is
|
|
52
|
+
* refused before any structural inspection runs, so an unsigned/untrusted
|
|
53
|
+
* submission can never use manifest-validation error messages as an
|
|
54
|
+
* oracle to probe this registry's rules.
|
|
55
|
+
* (2) **Manifeste** — task 1's real `definePlugin`, unchanged and
|
|
56
|
+
* unre-implemented: the exact same four hard refusals (unscoped
|
|
57
|
+
* `http.fetch`, storage outside the plugin's own prefix, unknown
|
|
58
|
+
* capability, block without `fallback`) plus every structural rule apply
|
|
59
|
+
* here, identically to a manifest loaded straight off disk.
|
|
60
|
+
* (3) **Revue** — a submission that clears both automatic gates reaches
|
|
61
|
+
* `pending`, exactly mirroring the Skills registry's (task 11) two-step
|
|
62
|
+
* state machine: automatic pre-check necessary but not sufficient, a real
|
|
63
|
+
* human decision required before acceptance. Plugins execute code — the
|
|
64
|
+
* one property distinguishing this registry from every other one in the
|
|
65
|
+
* lot's table — so no registry here is ever automatic-only.
|
|
66
|
+
*/
|
|
67
|
+
submit(input: PluginSubmissionInput): Promise<PluginSubmissionEntry>;
|
|
68
|
+
/** A human reviewer's accept/reject decision on a `pending` submission. */
|
|
69
|
+
review(id: string, decision: PluginReviewDecision, reviewerUserId: string, notes?: string): Promise<PluginReviewResult>;
|
|
70
|
+
listAccepted(): Promise<readonly PluginSubmissionEntry[]>;
|
|
71
|
+
get(id: string): Promise<PluginSubmissionEntry | null>;
|
|
72
|
+
}
|
|
73
|
+
export declare function createPluginRegistry(db: DatabaseHandle, options?: PluginRegistryOptions, now?: () => number): PluginRegistry;
|
|
74
|
+
//# sourceMappingURL=plugins.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugins.d.ts","sourceRoot":"","sources":["../../src/registries/plugins.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,cAAc,EAA0B,MAAM,eAAe,CAAA;AAKzF,MAAM,MAAM,sBAAsB,GAAG,SAAS,GAAG,UAAU,GAAG,UAAU,CAAA;AAExE,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,uFAAuF;IACvF,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;IAC1B,0FAA0F;IAC1F,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;CACxC;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IACnC,QAAQ,CAAC,MAAM,EAAE,sBAAsB,CAAA;IACvC,2FAA2F;IAC3F,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IACrC,qGAAqG;IACrG,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IACrC,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IACvC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;CAC7B;AAED,MAAM,MAAM,oBAAoB,GAAG,QAAQ,GAAG,QAAQ,CAAA;AAEtD,MAAM,MAAM,kBAAkB,GAC1B;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,qBAAqB,CAAA;CAAE,GAC5D;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;CAAE,GACpD;IACE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAA;IAClB,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAA;IAClC,QAAQ,CAAC,KAAK,EAAE,qBAAqB,CAAA;CACtC,CAAA;AAEL,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAC/C;AAED,MAAM,WAAW,cAAc;IAC7B;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,MAAM,CAAC,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAA;IACpE,2EAA2E;IAC3E,MAAM,CACJ,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,oBAAoB,EAC9B,cAAc,EAAE,MAAM,EACtB,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,kBAAkB,CAAC,CAAA;IAC9B,YAAY,IAAI,OAAO,CAAC,SAAS,qBAAqB,EAAE,CAAC,CAAA;IACzD,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAAA;CACvD;AAoCD,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,cAAc,EAClB,OAAO,GAAE,qBAA0B,EACnC,GAAG,GAAE,MAAM,MAAiB,GAC3B,cAAc,CAsHhB"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { CogentaError, identifier, newId, sql } from '@cogenta/core';
|
|
2
|
+
import { definePlugin } from '../manifest.js';
|
|
3
|
+
import { TRUSTED_REGISTRY_PUBLIC_KEYS, verifyContentAgainstTrustedKeys } from '../signing/verify.js';
|
|
4
|
+
import { REGISTRY_TABLES } from './tables.js';
|
|
5
|
+
function toEntry(row) {
|
|
6
|
+
const status = row.status === 'accepted' ? 'accepted' : row.status === 'pending' ? 'pending' : 'rejected';
|
|
7
|
+
return {
|
|
8
|
+
id: row.id,
|
|
9
|
+
submitterId: row.submitter_id,
|
|
10
|
+
displayName: row.display_name,
|
|
11
|
+
description: row.description,
|
|
12
|
+
status,
|
|
13
|
+
pluginName: row.plugin_name,
|
|
14
|
+
pluginVersion: row.plugin_version,
|
|
15
|
+
rejectionCode: row.rejection_code,
|
|
16
|
+
rejectionReason: row.rejection_reason,
|
|
17
|
+
reviewedBy: row.reviewed_by,
|
|
18
|
+
reviewedAt: row.reviewed_at,
|
|
19
|
+
submittedAt: row.submitted_at,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export function createPluginRegistry(db, options = {}, now = Date.now) {
|
|
23
|
+
const plugins = identifier(REGISTRY_TABLES.plugins, db.dialect);
|
|
24
|
+
const trustedPublicKeys = options.trustedPublicKeys ?? TRUSTED_REGISTRY_PUBLIC_KEYS;
|
|
25
|
+
return {
|
|
26
|
+
async submit(input) {
|
|
27
|
+
const id = newId(now);
|
|
28
|
+
const submittedAt = new Date(now()).toISOString();
|
|
29
|
+
let status = 'pending';
|
|
30
|
+
let pluginName = null;
|
|
31
|
+
let pluginVersion = null;
|
|
32
|
+
let rejectionCode = null;
|
|
33
|
+
let rejectionReason = null;
|
|
34
|
+
const signed = verifyContentAgainstTrustedKeys(input.manifest, input.signatureBase64, trustedPublicKeys);
|
|
35
|
+
if (!signed) {
|
|
36
|
+
status = 'rejected';
|
|
37
|
+
rejectionCode =
|
|
38
|
+
input.signatureBase64 === null ? 'PLUGIN_SIGNATURE_MISSING' : 'PLUGIN_SIGNATURE_INVALID';
|
|
39
|
+
rejectionReason =
|
|
40
|
+
input.signatureBase64 === null
|
|
41
|
+
? `The plugin "${input.displayName}" was submitted with no signature.`
|
|
42
|
+
: `The plugin "${input.displayName}" has no valid signature from a trusted registry key.`;
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
try {
|
|
46
|
+
const manifest = definePlugin(input.manifest);
|
|
47
|
+
pluginName = manifest.name;
|
|
48
|
+
pluginVersion = manifest.version;
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
status = 'rejected';
|
|
52
|
+
rejectionCode = error instanceof CogentaError ? error.code : 'PLUGIN_MANIFEST_INVALID';
|
|
53
|
+
rejectionReason = error instanceof Error ? error.message : String(error);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const description = input.description ?? null;
|
|
57
|
+
await db.query(sql `
|
|
58
|
+
insert into ${plugins}
|
|
59
|
+
(id, submitter_id, display_name, description, plugin_name, plugin_version,
|
|
60
|
+
status, rejection_code, rejection_reason, reviewed_by, reviewed_at, submitted_at)
|
|
61
|
+
values
|
|
62
|
+
(${id}, ${input.submitterId}, ${input.displayName}, ${description},
|
|
63
|
+
${pluginName}, ${pluginVersion}, ${status}, ${rejectionCode}, ${rejectionReason},
|
|
64
|
+
${null}, ${null}, ${submittedAt})`);
|
|
65
|
+
return {
|
|
66
|
+
id,
|
|
67
|
+
submitterId: input.submitterId,
|
|
68
|
+
displayName: input.displayName,
|
|
69
|
+
description,
|
|
70
|
+
status,
|
|
71
|
+
pluginName,
|
|
72
|
+
pluginVersion,
|
|
73
|
+
rejectionCode,
|
|
74
|
+
rejectionReason,
|
|
75
|
+
reviewedBy: null,
|
|
76
|
+
reviewedAt: null,
|
|
77
|
+
submittedAt,
|
|
78
|
+
};
|
|
79
|
+
},
|
|
80
|
+
async review(id, decision, reviewerUserId, notes) {
|
|
81
|
+
const result = await db.query(sql `
|
|
82
|
+
select id, submitter_id, display_name, description, plugin_name, plugin_version, status,
|
|
83
|
+
rejection_code, rejection_reason, reviewed_by, reviewed_at, submitted_at
|
|
84
|
+
from ${plugins} where id = ${id}`);
|
|
85
|
+
const row = result.rows[0];
|
|
86
|
+
if (row === undefined)
|
|
87
|
+
return { ok: false, reason: 'not_found' };
|
|
88
|
+
const current = toEntry(row);
|
|
89
|
+
if (current.status !== 'pending')
|
|
90
|
+
return { ok: false, reason: 'already_decided', entry: current };
|
|
91
|
+
const reviewedAt = new Date(now()).toISOString();
|
|
92
|
+
const nextStatus = decision === 'accept' ? 'accepted' : 'rejected';
|
|
93
|
+
const rejectionReason = decision === 'reject' ? (notes ?? null) : null;
|
|
94
|
+
await db.query(sql `
|
|
95
|
+
update ${plugins}
|
|
96
|
+
set status = ${nextStatus}, rejection_reason = ${rejectionReason},
|
|
97
|
+
reviewed_by = ${reviewerUserId}, reviewed_at = ${reviewedAt}
|
|
98
|
+
where id = ${id}`);
|
|
99
|
+
return {
|
|
100
|
+
ok: true,
|
|
101
|
+
entry: {
|
|
102
|
+
...current,
|
|
103
|
+
status: nextStatus,
|
|
104
|
+
rejectionReason,
|
|
105
|
+
reviewedBy: reviewerUserId,
|
|
106
|
+
reviewedAt,
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
},
|
|
110
|
+
async listAccepted() {
|
|
111
|
+
const result = await db.query(sql `
|
|
112
|
+
select id, submitter_id, display_name, description, plugin_name, plugin_version, status,
|
|
113
|
+
rejection_code, rejection_reason, reviewed_by, reviewed_at, submitted_at
|
|
114
|
+
from ${plugins} where status = 'accepted' order by submitted_at asc`);
|
|
115
|
+
return result.rows.map(toEntry);
|
|
116
|
+
},
|
|
117
|
+
async get(id) {
|
|
118
|
+
const result = await db.query(sql `
|
|
119
|
+
select id, submitter_id, display_name, description, plugin_name, plugin_version, status,
|
|
120
|
+
rejection_code, rejection_reason, reviewed_by, reviewed_at, submitted_at
|
|
121
|
+
from ${plugins} where id = ${id}`);
|
|
122
|
+
const row = result.rows[0];
|
|
123
|
+
return row === undefined ? null : toEntry(row);
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=plugins.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugins.js","sourceRoot":"","sources":["../../src/registries/plugins.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { type DatabaseHandle } from '@cogenta/core';
|
|
2
|
+
export type SkillSubmissionStatus = 'pending' | 'accepted' | 'rejected';
|
|
3
|
+
export interface SkillSubmissionInput {
|
|
4
|
+
readonly submitterId: string;
|
|
5
|
+
readonly displayName: string;
|
|
6
|
+
readonly description?: string;
|
|
7
|
+
/** The skill file's raw frontmatter+instructions text, in `parseSkillFile`'s real format. */
|
|
8
|
+
readonly rawContent: string;
|
|
9
|
+
}
|
|
10
|
+
export interface SkillSubmissionEntry {
|
|
11
|
+
readonly id: string;
|
|
12
|
+
readonly submitterId: string;
|
|
13
|
+
readonly displayName: string;
|
|
14
|
+
readonly description: string | null;
|
|
15
|
+
readonly status: SkillSubmissionStatus;
|
|
16
|
+
/** From the parsed skill's own frontmatter — `null` when the automatic parse pre-check failed. */
|
|
17
|
+
readonly skillName: string | null;
|
|
18
|
+
readonly skillVersion: string | null;
|
|
19
|
+
/** Set only for an automatic parse-failure rejection — never for a human decision. */
|
|
20
|
+
readonly rejectionCode: string | null;
|
|
21
|
+
readonly rejectionReason: string | null;
|
|
22
|
+
readonly reviewedBy: string | null;
|
|
23
|
+
readonly reviewedAt: string | null;
|
|
24
|
+
readonly submittedAt: string;
|
|
25
|
+
}
|
|
26
|
+
export type SkillReviewDecision = 'accept' | 'reject';
|
|
27
|
+
export type SkillReviewResult = {
|
|
28
|
+
readonly ok: true;
|
|
29
|
+
readonly entry: SkillSubmissionEntry;
|
|
30
|
+
} | {
|
|
31
|
+
readonly ok: false;
|
|
32
|
+
readonly reason: 'not_found';
|
|
33
|
+
} | {
|
|
34
|
+
readonly ok: false;
|
|
35
|
+
readonly reason: 'already_decided';
|
|
36
|
+
readonly entry: SkillSubmissionEntry;
|
|
37
|
+
};
|
|
38
|
+
export interface SkillRegistry {
|
|
39
|
+
/**
|
|
40
|
+
* Runs the submission through `@cogenta/agents`'s real `parseSkillFile` as
|
|
41
|
+
* a necessary-but-not-sufficient automatic pre-check: content that doesn't
|
|
42
|
+
* even parse as a skill file is rejected immediately, with the real parse
|
|
43
|
+
* error — but content that DOES parse only reaches `pending`, since the
|
|
44
|
+
* lot's own table requires "Revue de contenu" (human review) for skills,
|
|
45
|
+
* unlike the Skins gallery's fully automatic gate.
|
|
46
|
+
*/
|
|
47
|
+
submit(input: SkillSubmissionInput): Promise<SkillSubmissionEntry>;
|
|
48
|
+
/** A human reviewer's accept/reject decision on a `pending` submission. */
|
|
49
|
+
review(id: string, decision: SkillReviewDecision, reviewerUserId: string, notes?: string): Promise<SkillReviewResult>;
|
|
50
|
+
listAccepted(): Promise<readonly SkillSubmissionEntry[]>;
|
|
51
|
+
get(id: string): Promise<SkillSubmissionEntry | null>;
|
|
52
|
+
}
|
|
53
|
+
export declare function createSkillRegistry(db: DatabaseHandle, now?: () => number): SkillRegistry;
|
|
54
|
+
//# sourceMappingURL=skills.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/registries/skills.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,KAAK,cAAc,EAA0B,MAAM,eAAe,CAAA;AAGzF,MAAM,MAAM,qBAAqB,GAAG,SAAS,GAAG,UAAU,GAAG,UAAU,CAAA;AAEvE,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,6FAA6F;IAC7F,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAC5B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IACnC,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAA;IACtC,kGAAkG;IAClG,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IACpC,sFAAsF;IACtF,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IACrC,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IACvC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;CAC7B;AAED,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,QAAQ,CAAA;AAErD,MAAM,MAAM,iBAAiB,GACzB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,oBAAoB,CAAA;CAAE,GAC3D;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;CAAE,GACpD;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,oBAAoB,CAAA;CAAE,CAAA;AAEpG,MAAM,WAAW,aAAa;IAC5B;;;;;;;OAOG;IACH,MAAM,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAA;IAClE,2EAA2E;IAC3E,MAAM,CACJ,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,mBAAmB,EAC7B,cAAc,EAAE,MAAM,EACtB,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,iBAAiB,CAAC,CAAA;IAC7B,YAAY,IAAI,OAAO,CAAC,SAAS,oBAAoB,EAAE,CAAC,CAAA;IACxD,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAAA;CACtD;AAoCD,wBAAgB,mBAAmB,CACjC,EAAE,EAAE,cAAc,EAClB,GAAG,GAAE,MAAM,MAAiB,GAC3B,aAAa,CAoGf"}
|