Commit graph

2649 commits

Author SHA1 Message Date
Tibsfox
5affaaf734 fix(gsd): allow milestone completion when validation skipped by preference
The completing-milestone dispatch guard blocked completion when
operational verification was planned but the validation was
intentionally skipped by a budget profile preference. The guard
now detects skip-by-preference markers in the validation content
and allows completion to proceed.

Closes #3399
Closes #3344

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:52:55 -07:00
Jeremy McSpadden
b4c6229360 Merge pull request #3646 from jeremymcs/fix/notification-overlay-backdrop
fix(gsd): notification overlay backdrop and sizing
2026-04-06 19:09:22 -05:00
Jeremy
2c91b8c6d8 test(tui): add test for 256-color backdrop codes 2026-04-06 18:57:02 -05:00
Jeremy
c35385fe53 fix(gsd): improve notification overlay backdrop and content-fit sizing
Use dark gray background + dim foreground for visible backdrop effect
instead of barely-perceptible SGR dim. Size overlay box to content
instead of padding to fill the entire viewport.
2026-04-06 18:53:26 -05:00
Jeremy McSpadden
6d2345e939 Merge pull request #3638 from jeremymcs/fix/notification-overlay-backdrop
fix(gsd): notification overlay backdrop dimming and viewport padding
2026-04-06 18:27:52 -05:00
Jeremy
9d1e343e41 test(gsd): add overlay backdrop and notification lock safety tests
- Overlay layout: verify backdrop dims base lines, no dim without flag,
  overlay composites on top of dimmed background
- Notification store: verify markAllRead and clearNotifications do not
  delete a foreign process's lock file
