diff --git a/CHANGELOG.md b/CHANGELOG.md index ecb16a87..6d7e2c78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,19 @@ All notable changes to the `@hyperdag/trustshell` package. -## Unreleased (on main, in no npm release) +## 1.9.0 — 2026-11-08 -`package.json` on main is `1.9.0-dev.0`: main is ahead of the published 1.8.0, and nothing below is in any npm release. +Cut from main, not from the 1.8.1 branch. The fixes in 1.8.1 are here too: its four regression suites +pass on this tree, and the first-run suite was added to main for this release. New runtime dependency: +`@noble/hashes` 1.3.2. The package is 165 files (1.8.1: 123). The MCP server lists 21 tools (1.8.1: 20); +the new one is `inspect_run`. + +A successful CI run is not proof that the code is correct: Inspect reports what GitHub recorded about a run, +and nothing about whether its tests mean anything. A claim line the checker cannot read in full, such as +Markdown, a question or words it has no template for, makes the whole text NOT_CHECKED, which is never a pass. + +Guard, Carry and the sandbox are experimental, and they apply only to what goes through them: `trustshell run`, +the MCP server and the SDK's gated functions. Anything an agent does another way is neither seen nor limited. - **`trustshell trust-report`: one report for testing your own agent.** It joins what the agent said about a GitHub Actions run (`check --out` records) with every command that went through `trustshell run`, and keeps the two apart. It says what to do next and what it cannot see. `trust-report verify` proves the folder is whole, matches its evidence and was sealed by a key you pin. See `examples/own-agent`. - **Fix: `trustshell run` no longer prints "started" for a command that could not start.** On Windows it also says why a `.cmd` shim such as npm cannot be started directly. @@ -20,9 +30,61 @@ All notable changes to the `@hyperdag/trustshell` package. - **Answers:** each fact is true, false or not_measured; a read that failed is never false. Exit 0 grounded, 1 not grounded, 2 not measured. - **Where it comes from:** a third implementation of the facts in erc-8004/erc-8004-contracts#99. It agrees with the case authors and agent-receipt-verify on all five public vectors (tests/erc8004-grounding.test.ts, recorded tapes replayed offline). - **Requirements:** the optional `ethers` peer. `OFFLINE=1` sends nothing. -- **Fix: `OFFLINE=1` now stops the MCP `verify_output` (and `verify`, `evaluate`) and the SDK `verifyOutput`/`evaluate` too.** They sent the text to HAL under `OFFLINE=1`; only `TRUSTSHELL_LOCAL_ONLY=1` stopped them. Now they answer `NOT_CHECKED` with `seenBy: []` and no request leaves. The CLI `verify` and `check`, `check_claim` and `inspect_run` already did this. (`TrustShell.score` in `src/lib/trustshell.ts`; tests/mcp-offline-sends-nothing.test.ts.) - **`inspect_run` over MCP (#610).** Inspect for agents: a run URL and the claims as text in; the same record, digest and card that `trustshell check --claims` produces out, from api.github.com only. 1.8.0's MCP server lists 20 tools, and this is not one of them. - **Fix: a valid proof for ANOTHER agent no longer verifies under the agent you asked about.** `presentProof(id, { verify: true })`, `verifyProof(presentation)`, `trustshell badge ` and `trustshell proof --verify` ran the WASM verifier on `(proofBytes, statement)` and never compared the statement's `agent_id` to the agent asked about, so the badge rendered green "✓ ZK-verified" under the wrong name with exit 0. Now a statement for a different agent is not verified (`verification.reason: "statement_for_other_agent"`, badge red, exit 3), and an id the engine cannot resolve (`GET /api/v1/repid/?with=id`) is NOT_CHECKED (`"binding_unavailable"`, badge grey, exit 3), never verified. The same rule the browser extension already had. `verifyProof(bytes, statement)` names no agent and is unchanged. +- **Fix: a receipt, envelope, evidence or claims file saved with `>` in Windows PowerShell 5.1 can be read (#687).** PowerShell writes UTF-16 there, and the CLI read it as UTF-8. +- **Fix: `trustshell demo` no longer needs the optional `ethers` peer (#684).** On a clean install it exited 3. The receipt hash now comes from `@noble/hashes` 1.3.2, the version `ethers` pins, and a test compares the two byte for byte. +- **`trustshell run` checks more of what it starts.** An allowed interpreter (`node`, `python`, `bash`, `powershell` and others) runs only a script the policy pins by path and sha256 (#664). `guard allow tool: --exe ` pins a tool to one file (#683); without it the check is by name only, and the run card says so. `TRUSTSHELL_REQUIRE_POLICY` makes an absent policy refuse instead of warn (#670). +- **`trustshell run --sandbox` and the disposable mission runner behind it (#661, #668).** Needs a local container runtime, and refuses without one. The command gets no network and hands back files through an airlock that refuses a registered canary in a file's body or name (#669, #673). A signed per-mission passport can be compared across missions (#666). +- **The SDK's own action functions consult the Guard policy (#665).** The package root exports a gated `TrustShell` and gated kernel, signer and memory functions. A denied call throws `GuardDeniedError`, and nothing is sent, signed or written. +- **Offline receipt verification.** `@hyperdag/trustshell/verify` recomputes a kernel receipt's verdict with no network, against keys you pin (#676). An owner can seal a receipt with their own install key: it is labelled `owner-self-signed`, shows authorship and wholeness only, and is never reported as independently verified (#681). The kernel client accepts signed `kernel-receipt/2` (#663). +- **`check --claims --guided`, EXPERIMENTAL and opt-in (#620).** A claim line that cites nothing is read as about that run, and every check on its commit is read. A run that passed only on a re-run is NOT_CHECKED. +- **A shadow-only pre-action forecast for `learn`, with an independently graded outcome (#614).** Draft record types. It changes nothing else. +- **Text from a policy, profile or bundle prints as text in `guard show` and the bundle commands (#636, #638, #639).** A refused bundle no longer replays what the unsigned file said, and a ledger line that is JSON but not a record reads BROKEN instead of crashing every command. First-run polish for `guard`, `run` and `bundle` (#647). + +## 1.8.1 — 2026-10-24 + +1.8.1 is 1.8.1-rc.0 (the section below) with its version set to 1.8.1. No package code changed +between them: the published files differ only in `package.json`'s version, this section, and the +README's install pins and npm `latest` row, which now name 1.8.1. + +## 1.8.1-rc.0 — 2026-10-24 (release candidate) + +A patch for 1.8.0: fixes to code that 1.8.0 already ships, and nothing new. It is cut from +`4b01ec34` (the 1.8.0 source), not from main, so main's Guard + Carry, `trustshell run`, `bundle` +and the MCP `inspect_run` are not in it. The MCP server still lists the same 20 tools. + +- **Fix: `OFFLINE=1` now stops the MCP `verify_output` (and `verify`, `evaluate`) and the SDK + `verifyOutput`/`evaluate` (#623).** In 1.8.0 they sent the text to HAL under `OFFLINE=1`; only + `TRUSTSHELL_LOCAL_ONLY=1` stopped them. Now they answer `NOT_CHECKED` with `seenBy: []` and no + request leaves. The CLI `verify` and `check` and the MCP `check_claim` already did this in 1.8.0. + (`TrustShell.score` in `src/lib/trustshell.ts`; tests/mcp-offline-sends-nothing.test.ts.) +- **Fix: `profile show` prints `./.trustshell/profile.md` and its problem lines as text (#637).** + The file sits in the working folder, so a cloned repository can carry one, and its control and + bidi characters reached the terminal raw. Newlines are kept. + (tests/antifragile-profile-show-scrub.test.ts.) +- **Fix: bare Groq, Cerebras, xAI, Perplexity, Fireworks, Supabase, Tavily and Replicate keys are + credential shapes (#642).** `remember` refused a labelled `GROQ_API_KEY=...` but stored a bare + `gsk_...` key, and `redact`, which runs before `check ""` sends anything, left it in. + Each shape uses its key's real length, so an identifier like `fw_update_package` stays readable. + (`src/memory/redact.ts`; tests/antifragile-credential-shapes.test.ts.) +- **Three CLI fixes from #647 (F3, F4, F9; the rest of #647 is guard, run and bundle).** `learn + inject` with no lesson for the turn says why on stderr, and stdout stays empty. The CLI drops + Node's `SQLite is an experimental feature` warning, and only that one. A refused + `TRUSTSHELL_API_URL` prints one line saying what to change instead of a stack trace (exit 3 as + before). (tests/release-1.8.1-first-run.test.ts.) +- **The `check` record says only what was looked up (#619).** The run check labelled its commit + fact "The commit exists on the remote", but no lookup is made; it now reads "GitHub reports the + commit this run ran on". The label is part of the `--claims` evidence record, so a 1.8.1 record + of the same run and claims has a different SHA-256 digest from a 1.8.0 one. +- **README, package description and LICENSE (#619, and the A2A lines).** The README no longer says + "ZK-verifiable receipt", "portable reputation" or "portable agentic trust harness", and no + longer carries a commercial-use term that the LICENSE does not contain; it credits x402 + (Coinbase) and Plonky3 (Polygon Labs). The A2A lines no longer promise a "verifiable settlement + receipt": `pollUntilSettled` reads the backend's contract record and does not verify it. The npm + description leads with Inspect. LICENSE and README name the copyright holder as Sean Goodwin + (Sean, 2026-10-23). +- **Package size.** 123 files, the same as 1.8.0. Runtime dependencies are unchanged. ## 1.8.0 — 2026-10-22 diff --git a/PRODUCT.md b/PRODUCT.md index 204dbfad..55f29d5b 100644 --- a/PRODUCT.md +++ b/PRODUCT.md @@ -16,7 +16,7 @@ Developers building AI agents who need to check what an agent says it did before Owner-controlled authority, evidence-backed actions, portable context and earned autonomy, as one harness that works with any model. This is shown with a reproducible demo (the pinned-run challenge), never asserted as unique: no comparative research supports "nobody else does this". ## Operating Context -- `npx @hyperdag/trustshell@latest check --claims-file ` (Inspect): reads one public GitHub Actions run from api.github.com, no account, no key. Developer preview, in npm `latest` (1.8.0). +- `npx @hyperdag/trustshell@latest check --claims-file ` (Inspect): reads one public GitHub Actions run from api.github.com, no account, no key. Developer preview, in npm `latest` (1.9.0). - trustshell.dev: the hosted sentence check (sends text to the engine), `/inspect` (the challenge), `/docs`. - Developers arrive from GitHub, npm and their community channels; they evaluate by running a command, not by reading claims. diff --git a/README.md b/README.md index f426ef8b..fa778991 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ That run exited 1 (1.6.0, 2026-10-07). The last line names who decided; your run | | Today | |---|---| -| npm `latest` | **1.8.0** (`npm view @hyperdag/trustshell version`). | +| npm `latest` | **1.9.0** (`npm view @hyperdag/trustshell version`). | | HAL quorum | **3 answering / 5 configured** (MEASURED 2026-10-06, `GET /api/v1/hal/stats` → `quorum_health`, 24-hour window). Not a constant 6. | | Chain | **Base Sepolia**, not mainnet. | | Grounding | **shadow** — does not mutate live RepID. | @@ -127,7 +127,7 @@ The Chrome extension in `extension/` does not import this package. It asks the s Most "LLM trust" tools are *judges*: they score an output and leave the decision to you. TrustShell is built to **fail closed**. An unavailable check is never a pass. It hands you evidence you can check yourself, rather than our word. - **Today:** Inspect checks an agent's claims about a CI run against GitHub's own record. Its record is canonical JSON with a SHA-256 digest; it is not signed yet. -- **Direction:** a harness that is yours. Your rules, memory and evidence stay with you as you swap the model underneath. Carry, which takes your profile, rules and notes to another machine, is built and not yet released. Reputation that moves with an agent is the aim, and it is not a property of this release. +- **Direction:** a harness that is yours. Your rules, memory and evidence stay with you as you swap the model underneath. Carry, which takes your profile, rules and notes to another machine, is in this release, experimental. Reputation that moves with an agent is the aim, and it is not a property of this release. Why we build it, and the research for and against each part: [hyperdag-protocol/docs/WHY.md](https://github.com/DealAppSeo/hyperdag-protocol/blob/main/docs/WHY.md). @@ -148,7 +148,7 @@ TrustShell gives an AI agent (or the dev building one) three things against the 1. **Verify an output** — run any text through a real cross-provider HAL fact-check quorum and get a `PASS` / `FLAG` / `VETO` / `NOT_CHECKED` verdict with evidence. `NOT_CHECKED` means HAL did not decide, and it is never a pass. **No API key.** 2. **Look up reputation** — fetch any agent's current RepID score + tier. **No API key.** -3. **Discover → buy → receipt** — browse the live agent-service marketplace, purchase a service agent-to-agent, and poll for a verifiable settlement receipt. **Needs an API key + a funded Base Sepolia wallet** (it moves real testnet value). +3. **Discover → buy → receipt** — browse the live agent-service marketplace, purchase a service agent-to-agent, and poll the backend for the contract's settlement status (`pollUntilSettled`: the backend's record, which this package reads and does not verify). **Needs an API key + a funded Base Sepolia wallet** (it moves real testnet value). ### What runs keyless vs. what needs a key @@ -206,14 +206,14 @@ npm install @hyperdag/trustshell This is the one live, published install today. It delivers Inspect, the hosted **HAL** check, **ERC-8004** RepID reads and range proofs, and **x402** payments with a spend guard, against the live backend (anything on-chain is on the Base Sepolia test network). -The package does not carry the Next.js/React site. The 1.8.0 tarball is 123 files: `dist/`, the command shims in `bin/`, `scripts/init-pai.mjs`, `scripts/value-events.mjs`, `lib/interview.js`, and the README, changelog and license. Runtime dependencies are `@hyperdag/proof-verifier` (dynamically imported; degrades gracefully if the optional WASM build is absent), `@modelcontextprotocol/sdk` and `zod` (for the `trustshell-mcp` server). `ethers` is an **optional** peer dependency: install it (`npm i ethers@^6`) only if you sign x402 payments or call `verifySigner`. (`npm view @hyperdag/trustshell@1.8.0 dependencies peerDependencies dist.fileCount`) +The package does not carry the Next.js/React site. The 1.9.0 tarball is 165 files: `dist/`, the command shims in `bin/`, `scripts/init-pai.mjs`, `scripts/value-events.mjs`, `lib/interview.js`, and the README, changelog and license. Runtime dependencies are `@hyperdag/proof-verifier` (dynamically imported; degrades gracefully if the optional WASM build is absent), `@modelcontextprotocol/sdk` and `zod` (for the `trustshell-mcp` server), and `@noble/hashes` (the receipt hash). `ethers` is an **optional** peer dependency: install it (`npm i ethers@^6`) only if you sign x402 payments or call `verifySigner`. (`npm view @hyperdag/trustshell@1.9.0 dependencies peerDependencies dist.fileCount`) ### Which package do I install? | If you're… | Install | What you get | |---|---|---| | A developer building an agent/app **in code** | `npm install @hyperdag/trustshell` | The SDK — Inspect, HAL verification, ERC-8004 RepID reads and x402 payments, in your TypeScript/JS | -| Using an **AI tool** (Claude Desktop, Cursor, Claude Code), **no code** | `npm i -g @hyperdag/trustshell@1.8.0`, then point the tool at the `trustshell-mcp` bin (below) | The checks as AI-callable tools | +| Using an **AI tool** (Claude Desktop, Cursor, Claude Code), **no code** | `npm i -g @hyperdag/trustshell@1.9.0`, then point the tool at the `trustshell-mcp` bin (below) | The checks as AI-callable tools | | Only verifying **ZK proofs** client-side | `npm install @hyperdag/proof-verifier` | Standalone checking of [Plonky3](https://github.com/Plonky3/Plonky3) proofs (Plonky3 is Polygon Labs' proof system). It is a dependency of `@hyperdag/trustshell`, so installing that installs this too — rarely installed directly | **Most people want `@hyperdag/trustshell`. The SDK, the CLI and the MCP server are all in that one package. `proof-verifier` is a separate package it depends on: npm installs it alongside, and the published tarball contains none of its files.** @@ -223,7 +223,7 @@ The package does not carry the Next.js/React site. The 1.8.0 tarball is 123 file The MCP server is the `trustshell-mcp` bin inside `@hyperdag/trustshell`. A global install puts it on PATH: ```bash -npm i -g @hyperdag/trustshell@1.8.0 +npm i -g @hyperdag/trustshell@1.9.0 ``` Then add it to your Claude Desktop / Cursor / Claude Code config: @@ -232,13 +232,13 @@ Then add it to your Claude Desktop / Cursor / Claude Code config: { "mcpServers": { "trustshell": { "command": "trustshell-mcp" } } } ``` -In 1.8.0 its tools are `check_claim`, `verify_output`, `get_repid`, `getLeaderboard`, `present_proof`, `verify_proof`, `status`, `my_job` (the agent's role and allowed tools, read from its live grants), `kernel_receipt` (a policy-kernel receipt read back, hash checked locally, with its six claims; needs a REPID_API_KEY), `ground_quote` (`trustshell ground` for agents, with the source as text; local, no network), the quarantine tools `quarantine_list` and `quarantine_explain` (there is no release tool over MCP), the learning-loop tools `learn_lessons_for` and `learn_record` (local, no network; see "Learning loop v1" below), and the local `remember` / `recall` (plus deprecated aliases `verify`, `evaluate`, `repid` and `getRepID`). `learn_lessons_for` and `learn_record` are new in 1.8.0. `kernel_receipt`, `ground_quote`, `quarantine_list` and `quarantine_explain` came in 1.7.0; 1.6.1 had the rest, and 1.6.0 also lacked `my_job`. 1.6.0 and 1.6.1 also had a local redact tool; 1.7.0 removes it, because it let any connected agent delete the operator's keyed rows. Deleting stays at the CLI. Since 1.7.0, a note written through the MCP `remember` tool is untrusted and quarantined (see "Quarantine (immune system v0)" below). This tree also registers `inspect_run`, Inspect for agents: a run URL and the claims as text in, the same record, digest and card `trustshell check --claims ""` produces out, deterministic and from api.github.com only. It is a different check from `check_claim`, which labels one sentence with a hosted, model-based check. 1.8.0 does not include it. It has no purchase tool; buying is the SDK's `executeA2A`. Since 1.7.0, every tool that reads the network answers `{untrusted_data, screening}`: data from outside your machine, never instructions. A string in it that reads as instructions is withheld and its place listed in `screening.withheld`. +In 1.9.0 its tools are `inspect_run` (Inspect over MCP; new in 1.9.0), `check_claim`, `verify_output`, `get_repid`, `getLeaderboard`, `present_proof`, `verify_proof`, `status`, `my_job` (the agent's role and allowed tools, read from its live grants), `kernel_receipt` (a policy-kernel receipt read back, hash checked locally, with its six claims; needs a REPID_API_KEY), `ground_quote` (`trustshell ground` for agents, with the source as text; local, no network), the quarantine tools `quarantine_list` and `quarantine_explain` (there is no release tool over MCP), the learning-loop tools `learn_lessons_for` and `learn_record` (local, no network; see "Learning loop v1" below), and the local `remember` / `recall` (plus deprecated aliases `verify`, `evaluate`, `repid` and `getRepID`). `learn_lessons_for` and `learn_record` are new in 1.8.0. `kernel_receipt`, `ground_quote`, `quarantine_list` and `quarantine_explain` came in 1.7.0; 1.6.1 had the rest, and 1.6.0 also lacked `my_job`. 1.6.0 and 1.6.1 also had a local redact tool; 1.7.0 removes it, because it let any connected agent delete the operator's keyed rows. Deleting stays at the CLI. Since 1.7.0, a note written through the MCP `remember` tool is untrusted and quarantined (see "Quarantine (immune system v0)" below). This tree also registers `inspect_run`, Inspect for agents: a run URL and the claims as text in, the same record, digest and card `trustshell check --claims ""` produces out, deterministic and from api.github.com only. It is a different check from `check_claim`, which labels one sentence with a hosted, model-based check. 1.8.0 does not include it. It has no purchase tool; buying is the SDK's `executeA2A`. Since 1.7.0, every tool that reads the network answers `{untrusted_data, screening}`: data from outside your machine, never instructions. A string in it that reads as instructions is withheld and its place listed in `screening.withheld`. The separate npm package `@hyperdag/trustshell-mcp` is older (1.0.0, published 2026-07-08). It has no `check_claim`. Use the bin above. ### Install straight from GitHub (no npm registry) — LIVE -The SDK also installs directly from the repo. That gives you `main`, which can run ahead of the published 1.8.0 — useful for pinning a commit or as a registry-independent fallback: +The SDK also installs directly from the repo. That gives you `main`, which can run ahead of the published 1.9.0 — useful for pinning a commit or as a registry-independent fallback: ```bash npm install github:DealAppSeo/trustshell @@ -246,7 +246,7 @@ npm install github:DealAppSeo/trustshell npm install github:DealAppSeo/trustshell# ``` -The package ships a committed `dist/`, so there is no build step on your side, and the lean-package guarantee holds (no Next.js/React tree is pulled). That `dist/` is built from `main`, which can run ahead of the published release. For exactly what npm serves, install `@hyperdag/trustshell@1.8.0`. +The package ships a committed `dist/`, so there is no build step on your side, and the lean-package guarantee holds (no Next.js/React tree is pulled). That `dist/` is built from `main`, which can run ahead of the published release. For exactly what npm serves, install `@hyperdag/trustshell@1.9.0`. --- @@ -308,7 +308,7 @@ The private key signs locally and never leaves the process. ## Discover → buy → receipt (agent-to-agent) -The full A2A loop: find a listed service, buy it, get a verifiable receipt. Discovery is keyless; the **purchase** half **moves real Base Sepolia testnet value**, so that half needs an API key and a funded wallet. +The full A2A loop: find a listed service, buy it, and read back the backend's contract record (status and settlement id; this package does not verify them). Discovery is keyless; the **purchase** half **moves real Base Sepolia testnet value**, so that half needs an API key and a funded wallet. ```ts import { TrustShell, guardedX402Payment } from '@hyperdag/trustshell'; @@ -677,9 +677,9 @@ to the HyperDAG backend's classify endpoint and nothing else): | `status` | HyperDAG backend (`TRUSTSHELL_API_URL`): `GET /api/v1/after-create`, `/api/v1/hal/honesty-a` and `/readiness`. It sends no input of yours | keyless | | `bind-status` | HyperDAG backend (`TRUSTSHELL_API_URL`): `GET /api/v1/after-create` only. It sends no input of yours | keyless | | `traps` | **none** — reads the fixture bundled in the package and `.trustshell/traps.json` | none | -| `bundle` | **none** — reads `.trustshell/profile.md`, `~/.trustshell/policy.json` and the local memory file; writes one bundle file (export), or the profile, the policy and quarantined notes (import). In this tree, in no npm release yet (not in 1.8.0) | none | -| `guard` | **none** — reads and writes `~/.trustshell/policy.json` and appends to `guard-receipts.jsonl` beside it. `guard level` (autonomy levels, SHADOW, off until turned on: [docs/autonomy-levels.md](docs/autonomy-levels.md)) also reads the record file you name and appends to `autonomy.jsonl`. In this tree, in no npm release yet (not in 1.8.0) | none | -| `run` | **none** itself — it starts the command you give it only if the policy allows it, and that command's own network is neither seen nor limited. In this tree, in no npm release yet (not in 1.8.0) | none | +| `bundle` | **none** — reads `.trustshell/profile.md`, `~/.trustshell/policy.json` and the local memory file; writes one bundle file (export), or the profile, the policy and quarantined notes (import). Since 1.9.0 | none | +| `guard` | **none** — reads and writes `~/.trustshell/policy.json` and appends to `guard-receipts.jsonl` beside it. `guard level` (autonomy levels, SHADOW, off until turned on: [docs/autonomy-levels.md](docs/autonomy-levels.md)) also reads the record file you name and appends to `autonomy.jsonl`. Since 1.9.0 | none | +| `run` | **none** itself — it starts the command you give it only if the policy allows it, and that command's own network is neither seen nor limited. Since 1.9.0 | none | No command uploads your input anywhere other than the host named above. @@ -732,10 +732,10 @@ Run `trustshell --help` for the full reference. ## Agent skill -OpenClaw, Claude, and Grok load [`skills/trustshell/SKILL.md`](skills/trustshell/SKILL.md). A global install of `@hyperdag/trustshell@1.8.0` puts `trustshell` and `trustshell-mcp` on PATH. Agents shell out to those bins. They do not call a new API. +OpenClaw, Claude, and Grok load [`skills/trustshell/SKILL.md`](skills/trustshell/SKILL.md). A global install of `@hyperdag/trustshell@1.9.0` puts `trustshell` and `trustshell-mcp` on PATH. Agents shell out to those bins. They do not call a new API. ```bash -npm i -g @hyperdag/trustshell@1.8.0 +npm i -g @hyperdag/trustshell@1.9.0 trustshell verify "" trustshell repid @@ -757,7 +757,7 @@ ERC-8004 Identity Registry ← who is the agent? RepID Score ← has it earned trust? (this package) │ ▼ - x402 Payments ← autonomous action + verifiable receipt + x402 Payments ← autonomous action + the backend's settlement record ``` RepID is the middle layer — the behavioral credential that makes the agent economy accountable. diff --git a/components/test-agent-flow.tsx b/components/test-agent-flow.tsx index 57198a9e..0017f638 100644 --- a/components/test-agent-flow.tsx +++ b/components/test-agent-flow.tsx @@ -222,13 +222,14 @@ function PathOne() { function PathTwo() { return (
-

