likec4 1.56.0 → 1.57.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 (154) hide show
  1. package/__app__/chunks/AIChat2.mjs +2 -0
  2. package/__app__/chunks/DiagramActorProvider.mjs +4 -4
  3. package/__app__/chunks/EmbedPage.mjs +1 -0
  4. package/__app__/chunks/ExportPage.mjs +2 -0
  5. package/__app__/chunks/LikeC4Diagram.mjs +5 -5
  6. package/__app__/chunks/LikeC4Styles.mjs +11 -11
  7. package/__app__/chunks/Markdown.mjs +1 -0
  8. package/__app__/chunks/NavigationPanel.mjs +1 -1
  9. package/__app__/chunks/ViewReact.mjs +1 -1
  10. package/__app__/chunks/adhoc-editor.mjs +1 -1
  11. package/__app__/chunks/aichat.mjs +1 -0
  12. package/__app__/chunks/box.mjs +1 -0
  13. package/__app__/chunks/create-style-context.mjs +1 -0
  14. package/__app__/chunks/css.mjs +1 -0
  15. package/__app__/chunks/factory.mjs +1 -0
  16. package/__app__/chunks/hooks.mjs +1 -1
  17. package/__app__/chunks/hstack.mjs +1 -0
  18. package/__app__/chunks/libs/@dagrejs/dagre.mjs +1 -1
  19. package/__app__/chunks/libs/@floating-ui/core.mjs +1 -1
  20. package/__app__/chunks/libs/@floating-ui/dom.mjs +1 -1
  21. package/__app__/chunks/libs/@floating-ui/react.mjs +1 -1
  22. package/__app__/chunks/libs/@mantine/core.mjs +24 -24
  23. package/__app__/chunks/libs/@mantine/hooks.mjs +1 -1
  24. package/__app__/chunks/libs/@nanostores/react.mjs +1 -1
  25. package/__app__/chunks/libs/@react-hookz/web.mjs +1 -1
  26. package/__app__/chunks/libs/@tabler/icons-react.mjs +347 -4
  27. package/__app__/chunks/libs/@tanstack/ai-client.mjs +2 -0
  28. package/__app__/chunks/libs/@tanstack/ai-react-ui.mjs +1 -0
  29. package/__app__/chunks/libs/@tanstack/ai-react.mjs +1 -0
  30. package/__app__/chunks/libs/@tanstack/ai.mjs +2 -0
  31. package/__app__/chunks/libs/@tanstack/history.mjs +1 -1
  32. package/__app__/chunks/libs/@tanstack/react-router.mjs +3 -3
  33. package/__app__/chunks/libs/@tanstack/router-core.mjs +1 -1
  34. package/__app__/chunks/libs/@xstate/react.mjs +1 -1
  35. package/__app__/chunks/libs/@xstate/store.mjs +1 -1
  36. package/__app__/chunks/libs/@xyflow/react.mjs +3 -3
  37. package/__app__/chunks/libs/@zag-js/anatomy.mjs +1 -1
  38. package/__app__/chunks/libs/@zag-js/collection.mjs +1 -1
  39. package/__app__/chunks/libs/@zag-js/core.mjs +1 -1
  40. package/__app__/chunks/libs/@zag-js/react.mjs +1 -1
  41. package/__app__/chunks/libs/@zag-js/tree-view.mjs +1 -1
  42. package/__app__/chunks/libs/bezier-js.mjs +1 -1
  43. package/__app__/chunks/libs/copy-anything.mjs +1 -0
  44. package/__app__/chunks/libs/d3-path.mjs +1 -1
  45. package/__app__/chunks/libs/d3-shape.mjs +1 -1
  46. package/__app__/chunks/libs/fast-equals.mjs +1 -1
  47. package/__app__/chunks/libs/framer-motion.mjs +3 -3
  48. package/__app__/chunks/libs/html-to-image.mjs +2 -2
  49. package/__app__/chunks/libs/motion-dom.mjs +1 -1
  50. package/__app__/chunks/libs/nanostores.mjs +1 -1
  51. package/__app__/chunks/libs/react-error-boundary.mjs +1 -1
  52. package/__app__/chunks/libs/react-resizable-panels.mjs +1 -1
  53. package/__app__/chunks/libs/remeda.mjs +1 -1
  54. package/__app__/chunks/libs/superjson.mjs +1 -0
  55. package/__app__/chunks/libs/zod.mjs +39 -14
  56. package/__app__/chunks/rolldown-runtime.mjs +1 -1
  57. package/__app__/chunks/styles.css.mjs +1 -1
  58. package/__app__/chunks/txt.mjs +1 -0
  59. package/__app__/chunks/useLikeC4Project.mjs +1 -1
  60. package/__app__/codegen/webcomponent.mjs +221 -69
  61. package/__app__/src/aichat/index.mjs +1 -0
  62. package/__app__/src/main.mjs +45 -1
  63. package/__app__/src/pages/AdHocViewEditor.mjs +1 -1
  64. package/__app__/src/pages/EmbedPage.mjs +1 -1
  65. package/__app__/src/pages/ExportPage.mjs +1 -1
  66. package/__app__/src/pages/ProjectsOverview.mjs +1 -1
  67. package/__app__/src/pages/ViewAsD2.mjs +1 -1
  68. package/__app__/src/pages/ViewAsDot.mjs +1 -1
  69. package/__app__/src/pages/ViewAsMmd.mjs +1 -1
  70. package/__app__/src/pages/ViewAsPuml.mjs +1 -1
  71. package/__app__/src/pages/ViewEditor.mjs +1 -1
  72. package/__app__/src/style.css +1 -1
  73. package/config/schema.json +14 -41
  74. package/dist/chunks/enableServer.mjs +1 -0
  75. package/dist/chunks/index2.d.mts +569 -377
  76. package/dist/chunks/libs/@hono/mcp.mjs +33 -8
  77. package/dist/chunks/libs/@hono/node-server.mjs +1 -1
  78. package/dist/chunks/libs/@modelcontextprotocol/sdk.mjs +7 -7
  79. package/dist/chunks/libs/@ts-graphviz/ast.mjs +3 -0
  80. package/dist/chunks/libs/@ts-graphviz/common.d.mts +9 -0
  81. package/dist/chunks/libs/@ts-graphviz/core.mjs +1 -0
  82. package/dist/chunks/libs/ajv.mjs +1 -1
  83. package/dist/chunks/libs/ansi-styles.mjs +1 -1
  84. package/dist/chunks/libs/boxen.mjs +2 -2
  85. package/dist/chunks/libs/chevrotain.mjs +2 -2
  86. package/dist/chunks/libs/conf.mjs +1 -1
  87. package/dist/chunks/libs/langium.d.mts +5 -5
  88. package/dist/chunks/libs/langium.mjs +10 -10
  89. package/dist/chunks/libs/merge-error-cause.mjs +1 -1
  90. package/dist/chunks/libs/pako.mjs +3 -1
  91. package/dist/chunks/libs/remeda.mjs +1 -1
  92. package/dist/chunks/libs/ts-graphviz.mjs +1 -4
  93. package/dist/chunks/libs/unctx.mjs +1 -0
  94. package/dist/chunks/libs/vscode-languageserver.mjs +1 -1
  95. package/dist/chunks/libs/zod.d.mts +60 -25
  96. package/dist/chunks/node.mjs +62 -45
  97. package/dist/chunks/plugin.mjs +234 -41
  98. package/dist/chunks/sequence-view.mjs +1 -1
  99. package/dist/cli/index.mjs +142 -139
  100. package/dist/index.d.mts +1 -130
  101. package/dist/model/index.d.mts +1 -1
  102. package/dist/vite-plugin/index.d.mts +53 -2
  103. package/dist/vite-plugin/internal/index.d.mts +331 -3
  104. package/dist/vite-plugin/internal/index.mjs +1 -1
  105. package/package.json +65 -51
  106. package/react/index.d.mts +82 -50
  107. package/react/index.mjs +34017 -32421
  108. package/vite-plugin-modules.d.ts +4 -0
  109. package/__app__/chunks/ColorSchemeToggle.mjs +0 -1
  110. package/__app__/chunks/Fallback.mjs +0 -1
  111. package/__app__/chunks/Header.mjs +0 -13
  112. package/__app__/chunks/IconRenderer.mjs +0 -1
  113. package/__app__/chunks/LikeC4ModelContext.mjs +0 -1
  114. package/__app__/chunks/LikeC4ModelContext2.mjs +0 -1
  115. package/__app__/chunks/StaticLikeC4Diagram.mjs +0 -1
  116. package/__app__/chunks/__root.mjs +0 -1
  117. package/__app__/chunks/libs/motion.mjs +0 -1
  118. package/__app__/chunks/libs/xstate.mjs +0 -1
  119. package/__app__/chunks/safeCtx.mjs +0 -1
  120. package/__app__/chunks/searchParams.mjs +0 -1
  121. package/__app__/chunks/single-index.mjs +0 -1
  122. package/__app__/chunks/styled-system.mjs +0 -1
  123. package/__app__/chunks/useUpdateEffect.mjs +0 -1
  124. package/__app__/src/routeTree.gen.mjs +0 -1
  125. package/__app__/src/routes/__root.mjs +0 -1
  126. package/__app__/src/routes/_single/adhoc.mjs +0 -1
  127. package/__app__/src/routes/_single/embed._viewId.mjs +0 -1
  128. package/__app__/src/routes/_single/export._viewId.mjs +0 -1
  129. package/__app__/src/routes/_single/route.mjs +0 -1
  130. package/__app__/src/routes/_single/single-index.mjs +0 -1
  131. package/__app__/src/routes/_single/view._viewId.d2.mjs +0 -1
  132. package/__app__/src/routes/_single/view._viewId.dot.mjs +0 -1
  133. package/__app__/src/routes/_single/view._viewId.index.mjs +0 -1
  134. package/__app__/src/routes/_single/view._viewId.mjs +0 -1
  135. package/__app__/src/routes/_single/view._viewId.mmd.mjs +0 -1
  136. package/__app__/src/routes/_single/view._viewId.puml.mjs +0 -1
  137. package/__app__/src/routes/_single/webcomponent._.mjs +0 -33
  138. package/__app__/src/routes/index.mjs +0 -1
  139. package/__app__/src/routes/project._projectId/-components.mjs +0 -1
  140. package/__app__/src/routes/project._projectId/adhoc.mjs +0 -1
  141. package/__app__/src/routes/project._projectId/embed._viewId.mjs +0 -1
  142. package/__app__/src/routes/project._projectId/export._viewId.mjs +0 -1
  143. package/__app__/src/routes/project._projectId/index.mjs +0 -1
  144. package/__app__/src/routes/project._projectId/route.mjs +0 -1
  145. package/__app__/src/routes/project._projectId/view._viewId.d2.mjs +0 -1
  146. package/__app__/src/routes/project._projectId/view._viewId.dot.mjs +0 -1
  147. package/__app__/src/routes/project._projectId/view._viewId.index.mjs +0 -1
  148. package/__app__/src/routes/project._projectId/view._viewId.mjs +0 -1
  149. package/__app__/src/routes/project._projectId/view._viewId.mmd.mjs +0 -1
  150. package/__app__/src/routes/project._projectId/view._viewId.puml.mjs +0 -1
  151. package/__app__/src/routes/projects.mjs +0 -1
  152. package/dist/chunks/libs/ts-graphviz.d.mts +0 -12
  153. package/dist/vite-plugin/internal/chunks/libs/@nanostores/react.d.mts +0 -269
  154. package/dist/vite-plugin/internal/chunks/libs/nanostores.d.mts +0 -59
@@ -1,18 +1,18 @@
1
1
  #!/usr/bin/env node
2
- import{c as e,i as t}from"../chunks/rolldown-runtime.mjs";import{a as n,c as r,d as i,f as a,i as s,l as c,n as l,o as u,r as f,s as p,u as m}from"../chunks/node.mjs";import{t as h}from"../chunks/libs/defu.mjs";import{H as g,V as _,a as v,i as y,n as b,r as x,t as ee}from"../chunks/libs/langium.mjs";import{t as S}from"../chunks/libs/tinyrainbow.mjs";import{c as C,l as te,o as ne,r as w,s as T}from"../chunks/libs/ufo.mjs";import{t as E}from"../chunks/libs/json5.mjs";import{n as re,r as ie,t as ae}from"../chunks/libs/@hono/mcp.mjs";import{A as oe,C as se,G as ce,Q as le,X as ue,et as de,m as fe,q as pe,t as me,w as he,x as D,y as ge}from"../chunks/libs/remeda.mjs";import{t as _e}from"../chunks/libs/pretty-ms.mjs";import{t as ve}from"../chunks/libs/picomatch.mjs";import{n as ye}from"../chunks/libs/strip-indent.mjs";import{a as be,c as xe,i as Se,n as Ce,o as we,r as Te,s as Ee,t as De}from"../chunks/plugin.mjs";import{LikeC4Model as Oe}from"../model/index.mjs";import{t as O}from"../chunks/libs/is-inside-container.mjs";import{t as ke}from"../chunks/libs/boxen.mjs";import{t as Ae}from"../chunks/libs/package-up.mjs";import{n as je,t as Me}from"../chunks/libs/package-manager-detector.mjs";import{n as Ne,t as Pe}from"../chunks/libs/conf.mjs";import{a as k,c as A,d as j,f as Fe,i as Ie,l as M,n as N,o as P,p as Le,r as F,s as I,t as Re,u as L}from"../chunks/libs/@modelcontextprotocol/sdk.mjs";import{t as ze}from"../chunks/libs/ky.mjs";import{n as Be,t as Ve}from"../chunks/libs/get-port.mjs";import{t as He}from"../chunks/libs/vscode-languageserver.mjs";import{t as Ue}from"../chunks/libs/hono.mjs";import{t as We}from"../chunks/libs/@hono/node-server.mjs";import Ge from"node:module";import{invariant as R,nonexhaustive as Ke}from"@likec4/core";import{basename as qe,dirname as z,extname as Je,isAbsolute as Ye,join as B,relative as V,resolve as H,sep as Xe}from"node:path";import{compareNatural as Ze,ifilter as Qe,invariant as $e,isSameHierarchy as et,sortNaturalByFqn as tt}from"@likec4/core/utils";import{isDeploymentElementModel as nt,isDeploymentNodeModel as rt,isDeploymentRelationModel as it,isElementModel as at,isLikeC4ViewModel as ot,isRelationModel as st,modelConnection as ct}from"@likec4/core/model";import lt from"nano-spawn";import{tmpdir as ut}from"node:os";import{copyFileSync as dt,existsSync as U,readFileSync as ft,readdirSync as pt,rmSync as mt,statSync as ht}from"node:fs";import{copyFile as gt,mkdir as W,mkdtemp as _t,readFile as vt,readdir as yt,realpath as bt,rm as xt,stat as St,writeFile as G}from"node:fs/promises";import{fileURLToPath as Ct,pathToFileURL as wt}from"node:url";import{env as Tt,isCI as Et,isDevelopment as Dt,isTest as Ot,nodeENV as kt}from"std-env";import{argv as At,cwd as jt,exit as Mt,hrtime as Nt,stdout as Pt}from"node:process";import Ft from"yargs";import{hideBin as It}from"yargs/helpers";import{build as Lt,createServer as Rt,preview as zt}from"vite";import Bt from"@vitejs/plugin-react";import{viteSingleFile as Vt}from"vite-plugin-singlefile";import{setTimeout as Ht}from"node:timers/promises";import{setTimeout as Ut}from"node:timers";function toUnion(e){return e.length===0?`never`:e.sort(Ze).map(e=>` | ${JSON.stringify(e)}`).join(`
3
- `).trimStart()}function elementIdToUnion(e){let t=me(e);return t.length===0?`never`:le(t,tt,ge(e=>` | ${JSON.stringify(e.id)}`)).join(`
2
+ import{c as e,i as t}from"../chunks/rolldown-runtime.mjs";import{a as n,d as r,f as i,i as a,l as s,n as c,o as l,p as u,r as f,s as p,u as m}from"../chunks/node.mjs";import{t as h}from"../chunks/libs/defu.mjs";import{H as g,U as _,a as v,n as y,o as b,r as x,t as S}from"../chunks/libs/langium.mjs";import{t as C}from"../chunks/libs/tinyrainbow.mjs";import{c as w,l as T,o as ee,r as te,s as ne}from"../chunks/libs/ufo.mjs";import{t as E}from"../chunks/libs/json5.mjs";import{n as D,r as re,t as ie}from"../chunks/libs/@hono/mcp.mjs";import{C as ae,M as oe,Q as se,Y as ce,d as le,et as ue,m as de,nt as fe,q as pe,t as me,u as he,w as ge,x as O,y as _e}from"../chunks/libs/remeda.mjs";import{t as ve}from"../chunks/libs/pretty-ms.mjs";import{t as ye}from"../chunks/libs/picomatch.mjs";import{n as be}from"../chunks/libs/strip-indent.mjs";import{n as xe,t as Se}from"../chunks/libs/package-manager-detector.mjs";import{a as Ce,c as we,i as Te,l as Ee,n as De,o as Oe,r as ke,s as Ae,t as je}from"../chunks/plugin.mjs";import{LikeC4Model as Me}from"../model/index.mjs";import{t as k}from"../chunks/libs/is-inside-container.mjs";import{t as Ne}from"../chunks/libs/boxen.mjs";import{t as Pe}from"../chunks/libs/package-up.mjs";import{n as Fe,t as Ie}from"../chunks/libs/conf.mjs";import{a as A,c as j,d as M,f as N,h as Le,i as P,l as F,m as Re,n as ze,o as Be,p as I,r as Ve,s as L,t as He,u as R}from"../chunks/libs/@modelcontextprotocol/sdk.mjs";import{t as Ue}from"../chunks/libs/ky.mjs";import{n as We,t as Ge}from"../chunks/libs/get-port.mjs";import{t as Ke}from"../chunks/libs/vscode-languageserver.mjs";import{t as qe}from"../chunks/libs/unctx.mjs";import{t as Je}from"../chunks/libs/hono.mjs";import{t as Ye}from"../chunks/libs/@hono/node-server.mjs";import Xe from"node:module";import{basename as Ze,dirname as z,extname as Qe,isAbsolute as $e,join as B,relative as V,resolve as H,sep as et}from"node:path";import{hasProp as tt,invariant as U,nonexhaustive as nt}from"@likec4/core";import{compareNatural as rt,ifilter as it,invariant as at,isSameHierarchy as ot,sortNaturalByFqn as st}from"@likec4/core/utils";import{isDeploymentElementModel as ct,isDeploymentNodeModel as lt,isDeploymentRelationModel as ut,isElementModel as dt,isLikeC4ViewModel as ft,isRelationModel as pt,modelConnection as mt}from"@likec4/core/model";import ht from"nano-spawn";import{tmpdir as gt}from"node:os";import{copyFileSync as _t,existsSync as W,readFileSync as vt,readdirSync as yt,rmSync as bt,statSync as xt}from"node:fs";import{copyFile as St,cp as Ct,mkdir as G,mkdtemp as wt,readFile as Tt,readdir as Et,realpath as Dt,rm as Ot,stat as kt,writeFile as K}from"node:fs/promises";import{fileURLToPath as At,pathToFileURL as jt}from"node:url";import{env as Mt,isCI as Nt,isDevelopment as Pt,isTest as Ft,nodeENV as It}from"std-env";import{argv as Lt,cwd as Rt,exit as zt,hrtime as Bt,stdout as Vt}from"node:process";import Ht from"yargs";import{hideBin as Ut}from"yargs/helpers";import{build as Wt,createServer as Gt,preview as Kt}from"vite";import qt from"@vitejs/plugin-react";import{viteSingleFile as Jt}from"vite-plugin-singlefile";import{setTimeout as Yt}from"node:timers/promises";import{setTimeout as Xt}from"node:timers";function toUnion(e){return e.length===0?`never`:e.sort(rt).map(e=>` | ${JSON.stringify(e)}`).join(`
3
+ `).trimStart()}function elementIdToUnion(e){let t=me(e);return t.length===0?`never`:ue(t,st,_e(e=>` | ${JSON.stringify(e.id)}`)).join(`
4
4
  `).trimStart()}function generateAux(e,t={}){let{useCorePackage:n=!1}=t;return`
5
5
  import type { Aux, SpecAux } from '${n?`@likec4/core/types`:`likec4/model`}';
6
6
 
7
7
  export type $Specs = SpecAux<
8
8
  // Element kinds
9
- ${toUnion(D(e.specification.elements))},
9
+ ${toUnion(O(e.specification.elements))},
10
10
  // Deployment kinds
11
- ${toUnion(D(e.specification.deployments??{}))},
11
+ ${toUnion(O(e.specification.deployments??{}))},
12
12
  // Relationship kinds
13
- ${toUnion(D(e.specification.relationships??{}))},
13
+ ${toUnion(O(e.specification.relationships??{}))},
14
14
  // Tags
15
- ${toUnion(D(e.specification.tags??{}))},
15
+ ${toUnion(O(e.specification.tags??{}))},
16
16
  // Metadata keys
17
17
  ${toUnion(e.specification.metadataKeys??[])}
18
18
  >
@@ -24,7 +24,7 @@ export type $Aux = Aux<
24
24
  // Deployments
25
25
  ${elementIdToUnion(e.$data.deployments.elements)},
26
26
  // Views
27
- ${toUnion(D(e.$data.views))},
27
+ ${toUnion(O(e.$data.views))},
28
28
  // Project ID
29
29
  ${JSON.stringify(e.projectId)},
30
30
  $Specs
@@ -55,7 +55,7 @@ ${n}
55
55
  export const likec4model: LikeC4Model<$Aux> = new LikeC4Model(${E.stringify(e.$data,{space:2,quote:`'`})} as any) as any
56
56
 
57
57
  /* prettier-ignore-end */
58
- `.trimStart()}function generateViewId(e){return ee(e,e=>v`${E.stringify(e.id)}`,{separator:` | `})}function generateViewsDataTs(e){let t=Array.from(e),n=new b;return n.appendTemplate`
58
+ `.trimStart()}function generateViewId(e){return S(e,e=>b`${E.stringify(e.id)}`,{separator:` | `})}function generateViewsDataTs(e){let t=Array.from(e),n=new y;return n.appendTemplate`
59
59
  /******************************************************************************
60
60
  * This file was generated
61
61
  * DO NOT EDIT MANUALLY!
@@ -66,10 +66,10 @@ export const likec4model: LikeC4Model<$Aux> = new LikeC4Model(${E.stringify(e.$d
66
66
  // @ts-nocheck
67
67
 
68
68
  import type { DiagramView } from 'likec4'
69
- `.append(x,x),t.length===0?(n.append(`export {}`,x),y(n)):(n.appendTemplate`
69
+ `.append(x,x),t.length===0?(n.append(`export {}`,x),v(n)):(n.appendTemplate`
70
70
  export type LikeC4ViewId = ${generateViewId(t)};
71
71
  export const LikeC4Views = {
72
- `.indent({indentation:2,indentedChildren(e){e.appendNewLineIf(t.length>1).append(ee(t,e=>v`${E.stringify(e.id)}: (${E.stringify(e)} as unknown) as DiagramView`,{separator:`,`,appendNewLineIfNotEmpty:!0}))}}).append(`} as const satisfies Record<LikeC4ViewId, DiagramView>`,x,x).appendTemplate`
72
+ `.indent({indentation:2,indentedChildren(e){e.appendNewLineIf(t.length>1).append(S(t,e=>b`${E.stringify(e.id)}: (${E.stringify(e)} as unknown) as DiagramView`,{separator:`,`,appendNewLineIfNotEmpty:!0}))}}).append(`} as const satisfies Record<LikeC4ViewId, DiagramView>`,x,x).appendTemplate`
73
73
  export type LikeC4Views = typeof LikeC4Views
74
74
 
75
75
  export function isLikeC4ViewId(value: unknown): value is LikeC4ViewId {
@@ -81,7 +81,7 @@ export const likec4model: LikeC4Model<$Aux> = new LikeC4Model(${E.stringify(e.$d
81
81
  }
82
82
 
83
83
  /* prettier-ignore-end */
84
- `.append(x),y(n))}function generateReactTypes(e,t={}){let{useCorePackage:n=!1}=t;$e(!e.isParsed(),`can not generate react types for parsed model`);let r=generateAux(e,t);return`
84
+ `.append(x),v(n))}function generateReactTypes(e,t={}){let{useCorePackage:n=!1}=t;at(!e.isParsed(),`can not generate react types for parsed model`);let r=generateAux(e,t);return`
85
85
  /* prettier-ignore-start */
86
86
  /* eslint-disable */
87
87
 
@@ -137,10 +137,10 @@ export {
137
137
  ReactLikeC4
138
138
  }
139
139
  /* prettier-ignore-end */
140
- `.trimStart()}var Wt=`likec4`,Gt=`1.56.0`;const K=r.getChild(`cli`);function createLikeC4Logger(e){let t=r.getChild(e);return{info(e){t.info(e)},debug(e,...n){n.length===0?t.debug(e):t.debug(e,{args:n})},warn(e){if(e instanceof Error){t.warn(`${S.red(e.name+` `+e.message)}`,{msg:e});return}if(typeof e==`string`){t.warn(e);return}t.warn`${e}`},warnOnce(e){t.warn(e)},error(e,n){let r=n?.error??e;if(r instanceof Error){if(e===r){t.error(`${S.red(r.name+` `+r.message)}`,{error:r});return}t.error(S.red(e),{error:r});return}if(typeof e==`string`){t.error(S.red(e));return}t.error`${e}`},clearScreen:function(e){},hasErrorLogged:function(e){return!1},hasWarned:!1}}function inMillis(e){let[t,n]=Nt(e),r=t*1e3+n/1e6;return{ms:r,pretty:_e(r)}}function startTimer(e){let t=Nt();return{stopAndLog(n=`done in `){n=S.green(`${n}${inMillis(t).pretty}`),(e||K).info(n)}}}function boxen(e,t){console.log(ke(e,{padding:1,margin:1,dimBorder:!0,...t}))}const Kt=createLikeC4Logger(`vite`),qt=z(Ct(import.meta.url));function findPkgRoot(){let e=Ae({cwd:qt});if(!e)throw Error(`likec4 package folder not found`);return z(e)}function viteAppRoot(){let e=[H(findPkgRoot(),`__app__`),H(qt,`../__app__`),H(qt,`../../__app__`),H(qt,`../../dist/__app__`)],t=pe(e,U);if(!t)throw r.error(`likec4 app root does not exist, tried:\n${e.join(`
141
- `)}`),Error(`likec4 app root does not exist`);return t}async function mkTempPublicDir(){let e=await _t(B(ut(),`.likec4-public-`));return await G(B(e,`likec4-views.js`),`// generated by likec4
142
- `),e}function relativeToCwd(e){return V(jt(),e)}function viteAliases(){let e=findPkgRoot();return{"likec4/react":H(e,`react/index.mjs`),"likec4/model":H(e,`dist/model/index.mjs`),"likec4/vite-plugin/internal":H(e,`dist/vite-plugin/internal/index.mjs`)}}const viteConfig=async({languageServices:e,likec4AssetsDir:t,...n})=>{let r=n.customLogger??Kt,i=viteAppRoot();r.info(`${S.cyan(`likec4 app root`)} ${S.dim(relativeToCwd(i))}`);let a=n.outputDir??H(e.workspace,`dist`);r.info(S.cyan(`outDir`)+` `+S.dim(relativeToCwd(a)));let s=`/`;n.base&&(s=te(n.base),!w(s)&&s!==`./`&&(s=T(s))),s!==`/`&&r.info(`${S.green(`app base url`)} ${S.dim(s)}`);let c=n.webcomponentPrefix??`likec4`,l=n.title??`LikeC4`,u=n.outputSingleFile??!1;return{isDev:Dt,likec4AssetsDir:t,webcomponentPrefix:c,title:l,root:i,languageServices:e,clearScreen:!1,base:s,resolve:{alias:{...viteAliases(),"likec4/previews":t}},configFile:!1,mode:`production`,define:{"process.env.NODE_ENV":`"production"`},build:{outDir:a,emptyOutDir:!1,sourcemap:!1,minify:!0,copyPublicDir:!0,chunkSizeWarningLimit:2*1024,modulePreload:{polyfill:!1},...!u&&{rolldownOptions:{input:[H(i,`index.html`),H(i,`src`,`main.mjs`),H(i,`src`,`fonts.css`),H(i,`src`,`style.css`)],output:{codeSplitting:{groups:[{name:`likec4-core`,test:/(likec4[\\/]core|core[\\/]dist|immer)/},{test:/node_modules/,name:e=>{let t=e.match(/.*\/node_modules\/(?<package>@[^/]+\/[^/]+|[^/]+)/)?.groups?.package,n=/\.d\.[mc]?ts$/.test(e);return`libs/${t||`common`}${n?`.d`:``}`}}]}}}}},customLogger:r,plugins:[Bt(),De({languageServices:e.languageServices,appConfig:{webcomponentPrefix:c,pageTitle:l,useHashHistory:n.useHashHistory,theme:n.theme}}),u?Vt():void 0]}};function viteWebcomponentConfig({languageServices:e,outDir:t,base:n,webcomponentPrefix:r=`likec4`,filename:i=`likec4-views.js`}){let a=createLikeC4Logger([`vite`,`webcomponent`]),s=viteAppRoot();return a.info(S.cyan(`outDir`)+` `+S.dim(t)),{root:s,clearScreen:!1,base:n,configFile:!1,publicDir:!1,mode:`production`,resolve:{alias:viteAliases()},define:{"process.env.NODE_ENV":`"production"`},build:{outDir:t,emptyOutDir:!1,sourcemap:!1,minify:!0,assetsInlineLimit:500*1024,chunkSizeWarningLimit:3*1024,lib:{entry:`codegen/webcomponent.mjs`,fileName(e,t){return i},formats:[`iife`],name:`LikeC4Views`}},customLogger:a,plugins:[De({languageServices:e.languageServices,appConfig:{webcomponentPrefix:r}})]}}const Jt=[`favicon.ico`,`robots.txt`];async function viteBuild({buildWebcomponent:e=!0,webcomponentPrefix:t=`likec4`,title:n,languageServices:r,likec4AssetsDir:i,outputSingleFile:a,...s}){i??=await _t(B(ut(),`.likec4-assets-`));let c=await viteConfig({...s,languageServices:r,likec4AssetsDir:i,webcomponentPrefix:t,title:n,outputSingleFile:a}),l=!U(c.build.outDir)||pt(c.build.outDir).length===0,u=await mkTempPublicDir();for(let e of Jt){let t=H(c.root,e);U(t)&&dt(t,H(u,e))}let f=r.languageServices.projects();if(f.length===1){let e=await r.viewsService.computedViews(),t=await r.diagrams();if(t.length===0)throw process.exitCode=1,Error(`no views found`);t.length===e.length?c.customLogger.info(`${S.dim(`workspace:`)} ${S.green(`✓ all views layouted`)}`):c.customLogger.warn(`${S.dim(`workspace:`)} ${S.yellow(`✗ layouted ${t.length} of ${e.length} views`)}`),t.forEach(e=>{(e.hasLayoutDrift||e.drifts&&e.drifts.length>0)&&c.customLogger.warn(S.dim(`view`)+` `+S.red(e.id)+` `+S.yellow(`is out of date, layout drift detected`))});let n=f[0].config.landingPage;if(n&&(`include`in n||`exclude`in n)){let e=`include`in n?n.include:n.exclude;t.some(t=>e.some(e=>e.startsWith(`#`)?t.tags?.some(t=>t===e.slice(1)):t.id===e))||c.customLogger.warn(S.dim(`landingPage:`)+` `+S.yellow(`no views match the configured filter`))}}else for(let e of f){let t=await r.viewsService.computedViews(e.id);t.length===0?c.customLogger.warn(`${S.dim(`project:`)} ${e.id} ${S.yellow(`✗ no views found`)}`):c.customLogger.info(`${S.dim(`project:`)} ${e.id} ${S.green(`${t.length} views`)}`);let n=await r.diagrams(e.id),i=e.config.landingPage;if(i&&(`include`in i||`exclude`in i)){let t=`include`in i?i.include:i.exclude;n.some(e=>t.some(t=>t.startsWith(`#`)?e.tags?.some(e=>e===t.slice(1)):e.id===t))||c.customLogger.warn(`${S.dim(`project:`)} ${e.id} ${S.yellow(`landingPage: no views match the configured filter`)}`)}}if(e&&!a&&await Lt(viteWebcomponentConfig({webcomponentPrefix:t,languageServices:r,outDir:u,base:c.base})),await Lt({...c,customLogger:c.customLogger,publicDir:u,mode:`production`}),a){if(!l){c.customLogger.warn(S.yellow(`outDir was not empty, skipping cleanup`));return}for(let e of pt(H(c.build.outDir)).filter(e=>e!==`index.html`))mt(H(c.build.outDir,e),{recursive:!0})}let p=H(c.build.outDir,`index.html`);U(p)&&dt(p,H(c.build.outDir,`404.html`))}function isInstalled(e){try{return!!Ge.createRequire(import.meta.url).resolve(e)}catch(e){return K.debug(a(e)),!1}}async function ensureReact(){if(isInstalled(`react`)&&isInstalled(`react-dom`)){K.debug(`react already installed`);return}K.warn(`react not installed`);let e=await Me();e||(K.error`Package manager not detected, please install dependencies manually: ${`react`} ${`react-dom`}`,process.exit(1));let t=je(e.agent,`add`,[`react`,`react-dom`]);t||(K.error`Please install dependencies manually: ${`react`} ${`react-dom`}`,process.exit(1));try{await lt(t.command,t.args,{stdio:`inherit`})}catch(e){K.debug(a(e)),K.error`Please install dependencies manually: ${`react`} ${`react-dom`}`,process.exit(1)}}async function ensurePlaywright(){if(isInstalled(`playwright`)){K.debug(`playwright already installed`);return}K.warn(`playwright not installed`);let e=await Me();e||(K.error`Package manager not detected, please install dependencies manually: ${`playwright`}`,process.exit(1));let t=je(e.agent,`add`,[`playwright`]);t||(K.error`Please install dependencies manually: ${`playwright`}`,process.exit(1));try{await lt(t.command,t.args,{preferLocal:!0,stdio:`inherit`})}catch(e){K.debug(a(e)),K.error`Please install dependencies manually: ${`playwright`}`,process.exit(1)}}const q={type:`string`,desc:`<directory> with LikeC4 sources (default is current directory or 'LIKEC4_WORKSPACE' env)`,normalize:!0,default:Tt.LIKEC4_WORKSPACE||`.`,coerce:H},J={alias:`use-dot-bin`,boolean:!0,type:`boolean`,desc:O()?`enabled in container, disable by --no-use-dot`:`use graphviz binaries ("dot" should be on PATH)`,default:O()},Yt={boolean:!0,type:`boolean`,desc:"use `@likec4/core` package in types",default:!1},Xt={boolean:!0,type:`boolean`,desc:`use hash history for navigation, e.g. "/#/view" instead of "/view"`},Y={alias:[`o`,`output`],string:!0,desc:`output directory`,normalize:!0,nargs:1,coerce:H},Zt={alias:`w`,string:!0,desc:`prefix for Webcomponents, e.g "c4" generates <c4-view ../>`,default:`likec4`,nargs:1},Qt={alias:`t`,string:!0,desc:`base title of the app pages (default is "LikeC4")`,default:`LikeC4`,nargs:1},$t={choices:[`light`,`dark`],desc:`default color scheme for the built website (default: auto, follows system preference)`,nargs:1},en={alias:[`base-url`],string:!0,desc:`base url the app is being served from, e.g. "/" or "/pages/"`,nargs:1},tn={boolean:!0,desc:`outputs a single self-contained HTML file with all required resources inlined`},nn={alias:`l`,string:!0,...O()?{desc:`listen 0.0.0.0 by default in container`,default:`0.0.0.0`}:{desc:`ip address of the network interface to listen on`},nargs:1},rn={number:!0,desc:`port number for the dev server (default is 5173, or PORT environment variable)`,nargs:1},X={alias:`p`,string:!0,desc:`select LikeC4 project by name (e.g. "my-project") or by path`,nargs:1},an={hidden:!0,nargs:1,desc:`force log level`,choices:[`trace`,`debug`,`info`,`warning`,`error`],conflicts:[`verbose`]},on={boolean:!0,desc:`verbose logging`,conflicts:[`log-level`]},sn=Dt?`trace`:`debug`,cn={name:Wt,version:Gt},ln=fe(()=>new Pe({projectName:Wt,clearInvalidConfig:!0})),un=1e3*60,dn=un*60*24*7;function showSupportUsMessage(){if(!Et)try{let e=ln(),t=e.get(`lastSupportUsMessage`);if(!t){e.set(`lastSupportUsMessage`,Date.now()-dn+5*un);return}if(t+dn>Date.now())return;e.set(`lastSupportUsMessage`,Date.now()),boxen([S.dim(`If you are working in a commercial environment`),S.dim(`consider supporting the project`),``,S.dim(`How to get more?`)+` `+S.underline(`https://likec4.dev/sponsor/`)].join(`
143
- `))}catch{}}function _usingCtx(){var e=typeof SuppressedError==`function`?SuppressedError:function(e,t){var n=Error();return n.name=`SuppressedError`,n.error=e,n.suppressed=t,n},t={},n=[];function using(e,t){if(t!=null){if(Object(t)!==t)throw TypeError(`using declarations can only be used with objects, functions, null, or undefined.`);if(e)var r=t[Symbol.asyncDispose||Symbol.for(`Symbol.asyncDispose`)];if(r===void 0&&(r=t[Symbol.dispose||Symbol.for(`Symbol.dispose`)],e))var i=r;if(typeof r!=`function`)throw TypeError(`Object is not disposable.`);i&&(r=function o(){try{i.call(t)}catch(e){return Promise.reject(e)}}),n.push({v:t,d:r,a:e})}else e&&n.push({d:t,a:e});return t}return{e:t,u:using.bind(null,!1),a:using.bind(null,!0),d:function d(){var r,i=this.e,a=0;function next(){for(;r=n.pop();)try{if(!r.a&&a===1)return a=0,n.push(r),Promise.resolve().then(next);if(r.d){var e=r.d.call(r.v);if(r.a)return a|=2,Promise.resolve(e).then(next,err)}else a|=1}catch(e){return err(e)}if(a===1)return i===t?Promise.resolve():Promise.reject(i);if(i!==t)throw i}function err(n){return i=i===t?n:new e(n,i),next()}return next()}}}const buildCmd=e=>e.command({command:`build [path]`,aliases:[`bundle`],describe:`Build a static website`,builder:e=>e.positional(`path`,q).option(`output`,{alias:`o`,type:`string`,desc:`output directory for production build`,normalize:!0,coerce:H}).option(`base`,en).option(`use-hash-history`,Xt).option(`use-dot`,J).option(`webcomponent-prefix`,Zt).option(`title`,Qt).option(`output-single-file`,tn).option(`theme`,$t).example(`${S.green(`$0 build -o ./build ./src`)}`,S.gray(`Search for likec4 files in 'src' and output static site to 'build'`)).example(`${S.green(`$0 build --theme dark -o ./build ./src`)}`,S.gray(`Build with dark color scheme as default`)),handler:async e=>{try{var t=_usingCtx();let n={useHashHistory:e[`use-hash-history`]??!1,useDotBin:e[`use-dot`],webcomponentPrefix:e[`webcomponent-prefix`],outputSingleFile:e[`output-single-file`]??!1};await ensureReact();let r=createLikeC4Logger(`c4:build`),i=t.a(await l(e.path,{graphviz:e[`use-dot`]?`binary`:`wasm`,watch:!1})),a=e.output??H(i.workspace,`dist`),s=H(a,`assets`);await viteBuild({base:e.base,useHashHistory:n.outputSingleFile||n.useHashHistory,customLogger:r,webcomponentPrefix:n.webcomponentPrefix,title:e.title,theme:e.theme,languageServices:i,likec4AssetsDir:s,outputDir:a,outputSingleFile:n.outputSingleFile}),showSupportUsMessage()}catch(e){t.e=e}finally{await t.d()}}});var fn=e(Ne(),1);const pn=`check-update`;async function notifyAvailableUpdate(){if(Et||Ot||kt===pn)return;let e=ln(),t=e.get(`lastUpdateCheck`);if(!t){await checkAvailableUpdate(!1);return}let n=e.get(`latestVersion`);if(oe(n)||oe(t)||t+864e5<Date.now())try{lt(`likec4`,[`check-update`],{stdio:`ignore`,timeout:5e3,preferLocal:!0,detached:!0,env:{NODE_ENV:pn}}).catch(()=>{})}catch{}n&&(0,fn.gt)(n,cn.version)&&boxen([`Update available: `,S.dim(cn.version),S.reset(` → `),S.green(n)].join(``))}async function checkAvailableUpdate(e=!0){try{let t=ln();t.set({lastUpdateCheck:Date.now()});let n=await fetchLatestVersion();R(n,`No version found in latest npm`),t.set({lastUpdateCheck:Date.now(),latestVersion:n}),(0,fn.gt)(n,cn.version)?boxen([`Update available: `,S.dim(cn.version),S.reset(` → `),S.green(n)].join(``)):e&&boxen(S.dim(`Up to date: `)+` `+S.green(cn.version))}catch(e){K.warning(a(e))}}async function fetchLatestVersion(){return(await ze(`https://registry.npmjs.org/likec4/latest`,{headers:{accept:`application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*`},timeout:5e3,keepalive:!0}).json()).version}const checkUpdateCmd=e=>e.command({command:`check-update`,describe:`Check for updates`,handler:async()=>{await checkAvailableUpdate()}});function ensureProjectId(e,t){if(!t)return e.languageServices.projectsManager.ensureProjectId();let n=H(t);if(n===e.workspace)return e.languageServices.projectsManager.ensureProjectId();if(U(n)&&ht(n).isDirectory()){K.debug`Project path exists: ${n}`;let t=g.file(n.endsWith(Xe)?n:n+Xe),r=e.languageServices.projects().find(e=>e.folder.fsPath===t.fsPath);if(r)return K.debug`Found project ${r.id} at path: ${n}`,r.id;K.debug`No project registered at path: ${n}`}return e.languageServices.projectsManager.ensureProjectId(t)}function ensureProject(e,t){let n=ensureProjectId(e,t),r=e.languageServices.projectsManager.getProject(n);return e.languageServices.projectsManager.defaultProjectId=n,{projectId:n,projectFolder:r.folderUri.fsPath,config:r.config}}const mn=K.getChild(`generator`);async function customHandler({name:e,path:t,useDotBin:n,project:r}){try{var i=_usingCtx();let a=startTimer(mn),s=i.a(await l(t,{graphviz:n?`binary`:`wasm`,watch:!1})),{projectId:c,config:u}=ensureProject(s,r);r&&mn.info(`${S.dim(`project`)} ${S.green(c)}`);let f=u.generators?.[e];if(!f)throw mn.error(S.red(`generator ${e} does not exist in project config`)),Error(`generator ${e} does not exist in project config`);mn.info(`${S.dim(`generator`)} ${S.green(e)}`),await runCustomGenerator({likec4:s,model:await s.layoutedModel(c),generator:f,logger:mn.getChild(e)}),a.stopAndLog()}catch(e){i.e=e}finally{await i.d()}}async function runCustomGenerator({likec4:e,model:t,generator:n,logger:r}){let i=e.languageServices,a=new Set,s=i.project(t.project.id),c=t.project.id;r.debug(`${S.dim(`running for project:`)} ${S.green(s.id)}`),await Promise.resolve().then(()=>n({likec4model:t,ctx:{workspace:e.languageServices.workspaceUri,project:s,locate:e=>{let t=null;switch(!0){case at(e):t=i.locate({element:e.id,projectId:c});break;case ot(e):t=i.locate({view:e.id,projectId:c});break;case nt(e):t=i.locate({deployment:e.id,projectId:c});break;case st(e):case it(e):t=i.locate({relation:e.id,projectId:c});break;default:Ke(e)}if(!t)throw r.error(`Cannot locate ${e.id}`,{target:e}),Error(`Cannot locate ${e.id}`);let n=g.parse(t.uri);return{range:t.range,document:n,relativePath:_.relative(s.folder,n),folder:_.dirname(n).fsPath,filename:_.basename(n)}},write:async({path:e,content:t})=>{let n;n=Array.isArray(e)?H(s.folder.fsPath,...e):g.isUri(e)?e.fsPath:H(s.folder.fsPath,`${e}`);let i=z(n);a.has(i)||(U(i)||(r.debug(`${S.dim(`create directory`)} ${i}`),await W(i,{recursive:!0})),a.add(i)),r.debug(`${S.dim(`write`)} ${n}`),await G(n,t)},abort:e=>{throw r.error(e||`Generator aborted`),Error(e||`Generator aborted`)}}}))}async function singleFileCodegenAction(e,t,n){t??=H(e.workspace,`likec4.generated.ts`),Je(t)!==`.ts`&&(t+=`.ts`),await W(z(t),{recursive:!0});let r=generateViewsDataTs([...await e.diagrams()]);await G(t,r),n.info(`${S.dim(`generated`)} ${V(process.cwd(),t)}`)}async function dotCodegenAction(e,t,n){await W(t,{recursive:!0}),n.info(`${S.dim(`format`)} ${S.green(`dot`)}`),n.info(`${S.dim(`outdir`)} ${t}`);let r=new Set,i=await e.computedModel(),a=me(i.$data.views),s=0;for(let c of a)try{let a=await e.viewsService.layouter.dot({view:c,styles:i.$styles}),l=`.`;c.sourcePath&&(l=z(c.sourcePath)),l=H(t,l),r.has(l)||(await W(l,{recursive:!0}),r.add(l));let u=H(l,c.id+`.dot`);await G(u,a),n.info(`${S.dim(`generated`)} ${V(process.cwd(),u)}`),s++}catch(e){K.error(`error while generating ${c.id}`,{error:e})}s>0&&n.info(`${S.dim(`total`)} ${s} files`)}async function multipleFilesCodegenAction(e,t,n,r){await W(n,{recursive:!0}),r.info(`${S.dim(`format`)} ${S.green(t)}`),r.info(`${S.dim(`outdir`)} ${n}`);let i,a;switch(t){case`d2`:i=`.d2`,a=xe;break;case`mermaid`:i=`.mmd`,a=Te;break;case`plantuml`:i=`.puml`,a=Ce;break;default:Ke(t)}let s=new Set,c=await e.layoutedModel(),l=0;for(let e of c.views()){let t=e.$view;try{let c=`.`;t.sourcePath&&(c=z(t.sourcePath)),c=H(n,c),s.has(c)||(await W(c,{recursive:!0}),s.add(c));let u=H(c,t.id+i);await G(u,a(e)),r.info(`${S.dim(`generated`)} ${V(process.cwd(),u)}`),l++}catch(e){r.error(`error while generating ${t.id}`,{error:e})}}l>0&&r.info(`${S.dim(`total`)} ${l} files`)}async function legacyHandler({path:e,useDotBin:t,...n}){let r=createLikeC4Logger(`c4:codegen`),i=startTimer(r),a=await l(e,{graphviz:t?`binary`:`wasm`,watch:!1});if(a.ensureSingleProject(),(await a.viewsService.computedViews()).length===0)throw r.warn(`no views found`),process.exitCode=1,Error(`no views found`);switch(n.format){case`views`:await singleFileCodegenAction(a,n.outfile,r);break;case`dot`:await dotCodegenAction(a,n.outdir??e,r);break;case`d2`:case`mermaid`:case`plantuml`:await multipleFilesCodegenAction(a,n.format,n.outdir??e,r);break;default:Ke(n)}i.stopAndLog()}const hn=z(Ct(import.meta.url));function readVersion(){try{let e=JSON.parse(ft(B(hn,`..`,`package.json`),`utf8`));if(e.version)return e.version}catch{}try{let e=JSON.parse(ft(B(hn,`..`,`..`,`package.json`),`utf8`));if(e.version)return e.version}catch{}return`0.1.0`}const gn=readVersion(),_n=`leanix`,vn=new Set([`factSheetTypes`,`relationTypes`,`metadataToFields`]);function isPlainObjectRecordOfStrings(e){if(typeof e!=`object`||!e||Array.isArray(e))return!1;for(let t of Object.values(e))if(typeof t!=`string`)return!1;return!0}function parseLeanixMappingInput(e){if(e==null)return e;if(typeof e!=`object`||Array.isArray(e))throw Error(`LeanIX mapping must be a plain object (not an array or primitive)`);let t=e;for(let e of Object.keys(t))if(!vn.has(e))throw Error(`LeanIX mapping has unknown key "${e}". Allowed: factSheetTypes, relationTypes, metadataToFields`);if(t.factSheetTypes!==void 0&&!isPlainObjectRecordOfStrings(t.factSheetTypes))throw Error(`LeanIX mapping "factSheetTypes" must be an object with string keys and string values`);if(t.relationTypes!==void 0&&!isPlainObjectRecordOfStrings(t.relationTypes))throw Error(`LeanIX mapping "relationTypes" must be an object with string keys and string values`);if(t.metadataToFields!==void 0&&!isPlainObjectRecordOfStrings(t.metadataToFields))throw Error(`LeanIX mapping "metadataToFields" must be an object with string keys and string values`);return e}const yn={factSheetTypes:{system:`Application`,container:`ITComponent`,component:`ITComponent`,actor:`Provider`},relationTypes:{default:`depends on`},metadataToFields:{title:`name`,description:`description`,technology:`technology`}};function mergeWithDefault(e){let t=parseLeanixMappingInput(e),n={factSheetTypes:{...yn.factSheetTypes},relationTypes:{...yn.relationTypes},metadataToFields:{...yn.metadataToFields}};return t?{factSheetTypes:{...n.factSheetTypes,...t.factSheetTypes},relationTypes:{...n.relationTypes,...t.relationTypes},metadataToFields:{...n.metadataToFields,...t.metadataToFields}}:n}function getFactSheetType(e,t){return t.factSheetTypes[e]??t.factSheetTypes.default??`Application`}function getRelationType(e,t){let n=e??`default`;return t.relationTypes[n]??t.relationTypes.default??`depends on`}const bn={manifestVersion:`1.0`,bridgeVersion:gn,mappingProfile:`default`};function buildManifestEntities(e){let t={};for(let n of e.elements())t[n.id]={canonicalId:n.id,external:{}};return t}function buildManifestViews(e){let t={};for(let n of e.views())t[n.id]={viewId:n.id,external:{}};return t}function buildManifestRelations(e){let t=[];for(let n of e.relationships())t.push({relationId:n.id,sourceFqn:n.source.id,targetFqn:n.target.id,compositeKey:`${n.source.id}|${n.target.id}|${n.id}`,external:{}});return t}function toBridgeManifest(e,t={}){let n={...bn,...t,generatedAt:t.generatedAt??new Date().toISOString()};return{manifestVersion:n.manifestVersion,generatedAt:n.generatedAt,bridgeVersion:n.bridgeVersion,mappingProfile:n.mappingProfile,projectId:e.projectId,entities:buildManifestEntities(e),views:buildManifestViews(e),relations:buildManifestRelations(e)}}function buildFactSheetsFromModel(e,t){let n=[];for(let r of e.elements()){let e=getFactSheetType(r.kind,t),i=r.getMetadata(),a=typeof i.description==`string`?i.description:void 0,s=r.technology??(typeof i.technology==`string`?i.technology:void 0);n.push({type:e,likec4Id:r.id,name:r.title,...a!==void 0&&{description:a},...s!==void 0&&{technology:s},...r.tags.length>0&&{tags:[...r.tags]},...Object.keys(i).length>0&&{metadata:{...i}}})}return n.sort((e,t)=>e.likec4Id.localeCompare(t.likec4Id)),n}function buildRelationsFromModel(e,t){let n=[];for(let r of e.relationships()){let e=r.title??r.kind;n.push({type:getRelationType(r.kind,t),likec4RelationId:r.id,sourceLikec4Id:r.source.id,targetLikec4Id:r.target.id,...e!=null&&e!==``&&{title:String(e)}})}return n.sort((e,t)=>e.likec4RelationId.localeCompare(t.likec4RelationId)),n}function toLeanixInventoryDryRun(e,t={}){let n=mergeWithDefault(t.mapping),r=t.generatedAt??new Date().toISOString(),i=t.mappingProfile??(t.mapping?`custom`:`default`);return{generatedAt:r,projectId:e.projectId,mappingProfile:i,factSheets:buildFactSheetsFromModel(e,n),relations:buildRelationsFromModel(e,n)}}function buildCoherenceErrorMessage(e,t){let n=[];return e.projectId!==t.projectId&&n.push(`projectId (manifest: ${e.projectId}, leanixDryRun: ${t.projectId})`),e.mappingProfile!==t.mappingProfile&&n.push(`mappingProfile (manifest: ${e.mappingProfile}, leanixDryRun: ${t.mappingProfile})`),`Manifest and LeanIX dry-run must belong to the same run. Mismatch: ${n.join(`; `)}`}function buildBridgeReport(e,t){if(e.projectId!==t.projectId||e.mappingProfile!==t.mappingProfile)throw Error(buildCoherenceErrorMessage(e,t));return{generatedAt:e.generatedAt,projectId:e.projectId,manifestVersion:e.manifestVersion,bridgeVersion:e.bridgeVersion,mappingProfile:e.mappingProfile,counts:{entities:Object.keys(e.entities).length,views:Object.keys(e.views).length,relations:e.relations.length,factSheets:t.factSheets.length,leanixRelations:t.relations.length},artifacts:{manifest:`manifest.json`,leanixDryRun:`leanix-dry-run.json`}}}var LeanixApiError=class extends Error{constructor(e,t,n){super(e),this.statusCode=t,this.graphqlErrors=n,this.name=`LeanixApiError`}};function sleep(e){return new Promise(t=>setTimeout(t,e))}var LeanixApiClient=class{baseUrl;apiToken;requestDelayMs;lastRequestTime=0;rateLimitLock=Promise.resolve();constructor(e){this.apiToken=e.apiToken,this.baseUrl=(e.baseUrl??`https://app.leanix.net`).replace(/\/$/,``),this.requestDelayMs=e.requestDelayMs??200}async graphql(e,t){let run=async()=>{let n=Date.now()-this.lastRequestTime;n<this.requestDelayMs&&await sleep(this.requestDelayMs-n),this.lastRequestTime=Date.now();let r=`${this.baseUrl}/services/pathfinder/v1/graphql`,i;try{i=await fetch(r,{method:`POST`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${this.apiToken}`},body:JSON.stringify({query:e,variables:t})})}catch(e){throw new LeanixApiError(`GraphQL request failed: ${r} POST - ${e instanceof Error?e.message:String(e)}`)}let a;try{a=await i.json()}catch(e){let t=e instanceof Error?e.message:String(e);throw new LeanixApiError(`Invalid JSON response: ${r} ${i.status} ${i.statusText} - ${t}`,i.status)}if(!i.ok)throw new LeanixApiError(a.errors?.[0]?.message??`HTTP ${i.status} ${i.statusText}`,i.status,a.errors);if(a.errors&&a.errors.length>0)throw new LeanixApiError(a.errors.map(e=>e.message).join(`; `),i.status,a.errors);if(a.data===void 0)throw new LeanixApiError(`GraphQL response had no data and no errors`);return a.data},n=this.rateLimitLock,r;this.rateLimitLock=new Promise(e=>{r=e}),await n;try{return await run()}finally{r()}}};async function findFactSheetByNameAndType(e,t,n){let r=(await e.graphql(`
140
+ `.trimStart()}var Zt=`likec4`,Qt=`1.57.0`;const q=s.getChild(`cli`);function createLikeC4Logger(e){let t=s.getChild(e);return{info(e){t.info(e)},debug(e,...n){n.length===0?t.debug(e):t.debug(e,{args:n})},warn(e){if(e instanceof Error){t.warn(`${C.red(e.name+` `+e.message)}`,{msg:e});return}if(typeof e==`string`){t.warn(e);return}t.warn`${e}`},warnOnce(e){t.warn(e)},error(e,n){let r=n?.error??e;if(r instanceof Error){if(e===r){t.error(`${C.red(r.name+` `+r.message)}`,{error:r});return}t.error(C.red(e),{error:r});return}if(typeof e==`string`){t.error(C.red(e));return}t.error`${e}`},clearScreen:function(e){},hasErrorLogged:function(e){return!1},hasWarned:!1}}function inMillis(e){let[t,n]=Bt(e),r=t*1e3+n/1e6;return{ms:r,pretty:ve(r)}}function startTimer(e){let t=Bt();return{stopAndLog(n=`done in `){n=C.green(`${n}${inMillis(t).pretty}`),(e||q).info(n)}}}function boxen(e,t){console.log(Ne(e,{padding:1,margin:1,dimBorder:!0,...t}))}const $t=createLikeC4Logger(`vite`),en=z(At(import.meta.url));function findPkgRoot(){let e=Pe({cwd:en});if(!e)throw Error(`likec4 package folder not found`);return z(e)}function viteAppRoot(){let e=[H(findPkgRoot(),`__app__`),H(en,`../__app__`),H(en,`../../__app__`),H(en,`../../dist/__app__`)],t=ce(e,W);if(!t)throw s.error(`likec4 app root does not exist, tried:\n${e.join(`
141
+ `)}`),Error(`likec4 app root does not exist`);return t}async function mkTempPublicDir(){let e=await wt(B(gt(),`.likec4-public-`));return await K(B(e,`likec4-views.js`),`// generated by likec4
142
+ `),e}function relativeToCwd(e){return V(Rt(),e)}async function copyUserPublicDir(e,t){if(!W(e))throw Error(`--public directory does not exist: ${e}`);if(!xt(e).isDirectory())throw Error(`--public path is not a directory: ${e}`);let n=await Et(e);return await Ct(e,t,{recursive:!0,errorOnExist:!1}),n}function viteAliases(){let e=findPkgRoot();return{"likec4/react":H(e,`react/index.mjs`),"likec4/model":H(e,`dist/model/index.mjs`),"likec4/vite-plugin/internal":H(e,`dist/vite-plugin/internal/index.mjs`)}}const viteConfig=async({languageServices:e,likec4AssetsDir:t,...n})=>{let r=n.customLogger??$t,i=viteAppRoot();r.info(`${C.cyan(`likec4 app root`)} ${C.dim(relativeToCwd(i))}`);let a=n.outputDir??H(e.workspace,`dist`);r.info(C.cyan(`outDir`)+` `+C.dim(relativeToCwd(a)));let s=`/`;n.base&&(s=T(n.base),!te(s)&&s!==`./`&&(s=ne(s))),s!==`/`&&r.info(`${C.green(`app base url`)} ${C.dim(s)}`);let c=n.webcomponentPrefix??`likec4`,l=n.title??`LikeC4`,u=n.outputSingleFile??!1;return{isDev:Pt,likec4AssetsDir:t,webcomponentPrefix:c,title:l,root:i,languageServices:e,clearScreen:!1,base:s,resolve:{alias:{...viteAliases(),"likec4/previews":t}},configFile:!1,mode:`production`,define:{"process.env.NODE_ENV":`"production"`},build:{outDir:a,emptyOutDir:!1,sourcemap:!1,minify:!0,copyPublicDir:!0,chunkSizeWarningLimit:2*1024,modulePreload:{polyfill:!1},...!u&&{rolldownOptions:{input:[H(i,`index.html`),H(i,`src`,`main.mjs`),H(i,`src`,`fonts.css`),H(i,`src`,`style.css`)],output:{codeSplitting:{groups:[{name:`likec4-core`,test:/(likec4[\\/]core|core[\\/]dist|immer)/}]}}}}},customLogger:r,plugins:[qt(),je({languageServices:e.languageServices,appConfig:{webcomponentPrefix:c,pageTitle:l,useHashHistory:n.useHashHistory,theme:n.theme}}),u?Jt():void 0]}};function viteWebcomponentConfig({languageServices:e,outDir:t,base:n,webcomponentPrefix:r=`likec4`,filename:i=`likec4-views.js`}){let a=createLikeC4Logger([`vite`,`webcomponent`]),s=viteAppRoot();return a.info(C.cyan(`outDir`)+` `+C.dim(t)),{root:s,clearScreen:!1,base:n,configFile:!1,publicDir:!1,mode:`production`,resolve:{alias:viteAliases()},define:{"process.env.NODE_ENV":`"production"`},build:{outDir:t,emptyOutDir:!1,sourcemap:!1,minify:!0,assetsInlineLimit:500*1024,chunkSizeWarningLimit:3*1024,lib:{entry:`codegen/webcomponent.mjs`,fileName(e,t){return i},formats:[`iife`],name:`LikeC4Views`}},customLogger:a,plugins:[je({ai:`disabled`,languageServices:e.languageServices,appConfig:{webcomponentPrefix:r}})]}}const tn=[`favicon.ico`,`robots.txt`];function removeAllButPreserved(e,t){let n=new Set(t);for(let t of yt(e).filter(e=>!n.has(e)))bt(H(e,t),{recursive:!0})}async function viteBuild({buildWebcomponent:e=!0,webcomponentPrefix:t=`likec4`,title:n,languageServices:r,likec4AssetsDir:i,outputSingleFile:a,userPublicDir:s,...c}){i??=await wt(B(gt(),`.likec4-assets-`));let l=await viteConfig({...c,languageServices:r,likec4AssetsDir:i,webcomponentPrefix:t,title:n,outputSingleFile:a}),u=!W(l.build.outDir)||yt(l.build.outDir).length===0,f=await mkTempPublicDir(),p=s?await copyUserPublicDir(s,f):[];for(let e of tn){let t=H(l.root,e);W(t)&&_t(t,H(f,e))}let m=r.languageServices.projects();if(m.length===1){let e=await r.viewsService.computedViews(),t=await r.diagrams();if(t.length===0)throw process.exitCode=1,Error(`no views found`);t.length===e.length?l.customLogger.info(`${C.dim(`workspace:`)} ${C.green(`✓ all views layouted`)}`):l.customLogger.warn(`${C.dim(`workspace:`)} ${C.yellow(`✗ layouted ${t.length} of ${e.length} views`)}`),t.forEach(e=>{(e.hasLayoutDrift||e.drifts&&e.drifts.length>0)&&l.customLogger.warn(C.dim(`view`)+` `+C.red(e.id)+` `+C.yellow(`is out of date, layout drift detected`))});let n=m[0].config.landingPage;if(n&&(`include`in n||`exclude`in n)){let e=`include`in n?n.include:n.exclude;t.some(t=>e.some(e=>e.startsWith(`#`)?t.tags?.some(t=>t===e.slice(1)):t.id===e))||l.customLogger.warn(C.dim(`landingPage:`)+` `+C.yellow(`no views match the configured filter`))}}else for(let e of m){let t=await r.viewsService.computedViews(e.id);t.length===0?l.customLogger.warn(`${C.dim(`project:`)} ${e.id} ${C.yellow(`✗ no views found`)}`):l.customLogger.info(`${C.dim(`project:`)} ${e.id} ${C.green(`${t.length} views`)}`);let n=await r.diagrams(e.id),i=e.config.landingPage;if(i&&(`include`in i||`exclude`in i)){let t=`include`in i?i.include:i.exclude;n.some(e=>t.some(t=>t.startsWith(`#`)?e.tags?.some(e=>e===t.slice(1)):e.id===t))||l.customLogger.warn(`${C.dim(`project:`)} ${e.id} ${C.yellow(`landingPage: no views match the configured filter`)}`)}}if(e&&!a&&await Wt(viteWebcomponentConfig({webcomponentPrefix:t,languageServices:r,outDir:f,base:l.base})),await Wt({...l,customLogger:l.customLogger,publicDir:f,mode:`production`}),a){if(!u){l.customLogger.warn(C.yellow(`outDir was not empty, skipping cleanup`));return}removeAllButPreserved(l.build.outDir,[`index.html`,...p])}let h=H(l.build.outDir,`index.html`);W(h)&&_t(h,H(l.build.outDir,`404.html`))}function isInstalled(e){try{return!!Xe.createRequire(import.meta.url).resolve(e)}catch(e){return q.debug(u(e)),!1}}async function ensureReact(){if(isInstalled(`react`)&&isInstalled(`react-dom`)){q.debug(`react already installed`);return}q.warn(`react not installed`);let e=await Se();e||(q.error`Package manager not detected, please install dependencies manually: ${`react`} ${`react-dom`}`,process.exit(1));let t=xe(e.agent,`add`,[`react`,`react-dom`]);t||(q.error`Please install dependencies manually: ${`react`} ${`react-dom`}`,process.exit(1));try{await ht(t.command,t.args,{stdio:`inherit`})}catch(e){q.debug(u(e)),q.error`Please install dependencies manually: ${`react`} ${`react-dom`}`,process.exit(1)}}async function ensurePlaywright(){if(isInstalled(`playwright`)){q.debug(`playwright already installed`);return}q.warn(`playwright not installed`);let e=await Se();e||(q.error`Package manager not detected, please install dependencies manually: ${`playwright`}`,process.exit(1));let t=xe(e.agent,`add`,[`playwright`]);t||(q.error`Please install dependencies manually: ${`playwright`}`,process.exit(1));try{await ht(t.command,t.args,{preferLocal:!0,stdio:`inherit`})}catch(e){q.debug(u(e)),q.error`Please install dependencies manually: ${`playwright`}`,process.exit(1)}}const J={type:`string`,desc:`<directory> with LikeC4 sources (default is current directory or 'LIKEC4_WORKSPACE' env)`,normalize:!0,default:Mt.LIKEC4_WORKSPACE||`.`,coerce:H},Y={alias:`use-dot-bin`,boolean:!0,type:`boolean`,desc:k()?`enabled in container, disable by --no-use-dot`:`use graphviz binaries ("dot" should be on PATH)`,default:k()},nn={boolean:!0,type:`boolean`,desc:"use `@likec4/core` package in types",default:!1},rn={boolean:!0,type:`boolean`,desc:`use hash history for navigation, e.g. "/#/view" instead of "/view"`},X={alias:[`o`,`output`],string:!0,desc:`output directory`,normalize:!0,nargs:1,coerce:H},an={alias:`w`,string:!0,desc:`prefix for Webcomponents, e.g "c4" generates <c4-view ../>`,default:`likec4`,nargs:1},on={alias:`t`,string:!0,desc:`base title of the app pages (default is "LikeC4")`,default:`LikeC4`,nargs:1},sn={choices:[`light`,`dark`],desc:`default color scheme for the built website (default: auto, follows system preference)`,nargs:1},cn={alias:[`base-url`],string:!0,desc:`base url the app is being served from, e.g. "/" or "/pages/"`,nargs:1},ln={boolean:!0,desc:`outputs a single self-contained HTML file with all required resources inlined`},un={alias:`public-dir`,string:!0,desc:`directory whose files are copied to the output as-is (Vite publicDir, e.g. images linked from views)`,normalize:!0,nargs:1,coerce:H},dn={array:!0,string:!0,desc:`hostname allowed to respond to (Vite server.allowedHosts); can be repeated. Defaults to allowing all hosts.`,requiresArg:!0},fn={alias:`l`,string:!0,...k()?{desc:`listen 0.0.0.0 by default in container`,default:`0.0.0.0`}:{desc:`ip address of the network interface to listen on`},nargs:1},pn={number:!0,desc:`port number for the dev server (default is 5173, or PORT environment variable)`,nargs:1},mn={number:!0,desc:`port number for the HMR WebSocket server (default is auto-discovered from 24678-24690, or HMR_PORT environment variable)`,nargs:1},Z={alias:`p`,string:!0,desc:`select LikeC4 project by name (e.g. "my-project") or by path`,nargs:1},hn={hidden:!0,nargs:1,desc:`force log level`,choices:[`trace`,`debug`,`info`,`warning`,`error`],conflicts:[`verbose`]},gn={boolean:!0,desc:`verbose logging`,conflicts:[`log-level`]},_n=Pt?`trace`:`debug`,vn={name:Zt,version:Qt},yn=de(()=>new Ie({projectName:Zt,clearInvalidConfig:!0})),bn=1e3*60,xn=bn*60*24*7;function showSupportUsMessage(){if(!Nt)try{let e=yn(),t=e.get(`lastSupportUsMessage`);if(!t){e.set(`lastSupportUsMessage`,Date.now()-xn+5*bn);return}if(t+xn>Date.now())return;e.set(`lastSupportUsMessage`,Date.now()),boxen([C.dim(`If you are working in a commercial environment`),C.dim(`consider supporting the project`),``,C.dim(`How to get more?`)+` `+C.underline(`https://likec4.dev/sponsor/`)].join(`
143
+ `))}catch{}}function _usingCtx(){var e=typeof SuppressedError==`function`?SuppressedError:function(e,t){var n=Error();return n.name=`SuppressedError`,n.error=e,n.suppressed=t,n},t={},n=[];function using(e,t){if(t!=null){if(Object(t)!==t)throw TypeError(`using declarations can only be used with objects, functions, null, or undefined.`);if(e)var r=t[Symbol.asyncDispose||Symbol.for(`Symbol.asyncDispose`)];if(r===void 0&&(r=t[Symbol.dispose||Symbol.for(`Symbol.dispose`)],e))var i=r;if(typeof r!=`function`)throw TypeError(`Object is not disposable.`);i&&(r=function o(){try{i.call(t)}catch(e){return Promise.reject(e)}}),n.push({v:t,d:r,a:e})}else e&&n.push({d:t,a:e});return t}return{e:t,u:using.bind(null,!1),a:using.bind(null,!0),d:function d(){var r,i=this.e,a=0;function next(){for(;r=n.pop();)try{if(!r.a&&a===1)return a=0,n.push(r),Promise.resolve().then(next);if(r.d){var e=r.d.call(r.v);if(r.a)return a|=2,Promise.resolve(e).then(next,err)}else a|=1}catch(e){return err(e)}if(a===1)return i===t?Promise.resolve():Promise.reject(i);if(i!==t)throw i}function err(n){return i=i===t?n:new e(n,i),next()}return next()}}}const buildCmd=e=>e.command({command:`build [path]`,aliases:[`bundle`],describe:`Build a static website`,builder:e=>e.positional(`path`,J).option(`output`,{alias:`o`,type:`string`,desc:`output directory for production build`,normalize:!0,coerce:H}).option(`base`,cn).option(`use-hash-history`,rn).option(`use-dot`,Y).option(`webcomponent-prefix`,an).option(`title`,on).option(`output-single-file`,ln).option(`public`,un).option(`theme`,sn).example(`${C.green(`$0 build -o ./build ./src`)}`,C.gray(`Search for likec4 files in 'src' and output static site to 'build'`)).example(`${C.green(`$0 build --theme dark -o ./build ./src`)}`,C.gray(`Build with dark color scheme as default`)).example(`${C.green(`$0 build --public ./assets -o ./build ./src`)}`,C.gray(`Copy files from 'assets' to the output directory as-is`)),handler:async e=>{try{var t=_usingCtx();let n={useHashHistory:e[`use-hash-history`]??!1,useDotBin:e[`use-dot`],webcomponentPrefix:e[`webcomponent-prefix`],outputSingleFile:e[`output-single-file`]??!1};await ensureReact();let r=createLikeC4Logger(`c4:build`),i=t.a(await c(e.path,{graphviz:e[`use-dot`]?`binary`:`wasm`,watch:!1})),a=e.output??H(i.workspace,`dist`),s=H(a,`assets`);await viteBuild({base:e.base,useHashHistory:n.outputSingleFile||n.useHashHistory,customLogger:r,webcomponentPrefix:n.webcomponentPrefix,title:e.title,theme:e.theme,languageServices:i,likec4AssetsDir:s,outputDir:a,outputSingleFile:n.outputSingleFile,userPublicDir:e.public}),showSupportUsMessage()}catch(e){t.e=e}finally{await t.d()}}});var Sn=e(Fe(),1);const Cn=`check-update`;async function notifyAvailableUpdate(){if(Nt||Ft||It===Cn)return;let e=yn(),t=e.get(`lastUpdateCheck`);if(!t){await checkAvailableUpdate(!1);return}let n=e.get(`latestVersion`);if(oe(n)||oe(t)||t+864e5<Date.now())try{ht(`likec4`,[`check-update`],{stdio:`ignore`,timeout:5e3,preferLocal:!0,detached:!0,env:{NODE_ENV:Cn}}).catch(()=>{})}catch{}n&&(0,Sn.gt)(n,vn.version)&&boxen([`Update available: `,C.dim(vn.version),C.reset(` → `),C.green(n)].join(``))}async function checkAvailableUpdate(e=!0){try{let t=yn();t.set({lastUpdateCheck:Date.now()});let n=await fetchLatestVersion();U(n,`No version found in latest npm`),t.set({lastUpdateCheck:Date.now(),latestVersion:n}),(0,Sn.gt)(n,vn.version)?boxen([`Update available: `,C.dim(vn.version),C.reset(` → `),C.green(n)].join(``)):e&&boxen(C.dim(`Up to date: `)+` `+C.green(vn.version))}catch(e){q.warning(u(e))}}async function fetchLatestVersion(){return(await Ue(`https://registry.npmjs.org/likec4/latest`,{headers:{accept:`application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*`},timeout:5e3,keepalive:!0}).json()).version}const checkUpdateCmd=e=>e.command({command:`check-update`,describe:`Check for updates`,handler:async()=>{await checkAvailableUpdate()}});function ensureProjectId(e,t){if(!t)return e.languageServices.projectsManager.ensureProjectId();let n=H(t);if(n===e.workspace)return e.languageServices.projectsManager.ensureProjectId();if(W(n)&&xt(n).isDirectory()){q.debug`Project path exists: ${n}`;let t=_.file(n.endsWith(et)?n:n+et),r=e.languageServices.projects().find(e=>e.folder.fsPath===t.fsPath);if(r)return q.debug`Found project ${r.id} at path: ${n}`,r.id;q.debug`No project registered at path: ${n}`}return e.languageServices.projectsManager.ensureProjectId(t)}function ensureProject(e,t){let n=ensureProjectId(e,t),r=e.languageServices.projectsManager.getProject(n);return e.languageServices.projectsManager.defaultProjectId=n,{projectId:n,projectFolder:r.folderUri.fsPath,config:r.config}}const wn=q.getChild(`generator`);async function customHandler({name:e,path:t,useDotBin:n,project:r}){try{var i=_usingCtx();let a=startTimer(wn),s=i.a(await c(t,{graphviz:n?`binary`:`wasm`,watch:!1})),{projectId:l,config:u}=ensureProject(s,r);r&&wn.info(`${C.dim(`project`)} ${C.green(l)}`);let f=u.generators?.[e];if(!f)throw wn.error(C.red(`generator ${e} does not exist in project config`)),Error(`generator ${e} does not exist in project config`);wn.info(`${C.dim(`generator`)} ${C.green(e)}`),await runCustomGenerator({likec4:s,model:await s.layoutedModel(l),generator:f,logger:wn.getChild(e)}),a.stopAndLog()}catch(e){i.e=e}finally{await i.d()}}async function runCustomGenerator({likec4:e,model:t,generator:n,logger:r}){let i=e.languageServices,a=new Set,s=i.project(t.project.id),c=t.project.id;r.debug(`${C.dim(`running for project:`)} ${C.green(s.id)}`),await Promise.resolve().then(()=>n({likec4model:t,ctx:{workspace:e.languageServices.workspaceUri,project:s,locate:e=>{let t=null;switch(!0){case dt(e):t=i.locate({element:e.id,projectId:c});break;case ft(e):t=i.locate({view:e.id,projectId:c});break;case ct(e):t=i.locate({deployment:e.id,projectId:c});break;case pt(e):case ut(e):t=i.locate({relation:e.id,projectId:c});break;default:nt(e)}if(!t)throw r.error(`Cannot locate ${e.id}`,{target:e}),Error(`Cannot locate ${e.id}`);let n=_.parse(t.uri);return{range:t.range,document:n,relativePath:g.relative(s.folder,n),folder:g.dirname(n).fsPath,filename:g.basename(n)}},write:async({path:e,content:t})=>{let n;n=Array.isArray(e)?H(s.folder.fsPath,...e):_.isUri(e)?e.fsPath:H(s.folder.fsPath,`${e}`);let i=z(n);a.has(i)||(W(i)||(r.debug(`${C.dim(`create directory`)} ${i}`),await G(i,{recursive:!0})),a.add(i)),r.debug(`${C.dim(`write`)} ${n}`),await K(n,t)},abort:e=>{throw r.error(e||`Generator aborted`),Error(e||`Generator aborted`)}}}))}async function singleFileCodegenAction(e,t,n){t??=H(e.workspace,`likec4.generated.ts`),Qe(t)!==`.ts`&&(t+=`.ts`),await G(z(t),{recursive:!0});let r=generateViewsDataTs([...await e.diagrams()]);await K(t,r),n.info(`${C.dim(`generated`)} ${V(process.cwd(),t)}`)}async function dotCodegenAction(e,t,n){await G(t,{recursive:!0}),n.info(`${C.dim(`format`)} ${C.green(`dot`)}`),n.info(`${C.dim(`outdir`)} ${t}`);let r=new Set,i=await e.computedModel(),a=me(i.$data.views),s=0;for(let c of a)try{let a=await e.viewsService.layouter.dot({view:c,styles:i.$styles}),l=`.`;c.sourcePath&&(l=z(c.sourcePath)),l=H(t,l),r.has(l)||(await G(l,{recursive:!0}),r.add(l));let u=H(l,c.id+`.dot`);await K(u,a),n.info(`${C.dim(`generated`)} ${V(process.cwd(),u)}`),s++}catch(e){q.error(`error while generating ${c.id}`,{error:e})}s>0&&n.info(`${C.dim(`total`)} ${s} files`)}async function multipleFilesCodegenAction(e,t,n,r){await G(n,{recursive:!0}),r.info(`${C.dim(`format`)} ${C.green(t)}`),r.info(`${C.dim(`outdir`)} ${n}`);let i,a;switch(t){case`d2`:i=`.d2`,a=we;break;case`mermaid`:i=`.mmd`,a=ke;break;case`plantuml`:i=`.puml`,a=De;break;default:nt(t)}let s=new Set,c=await e.layoutedModel(),l=0;for(let e of c.views()){let t=e.$view;try{let c=`.`;t.sourcePath&&(c=z(t.sourcePath)),c=H(n,c),s.has(c)||(await G(c,{recursive:!0}),s.add(c));let u=H(c,t.id+i);await K(u,a(e)),r.info(`${C.dim(`generated`)} ${V(process.cwd(),u)}`),l++}catch(e){r.error(`error while generating ${t.id}`,{error:e})}}l>0&&r.info(`${C.dim(`total`)} ${l} files`)}async function legacyHandler({path:e,useDotBin:t,...n}){let r=createLikeC4Logger(`c4:codegen`),i=startTimer(r),a=await c(e,{graphviz:t?`binary`:`wasm`,watch:!1});if(a.ensureSingleProject(),(await a.viewsService.computedViews()).length===0)throw r.warn(`no views found`),process.exitCode=1,Error(`no views found`);switch(n.format){case`views`:await singleFileCodegenAction(a,n.outfile,r);break;case`dot`:await dotCodegenAction(a,n.outdir??e,r);break;case`d2`:case`mermaid`:case`plantuml`:await multipleFilesCodegenAction(a,n.format,n.outdir??e,r);break;default:nt(n)}i.stopAndLog()}const Tn=z(At(import.meta.url));function readVersion(){try{let e=JSON.parse(vt(B(Tn,`..`,`package.json`),`utf8`));if(e.version)return e.version}catch{}try{let e=JSON.parse(vt(B(Tn,`..`,`..`,`package.json`),`utf8`));if(e.version)return e.version}catch{}return`0.1.0`}const En=readVersion(),Dn=`leanix`,On=new Set([`factSheetTypes`,`relationTypes`,`metadataToFields`]);function isPlainObjectRecordOfStrings(e){if(typeof e!=`object`||!e||Array.isArray(e))return!1;for(let t of Object.values(e))if(typeof t!=`string`)return!1;return!0}function parseLeanixMappingInput(e){if(e==null)return e;if(typeof e!=`object`||Array.isArray(e))throw Error(`LeanIX mapping must be a plain object (not an array or primitive)`);let t=e;for(let e of Object.keys(t))if(!On.has(e))throw Error(`LeanIX mapping has unknown key "${e}". Allowed: factSheetTypes, relationTypes, metadataToFields`);if(t.factSheetTypes!==void 0&&!isPlainObjectRecordOfStrings(t.factSheetTypes))throw Error(`LeanIX mapping "factSheetTypes" must be an object with string keys and string values`);if(t.relationTypes!==void 0&&!isPlainObjectRecordOfStrings(t.relationTypes))throw Error(`LeanIX mapping "relationTypes" must be an object with string keys and string values`);if(t.metadataToFields!==void 0&&!isPlainObjectRecordOfStrings(t.metadataToFields))throw Error(`LeanIX mapping "metadataToFields" must be an object with string keys and string values`);return e}const kn={factSheetTypes:{system:`Application`,container:`ITComponent`,component:`ITComponent`,actor:`Provider`},relationTypes:{default:`depends on`},metadataToFields:{title:`name`,description:`description`,technology:`technology`}};function mergeWithDefault(e){let t=parseLeanixMappingInput(e),n={factSheetTypes:{...kn.factSheetTypes},relationTypes:{...kn.relationTypes},metadataToFields:{...kn.metadataToFields}};return t?{factSheetTypes:{...n.factSheetTypes,...t.factSheetTypes},relationTypes:{...n.relationTypes,...t.relationTypes},metadataToFields:{...n.metadataToFields,...t.metadataToFields}}:n}function getFactSheetType(e,t){return t.factSheetTypes[e]??t.factSheetTypes.default??`Application`}function getRelationType(e,t){let n=e??`default`;return t.relationTypes[n]??t.relationTypes.default??`depends on`}const An={manifestVersion:`1.0`,bridgeVersion:En,mappingProfile:`default`};function buildManifestEntities(e){let t={};for(let n of e.elements())t[n.id]={canonicalId:n.id,external:{}};return t}function buildManifestViews(e){let t={};for(let n of e.views())t[n.id]={viewId:n.id,external:{}};return t}function buildManifestRelations(e){let t=[];for(let n of e.relationships())t.push({relationId:n.id,sourceFqn:n.source.id,targetFqn:n.target.id,compositeKey:`${n.source.id}|${n.target.id}|${n.id}`,external:{}});return t}function toBridgeManifest(e,t={}){let n={...An,...t,generatedAt:t.generatedAt??new Date().toISOString()};return{manifestVersion:n.manifestVersion,generatedAt:n.generatedAt,bridgeVersion:n.bridgeVersion,mappingProfile:n.mappingProfile,projectId:e.projectId,entities:buildManifestEntities(e),views:buildManifestViews(e),relations:buildManifestRelations(e)}}function buildFactSheetsFromModel(e,t){let n=[];for(let r of e.elements()){let e=getFactSheetType(r.kind,t),i=r.getMetadata(),a=typeof i.description==`string`?i.description:void 0,s=r.technology??(typeof i.technology==`string`?i.technology:void 0);n.push({type:e,likec4Id:r.id,name:r.title,...a!==void 0&&{description:a},...s!==void 0&&{technology:s},...r.tags.length>0&&{tags:[...r.tags]},...Object.keys(i).length>0&&{metadata:{...i}}})}return n.sort((e,t)=>e.likec4Id.localeCompare(t.likec4Id)),n}function buildRelationsFromModel(e,t){let n=[];for(let r of e.relationships()){let e=r.title??r.kind;n.push({type:getRelationType(r.kind,t),likec4RelationId:r.id,sourceLikec4Id:r.source.id,targetLikec4Id:r.target.id,...e!=null&&e!==``&&{title:String(e)}})}return n.sort((e,t)=>e.likec4RelationId.localeCompare(t.likec4RelationId)),n}function toLeanixInventoryDryRun(e,t={}){let n=mergeWithDefault(t.mapping),r=t.generatedAt??new Date().toISOString(),i=t.mappingProfile??(t.mapping?`custom`:`default`);return{generatedAt:r,projectId:e.projectId,mappingProfile:i,factSheets:buildFactSheetsFromModel(e,n),relations:buildRelationsFromModel(e,n)}}function buildCoherenceErrorMessage(e,t){let n=[];return e.projectId!==t.projectId&&n.push(`projectId (manifest: ${e.projectId}, leanixDryRun: ${t.projectId})`),e.mappingProfile!==t.mappingProfile&&n.push(`mappingProfile (manifest: ${e.mappingProfile}, leanixDryRun: ${t.mappingProfile})`),`Manifest and LeanIX dry-run must belong to the same run. Mismatch: ${n.join(`; `)}`}function buildBridgeReport(e,t){if(e.projectId!==t.projectId||e.mappingProfile!==t.mappingProfile)throw Error(buildCoherenceErrorMessage(e,t));return{generatedAt:e.generatedAt,projectId:e.projectId,manifestVersion:e.manifestVersion,bridgeVersion:e.bridgeVersion,mappingProfile:e.mappingProfile,counts:{entities:Object.keys(e.entities).length,views:Object.keys(e.views).length,relations:e.relations.length,factSheets:t.factSheets.length,leanixRelations:t.relations.length},artifacts:{manifest:`manifest.json`,leanixDryRun:`leanix-dry-run.json`}}}var LeanixApiError=class extends Error{statusCode;graphqlErrors;constructor(e,t,n){super(e),this.statusCode=t,this.graphqlErrors=n,this.name=`LeanixApiError`}};function sleep(e){return new Promise(t=>setTimeout(t,e))}var LeanixApiClient=class{baseUrl;apiToken;requestDelayMs;lastRequestTime=0;rateLimitLock=Promise.resolve();constructor(e){this.apiToken=e.apiToken,this.baseUrl=(e.baseUrl??`https://app.leanix.net`).replace(/\/$/,``),this.requestDelayMs=e.requestDelayMs??200}async graphql(e,t){let run=async()=>{let n=Date.now()-this.lastRequestTime;n<this.requestDelayMs&&await sleep(this.requestDelayMs-n),this.lastRequestTime=Date.now();let r=`${this.baseUrl}/services/pathfinder/v1/graphql`,i;try{i=await fetch(r,{method:`POST`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${this.apiToken}`},body:JSON.stringify({query:e,variables:t})})}catch(e){throw new LeanixApiError(`GraphQL request failed: ${r} POST - ${e instanceof Error?e.message:String(e)}`)}let a;try{a=await i.json()}catch(e){let t=e instanceof Error?e.message:String(e);throw new LeanixApiError(`Invalid JSON response: ${r} ${i.status} ${i.statusText} - ${t}`,i.status)}if(!i.ok)throw new LeanixApiError(a.errors?.[0]?.message??`HTTP ${i.status} ${i.statusText}`,i.status,a.errors);if(a.errors&&a.errors.length>0)throw new LeanixApiError(a.errors.map(e=>e.message).join(`; `),i.status,a.errors);if(a.data===void 0)throw new LeanixApiError(`GraphQL response had no data and no errors`);return a.data},n=this.rateLimitLock,r;this.rateLimitLock=new Promise(e=>{r=e}),await n;try{return await run()}finally{r()}}};async function findFactSheetByNameAndType(e,t,n){let r=(await e.graphql(`
144
144
  query FindFactSheet($name: String!, $type: String!) {
145
145
  allFactSheets(filter: { name: $name, factSheetType: $type }) {
146
146
  edges { node { id name type } }
@@ -170,7 +170,7 @@ export {
170
170
  relation { id }
171
171
  }
172
172
  }
173
- `,{source:t,target:n,type:r}),s=a.createRelation?.relation?.id;if(!s){let e=JSON.stringify(a,null,2);throw Error(`createRelation did not return relation id (sourceFactSheetId=${t}, targetFactSheetId=${n}, relationType=${r}). Response: ${e}`)}return s}function buildFactSheetPlanEntry(e,t){let n=t?`update`:`create`;return{likec4Id:e.likec4Id,name:e.name,type:e.type,action:n,...t?{existingFactSheetId:t}:{}}}function buildPlanSummary(e,t){return{factSheetsToCreate:e.filter(e=>e.action===`create`).length,factSheetsToUpdate:e.filter(e=>e.action===`update`).length,relationsToCreate:t.length}}function toErrorMessage(e){if(e instanceof Error)return e.stack?`${e.message}\n${e.stack}`:e.message;if(typeof e==`object`&&e)try{return JSON.stringify(e,null,2)}catch{return Object.prototype.toString.call(e)}return String(e)}function applyLeanixIdsToEntities(e,t){let n={...e};for(let[r,i]of Object.entries(e)){let e=t.get(r);e&&(n[r]={...i,external:{...i.external,[_n]:{factSheetId:e,externalId:e}}})}return n}async function resolveExistingFactSheetId(e,t,n,r){if(!n)return null;if(r){let n=await findFactSheetByLikec4IdAttribute(e,r,t.likec4Id);if(n)return n;let i=await findFactSheetByNameAndType(e,t.name,t.type);if(i&&t.likec4Id)try{await patchFactSheetAttribute(e,i,r,t.likec4Id)}catch(e){console.warn(`[leanix-bridge] Failed to backfill likec4Id on fact sheet ${i} (${t.name}/${t.type}): ${e instanceof Error?e.message:String(e)}. Reusing ID.`)}return i??null}return findFactSheetByNameAndType(e,t.name,t.type)}async function syncFactSheetsToLeanix(e,t,n,r){let i=new Map,a=[],s=0,c=0;for(let l of t)try{let t=await resolveExistingFactSheetId(e,l,n,r);t&&c++,t||(t=await createFactSheet(e,l,r),s++),t&&i.set(l.likec4Id,t)}catch(e){a.push(`Fact sheet ${l.likec4Id} (${String(l.name)}): ${toErrorMessage(e)}`)}return{likec4IdToFactSheetId:i,factSheetsCreated:s,factSheetsReused:c,errors:a}}async function syncRelationsToLeanix(e,t,n,r){let i=[],a=[],s=0;for(let c of t){let t=r.get(c.sourceFqn),l=r.get(c.targetFqn),u=c.external?.[_n];if(t&&l&&!u?.relationId){let r=n.find(e=>e.sourceLikec4Id===c.sourceFqn&&e.targetLikec4Id===c.targetFqn&&e.likec4RelationId===c.relationId);if(r)try{let n=await createRelation(e,t,l,r.type,r.title);s++,i.push({...c,external:{...c.external,[_n]:{relationId:n,...c.external?.[_n]}}});continue}catch(e){a.push(`Relation ${c.compositeKey}: ${toErrorMessage(e)}`)}}i.push(c)}return{updatedRelations:i,relationsCreated:s,errors:a}}async function planSyncToLeanix(e,t,n={}){let r=n.idempotent??!0,i=n.likec4IdAttribute,a=n.generatedAt??new Date().toISOString(),s=[],c=[];for(let n of e.factSheets)try{let e=null;r&&(i?(e=await findFactSheetByLikec4IdAttribute(t,i,n.likec4Id),e||=await findFactSheetByNameAndType(t,n.name,n.type)):e=await findFactSheetByNameAndType(t,n.name,n.type)),c.push(buildFactSheetPlanEntry(n,e))}catch(e){s.push(`Fact sheet ${n.likec4Id} (${String(n.name)}): ${toErrorMessage(e)}`),c.push(buildFactSheetPlanEntry(n,null))}let l=e.relations.map(e=>({likec4RelationId:e.likec4RelationId,sourceLikec4Id:e.sourceLikec4Id,targetLikec4Id:e.targetLikec4Id,type:e.type,action:`create`}));return{generatedAt:a,projectId:e.projectId,mappingProfile:e.mappingProfile,summary:buildPlanSummary(c,l),factSheetPlans:c,relationPlans:l,errors:s}}async function syncToLeanix(e,t,n,r={}){let i=r.idempotent??!0,a=r.likec4IdAttribute,s=await syncFactSheetsToLeanix(n,t.factSheets,i,a),c=applyLeanixIdsToEntities(e.entities,s.likec4IdToFactSheetId),l=await syncRelationsToLeanix(n,e.relations,t.relations,s.likec4IdToFactSheetId);return{manifest:{...e,entities:c,relations:l.updatedRelations},factSheetsCreated:s.factSheetsCreated,factSheetsReused:s.factSheetsReused,relationsCreated:l.relationsCreated,errors:[...s.errors,...l.errors]}}async function withGraphQLRetry(e){let t;for(let n=0;n<3;n++)try{return await e()}catch(e){t=e,n<2&&await new Promise(e=>setTimeout(e,500*(n+1)))}throw t}async function fetchLeanixInventorySnapshot(e,t={}){let n=t.generatedAt??new Date().toISOString(),r=t.maxFactSheets??1e3;if(!Number.isInteger(r)||r<0)throw Error(`maxFactSheets must be a non-negative integer`);let i=t.likec4IdAttribute,a=await fetchAllFactSheets(e,{...i==null?{}:{likec4IdAttribute:i},maxFactSheets:r});return{generatedAt:n,factSheets:a,relations:await fetchAllRelations(e,a.map(e=>e.id))}}function mapNodeToFactSheetItem(e,t){if(!e?.id)return null;let n=t!=null&&Array.isArray(e.factSheetAttributes)?e.factSheetAttributes.find(e=>e.key===t)?.value:void 0;return{id:e.id,name:e.name??``,type:e.type??``,...n?{likec4Id:n}:{}}}async function fetchAllFactSheets(e,t){let n=t.likec4IdAttribute,r=Math.min(100,t.maxFactSheets),i=[],a=null,s=!0,c=`
173
+ `,{source:t,target:n,type:r}),s=a.createRelation?.relation?.id;if(!s){let e=JSON.stringify(a,null,2);throw Error(`createRelation did not return relation id (sourceFactSheetId=${t}, targetFactSheetId=${n}, relationType=${r}). Response: ${e}`)}return s}function buildFactSheetPlanEntry(e,t){let n=t?`update`:`create`;return{likec4Id:e.likec4Id,name:e.name,type:e.type,action:n,...t?{existingFactSheetId:t}:{}}}function buildPlanSummary(e,t){return{factSheetsToCreate:e.filter(e=>e.action===`create`).length,factSheetsToUpdate:e.filter(e=>e.action===`update`).length,relationsToCreate:t.length}}function toErrorMessage(e){if(e instanceof Error)return e.stack?`${e.message}\n${e.stack}`:e.message;if(typeof e==`object`&&e)try{return JSON.stringify(e,null,2)}catch{return Object.prototype.toString.call(e)}return String(e)}function applyLeanixIdsToEntities(e,t){let n={...e};for(let[r,i]of Object.entries(e)){let e=t.get(r);e&&(n[r]={...i,external:{...i.external,[Dn]:{factSheetId:e,externalId:e}}})}return n}async function resolveExistingFactSheetId(e,t,n,r){if(!n)return null;if(r){let n=await findFactSheetByLikec4IdAttribute(e,r,t.likec4Id);if(n)return n;let i=await findFactSheetByNameAndType(e,t.name,t.type);if(i&&t.likec4Id)try{await patchFactSheetAttribute(e,i,r,t.likec4Id)}catch(e){console.warn(`[leanix-bridge] Failed to backfill likec4Id on fact sheet ${i} (${t.name}/${t.type}): ${e instanceof Error?e.message:String(e)}. Reusing ID.`)}return i??null}return findFactSheetByNameAndType(e,t.name,t.type)}async function syncFactSheetsToLeanix(e,t,n,r){let i=new Map,a=[],s=0,c=0;for(let l of t)try{let t=await resolveExistingFactSheetId(e,l,n,r);t&&c++,t||(t=await createFactSheet(e,l,r),s++),t&&i.set(l.likec4Id,t)}catch(e){a.push(`Fact sheet ${l.likec4Id} (${String(l.name)}): ${toErrorMessage(e)}`)}return{likec4IdToFactSheetId:i,factSheetsCreated:s,factSheetsReused:c,errors:a}}async function syncRelationsToLeanix(e,t,n,r){let i=[],a=[],s=0;for(let c of t){let t=r.get(c.sourceFqn),l=r.get(c.targetFqn),u=c.external?.[Dn];if(t&&l&&!u?.relationId){let r=n.find(e=>e.sourceLikec4Id===c.sourceFqn&&e.targetLikec4Id===c.targetFqn&&e.likec4RelationId===c.relationId);if(r)try{let n=await createRelation(e,t,l,r.type,r.title);s++,i.push({...c,external:{...c.external,[Dn]:{relationId:n,...c.external?.[Dn]}}});continue}catch(e){a.push(`Relation ${c.compositeKey}: ${toErrorMessage(e)}`)}}i.push(c)}return{updatedRelations:i,relationsCreated:s,errors:a}}async function planSyncToLeanix(e,t,n={}){let r=n.idempotent??!0,i=n.likec4IdAttribute,a=n.generatedAt??new Date().toISOString(),s=[],c=[];for(let n of e.factSheets)try{let e=null;r&&(i?(e=await findFactSheetByLikec4IdAttribute(t,i,n.likec4Id),e||=await findFactSheetByNameAndType(t,n.name,n.type)):e=await findFactSheetByNameAndType(t,n.name,n.type)),c.push(buildFactSheetPlanEntry(n,e))}catch(e){s.push(`Fact sheet ${n.likec4Id} (${String(n.name)}): ${toErrorMessage(e)}`),c.push(buildFactSheetPlanEntry(n,null))}let l=e.relations.map(e=>({likec4RelationId:e.likec4RelationId,sourceLikec4Id:e.sourceLikec4Id,targetLikec4Id:e.targetLikec4Id,type:e.type,action:`create`}));return{generatedAt:a,projectId:e.projectId,mappingProfile:e.mappingProfile,summary:buildPlanSummary(c,l),factSheetPlans:c,relationPlans:l,errors:s}}async function syncToLeanix(e,t,n,r={}){let i=r.idempotent??!0,a=r.likec4IdAttribute,s=await syncFactSheetsToLeanix(n,t.factSheets,i,a),c=applyLeanixIdsToEntities(e.entities,s.likec4IdToFactSheetId),l=await syncRelationsToLeanix(n,e.relations,t.relations,s.likec4IdToFactSheetId);return{manifest:{...e,entities:c,relations:l.updatedRelations},factSheetsCreated:s.factSheetsCreated,factSheetsReused:s.factSheetsReused,relationsCreated:l.relationsCreated,errors:[...s.errors,...l.errors]}}async function withGraphQLRetry(e){let t;for(let n=0;n<3;n++)try{return await e()}catch(e){t=e,n<2&&await new Promise(e=>setTimeout(e,500*(n+1)))}throw t}async function fetchLeanixInventorySnapshot(e,t={}){let n=t.generatedAt??new Date().toISOString(),r=t.maxFactSheets??1e3;if(!Number.isInteger(r)||r<0)throw Error(`maxFactSheets must be a non-negative integer`);let i=t.likec4IdAttribute,a=await fetchAllFactSheets(e,{...i==null?{}:{likec4IdAttribute:i},maxFactSheets:r});return{generatedAt:n,factSheets:a,relations:await fetchAllRelations(e,a.map(e=>e.id))}}function mapNodeToFactSheetItem(e,t){if(!e?.id)return null;let n=t!=null&&Array.isArray(e.factSheetAttributes)?e.factSheetAttributes.find(e=>e.key===t)?.value:void 0;return{id:e.id,name:e.name??``,type:e.type??``,...n?{likec4Id:n}:{}}}async function fetchAllFactSheets(e,t){let n=t.likec4IdAttribute,r=Math.min(100,t.maxFactSheets),i=[],a=null,s=!0,c=`
174
174
  query AllFactSheets($first: Int!, $after: String, $filter: FilterInput) {
175
175
  allFactSheets(first: $first, after: $after, filter: $filter) {
176
176
  edges {
@@ -204,26 +204,26 @@ export {
204
204
  }
205
205
  }
206
206
  }
207
- `,{id:t,first:100,after:i})),c=s?.factSheet?.relations?.edges??[],l=s?.factSheet?.relations?.pageInfo;for(let e of c){let i=e.node,a=i?.targetFactSheet?.id;!a||!r.has(a)||n.push({...i?.id?{id:i.id}:{},sourceFactSheetId:t,targetFactSheetId:a,type:i?.type??`RELATES_TO`})}a=l?.hasNextPage===!0,i=l?.endCursor??null}return n}for(let e=0;e<t.length;e+=10){let r=t.slice(e,e+10),i=await Promise.all(r.map(e=>fetchRelationsForFactSheet(e)));for(let e of i)n.push(...e)}return n}function tryMatchByManifestFactSheetId(e,t,n,r){let i=e.external?.[_n],a=i?.factSheetId??i?.externalId;if(a==null)return null;let s=n.get(a);return!s||r.has(s.id)?null:(r.add(s.id),{canonicalId:t,factSheetId:s.id,name:s.name,type:s.type})}function tryMatchByLikec4Id(e,t,n){let r=t.get(e);return!r||n.has(r.id)?null:(n.add(r.id),{canonicalId:e,factSheetId:r.id,name:r.name,type:r.type})}function resolveByNameAndType(e,t,n,r,i,a,s,c){let l=`${t??e}${n??``}`,u=r.get(l)?.filter(e=>!i.has(e.id))??[];if(u.length===0)s.push({canonicalId:e,...t===void 0?{}:{name:t},...n===void 0?{}:{type:n}});else if(u.length===1){let t=u[0];a.push({canonicalId:e,factSheetId:t.id,name:t.name,type:t.type}),i.add(t.id)}else c.push({canonicalId:e,...t===void 0?{}:{name:t},...n===void 0?{}:{type:n},candidateFactSheetIds:u.map(e=>e.id)})}function reconcileInventoryWithManifest(e,t,n={}){let r=n.generatedAt??new Date().toISOString(),i=n.dryRun,a=[],s=[],c=[],l=new Map(e.factSheets.map(e=>[e.id,e])),u=new Map,f=new Map;for(let t of e.factSheets){t.likec4Id&&u.set(t.likec4Id,t);let e=`${t.name}${t.type}`;f.has(e)||f.set(e,[]),f.get(e).push(t)}let p=i?new Map(i.factSheets.map(e=>[e.likec4Id,e])):null,m=new Set;for(let[e,n]of Object.entries(t.entities)){let t=tryMatchByManifestFactSheetId(n,e,l,m);if(t){a.push(t);continue}let r=tryMatchByLikec4Id(e,u,m);if(r){a.push(r);continue}let i=p?.get(e);resolveByNameAndType(e,i?.name??void 0,i?.type??void 0,f,m,a,s,c)}let h=e.factSheets.filter(e=>!m.has(e.id)).map(e=>({factSheetId:e.id,name:e.name,type:e.type,...e.likec4Id?{likec4Id:e.likec4Id}:{}}));return{generatedAt:r,manifestProjectId:t.projectId,snapshotGeneratedAt:e.generatedAt,matched:a,unmatchedInLikec4:s,unmatchedInLeanix:h,ambiguous:c,summary:{matched:a.length,unmatchedInLikec4:s.length,unmatchedInLeanix:h.length,ambiguous:c.length}}}function isRecord(e){return typeof e==`object`&&!!e}function isManifestEntity(e){return isRecord(e)?typeof e.canonicalId==`string`:!1}function isManifestView(e){return isRecord(e)?typeof e.viewId==`string`:!1}function isManifestRelation(e){return isRecord(e)?typeof e.relationId==`string`&&typeof e.sourceFqn==`string`&&typeof e.targetFqn==`string`&&typeof e.compositeKey==`string`:!1}function isLeanixFactSheetSnapshotItem(e){return isRecord(e)?typeof e.id==`string`&&typeof e.name==`string`&&typeof e.type==`string`:!1}function isLeanixRelationSnapshotItem(e){return isRecord(e)?typeof e.sourceFactSheetId==`string`&&typeof e.targetFactSheetId==`string`&&typeof e.type==`string`:!1}function isBridgeManifest(e){if(!isRecord(e)||typeof e.manifestVersion!=`string`||typeof e.generatedAt!=`string`||typeof e.bridgeVersion!=`string`||typeof e.mappingProfile!=`string`||typeof e.projectId!=`string`)return!1;let t=e.entities;if(typeof t!=`object`||!t||Array.isArray(t))return!1;for(let e of Object.values(t))if(!isManifestEntity(e))return!1;let n=e.views;if(typeof n!=`object`||!n||Array.isArray(n))return!1;for(let e of Object.values(n))if(!isManifestView(e))return!1;let r=e.relations;if(!Array.isArray(r))return!1;for(let e of r)if(!isManifestRelation(e))return!1;return!0}function isLeanixInventorySnapshot(e){if(!isRecord(e)||typeof e.generatedAt!=`string`||e.workspaceId!==void 0&&typeof e.workspaceId!=`string`||!Array.isArray(e.factSheets))return!1;for(let t of e.factSheets)if(!isLeanixFactSheetSnapshotItem(t))return!1;if(!Array.isArray(e.relations))return!1;for(let t of e.relations)if(!isLeanixRelationSnapshotItem(t))return!1;return!0}const xn=`No project or empty model`,Sn=`LEANIX_API_TOKEN is required for likec4 sync leanix --apply`,Cn=`default`,wn=`manifest.json`,Tn=`leanix-dry-run.json`,En=`report.json`;function asBridgeModel(e){return{projectId:String(e.projectId),elements:()=>e.elements(),relationships:()=>e.relationships(),views:()=>e.views()}}function buildBridgeArtifacts(e){let t=toBridgeManifest(e,{mappingProfile:Cn}),n=toLeanixInventoryDryRun(e,{mappingProfile:Cn});return{manifest:t,dryRun:n,report:buildBridgeReport(t,n)}}async function writeBridgeArtifacts(e,t,n,r=process.cwd()){await W(e,{recursive:!0});let i=H(e,wn),a=H(e,Tn),s=H(e,En);await G(i,JSON.stringify(t.manifest,null,2)),await G(a,JSON.stringify(t.dryRun,null,2)),await G(s,JSON.stringify(t.report,null,2)),n.info(`${S.dim(`generated`)} ${V(r,i)}`),n.info(`${S.dim(`generated`)} ${V(r,a)}`),n.info(`${S.dim(`generated`)} ${V(r,s)}`)}const Dn={manifest:wn,dryRun:Tn,report:En};async function leanixDryRunHandler(e){let t=createLikeC4Logger(`c4:gen:leanix:dry-run`),n=startTimer(t),{path:r,outdir:i,project:a,useDotBin:s}=e;try{try{var c=_usingCtx();let e=c.a(await l(r,{graphviz:s?`binary`:`wasm`,watch:!1})),{projectId:n}=ensureProject(e,a);a&&t.info(`${S.dim(`project`)} ${S.green(n)}`);let u=await e.layoutedModel(n);if(u===Oe.EMPTY)throw t.error(xn),Error(xn);await writeBridgeArtifacts(i,buildBridgeArtifacts(asBridgeModel(u)),t)}catch(e){c.e=e}finally{await c.d()}}finally{n.stopAndLog()}}function createLeanixClientFromEnv(){let e=process.env.LEANIX_API_TOKEN?.trim();return e?new LeanixApiClient({apiToken:e,baseUrl:process.env.LEANIX_BASE_URL?.trim()||`https://app.leanix.net`,requestDelayMs:200}):null}function requireLeanixClient(){let e=createLeanixClientFromEnv();if(!e)throw Error(`LEANIX_API_TOKEN is required. Set it in the environment to call the LeanIX API.`);return e}async function leanixInventorySnapshotHandler(e){let t=createLikeC4Logger(`c4:gen:leanix:inventory`),n=startTimer(t),{outdir:r,likec4IdAttribute:i}=e;try{let e=requireLeanixClient(),n={};typeof i==`string`&&i.trim()!==``&&(n.likec4IdAttribute=i.trim());let a=await fetchLeanixInventorySnapshot(e,n);await W(r,{recursive:!0});let s=H(r,`leanix-inventory-snapshot.json`);await G(s,JSON.stringify(a,null,2)),t.info(`${S.dim(`generated`)} ${V(process.cwd(),s)}`),t.info(`${S.dim(`snapshot`)} ${a.factSheets.length} fact sheets, ${a.relations.length} relations`)}finally{n.stopAndLog()}}const On=`manifest.json`,kn=`leanix-inventory-snapshot.json`;async function readManifestAndSnapshot(e){let t=H(e,On),n=H(e,kn),[r,i]=await Promise.all([vt(t,`utf-8`),vt(n,`utf-8`)]),a=JSON.parse(r),s=JSON.parse(i);if(!isBridgeManifest(a))throw Error(`Invalid manifest format: missing manifestVersion, projectId, entities, relations, or views`);if(!isLeanixInventorySnapshot(s))throw Error(`Invalid snapshot format: missing factSheets or relations arrays`);return{manifest:a,snapshot:s}}async function loadDryRunFromWorkspace(e,t,n){try{var r=_usingCtx();let i=r.a(await l(e,{graphviz:n?`binary`:`wasm`,watch:!1})),{projectId:a}=ensureProject(i,t),s=await i.layoutedModel(a);return s===Oe.EMPTY?void 0:buildBridgeArtifacts(asBridgeModel(s)).dryRun}catch(e){r.e=e}finally{await r.d()}}async function leanixReconcileHandler(e){let t=createLikeC4Logger(`c4:gen:leanix:reconcile`),n=startTimer(t),{path:r,outdir:i,project:a,useDotBin:s}=e;try{let e,n;try{let t=await readManifestAndSnapshot(i);e=t.manifest,n=t.snapshot}catch(e){let n=e instanceof Error?e.message:String(e);throw t.error(`Failed to read ${On} or ${kn} from ${i}: ${n}`),e}let c;try{c=await loadDryRunFromWorkspace(r,a,s)}catch(e){let n=e instanceof Error?e.message:String(e);if(a!=null&&a!==``)throw t.error(`Failed to load workspace for dryRun enrichment: ${n}`),e;t.warn(`Could not load workspace for dryRun enrichment; proceeding without it: ${n}`),c=void 0}let l=reconcileInventoryWithManifest(n,e,{...c==null?{}:{dryRun:c}}),u=H(i,`reconciliation-report.json`);await G(u,JSON.stringify(l,null,2)),t.info(`${S.dim(`generated`)} ${V(process.cwd(),u)}`),t.info(`${S.dim(`reconcile`)} matched=${l.summary.matched} unmatchedLikec4=${l.summary.unmatchedInLikec4} unmatchedLeanix=${l.summary.unmatchedInLeanix} ambiguous=${l.summary.ambiguous}`)}finally{n.stopAndLog()}}async function modelHandler({path:e,useDotBin:t,useCorePackage:n,outfile:r,project:i}){try{var a=_usingCtx();let s=createLikeC4Logger(`c4:codegen`),c=startTimer(s),u=a.a(await l(e,{graphviz:t?`binary`:`wasm`,watch:!1})),{projectId:f,projectFolder:p}=ensureProject(u,i);i&&s.info(`${S.dim(`project`)} ${S.green(f)}`),s.info(`${S.dim(`format`)} ${S.green(`model`)}`);let m=await u.layoutedModel(f);for(let e of m.views())e.hasLayoutDrifts&&s.warn(S.yellow(`layout drift detected, view:`)+` `+S.red(e.id));let h=H(u.projectsManager.hasMultipleProjects()?p:u.workspace,`likec4-model.ts`);if(r&&(h=Ye(r)?r:H(r),U(r)&&(await St(r)).isDirectory()))throw Error(`output file is a directory: ${r}`);let g=qe(h);s.info(`${S.dim(`filename`)} ${g}`);let _=Je(g).toLocaleLowerCase();if(![`.ts`,`.mts`,`.cts`].includes(_))throw s.error(`output file ${r} has extension "${_}"`),Error(`output file ${r} must be a .ts, .mts or .cts file`);let v=z(h);s.info(`${S.dim(`outdir`)} ${v}`),await W(v,{recursive:!0}),await G(h,generateLikeC4Model(m,{useCorePackage:n}),{encoding:`utf-8`}),c.stopAndLog(),boxen(ye(`
208
- ${S.dim(`Source generated:`)}
209
- ${V(jt(),h)}
210
-
211
- ${S.dim(`How to use:`)}
212
- ${S.underline(`https://likec4.dev/tooling/code-generation/model/`)}
213
- `).trim(),{padding:1,borderColor:`green`,borderStyle:`round`})}catch(e){a.e=e}finally{await a.d()}}async function viteReactConfig({languageServices:e,outDir:t,filename:n=`likec4-react.mjs`}){let r=createLikeC4Logger([`vite`,`react`]),i=viteAppRoot();return r.info(`${S.cyan(`likec4 app root`)} ${S.dim(relativeToCwd(i))}`),r.info(S.cyan(`outDir`)+` `+S.dim(relativeToCwd(t))),{customLogger:r,root:i,configFile:!1,clearScreen:!1,publicDir:!1,mode:`production`,resolve:{alias:viteAliases()},build:{outDir:t,emptyOutDir:!1,sourcemap:!1,minify:!1,copyPublicDir:!1,lib:{entry:`codegen/react.mjs`,fileName(e,t){return n},formats:[`es`]},rolldownOptions:{external:[`likec4/react`,`likec4/model`,`react`,`react-dom`,`react/jsx-runtime`,`react/jsx-dev-runtime`,`react-dom/client`,/@likec4\/core.*/]}},plugins:[De({languageServices:e.languageServices})]}}async function reactHandler({path:e,useDotBin:t,useCorePackage:n,outfile:r,project:i}){try{var a=_usingCtx();await ensureReact();let s=createLikeC4Logger(`c4:codegen`),c=startTimer(s),u=a.a(await l(e,{graphviz:t?`binary`:`wasm`,watch:!1})),{projectId:f,projectFolder:p}=ensureProject(u,i);i&&s.info(`${S.dim(`project`)} ${S.green(f)}`),s.info(`${S.dim(`format`)} ${S.green(`react`)}`);let m=await u.diagrams(f);if(m.length===0)throw process.exitCode=1,Error(`no views found`);m.forEach(e=>{if(e.drifts&&e.drifts.length>0){s.info(S.yellow(`layout drift detected, view:`)+` `+S.red(e.id));return}if(e.hasLayoutDrift){s.warn(S.yellow(`drift detected, manual layout can not be applied, view:`)+` `+S.red(e.id));return}});let h=H(u.projectsManager.hasMultipleProjects()?p:u.workspace,`likec4-views.js`);if(r&&(h=Ye(r)?r:H(r),U(r)&&(await St(r)).isDirectory()))throw Error(`output file is a directory: ${r}`);let g=z(h);s.info(`${S.dim(`outdir`)} ${g}`);let _=qe(h);s.info(`${S.dim(`filename`)} ${_}`);let v=Je(_).toLocaleLowerCase();if(![`.js`,`.mjs`,`.jsx`].includes(v))throw s.error(`output file ${r} has extension "${v}"`),Error(`output file ${r} must be a .js, .jsx or .mjs`);await Lt({...await viteReactConfig({languageServices:u,outDir:g,filename:_}),logLevel:`warn`});let y=await u.layoutedModel(f),b=H(g,qe(h,v)+(v===`.mjs`?`.d.mts`:`.d.ts`));await G(b,generateReactTypes(y,{useCorePackage:n})),c.stopAndLog(),boxen(ye(`
214
- ${S.dim(`Sources generated:`)}
215
- ${V(jt(),h)}
216
- ${V(jt(),b)}
217
-
218
- ${S.dim(`How to use:`)}
219
- ${S.underline(`https://likec4.dev/tooling/code-generation/react/`)}
220
- `),{padding:1,borderColor:`green`,borderStyle:`round`})}catch(e){a.e=e}finally{await a.d()}}async function webcomponentHandler({project:e,path:t,useDotBin:n,webcomponentPrefix:r=`likec4`,outfile:i}){try{var a=_usingCtx();await ensureReact();let s=createLikeC4Logger(`c4:codegen`),c=startTimer(s),u=a.a(await l(t,{graphviz:n?`binary`:`wasm`,watch:!1})),{projectId:f,projectFolder:p}=ensureProject(u,e);e&&s.info(`${S.dim(`project`)} ${S.green(f)}`),s.info(`${S.dim(`format`)} ${S.green(`webcomponent`)}`);let m=await u.diagrams(f);if(!ue(m,1))throw s.warn(`no views found`),process.exitCode=1,Error(`no views found`);m.forEach(e=>{e.hasLayoutDrift&&s.warn(S.yellow(`drift detected, manual layout can not be applied, view:`)+` `+S.red(e.id))});let h=H(u.projectsManager.hasMultipleProjects()?p:u.workspace,`likec4-views.js`);if(i&&(h=Ye(i)?i:H(i),U(i)&&(await St(i)).isDirectory()))throw Error(`output file is a directory: ${i}`);s.debug(`${S.dim(`outfilepath`)} ${h}`);let g=qe(h);s.debug(`${S.dim(`filename`)} ${g}`);let _=Je(g).toLocaleLowerCase();if(_!==`.js`&&_!==`.mjs`)throw s.warn(`output file ${i} has extension "${_}"`),Error(`output file ${i} must be a .js or .mjs`);let v=await mkTempPublicDir();s.debug(`${S.dim(`created temp public`)} ${v}`);let y=viteWebcomponentConfig({languageServices:u,outDir:v,filename:g,webcomponentPrefix:r,base:`/`});s.debug(`${S.dim(`vite build webcomponent`)}`),await Lt({...y,logLevel:`warn`});let b=H(v,g);if(!U(b))throw Error(`output file not found: ${b}`);await W(z(h),{recursive:!0}),await gt(b,h),s.info(`${S.dim(`generated`)} ${h}`),s.debug(`${S.dim(`remove temp public`)}`),await xt(v,{recursive:!0,force:!0}),c.stopAndLog(),boxen(ye(`
221
- ${S.dim(`Webcomponents generated to:`)}
222
- ${V(jt(),h)}
223
-
224
- ${S.dim(`Setup and usage instructions:`)}
225
- ${S.blue(`https://likec4.dev/tooling/code-generation/webcomponent/`)}
226
- `))}catch(e){a.e=e}finally{await a.d()}}const codegenCmd=e=>e.command({command:`gen <command> [path]`,aliases:[`generate`,`codegen`],describe:`Generate various artifacts from LikeC4 sources`,builder:e=>e.positional(`path`,q).command(`react [path]`,`generate react component to render likec4 view`,e=>e.positional(`path`,q).option(`project`,X).option(`outfile`,{alias:[`o`,`output`],type:`string`,desc:`<file> path to output file (.jsx, .mjs or .js)`,normalize:!0,coerce:H}).option(`use-dot`,J).option(`use-core-package`,Yt),async e=>{await reactHandler({project:e.project,useDotBin:e.useDotBin,path:e.path,outfile:e.outfile,useCorePackage:e.useCorePackage}),showSupportUsMessage()}).command({command:`webcomponent [path]`,aliases:[`wc`,`webcomp`],describe:`generate js with webcomponents`,builder:e=>e.positional(`path`,q).option(`project`,X).option(`outfile`,{alias:[`o`,`output`],type:`string`,desc:`<file> path to output file (.mjs or .js)`,normalize:!0,coerce:H}).option(`webcomponent-prefix`,Zt).option(`use-dot`,J),handler:async e=>{await webcomponentHandler({project:e.project,useDotBin:e.useDotBin,path:e.path,outfile:e.outfile,webcomponentPrefix:e.webcomponentPrefix}),showSupportUsMessage()}}).command({command:`model [path]`,aliases:[`ts`],describe:`generate LikeC4Model (.ts)`,builder:e=>e.positional(`path`,q).option(`project`,X).option(`outfile`,{alias:[`o`,`output`],type:`string`,desc:`<file> path to output file (.ts)`,normalize:!0,coerce:H}).option(`use-dot`,J).option(`use-core-package`,Yt),handler:async e=>{await modelHandler({path:e.path,useDotBin:e.useDotBin,useCorePackage:e.useCorePackage,outfile:e.outfile,project:e.project}),showSupportUsMessage()}}).command({command:`views-data [path]`,aliases:[`views`],describe:`{deprecated} use codegen model`,deprecated:!0,builder:e=>e.positional(`path`,q).option(`outfile`,{alias:[`o`,`output`],type:`string`,desc:`<file> output .ts file`,normalize:!0,coerce:H}).option(`use-dot`,J),handler:async e=>{await legacyHandler({format:`views`,path:e.path,useDotBin:e.useDotBin,outfile:e.outfile})}}).command({command:`leanix [path]`,describe:`LeanIX bridge: dry-run, inventory snapshot, reconcile`,builder:e=>e.positional(`path`,q).demandCommand(1,`Choose a subcommand: dry-run, inventory, reconcile`).command(`dry-run [path]`,`generate LeanIX bridge artifacts (manifest, dry-run inventory, report)`,e=>e.positional(`path`,q).option(`outdir`,{...Y,desc:`<dir> output directory for manifest.json, leanix-dry-run.json, report.json`}).option(`project`,X).option(`use-dot`,J).example(`${S.green(`$0 gen leanix dry-run -o out/bridge`)}`,S.gray(`Write bridge artifacts to out/bridge`)),async e=>{await leanixDryRunHandler({path:e.path,outdir:e.outdir??H(process.cwd(),`out`,`bridge`),project:e.project,useDotBin:e.useDotBin})}).command(`inventory`,`fetch LeanIX inventory (read-only) and write leanix-inventory-snapshot.json`,e=>e.option(`outdir`,{...Y,default:H(process.cwd(),`out`,`bridge`),desc:`<dir> output directory for leanix-inventory-snapshot.json`}).option(`likec4-id-attribute`,{type:`string`,desc:`custom LeanIX attribute key for likec4Id (e.g. "likec4Id")`}).example(`${S.green(`$0 gen leanix inventory -o out/bridge`)}`,S.gray(`Requires LEANIX_API_TOKEN`)),async e=>{await leanixInventorySnapshotHandler({outdir:e.outdir??H(process.cwd(),`out`,`bridge`),...e.likec4IdAttribute==null?{}:{likec4IdAttribute:e.likec4IdAttribute}})}).command(`reconcile [path]`,`reconcile manifest with leanix-inventory-snapshot; write reconciliation-report.json`,e=>e.positional(`path`,q).option(`outdir`,{...Y,default:H(process.cwd(),`out`,`bridge`),desc:`<dir> directory with manifest.json and leanix-inventory-snapshot.json`}).option(`project`,X).option(`use-dot`,J).example(`${S.green(`$0 gen leanix reconcile -o out/bridge`)}`,S.gray(`Reads manifest + snapshot from outdir; optional workspace for name+type matching`)),async e=>{await leanixReconcileHandler({path:e.path,outdir:e.outdir??H(process.cwd(),`out`,`bridge`),project:e.project,useDotBin:e.useDotBin})}),handler:async()=>{}}).command({command:`dot [path]`,describe:`generate graphviz files (.dot)`,builder:e=>e.positional(`path`,q).option(`outdir`,Y).option(`use-dot`,J),handler:async e=>{await legacyHandler({format:`dot`,path:e.path,useDotBin:e.useDotBin,outdir:e.outdir}),showSupportUsMessage()}}).command({command:`d2 [path]`,describe:`generate D2 files (.d2)`,builder:e=>e.positional(`path`,q).option(`outdir`,Y).option(`use-dot`,J),handler:async e=>{await legacyHandler({format:`d2`,path:e.path,useDotBin:e.useDotBin,outdir:e.outdir}),showSupportUsMessage()}}).command({command:`mermaid [path]`,aliases:[`mmd`],describe:`generate Mermaid files (.mmd)`,builder:e=>e.positional(`path`,q).option(`outdir`,Y).option(`use-dot`,J),handler:async e=>{await legacyHandler({format:`mermaid`,useDotBin:e.useDotBin,path:e.path,outdir:e.outdir}),showSupportUsMessage()}}).command({command:`plantuml [path]`,aliases:[`puml`],describe:`generate PlantUML files (.puml)`,builder:e=>e.positional(`path`,q).option(`outdir`,Y).option(`use-dot`,J),handler:async e=>{await legacyHandler({format:`plantuml`,useDotBin:e.useDotBin,path:e.path,outdir:e.outdir}),showSupportUsMessage()}}).command({command:`<custom> [path]`,describe:`run custom generator from likec4 config`,builder:e=>e.positional(`path`,q).option(`project`,X).option(`use-dot`,J),handler:async e=>{await customHandler({name:`custom`,path:e.path,project:e.project,useDotBin:e.useDotBin})}}).epilog(`${S.bold(`Examples:`)}
207
+ `,{id:t,first:100,after:i})),c=s?.factSheet?.relations?.edges??[],l=s?.factSheet?.relations?.pageInfo;for(let e of c){let i=e.node,a=i?.targetFactSheet?.id;!a||!r.has(a)||n.push({...i?.id?{id:i.id}:{},sourceFactSheetId:t,targetFactSheetId:a,type:i?.type??`RELATES_TO`})}a=l?.hasNextPage===!0,i=l?.endCursor??null}return n}for(let e=0;e<t.length;e+=10){let r=t.slice(e,e+10),i=await Promise.all(r.map(e=>fetchRelationsForFactSheet(e)));for(let e of i)n.push(...e)}return n}function tryMatchByManifestFactSheetId(e,t,n,r){let i=e.external?.[Dn],a=i?.factSheetId??i?.externalId;if(a==null)return null;let s=n.get(a);return!s||r.has(s.id)?null:(r.add(s.id),{canonicalId:t,factSheetId:s.id,name:s.name,type:s.type})}function tryMatchByLikec4Id(e,t,n){let r=t.get(e);return!r||n.has(r.id)?null:(n.add(r.id),{canonicalId:e,factSheetId:r.id,name:r.name,type:r.type})}function resolveByNameAndType(e,t,n,r,i,a,s,c){let l=`${t??e}${n??``}`,u=r.get(l)?.filter(e=>!i.has(e.id))??[];if(u.length===0)s.push({canonicalId:e,...t===void 0?{}:{name:t},...n===void 0?{}:{type:n}});else if(u.length===1){let t=u[0];a.push({canonicalId:e,factSheetId:t.id,name:t.name,type:t.type}),i.add(t.id)}else c.push({canonicalId:e,...t===void 0?{}:{name:t},...n===void 0?{}:{type:n},candidateFactSheetIds:u.map(e=>e.id)})}function reconcileInventoryWithManifest(e,t,n={}){let r=n.generatedAt??new Date().toISOString(),i=n.dryRun,a=[],s=[],c=[],l=new Map(e.factSheets.map(e=>[e.id,e])),u=new Map,f=new Map;for(let t of e.factSheets){t.likec4Id&&u.set(t.likec4Id,t);let e=`${t.name}${t.type}`;f.has(e)||f.set(e,[]),f.get(e).push(t)}let p=i?new Map(i.factSheets.map(e=>[e.likec4Id,e])):null,m=new Set;for(let[e,n]of Object.entries(t.entities)){let t=tryMatchByManifestFactSheetId(n,e,l,m);if(t){a.push(t);continue}let r=tryMatchByLikec4Id(e,u,m);if(r){a.push(r);continue}let i=p?.get(e);resolveByNameAndType(e,i?.name??void 0,i?.type??void 0,f,m,a,s,c)}let h=e.factSheets.filter(e=>!m.has(e.id)).map(e=>({factSheetId:e.id,name:e.name,type:e.type,...e.likec4Id?{likec4Id:e.likec4Id}:{}}));return{generatedAt:r,manifestProjectId:t.projectId,snapshotGeneratedAt:e.generatedAt,matched:a,unmatchedInLikec4:s,unmatchedInLeanix:h,ambiguous:c,summary:{matched:a.length,unmatchedInLikec4:s.length,unmatchedInLeanix:h.length,ambiguous:c.length}}}function isRecord(e){return typeof e==`object`&&!!e}function isManifestEntity(e){return isRecord(e)?typeof e.canonicalId==`string`:!1}function isManifestView(e){return isRecord(e)?typeof e.viewId==`string`:!1}function isManifestRelation(e){return isRecord(e)?typeof e.relationId==`string`&&typeof e.sourceFqn==`string`&&typeof e.targetFqn==`string`&&typeof e.compositeKey==`string`:!1}function isLeanixFactSheetSnapshotItem(e){return isRecord(e)?typeof e.id==`string`&&typeof e.name==`string`&&typeof e.type==`string`:!1}function isLeanixRelationSnapshotItem(e){return isRecord(e)?typeof e.sourceFactSheetId==`string`&&typeof e.targetFactSheetId==`string`&&typeof e.type==`string`:!1}function isBridgeManifest(e){if(!isRecord(e)||typeof e.manifestVersion!=`string`||typeof e.generatedAt!=`string`||typeof e.bridgeVersion!=`string`||typeof e.mappingProfile!=`string`||typeof e.projectId!=`string`)return!1;let t=e.entities;if(typeof t!=`object`||!t||Array.isArray(t))return!1;for(let e of Object.values(t))if(!isManifestEntity(e))return!1;let n=e.views;if(typeof n!=`object`||!n||Array.isArray(n))return!1;for(let e of Object.values(n))if(!isManifestView(e))return!1;let r=e.relations;if(!Array.isArray(r))return!1;for(let e of r)if(!isManifestRelation(e))return!1;return!0}function isLeanixInventorySnapshot(e){if(!isRecord(e)||typeof e.generatedAt!=`string`||e.workspaceId!==void 0&&typeof e.workspaceId!=`string`||!Array.isArray(e.factSheets))return!1;for(let t of e.factSheets)if(!isLeanixFactSheetSnapshotItem(t))return!1;if(!Array.isArray(e.relations))return!1;for(let t of e.relations)if(!isLeanixRelationSnapshotItem(t))return!1;return!0}const jn=`No project or empty model`,Mn=`LEANIX_API_TOKEN is required for likec4 sync leanix --apply`,Nn=`default`,Pn=`manifest.json`,Fn=`leanix-dry-run.json`,In=`report.json`;function asBridgeModel(e){return{projectId:String(e.projectId),elements:()=>e.elements(),relationships:()=>e.relationships(),views:()=>e.views()}}function buildBridgeArtifacts(e){let t=toBridgeManifest(e,{mappingProfile:Nn}),n=toLeanixInventoryDryRun(e,{mappingProfile:Nn});return{manifest:t,dryRun:n,report:buildBridgeReport(t,n)}}async function writeBridgeArtifacts(e,t,n,r=process.cwd()){await G(e,{recursive:!0});let i=H(e,Pn),a=H(e,Fn),s=H(e,In);await K(i,JSON.stringify(t.manifest,null,2)),await K(a,JSON.stringify(t.dryRun,null,2)),await K(s,JSON.stringify(t.report,null,2)),n.info(`${C.dim(`generated`)} ${V(r,i)}`),n.info(`${C.dim(`generated`)} ${V(r,a)}`),n.info(`${C.dim(`generated`)} ${V(r,s)}`)}const Ln={manifest:Pn,dryRun:Fn,report:In};async function leanixDryRunHandler(e){let t=createLikeC4Logger(`c4:gen:leanix:dry-run`),n=startTimer(t),{path:r,outdir:i,project:a,useDotBin:s}=e;try{try{var l=_usingCtx();let e=l.a(await c(r,{graphviz:s?`binary`:`wasm`,watch:!1})),{projectId:n}=ensureProject(e,a);a&&t.info(`${C.dim(`project`)} ${C.green(n)}`);let u=await e.layoutedModel(n);if(u===Me.EMPTY)throw t.error(jn),Error(jn);await writeBridgeArtifacts(i,buildBridgeArtifacts(asBridgeModel(u)),t)}catch(e){l.e=e}finally{await l.d()}}finally{n.stopAndLog()}}function createLeanixClientFromEnv(){let e=process.env.LEANIX_API_TOKEN?.trim();return e?new LeanixApiClient({apiToken:e,baseUrl:process.env.LEANIX_BASE_URL?.trim()||`https://app.leanix.net`,requestDelayMs:200}):null}function requireLeanixClient(){let e=createLeanixClientFromEnv();if(!e)throw Error(`LEANIX_API_TOKEN is required. Set it in the environment to call the LeanIX API.`);return e}async function leanixInventorySnapshotHandler(e){let t=createLikeC4Logger(`c4:gen:leanix:inventory`),n=startTimer(t),{outdir:r,likec4IdAttribute:i}=e;try{let e=requireLeanixClient(),n={};typeof i==`string`&&i.trim()!==``&&(n.likec4IdAttribute=i.trim());let a=await fetchLeanixInventorySnapshot(e,n);await G(r,{recursive:!0});let s=H(r,`leanix-inventory-snapshot.json`);await K(s,JSON.stringify(a,null,2)),t.info(`${C.dim(`generated`)} ${V(process.cwd(),s)}`),t.info(`${C.dim(`snapshot`)} ${a.factSheets.length} fact sheets, ${a.relations.length} relations`)}finally{n.stopAndLog()}}const Rn=`manifest.json`,zn=`leanix-inventory-snapshot.json`;async function readManifestAndSnapshot(e){let t=H(e,Rn),n=H(e,zn),[r,i]=await Promise.all([Tt(t,`utf-8`),Tt(n,`utf-8`)]),a=JSON.parse(r),s=JSON.parse(i);if(!isBridgeManifest(a))throw Error(`Invalid manifest format: missing manifestVersion, projectId, entities, relations, or views`);if(!isLeanixInventorySnapshot(s))throw Error(`Invalid snapshot format: missing factSheets or relations arrays`);return{manifest:a,snapshot:s}}async function loadDryRunFromWorkspace(e,t,n){try{var r=_usingCtx();let i=r.a(await c(e,{graphviz:n?`binary`:`wasm`,watch:!1})),{projectId:a}=ensureProject(i,t),s=await i.layoutedModel(a);return s===Me.EMPTY?void 0:buildBridgeArtifacts(asBridgeModel(s)).dryRun}catch(e){r.e=e}finally{await r.d()}}async function leanixReconcileHandler(e){let t=createLikeC4Logger(`c4:gen:leanix:reconcile`),n=startTimer(t),{path:r,outdir:i,project:a,useDotBin:s}=e;try{let e,n;try{let t=await readManifestAndSnapshot(i);e=t.manifest,n=t.snapshot}catch(e){let n=e instanceof Error?e.message:String(e);throw t.error(`Failed to read ${Rn} or ${zn} from ${i}: ${n}`),e}let c;try{c=await loadDryRunFromWorkspace(r,a,s)}catch(e){let n=e instanceof Error?e.message:String(e);if(a!=null&&a!==``)throw t.error(`Failed to load workspace for dryRun enrichment: ${n}`),e;t.warn(`Could not load workspace for dryRun enrichment; proceeding without it: ${n}`),c=void 0}let l=reconcileInventoryWithManifest(n,e,{...c==null?{}:{dryRun:c}}),u=H(i,`reconciliation-report.json`);await K(u,JSON.stringify(l,null,2)),t.info(`${C.dim(`generated`)} ${V(process.cwd(),u)}`),t.info(`${C.dim(`reconcile`)} matched=${l.summary.matched} unmatchedLikec4=${l.summary.unmatchedInLikec4} unmatchedLeanix=${l.summary.unmatchedInLeanix} ambiguous=${l.summary.ambiguous}`)}finally{n.stopAndLog()}}async function modelHandler({path:e,useDotBin:t,useCorePackage:n,outfile:r,project:i}){try{var a=_usingCtx();let s=createLikeC4Logger(`c4:codegen`),l=startTimer(s),u=a.a(await c(e,{graphviz:t?`binary`:`wasm`,watch:!1})),{projectId:f,projectFolder:p}=ensureProject(u,i);i&&s.info(`${C.dim(`project`)} ${C.green(f)}`),s.info(`${C.dim(`format`)} ${C.green(`model`)}`);let m=await u.layoutedModel(f);for(let e of m.views())e.hasLayoutDrifts&&s.warn(C.yellow(`layout drift detected, view:`)+` `+C.red(e.id));let h=H(u.projectsManager.hasMultipleProjects()?p:u.workspace,`likec4-model.ts`);if(r&&(h=$e(r)?r:H(r),W(r)&&(await kt(r)).isDirectory()))throw Error(`output file is a directory: ${r}`);let g=Ze(h);s.info(`${C.dim(`filename`)} ${g}`);let _=Qe(g).toLocaleLowerCase();if(![`.ts`,`.mts`,`.cts`].includes(_))throw s.error(`output file ${r} has extension "${_}"`),Error(`output file ${r} must be a .ts, .mts or .cts file`);let v=z(h);s.info(`${C.dim(`outdir`)} ${v}`),await G(v,{recursive:!0}),await K(h,generateLikeC4Model(m,{useCorePackage:n}),{encoding:`utf-8`}),l.stopAndLog(),boxen(be(`
208
+ ${C.dim(`Source generated:`)}
209
+ ${V(Rt(),h)}
210
+
211
+ ${C.dim(`How to use:`)}
212
+ ${C.underline(`https://likec4.dev/tooling/code-generation/model/`)}
213
+ `).trim(),{padding:1,borderColor:`green`,borderStyle:`round`})}catch(e){a.e=e}finally{await a.d()}}async function viteReactConfig({languageServices:e,outDir:t,filename:n=`likec4-react.mjs`}){let r=createLikeC4Logger([`vite`,`react`]),i=viteAppRoot();return r.info(`${C.cyan(`likec4 app root`)} ${C.dim(relativeToCwd(i))}`),r.info(C.cyan(`outDir`)+` `+C.dim(relativeToCwd(t))),{customLogger:r,root:i,configFile:!1,clearScreen:!1,publicDir:!1,mode:`production`,resolve:{alias:viteAliases()},build:{outDir:t,emptyOutDir:!1,sourcemap:!1,minify:!1,copyPublicDir:!1,lib:{entry:`codegen/react.mjs`,fileName(e,t){return n},formats:[`es`]},rolldownOptions:{external:[`likec4/react`,`likec4/model`,`react`,`react-dom`,`react/jsx-runtime`,`react/jsx-dev-runtime`,`react-dom/client`,/@likec4\/core.*/]}},plugins:[je({ai:`disabled`,languageServices:e.languageServices})]}}async function reactHandler({path:e,useDotBin:t,useCorePackage:n,outfile:r,project:i}){try{var a=_usingCtx();await ensureReact();let s=createLikeC4Logger(`c4:codegen`),l=startTimer(s),u=a.a(await c(e,{graphviz:t?`binary`:`wasm`,watch:!1})),{projectId:f,projectFolder:p}=ensureProject(u,i);i&&s.info(`${C.dim(`project`)} ${C.green(f)}`),s.info(`${C.dim(`format`)} ${C.green(`react`)}`);let m=await u.diagrams(f);if(m.length===0)throw process.exitCode=1,Error(`no views found`);m.forEach(e=>{if(e.drifts&&e.drifts.length>0){s.info(C.yellow(`layout drift detected, view:`)+` `+C.red(e.id));return}if(e.hasLayoutDrift){s.warn(C.yellow(`drift detected, manual layout can not be applied, view:`)+` `+C.red(e.id));return}});let h=H(u.projectsManager.hasMultipleProjects()?p:u.workspace,`likec4-views.js`);if(r&&(h=$e(r)?r:H(r),W(r)&&(await kt(r)).isDirectory()))throw Error(`output file is a directory: ${r}`);let g=z(h);s.info(`${C.dim(`outdir`)} ${g}`);let _=Ze(h);s.info(`${C.dim(`filename`)} ${_}`);let v=Qe(_).toLocaleLowerCase();if(![`.js`,`.mjs`,`.jsx`].includes(v))throw s.error(`output file ${r} has extension "${v}"`),Error(`output file ${r} must be a .js, .jsx or .mjs`);await Wt({...await viteReactConfig({languageServices:u,outDir:g,filename:_}),logLevel:`warn`});let y=await u.layoutedModel(f),b=H(g,Ze(h,v)+(v===`.mjs`?`.d.mts`:`.d.ts`));await K(b,generateReactTypes(y,{useCorePackage:n})),l.stopAndLog(),boxen(be(`
214
+ ${C.dim(`Sources generated:`)}
215
+ ${V(Rt(),h)}
216
+ ${V(Rt(),b)}
217
+
218
+ ${C.dim(`How to use:`)}
219
+ ${C.underline(`https://likec4.dev/tooling/code-generation/react/`)}
220
+ `),{padding:1,borderColor:`green`,borderStyle:`round`})}catch(e){a.e=e}finally{await a.d()}}async function webcomponentHandler({project:e,path:t,useDotBin:n,webcomponentPrefix:r=`likec4`,outfile:i}){try{var a=_usingCtx();await ensureReact();let s=createLikeC4Logger(`c4:codegen`),l=startTimer(s),u=a.a(await c(t,{graphviz:n?`binary`:`wasm`,watch:!1})),{projectId:f,projectFolder:p}=ensureProject(u,e);e&&s.info(`${C.dim(`project`)} ${C.green(f)}`),s.info(`${C.dim(`format`)} ${C.green(`webcomponent`)}`);let m=await u.diagrams(f);if(!se(m,1))throw s.warn(`no views found`),process.exitCode=1,Error(`no views found`);m.forEach(e=>{e.hasLayoutDrift&&s.warn(C.yellow(`drift detected, manual layout can not be applied, view:`)+` `+C.red(e.id))});let h=H(u.projectsManager.hasMultipleProjects()?p:u.workspace,`likec4-views.js`);if(i&&(h=$e(i)?i:H(i),W(i)&&(await kt(i)).isDirectory()))throw Error(`output file is a directory: ${i}`);s.debug(`${C.dim(`outfilepath`)} ${h}`);let g=Ze(h);s.debug(`${C.dim(`filename`)} ${g}`);let _=Qe(g).toLocaleLowerCase();if(_!==`.js`&&_!==`.mjs`)throw s.warn(`output file ${i} has extension "${_}"`),Error(`output file ${i} must be a .js or .mjs`);let v=await mkTempPublicDir();s.debug(`${C.dim(`created temp public`)} ${v}`);let y=viteWebcomponentConfig({languageServices:u,outDir:v,filename:g,webcomponentPrefix:r,base:`/`});s.debug(`${C.dim(`vite build webcomponent`)}`),await Wt({...y,logLevel:`warn`});let b=H(v,g);if(!W(b))throw Error(`output file not found: ${b}`);await G(z(h),{recursive:!0}),await St(b,h),s.info(`${C.dim(`generated`)} ${h}`),s.debug(`${C.dim(`remove temp public`)}`),await Ot(v,{recursive:!0,force:!0}),l.stopAndLog(),boxen(be(`
221
+ ${C.dim(`Webcomponents generated to:`)}
222
+ ${V(Rt(),h)}
223
+
224
+ ${C.dim(`Setup and usage instructions:`)}
225
+ ${C.blue(`https://likec4.dev/tooling/code-generation/webcomponent/`)}
226
+ `))}catch(e){a.e=e}finally{await a.d()}}const codegenCmd=e=>e.command({command:`gen <command> [path]`,aliases:[`generate`,`codegen`],describe:`Generate various artifacts from LikeC4 sources`,builder:e=>e.positional(`path`,J).command(`react [path]`,`generate react component to render likec4 view`,e=>e.positional(`path`,J).option(`project`,Z).option(`outfile`,{alias:[`o`,`output`],type:`string`,desc:`<file> path to output file (.jsx, .mjs or .js)`,normalize:!0,coerce:H}).option(`use-dot`,Y).option(`use-core-package`,nn),async e=>{await reactHandler({project:e.project,useDotBin:e.useDotBin,path:e.path,outfile:e.outfile,useCorePackage:e.useCorePackage}),showSupportUsMessage()}).command({command:`webcomponent [path]`,aliases:[`wc`,`webcomp`],describe:`generate js with webcomponents`,builder:e=>e.positional(`path`,J).option(`project`,Z).option(`outfile`,{alias:[`o`,`output`],type:`string`,desc:`<file> path to output file (.mjs or .js)`,normalize:!0,coerce:H}).option(`webcomponent-prefix`,an).option(`use-dot`,Y),handler:async e=>{await webcomponentHandler({project:e.project,useDotBin:e.useDotBin,path:e.path,outfile:e.outfile,webcomponentPrefix:e.webcomponentPrefix}),showSupportUsMessage()}}).command({command:`model [path]`,aliases:[`ts`],describe:`generate LikeC4Model (.ts)`,builder:e=>e.positional(`path`,J).option(`project`,Z).option(`outfile`,{alias:[`o`,`output`],type:`string`,desc:`<file> path to output file (.ts)`,normalize:!0,coerce:H}).option(`use-dot`,Y).option(`use-core-package`,nn),handler:async e=>{await modelHandler({path:e.path,useDotBin:e.useDotBin,useCorePackage:e.useCorePackage,outfile:e.outfile,project:e.project}),showSupportUsMessage()}}).command({command:`views-data [path]`,aliases:[`views`],describe:`{deprecated} use codegen model`,deprecated:!0,builder:e=>e.positional(`path`,J).option(`outfile`,{alias:[`o`,`output`],type:`string`,desc:`<file> output .ts file`,normalize:!0,coerce:H}).option(`use-dot`,Y),handler:async e=>{await legacyHandler({format:`views`,path:e.path,useDotBin:e.useDotBin,outfile:e.outfile})}}).command({command:`leanix [path]`,describe:`LeanIX bridge: dry-run, inventory snapshot, reconcile`,builder:e=>e.positional(`path`,J).demandCommand(1,`Choose a subcommand: dry-run, inventory, reconcile`).command(`dry-run [path]`,`generate LeanIX bridge artifacts (manifest, dry-run inventory, report)`,e=>e.positional(`path`,J).option(`outdir`,{...X,desc:`<dir> output directory for manifest.json, leanix-dry-run.json, report.json`}).option(`project`,Z).option(`use-dot`,Y).example(`${C.green(`$0 gen leanix dry-run -o out/bridge`)}`,C.gray(`Write bridge artifacts to out/bridge`)),async e=>{await leanixDryRunHandler({path:e.path,outdir:e.outdir??H(process.cwd(),`out`,`bridge`),project:e.project,useDotBin:e.useDotBin})}).command(`inventory`,`fetch LeanIX inventory (read-only) and write leanix-inventory-snapshot.json`,e=>e.option(`outdir`,{...X,default:H(process.cwd(),`out`,`bridge`),desc:`<dir> output directory for leanix-inventory-snapshot.json`}).option(`likec4-id-attribute`,{type:`string`,desc:`custom LeanIX attribute key for likec4Id (e.g. "likec4Id")`}).example(`${C.green(`$0 gen leanix inventory -o out/bridge`)}`,C.gray(`Requires LEANIX_API_TOKEN`)),async e=>{await leanixInventorySnapshotHandler({outdir:e.outdir??H(process.cwd(),`out`,`bridge`),...e.likec4IdAttribute==null?{}:{likec4IdAttribute:e.likec4IdAttribute}})}).command(`reconcile [path]`,`reconcile manifest with leanix-inventory-snapshot; write reconciliation-report.json`,e=>e.positional(`path`,J).option(`outdir`,{...X,default:H(process.cwd(),`out`,`bridge`),desc:`<dir> directory with manifest.json and leanix-inventory-snapshot.json`}).option(`project`,Z).option(`use-dot`,Y).example(`${C.green(`$0 gen leanix reconcile -o out/bridge`)}`,C.gray(`Reads manifest + snapshot from outdir; optional workspace for name+type matching`)),async e=>{await leanixReconcileHandler({path:e.path,outdir:e.outdir??H(process.cwd(),`out`,`bridge`),project:e.project,useDotBin:e.useDotBin})}),handler:async()=>{}}).command({command:`dot [path]`,describe:`generate graphviz files (.dot)`,builder:e=>e.positional(`path`,J).option(`outdir`,X).option(`use-dot`,Y),handler:async e=>{await legacyHandler({format:`dot`,path:e.path,useDotBin:e.useDotBin,outdir:e.outdir}),showSupportUsMessage()}}).command({command:`d2 [path]`,describe:`generate D2 files (.d2)`,builder:e=>e.positional(`path`,J).option(`outdir`,X).option(`use-dot`,Y),handler:async e=>{await legacyHandler({format:`d2`,path:e.path,useDotBin:e.useDotBin,outdir:e.outdir}),showSupportUsMessage()}}).command({command:`mermaid [path]`,aliases:[`mmd`],describe:`generate Mermaid files (.mmd)`,builder:e=>e.positional(`path`,J).option(`outdir`,X).option(`use-dot`,Y),handler:async e=>{await legacyHandler({format:`mermaid`,useDotBin:e.useDotBin,path:e.path,outdir:e.outdir}),showSupportUsMessage()}}).command({command:`plantuml [path]`,aliases:[`puml`],describe:`generate PlantUML files (.puml)`,builder:e=>e.positional(`path`,J).option(`outdir`,X).option(`use-dot`,Y),handler:async e=>{await legacyHandler({format:`plantuml`,useDotBin:e.useDotBin,path:e.path,outdir:e.outdir}),showSupportUsMessage()}}).command({command:`<custom> [path]`,describe:`run custom generator from likec4 config`,builder:e=>e.positional(`path`,J).option(`project`,Z).option(`use-dot`,Y),handler:async e=>{await customHandler({name:`custom`,path:e.path,project:e.project,useDotBin:e.useDotBin})}}).epilog(`${C.bold(`Examples:`)}
227
227
  likec4 gen react -o dist/likec4-views.mjs ./src/likec4
228
228
  likec4 gen model -o likec4-model.ts
229
229
  likec4 gen leanix dry-run -o out/bridge
@@ -234,70 +234,73 @@ export {
234
234
  likec4 gen mmd --outdir assets/
235
235
  likec4 gen plantuml --outdir assets/
236
236
  likec4 gen dot -o out .
237
- `),handler:async e=>{await customHandler({name:e.command,path:e.path,project:e.project,useDotBin:e.useDotBin})}}),An=new Set([`node_modules`,`.git`]);function isSourceFile(e){return e.endsWith(`.c4`)||e.endsWith(`.likec4`)}function joinNonEmptyFiles(e,t=`
238
-
239
- `){return e.filter(e=>e.trim()!==``).join(t)}const jn=`No project or empty model`,Mn=`No views could be exported`;function getDrawioEpilog(){return`${S.bold(`Examples:`)}
240
- ${S.green(`$0 export drawio`)}
241
- ${S.gray(`Export each view to a separate .drawio file`)}
242
-
243
- ${S.green(`$0 export drawio --all-in-one -o ./diagrams src/`)}
244
- ${S.gray(`Export all views as tabs in one .drawio file`)}
245
-
246
- ${S.green(`$0 export drawio --roundtrip -o ./out`)}
247
- ${S.gray(`Re-apply layout/waypoints from comment blocks (e.g. after import from DrawIO)`)}
248
-
249
- ${S.green(`$0 export drawio --uncompressed -o ./out`)}
250
- ${S.gray(`Export with raw XML (no compression) for draw.io desktop compatibility`)}
251
-
252
- ${S.green(`$0 export drawio --profile leanix -o ./out`)}
253
- ${S.gray(`Export with bridge-managed metadata (likec4Id, likec4ViewId, etc.) for LeanIX interoperability`)}`}function toError(e){return e instanceof Error?e:Error(a(e))}function logAndRethrow(e,t,n){let r=toError(n);throw e.error(t,{error:r}),r}async function readWorkspaceSourceContent(e,t){let n=[],r=new Set;async function walk(e,i){if(i>=50)return;let a=await bt(e).catch(()=>null);if(a==null||r.has(a))return;r.add(a);let s=await yt(e,{withFileTypes:!0}).catch(n=>(t?.debug&&t.debug(`${S.dim(`Roundtrip:`)} readdir failed`,{dir:e,err:n}),[]));for(let r of s){let a=B(e,r.name);switch(!0){case r.isDirectory():An.has(r.name)||await walk(a,i+1);break;case r.isSymbolicLink():if((await St(a).catch(()=>null))?.isFile()&&isSourceFile(r.name)){let e=await vt(a,`utf-8`).catch(e=>(t?.debug&&t.debug(`${S.dim(`Roundtrip:`)} readFile failed`,{file:a,err:e}),``));e&&n.push(e)}break;case r.isFile()&&isSourceFile(r.name):{let e=await vt(a,`utf-8`).catch(e=>(t?.debug&&t.debug(`${S.dim(`Roundtrip:`)} readFile failed`,{file:a,err:e}),``));e&&n.push(e);break}}}}return await walk(e,0),joinNonEmptyFiles(n)}async function getSourceContentIfRoundtrip(e,t,n){if(t)return readWorkspaceSourceContent(H(e),n)}function buildDrawioExportOverrides(e,t,n){let r=e?{compressed:!1}:{compressed:!0};return t===`leanix`&&(r.profile=`leanix`,r.projectId=n),r}function buildOptionsByViewId(e,t,n,r,i){return Se(e.map(e=>String(e.$view.id)),t,buildDrawioExportOverrides(n,r,i))}async function exportDrawioAllInOne(e){let{viewmodels:t,outdir:n,workspacePath:r,roundtrip:i,uncompressed:a,profile:s,projectId:c,logger:l}=e,u=we(t,buildOptionsByViewId(t,await getSourceContentIfRoundtrip(r,i,l),a,s,c)),f=H(n,Ee);await G(f,u),l.info(`${S.dim(`generated`)} ${V(process.cwd(),f)} (${t.length} tab(s))`)}async function writeViewToFile(e,t,n,r){let i=String(e.$view.id);try{let a=be(e,t[i]),s=H(n,i+`.drawio`);return await W(z(s),{recursive:!0}),await G(s,a),r.info(`${S.dim(`generated`)} ${V(process.cwd(),s)}`),!0}catch(e){return r.error(`Failed to export view ${i}`,{error:toError(e)}),!1}}async function exportDrawioPerView(e){let{viewmodels:t,outdir:n,workspacePath:r,roundtrip:i,uncompressed:a,profile:s,projectId:c,logger:l}=e,u=buildOptionsByViewId(t,await getSourceContentIfRoundtrip(r,i,l),a,s,c),f=0;for(let e of t)await writeViewToFile(e,u,n,l)&&f++;return{succeeded:f}}async function runExportDrawio(e,t){try{var n=_usingCtx();let r=startTimer(t),i=n.a(await l(e.path,{graphviz:e.useDot?`binary`:`wasm`,watch:!1}));e.project||i.ensureSingleProject();let a=e.project==null?void 0:i.languageServices.projectsManager.ensureProjectId(e.project),s=await i.layoutedModel(a);if(s===Oe.EMPTY)throw t.error(jn),Error(jn);let c=[...s.views()];if(c.length===0)throw t.error(`No views to export`),Error(Mn);await W(e.outdir,{recursive:!0});let u=String(s.projectId),f={viewmodels:c,outdir:e.outdir,workspacePath:e.path,roundtrip:e.roundtrip,uncompressed:e.uncompressed,profile:e.profile,projectId:u,logger:t};if(e.allInOne)try{await exportDrawioAllInOne(f)}catch(e){logAndRethrow(t,`Failed to export DrawIO`,e)}else{let{succeeded:e}=await exportDrawioPerView(f);if(e===0)throw t.error(Mn),Error(Mn);t.info(`${S.dim(`total`)} ${e} DrawIO file(s)`)}r.stopAndLog(`✓ export drawio in `)}catch(e){n.e=e}finally{await n.d()}}function drawioCmd(e){return e.command({command:`drawio [path]`,describe:`export view(s) to DrawIO (.drawio) for editing in draw.io`,builder:e=>e.positional(`path`,q).option(`outdir`,{alias:`o`,type:`string`,desc:`<dir> output directory for .drawio files`,normalize:!0,coerce:H}).option(`all-in-one`,{type:`boolean`,default:!1,desc:`write one .drawio file with all views as tabs (diagrams)`}).option(`roundtrip`,{type:`boolean`,default:!1,desc:`apply layout/stroke/waypoints from DrawIO round-trip comment blocks in .c4 source`}).option(`uncompressed`,{type:`boolean`,default:!1,desc:`write diagram XML uncompressed inside .drawio (larger file; use if draw.io desktop fails to open compressed export)`}).option(`profile`,{type:`string`,choices:[`default`,`leanix`],default:`default`,desc:`export profile: default (round-trip) or leanix (bridge-managed metadata for LeanIX interoperability)`}).options({project:X,"use-dot":J}).epilog(getDrawioEpilog()),handler:async e=>{let t=createLikeC4Logger(`c4:export`);await runExportDrawio({path:e.path,outdir:e.outdir??e.path,allInOne:!!e.allInOne,roundtrip:!!e.roundtrip,uncompressed:!!e.uncompressed,profile:e.profile===`leanix`?`leanix`:`default`,project:e.project,useDot:!!e[`use-dot`]},t)}})}var Nn=e(ve(),1);function resolveServerUrl(e){if(e.resolvedUrls)return ce(e.resolvedUrls.network)??ce(e.resolvedUrls.local)}function printServerUrls(e){if(!e.resolvedUrls)throw Error(`Vite server is not ready, no resolvedUrls`);boxen([S.green(`LikeC4 served at:`),``,S.dim(`Local: `)+e.resolvedUrls.local.join(`
254
- `+``.padEnd(9,` `)),e.resolvedUrls.network.length?S.dim(`Network: `)+e.resolvedUrls.network.join(`
255
- `+``.padEnd(9,` `)):void 0].filter(e=>he(e)).join(`
256
- `))}async function viteDev({buildWebcomponent:e=!1,hmr:t=!0,webcomponentPrefix:n=`likec4`,title:r,languageServices:i,likec4AssetsDir:s,openBrowser:c,listen:l,port:u,...f}){s??=await _t(B(ut(),`.likec4-assets-`));let{isDev:p,...m}=await viteConfig({...f,languageServices:i,likec4AssetsDir:s,webcomponentPrefix:n,title:r}),h=m.customLogger;u??=Tt.PORT?parseInt(Tt.PORT,10):void 0,u||=await Ve({port:[5173,5174,...Be(61e3,61010),...Be(62002,62010)]});let g=24678,_=await mkTempPublicDir(),v=l??(O()?`0.0.0.0`:`localhost`);t?(g=await Ve({port:Be(24678,24690)}),h.info(`Enabling HMR: localhost:${g}`),O()&&h.info(S.yellow(`ensure port ${g} is published from container`))):h.info(`Disabling HMR`);let y=await Rt({...m,define:t?{...m.define,"process.env.NODE_ENV":`"development"`}:m.define,mode:t?`development`:m.mode,publicDir:_,optimizeDeps:{force:!0},server:{host:v,allowedHosts:!0,port:u,hmr:t&&{overlay:!0,port:g},fs:{strict:!1},open:c??(!p&&!O())}});if(e){let e=viteWebcomponentConfig({webcomponentPrefix:n,languageServices:i,outDir:_,base:m.base});h.info(`Building webcomponent`),Lt({...e,logLevel:`warn`}).catch(e=>{h.warn(a(e)),h.warn(`webcomponent build failed, ignoring error and continue`)})}else h.info(`Skip webcomponent build`);return await y.listen(),y}async function takeScreenshot({browserContext:e,views:t,output:n,logger:r,timeout:i,maxAttempts:a,dynamicVariant:s,outputType:c,theme:l,format:u=`png`,quality:f}){let p,m=t.map(e=>({view:e,attempt:1})),h=[],g;for(;g=m.shift();){let{view:t,attempt:_}=g,v=`export/${encodeURIComponent(t.id)}/`;try{if(_>1){p&&=(p.close({runBeforeUnload:!0}).catch(e=>r.error(`failed to close page: ${e}`)),void 0);let e=de(_*200,{min:200,max:1e3});r.info(S.cyan(v)+S.dim(` attempt ${_} of ${a} after ${e}ms`)),await Ht(e)}else t.hasLayoutDrift&&r.warn(S.yellow(`Drift detected, manual layout can not be applied, view may be invalid: `)+S.red(t.id));let m=`.`;c===`relative`&&(m=t.sourcePath??`.`,m=m.includes(`/`)?m.slice(0,m.lastIndexOf(`/`)):`.`);let g=u===`jpeg`?`.jpg`:`.png`,y=H(n,m,`${t.id}${g}`);p??=await e.newPage();let b=t.bounds;s===`sequence`&&t._type===`dynamic`&&(b=t.sequenceLayout.bounds),await p.setViewportSize({width:b.width+40+20,height:b.height+40+20}),await p.goto(C(v,{padding:20,theme:l,dynamic:s,...u===`jpeg`?{format:`jpeg`}:{}})),r.info(S.cyan(v)+S.dim(` -> ${V(n,y)}`)),await p.waitForSelector(`.react-flow.initialized`),t.nodes.some(e=>se(e.icon)&&e.icon.toLowerCase().startsWith(`http`))&&await waitAllImages(p,i),await p.getByTestId(`export-page`).screenshot({animations:`disabled`,path:y,type:u===`jpeg`?`jpeg`:`png`,...u===`jpeg`?{quality:f??80,omitBackground:!1}:{omitBackground:!0}}),h.push({view:t,path:y})}catch(e){p?.close({runBeforeUnload:!0}).catch(e=>r.error(`failed to close page: ${e}`)),r.error(S.red(`failed `+v+`
257
- `+e)),_<a&&(m.push({view:t,attempt:_+1}),r.info(S.dim(`retry ${v}`))),p=void 0}}return h}async function waitAllImages(e,t){let n=await e.locator(`//img`).all();if(!n.length)return;let r=n.map(e=>e.evaluate(e=>e.complete||new Promise(t=>{e.onload=t,e.onerror=t}),{timeout:Math.max(15e3,t)}));await Promise.allSettled(r)}async function exportViewsToPNG({logger:e,serverUrl:t,theme:n=`light`,timeoutMs:r=15e3,views:i,output:a,outputType:s=`relative`,maxAttempts:c=3,chromiumSandbox:l=!1,sequence:u=!1,format:f=`png`,quality:p}){e.info(`${S.dim(`output`)} ${a}`),e.info(`${S.dim(`base url`)} ${t}\n`);let{chromium:m}=await import(`playwright`),h=m.executablePath();e.info(S.cyan(`Start chromium`)+` `+S.dim(h));let g=await m.launch({chromiumSandbox:l,headless:!0});e.info(S.cyan(`Color scheme: `)+n+`
258
- `);let _=await g.newContext({deviceScaleFactor:2,colorScheme:n,baseURL:t,bypassCSP:!0,ignoreHTTPSErrors:!0,isMobile:!1});_.setDefaultNavigationTimeout(r),_.setDefaultTimeout(r);try{return await takeScreenshot({browserContext:_,views:i,output:a,outputType:s,logger:e,maxAttempts:c,dynamicVariant:u?`sequence`:`diagram`,timeout:r,theme:n,format:f,quality:p})}finally{e.info(S.cyan(`close chromium`)),await _.close(),await g.close()}}async function runExportPng(e,t){try{var n=_usingCtx();let{path:r,useDotBin:i,project:a,theme:s=`light`,output:c,outputType:u,serverUrl:f,ignore:p=!1,timeoutMs:m=15e3,maxAttempts:h=3,filter:g,sequence:_=!1,chromiumSandbox:v=!1,format:y=`png`,quality:b}=e,x=n.a(await l(r,{graphviz:i?`binary`:`wasm`,watch:!1})),ee=c??x.workspace,C,w=f,T=[...x.languageServices.projects()];if(a&&!T.some(e=>e.id===a))throw t.error(`project not found: ${a}`),Error(`project not found: ${a}`);try{if(!w&&(t.info(S.cyan(`start preview server`)),C=await viteDev({languageServices:x,buildWebcomponent:!1,openBrowser:!1,hmr:!1}),w=resolveServerUrl(C),!w))throw t.error(`Vite server is not ready, no resolvedUrls`),Error(`Vite server is not ready, no resolvedUrls`);for(let e of T){if(a&&e.id!==a)continue;T.length>1&&(t.info(S.dim(`---------`)),t.info(`${S.dim(`project:`)} ${e.id}`),t.info(`${S.dim(`folder:`)} ${e.folder.fsPath}`));let n=await x.diagrams(e.id);if(g&&ue(g,1)&&ue(n,1)){let e=(0,Nn.default)(g);t.info(`${S.cyan(`filter`)} ${S.dim(JSON.stringify(g))}`),n=n.filter(n=>e(n.id)?(t.info(`${S.green(`include`)} ${n.id} ✅`),!0):(t.info(`${S.gray(`skip`)} ${S.dim(n.id)}`),!1))}if(!ue(n,1)){t.warn(`no views found`);continue}let r=T.length>1?te(ne(w,`project`,e.id)):w,i=T.length>1?ne(ee,e.id):ee,c=Nt(),l=await exportViewsToPNG({logger:t,serverUrl:r,theme:s,timeoutMs:m,views:n,output:i,outputType:u,maxAttempts:h,sequence:_,chromiumSandbox:v,format:y,quality:b}),{pretty:f}=inMillis(c);if(l.length>0&&t.info(S.green(`exported ${l.length} views in ${f}`)+`
259
- `),l.length!==n.length&&(p&&l.length>0?t.info(S.dim(`ignore`)+` `+S.red(`failed ${n.length-l.length} out of ${n.length} views`)):t.error(S.red(`failed ${n.length-l.length} out of ${n.length} views`))),l.length!==n.length&&(l.length===0||!p))throw Error(`Failed ${n.length-l.length} out of ${n.length} views`)}}finally{C&&(t.info(S.cyan(`stop server`)),await C.close().catch(e=>{t.error(e)}))}}catch(e){n.e=e}finally{await n.d()}}async function pngHandler(e){await runExportPng(e,createLikeC4Logger(`c4:export`))}function pngCmd(e){return e.command({command:`png [path]`,describe:`export views to PNG`,builder:e=>e.positional(`path`,q).options({outdir:{alias:[`o`,`output`],type:`string`,desc:`output directory for PNG files; if not specified, images are saved next to sources`,normalize:!0,nargs:1,coerce:H},project:X,theme:{choices:[`light`,`dark`],desc:`color-scheme to use, defaults to light`,conflicts:[`dark`,`light`],nargs:1},dark:{type:`boolean`,desc:`use dark theme, shortcut for --theme=dark`,conflicts:[`theme`,`light`]},light:{type:`boolean`,desc:`use light theme, shortcut for --theme=light`,conflicts:[`theme`,`dark`]},"use-dot":J,seq:{alias:[`sequence`],type:`boolean`,desc:`use sequence layout for dynamic views`},flat:{alias:[`flatten`],type:`boolean`,desc:`flatten all images in outdir ignoring sources structure`},filter:{alias:`f`,array:!0,string:!0,desc:`include views with ids matching given patterns
260
- multiple patterns are combined with OR`},ignore:{boolean:!0,alias:`i`,desc:`continue if export fails for some views`},timeout:{type:`number`,alias:`t`,desc:`timeout for playwright (in seconds)`,default:15,nargs:1},"max-attempts":{type:`number`,desc:`max attempts to export failing view, 1 means no retry`,default:3,nargs:1},"server-url":{type:`string`,desc:`use this url instead of starting new likec4 server`,nargs:1},"chromium-sandbox":{boolean:!0,desc:`enable chromium sandbox (see Playwright docs)`,default:!1}}).epilog(`${S.bold(`Examples:`)}
261
- ${S.green(`$0 export png`)}
262
- ${S.gray(`Search for likec4 files in current directory and output PNG next to sources`)}
263
-
264
- ${S.green(`$0 export png --theme dark -o ./png src/likec4`)}
265
- ${S.gray(`Search for likec4 files in src/likec4 and output PNG with dark theme to png folder`)}
266
-
267
- ${S.green(`$0 export png -f "team1*" -f "team2*" --flat -o ./png src/likec4`)}
268
- ${S.gray(`Export views matching team1* or team2* only`)}
269
-
270
- ${S.green(`$0 export png -f "use-case*" --sequence src/likec4`)}
271
- ${S.gray(`Export views matching use-case* using sequence layout`)}
272
- `),handler:async e=>{R(e.timeout>=1,`timeout must be >= 1`),R(e[`max-attempts`]>=1,`max-attempts must be >= 1`),await ensureReact(),await ensurePlaywright();let t=e.theme??(e.dark?`dark`:`light`);await pngHandler({path:e.path,useDotBin:e[`use-dot`],output:e.outdir,project:e.project,timeoutMs:e.timeout*1e3,maxAttempts:e[`max-attempts`],ignore:e.ignore===!0,outputType:e.flat?`flat`:`relative`,serverUrl:e[`server-url`],theme:t,filter:e.filter,sequence:e.seq,chromiumSandbox:e[`chromium-sandbox`]}),showSupportUsMessage()}})}async function jpgHandler(e){let t=createLikeC4Logger(`c4:export`);await runExportPng({...e,format:`jpeg`},t)}function jpgCmd(e){return e.command({command:`jpg [path]`,describe:`export views to JPEG`,builder:e=>e.positional(`path`,q).options({outdir:{alias:[`o`,`output`],type:`string`,desc:`output directory for JPEG files; if not specified, images are saved next to sources`,normalize:!0,nargs:1,coerce:H},project:X,quality:{alias:`q`,type:`number`,desc:`JPEG quality (1-100)`,default:80,nargs:1},theme:{choices:[`light`,`dark`],desc:`color-scheme to use, defaults to light`,conflicts:[`dark`,`light`],nargs:1},dark:{type:`boolean`,desc:`use dark theme, shortcut for --theme=dark`,conflicts:[`theme`,`light`]},light:{type:`boolean`,desc:`use light theme, shortcut for --theme=light`,conflicts:[`theme`,`dark`]},"use-dot":J,seq:{alias:[`sequence`],type:`boolean`,desc:`use sequence layout for dynamic views`},flat:{alias:[`flatten`],type:`boolean`,desc:`flatten all images in outdir ignoring sources structure`},filter:{alias:`f`,array:!0,string:!0,desc:`include views with ids matching given patterns
273
- multiple patterns are combined with OR`},ignore:{boolean:!0,alias:`i`,desc:`continue if export fails for some views`},timeout:{type:`number`,alias:`t`,desc:`timeout for playwright (in seconds)`,default:15,nargs:1},"max-attempts":{type:`number`,desc:`max attempts to export failing view, 1 means no retry`,default:3,nargs:1},"server-url":{type:`string`,desc:`use this url instead of starting new likec4 server`,nargs:1},"chromium-sandbox":{boolean:!0,desc:`enable chromium sandbox (see Playwright docs)`,default:!1}}).epilog(`${S.bold(`Examples:`)}
274
- ${S.green(`$0 export jpg`)}
275
- ${S.gray(`Search for likec4 files in current directory and output JPEG next to sources`)}
276
-
277
- ${S.green(`$0 export jpg --theme dark -o ./jpg src/likec4`)}
278
- ${S.gray(`Search for likec4 files in src/likec4 and output JPEG with dark theme to jpg folder`)}
279
-
280
- ${S.green(`$0 export jpg --quality 90 -o ./jpg src/likec4`)}
281
- ${S.gray(`Export JPEG with 90% quality`)}
282
-
283
- ${S.green(`$0 export jpg -f "team1*" -f "team2*" --flat -o ./jpg src/likec4`)}
284
- ${S.gray(`Export views matching team1* or team2* only`)}
285
- `),handler:async e=>{R(e.quality>=1&&e.quality<=100,`quality must be between 1 and 100`),R(e.timeout>=1,`timeout must be >= 1`),R(e[`max-attempts`]>=1,`max-attempts must be >= 1`),await ensureReact(),await ensurePlaywright();let t=e.theme??(e.dark?`dark`:`light`);await jpgHandler({path:e.path,useDotBin:e[`use-dot`],output:e.outdir,project:e.project,timeoutMs:e.timeout*1e3,maxAttempts:e[`max-attempts`],ignore:e.ignore===!0,outputType:e.flat?`flat`:`relative`,serverUrl:e[`server-url`],theme:t,filter:e.filter,sequence:e.seq,chromiumSandbox:e[`chromium-sandbox`],format:`jpeg`,quality:e.quality}),showSupportUsMessage()}})}const Pn=`project not found`,Fn=`No projects found`;async function runExportJson(e,t){try{var n=_usingCtx();let r=startTimer(t),i=n.a(await l(e.path,{graphviz:e.useDot?`binary`:`wasm`,watch:!1})),a=[...i.projectsManager.all];if(e.project){if(a=a.filter(t=>t===e.project),!ue(a,1))throw t.error(`${Pn}: ${e.project}`),Error(`${Pn}: ${e.project}`)}else{if(!ue(a,1))throw t.error(Fn),Error(Fn);t.info(`${S.dim(`workspace:`)} Found ${a.length} projects`)}let s=[];for(let n of a){let r;if(e.skipLayout?(t.info(`Generate model for project ${S.green(n)} ${S.dim(`(skip layout)`)}`),r=await i.computedModel(n)):(t.info(`Generating layouted model for project ${S.green(n)}`),r=await i.layoutedModel(n)),r===Oe.EMPTY){t.warn(S.yellow(`Project ${n} is empty, skipping`));continue}s.push(r.$data)}if(s.length===0)throw t.warn(`No models generated, aborting export`),Error(`No models generated; all projects are empty or were skipped`);let c=e.outfile;Je(c).toLowerCase()!==`.json`&&(c+=`.json`),await W(z(c),{recursive:!0});let u=s.length===1?s[0]:s,f=e.pretty?JSON.stringify(u,void 0,2):JSON.stringify(u);await G(c,f);let p=c.startsWith(e.path)?V(e.path,c):c;t.info(`${S.dim(`generated`)} ${p}`),r.stopAndLog(`✓ export in `)}catch(e){n.e=e}finally{await n.d()}}function jsonCmd(e){return e.command({command:`json [path]`,describe:`export model(s) to JSON`,builder:e=>e.positional(`path`,q).option(`outfile`,{alias:`o`,type:`string`,desc:`<file> output .json file`,default:`likec4.json`,normalize:!0,coerce:H}).options({project:X,"use-dot":J,"skip-layout":{type:`boolean`,desc:`skip layouting (only compute model)`},pretty:{type:`boolean`,desc:`indented JSON output`}}).epilog(`${S.bold(`Examples:`)}
286
- ${S.green(`$0 export json --skip-layout`)}
287
- ${S.gray(`Search for likec4 files in current directory and output JSON to likec4.json (no layout)`)}
288
-
289
- ${S.green(`$0 export json --pretty -o ./generated/likec4.json src/likec4 `)}
290
- ${S.gray(`Search for likec4 files in src/likec4 and output JSON to generated/likec4.json`)}
291
- `),handler:async e=>{let t=createLikeC4Logger(`c4:export`);await runExportJson({path:e.path,outfile:e.outfile,project:e.project,skipLayout:!!e.skipLayout,pretty:!!e.pretty,useDot:!!e[`use-dot`]},t),showSupportUsMessage()}})}const exportCmd=e=>e.command({command:`export <format> [path]`,describe:`Export to images, JSON, or DrawIO`,builder:e=>le(e.usage(`${S.bold(`Usage:`)} $0 export <format> [path]`),pngCmd,jpgCmd,jsonCmd,drawioCmd).updateStrings({"Commands:":S.bold(`Formats:`)}),handler:()=>void 0}),formatCmd=e=>e.command({command:`format [path]`,aliases:[`fmt`],describe:`Format LikeC4 source files`,builder:e=>e.positional(`path`,q).options({project:{alias:`p`,type:`string`,array:!0,desc:`select project(s) to format (repeatable)`},files:{type:`string`,array:!0,normalize:!0,coerce:e=>e.map(e=>H(e)),desc:`specific file(s) to format (repeatable)`},check:{type:`boolean`,desc:`Check if files are formatted (exit with 1 if not)`,default:!1}}),handler:async e=>{try{var t=_usingCtx();let n=createLikeC4Logger(`c4:format`),r=startTimer(n),i=e.check,a;try{a=await l(e.path,{watch:!1})}catch(e){n.error(e instanceof Error?e.message:String(e)),process.exitCode=1;return}t.a(a);let s=e.project?.filter(Boolean),c=e.files?.filter(Boolean).map(e=>wt(e).toString());if(n.debug(`workspace: ${e.path}`),s?.length){n.debug(`projects:`);for(let e of s)n.debug(` ${e}`)}if(c?.length){n.debug(`files:`);for(let e of c)n.debug(` ${Ct(e)}`)}let u;try{u=await a.format({...s?.length&&{projects:s},...c?.length&&{documentUris:c}})}catch(e){n.error(e instanceof Error?e.message:String(e)),process.exitCode=1;return}n.debug(`${u.size} document(s) to process`);let f=process.cwd(),displayPath=e=>{let t=V(f,e);return t.startsWith(`..`)?e:t};if(c){let e=c.filter(e=>!u.has(e));for(let t of e)n.warn(`${S.yellow(`skipped`)} ${displayPath(Ct(t))} (not found in workspace)`)}let p=0,m=0,h=[];for(let[e,t]of u){let r=Ct(e),a=displayPath(r),s;try{s=await vt(r,`utf-8`)}catch(e){n.error(`Failed to read ${a}: ${e}`),m++;continue}if(s===t){n.debug(`${S.dim(`unchanged`)} ${a}`);continue}if(p++,h.push(a),i)n.info(`${S.yellow(`needs formatting`)} ${a}`);else try{await G(r,t,`utf-8`),n.info(`${S.green(`formatted`)} ${a}`)}catch(e){n.error(`Failed to write ${a}: ${e}`),m++}}if(m>0){n.error(`${m} file(s) failed to process`),process.exitCode=1;return}if(i){if(p>0){n.error(`${p} of ${u.size} file(s) need formatting:\n${h.map(e=>` ${e}`).join(`
292
- `)}`),process.exitCode=1;return}n.info(S.green(`All ${u.size} file(s) are formatted`))}else p>0?n.info(`${S.green(String(p))} of ${u.size} file(s) formatted`):n.info(S.green(`All ${u.size} file(s) already formatted`));r.stopAndLog(`✓ format in `)}catch(e){t.e=e}finally{await t.d()}}}),listIconsCmd=e=>e.command({command:`list-icons`,describe:`List available built-in icons`,builder:e=>e.option(`format`,{alias:`f`,choices:[`text`,`json`],default:`text`,description:`Output format`}).option(`group`,{alias:`g`,choices:s,description:`Filter icons by group`}),handler:e=>{let t=e.group?[e.group]:s;switch(!0){case e.format===`json`:{let e=Object.fromEntries(t.map(e=>[e,n[e]]));console.log(JSON.stringify(e,null,2));break}default:for(let e of t)for(let t of n[e])console.log(`${e}:${t}`)}}});var In=He();function lsp_default(e){return e.command({command:`lsp`,aliases:[],describe:`Start LSP server`,builder:e=>e.usage(`${S.bold(`Usage:`)} $0 lsp`).option(`log-level`,an).option(`verbose`,on).options({"node-ipc":{boolean:!0,description:`use node-ipc transport`,conflicts:[`stdio`,`socket`,`pipe`]},stdio:{boolean:!0,description:`use stdio transport`,conflicts:[`node-ipc`,`socket`,`pipe`]},socket:{number:!0,description:`use socket transport on specified port`,conflicts:[`node-ipc`,`stdio`,`pipe`],nargs:1},pipe:{string:!0,description:`use pipe transport with specified pipe name`,conflicts:[`node-ipc`,`stdio`,`socket`],nargs:1},"manual-layouts":{boolean:!0,description:`enable/disable manual layouts`,default:!0,defaultDescription:`enabled`},watch:{alias:`w`,boolean:!0,description:`enable built-in watcher`,default:!1,defaultDescription:`disabled`},telemetry:{boolean:!0,default:!0,defaultDescription:`IDE setting`,description:`enable/disable telemetry`,hidden:!0}}).option(`use-dot`,J).showHidden().epilog(`${S.bold(`Examples:`)}
293
-
294
- ${S.green(`$0 lsp --stdio `)}
295
- ${S.gray(`Start LSP with stdio transport`)}
296
-
297
- ${S.green(`$0 lsp --node-ipc --watch --no-manual-layouts --no-color `)}
298
- ${S.gray(`Start LSP with node-ipc transport and watcher, disabled manual layouts and disabled color`)}
299
-
300
- `),handler:e=>{let t;if(e.nodeIpc||e.stdio||e.socket||e.pipe)t=(0,In.createConnection)(In.ProposedFeatures.all);else throw Error(`No transport specified`);u({lspConnection:t,useStdErr:e.stdio===!0,colors:S.isColorSupported,enableTelemetry:e.telemetry,logLevel:e.verbose?sn:e.logLevel}),f({connection:t,enableManualLayouts:e.manualLayouts,enableWatcher:e.watch,graphviz:e.useDot?`binary`:`wasm`,configureLogger:!1})}})}t(lsp_default,`default`);const Z=r.getChild(`mcp`);function likec4Tool(e,t){let{name:n,description:r,...i}=e;return e=>[n,{description:r?.trim()??``,...i},mkcallTool(n,e,t)]}function mkcallTool(e,t,n){let r=n.bind(null,t);return(async function callTool(t,n){Z.debug(`Calling tool {name}, args: {args}`,{name:e,args:t});try{let e=await r.call(null,t,n);return typeof e==`string`?{content:[{type:`text`,text:e}]}:{content:[{type:`text`,text:JSON.stringify(e)}],structuredContent:e}}catch(t){return Z.error(`Tool ${e} failed`,{err:t}),{content:[{type:`text`,text:a(t)}],isError:!0}}})}var Ln=`1.56.0`;const Rn=A({name:L().describe(`Project identifier`),title:L().optional().describe(`Human-readable project title`),contactPerson:L().optional().describe(`Maintainer contact information`),metadata:M(L(),Fe()).optional().describe(`Custom project metadata as key-value pairs`),extends:j([L(),N(L())]).optional().describe(`Style inheritance paths`),exclude:N(L()).optional().describe(`File exclusion patterns`),include:A({paths:N(L()).describe(`Include paths`),maxDepth:I().describe(`Maximum directory depth`),fileThreshold:I().describe(`File threshold`)}).optional().describe(`Include configuration`),manualLayouts:A({outDir:L().describe(`Output directory for manual layouts`)}).optional().describe(`Manual layouts configuration`),styles:A({hasTheme:F().describe(`Whether theme customization is defined`),hasDefaults:F().describe(`Whether default style values are defined`),hasCustomCss:F().describe(`Whether custom CSS is defined`)}).optional().describe(`Simplified styles configuration (boolean flags)`)});function serializeConfig(e){let t={name:e.name};return e.title!=null&&(t.title=e.title),e.contactPerson!=null&&(t.contactPerson=e.contactPerson),e.metadata&&(t.metadata=e.metadata),e.extends&&(t.extends=e.extends),e.exclude&&(t.exclude=e.exclude),e.include&&(t.include={paths:e.include.paths||[],maxDepth:e.include.maxDepth??3,fileThreshold:e.include.fileThreshold??30}),e.manualLayouts&&(t.manualLayouts={outDir:e.manualLayouts.outDir??`.likec4`}),e.styles&&(t.styles={hasTheme:!!e.styles.theme,hasDefaults:!!e.styles.defaults,hasCustomCss:!!e.styles.customCss}),t}const Q=A({id:L().describe(`Element id (FQN)`),name:L().describe(`Element name`),kind:L().describe(`Element kind`),title:L(),tags:N(L()),metadata:M(j([L(),N(L())])),includedInViews:N(A({id:L().describe(`View id`),title:L().describe(`View title`),type:k([`element`,`deployment`,`dynamic`]).describe(`View type`)})).describe(`Views that include this element`)});function serializeElement(e){return{id:e.id,name:e.name,kind:e.kind,title:e.title,tags:[...e.tags],metadata:e.getMetadata(),includedInViews:includedInViews(e.views())}}function traverseGraph(e,t,n,r,i,a){R(e.findElement(t),`Element "${t}" not found`);let s=new Set,c={},l=0,u=!1,f=[{elementId:t,depth:0}];for(;f.length>0;){let{elementId:t,depth:p}=f.shift();if(p>i||s.has(t))continue;if(s.size>=a){u=!0;break}let m=e.findElement(t);if(!m)continue;s.add(t),l=Math.max(l,p);let h=(n===`incoming`?[...m.incoming(r)]:[...m.outgoing(r)]).map(e=>{let t={elementId:n===`incoming`?e.source.id:e.target.id};return e.title&&(t.relationshipLabel=e.title),e.technology&&(t.technology=e.technology),t});c[t]={...serializeElement(m),neighbors:h,depth:p};for(let e of h)s.has(e.elementId)||f.push({elementId:e.elementId,depth:p+1})}for(let e of Object.values(c))e.neighbors=e.neighbors.filter(e=>e.elementId in c);return{target:t,totalNodes:s.size,maxDepth:l,truncated:u,nodes:c}}const zn=A({path:L().describe(`Path to the file`),range:A({start:A({line:I(),character:I()}),end:A({line:I(),character:I()})}).describe(`Range in the file`)}).nullable(),$=L().refine(e=>!0).optional().default(`default`).describe(`Project id (optional, will use "default" if not specified)`),Bn=N(A({id:L().describe(`View id`),title:L().describe(`View title`),type:k([`element`,`deployment`,`dynamic`]).describe(`View type`)})),includedInViews=e=>[...e].map(e=>({id:e.id,title:e.titleOrId,type:e.$view._type})),mkLocate=(e,t)=>n=>{try{let r=e.locate({projectId:t,...n});return r?{path:g.parse(r.uri).fsPath,range:r.range}:null}catch(e){return Z.debug(`Failed to locate {params}`,{error:e,params:n}),null}},Vn=Q.extend({description:L().nullable().describe(`Element description`),technology:L().nullable().describe(`Element technology`),shape:L().describe(`Rendered shape`),color:L().describe(`Rendered color`),children:N(L()).describe(`Direct child element ids`),incomingCount:I().describe(`Number of incoming relationships`),outgoingCount:I().describe(`Number of outgoing relationships`)}),Hn=likec4Tool({name:`batch-read-elements`,description:`
237
+ `),handler:async e=>{await customHandler({name:e.command,path:e.path,project:e.project,useDotBin:e.useDotBin})}}),Bn=new Set([`node_modules`,`.git`]);function isSourceFile(e){return e.endsWith(`.c4`)||e.endsWith(`.likec4`)}function joinNonEmptyFiles(e,t=`
238
+
239
+ `){return e.filter(e=>e.trim()!==``).join(t)}const Vn=`No project or empty model`,Hn=`No views could be exported`;function getDrawioEpilog(){return`${C.bold(`Examples:`)}
240
+ ${C.green(`$0 export drawio`)}
241
+ ${C.gray(`Export each view to a separate .drawio file`)}
242
+
243
+ ${C.green(`$0 export drawio --all-in-one -o ./diagrams src/`)}
244
+ ${C.gray(`Export all views as tabs in one .drawio file`)}
245
+
246
+ ${C.green(`$0 export drawio --roundtrip -o ./out`)}
247
+ ${C.gray(`Re-apply layout/waypoints from comment blocks (e.g. after import from DrawIO)`)}
248
+
249
+ ${C.green(`$0 export drawio --uncompressed -o ./out`)}
250
+ ${C.gray(`Export with raw XML (no compression) for draw.io desktop compatibility`)}
251
+
252
+ ${C.green(`$0 export drawio --profile leanix -o ./out`)}
253
+ ${C.gray(`Export with bridge-managed metadata (likec4Id, likec4ViewId, etc.) for LeanIX interoperability`)}`}function toError(e){return e instanceof Error?e:Error(u(e))}function logAndRethrow(e,t,n){let r=toError(n);throw e.error(t,{error:r}),r}async function readWorkspaceSourceContent(e,t){let n=[],r=new Set;async function walk(e,i){if(i>=50)return;let a=await Dt(e).catch(()=>null);if(a==null||r.has(a))return;r.add(a);let s=await Et(e,{withFileTypes:!0}).catch(n=>(t?.debug&&t.debug(`${C.dim(`Roundtrip:`)} readdir failed`,{dir:e,err:n}),[]));for(let r of s){let a=B(e,r.name);switch(!0){case r.isDirectory():Bn.has(r.name)||await walk(a,i+1);break;case r.isSymbolicLink():if((await kt(a).catch(()=>null))?.isFile()&&isSourceFile(r.name)){let e=await Tt(a,`utf-8`).catch(e=>(t?.debug&&t.debug(`${C.dim(`Roundtrip:`)} readFile failed`,{file:a,err:e}),``));e&&n.push(e)}break;case r.isFile()&&isSourceFile(r.name):{let e=await Tt(a,`utf-8`).catch(e=>(t?.debug&&t.debug(`${C.dim(`Roundtrip:`)} readFile failed`,{file:a,err:e}),``));e&&n.push(e);break}}}}return await walk(e,0),joinNonEmptyFiles(n)}async function getSourceContentIfRoundtrip(e,t,n){if(t)return readWorkspaceSourceContent(H(e),n)}function buildDrawioExportOverrides(e,t,n){let r=e?{compressed:!1}:{compressed:!0};return t===`leanix`&&(r.profile=`leanix`,r.projectId=n),r}function buildOptionsByViewId(e,t,n,r,i){return Te(e.map(e=>String(e.$view.id)),t,buildDrawioExportOverrides(n,r,i))}async function exportDrawioAllInOne(e){let{viewmodels:t,outdir:n,workspacePath:r,roundtrip:i,uncompressed:a,profile:s,projectId:c,logger:l}=e,u=Oe(t,buildOptionsByViewId(t,await getSourceContentIfRoundtrip(r,i,l),a,s,c)),f=H(n,Ae);await K(f,u),l.info(`${C.dim(`generated`)} ${V(process.cwd(),f)} (${t.length} tab(s))`)}async function writeViewToFile(e,t,n,r){let i=String(e.$view.id);try{let a=Ce(e,t[i]),s=H(n,i+`.drawio`);return await G(z(s),{recursive:!0}),await K(s,a),r.info(`${C.dim(`generated`)} ${V(process.cwd(),s)}`),!0}catch(e){return r.error(`Failed to export view ${i}`,{error:toError(e)}),!1}}async function exportDrawioPerView(e){let{viewmodels:t,outdir:n,workspacePath:r,roundtrip:i,uncompressed:a,profile:s,projectId:c,logger:l}=e,u=buildOptionsByViewId(t,await getSourceContentIfRoundtrip(r,i,l),a,s,c),f=0;for(let e of t)await writeViewToFile(e,u,n,l)&&f++;return{succeeded:f}}async function runExportDrawio(e,t){try{var n=_usingCtx();let r=startTimer(t),i=n.a(await c(e.path,{graphviz:e.useDot?`binary`:`wasm`,watch:!1}));e.project||i.ensureSingleProject();let a=e.project==null?void 0:i.languageServices.projectsManager.ensureProjectId(e.project),s=await i.layoutedModel(a);if(s===Me.EMPTY)throw t.error(Vn),Error(Vn);let l=[...s.views()];if(l.length===0)throw t.error(`No views to export`),Error(Hn);await G(e.outdir,{recursive:!0});let u=String(s.projectId),f={viewmodels:l,outdir:e.outdir,workspacePath:e.path,roundtrip:e.roundtrip,uncompressed:e.uncompressed,profile:e.profile,projectId:u,logger:t};if(e.allInOne)try{await exportDrawioAllInOne(f)}catch(e){logAndRethrow(t,`Failed to export DrawIO`,e)}else{let{succeeded:e}=await exportDrawioPerView(f);if(e===0)throw t.error(Hn),Error(Hn);t.info(`${C.dim(`total`)} ${e} DrawIO file(s)`)}r.stopAndLog(`✓ export drawio in `)}catch(e){n.e=e}finally{await n.d()}}function drawioCmd(e){return e.command({command:`drawio [path]`,describe:`export view(s) to DrawIO (.drawio) for editing in draw.io`,builder:e=>e.positional(`path`,J).option(`outdir`,{alias:`o`,type:`string`,desc:`<dir> output directory for .drawio files`,normalize:!0,coerce:H}).option(`all-in-one`,{type:`boolean`,default:!1,desc:`write one .drawio file with all views as tabs (diagrams)`}).option(`roundtrip`,{type:`boolean`,default:!1,desc:`apply layout/stroke/waypoints from DrawIO round-trip comment blocks in .c4 source`}).option(`uncompressed`,{type:`boolean`,default:!1,desc:`write diagram XML uncompressed inside .drawio (larger file; use if draw.io desktop fails to open compressed export)`}).option(`profile`,{type:`string`,choices:[`default`,`leanix`],default:`default`,desc:`export profile: default (round-trip) or leanix (bridge-managed metadata for LeanIX interoperability)`}).options({project:Z,"use-dot":Y}).epilog(getDrawioEpilog()),handler:async e=>{let t=createLikeC4Logger(`c4:export`);await runExportDrawio({path:e.path,outdir:e.outdir??e.path,allInOne:!!e.allInOne,roundtrip:!!e.roundtrip,uncompressed:!!e.uncompressed,profile:e.profile===`leanix`?`leanix`:`default`,project:e.project,useDot:!!e[`use-dot`]},t)}})}var Un=e(ye(),1);function resolveServerUrl(e){if(e.resolvedUrls)return pe(e.resolvedUrls.network)??pe(e.resolvedUrls.local)}function printServerUrls(e){if(!e.resolvedUrls)throw Error(`Vite server is not ready, no resolvedUrls`);boxen([C.green(`LikeC4 served at:`),``,C.dim(`Local: `)+e.resolvedUrls.local.join(`
254
+ `+``.padEnd(9,` `)),e.resolvedUrls.network.length?C.dim(`Network: `)+e.resolvedUrls.network.join(`
255
+ `+``.padEnd(9,` `)):void 0].filter(e=>ge(e)).join(`
256
+ `))}function validatePort(e,t){if(!Number.isInteger(e)||e<1||e>65535)throw Error(`Invalid HMR port from ${t}: ${e}. Must be an integer between 1 and 65535.`)}async function resolveHmrPort(e,t){if(t){if(e!==void 0)return validatePort(e,`explicitPort`),e;if(Mt.HMR_PORT){let e=Number.parseInt(Mt.HMR_PORT,10);return validatePort(e,`HMR_PORT`),e}return Ge({port:We(24678,24690)})}}async function viteDev({buildWebcomponent:e=!1,hmr:t=!0,webcomponentPrefix:n=`likec4`,title:r,languageServices:i,likec4AssetsDir:a,openBrowser:s,listen:c,port:l,hmrPort:f,userPublicDir:p,allowedHosts:m,...h}){a??=await wt(B(gt(),`.likec4-assets-`));let{isDev:g,..._}=await viteConfig({...h,languageServices:i,likec4AssetsDir:a,webcomponentPrefix:n,title:r}),v=_.customLogger;l??=Mt.PORT?parseInt(Mt.PORT,10):void 0,l||=await Ge({port:[5173,5174,...We(61e3,61010),...We(62002,62010)]});let y=await mkTempPublicDir();p&&await copyUserPublicDir(p,y);let b=c??(k()?`0.0.0.0`:`localhost`),x=await resolveHmrPort(f,t);if(t&&x!==void 0){let e=f?` (explicit)`:Mt.HMR_PORT?` (env)`:` (auto-discovered)`;v.info(`Enabling HMR: localhost:${x}${e}`),k()&&v.info(C.yellow(`ensure port ${x} is published from container`))}else t||v.info(`Disabling HMR`);let S=await Gt({..._,define:t?{..._.define,"process.env.NODE_ENV":`"development"`}:_.define,mode:t?`development`:_.mode,publicDir:y,optimizeDeps:{force:!0},server:{host:b,allowedHosts:m&&m.length>0?m:!0,port:l,hmr:t&&{overlay:!0,...x===void 0?{}:{port:x}},fs:{strict:!1},open:s??(!g&&!k())}});if(e){let e=viteWebcomponentConfig({webcomponentPrefix:n,languageServices:i,outDir:y,base:_.base});v.info(`Building webcomponent`),Wt({...e,logLevel:`warn`}).catch(e=>{v.warn(u(e)),v.warn(`webcomponent build failed, ignoring error and continue`)})}else v.info(`Skip webcomponent build`);return await S.listen(),S}function createExportViewUrl({viewId:e,padding:t,theme:n,dynamicVariant:r,format:i=`png`,notation:a=!1,description:s=!1}){return w(`export/${encodeURIComponent(e)}/`,{padding:t,theme:n,dynamic:r,...a?{notation:!0}:{},...s?{description:!0}:{},...i===`jpeg`?{format:`jpeg`}:{}})}async function takeScreenshot({browserContext:e,views:t,output:n,logger:r,timeout:i,maxAttempts:a,dynamicVariant:s,outputType:c,theme:l,format:u=`png`,quality:f,notation:p=!1,description:m=!1}){let h,g=t.map(e=>({view:e,attempt:1})),_=[],v;for(;v=g.shift();){let{view:t,attempt:y}=v,b=`export/${encodeURIComponent(t.id)}/`;try{if(y>1){h&&=(h.close({runBeforeUnload:!0}).catch(e=>r.error(`failed to close page: ${e}`)),void 0);let e=fe(y*200,{min:200,max:1e3});r.info(C.cyan(b)+C.dim(` attempt ${y} of ${a} after ${e}ms`)),await Yt(e)}else t.hasLayoutDrift&&r.warn(C.yellow(`Drift detected, manual layout can not be applied, view may be invalid: `)+C.red(t.id));let g=`.`;c===`relative`&&(g=t.sourcePath??`.`,g=g.includes(`/`)?g.slice(0,g.lastIndexOf(`/`)):`.`);let v=u===`jpeg`?`.jpg`:`.png`,x=H(n,g,`${t.id}${v}`);h??=await e.newPage();let S=t.bounds;s===`sequence`&&t._type===`dynamic`&&(S=t.sequenceLayout.bounds),await h.setViewportSize({width:S.width+40+20,height:S.height+40+20}),await h.goto(createExportViewUrl({viewId:t.id,padding:20,theme:l,dynamicVariant:s,format:u,notation:p,description:m})),r.info(C.cyan(b)+C.dim(` -> ${V(n,x)}`)),await h.waitForSelector(`.react-flow.initialized`);let w=h.getByTestId(`export-page`),T=await w.boundingBox();if(T){let e=Math.ceil(T.width),t=Math.ceil(T.height),n=h.viewportSize();(!n||e>n.width||t>n.height)&&await h.setViewportSize({width:e,height:t})}t.nodes.some(e=>ae(e.icon)&&e.icon.toLowerCase().startsWith(`http`))&&await waitAllImages(h,i),await w.screenshot({animations:`disabled`,path:x,type:u===`jpeg`?`jpeg`:`png`,...u===`jpeg`?{quality:f??80,omitBackground:!1}:{omitBackground:!0}}),_.push({view:t,path:x})}catch(e){h?.close({runBeforeUnload:!0}).catch(e=>r.error(`failed to close page: ${e}`)),r.error(C.red(`failed `+b+`
257
+ `+e)),y<a&&(g.push({view:t,attempt:y+1}),r.info(C.dim(`retry ${b}`))),h=void 0}}return _}async function waitAllImages(e,t){let n=await e.locator(`//img`).all();if(!n.length)return;let r=n.map(e=>e.evaluate(e=>e.complete||new Promise(t=>{e.onload=t,e.onerror=t}),{timeout:Math.max(15e3,t)}));await Promise.allSettled(r)}async function exportViewsToPNG({logger:e,serverUrl:t,theme:n=`light`,timeoutMs:r=15e3,views:i,output:a,outputType:s=`relative`,maxAttempts:c=3,chromiumSandbox:l=!1,sequence:u=!1,format:f=`png`,quality:p,notation:m=!1,description:h=!1}){e.info(`${C.dim(`output`)} ${a}`),e.info(`${C.dim(`base url`)} ${t}\n`);let{chromium:g}=await import(`playwright`),_=g.executablePath();e.info(C.cyan(`Start chromium`)+` `+C.dim(_));let v=await g.launch({chromiumSandbox:l,headless:!0});e.info(C.cyan(`Color scheme: `)+n+`
258
+ `);let y=await v.newContext({deviceScaleFactor:2,colorScheme:n,baseURL:t,bypassCSP:!0,ignoreHTTPSErrors:!0,isMobile:!1});y.setDefaultNavigationTimeout(r),y.setDefaultTimeout(r);try{return await takeScreenshot({browserContext:y,views:i,output:a,outputType:s,logger:e,maxAttempts:c,dynamicVariant:u?`sequence`:`diagram`,timeout:r,theme:n,format:f,quality:p,notation:m,description:h})}finally{e.info(C.cyan(`close chromium`)),await y.close(),await v.close()}}async function runExportPng(e,t){try{var n=_usingCtx();let{path:r,useDotBin:i,project:a,theme:s=`light`,output:l,outputType:u,serverUrl:f,ignore:p=!1,timeoutMs:m=15e3,maxAttempts:h=3,filter:g,sequence:_=!1,chromiumSandbox:v=!1,format:y=`png`,quality:b,notation:x=!1,description:S=!1}=e,w=n.a(await c(r,{graphviz:i?`binary`:`wasm`,watch:!1})),te=l??w.workspace,ne,E=f,D=[...w.languageServices.projects()];if(a&&!D.some(e=>e.id===a))throw t.error(`project not found: ${a}`),Error(`project not found: ${a}`);try{if(!E&&(t.info(C.cyan(`start preview server`)),ne=await viteDev({languageServices:w,buildWebcomponent:!1,openBrowser:!1,hmr:!1}),E=resolveServerUrl(ne),!E))throw t.error(`Vite server is not ready, no resolvedUrls`),Error(`Vite server is not ready, no resolvedUrls`);for(let e of D){if(a&&e.id!==a)continue;D.length>1&&(t.info(C.dim(`---------`)),t.info(`${C.dim(`project:`)} ${e.id}`),t.info(`${C.dim(`folder:`)} ${e.folder.fsPath}`));let n=await w.diagrams(e.id);if(g&&se(g,1)&&se(n,1)){let e=(0,Un.default)(g);t.info(`${C.cyan(`filter`)} ${C.dim(JSON.stringify(g))}`),n=n.filter(n=>e(n.id)?(t.info(`${C.green(`include`)} ${n.id} ✅`),!0):(t.info(`${C.gray(`skip`)} ${C.dim(n.id)}`),!1))}if(!se(n,1)){t.warn(`no views found`);continue}let r=D.length>1?T(ee(E,`project`,e.id)):E,i=D.length>1?ee(te,e.id):te,c=Bt(),l=await exportViewsToPNG({logger:t,serverUrl:r,theme:s,timeoutMs:m,views:n,output:i,outputType:u,maxAttempts:h,sequence:_,chromiumSandbox:v,format:y,quality:b,notation:x,description:S}),{pretty:f}=inMillis(c);if(l.length>0&&t.info(C.green(`exported ${l.length} views in ${f}`)+`
259
+ `),l.length!==n.length&&(p&&l.length>0?t.info(C.dim(`ignore`)+` `+C.red(`failed ${n.length-l.length} out of ${n.length} views`)):t.error(C.red(`failed ${n.length-l.length} out of ${n.length} views`))),l.length!==n.length&&(l.length===0||!p))throw Error(`Failed ${n.length-l.length} out of ${n.length} views`)}}finally{ne&&(t.info(C.cyan(`stop server`)),await ne.close().catch(e=>{t.error(e)}))}}catch(e){n.e=e}finally{await n.d()}}async function pngHandler(e){await runExportPng(e,createLikeC4Logger(`c4:export`))}function pngCmd(e){return e.command({command:`png [path]`,describe:`export views to PNG`,builder:e=>e.positional(`path`,J).options({outdir:{alias:[`o`,`output`],type:`string`,desc:`output directory for PNG files; if not specified, images are saved next to sources`,normalize:!0,nargs:1,coerce:H},project:Z,theme:{choices:[`light`,`dark`],desc:`color-scheme to use, defaults to light`,conflicts:[`dark`,`light`],nargs:1},dark:{type:`boolean`,desc:`use dark theme, shortcut for --theme=dark`,conflicts:[`theme`,`light`]},light:{type:`boolean`,desc:`use light theme, shortcut for --theme=light`,conflicts:[`theme`,`dark`]},"use-dot":Y,seq:{alias:[`sequence`],type:`boolean`,desc:`use sequence layout for dynamic views`},flat:{alias:[`flatten`],type:`boolean`,desc:`flatten all images in outdir ignoring sources structure`},filter:{alias:`f`,array:!0,string:!0,desc:`include views with ids matching given patterns
260
+ multiple patterns are combined with OR`},ignore:{boolean:!0,alias:`i`,desc:`continue if export fails for some views`},timeout:{type:`number`,alias:`t`,desc:`timeout for playwright (in seconds)`,default:15,nargs:1},"max-attempts":{type:`number`,desc:`max attempts to export failing view, 1 means no retry`,default:3,nargs:1},"server-url":{type:`string`,desc:`use this url instead of starting new likec4 server`,nargs:1},"chromium-sandbox":{boolean:!0,desc:`enable chromium sandbox (see Playwright docs)`,default:!1},notation:{boolean:!0,desc:`include view notation in exported PNG files`,default:!1},description:{boolean:!0,desc:`include view description in exported PNG files`,default:!1}}).epilog(`${C.bold(`Examples:`)}
261
+ ${C.green(`$0 export png`)}
262
+ ${C.gray(`Search for likec4 files in current directory and output PNG next to sources`)}
263
+
264
+ ${C.green(`$0 export png --theme dark -o ./png src/likec4`)}
265
+ ${C.gray(`Search for likec4 files in src/likec4 and output PNG with dark theme to png folder`)}
266
+
267
+ ${C.green(`$0 export png -f "team1*" -f "team2*" --flat -o ./png src/likec4`)}
268
+ ${C.gray(`Export views matching team1* or team2* only`)}
269
+
270
+ ${C.green(`$0 export png -f "use-case*" --sequence src/likec4`)}
271
+ ${C.gray(`Export views matching use-case* using sequence layout`)}
272
+ `),handler:async e=>{U(e.timeout>=1,`timeout must be >= 1`),U(e[`max-attempts`]>=1,`max-attempts must be >= 1`),await ensureReact(),await ensurePlaywright();let t=e.theme??(e.dark?`dark`:`light`);await pngHandler({path:e.path,useDotBin:e[`use-dot`],output:e.outdir,project:e.project,timeoutMs:e.timeout*1e3,maxAttempts:e[`max-attempts`],ignore:e.ignore===!0,outputType:e.flat?`flat`:`relative`,serverUrl:e[`server-url`],theme:t,filter:e.filter,sequence:e.seq,chromiumSandbox:e[`chromium-sandbox`],notation:e.notation,description:e.description}),showSupportUsMessage()}})}async function jpgHandler(e){let t=createLikeC4Logger(`c4:export`);await runExportPng({...e,format:`jpeg`},t)}function jpgCmd(e){return e.command({command:`jpg [path]`,describe:`export views to JPEG`,builder:e=>e.positional(`path`,J).options({outdir:{alias:[`o`,`output`],type:`string`,desc:`output directory for JPEG files; if not specified, images are saved next to sources`,normalize:!0,nargs:1,coerce:H},project:Z,quality:{alias:`q`,type:`number`,desc:`JPEG quality (1-100)`,default:80,nargs:1},theme:{choices:[`light`,`dark`],desc:`color-scheme to use, defaults to light`,conflicts:[`dark`,`light`],nargs:1},dark:{type:`boolean`,desc:`use dark theme, shortcut for --theme=dark`,conflicts:[`theme`,`light`]},light:{type:`boolean`,desc:`use light theme, shortcut for --theme=light`,conflicts:[`theme`,`dark`]},"use-dot":Y,seq:{alias:[`sequence`],type:`boolean`,desc:`use sequence layout for dynamic views`},flat:{alias:[`flatten`],type:`boolean`,desc:`flatten all images in outdir ignoring sources structure`},filter:{alias:`f`,array:!0,string:!0,desc:`include views with ids matching given patterns
273
+ multiple patterns are combined with OR`},ignore:{boolean:!0,alias:`i`,desc:`continue if export fails for some views`},timeout:{type:`number`,alias:`t`,desc:`timeout for playwright (in seconds)`,default:15,nargs:1},"max-attempts":{type:`number`,desc:`max attempts to export failing view, 1 means no retry`,default:3,nargs:1},"server-url":{type:`string`,desc:`use this url instead of starting new likec4 server`,nargs:1},"chromium-sandbox":{boolean:!0,desc:`enable chromium sandbox (see Playwright docs)`,default:!1},notation:{boolean:!0,desc:`include view notation in exported JPEG files`,default:!1},description:{boolean:!0,desc:`include view description in exported JPEG files`,default:!1}}).epilog(`${C.bold(`Examples:`)}
274
+ ${C.green(`$0 export jpg`)}
275
+ ${C.gray(`Search for likec4 files in current directory and output JPEG next to sources`)}
276
+
277
+ ${C.green(`$0 export jpg --theme dark -o ./jpg src/likec4`)}
278
+ ${C.gray(`Search for likec4 files in src/likec4 and output JPEG with dark theme to jpg folder`)}
279
+
280
+ ${C.green(`$0 export jpg --quality 90 -o ./jpg src/likec4`)}
281
+ ${C.gray(`Export JPEG with 90% quality`)}
282
+
283
+ ${C.green(`$0 export jpg -f "team1*" -f "team2*" --flat -o ./jpg src/likec4`)}
284
+ ${C.gray(`Export views matching team1* or team2* only`)}
285
+ `),handler:async e=>{U(e.quality>=1&&e.quality<=100,`quality must be between 1 and 100`),U(e.timeout>=1,`timeout must be >= 1`),U(e[`max-attempts`]>=1,`max-attempts must be >= 1`),await ensureReact(),await ensurePlaywright();let t=e.theme??(e.dark?`dark`:`light`);await jpgHandler({path:e.path,useDotBin:e[`use-dot`],output:e.outdir,project:e.project,timeoutMs:e.timeout*1e3,maxAttempts:e[`max-attempts`],ignore:e.ignore===!0,outputType:e.flat?`flat`:`relative`,serverUrl:e[`server-url`],theme:t,filter:e.filter,sequence:e.seq,chromiumSandbox:e[`chromium-sandbox`],format:`jpeg`,quality:e.quality,notation:e.notation,description:e.description}),showSupportUsMessage()}})}const Wn=`project not found`,Gn=`No projects found`;async function runExportJson(e,t){try{var n=_usingCtx();let r=startTimer(t),i=n.a(await c(e.path,{graphviz:e.useDot?`binary`:`wasm`,watch:!1})),a=[...i.projectsManager.all];if(e.project){if(a=a.filter(t=>t===e.project),!se(a,1))throw t.error(`${Wn}: ${e.project}`),Error(`${Wn}: ${e.project}`)}else{if(!se(a,1))throw t.error(Gn),Error(Gn);t.info(`${C.dim(`workspace:`)} Found ${a.length} projects`)}let s=[];for(let n of a){let r;if(e.skipLayout?(t.info(`Generate model for project ${C.green(n)} ${C.dim(`(skip layout)`)}`),r=await i.computedModel(n)):(t.info(`Generating layouted model for project ${C.green(n)}`),r=await i.layoutedModel(n)),r===Me.EMPTY){t.warn(C.yellow(`Project ${n} is empty, skipping`));continue}s.push(r.$data)}if(s.length===0)throw t.warn(`No models generated, aborting export`),Error(`No models generated; all projects are empty or were skipped`);let l=e.outfile;Qe(l).toLowerCase()!==`.json`&&(l+=`.json`),await G(z(l),{recursive:!0});let u=s.length===1?s[0]:s,f=e.pretty?JSON.stringify(u,void 0,2):JSON.stringify(u);await K(l,f);let p=l.startsWith(e.path)?V(e.path,l):l;t.info(`${C.dim(`generated`)} ${p}`),r.stopAndLog(`✓ export in `)}catch(e){n.e=e}finally{await n.d()}}function jsonCmd(e){return e.command({command:`json [path]`,describe:`export model(s) to JSON`,builder:e=>e.positional(`path`,J).option(`outfile`,{alias:`o`,type:`string`,desc:`<file> output .json file`,default:`likec4.json`,normalize:!0,coerce:H}).options({project:Z,"use-dot":Y,"skip-layout":{type:`boolean`,desc:`skip layouting (only compute model)`},pretty:{type:`boolean`,desc:`indented JSON output`}}).epilog(`${C.bold(`Examples:`)}
286
+ ${C.green(`$0 export json --skip-layout`)}
287
+ ${C.gray(`Search for likec4 files in current directory and output JSON to likec4.json (no layout)`)}
288
+
289
+ ${C.green(`$0 export json --pretty -o ./generated/likec4.json src/likec4 `)}
290
+ ${C.gray(`Search for likec4 files in src/likec4 and output JSON to generated/likec4.json`)}
291
+ `),handler:async e=>{let t=createLikeC4Logger(`c4:export`);await runExportJson({path:e.path,outfile:e.outfile,project:e.project,skipLayout:!!e.skipLayout,pretty:!!e.pretty,useDot:!!e[`use-dot`]},t),showSupportUsMessage()}})}const exportCmd=e=>e.command({command:`export <format> [path]`,describe:`Export to images, JSON, or DrawIO`,builder:e=>ue(e.usage(`${C.bold(`Usage:`)} $0 export <format> [path]`),pngCmd,jpgCmd,jsonCmd,drawioCmd).updateStrings({"Commands:":C.bold(`Formats:`)}),handler:()=>void 0}),formatCmd=e=>e.command({command:`format [path]`,aliases:[`fmt`],describe:`Format LikeC4 source files`,builder:e=>e.positional(`path`,J).options({project:{alias:`p`,type:`string`,array:!0,desc:`select project(s) to format (repeatable)`},files:{type:`string`,array:!0,normalize:!0,coerce:e=>e.map(e=>H(e)),desc:`specific file(s) to format (repeatable)`},check:{type:`boolean`,desc:`Check if files are formatted (exit with 1 if not)`,default:!1}}),handler:async e=>{try{var t=_usingCtx();let n=createLikeC4Logger(`c4:format`),r=startTimer(n),i=e.check,a;try{a=await c(e.path,{watch:!1})}catch(e){n.error(e instanceof Error?e.message:String(e)),process.exitCode=1;return}t.a(a);let s=e.project?.filter(Boolean),l=e.files?.filter(Boolean).map(e=>jt(e).toString());if(n.debug(`workspace: ${e.path}`),s?.length){n.debug(`projects:`);for(let e of s)n.debug(` ${e}`)}if(l?.length){n.debug(`files:`);for(let e of l)n.debug(` ${At(e)}`)}let u;try{u=await a.format({...s?.length&&{projects:s},...l?.length&&{documentUris:l}})}catch(e){n.error(e instanceof Error?e.message:String(e)),process.exitCode=1;return}n.debug(`${u.size} document(s) to process`);let f=process.cwd(),displayPath=e=>{let t=V(f,e);return t.startsWith(`..`)?e:t};if(l){let e=l.filter(e=>!u.has(e));for(let t of e)n.warn(`${C.yellow(`skipped`)} ${displayPath(At(t))} (not found in workspace)`)}let p=0,m=0,h=[];for(let[e,t]of u){let r=At(e),a=displayPath(r),s;try{s=await Tt(r,`utf-8`)}catch(e){n.error(`Failed to read ${a}: ${e}`),m++;continue}if(s===t){n.debug(`${C.dim(`unchanged`)} ${a}`);continue}if(p++,h.push(a),i)n.info(`${C.yellow(`needs formatting`)} ${a}`);else try{await K(r,t,`utf-8`),n.info(`${C.green(`formatted`)} ${a}`)}catch(e){n.error(`Failed to write ${a}: ${e}`),m++}}if(m>0){n.error(`${m} file(s) failed to process`),process.exitCode=1;return}if(i){if(p>0){n.error(`${p} of ${u.size} file(s) need formatting:\n${h.map(e=>` ${e}`).join(`
292
+ `)}`),process.exitCode=1;return}n.info(C.green(`All ${u.size} file(s) are formatted`))}else p>0?n.info(`${C.green(String(p))} of ${u.size} file(s) formatted`):n.info(C.green(`All ${u.size} file(s) already formatted`));r.stopAndLog(`✓ format in `)}catch(e){t.e=e}finally{await t.d()}}}),listIconsCmd=e=>e.command({command:`list-icons`,describe:`List available built-in icons`,builder:e=>e.option(`format`,{alias:`f`,choices:[`text`,`json`],default:`text`,description:`Output format`}).option(`group`,{alias:`g`,choices:a,description:`Filter icons by group`}),handler:e=>{let t=e.group?[e.group]:a;switch(!0){case e.format===`json`:{let e=Object.fromEntries(t.map(e=>[e,n[e]]));console.log(JSON.stringify(e,null,2));break}default:for(let e of t)for(let t of n[e])console.log(`${e}:${t}`)}}});var Kn=Ke();function lsp_default(e){return e.command({command:`lsp`,aliases:[],describe:`Start LSP server`,builder:e=>e.usage(`${C.bold(`Usage:`)} $0 lsp`).option(`log-level`,hn).option(`verbose`,gn).options({"node-ipc":{boolean:!0,description:`use node-ipc transport`,conflicts:[`stdio`,`socket`,`pipe`]},stdio:{boolean:!0,description:`use stdio transport`,conflicts:[`node-ipc`,`socket`,`pipe`]},socket:{number:!0,description:`use socket transport on specified port`,conflicts:[`node-ipc`,`stdio`,`pipe`],nargs:1},pipe:{string:!0,description:`use pipe transport with specified pipe name`,conflicts:[`node-ipc`,`stdio`,`socket`],nargs:1},"manual-layouts":{boolean:!0,description:`enable/disable manual layouts`,default:!0,defaultDescription:`enabled`},watch:{alias:`w`,boolean:!0,description:`enable built-in watcher`,default:!1,defaultDescription:`disabled`},telemetry:{boolean:!0,default:!0,defaultDescription:`IDE setting`,description:`enable/disable telemetry`,hidden:!0}}).option(`use-dot`,Y).showHidden().epilog(`${C.bold(`Examples:`)}
293
+
294
+ ${C.green(`$0 lsp --stdio `)}
295
+ ${C.gray(`Start LSP with stdio transport`)}
296
+
297
+ ${C.green(`$0 lsp --node-ipc --watch --no-manual-layouts --no-color `)}
298
+ ${C.gray(`Start LSP with node-ipc transport and watcher, disabled manual layouts and disabled color`)}
299
+
300
+ `),handler:e=>{let t;if(e.nodeIpc||e.stdio||e.socket||e.pipe)t=(0,Kn.createConnection)(Kn.ProposedFeatures.all);else throw Error(`No transport specified`);l({lspConnection:t,useStdErr:e.stdio===!0,colors:C.isColorSupported,enableTelemetry:e.telemetry,logLevel:e.verbose?_n:e.logLevel}),f({connection:t,enableManualLayouts:e.manualLayouts,enableWatcher:e.watch,graphviz:e.useDot?`binary`:`wasm`,configureLogger:!1})}})}t(lsp_default,`default`);const qn=qe(),Jn=qe();function useLanguageServices(){return Jn.use()}function setMcpServerCtx(e){return e?qn.set(e,!0):qn.unset(),e}function setLanguageServicesCtx(e){return e?Jn.set(e,!0):Jn.unset(),e}const Q=s.getChild(`mcp`);function likec4Tool(e){return t=>n=>{let{name:r,description:i,...a}=e,s={description:i?.trim()??``,...a};return n.registerTool(r,s,async(...e)=>{let n=useLanguageServices();Q.debug(`Calling tool {name}, args: {args}`,{name:r,args:e});try{let r=await t.apply(null,[n,...e]);return typeof r==`string`?{content:[{type:`text`,text:r}]}:oe(s.outputSchema)?tt(r,`content`)?r:{content:[{type:`text`,text:JSON.stringify(r)}]}:{content:[],structuredContent:r}}catch(e){return Q.error(`Tool ${r} failed`,{err:e}),{content:[{type:`text`,text:u(e)}],isError:!0}}}),n}}var Yn=`1.57.0`;function applySemanticLayoutPrompt(e){let t=useLanguageServices();return e.registerPrompt(`apply_semantic_layout`,{title:`Prepare prompt for applying semantic layout to a likec4 view`,argsSchema:{projectId:Ve(N().describe(`Project id (optional, will use "default" if not specified)`),(e=``)=>t.projects().filter(t=>t.id.startsWith(e)).map(he(`id`))),viewId:Ve(N().describe(`View ID`),async(n=``,r)=>{let i=r?.arguments?.projectId??t.projectsManager.default.id,a=await t.computedModel(i);return a?Array.from(a.views()).filter(e=>e.id.startsWith(n)).map(he(`id`)):(await e.sendLoggingMessage({level:`warning`,data:`Completing viewId for project ${i} with input value "${n}", model not found`}),[])})}},async({viewId:e,projectId:t},n)=>({messages:[{role:`user`,content:{type:`text`,text:["Call `apply-semantic-layout` tool from `likec4` MCP with these arguments:","projectId: `"+t+"`","viewId: `"+e+"`"].join(`
301
+ `)}}]})),e}function projectResource(e){let t=useLanguageServices();return e.registerResource(`likec4-project`,new ze(`likec4://project/{projectId}`,{list:async()=>({resources:t.projects().map(e=>({uri:`likec4://project/${encodeURIComponent(e.id)}`,name:e.title}))}),complete:{projectId:e=>{if(!e)return t.projects().map(he(`id`));let n=e.toLowerCase();return t.projects().filter(e=>e.id.toLowerCase().includes(n)).map(he(`id`))}}}),{description:`LikeC4 project resource`,mimeType:`application/json`},async(e,{projectId:n})=>{if(!n)return{contents:[]};let r=typeof n==`string`?[n]:n;return{contents:t.projects().filter(e=>r.includes(e.id)).map(e=>({uri:`likec4://project/${encodeURIComponent(e.id)}`,text:JSON.stringify({id:e.id,title:e.title,folder:e.folder.fsPath})}))}}),e}const Xn=R({name:N().describe(`Project identifier`),title:N().optional().describe(`Human-readable project title`),contactPerson:N().optional().describe(`Maintainer contact information`),metadata:M(N(),Re()).optional().describe(`Custom project metadata as key-value pairs`),extends:I([N(),P(N())]).optional().describe(`Style inheritance paths`),exclude:P(N()).optional().describe(`File exclusion patterns`),include:R({paths:P(N()).describe(`Include paths`),maxDepth:F().describe(`Maximum directory depth`),fileThreshold:F().describe(`File threshold`)}).optional().describe(`Include configuration`),manualLayouts:R({outDir:N().describe(`Output directory for manual layouts`)}).optional().describe(`Manual layouts configuration`),styles:R({hasTheme:A().describe(`Whether theme customization is defined`),hasDefaults:A().describe(`Whether default style values are defined`),hasCustomCss:A().describe(`Whether custom CSS is defined`)}).optional().describe(`Simplified styles configuration (boolean flags)`)});function serializeConfig(e){let t={name:e.name};return e.title!=null&&(t.title=e.title),e.contactPerson!=null&&(t.contactPerson=e.contactPerson),e.metadata&&(t.metadata=e.metadata),e.extends&&(t.extends=e.extends),e.exclude&&(t.exclude=e.exclude),e.include&&(t.include={paths:e.include.paths||[],maxDepth:e.include.maxDepth??3,fileThreshold:e.include.fileThreshold??30}),e.manualLayouts&&(t.manualLayouts={outDir:e.manualLayouts.outDir??`.likec4`}),e.styles&&(t.styles={hasTheme:!!e.styles.theme,hasDefaults:!!e.styles.defaults,hasCustomCss:!!e.styles.customCss}),t}const Zn=R({id:N().describe(`Element id (FQN)`),name:N().describe(`Element name`),kind:N().describe(`Element kind`),title:N(),tags:P(N()),metadata:M(I([N(),P(N())])),includedInViews:P(R({id:N().describe(`View id`),title:N().describe(`View title`),type:L([`element`,`deployment`,`dynamic`]).describe(`View type`)})).describe(`Views that include this element`)});function serializeElement(e){return{id:e.id,name:e.name,kind:e.kind,title:e.title,tags:[...e.tags],metadata:e.getMetadata(),includedInViews:includedInViews(e.views())}}function traverseGraph(e,t,n,r,i,a){U(e.findElement(t),`Element "${t}" not found`);let s=new Set,c={},l=0,u=!1,f=[{elementId:t,depth:0}];for(;f.length>0;){let{elementId:t,depth:p}=f.shift();if(p>i||s.has(t))continue;if(s.size>=a){u=!0;break}let m=e.findElement(t);if(!m)continue;s.add(t),l=Math.max(l,p);let h=(n===`incoming`?[...m.incoming(r)]:[...m.outgoing(r)]).map(e=>{let t={elementId:n===`incoming`?e.source.id:e.target.id};return e.title&&(t.relationshipLabel=e.title),e.technology&&(t.technology=e.technology),t});c[t]={...serializeElement(m),neighbors:h,depth:p};for(let e of h)s.has(e.elementId)||f.push({elementId:e.elementId,depth:p+1})}for(let e of Object.values(c))e.neighbors=e.neighbors.filter(e=>e.elementId in c);return{target:t,totalNodes:s.size,maxDepth:l,truncated:u,nodes:c}}const Qn=R({path:N().describe(`Path to the file`),range:R({start:R({line:F(),character:F()}),end:R({line:F(),character:F()})}).describe(`Range in the file`)}).nullable(),$=N().refine(e=>!0).default(`default`).describe(`Project id (optional, will use "default" if not specified)`),$n=P(R({id:N().describe(`View id`),title:N().describe(`View title`),type:L([`element`,`deployment`,`dynamic`]).describe(`View type`)})),includedInViews=e=>[...e].map(e=>({id:e.id,title:e.titleOrId,type:e.$view._type})),mkLocate=(e,t)=>n=>{try{let r=e.locate({projectId:t,...n});return r?{path:_.parse(r.uri).fsPath,range:r.range}:null}catch(e){return Q.debug(`Failed to locate {params}`,{error:e,params:n}),null}};function toolError(e){return{isError:!0,content:[{type:`text`,text:e}]}}function applySemanticLayoutTool(e){let t=useLanguageServices();return e.registerTool(`apply-semantic-layout`,{description:`Apply semantic layout to the likec4 view`,inputSchema:{projectId:Ve(N().default(`default`).describe(`Project id (optional, will use "default" if not specified)`),(e=``)=>t.projects().filter(t=>t.id.startsWith(e)).map(he(`id`))),viewId:Ve(N().describe(`View ID to apply semantic layout to`),async(e,n)=>{let r=n?.arguments?.projectId??t.projectsManager.default.id,i=await t.computedModel(r);if(!i)return[];let a=e??``;return Array.from(i.views()).filter(e=>e.id.startsWith(a)).map(he(`id`))})},outputSchema:{reasoning:N().describe(`Reasoning behind the layout changes`),snapshotUri:N().nullish().describe(`Where snapshot was saved (after applying layout)`)}},async(n,r)=>{let i=t.projectsManager.ensureProjectId(n.projectId);i!==n.projectId&&await e.sendLoggingMessage({level:`notice`,data:`Using project "${i}" instead of "${n.projectId}"`},r.sessionId);let a=await t.computedModel(i),s=a.findView(n.viewId);if(!s)return toolError(`View "${n.viewId}" not found in project "${i}"`);let c=await Ee(s.$view,{name:`MCP`,async sendRequest({systemPrompt:e,userPrompt:t,diagram:n}){let i=await r.sendRequest({method:`sampling/createMessage`,params:{maxTokens:2e4,includeContext:`none`,systemPrompt:e,messages:[{role:`user`,content:{type:`text`,text:t+`
302
+
303
+ `+n}}]}},R({content:R({type:j(`text`),text:N()})}));return i.content.type===`text`?i.content.text:JSON.stringify(i.content)}},r.signal);if(!c)return await e.sendLoggingMessage({level:`error`,data:`Failed to generate layout hints`},r.sessionId),toolError(`Failed to generate layout hints`);await e.sendLoggingMessage({level:`info`,data:`Applying semantic layout...`},r.sessionId);let l=await t.views.layouter.aiLayout({view:s.$view,styles:a.$styles},c),u=await t.editor.applyChange({change:{op:`save-view-snapshot`,layout:l.diagram},viewId:s.id,projectId:i});return await e.sendLoggingMessage({level:`info`,data:`Layout applied successfully`},r.sessionId),{content:[],structuredContent:{reasoning:c.reasoning,...!!u.location&&{snapshotUri:u.location.uri.toString()}}}}),e}const er=Zn.extend({description:N().nullable().describe(`Element description`),technology:N().nullable().describe(`Element technology`),shape:N().describe(`Rendered shape`),color:N().describe(`Rendered color`),children:P(N()).describe(`Direct child element ids`),incomingCount:F().describe(`Number of incoming relationships`),outgoingCount:F().describe(`Number of outgoing relationships`)}),tr=likec4Tool({name:`batch-read-elements`,description:`
301
304
  Read details of multiple elements in a single call, reducing round-trips.
302
305
  Returns a compact summary for each element including metadata, description, technology, shape, children, and relationship counts.
303
306
 
@@ -359,7 +362,7 @@ Example response:
359
362
  ],
360
363
  "notFound": []
361
364
  }
362
- `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Batch read elements`},inputSchema:{ids:N(L()).min(1).max(50).describe(`Array of element ids (FQNs) to read (max 50)`),project:$},outputSchema:{elements:N(Vn),notFound:N(L()).describe(`Element ids that were not found`)}},async(e,t)=>{R(t.ids.length<=50,`Maximum 50 element ids per call`);let n=e.projectsManager.ensureProjectId(t.project),r=await e.computedModel(n),i=[],a=[];for(let e of t.ids){let t=r.findElement(e);if(!t){a.push(e);continue}i.push({...serializeElement(t),description:t.description.text,technology:t.technology,shape:t.shape,color:t.color,children:[...t.children()].map(e=>e.id),incomingCount:t.allIncoming.size,outgoingCount:t.allOutgoing.size})}return{elements:i,notFound:a}}),Un=A({id:L(),kind:L(),title:L(),description:L().nullable(),technology:L().nullable(),shape:L(),color:L()}),Wn=A({element1:Un,element2:Un,propertyDiffs:N(A({property:L().describe(`Property name`),element1Value:L().nullable().describe(`Value in element1`),element2Value:L().nullable().describe(`Value in element2`)})).describe(`Properties that differ between the two elements`),tags:A({onlyInElement1:N(L()).describe(`Tags present only in element1`),onlyInElement2:N(L()).describe(`Tags present only in element2`),common:N(L()).describe(`Tags present in both elements`)}),metadata:A({onlyInElement1:M(j([L(),N(L())])).describe(`Metadata keys only in element1`),onlyInElement2:M(j([L(),N(L())])).describe(`Metadata keys only in element2`),different:N(A({key:L(),element1Value:j([L(),N(L())]),element2Value:j([L(),N(L())])})).describe(`Metadata keys present in both but with different values`),common:M(j([L(),N(L())])).describe(`Metadata keys with identical values in both`)}),relationships:A({incomingOnlyElement1:I().describe(`Count of unique source elements sending to element1 only`),incomingOnlyElement2:I().describe(`Count of unique source elements sending to element2 only`),incomingShared:I().describe(`Count of unique source elements sending to both`),outgoingOnlyElement1:I().describe(`Count of unique target elements receiving from element1 only`),outgoingOnlyElement2:I().describe(`Count of unique target elements receiving from element2 only`),outgoingShared:I().describe(`Count of unique target elements receiving from both`)})}),Gn=likec4Tool({name:`element-diff`,description:`
365
+ `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Batch read elements`},inputSchema:{ids:P(N()).min(1).max(50).describe(`Array of element ids (FQNs) to read (max 50)`),project:$},outputSchema:{elements:P(er),notFound:P(N()).describe(`Element ids that were not found`)}})(async(e,t)=>{U(t.ids.length<=50,`Maximum 50 element ids per call`);let n=e.projectsManager.ensureProjectId(t.project),r=await e.computedModel(n),i=[],a=[];for(let e of t.ids){let t=r.findElement(e);if(!t){a.push(e);continue}i.push({...serializeElement(t),description:t.description.text,technology:t.technology,shape:t.shape,color:t.color,children:[...t.children()].map(e=>e.id),incomingCount:t.allIncoming.size,outgoingCount:t.allOutgoing.size})}return{elements:i,notFound:a}}),nr=R({id:N(),kind:N(),title:N(),description:N().nullable(),technology:N().nullable(),shape:N(),color:N()}),rr=R({element1:nr,element2:nr,propertyDiffs:P(R({property:N().describe(`Property name`),element1Value:N().nullable().describe(`Value in element1`),element2Value:N().nullable().describe(`Value in element2`)})).describe(`Properties that differ between the two elements`),tags:R({onlyInElement1:P(N()).describe(`Tags present only in element1`),onlyInElement2:P(N()).describe(`Tags present only in element2`),common:P(N()).describe(`Tags present in both elements`)}),metadata:R({onlyInElement1:M(I([N(),P(N())])).describe(`Metadata keys only in element1`),onlyInElement2:M(I([N(),P(N())])).describe(`Metadata keys only in element2`),different:P(R({key:N(),element1Value:I([N(),P(N())]),element2Value:I([N(),P(N())])})).describe(`Metadata keys present in both but with different values`),common:M(I([N(),P(N())])).describe(`Metadata keys with identical values in both`)}),relationships:R({incomingOnlyElement1:F().describe(`Count of unique source elements sending to element1 only`),incomingOnlyElement2:F().describe(`Count of unique source elements sending to element2 only`),incomingShared:F().describe(`Count of unique source elements sending to both`),outgoingOnlyElement1:F().describe(`Count of unique target elements receiving from element1 only`),outgoingOnlyElement2:F().describe(`Count of unique target elements receiving from element2 only`),outgoingShared:F().describe(`Count of unique target elements receiving from both`)})}),ir=likec4Tool({name:`element-diff`,description:`
363
366
  Compare two elements side-by-side, showing differences in properties, tags, metadata, and relationships.
364
367
 
365
368
  Request:
@@ -419,7 +422,7 @@ Example response:
419
422
  "outgoingShared": 2
420
423
  }
421
424
  }
422
- `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Compare two elements`},inputSchema:{element1Id:L().describe(`First element id (FQN)`),element2Id:L().describe(`Second element id (FQN)`),project:$},outputSchema:Wn.shape},async(e,t)=>{let n=e.projectsManager.ensureProjectId(t.project),r=await e.computedModel(n),i=r.findElement(t.element1Id);R(i,`Element "${t.element1Id}" not found in project "${n}"`);let a=r.findElement(t.element2Id);R(a,`Element "${t.element2Id}" not found in project "${n}"`);let s=[],c=[{name:`kind`,get:e=>e.kind},{name:`title`,get:e=>e.title},{name:`description`,get:e=>e.description.text},{name:`technology`,get:e=>e.technology},{name:`shape`,get:e=>e.shape},{name:`color`,get:e=>e.color}];for(let e of c){let t=e.get(i),n=e.get(a);t!==n&&s.push({property:e.name,element1Value:t,element2Value:n})}let l=new Set(i.tags),u=new Set(a.tags),f=[],p=[],m=[];for(let e of l)u.has(e)?f.push(e):p.push(e);for(let e of u)l.has(e)||m.push(e);let h=i.getMetadata(),g=a.getMetadata(),_=new Set([...Object.keys(h),...Object.keys(g)]),v={},y={},b=[],x={};for(let e of _){let t=h[e],n=g[e];t!==void 0&&n===void 0?v[e]=t:t===void 0&&n!==void 0?y[e]=n:t!==void 0&&n!==void 0&&(JSON.stringify(t)===JSON.stringify(n)?x[e]=t:b.push({key:e,element1Value:t,element2Value:n}))}let ee=new Set([...i.incoming()].map(e=>e.source.id)),S=new Set([...a.incoming()].map(e=>e.source.id)),C=new Set([...i.outgoing()].map(e=>e.target.id)),te=new Set([...a.outgoing()].map(e=>e.target.id)),ne=0,w=0,T=0;for(let e of ee)S.has(e)?ne++:w++;for(let e of S)ee.has(e)||T++;let E=0,re=0,ie=0;for(let e of C)te.has(e)?E++:re++;for(let e of te)C.has(e)||ie++;return{element1:{id:i.id,kind:i.kind,title:i.title,description:i.description.text,technology:i.technology,shape:i.shape,color:i.color},element2:{id:a.id,kind:a.kind,title:a.title,description:a.description.text,technology:a.technology,shape:a.shape,color:a.color},propertyDiffs:s,tags:{onlyInElement1:p,onlyInElement2:m,common:f},metadata:{onlyInElement1:v,onlyInElement2:y,different:b,common:x},relationships:{incomingOnlyElement1:w,incomingOnlyElement2:T,incomingShared:ne,outgoingOnlyElement1:re,outgoingOnlyElement2:ie,outgoingShared:E}}}),Kn=likec4Tool({name:`find-relationship-paths`,description:`
425
+ `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Compare two elements`},inputSchema:{element1Id:N().describe(`First element id (FQN)`),element2Id:N().describe(`Second element id (FQN)`),project:$},outputSchema:rr.shape})(async(e,t)=>{let n=e.projectsManager.ensureProjectId(t.project),r=await e.computedModel(n),i=r.findElement(t.element1Id);U(i,`Element "${t.element1Id}" not found in project "${n}"`);let a=r.findElement(t.element2Id);U(a,`Element "${t.element2Id}" not found in project "${n}"`);let s=[],c=[{name:`kind`,get:e=>e.kind},{name:`title`,get:e=>e.title},{name:`description`,get:e=>e.description.text},{name:`technology`,get:e=>e.technology},{name:`shape`,get:e=>e.shape},{name:`color`,get:e=>e.color}];for(let e of c){let t=e.get(i),n=e.get(a);t!==n&&s.push({property:e.name,element1Value:t,element2Value:n})}let l=new Set(i.tags),u=new Set(a.tags),f=[],p=[],m=[];for(let e of l)u.has(e)?f.push(e):p.push(e);for(let e of u)l.has(e)||m.push(e);let h=i.getMetadata(),g=a.getMetadata(),_=new Set([...Object.keys(h),...Object.keys(g)]),v={},y={},b=[],x={};for(let e of _){let t=h[e],n=g[e];t!==void 0&&n===void 0?v[e]=t:t===void 0&&n!==void 0?y[e]=n:t!==void 0&&n!==void 0&&(JSON.stringify(t)===JSON.stringify(n)?x[e]=t:b.push({key:e,element1Value:t,element2Value:n}))}let S=new Set([...i.incoming()].map(e=>e.source.id)),C=new Set([...a.incoming()].map(e=>e.source.id)),w=new Set([...i.outgoing()].map(e=>e.target.id)),T=new Set([...a.outgoing()].map(e=>e.target.id)),ee=0,te=0,ne=0;for(let e of S)C.has(e)?ee++:te++;for(let e of C)S.has(e)||ne++;let E=0,D=0,re=0;for(let e of w)T.has(e)?E++:D++;for(let e of T)w.has(e)||re++;return{element1:{id:i.id,kind:i.kind,title:i.title,description:i.description.text,technology:i.technology,shape:i.shape,color:i.color},element2:{id:a.id,kind:a.kind,title:a.title,description:a.description.text,technology:a.technology,shape:a.shape,color:a.color},propertyDiffs:s,tags:{onlyInElement1:p,onlyInElement2:m,common:f},metadata:{onlyInElement1:v,onlyInElement2:y,different:b,common:x},relationships:{incomingOnlyElement1:te,incomingOnlyElement2:ne,incomingShared:ee,outgoingOnlyElement1:D,outgoingOnlyElement2:re,outgoingShared:E}}}),ar=likec4Tool({name:`find-relationship-paths`,description:`
423
426
  Discover all paths (chains of relationships) between two elements, supporting multi-hop traversal.
424
427
 
425
428
  Request:
@@ -508,7 +511,7 @@ Example response:
508
511
  }
509
512
  ]
510
513
  }
511
- `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Find relationship paths`},inputSchema:{sourceId:L().describe(`Source element FQN`),targetId:L().describe(`Target element FQN`),maxDepth:I().int().min(1).max(5).optional().default(3).describe(`Maximum path length (default: 3, max: 5)`),includeIndirect:F().optional().default(!1).describe(`Include indirect (implied) relationships through nested elements (default: false)`),project:$},outputSchema:{paths:N(A({length:I().describe(`Number of hops in the path`),steps:N(A({source:L().describe(`Source element FQN`),target:L().describe(`Target element FQN`),relationship:A({kind:L().nullable().describe(`Relationship kind`),title:L().nullable().describe(`Relationship title`),description:L().nullable().describe(`Relationship description`),technology:L().nullable().describe(`Relationship technology`),tags:N(L()).describe(`Relationship tags`)})})).describe(`Ordered sequence of relationships in the path`)}))}},async(e,t)=>{let n=e.projectsManager.ensureProjectId(t.project),r=await e.computedModel(n),i=r.findElement(t.sourceId);R(i,`Source element "${t.sourceId}" not found in project "${n}"`);let a=r.findElement(t.targetId);R(a,`Target element "${t.targetId}" not found in project "${n}"`),R(i.id!==a.id,`Source and target must be different elements`);let s=t.maxDepth,c=t.includeIndirect?`all`:`direct`,l=[{elementId:i.id,path:[],visited:new Set([i.id])}],u=[];for(;l.length>0&&u.length<100;){let e=l.shift();if(e.path.length>=s)continue;let t=r.findElement(e.elementId);if(t)for(let n of t.outgoing(c)){let t=n.target.id;if(t===a.id){let t={source:n.source.id,target:n.target.id,relationship:{kind:n.kind,title:n.title,description:n.description.text,technology:n.technology,tags:[...n.tags]}};if(u.push({length:e.path.length+1,steps:[...e.path,t]}),u.length>=100)break;continue}if(e.visited.has(t))continue;let r={source:n.source.id,target:n.target.id,relationship:{kind:n.kind,title:n.title,description:n.description.text,technology:n.technology,tags:[...n.tags]}};l.push({elementId:t,path:[...e.path,r],visited:new Set([...e.visited,t])})}}return u.sort((e,t)=>e.length-t.length),{paths:u}}),qn=A({id:L(),title:L(),kind:L()}),Jn=A({type:k([`direct`,`indirect`]).describe(`Type of relationship, "direct" for direct relationships, "indirect" for relationships through nested elements`),source:qn,target:qn,kind:L().nullable().describe(`Relationship kind`),title:L().nullable().describe(`Relationship title`),description:L().nullable().describe(`Relationship description`),technology:L().nullable().describe(`Relationship technology`),tags:N(L()).describe(`Relationship tags`),includedInViews:Bn.describe(`Views that include this relationship`),sourceLocation:zn}),Yn=likec4Tool({name:`find-relationships`,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Find relationships between two elements`},description:`
514
+ `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Find relationship paths`},inputSchema:{sourceId:N().describe(`Source element FQN`),targetId:N().describe(`Target element FQN`),maxDepth:F().int().min(1).max(5).optional().default(3).describe(`Maximum path length (default: 3, max: 5)`),includeIndirect:A().optional().default(!1).describe(`Include indirect (implied) relationships through nested elements (default: false)`),project:$},outputSchema:{paths:P(R({length:F().describe(`Number of hops in the path`),steps:P(R({source:N().describe(`Source element FQN`),target:N().describe(`Target element FQN`),relationship:R({kind:N().nullable().describe(`Relationship kind`),title:N().nullable().describe(`Relationship title`),description:N().nullable().describe(`Relationship description`),technology:N().nullable().describe(`Relationship technology`),tags:P(N()).describe(`Relationship tags`)})})).describe(`Ordered sequence of relationships in the path`)}))}})(async(e,t)=>{let n=e.projectsManager.ensureProjectId(t.project),r=await e.computedModel(n),i=r.findElement(t.sourceId);U(i,`Source element "${t.sourceId}" not found in project "${n}"`);let a=r.findElement(t.targetId);U(a,`Target element "${t.targetId}" not found in project "${n}"`),U(i.id!==a.id,`Source and target must be different elements`);let s=t.maxDepth,c=t.includeIndirect?`all`:`direct`,l=[{elementId:i.id,path:[],visited:new Set([i.id])}],u=[];for(;l.length>0&&u.length<100;){let e=l.shift();if(e.path.length>=s)continue;let t=r.findElement(e.elementId);if(t)for(let n of t.outgoing(c)){let t=n.target.id;if(t===a.id){let t={source:n.source.id,target:n.target.id,relationship:{kind:n.kind,title:n.title,description:n.description.text,technology:n.technology,tags:[...n.tags]}};if(u.push({length:e.path.length+1,steps:[...e.path,t]}),u.length>=100)break;continue}if(e.visited.has(t))continue;let r={source:n.source.id,target:n.target.id,relationship:{kind:n.kind,title:n.title,description:n.description.text,technology:n.technology,tags:[...n.tags]}};l.push({elementId:t,path:[...e.path,r],visited:new Set([...e.visited,t])})}}return u.sort((e,t)=>e.length-t.length),{paths:u}}),or=R({id:N(),title:N(),kind:N()}),sr=R({type:L([`direct`,`indirect`]).describe(`Type of relationship, "direct" for direct relationships, "indirect" for relationships through nested elements`),source:or,target:or,kind:N().nullable().describe(`Relationship kind`),title:N().nullable().describe(`Relationship title`),description:N().nullable().describe(`Relationship description`),technology:N().nullable().describe(`Relationship technology`),tags:P(N()).describe(`Relationship tags`),includedInViews:$n.describe(`Views that include this relationship`),sourceLocation:Qn}),cr=likec4Tool({name:`find-relationships`,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Find relationships between two elements`},description:`
512
515
  Find relationships between two LikeC4 elements within a project.
513
516
 
514
517
  What it does:
@@ -579,7 +582,7 @@ Response:
579
582
  }
580
583
  ]
581
584
  }
582
- `,inputSchema:{element1:L().describe(`Element ID (FQN)`),element2:L().describe(`Element ID (FQN)`),project:$},outputSchema:{found:N(Jn)}},async(e,t)=>{let n=e.projectsManager.ensureProjectId(t.project);if(et(t.element1,t.element2))throw Error(`No relationships possible between parent-child`);let r=[],i=await e.computedModel(n),a=i.findElement(t.element1);$e(a,`Element "${t.element1}" not found in project "${n}"`);let s=i.findElement(t.element2);$e(s,`Element "${t.element2}" not found in project "${n}"`);let c=mkLocate(e,n),l=ct.findConnection(a,s,`both`).flatMap(e=>[...e.relations]);for(let e of l){let t=e.source===a&&e.target===s||e.source===s&&e.target===a;r.push({type:t?`direct`:`indirect`,source:{id:e.source.id,title:e.source.title,kind:e.source.kind},target:{id:e.target.id,title:e.target.title,kind:e.target.kind},kind:e.kind,title:e.title,description:e.description.text,technology:e.technology,tags:[...e.tags],includedInViews:includedInViews(e.views()),sourceLocation:c({relation:e.id})})}return{found:r}}),Xn=likec4Tool({name:`list-projects`,description:`
585
+ `,inputSchema:{element1:N().describe(`Element ID (FQN)`),element2:N().describe(`Element ID (FQN)`),project:$},outputSchema:{found:P(sr)}})(async(e,t)=>{let n=e.projectsManager.ensureProjectId(t.project);if(ot(t.element1,t.element2))throw Error(`No relationships possible between parent-child`);let r=[],i=await e.computedModel(n),a=i.findElement(t.element1);at(a,`Element "${t.element1}" not found in project "${n}"`);let s=i.findElement(t.element2);at(s,`Element "${t.element2}" not found in project "${n}"`);let c=mkLocate(e,n),l=mt.findConnection(a,s,`both`).flatMap(e=>[...e.relations]);for(let e of l){let t=e.source===a&&e.target===s||e.source===s&&e.target===a;r.push({type:t?`direct`:`indirect`,source:{id:e.source.id,title:e.source.title,kind:e.source.kind},target:{id:e.target.id,title:e.target.title,kind:e.target.kind},kind:e.kind,title:e.title,description:e.description.text,technology:e.technology,tags:[...e.tags],includedInViews:includedInViews(e.views()),sourceLocation:c({relation:e.id})})}return{found:r}}),lr=likec4Tool({name:`list-projects`,description:`
583
586
  List LikeC4 projects discoverable in the current workspace.
584
587
 
585
588
  Request:
@@ -612,7 +615,7 @@ Example response:
612
615
  }
613
616
  ]
614
617
  }
615
- `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`List projects`},outputSchema:{projects:N(A({id:L(),title:L(),folder:L(),sources:N(L())}))}},async e=>({projects:e.projects().map(e=>({id:e.id,title:e.title,folder:e.folder.fsPath,sources:e.documents.map(e=>e.fsPath)}))})),Zn=k([`exact`,`contains`,`exists`]),Qn=likec4Tool({name:`query-by-metadata`,description:`
618
+ `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`List projects`},inputSchema:{},outputSchema:{projects:P(R({id:N(),title:N(),folder:N(),sources:P(N())}))}})(async e=>({projects:e.projects().map(e=>({id:e.id,title:e.title,folder:e.folder.fsPath,sources:e.documents.map(e=>e.fsPath)}))})),ur=L([`exact`,`contains`,`exists`]),dr=likec4Tool({name:`query-by-metadata`,description:`
616
619
  Search elements and deployment nodes by metadata key-value pairs with flexible matching modes.
617
620
 
618
621
  Request:
@@ -678,7 +681,7 @@ Example response:
678
681
  }
679
682
  ]
680
683
  }
681
- `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Query by metadata`},inputSchema:{key:L().describe(`Metadata key to filter by`),value:L().optional().describe(`Metadata value to match (ignored for exists mode)`),matchMode:Zn.optional().default(`exact`).describe(`Matching mode`),project:$},outputSchema:{results:N(Q.extend({matchedValue:L().describe(`The metadata value that matched`)}))}},async(e,t)=>{let n=e.projectsManager.ensureProjectId(t.project),r=await e.computedModel(n),i=t.matchMode,a=[],matches=(e,t,n)=>{let r=Array.isArray(e)?e:[e];switch(n){case`exists`:return!0;case`exact`:return t===void 0?!1:r.some(e=>e===t);case`contains`:{if(t===void 0)return!1;let e=t.toLowerCase();return r.some(t=>t.toLowerCase().includes(e))}default:return!1}},getMatchedValue=(e,t,n)=>{let r=Array.isArray(e)?e:[e];if(n===`exists`||t===void 0)return r[0]||``;if(n===`exact`)return r.find(e=>e===t)||r[0]||``;if(n===`contains`){let e=t.toLowerCase();return r.find(t=>t.toLowerCase().includes(e))||r[0]||``}return r[0]||``};for(let e of r.elements()){if(a.length>=50)break;let n=e.getMetadata();if(t.key in n){let r=n[t.key];r!==void 0&&matches(r,t.value,i)&&a.push({...serializeElement(e),matchedValue:getMatchedValue(r,t.value,i)})}}if(a.length<50)for(let e of r.deployment.elements()){if(a.length>=50)break;let n=e.getMetadata();if(t.key in n){let r=n[t.key];r!==void 0&&matches(r,t.value,i)&&a.push({...serializeElement(e),matchedValue:getMatchedValue(r,t.value,i)})}}return{results:a}}),$n=likec4Tool({name:`query-by-tag-pattern`,description:`
684
+ `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Query by metadata`},inputSchema:{key:N().describe(`Metadata key to filter by`),value:N().optional().describe(`Metadata value to match (ignored for exists mode)`),matchMode:ur.optional().default(`exact`).describe(`Matching mode`),project:$},outputSchema:{results:P(Zn.extend({matchedValue:N().describe(`The metadata value that matched`)}))}})(async(e,t)=>{let n=e.projectsManager.ensureProjectId(t.project),r=await e.computedModel(n),i=t.matchMode,a=[],matches=(e,t,n)=>{let r=Array.isArray(e)?e:[e];switch(n){case`exists`:return!0;case`exact`:return t===void 0?!1:r.some(e=>e===t);case`contains`:{if(t===void 0)return!1;let e=t.toLowerCase();return r.some(t=>t.toLowerCase().includes(e))}default:return!1}},getMatchedValue=(e,t,n)=>{let r=Array.isArray(e)?e:[e];if(n===`exists`||t===void 0)return r[0]||``;if(n===`exact`)return r.find(e=>e===t)||r[0]||``;if(n===`contains`){let e=t.toLowerCase();return r.find(t=>t.toLowerCase().includes(e))||r[0]||``}return r[0]||``};for(let e of r.elements()){if(a.length>=50)break;let n=e.getMetadata();if(t.key in n){let r=n[t.key];r!==void 0&&matches(r,t.value,i)&&a.push({...serializeElement(e),matchedValue:getMatchedValue(r,t.value,i)})}}if(a.length<50)for(let e of r.deployment.elements()){if(a.length>=50)break;let n=e.getMetadata();if(t.key in n){let r=n[t.key];r!==void 0&&matches(r,t.value,i)&&a.push({...serializeElement(e),matchedValue:getMatchedValue(r,t.value,i)})}}return{results:a}}),fr=likec4Tool({name:`query-by-tag-pattern`,description:`
682
685
  Search elements by tag patterns using prefix or substring matching.
683
686
  Useful for tag taxonomies with structured naming conventions (e.g., "schedule_*", "*_asil_*").
684
687
 
@@ -733,7 +736,7 @@ Example response:
733
736
  "truncated": false,
734
737
  "matchedTagValues": ["target_asil_qm", "target_asil_asil_b", "target_asil_qm__tbc"]
735
738
  }
736
- `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Query by tag pattern`},inputSchema:{pattern:L().min(1).describe(`Tag pattern to match`),matchMode:k([`prefix`,`contains`,`suffix`]).optional().default(`prefix`).describe(`Pattern matching mode (default: prefix)`),project:$},outputSchema:{results:N(Q.extend({matchedTags:N(L()).describe(`Tags that matched the pattern`)})),truncated:F().describe(`True if results were truncated`),matchedTagValues:N(L()).describe(`All unique tag values matching the pattern across all elements`)}},async(e,t)=>{let n=e.projectsManager.ensureProjectId(t.project),r=await e.computedModel(n),i=t.pattern.toLowerCase(),matchesTag=e=>{let n=e.toLowerCase();switch(t.matchMode){case`prefix`:return n.startsWith(i);case`contains`:return n.includes(i);case`suffix`:return n.endsWith(i)}},a=[],s=!1,c=new Set;for(let e of r.elements()){let t=[...e.tags].filter(matchesTag);if(t.length>0){if(t.forEach(e=>c.add(e)),a.length>=50){s=!0;continue}a.push({...serializeElement(e),matchedTags:t})}}for(let e of r.deployment.elements()){if(!rt(e))continue;let t=[...e.tags].filter(matchesTag);if(t.length>0){if(t.forEach(e=>c.add(e)),a.length>=50){s=!0;continue}a.push({...serializeElement(e),matchedTags:t})}}return{results:a,truncated:s,matchedTagValues:[...c].sort((e,t)=>e.localeCompare(t))}}),er=likec4Tool({name:`query-by-tags`,description:`
739
+ `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Query by tag pattern`},inputSchema:{pattern:N().min(1).describe(`Tag pattern to match`),matchMode:L([`prefix`,`contains`,`suffix`]).optional().default(`prefix`).describe(`Pattern matching mode (default: prefix)`),project:$},outputSchema:{results:P(Zn.extend({matchedTags:P(N()).describe(`Tags that matched the pattern`)})),truncated:A().describe(`True if results were truncated`),matchedTagValues:P(N()).describe(`All unique tag values matching the pattern across all elements`)}})(async(e,t)=>{let n=e.projectsManager.ensureProjectId(t.project),r=await e.computedModel(n),i=t.pattern.toLowerCase(),matchesTag=e=>{let n=e.toLowerCase();switch(t.matchMode){case`prefix`:return n.startsWith(i);case`contains`:return n.includes(i);case`suffix`:return n.endsWith(i)}},a=[],s=!1,c=new Set;for(let e of r.elements()){let t=[...e.tags].filter(matchesTag);if(t.length>0){if(t.forEach(e=>c.add(e)),a.length>=50){s=!0;continue}a.push({...serializeElement(e),matchedTags:t})}}for(let e of r.deployment.elements()){if(!lt(e))continue;let t=[...e.tags].filter(matchesTag);if(t.length>0){if(t.forEach(e=>c.add(e)),a.length>=50){s=!0;continue}a.push({...serializeElement(e),matchedTags:t})}}return{results:a,truncated:s,matchedTagValues:[...c].sort((e,t)=>e.localeCompare(t))}}),pr=likec4Tool({name:`query-by-tags`,description:`
737
740
  Advanced tag filtering with boolean logic (AND, OR, NOT).
738
741
 
739
742
  Request:
@@ -797,7 +800,7 @@ Example response:
797
800
  }
798
801
  ]
799
802
  }
800
- `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Query by tags`},inputSchema:{allOf:N(L()).optional().describe(`Element must have ALL these tags (AND)`),anyOf:N(L()).optional().describe(`Element must have ANY of these tags (OR)`),noneOf:N(L()).optional().describe(`Element must have NONE of these tags (NOT)`),project:$},outputSchema:{results:N(Q),truncated:F().describe(`True if results were truncated due to exceeding the 50-result limit`)}},async(e,t)=>{R(t.allOf&&t.allOf.length>0||t.anyOf&&t.anyOf.length>0||t.noneOf&&t.noneOf.length>0,`At least one condition (allOf, anyOf, or noneOf) must be specified with at least one tag`);let n=e.projectsManager.ensureProjectId(t.project),r=await e.computedModel(n),i=[],a=!1,matchesTags=e=>{let n=e instanceof Set?e:new Set(e);return!(t.allOf&&t.allOf.length>0&&!t.allOf.every(e=>n.has(e))||t.anyOf&&t.anyOf.length>0&&!t.anyOf.some(e=>n.has(e))||t.noneOf&&t.noneOf.length>0&&t.noneOf.some(e=>n.has(e)))};for(let e of r.elements()){if(i.length>=50){a=!0;break}matchesTags(e.tags)&&i.push(serializeElement(e))}if(!a)for(let e of r.deployment.elements()){if(i.length>=50){a=!0;break}rt(e)&&matchesTags(e.tags)&&i.push(serializeElement(e))}return{results:i,truncated:a}}),tr=k([`ancestors`,`descendants`,`siblings`,`children`,`parent`,`incomers`,`outgoers`]),nr=likec4Tool({name:`query-graph`,description:`
803
+ `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Query by tags`},inputSchema:{allOf:P(N()).optional().describe(`Element must have ALL these tags (AND)`),anyOf:P(N()).optional().describe(`Element must have ANY of these tags (OR)`),noneOf:P(N()).optional().describe(`Element must have NONE of these tags (NOT)`),project:$},outputSchema:{results:P(Zn),truncated:A().describe(`True if results were truncated due to exceeding the 50-result limit`)}})(async(e,t)=>{U(t.allOf&&t.allOf.length>0||t.anyOf&&t.anyOf.length>0||t.noneOf&&t.noneOf.length>0,`At least one condition (allOf, anyOf, or noneOf) must be specified with at least one tag`);let n=e.projectsManager.ensureProjectId(t.project),r=await e.computedModel(n),i=[],a=!1,matchesTags=e=>{let n=e instanceof Set?e:new Set(e);return!(t.allOf&&t.allOf.length>0&&!t.allOf.every(e=>n.has(e))||t.anyOf&&t.anyOf.length>0&&!t.anyOf.some(e=>n.has(e))||t.noneOf&&t.noneOf.length>0&&t.noneOf.some(e=>n.has(e)))};for(let e of r.elements()){if(i.length>=50){a=!0;break}matchesTags(e.tags)&&i.push(serializeElement(e))}if(!a)for(let e of r.deployment.elements()){if(i.length>=50){a=!0;break}lt(e)&&matchesTags(e.tags)&&i.push(serializeElement(e))}return{results:i,truncated:a}}),mr=L([`ancestors`,`descendants`,`siblings`,`children`,`parent`,`incomers`,`outgoers`]),hr=likec4Tool({name:`query-graph`,description:`
801
804
  Query element hierarchy and relationships in the architecture graph.
802
805
 
803
806
  Request:
@@ -869,7 +872,7 @@ Example response:
869
872
  ],
870
873
  "truncated": false
871
874
  }
872
- `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Query element graph`},inputSchema:{elementId:L().describe(`Element id (FQN) to query`),queryType:tr.describe(`Type of graph query`),includeIndirect:F().optional().default(!0).describe(`For incomers/outgoers: include indirect relationships (default: true)`),project:$},outputSchema:{results:N(Q),truncated:F().describe(`True if results were truncated due to exceeding maximum limit`)}},async(e,t)=>{let n=e.projectsManager.ensureProjectId(t.project),r=(await e.computedModel(n)).findElement(t.elementId);R(r,`Element "${t.elementId}" not found in project "${n}"`);let i=[],a=!1;switch(t.queryType){case`ancestors`:for(let e of r.ancestors()){if(i.length>=100){a=!0;break}i.push(serializeElement(e))}break;case`descendants`:for(let e of r.descendants()){if(i.length>=100){a=!0;break}i.push(serializeElement(e))}break;case`siblings`:for(let e of r.siblings()){if(i.length>=100){a=!0;break}i.push(serializeElement(e))}break;case`children`:for(let e of r.children()){if(i.length>=100){a=!0;break}i.push(serializeElement(e))}break;case`parent`:{let e=r.parent;e&&i.push(serializeElement(e));break}case`incomers`:{let e=t.includeIndirect?`all`:`direct`;for(let t of r.incomers(e)){if(i.length>=100){a=!0;break}i.push(serializeElement(t))}break}case`outgoers`:{let e=t.includeIndirect?`all`:`direct`;for(let t of r.outgoers(e)){if(i.length>=100){a=!0;break}i.push(serializeElement(t))}break}}return{results:i,truncated:a}}),rr=A({elementId:L().describe(`ID of the incoming element`),relationshipLabel:L().optional().describe(`Label on the relationship`),technology:L().optional().describe(`Technology specified on the relationship`)}),ir=likec4Tool({name:`query-incomers-graph`,description:`
875
+ `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Query element graph`},inputSchema:{elementId:N().describe(`Element id (FQN) to query`),queryType:mr.describe(`Type of graph query`),includeIndirect:A().optional().default(!0).describe(`For incomers/outgoers: include indirect relationships (default: true)`),project:$},outputSchema:{results:P(Zn),truncated:A().describe(`True if results were truncated due to exceeding maximum limit`)}})(async(e,t)=>{let n=e.projectsManager.ensureProjectId(t.project),r=(await e.computedModel(n)).findElement(t.elementId);U(r,`Element "${t.elementId}" not found in project "${n}"`);let i=[],a=!1;switch(t.queryType){case`ancestors`:for(let e of r.ancestors()){if(i.length>=100){a=!0;break}i.push(serializeElement(e))}break;case`descendants`:for(let e of r.descendants()){if(i.length>=100){a=!0;break}i.push(serializeElement(e))}break;case`siblings`:for(let e of r.siblings()){if(i.length>=100){a=!0;break}i.push(serializeElement(e))}break;case`children`:for(let e of r.children()){if(i.length>=100){a=!0;break}i.push(serializeElement(e))}break;case`parent`:{let e=r.parent;e&&i.push(serializeElement(e));break}case`incomers`:{let e=t.includeIndirect?`all`:`direct`;for(let t of r.incomers(e)){if(i.length>=100){a=!0;break}i.push(serializeElement(t))}break}case`outgoers`:{let e=t.includeIndirect?`all`:`direct`;for(let t of r.outgoers(e)){if(i.length>=100){a=!0;break}i.push(serializeElement(t))}break}}return{results:i,truncated:a}}),gr=R({elementId:N().describe(`ID of the incoming element`),relationshipLabel:N().optional().describe(`Label on the relationship`),technology:N().optional().describe(`Technology specified on the relationship`)}),_r=likec4Tool({name:`query-incomers-graph`,description:`
873
876
  Query the complete graph of all elements that provide input to the target element (recursive incomers/producers).
874
877
 
875
878
  This tool performs a breadth-first traversal to discover all upstream dependencies - elements that directly or
@@ -926,7 +929,7 @@ Notes:
926
929
  Example:
927
930
  For a database element, this returns all services, APIs, and components that write to it,
928
931
  plus all their dependencies, recursively up to maxDepth levels.
929
- `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Query complete incomers graph`},inputSchema:{elementId:L().describe(`Target element id (FQN) to query incomers for`),includeIndirect:F().optional().default(!0).describe(`Include indirect relationships through nested elements (default: true)`),maxDepth:I().int().positive().max(50).optional().default(10).describe(`Maximum traversal depth (default: 10, max: 50)`),maxNodes:I().int().positive().max(2e3).optional().default(200).describe(`Maximum number of nodes to return (default: 200, max: 2000)`),project:$},outputSchema:{target:L().describe(`Target element id`),totalNodes:I().describe(`Total number of nodes in the graph`),maxDepth:I().describe(`Maximum depth reached`),truncated:F().describe(`True if result was truncated due to maxNodes limit`),nodes:M(Q.extend({incomers:N(rr).describe(`Incoming relationships with details`),depth:I().describe(`Distance from target element (0 = target)`)}))}},async(e,t)=>{let n=e.projectsManager.ensureProjectId(t.project),r=await e.computedModel(n);R(r.findElement(t.elementId),`Element "${t.elementId}" not found in project "${n}"`);let i=t.includeIndirect?`all`:`direct`,a=traverseGraph(r,t.elementId,`incoming`,i,t.maxDepth,t.maxNodes),s={};for(let[e,t]of Object.entries(a.nodes)){let{neighbors:n,...r}=t;s[e]={...r,incomers:n}}return{target:a.target,totalNodes:a.totalNodes,maxDepth:a.maxDepth,truncated:a.truncated,nodes:s}}),ar=A({elementId:L().describe(`ID of the outgoing element`),relationshipLabel:L().optional().describe(`Label on the relationship`),technology:L().optional().describe(`Technology specified on the relationship`)}),or=likec4Tool({name:`query-outgoers-graph`,description:`
932
+ `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Query complete incomers graph`},inputSchema:{elementId:N().describe(`Target element id (FQN) to query incomers for`),includeIndirect:A().optional().default(!0).describe(`Include indirect relationships through nested elements (default: true)`),maxDepth:F().int().positive().max(50).optional().default(10).describe(`Maximum traversal depth (default: 10, max: 50)`),maxNodes:F().int().positive().max(2e3).optional().default(200).describe(`Maximum number of nodes to return (default: 200, max: 2000)`),project:$},outputSchema:{target:N().describe(`Target element id`),totalNodes:F().describe(`Total number of nodes in the graph`),maxDepth:F().describe(`Maximum depth reached`),truncated:A().describe(`True if result was truncated due to maxNodes limit`),nodes:M(Zn.extend({incomers:P(gr).describe(`Incoming relationships with details`),depth:F().describe(`Distance from target element (0 = target)`)}))}})(async(e,t)=>{let n=e.projectsManager.ensureProjectId(t.project),r=await e.computedModel(n);U(r.findElement(t.elementId),`Element "${t.elementId}" not found in project "${n}"`);let i=t.includeIndirect?`all`:`direct`,a=traverseGraph(r,t.elementId,`incoming`,i,t.maxDepth,t.maxNodes),s={};for(let[e,t]of Object.entries(a.nodes)){let{neighbors:n,...r}=t;s[e]={...r,incomers:n}}return{target:a.target,totalNodes:a.totalNodes,maxDepth:a.maxDepth,truncated:a.truncated,nodes:s}}),vr=R({elementId:N().describe(`ID of the outgoing element`),relationshipLabel:N().optional().describe(`Label on the relationship`),technology:N().optional().describe(`Technology specified on the relationship`)}),yr=likec4Tool({name:`query-outgoers-graph`,description:`
930
933
  Query the complete graph of all elements that receive output from the target element (recursive outgoers/consumers).
931
934
 
932
935
  This tool performs a breadth-first traversal to discover all downstream dependencies - elements that directly or
@@ -983,7 +986,7 @@ Notes:
983
986
  Example:
984
987
  For an API service, this returns all clients, services, and systems that consume its output,
985
988
  plus all their consumers, recursively up to maxDepth levels.
986
- `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Query complete outgoers graph`},inputSchema:{elementId:L().describe(`Target element id (FQN) to query outgoers for`),includeIndirect:F().optional().default(!0).describe(`Include indirect relationships through nested elements (default: true)`),maxDepth:I().int().positive().max(50).optional().default(10).describe(`Maximum traversal depth (default: 10, max: 50)`),maxNodes:I().int().positive().max(2e3).optional().default(200).describe(`Maximum number of nodes to return (default: 200, max: 2000)`),project:$},outputSchema:{target:L().describe(`Target element id`),totalNodes:I().describe(`Total number of nodes in the graph`),maxDepth:I().describe(`Maximum depth reached`),truncated:F().describe(`True if result was truncated due to maxNodes limit`),nodes:M(Q.extend({outgoers:N(ar).describe(`Outgoing relationships with details`),depth:I().describe(`Distance from target element (0 = target)`)}))}},async(e,t)=>{let n=e.projectsManager.ensureProjectId(t.project),r=await e.computedModel(n);R(r.findElement(t.elementId),`Element "${t.elementId}" not found in project "${n}"`);let i=t.includeIndirect?`all`:`direct`,a=traverseGraph(r,t.elementId,`outgoing`,i,t.maxDepth,t.maxNodes),s={};for(let[e,t]of Object.entries(a.nodes)){let{neighbors:n,...r}=t;s[e]={...r,outgoers:n}}return{target:a.target,totalNodes:a.totalNodes,maxDepth:a.maxDepth,truncated:a.truncated,nodes:s}}),sr=likec4Tool({name:`read-deployment`,description:`
989
+ `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Query complete outgoers graph`},inputSchema:{elementId:N().describe(`Target element id (FQN) to query outgoers for`),includeIndirect:A().optional().default(!0).describe(`Include indirect relationships through nested elements (default: true)`),maxDepth:F().int().positive().max(50).optional().default(10).describe(`Maximum traversal depth (default: 10, max: 50)`),maxNodes:F().int().positive().max(2e3).optional().default(200).describe(`Maximum number of nodes to return (default: 200, max: 2000)`),project:$},outputSchema:{target:N().describe(`Target element id`),totalNodes:F().describe(`Total number of nodes in the graph`),maxDepth:F().describe(`Maximum depth reached`),truncated:A().describe(`True if result was truncated due to maxNodes limit`),nodes:M(Zn.extend({outgoers:P(vr).describe(`Outgoing relationships with details`),depth:F().describe(`Distance from target element (0 = target)`)}))}})(async(e,t)=>{let n=e.projectsManager.ensureProjectId(t.project),r=await e.computedModel(n);U(r.findElement(t.elementId),`Element "${t.elementId}" not found in project "${n}"`);let i=t.includeIndirect?`all`:`direct`,a=traverseGraph(r,t.elementId,`outgoing`,i,t.maxDepth,t.maxNodes),s={};for(let[e,t]of Object.entries(a.nodes)){let{neighbors:n,...r}=t;s[e]={...r,outgoers:n}}return{target:a.target,totalNodes:a.totalNodes,maxDepth:a.maxDepth,truncated:a.truncated,nodes:s}}),br=likec4Tool({name:`read-deployment`,description:`
987
990
  Read details about a deployment node or a deployed instance in a LikeC4 project.
988
991
 
989
992
  What it does:
@@ -1048,7 +1051,7 @@ Example response (deployed instance):
1048
1051
  "range": { "start": { "line": 10, "character": 0 }, "end": { "line": 25, "character": 0 } }
1049
1052
  }
1050
1053
  }
1051
- `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Read deployment entity`},inputSchema:{id:L().describe(`Deployment id (FQN)`),project:$},outputSchema:{type:k([`deployment-node`,`deployed-instance`]),id:L().describe(`Deployment id (FQN)`),kind:L().describe(`Deployment node kind, or element kind for deployed instances`),name:L(),title:L(),description:L().nullable(),technology:L().nullable(),tags:N(L()),project:L(),metadata:M(j([L(),N(L())])),links:N(A({title:L().nullable().describe(`Optional link title`),url:L().describe(`Link URL`),relative:L().nullable().describe(`Relative path (if URL is relative to workspace root)`)})).describe(`External links associated with this deployment entity`),shape:L(),color:L(),children:N(L()).describe(`Children of this deployment node (Array of Deployment ids)`),includedInViews:Bn.describe(`Views that include this deployment node`),instanceof:A({id:L().describe(`Element ID (FQN)`),title:L(),kind:L()}).nullable().describe(`If type is "deployed-instance", the referenced element`),sourceLocation:zn}},async(e,t)=>{let n=e.projectsManager.ensureProjectId(t.project),r=(await e.computedModel(n)).deployment.findElement(t.id);R(r,`Deployment entity "${t.id}" not found in project "${n}"`);let i=mkLocate(e,n);return{type:r.isInstance()?`deployed-instance`:`deployment-node`,id:r.id,name:r.name,kind:r.kind,title:r.title,description:r.description.text,technology:r.technology,tags:[...r.tags],project:n,metadata:r.getMetadata(),links:(r.links??[]).map(e=>({title:e.title??null,url:e.url,relative:e.relative??null})),shape:r.shape,color:r.color,children:r.isInstance()?[]:[...r.children()].map(e=>e.id),includedInViews:includedInViews(r.views()),instanceof:r.isInstance()?{id:r.element.id,title:r.element.title,kind:r.element.kind}:null,sourceLocation:i({deployment:r.id})}}),cr=likec4Tool({name:`read-element`,description:`
1054
+ `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Read deployment entity`},inputSchema:{id:N().describe(`Deployment id (FQN)`),project:$},outputSchema:{type:L([`deployment-node`,`deployed-instance`]),id:N().describe(`Deployment id (FQN)`),kind:N().describe(`Deployment node kind, or element kind for deployed instances`),name:N(),title:N(),description:N().nullable(),technology:N().nullable(),tags:P(N()),project:N(),metadata:M(I([N(),P(N())])),links:P(R({title:N().nullable().describe(`Optional link title`),url:N().describe(`Link URL`),relative:N().nullable().describe(`Relative path (if URL is relative to workspace root)`)})).describe(`External links associated with this deployment entity`),shape:N(),color:N(),children:P(N()).describe(`Children of this deployment node (Array of Deployment ids)`),includedInViews:$n.describe(`Views that include this deployment node`),instanceof:R({id:N().describe(`Element ID (FQN)`),title:N(),kind:N()}).nullable().describe(`If type is "deployed-instance", the referenced element`),sourceLocation:Qn}})(async(e,t)=>{let n=e.projectsManager.ensureProjectId(t.project),r=(await e.computedModel(n)).deployment.findElement(t.id);U(r,`Deployment entity "${t.id}" not found in project "${n}"`);let i=mkLocate(e,n);return{type:r.isInstance()?`deployed-instance`:`deployment-node`,id:r.id,name:r.name,kind:r.kind,title:r.title,description:r.description.text,technology:r.technology,tags:[...r.tags],project:n,metadata:r.getMetadata(),links:(r.links??[]).map(e=>({title:e.title??null,url:e.url,relative:e.relative??null})),shape:r.shape,color:r.color,children:r.isInstance()?[]:[...r.children()].map(e=>e.id),includedInViews:includedInViews(r.views()),instanceof:r.isInstance()?{id:r.element.id,title:r.element.title,kind:r.element.kind}:null,sourceLocation:i({deployment:r.id})}}),xr=likec4Tool({name:`read-element`,description:`
1052
1055
  Read detailed information about a LikeC4 element.
1053
1056
 
1054
1057
  Request:
@@ -1135,7 +1138,7 @@ Example response:
1135
1138
  "range": { "start": { "line": 10, "character": 0 }, "end": { "line": 25, "character": 0 } }
1136
1139
  }
1137
1140
  }
1138
- `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Read element`},inputSchema:{id:L().describe(`Element id (FQN)`),project:$},outputSchema:{id:L().describe(`Element id (FQN)`),kind:L().describe(`Element kind`),name:L().describe(`Element name`),title:L(),description:L().nullable(),technology:L().nullable(),tags:N(L()),project:L(),metadata:M(j([L(),N(L())])),links:N(A({title:L().nullable().describe(`Optional link title`),url:L().describe(`Link URL`),relative:L().nullable().describe(`Relative path (if URL is relative to workspace root)`)})).describe(`External links associated with this element`),shape:L(),color:L(),children:N(L()).describe(`Children of this element (Array of FQNs)`),defaultView:L().nullable().describe(`Name of the default view of this element`),includedInViews:Bn.describe(`Views that include this element`),relationships:A({incoming:N(A({source:A({id:L(),title:L(),kind:L()}).describe(`Source element of this relationship`),kind:L().nullable().describe(`Relationship kind`),target:L().describe(`Target element id (FQN), either this element or nested element, if relationship is indirect`),title:L().nullable().describe(`Relationship title`),description:L().nullable().describe(`Relationship description`),technology:L().nullable().describe(`Relationship technology`),tags:N(L()).describe(`Relationship tags`)})).describe(`Incoming relationships of this element (direct and indirect, incoming to nested elements)`),outgoing:N(A({source:L().describe(`Source element id (FQN), either this element or nested element, if relationship is indirect`),target:A({id:L(),title:L(),kind:L()}).describe(`Target element of this relationship`),kind:L().nullable().describe(`Relationship kind`),title:L().nullable().describe(`Relationship title`),description:L().nullable().describe(`Relationship description`),technology:L().nullable().describe(`Relationship technology`),tags:N(L()).describe(`Relationship tags`)})).describe(`Outgoing relationships of this element (direct and indirect, outgoing from nested elements)`)}).describe(`Relationships of this element`),deployedInstances:N(L()).describe(`Deployed instances of this element (Array of Deployment FQNs)`),sourceLocation:zn}},async(e,t)=>{let n=e.projectsManager.ensureProjectId(t.project),r=(await e.computedModel(n)).findElement(t.id);R(r,`Element "${t.id}" not found in project "${n}"`);let i=mkLocate(e,n);return{id:r.id,name:r.name,kind:r.kind,title:r.title,description:r.description.text,technology:r.technology,tags:[...r.tags],project:n,metadata:r.getMetadata(),links:(r.links??[]).map(e=>({title:e.title??null,url:e.url,relative:e.relative??null})),shape:r.shape,color:r.color,children:[...r.children()].map(e=>e.id),defaultView:r.defaultView?.id||null,includedInViews:includedInViews(r.views()),relationships:{incoming:[...r.incoming()].map(e=>({source:{id:e.source.id,title:e.source.title,kind:e.source.kind},kind:e.kind,target:e.target.id,title:e.title,description:e.description.text,technology:e.technology,tags:[...e.tags]})),outgoing:[...r.outgoing()].map(e=>({source:e.source.id,target:{id:e.target.id,title:e.target.title,kind:e.target.kind},kind:e.kind,title:e.title,description:e.description.text,technology:e.technology,tags:[...e.tags]}))},deployedInstances:[...r.deployments()].map(e=>e.id),sourceLocation:i({element:r.id})}}),lr=likec4Tool({name:`read-project-summary`,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Read project summary`},description:`
1141
+ `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Read element`},inputSchema:{id:N().describe(`Element id (FQN)`),project:$},outputSchema:{id:N().describe(`Element id (FQN)`),kind:N().describe(`Element kind`),name:N().describe(`Element name`),title:N(),description:N().nullable(),technology:N().nullable(),tags:P(N()),project:N(),metadata:M(I([N(),P(N())])),links:P(R({title:N().nullable().describe(`Optional link title`),url:N().describe(`Link URL`),relative:N().nullable().describe(`Relative path (if URL is relative to workspace root)`)})).describe(`External links associated with this element`),shape:N(),color:N(),children:P(N()).describe(`Children of this element (Array of FQNs)`),defaultView:N().nullable().describe(`Name of the default view of this element`),includedInViews:$n.describe(`Views that include this element`),relationships:R({incoming:P(R({source:R({id:N(),title:N(),kind:N()}).describe(`Source element of this relationship`),kind:N().nullable().describe(`Relationship kind`),target:N().describe(`Target element id (FQN), either this element or nested element, if relationship is indirect`),title:N().nullable().describe(`Relationship title`),description:N().nullable().describe(`Relationship description`),technology:N().nullable().describe(`Relationship technology`),tags:P(N()).describe(`Relationship tags`)})).describe(`Incoming relationships of this element (direct and indirect, incoming to nested elements)`),outgoing:P(R({source:N().describe(`Source element id (FQN), either this element or nested element, if relationship is indirect`),target:R({id:N(),title:N(),kind:N()}).describe(`Target element of this relationship`),kind:N().nullable().describe(`Relationship kind`),title:N().nullable().describe(`Relationship title`),description:N().nullable().describe(`Relationship description`),technology:N().nullable().describe(`Relationship technology`),tags:P(N()).describe(`Relationship tags`)})).describe(`Outgoing relationships of this element (direct and indirect, outgoing from nested elements)`)}).describe(`Relationships of this element`),deployedInstances:P(N()).describe(`Deployed instances of this element (Array of Deployment FQNs)`),sourceLocation:Qn}})(async(e,t)=>{let n=e.projectsManager.ensureProjectId(t.project),r=(await e.computedModel(n)).findElement(t.id);U(r,`Element "${t.id}" not found in project "${n}"`);let i=mkLocate(e,n);return{id:r.id,name:r.name,kind:r.kind,title:r.title,description:r.description.text,technology:r.technology,tags:[...r.tags],project:n,metadata:r.getMetadata(),links:(r.links??[]).map(e=>({title:e.title??null,url:e.url,relative:e.relative??null})),shape:r.shape,color:r.color,children:[...r.children()].map(e=>e.id),defaultView:r.defaultView?.id||null,includedInViews:includedInViews(r.views()),relationships:{incoming:[...r.incoming()].map(e=>({source:{id:e.source.id,title:e.source.title,kind:e.source.kind},kind:e.kind,target:e.target.id,title:e.title,description:e.description.text,technology:e.technology,tags:[...e.tags]})),outgoing:[...r.outgoing()].map(e=>({source:e.source.id,target:{id:e.target.id,title:e.target.title,kind:e.target.kind},kind:e.kind,title:e.title,description:e.description.text,technology:e.technology,tags:[...e.tags]}))},deployedInstances:[...r.deployments()].map(e=>e.id),sourceLocation:i({element:r.id})}}),Sr=likec4Tool({name:`read-project-summary`,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Read project summary`},description:`
1139
1142
  Request:
1140
1143
  - project: string (optional) — project id. Defaults to "default" if omitted.
1141
1144
 
@@ -1226,7 +1229,7 @@ Example response:
1226
1229
  }
1227
1230
  ]
1228
1231
  }
1229
- `,inputSchema:{project:$},outputSchema:{title:L(),folder:L(),sources:N(L()),config:Rn.describe(`Project configuration`),specification:A({elementKinds:N(L()),relationshipKinds:N(L()),deploymentKinds:N(L()),tags:N(L()),metadataKeys:N(L())}),elements:N(A({id:L(),kind:L(),title:L(),tags:N(L())})).describe(`List of elements in the project`),deployments:N(Ie(`type`,[A({type:P(`deployment-node`),id:L().describe(`Node ID`),kind:L().describe(`Deployment node kind`),title:L().describe(`Node title`),tags:N(L())}),A({type:P(`deployed-instance`),id:L().describe(`Node ID`),title:L().describe(`Node title`),tags:N(L()),referencedElementId:L().describe(`Element ID (FQN)`)})])).describe(`List of deployment nodes and deployed instances in the project`),views:N(A({id:L(),title:L(),type:k([`element`,`deployment`,`dynamic`])}))}},async(e,t)=>{let n=e.projectsManager.ensureProjectId(t.project),r=e.project(n),i=await e.computedModel(n);return{title:r.title,folder:r.folder.fsPath,sources:r.documents?.map(e=>e.fsPath)??[],config:serializeConfig(r.config),specification:{elementKinds:D(i.specification.elements),relationshipKinds:D(i.specification.relationships),deploymentKinds:D(i.specification.deployments),tags:[...i.tags],metadataKeys:i.specification.metadataKeys??[]},elements:[...i.elements()].filter(e=>!e.imported).map(e=>({id:e.id,kind:e.kind,title:e.title,tags:[...e.tags]})),deployments:[...i.deployment.elements()].map(e=>e.isInstance()?{type:`deployed-instance`,id:e.id,title:e.title,tags:[...e.tags],referencedElementId:e.element.id}:{type:`deployment-node`,id:e.id,kind:e.kind,title:e.title,tags:[...e.tags]}),views:[...i.views()].map(e=>({id:e.id,title:e.titleOrId,type:e.$view._type}))}}),modelRef=e=>e.hasElement()?e.element.id:e.hasDeployment()?e.deployment.id:null,ur=Ie(`type`,[A({type:P(`element`),id:L().describe(`Node ID`),elementId:L().describe(`Element ID (FQN)`),kind:L().describe(`Element kind`),title:L().describe(`Node title`),description:L().nullable(),technology:L().nullable(),children:N(L()).describe(`Children nodes, array of node IDs`),shape:L().describe(`Rendered shape`),color:L().describe(`Rendered color`),tags:N(L())}),A({type:P(`deployment-node`),id:L().describe(`Node ID`),deploymentId:L().describe(`Deployment entity ID (FQN)`),kind:L().describe(`Deployment kind`),title:L().describe(`Node title`),description:L().nullable(),technology:L().nullable(),children:N(L()).describe(`Children nodes, array of node IDs`),shape:L().describe(`Rendered shape`),color:L().describe(`Rendered color`),tags:N(L())}),A({type:P(`deployed-instance`),id:L().describe(`Node ID`),deploymentId:L().describe(`Deployment entity ID (FQN)`),title:L().describe(`Node title`),description:L().nullable(),technology:L().nullable(),referencedElement:A({id:L().describe(`Element ID (FQN)`),kind:L().describe(`Element kind`),title:L().describe(`Element title`)}),shape:L().describe(`Rendered shape`),color:L().describe(`Rendered color`),tags:N(L())})]),dr=likec4Tool({name:`read-view`,description:`
1232
+ `,inputSchema:{project:$},outputSchema:{title:N(),folder:N(),sources:P(N()),config:Xn.describe(`Project configuration`),specification:R({elementKinds:P(N()),relationshipKinds:P(N()),deploymentKinds:P(N()),tags:P(N()),metadataKeys:P(N())}),elements:P(R({id:N(),kind:N(),title:N(),tags:P(N())})).describe(`List of elements in the project`),deployments:P(Be(`type`,[R({type:j(`deployment-node`),id:N().describe(`Node ID`),kind:N().describe(`Deployment node kind`),title:N().describe(`Node title`),tags:P(N())}),R({type:j(`deployed-instance`),id:N().describe(`Node ID`),title:N().describe(`Node title`),tags:P(N()),referencedElementId:N().describe(`Element ID (FQN)`)})])).describe(`List of deployment nodes and deployed instances in the project`),views:P(R({id:N(),title:N(),type:L([`element`,`deployment`,`dynamic`])}))}})(async(e,t)=>{let n=e.projectsManager.ensureProjectId(t.project),r=e.project(n),i=await e.computedModel(n);return{title:r.title,folder:r.folder.fsPath,sources:r.documents?.map(e=>e.fsPath)??[],config:serializeConfig(r.config),specification:{elementKinds:O(i.specification.elements),relationshipKinds:O(i.specification.relationships),deploymentKinds:O(i.specification.deployments),tags:[...i.tags],metadataKeys:i.specification.metadataKeys??[]},elements:[...i.elements()].filter(e=>!e.imported).map(e=>({id:e.id,kind:e.kind,title:e.title,tags:[...e.tags]})),deployments:[...i.deployment.elements()].map(e=>e.isInstance()?{type:`deployed-instance`,id:e.id,title:e.title,tags:[...e.tags],referencedElementId:e.element.id}:{type:`deployment-node`,id:e.id,kind:e.kind,title:e.title,tags:[...e.tags]}),views:[...i.views()].map(e=>({id:e.id,title:e.titleOrId,type:e.$view._type}))}}),modelRef=e=>e.hasElement()?e.element.id:e.hasDeployment()?e.deployment.id:null,Cr=Be(`type`,[R({type:j(`element`),id:N().describe(`Node ID`),elementId:N().describe(`Element ID (FQN)`),kind:N().describe(`Element kind`),title:N().describe(`Node title`),description:N().nullable(),technology:N().nullable(),children:P(N()).describe(`Children nodes, array of node IDs`),shape:N().describe(`Rendered shape`),color:N().describe(`Rendered color`),tags:P(N())}),R({type:j(`deployment-node`),id:N().describe(`Node ID`),deploymentId:N().describe(`Deployment entity ID (FQN)`),kind:N().describe(`Deployment kind`),title:N().describe(`Node title`),description:N().nullable(),technology:N().nullable(),children:P(N()).describe(`Children nodes, array of node IDs`),shape:N().describe(`Rendered shape`),color:N().describe(`Rendered color`),tags:P(N())}),R({type:j(`deployed-instance`),id:N().describe(`Node ID`),deploymentId:N().describe(`Deployment entity ID (FQN)`),title:N().describe(`Node title`),description:N().nullable(),technology:N().nullable(),referencedElement:R({id:N().describe(`Element ID (FQN)`),kind:N().describe(`Element kind`),title:N().describe(`Element title`)}),shape:N().describe(`Rendered shape`),color:N().describe(`Rendered color`),tags:P(N())})]),wr=likec4Tool({name:`read-view`,description:`
1230
1233
  Read detailed information about a LikeC4 view.
1231
1234
 
1232
1235
  Request:
@@ -1274,7 +1277,7 @@ Example response:
1274
1277
  "range": { "start": { "line": 10, "character": 0 }, "end": { "line": 30, "character": 0 } }
1275
1278
  }
1276
1279
  }
1277
- `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Read view`},inputSchema:{viewId:L().describe(`View id (name)`),project:$},outputSchema:{id:L(),type:k([`element`,`deployment`,`dynamic`]).describe(`View type`),title:L(),description:L().nullable(),tags:N(L()),project:L(),nodes:N(ur),edges:N(A({source:L().describe(`Source node`),target:L().describe(`Target node`),label:L().nullable(),description:L().nullable(),technology:L().nullable(),tags:N(L())})).describe(`Edge represents relationship between nodes`),sourceLocation:zn}},async(e,t)=>{let n=e.projectsManager.ensureProjectId(t.project),r=e.project(n),i=(await e.computedModel(n)).findView(t.viewId);if(!i)throw Error(`View with ID '${t.viewId}' not found in project ${r.id}`);let a=mkLocate(e,r.id);return{id:i.id,type:i.$view._type,title:i.title??i.id,description:i.description.text,tags:[...i.tags],project:r.id,nodes:[...i.nodes()].flatMap(e=>{let t={id:e.id,title:e.title,description:e.description.text,technology:e.technology,shape:e.shape,color:e.color,tags:[...e.tags]};return e.hasDeployedInstance()?{...t,type:`deployed-instance`,deploymentId:e.deployment.id,referencedElement:{id:e.deployment.element.id,kind:e.deployment.element.kind,title:e.deployment.element.title}}:e.hasDeployment()?{...t,type:`deployment-node`,kind:e.deployment.kind,deploymentId:e.deployment.id,children:[...e.children()].map(e=>e.id)}:e.hasElement()?{...t,type:`element`,elementId:e.element.id,kind:e.element.kind,children:[...e.children()].flatMap(e=>modelRef(e)??[])}:[]}),edges:[...i.edges()].map(e=>({source:e.source.id,target:e.target.id,label:e.label,description:e.description.text,technology:e.technology,tags:[...e.tags]})),sourceLocation:a({view:i.id})}}),fr=N(Ie(`type`,[A({type:P(`element`),project:L().describe(`Project ID`),id:L().describe(`Element ID (FQN)`),name:L().describe(`Element name`),kind:L(),title:L(),technology:L().nullable(),shape:L(),includedInViews:Bn,metadata:M(j([L(),N(L())])),tags:N(L())}),A({type:P(`deployment-node`),project:L().describe(`Project ID`),id:L().describe(`Deployment ID (FQN)`),name:L().describe(`Deployment name`),kind:L(),title:L(),technology:L().nullable(),shape:L(),includedInViews:Bn,metadata:M(j([L(),N(L())])),tags:N(L())})])),pr=likec4Tool({name:`search-element`,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Search elements`},description:`
1280
+ `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Read view`},inputSchema:{viewId:N().describe(`View id (name)`),project:$},outputSchema:{id:N(),type:L([`element`,`deployment`,`dynamic`]).describe(`View type`),title:N(),description:N().nullable(),tags:P(N()),project:N(),nodes:P(Cr),edges:P(R({source:N().describe(`Source node`),target:N().describe(`Target node`),label:N().nullable(),description:N().nullable(),technology:N().nullable(),tags:P(N())})).describe(`Edge represents relationship between nodes`),sourceLocation:Qn}})(async(e,t)=>{let n=e.projectsManager.ensureProjectId(t.project),r=e.project(n),i=(await e.computedModel(n)).findView(t.viewId);if(!i)throw Error(`View with ID '${t.viewId}' not found in project ${r.id}`);let a=mkLocate(e,r.id);return{id:i.id,type:i.$view._type,title:i.title??i.id,description:i.description.text,tags:[...i.tags],project:r.id,nodes:[...i.nodes()].flatMap(e=>{let t={id:e.id,title:e.title,description:e.description.text,technology:e.technology,shape:e.shape,color:e.color,tags:[...e.tags]};return e.hasDeployedInstance()?{...t,type:`deployed-instance`,deploymentId:e.deployment.id,referencedElement:{id:e.deployment.element.id,kind:e.deployment.element.kind,title:e.deployment.element.title}}:e.hasDeployment()?{...t,type:`deployment-node`,kind:e.deployment.kind,deploymentId:e.deployment.id,children:[...e.children()].map(e=>e.id)}:e.hasElement()?{...t,type:`element`,elementId:e.element.id,kind:e.element.kind,children:[...e.children()].flatMap(e=>modelRef(e)??[])}:[]}),edges:[...i.edges()].map(e=>({source:e.source.id,target:e.target.id,label:e.label,description:e.description.text,technology:e.technology,tags:[...e.tags]})),sourceLocation:a({view:i.id})}}),Tr=P(Be(`type`,[R({type:j(`element`),project:N().describe(`Project ID`),id:N().describe(`Element ID (FQN)`),name:N().describe(`Element name`),kind:N(),title:N(),technology:N().nullable(),shape:N(),includedInViews:$n,metadata:M(I([N(),P(N())])),tags:P(N())}),R({type:j(`deployment-node`),project:N().describe(`Project ID`),id:N().describe(`Deployment ID (FQN)`),name:N().describe(`Deployment name`),kind:N(),title:N(),technology:N().nullable(),shape:N(),includedInViews:$n,metadata:M(I([N(),P(N())])),tags:P(N())})])),Er=likec4Tool({name:`search-element`,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Search elements`},description:`
1278
1281
  Search LikeC4 elements and deployment nodes across all projects.
1279
1282
 
1280
1283
  Query syntax (case-insensitive):
@@ -1329,7 +1332,7 @@ Example response:
1329
1332
  }
1330
1333
  ]
1331
1334
  }
1332
- `,inputSchema:{search:L().min(2,`Search must be at least 2 characters long`)},outputSchema:{total:I(),found:fr}},async(e,t)=>{let n=e.projects(),r=[],i=t.search.toLowerCase(),predicate;i.startsWith(`kind:`)?(i=i.slice(5),Z.debug(`search by kind: {search}`,{search:i}),predicate=e=>e.kind.toLowerCase()===i):i.startsWith(`shape:`)?(i=i.slice(6),Z.debug(`search by shape: {search}`,{search:i}),predicate=e=>e.shape.toLowerCase()===i):i.startsWith(`meta:`)?(i=i.slice(5),Z.debug(`search by metadata: {search}`,{search:i}),predicate=e=>!!e.getMetadata(i)):i.startsWith(`#`)?(i=i.slice(1),Z.debug(`search by tag: {search}`,{search:i}),predicate=e=>e.tags.some(e=>e.toLowerCase().includes(i))):(Z.debug(`search by id/title: {search}`,{search:i}),predicate=e=>e.id.toLowerCase().includes(i)||e.title.toLowerCase().includes(i));for(let t of n)try{let n=await e.computedModel(t.id);for(let e of Qe(n.elements(),e=>!e.imported&&predicate(e)))r.push({type:`element`,project:t.id,id:e.id,name:e.name,kind:e.kind,title:e.title,technology:e.technology,shape:e.shape,tags:[...e.tags],metadata:e.getMetadata(),includedInViews:includedInViews(e.views())});for(let e of Qe(n.deployment.nodes(),predicate))r.push({type:`deployment-node`,project:t.id,id:e.id,name:e.name,kind:e.kind,title:e.title,technology:e.technology,shape:e.shape,tags:[...e.tags],metadata:e.getMetadata(),includedInViews:includedInViews(e.views())})}catch(e){Z.error(`Error searching in project ${t.id}:`,{error:e})}return{total:r.length,found:r.slice(0,20)}}),mr=A({id:L().describe(`Element id (FQN)`),name:L().describe(`Element name`),kind:L().describe(`Element kind`),title:L().describe(`Human-readable title`),depth:I().describe(`Depth relative to the root element (1 = direct child)`),tags:N(L()).describe(`Assigned tags`),metadata:M(j([L(),N(L())])).describe(`Element metadata`),childCount:I().describe(`Number of direct children`),incomingCount:I().describe(`Number of incoming relationships`),outgoingCount:I().describe(`Number of outgoing relationships`)}),hr=likec4Tool({name:`subgraph-summary`,description:`
1335
+ `,inputSchema:{search:N().min(2,`Search must be at least 2 characters long`)},outputSchema:{total:F(),found:Tr}})(async(e,t)=>{let n=e.projects(),r=[],i=t.search.toLowerCase(),predicate;i.startsWith(`kind:`)?(i=i.slice(5),Q.debug(`search by kind: {search}`,{search:i}),predicate=e=>e.kind.toLowerCase()===i):i.startsWith(`shape:`)?(i=i.slice(6),Q.debug(`search by shape: {search}`,{search:i}),predicate=e=>e.shape.toLowerCase()===i):i.startsWith(`meta:`)?(i=i.slice(5),Q.debug(`search by metadata: {search}`,{search:i}),predicate=e=>!!e.getMetadata(i)):i.startsWith(`#`)?(i=i.slice(1),Q.debug(`search by tag: {search}`,{search:i}),predicate=e=>e.tags.some(e=>e.toLowerCase().includes(i))):(Q.debug(`search by id/title: {search}`,{search:i}),predicate=e=>e.id.toLowerCase().includes(i)||e.title.toLowerCase().includes(i));for(let t of n)try{let n=await e.computedModel(t.id);for(let e of it(n.elements(),e=>!e.imported&&predicate(e)))r.push({type:`element`,project:t.id,id:e.id,name:e.name,kind:e.kind,title:e.title,technology:e.technology,shape:e.shape,tags:[...e.tags],metadata:e.getMetadata(),includedInViews:includedInViews(e.views())});for(let e of it(n.deployment.nodes(),predicate))r.push({type:`deployment-node`,project:t.id,id:e.id,name:e.name,kind:e.kind,title:e.title,technology:e.technology,shape:e.shape,tags:[...e.tags],metadata:e.getMetadata(),includedInViews:includedInViews(e.views())})}catch(e){Q.error(`Error searching in project ${t.id}:`,{error:e})}return{total:r.length,found:r.slice(0,20)}}),Dr=R({id:N().describe(`Element id (FQN)`),name:N().describe(`Element name`),kind:N().describe(`Element kind`),title:N().describe(`Human-readable title`),depth:F().describe(`Depth relative to the root element (1 = direct child)`),tags:P(N()).describe(`Assigned tags`),metadata:M(I([N(),P(N())])).describe(`Element metadata`),childCount:F().describe(`Number of direct children`),incomingCount:F().describe(`Number of incoming relationships`),outgoingCount:F().describe(`Number of outgoing relationships`)}),Or=likec4Tool({name:`subgraph-summary`,description:`
1333
1336
  Get a compact, table-friendly summary of all descendants of a parent element.
1334
1337
  Returns each descendant with its depth, metadata, tags, and relationship counts in a single call.
1335
1338
  Much more efficient than calling read-element for each descendant individually.
@@ -1395,7 +1398,7 @@ Example response:
1395
1398
  "truncated": false,
1396
1399
  "truncatedByDepth": false
1397
1400
  }
1398
- `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Subgraph summary`},inputSchema:{elementId:L().describe(`Parent element id (FQN) whose descendants to summarize`),maxDepth:I().int().min(1).max(20).optional().default(10).describe(`Maximum depth of descendants to include (default: 10, max: 20)`),metadataKeys:N(L()).optional().describe(`If provided, only include these metadata keys in the response`),project:$},outputSchema:{root:A({id:L(),kind:L(),title:L(),childCount:I()}),descendants:N(mr),totalDescendants:I().describe(`Total number of descendants found`),truncated:F().describe(`True if results were truncated due to exceeding the limit`),truncatedByDepth:F().describe(`True if deeper descendants exist beyond maxDepth`)}},async(e,t)=>{let n=e.projectsManager.ensureProjectId(t.project),r=(await e.computedModel(n)).findElement(t.elementId);R(r,`Element "${t.elementId}" not found in project "${n}"`);let i=t.maxDepth,a=t.metadataKeys,s=[],c=0,l=!1,u=!1,f=[],p=[...r.children()];for(let e of p)f.push({element:e,depth:1});for(;f.length>0;){let{element:e,depth:t}=f.shift();if(t>i){u=!0;continue}c++;let n=[...e.children()];if(s.length<200){let r=e.getMetadata(),i=a?Object.fromEntries(a.filter(e=>e in r).map(e=>[e,r[e]])):r;s.push({id:e.id,name:e.name,kind:e.kind,title:e.title,depth:t,tags:[...e.tags],metadata:i,childCount:n.length,incomingCount:[...e.incoming()].length,outgoingCount:[...e.outgoing()].length})}else l=!0;for(let e of n)f.push({element:e,depth:t+1})}return{root:{id:r.id,kind:r.kind,title:r.title,childCount:p.length},descendants:s,totalDescendants:c,truncated:l,truncatedByDepth:u}});function createMCPServer(e,t){let n=new Re({name:`LikeC4`,version:Ln},{instructions:`LikeC4 MCP – query and navigate LikeC4 models.
1401
+ `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Subgraph summary`},inputSchema:{elementId:N().describe(`Parent element id (FQN) whose descendants to summarize`),maxDepth:F().int().min(1).max(20).optional().default(10).describe(`Maximum depth of descendants to include (default: 10, max: 20)`),metadataKeys:P(N()).optional().describe(`If provided, only include these metadata keys in the response`),project:$},outputSchema:{root:R({id:N(),kind:N(),title:N(),childCount:F()}),descendants:P(Dr),totalDescendants:F().describe(`Total number of descendants found`),truncated:A().describe(`True if results were truncated due to exceeding the limit`),truncatedByDepth:A().describe(`True if deeper descendants exist beyond maxDepth`)}})(async(e,t)=>{let n=e.projectsManager.ensureProjectId(t.project),r=(await e.computedModel(n)).findElement(t.elementId);U(r,`Element "${t.elementId}" not found in project "${n}"`);let i=t.maxDepth,a=t.metadataKeys,s=[],c=0,l=!1,u=!1,f=[],p=[...r.children()];for(let e of p)f.push({element:e,depth:1});for(;f.length>0;){let{element:e,depth:t}=f.shift();if(t>i){u=!0;continue}c++;let n=[...e.children()];if(s.length<200){let r=e.getMetadata(),i=a?Object.fromEntries(a.filter(e=>e in r).map(e=>[e,r[e]])):r;s.push({id:e.id,name:e.name,kind:e.kind,title:e.title,depth:t,tags:[...e.tags],metadata:i,childCount:n.length,incomingCount:[...e.incoming()].length,outgoingCount:[...e.outgoing()].length})}else l=!0;for(let e of n)f.push({element:e,depth:t+1})}return{root:{id:r.id,kind:r.kind,title:r.title,childCount:p.length},descendants:s,totalDescendants:c,truncated:l,truncatedByDepth:u}});function createMCPServer(e){let t=new He({name:`LikeC4`,version:Yn},{instructions:`LikeC4 MCP – query and navigate LikeC4 models.
1399
1402
 
1400
1403
  Conventions:
1401
1404
  - All tools are read-only and idempotent.
@@ -1428,14 +1431,14 @@ Instructions:
1428
1431
  - If response returns "sourceLocation", provide link to this location in the editor
1429
1432
 
1430
1433
  Full documentation: https://likec4.dev/llms-full.txt
1431
- `,enforceStrictCapabilities:!0,...t,capabilities:{tools:{},logging:{},...t?.capabilities}});return n.registerTool(...Xn(e)),n.registerTool(...lr(e)),n.registerTool(...cr(e)),n.registerTool(...sr(e)),n.registerTool(...dr(e)),n.registerTool(...pr(e)),n.registerTool(...Yn(e)),n.registerTool(...nr(e)),n.registerTool(...ir(e)),n.registerTool(...or(e)),n.registerTool(...Qn(e)),n.registerTool(...er(e)),n.registerTool(...Kn(e)),n.registerTool(...Hn(e)),n.registerTool(...$n(e)),n.registerTool(...Gn(e)),n.registerTool(...hr(e)),n.server.onerror=e=>{r.error(a(e))},n}var StdioLikeC4MCPServer=class{transport=void 0;_mcp=void 0;constructor(e){this.services=e}get mcp(){if(!this._mcp)throw Error(`MCP server is not started`);return this._mcp}get isStarted(){return this.transport!==void 0}get port(){return NaN}async dispose(){await this.stop()}async start(){this.transport||(Z.info(`Starting MCP stdio server`),this._mcp=createMCPServer(this.services),this.transport=new Le,await this._mcp.connect(this.transport),Z.info(`LikeC4 MCP Server running on stdio`))}async stop(){if(this.transport)try{Z.info(`Stopping MCP stdio server`),await this.transport.close(),this._mcp&&await this._mcp.close()}finally{this._mcp=void 0,this.transport=void 0}}};async function createHonoApp(e){let t=new Ue;t.use(`*`,ie({origin:`*`,allowHeaders:[`Content-Type`,`mcp-session-id`,`Last-Event-ID`,`mcp-protocol-version`],exposeHeaders:[`mcp-session-id`,`mcp-protocol-version`]})),t.get(`/health`,e=>e.json({status:`ok`}));let n=e(),r=new re({eventStore:new ae({})});return t.all(`/mcp`,async e=>(n.isConnected()||await n.connect(r),await r.handleRequest(e))),t.notFound(e=>(Z.debug(`${e.req.method} ${e.req.url} not found`),e.json({jsonrpc:`2.0`,error:{code:-32e3,message:`Method not found.`},id:null},{status:404}))),t.onError((e,t)=>(Z.error(a(e)),t.json({jsonrpc:`2.0`,error:{code:-32603,message:`Internal server error`},id:null},{status:500}))),t}async function startServer(e){let{factory:t,port:n}=e,r=await createHonoApp(t);return new Promise((e,t)=>{let i=We({fetch:r.fetch,hostname:`0.0.0.0`,port:n}).prependOnceListener(`error`,t).prependOnceListener(`listening`,()=>{i.removeListener(`error`,t),e(i.unref())})})}var StreamableLikeC4MCPServer=class{server=void 0;constructor(e,t=33335){this.services=e,this._port=t}get mcp(){throw Error(`StreamableLikeC4MCPServer has access to McpServer only during the request`)}get isStarted(){return this.server?.listening===!0}get port(){return this._port}async dispose(){await this.stop()}async start(e=this._port){if(this.server){if(this.port===e)return;await this.stop()}Z.info(`Starting MCP server on port {port}`,{port:e}),this._port=e,this.server=await startServer({factory:()=>createMCPServer(this.services),port:e}),Z.info(`MCP server ready at http://0.0.0.0:{port}/mcp`,{port:e})}stop(){let e=this.server;return e?(Z.info(`Stopping MCP server`),this.server=void 0,new Promise(t=>{e.close(e=>{e?Z.error(`Failed to stop MCP server`,{err:e}):Z.info(`MCP server stopped`),t()})})):(Z.info(`MCP server is not running, nothing to stop`),Promise.resolve())}};async function initLikeC4MCP(e){let t=h(e,{workspacePath:`.`,mcp:`stdio`,graphviz:`wasm`,watch:!0,throwIfInvalid:!1,configureLogger:!0});t.configureLogger&&(u({useStdErr:t.mcp===`stdio`,colors:S.isColorSupported&&t.mcp!==`stdio`,logLevel:Dt?`debug`:`info`}),process.on(`uncaughtException`,e=>{Z.error(`uncaughtException`,{err:e})}),process.on(`unhandledRejection`,e=>{Z.error(`unhandledRejection`,{err:e})}));let n=H(t.workspacePath);Z.info`Loading LikeC4 from workspace: ${n}`;let r=await l(n,{graphviz:t.graphviz,manualLayouts:!0,configureLogger:!1,watch:t.watch,throwIfInvalid:t.throwIfInvalid}),i=r.languageServices;return{server:t.mcp===`stdio`?new StdioLikeC4MCPServer(i):new StreamableLikeC4MCPServer(i,t.mcp.port),likec4:r}}async function startLikeC4MCP(e){let t=await initLikeC4MCP(e);return await t.server.start(),t}const mcpCmd=e=>e.command({command:`mcp [path]`,aliases:[],describe:`Start MCP server`,builder:e=>e.usage(`${S.bold(`Usage:`)} $0 mcp [path]`).positional(`path`,q).default(`path`,`.`,`current directory`).option(`stdio`,{boolean:!0,description:`use stdio transport`,conflicts:[`http`,`port`]}).option(`http`,{boolean:!0,description:`use streamable http transport (use 33335 port by default)`,conflicts:`stdio`}).option(`port`,{alias:`p`,number:!0,description:`enables http transport and sets the port`,conflicts:`stdio`}).option(`use-dot`,J).option(`log-level`,an).option(`verbose`,on).showHidden().epilog(`${S.bold(`Examples:`)}
1432
- ${S.green(`$0 mcp`)}
1433
- ${S.gray(`Start MCP with default stdio transport`)}
1434
- ${S.green(`$0 mcp --http ./src`)}
1435
- ${S.gray(`Start MCP with streamable http transport on port 33335 at ./src folder`)}
1436
- ${S.green(`$0 mcp -p 1234`)}
1437
- ${S.gray(`Start MCP with streamable http transport on port 1234`)}
1438
- `),handler:async e=>{e.http||e.port?(u({colors:S.isColorSupported,logLevel:e.verbose?sn:e.logLevel}),await startHttpMcp(e.path,e.useDot,e.port)):(u({useStdErr:!0,colors:!1,logLevel:e.verbose?sn:e.logLevel}),await startStdioMcp(e.path,e.useDot))}});async function startHttpMcp(e,t,n=33335){await startLikeC4MCP({workspacePath:e,mcp:{port:n},watch:!0,configureLogger:!1,graphviz:t?`binary`:`wasm`}),boxen([S.green(`LikeC4 MCP served at:`),`
1434
+ `,enforceStrictCapabilities:!0,capabilities:{completions:{},tools:{},logging:{},prompts:{},resources:{}}});return t.server.onerror=e=>{s.error(u(e))},ue(t,setMcpServerCtx,lr,Sr,xr,br,wr,Er,cr,ar,le(hr,_r,yr,dr,pr,fr),le(tr,ir,Or),le(applySemanticLayoutPrompt,applySemanticLayoutTool),projectResource)}var StdioLikeC4MCPServer=class{services;transport=void 0;_mcp=void 0;constructor(e){this.services=e}get mcp(){if(!this._mcp)throw Error(`MCP server is not started`);return this._mcp}get isStarted(){return this.transport!==void 0}get port(){return NaN}async dispose(){await this.stop()}async start(){this.transport||(Q.info(`Starting MCP stdio server`),this._mcp=createMCPServer(this.services),setMcpServerCtx(this._mcp),this.transport=new Le,await this._mcp.connect(this.transport),Q.info(`LikeC4 MCP Server running on stdio`))}async stop(){if(this.transport)try{Q.info(`Stopping MCP stdio server`),await this.transport.close(),this._mcp&&await this._mcp.close()}finally{this._mcp=void 0,this.transport=void 0,setMcpServerCtx(void 0)}}};async function createHonoApp(e){let t=new Je;t.use(`*`,re({origin:`*`,allowHeaders:[`Content-Type`,`mcp-session-id`,`Last-Event-ID`,`mcp-protocol-version`],exposeHeaders:[`mcp-session-id`,`mcp-protocol-version`]})),t.get(`/health`,e=>e.json({status:`ok`}));let n=e();setMcpServerCtx(n);let r=new D({eventStore:new ie({})});return t.all(`/mcp`,async e=>(n.isConnected()||await n.connect(r),await r.handleRequest(e))),t.notFound(e=>(Q.debug(`${e.req.method} ${e.req.url} not found`),e.json({jsonrpc:`2.0`,error:{code:-32e3,message:`Method not found.`},id:null},{status:404}))),t.onError((e,t)=>(Q.error(u(e)),t.json({jsonrpc:`2.0`,error:{code:-32603,message:`Internal server error`},id:null},{status:500}))),t}async function startServer(e){let{factory:t,port:n}=e,r=await createHonoApp(t);return new Promise((e,t)=>{let i=Ye({fetch:r.fetch,hostname:`0.0.0.0`,port:n}).prependOnceListener(`error`,t).prependOnceListener(`listening`,()=>{i.removeListener(`error`,t),e(i.unref())})})}var StreamableLikeC4MCPServer=class{services;_port;server=void 0;constructor(e,t=33335){this.services=e,this._port=t}get mcp(){throw Error(`StreamableLikeC4MCPServer has access to McpServer only during the request`)}get isStarted(){return this.server?.listening===!0}get port(){return this._port}async dispose(){await this.stop()}async start(e=this._port){if(this.server){if(this.port===e)return;await this.stop()}Q.info(`Starting MCP server on port {port}`,{port:e}),this._port=e,this.server=await startServer({factory:()=>createMCPServer(this.services),port:e}),Q.info(`MCP server ready at http://0.0.0.0:{port}/mcp`,{port:e})}stop(){let e=this.server;return e?(Q.info(`Stopping MCP server`),this.server=void 0,setMcpServerCtx(void 0),new Promise(t=>{e.close(e=>{e?Q.error(`Failed to stop MCP server`,{err:e}):Q.info(`MCP server stopped`),t()})})):(Q.info(`MCP server is not running, nothing to stop`),Promise.resolve())}};async function initLikeC4MCP(e){let t=h(e,{workspacePath:`.`,mcp:`stdio`,graphviz:`wasm`,watch:!0,throwIfInvalid:!1,configureLogger:!0});t.configureLogger&&(l({useStdErr:t.mcp===`stdio`,colors:C.isColorSupported&&t.mcp!==`stdio`,logLevel:Pt?`debug`:`info`}),process.on(`uncaughtException`,e=>{Q.error(`uncaughtException`,{err:e})}),process.on(`unhandledRejection`,e=>{Q.error(`unhandledRejection`,{err:e})}));let n=H(t.workspacePath);Q.info`Loading LikeC4 from workspace: ${n}`;let r=await c(n,{graphviz:t.graphviz,manualLayouts:!0,configureLogger:!1,watch:t.watch,throwIfInvalid:t.throwIfInvalid}),i=setLanguageServicesCtx(r.languageServices);return{server:t.mcp===`stdio`?new StdioLikeC4MCPServer(i):new StreamableLikeC4MCPServer(i,t.mcp.port),likec4:r}}async function startLikeC4MCP(e){let t=await initLikeC4MCP(e);return await t.server.start(),t}const mcpCmd=e=>e.command({command:`mcp [path]`,aliases:[],describe:`Start MCP server`,builder:e=>e.usage(`${C.bold(`Usage:`)} $0 mcp [path]`).positional(`path`,J).default(`path`,`.`,`current directory`).option(`stdio`,{boolean:!0,description:`use stdio transport`,conflicts:[`http`,`port`]}).option(`http`,{boolean:!0,description:`use streamable http transport (use 33335 port by default)`,conflicts:`stdio`}).option(`port`,{alias:`p`,number:!0,description:`enables http transport and sets the port`,conflicts:`stdio`}).option(`use-dot`,Y).option(`log-level`,hn).option(`verbose`,gn).showHidden().epilog(`${C.bold(`Examples:`)}
1435
+ ${C.green(`$0 mcp`)}
1436
+ ${C.gray(`Start MCP with default stdio transport`)}
1437
+ ${C.green(`$0 mcp --http ./src`)}
1438
+ ${C.gray(`Start MCP with streamable http transport on port 33335 at ./src folder`)}
1439
+ ${C.green(`$0 mcp -p 1234`)}
1440
+ ${C.gray(`Start MCP with streamable http transport on port 1234`)}
1441
+ `),handler:async e=>{e.http||e.port?(l({colors:C.isColorSupported,logLevel:e.verbose?_n:e.logLevel}),await startHttpMcp(e.path,e.useDot,e.port)):(l({useStdErr:!0,colors:!1,logLevel:e.verbose?_n:e.logLevel}),await startStdioMcp(e.path,e.useDot))}});async function startHttpMcp(e,t,n=33335){await startLikeC4MCP({workspacePath:e,mcp:{port:n},watch:!0,configureLogger:!1,graphviz:t?`binary`:`wasm`}),boxen([C.green(`LikeC4 MCP served at:`),`
1439
1442
  {
1440
1443
  "mcpServers": {
1441
1444
  "likec4": {
@@ -1444,18 +1447,18 @@ ${S.green(`$0 mcp -p 1234`)}
1444
1447
  }
1445
1448
  }
1446
1449
 
1447
- ${S.dim(`Documentation:`)}
1448
- ${S.underline(`https://likec4.dev/tooling/mcp/#using-extension`)}
1450
+ ${C.dim(`Documentation:`)}
1451
+ ${C.underline(`https://likec4.dev/tooling/mcp/#using-extension`)}
1449
1452
  `].join(`
1450
- `))}async function startStdioMcp(e,t){await startLikeC4MCP({workspacePath:e,mcp:`stdio`,watch:!0,configureLogger:!1,graphviz:t?`binary`:`wasm`})}async function vitePreview(e){let t=await viteConfig({...e,likec4AssetsDir:``,webcomponentPrefix:void 0}),n=await Ve({port:Be(62001,62010)}),r=e?.open??!1;return await zt({...t,customLogger:t.customLogger,mode:`production`,preview:{host:e.listen??`127.0.0.1`,allowedHosts:!0,port:n,open:r}})}async function handler$1({path:e,output:t,base:n,listen:r}){printServerUrls(await vitePreview({base:n,languageServices:await l(e,{watch:!1}),outputDir:t,open:!O(),listen:r}))}t(handler$1,`handler`);const previewCmd=e=>e.command({command:`preview [path]`,describe:`Start local server to preview production build`,builder:e=>e.positional(`path`,{type:`string`,desc:`Directory with LikeC4 source files
1451
- if not specified search in current directory`,normalize:!0}).options({output:{alias:`o`,type:`string`,desc:`output directory from production build`,normalize:!0},base:{type:`string`,desc:`base url the app is being served from`},listen:{alias:`l`,type:`string`,desc:`ip address of the network interface to listen on`}}).coerce([`path`,`output`],H).default(`path`,H(`.`),`.`).default(`listen`,`127.0.0.1`,`localhost`),handler:async e=>{await handler$1(e)}});async function handler({path:e,useDotBin:t,webcomponentPrefix:n,title:r,useHashHistory:i,enableWebcomponent:a=!0,enableHMR:s=!0,base:c,listen:u,port:f}){s&&(process.env.NODE_ENV=`development`);let p=await viteDev({buildWebcomponent:a,hmr:s,base:c,webcomponentPrefix:n,title:r,languageServices:await l(e,{graphviz:t?`binary`:`wasm`,watch:s}),useHashHistory:i,likec4AssetsDir:await _t(B(ut(),`.likec4-assets-`)),listen:u,port:f});p.config.logger.clearScreen(`info`),printServerUrls(p),Ut(showSupportUsMessage,1e3).unref()}const serveCmd=e=>e.command({command:`start [path]`,aliases:[`serve`,`dev`],describe:`Start local dev server to preview LikeC4 views`,builder:e=>e.positional(`path`,q).option(`base`,en).option(`webcomponent-prefix`,Zt).option(`title`,Qt).option(`use-hash-history`,Xt).option(`use-dot`,J).option(`listen`,nn).option(`port`,rn).options({"react-hmr":{type:`boolean`,default:!0,describe:`Enable/Disable React HMR`},"build-webcomponent":{type:`boolean`,default:!0,describe:`Enable/Disable Webcomponent build`}}),handler:async e=>{await ensureReact(),await handler({path:e.path,useDotBin:e[`use-dot`],base:e.base,webcomponentPrefix:e[`webcomponent-prefix`],title:e.title,useHashHistory:e[`use-hash-history`],listen:e.listen,port:e.port,enableHMR:e[`react-hmr`],enableWebcomponent:e[`build-webcomponent`]})}});async function runSyncPlan(e,t,n,r){let i=await planSyncToLeanix(t,n,{idempotent:!0}),a=H(e,`sync-plan.json`);if(await G(a,JSON.stringify(i,null,2)),r.info(`${S.dim(`generated`)} ${V(process.cwd(),a)}`),i.errors.length>0){let e=`${i.errors.length} plan error(s): ${i.errors.join(`; `)}`;throw r.error(e),Error(e)}}async function runSyncApply(e,t,n,r){let i=await syncToLeanix(t.manifest,t.dryRun,n,{idempotent:!0}),a=H(e,Dn.manifest);if(await G(a,JSON.stringify(i.manifest,null,2)),r.info(`${S.dim(`generated`)} ${V(process.cwd(),a)} (after sync)`),i.errors.length>0){let e=`${i.errors.length} sync error(s): ${i.errors.join(`; `)}`;throw r.error(e),Error(e)}}async function runSyncLeanix(e){let t=createLikeC4Logger(`c4:sync:leanix`),n=startTimer(t),{path:r,outdir:i,project:a,useDotBin:s,dryRun:c,apply:u}=e;try{try{var f=_usingCtx();if(c&&u)throw Error(`Choose either dryRun or apply, not both`);let e=f.a(await l(r,{graphviz:s?`binary`:`wasm`,watch:!1})),{projectId:n}=ensureProject(e,a);a&&t.info(`${S.dim(`project`)} ${S.green(n)}`);let p=await e.layoutedModel(n);if(p===Oe.EMPTY)throw t.error(xn),Error(xn);let m=buildBridgeArtifacts(asBridgeModel(p));await writeBridgeArtifacts(i,m,t);let h=createLeanixClientFromEnv();if((c||!u)&&(h?await runSyncPlan(i,m.dryRun,h,t):t.info(`${S.dim(`skip`)} sync-plan (set LEANIX_API_TOKEN to include plan)`)),u){if(!h)throw t.error(Sn),Error(Sn);await runSyncApply(i,m,h,t)}}catch(e){f.e=e}finally{await f.d()}}finally{n.stopAndLog()}}const gr=H(process.cwd(),`out`,`bridge`);function isSyncCmdArgs(e){return typeof e!=`object`||!e||!Object.hasOwn(e,`target`)?!1:typeof Reflect.get(e,`target`)==`string`}function syncCmd(e){return e.command({command:`sync <target> [path]`,describe:`Sync bridge artifacts (e.g. LeanIX)`,builder:e=>e.positional(`target`,{type:`string`,choices:[`leanix`],describe:`Target system (leanix)`}).positional(`path`,q).option(`outdir`,{...Y,default:gr,desc:`<dir> output directory for bridge artifacts (manifest, leanix-dry-run, report, sync-plan)`}).option(`dry-run`,{type:`boolean`,describe:`Only write artifacts and optional sync-plan; do not call LeanIX API for create/update`}).option(`apply`,{type:`boolean`,describe:`Run live sync to LeanIX (requires LEANIX_API_TOKEN)`}).conflicts(`dry-run`,`apply`).option(`project`,X).option(`use-dot`,J).example(`${S.green(`$0 sync leanix --dry-run -o out/bridge`)}`,S.gray(`Write bridge artifacts and optionally sync-plan when LEANIX_API_TOKEN is set`)).example(`${S.green(`$0 sync leanix --apply -o out/bridge`)}`,S.gray(`Write artifacts then run live sync; updates manifest with LeanIX IDs`)),handler:async e=>{if(!isSyncCmdArgs(e)||e.target!==`leanix`)return;let t=e.apply??!1,n=e.dryRun??!t;await runSyncLeanix({path:e.path??`.`,outdir:e.outdir??gr,project:e.project,useDotBin:e.useDotBin??!1,dryRun:n,apply:t})}})}const validateCmd=e=>e.command({command:`validate [path]`,aliases:[],describe:`Validate syntax, semantics and layout drifts`,builder:e=>e.positional(`path`,q).options({project:X,file:{alias:`f`,array:!0,string:!0,description:`only report errors from these files (can be specified multiple times)`},layout:{boolean:!0,default:!0,defaultDescription:`enabled`,description:`force layout validation, or disable with --no-layout`},json:{boolean:!0,nargs:0,description:`output as JSON (structured)`}}).showHidden().epilog(`${S.bold(`Examples:`)}
1452
- ${S.green(`$0 validate `)}
1453
- ${S.gray(`Validate all in the current directory`)}
1454
-
1455
- ${S.green(`$0 validate --no-layout --json -f ./src/model.c4 -f ./src/deployment.c4 `)}
1456
- ${S.gray([`Validate all`,`ignore layout drifts`,`report only errors from these files`,`output as JSON`].join(`, `))}
1457
-
1458
- ${S.green(`$0 validate --project my-project /some/where`)}
1459
- ${S.gray(`Validate my-project in /some/where`)}
1460
- `),handler:async e=>{try{var t=_usingCtx();let n=createLikeC4Logger(`c4:validate`),r=startTimer(n),i=e.json===!0,a=e.layout===!0,s=e.file?.map(e=>H(e))??null,c=t.a(await l(e.path,{watch:!1,printErrors:!i,throwIfInvalid:!1,configureLogger:i?`stderr`:!1})),u=c.getErrors().map(e=>({message:e.message,file:e.sourceFsPath,line:e.line,range:e.range})),f=[];if(a){n.debug(`running layout validation...`);try{let t=await c.diagrams(e.project);for(let n of t)n.drifts&&n.drifts.length>0&&f.push({message:`Layout drift detected on view '${n.id}'`,file:n.sourcePath?H(e.path,n.sourcePath):``,line:0,range:null})}catch(e){f.push({message:`Layout validation failed: ${e instanceof Error?e.message:String(e)}`,file:``,line:0,range:null})}}let p=[...u,...f],m=c.documentCount(),h=p.length,g=s?p.filter(e=>s.some(t=>e.file===t||e.file.endsWith(`/`+t)||e.file.endsWith(`\\`+t))):p,_=new Set(g.map(e=>e.file)),v=g.length===0;process.exitCode=+!v;let y={valid:v,errors:g,stats:{totalFiles:m,totalErrors:h,filteredFiles:s?_.size:m,filteredErrors:g.length}};if(i){console.log(JSON.stringify(y,null,2));return}for(let e of f)n.error(S.red(e.message)+(e.file?` at `+e.file:``));if(v)n.info(S.green(`✓ Valid`)+S.dim(` (${m} files)`));else{let e=s?`, ${g.length} in filtered files`:``;n.error(S.red(`✗ Invalid`)+S.dim(` (${m} files, ${h} errors${e})`))}r.stopAndLog(`validate `)}catch(e){t.e=e}finally{await t.d()}}});function applyLoggerConfig(e){let t=e??(Dt?`debug`:`info`);p({reset:!0,sinks:{console:c({formatter:S.isColorSupported?m():i()})},loggers:[{category:`likec4`,sinks:[`console`],lowestLevel:t}]})}async function main(){!Ot&&!Et&&!O()&&await notifyAvailableUpdate(),await le(Ft(It(At)),serveCmd,buildCmd,codegenCmd,exportCmd,formatCmd,previewCmd,syncCmd,validateCmd,listIconsCmd,mcpCmd,lsp_default,checkUpdateCmd,e=>e.command({command:`completion`,describe:`Generate completion script`,handler:()=>{e.showCompletionScript()}})).scriptName(`likec4`).usage(`Usage: $0 <command>`).version(Gt).alias(`v`,`version`).alias(`h`,`help`).help(`help`).option(`log-level`,an).option(`verbose`,on).option(`color`,{boolean:!0,describe:[`force color output, or disable with --no-color`,`respects 'FORCE_COLOR' and 'NO_COLOR' env variables`].join(`
1461
- `),skipValidation:!0,hidden:!0,global:!0}).group([`log-level`,`verbose`,`color`,`help`,`version`,`show-hidden`],`Globals:`).demandCommand(1,`Please run with valid command`).recommendCommands().showHelpOnFail(!0).showHidden().updateStrings({"Globals:":S.bold(`Globals:`),"Options:":S.bold(`Options:`),"Positionals:":S.bold(`Arguments:`),"Commands:":S.bold(`Commands:`),"Examples:":S.bold(`Examples:`)}).wrap(de(Pt.columns-10,{min:60,max:180})).middleware(e=>{applyLoggerConfig(e.verbose?sn:e.logLevel)}).parseAsync()}function exitWithFailure(e,t){console.error(t==null?a(e):`${t} ${a(e)}`),Mt(1)}main().catch(exitWithFailure),process.on(`unhandledRejection`,e=>{exitWithFailure(e,`Unhandled rejection:`)}),process.on(`uncaughtException`,e=>{console.error(e)});export{};
1453
+ `))}async function startStdioMcp(e,t){await startLikeC4MCP({workspacePath:e,mcp:`stdio`,watch:!0,configureLogger:!1,graphviz:t?`binary`:`wasm`})}async function vitePreview(e){let t=await viteConfig({...e,likec4AssetsDir:``,webcomponentPrefix:void 0}),n=await Ge({port:We(62001,62010)}),r=e?.open??!1;return await Kt({...t,customLogger:t.customLogger,mode:`production`,preview:{host:e.listen??`127.0.0.1`,allowedHosts:!0,port:n,open:r}})}async function handler$1({path:e,output:t,base:n,listen:r}){printServerUrls(await vitePreview({base:n,languageServices:await c(e,{watch:!1}),outputDir:t,open:!k(),listen:r}))}t(handler$1,`handler`);const previewCmd=e=>e.command({command:`preview [path]`,describe:`Start local server to preview production build`,builder:e=>e.positional(`path`,{type:`string`,desc:`Directory with LikeC4 source files
1454
+ if not specified search in current directory`,normalize:!0}).options({output:{alias:`o`,type:`string`,desc:`output directory from production build`,normalize:!0},base:{type:`string`,desc:`base url the app is being served from`},listen:{alias:`l`,type:`string`,desc:`ip address of the network interface to listen on`}}).coerce([`path`,`output`],H).default(`path`,H(`.`),`.`).default(`listen`,`127.0.0.1`,`localhost`),handler:async e=>{await handler$1(e)}});async function handler({path:e,useDotBin:t,webcomponentPrefix:n,title:r,useHashHistory:i,enableWebcomponent:a=!0,enableHMR:s=!0,base:l,listen:u,port:f,hmrPort:p,userPublicDir:m,allowedHosts:h}){s&&(process.env.NODE_ENV=`development`);let g=await viteDev({buildWebcomponent:a,hmr:s,base:l,webcomponentPrefix:n,title:r,languageServices:await c(e,{graphviz:t?`binary`:`wasm`,watch:s}),useHashHistory:i,likec4AssetsDir:await wt(B(gt(),`.likec4-assets-`)),listen:u,port:f,hmrPort:p,userPublicDir:m,allowedHosts:h});g.config.logger.clearScreen(`info`),printServerUrls(g),Xt(showSupportUsMessage,1e3).unref()}const serveCmd=e=>e.command({command:`start [path]`,aliases:[`serve`,`dev`],describe:`Start local dev server to preview LikeC4 views`,builder:e=>e.positional(`path`,J).option(`base`,cn).option(`webcomponent-prefix`,an).option(`title`,on).option(`use-hash-history`,rn).option(`use-dot`,Y).option(`listen`,fn).option(`port`,pn).option(`hmr-port`,mn).option(`public`,un).option(`allowed-host`,dn).options({"react-hmr":{type:`boolean`,default:!0,describe:`Enable/Disable React HMR`},"build-webcomponent":{type:`boolean`,default:!0,describe:`Enable/Disable Webcomponent build`}}),handler:async e=>{await ensureReact(),await handler({path:e.path,useDotBin:e[`use-dot`],base:e.base,webcomponentPrefix:e[`webcomponent-prefix`],title:e.title,useHashHistory:e[`use-hash-history`],listen:e.listen,port:e.port,hmrPort:e[`hmr-port`],enableHMR:e[`react-hmr`],enableWebcomponent:e[`build-webcomponent`],userPublicDir:e.public,allowedHosts:e[`allowed-host`]})}});async function runSyncPlan(e,t,n,r){let i=await planSyncToLeanix(t,n,{idempotent:!0}),a=H(e,`sync-plan.json`);if(await K(a,JSON.stringify(i,null,2)),r.info(`${C.dim(`generated`)} ${V(process.cwd(),a)}`),i.errors.length>0){let e=`${i.errors.length} plan error(s): ${i.errors.join(`; `)}`;throw r.error(e),Error(e)}}async function runSyncApply(e,t,n,r){let i=await syncToLeanix(t.manifest,t.dryRun,n,{idempotent:!0}),a=H(e,Ln.manifest);if(await K(a,JSON.stringify(i.manifest,null,2)),r.info(`${C.dim(`generated`)} ${V(process.cwd(),a)} (after sync)`),i.errors.length>0){let e=`${i.errors.length} sync error(s): ${i.errors.join(`; `)}`;throw r.error(e),Error(e)}}async function runSyncLeanix(e){let t=createLikeC4Logger(`c4:sync:leanix`),n=startTimer(t),{path:r,outdir:i,project:a,useDotBin:s,dryRun:l,apply:u}=e;try{try{var f=_usingCtx();if(l&&u)throw Error(`Choose either dryRun or apply, not both`);let e=f.a(await c(r,{graphviz:s?`binary`:`wasm`,watch:!1})),{projectId:n}=ensureProject(e,a);a&&t.info(`${C.dim(`project`)} ${C.green(n)}`);let p=await e.layoutedModel(n);if(p===Me.EMPTY)throw t.error(jn),Error(jn);let m=buildBridgeArtifacts(asBridgeModel(p));await writeBridgeArtifacts(i,m,t);let h=createLeanixClientFromEnv();if((l||!u)&&(h?await runSyncPlan(i,m.dryRun,h,t):t.info(`${C.dim(`skip`)} sync-plan (set LEANIX_API_TOKEN to include plan)`)),u){if(!h)throw t.error(Mn),Error(Mn);await runSyncApply(i,m,h,t)}}catch(e){f.e=e}finally{await f.d()}}finally{n.stopAndLog()}}const kr=H(process.cwd(),`out`,`bridge`);function isSyncCmdArgs(e){return typeof e!=`object`||!e||!Object.hasOwn(e,`target`)?!1:typeof Reflect.get(e,`target`)==`string`}function syncCmd(e){return e.command({command:`sync <target> [path]`,describe:`Sync bridge artifacts (e.g. LeanIX)`,builder:e=>e.positional(`target`,{type:`string`,choices:[`leanix`],describe:`Target system (leanix)`}).positional(`path`,J).option(`outdir`,{...X,default:kr,desc:`<dir> output directory for bridge artifacts (manifest, leanix-dry-run, report, sync-plan)`}).option(`dry-run`,{type:`boolean`,describe:`Only write artifacts and optional sync-plan; do not call LeanIX API for create/update`}).option(`apply`,{type:`boolean`,describe:`Run live sync to LeanIX (requires LEANIX_API_TOKEN)`}).conflicts(`dry-run`,`apply`).option(`project`,Z).option(`use-dot`,Y).example(`${C.green(`$0 sync leanix --dry-run -o out/bridge`)}`,C.gray(`Write bridge artifacts and optionally sync-plan when LEANIX_API_TOKEN is set`)).example(`${C.green(`$0 sync leanix --apply -o out/bridge`)}`,C.gray(`Write artifacts then run live sync; updates manifest with LeanIX IDs`)),handler:async e=>{if(!isSyncCmdArgs(e)||e.target!==`leanix`)return;let t=e.apply??!1,n=e.dryRun??!t;await runSyncLeanix({path:e.path??`.`,outdir:e.outdir??kr,project:e.project,useDotBin:e.useDotBin??!1,dryRun:n,apply:t})}})}const validateCmd=e=>e.command({command:`validate [path]`,aliases:[],describe:`Validate syntax, semantics and layout drifts`,builder:e=>e.positional(`path`,J).options({project:Z,file:{alias:`f`,array:!0,string:!0,description:`only report errors from these files (can be specified multiple times)`},layout:{boolean:!0,default:!0,defaultDescription:`enabled`,description:`force layout validation, or disable with --no-layout`},json:{boolean:!0,nargs:0,description:`output as JSON (structured)`}}).showHidden().epilog(`${C.bold(`Examples:`)}
1455
+ ${C.green(`$0 validate `)}
1456
+ ${C.gray(`Validate all in the current directory`)}
1457
+
1458
+ ${C.green(`$0 validate --no-layout --json -f ./src/model.c4 -f ./src/deployment.c4 `)}
1459
+ ${C.gray([`Validate all`,`ignore layout drifts`,`report only errors from these files`,`output as JSON`].join(`, `))}
1460
+
1461
+ ${C.green(`$0 validate --project my-project /some/where`)}
1462
+ ${C.gray(`Validate my-project in /some/where`)}
1463
+ `),handler:async e=>{try{var t=_usingCtx();let n=createLikeC4Logger(`c4:validate`),r=startTimer(n),i=e.json===!0,a=e.layout===!0,s=e.file?.map(e=>H(e))??null,l=t.a(await c(e.path,{watch:!1,printErrors:!i,throwIfInvalid:!1,configureLogger:i?`stderr`:!1})),u=l.getErrors().map(e=>({message:e.message,file:e.sourceFsPath,line:e.line,range:e.range})),f=[];if(a){n.debug(`running layout validation...`);try{let t=await l.diagrams(e.project);for(let n of t)n.drifts&&n.drifts.length>0&&f.push({message:`Layout drift detected on view '${n.id}'`,file:n.sourcePath?H(e.path,n.sourcePath):``,line:0,range:null})}catch(e){f.push({message:`Layout validation failed: ${e instanceof Error?e.message:String(e)}`,file:``,line:0,range:null})}}let p=[...u,...f],m=l.documentCount(),h=p.length,g=s?p.filter(e=>s.some(t=>e.file===t||e.file.endsWith(`/`+t)||e.file.endsWith(`\\`+t))):p,_=new Set(g.map(e=>e.file)),v=g.length===0;process.exitCode=+!v;let y={valid:v,errors:g,stats:{totalFiles:m,totalErrors:h,filteredFiles:s?_.size:m,filteredErrors:g.length}};if(i){console.log(JSON.stringify(y,null,2));return}for(let e of f)n.error(C.red(e.message)+(e.file?` at `+e.file:``));if(v)n.info(C.green(`✓ Valid`)+C.dim(` (${m} files)`));else{let e=s?`, ${g.length} in filtered files`:``;n.error(C.red(`✗ Invalid`)+C.dim(` (${m} files, ${h} errors${e})`))}r.stopAndLog(`validate `)}catch(e){t.e=e}finally{await t.d()}}});function applyLoggerConfig(e){let t=e??(Pt?`debug`:`info`);p({reset:!0,sinks:{console:m({formatter:C.isColorSupported?r():i()})},loggers:[{category:`likec4`,sinks:[`console`],lowestLevel:t}]})}async function main(){!Ft&&!Nt&&!k()&&await notifyAvailableUpdate(),await ue(Ht(Ut(Lt)),serveCmd,buildCmd,codegenCmd,exportCmd,formatCmd,previewCmd,syncCmd,validateCmd,listIconsCmd,mcpCmd,lsp_default,checkUpdateCmd,e=>e.command({command:`completion`,describe:`Generate completion script`,handler:()=>{e.showCompletionScript()}})).scriptName(`likec4`).usage(`Usage: $0 <command>`).parserConfiguration({"greedy-arrays":!1}).version(Qt).alias(`v`,`version`).alias(`h`,`help`).help(`help`).option(`log-level`,hn).option(`verbose`,gn).option(`color`,{boolean:!0,describe:[`force color output, or disable with --no-color`,`respects 'FORCE_COLOR' and 'NO_COLOR' env variables`].join(`
1464
+ `),skipValidation:!0,hidden:!0,global:!0}).group([`log-level`,`verbose`,`color`,`help`,`version`,`show-hidden`],`Globals:`).demandCommand(1,`Please run with valid command`).recommendCommands().showHelpOnFail(!0).showHidden().updateStrings({"Globals:":C.bold(`Globals:`),"Options:":C.bold(`Options:`),"Positionals:":C.bold(`Arguments:`),"Commands:":C.bold(`Commands:`),"Examples:":C.bold(`Examples:`)}).wrap(fe(Vt.columns-10,{min:60,max:180})).middleware(e=>{applyLoggerConfig(e.verbose?_n:e.logLevel)}).parseAsync()}function exitWithFailure(e,t){console.error(t==null?u(e):`${t} ${u(e)}`),zt(1)}main().catch(exitWithFailure),process.on(`unhandledRejection`,e=>{exitWithFailure(e,`Unhandled rejection:`)}),process.on(`uncaughtException`,e=>{console.error(e)});export{};