@work-graph/cli 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 (194) hide show
  1. package/README.md +31 -0
  2. package/bin/work-graph.mjs +238 -0
  3. package/package.json +38 -0
  4. package/vendor/packages/design-tokens/generated/gripe-dark-default.css +67 -0
  5. package/vendor/packages/design-tokens/generated/marketplace-default.css +67 -0
  6. package/vendor/packages/design-tokens/generated/workgraph-dark.css +67 -0
  7. package/vendor/packages/workgraph-mcp/README.md +28 -0
  8. package/vendor/packages/workgraph-mcp/bin/workgraph-mcp.mjs +21 -0
  9. package/vendor/packages/workgraph-mcp/package.json +37 -0
  10. package/vendor/packages/workgraph-mcp/src/handlers.mjs +761 -0
  11. package/vendor/packages/workgraph-mcp/src/index.mjs +638 -0
  12. package/vendor/packages/workgraph-mcp/src/prompts.mjs +162 -0
  13. package/vendor/public/assets/workgraph-logo.svg +11 -0
  14. package/vendor/public/fonts/GraphikLCG/GraphikLCG-Medium.woff2 +0 -0
  15. package/vendor/public/fonts/GraphikLCG/GraphikLCG-Regular.woff2 +0 -0
  16. package/vendor/public/fonts/GraphikLCG/GraphikLCG-Semibold.woff2 +0 -0
  17. package/vendor/public/fonts/GraphikLCG/stylesheet.css +25 -0
  18. package/vendor/public/graph-canvas-lit-flow.css +154 -0
  19. package/vendor/public/graph-canvas-lit-flow.css.map +7 -0
  20. package/vendor/public/graph-canvas-lit-flow.js +8530 -0
  21. package/vendor/public/graph-canvas-lit-flow.js.map +7 -0
  22. package/vendor/src/agentBehaviorRulesAudit.mjs +168 -0
  23. package/vendor/src/agentBehaviorRulesBundle.mjs +144 -0
  24. package/vendor/src/agentRunApi.mjs +136 -0
  25. package/vendor/src/agentToolLoopGuard.mjs +88 -0
  26. package/vendor/src/agentWorkerClaudeProvider.mjs +288 -0
  27. package/vendor/src/agentWorkerCursorSdkProvider.mjs +156 -0
  28. package/vendor/src/agentWorkerLiveLoop.mjs +455 -0
  29. package/vendor/src/agentWorkerLocalCliProvider.mjs +217 -0
  30. package/vendor/src/agentWorkerLocalRunner.mjs +246 -0
  31. package/vendor/src/agentWorkerOpenAiProvider.mjs +459 -0
  32. package/vendor/src/analyticsPanelProjection.mjs +212 -0
  33. package/vendor/src/analyticsRecordStore.mjs +165 -0
  34. package/vendor/src/analyticsRecordWorkItems.mjs +104 -0
  35. package/vendor/src/architectureL1Canon.mjs +419 -0
  36. package/vendor/src/architectureLayout.mjs +229 -0
  37. package/vendor/src/architectureSnapshot.mjs +490 -0
  38. package/vendor/src/architectureViewsProjection.mjs +116 -0
  39. package/vendor/src/atomInspector.mjs +253 -0
  40. package/vendor/src/atomInspectorApi.mjs +130 -0
  41. package/vendor/src/auditGapMatrixRefresh.mjs +121 -0
  42. package/vendor/src/backlogSchemaLint.mjs +176 -0
  43. package/vendor/src/blockedOnebaseGoPreflightEval.mjs +100 -0
  44. package/vendor/src/bracketIrTraceSignal.mjs +93 -0
  45. package/vendor/src/bvcAtomParser.mjs +210 -0
  46. package/vendor/src/bvcDialectRegistry.mjs +86 -0
  47. package/vendor/src/bvcFileFormat.mjs +218 -0
  48. package/vendor/src/bvcFormatCli.mjs +55 -0
  49. package/vendor/src/bvcLintCli.mjs +48 -0
  50. package/vendor/src/bvcNewWritePolicy.mjs +70 -0
  51. package/vendor/src/charterPreflightPromoteGate.mjs +194 -0
  52. package/vendor/src/claimNoEligibleEval.mjs +205 -0
  53. package/vendor/src/closingAnalysisSuggest.mjs +59 -0
  54. package/vendor/src/codeGapAnalyzer.mjs +308 -0
  55. package/vendor/src/codeGapBacklogFeeder.mjs +82 -0
  56. package/vendor/src/codeGapDraftIntakeApi.mjs +307 -0
  57. package/vendor/src/codeGapOperatorProjection.mjs +60 -0
  58. package/vendor/src/codeSyntaxHighlight.mjs +123 -0
  59. package/vendor/src/codegenEvidence.mjs +187 -0
  60. package/vendor/src/compilerRoundTripCli.mjs +164 -0
  61. package/vendor/src/dagreGraphLayout.mjs +78 -0
  62. package/vendor/src/draftIntakePromotionRules.mjs +205 -0
  63. package/vendor/src/epicWorkScope.mjs +85 -0
  64. package/vendor/src/evalLiveLlmEnv.mjs +63 -0
  65. package/vendor/src/evidenceReadModel.mjs +167 -0
  66. package/vendor/src/gfsOverlayProjectPassport.mjs +235 -0
  67. package/vendor/src/globalStepPathToBvcReferences.mjs +196 -0
  68. package/vendor/src/goldenPath.mjs +69 -0
  69. package/vendor/src/graphCanvasLayout.mjs +464 -0
  70. package/vendor/src/graphCanvasLitFlow/client/graphCanvasMinimap.ts +261 -0
  71. package/vendor/src/graphCanvasLitFlow/client/graphCanvasSvgEdges.ts +259 -0
  72. package/vendor/src/graphCanvasLitFlow/client/graphCanvasTheme.css +152 -0
  73. package/vendor/src/graphCanvasLitFlow/client/graphCardNode.ts +328 -0
  74. package/vendor/src/graphCanvasLitFlow/client/mountGraphCanvasLitFlow.ts +322 -0
  75. package/vendor/src/graphCanvasLitFlow/graphCanvasEdgeLabels.mjs +58 -0
  76. package/vendor/src/graphCanvasLitFlow/graphCanvasEdgeRouter.mjs +142 -0
  77. package/vendor/src/graphCanvasLitFlow/graphCanvasLayoutProfile.mjs +32 -0
  78. package/vendor/src/graphCanvasLitFlow/graphCanvasNodeMetrics.mjs +45 -0
  79. package/vendor/src/graphCanvasLitFlow/graphCanvasProjection.mjs +115 -0
  80. package/vendor/src/graphCanvasLitFlow/graphCanvasProjectionToFlow.mjs +133 -0
  81. package/vendor/src/graphCanvasLitFlow/graphCanvasTraversal.mjs +77 -0
  82. package/vendor/src/graphCanvasLitFlow/layoutIntentRoadmapWorkStack.mjs +73 -0
  83. package/vendor/src/graphCanvasLitFlow/resolveGraphCanvasOverlaps.mjs +77 -0
  84. package/vendor/src/graphRagContextSlice.mjs +461 -0
  85. package/vendor/src/gvmVerifyWorkerGate.mjs +95 -0
  86. package/vendor/src/homeSnapshotApi.mjs +131 -0
  87. package/vendor/src/homeSnapshotProjection.mjs +275 -0
  88. package/vendor/src/inboxEventStream.mjs +140 -0
  89. package/vendor/src/intentComposerApi.mjs +245 -0
  90. package/vendor/src/intentGraphGbcSliceBoundary.mjs +258 -0
  91. package/vendor/src/intentGraphProjection.mjs +208 -0
  92. package/vendor/src/intentHierarchy.mjs +241 -0
  93. package/vendor/src/intentNodeLint.mjs +107 -0
  94. package/vendor/src/intentNodeRuntime.mjs +185 -0
  95. package/vendor/src/intentRoadmapCanvas.mjs +393 -0
  96. package/vendor/src/intentRoadmapEpicProjection.mjs +122 -0
  97. package/vendor/src/intentRoadmapMermaid.mjs +165 -0
  98. package/vendor/src/intentRoadmapProjection.mjs +85 -0
  99. package/vendor/src/intentTreeLint.mjs +114 -0
  100. package/vendor/src/intentTreeMigration.mjs +150 -0
  101. package/vendor/src/intentTreeWorkItems.mjs +227 -0
  102. package/vendor/src/kanbanBoardProjection.mjs +58 -0
  103. package/vendor/src/languageAdapterRegistry.mjs +180 -0
  104. package/vendor/src/languageAdapters/goAdapter.mjs +62 -0
  105. package/vendor/src/languageAdapters/jsTsAdapter.mjs +60 -0
  106. package/vendor/src/languageAdapters/jsonYamlAdapter.mjs +103 -0
  107. package/vendor/src/languageAdapters/onebaseOsAdapter.mjs +55 -0
  108. package/vendor/src/languageAdapters/plaintextAdapter.mjs +36 -0
  109. package/vendor/src/languageAdapters/shared.mjs +68 -0
  110. package/vendor/src/languageAdapters/stepAdapter.mjs +81 -0
  111. package/vendor/src/lintPlanWorkAlignment.mjs +136 -0
  112. package/vendor/src/loopHintRepeatToolEval.mjs +153 -0
  113. package/vendor/src/lowcodeScaffoldCli.mjs +386 -0
  114. package/vendor/src/markdownDocumentRender.mjs +208 -0
  115. package/vendor/src/memoryPanelProjection.mjs +116 -0
  116. package/vendor/src/memoryRecordWriter.mjs +243 -0
  117. package/vendor/src/memoryWorkerSlice.mjs +238 -0
  118. package/vendor/src/migrateStepToBvc.mjs +133 -0
  119. package/vendor/src/missionControlServerHandlers.mjs +195 -0
  120. package/vendor/src/missionControlUiClient.mjs +278 -0
  121. package/vendor/src/onebaseCliCapabilityProbe.mjs +107 -0
  122. package/vendor/src/onebaseCliRunner.mjs +145 -0
  123. package/vendor/src/onebaseGrossProfitStaticVerify.mjs +98 -0
  124. package/vendor/src/onebaseParityEvidenceSync.mjs +88 -0
  125. package/vendor/src/onebasePvrgGraphNodes.mjs +257 -0
  126. package/vendor/src/onebaseRestEvidenceAdapter.mjs +216 -0
  127. package/vendor/src/onebaseVectorDslCodegenReadiness.mjs +137 -0
  128. package/vendor/src/onebaseWorkItemTemplate.mjs +154 -0
  129. package/vendor/src/onebaseWorkerTools.mjs +586 -0
  130. package/vendor/src/operatorShellProjection.mjs +102 -0
  131. package/vendor/src/pipelineProseRender.mjs +180 -0
  132. package/vendor/src/pipelineStageLint.mjs +118 -0
  133. package/vendor/src/promptRulesEditorApi.mjs +174 -0
  134. package/vendor/src/promptRulesProjection.mjs +134 -0
  135. package/vendor/src/pvrg/bladeAdapter.mjs +40 -0
  136. package/vendor/src/pvrgTaskScope.mjs +152 -0
  137. package/vendor/src/releaseGateMatrix.mjs +188 -0
  138. package/vendor/src/schematicView.mjs +305 -0
  139. package/vendor/src/seedAnalyticsRecord.mjs +217 -0
  140. package/vendor/src/semanticSearchBm25.mjs +103 -0
  141. package/vendor/src/semanticSearchExcerpts.mjs +68 -0
  142. package/vendor/src/semanticSearchTfidfVector.mjs +86 -0
  143. package/vendor/src/semanticSearchWorkflow.mjs +366 -0
  144. package/vendor/src/stepAtomFormatter.mjs +413 -0
  145. package/vendor/src/stepGraphSlice.mjs +318 -0
  146. package/vendor/src/ui/atoms/badge.mjs +40 -0
  147. package/vendor/src/ui/atoms/badgeClient.mjs +32 -0
  148. package/vendor/src/ui/atoms/button.mjs +114 -0
  149. package/vendor/src/ui/atoms/buttonClient.mjs +49 -0
  150. package/vendor/src/ui/atoms/icon.mjs +23 -0
  151. package/vendor/src/ui/atoms/input.mjs +38 -0
  152. package/vendor/src/ui/atoms/modal.mjs +44 -0
  153. package/vendor/src/ui/atoms/select.mjs +98 -0
  154. package/vendor/src/ui/backlogShellButtons.mjs +238 -0
  155. package/vendor/src/ui/htmlEscape.mjs +11 -0
  156. package/vendor/src/ui/molecules/rating.mjs +48 -0
  157. package/vendor/src/ui/molecules/tabs.mjs +70 -0
  158. package/vendor/src/ui/organisms/modal.mjs +1 -0
  159. package/vendor/src/ui/pages/uiKitPage.mjs +147 -0
  160. package/vendor/src/ui/workItemStatusTone.mjs +36 -0
  161. package/vendor/src/unifiedLinkageProjection.mjs +264 -0
  162. package/vendor/src/verificationLoop.mjs +206 -0
  163. package/vendor/src/workGraphBacklogPersist.mjs +234 -0
  164. package/vendor/src/workGraphBacklogUiServer.mjs +9192 -0
  165. package/vendor/src/workGraphBoundedTargetFileRead.mjs +178 -0
  166. package/vendor/src/workGraphCycleSlice.mjs +184 -0
  167. package/vendor/src/workGraphDaemonTick.mjs +307 -0
  168. package/vendor/src/workGraphDaemonWatch.mjs +157 -0
  169. package/vendor/src/workGraphEngineRoot.mjs +136 -0
  170. package/vendor/src/workGraphInstallLayout.mjs +65 -0
  171. package/vendor/src/workGraphLlmUsefulnessEval.mjs +611 -0
  172. package/vendor/src/workGraphPhasePromoteReadyQueue.mjs +159 -0
  173. package/vendor/src/workGraphProjectHost.mjs +149 -0
  174. package/vendor/src/workGraphProjectInit.mjs +392 -0
  175. package/vendor/src/workGraphPromoteReadyApi.mjs +115 -0
  176. package/vendor/src/workGraphRecoveryPolicy.mjs +124 -0
  177. package/vendor/src/workGraphRunnerQueueProjection.mjs +187 -0
  178. package/vendor/src/workGraphRuntime.mjs +1008 -0
  179. package/vendor/src/workGraphToolSurfaceAudit.mjs +372 -0
  180. package/vendor/src/workGraphToolTransportRuntime.mjs +195 -0
  181. package/vendor/src/workGraphWorkerProvider.mjs +600 -0
  182. package/vendor/src/workItemBvcQuality.mjs +262 -0
  183. package/vendor/src/workItemCreateAnalysis.mjs +157 -0
  184. package/vendor/src/workItemDecisionPipeline.mjs +278 -0
  185. package/vendor/src/workItemEpicCascade.mjs +176 -0
  186. package/vendor/src/workItemExecutionGate.mjs +78 -0
  187. package/vendor/src/workItemHierarchy.mjs +226 -0
  188. package/vendor/src/workItemProseLint.mjs +133 -0
  189. package/vendor/src/workItemTextRusify.mjs +794 -0
  190. package/vendor/src/workItemTraceEnvelope.mjs +158 -0
  191. package/vendor/src/workItemUiReferences.mjs +272 -0
  192. package/vendor/src/workflowEpicGrouping.mjs +67 -0
  193. package/vendor/src/workflowTreeProjection.mjs +53 -0
  194. package/vendor/src/workspaceRegistry.mjs +150 -0