2026-04-06 17:44:34 -05:00
Jeremy
d553455732 fix(gsd): only unlink notification lock when owned, prevent foreign lock deletion
_withLock() was unconditionally unlinking the lock file in finally,
even when lock acquisition failed. This could delete another process's
lock and allow unlocked concurrent writes. Now tracks ownership and
only cleans up locks we created.
2026-04-06 17:39:44 -05:00
Jeremy
2c4ac844f1 fix(gsd): add backdrop dimming and viewport padding to notification overlay
The notification overlay was rendering too small with few entries, allowing
underlying content to bleed through. Added viewport padding to fill the
overlay box and a new `backdrop` option to OverlayOptions that dims the
background behind modal overlays.
2026-04-06 17:34:45 -05:00
Jeremy McSpadden
42caabdd0d Merge pull request #3563 from Tibsfox/fix/headless-discuss-multi-turn
fix(headless): treat discuss and plan as multi-turn commands
2026-04-06 15:58:04 -05:00
Jeremy McSpadden
d26efa47bc Merge pull request #3591 from jeremymcs/fix/complete-slice-provides-string-coercion
fix(gsd): coerce plain-string provides field to array in complete-slice
2026-04-06 15:57:16 -05:00
Jeremy McSpadden
c53f8ab471 Merge pull request #3608 from deseltrus/perf/session-memory-cpu-leaks
perf: fix CPU/memory leaks in long-running sessions
2026-04-06 15:56:22 -05:00
Jeremy McSpadden
d877e6e152 Merge pull request #3627 from jeremymcs/fix/3615-continue-context-injection
fix(gsd): inject task context for unstructured resume prompts (#3615)
2026-04-06 12:27:43 -05:00
Jeremy
04dc4a988b fix(gsd): add intent + phase guards to resume context fallback (#3615)
Tighten the deriveState fallback per adversarial review:
- Intent-gated: only fire for low-entropy resume prompts via
  RESUME_INTENT_PATTERNS (continue, ok, go ahead, resume, etc.)
- Phase-gated: only during state.phase === "executing"
- Non-resume prompts (help, status, abort, diagnostics) are not
  hijacked with execution context

Add behavioral tests: 24 positive matches + 17 negative rejections
for the intent pattern, alongside the 5 structural tests.
2026-04-06 12:14:36 -05:00
Jeremy
5b104897c8 fix(gsd): inject task context for unstructured resume prompts (#3615)
When a user types "continue" or bare text to resume an in-progress
session, buildGuidedExecuteContextInjection() only matched two
hardcoded regex patterns and returned null for anything else — causing
the agent to rebuild everything from scratch and burn ~86k tokens.

Add a phase-gated deriveState fallback that injects task execution
context when state.phase === "executing" and an active task exists.
The phase guard prevents misrouting during replanning, gate evaluation,
or other non-execution phases.
2026-04-06 12:10:08 -05:00
Jeremy McSpadden
0d87df94be Merge pull request #3619 from frizynn/fix/3618-schema-overload-bash-exit-code
fix(agent-loop): schema overload cap ignores bash execution errors (#3618)
2026-04-06 10:13:03 -05:00
Jeremy McSpadden
4aa7fe3940 Merge pull request #3621 from jeremymcs/fix/3616-db-tools-missing-subagent
fix(pi-coding-agent): restore extension tools after session switch (#3616)
2026-04-06 10:12:32 -05:00
Jeremy
90feebeccf fix(pi-coding-agent): restore extension tools after session switch (#3616)
newSession() only rebuilt the tool registry when cwd changed. When cwd
stayed the same (e.g., discuss → plan-slice in the same worktree), any
tool narrowing from setActiveTools() persisted — stripping gsd_plan_slice
and other DB tools from auto-mode subagent sessions.

Add an else-branch that calls _refreshToolRegistry with
includeAllExtensionTools:true on every session switch, regardless of cwd.

Also call resetExtensionLoaderCache() in DefaultResourceLoader.reload()
so hot-updated extension code on disk is re-compiled instead of served
from the stale jiti module cache.

Closes #3616
2026-04-06 09:51:58 -05:00
frizynn
cd14a4c765 fix(agent-loop): schema overload cap ignores bash execution errors (#3618)
The schema overload detector counted ALL isError tool results toward the
consecutive-failure cap, including bash commands that returned non-zero exit
codes (e.g. rg/grep exit 1 = 'no matches'). Three consecutive exploratory
searches with no matches would trigger the cap and abort the session.

Root cause: the allToolsFailed check used toolResults.every(r => r.isError)
which conflates preparation-phase errors (schema validation, tool-not-found,
tool-blocked) with execution-phase errors (the tool ran successfully but
returned a non-zero exit code).

Fix: track preparationErrorCount alongside tool results. Only preparation
errors (schema/validation failures) increment the consecutive failure
counter. Tool execution errors — like bash exit code 1 — are valid usage
and do not count toward the cap.

Also fixes pre-existing StopReason type mismatches in agent-loop tests
(end_turn → stop, tool_use → toolUse).
2026-04-06 11:35:41 -03:00
deseltrus
4744e86c8f test: structural regression tests for session memory/CPU leak fixes
Verifies that defensive guards (render-skip, chat cap, dispose, signal
handler cleanup, alert cap, orphan kill) are present in source. These
are structural tests because the leaks manifest over hours of real
usage, not in unit test timescales.
2026-04-06 09:57:40 +02:00
deseltrus
886c5837ff fix(bg-shell): prevent signal handler accumulation + cap alert queue
Signal handlers (SIGTERM, SIGINT, beforeExit) were registered on every
session_start but never removed. Over multiple sessions within the same
process, handlers accumulated — each adding another cleanupAll() call
and descendant kill sweep on exit.

Fix: session_shutdown now calls process.off() for each handler before
cleanupAll(), preventing accumulation.

Also: signalCleanup now kills ALL descendant processes (not just those
tracked by bg-shell) to catch bash-tool spawned children.

Alert queue: pendingAlerts is capped at 50 entries to prevent unbounded
growth when background processes generate rapid alerts faster than the
agent consumes them.

pushAlert signature updated to accept null bg parameter for system-level
alerts that don't originate from a tracked process.
2026-04-06 09:52:36 +02:00
deseltrus
0b40d39b0e perf(interactive): cap rendered chat components + kill orphan descendants
Chat component cap: After 100 rendered components, oldest are removed
from the container (session transcript persists on disk via
SessionManager). Prevents unbounded memory growth in long sessions
where thousands of tool calls accumulate DOM-like component trees.

Orphan process prevention: On shutdown, listDescendants(process.pid)
finds ALL child processes (including those spawned by the Bash tool
that bg-shell doesn't track) and kills them with SIGTERM + 500ms
grace + SIGKILL. Prevents orphaned dev servers, build processes, etc.
from persisting after session exit.
2026-04-06 09:52:20 +02:00
deseltrus
c5227f7570 perf(tui): render-skip, frame isolation, Text cache guard, dispose
Container.render() now returns a stable array reference when output is
unchanged — TUI.doRender() skips ALL post-processing (isImageLine scans,
applyLineResets, differential diffs) when the reference matches.

Loader decouples spinner frame rotation from Text content updates.
Previously every 80ms tick called setText() which invalidated Text's
wrapTextWithAnsi/visibleWidth caches. Now the frame is prepended in
render() while Text caches the message separately.

Text.setText() returns early when text is unchanged, avoiding cache
invalidation on redundant updates.

ToolExecutionComponent.dispose() clears heavy references (image maps,
diff previews, result data) so GC can reclaim memory when components
are removed from the chat history.
2026-04-06 09:52:08 +02:00
Jeremy McSpadden
6dfc422990 Merge pull request #3587 from jeremymcs/feat/persistent-notification-panel
feat(gsd): persistent notification panel
2026-04-05 22:53:30 -05:00
Jeremy
9616b02c58 fix(gsd): coerce plain-string provides field to array in complete-slice (#3585)
LLMs sometimes pass simple string-array fields (provides, keyFiles, etc.)
as a plain string instead of a single-element array, causing TypeBox schema
validation to reject the call before the execute function's coercion logic
can run. Fix by accepting Union([Array, String]) in the schema and adding
wrapArray() coercion for all 8 simple array fields in the execute function.
2026-04-05 22:15:13 -05:00
Jeremy
8078755e4b feat(gsd): persistent notification panel with TUI overlay, widget, and web API
Notifications from ctx.ui.notify() and workflow-logger now persist to
.gsd/notifications.jsonl instead of evaporating as transient toasts.

- notification-store: JSONL persistence with 500-entry rotation, atomic
  temp+rename rewrites, ref-counted suppress API, disk-synced counters
- notify-interceptor: WeakSet-guarded monkey-patch on ctx.ui.notify
  installed at session_start and session_switch
- notification-widget: always-on belowEditor strip showing unread count
- notification-overlay: scrollable Ctrl+Alt+N panel with severity filter
- /gsd notifications command: clear, tail, filter subcommands
- workflow-logger: warnings now also persist to notification store
- web API: GET/DELETE /api/notifications with ?countOnly support
- 16 unit tests covering store, suppress, project isolation, resync
2026-04-05 22:13:28 -05:00
Jeremy McSpadden
c9d358b8fe Merge pull request #3468 from OfficialDelta/feat/enhanced-verification
feat(gsd): add enhanced verification checks for auto-mode
2026-04-05 21:59:03 -05:00
Alan Alwakeel
7af983bda2 fix: address PR #3468 review findings
1. Post-execution retry bypass (auto-verification.ts)
   - When postExecBlockingFailure is true, skip retry and pause immediately
   - Post-exec failures are cross-task consistency issues that retrying won't fix
   - Added test in post-exec-retry-bypass.test.ts

2. File path normalization (pre-execution-checks.ts)
   - Added normalizeFilePath() to handle ./path vs path equivalence
   - Normalizes backslashes, removes duplicate slashes, strips leading ./
   - Applied to checkFilePathConsistency() and checkTaskOrdering()
   - Added tests for path normalization in pre-execution-checks.test.ts

3. Pre-exec fail-closed (auto-post-unit.ts)
   - Added try/catch around runPreExecutionChecks() inside runSafely block
   - If runPreExecutionChecks throws, set preExecPauseNeeded = true
   - Used logError from workflow-logger (not raw stderr)
   - Added test in pre-execution-fail-closed.test.ts
2026-04-05 22:44:15 -04:00
Jeremy McSpadden
7b7cad0de9 Merge pull request #3586 from jeremymcs/fix/elapsed-timer-lost-on-resume
fix(gsd): persist elapsed timer across session resume
2026-04-05 21:21:37 -05:00
github-actions[bot]
f6a1549edd release: v2.64.0 2026-04-06 02:11:42 +00:00
Jeremy
b6794956f8 test(gsd): add regression tests for autoStartTime persistence (#3585)
Source-code guards verifying autoStartTime is saved in paused-session.json,
restored on both resume paths, and falls back to Date.now() when missing.
2026-04-05 21:07:58 -05:00
Jeremy
a0a20599a0 fix(gsd): persist autoStartTime across session resume so elapsed timer survives /exit
autoStartTime was never saved to paused-session.json, so cross-session
resume always started with autoStartTime=0 and the widget showed no
elapsed timer. Now saved on pause, restored on resume with Date.now()
fallback for old files.

Also fixes widget layout: elapsed/ETA stays on the header line above
the milestone/branch info line.
2026-04-05 21:04:05 -05:00
Alan Alwakeel
9711ac3efa test(gsd): add pause wiring and integration tests for enhanced verification
- pre-execution-pause-wiring.test.ts: Tests blocking check → pause control flow
- enhanced-verification-integration.test.ts: End-to-end integration coverage

Verifies that blocking pre-execution failures trigger auto-mode pause and
that the enhanced verification pipeline integrates correctly with existing
verification infrastructure.
2026-04-05 20:25:27 -04:00
Alan Alwakeel
8f2c544a91 fix(gsd): add enhanced_verification preferences to mergePreferences
The enhanced_verification_* preferences were validated and typed but not
included in mergePreferences(), causing project-level overrides to be
silently ignored. This fix ensures project preferences properly merge
with user-level defaults.
2026-04-05 19:47:34 -04:00
Alan Alwakeel
6ee0f40083 feat(gsd): wire blocking behavior and strict mode for enhanced verification
Integrates pre/post-execution checks into auto-mode:
- auto-verification.ts: runEnhancedPreChecks/runEnhancedPostChecks integration
- auto-post-unit.ts: pause control flow when blocking checks fail
- Respects enhanced_verification_strict preference for blocking vs warning

Control flow: blocking failures trigger auto-mode pause for user review.
2026-04-05 19:47:34 -04:00
Alan Alwakeel
a3d08f7125 feat(gsd): add post-execution cross-task consistency checks
Adds 3 post-execution checks that run after task completion:
- Import resolution: verifies relative imports resolve to existing files
- Export verification: confirms exported symbols are defined
- Type consistency: validates function return types match declarations

All checks follow the permissive-by-default pattern (R012) - warnings don't block.
2026-04-05 19:46:31 -04:00
Alan Alwakeel
992b321b63 feat(gsd): add pre-execution plan verification checks
Adds 4 pre-execution checks that run before each task:
- File ops review: surfaces create/edit/delete intent for manual review
- Read-before-create guard: fails when plan reads a file before creating it
- Package existence: verifies npm packages exist before install attempts
- Interface contract: warns on mismatched function signatures

Includes preference types and validation for enhanced_verification settings.
2026-04-05 19:46:31 -04:00
Jeremy McSpadden
24e0856950 Merge pull request #3583 from jeremymcs/fix/welcome-screen-full-width
fix(ui): remove 200-column cap on welcome screen width
2026-04-05 18:43:02 -05:00
Jeremy
0d92f2fbba test(ui): add regression test for full-width separator lines
Verifies separator lines extend to the full terminal width when
the terminal is wider than 200 columns.
2026-04-05 17:57:23 -05:00
Jeremy
efb4e21205 fix(ui): remove 200-column cap on welcome screen width
The welcome screen lines stopped short on wide terminals because
termWidth was capped at 200 columns. Remove the cap so separator
lines extend to the full terminal width.
2026-04-05 17:41:21 -05:00
Jeremy McSpadden
d1b7f6f85c Merge pull request #3570 from Tibsfox/fix/headless-query-extension-drift
fix(headless): sync resources and use agent dir for query
2026-04-05 16:05:56 -05:00
Jeremy McSpadden
2298b9acab Merge pull request #3576 from jeremymcs/feat/llm-safety-harness
feat(gsd): LLM safety harness for auto-mode damage control
2026-04-05 16:03:16 -05:00
Jeremy McSpadden
46b18818a6 Merge pull request #3561 from Tibsfox/fix/ollama-fallback-provider-ready
fix(pi-coding-agent): make Ollama visible to fallback resolver
2026-04-05 15:59:20 -05:00
Jeremy McSpadden
d666fea3a9 Merge pull request #3569 from Tibsfox/fix/update-diagnostics
fix(cli): show latest version and bypass npm cache in update check
2026-04-05 15:57:41 -05:00
Jeremy McSpadden
e17b50b8a4 Merge pull request #3577 from jeremymcs/fix/hardcoded-agent-paths-3575
fix(gsd): replace hardcoded agent skill paths with dynamic resolution
2026-04-05 15:56:49 -05:00
Jeremy
8d11e5d507 test: add regression tests for adversarial review fixes (#3576)
- git-checkpoint: rollback on checked-out branch, detached HEAD, ref cleanup
- ollama streaming: terminal done:true chunk content preservation
- provider registration: preflush clears queue to prevent double registration
2026-04-05 15:52:26 -05:00
Jeremy
ac20eab501 fix: address adversarial review findings for #3576
- Use `git reset --hard <sha>` for rollback instead of `git branch -f`
  which fails on checked-out branches and worktrees
- Clear pendingProviderRegistrations after preflush to prevent duplicate
  registration when bindCore() runs
- Process Ollama stream content on terminal `done:true` chunks to avoid
  truncating trailing assistant text
2026-04-05 15:48:25 -05:00
Jeremy McSpadden
369303f82f Merge pull request #3560 from Tibsfox/fix/ollama-stream-simple-crash
fix(ollama): use apiKey auth mode to avoid streamSimple crash
2026-04-05 15:22:38 -05:00
Jeremy McSpadden
adeedef328 Merge pull request #3562 from jeremymcs/fix/harden-flat-rate-guard
fix(gsd): harden flat-rate routing guard against alias/resolution gaps
2026-04-05 15:16:01 -05:00
Jeremy McSpadden
d3a38bb771 Merge pull request #3552 from Tibsfox/fix/disable-routing-copilot
fix(gsd): disable dynamic model routing for flat-rate providers
2026-04-05 15:15:50 -05:00
Jeremy
6d19cd6baf fix(gsd): replace hardcoded agent skill paths with dynamic resolution (#3575)
The system prompt hardcoded ~/.gsd/agent/skills/ paths for bundled skills,
causing ENOENT loops when skills weren't installed at those locations. The
auto-mode loop treated ENOENT as transient and retried indefinitely.

- Replace hardcoded skill paths in system.md with {{bundledSkillsTable}} template
  variable, resolved dynamically via resolveSkillReference() at runtime
- Replace hardcoded templates dir path with {{templatesDir}} variable
- Add buildBundledSkillsTable() to system-context.ts — only includes skills
  that actually exist on disk
- Export getTemplatesDir() from prompt-loader.ts
- Add Rule 4 to detect-stuck.ts: same ENOENT path seen twice in the sliding
  window triggers immediate stuck detection (missing files don't self-heal)
- Add 4 tests for Rule 4 coverage

Closes #3575
2026-04-05 15:12:19 -05:00