Commit Graph
844 Commits
Author SHA1 Message Date
sudhir 45f0867a74 Extract floorplan render logic into editor 2D modules 2026-04-26 23:02:03 +05:30
Aymeric Rabot b3d1f663f6 fix(mcp): use local sqlite scene storage 2026-04-24 13:32:04 -07:00
Wassim SAMADandGitHub 47d6a70192 Merge pull request #271 from sudhir9297/feat/color-picker-tool
Feat/color picker tool
2026-04-24 14:54:33 -04:00
sudhir 275a42cc7f Simplify paint material compatibility logic 2026-04-25 00:15:29 +05:30
sudhir cb268509ea Invalidate viewer on hover style updates 2026-04-25 00:06:31 +05:30
sudhir d36441fa47 Add hover highlights to paint interactions 2026-04-24 23:29:34 +05:30
sudhir 2b656bcf8b Remove editor hover styles from viewer defaults 2026-04-24 23:05:14 +05:30
sudhir 325f2e4603 Refactor viewer hover styles and remove preview state 2026-04-24 22:49:04 +05:30
sudhir 7297c76204 Use paint icon for material mode 2026-04-24 12:50:05 +05:30
sudhir ed4d6dbdef Fix 2D floorplan placement and ceiling drawing coords 2026-04-24 12:45:12 +05:30
sudhir 83e1c9d1fd Align floorplan drawing with local build coordinates 2026-04-24 12:39:36 +05:30
sudhir a5448a0053 Make material categories horizontally scrollable 2026-04-24 10:43:38 +05:30
sudhir 2876f39876 Refactor paint materials to use category-based compatibility 2026-04-23 12:48:50 +05:30
sudhir 88b2f095f1 Merge branch 'feat/color-picker-tool' of github.com:sudhir9297/editor into feat/color-picker-tool 2026-04-23 10:26:54 +05:30
sudhir 4483957a0d Remove material pickers from side panels 2026-04-23 10:21:33 +05:30
sudhir fb3de8debc Refactor material paint preview handling 2026-04-22 18:16:20 +05:30
Sudhir YadavandGitHub 8fde99e7c9 Merge branch 'main' into feat/color-picker-tool 2026-04-22 17:57:26 +05:30
sudhir 1492e5bd0c Add roof drag controls to the 2D floorplan 2026-04-22 17:24:58 +05:30
sudhir a69591670d Refactor floorplan wall visuals and shared plan helpers 2026-04-22 15:34:22 +05:30
sudhir 87dfdf1b38 Add paint hover previews to viewer 2026-04-22 10:52:35 +05:30
PascalandGitHub c0021cee24 release: v0.6.0
release: v0.6.0
2026-04-21 16:57:29 -04:00
open-pascal f9f8e6abdc docs: add CHANGELOG for v0.6.0 with contributor credits 2026-04-21 20:57:24 +00:00
Pascal 4b5c3beadc release: v0.6.0
Bump @pascal-app/core, @pascal-app/viewer, and @pascal-app/editor to 0.6.0.
Update cross-package peer/dev dependency versions.
2026-04-21 20:52:02 +00:00
Wassim SAMADandGitHub 5fbab1af26 Merge pull request #267 from sudhir9297/fix/minor-bug-fixes
Fix/minor bug fixes
2026-04-21 08:34:38 -04:00
sudhir 65399731f7 Enable material paint for fence slab and ceiling nodes 2026-04-21 15:19:46 +05:30
sudhir b925cf1e7a Show paint cursor on incompatible clicks 2026-04-21 15:11:46 +05:30
sudhir 5d75e29bc5 Add material paint mode with scrollable palette 2026-04-21 15:00:09 +05:30
sudhir ec393b0c91 Use live snap settings in polygon editor and slab actions 2026-04-21 11:46:57 +05:30
sudhir 53720d664f Align roof and slab dragging to snap targets 2026-04-21 11:41:31 +05:30
sudhir 8ae217502c Add curved fence support 2026-04-21 11:26:49 +05:30
sudhir 5b5b80be61 Support fence endpoint moves and drafting snap 2026-04-21 11:18:54 +05:30
sudhir ffa78f1344 Fix realtime undo updates for wall and fence moves 2026-04-21 11:12:04 +05:30
Wassim SAMADandGitHub 86a4a82a92 Merge pull request #266 from sudhir9297/feat/nodes-material-system
feat: nodes material system and bug fix
2026-04-20 15:10:28 -04:00
sudhir 8cf2df1483 Unify material target selection across wall stair and roof 2026-04-20 22:45:56 +05:30
sudhir dd5b6e5e83 Fix slab material reload and wall curve step 2026-04-20 14:13:47 +05:30
sudhir b715e96038 Fix fence UV generation before geometry merge 2026-04-20 13:12:20 +05:30
sudhir dfdeca4aae Refine roof edit selection behavior and panel actions 2026-04-20 13:08:45 +05:30
sudhir bbc351d3a4 Add roof material targets and UV mapping 2026-04-20 12:57:06 +05:30
sudhir 05002a7865 Allow stair side clicks to target side materials 2026-04-20 12:04:43 +05:30
sudhir 4f9b822e54 Add click-targeted stair materials and UV mapping 2026-04-20 12:01:23 +05:30
sudhir df9c4e499f Restrict ground occluder to recessed slabs 2026-04-20 11:25:36 +05:30
sudhir 71ddb7052b Add two-sided wall material targeting 2026-04-20 11:18:20 +05:30
Adrian PerezandClaude Opus 4.7 06d00566f0 docs(mcp): fix residual stale-number references in PR description
Two lines still cited the pre-A2 state (294 tests / 40 files,
"known gaps remain at save_scene / POST boundary"). Corrected
against the actual 302/41 and the Phase 10 A2 closure of those
boundaries via the shared apiGraphSchema.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 21:03:44 +02:00
Adrian PerezandClaude Opus 4.7 7ed34f5b4f docs(mcp): update PR description with post-A2 state (302 tests, 20 commits)
A5 wrote the initial PR description before the A2 security fixes
landed, so it cited 294 tests / 9 commits and listed several now-fixed
items as follow-ups. Updated:

