@sapiom/harness 0.1.6 → 0.2.1
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/CHANGELOG.md +105 -0
- package/dist/cli/args.d.ts +16 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +80 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/bin.js +12 -65
- package/dist/cli/bin.js.map +1 -1
- package/dist/cli/settings.d.ts.map +1 -1
- package/dist/cli/settings.js +33 -1
- package/dist/cli/settings.js.map +1 -1
- package/dist/core/adapters/claude-code.d.ts +60 -2
- package/dist/core/adapters/claude-code.d.ts.map +1 -1
- package/dist/core/adapters/claude-code.js +119 -32
- package/dist/core/adapters/claude-code.js.map +1 -1
- package/dist/core/adapters/codex.d.ts +21 -2
- package/dist/core/adapters/codex.d.ts.map +1 -1
- package/dist/core/adapters/codex.js +53 -2
- package/dist/core/adapters/codex.js.map +1 -1
- package/dist/core/adapters/detect.d.ts +9 -0
- package/dist/core/adapters/detect.d.ts.map +1 -1
- package/dist/core/adapters/detect.js +9 -0
- package/dist/core/adapters/detect.js.map +1 -1
- package/dist/core/canvas-body.d.ts +28 -28
- package/dist/core/canvas-body.d.ts.map +1 -1
- package/dist/core/canvas-body.js +117 -55
- package/dist/core/canvas-body.js.map +1 -1
- package/dist/core/canvas-derive.d.ts +43 -0
- package/dist/core/canvas-derive.d.ts.map +1 -0
- package/dist/core/canvas-derive.js +95 -0
- package/dist/core/canvas-derive.js.map +1 -0
- package/dist/core/canvas-enrichment.d.ts +52 -127
- package/dist/core/canvas-enrichment.d.ts.map +1 -1
- package/dist/core/canvas-enrichment.js +17 -178
- package/dist/core/canvas-enrichment.js.map +1 -1
- package/dist/core/canvas-graph.d.ts +40 -1
- package/dist/core/canvas-graph.d.ts.map +1 -1
- package/dist/core/canvas-graph.js +71 -9
- package/dist/core/canvas-graph.js.map +1 -1
- package/dist/core/canvas-interconnections.d.ts +26 -8
- package/dist/core/canvas-interconnections.d.ts.map +1 -1
- package/dist/core/canvas-interconnections.js +132 -24
- package/dist/core/canvas-interconnections.js.map +1 -1
- package/dist/core/canvas-manifest-check.d.ts.map +1 -1
- package/dist/core/canvas-manifest-check.js +15 -2
- package/dist/core/canvas-manifest-check.js.map +1 -1
- package/dist/core/canvas-render.d.ts +8 -15
- package/dist/core/canvas-render.d.ts.map +1 -1
- package/dist/core/canvas-render.js +29 -41
- package/dist/core/canvas-render.js.map +1 -1
- package/dist/core/canvas-run-state.d.ts +41 -0
- package/dist/core/canvas-run-state.d.ts.map +1 -1
- package/dist/core/canvas-run-state.js +136 -0
- package/dist/core/canvas-run-state.js.map +1 -1
- package/dist/core/canvas-svg.d.ts +9 -4
- package/dist/core/canvas-svg.d.ts.map +1 -1
- package/dist/core/canvas-svg.js +84 -13
- package/dist/core/canvas-svg.js.map +1 -1
- package/dist/core/canvas-template.d.ts +9 -10
- package/dist/core/canvas-template.d.ts.map +1 -1
- package/dist/core/canvas-template.js +57 -20
- package/dist/core/canvas-template.js.map +1 -1
- package/dist/core/canvas-watcher.d.ts +22 -1
- package/dist/core/canvas-watcher.d.ts.map +1 -1
- package/dist/core/canvas-watcher.js +111 -30
- package/dist/core/canvas-watcher.js.map +1 -1
- package/dist/core/collector/normalizer.d.ts +8 -0
- package/dist/core/collector/normalizer.d.ts.map +1 -1
- package/dist/core/collector/normalizer.js +8 -0
- package/dist/core/collector/normalizer.js.map +1 -1
- package/dist/core/collector/store.d.ts +75 -1
- package/dist/core/collector/store.d.ts.map +1 -1
- package/dist/core/collector/store.js +334 -2
- package/dist/core/collector/store.js.map +1 -1
- package/dist/core/errors.d.ts +10 -4
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +11 -5
- package/dist/core/errors.js.map +1 -1
- package/dist/core/example-seed.d.ts +8 -0
- package/dist/core/example-seed.d.ts.map +1 -1
- package/dist/core/example-seed.js +47 -10
- package/dist/core/example-seed.js.map +1 -1
- package/dist/core/inject/system-prompt.d.ts +8 -0
- package/dist/core/inject/system-prompt.d.ts.map +1 -1
- package/dist/core/inject/system-prompt.js +3 -1
- package/dist/core/inject/system-prompt.js.map +1 -1
- package/dist/core/macros.d.ts.map +1 -1
- package/dist/core/macros.js +5 -6
- package/dist/core/macros.js.map +1 -1
- package/dist/core/paths.d.ts +1 -0
- package/dist/core/paths.d.ts.map +1 -1
- package/dist/core/paths.js +1 -0
- package/dist/core/paths.js.map +1 -1
- package/dist/core/record-archive.d.ts +187 -0
- package/dist/core/record-archive.d.ts.map +1 -0
- package/dist/core/record-archive.js +465 -0
- package/dist/core/record-archive.js.map +1 -0
- package/dist/core/rehydration.d.ts +72 -0
- package/dist/core/rehydration.d.ts.map +1 -0
- package/dist/core/rehydration.js +72 -0
- package/dist/core/rehydration.js.map +1 -0
- package/dist/core/resume-brief.d.ts +130 -0
- package/dist/core/resume-brief.d.ts.map +1 -0
- package/dist/core/resume-brief.js +404 -0
- package/dist/core/resume-brief.js.map +1 -0
- package/dist/core/rolling-summary.d.ts +130 -0
- package/dist/core/rolling-summary.d.ts.map +1 -0
- package/dist/core/rolling-summary.js +227 -0
- package/dist/core/rolling-summary.js.map +1 -0
- package/dist/core/session-manager.d.ts +11 -3
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +56 -7
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-record.d.ts +165 -0
- package/dist/core/session-record.d.ts.map +1 -0
- package/dist/core/session-record.js +470 -0
- package/dist/core/session-record.js.map +1 -0
- package/dist/core/spawn-target.d.ts +12 -0
- package/dist/core/spawn-target.d.ts.map +1 -0
- package/dist/core/spawn-target.js +187 -0
- package/dist/core/spawn-target.js.map +1 -0
- package/dist/core/task-manager.d.ts.map +1 -1
- package/dist/core/task-manager.js +9 -1
- package/dist/core/task-manager.js.map +1 -1
- package/dist/core/template-catalog.d.ts +48 -0
- package/dist/core/template-catalog.d.ts.map +1 -0
- package/dist/core/template-catalog.js +338 -0
- package/dist/core/template-catalog.js.map +1 -0
- package/dist/core/workflow-registry.d.ts.map +1 -1
- package/dist/core/workflow-registry.js +2 -2
- package/dist/core/workflow-registry.js.map +1 -1
- package/dist/core/workspace-watcher.d.ts.map +1 -1
- package/dist/core/workspace-watcher.js +4 -3
- package/dist/core/workspace-watcher.js.map +1 -1
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -1
- package/dist/profiles/default.d.ts.map +1 -1
- package/dist/profiles/default.js +9 -14
- package/dist/profiles/default.js.map +1 -1
- package/dist/server/canvas.d.ts.map +1 -1
- package/dist/server/canvas.js +7 -7
- package/dist/server/canvas.js.map +1 -1
- package/dist/server/fs.d.ts.map +1 -1
- package/dist/server/fs.js +17 -1
- package/dist/server/fs.js.map +1 -1
- package/dist/server/index.d.ts +12 -3
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +321 -50
- package/dist/server/index.js.map +1 -1
- package/dist/server/ingest.d.ts +11 -0
- package/dist/server/ingest.d.ts.map +1 -1
- package/dist/server/ingest.js +1 -0
- package/dist/server/ingest.js.map +1 -1
- package/dist/server/macros.d.ts +4 -6
- package/dist/server/macros.d.ts.map +1 -1
- package/dist/server/macros.js.map +1 -1
- package/dist/server/rest.d.ts +18 -6
- package/dist/server/rest.d.ts.map +1 -1
- package/dist/server/rest.js +185 -48
- package/dist/server/rest.js.map +1 -1
- package/dist/server/templates.d.ts +24 -0
- package/dist/server/templates.d.ts.map +1 -0
- package/dist/server/templates.js +54 -0
- package/dist/server/templates.js.map +1 -0
- package/dist/shared/types.d.ts +477 -29
- package/dist/shared/types.d.ts.map +1 -1
- package/dist/shared/types.js +19 -11
- package/dist/shared/types.js.map +1 -1
- package/dist/web/assets/index-SYpugKQ1.css +32 -0
- package/dist/web/assets/index-vYYd44hZ.js +446 -0
- package/dist/web/index.html +2 -2
- package/package.json +5 -4
- package/dist/core/canvas-enrich.d.ts +0 -115
- package/dist/core/canvas-enrich.d.ts.map +0 -1
- package/dist/core/canvas-enrich.js +0 -186
- package/dist/core/canvas-enrich.js.map +0 -1
- package/dist/profiles/canvas-guidelines.d.ts +0 -20
- package/dist/profiles/canvas-guidelines.d.ts.map +0 -1
- package/dist/profiles/canvas-guidelines.js +0 -48
- package/dist/profiles/canvas-guidelines.js.map +0 -1
- package/dist/web/assets/index-DCtyI4VW.css +0 -32
- package/dist/web/assets/index-WSw5RvYR.js +0 -445
- package/dist/web/welcome-hero-dark.png +0 -0
- package/dist/web/welcome-hero-light.png +0 -0
package/dist/core/canvas-body.js
CHANGED
|
@@ -1,36 +1,134 @@
|
|
|
1
|
-
import { renderGraphSvg } from "./canvas-svg.js";
|
|
1
|
+
import { renderGraphSvg, usedKinds } from "./canvas-svg.js";
|
|
2
2
|
function esc(s) {
|
|
3
3
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
4
4
|
}
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
const NODE_KIND_LABEL = {
|
|
6
|
+
entry: "entry / active step",
|
|
7
|
+
step: "step",
|
|
8
|
+
pause: "pause / waits for input",
|
|
9
|
+
"terminal-success": "terminal · success",
|
|
10
|
+
"terminal-warn": "terminal · escalation",
|
|
11
|
+
"launched-workflow": "launches another workflow",
|
|
12
|
+
};
|
|
13
|
+
const NODE_KIND_ORDER = [
|
|
14
|
+
"entry",
|
|
15
|
+
"step",
|
|
16
|
+
"pause",
|
|
17
|
+
"terminal-success",
|
|
18
|
+
"terminal-warn",
|
|
19
|
+
"launched-workflow",
|
|
20
|
+
];
|
|
21
|
+
/**
|
|
22
|
+
* The color/shape key for one diagram: only the node kinds that actually appear
|
|
23
|
+
* (in stable order), plus a cross-workflow row when the graph has cross edges.
|
|
24
|
+
* Returns "" when nothing is worth keying, so the panel omits the footer.
|
|
25
|
+
*/
|
|
26
|
+
export function buildLegendHtml(nodeKinds, edgeKinds) {
|
|
27
|
+
const items = NODE_KIND_ORDER.filter((k) => nodeKinds.has(k)).map((k) => `<span class="canvas-legend-item"><span class="canvas-legend-marker canvas-legend-marker--${k}"></span>${NODE_KIND_LABEL[k]}</span>`);
|
|
28
|
+
if (edgeKinds.has("cross")) {
|
|
29
|
+
items.push(`<span class="canvas-legend-item"><span class="canvas-legend-marker canvas-legend-marker--cross"></span>cross-workflow signal/handoff</span>`);
|
|
30
|
+
}
|
|
31
|
+
if (items.length === 0)
|
|
32
|
+
return "";
|
|
33
|
+
return `<footer class="canvas-legend">${items.join("")}</footer>`;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Serializes the graph (enrichment merged) into the JSON payload the app's
|
|
37
|
+
* Steps tab / inspector consumes, embedded as a `<script id="sapiom-graph">`
|
|
38
|
+
* data block that `bootCanvasGraph` (canvas-run-state.ts) posts to the parent.
|
|
39
|
+
*
|
|
40
|
+
* The projection mirrors `renderGraphSvg`'s merge EXACTLY so the Steps tab and
|
|
41
|
+
* the drawn board never disagree: `role` = the node's sublabel (enrichment
|
|
42
|
+
* override first), `description` = the enrichment hover text, and each edge's
|
|
43
|
+
* `label` is keyed `from->to`. Web-only fields the server graph doesn't carry
|
|
44
|
+
* (timeout / input schema / capabilities) are omitted — `parseCanvasGraph`
|
|
45
|
+
* defaults them, so the drill-down degrades to names + roles + branch facts.
|
|
46
|
+
*
|
|
47
|
+
* `<` is escaped to `<` so a label containing `</script>` can't break out
|
|
48
|
+
* of the JSON block; the result is still valid JSON.
|
|
49
|
+
*/
|
|
50
|
+
function buildGraphPayload(graph, enrichment) {
|
|
51
|
+
const payload = {
|
|
52
|
+
name: graph.manifestName,
|
|
53
|
+
entry: graph.entry,
|
|
54
|
+
nodes: graph.nodes.map((n) => {
|
|
55
|
+
const details = enrichment?.nodeDetails?.[n.id];
|
|
56
|
+
return {
|
|
57
|
+
id: n.id,
|
|
58
|
+
kind: n.kind,
|
|
59
|
+
label: n.label,
|
|
60
|
+
role: details?.sublabel ?? n.sublabel ?? "",
|
|
61
|
+
// Manifest-authored description (Option A) wins; enrichment is the
|
|
62
|
+
// legacy fallback (currently always undefined).
|
|
63
|
+
description: details?.description ?? n.description ?? "",
|
|
64
|
+
inputSchema: n.inputSchema ?? null,
|
|
65
|
+
capabilities: n.capabilities ?? [],
|
|
66
|
+
timeoutMs: n.timeoutMs ?? null,
|
|
67
|
+
};
|
|
68
|
+
}),
|
|
69
|
+
edges: graph.edges.map((e) => ({
|
|
70
|
+
from: e.from,
|
|
71
|
+
to: e.to,
|
|
72
|
+
kind: e.kind,
|
|
73
|
+
label: enrichment?.edgeLabels?.[`${e.from}->${e.to}`] ?? e.label ?? "",
|
|
74
|
+
})),
|
|
75
|
+
warnings: graph.warnings,
|
|
76
|
+
};
|
|
77
|
+
return JSON.stringify(payload).replace(/</g, "\\u003c");
|
|
78
|
+
}
|
|
79
|
+
/** The workflow-level overview the Canvas tab's bottom panel shows: a
|
|
80
|
+
* deterministic stats line ("N steps · M exits · <entry> entry"), the shape
|
|
81
|
+
* summary as the description, and the graph's validation notes. Embedded as a
|
|
82
|
+
* JSON data block (read by bootCanvasOverview), the same pattern as the step
|
|
83
|
+
* graph — everything here is derived from the graph, no LLM. */
|
|
84
|
+
function buildOverviewPayload(graph, enrichment) {
|
|
85
|
+
const exits = graph.nodes.filter((n) => n.kind === "terminal-success" || n.kind === "terminal-warn").length;
|
|
86
|
+
const steps = graph.nodes.length - exits;
|
|
87
|
+
const entryLabel = graph.nodes.find((n) => n.id === graph.entry)?.label ?? graph.entry;
|
|
88
|
+
const parts = [`${steps} ${steps === 1 ? "step" : "steps"}`];
|
|
89
|
+
if (exits > 0)
|
|
90
|
+
parts.push(`${exits} ${exits === 1 ? "exit" : "exits"}`);
|
|
91
|
+
if (entryLabel)
|
|
92
|
+
parts.push(`${entryLabel} entry`);
|
|
93
|
+
const overview = {
|
|
94
|
+
// Human-authored workflow description from the manifest (Option A); "" when
|
|
95
|
+
// the workflow declares none (the shape summary still renders on the board).
|
|
96
|
+
description: graph.description ?? "",
|
|
97
|
+
stats: parts.join(" · "),
|
|
98
|
+
notes: enrichment?.notes ?? [],
|
|
99
|
+
};
|
|
100
|
+
// JSON in a <script> block: neutralize any "</script>"/"<" in derived text.
|
|
101
|
+
return JSON.stringify(overview).replace(/</g, "\\u003c");
|
|
102
|
+
}
|
|
103
|
+
/** One workflow's full panel: title/badges + summary header and the SVG
|
|
104
|
+
* diagram, with the deterministic enrichment merged in (summary line and
|
|
105
|
+
* node/edge annotations), plus the embedded step-graph payload the Steps tab
|
|
106
|
+
* reads. */
|
|
107
|
+
export function buildWorkflowPanelHtml(graph, meta, enrichment) {
|
|
9
108
|
const badges = (meta.badges ?? [])
|
|
10
109
|
.map((b) => `<span class="canvas-badge">${esc(b)}</span>`)
|
|
11
110
|
.join("");
|
|
12
111
|
const warningBadge = graph.warnings.length > 0
|
|
13
112
|
? `<span class="canvas-badge">${graph.warnings.length} warning${graph.warnings.length === 1 ? "" : "s"}</span>`
|
|
14
113
|
: "";
|
|
15
|
-
const enrichment = panelEnrichment?.enrichment ?? null;
|
|
16
|
-
const staleBadge = panelEnrichment?.stale
|
|
17
|
-
? `<span class="canvas-badge canvas-badge--stale">stale — Refresh</span>`
|
|
18
|
-
: "";
|
|
19
114
|
const summary = enrichment?.summary ? `\n <p class="canvas-subtitle">${esc(enrichment.summary)}</p>` : "";
|
|
115
|
+
const used = usedKinds(graph);
|
|
116
|
+
const legend = buildLegendHtml(used.nodeKinds, used.edgeKinds);
|
|
117
|
+
const legendHtml = legend ? `\n ${legend}` : "";
|
|
118
|
+
const graphData = buildGraphPayload(graph, enrichment);
|
|
119
|
+
const overviewData = buildOverviewPayload(graph, enrichment);
|
|
20
120
|
return `<section class="canvas-panel">
|
|
21
121
|
<header class="canvas-header">
|
|
22
122
|
<div class="canvas-title-row">
|
|
23
123
|
<h1 class="canvas-title">${esc(meta.title)}</h1>
|
|
24
|
-
${badges}${warningBadge}
|
|
124
|
+
${badges}${warningBadge}
|
|
25
125
|
</div>${summary}
|
|
26
|
-
<div class="canvas-stats">
|
|
27
|
-
<div class="canvas-stat"><span class="canvas-stat-value">${graph.nodes.length}</span><span class="canvas-stat-label">steps</span></div>
|
|
28
|
-
<div class="canvas-stat"><span class="canvas-stat-value">${esc(graph.entry)}</span><span class="canvas-stat-label">entry</span></div>
|
|
29
|
-
</div>
|
|
30
126
|
</header>
|
|
31
127
|
<div class="canvas-diagram-panel">
|
|
32
128
|
${renderGraphSvg(graph, enrichment)}
|
|
33
|
-
</div
|
|
129
|
+
</div>${legendHtml}
|
|
130
|
+
<script type="application/json" id="sapiom-graph">${graphData}</script>
|
|
131
|
+
<script type="application/json" id="sapiom-overview">${overviewData}</script>
|
|
34
132
|
</section>`;
|
|
35
133
|
}
|
|
36
134
|
/** A degraded panel for a workflow whose graph couldn't be extracted — never
|
|
@@ -49,46 +147,10 @@ export function buildErrorPanelHtml(title, reason) {
|
|
|
49
147
|
</div>
|
|
50
148
|
</section>`;
|
|
51
149
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
pause: "pause / waits for input",
|
|
56
|
-
"terminal-success": "terminal · success",
|
|
57
|
-
"terminal-warn": "terminal · escalation",
|
|
58
|
-
"launched-workflow": "launches another workflow",
|
|
59
|
-
};
|
|
60
|
-
const NODE_KIND_ORDER = [
|
|
61
|
-
"entry",
|
|
62
|
-
"step",
|
|
63
|
-
"pause",
|
|
64
|
-
"terminal-success",
|
|
65
|
-
"terminal-warn",
|
|
66
|
-
"launched-workflow",
|
|
67
|
-
];
|
|
68
|
-
/** Legend footer covering every node/edge kind actually used across every
|
|
69
|
-
* rendered panel (aggregate, not per-panel — matches the template's shape). */
|
|
70
|
-
export function buildLegendHtml(nodeKinds, edgeKinds) {
|
|
71
|
-
const items = NODE_KIND_ORDER.filter((k) => nodeKinds.has(k)).map((k) => `<span class="canvas-legend-item"><span class="canvas-legend-marker canvas-legend-marker--${k}"></span>${NODE_KIND_LABEL[k]}</span>`);
|
|
72
|
-
if (edgeKinds.has("cross")) {
|
|
73
|
-
items.push(`<span class="canvas-legend-item"><span class="canvas-legend-marker canvas-legend-marker--cross"></span>cross-workflow signal/handoff</span>`);
|
|
74
|
-
}
|
|
75
|
-
return `<div class="canvas-legend">${items.join("")}</div>`;
|
|
76
|
-
}
|
|
77
|
-
/** Joins panels + a footer (enrichment notes/cross-workflow tie, legend,
|
|
78
|
-
* note) into the final `#canvas-root` body — the string
|
|
79
|
-
* `renderCanvasDocument()` wraps. */
|
|
150
|
+
/** Joins the workflow panel(s) into the final `#canvas-root` body — the string
|
|
151
|
+
* `renderCanvasDocument()` wraps. Each panel already carries its own legend
|
|
152
|
+
* footer (see `buildWorkflowPanelHtml`); there is no document-level footer. */
|
|
80
153
|
export function assembleCanvasBody(input) {
|
|
81
|
-
|
|
82
|
-
const notesHtml = input.notes && input.notes.length > 0
|
|
83
|
-
? `\n <ul class="canvas-notes">${input.notes.map((n) => `<li>${esc(n)}</li>`).join("")}</ul>`
|
|
84
|
-
: "";
|
|
85
|
-
const crossHtml = input.crossWorkflow
|
|
86
|
-
? `\n <p class="canvas-cross-workflow">${esc(input.crossWorkflow)}</p>`
|
|
87
|
-
: "";
|
|
88
|
-
parts.push(`<footer class="canvas-footer">${notesHtml}${crossHtml}
|
|
89
|
-
${input.legend}
|
|
90
|
-
<p class="canvas-note">${esc(input.note)}</p>
|
|
91
|
-
</footer>`);
|
|
92
|
-
return parts.join("\n\n");
|
|
154
|
+
return input.panels.join("\n\n");
|
|
93
155
|
}
|
|
94
156
|
//# sourceMappingURL=canvas-body.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"canvas-body.js","sourceRoot":"","sources":["../../src/core/canvas-body.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"canvas-body.js","sourceRoot":"","sources":["../../src/core/canvas-body.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic canvas enrichment (no LLM, no user token, no file reads, no
|
|
3
|
+
* cache). Given the already-extracted CanvasGraph (core/canvas-graph.ts), it
|
|
4
|
+
* computes the same CanvasEnrichment shape the old AI task returned
|
|
5
|
+
* (core/canvas-enrichment.ts) — a summary line, footer notes, and a
|
|
6
|
+
* cross-workflow tie — entirely from the graph's own structure. Pure and
|
|
7
|
+
* total: the same graph in always yields the same enrichment out, and every
|
|
8
|
+
* string is kept within ENRICHMENT_LIMITS so the layout can't break.
|
|
9
|
+
*
|
|
10
|
+
* What it deliberately does NOT reproduce from the retired AI pass: free-prose
|
|
11
|
+
* per-step descriptions and condition-named edge labels, which needed a reading
|
|
12
|
+
* of the step bodies. The base render already conveys role (node border +
|
|
13
|
+
* classify-derived sublabel) and outcome (edge color), so their absence
|
|
14
|
+
* degrades to "less prose", never "less structure".
|
|
15
|
+
*/
|
|
16
|
+
import { type CanvasEnrichment } from "./canvas-enrichment.js";
|
|
17
|
+
import type { CanvasGraph } from "./canvas-graph.js";
|
|
18
|
+
/**
|
|
19
|
+
* A one-line description of the workflow's shape — step count, branch points,
|
|
20
|
+
* and terminal outcomes — the deterministic stand-in for the AI summary. Reads
|
|
21
|
+
* the same graph the diagram is drawn from, so it can never disagree with it.
|
|
22
|
+
*/
|
|
23
|
+
export declare function deriveSummary(graph: CanvasGraph): string;
|
|
24
|
+
/**
|
|
25
|
+
* Footer notes: the graph's own validation warnings (unreachable steps, no path
|
|
26
|
+
* to a terminal) — facts worth surfacing that the diagram can't show on its own.
|
|
27
|
+
* Undefined when the graph is clean, capped to the contract's count/length.
|
|
28
|
+
*/
|
|
29
|
+
export declare function deriveNotes(graph: CanvasGraph): string[] | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* The cross-workflow tie, derived from the dashed launched-workflow nodes the
|
|
32
|
+
* extraction already merged in (core/canvas-graph.ts's mergeLaunchesIntoGraph,
|
|
33
|
+
* fed by the grep in core/canvas-interconnections.ts). Undefined when this
|
|
34
|
+
* workflow launches none.
|
|
35
|
+
*/
|
|
36
|
+
export declare function deriveCrossWorkflow(graph: CanvasGraph): string | undefined;
|
|
37
|
+
/**
|
|
38
|
+
* Builds the deterministic enrichment for a graph. Only sets a field when it
|
|
39
|
+
* has real content, so an annotation-light but valid workflow renders its clean
|
|
40
|
+
* base — matching the "every field optional" contract the AI enrichment had.
|
|
41
|
+
*/
|
|
42
|
+
export declare function deriveEnrichment(graph: CanvasGraph): CanvasEnrichment;
|
|
43
|
+
//# sourceMappingURL=canvas-derive.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canvas-derive.d.ts","sourceRoot":"","sources":["../../src/core/canvas-derive.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAClF,OAAO,KAAK,EAAE,WAAW,EAA8B,MAAM,mBAAmB,CAAC;AAgBjF;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAuBxD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,EAAE,GAAG,SAAS,CAMpE;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,CAK1E;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,WAAW,GAAG,gBAAgB,CAOrE"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic canvas enrichment (no LLM, no user token, no file reads, no
|
|
3
|
+
* cache). Given the already-extracted CanvasGraph (core/canvas-graph.ts), it
|
|
4
|
+
* computes the same CanvasEnrichment shape the old AI task returned
|
|
5
|
+
* (core/canvas-enrichment.ts) — a summary line, footer notes, and a
|
|
6
|
+
* cross-workflow tie — entirely from the graph's own structure. Pure and
|
|
7
|
+
* total: the same graph in always yields the same enrichment out, and every
|
|
8
|
+
* string is kept within ENRICHMENT_LIMITS so the layout can't break.
|
|
9
|
+
*
|
|
10
|
+
* What it deliberately does NOT reproduce from the retired AI pass: free-prose
|
|
11
|
+
* per-step descriptions and condition-named edge labels, which needed a reading
|
|
12
|
+
* of the step bodies. The base render already conveys role (node border +
|
|
13
|
+
* classify-derived sublabel) and outcome (edge color), so their absence
|
|
14
|
+
* degrades to "less prose", never "less structure".
|
|
15
|
+
*/
|
|
16
|
+
import { ENRICHMENT_LIMITS } from "./canvas-enrichment.js";
|
|
17
|
+
/** Truncates to a hard cap with an ellipsis. The derivations below stay well
|
|
18
|
+
* under their caps; this just makes the same guarantee the contract does. */
|
|
19
|
+
function clamp(value, max) {
|
|
20
|
+
return value.length <= max ? value : `${value.slice(0, max - 1)}…`;
|
|
21
|
+
}
|
|
22
|
+
function countKind(nodes, kind) {
|
|
23
|
+
return nodes.filter((n) => n.kind === kind).length;
|
|
24
|
+
}
|
|
25
|
+
function plural(n, one, many = `${one}s`) {
|
|
26
|
+
return n === 1 ? one : many;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A one-line description of the workflow's shape — step count, branch points,
|
|
30
|
+
* and terminal outcomes — the deterministic stand-in for the AI summary. Reads
|
|
31
|
+
* the same graph the diagram is drawn from, so it can never disagree with it.
|
|
32
|
+
*/
|
|
33
|
+
export function deriveSummary(graph) {
|
|
34
|
+
// Real steps only — exclude the dashed launched-workflow placeholders.
|
|
35
|
+
const stepCount = graph.nodes.filter((n) => n.kind !== "launched-workflow").length;
|
|
36
|
+
// A branch point is a step that fans out to multiple successors; the graph
|
|
37
|
+
// marks exactly those edges "branching" (core/canvas-graph.ts's edgesForStep).
|
|
38
|
+
const branchPoints = new Set(graph.edges.filter((e) => e.kind === "branching").map((e) => e.from)).size;
|
|
39
|
+
const success = countKind(graph.nodes, "terminal-success");
|
|
40
|
+
const warn = countKind(graph.nodes, "terminal-warn");
|
|
41
|
+
const parts = [`${stepCount} ${plural(stepCount, "step")}`];
|
|
42
|
+
if (branchPoints > 0)
|
|
43
|
+
parts.push(`${branchPoints} ${plural(branchPoints, "branch point")}`);
|
|
44
|
+
const outcomes = [];
|
|
45
|
+
if (success > 0)
|
|
46
|
+
outcomes.push(`${success} success`);
|
|
47
|
+
if (warn > 0)
|
|
48
|
+
outcomes.push(`${warn} escalation`);
|
|
49
|
+
if (outcomes.length > 0) {
|
|
50
|
+
parts.push(`${outcomes.join(" / ")} ${plural(success + warn, "outcome")}`);
|
|
51
|
+
}
|
|
52
|
+
return clamp(parts.join(" · "), ENRICHMENT_LIMITS.summary);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Footer notes: the graph's own validation warnings (unreachable steps, no path
|
|
56
|
+
* to a terminal) — facts worth surfacing that the diagram can't show on its own.
|
|
57
|
+
* Undefined when the graph is clean, capped to the contract's count/length.
|
|
58
|
+
*/
|
|
59
|
+
export function deriveNotes(graph) {
|
|
60
|
+
if (graph.warnings.length === 0)
|
|
61
|
+
return undefined;
|
|
62
|
+
const notes = graph.warnings
|
|
63
|
+
.slice(0, ENRICHMENT_LIMITS.noteCount)
|
|
64
|
+
.map((w) => clamp(w, ENRICHMENT_LIMITS.note));
|
|
65
|
+
return notes.length > 0 ? notes : undefined;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* The cross-workflow tie, derived from the dashed launched-workflow nodes the
|
|
69
|
+
* extraction already merged in (core/canvas-graph.ts's mergeLaunchesIntoGraph,
|
|
70
|
+
* fed by the grep in core/canvas-interconnections.ts). Undefined when this
|
|
71
|
+
* workflow launches none.
|
|
72
|
+
*/
|
|
73
|
+
export function deriveCrossWorkflow(graph) {
|
|
74
|
+
const launched = graph.nodes.filter((n) => n.kind === "launched-workflow").map((n) => n.label);
|
|
75
|
+
if (launched.length === 0)
|
|
76
|
+
return undefined;
|
|
77
|
+
const unique = [...new Set(launched)].sort();
|
|
78
|
+
return clamp(`Launches ${unique.join(", ")}.`, ENRICHMENT_LIMITS.crossWorkflow);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Builds the deterministic enrichment for a graph. Only sets a field when it
|
|
82
|
+
* has real content, so an annotation-light but valid workflow renders its clean
|
|
83
|
+
* base — matching the "every field optional" contract the AI enrichment had.
|
|
84
|
+
*/
|
|
85
|
+
export function deriveEnrichment(graph) {
|
|
86
|
+
const enrichment = { summary: deriveSummary(graph) };
|
|
87
|
+
const notes = deriveNotes(graph);
|
|
88
|
+
if (notes)
|
|
89
|
+
enrichment.notes = notes;
|
|
90
|
+
const crossWorkflow = deriveCrossWorkflow(graph);
|
|
91
|
+
if (crossWorkflow)
|
|
92
|
+
enrichment.crossWorkflow = crossWorkflow;
|
|
93
|
+
return enrichment;
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=canvas-derive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canvas-derive.js","sourceRoot":"","sources":["../../src/core/canvas-derive.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* The canvas enrichment contract: the optional annotation layer merged on top
|
|
3
|
+
* of a deterministic canvas render — a summary line, per-node sublabels/hover
|
|
4
|
+
* descriptions, edge labels, footer notes, layout hints, and a cross-workflow
|
|
5
|
+
* tie. Every value is a BOUNDED plain string (the limits below are hard caps
|
|
6
|
+
* that keep the SVG layout from breaking); the renderer (core/canvas-svg.ts,
|
|
7
|
+
* core/canvas-body.ts) decides where each field goes.
|
|
8
|
+
*
|
|
9
|
+
* The enrichment is produced DETERMINISTICALLY, in-process, from the extracted
|
|
10
|
+
* graph — see core/canvas-derive.ts. There is no LLM, no user token, no file
|
|
11
|
+
* write, and no cache: it is recomputed from the current sources on every
|
|
12
|
+
* render, so it can never go stale. This module is now just the shared shape +
|
|
13
|
+
* limits both the producer (canvas-derive.ts) and the consumer (canvas-svg.ts,
|
|
14
|
+
* canvas-body.ts) agree on.
|
|
15
|
+
*
|
|
16
|
+
* Layout hints are the one structural field: named groups (rendered as subtle
|
|
17
|
+
* background bands) and per-layer ordering. The renderer applies a hint only
|
|
18
|
+
* when every node id it references actually exists in the graph (see
|
|
19
|
+
* canvas-svg.ts) — ids are validated at render time.
|
|
20
|
+
*/
|
|
3
21
|
export declare const ENRICHMENT_LIMITS: {
|
|
4
22
|
readonly summary: 160;
|
|
5
23
|
readonly sublabel: 48;
|
|
@@ -10,135 +28,42 @@ export declare const ENRICHMENT_LIMITS: {
|
|
|
10
28
|
readonly groupLabel: 48;
|
|
11
29
|
readonly crossWorkflow: 160;
|
|
12
30
|
};
|
|
13
|
-
|
|
31
|
+
/** Per-node annotations, keyed by node id. */
|
|
32
|
+
export interface CanvasNodeDetail {
|
|
33
|
+
/** Second text line inside the node box. */
|
|
34
|
+
sublabel?: string;
|
|
35
|
+
/** Hover tooltip (SVG <title>) — room for a full sentence. */
|
|
36
|
+
description?: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The one structural hint set: named clusters rendered as background bands
|
|
40
|
+
* behind their member nodes, and a preferred left-to-right node order per
|
|
41
|
+
* layout layer (keyed by the layer index as a string). `laneOrder` reorders
|
|
42
|
+
* WITHIN a computed layer only — it can never move a node between layers.
|
|
43
|
+
*/
|
|
44
|
+
export interface CanvasLayoutHints {
|
|
45
|
+
groups?: Array<{
|
|
46
|
+
label: string;
|
|
47
|
+
nodeIds: string[];
|
|
48
|
+
}>;
|
|
49
|
+
laneOrder?: Record<string, string[]>;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Everything the enrichment layer can add to a deterministic render. Every
|
|
53
|
+
* field is optional — the base structure render stands on its own without any
|
|
54
|
+
* of it, so a workflow with nothing worth annotating simply renders clean.
|
|
55
|
+
*/
|
|
56
|
+
export interface CanvasEnrichment {
|
|
14
57
|
/** One-liner under the panel header. */
|
|
15
|
-
summary
|
|
58
|
+
summary?: string;
|
|
16
59
|
/** Per-node annotations, keyed by node id. */
|
|
17
|
-
nodeDetails
|
|
18
|
-
/** Second text line inside the node box. */
|
|
19
|
-
sublabel: z.ZodOptional<z.ZodString>;
|
|
20
|
-
/** Hover tooltip (SVG <title>) — room for a full sentence. */
|
|
21
|
-
description: z.ZodOptional<z.ZodString>;
|
|
22
|
-
}, "strip", z.ZodTypeAny, {
|
|
23
|
-
description?: string | undefined;
|
|
24
|
-
sublabel?: string | undefined;
|
|
25
|
-
}, {
|
|
26
|
-
description?: string | undefined;
|
|
27
|
-
sublabel?: string | undefined;
|
|
28
|
-
}>>>;
|
|
60
|
+
nodeDetails?: Record<string, CanvasNodeDetail>;
|
|
29
61
|
/** Edge annotations (intent/condition names), keyed `"<from>-><to>"`. */
|
|
30
|
-
edgeLabels
|
|
62
|
+
edgeLabels?: Record<string, string>;
|
|
31
63
|
/** Footer facts worth knowing that don't fit the diagram itself. */
|
|
32
|
-
notes
|
|
33
|
-
layoutHints
|
|
34
|
-
/** Named clusters rendered as background bands behind member nodes. */
|
|
35
|
-
groups: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
36
|
-
label: z.ZodString;
|
|
37
|
-
nodeIds: z.ZodArray<z.ZodString, "many">;
|
|
38
|
-
}, "strip", z.ZodTypeAny, {
|
|
39
|
-
label: string;
|
|
40
|
-
nodeIds: string[];
|
|
41
|
-
}, {
|
|
42
|
-
label: string;
|
|
43
|
-
nodeIds: string[];
|
|
44
|
-
}>, "many">>;
|
|
45
|
-
/** Preferred left-to-right node order per layout layer, keyed by the
|
|
46
|
-
* layer index as a string. Reorders WITHIN the computed layer only —
|
|
47
|
-
* it can never move a node between layers. */
|
|
48
|
-
laneOrder: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString, "many">>>;
|
|
49
|
-
}, "strip", z.ZodTypeAny, {
|
|
50
|
-
groups?: {
|
|
51
|
-
label: string;
|
|
52
|
-
nodeIds: string[];
|
|
53
|
-
}[] | undefined;
|
|
54
|
-
laneOrder?: Record<string, string[]> | undefined;
|
|
55
|
-
}, {
|
|
56
|
-
groups?: {
|
|
57
|
-
label: string;
|
|
58
|
-
nodeIds: string[];
|
|
59
|
-
}[] | undefined;
|
|
60
|
-
laneOrder?: Record<string, string[]> | undefined;
|
|
61
|
-
}>>;
|
|
64
|
+
notes?: string[];
|
|
65
|
+
layoutHints?: CanvasLayoutHints;
|
|
62
66
|
/** How this workflow ties into the workspace's other workflows. */
|
|
63
|
-
crossWorkflow
|
|
64
|
-
}, "strip", z.ZodTypeAny, {
|
|
65
|
-
summary?: string | undefined;
|
|
66
|
-
nodeDetails?: Record<string, {
|
|
67
|
-
description?: string | undefined;
|
|
68
|
-
sublabel?: string | undefined;
|
|
69
|
-
}> | undefined;
|
|
70
|
-
edgeLabels?: Record<string, string> | undefined;
|
|
71
|
-
notes?: string[] | undefined;
|
|
72
|
-
layoutHints?: {
|
|
73
|
-
groups?: {
|
|
74
|
-
label: string;
|
|
75
|
-
nodeIds: string[];
|
|
76
|
-
}[] | undefined;
|
|
77
|
-
laneOrder?: Record<string, string[]> | undefined;
|
|
78
|
-
} | undefined;
|
|
79
|
-
crossWorkflow?: string | undefined;
|
|
80
|
-
}, {
|
|
81
|
-
summary?: string | undefined;
|
|
82
|
-
nodeDetails?: Record<string, {
|
|
83
|
-
description?: string | undefined;
|
|
84
|
-
sublabel?: string | undefined;
|
|
85
|
-
}> | undefined;
|
|
86
|
-
edgeLabels?: Record<string, string> | undefined;
|
|
87
|
-
notes?: string[] | undefined;
|
|
88
|
-
layoutHints?: {
|
|
89
|
-
groups?: {
|
|
90
|
-
label: string;
|
|
91
|
-
nodeIds: string[];
|
|
92
|
-
}[] | undefined;
|
|
93
|
-
laneOrder?: Record<string, string[]> | undefined;
|
|
94
|
-
} | undefined;
|
|
95
|
-
crossWorkflow?: string | undefined;
|
|
96
|
-
}>;
|
|
97
|
-
export type CanvasEnrichment = z.infer<typeof canvasEnrichmentSchema>;
|
|
98
|
-
export type CanvasLayoutHints = NonNullable<CanvasEnrichment["layoutHints"]>;
|
|
99
|
-
/**
|
|
100
|
-
* Validates a candidate enrichment object. Returns null on ANY schema
|
|
101
|
-
* violation (oversize string, wrong shape, too many notes) — partial
|
|
102
|
-
* salvage is deliberately not attempted, so the contract stays a hard line
|
|
103
|
-
* the prompt can state truthfully: "invalid output is thrown away whole."
|
|
104
|
-
*/
|
|
105
|
-
export declare function parseCanvasEnrichment(value: unknown): CanvasEnrichment | null;
|
|
106
|
-
/**
|
|
107
|
-
* Deterministic repair of the two ways an otherwise-good answer most often
|
|
108
|
-
* misses the contract, applied BEFORE strict validation:
|
|
109
|
-
* - `null` where the schema means "omit the field"
|
|
110
|
-
* - strings a few words over their cap (measured live: sonnet writes
|
|
111
|
-
* excellent content but doesn't count characters — a single 160-char note
|
|
112
|
-
* against the 140 cap discarded 3 of 4 real enrichments whole), truncated
|
|
113
|
-
* to the cap with an ellipsis; extra notes beyond the count cap dropped
|
|
114
|
-
*
|
|
115
|
-
* The bound the caps exist for — the AI can never blow up the layout with
|
|
116
|
-
* unbounded text — is still enforced, just deterministically here instead
|
|
117
|
-
* of by rejection. Everything else (wrong shapes, wrong types, unknown
|
|
118
|
-
* structure) still fails `parseCanvasEnrichment` and discards the
|
|
119
|
-
* enrichment whole.
|
|
120
|
-
*/
|
|
121
|
-
export declare function normalizeCanvasEnrichmentCandidate(value: unknown): unknown;
|
|
122
|
-
/**
|
|
123
|
-
* What one cache file holds. `sourceFingerprint` is canvas-cache.ts's cheap
|
|
124
|
-
* source fingerprint at the moment the enrichment task was SPAWNED — when it
|
|
125
|
-
* no longer matches the workflow's current sources, the base diagram
|
|
126
|
-
* re-renders immediately from fresh extraction while this enrichment stays
|
|
127
|
-
* displayed with a "stale" chip until a re-run replaces it.
|
|
128
|
-
*/
|
|
129
|
-
export interface EnrichmentCacheEntry {
|
|
130
|
-
/** The graph the enrichment was generated against (diagnostic context —
|
|
131
|
-
* renders always use the freshly extracted graph, never this copy). */
|
|
132
|
-
graph: CanvasGraph;
|
|
133
|
-
enrichment: CanvasEnrichment;
|
|
134
|
-
sourceFingerprint: string;
|
|
135
|
-
enrichedAt: string;
|
|
67
|
+
crossWorkflow?: string;
|
|
136
68
|
}
|
|
137
|
-
/** Reads + validates one enrichment cache file. Null for missing, unparsable
|
|
138
|
-
* or schema-invalid content — a bad cache degrades to "no enrichment". */
|
|
139
|
-
export declare function readEnrichmentCacheFile(filePath: string): Promise<EnrichmentCacheEntry | null>;
|
|
140
|
-
export declare function writeEnrichmentCacheFile(filePath: string, entry: EnrichmentCacheEntry): Promise<void>;
|
|
141
|
-
/** Deletes one enrichment cache file (the visualize macro's force refresh).
|
|
142
|
-
* Missing file is fine — the goal state is "no cache". */
|
|
143
|
-
export declare function removeEnrichmentCacheFile(filePath: string): Promise<void>;
|
|
144
69
|
//# sourceMappingURL=canvas-enrichment.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"canvas-enrichment.d.ts","sourceRoot":"","sources":["../../src/core/canvas-enrichment.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"canvas-enrichment.d.ts","sourceRoot":"","sources":["../../src/core/canvas-enrichment.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,eAAO,MAAM,iBAAiB;;;;;;;;;CASpB,CAAC;AAEX,8CAA8C;AAC9C,MAAM,WAAW,gBAAgB;IAC/B,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IACrD,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACtC;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8CAA8C;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAC/C,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,oEAAoE;IACpE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,mEAAmE;IACnE,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB"}
|