- trust-report is not in a published release yet. Until it is, follow the steps in{' '} +

+ Install it. The full steps are in{' '} examples/own-agent - , which run it from a clone. + .

+

Use a fresh TRUSTSHELL_HOME for each test, then, in your project:

    {PATH_TWO_COMMANDS.map((c, i) => ( diff --git a/docs/HUMAN_TESTNET.md b/docs/HUMAN_TESTNET.md index 0c2e3d9c..3af19916 100644 --- a/docs/HUMAN_TESTNET.md +++ b/docs/HUMAN_TESTNET.md @@ -2,7 +2,7 @@ Chain is Base Sepolia, chain id 84532. This is not mainnet. -1. Install: `npm i -g @hyperdag/trustshell@1.8.0` +1. Install: `npm i -g @hyperdag/trustshell@1.9.0` 2. Read `GET /api/v1/faucet/info` on the engine. `chain_id` is 84532. `dispenses` is false. 3. The faucet is external. The engine does not send ETH. 4. Fund a wallet from a faucet that response names. TrustShell does not send the ETH. diff --git a/docs/JOIN_KIT.md b/docs/JOIN_KIT.md index 93b167a9..2dbf1337 100644 --- a/docs/JOIN_KIT.md +++ b/docs/JOIN_KIT.md @@ -5,7 +5,7 @@ A portable trust harness. Autonomy is earned. One screen for an ERC-8004 agent. Verify a claim. Read the receipt line. ```bash -npm i -g @hyperdag/trustshell@1.8.0 +npm i -g @hyperdag/trustshell@1.9.0 trustshell verify "The capital of France is Paris." ``` diff --git a/docs/STATUS.md b/docs/STATUS.md index d989ae63..c1434188 100644 --- a/docs/STATUS.md +++ b/docs/STATUS.md @@ -4,7 +4,7 @@ Updated 2026-10-06. Not a launch announcement. | Fact | Today | |---|---| -| npm `latest` | **1.8.0** (`npm view @hyperdag/trustshell version`). | +| npm `latest` | **1.9.0** (`npm view @hyperdag/trustshell version`). | | HAL quorum | **3 answering / 5 configured** (MEASURED 2026-10-06, `GET /api/v1/hal/stats` → `quorum_health.answering_providers` / `configured_providers`, 24-hour window). Not a constant 6. | | Chain | **Base Sepolia** (84532), not mainnet. | | Grounding | **shadow**. Does not mutate live RepID. | diff --git a/docs/WALKTHROUGH.md b/docs/WALKTHROUGH.md index 306fee10..68d3c271 100644 --- a/docs/WALKTHROUGH.md +++ b/docs/WALKTHROUGH.md @@ -9,7 +9,7 @@ Screenshot placeholders below are names only. The pictures are not in this repo. ## 1. Install ```bash -npm i -g @hyperdag/trustshell@1.8.0 +npm i -g @hyperdag/trustshell@1.9.0 ``` Then: @@ -18,7 +18,7 @@ Then: trustshell --version ``` -You should see `1.8.0`. +You should see `1.9.0`. diff --git a/docs/api-reference.md b/docs/api-reference.md index 374fd548..de783042 100644 --- a/docs/api-reference.md +++ b/docs/api-reference.md @@ -722,7 +722,7 @@ date must read only one way (`03/04/2026` is `ambiguous_value`). A quote that on ### `trustshell erc8004 [--network base|base-sepolia] [--payment ]` -> **Unreleased (on main, in no npm release).** Needs the optional `ethers` peer (`npm i ethers@^6`). +> **Since 1.9.0.** Needs the optional `ethers` peer (`npm i ethers@^6`). Is one ERC-8004 feedback entry grounded in a payment from the rater? The command reads the public chain only, through `https://mainnet.base.org` (default) or `https://sepolia.base.org`. It never fetches the feedback file. `OFFLINE=1` sends nothing. @@ -816,9 +816,9 @@ CHECKED; `check `, `inspect` and `report` exit `3`. **Not every command | `status` | HyperDAG backend (`TRUSTSHELL_API_URL`): `GET /api/v1/after-create`, `/api/v1/hal/honesty-a` and `/readiness`. It sends no input of yours | keyless | | `bind-status` | HyperDAG backend (`TRUSTSHELL_API_URL`): `GET /api/v1/after-create` only. It sends no input of yours | keyless | | `traps` | **none** — reads the fixture bundled in the package and `.trustshell/traps.json` | none | -| `bundle` | **none** — reads `.trustshell/profile.md`, `~/.trustshell/policy.json` and the local memory file; writes one bundle file (export), or the profile, the policy and quarantined notes (import). In this tree, in no npm release yet (not in 1.8.0) | none | -| `guard` | **none** — reads and writes `~/.trustshell/policy.json` and appends to `guard-receipts.jsonl` beside it. In this tree, in no npm release yet (not in 1.8.0) | none | -| `run` | **none** itself — it starts the command you give it only if the policy allows it, and that command's own network is neither seen nor limited. With `--sandbox` it drives the local Docker CLI instead, whose daemon pulls the pinned `node:22-alpine` digest from Docker Hub if it is not present; the command gets no network, and `sandbox promote` reads only local files. In this tree, in no npm release yet (not in 1.8.0) | none | +| `bundle` | **none** — reads `.trustshell/profile.md`, `~/.trustshell/policy.json` and the local memory file; writes one bundle file (export), or the profile, the policy and quarantined notes (import). Since 1.9.0 | none | +| `guard` | **none** — reads and writes `~/.trustshell/policy.json` and appends to `guard-receipts.jsonl` beside it. Since 1.9.0 | none | +| `run` | **none** itself — it starts the command you give it only if the policy allows it, and that command's own network is neither seen nor limited. With `--sandbox` it drives the local Docker CLI instead, whose daemon pulls the pinned `node:22-alpine` digest from Docker Hub if it is not present; the command gets no network, and `sandbox promote` reads only local files. Since 1.9.0 | none | `init` and `profile` write one file to your working directory, `.trustshell/profile.md`. Other commands write there too: `check --out ` writes `record.json`, `card.md` and `card.html` into ``, @@ -1194,4 +1194,4 @@ The SDK **throws** on every non-2xx; the public REST endpoints return JSON error --- -> Reflects the main branch, not one release. Sections marked "Since 1.7.0" are in every npm release from 1.7.0 on. `profile`, `learn` and `check --claims-file` are in npm `latest` 1.8.0. `bundle`, `guard` and `run` are on main and in no npm release yet. REST examples are from the production `repid-engine` deployment. Click-by-click CLI walkthrough: [`WALKTHROUGH.md`](./WALKTHROUGH.md). +> Reflects the published `@hyperdag/trustshell` v1.9.0 surface and the production `repid-engine` deployment. Click-by-click CLI walkthrough: [`WALKTHROUGH.md`](./WALKTHROUGH.md). diff --git a/docs/autonomy-levels.md b/docs/autonomy-levels.md index d96c76c6..c13684e7 100644 --- a/docs/autonomy-levels.md +++ b/docs/autonomy-levels.md @@ -1,6 +1,6 @@ # Autonomy levels for Guard (SHADOW) -Status: **shadow by default, off until turned on.** On `main`, in no npm release. Source: +Status: **shadow by default, off until turned on.** In npm since 1.9.0. Source: `src/lib/autonomy.ts`, wired into `guardDecide` (`src/lib/guardrails.ts`) and `trustshell guard level` (`src/cli/guard.ts`). Tests: `tests/autonomy.test.ts`. diff --git a/docs/getting-started.md b/docs/getting-started.md index 115260f4..d8371691 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -34,7 +34,7 @@ Verify the install: ```bash trustshell --version -# → 1.8.0 (the installed package version) +# → 1.9.0 (the installed package version) ``` ## 4. 60-second quickstart diff --git a/docs/guard-carry-demo.md b/docs/guard-carry-demo.md index f51bef65..c9f46cc5 100644 --- a/docs/guard-carry-demo.md +++ b/docs/guard-carry-demo.md @@ -5,7 +5,7 @@ arrive, and each host should keep its own record of what it allowed and refused. on your machine, and then shows you each place where that promise stops. It takes under a minute on our Windows machine (24 to 65 s, measured); the first start of the copied node binary waits for the virus scanner. -Guard + Carry is on `main` and not yet in a published release, so run it from a clone. +Guard + Carry is in 1.9.0. This demonstration script is in the repository and not in the package, so run it from a clone. ## Run it diff --git a/docs/install/claude-code.md b/docs/install/claude-code.md index 8587e44a..2e444f07 100644 --- a/docs/install/claude-code.md +++ b/docs/install/claude-code.md @@ -6,7 +6,7 @@ The package was `@hyperdag/trustshell@1.5.0`. `trustshell --version` printed 1.5 ## Install ``` -npm i -g @hyperdag/trustshell@1.8.0 +npm i -g @hyperdag/trustshell@1.9.0 ``` That provides `trustshell` and `trustshell-mcp`. diff --git a/docs/install/claude-desktop.md b/docs/install/claude-desktop.md index 10c673bf..cc74c1bf 100644 --- a/docs/install/claude-desktop.md +++ b/docs/install/claude-desktop.md @@ -5,7 +5,7 @@ Claude Desktop 2.19675.0.0 is installed. Its config already had railway and gith ## Install ``` -npm i -g @hyperdag/trustshell@1.8.0 +npm i -g @hyperdag/trustshell@1.9.0 ``` ## Config diff --git a/docs/install/cursor.md b/docs/install/cursor.md index 60b202cd..b2c99e9f 100644 --- a/docs/install/cursor.md +++ b/docs/install/cursor.md @@ -5,7 +5,7 @@ Cursor 3.23.12 is installed. The user `mcp.json` under `.cursor` was absent. The ## Install ``` -npm i -g @hyperdag/trustshell@1.8.0 +npm i -g @hyperdag/trustshell@1.9.0 ``` ## Config diff --git a/docs/integrations/erc-8004-x402-openclaw.md b/docs/integrations/erc-8004-x402-openclaw.md index 601b2767..395c4258 100644 --- a/docs/integrations/erc-8004-x402-openclaw.md +++ b/docs/integrations/erc-8004-x402-openclaw.md @@ -178,7 +178,7 @@ Covers GitHub Actions runs only. MEASURED; the published 1.8.0 was not re-run. ### What an OpenClaw operator can attach TrustShell to **17. Is there an OpenClaw integration?** A **skill**: yes. [`skills/trustshell`](../../skills/trustshell/SKILL.md) carries OpenClaw -metadata, requires the `trustshell` and `trustshell-mcp` bins, pins `@hyperdag/trustshell@1.8.0`, and shells out to +metadata, requires the `trustshell` and `trustshell-mcp` bins, pins `@hyperdag/trustshell@1.9.0`, and shells out to `verify`, `repid`, `proof --verify` and `status`; it also shows the one-line MCP definition. Whether it was run inside OpenClaw, and whether it is published on ClawHub, I did not check. A **plugin that uses OpenClaw's tool hooks**: no. The README and [`PRODUCT.md`](../../PRODUCT.md) say so. NOT BUILT. diff --git a/docs/recipes/README.md b/docs/recipes/README.md index 599074e7..87edd42f 100644 --- a/docs/recipes/README.md +++ b/docs/recipes/README.md @@ -1,6 +1,6 @@ # TrustShell recipes: use it from the tools you already have -Each recipe uses only what ships today in `@hyperdag/trustshell` (1.8.0, npm `latest`). None needs an account, an API key or a model. Each says exactly what was run and what was not. +Each recipe uses only what ships today in `@hyperdag/trustshell` (1.9.0, npm `latest`). None needs an account, an API key or a model. Each says exactly what was run and what was not. | Recipe | You use | Status (2026-10-22, Windows 11) | Run it | |---|---|---|---| @@ -13,7 +13,7 @@ Each recipe uses only what ships today in `@hyperdag/trustshell` (1.8.0, npm `la ## What these prove, and what they do not - `ground_quote` is a **local, deterministic text check**: the quote is, or is not, in the source you gave it. It does not say the quote is true, or that the source is trustworthy. - The Inspect step (GitHub Actions) reads a **finished** run from api.github.com. SUPPORTED is scoped to the platform record, and a claim with a wrong workflow name is NOT_CHECKED, never SUPPORTED. It is not a code review. -- The published MCP server (1.8.0) does **not** expose Inspect (the CI-run check). This tree adds the `inspect_run` tool: a run URL and the claims as text in, the same record, digest and card as `check --claims` out, from api.github.com only. It differs from `check_claim`, which is a hosted, model-based check of one sentence. `ground_quote` and the note tools are local and deterministic; `inspect_run` is deterministic and reads api.github.com. +- The MCP server exposes Inspect (the CI-run check) since 1.9.0, through the `inspect_run` tool: a run URL and the claims as text in, the same record, digest and card as `check --claims` out, from api.github.com only. It differs from `check_claim`, which is a hosted, model-based check of one sentence. `ground_quote` and the note tools are local and deterministic; `inspect_run` is deterministic and reads api.github.com. - Nothing here is sandboxed: MCP servers run code on your machine. Read before you enable. **MCP does not grant authority.** `inspect_run` reads evidence and authorizes nothing: a SUPPORTED claim is not permission to merge, deploy or pay. It is not the hosted `check_claim`. And a tool that an agent can discover and call over MCP is not, for that reason, a tool the agent is permitted to act on. What an agent may do is your decision, written in your own policy, never inferred from a tool list. diff --git a/docs/recipes/mcp-clients/README.md b/docs/recipes/mcp-clients/README.md index 02434af9..d7222af2 100644 --- a/docs/recipes/mcp-clients/README.md +++ b/docs/recipes/mcp-clients/README.md @@ -2,7 +2,7 @@ The server is the `trustshell-mcp` command inside `@hyperdag/trustshell`. The older standalone `@hyperdag/trustshell-mcp` package is superseded (it predates `check_claim`); do not use it. -**Verified:** this exact launch, `npx -y -p @hyperdag/trustshell@latest trustshell-mcp`, starts server 1.8.0 and lists 20 tools (2026-10-23, Windows, `npx.cmd`). The same launch on 1.8.0-rc.0 listed 20 tools from two different MCP clients (LangChain adapters and smolagents) on Windows, through both `npx` and `npx.cmd`. +**Verified on 1.8.0, 2026-10-23, Windows, `npx.cmd`:** this exact launch, `npx -y -p @hyperdag/trustshell@latest trustshell-mcp`, started the server and listed 20 tools; 1.9.0 lists 21. The same launch on 1.8.0-rc.0 listed 20 tools from two different MCP clients (LangChain adapters and smolagents) on Windows, through both `npx` and `npx.cmd`. **Not verified:** the three apps below were not opened for this note. If one does not start the server, send us its log. ## Claude Code diff --git a/docs/red-team.md b/docs/red-team.md index ef5185b7..e8bbff35 100644 --- a/docs/red-team.md +++ b/docs/red-team.md @@ -1,5 +1,6 @@ # Red-team results + Records through **2026-10-23T19:15:13Z**. Everything on this page is derived from the files in [docs/red-team/records/](red-team/records) by [scripts/redteam-report.mjs](../scripts/redteam-report.mjs); `node scripts/redteam-report.mjs --check` re-derives it and fails if this page differs. No network, no key. The only statements not derived from those files are about other repositories and npm, and each carries the date it was checked. @@ -316,7 +317,7 @@ Why this page lists what it cannot show as carefully as what it can: [hyperdag-p | file | bytes | sha256 (first 16 hex, line endings normalised to LF) | |---|---|---| | DEGRADED_BATCHES.md | 1302 | 7c487eddfcf2337b | -| RC_ATTACK_1.8.0-dry.md | 8706 | 807ed944a69da8c5 | +| RC_ATTACK_1.8.0-dry.md | 8739 | ff517348d17a19d2 | | REDTEAM_LOOP_2026-10-21.md | 21049 | 473f87b90670d858 | | REDTEAM_LOOP_2026-10-23.md | 9267 | 8738c6ebba89dc1e | | arena-batches.jsonl | 12085 | b3c838523778c09a | diff --git a/docs/red-team/records/RC_ATTACK_1.8.0-dry.md b/docs/red-team/records/RC_ATTACK_1.8.0-dry.md index c8f49b05..e3c4c176 100644 --- a/docs/red-team/records/RC_ATTACK_1.8.0-dry.md +++ b/docs/red-team/records/RC_ATTACK_1.8.0-dry.md @@ -1,4 +1,4 @@ -# RC attack — 1.8.0-dry — 2026-10-23T00-10-12-628Z +# RC attack — 1.8.0-dry — 2026-10-23T00-10-12-628Z Candidate: `@hyperdag/trustshell@1.8.0` · tarball sha256 `52669e3c31cc0c27855a03ffa63ea0ac0b12ca72ed63831a7e21160714a527bf` · integrity `sha512-tkaDaVUYgOe7YVDe2YPBrmn8BsS9pIZAdGlcf+VTLRt7q8KbJ47HViiHGPiGcaCUw68K40xzWx2M2o8GMxsdsw==` diff --git a/examples/own-agent/README.md b/examples/own-agent/README.md index 819dcf4b..e0d36a7d 100644 --- a/examples/own-agent/README.md +++ b/examples/own-agent/README.md @@ -11,22 +11,12 @@ Two ways to check an agent. They are different things and prove different things Every command below is the same in bash, zsh and Windows PowerShell. The quotes around `'--'` matter: PowerShell drops a bare `--`. -`trust-report` is not in a published release yet, so install from a clone: +Install the release (Node 22.13 or later): ```bash -git clone https://github.com/DealAppSeo/trustshell +npm i -g @hyperdag/trustshell@1.9.0 ``` -```bash -cd trustshell -``` - -```bash -npm ci --ignore-scripts -``` - -Then use `node dist/cli/index.js` wherever `trustshell` appears below. - ## Path 1: check what it said Put your agent's words in a file, one claim per paragraph, each citing the run: diff --git a/examples/quickstart/QUICKSTART.md b/examples/quickstart/QUICKSTART.md index 81e78f79..fbd97c3a 100644 --- a/examples/quickstart/QUICKSTART.md +++ b/examples/quickstart/QUICKSTART.md @@ -15,11 +15,11 @@ in three lines, against the **live** repid-engine. The read paths below need **n npm install @hyperdag/trustshell ``` -The package leaves the site out: the 1.8.0 tarball is 123 files (`dist/`, the command shims in +The package leaves the site out: the 1.9.0 tarball is 165 files (`dist/`, the command shims in `bin/`, two scripts, `lib/interview.js`, and the README, changelog and license). `npm install` -pulls `@hyperdag/proof-verifier`, `@modelcontextprotocol/sdk` and `zod` — no Next.js, React, or +pulls `@hyperdag/proof-verifier`, `@modelcontextprotocol/sdk`, `@noble/hashes` and `zod` — no Next.js, React, or Supabase tree. `ethers` is an **optional** peer dependency: install it (`npm i ethers@^6`) only to -sign x402 payments or call `verifySigner`. (`npm view @hyperdag/trustshell@1.8.0 dependencies +sign x402 payments or call `verifySigner`. (`npm view @hyperdag/trustshell@1.9.0 dependencies peerDependencies dist.fileCount`; on 2026-10-06 a clean install added 96 packages in 5 s.) ## 2. Verify an agent output (no key required) @@ -48,7 +48,7 @@ A runnable copy is in this folder: **[`quickstart.mjs`](./quickstart.mjs)** — truthful and a false claim, looks up `trinity-shofet`, and prints the wall-clock time to the first verified call. From this repository the file imports `../../dist/lib/index.js` so `node examples/quickstart/quickstart.mjs` exercises the build committed in this checkout -(`package.json` 1.8.0) without installing from npm. After +(`package.json` 1.9.0) without installing from npm. After `npm install @hyperdag/trustshell` in *your* project, use the named import in the README. **Import note:** use the **named** import `import { TrustShell }`. It resolves cleanly from both diff --git a/package-lock.json b/package-lock.json index d48c686f..e5bf011c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@hyperdag/trustshell", - "version": "1.9.0-dev.0", + "version": "1.9.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@hyperdag/trustshell", - "version": "1.9.0-dev.0", + "version": "1.9.0", "license": "Apache-2.0", "dependencies": { "@hyperdag/proof-verifier": "^0.2.0", diff --git a/package.json b/package.json index dd5d3cbc..b121ccf6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@hyperdag/trustshell", - "version": "1.9.0-dev.0", + "version": "1.9.0", "description": "Check what your AI agent says it did against the evidence. Inspect checks an agent's claims about a GitHub Actions run against GitHub's own record, with no account; also a hosted second-opinion check, local memory, an MCP server and an SDK.", "license": "Apache-2.0", "publishConfig": { diff --git a/scripts/redteam-report.mjs b/scripts/redteam-report.mjs index 654a87fa..883f40fd 100644 --- a/scripts/redteam-report.mjs +++ b/scripts/redteam-report.mjs @@ -251,6 +251,7 @@ function render() { p('# Red-team results', '', + '', '', '', `Records through **${z(lastTime)}**. Everything on this page is derived from the files in [docs/red-team/records/](red-team/records) by [scripts/redteam-report.mjs](../scripts/redteam-report.mjs); \`node scripts/redteam-report.mjs --check\` re-derives it and fails if this page differs. No network, no key. The only statements not derived from those files are about other repositories and npm, and each carries the date it was checked.`, diff --git a/skills/trustshell/SKILL.md b/skills/trustshell/SKILL.md index 3d37debb..d673f0ad 100644 --- a/skills/trustshell/SKILL.md +++ b/skills/trustshell/SKILL.md @@ -1,7 +1,7 @@ --- name: trustshell description: Fact-check a claim, read an agent's live RepID, verify its ZK proof, or print after-create and Honesty A by shelling out to the published bins. Use when the user asks to verify a claim, look up a RepID, check a proof, see can_verify, or attach the local trustshell MCP server. -metadata: {"openclaw":{"emoji":"🛡️","requires":{"bins":["trustshell","trustshell-mcp"]},"install":[{"id":"npm","kind":"node","package":"@hyperdag/trustshell@1.8.0","bins":["trustshell","trustshell-mcp","hal"],"label":"Install @hyperdag/trustshell@1.8.0"}]}} +metadata: {"openclaw":{"emoji":"🛡️","requires":{"bins":["trustshell","trustshell-mcp"]},"install":[{"id":"npm","kind":"node","package":"@hyperdag/trustshell@1.9.0","bins":["trustshell","trustshell-mcp","hal"],"label":"Install @hyperdag/trustshell@1.9.0"}]}} --- # Trustshell @@ -11,7 +11,7 @@ metadata: {"openclaw":{"emoji":"🛡️","requires":{"bins":["trustshell","trust The bins must already be on PATH: ```bash -npm i -g @hyperdag/trustshell@1.8.0 +npm i -g @hyperdag/trustshell@1.9.0 ``` That install provides `trustshell`, `hal`, and `trustshell-mcp`. If `trustshell` is not on PATH, stop and say so. Do not install another package and do not start a server. @@ -64,11 +64,11 @@ The homepage is install-first (2026-10-24): `Check what your AI agent did, not w Other ways in: - In Chrome: the extension stamps replies on ChatGPT, Claude, Gemini, Grok and DeepSeek. -- In Claude Desktop, Cursor or Claude Code: an MCP paste. It runs `trustshell-mcp` from `@hyperdag/trustshell@1.8.0` through `npx -y -p`, for someone without the global install. With the prerequisite above, use the block under MCP instead. The ChatGPT and Grok apps do not load MCP servers yet; on their websites the Chrome extension stamps replies. +- In Claude Desktop, Cursor or Claude Code: an MCP paste. It runs `trustshell-mcp` from `@hyperdag/trustshell@1.9.0` through `npx -y -p`, for someone without the global install. With the prerequisite above, use the block under MCP instead. The ChatGPT and Grok apps do not load MCP servers yet; on their websites the Chrome extension stamps replies. - In your terminal: one `check` of a sample sentence through `npx`. It exits 0 when it checks out, 1 when caught, 2 when not checked. To keep it installed: ```bash -npm i -g @hyperdag/trustshell@1.8.0 +npm i -g @hyperdag/trustshell@1.9.0 ``` After that, `Want an agent you can trust?` leads to /pai: three questions make an agent, and the same six-step bar as /bind shows the rest of the path (claim, fund, stake, trade, earn). diff --git a/skills/trustshell/skill.json b/skills/trustshell/skill.json index e5bb087c..a0f66e6d 100644 --- a/skills/trustshell/skill.json +++ b/skills/trustshell/skill.json @@ -18,9 +18,9 @@ { "id": "npm", "kind": "node", - "package": "@hyperdag/trustshell@1.8.0", + "package": "@hyperdag/trustshell@1.9.0", "bins": ["trustshell", "trustshell-mcp", "hal"], - "label": "Install @hyperdag/trustshell@1.8.0" + "label": "Install @hyperdag/trustshell@1.9.0" } ] } diff --git a/tests/e2e/test-agent-walk.mjs b/tests/e2e/test-agent-walk.mjs index 660598ae..a00736a4 100644 --- a/tests/e2e/test-agent-walk.mjs +++ b/tests/e2e/test-agent-walk.mjs @@ -192,7 +192,7 @@ async function walk(label, viewport) { await page.getByRole('radio', { name: /Run a task through TrustShell/ }).check(); check(`${label}: path 2 replaces path 1`, (await page.getByTestId('path-two').isVisible()) && !(await page.getByTestId('path-one').isVisible())); - check(`${label}: path 2 says it is not released`, await page.getByText('not in a published release yet').isVisible()); + check(`${label}: path 2 gives the install command`, await page.getByText('npm i -g @hyperdag/trustshell@1.9.0').isVisible()); check(`${label}: path 2 says what it does not see`, await page.getByText('without trustshell run is not seen').isVisible()); await axe(page, `${label} path2`); await shot('2-path2'); diff --git a/tests/install-docs.test.ts b/tests/install-docs.test.ts index 3d7edd5e..0b04e0c4 100644 --- a/tests/install-docs.test.ts +++ b/tests/install-docs.test.ts @@ -20,7 +20,7 @@ describe('install docs', () => { it('Claude Code records the version, the package, and the config it wrote', () => { expect(claude).toContain('2.1.157'); - expect(claude).toContain('npm i -g @hyperdag/trustshell@1.8.0'); + expect(claude).toContain('npm i -g @hyperdag/trustshell@1.9.0'); expect(claude).toContain('"command": "trustshell-mcp"'); expect(claude).toContain('Pending approval'); expect(claude).toContain('trustshell 1.5.0'); @@ -28,14 +28,14 @@ describe('install docs', () => { it('Cursor records the installed version and that the server was not loaded', () => { expect(cursor).toContain('3.23.12'); - expect(cursor).toContain('npm i -g @hyperdag/trustshell@1.8.0'); + expect(cursor).toContain('npm i -g @hyperdag/trustshell@1.9.0'); expect(cursor).toContain('"command": "trustshell-mcp"'); expect(cursor).toMatch(/not loaded/i); }); it('Claude Desktop records the installed version and that the live file was not changed', () => { expect(desktop).toContain('2.19675.0.0'); - expect(desktop).toContain('npm i -g @hyperdag/trustshell@1.8.0'); + expect(desktop).toContain('npm i -g @hyperdag/trustshell@1.9.0'); expect(desktop).toContain('"command": "trustshell-mcp"'); expect(desktop).toMatch(/not changed/i); expect(desktop).toMatch(/not loaded/i); diff --git a/tests/join-kit.test.ts b/tests/join-kit.test.ts index 6cd61c79..ba69ae50 100644 --- a/tests/join-kit.test.ts +++ b/tests/join-kit.test.ts @@ -9,7 +9,7 @@ describe('join kit', () => { it('is one screen: verify, a receipt line, and no stake now', () => { expect(doc).toContain('A portable trust harness. Autonomy is earned.'); expect(doc).toContain('ERC-8004'); - expect(doc).toContain('npm i -g @hyperdag/trustshell@1.8.0'); + expect(doc).toContain('npm i -g @hyperdag/trustshell@1.9.0'); expect(doc).toContain('trustshell verify "The capital of France is Paris."'); expect(doc).toContain('glm cerebras FALSE'); expect(doc).toContain('openai openai NOT_CHECKED'); diff --git a/tests/register-not-minted.test.ts b/tests/register-not-minted.test.ts index d5002b2c..3d1b5409 100644 --- a/tests/register-not-minted.test.ts +++ b/tests/register-not-minted.test.ts @@ -54,7 +54,7 @@ describe('skill shells out to trustshell', () => { for (const command of manifest.commands) { expect(skill).toContain(command); } - expect(skill).toContain('npm i -g @hyperdag/trustshell@1.8.0'); + expect(skill).toContain('npm i -g @hyperdag/trustshell@1.9.0'); expect(skill).not.toMatch(/npx @hyperdag\/trustshell@1\.6\.2/); expect(skill).not.toMatch(/staking is live/i); }); diff --git a/tests/release-1.8.1-first-run.test.ts b/tests/release-1.8.1-first-run.test.ts new file mode 100644 index 00000000..ce86ee40 --- /dev/null +++ b/tests/release-1.8.1-first-run.test.ts @@ -0,0 +1,153 @@ +/** + * 1.8.1: the parts of #647's first-run polish that touch code already in 1.8.0 (F3 learn inject, F4 the SQLite + * warning, F9 a refused TRUSTSHELL_API_URL). Ported from tests/harness-first-run.test.ts on main, minus every case + * that needs guard, run or bundle, which 1.8.0 does not ship. Each fails on 4b01ec34 (the 1.8.0 source). + * Every test uses a temp TRUSTSHELL_HOME and memory file; the real home is never read or written. + */ +import { spawnSync } from 'node:child_process'; +import { mkdtempSync, readFileSync, rmSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { fatalLine, quietSqliteWarning } from '../src/cli'; +import { ApiUrlError } from '../src/lib/api-url'; +import { runLearn } from '../src/learn/cli'; + +describe('F3: learn inject with nothing to inject says why, on stderr only', () => { + const prevEnv = { ...process.env }; + let home = ''; + let out: string[] = []; + let err: string[] = []; + const io = { out: (s: string) => out.push(s), err: (s: string) => err.push(s) }; + const env = () => ({ ...process.env, TRUSTSHELL_HOME: home, TRUSTSHELL_MEMORY: join(home, 'memory.sqlite') }); + + beforeEach(() => { + home = mkdtempSync(join(tmpdir(), 'ts-181-first-run-')); + process.env.TRUSTSHELL_HOME = home; + out = []; + err = []; + }); + afterEach(() => { + process.env = { ...prevEnv }; + rmSync(home, { recursive: true, force: true }); + }); + + it("the README's own steps: a lesson scoped to ship-tests prints with --check ship-tests; without it, stdout is empty and stderr says why", async () => { + const e = env(); + expect(await runLearn(['job', 'add', 'ship', '--mode', 'delegate', 'When I ship a change, I want the tests green, so I can merge.'], io, e)).toBe(0); + expect(await runLearn(['check', 'add', '--job', 'ship', '--id', 'ship-tests', '--cmd', 'npm test'], io, e)).toBe(0); + expect(await runLearn(['correct', '--job', 'ship', '--check', 'ship-tests', 'Run the linter before you say done.'], io, e)).toBe(0); + expect(await runLearn(['accept', '1'], io, e)).toBe(0); + out = []; + err = []; + expect(await runLearn(['inject', '--job', 'ship'], io, e)).toBe(0); + expect(out).toEqual([]); // what a hook injects: nothing + expect(err.join('\n')).toContain('no lesson applies to this turn of job ship'); + expect(err.join('\n')).toContain('--check '); + out = []; + err = []; + expect(await runLearn(['inject', '--job', 'ship', '--check', 'ship-tests'], io, e)).toBe(0); + expect(out.join('\n')).toContain('Run the linter before you say done.'); + expect(err).toEqual([]); + }); + + it('an unknown job still prints nothing at all (the documented no-op)', async () => { + const e = env(); + expect(await runLearn(['job', 'add', 'ship', '--mode', 'delegate', 'When I ship, I want green tests, so I can merge.'], io, e)).toBe(0); + out = []; + err = []; + expect(await runLearn(['inject', '--job', 'nope'], io, e)).toBe(0); + expect(out).toEqual([]); + expect(err).toEqual([]); + }); + + it('the README example injects with --check ship-tests', () => { + const readme = readFileSync(join(__dirname, '..', 'README.md'), 'utf8'); + expect(readme).toContain('trustshell learn inject --job ship --check ship-tests'); + }); +}); + +describe('F9: a refused TRUSTSHELL_API_URL is one line with the next step', () => { + it('a refused TRUSTSHELL_API_URL is one line with the next step, never a stack trace', () => { + const line = fatalLine(new ApiUrlError('TRUSTSHELL_API_URL must be https (plain http only for localhost), so nothing was sent to http://example.com')); + expect(line).toContain('Unset TRUSTSHELL_API_URL, or point it at an https URL'); + expect(line).not.toContain('fatal'); + expect(line).not.toMatch(/\n\s+at /); + }); + + it('any other crash still prints "fatal" and its stack (control)', () => { + expect(fatalLine(new Error('boom'))).toMatch(/^trustshell: fatal: Error: boom\n\s+at /); + }); + + it('the built CLI: `recall` with an http TRUSTSHELL_API_URL exits 3 with the one line, no stack', () => { + const dir = mkdtempSync(join(tmpdir(), 'ts-181-first-run-url-')); + try { + const r = spawnSync(process.execPath, [join(__dirname, '..', 'dist', 'cli', 'index.js'), 'recall'], { + cwd: dir, + encoding: 'utf8', + env: { ...process.env, TRUSTSHELL_HOME: dir, TRUSTSHELL_MEMORY: join(dir, 'memory.sqlite'), TRUSTSHELL_API_URL: 'http://example.com' }, + }); + expect(r.status).toBe(3); + expect(r.stderr).toContain('Unset TRUSTSHELL_API_URL'); + expect(r.stderr).not.toMatch(/\n\s+at /); + } finally { + rmSync(dir, { recursive: true, force: true }); + } + }); +}); + +describe("F4: the CLI drops Node's SQLite ExperimentalWarning, and only that warning", () => { + const fake = () => { + const seen: unknown[][] = []; + const proc = { emitWarning: ((...a: unknown[]) => void seen.push(a)) as unknown as NodeJS.Process['emitWarning'] }; + quietSqliteWarning(proc); + return { proc, seen }; + }; + + it('the SQLite experimental warning is dropped, as a string and as an Error', () => { + const { proc, seen } = fake(); + proc.emitWarning('SQLite is an experimental feature and might change at any time', 'ExperimentalWarning'); + const e = new Error('SQLite is an experimental feature and might change at any time'); + e.name = 'ExperimentalWarning'; + proc.emitWarning(e); + expect(seen).toEqual([]); + }); + + it.each([ + ['another experimental feature', ['WASI is an experimental feature and might change at any time', 'ExperimentalWarning']], + ['the same text as another type', ['SQLite is an experimental feature and might change at any time', 'DeprecationWarning']], + ['an options object of another type', ['SQLite is an experimental feature', { type: 'Warning' }]], + ['a plain warning', ['something else']], + ])('%s still prints', (_n, args) => { + const { proc, seen } = fake(); + (proc.emitWarning as unknown as (...a: unknown[]) => void)(...args); + expect(seen).toEqual([args]); + }); + + // The built CLI, spawned the way npm's bin runs it, with Node's warnings left ON. + const cli = join(__dirname, '..', 'dist', 'cli', 'index.js'); + const spawnEnv = (extra: Record) => { + const e: NodeJS.ProcessEnv = { ...process.env, ...extra }; + delete e.NODE_NO_WARNINGS; + delete e.NODE_OPTIONS; + return e; + }; + // Control: does this Node warn on node:sqlite at all? If not, the dist test below proves nothing, so it is SKIPPED. + const nodeWarns = /ExperimentalWarning: SQLite/.test( + spawnSync(process.execPath, ['-e', "require('node:sqlite')"], { encoding: 'utf8', env: spawnEnv({}) }).stderr ?? '', + ); + (nodeWarns ? it : it.skip)('`trustshell recall` from dist prints no SQLite warning (this Node warns on a bare require: control)', () => { + const dir = mkdtempSync(join(tmpdir(), 'ts-181-first-run-dist-')); + try { + const r = spawnSync(process.execPath, [cli, 'recall'], { + cwd: dir, + encoding: 'utf8', + env: spawnEnv({ TRUSTSHELL_HOME: dir, TRUSTSHELL_MEMORY: join(dir, 'memory.sqlite') }), + }); + expect(r.status).toBe(0); + expect(r.stderr).not.toContain('ExperimentalWarning'); + expect(r.stdout).toContain('do_not_send COUNT 0'); // it ran, and it opened the memory file + } finally { + rmSync(dir, { recursive: true, force: true }); + } + }); +});