Commit graph

1099 commits

Author SHA1 Message Date
Tom Boucher
ea9c5f7ee2 fix: headless mode exits early on progress notifications containing 'complete' (#879) (#888)
isTerminalNotification() used broad substring matching against
['complete', 'stopped', 'blocked']. Any notification containing these
words triggered early exit — including progress messages like:
  'All slices are complete — nothing to discuss.'
  'Override(s) resolved — rewrite-docs completed.'
  'Skipped 5+ completed units. Yielding to UI before continuing.'

Fix: Replace substring matching with prefix matching against the actual
stop signals emitted by stopAuto():
  'Auto-mode stopped...'
  'Step-mode stopped...'

These are the ONLY notifications that indicate auto-mode has genuinely
terminated. All other notifications (slice completion, override
resolution, skip yielding) are progress events and must not trigger
exit.

Also tighten isBlockedNotification to match 'blocked:' (with colon)
instead of bare 'blocked' to avoid false positives from unrelated
messages.

Added 15 regression tests covering:
- All real terminal notification variants
- 6 false-positive cases from the issue report
- Non-notify event rejection
- Blocked detection with and without colon
2026-03-17 09:11:34 -06:00
Tom Boucher
3542b17c97 fix: normalize Windows paths in LLM-visible text to prevent bash failures (#874) (#884)
On Windows, process.cwd() returns backslash paths (C:\Users\name\...).
When these paths are injected into system prompts, worktree context
blocks, or tool results, the model copies them into bash commands.
Bash interprets backslashes as escape characters, silently stripping
them — producing invalid paths like 'C:Usersnamedevelopmentapp-name'.

This is not a regex hack — it's a proper cross-platform boundary:
- Filesystem operations (fs, path.join, spawn cwd) use native paths
  unchanged. Node handles both separators correctly for I/O.
- LLM-visible text (prompts, tool results, extension messages) uses
  toPosixPath() to normalize to forward slashes. C:/Users/name/...
  is valid in Git Bash, WSL bash, PowerShell, and Node.js.

Changes:

- utils/path-display.ts: New toPosixPath() utility in pi-coding-agent
  package (for system prompt) and shared extension module (for
  extensions that can't import from the compiled package at dev time)

- system-prompt.ts: Normalize resolvedCwd before injecting into the
  'Current working directory' line

- gsd/index.ts: Normalize all process.cwd() and originalBase paths in
  worktree context blocks injected into the system prompt

- bg-shell/index.ts: Normalize cwd in tool result text (start, env
  actions) that the model reads and may reference in commands

- path-display.test.ts: 9 regression tests covering toPosixPath
  behavior and system prompt output verification. Includes a scanner
  that fails if any Windows absolute paths with backslashes appear in
  buildSystemPrompt() output.

Audit scope: Checked all process.cwd() usage across pi-coding-agent
and all bundled extensions. Filesystem-only paths (join, readFile,
spawn cwd, existsSync) are correct and left unchanged. Only paths
entering LLM text are normalized.
2026-03-17 09:02:23 -06:00
Tom Boucher
7a26d27e94 feat: add model type, provider, and API docs fields to bug report template (#877) 2026-03-17 08:42:25 -06:00
Tom Boucher
7e1fcd3549 fix: don't trigger LLM turns on async_bash job completion (#875) (#880) 2026-03-17 08:30:13 -06:00
Tom Boucher
62bbaa8e8e feat: integrate hashline edit mode into active workflow (#870) (#872) 2026-03-17 08:23:53 -06:00
Jeremy McSpadden
a8eb66b8b3 feat: group /model selector by provider (#871) 2026-03-17 08:23:29 -06:00
Tom Boucher
ae8b8eeca3 fix: limit native web_search to max_uses:5 per response (#817) (#869) 2026-03-17 08:23:05 -06:00
Tom Boucher
4c7c64f7f5 fix: completed milestone with summary re-entered as active on resume (#864) (#868) 2026-03-17 08:22:16 -06:00
Gary Trakhman
9fe046d3fa Revert PR #744 - symlink-based development workflow (#867) 2026-03-17 08:21:55 -06:00
Jeremy McSpadden
c66ad3485e fix: add replan-slice artifact verification to break infinite replanning-slice loop (#858) (#865) 2026-03-17 08:20:24 -06:00
Jeremy McSpadden
d06e9ca12e fix: auto-heal STATE.md missing in preDispatchHealthGate (#862) 2026-03-17 08:20:10 -06:00
Jeremy McSpadden
c209dd1118 fix: replace orphaned invalidateStateCache() calls with invalidateAllCaches() (#861) 2026-03-17 08:19:55 -06:00
Tom Boucher
16bda686a1 fix: sync project root artifacts into worktree before deriveState to prevent stale DB loop (#853) (#855) 2026-03-17 08:19:37 -06:00
Tom Boucher
0abc61987d fix: add Alt+V as clipboard image paste shortcut on macOS and document it (#852) (#854) 2026-03-17 08:19:13 -06:00
Tom Boucher
ac585908fa docs: add explicit Gemini OAuth ToS warning to README (#850) (#851) 2026-03-17 08:17:48 -06:00
Tom Boucher
8872c9095e fix: mark transient network errors as retriable in Anthropic provider (#833) (#849) 2026-03-17 08:17:25 -06:00
Tom Boucher
9175eb0aa3 fix: treat needs-remediation as terminal validation verdict to prevent hard loop (#832) (#848) 2026-03-17 08:03:06 -06:00
Tom Boucher
11d0b26858 fix: use fixLevel 'all' in post-hook doctor after complete-slice to fix roadmap checkboxes (#839) (#847) 2026-03-17 08:01:10 -06:00
Tom Boucher
1868aaeb02 feat: show discussion status indicators in /gsd discuss slice picker (#782) (#846) 2026-03-17 08:00:56 -06:00
Tom Boucher
33fff7bab0 feat: add require_slice_discussion option to pause auto-mode before each slice (#789) (#845) 2026-03-17 08:00:41 -06:00
Tom Boucher
84e772f086 fix: invalidate caches before initial state derivation in startAuto (#800) (#843) 2026-03-17 08:00:24 -06:00
Tom Boucher
1f67ce250b fix: make task_done_missing_summary fixable in doctor to prevent validate-milestone skip loop (#820) (#842) 2026-03-17 08:00:10 -06:00
Tom Boucher
d593b2e367 fix: handle BMP clipboard images on WSL2 via wl-paste PNG conversion or ImageMagick (#813) (#841) 2026-03-17 07:59:56 -06:00
Tom Boucher
a706b4bd96 fix: extend idle timeout for headless new-milestone to prevent premature exit (#808) (#840) 2026-03-17 07:59:40 -06:00
Tom Boucher
0873961550 fix: handle EPIPE in LSP sendNotification and wait for process exit on reload (#815) (#837) 2026-03-17 07:59:25 -06:00
Tom Boucher
4a43679bc0 fix: add debug logging to silent early-return paths in dispatchNextUnit (#823) (#836) 2026-03-17 07:59:13 -06:00
Tom Boucher
a7453719f5 fix: add fallback parser for prose-style roadmaps without ## Slices section (#807) (#835)
When the LLM writes freeform prose roadmaps with `## Slice S01: Title`
headers instead of the machine-readable `## Slices` checklist,
parseRoadmapSlices() returned zero slices, causing deriveState() to
permanently block with 'No slice eligible'.

Add a fallback parser that detects prose-style `## Slice SXX:` headers
(and variants like `## S01:`, `## S01 —`) and extracts slice IDs,
titles, and dependencies from the prose. Also parses `Depends on:`
text patterns. All fallback slices default to risk:medium and done:false.
2026-03-17 07:49:50 -06:00
Tom Boucher
2f459b5d03 fix: remove untracked .gsd/ state files before milestone merge checkout (#827) (#834)
When merging a milestone back to main, `git checkout main` fails if
untracked .gsd/ state files (STATE.md, completed-units.json, auto.lock)
in the working tree conflict with tracked files on the branch.

Remove these known GSD-managed state files before checkout. They are
runtime artifacts regenerated by doctor/rebuildState and are not
meaningful in the main working tree — the worktree had the real state.
2026-03-17 07:49:26 -06:00
Tom Boucher
d94728aa7e fix: prevent crash when cancelling OAuth provider login dialog (#821) (#831)
OAuthSelectorComponent calls its onSelect callback synchronously (no
await), but the callback was async — calling showLoginDialog which
throws 'Login cancelled' on Escape. The unhandled rejection bubbled
up to the uncaughtException handler and crashed GSD.

Wrap the async work in a named function with .catch() so cancellation
errors are swallowed gracefully. showLoginDialog already handles its
own error display internally.
2026-03-17 07:49:09 -06:00
Tom Boucher
776a8800d8 fix: include STATE.md, KNOWLEDGE.md, OVERRIDES.md in worktree artifact copy (#809) (#830)
Worktree initialization only copied DECISIONS.md, REQUIREMENTS.md,
PROJECT.md, and QUEUE.md. The missing STATE.md caused the pre-dispatch
health check in doctor-proactive.ts to block dispatch with
'STATE.md missing'.

Add STATE.md, KNOWLEDGE.md, and OVERRIDES.md to the copy list so
worktrees start with complete planning state.
2026-03-17 07:48:53 -06:00
Tom Boucher
c6d1bdd1cc fix: compare gsdVersion instead of syncedAt for resource staleness check (#804) (#829)
Every new pi session writes a fresh syncedAt timestamp to
managed-resources.json, causing a running auto-mode session to falsely
detect a GSD update and stop. The actual version (gsdVersion) only
changes on real upgrades.

Switch the staleness check from syncedAt (timestamp) to gsdVersion
(semver string) so that launching a second session no longer triggers
a false positive.
2026-03-17 07:48:38 -06:00
Tom Boucher
ef706726c8 fix: use unique temp paths in saveFile() to prevent parallel write collisions (#810) (#828)
When multiple tool calls (e.g. concurrent gsd_save_decision) target the
same markdown file, the deterministic .tmp suffix caused ENOENT on
rename() because one caller consumed the temp file before another could
rename it.

Replace the static `.tmp` suffix with a per-call random suffix so each
concurrent writer gets its own temp file. Also clean up orphaned temp
files on rename failure.
2026-03-17 07:48:18 -06:00
Tom Boucher
b44896e187 fix: generate validation and summary files for completed milestones during migration (#819) (#838)
The .planning → .gsd migration creates roadmaps and summaries but not
VALIDATION files. deriveState() requires a terminal validation file
(verdict: pass) to consider a milestone complete. Without it, every
migrated milestone enters validating-milestone phase, blocking progress
to the actual current milestone.

For milestones where all slices are done, write a pass-through
VALIDATION.md (verdict: pass, migrated: true) and SUMMARY.md so
deriveState() skips them correctly.

Updated integration test to verify VALIDATION/SUMMARY files are written
and deriveState returns 'complete' phase with activeMilestone pointing
to the last completed entry (expected behavior).
2026-03-17 07:47:57 -06:00
Tom Boucher
1aebc06c46 docs: update documentation for v2.24 release features (#825)
- README: add parallel orchestration link, update loop diagram with validate-milestone phase
- architecture: add lazy provider loading, memory-extractor/store modules, update module table to v2.24
- auto-mode: add rate limit recovery section, parallel worker status in dashboard
- commands: add headless new-milestone command with --context/--context-text/--auto flags
- getting-started: add update check notification note
- troubleshooting: update rate limit recovery guidance
- visualizer: add task counts, discussion status to progress tab
2026-03-17 07:47:28 -06:00
Adam Dry
68edb39f9e fix: add gsd_generate_milestone_id tool for multi-milestone unique ID generation (#818)
When unique_milestone_ids is enabled, the LLM cannot generate random
suffixes itself. Previously only the first milestone got a correct ID
(pre-generated in TS), while subsequent milestones in multi-milestone
projects got bare M002/M003 without suffixes.

Added a gsd_generate_milestone_id tool that the LLM calls to get each
milestone ID. The tool scans disk for existing milestones and respects
the unique_milestone_ids preference, making it impossible to produce
wrong-format IDs.

Updated discuss, discuss-headless, and queue prompts to instruct the
LLM to use the tool instead of inventing milestone IDs.
2026-03-17 07:47:11 -06:00
deseltrus
7c449b8b73 feat: worker NDJSON monitoring + budget enforcement for parallel orchestration (#814)
* feat: worker NDJSON monitoring, budget enforcement, PID-based stop fallback

Closes three gaps in parallel orchestration:

1. **Worker stdout monitoring** — Workers now run with `--mode json` so
   they emit NDJSON events. The coordinator parses stdout line-by-line,
   extracting cost/token data from `message_end` events. This keeps
   per-worker cost tracking in sync with actual API spend and updates
   session status files for live dashboard visibility.

2. **Budget enforcement before spawn** — `startParallel()` now checks
   `isBudgetExceeded()` before each worker spawn. When the aggregate
   cost across all workers reaches the configured ceiling, no new
   workers are started.

3. **PID-based stop fallback** — `stopParallel()` now falls back to
   `process.kill(pid, "SIGTERM")` when the ChildProcess handle is null
   (e.g., after coordinator restart when handles aren't available).
   Previously, orphaned workers could not be stopped.

Includes 11 new tests covering NDJSON format validation, cost
aggregation, budget ceiling comparison, and PID-based kill patterns.
All 54 existing parallel-orchestration tests still pass.

Relates to #672

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

* fix: currentUnit type must match SessionStatus interface (object | null, not string)

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-17 07:46:52 -06:00
Lex Christopherson
4883ed1e99 2.25.0
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 23:47:17 -06:00
Lex Christopherson
8c9b40cb5e docs: update changelog for v2.25.0
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 23:46:58 -06:00
TÂCHES
440e6e878f feat: render native web search in TUI + PREFER_BRAVE_SEARCH toggle (#806)
* feat: render native web search tool calls in TUI

The Anthropic streaming parser silently dropped server_tool_use and
web_search_tool_result content blocks, making native web search
invisible. Add ServerToolUseContent and WebSearchResultContent types,
handle both block types in the streaming parser and conversation replay,
and render them as ToolExecutionComponent in the interactive TUI.

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

* feat: add PREFER_BRAVE_SEARCH env var to bypass native web search

Set PREFER_BRAVE_SEARCH=1 to keep Brave/custom search tools active
on Anthropic models instead of injecting native server-side web search.

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

* fix: skip non-toolCall blocks in Mistral provider conversation replay

The ServerToolUseContent and WebSearchResultContent types added for
native web search don't have id/name/arguments properties, causing
TypeScript errors when the Mistral provider tried to push them as
tool calls.

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-16 23:35:20 -06:00
TÂCHES
3adacf3ff5 feat: meaningful commit messages from task summaries (#803)
* feat: meaningful commit messages from task summaries (#785, #784)

Post-task commits now derive messages from the task summary one-liner,
inferred type, and key files. Planning prompts respect commit_docs: false.
Commit type inference expanded with perf type and oneLiner parameter.

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

* fix: replace invalidateStateCache with invalidateAllCaches in crash recovery

PR #799 reintroduced invalidateStateCache() calls in the phantom skip
loop crash recovery paths. These should use invalidateAllCaches() which
is the renamed function.

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

* fix: resolve CI failures from main merge conflicts

- Replace invalidateStateCache() → invalidateAllCaches() in crash
  recovery paths (reintroduced by PR #799 merge)
- Expand smart-entry-draft test chunk window from 3000 to 4000 chars
  to accommodate commitInstruction additions

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-16 23:30:33 -06:00
TÂCHES
28bb77b999 Merge pull request #805 from jeremymcs/test/expand-e2e-smoke-tests
test: expand E2E smoke tests with 14 new CLI verification tests
2026-03-16 23:18:25 -06:00
Jeremy McSpadden
aaf3fe394c fix: replace orphaned invalidateStateCache() calls and remove dead test
- Replace 2 remaining invalidateStateCache() calls with invalidateAllCaches()
  in auto.ts phantom skip loop recovery paths (lines 2473, 2551)
- Remove commit-message.test.ts which referenced the removed
  deriveCommitMessage export from auto.ts
2026-03-17 00:09:02 -05:00
Jeremy McSpadden
2d037249c4 test: expand E2E smoke tests with 14 new CLI verification tests
Add comprehensive black-box smoke tests covering command routing,
graceful error handling, headless mode validation, and help completeness.

New tests:
- Command routing: headless --help, sessions --help
- Flag aliases: -v (--version), -h (--help)
- Error handling: no-TTY clean exit, unknown flags resilience
- Headless mode: missing .gsd/ dir, missing --context, invalid/negative --timeout
- Help completeness: all subcommands listed, all key flags listed
- Edge cases: --version ignores trailing args, headless positional help

All tests run without API keys and use temp directory isolation.
2026-03-17 00:02:26 -05:00
TÂCHES
0e5cbee8d8 Merge pull request #799 from gsd-build/fix/790-crash-recovery-phantom-loop
fix: prevent phantom skip loop from stale crash recovery context (#790)
2026-03-16 22:35:10 -06:00
TÂCHES
e695cccc91 Merge pull request #801 from gsd-build/fix/clear-artifacts-in-invalidateAllCaches
fix: include DB artifact cache in invalidateAllCaches (#793)
2026-03-16 22:34:56 -06:00
TÂCHES
01646dce48 Merge pull request #798 from gsd-build/fix/792-skip-loop-uninterruptible
fix: make skip-loop interruptible and count toward lifetime cap (#792)
2026-03-16 22:32:45 -06:00
Lex Christopherson
72c86e0792 fix: include DB artifact cache in invalidateAllCaches (#793)
Cherry-picked from #797 — adds clearArtifacts() to gsd-db.ts and wires
it into invalidateAllCaches() so the DB artifact table is cleared
alongside state/path/parse caches.

Co-Authored-By: 0xLeathery (PR #797)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 22:32:10 -06:00
TÂCHES
5271e51a84 Merge pull request #796 from jeremymcs/fix/793-db-cache-invalidation
fix: invalidateAllCaches() in skip-loop eviction and rebuildState (#793)
2026-03-16 22:31:23 -06:00
Lex Christopherson
0184498a44 fix: prevent phantom skip loop from stale crash recovery context (#790)
When a crash lock references a unit from a fully-completed milestone,
crash recovery injects stale context that fights the skip-loop breaker,
creating an infinite evict/repair cycle with selfHealRuntimeRecords.

Fix 1: Validate recovered unit's milestone before synthesizing recovery
context. If the milestone has a SUMMARY file (complete), discard the
stale recovery context and clear the lock without injection.

Fix 2: Skip-loop breaker cross-checks whether the evicted unit belongs
to a completed milestone. If so, the eviction is counterproductive —
clear the skip counter and re-dispatch from fresh state instead.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 22:30:15 -06:00
TÂCHES
3e52f4d66b feat: incremental memory system for auto-mode (#795)
* chore: add .audits/ to .gitignore

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

* feat: add auto-learned project memory system

Extracts durable knowledge from completed unit activity logs via
background LLM calls (Haiku-preferred) and injects ranked memories
into the system prompt. Includes DB schema v3 migration, memory store
CRUD with confidence/hit-count ranking, secret redaction, decay, and
cap enforcement.

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

* fix: add timestamp to UserMessage in memory extractor

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

* fix: update schema version assertion in md-importer 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>
2026-03-16 22:29:35 -06:00