@axonflow/openclaw 2.1.0 → 2.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/dist/status.js ADDED
@@ -0,0 +1,377 @@
1
+ /**
2
+ * Plugin status surface — read-only introspection for users.
3
+ *
4
+ * Solves the W4 paid-Pro launch UX gap: a user installs the plugin, then
5
+ * needs to know their `tenant_id` to paste into the Stripe Payment Link
6
+ * custom field before they can buy Pro. There was no way to surface that
7
+ * value from the user's installed plugin without poking at on-disk
8
+ * `try-registration.json` themselves. This module reads that same file
9
+ * and reports the values back in a stable text shape the user can copy.
10
+ *
11
+ * Also reports tier state (Free vs Pro vs Pro-expired) and a redacted
12
+ * preview of the configured Pro license token, so a user mid-rollout
13
+ * can confirm whether `AXONFLOW_LICENSE_TOKEN` is wired through to
14
+ * this process AND when their license expires.
15
+ *
16
+ * V1 SaaS Plugin Pro tier-line surface parity (codex / cursor / claude /
17
+ * openclaw): the `tier` line includes the JWT `exp` claim from the
18
+ * configured license token in three shapes:
19
+ * - Pro (expires YYYY-MM-DD, N days remaining) exp future
20
+ * - Free (Pro expired YYYY-MM-DD — visit <url> to renew) exp past
21
+ * - Free (no Pro license configured) no token
22
+ * Plus a fallback "Pro (expires UNKNOWN — could not parse token)" for
23
+ * tokens whose JWT body does not parse. Signature is NEVER validated
24
+ * here — display only; the platform is the source of truth on validity.
25
+ *
26
+ * Security note (codex-plugin#41): we redact the license token to its
27
+ * last 4 chars and never print the full value. The `cmd_status` handler
28
+ * in the Codex plugin printed the raw token in human-readable status
29
+ * output, which made it trivially leakable via screen-share / copy-paste.
30
+ * Same surface here, same defensive redaction.
31
+ *
32
+ * Pure data + stdlib only — no network, no fs writes, no env mutations.
33
+ * Safe to call from any context (CLI, agent tool, library consumer).
34
+ */
35
+ import * as fs from "fs";
36
+ import * as path from "path";
37
+ import { axonflowConfigDir } from "./cache-dir.js";
38
+ /** Filename used by Community-SaaS bootstrap and recovery to persist credentials. */
39
+ const REGISTRATION_FILE_NAME = "try-registration.json";
40
+ /** Default agent endpoint the plugin talks to when no override is set. */
41
+ export const STATUS_DEFAULT_ENDPOINT = "https://try.getaxonflow.com";
42
+ /** Default upgrade URL surfaced in status output for free-tier users. */
43
+ export const STATUS_DEFAULT_UPGRADE_URL = "https://getaxonflow.com/pricing/";
44
+ /**
45
+ * Redact a license token to a fixed-shape preview suitable for printing
46
+ * in status output. Returns null for empty / whitespace-only / undefined
47
+ * inputs so callers can branch on tier presence.
48
+ *
49
+ * Output is always at most `…XXXX` (5 chars: ellipsis + last 4 chars of
50
+ * the input). Tokens shorter than 4 chars print as `…<token>` so we
51
+ * never print a token whose preview is longer than the token itself
52
+ * (which would be misleading) but we also never print MORE chars than
53
+ * the last 4. The full token is never reconstructible from the preview.
54
+ */
55
+ export function redactLicenseToken(token) {
56
+ if (typeof token !== "string")
57
+ return null;
58
+ const trimmed = token.trim();
59
+ if (trimmed.length === 0)
60
+ return null;
61
+ // Take last 4 chars (or fewer if the token is shorter). Always prefix
62
+ // with an ellipsis so the user can tell the value was truncated.
63
+ const tailLen = Math.min(4, trimmed.length);
64
+ const tail = trimmed.slice(trimmed.length - tailLen);
65
+ return `…${tail}`;
66
+ }
67
+ /**
68
+ * Read the persisted Community-SaaS registration file and extract the
69
+ * tenant_id. Returns null when the file is missing, unreadable, or has
70
+ * no usable tenant_id field. Never throws — status output should
71
+ * degrade gracefully when state is partial.
72
+ *
73
+ * Mode/permission checks are intentionally NOT enforced here: status is
74
+ * a read-only surface and we want to report a tenant_id even from a
75
+ * file with surprising permissions, so the user can see "yes you have
76
+ * a tenant, but the file is unsafe — re-register" rather than silently
77
+ * showing "no tenant_id found".
78
+ */
79
+ export function readPersistedTenantId(file) {
80
+ let raw;
81
+ try {
82
+ raw = fs.readFileSync(file, "utf8");
83
+ }
84
+ catch {
85
+ return null;
86
+ }
87
+ let parsed;
88
+ try {
89
+ parsed = JSON.parse(raw);
90
+ }
91
+ catch {
92
+ return null;
93
+ }
94
+ const tenantId = parsed["tenant_id"];
95
+ if (typeof tenantId !== "string" || tenantId.length === 0) {
96
+ return null;
97
+ }
98
+ return tenantId;
99
+ }
100
+ /**
101
+ * Parse the JWT `exp` claim out of an `AXON-`-prefixed license token.
102
+ * Returns the unix-epoch second value as an integer, or null on any
103
+ * parse failure (missing prefix, malformed segments, undecodable
104
+ * base64url, missing/non-numeric exp claim).
105
+ *
106
+ * Signature is NEVER validated here — we only extract `exp` for display.
107
+ * The platform is the source of truth on whether the token is actually
108
+ * valid (it re-validates the Ed25519 signature + DB row on every
109
+ * governed request).
110
+ *
111
+ * `Buffer.from(..., "base64url")` is supported on Node 16+; the openclaw
112
+ * plugin's package.json pins `>=18`, so this is safe.
113
+ */
114
+ export function parseLicenseTokenExpiry(token) {
115
+ if (typeof token !== "string")
116
+ return null;
117
+ const trimmed = token.trim();
118
+ if (trimmed.length === 0)
119
+ return null;
120
+ // Strip the AXON- prefix; rest is JWT (header.payload.signature).
121
+ const jwt = trimmed.startsWith("AXON-") ? trimmed.slice(5) : trimmed;
122
+ const parts = jwt.split(".");
123
+ if (parts.length < 2)
124
+ return null;
125
+ const payloadSegment = parts[1];
126
+ if (typeof payloadSegment !== "string" || payloadSegment.length === 0)
127
+ return null;
128
+ let decoded;
129
+ try {
130
+ decoded = Buffer.from(payloadSegment, "base64url").toString("utf8");
131
+ }
132
+ catch {
133
+ return null;
134
+ }
135
+ if (decoded.length === 0)
136
+ return null;
137
+ let payload;
138
+ try {
139
+ payload = JSON.parse(decoded);
140
+ }
141
+ catch {
142
+ return null;
143
+ }
144
+ const exp = payload["exp"];
145
+ if (typeof exp !== "number" || !Number.isFinite(exp) || !Number.isInteger(exp)) {
146
+ return null;
147
+ }
148
+ // Unix epoch seconds are positive integers; reject obvious garbage.
149
+ if (exp <= 0)
150
+ return null;
151
+ return exp;
152
+ }
153
+ /**
154
+ * Format a unix epoch second value as `YYYY-MM-DD` in UTC. Returns null
155
+ * on any toISOString failure (Date constructor rejects truly enormous
156
+ * values). `Date` accepts ms so we multiply by 1000.
157
+ */
158
+ export function formatExpiryDate(epochSeconds) {
159
+ if (epochSeconds === null || !Number.isFinite(epochSeconds))
160
+ return null;
161
+ try {
162
+ const iso = new Date(epochSeconds * 1000).toISOString();
163
+ return iso.slice(0, 10);
164
+ }
165
+ catch {
166
+ return null;
167
+ }
168
+ }
169
+ /**
170
+ * Compute days remaining until `epochSeconds`, given a "now". Forward-
171
+ * rounded (23h59m left → 1 day). Negative when `epochSeconds < now` —
172
+ * encoded as days SINCE expiry so consumers can sort / threshold.
173
+ *
174
+ * Returns null when either input is non-finite.
175
+ */
176
+ export function daysUntil(epochSeconds, nowEpochSeconds) {
177
+ if (epochSeconds === null || !Number.isFinite(epochSeconds) || !Number.isFinite(nowEpochSeconds)) {
178
+ return null;
179
+ }
180
+ const secondsDiff = epochSeconds - nowEpochSeconds;
181
+ if (secondsDiff >= 0) {
182
+ // Forward-round: 23h59m future → 1 day.
183
+ return Math.ceil(secondsDiff / 86400);
184
+ }
185
+ // Past: forward-round magnitude, return as negative.
186
+ return -Math.ceil((-secondsDiff) / 86400);
187
+ }
188
+ /**
189
+ * Build a fully-resolved status report from `StatusInputs`. Pure
190
+ * (modulo the single fs read for try-registration.json) and
191
+ * deterministic given the same inputs + on-disk state.
192
+ */
193
+ export function buildStatusReport(inputs = {}) {
194
+ const endpoint = (inputs.endpoint ?? "").trim() || STATUS_DEFAULT_ENDPOINT;
195
+ const upgradeUrl = (inputs.upgradeUrl ?? "").trim() || STATUS_DEFAULT_UPGRADE_URL;
196
+ const configDir = inputs.configDirOverride ?? axonflowConfigDir();
197
+ // axonflowConfigDir() can legitimately return "" on locked-down hosts.
198
+ // Use a stable string so the report still tells the user where we
199
+ // looked (or would have looked) — never show "" / undefined to users.
200
+ const registrationFile = configDir
201
+ ? path.join(configDir, REGISTRATION_FILE_NAME)
202
+ : "(unresolved — set AXONFLOW_CONFIG_DIR)";
203
+ const tenantId = configDir ? readPersistedTenantId(registrationFile) : null;
204
+ const licensePreview = redactLicenseToken(inputs.licenseToken);
205
+ // Compute tier + expiry. Three branches:
206
+ // 1. No token → "free", expires_at null.
207
+ // 2. Token + exp parsed:
208
+ // 2a. exp future → "pro", expires_at = YYYY-MM-DD, days_left positive.
209
+ // 2b. exp past → "pro_expired", expires_at = YYYY-MM-DD, days_left negative.
210
+ // 3. Token + exp NOT parsed → "pro", expires_at null (formatter
211
+ // surfaces "could not parse token").
212
+ let tier = "free";
213
+ let expiresAt = null;
214
+ let expiresInDays = null;
215
+ if (licensePreview !== null) {
216
+ // A token was supplied (any non-whitespace string) — start from "pro"
217
+ // and downgrade to "pro_expired" only if exp is parseable AND past.
218
+ tier = "pro";
219
+ const expEpoch = parseLicenseTokenExpiry(inputs.licenseToken);
220
+ if (expEpoch !== null) {
221
+ expiresAt = formatExpiryDate(expEpoch);
222
+ const now = inputs.nowEpochSeconds ?? Math.floor(Date.now() / 1000);
223
+ expiresInDays = daysUntil(expEpoch, now);
224
+ if (expEpoch <= now) {
225
+ tier = "pro_expired";
226
+ }
227
+ }
228
+ }
229
+ return {
230
+ tenant_id: tenantId,
231
+ endpoint,
232
+ tier,
233
+ license_token_preview: licensePreview,
234
+ expires_at: expiresAt,
235
+ expires_in_days: expiresInDays,
236
+ upgrade_url: upgradeUrl,
237
+ registration_file: registrationFile,
238
+ registration_present: tenantId !== null,
239
+ };
240
+ }
241
+ /**
242
+ * Resolve `StatusInputs` from process.env + an optional pluginConfig
243
+ * blob (mirrors `resolveConfig` semantics for the licenseToken /
244
+ * endpoint fields). Pulled out as its own function so tests can drive
245
+ * the env-resolution branches without the fs read.
246
+ *
247
+ * Resolution order:
248
+ * - licenseToken: env AXONFLOW_LICENSE_TOKEN > pluginConfig.licenseToken > undefined
249
+ * - endpoint: env AXONFLOW_ENDPOINT > pluginConfig.endpoint > STATUS_DEFAULT_ENDPOINT
250
+ * - upgradeUrl: env AXONFLOW_UPGRADE_URL > STATUS_DEFAULT_UPGRADE_URL
251
+ *
252
+ * `configDirOverride` is honoured for tests; production callers leave
253
+ * it undefined and rely on `axonflowConfigDir()` (which itself honours
254
+ * AXONFLOW_CONFIG_DIR).
255
+ */
256
+ export function resolveStatusInputs(pluginConfig, configDirOverride) {
257
+ const cfg = pluginConfig ?? {};
258
+ const envToken = typeof process.env["AXONFLOW_LICENSE_TOKEN"] === "string"
259
+ ? process.env["AXONFLOW_LICENSE_TOKEN"].trim()
260
+ : "";
261
+ const cfgToken = typeof cfg["licenseToken"] === "string"
262
+ ? cfg["licenseToken"].trim()
263
+ : "";
264
+ const licenseToken = envToken || cfgToken || undefined;
265
+ const envEndpoint = typeof process.env["AXONFLOW_ENDPOINT"] === "string"
266
+ ? process.env["AXONFLOW_ENDPOINT"].trim()
267
+ : "";
268
+ const cfgEndpoint = typeof cfg["endpoint"] === "string"
269
+ ? cfg["endpoint"].trim()
270
+ : "";
271
+ const endpoint = envEndpoint || cfgEndpoint || undefined;
272
+ const envUpgrade = typeof process.env["AXONFLOW_UPGRADE_URL"] === "string"
273
+ ? process.env["AXONFLOW_UPGRADE_URL"].trim()
274
+ : "";
275
+ const upgradeUrl = envUpgrade || undefined;
276
+ const inputs = {};
277
+ if (licenseToken !== undefined)
278
+ inputs.licenseToken = licenseToken;
279
+ if (endpoint !== undefined)
280
+ inputs.endpoint = endpoint;
281
+ if (upgradeUrl !== undefined)
282
+ inputs.upgradeUrl = upgradeUrl;
283
+ if (configDirOverride !== undefined)
284
+ inputs.configDirOverride = configDirOverride;
285
+ return inputs;
286
+ }
287
+ /**
288
+ * Format a status report as the human-readable text the CLI prints to
289
+ * stdout. Stable line shape so users can grep / pipe it.
290
+ *
291
+ * The report is intentionally chatty for first-time users: we explain
292
+ * what tenant_id is for (Stripe checkout custom field), and where to
293
+ * recover lost credentials. Power users who want a stable structured
294
+ * surface should consume `buildStatusReport()` directly.
295
+ */
296
+ export function formatStatusReport(report) {
297
+ const lines = [];
298
+ lines.push("AxonFlow OpenClaw plugin status");
299
+ lines.push("");
300
+ if (report.tenant_id) {
301
+ lines.push(` tenant_id: ${report.tenant_id}`);
302
+ lines.push(" (paste this into the Stripe checkout custom field when buying Pro)");
303
+ }
304
+ else {
305
+ lines.push(" tenant_id: (not registered)");
306
+ lines.push(` No registration file at ${report.registration_file}`);
307
+ lines.push(" The plugin auto-registers with Community SaaS on first init.");
308
+ lines.push(" Lost your registration? Run `axonflow-openclaw-recover <email>`");
309
+ }
310
+ lines.push(` endpoint: ${report.endpoint}`);
311
+ // V1 SaaS Plugin Pro tier-line surface parity (codex / cursor / claude /
312
+ // openclaw): four shapes, see StatusTier doc + parseLicenseTokenExpiry.
313
+ if (report.tier === "pro") {
314
+ if (report.expires_at !== null && report.expires_in_days !== null) {
315
+ lines.push(` tier: Pro (expires ${report.expires_at}, ${report.expires_in_days} days remaining)`);
316
+ }
317
+ else {
318
+ // Token loaded but JWT body did not parse. Treat as Pro for
319
+ // display; platform is the source of truth on validity.
320
+ lines.push(" tier: Pro (expires UNKNOWN — could not parse token)");
321
+ }
322
+ lines.push(` license: ${report.license_token_preview} (redacted — last 4 chars only)`);
323
+ }
324
+ else if (report.tier === "pro_expired") {
325
+ // Token still on disk but its exp is past — surface the renew CTA in
326
+ // the tier line itself so users notice it even if they only scan the
327
+ // first column. Don't print a generic "upgrade:" line on top — that
328
+ // would be redundant with the renew URL embedded in the tier line.
329
+ const expiresLabel = report.expires_at ?? "UNKNOWN";
330
+ lines.push(` tier: Free (Pro expired ${expiresLabel} — visit ${report.upgrade_url} to renew)`);
331
+ lines.push(` license: ${report.license_token_preview} (redacted — last 4 chars only)`);
332
+ lines.push(" The plugin will not forward an expired token.");
333
+ lines.push(" After buying a renewal, set AXONFLOW_LICENSE_TOKEN=<new> or restart with");
334
+ lines.push(" the new token in pluginConfig.licenseToken.");
335
+ }
336
+ else {
337
+ lines.push(" tier: Free (no Pro license configured)");
338
+ lines.push(` upgrade: ${report.upgrade_url}`);
339
+ }
340
+ lines.push("");
341
+ return lines.join("\n");
342
+ }
343
+ /**
344
+ * Build the one-line init log canary for the OpenClaw plugin's
345
+ * `registerAxonFlowGovernance` registration path. Three shapes:
346
+ * - Pro active → "[AxonFlow] Pro tier — expires YYYY-MM-DD (N days remaining); X-License-Token forwarded on every governed request"
347
+ * - Pro expired → "[AxonFlow] Free tier — Pro expired YYYY-MM-DD; visit <url> to renew"
348
+ * - Pro (could not parse) → "[AxonFlow] Pro tier active — license token configured, X-License-Token will be forwarded on every governed request" (preserves the legacy line for unparseable tokens — a noisy regression of the canary on every malformed token would be worse than silent fallback).
349
+ *
350
+ * Returns `null` when `licenseToken` is empty / null — Free-tier installs
351
+ * see no extra log line (matches the existing convention; only Pro state
352
+ * gets a canary).
353
+ */
354
+ export function buildProTierInitLogLine(licenseToken, upgradeUrl = STATUS_DEFAULT_UPGRADE_URL, nowEpochSeconds) {
355
+ if (typeof licenseToken !== "string" || licenseToken.trim().length === 0) {
356
+ return null;
357
+ }
358
+ const expEpoch = parseLicenseTokenExpiry(licenseToken);
359
+ if (expEpoch === null) {
360
+ // Legacy fallback — preserves byte-exact compat with the v2.1.x line
361
+ // for unparseable tokens. Mode-clarity test (tests/mode-clarity.test.ts)
362
+ // and any external grep on this string keep working.
363
+ return "[AxonFlow] Pro tier active — license token configured, X-License-Token will be forwarded on every governed request";
364
+ }
365
+ const now = nowEpochSeconds ?? Math.floor(Date.now() / 1000);
366
+ const expDate = formatExpiryDate(expEpoch);
367
+ const daysLeft = daysUntil(expEpoch, now);
368
+ if (expEpoch > now && expDate !== null && daysLeft !== null) {
369
+ return `[AxonFlow] Pro tier — expires ${expDate} (${daysLeft} days remaining); X-License-Token forwarded on every governed request`;
370
+ }
371
+ // exp is past — surface the renew CTA on init even though the token is
372
+ // still in config. Users notice this on the next plugin reload rather
373
+ // than discovering it on a 401 from a governed call.
374
+ const expLabel = expDate ?? "UNKNOWN";
375
+ return `[AxonFlow] Free tier — Pro expired ${expLabel}; visit ${upgradeUrl} to renew`;
376
+ }
377
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../src/status.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Plugin version — single source of truth.
3
+ *
4
+ * Kept in its own module so non-index consumers (axonflow-client.ts, etc.)
5
+ * can import it without creating a circular dependency through index.ts.
6
+ *
7
+ * Update this string before each release; CI release pipeline asserts it
8
+ * matches the package.json version on tag.
9
+ */
10
+ export declare const VERSION = "2.2.0";
11
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,eAAO,MAAM,OAAO,UAAU,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Plugin version — single source of truth.
3
+ *
4
+ * Kept in its own module so non-index consumers (axonflow-client.ts, etc.)
5
+ * can import it without creating a circular dependency through index.ts.
6
+ *
7
+ * Update this string before each release; CI release pipeline asserts it
8
+ * matches the package.json version on tag.
9
+ */
10
+ export const VERSION = "2.2.0";
11
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC"}
@@ -20,6 +20,10 @@
20
20
  "AXONFLOW_CONFIG_DIR": {
21
21
  "required": false,
22
22
  "description": "Override the per-user config directory used for the Community-SaaS registration file (mode 0o600). Defaults to OS conventions: $XDG_CONFIG_HOME/axonflow on Linux, ~/Library/Application Support/axonflow on macOS, %APPDATA%\\axonflow on Windows."
23
+ },
24
+ "AXONFLOW_LICENSE_TOKEN": {
25
+ "required": false,
26
+ "description": "AxonFlow Pro plugin-claim license token (begins with 'AXON-'). When set, the plugin forwards this token on every governed request via the X-License-Token header so the agent applies Pro-tier entitlements (extended audit retention, higher quotas, license-gated capabilities). Wins over pluginConfig.licenseToken when both are set. Get one from getaxonflow.com/plugins/pro — the token is emailed to the address used at Stripe Checkout."
23
27
  }
