@sapiom/harness 0.0.0 → 0.1.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/LICENSE +21 -0
- package/README.md +44 -43
- package/dist/cli/auth.d.ts +26 -0
- package/dist/cli/auth.d.ts.map +1 -0
- package/dist/cli/auth.js +39 -0
- package/dist/cli/auth.js.map +1 -0
- package/dist/cli/bin.d.ts +3 -0
- package/dist/cli/bin.d.ts.map +1 -0
- package/dist/cli/bin.js +163 -0
- package/dist/cli/bin.js.map +1 -0
- package/dist/cli/consent.d.ts +15 -0
- package/dist/cli/consent.d.ts.map +1 -0
- package/dist/cli/consent.js +81 -0
- package/dist/cli/consent.js.map +1 -0
- package/dist/cli/doctor.d.ts +27 -0
- package/dist/cli/doctor.d.ts.map +1 -0
- package/dist/cli/doctor.js +74 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/machine-id.d.ts +19 -0
- package/dist/cli/machine-id.d.ts.map +1 -0
- package/dist/cli/machine-id.js +75 -0
- package/dist/cli/machine-id.js.map +1 -0
- package/dist/cli/paths.d.ts +3 -0
- package/dist/cli/paths.d.ts.map +1 -0
- package/dist/cli/paths.js +11 -0
- package/dist/cli/paths.js.map +1 -0
- package/dist/cli/settings.d.ts +26 -0
- package/dist/cli/settings.d.ts.map +1 -0
- package/dist/cli/settings.js +123 -0
- package/dist/cli/settings.js.map +1 -0
- package/dist/core/adapters/claude-code.d.ts +41 -0
- package/dist/core/adapters/claude-code.d.ts.map +1 -0
- package/dist/core/adapters/claude-code.js +238 -0
- package/dist/core/adapters/claude-code.js.map +1 -0
- package/dist/core/adapters/codex.d.ts +59 -0
- package/dist/core/adapters/codex.d.ts.map +1 -0
- package/dist/core/adapters/codex.js +319 -0
- package/dist/core/adapters/codex.js.map +1 -0
- package/dist/core/canvas-body.d.ts +45 -0
- package/dist/core/canvas-body.d.ts.map +1 -0
- package/dist/core/canvas-body.js +94 -0
- package/dist/core/canvas-body.js.map +1 -0
- package/dist/core/canvas-cache.d.ts +23 -0
- package/dist/core/canvas-cache.d.ts.map +1 -0
- package/dist/core/canvas-cache.js +64 -0
- package/dist/core/canvas-cache.js.map +1 -0
- package/dist/core/canvas-enrich.d.ts +106 -0
- package/dist/core/canvas-enrich.d.ts.map +1 -0
- package/dist/core/canvas-enrich.js +178 -0
- package/dist/core/canvas-enrich.js.map +1 -0
- package/dist/core/canvas-enrichment.d.ts +144 -0
- package/dist/core/canvas-enrichment.d.ts.map +1 -0
- package/dist/core/canvas-enrichment.js +192 -0
- package/dist/core/canvas-enrichment.js.map +1 -0
- package/dist/core/canvas-graph.d.ts +71 -0
- package/dist/core/canvas-graph.d.ts.map +1 -0
- package/dist/core/canvas-graph.js +111 -0
- package/dist/core/canvas-graph.js.map +1 -0
- package/dist/core/canvas-index-classify.d.ts +41 -0
- package/dist/core/canvas-index-classify.d.ts.map +1 -0
- package/dist/core/canvas-index-classify.js +63 -0
- package/dist/core/canvas-index-classify.js.map +1 -0
- package/dist/core/canvas-interconnections.d.ts +24 -0
- package/dist/core/canvas-interconnections.d.ts.map +1 -0
- package/dist/core/canvas-interconnections.js +96 -0
- package/dist/core/canvas-interconnections.js.map +1 -0
- package/dist/core/canvas-manifest-check.d.ts +15 -0
- package/dist/core/canvas-manifest-check.d.ts.map +1 -0
- package/dist/core/canvas-manifest-check.js +90 -0
- package/dist/core/canvas-manifest-check.js.map +1 -0
- package/dist/core/canvas-render.d.ts +73 -0
- package/dist/core/canvas-render.d.ts.map +1 -0
- package/dist/core/canvas-render.js +145 -0
- package/dist/core/canvas-render.js.map +1 -0
- package/dist/core/canvas-svg.d.ts +50 -0
- package/dist/core/canvas-svg.d.ts.map +1 -0
- package/dist/core/canvas-svg.js +240 -0
- package/dist/core/canvas-svg.js.map +1 -0
- package/dist/core/canvas-template.d.ts +43 -0
- package/dist/core/canvas-template.d.ts.map +1 -0
- package/dist/core/canvas-template.js +365 -0
- package/dist/core/canvas-template.js.map +1 -0
- package/dist/core/canvas-watcher.d.ts +25 -0
- package/dist/core/canvas-watcher.d.ts.map +1 -0
- package/dist/core/canvas-watcher.js +144 -0
- package/dist/core/canvas-watcher.js.map +1 -0
- package/dist/core/collector/batcher.d.ts +57 -0
- package/dist/core/collector/batcher.d.ts.map +1 -0
- package/dist/core/collector/batcher.js +143 -0
- package/dist/core/collector/batcher.js.map +1 -0
- package/dist/core/collector/codex-tailer.d.ts +85 -0
- package/dist/core/collector/codex-tailer.d.ts.map +1 -0
- package/dist/core/collector/codex-tailer.js +270 -0
- package/dist/core/collector/codex-tailer.js.map +1 -0
- package/dist/core/collector/normalizer.d.ts +33 -0
- package/dist/core/collector/normalizer.d.ts.map +1 -0
- package/dist/core/collector/normalizer.js +94 -0
- package/dist/core/collector/normalizer.js.map +1 -0
- package/dist/core/collector/seq.d.ts +14 -0
- package/dist/core/collector/seq.d.ts.map +1 -0
- package/dist/core/collector/seq.js +20 -0
- package/dist/core/collector/seq.js.map +1 -0
- package/dist/core/collector/store.d.ts +16 -0
- package/dist/core/collector/store.d.ts.map +1 -0
- package/dist/core/collector/store.js +30 -0
- package/dist/core/collector/store.js.map +1 -0
- package/dist/core/collector/transcript.d.ts +38 -0
- package/dist/core/collector/transcript.d.ts.map +1 -0
- package/dist/core/collector/transcript.js +110 -0
- package/dist/core/collector/transcript.js.map +1 -0
- package/dist/core/event-bus.d.ts +9 -0
- package/dist/core/event-bus.d.ts.map +1 -0
- package/dist/core/event-bus.js +25 -0
- package/dist/core/event-bus.js.map +1 -0
- package/dist/core/example-seed.d.ts +34 -0
- package/dist/core/example-seed.d.ts.map +1 -0
- package/dist/core/example-seed.js +277 -0
- package/dist/core/example-seed.js.map +1 -0
- package/dist/core/inject/claude-settings.d.ts +34 -0
- package/dist/core/inject/claude-settings.d.ts.map +1 -0
- package/dist/core/inject/claude-settings.js +152 -0
- package/dist/core/inject/claude-settings.js.map +1 -0
- package/dist/core/inject/mcp-config.d.ts +26 -0
- package/dist/core/inject/mcp-config.d.ts.map +1 -0
- package/dist/core/inject/mcp-config.js +39 -0
- package/dist/core/inject/mcp-config.js.map +1 -0
- package/dist/core/inject/retention.d.ts +66 -0
- package/dist/core/inject/retention.d.ts.map +1 -0
- package/dist/core/inject/retention.js +119 -0
- package/dist/core/inject/retention.js.map +1 -0
- package/dist/core/inject/system-prompt.d.ts +11 -0
- package/dist/core/inject/system-prompt.d.ts.map +1 -0
- package/dist/core/inject/system-prompt.js +22 -0
- package/dist/core/inject/system-prompt.js.map +1 -0
- package/dist/core/macro-runner.d.ts +36 -0
- package/dist/core/macro-runner.d.ts.map +1 -0
- package/dist/core/macro-runner.js +66 -0
- package/dist/core/macro-runner.js.map +1 -0
- package/dist/core/macros.d.ts +10 -0
- package/dist/core/macros.d.ts.map +1 -0
- package/dist/core/macros.js +59 -0
- package/dist/core/macros.js.map +1 -0
- package/dist/core/path-safety.d.ts +33 -0
- package/dist/core/path-safety.d.ts.map +1 -0
- package/dist/core/path-safety.js +63 -0
- package/dist/core/path-safety.js.map +1 -0
- package/dist/core/paths.d.ts +27 -0
- package/dist/core/paths.d.ts.map +1 -0
- package/dist/core/paths.js +43 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/port-detector.d.ts +69 -0
- package/dist/core/port-detector.d.ts.map +1 -0
- package/dist/core/port-detector.js +121 -0
- package/dist/core/port-detector.js.map +1 -0
- package/dist/core/session-manager.d.ts +275 -0
- package/dist/core/session-manager.d.ts.map +1 -0
- package/dist/core/session-manager.js +729 -0
- package/dist/core/session-manager.js.map +1 -0
- package/dist/core/task-manager.d.ts +138 -0
- package/dist/core/task-manager.d.ts.map +1 -0
- package/dist/core/task-manager.js +286 -0
- package/dist/core/task-manager.js.map +1 -0
- package/dist/core/task-stream.d.ts +32 -0
- package/dist/core/task-stream.d.ts.map +1 -0
- package/dist/core/task-stream.js +87 -0
- package/dist/core/task-stream.js.map +1 -0
- package/dist/core/workflow-registry.d.ts +36 -0
- package/dist/core/workflow-registry.d.ts.map +1 -0
- package/dist/core/workflow-registry.js +220 -0
- package/dist/core/workflow-registry.js.map +1 -0
- package/dist/core/workspace-context.d.ts +43 -0
- package/dist/core/workspace-context.d.ts.map +1 -0
- package/dist/core/workspace-context.js +108 -0
- package/dist/core/workspace-context.js.map +1 -0
- package/dist/core/workspace-watcher.d.ts +26 -0
- package/dist/core/workspace-watcher.d.ts.map +1 -0
- package/dist/core/workspace-watcher.js +174 -0
- package/dist/core/workspace-watcher.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/profiles/canvas-guidelines.d.ts +20 -0
- package/dist/profiles/canvas-guidelines.d.ts.map +1 -0
- package/dist/profiles/canvas-guidelines.js +48 -0
- package/dist/profiles/canvas-guidelines.js.map +1 -0
- package/dist/profiles/default.d.ts +10 -0
- package/dist/profiles/default.d.ts.map +1 -0
- package/dist/profiles/default.js +70 -0
- package/dist/profiles/default.js.map +1 -0
- package/dist/server/auth.d.ts +9 -0
- package/dist/server/auth.d.ts.map +1 -0
- package/dist/server/auth.js +28 -0
- package/dist/server/auth.js.map +1 -0
- package/dist/server/canvas-render.d.ts +18 -0
- package/dist/server/canvas-render.d.ts.map +1 -0
- package/dist/server/canvas-render.js +24 -0
- package/dist/server/canvas-render.js.map +1 -0
- package/dist/server/canvas.d.ts +12 -0
- package/dist/server/canvas.d.ts.map +1 -0
- package/dist/server/canvas.js +174 -0
- package/dist/server/canvas.js.map +1 -0
- package/dist/server/events-ws.d.ts +11 -0
- package/dist/server/events-ws.d.ts.map +1 -0
- package/dist/server/events-ws.js +24 -0
- package/dist/server/events-ws.js.map +1 -0
- package/dist/server/fs.d.ts +4 -0
- package/dist/server/fs.d.ts.map +1 -0
- package/dist/server/fs.js +88 -0
- package/dist/server/fs.js.map +1 -0
- package/dist/server/index.d.ts +83 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +0 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/ingest.d.ts +74 -0
- package/dist/server/ingest.d.ts.map +1 -0
- package/dist/server/ingest.js +74 -0
- package/dist/server/ingest.js.map +1 -0
- package/dist/server/macros.d.ts +32 -0
- package/dist/server/macros.d.ts.map +1 -0
- package/dist/server/macros.js +76 -0
- package/dist/server/macros.js.map +1 -0
- package/dist/server/rest.d.ts +75 -0
- package/dist/server/rest.d.ts.map +1 -0
- package/dist/server/rest.js +235 -0
- package/dist/server/rest.js.map +1 -0
- package/dist/server/static.d.ts +8 -0
- package/dist/server/static.d.ts.map +1 -0
- package/dist/server/static.js +36 -0
- package/dist/server/static.js.map +1 -0
- package/dist/server/terminal-ws.d.ts +9 -0
- package/dist/server/terminal-ws.d.ts.map +1 -0
- package/dist/server/terminal-ws.js +59 -0
- package/dist/server/terminal-ws.js.map +1 -0
- package/dist/server/ws-router.d.ts +16 -0
- package/dist/server/ws-router.d.ts.map +1 -0
- package/dist/server/ws-router.js +26 -0
- package/dist/server/ws-router.js.map +1 -0
- package/dist/shared/types.d.ts +485 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/types.js +80 -0
- package/dist/shared/types.js.map +1 -0
- package/dist/web/assets/index-B9R4TzH7.css +32 -0
- package/dist/web/assets/index-Dh97QAgq.js +192 -0
- package/dist/web/index.html +27 -0
- package/package.json +84 -7
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic workflow graph extraction (no LLM). Runs `@sapiom/agent-core`'s
|
|
3
|
+
* `check()` pipeline (in an isolated child process — see
|
|
4
|
+
* core/canvas-manifest-check.ts for why) against a workflow project on disk
|
|
5
|
+
* — the same bundle+manifest+graph-validation path `sapiom agents check`
|
|
6
|
+
* uses — and reshapes the resulting manifest into the small node/edge model
|
|
7
|
+
* `canvas-svg.ts` renders. Never throws: extraction failure (missing
|
|
8
|
+
* node_modules, a type error, an invalid graph) is returned as a typed
|
|
9
|
+
* `ExtractionFailure` so the caller can render an honest degraded panel
|
|
10
|
+
* instead of crashing or silently falling back to an LLM.
|
|
11
|
+
*/
|
|
12
|
+
import type { AgentManifest } from "@sapiom/agent";
|
|
13
|
+
import { type DetectedLaunch } from "./canvas-interconnections.js";
|
|
14
|
+
export type CanvasNodeKind = "entry" | "step" | "pause" | "terminal-success" | "terminal-warn" | "launched-workflow";
|
|
15
|
+
export type CanvasEdgeKind = "sequential" | "branching" | "cross" | "launch";
|
|
16
|
+
export interface CanvasNode {
|
|
17
|
+
id: string;
|
|
18
|
+
kind: CanvasNodeKind;
|
|
19
|
+
label: string;
|
|
20
|
+
sublabel?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface CanvasEdge {
|
|
23
|
+
from: string;
|
|
24
|
+
to: string;
|
|
25
|
+
kind: CanvasEdgeKind;
|
|
26
|
+
label?: string;
|
|
27
|
+
}
|
|
28
|
+
/** One workflow's extracted, render-ready graph. */
|
|
29
|
+
export interface CanvasGraph {
|
|
30
|
+
/** The manifest's own name — used both as a display title fallback and as
|
|
31
|
+
* the match key for cross-workflow interconnection detection. */
|
|
32
|
+
manifestName: string;
|
|
33
|
+
entry: string;
|
|
34
|
+
nodes: CanvasNode[];
|
|
35
|
+
edges: CanvasEdge[];
|
|
36
|
+
/** Non-fatal graph smells from `assertValidGraph` (unreachable steps, no
|
|
37
|
+
* path to a terminal) — surfaced as a badge, not an error. */
|
|
38
|
+
warnings: string[];
|
|
39
|
+
}
|
|
40
|
+
export interface ExtractionSuccess {
|
|
41
|
+
ok: true;
|
|
42
|
+
graph: CanvasGraph;
|
|
43
|
+
}
|
|
44
|
+
export interface ExtractionFailure {
|
|
45
|
+
ok: false;
|
|
46
|
+
/** Human-readable, terminal-safe reason — shown verbatim in the degraded panel. */
|
|
47
|
+
reason: string;
|
|
48
|
+
}
|
|
49
|
+
export type ExtractionResult = ExtractionSuccess | ExtractionFailure;
|
|
50
|
+
/** Reshapes a validated `AgentManifest` into the render-ready graph model. */
|
|
51
|
+
export declare function graphFromManifest(manifest: AgentManifest, warnings: string[]): CanvasGraph;
|
|
52
|
+
/**
|
|
53
|
+
* Merges heuristically detected cross-workflow launches into the workflow's
|
|
54
|
+
* own graph: one dashed `launched-workflow` node per distinct slug, with a
|
|
55
|
+
* `launch`-kind edge from the step the call was attributed to (falling back
|
|
56
|
+
* to the entry step — the launch definitely happens somewhere downstream of
|
|
57
|
+
* it). Self-launches (a workflow re-launching itself) are skipped: the graph
|
|
58
|
+
* already shows those steps. Pure — returns a new graph.
|
|
59
|
+
*/
|
|
60
|
+
export declare function mergeLaunchesIntoGraph(graph: CanvasGraph, launches: readonly DetectedLaunch[]): CanvasGraph;
|
|
61
|
+
/**
|
|
62
|
+
* Extracts a workflow's step graph from its project directory, with detected
|
|
63
|
+
* cross-workflow launches merged in as dashed nodes. Never throws: any
|
|
64
|
+
* failure (no node_modules, a bundle/type error, an invalid graph, a
|
|
65
|
+
* check-process crash or timeout) comes back as `{ ok: false, reason }` for
|
|
66
|
+
* the caller to render as a degraded panel — this is the only place
|
|
67
|
+
* extraction failure is allowed to happen silently instead of crashing the
|
|
68
|
+
* render.
|
|
69
|
+
*/
|
|
70
|
+
export declare function extractWorkflowGraph(sourceDir: string): Promise<ExtractionResult>;
|
|
71
|
+
//# sourceMappingURL=canvas-graph.d.ts.map
|
|
@@ -0,0 +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,EAA0B,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAE3F,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;CACnB;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,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;AA0DrE,8EAA8E;AAC9E,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,WAAW,CAS1F;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,cAAc,EAAE,GAAG,WAAW,CAqB3G;AAED;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAMvF"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { runManifestCheck } from "./canvas-manifest-check.js";
|
|
2
|
+
import { detectWorkflowLaunches } from "./canvas-interconnections.js";
|
|
3
|
+
/**
|
|
4
|
+
* Classifies a step for node styling. Priority: the entry step always reads
|
|
5
|
+
* as "entry" (the diagram's obvious starting point) even if it also happens
|
|
6
|
+
* to declare a pause/terminal transition; next, a declared `pause` always
|
|
7
|
+
* shows the dashed border regardless of what else the step declares; a step
|
|
8
|
+
* that can `continue` somewhere is a mid-flow "step" even if it can also
|
|
9
|
+
* terminate/fail from a different runtime branch; only a step with NO
|
|
10
|
+
* `continue` targets left resolves to a terminal color, warn (fail) over
|
|
11
|
+
* success (terminate) is not possible to prioritize both apply — success
|
|
12
|
+
* wins as the more common single-outcome shape.
|
|
13
|
+
*
|
|
14
|
+
* Every branch also carries a deterministic `sublabel` — a one-line role
|
|
15
|
+
* derived purely from the step's declared transitions (entry / step / pause ·
|
|
16
|
+
* <signal> / terminal · success / terminal · needs attention) — so each node
|
|
17
|
+
* renders as a titled card even before any AI enrichment. `renderGraphSvg`
|
|
18
|
+
* prefers an enrichment-supplied sublabel over this default when present.
|
|
19
|
+
*/
|
|
20
|
+
function classifyNode(name, entry, step) {
|
|
21
|
+
const continueTargets = step.transitions.filter((t) => t.kind === "continue");
|
|
22
|
+
const pause = step.transitions.find((t) => t.kind === "pause");
|
|
23
|
+
const hasTerminate = step.transitions.some((t) => t.kind === "terminate");
|
|
24
|
+
const hasFail = step.transitions.some((t) => t.kind === "fail");
|
|
25
|
+
if (name === entry)
|
|
26
|
+
return { kind: "entry", sublabel: "entry" };
|
|
27
|
+
if (pause)
|
|
28
|
+
return { kind: "pause", sublabel: `pause · ${pause.signal}` };
|
|
29
|
+
if (continueTargets.length === 0 && hasFail && !hasTerminate)
|
|
30
|
+
return { kind: "terminal-warn", sublabel: "terminal · needs attention" };
|
|
31
|
+
if (continueTargets.length === 0 && hasTerminate)
|
|
32
|
+
return { kind: "terminal-success", sublabel: "terminal · success" };
|
|
33
|
+
if (continueTargets.length > 0 && (hasTerminate || hasFail)) {
|
|
34
|
+
return { kind: "step", sublabel: hasFail ? "step · can also fail" : "step · can also terminate" };
|
|
35
|
+
}
|
|
36
|
+
return { kind: "step", sublabel: "step" };
|
|
37
|
+
}
|
|
38
|
+
/** Builds every edge a step declares — one per `continue` target plus its
|
|
39
|
+
* `pause` edge, if any. Node kind (above) only decides border styling; every
|
|
40
|
+
* declared transition with a target still gets its own edge. */
|
|
41
|
+
function edgesForStep(name, step) {
|
|
42
|
+
const continueTargets = step.transitions.filter((t) => t.kind === "continue");
|
|
43
|
+
const edges = continueTargets.map((t) => ({
|
|
44
|
+
from: name,
|
|
45
|
+
to: t.target,
|
|
46
|
+
kind: continueTargets.length > 1 ? "branching" : "sequential",
|
|
47
|
+
}));
|
|
48
|
+
const pause = step.transitions.find((t) => t.kind === "pause");
|
|
49
|
+
if (pause) {
|
|
50
|
+
edges.push({ from: name, to: pause.resumeStep, kind: "cross", label: pause.signal });
|
|
51
|
+
}
|
|
52
|
+
return edges;
|
|
53
|
+
}
|
|
54
|
+
/** Reshapes a validated `AgentManifest` into the render-ready graph model. */
|
|
55
|
+
export function graphFromManifest(manifest, warnings) {
|
|
56
|
+
const nodes = Object.entries(manifest.steps).map(([name, step]) => {
|
|
57
|
+
const { kind, sublabel } = classifyNode(name, manifest.entry, step);
|
|
58
|
+
return { id: name, kind, label: name, sublabel };
|
|
59
|
+
});
|
|
60
|
+
const edges = Object.entries(manifest.steps).flatMap(([name, step]) => edgesForStep(name, step));
|
|
61
|
+
return { manifestName: manifest.name, entry: manifest.entry, nodes, edges, warnings };
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Merges heuristically detected cross-workflow launches into the workflow's
|
|
65
|
+
* own graph: one dashed `launched-workflow` node per distinct slug, with a
|
|
66
|
+
* `launch`-kind edge from the step the call was attributed to (falling back
|
|
67
|
+
* to the entry step — the launch definitely happens somewhere downstream of
|
|
68
|
+
* it). Self-launches (a workflow re-launching itself) are skipped: the graph
|
|
69
|
+
* already shows those steps. Pure — returns a new graph.
|
|
70
|
+
*/
|
|
71
|
+
export function mergeLaunchesIntoGraph(graph, launches) {
|
|
72
|
+
const stepIds = new Set(graph.nodes.map((n) => n.id));
|
|
73
|
+
const nodes = [...graph.nodes];
|
|
74
|
+
const edges = [...graph.edges];
|
|
75
|
+
const seenEdges = new Set();
|
|
76
|
+
for (const launch of launches) {
|
|
77
|
+
if (launch.slug === graph.manifestName)
|
|
78
|
+
continue;
|
|
79
|
+
// Prefixed id so a launched workflow can never collide with a step that
|
|
80
|
+
// happens to share its name.
|
|
81
|
+
const nodeId = `launch:${launch.slug}`;
|
|
82
|
+
if (!nodes.some((n) => n.id === nodeId)) {
|
|
83
|
+
nodes.push({ id: nodeId, kind: "launched-workflow", label: launch.slug, sublabel: "launched workflow" });
|
|
84
|
+
}
|
|
85
|
+
const from = launch.fromStepId && stepIds.has(launch.fromStepId) ? launch.fromStepId : graph.entry;
|
|
86
|
+
const edgeKey = `${from}->${nodeId}`;
|
|
87
|
+
if (seenEdges.has(edgeKey))
|
|
88
|
+
continue;
|
|
89
|
+
seenEdges.add(edgeKey);
|
|
90
|
+
edges.push({ from, to: nodeId, kind: "launch", label: "launch()" });
|
|
91
|
+
}
|
|
92
|
+
return { ...graph, nodes, edges };
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Extracts a workflow's step graph from its project directory, with detected
|
|
96
|
+
* cross-workflow launches merged in as dashed nodes. Never throws: any
|
|
97
|
+
* failure (no node_modules, a bundle/type error, an invalid graph, a
|
|
98
|
+
* check-process crash or timeout) comes back as `{ ok: false, reason }` for
|
|
99
|
+
* the caller to render as a degraded panel — this is the only place
|
|
100
|
+
* extraction failure is allowed to happen silently instead of crashing the
|
|
101
|
+
* render.
|
|
102
|
+
*/
|
|
103
|
+
export async function extractWorkflowGraph(sourceDir) {
|
|
104
|
+
const result = await runManifestCheck(sourceDir);
|
|
105
|
+
if (!result.ok)
|
|
106
|
+
return { ok: false, reason: result.reason };
|
|
107
|
+
const graph = graphFromManifest(result.manifest, result.warnings);
|
|
108
|
+
const launches = await detectWorkflowLaunches(sourceDir, new Set(graph.nodes.map((n) => n.id)));
|
|
109
|
+
return { ok: true, graph: mergeLaunchesIntoGraph(graph, launches) };
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=canvas-graph.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canvas-graph.js","sourceRoot":"","sources":["../../src/core/canvas-graph.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Classifies a `.sapiom/canvas/index.html` on disk as machine-generated
|
|
3
|
+
* (a leftover the harness itself wrote) vs. an agent-authored custom canvas,
|
|
4
|
+
* so the server can:
|
|
5
|
+
*
|
|
6
|
+
* (a) refuse to serve a stale machine-generated file as the UNBOUND canvas
|
|
7
|
+
* fallback — showing the clean empty state instead of stale content; and
|
|
8
|
+
* (b) delete a legacy deterministic-overview file on session create so an
|
|
9
|
+
* old one can't keep resurfacing (see `ensureCanvasTemplate`).
|
|
10
|
+
*
|
|
11
|
+
* Two machine-generated shapes exist in the wild:
|
|
12
|
+
*
|
|
13
|
+
* - The seeded pristine template (`canvas-template.ts`'s `TEMPLATE_HTML`) —
|
|
14
|
+
* benign (an empty state itself) but not a custom canvas either, so it
|
|
15
|
+
* shouldn't be served as one.
|
|
16
|
+
* - A LEGACY deterministic overview / single render. Before the
|
|
17
|
+
* per-workflow render split, the deterministic pipeline wrote its output
|
|
18
|
+
* straight to `index.html`; on a project first opened by one of those old
|
|
19
|
+
* servers, that file is a stacked all-workflows page with baked-in
|
|
20
|
+
* "render failed" panels that have nothing to do with the current session
|
|
21
|
+
* — the actual bug this guards against. The writer that produced it was
|
|
22
|
+
* removed when renders moved to `renders/<slug>.html`, so its signature is
|
|
23
|
+
* matched by literal markup here rather than an imported constant.
|
|
24
|
+
*
|
|
25
|
+
* Detection is by signature substrings that only this package's own writers
|
|
26
|
+
* emit and that an agent authoring its own canvas would not reproduce.
|
|
27
|
+
*/
|
|
28
|
+
/** True when `html` is a legacy deterministic overview/single render that was
|
|
29
|
+
* written directly to `index.html` by a pre-split server. This is the file
|
|
30
|
+
* worth deleting on session create — the harmful stale "render failed" wall. */
|
|
31
|
+
export declare function isLegacyDeterministicCanvas(html: string): boolean;
|
|
32
|
+
/** True when `html` is the seeded pristine template, still un-customized. */
|
|
33
|
+
export declare function isSeededCanvasTemplate(html: string): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* True when `html` is machine-generated (the seeded template OR a legacy
|
|
36
|
+
* deterministic overview) rather than an agent-authored custom canvas. Such a
|
|
37
|
+
* file must not be served as the unbound canvas fallback — the clean empty
|
|
38
|
+
* state is served instead.
|
|
39
|
+
*/
|
|
40
|
+
export declare function isMachineGeneratedCanvas(html: string): boolean;
|
|
41
|
+
//# sourceMappingURL=canvas-index-classify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canvas-index-classify.d.ts","sourceRoot":"","sources":["../../src/core/canvas-index-classify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAoBH;;iFAEiF;AACjF,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjE;AAED,6EAA6E;AAC7E,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE9D"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Classifies a `.sapiom/canvas/index.html` on disk as machine-generated
|
|
3
|
+
* (a leftover the harness itself wrote) vs. an agent-authored custom canvas,
|
|
4
|
+
* so the server can:
|
|
5
|
+
*
|
|
6
|
+
* (a) refuse to serve a stale machine-generated file as the UNBOUND canvas
|
|
7
|
+
* fallback — showing the clean empty state instead of stale content; and
|
|
8
|
+
* (b) delete a legacy deterministic-overview file on session create so an
|
|
9
|
+
* old one can't keep resurfacing (see `ensureCanvasTemplate`).
|
|
10
|
+
*
|
|
11
|
+
* Two machine-generated shapes exist in the wild:
|
|
12
|
+
*
|
|
13
|
+
* - The seeded pristine template (`canvas-template.ts`'s `TEMPLATE_HTML`) —
|
|
14
|
+
* benign (an empty state itself) but not a custom canvas either, so it
|
|
15
|
+
* shouldn't be served as one.
|
|
16
|
+
* - A LEGACY deterministic overview / single render. Before the
|
|
17
|
+
* per-workflow render split, the deterministic pipeline wrote its output
|
|
18
|
+
* straight to `index.html`; on a project first opened by one of those old
|
|
19
|
+
* servers, that file is a stacked all-workflows page with baked-in
|
|
20
|
+
* "render failed" panels that have nothing to do with the current session
|
|
21
|
+
* — the actual bug this guards against. The writer that produced it was
|
|
22
|
+
* removed when renders moved to `renders/<slug>.html`, so its signature is
|
|
23
|
+
* matched by literal markup here rather than an imported constant.
|
|
24
|
+
*
|
|
25
|
+
* Detection is by signature substrings that only this package's own writers
|
|
26
|
+
* emit and that an agent authoring its own canvas would not reproduce.
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* The footer note the deterministic render pipeline emits via
|
|
30
|
+
* `assembleCanvasBody` — `<p class="canvas-note">Static preview — …</p>`.
|
|
31
|
+
* Stable across both the legacy overview and single-render variants (the exact
|
|
32
|
+
* trailing text differed between versions; the "Static preview" prefix did
|
|
33
|
+
* not). An agent-authored canvas writes its own copy, never this.
|
|
34
|
+
*/
|
|
35
|
+
const DETERMINISTIC_NOTE_SIGNATURE = 'class="canvas-note">Static preview';
|
|
36
|
+
/**
|
|
37
|
+
* The inert patterns block the seeded template ships with, together with its
|
|
38
|
+
* untouched empty-state note. Both present means the seed is still
|
|
39
|
+
* un-customized — an agent is instructed to delete both once it authors real
|
|
40
|
+
* content, so their joint presence never matches a finished custom canvas.
|
|
41
|
+
*/
|
|
42
|
+
const TEMPLATE_PATTERNS_SIGNATURE = 'id="canvas-patterns"';
|
|
43
|
+
const TEMPLATE_EMPTY_NOTE_SIGNATURE = "Nothing visualized yet";
|
|
44
|
+
/** True when `html` is a legacy deterministic overview/single render that was
|
|
45
|
+
* written directly to `index.html` by a pre-split server. This is the file
|
|
46
|
+
* worth deleting on session create — the harmful stale "render failed" wall. */
|
|
47
|
+
export function isLegacyDeterministicCanvas(html) {
|
|
48
|
+
return html.includes(DETERMINISTIC_NOTE_SIGNATURE);
|
|
49
|
+
}
|
|
50
|
+
/** True when `html` is the seeded pristine template, still un-customized. */
|
|
51
|
+
export function isSeededCanvasTemplate(html) {
|
|
52
|
+
return html.includes(TEMPLATE_PATTERNS_SIGNATURE) && html.includes(TEMPLATE_EMPTY_NOTE_SIGNATURE);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* True when `html` is machine-generated (the seeded template OR a legacy
|
|
56
|
+
* deterministic overview) rather than an agent-authored custom canvas. Such a
|
|
57
|
+
* file must not be served as the unbound canvas fallback — the clean empty
|
|
58
|
+
* state is served instead.
|
|
59
|
+
*/
|
|
60
|
+
export function isMachineGeneratedCanvas(html) {
|
|
61
|
+
return isLegacyDeterministicCanvas(html) || isSeededCanvasTemplate(html);
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=canvas-index-classify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canvas-index-classify.js","sourceRoot":"","sources":["../../src/core/canvas-index-classify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH;;;;;;GAMG;AACH,MAAM,4BAA4B,GAAG,oCAAoC,CAAC;AAE1E;;;;;GAKG;AACH,MAAM,2BAA2B,GAAG,sBAAsB,CAAC;AAC3D,MAAM,6BAA6B,GAAG,wBAAwB,CAAC;AAE/D;;iFAEiF;AACjF,MAAM,UAAU,2BAA2B,CAAC,IAAY;IACtD,OAAO,IAAI,CAAC,QAAQ,CAAC,4BAA4B,CAAC,CAAC;AACrD,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,sBAAsB,CAAC,IAAY;IACjD,OAAO,IAAI,CAAC,QAAQ,CAAC,2BAA2B,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,6BAA6B,CAAC,CAAC;AACpG,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CAAC,IAAY;IACnD,OAAO,2BAA2B,CAAC,IAAI,CAAC,IAAI,sBAAsB,CAAC,IAAI,CAAC,CAAC;AAC3E,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lists the workflow's own `.ts`/`.tsx` sources (skipping node_modules and
|
|
3
|
+
* friends), bounded to MAX_FILES_PER_WORKFLOW. Shared with the extraction
|
|
4
|
+
* cache's source fingerprint (core/canvas-cache.ts) so "the files this grep
|
|
5
|
+
* reads" and "the files whose mtimes invalidate the cache" can't drift.
|
|
6
|
+
*/
|
|
7
|
+
export declare function listSourceFiles(root: string): Promise<string[]>;
|
|
8
|
+
export interface DetectedLaunch {
|
|
9
|
+
/** The `definition` slug the launch call referenced. */
|
|
10
|
+
slug: string;
|
|
11
|
+
/** The step (by declared name) the call was attributed to — the nearest
|
|
12
|
+
* preceding `name: "<known step>"` declaration in the same file — or null
|
|
13
|
+
* when no known step precedes it (e.g. a launch in a shared helper). */
|
|
14
|
+
fromStepId: string | null;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Every `*.launch({ definition: "..." })` call in `root`'s sources, each
|
|
18
|
+
* best-effort attributed to the step whose `defineStep` block it sits in
|
|
19
|
+
* (`knownStepIds` = the workflow's real step names, so an unrelated `name:`
|
|
20
|
+
* property can never be mistaken for a step). Never throws: unreadable
|
|
21
|
+
* files/directories simply contribute no launches.
|
|
22
|
+
*/
|
|
23
|
+
export declare function detectWorkflowLaunches(root: string, knownStepIds: ReadonlySet<string>): Promise<DetectedLaunch[]>;
|
|
24
|
+
//# sourceMappingURL=canvas-interconnections.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canvas-interconnections.d.ts","sourceRoot":"","sources":["../../src/core/canvas-interconnections.ts"],"names":[],"mappings":"AAkCA;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAsBrE;AAED,MAAM,WAAW,cAAc;IAC7B,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAC;IACb;;6EAEyE;IACzE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,GAChC,OAAO,CAAC,cAAc,EAAE,CAAC,CAuB3B"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Heuristic cross-workflow launch detection: greps a workflow project's
|
|
3
|
+
* TypeScript sources for `orchestrations.launch({ definition: "<slug>" })`
|
|
4
|
+
* (the pre-rename SDK's capability) and `agents.launch({ definition: ... })`
|
|
5
|
+
* (the current SDK, e.g. `ctx.sapiom.agents.launch`) calls, and best-effort
|
|
6
|
+
* attributes each call to the step whose `defineStep({ name: ... })` block it
|
|
7
|
+
* sits in. The result is merged into the workflow's own rendered graph as
|
|
8
|
+
* dashed "launched workflow" nodes (see core/canvas-graph.ts).
|
|
9
|
+
*
|
|
10
|
+
* This is deliberately a grep, not a type-aware analysis — a step can compute
|
|
11
|
+
* its `definition` dynamically, in which case it's simply not detected; false
|
|
12
|
+
* negatives are fine here, the launch nodes are a bonus, not a source of
|
|
13
|
+
* truth.
|
|
14
|
+
*/
|
|
15
|
+
import * as fs from "node:fs/promises";
|
|
16
|
+
import * as path from "node:path";
|
|
17
|
+
const SKIP_DIR_NAMES = new Set(["node_modules", ".git", "dist", "build", ".sapiom"]);
|
|
18
|
+
const SOURCE_EXTENSIONS = new Set([".ts", ".tsx"]);
|
|
19
|
+
const MAX_FILES_PER_WORKFLOW = 200;
|
|
20
|
+
const MAX_FILE_BYTES = 512 * 1024;
|
|
21
|
+
// Matches `orchestrations.launch({ ...definition: "slug"... })` (old SDK) and
|
|
22
|
+
// `agents.launch({ ...definition: "slug"... })` (current SDK), tolerating
|
|
23
|
+
// other fields before `definition` in the object literal (bounded lookahead
|
|
24
|
+
// so an unrelated huge object literal can't make this pathological).
|
|
25
|
+
const LAUNCH_CALL_PATTERN = /(?:orchestrations|agents)\s*\.\s*launch\s*\(\s*\{[\s\S]{0,400}?definition\s*:\s*(['"`])([^'"`]+)\1/g;
|
|
26
|
+
// A `name: "..."` property declaration — the step-name key `defineStep`
|
|
27
|
+
// blocks always open with. The lookbehind rejects longer identifiers ending
|
|
28
|
+
// in "name" (fromName, vendorName) without consuming the preceding char.
|
|
29
|
+
const STEP_NAME_PATTERN = /(?<![\w$.])name\s*:\s*(['"`])([^'"`]+)\1/g;
|
|
30
|
+
/**
|
|
31
|
+
* Lists the workflow's own `.ts`/`.tsx` sources (skipping node_modules and
|
|
32
|
+
* friends), bounded to MAX_FILES_PER_WORKFLOW. Shared with the extraction
|
|
33
|
+
* cache's source fingerprint (core/canvas-cache.ts) so "the files this grep
|
|
34
|
+
* reads" and "the files whose mtimes invalidate the cache" can't drift.
|
|
35
|
+
*/
|
|
36
|
+
export async function listSourceFiles(root) {
|
|
37
|
+
const files = [];
|
|
38
|
+
async function walk(dir) {
|
|
39
|
+
if (files.length >= MAX_FILES_PER_WORKFLOW)
|
|
40
|
+
return;
|
|
41
|
+
let entries;
|
|
42
|
+
try {
|
|
43
|
+
entries = await fs.readdir(dir, { withFileTypes: true });
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
for (const entry of entries) {
|
|
49
|
+
if (files.length >= MAX_FILES_PER_WORKFLOW)
|
|
50
|
+
return;
|
|
51
|
+
if (entry.isDirectory()) {
|
|
52
|
+
if (SKIP_DIR_NAMES.has(entry.name))
|
|
53
|
+
continue;
|
|
54
|
+
await walk(path.join(dir, entry.name));
|
|
55
|
+
}
|
|
56
|
+
else if (SOURCE_EXTENSIONS.has(path.extname(entry.name))) {
|
|
57
|
+
files.push(path.join(dir, entry.name));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
await walk(root);
|
|
62
|
+
return files;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Every `*.launch({ definition: "..." })` call in `root`'s sources, each
|
|
66
|
+
* best-effort attributed to the step whose `defineStep` block it sits in
|
|
67
|
+
* (`knownStepIds` = the workflow's real step names, so an unrelated `name:`
|
|
68
|
+
* property can never be mistaken for a step). Never throws: unreadable
|
|
69
|
+
* files/directories simply contribute no launches.
|
|
70
|
+
*/
|
|
71
|
+
export async function detectWorkflowLaunches(root, knownStepIds) {
|
|
72
|
+
const launches = [];
|
|
73
|
+
for (const file of await listSourceFiles(root)) {
|
|
74
|
+
let content;
|
|
75
|
+
try {
|
|
76
|
+
const stat = await fs.stat(file);
|
|
77
|
+
if (stat.size > MAX_FILE_BYTES)
|
|
78
|
+
continue;
|
|
79
|
+
content = await fs.readFile(file, "utf8");
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const stepDeclarations = [];
|
|
85
|
+
for (const match of content.matchAll(STEP_NAME_PATTERN)) {
|
|
86
|
+
if (knownStepIds.has(match[2]))
|
|
87
|
+
stepDeclarations.push({ index: match.index, stepId: match[2] });
|
|
88
|
+
}
|
|
89
|
+
for (const match of content.matchAll(LAUNCH_CALL_PATTERN)) {
|
|
90
|
+
const preceding = stepDeclarations.filter((d) => d.index < match.index).at(-1);
|
|
91
|
+
launches.push({ slug: match[2], fromStepId: preceding?.stepId ?? null });
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return launches;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=canvas-interconnections.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canvas-interconnections.js","sourceRoot":"","sources":["../../src/core/canvas-interconnections.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface ManifestCheckSuccess {
|
|
2
|
+
ok: true;
|
|
3
|
+
manifest: unknown;
|
|
4
|
+
warnings: string[];
|
|
5
|
+
}
|
|
6
|
+
export interface ManifestCheckFailure {
|
|
7
|
+
ok: false;
|
|
8
|
+
reason: string;
|
|
9
|
+
}
|
|
10
|
+
export type ManifestCheckResult = ManifestCheckSuccess | ManifestCheckFailure;
|
|
11
|
+
/** Runs `check({ sourceDir })` in a child `node` process; never throws or
|
|
12
|
+
* rejects — a crash, timeout, or unparsable output all come back as a
|
|
13
|
+
* `ManifestCheckFailure` with a human-readable reason. */
|
|
14
|
+
export declare function runManifestCheck(sourceDir: string): Promise<ManifestCheckResult>;
|
|
15
|
+
//# sourceMappingURL=canvas-manifest-check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canvas-manifest-check.d.ts","sourceRoot":"","sources":["../../src/core/canvas-manifest-check.ts"],"names":[],"mappings":"AA+DA,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,IAAI,CAAC;IACT,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,mBAAmB,GAAG,oBAAoB,GAAG,oBAAoB,CAAC;AAE9E;;2DAE2D;AAC3D,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CA8BhF"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runs `@sapiom/agent-core`'s `check()` in an isolated child process, rather
|
|
3
|
+
* than importing it in-process. Two independent reasons:
|
|
4
|
+
*
|
|
5
|
+
* 1. `check()` dynamically `import()`s an esbuild-bundled copy of whatever
|
|
6
|
+
* TypeScript the target workflow's `index.ts` contains — a workflow
|
|
7
|
+
* project the harness doesn't control. Running that inside the harness's
|
|
8
|
+
* own long-lived server process would let a stray top-level side effect,
|
|
9
|
+
* infinite loop, or crash in someone else's workflow code take the whole
|
|
10
|
+
* harness down. A child process bounds the blast radius to one failed
|
|
11
|
+
* render.
|
|
12
|
+
* 2. It sidesteps a real Vite/Vitest limitation: `check()`'s own dynamic
|
|
13
|
+
* `import(\`file://${tmpPath}\`)` gets intercepted by Vite's SSR
|
|
14
|
+
* dynamic-import-vars transform when anything imports `check` directly
|
|
15
|
+
* into a Vitest-run module graph, and mishandles the tmpdir's `file://`
|
|
16
|
+
* URL on darwin ("File URL host must be 'localhost' or empty"),
|
|
17
|
+
* corrupting every extraction. A plain child `node` process never goes
|
|
18
|
+
* through that transform.
|
|
19
|
+
*
|
|
20
|
+
* The child process is a short inline ESM script (no separate file to keep
|
|
21
|
+
* in sync across dev/build) run with `cwd` set to this package's own root,
|
|
22
|
+
* so `import { check } from "@sapiom/agent-core"` resolves against the
|
|
23
|
+
* harness's real dependency — exactly like the CLI's own `sapiom agents
|
|
24
|
+
* check` already runs it, just invoked programmatically instead of as a
|
|
25
|
+
* subcommand.
|
|
26
|
+
*/
|
|
27
|
+
import { execFile } from "node:child_process";
|
|
28
|
+
import { dirname, join } from "node:path";
|
|
29
|
+
import { fileURLToPath } from "node:url";
|
|
30
|
+
/** Hard ceiling, not the performance target — bundling a small workflow is
|
|
31
|
+
* typically well under a second; this only guards against a pathological
|
|
32
|
+
* project (a huge dependency tree, a hanging top-level side effect) from
|
|
33
|
+
* blocking a render indefinitely. */
|
|
34
|
+
const CHECK_TIMEOUT_MS = 15000;
|
|
35
|
+
const MAX_BUFFER_BYTES = 10 * 1024 * 1024;
|
|
36
|
+
// This module lives at either src/core/ (tsx dev, vitest) or dist/core/
|
|
37
|
+
// (built) — both two directories below the package root.
|
|
38
|
+
function packageRoot() {
|
|
39
|
+
return join(dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
40
|
+
}
|
|
41
|
+
const RUNNER_SOURCE = `
|
|
42
|
+
import { check, AgentOperationError } from "@sapiom/agent-core";
|
|
43
|
+
|
|
44
|
+
function reasonFor(err) {
|
|
45
|
+
if (err instanceof AgentOperationError) return err.hint ? \`\${err.message} \${err.hint}\` : err.message;
|
|
46
|
+
return err instanceof Error ? err.message : String(err);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const sourceDir = process.env.SAPIOM_CANVAS_CHECK_SOURCE_DIR;
|
|
50
|
+
try {
|
|
51
|
+
// typecheck: false — a diagram only needs the manifest/graph, and the
|
|
52
|
+
// project's own tsc --noEmit is the dominant multi-second per-render cost;
|
|
53
|
+
// esbuild still surfaces real breakage (bad imports, syntax errors).
|
|
54
|
+
const result = await check({ sourceDir, typecheck: false });
|
|
55
|
+
process.stdout.write(JSON.stringify({ ok: true, manifest: result.manifest, warnings: result.warnings }));
|
|
56
|
+
} catch (err) {
|
|
57
|
+
process.stdout.write(JSON.stringify({ ok: false, reason: reasonFor(err) }));
|
|
58
|
+
}
|
|
59
|
+
`;
|
|
60
|
+
/** Runs `check({ sourceDir })` in a child `node` process; never throws or
|
|
61
|
+
* rejects — a crash, timeout, or unparsable output all come back as a
|
|
62
|
+
* `ManifestCheckFailure` with a human-readable reason. */
|
|
63
|
+
export function runManifestCheck(sourceDir) {
|
|
64
|
+
return new Promise((resolve) => {
|
|
65
|
+
execFile(process.execPath, ["--input-type=module", "-e", RUNNER_SOURCE], {
|
|
66
|
+
cwd: packageRoot(),
|
|
67
|
+
env: { ...process.env, SAPIOM_CANVAS_CHECK_SOURCE_DIR: sourceDir },
|
|
68
|
+
timeout: CHECK_TIMEOUT_MS,
|
|
69
|
+
maxBuffer: MAX_BUFFER_BYTES,
|
|
70
|
+
}, (err, stdout, stderr) => {
|
|
71
|
+
if (err) {
|
|
72
|
+
const timedOut = err.killed && err.signal === "SIGTERM";
|
|
73
|
+
resolve({
|
|
74
|
+
ok: false,
|
|
75
|
+
reason: timedOut
|
|
76
|
+
? `Extraction timed out after ${CHECK_TIMEOUT_MS / 1000}s.`
|
|
77
|
+
: (stderr.trim() || err.message),
|
|
78
|
+
});
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
resolve(JSON.parse(stdout));
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
resolve({ ok: false, reason: `Unexpected output from the check process: ${stdout.slice(0, 500)}` });
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=canvas-manifest-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canvas-manifest-check.js","sourceRoot":"","sources":["../../src/core/canvas-manifest-check.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC;;;sCAGsC;AACtC,MAAM,gBAAgB,GAAG,KAAM,CAAC;AAChC,MAAM,gBAAgB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAE1C,wEAAwE;AACxE,yDAAyD;AACzD,SAAS,WAAW;IAClB,OAAO,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AACnE,CAAC;AAED,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;CAkBrB,CAAC;AAeF;;2DAE2D;AAC3D,MAAM,UAAU,gBAAgB,CAAC,SAAiB;IAChD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,QAAQ,CACN,OAAO,CAAC,QAAQ,EAChB,CAAC,qBAAqB,EAAE,IAAI,EAAE,aAAa,CAAC,EAC5C;YACE,GAAG,EAAE,WAAW,EAAE;YAClB,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,8BAA8B,EAAE,SAAS,EAAE;YAClE,OAAO,EAAE,gBAAgB;YACzB,SAAS,EAAE,gBAAgB;SAC5B,EACD,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;YACtB,IAAI,GAAG,EAAE,CAAC;gBACR,MAAM,QAAQ,GAAI,GAAoD,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC;gBAC1G,OAAO,CAAC;oBACN,EAAE,EAAE,KAAK;oBACT,MAAM,EAAE,QAAQ;wBACd,CAAC,CAAC,8BAA8B,gBAAgB,GAAG,IAAI,IAAI;wBAC3D,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,CAAC,OAAO,CAAC;iBACnC,CAAC,CAAC;gBACH,OAAO;YACT,CAAC;YACD,IAAI,CAAC;gBACH,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAwB,CAAC,CAAC;YACrD,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,6CAA6C,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;YACtG,CAAC;QACH,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
export interface RenderableSession {
|
|
2
|
+
cwd: string;
|
|
3
|
+
boundWorkflowPath: string | null;
|
|
4
|
+
}
|
|
5
|
+
export interface RenderableWorkflow {
|
|
6
|
+
path: string;
|
|
7
|
+
name: string;
|
|
8
|
+
definitionId: number | null;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Stable, filesystem-safe render-file name for a workflow: its directory
|
|
12
|
+
* basename (readable in `ls`) plus a short path hash (two same-named
|
|
13
|
+
* workflows at different paths can never collide). Shared by the writer here
|
|
14
|
+
* and the server's request-time resolution — must stay deterministic.
|
|
15
|
+
*/
|
|
16
|
+
export declare function slugForWorkflowPath(workflowPath: string): string;
|
|
17
|
+
/** Absolute path of `workflowPath`'s render file under `cwd`'s canvas dir. */
|
|
18
|
+
export declare function renderFileFor(cwd: string, workflowPath: string): string;
|
|
19
|
+
/** Absolute path of `workflowPath`'s enrichment cache file under `cwd`'s
|
|
20
|
+
* canvas dir — same slug scheme as the render file. */
|
|
21
|
+
export declare function enrichmentCacheFileFor(cwd: string, workflowPath: string): string;
|
|
22
|
+
export interface CanvasRenderOutcome {
|
|
23
|
+
/** "single": a bound workflow was rendered to its render file. "empty":
|
|
24
|
+
* the session is unbound (or bound to an unknown path) — nothing was
|
|
25
|
+
* extracted or written; the server serves the empty state on its own. */
|
|
26
|
+
mode: "single" | "empty";
|
|
27
|
+
workflowPath?: string;
|
|
28
|
+
/** Absolute path of the render file written (mode "single" only). */
|
|
29
|
+
renderPath?: string;
|
|
30
|
+
/** Display names of workflows whose graph couldn't be extracted (still rendered as a degraded panel). */
|
|
31
|
+
extractionFailed: string[];
|
|
32
|
+
/** True when the graph came from the extraction cache — no child process ran. */
|
|
33
|
+
cachedExtraction?: boolean;
|
|
34
|
+
/** True when a cached enrichment was merged into the render (mode "single",
|
|
35
|
+
* successful extraction only). */
|
|
36
|
+
enrichmentApplied?: boolean;
|
|
37
|
+
/** True when the merged enrichment's fingerprint no longer matches the
|
|
38
|
+
* current sources — rendered with the "stale" chip. */
|
|
39
|
+
enrichmentStale?: boolean;
|
|
40
|
+
/** Set only when writing the file itself failed (e.g. an unwritable cwd) — extraction success/failure above is unaffected. */
|
|
41
|
+
writeError?: string;
|
|
42
|
+
/** True when `preserveExistingOnFailure` kept the existing render instead of writing an error panel over it. */
|
|
43
|
+
preservedExisting?: boolean;
|
|
44
|
+
}
|
|
45
|
+
export interface RenderCanvasOptions {
|
|
46
|
+
/**
|
|
47
|
+
* For unprompted (auto) renders only — session create, boot. When the
|
|
48
|
+
* extraction failed AND a render file for this workflow already exists,
|
|
49
|
+
* keep the existing file rather than replace a possibly-good diagram with
|
|
50
|
+
* an error panel. An explicit user-invoked render (the Visualize macro,
|
|
51
|
+
* POST /canvas/:id/render) should NOT set this: there the honest error
|
|
52
|
+
* page IS the answer the user asked for.
|
|
53
|
+
*/
|
|
54
|
+
preserveExistingOnFailure?: boolean;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Renders `session`'s bound workflow to its per-workflow render file. Never
|
|
58
|
+
* throws — every failure mode (extraction, filesystem) is captured in the
|
|
59
|
+
* returned outcome instead. Unbound sessions are a cheap no-op: no
|
|
60
|
+
* extraction, no write (`mode: "empty"`).
|
|
61
|
+
*/
|
|
62
|
+
export declare function renderCanvasForSession(session: RenderableSession, workflows: readonly RenderableWorkflow[], options?: RenderCanvasOptions): Promise<CanvasRenderOutcome>;
|
|
63
|
+
/**
|
|
64
|
+
* Renders ONE workflow to its render file under `cwd`, merging in any cached
|
|
65
|
+
* enrichment (fresh or stale — stale gets the chip; the base structure is
|
|
66
|
+
* always freshly extracted either way). This is the write path shared by
|
|
67
|
+
* bind/create/macro renders (via `renderCanvasForSession`) and by the
|
|
68
|
+
* enrichment task's own completion re-render (core/canvas-enrich.ts), which
|
|
69
|
+
* targets a workflow directly — the session may have switched bindings while
|
|
70
|
+
* the task ran, and the render file is per-workflow anyway.
|
|
71
|
+
*/
|
|
72
|
+
export declare function renderWorkflowRenderFile(cwd: string, bound: RenderableWorkflow, options?: RenderCanvasOptions): Promise<CanvasRenderOutcome>;
|
|
73
|
+
//# sourceMappingURL=canvas-render.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canvas-render.d.ts","sourceRoot":"","sources":["../../src/core/canvas-render.ts"],"names":[],"mappings":"AAwCA,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAShE;AAED,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAEvE;AAED;wDACwD;AACxD,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAEhF;AAED,MAAM,WAAW,mBAAmB;IAClC;;8EAE0E;IAC1E,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yGAAyG;IACzG,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,iFAAiF;IACjF,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;uCACmC;IACnC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;4DACwD;IACxD,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,8HAA8H;IAC9H,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gHAAgH;IAChH,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,mBAAmB;IAClC;;;;;;;OAOG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACrC;AA+BD;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,iBAAiB,EAC1B,SAAS,EAAE,SAAS,kBAAkB,EAAE,EACxC,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,mBAAmB,CAAC,CAM9B;AAED;;;;;;;;GAQG;AACH,wBAAsB,wBAAwB,CAC5C,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,kBAAkB,EACzB,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,mBAAmB,CAAC,CA+C9B"}
|