Previously decoded entire image buffer to read headers. Now slices base64
to 32KB prefix before decoding — sufficient for PNG/GIF/WebP/JPEG headers.
Dramatically reduces memory allocation for large images.
Intercepts Read tool output with image attachments and resizes to comply with Anthropic API limits (≤1568px long edge, ≤5MB). Only activates for Anthropic provider sessions and appends resize metadata (original/new resolution, token count) to tool output.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
- Replace two-pass env interpolation with single-pass combined regex to
prevent re-interpolation of $-sequences in substituted header values
- Convert HookEntry to discriminated union so type: "http" requires url,
preventing invalid configs from passing type checking
- Add regression test for double-interpolation edge case
Add type: "http" hook support matching Claude Code's HTTP hook specification.
HTTP hooks send POST requests with JSON body, support env var interpolation
in headers via allowedEnvVars, and configurable timeout.
New files:
- execute-http-hook.ts: HTTP hook execution with env var interpolation
- dispatch-hook.ts: Unified dispatcher for command and HTTP hooks
- execute-http-hook.test.ts: 14 tests covering all HTTP hook scenarios
Modified files:
- types.ts: Added HookHttp interface, HookAction union type
- config.ts: Updated to accept HookAction in raw hook matchers
- pre-tool-use/post-tool-use/stop/user-prompt-submit/pre-compact:
Updated all 5 executors to dispatch HTTP hooks via dispatchHook()
- plugin-loader/types.ts: Added "http" to HookEntry type union
Prefer the in-memory session agent set by /start-work when validating idle continuation eligibility, so stale message storage agent values do not block boulder continuation.
Drop provider-specific thinking config injection (THINKING_CONFIGS, getThinkingConfig,
resolveProvider) and instead rely on the provider to handle thinking based on the variant field.
Hook now fires on chat.message using model from input rather than from the message object.
🤖 Generated with assistance of [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
When a background task completes and the parent session is waiting for
user input, promptAsync() fails with an aborted error. Previously the
notification was silently dropped — lost forever.
Fix: queue the notification text in-memory on the BackgroundManager
when promptAsync fails with an aborted/idle error. On the user's next
message to that session, the queued notifications are injected into the
chat context before the agent sees the message.
- BackgroundManager: add pendingNotifications map + queuePendingNotification()
and injectPendingNotificationsIntoChatMessage() methods
- background-notification hook: add chat.message handler that calls injection
- chat-message.ts: wire backgroundNotificationHook.chat.message into the
message processing chain
- Add tests covering queue-on-abort and next-message delivery
- Rename test to 'should inject when last agent is sisyphus and boulder targets atlas
explicitly' and flip expectation to toHaveBeenCalled() - the old assertion was
testing the buggy deadlock behavior
- Add 'should not inject when last agent is non-sisyphus and does not match boulder
agent' to verify hephaestus (unrelated agents) are still correctly skipped
The boulder continuation in event-handler.ts skipped injection whenever
the last agent was 'sisyphus' and the boulder state had agent='atlas'
set explicitly. The allowSisyphusWhenDefaultAtlas guard required
boulderAgentWasNotExplicitlySet=true, but start-work-hook.ts always
calls createBoulderState(..., 'atlas') which sets the agent explicitly.
This created a chicken-and-egg deadlock: boulder continuation needs
atlas to be the last agent, but the continuation itself is what switches
to atlas. With /start-work, the first iteration was always blocked.
Fix: drop the boulderAgentWasNotExplicitlySet constraint so Sisyphus is
always allowed when the boulder targets atlas (whether explicit or default).
Also reduce todo-continuation-enforcer CONTINUATION_COOLDOWN_MS from
30s to 5s to match atlas hook cooldown and recover interruptions faster.
Use sender-module indirection and an optional main-session filter guard to keep notification assertions deterministic across concurrent test execution.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
- Replace regex /^([A-Za-z_]+)#.../ with indexOf-based prefix check to catch
line-ref#VK and line.ref#VK style inputs that were previously giving generic errors
- Extract parseLineRefWithHint helper to eliminate duplicated try-catch in
validateLineRef and validateLineRefs
- Restore idempotency guard in appendWriteHashlineOutput using new output format
- Add tests for LINE42 extraction, line-ref hint, line.ref hint, and guard behavior
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
- fix(hooks): skip todo continuation when agent has pending question (#1888)
Add pending-question-detection module that walks messages backwards
to detect unanswered question tool_use, preventing CONTINUATION_PROMPT
injection while awaiting user response.
- fix(config): allow custom agent names in disabled_agents (#1693)
Change disabled_agents schema from BuiltinAgentNameSchema to z.string()
and add filterDisabledAgents helper in agent-config-handler to filter
user, project, and plugin agents with case-insensitive matching.
- fix(agents): change primary agents mode to 'all' (#1891)
Update Sisyphus, Hephaestus, and Atlas agent modes from 'primary'
to 'all' so they are available for @mention routing and task()
delegation in addition to direct chat.
Replace full hashlined file content in write tool response with a simple
'File written successfully. N lines written.' summary to reduce context
bloat.
Change LINE#HASH:content format to LINE#HASH|content across the entire
codebase. The pipe separator is more visually distinct and avoids
conflicts with TypeScript colons in code content.
15 files updated: implementation, prompts, tests, and READMEs.
OpenCode updated its read tool output format — the <content> tag now shares
a line with the first content line (<content>1: content) with no newline.
The hook's exact indexOf('<content>') detection returned -1, causing all
read output to pass through unmodified (no hash anchors). This silently
disabled the entire hashline-edit workflow.
Fixes:
- Sub-bug 1: Use findIndex + startsWith instead of exact indexOf match
- Sub-bug 2: Extract inline content after <content> prefix as first line
- Sub-bug 3: Normalize open-tag line to bare tag in output (no duplicate)
Also adds backward compat for legacy <file> + 00001| pipe format.