Commit Graph

579 Commits

Author SHA1 Message Date
YeonGyu-Kim 70f96d4e24 fix: rename prompt_async to promptAsync for SDK compatibility 2026-02-16 16:52:06 +09:00
YeonGyu-Kim b69fa7bda8 fix: normalize SDK response shape in readMessagesFromSDK
Use response.data ?? response to handle both object and array-shaped
SDK responses, consistent with all other SDK readers.
2026-02-16 16:13:40 +09:00
YeonGyu-Kim 64000785c7 fix: handle array-shaped SDK responses in getSdkMessages & dedup getMessageDir
- getSdkMessages now handles both response.data and direct array
  responses from SDK
- Consolidated getMessageDir: storage.ts now re-exports from shared
  opencode-message-dir.ts (with path traversal guards)
2026-02-16 16:13:40 +09:00
YeonGyu-Kim 2f6990890f 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 99272cddc0 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 9c2a92c235 docs: regenerate all 13 AGENTS.md files from deep codebase exploration 2026-02-16 16:13:40 +09:00
YeonGyu-Kim 052f52822c 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 e21c784cc5 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 39813842de 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 dc5e51598e 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 2cefc8818c 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 6f18113e99 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 8ddc37b61a 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 1c1c9d0bbc 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 ff7ba411ff 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 d0870d6fbe 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 432dcb039d 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 5c37dc8210 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 febc0de38f 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 a0668de9ea 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 ca622cbfb9 feat: migrate hook callers to SDK message finders on SQLite backend 2026-02-16 16:13:40 +09:00
YeonGyu-Kim a18ec856c6 feat: add SDK read paths for session-recovery parts/messages readers 2026-02-16 16:13:40 +09:00
YeonGyu-Kim 4574544849 feat: add SDK/HTTP paths for tool-result-storage truncation 2026-02-16 16:13:40 +09:00
YeonGyu-Kim f72773346b feat: implement SQLite backend for replaceEmptyTextParts via HTTP PATCH 2026-02-16 16:13:40 +09:00
YeonGyu-Kim 458f374bb1 feat: implement SQLite backend for prependThinkingPart via HTTP PATCH 2026-02-16 16:13:40 +09:00
YeonGyu-Kim 63af40713b feat: implement SQLite backend for injectTextPart via HTTP PATCH 2026-02-16 16:13:40 +09:00
YeonGyu-Kim b56ee901ee feat: implement SQLite backend for stripThinkingParts via HTTP DELETE 2026-02-16 16:13:40 +09:00
YeonGyu-Kim 6ca9a21048 fix: add explicit isSqliteBackend guards to pruning modules 2026-02-16 16:13:40 +09:00
YeonGyu-Kim a8d02b3e99 feat: add SDK path for getMessageIds in context-window recovery 2026-02-16 16:13:40 +09:00
YeonGyu-Kim e0fcd4f78d 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 d4b9246573 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 0708038712 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 31e9829741 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 804895b24a 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 e80211c1fd feat(context-window-recovery): gate JSON writes on OpenCode beta 2026-02-16 16:13:40 +09:00
YeonGyu-Kim 1d5920235f refactor(shared): consolidate 13+ getMessageDir copies into single shared function 2026-02-16 16:13:39 +09:00
YeonGyu-Kim ed098925b5 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 4f976c27a1 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 a747d0f253 fix: add post-max-failure recovery window for todo continuation 2026-02-16 15:27:00 +09:00
YeonGyu-Kim 0a2ec5d251 fix: apply cooldown on injection failure and cap retries 2026-02-16 15:00:41 +09:00
YeonGyu-Kim f734e9e600 fix: prevent duplicate compaction race and log preemptive failures 2026-02-16 14:58:59 +09:00
YeonGyu-Kim 75cfa966ec test(directory-readme-injector): use real files instead of fs module mocks 2026-02-14 22:06:57 +09:00
YeonGyu-Kim 98a9e29bd4 test(directory-agents-injector): use real files instead of fs module mocks 2026-02-14 22:06:52 +09:00
YeonGyu-Kim c569a58306 test(rules-injector): restore bun mocks after suite 2026-02-14 22:06:39 +09:00
YeonGyu-Kim f6b37ac45e test(atlas): reset session state instead of module mocking 2026-02-14 22:06:34 +09:00
YeonGyu-Kim 39e4cb2ec6 test(prometheus-md-only): avoid hook-message storage constant mocking 2026-02-14 22:06:28 +09:00
YeonGyu-Kim 9a1d228a36 test(todo-continuation-enforcer): stabilize fake timers 2026-02-14 22:06:18 +09:00
YeonGyu-Kim c2a8f360b5 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 022f60081b 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 83f1505c28 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