@vinkius-core/mcp-fusion 2.6.0 → 2.8.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/cli/fusion.d.ts +101 -0
- package/dist/cli/fusion.d.ts.map +1 -0
- package/dist/cli/fusion.js +333 -0
- package/dist/cli/fusion.js.map +1 -0
- package/dist/client/FusionClient.d.ts +122 -1
- package/dist/client/FusionClient.d.ts.map +1 -1
- package/dist/client/FusionClient.js +173 -11
- package/dist/client/FusionClient.js.map +1 -1
- package/dist/client/index.d.ts +2 -2
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/core/StandardSchema.d.ts +178 -0
- package/dist/core/StandardSchema.d.ts.map +1 -0
- package/dist/core/StandardSchema.js +166 -0
- package/dist/core/StandardSchema.js.map +1 -0
- package/dist/core/createGroup.d.ts +140 -0
- package/dist/core/createGroup.d.ts.map +1 -0
- package/dist/core/createGroup.js +133 -0
- package/dist/core/createGroup.js.map +1 -0
- package/dist/core/execution/ExecutionPipeline.d.ts.map +1 -1
- package/dist/core/execution/ExecutionPipeline.js +6 -2
- package/dist/core/execution/ExecutionPipeline.js.map +1 -1
- package/dist/core/index.d.ts +7 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +6 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/initFusion.d.ts +201 -0
- package/dist/core/initFusion.d.ts.map +1 -0
- package/dist/core/initFusion.js +134 -0
- package/dist/core/initFusion.js.map +1 -0
- package/dist/core/response.d.ts +49 -2
- package/dist/core/response.d.ts.map +1 -1
- package/dist/core/response.js +27 -5
- package/dist/core/response.js.map +1 -1
- package/dist/index.d.ts +57 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -4
- package/dist/index.js.map +1 -1
- package/dist/introspection/BehaviorDigest.d.ts +112 -0
- package/dist/introspection/BehaviorDigest.d.ts.map +1 -0
- package/dist/introspection/BehaviorDigest.js +146 -0
- package/dist/introspection/BehaviorDigest.js.map +1 -0
- package/dist/introspection/CapabilityLockfile.d.ts +259 -0
- package/dist/introspection/CapabilityLockfile.d.ts.map +1 -0
- package/dist/introspection/CapabilityLockfile.js +391 -0
- package/dist/introspection/CapabilityLockfile.js.map +1 -0
- package/dist/introspection/ContractAwareSelfHealing.d.ts +90 -0
- package/dist/introspection/ContractAwareSelfHealing.d.ts.map +1 -0
- package/dist/introspection/ContractAwareSelfHealing.js +132 -0
- package/dist/introspection/ContractAwareSelfHealing.js.map +1 -0
- package/dist/introspection/ContractDiff.d.ts +91 -0
- package/dist/introspection/ContractDiff.d.ts.map +1 -0
- package/dist/introspection/ContractDiff.js +466 -0
- package/dist/introspection/ContractDiff.js.map +1 -0
- package/dist/introspection/CryptoAttestation.d.ts +143 -0
- package/dist/introspection/CryptoAttestation.d.ts.map +1 -0
- package/dist/introspection/CryptoAttestation.js +194 -0
- package/dist/introspection/CryptoAttestation.js.map +1 -0
- package/dist/introspection/EntitlementScanner.d.ts +124 -0
- package/dist/introspection/EntitlementScanner.d.ts.map +1 -0
- package/dist/introspection/EntitlementScanner.js +244 -0
- package/dist/introspection/EntitlementScanner.js.map +1 -0
- package/dist/introspection/GovernanceObserver.d.ts +88 -0
- package/dist/introspection/GovernanceObserver.d.ts.map +1 -0
- package/dist/introspection/GovernanceObserver.js +132 -0
- package/dist/introspection/GovernanceObserver.js.map +1 -0
- package/dist/introspection/SemanticProbe.d.ts +207 -0
- package/dist/introspection/SemanticProbe.d.ts.map +1 -0
- package/dist/introspection/SemanticProbe.js +255 -0
- package/dist/introspection/SemanticProbe.js.map +1 -0
- package/dist/introspection/TokenEconomics.d.ts +210 -0
- package/dist/introspection/TokenEconomics.d.ts.map +1 -0
- package/dist/introspection/TokenEconomics.js +286 -0
- package/dist/introspection/TokenEconomics.js.map +1 -0
- package/dist/introspection/ToolContract.d.ts +159 -0
- package/dist/introspection/ToolContract.d.ts.map +1 -0
- package/dist/introspection/ToolContract.js +191 -0
- package/dist/introspection/ToolContract.js.map +1 -0
- package/dist/introspection/canonicalize.d.ts +20 -0
- package/dist/introspection/canonicalize.d.ts.map +1 -0
- package/dist/introspection/canonicalize.js +51 -0
- package/dist/introspection/canonicalize.js.map +1 -0
- package/dist/introspection/index.d.ts +20 -0
- package/dist/introspection/index.d.ts.map +1 -1
- package/dist/introspection/index.js +20 -0
- package/dist/introspection/index.js.map +1 -1
- package/dist/observability/DebugObserver.d.ts +26 -1
- package/dist/observability/DebugObserver.d.ts.map +1 -1
- package/dist/observability/DebugObserver.js +8 -1
- package/dist/observability/DebugObserver.js.map +1 -1
- package/dist/observability/index.d.ts +1 -1
- package/dist/observability/index.d.ts.map +1 -1
- package/dist/observability/index.js.map +1 -1
- package/dist/presenter/ZodDescriptionExtractor.d.ts +54 -0
- package/dist/presenter/ZodDescriptionExtractor.d.ts.map +1 -0
- package/dist/presenter/ZodDescriptionExtractor.js +131 -0
- package/dist/presenter/ZodDescriptionExtractor.js.map +1 -0
- package/dist/presenter/definePresenter.d.ts +172 -0
- package/dist/presenter/definePresenter.d.ts.map +1 -0
- package/dist/presenter/definePresenter.js +96 -0
- package/dist/presenter/definePresenter.js.map +1 -0
- package/dist/presenter/index.d.ts +3 -0
- package/dist/presenter/index.d.ts.map +1 -1
- package/dist/presenter/index.js +4 -0
- package/dist/presenter/index.js.map +1 -1
- package/dist/server/DevServer.d.ts +96 -0
- package/dist/server/DevServer.d.ts.map +1 -0
- package/dist/server/DevServer.js +187 -0
- package/dist/server/DevServer.js.map +1 -0
- package/dist/server/ServerAttachment.d.ts +41 -0
- package/dist/server/ServerAttachment.d.ts.map +1 -1
- package/dist/server/ServerAttachment.js +25 -1
- package/dist/server/ServerAttachment.js.map +1 -1
- package/dist/server/autoDiscover.d.ts +63 -0
- package/dist/server/autoDiscover.d.ts.map +1 -0
- package/dist/server/autoDiscover.js +157 -0
- package/dist/server/autoDiscover.js.map +1 -0
- package/dist/server/index.d.ts +4 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +4 -0
- package/dist/server/index.js.map +1 -1
- package/dist/state-sync/PolicyValidator.d.ts +36 -0
- package/dist/state-sync/PolicyValidator.d.ts.map +1 -1
- package/dist/state-sync/PolicyValidator.js +35 -0
- package/dist/state-sync/PolicyValidator.js.map +1 -1
- package/dist/state-sync/ResponseDecorator.d.ts.map +1 -1
- package/dist/state-sync/ResponseDecorator.js +2 -1
- package/dist/state-sync/ResponseDecorator.js.map +1 -1
- package/dist/state-sync/StateSyncLayer.d.ts +5 -4
- package/dist/state-sync/StateSyncLayer.d.ts.map +1 -1
- package/dist/state-sync/StateSyncLayer.js +35 -4
- package/dist/state-sync/StateSyncLayer.js.map +1 -1
- package/dist/state-sync/index.d.ts +3 -1
- package/dist/state-sync/index.d.ts.map +1 -1
- package/dist/state-sync/index.js +1 -0
- package/dist/state-sync/index.js.map +1 -1
- package/dist/state-sync/types.d.ts +62 -0
- package/dist/state-sync/types.d.ts.map +1 -1
- package/package.json +45 -1
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CapabilityLockfile — Behavioral Surface Snapshot
|
|
3
|
+
*
|
|
4
|
+
* Generates a deterministic, human-readable, git-diffable lockfile
|
|
5
|
+
* that captures the complete behavioral surface of an MCP Fusion
|
|
6
|
+
* server at a point in time.
|
|
7
|
+
*
|
|
8
|
+
* **Inspired by**: `yarn.lock`, `package-lock.json`, `Cargo.lock`.
|
|
9
|
+
* Those files snapshot the dependency resolution graph so that every
|
|
10
|
+
* `install` produces the same tree. `mcp-fusion.lock` does the same
|
|
11
|
+
* for the **behavioral surface** — ensuring that every deployment
|
|
12
|
+
* exposes the same tool contracts, cognitive guardrails, entitlements,
|
|
13
|
+
* and token economics that were reviewed and approved.
|
|
14
|
+
*
|
|
15
|
+
* **Why this matters for AI**:
|
|
16
|
+
*
|
|
17
|
+
* An LLM's calibration to a tool server depends on the *behavioral*
|
|
18
|
+
* surface — not just the input schema. If a system rule changes, an
|
|
19
|
+
* affordance link disappears, or a Presenter's egress schema mutates,
|
|
20
|
+
* the LLM may hallucinate or violate requirements. The lockfile makes
|
|
21
|
+
* these invisible changes **visible and auditable** in version control.
|
|
22
|
+
*
|
|
23
|
+
* **Workflow**:
|
|
24
|
+
*
|
|
25
|
+
* ```bash
|
|
26
|
+
* # Generate or update the lockfile
|
|
27
|
+
* fusion lock
|
|
28
|
+
*
|
|
29
|
+
* # CI gate: fail if the lockfile is stale
|
|
30
|
+
* fusion lock --check
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* The lockfile is committed alongside the code. Pull request diffs
|
|
34
|
+
* show exactly which behavioral surfaces changed, enabling reviewers
|
|
35
|
+
* to assess AI-facing impact before merge.
|
|
36
|
+
*
|
|
37
|
+
* Pure-function module for generation and verification.
|
|
38
|
+
* Side-effectful I/O is clearly separated.
|
|
39
|
+
*
|
|
40
|
+
* @module
|
|
41
|
+
*/
|
|
42
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
43
|
+
import { resolve } from 'node:path';
|
|
44
|
+
import { computeServerDigest } from './BehaviorDigest.js';
|
|
45
|
+
import { sha256, canonicalize } from './canonicalize.js';
|
|
46
|
+
// ============================================================================
|
|
47
|
+
// Lockfile Schema
|
|
48
|
+
// ============================================================================
|
|
49
|
+
/** Current lockfile format version. */
|
|
50
|
+
const LOCKFILE_VERSION = 1;
|
|
51
|
+
/** Default lockfile name. */
|
|
52
|
+
export const LOCKFILE_NAME = 'mcp-fusion.lock';
|
|
53
|
+
/**
|
|
54
|
+
* Generate a `CapabilityLockfile` from compiled tool contracts
|
|
55
|
+
* and (optionally) prompt builders.
|
|
56
|
+
*
|
|
57
|
+
* This is a **pure function**: given the same contracts and metadata,
|
|
58
|
+
* it always produces the same lockfile (modulo `generatedAt` timestamp).
|
|
59
|
+
*
|
|
60
|
+
* @param serverName - MCP server name
|
|
61
|
+
* @param contracts - Record of tool name → materialized contract
|
|
62
|
+
* @param fusionVersion - MCP Fusion version string
|
|
63
|
+
* @param options - Optional: prompt builders to include
|
|
64
|
+
* @returns A fully materialized lockfile
|
|
65
|
+
*/
|
|
66
|
+
export function generateLockfile(serverName, contracts, fusionVersion, options) {
|
|
67
|
+
const serverDigest = computeServerDigest(contracts);
|
|
68
|
+
const sortedNames = Object.keys(contracts).sort();
|
|
69
|
+
const tools = {};
|
|
70
|
+
for (const name of sortedNames) {
|
|
71
|
+
tools[name] = snapshotTool(contracts[name], serverDigest.tools[name]);
|
|
72
|
+
}
|
|
73
|
+
// ── Prompt Snapshots ─────────────────────────────────
|
|
74
|
+
const promptBuilders = options?.prompts ?? [];
|
|
75
|
+
let prompts;
|
|
76
|
+
const promptDigestParts = [];
|
|
77
|
+
if (promptBuilders.length > 0) {
|
|
78
|
+
prompts = {};
|
|
79
|
+
const sortedPromptNames = promptBuilders
|
|
80
|
+
.map(b => b.getName())
|
|
81
|
+
.sort();
|
|
82
|
+
for (const name of sortedPromptNames) {
|
|
83
|
+
const builder = promptBuilders.find(b => b.getName() === name);
|
|
84
|
+
const snapshot = snapshotPrompt(builder);
|
|
85
|
+
prompts[name] = snapshot;
|
|
86
|
+
promptDigestParts.push(`${name}:${snapshot.integrityDigest}`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// ── Integrity Digest (tools + prompts) ───────────────
|
|
90
|
+
const digestInput = promptDigestParts.length > 0
|
|
91
|
+
? `${serverDigest.digest}\n---prompts---\n${promptDigestParts.join('\n')}`
|
|
92
|
+
: serverDigest.digest;
|
|
93
|
+
const integrityDigest = promptDigestParts.length > 0
|
|
94
|
+
? sha256(digestInput)
|
|
95
|
+
: serverDigest.digest;
|
|
96
|
+
const capabilities = prompts
|
|
97
|
+
? { tools, prompts }
|
|
98
|
+
: { tools };
|
|
99
|
+
return {
|
|
100
|
+
lockfileVersion: LOCKFILE_VERSION,
|
|
101
|
+
serverName,
|
|
102
|
+
fusionVersion,
|
|
103
|
+
generatedAt: new Date().toISOString(),
|
|
104
|
+
integrityDigest: `sha256:${integrityDigest}`,
|
|
105
|
+
capabilities,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Serialize a lockfile to a deterministic JSON string.
|
|
110
|
+
*
|
|
111
|
+
* Uses sorted keys and 2-space indentation for git-friendly diffs.
|
|
112
|
+
* The output is canonical — identical lockfiles produce identical strings.
|
|
113
|
+
*
|
|
114
|
+
* @param lockfile - The lockfile to serialize
|
|
115
|
+
* @returns Deterministic JSON string with trailing newline
|
|
116
|
+
*/
|
|
117
|
+
export function serializeLockfile(lockfile) {
|
|
118
|
+
return JSON.stringify(lockfile, (_key, value) => {
|
|
119
|
+
if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
|
|
120
|
+
return Object.keys(value)
|
|
121
|
+
.sort()
|
|
122
|
+
.reduce((sorted, k) => {
|
|
123
|
+
sorted[k] = value[k];
|
|
124
|
+
return sorted;
|
|
125
|
+
}, {});
|
|
126
|
+
}
|
|
127
|
+
return value;
|
|
128
|
+
}, 2) + '\n';
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Verify that a lockfile matches the current server contracts and prompts.
|
|
132
|
+
*
|
|
133
|
+
* This is the **CI gate**: `fusion lock --check` calls this function
|
|
134
|
+
* and exits non-zero if the lockfile is stale.
|
|
135
|
+
*
|
|
136
|
+
* @param lockfile - Previously generated lockfile (from disk)
|
|
137
|
+
* @param contracts - Current compiled tool contracts (from code)
|
|
138
|
+
* @param options - Optional: prompt builders for prompt verification
|
|
139
|
+
* @returns Check result with per-tool and per-prompt diff details
|
|
140
|
+
*/
|
|
141
|
+
export function checkLockfile(lockfile, contracts, options) {
|
|
142
|
+
// Regenerate a fresh lockfile to compare digests
|
|
143
|
+
const fresh = generateLockfile(lockfile.serverName, contracts, lockfile.fusionVersion, options);
|
|
144
|
+
// Fast path: integrity digest matches → everything is identical
|
|
145
|
+
if (lockfile.integrityDigest === fresh.integrityDigest) {
|
|
146
|
+
return {
|
|
147
|
+
ok: true,
|
|
148
|
+
message: 'Lockfile is up to date.',
|
|
149
|
+
added: [],
|
|
150
|
+
removed: [],
|
|
151
|
+
changed: [],
|
|
152
|
+
unchanged: Object.keys(contracts).sort(),
|
|
153
|
+
addedPrompts: [],
|
|
154
|
+
removedPrompts: [],
|
|
155
|
+
changedPrompts: [],
|
|
156
|
+
unchangedPrompts: Object.keys(fresh.capabilities.prompts ?? {}).sort(),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
// Slow path: per-tool comparison
|
|
160
|
+
const lockedToolNames = new Set(Object.keys(lockfile.capabilities.tools));
|
|
161
|
+
const currentToolNames = new Set(Object.keys(contracts));
|
|
162
|
+
const added = [];
|
|
163
|
+
const removed = [];
|
|
164
|
+
const changed = [];
|
|
165
|
+
const unchanged = [];
|
|
166
|
+
for (const name of currentToolNames) {
|
|
167
|
+
if (!lockedToolNames.has(name)) {
|
|
168
|
+
added.push(name);
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
const lockedDigest = lockfile.capabilities.tools[name].integrityDigest;
|
|
172
|
+
const freshDigest = fresh.capabilities.tools[name].integrityDigest;
|
|
173
|
+
if (lockedDigest === freshDigest) {
|
|
174
|
+
unchanged.push(name);
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
changed.push(name);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
for (const name of lockedToolNames) {
|
|
182
|
+
if (!currentToolNames.has(name)) {
|
|
183
|
+
removed.push(name);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
// ── Per-prompt comparison ────────────────────────────
|
|
187
|
+
const lockedPrompts = lockfile.capabilities.prompts ?? {};
|
|
188
|
+
const freshPrompts = fresh.capabilities.prompts ?? {};
|
|
189
|
+
const lockedPromptNames = new Set(Object.keys(lockedPrompts));
|
|
190
|
+
const currentPromptNames = new Set(Object.keys(freshPrompts));
|
|
191
|
+
const addedPrompts = [];
|
|
192
|
+
const removedPrompts = [];
|
|
193
|
+
const changedPrompts = [];
|
|
194
|
+
const unchangedPrompts = [];
|
|
195
|
+
for (const name of currentPromptNames) {
|
|
196
|
+
if (!lockedPromptNames.has(name)) {
|
|
197
|
+
addedPrompts.push(name);
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
const lockedDigest = lockedPrompts[name].integrityDigest;
|
|
201
|
+
const freshDigest = freshPrompts[name].integrityDigest;
|
|
202
|
+
if (lockedDigest === freshDigest) {
|
|
203
|
+
unchangedPrompts.push(name);
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
changedPrompts.push(name);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
for (const name of lockedPromptNames) {
|
|
211
|
+
if (!currentPromptNames.has(name)) {
|
|
212
|
+
removedPrompts.push(name);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
// ── Build message ────────────────────────────────────
|
|
216
|
+
const driftParts = [];
|
|
217
|
+
if (added.length > 0)
|
|
218
|
+
driftParts.push(`tools added: [${added.join(', ')}]`);
|
|
219
|
+
if (removed.length > 0)
|
|
220
|
+
driftParts.push(`tools removed: [${removed.join(', ')}]`);
|
|
221
|
+
if (changed.length > 0)
|
|
222
|
+
driftParts.push(`tools changed: [${changed.join(', ')}]`);
|
|
223
|
+
if (addedPrompts.length > 0)
|
|
224
|
+
driftParts.push(`prompts added: [${addedPrompts.join(', ')}]`);
|
|
225
|
+
if (removedPrompts.length > 0)
|
|
226
|
+
driftParts.push(`prompts removed: [${removedPrompts.join(', ')}]`);
|
|
227
|
+
if (changedPrompts.length > 0)
|
|
228
|
+
driftParts.push(`prompts changed: [${changedPrompts.join(', ')}]`);
|
|
229
|
+
return {
|
|
230
|
+
ok: false,
|
|
231
|
+
message: `Lockfile is stale. ${driftParts.join('; ')}. Run \`fusion lock\` to update.`,
|
|
232
|
+
added,
|
|
233
|
+
removed,
|
|
234
|
+
changed,
|
|
235
|
+
unchanged,
|
|
236
|
+
addedPrompts,
|
|
237
|
+
removedPrompts,
|
|
238
|
+
changedPrompts,
|
|
239
|
+
unchangedPrompts,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Parse and validate a lockfile JSON string.
|
|
244
|
+
*
|
|
245
|
+
* @param content - Raw JSON string from `mcp-fusion.lock`
|
|
246
|
+
* @returns Parsed lockfile, or null if invalid
|
|
247
|
+
*/
|
|
248
|
+
export function parseLockfile(content) {
|
|
249
|
+
try {
|
|
250
|
+
const parsed = JSON.parse(content);
|
|
251
|
+
if (parsed['lockfileVersion'] !== LOCKFILE_VERSION)
|
|
252
|
+
return null;
|
|
253
|
+
if (typeof parsed['serverName'] !== 'string')
|
|
254
|
+
return null;
|
|
255
|
+
if (typeof parsed['integrityDigest'] !== 'string')
|
|
256
|
+
return null;
|
|
257
|
+
if (typeof parsed['generatedAt'] !== 'string')
|
|
258
|
+
return null;
|
|
259
|
+
if (typeof parsed['fusionVersion'] !== 'string')
|
|
260
|
+
return null;
|
|
261
|
+
if (!parsed['capabilities'] || typeof parsed['capabilities'] !== 'object')
|
|
262
|
+
return null;
|
|
263
|
+
const caps = parsed['capabilities'];
|
|
264
|
+
if (!caps['tools'] || typeof caps['tools'] !== 'object')
|
|
265
|
+
return null;
|
|
266
|
+
return parsed;
|
|
267
|
+
}
|
|
268
|
+
catch {
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
// ============================================================================
|
|
273
|
+
// Persistence (Side-effectful — clearly separated)
|
|
274
|
+
// ============================================================================
|
|
275
|
+
/**
|
|
276
|
+
* Write a lockfile to disk.
|
|
277
|
+
*
|
|
278
|
+
* @param lockfile - The lockfile to persist
|
|
279
|
+
* @param projectRoot - Project root directory
|
|
280
|
+
*/
|
|
281
|
+
export async function writeLockfile(lockfile, projectRoot) {
|
|
282
|
+
const filePath = resolve(projectRoot, LOCKFILE_NAME);
|
|
283
|
+
await writeFile(filePath, serializeLockfile(lockfile), 'utf-8');
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Read a lockfile from disk.
|
|
287
|
+
*
|
|
288
|
+
* @param projectRoot - Project root directory
|
|
289
|
+
* @returns Parsed lockfile, or null if not found / invalid
|
|
290
|
+
*/
|
|
291
|
+
export async function readLockfile(projectRoot) {
|
|
292
|
+
const filePath = resolve(projectRoot, LOCKFILE_NAME);
|
|
293
|
+
try {
|
|
294
|
+
const content = await readFile(filePath, 'utf-8');
|
|
295
|
+
return parseLockfile(content);
|
|
296
|
+
}
|
|
297
|
+
catch {
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
// ============================================================================
|
|
302
|
+
// Internals
|
|
303
|
+
// ============================================================================
|
|
304
|
+
/**
|
|
305
|
+
* Snapshot a single tool's contract into lockfile format.
|
|
306
|
+
* @internal
|
|
307
|
+
*/
|
|
308
|
+
function snapshotTool(contract, digest) {
|
|
309
|
+
const actionKeys = Object.keys(contract.surface.actions).sort();
|
|
310
|
+
const destructiveActions = actionKeys.filter(key => contract.surface.actions[key].destructive);
|
|
311
|
+
const readOnlyActions = actionKeys.filter(key => contract.surface.actions[key].readOnly);
|
|
312
|
+
return {
|
|
313
|
+
integrityDigest: `sha256:${digest.digest}`,
|
|
314
|
+
surface: {
|
|
315
|
+
description: contract.surface.description ?? null,
|
|
316
|
+
actions: actionKeys,
|
|
317
|
+
inputSchemaDigest: `sha256:${contract.surface.inputSchemaDigest}`,
|
|
318
|
+
tags: [...contract.surface.tags].sort(),
|
|
319
|
+
},
|
|
320
|
+
behavior: {
|
|
321
|
+
egressSchemaDigest: contract.behavior.egressSchemaDigest
|
|
322
|
+
? `sha256:${contract.behavior.egressSchemaDigest}`
|
|
323
|
+
: null,
|
|
324
|
+
systemRulesFingerprint: contract.behavior.systemRulesFingerprint,
|
|
325
|
+
destructiveActions,
|
|
326
|
+
readOnlyActions,
|
|
327
|
+
middlewareChain: [...contract.behavior.middlewareChain],
|
|
328
|
+
affordanceTopology: [...contract.behavior.affordanceTopology],
|
|
329
|
+
cognitiveGuardrails: {
|
|
330
|
+
agentLimitMax: contract.behavior.cognitiveGuardrails.agentLimitMax,
|
|
331
|
+
egressMaxBytes: contract.behavior.cognitiveGuardrails.egressMaxBytes,
|
|
332
|
+
},
|
|
333
|
+
},
|
|
334
|
+
tokenEconomics: {
|
|
335
|
+
inflationRisk: contract.tokenEconomics.inflationRisk,
|
|
336
|
+
schemaFieldCount: contract.tokenEconomics.schemaFieldCount,
|
|
337
|
+
unboundedCollection: contract.tokenEconomics.unboundedCollection,
|
|
338
|
+
},
|
|
339
|
+
entitlements: {
|
|
340
|
+
filesystem: contract.entitlements.filesystem,
|
|
341
|
+
network: contract.entitlements.network,
|
|
342
|
+
subprocess: contract.entitlements.subprocess,
|
|
343
|
+
crypto: contract.entitlements.crypto,
|
|
344
|
+
},
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Snapshot a single prompt builder into lockfile format.
|
|
349
|
+
*
|
|
350
|
+
* Extracts all declarative metadata and computes a SHA-256 digest
|
|
351
|
+
* over the canonical representation.
|
|
352
|
+
*
|
|
353
|
+
* @internal
|
|
354
|
+
*/
|
|
355
|
+
function snapshotPrompt(builder) {
|
|
356
|
+
const def = builder.buildPromptDefinition();
|
|
357
|
+
const tags = [...builder.getTags()].sort();
|
|
358
|
+
const hasMiddleware = builder.hasMiddleware();
|
|
359
|
+
const hydrationTimeout = builder.getHydrationTimeout() ?? null;
|
|
360
|
+
// Normalize arguments for deterministic serialization
|
|
361
|
+
const args = (def.arguments ?? [])
|
|
362
|
+
.map(a => ({
|
|
363
|
+
name: a.name,
|
|
364
|
+
description: a.description ?? null,
|
|
365
|
+
required: a.required ?? false,
|
|
366
|
+
}))
|
|
367
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
368
|
+
const argumentsDigest = `sha256:${sha256(canonicalize(args))}`;
|
|
369
|
+
// Compute integrity digest over all declarative fields
|
|
370
|
+
const surface = {
|
|
371
|
+
name: def.name,
|
|
372
|
+
description: def.description ?? null,
|
|
373
|
+
title: def.title ?? null,
|
|
374
|
+
tags,
|
|
375
|
+
arguments: args,
|
|
376
|
+
hasMiddleware,
|
|
377
|
+
hydrationTimeout,
|
|
378
|
+
};
|
|
379
|
+
const integrityDigest = `sha256:${sha256(canonicalize(surface))}`;
|
|
380
|
+
return {
|
|
381
|
+
integrityDigest,
|
|
382
|
+
description: def.description ?? null,
|
|
383
|
+
title: def.title ?? null,
|
|
384
|
+
tags,
|
|
385
|
+
arguments: args,
|
|
386
|
+
argumentsDigest,
|
|
387
|
+
hasMiddleware,
|
|
388
|
+
hydrationTimeout,
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
//# sourceMappingURL=CapabilityLockfile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CapabilityLockfile.js","sourceRoot":"","sources":["../../src/introspection/CapabilityLockfile.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ContractAwareSelfHealing — Runtime Contract Delta Injection
|
|
3
|
+
*
|
|
4
|
+
* **Evolution 4: Self-Healing Context**
|
|
5
|
+
*
|
|
6
|
+
* When a Zod validation error occurs (the LLM sent malformed
|
|
7
|
+
* arguments), this module enriches the error response with
|
|
8
|
+
* contract change context. If the tool's behavioral contract
|
|
9
|
+
* has changed since the LLM was last calibrated, the error
|
|
10
|
+
* message includes:
|
|
11
|
+
*
|
|
12
|
+
* 1. Which contract fields changed (from ContractDiff)
|
|
13
|
+
* 2. What the previous contract looked like
|
|
14
|
+
* 3. What the current contract requires
|
|
15
|
+
*
|
|
16
|
+
* This gives the LLM enough context to self-correct on the
|
|
17
|
+
* next invocation instead of repeating the same mistake.
|
|
18
|
+
*
|
|
19
|
+
* **Integration**: Plugs into the existing `formatValidationError()`
|
|
20
|
+
* pipeline via a wrapping function that checks for relevant
|
|
21
|
+
* contract deltas and injects them into the XML error response.
|
|
22
|
+
*
|
|
23
|
+
* **Zero-overhead**: When no contract changes exist, the function
|
|
24
|
+
* passes through to the original formatter with zero additional cost.
|
|
25
|
+
*
|
|
26
|
+
* @module
|
|
27
|
+
*/
|
|
28
|
+
import type { ContractDiffResult } from './ContractDiff.js';
|
|
29
|
+
/**
|
|
30
|
+
* Configuration for contract-aware self-healing.
|
|
31
|
+
*/
|
|
32
|
+
export interface SelfHealingConfig {
|
|
33
|
+
/**
|
|
34
|
+
* Active contract diff results, keyed by tool name.
|
|
35
|
+
* Populated at server startup by diffing current contracts
|
|
36
|
+
* against the last known-good lockfile.
|
|
37
|
+
*/
|
|
38
|
+
readonly activeDeltas: ReadonlyMap<string, ContractDiffResult>;
|
|
39
|
+
/**
|
|
40
|
+
* Whether to inject deltas for all severity levels.
|
|
41
|
+
* Default: only BREAKING and RISKY.
|
|
42
|
+
*/
|
|
43
|
+
readonly includeAllSeverities?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Maximum number of deltas to inject per error.
|
|
46
|
+
* Prevents context flooding from large diffs.
|
|
47
|
+
* Default: 5.
|
|
48
|
+
*/
|
|
49
|
+
readonly maxDeltasPerError?: number;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Result of self-healing injection.
|
|
53
|
+
*/
|
|
54
|
+
export interface SelfHealingResult {
|
|
55
|
+
/** The original error XML */
|
|
56
|
+
readonly originalError: string;
|
|
57
|
+
/** The enriched error XML with contract context */
|
|
58
|
+
readonly enrichedError: string;
|
|
59
|
+
/** Whether any contract context was injected */
|
|
60
|
+
readonly injected: boolean;
|
|
61
|
+
/** Number of deltas injected */
|
|
62
|
+
readonly deltaCount: number;
|
|
63
|
+
/** Tool name */
|
|
64
|
+
readonly toolName: string;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Enrich a validation error with contract change context.
|
|
68
|
+
*
|
|
69
|
+
* If the tool has relevant contract changes (from `SelfHealingConfig.activeDeltas`),
|
|
70
|
+
* this function injects them into the error XML so the LLM can self-correct.
|
|
71
|
+
*
|
|
72
|
+
* @param originalError - The original XML error from `formatValidationError()`
|
|
73
|
+
* @param toolName - The tool that failed validation
|
|
74
|
+
* @param actionKey - The action that failed
|
|
75
|
+
* @param config - Self-healing configuration with active deltas
|
|
76
|
+
* @returns Enriched error string with contract context
|
|
77
|
+
*/
|
|
78
|
+
export declare function enrichValidationError(originalError: string, toolName: string, actionKey: string, config: SelfHealingConfig): SelfHealingResult;
|
|
79
|
+
/**
|
|
80
|
+
* Create a tool-scoped self-healing enhancer.
|
|
81
|
+
*
|
|
82
|
+
* This is the primary integration point: wraps a per-tool
|
|
83
|
+
* error formatter with contract delta context.
|
|
84
|
+
*
|
|
85
|
+
* @param toolName - The tool name for delta lookup
|
|
86
|
+
* @param config - Self-healing configuration
|
|
87
|
+
* @returns A function that enriches error strings
|
|
88
|
+
*/
|
|
89
|
+
export declare function createToolEnhancer(toolName: string, config: SelfHealingConfig): (errorXml: string, actionKey: string) => string;
|
|
90
|
+
//# sourceMappingURL=ContractAwareSelfHealing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ContractAwareSelfHealing.d.ts","sourceRoot":"","sources":["../../src/introspection/ContractAwareSelfHealing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,KAAK,EAAiB,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAO3E;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,YAAY,EAAE,WAAW,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAE/D;;;OAGG;IACH,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAExC;;;;OAIG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CACvC;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAC9B,6BAA6B;IAC7B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,mDAAmD;IACnD,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,gDAAgD;IAChD,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,gCAAgC;IAChC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,gBAAgB;IAChB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC7B;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CACjC,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,iBAAiB,GAC1B,iBAAiB,CA4CnB;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAC9B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,iBAAiB,GAC1B,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,MAAM,CAajD"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { formatDeltasAsXml } from './ContractDiff.js';
|
|
2
|
+
// ============================================================================
|
|
3
|
+
// Core Logic
|
|
4
|
+
// ============================================================================
|
|
5
|
+
/**
|
|
6
|
+
* Enrich a validation error with contract change context.
|
|
7
|
+
*
|
|
8
|
+
* If the tool has relevant contract changes (from `SelfHealingConfig.activeDeltas`),
|
|
9
|
+
* this function injects them into the error XML so the LLM can self-correct.
|
|
10
|
+
*
|
|
11
|
+
* @param originalError - The original XML error from `formatValidationError()`
|
|
12
|
+
* @param toolName - The tool that failed validation
|
|
13
|
+
* @param actionKey - The action that failed
|
|
14
|
+
* @param config - Self-healing configuration with active deltas
|
|
15
|
+
* @returns Enriched error string with contract context
|
|
16
|
+
*/
|
|
17
|
+
export function enrichValidationError(originalError, toolName, actionKey, config) {
|
|
18
|
+
const diffResult = config.activeDeltas.get(toolName);
|
|
19
|
+
// No deltas for this tool → pass through
|
|
20
|
+
if (!diffResult || diffResult.deltas.length === 0) {
|
|
21
|
+
return {
|
|
22
|
+
originalError,
|
|
23
|
+
enrichedError: originalError,
|
|
24
|
+
injected: false,
|
|
25
|
+
deltaCount: 0,
|
|
26
|
+
toolName,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
// Filter deltas by relevance
|
|
30
|
+
const relevantDeltas = filterRelevantDeltas(diffResult.deltas, actionKey, config);
|
|
31
|
+
if (relevantDeltas.length === 0) {
|
|
32
|
+
return {
|
|
33
|
+
originalError,
|
|
34
|
+
enrichedError: originalError,
|
|
35
|
+
injected: false,
|
|
36
|
+
deltaCount: 0,
|
|
37
|
+
toolName,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
// Build the contract context injection
|
|
41
|
+
const contractXml = buildContractContext(toolName, actionKey, relevantDeltas);
|
|
42
|
+
// Inject before the closing </validation_error> tag
|
|
43
|
+
const enrichedError = injectIntoXml(originalError, contractXml);
|
|
44
|
+
return {
|
|
45
|
+
originalError,
|
|
46
|
+
enrichedError,
|
|
47
|
+
injected: true,
|
|
48
|
+
deltaCount: relevantDeltas.length,
|
|
49
|
+
toolName,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Create a tool-scoped self-healing enhancer.
|
|
54
|
+
*
|
|
55
|
+
* This is the primary integration point: wraps a per-tool
|
|
56
|
+
* error formatter with contract delta context.
|
|
57
|
+
*
|
|
58
|
+
* @param toolName - The tool name for delta lookup
|
|
59
|
+
* @param config - Self-healing configuration
|
|
60
|
+
* @returns A function that enriches error strings
|
|
61
|
+
*/
|
|
62
|
+
export function createToolEnhancer(toolName, config) {
|
|
63
|
+
const diffResult = config.activeDeltas.get(toolName);
|
|
64
|
+
// No deltas → return identity function (zero overhead)
|
|
65
|
+
if (!diffResult || diffResult.deltas.length === 0) {
|
|
66
|
+
return (errorXml) => errorXml;
|
|
67
|
+
}
|
|
68
|
+
// Pre-compute relevant deltas (avoids per-call filtering)
|
|
69
|
+
return (errorXml, actionKey) => {
|
|
70
|
+
const result = enrichValidationError(errorXml, toolName, actionKey, config);
|
|
71
|
+
return result.enrichedError;
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
// ============================================================================
|
|
75
|
+
// Internals
|
|
76
|
+
// ============================================================================
|
|
77
|
+
/** Severity levels considered actionable by default */
|
|
78
|
+
const ACTIONABLE_SEVERITIES = new Set(['BREAKING', 'RISKY']);
|
|
79
|
+
/**
|
|
80
|
+
* Filter deltas relevant to the failing action.
|
|
81
|
+
* @internal
|
|
82
|
+
*/
|
|
83
|
+
function filterRelevantDeltas(deltas, actionKey, config) {
|
|
84
|
+
const maxDeltas = config.maxDeltasPerError ?? 5;
|
|
85
|
+
const includeAll = config.includeAllSeverities ?? false;
|
|
86
|
+
const actionPrefix = `actions.${actionKey}`;
|
|
87
|
+
const isRelevant = (delta) => {
|
|
88
|
+
const severityOk = includeAll || ACTIONABLE_SEVERITIES.has(delta.severity);
|
|
89
|
+
const isGlobal = !delta.field.includes('actions.');
|
|
90
|
+
const isForAction = delta.field.includes(actionPrefix);
|
|
91
|
+
return severityOk && (isGlobal || isForAction);
|
|
92
|
+
};
|
|
93
|
+
return deltas.filter(isRelevant).slice(0, maxDeltas);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Build the contract context XML block.
|
|
97
|
+
* @internal
|
|
98
|
+
*/
|
|
99
|
+
function buildContractContext(toolName, actionKey, deltas) {
|
|
100
|
+
const lines = [
|
|
101
|
+
'',
|
|
102
|
+
'<contract_awareness>',
|
|
103
|
+
` <system_note>IMPORTANT: The behavioral contract for tool "${toolName}" has changed since your last calibration.</system_note>`,
|
|
104
|
+
` <action>${actionKey}</action>`,
|
|
105
|
+
` <change_count>${deltas.length}</change_count>`,
|
|
106
|
+
` <max_severity>${deltas[0]?.severity ?? 'UNKNOWN'}</max_severity>`,
|
|
107
|
+
'',
|
|
108
|
+
' <instructions>',
|
|
109
|
+
' Review the contract changes below and adjust your next invocation accordingly.',
|
|
110
|
+
' These changes may explain why your previous arguments were rejected.',
|
|
111
|
+
' </instructions>',
|
|
112
|
+
'',
|
|
113
|
+
` ${formatDeltasAsXml(deltas).split('\n').join('\n ')}`,
|
|
114
|
+
'</contract_awareness>',
|
|
115
|
+
];
|
|
116
|
+
return lines.join('\n');
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Inject contract context into the validation error XML.
|
|
120
|
+
*
|
|
121
|
+
* Inserts before `</validation_error>` if present,
|
|
122
|
+
* otherwise appends at the end.
|
|
123
|
+
* @internal
|
|
124
|
+
*/
|
|
125
|
+
function injectIntoXml(originalXml, contractXml) {
|
|
126
|
+
const closingTag = '</validation_error>';
|
|
127
|
+
const insertionPoint = originalXml.lastIndexOf(closingTag);
|
|
128
|
+
return insertionPoint === -1
|
|
129
|
+
? `${originalXml}\n${contractXml}`
|
|
130
|
+
: `${originalXml.slice(0, insertionPoint)}\n${contractXml}\n${originalXml.slice(insertionPoint)}`;
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=ContractAwareSelfHealing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ContractAwareSelfHealing.js","sourceRoot":"","sources":["../../src/introspection/ContractAwareSelfHealing.ts"],"names":[],"mappings":"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"}
|