Wholesale swap of packages/{core,viewer,editor,mcp} and apps/editor with the
versions from the private editor repo, which is the production source of truth.
Setup changes:
- packages/{core,viewer,editor} versions held at 0.7.0 baseline (matching
the most recent published release) so a bump=minor publishes 0.8.0
- packages/mcp held at 0.1.1 (never published; first publish will go through
the new release.yml flow)
- peerDependencies and devDependencies for inter-package @pascal-app/*
references pinned to ^0.7.0 instead of '*' / 'workspace:*' so they are
valid for npm consumers
- Root package.json: TypeScript bumped to 6.0.2, added overrides for
@types/react, @types/react-dom, @types/three to prevent JSX namespace
fragmentation across the workspace
- release.yml extended to also publish editor and mcp; 'both' option renamed
to 'all'; added a sync step that updates inter-package peerDeps/devDeps to
match the new versions on every bump (so viewer/editor/mcp tarballs always
reference the version of core they were built against)
- Root scripts gained release:editor and release:mcp shortcuts
Verification:
- bun install --frozen-lockfile is consistent
- packages/{core,viewer,mcp} build cleanly, dist/index.d.ts emitted
- packages/editor check-types reports 21 pre-existing errors, identical to
what private-editor currently reports
Open PRs against editor-v2 will need rebasing/conflict resolution.
66 lines
3.6 KiB
TypeScript
66 lines
3.6 KiB
TypeScript
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
||
import { z } from 'zod'
|
||
import type { SceneOperations } from '../operations'
|
||
import { SCENE_DESIGN_GUIDANCE } from './scene-guidance'
|
||
|
||
const PREAMBLE = [
|
||
'You are a Pascal 3D scene designer.',
|
||
'You have access to semantic scene tools and the lower-level `apply_patch` tool. Prefer semantic construction/room/opening/furnishing tools for architectural work, and use `apply_patch` for bulk graph edits that need exact control.',
|
||
'If the user asks for a new project, call `create_project` before building. Use `create_house_from_brief` for a fast starter, then refine with semantic tools. Semantic tools update the browser-visible draft; call `save_scene` with `saveMode: "checkpoint"` only for meaningful milestones, then call `verify_scene` and `get_project_status`, and return the final `editorUrl`.',
|
||
'Build incrementally with visible progress. Starting from an empty scene, first create/load a Site and Building, then create occupied Levels and `create_story_shell` once per story before detailed rooms, openings, furniture, a dedicated roof level via `create_roof`, and landscaping.',
|
||
'Respect these invariants:',
|
||
' - Levels live under a Building.',
|
||
' - Walls, fences, zones, slabs, ceilings, roofs, stairs live under a Level.',
|
||
' - Multi-story exterior walls are per-level story walls; never make lower-level walls taller to stand in for upper-level walls.',
|
||
' - Doors and windows live under a Wall (parentId = wallId).',
|
||
' - Floor items live under a Level; wall/ceiling-attached items live under their target Wall or Ceiling. Do not place items directly under the Site node.',
|
||
'Use realistic dimensions in meters. Keep wall thickness small (0.1–0.3 m) and ceiling height 2.4–3.0 m unless the brief dictates otherwise.',
|
||
SCENE_DESIGN_GUIDANCE,
|
||
'Respond ONLY with tool calls. Do not produce verbose narrative or prose; keep any explanations in short tool-call arguments.',
|
||
].join('\n')
|
||
|
||
/**
|
||
* Build the user-facing prompt text for `from_brief`. Pure function for testability.
|
||
*/
|
||
export function buildFromBriefPrompt(args: {
|
||
brief: string
|
||
constraints?: string | undefined
|
||
}): string {
|
||
const parts: string[] = [PREAMBLE, '', '## Brief', args.brief.trim()]
|
||
if (args.constraints && args.constraints.trim().length > 0) {
|
||
parts.push('', '## Constraints', args.constraints.trim())
|
||
}
|
||
parts.push(
|
||
'',
|
||
'## Task',
|
||
'Produce tool calls that realise the brief within the stated constraints. For a new project, call create_project first. Use create_house_from_brief for a fast starter or prefer create_story_shell/create_room/add_door/add_window/create_stair_between_levels/create_roof/furnish_room for architectural layout, use apply_patch for exact bulk graph work, call save_scene with saveMode: "checkpoint" only when the design reaches a meaningful milestone, then call validate_scene, verify_scene, and get_project_status.',
|
||
)
|
||
return parts.join('\n')
|
||
}
|
||
|
||
export function registerFromBrief(server: McpServer, _bridge: SceneOperations): void {
|
||
server.registerPrompt(
|
||
'from_brief',
|
||
{
|
||
title: 'Generate a Pascal scene from a brief',
|
||
description:
|
||
'Produces a plan of apply_patch calls to create a scene from a natural-language brief.',
|
||
argsSchema: {
|
||
brief: z.string(),
|
||
constraints: z.string().optional(),
|
||
},
|
||
},
|
||
async ({ brief, constraints }) => ({
|
||
messages: [
|
||
{
|
||
role: 'user',
|
||
content: {
|
||
type: 'text',
|
||
text: buildFromBriefPrompt({ brief, constraints }),
|
||
},
|
||
},
|
||
],
|
||
}),
|
||
)
|
||
}
|