13 Commits

Author SHA1 Message Date
Sisyphus
20cca35157
fix(ralph-loop): skip user messages in transcript completion detection (#622) (#1086)
* fix(ralph-loop): skip user messages in transcript completion detection (#622)

The transcript-based completion detection was searching the entire JSONL
file for <promise>DONE</promise>, including user message entries. The
RALPH_LOOP_TEMPLATE instructional text contains this literal pattern,
which gets recorded as a user message, causing false positive completion
detection on every iteration. This made the loop always terminate at
iteration 1.

Fix: Parse JSONL entries line-by-line and skip entries with type 'user'
so only tool_result/assistant entries are checked for the completion
promise. Also remove the hardcoded <promise>DONE</promise> from the
template exit conditions as defense-in-depth.

* chore: changes by sisyphus-dev-ai

---------

Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
2026-01-25 12:34:42 +09:00
YeonGyu-Kim
d13e8411f0
Add /ulw-loop command for ultrawork mode loop (#867)
* feat(ralph-loop): add ultrawork field to RalphLoopState

* feat(ralph-loop): persist ultrawork field in storage

* feat(ralph-loop): accept ultrawork option in startLoop

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* feat(ralph-loop): prepend ultrawork keyword when mode active

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* feat(ralph-loop): custom toast for ultrawork mode

* feat(ralph-loop): add /ulw-loop command for ultrawork mode

* fix(ralph-loop): add non-null assertion for type safety

* fix(ralph-loop): mirror argument parsing in ulw-loop handler

- Parse quoted prompts and strip flags from task text
- Support --max-iterations and --completion-promise options
- Add default prompt for empty input
- Fixes behavior inconsistency with /ralph-loop

---------

Co-authored-by: justsisyphus <sisyphus-dev-ai@users.noreply.github.com>
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-01-17 19:56:50 +09:00
justsisyphus
d00c2e7439 fix(hooks): extract model from assistant messages with flat modelID/providerID
OpenCode API returns different structures for user vs assistant messages:
- User: info.model = { providerID, modelID } (nested)
- Assistant: info.modelID, info.providerID (flat top-level)

Previous code only checked nested format, causing model info loss when
continuation hooks fired after assistant messages.

Files modified:
- todo-continuation-enforcer.ts
- ralph-loop/index.ts
- sisyphus-task/tools.ts
- background-agent/manager.ts

Added test for assistant message model extraction.
2026-01-16 13:54:22 +09:00
justsisyphus
c7ca608b38 refactor: unify system directive prefix for keyword-detector filtering
- Add shared/system-directive.ts with SYSTEM_DIRECTIVE_PREFIX constant
- Unify all system message prefixes to [SYSTEM DIRECTIVE: OH-MY-OPENCODE - ...]
- Add isSystemDirective() filter to keyword-detector to skip system messages
- Update prometheus-md-only tests to use new prefix constants
2026-01-16 11:35:37 +09:00
justsisyphus
e264cd5078 test: skip flaky timeout test in CI 2026-01-16 02:45:41 +09:00
justsisyphus
c9f762f980 fix(hooks): use API instead of filesystem to resolve model info for session.prompt
Previously, continuation hooks (todo-continuation, boulder-continuation, ralph-loop)
and background tasks resolved model info from filesystem cache, which could be stale
or missing. This caused session.prompt to fallback to default model (Sonnet) instead
of using the originally configured model (e.g., Opus).

Now all session.prompt calls first try API (session.messages) to get current model
info, with filesystem as fallback if API fails.

Affected files:
- todo-continuation-enforcer.ts
- sisyphus-orchestrator/index.ts
- ralph-loop/index.ts
- background-agent/manager.ts
- sisyphus-task/tools.ts
- hook-message-injector/index.ts (export ToolPermission type)
2026-01-16 02:33:44 +09:00
justsisyphus
54575ad259 fix: use dynamic message lookup for model/agent context in prompts
Instead of using stale parentModel/parentAgent from task state, now
dynamically looks up the current message to get fresh model/agent values.
Applied across all prompt injection points:
- background-agent notifyParentSession
- ralph-loop continuation
- sisyphus-orchestrator boulder continuation
- sisyphus-task resume

🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) assistance
2026-01-14 18:55:46 +09:00
YeonGyu-Kim
185d4e1e54 test(ralph-loop): add tests for loop restart scenarios
- Add test for starting new loop while previous loop active (different session)
- Add test for restarting loop in same session
- Verifies startLoop properly overwrites state and resets iteration
2026-01-09 16:39:53 +09:00
Victor Jaepyo Jo
95645effd7
fix(ralph-loop): clear orphaned state when original session no longer exists (#446)
* fix(ralph-loop): clear orphaned state when original session no longer exists

When a session with an active ralph-loop terminates abnormally (abort, window close),
the state file remains with active: true. Previously, when a new session started,
the hook would skip the orphaned state without cleaning it up.

This fix adds session existence validation:
- Before skipping a loop owned by a different session, check if that session still exists
- If the original session no longer exists, clear the orphan state and log
- If the original session still exists, skip as before (it's another active session's loop)

Changes:
- Add checkSessionExists option to RalphLoopOptions for dependency injection
- Wire up sessionExists from session-manager as the default implementation
- Add tests for orphan state cleanup and active session preservation

* fix(ralph-loop): add error handling around checkSessionExists call

Wraps the async checkSessionExists call in try/catch for consistency
with other async operations in this file. If the check throws, logs
the error and falls back to the original behavior (not clearing state).

---------

Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
2026-01-03 14:11:59 +09:00
Sisyphus
f345101f91
fix(ralph-loop): adopt OContinue patterns for better performance and abort handling (#431) 2026-01-03 09:55:12 +09:00
Sisyphus
3ba61790ab
fix(ralph-loop): detect completion promise from session messages API (#413)
* fix(ralph-loop): detect completion promise from session messages API

The completion promise (e.g., <promise>DONE</promise>) was not being detected
because assistant text messages were never recorded to the transcript file.
Only user messages, tool uses, and tool results were recorded.

This fix adds a new detection method that fetches session messages via the
OpenCode API and checks assistant text messages for the completion promise.
The transcript file check is kept as a fallback.

Fixes #412

* refactor(ralph-loop): address review feedback

- Simplify response parsing to use response.data consistently (greptile)
- Add session ID tracking to messages mock for better test coverage (cubic)
- Add assertion to verify correct session ID is passed to API

---------

Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
2026-01-02 16:37:04 +09:00
Sisyphus
a295202a81
fix(ralph-loop): generate transcript path from sessionID instead of relying on event properties (#355)
OpenCode doesn't pass transcriptPath in the session.idle event properties,
which caused detectCompletionPromise to always return false (the first check
returns early if transcriptPath is undefined).

This fix:
- Imports getTranscriptPath from claude-code-hooks/transcript
- Generates the transcript path from sessionID instead of reading from event
- Adds optional getTranscriptPath callback to RalphLoopOptions for testability

Fixes #354

Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
2025-12-30 23:08:30 +09:00
YeonGyu-Kim
0f0f49b823
feat: add Ralph Loop self-referential development loop (#337)
* feat(config): add RalphLoopConfigSchema and hook name

- Add ralph-loop to HookNameSchema enum
- Add RalphLoopConfigSchema with enabled, default_max_iterations, state_dir
- Add ralph_loop field to OhMyOpenCodeConfigSchema
- Export RalphLoopConfig type

* feat(ralph-loop): add hook directory structure with constants and types

- Add constants.ts with HOOK_NAME, DEFAULT_STATE_FILE, COMPLETION_TAG_PATTERN
- Add types.ts with RalphLoopState and RalphLoopOptions interfaces
- Export RalphLoopConfig from config/index.ts

* feat(ralph-loop): add storage module for markdown state file management

- Implement readState/writeState/clearState/incrementIteration
- Use YAML frontmatter format for state persistence
- Support custom state file paths via config

* feat(ralph-loop): implement main hook with session.idle handler

- Add createRalphLoopHook factory with event handler
- Implement startLoop, cancelLoop, getState API
- Detect completion promise in transcript
- Auto-continue with iteration tracking
- Handle max iterations limit
- Show toast notifications for status updates
- Support session recovery and cleanup

* test(ralph-loop): add comprehensive BDD-style tests

- Add 17 test cases covering storage, hook lifecycle, iteration
- Test completion detection, cancellation, recovery, session cleanup
- Fix storage.ts to handle YAML value parsing correctly
- Use BDD #given/#when/#then comments per project convention

* feat(builtin-commands): add ralph-loop and cancel-ralph commands

* feat(ralph-loop): register hook in main plugin

* docs: add Ralph Loop feature to all README files

* chore: regenerate JSON schema with ralph-loop config

* feat(ralph-loop): change state file path from .opencode to .sisyphus

🤖 Generated with assistance of https://github.com/code-yeongyu/oh-my-opencode

* feat(ralph-loop): integrate ralph-loop and cancel-ralph command handlers into plugin hooks

- Add chat.message hook to detect and start ralph-loop or cancel-ralph templates
- Add slashcommand hook to handle /ralph-loop and /cancel-ralph commands
- Support custom --max-iterations and --completion-promise options

🤖 Generated with assistance of https://github.com/code-yeongyu/oh-my-opencode

---------

Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
2025-12-30 17:41:03 +09:00