castle-web-cli 0.4.75 → 0.4.77

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 (74) hide show
  1. package/dist/agent-prompts.d.ts +13 -0
  2. package/dist/agent-prompts.js +43 -13
  3. package/dist/agent.d.ts +29 -0
  4. package/dist/agent.js +1004 -257
  5. package/dist/castle-host/host.js +59 -5
  6. package/dist/commonInstructions.d.ts +1 -1
  7. package/dist/commonInstructions.js +11 -1
  8. package/dist/filesChanged.d.ts +25 -0
  9. package/dist/filesChanged.js +140 -0
  10. package/dist/ide.d.ts +1 -0
  11. package/dist/ide.js +250 -1
  12. package/dist/init.js +46 -4
  13. package/dist/save-deck.js +8 -1
  14. package/dist/serve.js +45 -3
  15. package/dist/shell/assets/index-CvHiGhAV.js +141 -0
  16. package/dist/shell/assets/{index-WNbOHPBj.css → index-QteLRDnK.css} +1 -1
  17. package/dist/shell/index.html +2 -2
  18. package/kits/basic-2d/CLAUDE.md +13 -5
  19. package/kits/basic-2d/castle.json +15 -0
  20. package/kits/basic-2d/drawings/pig.pxart +22 -55
  21. package/kits/basic-2d/editors/PlayOnly.jsx +8 -3
  22. package/kits/basic-2d/editors/PxArtEditor.jsx +237 -4
  23. package/kits/basic-2d/editors/SingleEditor.jsx +30 -59
  24. package/kits/basic-2d/editors/pixelEditorChrome.jsx +17 -11
  25. package/kits/basic-2d/editors/pixelGeometry.js +95 -0
  26. package/kits/basic-2d/editors/pixelInspector.jsx +229 -51
  27. package/kits/basic-2d/editors/pxArtTools.js +109 -1
  28. package/kits/basic-2d/engine/ScenePlayer.jsx +11 -160
  29. package/kits/basic-2d/engine/liveReload.js +88 -0
  30. package/kits/basic-2d/engine/ui.jsx +15 -0
  31. package/kits/basic-2d/engine/ui.module.css +44 -117
  32. package/kits/basic-2d/main.jsx +6 -10
  33. package/package.json +10 -1
  34. package/dist/shell/assets/index-Dfn29Bkt.js +0 -108
  35. package/kits/basic-2d/editors/App.jsx +0 -226
  36. package/kits/basic-2d/editors/CodeEditor.jsx +0 -79
  37. package/kits/basic-2d/editors/FileBrowser.jsx +0 -349
  38. package/kits/basic-2d/editors/codeTheme.js +0 -135
  39. package/kits/basic-2d/engine/playConsole.js +0 -66
  40. package/kits/basic-2d/pnpm-workspace.yaml +0 -3
  41. package/kits/basic-3d/.prettierrc +0 -8
  42. package/kits/basic-3d/CLAUDE.md +0 -162
  43. package/kits/basic-3d/behaviors/Camera.jsx +0 -56
  44. package/kits/basic-3d/behaviors/Collider.jsx +0 -78
  45. package/kits/basic-3d/behaviors/Mesh.jsx +0 -82
  46. package/kits/basic-3d/behaviors/Model.jsx +0 -61
  47. package/kits/basic-3d/behaviors/Transform.jsx +0 -35
  48. package/kits/basic-3d/editors/App.jsx +0 -147
  49. package/kits/basic-3d/editors/CodeEditor.jsx +0 -112
  50. package/kits/basic-3d/editors/FileBrowser.jsx +0 -143
  51. package/kits/basic-3d/editors/ModelEditor.jsx +0 -400
  52. package/kits/basic-3d/editors/PlayOnly.jsx +0 -22
  53. package/kits/basic-3d/editors/SceneEditor.jsx +0 -1081
  54. package/kits/basic-3d/editors/behaviorRegistry.js +0 -24
  55. package/kits/basic-3d/editors/editorHistory.js +0 -52
  56. package/kits/basic-3d/editors/viewportRig.js +0 -90
  57. package/kits/basic-3d/engine/ScenePlayer.jsx +0 -58
  58. package/kits/basic-3d/engine/SceneUI.jsx +0 -67
  59. package/kits/basic-3d/engine/SceneViewport.jsx +0 -102
  60. package/kits/basic-3d/engine/autoInspector.jsx +0 -51
  61. package/kits/basic-3d/engine/files.js +0 -73
  62. package/kits/basic-3d/engine/scene.js +0 -502
  63. package/kits/basic-3d/engine/threeUtil.js +0 -260
  64. package/kits/basic-3d/engine/ui.jsx +0 -352
  65. package/kits/basic-3d/engine/ui.module.css +0 -944
  66. package/kits/basic-3d/eslint.config.js +0 -51
  67. package/kits/basic-3d/index.html +0 -11
  68. package/kits/basic-3d/main.jsx +0 -10
  69. package/kits/basic-3d/models/block.model +0 -14
  70. package/kits/basic-3d/package-lock.json +0 -2713
  71. package/kits/basic-3d/package.json +0 -41
  72. package/kits/basic-3d/pnpm-lock.yaml +0 -1769
  73. package/kits/basic-3d/scenes/main.scene +0 -76
  74. package/kits/basic-3d/vite.config.js +0 -1
