@xemahq/kernel-contracts 0.50.0 → 0.56.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/biome/lib/biome-manifest.d.ts +9 -0
- package/dist/biome/lib/biome-manifest.d.ts.map +1 -1
- package/dist/biome/lib/biome-manifest.js +2 -0
- package/dist/biome/lib/biome-manifest.js.map +1 -1
- package/dist/capability/index.d.ts +2 -1
- package/dist/capability/index.d.ts.map +1 -1
- package/dist/capability/index.js +2 -1
- package/dist/capability/index.js.map +1 -1
- package/dist/capability/lib/authority-effect.d.ts +8 -0
- package/dist/capability/lib/authority-effect.d.ts.map +1 -0
- package/dist/capability/lib/authority-effect.js +17 -0
- package/dist/capability/lib/authority-effect.js.map +1 -0
- package/dist/capability/lib/capability-contribution.d.ts +2 -0
- package/dist/capability/lib/capability-contribution.d.ts.map +1 -1
- package/dist/capability/lib/capability-contribution.js +2 -0
- package/dist/capability/lib/capability-contribution.js.map +1 -1
- package/dist/capability/lib/capability-domain.d.ts +8 -0
- package/dist/capability/lib/capability-domain.d.ts.map +1 -0
- package/dist/capability/lib/capability-domain.js +24 -0
- package/dist/capability/lib/capability-domain.js.map +1 -0
- package/dist/capability/lib/meta-tool.d.ts +51 -14
- package/dist/capability/lib/meta-tool.d.ts.map +1 -1
- package/dist/capability/lib/meta-tool.js +66 -12
- package/dist/capability/lib/meta-tool.js.map +1 -1
- package/dist/capability-projection/index.d.ts +4 -0
- package/dist/capability-projection/index.d.ts.map +1 -0
- package/dist/capability-projection/index.js +20 -0
- package/dist/capability-projection/index.js.map +1 -0
- package/dist/capability-projection/lib/capability-invocation-binding.d.ts +72 -0
- package/dist/capability-projection/lib/capability-invocation-binding.d.ts.map +1 -0
- package/dist/capability-projection/lib/capability-invocation-binding.js +101 -0
- package/dist/capability-projection/lib/capability-invocation-binding.js.map +1 -0
- package/dist/capability-projection/lib/capability-sync-manifest.d.ts +8 -0
- package/dist/capability-projection/lib/capability-sync-manifest.d.ts.map +1 -0
- package/dist/capability-projection/lib/capability-sync-manifest.js +8 -0
- package/dist/capability-projection/lib/capability-sync-manifest.js.map +1 -0
- package/dist/capability-projection/lib/projected-capability.d.ts +15 -0
- package/dist/capability-projection/lib/projected-capability.d.ts.map +1 -0
- package/dist/capability-projection/lib/projected-capability.js +17 -0
- package/dist/capability-projection/lib/projected-capability.js.map +1 -0
- package/dist/connector/lib/connector-adapter-contribution.d.ts +2 -0
- package/dist/connector/lib/connector-adapter-contribution.d.ts.map +1 -1
- package/dist/connector/lib/onboarding-manifest.d.ts +2 -0
- package/dist/connector/lib/onboarding-manifest.d.ts.map +1 -1
- package/dist/connector/lib/onboarding-manifest.js +1 -0
- package/dist/connector/lib/onboarding-manifest.js.map +1 -1
- package/dist/connector/lib/provider-descriptor.d.ts +2 -0
- package/dist/connector/lib/provider-descriptor.d.ts.map +1 -1
- package/dist/contribution/lib/contribution-kind.d.ts +1 -4
- package/dist/contribution/lib/contribution-kind.d.ts.map +1 -1
- package/dist/contribution/lib/contribution-kind.js +1 -4
- package/dist/contribution/lib/contribution-kind.js.map +1 -1
- package/dist/distribution/index.d.ts +1 -0
- package/dist/distribution/index.d.ts.map +1 -1
- package/dist/distribution/index.js +1 -0
- package/dist/distribution/index.js.map +1 -1
- package/dist/distribution/lib/distribution-lock.d.ts +6 -0
- package/dist/distribution/lib/distribution-lock.d.ts.map +1 -1
- package/dist/distribution/lib/distribution-lock.js +9 -1
- package/dist/distribution/lib/distribution-lock.js.map +1 -1
- package/dist/distribution/lib/first-party-capability-domains.d.ts +15 -0
- package/dist/distribution/lib/first-party-capability-domains.d.ts.map +1 -0
- package/dist/distribution/lib/first-party-capability-domains.js +52 -0
- package/dist/distribution/lib/first-party-capability-domains.js.map +1 -0
- package/dist/object/lib/xema-object-ref.d.ts +0 -5
- package/dist/object/lib/xema-object-ref.d.ts.map +1 -1
- package/dist/object/lib/xema-object-ref.js +12 -62
- package/dist/object/lib/xema-object-ref.js.map +1 -1
- package/dist/output-surface-inspect/index.d.ts +1 -0
- package/dist/output-surface-inspect/index.d.ts.map +1 -1
- package/dist/output-surface-inspect/index.js +1 -0
- package/dist/output-surface-inspect/index.js.map +1 -1
- package/dist/output-surface-inspect/lib/buffers.d.ts +52 -0
- package/dist/output-surface-inspect/lib/buffers.d.ts.map +1 -0
- package/dist/output-surface-inspect/lib/buffers.js +132 -0
- package/dist/output-surface-inspect/lib/buffers.js.map +1 -0
- package/dist/output-surface-inspect/lib/output-surface-inspect.d.ts +6 -1
- package/dist/output-surface-inspect/lib/output-surface-inspect.d.ts.map +1 -1
- package/dist/output-surface-inspect/lib/output-surface-inspect.js +12 -1
- package/dist/output-surface-inspect/lib/output-surface-inspect.js.map +1 -1
- package/dist/output-surface-inspect/lib/step-schema.d.ts +2 -1
- package/dist/output-surface-inspect/lib/step-schema.d.ts.map +1 -1
- package/dist/output-surface-inspect/lib/step-schema.js +9 -2
- package/dist/output-surface-inspect/lib/step-schema.js.map +1 -1
- package/dist/output-surface-inspect/runtime/index.d.ts +1 -0
- package/dist/output-surface-inspect/runtime/index.d.ts.map +1 -1
- package/dist/output-surface-inspect/runtime/index.js +1 -0
- package/dist/output-surface-inspect/runtime/index.js.map +1 -1
- package/dist/search/index.d.ts +1 -0
- package/dist/search/index.d.ts.map +1 -1
- package/dist/search/index.js +1 -0
- package/dist/search/index.js.map +1 -1
- package/dist/search/lib/route-template.d.ts +31 -0
- package/dist/search/lib/route-template.d.ts.map +1 -0
- package/dist/search/lib/route-template.js +142 -0
- package/dist/search/lib/route-template.js.map +1 -0
- package/dist/search/lib/search-contribution.d.ts +2 -0
- package/dist/search/lib/search-contribution.d.ts.map +1 -1
- package/dist/search/lib/search-contribution.js +34 -1
- package/dist/search/lib/search-contribution.js.map +1 -1
- package/dist/search-source/lib/indexable-document.d.ts +22 -0
- package/dist/search-source/lib/indexable-document.d.ts.map +1 -1
- package/dist/search-source/lib/indexable-document.js +10 -1
- package/dist/search-source/lib/indexable-document.js.map +1 -1
- package/dist/search-source/lib/search-index-event.d.ts +10 -0
- package/dist/search-source/lib/search-index-event.d.ts.map +1 -1
- package/dist/search-source/lib/search-ref.d.ts.map +1 -1
- package/dist/search-source/lib/search-ref.js +11 -2
- package/dist/search-source/lib/search-ref.js.map +1 -1
- package/dist/search-source/lib/search-replay.d.ts +10 -0
- package/dist/search-source/lib/search-replay.d.ts.map +1 -1
- package/dist/service-registry/lib/service-descriptor.d.ts +1 -0
- package/dist/service-registry/lib/service-descriptor.d.ts.map +1 -1
- package/dist/space/lib/space-ref-parser.d.ts +6 -4
- package/dist/space/lib/space-ref-parser.d.ts.map +1 -1
- package/dist/space/lib/space-ref-parser.js +90 -126
- package/dist/space/lib/space-ref-parser.js.map +1 -1
- package/dist/space/lib/space-traversal.d.ts.map +1 -1
- package/dist/space/lib/space-traversal.js +9 -13
- package/dist/space/lib/space-traversal.js.map +1 -1
- package/dist/space/lib/space.d.ts +7 -0
- package/dist/space/lib/space.d.ts.map +1 -1
- package/dist/space/lib/space.js +48 -29
- package/dist/space/lib/space.js.map +1 -1
- package/dist/subject/lib/subject.d.ts +1 -0
- package/dist/subject/lib/subject.d.ts.map +1 -1
- package/dist/subject/lib/subject.js +1 -0
- package/dist/subject/lib/subject.js.map +1 -1
- package/dist/surface/index.d.ts +4 -0
- package/dist/surface/index.d.ts.map +1 -0
- package/dist/surface/index.js +20 -0
- package/dist/surface/index.js.map +1 -0
- package/dist/surface/lib/surface-contribution.d.ts +24 -0
- package/dist/surface/lib/surface-contribution.d.ts.map +1 -0
- package/dist/surface/lib/surface-contribution.js +23 -0
- package/dist/surface/lib/surface-contribution.js.map +1 -0
- package/dist/surface/lib/surface-kind.d.ts +23 -0
- package/dist/surface/lib/surface-kind.d.ts.map +1 -0
- package/dist/surface/lib/surface-kind.js +27 -0
- package/dist/surface/lib/surface-kind.js.map +1 -0
- package/dist/surface/lib/vista-surface.d.ts +11 -0
- package/dist/surface/lib/vista-surface.d.ts.map +1 -0
- package/dist/surface/lib/vista-surface.js +13 -0
- package/dist/surface/lib/vista-surface.js.map +1 -0
- package/dist/widget/lib/chat-widget-envelope.d.ts.map +1 -1
- package/dist/widget/lib/chat-widget-envelope.js.map +1 -1
- package/dist/workflow/lib/enums.d.ts.map +1 -1
- package/dist/workflow/lib/enums.js.map +1 -1
- package/package.json +1 -1
- package/src/biome/lib/biome-manifest.ts +41 -1
- package/src/capability/index.ts +2 -1
- package/src/capability/lib/authority-effect.ts +88 -0
- package/src/capability/lib/capability-contribution.ts +21 -0
- package/src/capability/lib/capability-domain.ts +51 -0
- package/src/capability/lib/capability-grant.ts +1 -1
- package/src/capability/lib/meta-tool.ts +172 -39
- package/src/capability-projection/index.ts +3 -0
- package/src/capability-projection/lib/capability-invocation-binding.ts +223 -0
- package/src/capability-projection/lib/capability-sync-manifest.ts +52 -0
- package/src/capability-projection/lib/projected-capability.ts +63 -0
- package/src/connector/lib/onboarding-manifest.ts +16 -0
- package/src/contribution/lib/contribution-kind.ts +30 -29
- package/src/distribution/index.ts +1 -0
- package/src/distribution/lib/distribution-lock.ts +36 -0
- package/src/distribution/lib/first-party-capability-domains.ts +166 -0
- package/src/object/lib/xema-object-ref.ts +27 -82
- package/src/output-surface-inspect/index.ts +2 -0
- package/src/output-surface-inspect/lib/buffers.ts +252 -0
- package/src/output-surface-inspect/lib/output-surface-inspect.ts +65 -6
- package/src/output-surface-inspect/lib/step-schema.ts +36 -3
- package/src/output-surface-inspect/runtime/index.ts +1 -0
- package/src/search/index.ts +1 -0
- package/src/search/lib/route-template.ts +381 -0
- package/src/search/lib/search-contribution.ts +84 -11
- package/src/search-source/lib/indexable-document.ts +44 -0
- package/src/search-source/lib/search-ref.ts +22 -9
- package/src/service-registry/lib/service-descriptor.ts +16 -0
- package/src/space/lib/skill-mirror-path.ts +1 -1
- package/src/space/lib/space-ref-parser.ts +190 -165
- package/src/space/lib/space-traversal.ts +34 -17
- package/src/space/lib/space.ts +110 -35
- package/src/subject/lib/subject.ts +16 -0
- package/src/surface/index.ts +3 -0
- package/src/surface/lib/surface-contribution.ts +101 -0
- package/src/surface/lib/surface-kind.ts +65 -0
- package/src/surface/lib/vista-surface.ts +44 -0
- package/src/widget/lib/chat-widget-envelope.ts +6 -2
- package/src/workflow/lib/enums.ts +6 -7
- package/dist/capability/lib/first-party-capability-domains.d.ts +0 -30
- package/dist/capability/lib/first-party-capability-domains.d.ts.map +0 -1
- package/dist/capability/lib/first-party-capability-domains.js +0 -36
- package/dist/capability/lib/first-party-capability-domains.js.map +0 -1
- package/src/capability/lib/first-party-capability-domains.ts +0 -77
|
@@ -3,23 +3,42 @@ import { z } from 'zod';
|
|
|
3
3
|
import { CapabilityRefSchema, type CapabilityRef } from './capability-ref';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* The agent-facing MCP surface collapses to
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* The agent-facing MCP surface collapses to a fixed, small set of meta-tools.
|
|
7
|
+
* The set is CLOSED — no free-form strings — so we ship the canonical names as
|
|
8
|
+
* a kernel enum that the router controller, the mcp-gateway federation bridge,
|
|
9
|
+
* and any downstream client can all agree on.
|
|
10
10
|
*
|
|
11
11
|
* The string values are the wire names emitted to OpenCode via the
|
|
12
12
|
* mcp-gateway federation bridge (`resolveAsMetaTools()`). They are also the
|
|
13
13
|
* suffix segments of the router HTTP routes:
|
|
14
14
|
*
|
|
15
|
-
* POST /xema/capabilities/
|
|
16
|
-
* POST /xema/capabilities/describe
|
|
17
|
-
* POST /xema/capabilities/invoke
|
|
15
|
+
* POST /xema/capabilities/search → MetaToolName.Search
|
|
16
|
+
* POST /xema/capabilities/describe → MetaToolName.Describe
|
|
17
|
+
* POST /xema/capabilities/invoke → MetaToolName.Invoke
|
|
18
|
+
* POST /xema/capabilities/plan → MetaToolName.Plan
|
|
19
|
+
* POST /xema/capabilities/preflight → MetaToolName.Preflight
|
|
20
|
+
* POST /xema/capabilities/explain → MetaToolName.Explain
|
|
21
|
+
*
|
|
22
|
+
* `search` REPLACED the former `list` (gap X11). `list` returned the WHOLE
|
|
23
|
+
* catalogue and probed the PDP once per record, sequentially — O(catalogue)
|
|
24
|
+
* round-trips that collapse the moment capability projection takes the
|
|
25
|
+
* registry past a few hundred rows. `search` is anchor → traverse → rank over
|
|
26
|
+
* the derived capability graph and is O(neighbourhood). There is deliberately
|
|
27
|
+
* NO `list` alias: an unbounded catalogue read is not a supported operation.
|
|
28
|
+
*
|
|
29
|
+
* `plan` / `preflight` / `explain` are the graph's other three answers. They
|
|
30
|
+
* are thin, subject-scoped projections of `capability-registry-api`'s
|
|
31
|
+
* `/capability-graph/*` surface, which OWNS their wire shape — the kernel
|
|
32
|
+
* therefore names them and stops there rather than forking a second copy of
|
|
33
|
+
* those DTOs (see `docs`/`.claude/plans/canopy-universal-agent.md` §5.4).
|
|
18
34
|
*/
|
|
19
35
|
export enum MetaToolName {
|
|
20
|
-
|
|
36
|
+
Search = 'xema.capabilities.search',
|
|
21
37
|
Describe = 'xema.capabilities.describe',
|
|
22
38
|
Invoke = 'xema.capabilities.invoke',
|
|
39
|
+
Plan = 'xema.capabilities.plan',
|
|
40
|
+
Preflight = 'xema.capabilities.preflight',
|
|
41
|
+
Explain = 'xema.capabilities.explain',
|
|
23
42
|
}
|
|
24
43
|
|
|
25
44
|
export const MetaToolNameSchema = z.nativeEnum(MetaToolName);
|
|
@@ -38,16 +57,19 @@ export const META_TOOL_AUDIT_TOPIC = 'capability.invoked.v1';
|
|
|
38
57
|
* truth.
|
|
39
58
|
*/
|
|
40
59
|
export const META_TOOL_ROUTE_SUFFIX: Readonly<Record<MetaToolName, string>> = {
|
|
41
|
-
[MetaToolName.
|
|
60
|
+
[MetaToolName.Search]: 'search',
|
|
42
61
|
[MetaToolName.Describe]: 'describe',
|
|
43
62
|
[MetaToolName.Invoke]: 'invoke',
|
|
63
|
+
[MetaToolName.Plan]: 'plan',
|
|
64
|
+
[MetaToolName.Preflight]: 'preflight',
|
|
65
|
+
[MetaToolName.Explain]: 'explain',
|
|
44
66
|
};
|
|
45
67
|
|
|
46
68
|
// ─── Shared sub-types ───────────────────────────────────────────────────────
|
|
47
69
|
|
|
48
70
|
/**
|
|
49
71
|
* Reference to the biome that ships a capability — surfaced on every
|
|
50
|
-
* `
|
|
72
|
+
* `CapabilitySearchEntry` + `CapabilityDescribeEntry` so the agent can show
|
|
51
73
|
* provenance ("this tool came from biome X@1.4.0") to the human in the loop.
|
|
52
74
|
*/
|
|
53
75
|
export interface MetaToolBiomeRef {
|
|
@@ -60,66 +82,177 @@ export const MetaToolBiomeRefSchema: z.ZodType<MetaToolBiomeRef> = z.object({
|
|
|
60
82
|
version: z.string().min(1),
|
|
61
83
|
});
|
|
62
84
|
|
|
63
|
-
|
|
85
|
+
/**
|
|
86
|
+
* Policy decision kinds surfaced by meta-tool projections. Mirrors
|
|
87
|
+
* `@xemahq/policy-contracts/PolicyDecisionKind` value-for-value; we redefine
|
|
88
|
+
* it here so capability-contracts stays a leaf with no upward kernel deps.
|
|
89
|
+
*/
|
|
90
|
+
export enum MetaToolPolicyDecision {
|
|
91
|
+
Allow = 'allow',
|
|
92
|
+
Deny = 'deny',
|
|
93
|
+
NeedsApproval = 'needs_approval',
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export const MetaToolPolicyDecisionSchema = z.nativeEnum(MetaToolPolicyDecision);
|
|
97
|
+
|
|
98
|
+
// ─── search ─────────────────────────────────────────────────────────────────
|
|
99
|
+
|
|
100
|
+
/** Default / hard upper bound on one `search` page. */
|
|
101
|
+
export const META_TOOL_SEARCH_DEFAULT_LIMIT = 20;
|
|
102
|
+
export const META_TOOL_SEARCH_MAX_LIMIT = 50;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* How a capability reaches the anchor resource type of a search.
|
|
106
|
+
*
|
|
107
|
+
* Value-identical to `capability-registry-api`'s `NeighbourhoodRelation`
|
|
108
|
+
* (the graph owns the edges; this is the kernel vocabulary every consumer
|
|
109
|
+
* agrees on). {@link parseCapabilityRelation} fail-fasts if the two ever
|
|
110
|
+
* drift, so the mirror can never rot silently.
|
|
111
|
+
*/
|
|
112
|
+
export enum CapabilityRelation {
|
|
113
|
+
/** The capability's ref grammar declares the anchor as its subject. */
|
|
114
|
+
ActsOn = 'acts_on',
|
|
115
|
+
/** The capability takes a reference to the anchor type as input. */
|
|
116
|
+
Consumes = 'consumes',
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** Fail-fast parse of a graph-sourced relation string. Never coerces. */
|
|
120
|
+
export function parseCapabilityRelation(raw: string): CapabilityRelation {
|
|
121
|
+
const values = Object.values(CapabilityRelation) as string[];
|
|
122
|
+
if (!values.includes(raw)) {
|
|
123
|
+
throw new Error(
|
|
124
|
+
`Unknown capability relation "${raw}". Expected one of ${values.join(', ')}.`,
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
return raw as CapabilityRelation;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Whether invoking a capability changes state.
|
|
132
|
+
*
|
|
133
|
+
* STRUCTURALLY derived from the capability's persisted
|
|
134
|
+
* `CapabilityInvocationBinding` — never guessed from prose (`sideEffects` is
|
|
135
|
+
* free text) and never guessed from the ref verb (an open vocabulary). An
|
|
136
|
+
* `http` binding states its method, which is decisive; every other binding
|
|
137
|
+
* kind states nothing about mutation, so it is reported as
|
|
138
|
+
* {@link CapabilityMutationClass.Undetermined} rather than assumed either way.
|
|
139
|
+
*/
|
|
140
|
+
export enum CapabilityMutationClass {
|
|
141
|
+
Read = 'read',
|
|
142
|
+
Mutating = 'mutating',
|
|
143
|
+
Undetermined = 'undetermined',
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** Where a search's anchor resource type came from. */
|
|
147
|
+
export enum CapabilitySearchAnchorSource {
|
|
148
|
+
/** The caller named `resourceType` explicitly. */
|
|
149
|
+
Explicit = 'explicit',
|
|
150
|
+
/** A token of `query` matched a resource type known to the graph. */
|
|
151
|
+
DerivedFromQuery = 'derived-from-query',
|
|
152
|
+
/** No anchor — the search fell back to the bounded catalogue scan. */
|
|
153
|
+
None = 'none',
|
|
154
|
+
}
|
|
64
155
|
|
|
65
156
|
/**
|
|
66
|
-
* Request envelope for `xema.capabilities.
|
|
67
|
-
* `executionContext` payload (validated server-side against
|
|
157
|
+
* Request envelope for `xema.capabilities.search`. The router carries an
|
|
158
|
+
* opaque `executionContext` payload (validated server-side against
|
|
68
159
|
* `@xemahq/execution-context-contracts`) so the meta-tool surface and the
|
|
69
|
-
* grant-cache key
|
|
160
|
+
* grant-cache key share the same shape.
|
|
70
161
|
*/
|
|
71
|
-
export interface
|
|
162
|
+
export interface CapabilitySearchRequest {
|
|
72
163
|
readonly executionContext: Record<string, unknown>;
|
|
73
|
-
readonly
|
|
164
|
+
readonly query?: string | undefined;
|
|
165
|
+
readonly domain?: string | undefined;
|
|
166
|
+
readonly resourceType?: string | undefined;
|
|
167
|
+
readonly mutating?: boolean | undefined;
|
|
168
|
+
readonly limit?: number | undefined;
|
|
169
|
+
readonly cursor?: string | undefined;
|
|
74
170
|
}
|
|
75
171
|
|
|
76
|
-
export const
|
|
172
|
+
export const CapabilitySearchRequestSchema: z.ZodType<CapabilitySearchRequest> =
|
|
77
173
|
z.object({
|
|
78
174
|
executionContext: z.record(z.string(), z.unknown()),
|
|
79
|
-
|
|
175
|
+
query: z.string().optional(),
|
|
176
|
+
domain: z.string().optional(),
|
|
177
|
+
resourceType: z.string().optional(),
|
|
178
|
+
mutating: z.boolean().optional(),
|
|
179
|
+
limit: z
|
|
180
|
+
.number()
|
|
181
|
+
.int()
|
|
182
|
+
.min(1)
|
|
183
|
+
.max(META_TOOL_SEARCH_MAX_LIMIT)
|
|
184
|
+
.optional(),
|
|
185
|
+
cursor: z.string().optional(),
|
|
80
186
|
});
|
|
81
187
|
|
|
82
188
|
/**
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
189
|
+
* One search hit. Every entry returned is one the subject is AUTHORIZED to
|
|
190
|
+
* invoke — there is no `policyDecision` field and no `includeDenied` switch,
|
|
191
|
+
* because offering an action the caller cannot perform is worse than offering
|
|
192
|
+
* none (the agent will attempt it).
|
|
86
193
|
*/
|
|
87
|
-
export
|
|
88
|
-
Allow = 'allow',
|
|
89
|
-
Deny = 'deny',
|
|
90
|
-
NeedsApproval = 'needs_approval',
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export const MetaToolPolicyDecisionSchema = z.nativeEnum(MetaToolPolicyDecision);
|
|
94
|
-
|
|
95
|
-
export interface CapabilityListEntry {
|
|
194
|
+
export interface CapabilitySearchEntry {
|
|
96
195
|
readonly ref: CapabilityRef;
|
|
97
196
|
readonly biome: MetaToolBiomeRef;
|
|
98
197
|
readonly title: string;
|
|
99
198
|
readonly summary: string;
|
|
100
199
|
readonly riskTier: string;
|
|
101
|
-
readonly
|
|
102
|
-
readonly
|
|
200
|
+
readonly requiresApproval: boolean;
|
|
201
|
+
readonly mutation: CapabilityMutationClass;
|
|
202
|
+
/** Present only on an anchored search. */
|
|
203
|
+
readonly relation?: CapabilityRelation | undefined;
|
|
204
|
+
/** `child_of` hops from the anchor. Present only on an anchored search. */
|
|
205
|
+
readonly distance?: number | undefined;
|
|
206
|
+
/** Resource type this capability touches. Present only on an anchored search. */
|
|
207
|
+
readonly resourceType?: string | undefined;
|
|
103
208
|
}
|
|
104
209
|
|
|
105
|
-
export const
|
|
210
|
+
export const CapabilitySearchEntrySchema: z.ZodType<CapabilitySearchEntry> =
|
|
106
211
|
z.object({
|
|
107
212
|
ref: CapabilityRefSchema,
|
|
108
213
|
biome: MetaToolBiomeRefSchema,
|
|
109
214
|
title: z.string().min(1),
|
|
110
215
|
summary: z.string(),
|
|
111
216
|
riskTier: z.string().min(1),
|
|
112
|
-
|
|
113
|
-
|
|
217
|
+
requiresApproval: z.boolean(),
|
|
218
|
+
mutation: z.nativeEnum(CapabilityMutationClass),
|
|
219
|
+
relation: z.nativeEnum(CapabilityRelation).optional(),
|
|
220
|
+
distance: z.number().int().min(0).optional(),
|
|
221
|
+
resourceType: z.string().optional(),
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
export interface CapabilitySearchAnchor {
|
|
225
|
+
readonly resourceType: string | null;
|
|
226
|
+
readonly source: CapabilitySearchAnchorSource;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export const CapabilitySearchAnchorSchema: z.ZodType<CapabilitySearchAnchor> =
|
|
230
|
+
z.object({
|
|
231
|
+
resourceType: z.string().nullable(),
|
|
232
|
+
source: z.nativeEnum(CapabilitySearchAnchorSource),
|
|
114
233
|
});
|
|
115
234
|
|
|
116
|
-
export interface
|
|
117
|
-
readonly capabilities: readonly
|
|
235
|
+
export interface CapabilitySearchResponse {
|
|
236
|
+
readonly capabilities: readonly CapabilitySearchEntry[];
|
|
237
|
+
readonly anchor: CapabilitySearchAnchor;
|
|
238
|
+
/**
|
|
239
|
+
* Candidates considered before the authority filter. Compare with
|
|
240
|
+
* `capabilities.length` to see how much authority removed.
|
|
241
|
+
*/
|
|
242
|
+
readonly consideredCount: number;
|
|
243
|
+
/** Opaque continuation token. Absent ⇒ this is the last page. */
|
|
244
|
+
readonly nextCursor?: string | undefined;
|
|
245
|
+
/** Graph build generation that answered an anchored search. */
|
|
246
|
+
readonly generation?: number | undefined;
|
|
118
247
|
}
|
|
119
248
|
|
|
120
|
-
export const
|
|
249
|
+
export const CapabilitySearchResponseSchema: z.ZodType<CapabilitySearchResponse> =
|
|
121
250
|
z.object({
|
|
122
|
-
capabilities: z.array(
|
|
251
|
+
capabilities: z.array(CapabilitySearchEntrySchema).readonly(),
|
|
252
|
+
anchor: CapabilitySearchAnchorSchema,
|
|
253
|
+
consideredCount: z.number().int().min(0),
|
|
254
|
+
nextCursor: z.string().optional(),
|
|
255
|
+
generation: z.number().int().min(0).optional(),
|
|
123
256
|
});
|
|
124
257
|
|
|
125
258
|
// ─── describe ───────────────────────────────────────────────────────────────
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
ConnectorAdapterKind,
|
|
5
|
+
ConnectorAdapterKindSchema,
|
|
6
|
+
} from '../../connector';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* ─────────────────────────────────────────────────────────────────────────
|
|
10
|
+
* `CapabilityInvocationBinding` — HOW a projected capability is actually
|
|
11
|
+
* invoked, carried as DATA on the capability itself.
|
|
12
|
+
*
|
|
13
|
+
* This is the contract that lets the capability router resolve a target by
|
|
14
|
+
* LOOKUP instead of a hand-maintained `switch` over domains: every producer
|
|
15
|
+
* that projects a capability also declares the binding that executes it.
|
|
16
|
+
*
|
|
17
|
+
* `kind` is a CLOSED set ({@link CapabilityInvocationKind}). Adding a member
|
|
18
|
+
* is a kernel change AND requires a matching dispatch branch in whatever
|
|
19
|
+
* executes bindings — do not add a member that has no executor.
|
|
20
|
+
* ─────────────────────────────────────────────────────────────────────────
|
|
21
|
+
*/
|
|
22
|
+
export enum CapabilityInvocationKind {
|
|
23
|
+
/** A direct HTTP call to a first-party service resolved from the registry. */
|
|
24
|
+
Http = 'http',
|
|
25
|
+
/** A connector operation executed by the connector backend. */
|
|
26
|
+
Connector = 'connector',
|
|
27
|
+
/** A workflow dispatched by slug. */
|
|
28
|
+
Workflow = 'workflow',
|
|
29
|
+
/** A tool call proxied to a registered MCP server. */
|
|
30
|
+
Mcp = 'mcp',
|
|
31
|
+
/** An in-process handler resolved by key inside the owning service. */
|
|
32
|
+
Inline = 'inline',
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const CapabilityInvocationKindSchema = z.nativeEnum(
|
|
36
|
+
CapabilityInvocationKind,
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
/** HTTP verbs a projected capability may bind to. Closed set. */
|
|
40
|
+
export enum CapabilityHttpMethod {
|
|
41
|
+
Get = 'GET',
|
|
42
|
+
Post = 'POST',
|
|
43
|
+
Put = 'PUT',
|
|
44
|
+
Patch = 'PATCH',
|
|
45
|
+
Delete = 'DELETE',
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export const CapabilityHttpMethodSchema = z.nativeEnum(CapabilityHttpMethod);
|
|
49
|
+
|
|
50
|
+
/** Where an HTTP parameter is carried on the wire. Closed set. */
|
|
51
|
+
export enum CapabilityHttpParameterIn {
|
|
52
|
+
Path = 'path',
|
|
53
|
+
Query = 'query',
|
|
54
|
+
Header = 'header',
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export const CapabilityHttpParameterInSchema = z.nativeEnum(
|
|
58
|
+
CapabilityHttpParameterIn,
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* RFC-6901 JSON Pointer into the capability INPUT document. Deliberately
|
|
63
|
+
* strict — a pointer is the only supported way to address input data, so a
|
|
64
|
+
* binding can never carry a free-form expression that some executor would
|
|
65
|
+
* have to interpret heuristically.
|
|
66
|
+
*/
|
|
67
|
+
const JSON_POINTER_REGEX = /^(?:\/[^/]+)+$/;
|
|
68
|
+
|
|
69
|
+
export const CapabilityInputPointerSchema = z.string().regex(
|
|
70
|
+
JSON_POINTER_REGEX,
|
|
71
|
+
{
|
|
72
|
+
message:
|
|
73
|
+
'inputPointer must be a non-empty RFC-6901 JSON Pointer into the capability input (e.g. `/projectId`).',
|
|
74
|
+
},
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
/** One HTTP parameter of an {@link HttpCapabilityInvocation}. */
|
|
78
|
+
export interface CapabilityHttpParameterBinding {
|
|
79
|
+
/** Wire name of the parameter (path placeholder / query key / header name). */
|
|
80
|
+
readonly name: string;
|
|
81
|
+
readonly in: CapabilityHttpParameterIn;
|
|
82
|
+
/** JSON Pointer into the capability input that supplies the value. */
|
|
83
|
+
readonly inputPointer: string;
|
|
84
|
+
/** Whether the executor must refuse the call when the pointer resolves to nothing. */
|
|
85
|
+
readonly required: boolean;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export const CapabilityHttpParameterBindingSchema: z.ZodType<CapabilityHttpParameterBinding> =
|
|
89
|
+
z.object({
|
|
90
|
+
name: z.string().min(1).max(200),
|
|
91
|
+
in: CapabilityHttpParameterInSchema,
|
|
92
|
+
inputPointer: CapabilityInputPointerSchema,
|
|
93
|
+
required: z.boolean(),
|
|
94
|
+
}) as unknown as z.ZodType<CapabilityHttpParameterBinding>;
|
|
95
|
+
|
|
96
|
+
/** How the request body of an {@link HttpCapabilityInvocation} is built. Closed set. */
|
|
97
|
+
export enum CapabilityHttpBodyMode {
|
|
98
|
+
/** The whole capability input document IS the body. */
|
|
99
|
+
WholeInput = 'whole-input',
|
|
100
|
+
/** A sub-document of the capability input, addressed by `inputPointer`, is the body. */
|
|
101
|
+
InputPointer = 'input-pointer',
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export const CapabilityHttpBodyModeSchema = z.nativeEnum(
|
|
105
|
+
CapabilityHttpBodyMode,
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
export interface CapabilityHttpBodyBinding {
|
|
109
|
+
readonly mode: CapabilityHttpBodyMode;
|
|
110
|
+
/** REQUIRED iff `mode` is `input-pointer`; MUST be absent otherwise. */
|
|
111
|
+
readonly inputPointer?: string;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export const CapabilityHttpBodyBindingSchema: z.ZodType<CapabilityHttpBodyBinding> =
|
|
115
|
+
z
|
|
116
|
+
.object({
|
|
117
|
+
mode: CapabilityHttpBodyModeSchema,
|
|
118
|
+
inputPointer: CapabilityInputPointerSchema.optional(),
|
|
119
|
+
})
|
|
120
|
+
.superRefine((value, ctx) => {
|
|
121
|
+
const needsPointer = value.mode === CapabilityHttpBodyMode.InputPointer;
|
|
122
|
+
if (needsPointer && value.inputPointer === undefined) {
|
|
123
|
+
ctx.addIssue({
|
|
124
|
+
code: 'custom',
|
|
125
|
+
path: ['inputPointer'],
|
|
126
|
+
message: 'inputPointer is REQUIRED when mode is `input-pointer`.',
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
if (!needsPointer && value.inputPointer !== undefined) {
|
|
130
|
+
ctx.addIssue({
|
|
131
|
+
code: 'custom',
|
|
132
|
+
path: ['inputPointer'],
|
|
133
|
+
message: 'inputPointer is only allowed when mode is `input-pointer`.',
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}) as unknown as z.ZodType<CapabilityHttpBodyBinding>;
|
|
137
|
+
|
|
138
|
+
/** Service name as registered in the kernel service registry (kebab-case). */
|
|
139
|
+
const SERVICE_NAME_REGEX = /^[a-z][a-z0-9-]*$/;
|
|
140
|
+
|
|
141
|
+
export interface HttpCapabilityInvocation {
|
|
142
|
+
readonly kind: CapabilityInvocationKind.Http;
|
|
143
|
+
/** Registry name of the target service — resolved, never a hardcoded host. */
|
|
144
|
+
readonly serviceName: string;
|
|
145
|
+
readonly method: CapabilityHttpMethod;
|
|
146
|
+
/** Route template with `:param` / `{param}` placeholders, always absolute. */
|
|
147
|
+
readonly path: string;
|
|
148
|
+
readonly parameters: readonly CapabilityHttpParameterBinding[];
|
|
149
|
+
/** Absent for verbs that carry no body. */
|
|
150
|
+
readonly body?: CapabilityHttpBodyBinding;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export interface ConnectorCapabilityInvocation {
|
|
154
|
+
readonly kind: CapabilityInvocationKind.Connector;
|
|
155
|
+
/** Connector descriptor key (e.g. `ACME_CRM`). */
|
|
156
|
+
readonly connectorKey: string;
|
|
157
|
+
/** Operation key within the connector (its capability verb). */
|
|
158
|
+
readonly operationKey: string;
|
|
159
|
+
/**
|
|
160
|
+
* The operation's OWN backend discriminator. It is part of the BINDING (not
|
|
161
|
+
* of the connector) because two operations of the same connector may be
|
|
162
|
+
* served by different backends, and it is what the capability router
|
|
163
|
+
* dispatches on today.
|
|
164
|
+
*/
|
|
165
|
+
readonly adapterKind: ConnectorAdapterKind;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export interface WorkflowCapabilityInvocation {
|
|
169
|
+
readonly kind: CapabilityInvocationKind.Workflow;
|
|
170
|
+
readonly workflowSlug: string;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export interface McpCapabilityInvocation {
|
|
174
|
+
readonly kind: CapabilityInvocationKind.Mcp;
|
|
175
|
+
readonly serverId: string;
|
|
176
|
+
readonly toolName: string;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export interface InlineCapabilityInvocation {
|
|
180
|
+
readonly kind: CapabilityInvocationKind.Inline;
|
|
181
|
+
/** Key the owning service resolves to an in-process handler. */
|
|
182
|
+
readonly handlerKey: string;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export type CapabilityInvocationBinding =
|
|
186
|
+
| HttpCapabilityInvocation
|
|
187
|
+
| ConnectorCapabilityInvocation
|
|
188
|
+
| WorkflowCapabilityInvocation
|
|
189
|
+
| McpCapabilityInvocation
|
|
190
|
+
| InlineCapabilityInvocation;
|
|
191
|
+
|
|
192
|
+
export const CapabilityInvocationBindingSchema: z.ZodType<CapabilityInvocationBinding> =
|
|
193
|
+
z.discriminatedUnion('kind', [
|
|
194
|
+
z.object({
|
|
195
|
+
kind: z.literal(CapabilityInvocationKind.Http),
|
|
196
|
+
serviceName: z.string().regex(SERVICE_NAME_REGEX, {
|
|
197
|
+
message: 'serviceName must be a kebab-case service-registry name.',
|
|
198
|
+
}),
|
|
199
|
+
method: CapabilityHttpMethodSchema,
|
|
200
|
+
path: z.string().startsWith('/').min(1).max(2000),
|
|
201
|
+
parameters: z.array(CapabilityHttpParameterBindingSchema),
|
|
202
|
+
body: CapabilityHttpBodyBindingSchema.optional(),
|
|
203
|
+
}),
|
|
204
|
+
z.object({
|
|
205
|
+
kind: z.literal(CapabilityInvocationKind.Connector),
|
|
206
|
+
connectorKey: z.string().min(1).max(200),
|
|
207
|
+
operationKey: z.string().min(1).max(200),
|
|
208
|
+
adapterKind: ConnectorAdapterKindSchema,
|
|
209
|
+
}),
|
|
210
|
+
z.object({
|
|
211
|
+
kind: z.literal(CapabilityInvocationKind.Workflow),
|
|
212
|
+
workflowSlug: z.string().min(1).max(200),
|
|
213
|
+
}),
|
|
214
|
+
z.object({
|
|
215
|
+
kind: z.literal(CapabilityInvocationKind.Mcp),
|
|
216
|
+
serverId: z.string().min(1).max(200),
|
|
217
|
+
toolName: z.string().min(1).max(200),
|
|
218
|
+
}),
|
|
219
|
+
z.object({
|
|
220
|
+
kind: z.literal(CapabilityInvocationKind.Inline),
|
|
221
|
+
handlerKey: z.string().min(1).max(200),
|
|
222
|
+
}),
|
|
223
|
+
]) as unknown as z.ZodType<CapabilityInvocationBinding>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
CapabilityContributionManifestSchema,
|
|
5
|
+
type CapabilityContributionManifest,
|
|
6
|
+
} from '../../capability';
|
|
7
|
+
import {
|
|
8
|
+
CapabilityInvocationBindingSchema,
|
|
9
|
+
type CapabilityInvocationBinding,
|
|
10
|
+
} from './capability-invocation-binding';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* ─────────────────────────────────────────────────────────────────────────
|
|
14
|
+
* `CapabilitySyncManifest` — what an AUTHOR declares when publishing a
|
|
15
|
+
* capability, on EVERY publish path.
|
|
16
|
+
*
|
|
17
|
+
* It is the kernel `CapabilityContributionManifest` (what the capability IS)
|
|
18
|
+
* plus an optional {@link CapabilityInvocationBinding} (HOW it is invoked).
|
|
19
|
+
* The two are split across subpaths on purpose — `CapabilityInvocationBinding`
|
|
20
|
+
* depends on the `connector` subpath, which in turn depends on `capability`, so
|
|
21
|
+
* putting `invocation` directly on the contribution manifest would close a
|
|
22
|
+
* subpath cycle. This composition lives HERE, next to `ProjectedCapability`,
|
|
23
|
+
* which composes the same two halves for the DERIVED path.
|
|
24
|
+
*
|
|
25
|
+
* One shape, every producer:
|
|
26
|
+
* - a `*.capability.contribution.json` file / an `xema.contributions.inline[]`
|
|
27
|
+
* entry, parsed by `biome-host-api`'s `CapabilityParser`;
|
|
28
|
+
* - the `@XemaCapability` decorator's boot-time runtime sync;
|
|
29
|
+
* - `capability-registry-api`'s own contribution-sync handler.
|
|
30
|
+
* All three end on `POST /capabilities/sync` with this exact payload.
|
|
31
|
+
*
|
|
32
|
+
* `invocation` is OPTIONAL on the contract because a capability may instead be
|
|
33
|
+
* backed by an org `CapabilityProviderBinding` or by a live runner. It is NOT a
|
|
34
|
+
* soft default: a ref with none of the three FAILS FAST at the capability-router
|
|
35
|
+
* (`CapabilityInvocationBindingMissingError`) rather than degrading.
|
|
36
|
+
*
|
|
37
|
+
* NOTE the mechanical reason this is an INTERSECTION and not a widened object:
|
|
38
|
+
* `CapabilityContributionManifestSchema` is a `z.object` and therefore STRIPS
|
|
39
|
+
* unknown keys, so parsing an envelope through it alone would silently drop the
|
|
40
|
+
* binding. Intersecting merges both parsed outputs, so the binding survives —
|
|
41
|
+
* validated by the same kernel schema every other path uses.
|
|
42
|
+
* ─────────────────────────────────────────────────────────────────────────
|
|
43
|
+
*/
|
|
44
|
+
export interface CapabilitySyncManifest extends CapabilityContributionManifest {
|
|
45
|
+
readonly invocation?: CapabilityInvocationBinding;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export const CapabilitySyncManifestSchema: z.ZodType<CapabilitySyncManifest> =
|
|
49
|
+
z.intersection(
|
|
50
|
+
CapabilityContributionManifestSchema,
|
|
51
|
+
z.object({ invocation: CapabilityInvocationBindingSchema.optional() }),
|
|
52
|
+
) as unknown as z.ZodType<CapabilitySyncManifest>;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
CapabilityContributionManifestSchema,
|
|
5
|
+
type CapabilityContributionManifest,
|
|
6
|
+
} from '../../capability';
|
|
7
|
+
import {
|
|
8
|
+
CapabilityInvocationBindingSchema,
|
|
9
|
+
type CapabilityInvocationBinding,
|
|
10
|
+
} from './capability-invocation-binding';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Where a projected capability came from.
|
|
14
|
+
*
|
|
15
|
+
* `sourceKey` scopes the projector's PRUNE set: a projector may only ever
|
|
16
|
+
* delete refs it previously projected, and a ref is attributed to exactly one
|
|
17
|
+
* source per reconcile. `biomeId` / `biomeVersion` are the same provenance the
|
|
18
|
+
* contribution path stamps — authors never declare them inline.
|
|
19
|
+
*/
|
|
20
|
+
export interface ProjectedCapabilityProvenance {
|
|
21
|
+
readonly sourceKey: string;
|
|
22
|
+
readonly biomeId: string;
|
|
23
|
+
readonly biomeVersion: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const ProjectedCapabilityProvenanceSchema: z.ZodType<ProjectedCapabilityProvenance> =
|
|
27
|
+
z.object({
|
|
28
|
+
sourceKey: z.string().min(1).max(200),
|
|
29
|
+
biomeId: z.string().min(1).max(200),
|
|
30
|
+
biomeVersion: z.string().min(1).max(200),
|
|
31
|
+
}) as unknown as z.ZodType<ProjectedCapabilityProvenance>;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* ─────────────────────────────────────────────────────────────────────────
|
|
35
|
+
* `ProjectedCapability` — one capability DERIVED by a producer, rather than
|
|
36
|
+
* hand-authored as a contribution file.
|
|
37
|
+
*
|
|
38
|
+
* It deliberately EXTENDS {@link CapabilityContributionManifest} instead of
|
|
39
|
+
* restating its fields: the hand-authored path, the decorator path and the
|
|
40
|
+
* projection path must all end up on the SAME `POST /capabilities/register`
|
|
41
|
+
* wire shape, so there is exactly one place that shape is described. A
|
|
42
|
+
* projection adds only the two things a hand-authored descriptor does not
|
|
43
|
+
* carry:
|
|
44
|
+
*
|
|
45
|
+
* - {@link CapabilityInvocationBinding} — HOW to invoke it, as data, so the
|
|
46
|
+
* router resolves a target by lookup instead of a hardcoded switch;
|
|
47
|
+
* - {@link ProjectedCapabilityProvenance} — WHICH source owns it, which is
|
|
48
|
+
* what scopes the reconcile engine's prune set.
|
|
49
|
+
* ─────────────────────────────────────────────────────────────────────────
|
|
50
|
+
*/
|
|
51
|
+
export interface ProjectedCapability extends CapabilityContributionManifest {
|
|
52
|
+
readonly invocation: CapabilityInvocationBinding;
|
|
53
|
+
readonly provenance: ProjectedCapabilityProvenance;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export const ProjectedCapabilitySchema: z.ZodType<ProjectedCapability> = z
|
|
57
|
+
.intersection(
|
|
58
|
+
CapabilityContributionManifestSchema,
|
|
59
|
+
z.object({
|
|
60
|
+
invocation: CapabilityInvocationBindingSchema,
|
|
61
|
+
provenance: ProjectedCapabilityProvenanceSchema,
|
|
62
|
+
}),
|
|
63
|
+
) as unknown as z.ZodType<ProjectedCapability>;
|
|
@@ -99,6 +99,21 @@ export interface CredentialFieldSpec {
|
|
|
99
99
|
readonly type: CredentialFieldType;
|
|
100
100
|
/** When true, the wizard refuses submission unless the field is filled. */
|
|
101
101
|
readonly required: boolean;
|
|
102
|
+
/**
|
|
103
|
+
* DECLARED secrecy of the field's value. `true` ⇒ the value is a secret and
|
|
104
|
+
* MUST travel to credential custody (the broker's opaque `secretValue`
|
|
105
|
+
* bundle); `false` ⇒ the value is non-secret configuration and is stored in
|
|
106
|
+
* the provision's plain JSON config.
|
|
107
|
+
*
|
|
108
|
+
* This is a DECLARATION, never an inference. Secrecy was previously derived
|
|
109
|
+
* from `type === CredentialFieldType.PASSWORD`, which made a *rendering*
|
|
110
|
+
* affordance load-bearing for a *custody* decision: a secret rendered as
|
|
111
|
+
* `TEXT` (an API key an author wanted visible) silently landed in
|
|
112
|
+
* non-secret storage, and a non-secret masked for ergonomics silently landed
|
|
113
|
+
* in custody. `type` now means "how to render it" and `isSecret` means
|
|
114
|
+
* "where it may be stored" — the two are independent and both required.
|
|
115
|
+
*/
|
|
116
|
+
readonly isSecret: boolean;
|
|
102
117
|
/** Optional placeholder copy. */
|
|
103
118
|
readonly placeholder?: string;
|
|
104
119
|
/** Optional secondary hint shown beneath the input. */
|
|
@@ -119,6 +134,7 @@ export const CredentialFieldSpecSchema = z.strictObject({
|
|
|
119
134
|
label: z.string().min(1),
|
|
120
135
|
type: z.nativeEnum(CredentialFieldType),
|
|
121
136
|
required: z.boolean(),
|
|
137
|
+
isSecret: z.boolean(),
|
|
122
138
|
placeholder: z.string().optional(),
|
|
123
139
|
hint: z.string().optional(),
|
|
124
140
|
transform: z.nativeEnum(CredentialFieldTransform),
|