576 Commits

Author SHA1 Message Date
YeonGyu-Kim
5a6a9e9800 fix: defensive SDK response handling & parts-reader normalization
- Replace all response.data ?? [] with (response.data ?? response)
  pattern across 14 files to handle SDK array-shaped responses
- Normalize SDK parts in parts-reader.ts by injecting sessionID/
  messageID before validation (P1: SDK parts lack these fields)
- Treat unknown part types as having content in
  recover-empty-content-message-sdk.ts to prevent false placeholder
  injection on image/file parts
- Replace local isRecord with shared import in parts-reader.ts
2026-02-16 16:13:40 +09:00
YeonGyu-Kim
8edf6ed96f fix: address 5 SDK compatibility issues from Cubic round 8
- P1: Use compacted timestamp check instead of nonexistent truncated
  field in target-token-truncation.ts
- P1: Use defensive (response.data ?? response) pattern in
  hook-message-injector/injector.ts to match codebase convention
- P2: Filter by tool type in countTruncatedResultsFromSDK to avoid
  counting non-tool compacted parts
- P2: Treat thinking/meta-only messages as empty in both
  empty-content-recovery-sdk.ts and message-builder.ts to align
  SDK path with file-based logic
2026-02-16 16:13:40 +09:00
YeonGyu-Kim
cfb8164d9a docs: regenerate all 13 AGENTS.md files from deep codebase exploration 2026-02-16 16:13:40 +09:00
YeonGyu-Kim
c2012c6027 fix: address 8-domain Oracle review findings (C1, C2, M1-M4)
- C1: thinking-prepend unique part IDs per message (global PK collision)
- C2: recover-thinking-disabled-violation try/catch guard on SDK call
- M1: remove non-schema truncated/originalSize fields from SDK interfaces
- M2: messageHasContentFromSDK treats thinking-only messages as non-empty
- M3: syncAllTasksToTodos persists finalTodos + no-id rename dedup guard
- M4: AbortSignal.timeout(30s) on HTTP fetch calls in opencode-http-api

All 2739 tests pass, typecheck clean.
2026-02-16 16:13:40 +09:00
YeonGyu-Kim
106cd5c8b1 fix: re-read fresh messages before empty scan & dedup isRecord import
- Re-read messages from SDK after injectTextPartAsync to prevent stale
  snapshot from causing duplicate placeholder injection (P2)
- Replace local isRecord with shared import from record-type-guard (P3)
2026-02-16 16:13:40 +09:00
YeonGyu-Kim
c799584e61 fix: address Cubic round-6 P2/P3 issues
- P2: treat unknown part types as non-content in message-builder messageHasContentFromSDK
- P3: reuse shared isRecord from record-type-guard.ts in opencode-http-api
2026-02-16 16:13:40 +09:00
YeonGyu-Kim
3fe9c1f6e4 fix: address Cubic round-5 P1/P2 issues
- P1: add path traversal guard to getMessageDir (reject .., /, \)
- P2: treat unknown part types as non-content in messageHasContentFromSDK
2026-02-16 16:13:40 +09:00
YeonGyu-Kim
885c8586d2 fix: revert messageHasContentFromSDK unknown type handling
Unknown part types should be treated as content (return true)
to match parity with the existing message-builder implementation.
Using continue would incorrectly mark messages with unknown part
types as empty, triggering false recovery.
2026-02-16 16:13:40 +09:00
YeonGyu-Kim
8d82025b70 fix: address Cubic round-4 P2 issues
- isTodo: allow optional id to match Todo interface, preventing
  todos without ids from being silently dropped
- messageHasContentFromSDK: treat unknown part types as empty
  (continue) instead of content (return true) for parity with
  existing storage logic
- readMessagesFromSDK in recover-empty-content-message-sdk: wrap
  SDK call in try/catch to prevent recovery from throwing