package/dist/save-deck.js CHANGED
@@ -144,7 +144,14 @@ export async function saveDeck(dir, opts = {}) {
144
144
  uploadId: uploadConfig.uploadId,
145
145
  makeInitialCard: true,
146
146
  });
147
- const newCastleJson = { deckId: result.deckId, cardId: result.cardId, title };
147
+ // Preserve any deck-owned config already in castle.json (notably the
148
+ // `editor` block); save-deck only owns the identity fields below.
149
+ const newCastleJson = {
150
+ ...(castleJson ?? {}),
151
+ deckId: result.deckId,
152
+ cardId: result.cardId,
153
+ title,
154
+ };
148
155
  fs.writeFileSync(path.join(projectDir, 'castle.json'), JSON.stringify(newCastleJson, null, 2) + '\n', 'utf-8');
149
156
  if (isNew) {
150
157
  console.log(`Created deck "${title}" (${result.deckId}). Saved castle.json.`);
package/dist/serve.js CHANGED
@@ -7,6 +7,7 @@ import { WebSocketServer, WebSocket } from 'ws';
7
7
  import { createIdeServer } from './ide.js';
8
8
  import { createAgentServer } from './agent.js';
9
9
  import { sceneFilesPlugin } from './vitePlugins.js';
10
+ import { installFilesChangedWatcher } from './filesChanged.js';
10
11
  import * as config from './config.js';
11
12
  import { graphql as castleGraphql } from './api.js';
12
13
  import { executeCommand } from './castle-host/host.js';
@@ -25,13 +26,39 @@ async function findFreePorts(startPort) {
25
26
  }
26
27
  throw new Error(`No free port pair found starting from ${startPort}`);
27
28
  }
