castle-web-cli 0.4.10 → 0.4.12

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 (50) hide show
  1. package/dist/agent-prompts.d.ts +31 -0
  2. package/dist/agent-prompts.js +100 -0
  3. package/dist/agent.d.ts +17 -0
  4. package/dist/agent.js +894 -0
  5. package/dist/chat-client.d.ts +1 -0
  6. package/dist/chat-client.js +398 -0
  7. package/dist/commonInstructions.d.ts +1 -0
  8. package/dist/commonInstructions.js +8 -0
  9. package/dist/ide-client.js +46 -14
  10. package/dist/ide.d.ts +2 -0
  11. package/dist/ide.js +321 -36
  12. package/dist/init.js +12 -2
  13. package/dist/serve.js +62 -3
  14. package/kits/basic-2d/CLAUDE.md +3 -1
  15. package/kits/basic-2d/package.json +0 -1
  16. package/kits/basic-3d/.prettierrc +8 -0
  17. package/kits/basic-3d/CLAUDE.md +162 -0
  18. package/kits/basic-3d/behaviors/Camera.jsx +56 -0
  19. package/kits/basic-3d/behaviors/Collider.jsx +78 -0
  20. package/kits/basic-3d/behaviors/Mesh.jsx +82 -0
  21. package/kits/basic-3d/behaviors/Model.jsx +61 -0
  22. package/kits/basic-3d/behaviors/Transform.jsx +35 -0
  23. package/kits/basic-3d/editors/App.jsx +147 -0
  24. package/kits/basic-3d/editors/CodeEditor.jsx +112 -0
  25. package/kits/basic-3d/editors/FileBrowser.jsx +143 -0
  26. package/kits/basic-3d/editors/ModelEditor.jsx +400 -0
  27. package/kits/basic-3d/editors/PlayOnly.jsx +14 -0
  28. package/kits/basic-3d/editors/SceneEditor.jsx +1087 -0
  29. package/kits/basic-3d/editors/behaviorRegistry.js +24 -0
  30. package/kits/basic-3d/editors/editorHistory.js +52 -0
  31. package/kits/basic-3d/editors/viewportRig.js +90 -0
  32. package/kits/basic-3d/engine/ScenePlayer.jsx +55 -0
  33. package/kits/basic-3d/engine/SceneUI.jsx +67 -0
  34. package/kits/basic-3d/engine/SceneViewport.jsx +102 -0
  35. package/kits/basic-3d/engine/TouchControls.jsx +136 -0
  36. package/kits/basic-3d/engine/autoInspector.jsx +51 -0
  37. package/kits/basic-3d/engine/files.js +73 -0
  38. package/kits/basic-3d/engine/scene.js +502 -0
  39. package/kits/basic-3d/engine/threeUtil.js +260 -0
  40. package/kits/basic-3d/engine/ui.jsx +352 -0
  41. package/kits/basic-3d/engine/ui.module.css +944 -0
  42. package/kits/basic-3d/eslint.config.js +51 -0
  43. package/kits/basic-3d/index.html +11 -0
  44. package/kits/basic-3d/main.jsx +10 -0
  45. package/kits/basic-3d/models/block.model +14 -0
  46. package/kits/basic-3d/package-lock.json +2713 -0
  47. package/kits/basic-3d/package.json +41 -0
  48. package/kits/basic-3d/scenes/main.scene +76 -0
  49. package/kits/basic-3d/vite.config.js +1 -0
  50. package/package.json +6 -1