2026-02-16 16:13:40 +09:00
YeonGyu-Kim
557340af68 fix: restore readMessagesFromSDK and its test
The previous commit incorrectly removed this function and its test
as dead code. While the local implementations in other files have
different return types (MessageData[], MessagePart[]) and cannot be
replaced by this shared version, the function is a valid tested
utility. Deleting tests is an anti-pattern in this project.
2026-02-16 16:13:40 +09:00
YeonGyu-Kim
d7b38d7c34 fix: address Cubic round-3 P2/P3 issues
- Encode path segments with encodeURIComponent in HTTP API URLs
  to prevent broken requests when IDs contain special characters
- Remove unused readMessagesFromSDK from messages-reader.ts
  (production callers use local implementations; dead code)
2026-02-16 16:13:40 +09:00
YeonGyu-Kim
880b53c511 fix: address Cubic round-2 P2 issues
- target-token-truncation: eliminate redundant SDK messages fetch by
  extracting tool results from already-fetched toolPartsByKey map
- recover-thinking-block-order: wrap SDK message fetches in try/catch
  so recovery continues gracefully on API errors
- thinking-strip: guard against missing part.id before calling
  deletePart to prevent invalid HTTP requests
2026-02-16 16:13:40 +09:00
YeonGyu-Kim
3bbe0cbb1d feat: implement SDK/HTTP pruning for deduplication and tool-output truncation on SQLite
- executeDeduplication: now async, reads messages from SDK on SQLite via
  client.session.messages() instead of JSON file reads
- truncateToolOutputsByCallId: now async, uses truncateToolResultAsync()
  HTTP PATCH on SQLite instead of file-based truncateToolResult()
- deduplication-recovery: passes client through to both functions
- recovery-hook: passes ctx.client to attemptDeduplicationRecovery

Removes the last intentional feature gap on SQLite backend — dynamic
context pruning (dedup + tool-output truncation) now works on both
JSON and SQLite storage backends.
2026-02-16 16:13:40 +09:00
YeonGyu-Kim
52161ef69f fix: add SDK readParts fallback for recoverToolResultMissing on SQLite
On SQLite backend, readParts() returns [] since JSON files don't exist.
Add isSqliteBackend() branch that reads parts from SDK via
client.session.messages() when failedAssistantMsg.parts is empty.
2026-02-16 16:13:40 +09:00
YeonGyu-Kim
62e4e57455 feat: wire context-window-recovery callers to async SDK/HTTP variants on SQLite
- empty-content-recovery: isSqliteBackend() branch delegating to extracted
  empty-content-recovery-sdk.ts with SDK message scanning
- message-builder: sanitizeEmptyMessagesBeforeSummarize now async with SDK path
  using replaceEmptyTextPartsAsync/injectTextPartAsync
- target-token-truncation: truncateUntilTargetTokens now async with SDK path
  using findToolResultsBySizeFromSDK/truncateToolResultAsync
- aggressive-truncation-strategy: passes client to truncateUntilTargetTokens
- summarize-retry-strategy: await sanitizeEmptyMessagesBeforeSummarize
- client.ts: derive Client from PluginInput['client'] instead of manual defs
- executor.test.ts: .mockReturnValue() → .mockResolvedValue() for async fns
- storage.test.ts: add await for async truncateUntilTargetTokens
2026-02-16 16:13:40 +09:00
YeonGyu-Kim
dff3a551d8 feat: wire session-recovery callers to async SDK/HTTP variants on SQLite
- recover-thinking-disabled-violation: isSqliteBackend() branch using
  stripThinkingPartsAsync() with SDK message enumeration
- recover-thinking-block-order: isSqliteBackend() branch using
  prependThinkingPartAsync() with SDK orphan thinking detection
- recover-empty-content-message: isSqliteBackend() branch delegating to
  extracted recover-empty-content-message-sdk.ts (200 LOC limit)
