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
The bundled createTodoDescriptionOverrideHook returns { 'tool.definition': fn }, but plugin-interface.ts never exposes 'tool.definition' as an OpenCode hook handler. Result: the hook is constructed by createToolGuardHooks (line 132-134 of src/plugin/hooks/create-tool-guard-hooks.ts) but the function is never invoked, so todowrite keeps using OpenCode's core 7 KB description instead of the 1.4 KB TODOWRITE_DESCRIPTION. User-defined plugins under ~/.config/opencode/plugin/*.js use the same hook contract and work fine, confirming the contract itself is functional in opencode 1.14.28+.
Fix: add src/plugin/tool-definition.ts (createToolDefinitionHandler) that forwards the OpenCode 'tool.definition' input/output pair into hooks.todoDescriptionOverride. Wire it into plugin-interface.ts alongside tool.execute.before/after.
Regression coverage: src/plugin/tool-definition.test.ts covers (a) todowrite override applied, (b) other tools left untouched, (c) null hook is a no-op.
After the 4.2.0 unified-dispatch refactor (a42f894f / df198d8b / fee515c5 / 989ab717 / dd3fecaf / 1bbe065c / 12bd6580), at least one caller in the new prompt-async-gate path forwards a FallbackModelObject (or some other non-string shape) into parsers that statically claim 'model: string'. The downstream .trim() call then throws 'model.trim is not a function', which rejects the session.processor promise and surfaces as 'Aborted process' + UI 'interrupted'. The issue (#4145) reports this aborts 90% of subagent dispatches across every provider on 4.2.0 + opencode 1.15.4.
This patch adds a 'typeof x !== "string"' runtime guard at the four parser entrypoints called from the dispatch path:
- src/shared/fallback-chain-from-models.ts :: parseVariantFromModel, parseFallbackModelEntry
- src/tools/delegate-task/model-string-parser.ts :: parseVariantFromModelID, parseModelString
- src/shared/model-string-parser.ts (duplicate file with same API) :: parseVariantFromModelID, parseModelString
- src/features/claude-code-agent-loader/claude-model-mapper.ts :: mapClaudeModelString
Each parser now returns undefined / { modelID: "" } for non-string input instead of throwing. This unblocks subagent dispatch and leaves the underlying caller bug for a follow-up.
Regression coverage: three new tests in src/shared/fallback-chain-from-models.test.ts pin the non-string behavior (object, null/undefined, number). Existing 38 tests still pass. Total: 41/41 green, typecheck clean.
Skills with an `agent` frontmatter field are intended for a specific
agent. Previously they still appeared in:
- every agent's system prompt (via `buildAvailableSkills`)
- the `skill` tool's `<available_items>` description visible to all agents
This wasted tokens and could mislead agents into attempting calls that
would be rejected at execution time.
Changes:
- `buildAvailableSkills`: new optional `agentName` parameter; when
provided, skills whose `definition.agent` does not match are excluded
- `builtin-agents.ts`: pass per-agent name to `buildAvailableSkills`
for sisyphus, hephaestus, and atlas, so each agent's prompt only
lists the skills it is allowed to use
- `createSkillTool` (`tools.ts`): exclude agent-restricted skills from
both the eager and lazy description builds, keeping the shared tool
description free of skills the current agent cannot access
Execution-time enforcement (throwing on mismatch) is unchanged; this
change adds the earlier, description-level visibility gate.
Tests: new `available-skills.test.ts` (5 cases) + 3 new cases in
`tools.test.ts` covering the description-filter and execute paths.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
When OpenCode reports the original assistant error after a fallback retry has already been accepted, keep waiting for the pending fallback model instead of clearing the awaiting flag.
This prevents a duplicate stale session.error from advancing the fallback chain and dispatching a second assistant retry prompt.
Oracle review on PR #4132 flagged that resetStallStateForPlanChange only
reset state when stalledContinuationReason was already set, so partial
in-progress counts from plan A could carry to plan B and abort the new
plan on its first idle.
Adds activeContinuationPlanPath to SessionState and resets the
no-tool-progress counter + awaiting state whenever the active plan path
changes, even when no stall has occurred yet. The existing stalled-plan
reset still fires when the previously stalled plan path differs from
the new one.
Background fallback retry notifications were queued as bare internal user messages, so OpenCode could treat the notification as a new default-agent turn. Reuse the same parent prompt context resolver used by completion notifications for retrying and retry-ready wakes, and pin regression coverage for Hephaestus parent sessions plus missing-context fallbacks.
buildShellAwareGitPrefix incorrectly returned raw bash VAR=value prefix for csh, which does not support inline env assignment. Now routes csh through buildEnvPrefix() to emit setenv syntax. Also sets code block lang to csh and skips bash block regex prefixing for csh.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Mirrors the agent-config-handler change: command-config-handler now also discovers skills from host config.skills.paths set by other plugins, making them available as slash commands.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
When another plugin (e.g. superpowers) injects skill directories via config.skills.paths in the config hook, the agent-config-handler now discovers those skills via a second discoverConfigSourceSkills call using the adapted host config. Fixes#3396.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Converts the host OpenCode config.skills object (with paths/urls arrays set by other plugins like superpowers) into the SkillsConfig format used by discoverConfigSourceSkills. Filters blank/whitespace entries and non-string values.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
The previous code read params.config.default_agent which is always populated to
"Sisyphus - Ultraworker" by existing logic (lines 196-204) even when the user
never configured default_agent. This silently overrode any custom agent_order.
Now we gate on configuredDefaultAgent (the user's explicit value) so the sort
shim rank map is only mutated when the user actually set default_agent.
Add regression test: agent_order without default_agent must preserve order.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>