Compare commits

..

157 Commits

Author SHA1 Message Date
YeonGyu-Kim
77424f86c8 Merge pull request #2816 from code-yeongyu/fix/keep-agent-with-explicit-model
fix: always keep agent with explicit model, robust port binding & writable dir fallback
2026-03-25 11:48:26 +09:00
YeonGyu-Kim
919f7e4092 fix(data-path): writable directory fallback for data/cache paths
getDataDir() and getCacheDir() now verify the directory is writable and
fall back to os.tmpdir() if not.

🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 11:46:07 +09:00
YeonGyu-Kim
78a3e985be fix(mcp-oauth): robust port binding for callback server
Use port 0 fallback when findAvailablePort fails, read the actual bound
port from server.port. Tests refactored to use mock server when real
socket binding is unavailable in CI.

🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 11:46:07 +09:00
YeonGyu-Kim
42fb2548d6 fix(agent): always keep agent when model is explicitly configured
Previously, when an explicit model was configured, the agent name was
omitted to prevent opencode's built-in agent fallback chain from
overriding the user-specified model. This removes that conditional logic
and always passes the agent name alongside the model. Tests are updated
to reflect this behavior change.

🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 11:46:07 +09:00
YeonGyu-Kim
bff74f4237 Merge pull request #2695 from MoerAI/fix/provider-agnostic-fallback
fix(runtime-fallback): make fallback provider selection provider-agnostic (fixes #2303)
2026-03-25 11:36:50 +09:00
YeonGyu-Kim
038b8a79ec Revert "Merge pull request #2611 from MoerAI/fix/keep-default-builder-agent"
This reverts commit 0aa8bfe839, reversing
changes made to 422eaa9ae0.
2026-03-25 11:13:05 +09:00
YeonGyu-Kim
0aa8bfe839 Merge pull request #2611 from MoerAI/fix/keep-default-builder-agent
fix(config): keep default OpenCode Build agent enabled by default (fixes #2545)
2026-03-25 11:11:34 +09:00
YeonGyu-Kim
422eaa9ae0 Merge pull request #2753 from MoerAI/fix/prometheus-model-override
fix(prometheus): respect agent model override instead of using global opencode.json model (fixes #2693)
2026-03-25 11:09:48 +09:00
YeonGyu-Kim
63ebedc9a2 Merge pull request #2606 from RaviTharuma/fix/clamp-variant-on-non-opus-fallback
fix: clamp unsupported max variant for non-Opus Claude models
2026-03-25 11:06:31 +09:00
YeonGyu-Kim
f0b5835459 fix(publish): correct repo guard to oh-my-openagent (GitHub renamed repo) 2026-03-25 09:21:38 +09:00
YeonGyu-Kim
2a495c2e8d Merge pull request #2813 from code-yeongyu/fix/tmux-test-flake-20260325
test(tmux): remove flaky live env wrapper assertion
2026-03-25 02:08:05 +09:00
YeonGyu-Kim
0edb87b1c1 test(tmux): remove flaky live env wrapper assertion
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-25 02:05:51 +09:00
YeonGyu-Kim
cca057dc0f Merge pull request #2812 from code-yeongyu/fix/non-interactive-env-win-bash-prefix
fix(non-interactive-env): force unix prefix for bash git commands
2026-03-25 01:24:18 +09:00
YeonGyu-Kim
e000a3bb0d fix(non-interactive-env): force unix prefix for bash git commands
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-25 01:23:02 +09:00
YeonGyu-Kim
c19fc4ba22 Merge pull request #2811 from code-yeongyu/fix/publish-workflow-guard-topology-20260325
fix(publish): align repo guard and test topology
2026-03-25 01:19:29 +09:00
YeonGyu-Kim
e0de06851d fix(publish): align repo guard and test topology
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-25 01:17:42 +09:00
YeonGyu-Kim
26ac413dd9 Merge pull request #2801 from MoerAI/fix/null-byte-sanitization
fix(tool-execute-before): strip null bytes from bash commands to prevent crash (fixes #2220)
2026-03-25 01:12:45 +09:00
YeonGyu-Kim
81c912cf04 Merge pull request #2800 from MoerAI/fix/background-task-fallback-chain
fix(background-task): register fallback chain for background sessions (fixes #2203)
2026-03-25 01:12:41 +09:00
YeonGyu-Kim
9c348db450 Merge pull request #2799 from MoerAI/fix/unstable-agent-config-override
fix(category-resolver): respect is_unstable_agent config override (fixes #2061)
2026-03-25 01:12:36 +09:00
YeonGyu-Kim
2993b3255d Merge pull request #2796 from guazi04/fix/circuit-breaker-false-positive-upstream
fix(circuit-breaker): treat unknown tool input as non-comparable to prevent false positives on flat events
2026-03-25 01:12:31 +09:00
YeonGyu-Kim
0b77e2def0 Merge pull request #2810 from code-yeongyu/fix/webfetch-redirect-loop
fix(webfetch): guard redirect loops in built-in flow
2026-03-25 00:40:54 +09:00
YeonGyu-Kim
bfa8fa2378 Merge pull request #2804 from code-yeongyu/fix/b2-hashline-formatter-cache-per-project
fix(hashline-edit): scope formatter cache by directory
2026-03-25 00:32:41 +09:00
YeonGyu-Kim
6ee680af99 Merge pull request #2809 from code-yeongyu/fix/2330-recursive-subagent-spawn
fix(task): preserve restricted agent tools in sync continuation
2026-03-25 00:32:14 +09:00
YeonGyu-Kim
d327334ded Merge pull request #2808 from code-yeongyu/fix-gemini-3-pro-cleanup
fix(models): remove stale Gemini 3 Pro references
2026-03-25 00:32:10 +09:00
YeonGyu-Kim
07d120a78d Merge pull request #2807 from code-yeongyu/fix/b4-manager-model-override-1774351606
fix(background-task): apply model override omission to manager live path
2026-03-25 00:31:49 +09:00
YeonGyu-Kim
8b7b1c843a Merge pull request #2806 from code-yeongyu/fix/b5-permission-merge-order
fix(plugin): restore permission merge order precedence
2026-03-25 00:31:43 +09:00
YeonGyu-Kim
a1786f469d Merge pull request #2805 from code-yeongyu/fix/b3-config-filename-precedence
fix(config): prefer canonical plugin config filenames
2026-03-25 00:31:18 +09:00
YeonGyu-Kim
da77d8addf Merge pull request #2802 from code-yeongyu/fix/b1-preemptive-compaction-epoch-guard
fix: handle repeated compaction epochs in continuation guard
2026-03-25 00:30:54 +09:00
YeonGyu-Kim
971912e065 fix(webfetch): avoid rewriting successful redirect content 2026-03-24 23:59:57 +09:00
YeonGyu-Kim
af301ab29a fix(webfetch): guard redirect loops in built-in flow 2026-03-24 23:58:53 +09:00
YeonGyu-Kim
984464470c fix(task): preserve restricted agent tools in sync continuation
Restore sync continuation to apply agent tool restrictions after permissive defaults so resumed explore and librarian sessions cannot regain nested delegation. Add regression tests for resumed restricted agents while keeping plan-family continuation behavior intact.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-24 23:54:29 +09:00
YeonGyu-Kim
535ecee318 fix(models): remove stale Gemini 3 Pro references
Keep repo-owned CLI, docs, and test fixtures aligned with current Gemini 3.1 naming while leaving upstream catalog behavior untouched.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-24 23:53:56 +09:00
YeonGyu-Kim
32035d153e fix(config): prefer canonical plugin config filenames
Ensure oh-my-opencode filenames always win over legacy oh-my-openagent files so readers match canonical writer behavior.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-24 20:38:54 +09:00
YeonGyu-Kim
a0649616bf fix(todo-continuation-enforcer): acknowledge compaction epochs during idle
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-24 20:36:22 +09:00
YeonGyu-Kim
cb12b286c8 fix(todo-continuation-enforcer): arm compaction epochs on compaction
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-24 20:36:22 +09:00
YeonGyu-Kim
8e239e134c fix(todo-continuation-enforcer): make compaction guard epoch-aware
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-24 20:36:22 +09:00
YeonGyu-Kim
733676f1a9 fix(todo-continuation-enforcer): add compaction epoch state
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-24 20:36:22 +09:00
YeonGyu-Kim
d2e566ba9d fix(preemptive-compaction): mock session history in degradation test
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-24 20:36:22 +09:00
YeonGyu-Kim
6da4d2dae0 fix(hashline-edit): scope formatter cache by directory
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-24 20:30:16 +09:00
YeonGyu-Kim
3b41191980 fix(background-agent): honor explicit model override in manager
Keep BackgroundManager launch and resume from sending both agent and model so OpenCode does not override configured subagent models. Add launch and resume regressions for the live production path.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-24 20:28:01 +09:00
YeonGyu-Kim
0b614b751c fix(permissions): preserve explicit deny over OmO defaults
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-24 20:24:14 +09:00
MoerAI
c56a01c15d fix(tool-execute-before): strip null bytes from bash commands to prevent crash (fixes #2220) 2026-03-24 19:17:05 +09:00
MoerAI
d2d48fc9ff fix(background-task): register fallback chain for background sessions (fixes #2203) 2026-03-24 19:11:13 +09:00
MoerAI
41a43c62fc fix(category-resolver): respect is_unstable_agent config override (fixes #2061) 2026-03-24 19:08:21 +09:00
YeonGyu-Kim
cea8769a7f Merge pull request #2798 from code-yeongyu/fix/2353-model-selection-v2
fix(plugin): persist selected model only for main session
2026-03-24 18:57:50 +09:00
YeonGyu-Kim
7fa2417c42 fix(plugin): persist selected model only for main session
Reuse the stored model only for subsequent main-session messages when the UI provides no model, while preserving first-message behavior, explicit overrides, and subagent isolation.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-24 18:11:27 +09:00
YeonGyu-Kim
4bba924dad Revert "Merge pull request #2797 from code-yeongyu/fix/2353-model-selection-persistence"
This reverts commit e691303919, reversing
changes made to d4aee20743.
2026-03-24 17:59:21 +09:00
YeonGyu-Kim
e691303919 Merge pull request #2797 from code-yeongyu/fix/2353-model-selection-persistence
fix(plugin): preserve selected model across messages
2026-03-24 17:54:34 +09:00
YeonGyu-Kim
d4aee20743 Merge pull request #2794 from code-yeongyu/fix/2775-thinking-block-signatures
fix(thinking-block-validator): reuse signed thinking blocks instead of synthetic placeholders
2026-03-24 17:54:31 +09:00
YeonGyu-Kim
bad70f5e24 fix(plugin): preserve selected model across messages
Reuse the current session's selected model during config-time agent rebuilds when config.model is missing, so desktop sessions do not snap back to the default model after each send.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-24 17:47:08 +09:00
Mou
b9fa2a3ebc fix(background-agent): prevent circuit breaker false positives on flat-format events 2026-03-24 16:35:54 +08:00
YeonGyu-Kim
0e7bd595f8 fix(session-recovery): reuse signed thinking blocks safely
Reuse signed Anthropic thinking blocks only when they can still sort before the target message's parts, otherwise skip recovery instead of reintroducing invalid loops.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-24 17:22:07 +09:00
YeonGyu-Kim
0732cb85f9 fix(thinking-block-validator): reuse signed thinking parts
Preserve prior signed Anthropic thinking blocks instead of creating unsigned synthetic placeholders, and skip injection when no signed block exists.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-24 17:22:07 +09:00
YeonGyu-Kim
500784a9b9 Merge pull request #2790 from code-yeongyu/fix/2666-mcp-schema-sanitization
fix(schema): strip contentEncoding from MCP tool schemas for Gemini (fixes #2200)
2026-03-24 16:24:57 +09:00
YeonGyu-Kim
5e856b4fde fix(schema): strip contentEncoding from MCP tool schemas for Gemini compatibility
The existing normalizeToolArgSchemas only applies to omo plugin tools
(via tool-registry.ts), but MCP server tool schemas bypass this
sanitization entirely. MCP schemas with contentEncoding/contentMediaType
cause Gemini 400 errors.

Add sanitizeJsonSchema() to strip unsupported keywords from MCP tool
inputSchema before serialization in formatMcpCapabilities.

Fixes #2200
Supersedes #2666
2026-03-24 16:24:44 +09:00
YeonGyu-Kim
03dc903e8e Merge pull request #2789 from code-yeongyu/fix/2671-clearSessionState
fix(anthropic-recovery): clear session state after successful summarize (fixes #2225)
2026-03-24 16:23:25 +09:00
YeonGyu-Kim
69d0b23ab6 fix(anthropic-recovery): clear session state after successful summarize and fix timing test
- Add missing clearSessionState() call after successful summarize (line 117)
  Without this, retry state persisted even after success, potentially causing
  unnecessary retries on subsequent compaction events.

- Fix timing-sensitive test: adjust attempt=0 and firstAttemptTime to give
  proper remainingTimeMs buffer for capped delay calculation.

Fixes #2225
Supersedes #2671
2026-03-24 16:23:11 +09:00
YeonGyu-Kim
ee8735cd2c Merge pull request #2788 from code-yeongyu/fix/2670-uiSelectedModel-nullification
fix(agents): preserve uiSelectedModel when agent override has no model (fixes #2351)
2026-03-24 16:22:15 +09:00
YeonGyu-Kim
d8fe61131c fix(agents): preserve uiSelectedModel when agent override has no model
Three agent builder files used falsy checks that incorrectly nullified
uiSelectedModel when override objects existed but had no model set:

- sisyphus-agent.ts: `?.model ?` → `?.model !== undefined ?`
- atlas-agent.ts: `?.model ?` → `?.model !== undefined ?`
- general-agents.ts: `!override?.model` → `override?.model === undefined`

This caused user model selection in web mode to revert to defaults.

Fixes #2351
2026-03-24 16:22:03 +09:00
YeonGyu-Kim
935995d270 Merge pull request #2668 from MoerAI/fix/session-degradation-detection
fix(session): detect post-compaction no-text degradation and trigger recovery (fixes #2232)
2026-03-24 16:21:30 +09:00
YeonGyu-Kim
23d8b88c4a Merge pull request #2669 from MoerAI/fix/atlas-worktree-verification
fix(atlas): use worktree path for git verification when available (fixes #2229)
2026-03-24 16:21:27 +09:00
YeonGyu-Kim
b4285ce565 Merge pull request #2787 from code-yeongyu/fix/review-fixes
fix(permissions): ensure omo permission overrides take precedence over opencode defaults
2026-03-24 16:20:27 +09:00
YeonGyu-Kim
f9d354b63e fix(permissions): ensure omo permission overrides take precedence over opencode defaults
The spread order in applyToolConfig was incorrect - omo's external_directory: 'allow'
was placed BEFORE the config.permission spread, allowing opencode's default 'ask' to
overwrite it. This caused write/edit tools to hang on headless opencode serve sessions
(no TUI to approve permission prompts).

Move omo's permission overrides AFTER the base config spread so they always win.

Fixes write/edit tool hangs when running opencode serve headlessly.
2026-03-24 16:19:56 +09:00
YeonGyu-Kim
370eb945ee Merge pull request #2786 from code-yeongyu/docs/rename-opencode-to-openagent
docs: rename oh-my-opencode to oh-my-openagent
2026-03-24 15:39:00 +09:00
YeonGyu-Kim
6387065e6f docs: rename oh-my-opencode to oh-my-openagent 2026-03-24 15:31:54 +09:00
YeonGyu-Kim
bebdb97c21 Merge pull request #2784 from code-yeongyu/fix/remove-openclaw-hyperlink
docs: remove OpenClaw hyperlink
2026-03-24 13:35:12 +09:00
YeonGyu-Kim
b5e2ead4e1 docs: remove OpenClaw hyperlink from Building in Public 2026-03-24 13:34:57 +09:00
YeonGyu-Kim
91922dae36 Merge pull request #2783 from code-yeongyu/fix/building-in-public-image
docs: add screenshot to Building in Public section
2026-03-24 13:34:14 +09:00
YeonGyu-Kim
cb3d8af995 docs: add screenshot to Building in Public section
Added the actual Discord screenshot showing real-time development
with Jobdori in #building-in-public channel.
2026-03-24 13:34:04 +09:00
YeonGyu-Kim
0fb3e2063a Merge pull request #2782 from code-yeongyu/feat/building-in-public-readme
docs: add Building in Public section to all READMEs
2026-03-24 13:23:46 +09:00
YeonGyu-Kim
b37b877c45 docs: add Building in Public section to all READMEs
- Added TIP box linking to #building-in-public Discord channel
- Mentions Jobdori AI assistant (built on heavily customized OpenClaw)
- Added to all 5 language variants (EN, KO, JA, ZH-CN, RU)
- Positioned above waitlist section for visibility
2026-03-24 13:23:21 +09:00
YeonGyu-Kim
f854246d7f Merge pull request #2772 from MoerAI/fix/custom-model-resolution
fix(delegate-task): trust user-configured category models without fuzzy validation (fixes #2740)
2026-03-24 12:38:22 +09:00
YeonGyu-Kim
f1eaa7bf9b fix(shell): detect csh/tcsh and use setenv syntax (#2769)
fix(non-interactive-env): detect shell type for csh/tcsh env var syntax (fixes #2089)
2026-03-24 12:30:49 +09:00
YeonGyu-Kim
ed9b4a6329 Merge pull request #2780 from code-yeongyu/fix/issues-2741-2648-2779
fix: resolve subagent model override, empty plan completion, deep task refusal (#2741, #2648, #2779)
2026-03-24 10:28:24 +09:00
YeonGyu-Kim
a00a22ac4c fix: remove copy-paste artifacts in hephaestus gpt-5-3-codex prompt
Same issue as gpt.ts and gpt-5-4.ts: duplicated CORRECT block with pipe
characters and duplicated Hard Constraints/Task Scope Clarification sections.
2026-03-24 10:14:53 +09:00
YeonGyu-Kim
8879581fc1 fix: remove copy-paste artifacts in hephaestus GPT prompts
- Remove leading pipe characters (|) from duplicated CORRECT block
- Remove duplicated ## Hard Constraints and ### Task Scope Clarification sections
- Properly place Task Scope Clarification section between CORRECT list and Hard Constraints

Addresses review comments by cubic-dev-ai[bot] on PR #2780
2026-03-24 09:57:30 +09:00
YeonGyu-Kim
230ce835e5 fix: resolve 3 bugs - subagent model override, empty plan completion, deep task refusal
- #2741: Pass inheritedModel as fallback in subagent-resolver when user hasn't
  configured an override, ensuring custom provider models take priority
- #2648: Fix getPlanProgress to treat plans with 0 checkboxes as incomplete
  instead of complete (total > 0 && completed === total)
- #2779: Relax Hephaestus single-task guard to accept multi-step sub-tasks
  from Atlas delegation, only rejecting genuinely independent tasks

Fixes #2741, fixes #2648, fixes #2779
2026-03-24 09:45:11 +09:00
YeonGyu-Kim
10e56badb3 Merge pull request #2776 from code-yeongyu/fix/background-agent-timeout-defaults
fix: stabilize background-agent stale timeout tests (Date.now race condition)
2026-03-24 03:29:35 +09:00
YeonGyu-Kim
cddf78434c Merge pull request #2770 from code-yeongyu/fix/ci-test-timeout
fix: add fetch mock to install test to prevent CI timeout
2026-03-24 03:29:23 +09:00
YeonGyu-Kim
0078b736b9 fix: stabilize stale timeout tests with fixed Date.now()
Tests 'should use default timeout when config not provided' (manager.test.ts)
and 'should use DEFAULT_MESSAGE_STALENESS_TIMEOUT_MS when not configured'
(task-poller.test.ts) failed in CI because Date.now() drifted between
test setup (when creating timestamps like Date.now() - 46*60*1000) and
actual execution inside checkAndInterruptStaleTasks().

On slower CI machines, this drift pushed borderline values across
the threshold, causing tasks that should be stale to remain 'running'.

Fix: Mock Date.now with spyOn to return a fixed time, ensuring
consistent timeout calculations regardless of execution speed.
2026-03-23 22:17:03 +09:00
MoerAI
6d7f69625b fix: update stale timeout test fixtures for new 45/60 min defaults 2026-03-23 21:00:59 +09:00
MoerAI
fda17dd161 fix(background-agent): increase default stale timeouts and improve cancellation messages (fixes #2684) 2026-03-23 20:49:43 +09:00
MoerAI
c41d6fd912 fix(delegate-task): trust user-configured category models without fuzzy validation (fixes #2740) 2026-03-23 20:39:47 +09:00
YeonGyu-Kim
6e9128e060 fix: add fetch mock to install test to prevent CI timeout
The first test case 'non-TUI mode: should show warning but continue when
OpenCode binary not found' was missing a globalThis.fetch mock, causing it
to make a real HTTP request to npm registry via fetchNpmDistTags().
The npm fetch timeout (5s) collided with the test timeout (5s), causing
flaky CI failures.

Added the same fetch mock pattern already used by the other two test cases.
Test runtime dropped from 5000ms+ to ~2ms.
2026-03-23 20:03:45 +09:00
MoerAI
92509d8cfb fix(non-interactive-env): detect shell type for csh/tcsh env var syntax (fixes #2089) 2026-03-23 19:33:54 +09:00
YeonGyu-Kim
331f7ec52b Merge pull request #2768 from code-yeongyu/fix/issue-2117
fix: emit formatter events from hashline-edit tool (fixes #2117)
2026-03-23 18:49:10 +09:00
YeonGyu-Kim
4ba2da7ebb fix: add tests and fix typing for formatter trigger (#2768) 2026-03-23 18:46:44 +09:00
YeonGyu-Kim
f95d3b1ef5 fix: emit formatter events from hashline-edit tool (fixes #2117) 2026-03-23 18:40:27 +09:00
YeonGyu-Kim
d5d7c7dd26 Merge pull request #2767 from code-yeongyu/fix/issue-2742
fix: respect disabled_tools config in agent prompts (fixes #2742)
2026-03-23 18:39:51 +09:00
YeonGyu-Kim
6a56c0e241 Merge pull request #2766 from code-yeongyu/fix/issue-390
fix: trigger compaction before continue after session error recovery (fixes #390)
2026-03-23 18:39:50 +09:00
YeonGyu-Kim
94c234c88c Merge pull request #2765 from code-yeongyu/fix/issue-2024
fix: skip keyword injection for non-OMO agents (fixes #2024)
2026-03-23 18:39:48 +09:00
YeonGyu-Kim
2ab976c511 Merge pull request #2764 from code-yeongyu/fix/issue-2624
fix: add oh-my-openagent.jsonc config file detection (fixes #2624)
2026-03-23 18:39:46 +09:00
YeonGyu-Kim
dc66088483 Merge pull request #2763 from code-yeongyu/fix/issue-2037
fix: respect OPENCODE_DISABLE_CLAUDE_CODE env vars (fixes #2037)
2026-03-23 18:39:45 +09:00
YeonGyu-Kim
67b5f46a7c Merge pull request #2762 from code-yeongyu/fix/issue-2150
fix: clarify Prometheus file permission error message (fixes #2150)
2026-03-23 18:39:43 +09:00
YeonGyu-Kim
0e483d27ac Merge pull request #2761 from code-yeongyu/fix/issue-2729
fix: validate serverUrl port before tmux pane spawn (fixes #2729)
2026-03-23 18:39:41 +09:00
YeonGyu-Kim
f5eaa648e9 fix: respect disabled_tools config in agent prompts (fixes #2742)
- Check disabled_tools for 'question' in tool-config-handler permission logic
- Strip Question tool code examples from Prometheus prompts when disabled
- Pass disabled_tools through prometheus agent config builder pipeline
- Add tests for disabled_tools question permission handling
2026-03-23 18:13:38 +09:00
YeonGyu-Kim
4c4760a4ee fix: trigger compaction before continue after session error recovery (fixes #390) 2026-03-23 18:12:51 +09:00
YeonGyu-Kim
7f20dd6ff5 fix: add oh-my-openagent.jsonc config file detection (fixes #2624) 2026-03-23 18:11:01 +09:00
YeonGyu-Kim
de371be236 fix: skip keyword injection for non-OMO agents (fixes #2024) 2026-03-23 18:10:44 +09:00
YeonGyu-Kim
f3c2138ef4 fix: respect OPENCODE_DISABLE_CLAUDE_CODE env vars (fixes #2037) 2026-03-23 18:10:08 +09:00
YeonGyu-Kim
0810e37240 fix: validate serverUrl port before tmux pane spawn (fixes #2729) 2026-03-23 18:09:31 +09:00
YeonGyu-Kim
a64e364fa6 fix: clarify Prometheus file permission error message (fixes #2150) 2026-03-23 18:07:59 +09:00
github-actions[bot]
d886ac701f @hunghoang3011 has signed the CLA in code-yeongyu/oh-my-openagent#2758 2026-03-23 04:28:31 +00:00
MoerAI
11f1d71c93 fix(prometheus): respect agent model override instead of using global opencode.json model (fixes #2693) 2026-03-23 10:36:59 +09:00
github-actions[bot]
30dc50d880 @0xYiliu has signed the CLA in code-yeongyu/oh-my-openagent#2738 2026-03-21 23:05:07 +00:00
github-actions[bot]
b17e633464 @ndaemy has signed the CLA in code-yeongyu/oh-my-openagent#2734 2026-03-21 10:18:31 +00:00
YeonGyu-Kim
eec268ee42 fix: use find() instead of calls[0] in wakeGateway test to handle background fetch calls 2026-03-21 18:01:39 +09:00
github-actions[bot]
363661c0d6 @whackur has signed the CLA in code-yeongyu/oh-my-openagent#2733 2026-03-21 05:27:27 +00:00
github-actions[bot]
261bbdf4dc @nguyentamdat has signed the CLA in code-yeongyu/oh-my-openagent#2718 2026-03-20 07:34:31 +00:00
YeonGyu-Kim
8aec4c5cb3 feat(hooks/todo-continuation-enforcer): enhance continuation message with skeptical verification guidance 2026-03-20 16:13:02 +09:00
YeonGyu-Kim
16cbc847ac fix(cli/run): set OPENCODE_CLIENT to 'run' to exclude question tool from registry 2026-03-20 16:12:58 +09:00
YeonGyu-Kim
436ce71dc8 docs(skills/github-triage): fix Phase 1 JSON parsing and large repo handling 2026-03-20 16:12:54 +09:00
MoerAI
0e610a72bc fix(runtime-fallback): make fallback provider selection provider-agnostic (fixes #2303) 2026-03-20 09:53:24 +09:00
github-actions[bot]
d2a49428b9 @tonymfer has signed the CLA in code-yeongyu/oh-my-openagent#2701 2026-03-19 17:14:04 +00:00
github-actions[bot]
c3b23bf603 @trafgals has signed the CLA in code-yeongyu/oh-my-openagent#2690 2026-03-19 04:22:43 +00:00
YeonGyu-Kim
50094de73e docs: fix remaining AGENTS hook composition text
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-19 12:02:52 +09:00
YeonGyu-Kim
3aa2748c04 docs: sync hook counts after continuation hook removal
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-19 12:02:52 +09:00
YeonGyu-Kim
ccaf759b6b fix(hooks): remove gpt permission continuation hook
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-19 12:02:52 +09:00
YeonGyu-Kim
521a1f76a9 fix(atlas): stop only after 10 consecutive prompt failures
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-19 12:02:52 +09:00
github-actions[bot]
490f0f2090 @walioo has signed the CLA in code-yeongyu/oh-my-openagent#2688 2026-03-19 02:35:04 +00:00
YeonGyu-Kim
caf595e727 fix(build-binaries): prevent test imports from triggering binary builds
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-19 10:47:33 +09:00
YeonGyu-Kim
1f64a45113 Merge pull request #2620 from code-yeongyu/feat/openclaw-bidirectional
feat: port OpenClaw bidirectional integration from omx
2026-03-19 10:47:07 +09:00
YeonGyu-Kim
9b2dc2189c fix(ralph-loop): detect promise tags in tool_result parts for ulw verification
Oracle's <promise>VERIFIED</promise> arrives as a tool_result part from the
task() tool call, not as a text part. Both detectCompletionInSessionMessages
and collectAssistantText only scanned type=text parts, missing the
verification signal entirely. This caused ulw loops to fail verification
even when Oracle successfully emitted VERIFIED.

Include tool_result parts in promise detection alongside text parts.
Exclude tool_use parts to avoid false positives from instructional text.
2026-03-18 19:09:59 +09:00
MoerAI
071fab1618 fix: match existing codebase session.messages() parameter shape 2026-03-18 19:08:05 +09:00
YeonGyu-Kim
f6c24e42af fix(ralph-loop): detect promise tags in tool_result parts for ulw verification
Oracle's <promise>VERIFIED</promise> arrives as a tool_result part from the
task() tool call, not as a text part. Both detectCompletionInSessionMessages
and collectAssistantText only scanned type=text parts, missing the
verification signal entirely. This caused ulw loops to fail verification
even when Oracle successfully emitted VERIFIED.

Include tool_result parts in promise detection alongside text parts.
Exclude tool_use parts to avoid false positives from instructional text.
2026-03-18 19:03:30 +09:00
YeonGyu-Kim
22fd976eb9 feat(categories): change quick category default model from claude-haiku-4-5 to gpt-5.4-mini
GPT-5.4-mini provides stronger reasoning at comparable speed and cost.
Haiku remains as the next fallback priority in the chain.

Changes:
- DEFAULT_CATEGORIES quick model: anthropic/claude-haiku-4-5 → openai/gpt-5.4-mini
- Fallback chain: gpt-5.4-mini → haiku → gemini-3-flash → minimax-m2.5 → gpt-5-nano
- OpenAI-only catalog: quick uses gpt-5.4-mini directly
- Think-mode: add gpt-5-4-mini and gpt-5-4-nano high variants
- Update all documentation references
2026-03-18 19:03:30 +09:00
YeonGyu-Kim
826284f3d9 Merge pull request #2676 from code-yeongyu/fix/atlas-task-session-review-followup
fix(atlas): address review findings for task session reuse
2026-03-18 18:50:45 +09:00
YeonGyu-Kim
3c7e6a3940 fix(atlas): address review findings for task session reuse 2026-03-18 18:44:42 +09:00
YeonGyu-Kim
33ef4db502 Merge pull request #2640 from HaD0Yun/had0yun/atlas-task-session-reuse
feat(atlas): persist preferred task session reuse
2026-03-18 18:37:16 +09:00
YeonGyu-Kim
458ec06b0e fix: extract question text from questions array per opencode tool schema 2026-03-18 18:27:09 +09:00
YeonGyu-Kim
6b66f69433 feat(gpt-permission-continuation): add context-aware continuation prompts
- Add buildContextualContinuationPrompt to include assistant message context
- Move extractPermissionPhrase to detector module for better separation
- Block continuation injection in subagent sessions
- Update handler to use contextual prompts with last response context
- Add tests for subagent session blocking and contextual prompts
- Update todo coordination test to verify new prompt format

🤖 Generated with assistance of OhMyOpenCode
2026-03-18 17:52:32 +09:00
YeonGyu-Kim
ce8957e1e1 fix(ralph-loop): harden oracle verification flow
Capture oracle verification sessions more reliably and accept parent-session VERIFIED evidence so ULW loops do not retry after successful review.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-18 17:45:59 +09:00
MoerAI
a3db64b931 fix: address cubic review — SDK compatibility and race condition fixes 2026-03-18 17:42:17 +09:00
HaD0Yun
8859da5fef fix(atlas): harden task session reuse 2026-03-18 17:31:27 +09:00
YeonGyu-Kim
23c0ff60f2 feat(background-agent): increase default max tool calls to 4000
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-18 16:36:55 +09:00
MoerAI
4723319eef fix(atlas): use worktree path for git verification when available (fixes #2229) 2026-03-18 16:23:37 +09:00
MoerAI
b8f3186d65 fix(session): detect post-compaction no-text degradation and trigger recovery (fixes #2232) 2026-03-18 16:13:23 +09:00
YeonGyu-Kim
01e18f8773 chore: remove console.* debug logging from non-CLI source files 2026-03-18 15:29:50 +09:00
YeonGyu-Kim
1669c83782 revert(todo-continuation): remove [TODO-DIAG] console.error debug logging 2026-03-18 15:10:51 +09:00
YeonGyu-Kim
09cfd0b408 diag(todo-continuation): add comprehensive debug logging for session idle handling
Add [TODO-DIAG] console.error statements throughout the todo continuation
enforcer to help diagnose why continuation prompts aren't being injected.

Changes:
- Add session.idle event handler diagnostic in handler.ts
- Add detailed blocking reason logging in idle-event.ts for all gate checks
- Update JSON schema to reflect circuit breaker config changes

🤖 Generated with assistance of [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
2026-03-18 14:45:14 +09:00
YeonGyu-Kim
d48ea025f0 refactor(circuit-breaker): replace sliding window with consecutive call detection
Switch background task loop detection from percentage-based sliding window
(80% of 20-call window) to consecutive same-tool counting. Triggers when
same tool signature is called 20+ times in a row; a different tool resets
the counter.
2026-03-18 14:32:27 +09:00
YeonGyu-Kim
c5c7ba4eed perf: pre-compile regex patterns and optimize hot-path string operations
- error-classifier: pre-compile default retry pattern regex
- think-mode/detector: combine multilingual patterns into single regex
- parser: skip redundant toLowerCase on pre-lowered keywords
- edit-operations: use fast arraysEqual instead of JSON comparison
- hash-computation: optimize streaming line extraction with index tracking
2026-03-18 14:19:23 +09:00
YeonGyu-Kim
90aa3a306c perf(hooks,tools): optimize string operations and reduce redundant iterations
- output-renderer, hashline-edit-diff: replace str += with array join (H2)
- auto-slash-command: single-pass Map grouping instead of 6x filter (M1)
- comment-checker: hoist Zod schema to module scope (M2)
- session-last-agent: reverse iterate sorted array instead of sort+reverse (L2)
2026-03-18 14:19:12 +09:00
YeonGyu-Kim
c2f7d059d2 perf(shared): optimize hot-path utilities across plugin
- task-list: replace O(n³) blocker resolution with Map lookup (C4)
- logger: buffer log entries and flush periodically to reduce sync I/O (C5)
- plugin-interface: create chatParamsHandler once at init (H3)
- pattern-matcher: cache compiled RegExp for wildcard matchers (H6)
- file-reference-resolver: use replaceAll instead of split/join (M9)
- connected-providers-cache: add in-memory cache for read operations (L4)
2026-03-18 14:19:00 +09:00
YeonGyu-Kim
7a96a167e6 perf(claude-code-hooks): defer config loading until after disabled check
Move loadClaudeHooksConfig and loadPluginExtendedConfig after isHookDisabled check
in both tool-execute-before and tool-execute-after handlers to skip 5 file reads
per tool call when hooks are disabled (C1)
2026-03-18 14:18:49 +09:00
YeonGyu-Kim
2da19fe608 perf(background-agent): use Set for countedToolPartIDs, cache circuit breaker settings, optimize loop detector
- Replace countedToolPartIDs string[] with Set<string> for O(1) has/add vs O(n) includes/spread (C2)
- Cache resolveCircuitBreakerSettings at manager level to avoid repeated object creation (C3)
- Optimize recordToolCall to avoid full array copy with slice (L1)
2026-03-18 14:18:38 +09:00
YeonGyu-Kim
952bd5338d fix(background-agent): treat non-active session statuses as terminal to prevent parent session hang
Previously, pollRunningTasks() and checkAndInterruptStaleTasks() treated
any non-"idle" session status as "still running", which caused tasks with
terminal statuses like "interrupted" to be skipped indefinitely — both
for completion detection AND stale timeout. This made the parent session
hang forever waiting for an ALL COMPLETE notification that never came.

Extract isActiveSessionStatus() and isTerminalSessionStatus() that
classify session statuses explicitly. Only known active statuses
("busy", "retry", "running") protect tasks from completion/stale checks.
Known terminal statuses ("interrupted") trigger immediate completion.
Unknown statuses fall through to the standard idle/gone path with output
validation as a conservative default.

Introduced by: a0c93816 (2026-02-14), dc370f7f (2026-03-08)
2026-03-18 14:06:23 +09:00
Ravi Tharuma
71b1f7e807 fix(anthropic-effort): clamp variant against mutable request message 2026-03-17 11:57:56 +01:00
HaD0Yun
8adf6a2c47 fix(atlas): tighten session reuse metadata parsing 2026-03-17 18:14:17 +09:00
HaD0Yun
5c6194372e feat(atlas): persist preferred task session reuse 2026-03-17 17:25:46 +09:00
YeonGyu-Kim
399796cbe4 fix(openclaw): add comment clarifying proc.exited race condition avoidance
cubic identified potential race condition where Bun's proc.exitCode
may be null immediately after stdout closes. Added clarifying
comment that await proc.exited ensures exitCode is set before
checking.

fixes: cubic review on PR #2620
2026-03-17 17:14:52 +09:00
YeonGyu-Kim
77c3ed1a1f chore: remove omx state files and add .omx/ to gitignore 2026-03-17 17:00:29 +09:00
YeonGyu-Kim
82e25c845b fix: address cubic re-review — remove non-existent session.stop event, fix env var fallback test 2026-03-17 17:00:18 +09:00
YeonGyu-Kim
c644930753 Fix OpenClaw review issues 2026-03-16 22:28:54 +09:00
YeonGyu-Kim
b79df5e018 feat: port OpenClaw bidirectional integration from omx
Ports the complete OpenClaw integration system from oh-my-codex:

Outbound (opencode→OpenClaw):
- wakeOpenClaw() fire-and-forget gateway notifications
- HTTP and command gateway dispatchers
- Template variable interpolation
- Config from oh-my-opencode.jsonc (no env gate needed)

Inbound (OpenClaw→opencode):
- Reply listener daemon (Discord/Telegram polling)
- Session registry for message↔tmux pane correlation
- Tmux pane detection, content capture, and text injection
- Input sanitization and rate limiting
- Pane verification before injection

Files:
- src/openclaw/ (types, config, dispatcher, index, reply-listener, session-registry, tmux, daemon)
- src/config/schema/openclaw.ts (Zod v4 schema)
- src/hooks/openclaw.ts (session hook)
- Tests: 12 pass (config + dispatcher)
2026-03-16 21:55:10 +09:00
MoerAI
6455b851b8 fix(config): keep default OpenCode Build agent enabled by default
The default_builder_enabled config defaults to false, which removes
the default OpenCode Build agent on OMO install. This forces users
into the full OMO orchestration for every task, including simple ones
where the lightweight Build agent would be more appropriate.

Changed the default to true so the Build agent remains available
alongside Sisyphus. Users who prefer the previous behavior can set
default_builder_enabled: false in their config.

Fixes #2545
2026-03-16 19:18:46 +09:00
Ravi Tharuma
9346bc8379 fix: clamp variant "max" to "high" for non-Opus Claude models on fallback
When an agent configured with variant: "max" falls back from Opus to
Sonnet (or Haiku), the "max" variant was passed through unchanged.
OpenCode sends this as level: "max" to the Anthropic API, which rejects
it with: level "max" not supported, valid levels: low, medium, high

The anthropic-effort hook previously only handled Opus (inject effort=max)
and skipped all other Claude models. Now it actively clamps "max" → "high"
for non-Opus Claude models and mutates message.variant so OpenCode
doesn't pass the unsupported level to the API.
2026-03-16 07:49:55 +01:00
365 changed files with 9675 additions and 7020 deletions

View File

@@ -1,24 +1,26 @@
name: Bug Report
description: Report a bug or unexpected behavior in oh-my-openagent
description: Report a bug or unexpected behavior in oh-my-opencode
title: "[Bug]: "
labels: ["bug", "needs-triage"]
body:
- type: markdown
attributes:
value: |
**Please write your issue in English.** See our [Language Policy](https://github.com/code-yeongyu/oh-my-openagent/blob/dev/CONTRIBUTING.md#language-policy) for details.
**Please write your issue in English.** See our [Language Policy](https://github.com/code-yeongyu/oh-my-opencode/blob/dev/CONTRIBUTING.md#language-policy) for details.
- type: checkboxes
id: prerequisites
attributes:
label: Prerequisites
description: Please confirm the following before submitting
options:
- label: I will write this issue in English (see our [Language Policy](https://github.com/code-yeongyu/oh-my-openagent/blob/dev/CONTRIBUTING.md#language-policy))
- label: I will write this issue in English (see our [Language Policy](https://github.com/code-yeongyu/oh-my-opencode/blob/dev/CONTRIBUTING.md#language-policy))
required: true
- label: I have searched existing issues to avoid duplicates
required: true
- label: I am using the latest version of oh-my-openagent
- label: I am using the latest version of oh-my-opencode
required: true
- label: I have read the [documentation](https://github.com/code-yeongyu/oh-my-openagent#readme) or asked an AI coding agent with this project's GitHub URL loaded and couldn't find the answer
- label: I have read the [documentation](https://github.com/code-yeongyu/oh-my-opencode#readme) or asked an AI coding agent with this project's GitHub URL loaded and couldn't find the answer
required: true
- type: textarea
@@ -36,7 +38,8 @@ body:
label: Steps to Reproduce
description: Steps to reproduce the behavior
placeholder: |
1. Configure oh-my-openagent with...
1. Configure oh-my-opencode with...
2. Run command '...'
3. See error...
validations:
required: true
@@ -64,12 +67,15 @@ body:
attributes:
label: Doctor Output
description: |
**Required:** Run `bunx oh-my-openagent doctor` and paste the full output below.
**Required:** Run `bunx oh-my-opencode doctor` and paste the full output below.
This helps us diagnose your environment and configuration.
placeholder: |
Paste the output of: bunx oh-my-openagent doctor
Paste the output of: bunx oh-my-opencode doctor
Example:
✓ OpenCode version: 1.0.150
✓ oh-my-openagent version: 1.2.3
✓ oh-my-opencode version: 1.2.3
✓ Plugin loaded successfully
...
render: shell
validations:
@@ -87,7 +93,7 @@ body:
id: config
attributes:
label: Configuration
description: If relevant, share your oh-my-openagent configuration (remove sensitive data)
description: If relevant, share your oh-my-opencode configuration (remove sensitive data)
placeholder: |
{
"agents": { ... },

View File

@@ -4,4 +4,5 @@ contact_links:
url: https://discord.gg/PUwSMR9XNk
about: Join our Discord server for real-time discussions and community support
- name: Documentation
url: https://github.com/code-yeongyu/oh-my-openagent#readme
url: https://github.com/code-yeongyu/oh-my-opencode#readme
about: Read the comprehensive documentation and guides

View File

@@ -1,24 +1,26 @@
name: Feature Request
description: Suggest a new feature or enhancement for oh-my-openagent
description: Suggest a new feature or enhancement for oh-my-opencode
title: "[Feature]: "
labels: ["enhancement", "needs-triage"]
body:
- type: markdown
attributes:
value: |
**Please write your issue in English.** See our [Language Policy](https://github.com/code-yeongyu/oh-my-openagent/blob/dev/CONTRIBUTING.md#language-policy) for details.
**Please write your issue in English.** See our [Language Policy](https://github.com/code-yeongyu/oh-my-opencode/blob/dev/CONTRIBUTING.md#language-policy) for details.
- type: checkboxes
id: prerequisites
attributes:
label: Prerequisites
description: Please confirm the following before submitting
options:
- label: I will write this issue in English (see our [Language Policy](https://github.com/code-yeongyu/oh-my-openagent/blob/dev/CONTRIBUTING.md#language-policy))
- label: I will write this issue in English (see our [Language Policy](https://github.com/code-yeongyu/oh-my-opencode/blob/dev/CONTRIBUTING.md#language-policy))
required: true
- label: I have searched existing issues and discussions to avoid duplicates
required: true
- label: This feature request is specific to oh-my-openagent (not OpenCode core)
- label: This feature request is specific to oh-my-opencode (not OpenCode core)
required: true
- label: I have read the [documentation](https://github.com/code-yeongyu/oh-my-openagent#readme) or asked an AI coding agent with this project's GitHub URL loaded and couldn't find the answer
- label: I have read the [documentation](https://github.com/code-yeongyu/oh-my-opencode#readme) or asked an AI coding agent with this project's GitHub URL loaded and couldn't find the answer
required: true
- type: textarea
@@ -57,9 +59,11 @@ body:
attributes:
label: Doctor Output (Optional)
description: |
If relevant to your feature request, run `bunx oh-my-openagent doctor` and paste the output.
If relevant to your feature request, run `bunx oh-my-opencode doctor` and paste the output.
This helps us understand your environment.
placeholder: |
Paste the output of: bunx oh-my-openagent doctor
Paste the output of: bunx oh-my-opencode doctor
(Optional for feature requests)
render: shell
- type: textarea

View File

@@ -1,23 +1,24 @@
name: Question or Discussion
description: Ask a question or start a discussion about oh-my-openagent
description: Ask a question or start a discussion about oh-my-opencode
title: "[Question]: "
labels: ["question", "needs-triage"]
body:
- type: markdown
attributes:
value: |
**Please write your issue in English.** See our [Language Policy](https://github.com/code-yeongyu/oh-my-openagent/blob/dev/CONTRIBUTING.md#language-policy) for details.
**Please write your issue in English.** See our [Language Policy](https://github.com/code-yeongyu/oh-my-opencode/blob/dev/CONTRIBUTING.md#language-policy) for details.
- type: checkboxes
id: prerequisites
attributes:
label: Prerequisites
description: Please confirm the following before submitting
options:
- label: I will write this issue in English (see our [Language Policy](https://github.com/code-yeongyu/oh-my-openagent/blob/dev/CONTRIBUTING.md#language-policy))
- label: I will write this issue in English (see our [Language Policy](https://github.com/code-yeongyu/oh-my-opencode/blob/dev/CONTRIBUTING.md#language-policy))
required: true
- label: I have searched existing issues and discussions
required: true
- label: I have read the [documentation](https://github.com/code-yeongyu/oh-my-openagent#readme) or asked an AI coding agent with this project's GitHub URL loaded and couldn't find the answer
- label: I have read the [documentation](https://github.com/code-yeongyu/oh-my-opencode#readme) or asked an AI coding agent with this project's GitHub URL loaded and couldn't find the answer
required: true
- label: This is a question (not a bug report or feature request)
required: true
@@ -52,9 +53,9 @@ body:
attributes:
label: Doctor Output (Optional)
description: |
If your question is about configuration or setup, run `bunx oh-my-openagent doctor` and paste the output.
If your question is about configuration or setup, run `bunx oh-my-opencode doctor` and paste the output.
placeholder: |
Paste the output of: bunx oh-my-openagent doctor
Paste the output of: bunx oh-my-opencode doctor
(Optional for questions)
render: shell

BIN
.github/assets/building-in-public.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 278 KiB

View File

@@ -23,11 +23,12 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
path-to-signatures: 'signatures/cla.json'
path-to-document: 'https://github.com/code-yeongyu/oh-my-openagent/blob/master/CLA.md'
path-to-document: 'https://github.com/code-yeongyu/oh-my-opencode/blob/master/CLA.md'
branch: 'dev'
allowlist: code-yeongyu,bot*,dependabot*,github-actions*,*[bot],sisyphus-dev-ai,web-flow
custom-notsigned-prcomment: |
Thank you for your contribution! Before we can merge this PR, we need you to sign our [Contributor License Agreement (CLA)](https://github.com/code-yeongyu/oh-my-openagent/blob/master/CLA.md).
Thank you for your contribution! Before we can merge this PR, we need you to sign our [Contributor License Agreement (CLA)](https://github.com/code-yeongyu/oh-my-opencode/blob/master/CLA.md).
**To sign the CLA**, please comment on this PR with:
```
I have read the CLA Document and I hereby sign the CLA

View File

@@ -216,10 +216,6 @@ jobs:
retention-days: 1
if-no-files-found: error
# =============================================================================
# Job 2: Publish all platforms (oh-my-openagent + oh-my-opencode)
# - Uses NODE_AUTH_TOKEN for auth + OIDC for provenance attestation
# =============================================================================
publish:
needs: build
if: always() && !cancelled()
@@ -230,35 +226,38 @@ jobs:
matrix:
platform: [darwin-arm64, darwin-x64, darwin-x64-baseline, linux-x64, linux-x64-baseline, linux-arm64, linux-x64-musl, linux-x64-musl-baseline, linux-arm64-musl, windows-x64, windows-x64-baseline]
steps:
- name: Check if oh-my-openagent already published
- name: Check if already published
id: check
run: |
PKG_NAME="oh-my-openagent-${{ matrix.platform }}"
VERSION="${{ inputs.version }}"
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://registry.npmjs.org/${PKG_NAME}/${VERSION}")
if [ "$STATUS" = "200" ]; then
echo "skip=true" >> $GITHUB_OUTPUT
echo "✓ ${PKG_NAME}@${VERSION} already published, skipping"
OC_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://registry.npmjs.org/oh-my-opencode-${{ matrix.platform }}/${VERSION}")
OA_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://registry.npmjs.org/oh-my-openagent-${{ matrix.platform }}/${VERSION}")
if [ "$OC_STATUS" = "200" ]; then
echo "skip_opencode=true" >> $GITHUB_OUTPUT
echo "✓ oh-my-opencode-${{ matrix.platform }}@${VERSION} already published"
else
echo "→ ${PKG_NAME}@${VERSION} will be published"
echo "skip_opencode=false" >> $GITHUB_OUTPUT
fi
- name: Check if oh-my-opencode already published
id: check-opencode
run: |
PKG_NAME="oh-my-opencode-${{ matrix.platform }}"
VERSION="${{ inputs.version }}"
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://registry.npmjs.org/${PKG_NAME}/${VERSION}")
if [ "$STATUS" = "200" ]; then
echo "skip=true" >> $GITHUB_OUTPUT
echo "✓ ${PKG_NAME}@${VERSION} already published, skipping"
if [ "$OA_STATUS" = "200" ]; then
echo "skip_openagent=true" >> $GITHUB_OUTPUT
echo "✓ oh-my-openagent-${{ matrix.platform }}@${VERSION} already published"
else
echo "→ ${PKG_NAME}@${VERSION} will be published"
echo "skip_openagent=false" >> $GITHUB_OUTPUT
fi
# Need artifact if either package needs publishing
if [ "$OC_STATUS" = "200" ] && [ "$OA_STATUS" = "200" ]; then
echo "skip_all=true" >> $GITHUB_OUTPUT
else
echo "skip_all=false" >> $GITHUB_OUTPUT
fi
- name: Download artifact
id: download
if: steps.check.outputs.skip != 'true' || steps.check-opencode.outputs.skip != 'true'
if: steps.check.outputs.skip_all != 'true'
continue-on-error: true
uses: actions/download-artifact@v4
with:
@@ -266,7 +265,7 @@ jobs:
path: .
- name: Extract artifact
if: (steps.check.outputs.skip != 'true' || steps.check-opencode.outputs.skip != 'true') && steps.download.outcome == 'success'
if: steps.check.outputs.skip_all != 'true' && steps.download.outcome == 'success'
run: |
PLATFORM="${{ matrix.platform }}"
mkdir -p packages/${PLATFORM}
@@ -282,43 +281,43 @@ jobs:
ls -la packages/${PLATFORM}/bin/
- uses: actions/setup-node@v4
if: (steps.check.outputs.skip != 'true' || steps.check-opencode.outputs.skip != 'true') && steps.download.outcome == 'success'
if: steps.check.outputs.skip_all != 'true' && steps.download.outcome == 'success'
with:
node-version: "24"
registry-url: "https://registry.npmjs.org"
- name: Publish oh-my-opencode-${{ matrix.platform }}
if: steps.check.outputs.skip_opencode != 'true' && steps.download.outcome == 'success'
run: |
cd packages/${{ matrix.platform }}
TAG_ARG=""
if [ -n "${{ inputs.dist_tag }}" ]; then
TAG_ARG="--tag ${{ inputs.dist_tag }}"
fi
npm publish --access public --provenance $TAG_ARG
env:
NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }}
NPM_CONFIG_PROVENANCE: true
timeout-minutes: 15
- name: Publish oh-my-openagent-${{ matrix.platform }}
if: steps.check.outputs.skip != 'true' && steps.download.outcome == 'success'
if: steps.check.outputs.skip_openagent != 'true' && steps.download.outcome == 'success'
run: |
cd packages/${{ matrix.platform }}
TAG_ARG=""
if [ -n "${{ inputs.dist_tag }}" ]; then
TAG_ARG="--tag ${{ inputs.dist_tag }}"
fi
npm publish --access public --provenance $TAG_ARG
env:
NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }}
NPM_CONFIG_PROVENANCE: true
timeout-minutes: 15
- name: Publish oh-my-opencode-${{ matrix.platform }} (alias)
if: steps.check-opencode.outputs.skip != 'true' && steps.download.outcome == 'success'
run: |
cd packages/${{ matrix.platform }}
# Rename package for oh-my-opencode
jq --arg name "oh-my-opencode-${{ matrix.platform }}" \
--arg desc "Platform-specific binary for oh-my-opencode (${{ matrix.platform }})" \
'.name = $name | .description = $desc | .bin = {"oh-my-opencode": (.bin | to_entries | .[0].value)}' \
# Rename package for oh-my-openagent
jq --arg name "oh-my-openagent-${{ matrix.platform }}" \
--arg desc "Platform-specific binary for oh-my-openagent (${{ matrix.platform }})" \
'.name = $name | .description = $desc | .bin = {"oh-my-openagent": (.bin | to_entries | .[0].value)}' \
package.json > tmp.json && mv tmp.json package.json
TAG_ARG=""
if [ -n "${{ inputs.dist_tag }}" ]; then
TAG_ARG="--tag ${{ inputs.dist_tag }}"
fi
npm publish --access public --provenance $TAG_ARG
env:
NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }}

View File

@@ -57,6 +57,7 @@ jobs:
bun test src/cli/doctor/format-default.test.ts
bun test src/tools/call-omo-agent/sync-executor.test.ts
bun test src/tools/call-omo-agent/session-creator.test.ts
bun test src/tools/session-manager
bun test src/features/opencode-skill-loader/loader.test.ts
bun test src/hooks/anthropic-context-window-limit-recovery/recovery-hook.test.ts
bun test src/hooks/anthropic-context-window-limit-recovery/executor.test.ts
@@ -66,9 +67,8 @@ jobs:
# Enumerate subdirectories/files explicitly to EXCLUDE mock-heavy files
# that were already run in isolation above.
# Excluded from src/cli: doctor/formatter.test.ts, doctor/format-default.test.ts
# Excluded from src/tools: call-omo-agent/sync-executor.test.ts, call-omo-agent/session-creator.test.ts
# Excluded from src/tools: call-omo-agent/sync-executor.test.ts, call-omo-agent/session-creator.test.ts, session-manager (all)
# Excluded from src/hooks/anthropic-context-window-limit-recovery: recovery-hook.test.ts, executor.test.ts
# Excluded from src/tools: call-omo-agent/sync-executor.test.ts, call-omo-agent/session-creator.test.ts
bun test bin script src/config src/mcp src/index.test.ts \
src/agents src/shared \
src/cli/run src/cli/config-manager src/cli/mcp-oauth \
@@ -77,7 +77,7 @@ jobs:
src/cli/doctor/runner.test.ts src/cli/doctor/checks \
src/tools/ast-grep src/tools/background-task src/tools/delegate-task \
src/tools/glob src/tools/grep src/tools/interactive-bash \
src/tools/look-at src/tools/lsp src/tools/session-manager \
src/tools/look-at src/tools/lsp \
src/tools/skill src/tools/skill-mcp src/tools/slashcommand src/tools/task \
src/tools/call-omo-agent/background-agent-executor.test.ts \
src/tools/call-omo-agent/background-executor.test.ts \
@@ -151,7 +151,7 @@ jobs:
run: |
VERSION="${{ inputs.version }}"
if [ -z "$VERSION" ]; then
PREV=$(curl -s https://registry.npmjs.org/oh-my-openagent/latest | jq -r '.version // "0.0.0"')
PREV=$(curl -s https://registry.npmjs.org/oh-my-opencode/latest | jq -r '.version // "0.0.0"')
BASE="${PREV%%-*}"
IFS='.' read -r MAJOR MINOR PATCH <<< "$BASE"
case "${{ inputs.bump }}" in
@@ -175,10 +175,10 @@ jobs:
id: check
run: |
VERSION="${{ steps.version.outputs.version }}"
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://registry.npmjs.org/oh-my-openagent/${VERSION}")
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://registry.npmjs.org/oh-my-opencode/${VERSION}")
if [ "$STATUS" = "200" ]; then
echo "skip=true" >> $GITHUB_OUTPUT
echo "✓ oh-my-openagent@${VERSION} already published"
echo "✓ oh-my-opencode@${VERSION} already published"
else
echo "skip=false" >> $GITHUB_OUTPUT
fi
@@ -204,27 +204,9 @@ jobs:
bunx tsc --emitDeclarationOnly
bun run build:schema
- name: Publish oh-my-openagent (primary)
- name: Publish oh-my-opencode
if: steps.check.outputs.skip != 'true'
run: |
# Update package name to oh-my-openagent
jq '.name = "oh-my-openagent"' package.json > tmp.json && mv tmp.json package.json
# Update optionalDependencies to use oh-my-openagent naming
jq '.optionalDependencies = {
"oh-my-openagent-darwin-arm64": "${{ steps.version.outputs.version }}",
"oh-my-openagent-darwin-x64": "${{ steps.version.outputs.version }}",
"oh-my-openagent-darwin-x64-baseline": "${{ steps.version.outputs.version }}",
"oh-my-openagent-linux-arm64": "${{ steps.version.outputs.version }}",
"oh-my-openagent-linux-arm64-musl": "${{ steps.version.outputs.version }}",
"oh-my-openagent-linux-x64": "${{ steps.version.outputs.version }}",
"oh-my-openagent-linux-x64-baseline": "${{ steps.version.outputs.version }}",
"oh-my-openagent-linux-x64-musl": "${{ steps.version.outputs.version }}",
"oh-my-openagent-linux-x64-musl-baseline": "${{ steps.version.outputs.version }}",
"oh-my-openagent-windows-x64": "${{ steps.version.outputs.version }}",
"oh-my-openagent-windows-x64-baseline": "${{ steps.version.outputs.version }}"
}' package.json > tmp.json && mv tmp.json package.json
TAG_ARG=""
if [ -n "${{ steps.version.outputs.dist_tag }}" ]; then
TAG_ARG="--tag ${{ steps.version.outputs.dist_tag }}"
@@ -233,37 +215,46 @@ jobs:
env:
NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }}
NPM_CONFIG_PROVENANCE: true
- name: Publish oh-my-opencode (alias)
if: steps.check.outputs.skip != 'true'
- name: Check if oh-my-openagent already published
id: check-openagent
run: |
# Update package name/bin to oh-my-opencode alias
jq '.name = "oh-my-opencode" | .bin = {"oh-my-opencode": "bin/oh-my-openagent.js"}' package.json > tmp.json && mv tmp.json package.json
VERSION="${{ steps.version.outputs.version }}"
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://registry.npmjs.org/oh-my-openagent/${VERSION}")
if [ "$STATUS" = "200" ]; then
echo "skip=true" >> $GITHUB_OUTPUT
echo "✓ oh-my-openagent@${VERSION} already published"
else
echo "skip=false" >> $GITHUB_OUTPUT
fi
- name: Publish oh-my-openagent
if: steps.check-openagent.outputs.skip != 'true'
run: |
VERSION="${{ steps.version.outputs.version }}"
# Update optionalDependencies to use oh-my-opencode naming
jq '.optionalDependencies = {
"oh-my-opencode-darwin-arm64": "${{ steps.version.outputs.version }}",
"oh-my-opencode-darwin-x64": "${{ steps.version.outputs.version }}",
"oh-my-opencode-darwin-x64-baseline": "${{ steps.version.outputs.version }}",
"oh-my-opencode-linux-arm64": "${{ steps.version.outputs.version }}",
"oh-my-opencode-linux-arm64-musl": "${{ steps.version.outputs.version }}",
"oh-my-opencode-linux-x64": "${{ steps.version.outputs.version }}",
"oh-my-opencode-linux-x64-baseline": "${{ steps.version.outputs.version }}",
"oh-my-opencode-linux-x64-musl": "${{ steps.version.outputs.version }}",
"oh-my-opencode-linux-x64-musl-baseline": "${{ steps.version.outputs.version }}",
"oh-my-opencode-windows-x64": "${{ steps.version.outputs.version }}",
"oh-my-opencode-windows-x64-baseline": "${{ steps.version.outputs.version }}"
}' package.json > tmp.json && mv tmp.json package.json
# Update package name, version, and optionalDependencies for oh-my-openagent
jq --arg v "$VERSION" '
.name = "oh-my-openagent" |
.version = $v |
.optionalDependencies = (
.optionalDependencies | to_entries |
map(.key = (.key | sub("^oh-my-opencode-"; "oh-my-openagent-")) | .value = $v) |
from_entries
)
' package.json > tmp.json && mv tmp.json package.json
TAG_ARG=""
if [ -n "${{ steps.version.outputs.dist_tag }}" ]; then
TAG_ARG="--tag ${{ steps.version.outputs.dist_tag }}"
fi
npm publish --access public --provenance $TAG_ARG || echo "oh-my-opencode alias publish may have failed (package may already exist)"
npm publish --access public --provenance $TAG_ARG || echo "::warning::oh-my-openagent publish failed"
env:
NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }}
NPM_CONFIG_PROVENANCE: true
- name: Restore package.json
if: steps.check.outputs.skip != 'true'
if: steps.check-openagent.outputs.skip != 'true'
run: |
git checkout -- package.json

View File

@@ -69,14 +69,14 @@ jobs:
restore-keys: |
${{ runner.os }}-bun-
# Build local oh-my-openagent
- name: Build oh-my-openagent
# Build local oh-my-opencode
- name: Build oh-my-opencode
run: |
bun install
bun run build
# Install OpenCode + configure local plugin + auth in single step
- name: Setup OpenCode with oh-my-openagent
- name: Setup OpenCode with oh-my-opencode
env:
OPENCODE_AUTH_JSON: ${{ secrets.OPENCODE_AUTH_JSON }}
ANTHROPIC_BASE_URL: ${{ secrets.ANTHROPIC_BASE_URL }}
@@ -102,14 +102,14 @@ jobs:
fi
opencode --version
# Run local oh-my-openagent install (uses built dist)
# Run local oh-my-opencode install (uses built dist)
bun run dist/cli/index.js install --no-tui --claude=max20 --openai=no --gemini=no --copilot=no
# Override plugin to use local file reference
OPENCODE_JSON=~/.config/opencode/opencode.json
REPO_PATH=$(pwd)
jq --arg path "file://$REPO_PATH/src/index.ts" '
.plugin = [.plugin[] | select(. != "oh-my-opencode" and . != "oh-my-openagent")] + [$path]
.plugin = [.plugin[] | select(. != "oh-my-opencode")] + [$path]
' "$OPENCODE_JSON" > /tmp/oc.json && mv /tmp/oc.json "$OPENCODE_JSON"
OPENCODE_JSON=~/.config/opencode/opencode.json
@@ -190,7 +190,7 @@ jobs:
}
' "$OPENCODE_JSON" > /tmp/oc.json && mv /tmp/oc.json "$OPENCODE_JSON"
OMO_JSON=~/.config/opencode/oh-my-openagent.json
OMO_JSON=~/.config/opencode/oh-my-opencode.json
PROMPT_APPEND=$(cat << 'PROMPT_EOF'
<ultrawork-mode>
[CODE RED] Maximum precision required. Ultrathink before acting.
@@ -397,7 +397,7 @@ jobs:
--add-label "sisyphus: working" || true
fi
- name: Run oh-my-openagent
- name: Run oh-my-opencode
env:
GITHUB_TOKEN: ${{ secrets.GH_PAT }}
USER_COMMENT: ${{ steps.context.outputs.comment }}

1
.gitignore vendored
View File

@@ -36,3 +36,4 @@ test-injection/
notepad.md
oauth-success.html
*.bun-build
.omx/

View File

@@ -79,47 +79,65 @@ Pass `REPO`, `REPORT_DIR`, and `COMMIT_SHA` to every subagent.
---
## Phase 1: Fetch All Open Items
---
<fetch>
Paginate if 500 results returned.
## Phase 1: Fetch All Open Items (CORRECTED)
**IMPORTANT:** `body` and `comments` fields may contain control characters that break jq parsing. Fetch basic metadata first, then fetch full details per-item in subagents.
```bash
ISSUES=$(gh issue list --repo $REPO --state open --limit 500 \
--json number,title,state,createdAt,updatedAt,labels,author,body,comments)
ISSUE_LEN=$(echo "$ISSUES" | jq length)
if [ "$ISSUE_LEN" -eq 500 ]; then
LAST_DATE=$(echo "$ISSUES" | jq -r '.[-1].createdAt')
# Step 1: Fetch basic metadata (without body/comments to avoid JSON parsing issues)
ISSUES_LIST=$(gh issue list --repo $REPO --state open --limit 500 \
--json number,title,labels,author,createdAt)
ISSUE_COUNT=$(echo "$ISSUES_LIST" | jq length)
# Paginate if needed
if [ "$ISSUE_COUNT" -eq 500 ]; then
LAST_DATE=$(echo "$ISSUES_LIST" | jq -r '.[-1].createdAt')
while true; do
PAGE=$(gh issue list --repo $REPO --state open --limit 500 \
--search "created:<$LAST_DATE" \
--json number,title,state,createdAt,updatedAt,labels,author,body,comments)
PAGE_LEN=$(echo "$PAGE" | jq length)
[ "$PAGE_LEN" -eq 0 ] && break
ISSUES=$(echo "[$ISSUES, $PAGE]" | jq -s 'add | unique_by(.number)')
[ "$PAGE_LEN" -lt 500 ] && break
--json number,title,labels,author,createdAt)
PAGE_COUNT=$(echo "$PAGE" | jq length)
[ "$PAGE_COUNT" -eq 0 ] && break
ISSUES_LIST=$(echo "$ISSUES_LIST" "$PAGE" | jq -s '.[0] + .[1] | unique_by(.number)')
ISSUE_COUNT=$(echo "$ISSUES_LIST" | jq length)
[ "$PAGE_COUNT" -lt 500 ] && break
LAST_DATE=$(echo "$PAGE" | jq -r '.[-1].createdAt')
done
fi
PRS=$(gh pr list --repo $REPO --state open --limit 500 \
--json number,title,state,createdAt,updatedAt,labels,author,body,headRefName,baseRefName,isDraft,mergeable,reviewDecision,statusCheckRollup)
PR_LEN=$(echo "$PRS" | jq length)
if [ "$PR_LEN" -eq 500 ]; then
LAST_DATE=$(echo "$PRS" | jq -r '.[-1].createdAt')
# Same for PRs
PRS_LIST=$(gh pr list --repo $REPO --state open --limit 500 \
--json number,title,labels,author,headRefName,baseRefName,isDraft,createdAt)
PR_COUNT=$(echo "$PRS_LIST" | jq length)
if [ "$PR_COUNT" -eq 500 ]; then
LAST_DATE=$(echo "$PRS_LIST" | jq -r '.[-1].createdAt')
while true; do
PAGE=$(gh pr list --repo $REPO --state open --limit 500 \
--search "created:<$LAST_DATE" \
--json number,title,state,createdAt,updatedAt,labels,author,body,headRefName,baseRefName,isDraft,mergeable,reviewDecision,statusCheckRollup)
PAGE_LEN=$(echo "$PAGE" | jq length)
[ "$PAGE_LEN" -eq 0 ] && break
PRS=$(echo "[$PRS, $PAGE]" | jq -s 'add | unique_by(.number)')
[ "$PAGE_LEN" -lt 500 ] && break
--json number,title,labels,author,headRefName,baseRefName,isDraft,createdAt)
PAGE_COUNT=$(echo "$PAGE" | jq length)
[ "$PAGE_COUNT" -eq 0 ] && break
PRS_LIST=$(echo "$PRS_LIST" "$PAGE" | jq -s '.[0] + .[1] | unique_by(.number)')
PR_COUNT=$(echo "$PRS_LIST" | jq length)
[ "$PAGE_COUNT" -lt 500 ] && break
LAST_DATE=$(echo "$PAGE" | jq -r '.[-1].createdAt')
done
fi
echo "Total issues: $ISSUE_COUNT, Total PRs: $PR_COUNT"
```
</fetch>
**LARGE REPOSITORY HANDLING:**
If total items exceeds 50, you MUST process ALL items. Use the pagination code above to fetch every single open issue and PR.
**DO NOT** sample or limit to 50 items - process the entire backlog.
Example: If there are 500 open issues, spawn 500 subagents. If there are 1000 open PRs, spawn 1000 subagents.
**Note:** Background task system will queue excess tasks automatically.
---

View File

@@ -4,7 +4,7 @@
## OVERVIEW
OpenCode plugin (npm: `oh-my-opencode`) that extends Claude Code (OpenCode fork) with multi-agent orchestration, 46 lifecycle hooks, 26 tools, skill/command/MCP systems, and Claude Code compatibility. 1268 TypeScript files, 160k LOC.
OpenCode plugin (npm: `oh-my-opencode`) that extends Claude Code (OpenCode fork) with multi-agent orchestration, 48 lifecycle hooks, 26 tools, skill/command/MCP systems, and Claude Code compatibility. 1268 TypeScript files, 160k LOC.
## STRUCTURE
@@ -14,14 +14,14 @@ oh-my-opencode/
│ ├── index.ts # Plugin entry: loadConfig → createManagers → createTools → createHooks → createPluginInterface
│ ├── plugin-config.ts # JSONC multi-level config: user → project → defaults (Zod v4)
│ ├── agents/ # 11 agents (Sisyphus, Hephaestus, Oracle, Librarian, Explore, Atlas, Prometheus, Metis, Momus, Multimodal-Looker, Sisyphus-Junior)
│ ├── hooks/ # 46 hooks across 45 directories + 11 standalone files
│ ├── hooks/ # 48 lifecycle hooks across dedicated modules and standalone files
│ ├── tools/ # 26 tools across 15 directories
│ ├── features/ # 19 feature modules (background-agent, skill-loader, tmux, MCP-OAuth, etc.)
│ ├── shared/ # 95+ utility files in 13 categories
│ ├── config/ # Zod v4 schema system (24 files)
│ ├── cli/ # CLI: install, run, doctor, mcp-oauth (Commander.js)
│ ├── mcp/ # 3 built-in remote MCPs (websearch, context7, grep_app)
│ ├── plugin/ # 8 OpenCode hook handlers + 46 hook composition
│ ├── plugin/ # 8 OpenCode hook handlers + 48 hook composition
│ └── plugin-handlers/ # 6-phase config loading pipeline
├── packages/ # Monorepo: cli-runner, 12 platform binaries
└── local-ignore/ # Dev-only test fixtures
@@ -34,7 +34,7 @@ OhMyOpenCodePlugin(ctx)
├─→ loadPluginConfig() # JSONC parse → project/user merge → Zod validate → migrate
├─→ createManagers() # TmuxSessionManager, BackgroundManager, SkillMcpManager, ConfigHandler
├─→ createTools() # SkillContext + AvailableCategories + ToolRegistry (26 tools)
├─→ createHooks() # 3-tier: Core(37) + Continuation(7) + Skill(2) = 46 hooks
├─→ createHooks() # 3-tier: Core(39) + Continuation(7) + Skill(2) = 48 hooks
└─→ createPluginInterface() # 8 OpenCode hook handlers → PluginInterface
```
@@ -97,7 +97,7 @@ Fields: agents (14 overridable, 21 fields each), categories (8 built-in + custom
- **Test pattern**: Bun test (`bun:test`), co-located `*.test.ts`, given/when/then style (nested describe with `#given`/`#when`/`#then` prefixes)
- **CI test split**: mock-heavy tests run in isolation (separate `bun test` processes), rest in batch
- **Factory pattern**: `createXXX()` for all tools, hooks, agents
- **Hook tiers**: Session (23) → Tool-Guard (10) → Transform (4) → Continuation (7) → Skill (2)
- **Hook tiers**: Session (23) → Tool-Guard (12) → Transform (4) → Continuation (7) → Skill (2)
- **Agent modes**: `primary` (respects UI model) vs `subagent` (own fallback chain) vs `all`
- **Model resolution**: 4-step: override → category-default → provider-fallback → system-default
- **Config format**: JSONC with comments, Zod v4 validation, snake_case keys

2
CLA.md
View File

@@ -1,6 +1,6 @@
# Contributor License Agreement
Thank you for your interest in contributing to oh-my-openagent ("Project"), owned by YeonGyu Kim ("Owner").
Thank you for your interest in contributing to oh-my-opencode ("Project"), owned by YeonGyu Kim ("Owner").
By signing this Contributor License Agreement ("Agreement"), you agree to the following terms:

View File

@@ -1,6 +1,6 @@
# Contributing to Oh My OpenCode
First off, thanks for taking the time to contribute! This document provides guidelines and instructions for contributing to oh-my-openagent.
First off, thanks for taking the time to contribute! This document provides guidelines and instructions for contributing to oh-my-opencode.
## Table of Contents
@@ -87,19 +87,19 @@ After making changes, you can test your local build in OpenCode:
```json
{
"plugin": ["file:///absolute/path/to/oh-my-openagent/dist/index.js"]
"plugin": ["file:///absolute/path/to/oh-my-opencode/dist/index.js"]
}
```
For example, if your project is at `/Users/yourname/projects/oh-my-openagent`:
For example, if your project is at `/Users/yourname/projects/oh-my-opencode`:
```json
{
"plugin": ["file:///Users/yourname/projects/oh-my-openagent/dist/index.js"]
"plugin": ["file:///Users/yourname/projects/oh-my-opencode/dist/index.js"]
}
```
> **Note**: Remove `"oh-my-openagent"` from the plugin array if it exists, to avoid conflicts with the npm version.
> **Note**: Remove `"oh-my-opencode"` from the plugin array if it exists, to avoid conflicts with the npm version.
3. **Restart OpenCode** to load the changes.
@@ -108,9 +108,9 @@ After making changes, you can test your local build in OpenCode:
## Project Structure
```
oh-my-openagent/
oh-my-opencode/
├── src/
│ ├── index.ts # Plugin entry (OhMyOpenAgentPlugin)
│ ├── index.ts # Plugin entry (OhMyOpenCodePlugin)
│ ├── plugin-config.ts # JSONC multi-level config (Zod v4)
│ ├── agents/ # 11 agents (Sisyphus, Hephaestus, Oracle, Librarian, Explore, Atlas, Prometheus, Metis, Momus, Multimodal-Looker, Sisyphus-Junior)
│ ├── hooks/ # Lifecycle hooks for orchestration, recovery, UX, and context management

View File

@@ -2,7 +2,7 @@
Portions of this software are licensed as follows:
- All third party components incorporated into the oh-my-openagent Software are licensed under the original license
- All third party components incorporated into the oh-my-opencode Software are licensed under the original license
provided by the owner of the applicable component.
- Content outside of the above mentioned files or restrictions is available under the "Sustainable Use
License" as defined below.

View File

@@ -4,6 +4,17 @@
> コアメンテナーのQが負傷したため、今週は Issue/PR への返信とリリースが遅れる可能性があります。
> ご理解とご支援に感謝します。
> [!TIP]
> **Building in Public**
>
> メンテナーが Jobdori を使い、oh-my-opencode をリアルタイムで開発・メンテナンスしています。Jobdori は OpenClaw をベースに大幅カスタマイズされた AI アシスタントです。
> すべての機能開発、修正、Issue トリアージを Discord でライブでご覧いただけます。
>
> [![Building in Public](./.github/assets/building-in-public.png)](https://discord.gg/PUwSMR9XNk)
>
> [**→ #building-in-public で確認する**](https://discord.gg/PUwSMR9XNk)
> [!NOTE]
>
> [![Sisyphus Labs - Sisyphus is the agent that codes like your team.](./.github/assets/sisyphuslabs.png?v=2)](https://sisyphuslabs.ai)
@@ -12,18 +23,18 @@
> [!TIP]
> 私たちと一緒に!
>
> | [<img alt="Discord link" src="https://img.shields.io/discord/1452487457085063218?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=flat-square" width="156px" />](https://discord.gg/PUwSMR9XNk) | [Discordコミュニティ](https://discord.gg/PUwSMR9XNk)に参加して、コントリビューターや他の `oh-my-openagent` ユーザーと交流しましょう。 |
> | [<img alt="Discord link" src="https://img.shields.io/discord/1452487457085063218?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=flat-square" width="156px" />](https://discord.gg/PUwSMR9XNk) | [Discordコミュニティ](https://discord.gg/PUwSMR9XNk)に参加して、コントリビューターや他の `oh-my-opencode` ユーザーと交流しましょう。 |
> | :-----| :----- |
> | [<img alt="X link" src="https://img.shields.io/badge/Follow-%40justsisyphus-00CED1?style=flat-square&logo=x&labelColor=black" width="156px" />](https://x.com/justsisyphus) | `oh-my-openagent` のニュースやアップデートは私のXアカウントで投稿されていましたが、 <br /> 誤って凍結されてしまったため、現在は [@justsisyphus](https://x.com/justsisyphus) が代わりにアップデートを投稿しています。 |
> | [<img alt="X link" src="https://img.shields.io/badge/Follow-%40justsisyphus-00CED1?style=flat-square&logo=x&labelColor=black" width="156px" />](https://x.com/justsisyphus) | `oh-my-opencode` のニュースやアップデートは私のXアカウントで投稿されていましたが、 <br /> 誤って凍結されてしまったため、現在は [@justsisyphus](https://x.com/justsisyphus) が代わりにアップデートを投稿しています。 |
> | [<img alt="GitHub Follow" src="https://img.shields.io/github/followers/code-yeongyu?style=flat-square&logo=github&labelColor=black&color=24292f" width="156px" />](https://github.com/code-yeongyu) | さらに多くのプロジェクトを見たい場合は、GitHubで [@code-yeongyu](https://github.com/code-yeongyu) をフォローしてください。 |
<!-- <CENTERED SECTION FOR GITHUB DISPLAY> -->
<div align="center">
[![Oh My OpenCode](./.github/assets/hero.jpg)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-openagent)
[![Oh My OpenCode](./.github/assets/hero.jpg)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-opencode)
[![Preview](./.github/assets/omo.png)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-openagent)
[![Preview](./.github/assets/omo.png)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-opencode)
</div>
@@ -34,7 +45,7 @@
<div align="center">
[![GitHub Release](https://img.shields.io/github/v/release/code-yeongyu/oh-my-openagent?color=369eff&labelColor=black&logo=github&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/releases)
https://www.npmjs.com/package/oh-my-openagent
[![npm downloads](https://img.shields.io/npm/dt/oh-my-opencode?color=ff6b35&labelColor=black&style=flat-square)](https://www.npmjs.com/package/oh-my-opencode)
[![GitHub Contributors](https://img.shields.io/github/contributors/code-yeongyu/oh-my-openagent?color=c4f042&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/graphs/contributors)
[![GitHub Forks](https://img.shields.io/github/forks/code-yeongyu/oh-my-openagent?color=8ae8ff&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/network/members)
[![GitHub Stars](https://img.shields.io/github/stars/code-yeongyu/oh-my-openagent?color=ffcb47&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/stargazers)
@@ -58,7 +69,7 @@ https://www.npmjs.com/package/oh-my-openagent
> 「Ohmyopencodeとralph loopを使って、45k行のtauriアプリを一晩でSaaSウェブアプリに変換しました。インタビューモードから始めて、私のプロンプトに対して質問や推奨事項を尋ねました。勝手に作業していくのを見るのは楽しかったし、今朝起きたらウェブサイトがほぼ動いているのを見て驚愕しました」 - [James Hargis](https://x.com/hargabyte/status/2007299688261882202)
> 「oh-my-openagentを使ってください。もう二度と元には戻れません。」 <br/>- [d0t3ch](https://x.com/d0t3ch/status/2001685618200580503)
> 「oh-my-opencodeを使ってください。もう二度と元には戻れません。」 <br/>- [d0t3ch](https://x.com/d0t3ch/status/2001685618200580503)
> 「何がどうすごいのかまだ上手く言語化できないんですが、開発体験が完全に異次元に到達してしまいました。」 - [苔硯:こけすずり](https://x.com/kokesuzuri/status/2008532913961529372?s=20)
@@ -90,7 +101,7 @@ OmOをインストールして、`ultrawork`とタイプしてください。狂
以下のプロンプトをコピーして、あなたのLLMエージェントClaude Code、AmpCode、Cursorなどに貼り付けてください
```
Install and configure oh-my-openagent by following the instructions here:
Install and configure oh-my-opencode by following the instructions here:
https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/docs/guide/installation.md
```
@@ -260,19 +271,19 @@ project/
> **背景のストーリーを知りたいですか?** なぜSisyphusは岩を転がすのか、なぜHephaestusは「正当なる職人」なのか、そして[オーケストレーションガイド](docs/guide/orchestration.md)をお読みください。
>
> oh-my-openagentは初めてですか?どのモデルを使うべきかについては、**[インストールガイド](docs/guide/installation.md#step-5-understand-your-model-setup)** で推奨モデルを確認してください。
> oh-my-opencodeは初めてですか?どのモデルを使うべきかについては、**[インストールガイド](docs/guide/installation.md#step-5-understand-your-model-setup)** で推奨モデルを確認してください。
## アンインストール (Uninstallation)
oh-my-openagentを削除するには:
oh-my-opencodeを削除するには:
1. **OpenCodeの設定からプラグインを削除する**
`~/.config/opencode/opencode.json`(または `opencode.jsonc`)を編集し、`plugin` 配列から `"oh-my-openagent"` を削除します:
`~/.config/opencode/opencode.json`(または `opencode.jsonc`)を編集し、`plugin` 配列から `"oh-my-opencode"` を削除します:
```bash
# jq を使用する場合
jq '.plugin = [.plugin[] | select(. != "oh-my-openagent")]' \
jq '.plugin = [.plugin[] | select(. != "oh-my-opencode")]' \
~/.config/opencode/opencode.json > /tmp/oc.json && \
mv /tmp/oc.json ~/.config/opencode/opencode.json
```
@@ -281,10 +292,10 @@ oh-my-openagentを削除するには
```bash
# ユーザー設定を削除
rm -f ~/.config/opencode/oh-my-openagent.json ~/.config/opencode/oh-my-openagent.jsonc
rm -f ~/.config/opencode/oh-my-opencode.json ~/.config/opencode/oh-my-opencode.jsonc
# プロジェクト設定を削除(存在する場合)
rm -f .opencode/oh-my-openagent.json .opencode/oh-my-openagent.jsonc
rm -f .opencode/oh-my-opencode.json .opencode/oh-my-opencode.jsonc
```
3. **削除の確認**

View File

@@ -4,21 +4,32 @@
> 핵심 메인테이너 Q가 부상을 입어, 이번 주에는 이슈/PR 응답 및 릴리스가 지연될 수 있습니다.
> 양해와 응원에 감사드립니다.
> [!TIP]
> **Building in Public**
>
> 메인테이너가 Jobdori를 통해 oh-my-opencode를 실시간으로 개발하고 있습니다. Jobdori는 OpenClaw를 기반으로 대폭 커스터마이징된 AI 어시스턴트입니다.
> 모든 기능 개발, 버그 수정, 이슈 트리아지를 Discord에서 실시간으로 확인하세요.
>
> [![Building in Public](./.github/assets/building-in-public.png)](https://discord.gg/PUwSMR9XNk)
>
> [**→ #building-in-public에서 확인하기**](https://discord.gg/PUwSMR9XNk)
> [!TIP]
> 저희와 함께 하세요!
>
> | [<img alt="Discord link" src="https://img.shields.io/discord/1452487457085063218?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=flat-square" width="156px" />](https://discord.gg/PUwSMR9XNk) | [Discord 커뮤니티](https://discord.gg/PUwSMR9XNk)에 가입하여 기여자 및 다른 `oh-my-openagent` 사용자들과 소통하세요. |
> | [<img alt="Discord link" src="https://img.shields.io/discord/1452487457085063218?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=flat-square" width="156px" />](https://discord.gg/PUwSMR9XNk) | [Discord 커뮤니티](https://discord.gg/PUwSMR9XNk)에 가입하여 기여자 및 다른 `oh-my-opencode` 사용자들과 소통하세요. |
> | :-----| :----- |
> | [<img alt="X link" src="https://img.shields.io/badge/Follow-%40justsisyphus-00CED1?style=flat-square&logo=x&labelColor=black" width="156px" />](https://x.com/justsisyphus) | `oh-my-openagent`에 대한 소식과 업데이트는 제 X 계정에 올라왔었지만, <br /> 실수로 정지된 이후에는 [@justsisyphus](https://x.com/justsisyphus)가 대신 업데이트를 게시하고 있습니다. |
> | [<img alt="X link" src="https://img.shields.io/badge/Follow-%40justsisyphus-00CED1?style=flat-square&logo=x&labelColor=black" width="156px" />](https://x.com/justsisyphus) | `oh-my-opencode`에 대한 소식과 업데이트는 제 X 계정에 올라왔었지만, <br /> 실수로 정지된 이후에는 [@justsisyphus](https://x.com/justsisyphus)가 대신 업데이트를 게시하고 있습니다. |
> | [<img alt="GitHub Follow" src="https://img.shields.io/github/followers/code-yeongyu?style=flat-square&logo=github&labelColor=black&color=24292f" width="156px" />](https://github.com/code-yeongyu) | 더 많은 프로젝트를 보려면 GitHub에서 [@code-yeongyu](https://github.com/code-yeongyu)를 팔로우하세요. |
<!-- <CENTERED SECTION FOR GITHUB DISPLAY> -->
<div align="center">
[![Oh My OpenCode](./.github/assets/hero.jpg)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-openagent)
[![Oh My OpenCode](./.github/assets/hero.jpg)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-opencode)
[![Preview](./.github/assets/omo.png)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-openagent)
[![Preview](./.github/assets/omo.png)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-opencode)
</div>
@@ -29,7 +40,7 @@
<div align="center">
[![GitHub Release](https://img.shields.io/github/v/release/code-yeongyu/oh-my-openagent?color=369eff&labelColor=black&logo=github&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/releases)
[![npm downloads](https://img.shields.io/endpoint?url=https%3A%2F%2Fohmyopenagent.com%2Fapi%2Fnpm-downloads&style=flat-square)](https://www.npmjs.com/package/oh-my-openagent)
[![npm downloads](https://img.shields.io/npm/dt/oh-my-opencode?color=ff6b35&labelColor=black&style=flat-square)](https://www.npmjs.com/package/oh-my-opencode)
[![GitHub Contributors](https://img.shields.io/github/contributors/code-yeongyu/oh-my-openagent?color=c4f042&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/graphs/contributors)
[![GitHub Forks](https://img.shields.io/github/forks/code-yeongyu/oh-my-openagent?color=8ae8ff&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/network/members)
[![GitHub Stars](https://img.shields.io/github/stars/code-yeongyu/oh-my-openagent?color=ffcb47&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/stargazers)
@@ -53,7 +64,7 @@
> "Ohmyopencode와 ralph loop를 써서 45k 라인짜리 tauri 앱을 하룻밤 만에 SaaS 웹앱으로 변환했어요. 인터뷰 모드로 시작해서, 제가 쓴 프롬프트에 대해 질문하고 추천을 부탁했죠. 일하는 걸 지켜보는 것도 재밌었고, 아침에 일어났더니 웹사이트가 대부분 돌아가고 있는 걸 보고 경악했습니다!" - [James Hargis](https://x.com/hargabyte/status/2007299688261882202)
> "oh-my-openagent 쓰세요, 다시는 예전으로 못 돌아갑니다." <br/>- [d0t3ch](https://x.com/d0t3ch/status/2001685618200580503)
> "oh-my-opencode 쓰세요, 다시는 예전으로 못 돌아갑니다." <br/>- [d0t3ch](https://x.com/d0t3ch/status/2001685618200580503)
> "뭐가 이렇게 대단한 건지 아직 정확하게 말로 표현하긴 어려운데, 개발 경험 자체가 완전히 다른 차원에 도달해버렸어요." - [苔硯:こけすずり](https://x.com/kokesuzuri/status/2008532913961529372?s=20)
@@ -84,7 +95,7 @@ OmO 설치하고. `ultrawork` 치세요. 끝.
다음 프롬프트를 복사해서 여러분의 LLM 에이전트(Claude Code, AmpCode, Cursor 등)에 붙여넣으세요:
```
Install and configure oh-my-openagent by following the instructions here:
Install and configure oh-my-opencode by following the instructions here:
https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/docs/guide/installation.md
```
@@ -254,19 +265,19 @@ project/
> **비하인드 스토리가 궁금하신가요?** 왜 Sisyphus가 돌을 굴리는지, 왜 Hephaestus가 "진정한 장인"인지, 그리고 [오케스트레이션 가이드](docs/guide/orchestration.md)를 읽어보세요.
>
> oh-my-openagent가 처음이신가요? 어떤 모델을 써야 할지 **[설치 가이드](docs/guide/installation.md#step-5-understand-your-model-setup)** 에서 추천 조합을 확인하세요.
> oh-my-opencode가 처음이신가요? 어떤 모델을 써야 할지 **[설치 가이드](docs/guide/installation.md#step-5-understand-your-model-setup)** 에서 추천 조합을 확인하세요.
## 제거 (Uninstallation)
oh-my-openagent를 지우려면:
oh-my-opencode를 지우려면:
1. **OpenCode 설정에서 플러그인 제거**
`~/.config/opencode/opencode.json` (또는 `opencode.jsonc`)를 열고 `plugin` 배열에서 `"oh-my-openagent"`를 지우세요.
`~/.config/opencode/opencode.json` (또는 `opencode.jsonc`)를 열고 `plugin` 배열에서 `"oh-my-opencode"`를 지우세요.
```bash
# jq 사용 시
jq '.plugin = [.plugin[] | select(. != "oh-my-openagent")]' \
jq '.plugin = [.plugin[] | select(. != "oh-my-opencode")]' \
~/.config/opencode/opencode.json > /tmp/oc.json && \
mv /tmp/oc.json ~/.config/opencode/opencode.json
```
@@ -275,10 +286,10 @@ oh-my-openagent를 지우려면:
```bash
# 사용자 설정 제거
rm -f ~/.config/opencode/oh-my-openagent.json ~/.config/opencode/oh-my-openagent.jsonc
rm -f ~/.config/opencode/oh-my-opencode.json ~/.config/opencode/oh-my-opencode.jsonc
# 프로젝트 설정 제거 (있는 경우)
rm -f .opencode/oh-my-openagent.json .opencode/oh-my-openagent.jsonc
rm -f .opencode/oh-my-opencode.json .opencode/oh-my-opencode.jsonc
```
3. **제거 확인**

View File

@@ -1,3 +1,13 @@
> [!TIP]
> **Building in Public**
>
> The maintainer builds and maintains oh-my-opencode in real-time with Jobdori, an AI assistant built on a heavily customized fork of OpenClaw.
> Every feature, every fix, every issue triage — live in our Discord.
>
> [![Building in Public](./.github/assets/building-in-public.png)](https://discord.gg/PUwSMR9XNk)
>
> [**→ Watch it happen in #building-in-public**](https://discord.gg/PUwSMR9XNk)
> [!NOTE]
>
> [![Sisyphus Labs - Sisyphus is the agent that codes like your team.](./.github/assets/sisyphuslabs.png?v=2)](https://sisyphuslabs.ai)
@@ -6,9 +16,9 @@
> [!TIP]
> Be with us!
>
> | [<img alt="Discord link" src="https://img.shields.io/discord/1452487457085063218?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=flat-square" width="156px" />](https://discord.gg/PUwSMR9XNk) | Join our [Discord community](https://discord.gg/PUwSMR9XNk) to connect with contributors and fellow `oh-my-openagent` users. |
> | [<img alt="Discord link" src="https://img.shields.io/discord/1452487457085063218?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=flat-square" width="156px" />](https://discord.gg/PUwSMR9XNk) | Join our [Discord community](https://discord.gg/PUwSMR9XNk) to connect with contributors and fellow `oh-my-opencode` users. |
> | :-----| :----- |
> | [<img alt="X link" src="https://img.shields.io/badge/Follow-%40justsisyphus-00CED1?style=flat-square&logo=x&labelColor=black" width="156px" />](https://x.com/justsisyphus) | News and updates for `oh-my-openagent` used to be posted on my X account. <br /> Since it was suspended mistakenly, [@justsisyphus](https://x.com/justsisyphus) now posts updates on my behalf. |
> | [<img alt="X link" src="https://img.shields.io/badge/Follow-%40justsisyphus-00CED1?style=flat-square&logo=x&labelColor=black" width="156px" />](https://x.com/justsisyphus) | News and updates for `oh-my-opencode` used to be posted on my X account. <br /> Since it was suspended mistakenly, [@justsisyphus](https://x.com/justsisyphus) now posts updates on my behalf. |
> | [<img alt="GitHub Follow" src="https://img.shields.io/github/followers/code-yeongyu?style=flat-square&logo=github&labelColor=black&color=24292f" width="156px" />](https://github.com/code-yeongyu) | Follow [@code-yeongyu](https://github.com/code-yeongyu) on GitHub for more projects. |
<!-- <CENTERED SECTION FOR GITHUB DISPLAY> -->
@@ -55,7 +65,7 @@
> "I converted a 45k line tauri app into a SaaS web app overnight using Ohmyopencode and ralph loop. Started with interview me prompt, asked it for ratings and recommendations on the questions. It was amazing to watch it work and to wake up this morning to a mostly working website!" - [James Hargis](https://x.com/hargabyte/status/2007299688261882202)
> "use oh-my-openagent, you will never go back" <br/>- [d0t3ch](https://x.com/d0t3ch/status/2001685618200580503)
> "use oh-my-opencode, you will never go back" <br/>- [d0t3ch](https://x.com/d0t3ch/status/2001685618200580503)
> "I haven't really been able to articulate exactly what makes it so great yet, but the development experience has reached a completely different dimension." - [
苔硯:こけすずり](https://x.com/kokesuzuri/status/2008532913961529372?s=20)
@@ -87,7 +97,7 @@ Install OmO. Type `ultrawork`. Done.
Copy and paste this prompt to your LLM agent (Claude Code, AmpCode, Cursor, etc.):
```
Install and configure oh-my-openagent by following the instructions here:
Install and configure oh-my-opencode by following the instructions here:
https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/docs/guide/installation.md
```
@@ -255,19 +265,19 @@ Add your own: `.opencode/skills/*/SKILL.md` or `~/.config/opencode/skills/*/SKIL
---
> **New to oh-my-openagent?** Read the **[Overview](docs/guide/overview.md)** to understand what you have, or check the **[Orchestration Guide](docs/guide/orchestration.md)** for how agents collaborate.
> **New to oh-my-opencode?** Read the **[Overview](docs/guide/overview.md)** to understand what you have, or check the **[Orchestration Guide](docs/guide/orchestration.md)** for how agents collaborate.
## Uninstallation
To remove oh-my-openagent:
To remove oh-my-opencode:
1. **Remove the plugin from your OpenCode config**
Edit `~/.config/opencode/opencode.json` (or `opencode.jsonc`) and remove `"oh-my-openagent"` from the `plugin` array:
Edit `~/.config/opencode/opencode.json` (or `opencode.jsonc`) and remove `"oh-my-opencode"` from the `plugin` array:
```bash
# Using jq
jq '.plugin = [.plugin[] | select(. != "oh-my-openagent")]' \
jq '.plugin = [.plugin[] | select(. != "oh-my-opencode")]' \
~/.config/opencode/opencode.json > /tmp/oc.json && \
mv /tmp/oc.json ~/.config/opencode/opencode.json
```
@@ -276,10 +286,10 @@ To remove oh-my-openagent:
```bash
# Remove user config
rm -f ~/.config/opencode/oh-my-openagent.json ~/.config/opencode/oh-my-openagent.jsonc
rm -f ~/.config/opencode/oh-my-opencode.json ~/.config/opencode/oh-my-opencode.jsonc
# Remove project config (if exists)
rm -f .opencode/oh-my-openagent.json .opencode/oh-my-openagent.jsonc
rm -f .opencode/oh-my-opencode.json .opencode/oh-my-opencode.jsonc
```
3. **Verify removal**
@@ -304,7 +314,7 @@ See full [Features Documentation](docs/reference/features.md).
- **Claude Code Compatibility**: Full hook system, commands, skills, agents, MCPs
- **Built-in MCPs**: websearch (Exa), context7 (docs), grep_app (GitHub search)
- **Session Tools**: List, read, search, and analyze session history
- **Productivity Features**: Ralph Loop, Todo Enforcer, GPT permission-tail continuation, Comment Checker, Think Mode, and more
- **Productivity Features**: Ralph Loop, Todo Enforcer, Comment Checker, Think Mode, and more
- **Model Setup**: Agent-model matching is built into the [Installation Guide](docs/guide/installation.md#step-5-understand-your-model-setup)
## Configuration
@@ -314,14 +324,14 @@ Opinionated defaults, adjustable if you insist.
See [Configuration Documentation](docs/reference/configuration.md).
**Quick Overview:**
- **Config Locations**: `.opencode/oh-my-openagent.jsonc` or `.opencode/oh-my-openagent.json` (project), `~/.config/opencode/oh-my-openagent.jsonc` or `~/.config/opencode/oh-my-openagent.json` (user)
- **Config Locations**: `.opencode/oh-my-opencode.jsonc` or `.opencode/oh-my-opencode.json` (project), `~/.config/opencode/oh-my-opencode.jsonc` or `~/.config/opencode/oh-my-opencode.json` (user)
- **JSONC Support**: Comments and trailing commas supported
- **Agents**: Override models, temperatures, prompts, and permissions for any agent
- **Built-in Skills**: `playwright` (browser automation), `git-master` (atomic commits)
- **Sisyphus Agent**: Main orchestrator with Prometheus (Planner) and Metis (Plan Consultant)
- **Background Tasks**: Configure concurrency limits per provider/model
- **Categories**: Domain-specific task delegation (`visual`, `business-logic`, custom)
- **Hooks**: 25+ built-in hooks, including `gpt-permission-continuation`, all configurable via `disabled_hooks`
- **Hooks**: 25+ built-in hooks, all configurable via `disabled_hooks`
- **MCPs**: Built-in websearch (Exa), context7 (docs), grep_app (GitHub search)
- **LSP**: Full LSP support with refactoring tools
- **Experimental**: Aggressive truncation, auto-resume, and more

View File

@@ -4,6 +4,17 @@
> Ключевой мейнтейнер Q получил травму, поэтому на этой неделе ответы по issue/PR и релизы могут задерживаться.
> Спасибо за терпение и поддержку.
> [!TIP]
> **Building in Public**
>
> Мейнтейнер разрабатывает и поддерживает oh-my-opencode в режиме реального времени с помощью Jobdori — ИИ-ассистента на базе глубоко кастомизированной версии OpenClaw.
> Каждая фича, каждый фикс, каждый триаж issue — в прямом эфире в нашем Discord.
>
> [![Building in Public](./.github/assets/building-in-public.png)](https://discord.gg/PUwSMR9XNk)
>
> [**→ Смотрите в #building-in-public**](https://discord.gg/PUwSMR9XNk)
> [!NOTE]
>
> [![Sisyphus Labs - Sisyphus is the agent that codes like your team.](./.github/assets/sisyphuslabs.png?v=2)](https://sisyphuslabs.ai)
@@ -12,16 +23,16 @@
> [!TIP] Будьте с нами!
>
> | [](https://discord.gg/PUwSMR9XNk) | Вступайте в наш [Discord](https://discord.gg/PUwSMR9XNk), чтобы общаться с контрибьюторами и пользователями `oh-my-openagent`. |
> | [](https://discord.gg/PUwSMR9XNk) | Вступайте в наш [Discord](https://discord.gg/PUwSMR9XNk), чтобы общаться с контрибьюторами и пользователями `oh-my-opencode`. |
> | ----------------------------------- | ------------------------------------------------------------ |
> | [](https://x.com/justsisyphus) | Новости и обновления `oh-my-openagent` раньше публиковались на моём аккаунте X. <br /> После ошибочной блокировки, [@justsisyphus](https://x.com/justsisyphus) публикует обновления вместо меня. |
> | [](https://x.com/justsisyphus) | Новости и обновления `oh-my-opencode` раньше публиковались на моём аккаунте X. <br /> После ошибочной блокировки, [@justsisyphus](https://x.com/justsisyphus) публикует обновления вместо меня. |
> | [](https://github.com/code-yeongyu) | Подпишитесь на [@code-yeongyu](https://github.com/code-yeongyu) на GitHub, чтобы следить за другими проектами. |
<!-- <CENTERED SECTION FOR GITHUB DISPLAY> --> <div align="center">
[![Oh My OpenCode](./.github/assets/hero.jpg)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-openagent)
[![Oh My OpenCode](./.github/assets/hero.jpg)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-opencode)
[![Preview](./.github/assets/omo.png)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-openagent)
[![Preview](./.github/assets/omo.png)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-opencode)
</div>
@@ -31,7 +42,7 @@
<div align="center">
https://www.npmjs.com/package/oh-my-openagent
[![GitHub Release](https://img.shields.io/github/v/release/code-yeongyu/oh-my-openagent?color=369eff&labelColor=black&logo=github&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/releases) [![npm downloads](https://img.shields.io/npm/dt/oh-my-opencode?color=ff6b35&labelColor=black&style=flat-square)](https://www.npmjs.com/package/oh-my-opencode) [![GitHub Contributors](https://img.shields.io/github/contributors/code-yeongyu/oh-my-openagent?color=c4f042&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/graphs/contributors) [![GitHub Forks](https://img.shields.io/github/forks/code-yeongyu/oh-my-openagent?color=8ae8ff&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/network/members) [![GitHub Stars](https://img.shields.io/github/stars/code-yeongyu/oh-my-openagent?color=ffcb47&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/stargazers) [![GitHub Issues](https://img.shields.io/github/issues/code-yeongyu/oh-my-openagent?color=ff80eb&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/issues) [![License](https://img.shields.io/badge/license-SUL--1.0-white?labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/blob/master/LICENSE.md) [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/code-yeongyu/oh-my-openagent)
English | 한국어 | 日本語 | 简体中文 | Русский
@@ -47,7 +58,7 @@ English | 한국어 | 日本語 | 简体中文 | Русский
> «За ночь конвертировал приложение на tauri в 45k строк в веб-SaaS с помощью Ohmyopencode и ralph loop. Начал с промпта «проинтервьюируй меня», попросил оценки и рекомендации по вопросам. Было удивительно наблюдать за работой и утром проснуться с почти рабочим сайтом!» — [James Hargis](https://x.com/hargabyte/status/2007299688261882202)
> «Используйте oh-my-openagent — вы не захотите возвращаться назад.» <br/>— [d0t3ch](https://x.com/d0t3ch/status/2001685618200580503)
> «Используйте oh-my-opencode — вы не захотите возвращаться назад.» <br/>— [d0t3ch](https://x.com/d0t3ch/status/2001685618200580503)
> «Пока не могу точно объяснить, почему это так круто, но опыт разработки вышел на совершенно другой уровень.» — [苔硯:こけすずり](https://x.com/kokesuzuri/status/2008532913961529372?s=20)
@@ -76,7 +87,7 @@ English | 한국어 | 日本語 | 简体中文 | Русский
Скопируйте и вставьте этот промпт в ваш LLM-агент (Claude Code, AmpCode, Cursor и т.д.):
```
Install and configure oh-my-openagent by following the instructions here:
Install and configure oh-my-opencode by following the instructions here:
https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/docs/guide/installation.md
```
@@ -242,19 +253,19 @@ project/
------
> **Впервые в oh-my-openagent?** Прочитайте **Обзор**, чтобы понять, что у вас есть, или ознакомьтесь с **руководством по оркестрации**, чтобы узнать, как агенты взаимодействуют.
> **Впервые в oh-my-opencode?** Прочитайте **Обзор**, чтобы понять, что у вас есть, или ознакомьтесь с **руководством по оркестрации**, чтобы узнать, как агенты взаимодействуют.
## Удаление
Чтобы удалить oh-my-openagent:
Чтобы удалить oh-my-opencode:
1. **Удалите плагин из конфига OpenCode**
Отредактируйте `~/.config/opencode/opencode.json` (или `opencode.jsonc`) и уберите `"oh-my-openagent"` из массива `plugin`:
Отредактируйте `~/.config/opencode/opencode.json` (или `opencode.jsonc`) и уберите `"oh-my-opencode"` из массива `plugin`:
```bash
# С помощью jq
jq '.plugin = [.plugin[] | select(. != "oh-my-openagent")]' \
jq '.plugin = [.plugin[] | select(. != "oh-my-opencode")]' \
~/.config/opencode/opencode.json > /tmp/oc.json && \
mv /tmp/oc.json ~/.config/opencode/opencode.json
```
@@ -263,10 +274,10 @@ project/
```bash
# Удалить пользовательский конфиг
rm -f ~/.config/opencode/oh-my-openagent.json ~/.config/opencode/oh-my-openagent.jsonc
rm -f ~/.config/opencode/oh-my-opencode.json ~/.config/opencode/oh-my-opencode.jsonc
# Удалить конфиг проекта (если существует)
rm -f .opencode/oh-my-openagent.json .opencode/oh-my-openagent.jsonc
rm -f .opencode/oh-my-opencode.json .opencode/oh-my-opencode.jsonc
```
3. **Проверьте удаление**
@@ -303,7 +314,7 @@ project/
**Краткий обзор:**
- **Расположение конфигов**: `.opencode/oh-my-openagent.jsonc` или `.opencode/oh-my-openagent.json` (проект), `~/.config/opencode/oh-my-openagent.jsonc` или `~/.config/opencode/oh-my-openagent.json` (пользователь)
- **Расположение конфигов**: `.opencode/oh-my-opencode.jsonc` или `.opencode/oh-my-opencode.json` (проект), `~/.config/opencode/oh-my-opencode.jsonc` или `~/.config/opencode/oh-my-opencode.json` (пользователь)
- **Поддержка JSONC**: Комментарии и конечные запятые поддерживаются
- **Агенты**: Переопределение моделей, температур, промптов и разрешений для любого агента
- **Встроенные навыки**: `playwright` (автоматизация браузера), `git-master` (атомарные коммиты)

View File

@@ -4,6 +4,17 @@
> 核心维护者 Q 因受伤,本周 issue/PR 回复和发布可能会延迟。
> 感谢你的耐心与支持。
> [!TIP]
> **Building in Public**
>
> 维护者正在使用 Jobdori 实时开发和维护 oh-my-opencode。Jobdori 是基于 OpenClaw 深度定制的 AI 助手。
> 每个功能开发、每次修复、每次 Issue 分类,都在 Discord 上实时进行。
>
> [![Building in Public](./.github/assets/building-in-public.png)](https://discord.gg/PUwSMR9XNk)
>
> [**→ 在 #building-in-public 频道中查看**](https://discord.gg/PUwSMR9XNk)
> [!NOTE]
>
> [![Sisyphus Labs - Sisyphus is the agent that codes like your team.](./.github/assets/sisyphuslabs.png?v=2)](https://sisyphuslabs.ai)
@@ -12,18 +23,18 @@
> [!TIP]
> 加入我们!
>
> | [<img alt="Discord link" src="https://img.shields.io/discord/1452487457085063218?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=flat-square" width="156px" />](https://discord.gg/PUwSMR9XNk) | 加入我们的 [Discord 社区](https://discord.gg/PUwSMR9XNk),与贡献者及其他 `oh-my-openagent` 用户交流。 |
> | [<img alt="Discord link" src="https://img.shields.io/discord/1452487457085063218?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=flat-square" width="156px" />](https://discord.gg/PUwSMR9XNk) | 加入我们的 [Discord 社区](https://discord.gg/PUwSMR9XNk),与贡献者及其他 `oh-my-opencode` 用户交流。 |
> | :-----| :----- |
> | [<img alt="X link" src="https://img.shields.io/badge/Follow-%40justsisyphus-00CED1?style=flat-square&logo=x&labelColor=black" width="156px" />](https://x.com/justsisyphus) | 关于 `oh-my-openagent` 的新闻和更新过去发布在我的 X 账号上。<br /> 因为账号被意外停用,现在由 [@justsisyphus](https://x.com/justsisyphus) 代为发布更新。 |
> | [<img alt="X link" src="https://img.shields.io/badge/Follow-%40justsisyphus-00CED1?style=flat-square&logo=x&labelColor=black" width="156px" />](https://x.com/justsisyphus) | 关于 `oh-my-opencode` 的新闻和更新过去发布在我的 X 账号上。<br /> 因为账号被意外停用,现在由 [@justsisyphus](https://x.com/justsisyphus) 代为发布更新。 |
> | [<img alt="GitHub Follow" src="https://img.shields.io/github/followers/code-yeongyu?style=flat-square&logo=github&labelColor=black&color=24292f" width="156px" />](https://github.com/code-yeongyu) | 在 GitHub 上关注 [@code-yeongyu](https://github.com/code-yeongyu) 获取更多项目信息。 |
<!-- <CENTERED SECTION FOR GITHUB DISPLAY> -->
<div align="center">
[![Oh My OpenCode](./.github/assets/hero.jpg)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-openagent)
[![Oh My OpenCode](./.github/assets/hero.jpg)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-opencode)
[![Preview](./.github/assets/omo.png)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-openagent)
[![Preview](./.github/assets/omo.png)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-opencode)
</div>
@@ -34,7 +45,7 @@
<div align="center">
[![GitHub Release](https://img.shields.io/github/v/release/code-yeongyu/oh-my-openagent?color=369eff&labelColor=black&logo=github&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/releases)
[![npm downloads](https://img.shields.io/endpoint?url=https%3A%2F%2Fohmyopenagent.com%2Fapi%2Fnpm-downloads&style=flat-square)](https://www.npmjs.com/package/oh-my-openagent)
[![npm downloads](https://img.shields.io/npm/dt/oh-my-opencode?color=ff6b35&labelColor=black&style=flat-square)](https://www.npmjs.com/package/oh-my-opencode)
[![GitHub Contributors](https://img.shields.io/github/contributors/code-yeongyu/oh-my-openagent?color=c4f042&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/graphs/contributors)
[![GitHub Forks](https://img.shields.io/github/forks/code-yeongyu/oh-my-openagent?color=8ae8ff&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/network/members)
[![GitHub Stars](https://img.shields.io/github/stars/code-yeongyu/oh-my-openagent?color=ffcb47&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/stargazers)
@@ -58,7 +69,7 @@
> “我用 Ohmyopencode 和 ralph loop 花了一晚上的时间,把一个 45k 行代码的 tauri 应用转换成了 SaaS Web 应用。从面试模式开始,让它对我提供的提示词进行提问和提出建议。看着它工作很有趣,今早醒来看到网站基本已经跑起来了,太震撼了!” - [James Hargis](https://x.com/hargabyte/status/2007299688261882202)
> “用 oh-my-openagent 吧,你绝对回不去了。” <br/>- [d0t3ch](https://x.com/d0t3ch/status/2001685618200580503)
> “用 oh-my-opencode 吧,你绝对回不去了。” <br/>- [d0t3ch](https://x.com/d0t3ch/status/2001685618200580503)
> “我很难准确描述它到底哪里牛逼,但开发体验已经达到完全不同的维度了。” - [苔硯:こけすずり](https://x.com/kokesuzuri/status/2008532913961529372?s=20)
@@ -91,7 +102,7 @@
复制并粘贴以下提示词到你的 LLM Agent (Claude Code, AmpCode, Cursor 等):
```
Install and configure oh-my-openagent by following the instructions here:
Install and configure oh-my-opencode by following the instructions here:
https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/docs/guide/installation.md
```
@@ -259,19 +270,19 @@ Agent 会自动顺藤摸瓜加载对应的 Context免去了你所有的手动
---
> **第一次用 oh-my-openagent** 阅读 **[概述](docs/guide/overview.md)** 了解你拥有哪些功能,或查看 **[编排指南](docs/guide/orchestration.md)** 了解 Agent 如何协作。
> **第一次用 oh-my-opencode** 阅读 **[概述](docs/guide/overview.md)** 了解你拥有哪些功能,或查看 **[编排指南](docs/guide/orchestration.md)** 了解 Agent 如何协作。
## 如何卸载 (Uninstallation)
要移除 oh-my-openagent:
要移除 oh-my-opencode:
1. **从你的 OpenCode 配置文件中去掉插件**
编辑 `~/.config/opencode/opencode.json` (或 `opencode.jsonc`) ,并把 `"oh-my-openagent"``plugin` 数组中删掉:
编辑 `~/.config/opencode/opencode.json` (或 `opencode.jsonc`) ,并把 `"oh-my-opencode"``plugin` 数组中删掉:
```bash
# 如果你有 jq 的话
jq '.plugin = [.plugin[] | select(. != "oh-my-openagent")]' \
jq '.plugin = [.plugin[] | select(. != "oh-my-opencode")]' \
~/.config/opencode/opencode.json > /tmp/oc.json && \
mv /tmp/oc.json ~/.config/opencode/opencode.json
```
@@ -280,10 +291,10 @@ Agent 会自动顺藤摸瓜加载对应的 Context免去了你所有的手动
```bash
# 移除全局用户配置
rm -f ~/.config/opencode/oh-my-openagent.json ~/.config/opencode/oh-my-openagent.jsonc
rm -f ~/.config/opencode/oh-my-opencode.json ~/.config/opencode/oh-my-opencode.jsonc
# 移除当前项目的配置
rm -f .opencode/oh-my-openagent.json .opencode/oh-my-openagent.jsonc
rm -f .opencode/oh-my-opencode.json .opencode/oh-my-opencode.jsonc
```
3. **确认卸载成功**

File diff suppressed because it is too large Load Diff

View File

@@ -3716,15 +3716,10 @@
"minimum": 10,
"maximum": 9007199254740991
},
"windowSize": {
"consecutiveThreshold": {
"type": "integer",
"minimum": 5,
"maximum": 9007199254740991
},
"repetitionThresholdPercent": {
"type": "number",
"exclusiveMinimum": 0,
"maximum": 100
}
},
"additionalProperties": false
@@ -3741,6 +3736,147 @@
},
"additionalProperties": false
},
"openclaw": {
"type": "object",
"properties": {
"enabled": {
"default": false,
"type": "boolean"
},
"gateways": {
"default": {},
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "object",
"properties": {
"type": {
"default": "http",
"type": "string",
"enum": [
"http",
"command"
]
},
"url": {
"type": "string"
},
"method": {
"default": "POST",
"type": "string"
},
"headers": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "string"
}
},
"command": {
"type": "string"
},
"timeout": {
"type": "number"
}
},
"required": [
"type",
"method"
],
"additionalProperties": false
}
},
"hooks": {
"default": {},
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "object",
"properties": {
"enabled": {
"default": true,
"type": "boolean"
},
"gateway": {
"type": "string"
},
"instruction": {
"type": "string"
}
},
"required": [
"enabled",
"gateway",
"instruction"
],
"additionalProperties": false
}
},
"replyListener": {
"type": "object",
"properties": {
"discordBotToken": {
"type": "string"
},
"discordChannelId": {
"type": "string"
},
"discordMention": {
"type": "string"
},
"authorizedDiscordUserIds": {
"default": [],
"type": "array",
"items": {
"type": "string"
}
},
"telegramBotToken": {
"type": "string"
},
"telegramChatId": {
"type": "string"
},
"pollIntervalMs": {
"default": 3000,
"type": "number"
},
"rateLimitPerMinute": {
"default": 10,
"type": "number"
},
"maxMessageLength": {
"default": 500,
"type": "number"
},
"includePrefix": {
"default": true,
"type": "boolean"
}
},
"required": [
"authorizedDiscordUserIds",
"pollIntervalMs",
"rateLimitPerMinute",
"maxMessageLength",
"includePrefix"
],
"additionalProperties": false
}
},
"required": [
"enabled",
"gateways",
"hooks"
],
"additionalProperties": false
},
"babysitting": {
"type": "object",
"properties": {

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env node
// bin/oh-my-openagent.js
// bin/oh-my-opencode.js
// Wrapper script that detects platform and spawns the correct binary
import { spawnSync } from "node:child_process";
@@ -32,7 +32,7 @@ function supportsAvx2() {
return null;
}
if (process.env.OH_MY_OPENAGENT_FORCE_BASELINE === "1" || process.env.OH_MY_OPENCODE_FORCE_BASELINE === "1") {
if (process.env.OH_MY_OPENCODE_FORCE_BASELINE === "1") {
return false;
}
@@ -85,7 +85,7 @@ function main() {
preferBaseline: avx2Supported === false,
});
} catch (error) {
console.error(`\noh-my-openagent: ${error.message}\n`);
console.error(`\noh-my-opencode: ${error.message}\n`);
process.exit(1);
}
@@ -100,7 +100,7 @@ function main() {
.filter((entry) => entry !== null);
if (resolvedBinaries.length === 0) {
console.error(`\noh-my-openagent: Platform binary not installed.`);
console.error(`\noh-my-opencode: Platform binary not installed.`);
console.error(`\nYour platform: ${platform}-${arch}${libcFamily === "musl" ? "-musl" : ""}`);
console.error(`Expected packages (in order): ${packageCandidates.join(", ")}`);
console.error(`\nTo fix, run:`);
@@ -120,7 +120,7 @@ function main() {
continue;
}
console.error(`\noh-my-openagent: Failed to execute binary.`);
console.error(`\noh-my-opencode: Failed to execute binary.`);
console.error(`Error: ${result.error.message}\n`);
process.exit(2);
}

View File

@@ -8,7 +8,7 @@ Think of AI models as developers on a team. Each has a different brain, differen
This isn't a bug. It's the foundation of the entire system.
Oh My OpenCode assigns each agent a model that matches its _working style_ — like building a team where each person is in the role that fits their personality.
Oh My OpenAgent assigns each agent a model that matches its _working style_ — like building a team where each person is in the role that fits their personality.
### Sisyphus: The Sociable Lead
@@ -121,6 +121,7 @@ Principle-driven, explicit reasoning, deep technical capability. Best for agents
| ----------------- | ----------------------------------------------------------------------------------------------- |
| **GPT-5.3 Codex** | Deep coding powerhouse. Autonomous exploration. Required for Hephaestus. |
| **GPT-5.4** | High intelligence, strategic reasoning. Default for Oracle, Momus, and a key fallback for Prometheus / Atlas. Uses xhigh variant for Momus. |
| **GPT-5.4 Mini** | Fast + strong reasoning. Good for lightweight autonomous tasks. Default for quick category. |
| **GPT-5-Nano** | Ultra-cheap, fast. Good for simple utility tasks. |
### Other Models
@@ -170,7 +171,7 @@ When agents delegate work, they don't pick a model name — they pick a **catego
| `ultrabrain` | Maximum reasoning needed | GPT-5.4 → Gemini 3.1 Pro → Claude Opus → opencode-go/glm-5 |
| `deep` | Deep coding, complex logic | GPT-5.3 Codex → Claude Opus → Gemini 3.1 Pro |
| `artistry` | Creative, novel approaches | Gemini 3.1 Pro → Claude Opus → GPT-5.4 |
| `quick` | Simple, fast tasks | Claude Haiku → Gemini Flash → opencode-go/minimax-m2.5 → GPT-5-Nano |
| `quick` | Simple, fast tasks | GPT-5.4 Mini → Claude Haiku → Gemini Flash → opencode-go/minimax-m2.5 → GPT-5-Nano |
| `unspecified-high` | General complex work | Claude Opus → GPT-5.4 → GLM 5 → K2P5 → opencode-go/glm-5 → Kimi K2.5 |
| `unspecified-low` | General standard work | Claude Sonnet → GPT-5.3 Codex → opencode-go/kimi-k2.5 → Gemini Flash |
| `writing` | Text, docs, prose | Gemini Flash → opencode-go/kimi-k2.5 → Claude Sonnet |

View File

@@ -176,7 +176,7 @@ The `opencode-antigravity-auth` plugin uses different model names than the built
**Available models (Gemini CLI quota)**:
- `google/gemini-2.5-flash`, `google/gemini-2.5-pro`, `google/gemini-3-flash-preview`, `google/gemini-3-pro-preview`
- `google/gemini-2.5-flash`, `google/gemini-2.5-pro`, `google/gemini-3-flash-preview`, `google/gemini-3.1-pro-preview`
> **Note**: Legacy tier-suffixed names like `google/antigravity-gemini-3-pro-high` still work but variants are recommended. Use `--variant=high` with the base model name instead.
@@ -287,13 +287,14 @@ Not all models behave the same way. Understanding which models are "similar" hel
| ----------------- | -------------------------------- | ------------------------------------------------- |
| **GPT-5.3-codex** | openai, github-copilot, opencode | Deep coding powerhouse. Required for Hephaestus. |
| **GPT-5.4** | openai, github-copilot, opencode | High intelligence. Default for Oracle. |
| **GPT-5.4 Mini** | openai, github-copilot, opencode | Fast + strong reasoning. Default for quick category. |
| **GPT-5-Nano** | opencode | Ultra-cheap, fast. Good for simple utility tasks. |
**Different-Behavior Models**:
| Model | Provider(s) | Notes |
| --------------------- | -------------------------------- | ----------------------------------------------------------- |
| **Gemini 3 Pro** | google, github-copilot, opencode | Excels at visual/frontend tasks. Different reasoning style. |
| **Gemini 3.1 Pro** | google, github-copilot, opencode | Excels at visual/frontend tasks. Different reasoning style. |
| **Gemini 3 Flash** | google, github-copilot, opencode | Fast, good for doc search and light tasks. |
| **MiniMax M2.5** | venice | Fast and smart. Good for utility tasks. |
| **MiniMax M2.5 Free** | opencode | Free-tier MiniMax. Fast for search/retrieval. |
@@ -316,7 +317,7 @@ Based on your subscriptions, here's how the agents were configured:
| Agent | Role | Default Chain | What It Does |
| ------------ | ---------------- | ----------------------------------------------- | ---------------------------------------------------------------------------------------- |
| **Sisyphus** | Main ultraworker | Opus (max) → Kimi K2.5 → GLM 5 → Big Pickle | Primary coding agent. Orchestrates everything. **Never use GPT — no GPT prompt exists.** |
| **Metis** | Plan review | Opus (max) → Kimi K2.5 → GPT-5.4 → Gemini 3 Pro | Reviews Prometheus plans for gaps. |
| **Metis** | Plan review | Opus (max) → Kimi K2.5 → GPT-5.4 → Gemini 3.1 Pro | Reviews Prometheus plans for gaps. |
**Dual-Prompt Agents** (auto-switch between Claude and GPT prompts):
@@ -326,7 +327,7 @@ Priority: **Claude > GPT > Claude-like models**
| Agent | Role | Default Chain | GPT Prompt? |
| -------------- | ----------------- | ---------------------------------------------------------- | ---------------------------------------------------------------- |
| **Prometheus** | Strategic planner | Opus (max) → **GPT-5.4 (high)** → Kimi K2.5 → Gemini 3 Pro | Yes — XML-tagged, principle-driven (~300 lines vs ~1,100 Claude) |
| **Prometheus** | Strategic planner | Opus (max) → **GPT-5.4 (high)** → Kimi K2.5 → Gemini 3.1 Pro | Yes — XML-tagged, principle-driven (~300 lines vs ~1,100 Claude) |
| **Atlas** | Todo orchestrator | **Kimi K2.5** → Sonnet → GPT-5.4 | Yes — GPT-optimized todo management |
**GPT-Native Agents** (built for GPT, don't override to Claude):
@@ -334,8 +335,8 @@ Priority: **Claude > GPT > Claude-like models**
| Agent | Role | Default Chain | Notes |
| -------------- | ---------------------- | -------------------------------------- | ------------------------------------------------------ |
| **Hephaestus** | Deep autonomous worker | GPT-5.3-codex (medium) only | "Codex on steroids." No fallback. Requires GPT access. |
| **Oracle** | Architecture/debugging | GPT-5.4 (high) → Gemini 3 Pro → Opus | High-IQ strategic backup. GPT preferred. |
| **Momus** | High-accuracy reviewer | GPT-5.4 (medium) → Opus → Gemini 3 Pro | Verification agent. GPT preferred. |
| **Oracle** | Architecture/debugging | GPT-5.4 (high) → Gemini 3.1 Pro → Opus | High-IQ strategic backup. GPT preferred. |
| **Momus** | High-accuracy reviewer | GPT-5.4 (medium) → Opus → Gemini 3.1 Pro | Verification agent. GPT preferred. |
**Utility Agents** (speed over intelligence):
@@ -424,7 +425,7 @@ Read this document again, think about you have done everything correctly.
#### Say 'Congratulations! 🎉' to the user
Say to user: Congratulations! 🎉 You have successfully set up OhMyOpenCode! Type `opencode` in your terminal to start using it.
Say to user: Congratulations! 🎉 You have successfully set up OhMyOpenAgent! Type `opencode` in your terminal to start using it.
#### Free advertising

View File

@@ -1,6 +1,6 @@
# Orchestration System Guide
Oh My OpenCode's orchestration system transforms a simple AI agent into a coordinated development team through **separation of planning and execution**.
Oh My OpenAgent's orchestration system transforms a simple AI agent into a coordinated development team through **separation of planning and execution**.
---
@@ -298,7 +298,7 @@ task({ category: "quick", prompt: "..." }); // "Just get it done fast"
| `visual-engineering` | Gemini 3.1 Pro | Frontend, UI/UX, design, styling, animation |
| `ultrabrain` | GPT-5.4 (xhigh) | Deep logical reasoning, complex architecture decisions |
| `artistry` | Gemini 3.1 Pro (high) | Highly creative or artistic tasks, novel ideas |
| `quick` | Claude Haiku 4.5 | Trivial tasks - single file changes, typo fixes |
| `quick` | GPT-5.4 Mini | Trivial tasks - single file changes, typo fixes |
| `deep` | GPT-5.3 Codex (medium) | Goal-oriented autonomous problem-solving, thorough research |
| `unspecified-low` | Claude Sonnet 4.6 | Tasks that don't fit other categories, low effort |
| `unspecified-high` | Claude Opus 4.6 (max) | Tasks that don't fit other categories, high effort |

View File

@@ -1,6 +1,6 @@
# What Is Oh My OpenCode?
# What Is Oh My OpenAgent?
Oh My OpenCode is a multi-model agent orchestration harness for OpenCode. It transforms a single AI agent into a coordinated development team that actually ships code.
Oh My OpenAgent is a multi-model agent orchestration harness for OpenCode. It transforms a single AI agent into a coordinated development team that actually ships code.
Not locked to Claude. Not locked to OpenAI. Not locked to anyone.
@@ -41,13 +41,13 @@ We used to call this "Claude Code on steroids." That was wrong.
This isn't about making Claude Code better. It's about breaking free from the idea that one model, one provider, one way of working is enough. Anthropic wants you locked in. OpenAI wants you locked in. Everyone wants you locked in.
Oh My OpenCode doesn't play that game. It orchestrates across models, picking the right brain for the right job. Claude for orchestration. GPT for deep reasoning. Gemini for frontend. Haiku for quick tasks. All working together, automatically.
Oh My OpenAgent doesn't play that game. It orchestrates across models, picking the right brain for the right job. Claude for orchestration. GPT for deep reasoning. Gemini for frontend. GPT-5.4 Mini for quick tasks. All working together, automatically.
---
## How It Works: Agent Orchestration
Instead of one agent doing everything, Oh My OpenCode uses **specialized agents that delegate to each other** based on task type.
Instead of one agent doing everything, Oh My OpenAgent uses **specialized agents that delegate to each other** based on task type.
**The Architecture:**
@@ -99,9 +99,9 @@ Use Hephaestus when you need deep architectural reasoning, complex debugging acr
**Why this beats vanilla Codex CLI:**
- **Multi-model orchestration.** Pure Codex is single-model. OmO routes different tasks to different models automatically. GPT for deep reasoning. Gemini for frontend. Haiku for speed. The right brain for the right job.
- **Multi-model orchestration.** Pure Codex is single-model. OmO routes different tasks to different models automatically. GPT for deep reasoning. Gemini for frontend. GPT-5.4 Mini for speed. The right brain for the right job.
- **Background agents.** Fire 5+ agents in parallel. Something Codex simply cannot do. While one agent writes code, another researches patterns, another checks documentation. Like a real dev team.
- **Category system.** Tasks are routed by intent, not model name. `visual-engineering` gets Gemini. `ultrabrain` gets GPT-5.4. `quick` gets Haiku. No manual juggling.
- **Category system.** Tasks are routed by intent, not model name. `visual-engineering` gets Gemini. `ultrabrain` gets GPT-5.4. `quick` gets GPT-5.4 Mini. No manual juggling.
- **Accumulated wisdom.** Subagents learn from previous results. Conventions discovered in task 1 are passed to task 5. Mistakes made early aren't repeated. The system gets smarter as it works.
### Prometheus: The Strategic Planner
@@ -154,7 +154,7 @@ Use Prometheus for multi-day projects, critical production changes, complex refa
## Agent Model Matching
Different agents work best with different models. Oh My OpenCode automatically assigns optimal models, but you can customize everything.
Different agents work best with different models. Oh My OpenAgent automatically assigns optimal models, but you can customize everything.
### Default Configuration
@@ -195,8 +195,8 @@ You can override specific agents or categories in your config:
// General high-effort work
"unspecified-high": { "model": "anthropic/claude-opus-4-6", "variant": "max" },
// Quick tasks: use the cheapest models
"quick": { "model": "anthropic/claude-haiku-4-5" },
// Quick tasks: use GPT-5.4-mini (fast and cheap)
"quick": { "model": "openai/gpt-5.4-mini" },
// Deep reasoning: GPT-5.4
"ultrabrain": { "model": "openai/gpt-5.4", "variant": "xhigh" },
@@ -220,7 +220,7 @@ You can override specific agents or categories in your config:
**Different-behavior models**:
- Gemini 3 Pro — excels at visual/frontend tasks
- Gemini 3.1 Pro — excels at visual/frontend tasks
- MiniMax M2.5 — fast and smart for utility tasks
- Grok Code Fast 1 — optimized for code grep/search
@@ -232,7 +232,7 @@ See the [Agent-Model Matching Guide](./agent-model-matching.md) for complete det
Claude Code is good. But it's a single agent running a single model doing everything alone.
Oh My OpenCode turns that into a coordinated team:
Oh My OpenAgent turns that into a coordinated team:
**Parallel execution.** Claude Code processes one thing at a time. OmO fires background agents in parallel — research, implementation, and verification happening simultaneously. Like having 5 engineers instead of 1.
@@ -246,7 +246,7 @@ Oh My OpenCode turns that into a coordinated team:
**Discipline enforcement.** Todo enforcer yanks idle agents back to work. Comment checker strips AI slop. Ralph Loop keeps going until 100% done. The system doesn't let the agent slack off.
**The fundamental advantage.** Models have different temperaments. Claude thinks deeply. GPT reasons architecturally. Gemini visualizes. Haiku moves fast. Single-model tools force you to pick one personality for all tasks. Oh My OpenCode leverages them all, routing by task type. This isn't a temporary hack — it's the only architecture that makes sense as models specialize further. The gap between multi-model orchestration and single-model limitation widens every month. We're betting on that future.
**The fundamental advantage.** Models have different temperaments. Claude thinks deeply. GPT reasons architecturally. Gemini visualizes. Haiku moves fast. Single-model tools force you to pick one personality for all tasks. Oh My OpenAgent leverages them all, routing by task type. This isn't a temporary hack — it's the only architecture that makes sense as models specialize further. The gap between multi-model orchestration and single-model limitation widens every month. We're betting on that future.
---
@@ -256,7 +256,7 @@ Before acting on any request, Sisyphus classifies your true intent.
Are you asking for research? Implementation? Investigation? A fix? The Intent Gate figures out what you actually want, not just the literal words you typed. This means the agent understands context, nuance, and the real goal behind your request.
Claude Code doesn't have this. It takes your prompt and runs. Oh My OpenCode thinks first, then acts.
Claude Code doesn't have this. It takes your prompt and runs. Oh My OpenAgent thinks first, then acts.
---

View File

@@ -1,6 +1,6 @@
# Manifesto
The principles and philosophy behind Oh My OpenCode.
The principles and philosophy behind Oh My OpenAgent.
---
@@ -20,7 +20,7 @@ When you find yourself:
That's not "human-AI collaboration." That's the AI failing to do its job.
**Oh My OpenCode is built on this premise**: Human intervention during agentic work is fundamentally a wrong signal. If the system is designed correctly, the agent should complete the work without requiring you to babysit it.
**Oh My OpenAgent is built on this premise**: Human intervention during agentic work is fundamentally a wrong signal. If the system is designed correctly, the agent should complete the work without requiring you to babysit it.
---
@@ -144,7 +144,7 @@ Human Intent → Agent Execution → Verified Result
(intervention only on true failure)
```
Everything in Oh My OpenCode is designed to make this loop work:
Everything in Oh My OpenAgent is designed to make this loop work:
| Feature | Purpose |
|---------|---------|

View File

@@ -27,7 +27,7 @@ npx oh-my-openagent
## install
Interactive installation tool for initial Oh-My-OpenCode setup. Provides a TUI based on `@clack/prompts`.
Interactive installation tool for initial Oh-My-OpenAgent setup. Provides a TUI based on `@clack/prompts`.
### Usage
@@ -53,7 +53,7 @@ bunx oh-my-openagent install
## doctor
Diagnoses your environment to ensure Oh-My-OpenCode is functioning correctly. Performs 17+ health checks.
Diagnoses your environment to ensure Oh-My-OpenAgent is functioning correctly. Performs 17+ health checks.
### Usage
@@ -86,7 +86,7 @@ bunx oh-my-openagent doctor
oh-my-openagent doctor
┌──────────────────────────────────────────────────┐
│ Oh-My-OpenCode Doctor │
│ Oh-My-OpenAgent Doctor │
└──────────────────────────────────────────────────┘
Installation

View File

@@ -228,7 +228,7 @@ Domain-specific model delegation used by the `task()` tool. When Sisyphus delega
| `ultrabrain` | `openai/gpt-5.4` (xhigh) | Deep logical reasoning, complex architecture |
| `deep` | `openai/gpt-5.3-codex` (medium) | Autonomous problem-solving, thorough research |
| `artistry` | `google/gemini-3.1-pro` (high) | Creative/unconventional approaches |
| `quick` | `anthropic/claude-haiku-4-5` | Trivial tasks, typo fixes, single-file changes |
| `quick` | `openai/gpt-5.4-mini` | Trivial tasks, typo fixes, single-file changes |
| `unspecified-low` | `anthropic/claude-sonnet-4-6` | General tasks, low effort |
| `unspecified-high` | `anthropic/claude-opus-4-6` (max) | General tasks, high effort |
| `writing` | `google/gemini-3-flash` | Documentation, prose, technical writing |
@@ -286,7 +286,7 @@ Disable categories: `{ "disabled_categories": ["ultrabrain"] }`
| **ultrabrain** | `gpt-5.4` | `gpt-5.4``gemini-3.1-pro``claude-opus-4-6` |
| **deep** | `gpt-5.3-codex` | `gpt-5.3-codex``claude-opus-4-6``gemini-3.1-pro` |
| **artistry** | `gemini-3.1-pro` | `gemini-3.1-pro``claude-opus-4-6``gpt-5.4` |
| **quick** | `claude-haiku-4-5` | `claude-haiku-4-5``gemini-3-flash``gpt-5-nano` |
| **quick** | `gpt-5.4-mini` | `gpt-5.4-mini``claude-haiku-4-5``gemini-3-flash` `minimax-m2.5` `gpt-5-nano` |
| **unspecified-low** | `claude-sonnet-4-6` | `claude-sonnet-4-6``gpt-5.3-codex``gemini-3-flash` |
| **unspecified-high** | `claude-opus-4-6` | `claude-opus-4-6``gpt-5.4 (high)``glm-5``k2p5``kimi-k2.5` |
| **writing** | `gemini-3-flash` | `gemini-3-flash``claude-sonnet-4-6` |
@@ -418,15 +418,14 @@ Disable built-in skills: `{ "disabled_skills": ["playwright"] }`
Disable built-in hooks via `disabled_hooks`:
```json
{ "disabled_hooks": ["comment-checker", "gpt-permission-continuation"] }
{ "disabled_hooks": ["comment-checker"] }
```
Available hooks: `gpt-permission-continuation`, `todo-continuation-enforcer`, `context-window-monitor`, `session-recovery`, `session-notification`, `comment-checker`, `grep-output-truncator`, `tool-output-truncator`, `directory-agents-injector`, `directory-readme-injector`, `empty-task-response-detector`, `think-mode`, `anthropic-context-window-limit-recovery`, `rules-injector`, `background-notification`, `auto-update-checker`, `startup-toast`, `keyword-detector`, `agent-usage-reminder`, `non-interactive-env`, `interactive-bash-session`, `compaction-context-injector`, `thinking-block-validator`, `claude-code-hooks`, `ralph-loop`, `preemptive-compaction`, `auto-slash-command`, `sisyphus-junior-notepad`, `no-sisyphus-gpt`, `start-work`, `runtime-fallback`
Available hooks: `todo-continuation-enforcer`, `context-window-monitor`, `session-recovery`, `session-notification`, `comment-checker`, `grep-output-truncator`, `tool-output-truncator`, `directory-agents-injector`, `directory-readme-injector`, `empty-task-response-detector`, `think-mode`, `anthropic-context-window-limit-recovery`, `rules-injector`, `background-notification`, `auto-update-checker`, `startup-toast`, `keyword-detector`, `agent-usage-reminder`, `non-interactive-env`, `interactive-bash-session`, `compaction-context-injector`, `thinking-block-validator`, `claude-code-hooks`, `ralph-loop`, `preemptive-compaction`, `auto-slash-command`, `sisyphus-junior-notepad`, `no-sisyphus-gpt`, `start-work`, `runtime-fallback`
**Notes:**
- `directory-agents-injector` — auto-disabled on OpenCode 1.1.37+ (native AGENTS.md support)
- `gpt-permission-continuation` — resumes GPT sessions only when the last assistant reply ends with a permission-seeking tail like `If you want, ...`. Disable it if you prefer GPT sessions to wait for explicit user follow-up.
- `no-sisyphus-gpt`**do not disable**. It blocks incompatible GPT models for Sisyphus while allowing the dedicated GPT-5.4 prompt path.
- `startup-toast` is a sub-feature of `auto-update-checker`. Disable just the toast by adding `startup-toast` to `disabled_hooks`.

View File

@@ -1,8 +1,8 @@
# Oh-My-OpenCode Features Reference
# Oh-My-OpenAgent Features Reference
## Agents
Oh-My-OpenCode provides 11 specialized AI agents. Each has distinct expertise, optimized models, and tool permissions.
Oh-My-OpenAgent provides 11 specialized AI agents. Each has distinct expertise, optimized models, and tool permissions.
### Core Agents
@@ -111,7 +111,7 @@ By combining these two concepts, you can generate optimal agents through `task`.
| `ultrabrain` | `openai/gpt-5.4` (xhigh) | Deep logical reasoning, complex architecture decisions requiring extensive analysis |
| `deep` | `openai/gpt-5.3-codex` (medium) | Goal-oriented autonomous problem-solving. Thorough research before action. For hairy problems requiring deep understanding. |
| `artistry` | `google/gemini-3.1-pro` (high) | Highly creative/artistic tasks, novel ideas |
| `quick` | `anthropic/claude-haiku-4-5` | Trivial tasks - single file changes, typo fixes, simple modifications |
| `quick` | `openai/gpt-5.4-mini` | Trivial tasks - single file changes, typo fixes, simple modifications |
| `unspecified-low` | `anthropic/claude-sonnet-4-6` | Tasks that don't fit other categories, low effort required |
| `unspecified-high` | `anthropic/claude-opus-4-6` (max) | Tasks that don't fit other categories, high effort required |
| `writing` | `google/gemini-3-flash` | Documentation, prose, technical writing |
@@ -237,7 +237,7 @@ Skills provide specialized workflows with embedded MCP servers and detailed inst
### Browser Automation Options
Oh-My-OpenCode provides two browser automation providers, configurable via `browser_automation_engine.provider`.
Oh-My-OpenAgent provides two browser automation providers, configurable via `browser_automation_engine.provider`.
#### Option 1: Playwright MCP (Default)
@@ -558,7 +558,7 @@ Requires `experimental.task_system: true` in config.
#### Task System Details
**Note on Claude Code Alignment**: This implementation follows Claude Code's internal Task tool signatures (`TaskCreate`, `TaskUpdate`, `TaskList`, `TaskGet`) and field naming conventions (`subject`, `blockedBy`, `blocks`, etc.). However, Anthropic has not published official documentation for these tools. This is Oh My OpenCode's own implementation based on observed Claude Code behavior and internal specifications.
**Note on Claude Code Alignment**: This implementation follows Claude Code's internal Task tool signatures (`TaskCreate`, `TaskUpdate`, `TaskList`, `TaskGet`) and field naming conventions (`subject`, `blockedBy`, `blocks`, etc.). However, Anthropic has not published official documentation for these tools. This is Oh My OpenAgent's own implementation based on observed Claude Code behavior and internal specifications.
**Task Schema**:
@@ -680,7 +680,6 @@ Hooks intercept and modify behavior at key points in the agent lifecycle across
| **ralph-loop** | Event + Message | Manages self-referential loop continuation. |
| **start-work** | Message | Handles /start-work command execution. |
| **auto-slash-command** | Message | Automatically executes slash commands from prompts. |
| **gpt-permission-continuation** | Event | Auto-continues GPT sessions when the final assistant reply ends with a permission-seeking tail such as `If you want, ...`. |
| **stop-continuation-guard** | Event + Message | Guards the stop-continuation mechanism. |
| **category-skill-reminder** | Event + PostToolUse | Reminds agents about available category skills for delegation. |
| **anthropic-effort** | Params | Adjusts Anthropic API effort level based on context. |
@@ -735,7 +734,6 @@ Hooks intercept and modify behavior at key points in the agent lifecycle across
| Hook | Event | Description |
| ------------------------------ | ----- | ---------------------------------------------------------- |
| **gpt-permission-continuation** | Event | Continues GPT replies that end in a permission-seeking tail. |
| **todo-continuation-enforcer** | Event | Enforces todo completion — yanks idle agents back to work. |
| **compaction-todo-preserver** | Event | Preserves todo state during session compaction. |
| **unstable-agent-babysitter** | Event | Handles unstable agent behavior with recovery strategies. |
@@ -787,12 +785,10 @@ Disable specific hooks in config:
```json
{
"disabled_hooks": ["comment-checker", "gpt-permission-continuation"]
"disabled_hooks": ["comment-checker"]
}
```
Use `gpt-permission-continuation` when you want GPT sessions to stop at permission-seeking endings instead of auto-resuming.
## MCPs
### Built-in MCPs

View File

@@ -1,12 +1,12 @@
{
"name": "oh-my-openagent",
"name": "oh-my-opencode",
"version": "3.11.0",
"description": "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"type": "module",
"bin": {
"oh-my-openagent": "bin/oh-my-openagent.js"
"oh-my-opencode": "bin/oh-my-opencode.js"
},
"files": [
"dist",
@@ -18,7 +18,7 @@
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
},
"./schema.json": "./dist/oh-my-openagent.schema.json"
"./schema.json": "./dist/oh-my-opencode.schema.json"
},
"scripts": {
"build": "bun build src/index.ts --outdir dist --target bun --format esm --external @ast-grep/napi && tsc --emitDeclarationOnly && bun build src/cli/index.ts --outdir dist/cli --target bun --format esm --external @ast-grep/napi && bun run build:schema",
@@ -76,17 +76,17 @@
"typescript": "^5.7.3"
},
"optionalDependencies": {
"oh-my-openagent-darwin-arm64": "3.11.0",
"oh-my-openagent-darwin-x64": "3.11.0",
"oh-my-openagent-darwin-x64-baseline": "3.11.0",
"oh-my-openagent-linux-arm64": "3.11.0",
"oh-my-openagent-linux-arm64-musl": "3.11.0",
"oh-my-openagent-linux-x64": "3.11.0",
"oh-my-openagent-linux-x64-baseline": "3.11.0",
"oh-my-openagent-linux-x64-musl": "3.11.0",
"oh-my-openagent-linux-x64-musl-baseline": "3.11.0",
"oh-my-openagent-windows-x64": "3.11.0",
"oh-my-openagent-windows-x64-baseline": "3.11.0"
"oh-my-opencode-darwin-arm64": "3.11.0",
"oh-my-opencode-darwin-x64": "3.11.0",
"oh-my-opencode-darwin-x64-baseline": "3.11.0",
"oh-my-opencode-linux-arm64": "3.11.0",
"oh-my-opencode-linux-arm64-musl": "3.11.0",
"oh-my-opencode-linux-x64": "3.11.0",
"oh-my-opencode-linux-x64-baseline": "3.11.0",
"oh-my-opencode-linux-x64-musl": "3.11.0",
"oh-my-opencode-linux-x64-musl-baseline": "3.11.0",
"oh-my-opencode-windows-x64": "3.11.0",
"oh-my-opencode-windows-x64-baseline": "3.11.0"
},
"overrides": {
"@opencode-ai/sdk": "^1.2.24"

View File

@@ -1,7 +1,7 @@
{
"name": "oh-my-openagent-darwin-arm64",
"name": "oh-my-opencode-darwin-arm64",
"version": "3.11.0",
"description": "Platform-specific binary for oh-my-openagent (darwin-arm64)",
"description": "Platform-specific binary for oh-my-opencode (darwin-arm64)",
"license": "MIT",
"repository": {
"type": "git",

View File

@@ -1,7 +1,7 @@
{
"name": "oh-my-openagent-darwin-x64-baseline",
"name": "oh-my-opencode-darwin-x64-baseline",
"version": "3.11.0",
"description": "Platform-specific binary for oh-my-openagent (darwin-x64-baseline, no AVX2)",
"description": "Platform-specific binary for oh-my-opencode (darwin-x64-baseline, no AVX2)",
"license": "MIT",
"repository": {
"type": "git",

View File

@@ -1,7 +1,7 @@
{
"name": "oh-my-openagent-darwin-x64",
"name": "oh-my-opencode-darwin-x64",
"version": "3.11.0",
"description": "Platform-specific binary for oh-my-openagent (darwin-x64)",
"description": "Platform-specific binary for oh-my-opencode (darwin-x64)",
"license": "MIT",
"repository": {
"type": "git",

View File

@@ -1,7 +1,7 @@
{
"name": "oh-my-openagent-linux-arm64-musl",
"name": "oh-my-opencode-linux-arm64-musl",
"version": "3.11.0",
"description": "Platform-specific binary for oh-my-openagent (linux-arm64-musl)",
"description": "Platform-specific binary for oh-my-opencode (linux-arm64-musl)",
"license": "MIT",
"repository": {
"type": "git",

View File

@@ -1,7 +1,7 @@
{
"name": "oh-my-openagent-linux-arm64",
"name": "oh-my-opencode-linux-arm64",
"version": "3.11.0",
"description": "Platform-specific binary for oh-my-openagent (linux-arm64)",
"description": "Platform-specific binary for oh-my-opencode (linux-arm64)",
"license": "MIT",
"repository": {
"type": "git",

View File

@@ -1,7 +1,7 @@
{
"name": "oh-my-openagent-linux-x64-baseline",
"name": "oh-my-opencode-linux-x64-baseline",
"version": "3.11.0",
"description": "Platform-specific binary for oh-my-openagent (linux-x64-baseline, no AVX2)",
"description": "Platform-specific binary for oh-my-opencode (linux-x64-baseline, no AVX2)",
"license": "MIT",
"repository": {
"type": "git",

View File

@@ -1,7 +1,7 @@
{
"name": "oh-my-openagent-linux-x64-musl-baseline",
"name": "oh-my-opencode-linux-x64-musl-baseline",
"version": "3.11.0",
"description": "Platform-specific binary for oh-my-openagent (linux-x64-musl-baseline, no AVX2)",
"description": "Platform-specific binary for oh-my-opencode (linux-x64-musl-baseline, no AVX2)",
"license": "MIT",
"repository": {
"type": "git",

View File

@@ -1,7 +1,7 @@
{
"name": "oh-my-openagent-linux-x64-musl",
"name": "oh-my-opencode-linux-x64-musl",
"version": "3.11.0",
"description": "Platform-specific binary for oh-my-openagent (linux-x64-musl)",
"description": "Platform-specific binary for oh-my-opencode (linux-x64-musl)",
"license": "MIT",
"repository": {
"type": "git",

View File

@@ -1,7 +1,7 @@
{
"name": "oh-my-openagent-linux-x64",
"name": "oh-my-opencode-linux-x64",
"version": "3.11.0",
"description": "Platform-specific binary for oh-my-openagent (linux-x64)",
"description": "Platform-specific binary for oh-my-opencode (linux-x64)",
"license": "MIT",
"repository": {
"type": "git",

View File

@@ -1,7 +1,7 @@
{
"name": "oh-my-openagent-windows-x64-baseline",
"name": "oh-my-opencode-windows-x64-baseline",
"version": "3.11.0",
"description": "Platform-specific binary for oh-my-openagent (windows-x64-baseline, no AVX2)",
"description": "Platform-specific binary for oh-my-opencode (windows-x64-baseline, no AVX2)",
"license": "MIT",
"repository": {
"type": "git",

View File

@@ -1,7 +1,7 @@
{
"name": "oh-my-openagent-windows-x64",
"name": "oh-my-opencode-windows-x64",
"version": "3.11.0",
"description": "Platform-specific binary for oh-my-openagent (windows-x64)",
"description": "Platform-specific binary for oh-my-opencode (windows-x64)",
"license": "MIT",
"repository": {
"type": "git",

View File

@@ -48,9 +48,9 @@ function main() {
);
}
console.log(`✓ oh-my-openagent binary installed for ${platform}-${arch} (${resolvedPackage})`)
console.log(`✓ oh-my-opencode binary installed for ${platform}-${arch} (${resolvedPackage})`);
} catch (error) {
console.warn(`⚠ oh-my-openagent: ${error.message}`)
console.warn(`⚠ oh-my-opencode: ${error.message}`);
console.warn(` The CLI may not work on this platform.`);
// Don't fail installation - let user try anyway
}

View File

@@ -101,7 +101,9 @@ async function main() {
console.log("\n✅ All platform binaries built successfully!\n");
}
main().catch((error) => {
console.error("Fatal error:", error);
process.exit(1);
});
if (import.meta.main) {
main().catch((error) => {
console.error("Fatal error:", error);
process.exit(1);
});
}

View File

@@ -1,8 +1,8 @@
import * as z from "zod"
import { OhMyOpenAgentConfigSchema } from "../src/config/schema"
import { OhMyOpenCodeConfigSchema } from "../src/config/schema"
export function createOhMyOpenCodeJsonSchema(): Record<string, unknown> {
const jsonSchema = z.toJSONSchema(OhMyOpenAgentConfigSchema, {
const jsonSchema = z.toJSONSchema(OhMyOpenCodeConfigSchema, {
target: "draft-7",
unrepresentable: "any",
})

View File

@@ -3,30 +3,15 @@ import { createOhMyOpenCodeJsonSchema } from "./build-schema-document"
const SCHEMA_OUTPUT_PATH = "assets/oh-my-opencode.schema.json"
const DIST_SCHEMA_OUTPUT_PATH = "dist/oh-my-opencode.schema.json"
const OPENAGENT_SCHEMA_OUTPUT_PATH = "assets/oh-my-openagent.schema.json"
const OPENAGENT_DIST_SCHEMA_OUTPUT_PATH = "dist/oh-my-openagent.schema.json"
async function main() {
console.log("Generating JSON Schema...")
const finalSchema = createOhMyOpenCodeJsonSchema()
// oh-my-opencode schema (backward compatibility)
await Bun.write(SCHEMA_OUTPUT_PATH, JSON.stringify(finalSchema, null, 2))
await Bun.write(DIST_SCHEMA_OUTPUT_PATH, JSON.stringify(finalSchema, null, 2))
// oh-my-openagent schema (new name)
const openAgentSchema = {
...finalSchema,
$id: "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
title: "Oh My OpenAgent Configuration",
description: "Configuration schema for oh-my-openagent plugin",
}
await Bun.write(OPENAGENT_SCHEMA_OUTPUT_PATH, JSON.stringify(openAgentSchema, null, 2))
await Bun.write(OPENAGENT_DIST_SCHEMA_OUTPUT_PATH, JSON.stringify(openAgentSchema, null, 2))
console.log(`✓ JSON Schema generated: ${SCHEMA_OUTPUT_PATH}`)
console.log(`✓ JSON Schema generated: ${OPENAGENT_SCHEMA_OUTPUT_PATH}`)
}
main()

View File

@@ -2239,6 +2239,70 @@
"created_at": "2026-03-17T20:42:42Z",
"repoId": 1108837393,
"pullRequestNo": 2656
},
{
"name": "walioo",
"id": 25835823,
"comment_id": 4087098221,
"created_at": "2026-03-19T02:13:02Z",
"repoId": 1108837393,
"pullRequestNo": 2688
},
{
"name": "trafgals",
"id": 6454757,
"comment_id": 4087725932,
"created_at": "2026-03-19T04:22:32Z",
"repoId": 1108837393,
"pullRequestNo": 2690
},
{
"name": "tonymfer",
"id": 66512584,
"comment_id": 4091847232,
"created_at": "2026-03-19T17:13:49Z",
"repoId": 1108837393,
"pullRequestNo": 2701
},
{
"name": "nguyentamdat",
"id": 16253213,
"comment_id": 4096267323,
"created_at": "2026-03-20T07:34:22Z",
"repoId": 1108837393,
"pullRequestNo": 2718
},
{
"name": "whackur",
"id": 26926041,
"comment_id": 4102330445,
"created_at": "2026-03-21T05:27:17Z",
"repoId": 1108837393,
"pullRequestNo": 2733
},
{
"name": "ndaemy",
"id": 18691542,
"comment_id": 4103008804,
"created_at": "2026-03-21T10:18:22Z",
"repoId": 1108837393,
"pullRequestNo": 2734
},
{
"name": "0xYiliu",
"id": 3838688,
"comment_id": 4104738337,
"created_at": "2026-03-21T22:59:33Z",
"repoId": 1108837393,
"pullRequestNo": 2738
},
{
"name": "hunghoang3011",
"id": 65234777,
"comment_id": 4107900881,
"created_at": "2026-03-23T04:28:20Z",
"repoId": 1108837393,
"pullRequestNo": 2758
}
]
}

View File

@@ -14,7 +14,7 @@ Entry point `index.ts` orchestrates 5-step initialization: loadConfig → create
| `plugin-config.ts` | JSONC parse, multi-level merge, Zod v4 validation |
| `create-managers.ts` | TmuxSessionManager, BackgroundManager, SkillMcpManager, ConfigHandler |
| `create-tools.ts` | SkillContext + AvailableCategories + ToolRegistry (26 tools) |
| `create-hooks.ts` | 3-tier: Core(37) + Continuation(7) + Skill(2) = 46 hooks |
| `create-hooks.ts` | 3-tier: Core(39) + Continuation(7) + Skill(2) = 48 hooks |
| `plugin-interface.ts` | 8 OpenCode hook handlers: config, tool, chat.message, chat.params, chat.headers, event, tool.execute.before, tool.execute.after |
## CONFIG LOADING
@@ -32,10 +32,10 @@ loadPluginConfig(directory, ctx)
```
createHooks()
├─→ createCoreHooks() # 37 hooks
├─→ createCoreHooks() # 39 hooks
│ ├─ createSessionHooks() # 23: contextWindowMonitor, thinkMode, ralphLoop, modelFallback, runtimeFallback, noSisyphusGpt, noHephaestusNonGpt, anthropicEffort, intentGate...
│ ├─ createToolGuardHooks() # 10: commentChecker, rulesInjector, writeExistingFileGuard, jsonErrorRecovery, hashlineReadEnhancer...
│ ├─ createToolGuardHooks() # 12: commentChecker, rulesInjector, writeExistingFileGuard, jsonErrorRecovery, hashlineReadEnhancer...
│ └─ createTransformHooks() # 4: claudeCodeHooks, keywordDetector, contextInjector, thinkingBlockValidator
├─→ createContinuationHooks() # 7: todoContinuationEnforcer, atlas, stopContinuationGuard, ralphLoopActivator...
├─→ createContinuationHooks() # 7: todoContinuationEnforcer, atlas, stopContinuationGuard, compactionContextInjector...
└─→ createSkillHooks() # 2: categorySkillReminder, autoSlashCommand
```

View File

@@ -101,7 +101,7 @@ function buildDynamicOrchestratorPrompt(ctx?: OrchestratorContext): string {
export function createAtlasAgent(ctx: OrchestratorContext): AgentConfig {
const baseConfig = {
description:
"Orchestrates work via task() to complete ALL tasks in a todo list until fully done. (Atlas - OhMyOpenAgent)",
"Orchestrates work via task() to complete ALL tasks in a todo list until fully done. (Atlas - OhMyOpenCode)",
mode: MODE,
...(ctx.model ? { model: ctx.model } : {}),
temperature: 0.1,

View File

@@ -12,7 +12,7 @@ import { buildAntiDuplicationSection } from "../dynamic-agent-prompt-builder"
export const ATLAS_SYSTEM_PROMPT = `
<identity>
You are Atlas - the Master Orchestrator from OhMyOpenAgent.
You are Atlas - the Master Orchestrator from OhMyOpenCode.
In Greek mythology, Atlas holds up the celestial heavens. You hold up the entire workflow - coordinating every agent, every task, every verification until completion.

View File

@@ -12,7 +12,7 @@ import { buildAntiDuplicationSection } from "../dynamic-agent-prompt-builder"
export const ATLAS_GEMINI_SYSTEM_PROMPT = `
<identity>
You are Atlas - Master Orchestrator from OhMyOpenAgent.
You are Atlas - Master Orchestrator from OhMyOpenCode.
Role: Conductor, not musician. General, not soldier.
You DELEGATE, COORDINATE, and VERIFY. You NEVER write code yourself.

View File

@@ -12,7 +12,7 @@ import { buildAntiDuplicationSection } from "../dynamic-agent-prompt-builder"
export const ATLAS_GPT_SYSTEM_PROMPT = `
<identity>
You are Atlas - Master Orchestrator from OhMyOpenAgent.
You are Atlas - Master Orchestrator from OhMyOpenCode.
Role: Conductor, not musician. General, not soldier.
You DELEGATE, COORDINATE, and VERIFY. You NEVER write code yourself.
</identity>

View File

@@ -39,7 +39,7 @@ export function maybeCreateAtlasConfig(input: {
const atlasRequirement = AGENT_MODEL_REQUIREMENTS["atlas"]
const atlasResolution = applyModelResolution({
uiSelectedModel: orchestratorOverride?.model ? undefined : uiSelectedModel,
uiSelectedModel: orchestratorOverride?.model !== undefined ? undefined : uiSelectedModel,
userModel: orchestratorOverride?.model,
requirement: atlasRequirement,
availableModels,

View File

@@ -69,7 +69,7 @@ export function collectPendingBuiltinAgents(input: {
const isPrimaryAgent = isFactory(source) && source.mode === "primary"
let resolution = applyModelResolution({
uiSelectedModel: (isPrimaryAgent && !override?.model) ? uiSelectedModel : undefined,
uiSelectedModel: (isPrimaryAgent && override?.model === undefined) ? uiSelectedModel : undefined,
userModel: override?.model,
requirement,
availableModels,

View File

@@ -52,7 +52,7 @@ export function maybeCreateSisyphusConfig(input: {
if (disabledAgents.includes("sisyphus") || !meetsSisyphusAnyModelRequirement) return undefined
let sisyphusResolution = applyModelResolution({
uiSelectedModel: sisyphusOverride?.model ? undefined : uiSelectedModel,
uiSelectedModel: sisyphusOverride?.model !== undefined ? undefined : uiSelectedModel,
userModel: sisyphusOverride?.model,
requirement: sisyphusRequirement,
availableModels,

View File

@@ -181,7 +181,7 @@ describe("buildParallelDelegationSection", () => {
it("#given non-Claude model with deep category #when building #then returns aggressive delegation section", () => {
//#given
const model = "google/gemini-3-pro"
const model = "google/gemini-3.1-pro"
const categories = [deepCategory, otherCategory]
//#when
@@ -237,7 +237,7 @@ describe("buildParallelDelegationSection", () => {
describe("buildNonClaudePlannerSection", () => {
it("#given non-Claude model #when building #then returns plan agent section", () => {
//#given
const model = "google/gemini-3-pro"
const model = "google/gemini-3.1-pro"
//#when
const result = buildNonClaudePlannerSection(model)
@@ -272,4 +272,3 @@ describe("buildNonClaudePlannerSection", () => {
})
})

View File

@@ -35,7 +35,7 @@ export function createExploreAgent(model: string): AgentConfig {
return {
description:
'Contextual grep for codebases. Answers "Where is X?", "Which file has Y?", "Find the code that does Z". Fire multiple in parallel for broad searches. Specify thoroughness: "quick" for basic, "medium" for moderate, "very thorough" for comprehensive analysis. (Explore - OhMyOpenAgent)',
'Contextual grep for codebases. Answers "Where is X?", "Which file has Y?", "Find the code that does Z". Fire multiple in parallel for broad searches. Specify thoroughness: "quick" for basic, "medium" for moderate, "very thorough" for comprehensive analysis. (Explore - OhMyOpenCode)',
mode: MODE,
model,
temperature: 0.1,

View File

@@ -111,7 +111,7 @@ export function createHephaestusAgent(
return {
description:
"Autonomous Deep Worker - goal-oriented execution with GPT Codex. Explores thoroughly before acting, uses explore/librarian agents for comprehensive context, completes tasks end-to-end. Inspired by AmpCode deep mode. (Hephaestus - OhMyOpenAgent)",
"Autonomous Deep Worker - goal-oriented execution with GPT Codex. Explores thoroughly before acting, uses explore/librarian agents for comprehensive context, completes tasks end-to-end. Inspired by AmpCode deep mode. (Hephaestus - OhMyOpenCode)",
mode: MODE,
model,
maxTokens: 32000,

View File

@@ -162,6 +162,10 @@ Asking the user is the LAST resort after exhausting creative alternatives.
- User asks a question implying work → Answer briefly, DO the implied work in the same turn
- You wrote a plan in your response → EXECUTE the plan before ending turn — plans are starting lines, not finish lines
### Task Scope Clarification
You handle multi-step sub-tasks of a SINGLE GOAL. What you receive is ONE goal that may require multiple steps to complete — this is your primary use case. Only reject when given MULTIPLE INDEPENDENT goals in one request.
## Hard Constraints
${hardBlocks}
@@ -527,7 +531,7 @@ export function createHephaestusAgent(
return {
description:
"Autonomous Deep Worker - goal-oriented execution with GPT 5.4 Codex. Explores thoroughly before acting, uses explore/librarian agents for comprehensive context, completes tasks end-to-end. Inspired by AmpCode deep mode. (Hephaestus - OhMyOpenAgent)",
"Autonomous Deep Worker - goal-oriented execution with GPT 5.4 Codex. Explores thoroughly before acting, uses explore/librarian agents for comprehensive context, completes tasks end-to-end. Inspired by AmpCode deep mode. (Hephaestus - OhMyOpenCode)",
mode: MODE,
model,
maxTokens: 32000,

View File

@@ -121,6 +121,10 @@ When blocked: try a different approach → decompose the problem → challenge a
- User asks a question implying work → Answer briefly, DO the implied work in the same turn
- You wrote a plan in your response → EXECUTE the plan before ending turn — plans are starting lines, not finish lines
### Task Scope Clarification
You handle multi-step sub-tasks of a SINGLE GOAL. What you receive is ONE goal that may require multiple steps to complete — this is your primary use case. Only reject when given MULTIPLE INDEPENDENT goals in one request.
## Hard Constraints
${hardBlocks}

View File

@@ -112,6 +112,10 @@ Asking the user is the LAST resort after exhausting creative alternatives.
- Note assumptions in final message, not as questions mid-work
- Need context? Fire explore/librarian in background IMMEDIATELY — continue only with non-overlapping work while they search
### Task Scope Clarification
You handle multi-step sub-tasks of a SINGLE GOAL. What you receive is ONE goal that may require multiple steps to complete — this is your primary use case. Only reject when given MULTIPLE INDEPENDENT goals in one request.
## Hard Constraints
${hardBlocks}

View File

@@ -32,7 +32,7 @@ export function createLibrarianAgent(model: string): AgentConfig {
return {
description:
"Specialized codebase understanding agent for multi-repository analysis, searching remote codebases, retrieving official documentation, and finding implementation examples using GitHub CLI, Context7, and Web Search. MUST BE USED when users ask to look up code in remote repositories, explain library internals, or find usage examples in open source. (Librarian - OhMyOpenAgent)",
"Specialized codebase understanding agent for multi-repository analysis, searching remote codebases, retrieving official documentation, and finding implementation examples using GitHub CLI, Context7, and Web Search. MUST BE USED when users ask to look up code in remote repositories, explain library internals, or find usage examples in open source. (Librarian - OhMyOpenCode)",
mode: MODE,
model,
temperature: 0.1,

View File

@@ -302,7 +302,7 @@ const metisRestrictions = createAgentToolRestrictions([
export function createMetisAgent(model: string): AgentConfig {
return {
description:
"Pre-planning consultant that analyzes requests to identify hidden intentions, ambiguities, and AI failure points. (Metis - OhMyOpenAgent)",
"Pre-planning consultant that analyzes requests to identify hidden intentions, ambiguities, and AI failure points. (Metis - OhMyOpenCode)",
mode: MODE,
model,
temperature: 0.3,

View File

@@ -291,7 +291,7 @@ export function createMomusAgent(model: string): AgentConfig {
const base = {
description:
"Expert reviewer for evaluating work plans against rigorous clarity, verifiability, and completeness standards. (Momus - OhMyOpenAgent)",
"Expert reviewer for evaluating work plans against rigorous clarity, verifiability, and completeness standards. (Momus - OhMyOpenCode)",
mode: MODE,
model,
temperature: 0.1,

View File

@@ -16,7 +16,7 @@ export function createMultimodalLookerAgent(model: string): AgentConfig {
return {
description:
"Analyze media files (PDFs, images, diagrams) that require interpretation beyond raw text. Extracts specific information or summaries from documents, describes visual content. Use when you need analyzed/extracted data rather than literal file contents. (Multimodal-Looker - OhMyOpenAgent)",
"Analyze media files (PDFs, images, diagrams) that require interpretation beyond raw text. Extracts specific information or summaries from documents, describes visual content. Use when you need analyzed/extracted data rather than literal file contents. (Multimodal-Looker - OhMyOpenCode)",
mode: MODE,
model,
temperature: 0.1,

View File

@@ -252,7 +252,7 @@ export function createOracleAgent(model: string): AgentConfig {
const base = {
description:
"Read-only consultation agent. High-IQ reasoning specialist for debugging hard problems and high-difficulty architecture design. (Oracle - OhMyOpenAgent)",
"Read-only consultation agent. High-IQ reasoning specialist for debugging hard problems and high-difficulty architecture design. (Oracle - OhMyOpenCode)",
mode: MODE,
model,
temperature: 0.1,

View File

@@ -13,7 +13,7 @@ import { buildAntiDuplicationSection } from "../dynamic-agent-prompt-builder"
export const PROMETHEUS_GEMINI_SYSTEM_PROMPT = `
<identity>
You are Prometheus - Strategic Planning Consultant from OhMyOpenAgent.
You are Prometheus - Strategic Planning Consultant from OhMyOpenCode.
Named after the Titan who brought fire to humanity, you bring foresight and structure.
**YOU ARE A PLANNER. NOT AN IMPLEMENTER. NOT A CODE WRITER. NOT AN EXECUTOR.**

View File

@@ -12,7 +12,7 @@ import { buildAntiDuplicationSection } from "../dynamic-agent-prompt-builder";
export const PROMETHEUS_GPT_SYSTEM_PROMPT = `
<identity>
You are Prometheus - Strategic Planning Consultant from OhMyOpenAgent.
You are Prometheus - Strategic Planning Consultant from OhMyOpenCode.
Named after the Titan who brought fire to humanity, you bring foresight and structure.
**YOU ARE A PLANNER. NOT AN IMPLEMENTER. NOT A CODE WRITER.**

View File

@@ -0,0 +1,42 @@
import { describe, it, expect } from "bun:test"
import { getPrometheusPrompt } from "./system-prompt"
describe("getPrometheusPrompt", () => {
describe("#given question tool is not disabled", () => {
describe("#when generating prompt", () => {
it("#then should include Question tool references", () => {
const prompt = getPrometheusPrompt(undefined, [])
expect(prompt).toContain("Question({")
})
})
})
describe("#given question tool is disabled via disabled_tools", () => {
describe("#when generating prompt", () => {
it("#then should strip Question tool code examples", () => {
const prompt = getPrometheusPrompt(undefined, ["question"])
expect(prompt).not.toContain("Question({")
})
})
describe("#when disabled_tools includes question among other tools", () => {
it("#then should strip Question tool code examples", () => {
const prompt = getPrometheusPrompt(undefined, ["todowrite", "question", "interactive_bash"])
expect(prompt).not.toContain("Question({")
})
})
})
describe("#given no disabled_tools provided", () => {
describe("#when generating prompt with undefined", () => {
it("#then should include Question tool references", () => {
const prompt = getPrometheusPrompt(undefined, undefined)
expect(prompt).toContain("Question({")
})
})
})
})

View File

@@ -52,16 +52,34 @@ export function getPrometheusPromptSource(model?: string): PrometheusPromptSourc
* Gemini models → Gemini-optimized prompt (aggressive tool-call enforcement, thinking checkpoints)
* Default (Claude, etc.) → Claude-optimized prompt (modular sections)
*/
export function getPrometheusPrompt(model?: string): string {
export function getPrometheusPrompt(model?: string, disabledTools?: readonly string[]): string {
const source = getPrometheusPromptSource(model)
const isQuestionDisabled = disabledTools?.includes("question") ?? false
let prompt: string
switch (source) {
case "gpt":
return getGptPrometheusPrompt()
prompt = getGptPrometheusPrompt()
break
case "gemini":
return getGeminiPrometheusPrompt()
prompt = getGeminiPrometheusPrompt()
break
case "default":
default:
return PROMETHEUS_SYSTEM_PROMPT
prompt = PROMETHEUS_SYSTEM_PROMPT
}
if (isQuestionDisabled) {
prompt = stripQuestionToolReferences(prompt)
}
return prompt
}
/**
* Removes Question tool usage examples from prompt text when question tool is disabled.
*/
function stripQuestionToolReferences(prompt: string): string {
// Remove Question({...}) code blocks (multi-line)
return prompt.replace(/```typescript\n\s*Question\(\{[\s\S]*?\}\)\s*\n```/g, "")
}

View File

@@ -105,7 +105,7 @@ export function createSisyphusJuniorAgentWithOverrides(
const base: AgentConfig = {
description: override?.description ??
"Focused task executor. Same discipline, no delegation. (Sisyphus-Junior - OhMyOpenAgent)",
"Focused task executor. Same discipline, no delegation. (Sisyphus-Junior - OhMyOpenCode)",
mode: MODE,
model,
temperature,

View File

@@ -20,7 +20,7 @@ export function buildDefaultSisyphusJuniorPrompt(
: "All todos marked completed"
const prompt = `<Role>
Sisyphus-Junior - Focused executor from OhMyOpenAgent.
Sisyphus-Junior - Focused executor from OhMyOpenCode.
Execute tasks directly.
</Role>

View File

@@ -19,7 +19,8 @@ export function buildGeminiSisyphusJuniorPrompt(
const verificationText = useTaskSystem
? "All tasks marked completed"
: "All todos marked completed"
const prompt = `You are Sisyphus-Junior — a focused task executor from OhMyOpenAgent.
const prompt = `You are Sisyphus-Junior — a focused task executor from OhMyOpenCode.
## Identity
@@ -190,4 +191,4 @@ No tasks on multi-step work = INCOMPLETE WORK. The user tracks your progress thr
- **Batching** — NEVER batch completions. Mark EACH todo individually.
No todos on multi-step work = INCOMPLETE WORK. The user tracks your progress through todos.`
}
}

View File

@@ -17,7 +17,8 @@ export function buildGpt53CodexSisyphusJuniorPrompt(
const verificationText = useTaskSystem
? "All tasks marked completed"
: "All todos marked completed"
const prompt = `You are Sisyphus-Junior — a focused task executor from OhMyOpenAgent.
const prompt = `You are Sisyphus-Junior — a focused task executor from OhMyOpenCode.
## Identity

View File

@@ -20,7 +20,8 @@ export function buildGpt54SisyphusJuniorPrompt(
const verificationText = useTaskSystem
? "All tasks marked completed"
: "All todos marked completed";
const prompt = `You are Sisyphus-Junior — a focused task executor from OhMyOpenAgent.
const prompt = `You are Sisyphus-Junior — a focused task executor from OhMyOpenCode.
## Identity

View File

@@ -18,7 +18,8 @@ export function buildGptSisyphusJuniorPrompt(
const verificationText = useTaskSystem
? "All tasks marked completed"
: "All todos marked completed"
const prompt = `You are Sisyphus-Junior — a focused task executor from OhMyOpenAgent.
const prompt = `You are Sisyphus-Junior — a focused task executor from OhMyOpenCode.
## Identity

View File

@@ -73,7 +73,7 @@ function buildDynamicSisyphusPrompt(
: "YOUR TODO CREATION WOULD BE TRACKED BY HOOK([SYSTEM REMINDER - TODO CONTINUATION])";
return `<Role>
You are "Sisyphus" - Powerful AI Agent with orchestration capabilities from OhMyOpenAgent.
You are "Sisyphus" - Powerful AI Agent with orchestration capabilities from OhMyOpenCode.
**Why Sisyphus?**: Humans roll their boulder every day. So do you. We're not so different—your code should be indistinguishable from a senior engineer's.
@@ -467,7 +467,7 @@ export function createSisyphusAgent(
);
return {
description:
"Powerful AI orchestrator. Plans obsessively with todos, assesses search complexity before exploration, delegates strategically via category+skills combinations. Uses explore for internal code (parallel-friendly), librarian for external docs. (Sisyphus - OhMyOpenAgent)",
"Powerful AI orchestrator. Plans obsessively with todos, assesses search complexity before exploration, delegates strategically via category+skills combinations. Uses explore for internal code (parallel-friendly), librarian for external docs. (Sisyphus - OhMyOpenCode)",
mode: MODE,
model,
maxTokens: 64000,
@@ -518,7 +518,7 @@ export function createSisyphusAgent(
} as AgentConfig["permission"];
const base = {
description:
"Powerful AI orchestrator. Plans obsessively with todos, assesses search complexity before exploration, delegates strategically via category+skills combinations. Uses explore for internal code (parallel-friendly), librarian for external docs. (Sisyphus - OhMyOpenAgent)",
"Powerful AI orchestrator. Plans obsessively with todos, assesses search complexity before exploration, delegates strategically via category+skills combinations. Uses explore for internal code (parallel-friendly), librarian for external docs. (Sisyphus - OhMyOpenCode)",
mode: MODE,
model,
maxTokens: 64000,

View File

@@ -167,7 +167,7 @@ export function buildDefaultSisyphusPrompt(
: "YOUR TODO CREATION WOULD BE TRACKED BY HOOK([SYSTEM REMINDER - TODO CONTINUATION])";
return `<Role>
You are "Sisyphus" - Powerful AI Agent with orchestration capabilities from OhMyOpenAgent.
You are "Sisyphus" - Powerful AI Agent with orchestration capabilities from OhMyOpenCode.
**Why Sisyphus?**: Humans roll their boulder every day. So do you. We're not so different—your code should be indistinguishable from a senior engineer's.

View File

@@ -107,7 +107,7 @@ export function buildGpt54SisyphusPrompt(
: "YOUR TODO CREATION WOULD BE TRACKED BY HOOK([SYSTEM REMINDER - TODO CONTINUATION])";
const identityBlock = `<identity>
You are Sisyphus — an AI orchestrator from OhMyOpenAgent.
You are Sisyphus — an AI orchestrator from OhMyOpenCode.
You are a senior SF Bay Area engineer. You delegate, verify, and ship. Your code is indistinguishable from a senior engineer's work.

View File

@@ -2,7 +2,7 @@
exports[`generateModelConfig no providers available returns ULTIMATE_FALLBACK for all agents and categories when no providers 1`] = `
{
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
"agents": {
"atlas": {
"model": "opencode/gpt-5-nano",
@@ -66,7 +66,7 @@ exports[`generateModelConfig no providers available returns ULTIMATE_FALLBACK fo
exports[`generateModelConfig single native provider uses Claude models when only Claude is available 1`] = `
{
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
"agents": {
"atlas": {
"model": "anthropic/claude-sonnet-4-6",
@@ -128,7 +128,7 @@ exports[`generateModelConfig single native provider uses Claude models when only
exports[`generateModelConfig single native provider uses Claude models with isMax20 flag 1`] = `
{
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
"agents": {
"atlas": {
"model": "anthropic/claude-sonnet-4-6",
@@ -191,7 +191,7 @@ exports[`generateModelConfig single native provider uses Claude models with isMa
exports[`generateModelConfig single native provider uses OpenAI models when only OpenAI is available 1`] = `
{
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
"agents": {
"atlas": {
"model": "openai/gpt-5.4",
@@ -248,8 +248,7 @@ exports[`generateModelConfig single native provider uses OpenAI models when only
"variant": "medium",
},
"quick": {
"model": "openai/gpt-5.3-codex",
"variant": "low",
"model": "openai/gpt-5.4-mini",
},
"ultrabrain": {
"model": "openai/gpt-5.4",
@@ -277,7 +276,7 @@ exports[`generateModelConfig single native provider uses OpenAI models when only
exports[`generateModelConfig single native provider uses OpenAI models with isMax20 flag 1`] = `
{
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
"agents": {
"atlas": {
"model": "openai/gpt-5.4",
@@ -334,8 +333,7 @@ exports[`generateModelConfig single native provider uses OpenAI models with isMa
"variant": "medium",
},
"quick": {
"model": "openai/gpt-5.3-codex",
"variant": "low",
"model": "openai/gpt-5.4-mini",
},
"ultrabrain": {
"model": "openai/gpt-5.4",
@@ -363,7 +361,7 @@ exports[`generateModelConfig single native provider uses OpenAI models with isMa
exports[`generateModelConfig single native provider uses Gemini models when only Gemini is available 1`] = `
{
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
"agents": {
"atlas": {
"model": "opencode/gpt-5-nano",
@@ -423,7 +421,7 @@ exports[`generateModelConfig single native provider uses Gemini models when only
exports[`generateModelConfig single native provider uses Gemini models with isMax20 flag 1`] = `
{
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
"agents": {
"atlas": {
"model": "opencode/gpt-5-nano",
@@ -483,7 +481,7 @@ exports[`generateModelConfig single native provider uses Gemini models with isMa
exports[`generateModelConfig all native providers uses preferred models from fallback chains when all natives available 1`] = `
{
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
"agents": {
"atlas": {
"model": "anthropic/claude-sonnet-4-6",
@@ -533,7 +531,7 @@ exports[`generateModelConfig all native providers uses preferred models from fal
"variant": "medium",
},
"quick": {
"model": "anthropic/claude-haiku-4-5",
"model": "openai/gpt-5.4-mini",
},
"ultrabrain": {
"model": "openai/gpt-5.4",
@@ -558,7 +556,7 @@ exports[`generateModelConfig all native providers uses preferred models from fal
exports[`generateModelConfig all native providers uses preferred models with isMax20 flag when all natives available 1`] = `
{
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
"agents": {
"atlas": {
"model": "anthropic/claude-sonnet-4-6",
@@ -608,7 +606,7 @@ exports[`generateModelConfig all native providers uses preferred models with isM
"variant": "medium",
},
"quick": {
"model": "anthropic/claude-haiku-4-5",
"model": "openai/gpt-5.4-mini",
},
"ultrabrain": {
"model": "openai/gpt-5.4",
@@ -634,7 +632,7 @@ exports[`generateModelConfig all native providers uses preferred models with isM
exports[`generateModelConfig fallback providers uses OpenCode Zen models when only OpenCode Zen is available 1`] = `
{
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
"agents": {
"atlas": {
"model": "opencode/claude-sonnet-4-6",
@@ -684,7 +682,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models when on
"variant": "medium",
},
"quick": {
"model": "opencode/claude-haiku-4-5",
"model": "opencode/gpt-5.4-mini",
},
"ultrabrain": {
"model": "opencode/gpt-5.4",
@@ -709,7 +707,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models when on
exports[`generateModelConfig fallback providers uses OpenCode Zen models with isMax20 flag 1`] = `
{
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
"agents": {
"atlas": {
"model": "opencode/claude-sonnet-4-6",
@@ -759,7 +757,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models with is
"variant": "medium",
},
"quick": {
"model": "opencode/claude-haiku-4-5",
"model": "opencode/gpt-5.4-mini",
},
"ultrabrain": {
"model": "opencode/gpt-5.4",
@@ -785,7 +783,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models with is
exports[`generateModelConfig fallback providers uses GitHub Copilot models when only Copilot is available 1`] = `
{
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
"agents": {
"atlas": {
"model": "github-copilot/claude-sonnet-4.6",
@@ -830,7 +828,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when
"variant": "high",
},
"quick": {
"model": "github-copilot/claude-haiku-4.5",
"model": "github-copilot/gpt-5.4-mini",
},
"ultrabrain": {
"model": "github-copilot/gemini-3.1-pro-preview",
@@ -855,7 +853,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when
exports[`generateModelConfig fallback providers uses GitHub Copilot models with isMax20 flag 1`] = `
{
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
"agents": {
"atlas": {
"model": "github-copilot/claude-sonnet-4.6",
@@ -900,7 +898,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with
"variant": "high",
},
"quick": {
"model": "github-copilot/claude-haiku-4.5",
"model": "github-copilot/gpt-5.4-mini",
},
"ultrabrain": {
"model": "github-copilot/gemini-3.1-pro-preview",
@@ -926,7 +924,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with
exports[`generateModelConfig fallback providers uses ZAI model for librarian when only ZAI is available 1`] = `
{
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
"agents": {
"atlas": {
"model": "opencode/gpt-5-nano",
@@ -984,7 +982,7 @@ exports[`generateModelConfig fallback providers uses ZAI model for librarian whe
exports[`generateModelConfig fallback providers uses ZAI model for librarian with isMax20 flag 1`] = `
{
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
"agents": {
"atlas": {
"model": "opencode/gpt-5-nano",
@@ -1042,7 +1040,7 @@ exports[`generateModelConfig fallback providers uses ZAI model for librarian wit
exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen combination 1`] = `
{
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
"agents": {
"atlas": {
"model": "anthropic/claude-sonnet-4-6",
@@ -1092,7 +1090,7 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen
"variant": "medium",
},
"quick": {
"model": "anthropic/claude-haiku-4-5",
"model": "opencode/gpt-5.4-mini",
},
"ultrabrain": {
"model": "opencode/gpt-5.4",
@@ -1117,7 +1115,7 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen
exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot combination 1`] = `
{
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
"agents": {
"atlas": {
"model": "github-copilot/claude-sonnet-4.6",
@@ -1167,7 +1165,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb
"variant": "medium",
},
"quick": {
"model": "github-copilot/claude-haiku-4.5",
"model": "openai/gpt-5.4-mini",
},
"ultrabrain": {
"model": "openai/gpt-5.4",
@@ -1192,7 +1190,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb
exports[`generateModelConfig mixed provider scenarios uses Claude + ZAI combination (librarian uses ZAI) 1`] = `
{
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
"agents": {
"atlas": {
"model": "anthropic/claude-sonnet-4-6",
@@ -1256,7 +1254,7 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + ZAI combinat
exports[`generateModelConfig mixed provider scenarios uses Gemini + Claude combination (explore uses Gemini) 1`] = `
{
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
"agents": {
"atlas": {
"model": "anthropic/claude-sonnet-4-6",
@@ -1322,7 +1320,7 @@ exports[`generateModelConfig mixed provider scenarios uses Gemini + Claude combi
exports[`generateModelConfig mixed provider scenarios uses all fallback providers together 1`] = `
{
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
"agents": {
"atlas": {
"model": "github-copilot/claude-sonnet-4.6",
@@ -1375,7 +1373,7 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider
"variant": "medium",
},
"quick": {
"model": "github-copilot/claude-haiku-4.5",
"model": "github-copilot/gpt-5.4-mini",
},
"ultrabrain": {
"model": "opencode/gpt-5.4",
@@ -1400,7 +1398,7 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider
exports[`generateModelConfig mixed provider scenarios uses all providers together 1`] = `
{
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
"agents": {
"atlas": {
"model": "anthropic/claude-sonnet-4-6",
@@ -1453,7 +1451,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe
"variant": "medium",
},
"quick": {
"model": "anthropic/claude-haiku-4-5",
"model": "openai/gpt-5.4-mini",
},
"ultrabrain": {
"model": "openai/gpt-5.4",
@@ -1478,7 +1476,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe
exports[`generateModelConfig mixed provider scenarios uses all providers with isMax20 flag 1`] = `
{
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
"agents": {
"atlas": {
"model": "anthropic/claude-sonnet-4-6",
@@ -1531,7 +1529,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is
"variant": "medium",
},
"quick": {
"model": "anthropic/claude-haiku-4-5",
"model": "openai/gpt-5.4-mini",
},
"ultrabrain": {
"model": "openai/gpt-5.4",

View File

@@ -43,7 +43,7 @@ describe("runCliInstaller", () => {
}),
spyOn(configManager, "writeOmoConfig").mockReturnValue({
success: true,
configPath: "/tmp/oh-my-openagent.jsonc"
configPath: "/tmp/oh-my-opencode.jsonc",
}),
]

View File

@@ -32,7 +32,7 @@ export async function runCliInstaller(args: InstallArgs, version: string): Promi
}
console.log()
printInfo(
"Usage: bunx oh-my-openagent install --no-tui --claude=<no|yes|max20> --gemini=<no|yes> --copilot=<no|yes>"
"Usage: bunx oh-my-opencode install --no-tui --claude=<no|yes|max20> --gemini=<no|yes> --copilot=<no|yes>",
)
console.log()
return 1
@@ -65,7 +65,7 @@ export async function runCliInstaller(args: InstallArgs, version: string): Promi
const config = argsToConfig(args)
printStep(step++, totalSteps, "Adding oh-my-openagent plugin...")
printStep(step++, totalSteps, "Adding oh-my-opencode plugin...")
const pluginResult = await addPluginToOpenCodeConfig(version)
if (!pluginResult.success) {
printError(`Failed: ${pluginResult.error}`)
@@ -75,7 +75,7 @@ export async function runCliInstaller(args: InstallArgs, version: string): Promi
`Plugin ${isUpdate ? "verified" : "added"} ${SYMBOLS.arrow} ${color.dim(pluginResult.configPath)}`,
)
printStep(step++, totalSteps, "Writing oh-my-openagent configuration...")
printStep(step++, totalSteps, "Writing oh-my-opencode configuration...")
const omoResult = writeOmoConfig(config)
if (!omoResult.success) {
printError(`Failed: ${omoResult.error}`)

View File

@@ -15,14 +15,14 @@ const VERSION = packageJson.version
const program = new Command()
program
.name("oh-my-openagent")
.name("oh-my-opencode")
.description("The ultimate OpenCode plugin - multi-model orchestration, LSP tools, and more")
.version(VERSION, "-v, --version", "Show version number")
.enablePositionalOptions()
program
.command("install")
.description("Install and configure oh-my-openagent with interactive setup")
.description("Install and configure oh-my-opencode with interactive setup")
.option("--no-tui", "Run in non-interactive mode (requires all options)")
.option("--claude <value>", "Claude subscription: no, yes, max20")
.option("--openai <value>", "OpenAI/ChatGPT subscription: no, yes (default: no)")
@@ -35,14 +35,14 @@ program
.option("--skip-auth", "Skip authentication setup hints")
.addHelpText("after", `
Examples:
$ bunx oh-my-openagent install
$ bunx oh-my-openagent install --no-tui --claude=max20 --openai=yes --gemini=yes --copilot=no
$ bunx oh-my-openagent install --no-tui --claude=no --gemini=no --copilot=yes --opencode-zen=yes
$ bunx oh-my-opencode install
$ bunx oh-my-opencode install --no-tui --claude=max20 --openai=yes --gemini=yes --copilot=no
$ bunx oh-my-opencode install --no-tui --claude=no --gemini=no --copilot=yes --opencode-zen=yes
Model Providers (Priority: Native > Copilot > OpenCode Zen > Z.ai > Kimi):
Claude Native anthropic/ models (Opus, Sonnet, Haiku)
OpenAI Native openai/ models (GPT-5.4 for Oracle)
Gemini Native google/ models (Gemini 3 Pro, Flash)
Gemini Native google/ models (Gemini 3.1 Pro, Flash)
Copilot github-copilot/ models (fallback)
OpenCode Zen opencode/ models (opencode/claude-opus-4-6, etc.)
Z.ai zai-coding-plan/glm-5 (visual-engineering fallback)
@@ -82,20 +82,20 @@ program
.option("--session-id <id>", "Resume existing session instead of creating new one")
.addHelpText("after", `
Examples:
$ bunx oh-my-openagent run "Fix the bug in index.ts"
$ bunx oh-my-openagent run --agent Sisyphus "Implement feature X"
$ bunx oh-my-openagent run --port 4321 "Fix the bug"
$ bunx oh-my-openagent run --attach http://127.0.0.1:4321 "Fix the bug"
$ bunx oh-my-openagent run --json "Fix the bug" | jq .sessionId
$ bunx oh-my-openagent run --on-complete "notify-send Done" "Fix the bug"
$ bunx oh-my-openagent run --session-id ses_abc123 "Continue the work"
$ bunx oh-my-openagent run --model anthropic/claude-sonnet-4 "Fix the bug"
$ bunx oh-my-openagent run --agent Sisyphus --model openai/gpt-5.4 "Implement feature X"
$ bunx oh-my-opencode run "Fix the bug in index.ts"
$ bunx oh-my-opencode run --agent Sisyphus "Implement feature X"
$ bunx oh-my-opencode run --port 4321 "Fix the bug"
$ bunx oh-my-opencode run --attach http://127.0.0.1:4321 "Fix the bug"
$ bunx oh-my-opencode run --json "Fix the bug" | jq .sessionId
$ bunx oh-my-opencode run --on-complete "notify-send Done" "Fix the bug"
$ bunx oh-my-opencode run --session-id ses_abc123 "Continue the work"
$ bunx oh-my-opencode run --model anthropic/claude-sonnet-4 "Fix the bug"
$ bunx oh-my-opencode run --agent Sisyphus --model openai/gpt-5.4 "Implement feature X"
Agent resolution order:
1) --agent flag
2) OPENCODE_DEFAULT_AGENT
3) oh-my-openagent.json "default_run_agent"
3) oh-my-opencode.json "default_run_agent"
4) Sisyphus (fallback)
Available core agents:
@@ -134,9 +134,9 @@ program
.option("--json", "Output in JSON format for scripting")
.addHelpText("after", `
Examples:
$ bunx oh-my-openagent get-local-version
$ bunx oh-my-openagent get-local-version --json
$ bunx oh-my-openagent get-local-version --directory /path/to/project
$ bunx oh-my-opencode get-local-version
$ bunx oh-my-opencode get-local-version --json
$ bunx oh-my-opencode get-local-version --directory /path/to/project
This command shows:
- Current installed version
@@ -155,16 +155,16 @@ This command shows:
program
.command("doctor")
.description("Check oh-my-openagent installation health and diagnose issues")
.description("Check oh-my-opencode installation health and diagnose issues")
.option("--status", "Show compact system dashboard")
.option("--verbose", "Show detailed diagnostic information")
.option("--json", "Output results in JSON format")
.addHelpText("after", `
Examples:
$ bunx oh-my-openagent doctor # Show problems only
$ bunx oh-my-openagent doctor --status # Compact dashboard
$ bunx oh-my-openagent doctor --verbose # Deep diagnostics
$ bunx oh-my-openagent doctor --json # JSON output
$ bunx oh-my-opencode doctor # Show problems only
$ bunx oh-my-opencode doctor --status # Compact dashboard
$ bunx oh-my-opencode doctor --verbose # Deep diagnostics
$ bunx oh-my-opencode doctor --json # JSON output
`)
.action(async (options) => {
const mode = options.status ? "status" : options.verbose ? "verbose" : "default"
@@ -180,7 +180,7 @@ program
.command("version")
.description("Show version information")
.action(() => {
console.log(`oh-my-openagent v${VERSION}`)
console.log(`oh-my-opencode v${VERSION}`)
})
program.addCommand(createMcpOAuthCommand())

View File

@@ -23,7 +23,7 @@ describe("getPluginNameWithVersion", () => {
const result = await getPluginNameWithVersion("2.14.0")
// #then should use @latest tag
expect(result).toBe("oh-my-openagent@latest")
expect(result).toBe("oh-my-opencode@latest")
})
test("returns @beta when current version matches beta tag", async () => {
@@ -39,7 +39,7 @@ describe("getPluginNameWithVersion", () => {
const result = await getPluginNameWithVersion("3.0.0-beta.3")
// #then should use @beta tag
expect(result).toBe("oh-my-openagent@beta")
expect(result).toBe("oh-my-opencode@beta")
})
test("returns @next when current version matches next tag", async () => {
@@ -55,7 +55,7 @@ describe("getPluginNameWithVersion", () => {
const result = await getPluginNameWithVersion("3.1.0-next.1")
// #then should use @next tag
expect(result).toBe("oh-my-openagent@next")
expect(result).toBe("oh-my-opencode@next")
})
test("returns prerelease channel tag when no dist-tag matches prerelease version", async () => {
@@ -71,7 +71,7 @@ describe("getPluginNameWithVersion", () => {
const result = await getPluginNameWithVersion("3.0.0-beta.2")
// #then should preserve prerelease channel
expect(result).toBe("oh-my-openagent@beta")
expect(result).toBe("oh-my-opencode@beta")
})
test("returns prerelease channel tag when fetch fails", async () => {
@@ -82,7 +82,7 @@ describe("getPluginNameWithVersion", () => {
const result = await getPluginNameWithVersion("3.0.0-beta.3")
// #then should preserve prerelease channel
expect(result).toBe("oh-my-openagent@beta")
expect(result).toBe("oh-my-opencode@beta")
})
test("returns bare package name when npm returns non-ok response for stable version", async () => {
@@ -98,7 +98,7 @@ describe("getPluginNameWithVersion", () => {
const result = await getPluginNameWithVersion("2.14.0")
// #then should fall back to bare package entry
expect(result).toBe("oh-my-openagent")
expect(result).toBe("oh-my-opencode")
})
test("prioritizes latest over other tags when version matches multiple", async () => {
@@ -114,7 +114,7 @@ describe("getPluginNameWithVersion", () => {
const result = await getPluginNameWithVersion("3.0.0")
// #then should prioritize @latest
expect(result).toBe("oh-my-openagent@latest")
expect(result).toBe("oh-my-opencode@latest")
})
})
@@ -207,7 +207,7 @@ describe("generateOmoConfig - model fallback system", () => {
const result = generateOmoConfig(config)
// #then Sisyphus is omitted (requires all fallback providers)
expect(result.$schema).toBe("https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json")
expect(result.$schema).toBe("https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json")
expect((result.agents as Record<string, { model: string }>).sisyphus).toBeUndefined()
})

View File

@@ -1,109 +0,0 @@
import { afterEach, beforeEach, describe, expect, it } from "bun:test"
import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"
import { tmpdir } from "node:os"
import { join } from "node:path"
import { initConfigContext, resetConfigContext } from "./config-context"
import { addPluginToOpenCodeConfig } from "./add-plugin-to-opencode-config"
describe("addPluginToOpenCodeConfig", () => {
let testConfigDir = ""
let testConfigPath = ""
beforeEach(() => {
testConfigDir = join(tmpdir(), `omo-add-plugin-${Date.now()}-${Math.random().toString(36).slice(2)}`)
testConfigPath = join(testConfigDir, "opencode.json")
mkdirSync(testConfigDir, { recursive: true })
process.env.OPENCODE_CONFIG_DIR = testConfigDir
resetConfigContext()
initConfigContext("opencode", null)
})
afterEach(() => {
rmSync(testConfigDir, { recursive: true, force: true })
resetConfigContext()
delete process.env.OPENCODE_CONFIG_DIR
})
describe("#given opencode.json with oh-my-opencode plugin", () => {
it("replaces oh-my-opencode with new plugin entry", async () => {
// given
const config = { plugin: ["oh-my-opencode"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
// when
const result = await addPluginToOpenCodeConfig("3.11.0")
// then
expect(result.success).toBe(true)
const savedConfig = JSON.parse(readFileSync(testConfigPath, "utf-8"))
// getPluginNameWithVersion returns just the name (without version) for non-dist-tag versions
expect(savedConfig.plugin).toContain("oh-my-openagent")
expect(savedConfig.plugin).not.toContain("oh-my-opencode")
})
it("replaces oh-my-opencode@old-version with new plugin entry", async () => {
// given
const config = { plugin: ["oh-my-opencode@1.0.0"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
// when
const result = await addPluginToOpenCodeConfig("3.11.0")
// then
expect(result.success).toBe(true)
const savedConfig = JSON.parse(readFileSync(testConfigPath, "utf-8"))
expect(savedConfig.plugin).toContain("oh-my-openagent")
expect(savedConfig.plugin).not.toContain("oh-my-opencode@1.0.0")
})
})
describe("#given opencode.json with oh-my-openagent plugin", () => {
it("keeps existing oh-my-openagent when no version change needed", async () => {
// given
const config = { plugin: ["oh-my-openagent"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
// when
const result = await addPluginToOpenCodeConfig("3.11.0")
// then
expect(result.success).toBe(true)
const savedConfig = JSON.parse(readFileSync(testConfigPath, "utf-8"))
// Should keep the existing entry since getPluginNameWithVersion returns same name
expect(savedConfig.plugin).toContain("oh-my-openagent")
})
it("replaces oh-my-openagent@old-version with new plugin entry", async () => {
// given
const config = { plugin: ["oh-my-openagent@1.0.0"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
// when
const result = await addPluginToOpenCodeConfig("3.11.0")
// then
expect(result.success).toBe(true)
const savedConfig = JSON.parse(readFileSync(testConfigPath, "utf-8"))
expect(savedConfig.plugin).toContain("oh-my-openagent")
})
})
describe("#given opencode.json with other plugins", () => {
it("adds new plugin alongside existing plugins", async () => {
// given
const config = { plugin: ["some-other-plugin"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
// when
const result = await addPluginToOpenCodeConfig("3.11.0")
// then
expect(result.success).toBe(true)
const savedConfig = JSON.parse(readFileSync(testConfigPath, "utf-8"))
expect(savedConfig.plugin).toContain("oh-my-openagent")
expect(savedConfig.plugin).toContain("some-other-plugin")
})
})
})

View File

@@ -1,6 +1,6 @@
import { readFileSync, writeFileSync } from "node:fs"
import { LEGACY_PLUGIN_NAME, PLUGIN_NAME } from "../../shared"
import type { ConfigMergeResult } from "../types"
import { PLUGIN_NAME, LEGACY_PLUGIN_NAME } from "../../shared"
import { getConfigDir } from "./config-context"
import { ensureConfigDirectoryExists } from "./ensure-config-directory-exists"
import { formatErrorWithSuggestion } from "./format-error-with-suggestion"
@@ -8,21 +8,19 @@ import { detectConfigFormat } from "./opencode-config-format"
import { parseOpenCodeConfigFileWithError, type OpenCodeConfig } from "./parse-opencode-config-file"
import { getPluginNameWithVersion } from "./plugin-name-with-version"
const PACKAGE_NAME = PLUGIN_NAME
export async function addPluginToOpenCodeConfig(currentVersion: string): Promise<ConfigMergeResult> {
try {
ensureConfigDirectoryExists()
} catch (error) {
} catch (err) {
return {
success: false,
configPath: getConfigDir(),
error: formatErrorWithSuggestion(error, "create config directory"),
error: formatErrorWithSuggestion(err, "create config directory"),
}
}
const { format, path } = detectConfigFormat()
const pluginEntry = await getPluginNameWithVersion(currentVersion, PACKAGE_NAME)
const pluginEntry = await getPluginNameWithVersion(currentVersion, PLUGIN_NAME)
try {
if (format === "none") {
@@ -42,6 +40,8 @@ export async function addPluginToOpenCodeConfig(currentVersion: string): Promise
const config = parseResult.config
const plugins = config.plugin ?? []
// Check for existing plugin (either current or legacy name)
const currentNameIndex = plugins.findIndex(
(plugin) => plugin === PLUGIN_NAME || plugin.startsWith(`${PLUGIN_NAME}@`)
)
@@ -49,12 +49,14 @@ export async function addPluginToOpenCodeConfig(currentVersion: string): Promise
(plugin) => plugin === LEGACY_PLUGIN_NAME || plugin.startsWith(`${LEGACY_PLUGIN_NAME}@`)
)
// If either name exists, update to new name
if (currentNameIndex !== -1) {
if (plugins[currentNameIndex] === pluginEntry) {
return { success: true, configPath: path }
}
plugins[currentNameIndex] = pluginEntry
} else if (legacyNameIndex !== -1) {
// Upgrade legacy name to new name
plugins[legacyNameIndex] = pluginEntry
} else {
plugins.push(pluginEntry)
@@ -68,7 +70,7 @@ export async function addPluginToOpenCodeConfig(currentVersion: string): Promise
const match = content.match(pluginArrayRegex)
if (match) {
const formattedPlugins = plugins.map((plugin) => `"${plugin}"`).join(",\n ")
const formattedPlugins = plugins.map((p) => `"${p}"`).join(",\n ")
const newContent = content.replace(pluginArrayRegex, `"plugin": [\n ${formattedPlugins}\n ]`)
writeFileSync(path, newContent)
} else {
@@ -80,11 +82,11 @@ export async function addPluginToOpenCodeConfig(currentVersion: string): Promise
}
return { success: true, configPath: path }
} catch (error) {
} catch (err) {
return {
success: false,
configPath: path,
error: formatErrorWithSuggestion(error, "update opencode config"),
error: formatErrorWithSuggestion(err, "update opencode config"),
}
}
}

View File

@@ -1,106 +0,0 @@
import { afterEach, beforeEach, describe, expect, it } from "bun:test"
import { mkdirSync, rmSync, writeFileSync } from "node:fs"
import { tmpdir } from "node:os"
import { join } from "node:path"
import { initConfigContext, resetConfigContext } from "./config-context"
import { detectCurrentConfig } from "./detect-current-config"
describe("detectCurrentConfig", () => {
let testConfigDir = ""
let testConfigPath = ""
beforeEach(() => {
testConfigDir = join(tmpdir(), `omo-detect-config-${Date.now()}-${Math.random().toString(36).slice(2)}`)
testConfigPath = join(testConfigDir, "opencode.json")
mkdirSync(testConfigDir, { recursive: true })
process.env.OPENCODE_CONFIG_DIR = testConfigDir
resetConfigContext()
initConfigContext("opencode", null)
})
afterEach(() => {
rmSync(testConfigDir, { recursive: true, force: true })
resetConfigContext()
delete process.env.OPENCODE_CONFIG_DIR
})
describe("#given opencode.json with oh-my-opencode plugin", () => {
it("returns isInstalled: true when plugin array contains oh-my-opencode", () => {
// given
const config = { plugin: ["oh-my-opencode"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
// when
const result = detectCurrentConfig()
// then
expect(result.isInstalled).toBe(true)
})
it("returns isInstalled: true when plugin array contains oh-my-opencode with version", () => {
// given
const config = { plugin: ["oh-my-opencode@3.11.0"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
// when
const result = detectCurrentConfig()
// then
expect(result.isInstalled).toBe(true)
})
})
describe("#given opencode.json with oh-my-openagent plugin", () => {
it("returns isInstalled: true when plugin array contains oh-my-openagent", () => {
// given
const config = { plugin: ["oh-my-openagent"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
// when
const result = detectCurrentConfig()
// then
expect(result.isInstalled).toBe(true)
})
it("returns isInstalled: true when plugin array contains oh-my-openagent with version", () => {
// given
const config = { plugin: ["oh-my-openagent@3.11.0"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
// when
const result = detectCurrentConfig()
// then
expect(result.isInstalled).toBe(true)
})
})
describe("#given opencode.json with no plugin", () => {
it("returns isInstalled: false when plugin array is empty", () => {
// given
const config = { plugin: [] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
// when
const result = detectCurrentConfig()
// then
expect(result.isInstalled).toBe(false)
})
it("returns isInstalled: false when plugin array does not contain our plugin", () => {
// given
const config = { plugin: ["some-other-plugin"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
// when
const result = detectCurrentConfig()
// then
expect(result.isInstalled).toBe(false)
})
})
})

View File

@@ -36,12 +36,12 @@ function detectProvidersFromOmoConfig(): {
}
}
const configString = JSON.stringify(omoConfig)
const hasOpenAI = configString.includes('"openai/')
const hasOpencodeZen = configString.includes('"opencode/')
const hasZaiCodingPlan = configString.includes('"zai-coding-plan/')
const hasKimiForCoding = configString.includes('"kimi-for-coding/')
const hasOpencodeGo = configString.includes('"opencode-go/')
const configStr = JSON.stringify(omoConfig)
const hasOpenAI = configStr.includes('"openai/')
const hasOpencodeZen = configStr.includes('"opencode/')
const hasZaiCodingPlan = configStr.includes('"zai-coding-plan/')
const hasKimiForCoding = configStr.includes('"kimi-for-coding/')
const hasOpencodeGo = configStr.includes('"opencode-go/')
return { hasOpenAI, hasOpencodeZen, hasZaiCodingPlan, hasKimiForCoding, hasOpencodeGo }
} catch {
@@ -56,12 +56,8 @@ function detectProvidersFromOmoConfig(): {
}
function isOurPlugin(plugin: string): boolean {
return (
plugin === PLUGIN_NAME ||
plugin.startsWith(`${PLUGIN_NAME}@`) ||
plugin === LEGACY_PLUGIN_NAME ||
plugin.startsWith(`${LEGACY_PLUGIN_NAME}@`)
)
return plugin === PLUGIN_NAME || plugin.startsWith(`${PLUGIN_NAME}@`) ||
plugin === LEGACY_PLUGIN_NAME || plugin.startsWith(`${LEGACY_PLUGIN_NAME}@`)
}
export function detectCurrentConfig(): DetectedConfig {

View File

@@ -15,7 +15,7 @@ describe("detectCurrentConfig - single package detection", () => {
beforeEach(() => {
testConfigDir = join(tmpdir(), `omo-detect-config-${Date.now()}-${Math.random().toString(36).slice(2)}`)
testConfigPath = join(testConfigDir, "opencode.json")
testOmoConfigPath = join(testConfigDir, "oh-my-openagent.json")
testOmoConfigPath = join(testConfigDir, "oh-my-opencode.json")
mkdirSync(testConfigDir, { recursive: true })
process.env.OPENCODE_CONFIG_DIR = testConfigDir
@@ -28,31 +28,7 @@ describe("detectCurrentConfig - single package detection", () => {
delete process.env.OPENCODE_CONFIG_DIR
})
it("detects oh-my-openagent in plugin array", () => {
// given
const config = { plugin: ["oh-my-openagent"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
// when
const result = detectCurrentConfig()
// then
expect(result.isInstalled).toBe(true)
})
it("detects oh-my-openagent with version pin", () => {
// given
const config = { plugin: ["oh-my-openagent@3.11.0"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
// when
const result = detectCurrentConfig()
// then
expect(result.isInstalled).toBe(true)
})
it("detects oh-my-opencode as installed (legacy name)", () => {
it("detects oh-my-opencode in plugin array", () => {
// given
const config = { plugin: ["oh-my-opencode"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
@@ -64,7 +40,7 @@ describe("detectCurrentConfig - single package detection", () => {
expect(result.isInstalled).toBe(true)
})
it("detects oh-my-opencode with version pin as installed (legacy name)", () => {
it("detects oh-my-opencode with version pin", () => {
// given
const config = { plugin: ["oh-my-opencode@3.11.0"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
@@ -76,6 +52,30 @@ describe("detectCurrentConfig - single package detection", () => {
expect(result.isInstalled).toBe(true)
})
it("detects oh-my-openagent as installed (legacy name)", () => {
// given
const config = { plugin: ["oh-my-openagent"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
// when
const result = detectCurrentConfig()
// then
expect(result.isInstalled).toBe(true)
})
it("detects oh-my-openagent with version pin as installed (legacy name)", () => {
// given
const config = { plugin: ["oh-my-openagent@3.11.0"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
// when
const result = detectCurrentConfig()
// then
expect(result.isInstalled).toBe(true)
})
it("returns false when plugin not present", () => {
// given
const config = { plugin: ["some-other-plugin"] }
@@ -89,7 +89,7 @@ describe("detectCurrentConfig - single package detection", () => {
})
it("returns false when plugin not present (even with similar name)", () => {
// given
// given - not exactly oh-my-openagent
const config = { plugin: ["oh-my-openagent-extra"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
@@ -102,7 +102,7 @@ describe("detectCurrentConfig - single package detection", () => {
it("detects OpenCode Go from the existing omo config", () => {
// given
writeFileSync(testConfigPath, JSON.stringify({ plugin: ["oh-my-openagent"] }, null, 2) + "\n", "utf-8")
writeFileSync(testConfigPath, JSON.stringify({ plugin: ["oh-my-opencode"] }, null, 2) + "\n", "utf-8")
writeFileSync(
testOmoConfigPath,
JSON.stringify({ agents: { atlas: { model: "opencode-go/kimi-k2.5" } } }, null, 2) + "\n",
@@ -137,36 +137,7 @@ describe("addPluginToOpenCodeConfig - single package writes", () => {
delete process.env.OPENCODE_CONFIG_DIR
})
it("keeps oh-my-openagent when it already exists", async () => {
// given
const config = { plugin: ["oh-my-openagent"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
// when
const result = await addPluginToOpenCodeConfig("3.11.0")
// then
expect(result.success).toBe(true)
const savedConfig = JSON.parse(readFileSync(testConfigPath, "utf-8"))
expect(savedConfig.plugin).toContain("oh-my-openagent")
})
it("replaces version-pinned oh-my-openagent@X.Y.Z", async () => {
// given
const config = { plugin: ["oh-my-openagent@3.10.0"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
// when
const result = await addPluginToOpenCodeConfig("3.11.0")
// then
expect(result.success).toBe(true)
const savedConfig = JSON.parse(readFileSync(testConfigPath, "utf-8"))
expect(savedConfig.plugin).toContain("oh-my-openagent")
expect(savedConfig.plugin).not.toContain("oh-my-openagent@3.10.0")
})
it("recognizes oh-my-opencode as already installed (legacy name)", async () => {
it("keeps oh-my-opencode when it already exists", async () => {
// given
const config = { plugin: ["oh-my-opencode"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
@@ -177,12 +148,10 @@ describe("addPluginToOpenCodeConfig - single package writes", () => {
// then
expect(result.success).toBe(true)
const savedConfig = JSON.parse(readFileSync(testConfigPath, "utf-8"))
// Should upgrade to new name
expect(savedConfig.plugin).toContain("oh-my-openagent")
expect(savedConfig.plugin).not.toContain("oh-my-opencode")
expect(savedConfig.plugin).toContain("oh-my-opencode")
})
it("replaces version-pinned oh-my-opencode@X.Y.Z with new name", async () => {
it("replaces version-pinned oh-my-opencode@X.Y.Z", async () => {
// given
const config = { plugin: ["oh-my-opencode@3.10.0"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
@@ -190,12 +159,43 @@ describe("addPluginToOpenCodeConfig - single package writes", () => {
// when
const result = await addPluginToOpenCodeConfig("3.11.0")
// then
expect(result.success).toBe(true)
const savedConfig = JSON.parse(readFileSync(testConfigPath, "utf-8"))
expect(savedConfig.plugin).toContain("oh-my-opencode")
expect(savedConfig.plugin).not.toContain("oh-my-opencode@3.10.0")
})
it("recognizes oh-my-openagent as already installed (legacy name)", async () => {
// given
const config = { plugin: ["oh-my-openagent"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
// when
const result = await addPluginToOpenCodeConfig("3.11.0")
// then
expect(result.success).toBe(true)
const savedConfig = JSON.parse(readFileSync(testConfigPath, "utf-8"))
// Should upgrade to new name
expect(savedConfig.plugin).toContain("oh-my-opencode")
expect(savedConfig.plugin).not.toContain("oh-my-openagent")
})
it("replaces version-pinned oh-my-openagent@X.Y.Z with new name", async () => {
// given
const config = { plugin: ["oh-my-openagent@3.10.0"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
// when
const result = await addPluginToOpenCodeConfig("3.11.0")
// then
expect(result.success).toBe(true)
const savedConfig = JSON.parse(readFileSync(testConfigPath, "utf-8"))
// Legacy should be replaced with new name
expect(savedConfig.plugin).toContain("oh-my-openagent")
expect(savedConfig.plugin).not.toContain("oh-my-opencode")
expect(savedConfig.plugin).toContain("oh-my-opencode")
expect(savedConfig.plugin).not.toContain("oh-my-openagent")
})
it("adds new plugin when none exists", async () => {
@@ -209,7 +209,7 @@ describe("addPluginToOpenCodeConfig - single package writes", () => {
// then
expect(result.success).toBe(true)
const savedConfig = JSON.parse(readFileSync(testConfigPath, "utf-8"))
expect(savedConfig.plugin).toContain("oh-my-openagent")
expect(savedConfig.plugin).toContain("oh-my-opencode")
})
it("adds plugin when plugin array is empty", async () => {
@@ -223,6 +223,6 @@ describe("addPluginToOpenCodeConfig - single package writes", () => {
// then
expect(result.success).toBe(true)
const savedConfig = JSON.parse(readFileSync(testConfigPath, "utf-8"))
expect(savedConfig.plugin).toContain("oh-my-openagent")
expect(savedConfig.plugin).toContain("oh-my-opencode")
})
})

View File

@@ -1,7 +1,6 @@
import { PLUGIN_NAME } from "../../shared/plugin-identity"
import { fetchNpmDistTags } from "./npm-dist-tags"
const DEFAULT_PACKAGE_NAME = PLUGIN_NAME
const DEFAULT_PACKAGE_NAME = "oh-my-opencode"
const PRIORITIZED_TAGS = ["latest", "beta", "next"] as const
function getFallbackEntry(version: string, packageName: string): string {
@@ -19,6 +18,7 @@ export async function getPluginNameWithVersion(
): Promise<string> {
const distTags = await fetchNpmDistTags(packageName)
if (distTags) {
const allTags = new Set([...PRIORITIZED_TAGS, ...Object.keys(distTags)])
for (const tag of allTags) {

View File

@@ -34,7 +34,7 @@ describe("writeOmoConfig", () => {
beforeEach(() => {
testConfigDir = join(tmpdir(), `omo-write-config-${Date.now()}-${Math.random().toString(36).slice(2)}`)
testConfigPath = join(testConfigDir, "oh-my-openagent.json")
testConfigPath = join(testConfigDir, "oh-my-opencode.json")
mkdirSync(testConfigDir, { recursive: true })
process.env.OPENCODE_CONFIG_DIR = testConfigDir

View File

@@ -61,7 +61,7 @@ export function writeOmoConfig(installConfig: InstallConfig): ConfigMergeResult
return {
success: false,
configPath: omoConfigPath,
error: formatErrorWithSuggestion(err, "write oh-my-openagent config")
error: formatErrorWithSuggestion(err, "write oh-my-opencode config"),
}
}
}

View File

@@ -1,20 +1,16 @@
import { readFileSync } from "node:fs"
import { join } from "node:path"
import { OhMyOpenAgentConfigSchema } from "../../../config"
import { detectConfigFile, getOpenCodeConfigDir, parseJsonc } from "../../../shared"
import { CHECK_IDS, CHECK_NAMES, PACKAGE_NAMES } from "../constants"
import { OhMyOpenCodeConfigSchema } from "../../../config"
import { detectPluginConfigFile, getOpenCodeConfigDir, parseJsonc } from "../../../shared"
import { CHECK_IDS, CHECK_NAMES, PACKAGE_NAME } from "../constants"
import type { CheckResult, DoctorIssue } from "../types"
import { loadAvailableModelsFromCache } from "./model-resolution-cache"
import { getModelResolutionInfoWithOverrides } from "./model-resolution"
import type { OmoConfig } from "./model-resolution-types"
const USER_CONFIG_BASES = PACKAGE_NAMES.map((packageName) =>
join(getOpenCodeConfigDir({ binary: "opencode" }), packageName)
)
const PROJECT_CONFIG_BASES = PACKAGE_NAMES.map((packageName) =>
join(process.cwd(), ".opencode", packageName)
)
const USER_CONFIG_DIR = getOpenCodeConfigDir({ binary: "opencode" })
const PROJECT_CONFIG_DIR = join(process.cwd(), ".opencode")
interface ConfigValidationResult {
exists: boolean
@@ -25,15 +21,11 @@ interface ConfigValidationResult {
}
function findConfigPath(): string | null {
for (const projectConfigBase of PROJECT_CONFIG_BASES) {
const projectConfig = detectConfigFile(projectConfigBase)
if (projectConfig.format !== "none") return projectConfig.path
}
const projectConfig = detectPluginConfigFile(PROJECT_CONFIG_DIR)
if (projectConfig.format !== "none") return projectConfig.path
for (const userConfigBase of USER_CONFIG_BASES) {
const userConfig = detectConfigFile(userConfigBase)
if (userConfig.format !== "none") return userConfig.path
}
const userConfig = detectPluginConfigFile(USER_CONFIG_DIR)
if (userConfig.format !== "none") return userConfig.path
return null
}
@@ -47,7 +39,7 @@ function validateConfig(): ConfigValidationResult {
try {
const content = readFileSync(configPath, "utf-8")
const rawConfig = parseJsonc<OmoConfig>(content)
const schemaResult = OhMyOpenAgentConfigSchema.safeParse(rawConfig)
const schemaResult = OhMyOpenCodeConfigSchema.safeParse(rawConfig)
if (!schemaResult.success) {
return {

View File

@@ -1,44 +1,29 @@
import {
CONFIG_BASENAME,
LEGACY_CONFIG_BASENAME,
} from "../../../shared/plugin-identity"
import { readFileSync } from "node:fs"
import { join } from "node:path"
import { detectConfigFile, getOpenCodeConfigPaths, parseJsonc } from "../../../shared"
import { detectPluginConfigFile, getOpenCodeConfigPaths, parseJsonc } from "../../../shared"
import type { OmoConfig } from "./model-resolution-types"
const USER_CONFIG_BASES = [
join(getOpenCodeConfigPaths({ binary: "opencode", version: null }).configDir, CONFIG_BASENAME),
join(getOpenCodeConfigPaths({ binary: "opencode", version: null }).configDir, LEGACY_CONFIG_BASENAME),
] as const
const PROJECT_CONFIG_BASES = [
join(process.cwd(), ".opencode", CONFIG_BASENAME),
join(process.cwd(), ".opencode", LEGACY_CONFIG_BASENAME),
] as const
const USER_CONFIG_DIR = getOpenCodeConfigPaths({ binary: "opencode", version: null }).configDir
const PROJECT_CONFIG_DIR = join(process.cwd(), ".opencode")
export function loadOmoConfig(): OmoConfig | null {
for (const projectConfigBase of PROJECT_CONFIG_BASES) {
const projectDetected = detectConfigFile(projectConfigBase)
if (projectDetected.format !== "none") {
try {
const content = readFileSync(projectDetected.path, "utf-8")
return parseJsonc<OmoConfig>(content)
} catch {
return null
}
const projectDetected = detectPluginConfigFile(PROJECT_CONFIG_DIR)
if (projectDetected.format !== "none") {
try {
const content = readFileSync(projectDetected.path, "utf-8")
return parseJsonc<OmoConfig>(content)
} catch {
return null
}
}
for (const userConfigBase of USER_CONFIG_BASES) {
const userDetected = detectConfigFile(userConfigBase)
if (userDetected.format !== "none") {
try {
const content = readFileSync(userDetected.path, "utf-8")
return parseJsonc<OmoConfig>(content)
} catch {
return null
}
const userDetected = detectPluginConfigFile(USER_CONFIG_DIR)
if (userDetected.format !== "none") {
try {
const content = readFileSync(userDetected.path, "utf-8")
return parseJsonc<OmoConfig>(content)
} catch {
return null
}
}

View File

@@ -32,7 +32,7 @@ describe("model-resolution check", () => {
})
describe("getModelResolutionInfoWithOverrides", () => {
// given: User has overrides in oh-my-openagent.json
// given: User has overrides in oh-my-opencode.json
// when: Getting resolution info with config
// then: Shows user override in Step 1 position

View File

@@ -4,7 +4,7 @@ import { join } from "node:path"
import { getLatestVersion } from "../../../hooks/auto-update-checker/checker"
import { extractChannel } from "../../../hooks/auto-update-checker"
import { PACKAGE_NAME, PACKAGE_NAMES } from "../constants"
import { PACKAGE_NAME } from "../constants"
import { getOpenCodeCacheDir, getOpenCodeConfigPaths, parseJsonc } from "../../../shared"
interface PackageJsonShape {
@@ -12,18 +12,6 @@ interface PackageJsonShape {
dependencies?: Record<string, string>
}
interface CandidateLocation {
cacheDir: string
cachePackagePath: string
nodeModulesDir: string
}
interface CandidateSelection {
cacheDir: string
cachePackagePath: string
installedPackagePath: string
}
export interface LoadedVersionInfo {
cacheDir: string
cachePackagePath: string
@@ -68,44 +56,27 @@ function normalizeVersion(value: string | undefined): string | null {
export function getLoadedPluginVersion(): LoadedVersionInfo {
const configPaths = getOpenCodeConfigPaths({ binary: "opencode" })
const cacheDir = resolveOpenCodeCacheDir()
const candidates: CandidateLocation[] = [
const candidates = [
{
cacheDir: configPaths.configDir,
cachePackagePath: configPaths.packageJson,
nodeModulesDir: join(configPaths.configDir, "node_modules"),
installedPackagePath: join(configPaths.configDir, "node_modules", PACKAGE_NAME, "package.json"),
},
{
cacheDir,
cachePackagePath: join(cacheDir, "package.json"),
nodeModulesDir: join(cacheDir, "node_modules"),
installedPackagePath: join(cacheDir, "node_modules", PACKAGE_NAME, "package.json"),
},
]
const resolvedCandidates: CandidateSelection[] = candidates.map((candidate) => {
const installedPackagePath =
PACKAGE_NAMES.map((packageName) => join(candidate.nodeModulesDir, packageName, "package.json")).find((path) =>
existsSync(path)
) ?? join(candidate.nodeModulesDir, PACKAGE_NAME, "package.json")
return {
cacheDir: candidate.cacheDir,
cachePackagePath: candidate.cachePackagePath,
installedPackagePath,
}
})
const selectedCandidate = resolvedCandidates.find((candidate) => existsSync(candidate.installedPackagePath)) ?? resolvedCandidates[0]
const selectedCandidate = candidates.find((candidate) => existsSync(candidate.installedPackagePath)) ?? candidates[0]
const { cacheDir: selectedDir, cachePackagePath, installedPackagePath } = selectedCandidate
const cachePackage = readPackageJson(cachePackagePath)
const installedPackage = readPackageJson(installedPackagePath)
const expectedVersion = normalizeVersion(
PACKAGE_NAMES.map((packageName) => cachePackage?.dependencies?.[packageName]).find(
(version): version is string => typeof version === "string"
)
)
const expectedVersion = normalizeVersion(cachePackage?.dependencies?.[PACKAGE_NAME])
const loadedVersion = normalizeVersion(installedPackage?.version)
return {

View File

@@ -5,7 +5,7 @@ const mockGetOpenCodeVersion = mock(async () => "1.0.200")
const mockCompareVersions = mock(() => true)
const mockGetPluginInfo = mock(() => ({
registered: true,
entry: "oh-my-openagent",
entry: "oh-my-opencode",
isPinned: false,
pinnedVersion: null,
configPath: null,
@@ -14,7 +14,7 @@ const mockGetPluginInfo = mock(() => ({
const mockGetLoadedPluginVersion = mock(() => ({
cacheDir: "/Users/test/Library/Caches/opencode with spaces",
cachePackagePath: "/tmp/package.json",
installedPackagePath: "/tmp/node_modules/oh-my-openagent/package.json",
installedPackagePath: "/tmp/node_modules/oh-my-opencode/package.json",
expectedVersion: "3.0.0",
loadedVersion: "3.1.0",
}))
@@ -51,7 +51,7 @@ describe("system check", () => {
mockCompareVersions.mockReturnValue(true)
mockGetPluginInfo.mockReturnValue({
registered: true,
entry: "oh-my-openagent",
entry: "oh-my-opencode",
isPinned: false,
pinnedVersion: null,
configPath: null,
@@ -60,7 +60,7 @@ describe("system check", () => {
mockGetLoadedPluginVersion.mockReturnValue({
cacheDir: "/Users/test/Library/Caches/opencode with spaces",
cachePackagePath: "/tmp/package.json",
installedPackagePath: "/tmp/node_modules/oh-my-openagent/package.json",
installedPackagePath: "/tmp/node_modules/oh-my-opencode/package.json",
expectedVersion: "3.0.0",
loadedVersion: "3.1.0",
})
@@ -82,7 +82,7 @@ describe("system check", () => {
mockGetLoadedPluginVersion.mockReturnValue({
cacheDir: "/Users/test/Library/Caches/opencode with spaces",
cachePackagePath: "/tmp/package.json",
installedPackagePath: "/tmp/node_modules/oh-my-openagent/package.json",
installedPackagePath: "/tmp/node_modules/oh-my-opencode/package.json",
expectedVersion: "3.0.0-canary.1",
loadedVersion: "3.0.0-canary.1",
})
@@ -97,7 +97,7 @@ describe("system check", () => {
//#then
const outdatedIssue = result.issues.find((issue) => issue.title === "Loaded plugin is outdated")
expect(outdatedIssue?.fix).toBe(
'Update: cd "/Users/test/Library/Caches/opencode with spaces" && bun add oh-my-openagent@canary'
'Update: cd "/Users/test/Library/Caches/opencode with spaces" && bun add oh-my-opencode@canary'
)
})
})

View File

@@ -82,9 +82,9 @@ export async function checkSystem(): Promise<CheckResult> {
if (!pluginInfo.registered) {
issues.push({
title: "oh-my-openagent is not registered",
title: "oh-my-opencode is not registered",
description: "Plugin entry is missing from OpenCode configuration.",
fix: "Run: bunx oh-my-openagent install",
fix: "Run: bunx oh-my-opencode install",
severity: "error",
affects: ["all agents"],
})
@@ -108,7 +108,7 @@ export async function checkSystem(): Promise<CheckResult> {
issues.push({
title: "Loaded plugin is outdated",
description: `Loaded ${systemInfo.loadedVersion}, latest ${latestVersion}.`,
fix: `Update: cd "${loadedInfo.cacheDir}" && bun add oh-my-openagent@${installTag}`,
fix: `Update: cd "${loadedInfo.cacheDir}" && bun add oh-my-opencode@${installTag}`,
severity: "warning",
affects: ["plugin features"],
})

View File

@@ -1,4 +1,3 @@
import { LEGACY_PLUGIN_NAME, PLUGIN_NAME } from "../../shared/plugin-identity"
import color from "picocolors"
export const SYMBOLS = {
@@ -39,7 +38,6 @@ export const EXIT_CODES = {
export const MIN_OPENCODE_VERSION = "1.0.150"
export const PACKAGE_NAME = PLUGIN_NAME
export const PACKAGE_NAMES = [PLUGIN_NAME, LEGACY_PLUGIN_NAME] as const
export const PACKAGE_NAME = "oh-my-opencode"
export const OPENCODE_BINARIES = ["opencode", "opencode-desktop"] as const

Some files were not shown because too many files have changed in this diff Show More