Commit graph

1334 commits

Author SHA1 Message Date
TÂCHES
0929fd3c36 Merge pull request #2606 from gsd-build/refine/merge-worktree-sync-into-auto-worktree
refactor: merge auto-worktree-sync into auto-worktree
2026-03-25 22:57:30 -06:00
TÂCHES
1961fd7651 Merge pull request #2602 from gsd-build/refine/decouple-session-forensics-from-worktree
refactor: decouple session-forensics from auto-worktree
2026-03-25 22:49:36 -06:00
TÂCHES
277edae27e Merge pull request #2605 from gsd-build/refine/dedupe-artifact-path-functions
refactor: deduplicate artifact path functions into single module
2026-03-25 22:49:22 -06:00
TÂCHES
03d47fd51a Merge pull request #2604 from gsd-build/refine/remove-dead-selfHeal
refactor: remove dead selfHealRuntimeRecords function
2026-03-25 22:48:32 -06:00
TÂCHES
00e948ed8e Merge pull request #2603 from gsd-build/refine/remove-unused-gate-params
refine: remove unused basePath/unitId from verification gate
2026-03-25 22:47:56 -06:00
TÂCHES
eb9d2dd8c6 Merge pull request #2601 from gsd-build/refine/remove-dead-worktree-code
chore: remove dead worktree code and unused methods
2026-03-25 22:47:23 -06:00
Lex Christopherson
8429c0e173 refactor: merge auto-worktree-sync into auto-worktree
Consolidate all worktree sync, resource staleness, stale worktree escape,
and stale runtime unit cleanup into auto-worktree.ts. Extract shared
ROOT_STATE_FILES constant and isSamePath helper to eliminate triple
duplication of the rootFiles array and copy-pasted symlink checks.

