agent-canvas 0.1.36 → 0.1.38
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.
- package/.github/workflows/deploy-worker-prod.yml +3 -4
- package/.github/workflows/deploy-worker-stage.yml +3 -4
- package/.github/workflows/deploy-worker.yml +7 -8
- package/bin/lib/commands/push.ts +5 -1
- package/daemon/client/components/renderMarkdownChildren.tsx +54 -9
- package/daemon/dist/components.js +44 -44
- package/daemon/src/compiler.test.ts +39 -0
- package/daemon/src/compiler.ts +72 -11
- package/package.json +1 -1
- package/workers/canvas-share/public/assets/components.js +44 -44
|
@@ -14,7 +14,6 @@ jobs:
|
|
|
14
14
|
uses: ./.github/workflows/deploy-worker.yml
|
|
15
15
|
with:
|
|
16
16
|
env: prod
|
|
17
|
-
secrets
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
SHARE_AUTH_TOKEN: ${{ secrets.SHARE_AUTH_TOKEN_PROD }}
|
|
17
|
+
# inherit so the reusable workflow can resolve secrets; the env-scoped
|
|
18
|
+
# values (set on the `prod` environment) win over repo-level ones.
|
|
19
|
+
secrets: inherit
|
|
@@ -16,7 +16,6 @@ jobs:
|
|
|
16
16
|
uses: ./.github/workflows/deploy-worker.yml
|
|
17
17
|
with:
|
|
18
18
|
env: stage
|
|
19
|
-
secrets
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
SHARE_AUTH_TOKEN: ${{ secrets.SHARE_AUTH_TOKEN_STAGE }}
|
|
19
|
+
# inherit so the reusable workflow can resolve secrets; the env-scoped
|
|
20
|
+
# values (set on the `stage` environment) win over repo-level ones.
|
|
21
|
+
secrets: inherit
|
|
@@ -7,14 +7,13 @@ on:
|
|
|
7
7
|
description: "Target environment (stage or prod)"
|
|
8
8
|
required: true
|
|
9
9
|
type: string
|
|
10
|
-
secrets
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
required: false
|
|
10
|
+
# No `secrets:` inputs on purpose. The deploy job below declares
|
|
11
|
+
# `environment: ${{ inputs.env }}`, so referencing `secrets.X` directly
|
|
12
|
+
# resolves the matching *environment* secret (falling back to a
|
|
13
|
+
# repo-level secret of the same name). Callers pass `secrets: inherit`
|
|
14
|
+
# so org/repo secrets remain reachable too. This is what makes the
|
|
15
|
+
# CLOUDFLARE_* / SHARE_AUTH_TOKEN values environment-scoped — a prod
|
|
16
|
+
# token can never be read by a stage deploy and vice versa.
|
|
18
17
|
|
|
19
18
|
jobs:
|
|
20
19
|
deploy:
|
package/bin/lib/commands/push.ts
CHANGED
|
@@ -59,7 +59,11 @@ export async function handlePush(args: string[]) {
|
|
|
59
59
|
// Skip restart only for clear user errors (syntax errors with line/col,
|
|
60
60
|
// runtime validation errors) — those won't be fixed by a restart.
|
|
61
61
|
const isUserError = !result.ok && result.errors && Object.values(result.errors).every((e: any) =>
|
|
62
|
-
typeof e === "string" && (
|
|
62
|
+
typeof e === "string" && (
|
|
63
|
+
/\(line \d+, col \d+\)/.test(e) ||
|
|
64
|
+
/Syntax Error|Parse error|Mermaid syntax error/i.test(e) ||
|
|
65
|
+
e.startsWith("Runtime error:")
|
|
66
|
+
));
|
|
63
67
|
const shouldRestart = !result.ok && result.error === "Canvas compilation failed" && !isUserError;
|
|
64
68
|
if (shouldRestart) {
|
|
65
69
|
console.error("Compilation failed, restarting daemon and retrying...");
|
|
@@ -3,6 +3,27 @@ import { marked } from "marked";
|
|
|
3
3
|
|
|
4
4
|
marked.setOptions({ gfm: true, breaks: false });
|
|
5
5
|
|
|
6
|
+
/** Host tags that flow inline and must not break a prose run into separate blocks. */
|
|
7
|
+
const INLINE_TAGS = new Set([
|
|
8
|
+
"a", "abbr", "b", "br", "code", "del", "em", "i", "kbd", "mark",
|
|
9
|
+
"q", "s", "small", "span", "strong", "sub", "sup", "time", "u",
|
|
10
|
+
]);
|
|
11
|
+
|
|
12
|
+
/** Custom components that render inline (e.g. <Priority>). */
|
|
13
|
+
const INLINE_COMPONENTS = new Set(["Priority"]);
|
|
14
|
+
|
|
15
|
+
function isInlineNode(node: React.ReactNode): boolean {
|
|
16
|
+
if (typeof node === "string" || typeof node === "number") return true;
|
|
17
|
+
if (!React.isValidElement(node)) return false;
|
|
18
|
+
const type = node.type;
|
|
19
|
+
if (typeof type === "string") return INLINE_TAGS.has(type);
|
|
20
|
+
if (typeof type === "function") {
|
|
21
|
+
const name = (type as { displayName?: string; name?: string }).displayName ?? (type as { name?: string }).name;
|
|
22
|
+
return name ? INLINE_COMPONENTS.has(name) : false;
|
|
23
|
+
}
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
|
|
6
27
|
function renderTextAsMarkdown(text: string, key: string): React.ReactNode {
|
|
7
28
|
const trimmed = text.trim();
|
|
8
29
|
if (!trimmed) return null;
|
|
@@ -18,30 +39,54 @@ function renderTextAsMarkdown(text: string, key: string): React.ReactNode {
|
|
|
18
39
|
);
|
|
19
40
|
}
|
|
20
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Render a run of inline content (text + inline JSX like <code>/<strong>) as a single
|
|
44
|
+
* flowing paragraph. Text segments are parsed as inline markdown; JSX passes through.
|
|
45
|
+
* No `data-md` attribute so the markdown exporter treats it as an inline container.
|
|
46
|
+
*/
|
|
47
|
+
function renderInlineRun(run: React.ReactNode[], key: string): React.ReactNode {
|
|
48
|
+
return (
|
|
49
|
+
<div key={key} className="prose-canvas">
|
|
50
|
+
{run.map((node, i) => {
|
|
51
|
+
if (typeof node === "string" || typeof node === "number") {
|
|
52
|
+
const html = marked.parseInline(String(node), { async: false }) as string;
|
|
53
|
+
return <span key={i} dangerouslySetInnerHTML={{ __html: html }} />;
|
|
54
|
+
}
|
|
55
|
+
return node;
|
|
56
|
+
})}
|
|
57
|
+
</div>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
21
61
|
/**
|
|
22
62
|
* Auto-render markdown for string children, passing JSX children through.
|
|
23
|
-
*
|
|
24
|
-
*
|
|
63
|
+
* Block-level JSX (Callout, Diff, etc.) breaks the prose into separate markdown blocks,
|
|
64
|
+
* while inline JSX (code, strong, links) stays within the surrounding paragraph so text
|
|
65
|
+
* keeps flowing instead of stacking one fragment per line.
|
|
25
66
|
*/
|
|
26
67
|
export function renderMarkdownChildren(children: React.ReactNode): React.ReactNode {
|
|
27
68
|
const kids = React.Children.toArray(children);
|
|
28
69
|
if (kids.length === 0) return null;
|
|
29
70
|
|
|
30
71
|
const result: React.ReactNode[] = [];
|
|
31
|
-
let
|
|
32
|
-
let
|
|
72
|
+
let segment: React.ReactNode[] = [];
|
|
73
|
+
let segIdx = 0;
|
|
33
74
|
|
|
34
75
|
const flush = () => {
|
|
35
|
-
if (
|
|
36
|
-
|
|
76
|
+
if (segment.length === 0) return;
|
|
77
|
+
const hasInlineJsx = segment.some((n) => typeof n !== "string" && typeof n !== "number");
|
|
78
|
+
if (hasInlineJsx) {
|
|
79
|
+
result.push(renderInlineRun(segment, `md-${segIdx++}`));
|
|
80
|
+
} else {
|
|
81
|
+
const node = renderTextAsMarkdown(segment.join(""), `md-${segIdx++}`);
|
|
37
82
|
if (node) result.push(node);
|
|
38
|
-
buffer = "";
|
|
39
83
|
}
|
|
84
|
+
segment = [];
|
|
40
85
|
};
|
|
41
86
|
|
|
42
87
|
for (const child of kids) {
|
|
43
|
-
if (
|
|
44
|
-
|
|
88
|
+
if (isInlineNode(child)) {
|
|
89
|
+
segment.push(child);
|
|
45
90
|
} else {
|
|
46
91
|
flush();
|
|
47
92
|
result.push(child);
|