@@ -0,0 +1,261 @@
1
+ import type { FlowCanvas } from 'lit-flow';
2
+
3
+ type FlowNodeState = {
4
+ id: string;
5
+ position: { x: number; y: number };
6
+ width?: number;
7
+ height?: number;
8
+ measured?: { width?: number; height?: number };
9
+ };
10
+
11
+ type FlowInstanceLike = {
12
+ container: HTMLElement | null;
13
+ getState: () => { nodes: FlowNodeState[]; viewport: { x: number; y: number; zoom: number } };
14
+ getViewport: () => { x: number; y: number; zoom: number };
15
+ setViewport: (viewport: { x: number; y: number; zoom: number }) => void;
16
+ subscribe: (callback: () => void) => () => void;
17
+ };
18
+
19
+ type GraphBounds = {
20
+ minX: number;
21
+ minY: number;
22
+ width: number;
23
+ height: number;
24
+ };
25
+
26
+ type MinimapTransform = {
27
+ bounds: GraphBounds;
28
+ scale: number;
29
+ offsetX: number;
30
+ offsetY: number;
31
+ };
32
+
33
+ export type GraphCanvasMinimapOptions = {
34
+ width?: number;
35
+ height?: number;
36
+ theme?: 'dark' | 'light';
37
+ };
38
+
39
+ const minimapCleanups = new WeakMap<HTMLElement, () => void>();
40
+
41
+ function nodeSize(node: FlowNodeState) {
42
+ return {
43
+ width: node.measured?.width ?? node.width ?? 240,
44
+ height: node.measured?.height ?? node.height ?? 96,
45
+ };
46
+ }
47
+
48
+ function computeGraphBounds(nodes: FlowNodeState[]): GraphBounds | null {
49
+ if (nodes.length === 0) {
50
+ return null;
51
+ }
52
+
53
+ let minX = Infinity;
54
+ let minY = Infinity;
55
+ let maxX = -Infinity;
56
+ let maxY = -Infinity;
57
+
58
+ for (const node of nodes) {
59
+ const { width, height } = nodeSize(node);
60
+ minX = Math.min(minX, node.position.x);
61
+ minY = Math.min(minY, node.position.y);
62
+ maxX = Math.max(maxX, node.position.x + width);
63
+ maxY = Math.max(maxY, node.position.y + height);
64
+ }
65
+
66
+ const pad = 28;
67
+ return {
68
+ minX: minX - pad,
69
+ minY: minY - pad,
70
+ width: Math.max(1, maxX - minX + pad * 2),
71
+ height: Math.max(1, maxY - minY + pad * 2),
72
+ };
73
+ }
74
+
75
+ function buildMinimapTransform(bounds: GraphBounds, width: number, height: number): MinimapTransform {
76
+ const scale = Math.min(width / bounds.width, height / bounds.height);
77
+ const offsetX = (width - bounds.width * scale) / 2;
78
+ const offsetY = (height - bounds.height * scale) / 2;
79
+ return { bounds, scale, offsetX, offsetY };
80
+ }
81
+
82
+ function graphToMinimap(transform: MinimapTransform, x: number, y: number) {
83
+ return {
84
+ x: transform.offsetX + (x - transform.bounds.minX) * transform.scale,
85
+ y: transform.offsetY + (y - transform.bounds.minY) * transform.scale,
86
+ };
87
+ }
88
+
89
+ function minimapToGraph(transform: MinimapTransform, x: number, y: number) {
90
+ return {
91
+ x: transform.bounds.minX + (x - transform.offsetX) / transform.scale,
92
+ y: transform.bounds.minY + (y - transform.offsetY) / transform.scale,
93
+ };
94
+ }
95
+
96
+ function createSvgElement<K extends keyof SVGElementTagNameMap>(
97
+ tag: K,
98
+ attrs: Record<string, string> = {},
99
+ ) {
100
+ const element = document.createElementNS('http://www.w3.org/2000/svg', tag);
101
+ for (const [key, value] of Object.entries(attrs)) {
102
+ element.setAttribute(key, value);
103
+ }
104
+ return element;
105
+ }
106
+
107
+ export function mountGraphCanvasMinimap(
108
+ host: HTMLElement,
109
+ getCanvas: () => FlowCanvas | null,
110
+ options: GraphCanvasMinimapOptions = {},
111
+ ): () => void {
112
+ minimapCleanups.get(host)?.();
113
+
114
+ const width = options.width ?? 168;
115
+ const height = options.height ?? 108;
116
+ host.replaceChildren();
117
+ host.classList.add('graph-canvas-minimap');
118
+ host.dataset.theme = options.theme ?? 'light';
119
+ host.setAttribute('role', 'img');
120
+ host.setAttribute('aria-label', 'Graph overview');
121
+
122
+ const svg = createSvgElement('svg', {
123
+ width: String(width),
124
+ height: String(height),
125
+ viewBox: `0 0 ${width} ${height}`,
126
+ });
127
+ const nodesLayer = createSvgElement('g', { class: 'graph-canvas-minimap-nodes' });
128
+ const viewportLayer = createSvgElement('rect', {
129
+ class: 'graph-canvas-minimap-viewport',
130
+ 'pointer-events': 'none',
131
+ });
132
+ svg.appendChild(nodesLayer);
133
+ svg.appendChild(viewportLayer);
134
+ host.appendChild(svg);
135
+
136
+ let unsubscribe: (() => void) | null = null;
137
+ let rafId = 0;
138
+ let latestTransform: MinimapTransform | null = null;
139
+
140
+ const schedulePaint = () => {
141
+ window.cancelAnimationFrame(rafId);
142
+ rafId = window.requestAnimationFrame(paint);
143
+ };
144
+
145
+ const paint = () => {
146
+ const canvas = getCanvas();
147
+ const instance = canvas?.instance as FlowInstanceLike | undefined;
148
+ if (!instance) {
149
+ nodesLayer.replaceChildren();
150
+ viewportLayer.setAttribute('width', '0');
151
+ viewportLayer.setAttribute('height', '0');
152
+ return;
153
+ }
154
+
155
+ const { nodes } = instance.getState();
156
+ const bounds = computeGraphBounds(nodes);
157
+ if (!bounds) {
158
+ nodesLayer.replaceChildren();
159
+ viewportLayer.setAttribute('width', '0');
160
+ viewportLayer.setAttribute('height', '0');
161
+ return;
162
+ }
163
+
164
+ latestTransform = buildMinimapTransform(bounds, width, height);
165
+ nodesLayer.replaceChildren();
166
+
167
+ for (const node of nodes) {
168
+ const size = nodeSize(node);
169
+ const topLeft = graphToMinimap(latestTransform, node.position.x, node.position.y);
170
+ const rect = createSvgElement('rect', {
171
+ class: 'graph-canvas-minimap-node',
172
+ x: String(topLeft.x),
173
+ y: String(topLeft.y),
174
+ width: String(Math.max(2, size.width * latestTransform.scale)),
175
+ height: String(Math.max(2, size.height * latestTransform.scale)),
176
+ rx: '2',
177
+ });
178
+ nodesLayer.appendChild(rect);
179
+ }
180
+
181
+ const container = instance.container ?? canvas;
182
+ const viewport = instance.getViewport();
183
+ const zoom = viewport.zoom || 1;
184
+ const visibleX = -viewport.x / zoom;
185
+ const visibleY = -viewport.y / zoom;
186
+ const visibleWidth = container.clientWidth / zoom;
187
+ const visibleHeight = container.clientHeight / zoom;
188
+ const viewportTopLeft = graphToMinimap(latestTransform, visibleX, visibleY);
189
+ const viewportBottomRight = graphToMinimap(
190
+ latestTransform,
191
+ visibleX + visibleWidth,
192
+ visibleY + visibleHeight,
193
+ );
194
+
195
+ viewportLayer.setAttribute('x', String(viewportTopLeft.x));
196
+ viewportLayer.setAttribute('y', String(viewportTopLeft.y));
197
+ viewportLayer.setAttribute('width', String(Math.max(2, viewportBottomRight.x - viewportTopLeft.x)));
198
+ viewportLayer.setAttribute('height', String(Math.max(2, viewportBottomRight.y - viewportTopLeft.y)));
199
+ };
200
+
201
+ const bindInstance = () => {
202
+ unsubscribe?.();
203
+ unsubscribe = null;
204
+
205
+ const canvas = getCanvas();
206
+ const instance = canvas?.instance as FlowInstanceLike | undefined;
207
+ if (!instance?.subscribe) {
208
+ window.requestAnimationFrame(bindInstance);
209
+ return;
210
+ }
211
+
212
+ unsubscribe = instance.subscribe(schedulePaint);
213
+ schedulePaint();
214
+ };
215
+
216
+ const onPointerDown = (event: PointerEvent) => {
217
+ if (!latestTransform) {
218
+ return;
219
+ }
220
+ const canvas = getCanvas();
221
+ const instance = canvas?.instance as FlowInstanceLike | undefined;
222
+ if (!instance) {
223
+ return;
224
+ }
225
+
226
+ const rect = svg.getBoundingClientRect();
227
+ const localX = event.clientX - rect.left;
228
+ const localY = event.clientY - rect.top;
229
+ const graphPoint = minimapToGraph(latestTransform, localX, localY);
230
+ const container = instance.container ?? canvas;
231
+ const viewport = instance.getViewport();
232
+ const zoom = viewport.zoom || 1;
233
+
234
+ instance.setViewport({
235
+ x: container.clientWidth / 2 - graphPoint.x * zoom,
236
+ y: container.clientHeight / 2 - graphPoint.y * zoom,
237
+ zoom,
238
+ });
239
+ event.preventDefault();
240
+ };
241
+
242
+ svg.addEventListener('pointerdown', onPointerDown);
243
+
244
+ const cleanup = () => {
245
+ window.cancelAnimationFrame(rafId);
246
+ unsubscribe?.();
247
+ unsubscribe = null;
248
+ svg.removeEventListener('pointerdown', onPointerDown);
249
+ host.replaceChildren();
250
+ };
251
+
252
+ minimapCleanups.set(host, cleanup);
253
+ bindInstance();
254
+
255
+ return cleanup;
256
+ }
257
+
258
+ export function unmountGraphCanvasMinimap(host: HTMLElement) {
259
+ minimapCleanups.get(host)?.();
260
+ minimapCleanups.delete(host);
261
+ }
@@ -0,0 +1,259 @@
1
+ import {
2
+ buildGraphCanvasEdgeLabelHtml,
3
+ buildGraphCanvasEdgeStrokeStyle,
4
+ } from '../graphCanvasEdgeLabels.mjs';
5
+ import { buildGraphCanvasEdgeRoutes } from '../graphCanvasEdgeRouter.mjs';
6
+ import type { FlowCanvas } from 'lit-flow';
7
+
8
+ type GraphCanvasProjection = {
9
+ layoutDirection?: string;
10
+ nodes: Array<{ id: string; x?: number; y?: number; width?: number; height?: number }>;
11
+ edges: Array<{ id?: string; from: string; to: string; label?: string; rejected?: boolean; upstream?: boolean }>;
12
+ };
13
+
14
+ type SvgEdgeLayer = {
15
+ host: HTMLElement;
16
+ svg: SVGSVGElement;
17
+ labelsLayer: HTMLElement;
18
+ observer: MutationObserver | null;
19
+ paintKey: string;
20
+ };
21
+
22
+ const svgEdgeLayers = new WeakMap<FlowCanvas, SvgEdgeLayer>();
23
+
24
+ function resolveGraphCanvasTheme(): 'dark' | 'light' {
25
+ return document.body?.dataset?.theme === 'dark' ? 'dark' : 'light';
26
+ }
27
+
28
+ function buildPaintKey(projection: GraphCanvasProjection, theme: 'dark' | 'light') {
29
+ return `${theme}:${projection.layoutDirection ?? 'LR'}:${projection.edges.length}:${projection.nodes.length}`;
30
+ }
31
+
32
+ function buildMarkerDefs(theme: 'dark' | 'light') {
33
+ const color = theme === 'dark' ? '#858585' : '#8b8b95';
34
+ return `
35
+ <defs>
36
+ <marker id="wg-edge-arrow" markerWidth="12" markerHeight="12" refX="10" refY="6" orient="auto" markerUnits="userSpaceOnUse">
37
+ <path d="M0,0 L12,6 L0,12 Z" fill="${color}" />
38
+ </marker>
39
+ <marker id="wg-edge-arrow-upstream" markerWidth="12" markerHeight="12" refX="10" refY="6" orient="auto" markerUnits="userSpaceOnUse">
40
+ <path d="M0,0 L12,6 L0,12 Z" fill="${color}" opacity="0.72" />
41
+ </marker>
42
+ <marker id="wg-edge-arrow-rejected" markerWidth="12" markerHeight="12" refX="10" refY="6" orient="auto" markerUnits="userSpaceOnUse">
43
+ <path d="M0,0 L12,6 L0,12 Z" fill="${color}" opacity="0.42" />
44
+ </marker>
45
+ </defs>
46
+ `;
47
+ }
48
+
49
+ function paintSvgEdges(
50
+ layer: SvgEdgeLayer,
51
+ projection: GraphCanvasProjection,
52
+ theme: 'dark' | 'light',
53
+ force = false,
54
+ ) {
55
+ const paintKey = buildPaintKey(projection, theme);
56
+ if (!force && layer.paintKey === paintKey) {
57
+ return;
58
+ }
59
+
60
+ const routes = buildGraphCanvasEdgeRoutes(projection);
61
+ const paths = routes.map((route) => {
62
+ const stroke = buildGraphCanvasEdgeStrokeStyle(
63
+ { rejected: route.rejected, upstream: route.upstream },
64
+ theme,
65
+ );
66
+ const marker = route.rejected
67
+ ? 'url(#wg-edge-arrow-rejected)'
68
+ : route.upstream
69
+ ? 'url(#wg-edge-arrow-upstream)'
70
+ : 'url(#wg-edge-arrow)';
71
+ const dash = route.rejected
72
+ ? 'stroke-dasharray="6 4" opacity="0.42"'
73
+ : route.upstream
74
+ ? 'stroke-dasharray="5 4" opacity="0.72"'
75
+ : '';
76
+ return `<path class="graph-canvas-edge-path" data-edge-id="${route.id}" d="${route.d}" fill="none" stroke="${stroke.stroke}" stroke-width="${route.rejected ? 1.75 : 2.25}" marker-end="${marker}" ${dash} />`;
77
+ }).join('');
78
+
79
+ layer.svg.innerHTML = `${buildMarkerDefs(theme)}<g class="graph-canvas-edge-paths">${paths}</g>`;
80
+
81
+ layer.labelsLayer.replaceChildren();
82
+ for (const route of routes) {
83
+ if (!route.label) {
84
+ continue;
85
+ }
86
+ const labelHtml = buildGraphCanvasEdgeLabelHtml(route.label, theme, { rejected: route.rejected });
87
+ if (!labelHtml) {
88
+ continue;
89
+ }
90
+ const label = document.createElement('div');
91
+ label.className = 'graph-canvas-edge-label';
92
+ label.style.left = `${route.labelX}px`;
93
+ label.style.top = `${route.labelY}px`;
94
+ if (route.labelPlacement === 'start') {
95
+ label.style.transform = 'translate(8px, -50%)';
96
+ } else {
97
+ label.style.transform = 'translate(-50%, -50%)';
98
+ }
99
+ label.innerHTML = labelHtml;
100
+ layer.labelsLayer.appendChild(label);
101
+ }
102
+
103
+ layer.paintKey = paintKey;
104
+ }
105
+
106
+ function createSvgEdgeHost(): HTMLElement {
107
+ const host = document.createElement('div');
108
+ host.className = 'graph-canvas-wg-edges-layer';
109
+ host.dataset.testid = 'graph-canvas-svg-edges';
110
+ host.style.cssText = 'position:absolute;inset:0;pointer-events:none;z-index:0;overflow:visible;';
111
+ return host;
112
+ }
113
+
114
+ function createSvgEdgeLayer(host: HTMLElement): SvgEdgeLayer {
115
+ host.replaceChildren();
116
+
117
+ const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
118
+ svg.setAttribute('class', 'graph-canvas-svg-edges-svg');
119
+ svg.setAttribute('aria-hidden', 'true');
120
+ svg.style.cssText = 'position:absolute;inset:0;overflow:visible;display:block;';
121
+
122
+ const labelsLayer = document.createElement('div');
123
+ labelsLayer.className = 'graph-canvas-svg-edge-labels';
124
+ labelsLayer.style.cssText = 'position:absolute;inset:0;pointer-events:none;';
125
+
126
+ host.appendChild(svg);
127
+ host.appendChild(labelsLayer);
128
+
129
+ return {
130
+ host,
131
+ svg,
132
+ labelsLayer,
133
+ observer: null,
134
+ paintKey: '',
135
+ };
136
+ }
137
+
138
+ function getFlowViewport(canvas: FlowCanvas) {
139
+ return canvas.shadowRoot?.querySelector('.flow-viewport') ?? null;
140
+ }
141
+
142
+ function restoreSvgEdgeLayerIfMissing(canvas: FlowCanvas, projection: GraphCanvasProjection) {
143
+ const viewport = getFlowViewport(canvas);
144
+ const nodesLayer = viewport?.querySelector('.flow-nodes-layer');
145
+ if (!viewport || !nodesLayer) {
146
+ return null;
147
+ }
148
+
149
+ let layer = svgEdgeLayers.get(canvas);
150
+ if (layer?.host.isConnected && viewport.contains(layer.host)) {
151
+ return layer;
152
+ }
153
+
154
+ const host = createSvgEdgeHost();
155
+ viewport.insertBefore(host, nodesLayer);
156
+ layer = createSvgEdgeLayer(host);
157
+ svgEdgeLayers.set(canvas, layer);
158
+ paintSvgEdges(layer, projection, resolveGraphCanvasTheme(), true);
159
+ return layer;
160
+ }
161
+
162
+ function watchForSvgEdgeHostRemoval(canvas: FlowCanvas, projection: GraphCanvasProjection) {
163
+ const root = canvas.shadowRoot;
164
+ if (!root) {
165
+ return;
166
+ }
167
+
168
+ const existing = svgEdgeLayers.get(canvas);
169
+ existing?.observer?.disconnect();
170
+
171
+ let restoring = false;
172
+ const observer = new MutationObserver(() => {
173
+ if (restoring) {
174
+ return;
175
+ }
176
+ const viewport = getFlowViewport(canvas);
177
+ if (!viewport?.querySelector('.flow-nodes-layer')) {
178
+ return;
179
+ }
180
+ if (viewport.querySelector('.graph-canvas-wg-edges-layer')) {
181
+ return;
182
+ }
183
+
184
+ restoring = true;
185
+ try {
186
+ restoreSvgEdgeLayerIfMissing(canvas, projection);
187
+ } finally {
188
+ restoring = false;
189
+ }
190
+ });
191
+
192
+ observer.observe(root, { childList: true, subtree: true });
193
+
194
+ const layer = svgEdgeLayers.get(canvas);
195
+ if (layer) {
196
+ layer.observer = observer;
197
+ }
198
+ }
199
+
200
+ export function injectFlowCanvasNativeEdgeHide(canvas: FlowCanvas) {
201
+ const root = canvas.shadowRoot;
202
+ if (!root || root.querySelector('[data-wg-hide-native-edges]')) {
203
+ return;
204
+ }
205
+ const style = document.createElement('style');
206
+ style.setAttribute('data-wg-hide-native-edges', 'true');
207
+ style.textContent = `
208
+ .flow-edges-layer,
209
+ .flow-labels-overlay {
210
+ display: none !important;
211
+ }
212
+ `;
213
+ root.appendChild(style);
214
+ }
215
+
216
+ export function mountGraphCanvasSvgEdges(
217
+ canvas: FlowCanvas,
218
+ projection: GraphCanvasProjection,
219
+ ): () => void {
220
+ unmountGraphCanvasSvgEdges(canvas);
221
+
222
+ let attempts = 0;
223
+ const tryMount = () => {
224
+ const layer = restoreSvgEdgeLayerIfMissing(canvas, projection);
225
+ if (!layer) {
226
+ attempts += 1;
227
+ if (attempts < 120) {
228
+ window.requestAnimationFrame(tryMount);
229
+ }
230
+ return;
231
+ }
232
+ watchForSvgEdgeHostRemoval(canvas, projection);
233
+ };
234
+
235
+ tryMount();
236
+
237
+ return () => unmountGraphCanvasSvgEdges(canvas);
238
+ }
239
+
240
+ export function unmountGraphCanvasSvgEdges(canvas: FlowCanvas) {
241
+ const layer = svgEdgeLayers.get(canvas);
242
+ if (!layer) {
243
+ return;
244
+ }
245
+ layer.observer?.disconnect();
246
+ layer.host.remove();
247
+ svgEdgeLayers.delete(canvas);
248
+ }
249
+
250
+ export function repaintGraphCanvasSvgEdges(
251
+ canvas: FlowCanvas,
252
+ projection: GraphCanvasProjection,
253
+ ) {
254
+ const layer = restoreSvgEdgeLayerIfMissing(canvas, projection);
255
+ if (!layer) {
256
+ return;
257
+ }
258
+ paintSvgEdges(layer, projection, resolveGraphCanvasTheme(), true);
259
+ }
@@ -0,0 +1,152 @@
1
+ /* Work Graph overrides for lit-flow chrome inside backlog UI */
2
+
3
+ .graph-canvas-lit-flow-host {
4
+ --wg-graph-node-bg: #ffffff;
5
+ --wg-graph-node-border: #dfe1e6;
6
+ --wg-graph-node-text: #172b4d;
7
+ --wg-graph-node-subtext: #5e6c84;
8
+ --wg-graph-node-hover-border: #c1c7d0;
9
+ --wg-graph-node-selected-border: #0052cc;
10
+ --wg-graph-node-rejected-bg: #f4f5f7;
11
+ --wg-graph-node-selected-bg: linear-gradient(180deg, #deebff 0%, #ffffff 72%);
12
+ --wg-graph-layer-bg: rgba(9, 30, 66, 0.05);
13
+ --wg-graph-layer-border: rgba(9, 30, 66, 0.1);
14
+ --wg-graph-badge-bg: #f4f5f7;
15
+ --wg-graph-badge-border: #dfe1e6;
16
+ --wg-graph-badge-done-bg: #e3fcef;
17
+ --wg-graph-badge-done-border: #abf5d1;
18
+ --wg-graph-badge-done-text: #006644;
19
+ --wg-graph-badge-doing-bg: #fff7d6;
20
+ --wg-graph-badge-doing-border: #f0c36d;
21
+ --wg-graph-badge-doing-text: #7a4f01;
22
+ --wg-graph-badge-ready-bg: #deebff;
23
+ --wg-graph-badge-ready-border: #85b8ff;
24
+ --wg-graph-badge-ready-text: #0052cc;
25
+ --wg-graph-badge-blocked-bg: #ffebe6;
26
+ --wg-graph-badge-blocked-border: #ffbdad;
27
+ --wg-graph-badge-blocked-text: #bf2600;
28
+ --wg-graph-tone-question: #0052cc;
29
+ --wg-graph-tone-analysis: #5b21b6;
30
+ --wg-graph-tone-decision: #9a6700;
31
+ --wg-graph-tone-work: #1a7f37;
32
+ --wg-graph-tone-architecture: #0052cc;
33
+ }
34
+
35
+ .graph-canvas-lit-flow-host[data-graph-theme='dark'],
36
+ body[data-theme='dark'] .graph-canvas-lit-flow-host {
37
+ --wg-graph-node-bg: #252526;
38
+ --wg-graph-node-border: #3c3c3c;
39
+ --wg-graph-node-text: #e0e0e0;
40
+ --wg-graph-node-subtext: #9d9d9d;
41
+ --wg-graph-node-hover-border: #4a4a4a;
42
+ --wg-graph-node-selected-border: #0066ff;
43
+ --wg-graph-node-rejected-bg: #1f1f1f;
44
+ --wg-graph-node-selected-bg: linear-gradient(180deg, #1a2940 0%, #252526 72%);
45
+ --wg-graph-layer-bg: rgba(255, 255, 255, 0.05);
46
+ --wg-graph-layer-border: rgba(255, 255, 255, 0.08);
47
+ --wg-graph-badge-bg: #2d2d30;
48
+ --wg-graph-badge-border: #3c3c3c;
49
+ --wg-graph-badge-done-bg: #173b2b;
50
+ --wg-graph-badge-done-border: #2f6f4f;
51
+ --wg-graph-badge-done-text: #b5f2cf;
52
+ --wg-graph-badge-doing-bg: #3d2e12;
53
+ --wg-graph-badge-doing-border: #7a5a16;
54
+ --wg-graph-badge-doing-text: #ffd599;
55
+ --wg-graph-badge-ready-bg: #17324d;
56
+ --wg-graph-badge-ready-border: #24517a;
57
+ --wg-graph-badge-ready-text: #cce0ff;
58
+ --wg-graph-badge-blocked-bg: #4a1f1a;
59
+ --wg-graph-badge-blocked-border: #8f3328;
60
+ --wg-graph-badge-blocked-text: #ffb3b3;
61
+ --wg-graph-tone-question: #4d9fff;
62
+ --wg-graph-tone-analysis: #a371f7;
63
+ --wg-graph-tone-decision: #f0ad4e;
64
+ --wg-graph-tone-work: #2ea043;
65
+ --wg-graph-tone-architecture: #569cd6;
66
+ }
67
+
68
+ .graph-canvas-lit-flow-shell flow-canvas[theme='dark'] {
69
+ --flow-background-color: #1e1e1e;
70
+ --flow-grid-color: #3c3c3c;
71
+ --flow-edge-color: #858585;
72
+ --flow-edge-selected-color: #0066ff;
73
+ --flow-node-selected-border: #0066ff;
74
+ }
75
+
76
+ .graph-canvas-lit-flow-shell flow-canvas[theme='light'] {
77
+ --flow-background-color: #f4f5f7;
78
+ --flow-grid-color: #dfe1e6;
79
+ --flow-edge-color: #97a0af;
80
+ --flow-edge-selected-color: #0052cc;
81
+ --flow-node-selected-border: #0052cc;
82
+ }
83
+
84
+ .graph-canvas-lit-flow-host:focus-visible {
85
+ outline: 2px solid var(--accent, #0066ff);
86
+ outline-offset: 2px;
87
+ }
88
+
89
+ .graph-canvas-lit-flow-host .empty {
90
+ display: flex;
91
+ align-items: center;
92
+ justify-content: center;
93
+ height: 100%;
94
+ color: var(--muted, #9d9d9d);
95
+ font-size: 13px;
96
+ }
97
+
98
+ .graph-canvas-minimap-host {
99
+ bottom: 12px;
100
+ pointer-events: auto;
101
+ position: absolute;
102
+ right: 12px;
103
+ z-index: 4;
104
+ }
105
+
106
+ .graph-canvas-minimap {
107
+ background: var(--wg-graph-minimap-bg, #ffffff);
108
+ border: 1px solid var(--wg-graph-minimap-border, #dfe1e6);
109
+ border-radius: 8px;
110
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
111
+ cursor: pointer;
112
+ height: 108px;
113
+ opacity: 0.94;
114
+ overflow: hidden;
115
+ width: 168px;
116
+ }
117
+
118
+ .graph-canvas-minimap[data-theme='dark'] {
119
+ --wg-graph-minimap-bg: #252526;
120
+ --wg-graph-minimap-border: #3c3c3c;
121
+ --wg-graph-minimap-node-fill: #3c3c3c;
122
+ --wg-graph-minimap-node-stroke: #569cd6;
123
+ --wg-graph-minimap-viewport-stroke: #0066ff;
124
+ --wg-graph-minimap-viewport-fill: rgba(0, 102, 255, 0.14);
125
+ }
126
+
127
+ .graph-canvas-minimap[data-theme='light'] {
128
+ --wg-graph-minimap-bg: #ffffff;
129
+ --wg-graph-minimap-border: #dfe1e6;
130
+ --wg-graph-minimap-node-fill: #ebecf0;
131
+ --wg-graph-minimap-node-stroke: #97a0af;
132
+ --wg-graph-minimap-viewport-stroke: #0052cc;
133
+ --wg-graph-minimap-viewport-fill: rgba(0, 82, 204, 0.12);
134
+ }
135
+
136
+ .graph-canvas-minimap-node {
137
+ fill: var(--wg-graph-minimap-node-fill, #ebecf0);
138
+ stroke: var(--wg-graph-minimap-node-stroke, #97a0af);
139
+ stroke-width: 1;
140
+ }
141
+
142
+ .graph-canvas-minimap-viewport {
143
+ fill: var(--wg-graph-minimap-viewport-fill, rgba(0, 82, 204, 0.12));
144
+ stroke: var(--wg-graph-minimap-viewport-stroke, #0052cc);
145
+ stroke-width: 1.5;
146
+ }
147
+
148
+ .graph-canvas-svg-edge-labels .graph-canvas-edge-label {
149
+ pointer-events: none;
150
+ position: absolute;
151
+ white-space: nowrap;
152
+ }