Replace inline 26-line stale-unit cleanup in auto-start.ts with a call
to cleanStaleRuntimeUnits().

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 22:47:18 -06:00
TÂCHES
bdb21c3c23 Merge pull request #2600 from gsd-build/refine/consolidate-branch-patterns
refactor: consolidate branch name patterns into single module
2026-03-25 22:46:51 -06:00
Lex Christopherson
61cf3b556b refactor: deduplicate artifact path functions into single module
Remove duplicate resolveExpectedArtifactPath() and diagnoseExpectedArtifact()
from auto-recovery.ts, making auto-artifact-paths.ts the single source of truth.
auto-recovery.ts re-exports both functions for backward compatibility.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 22:43:05 -06:00
Lex Christopherson
ba6ea1c2fa refactor: remove dead selfHealRuntimeRecords function from auto-recovery
guided-flow.ts has its own local implementation; the exported version
in auto-recovery.ts was never imported anywhere. Removes 35 lines of
dead code, the unused clearUnitRuntimeRecord import, and associated
tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 22:42:18 -06:00
Lex Christopherson
fec7f8cc30 refactor: decouple session-forensics from auto-worktree
session-forensics.ts is a general-purpose JSONL parser that had a direct
import of getAutoWorktreePath from auto-worktree.ts, creating tight
coupling. getDeepDiagnostic now accepts an optional worktreePath parameter
instead of resolving it internally. The caller (auto.ts) resolves the
worktree path via readActiveMilestoneId + getAutoWorktreePath and passes
it in.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 22:41:53 -06:00
Lex Christopherson
f4c6dc67b7 refine: remove unused basePath/unitId from verification gate
Remove basePath and unitId from RunVerificationGateOptions — they were
defined in the interface and passed by callers but never read by
runVerificationGate(). This eliminates false coupling where callers
compute values that have zero effect.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 22:41:49 -06:00
Lex Christopherson
5bf36151d6 chore: remove dead worktree code and unused methods
Delete unused resource-version.ts (functions duplicated in auto-worktree-sync.ts
with zero imports). Remove GitServiceImpl.git() private method with no call sites.
Clean up orphaned section headers and dangling JSDoc in git-service.ts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 22:40:14 -06:00
Lex Christopherson
ed23fe56ab refactor: consolidate branch name patterns into single module
SLICE_BRANCH_RE, QUICK_BRANCH_RE, and WORKFLOW_BRANCH_RE were scattered
across worktree.ts and git-service.ts. Extract all three into
branch-patterns.ts as the single source of truth. Both original modules
re-export for backward compatibility — no consumer changes needed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 22:39:52 -06:00
Lex Christopherson
65f49af383 refactor: deduplicate session-lock compromise handler and state assignment
The lock acquisition had a primary path and a retry path with identical
28-line onCompromised callbacks and 6-line state assignment blocks (68 lines
of copy-paste). Extract into createLockCompromisedHandler() and
assignLockState() helpers so bug fixes only need to be applied once.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 22:38:14 -06:00
Lex Christopherson
020b4a876e merge: resolve conflict with main's assert.equal fix in doctor tests
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 22:32:54 -06:00
Lex Christopherson
ac4e3ac392 fix(tests): replace undefined assertTrue/assertEq with assert.ok/assert.equal
The doctor-environment and doctor-git tests used assertTrue and assertEq
which are not defined — they should be assert.ok and assert.equal from
the imported node:assert/strict module.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 22:26:59 -06:00
Lex Christopherson
f00b69621f fix(tests): replace undefined assertTrue/assertEq with assert.ok/deepStrictEqual
These test files imported `assert` from node:assert/strict but used
assertTrue/assertEq (from test-helpers.ts createTestContext) without
importing them, breaking typecheck:extensions on main and all PRs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 22:26:35 -06:00
Lex Christopherson
1d139da06e Merge remote-tracking branch 'origin/main' into fix/headless-auto-timeout-2586 2026-03-25 22:26:07 -06:00
TÂCHES
2d97f042de Merge pull request #2584 from jeremymcs/fix/web-search-budget-enforcement
fix(search): enforce hard search budget and survive context compaction
2026-03-25 22:22:12 -06:00
TÂCHES
9c2bacd39d Merge pull request #2597 from gsd-build/fix/complete-milestone-structured-params-2581
Fix complete-milestone prompt with structured params
2026-03-25 22:21:00 -06:00
Lex Christopherson
e1f51592b1 fix(gsd): handle session_switch event so /resume restores GSD state (#2587)
The GSD extension only listened for session_start, not session_switch.
When /resume switched to a previous session, GSD's write-gate, loop guard,
discussion flow, service tier, and tool API keys were never re-initialized,
leaving GSD in stale state from the prior session.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 22:20:43 -06:00
Lex Christopherson
36ff7ac4fe Fix complete-milestone prompt with structured parameter definitions
Replace the free-form parameter listing in step 7 of complete-milestone.md
with structured, typed parameter definitions that match the tool schema in
db-tools.ts. Parameters are grouped into required and optional sections with
explicit types (marking arrays as arrays, booleans as booleans) to prevent
LLM validation failures when calling gsd_complete_milestone.

Fixes #2581

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 22:19:53 -06:00
Lex Christopherson
ebb5afbd57 fix: use GitHub Issue Types via GraphQL instead of classification labels
The forensics prompt and gh skill used --label "bug" / --label "type:feature"
for issue classification, polluting the label taxonomy and leaving the Type
field unset. gh issue create has no --type flag, so issue types must be set
via GraphQL mutation after creation.

Closes #2579

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 22:18:26 -06:00
Lex Christopherson
fde0be6979 fix(headless): disable overall timeout for auto-mode, fix lock-guard auto-select (#2586)
Auto-mode sessions are long-running (minutes to hours) with their own
internal per-unit timeout via auto-supervisor. The 300s overall timeout
was killing active sessions mid-execution, triggering wasteful restart
cycles.

Changes:
- Disable overall timeout for auto-mode when using the default 300s
  (user can still set --timeout explicitly, including --timeout 0)
- Guard timeout timer creation for null when timeout is 0
- Cancel overall timeout when new-milestone --auto chains into auto-mode
- Fix headless auto-responder to pick "Force start" for lock-guard
  prompts instead of "View status" (which silently blocked auto-mode)
- Allow --timeout 0 to explicitly disable timeout for any command

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 22:18:05 -06:00
TÂCHES
7cf4084a1e Merge pull request #1887 from snowdamiz/fix/windows-standalone-package-root
fix(web): lazily compute default package root to avoid Windows standalone crash
2026-03-25 22:16:02 -06:00
TÂCHES
7751fab9a4 Merge pull request #1894 from trek-e/fix/1886-worktree-sync-overwrite-loop
fix: prevent worktree sync overwrite loop and forward-sync completed-units.json
2026-03-25 22:15:59 -06:00
TÂCHES
e9b82787bd Merge pull request #1980 from trek-e/fix/doctor-stale-deps-marker-1974
fix(doctor): use install marker mtime for stale dependency check
2026-03-25 22:15:56 -06:00
TÂCHES
d861352aac Merge pull request #1971 from trek-e/fix/doctor-orphan-worktree-cwd-1946
fix(doctor): chdir out of orphaned worktree before removal
2026-03-25 22:15:54 -06:00
TÂCHES
6476a8f073 Merge pull request #2257 from mastertyko/fix/skill-activation-param-syntax
fix(gsd): use explicit parameter syntax in skill activation prompts
2026-03-25 22:15:48 -06:00
TÂCHES
bdf835af08 Merge pull request #1966 from trek-e/fix/slice-roadmap-header-1940
fix(roadmap): recognize '## Slice Roadmap' header in slice parser
2026-03-25 22:15:34 -06:00
TÂCHES
7a7e564e95 Merge pull request #2559 from mastertyko/fix/doctor-legacy-pending-fallback
fix(gsd extension): preserve pending semantics in doctor legacy fallback
2026-03-25 22:15:13 -06:00
TÂCHES
3b6d9024f5 Merge pull request #2563 from mastertyko/fix/writeIntegrationBranch-workflow-template-guard
fix(gsd): guard writeIntegrationBranch against workflow-template branches
2026-03-25 22:15:10 -06:00
TÂCHES
874df9bc43 Merge pull request #2566 from jeremymcs/fix/hydrate-remote-tokens-esm
fix(remote-questions): use static ESM import for AuthStorage hydration
2026-03-25 22:14:56 -06:00
TÂCHES
5f8bbbc6e1 fix(auto): align UAT artifact suffix with gsd_slice_complete output (#2592)
* fix(auto): align UAT artifact suffix with gsd_slice_complete output

The auto-mode files referenced UAT-RESULT as the artifact suffix,
but gsd_slice_complete writes files as S##-UAT.md. This mismatch
caused ENOENT errors during validate-milestone dispatch.

Fixes #2564

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(auto): update test and doc references from UAT-RESULT to UAT

Aligns test assertions and ADR documentation with the corrected
artifact suffix.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(auto): replace separate UAT-RESULT file check with in-file verdict check

The original two-file model (UAT spec + UAT-RESULT verdict) never
worked because gsd_slice_complete only writes S##-UAT.md. The blind
string replacement made checkNeedsRunUat always return null by
resolving the same file twice. Now checks for a verdict: line inside
the UAT file content to determine if UAT has been completed.

Also deduplicates a redundant resolveSliceFile call in the verdict
gate and updates tests to verify the single-file verdict model.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 22:12:08 -06:00
TÂCHES
2a39adf5b4 Merge pull request #2591 from gsd-build/fix/lock-heartbeat-retry-v2
fix(session-lock): retry lock file reads before declaring compromise
2026-03-25 22:01:55 -06:00
TÂCHES
0705d65ed5 Merge pull request #2590 from gsd-build/fix/subdir-symlink-2380-v2
fix(gsd): prevent subdirectory .gsd symlink when git-root .gsd exists
2026-03-25 21:56:25 -06:00
Lex Christopherson
b4405cbb35 fix(test): replace stale completedUnits with sessionFile in session-lock test
SessionLockData no longer has a completedUnits field. Use sessionFile
(an actual optional field) for the same assertion coverage.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 21:56:08 -06:00
Tom Boucher
c09c256f28 fix(session-lock): retry lock file reads before declaring compromise
onCompromised was declaring lock lost when the lock file was temporarily
unreadable (NFS/CIFS latency, macOS APFS snapshot, or concurrent process
briefly holding the file). Add readExistingLockDataWithRetry (3 attempts,
200ms delay) so transient filesystem hiccups do not trigger false-positive
compromise events.

Fixes #2324

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 21:50:52 -06:00
Tom Boucher
a3250c4103 fix(gsd): prevent ensureGsdSymlink from creating subdirectory .gsd when git-root .gsd exists
When running GSD from a subdirectory (e.g. `cd src/ && gsd`),
ensureGsdSymlink would create a new `.gsd` symlink in the subdirectory
even though a valid `.gsd` already exists at the git root. On macOS
APFS this triggers the `.gsd 2` collision variant problem from #2205.

Add an early guard that detects when projectPath is a plain subdirectory
(not a worktree) of a git repo that already has `.gsd` at its root, and
returns the existing root .gsd target instead of creating a duplicate.

Fixes #2380

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 21:50:23 -06:00
Tom Boucher
47405dfda7 fix(auto): add EAGAIN to INFRA_ERROR_CODES to stop budget-burning retries
EAGAIN (resource temporarily unavailable) is a resource exhaustion error
that cannot be recovered by retrying, yet it was missing from the infra
error set. This caused auto-mode to keep retrying on EAGAIN failures,
burning LLM budget on guaranteed failures.

Fixes #2359

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 21:48:32 -06:00
TÂCHES
a53d021864 Merge pull request #2487 from jeremymcs/fix/isolation-mode-downgrade
fix(gsd): downgrade isolation mode when worktree creation fails
2026-03-25 21:46:38 -06:00
TÂCHES
8a533f2521 Merge pull request #2385 from trek-e/fix/queue-429-completed-milestones
fix(gsd): skip file loading for completed milestones in /gsd queue
2026-03-25 21:46:09 -06:00
Jeremy McSpadden
8e7ec7885a fix(search): enforce hard search budget and survive context compaction
- Native search: use monotonic high-water mark (Math.max) instead of
  overwriting sessionSearchCount from history. Prevents budget reset
  when context compaction removes web_search_tool_result blocks.
- Custom search tool: add MAX_SEARCHES_PER_SESSION=15 hard cap across
  all queries (not just consecutive duplicates). Returns budget_exhausted
  error when limit reached.
- Tighten MAX_CONSECUTIVE_DUPES from 3 to 1 — block on the 2nd identical
  search since cached results make repeats pointless.
- Add tests for compaction-safe high-water mark, session budget
  enforcement, and budget reset on session_start.

Closes #2583
2026-03-25 21:35:09 -05:00
Jeremy McSpadden
c06e42eec4 fix(remote-questions): use static ESM import for AuthStorage hydration
The hydrateRemoteTokensFromAuth() function used require() to load
AuthStorage from @gsd/pi-coding-agent, but the package is ESM-only
("type": "module" with only an "import" export condition). Node's
require() always throws for ESM packages, and the outer try/catch
silently swallowed the error — making hydration a no-op.

Replace require() with a static ESM import (consistent with every
other extension) and use AuthStorage.create() which resolves the
auth.json path internally via getAgentDir().

Closes #2565
2026-03-25 19:39:09 -05:00
mastertyko
e9c8994174 fix: add SAFE_SKILL_NAME guard to reject prompt-injection via crafted skill names
Adds /^[a-z0-9][a-z0-9-]*$/ validation in formatSkillActivationBlock() so that
skill names containing quotes, braces, or other special characters are silently
filtered out before interpolation into the prompt string.

Addresses the prompt injection surface noted by @trek-e in PR review.
Updates the special-character test to verify rejection instead of passthrough.
2026-03-26 00:51:05 +01:00
mastertyko
5a64da32d3 review: clarify comment wording, add special-character test
Address review feedback:
- Update comment to clarify that the function-call-like syntax led
  LLMs to infer a positional parameter name (not 'positional-looking')
- Add test documenting current behavior when skill names contain
  special characters (quotes, apostrophes)
2026-03-26 00:51:05 +01:00
mastertyko
006184456a fix(gsd): use explicit parameter syntax in skill activation prompts
The skill activation block used positional-looking syntax
`Call Skill('name')` which caused LLMs (especially non-Anthropic
models) to pass `{name: "..."}` instead of the required
`{skill: "..."}` parameter. This triggered tool validation failures
and stuck dispatch loops in auto-mode.

Change the prompt template to `Call Skill({ skill: 'name' })` which
makes the parameter name explicit and matches the Skill tool schema.

Update all 4 affected test assertions to match the new format.

Closes #2224
2026-03-26 00:51:05 +01:00
mastertyko
2e4d1489ae fix: guard writeIntegrationBranch against workflow-template branches
writeIntegrationBranch already rejects slice branches (SLICE_BRANCH_RE) and
quick-task branches (QUICK_BRANCH_RE), but has no guard for the 8 workflow-
template branches (gsd/hotfix/*, gsd/bugfix/*, gsd/spike/*, etc.). When a
user runs `/gsd start hotfix` during an active milestone, the ephemeral
hotfix branch gets recorded as the integration target and the milestone
later merges to the wrong branch.

Add WORKFLOW_BRANCH_RE (/^gsd\/(?!M\d)[\w-]+\//) that matches all
gsd/<templateId>/<slug> branches while excluding milestone slice branches
(gsd/M001/S01). The negative lookahead ensures milestone branches starting
with 'M' followed by a digit are not affected.

Same root cause as gsd/quick/* (#1293, PR #1342).

Closes #2498
2026-03-26 00:34:09 +01:00
TÂCHES
1436d8ed4a Merge pull request #2554 from gsd-build/copilot/clean-up-auto-commit-messages
refactor: move GSD metadata from commit subject scopes to git trailers, remove lifecycle noise
2026-03-25 17:14:49 -06:00