@agentguard-run/spend 0.15.7 → 0.15.8

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.
Files changed (61) hide show
  1. package/README.md +61 -1
  2. package/dist/anchor/index.d.ts +35 -0
  3. package/dist/anchor/index.d.ts.map +1 -0
  4. package/dist/anchor/index.js +80 -0
  5. package/dist/anchor/index.js.map +1 -0
  6. package/dist/anchor/opentimestamps.d.ts +55 -0
  7. package/dist/anchor/opentimestamps.d.ts.map +1 -0
  8. package/dist/anchor/opentimestamps.js +179 -0
  9. package/dist/anchor/opentimestamps.js.map +1 -0
  10. package/dist/anchor/store.d.ts +25 -0
  11. package/dist/anchor/store.d.ts.map +1 -0
  12. package/dist/anchor/store.js +112 -0
  13. package/dist/anchor/store.js.map +1 -0
  14. package/dist/anchor/types.d.ts +84 -0
  15. package/dist/anchor/types.d.ts.map +1 -0
  16. package/dist/anchor/types.js +28 -0
  17. package/dist/anchor/types.js.map +1 -0
  18. package/dist/cli/anchor.d.ts +10 -0
  19. package/dist/cli/anchor.d.ts.map +1 -0
  20. package/dist/cli/anchor.js +126 -0
  21. package/dist/cli/anchor.js.map +1 -0
  22. package/dist/cli/colors.d.ts +1 -0
  23. package/dist/cli/colors.d.ts.map +1 -1
  24. package/dist/cli/colors.js +4 -0
  25. package/dist/cli/colors.js.map +1 -1
  26. package/dist/cli/main.d.ts.map +1 -1
  27. package/dist/cli/main.js +10 -0
  28. package/dist/cli/main.js.map +1 -1
  29. package/dist/cli/sample.d.ts +43 -0
  30. package/dist/cli/sample.d.ts.map +1 -0
  31. package/dist/cli/sample.js +154 -0
  32. package/dist/cli/sample.js.map +1 -0
  33. package/dist/cli/serve.d.ts +1 -1
  34. package/dist/cli/serve.d.ts.map +1 -1
  35. package/dist/cli/serve.js +10 -4
  36. package/dist/cli/serve.js.map +1 -1
  37. package/dist/cli/verify.d.ts.map +1 -1
  38. package/dist/cli/verify.js +57 -0
  39. package/dist/cli/verify.js.map +1 -1
  40. package/dist/dashboard/aggregate.d.ts +2 -0
  41. package/dist/dashboard/aggregate.d.ts.map +1 -1
  42. package/dist/dashboard/aggregate.js.map +1 -1
  43. package/dist/decision-log.d.ts +28 -0
  44. package/dist/decision-log.d.ts.map +1 -1
  45. package/dist/decision-log.js +34 -0
  46. package/dist/decision-log.js.map +1 -1
  47. package/dist/index.d.ts +5 -2
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +27 -4
  50. package/dist/index.js.map +1 -1
  51. package/dist/samples/flows.d.ts +28 -0
  52. package/dist/samples/flows.d.ts.map +1 -0
  53. package/dist/samples/flows.js +151 -0
  54. package/dist/samples/flows.js.map +1 -0
  55. package/dist/samples/verifier-html.d.ts +29 -0
  56. package/dist/samples/verifier-html.d.ts.map +1 -0
  57. package/dist/samples/verifier-html.js +188 -0
  58. package/dist/samples/verifier-html.js.map +1 -0
  59. package/package.json +1 -1
  60. package/src/bindings/bindings-enforce.test.ts +97 -0
  61. package/src/dashboard/aggregate.ts +8 -1
package/README.md CHANGED
@@ -187,10 +187,70 @@ Each template sets recommended OpenRouter model assignments, capability tier, fa
187
187
 
188
188
  ## Provider bindings
189
189
 
