@nestpilot/mcp-app 1.0.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/README.md +350 -0
- package/dist/cli/doctor.d.ts +1 -0
- package/dist/cli/doctor.js +214 -0
- package/dist/cli/export-import.d.ts +6 -0
- package/dist/cli/export-import.js +132 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +168 -0
- package/dist/cli/init.d.ts +1 -0
- package/dist/cli/init.js +171 -0
- package/dist/host-configs/cowork.json +11 -0
- package/dist/host-configs/goose.yaml +22 -0
- package/dist/host-configs/openclaw-manifest.json +16 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +128 -0
- package/dist/mcp-app.html +155 -0
- package/dist/nestpilot-client.d.ts +44 -0
- package/dist/nestpilot-client.js +160 -0
- package/dist/planner.html +222 -0
- package/dist/server.d.ts +19 -0
- package/dist/server.js +245 -0
- package/dist/skills/SKILL.md +162 -0
- package/dist/skills/manifest.json +51 -0
- package/dist/skills/tools/activate_plan.md +36 -0
- package/dist/skills/tools/coach.md +59 -0
- package/dist/skills/tools/comprehensive_plan.md +65 -0
- package/dist/skills/tools/create_plan.md +59 -0
- package/dist/skills/tools/create_saved_plan.md +49 -0
- package/dist/skills/tools/delete_plan.md +42 -0
- package/dist/skills/tools/delete_scenario.md +38 -0
- package/dist/skills/tools/generate_proposal.md +63 -0
- package/dist/skills/tools/generate_retirement_report.md +50 -0
- package/dist/skills/tools/get_active_plan.md +44 -0
- package/dist/skills/tools/get_baseline_forecast.md +47 -0
- package/dist/skills/tools/get_plan.md +44 -0
- package/dist/skills/tools/get_plan_components.md +50 -0
- package/dist/skills/tools/get_scenario.md +46 -0
- package/dist/skills/tools/list_plans.md +44 -0
- package/dist/skills/tools/list_scenarios.md +42 -0
- package/dist/skills/tools/medicare-guardian.md +59 -0
- package/dist/skills/tools/nestpilot_run_plan.md +61 -0
- package/dist/skills/tools/optimize_roth_conversion.md +107 -0
- package/dist/skills/tools/optimize_ss_claiming.md +30 -0
- package/dist/skills/tools/rename_plan.md +34 -0
- package/dist/skills/tools/retirement-planner.md +55 -0
- package/dist/skills/tools/run_forecast.md +65 -0
- package/dist/skills/tools/run_saved_forecast.md +52 -0
- package/dist/skills/tools/run_scenario.md +66 -0
- package/dist/skills/tools/save_plan.md +48 -0
- package/dist/skills/tools/save_scenario.md +50 -0
- package/dist/skills/tools/verify_forecast.md +43 -0
- package/dist/src/config.d.ts +20 -0
- package/dist/src/config.js +44 -0
- package/dist/src/contracts/provenance.d.ts +37 -0
- package/dist/src/contracts/provenance.js +71 -0
- package/dist/src/contracts/tool-contract-registry.d.ts +43 -0
- package/dist/src/contracts/tool-contract-registry.js +282 -0
- package/dist/src/local/cloud-compute-client.d.ts +55 -0
- package/dist/src/local/cloud-compute-client.js +135 -0
- package/dist/src/local/encryption.d.ts +24 -0
- package/dist/src/local/encryption.js +105 -0
- package/dist/src/local/keychain.d.ts +41 -0
- package/dist/src/local/keychain.js +236 -0
- package/dist/src/local/local-config.d.ts +34 -0
- package/dist/src/local/local-config.js +61 -0
- package/dist/src/local/local-data-layer.d.ts +20 -0
- package/dist/src/local/local-data-layer.js +15 -0
- package/dist/src/local/local-plan-store.d.ts +66 -0
- package/dist/src/local/local-plan-store.js +195 -0
- package/dist/src/local/pii-scrubber.d.ts +26 -0
- package/dist/src/local/pii-scrubber.js +219 -0
- package/dist/src/policy/policy-engine.d.ts +44 -0
- package/dist/src/policy/policy-engine.js +119 -0
- package/dist/src/rate-limit.d.ts +17 -0
- package/dist/src/rate-limit.js +41 -0
- package/dist/src/security.d.ts +19 -0
- package/dist/src/security.js +118 -0
- package/dist/src/skills/index.d.ts +12 -0
- package/dist/src/skills/index.js +16 -0
- package/dist/src/skills/retirement-pack-v1.d.ts +28 -0
- package/dist/src/skills/retirement-pack-v1.js +295 -0
- package/dist/src/skills/skill-executor.d.ts +65 -0
- package/dist/src/skills/skill-executor.js +174 -0
- package/dist/src/skills/skill-manifest-schema.d.ts +337 -0
- package/dist/src/skills/skill-manifest-schema.js +94 -0
- package/dist/src/skills/skill-registry.d.ts +71 -0
- package/dist/src/skills/skill-registry.js +116 -0
- package/dist/src/telemetry.d.ts +12 -0
- package/dist/src/telemetry.js +59 -0
- package/dist/src/types.d.ts +46 -0
- package/dist/src/types.js +4 -0
- package/dist/tools/agent-tools.d.ts +12 -0
- package/dist/tools/agent-tools.js +141 -0
- package/dist/tools/forecast-management-tools.d.ts +9 -0
- package/dist/tools/forecast-management-tools.js +133 -0
- package/dist/tools/local-plan-tools.d.ts +8 -0
- package/dist/tools/local-plan-tools.js +357 -0
- package/dist/tools/mcp-helpers.d.ts +52 -0
- package/dist/tools/mcp-helpers.js +177 -0
- package/dist/tools/medicare-tools.d.ts +3 -0
- package/dist/tools/medicare-tools.js +162 -0
- package/dist/tools/optimize-roth-tools-test.d.ts +2 -0
- package/dist/tools/optimize-roth-tools-test.js +36 -0
- package/dist/tools/optimize-roth-tools.d.ts +3 -0
- package/dist/tools/optimize-roth-tools.js +818 -0
- package/dist/tools/plan-management-tools.d.ts +3 -0
- package/dist/tools/plan-management-tools.js +196 -0
- package/dist/tools/planning-tools.d.ts +3 -0
- package/dist/tools/planning-tools.js +290 -0
- package/dist/tools/proposal-tools.d.ts +3 -0
- package/dist/tools/proposal-tools.js +428 -0
- package/dist/tools/report-tools.d.ts +3 -0
- package/dist/tools/report-tools.js +245 -0
- package/dist/tools/scenario-management-tools.d.ts +3 -0
- package/dist/tools/scenario-management-tools.js +136 -0
- package/dist/views/verification-packet.html +211 -0
- package/host-configs/cowork.json +11 -0
- package/host-configs/goose.yaml +22 -0
- package/host-configs/openclaw-manifest.json +16 -0
- package/package.json +66 -0
- package/skills/SKILL.md +162 -0
- package/skills/manifest.json +51 -0
- package/skills/tools/activate_plan.md +36 -0
- package/skills/tools/coach.md +59 -0
- package/skills/tools/comprehensive_plan.md +65 -0
- package/skills/tools/create_plan.md +59 -0
- package/skills/tools/create_saved_plan.md +49 -0
- package/skills/tools/delete_plan.md +42 -0
- package/skills/tools/delete_scenario.md +38 -0
- package/skills/tools/generate_proposal.md +63 -0
- package/skills/tools/generate_retirement_report.md +50 -0
- package/skills/tools/get_active_plan.md +44 -0
- package/skills/tools/get_baseline_forecast.md +47 -0
- package/skills/tools/get_plan.md +44 -0
- package/skills/tools/get_plan_components.md +50 -0
- package/skills/tools/get_scenario.md +46 -0
- package/skills/tools/list_plans.md +44 -0
- package/skills/tools/list_scenarios.md +42 -0
- package/skills/tools/medicare-guardian.md +59 -0
- package/skills/tools/nestpilot_run_plan.md +61 -0
- package/skills/tools/optimize_roth_conversion.md +107 -0
- package/skills/tools/optimize_ss_claiming.md +30 -0
- package/skills/tools/rename_plan.md +34 -0
- package/skills/tools/retirement-planner.md +55 -0
- package/skills/tools/run_forecast.md +65 -0
- package/skills/tools/run_saved_forecast.md +52 -0
- package/skills/tools/run_scenario.md +66 -0
- package/skills/tools/save_plan.md +48 -0
- package/skills/tools/save_scenario.md +50 -0
- package/skills/tools/verify_forecast.md +43 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { checkCompatibility, } from "./skill-registry.js";
|
|
2
|
+
import { evaluatePolicy, } from "../policy/policy-engine.js";
|
|
3
|
+
/**
|
|
4
|
+
* Validates a payload against a skill I/O schema definition.
|
|
5
|
+
* Checks that all required fields are present and have the correct type.
|
|
6
|
+
*/
|
|
7
|
+
export function validateIO(payload, schema, direction) {
|
|
8
|
+
const errors = [];
|
|
9
|
+
for (const field of schema.fields) {
|
|
10
|
+
const value = payload[field.name];
|
|
11
|
+
if (field.required && (value === undefined || value === null)) {
|
|
12
|
+
errors.push(`${direction}.${field.name}: required field is missing`);
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
if (value !== undefined && value !== null) {
|
|
16
|
+
const actualType = Array.isArray(value) ? "array" : typeof value;
|
|
17
|
+
if (actualType !== field.type) {
|
|
18
|
+
errors.push(`${direction}.${field.name}: expected type '${field.type}', got '${actualType}'`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
if (errors.length > 0) {
|
|
23
|
+
return { valid: false, errors };
|
|
24
|
+
}
|
|
25
|
+
return { valid: true };
|
|
26
|
+
}
|
|
27
|
+
// ── Run ID generation ───────────────────────────────────────────────────
|
|
28
|
+
let runCounter = 0;
|
|
29
|
+
function generateRunId() {
|
|
30
|
+
runCounter += 1;
|
|
31
|
+
return `run-${Date.now()}-${runCounter}`;
|
|
32
|
+
}
|
|
33
|
+
// ── Executor ────────────────────────────────────────────────────────────
|
|
34
|
+
/**
|
|
35
|
+
* Executes a skill by:
|
|
36
|
+
* 1. Running compatibility checks against tool contracts.
|
|
37
|
+
* 2. Validating input against the skill's input schema.
|
|
38
|
+
* 3. Evaluating policy for each required tool.
|
|
39
|
+
* 4. Calling each required tool via the injected dispatcher.
|
|
40
|
+
* 5. Validating output against the skill's output schema.
|
|
41
|
+
* 6. Returning an execution record with full trace.
|
|
42
|
+
*/
|
|
43
|
+
export async function executeSkill(manifest, ctx) {
|
|
44
|
+
const runId = generateRunId();
|
|
45
|
+
const startedAt = new Date().toISOString();
|
|
46
|
+
const stepTrace = [];
|
|
47
|
+
const policyDecisions = [];
|
|
48
|
+
// ── 1. Compatibility check ────────────────────────────────────────────
|
|
49
|
+
const compat = checkCompatibility(manifest);
|
|
50
|
+
if (!compat.compatible) {
|
|
51
|
+
return {
|
|
52
|
+
runId,
|
|
53
|
+
skillId: manifest.skillId,
|
|
54
|
+
version: manifest.version,
|
|
55
|
+
status: "blocked",
|
|
56
|
+
stepTrace,
|
|
57
|
+
policyDecisions,
|
|
58
|
+
startedAt,
|
|
59
|
+
completedAt: new Date().toISOString(),
|
|
60
|
+
error: `Compatibility check failed: ${compat.failures.map((f) => f.reason).join("; ")}`,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
// ── 2. Validate input ─────────────────────────────────────────────────
|
|
64
|
+
const inputValidation = validateIO(ctx.input, manifest.inputSchema, "input");
|
|
65
|
+
if (!inputValidation.valid) {
|
|
66
|
+
return {
|
|
67
|
+
runId,
|
|
68
|
+
skillId: manifest.skillId,
|
|
69
|
+
version: manifest.version,
|
|
70
|
+
status: "error",
|
|
71
|
+
stepTrace,
|
|
72
|
+
policyDecisions,
|
|
73
|
+
startedAt,
|
|
74
|
+
completedAt: new Date().toISOString(),
|
|
75
|
+
error: `Input validation failed: ${inputValidation.errors.join("; ")}`,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
// ── 3. Execute each required tool step ────────────────────────────────
|
|
79
|
+
let accumulatedOutput = { ...ctx.input };
|
|
80
|
+
for (const req of manifest.requiredTools) {
|
|
81
|
+
const stepStart = Date.now();
|
|
82
|
+
// Policy evaluation
|
|
83
|
+
const decision = evaluatePolicy({
|
|
84
|
+
actorId: ctx.actorId,
|
|
85
|
+
role: ctx.role,
|
|
86
|
+
toolName: req.toolName,
|
|
87
|
+
});
|
|
88
|
+
policyDecisions.push(decision);
|
|
89
|
+
if (decision.decision === "deny") {
|
|
90
|
+
stepTrace.push({
|
|
91
|
+
toolName: req.toolName,
|
|
92
|
+
status: "blocked",
|
|
93
|
+
durationMs: Date.now() - stepStart,
|
|
94
|
+
policyDecision: decision,
|
|
95
|
+
});
|
|
96
|
+
return {
|
|
97
|
+
runId,
|
|
98
|
+
skillId: manifest.skillId,
|
|
99
|
+
version: manifest.version,
|
|
100
|
+
status: "blocked",
|
|
101
|
+
stepTrace,
|
|
102
|
+
policyDecisions,
|
|
103
|
+
startedAt,
|
|
104
|
+
completedAt: new Date().toISOString(),
|
|
105
|
+
error: `Policy blocked tool '${req.toolName}': ${decision.reasonCodes.join(", ")}`,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
// Tool invocation
|
|
109
|
+
try {
|
|
110
|
+
const result = await ctx.callTool(req.toolName, accumulatedOutput);
|
|
111
|
+
if (result && typeof result === "object") {
|
|
112
|
+
accumulatedOutput = { ...accumulatedOutput, ...result };
|
|
113
|
+
}
|
|
114
|
+
stepTrace.push({
|
|
115
|
+
toolName: req.toolName,
|
|
116
|
+
status: "executed",
|
|
117
|
+
durationMs: Date.now() - stepStart,
|
|
118
|
+
policyDecision: decision,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
stepTrace.push({
|
|
123
|
+
toolName: req.toolName,
|
|
124
|
+
status: "skipped",
|
|
125
|
+
durationMs: Date.now() - stepStart,
|
|
126
|
+
policyDecision: decision,
|
|
127
|
+
});
|
|
128
|
+
return {
|
|
129
|
+
runId,
|
|
130
|
+
skillId: manifest.skillId,
|
|
131
|
+
version: manifest.version,
|
|
132
|
+
status: "error",
|
|
133
|
+
stepTrace,
|
|
134
|
+
policyDecisions,
|
|
135
|
+
startedAt,
|
|
136
|
+
completedAt: new Date().toISOString(),
|
|
137
|
+
error: `Tool '${req.toolName}' execution failed: ${String(err)}`,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// ── 4. Validate output ────────────────────────────────────────────────
|
|
142
|
+
const outputValidation = validateIO(accumulatedOutput, manifest.outputSchema, "output");
|
|
143
|
+
if (!outputValidation.valid) {
|
|
144
|
+
return {
|
|
145
|
+
runId,
|
|
146
|
+
skillId: manifest.skillId,
|
|
147
|
+
version: manifest.version,
|
|
148
|
+
status: "error",
|
|
149
|
+
stepTrace,
|
|
150
|
+
policyDecisions,
|
|
151
|
+
startedAt,
|
|
152
|
+
completedAt: new Date().toISOString(),
|
|
153
|
+
output: accumulatedOutput,
|
|
154
|
+
error: `Output validation failed: ${outputValidation.errors.join("; ")}`,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
return {
|
|
158
|
+
runId,
|
|
159
|
+
skillId: manifest.skillId,
|
|
160
|
+
version: manifest.version,
|
|
161
|
+
status: "success",
|
|
162
|
+
stepTrace,
|
|
163
|
+
policyDecisions,
|
|
164
|
+
startedAt,
|
|
165
|
+
completedAt: new Date().toISOString(),
|
|
166
|
+
output: accumulatedOutput,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Resets the run counter (for testing only).
|
|
171
|
+
*/
|
|
172
|
+
export function _resetRunCounter() {
|
|
173
|
+
runCounter = 0;
|
|
174
|
+
}
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill Manifest v1 Schema — FEAT-0057
|
|
3
|
+
*
|
|
4
|
+
* Defines the versioned manifest format for NestPilot retirement skills.
|
|
5
|
+
* Each skill declares input/output contracts, safety constraints,
|
|
6
|
+
* required tool dependencies, and minimum contract versions.
|
|
7
|
+
*
|
|
8
|
+
* @feature FEAT-0057
|
|
9
|
+
* @design DES-0055
|
|
10
|
+
*/
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
export declare const SkillConstraintSchema: z.ZodObject<{
|
|
13
|
+
/** Human-readable constraint description. */
|
|
14
|
+
description: z.ZodString;
|
|
15
|
+
/** Whether this constraint is enforced at runtime (vs. advisory). */
|
|
16
|
+
enforced: z.ZodBoolean;
|
|
17
|
+
}, "strip", z.ZodTypeAny, {
|
|
18
|
+
description: string;
|
|
19
|
+
enforced: boolean;
|
|
20
|
+
}, {
|
|
21
|
+
description: string;
|
|
22
|
+
enforced: boolean;
|
|
23
|
+
}>;
|
|
24
|
+
export declare const RequiredToolSchema: z.ZodObject<{
|
|
25
|
+
/** Tool name as registered in the contract registry. */
|
|
26
|
+
toolName: z.ZodString;
|
|
27
|
+
/** Minimum contract version required (semver). */
|
|
28
|
+
minContractVersion: z.ZodString;
|
|
29
|
+
}, "strip", z.ZodTypeAny, {
|
|
30
|
+
toolName: string;
|
|
31
|
+
minContractVersion: string;
|
|
32
|
+
}, {
|
|
33
|
+
toolName: string;
|
|
34
|
+
minContractVersion: string;
|
|
35
|
+
}>;
|
|
36
|
+
export declare const SkillIOFieldSchema: z.ZodObject<{
|
|
37
|
+
/** Field name. */
|
|
38
|
+
name: z.ZodString;
|
|
39
|
+
/** JSON Schema type (string, number, object, array, boolean). */
|
|
40
|
+
type: z.ZodEnum<["string", "number", "object", "array", "boolean"]>;
|
|
41
|
+
/** Whether this field is required. */
|
|
42
|
+
required: z.ZodBoolean;
|
|
43
|
+
/** Human-readable description. */
|
|
44
|
+
description: z.ZodString;
|
|
45
|
+
}, "strip", z.ZodTypeAny, {
|
|
46
|
+
name: string;
|
|
47
|
+
type: "string" | "number" | "boolean" | "object" | "array";
|
|
48
|
+
description: string;
|
|
49
|
+
required: boolean;
|
|
50
|
+
}, {
|
|
51
|
+
name: string;
|
|
52
|
+
type: "string" | "number" | "boolean" | "object" | "array";
|
|
53
|
+
description: string;
|
|
54
|
+
required: boolean;
|
|
55
|
+
}>;
|
|
56
|
+
export declare const SkillIOSchema: z.ZodObject<{
|
|
57
|
+
fields: z.ZodArray<z.ZodObject<{
|
|
58
|
+
/** Field name. */
|
|
59
|
+
name: z.ZodString;
|
|
60
|
+
/** JSON Schema type (string, number, object, array, boolean). */
|
|
61
|
+
type: z.ZodEnum<["string", "number", "object", "array", "boolean"]>;
|
|
62
|
+
/** Whether this field is required. */
|
|
63
|
+
required: z.ZodBoolean;
|
|
64
|
+
/** Human-readable description. */
|
|
65
|
+
description: z.ZodString;
|
|
66
|
+
}, "strip", z.ZodTypeAny, {
|
|
67
|
+
name: string;
|
|
68
|
+
type: "string" | "number" | "boolean" | "object" | "array";
|
|
69
|
+
description: string;
|
|
70
|
+
required: boolean;
|
|
71
|
+
}, {
|
|
72
|
+
name: string;
|
|
73
|
+
type: "string" | "number" | "boolean" | "object" | "array";
|
|
74
|
+
description: string;
|
|
75
|
+
required: boolean;
|
|
76
|
+
}>, "many">;
|
|
77
|
+
}, "strip", z.ZodTypeAny, {
|
|
78
|
+
fields: {
|
|
79
|
+
name: string;
|
|
80
|
+
type: "string" | "number" | "boolean" | "object" | "array";
|
|
81
|
+
description: string;
|
|
82
|
+
required: boolean;
|
|
83
|
+
}[];
|
|
84
|
+
}, {
|
|
85
|
+
fields: {
|
|
86
|
+
name: string;
|
|
87
|
+
type: "string" | "number" | "boolean" | "object" | "array";
|
|
88
|
+
description: string;
|
|
89
|
+
required: boolean;
|
|
90
|
+
}[];
|
|
91
|
+
}>;
|
|
92
|
+
export declare const SkillExampleSchema: z.ZodObject<{
|
|
93
|
+
/** Short description of the example scenario. */
|
|
94
|
+
description: z.ZodString;
|
|
95
|
+
/** Example input payload. */
|
|
96
|
+
input: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
97
|
+
/** Expected output structure (may be partial). */
|
|
98
|
+
expectedOutput: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
99
|
+
}, "strip", z.ZodTypeAny, {
|
|
100
|
+
input: Record<string, unknown>;
|
|
101
|
+
description: string;
|
|
102
|
+
expectedOutput: Record<string, unknown>;
|
|
103
|
+
}, {
|
|
104
|
+
input: Record<string, unknown>;
|
|
105
|
+
description: string;
|
|
106
|
+
expectedOutput: Record<string, unknown>;
|
|
107
|
+
}>;
|
|
108
|
+
export declare const SkillManifestV1Schema: z.ZodObject<{
|
|
109
|
+
/** Unique skill identifier (kebab-case). */
|
|
110
|
+
skillId: z.ZodString;
|
|
111
|
+
/** Semver version string. */
|
|
112
|
+
version: z.ZodString;
|
|
113
|
+
/** Human-readable display name. */
|
|
114
|
+
displayName: z.ZodString;
|
|
115
|
+
/** Skill description (max 300 chars for Tier 0 token budget). */
|
|
116
|
+
description: z.ZodString;
|
|
117
|
+
/** Skill pack this manifest belongs to. */
|
|
118
|
+
pack: z.ZodString;
|
|
119
|
+
/** Tools this skill requires with minimum contract versions. */
|
|
120
|
+
requiredTools: z.ZodArray<z.ZodObject<{
|
|
121
|
+
/** Tool name as registered in the contract registry. */
|
|
122
|
+
toolName: z.ZodString;
|
|
123
|
+
/** Minimum contract version required (semver). */
|
|
124
|
+
minContractVersion: z.ZodString;
|
|
125
|
+
}, "strip", z.ZodTypeAny, {
|
|
126
|
+
toolName: string;
|
|
127
|
+
minContractVersion: string;
|
|
128
|
+
}, {
|
|
129
|
+
toolName: string;
|
|
130
|
+
minContractVersion: string;
|
|
131
|
+
}>, "many">;
|
|
132
|
+
/** Typed input schema. */
|
|
133
|
+
inputSchema: z.ZodObject<{
|
|
134
|
+
fields: z.ZodArray<z.ZodObject<{
|
|
135
|
+
/** Field name. */
|
|
136
|
+
name: z.ZodString;
|
|
137
|
+
/** JSON Schema type (string, number, object, array, boolean). */
|
|
138
|
+
type: z.ZodEnum<["string", "number", "object", "array", "boolean"]>;
|
|
139
|
+
/** Whether this field is required. */
|
|
140
|
+
required: z.ZodBoolean;
|
|
141
|
+
/** Human-readable description. */
|
|
142
|
+
description: z.ZodString;
|
|
143
|
+
}, "strip", z.ZodTypeAny, {
|
|
144
|
+
name: string;
|
|
145
|
+
type: "string" | "number" | "boolean" | "object" | "array";
|
|
146
|
+
description: string;
|
|
147
|
+
required: boolean;
|
|
148
|
+
}, {
|
|
149
|
+
name: string;
|
|
150
|
+
type: "string" | "number" | "boolean" | "object" | "array";
|
|
151
|
+
description: string;
|
|
152
|
+
required: boolean;
|
|
153
|
+
}>, "many">;
|
|
154
|
+
}, "strip", z.ZodTypeAny, {
|
|
155
|
+
fields: {
|
|
156
|
+
name: string;
|
|
157
|
+
type: "string" | "number" | "boolean" | "object" | "array";
|
|
158
|
+
description: string;
|
|
159
|
+
required: boolean;
|
|
160
|
+
}[];
|
|
161
|
+
}, {
|
|
162
|
+
fields: {
|
|
163
|
+
name: string;
|
|
164
|
+
type: "string" | "number" | "boolean" | "object" | "array";
|
|
165
|
+
description: string;
|
|
166
|
+
required: boolean;
|
|
167
|
+
}[];
|
|
168
|
+
}>;
|
|
169
|
+
/** Typed output schema. */
|
|
170
|
+
outputSchema: z.ZodObject<{
|
|
171
|
+
fields: z.ZodArray<z.ZodObject<{
|
|
172
|
+
/** Field name. */
|
|
173
|
+
name: z.ZodString;
|
|
174
|
+
/** JSON Schema type (string, number, object, array, boolean). */
|
|
175
|
+
type: z.ZodEnum<["string", "number", "object", "array", "boolean"]>;
|
|
176
|
+
/** Whether this field is required. */
|
|
177
|
+
required: z.ZodBoolean;
|
|
178
|
+
/** Human-readable description. */
|
|
179
|
+
description: z.ZodString;
|
|
180
|
+
}, "strip", z.ZodTypeAny, {
|
|
181
|
+
name: string;
|
|
182
|
+
type: "string" | "number" | "boolean" | "object" | "array";
|
|
183
|
+
description: string;
|
|
184
|
+
required: boolean;
|
|
185
|
+
}, {
|
|
186
|
+
name: string;
|
|
187
|
+
type: "string" | "number" | "boolean" | "object" | "array";
|
|
188
|
+
description: string;
|
|
189
|
+
required: boolean;
|
|
190
|
+
}>, "many">;
|
|
191
|
+
}, "strip", z.ZodTypeAny, {
|
|
192
|
+
fields: {
|
|
193
|
+
name: string;
|
|
194
|
+
type: "string" | "number" | "boolean" | "object" | "array";
|
|
195
|
+
description: string;
|
|
196
|
+
required: boolean;
|
|
197
|
+
}[];
|
|
198
|
+
}, {
|
|
199
|
+
fields: {
|
|
200
|
+
name: string;
|
|
201
|
+
type: "string" | "number" | "boolean" | "object" | "array";
|
|
202
|
+
description: string;
|
|
203
|
+
required: boolean;
|
|
204
|
+
}[];
|
|
205
|
+
}>;
|
|
206
|
+
/** Safety and behavioral constraints. */
|
|
207
|
+
constraints: z.ZodArray<z.ZodObject<{
|
|
208
|
+
/** Human-readable constraint description. */
|
|
209
|
+
description: z.ZodString;
|
|
210
|
+
/** Whether this constraint is enforced at runtime (vs. advisory). */
|
|
211
|
+
enforced: z.ZodBoolean;
|
|
212
|
+
}, "strip", z.ZodTypeAny, {
|
|
213
|
+
description: string;
|
|
214
|
+
enforced: boolean;
|
|
215
|
+
}, {
|
|
216
|
+
description: string;
|
|
217
|
+
enforced: boolean;
|
|
218
|
+
}>, "many">;
|
|
219
|
+
/** Non-permitted actions — things this skill must never do. */
|
|
220
|
+
nonPermittedActions: z.ZodArray<z.ZodString, "many">;
|
|
221
|
+
/** Sensitive data declarations. */
|
|
222
|
+
sensitiveDataRequirements: z.ZodArray<z.ZodString, "many">;
|
|
223
|
+
/** Example input/output pairs. */
|
|
224
|
+
examples: z.ZodArray<z.ZodObject<{
|
|
225
|
+
/** Short description of the example scenario. */
|
|
226
|
+
description: z.ZodString;
|
|
227
|
+
/** Example input payload. */
|
|
228
|
+
input: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
229
|
+
/** Expected output structure (may be partial). */
|
|
230
|
+
expectedOutput: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
231
|
+
}, "strip", z.ZodTypeAny, {
|
|
232
|
+
input: Record<string, unknown>;
|
|
233
|
+
description: string;
|
|
234
|
+
expectedOutput: Record<string, unknown>;
|
|
235
|
+
}, {
|
|
236
|
+
input: Record<string, unknown>;
|
|
237
|
+
description: string;
|
|
238
|
+
expectedOutput: Record<string, unknown>;
|
|
239
|
+
}>, "many">;
|
|
240
|
+
}, "strip", z.ZodTypeAny, {
|
|
241
|
+
version: string;
|
|
242
|
+
description: string;
|
|
243
|
+
skillId: string;
|
|
244
|
+
displayName: string;
|
|
245
|
+
pack: string;
|
|
246
|
+
requiredTools: {
|
|
247
|
+
toolName: string;
|
|
248
|
+
minContractVersion: string;
|
|
249
|
+
}[];
|
|
250
|
+
inputSchema: {
|
|
251
|
+
fields: {
|
|
252
|
+
name: string;
|
|
253
|
+
type: "string" | "number" | "boolean" | "object" | "array";
|
|
254
|
+
description: string;
|
|
255
|
+
required: boolean;
|
|
256
|
+
}[];
|
|
257
|
+
};
|
|
258
|
+
outputSchema: {
|
|
259
|
+
fields: {
|
|
260
|
+
name: string;
|
|
261
|
+
type: "string" | "number" | "boolean" | "object" | "array";
|
|
262
|
+
description: string;
|
|
263
|
+
required: boolean;
|
|
264
|
+
}[];
|
|
265
|
+
};
|
|
266
|
+
constraints: {
|
|
267
|
+
description: string;
|
|
268
|
+
enforced: boolean;
|
|
269
|
+
}[];
|
|
270
|
+
nonPermittedActions: string[];
|
|
271
|
+
sensitiveDataRequirements: string[];
|
|
272
|
+
examples: {
|
|
273
|
+
input: Record<string, unknown>;
|
|
274
|
+
description: string;
|
|
275
|
+
expectedOutput: Record<string, unknown>;
|
|
276
|
+
}[];
|
|
277
|
+
}, {
|
|
278
|
+
version: string;
|
|
279
|
+
description: string;
|
|
280
|
+
skillId: string;
|
|
281
|
+
displayName: string;
|
|
282
|
+
pack: string;
|
|
283
|
+
requiredTools: {
|
|
284
|
+
toolName: string;
|
|
285
|
+
minContractVersion: string;
|
|
286
|
+
}[];
|
|
287
|
+
inputSchema: {
|
|
288
|
+
fields: {
|
|
289
|
+
name: string;
|
|
290
|
+
type: "string" | "number" | "boolean" | "object" | "array";
|
|
291
|
+
description: string;
|
|
292
|
+
required: boolean;
|
|
293
|
+
}[];
|
|
294
|
+
};
|
|
295
|
+
outputSchema: {
|
|
296
|
+
fields: {
|
|
297
|
+
name: string;
|
|
298
|
+
type: "string" | "number" | "boolean" | "object" | "array";
|
|
299
|
+
description: string;
|
|
300
|
+
required: boolean;
|
|
301
|
+
}[];
|
|
302
|
+
};
|
|
303
|
+
constraints: {
|
|
304
|
+
description: string;
|
|
305
|
+
enforced: boolean;
|
|
306
|
+
}[];
|
|
307
|
+
nonPermittedActions: string[];
|
|
308
|
+
sensitiveDataRequirements: string[];
|
|
309
|
+
examples: {
|
|
310
|
+
input: Record<string, unknown>;
|
|
311
|
+
description: string;
|
|
312
|
+
expectedOutput: Record<string, unknown>;
|
|
313
|
+
}[];
|
|
314
|
+
}>;
|
|
315
|
+
export type SkillConstraint = z.infer<typeof SkillConstraintSchema>;
|
|
316
|
+
export type RequiredTool = z.infer<typeof RequiredToolSchema>;
|
|
317
|
+
export type SkillIOField = z.infer<typeof SkillIOFieldSchema>;
|
|
318
|
+
export type SkillIO = z.infer<typeof SkillIOSchema>;
|
|
319
|
+
export type SkillExample = z.infer<typeof SkillExampleSchema>;
|
|
320
|
+
export type SkillManifestV1 = z.infer<typeof SkillManifestV1Schema>;
|
|
321
|
+
export interface ManifestValidationResult {
|
|
322
|
+
valid: true;
|
|
323
|
+
manifest: SkillManifestV1;
|
|
324
|
+
}
|
|
325
|
+
export interface ManifestValidationError {
|
|
326
|
+
valid: false;
|
|
327
|
+
errors: string[];
|
|
328
|
+
}
|
|
329
|
+
export type ManifestValidation = ManifestValidationResult | ManifestValidationError;
|
|
330
|
+
/**
|
|
331
|
+
* Validates a raw object against the Skill Manifest v1 schema.
|
|
332
|
+
*/
|
|
333
|
+
export declare function validateManifest(raw: unknown): ManifestValidation;
|
|
334
|
+
/**
|
|
335
|
+
* Validates and returns the manifest or throws.
|
|
336
|
+
*/
|
|
337
|
+
export declare function requireValidManifest(raw: unknown): SkillManifestV1;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill Manifest v1 Schema — FEAT-0057
|
|
3
|
+
*
|
|
4
|
+
* Defines the versioned manifest format for NestPilot retirement skills.
|
|
5
|
+
* Each skill declares input/output contracts, safety constraints,
|
|
6
|
+
* required tool dependencies, and minimum contract versions.
|
|
7
|
+
*
|
|
8
|
+
* @feature FEAT-0057
|
|
9
|
+
* @design DES-0055
|
|
10
|
+
*/
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
// ── Zod Schemas ─────────────────────────────────────────────────────────
|
|
13
|
+
export const SkillConstraintSchema = z.object({
|
|
14
|
+
/** Human-readable constraint description. */
|
|
15
|
+
description: z.string().min(1),
|
|
16
|
+
/** Whether this constraint is enforced at runtime (vs. advisory). */
|
|
17
|
+
enforced: z.boolean(),
|
|
18
|
+
});
|
|
19
|
+
export const RequiredToolSchema = z.object({
|
|
20
|
+
/** Tool name as registered in the contract registry. */
|
|
21
|
+
toolName: z.string().min(1),
|
|
22
|
+
/** Minimum contract version required (semver). */
|
|
23
|
+
minContractVersion: z.string().regex(/^\d+\.\d+\.\d+$/, "Must be semver"),
|
|
24
|
+
});
|
|
25
|
+
export const SkillIOFieldSchema = z.object({
|
|
26
|
+
/** Field name. */
|
|
27
|
+
name: z.string().min(1),
|
|
28
|
+
/** JSON Schema type (string, number, object, array, boolean). */
|
|
29
|
+
type: z.enum(["string", "number", "object", "array", "boolean"]),
|
|
30
|
+
/** Whether this field is required. */
|
|
31
|
+
required: z.boolean(),
|
|
32
|
+
/** Human-readable description. */
|
|
33
|
+
description: z.string().min(1),
|
|
34
|
+
});
|
|
35
|
+
export const SkillIOSchema = z.object({
|
|
36
|
+
fields: z.array(SkillIOFieldSchema).min(1),
|
|
37
|
+
});
|
|
38
|
+
export const SkillExampleSchema = z.object({
|
|
39
|
+
/** Short description of the example scenario. */
|
|
40
|
+
description: z.string().min(1),
|
|
41
|
+
/** Example input payload. */
|
|
42
|
+
input: z.record(z.unknown()),
|
|
43
|
+
/** Expected output structure (may be partial). */
|
|
44
|
+
expectedOutput: z.record(z.unknown()),
|
|
45
|
+
});
|
|
46
|
+
export const SkillManifestV1Schema = z.object({
|
|
47
|
+
/** Unique skill identifier (kebab-case). */
|
|
48
|
+
skillId: z.string().regex(/^[a-z][a-z0-9-]*$/, "Must be kebab-case"),
|
|
49
|
+
/** Semver version string. */
|
|
50
|
+
version: z.string().regex(/^\d+\.\d+\.\d+$/, "Must be semver"),
|
|
51
|
+
/** Human-readable display name. */
|
|
52
|
+
displayName: z.string().min(1),
|
|
53
|
+
/** Skill description (max 300 chars for Tier 0 token budget). */
|
|
54
|
+
description: z.string().min(1).max(300),
|
|
55
|
+
/** Skill pack this manifest belongs to. */
|
|
56
|
+
pack: z.string().min(1),
|
|
57
|
+
/** Tools this skill requires with minimum contract versions. */
|
|
58
|
+
requiredTools: z.array(RequiredToolSchema).min(1),
|
|
59
|
+
/** Typed input schema. */
|
|
60
|
+
inputSchema: SkillIOSchema,
|
|
61
|
+
/** Typed output schema. */
|
|
62
|
+
outputSchema: SkillIOSchema,
|
|
63
|
+
/** Safety and behavioral constraints. */
|
|
64
|
+
constraints: z.array(SkillConstraintSchema).min(1),
|
|
65
|
+
/** Non-permitted actions — things this skill must never do. */
|
|
66
|
+
nonPermittedActions: z.array(z.string().min(1)),
|
|
67
|
+
/** Sensitive data declarations. */
|
|
68
|
+
sensitiveDataRequirements: z.array(z.string()),
|
|
69
|
+
/** Example input/output pairs. */
|
|
70
|
+
examples: z.array(SkillExampleSchema).min(1),
|
|
71
|
+
});
|
|
72
|
+
/**
|
|
73
|
+
* Validates a raw object against the Skill Manifest v1 schema.
|
|
74
|
+
*/
|
|
75
|
+
export function validateManifest(raw) {
|
|
76
|
+
const result = SkillManifestV1Schema.safeParse(raw);
|
|
77
|
+
if (result.success) {
|
|
78
|
+
return { valid: true, manifest: result.data };
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
valid: false,
|
|
82
|
+
errors: result.error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Validates and returns the manifest or throws.
|
|
87
|
+
*/
|
|
88
|
+
export function requireValidManifest(raw) {
|
|
89
|
+
const result = validateManifest(raw);
|
|
90
|
+
if (!result.valid) {
|
|
91
|
+
throw new Error(`Skill manifest validation failed:\n ${result.errors.join("\n ")}`);
|
|
92
|
+
}
|
|
93
|
+
return result.manifest;
|
|
94
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill Registry — FEAT-0057
|
|
3
|
+
*
|
|
4
|
+
* Loads, validates, and indexes v1 skill manifests.
|
|
5
|
+
* Performs compatibility checks against FEAT-0056 tool contracts
|
|
6
|
+
* to ensure required tool versions are available before execution.
|
|
7
|
+
*
|
|
8
|
+
* @feature FEAT-0057
|
|
9
|
+
* @design DES-0055
|
|
10
|
+
*/
|
|
11
|
+
import { type SkillManifestV1, type ManifestValidation } from "./skill-manifest-schema.js";
|
|
12
|
+
export interface CompatibilityCheckResult {
|
|
13
|
+
compatible: true;
|
|
14
|
+
skillId: string;
|
|
15
|
+
checkedTools: string[];
|
|
16
|
+
}
|
|
17
|
+
export interface CompatibilityToolFailure {
|
|
18
|
+
toolName: string;
|
|
19
|
+
requiredVersion: string;
|
|
20
|
+
reason: string;
|
|
21
|
+
}
|
|
22
|
+
export interface CompatibilityCheckFailure {
|
|
23
|
+
compatible: false;
|
|
24
|
+
skillId: string;
|
|
25
|
+
failures: CompatibilityToolFailure[];
|
|
26
|
+
}
|
|
27
|
+
export type CompatibilityCheck = CompatibilityCheckResult | CompatibilityCheckFailure;
|
|
28
|
+
export interface SkillLookupResult {
|
|
29
|
+
found: true;
|
|
30
|
+
manifest: SkillManifestV1;
|
|
31
|
+
}
|
|
32
|
+
export interface SkillLookupMiss {
|
|
33
|
+
found: false;
|
|
34
|
+
skillId: string;
|
|
35
|
+
reason: string;
|
|
36
|
+
}
|
|
37
|
+
export type SkillLookup = SkillLookupResult | SkillLookupMiss;
|
|
38
|
+
/**
|
|
39
|
+
* Returns true if `actual` >= `required` (semver).
|
|
40
|
+
*/
|
|
41
|
+
export declare function semverSatisfies(actual: string, required: string): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Registers a validated skill manifest in the registry.
|
|
44
|
+
* Returns validation result; rejects invalid manifests.
|
|
45
|
+
*/
|
|
46
|
+
export declare function registerSkill(raw: unknown): ManifestValidation;
|
|
47
|
+
/**
|
|
48
|
+
* Look up a registered skill by ID.
|
|
49
|
+
*/
|
|
50
|
+
export declare function lookupSkill(skillId: string): SkillLookup;
|
|
51
|
+
/**
|
|
52
|
+
* Returns all registered skill manifests.
|
|
53
|
+
*/
|
|
54
|
+
export declare function getAllSkills(): ReadonlyArray<SkillManifestV1>;
|
|
55
|
+
/**
|
|
56
|
+
* Checks whether all required tools for a skill are available
|
|
57
|
+
* in the contract registry with sufficient versions.
|
|
58
|
+
*
|
|
59
|
+
* This is the compatibility gate: execution MUST be blocked
|
|
60
|
+
* if any required tool contract is missing or below the
|
|
61
|
+
* minimum version.
|
|
62
|
+
*/
|
|
63
|
+
export declare function checkCompatibility(manifest: SkillManifestV1): CompatibilityCheck;
|
|
64
|
+
/**
|
|
65
|
+
* Checks compatibility and throws if requirements are not met.
|
|
66
|
+
*/
|
|
67
|
+
export declare function requireCompatibility(manifest: SkillManifestV1): CompatibilityCheckResult;
|
|
68
|
+
/**
|
|
69
|
+
* Clears all registered skills (for testing only).
|
|
70
|
+
*/
|
|
71
|
+
export declare function _resetSkillRegistry(): void;
|