Commit Graph

546 Commits

Author SHA1 Message Date
YeonGyu-Kim 804895b24a feat(storage): gate JSON write operations on OpenCode beta, document degraded features
- Gate session-recovery writes: injectTextPart, prependThinkingPart, replaceEmptyTextParts, stripThinkingParts

- Gate context-window-recovery writes: truncateToolResult

- Add isSqliteBackend() checks with log warnings

- Create beta-degraded-features.md documentation
2026-02-16 16:13:40 +09:00
YeonGyu-Kim e80211c1fd feat(context-window-recovery): gate JSON writes on OpenCode beta 2026-02-16 16:13:40 +09:00
YeonGyu-Kim 1d5920235f refactor(shared): consolidate 13+ getMessageDir copies into single shared function 2026-02-16 16:13:39 +09:00
YeonGyu-Kim ed098925b5 fix(todo): make Todo id field optional for OpenCode beta compatibility
- Make id field optional in all Todo interfaces (TodoInfo, Todo, TodoItem)
- Fix null-unsafe comparisons in todo-sync.ts to handle missing ids
- Add test case for todos without id field preservation
- All tests pass and typecheck clean
2026-02-16 16:13:39 +09:00
YeonGyu-Kim 4f976c27a1 Merge pull request #1878 from code-yeongyu/fix/1806-todo-enforcer-cooldown
fix: apply cooldown on injection failure and add max retry limit (#1806)
2026-02-16 15:42:24 +09:00
YeonGyu-Kim a747d0f253 fix: add post-max-failure recovery window for todo continuation 2026-02-16 15:27:00 +09:00
YeonGyu-Kim 0a2ec5d251 fix: apply cooldown on injection failure and cap retries 2026-02-16 15:00:41 +09:00
YeonGyu-Kim f734e9e600 fix: prevent duplicate compaction race and log preemptive failures 2026-02-16 14:58:59 +09:00
YeonGyu-Kim 75cfa966ec test(directory-readme-injector): use real files instead of fs module mocks 2026-02-14 22:06:57 +09:00
YeonGyu-Kim 98a9e29bd4 test(directory-agents-injector): use real files instead of fs module mocks 2026-02-14 22:06:52 +09:00
YeonGyu-Kim c569a58306 test(rules-injector): restore bun mocks after suite 2026-02-14 22:06:39 +09:00
YeonGyu-Kim f6b37ac45e test(atlas): reset session state instead of module mocking 2026-02-14 22:06:34 +09:00
YeonGyu-Kim 39e4cb2ec6 test(prometheus-md-only): avoid hook-message storage constant mocking 2026-02-14 22:06:28 +09:00
YeonGyu-Kim 9a1d228a36 test(todo-continuation-enforcer): stabilize fake timers 2026-02-14 22:06:18 +09:00
YeonGyu-Kim c2a8f360b5 Merge pull request #1832 from code-yeongyu/fix/issue-1691-antigravity-error
fix: resilient error parsing for non-standard providers
2026-02-14 15:01:14 +09:00
YeonGyu-Kim 022f60081b fix(parser): wrap parseAnthropicTokenLimitError in try/catch
Add outer try/catch to prevent crashes from non-standard error objects
returned by proxy providers (e.g., Antigravity). Add parser tests
covering edge cases: circular refs, non-object data fields, invalid
JSON in responseBody.
2026-02-14 14:58:06 +09:00
YeonGyu-Kim 83f1505c28 test(session-recovery): add tests for detect-error-type resilience
Add test coverage for detectErrorType and extractMessageIndex with
edge cases: circular references, non-standard proxy errors, null input.
Wrap both functions in try/catch to prevent crashes from malformed
error objects returned by non-standard providers like Antigravity.
2026-02-14 14:58:06 +09:00
YeonGyu-Kim 17255c14d8 fix(think-mode): disable thinking parameter for Z.ai GLM models
Z.ai GLM models don't support thinking/reasoning parameters.
Ensure these are omitted entirely to prevent empty responses.

Fixes #980

Community-reported-by: @iserifith
2026-02-14 14:58:02 +09:00
YeonGyu-Kim 119f314a47 Merge pull request #1817 from code-yeongyu/fix/todo-continuation-always-fire
fix(todo-continuation-enforcer): fire continuation for all sessions with incomplete todos
2026-02-14 11:43:10 +09:00
YeonGyu-Kim 156a106f92 Merge pull request #1750 from ojh102/fix/guard-non-string-tool-output
fix(hooks): guard against non-string tool output in afterToolResult hooks
2026-02-13 18:52:18 +09:00
YeonGyu-Kim db76a1a531 fix(todo-continuation-enforcer): fire continuation for all sessions with incomplete todos
Remove boulder session restriction (f84ef532) and stagnation cap (10a60854)
that prevented continuation from firing in regular sessions.

Changes:
- Remove boulder/subagent session gate in idle-event.ts — continuation now
  fires for ANY session with incomplete todos, as originally intended
- Remove stagnation cap (MAX_UNCHANGED_CYCLES) — agent must keep rolling
  the boulder until all todos are complete, no giving up after 3 attempts
- Remove lastTodoHash and unchangedCycles from SessionState type
- Keep 30s cooldown (CONTINUATION_COOLDOWN_MS) as safety net against
  re-injection loops
- Update tests: remove boulder gate tests, update stagnation test to verify
  continuous injection, update non-main-session test to verify injection

42 tests pass, typecheck and build clean.
2026-02-13 18:50:53 +09:00
YeonGyu-Kim 7e5d866875 Merge pull request #1787 from popododo0720/fix/memory-leak-session-messages-caching
fix: reduce session.messages() calls with event-based caching to prevent memory leaks
2026-02-13 18:44:00 +09:00
YeonGyu-Kim 5ef77cbbcf Merge pull request #1790 from raki-1203/fix/stop-hooks-early-return
fix: execute all Stop hooks instead of returning after first non-blocking result
2026-02-13 18:28:41 +09:00
YeonGyu-Kim 888e54fb9b feat(compaction): add delegated agent sessions section with resume directive
Adds §8 to compaction prompt instructing the LLM to preserve spawned agent
session IDs and resume them post-compaction instead of starting fresh.
Injects actual TaskHistory data when BackgroundManager is available.
2026-02-13 17:40:29 +09:00
YeonGyu-Kim d16073aa59 refactor: remove redundant subagent-question-blocker hook
Replace PreToolUse hook-based question tool blocking with the existing
tools parameter approach (tools: { question: false }) which physically
removes the tool from the LLM's toolset before inference.

The hook was redundant because every session.prompt() call already passes
question: false via the tools parameter. OpenCode converts this to a
PermissionNext deny rule and deletes the tool from the toolset, preventing
the LLM from even seeing it. The hook only fired after the LLM already
called the tool, wasting tokens.

Changes:
- Remove subagent-question-blocker hook invocation from PreToolUse chain
- Remove hook registration from create-session-hooks.ts
- Delete src/hooks/subagent-question-blocker/ directory (dead code)
- Remove hook from HookNameSchema and barrel export
- Fix sync-executor.ts missing question: false in tools parameter
- Add regression tests for both the removal and the tools parameter
2026-02-13 14:55:46 +09:00
YeonGyu-Kim 9c43e10055 perf(comment-checker): add hard process reap and global semaphore to prevent CPU runaway 2026-02-13 11:58:46 +09:00
YeonGyu-Kim 91d96765dc perf(todo-continuation): add cooldown and stagnation cap to prevent re-injection loops 2026-02-13 11:54:32 +09:00
YeonGyu-Kim d381305620 Merge pull request #1794 from solssak/fix/isGptModel-proxy-providers
Expand isGptModel to detect GPT models behind proxy providers
2026-02-13 11:52:59 +09:00
YeonGyu-Kim 68f184a7ea Merge branch 'perf/rules-injector-parse-cache' into dev 2026-02-13 11:47:56 +09:00
YeonGyu-Kim b99ba4f529 perf(rules-injector): add mtime-based parse cache and dirty-write gate 2026-02-13 11:46:45 +09:00
YeonGyu-Kim 06393ef1ae perf(directory-injectors): skip writeFileSync when no new paths injected 2026-02-13 11:44:07 +09:00
HyunJun CHOI 2fa94e8ef8 fix: detect GPT models behind proxy providers (litellm, ollama) in isGptModel
isGptModel only matched openai/ and github-copilot/gpt- prefixes, causing
models like litellm/gpt-5.2 to fall into the Claude code path. This
injected Claude-specific thinking config, which the opencode runtime
translated into a reasoningSummary API parameter — rejected by OpenAI.

Extract model name after provider prefix and match against GPT model
name patterns (gpt-*, o1, o3, o4).

Closes #1788

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-02-13 11:38:00 +09:00
raki-1203 f5679e388f fix: execute all Stop hooks instead of returning after first non-blocking result
Previously, executeStopHooks returned immediately after the first hook
that produced valid JSON stdout, even if it was non-blocking. This
prevented subsequent hooks from executing.

This was problematic when users had multiple Stop hooks (e.g.,
check-console-log.js + task-complete-notify.sh in settings.json),
because the first hook's stdout (which echoed stdin data as JSON)
caused an early return, silently skipping all remaining hooks.

Now only explicitly blocking results (exit code 2 or decision=block)
cause an early return, matching Claude Code's behavior of executing
all Stop hooks sequentially.

Closes #1707
2026-02-12 16:09:13 +09:00
popododo0720 e61a93faf8 fix: reduce session.messages() calls with event-based caching to prevent memory leaks
- Replace session.messages() fetch in context-window-monitor with message.updated event cache
- Replace session.messages() fetch in preemptive-compaction with message.updated event cache
- Add per-session transcript cache (5min TTL) to avoid full rebuild per tool call
- Remove session.messages() from background-agent polling (use event-based progress)
- Add TTL pruning to todo-continuation-enforcer session state Map
- Add setInterval.unref() to tool-input-cache cleanup timer

Fixes #1222
2026-02-12 11:38:11 +09:00
YeonGyu-Kim 454acf757c fix: use case-insensitive matching for prometheus agent detection in prometheus-md-only hook
The hook used exact string equality (agentName !== "prometheus") which fails
when display names like "Prometheus (Plan Builder)" are stored in session state.
Replace with case-insensitive substring matching via isPrometheusAgent() helper,
consistent with the pattern used in keyword-detector hook.

Closes #1764 (Bug 3)
2026-02-12 03:36:58 +09:00
YeonGyu-Kim 69494d7e5b fix: improve error message for marketplace plugin commands
- Detect namespaced commands (containing ':') from Claude marketplace plugins
- Provide clear error message explaining marketplace plugins are not supported
- Point users to .claude/commands/ as alternative for custom commands
- Fixes issue where /daplug:run-prompt gave ambiguous 'command not found'

Closes #1682
2026-02-12 03:05:55 +09:00
YeonGyu-Kim 8bcf9b893c Merge pull request #1754 from code-yeongyu/fix/issue-1745-auto-update-pin
fix: respect user-pinned plugin version, skip auto-update when explicitly pinned
2026-02-11 16:07:57 +09:00
YeonGyu-Kim f64a7112bf fix: guard output.output in tool after-hooks for MCP tools (#1720)
MCP tool responses can have undefined output.output, causing TypeError
crashes in tool.execute.after hooks.

Changes:
- comment-checker/hook.ts: guard output.output with ?? '' before toLowerCase()
- edit-error-recovery/hook.ts: guard output.output with ?? '' before toLowerCase()
- task-resume-info/hook.ts: extract output.output ?? '' into outputText before all string operations
- Added tests for undefined output.output in edit-error-recovery and task-resume-info
2026-02-11 15:49:56 +09:00
YeonGyu-Kim 688528cf99 fix: respect user-pinned plugin version, skip auto-update when explicitly pinned
When a user pins oh-my-opencode to a specific version (e.g., oh-my-opencode@3.4.0),
the auto-update checker now respects that choice and only shows a notification toast
instead of overwriting the pinned version with latest.

- Skip updatePinnedVersion() when pluginInfo.isPinned is true
- Show update-available toast only (notification, no modification)
- Added comprehensive tests for pinned/unpinned/autoUpdate scenarios

Fixes #1745
2026-02-11 15:39:15 +09:00
bob_karrot 2ec23dc7e1 fix(hooks): guard against non-string tool output in afterToolResult hooks
MCP tools can return non-string results (e.g. structured JSON objects).
When this happens, output.output is undefined, causing TypeError crashes
in edit-error-recovery and delegate-task-retry hooks that call methods
like .toLowerCase() without checking the type first.

Add typeof string guard in both hooks, consistent with the existing
pattern used in tool-output-truncator.
2026-02-11 14:23:37 +09:00
YeonGyu-Kim c611ea3d00 fix(auto-update): revert config pin on install failure to prevent version mismatch
When bun install fails after updating the config pin, the config now shows the
new version but the actual package is the old one. Add revertPinnedVersion() to
roll back the config entry on install failure, keeping config and installed
version in sync.

Ref #1472
2026-02-11 13:52:20 +09:00
YeonGyu-Kim 73c0fc9bb5 feat(atlas): add notepad reading step to boulder verification reminders
Instructs the orchestrator to read subagent notepad files
(.sisyphus/notepads/{planName}/) after task completion, ensuring
learnings, issues, and problems are propagated to subsequent delegations.
2026-02-11 13:52:20 +09:00
YeonGyu-Kim f7436903f0 fix: guard session_ids with optional chaining to prevent crash
boulderState?.session_ids.includes() only guards boulderState, not
session_ids. If boulder.json is corrupted or missing the field,
session_ids is undefined and .includes() crashes silently, losing
subagent results.

Changes:
- readBoulderState: validate parsed JSON is object, default session_ids to []
- atlas hook line 427: boulderState?.session_ids?.includes
- atlas hook line 655: boulderState?.session_ids?.includes
- prometheus-md-only line 93: boulderState?.session_ids?.includes
- appendSessionId: guard with ?. and initialize to [] if missing

Fixes #1672
2026-02-11 13:27:18 +09:00
YeonGyu-Kim 005f22f20b fix(atlas): await injectBoulderContinuation and handle errors
The async call was fire-and-forget with no error handling. Now properly
awaited with try/catch that logs failures and increments promptFailureCount.
2026-02-11 00:45:51 +09:00
YeonGyu-Kim 95db665ff5 fix(ralph-loop): only scan text parts for completion tags and handle both API shapes
Reasoning parts could contain completion-like text triggering false
positives. Also handles session.messages returning either an array
or {data: [...]} shape.
2026-02-11 00:45:51 +09:00
YeonGyu-Kim 623e456518 fix(atlas): correct plan path from .sisyphus/tasks/*.yaml to .sisyphus/plans/*.md
The verification reminder template was pointing at the wrong directory;
actual plan files are stored under .sisyphus/plans/ as markdown.
2026-02-11 00:45:51 +09:00
YeonGyu-Kim ae47ce3096 fix(comment-checker): add 30s hard timeout to CLI spawn
If the comment-checker binary hangs, Promise.race with a 30s timeout
kills the process and returns a safe fallback {hasComments: false}.
2026-02-11 00:45:51 +09:00
YeonGyu-Kim 254adcb05d fix(session-recovery): return success=false for assistant_prefill_unsupported
Returning true tricked the system into thinking recovery succeeded,
triggering auto-continue which hit the same error again in an infinite loop.
2026-02-11 00:45:51 +09:00
YeonGyu-Kim b16db15de1 fix(atlas): restrict boulder continuation to sessions in boulder session_ids
Main session was unconditionally allowed through the boulder session guard,
causing continuation injection into sessions not part of the active boulder.
Now only sessions explicitly in boulder's session_ids (or background tasks)
receive boulder continuation, matching todo-continuation-enforcer behavior.
2026-02-10 22:15:28 +09:00
YeonGyu-Kim caee5ebc18 docs: document intentional design decisions in atlas, todo-continuation, and delegation hooks 2026-02-10 22:00:54 +09:00