190
- TypeScript includes native OpenAI, Anthropic, and Bedrock bindings. Streaming usage is settled from provider usage events when available, with local token-estimator fallback when usage is missing. Settlement entries are signed into the same hash chain as enforcement decisions.
190
+ TypeScript includes native OpenAI, Anthropic, and Bedrock bindings. Each wraps a direct provider client in one line, with per-provider cost tables and response-shape handling. Enforcement semantics are identical across all three (and the OpenRouter path): the same policy blocks, downgrades, shadows, or allows a call before any bytes leave the process. Streaming usage is settled from provider usage events when available, with local token-estimator fallback when usage is missing. Settlement entries are signed into the same hash chain as enforcement decisions.
191
+
192
+ Wrap a direct **OpenAI** client:
193
+
194
+ ```ts
195
+ import OpenAI from 'openai';
196
+ import { withSpendGuard } from '@agentguard-run/spend';
197
+
198
+ const openai = withSpendGuard(new OpenAI(), { policy, scope: { tenantId: 'acme' } });
199
+ await openai.chat.completions.create({ model: 'gpt-5', messages });
200
+ ```
201
+
202
+ Wrap a direct **Anthropic** client:
203
+
204
+ ```ts
205
+ import Anthropic from '@anthropic-ai/sdk';
206
+ import { withSpendGuardAnthropic } from '@agentguard-run/spend';
207
+
208
+ const anthropic = withSpendGuardAnthropic(new Anthropic(), { policy, scope: { tenantId: 'acme' } });
209
+ await anthropic.messages.create({ model: 'claude-sonnet-4-6', max_tokens: 1024, messages });
210
+ ```
211
+
212
+ Wrap a direct **Bedrock** runtime client:
213
+
214
+ ```ts
215
+ import { BedrockRuntimeClient } from '@aws-sdk/client-bedrock-runtime';
216
+ import { withSpendGuardBedrock } from '@agentguard-run/spend';
217
+
218
+ const bedrock = withSpendGuardBedrock(new BedrockRuntimeClient({ region: 'us-east-1' }), { policy, scope: { tenantId: 'acme' } });
219
+ await bedrock.send(new InvokeModelCommand({ modelId: 'anthropic.claude-sonnet-4-v1:0', body }));
220
+ ```
221
+
222
+ Only `InvokeModel` / `InvokeModelWithResponseStream` commands are gated; other Bedrock commands pass through untouched.
191
223
 
192
224
  Python includes OpenAI, Anthropic, Bedrock, LangChain, CrewAI, and LlamaIndex integration helpers.
193
225
 
226
+ ## Sample receipts for outreach
227
+
228
+ Generate a realistic, signed sample receipt for a named flow plus a self-contained, self-verifying HTML page — "exactly what your counterparty would get":
229
+
230
+ ```bash
231
+ agentguard sample --flow x402-payment # or: refund | agent-purchase
232
+ ```
233
+
234
+ This writes `receipt.json` and `verify.html`. The HTML re-derives the entry hash from canonical JSON (SHA-256) and verifies the Ed25519 signature in-browser via WebCrypto, with NO network calls; where a browser lacks WebCrypto Ed25519 it still checks the hash chain and links to agentguard.run/verify with the receipt prefilled. The signature is real; only the flow parameters are illustrative.
235
+
236
+ ## External timestamp anchoring (opt-in)
237
+
238
+ Signed receipts prove internal order and integrity, but the signatures are produced in your own environment. Anchoring the chain head's SHA-256 to a public timestamp calendar (OpenTimestamps → Bitcoin) adds an EXTERNAL clock, so "this chain existed no later than <time>" is provable to a third party.
239
+
240
+ ```bash
241
+ AGENTGUARD_ANCHOR=opentimestamps agentguard anchor --tenant my-tenant
242
+ agentguard verify --trace ~/.agentguard/my-tenant/decisions.ndjson
243
+ # → chain head submitted to external timestamp calendar at <time>
244
+ ```
245
+
246
+ Anchoring is OFF by default; nothing changes for existing users. **Zero data plane is preserved: only the 32-byte SHA-256 of the chain head leaves the machine.** A hash reveals nothing about prompts, completions, keys, amounts, or model identity. The proof is stored alongside the ledger at `~/.agentguard/<tenant>/anchor.json` (+ `anchor.ots`).
247
+
248
+ Note: full Bitcoin-attestation verification requires the `opentimestamps` npm package, which is not yet bundled. Without it, submitted proofs are reported as `pending` (calendar commitment received; external attestation not yet confirmed) — never as a fabricated attested time.
249
+
250
+ ## Completeness: sequence-gap detection
251
+
252
+ Each signed entry carries a monotonic per-tenant sequence number. `agentguard verify` and the `agentguard serve` integrity badge flag missing sequence numbers as `possible omitted actions: sequence gap at N` — evidence that an action may have been taken around the SDK and not logged, or that a logged entry was deleted. This is detection and reporting only; it never changes spend-cap enforcement.
253
+
194
254
  ## No proxy
195
255
 
196
256
  AgentGuard Spend is a library, not a gateway. It does not proxy traffic, store prompts, hold provider keys, or host policy state. The signed log lives in your storage.