24
28
  },
25
29
  "runtimeBehavior": {
@@ -81,6 +85,12 @@
81
85
  "placeholder": "alice@example.com",
82
86
  "help": "Per-user identity forwarded as the X-User-Email header. Required for the override lifecycle endpoints (createOverride, revokeOverride, listOverrides) and for correct per-user scoping on explainDecision. Block-path features still work without it."
83
87
  },
88
+ "licenseToken": {
89
+ "label": "Pro License Token",
90
+ "sensitive": true,
91
+ "placeholder": "AXON-...",
92
+ "help": "AxonFlow Pro plugin-claim license token. When set, the plugin forwards this on every governed request via X-License-Token so the agent applies Pro-tier entitlements (longer audit retention, higher quotas, license-gated capabilities). AXONFLOW_LICENSE_TOKEN env var wins over this value."
93
+ },
84
94
  "highRiskTools": {
85
95
  "label": "High-Risk Tools",
86
96
  "placeholder": "web_fetch, message",
@@ -127,6 +137,9 @@
127
137
  "userEmail": {
128
138
  "type": "string"
129
139
  },
140
+ "licenseToken": {
141
+ "type": "string"
142
+ },
130
143
  "highRiskTools": {
131
144
  "type": "array",
132
145
  "items": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axonflow/openclaw",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "Policy enforcement, approval gates, and audit trails for OpenClaw — govern tool inputs before execution, scan outbound messages for PII/secrets, and record agent activity for review and compliance",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -11,8 +11,13 @@
11
11
  "types": "./dist/index.d.ts"
12
12
  }
13
13
  },
14
+ "bin": {
15
+ "axonflow-openclaw-recover": "./bin/axonflow-openclaw-recover.mjs",
16
+ "axonflow-openclaw-status": "./bin/axonflow-openclaw-status.mjs"
17
+ },
14
18
  "files": [
15
19
  "dist",
20
+ "bin",
16
21
  "policies",
17
22
  "README.md",
18
23
  "CHANGELOG.md",