authority-layer 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/AuthorityLayer.d.ts +70 -0
  2. package/dist/AuthorityLayer.d.ts.map +1 -0
  3. package/dist/AuthorityLayer.js +175 -0
  4. package/dist/AuthorityLayer.js.map +1 -0
  5. package/dist/EnforcementHalt.d.ts +10 -0
  6. package/dist/EnforcementHalt.d.ts.map +1 -0
  7. package/dist/EnforcementHalt.js +34 -0
  8. package/dist/EnforcementHalt.js.map +1 -0
  9. package/dist/doctor.d.ts +3 -0
  10. package/dist/doctor.d.ts.map +1 -0
  11. package/dist/doctor.js +81 -0
  12. package/dist/doctor.js.map +1 -0
  13. package/dist/enforcement/budgetGuard.d.ts +14 -0
  14. package/dist/enforcement/budgetGuard.d.ts.map +1 -0
  15. package/dist/enforcement/budgetGuard.js +43 -0
  16. package/dist/enforcement/budgetGuard.js.map +1 -0
  17. package/dist/enforcement/loopGuard.d.ts +17 -0
  18. package/dist/enforcement/loopGuard.d.ts.map +1 -0
  19. package/dist/enforcement/loopGuard.js +43 -0
  20. package/dist/enforcement/loopGuard.js.map +1 -0
  21. package/dist/enforcement/toolThrottle.d.ts +20 -0
  22. package/dist/enforcement/toolThrottle.d.ts.map +1 -0
  23. package/dist/enforcement/toolThrottle.js +50 -0
  24. package/dist/enforcement/toolThrottle.js.map +1 -0
  25. package/dist/index.d.ts +4 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +10 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/integrity/hashChain.d.ts +27 -0
  30. package/dist/integrity/hashChain.d.ts.map +1 -0
  31. package/dist/integrity/hashChain.js +87 -0
  32. package/dist/integrity/hashChain.js.map +1 -0
  33. package/dist/types.d.ts +79 -0
  34. package/dist/types.d.ts.map +1 -0
  35. package/dist/types.js +9 -0
  36. package/dist/types.js.map +1 -0
  37. package/package.json +46 -0
