Commit graph

640 commits

Author SHA1 Message Date
Mikael Hugo
2911d3b93d port gsd2: reassess-roadmap opt-in (ADR-003 §4) + prefer toolDefinition.label
reassess-roadmap: flip default from true → false. Most reassess units
conclude "roadmap is fine" burning a session for no change; the
plan-slice prompt now carries a JIT preamble at zero cost. (#4778)

tool-execution: always prefer toolDefinition.label when non-empty,
even when label === name — allows tools to display their canonical
name explicitly. (#4758)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 08:33:50 +02:00
Mikael Hugo
4fdd8700a3 port gsd2 upstream features: scope classifier, composer v2, GPT-5.5, test timeout
- milestone-scope-classifier: add getMilestonePipelineVariant + milestoneRowToScopeInput
  wired into auto-dispatch trivial-skip for research/validation phases (#4781)
- auto-prompts: rename GSD→SF identifiers, add isSummaryCleanForSkip, prefs param
  on checkNeedsReassessment, buildExtractionStepsBlock from commands-extract-learnings
- unit-context-manifest + unit-context-composer: port v2 typed computed artifacts (#4924)
- skill-manifest: per-unit-type skill filter resolver (#4788, #4792)
- escalation: stub for ADR-011 mid-execution escalation (full port deferred)
- auto-start: extract decideSurvivorAction for testability (#4832)
- models: add gpt-5.5 + gpt-5.4-mini to cost table, router, and models.generated.ts
- types: EscalationArtifact, context_window_override, skip_clean_reassess,
  mid_execution_escalation, sketch_scope on SliceRow
- tool-execution: add visibleWidth import (was undefined)
- package.json: add --test-timeout=30000 to prevent parallel tests from freezing machine

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 08:08:11 +02:00
Mikael Hugo
e2147c0694 sf snapshot: pre-dispatch, uncommitted changes after 43m inactivity 2026-04-25 06:34:49 +02:00
Mikael Hugo
7b6c9dd099 sf snapshot: pre-dispatch, uncommitted changes after 4703m inactivity 2026-04-25 05:51:29 +02:00
ace-pm
51b65fd490
fix: symlink extensions + silent catches masking real errors
Real bugs from 2nd-pass scan:

1. extension-registry.ts: discoverAllManifests skipped symlinked extension
   dirs because Dirent.isDirectory() returns false for symlinks. Dev-workflow
   symlinks under ~/.sf/agent/extensions/ were invisible to list/enable/
   disable/info. Matches the regression documented in
   symlink-extension-discovery.test.ts — the test inlines the correct logic,
   but this callsite still had the buggy form. Now accepts isDirectory() ||
   isSymbolicLink().

2. headless.ts SIGINT handler: client.stop() failures were double-silenced
   (inner .catch(()=>{}), outer try{}catch{}). Interactive mode logs stop
   errors to stderr. Restored head/headless parity — still fire-and-forget
   (exit code is forced via process.exit) but failures are observable.

3. openai-codex-responses.ts SSE parser: malformed data frames were silently
   dropped so broken streams looked identical to clean ones. Now debug-logs
   the parse error with the chunk context so broken streams are
   distinguishable in logs. Stream continues on bad chunk (one bad frame
   shouldn't kill the whole generation).

4. web/cleanup-service.ts generated script: bare 'catch {}' around four native
   git calls (nativeBranchList, nativeDetectMainBranch, nativeBranchListMerged,
   nativeForEachRef). A failed main-branch detection silently left mainBranch
   undefined-shaped, then the next native call operated on garbage. Now emits
   console.warn so failures surface in the subprocess log.

5. web/undo-service.ts generated script: git revert failure was silenced;
   when --no-commit failed, user saw commitsReverted=0 with no reason. Now
   logs the revert error before attempting --abort (abort itself remains
   best-effort silent).

False positives from the same scan (investigated and dismissed):
- auto-worktree.ts #2505: code uses ':(exclude).sf/milestones' pathspec +
  shelter-and-restore, which is a better fix than the 'drop --include-untracked'
  approach the test comment describes. Test comment is stale; source is correct.
- Lifecycle handler unhandled rejections across 5 extensions: extensions/runner.ts
  already try/catches handler invocations and routes to emitError. Wrapping the
  individual handlers would be redundant.
2026-04-21 02:01:41 +02:00
ace-pm
485e8f608e
chore: init sf 2026-04-21 01:38:02 +02:00
ace-pm
e63184f91d
fix(migrations): drop press-any-key block to avoid stdin wedge
showDeprecationWarnings ran setRawMode(true)/once('data')/setRawMode(false)/
pause() right before pi-tui's own stdin setup. That handoff is fragile —
buffered bytes and mode flips between the migration prompt and the TUI's
raw-mode setup can leave stdin cooked and line-buffered, producing the
'Enter does nothing + garbled typing' symptom.

Warnings now print non-blocking. They stay visible in scrollback above
the TUI, so users still see them without a blocking acknowledge step.
2026-04-21 00:56:18 +02:00
Mikael Hugo
f1da908dcd pi-ai: add reasoning:auto across all providers + Kimi K2.6
RequestedThinkingLevel adds "auto" to the reasoning option. Each provider
handles it natively:

- Claude 4.x (anthropic/bedrock): adaptive thinking, no effort constraint
- Gemini 2.5 Pro/Flash (google/vertex/gemini-cli): THINKING_LEVEL_UNSPECIFIED
- GPT-5+ (openai-responses/azure): reasoning.effort omitted, model decides
- Kimi (kimi-coding): {"type":"enabled"} without budget_tokens via new
  capabilities.thinkingNoBudget flag — model manages reasoning depth
- GLM (zai, thinkingFormat:zai): enable_thinking:true already correct
- MiniMax (anthropic API): explicit budget_tokens required, resolves to medium

ModelCapabilities.thinkingNoBudget: new flag for Anthropic-compatible providers
that accept {"type":"enabled"} without a budget (Kimi API).

models.generated.ts: add Kimi K2.6 (id: kimi-for-coding, beta API); add
thinkingNoBudget capability to all kimi-coding models.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 21:22:25 +02:00
Mikael Hugo
8abfc98fdc pi-ai: source google-gemini-cli model list from cli-core's VALID_GEMINI_MODELS
generate-models.ts now imports @google/gemini-cli-core's
VALID_GEMINI_MODELS set and iterates it to produce SF's google-gemini-cli
provider entries. Single source of truth: when Google ships a new Gemini
model, it lands in cli-core first, then flows into SF on
`npm update @google/gemini-cli-core` + `generate-models.ts` re-run —
no more hand-editing the generate script.

Before:  6 hardcoded entries (gemini-2.0/2.5/3 flash + pro preview, etc.)
After:   7 entries sourced dynamically, filtered to drop `-customtools`
         variants which require a different tool protocol:

  gemini-2.5-pro, gemini-2.5-flash, gemini-2.5-flash-lite,
  gemini-3-pro-preview, gemini-3-flash-preview,
  gemini-3.1-pro-preview, gemini-3.1-flash-lite-preview

Capability tagging uses cli-core's isProModel / isPreviewModel so
reasoning=true for pro + 3.x preview variants (excluding flash-lite).
Context-window / max-output-tokens kept in an SF-local override table
since cli-core doesn't publish those per-model.

Pre-existing 4 test failures (zai glm-5.1 x3, anthropic resolveBaseUrl
#4140) unchanged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 11:44:28 +02:00
Mikael Hugo
d83a59fb14 pi-ai/google-gemini-cli: re-platform transport on @google/gemini-cli-core
Replaces the handwritten fetch() + SSE-parsing + custom retry loop in
packages/pi-ai/src/providers/google-gemini-cli.ts with direct calls into
`CodeAssistServer.generateContentStream()` from @google/gemini-cli-core.
Requests to cloudcode-pa.googleapis.com are now byte-identical to what
the real `gemini` CLI sends — same User-Agent, same Client-Metadata,
same retry semantics — which preserves Google's subsidised free-OAuth
quota treatment and eliminates third-party-bot ban risk.

File size: 798 → 511 lines (~290 lines deleted net).

What went away:
  - DEFAULT_ENDPOINT, GEMINI_CLI_HEADERS (cli-core sets these itself)
  - MAX_RETRIES, BASE_DELAY_MS, MAX_EMPTY_STREAM_RETRIES, EMPTY_STREAM_BASE_DELAY_MS
  - CLAUDE_THINKING_BETA_HEADER (was antigravity-only)
  - extractRetryDelay(), isRetryableError(), extractErrorMessage(),
    sleep() — cli-core handles 429/5xx retry with Retry-After honoured
  - needsClaudeThinkingBetaHeader() — antigravity-only stub
  - CloudCodeAssistRequest + CloudCodeAssistResponseChunk interfaces
    (replaced by @google/genai's GenerateContentParameters +
     GenerateContentResponse — already unwrapped by cli-core)
  - ~200-line SSE body-reader block (response.body.getReader() + decoder
     + 'data:' line parsing) — cli-core yields parsed objects directly
  - Empty-stream retry workaround — handled upstream now

What stayed (pure SF adapter code):
  - convertMessages() → @google/genai Content[]
  - convertTools() → functionDeclarations
  - AssistantMessageEventStream — our event shape
  - Part-by-part processing: text vs thinking blocks, function-call
    translation to ToolCall, thoughtSignature retention, usage token
    extraction

New helper:
  - buildCodeAssistServer(token, projectId) constructs an OAuth2Client
    (google-auth-library) seeded with the SF-cached access token and
    wraps it in a CodeAssistServer instance. Ready for future promotion
    to cli-core's getOauthClient() for full auto-refresh; today we
    still pass the token through from SF's auth storage (Strategy A
    from the plan doc).

Live verified end-to-end against gemini-2.5-flash using the user's
cached ~/.gemini/oauth_creds.json — got real streaming response,
correct stopReason, usage tokens accounted.

Models registry test updated from 23 → 22 providers (antigravity gone).
Remaining 4 pi-ai test failures are pre-existing and unrelated
(custom-zai glm-5.1, resolveAnthropicBaseUrl #4140).

Type note: cli-core bundles its own nested copy of @google/genai, so
TypeScript sees two structurally-identical Content types. Runtime is
fine; a single `as any` cast at the generateContentStream call site
handles the nominal split.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 11:29:56 +02:00
Mikael Hugo
bae6553e67 pi-ai: remove google-antigravity provider entirely
Continues the antigravity rip-out (previous commit covered SF + pi-coding-
agent UI layer). This commit removes the code from pi-ai:

- Delete packages/pi-ai/src/utils/oauth/google-antigravity.ts (313 lines)
- Update oauth/index.ts: drop antigravityOAuthProvider, refreshAntigravityToken,
  loginAntigravity exports + registry entry. Add comment explaining why
  (no vendor core lib + Google ban risk).
- google-gemini-cli.ts: strip ANTIGRAVITY_* constants, ANTIGRAVITY_ENDPOINT_FALLBACKS,
  getAntigravityHeaders(), ANTIGRAVITY_SYSTEM_INSTRUCTION, and all
  isAntigravity branching from streamGoogleGeminiCli + buildRequest.
  File header rewritten. needsClaudeThinkingBetaHeader() collapses to
  always-false (antigravity was the only path that needed it).
- google-shared.ts: strip stale Antigravity comments (file still shared
  between google, google-gemini-cli, google-vertex).
- types.ts: drop "google-antigravity" from Api / KnownProvider union.
- models.generated.ts: remove google-antigravity provider block (~170 lines,
  4 claude-* models that were only served via Antigravity).
- models.generated.test.ts: drop from expected-providers snapshot.
- scripts/generate-models.ts: remove antigravity model emission + context-
  window override so future regenerations don't re-add it.

Reasoning (same as previous commit): Antigravity has no vendor-published
core library we can embed. Hand-rolled OAuth against
daily-cloudcode-pa.sandbox.googleapis.com was exactly the pattern
Google is banning for third-party tools. Removing it eliminates the
risk surface.

Breaking change: users with google-antigravity configured in their
models.* block will need to migrate to google-gemini-cli (OAuth via
the real `gemini` CLI), google (API key), or google-vertex (GCP auth).

Build passes. Next commit wires the google-gemini-cli provider to
@google/gemini-cli-core per the plan.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 10:45:44 +02:00
Mikael Hugo
59806f8cc5 rip out antigravity from SF + pi-coding-agent UI/config layer
Antigravity (Google's IDE sandbox product, different from Gemini CLI) is
removed from:

  src/onboarding.ts                         — drop from LLM_PROVIDER_IDS + OAuth-flow picker
  src/pi-migration.ts                       — drop from LLM_PROVIDER_IDS migration list
  src/web/onboarding-service.ts             — drop from web-UI provider list
  src/tests/integration/web-onboarding-contract.test.ts — update contract
  src/resources/extensions/sf/doctor-providers.ts — drop from CLI_AUTH_PROVIDERS
  src/resources/extensions/sf/key-manager.ts      — drop UI listing
  src/resources/extensions/sf-usage-bar/index.ts  — delete entire quota fetcher block (~200 lines)
  packages/pi-coding-agent/src/cli/args.ts        — drop PI_AI_ANTIGRAVITY_VERSION doc
  packages/pi-coding-agent/src/utils/proxy-server.ts — drop from claude provider chain

Reason: antigravity has no vendor-published core library we can embed
(unlike @google/gemini-cli-core for the Gemini CLI). Continuing to
hand-roll OAuth against daily-cloudcode-pa.sandbox.googleapis.com is
exactly the pattern Google has started banning for third-party tools.
Removing the code removes the ban risk.

pi-ai provider code, OAuth util, and models.generated entries for
google-antigravity are removed in follow-up commits (separated for
reviewability — each layer verified independently).

Build passes. Note: this is a breaking change for any user who had
google-antigravity configured — they'll need to migrate to
google-gemini-cli (OAuth), google (API key), or google-vertex.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 10:39:36 +02:00
Mikael Hugo
233432d486 model-registry: drop google-antigravity from claude family_failover (preparing rip-out) 2026-04-19 10:35:56 +02:00
Mikael Hugo
eed84a2624 pi-ai: add @google/gemini-cli-core@0.38.2 dependency + refactor plan
Installs Google's official core library that powers the `gemini` CLI
binary. This is the first step of re-platforming pi-ai's
`google-gemini-cli` provider to use cli-core's transport instead of
handwritten fetch() calls against cloudcode-pa.googleapis.com.

Why:
  - cli-core requests are byte-for-byte identical to the official
    gemini CLI — preserves Google's subsidised free-OAuth quota and
    eliminates bot-detection drift risk from our reverse-engineered
    User-Agent / Client-Metadata headers.
  - Auto-inherit upstream improvements (new tool formats, grounding,
    session caching, quota displays) on `npm update`.
  - The `genai-proxy` extension (localhost proxy for gemini-cli-format
    clients) becomes "the CLI, but programmable" — same upstream
    behavior, hookable SF routing underneath.

Auth model (unchanged for users):
  - User runs the real `gemini` CLI once to OAuth; credentials land
    in ~/.gemini/oauth_creds.json (or keychain on newer installs).
  - SF reads those credentials via cli-core's own storage helpers;
    no SF-side OAuth flow, no separate login.

Scope for this commit: dependency only. The transport refactor
(replacing the fetch() calls in google-gemini-cli.ts with
CodeAssistServer.generateContentStream()) is queued as the next
task and documented in google-gemini-cli-core-plan.md with a
detailed API map, two integration strategies (transport-only vs
full cli-core auth), and a step-by-step implementation checklist.

Note: this commit adds 66 transitive deps to pi-ai (ajv, zod,
glob, mime, open, etc.). google-antigravity provider stays on
handwritten code — different sandbox endpoints, different auth
contract, not in cli-core's scope.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 10:33:22 +02:00
Mikael Hugo
ffe86284d2 model-registry: split direct vs family_failover providers per model family
Prior PROXY_FAMILY_PRIORITY table conflated "direct provider" with
"failover provider that happens to serve this family". Observed case:
claude-* family listed anthropic, google-antigravity, and
github-copilot all as "providers" — but only anthropic is the direct
vendor. google-antigravity re-serves Claude via Google's sandbox
IDE product (same endpoint as gemini-cli, different auth contract);
github-copilot re-serves via GitHub's paid platform.

This matters for the 429 fallback chain: a broken anthropic key
should try genuinely-vendored endpoints first (none, for Claude),
then fall into family_failover (antigravity, copilot), and only then
reach the generic GLOBAL_PROVIDER_FALLBACK (opencode, opencode-go,
openrouter, ollama-cloud). The old all-flat list hid this distinction.

New shape:
  { providers: [...], family_failover?: [...] }

Corrections applied:
  claude-*: providers=[anthropic], failover=[google-antigravity, github-copilot]
  gemini-*: providers=[google-gemini-cli, google, google-vertex],
            failover=[github-copilot]
  gpt-* / o* / codex-*: providers=[openai],
            failover=[azure-openai-responses, openai-codex, github-copilot]
  mimo-*: providers=[xiaomi]  (new: was [] — Xiaomi MiMo Open Platform
          is direct API at api.xiaomimimo.com / token-plan-sgp.xiaomimimo.com)

buildCandidateOrder stitches [direct, family_failover, global_fallback]
with deduplication. User overrides via settings.proxy.providerPriority
continue to replace only the direct-provider list, keeping family
failover and global fallback intact.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 10:20:32 +02:00
Mikael Hugo
6450b37025 core + search + benchmarks: auth-error recovery, multi-provider search, M2.7-highspeed entry
Four related improvements that landed in the working tree after the
auto-hardening merge but hadn't been committed:

1. auth_error as a distinct error type (auth-storage + retry-handler).
   Previously invalid/expired API keys would retry the same failing
   credential until the retry budget exhausted. Now:
     - classifyErrorType() recognizes 401s, "invalid api key",
       "authentication error", "unauthorized" etc as "auth_error"
     - RetryHandler triggers cross-provider fallback on auth_error just
       like it does for rate_limit and quota_exhausted — switch
       providers rather than burning retries on a broken key
   Outcome: a stale OPENCODE_API_KEY in sops now fails over to kimi or
   minimax immediately instead of stalling the unit.

2. Multi-provider search-key detection (native-search.ts).
   The "Web search: Set BRAVE_API_KEY" warning fired whenever a
   non-Anthropic model lacked BRAVE_API_KEY, even when the user had
   TAVILY_API_KEY or OLLAMA_API_KEY available. Now: the warning
   suppresses if any of BRAVE/TAVILY/OLLAMA keys is present, and the
   warning text lists all three options. Matches the preferences-
   validation allow-list for search_provider.

3. MiniMax-M2.7-highspeed benchmark entry (model-benchmarks.json).
   Routes the fast-tier variant of M2.7 through the Bayesian blender
   with inherited RULER scores. Lets dynamic routing consider the
   highspeed model when speed matters more than peak quality.

No regressions: the 41 pre-existing test failures in pi-coding-agent
(FallbackResolver chain-membership + LSP integration) are unchanged
relative to the prior commit.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 09:24:54 +02:00
Mikael Hugo
3bb93b1612 Cherry-pick process lifecycle fixes for multi-day autonomous operation
- shell: add trackDetachedChildPid / untrackDetachedChildPid /
  killTrackedDetachedChildren (#9b7948c)
- bash: track/untrack detached child PIDs so they are killed on shutdown
- interactive-mode: register SIGTERM/SIGHUP handlers for clean shutdown
  (#5d440b0); kill tracked bash children on shutdown
- rpc-mode: register SIGTERM/SIGHUP handlers, refactor to forceShutdown()
  that deduplicates shutdown path (#5d440b0); kill tracked bash children
- print-mode: register SIGTERM/SIGHUP handlers for graceful exit

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 14:38:55 +02:00
Mikael Hugo
aff49e52aa Cherry-pick 4 critical recovery fixes from pi-mono upstream
- agent-loop: wrap afterToolCall in try/catch so hook throws don't crash
  parallel tool batches (#3084)
- retry-handler: add "connection lost" to retryable error patterns (#3317)
- rpc-mode: redirect console.log to stderr to protect JSON stdout (#2388)
- openai-completions: ignore null/non-object chunks in stream (#2466)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 14:28:15 +02:00
Mikael Hugo
f153521c24 Cherry-pick tool bug fixes from pi-mono upstream
- compaction: fix repeated compaction dropping kept messages (#2608)
  Re-summarize from previous compaction's firstKeptEntryId instead of
  prevCompactionIndex+1; use buildSessionContext for accurate tokensBefore

- edit: add multi-edit support via edits[] array
  Single call can update multiple disjoint regions in one file;
  applyEditsToNormalizedContent matches all edits against original content
  and applies in reverse order for stable offsets

- bash: persist full output when line-count truncation occurs (#2852)
  ensureTempFile now called on any truncation, not only byte overflow;
  prevents data loss when output exceeds line limit before byte threshold

- bash-executor: same fix for remote/operations-based execution
  ensureTempFile includes SF cleanup registration (registerTempCleanup,
  bashTempFiles tracking)

- grep: include lineText from rg JSON events to avoid per-match file reads
  Eliminates stall when context=0 on broad searches (#3148)

- agent-session: forward isError override from afterToolCall extension hook
  Allows extensions to change error status of tool results (#3051)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 14:18:52 +02:00
Mikael Hugo
830328da95 feat(pi-ai): add claude-opus-4-7 model support (#4348)
Cherry-pick of gsd-build/gsd-2@8f8187e23 adapted for our single-file models.generated.ts:
- Amazon Bedrock: add anthropic.claude-opus-4-7, eu/global/us prefix variants
- Google Antigravity: add claude-opus-4-7-thinking
- OpenRouter: add anthropic/claude-opus-4.7

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 13:46:30 +02:00
Jeremy
b5e1beff8e fix(auth): self-heal stale Anthropic OAuth credential (#4399)
Anthropic OAuth was removed in v2.74.0 for TOS compliance (#3952). Users
who upgraded through that version still have type:"oauth" entries under
`anthropic` in auth.json which cannot resolve to a valid API key.

stale entry, so hasAuth("anthropic") kept reporting true and masked the
claude-code fallback path. Users had to hand-edit auth.json to recover.

Self-heal instead:

- AuthStorage.removeLegacyOAuthCredential(provider) strips only
  type:"oauth" entries and preserves any api_key credentials.
- sdk.ts getApiKey() calls it when the legacy-OAuth branch triggers,
  logs a one-line warning, and throws a message pointing the user at
  the "claude-code" provider when the `claude` binary is in PATH, or
  at ANTHROPIC_API_KEY otherwise.

Closes #4399

(cherry picked from commit b8ef6604617fda239a037cf5d5e6020b168d2e62)
2026-04-18 13:40:02 +02:00
Nils Reeh
3b23ef3d4b fix(pi-ai): wire thinking:{type} field and extend adaptive-thinking model coverage (#4392)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
(cherry picked from commit 503e79070d198254661febad35a267ead487b7e1)
2026-04-18 13:38:30 +02:00
Yeon Gil Kang
b73763d944 fix(pi-ai): hide unsupported ChatGPT codex oauth models
ChatGPT-backed Codex sign-in no longer exposes the removed 5.1/5.2 Codex variants. Filter those models from openai-codex OAuth so GSD stops surfacing selections that immediately fail while leaving API-key-backed OpenAI models available.

(cherry picked from commit 1aedba583916826fc5c6129037f61e9802010e46)
2026-04-18 13:35:45 +02:00
Nils Reeh
1914f31342 feat(pi-ai): support ANTHROPIC_BASE_URL env var for custom proxy endpoints (#4140)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
(cherry picked from commit e94cf668e2fdf28537aead642b4062cd3a22a8d3)
2026-04-18 13:34:58 +02:00
Mikael Hugo
78c5c3a78b Add proxy routing tests; fix two build errors
- 15 tests for ModelRegistry.getModelsForProxy covering family priority
  ordering, auth-ready promotion, overrides, and edge cases
- Fix StreamOptions cast in proxy-server.ts (lost during rebase conflict)
- Fix .ts import extension in args.test.ts (pre-existing)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 12:40:03 +02:00
Mikael Hugo
30730dd25b Fix rebrand artifacts, add family-priority model routing to proxy server
- Update Dockerfile image name and package.json URLs to singularity-ng/singularity-foundry
- Add uv to nix develop shell in flake.nix
- Rename resolveGsdRoot → resolveSFRoot in src/cli.ts
- Add PROXY_FAMILY_PRIORITY routing table + sortByFamilyPriority to proxy-server.ts
- Fix duplicate scope key and simplify link-workspace-packages.cjs
- Remove duplicate conditions in postinstall.js
- Add ES2024 target/lib to tsconfig.extensions.json
- Delete obsolete GSD recovery scripts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 12:28:27 +02:00
github-actions[bot]
8f160677b7
release: v2.75.0
https://claude.ai/code/session_013BwmqG3NuwwZY3vsUb4Y9Y
2026-04-17 17:26:59 +00:00
mikkihugo
dc0db3868a
Add per-family proxy provider priority system with TUI and 429 fallback
- model-registry: export PROXY_FAMILY_PRIORITY and GLOBAL_PROVIDER_FALLBACK
  constants; add getModelsForProxy() returning candidates ordered by family
  priority then global fallback (opencode → opencode-go → openrouter →
  ollama-cloud); add getModel() convenience wrapper
- proxy-server: add priorityOverrides option; handleChat iterates all
  candidates in priority order and falls through to the next on 429
- settings-manager: add ProxySettings type with providerPriority override
  map; add getProxyProviderPriority() / setProxyFamilyProvider() accessors
- settings-selector: add ProxyPrioritySubmenu — a two-level TUI submenu
  (family → provider) that dynamically generates entries from
  PROXY_FAMILY_PRIORITY; wired in interactive-mode with full callback

Family defaults: MiniMax→minimax, GLM→zai, Kimi→kimi-coding,
MiMo→global-fallback, Gemini/Gemma→google-gemini-cli, Claude→anthropic,
GPT/o-series→openai

https://claude.ai/code/session_013BwmqG3NuwwZY3vsUb4Y9Y

Co-authored-by: Claude <noreply@anthropic.com>
2026-04-17 19:17:50 +02:00
ace-pm
f92ee8d64c
Rename @sf-run/* → @singularity-forge/* package scope
- All 373 source files updated
- Package.json scopes in all workspace packages
- Loader workspace symlink dir updated
- RpcClient import unified from pi-coding-agent (fixes type mismatch)
- Scripts, configs, flake.nix updated
- Workspace symlinks rebuilt
2026-04-15 22:56:33 +02:00
ace-pm
9d739dfa5d Rename GSD→SF: complete rebrand from fork origin
- All gsdDir/gsdRoot/gsdHome → sfDir/sfRootDir/sfHome
- GSDWorkspace* → SFWorkspace* interfaces
- bootstrapGsdProject → bootstrapProject
- runGSDDoctor → runSFDoctor
- GsdClient → SfClient, gsd-client.ts → sf-client.ts
- .gsd/ → .sf/ in all tests, docs, docker, native, vscode
- Auto-migration: headless detects .gsd/ → renames to .sf/
- Deleted gsd-phase-state.ts backward-compat re-export
- Renamed bin/gsd-from-source → bin/sf-from-source
- Updated mintlify docs, github workflows, docker configs
2026-04-15 18:33:47 +02:00
ace-pm
421fccd898 refactor: rebrand gsd_ tool names and references to sf_ namespace
Updates workflow tool names, documentation references, and internal naming
conventions across MCP server, CLI, tests, and web components to complete
the singularity-forge rebrand from gsd to sf.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 15:51:38 +02:00
ace-pm
6b0ac484ba refactor: update log prefixes and string values from gsd- to sf- namespace
Updates channel prefixes, log messages, comments, and configuration values
across daemon, mcp-server, and related packages to complete the rebrand from
gsd to sf-run naming.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 15:37:12 +02:00
ace-pm
6e520b1db8 fix(daemon): rename Discord slash commands from gsd- to sf- prefix
Update command names to match the rebrand:
- gsd-status → sf-status
- gsd-start → sf-start
- gsd-stop → sf-stop
- gsd-verbose → sf-verbose

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 15:05:53 +02:00
ace-pm
b29c12d5e5 refactor(native): rename gsd_parser.rs to forge_parser.rs
Final rebrand: rename remaining Rust source file to complete the gsd → forge
transition. All parser references already use forge_parser after earlier commits.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 14:58:21 +02:00
ace-pm
35dc87ef53 chore: sync workspace state after rebrand
- Rebrand commits already in history (gsd → forge)
- Sync pre-existing doc, docker, and CI config updates
- All rebrand artifacts verified in place:
  * Native crates: forge-engine, forge-ast, forge-grep
  * Log prefixes: [forge] across 22+ files
  * Binary: ~/bin/sf-run
  * Workspace scopes: @sf-run/*, @singularity-forge/*
  * Nix flake: Rust toolchain ready

System ready for: nix develop && bun run build:native

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 14:54:20 +02:00
ace-pm
d501ca7d6d fix: clean up git state after directory restoration
- Accept deletion of gsd-phase-state.ts (renamed to forge-phase-state.ts earlier)
- Accept deletion of create-gsd-extension/ (renamed to create-forge-extension/ earlier)
- These renames were part of the rebrand and are preserved in commit history

Stabilize git state after restoration operations.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 14:34:53 +02:00
ace-pm
83feadb4e1 wip: rename gsd-parser dir + exports, fix native package.json
- packages/native/src/gsd-parser → packages/native/src/forge-parser
- Update packages/native/package.json exports: ./gsd-parser → ./forge-parser
- Update packages/native/src/index.ts imports: ./gsd-parser → ./forge-parser

Build in progress: native tsc output missing submodule dists (fd, text, image, etc).
This is a pre-existing issue with the build system, not caused by rebrand.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 14:22:21 +02:00
ace-pm
172753c3b2 refactor(forge): complete gsd → forge rebrand across native, logging, and build system
- Rename native Rust crates: gsd-engine → forge-engine, gsd-ast → forge-ast, gsd-grep → forge-grep
- Update all crate dependencies (Cargo.toml, .rs source) and N-API artifacts
- Mass rename log prefix [gsd] → [forge] across 81 files (scripts, src/, extensions, tests)
- Rename log prefix "gsd-db:" → "forge-db:" in template literals
- Update nix flake: add sf-run-native devShell with Rust toolchain for native addon builds
- Update CI workflow artifact names (build-native.yml)
- Verify only packages/native/* touched (no upstream pi-* packages renamed)

Rationale: Complete gsd-2 → singularity-forge rebrand (2026-04-15). Native addon is
sf-run-specific; all gsd-prefixed logging and crate names must align with new identity.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 14:11:45 +02:00
ace-pm
e5d655bdb3 chore: checkpoint workspace changes 2026-04-15 13:38:15 +02:00
ace-pm
c0de3538ec fix(retry-handler): classify 529/overloaded as rate_limit for fallback walk
Minimax and other Anthropic-protocol providers return HTTP 529 with
`overloaded_error` bodies under heavy load. The retryable regex (line 119)
matched `overloaded` so the error was retried, but the rate-limit
classifier (line 423) only matched `429`, so the error never triggered
credential rotation or cross-provider fallback — the handler looped on
the same provider forever.

Adds `529|overloaded` to the rate-limit classifier so 529 responses
route through the same backoff + fallback path as real rate limits.
2026-04-15 11:04:41 +02:00
ace-pm
1f1c029c74 fix(cli): invert persistModelChanges default to false (#4251)
Followup to 828c5edf6. Swarm review flagged default=true as a latent
footgun: any SDK consumer of createAgentSession() that forgets to pass
persistModelChanges would silently mutate ~/.gsd/agent/settings.json.

Flip the default to false so persistence is opt-in. Interactive CLI
entry points now explicitly pass persistModelChanges: true:
- src/cli.ts interactive createAgentSession call
- packages/pi-coding-agent/src/main.ts: persistModelChanges = isInteractive

Print/rpc/mcp stay at the safe default. Tests updated (9/9 green).
2026-04-15 10:45:26 +02:00
ace-pm
828c5edf62 fix(cli): don't persist --model override in print mode (#4251)
`gsd -p --model X "msg"` was silently overwriting defaultProvider/
defaultModel in settings.json. One-shot verification runs must use the
model for that invocation only.

Adds an AgentSessionConfig.persistModelChanges flag (default true so
interactive behavior is unchanged), forwards it through createAgentSession,
and sets it false in main.ts when !isInteractive and in src/cli.ts print
mode. The gsd wrapper also skips validateConfiguredModel when --model is
explicitly passed, so a CLI-provided model can't trigger a fallback repair
that writes the wrong default back.

Three settings.json write sinks audited: agent-session._applyModelChange
(gated on flag), model-selector.ts (interactive only, unreachable in
print), startup-model-validation (gated by !cliFlags.model in print).

Regression: 8 source-assertion tests in
agent-session-print-mode-persist.test.ts.
2026-04-15 10:12:32 +02:00
ace-pm
1fc62582ed feat(anthropic): support longcat as Bearer-auth Anthropic-compatible provider
LongCat (Meituan) ships an Anthropic-compatible endpoint at
https://api.longcat.chat/anthropic that authenticates via
`Authorization: Bearer $KEY` instead of Anthropic's native `x-api-key`
header. Without this change, pi sends x-api-key and LongCat replies
with 401 invalid_api_key / missing_api_key.

Same topology as the existing alibaba-coding-plan / minimax /
minimax-cn entries (#3783).

- Add "longcat" to usesAnthropicBearerAuth() so createClient routes
  the key through authToken.
- Add "longcat": "LONGCAT_API_KEY" to env-api-keys.ts envMap so
  getEnvApiKey() can resolve it when options.apiKey is absent.
- Add "longcat" to KnownProvider so the === literal check type-checks.
- Extend anthropic-auth.test.ts to assert usesAnthropicBearerAuth
  returns true for longcat.
2026-04-15 08:54:52 +02:00
Jeremy McSpadden
cb8ac79ce6 Merge pull request #4245 from jeremymcs/fix/claude-mcp-orphaned-subturn-text
fix(chat): preserve Claude MCP chat visibility during tool-only windows
2026-04-14 23:41:36 -05:00
Jeremy
bc98495cdd fix(chat): preserve claude MCP thinking visibility during tool windows 2026-04-14 23:09:20 -05:00
Jeremy
51fdd6e973 fix(chat): cap claude reasoning blocks to keep chat visible 2026-04-14 22:58:56 -05:00
Jeremy McSpadden
9cc66484a9 Merge pull request #4238 from jeremymcs/fix/claude-mcp-orphaned-subturn-text
fix(chat): prune orphaned Claude MCP sub-turn provisional text
2026-04-14 22:41:03 -05:00
Jeremy McSpadden
3fb1bef6d8 Merge pull request #4227 from NilsR0711/feat/gsd-extract-learnings
feat(gsd): add /gsd extract-learnings command
2026-04-14 22:33:37 -05:00
Jeremy
9a344ad6ca fix(chat): prune orphaned claude MCP provisional sub-turn text 2026-04-14 22:22:10 -05:00
Jeremy McSpadden
b803d6e023 Merge pull request #3878 from mastertyko/fix/3782-minimax-env-key-fallback
fix(pi-coding-agent): fall back to env keys for built-ins
2026-04-14 22:03:31 -05:00