@@ -0,0 +1,35 @@
1
+ /**
2
+ * External timestamp anchoring: public surface + factory.
3
+ *
4
+ * Opt-in only. `createAnchorFromEnv()` returns null unless AGENTGUARD_ANCHOR is
5
+ * set (today: "opentimestamps"). Nothing in the default SDK path anchors, so
6
+ * existing users see zero behavior change.
7
+ *
8
+ * Patent notice: Protected by U.S. patent-pending technology
9
+ * (App. Nos. 63/983,615; 63/983,621; 63/983,843; 63/984,626;
10
+ * 64/071,781; 64/071,789).
11
+ */
12
+ import type { SignedDecisionLogEntry } from '../types';
13
+ import type { TimestampAnchor } from './types';
14
+ import { type OpenTimestampsAnchorOptions } from './opentimestamps';
15
+ export type { AnchorProof, AnchorStatus, AnchorVerification, TimestampAnchor } from './types';
16
+ export { OpenTimestampsAnchor, DEFAULT_OTS_CALENDARS, type OtsSubmit, type OpenTimestampsAnchorOptions } from './opentimestamps';
17
+ export { writeAnchorProof, readAnchorIndex, readAnchorIndexAt, findAnchorForHead, anchorIndexPath, anchorProofPath, anchorDir, } from './store';
18
+ /** Build a named anchor. Extend the switch as adapters are added. */
19
+ export declare function createAnchor(type: string, options?: OpenTimestampsAnchorOptions): TimestampAnchor | null;
20
+ /** Resolve the configured anchor from AGENTGUARD_ANCHOR, or null when unset. */
21
+ export declare function createAnchorFromEnv(options?: OpenTimestampsAnchorOptions): TimestampAnchor | null;
22
+ /**
23
+ * The digest an anchor should submit for a ledger: the SHA-256 of the current
24
+ * chain HEAD entry hash. Anchoring the head transitively commits to every prior
25
+ * entry (each entry binds its predecessor's hash), so a single 32-byte digest
26
+ * externally timestamps the whole chain. Returns null for an empty chain.
27
+ */
28
+ export declare function chainHeadDigestHex(entries: ReadonlyArray<Pick<SignedDecisionLogEntry, 'sequence' | 'entryHash'>>): string | null;
29
+ /**
30
+ * A Merkle root over the ndjson chain's entry hashes — an alternative anchor
31
+ * digest when you want the anchored value to be independent of chain order
32
+ * bugs. Uses SHA-256 with duplicate-last-node padding.
33
+ */
34
+ export declare function merkleRootHex(entries: ReadonlyArray<Pick<SignedDecisionLogEntry, 'entryHash'>>): string | null;
35
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/anchor/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAwB,KAAK,2BAA2B,EAAE,MAAM,kBAAkB,CAAC;AAE1F,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC9F,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,KAAK,SAAS,EAAE,KAAK,2BAA2B,EAAE,MAAM,kBAAkB,CAAC;AACjI,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,SAAS,GACV,MAAM,SAAS,CAAC;AAEjB,qEAAqE;AACrE,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,2BAAgC,GAAG,eAAe,GAAG,IAAI,CAG5G;AAED,gFAAgF;AAChF,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,2BAAgC,GAAG,eAAe,GAAG,IAAI,CAIrG;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,sBAAsB,EAAE,UAAU,GAAG,WAAW,CAAC,CAAC,GAAG,MAAM,GAAG,IAAI,CAKhI;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,sBAAsB,EAAE,WAAW,CAAC,CAAC,GAAG,MAAM,GAAG,IAAI,CAa9G"}
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ /**
3
+ * External timestamp anchoring: public surface + factory.
4
+ *
5
+ * Opt-in only. `createAnchorFromEnv()` returns null unless AGENTGUARD_ANCHOR is
6
+ * set (today: "opentimestamps"). Nothing in the default SDK path anchors, so
7
+ * existing users see zero behavior change.
8
+ *
9
+ * Patent notice: Protected by U.S. patent-pending technology
10
+ * (App. Nos. 63/983,615; 63/983,621; 63/983,843; 63/984,626;
11
+ * 64/071,781; 64/071,789).
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.anchorDir = exports.anchorProofPath = exports.anchorIndexPath = exports.findAnchorForHead = exports.readAnchorIndexAt = exports.readAnchorIndex = exports.writeAnchorProof = exports.DEFAULT_OTS_CALENDARS = exports.OpenTimestampsAnchor = void 0;
15
+ exports.createAnchor = createAnchor;
16
+ exports.createAnchorFromEnv = createAnchorFromEnv;
17
+ exports.chainHeadDigestHex = chainHeadDigestHex;
18
+ exports.merkleRootHex = merkleRootHex;
19
+ const crypto_1 = require("crypto");
20
+ const opentimestamps_1 = require("./opentimestamps");
21
+ var opentimestamps_2 = require("./opentimestamps");
22
+ Object.defineProperty(exports, "OpenTimestampsAnchor", { enumerable: true, get: function () { return opentimestamps_2.OpenTimestampsAnchor; } });
23
+ Object.defineProperty(exports, "DEFAULT_OTS_CALENDARS", { enumerable: true, get: function () { return opentimestamps_2.DEFAULT_OTS_CALENDARS; } });
24
+ var store_1 = require("./store");
25
+ Object.defineProperty(exports, "writeAnchorProof", { enumerable: true, get: function () { return store_1.writeAnchorProof; } });
26
+ Object.defineProperty(exports, "readAnchorIndex", { enumerable: true, get: function () { return store_1.readAnchorIndex; } });
27
+ Object.defineProperty(exports, "readAnchorIndexAt", { enumerable: true, get: function () { return store_1.readAnchorIndexAt; } });
28
+ Object.defineProperty(exports, "findAnchorForHead", { enumerable: true, get: function () { return store_1.findAnchorForHead; } });
29
+ Object.defineProperty(exports, "anchorIndexPath", { enumerable: true, get: function () { return store_1.anchorIndexPath; } });
30
+ Object.defineProperty(exports, "anchorProofPath", { enumerable: true, get: function () { return store_1.anchorProofPath; } });
31
+ Object.defineProperty(exports, "anchorDir", { enumerable: true, get: function () { return store_1.anchorDir; } });
32
+ /** Build a named anchor. Extend the switch as adapters are added. */
33
+ function createAnchor(type, options = {}) {
34
+ if (type === 'opentimestamps')
35
+ return new opentimestamps_1.OpenTimestampsAnchor(options);
36
+ return null;
37
+ }
38
+ /** Resolve the configured anchor from AGENTGUARD_ANCHOR, or null when unset. */
39
+ function createAnchorFromEnv(options = {}) {
40
+ const type = (process.env.AGENTGUARD_ANCHOR || '').trim().toLowerCase();
41
+ if (!type || type === 'off' || type === 'none' || type === '0')
42
+ return null;
43
+ return createAnchor(type, options);
44
+ }
45
+ /**
46
+ * The digest an anchor should submit for a ledger: the SHA-256 of the current
47
+ * chain HEAD entry hash. Anchoring the head transitively commits to every prior
48
+ * entry (each entry binds its predecessor's hash), so a single 32-byte digest
49
+ * externally timestamps the whole chain. Returns null for an empty chain.
50
+ */
51
+ function chainHeadDigestHex(entries) {
52
+ if (entries.length === 0)
53
+ return null;
54
+ let head = entries[0];
55
+ for (const e of entries)
56
+ if (e.sequence >= head.sequence)
57
+ head = e;
58
+ return (0, crypto_1.createHash)('sha256').update(head.entryHash, 'utf8').digest('hex');
59
+ }
60
+ /**
61
+ * A Merkle root over the ndjson chain's entry hashes — an alternative anchor
62
+ * digest when you want the anchored value to be independent of chain order
63
+ * bugs. Uses SHA-256 with duplicate-last-node padding.
64
+ */
65
+ function merkleRootHex(entries) {
66
+ if (entries.length === 0)
67
+ return null;
68
+ let level = entries.map((e) => new Uint8Array((0, crypto_1.createHash)('sha256').update(e.entryHash, 'utf8').digest()));
69
+ while (level.length > 1) {
70
+ const next = [];
71
+ for (let i = 0; i < level.length; i += 2) {
72
+ const left = level[i];
73
+ const right = level[i + 1] ?? left;
74
+ next.push(new Uint8Array((0, crypto_1.createHash)('sha256').update(Buffer.concat([left, right])).digest()));
75
+ }
76
+ level = next;
77
+ }
78
+ return Buffer.from(level[0]).toString('hex');
79
+ }
80
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/anchor/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;;AAoBH,oCAGC;AAGD,kDAIC;AAQD,gDAKC;AAOD,sCAaC;AA7DD,mCAAoC;AAGpC,qDAA0F;AAG1F,mDAAiI;AAAxH,sHAAA,oBAAoB,OAAA;AAAE,uHAAA,qBAAqB,OAAA;AACpD,iCAQiB;AAPf,yGAAA,gBAAgB,OAAA;AAChB,wGAAA,eAAe,OAAA;AACf,0GAAA,iBAAiB,OAAA;AACjB,0GAAA,iBAAiB,OAAA;AACjB,wGAAA,eAAe,OAAA;AACf,wGAAA,eAAe,OAAA;AACf,kGAAA,SAAS,OAAA;AAGX,qEAAqE;AACrE,SAAgB,YAAY,CAAC,IAAY,EAAE,UAAuC,EAAE;IAClF,IAAI,IAAI,KAAK,gBAAgB;QAAE,OAAO,IAAI,qCAAoB,CAAC,OAAO,CAAC,CAAC;IACxE,OAAO,IAAI,CAAC;AACd,CAAC;AAED,gFAAgF;AAChF,SAAgB,mBAAmB,CAAC,UAAuC,EAAE;IAC3E,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACxE,IAAI,CAAC,IAAI,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IAC5E,OAAO,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AACrC,CAAC;AAED;;;;;GAKG;AACH,SAAgB,kBAAkB,CAAC,OAA8E;IAC/G,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACtC,IAAI,IAAI,GAAG,OAAO,CAAC,CAAC,CAAE,CAAC;IACvB,KAAK,MAAM,CAAC,IAAI,OAAO;QAAE,IAAI,CAAC,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ;YAAE,IAAI,GAAG,CAAC,CAAC;IACnE,OAAO,IAAA,mBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC3E,CAAC;AAED;;;;GAIG;AACH,SAAgB,aAAa,CAAC,OAAiE;IAC7F,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACtC,IAAI,KAAK,GAAiB,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,UAAU,CAAC,IAAA,mBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACxH,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,GAAiB,EAAE,CAAC;QAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YACzC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC;YACvB,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC;YACnC,IAAI,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,IAAA,mBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAChG,CAAC;QACD,KAAK,GAAG,IAAI,CAAC;IACf,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAChD,CAAC"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * OpenTimestamps anchor adapter.
3
+ *
4
+ * Submits ONLY the 32-byte SHA-256 of the chain head to one or more public
5
+ * OpenTimestamps calendar servers and stores the returned commitment. Nothing
6
+ * else leaves the process (zero data plane): a hash is submitted, a proof comes
7
+ * back.
8
+ *
9
+ * IMPORTANT HONESTY NOTE (read before relying on this in production):
10
+ * The canonical OpenTimestamps `.ots` serialization and the Bitcoin-attestation
11
+ * *upgrade + verification* require the `opentimestamps` npm package, which is
12
+ * NOT a dependency of this package today. Without it, this adapter:
13
+ * - DOES perform a real calendar submission (POST <calendar>/digest) and
14
+ * store the raw calendar response bytes, and
15
+ * - DOES bind the proof to the exact head hash it anchored,
16
+ * but it does NOT parse the .ots structure or confirm the Bitcoin attestation.
17
+ * Such proofs are therefore reported as `status: 'pending'` with
18
+ * `attested: false`. The OTS wire/verification protocol is STUBBED pending the
19
+ * `opentimestamps` dependency. We never fabricate an attested time.
20
+ *
21
+ * To complete the chain to Bitcoin: add `opentimestamps` and upgrade the stored
22
+ * proof (`ots upgrade`), then `attestedAt` can be populated from the real
23
+ * Bitcoin block time. This adapter reads `attestedAt` if present but never sets
24
+ * it without a real upgrade.
25
+ *
26
+ * Patent notice: Protected by U.S. patent-pending technology
27
+ * (App. Nos. 63/983,615; 63/983,621; 63/983,843; 63/984,626;
28
+ * 64/071,781; 64/071,789).
29
+ */
30
+ import type { AnchorProof, AnchorVerification, TimestampAnchor } from './types';
31
+ /** Public OpenTimestamps calendar servers (aggregators). */
32
+ export declare const DEFAULT_OTS_CALENDARS: string[];
33
+ /**
34
+ * Transport hook: submit a digest to one calendar, return the raw response
35
+ * bytes (the calendar's commitment). Injectable for tests / private mirrors.
36
+ * Should reject on network/HTTP failure.
37
+ */
38
+ export type OtsSubmit = (calendarUrl: string, digest: Uint8Array) => Promise<Uint8Array>;
39
+ export interface OpenTimestampsAnchorOptions {
40
+ calendars?: string[];
41
+ /** Override the calendar transport (defaults to a real https POST). */
42
+ submit?: OtsSubmit;
43
+ /** Require at least one calendar to succeed. Defaults to true. */
44
+ requireCalendar?: boolean;
45
+ }
46
+ export declare class OpenTimestampsAnchor implements TimestampAnchor {
47
+ readonly type = "opentimestamps";
48
+ private readonly calendars;
49
+ private readonly submit;
50
+ private readonly requireCalendar;
51
+ constructor(options?: OpenTimestampsAnchorOptions);
52
+ anchor(headHashHex: string): Promise<AnchorProof>;
53
+ verify(headHashHex: string, proof: AnchorProof): Promise<AnchorVerification>;
54
+ }
55
+ //# sourceMappingURL=opentimestamps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opentimestamps.d.ts","sourceRoot":"","sources":["../../src/anchor/opentimestamps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAEhF,4DAA4D;AAC5D,eAAO,MAAM,qBAAqB,UAGjC,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;AAEzF,MAAM,WAAW,2BAA2B;IAC1C,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,uEAAuE;IACvE,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,kEAAkE;IAClE,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAiDD,qBAAa,oBAAqB,YAAW,eAAe;IAC1D,QAAQ,CAAC,IAAI,oBAAoB;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAW;IACrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAY;IACnC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAU;gBAE9B,OAAO,GAAE,2BAAgC;IAM/C,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAwCjD,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,kBAAkB,CAAC;CAiCnF"}
@@ -0,0 +1,179 @@
1
+ "use strict";
2
+ /**
3
+ * OpenTimestamps anchor adapter.
4
+ *
5
+ * Submits ONLY the 32-byte SHA-256 of the chain head to one or more public
6
+ * OpenTimestamps calendar servers and stores the returned commitment. Nothing
7
+ * else leaves the process (zero data plane): a hash is submitted, a proof comes
8
+ * back.
9
+ *
10
+ * IMPORTANT HONESTY NOTE (read before relying on this in production):
11
+ * The canonical OpenTimestamps `.ots` serialization and the Bitcoin-attestation
12
+ * *upgrade + verification* require the `opentimestamps` npm package, which is
13
+ * NOT a dependency of this package today. Without it, this adapter:
14
+ * - DOES perform a real calendar submission (POST <calendar>/digest) and
15
+ * store the raw calendar response bytes, and
16
+ * - DOES bind the proof to the exact head hash it anchored,
17
+ * but it does NOT parse the .ots structure or confirm the Bitcoin attestation.
18
+ * Such proofs are therefore reported as `status: 'pending'` with
19
+ * `attested: false`. The OTS wire/verification protocol is STUBBED pending the
20
+ * `opentimestamps` dependency. We never fabricate an attested time.
21
+ *
22
+ * To complete the chain to Bitcoin: add `opentimestamps` and upgrade the stored
23
+ * proof (`ots upgrade`), then `attestedAt` can be populated from the real
24
+ * Bitcoin block time. This adapter reads `attestedAt` if present but never sets
25
+ * it without a real upgrade.
26
+ *
27
+ * Patent notice: Protected by U.S. patent-pending technology
28
+ * (App. Nos. 63/983,615; 63/983,621; 63/983,843; 63/984,626;
29
+ * 64/071,781; 64/071,789).
30
+ */
31
+ Object.defineProperty(exports, "__esModule", { value: true });
32
+ exports.OpenTimestampsAnchor = exports.DEFAULT_OTS_CALENDARS = void 0;
33
+ /** Public OpenTimestamps calendar servers (aggregators). */
34
+ exports.DEFAULT_OTS_CALENDARS = [
35
+ 'https://alice.btc.calendar.opentimestamps.org',
36
+ 'https://bob.btc.calendar.opentimestamps.org',
37
+ ];
38
+ function hexToBytes(hex) {
39
+ const clean = hex.trim().toLowerCase();
40
+ if (!/^[0-9a-f]*$/.test(clean) || clean.length % 2 !== 0) {
41
+ throw new Error('OpenTimestampsAnchor: headHashHex must be lowercase hex of even length');
42
+ }
43
+ const out = new Uint8Array(clean.length / 2);
44
+ for (let i = 0; i < out.length; i++)
45
+ out[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);
46
+ return out;
47
+ }
48
+ /** Default transport: POST the raw digest bytes to <calendar>/digest over https. */
49
+ const defaultSubmit = (calendarUrl, digest) => new Promise((resolve, reject) => {
50
+ // Lazy require so the SDK never pulls node:https at import time in bundlers.
51
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
52
+ const https = require('https');
53
+ const url = new URL(calendarUrl.replace(/\/+$/, '') + '/digest');
54
+ const req = https.request({
55
+ hostname: url.hostname,
56
+ port: url.port || 443,
57
+ path: url.pathname,
58
+ method: 'POST',
59
+ headers: {
60
+ 'Content-Type': 'application/octet-stream',
61
+ 'Accept': 'application/vnd.opentimestamps.v1',
62
+ 'Content-Length': digest.length,
63
+ 'User-Agent': 'agentguard-spend',
64
+ },
65
+ }, (res) => {
66
+ const chunks = [];
67
+ res.on('data', (c) => chunks.push(c));
68
+ res.on('end', () => {
69
+ if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
70
+ resolve(new Uint8Array(Buffer.concat(chunks)));
71
+ }
72
+ else {
73
+ reject(new Error(`OTS calendar ${calendarUrl} returned HTTP ${res.statusCode}`));
74
+ }
75
+ });
76
+ });
77
+ req.on('error', reject);
78
+ req.write(Buffer.from(digest));
79
+ req.end();
80
+ });
81
+ class OpenTimestampsAnchor {
82
+ type = 'opentimestamps';
83
+ calendars;
84
+ submit;
85
+ requireCalendar;
86
+ constructor(options = {}) {
87
+ this.calendars = options.calendars ?? exports.DEFAULT_OTS_CALENDARS;
88
+ this.submit = options.submit ?? defaultSubmit;
89
+ this.requireCalendar = options.requireCalendar ?? true;
90
+ }
91
+ async anchor(headHashHex) {
92
+ const digest = hexToBytes(headHashHex);
93
+ if (digest.length !== 32) {
94
+ throw new Error('OpenTimestampsAnchor: chain head digest must be SHA-256 (32 bytes)');
95
+ }
96
+ const responses = [];
97
+ const used = [];
98
+ const errors = [];
99
+ for (const calendar of this.calendars) {
100
+ try {
101
+ const bytes = await this.submit(calendar, digest);
102
+ responses.push(bytes);
103
+ used.push(calendar);
104
+ }
105
+ catch (err) {
106
+ errors.push(`${calendar}: ${err instanceof Error ? err.message : String(err)}`);
107
+ }
108
+ }
109
+ if (responses.length === 0 && this.requireCalendar) {
110
+ throw new Error('OpenTimestampsAnchor: no calendar accepted the digest: ' + errors.join('; '));
111
+ }
112
+ // Concatenate raw calendar commitments length-prefixed so verify can bind
113
+ // them back to the head. This is NOT a canonical .ots file — see the module
114
+ // note. It is a real, non-fabricated record of what each calendar returned.
115
+ const proofBytes = concatLengthPrefixed(responses);
116
+ return {
117
+ version: 1,
118
+ anchorType: this.type,
119
+ headHashHex: headHashHex.trim().toLowerCase(),
120
+ submittedAt: new Date().toISOString(),
121
+ proof: Buffer.from(proofBytes).toString('base64'),
122
+ status: 'pending',
123
+ calendars: used,
124
+ attestedAt: null,
125
+ note: 'Calendar commitment stored. Bitcoin attestation upgrade + verification ' +
126
+ 'require the `opentimestamps` npm package (not bundled); OTS .ots ' +
127
+ 'serialization is stubbed pending that dependency. Only a SHA-256 hash was sent.',
128
+ };
129
+ }
130
+ async verify(headHashHex, proof) {
131
+ const head = headHashHex.trim().toLowerCase();
132
+ if (proof.anchorType !== this.type) {
133
+ return { ok: false, status: 'invalid', when: null, attested: false, detail: `not an ${this.type} proof` };
134
+ }
135
+ if (proof.headHashHex.trim().toLowerCase() !== head) {
136
+ return {
137
+ ok: false,
138
+ status: 'invalid',
139
+ when: null,
140
+ attested: false,
141
+ detail: 'proof does not bind the supplied chain head hash',
142
+ };
143
+ }
144
+ // A real Bitcoin-attested upgrade populates attestedAt; we trust it only if
145
+ // present (never synthesised here).
146
+ if (proof.attestedAt) {
147
+ return { ok: true, status: 'complete', when: proof.attestedAt, attested: true };
148
+ }
149
+ const hasCommitment = typeof proof.proof === 'string' && proof.proof.length > 0;
150
+ if (!hasCommitment && !(proof.calendars && proof.calendars.length > 0)) {
151
+ return { ok: false, status: 'invalid', when: null, attested: false, detail: 'proof carries no calendar commitment' };
152
+ }
153
+ return {
154
+ ok: true,
155
+ status: 'pending',
156
+ when: proof.submittedAt ?? null,
157
+ attested: false,
158
+ detail: 'Calendar commitment present for this head hash; Bitcoin attestation not yet ' +
159
+ 'confirmed (requires `opentimestamps` upgrade). `when` is the submission time, not an attested time.',
160
+ };
161
+ }
162
+ }
163
+ exports.OpenTimestampsAnchor = OpenTimestampsAnchor;
164
+ function concatLengthPrefixed(chunks) {
165
+ let total = 0;
166
+ for (const c of chunks)
167
+ total += 4 + c.length;
168
+ const out = new Uint8Array(total);
169
+ const view = new DataView(out.buffer);
170
+ let offset = 0;
171
+ for (const c of chunks) {
172
+ view.setUint32(offset, c.length, false);
173
+ offset += 4;
174
+ out.set(c, offset);
175
+ offset += c.length;
176
+ }
177
+ return out;
178
+ }
179
+ //# sourceMappingURL=opentimestamps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opentimestamps.js","sourceRoot":"","sources":["../../src/anchor/opentimestamps.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Anchor proof persistence, stored ALONGSIDE the ndjson ledger so a verifier
3
+ * can find both together:
4
+ * ~/.agentguard/<tenant>/anchor.ots latest raw calendar proof bytes (binary)
5
+ * ~/.agentguard/<tenant>/anchor.json small append-only index of AnchorProof
6
+ *
7
+ * The index is what `agentguard verify` reads to report external timestamping.
8
+ *
9
+ * Patent notice: Protected by U.S. patent-pending technology
10
+ * (App. Nos. 63/983,615; 63/983,621; 63/983,843; 63/984,626;
11
+ * 64/071,781; 64/071,789).
12
+ */
13
+ import type { AnchorProof } from './types';
14
+ export declare function defaultHome(): string;
15
+ export declare function anchorDir(tenant: string, home?: string): string;
16
+ export declare function anchorIndexPath(tenant: string, home?: string): string;
17
+ export declare function anchorProofPath(tenant: string, home?: string): string;
18
+ /** Append a proof to the tenant index and write its raw bytes to anchor.ots. */
19
+ export declare function writeAnchorProof(tenant: string, proof: AnchorProof, home?: string): void;
20
+ export declare function readAnchorIndex(tenant: string, home?: string): AnchorProof[];
21
+ /** Read an anchor index directly from a path (used by verify beside a trace). */
22
+ export declare function readAnchorIndexAt(indexPath: string): AnchorProof[];
23
+ /** The most recent proof recorded for a given head hash, if any. */
24
+ export declare function findAnchorForHead(proofs: AnchorProof[], headHashHex: string): AnchorProof | null;
25
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/anchor/store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE,MAAsB,GAAG,MAAM,CAG9E;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAErE;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAErE;AAED,gFAAgF;AAChF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAWxF;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,WAAW,EAAE,CAE5E;AAED,iFAAiF;AACjF,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,EAAE,CASlE;AAED,oEAAoE;AACpE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,WAAW,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAMhG"}
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ /**
3
+ * Anchor proof persistence, stored ALONGSIDE the ndjson ledger so a verifier
4
+ * can find both together:
5
+ * ~/.agentguard/<tenant>/anchor.ots latest raw calendar proof bytes (binary)
6
+ * ~/.agentguard/<tenant>/anchor.json small append-only index of AnchorProof
7
+ *
8
+ * The index is what `agentguard verify` reads to report external timestamping.
9
+ *
10
+ * Patent notice: Protected by U.S. patent-pending technology
11
+ * (App. Nos. 63/983,615; 63/983,621; 63/983,843; 63/984,626;
12
+ * 64/071,781; 64/071,789).
13
+ */
14
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ var desc = Object.getOwnPropertyDescriptor(m, k);
17
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
18
+ desc = { enumerable: true, get: function() { return m[k]; } };
19
+ }
20
+ Object.defineProperty(o, k2, desc);
21
+ }) : (function(o, m, k, k2) {
22
+ if (k2 === undefined) k2 = k;
23
+ o[k2] = m[k];
24
+ }));
25
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
26
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
27
+ }) : function(o, v) {
28
+ o["default"] = v;
29
+ });
30
+ var __importStar = (this && this.__importStar) || (function () {
31
+ var ownKeys = function(o) {
32
+ ownKeys = Object.getOwnPropertyNames || function (o) {
33
+ var ar = [];
34
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
35
+ return ar;
36
+ };
37
+ return ownKeys(o);
38
+ };
39
+ return function (mod) {
40
+ if (mod && mod.__esModule) return mod;
41
+ var result = {};
42
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
43
+ __setModuleDefault(result, mod);
44
+ return result;
45
+ };
46
+ })();
47
+ Object.defineProperty(exports, "__esModule", { value: true });
48
+ exports.defaultHome = defaultHome;
49
+ exports.anchorDir = anchorDir;
50
+ exports.anchorIndexPath = anchorIndexPath;
51
+ exports.anchorProofPath = anchorProofPath;
52
+ exports.writeAnchorProof = writeAnchorProof;
53
+ exports.readAnchorIndex = readAnchorIndex;
54
+ exports.readAnchorIndexAt = readAnchorIndexAt;
55
+ exports.findAnchorForHead = findAnchorForHead;
56
+ const fs = __importStar(require("fs"));
57
+ const os = __importStar(require("os"));
58
+ const path = __importStar(require("path"));
59
+ function defaultHome() {
60
+ return process.env.AGENTGUARD_HOME || path.join(os.homedir(), '.agentguard');
61
+ }
62
+ function anchorDir(tenant, home = defaultHome()) {
63
+ const clean = String(tenant || 'default').replace(/[^A-Za-z0-9._-]/g, '_') || 'default';
64
+ return path.join(home, clean);
65
+ }
66
+ function anchorIndexPath(tenant, home) {
67
+ return path.join(anchorDir(tenant, home), 'anchor.json');
68
+ }
69
+ function anchorProofPath(tenant, home) {
70
+ return path.join(anchorDir(tenant, home), 'anchor.ots');
71
+ }
72
+ /** Append a proof to the tenant index and write its raw bytes to anchor.ots. */
73
+ function writeAnchorProof(tenant, proof, home) {
74
+ const dir = anchorDir(tenant, home);
75
+ fs.mkdirSync(dir, { recursive: true });
76
+ const existing = readAnchorIndex(tenant, home);
77
+ existing.push(proof);
78
+ fs.writeFileSync(anchorIndexPath(tenant, home), JSON.stringify(existing, null, 2) + '\n');
79
+ try {
80
+ fs.writeFileSync(anchorProofPath(tenant, home), Buffer.from(proof.proof, 'base64'));
81
+ }
82
+ catch {
83
+ // best-effort binary sidecar; the JSON index is the source of truth
84
+ }
85
+ }
86
+ function readAnchorIndex(tenant, home) {
87
+ return readAnchorIndexAt(anchorIndexPath(tenant, home));
88
+ }
89
+ /** Read an anchor index directly from a path (used by verify beside a trace). */
90
+ function readAnchorIndexAt(indexPath) {
91
+ try {
92
+ const parsed = JSON.parse(fs.readFileSync(indexPath, 'utf-8'));
93
+ if (Array.isArray(parsed))
94
+ return parsed;
95
+ if (parsed && typeof parsed === 'object')
96
+ return [parsed];
97
+ return [];
98
+ }
99
+ catch {
100
+ return [];
101
+ }
102
+ }
103
+ /** The most recent proof recorded for a given head hash, if any. */
104
+ function findAnchorForHead(proofs, headHashHex) {
105
+ const head = headHashHex.trim().toLowerCase();
106
+ for (let i = proofs.length - 1; i >= 0; i--) {
107
+ if (proofs[i]?.headHashHex?.trim().toLowerCase() === head)
108
+ return proofs[i];
109
+ }
110
+ return null;
111
+ }
112
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/anchor/store.ts"],"names":[],"mappings":"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"}