attestari 0.0.0-stage → 2.9.1

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 (3) hide show
  1. package/README.md +55 -2
  2. package/dist/hook.js +2416 -0
  3. package/package.json +29 -4
package/README.md CHANGED
@@ -1,3 +1,56 @@
1
- # Temporary Holding Version
1
+ # attestari
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ The Attestari Protect hook: the one file each agent (Claude Code first) runs itself.
4
+
5
+ - `dist/hook.js` is the whole hook. It is built from `src/` by esbuild, committed, and has no runtime
6
+ dependency: it requires only Node's own modules (`node:fs`, `node:path`, `node:os`, and the like).
7
+ - Build: `npm install && npm run build`. Test: `npm test` (builds, then runs `node --test` on the built file).
8
+ Type check: `npm run check`.
9
+ - `node dist/hook.js status` prints each agent folder under `~/.attestari/`; every unbuilt subcommand exits 2.
10
+ - Built for Claude Code: `pair --code <code>`, `claude-code session-start` (resolves the configured servers of its
11
+ folder and starts the check-in detached), `claude-code refresh` (the check-in: the policy, the events,
12
+ and the agent's own `deniedMcpServers` entries) and `claude-code pre-tool-use` (decides each MCP call, and starts the
13
+ refresh when the last check-in is over an hour old). `ATTESTARI_ACCOUNTS_URL` points the hook at another accounts
14
+ service only on loopback (`127.0.0.1`, `::1`, `localhost`: the tests' local server); any other address is ignored
15
+ with one line on stderr.
16
+ - What it resolves: `npx`/`bunx`/`pnpx`/`pnpm dlx`/`yarn dlx` an npm package, `uvx`/`pipx run` a PyPI package, a URL a
17
+ remote, any other command (`docker`, `node file.js`, an executable) a local tool. A registry runner whose package
18
+ it cannot name (an alias, a git, tarball, file or URL spec, a second package, `${PKG}`, or any flag but `-y`,
19
+ `--yes`, `-q`, `--quiet`, `-p`/`--package`, uvx's `--from`, `--python` and `-p` (python) and pipx's `--spec`) is left out of the resolution,
20
+ reported to nobody, and denied as not checked, never a local tool; stderr says "its package could not be named"
21
+ with the key.
22
+ - What it keeps, under `~/.attestari/claude-code/`: `token`, `secret` (the key of a local tool's hash), `policy.json`
23
+ and `policy.etag`, `resolved/<folder>.json` and `written/<folder>.json` (per working folder: `<folder>` is the first
24
+ 16 hexadecimal characters of the SHA-256 of the session's `cwd`; the resolution holds the folder's path, and both
25
+ are dropped at a check-in once the folder is gone or its resolution was not rewritten by a session start for 30
26
+ days, its deny entries taken back when it was read whole), `sessions/<session_id>` (the folder a session
27
+ started in, its id and path, written at SessionStart; pruned after 30 days at a check-in), `events.jsonl`, and the
28
+ times `checked_in_at`, `refresh_started_at` (with the refresh's process id) and `next_refresh_at`. A call is decided
29
+ by the `resolved/` file of its session's start folder (the call's `cwd` follows Claude's `cd`; it is used only when
30
+ the session has no file); the check-in reports the union of them all, a key launching different packages in two folders
31
+ once per folder as `<key>/<8 hex of the folder's hash>`. `refresh --cwd <folder>` resolves that folder first when
32
+ it has no file yet. A check-in answered 401 `invalid_token` (the agent was removed) deletes `token`, `policy.json`
33
+ and `policy.etag`, so every MCP call is then denied until the agent is paired again; the deny entries are written
34
+ only when `~/.claude/settings.json` is unchanged between the reading and the rename.
35
+ - The build also copies `dist/hook.js` to `plugins/attestari/hooks/hook.js`, the Claude Code plugin's copy (the
36
+ marketplace is `plugins/`); `test/build.test.mjs` refuses a difference, and CI refuses a committed copy older than
37
+ the build. `pair` installs the plugin when `claude` is on the PATH (`claude plugin marketplace add
38
+ attestari-ai/plugins`, then `claude plugin install attestari@attestari --scope user`; `ATTESTARI_MARKETPLACE` names
39
+ another marketplace, such as a local `plugins/` folder) and otherwise prints the two commands. What the hook reads
40
+ and writes on a computer: `docs/app.attestari.ai/hook.md`.
41
+ - The build also makes `dist/gateway.js` (from `src/gateway-main.ts`; not committed itself, but copied byte for byte to
42
+ `extension/server/gateway.js`, which is, and packed into `attestari.mcpb` by `npm run pack:extension`): the Claude
43
+ Desktop extension's gateway (M2.5), one MCP server on stdio that starts the child servers it is given, in the home
44
+ folder, and relays them under `<key>__`, with its own `attestari_status` tool. Run with no argument (as Claude
45
+ Desktop runs it) it first runs a provisional plan from the policy held (no network call before `initialize` is
46
+ answered), then pairs by `ATTESTARI_INSTALL_CODE`, checks in as `Claude Desktop`, decides from the policy which
47
+ servers of `~/.attestari/claude-desktop/servers.json` to start (`desktop.ts`), and checks in again hourly, stopping
48
+ and starting children as the policy moves; `checkin.ts` is the check-in it makes (session.ts's refresh without the
49
+ Claude Code parts; session.ts keeps its own copy so `dist/hook.js` does not move). `--servers <file>` runs it on a
50
+ `{servers, refused, notice}` file instead, bypassing the policy, and only with `ATTESTARI_GATEWAY_UNSAFE_FILE=1` and
51
+ a loopback `ATTESTARI_ACCOUNTS_URL` (the tests'; the same condition holds for `ATTESTARI_GATEWAY_REFRESH_MS`). Once
52
+ paired it moves Claude Desktop's own servers (`claude_desktop_config.json`'s `mcpServers`) into `servers.json` when
53
+ `ATTESTARI_MOVE_SERVERS` is `"true"`, with a dated backup beside the config, and puts them back when it is `"false"`
54
+ (`adapters/claude-desktop.ts`). What it reads, sends and writes: `docs/app.attestari.ai/hook.md`,
55
+ "Claude Desktop".
56
+ - The sources, the tests and the built file are LF everywhere.