-
Notifications
You must be signed in to change notification settings - Fork 0
nono-here #110
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
nono-here #110
Changes from all commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
3f927eb
Makes run_harness more generic by moving SANDBOX_COMMAND to defaults …
MKuckert 441a15c
Prepares nono-here template
MKuckert 2c32e4d
chore: Adds plan for new nono-here script
MKuckert 1bd2532
Merge branch 'main' into feature/nono-here
MKuckert 1ef1f7f
feat: add nono-here.sh skeleton with self-location and workdir resolu…
MKuckert 7638391
refactor: scope self-location, guard symlink cycles in nono-here.sh
MKuckert a858fb1
chore: Extends agent permissions
MKuckert 3a4fda4
chore: Adds cost-guard plugin
MKuckert b568f1e
feat: add handover() single exec site to nono-here.sh (Task 9)
MKuckert 142935a
feat: add fast-path handover branch ladder to nono-here.sh (Task 2)
MKuckert 29dd5b9
feat: add harness selection with override and select menu (Task 3)
MKuckert 8b4a0c1
feat: add template resolution and in-place validation (Task 4)
MKuckert 11e4814
feat: add stale .sandbox confirmation and removal (Task 5)
MKuckert de19bd3
feat: copy template into .sandbox with non-directory guard (Task 6)
MKuckert 9ec305b
feat: move run_harness.sh into workspace with mode post-condition (Ta…
MKuckert fb0b9d0
feat: generate .sandbox/defaults.sh, preserving template-provided one…
MKuckert 7f4459d
feat: hand over to run_harness.sh after provisioning (Task 8b)
MKuckert 4fc989e
fix: guard empty SANDBOX_COMMAND_DEFAULTS under set -u on Bash 3.2 (T…
MKuckert 79afda0
chore: Allow access to repo base
MKuckert df52a0b
test: add test_nono_here.sh test suite for nono-here.sh (Task 11)
MKuckert 7ecb263
docs: archive nono-here bootstrap plan with post-mortem, add PROJECT_…
MKuckert 52062d1
revert: restore agent permission guardrails (PR #110 review B1)
9a1667a
fix: address provisioning and startup review findings (PR #110)
d6823bb
fix: sync live run_harness.sh with template, harden test suite (PR #110)
f189fc8
docs: rework nono-here.sh comments to explain intent, not history
8da2c8f
Delete PROJECT_MAP.md
MKuckert 84654d2
Merge remote-tracking branch 'origin/main' into feature/nono-here
d953c11
Merge remote-tracking branch 'origin/feature/nono-here' into feature/…
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| { | ||
| "maxCostUsd": 5.0, | ||
| "warnAtPercent": 80, | ||
| "mode": "block" | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,2 @@ | ||
| #!/usr/bin/env bash | ||
| SANDBOX_COMMAND_DEFAULTS=() | ||
| SANDBOX_COMMAND=opencode |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,203 @@ | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
| # VERSION 2 | ||
|
|
||
| SELF="$(basename "$0")" | ||
|
|
||
| # Documented extension point: adding a harness is a one-token edit to this | ||
| # array and nothing else. | ||
| HARNESSES=(claude opencode codex copilot pi) | ||
|
|
||
| die() { | ||
| local code="$1" | ||
| shift | ||
| echo "$SELF: $*" >&2 | ||
| exit "$code" | ||
| } | ||
|
|
||
| # Resolve the script's own directory, following symlinks (portable, no | ||
| # readlink -f / realpath — must work on macOS/Bash 3.2). Bounded to guard | ||
| # against symlink cycles (e.g. a -> b -> a). | ||
| resolve_script_dir() { | ||
| local src dir target hops | ||
| src="$0" | ||
| hops=0 | ||
| while [[ -L "$src" ]]; do | ||
| hops=$((hops + 1)) | ||
| if [[ "$hops" -gt 40 ]]; then | ||
| die 1 "symlink resolution exceeded 40 hops (possible cycle) for '$0'" | ||
| fi | ||
| dir="$(cd -P "$(dirname "$src")" && pwd)" | ||
| target="$(readlink "$src")" | ||
| case "$target" in | ||
| /*) src="$target" ;; | ||
| *) src="$dir/$target" ;; | ||
| esac | ||
| done | ||
| cd -P "$(dirname "$src")" && pwd | ||
| } | ||
|
|
||
| # Keep this assignment bare (no `local`/`export`): with `set -e`, a failure | ||
| # inside resolve_script_dir must abort the script. Wrapping it would replace | ||
| # $? with the local/export builtin's exit status, masking the failure. | ||
| script_dir="$(resolve_script_dir)" | ||
|
|
||
| # Exported so a future child process can inherit the resolved home; nothing | ||
| # consumes it yet. | ||
| export NONO_HERE_HOME="${NONO_HERE_HOME:-$script_dir}" | ||
|
|
||
| workdir=$(git rev-parse --show-toplevel 2>/dev/null || echo "$PWD") | ||
|
|
||
| # The single exec site, shared by the fast path and the end of provisioning | ||
| # so both hand over identically (same CWD, same argument handling). | ||
| handover() { | ||
| cd "$workdir" || die 1 "cannot enter $workdir" | ||
| exec ./run_harness.sh "$@" | ||
| } | ||
|
|
||
| # Fast path: an already-provisioned workspace hands straight over, silently. | ||
| # (workdir and template are echoed to stderr only when provisioning happens.) | ||
| if [[ -e "$workdir/run_harness.sh" || -L "$workdir/run_harness.sh" ]] && [[ ! -f "$workdir/run_harness.sh" ]]; then | ||
| die 9 "$workdir/run_harness.sh exists but is not a regular file" | ||
| elif [[ -f "$workdir/run_harness.sh" ]] && [[ ! -x "$workdir/run_harness.sh" ]]; then | ||
| die 2 "$workdir/run_harness.sh is not executable; run: chmod +x \"$workdir/run_harness.sh\"" | ||
| elif [[ -f "$workdir/run_harness.sh" ]] && [[ -x "$workdir/run_harness.sh" ]]; then | ||
| if [[ ! -x "$workdir/.sandbox/start.sh" ]]; then | ||
|
|
||
| die 3 "$workdir/.sandbox/start.sh is missing or not executable; run: chmod +x \"$workdir/.sandbox/start.sh\"" | ||
| fi | ||
| handover "$@" | ||
| fi | ||
|
|
||
| # Provisioning begins here: run_harness.sh is entirely absent. Nothing on | ||
| # disk changes until a harness and template have been validated. | ||
|
|
||
| if [[ -n "${NONO_HERE_HARNESS:-}" ]]; then | ||
| harness="" | ||
| for h in "${HARNESSES[@]}"; do | ||
| if [[ "$h" == "$NONO_HERE_HARNESS" ]]; then | ||
| harness="$h" | ||
| break | ||
| fi | ||
| done | ||
| if [[ -z "$harness" ]]; then | ||
| die 8 "invalid NONO_HERE_HARNESS '$NONO_HERE_HARNESS'; valid values: ${HARNESSES[*]}" | ||
| fi | ||
| elif [[ ! -t 0 ]]; then | ||
| die 4 "no TTY for interactive harness selection; set NONO_HERE_HARNESS to one of: ${HARNESSES[*]}" | ||
| else | ||
| PS3="harness> " | ||
| select harness in "${HARNESSES[@]}"; do | ||
| if [[ -n "${harness:-}" ]]; then | ||
| break | ||
| fi | ||
| echo "$SELF: invalid selection '$REPLY'; choose a number from the list" >&2 | ||
| done | ||
| if [[ -z "${harness:-}" ]]; then | ||
| die 10 "no harness selected (input closed)" | ||
| fi | ||
| fi | ||
|
|
||
| # Template resolution: user overrides beat bundled templates, | ||
| # harness-specific beats default; the first existing directory wins. | ||
| template="" | ||
| for candidate in \ | ||
| "${HOME:-}/.nono-here/templates/$harness" \ | ||
| "${HOME:-}/.nono-here/templates/default" \ | ||
| "$NONO_HERE_HOME/templates/$harness" \ | ||
| "$NONO_HERE_HOME/templates/default"; do | ||
| if [[ -d "$candidate" ]]; then | ||
| template="$candidate" | ||
| break | ||
| fi | ||
| done | ||
|
|
||
| if [[ -z "$template" ]]; then | ||
| die 5 "no template directory found; probed in order: | ||
| ${HOME:-}/.nono-here/templates/$harness | ||
| ${HOME:-}/.nono-here/templates/default | ||
| $NONO_HERE_HOME/templates/$harness | ||
| $NONO_HERE_HOME/templates/default" | ||
| fi | ||
|
|
||
| echo "$SELF: workdir: $workdir" >&2 | ||
| echo "$SELF: template: $template" >&2 | ||
|
|
||
| for required in run_harness.sh start.sh; do | ||
| if [[ ! -f "$template/$required" ]]; then | ||
| die 7 "template '$template' is missing required file '$required'" | ||
| fi | ||
| if [[ ! -x "$template/$required" ]]; then | ||
| die 7 "template '$template' has '$required' without the executable bit; run: chmod +x \"$template/$required\"" | ||
| fi | ||
| done | ||
|
|
||
| # A .sandbox without run_harness.sh is the remnant of an interrupted | ||
| # previous run. This point is only reached with a fully validated template | ||
| # in hand, so deleting it never leaves the workspace with neither sandbox | ||
| # nor replacement. | ||
| if [[ -e "$workdir/.sandbox" ]]; then | ||
| if [[ ! -t 0 ]]; then | ||
| die 6 "$workdir/.sandbox exists but is incomplete; remove it manually and re-run: rm -r \"$workdir/.sandbox\"" | ||
| fi | ||
|
|
||
| echo -e "\033[33mWarning: '$workdir/.sandbox' exists but 'run_harness.sh' is missing — the sandbox is incomplete.\033[0m" >&2 | ||
| echo -e "\033[33mIt will be re-created from template '$template'.\033[0m" >&2 | ||
| echo -e "\033[33mThis is self-healing: it is the expected result of a previous run interrupted between the copy and completion; re-creating from the template repairs it.\033[0m" >&2 | ||
|
|
||
| reply="" | ||
| read -r -p "delete .sandbox and re-create from $template? [y/N] " reply || reply="" | ||
| case "$reply" in | ||
| y | Y) ;; | ||
| *) die 6 "aborted; '$workdir/.sandbox' left untouched" ;; | ||
| esac | ||
|
|
||
| rm -r "$workdir/.sandbox" | ||
| fi | ||
|
|
||
| # A dangling symlink named .sandbox is invisible to the `-e` test above | ||
| # (false for a broken link). Without this guard, `mkdir -p` would abort via | ||
| # set -e with a bare, unexplained `File exists`. Every other kind of | ||
| # pre-existing .sandbox was already intercepted with exit 6. | ||
| if [[ -e "$workdir/.sandbox" || -L "$workdir/.sandbox" ]] && [[ ! -d "$workdir/.sandbox" ]]; then | ||
| die 9 "$workdir/.sandbox exists but is not a directory" | ||
| fi | ||
|
|
||
| mkdir -p "$workdir/.sandbox" | ||
| cp -R "$template/." "$workdir/.sandbox/" | ||
|
|
||
| # defaults.sh is generated before run_harness.sh is moved into place: if | ||
| # generation fails, run_harness.sh is still absent, so the next invocation | ||
| # re-enters provisioning instead of taking the fast path against a | ||
| # workspace that is missing its defaults file. | ||
| # | ||
| # A dangling symlink named defaults.sh is invisible to `-e`, and `cat >` | ||
| # would follow it, writing outside .sandbox. Reject any non-regular path. | ||
| if [[ -e "$workdir/.sandbox/defaults.sh" || -L "$workdir/.sandbox/defaults.sh" ]] && [[ ! -f "$workdir/.sandbox/defaults.sh" ]]; then | ||
| die 9 "$workdir/.sandbox/defaults.sh exists but is not a regular file" | ||
| fi | ||
| if [[ -f "$workdir/.sandbox/defaults.sh" ]]; then | ||
| echo "$SELF: '$workdir/.sandbox/defaults.sh' already exists; preserved untouched." >&2 | ||
| else | ||
| cat >"$workdir/.sandbox/defaults.sh" <<EOF | ||
| # generated by nono-here.sh | ||
| SANDBOX_COMMAND="$harness" | ||
| SANDBOX_COMMAND_DEFAULTS=() | ||
| EOF | ||
| fi | ||
|
|
||
| mv "$workdir/.sandbox/run_harness.sh" "$workdir/run_harness.sh" | ||
|
|
||
| # The template's mode bits were validated above; if the copy lost them, | ||
| # name the template rather than suggest a `chmod` on a file that will be | ||
| # regenerated on the next run. | ||
| if [[ ! -x "$workdir/run_harness.sh" ]]; then | ||
| die 7 "template '$template' produced a non-executable 'run_harness.sh'; the copy did not preserve permissions" | ||
| fi | ||
| if [[ ! -x "$workdir/.sandbox/start.sh" ]]; then | ||
| die 7 "template '$template' produced a non-executable 'start.sh'; the copy did not preserve permissions" | ||
| fi | ||
|
|
||
| # Provisioning complete: run_harness.sh in place, .sandbox populated, | ||
| # defaults.sh generated or preserved. Hand over through the same single | ||
| # exec site as the fast path. | ||
| handover "$@" | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| profile.json |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| { | ||
| "extends": ["default"], | ||
| "meta": { | ||
| "name": "NAME", | ||
| "version": "1" | ||
| }, | ||
| "workdir": { | ||
| "access": "readwrite" | ||
| }, | ||
| "filesystem": { | ||
| "allow": [], | ||
| "deny": [], | ||
| "read_file": ["~/.gitignore"], | ||
| "read": ["~/.CFUserTextEncoding"] | ||
| }, | ||
| "network": { | ||
| "allow_domain": [] | ||
| }, | ||
| "environment": { | ||
| "allow_vars": [ | ||
| "HOME", | ||
| "SHELL", | ||
| "TERM", | ||
| "PATH", | ||
| "LSCOLORS", | ||
| "LS_COLORS", | ||
| "LC_ALL", | ||
| "LANG", | ||
| "PWD", | ||
| "USER", | ||
| "EDITOR", | ||
| "DO_NOT_TRACK" | ||
| ] | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| #!/usr/bin/env bash | ||
| # VERSION 3 | ||
| set -euo pipefail | ||
|
|
||
| WORKSPACE=$(git rev-parse --show-toplevel 2>/dev/null || echo "$PWD") | ||
| DEFAULTS_FILE="${DEFAULTS_FILE:-$WORKSPACE/.sandbox/defaults.sh}" | ||
|
|
||
| if [[ ! -f "$DEFAULTS_FILE" ]]; then | ||
| echo "missing defaults file $DEFAULTS_FILE" | ||
| exit 1 | ||
| fi | ||
|
|
||
| source "$DEFAULTS_FILE" | ||
| SANDBOX_COMMAND="${SANDBOX_COMMAND:-}" | ||
| if [[ "$SANDBOX_COMMAND" = "" ]]; then | ||
| echo "missing 'SANDBOX_COMMAND' in $DEFAULTS_FILE" | ||
| exit 2 | ||
| fi | ||
|
|
||
| if [[ $# -eq 0 || "${1:-}" == -* ]]; then | ||
| set -- ${SANDBOX_COMMAND_DEFAULTS[@]+"${SANDBOX_COMMAND_DEFAULTS[@]}"} "$@" | ||
| fi | ||
|
|
||
| if [[ "${1:-}" == "$SANDBOX_COMMAND" ]]; then | ||
| shift | ||
| fi | ||
|
|
||
| "$WORKSPACE/.sandbox/start.sh" "$SANDBOX_COMMAND" "$@" |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.