From 079dcbba979872cdd980f5f186d7234862f8a725 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 29 Jul 2026 17:09:32 +0000 Subject: [PATCH 1/3] docs: add Cursor Cloud setup instructions in AGENTS.md Co-authored-by: CaNoe --- AGENTS.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..da4f881 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,34 @@ +# AGENTS.md + +## Cursor Cloud specific instructions + +Web3 Signature Decoder is a TypeScript **npm-workspaces monorepo** (Node `>=20.11`). The shared logic lives in `packages/@sd/core-*`; the runnable apps live in `apps/`. See `README.md` for the full architecture, API routes, and env var table. + +### Build is required before running apps or tests (non-obvious) +The apps and tests import the **compiled `dist/` output** of the `@sd/*` workspace packages (each package's `main` is `dist/index.js`), not their TypeScript source. So on a fresh checkout you MUST build the library packages before `dev`/`test` will work. The startup update script already runs the library builds (`@sd/core-schema`, `core-knowledge`, `core-llm`, `core-engine`, `core-renderers`, `test-fixtures`, `test-harness`); if you add/checkout a fresh tree yourself, rebuild them (dependency order: `core-schema` first). The dev servers themselves run via `tsx` on their own `src/`, so only the imported `@sd/*` libraries need building, not the apps. + +### Port mismatch gotcha (test-api vs test-web) +`apps/test-api` defaults to `TEST_API_PORT=4005` in code, but `apps/test-web` (and the README) default the browser API base to `http://localhost:4000`. To make the test-web UI work against the API out of the box, start the API on port 4000: `TEST_API_PORT=4000 npm run dev:test-api`. + +### Running the services (dev mode, from repo root) +- `TEST_API_PORT=4000 npm run dev:test-api` — Express REST API (`/v2/health`, `/v2/analyze`, `/v2/fixtures/validate`, `/v2/reason`). +- `npm run dev:test-web` — browser test shell on `http://localhost:4173` (select a fixture → `POST /v2/analyze`). +- `npm run dev:site` — landing / Snap-init page on `http://localhost:8000`. +- `npm run dev:snap` — MetaMask Snap watcher (`mm-snap watch`); needs MetaMask Flask in a real browser to fully exercise. +- `npm run dev` runs test-api + snap + site together (note: it starts test-api on its 4005 default, so point test-web at 4005 or run test-api separately on 4000). + +### LLM / OpenAI behavior without a key (expected, not a bug) +There is no `OPENAI_API_KEY` by default and no `.env.example` in the repo (despite the README mention). With no key the engine is **fail-closed**: +- Benign requests (e.g. SIWE login) return `decision.value: "error"` with `policyReason: "analysis_unavailable"`. +- Requests with critical knowledge signals (`infinite_allowance`, `malicious_address_hit`, `malicious_domain_hit`, `phishing_domain`) still deterministically return `decision.value: "block"` with `policyReason: "high_risk"`. +- Consequently `POST /v2/fixtures/validate` returns `pass: false` (fixtures expecting `allow` get `error`). This is expected without a key. +To exercise the full LLM path and get `allow` decisions on benign fixtures, put `OPENAI_API_KEY` (and optionally `OPENAI_MODEL`) in a workspace-root `.env` (loaded by `apps/test-api`). + +### Lint / test / build +- No dedicated `lint` script and no committed ESLint/Prettier config; the effective static check is the strict-mode TypeScript build. `npx prettier --check` reports diffs against Prettier defaults, but reformatting would rewrite existing source — do not run `--write` as a "lint fix". +- Tests: `npm run test` (Vitest harness + Jest snap install test). Harness only: `npm run test:harness`. +- Build all (incl. snap): `npm run build`. Note `mm-snap build` (run by `npm run build` and `dev:snap`) rewrites `apps/snap/snap.manifest.json`'s `shasum`; that incidental change should not be committed. +- The `clean` npm scripts use PowerShell (`Test-Path`) syntax and fail on Linux/bash — delete `dist/` manually instead of `npm run clean`. + +### Fixture request shape +`packages/test-fixtures/src/fixtures/*.json` wrap the request as `{ name, request, expected }`; the object to POST to `/v2/analyze` is the inner `request`. The inline fixtures in `apps/test-web/public/app.js` are already raw request objects. From 880cdf58d6f9a158028261e6d04aa554eb4adbdd Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 30 Jul 2026 03:49:01 +0000 Subject: [PATCH 2/3] fix(core-llm): drop hardcoded temperature:0 for model compatibility Newer OpenAI models (e.g. gpt-5.6-terra) reject temperature=0 and only accept the default (1). Omitting the field uses each model's default and remains compatible with gpt-5.2. Co-authored-by: CaNoe --- packages/core-llm/src/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/core-llm/src/index.ts b/packages/core-llm/src/index.ts index 9749029..40898e0 100644 --- a/packages/core-llm/src/index.ts +++ b/packages/core-llm/src/index.ts @@ -92,7 +92,6 @@ export class OpenAiReasoningProvider implements ReasoningProvider { }, body: JSON.stringify({ model: this.model, - temperature: 0, messages: [ { role: "system", From 4588c51eafb1a5d3e5bc2e0ed40e822bcc5da090 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 30 Jul 2026 04:00:55 +0000 Subject: [PATCH 3/3] docs(AGENTS): document Cloud Agent env configuration and precedence Co-authored-by: CaNoe --- AGENTS.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index da4f881..7e29dbe 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -22,7 +22,13 @@ There is no `OPENAI_API_KEY` by default and no `.env.example` in the repo (despi - Benign requests (e.g. SIWE login) return `decision.value: "error"` with `policyReason: "analysis_unavailable"`. - Requests with critical knowledge signals (`infinite_allowance`, `malicious_address_hit`, `malicious_domain_hit`, `phishing_domain`) still deterministically return `decision.value: "block"` with `policyReason: "high_risk"`. - Consequently `POST /v2/fixtures/validate` returns `pass: false` (fixtures expecting `allow` get `error`). This is expected without a key. -To exercise the full LLM path and get `allow` decisions on benign fixtures, put `OPENAI_API_KEY` (and optionally `OPENAI_MODEL`) in a workspace-root `.env` (loaded by `apps/test-api`). +To exercise the full LLM path and get `allow` decisions on benign fixtures, `OPENAI_API_KEY` must be set (see env configuration below). + +### Env configuration (Cloud Agent) +Config precedence is **injected `process.env` (Cursor Secrets) > workspace-root `.env`** — `apps/test-api` loads `.env` via dotenv, which does NOT override already-set env vars. Full variable list is in `README.md`. +- Durable / cross-VM values (e.g. `OPENAI_API_KEY`, `OPENAI_MODEL`, `SNAP_GATEWAY_TOKEN`): set them as **Cursor Secrets** — they are injected as env vars into every new VM. A workspace-root `.env` is git-ignored and does NOT persist to a fresh VM, so don't rely on it for cross-run config. Do not set env vars in the startup update script. +- Model selection: `OPENAI_MODEL` (default `gpt-5.2` from `apps/test-api`). Note some newer models only accept the default `temperature`, which is why the OpenAI request no longer hardcodes `temperature`. +- Start the API on port 4000 (see port gotcha above): `TEST_API_PORT=4000 npm run dev:test-api`. ### Lint / test / build - No dedicated `lint` script and no committed ESLint/Prettier config; the effective static check is the strict-mode TypeScript build. `npx prettier --check` reports diffs against Prettier defaults, but reformatting would rewrite existing source — do not run `--write` as a "lint fix".