- storage.ts barrel: add async variant exports for all SDK functions
2026-02-16 16:13:40 +09:00
YeonGyu-Kim
0a085adcd6 fix(test): rewrite SDK reader tests to use mock client objects instead of mock.module 2026-02-16 16:13:40 +09:00
YeonGyu-Kim
2bf8b15f24 feat: migrate hook callers to SDK message finders on SQLite backend 2026-02-16 16:13:40 +09:00
YeonGyu-Kim
af8de2eaa2 feat: add SDK read paths for session-recovery parts/messages readers 2026-02-16 16:13:40 +09:00
YeonGyu-Kim
1197f919af feat: add SDK/HTTP paths for tool-result-storage truncation 2026-02-16 16:13:40 +09:00
YeonGyu-Kim
808de5836d feat: implement SQLite backend for replaceEmptyTextParts via HTTP PATCH 2026-02-16 16:13:40 +09:00
YeonGyu-Kim
f69820e76e feat: implement SQLite backend for prependThinkingPart via HTTP PATCH 2026-02-16 16:13:40 +09:00
YeonGyu-Kim
c771eb5acd feat: implement SQLite backend for injectTextPart via HTTP PATCH 2026-02-16 16:13:40 +09:00
YeonGyu-Kim
049a259332 feat: implement SQLite backend for stripThinkingParts via HTTP DELETE 2026-02-16 16:13:40 +09:00
YeonGyu-Kim
d414f6daba fix: add explicit isSqliteBackend guards to pruning modules 2026-02-16 16:13:40 +09:00
YeonGyu-Kim
0c6fe3873c feat: add SDK path for getMessageIds in context-window recovery 2026-02-16 16:13:40 +09:00
YeonGyu-Kim
2a7535bb48 fix(test): mock isSqliteBackend in prometheus-md-only tests for SQLite environments
On machines running OpenCode beta (v1.1.53+) with SQLite backend,
getMessageDir() returns null because isSqliteBackend() returns true.
This caused all 15 message-storage-dependent tests to fail.

Fix: mock opencode-storage-detection to force JSON mode, and use
ses_ prefixed session IDs to match getMessageDir's validation.
2026-02-16 16:13:40 +09:00
YeonGyu-Kim
4cf3bc431b refactor(shared): unify MESSAGE_STORAGE/PART_STORAGE constants into single source
- Create src/shared/opencode-storage-paths.ts with all 4 constants
- Update 4 previous declaration sites to import from shared file
- Update additional OPENCODE_STORAGE usages for consistency
- Re-export from src/shared/index.ts
- No duplicate constant declarations remain
2026-02-16 16:13:40 +09:00
YeonGyu-Kim
068831f79e refactor: cleanup shared constants and add async SDK support for isCallerOrchestrator
- Use shared OPENCODE_STORAGE, MESSAGE_STORAGE, PART_STORAGE constants
- Make isCallerOrchestrator async with SDK fallback for beta
- Fix cache implementation using Symbol sentinel
- Update atlas hooks and sisyphus-junior-notepad to use async isCallerOrchestrator
2026-02-16 16:13:40 +09:00
YeonGyu-Kim
07da116671 fix: address Cubic review comments (P2/P3 issues)
- Fix empty catch block in opencode-message-dir.ts (P2)

- Add log deduplication for truncateToolResult to prevent spam (P3)
2026-02-16 16:13:40 +09:00
YeonGyu-Kim
49dafd3c91 feat(storage): gate JSON write operations on OpenCode beta, document degraded features
- Gate session-recovery writes: injectTextPart, prependThinkingPart, replaceEmptyTextParts, stripThinkingParts

- Gate context-window-recovery writes: truncateToolResult

- Add isSqliteBackend() checks with log warnings

