Skip to content
This repository was archived by the owner on Jun 26, 2026. It is now read-only.

Commit 5ca7a87

Browse files
matejvasekclaude
andcommitted
feat: better testing server setup for init.sh
- Stop operations use PID files (.dev-pids/) with recursive kill_tree instead of pgrep/pkill, handles deep process trees (e.g. yarn->webpack) - Ports randomized via --randomize-ports flag (default ports unchanged) - Active ports written to .dev-env.json for agent and tooling discovery - Go backend auto-recompiles on .go/.mod/.sum changes via inotifywait with build-then-swap strategy (build to tmp, swap only on success) - On compilation failure, errserver returns HTTP 500 with build error as JSON so the UI displays actual compiler output - Watcher shuts down on inotifywait or errserver startup failure - start-console.sh accepts --backend-port, --plugin-port, --console-port, --cidfile CLI args - Dropped --network=host on Linux, uses -p port mapping everywhere - webpack.config.ts reads PLUGIN_PORT env var with fallback to 9001 - Agent docs (AGENTS.md, WORKFLOW.md, init-session) reference .dev-env.json and .dev-logs/ - inotify-tools documented as optional dev prerequisite in README Signed-off-by: Matej Vašek <matejvasek@gmail.com> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 847c4e3 commit 5ca7a87

14 files changed

Lines changed: 1115 additions & 38 deletions

File tree

.claude/commands/init-session.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
allowed-tools: Bash(git log:*), Bash(pwd), Bash(./init.sh), Bash(yarn test*), Read
2+
allowed-tools: Bash(git log:*), Bash(pwd), Bash(./init.sh), Bash(yarn test*), Bash(cat .dev-env.json), Read
33
description: Run startup sequence (steps 1-6 from docs/WORKFLOW.md)
44
---
55

@@ -19,5 +19,6 @@ Execute the startup sequence from `docs/WORKFLOW.md`. AGENTS.md is always in con
1919
3. **Check struggles** — read `docs/agent-struggles.json`. If unresolved entries exist, present to user.
2020
4. **Pick feature** — read `docs/features.json`, find first `"passes": false` entry.
2121
5. **Start dev env** — run `./init.sh`.
22-
6. **Run tests** — run `yarn test` and verify app is healthy.
23-
7. **Wait** — tell the user you're oriented, report the picked feature and which step of the Feature Development Sequence you'd start at. When the user says to proceed, follow the Feature Development Sequence in `docs/WORKFLOW.md` step by step. Do NOT start any work autonomously.
22+
6. **Read ports** — read `.dev-env.json` and note the backend, plugin, and console ports.
23+
7. **Run tests** — run `yarn test` and verify app is healthy.
24+
8. **Wait** — tell the user you're oriented, report the picked feature and which step of the Feature Development Sequence you'd start at. When the user says to proceed, follow the Feature Development Sequence in `docs/WORKFLOW.md` step by step. Do NOT start any work autonomously.

.dockerignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
11
/bin
2+
.dev-logs
3+
.dev-pids
4+
.dev-env.json

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ AGENTS.override.md
3535
# Local development configuration
3636
.dev
3737
.dev-logs
38+
.dev-pids
39+
.dev-env.json
3840

