@paybond/kit 0.10.0 → 0.11.1
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 +59 -15
- package/completion-presets/catalog.json +1187 -0
- package/completion-presets/catalog.sha256 +1 -0
- package/dev/trace-ui/dashboard.html +617 -0
- package/dist/agent/adapter.d.ts +51 -0
- package/dist/agent/adapter.js +66 -0
- package/dist/agent/attach-bundle.d.ts +37 -0
- package/dist/agent/attach-bundle.js +118 -0
- package/dist/agent/authorization-cache.d.ts +22 -0
- package/dist/agent/authorization-cache.js +36 -0
- package/dist/agent/deferred-tools.d.ts +11 -0
- package/dist/agent/deferred-tools.js +62 -0
- package/dist/agent/discover.d.ts +41 -0
- package/dist/agent/discover.js +147 -0
- package/dist/agent/evidence.d.ts +9 -0
- package/dist/agent/evidence.js +28 -0
- package/dist/agent/facade.d.ts +48 -0
- package/dist/agent/facade.js +112 -0
- package/dist/agent/gateway-trace-reporter.d.ts +28 -0
- package/dist/agent/gateway-trace-reporter.js +49 -0
- package/dist/agent/generic-runner.d.ts +14 -0
- package/dist/agent/generic-runner.js +49 -0
- package/dist/agent/generic-sandbox-demo.d.ts +36 -0
- package/dist/agent/generic-sandbox-demo.js +82 -0
- package/dist/agent/guarded-agent.d.ts +49 -0
- package/dist/agent/guarded-agent.js +100 -0
- package/dist/agent/index.d.ts +13 -0
- package/dist/agent/index.js +13 -0
- package/dist/agent/instrument.d.ts +156 -0
- package/dist/agent/instrument.js +442 -0
- package/dist/agent/interceptor.d.ts +24 -0
- package/dist/agent/interceptor.js +440 -0
- package/dist/agent/lazy-context-tools.d.ts +15 -0
- package/dist/agent/lazy-context-tools.js +81 -0
- package/dist/agent/registry-file.d.ts +39 -0
- package/dist/agent/registry-file.js +219 -0
- package/dist/agent/registry.d.ts +37 -0
- package/dist/agent/registry.js +128 -0
- package/dist/agent/run.d.ts +124 -0
- package/dist/agent/run.js +301 -0
- package/dist/agent/types.d.ts +318 -0
- package/dist/agent/types.js +42 -0
- package/dist/agent-recognition.d.ts +72 -0
- package/dist/agent-recognition.js +165 -0
- package/dist/bincode-wire.d.ts +18 -0
- package/dist/bincode-wire.js +93 -0
- package/dist/claude-agents/config.d.ts +21 -0
- package/dist/claude-agents/config.js +145 -0
- package/dist/claude-agents/index.d.ts +2 -0
- package/dist/claude-agents/index.js +2 -0
- package/dist/claude-agents/sandbox-demo.d.ts +30 -0
- package/dist/claude-agents/sandbox-demo.js +91 -0
- package/dist/cli/agent/demo-loaders.d.ts +4 -0
- package/dist/cli/agent/demo-loaders.js +66 -0
- package/dist/cli/agent/env-quote.d.ts +1 -0
- package/dist/cli/agent/env-quote.js +6 -0
- package/dist/cli/agent/env-write.d.ts +8 -0
- package/dist/cli/agent/env-write.js +47 -0
- package/dist/cli/agent/paybond.d.ts +16 -0
- package/dist/cli/agent/paybond.js +55 -0
- package/dist/cli/agent/policy-file.d.ts +29 -0
- package/dist/cli/agent/policy-file.js +61 -0
- package/dist/cli/agent/production-evidence.d.ts +24 -0
- package/dist/cli/agent/production-evidence.js +98 -0
- package/dist/cli/agent/run-store.d.ts +30 -0
- package/dist/cli/agent/run-store.js +42 -0
- package/dist/cli/agent/run-trace-store.d.ts +39 -0
- package/dist/cli/agent/run-trace-store.js +143 -0
- package/dist/cli/agent-run-trace-table.d.ts +9 -0
- package/dist/cli/agent-run-trace-table.js +24 -0
- package/dist/cli/agent-sandbox-smoke-checklist.d.ts +9 -0
- package/dist/cli/agent-sandbox-smoke-checklist.js +50 -0
- package/dist/cli/command-spec.d.ts +1 -0
- package/dist/cli/command-spec.js +286 -5
- package/dist/cli/commands/agent.d.ts +16 -0
- package/dist/cli/commands/agent.js +1136 -0
- package/dist/cli/commands/dev.d.ts +7 -0
- package/dist/cli/commands/dev.js +348 -0
- package/dist/cli/commands/discovery.js +3 -3
- package/dist/cli/commands/policy.d.ts +13 -0
- package/dist/cli/commands/policy.js +769 -0
- package/dist/cli/commands/setup.d.ts +3 -0
- package/dist/cli/commands/setup.js +124 -8
- package/dist/cli/commands/workflows.js +9 -4
- package/dist/cli/config.d.ts +2 -0
- package/dist/cli/config.js +4 -2
- package/dist/cli/context.js +2 -1
- package/dist/cli/credentials.js +2 -2
- package/dist/cli/doctor-agent-middleware.d.ts +5 -0
- package/dist/cli/doctor-agent-middleware.js +49 -0
- package/dist/cli/globals.d.ts +1 -0
- package/dist/cli/globals.js +11 -1
- package/dist/cli/help.d.ts +1 -1
- package/dist/cli/help.js +35 -3
- package/dist/cli/mcp-install.js +2 -2
- package/dist/cli/mcp-policy.d.ts +3 -0
- package/dist/cli/mcp-policy.js +19 -13
- package/dist/cli/mcp-verify-config.js +9 -11
- package/dist/cli/redact.js +29 -8
- package/dist/cli/router.js +105 -2
- package/dist/cli/smoke-deep-links.d.ts +15 -0
- package/dist/cli/smoke-deep-links.js +63 -0
- package/dist/cli/telemetry.d.ts +17 -0
- package/dist/cli/telemetry.js +94 -0
- package/dist/completion-catalog-digest.d.ts +2 -0
- package/dist/completion-catalog-digest.js +2 -0
- package/dist/completion-catalog-integrity.d.ts +2 -0
- package/dist/completion-catalog-integrity.js +17 -0
- package/dist/completion-catalog.d.ts +49 -0
- package/dist/completion-catalog.js +62 -0
- package/dist/completion-contract-digest.d.ts +37 -0
- package/dist/completion-contract-digest.js +73 -0
- package/dist/completion-forbidden-fields.d.ts +5 -0
- package/dist/completion-forbidden-fields.js +26 -0
- package/dist/completion-init.d.ts +8 -0
- package/dist/completion-init.js +334 -0
- package/dist/completion-resolve.d.ts +21 -0
- package/dist/completion-resolve.js +86 -0
- package/dist/completion-validate-evidence.d.ts +24 -0
- package/dist/completion-validate-evidence.js +145 -0
- package/dist/dev/offline-gateway.d.ts +24 -0
- package/dist/dev/offline-gateway.js +102 -0
- package/dist/dev/trace-buffer.d.ts +61 -0
- package/dist/dev/trace-buffer.js +330 -0
- package/dist/dev/trace-security-headers.d.ts +11 -0
- package/dist/dev/trace-security-headers.js +16 -0
- package/dist/dev/trace-server.d.ts +8 -0
- package/dist/dev/trace-server.js +38 -0
- package/dist/dev/trace-ui.d.ts +4 -0
- package/dist/dev/trace-ui.js +25 -0
- package/dist/dev/wiremock-up.d.ts +15 -0
- package/dist/dev/wiremock-up.js +118 -0
- package/dist/doctor-completion.d.ts +17 -0
- package/dist/doctor-completion.js +428 -0
- package/dist/gateway-url.d.ts +7 -0
- package/dist/gateway-url.js +69 -0
- package/dist/index.d.ts +119 -2
- package/dist/index.js +267 -6
- package/dist/init.js +374 -57
- package/dist/langgraph/awrap-tool-call.d.ts +25 -0
- package/dist/langgraph/awrap-tool-call.js +81 -0
- package/dist/langgraph/config.d.ts +13 -0
- package/dist/langgraph/config.js +11 -0
- package/dist/langgraph/index.d.ts +4 -0
- package/dist/langgraph/index.js +4 -0
- package/dist/langgraph/sandbox-demo.d.ts +40 -0
- package/dist/langgraph/sandbox-demo.js +96 -0
- package/dist/langgraph/tool-node.d.ts +10 -0
- package/dist/langgraph/tool-node.js +38 -0
- package/dist/login.js +7 -0
- package/dist/mcp/index.d.ts +1 -0
- package/dist/mcp/index.js +1 -0
- package/dist/mcp/tool-surface.d.ts +25 -0
- package/dist/mcp/tool-surface.js +17 -0
- package/dist/mcp-capability-token-cache.d.ts +24 -0
- package/dist/mcp-capability-token-cache.js +101 -0
- package/dist/mcp-evidence-policy.d.ts +48 -0
- package/dist/mcp-evidence-policy.js +117 -0
- package/dist/mcp-policy-reload.d.ts +79 -0
- package/dist/mcp-policy-reload.js +200 -0
- package/dist/mcp-sep2828-evidence.d.ts +36 -0
- package/dist/mcp-sep2828-evidence.js +65 -0
- package/dist/mcp-server.d.ts +6 -0
- package/dist/mcp-server.js +224 -44
- package/dist/openai-agents/index.d.ts +40 -0
- package/dist/openai-agents/index.js +151 -0
- package/dist/openai-agents/sandbox-demo.d.ts +34 -0
- package/dist/openai-agents/sandbox-demo.js +118 -0
- package/dist/payee-evidence.js +2 -29
- package/dist/policy/catalog.d.ts +31 -0
- package/dist/policy/catalog.js +48 -0
- package/dist/policy/compose-utils.d.ts +3 -0
- package/dist/policy/compose-utils.js +4 -0
- package/dist/policy/compose.d.ts +20 -0
- package/dist/policy/compose.js +240 -0
- package/dist/policy/digest.d.ts +7 -0
- package/dist/policy/digest.js +75 -0
- package/dist/policy/domain.d.ts +15 -0
- package/dist/policy/domain.js +28 -0
- package/dist/policy/guardrail-spec.d.ts +17 -0
- package/dist/policy/guardrail-spec.js +140 -0
- package/dist/policy/guardrails.d.ts +48 -0
- package/dist/policy/guardrails.js +72 -0
- package/dist/policy/index.d.ts +21 -0
- package/dist/policy/index.js +21 -0
- package/dist/policy/init.d.ts +102 -0
- package/dist/policy/init.js +351 -0
- package/dist/policy/intent-spec.d.ts +52 -0
- package/dist/policy/intent-spec.js +176 -0
- package/dist/policy/json-path.d.ts +4 -0
- package/dist/policy/json-path.js +23 -0
- package/dist/policy/layers-io.d.ts +7 -0
- package/dist/policy/layers-io.js +28 -0
- package/dist/policy/load-effective.d.ts +22 -0
- package/dist/policy/load-effective.js +77 -0
- package/dist/policy/load.d.ts +85 -0
- package/dist/policy/load.js +164 -0
- package/dist/policy/merge.d.ts +29 -0
- package/dist/policy/merge.js +297 -0
- package/dist/policy/parse-text.d.ts +2 -0
- package/dist/policy/parse-text.js +126 -0
- package/dist/policy/policy-api.d.ts +45 -0
- package/dist/policy/policy-api.js +61 -0
- package/dist/policy/presets.d.ts +19 -0
- package/dist/policy/presets.js +66 -0
- package/dist/policy/registry.d.ts +7 -0
- package/dist/policy/registry.js +33 -0
- package/dist/policy/reload.d.ts +86 -0
- package/dist/policy/reload.js +233 -0
- package/dist/policy/render-yaml.d.ts +3 -0
- package/dist/policy/render-yaml.js +69 -0
- package/dist/policy/sandbox-bootstrap.d.ts +19 -0
- package/dist/policy/sandbox-bootstrap.js +66 -0
- package/dist/policy/schema.d.ts +204 -0
- package/dist/policy/schema.js +255 -0
- package/dist/policy/snapshot.d.ts +33 -0
- package/dist/policy/snapshot.js +23 -0
- package/dist/policy/validate-remote.d.ts +43 -0
- package/dist/policy/validate-remote.js +104 -0
- package/dist/policy/validate.d.ts +36 -0
- package/dist/policy/validate.js +150 -0
- package/dist/policy/watcher.d.ts +29 -0
- package/dist/policy/watcher.js +112 -0
- package/dist/principal-intent.d.ts +52 -0
- package/dist/principal-intent.js +193 -37
- package/dist/project-init.d.ts +34 -0
- package/dist/project-init.js +898 -0
- package/dist/sep2828-signature.d.ts +10 -0
- package/dist/sep2828-signature.js +134 -0
- package/dist/solutions/api.d.ts +22 -0
- package/dist/solutions/api.js +40 -0
- package/dist/solutions/catalog.d.ts +34 -0
- package/dist/solutions/catalog.js +129 -0
- package/dist/solutions/index.d.ts +2 -0
- package/dist/solutions/index.js +2 -0
- package/dist/template-init.d.ts +54 -0
- package/dist/template-init.js +203 -0
- package/dist/vercel-ai/config.d.ts +15 -0
- package/dist/vercel-ai/config.js +13 -0
- package/dist/vercel-ai/index.d.ts +4 -0
- package/dist/vercel-ai/index.js +4 -0
- package/dist/vercel-ai/sandbox-demo.d.ts +44 -0
- package/dist/vercel-ai/sandbox-demo.js +153 -0
- package/dist/vercel-ai/tool-approval.d.ts +16 -0
- package/dist/vercel-ai/tool-approval.js +41 -0
- package/dist/vercel-ai/wrap-tools.d.ts +9 -0
- package/dist/vercel-ai/wrap-tools.js +40 -0
- package/dist/x402-receipt-evidence.d.ts +29 -0
- package/dist/x402-receipt-evidence.js +97 -0
- package/dist/x402-receipt-signature.d.ts +12 -0
- package/dist/x402-receipt-signature.js +211 -0
- package/package.json +75 -3
- package/solutions/aws.json +17 -0
- package/solutions/saas.json +17 -0
- package/solutions/shopping.json +17 -0
- package/solutions/travel.json +18 -0
- package/templates/manifest.json +169 -0
- package/templates/openai-shopping-agent/.env.example +3 -0
- package/templates/openai-shopping-agent/.github/workflows/smoke.yml +20 -0
- package/templates/openai-shopping-agent/LICENSE +201 -0
- package/templates/openai-shopping-agent/README.md +29 -0
- package/templates/openai-shopping-agent/package-lock.json +1525 -0
- package/templates/openai-shopping-agent/package.json +22 -0
- package/templates/openai-shopping-agent/paybond.policy.yaml +22 -0
- package/templates/openai-shopping-agent/src/index.ts +22 -0
- package/templates/openai-shopping-agent/src/paybond.config.ts +51 -0
- package/templates/openai-shopping-agent/tsconfig.json +13 -0
- package/templates/paybond-aws-operator/.env.example +3 -0
- package/templates/paybond-aws-operator/.github/workflows/smoke.yml +20 -0
- package/templates/paybond-aws-operator/LICENSE +201 -0
- package/templates/paybond-aws-operator/README.md +29 -0
- package/templates/paybond-aws-operator/package-lock.json +151 -0
- package/templates/paybond-aws-operator/package.json +20 -0
- package/templates/paybond-aws-operator/paybond.policy.yaml +22 -0
- package/templates/paybond-aws-operator/src/index.ts +54 -0
- package/templates/paybond-aws-operator/src/paybond.config.ts +51 -0
- package/templates/paybond-aws-operator/tsconfig.json +13 -0
- package/templates/paybond-claude-agents-demo/.env.example +3 -0
- package/templates/paybond-claude-agents-demo/.github/workflows/smoke.yml +20 -0
- package/templates/paybond-claude-agents-demo/LICENSE +201 -0
- package/templates/paybond-claude-agents-demo/README.md +29 -0
- package/templates/paybond-claude-agents-demo/package-lock.json +1489 -0
- package/templates/paybond-claude-agents-demo/package.json +22 -0
- package/templates/paybond-claude-agents-demo/paybond.policy.yaml +22 -0
- package/templates/paybond-claude-agents-demo/src/index.ts +22 -0
- package/templates/paybond-claude-agents-demo/src/paybond.config.ts +51 -0
- package/templates/paybond-claude-agents-demo/tsconfig.json +13 -0
- package/templates/paybond-invoice-agent/.env.example +3 -0
- package/templates/paybond-invoice-agent/.github/workflows/smoke.yml +19 -0
- package/templates/paybond-invoice-agent/LICENSE +201 -0
- package/templates/paybond-invoice-agent/README.md +29 -0
- package/templates/paybond-invoice-agent/app.py +27 -0
- package/templates/paybond-invoice-agent/package.json +6 -0
- package/templates/paybond-invoice-agent/paybond.policy.yaml +22 -0
- package/templates/paybond-invoice-agent/paybond_config.py +45 -0
- package/templates/paybond-invoice-agent/requirements.txt +2 -0
- package/templates/paybond-mcp-coding-agent/.env.example +3 -0
- package/templates/paybond-mcp-coding-agent/.github/workflows/smoke.yml +20 -0
- package/templates/paybond-mcp-coding-agent/LICENSE +201 -0
- package/templates/paybond-mcp-coding-agent/README.md +39 -0
- package/templates/paybond-mcp-coding-agent/package-lock.json +151 -0
- package/templates/paybond-mcp-coding-agent/package.json +20 -0
- package/templates/paybond-mcp-coding-agent/paybond.policy.yaml +25 -0
- package/templates/paybond-mcp-coding-agent/src/index.ts +40 -0
- package/templates/paybond-mcp-coding-agent/src/paybond.config.ts +51 -0
- package/templates/paybond-mcp-coding-agent/tsconfig.json +13 -0
- package/templates/paybond-openai-agents-demo/.env.example +3 -0
- package/templates/paybond-openai-agents-demo/.github/workflows/smoke.yml +20 -0
- package/templates/paybond-openai-agents-demo/LICENSE +201 -0
- package/templates/paybond-openai-agents-demo/README.md +29 -0
- package/templates/paybond-openai-agents-demo/package-lock.json +1525 -0
- package/templates/paybond-openai-agents-demo/package.json +22 -0
- package/templates/paybond-openai-agents-demo/paybond.policy.yaml +22 -0
- package/templates/paybond-openai-agents-demo/src/index.ts +22 -0
- package/templates/paybond-openai-agents-demo/src/paybond.config.ts +51 -0
- package/templates/paybond-openai-agents-demo/tsconfig.json +13 -0
- package/templates/paybond-procurement-agent/.env.example +3 -0
- package/templates/paybond-procurement-agent/.github/workflows/smoke.yml +20 -0
- package/templates/paybond-procurement-agent/LICENSE +201 -0
- package/templates/paybond-procurement-agent/README.md +29 -0
- package/templates/paybond-procurement-agent/package-lock.json +151 -0
- package/templates/paybond-procurement-agent/package.json +20 -0
- package/templates/paybond-procurement-agent/paybond.policy.yaml +25 -0
- package/templates/paybond-procurement-agent/src/index.ts +54 -0
- package/templates/paybond-procurement-agent/src/paybond.config.ts +51 -0
- package/templates/paybond-procurement-agent/tsconfig.json +13 -0
- package/templates/paybond-travel-agent/.env.example +3 -0
- package/templates/paybond-travel-agent/.github/workflows/smoke.yml +20 -0
- package/templates/paybond-travel-agent/LICENSE +201 -0
- package/templates/paybond-travel-agent/README.md +29 -0
- package/templates/paybond-travel-agent/package-lock.json +444 -0
- package/templates/paybond-travel-agent/package.json +23 -0
- package/templates/paybond-travel-agent/paybond.policy.yaml +22 -0
- package/templates/paybond-travel-agent/src/index.ts +22 -0
- package/templates/paybond-travel-agent/src/paybond.config.ts +51 -0
- package/templates/paybond-travel-agent/tsconfig.json +13 -0
- package/templates/paybond-vercel-shopping-agent/.env.example +3 -0
- package/templates/paybond-vercel-shopping-agent/.github/workflows/smoke.yml +20 -0
- package/templates/paybond-vercel-shopping-agent/LICENSE +201 -0
- package/templates/paybond-vercel-shopping-agent/README.md +29 -0
- package/templates/paybond-vercel-shopping-agent/package-lock.json +265 -0
- package/templates/paybond-vercel-shopping-agent/package.json +22 -0
- package/templates/paybond-vercel-shopping-agent/paybond.policy.yaml +22 -0
- package/templates/paybond-vercel-shopping-agent/src/index.ts +22 -0
- package/templates/paybond-vercel-shopping-agent/src/paybond.config.ts +51 -0
- package/templates/paybond-vercel-shopping-agent/tsconfig.json +13 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Paybond } from "../index.js";
|
|
2
|
+
export type RunLangGraphSandboxDemoInput = {
|
|
3
|
+
paybond: Paybond;
|
|
4
|
+
operation?: string;
|
|
5
|
+
requestedSpendCents?: number;
|
|
6
|
+
evidencePreset?: string;
|
|
7
|
+
toolCallId?: string;
|
|
8
|
+
};
|
|
9
|
+
export type RunLangGraphSandboxDemoResult = {
|
|
10
|
+
bind: {
|
|
11
|
+
run_id: string;
|
|
12
|
+
tenant_id: string;
|
|
13
|
+
intent_id: string;
|
|
14
|
+
capability_token: string;
|
|
15
|
+
operation: string;
|
|
16
|
+
sandbox_lifecycle_status?: string;
|
|
17
|
+
};
|
|
18
|
+
authorization: {
|
|
19
|
+
allow: boolean;
|
|
20
|
+
audit_id?: string;
|
|
21
|
+
decision_id?: string;
|
|
22
|
+
};
|
|
23
|
+
tool_message: {
|
|
24
|
+
content: string;
|
|
25
|
+
status: string;
|
|
26
|
+
name: string;
|
|
27
|
+
tool_call_id: string;
|
|
28
|
+
};
|
|
29
|
+
evidence: {
|
|
30
|
+
submitted: boolean;
|
|
31
|
+
sandbox_lifecycle_status?: string;
|
|
32
|
+
predicate_passed?: boolean | null;
|
|
33
|
+
intent_state?: string;
|
|
34
|
+
};
|
|
35
|
+
intent_state?: string;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* No-LLM LangGraph sandbox demo: `ToolNode` + Paybond interceptor + auto-evidence.
|
|
39
|
+
*/
|
|
40
|
+
export declare function runLangGraphSandboxDemo(input: RunLangGraphSandboxDemoInput): Promise<RunLangGraphSandboxDemoResult>;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { AIMessage } from "@langchain/core/messages";
|
|
2
|
+
import { tool } from "@langchain/core/tools";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { createPaybondToolRegistry } from "../agent/registry.js";
|
|
5
|
+
import { paybondToolNode } from "./tool-node.js";
|
|
6
|
+
async function executePaidTool(args) {
|
|
7
|
+
return { status: "completed", cost_cents: args.estimatedPriceCents };
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* No-LLM LangGraph sandbox demo: `ToolNode` + Paybond interceptor + auto-evidence.
|
|
11
|
+
*/
|
|
12
|
+
export async function runLangGraphSandboxDemo(input) {
|
|
13
|
+
const operation = (input.operation ?? "paid-tool").trim();
|
|
14
|
+
const requestedSpendCents = input.requestedSpendCents ?? 100;
|
|
15
|
+
const evidencePreset = (input.evidencePreset ?? "cost_and_completion").trim();
|
|
16
|
+
const toolCallId = (input.toolCallId ?? "langgraph-demo-1").trim();
|
|
17
|
+
const registry = createPaybondToolRegistry({
|
|
18
|
+
defaultDeny: true,
|
|
19
|
+
sideEffecting: {
|
|
20
|
+
[operation]: {
|
|
21
|
+
operation,
|
|
22
|
+
evidencePreset,
|
|
23
|
+
spendCents: (args) => typeof args === "object" &&
|
|
24
|
+
args !== null &&
|
|
25
|
+
"estimatedPriceCents" in args &&
|
|
26
|
+
typeof args.estimatedPriceCents === "number"
|
|
27
|
+
? args.estimatedPriceCents
|
|
28
|
+
: requestedSpendCents,
|
|
29
|
+
evidenceMapper: (result) => {
|
|
30
|
+
const payload = result;
|
|
31
|
+
return {
|
|
32
|
+
status: payload.status,
|
|
33
|
+
cost_cents: payload.cost_cents,
|
|
34
|
+
};
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
const run = await input.paybond.agentRun.bind({
|
|
40
|
+
bootstrap: {
|
|
41
|
+
kind: "sandbox",
|
|
42
|
+
operation,
|
|
43
|
+
requestedSpendCents,
|
|
44
|
+
completionPreset: evidencePreset,
|
|
45
|
+
},
|
|
46
|
+
registry,
|
|
47
|
+
});
|
|
48
|
+
const paidTool = tool(executePaidTool, {
|
|
49
|
+
name: operation,
|
|
50
|
+
description: `Paid operation ${operation}`,
|
|
51
|
+
schema: z.object({
|
|
52
|
+
estimatedPriceCents: z.number().int().nonnegative(),
|
|
53
|
+
}),
|
|
54
|
+
});
|
|
55
|
+
const node = paybondToolNode([paidTool], run);
|
|
56
|
+
const fakeAi = new AIMessage({
|
|
57
|
+
content: "",
|
|
58
|
+
tool_calls: [
|
|
59
|
+
{
|
|
60
|
+
name: operation,
|
|
61
|
+
args: { estimatedPriceCents: requestedSpendCents },
|
|
62
|
+
id: toolCallId,
|
|
63
|
+
type: "tool_call",
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
});
|
|
67
|
+
const out = await node.invoke([fakeAi]);
|
|
68
|
+
const messages = Array.isArray(out) ? out : out.messages;
|
|
69
|
+
const toolMessage = messages[messages.length - 1];
|
|
70
|
+
const sandboxStatus = run.binding.sandbox?.sandboxLifecycleStatus;
|
|
71
|
+
return {
|
|
72
|
+
bind: {
|
|
73
|
+
run_id: run.runId,
|
|
74
|
+
tenant_id: run.tenantId,
|
|
75
|
+
intent_id: run.intentId,
|
|
76
|
+
capability_token: run.capabilityToken,
|
|
77
|
+
operation,
|
|
78
|
+
sandbox_lifecycle_status: sandboxStatus,
|
|
79
|
+
},
|
|
80
|
+
authorization: {
|
|
81
|
+
allow: toolMessage.status !== "error",
|
|
82
|
+
},
|
|
83
|
+
tool_message: {
|
|
84
|
+
content: String(toolMessage.content),
|
|
85
|
+
status: String(toolMessage.status ?? "success"),
|
|
86
|
+
name: String(toolMessage.name ?? operation),
|
|
87
|
+
tool_call_id: String(toolMessage.tool_call_id ?? toolCallId),
|
|
88
|
+
},
|
|
89
|
+
evidence: {
|
|
90
|
+
submitted: toolMessage.status !== "error",
|
|
91
|
+
sandbox_lifecycle_status: sandboxStatus,
|
|
92
|
+
predicate_passed: toolMessage.status !== "error" ? true : null,
|
|
93
|
+
},
|
|
94
|
+
intent_state: sandboxStatus,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { DynamicTool, StructuredToolInterface } from "@langchain/core/tools";
|
|
2
|
+
import type { RunnableToolLike } from "@langchain/core/runnables";
|
|
3
|
+
import { ToolNode, type ToolNodeOptions } from "@langchain/langgraph/prebuilt";
|
|
4
|
+
import type { PaybondAgentRun } from "../agent/run.js";
|
|
5
|
+
type LangGraphTool = StructuredToolInterface | DynamicTool | RunnableToolLike;
|
|
6
|
+
/**
|
|
7
|
+
* Convenience factory: `ToolNode` with Paybond spend guard + auto-evidence on every tool call.
|
|
8
|
+
*/
|
|
9
|
+
export declare function paybondToolNode(tools: LangGraphTool[], run: PaybondAgentRun, options?: ToolNodeOptions): ToolNode;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ToolNode } from "@langchain/langgraph/prebuilt";
|
|
2
|
+
import { normalizeLangGraphHookResult, paybondAwrapToolCall, } from "./awrap-tool-call.js";
|
|
3
|
+
/**
|
|
4
|
+
* `ToolNode` subclass that runs {@link paybondAwrapToolCall} before each tool invocation.
|
|
5
|
+
*
|
|
6
|
+
* LangGraph JS does not yet expose `awrapToolCall` on `ToolNode`; this wrapper provides the
|
|
7
|
+
* same interceptor boundary as Python's `ToolNode(..., awrap_tool_call=...)`.
|
|
8
|
+
*/
|
|
9
|
+
class PaybondGuardedToolNode extends ToolNode {
|
|
10
|
+
awrap;
|
|
11
|
+
constructor(tools, run, options) {
|
|
12
|
+
super(tools, options);
|
|
13
|
+
this.awrap = paybondAwrapToolCall(run);
|
|
14
|
+
}
|
|
15
|
+
async runTool(call, config, state) {
|
|
16
|
+
const request = {
|
|
17
|
+
tool_call: {
|
|
18
|
+
name: call.name,
|
|
19
|
+
id: call.id,
|
|
20
|
+
args: (call.args ?? {}),
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
const execute = async (req) => super.runTool({
|
|
24
|
+
...call,
|
|
25
|
+
name: req.tool_call.name,
|
|
26
|
+
id: req.tool_call.id ?? call.id,
|
|
27
|
+
args: req.tool_call.args ?? call.args,
|
|
28
|
+
}, config, state);
|
|
29
|
+
const result = await this.awrap(request, execute);
|
|
30
|
+
return normalizeLangGraphHookResult(call, result);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Convenience factory: `ToolNode` with Paybond spend guard + auto-evidence on every tool call.
|
|
35
|
+
*/
|
|
36
|
+
export function paybondToolNode(tools, run, options) {
|
|
37
|
+
return new PaybondGuardedToolNode(tools, run, options);
|
|
38
|
+
}
|
package/dist/login.js
CHANGED
|
@@ -4,6 +4,7 @@ import fs from "node:fs/promises";
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
6
6
|
import { runCli } from "./cli/router.js";
|
|
7
|
+
import { requireSecureGatewayUrl } from "./gateway-url.js";
|
|
7
8
|
const DEFAULT_GATEWAY = "https://api.paybond.ai";
|
|
8
9
|
const DEFAULT_ENV_FILE = ".env.local";
|
|
9
10
|
const CLIENT_ID = "paybond-kit-cli";
|
|
@@ -124,6 +125,12 @@ export function parseArgs(argv) {
|
|
|
124
125
|
if (!gateway.trim()) {
|
|
125
126
|
throw new PaybondLoginError("invalid --gateway");
|
|
126
127
|
}
|
|
128
|
+
try {
|
|
129
|
+
gateway = requireSecureGatewayUrl(gateway);
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
throw new PaybondLoginError(err instanceof Error ? err.message : String(err));
|
|
133
|
+
}
|
|
127
134
|
return { envFile, gateway, environment, noOpen, force };
|
|
128
135
|
}
|
|
129
136
|
function envKeyPattern() {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createPaybondMcpToolSurface, type PaybondMcpToolSurface, type PaybondMcpToolSurfaceOptions, } from "./tool-surface.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createPaybondMcpToolSurface, } from "./tool-surface.js";
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { PaybondAgentRun } from "../agent/run.js";
|
|
2
|
+
import { type McpInstallFormat, type McpServerEntry } from "../cli/mcp-install.js";
|
|
3
|
+
import type { McpToolPolicyConfig } from "../cli/mcp-policy.js";
|
|
4
|
+
export type PaybondMcpToolSurfaceOptions = {
|
|
5
|
+
/** Env file referenced by `PAYBOND_ENV_FILE` in the MCP host config (default `.env.local`). */
|
|
6
|
+
envFile?: string;
|
|
7
|
+
/** Override stdio server launch command (default: package-local `paybond-mcp-server`). */
|
|
8
|
+
serverCommand?: string[];
|
|
9
|
+
/** Optional MCP tool exposure policy for the stdio server process. */
|
|
10
|
+
toolPolicy?: McpToolPolicyConfig | null;
|
|
11
|
+
};
|
|
12
|
+
/** Stdio MCP host configuration derived from `paybond mcp install` patterns. */
|
|
13
|
+
export type PaybondMcpToolSurface = {
|
|
14
|
+
serverConfig: McpServerEntry;
|
|
15
|
+
/** Serialize host config as JSON (Claude Desktop, generic) or TOML (Codex). */
|
|
16
|
+
installPayload: (format?: McpInstallFormat) => string;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Framework runner helper for external MCP hosts (Claude Desktop, Codex, generic stdio).
|
|
20
|
+
*
|
|
21
|
+
* The bound {@link PaybondAgentRun} establishes tenant/intent context for your app;
|
|
22
|
+
* the returned `serverConfig` is the stdio entry coding-agent hosts consume via
|
|
23
|
+
* `PAYBOND_ENV_FILE` (never raw API keys in host config files).
|
|
24
|
+
*/
|
|
25
|
+
export declare function createPaybondMcpToolSurface(_run: PaybondAgentRun, options?: PaybondMcpToolSurfaceOptions): PaybondMcpToolSurface;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { buildMcpServerEntry, defaultMcpServerCommand, serializeMcpInstallPayload, } from "../cli/mcp-install.js";
|
|
2
|
+
/**
|
|
3
|
+
* Framework runner helper for external MCP hosts (Claude Desktop, Codex, generic stdio).
|
|
4
|
+
*
|
|
5
|
+
* The bound {@link PaybondAgentRun} establishes tenant/intent context for your app;
|
|
6
|
+
* the returned `serverConfig` is the stdio entry coding-agent hosts consume via
|
|
7
|
+
* `PAYBOND_ENV_FILE` (never raw API keys in host config files).
|
|
8
|
+
*/
|
|
9
|
+
export function createPaybondMcpToolSurface(_run, options) {
|
|
10
|
+
const envFile = options?.envFile?.trim() || ".env.local";
|
|
11
|
+
const serverCommand = options?.serverCommand ?? defaultMcpServerCommand();
|
|
12
|
+
const serverConfig = buildMcpServerEntry(envFile, serverCommand, options?.toolPolicy);
|
|
13
|
+
return {
|
|
14
|
+
serverConfig,
|
|
15
|
+
installPayload: (format = "json") => serializeMcpInstallPayload(format, serverConfig),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export declare const MCP_CAPABILITY_TOKEN_TTL_ENV = "PAYBOND_MCP_CAPABILITY_TOKEN_TTL_SEC";
|
|
2
|
+
export declare const MCP_CAPABILITY_TOKEN_CACHE_MAX_ENV = "PAYBOND_MCP_CAPABILITY_TOKEN_CACHE_MAX";
|
|
3
|
+
export declare const DEFAULT_MCP_CAPABILITY_TOKEN_TTL_SEC = 900;
|
|
4
|
+
export declare const DEFAULT_MCP_CAPABILITY_TOKEN_CACHE_MAX = 64;
|
|
5
|
+
/** MCP tools that mint or return funded intent capability tokens from Harbor. */
|
|
6
|
+
export declare const MCP_CAPABILITY_TOKEN_STORE_TOOLS: readonly ["paybond_bootstrap_sandbox_guardrail", "paybond_create_intent", "paybond_create_spend_intent", "paybond_fund_intent"];
|
|
7
|
+
export type McpCapabilityTokenStoreTool = (typeof MCP_CAPABILITY_TOKEN_STORE_TOOLS)[number];
|
|
8
|
+
/** Return true when an MCP tool response may populate the runtime token cache. */
|
|
9
|
+
export declare function mcpToolStoresCapabilityToken(toolName: string): boolean;
|
|
10
|
+
export type McpCapabilityTokenCacheConfig = {
|
|
11
|
+
ttlSec: number;
|
|
12
|
+
maxEntries: number;
|
|
13
|
+
};
|
|
14
|
+
export declare class McpCapabilityTokenCache {
|
|
15
|
+
private readonly ttlSec;
|
|
16
|
+
private readonly maxEntries;
|
|
17
|
+
private readonly entries;
|
|
18
|
+
constructor(config?: McpCapabilityTokenCacheConfig);
|
|
19
|
+
store(intentId: string, token: string): void;
|
|
20
|
+
resolve(intentId: string): string | undefined;
|
|
21
|
+
private evictExpired;
|
|
22
|
+
private evictOverflow;
|
|
23
|
+
}
|
|
24
|
+
export declare function parseMcpCapabilityTokenCacheConfig(env?: Record<string, string | undefined>): McpCapabilityTokenCacheConfig;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
export const MCP_CAPABILITY_TOKEN_TTL_ENV = "PAYBOND_MCP_CAPABILITY_TOKEN_TTL_SEC";
|
|
2
|
+
export const MCP_CAPABILITY_TOKEN_CACHE_MAX_ENV = "PAYBOND_MCP_CAPABILITY_TOKEN_CACHE_MAX";
|
|
3
|
+
export const DEFAULT_MCP_CAPABILITY_TOKEN_TTL_SEC = 900;
|
|
4
|
+
export const DEFAULT_MCP_CAPABILITY_TOKEN_CACHE_MAX = 64;
|
|
5
|
+
const MIN_MCP_CAPABILITY_TOKEN_TTL_SEC = 60;
|
|
6
|
+
const MAX_MCP_CAPABILITY_TOKEN_TTL_SEC = 86_400;
|
|
7
|
+
const MIN_MCP_CAPABILITY_TOKEN_CACHE_MAX = 1;
|
|
8
|
+
const MAX_MCP_CAPABILITY_TOKEN_CACHE_MAX = 512;
|
|
9
|
+
/** MCP tools that mint or return funded intent capability tokens from Harbor. */
|
|
10
|
+
export const MCP_CAPABILITY_TOKEN_STORE_TOOLS = [
|
|
11
|
+
"paybond_bootstrap_sandbox_guardrail",
|
|
12
|
+
"paybond_create_intent",
|
|
13
|
+
"paybond_create_spend_intent",
|
|
14
|
+
"paybond_fund_intent",
|
|
15
|
+
];
|
|
16
|
+
const MCP_CAPABILITY_TOKEN_STORE_TOOL_SET = new Set(MCP_CAPABILITY_TOKEN_STORE_TOOLS);
|
|
17
|
+
/** Return true when an MCP tool response may populate the runtime token cache. */
|
|
18
|
+
export function mcpToolStoresCapabilityToken(toolName) {
|
|
19
|
+
return MCP_CAPABILITY_TOKEN_STORE_TOOL_SET.has(toolName.trim());
|
|
20
|
+
}
|
|
21
|
+
export class McpCapabilityTokenCache {
|
|
22
|
+
ttlSec;
|
|
23
|
+
maxEntries;
|
|
24
|
+
entries = new Map();
|
|
25
|
+
constructor(config) {
|
|
26
|
+
this.ttlSec = config?.ttlSec ?? DEFAULT_MCP_CAPABILITY_TOKEN_TTL_SEC;
|
|
27
|
+
this.maxEntries = config?.maxEntries ?? DEFAULT_MCP_CAPABILITY_TOKEN_CACHE_MAX;
|
|
28
|
+
}
|
|
29
|
+
store(intentId, token) {
|
|
30
|
+
const key = intentId.trim();
|
|
31
|
+
const value = token.trim();
|
|
32
|
+
if (!key || !value) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
this.evictExpired();
|
|
36
|
+
this.entries.set(key, { token: value, storedAtMs: Date.now() });
|
|
37
|
+
this.evictOverflow();
|
|
38
|
+
}
|
|
39
|
+
resolve(intentId) {
|
|
40
|
+
this.evictExpired();
|
|
41
|
+
const key = String(intentId).trim();
|
|
42
|
+
const entry = this.entries.get(key);
|
|
43
|
+
if (!entry) {
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
if (Date.now() - entry.storedAtMs > this.ttlSec * 1000) {
|
|
47
|
+
this.entries.delete(key);
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
this.entries.delete(key);
|
|
51
|
+
this.entries.set(key, entry);
|
|
52
|
+
return entry.token;
|
|
53
|
+
}
|
|
54
|
+
evictExpired() {
|
|
55
|
+
const now = Date.now();
|
|
56
|
+
const ttlMs = this.ttlSec * 1000;
|
|
57
|
+
for (const [key, entry] of this.entries) {
|
|
58
|
+
if (now - entry.storedAtMs > ttlMs) {
|
|
59
|
+
this.entries.delete(key);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
evictOverflow() {
|
|
64
|
+
while (this.entries.size > this.maxEntries) {
|
|
65
|
+
const oldest = this.entries.keys().next().value;
|
|
66
|
+
if (oldest === undefined) {
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
this.entries.delete(oldest);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
export function parseMcpCapabilityTokenCacheConfig(env = process.env) {
|
|
74
|
+
const ttlRaw = env[MCP_CAPABILITY_TOKEN_TTL_ENV]?.trim();
|
|
75
|
+
const maxRaw = env[MCP_CAPABILITY_TOKEN_CACHE_MAX_ENV]?.trim();
|
|
76
|
+
let ttlSec = DEFAULT_MCP_CAPABILITY_TOKEN_TTL_SEC;
|
|
77
|
+
if (ttlRaw) {
|
|
78
|
+
const parsed = Number.parseFloat(ttlRaw);
|
|
79
|
+
if (!Number.isFinite(parsed)) {
|
|
80
|
+
throw new Error(`invalid ${MCP_CAPABILITY_TOKEN_TTL_ENV} (expected a number of seconds)`);
|
|
81
|
+
}
|
|
82
|
+
if (parsed < MIN_MCP_CAPABILITY_TOKEN_TTL_SEC ||
|
|
83
|
+
parsed > MAX_MCP_CAPABILITY_TOKEN_TTL_SEC) {
|
|
84
|
+
throw new Error(`invalid ${MCP_CAPABILITY_TOKEN_TTL_ENV} (expected ${MIN_MCP_CAPABILITY_TOKEN_TTL_SEC}-${MAX_MCP_CAPABILITY_TOKEN_TTL_SEC} seconds)`);
|
|
85
|
+
}
|
|
86
|
+
ttlSec = parsed;
|
|
87
|
+
}
|
|
88
|
+
let maxEntries = DEFAULT_MCP_CAPABILITY_TOKEN_CACHE_MAX;
|
|
89
|
+
if (maxRaw) {
|
|
90
|
+
const parsed = Number.parseInt(maxRaw, 10);
|
|
91
|
+
if (!Number.isInteger(parsed)) {
|
|
92
|
+
throw new Error(`invalid ${MCP_CAPABILITY_TOKEN_CACHE_MAX_ENV} (expected an integer)`);
|
|
93
|
+
}
|
|
94
|
+
if (parsed < MIN_MCP_CAPABILITY_TOKEN_CACHE_MAX ||
|
|
95
|
+
parsed > MAX_MCP_CAPABILITY_TOKEN_CACHE_MAX) {
|
|
96
|
+
throw new Error(`invalid ${MCP_CAPABILITY_TOKEN_CACHE_MAX_ENV} (expected ${MIN_MCP_CAPABILITY_TOKEN_CACHE_MAX}-${MAX_MCP_CAPABILITY_TOKEN_CACHE_MAX})`);
|
|
97
|
+
}
|
|
98
|
+
maxEntries = parsed;
|
|
99
|
+
}
|
|
100
|
+
return { ttlSec, maxEntries };
|
|
101
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { type CompletionEvidenceValidationReport } from "./completion-validate-evidence.js";
|
|
2
|
+
export type McpEvidencePolicy = "strict" | "off";
|
|
3
|
+
export declare const MCP_EVIDENCE_POLICY_ENV = "PAYBOND_MCP_EVIDENCE_POLICY";
|
|
4
|
+
export declare const DEFAULT_MCP_EVIDENCE_POLICY: McpEvidencePolicy;
|
|
5
|
+
export declare const EVIDENCE_SUBMIT_TOOL_NAMES: Set<string>;
|
|
6
|
+
export declare class McpEvidencePolicyError extends Error {
|
|
7
|
+
constructor(message: string);
|
|
8
|
+
}
|
|
9
|
+
export declare function parseMcpEvidencePolicy(raw: string | undefined): McpEvidencePolicy;
|
|
10
|
+
export declare function completionEvidenceValidationOk(report: CompletionEvidenceValidationReport): boolean;
|
|
11
|
+
export declare function evidenceValidationGateKey(input: {
|
|
12
|
+
presetId: string;
|
|
13
|
+
vendorPayload?: Record<string, unknown>;
|
|
14
|
+
canonicalPayload?: Record<string, unknown>;
|
|
15
|
+
}): string;
|
|
16
|
+
export declare function extractHarborEvidenceValidationInput(body: Record<string, unknown>, completionPresetId?: string): {
|
|
17
|
+
presetId: string;
|
|
18
|
+
vendorPayload?: Record<string, unknown>;
|
|
19
|
+
canonicalPayload?: Record<string, unknown>;
|
|
20
|
+
};
|
|
21
|
+
export declare function extractSandboxGuardrailValidationInput(input: {
|
|
22
|
+
payload?: Record<string, unknown>;
|
|
23
|
+
completionPresetId?: string;
|
|
24
|
+
}): {
|
|
25
|
+
presetId: string;
|
|
26
|
+
vendorPayload?: Record<string, unknown>;
|
|
27
|
+
canonicalPayload?: Record<string, unknown>;
|
|
28
|
+
};
|
|
29
|
+
export declare class McpEvidenceValidationGate {
|
|
30
|
+
readonly policy: McpEvidencePolicy;
|
|
31
|
+
private readonly passes;
|
|
32
|
+
constructor(policy?: McpEvidencePolicy);
|
|
33
|
+
recordPass(gateKey: string): void;
|
|
34
|
+
hasPass(gateKey: string): boolean;
|
|
35
|
+
requirePass(input: {
|
|
36
|
+
presetId: string;
|
|
37
|
+
vendorPayload?: Record<string, unknown>;
|
|
38
|
+
canonicalPayload?: Record<string, unknown>;
|
|
39
|
+
}): void;
|
|
40
|
+
validateAndRecord(input: {
|
|
41
|
+
presetId: string;
|
|
42
|
+
vendorPayload?: Record<string, unknown>;
|
|
43
|
+
canonicalPayload?: Record<string, unknown>;
|
|
44
|
+
frozenVendorApiVersion?: string;
|
|
45
|
+
frozenVendorSchemaDigestHex?: string;
|
|
46
|
+
frozenCanonicalSchemaDigestHex?: string;
|
|
47
|
+
}): CompletionEvidenceValidationReport;
|
|
48
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { validateCompletionEvidence, } from "./completion-validate-evidence.js";
|
|
2
|
+
import { jsonValueDigest } from "./json-digest.js";
|
|
3
|
+
export const MCP_EVIDENCE_POLICY_ENV = "PAYBOND_MCP_EVIDENCE_POLICY";
|
|
4
|
+
export const DEFAULT_MCP_EVIDENCE_POLICY = "strict";
|
|
5
|
+
export const EVIDENCE_SUBMIT_TOOL_NAMES = new Set([
|
|
6
|
+
"paybond_submit_evidence",
|
|
7
|
+
"paybond_submit_spend_evidence",
|
|
8
|
+
"paybond_submit_sandbox_guardrail_evidence",
|
|
9
|
+
]);
|
|
10
|
+
export class McpEvidencePolicyError extends Error {
|
|
11
|
+
constructor(message) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.name = "McpEvidencePolicyError";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export function parseMcpEvidencePolicy(raw) {
|
|
17
|
+
const value = (raw ?? "").trim().toLowerCase();
|
|
18
|
+
if (!value) {
|
|
19
|
+
return DEFAULT_MCP_EVIDENCE_POLICY;
|
|
20
|
+
}
|
|
21
|
+
if (value === "strict" || value === "off") {
|
|
22
|
+
return value;
|
|
23
|
+
}
|
|
24
|
+
throw new Error("invalid PAYBOND_MCP_EVIDENCE_POLICY (expected strict|off)");
|
|
25
|
+
}
|
|
26
|
+
export function completionEvidenceValidationOk(report) {
|
|
27
|
+
return report.drift_kinds.length === 0;
|
|
28
|
+
}
|
|
29
|
+
export function evidenceValidationGateKey(input) {
|
|
30
|
+
const presetId = input.presetId.trim();
|
|
31
|
+
if (!presetId) {
|
|
32
|
+
throw new Error("completion preset id is required for evidence validation");
|
|
33
|
+
}
|
|
34
|
+
const digest = jsonValueDigest({
|
|
35
|
+
preset_id: presetId,
|
|
36
|
+
vendor_payload: input.vendorPayload,
|
|
37
|
+
canonical_payload: input.canonicalPayload,
|
|
38
|
+
});
|
|
39
|
+
return Buffer.from(digest).toString("hex");
|
|
40
|
+
}
|
|
41
|
+
export function extractHarborEvidenceValidationInput(body, completionPresetId) {
|
|
42
|
+
let presetId = (completionPresetId ?? "").trim();
|
|
43
|
+
if (!presetId) {
|
|
44
|
+
for (const key of ["completion_preset_id", "completion_preset"]) {
|
|
45
|
+
const raw = body[key];
|
|
46
|
+
if (typeof raw === "string" && raw.trim()) {
|
|
47
|
+
presetId = raw.trim();
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const vendorRaw = body.vendor_payload;
|
|
53
|
+
const vendorPayload = vendorRaw !== undefined && typeof vendorRaw === "object" && vendorRaw !== null && !Array.isArray(vendorRaw)
|
|
54
|
+
? vendorRaw
|
|
55
|
+
: undefined;
|
|
56
|
+
const payloadRaw = body.payload;
|
|
57
|
+
const canonicalPayload = payloadRaw !== undefined && typeof payloadRaw === "object" && payloadRaw !== null && !Array.isArray(payloadRaw)
|
|
58
|
+
? payloadRaw
|
|
59
|
+
: undefined;
|
|
60
|
+
return { presetId, vendorPayload, canonicalPayload };
|
|
61
|
+
}
|
|
62
|
+
export function extractSandboxGuardrailValidationInput(input) {
|
|
63
|
+
const presetId = (input.completionPresetId ?? "").trim();
|
|
64
|
+
return {
|
|
65
|
+
presetId,
|
|
66
|
+
vendorPayload: input.payload,
|
|
67
|
+
canonicalPayload: input.payload,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
export class McpEvidenceValidationGate {
|
|
71
|
+
policy;
|
|
72
|
+
passes = new Set();
|
|
73
|
+
constructor(policy = DEFAULT_MCP_EVIDENCE_POLICY) {
|
|
74
|
+
this.policy = policy;
|
|
75
|
+
}
|
|
76
|
+
recordPass(gateKey) {
|
|
77
|
+
this.passes.add(gateKey);
|
|
78
|
+
}
|
|
79
|
+
hasPass(gateKey) {
|
|
80
|
+
return this.passes.has(gateKey);
|
|
81
|
+
}
|
|
82
|
+
requirePass(input) {
|
|
83
|
+
if (this.policy === "off") {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const presetId = input.presetId.trim();
|
|
87
|
+
if (!presetId) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const gateKey = evidenceValidationGateKey({
|
|
91
|
+
presetId,
|
|
92
|
+
vendorPayload: input.vendorPayload,
|
|
93
|
+
canonicalPayload: input.canonicalPayload,
|
|
94
|
+
});
|
|
95
|
+
if (!this.hasPass(gateKey)) {
|
|
96
|
+
throw new McpEvidencePolicyError("completion evidence was not pre-validated; call paybond_validate_completion_evidence with the same preset and payload before submit (Harbor remains authoritative at submit time)");
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
validateAndRecord(input) {
|
|
100
|
+
const report = validateCompletionEvidence({
|
|
101
|
+
presetId: input.presetId,
|
|
102
|
+
vendorPayload: input.vendorPayload,
|
|
103
|
+
canonicalPayload: input.canonicalPayload,
|
|
104
|
+
frozenVendorApiVersion: input.frozenVendorApiVersion,
|
|
105
|
+
frozenVendorSchemaDigestHex: input.frozenVendorSchemaDigestHex,
|
|
106
|
+
frozenCanonicalSchemaDigestHex: input.frozenCanonicalSchemaDigestHex,
|
|
107
|
+
});
|
|
108
|
+
if (completionEvidenceValidationOk(report)) {
|
|
109
|
+
this.recordPass(evidenceValidationGateKey({
|
|
110
|
+
presetId: input.presetId,
|
|
111
|
+
vendorPayload: input.vendorPayload,
|
|
112
|
+
canonicalPayload: input.canonicalPayload,
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
115
|
+
return report;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { type PaybondPolicyReloadOptions, type PaybondPolicyReloadResult, type PolicyReloadHandle } from "./policy/reload.js";
|
|
2
|
+
import type { PaybondPolicySnapshot } from "./policy/snapshot.js";
|
|
3
|
+
import { type PolicyEffectiveResolveClient } from "./policy/load-effective.js";
|
|
4
|
+
import { type PolicyRemoteValidateClient } from "./policy/validate-remote.js";
|
|
5
|
+
export declare const MCP_POLICY_FILE_ENV = "PAYBOND_POLICY_FILE";
|
|
6
|
+
export declare const MCP_POLICY_RELOAD_ENV = "PAYBOND_POLICY_RELOAD";
|
|
7
|
+
export declare const MCP_POLICY_RELOAD_ALLOW_LOOSEN_ENV = "PAYBOND_POLICY_RELOAD_ALLOW_LOOSEN";
|
|
8
|
+
export type McpPolicyReloadMode = "off" | "watch" | "poll";
|
|
9
|
+
export type McpPolicyReloadConfig = {
|
|
10
|
+
policyFile: string;
|
|
11
|
+
reloadMode: McpPolicyReloadMode;
|
|
12
|
+
allowLoosen?: boolean;
|
|
13
|
+
watchDebounceMs?: number;
|
|
14
|
+
pollIntervalMs?: number;
|
|
15
|
+
};
|
|
16
|
+
export type McpPolicySpendGateInput = {
|
|
17
|
+
toolName?: string;
|
|
18
|
+
operation: string;
|
|
19
|
+
allowedTools: readonly string[];
|
|
20
|
+
arguments?: unknown;
|
|
21
|
+
requestedSpendCents?: number;
|
|
22
|
+
};
|
|
23
|
+
export type McpPolicySpendGateResult = {
|
|
24
|
+
operation: string;
|
|
25
|
+
requestedSpendCents: number;
|
|
26
|
+
policyDigest?: string;
|
|
27
|
+
};
|
|
28
|
+
export type McpPolicyReloadStatus = {
|
|
29
|
+
enabled: boolean;
|
|
30
|
+
policy_file?: string;
|
|
31
|
+
policy_digest?: string;
|
|
32
|
+
policy_loaded_at?: string;
|
|
33
|
+
reload_mode: McpPolicyReloadMode;
|
|
34
|
+
last_reload_at?: string;
|
|
35
|
+
last_reload_error?: string;
|
|
36
|
+
};
|
|
37
|
+
export declare class McpPolicyReloadError extends Error {
|
|
38
|
+
constructor(message: string);
|
|
39
|
+
}
|
|
40
|
+
/** Gateway adapter for MCP poll reload with remote validation. */
|
|
41
|
+
export type McpPolicyGatewayClient = PolicyRemoteValidateClient & PolicyEffectiveResolveClient;
|
|
42
|
+
export declare function createMcpPolicyGatewayAdapter(client: {
|
|
43
|
+
postJSON(path: string, payload: Record<string, unknown>, extraHeaders?: Record<string, string>): Promise<Record<string, unknown>>;
|
|
44
|
+
}): McpPolicyGatewayClient;
|
|
45
|
+
export declare function parseMcpPolicyReloadMode(raw: string | undefined): McpPolicyReloadMode;
|
|
46
|
+
export declare function parseMcpPolicyReloadConfig(env: Record<string, string | undefined>): McpPolicyReloadConfig | null;
|
|
47
|
+
/**
|
|
48
|
+
* Long-lived MCP policy gate: versioned snapshot, safe reload, and spend-gate registry checks.
|
|
49
|
+
*/
|
|
50
|
+
export declare class McpPolicyReloadGate implements PolicyReloadHandle {
|
|
51
|
+
readonly config: McpPolicyReloadConfig;
|
|
52
|
+
private _snapshot?;
|
|
53
|
+
private _inFlightCount;
|
|
54
|
+
private _lastAllowedTools;
|
|
55
|
+
private _controller?;
|
|
56
|
+
private _reloadDefaults;
|
|
57
|
+
readonly policyFilePath: string;
|
|
58
|
+
lastReloadAt?: string;
|
|
59
|
+
lastReloadError?: string;
|
|
60
|
+
private constructor();
|
|
61
|
+
static open(config: McpPolicyReloadConfig, options?: {
|
|
62
|
+
gateway?: McpPolicyGatewayClient;
|
|
63
|
+
}): Promise<McpPolicyReloadGate>;
|
|
64
|
+
get currentSnapshot(): PaybondPolicySnapshot | undefined;
|
|
65
|
+
get policyDigest(): string | undefined;
|
|
66
|
+
get inFlightCount(): number;
|
|
67
|
+
get registry(): import("./index.js").PaybondToolRegistry;
|
|
68
|
+
applyPolicySnapshot(snapshot: PaybondPolicySnapshot): void;
|
|
69
|
+
reloadPolicy(options?: PaybondPolicyReloadOptions): Promise<PaybondPolicyReloadResult>;
|
|
70
|
+
beginToolCall(): void;
|
|
71
|
+
endToolCall(): void;
|
|
72
|
+
/**
|
|
73
|
+
* Enforce paybond.policy.yaml registry rules before Harbor spend authorization.
|
|
74
|
+
* Pins policy_digest for the current MCP tool invocation.
|
|
75
|
+
*/
|
|
76
|
+
assertSpendGate(input: McpPolicySpendGateInput): McpPolicySpendGateResult;
|
|
77
|
+
status(): McpPolicyReloadStatus;
|
|
78
|
+
stop(): void;
|
|
79
|
+
}
|