- Create beta-degraded-features.md documentation
2026-02-16 16:13:40 +09:00
YeonGyu-Kim
e34fbd08a9 feat(context-window-recovery): gate JSON writes on OpenCode beta 2026-02-16 16:13:40 +09:00
YeonGyu-Kim
c9c02e0525 refactor(shared): consolidate 13+ getMessageDir copies into single shared function 2026-02-16 16:13:39 +09:00
YeonGyu-Kim
e90734d6d9 fix(todo): make Todo id field optional for OpenCode beta compatibility
- Make id field optional in all Todo interfaces (TodoInfo, Todo, TodoItem)
- Fix null-unsafe comparisons in todo-sync.ts to handle missing ids
- Add test case for todos without id field preservation
- All tests pass and typecheck clean
2026-02-16 16:13:39 +09:00
YeonGyu-Kim
7e6982c8d8
Merge pull request #1878 from code-yeongyu/fix/1806-todo-enforcer-cooldown
fix: apply cooldown on injection failure and add max retry limit (#1806)
2026-02-16 15:42:24 +09:00
YeonGyu-Kim
2a4009e692 fix: add post-max-failure recovery window for todo continuation 2026-02-16 15:27:00 +09:00
YeonGyu-Kim
c2f22cd6e5 fix: apply cooldown on injection failure and cap retries 2026-02-16 15:00:41 +09:00
YeonGyu-Kim
6a90182503 fix: prevent duplicate compaction race and log preemptive failures 2026-02-16 14:58:59 +09:00
YeonGyu-Kim
dcb76f7efd test(directory-readme-injector): use real files instead of fs module mocks 2026-02-14 22:06:57 +09:00
YeonGyu-Kim
7b62f0c68b test(directory-agents-injector): use real files instead of fs module mocks 2026-02-14 22:06:52 +09:00
YeonGyu-Kim
2b4651e119 test(rules-injector): restore bun mocks after suite 2026-02-14 22:06:39 +09:00
YeonGyu-Kim
37d3086658 test(atlas): reset session state instead of module mocking 2026-02-14 22:06:34 +09:00
YeonGyu-Kim
e7dc3721df test(prometheus-md-only): avoid hook-message storage constant mocking 2026-02-14 22:06:28 +09:00
YeonGyu-Kim
3a690965fd test(todo-continuation-enforcer): stabilize fake timers 2026-02-14 22:06:18 +09:00
YeonGyu-Kim
cdda08cdb0
Merge pull request #1832 from code-yeongyu/fix/issue-1691-antigravity-error
fix: resilient error parsing for non-standard providers
2026-02-14 15:01:14 +09:00
YeonGyu-Kim
072b30593e fix(parser): wrap parseAnthropicTokenLimitError in try/catch
Add outer try/catch to prevent crashes from non-standard error objects
returned by proxy providers (e.g., Antigravity). Add parser tests
covering edge cases: circular refs, non-object data fields, invalid
JSON in responseBody.
2026-02-14 14:58:06 +09:00
YeonGyu-Kim
dd9eeaa6d6 test(session-recovery): add tests for detect-error-type resilience
Add test coverage for detectErrorType and extractMessageIndex with
edge cases: circular references, non-standard proxy errors, null input.
Wrap both functions in try/catch to prevent crashes from malformed
error objects returned by non-standard providers like Antigravity.
2026-02-14 14:58:06 +09:00
YeonGyu-Kim
9f52e48e8f fix(think-mode): disable thinking parameter for Z.ai GLM models
Z.ai GLM models don't support thinking/reasoning parameters.
Ensure these are omitted entirely to prevent empty responses.

Fixes #980

Community-reported-by: @iserifith
2026-02-14 14:58:02 +09:00
YeonGyu-Kim
c8cd6370e2
Merge pull request #1817 from code-yeongyu/fix/todo-continuation-always-fire
fix(todo-continuation-enforcer): fire continuation for all sessions with incomplete todos
2026-02-14 11:43:10 +09:00
YeonGyu-Kim
f876d60e87
Merge pull request #1750 from ojh102/fix/guard-non-string-tool-output
fix(hooks): guard against non-string tool output in afterToolResult hooks
2026-02-13 18:52:18 +09:00