feat(hooks): add reliability stack hooks for memory gating and crash recovery#2329
feat(hooks): add reliability stack hooks for memory gating and crash recovery#2329inwardwellbeing wants to merge 6 commits intocode-yeongyu:devfrom
Conversation
Add correction detection for identifying user corrections in conversations. Includes detector logic, event emitter, and constants. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <[email protected]>
Blocks agent spawning when available memory <1GB, warns at <2GB. Uses vm_stat + sysctl vm.swapusage parsing with os.freemem() fallback. Dispatched first in tool-execute-before chain to catch OOM before any tool runs. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <[email protected]>
…kpoint hooks Three session hooks for the reliability stack: execution-gate controls agent dispatch flow, learning-bus-injector feeds corrections into session context, auto-checkpoint injects session_restore on first idle and session_checkpoint after sustained activity (20 idles or 15 min, 5-min cooldown). Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <[email protected]>
Add learning-bus-injector, execution-gate, resource-gate, and auto-checkpoint to HookNameSchema. Export factory functions and types from hooks barrel. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <[email protected]>
Version bump for reliability stack: resource-gate, auto-checkpoint, execution-gate, learning-bus-injector, and correction-detector hooks. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <[email protected]>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <[email protected]>
|
Thank you for your contribution! Before we can merge this PR, we need you to sign our Contributor License Agreement (CLA). To sign the CLA, please comment on this PR with: This is a one-time requirement. Once signed, all your future contributions will be automatically accepted. I have read the CLA Document and I hereby sign the CLA You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot. |
There was a problem hiding this comment.
10 issues found across 30 files
Confidence score: 2/5
- High-confidence compatibility bugs in
src/hooks/index.tsare likely merge-blocking:auto-checkpoint,execution-gate, andlearning-bus-injectorpasspath: { id: sessionID }instead ofpath: { sessionID }, which can break Opencode SDK calls at runtime. src/hooks/execution-gate/constants.tshardcodes a personal iCloud Obsidian vault path, creating clear cross-platform/usability regressions for other environments unless replaced with config/env-driven paths.- There are additional behavior risks in timing/filtering and text processing (
src/hooks/auto-checkpoint/hook.ts,src/hooks/learning-bus-injector/event-reader.ts,src/hooks/correction-detector/detector.ts), so this is not just a housekeeping pass and needs targeted fixes before merging. - Pay close attention to
src/hooks/index.ts,src/hooks/execution-gate/constants.ts,src/hooks/auto-checkpoint/hook.ts,src/hooks/learning-bus-injector/event-reader.ts- SDK path contract mismatches, hardcoded environment paths, and logic edge cases could cause immediate runtime or correctness issues.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/hooks/execution-gate/constants.ts">
<violation number="1" location="src/hooks/execution-gate/constants.ts:6">
P1: Custom agent: **Opencode Compatibility**
Hardcoding a personal iCloud Obsidian vault path breaks cross-platform compatibility and usability for other Opencode users. Use an environment variable or a standard Opencode configuration directory instead.</violation>
</file>
<file name="src/hooks/index.ts">
<violation number="1" location="src/hooks/index.ts:54">
P0: Custom agent: **Opencode Compatibility**
The `learning-bus-injector` hook implementation passes invalid path parameters to the Opencode SDK. It uses `path: { id: sessionID }` instead of the required `path: { sessionID }` for `session.messages()` and `session.promptAsync()`. This will cause URL interpolation failures.</violation>
<violation number="2" location="src/hooks/index.ts:55">
P0: Custom agent: **Opencode Compatibility**
The `execution-gate` hook implementation passes invalid path parameters to the Opencode SDK. It uses `path: { id: sessionID }` instead of the required `path: { sessionID }` for `session.messages()` and `session.promptAsync()`. This will result in SDK request failures.</violation>
<violation number="3" location="src/hooks/index.ts:57">
P0: Custom agent: **Opencode Compatibility**
The `auto-checkpoint` hook implementation passes invalid path parameters to the Opencode SDK. It uses `path: { id: sessionID }` instead of the required `path: { sessionID }` for `session.messages()` and `session.promptAsync()`. This will result in SDK request failures.</violation>
</file>
<file name="src/hooks/auto-checkpoint/hook.ts">
<violation number="1" location="src/hooks/auto-checkpoint/hook.ts:116">
P1: When `lastInjectionAt` is 0 (initial state or failed injection), `timeSinceLastInjection` incorrectly falls back to `now` (current timestamp), causing `minutesSince` to calculate as ~28 million minutes. The checkpoint prompt then displays an absurd duration. The fallback should be `0` instead of `now` to correctly indicate no time has passed since injection.</violation>
</file>
<file name="src/hooks/learning-bus-injector/event-reader.ts">
<violation number="1" location="src/hooks/learning-bus-injector/event-reader.ts:43">
P2: Unsafe property access via event.event_type could return prototype methods instead of weight values. If event_type is 'constructor', 'toString', or other Object.prototype property names, the lookup returns a function rather than undefined, bypassing the ?? 0.3 fallback and causing NaN in score calculations.</violation>
<violation number="2" location="src/hooks/learning-bus-injector/event-reader.ts:65">
P2: Use numeric timestamp comparison instead of lexicographical string comparison for date filtering</violation>
</file>
<file name="src/hooks/correction-detector/emitter.ts">
<violation number="1" location="src/hooks/correction-detector/emitter.ts:1">
P1: Unregistered 'correction-detector' hook implementation is dead code</violation>
</file>
<file name="src/hooks/correction-detector/detector.ts">
<violation number="1" location="src/hooks/correction-detector/detector.ts:14">
P2: Removing code blocks and system tags with empty string instead of space causes adjacent words to merge, breaking word boundary pattern matching for correction detection</violation>
</file>
<file name="src/hooks/resource-gate/memory-check.ts">
<violation number="1" location="src/hooks/resource-gate/memory-check.ts:115">
P2: Add platform guard to avoid unnecessary process spawning on non-macOS systems. Consider checking `process.platform === 'darwin'` before executing macOS-specific commands.</violation>
</file>
Since this is your first cubic review, here's how it works:
- cubic automatically reviews your code and comments on bugs and improvements
- Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
- Add one-off context when rerunning by tagging
@cubic-dev-aiwith guidance or docs links (includingllms.txt) - Ask questions if you need clarification on any suggestion
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| export { createLearningBusInjectorHook, type LearningBusInjectorHook } from "./learning-bus-injector" | ||
| export { createExecutionGateHook, type ExecutionGateHook } from "./execution-gate" | ||
| export { createResourceGateHook, type MemoryStatus } from "./resource-gate" | ||
| export { createAutoCheckpointHook } from "./auto-checkpoint" |
There was a problem hiding this comment.
P0: Custom agent: Opencode Compatibility
The auto-checkpoint hook implementation passes invalid path parameters to the Opencode SDK. It uses path: { id: sessionID } instead of the required path: { sessionID } for session.messages() and session.promptAsync(). This will result in SDK request failures.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/hooks/index.ts, line 57:
<comment>The `auto-checkpoint` hook implementation passes invalid path parameters to the Opencode SDK. It uses `path: { id: sessionID }` instead of the required `path: { sessionID }` for `session.messages()` and `session.promptAsync()`. This will result in SDK request failures.</comment>
<file context>
@@ -51,3 +51,7 @@ export { createWriteExistingFileGuardHook } from "./write-existing-file-guard";
+export { createLearningBusInjectorHook, type LearningBusInjectorHook } from "./learning-bus-injector"
+export { createExecutionGateHook, type ExecutionGateHook } from "./execution-gate"
+export { createResourceGateHook, type MemoryStatus } from "./resource-gate"
+export { createAutoCheckpointHook } from "./auto-checkpoint"
</file context>
| export { createJsonErrorRecoveryHook, JSON_ERROR_TOOL_EXCLUDE_LIST, JSON_ERROR_PATTERNS, JSON_ERROR_REMINDER } from "./json-error-recovery"; | ||
| export { createReadImageResizerHook } from "./read-image-resizer" | ||
| export { createLearningBusInjectorHook, type LearningBusInjectorHook } from "./learning-bus-injector" | ||
| export { createExecutionGateHook, type ExecutionGateHook } from "./execution-gate" |
There was a problem hiding this comment.
P0: Custom agent: Opencode Compatibility
The execution-gate hook implementation passes invalid path parameters to the Opencode SDK. It uses path: { id: sessionID } instead of the required path: { sessionID } for session.messages() and session.promptAsync(). This will result in SDK request failures.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/hooks/index.ts, line 55:
<comment>The `execution-gate` hook implementation passes invalid path parameters to the Opencode SDK. It uses `path: { id: sessionID }` instead of the required `path: { sessionID }` for `session.messages()` and `session.promptAsync()`. This will result in SDK request failures.</comment>
<file context>
@@ -51,3 +51,7 @@ export { createWriteExistingFileGuardHook } from "./write-existing-file-guard";
export { createJsonErrorRecoveryHook, JSON_ERROR_TOOL_EXCLUDE_LIST, JSON_ERROR_PATTERNS, JSON_ERROR_REMINDER } from "./json-error-recovery";
export { createReadImageResizerHook } from "./read-image-resizer"
+export { createLearningBusInjectorHook, type LearningBusInjectorHook } from "./learning-bus-injector"
+export { createExecutionGateHook, type ExecutionGateHook } from "./execution-gate"
+export { createResourceGateHook, type MemoryStatus } from "./resource-gate"
+export { createAutoCheckpointHook } from "./auto-checkpoint"
</file context>
| export { createHashlineReadEnhancerHook } from "./hashline-read-enhancer"; | ||
| export { createJsonErrorRecoveryHook, JSON_ERROR_TOOL_EXCLUDE_LIST, JSON_ERROR_PATTERNS, JSON_ERROR_REMINDER } from "./json-error-recovery"; | ||
| export { createReadImageResizerHook } from "./read-image-resizer" | ||
| export { createLearningBusInjectorHook, type LearningBusInjectorHook } from "./learning-bus-injector" |
There was a problem hiding this comment.
P0: Custom agent: Opencode Compatibility
The learning-bus-injector hook implementation passes invalid path parameters to the Opencode SDK. It uses path: { id: sessionID } instead of the required path: { sessionID } for session.messages() and session.promptAsync(). This will cause URL interpolation failures.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/hooks/index.ts, line 54:
<comment>The `learning-bus-injector` hook implementation passes invalid path parameters to the Opencode SDK. It uses `path: { id: sessionID }` instead of the required `path: { sessionID }` for `session.messages()` and `session.promptAsync()`. This will cause URL interpolation failures.</comment>
<file context>
@@ -51,3 +51,7 @@ export { createWriteExistingFileGuardHook } from "./write-existing-file-guard";
export { createHashlineReadEnhancerHook } from "./hashline-read-enhancer";
export { createJsonErrorRecoveryHook, JSON_ERROR_TOOL_EXCLUDE_LIST, JSON_ERROR_PATTERNS, JSON_ERROR_REMINDER } from "./json-error-recovery";
export { createReadImageResizerHook } from "./read-image-resizer"
+export { createLearningBusInjectorHook, type LearningBusInjectorHook } from "./learning-bus-injector"
+export { createExecutionGateHook, type ExecutionGateHook } from "./execution-gate"
+export { createResourceGateHook, type MemoryStatus } from "./resource-gate"
</file context>
|
|
||
| export const HOOK_NAME = "execution-gate" | ||
|
|
||
| export const VAULT_ROOT = path.join( |
There was a problem hiding this comment.
P1: Custom agent: Opencode Compatibility
Hardcoding a personal iCloud Obsidian vault path breaks cross-platform compatibility and usability for other Opencode users. Use an environment variable or a standard Opencode configuration directory instead.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/hooks/execution-gate/constants.ts, line 6:
<comment>Hardcoding a personal iCloud Obsidian vault path breaks cross-platform compatibility and usability for other Opencode users. Use an environment variable or a standard Opencode configuration directory instead.</comment>
<file context>
@@ -0,0 +1,21 @@
+
+export const HOOK_NAME = "execution-gate"
+
+export const VAULT_ROOT = path.join(
+ os.homedir(),
+ "Library/Mobile Documents/iCloud~md~obsidian/Documents/Mind Palace",
</file context>
|
|
||
| // Check thresholds: idle count (proxy for messages) or time since last injection | ||
| const idlesSinceLastInjection = state.idleCount | ||
| const timeSinceLastInjection = state.lastInjectionAt === 0 ? now : now - state.lastInjectionAt |
There was a problem hiding this comment.
P1: When lastInjectionAt is 0 (initial state or failed injection), timeSinceLastInjection incorrectly falls back to now (current timestamp), causing minutesSince to calculate as ~28 million minutes. The checkpoint prompt then displays an absurd duration. The fallback should be 0 instead of now to correctly indicate no time has passed since injection.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/hooks/auto-checkpoint/hook.ts, line 116:
<comment>When `lastInjectionAt` is 0 (initial state or failed injection), `timeSinceLastInjection` incorrectly falls back to `now` (current timestamp), causing `minutesSince` to calculate as ~28 million minutes. The checkpoint prompt then displays an absurd duration. The fallback should be `0` instead of `now` to correctly indicate no time has passed since injection.</comment>
<file context>
@@ -0,0 +1,157 @@
+
+ // Check thresholds: idle count (proxy for messages) or time since last injection
+ const idlesSinceLastInjection = state.idleCount
+ const timeSinceLastInjection = state.lastInjectionAt === 0 ? now : now - state.lastInjectionAt
+
+ const messageThresholdMet = idlesSinceLastInjection >= CHECKPOINT_MESSAGE_THRESHOLD
</file context>
| const timeSinceLastInjection = state.lastInjectionAt === 0 ? now : now - state.lastInjectionAt | |
| const timeSinceLastInjection = state.lastInjectionAt === 0 ? 0 : now - state.lastInjectionAt |
| @@ -0,0 +1,98 @@ | |||
| import * as fs from "node:fs" | |||
There was a problem hiding this comment.
P1: Unregistered 'correction-detector' hook implementation is dead code
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/hooks/correction-detector/emitter.ts:
<comment>Unregistered 'correction-detector' hook implementation is dead code</comment>
<file context>
@@ -0,0 +1,98 @@
+import * as fs from "node:fs"
+import * as path from "node:path"
+import * as os from "node:os"
+
+import { SYSTEM_EVENTS_PATH, SEVERITY_WEIGHTS, HOOK_NAME } from "./constants"
+import type { DetectedCorrection } from "./detector"
+import { highestSeverity } from "./detector"
+import { log } from "../../shared/logger"
+
</file context>
| if (!line.trim()) continue | ||
| try { | ||
| const event = JSON.parse(line) as SystemEvent | ||
| if (event.timestamp >= cutoffStr) { |
There was a problem hiding this comment.
P2: Use numeric timestamp comparison instead of lexicographical string comparison for date filtering
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/hooks/learning-bus-injector/event-reader.ts, line 65:
<comment>Use numeric timestamp comparison instead of lexicographical string comparison for date filtering</comment>
<file context>
@@ -0,0 +1,84 @@
+ if (!line.trim()) continue
+ try {
+ const event = JSON.parse(line) as SystemEvent
+ if (event.timestamp >= cutoffStr) {
+ const confidence = event.confidence ?? 0.8
+ if (confidence >= MIN_CONFIDENCE) {
</file context>
| } | ||
|
|
||
| function computeScore(event: SystemEvent): number { | ||
| const typeWeight = EVENT_TYPE_WEIGHTS[event.event_type] ?? 0.3 |
There was a problem hiding this comment.
P2: Unsafe property access via event.event_type could return prototype methods instead of weight values. If event_type is 'constructor', 'toString', or other Object.prototype property names, the lookup returns a function rather than undefined, bypassing the ?? 0.3 fallback and causing NaN in score calculations.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/hooks/learning-bus-injector/event-reader.ts, line 43:
<comment>Unsafe property access via event.event_type could return prototype methods instead of weight values. If event_type is 'constructor', 'toString', or other Object.prototype property names, the lookup returns a function rather than undefined, bypassing the ?? 0.3 fallback and causing NaN in score calculations.</comment>
<file context>
@@ -0,0 +1,84 @@
+}
+
+function computeScore(event: SystemEvent): number {
+ const typeWeight = EVENT_TYPE_WEIGHTS[event.event_type] ?? 0.3
+ const confidence = event.confidence ?? 0.8
+ const recency = recencyScore(event.timestamp)
</file context>
| */ | ||
| function cleanText(text: string): string { | ||
| return text | ||
| .replace(/```[\s\S]*?```/g, "") |
There was a problem hiding this comment.
P2: Removing code blocks and system tags with empty string instead of space causes adjacent words to merge, breaking word boundary pattern matching for correction detection
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/hooks/correction-detector/detector.ts, line 14:
<comment>Removing code blocks and system tags with empty string instead of space causes adjacent words to merge, breaking word boundary pattern matching for correction detection</comment>
<file context>
@@ -0,0 +1,52 @@
+ */
+function cleanText(text: string): string {
+ return text
+ .replace(/```[\s\S]*?```/g, "")
+ .replace(/`[^`]+`/g, "")
+ .replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "")
</file context>
| } | ||
| } | ||
|
|
||
| export function checkMacOSMemory(): MemoryStatus { |
There was a problem hiding this comment.
P2: Add platform guard to avoid unnecessary process spawning on non-macOS systems. Consider checking process.platform === 'darwin' before executing macOS-specific commands.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/hooks/resource-gate/memory-check.ts, line 115:
<comment>Add platform guard to avoid unnecessary process spawning on non-macOS systems. Consider checking `process.platform === 'darwin'` before executing macOS-specific commands.</comment>
<file context>
@@ -0,0 +1,136 @@
+ }
+}
+
+export function checkMacOSMemory(): MemoryStatus {
+ try {
+ const vmStatOutput = execSync("vm_stat", { encoding: "utf8" })
</file context>
Summary
resource-gatetool-guard hook to block agent/tool execution under critical memory pressure and warn under high pressure using macOSvm_stat+ swap telemetryauto-checkpoint,execution-gate,learning-bus-injector, andcorrection-detector3.10.0, and ignore platform sourcemaps inpackages/*/bin/*.mapWhy
Verification
Summary by cubic
Adds a reliability stack to prevent OOMs and improve session recovery. Adds memory gating for background tasks and session hooks for auto-restore/checkpointing and startup briefings.
New Features
Migration
/Library/Mobile Documents/iCloudmd~obsidian/Documents/Mind Palace with:Written for commit 3905a7b. Summary will update on new commits.