Commit Graph

545 Commits

Author SHA1 Message Date
Matan Kushner 569addd3b0 docs(provider): add comments to vercel transform logic 2026-04-13 14:05:29 +09:00
Matan Kushner effae16c14 refactor(provider): replace per-model string replacements with generic regex
Claude version transforms now use a single regex
claude-(\w+)-(\d+)-(\d+) -> claude-$1-$2.$3 instead of one
.replace() per model. New claude models need zero changes.
2026-04-13 14:01:17 +09:00
Matan Kushner 34e334eabe feat(provider): add vercel to all gateway-supported fallback entries
Adds vercel to every fallback entry where the model exists on the
gateway (kimi-k2.5, glm-5, glm-4.6v, minimax-m2.7, grok-code-fast-1,
gpt-5-nano). Adds inferSubProvider mappings for minimax, moonshotai,
and zai. Updates librarian/explore special cases to prefer minimax
via gateway over claude-haiku.
2026-04-13 13:44:50 +09:00
Matan Kushner 542dc890f9 fix(provider): use gateway-specific model IDs for vercel transform
The gateway uses google/gemini-3-flash (no -preview suffix) unlike the
direct Google API. Give the vercel provider its own transform instead
of delegating to sub-provider transforms blindly.
2026-04-13 12:51:56 +09:00
Matan Kushner dac0c99e8c feat: add Vercel AI Gateway as a provider
Adds 'vercel' as a recognized provider throughout the model resolution
system, enabling users with Vercel AI Gateway to use it as a universal
fallback for OpenAI, Anthropic, and Google models.

