From 2034cf137aa388b61b0d607851ec914652a91201 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Thu, 19 Feb 2026 03:22:39 +0900 Subject: [PATCH] docs: add module-level AGENTS.md for config-manager, keyword-detector, ralph-loop, session-recovery, todo-continuation-enforcer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with assistance of [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) --- src/cli/config-manager/AGENTS.md | 52 +++++++++++++++ src/hooks/keyword-detector/AGENTS.md | 57 ++++++++++++++++ src/hooks/ralph-loop/AGENTS.md | 62 ++++++++++++++++++ src/hooks/session-recovery/AGENTS.md | 59 +++++++++++++++++ .../todo-continuation-enforcer/AGENTS.md | 65 +++++++++++++++++++ 5 files changed, 295 insertions(+) create mode 100644 src/cli/config-manager/AGENTS.md create mode 100644 src/hooks/keyword-detector/AGENTS.md create mode 100644 src/hooks/ralph-loop/AGENTS.md create mode 100644 src/hooks/session-recovery/AGENTS.md create mode 100644 src/hooks/todo-continuation-enforcer/AGENTS.md diff --git a/src/cli/config-manager/AGENTS.md b/src/cli/config-manager/AGENTS.md new file mode 100644 index 000000000..ff90e2948 --- /dev/null +++ b/src/cli/config-manager/AGENTS.md @@ -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.) diff --git a/src/hooks/keyword-detector/AGENTS.md b/src/hooks/keyword-detector/AGENTS.md new file mode 100644 index 000000000..80fe2c77e --- /dev/null +++ b/src/hooks/keyword-detector/AGENTS.md @@ -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 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 diff --git a/src/hooks/ralph-loop/AGENTS.md b/src/hooks/ralph-loop/AGENTS.md new file mode 100644 index 000000000..f5cd48657 --- /dev/null +++ b/src/hooks/ralph-loop/AGENTS.md @@ -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 `DONE` 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 DONE + → 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 `DONE` | +| `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: "DONE") + ultrawork?: boolean // Enable ultrawork mode for iterations +}) +``` + +## EXPORTED INTERFACE + +```typescript +interface RalphLoopHook { + event: (input) => Promise // session.idle handler + startLoop: (sessionID, prompt, options?) => boolean + cancelLoop: (sessionID) => boolean + getState: () => RalphLoopState | null +} +``` diff --git a/src/hooks/session-recovery/AGENTS.md b/src/hooks/session-recovery/AGENTS.md new file mode 100644 index 000000000..28e3e75af --- /dev/null +++ b/src/hooks/session-recovery/AGENTS.md @@ -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 + 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) diff --git a/src/hooks/todo-continuation-enforcer/AGENTS.md b/src/hooks/todo-continuation-enforcer/AGENTS.md new file mode 100644 index 000000000..777fe5c47 --- /dev/null +++ b/src/hooks/todo-continuation-enforcer/AGENTS.md @@ -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.