@consiliency/agent-board-cli 1.22.5 → 1.24.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.
@@ -0,0 +1,288 @@
1
+ import type { IdentityHarness } from "@consiliency/agent-board-client";
2
+ export declare const BOARD_MCP_MARKER = "agent-board-mcp";
3
+ export declare const METADATA_ONLY_FLAG = "--metadata-only";
4
+ export declare const OPENCODE_PLUGIN_PACKAGE = "@consiliency/agent-board-opencode";
5
+ export declare const PI_PACKAGE = "npm:@consiliency/agent-board-pi";
6
+ /** Claude Code events that each need exactly one `wake-hook.sh` hook (`docs/local-wake-signal.md`). */
7
+ export declare const CLAUDE_REQUIRED_HOOK_EVENTS: readonly ["SessionStart", "FileChanged"];
8
+ /** A wake hook is a command with a token whose BASENAME is this (see `namesWakeHook`). */
9
+ export declare const WAKE_HOOK_MARKER = "wake-hook.sh";
10
+ export declare const CLAUDE_PLUGIN_ID = "agent-board@message-board";
11
+ export declare const CLAUDE_PLUGIN_MARKETPLACE = "message-board";
12
+ /** Compared lower-cased, as Claude Code compares repos. */
13
+ export declare const CLAUDE_PLUGIN_REPO = "consiliency/message-board";
14
+ export declare const CLAUDE_PLUGIN_SERVER = "agent-board";
15
+ export declare const CLAUDE_PLUGIN_MCP_PACKAGE = "@consiliency/agent-board-mcp";
16
+ /** The SL-0 outcome: `B` = the FileChanged hook carries `asyncRewake: true`. */
17
+ export declare const CLAUDE_WAKE_SHAPE: "A" | "B";
18
+ export declare const CLAUDE_PLUGIN_HOOK_COMMANDS: Readonly<Record<string, string>>;
19
+ /** The stanza a plugin of version `version` must carry: the pin IS the plugin version. */
20
+ export declare function claudePluginStanza(version: string): {
21
+ command: string;
22
+ args: string[];
23
+ };
24
+ /**
25
+ * Whether a hook command names the wake hook. The tokenizer is frozen: split on whitespace, strip
26
+ * quotes, no comment handling; a token matches when its basename is exactly `wake-hook.sh`, so
27
+ * `codex-wake-hook.sh` does not. Floor: a hook that never names the basename is invisible.
28
+ */
29
+ export declare function namesWakeHook(command: string): boolean;
30
+ export interface ScopeContext {
31
+ cwd: string;
32
+ home: string;
33
+ env: Record<string, string | undefined>;
34
+ /** Claude Code's managed directory (Linux `/etc/claude-code`); injectable for tests. */
35
+ claudeManagedDir: string;
36
+ fs: RegistrationFs;
37
+ /** The OS, for the managed (MDM) sources doctor probes. Absent → treated as Linux. */
38
+ platform?: NodeJS.Platform;
39
+ /** The login name the macOS per-user managed plist is keyed by. */
40
+ userName?: string;
41
+ /** Registry probe for the Windows policy keys; default `nodeRegQuery`. */
42
+ regQuery?: RegQuery;
43
+ }
44
+ /** The filesystem reads registration makes; everything is read-only. */
45
+ export interface RegistrationFs {
46
+ /** File text, or null when the file does not exist. */
47
+ readFile(path: string): string | null;
48
+ /** Sorted entry names, or null when the directory does not exist. */
49
+ readdir(path: string): string[] | null;
50
+ lstat(path: string): {
51
+ uid: number;
52
+ size: number;
53
+ isFile: boolean;
54
+ } | null;
55
+ exists(path: string): boolean;
56
+ /** The canonical path (every symlink resolved), or null when it does not exist. */
57
+ realpath(path: string): string | null;
58
+ getuid(): number;
59
+ }
60
+ export declare const nodeRegistrationFs: RegistrationFs;
61
+ export declare class UnparseableConfigError extends Error {
62
+ constructor(message: string);
63
+ }
64
+ /** Keys that name a prototype slot rather than data: a file carrying one is refused. */
65
+ export declare const FORBIDDEN_CONFIG_KEYS: ReadonlySet<string>;
66
+ /** An OWN property of `value`, else undefined: nothing is read through a prototype. */
67
+ export declare function own(value: unknown, key: string): unknown;
68
+ /** JSONC: `//` and `/* *\/` comments and trailing commas removed outside strings, then JSON. */
69
+ export declare function parseJsonc(text: string): unknown;
70
+ /**
71
+ * A restricted TOML reader: enough of the grammar to read `[mcp_servers.*]` and `[projects.*]`
72
+ * tables without a new dependency, and fail-closed on anything outside it. It handles bare and
73
+ * quoted dotted keys, `[table]` and `[[array.table]]` headers, basic/literal (and multi-line)
74
+ * strings, arrays over several lines, inline tables, and bare scalars. Sub-tables nest, so
75
+ * `[mcp_servers.x.env]` is `x`'s `env`, never a server named `x.env`.
76
+ */
77
+ export declare function parseRestrictedToml(text: string): Record<string, unknown>;
78
+ type McpShape = "claude" | "toml" | "agy" | "opencode";
79
+ export interface McpEntry {
80
+ /** Server name (the harness merges same-named entries across its layers). */
81
+ name: string;
82
+ command: string | null;
83
+ args: string[];
84
+ /** The harness will not launch it (`disabled: true`, `enabled = false`). */
85
+ disabled: boolean;
86
+ /** The entry's own fields, as written: a field-merging harness overlays these across layers. */
87
+ fields: Readonly<Record<string, unknown>>;
88
+ shape: McpShape;
89
+ }
90
+ export interface HookEntry {
91
+ /** The handler's `type` (`command`, `http`, `prompt`, `agent`, `mcp_tool`); a non-string type is "". */
92
+ type: string;
93
+ /** A command handler's command; null for every other handler (its url or prompt is never kept). */
94
+ command: string | null;
95
+ /** Claude Code's `asyncRewake`: only a literal `true` counts. */
96
+ asyncRewake: boolean;
97
+ /**
98
+ * The group has a matcher that filters (round-2 F029): anything but absent or "". A SessionStart
99
+ * matcher filters on the start source, a FileChanged one on basename(file_path) (binary). The
100
+ * matcher text itself is never kept.
101
+ */
102
+ hasMatcher: boolean;
103
+ /** The handler's and its group's own key NAMES (never values), for the exact freeze. */
104
+ handlerKeys: string[];
105
+ groupKeys: string[];
106
+ }
107
+ export interface ScopeContribution {
108
+ mcp: McpEntry[];
109
+ /** Claude hooks: event → the hooks registered for it. */
110
+ hooks: Record<string, HookEntry[]>;
111
+ /** opencode `plugin` / pi `packages` specs. */
112
+ packages: string[];
113
+ }
114
+ export interface ScopeFile {
115
+ row: string;
116
+ path: string;
117
+ contribution: ScopeContribution;
118
+ /** A synthetic plugin file's plugin id (for the managed-plugin hook exemption); never echoed. */
119
+ pluginId?: string;
120
+ }
121
+ type Parser = "json" | "json_or_empty" | "jsonc" | "toml";
122
+ export interface ScopeRow {
123
+ /** Stable row name; reported, and keyed by the per-row fixture table in doctor.test.ts. */
124
+ name: string;
125
+ parser: Parser;
126
+ /** Precedence within the harness: a same-named entry in a higher-ranked row overrides. */
127
+ rank: number;
128
+ /**
129
+ * For a row whose paths walk from cwd up to the git root (cwd first), one file per directory:
130
+ * which end wins when two of its files name the same server. Absent for a single-path row, and
131
+ * for a row that already returns its paths in application order (`opencode_project`, which has
132
+ * two files per directory and must not have them swapped).
133
+ */
134
+ walkWins?: "nearest" | "farthest";
135
+ /** Every candidate file for this row (absent ones are skipped). */
136
+ paths(ctx: ScopeContext): string[];
137
+ /** Whether a present file at `path` is loaded by the harness (codex trust). Default: yes. */
138
+ loaded?(path: string, ctx: ScopeContext): boolean;
139
+ extract(document: unknown, ctx: ScopeContext): ScopeContribution;
140
+ }
141
+ /** Judge-relevant fields of one entry, from its own fields only. */
142
+ export declare function mcpEntry(name: string, fields: Readonly<Record<string, unknown>>, shape: McpShape): McpEntry;
143
+ /** Directories from `cwd` up to its git root (inclusive); just `cwd` outside a repository. */
144
+ export declare function walkToGitRoot(cwd: string, fs: RegistrationFs): string[];
145
+ /** The frozen, re-checked scope table (see the header for each amendment and its evidence). */
146
+ export declare const HARNESS_CONFIG_SCOPES: Readonly<Record<IdentityHarness, readonly ScopeRow[]>>;
147
+ /**
148
+ * How a harness combines a same-named entry across its layers (see the header): codex and
149
+ * opencode overlay the higher layer's fields (measured); claude replaces the whole entry
150
+ * (inferred); grok is assumed to behave like codex (unmeasured); agy and pi have one layer, so
151
+ * their value is never used.
152
+ */
153
+ export declare const MCP_LAYER_MERGE: Readonly<Record<IdentityHarness, "replace" | "fields">>;
154
+ /** Synthetic row names: authored, so no plugin id, marketplace name or path reaches a reason. */
155
+ export declare const CLAUDE_PLUGIN_ROW = "claude_plugin";
156
+ export declare const CLAUDE_FOREIGN_PLUGIN_ROW = "claude_plugin_foreign";
157
+ export type AutoUpdateSource = "env_disabled" | "config_disabled" | "settings" | "known_marketplaces" | "default" | "undetermined";
158
+ /** What doctor learned about OUR plugin. Values are raw; the report sanitises them. */
159
+ export interface ClaudePluginSummary {
160
+ installed: boolean;
161
+ /** Our plugin's board server is registered in this cwd (not turned off by `disabledMcpServers`). */
162
+ serverActive: boolean;
163
+ version: string | null;
164
+ pinnedMcpVersion: string | null;
165
+ sourceRef: string | null;
166
+ autoUpdate: {
167
+ effective: boolean;
168
+ source: AutoUpdateSource;
169
+ };
170
+ }
171
+ export interface ClaudePluginRead {
172
+ /** One synthetic file per enabled plugin read, ranked above user settings. */
173
+ files: ScopeFile[];
174
+ unparseable: string[];
175
+ /** An installPath (or a file under it) resolved outside the cache: nothing beyond it was read. */
176
+ untrusted: boolean;
177
+ failures: string[];
178
+ summary: ClaudePluginSummary;
179
+ hookPolicy: ClaudeHookPolicy;
180
+ }
181
+ /**
182
+ * Which hooks Claude Code runs (round-2 F027/F028; see the header's `hook policy`): settings
183
+ * hooks from every scope, from managed settings only, or none; plugin hooks from every plugin,
184
+ * only from plugins managed settings enable, or none.
185
+ */
186
+ export interface ClaudeHookPolicy {
187
+ settings: "all" | "managed_only" | "none";
188
+ plugins: "all" | "managed_only" | "none";
189
+ /** Plugin ids managed settings enable (`enabledPlugins[id] === true`), for `managed_only`. */
190
+ managedPluginIds: ReadonlySet<string>;
191
+ /** The managed-plugin set comes from somewhere doctor cannot read (managed `prependPlugins`/`appendPlugins`). */
192
+ unjudgeable: boolean;
193
+ /**
194
+ * The managed tier may not be the file doctor reads (round-3 N1): a server-managed or MDM source
195
+ * replaces the file tier entirely ("first-wins"), and doctor reads neither. True when the probe
196
+ * found evidence of one, or could not complete.
197
+ */
198
+ managedTierUnreadable: boolean;
199
+ probe: ManagedPolicyProbe;
200
+ }
201
+ export declare const CLAUDE_REMOTE_SETTINGS_FILE = "remote-settings.json";
202
+ /**
203
+ * Storage-v5 (round 4): the binary writes the server-managed payload to its state store
204
+ * (`Re.state("remote-settings")`, a `state` namespace in the config home) and a signed-cache
205
+ * sidecar beside the json path. The store's exact on-disk name is not recoverable from strings,
206
+ * so every candidate is probed; any one present is evidence.
207
+ */
208
+ export declare const CLAUDE_REMOTE_SETTINGS_STATE_CANDIDATES: readonly string[];
209
+ export declare const CLAUDE_REMOTE_SETTINGS_SIDECARS: readonly string[];
210
+ export declare const MACOS_MANAGED_PREFERENCES = "/Library/Managed Preferences";
211
+ export declare const MACOS_POLICY_PLIST = "com.anthropic.claudecode.plist";
212
+ export declare const WINDOWS_POLICY_KEYS: Readonly<{
213
+ hklm: "HKLM\\SOFTWARE\\Policies\\ClaudeCode";
214
+ hkcu: "HKCU\\SOFTWARE\\Policies\\ClaudeCode";
215
+ }>;
216
+ export declare const WINDOWS_POLICY_VALUE = "Settings";
217
+ /** Where WSL's Windows interop puts reg.exe; the binary reads HKLM policy through this path. */
218
+ export declare const WSL_REG_EXE = "/mnt/c/Windows/System32/reg.exe";
219
+ export declare const WSL_WINDOWS_MANAGED_DIR = "/mnt/c/Program Files/ClaudeCode";
220
+ export type RegQueryOutcome = {
221
+ kind: "present";
222
+ } | {
223
+ kind: "absent";
224
+ } | {
225
+ kind: "error";
226
+ cause: "reg_unavailable" | "reg_timeout" | "reg_failed";
227
+ };
228
+ /** `reg query <key> /v Settings`, read-only. */
229
+ export type RegQuery = (regExe: string, key: string) => RegQueryOutcome;
230
+ /**
231
+ * The binary's own query: `reg query <key> /v Settings`, an argv array, no shell, 5 s. Exit 0 →
232
+ * the value is there; reg's "unable to find" → not there (the binary's own test); anything else —
233
+ * no reg.exe, a timeout, another failure — is an error, never "absent".
234
+ */
235
+ export declare function regQueryWith(timeoutMs: number): RegQuery;
236
+ export declare const nodeRegQuery: RegQuery;
237
+ /** What doctor looked at for admin policy: authored source names only. */
238
+ export interface ManagedPolicyProbe {
239
+ checked: string[];
240
+ /** Sources that exist: each means a tier doctor cannot read replaces the managed file. */
241
+ evidence: string[];
242
+ /** Authored causes of probes that could not finish (`reg_unavailable`, `reg_timeout`, `reg_failed`, `login_unavailable`). */
243
+ errors: string[];
244
+ /** The platform has admin sources doctor checks only by presence (macOS, Windows, WSL). */
245
+ unreadableSourcesPossible: boolean;
246
+ platformLabel: "Linux" | "macOS" | "Windows" | "WSL";
247
+ }
248
+ export declare function probeManagedPolicy(ctx: ScopeContext): ManagedPolicyProbe;
249
+ /** Evidence of (or an unfinished probe for) a tier that replaces the managed settings FILE. */
250
+ export declare const managedFileTierReplaced: (probe: ManagedPolicyProbe) => boolean;
251
+ /**
252
+ * IF-0-CCPLUGIN-3: every plugin enabled for `ctx.cwd`, followed from `enabledPlugins` to its
253
+ * installed row and read from the cache. Ours is the plugin id `agent-board@message-board` whose
254
+ * marketplace is declared, EVERYWHERE it is declared, as the github repository
255
+ * Consiliency/message-board; anything else contributing a board server or a wake hook is foreign.
256
+ */
257
+ export declare function readClaudePluginScopes(ctx: ScopeContext): ClaudePluginRead;
258
+ /** A package spec's identity without its version: `@scope/name@1.2.3` → `@scope/name`. */
259
+ export declare function packageIdentity(spec: string): string;
260
+ interface BoardEntryVerdict {
261
+ board: boolean;
262
+ flagged: boolean;
263
+ }
264
+ /** A board MCP entry names `agent-board-mcp` in its command/args, or through ONE user-owned wrapper file. */
265
+ export declare function judgeMcpEntry(entry: McpEntry, fs: RegistrationFs): BoardEntryVerdict;
266
+ export interface RegistrationVerdict {
267
+ status: "pass" | "fail" | "undetermined";
268
+ reason: string;
269
+ /** claude only: what doctor learned about our plugin, for the report and the pin check. */
270
+ plugin?: ClaudePluginSummary;
271
+ /** claude only: wake hooks per required event, across settings and plugins. */
272
+ hookCounts?: Record<(typeof CLAUDE_REQUIRED_HOOK_EVENTS)[number], number>;
273
+ /** claude only: which admin-policy sources were probed, for the report. */
274
+ managedPolicy?: ManagedPolicyProbe;
275
+ }
276
+ /**
277
+ * Read every scope row of `harness` for `cwd`. A file that fails to parse is reported, not guessed.
278
+ * `files` is in ascending precedence: a later file's same-named entry overrides an earlier one's.
279
+ */
280
+ export declare function readScopes(harness: IdentityHarness, ctx: ScopeContext): {
281
+ files: ScopeFile[];
282
+ unparseable: string[];
283
+ };
284
+ /** The `.claude.json` `projects` key Claude Code uses for `cwd`: the git root of its realpath, else the realpath. */
285
+ export declare function claudeProjectKey(ctx: ScopeContext): string;
286
+ /** IF-0-CREDPATH-4 registration, for one working directory. */
287
+ export declare function judgeRegistration(harness: IdentityHarness, ctx: ScopeContext): RegistrationVerdict;
288
+ export {};