From 2632b6df360516ca5872d2f1e2aa0e64fbe29ecd Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 1 Nov 2026 19:49:14 +0000 Subject: [PATCH 1/4] #85 - new-worktree.sh: pass an origin-only base as origin/ and verify the branch With Git 2.43, `git worktree add --no-track -b ` with a that exists only as origin/ created and checked out a local instead of , exiting 0. Resolve such a base to origin/, and after the add fail with a clear message unless the worktree is on . Adds an e2e regression test; bumps Delphi to 2.1.1. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_013vbA3k48FrWnPhQqCegP4i --- .delphi/manifest.yml | 2 +- .delphi/new-worktree.sh | 11 +++++++++-- .delphi/versions | 1 + tests/e2e.sh | 9 ++++++++- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/.delphi/manifest.yml b/.delphi/manifest.yml index fb1aa03..484f83d 100644 --- a/.delphi/manifest.yml +++ b/.delphi/manifest.yml @@ -6,7 +6,7 @@ # MINOR something new that existing clones need nothing for # MAJOR clones need cleanup (MINOR while 0.x): add .delphi/migrations/-.sh, which # setup.sh runs once per workspace in each clone (rules in Delphi's CLAUDE.md) -version: 2.1.0 +version: 2.1.1 files: # repo-relative paths; a trailing / means everything under it - .delphi/manifest.yml - .delphi/.gitattributes diff --git a/.delphi/new-worktree.sh b/.delphi/new-worktree.sh index 6e53461..ded2452 100755 --- a/.delphi/new-worktree.sh +++ b/.delphi/new-worktree.sh @@ -2,7 +2,8 @@ # .delphi/new-worktree.sh []: create or reuse worktrees// from # the bare store .delphi/setup.sh made at worktrees//.bare (never the clone at repos/), and # print its path. An existing branch (local or on origin) is checked out; a new one starts from -# (default: origin's default branch). Runs on bash 3.2 and Git Bash. +# (default: origin's default branch; a only on origin is used as origin/), and the script +# fails unless the worktree ends up on . Runs on bash 3.2 and Git Bash. set -euo pipefail # shellcheck source-path=SCRIPTDIR source=paths.sh . "$(dirname "$0")/paths.sh" @@ -18,7 +19,13 @@ elif g rev-parse -q --verify "refs/heads/$branch" >/dev/null; then g worktree add -q "$dest" "$branch" elif g rev-parse -q --verify "refs/remotes/origin/$branch" >/dev/null; then g worktree add -q --track -b "$branch" "$dest" "origin/$branch" -else +else # a only on origin goes as origin/: given the bare name, Git 2.43 checks out , not -b + if ! g rev-parse -q --verify "$base^{commit}" >/dev/null && g rev-parse -q --verify "refs/remotes/origin/$base" >/dev/null; then + base=origin/$base + fi g worktree add -q --no-track -b "$branch" "$dest" "$base" fi +on=$(git -C "$dest" branch --show-current) +[ "$on" = "$branch" ] || { echo "new-worktree: worktrees/$repo/$branch is on '${on:-a detached HEAD}', not '$branch';" \ + "remove it (git -C worktrees/$repo/.bare worktree remove ../$branch) and rerun" >&2 && exit 1; } echo "$dest" diff --git a/.delphi/versions b/.delphi/versions index 1c95e06..e21026d 100644 --- a/.delphi/versions +++ b/.delphi/versions @@ -19,3 +19,4 @@ 1.2.0 d139aaf9f4a5 worktrees come from their own bare store, worktrees//.bare, separate from the plain clone at repos/; setup.sh makes the store and the default-branch worktree again; an older bare store at repos/ is left as it is 2.0.0 750acf945979 a bare repos/ from before 1.1.0 becomes the worktree store, worktrees//.bare, with its worktrees, and repos/ is cloned normally (migration; skipped with a message if it has no origin or work not on origin) 2.1.0 84b00128fc22 add a harness-independent per-command workspace bootstrap for Codex +2.1.1 66714104d7a3 new-worktree.sh passes a only on origin as origin/ (Git 2.43 checked out instead of -b) and fails unless the worktree is on (#85) diff --git a/tests/e2e.sh b/tests/e2e.sh index fd9d04f..f2751e4 100644 --- a/tests/e2e.sh +++ b/tests/e2e.sh @@ -1073,11 +1073,18 @@ nw code feat >/dev/null && [ "$(git -C "$w/worktrees/code/feat" rev-parse HEAD)" [ "$(git -C "$w/worktrees/code/feat" rev-parse --abbrev-ref '@{u}')" = origin/feat ] || fail "existing branch not tracking origin" nw code 2-dev origin/develop >/dev/null && [ "$(git -C "$w/worktrees/code/2-dev" rev-parse HEAD)" = "$(git -C "$t/code" rev-parse develop)" ] || fail " ignored" +! git -C "$w/worktrees/code/.bare" rev-parse -q --verify refs/heads/develop >/dev/null || fail "store already has a local develop" +nw code 3-dev develop >/dev/null && [ "$(git -C "$w/worktrees/code/3-dev" branch --show-current)" = 3-dev ] && + [ "$(git -C "$w/worktrees/code/3-dev" rev-parse HEAD)" = "$(git -C "$t/code" rev-parse develop)" ] || fail " only on origin: not on the new branch" +! git -C "$w/worktrees/code/.bare" rev-parse -q --verify refs/heads/develop >/dev/null || fail " only on origin: left a local develop" +git -C "$w/worktrees/code/.bare" worktree add -q --detach "$w/worktrees/code/4-off" origin/develop +! nw code 4-off >/dev/null 2>"$t/err" || fail "worktree off its branch not refused" +grep -q "is on 'a detached HEAD', not '4-off'" "$t/err" || fail "worktree off its branch refusal unexplained: $(cat "$t/err")" [ "$(nw code feat)" = "$w/worktrees/code/feat" ] || fail "rerun did not reuse" [ "$(git -C "$w/worktrees/code/$def" branch --show-current)" = "$def" ] || fail "default worktree left its branch" { [ "$(git -C "$w/repos/code" branch --show-current)" = "$def" ] && [ "$(git -C "$w/repos/code" worktree list | wc -l | tr -d " ")" = 1 ] && ! git -C "$w/repos/code" rev-parse -q --verify refs/heads/1-new >/dev/null; } || fail "new-worktree touched the clone at repos/code" -ok "new-worktree.sh makes new branches from the default or , checks out existing ones, reuses on rerun, never touching repos/" +ok "new-worktree.sh makes new branches from the default or (local or only on origin), checks out existing ones, reuses on rerun, refuses a worktree off its branch, never touching repos/" # skill scripts read the workspace from $DELPHI_ROOT (the session hook evals paths.sh's export line) and every folder from paths.sh (. "$w/.delphi/paths.sh" && [ "$DELPHI_ROOT" = "$w" ] && [ "$DELPHI_REPOS" = "$w/repos" ] && [ "$DELPHI_WORKTREES" = "$w/worktrees" ] && [ "$DELPHI_REFERENCES" = "$w/references" ] && [ "$DELPHI_WORKSPACES" = "$w/workspaces" ]) || From 6c13327d7925ed755cf10af4f14d7e5b1b309fe2 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 2 Nov 2026 18:26:48 +0000 Subject: [PATCH 2/4] argos: run AGLint in implement and open-pr when it's installed and configured Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_013vbA3k48FrWnPhQqCegP4i --- .../.claude/skills/implement/SKILL.md | 1 + .../.claude/skills/pr-conventions/SKILL.md | 4 ++++ .../.claude/skills/pr-conventions/scripts/aglint.sh | 13 +++++++++++++ 3 files changed, 18 insertions(+) create mode 100644 software/application-software/argos/workspace-inherit/.claude/skills/pr-conventions/scripts/aglint.sh diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/implement/SKILL.md b/software/application-software/argos/workspace-inherit/.claude/skills/implement/SKILL.md index f24d293..38486ab 100644 --- a/software/application-software/argos/workspace-inherit/.claude/skills/implement/SKILL.md +++ b/software/application-software/argos/workspace-inherit/.claude/skills/implement/SKILL.md @@ -11,4 +11,5 @@ description: Implement an Argos ticket or task in its own worktree, test-first, - Frontend, in `(cd worktrees/argos//angular-client && …)`: `npx ng test --include='src/**/thing.spec.ts' --watch=false` while iterating; at the end `npx ng test --watch=false` (bare `ng test` blocks), then `npx prettier --check "src/**/*.{ts,html,scss}" && npx ng lint`. - Backend, in `(cd worktrees/argos//scylla-server && …)`: `cargo build` and single tests while iterating; `cargo test` at the end. - UI changes: verify in the running app with `run-local `. + - AGLint, last: load the `pr-conventions` skill and follow its AGLint check. 6. **Commit** with `/commit`. Don't push or open a PR unless asked; that's `/open-pr`. diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/pr-conventions/SKILL.md b/software/application-software/argos/workspace-inherit/.claude/skills/pr-conventions/SKILL.md index 2265e4f..cb46c53 100644 --- a/software/application-software/argos/workspace-inherit/.claude/skills/pr-conventions/SKILL.md +++ b/software/application-software/argos/workspace-inherit/.claude/skills/pr-conventions/SKILL.md @@ -10,6 +10,10 @@ The shared rules are in the `open-pr` skill; this adds only what is Argos's. - Base branch: `develop`. Commit format: `^#[0-9]+ - ` (the format in CLAUDE.md). - Checks: `bash scripts/lint.sh ` (frontend prettier and ng lint, only if angular-client/ changed). +- AGLint, after `npm ci` in angular-client/: `bash scripts/aglint.sh ` runs `aglint check --fast` (the branch against `origin/develop`) and exits 0 PASS, 4 WARN, 1 FAIL, 2 or 3 if AGLint itself failed (show the user). It prints nothing when `aglint` isn't on PATH or the worktree has no `angular-client/.aglint/`; say nothing then. Run other `aglint` commands in `(cd worktrees/argos//angular-client && …)`: `aglint explain ` gives a signal's evidence and fix; reports are in `.aglint/out/`. + - FAIL: fix the cause and rerun, or stop and show the user the failing signals. + - WARN: show the user the top signals, then fix them, or ask the user before `aglint accept --reason "…" --expires `. Never accept on your own; commit `.aglint/accepted.yml` with the change. + - PR body: one Testing line with the verdict and any accepted signals. - Labels: one written-by (`by: human` if the user wrote it, `by: ai-assisted` if they gave the substance, `by: ai` if you wrote it) and at least one area label (`frontend`, `backend`, `devops`), besides `open-pr`'s category label. - Screenshots: `pictures//` at the worktree root (git-ignored). - UI QA: get the branch running with `run-local `, then drive it with Playwright, using the `playwright-cdp` server if `curl -s localhost:9222/json/version` responds, otherwise `playwright`. diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/pr-conventions/scripts/aglint.sh b/software/application-software/argos/workspace-inherit/.claude/skills/pr-conventions/scripts/aglint.sh new file mode 100644 index 0000000..825930e --- /dev/null +++ b/software/application-software/argos/workspace-inherit/.claude/skills/pr-conventions/scripts/aglint.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +# aglint.sh : Argos's AGLint check, on worktrees/argos//angular-client. Runs +# `aglint check --fast` (the branch against the base in .aglint/config.yml) and exits with its code: +# 0 PASS, 4 WARN, 1 FAIL, 2 config error, 3 internal error. Prints nothing and exits 0 when aglint +# isn't on PATH or the worktree has no angular-client/.aglint/ (AGLint is private and not on develop yet). +set -euo pipefail +usage="usage: aglint.sh " +branch=${1:?$usage} +# shellcheck source=/dev/null +. "${DELPHI_ROOT:?unset: start the session at the workspace root, on Delphi 0.2.0+ (pull its ws/ branch), or source /.delphi/paths.sh}/.delphi/paths.sh" +cd "$DELPHI_WORKTREES/argos/$branch" +if ! command -v aglint >/dev/null || [ ! -d angular-client/.aglint ]; then exit 0; fi +cd angular-client && exec aglint check --fast From 77362a30c8287d2d84fcb3eedb57ea2b0b21597f Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 2 Nov 2026 20:06:13 +0000 Subject: [PATCH 3/4] argos: run AGLint once over every configured subproject (angular-client, scylla-server) Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_013vbA3k48FrWnPhQqCegP4i --- .../.claude/skills/pr-conventions/SKILL.md | 2 +- .../.claude/skills/pr-conventions/scripts/aglint.sh | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/pr-conventions/SKILL.md b/software/application-software/argos/workspace-inherit/.claude/skills/pr-conventions/SKILL.md index cb46c53..da2d36b 100644 --- a/software/application-software/argos/workspace-inherit/.claude/skills/pr-conventions/SKILL.md +++ b/software/application-software/argos/workspace-inherit/.claude/skills/pr-conventions/SKILL.md @@ -10,7 +10,7 @@ The shared rules are in the `open-pr` skill; this adds only what is Argos's. - Base branch: `develop`. Commit format: `^#[0-9]+ - ` (the format in CLAUDE.md). - Checks: `bash scripts/lint.sh ` (frontend prettier and ng lint, only if angular-client/ changed). -- AGLint, after `npm ci` in angular-client/: `bash scripts/aglint.sh ` runs `aglint check --fast` (the branch against `origin/develop`) and exits 0 PASS, 4 WARN, 1 FAIL, 2 or 3 if AGLint itself failed (show the user). It prints nothing when `aglint` isn't on PATH or the worktree has no `angular-client/.aglint/`; say nothing then. Run other `aglint` commands in `(cd worktrees/argos//angular-client && …)`: `aglint explain ` gives a signal's evidence and fix; reports are in `.aglint/out/`. +- AGLint, after `npm ci` in angular-client/: `bash scripts/aglint.sh ` runs `aglint check --fast` once from the worktree root over every subproject with an `.aglint/` (angular-client, scylla-server), skipping those the branch doesn't touch, against `origin/develop`. It exits 0 PASS, 4 WARN, 1 FAIL, 2 or 3 if AGLint itself failed (show the user). It prints nothing when `aglint` isn't on PATH or no subproject has an `.aglint/`; say nothing then. Run other `aglint` commands from the worktree root with `--root `: `aglint explain --root angular-client` gives a signal's evidence and fix; the combined report is in `.aglint/out/`. - FAIL: fix the cause and rerun, or stop and show the user the failing signals. - WARN: show the user the top signals, then fix them, or ask the user before `aglint accept --reason "…" --expires `. Never accept on your own; commit `.aglint/accepted.yml` with the change. - PR body: one Testing line with the verdict and any accepted signals. diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/pr-conventions/scripts/aglint.sh b/software/application-software/argos/workspace-inherit/.claude/skills/pr-conventions/scripts/aglint.sh index 825930e..227a3cb 100644 --- a/software/application-software/argos/workspace-inherit/.claude/skills/pr-conventions/scripts/aglint.sh +++ b/software/application-software/argos/workspace-inherit/.claude/skills/pr-conventions/scripts/aglint.sh @@ -1,13 +1,14 @@ #!/usr/bin/env bash -# aglint.sh : Argos's AGLint check, on worktrees/argos//angular-client. Runs -# `aglint check --fast` (the branch against the base in .aglint/config.yml) and exits with its code: -# 0 PASS, 4 WARN, 1 FAIL, 2 config error, 3 internal error. Prints nothing and exits 0 when aglint -# isn't on PATH or the worktree has no angular-client/.aglint/ (AGLint is private and not on develop yet). +# aglint.sh : Argos's AGLint check, from the root of worktrees/argos/. Runs +# `aglint check --fast` once over every subproject with an .aglint/ (angular-client, scylla-server), +# skipping those the branch doesn't touch, and exits with the combined code: 0 PASS, 4 WARN, 1 FAIL, +# 2 config error, 3 internal error. Prints nothing and exits 0 when aglint isn't on PATH or no +# subproject has an .aglint/ (AGLint is private and not on develop yet). set -euo pipefail usage="usage: aglint.sh " branch=${1:?$usage} # shellcheck source=/dev/null . "${DELPHI_ROOT:?unset: start the session at the workspace root, on Delphi 0.2.0+ (pull its ws/ branch), or source /.delphi/paths.sh}/.delphi/paths.sh" cd "$DELPHI_WORKTREES/argos/$branch" -if ! command -v aglint >/dev/null || [ ! -d angular-client/.aglint ]; then exit 0; fi -cd angular-client && exec aglint check --fast +if ! command -v aglint >/dev/null || ! compgen -G '*/.aglint/config.yml' >/dev/null; then exit 0; fi +exec aglint check --fast From 63af95d822a213d56e9dc7f62aba913278191104 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 3 Nov 2026 14:08:48 +0000 Subject: [PATCH 4/4] argos: take AGLint back out of the implement and pr-conventions skills Reverts 6c13327 and 77362a3; AGLint isn't being adopted in the workflow yet. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_013vbA3k48FrWnPhQqCegP4i --- .../.claude/skills/implement/SKILL.md | 1 - .../.claude/skills/pr-conventions/SKILL.md | 4 ---- .../skills/pr-conventions/scripts/aglint.sh | 14 -------------- 3 files changed, 19 deletions(-) delete mode 100644 software/application-software/argos/workspace-inherit/.claude/skills/pr-conventions/scripts/aglint.sh diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/implement/SKILL.md b/software/application-software/argos/workspace-inherit/.claude/skills/implement/SKILL.md index 38486ab..f24d293 100644 --- a/software/application-software/argos/workspace-inherit/.claude/skills/implement/SKILL.md +++ b/software/application-software/argos/workspace-inherit/.claude/skills/implement/SKILL.md @@ -11,5 +11,4 @@ description: Implement an Argos ticket or task in its own worktree, test-first, - Frontend, in `(cd worktrees/argos//angular-client && …)`: `npx ng test --include='src/**/thing.spec.ts' --watch=false` while iterating; at the end `npx ng test --watch=false` (bare `ng test` blocks), then `npx prettier --check "src/**/*.{ts,html,scss}" && npx ng lint`. - Backend, in `(cd worktrees/argos//scylla-server && …)`: `cargo build` and single tests while iterating; `cargo test` at the end. - UI changes: verify in the running app with `run-local `. - - AGLint, last: load the `pr-conventions` skill and follow its AGLint check. 6. **Commit** with `/commit`. Don't push or open a PR unless asked; that's `/open-pr`. diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/pr-conventions/SKILL.md b/software/application-software/argos/workspace-inherit/.claude/skills/pr-conventions/SKILL.md index da2d36b..2265e4f 100644 --- a/software/application-software/argos/workspace-inherit/.claude/skills/pr-conventions/SKILL.md +++ b/software/application-software/argos/workspace-inherit/.claude/skills/pr-conventions/SKILL.md @@ -10,10 +10,6 @@ The shared rules are in the `open-pr` skill; this adds only what is Argos's. - Base branch: `develop`. Commit format: `^#[0-9]+ - ` (the format in CLAUDE.md). - Checks: `bash scripts/lint.sh ` (frontend prettier and ng lint, only if angular-client/ changed). -- AGLint, after `npm ci` in angular-client/: `bash scripts/aglint.sh ` runs `aglint check --fast` once from the worktree root over every subproject with an `.aglint/` (angular-client, scylla-server), skipping those the branch doesn't touch, against `origin/develop`. It exits 0 PASS, 4 WARN, 1 FAIL, 2 or 3 if AGLint itself failed (show the user). It prints nothing when `aglint` isn't on PATH or no subproject has an `.aglint/`; say nothing then. Run other `aglint` commands from the worktree root with `--root `: `aglint explain --root angular-client` gives a signal's evidence and fix; the combined report is in `.aglint/out/`. - - FAIL: fix the cause and rerun, or stop and show the user the failing signals. - - WARN: show the user the top signals, then fix them, or ask the user before `aglint accept --reason "…" --expires `. Never accept on your own; commit `.aglint/accepted.yml` with the change. - - PR body: one Testing line with the verdict and any accepted signals. - Labels: one written-by (`by: human` if the user wrote it, `by: ai-assisted` if they gave the substance, `by: ai` if you wrote it) and at least one area label (`frontend`, `backend`, `devops`), besides `open-pr`'s category label. - Screenshots: `pictures//` at the worktree root (git-ignored). - UI QA: get the branch running with `run-local `, then drive it with Playwright, using the `playwright-cdp` server if `curl -s localhost:9222/json/version` responds, otherwise `playwright`. diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/pr-conventions/scripts/aglint.sh b/software/application-software/argos/workspace-inherit/.claude/skills/pr-conventions/scripts/aglint.sh deleted file mode 100644 index 227a3cb..0000000 --- a/software/application-software/argos/workspace-inherit/.claude/skills/pr-conventions/scripts/aglint.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash -# aglint.sh : Argos's AGLint check, from the root of worktrees/argos/. Runs -# `aglint check --fast` once over every subproject with an .aglint/ (angular-client, scylla-server), -# skipping those the branch doesn't touch, and exits with the combined code: 0 PASS, 4 WARN, 1 FAIL, -# 2 config error, 3 internal error. Prints nothing and exits 0 when aglint isn't on PATH or no -# subproject has an .aglint/ (AGLint is private and not on develop yet). -set -euo pipefail -usage="usage: aglint.sh " -branch=${1:?$usage} -# shellcheck source=/dev/null -. "${DELPHI_ROOT:?unset: start the session at the workspace root, on Delphi 0.2.0+ (pull its ws/ branch), or source /.delphi/paths.sh}/.delphi/paths.sh" -cd "$DELPHI_WORKTREES/argos/$branch" -if ! command -v aglint >/dev/null || ! compgen -G '*/.aglint/config.yml' >/dev/null; then exit 0; fi -exec aglint check --fast