@fidacy/openclaw-plugin 0.1.10 → 0.1.12
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 +4 -0
- package/dist/index.js +78 -10
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -4415,6 +4415,19 @@ var DevFidacyCore = class {
|
|
|
4415
4415
|
this.spent += r.amount;
|
|
4416
4416
|
}
|
|
4417
4417
|
}
|
|
4418
|
+
/**
|
|
4419
|
+
* Swap the active mandate (shell config hot-reload: edit config.json, the next
|
|
4420
|
+
* call picks it up, no host restart). Decision state is REBUILT from the audit
|
|
4421
|
+
* log under the new window/currency, so a reload can never reset the BEC
|
|
4422
|
+
* invoice dedup or undercount spend: a paid invoice stays paid, spent is
|
|
4423
|
+
* recomputed.
|
|
4424
|
+
*/
|
|
4425
|
+
setMandate(m) {
|
|
4426
|
+
this.mandate = m;
|
|
4427
|
+
this.spent = 0;
|
|
4428
|
+
this.claimedInvoices.clear();
|
|
4429
|
+
this.rehydrate();
|
|
4430
|
+
}
|
|
4418
4431
|
async getMandate() {
|
|
4419
4432
|
return this.mandate;
|
|
4420
4433
|
}
|
|
@@ -4557,6 +4570,9 @@ var FileAuditStore = class {
|
|
|
4557
4570
|
const digest = sha256(stableStringify({ decisionId: decision.decisionId, status: decision.status, request: decision.request, violatedRule: decision.violatedRule ?? null }));
|
|
4558
4571
|
const hash = sha256(`${prevHash}|${digest}|${seq}|${ts}`);
|
|
4559
4572
|
const record2 = { seq, decisionId: decision.decisionId, status: decision.status, subject: decision.subject, digest, prevHash, hash, ts };
|
|
4573
|
+
if (typeof decision.request?.purpose === "string" && decision.request.purpose.trim()) {
|
|
4574
|
+
record2.purpose = decision.request.purpose.slice(0, 500);
|
|
4575
|
+
}
|
|
4560
4576
|
if (decision.status === "ALLOW") {
|
|
4561
4577
|
const req = decision.request;
|
|
4562
4578
|
if (typeof req?.amount === "number" && Number.isFinite(req.amount))
|
|
@@ -4590,6 +4606,9 @@ var FileAuditStore = class {
|
|
|
4590
4606
|
}
|
|
4591
4607
|
};
|
|
4592
4608
|
|
|
4609
|
+
// ../mcp/src/core.ts
|
|
4610
|
+
import { statSync } from "node:fs";
|
|
4611
|
+
|
|
4593
4612
|
// ../mcp/src/config.ts
|
|
4594
4613
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
4595
4614
|
import { homedir } from "node:os";
|
|
@@ -4671,7 +4690,25 @@ function resolveMandateRules(cfg) {
|
|
|
4671
4690
|
}
|
|
4672
4691
|
|
|
4673
4692
|
// ../mcp/src/telemetry.ts
|
|
4674
|
-
var CLIENT_VERSION = true ? "0.1.
|
|
4693
|
+
var CLIENT_VERSION = true ? "0.1.12" : "dev";
|
|
4694
|
+
function bandOf(amount) {
|
|
4695
|
+
if (typeof amount !== "number" || !Number.isFinite(amount) || amount <= 0) return void 0;
|
|
4696
|
+
if (amount < 10) return "lt10";
|
|
4697
|
+
if (amount < 100) return "10_99";
|
|
4698
|
+
if (amount < 1e3) return "100_999";
|
|
4699
|
+
if (amount < 1e4) return "1k_10k";
|
|
4700
|
+
if (amount < 1e5) return "10k_100k";
|
|
4701
|
+
return "gte100k";
|
|
4702
|
+
}
|
|
4703
|
+
function capRatioOf(amount, perTxMax) {
|
|
4704
|
+
if (typeof amount !== "number" || typeof perTxMax !== "number") return void 0;
|
|
4705
|
+
if (!Number.isFinite(amount) || !Number.isFinite(perTxMax) || perTxMax <= 0 || amount <= perTxMax) return void 0;
|
|
4706
|
+
const r = amount / perTxMax;
|
|
4707
|
+
if (r < 2) return "1_2x";
|
|
4708
|
+
if (r < 5) return "2_5x";
|
|
4709
|
+
if (r < 10) return "5_10x";
|
|
4710
|
+
return "gt10x";
|
|
4711
|
+
}
|
|
4675
4712
|
var currentShell = "mcp";
|
|
4676
4713
|
function setTelemetryShell(shell) {
|
|
4677
4714
|
currentShell = shell;
|
|
@@ -4704,9 +4741,17 @@ function resultOf(status, violatedRule) {
|
|
|
4704
4741
|
if (r.startsWith("non_positive_amount") || r.startsWith("invalid_")) return "deny_invalid";
|
|
4705
4742
|
return "deny_scope";
|
|
4706
4743
|
}
|
|
4707
|
-
function record(type, result) {
|
|
4744
|
+
function record(type, result, band, capRatio) {
|
|
4708
4745
|
if (!telemetryEnabled()) return;
|
|
4709
|
-
buffer.push({
|
|
4746
|
+
buffer.push({
|
|
4747
|
+
type,
|
|
4748
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4749
|
+
client_version: CLIENT_VERSION,
|
|
4750
|
+
shell: currentShell,
|
|
4751
|
+
...result ? { result } : {},
|
|
4752
|
+
...band ? { band } : {},
|
|
4753
|
+
...capRatio ? { cap_ratio: capRatio } : {}
|
|
4754
|
+
});
|
|
4710
4755
|
if (!flushTimer) {
|
|
4711
4756
|
flushTimer = setTimeout(() => {
|
|
4712
4757
|
void flush();
|
|
@@ -4716,7 +4761,7 @@ function record(type, result) {
|
|
|
4716
4761
|
}
|
|
4717
4762
|
var recordInstall = () => record("install");
|
|
4718
4763
|
var recordAgentActive = () => record("agent_active");
|
|
4719
|
-
var recordDecision = (status, violatedRule) => record("decision", resultOf(status, violatedRule));
|
|
4764
|
+
var recordDecision = (status, violatedRule, amount, perTxMax) => record("decision", resultOf(status, violatedRule), bandOf(amount), capRatioOf(amount, perTxMax));
|
|
4720
4765
|
var recordUpgradeIntent = () => record("upgrade_intent");
|
|
4721
4766
|
async function flush() {
|
|
4722
4767
|
if (flushTimer) {
|
|
@@ -4779,11 +4824,34 @@ function makeCore() {
|
|
|
4779
4824
|
if (!url || !key) throw new Error("FIDACY_MODE=http requires FIDACY_API_URL and FIDACY_API_KEY");
|
|
4780
4825
|
return new HttpFidacyCore(url, key, process.env.FIDACY_PUBLIC_KEY_PEM ?? "");
|
|
4781
4826
|
}
|
|
4782
|
-
|
|
4783
|
-
|
|
4827
|
+
let activeMandate = buildMandate();
|
|
4828
|
+
const dev = new DevFidacyCore({
|
|
4829
|
+
mandate: activeMandate,
|
|
4784
4830
|
auditLogPath: auditLogPath(),
|
|
4785
|
-
onDecision: (d) => recordDecision(d.status, d.violatedRule)
|
|
4831
|
+
onDecision: (d) => recordDecision(d.status, d.violatedRule, d.request?.amount, activeMandate?.allow?.perTxMax)
|
|
4786
4832
|
});
|
|
4833
|
+
const mtimeOf = () => statSync(configPath(), { throwIfNoEntry: false })?.mtimeMs ?? 0;
|
|
4834
|
+
let seenMtime = mtimeOf();
|
|
4835
|
+
const maybeReload = () => {
|
|
4836
|
+
const m = mtimeOf();
|
|
4837
|
+
if (m !== seenMtime) {
|
|
4838
|
+
seenMtime = m;
|
|
4839
|
+
activeMandate = buildMandate();
|
|
4840
|
+
dev.setMandate(activeMandate);
|
|
4841
|
+
}
|
|
4842
|
+
};
|
|
4843
|
+
return {
|
|
4844
|
+
getMandate: () => {
|
|
4845
|
+
maybeReload();
|
|
4846
|
+
return dev.getMandate();
|
|
4847
|
+
},
|
|
4848
|
+
decide: (req, subject) => {
|
|
4849
|
+
maybeReload();
|
|
4850
|
+
return dev.decide(req, subject);
|
|
4851
|
+
},
|
|
4852
|
+
getProof: (decisionId) => dev.getProof(decisionId),
|
|
4853
|
+
publicKey: () => dev.publicKey()
|
|
4854
|
+
};
|
|
4787
4855
|
}
|
|
4788
4856
|
|
|
4789
4857
|
// ../mcp/src/upgrade.ts
|
|
@@ -4799,7 +4867,7 @@ function requestUpgrade() {
|
|
|
4799
4867
|
}
|
|
4800
4868
|
|
|
4801
4869
|
// ../mcp/src/provision.ts
|
|
4802
|
-
var CLIENT_VERSION2 = true ? "0.1.
|
|
4870
|
+
var CLIENT_VERSION2 = true ? "0.1.12" : "dev";
|
|
4803
4871
|
function provisionEnabled() {
|
|
4804
4872
|
const v = (process.env.FIDACY_DISABLE_PROVISION ?? "").trim().toLowerCase();
|
|
4805
4873
|
return !(v === "1" || v === "true" || v === "yes");
|
|
@@ -4962,7 +5030,7 @@ async function postOnce(fetchImpl, url, headers, payload, timeoutMs) {
|
|
|
4962
5030
|
body: payload,
|
|
4963
5031
|
signal: controller.signal
|
|
4964
5032
|
});
|
|
4965
|
-
} catch
|
|
5033
|
+
} catch {
|
|
4966
5034
|
const aborted = controller.signal.aborted;
|
|
4967
5035
|
throw new AssessError({ type: aborted ? "timeout" : "network_error", status: 0 });
|
|
4968
5036
|
} finally {
|
|
@@ -5118,7 +5186,7 @@ var index_default = defineToolPlugin({
|
|
|
5118
5186
|
async execute(params, config) {
|
|
5119
5187
|
const d = await boot().decide(params, subjectOf(config));
|
|
5120
5188
|
const base = d.status === "ALLOW" ? `ALLOW (decision ${d.decisionId})${params.invoiceRef ? ` for invoice ${params.invoiceRef}` : ""}. To settle, call the executor with the SAME payee, amount, currency, and idempotencyKey, and set "grant" to EXACTLY this signed value:
|
|
5121
|
-
${d.grant}` : `DENY (decision ${d.decisionId}). Rule violated: ${d.violatedRule}. No grant issued, this payment cannot proceed. The denial itself is recorded in the tamper-evident, hash-chained audit: call get_audit_proof with decisionId ${d.decisionId} for the proof of what was blocked
|
|
5189
|
+
${d.grant}` : `DENY (decision ${d.decisionId}). Rule violated: ${d.violatedRule}. No grant issued, this payment cannot proceed. The denial itself is recorded in the tamper-evident, hash-chained audit: call get_audit_proof with decisionId ${d.decisionId} for the proof of what was blocked.${d.violatedRule?.startsWith("payee_not_in_allowlist") ? ` If the user trusts this payee, add "${params.payee}" to mandate.payees in ~/.fidacy/config.json and retry: the firewall picks the change up on the next call, no restart needed.` : ""}`;
|
|
5122
5190
|
const nudge = decisionNudge(d.status, d.violatedRule, "fidacy_upgrade");
|
|
5123
5191
|
const message = nudge ? `${base} ${nudge}` : base;
|
|
5124
5192
|
return { status: d.status, decisionId: d.decisionId, grant: d.grant, violatedRule: d.violatedRule, message };
|
package/openclaw.plugin.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
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.11",
|
|
7
7
|
"contracts": {
|
|
8
8
|
"tools": [
|
|
9
9
|
"request_payment",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fidacy/openclaw-plugin",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12",
|
|
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",
|