29
+ // Injected into the deck iframe (only when it carries `?logs=1`, i.e. the
30
+ // editor's builtin Play panel) to forward the deck's console output to the
31
+ // shell via postMessage, where the builtin Play panel renders a logs drawer.
32
+ // Kit-agnostic: works on a bare `--kit none` deck with no editor framework.
33
+ // Never injected for the published feed (that path doesn't go through dev serve).
34
+ const CONSOLE_CAPTURE = `<script>(function(){
35
+ try { if (new URLSearchParams(location.search).get('logs') !== '1') return; } catch (e) { return; }
36
+ if (window.parent === window) return;
37
+ var fmt = function (a) {
38
+ if (typeof a === 'string') return a;
39
+ if (a instanceof Error) return a.stack || a.message;
40
+ try { return JSON.stringify(a); } catch (e) { return String(a); }
41
+ };
42
+ ['log', 'warn', 'error'].forEach(function (level) {
43
+ var orig = typeof console[level] === 'function' ? console[level].bind(console) : null;
44
+ console[level] = function () {
45
+ if (orig) orig.apply(null, arguments);
46
+ try {
47
+ window.parent.postMessage(
48
+ { type: 'castle-console', level: level, text: Array.prototype.map.call(arguments, fmt).join(' ') },
49
+ '*'
50
+ );
51
+ } catch (e) {}
52
+ };
53
+ });
54
+ })();</script>`;
28
55
  function castlePlugin(wsPort, ideServer, agentServer) {
29
56
  return {
30
57
  name: 'castle-dev',
31
58
  transformIndexHtml: {
32
59
  order: 'pre',
33
60
  handler(html) {
34
- return html.replace(/<head(\s[^>]*)?>/i, (match) => `${match}\n <script>window.CastleEmbed={edit:true,host:'dev'};</script>`);
61
+ return html.replace(/<head(\s[^>]*)?>/i, (match) => `${match}\n <script>window.CastleEmbed={edit:true,host:'dev'};</script>\n ${CONSOLE_CAPTURE}`);
35
62
  },
36
63
  },
37
64
  configureServer(server) {
@@ -214,7 +241,7 @@ export async function serve(dir, options = {}) {
214
241
  // The WS server forwards `restart` to the browser, but it also needs the
215
242
  // Vite instance so it can drop transform caches first (see invalidateModuleCaches).
216
243
  const viteHolder = { vite: null };
217
- startWSServer(wsPort, projectDir, logFile, screenshotsDir, viteHolder);
244
+ const { broadcast } = startWSServer(wsPort, projectDir, logFile, screenshotsDir, viteHolder);
218
245
  // The deck root `/` serves a split-view shell: the deck in an iframe plus a
219
246
  // toggle button for an xterm.js terminal. The terminal's PTY is lazy -- it
220
247
  // spawns only when a browser first opens the PTY WebSocket.
@@ -253,6 +280,14 @@ export async function serve(dir, options = {}) {
253
280
  logLevel: 'info',
254
281
  });
255
282
  viteHolder.vite = vite;
283
+ // File changes from ANY source (editors, agents, terminal) become one
284
+ // coalesced `files_changed` broadcast; consumers decide what to reload.
285
+ installFilesChangedWatcher({
286
+ vite,
287
+ projectDir,
288
+ broadcast,
289
+ invalidate: () => invalidateModuleCaches(vite),
290
+ });
256
291
  await vite.listen();
257
292
  // The PTY WebSocket upgrade is handled directly on Vite's HTTP server rather
258
293
  // than through Vite's proxy (Vite's ws proxy didn't forward this path).
@@ -348,6 +383,13 @@ async function serveDetached(projectDir, options) {
348
383
  function startWSServer(port, projectDir, logFile, screenshotsDir, viteHolder) {
349
384
  const wss = new WebSocketServer({ port });
350
385
  const clients = new Set();
386
+ const broadcast = (msg) => {
387
+ const data = JSON.stringify(msg);
388
+ for (const c of clients) {
389
+ if (c.readyState === WebSocket.OPEN)
390
+ c.send(data);
391
+ }
392
+ };
351
393
  // For round-trip requests (e.g. screenshot), remember which socket issued a
352
394
  // given requestId so the matching response is routed back to just that
353
395
  // client instead of broadcast to every tab/CLI. Mirrors how `write_file`
@@ -465,7 +507,7 @@ function startWSServer(port, projectDir, logFile, screenshotsDir, viteHolder) {
465
507
  }
466
508
  });
467
509
  });
468
- return wss;
510
+ return { wss, broadcast };
469
511
  }
470
512
  function writeProjectFile(projectDir, requestedPath, contents) {
471
513
  if (typeof requestedPath !== 'string' || requestedPath.trim() === '') {