Skip to content

fix(viewer): graph tab blank on large graphs (graph/query pagination)#789

Merged
rohitg00 merged 1 commit into
mainfrom
fix/753-graph-pagination
Jun 2, 2026
Merged

fix(viewer): graph tab blank on large graphs (graph/query pagination)#789
rohitg00 merged 1 commit into
mainfrom
fix/753-graph-pagination

Conversation

@rohitg00

@rohitg00 rohitg00 commented Jun 2, 2026

Copy link
Copy Markdown
Owner

Closes #753.

POST /agentmemory/graph/query with an unbounded body {} on a corpus with 11k+ nodes returned HTTP 500 Invocation stopped because the response payload exceeded the iii state response channel ceiling. The viewer's api() returns null on non-2xx so the failure surfaced as "0 nodes / 0 edges" on a blank canvas with no signal. Same shape as #544; was never covered for graph/query.

Backend (src/functions/graph.ts)

  • mem::graph-query accepts limit + offset on every branch and applies a default cap (DEFAULT_GRAPH_QUERY_LIMIT = 500, MAX = 5000). An empty {} body never materializes the whole graph in one invocation.
  • Empty-body / nodeType-only branch ranks nodes by incident-edge degree before paginating, so the truncated page surfaces the densest subgraph rather than an arbitrary KV scan order.
  • Page edges are restricted to edges where both endpoints land in the page. Cross-page edges are dropped so the viewer doesn't render dangling lines.
  • Response shape extended: totalNodes, totalEdges, truncated, limit, offset. Totals reflect the unbounded result for the given filter so callers render "showing X of Y" without re-querying.

API (src/triggers/api.ts)

  • api::graph-query whitelists payload fields (startNodeId, nodeType, maxDepth, query, limit, offset) per AGENTS.md security rule. No more raw req.body spread.

Viewer (src/viewer/index.html)

  • Initial /graph/query sends { limit: 500 } instead of {}.
  • Distinguishes apiPost === null (server error) from { nodes: [], edges: [] } (truly empty corpus). Failure renders a visible Graph query failed banner with a Retry button instead of the "No graph data yet. Building..." empty state.
  • Truncation banner above the search box: "Showing N of M nodes (most-connected first). The full graph is too large to render at once."
  • state.graph gains queryError, truncated, totalNodes, totalEdges.

Tests (test/graph.test.ts)

4 new cases:

  • Unbounded {} body caps to 500 with truncated: true on a 1,200-node seed; the 50 high-degree nodes land on page 1.
  • limit + offset paginate without overlap on a 50-node seed.
  • limit: 999999 clamps to MAX_GRAPH_QUERY_LIMIT.
  • Cross-page edges excluded from page response; totalEdges still counts unbounded.

Full suite: 121 files / 1330 tests pass.

Edge cases handled

  • Cross-page dangling edges: edges to nodes off-page filtered out (test covers).
  • limit above MAX: clamped to 5000.
  • limit non-finite / negative: falls back to default 500 / clamped to 1.
  • offset past end: returns empty nodes page; totalNodes still accurate so the viewer can stop paging.
  • Viewer rebuild button: was already wired; now also surfaces in the error banner as "Retry".
  • Empty corpus: state.graph.stats.totalNodes === 0 path preserved (still triggers graph/build).
  • Viewer graph does not settle with >1000 nodes #563 (>1000 node layout settle): default cap is 500 — well below Viewer graph does not settle with >1000 nodes #563's threshold. The two fixes compose.

Acceptance map (issue #753)

  • Viewer issues a bounded initial query
  • graph/query accepts + enforces limit / offset, returns totalNodes/totalEdges, default cap when body is {}
  • Viewer renders backend errors as visible error state
  • Regression coverage for graph/query at 1,200+ nodes (proxy for 10k+)

Summary by CodeRabbit

  • New Features

    • Graph queries now support pagination with configurable limit and offset parameters.
    • UI displays truncation status and total node/edge counts when results are capped.
  • Bug Fixes

    • Fixed large graph query failures.
    • Improved error handling with actionable error banners and retry functionality.
  • Tests

    • Added pagination and limiting coverage tests for graph queries.

Closes #753.

POST /agentmemory/graph/query with an unbounded body ({}) on a corpus
with 11k+ nodes returned HTTP 500 'Invocation stopped' because the
response payload exceeded the iii state response channel ceiling.
Viewer's api() returns null on non-2xx so the failure surfaced as
'0 nodes / 0 edges' on a blank canvas with no signal — same shape as
#544, never covered for graph/query.

Backend (src/functions/graph.ts)

- mem::graph-query accepts limit + offset on every branch and applies
  a default cap (DEFAULT_GRAPH_QUERY_LIMIT = 500, MAX = 5000) so an
  empty {} body never materializes the whole graph in one invocation.
- Empty-body / nodeType-only branch ranks nodes by incident-edge
  degree before paginating so the truncated page surfaces the densest
  subgraph rather than an arbitrary KV scan order.
- Edges in the page response are restricted to edges with BOTH
  endpoints in the page; cross-page edges are dropped so the viewer
  doesn't render dangling lines.
- Response shape extended: totalNodes, totalEdges, truncated, limit,
  offset. totalNodes / totalEdges reflect the unbounded result for the
  given filter so callers can render 'showing X of Y' without
  re-querying.

API (src/triggers/api.ts)

- api::graph-query whitelists payload fields (startNodeId, nodeType,
  maxDepth, query, limit, offset) per AGENTS.md security rule. No
  more raw req.body spread.

Viewer (src/viewer/index.html)

- Initial /graph/query sends an explicit limit (500) rather than {}.
- Distinguishes apiPost === null (server error) from
  { nodes: [], edges: [] } (truly empty corpus). Failure now renders
  a visible 'Graph query failed' banner with a Retry button instead
  of the 'No graph data yet. Building...' empty state.
- Truncation banner above the search box: 'Showing N of M nodes
  (most-connected first). The full graph is too large to render at
  once.' so operators know the page is bounded.
- state.graph gains queryError, truncated, totalNodes, totalEdges
  fields.

Tests (test/graph.test.ts)

- Unbounded {} body caps to 500 with truncated=true on a 1,200-node
  seed; high-degree nodes land on page 1.
- limit + offset paginate without overlap on a 50-node seed.
- limit clamped above MAX returns at most MAX.
- Cross-page edges excluded from page response; totalEdges still
  counts unbounded.

121 test files / 1330 tests pass.
@vercel

vercel Bot commented Jun 2, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agentmemory Ready Ready Preview, Comment Jun 2, 2026 10:51pm

Request Review

@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds pagination and safety limits to graph queries to prevent unbounded full-graph materialization on large corpuses. It introduces default and maximum query limits, updates the result type with truncation metadata, sanitizes API payloads, and integrates bounded loading with error feedback in the viewer.

Changes

Graph Query Pagination and Safety

Layer / File(s) Summary
Pagination result type contract
src/types.ts
GraphQueryResult gains optional totalNodes, totalEdges, truncated, limit, and offset fields to support "showing N of M" UI patterns without re-querying.
Graph query pagination implementation
src/functions/graph.ts
Added DEFAULT_GRAPH_QUERY_LIMIT and MAX_GRAPH_QUERY_LIMIT constants; implemented resolvePagination, rankByDegree, and paginate helpers. Updated mem::graph-query signature to accept optional limit and offset, and integrated pagination across all branches (query, traversal, nodeType-only, empty-body).
API request sanitization
src/triggers/api.ts
Updated api::graph-query handler to define explicit request shape with limit and offset, constructs a whitelisted payload from specific request fields, and passes only sanitized input to the function trigger.
Viewer bounded graph loading and state
src/viewer/index.html
Extended state.graph with queryError, truncated, totalNodes, and totalEdges fields. Updated loadGraph() to pass an explicit initial limit to graph/query, distinguish query failures from empty results, populate truncation/total fields on success, and skip building on failure.
Viewer truncation feedback UI
src/viewer/index.html
Adjusted renderGraphSidebar() to render conditional banners for query errors (with Retry button) and truncated graphs ("Showing X of Y nodes"), placed above the search input.
Graph query pagination test coverage
test/graph.test.ts
Added four test suites: (1) default-limit capping with degree-based ranking, (2) limit+offset paging without overlaps, (3) explicit oversized limit clamping, and (4) edge filtering to fully-contained pairs while tracking full totalEdges.

Sequence Diagram

sequenceDiagram
  participant Viewer
  participant APIHandler as api::graph-query
  participant GraphQuery as mem::graph-query
  participant Paginate as paginate()
  
  Viewer->>APIHandler: POST graph/query {limit, offset, nodeType?}
  APIHandler->>APIHandler: Whitelist fields into payload
  APIHandler->>GraphQuery: Sanitized payload with limit/offset
  
  alt Query branch
    GraphQuery->>GraphQuery: Apply query filter
    GraphQuery->>Paginate: Collected nodes/edges
  else StartNodeId branch
    GraphQuery->>GraphQuery: Traverse from node
    GraphQuery->>Paginate: Traversed nodes/edges
  else NodeType or empty body
    GraphQuery->>GraphQuery: rankByDegree(nodes)
    GraphQuery->>Paginate: Ranked nodes/edges
  end
  
  Paginate->>Paginate: Slice to [offset, offset+limit)
  Paginate->>Paginate: Filter edges to contained endpoints
  Paginate->>Paginate: Compute unbounded totals
  
  GraphQuery->>APIHandler: GraphQueryResult + pagination metadata
  APIHandler->>Viewer: {nodes, edges, totalNodes, totalEdges, truncated, limit, offset}
  
  alt Success (null check)
    Viewer->>Viewer: Set state.graph fields, build/render
  else Failure (null result)
    Viewer->>Viewer: Set queryError, render error banner
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

A rabbit hops through graphs so grand,
But bounded now, at last they stand!
With limits set and pages neat,
Large corpuses no longer cheat.
The viewer shows the truth at last:
"Showing N of M"—the die is cast! 🐰📊

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly identifies the main change: fixing the viewer's blank graph tab on large graphs by implementing pagination.
Linked Issues check ✅ Passed The PR fully addresses all coding objectives from issue #753: pagination support in graph/query with limits/offsets, bounded default responses, error surface in viewer, and test coverage for large graphs.
Out of Scope Changes check ✅ Passed All code changes are directly aligned with fixing issue #753: backend pagination logic, API whitelisting, viewer error handling, and regression tests are all in scope.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/753-graph-pagination

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
src/triggers/api.ts (1)

1346-1355: 💤 Low value

Whitelist implementation is correct.

The explicit payload construction properly follows the coding guideline requiring REST endpoints to never pass raw req.body to sdk.trigger.

For consistency with other endpoints (e.g., api::search validates limit), consider adding input validation for limit and offset at the API boundary. Since the backend handles clamping via resolvePagination, this is optional.

♻️ Optional: Add boundary validation
     const authErr = checkAuth(req, secret);
     if (authErr) return authErr;
+    const body = (req.body ?? {}) as Record<string, unknown>;
+    if (
+      body.limit !== undefined &&
+      (!Number.isInteger(body.limit) || (body.limit as number) < 1)
+    ) {
+      return { status_code: 400, body: { error: "limit must be a positive integer" } };
+    }
+    if (
+      body.offset !== undefined &&
+      (!Number.isInteger(body.offset) || (body.offset as number) < 0)
+    ) {
+      return { status_code: 400, body: { error: "offset must be a non-negative integer" } };
+    }
     // Whitelist payload fields explicitly; AGENTS.md security rule:
     // REST endpoints never pass raw req.body through to sdk.trigger.
     const payload = {

As per coding guidelines: {src/mcp/**,src/triggers/**}/*.ts: Perform input validation at system boundaries.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/triggers/api.ts` around lines 1346 - 1355, The payload is properly
whitelisted but lacks API-boundary validation for pagination; add simple input
checks before constructing payload: validate and coerce req.body.limit and
req.body.offset to safe integers (e.g., ensure non-negative integers and apply
sensible defaults) so payload.limit and payload.offset are always numeric, and
keep backend clamping via resolvePagination; update the block building payload
(referencing payload, req.body, sdk.trigger, and resolvePagination) to perform
these checks consistent with api::search.
test/graph.test.ts (2)

339-366: 💤 Low value

Consider condensing the implementation-detail comments.

The comments on lines 339-366 explain HOW the test works (tight cluster, degree ranking, cross-page edge mechanics). While helpful, they narrate WHAT the code does rather than WHY. The setup code and assertions are self-documenting.

♻️ Suggested simplification
-    // Make the first 10 nodes a tightly connected cluster so they
-    // rank highest by degree and land on the page deterministically.
+    // First 10 nodes form a cluster (high degree → ranked first).
     for (let i = 0; i < 10; i++) {
       const next = (i + 1) % 10;
       await kv.set("mem:graph:edges", `cluster_${i}`, {
@@ -353,10 +339,7 @@
       });
     }
-    // Cross-page edge: source in the high-degree cluster (on page),
-    // target is an isolated node (degree 1; cluster nodes have
-    // degree 2 so the target ranks below the cap).
+    // Cross-page edge: source on-page, target off-page.
     await kv.set("mem:graph:edges", "cross", {

As per coding guidelines: "No code comments explaining WHAT — use clear naming instead" for src/**/*.ts.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/graph.test.ts` around lines 339 - 366, Replace the multi-line HOW
comments above the cluster creation loop and the "cross" edge with a single
concise purpose comment: e.g., "Create a high-degree cluster and a cross-page
edge to exercise degree-based pagination." Keep the setup code as-is (the for
loop that calls kv.set("mem:graph:edges", `cluster_${i}`...) and the subsequent
kv.set("mem:graph:edges", "cross", ...)), but remove the detailed step-by-step
narrative and keep only the short WHY-focused comment so the self-documenting
names (cluster_${i}, "cross", sourceNodeId x_005, targetNodeId x_055) describe
WHAT is happening.

218-223: ⚡ Quick win

Remove or condense the explanatory comment.

This comment explains WHAT the code does rather than WHY it exists. As per coding guidelines, use clear naming instead of comments explaining WHAT. The test name and assertions already document the expected behavior.

♻️ Suggested simplification
-  // `#753`: an unbounded {} body used to materialize every node+edge in
-  // one payload, which exceeded the iii state response channel on
-  // large corpora (11k+ nodes) and returned HTTP 500 "Invocation
-  // stopped". The fix caps the page at DEFAULT_GRAPH_QUERY_LIMIT (500)
-  // and surfaces totalNodes / totalEdges so callers know it was
-  // truncated.
+  // `#753`
   it("caps an unbounded graph-query body to a default page and reports totals", async () => {

As per coding guidelines: "No code comments explaining WHAT — use clear naming instead" for src/**/*.ts.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/graph.test.ts` around lines 218 - 223, Remove or greatly shorten the
explanatory comment block that describes what the test does; instead rely on the
test name and assertions to document behavior and (if a short note is still
helpful) replace it with a one-line rationale like "Ensure pagination prevents
unbounded payloads" referencing DEFAULT_GRAPH_QUERY_LIMIT so readers know the
limit being asserted; update or trim the comment around the test asserting
DEFAULT_GRAPH_QUERY_LIMIT, totalNodes, and totalEdges to a single-line WHY note
or delete it entirely.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/viewer/index.html`:
- Around line 1718-1726: When handling the post-rebuild freshResults, ensure we
set a visible query error if the subsequent graph/query failed: check
freshResults[0] (freshQuery) and if it is falsy, assign state.graph.queryError
to freshResults[1] (or a small default error object/message) so the UI shows an
error banner; otherwise proceed to clear/set state.graph.nodes, edges,
truncated, totalNodes, totalEdges and ensure state.graph.queryError is cleared
when the query succeeds. Reference symbols: freshResults, freshQuery,
state.graph, state.graph.queryError, graph/query.

---

Nitpick comments:
In `@src/triggers/api.ts`:
- Around line 1346-1355: The payload is properly whitelisted but lacks
API-boundary validation for pagination; add simple input checks before
constructing payload: validate and coerce req.body.limit and req.body.offset to
safe integers (e.g., ensure non-negative integers and apply sensible defaults)
so payload.limit and payload.offset are always numeric, and keep backend
clamping via resolvePagination; update the block building payload (referencing
payload, req.body, sdk.trigger, and resolvePagination) to perform these checks
consistent with api::search.

In `@test/graph.test.ts`:
- Around line 339-366: Replace the multi-line HOW comments above the cluster
creation loop and the "cross" edge with a single concise purpose comment: e.g.,
"Create a high-degree cluster and a cross-page edge to exercise degree-based
pagination." Keep the setup code as-is (the for loop that calls
kv.set("mem:graph:edges", `cluster_${i}`...) and the subsequent
kv.set("mem:graph:edges", "cross", ...)), but remove the detailed step-by-step
narrative and keep only the short WHY-focused comment so the self-documenting
names (cluster_${i}, "cross", sourceNodeId x_005, targetNodeId x_055) describe
WHAT is happening.
- Around line 218-223: Remove or greatly shorten the explanatory comment block
that describes what the test does; instead rely on the test name and assertions
to document behavior and (if a short note is still helpful) replace it with a
one-line rationale like "Ensure pagination prevents unbounded payloads"
referencing DEFAULT_GRAPH_QUERY_LIMIT so readers know the limit being asserted;
update or trim the comment around the test asserting DEFAULT_GRAPH_QUERY_LIMIT,
totalNodes, and totalEdges to a single-line WHY note or delete it entirely.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 35319d50-34ca-4745-8205-957eafb56348

📥 Commits

Reviewing files that changed from the base of the PR and between 9a4bdbe and 436c86c.

📒 Files selected for processing (5)
  • src/functions/graph.ts
  • src/triggers/api.ts
  • src/types.ts
  • src/viewer/index.html
  • test/graph.test.ts

Comment thread src/viewer/index.html
Comment on lines +1718 to 1726
var freshQuery = freshResults[0];
if (freshQuery) {
state.graph.nodes = freshQuery.nodes || [];
state.graph.edges = freshQuery.edges || [];
state.graph.truncated = freshQuery.truncated === true;
state.graph.totalNodes = typeof freshQuery.totalNodes === 'number' ? freshQuery.totalNodes : state.graph.nodes.length;
state.graph.totalEdges = typeof freshQuery.totalEdges === 'number' ? freshQuery.totalEdges : state.graph.edges.length;
}
state.graph.stats = freshResults[1] || {};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Handle post-rebuild query failure.

If the rebuild succeeds but the subsequent graph/query request fails (returns null), the viewer does not set state.graph.queryError, so no error banner is shown. The user sees an empty graph with no indication that the query failed.

While rare (requires first load + successful build + failed query), this violates the PR objective to surface backend errors as a visible error state instead of falling silent.

🛡️ Proposed fix to set queryError when fresh query fails
       var freshResults = await Promise.all([
         apiPost('graph/query', { limit: GRAPH_INITIAL_LIMIT }),
         apiGet('graph/stats')
       ]);
       var freshQuery = freshResults[0];
       if (freshQuery) {
         state.graph.nodes = freshQuery.nodes || [];
         state.graph.edges = freshQuery.edges || [];
         state.graph.truncated = freshQuery.truncated === true;
         state.graph.totalNodes = typeof freshQuery.totalNodes === 'number' ? freshQuery.totalNodes : state.graph.nodes.length;
         state.graph.totalEdges = typeof freshQuery.totalEdges === 'number' ? freshQuery.totalEdges : state.graph.edges.length;
+      } else {
+        state.graph.queryError = 'graph/query failed after rebuild (check server logs)';
       }
       state.graph.stats = freshResults[1] || {};
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
var freshQuery = freshResults[0];
if (freshQuery) {
state.graph.nodes = freshQuery.nodes || [];
state.graph.edges = freshQuery.edges || [];
state.graph.truncated = freshQuery.truncated === true;
state.graph.totalNodes = typeof freshQuery.totalNodes === 'number' ? freshQuery.totalNodes : state.graph.nodes.length;
state.graph.totalEdges = typeof freshQuery.totalEdges === 'number' ? freshQuery.totalEdges : state.graph.edges.length;
}
state.graph.stats = freshResults[1] || {};
var freshQuery = freshResults[0];
if (freshQuery) {
state.graph.nodes = freshQuery.nodes || [];
state.graph.edges = freshQuery.edges || [];
state.graph.truncated = freshQuery.truncated === true;
state.graph.totalNodes = typeof freshQuery.totalNodes === 'number' ? freshQuery.totalNodes : state.graph.nodes.length;
state.graph.totalEdges = typeof freshQuery.totalEdges === 'number' ? freshQuery.totalEdges : state.graph.edges.length;
} else {
state.graph.queryError = 'graph/query failed after rebuild (check server logs)';
}
state.graph.stats = freshResults[1] || {};
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/viewer/index.html` around lines 1718 - 1726, When handling the
post-rebuild freshResults, ensure we set a visible query error if the subsequent
graph/query failed: check freshResults[0] (freshQuery) and if it is falsy,
assign state.graph.queryError to freshResults[1] (or a small default error
object/message) so the UI shows an error banner; otherwise proceed to clear/set
state.graph.nodes, edges, truncated, totalNodes, totalEdges and ensure
state.graph.queryError is cleared when the query succeeds. Reference symbols:
freshResults, freshQuery, state.graph, state.graph.queryError, graph/query.

@rohitg00 rohitg00 merged commit 3e806c9 into main Jun 2, 2026
7 checks passed
rohitg00 added a commit that referenced this pull request Jun 2, 2026
Bump to 0.9.25 across 9 files + CHANGELOG.

Closes #778 #775 #783 (PR #791), #758 #726 (PR #773), #759 (PR #772),
#752 (PR #774), #729 (PR #780), #781 (PR #782), #753 (PR #789), #771
(PR #786), #762 (PR #764).

Files bumped:
  - package.json
  - packages/mcp/package.json
  - plugin/.claude-plugin/plugin.json
  - plugin/.codex-plugin/plugin.json
  - plugin/plugin.json
  - src/version.ts
  - src/types.ts (ExportData.version union)
  - src/functions/export-import.ts (supportedVersions Set)
  - test/export-import.test.ts (assertion)

125 test files / 1379 tests pass. npm audit (root + website): 0 vulns.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant