@galaxy-tool-util/cli 1.1.0 → 1.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.
Files changed (67) hide show
  1. package/dist/commands/annotate-connections.d.ts +30 -0
  2. package/dist/commands/annotate-connections.d.ts.map +1 -0
  3. package/dist/commands/annotate-connections.js +42 -0
  4. package/dist/commands/annotate-connections.js.map +1 -0
  5. package/dist/commands/connection-validation.d.ts +20 -0
  6. package/dist/commands/connection-validation.d.ts.map +1 -0
  7. package/dist/commands/connection-validation.js +26 -0
  8. package/dist/commands/connection-validation.js.map +1 -0
  9. package/dist/commands/cytoscapejs/_template-bundled.d.ts +2 -0
  10. package/dist/commands/cytoscapejs/_template-bundled.d.ts.map +1 -0
  11. package/dist/commands/cytoscapejs/_template-bundled.js +182 -0
  12. package/dist/commands/cytoscapejs/_template-bundled.js.map +1 -0
  13. package/dist/commands/cytoscapejs.d.ts +12 -0
  14. package/dist/commands/cytoscapejs.d.ts.map +1 -0
  15. package/dist/commands/cytoscapejs.js +62 -0
  16. package/dist/commands/cytoscapejs.js.map +1 -0
  17. package/dist/commands/mermaid.d.ts +2 -0
  18. package/dist/commands/mermaid.d.ts.map +1 -1
  19. package/dist/commands/mermaid.js +5 -1
  20. package/dist/commands/mermaid.js.map +1 -1
  21. package/dist/commands/validate-workflow.d.ts +1 -0
  22. package/dist/commands/validate-workflow.d.ts.map +1 -1
  23. package/dist/commands/validate-workflow.js +38 -3
  24. package/dist/commands/validate-workflow.js.map +1 -1
  25. package/dist/index.d.ts +3 -0
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +2 -0
  28. package/dist/index.js.map +1 -1
  29. package/dist/meta/extract-spec.d.ts +13 -0
  30. package/dist/meta/extract-spec.d.ts.map +1 -0
  31. package/dist/meta/extract-spec.js +90 -0
  32. package/dist/meta/extract-spec.js.map +1 -0
  33. package/dist/meta/index.d.ts +8 -0
  34. package/dist/meta/index.d.ts.map +1 -0
  35. package/dist/meta/index.js +21 -0
  36. package/dist/meta/index.js.map +1 -0
  37. package/dist/meta/spec-types.d.ts +40 -0
  38. package/dist/meta/spec-types.d.ts.map +1 -0
  39. package/dist/meta/spec-types.js +11 -0
  40. package/dist/meta/spec-types.js.map +1 -0
  41. package/dist/meta/specs.d.ts +4 -0
  42. package/dist/meta/specs.d.ts.map +1 -0
  43. package/dist/meta/specs.js +10 -0
  44. package/dist/meta/specs.js.map +1 -0
  45. package/dist/meta/types.d.ts +55 -0
  46. package/dist/meta/types.d.ts.map +1 -0
  47. package/dist/meta/types.js +9 -0
  48. package/dist/meta/types.js.map +1 -0
  49. package/dist/meta-build.d.ts +13 -0
  50. package/dist/meta-build.d.ts.map +1 -0
  51. package/dist/meta-build.js +60 -0
  52. package/dist/meta-build.js.map +1 -0
  53. package/dist/programs/galaxy-tool-cache.d.ts +5 -1
  54. package/dist/programs/galaxy-tool-cache.d.ts.map +1 -1
  55. package/dist/programs/galaxy-tool-cache.js +12 -56
  56. package/dist/programs/galaxy-tool-cache.js.map +1 -1
  57. package/dist/programs/gxwf.d.ts +7 -1
  58. package/dist/programs/gxwf.d.ts.map +1 -1
  59. package/dist/programs/gxwf.js +36 -184
  60. package/dist/programs/gxwf.js.map +1 -1
  61. package/dist/spec/build-program.d.ts +12 -0
  62. package/dist/spec/build-program.d.ts.map +1 -0
  63. package/dist/spec/build-program.js +102 -0
  64. package/dist/spec/build-program.js.map +1 -0
  65. package/package.json +10 -4
  66. package/spec/galaxy-tool-cache.json +152 -0
  67. package/spec/gxwf.json +693 -0
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Helper for `gxwf mermaid` / `gxwf cytoscapejs` `--annotate-connections`:
3
+ * runs the connection validator against a workflow and returns the
4
+ * `EdgeAnnotation` lookup the emitters consume.
5
+ */
6
+ import { type EdgeAnnotation } from "@galaxy-tool-util/connection-validation";
7
+ import type { ToolCache } from "@galaxy-tool-util/core";
8
+ import type { ParsedTool } from "@galaxy-tool-util/schema";
9
+ export interface ResolveEdgeAnnotationsOptions {
10
+ cacheDir?: string;
11
+ }
12
+ export declare function resolveEdgeAnnotations(data: Record<string, unknown>, opts?: ResolveEdgeAnnotationsOptions): Promise<Map<string, EdgeAnnotation>>;
13
+ export declare function resolveEdgeAnnotationsWithCache(data: Record<string, unknown>, cache: ToolCache): Promise<Map<string, EdgeAnnotation>>;
14
+ export interface ResolvedToolSpec {
15
+ tool_id: string;
16
+ tool_version: string;
17
+ parsed: ParsedTool;
18
+ }
19
+ /**
20
+ * Variant of `resolveEdgeAnnotationsWithCache` that also returns the
21
+ * `ParsedTool` specs the validator consumed, keyed by `toolId@toolVersion`.
22
+ * The hybrid `gxwf-web` edge-annotations response uses this so co-resident
23
+ * browsers can write the specs into IndexedDB and warm the client-side
24
+ * `useToolInfoService` for free.
25
+ */
26
+ export declare function resolveEdgeAnnotationsAndSpecsWithCache(data: Record<string, unknown>, cache: ToolCache): Promise<{
27
+ annotations: Map<string, EdgeAnnotation>;
28
+ specs: Map<string, ResolvedToolSpec>;
29
+ }>;
30
+ //# sourceMappingURL=annotate-connections.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"annotate-connections.d.ts","sourceRoot":"","sources":["../../src/commands/annotate-connections.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAKL,KAAK,cAAc,EACpB,MAAM,yCAAyC,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAExD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAK3D,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,IAAI,GAAE,6BAAkC,GACvC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAItC;AAED,wBAAsB,+BAA+B,CACnD,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,SAAS,GACf,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAKtC;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,UAAU,CAAC;CACpB;AAED;;;;;;GAMG;AACH,wBAAsB,uCAAuC,CAC3D,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,SAAS,GACf,OAAO,CAAC;IACT,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IACzC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CACtC,CAAC,CAYD"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Helper for `gxwf mermaid` / `gxwf cytoscapejs` `--annotate-connections`:
3
+ * runs the connection validator against a workflow and returns the
4
+ * `EdgeAnnotation` lookup the emitters consume.
5
+ */
6
+ import { buildEdgeAnnotations, buildGetToolInfo as _buildGetToolInfo, buildWorkflowGraph, validateConnectionGraph, } from "@galaxy-tool-util/connection-validation";
7
+ import { makeNodeToolCache } from "@galaxy-tool-util/core/node";
8
+ import { buildGetToolInfo } from "./connection-validation.js";
9
+ import { isResolveError, loadCachedTool } from "./resolve-tool.js";
10
+ export async function resolveEdgeAnnotations(data, opts = {}) {
11
+ const cache = makeNodeToolCache({ cacheDir: opts.cacheDir });
12
+ await cache.index.load();
13
+ return resolveEdgeAnnotationsWithCache(data, cache);
14
+ }
15
+ export async function resolveEdgeAnnotationsWithCache(data, cache) {
16
+ const getToolInfo = await buildGetToolInfo(data, cache);
17
+ const graph = buildWorkflowGraph(data, getToolInfo);
18
+ const [report] = validateConnectionGraph(graph);
19
+ return buildEdgeAnnotations(report);
20
+ }
21
+ /**
22
+ * Variant of `resolveEdgeAnnotationsWithCache` that also returns the
23
+ * `ParsedTool` specs the validator consumed, keyed by `toolId@toolVersion`.
24
+ * The hybrid `gxwf-web` edge-annotations response uses this so co-resident
25
+ * browsers can write the specs into IndexedDB and warm the client-side
26
+ * `useToolInfoService` for free.
27
+ */
28
+ export async function resolveEdgeAnnotationsAndSpecsWithCache(data, cache) {
29
+ const specs = new Map();
30
+ const getToolInfo = await _buildGetToolInfo(data, async (id, version) => {
31
+ const r = await loadCachedTool(cache, id, version);
32
+ if (isResolveError(r))
33
+ return null;
34
+ const ver = r.tool.version ?? version ?? "";
35
+ specs.set(`${id}@${ver}`, { tool_id: id, tool_version: ver, parsed: r.tool });
36
+ return r.tool;
37
+ });
38
+ const graph = buildWorkflowGraph(data, getToolInfo);
39
+ const [report] = validateConnectionGraph(graph);
40
+ return { annotations: buildEdgeAnnotations(report), specs };
41
+ }
42
+ //# sourceMappingURL=annotate-connections.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"annotate-connections.js","sourceRoot":"","sources":["../../src/commands/annotate-connections.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,oBAAoB,EACpB,gBAAgB,IAAI,iBAAiB,EACrC,kBAAkB,EAClB,uBAAuB,GAExB,MAAM,yCAAyC,CAAC;AAEjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAGhE,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAMnE,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,IAA6B,EAC7B,OAAsC,EAAE;IAExC,MAAM,KAAK,GAAG,iBAAiB,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC7D,MAAM,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IACzB,OAAO,+BAA+B,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,+BAA+B,CACnD,IAA6B,EAC7B,KAAgB;IAEhB,MAAM,WAAW,GAAG,MAAM,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACxD,MAAM,KAAK,GAAG,kBAAkB,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IACpD,MAAM,CAAC,MAAM,CAAC,GAAG,uBAAuB,CAAC,KAAK,CAAC,CAAC;IAChD,OAAO,oBAAoB,CAAC,MAAM,CAAC,CAAC;AACtC,CAAC;AAQD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,uCAAuC,CAC3D,IAA6B,EAC7B,KAAgB;IAKhB,MAAM,KAAK,GAAG,IAAI,GAAG,EAA4B,CAAC;IAClD,MAAM,WAAW,GAAG,MAAM,iBAAiB,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE;QACtE,MAAM,CAAC,GAAG,MAAM,cAAc,CAAC,KAAK,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;QACnD,IAAI,cAAc,CAAC,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;QACnC,MAAM,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,IAAI,OAAO,IAAI,EAAE,CAAC;QAC5C,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,GAAG,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QAC9E,OAAO,CAAC,CAAC,IAAI,CAAC;IAChB,CAAC,CAAC,CAAC;IACH,MAAM,KAAK,GAAG,kBAAkB,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IACpD,MAAM,CAAC,MAAM,CAAC,GAAG,uBAAuB,CAAC,KAAK,CAAC,CAAC;IAChD,OAAO,EAAE,WAAW,EAAE,oBAAoB,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC;AAC9D,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * CLI integration for connection validation.
3
+ *
4
+ * Walks a workflow dict to collect every tool reference (recursing into
5
+ * subworkflows), preloads each tool from the cache, and runs
6
+ * `validateConnectionsReport`. The connection validator wants a sync
7
+ * `GetToolInfo` lookup, so async cache fetches happen up front.
8
+ *
9
+ * The walker + preloader live in `@galaxy-tool-util/connection-validation`
10
+ * (`collectToolRefs`, `buildGetToolInfo`); this module is a thin wrapper that
11
+ * adapts the CLI's on-disk `ToolCache` to the lifted helper's `AsyncToolFetcher`.
12
+ */
13
+ import { collectToolRefs, type GetToolInfo } from "@galaxy-tool-util/connection-validation";
14
+ import type { ToolCache } from "@galaxy-tool-util/core";
15
+ import type { ConnectionValidationReport } from "@galaxy-tool-util/schema";
16
+ export { collectToolRefs };
17
+ export type { ToolRef } from "@galaxy-tool-util/connection-validation";
18
+ export declare function buildConnectionReport(data: Record<string, unknown>, cache: ToolCache): Promise<ConnectionValidationReport>;
19
+ export declare function buildGetToolInfo(data: Record<string, unknown>, cache: ToolCache): Promise<GetToolInfo>;
20
+ //# sourceMappingURL=connection-validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection-validation.d.ts","sourceRoot":"","sources":["../../src/commands/connection-validation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAEL,eAAe,EAEf,KAAK,WAAW,EACjB,MAAM,yCAAyC,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AAI3E,OAAO,EAAE,eAAe,EAAE,CAAC;AAC3B,YAAY,EAAE,OAAO,EAAE,MAAM,yCAAyC,CAAC;AAEvE,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,SAAS,GACf,OAAO,CAAC,0BAA0B,CAAC,CAGrC;AAED,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,SAAS,GACf,OAAO,CAAC,WAAW,CAAC,CAKtB"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * CLI integration for connection validation.
3
+ *
4
+ * Walks a workflow dict to collect every tool reference (recursing into
5
+ * subworkflows), preloads each tool from the cache, and runs
6
+ * `validateConnectionsReport`. The connection validator wants a sync
7
+ * `GetToolInfo` lookup, so async cache fetches happen up front.
8
+ *
9
+ * The walker + preloader live in `@galaxy-tool-util/connection-validation`
10
+ * (`collectToolRefs`, `buildGetToolInfo`); this module is a thin wrapper that
11
+ * adapts the CLI's on-disk `ToolCache` to the lifted helper's `AsyncToolFetcher`.
12
+ */
13
+ import { buildGetToolInfo as _buildGetToolInfo, collectToolRefs, validateConnectionsReport, } from "@galaxy-tool-util/connection-validation";
14
+ import { isResolveError, loadCachedTool } from "./resolve-tool.js";
15
+ export { collectToolRefs };
16
+ export async function buildConnectionReport(data, cache) {
17
+ const getToolInfo = await buildGetToolInfo(data, cache);
18
+ return validateConnectionsReport(data, getToolInfo);
19
+ }
20
+ export async function buildGetToolInfo(data, cache) {
21
+ return _buildGetToolInfo(data, async (id, version) => {
22
+ const r = await loadCachedTool(cache, id, version);
23
+ return isResolveError(r) ? null : r.tool;
24
+ });
25
+ }
26
+ //# sourceMappingURL=connection-validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection-validation.js","sourceRoot":"","sources":["../../src/commands/connection-validation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,gBAAgB,IAAI,iBAAiB,EACrC,eAAe,EACf,yBAAyB,GAE1B,MAAM,yCAAyC,CAAC;AAIjD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnE,OAAO,EAAE,eAAe,EAAE,CAAC;AAG3B,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,IAA6B,EAC7B,KAAgB;IAEhB,MAAM,WAAW,GAAG,MAAM,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACxD,OAAO,yBAAyB,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,IAA6B,EAC7B,KAAgB;IAEhB,OAAO,iBAAiB,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE;QACnD,MAAM,CAAC,GAAG,MAAM,cAAc,CAAC,KAAK,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;QACnD,OAAO,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC3C,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const CYTOSCAPE_HTML_TEMPLATE = "<!doctype html>\n\n<html>\n\n<head>\n <title>Galaxy Workflow</title>\n <script src=\"https://unpkg.com/cytoscape@3.33.2/dist/cytoscape.min.js\"></script>\n <script src=\"https://unpkg.com/dagre@0.8.5/dist/dagre.min.js\"></script>\n <script src=\"https://unpkg.com/cytoscape-dagre@2.5.0/cytoscape-dagre.js\"></script>\n <script src=\"https://unpkg.com/@popperjs/core@2.11.8/dist/umd/popper.min.js\"></script>\n <script src=\"https://unpkg.com/cytoscape-popper@2.0.0/cytoscape-popper.js\"></script>\n <script src=\"https://unpkg.com/tippy.js@6.3.7/dist/tippy.umd.min.js\"></script>\n <link rel=\"stylesheet\" href=\"https://unpkg.com/tippy.js@6.3.7/dist/tippy.css\" />\n <script>\ndocument.addEventListener(\"DOMContentLoaded\", function() {\n var requestedLayout = $layout;\n var dagreReady = (typeof cytoscapeDagre !== 'undefined');\n if (dagreReady && cytoscape.use) {\n try { cytoscape.use(cytoscapeDagre); } catch (e) { /* already registered */ }\n }\n var layoutConfig = (function(name) {\n if (name === 'dagre') {\n return dagreReady\n ? { name: 'dagre', rankDir: 'LR', nodeSep: 40, rankSep: 80 }\n : { name: 'preset' };\n }\n if (name === 'breadthfirst') return { name: 'breadthfirst', directed: true, spacingFactor: 1.2 };\n if (name === 'grid') return { name: 'grid' };\n if (name === 'cose') return { name: 'cose' };\n if (name === 'random') return { name: 'random' };\n if (name === 'topological') return { name: 'preset' };\n return { name: 'preset' };\n })(requestedLayout);\n var cy = cytoscape({\n container: document.getElementById('cy'),\n elements: $elements,\n layout: layoutConfig,\n // so we can see the ids\n style: [\n {\n selector: 'node',\n style: {\n 'label': 'data(label)'\n }\n },\n {\n selector: 'edge',\n style: {\n 'curve-style': 'bezier',\n 'target-arrow-shape': 'vee',\n 'arrow-scale': 2\n }\n },\n {\n selector: \".input\",\n style: {\n shape: 'diamond',\n 'background-color': '#d0bb46'\n }\n },\n {\n selector: \".runnable\",\n style: {\n shape: 'round-rectangle',\n 'background-color': '#2c3143'\n }\n },\n {\n selector: 'edge.mapover_1',\n style: { width: 4, 'line-color': '#5a8' }\n },\n {\n selector: 'edge.mapover_2',\n style: { width: 6, 'line-color': '#5a8' }\n },\n {\n selector: 'edge.mapover_3',\n style: { width: 8, 'line-color': '#5a8' }\n },\n {\n selector: 'edge.reduction',\n style: {\n 'line-style': 'dashed',\n 'line-color': '#a55',\n 'target-arrow-shape': 'tee',\n 'target-arrow-color': '#a55'\n }\n }\n ]\n });\n\n function makePopper(ele) {\n let ref = ele.popperRef(); // used only for positioning\n let dummyDomEle = document.createElement('div');\n\n ele.tippy = tippy(dummyDomEle, { // tippy options:\n getReferenceClientRect: ref.getBoundingClientRect.bind(ref),\n content: function() {\n let content = document.createElement('div');\n\n let innerHTML = '';\n if(ele.isNode()) {\n let stepType = ele.data(\"step_type\");\n innerHTML += \"<p><i>Step Type:</i> \" + stepType + \"</p>\";\n let toolId = ele.data(\"tool_id\");\n if (toolId) {\n innerHTML += \"<p><i>ToolID:</i> \" + toolId + \"</p>\";\n }\n let repoLink = ele.data(\"repo_link\");\n if (repoLink) {\n innerHTML += \"<a href=\" + repoLink + '\">Visit Tool Shed Repository</a>';\n }\n let doc = ele.data('doc');\n if (doc) {\n innerHTML += \"<p>\" + doc + \"</p>\";\n }\n } else {\n let output = ele.data(\"output\");\n let input = ele.data(\"input\");\n if(output) {\n innerHTML += \"Output named \" + output + \" connects to \" + input;\n } else {\n innerHTML += \"Connected to input \" + input;\n }\n let mapDepth = ele.data(\"map_depth\");\n if (mapDepth) {\n let mapping = ele.data(\"mapping\");\n innerHTML += \"<p><i>Map depth:</i> \" + mapDepth + (mapping ? \" (\" + mapping + \")\" : \"\") + \"</p>\";\n }\n if (ele.data(\"reduction\")) {\n innerHTML += \"<p><i>Reduction:</i> list \u2192 multi-data</p>\";\n }\n }\n content.innerHTML = innerHTML;\n\n return content;\n },\n delay: [0,1000],\n interactive: true,\n placement: 'bottom',\n trigger: 'manual', // probably want manual mode\n appendTo: document.body\n });\n }\n\n cy.ready(function() {\n cy.elements().forEach(function(ele) {\n makePopper(ele);\n });\n });\n\n cy.elements().unbind('mouseover');\n cy.elements().bind('mouseover', function(event) { event.target.tippy.show(); });\n\n cy.elements().unbind('mouseout');\n cy.elements().bind('mouseout', function(event) { event.target.tippy.hide(); });\n // document.querySelector('#cypng').setAttribute('src', cy.png());\n});\n\n </script>\n</head>\n\n<style>\n #cy {\n width: 100%;\n height: 100%;\n position: absolute;\n top: 0px;\n left: 0px;\n }\n a {\n color: #d0bb46\n }\n</style>\n\n<body>\n <div id=\"cy\"></div>\n</body>\n</html>\n";
2
+ //# sourceMappingURL=_template-bundled.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_template-bundled.d.ts","sourceRoot":"","sources":["../../../src/commands/cytoscapejs/_template-bundled.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,uBAAuB,s/LAmLnC,CAAC"}
@@ -0,0 +1,182 @@
1
+ // AUTO-GENERATED by scripts/bundle-templates.mjs — do not edit.
2
+ export const CYTOSCAPE_HTML_TEMPLATE = `<!doctype html>
3
+
4
+ <html>
5
+
6
+ <head>
7
+ <title>Galaxy Workflow</title>
8
+ <script src="https://unpkg.com/cytoscape@3.33.2/dist/cytoscape.min.js"></script>
9
+ <script src="https://unpkg.com/dagre@0.8.5/dist/dagre.min.js"></script>
10
+ <script src="https://unpkg.com/cytoscape-dagre@2.5.0/cytoscape-dagre.js"></script>
11
+ <script src="https://unpkg.com/@popperjs/core@2.11.8/dist/umd/popper.min.js"></script>
12
+ <script src="https://unpkg.com/cytoscape-popper@2.0.0/cytoscape-popper.js"></script>
13
+ <script src="https://unpkg.com/tippy.js@6.3.7/dist/tippy.umd.min.js"></script>
14
+ <link rel="stylesheet" href="https://unpkg.com/tippy.js@6.3.7/dist/tippy.css" />
15
+ <script>
16
+ document.addEventListener("DOMContentLoaded", function() {
17
+ var requestedLayout = $layout;
18
+ var dagreReady = (typeof cytoscapeDagre !== 'undefined');
19
+ if (dagreReady && cytoscape.use) {
20
+ try { cytoscape.use(cytoscapeDagre); } catch (e) { /* already registered */ }
21
+ }
22
+ var layoutConfig = (function(name) {
23
+ if (name === 'dagre') {
24
+ return dagreReady
25
+ ? { name: 'dagre', rankDir: 'LR', nodeSep: 40, rankSep: 80 }
26
+ : { name: 'preset' };
27
+ }
28
+ if (name === 'breadthfirst') return { name: 'breadthfirst', directed: true, spacingFactor: 1.2 };
29
+ if (name === 'grid') return { name: 'grid' };
30
+ if (name === 'cose') return { name: 'cose' };
31
+ if (name === 'random') return { name: 'random' };
32
+ if (name === 'topological') return { name: 'preset' };
33
+ return { name: 'preset' };
34
+ })(requestedLayout);
35
+ var cy = cytoscape({
36
+ container: document.getElementById('cy'),
37
+ elements: $elements,
38
+ layout: layoutConfig,
39
+ // so we can see the ids
40
+ style: [
41
+ {
42
+ selector: 'node',
43
+ style: {
44
+ 'label': 'data(label)'
45
+ }
46
+ },
47
+ {
48
+ selector: 'edge',
49
+ style: {
50
+ 'curve-style': 'bezier',
51
+ 'target-arrow-shape': 'vee',
52
+ 'arrow-scale': 2
53
+ }
54
+ },
55
+ {
56
+ selector: ".input",
57
+ style: {
58
+ shape: 'diamond',
59
+ 'background-color': '#d0bb46'
60
+ }
61
+ },
62
+ {
63
+ selector: ".runnable",
64
+ style: {
65
+ shape: 'round-rectangle',
66
+ 'background-color': '#2c3143'
67
+ }
68
+ },
69
+ {
70
+ selector: 'edge.mapover_1',
71
+ style: { width: 4, 'line-color': '#5a8' }
72
+ },
73
+ {
74
+ selector: 'edge.mapover_2',
75
+ style: { width: 6, 'line-color': '#5a8' }
76
+ },
77
+ {
78
+ selector: 'edge.mapover_3',
79
+ style: { width: 8, 'line-color': '#5a8' }
80
+ },
81
+ {
82
+ selector: 'edge.reduction',
83
+ style: {
84
+ 'line-style': 'dashed',
85
+ 'line-color': '#a55',
86
+ 'target-arrow-shape': 'tee',
87
+ 'target-arrow-color': '#a55'
88
+ }
89
+ }
90
+ ]
91
+ });
92
+
93
+ function makePopper(ele) {
94
+ let ref = ele.popperRef(); // used only for positioning
95
+ let dummyDomEle = document.createElement('div');
96
+
97
+ ele.tippy = tippy(dummyDomEle, { // tippy options:
98
+ getReferenceClientRect: ref.getBoundingClientRect.bind(ref),
99
+ content: function() {
100
+ let content = document.createElement('div');
101
+
102
+ let innerHTML = '';
103
+ if(ele.isNode()) {
104
+ let stepType = ele.data("step_type");
105
+ innerHTML += "<p><i>Step Type:</i> " + stepType + "</p>";
106
+ let toolId = ele.data("tool_id");
107
+ if (toolId) {
108
+ innerHTML += "<p><i>ToolID:</i> " + toolId + "</p>";
109
+ }
110
+ let repoLink = ele.data("repo_link");
111
+ if (repoLink) {
112
+ innerHTML += "<a href=" + repoLink + '">Visit Tool Shed Repository</a>';
113
+ }
114
+ let doc = ele.data('doc');
115
+ if (doc) {
116
+ innerHTML += "<p>" + doc + "</p>";
117
+ }
118
+ } else {
119
+ let output = ele.data("output");
120
+ let input = ele.data("input");
121
+ if(output) {
122
+ innerHTML += "Output named " + output + " connects to " + input;
123
+ } else {
124
+ innerHTML += "Connected to input " + input;
125
+ }
126
+ let mapDepth = ele.data("map_depth");
127
+ if (mapDepth) {
128
+ let mapping = ele.data("mapping");
129
+ innerHTML += "<p><i>Map depth:</i> " + mapDepth + (mapping ? " (" + mapping + ")" : "") + "</p>";
130
+ }
131
+ if (ele.data("reduction")) {
132
+ innerHTML += "<p><i>Reduction:</i> list → multi-data</p>";
133
+ }
134
+ }
135
+ content.innerHTML = innerHTML;
136
+
137
+ return content;
138
+ },
139
+ delay: [0,1000],
140
+ interactive: true,
141
+ placement: 'bottom',
142
+ trigger: 'manual', // probably want manual mode
143
+ appendTo: document.body
144
+ });
145
+ }
146
+
147
+ cy.ready(function() {
148
+ cy.elements().forEach(function(ele) {
149
+ makePopper(ele);
150
+ });
151
+ });
152
+
153
+ cy.elements().unbind('mouseover');
154
+ cy.elements().bind('mouseover', function(event) { event.target.tippy.show(); });
155
+
156
+ cy.elements().unbind('mouseout');
157
+ cy.elements().bind('mouseout', function(event) { event.target.tippy.hide(); });
158
+ // document.querySelector('#cypng').setAttribute('src', cy.png());
159
+ });
160
+
161
+ </script>
162
+ </head>
163
+
164
+ <style>
165
+ #cy {
166
+ width: 100%;
167
+ height: 100%;
168
+ position: absolute;
169
+ top: 0px;
170
+ left: 0px;
171
+ }
172
+ a {
173
+ color: #d0bb46
174
+ }
175
+ </style>
176
+
177
+ <body>
178
+ <div id="cy"></div>
179
+ </body>
180
+ </html>
181
+ `;
182
+ //# sourceMappingURL=_template-bundled.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_template-bundled.js","sourceRoot":"","sources":["../../../src/commands/cytoscapejs/_template-bundled.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,MAAM,CAAC,MAAM,uBAAuB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmLtC,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { CytoscapeElements, LayoutName } from "@galaxy-tool-util/schema";
2
+ export interface CytoscapeJsCommandOptions {
3
+ output?: string;
4
+ html?: boolean;
5
+ json?: boolean;
6
+ annotateConnections?: boolean;
7
+ cacheDir?: string;
8
+ layout?: string;
9
+ }
10
+ export declare function renderHtml(elements: CytoscapeElements, layout?: LayoutName): string;
11
+ export declare function runCytoscapeJs(filePath: string, opts: CytoscapeJsCommandOptions): Promise<void>;
12
+ //# sourceMappingURL=cytoscapejs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cytoscapejs.d.ts","sourceRoot":"","sources":["../../src/commands/cytoscapejs.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAO9E,MAAM,WAAW,yBAAyB;IACxC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,iBAAiB,EAAE,MAAM,GAAE,UAAqB,GAAG,MAAM,CAQ7F;AAmBD,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,yBAAyB,GAC9B,OAAO,CAAC,IAAI,CAAC,CA+Bf"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * `gxwf cytoscapejs` — render a Galaxy workflow as Cytoscape.js elements,
3
+ * either as JSON (default / `.json` output) or as a standalone HTML viewer
4
+ * (`.html` output).
5
+ *
6
+ * Port of gxformat2's `gxwf-viz` CLI; diverges from Python by defaulting to
7
+ * stdout JSON when no output path is given.
8
+ */
9
+ import { cytoscapeElements, elementsToList, isLayoutName } from "@galaxy-tool-util/schema";
10
+ import { writeFile } from "node:fs/promises";
11
+ import { resolveEdgeAnnotations } from "./annotate-connections.js";
12
+ import { CYTOSCAPE_HTML_TEMPLATE } from "./cytoscapejs/_template-bundled.js";
13
+ import { readWorkflowFile } from "./workflow-io.js";
14
+ export function renderHtml(elements, layout = "preset") {
15
+ const elementsJson = JSON.stringify(elementsToList(elements));
16
+ // Python uses string.Template.safe_substitute(...). Tokens are $elements
17
+ // and $layout (a quoted string the template embeds inside `layout: { name: ... }`).
18
+ return CYTOSCAPE_HTML_TEMPLATE.replaceAll("$elements", elementsJson).replaceAll("$layout", JSON.stringify(layout));
19
+ }
20
+ function chooseFormat(opts) {
21
+ if (opts.html)
22
+ return "html";
23
+ if (opts.json)
24
+ return "json";
25
+ if (opts.output?.endsWith(".html"))
26
+ return "html";
27
+ return "json";
28
+ }
29
+ function resolveLayout(raw) {
30
+ if (raw == null)
31
+ return "preset";
32
+ if (!isLayoutName(raw)) {
33
+ throw new Error(`Unknown --layout "${raw}". Valid values: preset, topological, dagre, breadthfirst, grid, cose, random.`);
34
+ }
35
+ return raw;
36
+ }
37
+ export async function runCytoscapeJs(filePath, opts) {
38
+ const data = await readWorkflowFile(filePath);
39
+ if (!data)
40
+ return;
41
+ const layout = resolveLayout(opts.layout);
42
+ const edgeAnnotations = opts.annotateConnections
43
+ ? await resolveEdgeAnnotations(data, { cacheDir: opts.cacheDir })
44
+ : undefined;
45
+ const elements = cytoscapeElements(data, { edgeAnnotations, layout });
46
+ const format = chooseFormat(opts);
47
+ // JSON shape: bare list when layout=preset (Python parity), wrapped
48
+ // {elements, layout} when caller opted in to a non-default layout. The
49
+ // wrapper carries the hint so downstream consumers (e.g. gxwf-ui) can honor
50
+ // it without sniffing.
51
+ const jsonPayload = layout === "preset"
52
+ ? elementsToList(elements)
53
+ : { elements: elementsToList(elements), layout: { name: layout } };
54
+ const content = format === "html" ? renderHtml(elements, layout) : JSON.stringify(jsonPayload, null, 2);
55
+ if (!opts.output) {
56
+ process.stdout.write(content + "\n");
57
+ return;
58
+ }
59
+ await writeFile(opts.output, content + "\n", "utf-8");
60
+ console.error(`Cytoscape ${format.toUpperCase()} written to ${opts.output}`);
61
+ }
62
+ //# sourceMappingURL=cytoscapejs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cytoscapejs.js","sourceRoot":"","sources":["../../src/commands/cytoscapejs.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAE3F,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAWpD,MAAM,UAAU,UAAU,CAAC,QAA2B,EAAE,SAAqB,QAAQ;IACnF,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC9D,yEAAyE;IACzE,oFAAoF;IACpF,OAAO,uBAAuB,CAAC,UAAU,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC,UAAU,CAC7E,SAAS,EACT,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CACvB,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,IAA+B;IACnD,IAAI,IAAI,CAAC,IAAI;QAAE,OAAO,MAAM,CAAC;IAC7B,IAAI,IAAI,CAAC,IAAI;QAAE,OAAO,MAAM,CAAC;IAC7B,IAAI,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC;QAAE,OAAO,MAAM,CAAC;IAClD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,aAAa,CAAC,GAAuB;IAC5C,IAAI,GAAG,IAAI,IAAI;QAAE,OAAO,QAAQ,CAAC;IACjC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CACb,qBAAqB,GAAG,gFAAgF,CACzG,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,QAAgB,EAChB,IAA+B;IAE/B,MAAM,IAAI,GAAG,MAAM,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAC9C,IAAI,CAAC,IAAI;QAAE,OAAO;IAElB,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAE1C,MAAM,eAAe,GAAG,IAAI,CAAC,mBAAmB;QAC9C,CAAC,CAAC,MAAM,sBAAsB,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;QACjE,CAAC,CAAC,SAAS,CAAC;IAEd,MAAM,QAAQ,GAAG,iBAAiB,CAAC,IAAI,EAAE,EAAE,eAAe,EAAE,MAAM,EAAE,CAAC,CAAC;IACtE,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAElC,oEAAoE;IACpE,uEAAuE;IACvE,4EAA4E;IAC5E,uBAAuB;IACvB,MAAM,WAAW,GACf,MAAM,KAAK,QAAQ;QACjB,CAAC,CAAC,cAAc,CAAC,QAAQ,CAAC;QAC1B,CAAC,CAAC,EAAE,QAAQ,EAAE,cAAc,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC;IAEvE,MAAM,OAAO,GACX,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAE1F,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;QACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;QACrC,OAAO;IACT,CAAC;IACD,MAAM,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;IACtD,OAAO,CAAC,KAAK,CAAC,aAAa,MAAM,CAAC,WAAW,EAAE,eAAe,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;AAC/E,CAAC"}
@@ -1,6 +1,8 @@
1
1
  export interface MermaidCommandOptions {
2
2
  output?: string;
3
3
  comments?: boolean;
4
+ annotateConnections?: boolean;
5
+ cacheDir?: string;
4
6
  }
5
7
  export declare function runMermaid(filePath: string, opts: MermaidCommandOptions): Promise<void>;
6
8
  //# sourceMappingURL=mermaid.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mermaid.d.ts","sourceRoot":"","sources":["../../src/commands/mermaid.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB7F"}
1
+ {"version":3,"file":"mermaid.d.ts","sourceRoot":"","sources":["../../src/commands/mermaid.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoB7F"}
@@ -4,11 +4,15 @@
4
4
  import { workflowToMermaid } from "@galaxy-tool-util/schema";
5
5
  import { writeFile } from "node:fs/promises";
6
6
  import { readWorkflowFile } from "./workflow-io.js";
7
+ import { resolveEdgeAnnotations } from "./annotate-connections.js";
7
8
  export async function runMermaid(filePath, opts) {
8
9
  const data = await readWorkflowFile(filePath);
9
10
  if (!data)
10
11
  return;
11
- const diagram = workflowToMermaid(data, { comments: opts.comments });
12
+ const edgeAnnotations = opts.annotateConnections
13
+ ? await resolveEdgeAnnotations(data, { cacheDir: opts.cacheDir })
14
+ : undefined;
15
+ const diagram = workflowToMermaid(data, { comments: opts.comments, edgeAnnotations });
12
16
  if (!opts.output) {
13
17
  process.stdout.write(diagram + "\n");
14
18
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"mermaid.js","sourceRoot":"","sources":["../../src/commands/mermaid.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAOpD,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,QAAgB,EAAE,IAA2B;IAC5E,MAAM,IAAI,GAAG,MAAM,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAC9C,IAAI,CAAC,IAAI;QAAE,OAAO;IAElB,MAAM,OAAO,GAAG,iBAAiB,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;IAErE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;QACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;QACrC,OAAO;IACT,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QACzC,CAAC,CAAC,kBAAkB,OAAO,YAAY;QACvC,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC;IACnB,MAAM,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC/C,OAAO,CAAC,KAAK,CAAC,8BAA8B,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;AAC7D,CAAC"}
1
+ {"version":3,"file":"mermaid.js","sourceRoot":"","sources":["../../src/commands/mermaid.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AASnE,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,QAAgB,EAAE,IAA2B;IAC5E,MAAM,IAAI,GAAG,MAAM,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAC9C,IAAI,CAAC,IAAI;QAAE,OAAO;IAElB,MAAM,eAAe,GAAG,IAAI,CAAC,mBAAmB;QAC9C,CAAC,CAAC,MAAM,sBAAsB,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;QACjE,CAAC,CAAC,SAAS,CAAC;IAEd,MAAM,OAAO,GAAG,iBAAiB,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,eAAe,EAAE,CAAC,CAAC;IAEtF,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;QACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;QACrC,OAAO;IACT,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QACzC,CAAC,CAAC,kBAAkB,OAAO,YAAY;QACvC,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC;IACnB,MAAM,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC/C,OAAO,CAAC,KAAK,CAAC,8BAA8B,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;AAC7D,CAAC"}
@@ -11,6 +11,7 @@ export interface ValidateWorkflowOptions extends StrictOptions {
11
11
  toolSchemaDir?: string;
12
12
  json?: boolean;
13
13
  reportHtml?: string | boolean;
14
+ connections?: boolean;
14
15
  }
15
16
  /** Run Effect Schema decode on raw workflow data and return structural decode failures. */
16
17
  export declare function decodeStructureErrors(data: Record<string, unknown>, format: WorkflowFormat): string[];
@@ -1 +1 @@
1
- {"version":3,"file":"validate-workflow.d.ts","sourceRoot":"","sources":["../../src/commands/validate-workflow.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAExD,OAAO,EAmBL,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACpB,MAAM,0BAA0B,CAAC;AAQlC,OAAO,EAAwB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAG/E,YAAY,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE/D,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,aAAa,CAAC;AAEtD,MAAM,WAAW,uBAAwB,SAAQ,aAAa;IAC5D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CAC/B;AAOD,2FAA2F;AAC3F,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,MAAM,EAAE,cAAc,GACrB,MAAM,EAAE,CAaV;AAED,YAAY,EAAE,oBAAoB,IAAI,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAG7F,OAAO,KAAK,EAAE,oBAAoB,IAAI,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAE7F,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,uBAAuB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAgIf;AAID,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,SAAS,EAChB,MAAM,SAAK,EACX,aAAa,CAAC,EAAE,gBAAgB,GAC/B,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAGjC;AA4GD,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,SAAS,EAChB,MAAM,SAAK,EACX,aAAa,CAAC,EAAE,gBAAgB,GAC/B,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAGjC;AAmJD;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,cAAc,EACtB,aAAa,CAAC,EAAE,gBAAgB,GAC/B,OAAO,CAAC,MAAM,EAAE,CAAC,CAOnB"}
1
+ {"version":3,"file":"validate-workflow.d.ts","sourceRoot":"","sources":["../../src/commands/validate-workflow.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAExD,OAAO,EAmBL,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACpB,MAAM,0BAA0B,CAAC;AAQlC,OAAO,EAAwB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAK/E,YAAY,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE/D,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,aAAa,CAAC;AAEtD,MAAM,WAAW,uBAAwB,SAAQ,aAAa;IAC5D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9B,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAOD,2FAA2F;AAC3F,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,MAAM,EAAE,cAAc,GACrB,MAAM,EAAE,CAaV;AAED,YAAY,EAAE,oBAAoB,IAAI,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAG7F,OAAO,KAAK,EAAE,oBAAoB,IAAI,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAE7F,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,uBAAuB,GAC5B,OAAO,CAAC,IAAI,CAAC,CA4If;AAwBD,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,SAAS,EAChB,MAAM,SAAK,EACX,aAAa,CAAC,EAAE,gBAAgB,GAC/B,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAGjC;AA4GD,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,SAAS,EAChB,MAAM,SAAK,EACX,aAAa,CAAC,EAAE,gBAAgB,GAC/B,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAGjC;AAmJD;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,cAAc,EACtB,aAAa,CAAC,EAAE,gBAAgB,GAC/B,OAAO,CAAC,MAAM,EAAE,CAAC,CAOnB"}
@@ -9,6 +9,7 @@ import { renderStepResults } from "./render-results.js";
9
9
  import { readWorkflowFile, resolveFormat } from "./workflow-io.js";
10
10
  import { resolveStrictOptions } from "./strict-options.js";
11
11
  import { writeReportHtml } from "./report-output.js";
12
+ import { buildConnectionReport } from "./connection-validation.js";
12
13
  function formatIssues(error) {
13
14
  const issues = ParseResult.ArrayFormatter.formatErrorSync(error);
14
15
  return issues.map((i) => `${i.path.join(".")}: ${i.message}`);
@@ -115,32 +116,66 @@ export async function runValidateWorkflow(filePath, opts) {
115
116
  }
116
117
  }
117
118
  const stateOk = !results.some((r) => r.status === "fail");
119
+ let connectionReport = null;
120
+ if (opts.connections) {
121
+ connectionReport = await buildConnectionReport(data, cache);
122
+ }
123
+ const connectionsOk = connectionReport === null || connectionReport.valid;
118
124
  if (opts.json || opts.reportHtml) {
119
125
  const report = buildSingleValidationReport(filePath, results, {
120
126
  structure_errors: structureErrors,
121
127
  encoding_errors: encodingErrors,
122
128
  });
129
+ if (connectionReport !== null) {
130
+ report.connection_report = connectionReport;
131
+ }
123
132
  if (opts.json) {
124
133
  console.log(JSON.stringify(report, null, 2));
125
134
  }
126
135
  await writeReportHtml("validate", report, opts.reportHtml);
127
- process.exitCode = structOk && stateOk ? 0 : 1;
136
+ process.exitCode = structOk && stateOk && connectionsOk ? 0 : 1;
128
137
  return;
129
138
  }
130
139
  if (results.length === 0) {
131
140
  console.log("No tool steps to validate state for.");
132
- process.exitCode = structOk ? 0 : 1;
141
+ if (connectionReport !== null)
142
+ printConnectionReport(connectionReport);
143
+ process.exitCode = structOk && connectionsOk ? 0 : 1;
133
144
  return;
134
145
  }
135
146
  const { validated, skipped } = renderStepResults(results);
136
147
  console.log(`\nTool state: ${validated} validated, ${skipped} skipped`);
148
+ if (connectionReport !== null)
149
+ printConnectionReport(connectionReport);
137
150
  // --- strict state: promote skips to failures ---
138
151
  if (strict.strictState && results.some((r) => r.status !== "ok" && r.status !== "fail")) {
139
152
  console.error("Strict state: skipped steps not allowed");
140
153
  process.exitCode = 2;
141
154
  return;
142
155
  }
143
- process.exitCode = structOk && stateOk ? 0 : 1;
156
+ process.exitCode = structOk && stateOk && connectionsOk ? 0 : 1;
157
+ }
158
+ function printConnectionReport(report) {
159
+ const { ok = 0, invalid = 0, skip = 0 } = report.summary;
160
+ console.log(`\nConnections: ${report.valid ? "OK" : "INVALID"} — ${ok} ok, ${invalid} invalid, ${skip} skip`);
161
+ if (!report.has_details)
162
+ return;
163
+ for (const sr of report.step_results) {
164
+ if (sr.errors.length === 0 && sr.connections.every((c) => c.status === "ok"))
165
+ continue;
166
+ const label = sr.tool_id ? `${sr.step} (${sr.tool_id})` : sr.step;
167
+ console.log(` step ${label}${sr.map_over ? ` [map_over=${sr.map_over}]` : ""}`);
168
+ for (const e of sr.errors)
169
+ console.log(` error: ${e}`);
170
+ for (const cr of sr.connections) {
171
+ if (cr.status === "ok")
172
+ continue;
173
+ const arrow = `${cr.source_step}/${cr.source_output} -> ${cr.target_input}`;
174
+ console.log(` ${cr.status}: ${arrow}`);
175
+ for (const e of cr.errors)
176
+ console.log(` ${e}`);
177
+ }
178
+ }
144
179
  }
145
180
  // --- Native validation ---
146
181
  export async function validateNativeSteps(data, cache, prefix = "", expansionOpts) {