Commit Graph
138 Commits
Author SHA1 Message Date
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
newblaccandClaude Sonnet 4.6 5539235004 feat(security): harden canvas server with auth, rate-limiting, and validation
- Add security.ts: helmet, CORS allowlist, timing-safe API key auth, prototype
  pollution guard, Mermaid input limits, rate limiting (general/destructive/burst)
- WS auth challenge-response with 5 s timeout and close code 4001
- Fix sync crash: array check before logger access (500 → 400)
- Fix sync/v2: validate element type before write (invalid → 400)
- Upgrade zod 3.22.4 → 3.25.5 (fixes ERR_PACKAGE_PATH_NOT_EXPORTED on startup)
- Extract ElementSharedFieldsSchema; move VALID_ELEMENT_TYPES to module level
- Docker: resource limits, .dockerignore hardening
- Add .project-hooks/pre-commit; expand test coverage (369 tests)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 16:06:04 +02:00
sanjibdevnathlabs-release-bot[bot] a1977d86f9 chore(release): v1.6.2 v1.6.2 2026-03-18 04:39:37 +00:00
Sanjib DevnathandGitHub 2e743c1356 🐛 fix(sync): resolve delete persistence regression and harden data-safety invariants (#13)
Deletions made in the UI were silently lost on page reload because the sync
baseline (lastSyncedElementsRef) was never populated after initial load,
making the delta algorithm unable to detect removed elements. Additionally,
import_scene and restore_snapshot used a non-atomic clear+create pattern
that could permanently lose all canvas data if the batch create failed
after clearing, and duplicate_elements copied stale binding references
pointing to original element IDs instead of remapped duplicates.

🔧 Sync baseline restoration:
- Populate deletion-detection baseline on every server-to-client data path
  (page load, delta resync, hello handshake, initial elements broadcast)
- Establish sync version and hash baselines to prevent phantom re-syncs

🛡️ Data-loss prevention:
- Backup current scene before destructive clear in replace-mode operations
- Atomic restore from backup when subsequent batch create fails
- Remap all binding references (start/end IDs, boundElements, containerId)
  to new IDs during element duplication

 Comprehensive test coverage (154 new tests, 344 total):
- Delta sync flows including deletion persistence and bidirectional sync
- Multi-tenant element/sync/WebSocket isolation
- Arrow binding resolution across all shape types and edge cases
- MCP tool integration covering backup-restore and binding remapping
- Input validation and security boundary testing
- Frontend sync algorithm unit tests reproducing the exact regression

🎯 Eliminates the most critical data-integrity risks: deletions now
persist reliably, destructive operations are rollback-safe, and the
full test suite provides regression coverage for every sync path.
2026-03-18 10:07:07 +05:30
sanjibdevnathlabs-release-bot[bot] 459dbfdb3a chore(release): v1.6.1 v1.6.1 2026-03-18 03:00:11 +00:00
7c59972bb1 🐛 fix(mcp): resolve race conditions, sync failures, and preference regressions (#12)
Fix 6 bugs discovered during MCP tool usage:

1. syncToCanvas error handling: Distinguish network errors (return null)
   from API errors (re-throw with actual message). Fixes misleading
   "HTTP server unavailable" on batch_create_elements.

2. USER_PREFS fallbacks: create_element and batch_create_elements now
   apply fontFamily/roughness/fontSize/strokeWidth from preferences.json
   when not explicitly provided by the caller.

3. Hello handshake: Frontend sends `hello` on tenant_switched and handles
   `hello_ack`. Server resolves projectId from tenantId when absent.
   Fixes WS connections being registered under wrong scope.

4. Serialized broadcasts: Add serializedBroadcastWithAck() that queues
   broadcasts per tenant/project scope. Prevents race condition where
   parallel MCP create_element calls produce overlapping WS messages
   that clobber each other in the frontend.

5. Viewport screenshot: get_canvas_screenshot passes captureViewport=true,
   frontend captures DOM canvas via toDataURL() instead of exportToBlob()
   which always rendered the full scene bounding box.

6. Viewport animate:false: set_viewport uses animate:false for instant
   positioning, preventing mid-animation screenshot captures.

Tests: 14 new tests (8 API, 6 WS) + 9 E2E specs covering all fixes.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 08:28:00 +05:30
sanjibdevnathlabs-release-bot[bot] 670961ee73 chore(release): v1.6.0 v1.6.0 2026-03-17 18:16:39 +00:00
2cca18153f feat(sync): implement scoped sync architecture with ACK model and comprehensive tests (#11)
Implement a complete sync architecture overhaul (12 tasks) replacing the flat
WebSocket broadcast with scoped, acknowledged delivery:

**Backend (server.ts, db.ts, types.ts, index.ts):**
- Scoped connection registry: Map<tenant, Map<project, Set<ClientConnection>>>
- Hello handshake: WS clients identify tenant/project, server responds with scoped elements
- broadcastToScope() replaces global broadcast for element mutations
- broadcastWithAck() waits for browser ACK before returning syncedToCanvas status
- sync_version: monotonic counter per project, stamped on every mutation
- Delta sync v2: POST /api/elements/sync/v2 for incremental sync with version tracking
- GET /api/sync/version endpoint
- Honest syncedToCanvas + canvasStatus in all mutation responses
- Fixed silent try/catch in tenant switch verification

**Frontend (App.tsx):**
- ACK sending after every updateScene() with element verification
- Delta sync v2 integration in syncToBackend()
- Gap detection: triggers resync when sync_version gaps are detected
- lastSyncVersion tracking via refs + localStorage persistence

**Tests (40 new tests, 168 total):**
- db.test.ts: +11 tests for sync_version CRUD, scoping, getChangesSince
- ws.test.ts: +8 tests for hello handshake, scoped broadcast, ACK model
- api.test.ts: +10 tests for sync/v2, sync/version, canvasStatus responses
- helpers.test.ts: +11 tests for isImageElement, normalizeImageElement, restoreBindings
- canvas.spec.ts: +8 e2e tests including full ACK pipeline verification
- Fixed stale tenant state bug in api.test.ts beforeEach

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 23:44:17 +05:30
sanjibdevnathlabs-release-bot[bot] 4e410f1205 chore(release): v1.5.1 v1.5.1 2026-03-17 13:27:27 +00:00
sanjibdevnathlabsandClaude Opus 4.6 71b2a55231 ♻️ refactor(fonts): extract font families to shared JSON single source of truth
Font family IDs were duplicated across 5 files (types.ts, setup.ts,
index.ts, SKILL.md, preferences.example.json) with inconsistent
mappings — Comic Shanns was 4 in some places but actually 8 in
Excalidraw source. This caused wrong fonts to render on canvas.

Fix: create src/font-families.json as the canonical font data, import
it in types.ts, and derive all other references from it. Static docs
now point to the JSON file instead of duplicating the mapping.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 18:55:11 +05:30
sanjibdevnathlabs-release-bot[bot] 25767838fa chore(release): v1.5.0 v1.5.0 2026-03-17 12:12:15 +00:00
sanjibdevnathlabsandClaude Opus 4.6 493a20054b feat(setup): add interactive diagram preferences to setup and update flows
Users are now prompted to choose their preferred font family and roughness
style during both `setup` and `update`. Preferences are saved to
~/.claude/skills/excalidraw-skill/preferences.json, which the MCP server
already reads at startup via loadPreferences(). This ensures third-party
users who install via npx get preferences configured before first use.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 17:39:58 +05:30
sanjibdevnathlabs-release-bot[bot] aa29ddbf13 chore(release): v1.4.0 v1.4.0 2026-03-17 09:02:29 +00:00
sanjibdevnathlabsandClaude Opus 4.6 9114e81f02 feat(skill): add user-configurable diagram preferences system
Add a preference system that lets users configure default font, roughness,
fontSize, and strokeWidth — with three scopes (session/folder/global).

Skill layer (Step 1 in SKILL.md):
- Reads .claude/excalidraw-preferences.json (folder) then
  ~/.claude/skills/excalidraw-skill/preferences.json (global)
- If neither exists, prompts user interactively on first use
- Session-only scope keeps preferences in-memory without saving

Server layer (index.ts):
- loadPreferences() reads the same files at startup
- Replaces hardcoded fontFamily ?? 1 with USER_PREFS.fontFamily
- Folder-level preferences override global; user values override both

Also ships preferences.example.json as a template (preferences.json
is gitignored).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 14:27:34 +05:30
sanjibdevnathlabs-release-bot[bot] fac1c7a267 chore(release): v1.3.0 v1.3.0 2026-03-13 18:19:16 +00:00
sanjibdevnathlabs 9311561227 feat(skill): add auto-triggering for excalidraw-skill via CLAUDE.md directives
The excalidraw-skill was not being auto-invoked when users prompted
Claude to draw diagrams, despite being installed. Claude would call
Excalidraw MCP tools directly, bypassing the skill's critical sizing
formulas and verification workflow — producing broken diagrams with
invisible arrows, truncated text, and overlapping elements. The root
cause is that Claude Code's skill system is advisory: when direct MCP
tools or built-in Bash instructions are available, Claude skips skill
consultation entirely.

🔧 Skill description rewrite:
- Lead with "MANDATORY prerequisite" to assert priority over raw MCP tools
- Add user-intent trigger keywords (draw, visualize, sketch, diagram)
- Name specific consequences of skipping the skill
- List common diagram types for semantic matching

🏗️ Setup/update auto-directives:
- Write marked CLAUDE.md sections during skill install and update
- Write Cursor .mdc rules with alwaysApply for Cursor users
- Use HTML comment markers for idempotent append-or-replace on updates
- Non-fatal directive writing — skill installs even if directive fails

🎯 Two-layer defense ensures reliable skill triggering: the description
catches semantic matching, while the CLAUDE.md directive provides an
authoritative instruction that Claude cannot deprioritize in favor of
raw tool access.
2026-03-13 23:46:59 +05:30
sanjibdevnathlabs-release-bot[bot] 6db9227b59 chore(release): v1.2.1 v1.2.1 2026-03-13 17:26:09 +00:00