agent-canvas 0.1.37 → 0.1.39
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/highlightRange.ts +27 -17
- package/daemon/dist/client.js +27 -27
- 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/client.js +27 -27
|
@@ -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...");
|
|
@@ -58,6 +58,7 @@ function getTextNodesInRange(range: Range): Text[] {
|
|
|
58
58
|
// Skip line numbers and existing marks
|
|
59
59
|
const parent = node.parentElement;
|
|
60
60
|
if (parent?.classList.contains("select-none")) continue;
|
|
61
|
+
if (parent?.closest("[data-annotation-id]")) continue;
|
|
61
62
|
|
|
62
63
|
if (range.intersectsNode(node)) {
|
|
63
64
|
nodes.push(node);
|
|
@@ -108,27 +109,18 @@ export function restoreMarks(
|
|
|
108
109
|
container: HTMLElement,
|
|
109
110
|
annotations: { id: string; snippet: string; filePath?: string; context?: { before: string; after: string; hierarchy: string[] } }[]
|
|
110
111
|
) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
if (!toRestore.length) return;
|
|
112
|
+
for (const ann of annotations) {
|
|
113
|
+
// A canvas can be rendered more than once (overview, compare, hidden
|
|
114
|
+
// source panes), so restore decisions must be scoped to this container.
|
|
115
|
+
if (container.querySelector(`[data-annotation-id="${ann.id}"]`)) continue;
|
|
116
116
|
|
|
117
|
-
// Build full text content + mapping from text offset to (textNode, offsetInNode)
|
|
118
|
-
const textNodes: { node: Text; start: number }[] = [];
|
|
119
|
-
let fullText = "";
|
|
120
|
-
const walker = document.createTreeWalker(container, NodeFilter.SHOW_TEXT);
|
|
121
|
-
let tn: Text | null;
|
|
122
|
-
while ((tn = walker.nextNode() as Text | null)) {
|
|
123
|
-
if (tn.parentElement?.classList.contains("select-none")) continue;
|
|
124
|
-
textNodes.push({ node: tn, start: fullText.length });
|
|
125
|
-
fullText += tn.textContent || "";
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
for (const ann of toRestore) {
|
|
129
117
|
const snippet = ann.snippet;
|
|
130
118
|
if (!snippet) continue;
|
|
131
119
|
|
|
120
|
+
// Rebuild after every inserted mark. Wrapping text splits and moves text
|
|
121
|
+
// nodes, so a cached offset map can point at stale DOM after the first hit.
|
|
122
|
+
const { fullText, textNodes } = buildTextIndex(container);
|
|
123
|
+
|
|
132
124
|
// Find all occurrences of the snippet in the full text
|
|
133
125
|
const occurrences: number[] = [];
|
|
134
126
|
let searchFrom = 0;
|
|
@@ -181,6 +173,24 @@ export function restoreMarks(
|
|
|
181
173
|
}
|
|
182
174
|
}
|
|
183
175
|
|
|
176
|
+
function buildTextIndex(container: HTMLElement): {
|
|
177
|
+
fullText: string;
|
|
178
|
+
textNodes: { node: Text; start: number }[];
|
|
179
|
+
} {
|
|
180
|
+
const textNodes: { node: Text; start: number }[] = [];
|
|
181
|
+
let fullText = "";
|
|
182
|
+
const walker = document.createTreeWalker(container, NodeFilter.SHOW_TEXT);
|
|
183
|
+
let tn: Text | null;
|
|
184
|
+
while ((tn = walker.nextNode() as Text | null)) {
|
|
185
|
+
const parent = tn.parentElement;
|
|
186
|
+
if (parent?.classList.contains("select-none")) continue;
|
|
187
|
+
if (parent?.closest("[data-annotation-id]")) continue;
|
|
188
|
+
textNodes.push({ node: tn, start: fullText.length });
|
|
189
|
+
fullText += tn.textContent || "";
|
|
190
|
+
}
|
|
191
|
+
return { fullText, textNodes };
|
|
192
|
+
}
|
|
193
|
+
|
|
184
194
|
function offsetToNode(
|
|
185
195
|
textNodes: { node: Text; start: number }[],
|
|
186
196
|
offset: number
|