Compare commits

...

6 Commits

Author SHA1 Message Date
github-actions[bot]
edff922afb release: v0.1.29 2025-12-09 01:37:46 +00:00
YeonGyu-Kim
45bdcf3580 docs(readme): clarify nested AGENTS.md injection behavior with example
Added directory tree example showing how multiple AGENTS.md files are
collected and injected in hierarchical order when reading nested files.

🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
2025-12-09 10:36:34 +09:00
YeonGyu-Kim
b07dd22093 fix(pulse-monitor): reset heartbeat after tool execution to prevent false positives
Tools can take arbitrary time, so we need a fresh baseline after execution.
Previously, lastHeartbeat wasn't updated after tool.execute.after, causing
stalled detection to trigger immediately after long-running tools.

🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
2025-12-09 10:36:34 +09:00
YeonGyu-Kim
c7d29fea48 refactor(mcp): remove unused builtinMcps export
🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
2025-12-09 10:36:34 +09:00
YeonGyu-Kim
55675497a5 refactor(session-recovery): remove unused ThinkingPart interface and fallbackRevertStrategy function
🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
2025-12-09 10:36:34 +09:00
YeonGyu-Kim
ae2d347d81 refactor(lsp): remove unused formatWorkspaceEdit import
🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
2025-12-09 10:36:34 +09:00
6 changed files with 23 additions and 68 deletions

View File

@@ -138,7 +138,17 @@ I believe in the right tool for the job. For your wallet's sake, use CLIProxyAPI
- **Thinking Disabled Violation**: When thinking blocks exist but thinking is disabled → strips thinking blocks
- **Empty Content Message**: When message has only thinking/meta blocks without actual content → injects "(interrupted)" text via filesystem
- **Comment Checker**: Detects and reports unnecessary comments after code modifications. Smartly ignores valid patterns (BDD, directives, docstrings, shebangs) to keep the codebase clean from AI-generated artifacts.
- **Directory AGENTS.md Injector**: Automatically injects `AGENTS.md` contents when reading files. Searches upward from the file's directory to project root, providing directory-level context to the agent. Inspired by Claude Code's CLAUDE.md feature.
- **Directory AGENTS.md Injector**: Automatically injects `AGENTS.md` contents when reading files. Searches upward from the file's directory to project root, collecting **all** `AGENTS.md` files along the path hierarchy. This enables nested, directory-specific instructions:
```
project/
├── AGENTS.md # Project-wide context
├── src/
│ ├── AGENTS.md # src-specific context
│ └── components/
│ ├── AGENTS.md # Component-specific context
│ └── Button.tsx # Reading this injects ALL 3 AGENTS.md files
```
When reading `Button.tsx`, the hook injects contexts in order: `project/AGENTS.md` → `src/AGENTS.md` → `components/AGENTS.md`. Each directory's context is injected only once per session. Inspired by Claude Code's CLAUDE.md feature.
### Agents
- **oracle** (`openai/gpt-5.1`): The architect. Expert in code reviews and strategy. Uses GPT-5.1 for its unmatched logic and reasoning capabilities. Inspired by AmpCode.

View File

@@ -1,6 +1,6 @@
{
"name": "oh-my-opencode",
"version": "0.1.28",
"version": "0.1.29",
"description": "OpenCode plugin - custom agents (oracle, librarian) and enhanced features",
"main": "dist/index.js",
"types": "dist/index.d.ts",

View File

@@ -132,8 +132,13 @@ export function createPulseMonitorHook(ctx: PluginInput) {
// Pause monitoring while tool runs locally (tools can take time)
stopMonitoring()
},
"tool.execute.after": async (_input: { sessionID: string }) => {
// Don't forcefully restart monitoring here to avoid false positives
"tool.execute.after": async (input: { sessionID: string }) => {
// Reset heartbeat after tool execution to prevent false positives
// Tools can take arbitrary time, so we need a fresh baseline
if (input.sessionID && currentSessionID === input.sessionID) {
lastHeartbeat = Date.now()
}
// Don't forcefully restart monitoring here
// Monitoring will naturally resume when next session/message event arrives
// This prevents stalled detection on legitimately idle sessions
}

View File

@@ -34,11 +34,6 @@ interface ToolUsePart {
input: Record<string, unknown>
}
interface ThinkingPart {
type: "thinking"
thinking: string
}
interface MessagePart {
type: string
id?: string
@@ -186,62 +181,10 @@ async function recoverEmptyContentMessage(
return anySuccess
}
async function fallbackRevertStrategy(
client: Client,
sessionID: string,
failedAssistantMsg: MessageData,
directory: string
): Promise<boolean> {
const parentMsgID = failedAssistantMsg.info?.parentID
const messagesResp = await client.session.messages({
path: { id: sessionID },
query: { directory },
})
const msgs = (messagesResp as { data?: MessageData[] }).data
if (!msgs || msgs.length === 0) {
return false
}
let targetUserMsg: MessageData | null = null
if (parentMsgID) {
targetUserMsg = msgs.find((m) => m.info?.id === parentMsgID) ?? null
}
if (!targetUserMsg) {
for (let i = msgs.length - 1; i >= 0; i--) {
if (msgs[i].info?.role === "user") {
targetUserMsg = msgs[i]
break
}
}
}
if (!targetUserMsg?.parts?.length) {
return false
}
await client.session.revert({
path: { id: sessionID },
body: { messageID: targetUserMsg.info?.id ?? "" },
query: { directory },
})
const textParts = targetUserMsg.parts
.filter((p) => p.type === "text" && p.text)
.map((p) => ({ type: "text" as const, text: p.text ?? "" }))
if (textParts.length === 0) {
return false
}
await client.session.prompt({
path: { id: sessionID },
body: { parts: textParts },
query: { directory },
})
return true
}
// NOTE: fallbackRevertStrategy was removed (2025-12-08)
// Reason: Function was defined but never called - no error recovery paths used it.
// All error types have dedicated recovery functions (recoverToolResultMissing,
// recoverThinkingBlockOrder, recoverThinkingDisabledViolation, recoverEmptyContentMessage).
export function createSessionRecoveryHook(ctx: PluginInput) {
const processingErrors = new Set<string>()

View File

@@ -20,5 +20,3 @@ export function createBuiltinMcps(disabledMcps: McpName[] = []) {
return mcps
}
export const builtinMcps = allBuiltinMcps

View File

@@ -14,7 +14,6 @@ import {
formatDiagnostic,
filterDiagnosticsBySeverity,
formatPrepareRenameResult,
formatWorkspaceEdit,
formatCodeActions,
applyWorkspaceEdit,
formatApplyResult,