docs: add module-level AGENTS.md for config-manager, keyword-detector, ralph-loop, session-recovery, todo-continuation-enforcer
🤖 Generated with assistance of [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
This commit is contained in:
52
src/cli/config-manager/AGENTS.md
Normal file
52
src/cli/config-manager/AGENTS.md
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
# src/cli/config-manager/ — CLI Installation Utilities
|
||||||
|
|
||||||
|
**Generated:** 2026-02-19
|
||||||
|
|
||||||
|
## OVERVIEW
|
||||||
|
|
||||||
|
20 files. Stateless utility functions for the `install` command. Handles OpenCode config manipulation, provider configuration, JSONC operations, binary detection, and npm registry queries. No class — flat utility collection.
|
||||||
|
|
||||||
|
## FILE CATALOG
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| `add-plugin-to-opencode-config.ts` | Register `oh-my-opencode` in `.opencode/opencode.json` plugin array |
|
||||||
|
| `add-provider-config.ts` | Add provider API key to OpenCode config (user-level) |
|
||||||
|
| `antigravity-provider-configuration.ts` | Handle Antigravity provider setup (special case) |
|
||||||
|
| `auth-plugins.ts` | Detect auth plugin requirements per provider (oauth vs key) |
|
||||||
|
| `bun-install.ts` | Run `bun install` / `npm install` for plugin setup |
|
||||||
|
| `config-context.ts` | `ConfigContext` — shared config state across install steps |
|
||||||
|
| `deep-merge-record.ts` | Deep merge utility for JSONC config objects |
|
||||||
|
| `detect-current-config.ts` | Read existing OpenCode config, detect installed plugins |
|
||||||
|
| `ensure-config-directory-exists.ts` | Create `.opencode/` dir if missing |
|
||||||
|
| `format-error-with-suggestion.ts` | Format errors with actionable suggestions |
|
||||||
|
| `generate-omo-config.ts` | Generate `oh-my-opencode.jsonc` from install selections |
|
||||||
|
| `jsonc-provider-editor.ts` | Read/write JSONC files with comment preservation |
|
||||||
|
| `npm-dist-tags.ts` | Fetch latest version from npm registry (dist-tags) |
|
||||||
|
| `opencode-binary.ts` | Detect OpenCode binary location, verify it's installed |
|
||||||
|
| `opencode-config-format.ts` | OpenCode config format constants and type guards |
|
||||||
|
| `parse-opencode-config-file.ts` | Parse opencode.json/opencode.jsonc with fallback |
|
||||||
|
| `plugin-name-with-version.ts` | Resolve `oh-my-opencode@X.Y.Z` for installation |
|
||||||
|
| `write-omo-config.ts` | Write generated config to `.opencode/oh-my-opencode.jsonc` |
|
||||||
|
|
||||||
|
## USAGE PATTERN
|
||||||
|
|
||||||
|
Functions are called sequentially by `src/cli/install.ts` / `src/cli/tui-installer.ts`:
|
||||||
|
|
||||||
|
```
|
||||||
|
1. ensure-config-directory-exists
|
||||||
|
2. detect-current-config (check what's already set up)
|
||||||
|
3. opencode-binary (verify opencode installed)
|
||||||
|
4. npm-dist-tags (get latest version)
|
||||||
|
5. generate-omo-config (build config from user selections)
|
||||||
|
6. write-omo-config
|
||||||
|
7. add-plugin-to-opencode-config
|
||||||
|
8. add-provider-config (for each provider selected)
|
||||||
|
9. bun-install
|
||||||
|
```
|
||||||
|
|
||||||
|
## NOTES
|
||||||
|
|
||||||
|
- All functions are pure / stateless (except disk I/O) — no shared module state
|
||||||
|
- `jsonc-provider-editor.ts` uses comment-preserving JSONC library — NEVER use `JSON.parse` on JSONC files
|
||||||
|
- `opencode-binary.ts` searches PATH + common install locations (`.local/bin`, `~/.bun/bin`, etc.)
|
||||||
57
src/hooks/keyword-detector/AGENTS.md
Normal file
57
src/hooks/keyword-detector/AGENTS.md
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
# src/hooks/keyword-detector/ — Mode Keyword Injection
|
||||||
|
|
||||||
|
**Generated:** 2026-02-19
|
||||||
|
|
||||||
|
## OVERVIEW
|
||||||
|
|
||||||
|
8 files + 3 mode subdirs (~1665 LOC). Transform Tier hook on `messages.transform`. Scans first user message for mode keywords (ultrawork, search, analyze) and injects mode-specific system prompts.
|
||||||
|
|
||||||
|
## KEYWORDS
|
||||||
|
|
||||||
|
| Keyword | Pattern | Effect |
|
||||||
|
|---------|---------|--------|
|
||||||
|
| `ultrawork` / `ulw` | `/\b(ultrawork|ulw)\b/i` | Full orchestration mode — parallel agents, deep exploration, relentless execution |
|
||||||
|
| Search mode | `SEARCH_PATTERN` (from `search/`) | Web/doc search focus prompt injection |
|
||||||
|
| Analyze mode | `ANALYZE_PATTERN` (from `analyze/`) | Deep analysis mode prompt injection |
|
||||||
|
|
||||||
|
## STRUCTURE
|
||||||
|
|
||||||
|
```
|
||||||
|
keyword-detector/
|
||||||
|
├── index.ts # Barrel export
|
||||||
|
├── hook.ts # createKeywordDetectorHook() — chat.message handler
|
||||||
|
├── detector.ts # detectKeywordsWithType() + extractPromptText()
|
||||||
|
├── constants.ts # KEYWORD_DETECTORS array, re-exports from submodules
|
||||||
|
├── types.ts # KeywordDetector, DetectedKeyword types
|
||||||
|
├── ultrawork/
|
||||||
|
│ ├── index.ts
|
||||||
|
│ ├── message.ts # getUltraworkMessage() — dynamic prompt by agent/model
|
||||||
|
│ └── isPlannerAgent.ts
|
||||||
|
├── search/
|
||||||
|
│ ├── index.ts
|
||||||
|
│ ├── pattern.ts # SEARCH_PATTERN regex
|
||||||
|
│ └── message.ts # SEARCH_MESSAGE
|
||||||
|
└── analyze/
|
||||||
|
├── index.ts
|
||||||
|
├── pattern.ts # ANALYZE_PATTERN regex
|
||||||
|
└── message.ts # ANALYZE_MESSAGE
|
||||||
|
```
|
||||||
|
|
||||||
|
## DETECTION LOGIC
|
||||||
|
|
||||||
|
```
|
||||||
|
chat.message (user input)
|
||||||
|
→ extractPromptText(parts)
|
||||||
|
→ isSystemDirective? → skip
|
||||||
|
→ removeSystemReminders(text) # strip <SYSTEM_REMINDER> blocks
|
||||||
|
→ detectKeywordsWithType(cleanText, agentName, modelID)
|
||||||
|
→ isPlannerAgent(agentName)? → filter out ultrawork
|
||||||
|
→ for each detected keyword: inject mode message into output
|
||||||
|
```
|
||||||
|
|
||||||
|
## GUARDS
|
||||||
|
|
||||||
|
- **System directive skip**: Messages tagged as system directives are not scanned (prevents infinite loops)
|
||||||
|
- **Planner agent filter**: Prometheus/plan agents do not receive `ultrawork` injection
|
||||||
|
- **Session agent tracking**: Uses `getSessionAgent()` to get actual agent (not just input hint)
|
||||||
|
- **Model-aware messages**: `getUltraworkMessage(agentName, modelID)` adapts message to active model
|
||||||
62
src/hooks/ralph-loop/AGENTS.md
Normal file
62
src/hooks/ralph-loop/AGENTS.md
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
# src/hooks/ralph-loop/ — Self-Referential Dev Loop
|
||||||
|
|
||||||
|
**Generated:** 2026-02-19
|
||||||
|
|
||||||
|
## OVERVIEW
|
||||||
|
|
||||||
|
14 files (~1687 LOC). The `ralphLoop` Session Tier hook — powers the `/ralph-loop` command. Iterates a development loop until the agent emits `<promise>DONE</promise>` or max iterations reached.
|
||||||
|
|
||||||
|
## LOOP LIFECYCLE
|
||||||
|
|
||||||
|
```
|
||||||
|
/ralph-loop → startLoop(sessionID, prompt, options)
|
||||||
|
→ loopState.startLoop() → persists state to .sisyphus/ralph-loop.local.md
|
||||||
|
→ session.idle events → createRalphLoopEventHandler()
|
||||||
|
→ completionPromiseDetector: scan output for <promise>DONE</promise>
|
||||||
|
→ if not done: inject continuation prompt → loop
|
||||||
|
→ if done or maxIterations: cancelLoop()
|
||||||
|
```
|
||||||
|
|
||||||
|
## KEY FILES
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| `ralph-loop-hook.ts` | `createRalphLoopHook()` — composes controller + recovery + event handler |
|
||||||
|
| `ralph-loop-event-handler.ts` | `createRalphLoopEventHandler()` — handles session.idle, drives loop |
|
||||||
|
| `loop-state-controller.ts` | State CRUD: startLoop, cancelLoop, getState, persist to disk |
|
||||||
|
| `loop-session-recovery.ts` | Recover from crashed/interrupted loop sessions |
|
||||||
|
| `completion-promise-detector.ts` | Scan session transcript for `<promise>DONE</promise>` |
|
||||||
|
| `continuation-prompt-builder.ts` | Build continuation message for next iteration |
|
||||||
|
| `continuation-prompt-injector.ts` | Inject built prompt into active session |
|
||||||
|
| `storage.ts` | Read/write `.sisyphus/ralph-loop.local.md` state file |
|
||||||
|
| `message-storage-directory.ts` | Temp dir for prompt injection |
|
||||||
|
| `with-timeout.ts` | API call wrapper with timeout (default 5000ms) |
|
||||||
|
| `types.ts` | `RalphLoopState`, `RalphLoopOptions`, loop iteration types |
|
||||||
|
|
||||||
|
## STATE FILE
|
||||||
|
|
||||||
|
```
|
||||||
|
.sisyphus/ralph-loop.local.md (gitignored)
|
||||||
|
→ sessionID, prompt, iteration count, maxIterations, completionPromise, ultrawork flag
|
||||||
|
```
|
||||||
|
|
||||||
|
## OPTIONS
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
startLoop(sessionID, prompt, {
|
||||||
|
maxIterations?: number // Default from config (default: 100)
|
||||||
|
completionPromise?: string // Custom "done" signal (default: "<promise>DONE</promise>")
|
||||||
|
ultrawork?: boolean // Enable ultrawork mode for iterations
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## EXPORTED INTERFACE
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface RalphLoopHook {
|
||||||
|
event: (input) => Promise<void> // session.idle handler
|
||||||
|
startLoop: (sessionID, prompt, options?) => boolean
|
||||||
|
cancelLoop: (sessionID) => boolean
|
||||||
|
getState: () => RalphLoopState | null
|
||||||
|
}
|
||||||
|
```
|
||||||
59
src/hooks/session-recovery/AGENTS.md
Normal file
59
src/hooks/session-recovery/AGENTS.md
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
# src/hooks/session-recovery/ — Auto Session Error Recovery
|
||||||
|
|
||||||
|
**Generated:** 2026-02-19
|
||||||
|
|
||||||
|
## OVERVIEW
|
||||||
|
|
||||||
|
16 files + storage/ subdir. Session Tier hook handling `session.error` events. Detects recoverable error types, applies targeted recovery strategies, and resumes the session transparently.
|
||||||
|
|
||||||
|
## RECOVERY STRATEGIES
|
||||||
|
|
||||||
|
| Error Type | File | Recovery Action |
|
||||||
|
|------------|------|-----------------|
|
||||||
|
| `tool_result_missing` | `recover-tool-result-missing.ts` | Reconstruct missing tool results from storage |
|
||||||
|
| `thinking_block_order` | `recover-thinking-block-order.ts` | Reorder malformed thinking blocks |
|
||||||
|
| `thinking_disabled_violation` | `recover-thinking-disabled-violation.ts` | Strip thinking blocks when disabled |
|
||||||
|
| `empty_content_message` | `recover-empty-content-message*.ts` | Handle empty/null content blocks |
|
||||||
|
|
||||||
|
## KEY FILES
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| `hook.ts` | `createSessionRecoveryHook()` — error detection, strategy dispatch, resume |
|
||||||
|
| `detect-error-type.ts` | `detectErrorType(error)` → `RecoveryErrorType \| null` |
|
||||||
|
| `resume.ts` | `resumeSession()` — rebuild session context, trigger retry |
|
||||||
|
| `storage.ts` | Per-session message storage for recovery reconstruction |
|
||||||
|
| `recover-tool-result-missing.ts` | Reconstruct tool results from stored metadata |
|
||||||
|
| `recover-thinking-block-order.ts` | Fix malformed thinking block sequences |
|
||||||
|
| `recover-thinking-disabled-violation.ts` | Remove thinking blocks from model context |
|
||||||
|
| `recover-empty-content-message.ts` | Handle empty assistant messages |
|
||||||
|
| `recover-empty-content-message-sdk.ts` | SDK variant for empty content recovery |
|
||||||
|
| `types.ts` | `StoredMessageMeta`, `StoredPart`, `ResumeConfig`, `MessageData` |
|
||||||
|
|
||||||
|
## STORAGE SUBDIRECTORY
|
||||||
|
|
||||||
|
```
|
||||||
|
storage/
|
||||||
|
├── message-store.ts # In-memory + file message cache
|
||||||
|
├── part-store.ts # Individual message parts storage
|
||||||
|
└── index.ts # Barrel export
|
||||||
|
```
|
||||||
|
|
||||||
|
Stores message metadata and parts per session for recovery reconstruction.
|
||||||
|
|
||||||
|
## HOOK INTERFACE
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface SessionRecoveryHook {
|
||||||
|
handleSessionRecovery: (info: MessageInfo) => Promise<boolean>
|
||||||
|
isRecoverableError: (error: unknown) => boolean
|
||||||
|
setOnAbortCallback: (cb: (sessionID: string) => void) => void
|
||||||
|
setOnRecoveryCompleteCallback: (cb: (sessionID: string) => void) => void
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## NOTES
|
||||||
|
|
||||||
|
- Guards with `processingErrors` Set to prevent duplicate recovery attempts on same error
|
||||||
|
- Supports `experimental` config for behavior flags
|
||||||
|
- Distinct from `anthropic-context-window-limit-recovery` (handles token limit; this handles structural errors)
|
||||||
65
src/hooks/todo-continuation-enforcer/AGENTS.md
Normal file
65
src/hooks/todo-continuation-enforcer/AGENTS.md
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
# src/hooks/todo-continuation-enforcer/ — Boulder Continuation Mechanism
|
||||||
|
|
||||||
|
**Generated:** 2026-02-19
|
||||||
|
|
||||||
|
## OVERVIEW
|
||||||
|
|
||||||
|
14 files (~2061 LOC). The "boulder" — Continuation Tier hook that forces Sisyphus to keep rolling when incomplete todos remain. Fires on `session.idle`, injects continuation prompt after 2s countdown toast.
|
||||||
|
|
||||||
|
## HOW IT WORKS
|
||||||
|
|
||||||
|
```
|
||||||
|
session.idle
|
||||||
|
→ Is main session (not prometheus/compaction)? (DEFAULT_SKIP_AGENTS)
|
||||||
|
→ No abort detected recently? (ABORT_WINDOW_MS = 3s)
|
||||||
|
→ Todos still incomplete? (todo.ts)
|
||||||
|
→ No background tasks running?
|
||||||
|
→ Cooldown passed? (CONTINUATION_COOLDOWN_MS = 30s)
|
||||||
|
→ Failure count < max? (MAX_CONSECUTIVE_FAILURES = 5)
|
||||||
|
→ Start 2s countdown toast → inject CONTINUATION_PROMPT
|
||||||
|
```
|
||||||
|
|
||||||
|
## KEY FILES
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| `handler.ts` | `createTodoContinuationHandler()` — event router, delegates to idle/non-idle handlers |
|
||||||
|
| `idle-event.ts` | `handleSessionIdle()` — main decision gate for session.idle |
|
||||||
|
| `non-idle-events.ts` | `handleNonIdleEvent()` — handles session.error (abort detection) |
|
||||||
|
| `session-state.ts` | `SessionStateStore` — per-session failure/abort/cooldown state |
|
||||||
|
| `todo.ts` | Check todo completion status via session store |
|
||||||
|
| `countdown.ts` | 2s countdown toast before injection |
|
||||||
|
| `abort-detection.ts` | Detect MessageAbortedError / AbortError |
|
||||||
|
| `continuation-injection.ts` | Build + inject CONTINUATION_PROMPT into session |
|
||||||
|
| `message-directory.ts` | Temp dir for message injection exchange |
|
||||||
|
| `constants.ts` | Timing constants, CONTINUATION_PROMPT, skip agents |
|
||||||
|
| `types.ts` | `SessionState`, handler argument types |
|
||||||
|
|
||||||
|
## CONSTANTS
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
DEFAULT_SKIP_AGENTS = ["prometheus", "compaction"]
|
||||||
|
CONTINUATION_COOLDOWN_MS = 30_000 // 30s between injections
|
||||||
|
MAX_CONSECUTIVE_FAILURES = 5 // Then 5min pause (exponential backoff)
|
||||||
|
FAILURE_RESET_WINDOW_MS = 5 * 60_000 // 5min window for failure reset
|
||||||
|
COUNTDOWN_SECONDS = 2
|
||||||
|
ABORT_WINDOW_MS = 3000 // Grace after abort signal
|
||||||
|
```
|
||||||
|
|
||||||
|
## STATE PER SESSION
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface SessionState {
|
||||||
|
failureCount: number // Consecutive failures
|
||||||
|
lastFailureAt?: number // Timestamp
|
||||||
|
abortDetectedAt?: number // Reset after ABORT_WINDOW_MS
|
||||||
|
cooldownUntil?: number // Next injection allowed after
|
||||||
|
countdownTimer?: Timer // Active countdown reference
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## RELATIONSHIP TO ATLAS
|
||||||
|
|
||||||
|
`todoContinuationEnforcer` handles **main Sisyphus sessions** only.
|
||||||
|
`atlasHook` handles **boulder/ralph/subagent sessions** with a different decision gate.
|
||||||
|
Both fire on `session.idle` but check session type first.
|
||||||
Reference in New Issue
Block a user