- 294 -> 302 tests (8 new SSRF guard tests in safe-fetch.test.ts)
- 40 -> 41 test files
- 9 -> 20 commits with the actual Phase 5-10 series listed
- Security-notes section: document safeFetch + shared apiGraphSchema
  wiring on both POST and PUT; remove "tracked follow-up" for
  save_scene URL validation (done); add "tracked follow-up" keeps
  same-id write race + auth layer
- Checklist: flip two items from [ ] to [x] for URL validation and
  SSRF protection

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 21:02:39 +02:00
Adrian PerezandClaude Opus 4.7 6ace4bf7c8 docs(mcp): add Phase 10 pre-push audit reports (5 agents)
Five parallel audit agents reviewed the branch before open-sourcing
the PR to pascalorg/editor:

- a1-secrets.md: SAFE TO PUSH. Scanned 176 files / 40,768 diff lines.
  Zero secrets, tokens, API keys, PEM blocks, JWTs, or cookies.
  Only MEDIUM finding: absolute /Users/adrian paths in test-report
  scripts (cosmetic, not security).

- a2-security.md: FOUND 2 HIGH-severity issues, both FIXED in
  commit 8757de0:
  * PUT /api/scenes/[id] still had the loose graphSchema that POST
    got fixed in Phase 8 P4. Shared schema extracted to
    apps/editor/lib/graph-schema.ts so both routes re-validate.
  * photo_to_scene + analyze_floorplan_image + analyze_room_photo
    all did raw fetch(url) on user-supplied URLs - a textbook SSRF
    to 169.254.169.254 cloud metadata. Added safe-fetch.ts with
    private-IP / link-local / .local-hostname denylists, manual
    redirect revalidation, size cap, timeout, env-allowlist.

- a3-code-quality.md: READY FOR REVIEW. Zero production `any`, all
  tools Zod-validated in+out, uniform error handling,
  conventional-commits. Two non-blocking follow-ups: client editor
  components (SceneLoader, SaveButton) have no tests; document
  check_collisions n^2 scaling.

- a4-performance.md: SHIP WITH NOTES. MCP dist 904 KB, Supabase
  lazy-imported (zero editor bundle impact), v0.1 hot paths
  sub-200ms. Flagged: FilesystemSceneStore.index.json O(n) per
  write (fine <1k scenes), concurrency races (documented in P8),
  client render at 5k nodes unverified.

- a5-pr-description.md: polished final PR description that
  corrected stale test counts (294 not 142), disclosed all 5
  cross-cutting surfaces, named the known failures honestly,
  split the checklist, expanded the scope to the real Phase 7
  deliverables.

Overall verdict: READY TO PUSH after the A2 fixes landed. No
blockers remain.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 21:00:02 +02:00
Adrian PerezandClaude Opus 4.7 8757de0c36 fix(mcp,editor): close PUT-route URL bypass + vision-tool SSRF (Phase 10 A2)
Pre-push audit agent A2 flagged two HIGH-severity security issues that
would have shipped in the PR had we not checked:

1. PUT /api/scenes/[id] URL-validation bypass. Phase 8 P4 fixed
   the POST /api/scenes route by replacing a loose z.unknown() graph
   schema with AnyNode superRefine. The fix never made it to the PUT
   handler - an attacker could resubmit the same javascript:/file:///
   payloads via PUT. Fixed by extracting the tight validator into
   apps/editor/lib/graph-schema.ts and sharing it across both routes.