3941
# Yarn v4 (Berry)
4042
.yarn/*

AGENTS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,7 @@ No em dashes (`—`). Use commas, periods, or parentheses instead.
3232
| `docs/potential-features.json` | Candidate features for future implementation |
3333
| `docs/claude-progress.txt` | Session handoff log — see [`references/claude-progress-readme.md`](docs/references/claude-progress-readme.md) |
3434
| `docs/agent-struggles.json` | Struggle log — see [`references/agent-struggles-readme.md`](docs/references/agent-struggles-readme.md) |
35+
| `.dev-env.json` | Dev server ports (backendPort, pluginPort, consolePort), written by init.sh |
36+
| `.dev-logs/` | Dev server log files (backend.log, webpack.log, console.log) |
3537
| `docs/references/ocp-plugin-guide.md` | OCP dynamic plugin mechanics, i18n, extension points |
3638
| `docs/references/commit-message-guide.md` | Git commit conventions and authorship rules |

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ Available image tags are listed in the [container registry](https://github.com/f
4848
- [Docker](https://www.docker.com) or [podman 3.2.0+](https://podman.io)
4949
- An [OpenShift cluster](https://console.redhat.com/openshift/create)
5050
- Github [*Personal Access Token*](https://github.com/settings/personal-access-tokens) with *administration*, *content* and *workflow* write permissions in all repositories
51+
- [inotify-tools](https://github.com/inotify-tools/inotify-tools) (optional, enables Go backend auto-recompile on file changes)
5152

5253
### Option 1: Local
5354

backend/cmd/errserver/main.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package main
2+
3+
import (
4+
"encoding/json"
5+
"flag"
6+
"fmt"
7+
"log"
8+
"net/http"
9+
"os"
10+
)
11+
12+
func main() {
13+
port := flag.Int("port", 8080, "HTTP server port")
14+
msgFile := flag.String("msg-file", "", "file containing the error message to serve")
15+
flag.Parse()
16+
17+
msg, err := os.ReadFile(*msgFile)
18+
if err != nil {
19+
log.Fatalf("Failed to read message file: %v", err)
20+
}
21+
22+
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
23+
w.Header().Set("Content-Type", "application/json")
24+
w.WriteHeader(http.StatusInternalServerError)
25+
json.NewEncoder(w).Encode(map[string]string{"message": string(msg)})
26+
})
27+
28+
log.Printf("Serving compilation error on :%d", *port)
29+
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", *port), nil))
30+
}

docs/WORKFLOW.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ Every session, before doing any work:
99
3. Read `docs/agent-struggles.json` — if unresolved entries exist, present to user
1010
4. Read `docs/features.json` — pick first `"passes": false` entry
1111
5. Run `./init.sh` — start dev env
12-
6. Run tests — verify app is healthy
13-
7. If broken → fix first. If clean → start [Feature Development Sequence](#feature-development-sequence).
12+
6. Read `.dev-env.json` — note the dev server ports (backend, plugin, console)
13+
7. Run tests — verify app is healthy
14+
8. If broken → fix first. If clean → start [Feature Development Sequence](#feature-development-sequence).
1415

1516
## Feature Development Sequence
1617

docs/claude-progress.txt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,32 @@
11
# Claude Progress Log
22
# Newest entries first. Agents: append your entry at the top after the header.
33

4+
---
5+
## 2026-05-18 | Session: Error server and JSON error responses
6+
Worked on: Errserver for failed Go compilation, JSON error responses for backend
7+
Completed:
8+
- Error server (backend/cmd/errserver): on Go build failure, the file watcher starts errserver which returns HTTP 500 with compilation error as JSON {"message": "..."}
9+
- OCP console's appFetch parses json.message automatically, so the UI shows actual compiler output instead of generic "Internal Server Error"
10+
Left off: Branch improve-test-cluster, PR #25 open. Backend JSON error response not yet pushed.
11+
Blockers: None
12+
13+
---
14+
## 2026-05-15 | Session: Better testing server setup (init.sh)
15+
Worked on: Improve init.sh with PID files, port randomization, Go auto-recompile, agent docs
16+
Completed:
17+
- Stop operations use PID files (.dev-pids/) with recursive kill_tree instead of pgrep/pkill
18+
- Ports randomized via --randomize-ports flag (default ports unchanged for human testers)
19+
- Active ports written to .dev-env.json for agent and tooling discovery
20+
- Go backend auto-recompiles on .go/.mod/.sum changes via inotifywait (build-then-swap strategy)
21+
- start-console.sh accepts --backend-port, --plugin-port, --console-port, --cidfile CLI args
22+
- Dropped --network=host on Linux in favor of -p port mapping (enables console port randomization)
23+
- webpack.config.ts reads PLUGIN_PORT env var with fallback to 9001
24+
- Agent docs (AGENTS.md, WORKFLOW.md, init-session) reference .dev-env.json and .dev-logs/
25+
- Design spec and implementation plan written
26+
- 13 suites, 112 tests, all passing
27+
Left off: Branch improve-test-cluster, PR #25 open.
28+
Blockers: None
29+
430
---
531
## 2026-05-13 | Session: Fix function list not updating on GitHub user switch
632
Worked on: Bug fix for PAT switching via Avatar button not refreshing the function list
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
# Better Testing Server Setup (init.sh)
2+
3+
## Goal
4+
5+
Make init.sh suitable for running multiple dev environments concurrently (across different repo clones/worktrees) and improve the Go backend development loop with auto-recompile on file changes.
6+
7+
## Use Case
8+
9+
Multiple repos/worktrees running dev environments simultaneously. Each gets its own randomized ports so there are no collisions.
10+
11+
## Changes
12+
13+
### 1. PID File Management
14+
15+
**Current:** `--stop` uses `pgrep -f` / `pkill -f` with name patterns (e.g. `"bin/backend"`, `"webpack serve"`). Fragile, can kill processes from other repos.
16+
17+
**New:**
18+
19+
- PID files stored in `.dev-pids/` directory (created on startup)
20+
- Files: `backend.pid`, `webpack.pid`, `backend-watcher.pid`
21+
- Console container ID stored in `.dev-pids/console.cid` (via `podman run --cidfile`)
22+
- Each `start_*` function writes `$!` (backgrounded PID) to its PID file
23+
- Each `stop_*` function reads the PID file, sends SIGTERM, waits briefly, removes the PID file
24+
- `--stop` iterates over whatever PID/CID files exist (safe if only some services are running)
25+
26+
### 2. Port Randomization
27+
28+
**Current:** Hardcoded ports: backend 8080, webpack 9001, console 9000.
29+
30+
**New:**
31+
32+
- By default, init.sh uses the same hardcoded defaults as today (8080, 9001, 9000) so human testers are not surprised
33+
- When `--randomize-ports` flag is passed, init.sh picks three random available ports from range 10000-60000
34+
- A `random_free_port()` helper function loops until it finds an unused port (TCP probe check)
35+
- `.dev-env.json` is always written at project root, regardless of whether ports are randomized or default:
36+
```json
37+
{
38+
"backendPort": 12345,
39+
"pluginPort": 12346,
40+
"consolePort": 12347
41+
}
42+
```
43+
- `--stop` removes `.dev-env.json`
44+
45+
### 3. Go Backend Auto-Recompile
46+
47+
**Current:** `start_backend` builds once and runs the binary. Changes require manual restart.
48+
49+
**New:**
50+
51+
- After backend starts, init.sh spawns a watcher process in the background
52+
- Watcher uses `inotifywait -m -r -e modify,create,delete,move --include '\.(go|mod|sum)$' backend/` to monitor for Go source and module changes
53+
- On each event, debounce (1 second) to let rapid successive changes settle
54+
- Rebuild strategy (build-then-swap):
55+
1. Build to temporary binary: `go build -buildvcs=false -o ../bin/backend-tmp .`
56+
2. If build fails: log error to `.dev-logs/backend.log`, keep current backend running, continue watching
57+
3. If build succeeds: kill current backend (via PID file), move `backend-tmp` to `backend`, start new process, write new PID to `.dev-pids/backend.pid`
58+
- Watcher gets its own PID file: `.dev-pids/backend-watcher.pid`
59+
- init.sh checks for `inotifywait` at startup. If missing, prints warning and skips the watcher (backend still works, no auto-reload)
60+
61+
### 4. Port Passing to Downstream Scripts
62+
63+
**start-console.sh:**
64+
65+
- Accepts CLI arguments: `--backend-port`, `--plugin-port`, `--console-port`
66+
- Each argument falls back to the current hardcoded default (8080, 9001, 9000) so the script works standalone
67+
- Replaces hardcoded port values in `BRIDGE_PLUGINS`, `BRIDGE_PLUGIN_PROXY`, and the `-p` container port flag
68+
69+
**webpack.config.ts:**
70+
71+
- Dev server port changes from hardcoded `9001` to `Number(process.env.PLUGIN_PORT) || 9001`
72+
- init.sh exports `PLUGIN_PORT` before running `yarn start`
73+
74+
**init.sh invocations:**
75+
76+
```bash
77+
PLUGIN_PORT="$PLUGIN_PORT" yarn start > "$LOG_DIR/webpack.log" 2>&1 &
78+
79+
./start-console.sh \
80+
--backend-port "$BACKEND_PORT" \
81+
--plugin-port "$PLUGIN_PORT" \
82+
--console-port "$CONSOLE_PORT" \
83+
> "$LOG_DIR/console.log" 2>&1 &
84+
```
85+
86+
### 5. Agent Awareness
87+
88+
Agents need to know where the dev server is running so they can connect to it (e.g. for browser testing or API calls).
89+
90+
- **CLAUDE.md**: Add `.dev-env.json` and `.dev-logs/` to the knowledge base table, noting dev server ports and log file locations respectively
91+
- **WORKFLOW.md**: Add a step to the Startup Sequence (after "Run `./init.sh`") to read `.dev-env.json` and note the ports
92+
- **`.claude/commands/init-session.md`**: Add a step to read `.dev-env.json` and report the ports to the user
93+
94+
## Files Modified
95+
96+
| File | Change |
97+
|------|--------|
98+
| `init.sh` | PID files, `--randomize-ports` flag, `.dev-env.json` output, inotifywait backend watcher, pass ports downstream, `--stop` reads PIDs/CID |
99+
| `start-console.sh` | Accept `--backend-port`, `--plugin-port`, `--console-port` CLI args with fallback defaults |
100+
| `webpack.config.ts` | Read `PLUGIN_PORT` env var with fallback to 9001 |
101+
| `.gitignore` | Add `.dev-pids/` and `.dev-env.json` |
102+
| `.dockerignore` | Add `.dev-pids/` and `.dev-env.json` |
103+
| `CLAUDE.md` | Add `.dev-env.json` and `.dev-logs/` to knowledge base table |
104+
| `docs/WORKFLOW.md` | Add port discovery step to Startup Sequence |
105+
| `.claude/commands/init-session.md` | Add step to read and report dev server ports |
106+
107+
No new files created (besides runtime artifacts which are gitignored/dockerignored).
108+
109+
## Backwards Compatibility
110+
111+
All three modified files retain current default behavior when invoked without the new arguments/env vars. Running `./start-console.sh` directly or `yarn start` without init.sh produces the same ports as today.
112+
113+
## Prerequisites
114+
115+
- `inotify-tools` package for the Go backend watcher. Gracefully degrades if missing (warning printed, watcher skipped).

docs/features.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,17 @@
145145
],
146146
"passes": true
147147
},
148+
{
149+
"category": "technical",
150+
"description": "Better testing server setup (init.sh)",
151+
"steps": [
152+
"The --stop operation shall employ PID files, not kill processes by name.",
153+
"The ports (go backend 8080, webpack server 9001, webconsole container 9000) shall randomized, so it's possible to run multiple testing servers (for multiple Claude instances).",
154+
"The randomized ports shall be available to the Claude via a file.",
155+
"The go backend service should be automatically recompiled/restarted upon change to the ./backend directory."
156+
],
157+
"passes": true
158+
},
148159
{
149160
"category": "functional",
150161
"description": "Function List Page shows deployed functions from all user-accessible namespaces without requiring a PAT",

0 commit comments

Comments
 (0)