@@ -0,0 +1,70 @@
1
+ import type { AuthorityConfig } from "./types";
2
+ export declare class AuthorityLayer {
3
+ private readonly mode;
4
+ private readonly budgetGuard?;
5
+ private readonly loopGuard?;
6
+ private readonly toolThrottle?;
7
+ private readonly chain;
8
+ constructor(config: AuthorityConfig);
9
+ /**
10
+ * Convert a guard's PendingHalt into a logged HaltResult, then either
11
+ * throw an EnforcementHalt (strict) or emit a console warning (warn/stub).
12
+ */
13
+ private enforce;
14
+ /**
15
+ * Wrap an agent run with enforcement.
16
+ *
17
+ * - Resets per-run counters (loop guard).
18
+ * - Logs run.start and run.complete events to the chain.
19
+ * - Re-throws EnforcementHalt cleanly; logs unexpected errors to the chain
20
+ * before re-throwing so they appear in the audit log.
21
+ *
22
+ * @example
23
+ * await authority.wrap(async () => {
24
+ * const result = await authority.tool("openai.chat", () => openai.chat(...));
25
+ * authority.recordSpend(result.usage.cost);
26
+ * });
27
+ */
28
+ wrap(fn: () => Promise<void>): Promise<void>;
29
+ /**
30
+ * Wrap a single tool call with loop guard and throttle enforcement.
31
+ *
32
+ * This is the sole mechanism for calling external tools within wrap().
33
+ * Both guards are checked before the tool function executes — the tool
34
+ * function is never called if a limit has already been breached.
35
+ *
36
+ * @param name Human-readable tool name, logged to the event chain.
37
+ * @param fn Async function that performs the actual tool call.
38
+ * @returns The resolved return value of fn().
39
+ *
40
+ * @example
41
+ * const data = await authority.tool("stripe.charge", () =>
42
+ * stripe.charges.create({ amount: 100, currency: "usd" })
43
+ * );
44
+ */
45
+ tool<T>(name: string, fn: () => Promise<T>): Promise<T>;
46
+ /**
47
+ * Report token or API spend in USD.
48
+ *
49
+ * Call this after each model or billable API call. AuthorityLayer does not
50
+ * intercept pricing automatically — different providers expose cost
51
+ * differently, so the host is responsible for calculating the USD amount.
52
+ *
53
+ * @example
54
+ * const response = await openai.chat.completions.create({ ... });
55
+ * const costUSD = response.usage.total_tokens * PRICE_PER_TOKEN;
56
+ * authority.recordSpend(costUSD);
57
+ */
58
+ recordSpend(amountUSD: number): void;
59
+ /**
60
+ * Return a read-only copy of the enforcement event chain.
61
+ * Useful for inspecting what happened during a run or persisting to disk.
62
+ */
63
+ getChain(): readonly import("./types").EnforcementEvent[];
64
+ /**
65
+ * Verify the integrity of the in-memory event chain.
66
+ * Returns false if any event has been tampered with.
67
+ */
68
+ verifyChain(): boolean;
69
+ }
70
+ //# sourceMappingURL=AuthorityLayer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AuthorityLayer.d.ts","sourceRoot":"","sources":["../src/AuthorityLayer.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,eAAe,EAA4C,MAAM,SAAS,CAAC;AAOzF,qBAAa,cAAc;IACvB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAkB;IACvC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAc;IAC3C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAY;IACvC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAe;IAC7C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAY;gBAEtB,MAAM,EAAE,eAAe;IAiBnC;;;OAGG;IACH,OAAO,CAAC,OAAO;IAgCf;;;;;;;;;;;;;OAaG;IACG,IAAI,CAAC,EAAE,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBlD;;;;;;;;;;;;;;;OAeG;IACG,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAgB7D;;;;;;;;;;;OAWG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAOpC;;;OAGG;IACH,QAAQ;IAIR;;;OAGG;IACH,WAAW,IAAI,OAAO;CAGzB"}
@@ -0,0 +1,175 @@
1
+ "use strict";
2
+ // ─────────────────────────────────────────────────────────────────────────────
3
+ // AuthorityLayer — Main Enforcement Class
4
+ //
5
+ // This is the single public surface of the SDK. Instantiate once, pass config,
6
+ // then route all agent execution through wrap() and all tool calls through
7
+ // tool(). recordSpend() is the only other public method — it exists because
8
+ // token pricing is framework-specific and must be reported explicitly.
9
+ //
10
+ // Design decisions:
11
+ //
12
+ // 1. Guards are instantiated only when their config section is present.
13
+ // Omitting a config key disables that primitive entirely — no silent
14
+ // defaults that appear inactive but still run.
15
+ //
16
+ // 2. tool() is the single composable hook for all external tool calls.
17
+ // It bundles loop guard + throttle in one call, keeping adoption simple
18
+ // and preventing the misuse that separate checkLoop() / checkThrottle()
19
+ // methods would invite (forgetting to call one, calling them twice, etc.).
20
+ //
21
+ // 3. EnforcementHalt is a typed error, not a raw throw. Its .enforcement
22
+ // property carries the full structured HaltResult so callers never need
23
+ // to parse error messages.
24
+ //
25
+ // 4. mode: "warn" is stubbed in V1. The config option is accepted and stored
26
+ // so existing configs won't break when warn mode is implemented.
27
+ // ─────────────────────────────────────────────────────────────────────────────
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.AuthorityLayer = void 0;
30
+ const budgetGuard_1 = require("./enforcement/budgetGuard");
31
+ const loopGuard_1 = require("./enforcement/loopGuard");
32
+ const toolThrottle_1 = require("./enforcement/toolThrottle");
33
+ const hashChain_1 = require("./integrity/hashChain");
34
+ const EnforcementHalt_1 = require("./EnforcementHalt");
35
+ class AuthorityLayer {
36
+ constructor(config) {
37
+ this.mode = config.mode ?? "strict";
38
+ this.chain = new hashChain_1.HashChain();
39
+ if (config.budget) {
40
+ this.budgetGuard = new budgetGuard_1.BudgetGuard(config.budget);
41
+ }
42
+ if (config.loopGuard) {
43
+ this.loopGuard = new loopGuard_1.LoopGuard(config.loopGuard);
44
+ }
45
+ if (config.toolThrottle) {
46
+ this.toolThrottle = new toolThrottle_1.ToolThrottle(config.toolThrottle);
47
+ }
48
+ }
49
+ // ── Private helpers ─────────────────────────────────────────────────────────
50
+ /**
51
+ * Convert a guard's PendingHalt into a logged HaltResult, then either
52
+ * throw an EnforcementHalt (strict) or emit a console warning (warn/stub).
53
+ */
54
+ enforce(result, context) {
55
+ if (result.status !== "halted")
56
+ return;
57
+ const event = this.chain.append("enforcement.halt", {
58
+ reason: result.reason,
59
+ limit: result.limit,
60
+ spent: result.spent,
61
+ ...context,
62
+ });
63
+ const haltResult = {
64
+ status: "halted",
65
+ reason: result.reason,
66
+ limit: result.limit,
67
+ spent: result.spent,
68
+ event_id: event.event_id,
69
+ };
70
+ if (this.mode === "strict") {
71
+ throw new EnforcementHalt_1.EnforcementHalt(haltResult);
72
+ }
73
+ else {
74
+ // V1 stub: warn mode is accepted in config but not yet implemented.
75
+ // In a future release this will emit a structured warning and continue.
76
+ console.warn("[AuthorityLayer] WARN (warn mode stub):", haltResult);
77
+ }
78
+ }
79
+ // ── Public API ──────────────────────────────────────────────────────────────
80
+ /**
81
+ * Wrap an agent run with enforcement.
82
+ *
83
+ * - Resets per-run counters (loop guard).
84
+ * - Logs run.start and run.complete events to the chain.
85
+ * - Re-throws EnforcementHalt cleanly; logs unexpected errors to the chain
86
+ * before re-throwing so they appear in the audit log.
87
+ *
88
+ * @example
89
+ * await authority.wrap(async () => {
90
+ * const result = await authority.tool("openai.chat", () => openai.chat(...));
91
+ * authority.recordSpend(result.usage.cost);
92
+ * });
93
+ */
94
+ async wrap(fn) {
95
+ // Per-run reset
96
+ this.loopGuard?.reset();
97
+ this.chain.append("run.start", { timestamp: new Date().toISOString() });
98
+ try {
99
+ await fn();
100
+ this.chain.append("run.complete", { timestamp: new Date().toISOString() });
101
+ }
102
+ catch (err) {
103
+ if (err instanceof EnforcementHalt_1.EnforcementHalt) {
104
+ // Already logged by enforce() — just propagate.
105
+ throw err;
106
+ }
107
+ // Unexpected error — log it to the chain for auditability, then rethrow.
108
+ this.chain.append("run.error", {
109
+ message: err instanceof Error ? err.message : String(err),
110
+ });
111
+ throw err;
112
+ }
113
+ }
114
+ /**
115
+ * Wrap a single tool call with loop guard and throttle enforcement.
116
+ *
117
+ * This is the sole mechanism for calling external tools within wrap().
118
+ * Both guards are checked before the tool function executes — the tool
119
+ * function is never called if a limit has already been breached.
120
+ *
121
+ * @param name Human-readable tool name, logged to the event chain.
122
+ * @param fn Async function that performs the actual tool call.
123
+ * @returns The resolved return value of fn().
124
+ *
125
+ * @example
126
+ * const data = await authority.tool("stripe.charge", () =>
127
+ * stripe.charges.create({ amount: 100, currency: "usd" })
128
+ * );
129
+ */
130
+ async tool(name, fn) {
131
+ const ctx = { tool: name };
132
+ if (this.loopGuard) {
133
+ this.enforce(this.loopGuard.tick(), ctx);
134
+ }
135
+ if (this.toolThrottle) {
136
+ this.enforce(this.toolThrottle.tick(), ctx);
137
+ }
138
+ this.chain.append("tool.call", { name });
139
+ return fn();
140
+ }
141
+ /**
142
+ * Report token or API spend in USD.
143
+ *
144
+ * Call this after each model or billable API call. AuthorityLayer does not
145
+ * intercept pricing automatically — different providers expose cost
146
+ * differently, so the host is responsible for calculating the USD amount.
147
+ *
148
+ * @example
149
+ * const response = await openai.chat.completions.create({ ... });
150
+ * const costUSD = response.usage.total_tokens * PRICE_PER_TOKEN;
151
+ * authority.recordSpend(costUSD);
152
+ */
153
+ recordSpend(amountUSD) {
154
+ if (!this.budgetGuard)
155
+ return;
156
+ this.enforce(this.budgetGuard.record(amountUSD));
157
+ }
158
+ // ── Audit / integrity ───────────────────────────────────────────────────────
159
+ /**
160
+ * Return a read-only copy of the enforcement event chain.
161
+ * Useful for inspecting what happened during a run or persisting to disk.
162
+ */
163
+ getChain() {
164
+ return this.chain.getChain();
165
+ }
166
+ /**
167
+ * Verify the integrity of the in-memory event chain.
168
+ * Returns false if any event has been tampered with.
169
+ */
170
+ verifyChain() {
171
+ return this.chain.verify();
172
+ }
173
+ }
174
+ exports.AuthorityLayer = AuthorityLayer;
175
+ //# sourceMappingURL=AuthorityLayer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AuthorityLayer.js","sourceRoot":"","sources":["../src/AuthorityLayer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { HaltResult } from "./types";
2
+ export declare class EnforcementHalt extends Error {
3
+ /**
4
+ * The full, structured enforcement result.
5
+ * This is the canonical way to inspect why execution was halted.
6
+ */
7
+ readonly enforcement: HaltResult;
8
+ constructor(result: HaltResult);
9
+ }
10
+ //# sourceMappingURL=EnforcementHalt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EnforcementHalt.d.ts","sourceRoot":"","sources":["../src/EnforcementHalt.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C,qBAAa,eAAgB,SAAQ,KAAK;IACtC;;;OAGG;IACH,QAAQ,CAAC,WAAW,EAAE,UAAU,CAAC;gBAErB,MAAM,EAAE,UAAU;CAWjC"}
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ // ─────────────────────────────────────────────────────────────────────────────
3
+ // EnforcementHalt — Typed Enforcement Error
4
+ //
5
+ // Thrown by AuthorityLayer in strict mode when a guard limit is breached.
6
+ //
7
+ // IMPORTANT: always access halt details via the `.enforcement` property,
8
+ // not by parsing the error message. The structured object is stable API;
9
+ // the message string is not.
10
+ //
11
+ // @example
12
+ // try {
13
+ // await authority.wrap(async () => { ... });
14
+ // } catch (err) {
15
+ // if (err instanceof EnforcementHalt) {
16
+ // console.log(err.enforcement);
17
+ // // { status: "halted", reason: "budget_exceeded", limit: 50, spent: 52.14, event_id: "evt_..." }
18
+ // }
19
+ // }
20
+ // ─────────────────────────────────────────────────────────────────────────────
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.EnforcementHalt = void 0;
23
+ class EnforcementHalt extends Error {
24
+ constructor(result) {
25
+ super(`[AuthorityLayer] Execution halted — ${result.reason} ` +
26
+ `(limit: ${result.limit}, spent: ${result.spent}, event: ${result.event_id})`);
27
+ this.name = "EnforcementHalt";
28
+ this.enforcement = result;
29
+ // Restore prototype chain for instanceof checks across transpilation targets
30
+ Object.setPrototypeOf(this, EnforcementHalt.prototype);
31
+ }
32
+ }
33
+ exports.EnforcementHalt = EnforcementHalt;
34
+ //# sourceMappingURL=EnforcementHalt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EnforcementHalt.js","sourceRoot":"","sources":["../src/EnforcementHalt.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,4CAA4C;AAC5C,EAAE;AACF,0EAA0E;AAC1E,EAAE;AACF,yEAAyE;AACzE,yEAAyE;AACzE,6BAA6B;AAC7B,EAAE;AACF,WAAW;AACX,QAAQ;AACR,+CAA+C;AAC/C,kBAAkB;AAClB,0CAA0C;AAC1C,oCAAoC;AACpC,uGAAuG;AACvG,MAAM;AACN,IAAI;AACJ,gFAAgF;;;AAIhF,MAAa,eAAgB,SAAQ,KAAK;IAOtC,YAAY,MAAkB;QAC1B,KAAK,CACD,uCAAuC,MAAM,CAAC,MAAM,GAAG;YACvD,WAAW,MAAM,CAAC,KAAK,YAAY,MAAM,CAAC,KAAK,YAAY,MAAM,CAAC,QAAQ,GAAG,CAChF,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;QAC9B,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC;QAE1B,6EAA6E;QAC7E,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,eAAe,CAAC,SAAS,CAAC,CAAC;IAC3D,CAAC;CACJ;AAlBD,0CAkBC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":""}
package/dist/doctor.js ADDED
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ // ─────────────────────────────────────────────────────────────────────────────
4
+ // authority-layer doctor
5
+ //
6
+ // Runs a series of guardrail checks and prints results to stdout.
7
+ // Exit 0 = all checks pass. Exit 1 = one or more checks failed.
8
+ //
9
+ // Usage:
10
+ // npx authority-layer doctor
11
+ // authority-layer doctor (if installed globally)
12
+ // ─────────────────────────────────────────────────────────────────────────────
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ const crypto_1 = require("crypto");
15
+ const RESET = "\x1b[0m";
16
+ const GREEN = "\x1b[1;32m";
17
+ const RED = "\x1b[1;31m";
18
+ const YELLOW = "\x1b[1;33m";
19
+ const BOLD = "\x1b[1m";
20
+ const results = [];
21
+ function check(name, ok, note) {
22
+ results.push({ name, ok, note });
23
+ }
24
+ // ── Guardrail checks ──────────────────────────────────────────────────────────
25
+ // 1. Node version
26
+ const [major] = process.versions.node.split(".").map(Number);
27
+ check("Node.js version >= 18", major >= 18, `found ${process.versions.node}`);
28
+ // 2. crypto module (required by hash chain)
29
+ try {
30
+ (0, crypto_1.createHash)("sha256").update("test").digest("hex");
31
+ check("crypto module (sha256)", true);
32
+ }
33
+ catch {
34
+ check("crypto module (sha256)", false, "built-in crypto unavailable");
35
+ }
36
+ // 3. No AUTHORITY_LAYER_DISABLE env flag set
37
+ const disabled = process.env["AUTHORITY_LAYER_DISABLE"] === "1";
38
+ check("AUTHORITY_LAYER_DISABLE not set", !disabled, disabled ? "enforcement is currently disabled via env" : undefined);
39
+ // 4. Offline capable — confirm no network is required for import
40
+ try {
41
+ // Dynamic require — avoids top-level import that would run before checks
42
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
43
+ require("./index");
44
+ check("core module loads offline", true);
45
+ }
46
+ catch (err) {
47
+ check("core module loads offline", false, String(err));
48
+ }
49
+ // 5. Sanity: AuthorityLayer instantiates with a minimal config
50
+ try {
51
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
52
+ const { AuthorityLayer } = require("./index");
53
+ const a = new AuthorityLayer({ budget: { dailyUSD: 1 } });
54
+ const chain = a.getChain();
55
+ check("AuthorityLayer instantiates", true, `chain length: ${chain.length}`);
56
+ }
57
+ catch (err) {
58
+ check("AuthorityLayer instantiates", false, String(err));
59
+ }
60
+ // ── Output ────────────────────────────────────────────────────────────────────
61
+ const pkg = require("../package.json");
62
+ console.log(`\n${BOLD}AuthorityLayer Doctor${RESET} ${YELLOW}${pkg.name}@${pkg.version}${RESET}\n`);
63
+ let failed = 0;
64
+ for (const r of results) {
65
+ const icon = r.ok ? `${GREEN}✔${RESET}` : `${RED}✘${RESET}`;
66
+ const status = r.ok ? `${GREEN}pass${RESET}` : `${RED}FAIL${RESET}`;
67
+ const note = r.note ? ` ${YELLOW}(${r.note})${RESET}` : "";
68
+ console.log(` ${icon} ${r.name.padEnd(38)} ${status}${note}`);
69
+ if (!r.ok)
70
+ failed++;
71
+ }
72
+ console.log();
73
+ if (failed === 0) {
74
+ console.log(`${GREEN}All checks passed.${RESET} AuthorityLayer is ready.\n`);
75
+ process.exit(0);
76
+ }
77
+ else {
78
+ console.log(`${RED}${failed} check(s) failed.${RESET} Review the output above.\n`);
79
+ process.exit(1);
80
+ }
81
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { BudgetConfig, GuardResult } from "../types";
2
+ export declare class BudgetGuard {
3
+ private spent;
4
+ private readonly limit;
5
+ constructor(config: BudgetConfig);
6
+ /**
7
+ * Record additional spend and check against the hard limit.
8
+ * Returns a PendingHalt if the cumulative spend now exceeds the limit.
9
+ */
10
+ record(amountUSD: number): GuardResult;
11
+ getSpent(): number;
12
+ getLimit(): number;
13
+ }
14
+ //# sourceMappingURL=budgetGuard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budgetGuard.d.ts","sourceRoot":"","sources":["../../src/enforcement/budgetGuard.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE1D,qBAAa,WAAW;IACpB,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;gBAEnB,MAAM,EAAE,YAAY;IAIhC;;;OAGG;IACH,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW;IAetC,QAAQ,IAAI,MAAM;IAIlB,QAAQ,IAAI,MAAM;CAGrB"}
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ // ─────────────────────────────────────────────────────────────────────────────
3
+ // BudgetGuard — Hard USD Spend Cap
4
+ //
5
+ // Tracks cumulative USD spend across a run and halts execution when it
6
+ // exceeds the configured dailyUSD limit.
7
+ //
8
+ // Spend is reported explicitly by the host via AuthorityLayer.recordSpend().
9
+ // This keeps the core framework-agnostic — different model providers expose
10
+ // pricing differently, so the host is responsible for conversion.
11
+ // ─────────────────────────────────────────────────────────────────────────────
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.BudgetGuard = void 0;
14
+ class BudgetGuard {
15
+ constructor(config) {
16
+ this.spent = 0;
17
+ this.limit = config.dailyUSD;
18
+ }
19
+ /**
20
+ * Record additional spend and check against the hard limit.
21
+ * Returns a PendingHalt if the cumulative spend now exceeds the limit.
22
+ */
23
+ record(amountUSD) {
24
+ this.spent += amountUSD;
25
+ if (this.spent > this.limit) {
26
+ return {
27
+ status: "halted",
28
+ reason: "budget_exceeded",
29
+ limit: this.limit,
30
+ spent: this.spent,
31
+ };
32
+ }
33
+ return { status: "ok" };
34
+ }
35
+ getSpent() {
36
+ return this.spent;
37
+ }
38
+ getLimit() {
39
+ return this.limit;
40
+ }
41
+ }
42
+ exports.BudgetGuard = BudgetGuard;
43
+ //# sourceMappingURL=budgetGuard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budgetGuard.js","sourceRoot":"","sources":["../../src/enforcement/budgetGuard.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,mCAAmC;AACnC,EAAE;AACF,uEAAuE;AACvE,yCAAyC;AACzC,EAAE;AACF,6EAA6E;AAC7E,4EAA4E;AAC5E,kEAAkE;AAClE,gFAAgF;;;AAIhF,MAAa,WAAW;IAIpB,YAAY,MAAoB;QAHxB,UAAK,GAAG,CAAC,CAAC;QAId,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC;IACjC,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,SAAiB;QACpB,IAAI,CAAC,KAAK,IAAI,SAAS,CAAC;QAExB,IAAI,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;YAC1B,OAAO;gBACH,MAAM,EAAE,QAAQ;gBAChB,MAAM,EAAE,iBAAiB;gBACzB,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,KAAK,EAAE,IAAI,CAAC,KAAK;aACpB,CAAC;QACN,CAAC;QAED,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IAC5B,CAAC;IAED,QAAQ;QACJ,OAAO,IAAI,CAAC,KAAK,CAAC;IACtB,CAAC;IAED,QAAQ;QACJ,OAAO,IAAI,CAAC,KAAK,CAAC;IACtB,CAAC;CACJ;AAlCD,kCAkCC"}
@@ -0,0 +1,17 @@
1
+ import type { LoopGuardConfig, GuardResult } from "../types";
2
+ export declare class LoopGuard {
3
+ private count;
4
+ private readonly limit;
5
+ constructor(config: LoopGuardConfig);
6
+ /**
7
+ * Reset the call counter. Called by AuthorityLayer at the start of wrap().
8
+ */
9
+ reset(): void;
10
+ /**
11
+ * Increment the counter and check against the per-run limit.
12
+ * Returns a PendingHalt once the count exceeds the limit.
13
+ */
14
+ tick(): GuardResult;
15
+ getCount(): number;
16
+ }
17
+ //# sourceMappingURL=loopGuard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loopGuard.d.ts","sourceRoot":"","sources":["../../src/enforcement/loopGuard.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE7D,qBAAa,SAAS;IAClB,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;gBAEnB,MAAM,EAAE,eAAe;IAInC;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;;OAGG;IACH,IAAI,IAAI,WAAW;IAenB,QAAQ,IAAI,MAAM;CAGrB"}
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ // ─────────────────────────────────────────────────────────────────────────────
3
+ // LoopGuard — Per-Run Tool Call Limiter
4
+ //
5
+ // Prevents infinite tool loops within a single agent run by counting every
6
+ // call routed through authority.tool(). The counter resets at the start of
7
+ // each wrap() invocation, so limits apply per-run, not globally.
8
+ // ─────────────────────────────────────────────────────────────────────────────
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.LoopGuard = void 0;
11
+ class LoopGuard {
12
+ constructor(config) {
13
+ this.count = 0;
14
+ this.limit = config.maxToolCallsPerRun;
15
+ }
16
+ /**
17
+ * Reset the call counter. Called by AuthorityLayer at the start of wrap().
18
+ */
19
+ reset() {
20
+ this.count = 0;
21
+ }
22
+ /**
23
+ * Increment the counter and check against the per-run limit.
24
+ * Returns a PendingHalt once the count exceeds the limit.
25
+ */
26
+ tick() {
27
+ this.count += 1;
28
+ if (this.count > this.limit) {
29
+ return {
30
+ status: "halted",
31
+ reason: "loop_limit_exceeded",
32
+ limit: this.limit,
33
+ spent: this.count,
34
+ };
35
+ }
36
+ return { status: "ok" };
37
+ }
38
+ getCount() {
39
+ return this.count;
40
+ }
41
+ }
42
+ exports.LoopGuard = LoopGuard;
43
+ //# sourceMappingURL=loopGuard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loopGuard.js","sourceRoot":"","sources":["../../src/enforcement/loopGuard.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,wCAAwC;AACxC,EAAE;AACF,2EAA2E;AAC3E,2EAA2E;AAC3E,iEAAiE;AACjE,gFAAgF;;;AAIhF,MAAa,SAAS;IAIlB,YAAY,MAAuB;QAH3B,UAAK,GAAG,CAAC,CAAC;QAId,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,kBAAkB,CAAC;IAC3C,CAAC;IAED;;OAEG;IACH,KAAK;QACD,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;IACnB,CAAC;IAED;;;OAGG;IACH,IAAI;QACA,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC;QAEhB,IAAI,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;YAC1B,OAAO;gBACH,MAAM,EAAE,QAAQ;gBAChB,MAAM,EAAE,qBAAqB;gBAC7B,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,KAAK,EAAE,IAAI,CAAC,KAAK;aACpB,CAAC;QACN,CAAC;QAED,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IAC5B,CAAC;IAED,QAAQ;QACJ,OAAO,IAAI,CAAC,KAAK,CAAC;IACtB,CAAC;CACJ;AArCD,8BAqCC"}
@@ -0,0 +1,20 @@
1
+ import type { ToolThrottleConfig, GuardResult } from "../types";
2
+ export declare class ToolThrottle {
3
+ /**
4
+ * Stores the timestamp (ms since epoch) of each tool call inside the
5
+ * current sliding window. Entries older than WINDOW_MS are pruned on
6
+ * every tick so the array never grows unbounded.
7
+ */
8
+ private callTimestamps;
9
+ private readonly limit;
10
+ constructor(config: ToolThrottleConfig);
11
+ /**
12
+ * Record a tool call and check the rate against the configured limit.
13
+ * Returns a PendingHalt if the call count in the last 60 seconds exceeds
14
+ * maxCallsPerMinute.
15
+ */
16
+ tick(): GuardResult;
17
+ /** Returns the number of calls recorded in the current window (for diagnostics). */
18
+ getWindowCount(): number;
19
+ }
20
+ //# sourceMappingURL=toolThrottle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolThrottle.d.ts","sourceRoot":"","sources":["../../src/enforcement/toolThrottle.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAIhE,qBAAa,YAAY;IACrB;;;;OAIG;IACH,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;gBAEnB,MAAM,EAAE,kBAAkB;IAItC;;;;OAIG;IACH,IAAI,IAAI,WAAW;IAuBnB,oFAAoF;IACpF,cAAc,IAAI,MAAM;CAI3B"}
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ // ─────────────────────────────────────────────────────────────────────────────
3
+ // ToolThrottle — Sliding-Window Rate Limiter
4
+ //
5
+ // Caps the number of tool calls within any 60-second window using a sliding
6
+ // timestamp array. Unlike a fixed-bucket approach, this never resets abruptly
7
+ // mid-window — it always reflects the true call density in the last minute.
8
+ // ─────────────────────────────────────────────────────────────────────────────
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.ToolThrottle = void 0;
11
+ const WINDOW_MS = 60000; // 1-minute sliding window
12
+ class ToolThrottle {
13
+ constructor(config) {
14
+ /**
15
+ * Stores the timestamp (ms since epoch) of each tool call inside the
16
+ * current sliding window. Entries older than WINDOW_MS are pruned on
17
+ * every tick so the array never grows unbounded.
18
+ */
19
+ this.callTimestamps = [];
20
+ this.limit = config.maxCallsPerMinute;
21
+ }
22
+ /**
23
+ * Record a tool call and check the rate against the configured limit.
24
+ * Returns a PendingHalt if the call count in the last 60 seconds exceeds
25
+ * maxCallsPerMinute.
26
+ */
27
+ tick() {
28
+ const now = Date.now();
29
+ // Evict calls that have slid out of the window
30
+ this.callTimestamps = this.callTimestamps.filter((t) => now - t < WINDOW_MS);
31
+ this.callTimestamps.push(now);
32
+ const callsInWindow = this.callTimestamps.length;
33
+ if (callsInWindow > this.limit) {
34
+ return {
35
+ status: "halted",
36
+ reason: "tool_throttle_exceeded",
37
+ limit: this.limit,
38
+ spent: callsInWindow,
39
+ };
40
+ }
41
+ return { status: "ok" };
42
+ }
43
+ /** Returns the number of calls recorded in the current window (for diagnostics). */
44
+ getWindowCount() {
45
+ const now = Date.now();
46
+ return this.callTimestamps.filter((t) => now - t < WINDOW_MS).length;
47
+ }
48
+ }
49
+ exports.ToolThrottle = ToolThrottle;
50
+ //# sourceMappingURL=toolThrottle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolThrottle.js","sourceRoot":"","sources":["../../src/enforcement/toolThrottle.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,6CAA6C;AAC7C,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,4EAA4E;AAC5E,gFAAgF;;;AAIhF,MAAM,SAAS,GAAG,KAAM,CAAC,CAAC,0BAA0B;AAEpD,MAAa,YAAY;IASrB,YAAY,MAA0B;QARtC;;;;WAIG;QACK,mBAAc,GAAa,EAAE,CAAC;QAIlC,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,iBAAiB,CAAC;IAC1C,CAAC;IAED;;;;OAIG;IACH,IAAI;QACA,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEvB,+CAA+C;QAC/C,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,CAC5C,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,GAAG,SAAS,CAC7B,CAAC;QAEF,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC9B,MAAM,aAAa,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC;QAEjD,IAAI,aAAa,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;YAC7B,OAAO;gBACH,MAAM,EAAE,QAAQ;gBAChB,MAAM,EAAE,wBAAwB;gBAChC,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,KAAK,EAAE,aAAa;aACvB,CAAC;QACN,CAAC;QAED,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IAC5B,CAAC;IAED,oFAAoF;IACpF,cAAc;QACV,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,OAAO,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,GAAG,SAAS,CAAC,CAAC,MAAM,CAAC;IACzE,CAAC;CACJ;AA9CD,oCA8CC"}
@@ -0,0 +1,4 @@
1
+ export { AuthorityLayer } from "./AuthorityLayer";
2
+ export { EnforcementHalt } from "./EnforcementHalt";
3
+ export type { AuthorityConfig, BudgetConfig, LoopGuardConfig, ToolThrottleConfig, EnforcementMode, HaltResult, HaltReason, PassResult, GuardResult, EnforcementEvent, } from "./types";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,YAAY,EACR,eAAe,EACf,YAAY,EACZ,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,UAAU,EACV,UAAU,EACV,UAAU,EACV,WAAW,EACX,gBAAgB,GACnB,MAAM,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ // Public surface of the authority-layer package.
3
+ // Import from here, not from internal module paths.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.EnforcementHalt = exports.AuthorityLayer = void 0;
6
+ var AuthorityLayer_1 = require("./AuthorityLayer");
7
+ Object.defineProperty(exports, "AuthorityLayer", { enumerable: true, get: function () { return AuthorityLayer_1.AuthorityLayer; } });
8
+ var EnforcementHalt_1 = require("./EnforcementHalt");
9
+ Object.defineProperty(exports, "EnforcementHalt", { enumerable: true, get: function () { return EnforcementHalt_1.EnforcementHalt; } });
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,iDAAiD;AACjD,oDAAoD;;;AAEpD,mDAAkD;AAAzC,gHAAA,cAAc,OAAA;AACvB,qDAAoD;AAA3C,kHAAA,eAAe,OAAA"}
@@ -0,0 +1,27 @@
1
+ import type { EnforcementEvent } from "../types";
2
+ export declare class HashChain {
3
+ private readonly chain;
4
+ private previousHash;
5
+ /**
6
+ * Append a new event to the chain.
7
+ *
8
+ * The hash covers the serialized event fields (event_id, type, timestamp,
9
+ * data) concatenated with the previous event's hash. This means you cannot
10
+ * alter any event — or its position in the chain — without invalidating all
11
+ * subsequent hashes.
12
+ */
13
+ append(type: string, data: Record<string, unknown>): EnforcementEvent;
14
+ /**
15
+ * Return an immutable copy of the full event chain.
16
+ */
17
+ getChain(): ReadonlyArray<EnforcementEvent>;
18
+ /**
19
+ * Verify the integrity of the entire chain locally.
20
+ *
21
+ * Re-derives each event's hash from its fields and previousHash, then
22
+ * compares against the stored hash. Returns false if any event has been
23
+ * tampered with or if the linkage is broken.
24
+ */
25
+ verify(): boolean;
26
+ }
27
+ //# sourceMappingURL=hashChain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hashChain.d.ts","sourceRoot":"","sources":["../../src/integrity/hashChain.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAKjD,qBAAa,SAAS;IAClB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA0B;IAChD,OAAO,CAAC,YAAY,CAAwB;IAE5C;;;;;;;OAOG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,gBAAgB;IAyBrE;;OAEG;IACH,QAAQ,IAAI,aAAa,CAAC,gBAAgB,CAAC;IAI3C;;;;;;OAMG;IACH,MAAM,IAAI,OAAO;CA4BpB"}
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ // ─────────────────────────────────────────────────────────────────────────────
3
+ // HashChain — Tamper-Evident Enforcement Event Log
4
+ //
5
+ // Stores enforcement events in memory as a hash-linked chain. Each event
6
+ // includes a SHA-256 hash chained to the previous event's hash, making it
7
+ // detectable if any event is retroactively altered or removed.
8
+ //
9
+ // V1: in-memory only. No disk persistence or cloud anchoring.
10
+ // Future: optional disk flush and independent cloud anchor.
11
+ // ─────────────────────────────────────────────────────────────────────────────
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.HashChain = void 0;
14
+ const crypto_1 = require("crypto");
15
+ /** Sentinel value used as the previousHash for the first event in the chain. */
16
+ const GENESIS_HASH = "genesis";
17
+ class HashChain {
18
+ constructor() {
19
+ this.chain = [];
20
+ this.previousHash = GENESIS_HASH;
21
+ }
22
+ /**
23
+ * Append a new event to the chain.
24
+ *
25
+ * The hash covers the serialized event fields (event_id, type, timestamp,
26
+ * data) concatenated with the previous event's hash. This means you cannot
27
+ * alter any event — or its position in the chain — without invalidating all
28
+ * subsequent hashes.
29
+ */
30
+ append(type, data) {
31
+ const event_id = `evt_${(0, crypto_1.randomBytes)(8).toString("hex")}`;
32
+ const timestamp = new Date().toISOString();
33
+ // Hash covers content + chain position (previousHash)
34
+ const payload = JSON.stringify({ event_id, type, timestamp, data });
35
+ const hash = (0, crypto_1.createHash)("sha256")
36
+ .update(payload + this.previousHash)
37
+ .digest("hex");
38
+ const event = {
39
+ event_id,
40
+ type,
41
+ timestamp,
42
+ data,
43
+ hash,
44
+ previousHash: this.previousHash,
45
+ };
46
+ this.chain.push(event);
47
+ this.previousHash = hash;
48
+ return event;
49
+ }
50
+ /**
51
+ * Return an immutable copy of the full event chain.
52
+ */
53
+ getChain() {
54
+ return Object.freeze([...this.chain]);
55
+ }
56
+ /**
57
+ * Verify the integrity of the entire chain locally.
58
+ *
59
+ * Re-derives each event's hash from its fields and previousHash, then
60
+ * compares against the stored hash. Returns false if any event has been
61
+ * tampered with or if the linkage is broken.
62
+ */
63
+ verify() {
64
+ let prev = GENESIS_HASH;
65
+ for (const event of this.chain) {
66
+ if (event.previousHash !== prev) {
67
+ return false;
68
+ }
69
+ const payload = JSON.stringify({
70
+ event_id: event.event_id,
71
+ type: event.type,
72
+ timestamp: event.timestamp,
73
+ data: event.data,
74
+ });
75
+ const expected = (0, crypto_1.createHash)("sha256")
76
+ .update(payload + prev)
77
+ .digest("hex");
78
+ if (expected !== event.hash) {
79
+ return false;
80
+ }
81
+ prev = event.hash;
82
+ }
83
+ return true;
84
+ }
85
+ }
86
+ exports.HashChain = HashChain;
87
+ //# sourceMappingURL=hashChain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hashChain.js","sourceRoot":"","sources":["../../src/integrity/hashChain.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,mDAAmD;AACnD,EAAE;AACF,yEAAyE;AACzE,0EAA0E;AAC1E,+DAA+D;AAC/D,EAAE;AACF,8DAA8D;AAC9D,4DAA4D;AAC5D,gFAAgF;;;AAEhF,mCAAiD;AAGjD,gFAAgF;AAChF,MAAM,YAAY,GAAG,SAAS,CAAC;AAE/B,MAAa,SAAS;IAAtB;QACqB,UAAK,GAAuB,EAAE,CAAC;QACxC,iBAAY,GAAW,YAAY,CAAC;IA6EhD,CAAC;IA3EG;;;;;;;OAOG;IACH,MAAM,CAAC,IAAY,EAAE,IAA6B;QAC9C,MAAM,QAAQ,GAAG,OAAO,IAAA,oBAAW,EAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACzD,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAE3C,sDAAsD;QACtD,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACpE,MAAM,IAAI,GAAG,IAAA,mBAAU,EAAC,QAAQ,CAAC;aAC5B,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC;aACnC,MAAM,CAAC,KAAK,CAAC,CAAC;QAEnB,MAAM,KAAK,GAAqB;YAC5B,QAAQ;YACR,IAAI;YACJ,SAAS;YACT,IAAI;YACJ,IAAI;YACJ,YAAY,EAAE,IAAI,CAAC,YAAY;SAClC,CAAC;QAEF,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QAEzB,OAAO,KAAK,CAAC;IACjB,CAAC;IAED;;OAEG;IACH,QAAQ;QACJ,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IAC1C,CAAC;IAED;;;;;;OAMG;IACH,MAAM;QACF,IAAI,IAAI,GAAG,YAAY,CAAC;QAExB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC7B,IAAI,KAAK,CAAC,YAAY,KAAK,IAAI,EAAE,CAAC;gBAC9B,OAAO,KAAK,CAAC;YACjB,CAAC;YAED,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC;gBAC3B,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,IAAI,EAAE,KAAK,CAAC,IAAI;aACnB,CAAC,CAAC;YAEH,MAAM,QAAQ,GAAG,IAAA,mBAAU,EAAC,QAAQ,CAAC;iBAChC,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;iBACtB,MAAM,CAAC,KAAK,CAAC,CAAC;YAEnB,IAAI,QAAQ,KAAK,KAAK,CAAC,IAAI,EAAE,CAAC;gBAC1B,OAAO,KAAK,CAAC;YACjB,CAAC;YAED,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;QACtB,CAAC;QAED,OAAO,IAAI,CAAC;IAChB,CAAC;CACJ;AA/ED,8BA+EC"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Enforcement mode.
3
+ * "strict" — limits halt execution immediately (default, V1 implemented)
4
+ * "warn" — limits emit a warning but allow continuation (V1 stubbed)
5
+ */
6
+ export type EnforcementMode = "strict" | "warn";
7
+ export interface BudgetConfig {
8
+ /** Hard daily spend cap in USD. Execution halts if cumulative spend exceeds this. */
9
+ dailyUSD: number;
10
+ }
11
+ export interface LoopGuardConfig {
12
+ /** Maximum number of tool calls allowed per wrap() invocation. */
13
+ maxToolCallsPerRun: number;
14
+ }
15
+ export interface ToolThrottleConfig {
16
+ /** Maximum number of tool calls allowed within any 60-second sliding window. */
17
+ maxCallsPerMinute: number;
18
+ }
19
+ export interface AuthorityConfig {
20
+ /**
21
+ * Enforcement mode. Defaults to "strict".
22
+ * In V1, only "strict" is fully implemented. "warn" is stubbed.
23
+ */
24
+ mode?: EnforcementMode;
25
+ /** Enable hard USD budget cap. Omit to disable. */
26
+ budget?: BudgetConfig;
27
+ /** Enable loop/call-count guard per run. Omit to disable. */
28
+ loopGuard?: LoopGuardConfig;
29
+ /** Enable tool call rate throttle. Omit to disable. */
30
+ toolThrottle?: ToolThrottleConfig;
31
+ }
32
+ export type HaltReason = "budget_exceeded" | "loop_limit_exceeded" | "tool_throttle_exceeded";
33
+ /**
34
+ * Internal guard result before the event chain assigns an event_id.
35
+ * Guards return this; AuthorityLayer promotes it to HaltResult after logging.
36
+ */
37
+ export interface PendingHalt {
38
+ status: "halted";
39
+ reason: HaltReason;
40
+ /** The configured limit that was breached. */
41
+ limit: number;
42
+ /** The value that exceeded the limit (spend, call count, etc.). */
43
+ spent: number;
44
+ }
45
+ /**
46
+ * The public enforcement halt object. Returned on the EnforcementHalt error
47
+ * and also accessible via .enforcement on that error instance.
48
+ *
49
+ * Always prefer accessing this via `error.enforcement` rather than parsing
50
+ * the error message string.
51
+ */
52
+ export interface HaltResult extends PendingHalt {
53
+ /** Unique event ID assigned by the hash-linked event chain. */
54
+ event_id: string;
55
+ }
56
+ export interface PassResult {
57
+ status: "ok";
58
+ }
59
+ /** Union returned by all guard check methods. */
60
+ export type GuardResult = PendingHalt | PassResult;
61
+ /**
62
+ * A single entry in the enforcement event chain.
63
+ * Each event is hash-linked to its predecessor, forming a tamper-evident log.
64
+ */
65
+ export interface EnforcementEvent {
66
+ /** Unique identifier (evt_<random hex>). */
67
+ event_id: string;
68
+ /** Semantic event type, e.g. "enforcement.halt", "tool.call", "run.start". */
69
+ type: string;
70
+ /** ISO-8601 timestamp of the event. */
71
+ timestamp: string;
72
+ /** Arbitrary structured data for this event. */
73
+ data: Record<string, unknown>;
74
+ /** SHA-256 of (serialized event fields + previousHash). */
75
+ hash: string;
76
+ /** Hash of the preceding event ("genesis" for the first event). */
77
+ previousHash: string;
78
+ }
79
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAOA;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,MAAM,CAAC;AAIhD,MAAM,WAAW,YAAY;IAC3B,qFAAqF;IACrF,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,kEAAkE;IAClE,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,kBAAkB;IACjC,gFAAgF;IAChF,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAID,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,IAAI,CAAC,EAAE,eAAe,CAAC;IAEvB,mDAAmD;IACnD,MAAM,CAAC,EAAE,YAAY,CAAC;IAEtB,6DAA6D;IAC7D,SAAS,CAAC,EAAE,eAAe,CAAC;IAE5B,uDAAuD;IACvD,YAAY,CAAC,EAAE,kBAAkB,CAAC;CACnC;AAID,MAAM,MAAM,UAAU,GAClB,iBAAiB,GACjB,qBAAqB,GACrB,wBAAwB,CAAC;AAE7B;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,QAAQ,CAAC;IACjB,MAAM,EAAE,UAAU,CAAC;IACnB,8CAA8C;IAC9C,KAAK,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;GAMG;AACH,MAAM,WAAW,UAAW,SAAQ,WAAW;IAC7C,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,IAAI,CAAC;CACd;AAED,iDAAiD;AACjD,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,UAAU,CAAC;AAInD;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAC;IACb,uCAAuC;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,mEAAmE;IACnE,YAAY,EAAE,MAAM,CAAC;CACtB"}
package/dist/types.js ADDED
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ // ─────────────────────────────────────────────────────────────────────────────
3
+ // AuthorityLayer — Shared Types
4
+ //
5
+ // All interfaces used across enforcement primitives and the core class live
6
+ // here. Keeping them in one file makes cross-module consistency easy to audit.
7
+ // ─────────────────────────────────────────────────────────────────────────────
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,gCAAgC;AAChC,EAAE;AACF,4EAA4E;AAC5E,+EAA+E;AAC/E,gFAAgF"}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "authority-layer",
3
+ "version": "0.1.0",
4
+ "description": "Hard execution and budget limits for autonomous agents — enforced locally.",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "bin": {
11
+ "authority-layer": "dist/doctor.js"
12
+ },
13
+ "scripts": {
14
+ "build": "tsc -p tsconfig.json",
15
+ "dev": "tsc -p tsconfig.json --watch",
16
+ "typecheck": "tsc -p tsconfig.json --noEmit",
17
+ "validate": "tsc -p tsconfig.json && node dist/index.js",
18
+ "example": "node ../../examples/run.js",
19
+ "doctor": "node dist/doctor.js",
20
+ "prepublishOnly": "npm run build && npm run typecheck"
21
+ },
22
+ "keywords": [
23
+ "ai",
24
+ "agents",
25
+ "guardrails",
26
+ "runtime",
27
+ "budget",
28
+ "limits"
29
+ ],
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "https://github.com/032383justin/authority-layer"
33
+ },
34
+ "homepage": "https://github.com/032383justin/authority-layer",
35
+ "bugs": {
36
+ "url": "https://github.com/032383justin/authority-layer/issues"
37
+ },
38
+ "license": "MIT",
39
+ "engines": {
40
+ "node": ">=18.0.0"
41
+ },
42
+ "devDependencies": {
43
+ "typescript": "^5.4.0",
44
+ "@types/node": "^20.0.0"
45
+ }
46
+ }