* fix(gsd): enforce backtick file paths in task plan IO sections
The reactive task graph (ADR-004) derives dependencies from backtick-wrapped
file paths in ## Inputs and ## Expected Output sections. Without concrete
paths, the graph is ambiguous and falls back to sequential execution.
Changes:
- task-plan.md template: add comments explaining paths are machine-parsed
- plan-slice.md prompt: explicitly instruct planner to write backtick file
paths in IO sections, add self-audit check for path presence
- observability-validator.ts: new validation rules missing_output_file_paths
(warning) and missing_input_file_paths (info) catch plans without paths
- plan-quality-validator.test.ts: 4 new test cases for IO path validation
* fix(ci): increase max_tokens and add JSON parse error handling in ai-triage
max_tokens: 300 was too low, causing truncated JSON responses from Claude
that failed to parse. Bumped to 1024 and added try/catch with raw text
logging for easier debugging.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
pull_request events from forks/branches cannot access repo secrets,
causing 401 auth failures on every PR triage. pull_request_target runs
in the base repo context. Safe because the workflow only reads event
payload data and sparse-checks base branch docs — no PR code executes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove the bundled SwiftUI skill which had 13+ broken references to a
non-existent `../macos-apps/references/` directory. Add a CI script
that validates all relative .md file references in bundled skills,
preventing this class of bug from shipping again. Fix 5 additional
pre-existing broken references in other skills.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds a GitHub Actions workflow that automatically triages new issues and
PRs using Claude Haiku 4.5. Classifies with type and priority labels,
and flags items that violate VISION.md or CONTRIBUTING.md guidelines
with a `needs-review` label and explanatory comment. No auto-closing —
maintainer makes all final decisions.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
10 tests that run against the installed gsd binary after npm publish:
1. headless query returns valid JSON
2. Empty project → pre-planning phase
3. Milestone with roadmap → planning phase
4. All tasks done → summarizing phase
5. Complete milestone → complete phase
6. Stale auto.lock doesn't block --version
7. Crash recovery query works with stale lock
8. Non-TTY exits quickly with clean error
9. Version skew detected before TTY check
10. --help works (native addon loads or falls back)
Wired into pipeline.yml test-verify job after fixture tests
and before @next promotion.
These catch the state machine / infrastructure bugs from #1308
that unit tests can't reach — they exercise deriveState through
the real gsd binary with real .gsd/ directory structures.
Part of #1308
Two issues in the pipeline:
1. cancel-in-progress: true could cancel a running deployment when a
new push arrives. Deployments should never be interrupted mid-flight.
Changed back to false.
2. The prod-release job bumps the version, commits, and tags — but never
publishes the release version to npm. The dev-publish step publishes
@dev, test-verify promotes to @next, but @latest was never updated.
Users running 'npm install -g gsd-pi' would get stale versions.
Added 'Build release' and 'Publish release to npm @latest' steps after
the git tag push, with idempotent guard for already-published versions.
When the prod environment gate is approved, the pipeline now automatically
determines the semver bump from conventional commits, generates a changelog
entry, bumps all package versions, commits + tags + pushes (triggering
build-native.yml for npm @latest), creates a GitHub Release, and posts
to Discord.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dev-stamped versions (2.28.0-dev.xxx) should never be promoted to
@latest on npm. Stable releases are handled by the publish-version
workflow. The pipeline promotes @dev → @next only.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Multiple pipeline runs for the same base version produce identical
release tags, causing E422. Check if release exists before creating.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Multiple CI completions on the same commit trigger duplicate Pipeline
runs. The second run fails with E403 because the version was already
published. Fix by checking npm registry before attempting publish, and
enable cancel-in-progress to avoid redundant runs.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The local smoke test runs npx gsd-pi which fails in the container
because the gsd bin isn't on PATH. Point GSD_SMOKE_BINARY at the
built dist/loader.js directly with an absolute path so smoke tests
work from any cwd.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add pre-commit secret scanner and CI secret detection
Add a comprehensive secret scanning system to prevent accidental
credential leaks in commits and pull requests:
- scripts/secret-scan.sh: ERE-based scanner (macOS/Linux compatible)
that detects AWS keys, API tokens, private keys, database URLs,
GitHub/GitLab/Slack/Stripe/Google/npm tokens, and hardcoded passwords
- scripts/install-hooks.sh: one-command git pre-commit hook installer
- .secretscanignore: allowlist for known false positives (test fixtures,
env var references, placeholder values)
- CI job: secret-scan step in ci.yml scans PR diffs against origin/main
- npm scripts: test:secret-scan, secret-scan, secret-scan:install-hook
- 17 tests covering detection, non-detection, binary skipping, CI mode
* fix: exclude secret-scan test file from CI scanning
The test file contains intentional fake secrets as test inputs.
Add it to .secretscanignore so CI doesn't flag them.
* fix: skip secret-scan tests on Windows (requires bash/POSIX grep)
Two bugs in the Dev Publish job:
1. node -p with escaped double-quotes broke on Node 22's eval mode
(SyntaxError: Invalid or unexpected token). Switched to node -e
with process.stdout.write and unescaped inner quotes.
2. version-stamp updated root package.json but not platform packages.
When npm publish triggered prepublishOnly, sync-platform-versions
dirtied 5 platform package.json files and git diff --exit-code
failed. Added sync-platform-versions to the stamp step so
prepublishOnly finds everything already in sync.
Fixes: https://github.com/gsd-build/gsd-2/actions/runs/23233857718
* feat(S01/T01): Scaffolded the `studio` Electron workspace with a workin…
- package.json
- studio/package.json
- studio/electron.vite.config.ts
- studio/src/main/index.ts
- studio/src/preload/index.ts
- studio/src/renderer/src/styles/index.css
- studio/src/renderer/src/App.tsx
* chore: init gsd
* fix(ci): add safe.directory for containerized pipeline job
The Dev Publish job runs inside a Docker container where the checkout
user differs from the container user (root), causing git's dubious
ownership check to reject git operations in version-stamp.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(ci): remove .gsd/.gitignore from tracking
The no-gsd-dir CI check fails when .gsd/ exists as a directory, even
if only .gitignore is tracked inside it.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(ci): add version stamp script for dev publishes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(ci): add CLI smoke tests for pipeline test stage
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(ci): add FixtureProvider for LLM conversation recording and replay
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(ci): add fixture test runner and sample recordings
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(ci): add live test stubs and pipeline npm scripts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(ci): add three-stage promotion pipeline workflow
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(ci): add weekly cleanup workflow for stale dev versions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(ci): add fixture recording helper stub
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fixes#882 — npm install -g gsd-pi installing a broken version where
@gsd/pi-coding-agent cannot be resolved, causing ERR_MODULE_NOT_FOUND.
Root causes addressed:
1. On Windows without Developer Mode or admin rights, symlinkSync fails
even for NTFS junctions, leaving node_modules/@gsd/ empty and causing
a cryptic ERR_MODULE_NOT_FOUND instead of a usable error message.
2. If npm latest dist-tag is stale (pointing to an old version that
predates the packages/ directory), users get the same failure.
Changes:
- src/loader.ts: after symlinking, validate @gsd/pi-coding-agent exists;
emit a clear actionable error with reinstall instructions instead of
letting Node throw ERR_MODULE_NOT_FOUND deep inside cli.js. Also adds
cpSync fallback when symlinkSync fails (Windows without elevated perms).
- scripts/link-workspace-packages.cjs: same cpSync fallback — ensures
postinstall succeeds on restricted Windows environments.
- scripts/validate-pack.js: verify @gsd/* packages are resolvable after
the isolated install test, and run `gsd -v` to confirm end-to-end
resolution before declaring the pack valid.
- .github/workflows/build-native.yml: add post-publish dist-tag
verification step that confirms npm dist-tags.latest matches the
published version for stable releases, catching stale-tag regressions
in CI before users encounter them.
* ci: add extension type-checking to CI pipeline and prepublishOnly
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: resolve remaining extension type errors after merge
- Use cred.type === "api_key" for proper union narrowing in loadToolApiKeys
- Fix optional level parameter in provider-error-pause test
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Detect prerelease versions (containing -next.) and publish npm packages
with --tag next instead of --tag latest, keeping stable users unaffected.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The --version flag outputs a banner with ANSI escape codes. The smoke
test compared the entire multi-line output against the bare version
string, causing false failures on every release.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: remove @gsd/* cross-deps that break npm install (#hotfix)
Workspace packages declared @gsd/* as dependencies in their own
package.json files. npm's bundleDependencies bundles packages into
node_modules/ but still tries to resolve sub-dependencies from the
registry — causing 404s for the unpublished @gsd/* scope.
- Remove @gsd/* from all dependencies (root and workspace packages)
- Add validate-pack.sh: tests tarball installability before publish
- Wire validate-pack into CI (every PR) and publish pipeline
- Bump to v2.10.10
- Update changelog
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: drop bundleDependencies, use postinstall symlinks instead
bundleDependencies with workspace packages causes npm to resolve
@gsd/* from the registry during install — 404 since they're not
published. Replace with a postinstall script that creates
node_modules/@gsd/* symlinks pointing to packages/*.
- Remove @gsd/* from dependencies and bundleDependencies
- Add link-workspace-packages.cjs (CJS, runs before ESM postinstall)
- Update validate-pack to verify symlinks after install
- Include link script in files array
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: robust validate-pack + fallback workspace linking
- Keep @gsd/* in bundleDependencies (for npm pack bundling)
- Remove @gsd/* from root dependencies (prevents 404 registry lookups)
- Add link-workspace-packages.cjs fallback for when bundled symlinks
aren't created
- Simplified validate-pack with better error diagnostics
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: remove bundleDependencies — use postinstall symlinks only
npm 10.x fetches packument metadata for ALL deps including bundled ones.
@gsd/* packages don't exist on npm → 404 → hard install failure.
bundleDependencies is fundamentally broken for unpublished workspace
packages. Replace with:
- packages/ shipped via files array (already was)
- link-workspace-packages.cjs creates node_modules/@gsd/* symlinks in
postinstall, pointing to packages/*
- No @gsd/* in dependencies or bundleDependencies at all
Tarball drops from 40M to 3M (no bundled node_modules).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add .npmignore to prevent .gitignore from excluding dist/
.gitignore contains /dist/ and packages/*/dist/ which are needed in
the published tarball. Without .npmignore, npm pack respects .gitignore
and excludes them — even though "files" in package.json should override.
An empty .npmignore causes npm to ignore .gitignore entirely, letting
the "files" field control what's packed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: avoid SIGPIPE in validate-pack on Linux
tar | grep -q causes SIGPIPE (exit 141) on Linux when grep closes the
pipe early. Write tar listing to a temp file and grep that instead.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs: update changelog for v2.10.9
* 2.10.9
* fix(ci): retry smoke test with backoff for npm propagation delay
The post-publish smoke test was failing because npm registry propagation
can take 30-90s. Replaced the fixed 15s sleep with a retry loop (5
attempts, 30s backoff).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: suppress git credential prompts that freeze TUI (#280)
Set GIT_TERMINAL_PROMPT=0 and GIT_ASKPASS="" on all git subprocess calls
so git fails immediately instead of prompting for credentials when tokens
expire, which deadlocks the TUI's stdin.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ci: add CI workflow and fix publish to prevent broken releases
Add ci.yml that runs build + test + smoke test on every push/PR to main.
Fix build-native.yml publish job to explicitly build before publishing,
verify dist/loader.js exists, check tarball contents, and smoke test the
published package.
Closes#293
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add GitHub Workflows skill with CI workflow and ci_monitor tool
- Runs on push to main and feature branches
- Runs on pull requests to main
- Build + test pipeline using Node 22
Cross-platform CI monitoring tool for debugging GitHub Actions:
- `runs` - List recent workflow runs
- `watch` - Monitor running workflow
- `fail-fast` - Exit 1 on first failure (for scripts)
- `log-failed` - Show failed job logs
- `test-summary` - Extract test pass/fail counts
- `check-actions` - GraphQL query for action versions
- `grep` - Search logs with context
- `wait-for` - Block until deployment keyword appears
Pure Node.js - no shell interpolation, works on macOS/Windows/Linux.
Drift-immune skill that:
- Routes all CI operations through ci_monitor.cjs
- Fetches live docs from docs.github.com (no stale training data)
- Provides validation constraints (BEFORE/AFTER/EVIDENCE)
- Split tests into test:unit (141 tests, ~12s) and test:integration (5 tests)
- Fixed idle-recovery.test.ts for current implementation
- Removed AGENTS.md dead code from resource-loader.ts
- Moved npm run build out of tests (fixes ENOBUFS)
When CI fails, you need observable diagnostics:
- `gh run` output is not script-friendly
- ci_monitor.cjs provides structured output for automation
- The skill ensures AI uses the tool, not stale training data
* fix: resolve imports and path for current upstream version
- Updated imports from @mariozechner/pi-coding-agent to @gsd/pi-coding-agent
- Fixed integration test path calculation to use process.cwd()
- Kept test:unit and test:integration scripts
* fix: replace search provider preference instead of accumulating
AuthStorage.set() for api_key credentials appends to the existing list
rather than replacing. When setSearchProviderPreference was called twice
with different values, the second call appended the new value, leaving
the first value at index 0, which get() returned.
Fix: call auth.remove() before auth.set() to ensure only the latest
preference is stored.
https://claude.ai/code/session_01Qx7HRSDb117KzDZzdKk1KB
* fix: address all 10 open PR review comments
- package.json: run build before test:integration so a fresh checkout works
- pack-install.test.ts: replace execSync+shell redirects with execFileSync
argument arrays (portable, no shell parsing, paths with spaces safe)
- ci_monitor.test.ts: remove unconditional passed++ after assert; move
success message after the failed > 0 check so it only prints on success
- setup_gh.cjs: replace unzip/tar shell-outs with platform-specific
execFileSync calls (unzip on macOS, PowerShell Expand-Archive on Windows);
add compareVersions() for correct element-by-element semver comparison
- ci_monitor.cjs: add --repo/-R global option so repo is overrideable;
fix getLogs() to use gh run view --log --job instead of binary REST endpoint
https://claude.ai/code/session_01AT6CgcAB62kWcDsTJg9HZM
* fix: make all changed files fully cross-platform (Windows/macOS/Linux)
- pack-install.test.ts: use tar npm package instead of tar CLI; resolve
gsd binary as gsd.cmd on Windows; skip shebang check on Windows
- setup_gh.cjs: use execFileSync for all binary invocations; replace
which with where on Windows; add Windows PATH guidance; filter preferred
install dirs by platform; unify ZIP extraction to use process.platform
consistently; escape single quotes in PowerShell Expand-Archive args
- ci_monitor.cjs: use path.join for .github/workflows paths; replace
all split('\n') with split(/\r?\n/) to handle Windows CRLF output
https://claude.ai/code/session_01AT6CgcAB62kWcDsTJg9HZM
* refactor: simplify and deduplicate changed files
- ci_monitor.cjs: memoize getRepo() so gh repo view subprocess runs at
most once per invocation instead of once per command call in watch loops
- pack-install.test.ts: extract packTarball() helper to eliminate
duplicate npm pack logic across two tests; remove unused contents variable
https://claude.ai/code/session_01AT6CgcAB62kWcDsTJg9HZM
* refactor: remove redundant existsSync before canWrite() in findInstallDir
canWrite() already returns false for non-existent directories, so the
pre-check was a TOCTOU-style redundancy with no behavioral value.
https://claude.ai/code/session_01AT6CgcAB62kWcDsTJg9HZM
* fix: replace tar npm package with Node built-ins (zlib + manual tar parsing)
tar is not in the dependency tree. listTarEntries() decompresses via
createGunzip() and parses the 512-byte tar block format directly,
reading name/prefix/type/size fields per POSIX ustar spec. No external
dependency required. Also fixes the broken tarball variable reference
left over from the packTarball() refactor.
https://claude.ai/code/session_01AT6CgcAB62kWcDsTJg9HZM
* remove: drop setup_gh scripts in favour of ci_monitor
setup_gh.cjs and setup_gh.py were one-shot gh CLI installers.
ci_monitor.cjs covers the day-to-day CI use case and is the tool
the skill routes through. Environments that need gh installed can
use brew/winget/distro packages directly.
https://claude.ai/code/session_01AT6CgcAB62kWcDsTJg9HZM
* fix: run only unit tests in CI — integration tests cause ENOBUFS
The integration tests (npm pack → npm install → spawn node) exceed
the buffer limits of the CI runner environment. They are documented
as requiring a manual build+run step. CI now runs test:unit only.
https://claude.ai/code/session_01AT6CgcAB62kWcDsTJg9HZM
* fix: run all tests in CI without ENOBUFS
- ci.yml: run unit and integration as separate steps; build is already
its own step so test:integration doesn't need to rebuild
- package.json: remove npm run build from test:integration script
- pack-install.test.ts: npm install uses stdio:'ignore' to avoid
piping large output through Node buffers (root cause of ENOBUFS);
add early dist/ check with clear error message instead of rebuilding
https://claude.ai/code/session_01AT6CgcAB62kWcDsTJg9HZM
* fix: resolve ENOBUFS and clean up setup_gh references
- pack-install.test.ts: derive tarball filename from package.json
instead of piping npm pack --json stdout; use stdio:ignore throughout
to avoid exhausting OS pipe buffers on CI runners
- SKILL.md: remove setup_gh install instructions; assume gh is
pre-installed via system package manager; point to ci_monitor.cjs
- github_project_setup.py: remove setup_gh.py reference from error message
https://claude.ai/code/session_01AT6CgcAB62kWcDsTJg9HZM
* fix: address Copilot review comments on pack-install.test.ts
- listTarEntries: collect chunks in array, Buffer.concat once on end
instead of O(n²) repeated concat in data handler
- listTarEntries: attach error handler to createReadStream so read
errors reject the Promise instead of crashing the process
- npm pack: use stdio:['ignore','ignore','pipe'] to preserve stderr
for diagnostics while still avoiding ENOBUFS on stdout
- npm install: same — pipe stderr so failures include error output
https://claude.ai/code/session_01AT6CgcAB62kWcDsTJg9HZM
---------
Co-authored-by: Claude <noreply@anthropic.com>
Prevents publishing gsd-pi to npm if any @gsd-build/engine-* optional
dependency is missing at the expected version. Avoids the failure mode
seen in 2.10.5 where the main package shipped before platform packages
were available, causing 'Cannot find module' errors on fresh installs.
macos-13 runners are deprecated on GitHub Actions. Use macos-14 (ARM64)
and cross-compile for x86_64-apple-darwin instead.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rename all platform packages from @gsd/engine-* to @gsd-build/engine-*
to match the npm org. Remove the darwin-arm64 binary from git and
native/addon from files — production binaries come exclusively from
CI-published platform packages.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Use CARGO_ENCODED_RUSTFLAGS="" to override target-specific rustflags
in .cargo/config.toml (RUSTFLAGS env var doesn't override [target.*])
- Fix sync script filename: .cjs not .js
- Fail hard when no library found instead of silent exit 0
- Only tolerate "already published" errors, fail on real publish errors
- Use --ignore-scripts for main package publish to skip redundant build
- Use cd "$GITHUB_WORKSPACE" instead of cd - for reliability
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add the esbuild/swc pattern for distributing platform-specific native
binaries via npm optional dependencies. Each supported platform gets its
own @gsd/engine-{platform} package containing just the .node binary.
- 5 platform package stubs (darwin-arm64, darwin-x64, linux-x64-gnu,
linux-arm64-gnu, win32-x64-msvc) with os/cpu filters
- Rewritten native loader: tries npm package first, then local build
- Version sync script keeps platform packages in lock-step with root
- GitHub Actions workflow for cross-platform build + publish on tag push
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>