Two bugs were causing version drift across the repo:
1. Root package.json was silently reverted from 2.74.0 → 2.73.1 during
commit b03c9401c (a CI optimization rebase). Tag v2.74.0 is already
published on npm, so the next release would have computed 2.73.2 —
lower than what's already out — and shipped a broken version.
2. scripts/bump-version.mjs only touches pi-coding-agent + pkg + native
platform shims. Other workspace packages drift independently:
- @gsd-build/mcp-server: stuck at 2.52.0 (22 minor versions behind)
- @gsd-build/rpc-client: stuck at 2.52.0
- @gsd/pi-ai, pi-tui, pi-agent-core: stuck at 0.57.1
- @gsd/native, @gsd-build/daemon: stuck at 0.1.0
Changes:
- Bump all non-private workspace packages to 2.74.0 to match the latest
release tag. Update daemon + mcp-server's internal rpc-client dep
from ^2.52.0 → ^2.74.0. Regenerate root lockfile.
- scripts/generate-changelog.mjs: compute newVersion from max(latest
stable tag, package.json) instead of package.json alone. Prevents
version regressions when package.json is accidentally clobbered by
rebases or merges.
- scripts/bump-version.mjs: extend to sync all eight non-private
workspace packages (daemon, mcp-server, native, pi-agent-core, pi-ai,
pi-coding-agent, pi-tui, rpc-client) including their internal deps
on each other. Private packages (studio, web) are left alone.
Studio and web remain on their own versioning (private: true, never
published). The native platform shims under native/npm/* are still
synced via native/scripts/sync-platform-versions.cjs from the root
version as before.
Pure deletion/deduplication pass on top-level src/*.ts. External behavior
unchanged; all targeted unit tests still pass.
cli.ts (−170 net lines)
- Adopt canonical validateConfiguredModel from startup-model-validation.ts;
delete the drifted local copy with hardcoded model fallbacks.
- Import CliFlags + parseCliArgs from cli-web-branch.ts instead of keeping
a second, 90%-identical parser; pass cliFlags directly into
runWebCliBranch instead of re-parsing process.argv.
- Extract 3 helpers for verbatim duplicates:
* printNonTtyErrorAndExit (TTY gate, 2 call sites)
* printExtensionErrors (extension load errors, 2 call sites)
* reapplyValidatedModelOnFallback (post-createAgentSession fix, 2 sites)
- Factor runHeadlessFromAuto helper shared by the `gsd auto` shorthand
and the auto-piped-stdout redirect.
- Collapse ensureRtkBootstrap from hand-rolled _done flag to a
promise-memoized doRtkBootstrap.
- Drop redundant validateConfiguredModel pre-createAgentSession calls
(the post-createAgentSession call is the correct one per #2626).
- Delete dead --version/-v and --help/-h fast paths (loader.ts already
handles these before cli.ts is imported).
cli-web-branch.ts
- Unify CliFlags with worktree, 'mcp' mode, and _selectedSessionPath.
- Drop unused help?/version? flags (loader.ts intercepts them).
onboarding.ts
- Add runStep<T>() helper with shared cancel/warn handling; collapse 4
near-identical try/catch blocks around runLlmStep, runWebSearchStep,
runRemoteQuestionsStep, runToolKeysStep.
- Delete trivial isCancelError helper (inlined as p.isCancel).
- Rewrite loadPico() adapter to build PicoModule from chalk so we can
drop the redundant picocolors dependency.
package.json / package-lock.json
- Remove picocolors direct dep (chalk remains the single color library).
getServerConfig now trims whitespace and performs case-insensitive
matching so that names like "langgraph Code" resolve correctly.
getOrConnect uses config.name as the canonical cache key to prevent
duplicate connections from variant casing.
Closes#3029
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(test): wire src/resources/extensions/shared/tests/ into test:unit runner
The test:unit glob excluded src/resources/extensions/shared/tests/ entirely,
leaving format-utils.test.ts (and any future tests there) silently unfired.
- Add shared/tests/*.test.ts to the test:unit glob in package.json
- Export newestSrcMtime from ensure-workspace-builds.cjs (require.main guard
prevents side-effects on require) so the staleness logic can be tested
- Add src/tests/ensure-workspace-builds.test.ts covering newestSrcMtime:
non-existent dir, no .ts files, single file, max of multiple, recursion,
node_modules skip
Closes#2808
* perf(test): compile unit tests with esbuild and fix dist-test/node_modules
Replace per-file --experimental-strip-types with a single esbuild compilation
step (scripts/compile-tests.mjs) that compiles all src/ TypeScript to dist-test/
in ~3s, then runs the pre-compiled JS. Eliminates ~1.7s Node startup overhead
per test file.
- scripts/compile-tests.mjs: esbuild compilation, asset copy, .ts→.js rewrite,
stale file cleanup; creates dist-test/node_modules symlink so resource-loader.ts
resolves gsdNodeModules to a real path (fixes node-modules-symlink test failure)
- scripts/dist-test-resolve.mjs: ESM loader hook for @gsd/* bare specifiers and
.ts→.js fallback rewriting at runtime
- .gitignore: exclude dist-test/ from version control
- package.json: add test:compile script; update test:unit to compile-then-run;
update test:integration globs to cover new integration/ subdirectories
- worker-registry.ts: unref() cleanup timer so it does not keep the Node process
alive after tests complete
Closes#2858
* fix(test): update relative imports in tests/integration/ after directory move
When tests were moved from tests/ to tests/integration/ in the previous
commit, relative imports weren't updated. ../foo now resolves one level
too shallow.
Fix all 117 import paths across 43 test files:
- ../foo → ../../foo (source files at gsd/ level)
- ../../get-secrets-from-user.ts → ../../../ (at extensions/ level)
- ../../subagent/worker-registry.ts → ../../../ (at extensions/ level)
- ./marketplace-test-fixtures.js → ../marketplace-test-fixtures.ts
- ./test-helpers.ts → ../test-helpers.ts
typecheck:extensions now passes with zero errors.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* test(integration): set 10-minute timeout for integration test runner
build job takes ~7min on main. Without a global timeout, hanging tests
block the suite indefinitely. --test-timeout=600000 caps each test at 10min.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Revert "test(integration): set 10-minute timeout for integration test runner"
This reverts commit be77ead77d369ad8569292ae6b69ba56435f5433.
* fix(test): correct formatDuration(0) edge case and docker test root path
- formatDuration(0) now returns '0s' instead of '0ms' by guarding the
sub-second branch with ms > 0
- docker-template.test.ts root path goes ../../.. from dist-test/src/tests/
to reach project root instead of landing in dist-test/
- replace require() calls in skill-health.ts and visualizer-overlay.ts
with proper ES module imports
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(test): correct relative import paths in integration tests
All affected tests were one directory level off — importing from ../web/
and ../resources/ when the correct paths are ../../web/ and ../../resources/.
Tests live at src/tests/integration/, not src/tests/.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(test): add esbuild to root devDeps and wire dist-test-resolve hook
P1: esbuild was only in web/package.json — compile-tests.mjs requires it
at the root node_modules path, so CI failed on clean installs.
P2: dist-test-resolve.mjs existed but was never loaded; @gsd/* imports in
compiled tests resolved to installed workspace packages instead of freshly
compiled dist-test output. Add --import to test:unit.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(deps): align esbuild version with lock file (0.25.12)
^0.27.4 didn't satisfy the existing lock file entry. Use the version
already present so npm ci passes without regenerating the lock file.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(test): correct all relative import depths in src/tests/integration/
Tests in src/tests/integration/ need 3 levels up (../../..) to reach
project-root dirs (web/, packages/) and 2 levels up (../..) to reach
src-level dirs (src/web/, src/cli-web-branch.ts).
Fixes:
- ../../web/lib/ → ../../../web/lib/ (Next.js app, not src/web/)
- ../../web/app/ → ../../../web/app/
- ../../packages/ → ../../../packages/
- ../cli-web-branch.ts → ../../cli-web-branch.ts
- ../web-mode.ts → ../../web-mode.ts
- ../resources/extensions/ → ../../resources/extensions/
- ci_monitor ROOT path: 2 levels up → 3 levels up
- web-responsive WEB_ROOT: 2 levels up → 3 levels up
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* chore(test): use dot reporter for test:unit to reduce noise
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* chore(test): switch test:unit reporter to tap
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* chore(test): compact test reporter — silent on pass, failures + summary only
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* chore(test): include shared/tests in test:coverage
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(test): correct path depths in tests moved to integration/
Tests moved from tests/ to tests/integration/ need one extra ../
to reach the same source files. Also fix web component paths — those
files live at web/ not src/web/.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(test): fix web component paths in web-session-parity-contract
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(test): use process.cwd() for project root in docker-template test
Resolving relative to __dirname breaks under test:coverage which runs
source files directly from src/tests/ — needs ../.. not ../../..
(the extra level only exists in the compiled dist-test/ output).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* ci: retrigger CI
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Add two CI gates to enforce CONTRIBUTING.md test requirements:
1. File-matching check (lint job): fails PRs that change source files
without including test file changes. Exempts docs/chore/ci branches.
2. Coverage gate (build job): wires existing `npm run test:coverage`
into CI with c8 thresholds (40% statements/lines, 20% branches/functions).
Previously defined in package.json but never ran in CI.
Lowers coverage thresholds from 50% to 40% for statements/lines to match
current codebase reality (~44%) — prevents the gate from blocking every PR
on day one while still catching coverage regressions.
Implements Phase 1 of the Claude Code subscription-as-provider integration
(issue #2509). Users with a Claude Code subscription (Pro/Max/Team) can
use subsidized inference through GSD's UI via the official Agent SDK.
The extension registers a provider with authMode: "externalCli" that
delegates to the user's locally-installed claude CLI. The SDK runs the
full agentic loop (multi-turn, tool execution) in one streamSimple call.
Tool calls stream in real-time for TUI visibility but are stripped from
the final AssistantMessage so the agent loop ends cleanly without local
tool dispatch.
Zero core changes — pure extension-based implementation.
Closes#2509
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The 13 test files in packages/pi-coding-agent/src/core/ were never executed
in CI or by `npm test`. The test:unit glob only covers src/resources/extensions/gsd/tests/
and src/tests/, leaving lifecycle-hooks, model-registry-auth-mode, auth-storage,
and 10 other suites with zero enforcement.
- Add `test:packages` script that runs compiled dist tests after build
- Wire into both the linux build job and windows-portability job in CI
- Fix two env-isolation bugs in auth-storage.test.ts: the "returns undefined"
and "falls through to fallback resolver" tests were not clearing
OPENROUTER_API_KEY before calling getApiKey, causing failures when the
env var is set in the caller's environment
Vitest/node --test uses esbuild for transpilation and skips type-checking,
so type errors in extension tests accumulate silently until CI runs
tsc --noEmit. Adding typecheck:extensions as a pretest gate catches drift
locally before it reaches CI.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>