chore: bump to v1.38.1.0

VERSION + package.json + CHANGELOG header + migration filename + test
reference all consistently at v1.38.1.0. Migration renamed:
gstack-upgrade/migrations/v1.38.0.0.sh -> v1.38.1.0.sh.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Garry Tan 2026-05-14 18:34:36 -07:00
parent 4cb406ca77
commit 66c8a55dbb
No known key found for this signature in database
GPG Key ID: C1F69E85C74EFE1D
5 changed files with 14 additions and 14 deletions

View File

@ -1,6 +1,6 @@
# Changelog
## [1.38.0.0] - 2026-05-14
## [1.38.1.0] - 2026-05-14
## **Page captures stop crashing on broken emoji bytes, every review skill ends with a build-actionable task checklist, federation sync no longer drops office-hours design docs.**
## **Three community-filed issues landed as one bug-fix wave: surrogate-safe browse responses (including `/batch`), per-skill Implementation Tasks with JSONL handoff to `/autoplan`, and root-level artifact patterns in `.brain-allowlist`.**
@ -9,7 +9,7 @@ Page captures from real-world HTML hit `API Error 400: no low surrogate in strin
All four review skills (CEO / design / eng / DX) now end with an `## Implementation Tasks` markdown checklist and write a `jq`-built JSONL artifact to `~/.gstack/projects/$SLUG/tasks-{phase}-{datetime}.jsonl`. `/autoplan`'s Phase 4 reads all four files, scopes by current branch + 5-commit window, dedupes on exact `(component, sorted(files), title)` matches, and renders one aggregated list inside the final approval gate. Tasks that derive from the same finding now collapse; tasks that just happen to touch the same file with different titles surface separately so the human can decide whether they're the same work. Standalone review runs (`/plan-eng-review` alone, etc.) produce their own task list and JSONL file even outside autoplan — the JSONL is the handoff contract.
Federation sync (`gstack-brain-sync`) was silently skipping root-level design and test-plan docs — `/office-hours` and `/plan-eng-review` write at `projects/{slug}/{user}-{branch}-design-*.md`, but the allowlist only knew about `projects/*/designs/*.md` and `projects/*/ceo-plans/*.md`. New patterns ship in `.brain-allowlist`, `.brain-privacy-map.json` (classified as `artifact`), and `.gitattributes` (with `merge=union` to handle cross-machine conflicts). An idempotent jq-based migration (`gstack-upgrade/migrations/v1.38.0.0.sh`) patches existing installs in-place without re-running `gstack-artifacts-init` (which would have done a git commit + push and clobbered user state).
Federation sync (`gstack-brain-sync`) was silently skipping root-level design and test-plan docs — `/office-hours` and `/plan-eng-review` write at `projects/{slug}/{user}-{branch}-design-*.md`, but the allowlist only knew about `projects/*/designs/*.md` and `projects/*/ceo-plans/*.md`. New patterns ship in `.brain-allowlist`, `.brain-privacy-map.json` (classified as `artifact`), and `.gitattributes` (with `merge=union` to handle cross-machine conflicts). An idempotent jq-based migration (`gstack-upgrade/migrations/v1.38.1.0.sh`) patches existing installs in-place without re-running `gstack-artifacts-init` (which would have done a git commit + push and clobbered user state).
### The numbers that matter
@ -42,7 +42,7 @@ Page captures with mixed-script Unicode round-trip cleanly to the Claude API now
- **`## Implementation Tasks` section + JSONL handoff in every review skill (#1454)** — `plan-ceo-review`, `plan-design-review`, `plan-eng-review`, `plan-devex-review` each emit a per-skill markdown checklist and write `~/.gstack/projects/$SLUG/tasks-{phase}-{datetime}.jsonl` via `jq -nc` (never hand-rolled echo). `/autoplan` Phase 4 reads all four phase JSONL files, scopes by current branch and 5-commit window, dedupes on exact `(component, sorted(files), title)` matches, and renders one aggregated list. Near-duplicates surface separately with a possible-duplicate note for human resolution.
- **`browse/src/sanitize.ts`** — two surrogate-stripping utilities plus a convenience selector keyed on content-type. Pairs with a refactored `buildCommandResponse` in `server.ts` (exported for testability) and per-result sanitization in the `/batch` handler.
- **`gstack-upgrade/migrations/v1.38.0.0.sh`** — idempotent per-file repair for `.brain-allowlist`, `.brain-privacy-map.json`, and `.gitattributes`. Uses `jq` for the JSON file (preserves validity); falls back with a clear warning if `jq` is missing. Does NOT re-run `gstack-artifacts-init` (which would commit + push to the user's federated repo).
- **`gstack-upgrade/migrations/v1.38.1.0.sh`** — idempotent per-file repair for `.brain-allowlist`, `.brain-privacy-map.json`, and `.gitattributes`. Uses `jq` for the JSON file (preserves validity); falls back with a clear warning if `jq` is missing. Does NOT re-run `gstack-artifacts-init` (which would commit + push to the user's federated repo).
- **32 new unit tests** across `browse/test/sanitize.test.ts` (18), `browse/test/build-command-response.test.ts` (7), `test/artifacts-init-migration.test.ts` (7). All gate-tier (free, runs on every PR).
#### Changed

View File

@ -1 +1 @@
1.38.0.0
1.38.1.0

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash
# Migration: v1.38.0.0 — add root-level design + test-plan patterns to
# Migration: v1.38.1.0 — add root-level design + test-plan patterns to
# .brain-allowlist, .brain-privacy-map.json, and .gitattributes (#1452).
#
# Why a migration: gstack-artifacts-init regenerates these files but also
@ -21,7 +21,7 @@ PRIVACY="${GSTACK_HOME}/.brain-privacy-map.json"
GITATTRS="${GSTACK_HOME}/.gitattributes"
MIGRATION_DIR="${GSTACK_HOME}/.migrations"
DONE="${MIGRATION_DIR}/v1.38.0.0.done"
DONE="${MIGRATION_DIR}/v1.38.1.0.done"
mkdir -p "${MIGRATION_DIR}" 2>/dev/null || true
if [ -f "${DONE}" ]; then
@ -67,12 +67,12 @@ if [ -f "${PRIVACY}" ]; then
added_any=1
else
rm -f "${PRIVACY}.tmp"
echo " [v1.38.0.0] WARN: jq failed to patch ${PRIVACY}; skipping pattern ${PATTERN}." >&2
echo " [v1.38.1.0] WARN: jq failed to patch ${PRIVACY}; skipping pattern ${PATTERN}." >&2
fi
fi
done
else
echo " [v1.38.0.0] WARN: jq not found; skipping privacy-map repair. Install jq and re-run gstack-upgrade, or run gstack-artifacts-init manually." >&2
echo " [v1.38.1.0] WARN: jq not found; skipping privacy-map repair. Install jq and re-run gstack-upgrade, or run gstack-artifacts-init manually." >&2
fi
fi
@ -92,7 +92,7 @@ fi
touch "${DONE}"
if [ "${added_any}" = "1" ]; then
echo " [v1.38.0.0] allowlist/privacy-map/gitattributes patched for root-level design + test-plan artifacts (idempotent)" >&2
echo " [v1.38.1.0] allowlist/privacy-map/gitattributes patched for root-level design + test-plan artifacts (idempotent)" >&2
fi
# NEVER `git commit + push` from this migration. The user controls when the

View File

@ -1,6 +1,6 @@
{
"name": "gstack",
"version": "1.38.0.0",
"version": "1.38.1.0",
"description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.",
"license": "MIT",
"type": "module",

View File

@ -1,4 +1,4 @@
// Unit tests for gstack-upgrade/migrations/v1.38.0.0.sh (#1452).
// Unit tests for gstack-upgrade/migrations/v1.38.1.0.sh (#1452).
// Verifies idempotent in-place repair of .brain-allowlist,
// .brain-privacy-map.json, and .gitattributes.
@ -8,7 +8,7 @@ import { tmpdir } from 'os';
import { join } from 'path';
const REPO_ROOT = new URL('..', import.meta.url).pathname;
const MIGRATION = join(REPO_ROOT, 'gstack-upgrade', 'migrations', 'v1.38.0.0.sh');
const MIGRATION = join(REPO_ROOT, 'gstack-upgrade', 'migrations', 'v1.38.1.0.sh');
function setupFakeHome(): string {
const dir = mkdtempSync(join(tmpdir(), 'mig-v1340-'));
@ -30,7 +30,7 @@ function runMigration(fakeHome: string): { code: number; stdout: string; stderr:
};
}
describe('v1.38.0.0 migration', () => {
describe('v1.38.1.0 migration', () => {
test('adds patterns to allowlist before USER ADDITIONS marker', () => {
const home = setupFakeHome();
try {
@ -166,7 +166,7 @@ describe('v1.38.0.0 migration', () => {
writeFileSync(join(home, '.gstack', '.brain-allowlist'), '# ---- USER ADDITIONS BELOW\n');
runMigration(home);
// Confirm marker file exists
expect(existsSync(join(home, '.gstack', '.migrations', 'v1.38.0.0.done'))).toBe(true);
expect(existsSync(join(home, '.gstack', '.migrations', 'v1.38.1.0.done'))).toBe(true);
// Modify allowlist so we can detect if the migration would re-run
writeFileSync(join(home, '.gstack', '.brain-allowlist'), '# minimal\n');