Skip to content

feat: decompress tool range mode (startId/endId) — issue #14#73

Open
ranxianglei wants to merge 1 commit into
masterfrom
2026-07-07_decompress-range-mode
Open

feat: decompress tool range mode (startId/endId) — issue #14#73
ranxianglei wants to merge 1 commit into
masterfrom
2026-07-07_decompress-range-mode

Conversation

@ranxianglei

Copy link
Copy Markdown
Owner

Summary

Adds optional startId/endId params to the decompress tool schema as an alternative to blockId. Range mode batch-restores every active block whose effectiveMessageIds overlaps the resolved message range in one call — eliminating the acp_status → decompress-per-block loop.

Mirrors Gitea PR #15.

Changes

  • lib/compress/decompress.ts — schema gains optional startId/endId; handler refactored into resolveTargets dispatcher → resolveSingleBlockTarget (unchanged) | resolveRangeTarget (new). Shared tail handles N targets (toFile gather, deactivate loop, pluralized report).
  • lib/compress/decompress-logic.ts — new exported findActiveBlocksOverlappingMessages(messagesState, messageIdSet). Pure, O(blocks × effectiveIds), dedupes via Map, returns sorted by blockId.
  • tests/decompress-logic.test.ts — 11 new tests covering empty set, no blocks, overlap match, inactive skip, partial overlap, multi-block sort, dedupe, disjoint, undefined effectiveIds, nested child-only, nested ancestor+child.
  • devlog/2026-07-07_decompress-range-mode/ — REQ.md, DESIGN.md, WORKLOG.md.

Design highlights

  • Reuses compress/search.ts for boundary resolution — inherits Bug 34 (auto-swap reversed boundaries), OOB clamping, and recovery hints for free.
  • Nested correctness without a parent-chain walk: a child block's effectiveMessageIds ⊇ consumed ancestor's effective IDs, so both are always matched when the range overlaps. Proof in devlog/2026-07-07_decompress-range-mode/DESIGN.md.
  • Backward compatible: blockId path byte-identical to before. New fields are optional; blockId XOR (startId AND endId) enforced at handler level with clear errors.

Schema

decompress({
  blockId?: string,      // "b0" — use this OR startId+endId
  startId?:  string,     // "m00150" — range start
  endId?:    string,     // "m00200" — range end
  toFile?:   string,     // optional, writes to file instead of inflating context
})

Edge cases handled

  • blockId + startId/endId mixed → mutual-exclusivity error
  • Only one of startId/endId → error
  • Range with no overlapping active blocks → error pointing to acp_status
  • Reversed boundaries → auto-swapped (Bug 34 fix)
  • Partial overlap → whole block decompressed (atomic)
  • Nested blocks → both ancestor and child restored

Verification

  • npm run typecheck — PASS
  • npm run build — PASS (dist/index.js 357 KB)
  • bun test tests/ — 586 pass, 1 pre-existing fail (Bun limitation in prompts.test.ts:53 — nested test() unsupported; verified on master via stash/pop)

Follow-ups

Add optional startId/endId params to decompress schema as alternative to
blockId. Range mode batch-restores every active block whose
effectiveMessageIds overlaps the resolved message range in one call,
eliminating the acp_status → decompress-per-block loop.

Changes:
- lib/compress/decompress.ts: schema gains optional startId/endId;
  handler refactored into resolveTargets dispatcher → single-block
  (unchanged logic) | range (new). Shared tail handles N targets.
- lib/compress/decompress-logic.ts: new findActiveBlocksOverlappingMessages
  pure function.
- tests/decompress-logic.test.ts: 11 new tests for overlap resolution.

Boundary resolution reuses compress/search.ts (auto-swap reversed
boundaries via Bug 34 fix, OOB clamping, recovery hints). Nested
correctness: child effectiveMessageIds ⊇ consumed ancestor's, so both
matched automatically — no separate parent-chain walk needed.

Backward compatible: blockId path byte-identical to before; new fields
are optional and mutually exclusive with blockId (handler rejects mixes).

Tests: 586 pass, 1 pre-existing unrelated Bun limitation (prompts.test.ts
nested test(), verified on master).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant