figjam-context-mcp 0.0.0-stage → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/.env.example +66 -0
  2. package/CHANGELOG.md +43 -0
  3. package/LICENSE +21 -0
  4. package/README.md +149 -2
  5. package/SECURITY.md +26 -0
  6. package/dist/index.d.ts +2 -0
  7. package/dist/index.js +20 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/lib/boardDiff.d.ts +55 -0
  10. package/dist/lib/boardDiff.js +285 -0
  11. package/dist/lib/boardDiff.js.map +1 -0
  12. package/dist/lib/cache.d.ts +9 -0
  13. package/dist/lib/cache.js +63 -0
  14. package/dist/lib/cache.js.map +1 -0
  15. package/dist/lib/connectorGraph.d.ts +32 -0
  16. package/dist/lib/connectorGraph.js +121 -0
  17. package/dist/lib/connectorGraph.js.map +1 -0
  18. package/dist/lib/docStructureMapper.d.ts +24 -0
  19. package/dist/lib/docStructureMapper.js +121 -0
  20. package/dist/lib/docStructureMapper.js.map +1 -0
  21. package/dist/lib/env.d.ts +2 -0
  22. package/dist/lib/env.js +25 -0
  23. package/dist/lib/env.js.map +1 -0
  24. package/dist/lib/evidence.d.ts +63 -0
  25. package/dist/lib/evidence.js +474 -0
  26. package/dist/lib/evidence.js.map +1 -0
  27. package/dist/lib/figmaApi.d.ts +24 -0
  28. package/dist/lib/figmaApi.js +173 -0
  29. package/dist/lib/figmaApi.js.map +1 -0
  30. package/dist/lib/llmClient.d.ts +61 -0
  31. package/dist/lib/llmClient.js +441 -0
  32. package/dist/lib/llmClient.js.map +1 -0
  33. package/dist/lib/llmOutputBudgets.d.ts +6 -0
  34. package/dist/lib/llmOutputBudgets.js +13 -0
  35. package/dist/lib/llmOutputBudgets.js.map +1 -0
  36. package/dist/lib/llmTimeouts.d.ts +4 -0
  37. package/dist/lib/llmTimeouts.js +10 -0
  38. package/dist/lib/llmTimeouts.js.map +1 -0
  39. package/dist/lib/modelRegistry.d.ts +12 -0
  40. package/dist/lib/modelRegistry.js +91 -0
  41. package/dist/lib/modelRegistry.js.map +1 -0
  42. package/dist/lib/nodeTree.d.ts +9 -0
  43. package/dist/lib/nodeTree.js +174 -0
  44. package/dist/lib/nodeTree.js.map +1 -0
  45. package/dist/lib/persistentCache.d.ts +32 -0
  46. package/dist/lib/persistentCache.js +301 -0
  47. package/dist/lib/persistentCache.js.map +1 -0
  48. package/dist/lib/spatialCluster.d.ts +58 -0
  49. package/dist/lib/spatialCluster.js +340 -0
  50. package/dist/lib/spatialCluster.js.map +1 -0
  51. package/dist/lib/visionInterpreter.d.ts +14 -0
  52. package/dist/lib/visionInterpreter.js +205 -0
  53. package/dist/lib/visionInterpreter.js.map +1 -0
  54. package/dist/schemas/answerFromBoard.d.ts +75 -0
  55. package/dist/schemas/answerFromBoard.js +28 -0
  56. package/dist/schemas/answerFromBoard.js.map +1 -0
  57. package/dist/schemas/common.d.ts +14 -0
  58. package/dist/schemas/common.js +59 -0
  59. package/dist/schemas/common.js.map +1 -0
  60. package/dist/schemas/diagnoseLlmConfig.d.ts +35 -0
  61. package/dist/schemas/diagnoseLlmConfig.js +20 -0
  62. package/dist/schemas/diagnoseLlmConfig.js.map +1 -0
  63. package/dist/schemas/diffBoard.d.ts +118 -0
  64. package/dist/schemas/diffBoard.js +61 -0
  65. package/dist/schemas/diffBoard.js.map +1 -0
  66. package/dist/schemas/getBoardContext.d.ts +255 -0
  67. package/dist/schemas/getBoardContext.js +77 -0
  68. package/dist/schemas/getBoardContext.js.map +1 -0
  69. package/dist/schemas/ingestBoard.d.ts +96 -0
  70. package/dist/schemas/ingestBoard.js +88 -0
  71. package/dist/schemas/ingestBoard.js.map +1 -0
  72. package/dist/server.d.ts +16 -0
  73. package/dist/server.js +131 -0
  74. package/dist/server.js.map +1 -0
  75. package/dist/tools/answerFromBoard.d.ts +9 -0
  76. package/dist/tools/answerFromBoard.js +239 -0
  77. package/dist/tools/answerFromBoard.js.map +1 -0
  78. package/dist/tools/diagnoseLlmConfig.d.ts +4 -0
  79. package/dist/tools/diagnoseLlmConfig.js +158 -0
  80. package/dist/tools/diagnoseLlmConfig.js.map +1 -0
  81. package/dist/tools/diffBoard.d.ts +11 -0
  82. package/dist/tools/diffBoard.js +49 -0
  83. package/dist/tools/diffBoard.js.map +1 -0
  84. package/dist/tools/getBoardContext.d.ts +3 -0
  85. package/dist/tools/getBoardContext.js +157 -0
  86. package/dist/tools/getBoardContext.js.map +1 -0
  87. package/dist/tools/ingestBoard.d.ts +8 -0
  88. package/dist/tools/ingestBoard.js +594 -0
  89. package/dist/tools/ingestBoard.js.map +1 -0
  90. package/dist/types.d.ts +145 -0
  91. package/dist/types.js +6 -0
  92. package/dist/types.js.map +1 -0
  93. package/docs/pipeline.gif +0 -0
  94. package/package.json +73 -4
  95. package/server.json +48 -0
