@fidacy/openclaw-plugin 0.2.9 → 0.2.11

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 CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.10
4
+
5
+ ### Patch Changes
6
+
7
+ - 01f0734: Two fixes proven against a real OpenClaw host. Install/active telemetry now flushes immediately at plugin load instead of on a 2s timer that died with short-lived CLI commands (openclaw plugins install/list), which is why the plugin channel reported zero despite real installs. And the manifest now declares every registered tool (spend_summary, list_decisions, sentinel_alerts, explain_decision were missing, tripping openclaw plugins doctor); the build stamps contracts.tools from the source so it can never drift again.
8
+
3
9
  ## 0.2.9
4
10
 
5
11
  ### Patch Changes
package/dist/index.js CHANGED
@@ -4308,10 +4308,23 @@ function lookalikePayee(payee, allowed) {
4308
4308
  }
4309
4309
  return null;
4310
4310
  }
4311
+ function validateMandateCaps(mandate) {
4312
+ const bad = (v) => typeof v !== "number" || !Number.isFinite(v) || v <= 0;
4313
+ if (!mandate.allow || typeof mandate.allow !== "object")
4314
+ return "invalid_mandate:missing_allow";
4315
+ if (bad(mandate.allow.perTxMax))
4316
+ return `invalid_mandate_cap:perTxMax=${String(mandate.allow.perTxMax)}`;
4317
+ if (bad(mandate.allow.maxTotal))
4318
+ return `invalid_mandate_cap:maxTotal=${String(mandate.allow.maxTotal)}`;
4319
+ return null;
4320
+ }
4311
4321
  function evaluate(mandate, req, spentSoFar) {
4312
4322
  const now = Date.now();
4313
4323
  if (mandate.revoked)
4314
4324
  return "mandate_revoked";
4325
+ const badCap = validateMandateCaps(mandate);
4326
+ if (badCap)
4327
+ return badCap;
4315
4328
  if (now < Date.parse(mandate.window.notBefore))
4316
4329
  return "before_mandate_window";
4317
4330
  if (now > Date.parse(mandate.window.notAfter))
@@ -4638,6 +4651,9 @@ import {
4638
4651
  readFileSync,
4639
4652
  writeFileSync
4640
4653
  } from "node:fs";
4654
+ function hasEngineKey(keyOverride) {
4655
+ return Boolean((keyOverride ?? process.env.FIDACY_ENGINE_API_KEY ?? "").trim());
4656
+ }
4641
4657
  function configDir() {
4642
4658
  return process.env.FIDACY_CONFIG_DIR ?? join(homedir(), ".fidacy");
4643
4659
  }
@@ -4698,18 +4714,29 @@ function ensureState() {
4698
4714
  function resolveMandateRules(cfg) {
4699
4715
  const m = cfg?.mandate ?? {};
4700
4716
  const envList = (v) => v === void 0 ? void 0 : v.split(",").map((s) => s.trim()).filter(Boolean);
4701
- const envNum = (v) => v === void 0 || v === "" ? void 0 : Number(v);
4717
+ const envNum = (name, v) => {
4718
+ if (v === void 0 || v.trim() === "") return void 0;
4719
+ const n = Number(v);
4720
+ if (!Number.isFinite(n) || n <= 0) {
4721
+ console.error(
4722
+ `[fidacy] ${name}="${v}" is not a positive number, so it cannot be enforced as a cap. Ignoring it and using the safe default. Write digits only, with no thousands separator, currency symbol or unit (e.g. ${name}=2500).`
4723
+ );
4724
+ return void 0;
4725
+ }
4726
+ return n;
4727
+ };
4728
+ const fileNum = (v) => typeof v === "number" && Number.isFinite(v) && v > 0 ? v : void 0;
4702
4729
  return {
4703
4730
  payees: envList(process.env.FIDACY_ALLOW_PAYEES) ?? m.payees ?? [],
4704
4731
  categories: envList(process.env.FIDACY_ALLOW_CATEGORIES) ?? m.categories ?? ["*"],
4705
4732
  currency: process.env.FIDACY_CURRENCY ?? m.currency ?? "USD",
4706
- perTxMax: envNum(process.env.FIDACY_PER_TX_MAX) ?? m.perTxMax ?? 2500,
4707
- maxTotal: envNum(process.env.FIDACY_MAX_TOTAL) ?? m.maxTotal ?? 1e4
4733
+ perTxMax: envNum("FIDACY_PER_TX_MAX", process.env.FIDACY_PER_TX_MAX) ?? fileNum(m.perTxMax) ?? 2500,
4734
+ maxTotal: envNum("FIDACY_MAX_TOTAL", process.env.FIDACY_MAX_TOTAL) ?? fileNum(m.maxTotal) ?? 1e4
4708
4735
  };
4709
4736
  }
4710
4737
 
4711
4738
  // ../mcp/src/telemetry.ts
4712
- var CLIENT_VERSION = true ? "0.2.9" : "dev";
4739
+ var CLIENT_VERSION = true ? "0.2.11" : "dev";
4713
4740
  function bandOf(amount) {
4714
4741
  if (typeof amount !== "number" || !Number.isFinite(amount) || amount <= 0) return void 0;
4715
4742
  if (amount < 10) return "lt10";
@@ -4748,6 +4775,14 @@ function anonId() {
4748
4775
  }
4749
4776
  var buffer = [];
4750
4777
  var flushTimer = null;
4778
+ var exitHookArmed = false;
4779
+ function armExitFlush() {
4780
+ if (exitHookArmed || typeof process === "undefined" || typeof process.once !== "function") return;
4781
+ exitHookArmed = true;
4782
+ process.once("beforeExit", () => {
4783
+ if (buffer.length > 0) void flush();
4784
+ });
4785
+ }
4751
4786
  function resultOf(status, violatedRule) {
4752
4787
  if (status === "ALLOW") return "allow";
4753
4788
  const r = violatedRule ?? "";
@@ -4762,6 +4797,7 @@ function resultOf(status, violatedRule) {
4762
4797
  }
4763
4798
  function record(type, result, band, capRatio, action) {
4764
4799
  if (!telemetryEnabled()) return;
4800
+ armExitFlush();
4765
4801
  buffer.push({
4766
4802
  type,
4767
4803
  ts: (/* @__PURE__ */ new Date()).toISOString(),
@@ -4888,7 +4924,7 @@ function requestUpgrade() {
4888
4924
  }
4889
4925
 
4890
4926
  // ../mcp/src/provision.ts
4891
- var CLIENT_VERSION2 = true ? "0.2.9" : "dev";
4927
+ var CLIENT_VERSION2 = true ? "0.2.11" : "dev";
4892
4928
  function provisionEnabled() {
4893
4929
  const v = (process.env.FIDACY_DISABLE_PROVISION ?? "").trim().toLowerCase();
4894
4930
  return !(v === "1" || v === "true" || v === "yes");
@@ -4985,9 +5021,6 @@ function noKeyCta() {
4985
5021
 
4986
5022
  // ../mcp/src/activation.ts
4987
5023
  var FREE_DECISIONS = 20;
4988
- function hasEngineKey(keyOverride) {
4989
- return Boolean((keyOverride ?? process.env.FIDACY_ENGINE_API_KEY ?? "").trim());
4990
- }
4991
5024
  function decisionsUsed() {
4992
5025
  return Math.max(readConfig()?.decisions_count ?? 0, sessionDecisionCount());
4993
5026
  }
@@ -5220,6 +5253,7 @@ var AssessError = class extends Error {
5220
5253
  status;
5221
5254
  details;
5222
5255
  rejection_reasons;
5256
+ billing;
5223
5257
  constructor(opts) {
5224
5258
  super(`Fidacy assess error (${opts.type}, HTTP ${opts.status})`);
5225
5259
  this.name = "AssessError";
@@ -5227,6 +5261,7 @@ var AssessError = class extends Error {
5227
5261
  this.status = opts.status;
5228
5262
  this.details = opts.details;
5229
5263
  this.rejection_reasons = opts.rejection_reasons;
5264
+ this.billing = opts.billing;
5230
5265
  }
5231
5266
  };
5232
5267
  var DEFAULT_TIMEOUT = 1e4;
@@ -5322,7 +5357,12 @@ async function postOnce(fetchImpl, url, headers, payload, timeoutMs) {
5322
5357
  const type = isRecord(parsed) && typeof parsed.error === "string" && parsed.error || `http_${res.status}`;
5323
5358
  const details = isRecord(parsed) ? parsed.details : void 0;
5324
5359
  const rejection_reasons = isRecord(parsed) && Array.isArray(parsed.rejection_reasons) ? parsed.rejection_reasons : void 0;
5325
- throw new AssessError({ type, status: res.status, details, rejection_reasons });
5360
+ const billing = res.status === 402 && isRecord(parsed) ? {
5361
+ reason: typeof parsed.reason === "string" ? parsed.reason : void 0,
5362
+ detail: typeof parsed.detail === "string" ? parsed.detail : void 0,
5363
+ billingUrl: typeof parsed.billing_url === "string" ? parsed.billing_url : void 0
5364
+ } : void 0;
5365
+ throw new AssessError({ type, status: res.status, details, rejection_reasons, billing });
5326
5366
  }
5327
5367
  if (!isRecord(parsed)) {
5328
5368
  throw new AssessError({ type: "invalid_response", status: res.status });
@@ -5404,6 +5444,7 @@ function onPluginLoad() {
5404
5444
  const state = ensureState();
5405
5445
  if (state.firstRun) recordInstall();
5406
5446
  recordAgentActive();
5447
+ void flush();
5407
5448
  void autoProvision();
5408
5449
  }
5409
5450
  var core;
@@ -1,14 +1,18 @@
1
1
  {
2
2
  "id": "fidacy",
3
- "name": "Fidacy Payment Firewall",
3
+ "name": "Fidacy AI Agent 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.2.6",
6
+ "version": "0.2.11",
7
7
  "contracts": {
8
8
  "tools": [
9
9
  "request_payment",
10
10
  "verify_mandate",
11
11
  "get_audit_proof",
12
+ "spend_summary",
13
+ "list_decisions",
14
+ "sentinel_alerts",
15
+ "explain_decision",
12
16
  "assess_action",
13
17
  "anchor_artifact",
14
18
  "check_artifact",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fidacy/openclaw-plugin",
3
- "version": "0.2.9",
3
+ "version": "0.2.11",
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
  "author": "Fidacy (ZeepCode Group Technology LLC) <hello@fidacy.com> (https://fidacy.com)",
@@ -56,8 +56,8 @@
56
56
  "openclaw": "2026.6.11",
57
57
  "typebox": "1.1.39",
58
58
  "typescript": "^5.6.3",
59
- "@fidacy/mcp": "0.3.0",
60
- "@fidacy/firewall": "0.1.1"
59
+ "@fidacy/firewall": "0.1.1",
60
+ "@fidacy/mcp": "0.3.3"
61
61
  },
62
62
  "scripts": {
63
63
  "build": "node scripts/bundle.mjs",