@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.
Files changed (86) hide show
  1. package/dist/guest/sandbox-entry.mjs +155 -0
  2. package/dist/host/capabilities.d.ts +46 -0
  3. package/dist/host/capabilities.d.ts.map +1 -0
  4. package/dist/host/capabilities.js +105 -0
  5. package/dist/host/capabilities.js.map +1 -0
  6. package/dist/host/protocol.d.ts +58 -0
  7. package/dist/host/protocol.d.ts.map +1 -0
  8. package/dist/host/protocol.js +10 -0
  9. package/dist/host/protocol.js.map +1 -0
  10. package/dist/host/worker-runner.d.ts +92 -0
  11. package/dist/host/worker-runner.d.ts.map +1 -0
  12. package/dist/host/worker-runner.js +196 -0
  13. package/dist/host/worker-runner.js.map +1 -0
  14. package/dist/index.d.ts +34 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +20 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/loader.d.ts +81 -0
  19. package/dist/loader.d.ts.map +1 -0
  20. package/dist/loader.js +190 -0
  21. package/dist/loader.js.map +1 -0
  22. package/dist/manifest.d.ts +93 -0
  23. package/dist/manifest.d.ts.map +1 -0
  24. package/dist/manifest.js +197 -0
  25. package/dist/manifest.js.map +1 -0
  26. package/dist/permissions/describe.d.ts +22 -0
  27. package/dist/permissions/describe.d.ts.map +1 -0
  28. package/dist/permissions/describe.js +158 -0
  29. package/dist/permissions/describe.js.map +1 -0
  30. package/dist/permissions/disabled.d.ts +25 -0
  31. package/dist/permissions/disabled.d.ts.map +1 -0
  32. package/dist/permissions/disabled.js +29 -0
  33. package/dist/permissions/disabled.js.map +1 -0
  34. package/dist/permissions/grants.d.ts +22 -0
  35. package/dist/permissions/grants.d.ts.map +1 -0
  36. package/dist/permissions/grants.js +31 -0
  37. package/dist/permissions/grants.js.map +1 -0
  38. package/dist/permissions/resolve.d.ts +47 -0
  39. package/dist/permissions/resolve.d.ts.map +1 -0
  40. package/dist/permissions/resolve.js +51 -0
  41. package/dist/permissions/resolve.js.map +1 -0
  42. package/dist/permissions/review.d.ts +50 -0
  43. package/dist/permissions/review.d.ts.map +1 -0
  44. package/dist/permissions/review.js +46 -0
  45. package/dist/permissions/review.js.map +1 -0
  46. package/dist/permissions/tables.d.ts +18 -0
  47. package/dist/permissions/tables.d.ts.map +1 -0
  48. package/dist/permissions/tables.js +48 -0
  49. package/dist/permissions/tables.js.map +1 -0
  50. package/dist/registries/plugins.d.ts +74 -0
  51. package/dist/registries/plugins.d.ts.map +1 -0
  52. package/dist/registries/plugins.js +127 -0
  53. package/dist/registries/plugins.js.map +1 -0
  54. package/dist/registries/skills.d.ts +54 -0
  55. package/dist/registries/skills.d.ts.map +1 -0
  56. package/dist/registries/skills.js +113 -0
  57. package/dist/registries/skills.js.map +1 -0
  58. package/dist/registries/skins.d.ts +33 -0
  59. package/dist/registries/skins.d.ts.map +1 -0
  60. package/dist/registries/skins.js +65 -0
  61. package/dist/registries/skins.js.map +1 -0
  62. package/dist/registries/tables.d.ts +44 -0
  63. package/dist/registries/tables.d.ts.map +1 -0
  64. package/dist/registries/tables.js +118 -0
  65. package/dist/registries/tables.js.map +1 -0
  66. package/dist/registries/themes.d.ts +59 -0
  67. package/dist/registries/themes.d.ts.map +1 -0
  68. package/dist/registries/themes.js +82 -0
  69. package/dist/registries/themes.js.map +1 -0
  70. package/dist/semver.d.ts +24 -0
  71. package/dist/semver.d.ts.map +1 -0
  72. package/dist/semver.js +93 -0
  73. package/dist/semver.js.map +1 -0
  74. package/dist/signing/keys.d.ts +18 -0
  75. package/dist/signing/keys.d.ts.map +1 -0
  76. package/dist/signing/keys.js +15 -0
  77. package/dist/signing/keys.js.map +1 -0
  78. package/dist/signing/sign.d.ts +35 -0
  79. package/dist/signing/sign.d.ts.map +1 -0
  80. package/dist/signing/sign.js +63 -0
  81. package/dist/signing/sign.js.map +1 -0
  82. package/dist/signing/verify.d.ts +40 -0
  83. package/dist/signing/verify.d.ts.map +1 -0
  84. package/dist/signing/verify.js +73 -0
  85. package/dist/signing/verify.js.map +1 -0
  86. 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"}