@atbash/cli 0.5.15 → 0.6.1-dev.2

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.
Files changed (66) hide show
  1. package/README.md +389 -2
  2. package/dist/bin/atbash.js +39 -4
  3. package/dist/bin/atbash.js.map +1 -1
  4. package/dist/commands/config-cmd.js +15 -15
  5. package/dist/commands/config-cmd.js.map +1 -1
  6. package/dist/commands/connect.d.ts +115 -1
  7. package/dist/commands/connect.js +292 -73
  8. package/dist/commands/connect.js.map +1 -1
  9. package/dist/commands/github-scan.d.ts +104 -0
  10. package/dist/commands/github-scan.js +1054 -0
  11. package/dist/commands/github-scan.js.map +1 -0
  12. package/dist/commands/held.js +7 -2
  13. package/dist/commands/held.js.map +1 -1
  14. package/dist/commands/history.js +4 -1
  15. package/dist/commands/history.js.map +1 -1
  16. package/dist/commands/judge-options.d.ts +21 -0
  17. package/dist/commands/judge-options.js +24 -0
  18. package/dist/commands/judge-options.js.map +1 -0
  19. package/dist/commands/judge.js +5 -2
  20. package/dist/commands/judge.js.map +1 -1
  21. package/dist/commands/mcp-cmd.d.ts +13 -0
  22. package/dist/commands/mcp-cmd.js +216 -0
  23. package/dist/commands/mcp-cmd.js.map +1 -0
  24. package/dist/commands/policy.js +4 -1
  25. package/dist/commands/policy.js.map +1 -1
  26. package/dist/commands/scan.d.ts +45 -0
  27. package/dist/commands/scan.js +301 -0
  28. package/dist/commands/scan.js.map +1 -0
  29. package/dist/commands/setup.d.ts +533 -0
  30. package/dist/commands/setup.js +2653 -0
  31. package/dist/commands/setup.js.map +1 -0
  32. package/dist/commands/stats.js +3 -1
  33. package/dist/commands/stats.js.map +1 -1
  34. package/dist/commands/status.js +4 -1
  35. package/dist/commands/status.js.map +1 -1
  36. package/dist/commands/tier.js +4 -1
  37. package/dist/commands/tier.js.map +1 -1
  38. package/dist/commands/tools.js +11 -4
  39. package/dist/commands/tools.js.map +1 -1
  40. package/dist/commands/whoami.js +4 -1
  41. package/dist/commands/whoami.js.map +1 -1
  42. package/dist/lib/grade-llm.d.ts +38 -0
  43. package/dist/lib/grade-llm.js +64 -0
  44. package/dist/lib/grade-llm.js.map +1 -0
  45. package/dist/lib/llm.d.ts +34 -0
  46. package/dist/lib/llm.js +101 -0
  47. package/dist/lib/llm.js.map +1 -0
  48. package/dist/lib/policy.d.ts +40 -0
  49. package/dist/lib/policy.js +94 -0
  50. package/dist/lib/policy.js.map +1 -0
  51. package/dist/lib/risk.d.ts +112 -0
  52. package/dist/lib/risk.js +288 -0
  53. package/dist/lib/risk.js.map +1 -0
  54. package/dist/lib/threats-llm.d.ts +39 -0
  55. package/dist/lib/threats-llm.js +72 -0
  56. package/dist/lib/threats-llm.js.map +1 -0
  57. package/dist/shared/atbash-targets.d.ts +49 -0
  58. package/dist/shared/atbash-targets.js +63 -0
  59. package/dist/shared/atbash-targets.js.map +1 -0
  60. package/dist/shared/openclaw-runtime.d.ts +221 -0
  61. package/dist/shared/openclaw-runtime.js +476 -0
  62. package/dist/shared/openclaw-runtime.js.map +1 -0
  63. package/dist/shared/win-exec.d.ts +63 -0
  64. package/dist/shared/win-exec.js +147 -0
  65. package/dist/shared/win-exec.js.map +1 -0
  66. package/package.json +4 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"risk.js","sourceRoot":"","sources":["../../src/lib/risk.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Optional LLM pass enumerating CROSS-TOOL threat chains.
3
+ *
4
+ * The deterministic engine grades one tool at a time, which is exactly what it
5
+ * can defend: a rule sees a name and a description. It cannot see that "read CRM"
6
+ * plus "send email" is an exfiltration path, because neither tool is dangerous
7
+ * alone. That combination is what this pass is for, and it is the analysis Koray
8
+ * described the hosted backend as doing.
9
+ *
10
+ * ADDITIVE ONLY. Threats never replace the deterministic paths and never move the
11
+ * risk score: the score gates CI through --fail-on, and a number that moved
12
+ * because a model phrased things differently this run would make that gate flaky.
13
+ * The dashboard rescores on threats; a terminal that exits non-zero must not.
14
+ *
15
+ * Spends the user's own key. One request, bounded, hard timeout; any failure
16
+ * returns no threats and the scan keeps its deterministic report.
17
+ */
18
+ import type { ScanTool, Severity, Verdict } from "./risk";
19
+ export interface Threat {
20
+ /** The bad OUTCOME in plain English, not a tool name. */
21
+ title: string;
22
+ /** Which capabilities combine to enable it, e.g. "CRM read + browser". */
23
+ enabledBy?: string;
24
+ category: string;
25
+ severity: Severity;
26
+ recommendedVerdict: Verdict;
27
+ consequence: string;
28
+ }
29
+ export interface ThreatOutcome {
30
+ threats: Threat[];
31
+ requests: number;
32
+ skipped: number;
33
+ error?: string;
34
+ }
35
+ export declare function deriveThreats(tools: ScanTool[], options: {
36
+ apiKey: string;
37
+ model?: string;
38
+ timeoutMs?: number;
39
+ }): Promise<ThreatOutcome>;
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deriveThreats = deriveThreats;
4
+ const llm_1 = require("./llm");
5
+ /** Matches the dashboard's ceiling, so the two passes see the same surface. */
6
+ const MAX_TOOLS = 200;
7
+ const DESC_CAP = 240;
8
+ const SYSTEM_PROMPT = `You are an AI-agent security analyst. Given an agent's tools, enumerate the most consequential risk paths — including CROSS-TOOL chains (e.g. read sensitive data + external send = exfiltration).
9
+
10
+ Frame each as a THREAT a non-technical manager understands — the bad OUTCOME, not the tool name. Good titles: "Infer sensitive personal characteristics", "Leak CRM data into external tools", "Issue unauthorized or excessive refunds", "Weaken its own policy or authority". Bad titles: raw tool names like "deletePet".
11
+
12
+ Return ONLY a JSON object of the form {"threats":[ ... ]}, no prose. Each entry:
13
+ {"title":"<the threat, plain English>","enabledBy":"<which capabilities enable it, e.g. 'CRM read + browser'>","category":"<one category from the list below>","severity":"low|medium|high","recommendedVerdict":"allow|hold|block|jail","consequence":"<concrete harm in plain words>"}
14
+
15
+ "category" MUST be EXACTLY one of these protection categories (pick the closest):
16
+ Financial, Communication, File system, Code execution, Network & web, Accounts & identity, Calendar, Self-modification, Cross-agent, Behavioral anomaly.
17
+
18
+ Rules:
19
+ - recommendedVerdict: block = must never run; jail = attempts to weaken its own authority; hold = needs human approval; allow = low-consequence.
20
+ - Judge the exposure the tools ALLOW, not intent. Never invent capabilities not implied by the tools.
21
+ - Return AT MOST 6 entries, the most consequential ones. Fewer is better than padding with near-duplicates.
22
+ - Keep every field short: "title" at most 8 words, "consequence" at most 15 words, "enabledBy" at most 8 words. Do not restate the title in the consequence.`;
23
+ const SEVERITIES = ["low", "medium", "high"];
24
+ const VERDICTS = ["allow", "hold", "block", "jail"];
25
+ async function deriveThreats(tools, options) {
26
+ const batch = tools.slice(0, MAX_TOOLS);
27
+ const skipped = Math.max(0, tools.length - batch.length);
28
+ if (batch.length === 0)
29
+ return { threats: [], requests: 0, skipped: 0 };
30
+ const catalog = batch.map((t) => ({ name: t.name, description: (t.description ?? "").slice(0, DESC_CAP) }));
31
+ const res = await (0, llm_1.chatJson)({
32
+ apiKey: options.apiKey,
33
+ model: options.model,
34
+ timeoutMs: options.timeoutMs,
35
+ system: SYSTEM_PROMPT,
36
+ user: JSON.stringify(catalog),
37
+ maxTokens: 2000,
38
+ });
39
+ if (!res.data)
40
+ return { threats: [], requests: res.requests, skipped, error: res.error };
41
+ // Accept the {"threats":[...]} wrapper or a bare array, since models drop the
42
+ // wrapper often enough that rejecting it would lose whole runs.
43
+ const raw = Array.isArray(res.data)
44
+ ? res.data
45
+ : Array.isArray(res.data.threats)
46
+ ? (res.data.threats)
47
+ : [];
48
+ const threats = [];
49
+ const seen = new Set();
50
+ for (const entry of raw) {
51
+ if (!entry || typeof entry !== "object")
52
+ continue;
53
+ const p = entry;
54
+ const title = (0, llm_1.coerceStr)(p.title, 140).trim();
55
+ if (!title || seen.has(title.toLowerCase()))
56
+ continue;
57
+ seen.add(title.toLowerCase());
58
+ const severity = SEVERITIES.find((s) => s === (0, llm_1.coerceStr)(p.severity, 12).trim().toLowerCase()) ?? "medium";
59
+ const verdict = VERDICTS.find((v) => v === (0, llm_1.coerceStr)(p.recommendedVerdict, 12).trim().toLowerCase()) ?? "hold";
60
+ const enabledBy = (0, llm_1.coerceStr)(p.enabledBy, 140).trim();
61
+ threats.push({
62
+ title,
63
+ ...(enabledBy ? { enabledBy } : {}),
64
+ category: (0, llm_1.coerceStr)(p.category, 60).trim() || "Behavioral anomaly",
65
+ severity,
66
+ recommendedVerdict: verdict,
67
+ consequence: (0, llm_1.coerceStr)(p.consequence, 200).trim(),
68
+ });
69
+ }
70
+ return { threats, requests: res.requests, skipped };
71
+ }
72
+ //# sourceMappingURL=threats-llm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"threats-llm.js","sourceRoot":"","sources":["../../src/lib/threats-llm.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Facts about WHERE Atbash lives — the deployments it trusts, and the on-disk
3
+ * locations it knows about.
4
+ *
5
+ * These are shared by the read-only connector (`atbash connect`) and the
6
+ * write-capable configurator (`atbash setup`). They live here rather than in
7
+ * either command because both must agree:
8
+ *
9
+ * - A host the connector will relay to must be a host setup will verify
10
+ * registration against. Two different allowlists would mean a deployment that
11
+ * can receive a scan but cannot confirm the agent it scanned.
12
+ * - A config path the scan reports must be a path setup can find. A client that
13
+ * shows up in the dashboard but not in `setup` reads as a bug in whichever of
14
+ * the two the operator happened to trust first.
15
+ *
16
+ * When they lived in connect.ts and setup imported them from there, a refactor of
17
+ * the connector could silently change the configurator's behaviour. Adding a
18
+ * client here updates both callers at once, which is the point.
19
+ */
20
+ /**
21
+ * Official Atbash deployments that legitimately serve the onboarding flow.
22
+ *
23
+ * The pairing screen builds `--host` from the page you opened, so every origin
24
+ * that can host onboarding must appear here. If production were missing, the real
25
+ * atbash.ai would be flagged "unrecognized destination" — a false alarm on the
26
+ * genuine article, which is worse than silence: it teaches people and agents to
27
+ * wave through the one warning that actually catches a swapped host.
28
+ *
29
+ * Matched on EXACT hostname, never a suffix — "atbash.ai.evil.com" must not pass.
30
+ * Deliberately not a *.vercel.app wildcard: that would bless anyone's preview.
31
+ */
32
+ export declare const KNOWN_HOSTS: Set<string>;
33
+ /**
34
+ * Used when neither --host nor ATBASH_HOST is given. Still the dev deployment,
35
+ * because it is the one running the current connector API; switch this to
36
+ * https://atbash.ai once production serves it (KNOWN_HOSTS already allows it).
37
+ */
38
+ export declare const DEFAULT_HOST = "https://chromia-verified-ai-dev-two.vercel.app";
39
+ /**
40
+ * MCP client config locations, relative to the user's home directory.
41
+ *
42
+ * Claude Code (`~/.claude.json`) and Codex (`~/.codex/config.toml`) are NOT here
43
+ * on purpose: each needs bespoke handling (per-project server maps, and TOML
44
+ * respectively) and both callers special-case them.
45
+ */
46
+ export declare const MCP_CONFIGS: {
47
+ label: string;
48
+ segs: string[];
49
+ }[];
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ /**
3
+ * Facts about WHERE Atbash lives — the deployments it trusts, and the on-disk
4
+ * locations it knows about.
5
+ *
6
+ * These are shared by the read-only connector (`atbash connect`) and the
7
+ * write-capable configurator (`atbash setup`). They live here rather than in
8
+ * either command because both must agree:
9
+ *
10
+ * - A host the connector will relay to must be a host setup will verify
11
+ * registration against. Two different allowlists would mean a deployment that
12
+ * can receive a scan but cannot confirm the agent it scanned.
13
+ * - A config path the scan reports must be a path setup can find. A client that
14
+ * shows up in the dashboard but not in `setup` reads as a bug in whichever of
15
+ * the two the operator happened to trust first.
16
+ *
17
+ * When they lived in connect.ts and setup imported them from there, a refactor of
18
+ * the connector could silently change the configurator's behaviour. Adding a
19
+ * client here updates both callers at once, which is the point.
20
+ */
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.MCP_CONFIGS = exports.DEFAULT_HOST = exports.KNOWN_HOSTS = void 0;
23
+ /**
24
+ * Official Atbash deployments that legitimately serve the onboarding flow.
25
+ *
26
+ * The pairing screen builds `--host` from the page you opened, so every origin
27
+ * that can host onboarding must appear here. If production were missing, the real
28
+ * atbash.ai would be flagged "unrecognized destination" — a false alarm on the
29
+ * genuine article, which is worse than silence: it teaches people and agents to
30
+ * wave through the one warning that actually catches a swapped host.
31
+ *
32
+ * Matched on EXACT hostname, never a suffix — "atbash.ai.evil.com" must not pass.
33
+ * Deliberately not a *.vercel.app wildcard: that would bless anyone's preview.
34
+ */
35
+ exports.KNOWN_HOSTS = new Set([
36
+ "atbash.ai",
37
+ "www.atbash.ai",
38
+ "chromia-verified-ai-dev-two.vercel.app",
39
+ "chromia-verified-ai-agent-scan.vercel.app",
40
+ ]);
41
+ /**
42
+ * Used when neither --host nor ATBASH_HOST is given. Still the dev deployment,
43
+ * because it is the one running the current connector API; switch this to
44
+ * https://atbash.ai once production serves it (KNOWN_HOSTS already allows it).
45
+ */
46
+ exports.DEFAULT_HOST = "https://chromia-verified-ai-dev-two.vercel.app";
47
+ /**
48
+ * MCP client config locations, relative to the user's home directory.
49
+ *
50
+ * Claude Code (`~/.claude.json`) and Codex (`~/.codex/config.toml`) are NOT here
51
+ * on purpose: each needs bespoke handling (per-project server maps, and TOML
52
+ * respectively) and both callers special-case them.
53
+ */
54
+ exports.MCP_CONFIGS = [
55
+ { label: "Claude Desktop", segs: ["Library", "Application Support", "Claude", "claude_desktop_config.json"] },
56
+ { label: "Claude Desktop", segs: [".config", "Claude", "claude_desktop_config.json"] },
57
+ { label: "Cursor", segs: [".cursor", "mcp.json"] },
58
+ { label: "Windsurf", segs: [".codeium", "windsurf", "mcp_config.json"] },
59
+ { label: "VS Code (MCP)", segs: [".vscode", "mcp.json"] },
60
+ { label: "Gemini CLI", segs: [".gemini", "settings.json"] },
61
+ { label: "Continue", segs: [".continue", "config.json"] },
62
+ ];
63
+ //# sourceMappingURL=atbash-targets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"atbash-targets.js","sourceRoot":"","sources":["../../src/shared/atbash-targets.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;GAkBG;;;AAEH;;;;;;;;;;;GAWG;AACU,QAAA,WAAW,GAAG,IAAI,GAAG,CAAC;IACjC,WAAW;IACX,eAAe;IACf,wCAAwC;IACxC,2CAA2C;CAC5C,CAAC,CAAC;AAEH;;;;GAIG;AACU,QAAA,YAAY,GAAG,gDAAgD,CAAC;AAE7E;;;;;;GAMG;AACU,QAAA,WAAW,GAAwC;IAC9D,EAAE,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC,SAAS,EAAE,qBAAqB,EAAE,QAAQ,EAAE,4BAA4B,CAAC,EAAE;IAC7G,EAAE,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC,SAAS,EAAE,QAAQ,EAAE,4BAA4B,CAAC,EAAE;IACtF,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC,EAAE;IAClD,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,UAAU,EAAE,UAAU,EAAE,iBAAiB,CAAC,EAAE;IACxE,EAAE,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC,EAAE;IACzD,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,SAAS,EAAE,eAAe,CAAC,EAAE;IAC3D,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,aAAa,CAAC,EAAE;CAC1D,CAAC"}
@@ -0,0 +1,221 @@
1
+ /** How this OpenClaw got onto the machine — decides the UPDATE command. */
2
+ export type OpenclawChannel = "brew-formula" | "brew-cask" | "npm" | "unknown";
3
+ /**
4
+ * Config subcommands this build has.
5
+ *
6
+ * Probed from `openclaw config --help`, because the boundary is not guessable
7
+ * from a version number. Observed: 2026.2.1 has only `get set unset`, while both
8
+ * 2026.6.6 and 2026.7.1 have `file get patch schema set unset validate`.
9
+ */
10
+ export interface OpenclawCaps {
11
+ /**
12
+ * `openclaw config patch` — "Patch config from a JSON5 object in one validated
13
+ * write. Objects merge recursively, arrays/scalars replace, and null deletes a
14
+ * path", with `--stdin` and `--dry-run`.
15
+ *
16
+ * This is EXACTLY the operation setup needs, performed by OpenClaw itself, so
17
+ * where it exists we stop hand-merging JSON. That hands OpenClaw responsibility
18
+ * for its own file format, key names, schema, permissions and migrations — all
19
+ * the things we kept getting wrong from the outside. It also removes the
20
+ * clobber hazard: a machine in the field had three
21
+ * `openclaw.json.clobbered.<timestamp>` files, so OpenClaw rewrites that file
22
+ * on its own and anything we hand-merge can be discarded without warning.
23
+ */
24
+ patch: boolean;
25
+ /** `openclaw config validate` — schema check without starting the gateway. */
26
+ validate: boolean;
27
+ /** `openclaw config schema` — the authoritative key list for THIS build. */
28
+ schema: boolean;
29
+ /** `openclaw config file` — where the active config actually lives. */
30
+ configFile: boolean;
31
+ }
32
+ export interface OpenclawRuntime {
33
+ /** False when there is no OpenClaw on this machine at all. */
34
+ present: boolean;
35
+ /** As reported by `openclaw --version`, e.g. "2026.7.1". Undefined if unparseable. */
36
+ version?: string;
37
+ /** Build hash when the version line carries one — pins a build exactly. */
38
+ build?: string;
39
+ channel: OpenclawChannel;
40
+ /** Resolved path to the binary, for diagnostics. */
41
+ binPath?: string;
42
+ caps: OpenclawCaps;
43
+ }
44
+ /**
45
+ * Where the `openclaw` on PATH came from.
46
+ *
47
+ * Path-based rather than asked of a package manager, because shelling out to
48
+ * brew and npm to answer a question we can read off a path is slow and can hang
49
+ * on a bad network — and this runs before we have written anything, where a
50
+ * hang looks like the command being broken.
51
+ *
52
+ * ⚠️ The npm case is not hypothetical or unusual: the machine that reported the
53
+ * original failure ran `/Users/m4/.nvm/versions/node/v24.13.0/bin/openclaw`,
54
+ * so `brew info openclaw-cli` there said "Not installed" while OpenClaw was
55
+ * plainly running. Telling that user `brew upgrade openclaw-cli` would have been
56
+ * useless, which is the whole reason this returns a channel at all.
57
+ */
58
+ export declare function detectChannel(binPath: string | undefined): OpenclawChannel;
59
+ /**
60
+ * The command that updates THIS install, or undefined when we cannot tell.
61
+ *
62
+ * Returning undefined is deliberate and better than a plausible guess: a user
63
+ * told to run `brew upgrade openclaw-cli` on an npm install gets "No available
64
+ * formula", concludes our instructions are wrong, and is no closer to an
65
+ * upgrade. `openclaw update` is the honest fallback where the channel is
66
+ * unknown — it is OpenClaw's own self-updater, and 2026.6.6's `doctor` already
67
+ * recommends exactly that ("Run `openclaw update` to update via your package
68
+ * manager (npm/pnpm)").
69
+ */
70
+ export declare function updateCommand(channel: OpenclawChannel): string;
71
+ /**
72
+ * Inspect the OpenClaw on this machine. Read-only: probes `--version` and
73
+ * `config --help`, writes nothing, and never throws.
74
+ */
75
+ export declare function detectOpenclaw(binary?: string): OpenclawRuntime;
76
+ /** How setup should write config on this machine. */
77
+ export type WriteStrategy =
78
+ /** `openclaw config patch --stdin` — OpenClaw merges and validates its own file. */
79
+ "openclaw-patch"
80
+ /** Hand-merge the JSON ourselves. The only option on 2026.2.x. */
81
+ | "hand-merge";
82
+ export declare function writeStrategy(rt: OpenclawRuntime): WriteStrategy;
83
+ /**
84
+ * Whether this OpenClaw is one we can wire at all, and what to say if not.
85
+ *
86
+ * DELIBERATELY PERMISSIVE. The floor is "there is an OpenClaw here", not "it has
87
+ * the newest config commands", because 2026.2.x installs are real — the box every
88
+ * CLI attestation was verified on is one — and the minimal entry-only config we
89
+ * now write was confirmed to load there with the plugin reporting
90
+ * `[atbash] plugin loaded` and `guard manager ready`. Narrowing support to the
91
+ * versions we happen to run is the mistake that produced this whole module.
92
+ *
93
+ * So an older build is a DEGRADED path with an offer, never a refusal: it gets
94
+ * the hand-merge, and the reason to upgrade is stated once, with the command for
95
+ * its own channel. Refusal is reserved for "no OpenClaw at all", where there is
96
+ * genuinely nothing to configure.
97
+ */
98
+ export declare function supportStatus(rt: OpenclawRuntime): {
99
+ supported: boolean;
100
+ degraded: boolean;
101
+ /** Plain-language line for a non-technical operator. */
102
+ message: string;
103
+ /** The channel-correct upgrade command, when upgrading would help. */
104
+ upgrade?: string;
105
+ };
106
+ /**
107
+ * What OpenClaw says about the Atbash plugin after we have wired it.
108
+ *
109
+ * `state` is deliberately not a boolean. "Is this agent governed?" has more than
110
+ * two answers, and collapsing them is how setup came to print a green summary
111
+ * over an ungoverned machine.
112
+ */
113
+ export interface PluginVerdict {
114
+ state:
115
+ /** Present, switched on, and loaded. The only state that means governed. */
116
+ "loaded"
117
+ /** On disk but switched off — governs nothing, and is a deliberate act. */
118
+ | "disabled"
119
+ /** OpenClaw tried and failed to load it. Worse than missing: it looks wired. */
120
+ | "load-error"
121
+ /** OpenClaw does not know about it at all. */
122
+ | "missing"
123
+ /** We could not ask. Must never be reported as success. */
124
+ | "unknown";
125
+ entry?: string;
126
+ version?: string;
127
+ /** Required runtime dependencies OpenClaw reports as absent. */
128
+ missingDeps?: string[];
129
+ /** Raw explanation for the operator, in OpenClaw's terms where possible. */
130
+ detail?: string;
131
+ }
132
+ /**
133
+ * Ask OpenClaw whether the plugin actually loaded — the check setup never had.
134
+ *
135
+ * ⚠️ WHY THIS IS NOT OPTIONAL. Setup used to declare success on the strength of
136
+ * having written what it meant to write. That is not the same claim: on the
137
+ * machine that reported the original failure, the config entry existed and the
138
+ * plugin did not, and OpenClaw said so plainly —
139
+ *
140
+ * plugins.entries.atbash-openclaw: plugin not found: atbash-openclaw
141
+ * (stale config entry ignored; remove it from plugins config)
142
+ *
143
+ * — while setup reported the run as done. An owner reading that summary believes
144
+ * their agent is governed. Nothing is more expensive than a false green on a
145
+ * control boundary, so the last word belongs to OpenClaw, not to us.
146
+ *
147
+ * ⚠️ DO NOT check `hookCount` or `hookNames` here. They are 0 and empty for a
148
+ * perfectly healthy plugin: hooks register when the GATEWAY starts, not when
149
+ * `plugins list` runs. Verified against a plugin that was demonstrably loaded and
150
+ * enforcing — it reports `hookCount: 0`. Treating that as a fault would fail
151
+ * every correct install.
152
+ */
153
+ export declare function verifyOpenclawPlugin(rt: OpenclawRuntime, opts: {
154
+ /** Entry ids that count as Atbash, current first. */
155
+ entryIds: readonly string[];
156
+ /** Pin the config being inspected, so this cannot read a different one. */
157
+ configPath?: string;
158
+ /**
159
+ * The package spec that was installed, e.g. `@atbash/atbash-openclaw@dev`.
160
+ * Used to catch the environment mismatch that loads cleanly and then fails
161
+ * every judge call: the plugin's endpoint and chain ids are compiled in, so a
162
+ * production build on a dev-onboarded agent is silently useless.
163
+ */
164
+ expectedSpec?: string;
165
+ /**
166
+ * The home directory being configured, when it is not the process's own.
167
+ *
168
+ * ⚠️ REQUIRED FOR A `--home` RUN, AND OMITTING IT PRODUCED A FALSE GREEN.
169
+ * Pinning `OPENCLAW_CONFIG_PATH` aims OpenClaw at the right CONFIG, but
170
+ * plugin discovery still walks `$HOME/.openclaw`, so the child process
171
+ * happily reported the plugin from the operator's real machine while we were
172
+ * asking about a different one. It printed "OpenClaw loads the plugin" about
173
+ * a home directory that contained no plugin at all — precisely the false
174
+ * green this whole check exists to prevent, produced by the check itself.
175
+ */
176
+ home?: string;
177
+ binary?: string;
178
+ }): PluginVerdict;
179
+ /**
180
+ * Ask OpenClaw whether a config is valid, when it can answer.
181
+ *
182
+ * This is the PREFLIGHT the command never had. Setup merged into
183
+ * `~/.openclaw/openclaw.json` without ever checking whether that file currently
184
+ * loads — so on a machine whose config was already broken it added its own entry
185
+ * to an unloadable file, and then its `openclaw plugins install` step died on the
186
+ * pre-existing breakage. Reported as an Atbash failure; it was not one.
187
+ *
188
+ * `undefined` means "cannot tell" (no `validate` on this build) and must be
189
+ * treated as such — not as a pass and not as a failure.
190
+ */
191
+ /**
192
+ * Does THIS build accept `hooks` on a plugin entry?
193
+ *
194
+ * Asked of `openclaw config schema`, never inferred from a version number or
195
+ * correlated with other capabilities — the whole point of this module.
196
+ *
197
+ * ⚠️ WHY THIS QUESTION EXISTS. `hooks` was ADDED, not removed: it is unknown on
198
+ * 2026.2.1 and valid, optional and undeprecated on 2026.6.6 and 2026.7.1, where
199
+ * an entry accepts `enabled | hooks | subagent | llm | config`. Because the entry
200
+ * schema is `additionalProperties: false`, the same key is FATAL on the old build
201
+ * and legitimate on the new one.
202
+ *
203
+ * Setup never writes `hooks` — nothing under it is required, and it gates hook
204
+ * families this plugin does not use (it registers only `before_tool_call`). But
205
+ * it also used to DELETE an operator's `hooks` block unconditionally, and on a
206
+ * build that accepts the key that is destroying their configuration:
207
+ * `hooks.timeoutMs` bounds this plugin's hook latency "without changing plugin
208
+ * code", which is a deliberate operator choice, not damage to repair.
209
+ *
210
+ * `undefined` means "cannot tell" (no `config schema` on this build). The caller
211
+ * must treat that as NOT supported and strip: keeping an unrecognized key makes
212
+ * OpenClaw refuse the entire config, and losing a timeout knob is a far smaller
213
+ * harm than a machine whose config will not load at all.
214
+ */
215
+ export declare function pluginEntryAcceptsHooks(rt: OpenclawRuntime, binary?: string): boolean | undefined;
216
+ export declare function validateConfig(rt: OpenclawRuntime, configPath: string, binary?: string,
217
+ /** The home being configured, when not the process's own — see verifyOpenclawPlugin. */
218
+ home?: string): {
219
+ valid: boolean;
220
+ problems: string;
221
+ } | undefined;