@sapiom/harness 0.1.5 → 0.2.0
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 +151 -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 +30 -66
- package/dist/cli/bin.js.map +1 -1
- package/dist/cli/consent.js +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/adapter.d.ts +2 -2
- 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/api-key-provider.d.ts +79 -0
- package/dist/core/api-key-provider.d.ts.map +1 -0
- package/dist/core/api-key-provider.js +91 -0
- package/dist/core/api-key-provider.js.map +1 -0
- 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 +50 -5
- package/dist/core/canvas-run-state.d.ts.map +1 -1
- package/dist/core/canvas-run-state.js +176 -11
- 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/definition-slug-resolver.d.ts +13 -0
- package/dist/core/definition-slug-resolver.d.ts.map +1 -1
- package/dist/core/definition-slug-resolver.js +29 -0
- package/dist/core/definition-slug-resolver.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/render-local-run.d.ts +82 -0
- package/dist/core/render-local-run.d.ts.map +1 -0
- package/dist/core/render-local-run.js +105 -0
- package/dist/core/render-local-run.js.map +1 -0
- package/dist/core/render-log-slice.d.ts +30 -0
- package/dist/core/render-log-slice.d.ts.map +1 -0
- package/dist/core/render-log-slice.js +49 -0
- package/dist/core/render-log-slice.js.map +1 -0
- package/dist/core/render-run-state.d.ts.map +1 -1
- package/dist/core/render-run-state.js +30 -49
- package/dist/core/render-run-state.js.map +1 -1
- 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/run-local-bootstrap.d.ts +93 -0
- package/dist/core/run-local-bootstrap.d.ts.map +1 -0
- package/dist/core/run-local-bootstrap.js +155 -0
- package/dist/core/run-local-bootstrap.js.map +1 -0
- package/dist/core/run-state.d.ts +16 -1
- package/dist/core/run-state.d.ts.map +1 -1
- package/dist/core/run-state.js +75 -25
- package/dist/core/run-state.js.map +1 -1
- 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/stub-feedback.d.ts +52 -0
- package/dist/core/stub-feedback.d.ts.map +1 -0
- package/dist/core/stub-feedback.js +33 -0
- package/dist/core/stub-feedback.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/actions.d.ts +139 -0
- package/dist/server/actions.d.ts.map +1 -0
- package/dist/server/actions.js +430 -0
- package/dist/server/actions.js.map +1 -0
- package/dist/server/auth-routes.d.ts +92 -0
- package/dist/server/auth-routes.d.ts.map +1 -0
- package/dist/server/auth-routes.js +151 -0
- package/dist/server/auth-routes.js.map +1 -0
- 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 +0 -0
- 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 -50
- package/dist/server/rest.js.map +1 -1
- package/dist/server/runs.d.ts +16 -15
- package/dist/server/runs.d.ts.map +1 -1
- package/dist/server/runs.js +15 -80
- package/dist/server/runs.js.map +1 -1
- package/dist/server/static.d.ts +15 -1
- package/dist/server/static.d.ts.map +1 -1
- package/dist/server/static.js +54 -4
- package/dist/server/static.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 +558 -66
- 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-DC65cskq.js +446 -0
- package/dist/web/assets/index-xtD-3FFa.css +32 -0
- package/dist/web/canvas/sess-boot/index.html +305 -0
- package/dist/web/index.html +4 -9
- package/package.json +8 -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/core/run-spend.d.ts +0 -55
- package/dist/core/run-spend.d.ts.map +0 -1
- package/dist/core/run-spend.js +0 -109
- package/dist/core/run-spend.js.map +0 -1
- package/dist/core/run-transactions.d.ts +0 -60
- package/dist/core/run-transactions.d.ts.map +0 -1
- package/dist/core/run-transactions.js +0 -129
- package/dist/core/run-transactions.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/server/skills.d.ts +0 -51
- package/dist/server/skills.d.ts.map +0 -1
- package/dist/server/skills.js +0 -312
- package/dist/server/skills.js.map +0 -1
- package/dist/web/assets/index-DM84J83Y.js +0 -234
- package/dist/web/assets/index-DemtWW4L.css +0 -32
|
@@ -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"}
|
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* nothing but itself.
|
|
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.
|
|
9
8
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
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.
|
|
16
20
|
*/
|
|
17
|
-
import * as fs from "node:fs/promises";
|
|
18
|
-
import * as path from "node:path";
|
|
19
|
-
import { z } from "zod";
|
|
20
21
|
export const ENRICHMENT_LIMITS = {
|
|
21
22
|
summary: 160,
|
|
22
23
|
sublabel: 48,
|
|
@@ -27,166 +28,4 @@ export const ENRICHMENT_LIMITS = {
|
|
|
27
28
|
groupLabel: 48,
|
|
28
29
|
crossWorkflow: 160,
|
|
29
30
|
};
|
|
30
|
-
const bounded = (max) => z.string().max(max);
|
|
31
|
-
export const canvasEnrichmentSchema = z
|
|
32
|
-
.object({
|
|
33
|
-
/** One-liner under the panel header. */
|
|
34
|
-
summary: bounded(ENRICHMENT_LIMITS.summary).optional(),
|
|
35
|
-
/** Per-node annotations, keyed by node id. */
|
|
36
|
-
nodeDetails: z
|
|
37
|
-
.record(z
|
|
38
|
-
.object({
|
|
39
|
-
/** Second text line inside the node box. */
|
|
40
|
-
sublabel: bounded(ENRICHMENT_LIMITS.sublabel).optional(),
|
|
41
|
-
/** Hover tooltip (SVG <title>) — room for a full sentence. */
|
|
42
|
-
description: bounded(ENRICHMENT_LIMITS.description).optional(),
|
|
43
|
-
})
|
|
44
|
-
.strip())
|
|
45
|
-
.optional(),
|
|
46
|
-
/** Edge annotations (intent/condition names), keyed `"<from>-><to>"`. */
|
|
47
|
-
edgeLabels: z.record(bounded(ENRICHMENT_LIMITS.edgeLabel)).optional(),
|
|
48
|
-
/** Footer facts worth knowing that don't fit the diagram itself. */
|
|
49
|
-
notes: z.array(bounded(ENRICHMENT_LIMITS.note)).max(ENRICHMENT_LIMITS.noteCount).optional(),
|
|
50
|
-
layoutHints: z
|
|
51
|
-
.object({
|
|
52
|
-
/** Named clusters rendered as background bands behind member nodes. */
|
|
53
|
-
groups: z
|
|
54
|
-
.array(z
|
|
55
|
-
.object({
|
|
56
|
-
label: bounded(ENRICHMENT_LIMITS.groupLabel),
|
|
57
|
-
nodeIds: z.array(z.string()).min(1),
|
|
58
|
-
})
|
|
59
|
-
.strip())
|
|
60
|
-
.optional(),
|
|
61
|
-
/** Preferred left-to-right node order per layout layer, keyed by the
|
|
62
|
-
* layer index as a string. Reorders WITHIN the computed layer only —
|
|
63
|
-
* it can never move a node between layers. */
|
|
64
|
-
laneOrder: z.record(z.array(z.string()).min(1)).optional(),
|
|
65
|
-
})
|
|
66
|
-
.strip()
|
|
67
|
-
.optional(),
|
|
68
|
-
/** How this workflow ties into the workspace's other workflows. */
|
|
69
|
-
crossWorkflow: bounded(ENRICHMENT_LIMITS.crossWorkflow).optional(),
|
|
70
|
-
})
|
|
71
|
-
.strip();
|
|
72
|
-
/**
|
|
73
|
-
* Validates a candidate enrichment object. Returns null on ANY schema
|
|
74
|
-
* violation (oversize string, wrong shape, too many notes) — partial
|
|
75
|
-
* salvage is deliberately not attempted, so the contract stays a hard line
|
|
76
|
-
* the prompt can state truthfully: "invalid output is thrown away whole."
|
|
77
|
-
*/
|
|
78
|
-
export function parseCanvasEnrichment(value) {
|
|
79
|
-
const parsed = canvasEnrichmentSchema.safeParse(value);
|
|
80
|
-
return parsed.success ? parsed.data : null;
|
|
81
|
-
}
|
|
82
|
-
function clampString(value, max) {
|
|
83
|
-
if (typeof value !== "string" || value.length <= max)
|
|
84
|
-
return value;
|
|
85
|
-
return `${value.slice(0, max - 1)}…`;
|
|
86
|
-
}
|
|
87
|
-
function isRecord(value) {
|
|
88
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
89
|
-
}
|
|
90
|
-
/** Removes null/undefined-valued properties (models write `"field": null`
|
|
91
|
-
* to mean "omitted"; the schema means it as `undefined`). Shallow — called
|
|
92
|
-
* per level below where object shapes are known. */
|
|
93
|
-
function dropNulls(record) {
|
|
94
|
-
return Object.fromEntries(Object.entries(record).filter(([, v]) => v != null));
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* Deterministic repair of the two ways an otherwise-good answer most often
|
|
98
|
-
* misses the contract, applied BEFORE strict validation:
|
|
99
|
-
* - `null` where the schema means "omit the field"
|
|
100
|
-
* - strings a few words over their cap (measured live: sonnet writes
|
|
101
|
-
* excellent content but doesn't count characters — a single 160-char note
|
|
102
|
-
* against the 140 cap discarded 3 of 4 real enrichments whole), truncated
|
|
103
|
-
* to the cap with an ellipsis; extra notes beyond the count cap dropped
|
|
104
|
-
*
|
|
105
|
-
* The bound the caps exist for — the AI can never blow up the layout with
|
|
106
|
-
* unbounded text — is still enforced, just deterministically here instead
|
|
107
|
-
* of by rejection. Everything else (wrong shapes, wrong types, unknown
|
|
108
|
-
* structure) still fails `parseCanvasEnrichment` and discards the
|
|
109
|
-
* enrichment whole.
|
|
110
|
-
*/
|
|
111
|
-
export function normalizeCanvasEnrichmentCandidate(value) {
|
|
112
|
-
if (!isRecord(value))
|
|
113
|
-
return value;
|
|
114
|
-
const L = ENRICHMENT_LIMITS;
|
|
115
|
-
const out = { ...value };
|
|
116
|
-
out.summary = clampString(out.summary, L.summary);
|
|
117
|
-
out.crossWorkflow = clampString(out.crossWorkflow, L.crossWorkflow);
|
|
118
|
-
if (isRecord(out.nodeDetails)) {
|
|
119
|
-
out.nodeDetails = Object.fromEntries(Object.entries(out.nodeDetails).map(([id, details]) => {
|
|
120
|
-
if (!isRecord(details))
|
|
121
|
-
return [id, details];
|
|
122
|
-
return [
|
|
123
|
-
id,
|
|
124
|
-
dropNulls({
|
|
125
|
-
...details,
|
|
126
|
-
sublabel: clampString(details.sublabel, L.sublabel),
|
|
127
|
-
description: clampString(details.description, L.description),
|
|
128
|
-
}),
|
|
129
|
-
];
|
|
130
|
-
}));
|
|
131
|
-
}
|
|
132
|
-
if (isRecord(out.edgeLabels)) {
|
|
133
|
-
out.edgeLabels = Object.fromEntries(Object.entries(out.edgeLabels).map(([key, label]) => [key, clampString(label, L.edgeLabel)]));
|
|
134
|
-
}
|
|
135
|
-
if (Array.isArray(out.notes)) {
|
|
136
|
-
out.notes = out.notes.slice(0, L.noteCount).map((note) => clampString(note, L.note));
|
|
137
|
-
}
|
|
138
|
-
if (isRecord(out.layoutHints)) {
|
|
139
|
-
const hints = dropNulls({ ...out.layoutHints });
|
|
140
|
-
if (Array.isArray(hints.groups)) {
|
|
141
|
-
hints.groups = hints.groups.map((group) => isRecord(group) ? dropNulls({ ...group, label: clampString(group.label, L.groupLabel) }) : group);
|
|
142
|
-
}
|
|
143
|
-
out.layoutHints = hints;
|
|
144
|
-
}
|
|
145
|
-
return dropNulls(out);
|
|
146
|
-
}
|
|
147
|
-
/** Envelope validation is deliberately shallow for `graph` (it's our own
|
|
148
|
-
* writer's serialization, not AI output) and strict for `enrichment` (it IS
|
|
149
|
-
* AI output — re-validated on every read, so a hand-edited or corrupted
|
|
150
|
-
* cache file can never smuggle unbounded strings into a render). */
|
|
151
|
-
const cacheEntrySchema = z.object({
|
|
152
|
-
graph: z.object({
|
|
153
|
-
manifestName: z.string(),
|
|
154
|
-
entry: z.string(),
|
|
155
|
-
nodes: z.array(z.record(z.unknown())),
|
|
156
|
-
edges: z.array(z.record(z.unknown())),
|
|
157
|
-
warnings: z.array(z.string()),
|
|
158
|
-
}),
|
|
159
|
-
enrichment: canvasEnrichmentSchema,
|
|
160
|
-
sourceFingerprint: z.string(),
|
|
161
|
-
enrichedAt: z.string(),
|
|
162
|
-
});
|
|
163
|
-
/** Reads + validates one enrichment cache file. Null for missing, unparsable
|
|
164
|
-
* or schema-invalid content — a bad cache degrades to "no enrichment". */
|
|
165
|
-
export async function readEnrichmentCacheFile(filePath) {
|
|
166
|
-
let raw;
|
|
167
|
-
try {
|
|
168
|
-
raw = await fs.readFile(filePath, "utf8");
|
|
169
|
-
}
|
|
170
|
-
catch {
|
|
171
|
-
return null;
|
|
172
|
-
}
|
|
173
|
-
try {
|
|
174
|
-
const parsed = cacheEntrySchema.safeParse(JSON.parse(raw));
|
|
175
|
-
// The shallow node/edge validation above means this cast, not a full
|
|
176
|
-
// structural proof — see the schema's own comment for why that's enough.
|
|
177
|
-
return parsed.success ? parsed.data : null;
|
|
178
|
-
}
|
|
179
|
-
catch {
|
|
180
|
-
return null;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
export async function writeEnrichmentCacheFile(filePath, entry) {
|
|
184
|
-
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
185
|
-
await fs.writeFile(filePath, JSON.stringify(entry, null, 2), "utf8");
|
|
186
|
-
}
|
|
187
|
-
/** Deletes one enrichment cache file (the visualize macro's force refresh).
|
|
188
|
-
* Missing file is fine — the goal state is "no cache". */
|
|
189
|
-
export async function removeEnrichmentCacheFile(filePath) {
|
|
190
|
-
await fs.rm(filePath, { force: true });
|
|
191
|
-
}
|
|
192
31
|
//# sourceMappingURL=canvas-enrichment.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"canvas-enrichment.js","sourceRoot":"","sources":["../../src/core/canvas-enrichment.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"canvas-enrichment.js","sourceRoot":"","sources":["../../src/core/canvas-enrichment.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,OAAO,EAAE,GAAG;IACZ,QAAQ,EAAE,EAAE;IACZ,WAAW,EAAE,GAAG;IAChB,SAAS,EAAE,EAAE;IACb,SAAS,EAAE,CAAC;IACZ,IAAI,EAAE,GAAG;IACT,UAAU,EAAE,EAAE;IACd,aAAa,EAAE,GAAG;CACV,CAAC"}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* instead of crashing or silently falling back to an LLM.
|
|
11
11
|
*/
|
|
12
12
|
import type { AgentManifest } from "@sapiom/agent";
|
|
13
|
-
import { type DetectedLaunch } from "./canvas-interconnections.js";
|
|
13
|
+
import { type DetectedLaunch, type DetectedCapability } from "./canvas-interconnections.js";
|
|
14
14
|
export type CanvasNodeKind = "entry" | "step" | "pause" | "terminal-success" | "terminal-warn" | "launched-workflow";
|
|
15
15
|
export type CanvasEdgeKind = "sequential" | "branching" | "cross" | "launch";
|
|
16
16
|
export interface CanvasNode {
|
|
@@ -18,6 +18,14 @@ export interface CanvasNode {
|
|
|
18
18
|
kind: CanvasNodeKind;
|
|
19
19
|
label: string;
|
|
20
20
|
sublabel?: string;
|
|
21
|
+
/** Human-authored step description from the manifest (Option A); "" when none. */
|
|
22
|
+
description?: string;
|
|
23
|
+
/** The step's declared input contract (JSON Schema) from the manifest. */
|
|
24
|
+
inputSchema?: Record<string, unknown> | null;
|
|
25
|
+
/** Author-declared Sapiom capabilities the step calls. */
|
|
26
|
+
capabilities?: readonly string[];
|
|
27
|
+
/** The step's declared dispatch timeout (ms); null when unset. */
|
|
28
|
+
timeoutMs?: number | null;
|
|
21
29
|
}
|
|
22
30
|
export interface CanvasEdge {
|
|
23
31
|
from: string;
|
|
@@ -30,6 +38,8 @@ export interface CanvasGraph {
|
|
|
30
38
|
/** The manifest's own name — used both as a display title fallback and as
|
|
31
39
|
* the match key for cross-workflow interconnection detection. */
|
|
32
40
|
manifestName: string;
|
|
41
|
+
/** Human-authored workflow description from the manifest (Option A); "" when none. */
|
|
42
|
+
description?: string;
|
|
33
43
|
entry: string;
|
|
34
44
|
nodes: CanvasNode[];
|
|
35
45
|
edges: CanvasEdge[];
|
|
@@ -47,6 +57,31 @@ export interface ExtractionFailure {
|
|
|
47
57
|
reason: string;
|
|
48
58
|
}
|
|
49
59
|
export type ExtractionResult = ExtractionSuccess | ExtractionFailure;
|
|
60
|
+
/**
|
|
61
|
+
* The precedence table above, over nothing but a step's declared transition
|
|
62
|
+
* kinds — so a caller that has transitions from somewhere OTHER than a local
|
|
63
|
+
* `AgentManifest` classifies identically.
|
|
64
|
+
*
|
|
65
|
+
* Exported because the Studio's template preview projects the SAME graph from
|
|
66
|
+
* core's relayed `DefinitionTransitionDto[]` (see `core/template-catalog.ts`).
|
|
67
|
+
* That preview claims parity with the canvas, so it must not re-derive this:
|
|
68
|
+
* a second copy of the rule is a second answer to "what kind of node is this",
|
|
69
|
+
* and the two surfaces disagreeing is the exact class of bug the template work
|
|
70
|
+
* set out to remove. Collapsing the four kinds into a single `terminal` boolean
|
|
71
|
+
* (as the first cut of that preview did) renders a fail-only sink as a green
|
|
72
|
+
* success exit and a `continue`-plus-`terminate` gate as a terminal.
|
|
73
|
+
*/
|
|
74
|
+
export declare function classifyStepKind(input: {
|
|
75
|
+
name: string;
|
|
76
|
+
entry: string;
|
|
77
|
+
transitions: ReadonlyArray<{
|
|
78
|
+
kind: string;
|
|
79
|
+
signal?: string | null;
|
|
80
|
+
}>;
|
|
81
|
+
}): {
|
|
82
|
+
kind: CanvasNodeKind;
|
|
83
|
+
sublabel: string;
|
|
84
|
+
};
|
|
50
85
|
/** Reshapes a validated `AgentManifest` into the render-ready graph model. */
|
|
51
86
|
export declare function graphFromManifest(manifest: AgentManifest, warnings: string[]): CanvasGraph;
|
|
52
87
|
/**
|
|
@@ -58,6 +93,10 @@ export declare function graphFromManifest(manifest: AgentManifest, warnings: str
|
|
|
58
93
|
* already shows those steps. Pure — returns a new graph.
|
|
59
94
|
*/
|
|
60
95
|
export declare function mergeLaunchesIntoGraph(graph: CanvasGraph, launches: readonly DetectedLaunch[]): CanvasGraph;
|
|
96
|
+
/** Fills each step node's `capabilities` from statically-detected
|
|
97
|
+
* `ctx.sapiom.*` calls, unless the manifest already declared them (authored
|
|
98
|
+
* capabilities win). Pure — returns a new graph. */
|
|
99
|
+
export declare function mergeCapabilitiesIntoGraph(graph: CanvasGraph, detected: readonly DetectedCapability[]): CanvasGraph;
|
|
61
100
|
/**
|
|
62
101
|
* Extracts a workflow's step graph from its project directory, with detected
|
|
63
102
|
* cross-workflow launches merged in as dashed nodes. Never throws: any
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"canvas-graph.d.ts","sourceRoot":"","sources":["../../src/core/canvas-graph.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,aAAa,EAAqB,MAAM,eAAe,CAAC;AAEtE,OAAO,
|
|
1
|
+
{"version":3,"file":"canvas-graph.d.ts","sourceRoot":"","sources":["../../src/core/canvas-graph.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,aAAa,EAAqB,MAAM,eAAe,CAAC;AAEtE,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACxB,MAAM,8BAA8B,CAAC;AAEtC,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,kBAAkB,GAAG,eAAe,GAAG,mBAAmB,CAAC;AACrH,MAAM,MAAM,cAAc,GAAG,YAAY,GAAG,WAAW,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE7E,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,cAAc,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kFAAkF;IAClF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0EAA0E;IAC1E,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC7C,0DAA0D;IAC1D,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,cAAc,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,oDAAoD;AACpD,MAAM,WAAW,WAAW;IAC1B;sEACkE;IAClE,YAAY,EAAE,MAAM,CAAC;IACrB,sFAAsF;IACtF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB;mEAC+D;IAC/D,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,IAAI,CAAC;IACT,KAAK,EAAE,WAAW,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,KAAK,CAAC;IACV,mFAAmF;IACnF,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,gBAAgB,GAAG,iBAAiB,GAAG,iBAAiB,CAAC;AA2BrE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,aAAa,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;CACtE,GAAG;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAiB7C;AAmBD,8EAA8E;AAC9E,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,WAAW,CAyB1F;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,cAAc,EAAE,GAAG,WAAW,CAqB3G;AAED;;qDAEqD;AACrD,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,SAAS,kBAAkB,EAAE,GACtC,WAAW,CAiBb;AAED;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAUvF"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { runManifestCheck } from "./canvas-manifest-check.js";
|
|
2
|
-
import {
|
|
2
|
+
import { scanWorkflowSources, } from "./canvas-interconnections.js";
|
|
3
3
|
/**
|
|
4
4
|
* Classifies a step for node styling. Priority: the entry step always reads
|
|
5
5
|
* as "entry" (the diagram's obvious starting point) even if it also happens
|
|
@@ -18,10 +18,28 @@ import { detectWorkflowLaunches } from "./canvas-interconnections.js";
|
|
|
18
18
|
* prefers an enrichment-supplied sublabel over this default when present.
|
|
19
19
|
*/
|
|
20
20
|
function classifyNode(name, entry, step) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
return classifyStepKind({ name, entry, transitions: step.transitions });
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The precedence table above, over nothing but a step's declared transition
|
|
25
|
+
* kinds — so a caller that has transitions from somewhere OTHER than a local
|
|
26
|
+
* `AgentManifest` classifies identically.
|
|
27
|
+
*
|
|
28
|
+
* Exported because the Studio's template preview projects the SAME graph from
|
|
29
|
+
* core's relayed `DefinitionTransitionDto[]` (see `core/template-catalog.ts`).
|
|
30
|
+
* That preview claims parity with the canvas, so it must not re-derive this:
|
|
31
|
+
* a second copy of the rule is a second answer to "what kind of node is this",
|
|
32
|
+
* and the two surfaces disagreeing is the exact class of bug the template work
|
|
33
|
+
* set out to remove. Collapsing the four kinds into a single `terminal` boolean
|
|
34
|
+
* (as the first cut of that preview did) renders a fail-only sink as a green
|
|
35
|
+
* success exit and a `continue`-plus-`terminate` gate as a terminal.
|
|
36
|
+
*/
|
|
37
|
+
export function classifyStepKind(input) {
|
|
38
|
+
const { name, entry, transitions } = input;
|
|
39
|
+
const continueTargets = transitions.filter((t) => t.kind === "continue");
|
|
40
|
+
const pause = transitions.find((t) => t.kind === "pause");
|
|
41
|
+
const hasTerminate = transitions.some((t) => t.kind === "terminate");
|
|
42
|
+
const hasFail = transitions.some((t) => t.kind === "fail");
|
|
25
43
|
if (name === entry)
|
|
26
44
|
return { kind: "entry", sublabel: "entry" };
|
|
27
45
|
if (pause)
|
|
@@ -55,10 +73,26 @@ function edgesForStep(name, step) {
|
|
|
55
73
|
export function graphFromManifest(manifest, warnings) {
|
|
56
74
|
const nodes = Object.entries(manifest.steps).map(([name, step]) => {
|
|
57
75
|
const { kind, sublabel } = classifyNode(name, manifest.entry, step);
|
|
58
|
-
return {
|
|
76
|
+
return {
|
|
77
|
+
id: name,
|
|
78
|
+
kind,
|
|
79
|
+
label: name,
|
|
80
|
+
sublabel,
|
|
81
|
+
description: step.description ?? "",
|
|
82
|
+
inputSchema: step.inputSchema ?? null,
|
|
83
|
+
capabilities: step.capabilities ?? [],
|
|
84
|
+
timeoutMs: step.timeoutMs ?? null,
|
|
85
|
+
};
|
|
59
86
|
});
|
|
60
87
|
const edges = Object.entries(manifest.steps).flatMap(([name, step]) => edgesForStep(name, step));
|
|
61
|
-
return {
|
|
88
|
+
return {
|
|
89
|
+
manifestName: manifest.name,
|
|
90
|
+
description: manifest.description ?? "",
|
|
91
|
+
entry: manifest.entry,
|
|
92
|
+
nodes,
|
|
93
|
+
edges,
|
|
94
|
+
warnings,
|
|
95
|
+
};
|
|
62
96
|
}
|
|
63
97
|
/**
|
|
64
98
|
* Merges heuristically detected cross-workflow launches into the workflow's
|
|
@@ -91,6 +125,30 @@ export function mergeLaunchesIntoGraph(graph, launches) {
|
|
|
91
125
|
}
|
|
92
126
|
return { ...graph, nodes, edges };
|
|
93
127
|
}
|
|
128
|
+
/** Fills each step node's `capabilities` from statically-detected
|
|
129
|
+
* `ctx.sapiom.*` calls, unless the manifest already declared them (authored
|
|
130
|
+
* capabilities win). Pure — returns a new graph. */
|
|
131
|
+
export function mergeCapabilitiesIntoGraph(graph, detected) {
|
|
132
|
+
if (detected.length === 0)
|
|
133
|
+
return graph;
|
|
134
|
+
const byStep = new Map();
|
|
135
|
+
for (const d of detected) {
|
|
136
|
+
if (!d.fromStepId)
|
|
137
|
+
continue;
|
|
138
|
+
const set = byStep.get(d.fromStepId) ?? new Set();
|
|
139
|
+
set.add(d.capability);
|
|
140
|
+
byStep.set(d.fromStepId, set);
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
...graph,
|
|
144
|
+
nodes: graph.nodes.map((n) => {
|
|
145
|
+
if ((n.capabilities?.length ?? 0) > 0)
|
|
146
|
+
return n; // authored capabilities win
|
|
147
|
+
const caps = byStep.get(n.id);
|
|
148
|
+
return caps ? { ...n, capabilities: [...caps].sort() } : n;
|
|
149
|
+
}),
|
|
150
|
+
};
|
|
151
|
+
}
|
|
94
152
|
/**
|
|
95
153
|
* Extracts a workflow's step graph from its project directory, with detected
|
|
96
154
|
* cross-workflow launches merged in as dashed nodes. Never throws: any
|
|
@@ -105,7 +163,11 @@ export async function extractWorkflowGraph(sourceDir) {
|
|
|
105
163
|
if (!result.ok)
|
|
106
164
|
return { ok: false, reason: result.reason };
|
|
107
165
|
const graph = graphFromManifest(result.manifest, result.warnings);
|
|
108
|
-
const
|
|
109
|
-
|
|
166
|
+
const stepIds = new Set(graph.nodes.map((n) => n.id));
|
|
167
|
+
// One walk over the sources yields both — halves the I/O on the auto-render
|
|
168
|
+
// hot path (this runs on every workflow-source save).
|
|
169
|
+
const { launches, capabilities } = await scanWorkflowSources(sourceDir, stepIds);
|
|
170
|
+
const withLaunches = mergeLaunchesIntoGraph(graph, launches);
|
|
171
|
+
return { ok: true, graph: mergeCapabilitiesIntoGraph(withLaunches, capabilities) };
|
|
110
172
|
}
|
|
111
173
|
//# sourceMappingURL=canvas-graph.js.map
|