agent-canvas 0.1.23 → 0.1.24

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.
@@ -55,9 +55,13 @@ export async function handlePush(args: string[]) {
55
55
  let result = await response.json() as any;
56
56
 
57
57
  // Bun.build() can corrupt internal state in long-running daemons,
58
- // causing compilation failures that look like user errors. Restart
59
- // the daemon and retry once — if the retry also fails, it's a real error.
60
- if (!result.ok && result.error === "Canvas compilation failed") {
58
+ // throwing opaque errors like "Bundle failed" or "Unknown Error".
59
+ // Restart and retry once — but not for clear syntax errors (which
60
+ // now have precise line/col info from the transpiler pre-check).
61
+ const isBundlerCrash = !result.ok && result.error === "Canvas compilation failed"
62
+ && result.errors && Object.values(result.errors).some((e: any) =>
63
+ typeof e === "string" && (e === "Bundle failed" || e.includes("Unknown Error")));
64
+ if (isBundlerCrash) {
61
65
  console.error("Compilation failed, restarting daemon and retrying...");
62
66
  stopDaemon();
63
67
  await startDaemon();
@@ -20,6 +20,9 @@ const { Section, Item, Task, FilePreview, CodeBlock, Callout,
20
20
  Markdown, useFeedback, useAnnotations } = C;
21
21
  `;
22
22
 
23
+ /** Number of lines in COMPONENT_IMPORTS — used to adjust error line numbers */
24
+ const COMPONENT_IMPORTS_LINES = COMPONENT_IMPORTS.split("\n").length - 1;
25
+
23
26
  // --- Validation via Preact --------------------------------------------------
24
27
  // After Bun.build() succeeds we strip ESM syntax from the compiled output,
25
28
  // provide Preact as the React implementation with lightweight stub components,
@@ -121,7 +124,11 @@ async function validateCompiledPlan(js: string): Promise<{ ok: true } | { ok: fa
121
124
  try {
122
125
  await mermaid.parse(source);
123
126
  } catch (e: any) {
124
- return { ok: false, error: `Mermaid syntax error: ${e?.message || String(e)}` };
127
+ const msg = e?.message || String(e);
128
+ // DOMPurify doesn't work in Bun (no DOM) — mermaid.parse() triggers
129
+ // it for some diagram types even though it's just parsing. Skip these.
130
+ if (msg.includes("DOMPurify")) continue;
131
+ return { ok: false, error: `Mermaid syntax error: ${msg}` };
125
132
  }
126
133
  }
127
134
 
@@ -148,6 +155,20 @@ export async function compilePlan(jsx: string, projectRoot?: string): Promise<Co
148
155
  ? `${COMPONENT_IMPORTS}\n${jsx}`
149
156
  : `${COMPONENT_IMPORTS}\nexport default function Plan() {\n return (<>${jsx}</>);\n}\n`;
150
157
 
158
+ // Pre-validate syntax with Bun.Transpiler — gives precise error positions,
159
+ // unlike Bun.build() which throws opaque "Bundle failed" for syntax errors.
160
+ try {
161
+ const transpiler = new Bun.Transpiler({ loader: "jsx" });
162
+ transpiler.transformSync(source);
163
+ } catch (syntaxError: any) {
164
+ const pos = syntaxError?.position;
165
+ // Offset: COMPONENT_IMPORTS lines + wrapper lines (export default function Plan() + return)
166
+ const wrapperLines = hasDefaultExport ? 1 : 2;
167
+ const lineOffset = COMPONENT_IMPORTS_LINES + wrapperLines;
168
+ const loc = pos ? ` (line ${pos.line - lineOffset}, col ${pos.column})` : "";
169
+ return { ok: false, error: `${syntaxError?.message || "Syntax error"}${loc}` };
170
+ }
171
+
151
172
  const tmpFile = join(COMPILE_TEMP_DIR, `plan-${randomUUID()}.jsx`);
152
173
 
153
174
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-canvas",
3
- "version": "0.1.23",
3
+ "version": "0.1.24",
4
4
  "description": "Interactive visual canvas for Claude Code — rich annotatable documents in the browser",
5
5
  "bin": {
6
6
  "agent-canvas": "bin/agent-canvas.js"