2. SSRF in photo_to_scene / analyze_floorplan_image /
   analyze_room_photo. All three tools called raw fetch(image) on
   user-supplied URLs with no validation - a direct
   http://169.254.169.254/latest/meta-data/ exfil primitive on any
   cloud host. Added packages/mcp/src/lib/safe-fetch.ts that:
   - Blocks loopback (127.0.0.0/8, ::1)
   - Blocks link-local incl. cloud metadata (169.254.0.0/16)
   - Blocks private ranges (10/8, 172.16/12, 192.168/16, fc00::/7)
   - Blocks .local/.internal/.corp hostnames + localhost variants
   - Blocks v4-mapped IPv6 loopback (::ffff:127.0.0.1)
   - Manual redirects (max 3), revalidating the allowlist per hop
   - 20 MB response-size cap (streamed, enforced per-chunk)
   - 10s timeout
   - Optional PASCAL_ALLOWED_ASSET_ORIGINS env allowlist

Tests: 8 new SSRF guard tests, all vision tests still pass, full
suite 302/302.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 20:59:26 +02:00
Adrian PerezandClaude Opus 4.7 08e7b6db71 test(mcp): add populate-gallery script for post-ship demo
Seeds the shared scene store with Casa del Sol + 3 templates + 3 Villa
Azul variants so /scenes can be browsed end-to-end after a fresh
`bun dev` + `pascal-mcp --http` restart.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 20:52:55 +02:00
Adrian PerezandClaude Opus 4.7 f230d9a401 test(mcp): Villa Azul + 10-agent deep verification
Builds a larger, richer house than Casa del Sol via MCP save_scene
(no injection hack), then dispatches 10 parallel verifiers across
schema, geometry, dimensions, openings, HTTP, page render,
parentage, round-trip, spatial, visual.

