@ai-agent-forge/plugin-sdk 0.85.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 (58) hide show
  1. package/README.md +27 -0
  2. package/dist/artifact.d.ts +20 -0
  3. package/dist/artifact.d.ts.map +1 -0
  4. package/dist/artifact.js +63 -0
  5. package/dist/artifact.js.map +1 -0
  6. package/dist/capability-manifest.d.ts +11 -0
  7. package/dist/capability-manifest.d.ts.map +1 -0
  8. package/dist/capability-manifest.js +188 -0
  9. package/dist/capability-manifest.js.map +1 -0
  10. package/dist/common.d.ts +24 -0
  11. package/dist/common.d.ts.map +1 -0
  12. package/dist/common.js +115 -0
  13. package/dist/common.js.map +1 -0
  14. package/dist/context-budget.d.ts +33 -0
  15. package/dist/context-budget.d.ts.map +1 -0
  16. package/dist/context-budget.js +124 -0
  17. package/dist/context-budget.js.map +1 -0
  18. package/dist/diff.d.ts +38 -0
  19. package/dist/diff.d.ts.map +1 -0
  20. package/dist/diff.js +164 -0
  21. package/dist/diff.js.map +1 -0
  22. package/dist/durable.d.ts +108 -0
  23. package/dist/durable.d.ts.map +1 -0
  24. package/dist/durable.js +15 -0
  25. package/dist/durable.js.map +1 -0
  26. package/dist/ecosystem-manifest.d.ts +56 -0
  27. package/dist/ecosystem-manifest.d.ts.map +1 -0
  28. package/dist/ecosystem-manifest.js +11 -0
  29. package/dist/ecosystem-manifest.js.map +1 -0
  30. package/dist/index.d.ts +13 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +13 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/memory.d.ts +370 -0
  35. package/dist/memory.d.ts.map +1 -0
  36. package/dist/memory.js +26 -0
  37. package/dist/memory.js.map +1 -0
  38. package/dist/observability.d.ts +354 -0
  39. package/dist/observability.d.ts.map +1 -0
  40. package/dist/observability.js +33 -0
  41. package/dist/observability.js.map +1 -0
  42. package/dist/operation.d.ts +60 -0
  43. package/dist/operation.d.ts.map +1 -0
  44. package/dist/operation.js +202 -0
  45. package/dist/operation.js.map +1 -0
  46. package/dist/public-api.d.ts +1977 -0
  47. package/dist/public-api.d.ts.map +1 -0
  48. package/dist/public-api.js +237 -0
  49. package/dist/public-api.js.map +1 -0
  50. package/dist/render.d.ts +38 -0
  51. package/dist/render.d.ts.map +1 -0
  52. package/dist/render.js +112 -0
  53. package/dist/render.js.map +1 -0
  54. package/dist/session-lineage.d.ts +36 -0
  55. package/dist/session-lineage.d.ts.map +1 -0
  56. package/dist/session-lineage.js +134 -0
  57. package/dist/session-lineage.js.map +1 -0
  58. package/package.json +55 -0
