@decidio/sdk 0.7.0 → 0.8.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 +1 -1
- package/dist/adapters/_gate.d.ts +20 -0
- package/dist/adapters/_gate.js +16 -1
- package/dist/cli.d.ts +50 -0
- package/dist/cli.js +1707 -10
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -1
- package/dist/resume.d.ts +12 -2
- package/dist/resume.js +12 -0
- package/dist/signing.d.ts +5 -0
- package/dist/signing.js +3 -0
- package/openapi.yaml +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export type { PendingAction, PendingStore, ResumeController, ResumeOutcome, Appr
|
|
|
6
6
|
export { guard, Guard } from "./guard.js";
|
|
7
7
|
export type { GuardFacadeConfig, ProtectOptions } from "./guard.js";
|
|
8
8
|
export { DecidioHttpError, decisionIdProblem } from "./errors.js";
|
|
9
|
-
export { generateKeypair, didFromPrivateKey, signBoundProof, signConfirm, signExecutionReport, verifyExecutionReport, resultDigest, assertSafeTransport, carriesCredential, bindingMaterial, requestCommitment, idempotencyKey, committedRequestJson } from "./signing.js";
|
|
9
|
+
export { generateKeypair, didFromPrivateKey, signBoundProof, signConfirm, signExecutionReport, verifyExecutionReport, resultDigest, assertSafeTransport, carriesCredential, bindingMaterial, boundScope, requestCommitment, idempotencyKey, committedRequestJson } from "./signing.js";
|
|
10
10
|
export type { BindingMaterial, CommittedRequest } from "./signing.js";
|
|
11
11
|
export { canonicalize, canonicalizeArgs, canonicalJson, DecidioUnsafeArgumentsError } from "./canonical.js";
|
|
12
12
|
export type { JsonValue, JsonPrimitive } from "./canonical.js";
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ export { DecidioSuspendedError, DecidioDeniedError, DecidioRecoveryUnavailableEr
|
|
|
6
6
|
export { guard, Guard } from "./guard.js";
|
|
7
7
|
export { DecidioHttpError, decisionIdProblem } from "./errors.js";
|
|
8
8
|
import { DecidioHttpError, decisionIdProblem } from "./errors.js";
|
|
9
|
-
export { generateKeypair, didFromPrivateKey, signBoundProof, signConfirm, signExecutionReport, verifyExecutionReport, resultDigest, assertSafeTransport, carriesCredential, bindingMaterial, requestCommitment, idempotencyKey, committedRequestJson } from "./signing.js";
|
|
9
|
+
export { generateKeypair, didFromPrivateKey, signBoundProof, signConfirm, signExecutionReport, verifyExecutionReport, resultDigest, assertSafeTransport, carriesCredential, bindingMaterial, boundScope, requestCommitment, idempotencyKey, committedRequestJson } from "./signing.js";
|
|
10
10
|
export { canonicalize, canonicalizeArgs, canonicalJson, DecidioUnsafeArgumentsError } from "./canonical.js";
|
|
11
11
|
export { readConfirmResponse, buildConfirmBody, describeTierGap, EVIDENCE_TIERS } from "./evidence.js";
|
|
12
12
|
export class DecidioBlockedError extends Error {
|
|
@@ -55,6 +55,8 @@ export function approvalRefusal(check) {
|
|
|
55
55
|
case "commitment_missing": return new DecidioApprovalUnverifiedError(id, "commitment_missing", check.reason ?? "Decidio answered without the request commitment this SDK sent");
|
|
56
56
|
case "unverifiable": return new DecidioApprovalUnverifiedError(id, "unverifiable", check.reason ?? "the approval could not be tied to this request");
|
|
57
57
|
case "pending": return new DecidioBlockedError(`not approved - ${check.reason ?? `Decidio records ${id} as pending`}`, id);
|
|
58
|
+
case "spent": return new DecidioBlockedError(`not executed - ${check.reason ?? `the approval for ${id} is already spent`}`, id);
|
|
59
|
+
case "expired": return new DecidioBlockedError(`not executed - ${check.reason ?? `the approval for ${id} has expired`}`, id);
|
|
58
60
|
default: return new DecidioBlockedError(check.reason ?? `not approved (Decidio answered ${JSON.stringify(check.state)})`, id);
|
|
59
61
|
}
|
|
60
62
|
}
|
package/dist/resume.d.ts
CHANGED
|
@@ -701,11 +701,18 @@ export declare function verifyResumeSignature(secret: string, body: string, head
|
|
|
701
701
|
* called it: the claim was what kept anyone from noticing the disagreement. */
|
|
702
702
|
export declare function assertConfirmRecorded(body: any, decisionId: string, signed: boolean): string;
|
|
703
703
|
/** What GET /agent/status answers. `requestCommitment` (0.7.0) is the commitment the decision was
|
|
704
|
-
* authorized with, or null for a decision whose request was never bound.
|
|
704
|
+
* authorized with, or null for a decision whose request was never bound. `spent` and `grantExpiresAt` (0.8.0,
|
|
705
|
+
* mini-approvals): the grant is ONE-TIME - `spent` once an execution was recorded on it, `grantExpiresAt` when
|
|
706
|
+
* it lapses (the seal's time plus the gate's TTL) for a granted decision, null otherwise. A gate that predates
|
|
707
|
+
* them answers neither. */
|
|
705
708
|
export interface DecisionStatus {
|
|
706
709
|
state: string;
|
|
710
|
+
decisionId?: string;
|
|
711
|
+
receiptId?: string | null;
|
|
707
712
|
reason?: string | null;
|
|
708
713
|
requestCommitment?: string | null;
|
|
714
|
+
spent?: boolean;
|
|
715
|
+
grantExpiresAt?: string | null;
|
|
709
716
|
}
|
|
710
717
|
type StatusConfig = {
|
|
711
718
|
apiUrl: string;
|
|
@@ -717,11 +724,14 @@ type StatusConfig = {
|
|
|
717
724
|
/** Why an approval check did not pass.
|
|
718
725
|
* pending / unrecognized_state — Decidio records no approval (yet): nothing may run.
|
|
719
726
|
* rejected / blocked — Decidio's final answer is no.
|
|
727
|
+
* spent — the approval was already used: an execution is recorded on it (one approval
|
|
728
|
+
* covers one action, once) - ask again.
|
|
729
|
+
* expired — the approval lapsed (its grant's time passed) before anything ran - ask again.
|
|
720
730
|
* request_changed — the approval is for a DIFFERENT request than the one about to run.
|
|
721
731
|
* commitment_missing — this SDK bound the request, the gate answered without a commitment.
|
|
722
732
|
* unverifiable — Decidio holds a commitment this process cannot recompute (no or
|
|
723
733
|
* unreadable key material), or answered a malformed one. */
|
|
724
|
-
export type ApprovalCheckCode = "pending" | "unrecognized_state" | "rejected" | "blocked" | "request_changed" | "commitment_missing" | "unverifiable";
|
|
734
|
+
export type ApprovalCheckCode = "pending" | "unrecognized_state" | "rejected" | "blocked" | "spent" | "expired" | "request_changed" | "commitment_missing" | "unverifiable";
|
|
725
735
|
/** The outcome of the one check. Plain JSON on purpose: an engine that runs it as an activity or a
|
|
726
736
|
* step (Temporal, Inngest) memoizes it across its serialization boundary. */
|
|
727
737
|
export interface ApprovalCheck {
|
package/dist/resume.js
CHANGED
|
@@ -839,6 +839,18 @@ export async function checkApproval(cfg, decisionId, request, opts = {}) {
|
|
|
839
839
|
return no("pending", `Decidio records decision ${decisionId} as pending - no human has approved it`);
|
|
840
840
|
if (state !== "approved" && state !== "auto_approved")
|
|
841
841
|
return no("unrecognized_state", `Decidio answered state ${JSON.stringify(st?.state ?? null)} for decision ${decisionId}, which is not an approval this SDK recognises (an answer it does not understand is never permission)`);
|
|
842
|
+
if (st?.spent === true)
|
|
843
|
+
return no("spent", `decision ${decisionId} was approved once and that approval is already spent (an execution is recorded on it) - ask again for a fresh approval; nothing was executed`);
|
|
844
|
+
if (typeof st?.grantExpiresAt === "string") {
|
|
845
|
+
const until = Date.parse(st.grantExpiresAt);
|
|
846
|
+
if (!Number.isFinite(until))
|
|
847
|
+
return no("unverifiable", `Decidio answered a malformed grant expiry for decision ${decisionId} (${JSON.stringify(st.grantExpiresAt)}), so the approval cannot be known to be in force`);
|
|
848
|
+
if (until <= Date.now())
|
|
849
|
+
return no("expired", `decision ${decisionId}'s approval expired at ${st.grantExpiresAt} before anything ran - ask again for a fresh approval; nothing was executed`);
|
|
850
|
+
}
|
|
851
|
+
else if (typeof st?.spent === "boolean" && st?.grantExpiresAt === null) {
|
|
852
|
+
return no("expired", `decision ${decisionId} is approved but Decidio names no expiry for its grant (its age is unknown) - ask again for a fresh approval; nothing was executed`);
|
|
853
|
+
}
|
|
842
854
|
const server = st?.requestCommitment;
|
|
843
855
|
if (server !== undefined && server !== null) {
|
|
844
856
|
if (typeof server !== "string" || !/^[0-9a-f]{64}$/.test(server))
|
package/dist/signing.d.ts
CHANGED
|
@@ -126,6 +126,11 @@ export declare function requestCommitment(material: BindingMaterial, request: Co
|
|
|
126
126
|
/** lowercase-hex idempotency key over an execution identity (e.g. LangGraph's thread + task +
|
|
127
127
|
* commitment), keyed so the host's thread ids never reach Decidio in the clear. */
|
|
128
128
|
export declare function idempotencyKey(material: BindingMaterial, identity: Record<string, JsonValue>): string;
|
|
129
|
+
/** The Claude Code hook's request scope: `cmd-` + 16 hex of a KEYED digest over the command text and its subject
|
|
130
|
+
* (chat approvals follow-up, invariant-guard 2026-10-15). The text may carry a credential the display redacts; an
|
|
131
|
+
* unkeyed digest sealed beside the redacted text would be an offline oracle for a weak password. Keyed under its own
|
|
132
|
+
* domain, so it is deterministic for this agent and nothing to anyone without the key material. */
|
|
133
|
+
export declare function boundScope(material: BindingMaterial, text: string): string;
|
|
129
134
|
/** A signed, DOMAIN-SEPARATED, versioned attestation that THIS agent reported THIS captured
|
|
130
135
|
* response for THIS decision. Distinct from the identity proof (`signConfirm`) in every field
|
|
131
136
|
* that matters, so a report can never be lifted from one decision onto another: the decision id,
|
package/dist/signing.js
CHANGED
|
@@ -198,6 +198,9 @@ export function requestCommitment(material, request) {
|
|
|
198
198
|
export function idempotencyKey(material, identity) {
|
|
199
199
|
return createHmac("sha256", bindingSubkey(material, "decidio.idempotency-key.v1")).update(canonicalJson(identity, "idempotency identity"), "utf8").digest("hex");
|
|
200
200
|
}
|
|
201
|
+
export function boundScope(material, text) {
|
|
202
|
+
return "cmd-" + createHmac("sha256", bindingSubkey(material, "decidio.hook-scope.v1")).update(text, "utf8").digest("hex").slice(0, 16);
|
|
203
|
+
}
|
|
201
204
|
export function signExecutionReport(privateKeyBase64, fields) {
|
|
202
205
|
const key = createPrivateKey({ key: Buffer.from(privateKeyBase64, "base64"), format: "der", type: "pkcs8" });
|
|
203
206
|
const nonce = fields.nonce ?? randomUUID();
|
package/openapi.yaml
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
openapi: 3.1.0
|
|
6
6
|
info:
|
|
7
7
|
title: Decidio Agent Gate
|
|
8
|
-
version: 0.
|
|
8
|
+
version: 0.8.1 # tracks the SDK release - checked by packages/conformance/manifests.mjs
|
|
9
9
|
description: >
|
|
10
10
|
Authorize an AI-agent action (proceed | route | block), confirm the captured outcome, and
|
|
11
11
|
receive the signed resume webhook when a routed action is decided. Every outcome seals a
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decidio/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"description": "One-line approval gate for AI-agent actions. Wrap a risky tool call with guard.protect(); Decidio's policy engine decides proceed | route | block, a human approves routed actions, and every outcome is sealed as a verifiable Authority Receipt.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"prepublishOnly": "npm run typecheck && npm run build && node ../publish-boundary/check.mjs --only @decidio/sdk"
|
|
85
85
|
},
|
|
86
86
|
"dependencies": {
|
|
87
|
-
"@decidio/verify": "0.
|
|
87
|
+
"@decidio/verify": "0.8.1"
|
|
88
88
|
},
|
|
89
89
|
"author": "OmniTwin Technologies Inc.",
|
|
90
90
|
"bugs": {
|