Villa Azul — 56 nodes, validate_scene=true, 44KB on disk:
- 15x10m building envelope (vs Casa del Sol's 12x8)
- 9 interior zones (master bed/bath, bed 2/3, shared bath,
  living/dining, kitchen, entry hall, corridor)
- 10 doors + 12 windows (all cut successfully)
- 4 exterior zones (pool 8x4 + basin slab at -2m, outdoor kitchen,
  driveway, back patio)
- 5 rail-style fences (vs Casa del Sol's privacy) with 2m entrance gap

Verification: 108 checks, 104 PASS, 4 findings:
- V1 schema: 56/56
- V2 geometry: 7/7 (perimeter closes, interior T-junctions, no
  zone overlaps, fence gap verified)
- V3 dimensions: 13/13 zone areas exact (1 spec mismatch on site
  polygon default, not a build bug)
- V4 openings: 22/22 dimensional fit, surfaced a tool gap in
  cut_opening (no adjacency check) + my build packed too tightly
- V5 HTTP: 10/10 (GET/PUT/PATCH/DELETE/HEAD, If-Match conflicts)
- V6 page: 14/14 (/scene/:id 81KB, /scenes 20KB, 404 fallback)
- V7 parentage: surfaced CROSS_CUTTING §2 site->building->level
  parentId=null (pre-existing in core's loadScene)
- V8 round-trip: 10/10 byte-equal, duplicate_level -> 110 nodes
- V9 spatial: 12/12 (find_nodes, measure, constraints resource)
- V10 visual: HTML fallback (Chrome extension disconnected during
  run); API layer intact

Follow-up tracked: `cut_opening` should check opening-adjacency on
the same wall (minimum gap) to catch tight packing during patch
construction. Currently returns success and relies on the UI to
visualise the overlap.

Live at http://localhost:3002/scene/a6e7919eacbe.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 20:39:08 +02:00
Adrian PerezandClaude Opus 4.7 0b84e7b7b1 fix(mcp,editor): close URL-validation bypasses surfaced by Phase 8 P4
Phase 8 parallel validation flagged two boundaries where malicious URLs
(javascript:, file:, external http:, data:text/html, ...) could be
persisted despite the AssetUrl allowlist added in Phase 7 A7:

1. `save_scene({ includeCurrentScene: false, graph })` — the graph arg
   was treated as opaque (`z.record(z.string(), z.unknown())`) and
   written to the store without re-running AnyNode.safeParse.

2. `POST /api/scenes { graph }` in the editor API — same issue; the
   Zod `graphSchema` accepted anything object-shaped.

Fixes:
- `save-scene.ts`: when `includeCurrentScene === false`, iterate every
  node and run `AnyNode.safeParse`; collect issues and throw
  `McpError(InvalidParams, 'graph_invalid', { errors })` on any
  failure.
- `app/api/scenes/route.ts`: replace `graphSchema` with a structured
  `z.object({ nodes, rootNodeIds, collections? })` + `superRefine`
  that runs `AnyNode.safeParse` on every node. Invalid → 400 with
  detailed issue paths.

Tests:
- Added `save_scene` regression test for the P4 attack
  (item.asset.src = 'javascript:alert(1)') — expected error.
- Fixed the existing `includeCurrentScene=false` test to use a
  schema-compliant site node id (the prior `id: 'root'` now fails
  the AnyNode parse, which is the desired strict behaviour).
- Full suite: 294 pass / 0 fail.

Also adds Phase 8 test-reports/phase8/** (10 agents, ~15 scripts +
markdown reports) documenting the validation run, plus minor biome
cleanups to the Phase 5/7 test artefacts (removed stale
`// biome-ignore` suppression comments that now resolve to the
already-off `noConsole` rule).

Phase 8 result summary (10 parallel agents, stdio MCP transport with
isolated data dirs):
- P1 templates: 18/18 PASS
- P2 variants: 6/7 mutations + determinism + save + combined + error
- P3 locking: 12/12 PASS (MCP + editor HTTP If-Match)
- P4 URL hardening: fixed 2 bypasses (see above)
- P5 photo-to-scene: 6/6 PASS
- P6 Casa del Sol via save_scene: 13/13 PASS
- P7 editor HTTP API: 18/18 PASS
- P8 concurrency: 4/5 PASS, flagged 2 real filesystem-store races
  (expectedVersion CAS gap + .index.json drift under parallel writes)
- P9 edge cases: 13/13 PASS (size cap, slug safety, bad inputs)
- P10 full sweep: 37/37 PASS (30 tools + 4 resources + 3 prompts)

Known follow-ups:
- FilesystemSceneStore needs a proper lockfile / atomic CAS to fix
  the P8 concurrency bugs (low priority: single-writer MCP is the
  typical case).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 20:26:26 +02:00
Adrian PerezandClaude Opus 4.7 e8d0b13ff5 feat(mcp,editor): Option A+B storage + 10 agent deliverables (Phase 7)
Ships the combined filesystem/Supabase storage adapter + MCP scene
lifecycle tools + Next.js API routes + editor /scene/[id] route, so
an MCP save is directly openable at /scene/<id> without any
injection hack. End-to-end verified: 10/10 e2e steps pass.

Storage (A1/A2/A3):
- SceneStore interface + error classes + slug helpers
- FilesystemSceneStore at $PASCAL_DATA_DIR (defaults XDG/~/.pascal)
  with atomic writes, .index sidecar, optimistic locking
- SupabaseSceneStore with scenes + scene_revisions tables, RLS
  migration SQL, mock-backed unit tests
- createSceneStore(env) auto-selects based on SUPABASE_URL +
  SUPABASE_SERVICE_ROLE_KEY

MCP tools (A4, A8, A9, A10):
- save_scene / load_scene / list_scenes / delete_scene / rename_scene
- list_templates / create_from_template (3 seed templates:
  empty-studio, two-bedroom, garden-house)
- generate_variants (7 mutation kinds, seeded RNG, save=true|false)
- photo_to_scene (vision sampling → scene graph → save)

Editor (A5, A6):
- /api/scenes + /api/scenes/[id] with RFC 7232 If-Match locking
- /scene/[id] and /scenes route pages with save button, SceneLoader
- Removed the window.__pascalScene dev injection hack

Security + UX edges (A7, A8):
- AssetUrl Zod validator: asset:// blob: data:image/ /path https:
  (http://localhost for dev) + PASCAL_ALLOWED_ASSET_ORIGINS env
  allowlist. Hardens scan.url, guide.url, item.asset.src,
  material.texture.url, MaterialMaps.*Map
- Auto-frame camera on empty→non-empty scene transition
  (camera-controls:fit-scene emitter event)

Shared utilities:
- rehydrateSiteChildren() extracted to packages/mcp/src/lib/ and
  used by both create-from-template and generate-variants to work
  around the SiteNode.children-as-objects vs. ids inconsistency
  (CROSS_CUTTING §2)
- Storage + MCP subpath exports added to packages/mcp/package.json
  (CROSS_CUTTING §4)

Tests: 293 pass / 0 fail across 40 files (was 142 pre-Phase-7).
Biome: clean.

Phase-7 e2e script at packages/mcp/test-reports/phase7-e2e.ts:
MCP HTTP + editor Next.js both point at $PASCAL_DATA_DIR =
/tmp/pascal-e2e, save_scene from MCP, GET /api/scenes/<id> from
editor server, /scenes list page renders all saved scenes, scene
page renders SceneLoader, delete_scene works.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 19:29:28 +02:00