package/README.md ADDED
@@ -0,0 +1,27 @@
1
+ # @agent-forge/plugin-sdk
2
+
3
+ Shared, transport-neutral contracts used by first-party and third-party Agent Forge plugins. Third-party plugin developers install this package as a development dependency; the host re-exports the same modules as `PluginContractsV1`.
4
+
5
+ ## Modules
6
+
7
+ - `artifact`: `ArtifactRefV1` opaque artifact handles and validation.
8
+ - `operation`: `PluginOperationV1`, `PluginResultV1`, `EvidenceRefV1`, `VerificationV1`, `PluginErrorV1`.
9
+ - `diff`: `DiffRequestV1` / `DiffResultV1` comparisons.
10
+ - `render`: `RenderRequestV1` / `RenderResultV1` surface rendering.
11
+ - `context-budget`: `projectPluginContextV1` model-visible egress budget enforcement.
12
+ - `common`: JSON helpers (`JsonValue`, `stableStringifyV1`, `detachedFreeze`, assertion utilities).
13
+
14
+ All validators freeze their output and reject unknown fields, so validated values are stable and deterministic across repeated runs.
15
+
16
+ ```ts
17
+ import { buildArtifactRefV1, type ArtifactRefV1 } from "@agent-forge/plugin-sdk";
18
+
19
+ const ref: ArtifactRefV1 = buildArtifactRefV1({
20
+ version: 1,
21
+ artifactRef: "artifact:example",
22
+ kind: "screenshot",
23
+ mimeType: "image/png",
24
+ });
25
+ ```
26
+
27
+ SDK versions align with the host `apiVersion` milestones (`插件独立分发与启动装配设计.md` §4.7).
@@ -0,0 +1,20 @@
1
+ export interface ArtifactRefV1 {
2
+ readonly version: 1;
3
+ /** Opaque host reference. It must not be a machine-local path. */
4
+ readonly artifactRef: string;
5
+ readonly kind: string;
6
+ readonly mimeType: string;
7
+ readonly digest?: string;
8
+ readonly sizeBytes?: number;
9
+ readonly operationId?: string;
10
+ readonly pluginId?: string;
11
+ }
12
+ /** Opaque handles may carry a host namespace and signed token, but never bytes. */
13
+ export declare const MAX_ARTIFACT_REF_CHARS_V1 = 2048;
14
+ /** Metadata is model-visible and follows the shared inline-string budget. */
15
+ export declare const MAX_ARTIFACT_METADATA_CHARS_V1 = 256;
16
+ export declare function validateArtifactRefV1(value: unknown, label?: string): ArtifactRefV1;
17
+ export declare function buildArtifactRefV1(input: ArtifactRefV1): ArtifactRefV1;
18
+ export declare function isArtifactRefV1(value: unknown): value is ArtifactRefV1;
19
+ export declare function artifactRefKeyV1(ref: ArtifactRefV1): string;
20
+ //# sourceMappingURL=artifact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact.d.ts","sourceRoot":"","sources":["../src/artifact.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IACpB,kEAAkE;IAClE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,mFAAmF;AACnF,eAAO,MAAM,yBAAyB,OAAO,CAAC;AAC9C,6EAA6E;AAC7E,eAAO,MAAM,8BAA8B,MAAM,CAAC;AAalD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,SAAuB,GAAG,aAAa,CAmCjG;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,aAAa,GAAG,aAAa,CAEtE;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,aAAa,CAOtE;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAE3D","sourcesContent":["import {\n\tassertExactKeys,\n\tassertNonEmptyString,\n\tassertNonNegativeSafeInteger,\n\tassertPlainRecord,\n\tdetachedFreeze,\n\tPLUGIN_SHARED_CONTRACT_VERSION_V1,\n} from \"./common.ts\";\n\nexport interface ArtifactRefV1 {\n\treadonly version: 1;\n\t/** Opaque host reference. It must not be a machine-local path. */\n\treadonly artifactRef: string;\n\treadonly kind: string;\n\treadonly mimeType: string;\n\treadonly digest?: string;\n\treadonly sizeBytes?: number;\n\treadonly operationId?: string;\n\treadonly pluginId?: string;\n}\n\n/** Opaque handles may carry a host namespace and signed token, but never bytes. */\nexport const MAX_ARTIFACT_REF_CHARS_V1 = 2048;\n/** Metadata is model-visible and follows the shared inline-string budget. */\nexport const MAX_ARTIFACT_METADATA_CHARS_V1 = 256;\n\nfunction validateBoundedString(value: unknown, label: string, maximum: number): string {\n\tassertNonEmptyString(value, label);\n\tif (value.length > maximum) throw new Error(`${label} exceeds the context budget (${maximum} characters)`);\n\treturn value;\n}\n\nfunction validateDigest(value: unknown, label: string): string | undefined {\n\tif (value === undefined) return undefined;\n\treturn validateBoundedString(value, label, MAX_ARTIFACT_METADATA_CHARS_V1);\n}\n\nexport function validateArtifactRefV1(value: unknown, label = \"Artifact reference\"): ArtifactRefV1 {\n\tassertPlainRecord(value, label);\n\tassertExactKeys(\n\t\tvalue,\n\t\t[\"version\", \"artifactRef\", \"kind\", \"mimeType\"],\n\t\t[\"digest\", \"sizeBytes\", \"operationId\", \"pluginId\"],\n\t\tlabel,\n\t);\n\tif (value.version !== PLUGIN_SHARED_CONTRACT_VERSION_V1) throw new Error(`${label}.version must be 1`);\n\tconst artifactRef = validateBoundedString(value.artifactRef, `${label}.artifactRef`, MAX_ARTIFACT_REF_CHARS_V1);\n\tif (/^(?:file:|[a-zA-Z]:[\\\\/]|[\\\\/]{1,2}|\\\\\\\\)/iu.test(artifactRef)) {\n\t\tthrow new Error(`${label}.artifactRef must be an opaque reference, not a local path`);\n\t}\n\tconst kind = validateBoundedString(value.kind, `${label}.kind`, MAX_ARTIFACT_METADATA_CHARS_V1);\n\tconst mimeType = validateBoundedString(value.mimeType, `${label}.mimeType`, MAX_ARTIFACT_METADATA_CHARS_V1);\n\tconst digest = validateDigest(value.digest, `${label}.digest`);\n\tif (value.sizeBytes !== undefined) assertNonNegativeSafeInteger(value.sizeBytes, `${label}.sizeBytes`);\n\tconst operationId =\n\t\tvalue.operationId === undefined\n\t\t\t? undefined\n\t\t\t: validateBoundedString(value.operationId, `${label}.operationId`, MAX_ARTIFACT_METADATA_CHARS_V1);\n\tconst pluginId =\n\t\tvalue.pluginId === undefined\n\t\t\t? undefined\n\t\t\t: validateBoundedString(value.pluginId, `${label}.pluginId`, MAX_ARTIFACT_METADATA_CHARS_V1);\n\treturn detachedFreeze({\n\t\tversion: 1,\n\t\tartifactRef,\n\t\tkind,\n\t\tmimeType,\n\t\t...(digest === undefined ? {} : { digest }),\n\t\t...(value.sizeBytes === undefined ? {} : { sizeBytes: value.sizeBytes }),\n\t\t...(operationId === undefined ? {} : { operationId }),\n\t\t...(pluginId === undefined ? {} : { pluginId }),\n\t});\n}\n\nexport function buildArtifactRefV1(input: ArtifactRefV1): ArtifactRefV1 {\n\treturn validateArtifactRefV1(input);\n}\n\nexport function isArtifactRefV1(value: unknown): value is ArtifactRefV1 {\n\ttry {\n\t\tvalidateArtifactRefV1(value);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nexport function artifactRefKeyV1(ref: ArtifactRefV1): string {\n\treturn ref.artifactRef;\n}\n"]}
@@ -0,0 +1,63 @@
1
+ import { assertExactKeys, assertNonEmptyString, assertNonNegativeSafeInteger, assertPlainRecord, detachedFreeze, PLUGIN_SHARED_CONTRACT_VERSION_V1, } from "./common.js";
2
+ /** Opaque handles may carry a host namespace and signed token, but never bytes. */
3
+ export const MAX_ARTIFACT_REF_CHARS_V1 = 2048;
4
+ /** Metadata is model-visible and follows the shared inline-string budget. */
5
+ export const MAX_ARTIFACT_METADATA_CHARS_V1 = 256;
6
+ function validateBoundedString(value, label, maximum) {
7
+ assertNonEmptyString(value, label);
8
+ if (value.length > maximum)
9
+ throw new Error(`${label} exceeds the context budget (${maximum} characters)`);
10
+ return value;
11
+ }
12
+ function validateDigest(value, label) {
13
+ if (value === undefined)
14
+ return undefined;
15
+ return validateBoundedString(value, label, MAX_ARTIFACT_METADATA_CHARS_V1);
16
+ }
17
+ export function validateArtifactRefV1(value, label = "Artifact reference") {
18
+ assertPlainRecord(value, label);
19
+ assertExactKeys(value, ["version", "artifactRef", "kind", "mimeType"], ["digest", "sizeBytes", "operationId", "pluginId"], label);
20
+ if (value.version !== PLUGIN_SHARED_CONTRACT_VERSION_V1)
21
+ throw new Error(`${label}.version must be 1`);
22
+ const artifactRef = validateBoundedString(value.artifactRef, `${label}.artifactRef`, MAX_ARTIFACT_REF_CHARS_V1);
23
+ if (/^(?:file:|[a-zA-Z]:[\\/]|[\\/]{1,2}|\\\\)/iu.test(artifactRef)) {
24
+ throw new Error(`${label}.artifactRef must be an opaque reference, not a local path`);
25
+ }
26
+ const kind = validateBoundedString(value.kind, `${label}.kind`, MAX_ARTIFACT_METADATA_CHARS_V1);
27
+ const mimeType = validateBoundedString(value.mimeType, `${label}.mimeType`, MAX_ARTIFACT_METADATA_CHARS_V1);
28
+ const digest = validateDigest(value.digest, `${label}.digest`);
29
+ if (value.sizeBytes !== undefined)
30
+ assertNonNegativeSafeInteger(value.sizeBytes, `${label}.sizeBytes`);
31
+ const operationId = value.operationId === undefined
32
+ ? undefined
33
+ : validateBoundedString(value.operationId, `${label}.operationId`, MAX_ARTIFACT_METADATA_CHARS_V1);
34
+ const pluginId = value.pluginId === undefined
35
+ ? undefined
36
+ : validateBoundedString(value.pluginId, `${label}.pluginId`, MAX_ARTIFACT_METADATA_CHARS_V1);
37
+ return detachedFreeze({
38
+ version: 1,
39
+ artifactRef,
40
+ kind,
41
+ mimeType,
42
+ ...(digest === undefined ? {} : { digest }),
43
+ ...(value.sizeBytes === undefined ? {} : { sizeBytes: value.sizeBytes }),
44
+ ...(operationId === undefined ? {} : { operationId }),
45
+ ...(pluginId === undefined ? {} : { pluginId }),
46
+ });
47
+ }
48
+ export function buildArtifactRefV1(input) {
49
+ return validateArtifactRefV1(input);
50
+ }
51
+ export function isArtifactRefV1(value) {
52
+ try {
53
+ validateArtifactRefV1(value);
54
+ return true;
55
+ }
56
+ catch {
57
+ return false;
58
+ }
59
+ }
60
+ export function artifactRefKeyV1(ref) {
61
+ return ref.artifactRef;
62
+ }
63
+ //# sourceMappingURL=artifact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact.js","sourceRoot":"","sources":["../src/artifact.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tassertExactKeys,\n\tassertNonEmptyString,\n\tassertNonNegativeSafeInteger,\n\tassertPlainRecord,\n\tdetachedFreeze,\n\tPLUGIN_SHARED_CONTRACT_VERSION_V1,\n} from \"./common.ts\";\n\nexport interface ArtifactRefV1 {\n\treadonly version: 1;\n\t/** Opaque host reference. It must not be a machine-local path. */\n\treadonly artifactRef: string;\n\treadonly kind: string;\n\treadonly mimeType: string;\n\treadonly digest?: string;\n\treadonly sizeBytes?: number;\n\treadonly operationId?: string;\n\treadonly pluginId?: string;\n}\n\n/** Opaque handles may carry a host namespace and signed token, but never bytes. */\nexport const MAX_ARTIFACT_REF_CHARS_V1 = 2048;\n/** Metadata is model-visible and follows the shared inline-string budget. */\nexport const MAX_ARTIFACT_METADATA_CHARS_V1 = 256;\n\nfunction validateBoundedString(value: unknown, label: string, maximum: number): string {\n\tassertNonEmptyString(value, label);\n\tif (value.length > maximum) throw new Error(`${label} exceeds the context budget (${maximum} characters)`);\n\treturn value;\n}\n\nfunction validateDigest(value: unknown, label: string): string | undefined {\n\tif (value === undefined) return undefined;\n\treturn validateBoundedString(value, label, MAX_ARTIFACT_METADATA_CHARS_V1);\n}\n\nexport function validateArtifactRefV1(value: unknown, label = \"Artifact reference\"): ArtifactRefV1 {\n\tassertPlainRecord(value, label);\n\tassertExactKeys(\n\t\tvalue,\n\t\t[\"version\", \"artifactRef\", \"kind\", \"mimeType\"],\n\t\t[\"digest\", \"sizeBytes\", \"operationId\", \"pluginId\"],\n\t\tlabel,\n\t);\n\tif (value.version !== PLUGIN_SHARED_CONTRACT_VERSION_V1) throw new Error(`${label}.version must be 1`);\n\tconst artifactRef = validateBoundedString(value.artifactRef, `${label}.artifactRef`, MAX_ARTIFACT_REF_CHARS_V1);\n\tif (/^(?:file:|[a-zA-Z]:[\\\\/]|[\\\\/]{1,2}|\\\\\\\\)/iu.test(artifactRef)) {\n\t\tthrow new Error(`${label}.artifactRef must be an opaque reference, not a local path`);\n\t}\n\tconst kind = validateBoundedString(value.kind, `${label}.kind`, MAX_ARTIFACT_METADATA_CHARS_V1);\n\tconst mimeType = validateBoundedString(value.mimeType, `${label}.mimeType`, MAX_ARTIFACT_METADATA_CHARS_V1);\n\tconst digest = validateDigest(value.digest, `${label}.digest`);\n\tif (value.sizeBytes !== undefined) assertNonNegativeSafeInteger(value.sizeBytes, `${label}.sizeBytes`);\n\tconst operationId =\n\t\tvalue.operationId === undefined\n\t\t\t? undefined\n\t\t\t: validateBoundedString(value.operationId, `${label}.operationId`, MAX_ARTIFACT_METADATA_CHARS_V1);\n\tconst pluginId =\n\t\tvalue.pluginId === undefined\n\t\t\t? undefined\n\t\t\t: validateBoundedString(value.pluginId, `${label}.pluginId`, MAX_ARTIFACT_METADATA_CHARS_V1);\n\treturn detachedFreeze({\n\t\tversion: 1,\n\t\tartifactRef,\n\t\tkind,\n\t\tmimeType,\n\t\t...(digest === undefined ? {} : { digest }),\n\t\t...(value.sizeBytes === undefined ? {} : { sizeBytes: value.sizeBytes }),\n\t\t...(operationId === undefined ? {} : { operationId }),\n\t\t...(pluginId === undefined ? {} : { pluginId }),\n\t});\n}\n\nexport function buildArtifactRefV1(input: ArtifactRefV1): ArtifactRefV1 {\n\treturn validateArtifactRefV1(input);\n}\n\nexport function isArtifactRefV1(value: unknown): value is ArtifactRefV1 {\n\ttry {\n\t\tvalidateArtifactRefV1(value);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nexport function artifactRefKeyV1(ref: ArtifactRefV1): string {\n\treturn ref.artifactRef;\n}\n"]}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Capability plugin manifest schema (plugin.json) and its pure validation.
3
+ *
4
+ * Authority: `@agent-forge/plugin-sdk` (D-075 S2). The host re-exports these
5
+ * symbols from its loader module; filesystem discovery, jiti loading, and
6
+ * lifecycle dispatch stay host-side.
7
+ */
8
+ import type { PluginManifest } from "./public-api.ts";
9
+ /** Parse a capability plugin manifest without accepting malformed fields. */
10
+ export declare function parseCapabilityPluginManifest(value: unknown, manifestPath?: string): PluginManifest;
11
+ //# sourceMappingURL=capability-manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capability-manifest.d.ts","sourceRoot":"","sources":["../src/capability-manifest.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAKX,cAAc,EACd,MAAM,iBAAiB,CAAC;AA+IzB,6EAA6E;AAC7E,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,EAAE,YAAY,SAAe,GAAG,cAAc,CA8DzG","sourcesContent":["/**\n * Capability plugin manifest schema (plugin.json) and its pure validation.\n *\n * Authority: `@agent-forge/plugin-sdk` (D-075 S2). The host re-exports these\n * symbols from its loader module; filesystem discovery, jiti loading, and\n * lifecycle dispatch stay host-side.\n */\n\nimport { validRange } from \"semver\";\nimport type {\n\tAgentDefinitionDeclaration,\n\tPluginAgentRole,\n\tPluginCapabilityDeclaration,\n\tPluginCapabilityRequirement,\n\tPluginManifest,\n} from \"./public-api.ts\";\nimport { EXPERIMENTAL_PUBLIC_API_VERSION } from \"./public-api.ts\";\n\nfunction isStringArray(value: unknown): value is string[] {\n\treturn Array.isArray(value) && value.every((entry) => typeof entry === \"string\");\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isJsonConfigValue(value: unknown): boolean {\n\tif (value === null || typeof value === \"boolean\" || typeof value === \"string\") return true;\n\tif (typeof value === \"number\") return Number.isFinite(value);\n\tif (Array.isArray(value)) return value.every(isJsonConfigValue);\n\tif (!isObject(value)) return false;\n\treturn Object.values(value).every(isJsonConfigValue);\n}\n\nfunction assertPluginCapabilityId(value: unknown, field: string, manifestPath: string): asserts value is string {\n\tif (typeof value !== \"string\" || !value.trim()) {\n\t\tthrow new Error(`Capability plugin ${field} must be a non-empty string: ${manifestPath}`);\n\t}\n}\n\nfunction assertPluginCapabilityVersion(value: unknown, field: string, manifestPath: string): asserts value is number {\n\tif (typeof value !== \"number\" || !Number.isSafeInteger(value) || value < 1) {\n\t\tthrow new Error(`Capability plugin ${field} must be a positive safe integer: ${manifestPath}`);\n\t}\n}\n\nfunction capabilityKey(id: string, version: number): string {\n\treturn `${id}\\u0000${version}`;\n}\n\nfunction parsePluginAgentRoles(value: unknown, manifestPath: string): readonly PluginAgentRole[] | undefined {\n\tif (value === undefined) return undefined;\n\tif (!Array.isArray(value)) throw new Error(`Capability plugin roles must be an array: ${manifestPath}`);\n\tconst roles: PluginAgentRole[] = [];\n\tconst seen = new Set<string>();\n\tfor (const [index, role] of value.entries()) {\n\t\tif (role !== \"root-agent-controller\" && role !== \"child-agent-controller\") {\n\t\t\tthrow new Error(`Capability plugin roles[${index}] is invalid: ${manifestPath}`);\n\t\t}\n\t\tif (seen.has(role)) throw new Error(`Capability plugin roles duplicates ${role}: ${manifestPath}`);\n\t\tseen.add(role);\n\t\troles.push(role);\n\t}\n\treturn roles;\n}\n\nfunction parsePluginAgentDeclarations(\n\tvalue: unknown,\n\troles: readonly PluginAgentRole[] | undefined,\n\tmanifestPath: string,\n): readonly AgentDefinitionDeclaration[] | undefined {\n\tif (value === undefined) return undefined;\n\tif (!Array.isArray(value)) throw new Error(`Capability plugin agents must be an array: ${manifestPath}`);\n\tconst declarations: AgentDefinitionDeclaration[] = [];\n\tconst seen = new Set<string>();\n\tfor (const [index, candidate] of value.entries()) {\n\t\tif (!isObject(candidate))\n\t\t\tthrow new Error(`Capability plugin agents[${index}] must be an object: ${manifestPath}`);\n\t\tconst { id, version, role, entry } = candidate;\n\t\tassertPluginCapabilityId(id, `agents[${index}].id`, manifestPath);\n\t\tassertPluginCapabilityVersion(version, `agents[${index}].version`, manifestPath);\n\t\tif (role !== \"root-agent-controller\" && role !== \"child-agent-controller\") {\n\t\t\tthrow new Error(`Capability plugin agents[${index}].role is invalid: ${manifestPath}`);\n\t\t}\n\t\tif (typeof entry !== \"string\" || !entry.trim()) {\n\t\t\tthrow new Error(`Capability plugin agents[${index}].entry must be a non-empty string: ${manifestPath}`);\n\t\t}\n\t\tif (roles !== undefined && !roles.includes(role)) {\n\t\t\tthrow new Error(`Capability plugin agents[${index}].role is not declared in roles: ${manifestPath}`);\n\t\t}\n\t\tconst key = capabilityKey(id, version);\n\t\tif (seen.has(key)) throw new Error(`Capability plugin agents duplicates ${id}@${version}: ${manifestPath}`);\n\t\tseen.add(key);\n\t\tdeclarations.push({ id, version, role, entry });\n\t}\n\treturn declarations;\n}\n\nfunction parsePluginCapabilityDeclarations(\n\tvalue: unknown,\n\tmanifestPath: string,\n): readonly PluginCapabilityDeclaration[] | undefined {\n\tif (value === undefined) return undefined;\n\tif (!Array.isArray(value)) {\n\t\tthrow new Error(`Capability plugin provides must be an array: ${manifestPath}`);\n\t}\n\tconst declarations: PluginCapabilityDeclaration[] = [];\n\tconst seen = new Set<string>();\n\tfor (const [index, candidate] of value.entries()) {\n\t\tif (!isObject(candidate)) {\n\t\t\tthrow new Error(`Capability plugin provides[${index}] must be an object: ${manifestPath}`);\n\t\t}\n\t\tconst { id, version, kind } = candidate;\n\t\tassertPluginCapabilityId(id, `provides[${index}].id`, manifestPath);\n\t\tassertPluginCapabilityVersion(version, `provides[${index}].version`, manifestPath);\n\t\tif (kind !== \"service\" && kind !== \"contribution\" && kind !== \"transform\") {\n\t\t\tthrow new Error(`Capability plugin provides[${index}].kind is invalid: ${manifestPath}`);\n\t\t}\n\t\tconst key = capabilityKey(id, version);\n\t\tif (seen.has(key)) {\n\t\t\tthrow new Error(`Capability plugin provides duplicates ${id}@${version}: ${manifestPath}`);\n\t\t}\n\t\tseen.add(key);\n\t\tdeclarations.push({ id, version, kind });\n\t}\n\treturn declarations;\n}\n\nfunction parsePluginCapabilityRequirements(\n\tvalue: unknown,\n\tmanifestPath: string,\n): readonly PluginCapabilityRequirement[] | undefined {\n\tif (value === undefined) return undefined;\n\tif (!Array.isArray(value)) {\n\t\tthrow new Error(`Capability plugin requires must be an array: ${manifestPath}`);\n\t}\n\tconst requirements: PluginCapabilityRequirement[] = [];\n\tconst seen = new Set<string>();\n\tfor (const [index, candidate] of value.entries()) {\n\t\tif (!isObject(candidate)) {\n\t\t\tthrow new Error(`Capability plugin requires[${index}] must be an object: ${manifestPath}`);\n\t\t}\n\t\tconst { id, version, optional } = candidate;\n\t\tassertPluginCapabilityId(id, `requires[${index}].id`, manifestPath);\n\t\tassertPluginCapabilityVersion(version, `requires[${index}].version`, manifestPath);\n\t\tif (optional !== undefined && typeof optional !== \"boolean\") {\n\t\t\tthrow new Error(`Capability plugin requires[${index}].optional must be a boolean: ${manifestPath}`);\n\t\t}\n\t\tconst key = capabilityKey(id, version);\n\t\tif (seen.has(key)) {\n\t\t\tthrow new Error(`Capability plugin requires duplicates ${id}@${version}: ${manifestPath}`);\n\t\t}\n\t\tseen.add(key);\n\t\trequirements.push(optional === undefined ? { id, version } : { id, version, optional });\n\t}\n\treturn requirements;\n}\n\n/** Parse a capability plugin manifest without accepting malformed fields. */\nexport function parseCapabilityPluginManifest(value: unknown, manifestPath = \"<manifest>\"): PluginManifest {\n\tif (!isObject(value)) throw new Error(`Capability plugin manifest must be an object: ${manifestPath}`);\n\tconst {\n\t\tid,\n\t\tversion,\n\t\thostVersion,\n\t\tapiVersion,\n\t\tentry,\n\t\trequiredCapabilities,\n\t\toptionalCapabilities,\n\t\tprovides,\n\t\trequires,\n\t\troles,\n\t\tagents,\n\t\tconfig,\n\t} = value;\n\tif (\n\t\ttypeof id !== \"string\" ||\n\t\ttypeof version !== \"string\" ||\n\t\ttypeof apiVersion !== \"string\" ||\n\t\ttypeof entry !== \"string\"\n\t) {\n\t\tthrow new Error(`Capability plugin manifest requires string id, version, apiVersion, and entry: ${manifestPath}`);\n\t}\n\tif (apiVersion !== EXPERIMENTAL_PUBLIC_API_VERSION) {\n\t\tthrow new Error(`Unsupported plugin API version: ${apiVersion}: ${manifestPath}`);\n\t}\n\tif (\n\t\thostVersion !== undefined &&\n\t\t(typeof hostVersion !== \"string\" || hostVersion.trim() === \"\" || validRange(hostVersion) === null)\n\t) {\n\t\tthrow new Error(\n\t\t\t`Capability plugin hostVersion must be a non-empty string containing a valid semver range (e.g. \">=0.84.0\"): ${manifestPath}`,\n\t\t);\n\t}\n\tif (requiredCapabilities !== undefined && !isStringArray(requiredCapabilities)) {\n\t\tthrow new Error(`Capability plugin requiredCapabilities must be a string array: ${manifestPath}`);\n\t}\n\tif (optionalCapabilities !== undefined && !isStringArray(optionalCapabilities)) {\n\t\tthrow new Error(`Capability plugin optionalCapabilities must be a string array: ${manifestPath}`);\n\t}\n\tif (config !== undefined && (!isObject(config) || !isJsonConfigValue(config))) {\n\t\tthrow new Error(`Capability plugin config must be a JSON object: ${manifestPath}`);\n\t}\n\tconst parsedProvides = parsePluginCapabilityDeclarations(provides, manifestPath);\n\tconst parsedRequires = parsePluginCapabilityRequirements(requires, manifestPath);\n\tconst parsedRoles = parsePluginAgentRoles(roles, manifestPath);\n\tconst parsedAgents = parsePluginAgentDeclarations(agents, parsedRoles, manifestPath);\n\treturn {\n\t\tid,\n\t\tversion,\n\t\tapiVersion: apiVersion as PluginManifest[\"apiVersion\"],\n\t\tentry,\n\t\trequiredCapabilities,\n\t\toptionalCapabilities,\n\t\t...(hostVersion === undefined ? {} : { hostVersion }),\n\t\t...(parsedProvides === undefined ? {} : { provides: parsedProvides }),\n\t\t...(parsedRequires === undefined ? {} : { requires: parsedRequires }),\n\t\t...(parsedRoles === undefined ? {} : { roles: parsedRoles }),\n\t\t...(parsedAgents === undefined ? {} : { agents: parsedAgents }),\n\t\t...(config === undefined ? {} : { config: config as PluginManifest[\"config\"] }),\n\t};\n}\n"]}
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Capability plugin manifest schema (plugin.json) and its pure validation.
3
+ *
4
+ * Authority: `@agent-forge/plugin-sdk` (D-075 S2). The host re-exports these
5
+ * symbols from its loader module; filesystem discovery, jiti loading, and
6
+ * lifecycle dispatch stay host-side.
7
+ */
8
+ import { validRange } from "semver";
9
+ import { EXPERIMENTAL_PUBLIC_API_VERSION } from "./public-api.js";
10
+ function isStringArray(value) {
11
+ return Array.isArray(value) && value.every((entry) => typeof entry === "string");
12
+ }
13
+ function isObject(value) {
14
+ return typeof value === "object" && value !== null && !Array.isArray(value);
15
+ }
16
+ function isJsonConfigValue(value) {
17
+ if (value === null || typeof value === "boolean" || typeof value === "string")
18
+ return true;
19
+ if (typeof value === "number")
20
+ return Number.isFinite(value);
21
+ if (Array.isArray(value))
22
+ return value.every(isJsonConfigValue);
23
+ if (!isObject(value))
24
+ return false;
25
+ return Object.values(value).every(isJsonConfigValue);
26
+ }
27
+ function assertPluginCapabilityId(value, field, manifestPath) {
28
+ if (typeof value !== "string" || !value.trim()) {
29
+ throw new Error(`Capability plugin ${field} must be a non-empty string: ${manifestPath}`);
30
+ }
31
+ }
32
+ function assertPluginCapabilityVersion(value, field, manifestPath) {
33
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1) {
34
+ throw new Error(`Capability plugin ${field} must be a positive safe integer: ${manifestPath}`);
35
+ }
36
+ }
37
+ function capabilityKey(id, version) {
38
+ return `${id}\u0000${version}`;
39
+ }
40
+ function parsePluginAgentRoles(value, manifestPath) {
41
+ if (value === undefined)
42
+ return undefined;
43
+ if (!Array.isArray(value))
44
+ throw new Error(`Capability plugin roles must be an array: ${manifestPath}`);
45
+ const roles = [];
46
+ const seen = new Set();
47
+ for (const [index, role] of value.entries()) {
48
+ if (role !== "root-agent-controller" && role !== "child-agent-controller") {
49
+ throw new Error(`Capability plugin roles[${index}] is invalid: ${manifestPath}`);
50
+ }
51
+ if (seen.has(role))
52
+ throw new Error(`Capability plugin roles duplicates ${role}: ${manifestPath}`);
53
+ seen.add(role);
54
+ roles.push(role);
55
+ }
56
+ return roles;
57
+ }
58
+ function parsePluginAgentDeclarations(value, roles, manifestPath) {
59
+ if (value === undefined)
60
+ return undefined;
61
+ if (!Array.isArray(value))
62
+ throw new Error(`Capability plugin agents must be an array: ${manifestPath}`);
63
+ const declarations = [];
64
+ const seen = new Set();
65
+ for (const [index, candidate] of value.entries()) {
66
+ if (!isObject(candidate))
67
+ throw new Error(`Capability plugin agents[${index}] must be an object: ${manifestPath}`);
68
+ const { id, version, role, entry } = candidate;
69
+ assertPluginCapabilityId(id, `agents[${index}].id`, manifestPath);
70
+ assertPluginCapabilityVersion(version, `agents[${index}].version`, manifestPath);
71
+ if (role !== "root-agent-controller" && role !== "child-agent-controller") {
72
+ throw new Error(`Capability plugin agents[${index}].role is invalid: ${manifestPath}`);
73
+ }
74
+ if (typeof entry !== "string" || !entry.trim()) {
75
+ throw new Error(`Capability plugin agents[${index}].entry must be a non-empty string: ${manifestPath}`);
76
+ }
77
+ if (roles !== undefined && !roles.includes(role)) {
78
+ throw new Error(`Capability plugin agents[${index}].role is not declared in roles: ${manifestPath}`);
79
+ }
80
+ const key = capabilityKey(id, version);
81
+ if (seen.has(key))
82
+ throw new Error(`Capability plugin agents duplicates ${id}@${version}: ${manifestPath}`);
83
+ seen.add(key);
84
+ declarations.push({ id, version, role, entry });
85
+ }
86
+ return declarations;
87
+ }
88
+ function parsePluginCapabilityDeclarations(value, manifestPath) {
89
+ if (value === undefined)
90
+ return undefined;
91
+ if (!Array.isArray(value)) {
92
+ throw new Error(`Capability plugin provides must be an array: ${manifestPath}`);
93
+ }
94
+ const declarations = [];
95
+ const seen = new Set();
96
+ for (const [index, candidate] of value.entries()) {
97
+ if (!isObject(candidate)) {
98
+ throw new Error(`Capability plugin provides[${index}] must be an object: ${manifestPath}`);
99
+ }
100
+ const { id, version, kind } = candidate;
101
+ assertPluginCapabilityId(id, `provides[${index}].id`, manifestPath);
102
+ assertPluginCapabilityVersion(version, `provides[${index}].version`, manifestPath);
103
+ if (kind !== "service" && kind !== "contribution" && kind !== "transform") {
104
+ throw new Error(`Capability plugin provides[${index}].kind is invalid: ${manifestPath}`);
105
+ }
106
+ const key = capabilityKey(id, version);
107
+ if (seen.has(key)) {
108
+ throw new Error(`Capability plugin provides duplicates ${id}@${version}: ${manifestPath}`);
109
+ }
110
+ seen.add(key);
111
+ declarations.push({ id, version, kind });
112
+ }
113
+ return declarations;
114
+ }
115
+ function parsePluginCapabilityRequirements(value, manifestPath) {
116
+ if (value === undefined)
117
+ return undefined;
118
+ if (!Array.isArray(value)) {
119
+ throw new Error(`Capability plugin requires must be an array: ${manifestPath}`);
120
+ }
121
+ const requirements = [];
122
+ const seen = new Set();
123
+ for (const [index, candidate] of value.entries()) {
124
+ if (!isObject(candidate)) {
125
+ throw new Error(`Capability plugin requires[${index}] must be an object: ${manifestPath}`);
126
+ }
127
+ const { id, version, optional } = candidate;
128
+ assertPluginCapabilityId(id, `requires[${index}].id`, manifestPath);
129
+ assertPluginCapabilityVersion(version, `requires[${index}].version`, manifestPath);
130
+ if (optional !== undefined && typeof optional !== "boolean") {
131
+ throw new Error(`Capability plugin requires[${index}].optional must be a boolean: ${manifestPath}`);
132
+ }
133
+ const key = capabilityKey(id, version);
134
+ if (seen.has(key)) {
135
+ throw new Error(`Capability plugin requires duplicates ${id}@${version}: ${manifestPath}`);
136
+ }
137
+ seen.add(key);
138
+ requirements.push(optional === undefined ? { id, version } : { id, version, optional });
139
+ }
140
+ return requirements;
141
+ }
142
+ /** Parse a capability plugin manifest without accepting malformed fields. */
143
+ export function parseCapabilityPluginManifest(value, manifestPath = "<manifest>") {
144
+ if (!isObject(value))
145
+ throw new Error(`Capability plugin manifest must be an object: ${manifestPath}`);
146
+ const { id, version, hostVersion, apiVersion, entry, requiredCapabilities, optionalCapabilities, provides, requires, roles, agents, config, } = value;
147
+ if (typeof id !== "string" ||
148
+ typeof version !== "string" ||
149
+ typeof apiVersion !== "string" ||
150
+ typeof entry !== "string") {
151
+ throw new Error(`Capability plugin manifest requires string id, version, apiVersion, and entry: ${manifestPath}`);
152
+ }
153
+ if (apiVersion !== EXPERIMENTAL_PUBLIC_API_VERSION) {
154
+ throw new Error(`Unsupported plugin API version: ${apiVersion}: ${manifestPath}`);
155
+ }
156
+ if (hostVersion !== undefined &&
157
+ (typeof hostVersion !== "string" || hostVersion.trim() === "" || validRange(hostVersion) === null)) {
158
+ throw new Error(`Capability plugin hostVersion must be a non-empty string containing a valid semver range (e.g. ">=0.84.0"): ${manifestPath}`);
159
+ }
160
+ if (requiredCapabilities !== undefined && !isStringArray(requiredCapabilities)) {
161
+ throw new Error(`Capability plugin requiredCapabilities must be a string array: ${manifestPath}`);
162
+ }
163
+ if (optionalCapabilities !== undefined && !isStringArray(optionalCapabilities)) {
164
+ throw new Error(`Capability plugin optionalCapabilities must be a string array: ${manifestPath}`);
165
+ }
166
+ if (config !== undefined && (!isObject(config) || !isJsonConfigValue(config))) {
167
+ throw new Error(`Capability plugin config must be a JSON object: ${manifestPath}`);
168
+ }
169
+ const parsedProvides = parsePluginCapabilityDeclarations(provides, manifestPath);
170
+ const parsedRequires = parsePluginCapabilityRequirements(requires, manifestPath);
171
+ const parsedRoles = parsePluginAgentRoles(roles, manifestPath);
172
+ const parsedAgents = parsePluginAgentDeclarations(agents, parsedRoles, manifestPath);
173
+ return {
174
+ id,
175
+ version,
176
+ apiVersion: apiVersion,
177
+ entry,
178
+ requiredCapabilities,
179
+ optionalCapabilities,
180
+ ...(hostVersion === undefined ? {} : { hostVersion }),
181
+ ...(parsedProvides === undefined ? {} : { provides: parsedProvides }),
182
+ ...(parsedRequires === undefined ? {} : { requires: parsedRequires }),
183
+ ...(parsedRoles === undefined ? {} : { roles: parsedRoles }),
184
+ ...(parsedAgents === undefined ? {} : { agents: parsedAgents }),
185
+ ...(config === undefined ? {} : { config: config }),
186
+ };
187
+ }
188
+ //# sourceMappingURL=capability-manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capability-manifest.js","sourceRoot":"","sources":["../src/capability-manifest.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Capability plugin manifest schema (plugin.json) and its pure validation.\n *\n * Authority: `@agent-forge/plugin-sdk` (D-075 S2). The host re-exports these\n * symbols from its loader module; filesystem discovery, jiti loading, and\n * lifecycle dispatch stay host-side.\n */\n\nimport { validRange } from \"semver\";\nimport type {\n\tAgentDefinitionDeclaration,\n\tPluginAgentRole,\n\tPluginCapabilityDeclaration,\n\tPluginCapabilityRequirement,\n\tPluginManifest,\n} from \"./public-api.ts\";\nimport { EXPERIMENTAL_PUBLIC_API_VERSION } from \"./public-api.ts\";\n\nfunction isStringArray(value: unknown): value is string[] {\n\treturn Array.isArray(value) && value.every((entry) => typeof entry === \"string\");\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isJsonConfigValue(value: unknown): boolean {\n\tif (value === null || typeof value === \"boolean\" || typeof value === \"string\") return true;\n\tif (typeof value === \"number\") return Number.isFinite(value);\n\tif (Array.isArray(value)) return value.every(isJsonConfigValue);\n\tif (!isObject(value)) return false;\n\treturn Object.values(value).every(isJsonConfigValue);\n}\n\nfunction assertPluginCapabilityId(value: unknown, field: string, manifestPath: string): asserts value is string {\n\tif (typeof value !== \"string\" || !value.trim()) {\n\t\tthrow new Error(`Capability plugin ${field} must be a non-empty string: ${manifestPath}`);\n\t}\n}\n\nfunction assertPluginCapabilityVersion(value: unknown, field: string, manifestPath: string): asserts value is number {\n\tif (typeof value !== \"number\" || !Number.isSafeInteger(value) || value < 1) {\n\t\tthrow new Error(`Capability plugin ${field} must be a positive safe integer: ${manifestPath}`);\n\t}\n}\n\nfunction capabilityKey(id: string, version: number): string {\n\treturn `${id}\\u0000${version}`;\n}\n\nfunction parsePluginAgentRoles(value: unknown, manifestPath: string): readonly PluginAgentRole[] | undefined {\n\tif (value === undefined) return undefined;\n\tif (!Array.isArray(value)) throw new Error(`Capability plugin roles must be an array: ${manifestPath}`);\n\tconst roles: PluginAgentRole[] = [];\n\tconst seen = new Set<string>();\n\tfor (const [index, role] of value.entries()) {\n\t\tif (role !== \"root-agent-controller\" && role !== \"child-agent-controller\") {\n\t\t\tthrow new Error(`Capability plugin roles[${index}] is invalid: ${manifestPath}`);\n\t\t}\n\t\tif (seen.has(role)) throw new Error(`Capability plugin roles duplicates ${role}: ${manifestPath}`);\n\t\tseen.add(role);\n\t\troles.push(role);\n\t}\n\treturn roles;\n}\n\nfunction parsePluginAgentDeclarations(\n\tvalue: unknown,\n\troles: readonly PluginAgentRole[] | undefined,\n\tmanifestPath: string,\n): readonly AgentDefinitionDeclaration[] | undefined {\n\tif (value === undefined) return undefined;\n\tif (!Array.isArray(value)) throw new Error(`Capability plugin agents must be an array: ${manifestPath}`);\n\tconst declarations: AgentDefinitionDeclaration[] = [];\n\tconst seen = new Set<string>();\n\tfor (const [index, candidate] of value.entries()) {\n\t\tif (!isObject(candidate))\n\t\t\tthrow new Error(`Capability plugin agents[${index}] must be an object: ${manifestPath}`);\n\t\tconst { id, version, role, entry } = candidate;\n\t\tassertPluginCapabilityId(id, `agents[${index}].id`, manifestPath);\n\t\tassertPluginCapabilityVersion(version, `agents[${index}].version`, manifestPath);\n\t\tif (role !== \"root-agent-controller\" && role !== \"child-agent-controller\") {\n\t\t\tthrow new Error(`Capability plugin agents[${index}].role is invalid: ${manifestPath}`);\n\t\t}\n\t\tif (typeof entry !== \"string\" || !entry.trim()) {\n\t\t\tthrow new Error(`Capability plugin agents[${index}].entry must be a non-empty string: ${manifestPath}`);\n\t\t}\n\t\tif (roles !== undefined && !roles.includes(role)) {\n\t\t\tthrow new Error(`Capability plugin agents[${index}].role is not declared in roles: ${manifestPath}`);\n\t\t}\n\t\tconst key = capabilityKey(id, version);\n\t\tif (seen.has(key)) throw new Error(`Capability plugin agents duplicates ${id}@${version}: ${manifestPath}`);\n\t\tseen.add(key);\n\t\tdeclarations.push({ id, version, role, entry });\n\t}\n\treturn declarations;\n}\n\nfunction parsePluginCapabilityDeclarations(\n\tvalue: unknown,\n\tmanifestPath: string,\n): readonly PluginCapabilityDeclaration[] | undefined {\n\tif (value === undefined) return undefined;\n\tif (!Array.isArray(value)) {\n\t\tthrow new Error(`Capability plugin provides must be an array: ${manifestPath}`);\n\t}\n\tconst declarations: PluginCapabilityDeclaration[] = [];\n\tconst seen = new Set<string>();\n\tfor (const [index, candidate] of value.entries()) {\n\t\tif (!isObject(candidate)) {\n\t\t\tthrow new Error(`Capability plugin provides[${index}] must be an object: ${manifestPath}`);\n\t\t}\n\t\tconst { id, version, kind } = candidate;\n\t\tassertPluginCapabilityId(id, `provides[${index}].id`, manifestPath);\n\t\tassertPluginCapabilityVersion(version, `provides[${index}].version`, manifestPath);\n\t\tif (kind !== \"service\" && kind !== \"contribution\" && kind !== \"transform\") {\n\t\t\tthrow new Error(`Capability plugin provides[${index}].kind is invalid: ${manifestPath}`);\n\t\t}\n\t\tconst key = capabilityKey(id, version);\n\t\tif (seen.has(key)) {\n\t\t\tthrow new Error(`Capability plugin provides duplicates ${id}@${version}: ${manifestPath}`);\n\t\t}\n\t\tseen.add(key);\n\t\tdeclarations.push({ id, version, kind });\n\t}\n\treturn declarations;\n}\n\nfunction parsePluginCapabilityRequirements(\n\tvalue: unknown,\n\tmanifestPath: string,\n): readonly PluginCapabilityRequirement[] | undefined {\n\tif (value === undefined) return undefined;\n\tif (!Array.isArray(value)) {\n\t\tthrow new Error(`Capability plugin requires must be an array: ${manifestPath}`);\n\t}\n\tconst requirements: PluginCapabilityRequirement[] = [];\n\tconst seen = new Set<string>();\n\tfor (const [index, candidate] of value.entries()) {\n\t\tif (!isObject(candidate)) {\n\t\t\tthrow new Error(`Capability plugin requires[${index}] must be an object: ${manifestPath}`);\n\t\t}\n\t\tconst { id, version, optional } = candidate;\n\t\tassertPluginCapabilityId(id, `requires[${index}].id`, manifestPath);\n\t\tassertPluginCapabilityVersion(version, `requires[${index}].version`, manifestPath);\n\t\tif (optional !== undefined && typeof optional !== \"boolean\") {\n\t\t\tthrow new Error(`Capability plugin requires[${index}].optional must be a boolean: ${manifestPath}`);\n\t\t}\n\t\tconst key = capabilityKey(id, version);\n\t\tif (seen.has(key)) {\n\t\t\tthrow new Error(`Capability plugin requires duplicates ${id}@${version}: ${manifestPath}`);\n\t\t}\n\t\tseen.add(key);\n\t\trequirements.push(optional === undefined ? { id, version } : { id, version, optional });\n\t}\n\treturn requirements;\n}\n\n/** Parse a capability plugin manifest without accepting malformed fields. */\nexport function parseCapabilityPluginManifest(value: unknown, manifestPath = \"<manifest>\"): PluginManifest {\n\tif (!isObject(value)) throw new Error(`Capability plugin manifest must be an object: ${manifestPath}`);\n\tconst {\n\t\tid,\n\t\tversion,\n\t\thostVersion,\n\t\tapiVersion,\n\t\tentry,\n\t\trequiredCapabilities,\n\t\toptionalCapabilities,\n\t\tprovides,\n\t\trequires,\n\t\troles,\n\t\tagents,\n\t\tconfig,\n\t} = value;\n\tif (\n\t\ttypeof id !== \"string\" ||\n\t\ttypeof version !== \"string\" ||\n\t\ttypeof apiVersion !== \"string\" ||\n\t\ttypeof entry !== \"string\"\n\t) {\n\t\tthrow new Error(`Capability plugin manifest requires string id, version, apiVersion, and entry: ${manifestPath}`);\n\t}\n\tif (apiVersion !== EXPERIMENTAL_PUBLIC_API_VERSION) {\n\t\tthrow new Error(`Unsupported plugin API version: ${apiVersion}: ${manifestPath}`);\n\t}\n\tif (\n\t\thostVersion !== undefined &&\n\t\t(typeof hostVersion !== \"string\" || hostVersion.trim() === \"\" || validRange(hostVersion) === null)\n\t) {\n\t\tthrow new Error(\n\t\t\t`Capability plugin hostVersion must be a non-empty string containing a valid semver range (e.g. \">=0.84.0\"): ${manifestPath}`,\n\t\t);\n\t}\n\tif (requiredCapabilities !== undefined && !isStringArray(requiredCapabilities)) {\n\t\tthrow new Error(`Capability plugin requiredCapabilities must be a string array: ${manifestPath}`);\n\t}\n\tif (optionalCapabilities !== undefined && !isStringArray(optionalCapabilities)) {\n\t\tthrow new Error(`Capability plugin optionalCapabilities must be a string array: ${manifestPath}`);\n\t}\n\tif (config !== undefined && (!isObject(config) || !isJsonConfigValue(config))) {\n\t\tthrow new Error(`Capability plugin config must be a JSON object: ${manifestPath}`);\n\t}\n\tconst parsedProvides = parsePluginCapabilityDeclarations(provides, manifestPath);\n\tconst parsedRequires = parsePluginCapabilityRequirements(requires, manifestPath);\n\tconst parsedRoles = parsePluginAgentRoles(roles, manifestPath);\n\tconst parsedAgents = parsePluginAgentDeclarations(agents, parsedRoles, manifestPath);\n\treturn {\n\t\tid,\n\t\tversion,\n\t\tapiVersion: apiVersion as PluginManifest[\"apiVersion\"],\n\t\tentry,\n\t\trequiredCapabilities,\n\t\toptionalCapabilities,\n\t\t...(hostVersion === undefined ? {} : { hostVersion }),\n\t\t...(parsedProvides === undefined ? {} : { provides: parsedProvides }),\n\t\t...(parsedRequires === undefined ? {} : { requires: parsedRequires }),\n\t\t...(parsedRoles === undefined ? {} : { roles: parsedRoles }),\n\t\t...(parsedAgents === undefined ? {} : { agents: parsedAgents }),\n\t\t...(config === undefined ? {} : { config: config as PluginManifest[\"config\"] }),\n\t};\n}\n"]}
@@ -0,0 +1,24 @@
1
+ /** Shared, transport-neutral contracts used by first-party and third-party plugins. */
2
+ export declare const PLUGIN_SHARED_CONTRACT_VERSION_V1: 1;
3
+ export type JsonValue = null | boolean | number | string | JsonValue[] | {
4
+ readonly [key: string]: JsonValue;
5
+ };
6
+ export type JsonObject = {
7
+ readonly [key: string]: JsonValue;
8
+ };
9
+ export type PlainRecord = Record<string, unknown>;
10
+ export declare function isPlainRecord(value: unknown): value is PlainRecord;
11
+ export declare function assertPlainRecord(value: unknown, label: string): asserts value is PlainRecord;
12
+ export declare function assertExactKeys(value: PlainRecord, required: readonly string[], optional: readonly string[], label: string): void;
13
+ export declare function assertNonEmptyString(value: unknown, label: string): asserts value is string;
14
+ export declare function assertOptionalString(value: unknown, label: string): asserts value is string | undefined;
15
+ export declare function assertFiniteNumber(value: unknown, label: string): asserts value is number;
16
+ export declare function assertNonNegativeNumber(value: unknown, label: string): asserts value is number;
17
+ export declare function assertPositiveSafeInteger(value: unknown, label: string): asserts value is number;
18
+ export declare function assertNonNegativeSafeInteger(value: unknown, label: string): asserts value is number;
19
+ export declare function assertJsonValue(value: unknown, label: string, seen?: WeakSet<object>): asserts value is JsonValue;
20
+ /** Detaches input data and sorts object keys so repeated runs have identical output. */
21
+ export declare function detachedFreeze<T>(value: T, seen?: WeakMap<object, unknown>): T;
22
+ export declare function sortByKey<T>(values: readonly T[], key: (value: T) => string): readonly T[];
23
+ export declare function stableStringifyV1(value: JsonValue): string;
24
+ //# sourceMappingURL=common.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../src/common.ts"],"names":[],"mappings":"AAAA,uFAAuF;AAEvF,eAAO,MAAM,iCAAiC,GAAa,CAAC;AAE5D,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,EAAE,GAAG;IAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAC/G,MAAM,MAAM,UAAU,GAAG;IAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAC/D,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAElD,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,WAAW,CAIlE;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,IAAI,WAAW,CAE7F;AAED,wBAAgB,eAAe,CAC9B,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,KAAK,EAAE,MAAM,GACX,IAAI,CASN;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,IAAI,MAAM,CAE3F;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,IAAI,MAAM,GAAG,SAAS,CAEvG;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,IAAI,MAAM,CAEzF;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,IAAI,MAAM,CAG9F;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,IAAI,MAAM,CAIhG;AAED,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,IAAI,MAAM,CAInG;AAED,wBAAgB,eAAe,CAC9B,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,MAAM,EACb,IAAI,kBAAwB,GAC1B,OAAO,CAAC,KAAK,IAAI,SAAS,CAgB5B;AAED,wFAAwF;AACxF,wBAAgB,cAAc,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,2BAAiC,GAAG,CAAC,CAgBpF;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,MAAM,GAAG,SAAS,CAAC,EAAE,CAM1F;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAM1D","sourcesContent":["/** Shared, transport-neutral contracts used by first-party and third-party plugins. */\n\nexport const PLUGIN_SHARED_CONTRACT_VERSION_V1 = 1 as const;\n\nexport type JsonValue = null | boolean | number | string | JsonValue[] | { readonly [key: string]: JsonValue };\nexport type JsonObject = { readonly [key: string]: JsonValue };\nexport type PlainRecord = Record<string, unknown>;\n\nexport function isPlainRecord(value: unknown): value is PlainRecord {\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value)) return false;\n\tconst prototype = Object.getPrototypeOf(value);\n\treturn prototype === Object.prototype || prototype === null;\n}\n\nexport function assertPlainRecord(value: unknown, label: string): asserts value is PlainRecord {\n\tif (!isPlainRecord(value)) throw new Error(`${label} must be a plain object`);\n}\n\nexport function assertExactKeys(\n\tvalue: PlainRecord,\n\trequired: readonly string[],\n\toptional: readonly string[],\n\tlabel: string,\n): void {\n\tconst allowed = new Set([...required, ...optional]);\n\tconst unsupported = Object.keys(value)\n\t\t.filter((key) => !allowed.has(key))\n\t\t.sort();\n\tif (unsupported.length > 0) throw new Error(`${label} has unsupported fields: ${unsupported.join(\", \")}`);\n\tfor (const key of required) {\n\t\tif (!(key in value)) throw new Error(`${label} is missing required field: ${key}`);\n\t}\n}\n\nexport function assertNonEmptyString(value: unknown, label: string): asserts value is string {\n\tif (typeof value !== \"string\" || value.trim().length === 0) throw new Error(`${label} must be a non-empty string`);\n}\n\nexport function assertOptionalString(value: unknown, label: string): asserts value is string | undefined {\n\tif (value !== undefined) assertNonEmptyString(value, label);\n}\n\nexport function assertFiniteNumber(value: unknown, label: string): asserts value is number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) throw new Error(`${label} must be a finite number`);\n}\n\nexport function assertNonNegativeNumber(value: unknown, label: string): asserts value is number {\n\tassertFiniteNumber(value, label);\n\tif (value < 0) throw new Error(`${label} must be non-negative`);\n}\n\nexport function assertPositiveSafeInteger(value: unknown, label: string): asserts value is number {\n\tif (typeof value !== \"number\" || !Number.isSafeInteger(value) || value < 1) {\n\t\tthrow new Error(`${label} must be a positive safe integer`);\n\t}\n}\n\nexport function assertNonNegativeSafeInteger(value: unknown, label: string): asserts value is number {\n\tif (typeof value !== \"number\" || !Number.isSafeInteger(value) || value < 0) {\n\t\tthrow new Error(`${label} must be a non-negative safe integer`);\n\t}\n}\n\nexport function assertJsonValue(\n\tvalue: unknown,\n\tlabel: string,\n\tseen = new WeakSet<object>(),\n): asserts value is JsonValue {\n\tif (value === null || typeof value === \"boolean\" || typeof value === \"string\") return;\n\tif (typeof value === \"number\") {\n\t\tif (Number.isFinite(value)) return;\n\t\tthrow new Error(`${label} must contain finite JSON numbers`);\n\t}\n\tif (typeof value !== \"object\") throw new Error(`${label} must be JSON-compatible`);\n\tif (seen.has(value)) throw new Error(`${label} must not contain cycles`);\n\tseen.add(value);\n\tif (Array.isArray(value)) {\n\t\tfor (const [index, child] of value.entries()) assertJsonValue(child, `${label}[${index}]`, seen);\n\t} else {\n\t\tif (!isPlainRecord(value)) throw new Error(`${label} must contain only plain JSON objects`);\n\t\tfor (const [key, child] of Object.entries(value)) assertJsonValue(child, `${label}.${key}`, seen);\n\t}\n\tseen.delete(value);\n}\n\n/** Detaches input data and sorts object keys so repeated runs have identical output. */\nexport function detachedFreeze<T>(value: T, seen = new WeakMap<object, unknown>()): T {\n\tif (value === null || typeof value !== \"object\") return value;\n\tconst existing = seen.get(value);\n\tif (existing !== undefined) return existing as T;\n\tif (Array.isArray(value)) {\n\t\tconst result: unknown[] = [];\n\t\tseen.set(value, result);\n\t\tfor (const child of value) result.push(detachedFreeze(child, seen));\n\t\treturn Object.freeze(result) as T;\n\t}\n\tconst result: PlainRecord = {};\n\tseen.set(value, result);\n\tfor (const key of Object.keys(value as PlainRecord).sort()) {\n\t\tresult[key] = detachedFreeze((value as PlainRecord)[key], seen);\n\t}\n\treturn Object.freeze(result) as T;\n}\n\nexport function sortByKey<T>(values: readonly T[], key: (value: T) => string): readonly T[] {\n\treturn [...values].sort((left, right) => {\n\t\tconst a = key(left);\n\t\tconst b = key(right);\n\t\treturn a < b ? -1 : a > b ? 1 : 0;\n\t});\n}\n\nexport function stableStringifyV1(value: JsonValue): string {\n\tif (value === null || typeof value === \"boolean\" || typeof value === \"number\") return JSON.stringify(value);\n\tif (typeof value === \"string\") return JSON.stringify(value);\n\tif (Array.isArray(value)) return `[${value.map((item) => stableStringifyV1(item)).join(\",\")}]`;\n\tconst entries = Object.entries(value).sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));\n\treturn `{${entries.map(([key, item]) => `${JSON.stringify(key)}:${stableStringifyV1(item)}`).join(\",\")}}`;\n}\n"]}
package/dist/common.js ADDED
@@ -0,0 +1,115 @@
1
+ /** Shared, transport-neutral contracts used by first-party and third-party plugins. */
2
+ export const PLUGIN_SHARED_CONTRACT_VERSION_V1 = 1;
3
+ export function isPlainRecord(value) {
4
+ if (value === null || typeof value !== "object" || Array.isArray(value))
5
+ return false;
6
+ const prototype = Object.getPrototypeOf(value);
7
+ return prototype === Object.prototype || prototype === null;
8
+ }
9
+ export function assertPlainRecord(value, label) {
10
+ if (!isPlainRecord(value))
11
+ throw new Error(`${label} must be a plain object`);
12
+ }
13
+ export function assertExactKeys(value, required, optional, label) {
14
+ const allowed = new Set([...required, ...optional]);
15
+ const unsupported = Object.keys(value)
16
+ .filter((key) => !allowed.has(key))
17
+ .sort();
18
+ if (unsupported.length > 0)
19
+ throw new Error(`${label} has unsupported fields: ${unsupported.join(", ")}`);
20
+ for (const key of required) {
21
+ if (!(key in value))
22
+ throw new Error(`${label} is missing required field: ${key}`);
23
+ }
24
+ }
25
+ export function assertNonEmptyString(value, label) {
26
+ if (typeof value !== "string" || value.trim().length === 0)
27
+ throw new Error(`${label} must be a non-empty string`);
28
+ }
29
+ export function assertOptionalString(value, label) {
30
+ if (value !== undefined)
31
+ assertNonEmptyString(value, label);
32
+ }
33
+ export function assertFiniteNumber(value, label) {
34
+ if (typeof value !== "number" || !Number.isFinite(value))
35
+ throw new Error(`${label} must be a finite number`);
36
+ }
37
+ export function assertNonNegativeNumber(value, label) {
38
+ assertFiniteNumber(value, label);
39
+ if (value < 0)
40
+ throw new Error(`${label} must be non-negative`);
41
+ }
42
+ export function assertPositiveSafeInteger(value, label) {
43
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1) {
44
+ throw new Error(`${label} must be a positive safe integer`);
45
+ }
46
+ }
47
+ export function assertNonNegativeSafeInteger(value, label) {
48
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
49
+ throw new Error(`${label} must be a non-negative safe integer`);
50
+ }
51
+ }
52
+ export function assertJsonValue(value, label, seen = new WeakSet()) {
53
+ if (value === null || typeof value === "boolean" || typeof value === "string")
54
+ return;
55
+ if (typeof value === "number") {
56
+ if (Number.isFinite(value))
57
+ return;
58
+ throw new Error(`${label} must contain finite JSON numbers`);
59
+ }
60
+ if (typeof value !== "object")
61
+ throw new Error(`${label} must be JSON-compatible`);
62
+ if (seen.has(value))
63
+ throw new Error(`${label} must not contain cycles`);
64
+ seen.add(value);
65
+ if (Array.isArray(value)) {
66
+ for (const [index, child] of value.entries())
67
+ assertJsonValue(child, `${label}[${index}]`, seen);
68
+ }
69
+ else {
70
+ if (!isPlainRecord(value))
71
+ throw new Error(`${label} must contain only plain JSON objects`);
72
+ for (const [key, child] of Object.entries(value))
73
+ assertJsonValue(child, `${label}.${key}`, seen);
74
+ }
75
+ seen.delete(value);
76
+ }
77
+ /** Detaches input data and sorts object keys so repeated runs have identical output. */
78
+ export function detachedFreeze(value, seen = new WeakMap()) {
79
+ if (value === null || typeof value !== "object")
80
+ return value;
81
+ const existing = seen.get(value);
82
+ if (existing !== undefined)
83
+ return existing;
84
+ if (Array.isArray(value)) {
85
+ const result = [];
86
+ seen.set(value, result);
87
+ for (const child of value)
88
+ result.push(detachedFreeze(child, seen));
89
+ return Object.freeze(result);
90
+ }
91
+ const result = {};
92
+ seen.set(value, result);
93
+ for (const key of Object.keys(value).sort()) {
94
+ result[key] = detachedFreeze(value[key], seen);
95
+ }
96
+ return Object.freeze(result);
97
+ }
98
+ export function sortByKey(values, key) {
99
+ return [...values].sort((left, right) => {
100
+ const a = key(left);
101
+ const b = key(right);
102
+ return a < b ? -1 : a > b ? 1 : 0;
103
+ });
104
+ }
105
+ export function stableStringifyV1(value) {
106
+ if (value === null || typeof value === "boolean" || typeof value === "number")
107
+ return JSON.stringify(value);
108
+ if (typeof value === "string")
109
+ return JSON.stringify(value);
110
+ if (Array.isArray(value))
111
+ return `[${value.map((item) => stableStringifyV1(item)).join(",")}]`;
112
+ const entries = Object.entries(value).sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));
113
+ return `{${entries.map(([key, item]) => `${JSON.stringify(key)}:${stableStringifyV1(item)}`).join(",")}}`;
114
+ }
115
+ //# sourceMappingURL=common.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"common.js","sourceRoot":"","sources":["../src/common.ts"],"names":[],"mappings":"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","sourcesContent":["/** Shared, transport-neutral contracts used by first-party and third-party plugins. */\n\nexport const PLUGIN_SHARED_CONTRACT_VERSION_V1 = 1 as const;\n\nexport type JsonValue = null | boolean | number | string | JsonValue[] | { readonly [key: string]: JsonValue };\nexport type JsonObject = { readonly [key: string]: JsonValue };\nexport type PlainRecord = Record<string, unknown>;\n\nexport function isPlainRecord(value: unknown): value is PlainRecord {\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value)) return false;\n\tconst prototype = Object.getPrototypeOf(value);\n\treturn prototype === Object.prototype || prototype === null;\n}\n\nexport function assertPlainRecord(value: unknown, label: string): asserts value is PlainRecord {\n\tif (!isPlainRecord(value)) throw new Error(`${label} must be a plain object`);\n}\n\nexport function assertExactKeys(\n\tvalue: PlainRecord,\n\trequired: readonly string[],\n\toptional: readonly string[],\n\tlabel: string,\n): void {\n\tconst allowed = new Set([...required, ...optional]);\n\tconst unsupported = Object.keys(value)\n\t\t.filter((key) => !allowed.has(key))\n\t\t.sort();\n\tif (unsupported.length > 0) throw new Error(`${label} has unsupported fields: ${unsupported.join(\", \")}`);\n\tfor (const key of required) {\n\t\tif (!(key in value)) throw new Error(`${label} is missing required field: ${key}`);\n\t}\n}\n\nexport function assertNonEmptyString(value: unknown, label: string): asserts value is string {\n\tif (typeof value !== \"string\" || value.trim().length === 0) throw new Error(`${label} must be a non-empty string`);\n}\n\nexport function assertOptionalString(value: unknown, label: string): asserts value is string | undefined {\n\tif (value !== undefined) assertNonEmptyString(value, label);\n}\n\nexport function assertFiniteNumber(value: unknown, label: string): asserts value is number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) throw new Error(`${label} must be a finite number`);\n}\n\nexport function assertNonNegativeNumber(value: unknown, label: string): asserts value is number {\n\tassertFiniteNumber(value, label);\n\tif (value < 0) throw new Error(`${label} must be non-negative`);\n}\n\nexport function assertPositiveSafeInteger(value: unknown, label: string): asserts value is number {\n\tif (typeof value !== \"number\" || !Number.isSafeInteger(value) || value < 1) {\n\t\tthrow new Error(`${label} must be a positive safe integer`);\n\t}\n}\n\nexport function assertNonNegativeSafeInteger(value: unknown, label: string): asserts value is number {\n\tif (typeof value !== \"number\" || !Number.isSafeInteger(value) || value < 0) {\n\t\tthrow new Error(`${label} must be a non-negative safe integer`);\n\t}\n}\n\nexport function assertJsonValue(\n\tvalue: unknown,\n\tlabel: string,\n\tseen = new WeakSet<object>(),\n): asserts value is JsonValue {\n\tif (value === null || typeof value === \"boolean\" || typeof value === \"string\") return;\n\tif (typeof value === \"number\") {\n\t\tif (Number.isFinite(value)) return;\n\t\tthrow new Error(`${label} must contain finite JSON numbers`);\n\t}\n\tif (typeof value !== \"object\") throw new Error(`${label} must be JSON-compatible`);\n\tif (seen.has(value)) throw new Error(`${label} must not contain cycles`);\n\tseen.add(value);\n\tif (Array.isArray(value)) {\n\t\tfor (const [index, child] of value.entries()) assertJsonValue(child, `${label}[${index}]`, seen);\n\t} else {\n\t\tif (!isPlainRecord(value)) throw new Error(`${label} must contain only plain JSON objects`);\n\t\tfor (const [key, child] of Object.entries(value)) assertJsonValue(child, `${label}.${key}`, seen);\n\t}\n\tseen.delete(value);\n}\n\n/** Detaches input data and sorts object keys so repeated runs have identical output. */\nexport function detachedFreeze<T>(value: T, seen = new WeakMap<object, unknown>()): T {\n\tif (value === null || typeof value !== \"object\") return value;\n\tconst existing = seen.get(value);\n\tif (existing !== undefined) return existing as T;\n\tif (Array.isArray(value)) {\n\t\tconst result: unknown[] = [];\n\t\tseen.set(value, result);\n\t\tfor (const child of value) result.push(detachedFreeze(child, seen));\n\t\treturn Object.freeze(result) as T;\n\t}\n\tconst result: PlainRecord = {};\n\tseen.set(value, result);\n\tfor (const key of Object.keys(value as PlainRecord).sort()) {\n\t\tresult[key] = detachedFreeze((value as PlainRecord)[key], seen);\n\t}\n\treturn Object.freeze(result) as T;\n}\n\nexport function sortByKey<T>(values: readonly T[], key: (value: T) => string): readonly T[] {\n\treturn [...values].sort((left, right) => {\n\t\tconst a = key(left);\n\t\tconst b = key(right);\n\t\treturn a < b ? -1 : a > b ? 1 : 0;\n\t});\n}\n\nexport function stableStringifyV1(value: JsonValue): string {\n\tif (value === null || typeof value === \"boolean\" || typeof value === \"number\") return JSON.stringify(value);\n\tif (typeof value === \"string\") return JSON.stringify(value);\n\tif (Array.isArray(value)) return `[${value.map((item) => stableStringifyV1(item)).join(\",\")}]`;\n\tconst entries = Object.entries(value).sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));\n\treturn `{${entries.map(([key, item]) => `${JSON.stringify(key)}:${stableStringifyV1(item)}`).join(\",\")}}`;\n}\n"]}
@@ -0,0 +1,33 @@
1
+ import type { JsonValue } from "./common.ts";
2
+ import type { PluginErrorV1 } from "./operation.ts";
3
+ /** Shared egress budget for every plugin result that is projected into model context. */
4
+ export interface PluginContextBudgetV1 {
5
+ readonly maxOutputBytes: number;
6
+ readonly maxInlineItems: number;
7
+ readonly maxCellChars: number;
8
+ }
9
+ export interface PluginContextProjectionInputV1 {
10
+ readonly version: 1;
11
+ readonly operationId: string;
12
+ /** Already summarized values only. Raw rows/payloads are rejected at this boundary. */
13
+ readonly items: readonly JsonValue[];
14
+ readonly outputArtifactRef?: string;
15
+ readonly truncated?: boolean;
16
+ }
17
+ export interface PluginContextProjectionV1 {
18
+ readonly version: 1;
19
+ readonly operationId: string;
20
+ readonly status: "succeeded" | "failed";
21
+ readonly inlineItems: readonly JsonValue[];
22
+ readonly truncated: boolean;
23
+ readonly outputArtifactRef?: string;
24
+ readonly error?: PluginErrorV1;
25
+ }
26
+ declare const DEFAULT_PLUGIN_CONTEXT_BUDGET_V1: PluginContextBudgetV1;
27
+ /**
28
+ * Projects plugin summaries into the model-visible context envelope. This is an
29
+ * egress boundary: it never accepts raw rows or silently exceeds a byte budget.
30
+ */
31
+ export declare function projectPluginContextV1(input: PluginContextProjectionInputV1, limits?: Partial<PluginContextBudgetV1>): PluginContextProjectionV1;
32
+ export { DEFAULT_PLUGIN_CONTEXT_BUDGET_V1 };
33
+ //# sourceMappingURL=context-budget.d.ts.map