Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
127 commits
Select commit Hold shift + click to select a range
7ab2713
fix(test): host-config goldens self-provision .agents/.factory artifacts
garrytan Aug 16, 2026
cb8c79a
fix(test): exempt the live repo tree from hermetic-wiring's operator-…
sneakygriff Aug 15, 2026
ba979db
fix(gen-skill-docs): quote YAML inline scalars containing '...' (Bun …
sneakygriff Aug 15, 2026
480ebe4
fix(gen-skill-docs): throw when a template contains {{PREAMBLE}} twice
garrytan Aug 16, 2026
7ed17bf
fix(test): classify catalog-trim.test.ts as tree-mutating
garrytan Aug 16, 2026
890fcac
fix(test): prepush hook test builds PATH with a POSIX-only separator
luckywenapere Aug 13, 2026
de670f6
fix(artifacts): sync the decision store, which no allowlist glob matched
source-utsho Aug 14, 2026
dc86570
fix(windows): resolve the project slug natively when gstack-slug cann…
source-utsho Aug 14, 2026
69c1b3d
fix(security): guard brain-sync arithmetic against injected .brain-la…
garrytan Aug 16, 2026
ea780fe
fix(sync): run gstack-brain-sync through bash, not cmd.exe, on Windows
ShahriarLak Aug 10, 2026
4047e52
fix(gbrain): quote cmd.exe arguments at a single gbrain invocation seam
garrytan Aug 16, 2026
184cf84
fix(brain-sync): classify queue entries, rewrite surgically, re-push …
garrytan Aug 16, 2026
4f5e351
fix(gbrain): make --full do a full code walk, not a delta one
ShahriarLak Jul 31, 2026
c024a5b
fix(brain-cache): honest 'missing' instead of fabricated-empty digest…
sneakygriff Aug 15, 2026
c2cdf65
fix(test): give the schema-mismatch rebuild test a load-proof budget
garrytan Aug 16, 2026
00d0115
fix(memory-ingest): parse the current Codex response_item rollout shape
garrytan Aug 16, 2026
9df6015
fix(test): refresh codex/factory ship goldens from post-#2588 regener…
garrytan Aug 16, 2026
a118fd0
fix(make-pdf): boolean flags no longer swallow the next positional ar…
garrytan Aug 16, 2026
2c07418
fix(repo-mode): probe GNU stat before BSD so Git Bash stops crashing
garrytan Aug 16, 2026
bab1923
fix(retro): point the prior-retros context query at files /retro actu…
garrytan Aug 16, 2026
0f70ea8
fix(sync-gbrain): remove the capability-check page file left in the u…
garrytan Aug 16, 2026
9cd1e87
docs(browse): warn that hover scrolls and the daemon tab persists acr…
garrytan Aug 16, 2026
1a1dab2
fix(gitattributes): pin *.txt to LF
mlaniak Aug 11, 2026
0f38fee
fix(setup): install every skill runtime asset for the Claude host
garrytan Aug 16, 2026
663aca3
fix(setup): alias skills install as rewritten copies, never symlinks
garrytan Aug 16, 2026
52006fe
fix(setup): Windows re-runs refresh installed skills for codex/factor…
garrytan Aug 16, 2026
c842468
fix(uninstall): remove real-directory skill installs, gated on proven…
garrytan Aug 16, 2026
2be9bd0
feat(setup): wire --host cursor through the full install path
garrytan Aug 16, 2026
1dbed2c
fix(settings): include command in add-event dedup key (#2382)
gregario Aug 1, 2026
9af589b
fix(setup): render the gbrain :user variant to an out-dir — global in…
garrytan Aug 16, 2026
9c0de5f
fix(redact): close the remaining #1946 fail-opens — detection coverag…
garrytan Aug 16, 2026
4d0e7b7
feat(hooks): Stop hook closes dangling timeline entries — fail-open
garrytan Aug 16, 2026
ecfd9af
ios-qa: guard DebugBridgeTouch.m on DEBUG, not just TARGET_OS_IOS
Bastea Aug 15, 2026
e20c29f
fix(ios-qa): bridges search front-most presented content first
garrytan Aug 16, 2026
d889453
fix(setup-gbrain): invoke gstack-memory-ingest/gstack-gbrain-sync via…
garrytan Aug 16, 2026
5b65f91
fix(test): update four main-side assertions to the T3 installer contr…
garrytan Aug 16, 2026
f9f3c98
fix: whitelist engine-locked at all three gbrain-usable gates (#2456)
garrytan Aug 16, 2026
ce4a7bb
fix: detect bearer-token thin clients via host MCP registration (#2520)
garrytan Aug 16, 2026
5854d12
fix: resolve GBRAIN_HOME with gbrain's parent-dir semantics (#2521)
garrytan Aug 16, 2026
acc354f
fix: read project-scoped MCP registrations in gbrain detection (#2499)
garrytan Aug 16, 2026
bfa579d
fix: /sync-gbrain respects an existing valid .gbrain-source pin (#2417)
garrytan Aug 16, 2026
c7faef8
fix: gstack-gbrain-install --dry-run no longer requires the network (…
garrytan Aug 16, 2026
d7ab20a
feat: accept 3-digit semver + package.json version sources (#2501)
garrytan Aug 16, 2026
c33b371
fix: write/repair sync npm lockfiles' version fields (#2567)
garrytan Aug 16, 2026
7b5fdab
feat: subdirectory manifests + npm-valid version mirror (#2531)
garrytan Aug 16, 2026
da0e28e
feat: git-based version allocator when the PR queue is unreachable (#…
garrytan Aug 16, 2026
909a9e9
fix: version-bump honors the .gstack/version-path pin in versionRel (…
garrytan Aug 16, 2026
73cf0ed
fix: diff-scope glob coverage, honest exit contract, dirty-tree visib…
garrytan Aug 16, 2026
4e055ca
fix(redact-prepush): don't re-scan commits a catch-up merge brought in
garrytan Aug 16, 2026
4cc19e4
fix(redact): parcel IDs are not phone numbers
garrytan Aug 16, 2026
45fd8e2
test: prove the rebased force-push shape is scanned correctly (#2573)
garrytan Aug 16, 2026
ca8ee4b
fix(test): ratchet four skeleton-size caps for the wave's preamble gr…
garrytan Aug 16, 2026
3c04178
docs(todos): file the v1.67 fix-wave deferrals + ZeroEntropy sunset d…
garrytan Aug 16, 2026
2851535
deps(browse): bump playwright + playwright-core to 1.62.1 (P0 #2554 v…
garrytan Aug 16, 2026
822de7d
fix(browse): XProtect launch-kill self-heal — classify, quarantine-cl…
garrytan Aug 16, 2026
25ccda9
fix(browse): daemon owns signal policy — handleSIG*:false at launch s…
garrytan Aug 16, 2026
b3a2717
fix(browse): absorb #2414 residuals — EPERM-alive liveness + Windows-…
garrytan Aug 16, 2026
7171f10
fix(browse): isProcessAlive uses signal-0 on every platform — no more…
garrytan Aug 16, 2026
7686eb2
fix(browse): windowsHide sweep — flag every residual child_process si…
garrytan Aug 16, 2026
e2f70f1
fix(browse): fail-fast busy-daemon semantics — never auto-kill an ali…
garrytan Aug 16, 2026
5a6dd6b
fix(browse): `stop` on a dead daemon is success — never boots a daemo…
garrytan Aug 16, 2026
908c5a6
fix(upgrade): /gstack-upgrade stops a stale daemon — deferring to a b…
garrytan Aug 16, 2026
0d4d554
fix(browse): terminal-agent allocates from the fixed port scan range,…
garrytan Aug 16, 2026
c4e2233
fix(browse): capture daemon stdout/stderr to browse-daemon.log + Wind…
garrytan Aug 16, 2026
af23375
fix: raise gbrain version-probe timeout to 10s on Windows
vaston-viji Aug 4, 2026
f4e84b4
fix(browse): remove the dead security shield + unfed /health.security…
garrytan Aug 16, 2026
be66d4f
fix(browse): capture browser-skill subprocess output via temp files, …
garrytan Aug 16, 2026
0cbaead
feat(browse): allow Emulation.setEmulatedMedia on the CDP allowlist (…
garrytan Aug 16, 2026
994b5f5
fix(browse): create node bundle output directory
ming1523 Aug 13, 2026
436adb7
fix(deps): bun-patch playwright-core 1.62.1 — windowsHide at launch +…
garrytan Aug 16, 2026
95b66b5
fix(preamble): probe AGENTS.md for skill routing; team-init resolves …
garrytan Aug 16, 2026
08bff7e
fix(resolvers): empty find must not fall through to cwd (#2483)
garrytan Aug 16, 2026
a9ca914
fix(codex): retire deprecated web-search flag behind one CODEX_WEB_SE…
garrytan Aug 16, 2026
96c22cb
fix(question-tuning): interpolate the absolute question-registry path…
garrytan Aug 16, 2026
a8d9cf9
fix(resolvers): slug-canonical branch form in file-path positions (#2…
garrytan Aug 16, 2026
63e2b7a
fix(ship): review fix loop stays in one invocation, bounded at 3 cycl…
garrytan Aug 16, 2026
73c96f9
feat(codex): model round-trip probe — an unusable configured model fa…
garrytan Aug 16, 2026
ae47c29
fix(review): skip nested codex spawns when already running under a Co…
garrytan Aug 16, 2026
504409d
fix(build): convert MSYS paths for Bun in the Windows server-bundle b…
garrytan Aug 16, 2026
0f6e471
fix(test): update four main-side gen-skill-docs assertions to the T6 …
garrytan Aug 16, 2026
87c2583
fix(sync-gbrain): dream pack-capability WARN anchors to the graph phase
garrytan Aug 16, 2026
f0f2838
fix(setup): install office-hours into the external-host runtime roots
garrytan Aug 16, 2026
e5610e4
fix(gbrain-install): name the real fix when an npm-installed bun brea…
garrytan Aug 16, 2026
f8eecd4
docs(ios-qa): document the bridge compatibility preflight and non-Swi…
garrytan Aug 16, 2026
74ddc7a
fix(deps): force adm-zip past CVE-2026-39244 via an override
garrytan Aug 16, 2026
8abf7cf
deps: remove unused puppeteer-core; bump transformers/marked/socks
garrytan Aug 16, 2026
a19cdd6
chore(deps): bump the github-actions group across 1 directory with 10…
dependabot[bot] Aug 16, 2026
4da5be2
fix(test): scope rendered-output tripwires to repo sources; stop cdp-…
garrytan Aug 16, 2026
fb66780
fix(test): honest budget for the suite's one headed persistent-contex…
garrytan Aug 16, 2026
a2c1dff
fix(test): assemble redact fixtures at runtime — the guard caught its…
garrytan Aug 16, 2026
54ca64b
fix(test): sync ios-qa fixture mirrors with the #2585 DEBUG-guard tem…
garrytan Aug 16, 2026
5af4a03
fix(slug): env-override runs never persist to the cwd cache; cache is…
garrytan Aug 16, 2026
bd0cdbb
fix(test): pin GSTACK_HOME in the slug walk-up cache tests
garrytan Aug 16, 2026
415a866
fix(test): the cache-hygiene test strips ambient GSTACK_PROJECT_SLUG
garrytan Aug 16, 2026
820b3cc
Merge remote-tracking branch 'origin/main' into garrytan/fix-wave-iss…
garrytan Aug 16, 2026
8a4f4dc
fix(test): ratchet ship's skeleton cap for the v1.66.1 merge union
garrytan Aug 16, 2026
4bc5b4c
fix(brain-sync): throttle + bound the detector push; empty-queue fast…
garrytan Aug 16, 2026
65fd3e8
fix(version-bump): JSON version-paths get the npm translation; honest…
garrytan Aug 16, 2026
dcc6e9e
fix(extension): remove the orphaned security-banner block; repair two…
garrytan Aug 16, 2026
6bcd2dd
fix(brain-sync): detector pushes only when ALL unpushed commits are i…
garrytan Aug 16, 2026
e86dcd6
fix(version-bump): version-path and package-json-path pins cannot esc…
garrytan Aug 16, 2026
c10a973
fix(browse): port allocator range actually stays below the ephemeral …
garrytan Aug 16, 2026
998aeb8
fix(codex-probe): bash-native watchdog when no timeout binary exists;…
garrytan Aug 16, 2026
6430197
fix(browse): xprotect heal resolves the install root via os.homedir a…
garrytan Aug 16, 2026
f808782
fix(make-pdf): --strict and --confidential join BOOLEAN_FLAGS; the gu…
garrytan Aug 16, 2026
2f65558
docs(todos): file the v1.67 adversarial-review residuals + coverage-a…
garrytan Aug 16, 2026
160c73c
v1.67.0.0: version bump (MINOR — full-tracker fix wave, pre-approved)
garrytan Aug 16, 2026
e7c464e
docs(changelog): v1.67.0.0 release summary + itemized changes with co…
garrytan Aug 16, 2026
166ac2c
docs(todos): mark the 2026-08-14 tracker-audit waves shipped in v1.67…
garrytan Aug 16, 2026
4a95ce6
fix(uninstall): provenance-gate the shape-2 and cursor sweeps; docume…
garrytan Aug 16, 2026
412ad5c
fix(redact): env.kv stops flagging cacheKey-style names; prepush excl…
garrytan Aug 16, 2026
aa6c738
fix(browse): honest probe budget, bounded daemon log, single refusal …
garrytan Aug 16, 2026
45b7298
fix(hooks): timeline Stop hook reads a 256KB tail instead of the whol…
garrytan Aug 16, 2026
2f8638a
fix(setup): Windows runtime-asset copies prune nested gitignored buil…
garrytan Aug 16, 2026
68006e2
fix(upgrade): migrations see the real install dir; stash can no longe…
garrytan Aug 16, 2026
a5b6522
fix(browse): stop --force-restart kills the live daemon directly inst…
garrytan Aug 16, 2026
8c1192d
fix(hooks): timeline repair counts started vs completed per key inste…
garrytan Aug 16, 2026
77374d1
fix(setup): Windows refresh bypass no longer deletes a user's own ski…
garrytan Aug 16, 2026
594ecf8
fix(render): a failed brain-aware render can no longer vanish the ins…
garrytan Aug 16, 2026
084e2ed
test+docs: codex probe cache invalidation coverage, make-pdf --no-* s…
garrytan Aug 16, 2026
730327e
fix(test): package.json version check accepts the decision-11 npm tra…
garrytan Aug 16, 2026
8cc379b
docs: sync project documentation with the v1.67.0.0 fix wave
garrytan Aug 16, 2026
415beed
docs(browse): findAvailablePort comment matches the 49151 range cap
garrytan Aug 16, 2026
fe20340
fix(ci-image): the dependency layer carries patches/ — bun install ne…
garrytan Aug 16, 2026
49c1fed
fix(codex-probe): cache signature uses GNU-first stat with numeric va…
garrytan Aug 16, 2026
4c335c9
fix(test): first cross-platform run of the wave's tests — Linux tmp p…
garrytan Aug 16, 2026
85fbd00
fix(ci-image): stage patches/ into the narrow build context in all th…
garrytan Aug 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*.yaml text eol=lf
*.json text eol=lf
*.toml text eol=lf
*.txt text eol=lf

# Bash scripts must always use LF — CRLF in bash scripts produces bizarre
# "Bad interpreter" / "command not found" errors on Linux runners.
Expand Down
5 changes: 5 additions & 0 deletions .github/docker/Dockerfile.ci
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,12 @@ RUN for i in 1 2 3; do \
# resolution. Without bun.lock here, bun install resolved transitive deps
# differently in CI vs local (observed on v1.28.0.0: socks landed but
# smart-buffer + ip-address didn't make it into the cached node_modules).
# patches/ rides along: bun.lock's patchedDependencies (playwright-core
# windowsHide, v1.67) makes install fail without the patch files present —
# and the workflows' image-tag hash includes patches/** so editing a patch
# rebuilds this layer.
COPY package.json bun.lock /workspace/
COPY patches /workspace/patches
WORKDIR /workspace
RUN bun install --frozen-lockfile && rm -rf /tmp/*

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/actionlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
actionlint:
runs-on: ubicloud-standard-2
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
with:
persist-credentials: false
# Pull the prebuilt image instead of rhysd/actionlint@v1.7.11 (a Docker
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/ci-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,28 @@ jobs:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7

# Copy lockfile + package.json into Docker build context
- run: cp package.json bun.lock .github/docker/
- run: cp package.json bun.lock .github/docker/ && cp -R patches .github/docker/patches

# Same content-hash tag expression as evals.yml / evals-periodic.yml.
# This is the tag the eval matrix looks up first — without pushing it
# here, the weekly/main prebuild never warms the cache that matters.
- id: meta
run: echo "tag=ghcr.io/${{ github.repository }}/ci:${{ hashFiles('.github/docker/Dockerfile.ci', 'bun.lock') }}" >> "$GITHUB_OUTPUT"
run: echo "tag=ghcr.io/${{ github.repository }}/ci:${{ hashFiles('.github/docker/Dockerfile.ci', 'bun.lock', 'patches/**') }}" >> "$GITHUB_OUTPUT"

- uses: docker/login-action@v3
- uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

# Registry cache export needs a docker-container builder — the default
# `docker` driver hard-errors on cache-to.
- uses: docker/setup-buildx-action@v3
- uses: docker/setup-buildx-action@v4

- uses: docker/build-push-action@v6
- uses: docker/build-push-action@v7
with:
context: .github/docker
file: .github/docker/Dockerfile.ci
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/dependency-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ jobs:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4.9.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v4
- uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0
with:
fail-on-severity: high
fail-on-scopes: runtime, development
Expand Down
16 changes: 8 additions & 8 deletions .github/workflows/evals-periodic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ jobs:
outputs:
image-tag: ${{ steps.meta.outputs.tag }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7

- id: meta
# Keep in sync with evals.yml — key on Dockerfile + lockfile only
# (package.json's version field would bust the key on every ship).
run: echo "tag=${{ env.IMAGE }}:${{ hashFiles('.github/docker/Dockerfile.ci', 'bun.lock') }}" >> "$GITHUB_OUTPUT"
run: echo "tag=${{ env.IMAGE }}:${{ hashFiles('.github/docker/Dockerfile.ci', 'bun.lock', 'patches/**') }}" >> "$GITHUB_OUTPUT"

- uses: docker/login-action@v3
- uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
Expand All @@ -45,15 +45,15 @@ jobs:
fi

- if: steps.check.outputs.exists == 'false'
run: cp package.json bun.lock .github/docker/
run: cp package.json bun.lock .github/docker/ && cp -R patches .github/docker/patches

# Registry cache export needs a docker-container builder — the default
# `docker` driver hard-errors on cache-to.
- if: steps.check.outputs.exists == 'false'
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v4

- if: steps.check.outputs.exists == 'false'
uses: docker/build-push-action@v6
uses: docker/build-push-action@v7
with:
context: .github/docker
file: .github/docker/Dockerfile.ci
Expand Down Expand Up @@ -103,7 +103,7 @@ jobs:
- name: e2e-gemini
file: test/gemini-e2e.test.ts
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
with:
fetch-depth: 0

Expand Down Expand Up @@ -141,7 +141,7 @@ jobs:

- name: Upload eval results
if: always()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: eval-periodic-${{ matrix.suite.name }}
path: ~/.gstack-dev/evals/*.json
Expand Down
20 changes: 10 additions & 10 deletions .github/workflows/evals.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,17 @@ jobs:
outputs:
image-tag: ${{ steps.meta.outputs.tag }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7

- id: meta
# Key on Dockerfile + lockfile only. package.json is deliberately NOT
# hashed: its version field changes on every ship (60/60 recent commits),
# which rebuilt the image each time for a dependency set that only
# bun.lock determines. A stale baked package.json is harmless — checkout
# overwrites /workspace and node_modules comes from the lockfile.
run: echo "tag=${{ env.IMAGE }}:${{ hashFiles('.github/docker/Dockerfile.ci', 'bun.lock') }}" >> "$GITHUB_OUTPUT"
run: echo "tag=${{ env.IMAGE }}:${{ hashFiles('.github/docker/Dockerfile.ci', 'bun.lock', 'patches/**') }}" >> "$GITHUB_OUTPUT"

- uses: docker/login-action@v3
- uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
Expand All @@ -54,7 +54,7 @@ jobs:
fi
- if: steps.check.outputs.exists == 'false'
run: cp package.json bun.lock .github/docker/
run: cp package.json bun.lock .github/docker/ && cp -R patches .github/docker/patches

# A fork PR's GITHUB_TOKEN only has `packages: read`, so pushing fails.
# Still BUILD (validates Dockerfile.ci changes), just don't publish. This
Expand All @@ -63,10 +63,10 @@ jobs:
# Registry cache export needs a docker-container builder — the default
# `docker` driver hard-errors on cache-to (first live run of the trio).
- if: steps.check.outputs.exists == 'false'
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v4

- if: steps.check.outputs.exists == 'false'
uses: docker/build-push-action@v6
uses: docker/build-push-action@v7
with:
context: .github/docker
file: .github/docker/Dockerfile.ci
Expand Down Expand Up @@ -158,7 +158,7 @@ jobs:
# row keeps --retry 1.
retries: 2
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
with:
fetch-depth: 0

Expand Down Expand Up @@ -320,7 +320,7 @@ jobs:

- name: Upload eval results
if: always()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: eval-${{ matrix.suite.name }}
path: ~/.gstack-dev/evals/*.json
Expand All @@ -341,12 +341,12 @@ jobs:
# early and never hit it, which is why this stayed hidden). See #1802 CI fix.
issues: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
with:
fetch-depth: 1

- name: Download all eval artifacts
uses: actions/download-artifact@v4
uses: actions/download-artifact@v8
with:
pattern: eval-*
path: /tmp/eval-results
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/free-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,15 @@ jobs:
runs-on: ubicloud-standard-8
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
with:
persist-credentials: false

- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.13

- uses: actions/cache@v4
- uses: actions/cache@v6
with:
path: ~/.bun/install/cache
key: linux-bun-${{ hashFiles('bun.lock') }}
Expand All @@ -67,7 +67,7 @@ jobs:
- name: Install dependencies
run: bun install --frozen-lockfile

- uses: actions/cache@v4
- uses: actions/cache@v6
with:
path: ~/.cache/ms-playwright
key: linux-playwright-${{ hashFiles('bun.lock') }}
Expand Down Expand Up @@ -118,7 +118,7 @@ jobs:
# need a local re-run, which fork contributors can't do on this image.
- name: Upload shard logs on failure
if: failure()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: free-test-shard-logs
path: /tmp/gstack-free-test-*.log
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/make-pdf-gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:

runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7

- uses: oven-sh/setup-bun@v2
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/osv-scanner.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
actions: read
contents: read
security-events: write
uses: google/osv-scanner-action/.github/workflows/osv-scanner-reusable.yml@3adb4b14a2b0623876d18d863a498b785fb3752d # v2.3.8
uses: google/osv-scanner-action/.github/workflows/osv-scanner-reusable.yml@f4cfcc01edc9c8b756a9b873b7a623ca674da51e # v2.3.8
with:
scan-args: |-
--include-git-root
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pr-title-sync.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:
steps:
# Base repo only — trusted infra (the rewrite helper). No PR-head checkout.
- name: Checkout base repo (trusted)
uses: actions/checkout@v4
uses: actions/checkout@v7
with:
fetch-depth: 1

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/quality-gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
runs-on: ubicloud-standard-8
timeout-minutes: 20
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v4
with:
fetch-depth: 0
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/skill-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
check-freshness:
runs-on: ubicloud-standard-2
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
- uses: oven-sh/setup-bun@v2
- run: bun install
# One generation pass for ALL 10 hosts. gen-skill-docs --host all
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/version-gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
pull-requests: read
steps:
- name: Checkout PR head
uses: actions/checkout@v4
uses: actions/checkout@v7
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}
Expand Down
11 changes: 7 additions & 4 deletions .github/workflows/windows-free-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,16 @@ jobs:
timeout-minutes: 15

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7

- uses: oven-sh/setup-bun@v1
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.13

# bun install was 35s of a 55s job, all network. Cache keyed on the
# lockfile; bun's install cache lives under ~/.bun/install/cache on
# every platform.
- uses: actions/cache@v4
- uses: actions/cache@v6
with:
path: ~/.bun/install/cache
key: windows-bun-${{ hashFiles('bun.lock') }}
Expand Down Expand Up @@ -119,9 +119,12 @@ jobs:

# Same diagnosability contract as free-tests.yml: a red lane must
# carry the WHY (the runner's quiet console names files, not causes).
# (#2561 was written against the old hand-listed subset; its two new
# test files are pure-TS and flow into the --windows-only curation
# automatically, so no per-file entry is needed here.)
- name: Upload shard logs on failure
if: failure()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: windows-free-test-shard-logs
path: ${{ runner.temp }}/gstack-free-test-*.log
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/windows-setup-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,15 @@ jobs:
timeout-minutes: 15

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7

- uses: oven-sh/setup-bun@v1
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.13

# Same lockfile-keyed install cache as windows-free-tests.yml (install
# was 45s of a 64s job, all network).
- uses: actions/cache@v4
- uses: actions/cache@v6
with:
path: ~/.bun/install/cache
key: windows-bun-${{ hashFiles('bun.lock') }}
Expand Down
16 changes: 8 additions & 8 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,11 @@ The server writes `.gstack/browse.json` (atomic write via tmp + rename, mode 0o6
{ "pid": 12345, "port": 34567, "token": "uuid-v4", "startedAt": "...", "binaryVersion": "abc123" }
```

The CLI reads this file to find the server. If the file is missing or the server fails an HTTP health check, the CLI spawns a new server. On Windows, PID-based process detection is unreliable in Bun binaries, so the health check (GET /health) is the primary liveness signal on all platforms.
The CLI reads this file to find the server. If the file is missing or the daemon process is dead, the CLI spawns a new server. A process that is alive but not answering `/health` is busy, not dead: the CLI probes for a bounded ~8s, then reports busy with a nonzero exit — only an explicit `--force-restart` kills a live daemon. Process liveness uses signal-0 (`isProcessAlive`, EPERM counts as alive) on every platform, with the health check (GET /health) as the responsiveness signal. Daemon stdout/stderr persists to `<project>/.gstack/browse-daemon.log`.

### Port selection

Random port between 10000-60000 (retry up to 5 on collision). This means 10 Conductor workspaces can each run their own browse daemon with zero configuration and zero port conflicts. The old approach (scanning 9400-9409) broke constantly in multi-workspace setups.
Random port between 10000-49151 (retry up to 5 on collision), allocated through the shared `browse/src/port-allocator.ts` so every long-lived gstack listener draws from the same range. The range ends at 49151 on purpose: 49152-65535 is the macOS ephemeral pool, and allocating inside it meant the OS could hand the same port to another process moments later. This means 10 Conductor workspaces can each run their own browse daemon with zero configuration and zero port conflicts. The old approach (scanning 9400-9409) broke constantly in multi-workspace setups.

### Version auto-restart

Expand Down Expand Up @@ -176,19 +176,19 @@ The Chrome sidebar agent has tools (Bash, Read, Glob, Grep, WebFetch) and reads

1. **L1-L3 content security (`browse/src/content-security.ts`).** Runs on every page-content command and every tool output: datamarking, hidden-element strip, ARIA regex, URL blocklist, and a trust-boundary envelope wrapper. Applied at both the server and the agent.

2. **L4 ML classifier — TestSavantAI (`browse/src/security-classifier.ts`).** A 22MB BERT-small ONNX model (int8 quantized) bundled with the agent. Runs locally, no network. Scans every user message and every Read/Glob/Grep/WebFetch tool output before Claude sees it. Opt-in 721MB DeBERTa-v3 ensemble via `GSTACK_SECURITY_ENSEMBLE=deberta`.
2. **L4 ML classifier — TestSavantAI (`browse/src/security-classifier.ts`).** A 22MB BERT-small ONNX model (int8 quantized) running in the security sidecar subprocess. Runs locally, no network. Scans page-derived content on the inject-scan path before the agent sees it.

3. **L4b transcript classifier.** A Claude Haiku pass that looks at the full conversation shape (user message, tool calls, tool output), not just text. Gated by `LOG_ONLY: 0.40` so most clean traffic skips the paid call.
3. **L4b transcript classifier (removed).** A Claude Haiku conversation-shape pass existed until the chat-path agent that invoked it was ripped; it was deleted as dead code (zero production callers), along with the opt-in DeBERTa ensemble. Do not re-document either as live.

4. **L5 canary token (`browse/src/security.ts`).** A random token injected into the system prompt at session start. Rolling-buffer detection across `text_delta` and `input_json_delta` streams catches the token if it shows up anywhere in Claude's output, tool arguments, URLs, or file writes. Deterministic BLOCK — if the token leaks, the attacker convinced Claude to reveal the system prompt, and the session ends.
4. **L5 canary token (`browse/src/security.ts`).** Generate/inject/detect utilities for a random system-prompt token whose leak means the attacker convinced the model to reveal the system prompt. Canary leak BLOCKs deterministically. The utilities are pure and tested; the chat prompt-builder that injected the canary was ripped, so no production path injects it today.

5. **L6 ensemble combiner (`combineVerdict`).** BLOCK requires agreement from two ML classifiers at >= `WARN` (0.75), not a single confident hit. This is the Stack Overflow instruction-writing false-positive mitigation. On tool-output scans, single-layer high confidence BLOCKs directly — the content wasn't user-authored, so the FP concern doesn't apply.

**Critical constraint:** `security-classifier.ts` runs only in the sidebar-agent process, never in the compiled browse binary. `@huggingface/transformers` v4 requires `onnxruntime-node`, which fails `dlopen` from Bun compile's temp extract directory. Only the pure-string pieces (canary inject/check, verdict combiner, attack log, status) are in `security.ts`, which is safe to import from `server.ts`.
**Critical constraint:** `security-classifier.ts` runs only in the security sidecar subprocess (`security-sidecar-entry.ts`), never in the compiled browse binary. `@huggingface/transformers` v4 requires `onnxruntime-node`, which fails `dlopen` from Bun compile's temp extract directory. Only the pure-string pieces (canary inject/check, verdict combiner) are in `security.ts`, which is safe to import from `server.ts`. (The attack log lives in `tunnel-denial-log.ts`; the session-state/status surface was removed in #2557.)

**Env knobs:** `GSTACK_SECURITY_OFF=1` is a real kill switch (skips ML scan, canary still injects). Model cache at `~/.gstack/models/testsavant-small/` (112MB, first run) and `~/.gstack/models/deberta-v3-injection/` (721MB, opt-in only). Attack log at `~/.gstack/security/attempts.jsonl` (salted sha256 + domain, rotates at 10MB, 5 generations). Per-device salt at `~/.gstack/security/device-salt` (0600), cached in-process to survive FS-unwritable environments.
**Env knobs:** `GSTACK_SECURITY_OFF=1` is a real kill switch (classifier stays off even if warmed; the L1-L3 filters keep running). Model cache at `~/.gstack/models/testsavant-small/` (112MB, first run). Attack log at `~/.gstack/security/attempts.jsonl` (salted sha256 + domain, rotates at 10MB, 5 generations). Per-device salt at `~/.gstack/security/device-salt` (0600), cached in-process to survive FS-unwritable environments.

**Visibility.** The sidebar header shows a shield icon (green/amber/red) polled via `/sidebar-chat`. A centered banner appears on canary leak or BLOCK verdict with the exact layer scores. `bin/gstack-security-dashboard` aggregates local attempts; `supabase/functions/community-pulse` aggregates opt-in community telemetry across users.
**Visibility.** A centered banner appears on canary leak or BLOCK verdict with the exact layer scores. `bin/gstack-security-dashboard` aggregates local attempts; `supabase/functions/community-pulse` aggregates opt-in community telemetry across users. (The sidebar header's SEC shield icon and the `/health` `security` field were removed in #2557: their only data source — `~/.gstack/security/session-state.json` — lost its only writer when the chat-path agent was ripped, so the shield reported stale or empty state. The live defenses report through their own call sites.)

## The ref system

Expand Down
Loading
Loading