The gateway transform infers the sub-provider from canonical model names
(claude->anthropic, gpt->openai, gemini->google) and delegates to the
appropriate provider-specific transform, producing model strings like
vercel/anthropic/claude-opus-4.6.
2026-04-13 11:22:22 +09:00
YeonGyu-Kim 051ab840d6 Merge pull request #3348 from code-yeongyu/refactor/ulw-repo-cleanup-20260411
refactor: simplify nullish guards and remove dead no-op paths
2026-04-12 18:04:43 +09:00
YeonGyu-Kim c750781be4 fix(shared): avoid false-positive skill path resolution on npm scoped packages (#2857)
The @scope/path regex incorrectly matched npm scoped package references
like 'require(\"@scope/pkg\")' or '--package=@scope/pkg'. Added context
filtering to exclude matches preceded by npm/import indicators.

🤖 Generated with OhMyOpenCode assistance
https://github.com/code-yeongyu/oh-my-opencode
2026-04-12 02:28:46 +09:00
YeonGyu-Kim 4f02ace7de fix(shared): guard maxOutputTokens <= 0 in model settings compatibility (#3305)
When model metadata reports maxOutputTokens as 0 or negative, the
clamp logic would set maxTokens to 0 and break generation. Added
a positive-value guard so invalid metadata is ignored and the
user-requested maxTokens is preserved.

🤖 Generated with OhMyOpenCode assistance
https://github.com/code-yeongyu/oh-my-opencode
2026-04-12 02:28:36 +09:00
YeonGyu-Kim a6e4f211a3 fix(shared): normalize claude model IDs for anthropic provider (#3290)
Anthropic API accepts claude-opus-4.6 (dot format) but not
claude-opus-4-6 (dash format). Added anthropic case to
transformModelForProvider to normalize dash-format model IDs before
they reach the provider. Updated model config snapshots and test
expectations to match the new dot-format output.

🤖 Generated with OhMyOpenCode assistance
https://github.com/code-yeongyu/oh-my-opencode
2026-04-12 02:28:27 +09:00
YeonGyu-Kim 9ef133a8c7 fix(migration): register parenthesized legacy agent aliases in AGENT_NAME_MAP (#3281)
Old sessions and configs reference agent names in parenthesized format
like 'Sisyphus (Ultraworker)' and 'Atlas (Plan Executor)' which failed
to map during migration. Added entries for all six core agents.

🤖 Generated with OhMyOpenCode assistance
https://github.com/code-yeongyu/oh-my-opencode
2026-04-12 02:28:15 +09:00
YeonGyu-Kim 7accb53cbb fix(shared): handle Windows rename-over-existing in write-file-atomically (#3222)
On Windows, renameSync fails with EPERM/EACCES when the target file
already exists. Fall back to unlink + rename on Windows permission
errors while preserving atomic semantics on other platforms.

🤖 Generated with OhMyOpenCode assistance
https://github.com/code-yeongyu/oh-my-opencode
2026-04-12 02:28:05 +09:00
YeonGyu-Kim e71c34acb2 fix(migration): return true when canonical config write succeeds regardless of archive status (#3133)
Previously returned archivedLegacyConfig which was false when archive
rename failed, even though the canonical file was successfully written.
Archive failure is secondary cleanup and should not be reported as
migration failure.

🤖 Generated with OhMyOpenCode assistance
https://github.com/code-yeongyu/oh-my-opencode
2026-04-12 02:27:56 +09:00
YeonGyu-Kim 2d65896bbd refactor(shared): simplify normalize SDK null guards
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-12 00:07:10 +09:00
YeonGyu-Kim d21ed3f765 fix(doctor): add timeouts to subprocess spawns to prevent exit code 137
Doctor checks spawned subprocesses (gh, opencode, sg) without timeouts,
causing the process to hang indefinitely if any binary was stuck.
The OS would then SIGKILL the process (exit code 137).

- Add spawnWithTimeout utility with 10s per-spawn timeout and proper
  cleanup (timer cleared on success, proc.exited awaited after kill)
- Capture both stdout and stderr to preserve gh auth status behavior
- Add 30s overall doctor command timeout with JSON-mode support
- Distinguish timeout errors from other failures in runner
- Update all doctor check subprocess calls to use timeouts
2026-04-11 23:15:09 +09:00
YeonGyu-Kim 314e1a5efb fix(telemetry): enable GeoIP resolution for PostHog events
posthog-node SDK defaults disableGeoip to true, preventing country/city
data from being populated despite $ip being sent. Explicitly set
disableGeoip: false to enable geographic analytics.
2026-04-11 23:15:09 +09:00
YeonGyu-Kim 44ebf4b809 Merge pull request #3343 from code-yeongyu/refactor/ultrawork-cleanup-pass
refactor: trim duplicate logic and dead internal exports
2026-04-11 23:12:16 +09:00
YeonGyu-Kim 0c5cd3a1c4 chore(agents): update all AGENTS.md generation dates to 2026-04-11
🤖 Generated with OhMyOpenCode assistance
2026-04-11 22:33:22 +09:00
YeonGyu-Kim e9b6bba1d7 refactor(agent-display): centralize name normalization resolution
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-11 22:28:58 +09:00
YeonGyu-Kim cfc3f33f8f feat(agent): add getAgentListDisplayName utility for OpenCode list ordering
Add helper function that returns runtime-facing agent name with sort

prefixes for consistent OpenCode agent list display ordering.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-11 22:01:16 +09:00
YeonGyu-Kim d62e3eacb1 Merge pull request #3342 from code-yeongyu/fix/migration-sidecar-transaction-order
fix(migration): write config before sidecar updates
2026-04-11 21:34:43 +09:00
YeonGyu-Kim 6f21e74d56 fix(migration): write config before sidecar updates
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-11 21:27:21 +09:00
YeonGyu-Kim e2f304f1a8 fix(telemetry): validate activity state shape
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-11 21:25:27 +09:00
YeonGyu-Kim e4bb60ba07 Merge pull request #3339 from Qiiks/fix/shell-detection-shell-before-psmodulepath
fix(shell-env): check SHELL before PSModulePath for shell detection
2026-04-11 21:14:02 +09:00
YeonGyu-Kim a442976d77 Fix invisible characters in agent names 2026-04-11 20:44:57 +09:00
Qiiks f5a95203a4 fix(shell-env): check SHELL before PSModulePath for shell detection
On Windows, PSModulePath is always set by the system even when the
active shell is Git Bash (via SHELL env var). This caused the
non-interactive-env hook to generate PowerShell syntax ($env:VAR=val)
for bash shells, resulting in 15+ errors per command.

The fix prioritizes SHELL over PSModulePath since an explicit SHELL
variable indicates the user's chosen shell, while PSModulePath is just
a system-wide module path that doesn't indicate the active shell.

Fixes: #3338
2026-04-11 16:06:42 +05:30
YeonGyu-Kim c30b058b7e fix(agents): use runtime names for default_agent to match ordered agent list 2026-04-11 14:15:00 +09:00
YeonGyu-Kim 280a8a34e1 feat(telemetry): add PostHog client factory with activity state tracking 2026-04-11 14:14:24 +09:00
YeonGyu-Kim 5493ae226c fix(migration): persist fullMigrationSet in-config when sidecar write fails
Addresses Cubic review: configs without prior _migrations now get the
full migration set written to config as fallback when sidecar write
fails, preventing migration tracking loss.
2026-04-10 19:01:59 +09:00
YeonGyu-Kim 68c8701d34 fix(migration): preserve _migrations in config when sidecar write fails 2026-04-10 18:47:18 +09:00
YeonGyu-Kim e7f5d0d5fd test(shared): update shared utility tests
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-10 15:53:37 +09:00
YeonGyu-Kim bd910ad011 fix(shared): improve compaction marker and tmux server health
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-10 15:53:09 +09:00
YeonGyu-Kim 046ab1060d feat(analytics): add PostHog analytics module
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-10 15:53:00 +09:00
YeonGyu-Kim 33ac57ba7a refactor: update remaining modules to use plugin-identity constants
Update various modules to use centralized constants from plugin-identity:
- get-local-version/formatter: Use PUBLISHED_PACKAGE_NAME
- run/session-resolver: Use PUBLISHED_PACKAGE_NAME
- background-agent/task-poller: Use PUBLISHED_PACKAGE_NAME
- mcp-oauth/provider: Use PUBLISHED_PACKAGE_NAME
- auto-update-checker/constants: Use ACCEPTED_PACKAGE_NAMES
- comment-checker/downloader: Use PUBLISHED_PACKAGE_NAME
- legacy-plugin-toast/hook: Use PLUGIN_NAME
- shared/data-path: Use CACHE_DIR_NAME
- shared/external-plugin-detector: Use ACCEPTED_PACKAGE_NAMES
- shared/logger: Use LOG_FILENAME
- tools/ast-grep/downloader: Use PUBLISHED_PACKAGE_NAME
- tools/call-omo-agent/tools: Use PUBLISHED_PACKAGE_NAME
- tools/delegate-task/category-resolver: Use PUBLISHED_PACKAGE_NAME
- tools/grep/constants: Use PUBLISHED_PACKAGE_NAME
- tools/grep/downloader: Use PUBLISHED_PACKAGE_NAME
- tools/lsp/lsp-client-wrapper: Use PUBLISHED_PACKAGE_NAME

🤖 Generated with assistance of OhMyOpenCode
2026-04-10 11:16:16 +09:00
YeonGyu-Kim 5000d1e37d feat(plugin-identity): add config basename constants for migration
Add CONFIG_BASENAME and LEGACY_CONFIG_BASENAME constants to support
migrating from oh-my-opencode.json to oh-my-openagent.json naming.

🤖 Generated with assistance of OhMyOpenCode
2026-04-10 11:15:42 +09:00
YeonGyu-Kim 7a1f121fdd fix(ci): isolate model-resolution-pipeline test to prevent mock contamination
The resolveModelPipeline test was consistently failing on CI
(resolveModelPipeline > does not return unused explicit user config
metadata in override result) while passing locally. Root cause is the
same mock.module contamination pattern as #3243: when bun runs all test
files in a single process, mock.module calls from other files (e.g.
model-resolver.test.ts) leak into this file's module scope.

Add mock.module('./logger', ...) so run-ci-tests.ts auto-detects the
file and runs it in its own isolated bun process.

This unblocks the v3.16.1 publish workflow which hit this flake twice.
2026-04-09 14:19:17 +09:00
YeonGyu-Kim 0d5b087440 Revert "Merge pull request #3260 from code-yeongyu/fix/remove-zwsp-sort-prefixes"
This reverts commit c3be4c2793, reversing
changes made to d2bb5d57d1.
2026-04-09 12:21:02 +09:00
YeonGyu-Kim 57ebb11e68 Merge pull request #3262 from code-yeongyu/fix/migration-sidecar
fix(migration): track applied migrations in sidecar so user reverts stick
2026-04-09 11:01:02 +09:00
YeonGyu-Kim 00a4f318ef fix(migration): track applied migrations in sidecar so user reverts stick
Users who auto-migrated from `openai/gpt-5.3-codex` to `openai/gpt-5.4`
and then reverted their config back to `gpt-5.3-codex` by hand had the
migration re-apply on every startup in an infinite loop. Discord bug
report pointed at the exact symptom: "i deleted the migrations and they
kept coming back".

The old migration tracking lived on the config body itself as a
`_migrations` string array. The skip-already-applied check relied on
the user not touching that field. But users hit by the unwanted
migration naturally reached for the JSON file to roll their model back,
and the natural human reaction to an incomprehensible internal field
next to their config is to delete it. That wiped the migration memory
and let the same migration re-apply at the next startup.

This PR introduces a sidecar state file that lives next to the config
as `<configPath>.migrations.json` and tracks applied migrations
outside the user's hand-editable config body. The migration pipeline:

  1. Reads applied migrations from BOTH the sidecar AND the legacy
     in-config `_migrations` field, unioning them. This keeps old
     configs that still carry `_migrations` working without forcing
     a reset.

  2. Writes the updated migration set to the sidecar, never to the
     config body.

  3. Strips the legacy `_migrations` field out of the config body on
     the first write after the sidecar takes over. Users stop seeing
     the mystery internal field in their own config from that point
     forward.

If the user also deletes the sidecar (explicit fresh-start gesture)
the migrations run again - that is intentional.

Tests (TDD, all new tests written before implementation):

  - src/shared/migration/migrations-sidecar.test.ts - 11 unit tests
    covering read/write/round-trip, malformed-payload resilience,
    parent-directory creation, sorted output for stable diffs, and
    non-string entry filtering.

  - src/shared/migration.test.ts - 6 new integration tests under the
    "migrateConfigFile with migration tracking via sidecar" block
    covering: no-op path, sidecar-only write, sidecar skip after user
    revert, legacy _migrations mirroring + strip, sidecar + legacy
    union with dedupe, and partial-history append. Existing
    "preserves existing _migrations and appends new ones" test was
    rewritten to assert the new sidecar-based contract.

  - Also fixes a latent test-hygiene bug: the shared
    /tmp/nonexistent-path-for-test.json config path used by many
    migrateConfigFile tests did not clean up its companion sidecar
    between tests, letting state from one test bleed into the next.
    Added afterEach that unlinks the sidecar.

Verified:

  - bun test src/shared/migration/ -> 11 new sidecar tests pass
  - bun test src/shared/migration.test.ts -> 82 pass, 0 fail
  - bun run typecheck -> clean
  - bun run script/run-ci-tests.ts -> 4458 pass, 0 fail (full suite)
2026-04-09 10:54:25 +09:00
YeonGyu-Kim 8b418ea38a fix(agents): remove ZWSP sort prefixes from display name helper (#3259)
AGENT_LIST_SORT_PREFIXES prepended U+200B Zero Width Space characters
to the four core agent display names so they would sort ahead of user
agents in the Tab cycle. Two problems with that approach surfaced:

  1. Some terminal emulators (Ghostty, certain Windows Terminal
     builds) render ZWSP as a visible box or extra space, producing a
     visible black gap in the status bar before "Sisyphus" and
     misaligning the layout (#3259).

  2. The prefixes leaked into the plugin API surface via config.agent
     keys, breaking prompt_async consumers that received
     ZWSP-contaminated agent names (#3238).

#3242 already removed every call site of getAgentListDisplayName() in
production code. That made the sort prefixes dead code: the constant
table was still defined but nothing read it. This PR finishes the
cleanup by:

  - Deleting the AGENT_LIST_SORT_PREFIXES constant entirely
  - Turning getAgentListDisplayName() into a thin alias over
    getAgentDisplayName() for BC with external importers
  - Keeping stripAgentListSortPrefix() as a legacy data migration for
    users upgrading from v3.14.0-v3.16.0 whose config.agent keys may
    still have ZWSP baked in from the old code path
  - Documenting the history on stripAgentListSortPrefix() so future
    maintainers understand why the stripper has to stay even after
    the injector is gone

Sort ordering is preserved via JS object insertion order in
reorderAgentsByPriority() plus the `order` field it injects on the
four core agents. Both mechanisms are already in place and both
pre-date this PR; the ZWSP prefix was an older third layer that was
only meant to work around alphabetical sorting in legacy OpenCode
before the `order` field landed upstream.

Tests: 4445 pass, 0 fail. Added 3 new assertions to
agent-display-names.test.ts verifying that getAgentListDisplayName
returns plain names containing no zero-width characters. Updated
chat-message.test.ts to use a literal ZWSP string instead of the
helper so the defensive-strip path still has coverage.

Closes #3259
2026-04-09 10:10:12 +09:00
YeonGyu-Kim 6943b6d4d8 fix(ci): isolate model-resolver and prometheus-config tests from mock.module contamination
model-resolver.test.ts and prometheus-agent-config-builder.test.ts use
spyOn(shared, 'log') but do not own the logger module. When other test
files in the same bun test process call mock.module('../shared/logger'),
the import cache is poisoned and the spyOn targets a stale binding.

Add a lightweight mock.module call at the top of each file so the
auto-detection in run-ci-tests.ts picks them up as isolated targets.
This ensures each file gets its own module instance and the spy
captures all calls correctly.

Fixes the flaky CI failure pattern where resolveModelWithFallback and
buildPrometheusAgentConfig tests pass locally (separate bun process)
but fail in the shared CI batch.
2026-04-08 23:39:43 +09:00
YeonGyu-Kim 47283f9238 fix(agents): remove ZWSP prefixes from config.agent keys (#3238)
Agent names in the config.agent object (which becomes the /agent API
response) contained invisible Zero-Width Space (U+200B) characters
baked in by getAgentListDisplayName(). These ZWSP prefixes were used
for TUI sort ordering, but they leaked into the public API surface.

Impact: any prompt_async consumer that discovered agent names via the
/agent endpoint and passed them back to prompt_async without manual
ZWSP stripping got silent message drops — the agent name didn't match.
hy-pony's feishu-bridge integration went dark after upgrading to 3.16.0
with no error, no warning, and no indication that invisible Unicode
characters in agent names were the cause.

Fix: switch all four callsites from getAgentListDisplayName() (which
prepends \u200B×N) to getAgentDisplayName() (clean names):

- agent-key-remapper.ts: config keys → display names (was the primary
  injection point)
- agent-priority-order.ts: CORE_AGENT_ORDER lookup (must agree with
  the keys emitted by the remapper)
- command-config-handler.ts: command agent field normalization
- tool-config-handler.ts: agent config lookup (simplified fallback
  chain since the primary lookup is now clean)

Sort ordering is preserved by:
1. JS object insertion order from reorderAgentsByPriority()
2. The injected `order` field (1-4) added by injectOrderField()

getAgentListDisplayName() is marked @deprecated with a link to #3238.
AGENT_LIST_SORT_PREFIXES and stripAgentListSortPrefix() are kept for
any internal callers that strip prefixes from legacy data.

Closes #3238
2026-04-08 22:51:59 +09:00
YeonGyu-Kim ed16dc0608 fix(chat-params): complete maxOutputTokens migration in session prompt params 2026-04-08 17:14:17 +09:00
YeonGyu-Kim 4394129667 fix(compaction): harden continuation directive markers 2026-04-08 15:58:02 +09:00
YeonGyu-Kim 78e6d780eb fix(plugin): verify event hook compatibility with v1.4.0
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-08 13:08:03 +09:00
YeonGyu-Kim e52dd340c6 fix(plugin): migrate chat.params to maxOutputTokens for v1.4.0
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-08 13:02:51 +09:00
YeonGyu-Kim 317e2c6465 fix(zwsp): strip zero-width chars in start-work-hook
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-08 13:01:51 +09:00
YeonGyu-Kim a00fe13122 fix(test): update normalizeAgentForPrompt expectations to dash format
Test expected legacy parenthesized names but display names now use
dash format (Sisyphus - Ultraworker, not Sisyphus (Ultraworker)).
This was the flaky CI failure on dev.
2026-04-07 16:09:37 +09:00
YeonGyu-Kim 6eb527c914 fix: remove ZWSP from agent display names (#3146) 2026-04-07 15:44:31 +09:00
YeonGyu-Kim b77c256943 fix(jsonc): strip BOM before parsing (#3164) 2026-04-07 15:39:51 +09:00
YeonGyu-Kim bf2c104c9e Merge pull request #3172 from code-yeongyu/fix/bom-strip-jsonc
fix(jsonc-parser): strip UTF-8 BOM before parsing
2026-04-07 14:51:00 +09:00