package/.env.example ADDED
@@ -0,0 +1,66 @@
1
+ # Figma personal access token
2
+ # figma.com → Settings → Security → Personal access tokens
3
+ # Scope: file_content:read. The token must have access to the requested board.
4
+ # Prefer environment credentials; tool arguments can appear in client logs.
5
+ FIGMA_ACCESS_TOKEN=
6
+
7
+ # --- LLM (vision interpretation + answer synthesis) ---------------------
8
+ # OpenAI-compatible chat completions endpoint. Model quotas/prices can change.
9
+ # Board text/images are sent to this provider for vision and Q&A; use max_speed
10
+ # and get_board_context for deterministic context without model calls.
11
+ #
12
+ # 1) OpenRouter (default): create a key at https://openrouter.ai/keys.
13
+ # The student-free preset uses nvidia/nemotron-3-super-120b-a12b:free for
14
+ # text, then the openrouter/free router, and the router alone for vision.
15
+ # Free models and their limits change; run diagnose_llm_config to check.
16
+ #
17
+ # 2) GitHub Models: free with any GitHub account
18
+ # (https://github.com/marketplace/models) — set
19
+ # LLM_BASE_URL=https://models.github.ai/inference and use a GitHub PAT
20
+ # as LLM_API_KEY, with a vision-capable model id.
21
+ LLM_BASE_URL=https://openrouter.ai/api/v1
22
+ LLM_API_KEY=
23
+ # Supported presets: student-free
24
+ LLM_MODEL_PRESET=student-free
25
+ # Optional role-specific overrides. Legacy LLM_VISION_MODEL / LLM_TEXT_MODEL
26
+ # still work and become the first candidate in each list.
27
+ # LLM_VISION_MODELS=openrouter/free
28
+ # LLM_TEXT_MODELS=nvidia/nemotron-3-super-120b-a12b:free,openrouter/free
29
+ # LLM_FAST_TEXT_MODELS=nvidia/nemotron-3-super-120b-a12b:free,openrouter/free
30
+ # LLM_PROVIDER_REQUIRE_PARAMETERS=true
31
+ # Optional answer-only reasoning effort: none, low, medium or high.
32
+ # Omit to retain provider defaults; support depends on the configured model.
33
+ # LLM_ANSWER_REASONING_EFFORT=none
34
+
35
+ # --- Timeout controls ----------------------------------------------------
36
+ # Defaults are tuned so MCP UI clients do not wait forever on slow providers.
37
+ # Increase these only if your MCP client/request timeout is also higher.
38
+ # FIGMA_REQUEST_TIMEOUT_MS=15000
39
+ # FIGMA_FILE_REQUEST_TIMEOUT_MS=60000
40
+ # LLM_REQUEST_TIMEOUT_MS=20000
41
+ # Vision: explicit role value > explicit global value > 60000 ms.
42
+ # LLM_VISION_REQUEST_TIMEOUT_MS=60000
43
+ # LLM_SDK_MAX_RETRIES=0
44
+ # LLM_RATE_LIMIT_RETRIES=1
45
+ # LLM_RATE_LIMIT_MAX_BACKOFF_MS=5000
46
+ # LLM_ANSWER_MAX_OUTPUT_TOKENS=2048
47
+ # LLM_VISION_MAX_OUTPUT_TOKENS=4096
48
+ # LLM_ANSWER_TOP_K=6
49
+ # LLM_ANSWER_PROMPT_MAX_CHARS=24000
50
+ # INGEST_BOARD_VISION_BUDGET_MS=40000
51
+ # INGEST_BOARD_MIN_VISION_SLOT_MS=10000
52
+ # INGEST_BOARD_VISION_CONCURRENCY=3
53
+ # FIGMA_SCREENSHOT_DOWNLOAD_CONCURRENCY=3
54
+
55
+ # --- Cache controls ------------------------------------------------------
56
+ # Maximum full boards retained in process memory. Older entries remain on
57
+ # disk and are restored on demand.
58
+ # FIGJAM_MCP_MEMORY_CACHE_MAX_BOARDS=10
59
+
60
+ # Private cache root (v4/ is created beneath it). Omit for the per-user OS default.
61
+ # macOS: ~/Library/Caches/figjam-context-mcp
62
+ # Windows: %LOCALAPPDATA%/figjam-context-mcp
63
+ # Linux: $XDG_CACHE_HOME/figjam-context-mcp or ~/.cache/figjam-context-mcp
64
+ # Use an absolute dedicated directory, not a shared project directory.
65
+ # FIGJAM_MCP_CACHE_DIR=/absolute/private/path/figjam-context-mcp
66
+ # Legacy v3 data is preserved; re-ingest boards to populate v4.
package/CHANGELOG.md ADDED
@@ -0,0 +1,43 @@
1
+ # Changelog
2
+
3
+ ## 0.4.0 — 2026-10-18
4
+
5
+ - New `student-free` defaults: text uses `nvidia/nemotron-3-super-120b-a12b:free`,
6
+ then `openrouter/free`; vision uses `openrouter/free`. OpenRouter's
7
+ `provider.require_parameters` is no longer sent to other providers.
8
+ - `ingest_board` fits a 60-second client timeout: the vision phase defaults to
9
+ 40 s (`INGEST_BOARD_VISION_BUDGET_MS`). Unfinished clusters continue on the
10
+ next ingest, and the summary says so.
11
+ - `diagnose_llm_config` runs its checks in parallel with the same output budgets
12
+ as the real calls and answers within 45 s.
13
+ - Stable MCP TypeScript SDK v2 and Zod 4 with unchanged tool names and required
14
+ fields; cancellation, ingest progress and tool annotations. Requires Node.js 22.12+.
15
+ - Answers cite source nodes with exact quotes and Figma links, and report
16
+ insufficient evidence instead of guessing.
17
+ - Answers keep confirmed statuses, explicit negatives, open tasks, proposals and
18
+ conflicting sources apart. Optional `LLM_ANSWER_REASONING_EFFORT` for answers.
19
+ - `get_board_context` adds pagination, character budgets, exact node lookups and
20
+ local BM25 search over original text, table cells and names. Topics without
21
+ matches return empty results.
22
+ - Tables, pages, sections and arrow direction are preserved. Arrows anchored to
23
+ the page canvas no longer create connections.
24
+ - `diff_board` compares the latest snapshot with an earlier one (20 are kept),
25
+ including table-cell, visual and connector changes.
26
+ - Re-ingests reuse unchanged clusters and skip the download when Figma reports
27
+ the same version. Model or prompt changes invalidate interpretations automatically.
28
+ - Ingest results report why vision is incomplete (time budget, timeout, rate
29
+ limit, configuration, access) and when to retry; Retry-After is respected.
30
+ - Private v4 cache with atomic writes and a write lock. Legacy v3 caches are kept;
31
+ re-ingest once after upgrading.
32
+ - Bounded work: 64 MiB per file, 100,000 nodes, 8 MiB per image, 64 MiB of
33
+ screenshots per ingest, and per-request timeouts for Figma and the LLM.
34
+ - Vision summaries keep visible facts and diagram direction and are marked as
35
+ model-derived.
36
+ - Offline retrieval and diff evaluation with 20 synthetic cases
37
+ (`npm run eval:retrieval`); MIT license and CI on Linux, macOS and Windows.
38
+
39
+ ## 0.3.0 — Development history
40
+
41
+ Added board snapshot diffs, incremental interpretation, bounded concurrent vision,
42
+ connector relations and an npm tarball startup smoke test. No published release
43
+ date is asserted for this development version.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ecestnrkl
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,150 @@
1
- # Temporary Holding Version
1
+ # figjam-context-mcp
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ A local MCP server that turns FigJam boards into source-cited context for LLMs.
4
+ It reads a board through the Figma REST API, groups stickies, tables, images and
5
+ arrows into clusters, and answers questions with links back to the original nodes.
6
+
7
+ ![Pipeline: a FigJam board is read through the Figma API, clustered by geometry, refined with vision and turned into LLM-ready context](https://raw.githubusercontent.com/ecestnrkl/figjam-mcp/main/docs/pipeline.gif)
8
+
9
+ ## Why
10
+
11
+ Workshop boards hold research notes, decisions and open questions, but an LLM
12
+ cannot read a canvas. Screenshots and PDF exports lose tables, arrow direction
13
+ and the link to the source. This server keeps the board's structure and cites
14
+ every answer to the nodes it came from.
15
+
16
+ ## Tools
17
+
18
+ | Tool | What it does | LLM call |
19
+ | --- | --- | --- |
20
+ | `ingest_board` | Reads a board, clusters it and saves a local snapshot. Re-ingests reuse unchanged clusters. | In `balanced` (default) and `max_quality` mode |
21
+ | `get_board_context` | Returns bounded, paginated context with source links, optionally for a topic or exact node IDs. | No |
22
+ | `answer_from_board` | Answers a question from the snapshot with node-level citations, or reports insufficient evidence. | Yes |
23
+ | `diff_board` | Compares two snapshots: new, removed and changed clusters, nodes, table cells and arrows. | No |
24
+ | `diagnose_llm_config` | Tests the configured models with small text and image JSON checks. | Yes |
25
+
26
+ ## Quick start
27
+
28
+ Requires Node.js 22.12 or later.
29
+
30
+ 1. Create a Figma personal access token under **Settings → Security → Personal
31
+ access tokens** with the scope `file_content:read`. Add `file_metadata:read`
32
+ so re-ingests of an unchanged board skip the download. The token's account
33
+ needs access to the board.
34
+ 2. Optional: create an OpenRouter key at
35
+ [openrouter.ai/keys](https://openrouter.ai/keys). It enables image
36
+ interpretation, `answer_from_board` and `diagnose_llm_config`. Without it, use
37
+ `ingestMode: "max_speed"` with `get_board_context` and `diff_board`.
38
+ 3. Add the server to your MCP client:
39
+
40
+ ```json
41
+ {
42
+ "mcpServers": {
43
+ "figjam-context": {
44
+ "command": "npx",
45
+ "args": ["-y", "figjam-context-mcp"],
46
+ "env": {
47
+ "FIGMA_ACCESS_TOKEN": "your-figma-token",
48
+ "LLM_BASE_URL": "https://openrouter.ai/api/v1",
49
+ "LLM_API_KEY": "your-openrouter-key"
50
+ }
51
+ }
52
+ }
53
+ }
54
+ ```
55
+
56
+ For Claude Code:
57
+
58
+ ```bash
59
+ claude mcp add figjam-context -e FIGMA_ACCESS_TOKEN=your-figma-token -e LLM_BASE_URL=https://openrouter.ai/api/v1 -e LLM_API_KEY=your-openrouter-key -- npx -y figjam-context-mcp
60
+ ```
61
+
62
+ Then ask your assistant to ingest a board URL, for example *"Ingest
63
+ https://www.figma.com/board/FILE_KEY/Name and list the open questions."*
64
+ The `boardId` of every later call is the file key from that URL.
65
+
66
+ All settings: [configuration](https://github.com/ecestnrkl/figjam-mcp/blob/main/docs/configuration.md).
67
+ Problems: [troubleshooting](https://github.com/ecestnrkl/figjam-mcp/blob/main/docs/troubleshooting.md).
68
+
69
+ ## How it works
70
+
71
+ 1. **Read.** `ingest_board` downloads the board through the Figma REST API. If
72
+ Figma reports the same version as the last ingest, the download is skipped.
73
+ 2. **Normalize.** Nodes become text, table cells, images and connectors, with
74
+ their pages and sections.
75
+ 3. **Cluster.** Nearby nodes are grouped by rotation-aware distance. Arrows
76
+ between groups become directed relations.
77
+ 4. **Interpret.** In `balanced` mode, clusters with images or little text get a
78
+ vision-model summary within a 40-second budget; the rest keep their extracted
79
+ text. Unfinished clusters continue on the next ingest.
80
+ 5. **Serve.** The snapshot is saved to a private local cache.
81
+ `get_board_context` searches it (BM25 over original text, table cells and
82
+ names), `answer_from_board` answers with citations and `diff_board` compares
83
+ snapshots.
84
+
85
+ ## Models and cost
86
+
87
+ The default preset `student-free` uses free OpenRouter models: text goes to
88
+ `nvidia/nemotron-3-super-120b-a12b:free` and then `openrouter/free`; images go to
89
+ `openrouter/free`, which picks a free model that accepts images and structured
90
+ outputs. The free default is best effort: free models change, hit rate limits
91
+ and time out.
92
+
93
+ - OpenRouter allows free models 20 requests per minute and 50 requests per day,
94
+ or 1,000 per day once you have bought at least 10 credits
95
+ ([limits](https://openrouter.ai/docs/api-reference/limits)).
96
+ - Figma limits file downloads and image renders by seat and plan: Dev and Full
97
+ seats on paid plans get 10–20 requests per minute, View and Collab seats and
98
+ files in Starter plans at most 20 per month
99
+ ([rate limits](https://developers.figma.com/docs/rest-api/rate-limits/));
100
+ each cluster sent to the vision model uses one render.
101
+ - For a team, configure your own model: `LLM_BASE_URL` takes any
102
+ OpenAI-compatible endpoint, and `LLM_TEXT_MODELS` / `LLM_VISION_MODELS` set
103
+ the model lists.
104
+ - Run `diagnose_llm_config` after every model change. It checks JSON replies
105
+ and image understanding with synthetic inputs.
106
+
107
+ ## Privacy
108
+
109
+ - The server reads from Figma and never changes a board.
110
+ - `balanced` and `max_quality` ingests send board text and screenshots to the
111
+ configured LLM provider. `answer_from_board` sends the question and selected
112
+ excerpts. `max_speed` with `get_board_context` and `diff_board` sends nothing
113
+ to an LLM provider.
114
+ - Snapshots stay in a private per-user cache on your machine. Delete the cache
115
+ directory to remove them.
116
+ - Keep tokens in the client's environment. A token passed as a tool argument can
117
+ appear in client logs.
118
+
119
+ ## Limitations
120
+
121
+ - Image interpretation gets 40 seconds per ingest by default; large boards need
122
+ several ingests to interpret every image cluster.
123
+ - A client that cancels an ingest, for example after a 60-second timeout, gets
124
+ no partial result.
125
+ - Free models are best effort. Citations show where an answer comes from, not
126
+ that its conclusion is right.
127
+ - Search is lexical; synonyms without shared words do not match.
128
+ - Local stdio only; no hosted or multi-user mode.
129
+
130
+ Measured results: [evaluation](https://github.com/ecestnrkl/figjam-mcp/blob/main/docs/evaluation.md).
131
+
132
+ ## Development
133
+
134
+ ```bash
135
+ git clone https://github.com/ecestnrkl/figjam-mcp.git
136
+ cd figjam-mcp
137
+ npm ci
138
+ cp .env.example .env # add your tokens
139
+ npm run check # typecheck, tests, build, package validation
140
+ npm run package:smoke # install the packed package and exercise all tools
141
+ npm run eval:retrieval # offline retrieval and diff evaluation
142
+ npx @modelcontextprotocol/inspector --config inspector.config.json
143
+ ```
144
+
145
+ See [CONTRIBUTING.md](https://github.com/ecestnrkl/figjam-mcp/blob/main/CONTRIBUTING.md)
146
+ and the [changelog](https://github.com/ecestnrkl/figjam-mcp/blob/main/CHANGELOG.md).
147
+
148
+ ## License
149
+
150
+ [MIT](https://github.com/ecestnrkl/figjam-mcp/blob/main/LICENSE) © 2026 ecestnrkl
package/SECURITY.md ADDED
@@ -0,0 +1,26 @@
1
+ # Security policy
2
+
3
+ Security fixes target the latest release on the current development line.
4
+ Use supported Node.js LTS versions and apply dependency updates promptly.
5
+
6
+ ## Reporting
7
+
8
+ Use GitHub's **Report a vulnerability** option on the repository Security tab
9
+ when private reporting is enabled. If that option is unavailable, open an issue
10
+ requesting a private reporting channel without including exploit details or
11
+ secrets. Do not attach Figma tokens, provider keys, private board content or cache
12
+ files to public issues. There is no guaranteed response-time SLA.
13
+
14
+ ## Data boundary
15
+
16
+ This is a local stdio server intended for one user's trusted MCP client. It does
17
+ not expose an HTTP endpoint or implement multi-user access control. Figma tokens
18
+ belong in the environment. Board text/screenshots and questions can be sent to the
19
+ configured LLM provider; provider retention and costs depend on that provider.
20
+ Use max_speed ingest and get_board_context to avoid model calls.
21
+
22
+ Local snapshots contain board content and are stored in a private per-user cache.
23
+ Only connect clients trusted to read that data. Re-ingest after upgrading from
24
+ legacy cache formats. Stop the server before removing its cache directory.
25
+ Board content is untrusted input; source citations and prompt boundaries reduce
26
+ risk but do not make model output authoritative. Review cited source nodes.
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import "dotenv/config";
package/dist/index.js ADDED
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+ import "dotenv/config";
3
+ import { serveStdio } from "@modelcontextprotocol/server/stdio";
4
+ import { createServer, packageMetadata } from "./server.js";
5
+ async function main() {
6
+ if (process.argv.includes("--version") || process.argv.includes("-v")) {
7
+ process.stdout.write(`${packageMetadata.version}\n`);
8
+ return;
9
+ }
10
+ const handle = serveStdio(() => createServer());
11
+ const shutdown = () => { void handle.close(); };
12
+ process.once("SIGINT", shutdown);
13
+ process.once("SIGTERM", shutdown);
14
+ console.error(`${packageMetadata.name} running on stdio`);
15
+ }
16
+ main().catch((error) => {
17
+ console.error(`Fatal error starting ${packageMetadata.name}:`, error);
18
+ process.exit(1);
19
+ });
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,eAAe,CAAC;AACvB,OAAO,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE5D,KAAK,UAAU,IAAI;IACjB,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACtE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,eAAe,CAAC,OAAO,IAAI,CAAC,CAAC;QACrD,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,YAAY,EAAE,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAG,GAAG,EAAE,GAAG,KAAK,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;IAChD,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACjC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAClC,OAAO,CAAC,KAAK,CAAC,GAAG,eAAe,CAAC,IAAI,mBAAmB,CAAC,CAAC;AAC5D,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IAC9B,OAAO,CAAC,KAAK,CAAC,wBAAwB,eAAe,CAAC,IAAI,GAAG,EAAE,KAAK,CAAC,CAAC;IACtE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,55 @@
1
+ import type { BoardData } from "../types.js";
2
+ /**
3
+ * Compares two ingest snapshots of the same board — "what changed since the
4
+ * last workshop?". Works on three levels:
5
+ * - nodes: added / removed / edited content nodes (structural containers
6
+ * and connectors excluded — connectors are diffed separately),
7
+ * - clusters: matched across snapshots by member overlap, then classified
8
+ * as unchanged (same content hash), modified, new, or removed,
9
+ * - connections: connector arrows diffed as (from, to, label) edges and
10
+ * rendered with the owning clusters' labels.
11
+ */
12
+ export interface ClusterSummaryRef {
13
+ label: string;
14
+ summary: string;
15
+ }
16
+ export interface ModifiedClusterDiff {
17
+ label: string;
18
+ previousLabel: string;
19
+ addedNodeCount: number;
20
+ removedNodeCount: number;
21
+ editedNodeCount: number;
22
+ }
23
+ export interface BoardDiffStats {
24
+ addedNodes: number;
25
+ removedNodes: number;
26
+ editedNodes: number;
27
+ newClusters: number;
28
+ removedClusters: number;
29
+ modifiedClusters: number;
30
+ unchangedClusters: number;
31
+ addedConnections: number;
32
+ removedConnections: number;
33
+ }
34
+ export interface BoardDiffResult {
35
+ stats: BoardDiffStats;
36
+ newClusters: ClusterSummaryRef[];
37
+ removedClusters: ClusterSummaryRef[];
38
+ modifiedClusters: ModifiedClusterDiff[];
39
+ addedConnections: string[];
40
+ removedConnections: string[];
41
+ summaryText: string;
42
+ tableCellChanges: TableCellChange[];
43
+ }
44
+ export interface TableCellChange {
45
+ tableNodeId: string;
46
+ cellId: string;
47
+ changeType: "added" | "removed" | "modified";
48
+ previousText?: string;
49
+ currentText?: string;
50
+ previousRow?: number;
51
+ previousColumn?: number;
52
+ currentRow?: number;
53
+ currentColumn?: number;
54
+ }
55
+ export declare function diffBoards(baseline: BoardData, current: BoardData): BoardDiffResult;