mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-06 08:54:04 +01:00
fix(windows): detect Git Bash/MSYS2/Cygwin from OSTYPE, as gstack-doctor does, so uname stubs in setup fixtures stay untouched
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
27e5dce493
commit
de5998fd49
47 files changed
+77
-82
No files matched your search
@@ -303,4 +303,4 @@ Agents poll `eval:bg:*` logs for the `### gstack-detach EXIT=<code> ###` sentine
|
||||
- Every Codex run's verdict goes through `lib/outside-review-result.ts`; its reason codes live in `lib/gate-outcomes.ts`, each with a `docs/troubleshooting.md` anchor.
|
||||
- `test/module-size-ratchet.test.ts` keeps refactored owner modules at or under 800 lines (150 per function) and residual files from growing.
|
||||
- The `claude` CLI binary resolves via `lib/claude-bin.ts` (re-exported from `browse/src/claude-bin.ts` for browse internals; `Bun.which()` + `GSTACK_CLAUDE_BIN` override). Set `GSTACK_CLAUDE_BIN=wsl` plus `GSTACK_CLAUDE_BIN_ARGS='["claude"]'` to run Claude through WSL on Windows.
|
||||
- Every Bun gstack starts ignores the working directory's `.env` files and `bunfig.toml`: bun shebangs are `#!/usr/bin/env -S bun --no-env-file --config=/dev/null`, skill prose passes `bun --no-env-file --config=/dev/null`, shipped shell files define `GSTACK_BUN_CONFIG` with the line in `test/bun-entry-isolation.test.ts` (`NUL` under MINGW, MSYS and Cygwin, where native Bun cannot open `/dev/null`, #3415) and pass `bun --no-env-file --config="${GSTACK_BUN_CONFIG:-/dev/null}"`, TypeScript spawns use `bunIsolationArgs()` from `lib/bun-isolation.ts`, and `bun build --compile` adds `--no-compile-autoload-dotenv --no-compile-autoload-bunfig`. `test/bun-entry-isolation.test.ts` enforces all four.
|
||||
- Every Bun gstack starts ignores the working directory's `.env` files and `bunfig.toml`: bun shebangs are `#!/usr/bin/env -S bun --no-env-file --config=/dev/null`, skill prose passes `bun --no-env-file --config=/dev/null`, shipped shell files define `GSTACK_BUN_CONFIG` with the line in `test/bun-entry-isolation.test.ts` (`NUL` when `OSTYPE` is `msys` or `cygwin`, where native Bun cannot open `/dev/null`, #3415) and pass `bun --no-env-file --config="${GSTACK_BUN_CONFIG:-/dev/null}"`, TypeScript spawns use `bunIsolationArgs()` from `lib/bun-isolation.ts`, and `bun build --compile` adds `--no-compile-autoload-dotenv --no-compile-autoload-bunfig`. `test/bun-entry-isolation.test.ts` enforces all four.
|
||||
+2
-2
@@ -5,12 +5,12 @@
|
||||
**Windows: gstack's shell bins stop losing review, question, learning and timeline records when Git Bash path conversion is off (#3415).** Since GSTA-56 every shell bin started Bun with `--config=/dev/null`. Native `bun.exe` cannot open `/dev/null`: it exits 1 with `EINVAL` on Bun 1.3.10, 1.4.2 and 1.4.4 (measured on windows-latest). Git Bash hides this by rewriting the argument to `nul`, but only while MSYS path conversion is on. With it off (`MSYS_NO_PATHCONV` set to any value, even empty; `MSYS2_ARG_CONV_EXCL=*`; or Cygwin), `gstack-review-log`, `gstack-question-log` and `gstack-learnings-log` exited 1 with nothing written, and `gstack-timeline-log` exited 0 with nothing written.
|
||||
|
||||
### Fixed
|
||||
- **40 shipped shell files** (the bash bins, the Claude hook wrappers, `setup`, `scripts/build-cso.sh` and one migration) define `GSTACK_BUN_CONFIG` once (`NUL` under MINGW, MSYS and Cygwin, `/dev/null` elsewhere) and start Bun with `--config="${GSTACK_BUN_CONFIG:-/dev/null}"`. Bun 1.4.2 and later, gstack's minimum, read `NUL` as an empty config whether or not conversion is on. The `:-/dev/null` default fails closed: a call that loses its definition still passes `/dev/null`, so POSIX is unchanged and Windows fails loudly as before, and never reads the repository's `bunfig.toml`. `bin/gstack-codex-probe` is sourced into the caller's shell, so it defines the variable inside the one function that starts Bun and still runs nothing at source time.
|
||||
- **40 shipped shell files** (the bash bins, the Claude hook wrappers, `setup`, `scripts/build-cso.sh` and one migration) define `GSTACK_BUN_CONFIG` once (`NUL` when `OSTYPE` is `msys` or `cygwin`, as in Git Bash, MSYS2 and Cygwin, the check `gstack-doctor` already uses; `/dev/null` elsewhere) and start Bun with `--config="${GSTACK_BUN_CONFIG:-/dev/null}"`. Bun 1.4.2 and later, gstack's minimum, read `NUL` as an empty config whether or not conversion is on. The `:-/dev/null` default fails closed: a call that loses its definition still passes `/dev/null`, so POSIX is unchanged and Windows fails loudly as before, and never reads the repository's `bunfig.toml`. `bin/gstack-codex-probe` is sourced into the caller's shell, so it defines the variable inside the one function that starts Bun and still runs nothing at source time.
|
||||
- **`bin/gstack-timeline-log`**: invalid input still exits 0 with nothing logged (the hook-path contract). Its validator now exits 3 for invalid input, and any other non-zero exit, which is Bun itself failing, is reported on stderr and returned instead of being skipped as invalid.
|
||||
- Unchanged: bun shebangs and skill prose keep `--config=/dev/null`. A shebang cannot name a per-platform path, and with conversion off their POSIX script paths (`/c/Users/...`) fail in `bun.exe` anyway, so they work wherever they worked before. TypeScript spawns keep `bunIsolationArgs()`, and `scripts/ubicloud/` keeps `/dev/null` because it runs on Linux.
|
||||
|
||||
### Tests
|
||||
- `test/bun-config-shell-bins.test.ts` (new; force-included in the Windows lane): on every platform, the four record bins run through `lib/script-invocation.ts` with conversion off in a repository whose `bunfig.toml` preload and `.env` are hostile. Each writes exactly one record, and neither the preload nor the `.env` state root takes effect. Invalid timeline input still exits 0 silently. On POSIX hosts a simulated Windows bash (uname reports MINGW64, and a `bun` stand-in rejects `/dev/null` with EINVAL as `bun.exe` does) reproduces the bug: on main the four bins write nothing and the timeline control exits 0 (5 failures); with the fix they pass. The controls, with uname reporting Linux, show each bin exits non-zero with nothing written.
|
||||
- `test/bun-config-shell-bins.test.ts` (new; force-included in the Windows lane): on every platform, the four record bins run through `lib/script-invocation.ts` with conversion off in a repository whose `bunfig.toml` preload and `.env` are hostile. Each writes exactly one record, and neither the preload nor the `.env` state root takes effect. Invalid timeline input still exits 0 silently. On POSIX hosts a simulated Windows bash (`OSTYPE=msys`, and a `bun` stand-in rejects `/dev/null` with EINVAL as `bun.exe` does) reproduces the bug: on main the four bins write nothing and the timeline control exits 0 (5 failures); with the fix they pass. The controls, without `OSTYPE=msys`, show each bin exits non-zero with nothing written.
|
||||
- `test/bun-isolation-launch.test.ts`: the shell-file spelling stays isolated with conversion off, and a win32-only control shows that the literal `--config=/dev/null` fails there with EINVAL.
|
||||
- `test/bun-entry-isolation.test.ts`: shipped shell files must use the fail-closed spelling and define `GSTACK_BUN_CONFIG` with the canonical line before first use. Skill sources keep the literal spelling.
|
||||
- `test/learnings-injection.test.ts`, `browse/test/learnings-injection.test.ts` and `test/setup-hook-canonical-paths.test.ts` now anchor on the new spelling. Their assertions are unchanged.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
# Native Read barrier. A broken install must return deny JSON, never silence.
|
||||
set -euo pipefail
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
_AUTOPLAN_DECIDED=''
|
||||
_autoplan_backstop() {
|
||||
if [ -z "$_AUTOPLAN_DECIDED" ]; then
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
BASH_COMPAT=50
|
||||
|
||||
set -uo pipefail
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
|
||||
. "$(dirname "$0")/gstack-state-root.sh" 2>/dev/null || { echo "$0: cannot resolve the gstack state root: $(dirname "$0")/gstack-state-root.sh is missing. fix: reinstall with ./setup or /gstack-upgrade (docs/state-root.md)" >&2; exit 1; }
|
||||
gstack_state_root_select
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
# GSTACK_CHROMIUM_NO_SANDBOX=1 for the probe. Bash 3.2 plus POSIX tools.
|
||||
BASH_COMPAT=50
|
||||
set -u
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)" || { echo "gstack-browser-ensure: cannot resolve the install root" >&2; exit 1; }
|
||||
DOCS="https://github.com/garrytan/gstack/blob/main/docs/troubleshooting.md#browser-ensure-failed"
|
||||
|
||||
@@ -157,7 +157,7 @@ _gstack_codex_select_model() {
|
||||
# working-directory context forwarded to the shared role resolver.
|
||||
# The TOML is read by the TypeScript resolver; bash never parses it.
|
||||
local _kind="${1:-exec}" _explicit="${2:-}" _role="${3:-}" _cwd="${4:-}" _line _rc _rest
|
||||
local GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
local GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
case "$_kind" in exec|review) ;; *) echo "ERROR: _gstack_codex_select_model takes exec or review" >&2; return 2 ;; esac
|
||||
case "$_role" in ''|plan-review) ;; *) echo "ERROR: _gstack_codex_select_model role must be plan-review" >&2; return 2 ;; esac
|
||||
if ! command -v bun >/dev/null 2>&1; then
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
# Writes via bin/gstack-question-log so source tagging, dedup, and async
|
||||
# derive all apply uniformly.
|
||||
set -euo pipefail
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
. "$(dirname "$0")/gstack-state-root.sh" 2>/dev/null || { echo "$0: cannot resolve the gstack state root: $(dirname "$0")/gstack-state-root.sh is missing. fix: reinstall with ./setup or /gstack-upgrade (docs/state-root.md)" >&2; exit 1; }
|
||||
gstack_state_root_select
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
# docs/designs/PLAN_TUNING_V0.md). Event file: ~/.gstack/projects/{SLUG}/
|
||||
# question-events.jsonl.
|
||||
set -euo pipefail
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
# gstack-distill-apply --proposal <N> --gbrain-published true
|
||||
# gstack-distill-apply --list # show pending proposals
|
||||
set -euo pipefail
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
. "$(dirname "$0")/gstack-state-root.sh" 2>/dev/null || { echo "$0: cannot resolve the gstack state root: $(dirname "$0")/gstack-state-root.sh is missing. fix: reinstall with ./setup or /gstack-upgrade (docs/state-root.md)" >&2; exit 1; }
|
||||
gstack_state_root_select
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
# auditability via --status when you want it.
|
||||
# Per D6: Anthropic SDK direct call, fail-loud on missing ANTHROPIC_API_KEY.
|
||||
set -euo pipefail
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
|
||||
# Heredoc delivery guard. bash 5.2+ writes a heredoc body <=64KiB through a
|
||||
# pipe in the forked child before exec, with no reader on the other end. On
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@
|
||||
BASH_COMPAT=50
|
||||
|
||||
set -u
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
|
||||
usage() {
|
||||
sed -n '3,13p' "$0" | sed 's/^# \{0,1\}//'
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
# remote's capy/support.env, `unknown` when its fetch failed, or ""), LIVE.
|
||||
# GSTACK_CAPY_WRAPPER_PATH (optional) names the wrapper a below-minimum fix runs.
|
||||
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
. "$BIN/gstack-doctor-components.sh" || { echo "gstack-doctor: $BIN/gstack-doctor-components.sh is missing; reinstall with cd $SRC && ./setup" >&2; exit 1; }
|
||||
. "$BIN/gstack-install-registry.sh" 2>/dev/null || { echo "gstack-doctor: $BIN/gstack-install-registry.sh is missing; reinstall with cd $SRC && ./setup" >&2; exit 1; }
|
||||
. "$BIN/gstack-bun-version.sh" 2>/dev/null || { echo "gstack-doctor: $BIN/gstack-bun-version.sh is missing; reinstall with cd $SRC && ./setup" >&2; exit 1; }
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
# 2 — prerequisite missing or invalid argument
|
||||
# 3 — post-install validation failed (PATH shadow, broken binary, etc.)
|
||||
set -euo pipefail
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
|
||||
# --- defaults ---
|
||||
# No version pin by default — install the latest default-branch HEAD (#1744).
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
# Depends on: bun (already a gstack dependency), gbrain, git.
|
||||
|
||||
set -euo pipefail
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
CONFIG_BIN="$SCRIPT_DIR/gstack-config"
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
# (needed when a hook runs TypeScript) is not found. Set GSTACK_HOOK_CHECK_BUN to
|
||||
# the bun to run (setup passes its own).
|
||||
set -u
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
|
||||
LIST_ONLY=0 SETUP_FILE=""
|
||||
while [ $# -gt 1 ]; do
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
# spawned sessions (ambient OpenClaw) only warn. GSTACK_ALLOW_UNSUPPORTED_RUNTIME=1
|
||||
# admits anyway and says so.
|
||||
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
|
||||
# gstack_source_root BIN_DIR — the source checkout behind an install: an
|
||||
# installed runtime root's recorded .source-path (setup _link_runtime_dists),
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
# session tokens are outstanding.
|
||||
|
||||
set -euo pipefail
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
# The --help heredoc is over 512 bytes; keep it off a pipe (test/heredoc-pipe-deadlock.test.ts).
|
||||
BASH_COMPAT=50
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
# Allowlist file: ~/.gstack/ios-qa-allowlist.json (mode 0600).
|
||||
|
||||
set -euo pipefail
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
GSTACK_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# package and the app-owned typed state accessors.
|
||||
|
||||
set -euo pipefail
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# Append-only storage. Duplicates (same key+type) are resolved at read time
|
||||
# by gstack-learnings-search ("latest winner" per key+type).
|
||||
set -euo pipefail
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
# Windows git-bash (#1950): pwd yields a POSIX path (/c/Users/...), which Bun
|
||||
# on Windows cannot resolve as an ES module specifier in the import below.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
# exits 127 and a failed read exits non-zero with its stderr (#2790): "could
|
||||
# not read" must never look like "nothing recorded".
|
||||
set -euo pipefail
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
eval "$("$SCRIPT_DIR/gstack-slug" 2>/dev/null)"
|
||||
. "$(dirname "$0")/gstack-state-root.sh" 2>/dev/null || { echo "$0: cannot resolve the gstack state root: $(dirname "$0")/gstack-state-root.sh is missing. fix: reinstall with ./setup or /gstack-upgrade (docs/state-root.md)" >&2; exit 1; }
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
# Heredoc delivery guard (see bin/gstack-settings-hook for the rationale).
|
||||
BASH_COMPAT=50
|
||||
set -uo pipefail
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#
|
||||
# Append-only JSONL. Dedup is at read time in gstack-question-sensitivity --read-log.
|
||||
set -euo pipefail
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
# Windows git-bash (#1950): pwd yields a POSIX path (/c/Users/...), which Bun
|
||||
# on Windows cannot resolve as an ES module specifier in bun -e imports.
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
# --check already ignores those prefs; storing them made --stats lie.
|
||||
# always-ask on a one-way id is fine (it agrees with the safety override).
|
||||
set -euo pipefail
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@
|
||||
# GSTACK_INSTALL_DIR — override gstack install directory
|
||||
# GSTACK_SKILLS_DIR — override target skills directory
|
||||
set -euo pipefail
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
GSTACK_CONFIG="${SCRIPT_DIR}/gstack-config"
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
# a model read the code. Caller-supplied binding fields are always discarded.
|
||||
# Plan-tier rows retain their legacy binding behavior.
|
||||
set -euo pipefail
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
export GIT_OPTIONAL_LOCKS=0
|
||||
export GIT_CONFIG_PARAMETERS="${GIT_CONFIG_PARAMETERS:+$GIT_CONFIG_PARAMETERS }'core.fsmonitor=false' 'core.untrackedCache=false'"
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
# rows using review_freshness; legacy or uncaptured diff evidence cannot fall
|
||||
# back to HEAD equality. Plan rows are unchanged.
|
||||
set -euo pipefail
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
case "$(uname -s)" in
|
||||
MINGW*|MSYS*|CYGWIN*) command -v cygpath >/dev/null 2>&1 && SCRIPT_DIR="$(cygpath -m "$SCRIPT_DIR")" ;;
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
BASH_COMPAT=50
|
||||
|
||||
set -euo pipefail
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
|
||||
ACTION="${1:-}"
|
||||
SETTINGS_FILE="${GSTACK_SETTINGS_FILE:-${CLAUDE_CONFIG_DIR:-$HOME/.claude}/settings.json}"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
# Fix-range passes (scope "fix-range", #3339) are skipped: a narrowed dispatch
|
||||
# says nothing about a specialist's hit rate on a whole branch.
|
||||
set -euo pipefail
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
eval "$("$SCRIPT_DIR/gstack-slug" 2>/dev/null)"
|
||||
. "$(dirname "$0")/gstack-state-root.sh" 2>/dev/null || { echo "$0: cannot resolve the gstack state root: $(dirname "$0")/gstack-state-root.sh is missing. fix: reinstall with ./setup or /gstack-upgrade (docs/state-root.md)" >&2; exit 1; }
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
BASH_COMPAT=50
|
||||
|
||||
set -euo pipefail
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
|
||||
MODE="${1:-}"
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#
|
||||
# NOTE: Uses set -uo pipefail (no -e) — telemetry must never exit non-zero
|
||||
set -uo pipefail
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
|
||||
GSTACK_DIR="${GSTACK_DIR:-$(cd "$(dirname "$0")/.." && pwd)}"
|
||||
SCRIPT_DIR="$GSTACK_DIR/bin"
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
# Optional: branch, outcome, duration_s, session, ts.
|
||||
# Validation failure → skip silently (non-blocking).
|
||||
set -euo pipefail
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
eval "$("$SCRIPT_DIR/gstack-slug" 2>/dev/null)"
|
||||
. "$(dirname "$0")/gstack-state-root.sh" 2>/dev/null || { echo "$0: cannot resolve the gstack state root: $(dirname "$0")/gstack-state-root.sh is missing. fix: reinstall with ./setup or /gstack-upgrade (docs/state-root.md)" >&2; exit 1; }
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
# --branch, or an unknown argument exits 2 before any read (#1723); --help
|
||||
# prints the usage line and exits 0.
|
||||
set -euo pipefail
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
USAGE='Usage: gstack-timeline-read [--since "7 days ago"|7d|YYYY-MM-DD] [--limit N] [--branch NAME]'
|
||||
SINCE_FORMS='accepted: "<N> minute|hour|day|week|month[s] ago", "<N>h|d|w", or an ISO date YYYY-MM-DD or YYYY-MM-DDTHH:MM:SSZ'
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# shared old renders are retired. This post-setup pass repairs missed upgrades.
|
||||
# Idempotent and non-fatal: foreign entries and failed replacements stay intact.
|
||||
set -u
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
INSTALL_DIR="${GSTACK_INSTALL_DIR:-$HOME/.claude/skills/gstack}"
|
||||
if [ -f "$INSTALL_DIR/bin/gstack-migrate-claude-code" ] && command -v bun >/dev/null 2>&1; then
|
||||
bun --no-env-file --config="${GSTACK_BUN_CONFIG:-/dev/null}" "$INSTALL_DIR/bin/gstack-migrate-claude-code" --install-dir "$INSTALL_DIR" || true
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
# wrapper makes the TypeScript hook executable via bun. Settings.json
|
||||
# references this file directly.
|
||||
set -e
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
HERE="$(cd "$(dirname "$0")" && pwd)"
|
||||
exec bun --no-env-file --config="${GSTACK_BUN_CONFIG:-/dev/null}" "$HERE/auq-error-fallback-hook.ts"
|
||||
@@ -12,7 +12,7 @@
|
||||
# vendor process running with the prompt on its stdin. Forwarded, the signal
|
||||
# reaches the .ts, which kills the vendor's process group on its way out.
|
||||
# `<&0` keeps stdin: bash hands background jobs /dev/null otherwise.
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
HERE="$(cd "$(dirname "$0")" && pwd)" || exit 0
|
||||
bun --no-env-file --config="${GSTACK_BUN_CONFIG:-/dev/null}" "$HERE/memorable-user-prompt-hook.ts" <&0 &
|
||||
_child=$!
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
# wrapper makes the TypeScript hook executable via bun. Settings.json
|
||||
# references this file directly.
|
||||
set -e
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
HERE="$(cd "$(dirname "$0")" && pwd)"
|
||||
exec bun --no-env-file --config="${GSTACK_BUN_CONFIG:-/dev/null}" "$HERE/question-log-hook.ts"
|
||||
@@ -3,6 +3,6 @@
|
||||
# wrapper makes the TypeScript hook executable via bun. Settings.json
|
||||
# references this file directly.
|
||||
set -e
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
HERE="$(cd "$(dirname "$0")" && pwd)"
|
||||
exec bun --no-env-file --config="${GSTACK_BUN_CONFIG:-/dev/null}" "$HERE/question-preference-hook.ts"
|
||||
@@ -5,7 +5,7 @@
|
||||
#
|
||||
# FAIL-OPEN (F5): a Stop-event telemetry repair must never block the session.
|
||||
# Every failure path — bun missing, script crash — still exits 0.
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
HERE="$(cd "$(dirname "$0")" && pwd)" || exit 0
|
||||
bun --no-env-file --config="${GSTACK_BUN_CONFIG:-/dev/null}" "$HERE/timeline-stop-hook.ts" || true
|
||||
exit 0
|
||||
@@ -6,8 +6,8 @@
|
||||
* code under review. Every Bun gstack starts passes --no-env-file and an empty
|
||||
* --config: shebangs and skill prose spell it
|
||||
* `bun --no-env-file --config=/dev/null`, shipped shell files spell
|
||||
* `--config="${GSTACK_BUN_CONFIG:-/dev/null}"` (NUL under MINGW, MSYS and
|
||||
* Cygwin, #3415), TypeScript spawns use bunIsolationArgs().
|
||||
* `--config="${GSTACK_BUN_CONFIG:-/dev/null}"` (NUL when OSTYPE is msys or
|
||||
* cygwin, #3415), TypeScript spawns use bunIsolationArgs().
|
||||
* test/bun-entry-isolation.test.ts holds every entry point to that form.
|
||||
*
|
||||
* POSIX passes /dev/null. Native Windows has no /dev/null and `--config=NUL`
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
# Bash shim — Claude Code runs hook commands through /bin/sh; this runs the
|
||||
# TypeScript hook with bun.
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
HERE="$(cd "$(dirname "$0")" && pwd)"
|
||||
exec bun --no-env-file --config="${GSTACK_BUN_CONFIG:-/dev/null}" "$HERE/mode-handoff-hook.ts"
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
|
||||
CSO_BUILD_ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
||||
cd "$CSO_BUILD_ROOT"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
# gstack setup — build browser binary + register skills with Claude Code / Codex
|
||||
set -e
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac
|
||||
umask 077 # Restrict new files to owner-only (0o600 files, 0o700 dirs)
|
||||
|
||||
# Heredoc delivery guard. bash 5.2+ writes a heredoc body <=64KiB through a
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/**
|
||||
* #3415: gstack's shell bins start Bun with
|
||||
* --config="${GSTACK_BUN_CONFIG:-/dev/null}", and each defines
|
||||
* GSTACK_BUN_CONFIG as NUL under MINGW, MSYS and Cygwin. Native bun.exe cannot
|
||||
* GSTACK_BUN_CONFIG as NUL when OSTYPE is msys or cygwin (Git Bash, MSYS2,
|
||||
* Cygwin). Native bun.exe cannot
|
||||
* open /dev/null (EINVAL), so a Windows bash with MSYS path conversion off
|
||||
* (MSYS_NO_PATHCONV=1, MSYS2_ARG_CONV_EXCL=*) made the literal spelling fail:
|
||||
* the record bins wrote nothing, and gstack-timeline-log still exited 0.
|
||||
@@ -9,10 +10,10 @@
|
||||
* On every platform the free lanes run, windows-latest included, the record
|
||||
* bins run through lib/script-invocation.ts with conversion off in a hostile
|
||||
* repository: each writes its record, and the repository's bunfig.toml preload
|
||||
* and .env never load. On POSIX a simulated Windows bash (uname reporting
|
||||
* MINGW64, a bun that rejects /dev/null the way bun.exe does) reproduces the
|
||||
* bug; its controls, with uname reporting Linux, show each bin fails loudly
|
||||
* with nothing written instead of exiting 0.
|
||||
* and .env never load. On POSIX a simulated Windows bash (OSTYPE=msys, a bun
|
||||
* that rejects /dev/null the way bun.exe does) reproduces the bug; its
|
||||
* controls, without OSTYPE=msys, show each bin fails loudly with nothing
|
||||
* written instead of exiting 0.
|
||||
*/
|
||||
import { afterAll, beforeAll, describe, expect, test } from 'bun:test';
|
||||
import { spawnSync } from 'node:child_process';
|
||||
@@ -29,8 +30,7 @@ let repo = '';
|
||||
let stateRoot = '';
|
||||
let evilRoot = '';
|
||||
let preloadMarker = '';
|
||||
let fakeWindows = '';
|
||||
let fakeBunOnly = '';
|
||||
let fakeBun = '';
|
||||
|
||||
const BINS: Array<{ bin: string; input: string; log: string }> = [
|
||||
{ bin: 'gstack-review-log', log: 'main-reviews.jsonl', input: JSON.stringify({ skill: 'plan-eng-review', timestamp: '2026-10-25T00:00:00Z', status: 'clean', unresolved: 0, critical_gaps: 0, issues_found: 0, mode: 'FULL_REVIEW', commit: 'abc1234' }) },
|
||||
@@ -39,16 +39,16 @@ const BINS: Array<{ bin: string; input: string; log: string }> = [
|
||||
{ bin: 'gstack-timeline-log', log: 'timeline.jsonl', input: JSON.stringify({ skill: 'review', event: 'started', branch: 'main' }) },
|
||||
];
|
||||
|
||||
function env(pathPrefix?: string): NodeJS.ProcessEnv {
|
||||
function env(pathPrefix?: string, extra: Record<string, string> = {}): NodeJS.ProcessEnv {
|
||||
const out: NodeJS.ProcessEnv = {};
|
||||
for (const [k, v] of Object.entries(process.env)) if (!/^(GSTACK_|MSYS)/.test(k)) out[k] = v;
|
||||
for (const [k, v] of Object.entries(process.env)) if (!/^(GSTACK_|MSYS|OSTYPE$)/.test(k)) out[k] = v;
|
||||
const PATH = Object.keys(out).find(k => k.toUpperCase() === 'PATH') ?? 'PATH';
|
||||
if (pathPrefix) out[PATH] = pathPrefix + path.delimiter + (out[PATH] ?? '');
|
||||
return { ...out, HOME: path.join(tmp, 'home'), GSTACK_STATE_ROOT: stateRoot, MSYS_NO_PATHCONV: '1', MSYS2_ARG_CONV_EXCL: '*' };
|
||||
return { ...out, HOME: path.join(tmp, 'home'), GSTACK_STATE_ROOT: stateRoot, MSYS_NO_PATHCONV: '1', MSYS2_ARG_CONV_EXCL: '*', ...extra };
|
||||
}
|
||||
|
||||
function run(bin: string, input: string, pathPrefix?: string) {
|
||||
return runScriptSync(path.join(ROOT, 'bin', bin), [input], { cwd: repo, env: env(pathPrefix), encoding: 'utf8', timeout: 60_000 });
|
||||
function run(bin: string, input: string, pathPrefix?: string, extra: Record<string, string> = {}) {
|
||||
return runScriptSync(path.join(ROOT, 'bin', bin), [input], { cwd: repo, env: env(pathPrefix, extra), encoding: 'utf8', timeout: 60_000 });
|
||||
}
|
||||
|
||||
function records(log: string): string[] {
|
||||
@@ -84,26 +84,21 @@ beforeAll(() => {
|
||||
fs.writeFileSync(path.join(repo, 'preload.ts'), `require('fs').writeFileSync(${JSON.stringify(preloadMarker)}, 'ran');\n`);
|
||||
fs.writeFileSync(path.join(repo, 'bunfig.toml'), 'preload = ["./preload.ts"]\n');
|
||||
if (IS_WINDOWS) return;
|
||||
fakeWindows = path.join(tmp, 'fake-windows');
|
||||
fakeBunOnly = path.join(tmp, 'fake-bun-only');
|
||||
for (const dir of [fakeWindows, fakeBunOnly]) {
|
||||
fs.mkdirSync(dir);
|
||||
writeExec(path.join(dir, 'bun'), [
|
||||
'#!/usr/bin/env bash',
|
||||
'a=()',
|
||||
'for x in "$@"; do',
|
||||
' case "$x" in',
|
||||
' --config=/dev/null) echo "EINVAL: Invalid argument (open())" >&2; echo "while reading config \\"/dev/null\\"" >&2; exit 1 ;;',
|
||||
' --config=NUL) a+=(--config=/dev/null) ;;',
|
||||
' *) a+=("$x") ;;',
|
||||
' esac',
|
||||
'done',
|
||||
`exec ${JSON.stringify(process.execPath)} "\${a[@]}"`,
|
||||
'',
|
||||
].join('\n'));
|
||||
}
|
||||
writeExec(path.join(fakeWindows, 'uname'), '#!/usr/bin/env bash\n[ "$1" = -s ] && { echo MINGW64_NT-10.0-26100; exit 0; }\nexec /usr/bin/uname "$@"\n');
|
||||
writeExec(path.join(fakeWindows, 'cygpath'), '#!/usr/bin/env bash\nprintf "%s\\n" "$2"\n');
|
||||
fakeBun = path.join(tmp, 'fake-bun');
|
||||
fs.mkdirSync(fakeBun);
|
||||
writeExec(path.join(fakeBun, 'bun'), [
|
||||
'#!/usr/bin/env bash',
|
||||
'a=()',
|
||||
'for x in "$@"; do',
|
||||
' case "$x" in',
|
||||
' --config=/dev/null) echo "EINVAL: Invalid argument (open())" >&2; echo "while reading config \\"/dev/null\\"" >&2; exit 1 ;;',
|
||||
' --config=NUL) a+=(--config=/dev/null) ;;',
|
||||
' *) a+=("$x") ;;',
|
||||
' esac',
|
||||
'done',
|
||||
`exec ${JSON.stringify(process.execPath)} "\${a[@]}"`,
|
||||
'',
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
afterAll(() => { if (tmp) fs.rmSync(tmp, { recursive: true, force: true }); });
|
||||
@@ -143,7 +138,7 @@ describe.skipIf(IS_WINDOWS)('#3415: simulated Windows bash (POSIX hosts)', () =>
|
||||
for (const { bin, input, log } of BINS) {
|
||||
test(`${bin} passes NUL and writes its record`, () => {
|
||||
resetState();
|
||||
const r = run(bin, input, fakeWindows);
|
||||
const r = run(bin, input, fakeBun, { OSTYPE: 'msys' });
|
||||
expect(r.stderr).not.toContain('EINVAL');
|
||||
expect(r.status).toBe(0);
|
||||
expect(records(log).length).toBe(1);
|
||||
@@ -152,7 +147,7 @@ describe.skipIf(IS_WINDOWS)('#3415: simulated Windows bash (POSIX hosts)', () =>
|
||||
|
||||
test(`control: when Bun rejects the config, ${bin} fails loudly and writes nothing`, () => {
|
||||
resetState();
|
||||
const r = run(bin, input, fakeBunOnly);
|
||||
const r = run(bin, input, fakeBun);
|
||||
expect(r.stderr).toContain('EINVAL');
|
||||
expect(r.status).not.toBe(0);
|
||||
expect(records(log)).toEqual([]);
|
||||
|
||||
@@ -30,7 +30,7 @@ const ROOT = path.resolve(import.meta.dir, '..');
|
||||
const FLAGS = '--no-env-file --config=/dev/null';
|
||||
const ISOLATED_SHEBANG = `#!/usr/bin/env -S bun ${FLAGS}`;
|
||||
const SHELL_FLAGS = '--no-env-file --config="${GSTACK_BUN_CONFIG:-/dev/null}"';
|
||||
const CONFIG_DEF = 'GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac';
|
||||
const CONFIG_DEF = 'GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac';
|
||||
|
||||
const TRACKED = spawnSync('git', ['ls-files', '-z'], { cwd: ROOT, encoding: 'utf8', timeout: 30_000 }).stdout.split('\0').filter(Boolean)
|
||||
.filter(f => !/(^|\/)test\//.test(f) && fs.existsSync(path.join(ROOT, f)) && fs.statSync(path.join(ROOT, f)).isFile());
|
||||
|
||||
@@ -18,7 +18,7 @@ import { bunIsolationArgs } from '../lib/bun-isolation';
|
||||
import { bashCommandInvocation } from '../lib/script-invocation';
|
||||
|
||||
const PRINT = 'console.log("env=" + (process.env.GSTACK_LAUNCH_PROBE ?? "unset"))';
|
||||
const CONFIG_DEF = 'GSTACK_BUN_CONFIG=/dev/null; case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) GSTACK_BUN_CONFIG=NUL ;; esac';
|
||||
const CONFIG_DEF = 'GSTACK_BUN_CONFIG=/dev/null; case "${OSTYPE:-}" in msys*|cygwin*) GSTACK_BUN_CONFIG=NUL ;; esac';
|
||||
const NO_PATHCONV = { MSYS_NO_PATHCONV: '1', MSYS2_ARG_CONV_EXCL: '*' };
|
||||
let project = '';
|
||||
let preloadMarker = '';
|
||||
|
||||
@@ -16,7 +16,7 @@ import * as path from 'path';
|
||||
|
||||
const ROOT = path.resolve(import.meta.dir, '..');
|
||||
const PLAN_ARG = '${_PLAN_MODE_ARG:+"$_PLAN_MODE_ARG"}';
|
||||
const GENERATOR = /(?:\bbun(?: --no-env-file --config=\/dev\/null)?|\bbun_cmd|_gstack_render_bun) run (?:gen:skill-docs(?::user)?|scripts\/gen-skill-docs\.ts) --[a-z]/;
|
||||
const GENERATOR = /(?:\bbun(?: --no-env-file --config=(?:\/dev\/null|"\$\{GSTACK_BUN_CONFIG:-\/dev\/null\}"))?|\bbun_cmd|_gstack_render_bun) run (?:gen:skill-docs(?::user)?|scripts\/gen-skill-docs\.ts) --[a-z]/;
|
||||
const CONFIG_READ = '[ "$("$GSTACK_CONFIG" get plan_mode_preamble 2>/dev/null || true)" != off ] || _PLAN_MODE_ARG="--plan-mode=off"';
|
||||
|
||||
/** Generator invocations in a file: not comments, and not echoed or logged instructions. */
|
||||
|
||||
Reference in new issue
Block a user