@sapiom/harness 0.1.5 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (245) hide show
  1. package/CHANGELOG.md +151 -0
  2. package/dist/cli/args.d.ts +16 -0
  3. package/dist/cli/args.d.ts.map +1 -0
  4. package/dist/cli/args.js +80 -0
  5. package/dist/cli/args.js.map +1 -0
  6. package/dist/cli/bin.js +30 -66
  7. package/dist/cli/bin.js.map +1 -1
  8. package/dist/cli/consent.js +1 -1
  9. package/dist/cli/settings.d.ts.map +1 -1
  10. package/dist/cli/settings.js +33 -1
  11. package/dist/cli/settings.js.map +1 -1
  12. package/dist/core/adapters/adapter.d.ts +2 -2
  13. package/dist/core/adapters/claude-code.d.ts +60 -2
  14. package/dist/core/adapters/claude-code.d.ts.map +1 -1
  15. package/dist/core/adapters/claude-code.js +119 -32
  16. package/dist/core/adapters/claude-code.js.map +1 -1
  17. package/dist/core/adapters/codex.d.ts +21 -2
  18. package/dist/core/adapters/codex.d.ts.map +1 -1
  19. package/dist/core/adapters/codex.js +53 -2
  20. package/dist/core/adapters/codex.js.map +1 -1
  21. package/dist/core/adapters/detect.d.ts +9 -0
  22. package/dist/core/adapters/detect.d.ts.map +1 -1
  23. package/dist/core/adapters/detect.js +9 -0
  24. package/dist/core/adapters/detect.js.map +1 -1
  25. package/dist/core/api-key-provider.d.ts +79 -0
  26. package/dist/core/api-key-provider.d.ts.map +1 -0
  27. package/dist/core/api-key-provider.js +91 -0
  28. package/dist/core/api-key-provider.js.map +1 -0
  29. package/dist/core/canvas-body.d.ts +28 -28
  30. package/dist/core/canvas-body.d.ts.map +1 -1
  31. package/dist/core/canvas-body.js +117 -55
  32. package/dist/core/canvas-body.js.map +1 -1
  33. package/dist/core/canvas-derive.d.ts +43 -0
  34. package/dist/core/canvas-derive.d.ts.map +1 -0
  35. package/dist/core/canvas-derive.js +95 -0
  36. package/dist/core/canvas-derive.js.map +1 -0
  37. package/dist/core/canvas-enrichment.d.ts +52 -127
  38. package/dist/core/canvas-enrichment.d.ts.map +1 -1
  39. package/dist/core/canvas-enrichment.js +17 -178
  40. package/dist/core/canvas-enrichment.js.map +1 -1
  41. package/dist/core/canvas-graph.d.ts +40 -1
  42. package/dist/core/canvas-graph.d.ts.map +1 -1
  43. package/dist/core/canvas-graph.js +71 -9
  44. package/dist/core/canvas-graph.js.map +1 -1
  45. package/dist/core/canvas-interconnections.d.ts +26 -8
  46. package/dist/core/canvas-interconnections.d.ts.map +1 -1
  47. package/dist/core/canvas-interconnections.js +132 -24
  48. package/dist/core/canvas-interconnections.js.map +1 -1
  49. package/dist/core/canvas-manifest-check.d.ts.map +1 -1
  50. package/dist/core/canvas-manifest-check.js +15 -2
  51. package/dist/core/canvas-manifest-check.js.map +1 -1
  52. package/dist/core/canvas-render.d.ts +8 -15
  53. package/dist/core/canvas-render.d.ts.map +1 -1
  54. package/dist/core/canvas-render.js +29 -41
  55. package/dist/core/canvas-render.js.map +1 -1
  56. package/dist/core/canvas-run-state.d.ts +50 -5
  57. package/dist/core/canvas-run-state.d.ts.map +1 -1
  58. package/dist/core/canvas-run-state.js +176 -11
  59. package/dist/core/canvas-run-state.js.map +1 -1
  60. package/dist/core/canvas-svg.d.ts +9 -4
  61. package/dist/core/canvas-svg.d.ts.map +1 -1
  62. package/dist/core/canvas-svg.js +84 -13
  63. package/dist/core/canvas-svg.js.map +1 -1
  64. package/dist/core/canvas-template.d.ts +9 -10
  65. package/dist/core/canvas-template.d.ts.map +1 -1
  66. package/dist/core/canvas-template.js +57 -20
  67. package/dist/core/canvas-template.js.map +1 -1
  68. package/dist/core/canvas-watcher.d.ts +22 -1
  69. package/dist/core/canvas-watcher.d.ts.map +1 -1
  70. package/dist/core/canvas-watcher.js +111 -30
  71. package/dist/core/canvas-watcher.js.map +1 -1
  72. package/dist/core/collector/normalizer.d.ts +8 -0
  73. package/dist/core/collector/normalizer.d.ts.map +1 -1
  74. package/dist/core/collector/normalizer.js +8 -0
  75. package/dist/core/collector/normalizer.js.map +1 -1
  76. package/dist/core/collector/store.d.ts +75 -1
  77. package/dist/core/collector/store.d.ts.map +1 -1
  78. package/dist/core/collector/store.js +334 -2
  79. package/dist/core/collector/store.js.map +1 -1
  80. package/dist/core/definition-slug-resolver.d.ts +13 -0
  81. package/dist/core/definition-slug-resolver.d.ts.map +1 -1
  82. package/dist/core/definition-slug-resolver.js +29 -0
  83. package/dist/core/definition-slug-resolver.js.map +1 -1
  84. package/dist/core/errors.d.ts +10 -4
  85. package/dist/core/errors.d.ts.map +1 -1
  86. package/dist/core/errors.js +11 -5
  87. package/dist/core/errors.js.map +1 -1
  88. package/dist/core/example-seed.d.ts +8 -0
  89. package/dist/core/example-seed.d.ts.map +1 -1
  90. package/dist/core/example-seed.js +47 -10
  91. package/dist/core/example-seed.js.map +1 -1
  92. package/dist/core/inject/system-prompt.d.ts +8 -0
  93. package/dist/core/inject/system-prompt.d.ts.map +1 -1
  94. package/dist/core/inject/system-prompt.js +3 -1
  95. package/dist/core/inject/system-prompt.js.map +1 -1
  96. package/dist/core/macros.d.ts.map +1 -1
  97. package/dist/core/macros.js +5 -6
  98. package/dist/core/macros.js.map +1 -1
  99. package/dist/core/paths.d.ts +1 -0
  100. package/dist/core/paths.d.ts.map +1 -1
  101. package/dist/core/paths.js +1 -0
  102. package/dist/core/paths.js.map +1 -1
  103. package/dist/core/record-archive.d.ts +187 -0
  104. package/dist/core/record-archive.d.ts.map +1 -0
  105. package/dist/core/record-archive.js +465 -0
  106. package/dist/core/record-archive.js.map +1 -0
  107. package/dist/core/rehydration.d.ts +72 -0
  108. package/dist/core/rehydration.d.ts.map +1 -0
  109. package/dist/core/rehydration.js +72 -0
  110. package/dist/core/rehydration.js.map +1 -0
  111. package/dist/core/render-local-run.d.ts +82 -0
  112. package/dist/core/render-local-run.d.ts.map +1 -0
  113. package/dist/core/render-local-run.js +105 -0
  114. package/dist/core/render-local-run.js.map +1 -0
  115. package/dist/core/render-log-slice.d.ts +30 -0
  116. package/dist/core/render-log-slice.d.ts.map +1 -0
  117. package/dist/core/render-log-slice.js +49 -0
  118. package/dist/core/render-log-slice.js.map +1 -0
  119. package/dist/core/render-run-state.d.ts.map +1 -1
  120. package/dist/core/render-run-state.js +30 -49
  121. package/dist/core/render-run-state.js.map +1 -1
  122. package/dist/core/resume-brief.d.ts +130 -0
  123. package/dist/core/resume-brief.d.ts.map +1 -0
  124. package/dist/core/resume-brief.js +404 -0
  125. package/dist/core/resume-brief.js.map +1 -0
  126. package/dist/core/rolling-summary.d.ts +130 -0
  127. package/dist/core/rolling-summary.d.ts.map +1 -0
  128. package/dist/core/rolling-summary.js +227 -0
  129. package/dist/core/rolling-summary.js.map +1 -0
  130. package/dist/core/run-local-bootstrap.d.ts +93 -0
  131. package/dist/core/run-local-bootstrap.d.ts.map +1 -0
  132. package/dist/core/run-local-bootstrap.js +155 -0
  133. package/dist/core/run-local-bootstrap.js.map +1 -0
  134. package/dist/core/run-state.d.ts +16 -1
  135. package/dist/core/run-state.d.ts.map +1 -1
  136. package/dist/core/run-state.js +75 -25
  137. package/dist/core/run-state.js.map +1 -1
  138. package/dist/core/session-manager.d.ts +11 -3
  139. package/dist/core/session-manager.d.ts.map +1 -1
  140. package/dist/core/session-manager.js +56 -7
  141. package/dist/core/session-manager.js.map +1 -1
  142. package/dist/core/session-record.d.ts +165 -0
  143. package/dist/core/session-record.d.ts.map +1 -0
  144. package/dist/core/session-record.js +470 -0
  145. package/dist/core/session-record.js.map +1 -0
  146. package/dist/core/spawn-target.d.ts +12 -0
  147. package/dist/core/spawn-target.d.ts.map +1 -0
  148. package/dist/core/spawn-target.js +187 -0
  149. package/dist/core/spawn-target.js.map +1 -0
  150. package/dist/core/stub-feedback.d.ts +52 -0
  151. package/dist/core/stub-feedback.d.ts.map +1 -0
  152. package/dist/core/stub-feedback.js +33 -0
  153. package/dist/core/stub-feedback.js.map +1 -0
  154. package/dist/core/task-manager.d.ts.map +1 -1
  155. package/dist/core/task-manager.js +9 -1
  156. package/dist/core/task-manager.js.map +1 -1
  157. package/dist/core/template-catalog.d.ts +48 -0
  158. package/dist/core/template-catalog.d.ts.map +1 -0
  159. package/dist/core/template-catalog.js +338 -0
  160. package/dist/core/template-catalog.js.map +1 -0
  161. package/dist/core/workflow-registry.d.ts.map +1 -1
  162. package/dist/core/workflow-registry.js +2 -2
  163. package/dist/core/workflow-registry.js.map +1 -1
  164. package/dist/core/workspace-watcher.d.ts.map +1 -1
  165. package/dist/core/workspace-watcher.js +4 -3
  166. package/dist/core/workspace-watcher.js.map +1 -1
  167. package/dist/index.d.ts +12 -0
  168. package/dist/index.d.ts.map +1 -1
  169. package/dist/index.js +21 -0
  170. package/dist/index.js.map +1 -1
  171. package/dist/profiles/default.d.ts.map +1 -1
  172. package/dist/profiles/default.js +9 -14
  173. package/dist/profiles/default.js.map +1 -1
  174. package/dist/server/actions.d.ts +139 -0
  175. package/dist/server/actions.d.ts.map +1 -0
  176. package/dist/server/actions.js +430 -0
  177. package/dist/server/actions.js.map +1 -0
  178. package/dist/server/auth-routes.d.ts +92 -0
  179. package/dist/server/auth-routes.d.ts.map +1 -0
  180. package/dist/server/auth-routes.js +151 -0
  181. package/dist/server/auth-routes.js.map +1 -0
  182. package/dist/server/canvas.d.ts.map +1 -1
  183. package/dist/server/canvas.js +7 -7
  184. package/dist/server/canvas.js.map +1 -1
  185. package/dist/server/fs.d.ts.map +1 -1
  186. package/dist/server/fs.js +17 -1
  187. package/dist/server/fs.js.map +1 -1
  188. package/dist/server/index.d.ts +12 -3
  189. package/dist/server/index.d.ts.map +1 -1
  190. package/dist/server/index.js +0 -0
  191. package/dist/server/index.js.map +1 -1
  192. package/dist/server/ingest.d.ts +11 -0
  193. package/dist/server/ingest.d.ts.map +1 -1
  194. package/dist/server/ingest.js +1 -0
  195. package/dist/server/ingest.js.map +1 -1
  196. package/dist/server/macros.d.ts +4 -6
  197. package/dist/server/macros.d.ts.map +1 -1
  198. package/dist/server/macros.js.map +1 -1
  199. package/dist/server/rest.d.ts +18 -6
  200. package/dist/server/rest.d.ts.map +1 -1
  201. package/dist/server/rest.js +185 -50
  202. package/dist/server/rest.js.map +1 -1
  203. package/dist/server/runs.d.ts +16 -15
  204. package/dist/server/runs.d.ts.map +1 -1
  205. package/dist/server/runs.js +15 -80
  206. package/dist/server/runs.js.map +1 -1
  207. package/dist/server/static.d.ts +15 -1
  208. package/dist/server/static.d.ts.map +1 -1
  209. package/dist/server/static.js +54 -4
  210. package/dist/server/static.js.map +1 -1
  211. package/dist/server/templates.d.ts +24 -0
  212. package/dist/server/templates.d.ts.map +1 -0
  213. package/dist/server/templates.js +54 -0
  214. package/dist/server/templates.js.map +1 -0
  215. package/dist/shared/types.d.ts +558 -66
  216. package/dist/shared/types.d.ts.map +1 -1
  217. package/dist/shared/types.js +19 -11
  218. package/dist/shared/types.js.map +1 -1
  219. package/dist/web/assets/index-DC65cskq.js +446 -0
  220. package/dist/web/assets/index-xtD-3FFa.css +32 -0
  221. package/dist/web/canvas/sess-boot/index.html +305 -0
  222. package/dist/web/index.html +4 -9
  223. package/package.json +8 -4
  224. package/dist/core/canvas-enrich.d.ts +0 -115
  225. package/dist/core/canvas-enrich.d.ts.map +0 -1
  226. package/dist/core/canvas-enrich.js +0 -186
  227. package/dist/core/canvas-enrich.js.map +0 -1
  228. package/dist/core/run-spend.d.ts +0 -55
  229. package/dist/core/run-spend.d.ts.map +0 -1
  230. package/dist/core/run-spend.js +0 -109
  231. package/dist/core/run-spend.js.map +0 -1
  232. package/dist/core/run-transactions.d.ts +0 -60
  233. package/dist/core/run-transactions.d.ts.map +0 -1
  234. package/dist/core/run-transactions.js +0 -129
  235. package/dist/core/run-transactions.js.map +0 -1
  236. package/dist/profiles/canvas-guidelines.d.ts +0 -20
  237. package/dist/profiles/canvas-guidelines.d.ts.map +0 -1
  238. package/dist/profiles/canvas-guidelines.js +0 -48
  239. package/dist/profiles/canvas-guidelines.js.map +0 -1
  240. package/dist/server/skills.d.ts +0 -51
  241. package/dist/server/skills.d.ts.map +0 -1
  242. package/dist/server/skills.js +0 -312
  243. package/dist/server/skills.js.map +0 -1
  244. package/dist/web/assets/index-DM84J83Y.js +0 -234
  245. package/dist/web/assets/index-DemtWW4L.css +0 -32
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canvas-derive.js","sourceRoot":"","sources":["../../src/core/canvas-derive.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,23 @@
1
- import { z } from "zod";
2
- import type { CanvasGraph } from "./canvas-graph.js";
1
+ /**
2
+ * The canvas enrichment contract: the optional annotation layer merged on top
3
+ * of a deterministic canvas render — a summary line, per-node sublabels/hover
4
+ * descriptions, edge labels, footer notes, layout hints, and a cross-workflow
5
+ * tie. Every value is a BOUNDED plain string (the limits below are hard caps
6
+ * that keep the SVG layout from breaking); the renderer (core/canvas-svg.ts,
7
+ * core/canvas-body.ts) decides where each field goes.
8
+ *
9
+ * The enrichment is produced DETERMINISTICALLY, in-process, from the extracted
10
+ * graph — see core/canvas-derive.ts. There is no LLM, no user token, no file
11
+ * write, and no cache: it is recomputed from the current sources on every
12
+ * render, so it can never go stale. This module is now just the shared shape +
13
+ * limits both the producer (canvas-derive.ts) and the consumer (canvas-svg.ts,
14
+ * canvas-body.ts) agree on.
15
+ *
16
+ * Layout hints are the one structural field: named groups (rendered as subtle
17
+ * background bands) and per-layer ordering. The renderer applies a hint only
18
+ * when every node id it references actually exists in the graph (see
19
+ * canvas-svg.ts) — ids are validated at render time.
20
+ */
3
21
  export declare const ENRICHMENT_LIMITS: {
4
22
  readonly summary: 160;
5
23
  readonly sublabel: 48;
@@ -10,135 +28,42 @@ export declare const ENRICHMENT_LIMITS: {
10
28
  readonly groupLabel: 48;
11
29
  readonly crossWorkflow: 160;
12
30
  };
13
- export declare const canvasEnrichmentSchema: z.ZodObject<{
31
+ /** Per-node annotations, keyed by node id. */
32
+ export interface CanvasNodeDetail {
33
+ /** Second text line inside the node box. */
34
+ sublabel?: string;
35
+ /** Hover tooltip (SVG <title>) — room for a full sentence. */
36
+ description?: string;
37
+ }
38
+ /**
39
+ * The one structural hint set: named clusters rendered as background bands
40
+ * behind their member nodes, and a preferred left-to-right node order per
41
+ * layout layer (keyed by the layer index as a string). `laneOrder` reorders
42
+ * WITHIN a computed layer only — it can never move a node between layers.
43
+ */
44
+ export interface CanvasLayoutHints {
45
+ groups?: Array<{
46
+ label: string;
47
+ nodeIds: string[];
48
+ }>;
49
+ laneOrder?: Record<string, string[]>;
50
+ }
51
+ /**
52
+ * Everything the enrichment layer can add to a deterministic render. Every
53
+ * field is optional — the base structure render stands on its own without any
54
+ * of it, so a workflow with nothing worth annotating simply renders clean.
55
+ */
56
+ export interface CanvasEnrichment {
14
57
  /** One-liner under the panel header. */
15
- summary: z.ZodOptional<z.ZodString>;
58
+ summary?: string;
16
59
  /** Per-node annotations, keyed by node id. */
17
- nodeDetails: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
18
- /** Second text line inside the node box. */
19
- sublabel: z.ZodOptional<z.ZodString>;
20
- /** Hover tooltip (SVG <title>) — room for a full sentence. */
21
- description: z.ZodOptional<z.ZodString>;
22
- }, "strip", z.ZodTypeAny, {
23
- description?: string | undefined;
24
- sublabel?: string | undefined;
25
- }, {
26
- description?: string | undefined;
27
- sublabel?: string | undefined;
28
- }>>>;
60
+ nodeDetails?: Record<string, CanvasNodeDetail>;
29
61
  /** Edge annotations (intent/condition names), keyed `"<from>-><to>"`. */
30
- edgeLabels: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
62
+ edgeLabels?: Record<string, string>;
31
63
  /** Footer facts worth knowing that don't fit the diagram itself. */
32
- notes: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
33
- layoutHints: z.ZodOptional<z.ZodObject<{
34
- /** Named clusters rendered as background bands behind member nodes. */
35
- groups: z.ZodOptional<z.ZodArray<z.ZodObject<{
36
- label: z.ZodString;
37
- nodeIds: z.ZodArray<z.ZodString, "many">;
38
- }, "strip", z.ZodTypeAny, {
39
- label: string;
40
- nodeIds: string[];
41
- }, {
42
- label: string;
43
- nodeIds: string[];
44
- }>, "many">>;
45
- /** Preferred left-to-right node order per layout layer, keyed by the
46
- * layer index as a string. Reorders WITHIN the computed layer only —
47
- * it can never move a node between layers. */
48
- laneOrder: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString, "many">>>;
49
- }, "strip", z.ZodTypeAny, {
50
- groups?: {
51
- label: string;
52
- nodeIds: string[];
53
- }[] | undefined;
54
- laneOrder?: Record<string, string[]> | undefined;
55
- }, {
56
- groups?: {
57
- label: string;
58
- nodeIds: string[];
59
- }[] | undefined;
60
- laneOrder?: Record<string, string[]> | undefined;
61
- }>>;
64
+ notes?: string[];
65
+ layoutHints?: CanvasLayoutHints;
62
66
  /** How this workflow ties into the workspace's other workflows. */
63
- crossWorkflow: z.ZodOptional<z.ZodString>;
64
- }, "strip", z.ZodTypeAny, {
65
- summary?: string | undefined;
66
- nodeDetails?: Record<string, {
67
- description?: string | undefined;
68
- sublabel?: string | undefined;
69
- }> | undefined;
70
- edgeLabels?: Record<string, string> | undefined;
71
- notes?: string[] | undefined;
72
- layoutHints?: {
73
- groups?: {
74
- label: string;
75
- nodeIds: string[];
76
- }[] | undefined;
77
- laneOrder?: Record<string, string[]> | undefined;
78
- } | undefined;
79
- crossWorkflow?: string | undefined;
80
- }, {
81
- summary?: string | undefined;
82
- nodeDetails?: Record<string, {
83
- description?: string | undefined;
84
- sublabel?: string | undefined;
85
- }> | undefined;
86
- edgeLabels?: Record<string, string> | undefined;
87
- notes?: string[] | undefined;
88
- layoutHints?: {
89
- groups?: {
90
- label: string;
91
- nodeIds: string[];
92
- }[] | undefined;
93
- laneOrder?: Record<string, string[]> | undefined;
94
- } | undefined;
95
- crossWorkflow?: string | undefined;
96
- }>;
97
- export type CanvasEnrichment = z.infer<typeof canvasEnrichmentSchema>;
98
- export type CanvasLayoutHints = NonNullable<CanvasEnrichment["layoutHints"]>;
99
- /**
100
- * Validates a candidate enrichment object. Returns null on ANY schema
101
- * violation (oversize string, wrong shape, too many notes) — partial
102
- * salvage is deliberately not attempted, so the contract stays a hard line
103
- * the prompt can state truthfully: "invalid output is thrown away whole."
104
- */
105
- export declare function parseCanvasEnrichment(value: unknown): CanvasEnrichment | null;
106
- /**
107
- * Deterministic repair of the two ways an otherwise-good answer most often
108
- * misses the contract, applied BEFORE strict validation:
109
- * - `null` where the schema means "omit the field"
110
- * - strings a few words over their cap (measured live: sonnet writes
111
- * excellent content but doesn't count characters — a single 160-char note
112
- * against the 140 cap discarded 3 of 4 real enrichments whole), truncated
113
- * to the cap with an ellipsis; extra notes beyond the count cap dropped
114
- *
115
- * The bound the caps exist for — the AI can never blow up the layout with
116
- * unbounded text — is still enforced, just deterministically here instead
117
- * of by rejection. Everything else (wrong shapes, wrong types, unknown
118
- * structure) still fails `parseCanvasEnrichment` and discards the
119
- * enrichment whole.
120
- */
121
- export declare function normalizeCanvasEnrichmentCandidate(value: unknown): unknown;
122
- /**
123
- * What one cache file holds. `sourceFingerprint` is canvas-cache.ts's cheap
124
- * source fingerprint at the moment the enrichment task was SPAWNED — when it
125
- * no longer matches the workflow's current sources, the base diagram
126
- * re-renders immediately from fresh extraction while this enrichment stays
127
- * displayed with a "stale" chip until a re-run replaces it.
128
- */
129
- export interface EnrichmentCacheEntry {
130
- /** The graph the enrichment was generated against (diagnostic context —
131
- * renders always use the freshly extracted graph, never this copy). */
132
- graph: CanvasGraph;
133
- enrichment: CanvasEnrichment;
134
- sourceFingerprint: string;
135
- enrichedAt: string;
67
+ crossWorkflow?: string;
136
68
  }
137
- /** Reads + validates one enrichment cache file. Null for missing, unparsable
138
- * or schema-invalid content — a bad cache degrades to "no enrichment". */
139
- export declare function readEnrichmentCacheFile(filePath: string): Promise<EnrichmentCacheEntry | null>;
140
- export declare function writeEnrichmentCacheFile(filePath: string, entry: EnrichmentCacheEntry): Promise<void>;
141
- /** Deletes one enrichment cache file (the visualize macro's force refresh).
142
- * Missing file is fine — the goal state is "no cache". */
143
- export declare function removeEnrichmentCacheFile(filePath: string): Promise<void>;
144
69
  //# sourceMappingURL=canvas-enrichment.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"canvas-enrichment.d.ts","sourceRoot":"","sources":["../../src/core/canvas-enrichment.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,eAAO,MAAM,iBAAiB;;;;;;;;;CASpB,CAAC;AAIX,eAAO,MAAM,sBAAsB;IAE/B,wCAAwC;;IAExC,8CAA8C;;QAKtC,4CAA4C;;QAE5C,8DAA8D;;;;;;;;;IAMtE,yEAAyE;;IAEzE,oEAAoE;;;QAIhE,uEAAuE;;;;;;;;;;;QAWvE;;uDAE+C;;;;;;;;;;;;;;;IAKnD,mEAAmE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAG7D,CAAC;AAEX,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AACtE,MAAM,MAAM,iBAAiB,GAAG,WAAW,CAAC,gBAAgB,CAAC,aAAa,CAAC,CAAC,CAAC;AAE7E;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,gBAAgB,GAAG,IAAI,CAG7E;AAkBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kCAAkC,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CA6C1E;AAMD;;;;;;GAMG;AACH,MAAM,WAAW,oBAAoB;IACnC;4EACwE;IACxE,KAAK,EAAE,WAAW,CAAC;IACnB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;CACpB;AAmBD;2EAC2E;AAC3E,wBAAsB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAepG;AAED,wBAAsB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAG3G;AAED;2DAC2D;AAC3D,wBAAsB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/E"}
1
+ {"version":3,"file":"canvas-enrichment.d.ts","sourceRoot":"","sources":["../../src/core/canvas-enrichment.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,eAAO,MAAM,iBAAiB;;;;;;;;;CASpB,CAAC;AAEX,8CAA8C;AAC9C,MAAM,WAAW,gBAAgB;IAC/B,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IACrD,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACtC;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8CAA8C;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAC/C,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,oEAAoE;IACpE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,mEAAmE;IACnE,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB"}
@@ -1,22 +1,23 @@
1
1
  /**
2
- * The AI enrichment contract: everything the enrichment task is allowed to
3
- * add to a deterministic canvas render, as a zod schema. The AI never writes
4
- * HTML it returns one JSON object of BOUNDED plain strings (every limit
5
- * below is a hard cap, not advice) and the renderer decides where they go.
6
- * Unknown keys are stripped; any parse failure means the whole enrichment is
7
- * discarded and the base render stands — a malformed answer can degrade
8
- * nothing but itself.
2
+ * The canvas enrichment contract: the optional annotation layer merged on top
3
+ * of a deterministic canvas render a summary line, per-node sublabels/hover
4
+ * descriptions, edge labels, footer notes, layout hints, and a cross-workflow
5
+ * tie. Every value is a BOUNDED plain string (the limits below are hard caps
6
+ * that keep the SVG layout from breaking); the renderer (core/canvas-svg.ts,
7
+ * core/canvas-body.ts) decides where each field goes.
9
8
  *
10
- * Layout hints are the one structural concession: named groups (rendered as
11
- * subtle background bands) and per-layer ordering. The renderer applies a
12
- * hint only when every node id it references actually exists in the graph
13
- * (see canvas-svg.ts) ids are validated at render time, not here, because
14
- * an enrichment can outlive the graph it was written against (the "stale"
15
- * cache state).
9
+ * The enrichment is produced DETERMINISTICALLY, in-process, from the extracted
10
+ * graph see core/canvas-derive.ts. There is no LLM, no user token, no file
11
+ * write, and no cache: it is recomputed from the current sources on every
12
+ * render, so it can never go stale. This module is now just the shared shape +
13
+ * limits both the producer (canvas-derive.ts) and the consumer (canvas-svg.ts,
14
+ * canvas-body.ts) agree on.
15
+ *
16
+ * Layout hints are the one structural field: named groups (rendered as subtle
17
+ * background bands) and per-layer ordering. The renderer applies a hint only
18
+ * when every node id it references actually exists in the graph (see
19
+ * canvas-svg.ts) — ids are validated at render time.
16
20
  */
17
- import * as fs from "node:fs/promises";
18
- import * as path from "node:path";
19
- import { z } from "zod";
20
21
  export const ENRICHMENT_LIMITS = {
21
22
  summary: 160,
22
23
  sublabel: 48,
@@ -27,166 +28,4 @@ export const ENRICHMENT_LIMITS = {
27
28
  groupLabel: 48,
28
29
  crossWorkflow: 160,
29
30
  };
30
- const bounded = (max) => z.string().max(max);
31
- export const canvasEnrichmentSchema = z
32
- .object({
33
- /** One-liner under the panel header. */
34
- summary: bounded(ENRICHMENT_LIMITS.summary).optional(),
35
- /** Per-node annotations, keyed by node id. */
36
- nodeDetails: z
37
- .record(z
38
- .object({
39
- /** Second text line inside the node box. */
40
- sublabel: bounded(ENRICHMENT_LIMITS.sublabel).optional(),
41
- /** Hover tooltip (SVG <title>) — room for a full sentence. */
42
- description: bounded(ENRICHMENT_LIMITS.description).optional(),
43
- })
44
- .strip())
45
- .optional(),
46
- /** Edge annotations (intent/condition names), keyed `"<from>-><to>"`. */
47
- edgeLabels: z.record(bounded(ENRICHMENT_LIMITS.edgeLabel)).optional(),
48
- /** Footer facts worth knowing that don't fit the diagram itself. */
49
- notes: z.array(bounded(ENRICHMENT_LIMITS.note)).max(ENRICHMENT_LIMITS.noteCount).optional(),
50
- layoutHints: z
51
- .object({
52
- /** Named clusters rendered as background bands behind member nodes. */
53
- groups: z
54
- .array(z
55
- .object({
56
- label: bounded(ENRICHMENT_LIMITS.groupLabel),
57
- nodeIds: z.array(z.string()).min(1),
58
- })
59
- .strip())
60
- .optional(),
61
- /** Preferred left-to-right node order per layout layer, keyed by the
62
- * layer index as a string. Reorders WITHIN the computed layer only —
63
- * it can never move a node between layers. */
64
- laneOrder: z.record(z.array(z.string()).min(1)).optional(),
65
- })
66
- .strip()
67
- .optional(),
68
- /** How this workflow ties into the workspace's other workflows. */
69
- crossWorkflow: bounded(ENRICHMENT_LIMITS.crossWorkflow).optional(),
70
- })
71
- .strip();
72
- /**
73
- * Validates a candidate enrichment object. Returns null on ANY schema
74
- * violation (oversize string, wrong shape, too many notes) — partial
75
- * salvage is deliberately not attempted, so the contract stays a hard line
76
- * the prompt can state truthfully: "invalid output is thrown away whole."
77
- */
78
- export function parseCanvasEnrichment(value) {
79
- const parsed = canvasEnrichmentSchema.safeParse(value);
80
- return parsed.success ? parsed.data : null;
81
- }
82
- function clampString(value, max) {
83
- if (typeof value !== "string" || value.length <= max)
84
- return value;
85
- return `${value.slice(0, max - 1)}…`;
86
- }
87
- function isRecord(value) {
88
- return typeof value === "object" && value !== null && !Array.isArray(value);
89
- }
90
- /** Removes null/undefined-valued properties (models write `"field": null`
91
- * to mean "omitted"; the schema means it as `undefined`). Shallow — called
92
- * per level below where object shapes are known. */
93
- function dropNulls(record) {
94
- return Object.fromEntries(Object.entries(record).filter(([, v]) => v != null));
95
- }
96
- /**
97
- * Deterministic repair of the two ways an otherwise-good answer most often
98
- * misses the contract, applied BEFORE strict validation:
99
- * - `null` where the schema means "omit the field"
100
- * - strings a few words over their cap (measured live: sonnet writes
101
- * excellent content but doesn't count characters — a single 160-char note
102
- * against the 140 cap discarded 3 of 4 real enrichments whole), truncated
103
- * to the cap with an ellipsis; extra notes beyond the count cap dropped
104
- *
105
- * The bound the caps exist for — the AI can never blow up the layout with
106
- * unbounded text — is still enforced, just deterministically here instead
107
- * of by rejection. Everything else (wrong shapes, wrong types, unknown
108
- * structure) still fails `parseCanvasEnrichment` and discards the
109
- * enrichment whole.
110
- */
111
- export function normalizeCanvasEnrichmentCandidate(value) {
112
- if (!isRecord(value))
113
- return value;
114
- const L = ENRICHMENT_LIMITS;
115
- const out = { ...value };
116
- out.summary = clampString(out.summary, L.summary);
117
- out.crossWorkflow = clampString(out.crossWorkflow, L.crossWorkflow);
118
- if (isRecord(out.nodeDetails)) {
119
- out.nodeDetails = Object.fromEntries(Object.entries(out.nodeDetails).map(([id, details]) => {
120
- if (!isRecord(details))
121
- return [id, details];
122
- return [
123
- id,
124
- dropNulls({
125
- ...details,
126
- sublabel: clampString(details.sublabel, L.sublabel),
127
- description: clampString(details.description, L.description),
128
- }),
129
- ];
130
- }));
131
- }
132
- if (isRecord(out.edgeLabels)) {
133
- out.edgeLabels = Object.fromEntries(Object.entries(out.edgeLabels).map(([key, label]) => [key, clampString(label, L.edgeLabel)]));
134
- }
135
- if (Array.isArray(out.notes)) {
136
- out.notes = out.notes.slice(0, L.noteCount).map((note) => clampString(note, L.note));
137
- }
138
- if (isRecord(out.layoutHints)) {
139
- const hints = dropNulls({ ...out.layoutHints });
140
- if (Array.isArray(hints.groups)) {
141
- hints.groups = hints.groups.map((group) => isRecord(group) ? dropNulls({ ...group, label: clampString(group.label, L.groupLabel) }) : group);
142
- }
143
- out.layoutHints = hints;
144
- }
145
- return dropNulls(out);
146
- }
147
- /** Envelope validation is deliberately shallow for `graph` (it's our own
148
- * writer's serialization, not AI output) and strict for `enrichment` (it IS
149
- * AI output — re-validated on every read, so a hand-edited or corrupted
150
- * cache file can never smuggle unbounded strings into a render). */
151
- const cacheEntrySchema = z.object({
152
- graph: z.object({
153
- manifestName: z.string(),
154
- entry: z.string(),
155
- nodes: z.array(z.record(z.unknown())),
156
- edges: z.array(z.record(z.unknown())),
157
- warnings: z.array(z.string()),
158
- }),
159
- enrichment: canvasEnrichmentSchema,
160
- sourceFingerprint: z.string(),
161
- enrichedAt: z.string(),
162
- });
163
- /** Reads + validates one enrichment cache file. Null for missing, unparsable
164
- * or schema-invalid content — a bad cache degrades to "no enrichment". */
165
- export async function readEnrichmentCacheFile(filePath) {
166
- let raw;
167
- try {
168
- raw = await fs.readFile(filePath, "utf8");
169
- }
170
- catch {
171
- return null;
172
- }
173
- try {
174
- const parsed = cacheEntrySchema.safeParse(JSON.parse(raw));
175
- // The shallow node/edge validation above means this cast, not a full
176
- // structural proof — see the schema's own comment for why that's enough.
177
- return parsed.success ? parsed.data : null;
178
- }
179
- catch {
180
- return null;
181
- }
182
- }
183
- export async function writeEnrichmentCacheFile(filePath, entry) {
184
- await fs.mkdir(path.dirname(filePath), { recursive: true });
185
- await fs.writeFile(filePath, JSON.stringify(entry, null, 2), "utf8");
186
- }
187
- /** Deletes one enrichment cache file (the visualize macro's force refresh).
188
- * Missing file is fine — the goal state is "no cache". */
189
- export async function removeEnrichmentCacheFile(filePath) {
190
- await fs.rm(filePath, { force: true });
191
- }
192
31
  //# sourceMappingURL=canvas-enrichment.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"canvas-enrichment.js","sourceRoot":"","sources":["../../src/core/canvas-enrichment.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"canvas-enrichment.js","sourceRoot":"","sources":["../../src/core/canvas-enrichment.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,OAAO,EAAE,GAAG;IACZ,QAAQ,EAAE,EAAE;IACZ,WAAW,EAAE,GAAG;IAChB,SAAS,EAAE,EAAE;IACb,SAAS,EAAE,CAAC;IACZ,IAAI,EAAE,GAAG;IACT,UAAU,EAAE,EAAE;IACd,aAAa,EAAE,GAAG;CACV,CAAC"}
@@ -10,7 +10,7 @@
10
10
  * instead of crashing or silently falling back to an LLM.
11
11
  */
12
12
  import type { AgentManifest } from "@sapiom/agent";
13
- import { type DetectedLaunch } from "./canvas-interconnections.js";
13
+ import { type DetectedLaunch, type DetectedCapability } from "./canvas-interconnections.js";
14
14
  export type CanvasNodeKind = "entry" | "step" | "pause" | "terminal-success" | "terminal-warn" | "launched-workflow";
15
15
  export type CanvasEdgeKind = "sequential" | "branching" | "cross" | "launch";
16
16
  export interface CanvasNode {
@@ -18,6 +18,14 @@ export interface CanvasNode {
18
18
  kind: CanvasNodeKind;
19
19
  label: string;
20
20
  sublabel?: string;
21
+ /** Human-authored step description from the manifest (Option A); "" when none. */
22
+ description?: string;
23
+ /** The step's declared input contract (JSON Schema) from the manifest. */
24
+ inputSchema?: Record<string, unknown> | null;
25
+ /** Author-declared Sapiom capabilities the step calls. */
26
+ capabilities?: readonly string[];
27
+ /** The step's declared dispatch timeout (ms); null when unset. */
28
+ timeoutMs?: number | null;
21
29
  }
22
30
  export interface CanvasEdge {
23
31
  from: string;
@@ -30,6 +38,8 @@ export interface CanvasGraph {
30
38
  /** The manifest's own name — used both as a display title fallback and as
31
39
  * the match key for cross-workflow interconnection detection. */
32
40
  manifestName: string;
41
+ /** Human-authored workflow description from the manifest (Option A); "" when none. */
42
+ description?: string;
33
43
  entry: string;
34
44
  nodes: CanvasNode[];
35
45
  edges: CanvasEdge[];
@@ -47,6 +57,31 @@ export interface ExtractionFailure {
47
57
  reason: string;
48
58
  }
49
59
  export type ExtractionResult = ExtractionSuccess | ExtractionFailure;
60
+ /**
61
+ * The precedence table above, over nothing but a step's declared transition
62
+ * kinds — so a caller that has transitions from somewhere OTHER than a local
63
+ * `AgentManifest` classifies identically.
64
+ *
65
+ * Exported because the Studio's template preview projects the SAME graph from
66
+ * core's relayed `DefinitionTransitionDto[]` (see `core/template-catalog.ts`).
67
+ * That preview claims parity with the canvas, so it must not re-derive this:
68
+ * a second copy of the rule is a second answer to "what kind of node is this",
69
+ * and the two surfaces disagreeing is the exact class of bug the template work
70
+ * set out to remove. Collapsing the four kinds into a single `terminal` boolean
71
+ * (as the first cut of that preview did) renders a fail-only sink as a green
72
+ * success exit and a `continue`-plus-`terminate` gate as a terminal.
73
+ */
74
+ export declare function classifyStepKind(input: {
75
+ name: string;
76
+ entry: string;
77
+ transitions: ReadonlyArray<{
78
+ kind: string;
79
+ signal?: string | null;
80
+ }>;
81
+ }): {
82
+ kind: CanvasNodeKind;
83
+ sublabel: string;
84
+ };
50
85
  /** Reshapes a validated `AgentManifest` into the render-ready graph model. */
51
86
  export declare function graphFromManifest(manifest: AgentManifest, warnings: string[]): CanvasGraph;
52
87
  /**
@@ -58,6 +93,10 @@ export declare function graphFromManifest(manifest: AgentManifest, warnings: str
58
93
  * already shows those steps. Pure — returns a new graph.
59
94
  */
60
95
  export declare function mergeLaunchesIntoGraph(graph: CanvasGraph, launches: readonly DetectedLaunch[]): CanvasGraph;
96
+ /** Fills each step node's `capabilities` from statically-detected
97
+ * `ctx.sapiom.*` calls, unless the manifest already declared them (authored
98
+ * capabilities win). Pure — returns a new graph. */
99
+ export declare function mergeCapabilitiesIntoGraph(graph: CanvasGraph, detected: readonly DetectedCapability[]): CanvasGraph;
61
100
  /**
62
101
  * Extracts a workflow's step graph from its project directory, with detected
63
102
  * cross-workflow launches merged in as dashed nodes. Never throws: any
@@ -1 +1 @@
1
- {"version":3,"file":"canvas-graph.d.ts","sourceRoot":"","sources":["../../src/core/canvas-graph.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,aAAa,EAAqB,MAAM,eAAe,CAAC;AAEtE,OAAO,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"}
1
+ {"version":3,"file":"canvas-graph.d.ts","sourceRoot":"","sources":["../../src/core/canvas-graph.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,aAAa,EAAqB,MAAM,eAAe,CAAC;AAEtE,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACxB,MAAM,8BAA8B,CAAC;AAEtC,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,kBAAkB,GAAG,eAAe,GAAG,mBAAmB,CAAC;AACrH,MAAM,MAAM,cAAc,GAAG,YAAY,GAAG,WAAW,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE7E,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,cAAc,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kFAAkF;IAClF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0EAA0E;IAC1E,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC7C,0DAA0D;IAC1D,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,cAAc,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,oDAAoD;AACpD,MAAM,WAAW,WAAW;IAC1B;sEACkE;IAClE,YAAY,EAAE,MAAM,CAAC;IACrB,sFAAsF;IACtF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB;mEAC+D;IAC/D,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,IAAI,CAAC;IACT,KAAK,EAAE,WAAW,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,KAAK,CAAC;IACV,mFAAmF;IACnF,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,gBAAgB,GAAG,iBAAiB,GAAG,iBAAiB,CAAC;AA2BrE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,aAAa,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;CACtE,GAAG;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAiB7C;AAmBD,8EAA8E;AAC9E,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,WAAW,CAyB1F;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,cAAc,EAAE,GAAG,WAAW,CAqB3G;AAED;;qDAEqD;AACrD,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,SAAS,kBAAkB,EAAE,GACtC,WAAW,CAiBb;AAED;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAUvF"}
@@ -1,5 +1,5 @@
1
1
  import { runManifestCheck } from "./canvas-manifest-check.js";
2
- import { detectWorkflowLaunches } from "./canvas-interconnections.js";
2
+ import { scanWorkflowSources, } from "./canvas-interconnections.js";
3
3
  /**
4
4
  * Classifies a step for node styling. Priority: the entry step always reads
5
5
  * as "entry" (the diagram's obvious starting point) even if it also happens
@@ -18,10 +18,28 @@ import { detectWorkflowLaunches } from "./canvas-interconnections.js";
18
18
  * prefers an enrichment-supplied sublabel over this default when present.
19
19
  */
20
20
  function classifyNode(name, entry, step) {
21
- 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");
21
+ return classifyStepKind({ name, entry, transitions: step.transitions });
22
+ }
23
+ /**
24
+ * The precedence table above, over nothing but a step's declared transition
25
+ * kinds — so a caller that has transitions from somewhere OTHER than a local
26
+ * `AgentManifest` classifies identically.
27
+ *
28
+ * Exported because the Studio's template preview projects the SAME graph from
29
+ * core's relayed `DefinitionTransitionDto[]` (see `core/template-catalog.ts`).
30
+ * That preview claims parity with the canvas, so it must not re-derive this:
31
+ * a second copy of the rule is a second answer to "what kind of node is this",
32
+ * and the two surfaces disagreeing is the exact class of bug the template work
33
+ * set out to remove. Collapsing the four kinds into a single `terminal` boolean
34
+ * (as the first cut of that preview did) renders a fail-only sink as a green
35
+ * success exit and a `continue`-plus-`terminate` gate as a terminal.
36
+ */
37
+ export function classifyStepKind(input) {
38
+ const { name, entry, transitions } = input;
39
+ const continueTargets = transitions.filter((t) => t.kind === "continue");
40
+ const pause = transitions.find((t) => t.kind === "pause");
41
+ const hasTerminate = transitions.some((t) => t.kind === "terminate");
42
+ const hasFail = transitions.some((t) => t.kind === "fail");
25
43
  if (name === entry)
26
44
  return { kind: "entry", sublabel: "entry" };
27
45
  if (pause)
@@ -55,10 +73,26 @@ function edgesForStep(name, step) {
55
73
  export function graphFromManifest(manifest, warnings) {
56
74
  const nodes = Object.entries(manifest.steps).map(([name, step]) => {
57
75
  const { kind, sublabel } = classifyNode(name, manifest.entry, step);
58
- return { id: name, kind, label: name, sublabel };
76
+ return {
77
+ id: name,
78
+ kind,
79
+ label: name,
80
+ sublabel,
81
+ description: step.description ?? "",
82
+ inputSchema: step.inputSchema ?? null,
83
+ capabilities: step.capabilities ?? [],
84
+ timeoutMs: step.timeoutMs ?? null,
85
+ };
59
86
  });
60
87
  const edges = Object.entries(manifest.steps).flatMap(([name, step]) => edgesForStep(name, step));
61
- return { manifestName: manifest.name, entry: manifest.entry, nodes, edges, warnings };
88
+ return {
89
+ manifestName: manifest.name,
90
+ description: manifest.description ?? "",
91
+ entry: manifest.entry,
92
+ nodes,
93
+ edges,
94
+ warnings,
95
+ };
62
96
  }
63
97
  /**
64
98
  * Merges heuristically detected cross-workflow launches into the workflow's
@@ -91,6 +125,30 @@ export function mergeLaunchesIntoGraph(graph, launches) {
91
125
  }
92
126
  return { ...graph, nodes, edges };
93
127
  }
128
+ /** Fills each step node's `capabilities` from statically-detected
129
+ * `ctx.sapiom.*` calls, unless the manifest already declared them (authored
130
+ * capabilities win). Pure — returns a new graph. */
131
+ export function mergeCapabilitiesIntoGraph(graph, detected) {
132
+ if (detected.length === 0)
133
+ return graph;
134
+ const byStep = new Map();
135
+ for (const d of detected) {
136
+ if (!d.fromStepId)
137
+ continue;
138
+ const set = byStep.get(d.fromStepId) ?? new Set();
139
+ set.add(d.capability);
140
+ byStep.set(d.fromStepId, set);
141
+ }
142
+ return {
143
+ ...graph,
144
+ nodes: graph.nodes.map((n) => {
145
+ if ((n.capabilities?.length ?? 0) > 0)
146
+ return n; // authored capabilities win
147
+ const caps = byStep.get(n.id);
148
+ return caps ? { ...n, capabilities: [...caps].sort() } : n;
149
+ }),
150
+ };
151
+ }
94
152
  /**
95
153
  * Extracts a workflow's step graph from its project directory, with detected
96
154
  * cross-workflow launches merged in as dashed nodes. Never throws: any
@@ -105,7 +163,11 @@ export async function extractWorkflowGraph(sourceDir) {
105
163
  if (!result.ok)
106
164
  return { ok: false, reason: result.reason };
107
165
  const graph = graphFromManifest(result.manifest, result.warnings);
108
- const launches = await detectWorkflowLaunches(sourceDir, new Set(graph.nodes.map((n) => n.id)));
109
- return { ok: true, graph: mergeLaunchesIntoGraph(graph, launches) };
166
+ const stepIds = new Set(graph.nodes.map((n) => n.id));
167
+ // One walk over the sources yields both — halves the I/O on the auto-render
168
+ // hot path (this runs on every workflow-source save).
169
+ const { launches, capabilities } = await scanWorkflowSources(sourceDir, stepIds);
170
+ const withLaunches = mergeLaunchesIntoGraph(graph, launches);
171
+ return { ok: true, graph: mergeCapabilitiesIntoGraph(withLaunches, capabilities) };
110
172
  }
111
173
  //# sourceMappingURL=canvas-graph.js.map