@fidacy/openclaw-plugin 0.1.8 → 0.1.10
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 +10 -0
- package/dist/index.js +166 -2
- package/openclaw.plugin.json +3 -1
- package/package.json +8 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.10 — 2026-07-03
|
|
4
|
+
|
|
5
|
+
- Artifact tools gain the `conversation` kind (chatbot session digests via
|
|
6
|
+
`@fidacy/session`, conversation receipts).
|
|
7
|
+
|
|
8
|
+
## 0.1.9 — 2026-07-03
|
|
9
|
+
|
|
10
|
+
- New tools: `anchor_artifact` and `check_artifact` (hash-only artifact anchoring
|
|
11
|
+
on the Bitcoin-checkpointed audit chain; files never leave the machine).
|
|
12
|
+
|
|
3
13
|
## 0.1.1 — 2026-07-02
|
|
4
14
|
|
|
5
15
|
- README: animated demo (BEC lookalike-payee DENY → legit ALLOW with signed
|
package/dist/index.js
CHANGED
|
@@ -4671,7 +4671,7 @@ function resolveMandateRules(cfg) {
|
|
|
4671
4671
|
}
|
|
4672
4672
|
|
|
4673
4673
|
// ../mcp/src/telemetry.ts
|
|
4674
|
-
var CLIENT_VERSION = true ? "0.1.
|
|
4674
|
+
var CLIENT_VERSION = true ? "0.1.10" : "dev";
|
|
4675
4675
|
var currentShell = "mcp";
|
|
4676
4676
|
function setTelemetryShell(shell) {
|
|
4677
4677
|
currentShell = shell;
|
|
@@ -4799,7 +4799,7 @@ function requestUpgrade() {
|
|
|
4799
4799
|
}
|
|
4800
4800
|
|
|
4801
4801
|
// ../mcp/src/provision.ts
|
|
4802
|
-
var CLIENT_VERSION2 = true ? "0.1.
|
|
4802
|
+
var CLIENT_VERSION2 = true ? "0.1.10" : "dev";
|
|
4803
4803
|
function provisionEnabled() {
|
|
4804
4804
|
const v = (process.env.FIDACY_DISABLE_PROVISION ?? "").trim().toLowerCase();
|
|
4805
4805
|
return !(v === "1" || v === "true" || v === "yes");
|
|
@@ -4988,6 +4988,71 @@ async function postOnce(fetchImpl, url, headers, payload, timeoutMs) {
|
|
|
4988
4988
|
return parsed;
|
|
4989
4989
|
}
|
|
4990
4990
|
|
|
4991
|
+
// ../mcp/src/artifacts.ts
|
|
4992
|
+
import { createHash } from "node:crypto";
|
|
4993
|
+
import { createReadStream } from "node:fs";
|
|
4994
|
+
import { pipeline } from "node:stream/promises";
|
|
4995
|
+
var ARTIFACT_KINDS = [
|
|
4996
|
+
"contract",
|
|
4997
|
+
"invoice",
|
|
4998
|
+
"prescription",
|
|
4999
|
+
"claim",
|
|
5000
|
+
"document",
|
|
5001
|
+
"image",
|
|
5002
|
+
"audio",
|
|
5003
|
+
"video",
|
|
5004
|
+
"conversation",
|
|
5005
|
+
"custom"
|
|
5006
|
+
];
|
|
5007
|
+
async function hashFile(path) {
|
|
5008
|
+
const hash = createHash("sha256");
|
|
5009
|
+
await pipeline(createReadStream(path), async function* (source) {
|
|
5010
|
+
for await (const chunk of source) {
|
|
5011
|
+
hash.update(chunk);
|
|
5012
|
+
yield;
|
|
5013
|
+
}
|
|
5014
|
+
});
|
|
5015
|
+
return hash.digest("hex");
|
|
5016
|
+
}
|
|
5017
|
+
async function engineFetch(method, pathAndQuery, cfg, body) {
|
|
5018
|
+
const base = requireSafeBaseUrl(cfg.engineUrl);
|
|
5019
|
+
const controller = new AbortController();
|
|
5020
|
+
const timer = setTimeout(() => controller.abort(), 1e4);
|
|
5021
|
+
let res;
|
|
5022
|
+
try {
|
|
5023
|
+
res = await fetch(`${base}${pathAndQuery}`, {
|
|
5024
|
+
method,
|
|
5025
|
+
headers: {
|
|
5026
|
+
authorization: `Bearer ${cfg.apiKey}`,
|
|
5027
|
+
...body !== void 0 ? { "content-type": "application/json" } : {}
|
|
5028
|
+
},
|
|
5029
|
+
body: body !== void 0 ? JSON.stringify(body) : void 0,
|
|
5030
|
+
signal: controller.signal
|
|
5031
|
+
});
|
|
5032
|
+
} catch {
|
|
5033
|
+
throw new AssessError({ type: "network_error", status: 0 });
|
|
5034
|
+
} finally {
|
|
5035
|
+
clearTimeout(timer);
|
|
5036
|
+
}
|
|
5037
|
+
let json;
|
|
5038
|
+
try {
|
|
5039
|
+
json = await res.json();
|
|
5040
|
+
} catch {
|
|
5041
|
+
throw new AssessError({ type: "bad_response", status: res.status });
|
|
5042
|
+
}
|
|
5043
|
+
if (!res.ok) {
|
|
5044
|
+
const type = typeof json?.error === "string" ? String(json.error) : "engine_error";
|
|
5045
|
+
throw new AssessError({ type, status: res.status });
|
|
5046
|
+
}
|
|
5047
|
+
return json;
|
|
5048
|
+
}
|
|
5049
|
+
async function anchorArtifact(params, cfg) {
|
|
5050
|
+
return await engineFetch("POST", "/v1/artifacts", cfg, params);
|
|
5051
|
+
}
|
|
5052
|
+
async function findArtifacts(sha2562, cfg) {
|
|
5053
|
+
return await engineFetch("GET", `/v1/artifacts?sha256=${sha2562}`, cfg);
|
|
5054
|
+
}
|
|
5055
|
+
|
|
4991
5056
|
// src/index.ts
|
|
4992
5057
|
var core;
|
|
4993
5058
|
function boot() {
|
|
@@ -5129,6 +5194,105 @@ ${d.grant}` : `DENY (decision ${d.decisionId}). Rule violated: ${d.violatedRule}
|
|
|
5129
5194
|
}
|
|
5130
5195
|
}
|
|
5131
5196
|
}),
|
|
5197
|
+
// ARTIFACT ANCHORING. Hash-only integrity/existence proof: the file is hashed
|
|
5198
|
+
// locally (streaming) and never uploaded; the SHA-256 joins the same
|
|
5199
|
+
// Bitcoin-checkpointed audit chain as the verdicts. Receipt = offline JWS.
|
|
5200
|
+
tool({
|
|
5201
|
+
name: "anchor_artifact",
|
|
5202
|
+
label: "Anchor Artifact (Bitcoin-anchored integrity proof)",
|
|
5203
|
+
description: "Prove an artifact existed exactly as-is at this moment, and make any later tampering detectable. Give a file `path` (hashed locally with SHA-256 \u2014 the file itself is NEVER uploaded) or a precomputed `sha256`. The hash is registered on Fidacy's tamper-evident audit chain, which is checkpointed to the Bitcoin blockchain, and you get a signed receipt (JWS) verifiable offline against the engine JWKS. Use it for contracts, invoices, medical prescriptions, insurance claims, images, audio, video. `kind` defaults to document; optional `label` is a short reference (no PII).",
|
|
5204
|
+
parameters: typebox_exports.Object({
|
|
5205
|
+
path: typebox_exports.Optional(typebox_exports.String()),
|
|
5206
|
+
sha256: typebox_exports.Optional(typebox_exports.String({ pattern: "^[0-9a-f]{64}$" })),
|
|
5207
|
+
kind: typebox_exports.Optional(typebox_exports.Union(ARTIFACT_KINDS.map((k) => typebox_exports.Literal(k)))),
|
|
5208
|
+
label: typebox_exports.Optional(typebox_exports.String({ maxLength: 120 })),
|
|
5209
|
+
subject: typebox_exports.Optional(typebox_exports.String({ maxLength: 120 }))
|
|
5210
|
+
}),
|
|
5211
|
+
async execute(params, config) {
|
|
5212
|
+
boot();
|
|
5213
|
+
const engineUrl = config.engineUrl ?? process.env.FIDACY_ENGINE_URL ?? "https://api.fidacy.com";
|
|
5214
|
+
const apiKey = (config.engineApiKey ?? process.env.FIDACY_ENGINE_API_KEY ?? "").trim();
|
|
5215
|
+
if (!apiKey) {
|
|
5216
|
+
throw new Error(
|
|
5217
|
+
"anchor_artifact requires an engine API key (an fky_live_/fky_test_ key with assess:write). Set plugins.entries.fidacy.config.engineApiKey or FIDACY_ENGINE_API_KEY."
|
|
5218
|
+
);
|
|
5219
|
+
}
|
|
5220
|
+
if (!params.path && !params.sha256) {
|
|
5221
|
+
throw new Error("Give a file `path` (hashed locally) or a precomputed `sha256`.");
|
|
5222
|
+
}
|
|
5223
|
+
let hash = params.sha256 ?? "";
|
|
5224
|
+
if (!hash && params.path) {
|
|
5225
|
+
try {
|
|
5226
|
+
hash = await hashFile(params.path);
|
|
5227
|
+
} catch {
|
|
5228
|
+
throw new Error("Could not read that file locally (check the path and permissions). Nothing was sent anywhere.");
|
|
5229
|
+
}
|
|
5230
|
+
}
|
|
5231
|
+
try {
|
|
5232
|
+
const r = await anchorArtifact(
|
|
5233
|
+
{ sha256: hash, kind: params.kind ?? "document", ...params.label ? { label: params.label } : {}, ...params.subject ? { subject: params.subject } : {} },
|
|
5234
|
+
{ engineUrl, apiKey }
|
|
5235
|
+
);
|
|
5236
|
+
return {
|
|
5237
|
+
summary: `ANCHORED ${r.kind} \xB7 sha256 ${hash.slice(0, 16)}\u2026 \xB7 audit seq ${r.audit.seq} \xB7 Bitcoin checkpoint: ${r.anchor.status}. The file never left this machine.`,
|
|
5238
|
+
...r
|
|
5239
|
+
};
|
|
5240
|
+
} catch (e) {
|
|
5241
|
+
if (e instanceof AssessError) throw new Error(`ANCHOR ${e.status}: ${e.type}`);
|
|
5242
|
+
throw new Error("ANCHOR failed: unexpected error");
|
|
5243
|
+
}
|
|
5244
|
+
}
|
|
5245
|
+
}),
|
|
5246
|
+
// Verification half: was this exact content anchored, and did it reach Bitcoin?
|
|
5247
|
+
tool({
|
|
5248
|
+
name: "check_artifact",
|
|
5249
|
+
label: "Check Artifact (was this hash anchored?)",
|
|
5250
|
+
description: "Check whether an artifact was anchored by this account and the state of its Bitcoin checkpoint. Give a file `path` (hashed locally, never uploaded) or a `sha256`. If the current hash of a file does NOT match an anchored record you expected, the file changed since anchoring \u2014 that is the tampering signal.",
|
|
5251
|
+
parameters: typebox_exports.Object({
|
|
5252
|
+
path: typebox_exports.Optional(typebox_exports.String()),
|
|
5253
|
+
sha256: typebox_exports.Optional(typebox_exports.String({ pattern: "^[0-9a-f]{64}$" }))
|
|
5254
|
+
}),
|
|
5255
|
+
async execute(params, config) {
|
|
5256
|
+
boot();
|
|
5257
|
+
const engineUrl = config.engineUrl ?? process.env.FIDACY_ENGINE_URL ?? "https://api.fidacy.com";
|
|
5258
|
+
const apiKey = (config.engineApiKey ?? process.env.FIDACY_ENGINE_API_KEY ?? "").trim();
|
|
5259
|
+
if (!apiKey) {
|
|
5260
|
+
throw new Error(
|
|
5261
|
+
"check_artifact requires an engine API key. Set plugins.entries.fidacy.config.engineApiKey or FIDACY_ENGINE_API_KEY."
|
|
5262
|
+
);
|
|
5263
|
+
}
|
|
5264
|
+
if (!params.path && !params.sha256) {
|
|
5265
|
+
throw new Error("Give a file `path` (hashed locally) or a `sha256`.");
|
|
5266
|
+
}
|
|
5267
|
+
let hash = params.sha256 ?? "";
|
|
5268
|
+
if (!hash && params.path) {
|
|
5269
|
+
try {
|
|
5270
|
+
hash = await hashFile(params.path);
|
|
5271
|
+
} catch {
|
|
5272
|
+
throw new Error("Could not read that file locally (check the path and permissions). Nothing was sent anywhere.");
|
|
5273
|
+
}
|
|
5274
|
+
}
|
|
5275
|
+
try {
|
|
5276
|
+
const r = await findArtifacts(hash, { engineUrl, apiKey });
|
|
5277
|
+
if (!r.artifacts.length) {
|
|
5278
|
+
return {
|
|
5279
|
+
summary: `NOT FOUND \xB7 sha256 ${hash.slice(0, 16)}\u2026 has no anchored record in this account. If you expected a match, the file changed since anchoring.`,
|
|
5280
|
+
sha256: hash,
|
|
5281
|
+
artifacts: []
|
|
5282
|
+
};
|
|
5283
|
+
}
|
|
5284
|
+
const first = r.artifacts[0];
|
|
5285
|
+
return {
|
|
5286
|
+
summary: `FOUND ${r.artifacts.length} record(s) \xB7 newest: ${String(first.kind)} anchored ${String(first.createdAt)} (audit seq ${String(first.auditSeq)}). Content matches the anchored hash byte for byte.`,
|
|
5287
|
+
sha256: hash,
|
|
5288
|
+
...r
|
|
5289
|
+
};
|
|
5290
|
+
} catch (e) {
|
|
5291
|
+
if (e instanceof AssessError) throw new Error(`CHECK ${e.status}: ${e.type}`);
|
|
5292
|
+
throw new Error("CHECK failed: unexpected error");
|
|
5293
|
+
}
|
|
5294
|
+
}
|
|
5295
|
+
}),
|
|
5132
5296
|
// Upgrade funnel. Records the intent signal and returns the real-account link;
|
|
5133
5297
|
// the anon_id travels in the URL so the engine binds past usage to the tenant.
|
|
5134
5298
|
tool({
|
package/openclaw.plugin.json
CHANGED
|
@@ -3,13 +3,15 @@
|
|
|
3
3
|
"name": "Fidacy \u2014 Payment Firewall",
|
|
4
4
|
"description": "A signed, independently-verifiable verdict on every money-moving agent action. Blocks wrong/lookalike payee, over-cap, and duplicate-invoice fraud before money moves. Non-custodial, local-first, deny-by-default.",
|
|
5
5
|
"icon": "https://fidacy.com/logo.png",
|
|
6
|
-
"version": "0.1.
|
|
6
|
+
"version": "0.1.10",
|
|
7
7
|
"contracts": {
|
|
8
8
|
"tools": [
|
|
9
9
|
"request_payment",
|
|
10
10
|
"verify_mandate",
|
|
11
11
|
"get_audit_proof",
|
|
12
12
|
"assess_action",
|
|
13
|
+
"anchor_artifact",
|
|
14
|
+
"check_artifact",
|
|
13
15
|
"fidacy_upgrade"
|
|
14
16
|
]
|
|
15
17
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fidacy/openclaw-plugin",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"description": "Fidacy payment firewall as a native OpenClaw plugin: signed, verifiable verdicts on every money-moving agent action, in-process (no MCP subprocess).",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://fidacy.com",
|
|
@@ -46,20 +46,20 @@
|
|
|
46
46
|
"npmSpec": "@fidacy/openclaw-plugin"
|
|
47
47
|
}
|
|
48
48
|
},
|
|
49
|
+
"scripts": {
|
|
50
|
+
"build": "node scripts/bundle.mjs",
|
|
51
|
+
"typecheck": "tsc --noEmit"
|
|
52
|
+
},
|
|
49
53
|
"engines": {
|
|
50
54
|
"node": ">=20"
|
|
51
55
|
},
|
|
52
56
|
"devDependencies": {
|
|
57
|
+
"@fidacy/firewall": "workspace:*",
|
|
58
|
+
"@fidacy/mcp": "workspace:*",
|
|
53
59
|
"@types/node": "^22.10.0",
|
|
54
60
|
"esbuild": "^0.24.0",
|
|
55
61
|
"openclaw": "2026.6.11",
|
|
56
62
|
"typebox": "1.1.39",
|
|
57
|
-
"typescript": "^5.6.3"
|
|
58
|
-
"@fidacy/firewall": "0.1.0",
|
|
59
|
-
"@fidacy/mcp": "0.1.14"
|
|
60
|
-
},
|
|
61
|
-
"scripts": {
|
|
62
|
-
"build": "node scripts/bundle.mjs",
|
|
63
|
-
"typecheck": "tsc --noEmit"
|
|
63
|
+
"typescript": "^5.6.3"
|
|
64
64
|
}
|
|
65
65
|
}
|