From b3d1a7aa8bffbe96e445856557254d87f15c3c78 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Thu, 9 Jul 2026 08:33:46 +0200 Subject: [PATCH] :books: Add better dev tools doc to serena --- .opencode/skills/nrepl-eval/SKILL.md | 99 ++------------------- .serena/memories/critical-info.md | 19 +++- .serena/memories/tools/gh.md | 80 +++++++++++++++++ .serena/memories/tools/nrepl-eval.md | 126 +++++++++++++++++++++++++++ .serena/memories/tools/taiga.md | 44 ++++++++++ tools/nrepl-eval.mjs | 29 +++++- 6 files changed, 299 insertions(+), 98 deletions(-) create mode 100644 .serena/memories/tools/gh.md create mode 100644 .serena/memories/tools/nrepl-eval.md create mode 100644 .serena/memories/tools/taiga.md diff --git a/.opencode/skills/nrepl-eval/SKILL.md b/.opencode/skills/nrepl-eval/SKILL.md index 2cf44d88c7..b4b3d76d7f 100644 --- a/.opencode/skills/nrepl-eval/SKILL.md +++ b/.opencode/skills/nrepl-eval/SKILL.md @@ -6,26 +6,20 @@ description: Evaluate Clojure code via nREPL using the standalone tools/nrepl-ev # nREPL Eval Evaluate Clojure (or ClojureScript) code via a running nREPL server using -`tools/nrepl-eval.mjs` — a standalone CLI application. +`tools/nrepl-eval.mjs`. -Session state (defs, in-ns, etc.) persists across invocations via a stored -session ID, so you can build up state incrementally. +Full documentation: `mem:tools/nrepl-eval` (file: `.serena/memories/tools/nrepl-eval.md`) -## Usage +## Quick Reference -```bash -node tools/nrepl-eval.mjs [options] [] -``` - -The tool is also executable directly: ```bash ./tools/nrepl-eval.mjs [options] [] ``` -## Options - | Flag | Description | Default | |------|-------------|---------| +| `--backend` | Connect to backend nREPL (port 6064) | — | +| `--frontend` | Connect to frontend nREPL (port 3447) | — | | `-p, --port PORT` | nREPL server port | `6064` | | `-H, --host HOST` | nREPL server host | `127.0.0.1` | | `-t, --timeout MS` | Timeout in milliseconds | `120000` | @@ -33,88 +27,11 @@ The tool is also executable directly: | `-e, --last-error` | Evaluate `*e` to retrieve the last exception | — | | `-h, --help` | Show help message | — | -## When to Use +## Examples -Use this tool when you need to: - -1. **Evaluate Clojure code** during development — test functions, inspect - state, or run experiments against a running Clojure process. -2. **Verify that edited files compile** — require namespaces with `:reload` - to pick up changes. -3. **Inspect the last exception** after a failed evaluation — use `-e` to - print the error stored in `*e`. - -## Workflow - -### 1. Session management - -Sessions are persisted to `/tmp/penpot-nrepl-session--`. State -carries across calls automatically: - -```bash -./tools/nrepl-eval.mjs '(def x 42)' -./tools/nrepl-eval.mjs 'x' -# => 42 -``` - -Reset the session to start fresh: - -```bash -./tools/nrepl-eval.mjs --reset-session '(def x 0)' -``` - -### 2. Evaluate code - -**Single expression (inline) — uses default port 6064:** ```bash ./tools/nrepl-eval.mjs '(+ 1 2 3)' -``` - -**Multiple expressions via heredoc (recommended — avoids escaping issues):** -```bash -./tools/nrepl-eval.mjs <<'EOF' -(def x 10) -(+ x 20) -EOF -``` - -**Override with a different port:** -```bash -./tools/nrepl-eval.mjs -p 7888 '(+ 1 2 3)' -``` - -### 3. Inspect last exception - -After code throws an error, retrieve the full exception details: - -```bash +./tools/nrepl-eval.mjs --backend '(+ 1 2 3)' +./tools/nrepl-eval.mjs --frontend '(js/alert "hi")' ./tools/nrepl-eval.mjs -e ``` - -## Common Patterns - -**Require a namespace with reload:** -```bash -./tools/nrepl-eval.mjs "(require '[my.namespace :as ns] :reload)" -``` - -**Test a function:** -```bash -./tools/nrepl-eval.mjs "(ns/my-function arg1 arg2)" -``` - -**Long-running operation with custom timeout:** -```bash -./tools/nrepl-eval.mjs -t 300000 "(long-running-fn)" -``` - -## Key Principles - -- **Default port is 6064** — just pass code directly, no `-p` needed when - your nREPL server is on 6064. Use `-p ` for a different port. -- **Always use `:reload`** when requiring namespaces to pick up file changes. -- **Session is reused** across invocations — defs, in-ns, and var bindings - persist. Use `--reset-session` to clear. -- **Do not start any server** — the tool connects to an existing nREPL - server, it is not the agent's responsibility to start the nREPL server - (assume the server is already running on the specified port). diff --git a/.serena/memories/critical-info.md b/.serena/memories/critical-info.md index d0f83b656b..1027829bcf 100644 --- a/.serena/memories/critical-info.md +++ b/.serena/memories/critical-info.md @@ -48,13 +48,24 @@ module. You can read it from `mem:/core` When working on devenv startup, compose layout, instance config (`defaults.env`), tmux session lifecycle, MinIO provisioning, or anything in `manage.sh`'s `*-devenv` commands, read `mem:devenv/core`. -- `tools/` contains standalone dev utilities: `nrepl-eval.mjs` (backend REPL eval), - `paren-repair.bb` (delimiter-error fixer, see `mem:tools/paren-repair`), - `psql` / `db-schema` (PostgreSQL client and schema dump wrappers, see `mem:tools/psql`), and - `taiga.py` / `gh.py` (issue management helpers). - `experiments/` contains standalone experimental HTML/JS/scripts; treat it as non-core unless the user explicitly asks about it. - `sample_media/` contains sample image/icon media and config used as fixtures/demo material; do not infer app behavior from it. +# Dev tools + +- `tools/nrepl-eval.mjs` — Evaluate Clojure/ClojureScript code via nREPL. + Supports `--backend` (port 6064) and `--frontend` (port 3447) aliases. + See `mem:tools/nrepl-eval`. +- `tools/paren-repair.bb` — Fix mismatched delimiters in Clojure/CLJS files + and reformat with cljfmt. Run before lint checks when LLM edits break parens. + See `mem:tools/paren-repair`. +- `tools/psql` — PostgreSQL client wrapper with devenv defaults. + Companion: `tools/db-schema` for DDL dumps. See `mem:tools/psql`. +- `tools/taiga.py` — Fetch public issues, user stories, and tasks from the + Penpot Taiga project without authentication. See `mem:tools/taiga`. +- `tools/gh.py` — GitHub operations helper: list milestone issues, fetch PR + details, compare against CHANGES.md. Requires `gh` CLI. See `mem:tools/gh`. + # Dependency graph `frontend -> common`, `backend -> common`, `exporter -> common`, and `frontend -> render-wasm`. Changes in `common` can diff --git a/.serena/memories/tools/gh.md b/.serena/memories/tools/gh.md new file mode 100644 index 0000000000..3f74b82b66 --- /dev/null +++ b/.serena/memories/tools/gh.md @@ -0,0 +1,80 @@ +# GitHub operations helper + +`tools/gh.py` is a multi-purpose CLI for querying the penpot/penpot GitHub +repository via GraphQL and REST APIs through the authenticated `gh` CLI. + +## When to use + +- Listing issues in a milestone (for changelog generation). +- Finding issues with no milestone. +- Fetching PR details by number or by milestone. +- Comparing milestone issues against CHANGES.md to find missing entries. + +## Prerequisites + +- `gh` CLI authenticated (`gh auth status`). +- Python 3.8+. + +## Subcommands + +### `issues` + +List issues in a milestone, with filtering by state, labels, and project status. + +```bash +# Closed issues in a milestone (default) +python3 tools/gh.py issues "2.16.0" + +# All issues in a milestone +python3 tools/gh.py issues "2.16.0" --state all + +# Issues with no milestone +python3 tools/gh.py issues none +python3 tools/gh.py issues none --state open + +# Filter by label (include only) +python3 tools/gh.py issues "2.16.0" --label "bug" +python3 tools/gh.py issues "2.16.0" --label "bug,regression" + +# Exclude by label +python3 tools/gh.py issues "2.16.0" --exclude "release blocker,no changelog" + +# Show only issues NOT yet in CHANGES.md +python3 tools/gh.py issues "2.16.0" --compare CHANGES.md +``` + +**Default filters** (override with flags): +- Issues with type "Task" are excluded (`--include-tasks` to keep them). +- Issues with "Rejected" project status are excluded (`--include-rejected` to keep them). + +**Output**: JSON array to stdout; progress to stderr. + +### `prs` + +Fetch PR details by number or by milestone. + +```bash +# Fetch specific PRs +python3 tools/gh.py prs 9179 9204 9311 + +# Read PR numbers from file +python3 tools/gh.py prs --file prs.txt + +# Read PR numbers from stdin +cat prs.txt | python3 tools/gh.py prs --stdin + +# All PRs in a milestone (default: merged only) +python3 tools/gh.py prs --milestone "2.16.0" + +# All PRs in a milestone (all states) +python3 tools/gh.py prs --milestone "2.16.0" --state all +``` + +**Output**: JSON array to stdout; progress to stderr. + +## Key principles + +- All output is JSON — pipe into `jq` or other tools for further processing. +- Milestone lookup is by exact title match. +- `issues` subcommand auto-paginates (100 items per page). +- `prs` subcommand batches PR number lookups (50 per GraphQL query). diff --git a/.serena/memories/tools/nrepl-eval.md b/.serena/memories/tools/nrepl-eval.md new file mode 100644 index 0000000000..f5ec3ab994 --- /dev/null +++ b/.serena/memories/tools/nrepl-eval.md @@ -0,0 +1,126 @@ +# nREPL Eval + +Evaluate Clojure (or ClojureScript) code via a running nREPL server using +`tools/nrepl-eval.mjs` — a standalone CLI application. + +Session state (defs, in-ns, etc.) persists across invocations via a stored +session ID, so you can build up state incrementally. + +## Usage + +```bash +node tools/nrepl-eval.mjs [options] [] +# or +./tools/nrepl-eval.mjs [options] [] +``` + +## Options + +| Flag | Description | Default | +|------|-------------|---------| +| `--backend` | Connect to backend nREPL (port 6064) | — | +| `--frontend` | Connect to frontend nREPL (port 3447) | — | +| `-p, --port PORT` | nREPL server port | `6064` | +| `-H, --host HOST` | nREPL server host | `127.0.0.1` | +| `-t, --timeout MS` | Timeout in milliseconds | `120000` | +| `--reset-session` | Discard stored session and start fresh | — | +| `-e, --last-error` | Evaluate `*e` to retrieve the last exception | — | +| `-h, --help` | Show help message | — | + +- `--backend` and `--frontend` are mutually exclusive. +- Explicit `--port` is overridden when `--backend`/`--frontend` is used. + +## When to Use + +1. **Evaluate Clojure code** during development — test functions, inspect + state, or run experiments against a running Clojure process. +2. **Verify that edited files compile** — require namespaces with `:reload` + to pick up changes. +3. **Inspect the last exception** after a failed evaluation — use `-e` to + print the error stored in `*e`. + +## Workflow + +### Session management + +Sessions are persisted to `/tmp/penpot-nrepl-session--`. State +carries across calls automatically: + +```bash +./tools/nrepl-eval.mjs '(def x 42)' +./tools/nrepl-eval.mjs 'x' +# => 42 +``` + +Reset the session to start fresh: + +```bash +./tools/nrepl-eval.mjs --reset-session '(def x 0)' +``` + +### Evaluate code + +**Single expression (inline) — uses default port 6064:** +```bash +./tools/nrepl-eval.mjs '(+ 1 2 3)' +``` + +**Backend nREPL (explicit):** +```bash +./tools/nrepl-eval.mjs --backend '(+ 1 2 3)' +``` + +**Frontend nREPL:** +```bash +./tools/nrepl-eval.mjs --frontend '(js/alert "hi")' +``` + +**Multiple expressions via heredoc (recommended — avoids escaping issues):** +```bash +./tools/nrepl-eval.mjs <<'EOF' +(def x 10) +(+ x 20) +EOF +``` + +**Override with a different port:** +```bash +./tools/nrepl-eval.mjs -p 7888 '(+ 1 2 3)' +``` + +### Inspect last exception + +After code throws an error, retrieve the full exception details: + +```bash +./tools/nrepl-eval.mjs -e +``` + +## Common Patterns + +**Require a namespace with reload:** +```bash +./tools/nrepl-eval.mjs "(require '[my.namespace :as ns] :reload)" +``` + +**Test a function:** +```bash +./tools/nrepl-eval.mjs "(ns/my-function arg1 arg2)" +``` + +**Long-running operation with custom timeout:** +```bash +./tools/nrepl-eval.mjs -t 300000 "(long-running-fn)" +``` + +## Key Principles + +- **Default port is 6064** — just pass code directly, no `-p` needed when + your nREPL server is on 6064. Use `--backend` (6064) or `--frontend` (3447) + as quick aliases. Use `-p ` for any other port. +- **Always use `:reload`** when requiring namespaces to pick up file changes. +- **Session is reused** across invocations — defs, in-ns, and var bindings + persist. Use `--reset-session` to clear. +- **Do not start any server** — the tool connects to an existing nREPL + server, it is not the agent's responsibility to start the nREPL server + (assume the server is already running on the specified port). diff --git a/.serena/memories/tools/taiga.md b/.serena/memories/tools/taiga.md new file mode 100644 index 0000000000..b4e623e3e1 --- /dev/null +++ b/.serena/memories/tools/taiga.md @@ -0,0 +1,44 @@ +# Taiga API client + +`tools/taiga.py` fetches public issues, user stories, and tasks from the +Penpot Taiga project (id 345963) without authentication. + +## When to use + +- Fetching details of a Taiga issue, user story, or task by URL or ref number. +- Inspecting status, assignee, tags, description, and other metadata. +- Piping structured JSON into other scripts (with `--json`). + +## How to use + +```bash +# Fetch by full Taiga URL +python3 tools/taiga.py https://tree.taiga.io/project/penpot/issue/13714 + +# Fetch by type and ref number +python3 tools/taiga.py issue 13714 +python3 tools/taiga.py us 14128 +python3 tools/taiga.py task 13648 + +# Output raw JSON instead of formatted summary +python3 tools/taiga.py --json issue 13714 +python3 tools/taiga.py --json https://tree.taiga.io/project/penpot/us/14128 +``` + +## Supported types + +| Type | Description | +|------|-------------| +| `issue` | Bug reports, feature requests | +| `us` | User stories | +| `task` | Implementation tasks | + +## Output + +Default output is a formatted summary with title, status, assignee, author, +tags, URL, and description. Use `--json` for the raw API response. + +## Prerequisites + +- Python 3.8+ (standard library only, no dependencies). +- Network access to `api.taiga.io`. diff --git a/tools/nrepl-eval.mjs b/tools/nrepl-eval.mjs index 45da2445de..8a10905305 100755 --- a/tools/nrepl-eval.mjs +++ b/tools/nrepl-eval.mjs @@ -128,18 +128,24 @@ function formatEvalMessages(messages) { function parseArgs(argv) { const args = { - port: 6064, + port: null, host: "127.0.0.1", timeout: DEFAULT_TIMEOUT, help: false, resetSession: false, lastError: false, + backend: false, + frontend: false, code: null, }; for (let i = 0; i < argv.length; i++) { const a = argv[i]; - if (a === "-p" || a === "--port") { + if (a === "--backend") { + args.backend = true; + } else if (a === "--frontend") { + args.frontend = true; + } else if (a === "-p" || a === "--port") { const val = argv[++i]; if (val === undefined) { console.error("Error: --port requires a value."); process.exit(1); } args.port = parseInt(val, 10); @@ -166,6 +172,19 @@ function parseArgs(argv) { } } + if (args.backend && args.frontend) { + console.error("Error: --backend and --frontend are mutually exclusive."); + process.exit(1); + } + + if (args.backend) { + args.port = 6064; + } else if (args.frontend) { + args.port = 3447; + } else if (args.port === null) { + args.port = 6064; + } + return args; } @@ -177,7 +196,9 @@ Evaluate Clojure code via a running nREPL server. Session state (defs, in-ns) persists across invocations via a stored session ID. Options: - -p, --port PORT nREPL port (default: 6064) + --backend Connect to backend nREPL on port 6064 (default) + --frontend Connect to frontend nREPL on port 3447 + -p, --port PORT nREPL port (default: 6064; overridden by --backend/--frontend) -H, --host HOST nREPL host (default: 127.0.0.1) -t, --timeout MILLISECONDS Timeout in milliseconds (default: 120000) --reset-session Discard stored session and start fresh @@ -187,6 +208,8 @@ Options: Examples: ${bin} '(def x 42)' ${bin} 'x' + ${bin} --backend '(+ 1 2 3)' + ${bin} --frontend '(js/alert "hi")' ${bin} --reset-session '(def x 0)' ${bin} --last-error ${bin} <<'EOF'