@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,43 @@
|
|
|
1
|
+
# Tool Skill: verify_forecast
|
|
2
|
+
|
|
3
|
+
Runs a retirement forecast and returns a verification packet — a structured, auditable record
|
|
4
|
+
of the inputs, calculation trace, and verdict. Used to verify advisor projections or double-check
|
|
5
|
+
personal planning scenarios.
|
|
6
|
+
|
|
7
|
+
## When to Use
|
|
8
|
+
|
|
9
|
+
Use `verify_forecast` when the user wants to:
|
|
10
|
+
- Verify numbers from their financial advisor
|
|
11
|
+
- Create an auditable record of their retirement projection
|
|
12
|
+
- Get a "second opinion" on a specific set of assumptions
|
|
13
|
+
|
|
14
|
+
## Core Purpose: Independent Verification
|
|
15
|
+
|
|
16
|
+
This is NestPilot's signature capability. The verification packet is the user's proof that
|
|
17
|
+
the math was run independently, with explicit assumptions, and the results are reproducible.
|
|
18
|
+
|
|
19
|
+
ALWAYS frame verification as: "Let's verify these numbers independently."
|
|
20
|
+
NEVER suggest the advisor was wrong — present the verification as a confirmation or a
|
|
21
|
+
starting point for a conversation with the advisor.
|
|
22
|
+
|
|
23
|
+
## Presenting the Verification Packet
|
|
24
|
+
|
|
25
|
+
Structure the response in three parts:
|
|
26
|
+
1. **Assumptions verified**: List the key inputs (return rate, withdrawal rate, balance,
|
|
27
|
+
timeline) that were used in the calculation.
|
|
28
|
+
2. **Result**: The verified balance, income, and longevity assessment.
|
|
29
|
+
3. **Verdict**: "The projection is mathematically consistent with the stated assumptions" OR
|
|
30
|
+
"The projection assumes [X] which appears [optimistic/conservative] — here's why..."
|
|
31
|
+
|
|
32
|
+
## Framing the Verdict
|
|
33
|
+
|
|
34
|
+
- If results match: "The projection checks out. The math supports a balance of $[X] at age [Y]
|
|
35
|
+
under these assumptions."
|
|
36
|
+
- If there's a discrepancy: "Our calculation shows $[X] vs the stated $[Y]. The difference is
|
|
37
|
+
likely due to [possible cause]. We recommend confirming the assumed return rate and
|
|
38
|
+
whether Social Security income is included."
|
|
39
|
+
- NEVER say "your advisor is wrong" — say "the numbers differ, which is worth discussing."
|
|
40
|
+
|
|
41
|
+
## Error Handling
|
|
42
|
+
|
|
43
|
+
Same as `run_forecast`. Validation errors should prompt clarification of the specific field.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified MCP App configuration.
|
|
3
|
+
*
|
|
4
|
+
* Merges the original mcp-app config with mcp-edge production features:
|
|
5
|
+
* authentication, rate limiting, telemetry.
|
|
6
|
+
*/
|
|
7
|
+
export interface AppConfig {
|
|
8
|
+
port: number;
|
|
9
|
+
backendUrl: string;
|
|
10
|
+
agentRuntimeUrl: string;
|
|
11
|
+
/** "token" = opaque token validation (existing), "jwt-passthrough" = forward JWT to backend */
|
|
12
|
+
authMode: "token" | "jwt-passthrough";
|
|
13
|
+
requireAuth: boolean;
|
|
14
|
+
authTokens: Set<string>;
|
|
15
|
+
defaultUserId: string;
|
|
16
|
+
rateLimitWindowMs: number;
|
|
17
|
+
rateLimitMaxRequests: number;
|
|
18
|
+
enableConsoleTracing: boolean;
|
|
19
|
+
}
|
|
20
|
+
export declare function loadConfig(env?: NodeJS.ProcessEnv): AppConfig;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified MCP App configuration.
|
|
3
|
+
*
|
|
4
|
+
* Merges the original mcp-app config with mcp-edge production features:
|
|
5
|
+
* authentication, rate limiting, telemetry.
|
|
6
|
+
*/
|
|
7
|
+
function parseBoolean(value, fallback) {
|
|
8
|
+
if (value === undefined)
|
|
9
|
+
return fallback;
|
|
10
|
+
const normalized = value.trim().toLowerCase();
|
|
11
|
+
if (["1", "true", "yes", "on"].includes(normalized))
|
|
12
|
+
return true;
|
|
13
|
+
if (["0", "false", "no", "off"].includes(normalized))
|
|
14
|
+
return false;
|
|
15
|
+
return fallback;
|
|
16
|
+
}
|
|
17
|
+
function parsePositiveInt(value, fallback) {
|
|
18
|
+
if (!value)
|
|
19
|
+
return fallback;
|
|
20
|
+
const parsed = Number.parseInt(value, 10);
|
|
21
|
+
return Number.isNaN(parsed) || parsed <= 0 ? fallback : parsed;
|
|
22
|
+
}
|
|
23
|
+
function parseTokenSet(value) {
|
|
24
|
+
if (!value)
|
|
25
|
+
return new Set();
|
|
26
|
+
return new Set(value
|
|
27
|
+
.split(",")
|
|
28
|
+
.map((item) => item.trim())
|
|
29
|
+
.filter(Boolean));
|
|
30
|
+
}
|
|
31
|
+
export function loadConfig(env = process.env) {
|
|
32
|
+
return {
|
|
33
|
+
port: parsePositiveInt(env.PORT, 3001),
|
|
34
|
+
backendUrl: env.NESTPILOT_BACKEND_URL ?? "http://localhost:8080",
|
|
35
|
+
agentRuntimeUrl: env.AGENT_RUNTIME_URL ?? "http://localhost:3002",
|
|
36
|
+
authMode: env.MCP_AUTH_MODE === "jwt-passthrough" ? "jwt-passthrough" : "token",
|
|
37
|
+
requireAuth: parseBoolean(env.MCP_REQUIRE_AUTH, true),
|
|
38
|
+
authTokens: parseTokenSet(env.MCP_AUTH_TOKENS),
|
|
39
|
+
defaultUserId: env.MCP_DEFAULT_USER_ID ?? "anonymous",
|
|
40
|
+
rateLimitWindowMs: parsePositiveInt(env.MCP_RATE_LIMIT_WINDOW_MS, 60_000),
|
|
41
|
+
rateLimitMaxRequests: parsePositiveInt(env.MCP_RATE_LIMIT_MAX_REQUESTS, 60),
|
|
42
|
+
enableConsoleTracing: parseBoolean(env.MCP_ENABLE_CONSOLE_TRACING, false),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provenance Annotator — FEAT-0056
|
|
3
|
+
*
|
|
4
|
+
* Appends source, timestamp, and contract metadata to successful
|
|
5
|
+
* tool responses. Every tool result envelope includes provenance
|
|
6
|
+
* fields so decisions are traceable and auditable.
|
|
7
|
+
*
|
|
8
|
+
* @feature FEAT-0056
|
|
9
|
+
*/
|
|
10
|
+
export interface ProvenanceMetadata {
|
|
11
|
+
source: string;
|
|
12
|
+
timestamp: string;
|
|
13
|
+
contractVersion: string;
|
|
14
|
+
requestId: string;
|
|
15
|
+
toolName: string;
|
|
16
|
+
}
|
|
17
|
+
export interface ProvenanceEnvelope<T = unknown> {
|
|
18
|
+
data: T;
|
|
19
|
+
provenance: ProvenanceMetadata;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Wraps a tool result payload with provenance metadata.
|
|
23
|
+
*/
|
|
24
|
+
export declare function annotateWithProvenance<T>(data: T, toolName: string, contractVersion: string): ProvenanceEnvelope<T>;
|
|
25
|
+
/**
|
|
26
|
+
* Checks whether a payload already has a provenance envelope.
|
|
27
|
+
*/
|
|
28
|
+
export declare function hasProvenance(payload: unknown): payload is ProvenanceEnvelope;
|
|
29
|
+
/**
|
|
30
|
+
* Validates that a provenance envelope has all required fields.
|
|
31
|
+
* Returns an array of missing field names (empty = valid).
|
|
32
|
+
*/
|
|
33
|
+
export declare function validateProvenance(envelope: ProvenanceEnvelope): string[];
|
|
34
|
+
/**
|
|
35
|
+
* Resets the request counter (for testing only).
|
|
36
|
+
*/
|
|
37
|
+
export declare function _resetRequestCounter(): void;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provenance Annotator — FEAT-0056
|
|
3
|
+
*
|
|
4
|
+
* Appends source, timestamp, and contract metadata to successful
|
|
5
|
+
* tool responses. Every tool result envelope includes provenance
|
|
6
|
+
* fields so decisions are traceable and auditable.
|
|
7
|
+
*
|
|
8
|
+
* @feature FEAT-0056
|
|
9
|
+
*/
|
|
10
|
+
// ── Constants ────────────────────────────────────────────────────────────
|
|
11
|
+
const SOURCE = "nestpilot-mcp-app";
|
|
12
|
+
let requestCounter = 0;
|
|
13
|
+
function generateRequestId() {
|
|
14
|
+
requestCounter += 1;
|
|
15
|
+
return `req-${Date.now()}-${requestCounter}`;
|
|
16
|
+
}
|
|
17
|
+
// ── Annotator ────────────────────────────────────────────────────────────
|
|
18
|
+
/**
|
|
19
|
+
* Wraps a tool result payload with provenance metadata.
|
|
20
|
+
*/
|
|
21
|
+
export function annotateWithProvenance(data, toolName, contractVersion) {
|
|
22
|
+
return {
|
|
23
|
+
data,
|
|
24
|
+
provenance: {
|
|
25
|
+
source: SOURCE,
|
|
26
|
+
timestamp: new Date().toISOString(),
|
|
27
|
+
contractVersion,
|
|
28
|
+
requestId: generateRequestId(),
|
|
29
|
+
toolName,
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Checks whether a payload already has a provenance envelope.
|
|
35
|
+
*/
|
|
36
|
+
export function hasProvenance(payload) {
|
|
37
|
+
if (payload && typeof payload === "object" && "provenance" in payload) {
|
|
38
|
+
const p = payload.provenance;
|
|
39
|
+
return (typeof p === "object" &&
|
|
40
|
+
p !== null &&
|
|
41
|
+
typeof p.source === "string" &&
|
|
42
|
+
typeof p.timestamp === "string" &&
|
|
43
|
+
typeof p.contractVersion === "string");
|
|
44
|
+
}
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Validates that a provenance envelope has all required fields.
|
|
49
|
+
* Returns an array of missing field names (empty = valid).
|
|
50
|
+
*/
|
|
51
|
+
export function validateProvenance(envelope) {
|
|
52
|
+
const missing = [];
|
|
53
|
+
const p = envelope.provenance;
|
|
54
|
+
if (!p.source)
|
|
55
|
+
missing.push("source");
|
|
56
|
+
if (!p.timestamp)
|
|
57
|
+
missing.push("timestamp");
|
|
58
|
+
if (!p.contractVersion)
|
|
59
|
+
missing.push("contractVersion");
|
|
60
|
+
if (!p.requestId)
|
|
61
|
+
missing.push("requestId");
|
|
62
|
+
if (!p.toolName)
|
|
63
|
+
missing.push("toolName");
|
|
64
|
+
return missing;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Resets the request counter (for testing only).
|
|
68
|
+
*/
|
|
69
|
+
export function _resetRequestCounter() {
|
|
70
|
+
requestCounter = 0;
|
|
71
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Contract Registry — FEAT-0056
|
|
3
|
+
*
|
|
4
|
+
* Stores versioned contract descriptors for P0 retirement MCP tools.
|
|
5
|
+
* Each descriptor defines the tool's interface contract including schema
|
|
6
|
+
* references, idempotency mode, and error semantics.
|
|
7
|
+
*
|
|
8
|
+
* @feature FEAT-0056
|
|
9
|
+
*/
|
|
10
|
+
export type IdempotencyMode = "none" | "idempotent" | "safe-retry";
|
|
11
|
+
export interface ToolContractDescriptor {
|
|
12
|
+
toolName: string;
|
|
13
|
+
contractVersion: string;
|
|
14
|
+
inputSchemaRef: string;
|
|
15
|
+
outputSchemaRef: string;
|
|
16
|
+
errorSchemaRef: string;
|
|
17
|
+
idempotencyMode: IdempotencyMode;
|
|
18
|
+
privileged: boolean;
|
|
19
|
+
description: string;
|
|
20
|
+
}
|
|
21
|
+
export interface ContractLookupResult {
|
|
22
|
+
found: true;
|
|
23
|
+
contract: ToolContractDescriptor;
|
|
24
|
+
}
|
|
25
|
+
export interface ContractLookupMiss {
|
|
26
|
+
found: false;
|
|
27
|
+
toolName: string;
|
|
28
|
+
reason: string;
|
|
29
|
+
}
|
|
30
|
+
export type ContractLookup = ContractLookupResult | ContractLookupMiss;
|
|
31
|
+
/**
|
|
32
|
+
* Look up the contract descriptor for a given tool name.
|
|
33
|
+
*/
|
|
34
|
+
export declare function lookupContract(toolName: string): ContractLookup;
|
|
35
|
+
/**
|
|
36
|
+
* Returns all registered contract descriptors.
|
|
37
|
+
*/
|
|
38
|
+
export declare function getAllContracts(): ReadonlyArray<ToolContractDescriptor>;
|
|
39
|
+
/**
|
|
40
|
+
* Validates that a tool name has a registered contract.
|
|
41
|
+
* Returns the contract version on success, or throws on failure.
|
|
42
|
+
*/
|
|
43
|
+
export declare function requireContract(toolName: string): ToolContractDescriptor;
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Contract Registry — FEAT-0056
|
|
3
|
+
*
|
|
4
|
+
* Stores versioned contract descriptors for P0 retirement MCP tools.
|
|
5
|
+
* Each descriptor defines the tool's interface contract including schema
|
|
6
|
+
* references, idempotency mode, and error semantics.
|
|
7
|
+
*
|
|
8
|
+
* @feature FEAT-0056
|
|
9
|
+
*/
|
|
10
|
+
// ── P0 Retirement Tool Contracts ─────────────────────────────────────────
|
|
11
|
+
const P0_CONTRACTS = [
|
|
12
|
+
{
|
|
13
|
+
toolName: "create_plan",
|
|
14
|
+
contractVersion: "1.0.0",
|
|
15
|
+
inputSchemaRef: "schemas/plan-schema-v1.json#/quickstart",
|
|
16
|
+
outputSchemaRef: "schemas/plan-schema-v1.json#/projection",
|
|
17
|
+
errorSchemaRef: "schemas/error-envelope-v1.json",
|
|
18
|
+
idempotencyMode: "safe-retry",
|
|
19
|
+
privileged: false,
|
|
20
|
+
description: "Quick retirement projection from basic inputs",
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
toolName: "run_forecast",
|
|
24
|
+
contractVersion: "1.0.0",
|
|
25
|
+
inputSchemaRef: "schemas/plan-schema-v1.json#/extended",
|
|
26
|
+
outputSchemaRef: "schemas/forecast-schema-v1.json",
|
|
27
|
+
errorSchemaRef: "schemas/error-envelope-v1.json",
|
|
28
|
+
idempotencyMode: "idempotent",
|
|
29
|
+
privileged: false,
|
|
30
|
+
description: "Comprehensive multi-account retirement forecast",
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
toolName: "run_scenario",
|
|
34
|
+
contractVersion: "1.0.0",
|
|
35
|
+
inputSchemaRef: "schemas/plan-schema-v1.json#/scenario",
|
|
36
|
+
outputSchemaRef: "schemas/forecast-schema-v1.json#/scenario-result",
|
|
37
|
+
errorSchemaRef: "schemas/error-envelope-v1.json",
|
|
38
|
+
idempotencyMode: "idempotent",
|
|
39
|
+
privileged: false,
|
|
40
|
+
description: "What-if scenario comparison with deltas and stress tests",
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
toolName: "verify_forecast",
|
|
44
|
+
contractVersion: "1.0.0",
|
|
45
|
+
inputSchemaRef: "schemas/plan-schema-v1.json#/extended",
|
|
46
|
+
outputSchemaRef: "schemas/forecast-schema-v1.json#/verification-packet",
|
|
47
|
+
errorSchemaRef: "schemas/error-envelope-v1.json",
|
|
48
|
+
idempotencyMode: "idempotent",
|
|
49
|
+
privileged: false,
|
|
50
|
+
description: "Auditable forecast verification with trace",
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
toolName: "coach",
|
|
54
|
+
contractVersion: "1.0.0",
|
|
55
|
+
inputSchemaRef: "schemas/coach-schema-v1.1.json#/input",
|
|
56
|
+
outputSchemaRef: "schemas/coach-schema-v1.1.json#/output",
|
|
57
|
+
errorSchemaRef: "schemas/error-envelope-v1.json",
|
|
58
|
+
idempotencyMode: "safe-retry",
|
|
59
|
+
privileged: false,
|
|
60
|
+
description: "AI-powered retirement coaching guidance",
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
toolName: "medicare-analyze",
|
|
64
|
+
contractVersion: "1.0.0",
|
|
65
|
+
inputSchemaRef: "schemas/medicare-analyze-v1.json#/input",
|
|
66
|
+
outputSchemaRef: "schemas/medicare-analyze-v1.json#/output",
|
|
67
|
+
errorSchemaRef: "schemas/error-envelope-v1.json",
|
|
68
|
+
idempotencyMode: "idempotent",
|
|
69
|
+
privileged: false,
|
|
70
|
+
description: "Medicare enrollment health check analysis",
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
toolName: "optimize_roth_conversion",
|
|
74
|
+
contractVersion: "1.0.0",
|
|
75
|
+
inputSchemaRef: "schemas/roth-optimization-v1.json#/input",
|
|
76
|
+
outputSchemaRef: "schemas/roth-optimization-v1.json#/output",
|
|
77
|
+
errorSchemaRef: "schemas/error-envelope-v1.json",
|
|
78
|
+
idempotencyMode: "idempotent",
|
|
79
|
+
privileged: false,
|
|
80
|
+
description: "Multi-year Roth conversion optimization with tax impact analysis",
|
|
81
|
+
},
|
|
82
|
+
// ── Plan management contracts ───────────────────────────────────────
|
|
83
|
+
{
|
|
84
|
+
toolName: "list_plans",
|
|
85
|
+
contractVersion: "1.0.0",
|
|
86
|
+
inputSchemaRef: "schemas/plan-management-v1.json#/list",
|
|
87
|
+
outputSchemaRef: "schemas/plan-management-v1.json#/list-result",
|
|
88
|
+
errorSchemaRef: "schemas/error-envelope-v1.json",
|
|
89
|
+
idempotencyMode: "safe-retry",
|
|
90
|
+
privileged: false,
|
|
91
|
+
description: "Lists all saved retirement plans for the authenticated user",
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
toolName: "get_plan",
|
|
95
|
+
contractVersion: "1.0.0",
|
|
96
|
+
inputSchemaRef: "schemas/plan-management-v1.json#/get",
|
|
97
|
+
outputSchemaRef: "schemas/plan-management-v1.json#/get-result",
|
|
98
|
+
errorSchemaRef: "schemas/error-envelope-v1.json",
|
|
99
|
+
idempotencyMode: "safe-retry",
|
|
100
|
+
privileged: false,
|
|
101
|
+
description: "Retrieves a single saved plan by ID",
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
toolName: "get_active_plan",
|
|
105
|
+
contractVersion: "1.0.0",
|
|
106
|
+
inputSchemaRef: "schemas/plan-management-v1.json#/get-active",
|
|
107
|
+
outputSchemaRef: "schemas/plan-management-v1.json#/get-result",
|
|
108
|
+
errorSchemaRef: "schemas/error-envelope-v1.json",
|
|
109
|
+
idempotencyMode: "safe-retry",
|
|
110
|
+
privileged: false,
|
|
111
|
+
description: "Retrieves the user's currently active plan",
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
toolName: "create_saved_plan",
|
|
115
|
+
contractVersion: "1.0.0",
|
|
116
|
+
inputSchemaRef: "schemas/plan-management-v1.json#/create",
|
|
117
|
+
outputSchemaRef: "schemas/plan-management-v1.json#/create-result",
|
|
118
|
+
errorSchemaRef: "schemas/error-envelope-v1.json",
|
|
119
|
+
idempotencyMode: "none",
|
|
120
|
+
privileged: false,
|
|
121
|
+
description: "Creates and persists a new retirement plan",
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
toolName: "save_plan",
|
|
125
|
+
contractVersion: "1.0.0",
|
|
126
|
+
inputSchemaRef: "schemas/plan-management-v1.json#/save",
|
|
127
|
+
outputSchemaRef: "schemas/plan-management-v1.json#/save-result",
|
|
128
|
+
errorSchemaRef: "schemas/error-envelope-v1.json",
|
|
129
|
+
idempotencyMode: "idempotent",
|
|
130
|
+
privileged: false,
|
|
131
|
+
description: "Updates an existing saved plan with new inputs",
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
toolName: "activate_plan",
|
|
135
|
+
contractVersion: "1.0.0",
|
|
136
|
+
inputSchemaRef: "schemas/plan-management-v1.json#/activate",
|
|
137
|
+
outputSchemaRef: "schemas/plan-management-v1.json#/activate-result",
|
|
138
|
+
errorSchemaRef: "schemas/error-envelope-v1.json",
|
|
139
|
+
idempotencyMode: "idempotent",
|
|
140
|
+
privileged: false,
|
|
141
|
+
description: "Sets a plan as the user's active default plan",
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
toolName: "delete_plan",
|
|
145
|
+
contractVersion: "1.0.0",
|
|
146
|
+
inputSchemaRef: "schemas/plan-management-v1.json#/delete",
|
|
147
|
+
outputSchemaRef: "schemas/plan-management-v1.json#/delete-result",
|
|
148
|
+
errorSchemaRef: "schemas/error-envelope-v1.json",
|
|
149
|
+
idempotencyMode: "none",
|
|
150
|
+
privileged: false,
|
|
151
|
+
description: "Soft-deletes a saved plan",
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
toolName: "rename_plan",
|
|
155
|
+
contractVersion: "1.0.0",
|
|
156
|
+
inputSchemaRef: "schemas/plan-management-v1.json#/rename",
|
|
157
|
+
outputSchemaRef: "schemas/plan-management-v1.json#/rename-result",
|
|
158
|
+
errorSchemaRef: "schemas/error-envelope-v1.json",
|
|
159
|
+
idempotencyMode: "idempotent",
|
|
160
|
+
privileged: false,
|
|
161
|
+
description: "Renames an existing plan",
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
toolName: "get_plan_components",
|
|
165
|
+
contractVersion: "1.0.0",
|
|
166
|
+
inputSchemaRef: "schemas/plan-management-v1.json#/components",
|
|
167
|
+
outputSchemaRef: "schemas/plan-management-v1.json#/components-result",
|
|
168
|
+
errorSchemaRef: "schemas/error-envelope-v1.json",
|
|
169
|
+
idempotencyMode: "safe-retry",
|
|
170
|
+
privileged: false,
|
|
171
|
+
description: "Retrieves financial components attached to a saved plan",
|
|
172
|
+
},
|
|
173
|
+
// ── Forecast management contracts ───────────────────────────────────
|
|
174
|
+
{
|
|
175
|
+
toolName: "run_saved_forecast",
|
|
176
|
+
contractVersion: "1.0.0",
|
|
177
|
+
inputSchemaRef: "schemas/forecast-management-v1.json#/run",
|
|
178
|
+
outputSchemaRef: "schemas/forecast-management-v1.json#/run-result",
|
|
179
|
+
errorSchemaRef: "schemas/error-envelope-v1.json",
|
|
180
|
+
idempotencyMode: "none",
|
|
181
|
+
privileged: false,
|
|
182
|
+
description: "Triggers a forecast run for a saved plan",
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
toolName: "get_baseline_forecast",
|
|
186
|
+
contractVersion: "1.0.0",
|
|
187
|
+
inputSchemaRef: "schemas/forecast-management-v1.json#/get-baseline",
|
|
188
|
+
outputSchemaRef: "schemas/forecast-management-v1.json#/get-baseline-result",
|
|
189
|
+
errorSchemaRef: "schemas/error-envelope-v1.json",
|
|
190
|
+
idempotencyMode: "safe-retry",
|
|
191
|
+
privileged: false,
|
|
192
|
+
description: "Retrieves the most recent baseline forecast for a saved plan",
|
|
193
|
+
},
|
|
194
|
+
// ── Scenario management contracts ───────────────────────────────────
|
|
195
|
+
{
|
|
196
|
+
toolName: "save_scenario",
|
|
197
|
+
contractVersion: "1.0.0",
|
|
198
|
+
inputSchemaRef: "schemas/scenario-management-v1.json#/save",
|
|
199
|
+
outputSchemaRef: "schemas/scenario-management-v1.json#/save-result",
|
|
200
|
+
errorSchemaRef: "schemas/error-envelope-v1.json",
|
|
201
|
+
idempotencyMode: "none",
|
|
202
|
+
privileged: false,
|
|
203
|
+
description: "Persists a what-if scenario",
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
toolName: "list_scenarios",
|
|
207
|
+
contractVersion: "1.0.0",
|
|
208
|
+
inputSchemaRef: "schemas/scenario-management-v1.json#/list",
|
|
209
|
+
outputSchemaRef: "schemas/scenario-management-v1.json#/list-result",
|
|
210
|
+
errorSchemaRef: "schemas/error-envelope-v1.json",
|
|
211
|
+
idempotencyMode: "safe-retry",
|
|
212
|
+
privileged: false,
|
|
213
|
+
description: "Lists saved scenarios, optionally filtered by plan",
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
toolName: "get_scenario",
|
|
217
|
+
contractVersion: "1.0.0",
|
|
218
|
+
inputSchemaRef: "schemas/scenario-management-v1.json#/get",
|
|
219
|
+
outputSchemaRef: "schemas/scenario-management-v1.json#/get-result",
|
|
220
|
+
errorSchemaRef: "schemas/error-envelope-v1.json",
|
|
221
|
+
idempotencyMode: "safe-retry",
|
|
222
|
+
privileged: false,
|
|
223
|
+
description: "Retrieves a single saved scenario by ID",
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
toolName: "delete_scenario",
|
|
227
|
+
contractVersion: "1.0.0",
|
|
228
|
+
inputSchemaRef: "schemas/scenario-management-v1.json#/delete",
|
|
229
|
+
outputSchemaRef: "schemas/scenario-management-v1.json#/delete-result",
|
|
230
|
+
errorSchemaRef: "schemas/error-envelope-v1.json",
|
|
231
|
+
idempotencyMode: "none",
|
|
232
|
+
privileged: false,
|
|
233
|
+
description: "Deletes a saved scenario by ID",
|
|
234
|
+
},
|
|
235
|
+
// ── Comprehensive plan contract ─────────────────────────────────────
|
|
236
|
+
{
|
|
237
|
+
toolName: "comprehensive_plan",
|
|
238
|
+
contractVersion: "1.0.0",
|
|
239
|
+
inputSchemaRef: "schemas/plan-schema-v1.json#/extended",
|
|
240
|
+
outputSchemaRef: "schemas/plan-schema-v1.json#/comprehensive-result",
|
|
241
|
+
errorSchemaRef: "schemas/error-envelope-v1.json",
|
|
242
|
+
idempotencyMode: "idempotent",
|
|
243
|
+
privileged: false,
|
|
244
|
+
description: "Combined coach insights + forecast in a single call",
|
|
245
|
+
},
|
|
246
|
+
];
|
|
247
|
+
// ── Registry ─────────────────────────────────────────────────────────────
|
|
248
|
+
const contractMap = new Map();
|
|
249
|
+
for (const contract of P0_CONTRACTS) {
|
|
250
|
+
contractMap.set(contract.toolName, contract);
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Look up the contract descriptor for a given tool name.
|
|
254
|
+
*/
|
|
255
|
+
export function lookupContract(toolName) {
|
|
256
|
+
const contract = contractMap.get(toolName);
|
|
257
|
+
if (contract) {
|
|
258
|
+
return { found: true, contract };
|
|
259
|
+
}
|
|
260
|
+
return {
|
|
261
|
+
found: false,
|
|
262
|
+
toolName,
|
|
263
|
+
reason: `No contract registered for tool '${toolName}'`,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Returns all registered contract descriptors.
|
|
268
|
+
*/
|
|
269
|
+
export function getAllContracts() {
|
|
270
|
+
return P0_CONTRACTS;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Validates that a tool name has a registered contract.
|
|
274
|
+
* Returns the contract version on success, or throws on failure.
|
|
275
|
+
*/
|
|
276
|
+
export function requireContract(toolName) {
|
|
277
|
+
const lookup = lookupContract(toolName);
|
|
278
|
+
if (!lookup.found) {
|
|
279
|
+
throw new Error(`Contract validation failed: ${lookup.reason}`);
|
|
280
|
+
}
|
|
281
|
+
return lookup.contract;
|
|
282
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cloud Compute Client — sends PII-free mathematical payloads to the
|
|
3
|
+
* NestPilot cloud API for compute-intensive operations (forecast, scenario,
|
|
4
|
+
* Roth optimization, coaching).
|
|
5
|
+
*
|
|
6
|
+
* All requests include:
|
|
7
|
+
* - `Authorization: Bearer {apiKey}` for metering
|
|
8
|
+
* - `X-Client-Mode: local` to distinguish local-first traffic
|
|
9
|
+
* - 30 second timeout
|
|
10
|
+
*
|
|
11
|
+
* On network failure, the client returns cached results when available.
|
|
12
|
+
*
|
|
13
|
+
* @feature FEAT-0087
|
|
14
|
+
*/
|
|
15
|
+
export interface CloudComputeResult {
|
|
16
|
+
data?: Record<string, unknown>;
|
|
17
|
+
error?: boolean;
|
|
18
|
+
message?: string;
|
|
19
|
+
cached?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export declare class CloudComputeClient {
|
|
22
|
+
private cloudApiUrl;
|
|
23
|
+
private apiKey;
|
|
24
|
+
constructor(cloudApiUrl: string, apiKey: string);
|
|
25
|
+
/**
|
|
26
|
+
* Run a retirement forecast against the cloud engine.
|
|
27
|
+
*/
|
|
28
|
+
forecast(payload: Record<string, unknown>): Promise<CloudComputeResult>;
|
|
29
|
+
/**
|
|
30
|
+
* Run a what-if scenario comparison against the cloud engine.
|
|
31
|
+
*/
|
|
32
|
+
scenario(payload: Record<string, unknown>): Promise<CloudComputeResult>;
|
|
33
|
+
/**
|
|
34
|
+
* Run Roth conversion optimization against the cloud engine.
|
|
35
|
+
*/
|
|
36
|
+
rothOptimize(payload: Record<string, unknown>): Promise<CloudComputeResult>;
|
|
37
|
+
/**
|
|
38
|
+
* Get AI coaching guidance from the cloud engine.
|
|
39
|
+
*/
|
|
40
|
+
coach(payload: Record<string, unknown>): Promise<CloudComputeResult>;
|
|
41
|
+
/**
|
|
42
|
+
* Run forecast verification against the cloud engine.
|
|
43
|
+
*/
|
|
44
|
+
verify(payload: Record<string, unknown>): Promise<CloudComputeResult>;
|
|
45
|
+
/**
|
|
46
|
+
* Quick-calc for initial plan creation.
|
|
47
|
+
*/
|
|
48
|
+
quickCalc(payload: Record<string, unknown>): Promise<CloudComputeResult>;
|
|
49
|
+
/**
|
|
50
|
+
* Health check — verifies the cloud API is reachable.
|
|
51
|
+
*/
|
|
52
|
+
healthCheck(): Promise<boolean>;
|
|
53
|
+
private post;
|
|
54
|
+
private buildHeaders;
|
|
55
|
+
}
|