@coproduct_inc/verify 0.1.0 → 0.2.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.
- package/CHANGELOG.md +33 -0
- package/README.md +24 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -0
- package/dist/producer-cli.d.ts +16 -0
- package/dist/producer-cli.js +84 -0
- package/dist/toolproxy.d.ts +75 -0
- package/dist/toolproxy.js +74 -0
- package/package.json +9 -3
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@coproduct_inc/verify`.
|
|
4
|
+
|
|
5
|
+
## 0.2.0
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- **Producer-side instrumentation** — turn a nucleus-tool-proxy trace into a
|
|
9
|
+
signed in-bounds attestation receipt.
|
|
10
|
+
- `./toolproxy` export: `attestToolProxyRun`, `boundaryFromExport`,
|
|
11
|
+
`traceEventsFromRecords`, `parseExport`. Maps the tool-proxy's verdict
|
|
12
|
+
records (`actor`/`operation`/`verdict`/`subject`/`deny_reason`, mirroring
|
|
13
|
+
the `verdict_sink` `tool_call` span) into the receipt schema and signs it.
|
|
14
|
+
Includes a cross-check that the proxy's own allow/deny agrees with the
|
|
15
|
+
receipt's independently recomputed verdict (surfaces boundary drift).
|
|
16
|
+
- `nucleus-attest` bin: read a trace export (stdin or file), sign a receipt.
|
|
17
|
+
With `--key <pkcs8.pem>` uses a real key; otherwise an ephemeral in-memory
|
|
18
|
+
key (no custody), printing the public key to stderr.
|
|
19
|
+
- Release workflow: OIDC trusted publishing to npm (no stored token).
|
|
20
|
+
|
|
21
|
+
## 0.1.0
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
- **Capability-boundary in-bounds attestation** — the headline evidence layer.
|
|
25
|
+
- `verifyReceipt` / `verifyReceiptJson`: offline, zero-trust verification of
|
|
26
|
+
an Ed25519-signed, SHA-256-hash-chained receipt that an agent run stayed
|
|
27
|
+
within a declared capability boundary, keyed on a cryptographic principal
|
|
28
|
+
(SPIFFE id + permission fingerprint), never a mutable display name.
|
|
29
|
+
- `signReceipt`, `recomputeVerdict` (the pure soundness floor), `makeBoundary`.
|
|
30
|
+
- `nucleus-verify` CLI (exit 0 in-bounds / 1 refused / 2 usage) and a
|
|
31
|
+
composite GitHub Action.
|
|
32
|
+
- **Auction receipts** (original use case): `verify`, `recomputeClearing`,
|
|
33
|
+
`verifySignature` over the bundled `nucleus-wasm` core.
|
package/README.md
CHANGED
|
@@ -68,6 +68,30 @@ pnpm build && pnpm demo # examples/openclaw-replay.mjs
|
|
|
68
68
|
- **The permission fingerprint binds identity to capability.** `permissionFingerprint` is SHA-256 over the sorted, de-duplicated `allowedTools` — mirroring the X.509 permission-fingerprint extension in `nucleus-tool-proxy`/`nucleus-identity` (`identity_fusion`: "who you are" bound to "what you can do"). Widening the tool set changes the fingerprint and invalidates the boundary.
|
|
69
69
|
- **The hash-chain pins trace order.** `rootHash` is `hᵢ = SHA256(hᵢ₋₁ ‖ canonical(eventᵢ))`; reorder or insert and the root changes.
|
|
70
70
|
|
|
71
|
+
### Producer-side: from a real nucleus-tool-proxy trace
|
|
72
|
+
|
|
73
|
+
The receipt is emitted from the tool-proxy's actual authorization output, not a hand-authored fixture. A trace export pairs the **declared boundary** (a SPIFFE principal + the task-shield allowlist — `portcullis_core::task_shield::TaskWitness`'s allow-set) with one record per observed call mirroring the `verdict_sink` `tool_call` span fields (`actor`, `operation`, `verdict`, `subject`, `deny_reason`):
|
|
74
|
+
|
|
75
|
+
```jsonc
|
|
76
|
+
{
|
|
77
|
+
"boundary": { "principal": "spiffe://acme/agent/billing", "allowedTools": ["read_files","glob_search","grep_search"] },
|
|
78
|
+
"records": [
|
|
79
|
+
{ "actor": "spiffe://acme/agent/billing", "operation": "read_files", "verdict": "allow", "subject": "invoices/2026-06.pdf" }
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Pipe it through the `nucleus-attest` producer to get a signed receipt, then verify:
|
|
85
|
+
|
|
86
|
+
```sh
|
|
87
|
+
# emit a REAL trace from portcullis (TaskWitness::permits decides each verdict):
|
|
88
|
+
cargo run -q -p nucleus-policy --example emit_toolproxy_trace -- clean \
|
|
89
|
+
| nucleus-attest \
|
|
90
|
+
| nucleus-verify - # exit 0: in bounds · exit 1: refused
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
`nucleus-attest` also runs a **cross-check**: the proxy's own `allow`/`deny` per call must agree with the receipt's independently recomputed in-bounds verdict — a mismatch surfaces boundary drift. The producer never asserts in-bounds itself; it only records what happened (`attestToolProxyRun`/`./toolproxy`). The Rust emitter lives at `crates/nucleus-policy/examples/emit_toolproxy_trace.rs`.
|
|
94
|
+
|
|
71
95
|
### Honest scope
|
|
72
96
|
|
|
73
97
|
This attests that the **observed trace** stayed within the **declared boundary** — integrity-axis, model-level evidence (the bar-2 IFC noninterference guarantee). It is **not**:
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -67,3 +67,6 @@ export async function verifySignature(receiptJson, jwksJson) {
|
|
|
67
67
|
// Pure Node (`node:crypto`), no WASM — runs in CI, the CLI, and the Action.
|
|
68
68
|
// ---------------------------------------------------------------------------
|
|
69
69
|
export * from "./attestation.js";
|
|
70
|
+
// Producer-side instrumentation: turn a nucleus-tool-proxy trace into a signed
|
|
71
|
+
// in-bounds receipt. See `./toolproxy` and the `nucleus-attest` CLI.
|
|
72
|
+
export * from "./toolproxy.js";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* `nucleus-attest` — producer-side CLI. Reads a nucleus-tool-proxy trace
|
|
4
|
+
* export (from the `emit_toolproxy_trace` example, or any equivalent
|
|
5
|
+
* instrumentation), signs an in-bounds attestation receipt, and writes it to
|
|
6
|
+
* stdout. The cross-check + signer public key go to stderr.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* nucleus-attest [export.json] [--key <pkcs8.pem>] [--signed-at <iso>]
|
|
10
|
+
* emit_toolproxy_trace ... | nucleus-attest > receipt.json
|
|
11
|
+
*
|
|
12
|
+
* With no --key, an EPHEMERAL Ed25519 keypair is generated in memory (no key
|
|
13
|
+
* custody) — fine for demos/CI dry-runs; the public key is printed to stderr
|
|
14
|
+
* so a verifier can pin it. Exit 0 on a produced receipt, 2 on error.
|
|
15
|
+
*/
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* `nucleus-attest` — producer-side CLI. Reads a nucleus-tool-proxy trace
|
|
4
|
+
* export (from the `emit_toolproxy_trace` example, or any equivalent
|
|
5
|
+
* instrumentation), signs an in-bounds attestation receipt, and writes it to
|
|
6
|
+
* stdout. The cross-check + signer public key go to stderr.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* nucleus-attest [export.json] [--key <pkcs8.pem>] [--signed-at <iso>]
|
|
10
|
+
* emit_toolproxy_trace ... | nucleus-attest > receipt.json
|
|
11
|
+
*
|
|
12
|
+
* With no --key, an EPHEMERAL Ed25519 keypair is generated in memory (no key
|
|
13
|
+
* custody) — fine for demos/CI dry-runs; the public key is printed to stderr
|
|
14
|
+
* so a verifier can pin it. Exit 0 on a produced receipt, 2 on error.
|
|
15
|
+
*/
|
|
16
|
+
import { readFileSync } from "node:fs";
|
|
17
|
+
import { generateKeypair, privateKeyFromPem, exportPublicKey } from "./attestation.js";
|
|
18
|
+
import { createPublicKey } from "node:crypto";
|
|
19
|
+
import { parseExport, attestToolProxyRun } from "./toolproxy.js";
|
|
20
|
+
function arg(flag) {
|
|
21
|
+
const i = process.argv.indexOf(flag);
|
|
22
|
+
return i >= 0 ? process.argv[i + 1] : undefined;
|
|
23
|
+
}
|
|
24
|
+
function main() {
|
|
25
|
+
if (process.argv.includes("-h") || process.argv.includes("--help")) {
|
|
26
|
+
process.stdout.write("nucleus-attest — sign an in-bounds receipt from a tool-proxy trace\n\n" +
|
|
27
|
+
"Usage: nucleus-attest [export.json] [--key <pkcs8.pem>] [--signed-at <iso>]\n");
|
|
28
|
+
return 0;
|
|
29
|
+
}
|
|
30
|
+
// Positional input path = first non-flag arg after argv[1].
|
|
31
|
+
const positional = process.argv.slice(2).find((a) => !a.startsWith("--") && a !== arg("--key") && a !== arg("--signed-at"));
|
|
32
|
+
let exportJson;
|
|
33
|
+
try {
|
|
34
|
+
exportJson = positional ? readFileSync(positional, "utf8") : readFileSync(0, "utf8");
|
|
35
|
+
}
|
|
36
|
+
catch (e) {
|
|
37
|
+
process.stderr.write(`error: cannot read export: ${e.message}\n`);
|
|
38
|
+
return 2;
|
|
39
|
+
}
|
|
40
|
+
let exp;
|
|
41
|
+
try {
|
|
42
|
+
exp = parseExport(exportJson);
|
|
43
|
+
}
|
|
44
|
+
catch (e) {
|
|
45
|
+
process.stderr.write(`error: ${e.message}\n`);
|
|
46
|
+
return 2;
|
|
47
|
+
}
|
|
48
|
+
// Key: load from PEM, or generate ephemeral.
|
|
49
|
+
let privateKey;
|
|
50
|
+
let ephemeral = false;
|
|
51
|
+
const keyPath = arg("--key");
|
|
52
|
+
try {
|
|
53
|
+
if (keyPath) {
|
|
54
|
+
privateKey = privateKeyFromPem(readFileSync(keyPath, "utf8"));
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
privateKey = generateKeypair().privateKey;
|
|
58
|
+
ephemeral = true;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
catch (e) {
|
|
62
|
+
process.stderr.write(`error: cannot load key: ${e.message}\n`);
|
|
63
|
+
return 2;
|
|
64
|
+
}
|
|
65
|
+
const signedAt = arg("--signed-at");
|
|
66
|
+
const { receipt, crossCheck } = attestToolProxyRun(exp, privateKey, signedAt ? { signedAt } : {});
|
|
67
|
+
// Receipt → stdout (the artifact).
|
|
68
|
+
process.stdout.write(JSON.stringify(receipt, null, 2) + "\n");
|
|
69
|
+
// Diagnostics → stderr.
|
|
70
|
+
const pub = exportPublicKey(createPublicKey(privateKey));
|
|
71
|
+
process.stderr.write(`signer publicKey: ${pub}${ephemeral ? " (ephemeral)" : ""}\n` +
|
|
72
|
+
`recomputed inBounds: ${receipt.verdict.inBounds}\n`);
|
|
73
|
+
if (crossCheck.length > 0) {
|
|
74
|
+
process.stderr.write(`cross-check issues (${crossCheck.length}):\n`);
|
|
75
|
+
for (const c of crossCheck) {
|
|
76
|
+
process.stderr.write(` #${c.seq} ${c.operation}: proxy=${c.proxyVerdict} recomputed-inBounds=${c.recomputedInBounds} — ${c.note}\n`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
process.stderr.write("cross-check: proxy decisions agree with recomputed verdict\n");
|
|
81
|
+
}
|
|
82
|
+
return 0;
|
|
83
|
+
}
|
|
84
|
+
process.exit(main());
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Producer-side instrumentation: turn a **nucleus-tool-proxy trace** into a
|
|
3
|
+
* signed capability-boundary in-bounds attestation receipt.
|
|
4
|
+
*
|
|
5
|
+
* The trace is the real output of the tool-proxy's authorization layer: a
|
|
6
|
+
* declared boundary (a SPIFFE principal + the task-shield allowlist, i.e.
|
|
7
|
+
* `TaskWitness`'s allow-set) plus one record per observed tool call mirroring
|
|
8
|
+
* the `verdict_sink` "tool_call" span fields (`actor`, `operation`,
|
|
9
|
+
* `verdict`, `subject`, `deny_reason`). See
|
|
10
|
+
* `crates/nucleus-policy/examples/emit_toolproxy_trace.rs` for the emitter.
|
|
11
|
+
*
|
|
12
|
+
* This module maps that export into the {@link Receipt} schema and signs it.
|
|
13
|
+
* The receipt's verdict is still recomputed independently by the verifier —
|
|
14
|
+
* the producer never gets to assert in-bounds; it only records what happened.
|
|
15
|
+
*/
|
|
16
|
+
import { type KeyObject } from "node:crypto";
|
|
17
|
+
import { type CapabilityBoundary, type TraceEvent, type Receipt } from "./attestation.js";
|
|
18
|
+
/** A single observed tool call, mirroring the tool-proxy `verdict_sink` span. */
|
|
19
|
+
export interface ToolProxyVerdictRecord {
|
|
20
|
+
/** SPIFFE id of the actor that made the call (`nucleus.actor`). */
|
|
21
|
+
actor: string;
|
|
22
|
+
/** Operation/tool invoked (`nucleus.operation`), canonical serde name. */
|
|
23
|
+
operation: string;
|
|
24
|
+
/** The proxy's own decision (`nucleus.verdict`). */
|
|
25
|
+
verdict: "allow" | "deny" | "error";
|
|
26
|
+
/** The call's target/argument (`nucleus.subject`), if present. */
|
|
27
|
+
subject?: string;
|
|
28
|
+
/** Proxy deny reason (`nucleus.deny_reason`), if any. */
|
|
29
|
+
deny_reason?: string;
|
|
30
|
+
/** Human-readable label, if the runtime recorded one (mutable, untrusted). */
|
|
31
|
+
displayName?: string;
|
|
32
|
+
}
|
|
33
|
+
/** The full trace export the emitter produces. */
|
|
34
|
+
export interface ToolProxyExport {
|
|
35
|
+
boundary: {
|
|
36
|
+
principal: string;
|
|
37
|
+
allowedTools: string[];
|
|
38
|
+
};
|
|
39
|
+
records: ToolProxyVerdictRecord[];
|
|
40
|
+
/** Optional task-shield hash (provenance; not part of the receipt). */
|
|
41
|
+
taskHashHex?: string;
|
|
42
|
+
}
|
|
43
|
+
/** A disagreement between the proxy's decision and the recomputed verdict. */
|
|
44
|
+
export interface CrossCheckIssue {
|
|
45
|
+
seq: number;
|
|
46
|
+
operation: string;
|
|
47
|
+
proxyVerdict: string;
|
|
48
|
+
recomputedInBounds: boolean;
|
|
49
|
+
note: string;
|
|
50
|
+
}
|
|
51
|
+
export interface AttestResult {
|
|
52
|
+
receipt: Receipt;
|
|
53
|
+
/**
|
|
54
|
+
* Sanity cross-check: the proxy's per-call decision should agree with the
|
|
55
|
+
* receipt's recomputed in-bounds finding (a proxy `deny` of an out-of-policy
|
|
56
|
+
* op should land out-of-bounds, an `allow` of an in-policy op in-bounds). A
|
|
57
|
+
* non-empty list means the trace and the declared boundary disagree — worth
|
|
58
|
+
* surfacing, though the receipt's recomputed verdict remains authoritative.
|
|
59
|
+
*/
|
|
60
|
+
crossCheck: CrossCheckIssue[];
|
|
61
|
+
}
|
|
62
|
+
/** Build the declared {@link CapabilityBoundary} from a trace export. */
|
|
63
|
+
export declare function boundaryFromExport(exp: ToolProxyExport): CapabilityBoundary;
|
|
64
|
+
/** Map the proxy's verdict records into receipt {@link TraceEvent}s. */
|
|
65
|
+
export declare function traceEventsFromRecords(records: ToolProxyVerdictRecord[]): TraceEvent[];
|
|
66
|
+
/**
|
|
67
|
+
* Attest a tool-proxy run: build the boundary + events from the export and
|
|
68
|
+
* sign the receipt. Also runs a cross-check that the proxy's own decisions
|
|
69
|
+
* agree with the recomputed in-bounds verdict.
|
|
70
|
+
*/
|
|
71
|
+
export declare function attestToolProxyRun(exp: ToolProxyExport, privateKey: KeyObject, opts?: {
|
|
72
|
+
signedAt?: string;
|
|
73
|
+
}): AttestResult;
|
|
74
|
+
/** Parse a trace export from JSON text. Accepts the emitter's pretty output. */
|
|
75
|
+
export declare function parseExport(json: string): ToolProxyExport;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Producer-side instrumentation: turn a **nucleus-tool-proxy trace** into a
|
|
3
|
+
* signed capability-boundary in-bounds attestation receipt.
|
|
4
|
+
*
|
|
5
|
+
* The trace is the real output of the tool-proxy's authorization layer: a
|
|
6
|
+
* declared boundary (a SPIFFE principal + the task-shield allowlist, i.e.
|
|
7
|
+
* `TaskWitness`'s allow-set) plus one record per observed tool call mirroring
|
|
8
|
+
* the `verdict_sink` "tool_call" span fields (`actor`, `operation`,
|
|
9
|
+
* `verdict`, `subject`, `deny_reason`). See
|
|
10
|
+
* `crates/nucleus-policy/examples/emit_toolproxy_trace.rs` for the emitter.
|
|
11
|
+
*
|
|
12
|
+
* This module maps that export into the {@link Receipt} schema and signs it.
|
|
13
|
+
* The receipt's verdict is still recomputed independently by the verifier —
|
|
14
|
+
* the producer never gets to assert in-bounds; it only records what happened.
|
|
15
|
+
*/
|
|
16
|
+
import { createHash } from "node:crypto";
|
|
17
|
+
import { makeBoundary, signReceipt, recomputeVerdict, } from "./attestation.js";
|
|
18
|
+
function sha256Hex(input) {
|
|
19
|
+
return createHash("sha256").update(input).digest("hex");
|
|
20
|
+
}
|
|
21
|
+
/** Build the declared {@link CapabilityBoundary} from a trace export. */
|
|
22
|
+
export function boundaryFromExport(exp) {
|
|
23
|
+
return makeBoundary(exp.boundary.principal, exp.boundary.allowedTools);
|
|
24
|
+
}
|
|
25
|
+
/** Map the proxy's verdict records into receipt {@link TraceEvent}s. */
|
|
26
|
+
export function traceEventsFromRecords(records) {
|
|
27
|
+
return records.map((r, i) => {
|
|
28
|
+
const ev = { seq: i, tool: r.operation, principal: r.actor };
|
|
29
|
+
if (r.displayName !== undefined)
|
|
30
|
+
ev.displayName = r.displayName;
|
|
31
|
+
// Bind the event to the call's target via a digest (subject is the
|
|
32
|
+
// tool-proxy's `nucleus.subject`); opaque to the in-bounds verdict.
|
|
33
|
+
if (r.subject !== undefined && r.subject !== "")
|
|
34
|
+
ev.argsDigest = sha256Hex(r.subject);
|
|
35
|
+
return ev;
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Attest a tool-proxy run: build the boundary + events from the export and
|
|
40
|
+
* sign the receipt. Also runs a cross-check that the proxy's own decisions
|
|
41
|
+
* agree with the recomputed in-bounds verdict.
|
|
42
|
+
*/
|
|
43
|
+
export function attestToolProxyRun(exp, privateKey, opts = {}) {
|
|
44
|
+
const boundary = boundaryFromExport(exp);
|
|
45
|
+
const events = traceEventsFromRecords(exp.records);
|
|
46
|
+
const receipt = signReceipt(boundary, events, privateKey, opts);
|
|
47
|
+
// Cross-check the proxy's decisions against an independent recompute.
|
|
48
|
+
const recomputed = recomputeVerdict(boundary, events);
|
|
49
|
+
const crossCheck = [];
|
|
50
|
+
recomputed.events.forEach((finding, i) => {
|
|
51
|
+
const proxyVerdict = exp.records[i]?.verdict ?? "error";
|
|
52
|
+
const proxyAllowed = proxyVerdict === "allow";
|
|
53
|
+
if (proxyAllowed !== finding.inBounds) {
|
|
54
|
+
crossCheck.push({
|
|
55
|
+
seq: finding.seq,
|
|
56
|
+
operation: finding.tool,
|
|
57
|
+
proxyVerdict,
|
|
58
|
+
recomputedInBounds: finding.inBounds,
|
|
59
|
+
note: proxyAllowed
|
|
60
|
+
? "proxy allowed a call the declared boundary does not permit (boundary drift?)"
|
|
61
|
+
: "proxy denied a call the declared boundary permits (extra restriction outside the boundary)",
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
return { receipt, crossCheck };
|
|
66
|
+
}
|
|
67
|
+
/** Parse a trace export from JSON text. Accepts the emitter's pretty output. */
|
|
68
|
+
export function parseExport(json) {
|
|
69
|
+
const obj = JSON.parse(json);
|
|
70
|
+
if (!obj || typeof obj !== "object" || !obj.boundary || !Array.isArray(obj.records)) {
|
|
71
|
+
throw new Error("not a tool-proxy trace export (need { boundary, records })");
|
|
72
|
+
}
|
|
73
|
+
return obj;
|
|
74
|
+
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coproduct_inc/verify",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Offline, zero-trust verification of agent capability-boundary in-bounds attestation receipts: emit and verify an Ed25519-signed, hash-chained receipt that an agent run stayed within a declared boundary, keyed on a cryptographic principal (not a mutable display name) — the evidence layer above probabilistic guardrails. Also verifies Nucleus auction receipts by re-running the clearing locally. Zero runtime deps for the attestation core (node:crypto).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/index.js",
|
|
8
8
|
"types": "./dist/index.d.ts",
|
|
9
9
|
"bin": {
|
|
10
|
-
"nucleus-verify": "dist/cli.js"
|
|
10
|
+
"nucleus-verify": "dist/cli.js",
|
|
11
|
+
"nucleus-attest": "dist/producer-cli.js"
|
|
11
12
|
},
|
|
12
13
|
"exports": {
|
|
13
14
|
".": {
|
|
@@ -17,6 +18,10 @@
|
|
|
17
18
|
"./attestation": {
|
|
18
19
|
"types": "./dist/attestation.d.ts",
|
|
19
20
|
"import": "./dist/attestation.js"
|
|
21
|
+
},
|
|
22
|
+
"./toolproxy": {
|
|
23
|
+
"types": "./dist/toolproxy.d.ts",
|
|
24
|
+
"import": "./dist/toolproxy.js"
|
|
20
25
|
}
|
|
21
26
|
},
|
|
22
27
|
"files": [
|
|
@@ -27,7 +32,8 @@
|
|
|
27
32
|
"wasm/nodejs/nucleus_wasm_bg.wasm",
|
|
28
33
|
"wasm/nodejs/nucleus_wasm_bg.wasm.d.ts",
|
|
29
34
|
"examples/openclaw-replay.mjs",
|
|
30
|
-
"README.md"
|
|
35
|
+
"README.md",
|
|
36
|
+
"CHANGELOG.md"
|
|
31
37
|
],
|
|
32
38
|
"scripts": {
|
|
33
39
|
"build:wasm": "wasm-pack build ../../crates/nucleus-wasm --target nodejs --out-dir ../../packages/nucleus-verify/wasm/nodejs && rm -f wasm/nodejs/.gitignore wasm/nodejs/package.json",
|