Merge remote-tracking branch 'origin/staging' into develop

This commit is contained in:
Andrey Antukh 2026-07-09 08:34:27 +02:00
commit 54bef496f1
6 changed files with 299 additions and 98 deletions

View File

@ -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] [<code>]
```
The tool is also executable directly:
```bash
./tools/nrepl-eval.mjs [options] [<code>]
```
## 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-<host>-<port>`. 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 <PORT>` 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).

View File

@ -48,13 +48,24 @@ module. You can read it from `mem:<MODULE>/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

View File

@ -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).

View File

@ -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] [<code>]
# or
./tools/nrepl-eval.mjs [options] [<code>]
```
## 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-<host>-<port>`. 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 <PORT>` 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).

View File

@ -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`.

View File

@ -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'