- Add src/locales/ with en baseline and zh overrides (Partial<Record> fallback)
- Add src/shared/i18n.ts with initI18n/t/setLocale/getLocale (LANG env auto-detect)
- Add I18nConfigSchema with locale field to plugin config
- Internationalize 13 hardcoded strings in task-toast-manager
- Add 18 unit tests for i18n module
- Pin manager tests to en locale for determinism
When all plugin hooks are removed (user disables/uninstalls plugins),
hooksConfigs becomes an empty array. The previous guard
(hooksConfigs.length > 0) skipped setPluginHooksConfigs(), leaving
stale plugin hooks active in pendingPluginHooksConfigs. Now we always
call setPluginHooksConfigs() so empty configs properly clear the
pending state and invalidate the cache.
Previously, loadPluginHooksConfigs() loaded plugin hooks from marketplace
plugins (hookify, superpowers, zzcommon, zzfe, etc.) into
pluginComponents.hooksConfigs, but config-handler.ts never consumed them.
This meant plugin hooks were discovered but never merged into the runtime
hooks dispatch system.
Changes:
- Extend ClaudeHookEvent and ClaudeHooksConfig to support all 12 event
types (PostToolUseFailure, PermissionRequest, Notification,
SubagentStart, SubagentStop, SessionStart, SessionEnd) in addition to
the existing 5
- Add ALL_HOOK_EVENT_TYPES constant as single source of truth for event
type iteration
- Add mergePluginHooksConfigs() to unwrap plugin HooksConfig (with hooks
wrapper) into flat ClaudeHooksConfig, filtering out unsupported
prompt/agent hook types
- Add setPluginHooksConfigs() to store pending plugin configs and
invalidate the config cache
- Create applyHookConfig() handler following existing applyXxxConfig
pattern, wired into config-handler after loadPluginComponents()
- Extend DisabledHooksConfig and mergeDisabledHooks for all 12 events
Closes#4179
Include Vertex Anthropic in the assistant-tail prefill guard after Cubic flagged the strict provider check. Keep the non-Anthropic opencode negative control covered by tests.
Plan: plans/fix-anthropic-assistant-prefill-tail.md
Tighten the assistant-tail repair after review so only the Anthropic provider is treated as prefill-rejecting, and so assistant-tail model metadata is evaluated independently from the last user model.
Add regression coverage for an allowed user model followed by a rejecting Anthropic assistant tail, plus a non-Anthropic provider carrying a Claude-looking model id.
Plan: plans/fix-anthropic-assistant-prefill-tail.md
Claude Opus 4.7 rejects requests whose final message is an assistant turn, because Anthropic treats that as unsupported assistant prefill. Add a transform guard that appends the existing synthetic user recovery turn only for Anthropic prefill-rejecting model IDs, while preserving assistant-prefill behavior for supported and unknown models.
Tests cover Opus 4.7, Opus 4.6 assistant metadata fallback, direct Sonnet 4.6 model fields, allowed OpenAI/Sonnet 4.5 tails, missing metadata, and compaction continuation compatibility.
Plan: plans/fix-anthropic-assistant-prefill-tail.md
Discord support and other guidance still tell users 'bunx oh-my-opencode setup', but the CLI only registers 'install'. Running the recommended command produces:
error: unknown command 'setup'
which dead-ends users who are trying to refresh missing skills (hyperplan, etc.) after upgrading. Commander.js supports first-class aliases, so declaring '.alias("setup")' on the install command makes both names route to the same action without any code duplication. Help output now reads 'Usage: oh-my-opencode install|setup [options]', which is the right discovery hint for both newcomers and users following older docs.
Regression test parses cli-program.ts and asserts the install command block contains '.alias("setup")' before its '.action(' so a future refactor of the CLI cannot silently drop the alias.
- Add focused ROADMAP with TOC and clear priorities
- Pin package layering refactor as #1 urgent work
- Add multi-harness agent OS notice to all language READMEs
- Add ROADMAP section to root README with contributor guidance
- All ROADMAP-related PRs should use the ROADMAP label
ensureBaseDirs unconditionally called chmod(baseDir, 0o700) on every startup
and on every team_create. On filesystems where the OS rejects chmod for the
directory (network mounts, SIP-protected locations, non-owner cases on macOS
shared by multiple GUI users), the call raises EPERM and the entire team-mode
init aborts:
[team-mode] init failed: EPERM: operation not permitted, chmod '/Users/<u>/.omo'
Wrap chmod through a small safeChmod helper that converts EPERM, ENOTSUP, and
EINVAL into a single warning log and continues. mkdir already creates new
directories with mode 0o700, and the existing post-creation stat-guard remains
in place for the case where the directory pre-exists with a different mode and
chmod is permitted, so the security envelope on supported filesystems is
unchanged. All other error codes (ENOENT, EACCES, etc.) still propagate.
Regression test mocks node:fs/promises.chmod to throw EPERM and asserts that
ensureBaseDirs completes successfully and emits exactly the documented warning.
The multimodal-looker prompt described what to do but never told the model which tools are available. Smaller VL models (e.g. Qwen3-VL-8B) would try to call non-existent tools and enter an infinite loop emitting:
Model tried to call unavailable tool 'invalid'. Available tools: call_omo_agent, read.
Add a single sentence at the top of the prompt that explicitly enumerates the only allowed tools ('read' and 'call_omo_agent') and forbids calling any other tool. This matches the runtime allowlist enforced by createAgentToolAllowlist(["read"]).
Regression test asserts the prompt contains the available-tools enumeration so future prompt rewrites don't regress.
Require the latest assistant tool-wait turn itself to be stale before a shouldReply parent wake can bypass tool-call deferral. This prevents an all-complete background wake from forking a second parent prompt loop when OpenCode has repaired the tail to a synthetic user message.
Tests:
- bun test src/features/background-agent/parent-wake-user-message-race.test.ts src/features/background-agent/task-completion-cleanup.test.ts src/hooks/shared/prompt-async-gate.test.ts src/shared/prompt-async-route-audit.test.ts --bail
- bun run typecheck
- bun test
Keep the built-in lsp MCP registered even when the submodule CLI artifact is missing.
The fallback command initializes the lsp-tools-mcp submodule, prefers the source CLI without dirtying the checkout with dist output, and keeps npm build as a last resort when Bun cannot run the source entrypoint.
Plan: plans/fix-lsp-mcp-missing-cli.md