@amboras-dev/capability-kit 0.2.1 → 0.3.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 +7 -6
- package/dist/index.cjs +23 -24
- package/dist/index.d.cts +0 -22
- package/dist/index.d.ts +0 -22
- package/dist/index.js +11 -22
- package/package.json +10 -9
package/README.md
CHANGED
|
@@ -6,8 +6,9 @@ merchant action: id, zod input/output, policy and agent text. The kit checks it
|
|
|
6
6
|
once, converts money at one boundary, answers errors in one shape and emits a
|
|
7
7
|
hashed manifest the other repo re-checks on load. CommonJS + ESM + types; Node >= 20 and
|
|
8
8
|
browsers. One runtime dependency, `@amboras-dev/money` (the storage rule, conversion
|
|
9
|
-
and money view; the kit pins its exact version), and the `zod` peer (`^3.25.76 || ^4.
|
|
10
|
-
imported only as `zod/v4`; zod 3.25.0 ships without `dist/` and cannot load `zod/v4
|
|
9
|
+
and money view; the kit pins its exact version), and the `zod` peer (`^3.25.76 || ^4.6.6`,
|
|
10
|
+
imported only as `zod/v4`; zod 3.25.0 ships without `dist/` and cannot load `zod/v4`;
|
|
11
|
+
the 4.x floor is 4.6.6, the first release patched for GHSA-mrhx-c7xc-m3w5, which has no 3.x fix).
|
|
11
12
|
|
|
12
13
|
```ts
|
|
13
14
|
import { defineCapability, money, toStorageAmount, moneyView, emitManifest, parseManifest } from '@amboras-dev/capability-kit'
|
|
@@ -136,8 +137,8 @@ count, or a count that is not a non-negative integer.
|
|
|
136
137
|
loose objects, so a field added by a newer kit passes through and stays covered
|
|
137
138
|
by the hash. The hash proves integrity, not origin: trust comes from reading the
|
|
138
139
|
committed file.
|
|
139
|
-
- **zod 3.25 and 4.x.** The suite runs three times: on zod 4.
|
|
140
|
-
(`vitest.
|
|
140
|
+
- **zod 3.25 and 4.x.** The suite runs three times: on zod 4.6.7, on zod 4.6.6
|
|
141
|
+
(`vitest.zod46.config.ts`, the 4.x floor) and on zod 3.25.76's `zod/v4`
|
|
141
142
|
(`vitest.zod3.config.ts`); types are checked against all three. A manifest
|
|
142
143
|
emitted on 3.25 (`test-fixtures/manifest.zod-3.25.json`) parses on every line,
|
|
143
144
|
and each line's hash is pinned. zod 3.25's
|
|
@@ -152,8 +153,8 @@ count, or a count that is not a non-negative integer.
|
|
|
152
153
|
## Testing
|
|
153
154
|
|
|
154
155
|
```bash
|
|
155
|
-
pnpm test # vitest + 100% coverage on zod 4.
|
|
156
|
-
pnpm typecheck # src (no Node types), tests, and src+tests against zod 3.25 and 4.
|
|
156
|
+
pnpm test # vitest + 100% coverage on zod 4.6.7, then the same suite on 3.25.76 and 4.6.6
|
|
157
|
+
pnpm typecheck # src (no Node types), tests, and src+tests against zod 3.25 and 4.6.6 types
|
|
157
158
|
# regenerate the 3.25 manifest fixture after a deliberate change:
|
|
158
159
|
UPDATE_FIXTURES=1 npx vitest run --config vitest.zod3.config.ts src/manifest-cross-zod.test.ts
|
|
159
160
|
```
|
package/dist/index.cjs
CHANGED
|
@@ -2,7 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
2
2
|
let zod_v4 = require("zod/v4");
|
|
3
3
|
let _amboras_dev_money = require("@amboras-dev/money");
|
|
4
4
|
let _amboras_dev_money_ai = require("@amboras-dev/money/ai");
|
|
5
|
-
|
|
5
|
+
// src/canonical-json.ts
|
|
6
6
|
function serialize(value, seen) {
|
|
7
7
|
if (value !== null && typeof value === "object" && typeof value.toJSON === "function") value = value.toJSON();
|
|
8
8
|
if (value === null) return "null";
|
|
@@ -35,8 +35,7 @@ function serialize(value, seen) {
|
|
|
35
35
|
function canonicalJson(v) {
|
|
36
36
|
return serialize(v, /* @__PURE__ */ new Set()) ?? "null";
|
|
37
37
|
}
|
|
38
|
-
|
|
39
|
-
//#region src/errors.ts
|
|
38
|
+
// src/errors.ts
|
|
40
39
|
const STATUS = {
|
|
41
40
|
invalid_input: 400,
|
|
42
41
|
forbidden: 403,
|
|
@@ -165,8 +164,7 @@ function fromZodError(err, options = {}) {
|
|
|
165
164
|
issues
|
|
166
165
|
});
|
|
167
166
|
}
|
|
168
|
-
|
|
169
|
-
//#region src/ids.ts
|
|
167
|
+
// src/ids.ts
|
|
170
168
|
const AREAS = [
|
|
171
169
|
"promotions",
|
|
172
170
|
"catalog",
|
|
@@ -197,8 +195,7 @@ function areaOf(id) {
|
|
|
197
195
|
function isRole(value) {
|
|
198
196
|
return value === "owner" || value === "manager" || value === "staff";
|
|
199
197
|
}
|
|
200
|
-
|
|
201
|
-
//#region src/money.ts
|
|
198
|
+
// src/money.ts
|
|
202
199
|
/**
|
|
203
200
|
* A bad amount or currency code. It is an `invalid_input` CapabilityError, so an
|
|
204
201
|
* adapter that maps CapabilityError answers 400 with the rule (and the field,
|
|
@@ -354,8 +351,7 @@ function moneyView(minor, currency) {
|
|
|
354
351
|
throw toCapabilityMoneyError(error);
|
|
355
352
|
}
|
|
356
353
|
}
|
|
357
|
-
|
|
358
|
-
//#region src/json-schema.ts
|
|
354
|
+
// src/json-schema.ts
|
|
359
355
|
/**
|
|
360
356
|
* The exact conversion every manifest uses. Throws for types JSON Schema cannot
|
|
361
357
|
* express. Every money() field gets its marker back, and its unit sentence when
|
|
@@ -433,8 +429,7 @@ function omitFields(schema, fields) {
|
|
|
433
429
|
}
|
|
434
430
|
return copy;
|
|
435
431
|
}
|
|
436
|
-
|
|
437
|
-
//#region src/guards.ts
|
|
432
|
+
// src/guards.ts
|
|
438
433
|
/**
|
|
439
434
|
* Tenant and actor ids come from the call context, never from input. A name is
|
|
440
435
|
* refused when, lower-cased with separators removed, it ends in one of these
|
|
@@ -587,8 +582,7 @@ function checkEntry(entry) {
|
|
|
587
582
|
if (typeof entry.agent.description !== "string" || entry.agent.description.trim() === "") fail(id, "agent.description is required");
|
|
588
583
|
if (entry.agent.toolName !== void 0 && !TOOL_NAME.test(entry.agent.toolName)) fail(id, `agent.toolName must match ${TOOL_NAME}`);
|
|
589
584
|
}
|
|
590
|
-
|
|
591
|
-
//#region src/define.ts
|
|
585
|
+
// src/define.ts
|
|
592
586
|
function convert(schema, io, id) {
|
|
593
587
|
try {
|
|
594
588
|
return toJsonSchema(schema, io);
|
|
@@ -638,8 +632,7 @@ function defineCapability(def) {
|
|
|
638
632
|
agent: freezeCopy(def.agent)
|
|
639
633
|
});
|
|
640
634
|
}
|
|
641
|
-
|
|
642
|
-
//#region src/sha256.ts
|
|
635
|
+
// src/sha256.ts
|
|
643
636
|
const K = new Uint32Array([
|
|
644
637
|
1116352408,
|
|
645
638
|
1899447441,
|
|
@@ -782,8 +775,7 @@ function sha256Hex(text) {
|
|
|
782
775
|
for (const word of h) hex += word.toString(16).padStart(8, "0");
|
|
783
776
|
return hex;
|
|
784
777
|
}
|
|
785
|
-
|
|
786
|
-
//#region src/idempotency.ts
|
|
778
|
+
// src/idempotency.ts
|
|
787
779
|
/**
|
|
788
780
|
* 8–100 of `A-Z a-z 0-9 . _ : -`. The underscore is there because the
|
|
789
781
|
* orchestrator's key is `cap.{runId}.{toolCallId}` and model tool call ids
|
|
@@ -801,8 +793,7 @@ function requestFingerprint(id, input) {
|
|
|
801
793
|
input
|
|
802
794
|
}));
|
|
803
795
|
}
|
|
804
|
-
|
|
805
|
-
//#region src/manifest.ts
|
|
796
|
+
// src/manifest.ts
|
|
806
797
|
const hashOf = (capabilities) => sha256Hex(canonicalJson(capabilities));
|
|
807
798
|
/** Plain JSON with keys sorted at every level, so the committed file is stable text. */
|
|
808
799
|
const sortedJson = (value) => JSON.parse(canonicalJson(value));
|
|
@@ -926,8 +917,7 @@ function parseManifest(json) {
|
|
|
926
917
|
if (actual !== manifest.hash) throw new CapabilityManifestError(`Capability manifest hash mismatch: header ${manifest.hash}, content ${actual}`);
|
|
927
918
|
return manifest;
|
|
928
919
|
}
|
|
929
|
-
|
|
930
|
-
//#region src/policy.ts
|
|
920
|
+
// src/policy.ts
|
|
931
921
|
function roleCheck(policy, ctx) {
|
|
932
922
|
const { actor } = ctx;
|
|
933
923
|
if (actor.kind === "internal") return null;
|
|
@@ -1014,14 +1004,23 @@ function confirmationRequired(policy, records) {
|
|
|
1014
1004
|
if (typeof records !== "number" || !Number.isInteger(records) || records < 0) return true;
|
|
1015
1005
|
return records >= confirm.when.recordsAtLeast;
|
|
1016
1006
|
}
|
|
1017
|
-
//#endregion
|
|
1018
1007
|
exports.AREAS = AREAS;
|
|
1019
1008
|
exports.CapabilityDefinitionError = CapabilityDefinitionError;
|
|
1020
1009
|
exports.CapabilityError = CapabilityError;
|
|
1021
1010
|
exports.CapabilityManifestError = CapabilityManifestError;
|
|
1022
1011
|
exports.IDEMPOTENCY_KEY_PATTERN = IDEMPOTENCY_KEY_PATTERN;
|
|
1023
|
-
exports
|
|
1024
|
-
|
|
1012
|
+
Object.defineProperty(exports, "MONEY_META_KEY", {
|
|
1013
|
+
enumerable: true,
|
|
1014
|
+
get: function() {
|
|
1015
|
+
return _amboras_dev_money_ai.MONEY_META_KEY;
|
|
1016
|
+
}
|
|
1017
|
+
});
|
|
1018
|
+
Object.defineProperty(exports, "MONEY_UNIT_SENTENCE", {
|
|
1019
|
+
enumerable: true,
|
|
1020
|
+
get: function() {
|
|
1021
|
+
return _amboras_dev_money_ai.MONEY_UNIT_SENTENCE;
|
|
1022
|
+
}
|
|
1023
|
+
});
|
|
1025
1024
|
exports.MoneyError = MoneyError;
|
|
1026
1025
|
exports.ROLE_RANK = ROLE_RANK;
|
|
1027
1026
|
exports.areaOf = areaOf;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
2
|
import { MONEY_META_KEY, MONEY_UNIT_SENTENCE } from "@amboras-dev/money/ai";
|
|
3
|
-
//#region src/canonical-json.d.ts
|
|
4
3
|
/** Sorted keys, no whitespace. Throws on BigInt and circular values; `undefined` at the top serializes as `null`. */
|
|
5
4
|
export declare function canonicalJson(v: unknown): string;
|
|
6
|
-
//#endregion
|
|
7
|
-
//#region src/ids.d.ts
|
|
8
5
|
export declare const AREAS: readonly ["promotions", "catalog", "inventory", "setup", "content", "orders", "payments", "domains", "publish"];
|
|
9
6
|
type Area = (typeof AREAS)[number];
|
|
10
7
|
/** `<area>.<verb>` or `<area>.<entity>.<verb>`: lowercase segments of `a-z` and `_`. */
|
|
@@ -16,8 +13,6 @@ export declare const ROLE_RANK: Readonly<Record<Role, number>>;
|
|
|
16
13
|
export declare function isCapabilityId(value: unknown): value is CapabilityId;
|
|
17
14
|
/** The area an id belongs to (`promotions.create` → `promotions`). */
|
|
18
15
|
export declare function areaOf(id: CapabilityId): Area;
|
|
19
|
-
//#endregion
|
|
20
|
-
//#region src/context.d.ts
|
|
21
16
|
type Actor = {
|
|
22
17
|
kind: 'member';
|
|
23
18
|
profileId: string;
|
|
@@ -34,8 +29,6 @@ interface CapabilityCallContext {
|
|
|
34
29
|
surface: Surface;
|
|
35
30
|
runId?: string;
|
|
36
31
|
}
|
|
37
|
-
//#endregion
|
|
38
|
-
//#region src/json-schema.d.ts
|
|
39
32
|
type JsonSchema = {
|
|
40
33
|
[key: string]: unknown;
|
|
41
34
|
};
|
|
@@ -44,8 +37,6 @@ type JsonSchema = {
|
|
|
44
37
|
* dropped from `required`. Adapters build the model-facing input with this.
|
|
45
38
|
*/
|
|
46
39
|
export declare function omitFields(schema: JsonSchema, fields: readonly string[]): JsonSchema;
|
|
47
|
-
//#endregion
|
|
48
|
-
//#region src/policy-types.d.ts
|
|
49
40
|
interface CapabilityPolicy {
|
|
50
41
|
minRole: Role;
|
|
51
42
|
planFeature?: string;
|
|
@@ -63,8 +54,6 @@ interface CapabilityPolicy {
|
|
|
63
54
|
perMinute: number;
|
|
64
55
|
};
|
|
65
56
|
}
|
|
66
|
-
//#endregion
|
|
67
|
-
//#region src/define.d.ts
|
|
68
57
|
interface CapabilityAgentSpec {
|
|
69
58
|
/** What it does and when to use it, written for the model. */
|
|
70
59
|
description: string;
|
|
@@ -107,8 +96,6 @@ interface CapabilityDefinition<I = unknown, O = unknown, Ctx = unknown> {
|
|
|
107
96
|
* minRole, confirm threshold, rate limit or toolName.
|
|
108
97
|
*/
|
|
109
98
|
export declare function defineCapability<I, O, Ctx = unknown>(def: CapabilityDefinition<I, O, Ctx>): Readonly<CapabilityDefinition<I, O, Ctx>>;
|
|
110
|
-
//#endregion
|
|
111
|
-
//#region src/errors.d.ts
|
|
112
99
|
type CapabilityErrorCode = 'invalid_input' | 'forbidden' | 'not_found' | 'conflict' | 'confirmation_required' | 'rate_limited' | 'idempotency_conflict' | 'unavailable' | 'internal';
|
|
113
100
|
interface CapabilityErrorBody {
|
|
114
101
|
code: CapabilityErrorCode;
|
|
@@ -158,8 +145,6 @@ interface FromZodErrorOptions {
|
|
|
158
145
|
* `options.renamed` for steering removed field names.
|
|
159
146
|
*/
|
|
160
147
|
export declare function fromZodError(err: z.ZodError, options?: FromZodErrorOptions): CapabilityError;
|
|
161
|
-
//#endregion
|
|
162
|
-
//#region src/idempotency.d.ts
|
|
163
148
|
/**
|
|
164
149
|
* 8–100 of `A-Z a-z 0-9 . _ : -`. The underscore is there because the
|
|
165
150
|
* orchestrator's key is `cap.{runId}.{toolCallId}` and model tool call ids
|
|
@@ -170,8 +155,6 @@ export declare const IDEMPOTENCY_KEY_PATTERN: RegExp;
|
|
|
170
155
|
export declare function requiresIdempotencyKey(policy: Pick<CapabilityPolicy, 'effect' | 'idempotent'>): boolean;
|
|
171
156
|
/** sha256 hex of canonicalJson({ id, input }): same key + different fingerprint = a different request. */
|
|
172
157
|
export declare function requestFingerprint(id: CapabilityId, input: unknown): string;
|
|
173
|
-
//#endregion
|
|
174
|
-
//#region src/manifest.d.ts
|
|
175
158
|
interface ManifestEntry {
|
|
176
159
|
id: CapabilityId;
|
|
177
160
|
version: number;
|
|
@@ -209,8 +192,6 @@ export declare function emitManifest(defs: readonly AnyCapabilityDefinition[], s
|
|
|
209
192
|
* the file is read (the committed copy), not from the hash.
|
|
210
193
|
*/
|
|
211
194
|
export declare function parseManifest(json: unknown): CapabilityManifest;
|
|
212
|
-
//#endregion
|
|
213
|
-
//#region src/money.d.ts
|
|
214
195
|
/**
|
|
215
196
|
* A bad amount or currency code. It is an `invalid_input` CapabilityError, so an
|
|
216
197
|
* adapter that maps CapabilityError answers 400 with the rule (and the field,
|
|
@@ -286,8 +267,6 @@ export declare const moneyViewSchema: z.ZodType<MoneyView>;
|
|
|
286
267
|
* unknown code throws `currency_invalid`.
|
|
287
268
|
*/
|
|
288
269
|
export declare function moneyView(minor: number, currency: string): MoneyView;
|
|
289
|
-
//#endregion
|
|
290
|
-
//#region src/policy.d.ts
|
|
291
270
|
/** Phase 1 adapters pass observe/observe. */
|
|
292
271
|
interface PolicyEnforcement {
|
|
293
272
|
role: 'enforce' | 'observe';
|
|
@@ -310,5 +289,4 @@ export declare function evaluatePolicy(policy: CapabilityPolicy, ctx: Capability
|
|
|
310
289
|
* is not a non-negative integer, requires confirmation (the adapter could not count).
|
|
311
290
|
*/
|
|
312
291
|
export declare function confirmationRequired(policy: Pick<CapabilityPolicy, 'confirm'>, records?: number): boolean;
|
|
313
|
-
//#endregion
|
|
314
292
|
export { type Actor, type AnyCapabilityDefinition, type Area, type CapabilityAgentSpec, type CapabilityCallContext, type CapabilityDefinition, type CapabilityErrorBody, type CapabilityErrorCode, type CapabilityErrorInit, type CapabilityId, type CapabilityManifest, type CapabilityPolicy, type FromZodErrorOptions, type JsonSchema, MONEY_META_KEY, MONEY_UNIT_SENTENCE, type ManifestEntry, type MoneyCurrency, type MoneyOptions, type MoneyView, type PolicyDecision, type PolicyEnforcement, type Role, type Surface };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
2
|
import { MONEY_META_KEY, MONEY_UNIT_SENTENCE } from "@amboras-dev/money/ai";
|
|
3
|
-
//#region src/canonical-json.d.ts
|
|
4
3
|
/** Sorted keys, no whitespace. Throws on BigInt and circular values; `undefined` at the top serializes as `null`. */
|
|
5
4
|
export declare function canonicalJson(v: unknown): string;
|
|
6
|
-
//#endregion
|
|
7
|
-
//#region src/ids.d.ts
|
|
8
5
|
export declare const AREAS: readonly ["promotions", "catalog", "inventory", "setup", "content", "orders", "payments", "domains", "publish"];
|
|
9
6
|
type Area = (typeof AREAS)[number];
|
|
10
7
|
/** `<area>.<verb>` or `<area>.<entity>.<verb>`: lowercase segments of `a-z` and `_`. */
|
|
@@ -16,8 +13,6 @@ export declare const ROLE_RANK: Readonly<Record<Role, number>>;
|
|
|
16
13
|
export declare function isCapabilityId(value: unknown): value is CapabilityId;
|
|
17
14
|
/** The area an id belongs to (`promotions.create` → `promotions`). */
|
|
18
15
|
export declare function areaOf(id: CapabilityId): Area;
|
|
19
|
-
//#endregion
|
|
20
|
-
//#region src/context.d.ts
|
|
21
16
|
type Actor = {
|
|
22
17
|
kind: 'member';
|
|
23
18
|
profileId: string;
|
|
@@ -34,8 +29,6 @@ interface CapabilityCallContext {
|
|
|
34
29
|
surface: Surface;
|
|
35
30
|
runId?: string;
|
|
36
31
|
}
|
|
37
|
-
//#endregion
|
|
38
|
-
//#region src/json-schema.d.ts
|
|
39
32
|
type JsonSchema = {
|
|
40
33
|
[key: string]: unknown;
|
|
41
34
|
};
|
|
@@ -44,8 +37,6 @@ type JsonSchema = {
|
|
|
44
37
|
* dropped from `required`. Adapters build the model-facing input with this.
|
|
45
38
|
*/
|
|
46
39
|
export declare function omitFields(schema: JsonSchema, fields: readonly string[]): JsonSchema;
|
|
47
|
-
//#endregion
|
|
48
|
-
//#region src/policy-types.d.ts
|
|
49
40
|
interface CapabilityPolicy {
|
|
50
41
|
minRole: Role;
|
|
51
42
|
planFeature?: string;
|
|
@@ -63,8 +54,6 @@ interface CapabilityPolicy {
|
|
|
63
54
|
perMinute: number;
|
|
64
55
|
};
|
|
65
56
|
}
|
|
66
|
-
//#endregion
|
|
67
|
-
//#region src/define.d.ts
|
|
68
57
|
interface CapabilityAgentSpec {
|
|
69
58
|
/** What it does and when to use it, written for the model. */
|
|
70
59
|
description: string;
|
|
@@ -107,8 +96,6 @@ interface CapabilityDefinition<I = unknown, O = unknown, Ctx = unknown> {
|
|
|
107
96
|
* minRole, confirm threshold, rate limit or toolName.
|
|
108
97
|
*/
|
|
109
98
|
export declare function defineCapability<I, O, Ctx = unknown>(def: CapabilityDefinition<I, O, Ctx>): Readonly<CapabilityDefinition<I, O, Ctx>>;
|
|
110
|
-
//#endregion
|
|
111
|
-
//#region src/errors.d.ts
|
|
112
99
|
type CapabilityErrorCode = 'invalid_input' | 'forbidden' | 'not_found' | 'conflict' | 'confirmation_required' | 'rate_limited' | 'idempotency_conflict' | 'unavailable' | 'internal';
|
|
113
100
|
interface CapabilityErrorBody {
|
|
114
101
|
code: CapabilityErrorCode;
|
|
@@ -158,8 +145,6 @@ interface FromZodErrorOptions {
|
|
|
158
145
|
* `options.renamed` for steering removed field names.
|
|
159
146
|
*/
|
|
160
147
|
export declare function fromZodError(err: z.ZodError, options?: FromZodErrorOptions): CapabilityError;
|
|
161
|
-
//#endregion
|
|
162
|
-
//#region src/idempotency.d.ts
|
|
163
148
|
/**
|
|
164
149
|
* 8–100 of `A-Z a-z 0-9 . _ : -`. The underscore is there because the
|
|
165
150
|
* orchestrator's key is `cap.{runId}.{toolCallId}` and model tool call ids
|
|
@@ -170,8 +155,6 @@ export declare const IDEMPOTENCY_KEY_PATTERN: RegExp;
|
|
|
170
155
|
export declare function requiresIdempotencyKey(policy: Pick<CapabilityPolicy, 'effect' | 'idempotent'>): boolean;
|
|
171
156
|
/** sha256 hex of canonicalJson({ id, input }): same key + different fingerprint = a different request. */
|
|
172
157
|
export declare function requestFingerprint(id: CapabilityId, input: unknown): string;
|
|
173
|
-
//#endregion
|
|
174
|
-
//#region src/manifest.d.ts
|
|
175
158
|
interface ManifestEntry {
|
|
176
159
|
id: CapabilityId;
|
|
177
160
|
version: number;
|
|
@@ -209,8 +192,6 @@ export declare function emitManifest(defs: readonly AnyCapabilityDefinition[], s
|
|
|
209
192
|
* the file is read (the committed copy), not from the hash.
|
|
210
193
|
*/
|
|
211
194
|
export declare function parseManifest(json: unknown): CapabilityManifest;
|
|
212
|
-
//#endregion
|
|
213
|
-
//#region src/money.d.ts
|
|
214
195
|
/**
|
|
215
196
|
* A bad amount or currency code. It is an `invalid_input` CapabilityError, so an
|
|
216
197
|
* adapter that maps CapabilityError answers 400 with the rule (and the field,
|
|
@@ -286,8 +267,6 @@ export declare const moneyViewSchema: z.ZodType<MoneyView>;
|
|
|
286
267
|
* unknown code throws `currency_invalid`.
|
|
287
268
|
*/
|
|
288
269
|
export declare function moneyView(minor: number, currency: string): MoneyView;
|
|
289
|
-
//#endregion
|
|
290
|
-
//#region src/policy.d.ts
|
|
291
270
|
/** Phase 1 adapters pass observe/observe. */
|
|
292
271
|
interface PolicyEnforcement {
|
|
293
272
|
role: 'enforce' | 'observe';
|
|
@@ -310,5 +289,4 @@ export declare function evaluatePolicy(policy: CapabilityPolicy, ctx: Capability
|
|
|
310
289
|
* is not a non-negative integer, requires confirmation (the adapter could not count).
|
|
311
290
|
*/
|
|
312
291
|
export declare function confirmationRequired(policy: Pick<CapabilityPolicy, 'confirm'>, records?: number): boolean;
|
|
313
|
-
//#endregion
|
|
314
292
|
export { type Actor, type AnyCapabilityDefinition, type Area, type CapabilityAgentSpec, type CapabilityCallContext, type CapabilityDefinition, type CapabilityErrorBody, type CapabilityErrorCode, type CapabilityErrorInit, type CapabilityId, type CapabilityManifest, type CapabilityPolicy, type FromZodErrorOptions, type JsonSchema, MONEY_META_KEY, MONEY_UNIT_SENTENCE, type ManifestEntry, type MoneyCurrency, type MoneyOptions, type MoneyView, type PolicyDecision, type PolicyEnforcement, type Role, type Surface };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
2
|
import { currencyCode, fromMajor, money as money$1, storageDigits, storageScale as storageScale$1, toMajorNumber } from "@amboras-dev/money";
|
|
3
3
|
import { MONEY_META_KEY, MONEY_UNIT_SENTENCE, moneyView as moneyView$1 } from "@amboras-dev/money/ai";
|
|
4
|
-
|
|
4
|
+
// src/canonical-json.ts
|
|
5
5
|
function serialize(value, seen) {
|
|
6
6
|
if (value !== null && typeof value === "object" && typeof value.toJSON === "function") value = value.toJSON();
|
|
7
7
|
if (value === null) return "null";
|
|
@@ -34,8 +34,7 @@ function serialize(value, seen) {
|
|
|
34
34
|
function canonicalJson(v) {
|
|
35
35
|
return serialize(v, /* @__PURE__ */ new Set()) ?? "null";
|
|
36
36
|
}
|
|
37
|
-
|
|
38
|
-
//#region src/errors.ts
|
|
37
|
+
// src/errors.ts
|
|
39
38
|
const STATUS = {
|
|
40
39
|
invalid_input: 400,
|
|
41
40
|
forbidden: 403,
|
|
@@ -164,8 +163,7 @@ function fromZodError(err, options = {}) {
|
|
|
164
163
|
issues
|
|
165
164
|
});
|
|
166
165
|
}
|
|
167
|
-
|
|
168
|
-
//#region src/ids.ts
|
|
166
|
+
// src/ids.ts
|
|
169
167
|
const AREAS = [
|
|
170
168
|
"promotions",
|
|
171
169
|
"catalog",
|
|
@@ -196,8 +194,7 @@ function areaOf(id) {
|
|
|
196
194
|
function isRole(value) {
|
|
197
195
|
return value === "owner" || value === "manager" || value === "staff";
|
|
198
196
|
}
|
|
199
|
-
|
|
200
|
-
//#region src/money.ts
|
|
197
|
+
// src/money.ts
|
|
201
198
|
/**
|
|
202
199
|
* A bad amount or currency code. It is an `invalid_input` CapabilityError, so an
|
|
203
200
|
* adapter that maps CapabilityError answers 400 with the rule (and the field,
|
|
@@ -353,8 +350,7 @@ function moneyView(minor, currency) {
|
|
|
353
350
|
throw toCapabilityMoneyError(error);
|
|
354
351
|
}
|
|
355
352
|
}
|
|
356
|
-
|
|
357
|
-
//#region src/json-schema.ts
|
|
353
|
+
// src/json-schema.ts
|
|
358
354
|
/**
|
|
359
355
|
* The exact conversion every manifest uses. Throws for types JSON Schema cannot
|
|
360
356
|
* express. Every money() field gets its marker back, and its unit sentence when
|
|
@@ -432,8 +428,7 @@ function omitFields(schema, fields) {
|
|
|
432
428
|
}
|
|
433
429
|
return copy;
|
|
434
430
|
}
|
|
435
|
-
|
|
436
|
-
//#region src/guards.ts
|
|
431
|
+
// src/guards.ts
|
|
437
432
|
/**
|
|
438
433
|
* Tenant and actor ids come from the call context, never from input. A name is
|
|
439
434
|
* refused when, lower-cased with separators removed, it ends in one of these
|
|
@@ -586,8 +581,7 @@ function checkEntry(entry) {
|
|
|
586
581
|
if (typeof entry.agent.description !== "string" || entry.agent.description.trim() === "") fail(id, "agent.description is required");
|
|
587
582
|
if (entry.agent.toolName !== void 0 && !TOOL_NAME.test(entry.agent.toolName)) fail(id, `agent.toolName must match ${TOOL_NAME}`);
|
|
588
583
|
}
|
|
589
|
-
|
|
590
|
-
//#region src/define.ts
|
|
584
|
+
// src/define.ts
|
|
591
585
|
function convert(schema, io, id) {
|
|
592
586
|
try {
|
|
593
587
|
return toJsonSchema(schema, io);
|
|
@@ -637,8 +631,7 @@ function defineCapability(def) {
|
|
|
637
631
|
agent: freezeCopy(def.agent)
|
|
638
632
|
});
|
|
639
633
|
}
|
|
640
|
-
|
|
641
|
-
//#region src/sha256.ts
|
|
634
|
+
// src/sha256.ts
|
|
642
635
|
const K = new Uint32Array([
|
|
643
636
|
1116352408,
|
|
644
637
|
1899447441,
|
|
@@ -781,8 +774,7 @@ function sha256Hex(text) {
|
|
|
781
774
|
for (const word of h) hex += word.toString(16).padStart(8, "0");
|
|
782
775
|
return hex;
|
|
783
776
|
}
|
|
784
|
-
|
|
785
|
-
//#region src/idempotency.ts
|
|
777
|
+
// src/idempotency.ts
|
|
786
778
|
/**
|
|
787
779
|
* 8–100 of `A-Z a-z 0-9 . _ : -`. The underscore is there because the
|
|
788
780
|
* orchestrator's key is `cap.{runId}.{toolCallId}` and model tool call ids
|
|
@@ -800,8 +792,7 @@ function requestFingerprint(id, input) {
|
|
|
800
792
|
input
|
|
801
793
|
}));
|
|
802
794
|
}
|
|
803
|
-
|
|
804
|
-
//#region src/manifest.ts
|
|
795
|
+
// src/manifest.ts
|
|
805
796
|
const hashOf = (capabilities) => sha256Hex(canonicalJson(capabilities));
|
|
806
797
|
/** Plain JSON with keys sorted at every level, so the committed file is stable text. */
|
|
807
798
|
const sortedJson = (value) => JSON.parse(canonicalJson(value));
|
|
@@ -925,8 +916,7 @@ function parseManifest(json) {
|
|
|
925
916
|
if (actual !== manifest.hash) throw new CapabilityManifestError(`Capability manifest hash mismatch: header ${manifest.hash}, content ${actual}`);
|
|
926
917
|
return manifest;
|
|
927
918
|
}
|
|
928
|
-
|
|
929
|
-
//#region src/policy.ts
|
|
919
|
+
// src/policy.ts
|
|
930
920
|
function roleCheck(policy, ctx) {
|
|
931
921
|
const { actor } = ctx;
|
|
932
922
|
if (actor.kind === "internal") return null;
|
|
@@ -1013,5 +1003,4 @@ function confirmationRequired(policy, records) {
|
|
|
1013
1003
|
if (typeof records !== "number" || !Number.isInteger(records) || records < 0) return true;
|
|
1014
1004
|
return records >= confirm.when.recordsAtLeast;
|
|
1015
1005
|
}
|
|
1016
|
-
//#endregion
|
|
1017
1006
|
export { AREAS, CapabilityDefinitionError, CapabilityError, CapabilityManifestError, IDEMPOTENCY_KEY_PATTERN, MONEY_META_KEY, MONEY_UNIT_SENTENCE, MoneyError, ROLE_RANK, areaOf, canonicalJson, confirmationRequired, defineCapability, emitManifest, evaluatePolicy, fractionDigits, fromStorageAmount, fromZodError, httpStatusFor, isCapabilityId, money, moneyView, moneyViewSchema, omitFields, parseManifest, requestFingerprint, requiresIdempotencyKey, storageScale, toStorageAmount };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@amboras-dev/capability-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Capability contract for Amboras: defineCapability, major-unit money (on @amboras-dev/money), the shared error contract, pure policy evaluation, idempotency helpers and a deterministic manifest. Peer dependency on zod.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"repository": {
|
|
@@ -36,25 +36,26 @@
|
|
|
36
36
|
"access": "public"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@amboras-dev/money": "0.
|
|
39
|
+
"@amboras-dev/money": "0.4.0"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
|
-
"zod": "^3.25.76 || ^4.
|
|
42
|
+
"zod": "^3.25.76 || ^4.6.6"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@types/node": "22.20.5",
|
|
46
|
-
"@vitest/coverage-v8": "
|
|
46
|
+
"@vitest/coverage-v8": "5.0.5",
|
|
47
47
|
"fast-check": "4.3.0",
|
|
48
48
|
"tsdown": "0.23.0",
|
|
49
49
|
"typescript": "5.9.3",
|
|
50
|
-
"
|
|
51
|
-
"
|
|
50
|
+
"vite": "8.3.5",
|
|
51
|
+
"vitest": "5.0.5",
|
|
52
|
+
"zod": "4.6.7",
|
|
52
53
|
"zod3": "npm:zod@3.25.76",
|
|
53
|
-
"
|
|
54
|
+
"zod46": "npm:zod@4.6.6"
|
|
54
55
|
},
|
|
55
56
|
"scripts": {
|
|
56
57
|
"build": "tsdown",
|
|
57
|
-
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.test.json && tsc --noEmit -p tsconfig.zod3.json && tsc --noEmit -p tsconfig.
|
|
58
|
-
"test": "vitest run --coverage && vitest run --config vitest.zod3.config.ts && vitest run --config vitest.
|
|
58
|
+
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.test.json && tsc --noEmit -p tsconfig.zod3.json && tsc --noEmit -p tsconfig.zod46.json",
|
|
59
|
+
"test": "vitest run --coverage && vitest run --config vitest.zod3.config.ts && vitest run --config vitest.zod46.config.ts"
|
|
59
60
|
}
|
|
60
61
|
}
|