@@ -0,0 +1,31 @@
1
+ export interface PromptMessage {
2
+ role: 'user' | 'assistant';
3
+ text: string;
4
+ }
5
+ export interface PromptTask {
6
+ id: string;
7
+ title: string;
8
+ status: string;
9
+ progress: number;
10
+ notes: string;
11
+ }
12
+ export declare function buildRouterPrompt(opts: {
13
+ deckLabel: string;
14
+ messages: PromptMessage[];
15
+ tasks: PromptTask[];
16
+ instruction: string;
17
+ }): string;
18
+ export declare function userTurnInstruction(opts: {
19
+ text: string;
20
+ interruptedDraft?: string;
21
+ attachments?: string[];
22
+ }): string;
23
+ export declare function buildTaskPrompt(opts: {
24
+ deckLabel: string;
25
+ taskId: string;
26
+ title: string;
27
+ prompt: string;
28
+ progressPath: string;
29
+ notesPath: string;
30
+ depsSummary?: string;
31
+ }): string;
@@ -0,0 +1,100 @@
1
+ // Prompt builders for the agent panel: the conversational "router" that chats
2
+ // with the user and spawns background tasks, and the task agents that do the
3
+ // actual deck edits. Kept separate from agent.ts so the orchestration code
4
+ // stays readable.
5
+ // How many trailing conversation messages get replayed into each router call.
6
+ // Router calls are stateless (a fresh cursor-agent print run each time) so the
7
+ // transcript is the only memory.
8
+ const TRANSCRIPT_LIMIT = 40;
9
+ const ROUTER_RULES = `You are Castle's create assistant: the fast conversational router for a game-making session. The deck (game project) lives in the current directory and runs live in a pane right next to this chat.
10
+
11
+ Hard rules:
12
+ - You NEVER edit files or run state-changing commands. All building and fixing happens through background task agents -- always hand the longer work to them.
13
+ - You are the fast lane: get to your final reply as quickly as possible. When the user reports something broken, do NOT dig into the code to diagnose it first -- spawn a task whose job is to investigate AND fix it. Only read deck files when your reply itself needs them (answering a question about the deck, grounding a claim -- never make things up); never read as pre-work before spawning a task.
14
+ - Decompose with judgment -- parallel tasks are powerful but add overhead. Parallelize when the work is ambitious enough to be worth it, not for small asks.
15
+ - For a new game (or a substantial new part of one): make sure the FIRST task delivers a small coherent playable demo on its own, so the user is not waiting on several tasks before playing anything. Then fan out in parallel to take it further.
16
+ - Work on ART and MECHANICS simultaneously as separate tasks, with a later task (\`after:\` both) that combines them.
17
+ - Parallel tasks must each be separately testable and must not step on each other's files.
18
+ - To spawn a background task, include a fenced block in your reply:
19
+
20
+ \`\`\`castle-task
21
+ short imperative title on the first line
22
+ after: comma-separated titles or ids this task must wait for (optional line)
23
+ supersedes: comma-separated titles or ids this task replaces (optional line)
24
+ Then a detailed, self-contained prompt for the implementing agent:
25
+ what to build or fix, which files matter, and what "done" looks like.
26
+ \`\`\`
27
+
28
+ - Use \`after:\` only when a task truly builds on or would conflict with another (it may reference tasks spawned in this same reply, by title). Independent tasks must NOT wait on each other.
29
+ - Use \`supersedes:\` whenever the new task fixes, redoes, or makes obsolete an earlier task -- the old row is checked off the user's board automatically. Keep the board meaning "what to look at right now".
30
+ - Tasks are one-and-done -- when the user gives feedback on a finished task, spawn a new fix task rather than reopening the old one.
31
+ - Task agents are capable coding agents working in this same deck directory, but they know nothing about this conversation beyond your prompt.
32
+
33
+ Conversation style:
34
+ - As short and focused as possible -- a few tight sentences. Concrete, energetic. Ask at most one question per reply.
35
+ - Do not narrate before tool calls ("Checking the deck...") -- that reads as noise in the chat. Read silently, then give one reply after your final tool call.
36
+ - The user sees a live task board above the chat -- never re-announce task status yourself.
37
+ - The user playtests in the pane beside this chat; finished work shows up there after a reload.`;
38
+ function renderTranscript(messages) {
39
+ const recent = messages.slice(-TRANSCRIPT_LIMIT);
40
+ if (recent.length === 0)
41
+ return '(no conversation yet)';
42
+ return recent
43
+ .map((m) => `${m.role === 'user' ? 'user' : 'you'}: ${m.text}`)
44
+ .join('\n\n');
45
+ }
46
+ function renderTasks(tasks) {
47
+ if (tasks.length === 0)
48
+ return '(none yet)';
49
+ return tasks
50
+ .map((t) => {
51
+ const notes = t.notes.trim() ? ` -- notes: ${t.notes.trim()}` : '';
52
+ return `- [${t.status} ${t.progress}%] ${t.title} (${t.id})${notes}`;
53
+ })
54
+ .join('\n');
55
+ }
56
+ export function buildRouterPrompt(opts) {
57
+ return `${ROUTER_RULES}
58
+
59
+ == deck ==
60
+ ${opts.deckLabel}
61
+
62
+ == background tasks ==
63
+ ${renderTasks(opts.tasks)}
64
+
65
+ == conversation so far ==
66
+ ${renderTranscript(opts.messages)}
67
+
68
+ == now ==
69
+ ${opts.instruction}
70
+
71
+ Reply now, as "you" in the conversation. Plain reply text only -- no role prefix.`;
72
+ }
73
+ export function userTurnInstruction(opts) {
74
+ const parts = [];
75
+ if (opts.interruptedDraft?.trim()) {
76
+ parts.push(`Your previous reply was interrupted mid-stream by the user's new message. Its draft so far (already shown to the user; NO tasks were spawned from it):\n\n${opts.interruptedDraft.trim()}\n\nContinue that line of work AND address the new message -- do both in this one reply, spawning whatever tasks are needed for either.`);
77
+ }
78
+ parts.push(`The user just said:\n\n${opts.text}`);
79
+ if (opts.attachments && opts.attachments.length > 0) {
80
+ parts.push(`The user attached image file(s), saved in the deck at: ${opts.attachments.join(', ')}. Open them with your read tool and take them into account; pass the paths along to task agents that need them.`);
81
+ }
82
+ return parts.join('\n\n');
83
+ }
84
+ export function buildTaskPrompt(opts) {
85
+ const deps = opts.depsSummary
86
+ ? `\n\nThis task waited on earlier tasks:\n${opts.depsSummary}\n`
87
+ : '';
88
+ return `You are a background build agent for the Castle deck "${opts.deckLabel}" (current directory). A separate conversation agent dispatched you with one task. Read the deck's CLAUDE.md / AGENTS.md first and follow its workflow (including reloading the served deck after changes, e.g. \`npm run restart\`).
89
+
90
+ Your task (id ${opts.taskId}): ${opts.title}
91
+
92
+ ${opts.prompt}${deps}
93
+
94
+ Operating rules:
95
+ - Do this one task completely, then stop. Do not expand scope.
96
+ - Update your progress VERY frequently: write a bare integer 0-100 to ${opts.progressPath} (e.g. \`echo 30 > ${opts.progressPath}\`) every time you advance -- at least every 10 points, or every 20 for properly small tasks. Start near 10, write 90 just before wrapping up. Never let it sit stale while you work.
97
+ - Before finishing, write ${opts.notesPath}: a SHORT test guide for the user -- 2-4 brief sentences. Lead with exactly what to try in the running deck; mention a blocker or open question if you hit one. NO file-by-file implementation detail, no code names unless the user needs them to test. The user reads this verbatim when checking your work off.
98
+ - If you are truly blocked, write the blocker to the notes file and stop rather than guessing wildly.
99
+ - Never touch files under .castle/ other than those two paths.`;
100
+ }
@@ -0,0 +1,17 @@
1
+ import * as http from 'http';
2
+ import { Duplex } from 'stream';
3
+ export declare const AGENT_WS_PATH = "/__castle/agent";
4
+ export declare const AGENT_ATTACHMENT_PREFIX = "/__castle/agent/attachments/";
5
+ export type AgentBackend = 'cursor' | 'claude';
6
+ export type ClaudeModel = 'sonnet' | 'opus' | 'fable';
7
+ export interface AgentServer {
8
+ /** Attach the agent WebSocket if the upgrade targets the agent path. */
9
+ handleUpgrade(req: http.IncomingMessage, socket: Duplex, head: Buffer): boolean;
10
+ /** Serve attachment images. Returns true if it handled the request. */
11
+ handleHttpRequest(req: http.IncomingMessage, res: http.ServerResponse, reqPath: string): boolean;
12
+ shutdown(): void;
13
+ }
14
+ export declare function createAgentServer(opts: {
15
+ deckDir: string;
16
+ deckLabel: string;
17
+ }): AgentServer;