Commit graph

264 commits

Author SHA1 Message Date
github-actions[bot]
c4286f4c57 release: v2.40.0 2026-03-20 21:54:27 +00:00
Derek Pearson
83bacfcc94 feat(pi): add Skill tool resolution (#1661)
* fix(gsd extension): detect initialized projects in health widget

Use .gsd presence plus project-state detection for the health widget so bootstrapped projects no longer appear as unloaded before metrics exist.

* fix(gsd extension): detect initialized projects in health widget

Use .gsd presence plus project-state detection for the health widget so bootstrapped projects no longer appear as unloaded before metrics exist.

* feat: add Skill tool resolution for Pi agent

Expose a built-in Skill tool so dispatched prompts can resolve skill names without guessing file paths. This aligns runtime behavior with skill activation prompts and adds coverage for exact activation and unknown-skill handling.
2026-03-20 15:42:28 -06:00
TÂCHES
cc2c887948 Refactor GSD command and bootstrap modules (#1634)
* Refactor GSD command/bootstrap modules

* fix: resolve TypeScript build errors in refactored db-tools and catalog

- db-tools.ts: add missing execute callback params (signal, onUpdate, ctx),
  remove isError from return objects (not in AgentToolResult type), cast
  details as any to avoid union type mismatch across error/success paths
- catalog.ts: use Object.entries() on TemplateRegistry.templates Record
  instead of treating it as an array, use Record key as template id

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

* fix: update source-contract tests to reference refactored file locations

The god-file refactor moved code from index.ts and commands.ts into
bootstrap/agent-end-recovery.ts, bootstrap/register-hooks.ts, and
commands/handlers/core.ts. Update three test files to read from the
correct paths and adjust pattern assertions to match the new code
structure.

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-20 15:19:16 -06:00
github-actions[bot]
2d08391649 release: v2.39.0 2026-03-20 19:41:22 +00:00
Derek Pearson
90d6d71e38 feat(gsd): activate matching skills in dispatched prompts (#1630)
* fix(gsd extension): detect initialized projects in health widget

Use .gsd presence plus project-state detection for the health widget so bootstrapped projects no longer appear as unloaded before metrics exist.

* fix(gsd extension): detect initialized projects in health widget

Use .gsd presence plus project-state detection for the health widget so bootstrapped projects no longer appear as unloaded before metrics exist.

* feat(gsd): activate matching skills in dispatched prompts

Inject skill activations from installed skills, preferences, and task-plan handoff so GSD agents load the right skills automatically instead of relying on generic guidance. Align prompt templates and tests with the activation flow and current resource sync behavior.

* fix(gsd extension): detect initialized projects in health widget

Use .gsd presence plus project-state detection for the health widget so bootstrapped projects no longer appear as unloaded before metrics exist.

* fix(gsd extension): restore health widget build paths

* test(resource-loader): fix sibling cleanup assertion
2026-03-20 13:20:06 -06:00
TÂCHES
7564901868 fix: auto-resolve npm subpath exports in extension loader (#1624)
Extensions importing unlisted subpaths from bundled packages (e.g.
@modelcontextprotocol/sdk/server) fail because jiti's CJS fallback
double-resolves paths. This adds auto-discovery of subpath exports from
bundled packages' package.json exports fields, generating alias entries
for all explicit and wildcard subpaths so extensions can import any
standard Node.js subpath export.

Closes #1604

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 10:53:10 -06:00
TÂCHES
43d8dbc9d3 fix: update Anthropic OAuth endpoints to platform.claude.com (#1608)
Anthropic migrated their OAuth infrastructure from console.anthropic.com
to platform.claude.com. The old URLs are decommissioned, breaking all
OAuth login flows.

Closes #1587

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 10:27:20 -06:00
Jeremy McSpadden
b580f64144 fix: apply pi manifest opt-out to extension-discovery.ts (#1545)
* fix: apply pi manifest opt-out to extension-discovery.ts (#1537 follow-up)

The cmux fix in #1537 patched resolveExtensionEntries() in
packages/pi-coding-agent/src/core/extensions/loader.ts to honor
"pi": {} as an opt-out from auto-discovery. However, there is a
second copy of resolveExtensionEntries() in src/extension-discovery.ts
that was not updated. This is the version actually used at startup
by loader.js via discoverExtensionEntryPaths().

As a result, cmux/index.js is still discovered and loaded as an
extension on startup, producing:
  Extension does not export a valid factory function: .../cmux/index.js

Fix: Apply the same authoritative-manifest logic to the
extension-discovery.ts copy. When a package.json has a "pi" field,
treat it as authoritative and return early — either with declared
extension paths or an empty array for library opt-out.

Tests: 7 new tests covering resolveExtensionEntries and
discoverExtensionEntryPaths behavior for opt-out, declared
extensions, and fallback discovery.

* fix: apply pi manifest opt-out to package-manager.ts (third copy)

There are THREE copies of resolveExtensionEntries():
1. packages/pi-coding-agent/src/core/extensions/loader.ts (fixed in #1537)
2. src/extension-discovery.ts (fixed in previous commit)
3. packages/pi-coding-agent/src/core/package-manager.ts (THIS commit)

Copy #3 is used by collectAutoExtensionEntries() which is called from
addAutoDiscoveredResources() during DefaultPackageManager.resolve().
This is the actual code path that discovers ~/.gsd/agent/extensions/cmux
and passes it to loadExtensions(), producing the factory function error.

* fix: rewrite pi.extensions .ts paths to .js during resource copy

copy-resources.cjs compiles .ts → .js via tsc but copies package.json
files verbatim. Extensions with pi.extensions: ["./index.ts"] end up
in dist/ pointing to a .ts file that doesn't exist (only .js does).

This causes resolveExtensionEntries() to find no valid entry points,
silently skipping the extension. Affected: gsd, browser-tools, context7,
google-search, universal-config — all extensions with pi manifests.

Fix: When copying package.json files, rewrite .ts/.tsx extensions in
pi.extensions arrays to .js so they match the compiled output.

* fix: add missing commands to /gsd description and rate sub-completions

- Add 9 missing commands to the description string: widget, rate, park,
  unpark, init, setup, logs, inspect, extensions
- Add sub-completions for /gsd rate (over/ok/under)

* feat: grid layout for parallel cmux splits and completion trailing-space fix

CmuxClient.createGridLayout(count) pre-creates a tiled grid of surfaces
before launching parallel agents, instead of the previous approach of
creating splits per-agent with alternating right/down directions.

Grid layout strategy:
  1 agent:  [gsd | A]
  2 agents: [gsd | A]    (A split down)
            [    | B]
  3 agents: [gsd | A]    (2x2 grid)
            [ C  | B]
  4 agents: [gsd | A]    (additional splits from bottom-right)
            [ C  | B]
            [    | D]

Changes:
- Add CmuxClient.createSplitFrom(sourceSurfaceId, direction) to split
  from a specific surface rather than always the gsd surface
- Add CmuxClient.createGridLayout(count) that builds the grid and
  returns surface IDs in order
- Update runSingleAgentInCmuxSplit to accept a pre-created surface ID
  (string) or a direction for backward compatibility
- Parallel dispatch pre-creates grid, assigns each agent a surface
- Fix getArgumentCompletions trailing-space handling so sub-completions
  work (e.g., /gsd cmux <tab> now shows status/on/off/etc.)
- 5 new tests for grid layout logic
2026-03-20 08:11:51 -06:00
github-actions[bot]
1b2ff19615 release: v2.38.0 2026-03-20 07:07:25 +00:00
Nathan Roe
39cd932abb feat: add anthropic-vertex provider for Claude on Vertex AI (#1533)
* feat: add anthropic-vertex provider for Claude models on Google Vertex AI

Add a new anthropic-vertex provider that enables using Claude models
(Opus 4.6, Sonnet 4.6, Haiku 4.5) through Google Vertex AI using the
@anthropic-ai/vertex-sdk package. Follows the same pattern as the
existing google/google-vertex provider split.

Detection uses ANTHROPIC_VERTEX_PROJECT_ID (same env var as Claude Code)
with CLOUD_ML_REGION for region selection, falling back to us-central1.

Extracts shared Anthropic utilities into anthropic-shared.ts (message
conversion, tool conversion, param building, stream processing) to
avoid duplication between anthropic.ts and anthropic-vertex.ts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add full Claude model set for anthropic-vertex provider

Add 200K context window variants for Opus 4.6 and Sonnet 4.6, plus
older models (Sonnet 4.5, Sonnet 4, Opus 4.5, Opus 4.1, Opus 4, Haiku 4.5).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: add @anthropic-ai/vertex-sdk to root dependencies

Required for the published package to resolve the vertex SDK at runtime.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: remove unnecessary comments to match codebase style

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: remove duplicate stream functions after rebase

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Nathan Roe <nathan.roe@carvana.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 23:14:13 -06:00
github-actions[bot]
65647f83af release: v2.37.1 2026-03-20 04:08:02 +00:00
Jeremy McSpadden
71c3b12e70 fix: cmux library directory incorrectly loaded as extension (#1537)
* fix(#1526): auto-mode worktree commits land on main instead of milestone branch

GitServiceImpl.getMainBranch() was designed to detect manual /worktree worktrees
(worktree/<name> branches) but incorrectly applied the same logic to auto-mode
worktrees (milestone/<MID> branches). When no worktree/<name> branch existed,
it fell back to the current branch, which in certain contexts could be main,
causing slice commits to land on main instead of the milestone branch.

Fix: Detect if currently on a milestone/* branch first (auto-mode case) and
return it, before checking for worktree/* branches (manual worktree case).

- Modify getMainBranch() to detect milestone branches first
- Add test verifying getMainBranch() returns correct branch in auto-worktree
- All tests pass, build succeeds

Fixes #1526

* fix: cmux library directory incorrectly loaded as extension

The extension auto-discovery in resolveExtensionEntries() finds
index.js files in subdirectories and treats them as extensions.
The cmux directory has an index.js but it's a utility library
(imported by gsd and subagent extensions), not an extension itself.

Two changes:
1. When a package.json has a "pi" manifest, treat it as authoritative
   and don't fall through to index.ts/index.js auto-detection. This
   lets library directories opt out with "pi": {}.
2. Add package.json to cmux directory with empty pi manifest.
2026-03-19 21:14:25 -06:00
github-actions[bot]
f83a85eb7c release: v2.37.0 2026-03-20 02:50:52 +00:00
Jeremy McSpadden
b247c3510e feat: integrate cmux with gsd runtime (#1532) 2026-03-19 20:05:06 -06:00
github-actions[bot]
37d657b949 release: v2.36.0 2026-03-20 01:26:46 +00:00
TÂCHES
d57c6d4e46 fix: preserve user messages during abort with origin-aware queue clearing (#1439) (#1521)
When a user presses Escape during streaming, the abort flow clears all
queued messages indiscriminately. User messages typed during streaming
are silently discarded. This adds a QueueEntry wrapper in the Agent class
to track message origin ("user" vs "system"), so that clearQueue() can
preserve user-typed messages while discarding system-generated ones.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 18:05:04 -06:00
Tom Boucher
8aa71bfb55 fix: prevent ensureGitignore from adding .gsd when tracked in git (#1364) (#1367)
* rfc: GitOps branching & versioning strategy proposal

Proposes a Git-Flow Lite model with automated integration branches:

  main          ← production-ready, tagged releases only
  next          ← integration branch for next minor (PRs target here)
  release/X.Y   ← stabilization branch, only bugfixes allowed
  hotfix/X.Y.Z  ← emergency fixes cherry-picked to release

Includes:
  - RFC document with lifecycle diagrams, migration path, open questions
  - Workflow scaffolds (in docs/proposals/workflows/, NOT .github/):
    - create-release.yml: manual dispatch to cut release branch from next
    - sync-next.yml: auto-sync next branch after version tags
    - backmerge.yml: auto back-merge release fixes to next

This is an experimental proposal requesting community feedback before
any implementation. The workflow files are inert scaffolds — they do
not run in CI.

* fix: prevent ensureGitignore from adding .gsd when tracked in git (#1364)

CRITICAL DATA-LOSS FIX: ensureGitignore() unconditionally added '.gsd' to
.gitignore even when .gsd/ was a real git-tracked directory, causing git to
report ~889 tracked files as deleted.

Root cause: BASELINE_PATTERNS included '.gsd' unconditionally, and the
gitignore modification ran BEFORE migration checks in auto-start.ts.

Changes:
- Add hasGitTrackedGsdFiles() helper using nativeLsFiles to detect tracked
  .gsd/ content
- ensureGitignore() now skips the '.gsd' pattern when .gsd/ has tracked files
- untrackRuntimeFiles() now skips entirely when .gsd/ has tracked files
- migrateToExternalState() aborts when .gsd/ has tracked files
- Reorder auto-start.ts: migration runs BEFORE gitignore modification
- Add 8 regression tests covering all scenarios

Fixes #1364

* fix: break recursive dialog loop when all milestones complete (#1348)

Two interacting bugs:

1. Recursive dialog loop: When all milestones are complete, bootstrapAutoSession
   calls showSmartEntry → sets pendingAutoStart → checkAutoStartAfterDiscuss
   calls startAuto → bootstrapAutoSession → showSmartEntry → infinite loop.
   The discuss workflow completes without producing a milestone directory, so
   phase stays 'complete' and the cycle never breaks.

   Fix: Add a re-entry counter (_consecutiveCompleteBootstraps) that tracks
   how many times bootstrapAutoSession enters the 'complete' branch without
   advancing. After 2 consecutive attempts, break the loop with a warning
   message and return false.

2. Missing _releaseFunction = null in retry lock onCompromised handler:
   The retry lock path in session-lock.ts set _lockCompromised but didn't
   null out _releaseFunction, which could leave a stale reference that
   masks the compromise detection in validateSessionLock().

Fixes #1348

* fix: self-heal stale roadmap checkbox for interrupted complete-slice (#1350)

When complete-slice is interrupted after writing SUMMARY.md and UAT.md but
before flipping the roadmap checkbox, auto-mode enters an infinite loop —
re-launching the same complete-slice unit because the dispatch loop uses
the roadmap checkbox as the sole 'slice done' signal.

Fix: Add a self-heal case in selfHealRuntimeRecords that detects when
SUMMARY + UAT exist but the roadmap checkbox is unchecked, and auto-fixes
the checkbox. This allows the verification to pass and the dispatch loop
to advance.

Fixes #1350

* fix: add EISDIR guard to complete/validate milestone prompts (#1343)

The LLM was passing tasks/ directory paths to the read tool during
milestone completion, causing EISDIR crashes. Added file system safety
instructions to both complete-milestone and validate-milestone prompts
telling the LLM to use ls/find for directory listing, not the read tool.

Fixes #1343

* feat: improve extension conflict messages with removal guidance (#1347)

When a user extension registers tools/commands that now ship as built-ins,
the conflict message now includes '(built-in tool supersedes — consider
removing <path>)' and the log level is downgraded from 'Extension load error'
to 'Extension conflict'.

Changes:
- resource-loader.ts: detect built-in vs user extension conflicts, add hint
- cli.ts: downgrade severity for superseded-tool conflicts

Fixes #1347

* test: fix always-skipped preferences test, add test:marketplace script

- preferences.test.ts: Replace always-skipped getIsolationMode test with
  a filesystem-independent version that validates the default through
  validatePreferences() instead of reading ~/.gsd/preferences.md.
  Reduces skipped count from 3 → 2.

- package.json: Add test:marketplace script for running marketplace
  contract tests (claude-import-tui, plugin-importer-live,
  marketplace-discovery) with GSD_TEST_CLONE_MARKETPLACES=1.
  These tests need external repos and self-skip in unit test runs.

Remaining 2 skips:
- Marketplace contract test suites (need external repos, run via test:marketplace)
- Windows-only tests in validate-directory.test.ts are platform-conditional
  and correctly skip on macOS

* fix: use execFileSync in regression tests for Windows portability

The regression tests used execSync with shell-dependent constructs:
- '&&' command chaining (works in bash/cmd but fragile)
- Single-quoted commit messages (bash-only, cmd.exe splits on spaces)

Replaced with execFileSync via a git() helper that bypasses the shell
entirely. Each git operation is a separate call with proper argument
arrays, eliminating all shell interpretation issues.

Fixes windows-portability CI failure.

* fix: guard milestone completion against missing slice summaries (#1368)

Auto-mode could report a milestone as complete after executing only the
last slice, skipping earlier unexecuted slices. The milestone completion
signal fired based on roadmap checkbox state, which could be stale or
inconsistent after worktree transitions.

Changes:
- auto-dispatch.ts: Added slice SUMMARY file existence check to both
  validating-milestone and completing-milestone dispatch rules. If any
  slice lacks a SUMMARY file, dispatch stops with a diagnostic error
  instead of proceeding to validation/completion.
- validate-milestone.test.ts: Updated tests to create slice summary
  files (required by the new guard).
- file-watcher.test.ts: Fixed flaky 'auth.json change emits auth-changed
  event' test by adding watcher initialization delay and increasing event
  propagation timeout (race condition when run in full suite).

Fixes #1368

* fix: warn on common misspelled preference keys + verify field guidance (#1373, #1341)

#1373: Users setting 'taskIsolation.mode: none' instead of 'git.isolation: none'
got a generic 'unknown key' warning. Added KEY_MIGRATION_HINTS that map common
misspellings (taskIsolation, task_isolation, isolation, manage_gitignore, auto_push,
main_branch) to their correct git.* equivalents with actionable messages.

#1341: Planning agent writes aspirational prose in Verify fields ('Sections 3.1
and 3.2 exist with exact formulas. Zero TBD.') instead of executable commands.
Added explicit verify field rules to the plan template: must be mechanically
executable, with examples of good vs bad patterns for content tasks.

Fixes #1373, partially addresses #1341

* refactor: extract roadmap-mutations.ts + shared test-utils.ts

Consolidation:
- roadmap-mutations.ts: Extracted markSliceDoneInRoadmap() and markTaskDoneInPlan()
  from duplicated implementations in doctor.ts, mechanical-completion.ts, and
  auto-recovery.ts. All three callers used identical regex patterns.
  mechanical-completion.ts and auto-recovery.ts now import the shared utility.
  (doctor.ts deferred — touched by PR #1349)

- test-utils.ts: Shared cross-platform test utilities for GSD extension tests.
  Provides git() helper (execFileSync, no shell), makeTempRepo() with
  core.autocrlf=false, cleanup(), createFile(), safeReadFile(), and
  writeMilestoneFixture(). 12 test files currently define their own versions
  of these helpers — new tests should import from test-utils.ts instead.

Security audit: No injection vectors (sid/tid are alphanumeric from roadmap
parser), no path traversal, no secrets, no new dependencies.

* fix: port conflict false positive on non-Node projects + paused worktree resume (#1381, #1383)

projects without package.json. macOS AirPlay Receiver listens on port 5000,
causing a spurious warning on non-Node projects.
Fix: Skip port checks entirely when no package.json exists. When using
default ports, filter out 5000 on macOS.

in-memory only. Re-entering /gsd started a fresh bootstrap from the project
root instead of the active worktree.
Fix: pauseAuto() now writes paused-session.json to .gsd/runtime/ with
milestoneId, worktreePath, originalBasePath, and stepMode. startAuto()
checks for this file before bootstrap and restores the paused session
context, including worktree re-entry. stopAuto() cleans up the file.

Fixes #1381, #1383

* fix: catch spawn ENOENT in uncaught exception guard + snapshot session lock path (#1384, #1363)

uncaught exception and crashes auto-mode. The EPIPE guard now also catches
ENOENT from spawn syscalls — logs the error and continues instead of
terminating the process.

the lock path differently via gsdRoot() because basePath could be either the
project root or a worktree path. gsdRoot() produces different results for
each, so the lock was written to one path and validated against another.
Fix: Snapshot the resolved lock path (_snapshotLockPath) at acquisition time
and reuse it for all subsequent lock operations within the session.

Fixes #1384, #1363

* fix: suppress false-positive lock compromise + skip migration with active worktrees (#1362, #1337)

because the event loop stall delays the heartbeat mtime update. The handler
now checks elapsed time since acquisition — if within the 30-minute stale
window, it logs a warning and continues instead of setting _lockCompromised.
Real takeovers (past the stale window) still trigger the compromise flag.

even when .gsd/worktrees/ contained active git worktrees with locked
directory handles. This caused EBUSY errors and destructive data loss.
Migration now checks for active worktree directories and skips entirely
if any are found.

Fixes #1362, #1337
2026-03-19 17:06:01 -06:00
TÂCHES
ad01d0ada4 Merge pull request #1365 from jbrahy/fix/openai-reasoning-encrypted-content-always-include
fix: always include reasoning.encrypted_content for OpenAI reasoning models
2026-03-19 16:38:24 -06:00
github-actions[bot]
290b2b2a25 release: v2.35.0 2026-03-19 22:05:29 +00:00
TÂCHES
efc23a2342 Merge pull request #1498 from gsd-build/fix/lsp-get-server-for-file
fix: restore LSP single-server selector export
2026-03-19 15:53:26 -06:00
TÂCHES
cc17d20820 Merge pull request #1457 from frizynn/refactor/agent-session-model-switching
refactor: consolidate model switching logic in agent-session
2026-03-19 15:52:12 -06:00
TÂCHES
45193d5499 Merge pull request #1458 from frizynn/refactor/resource-loader-generics
refactor: consolidate resource-loader duplicate methods into generics
2026-03-19 15:52:01 -06:00
TÂCHES
b5563e18c6 Merge pull request #1459 from frizynn/refactor/shared-lock-utils
refactor: extract shared file lock utilities
2026-03-19 15:51:47 -06:00
TÂCHES
a23c69aaae Merge pull request #1468 from frizynn/refactor/oauth-utils-consolidation
refactor: consolidate Google OAuth callback server and helper utilities
2026-03-19 15:50:59 -06:00
TÂCHES
0259f0f2e3 Merge pull request #1479 from frizynn/refactor/rpc-mode-dedup
refactor: deduplicate RPC mode shared patterns
2026-03-19 15:50:03 -06:00
TÂCHES
00b18460e9 Merge pull request #1481 from frizynn/refactor/tui-rendering-dedup
refactor: deduplicate rendering patterns in markdown and keys
2026-03-19 15:49:29 -06:00
TÂCHES
0c2105d71d Merge pull request #1484 from frizynn/refactor/agent-session-decomposition
refactor: extract retry handler and compaction orchestrator from agent-session
2026-03-19 15:48:59 -06:00
TÂCHES
86ada3a345 Merge pull request #1480 from frizynn/refactor/openai-providers-shared-base
refactor: consolidate shared code between OpenAI providers
2026-03-19 15:48:17 -06:00
Lex Christopherson
5e501d59a0 fix: restore lsp single-server selector export 2026-03-19 15:46:20 -06:00
TÂCHES
5ab6fa2853 Merge pull request #1448 from frizynn/refactor/deduplicate-small-utilities
refactor: deduplicate toPosixPath, ZERO_USAGE, and shortenPath utilities
2026-03-19 15:46:13 -06:00
TÂCHES
dea2f1a426 Merge pull request #1449 from frizynn/refactor/compaction-helpers-extraction
refactor: extract shared helpers in compaction module
2026-03-19 15:45:21 -06:00
TÂCHES
cb9bd2bc99 Merge pull request #1447 from frizynn/refactor/extension-runner-emit-consolidation
refactor: consolidate extension runner emit methods into shared invokeHandlers
2026-03-19 15:44:37 -06:00
TÂCHES
671b72b684 Merge pull request #1446 from frizynn/refactor/extension-type-guards-consolidation
refactor: consolidate extension type guards and inline handler aliases
2026-03-19 15:44:17 -06:00
TÂCHES
66bca9c8a2 Merge pull request #1477 from frizynn/refactor/tree-render-shared-utils
refactor: extract shared tree rendering utilities
2026-03-19 15:40:26 -06:00
TÂCHES
e01536c8a3 Merge pull request #1445 from frizynn/refactor/lsp-deduplication
refactor: consolidate duplicate patterns in LSP module
2026-03-19 15:40:07 -06:00
TÂCHES
364bd5b65b Merge pull request #1430 from trek-e/fix/1423-session-cost-compaction
fix: accumulate session cost independently of message array (#1423)
2026-03-19 15:39:19 -06:00
Juan Francisco Lebrero
da2af65971 refactor: deduplicate error emission and message patterns in agent-core (#1444)
- Extract emitMessagePair() to consolidate 6 message_start/message_end push pairs in agent-loop.ts
- Extract emitErrorSequence() to deduplicate identical catch blocks in agentLoop and agentLoopContinue
- Export ZERO_USAGE constant and reuse it in agent.ts instead of inline object literals
- Merge identical message_start/message_update switch cases in Agent._runLoop
- Extract Agent._updatePendingToolCalls() to consolidate tool_execution_start/end Set mutation
2026-03-19 15:39:12 -06:00
Juan Francisco Lebrero
54b1446fb2 refactor: simplify settings manager with generic setter helpers (#1461)
Replace 30+ repetitive setter method bodies with four generic private
helpers: setGlobalSetting, setScopedSetting, setNestedGlobalSetting,
and setProjectSetting. Each setter method retains its original public
signature and behavior — only the internal implementation is consolidated.

Methods with custom logic (setEditorPaddingX, setAutocompleteMaxVisible,
setSearchExcludeDirs, setFallbackChain, removeFallbackChain,
setDefaultModelAndProvider) are left unchanged or minimally adapted.

Net reduction: 79 lines (164 deleted, 85 added).
2026-03-19 15:37:24 -06:00
Juan Francisco Lebrero
988ef61488 refactor: consolidate theme files and remove manual schema (#1478)
- Delete theme-schema.json (335 lines): redundant with the TypeBox
  schema already defined in theme.ts, only referenced via $schema URLs
  in the JSON files for editor autocomplete.
- Delete dark.json (85 lines) and light.json (84 lines): move built-in
  theme definitions into themes.ts as TypeScript objects, eliminating
  runtime filesystem reads and the getThemesDir() dependency.
- Export ThemeJson type from theme.ts so themes.ts can reference it.
- Net reduction: ~319 lines removed.
2026-03-19 15:35:56 -06:00
Juan Francisco Lebrero
aa85e99dc0 refactor: extract overlay layout and compositing from TUI into separate module (#1482)
Move overlay positioning (resolveOverlayLayout, resolveAnchorRow/Col),
line compositing (compositeLineAt, compositeOverlays, applyLineResets),
cursor extraction, and size parsing into overlay-layout.ts. These are
pure functions with no TUI state dependencies, reducing tui.ts from
1,200 to 899 lines.
2026-03-19 15:35:00 -06:00
Juan Francisco Lebrero
334a7cf076 refactor: extract slash command handlers from interactive-mode (#1485)
Move slash command dispatch logic and 12 individual command handlers
(/export, /share, /copy, /name, /session, /changelog, /hotkeys,
/compact, /thinking, /edit-mode, /arminsayshi, plus showThinkingSelector)
into a new slash-command-handlers.ts module.

InteractiveMode now delegates to dispatchSlashCommand() via a
SlashCommandContext interface, keeping the integration surface minimal.
Handlers that are also invoked from keybindings/events remain on
InteractiveMode and are accessed through the context.

Reduces interactive-mode.ts from 4,783 to 4,272 lines (-511).
2026-03-19 15:34:14 -06:00
Juan Francisco Lebrero
4e29ca4544 refactor: remove dead code (unused exports) (#1486)
Remove exported functions/constants/classes that are never imported
anywhere else in the codebase:

Fully removed (not used anywhere):
- nativeAvailable (native)
- getApiProviders, unregisterApiProviders (pi-ai/api-registry)
- createAssistantMessageEventStream (pi-ai/event-stream)
- getOverflowPatterns (pi-ai/overflow)
- validateToolCall (pi-ai/validation)
- getToolsDir (pi-coding-agent/config)
- emitSessionShutdownEvent (extensions/runner)
- syncContent, notifySaved (lsp/client)
- getServerForFile, hasCapability (lsp/config)
- severityToIcon, formatPosition, formatTextEdit, symbolKindToName (lsp/utils)
- clearApiKeyCache (model-registry)
- restoreModelFromSession (model-resolver)
- isLightTheme (theme)
- loadPhoton + all internal helpers (photon)
- extractAnsiCode (pi-tui/utils)

De-exported (used locally, not externally):
- extractRetryAfterMs, inferCopilotInitiator, extractRetryDelay,
  buildRequest, requiresToolCallId, registerBuiltInApiProviders,
  streamProxy, isBunRuntime, detectInstallMethod, getPackageDir,
  getPackageJsonPath, ansiToHtml, DEFAULT_APP_KEYBINDINGS,
  DEFAULT_KEYBINDINGS, shutdownClient, sendNotification, shutdownAll,
  applyTextEditsToString, wrapWithLspmux, severityToString,
  COMPACTION_SUMMARY_PREFIX/SUFFIX, BRANCH_SUMMARY_PREFIX/SUFFIX,
  bashExecutionToText, defaultModelPerProvider, parseModelPattern,
  parseCommandArgs, substituteArgs, loadEntriesFromFile,
  findMostRecentSession, FileSettingsStorage, InMemorySettingsStorage,
  migrateAuthToAuthJson, migrateSessionsFromAgentRoot,
  parseSearchQuery, matchSession, compareVersions, isWaylandSession,
  getToolPath, wordWrapLine
2026-03-19 15:33:32 -06:00
github-actions[bot]
f196309295 release: v2.34.0 2026-03-19 21:08:44 +00:00
TÂCHES
d761e45a41 M001: The Minimal Machine — linear auto-loop, sole-authority state, sidecar queue, WorktreeResolver (#1419)
* refactor: replace recursive auto-dispatch with linear autoLoop, delete ~3k lines of dead code

Replace the complex recursive dispatch system (dispatchNextUnit, reentrancy
guards, stall detection, idempotency tracking, skip-depth machinery) with a
simple linear while(s.active) loop in auto-loop.ts.

Key changes:
- New auto-loop.ts with autoLoop(), runUnit(), resolveAgentEnd()
- Deleted auto-idempotency.ts, auto-stuck-detection.ts, session-lock.ts,
  mechanical-completion.ts, progress-score.ts, auto-constants.ts, unit-id.ts
- Extracted WorktreeResolver class for worktree path resolution
- Added auto-worktree-sync.ts for worktree synchronization
- Simplified auto.ts from ~1400 lines to ~400 lines
- Fixed 9 TypeScript errors (NotifyCtx type widening, capture typing)
- Comprehensive test coverage: 32 auto-loop tests + worktree resolver/DB tests

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

* fix: address 6 audit findings in auto-loop refactor

1. CRITICAL: Move pendingResolve to AutoSession + queue orphaned agent_end
   events instead of silently dropping them. Prevents permanent stalls when
   error-recovery sendMessage retries fire between loop iterations.

2. HIGH: Scope pendingResolve per-session via _activeSession ref, preventing
   concurrent /gsd auto sessions from corrupting each other's promises.

3. HIGH: Replace console.log in dispatchHookUnit with debugLog to prevent
   hook prompt content (potentially containing secrets) from leaking to stdout.

4. HIGH: Restore parked milestone handling in state.ts — Phase 1 skips
   parked milestones so they don't satisfy depends_on, Phase 2 registers
   them as 'parked' status. Add 'parked' to MilestoneRegistryEntry type.

5. MEDIUM: Restore queuePhaseActive parameter in shouldBlockContextWrite
   and re-export setQueuePhaseActive for guided-flow-queue.ts consumers.

6. MEDIUM: Add MAX_LOOP_ITERATIONS (500) lifetime cap to autoLoop to prevent
   runaway loops when units alternate between IDs.

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

* fix: resolve build breakers, add correctness fixes, and graduated recovery

Build breakers (CRITICAL):
- Restore unit-id.ts (deleted but still imported by complexity-classifier.ts, metrics.ts)
- Restore progress-score.ts (deleted but still imported by commands.ts, dashboard-overlay.ts, doctor.ts)
- Rewrite worktree-sync-milestones.test.ts to use new syncProjectRootToWorktree API

Correctness fixes (MEDIUM):
- Cap pendingAgentEndQueue to 3 entries to prevent unbounded growth from stale events
- Add milestoneId path traversal validation in WorktreeResolver
- Clear depthVerificationDone on session_start to prevent cross-session leaks in RPC mode
- Add verification gate for non-hook sidecar units (triage, quick-tasks)
- Remove dead handleAgentEnd import from index.ts

Graduated recovery (Jeremy's feedback):
- Blanket try/catch around loop body — one bad iteration no longer kills the session
- Graduated stuck recovery: at count 3 try artifact verification + cache invalidation,
  at count 5 hard stop (was: binary stop at 5 with no recovery attempt)
- Graduated error recovery: 1st error retries, 2nd invalidates caches, 3rd stops

Test results: 32/32 auto-loop, 28/28 worktree-resolver, 11/11 sidecar-queue, tsc clean.

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

* fix: restore copyWorktreeDb/reconcileWorktreeDb exports and fix loadToolApiKeys import

Two missing exports caused ~90% of the 120 pre-existing test failures:

1. copyWorktreeDb + reconcileWorktreeDb — imported by auto-worktree.ts but
   never added to gsd-db.ts. Restored with the original implementations.
2. loadToolApiKeys — moved to commands-config.ts but index.ts still imported
   from commands.ts. Fixed the import path.

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

* fix: move loadToolApiKeys import to commands-config.js

loadToolApiKeys was moved to commands-config.ts but index.ts still
imported it from commands.ts, causing runtime failures in all tests
that transitively load the extension entry point.

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

* test: fix provider error assertion on windows

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 14:56:00 -06:00
frizynn
3090f968f4 refactor: extract retry handler and compaction orchestrator from agent-session
Extract two self-contained subsystems from agent-session.ts (3,367 -> 2,737 lines):

- RetryHandler: auto-retry with exponential backoff, credential rotation,
  and cross-provider fallback logic
- CompactionOrchestrator: manual/auto compaction, overflow recovery, and
  extension integration for custom compaction providers

Also add shared getErrorMessage() utility to replace repeated
`err instanceof Error ? err.message : String(err)` patterns.

The extracted modules receive AgentSession state via dependency injection
interfaces, avoiding state duplication. AgentSession remains the coordinator
that delegates to these modules.
2026-03-19 16:46:14 -03:00
frizynn
9938fb3730 refactor: deduplicate rendering patterns in markdown and keys
markdown.ts: Extract renderCodeBlock() helper to eliminate duplicated
code block rendering between renderToken and renderListItem.

keys.ts: Consolidate LEGACY_KEY_SEQUENCES, LEGACY_SHIFT_SEQUENCES, and
LEGACY_CTRL_SEQUENCES into a single LEGACY_SEQUENCES structure with
plain/shift/ctrl variants per key. Auto-generate LEGACY_SEQUENCE_KEY_IDS
from this structure instead of hand-maintaining a 50+ entry reverse
lookup. Extract hasKittyEventType() to deduplicate isKeyRelease and
isKeyRepeat. Net reduction of ~80 lines.
2026-03-19 16:39:18 -03:00
frizynn
1c5fdc9144 refactor: consolidate shared code between OpenAI providers
Extract duplicated patterns from openai-completions.ts,
openai-responses.ts, and azure-openai-responses.ts into a new
openai-shared.ts module:

- getOpenAIClass: unified lazy SDK loading (was duplicated in both)
- createOpenAIClient: shared client creation with Copilot headers,
  options header merging, and lazy loading (was ~30 lines each)
- buildInitialOutput: AssistantMessage initialization (was ~15 lines x3)
- assertStreamSuccess / finalizeStream / handleStreamError: stream
  lifecycle helpers (was ~10 lines each x3)
- clampReasoningForModel: reasoning effort clamping for gpt-5.x models
  (was duplicated in openai-responses.ts and azure-openai-responses.ts)

Net reduction: ~185 lines removed across the three provider files.
2026-03-19 16:39:12 -03:00
frizynn
502067c213 refactor: deduplicate RPC mode shared patterns
Extract the duplicated commandContextActions implementations from
rpc-mode.ts and print-mode.ts into a shared
createDefaultCommandContextActions() factory in
modes/shared/command-context-actions.ts.

Both headless modes (RPC and print) had identical implementations of
waitForIdle, newSession, fork, navigateTree, switchSession, and reload
that simply delegate to AgentSession. The shared factory provides these
defaults; interactive mode continues to layer TUI-specific behavior on
top via its own overrides.

Also fixes a subtle redundancy in print mode where newSession manually
called options.setup after session.newSession(), even though
session.newSession() already handles the setup callback internally.
2026-03-19 16:38:51 -03:00
frizynn
6cb8e3c524 refactor: extract shared tree rendering utilities
Extract duplicated tree rendering logic from tree-selector.ts and
session-selector.ts into tree-render-utils.ts:

- computeScrollWindow: centered scroll window calculation
- renderCursor: accent-colored selection cursor indicator
- applyRowHighlight: selected-row background + truncation
- renderScrollPosition: muted (current/total) position indicator
- buildTreePrefix: tree connector prefix from ancestor-continuation flags
- TREE_BRANCH/TREE_LAST/TREE_PIPE/TREE_SPACE connector character constants
2026-03-19 16:37:40 -03:00
frizynn
d0cd3451fd refactor: consolidate OAuth callback server and helper utilities
Extract duplicated implementations of startCallbackServer, parseRedirectUrl,
getUserEmail, and token refresh logic from google-antigravity.ts and
google-gemini-cli.ts into a shared google-oauth-utils.ts module.
2026-03-19 15:55:10 -03:00