Commit Graph
154 Commits
Author SHA1 Message Date
forkless ac638a3586 ci: retry build
Docker Build (ARM64) / Build & Push (push) Successful in 8s
2026-06-24 18:58:30 +02:00
forkless 3de5951e48 ci: retry build 2026-06-24 18:56:58 +02:00
forkless 5775ec1e3b ci: trigger build [force]
Docker Build (ARM64) / Build & Push (push) Failing after 5s
2026-06-24 18:55:36 +02:00
forkless d50de9232f ci: fresh build 2026-06-24 18:55:16 +02:00
forkless 547fd6affb fix: add onCollabDialogOpen to show share button
Docker Build (ARM64) / Build & Push (push) Successful in 2m3s
2026-06-24 18:40:40 +02:00
forkless 460671e753 perf: switch to node:20-alpine base images
Docker Build (ARM64) / Build & Push (push) Failing after 5s
2026-06-24 18:32:35 +02:00
forkless 32188d93b4 fix: collab WS path /socket.io for Excalidraw library
Docker Build (ARM64) / Build & Push (push) Has been cancelled
2026-06-24 18:31:37 +02:00
forkless 27dbc1f40e fix: back to runs-on ubuntu-latest, both runners compete
Docker Build (ARM64) / Build & Push (push) Successful in 1m28s
2026-06-24 18:27:55 +02:00
forkless 2b6500c697 fix: target ARM64 runner with label arm64
Docker Build (ARM64) / Build & Push (push) Failing after 7s
2026-06-24 18:25:36 +02:00
forkless 0e8c855818 revert: back to plain docker build (no buildx)
Docker Build (ARM64) / Build & Push (push) Failing after 1m30s
2026-06-24 18:23:10 +02:00
forkless 936dd63976 fix: use buildx --platform linux/arm64 for ARM64 cross-build
Docker Build (ARM64) / Build & Push (push) Has been cancelled
2026-06-24 18:22:41 +02:00
forkless 4dceeb2e7f fix: point frontend WS to wss://excalidraw.forkless.com
Docker Build (ARM64) / Build & Push (push) Successful in 2m2s
2026-06-24 18:18:19 +02:00
forkless a4a1b03215 fix: redirect collab WS to excalidraw.forkless.com
Docker Build (ARM64) / Build & Push (push) Successful in 2m24s
2026-06-24 18:09:31 +02:00
forkless f91082d2a3 fix: disable Excalidraw collaboration WS to oss-collab.excalidraw.com
Docker Build (ARM64) / Build & Push (push) Has been cancelled
2026-06-24 18:08:40 +02:00
forkless 82574e7308 ci: trigger build
Docker Build (ARM64) / Build & Push (push) Successful in 4m49s
2026-06-24 16:53:40 +02:00
forkless 8d99a58600 ci: trigger build with secrets 2026-06-24 16:52:47 +02:00
forkless f1b71ca5b8 ci: trigger build [force]
Docker Build (ARM64) / Build & Push (push) Failing after 5s
2026-06-24 16:37:49 +02:00
forkless a092e5b548 ci: trigger docker build 2026-06-24 16:36:11 +02:00
forkless 37be53dae8 fix: add .gitea/** to workflow path triggers
Docker Build (ARM64) / Build & Push (push) Failing after 6s
2026-06-24 16:31:26 +02:00
forkless a8723f6875 ci: ARM64 Docker build via Gitea Actions 2026-06-24 16:24:50 +02:00
046719aabc feat(transport): Streamable HTTP mode — one shared MCP process for all sessions (v1.2.0) (#13)
* chore(ci): release fires on workflow_dispatch, not on every CI pass

Replaced workflow_run trigger (fired automatically when CI completed
on main) with workflow_dispatch. The full semantic-release automation
is preserved — bump detection, version commit, tag, GitHub Release,
NPM + Docker publish — but now runs only when explicitly triggered.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(transport): add Streamable HTTP mode — one shared process for all MCP clients (v1.2.0)

Add MCP_TRANSPORT=http mode backed by StreamableHTTPServerTransport. Each
Claude Code session connects to the shared long-lived process via HTTP (port
3031 by default) instead of spawning a new stdio process per session, eliminating
per-session process multiplication. Sessions are isolated by mcp-session-id header.

Also refactor src/index.ts to extract createMcpServer()/registerHandlers() for
clean per-session server instantiation, and upgrade fs.writeFileSync/readFileSync
calls to fs.promises async variants in export/import tool handlers.

9 new tests cover transport resolution, session isolation, teardown, and
startMcpHttpServer. All 528 tests pass. Bumps v1.1.0 → v1.2.0.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: newblacc <newblacc@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
v1.2.0
2026-05-20 14:51:08 +02:00
9846e0ba0f feat(canvas): native field preservation, label materialization, batch workspace delete (#12)
* feat(canvas): native field preservation, label materialization, batch workspace delete

- fillNativeFields() + repairContainerBinding() in db layer ensure every
  element stored in SQLite is a complete, round-trippable Excalidraw element
  with correct containerId ↔ boundElements bidirectional binding
- materializeLabel() in server.ts: shapes with label.text/text produce a
  native bound text element at write time (create, update, batch) so text
  follows its container when moved — matches VSCode Excalidraw extension behavior
- Batch workspace UI: Select/Unselect All, per-row checkboxes, Delete N
  workspaces button with confirmation
- POST /api/tenants/batch-delete: delete up to 50 tenants in one request
- 42 new backend tests; 519 total passing
- Bump version 1.0.6 → 1.1.0

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(tests): update e2e assertions for label materialization

phase2-regressions: label is now a native bound text element
(id: pos-stable-1-label) — check bound text element text instead
of container.label?.text which is no longer stored.

sync-flows FTS: search now matches the bound text element (fts-el-label)
rather than the container — accept either id as valid match.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 21:12:01 +02:00
d14d767c75 feat(tenants): add workspace delete UI and fix project switch element loading (#11)
- Add DELETE /api/tenants/:id endpoint with cascade (projects, elements, snapshots)
- Add delete buttons with inline confirm in workspace switcher panel
- Fix project switch not loading elements: switchProjectUI now directly clears
  canvas and calls loadExistingElements() instead of relying on WS roundtrip

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
v1.0.6
2026-04-06 14:37:11 +02:00
Maxime Roy (new.blacc)andGitHub 1166ea5b3f chore: release v1.0.5 (#10)
feat(projects): project management UI, sync countdown, fix project switching
v1.0.5
2026-04-06 13:18:03 +02:00
798f62f63a fix(logger): make file transport opt-in via LOG_FILE_PATH (#9)
The file transport defaulted to writing excalidraw.log relative to
process.cwd(), polluting every project directory where the MCP server
started. Console transport already handles warn+error to stderr.

File logging is now opt-in: set LOG_FILE_PATH to enable it.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 10:02:27 +02:00
f770c811e9 chore: document similar-project scan in AGENTS.md; ignore .serena/ (#8)
* chore: document similar-project scan in AGENTS.md; ignore .serena/ and .DS_Store

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: add .shipguard.yml — exclude node_modules, acknowledge upstream JS debt

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: actually ignore .serena/ (prior commit added negation only)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: newblacc <refactor code>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 09:57:07 +02:00
Maxime Roy (new.blacc)andGitHub 81f38de508 Merge pull request #7 from celstnblacc/chore/release-v1.0.4
chore: release v1.0.4
v1.0.4
2026-03-31 13:21:57 +02:00
newblaccandClaude Sonnet 4.6 80c82665ea chore: release v1.0.4
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 13:19:31 +02:00
Maxime Roy (new.blacc)andGitHub d020459e90 Merge pull request #6 from celstnblacc/fix/windows-postinstall
fix: make postinstall cross-platform for Windows
2026-03-31 13:18:12 +02:00
newblaccandClaude Sonnet 4.6 ae52198729 fix: make postinstall script cross-platform for Windows compatibility
Replace Unix-only `2>/dev/null || true` with a `node -e` inline script
that silently ignores better-sqlite3 rebuild failures on all platforms.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 13:14:25 +02:00
newblaccandClaude Sonnet 4.6 c368d4088a fix: upgrade zod to v4 to fix global install crash
@modelcontextprotocol/sdk@1.26.0 uses zod/v4 APIs (specifically
z.literal().value getter). When installed globally, npm shared the
project's zod@3.25.5 instead of the SDK's nested zod@4.3.6; the
3.25.5 v4 compat shim lacks the .value getter, throwing
'Schema method literal must be a string' on startup.

Also updates z.record(z.any()) to z.record(z.string(), z.any())
for zod v4 strict record key typing.

446/446 tests passing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v1.0.3
2026-03-30 22:42:46 +02:00
newblaccandClaude Sonnet 4.6 d1689a2e5c chore: release v1.0.2
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v1.0.2
2026-03-30 21:32:28 +02:00
Maxime Roy (new.blacc)andGitHub d073b6348d Merge pull request #5 from celstnblacc/fix/bidirectional-sync-and-label-updates
fix: bidirectional sync, text alignment, WS race, and security hardening
2026-03-30 21:24:22 +02:00
newblaccandClaude Sonnet 4.6 64ebfc6791 fix: gauntlet hardening — alignment regression tests, cleanup, DRY, docker labels
- test: 3 regression tests for textAlign/verticalAlign/containerId REST round-trip
  (Zod was silently stripping these fields before the schema fix)
- fix: pendingTitleTimerRef cleanup on unmount (App.tsx)
- fix: localStorage JSON.parse wrapped in try/catch to prevent crash (App.tsx)
- refactor: extract seedKnownContainers() helper — 4 identical loops → 1 (App.tsx)
- chore: remove unnecessary `as any` cast on subtitle element type (index.ts)
- docs: test counts updated to 446 (README.md, CLAUDE.md)
- chore: fix stale LABEL source URLs in Dockerfile and Dockerfile.canvas

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 21:20:14 +02:00
newblaccandClaude Sonnet 4.6 87e8a8e314 fix: preserve textAlign/verticalAlign/containerId through REST round-trip
ElementSharedFieldsSchema in server.ts was silently stripping textAlign,
verticalAlign, and containerId on every POST/PATCH, causing bound text
inside containers to lose centering after a sync round-trip.

- Add missing fields to ElementSharedFieldsSchema (server.ts)
- Add textAlign?, verticalAlign?, containerId? to ServerElement (types.ts)
- Set textAlign: "center", verticalAlign: "top" on MCP subtitle elements (index.ts)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 20:56:46 +02:00
newblaccandClaude Sonnet 4.6 90cae43193 fix: resolve double-WS race and WS-delivered title injection; add curved arrow e2e
- Block CONNECTING state in WS guard to prevent second connection seeding
  knownContainerIdsRef before element_created fires
- Call handleCanvasChange() explicitly after element_created updateScene
  (CaptureUpdateAction.NEVER suppresses onChange in Excalidraw 0.18)
- E2E: curved arrow stays deformable after sync round-trip
- E2E: auto-title injection test now reliably passes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 18:33:18 +02:00
newblacc f1db126566 test: add phase security/smoke/e2e coverage and tighten MCP contract handling 2026-03-30 15:52:24 +02:00
newblaccandClaude Opus 4.6 a605a15282 feat: auto title/subtitle, Nunito default, position-preserving sync, draggable font widget
- Default font changed to Nunito (id 6)
- Containers auto-inject "Title" + "Text here" subtitle on draw (grouped)
- MCP create_element defaults to title/subtitle card layout for containers
- Sync preserves element geometry (x/y/width/height) across refreshes
- normalizeForBackend preserves native bound text instead of collapsing to label.text
- Rate limits raised to 500 req/15min general, 30 req/min sync writes
- Draggable "Font px" widget with localStorage position persistence
- Left panel widened for full Opacity visibility
- Updated rate-limit tests to match new limits (30 write, 500 general)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 11:56:59 +02:00
newblaccandClaude Opus 4.6 1e535a5e31 fix: labels stored as label.text now persist across page refresh
convertToExcalidrawElements silently dropped label.text on reload.
Added expandLabelsToNative() that pre-expands server-format labels
into native Excalidraw bound text elements before the scene is set,
ensuring labels survive DB round-trips.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 00:43:50 +02:00
newblaccandClaude Sonnet 4.6 d8ef0379f5 feat: set dark theme as default
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 00:29:37 +02:00
newblaccandClaude Sonnet 4.6 d993355a54 fix: bidirectional sync conflict and labeled element update rendering
- Update lastSyncedElementsRef on every WS-applied scene change so
  auto-sync does not revert MCP writes back to stale browser state
- Fix labeled container updates (rect/ellipse/diamond/arrow) to use
  convertToExcalidrawElements with bound-text ID transplant, preventing
  text clipping and empty labels after update
- Fix standalone text element updates to write into text/originalText
  so Excalidraw renders the new value immediately
- Fix convertTextToLabel to handle arrows and empty string text values

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 00:23:41 +02:00
Maxime Roy (new.blacc)andGitHub d838b67e31 Merge pull request #4 from celstnblacc/fix/better-sqlite3-node-version
fix: rebuild better-sqlite3 on install to fix Node version mismatch
v1.0.1
2026-03-29 22:32:41 +02:00
newblaccandClaude Opus 4.6 fa6b7e8939 fix: rebuild better-sqlite3 on install to fix Node version mismatch
Adds postinstall script to rebuild better-sqlite3 native bindings for
the current Node.js version. Fixes ERR_DLOPEN_FAILED when installing
via npx on a different Node version than was used to publish.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-29 22:29:53 +02:00
Maxime Roy (new.blacc)andGitHub 321c828c86 Merge pull request #3 from celstnblacc/rename/excalidraw-mcp-sentinel
chore: rename project to excalidraw-mcp-sentinel
2026-03-29 20:05:01 +02:00
newblaccandClaude Opus 4.6 15a5cfcc61 chore: add security tests and SECURITY.md (previously untracked)
- 9 backend security test files (auth, headers, rate-limit, middleware
  order, smoke, validation, WS auth, integration bootstrap)
- 1 e2e test (clear-preference)
- SECURITY.md policy doc

These files powered the 369-test suite but were never committed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-29 20:03:50 +02:00
newblaccandClaude Opus 4.6 9fb8ce34ec chore: rename project to excalidraw-mcp-sentinel
- Package name: @sanjibdevnath/mcp-excalidraw-local → excalidraw-mcp-sentinel
- GitHub repo: celstnblacc/mcp-excalidraw-local → celstnblacc/excalidraw-mcp-sentinel
- Docker images, CLI binary, CI workflows, docs all updated
- Version reset to 1.0.0 for independent release track
- Added "Why this fork?" section to README
- Removed superseded planning docs (PLAN.md, PLAN_v2.md, REVIEW.md, HANDOFF.md)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-29 20:00:27 +02:00
Maxime Roy (new.blacc)andGitHub 8f9fe3fa08 Merge pull request #2 from celstnblacc/feat/gauntlet-hardening
chore: add AGENTS.md and publish readiness checklist
2026-03-29 16:49:58 +02:00
newblaccandClaude Sonnet 4.6 f32a756434 chore: add AGENTS.md and publish readiness checklist to CLAUDE.md
- AGENTS.md: agent instructions covering commands, architecture, key
  constraints, security middleware map, env vars, testing rules, and
  pre-publish checklist
- CLAUDE.md: add Publish Readiness section with security posture summary
  and pre-publish checklist

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 16:36:32 +02:00
Maxime Roy (new.blacc)andGitHub 3a0dfea128 Merge pull request #1 from celstnblacc/feat/gauntlet-hardening
feat(security): harden canvas server with auth, rate-limiting, and validation
2026-03-29 16:18:27 +02:00
newblaccandClaude Sonnet 4.6 6c551f4cd0 fix(ci): update deprecated upload-artifact v3 SHA and missing docker/metadata-action SHA
- actions/upload-artifact: replace stale v3 SHA (pinned as v4.6.2) with @v4
- docker/metadata-action: replace non-existent SHA 902fa8ec7 with @v5

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 16:15:03 +02:00