likec4 1.53.0 → 1.55.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 (41) hide show
  1. package/__app__/src/likec4.js +9 -5
  2. package/__app__/src/routes/index.js +2 -2
  3. package/__app__/src/style.css +1 -1
  4. package/__app__/src/vendors.js +4023 -2281
  5. package/config/schema.json +77 -92
  6. package/dist/THIRD-PARTY-LICENSES.md +3 -69
  7. package/dist/_chunks/index.d.mts +1 -1
  8. package/dist/_chunks/index2.d.mts +10 -20
  9. package/dist/_chunks/libs/@chevrotain/cst-dts-gen.mjs +7 -7
  10. package/dist/_chunks/libs/@hono/mcp.mjs +35 -24
  11. package/dist/_chunks/libs/@hono/node-server.mjs +1 -1
  12. package/dist/_chunks/libs/@logtape/logtape.d.mts +3 -3
  13. package/dist/_chunks/libs/@logtape/logtape.mjs +3 -3
  14. package/dist/_chunks/libs/@modelcontextprotocol/sdk.mjs +8 -8
  15. package/dist/_chunks/libs/@nanostores/react.d.mts +22 -17
  16. package/dist/_chunks/libs/@nanostores/react.mjs +1 -1
  17. package/dist/_chunks/libs/ajv.mjs +1 -1
  18. package/dist/_chunks/libs/atomically.mjs +1 -1
  19. package/dist/_chunks/libs/conf.mjs +1 -1
  20. package/dist/_chunks/libs/defu.mjs +1 -1
  21. package/dist/_chunks/libs/find-up-simple.mjs +1 -1
  22. package/dist/_chunks/libs/p-timeout.mjs +1 -0
  23. package/dist/_chunks/libs/package-manager-detector.mjs +1 -1
  24. package/dist/_chunks/libs/pathe.mjs +1 -1
  25. package/dist/_chunks/libs/picomatch.mjs +1 -1
  26. package/dist/_chunks/libs/tinyrainbow.mjs +1 -1
  27. package/dist/_chunks/libs/zod.d.mts +2091 -0
  28. package/dist/_chunks/node.mjs +76 -1
  29. package/dist/_chunks/src2.mjs +69 -69
  30. package/dist/cli/index.mjs +1228 -97
  31. package/dist/config/index.d.mts +1 -1
  32. package/dist/index.d.mts +1 -1
  33. package/dist/index.mjs +1 -1
  34. package/dist/vite-plugin/index.d.mts +1 -1
  35. package/dist/vite-plugin/index.mjs +1 -1
  36. package/dist/vite-plugin/internal.mjs +1 -1
  37. package/package.json +32 -31
  38. package/react/index.d.mts +6 -0
  39. package/react/index.mjs +55 -37
  40. package/dist/_chunks/filesystem.mjs +0 -1231
  41. package/dist/_chunks/libs/@modelcontextprotocol/sdk.d.mts +0 -8725
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import{s as e}from"../_chunks/rolldown-runtime.mjs";import"../_chunks/libs/birpc.mjs";import{$ as t,C as n,K as r,W as i,Y as a,Z as o,k as s,m as c,t as l,w as u}from"../_chunks/libs/remeda.mjs";import"../_chunks/libs/@logtape/logtape.mjs";import"../_chunks/libs/merge-error-cause.mjs";import"../_chunks/libs/is-error-instance.mjs";import"../_chunks/libs/is-plain-obj.mjs";import"../_chunks/libs/safe-stringify.mjs";import{_ as d,b as f,g as p,n as m,u as h,v as g,x as _,y as v}from"../_chunks/filesystem.mjs";import"../_chunks/libs/defu.mjs";import"../_chunks/libs/pathe.mjs";import{t as y}from"../_chunks/libs/tinyrainbow.mjs";import"../_chunks/libs/json5.mjs";import"../_chunks/libs/@hono/mcp.mjs";import"../_chunks/src.mjs";import{H as b,V as x}from"../_chunks/libs/langium.mjs";import"../_chunks/libs/@chevrotain/regexp-to-ast.mjs";import"../_chunks/libs/chevrotain.mjs";import"../_chunks/libs/@chevrotain/cst-dts-gen.mjs";import"../_chunks/libs/@chevrotain/utils.mjs";import"../_chunks/libs/chevrotain-allstar.mjs";import"../_chunks/sequence.mjs";import"../_chunks/libs/@lume/kiwi.mjs";import"../_chunks/libs/ts-graphviz.mjs";import"../_chunks/libs/word-wrap.mjs";import"../_chunks/libs/khroma.mjs";import"../_chunks/libs/p-limit.mjs";import"../_chunks/libs/eventemitter3.mjs";import"../_chunks/libs/p-queue.mjs";import"../_chunks/libs/isexe.mjs";import"../_chunks/libs/which.mjs";import"../_chunks/libs/parse-ms.mjs";import{t as S}from"../_chunks/libs/pretty-ms.mjs";import{t as ee}from"../_chunks/libs/picomatch.mjs";import{c as te,l as ne,o as re,r as ie,s as ae}from"../_chunks/libs/ufo.mjs";import"../_chunks/libs/@modelcontextprotocol/sdk.mjs";import"../_chunks/libs/@hono/node-server.mjs";import"../_chunks/libs/fast-equals.mjs";import{n as oe}from"../_chunks/libs/strip-indent.mjs";import"../_chunks/libs/destr.mjs";import"../_chunks/libs/unstorage.mjs";import{a as se,c as ce,d as le,f as C,i as ue,l as de,n as fe,o as pe,r as me,s as he,t as ge,u as _e}from"../_chunks/src2.mjs";import"../_chunks/libs/pako.mjs";import{LikeC4Model as w}from"../model/index.mjs";import"../_chunks/libs/is-docker.mjs";import{t as T}from"../_chunks/libs/is-inside-container.mjs";import"../_chunks/libs/ansi-regex.mjs";import{t as ve}from"../_chunks/libs/boxen.mjs";import"../_chunks/libs/ansi-align.mjs";import"../_chunks/libs/ansi-styles.mjs";import"../_chunks/libs/find-up-simple.mjs";import{t as ye}from"../_chunks/libs/package-up.mjs";import{n as be,t as xe}from"../_chunks/libs/package-manager-detector.mjs";import{t as Se}from"../_chunks/libs/esm-env.mjs";import{n as Ce,t as we}from"../_chunks/libs/conf.mjs";import"../_chunks/libs/atomically.mjs";import"../_chunks/libs/ajv.mjs";import{t as Te}from"../_chunks/libs/ky.mjs";import{n as Ee}from"../_chunks/node.mjs";import{n as De,t as Oe}from"../_chunks/libs/get-port.mjs";import{t as ke}from"../_chunks/libs/vscode-languageserver.mjs";import Ae from"node:module";import{isDeploymentElementModel as je,isDeploymentRelationModel as Me,isElementModel as Ne,isLikeC4ViewModel as Pe,isRelationModel as Fe}from"@likec4/core/model";import{invariant as Ie,nonexhaustive as Le}from"@likec4/core";import Re from"nano-spawn";import{tmpdir as ze}from"node:os";import{resolve as E}from"path";import{env as Be,isCI as Ve,isDevelopment as He,isProduction as Ue,isTest as We,nodeENV as Ge}from"std-env";import{copyFile as Ke,mkdir as D,mkdtemp as qe,readFile as O,readdir as Je,realpath as Ye,rm as Xe,stat as Ze,writeFile as k}from"node:fs/promises";import{basename as Qe,dirname as A,extname as j,isAbsolute as $e,join as M,relative as N,resolve as P,sep as et}from"node:path";import{copyFileSync as tt,existsSync as F,readFileSync as nt,readdirSync as rt,rmSync as it,statSync as at}from"node:fs";import{argv as ot,cwd as I,exit as st,hrtime as ct,stdout as lt}from"node:process";import ut from"yargs";import{hideBin as dt}from"yargs/helpers";import{fileURLToPath as L,pathToFileURL as ft}from"node:url";import pt from"@vitejs/plugin-react";import{viteSingleFile as mt}from"vite-plugin-singlefile";import{build as R,createServer as ht,preview as gt}from"vite";import{setTimeout as _t}from"node:timers/promises";import{setTimeout as vt}from"node:timers";var yt=`likec4`,bt=`1.53.0`;const z=d.getChild(`cli`);function B(e){let t=d.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(`${y.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(`${y.red(r.name+` `+r.message)}`,{error:r});return}t.error(y.red(e),{error:r});return}if(typeof e==`string`){t.error(y.red(e));return}t.error`${e}`},clearScreen:function(e){},hasErrorLogged:function(e){return!1},hasWarned:!1}}function xt(e){let[t,n]=ct(e),r=t*1e3+n/1e6;return{ms:r,pretty:S(r)}}function V(e){let t=ct();return{stopAndLog(n=`done in `){n=y.green(`${n}${xt(t).pretty}`),(e||z).info(n)}}}function H(e,t){console.log(ve(e,{padding:1,margin:1,dimBorder:!0,...t}))}const St=B(`vite`),Ct=A(L(import.meta.url)),wt={banner:`/* prettier-ignore-start */
2
+ import{s as e}from"../_chunks/rolldown-runtime.mjs";import"../_chunks/libs/birpc.mjs";import{$ as t,C as n,K as r,W as i,Y as a,Z as o,k as s,m as c,t as l,w as u,x as d}from"../_chunks/libs/remeda.mjs";import"../_chunks/libs/@logtape/logtape.mjs";import"../_chunks/libs/merge-error-cause.mjs";import"../_chunks/libs/is-error-instance.mjs";import"../_chunks/libs/is-plain-obj.mjs";import"../_chunks/libs/safe-stringify.mjs";import{a as f,c as p,d as m,f as h,i as g,l as _,n as v,o as y,r as ee,s as b,u as te}from"../_chunks/node.mjs";import{t as ne}from"../_chunks/libs/defu.mjs";import{H as re,V as ie}from"../_chunks/libs/langium.mjs";import"../_chunks/libs/@chevrotain/regexp-to-ast.mjs";import"../_chunks/libs/chevrotain.mjs";import"../_chunks/libs/@chevrotain/cst-dts-gen.mjs";import"../_chunks/libs/@chevrotain/utils.mjs";import"../_chunks/libs/chevrotain-allstar.mjs";import{t as x}from"../_chunks/libs/tinyrainbow.mjs";import{c as ae,l as oe,o as se,r as ce,s as le}from"../_chunks/libs/ufo.mjs";import"../_chunks/libs/json5.mjs";import{i as ue,n as de,r as fe,t as pe}from"../_chunks/libs/@hono/mcp.mjs";import"../_chunks/src.mjs";import"../_chunks/libs/pathe.mjs";import"../_chunks/sequence.mjs";import"../_chunks/libs/@lume/kiwi.mjs";import"../_chunks/libs/ts-graphviz.mjs";import"../_chunks/libs/word-wrap.mjs";import"../_chunks/libs/khroma.mjs";import"../_chunks/libs/p-limit.mjs";import"../_chunks/libs/eventemitter3.mjs";import"../_chunks/libs/p-queue.mjs";import"../_chunks/libs/isexe.mjs";import"../_chunks/libs/which.mjs";import"../_chunks/libs/parse-ms.mjs";import{t as me}from"../_chunks/libs/pretty-ms.mjs";import{t as he}from"../_chunks/libs/picomatch.mjs";import"../_chunks/libs/p-timeout.mjs";import"../_chunks/libs/fast-equals.mjs";import{n as ge}from"../_chunks/libs/strip-indent.mjs";import"../_chunks/libs/destr.mjs";import"../_chunks/libs/unstorage.mjs";import{a as _e,c as ve,d as ye,i as be,l as xe,n as Se,o as Ce,r as we,s as Te,t as Ee,u as De}from"../_chunks/src2.mjs";import"../_chunks/libs/pako.mjs";import{LikeC4Model as Oe}from"../model/index.mjs";import"../_chunks/libs/is-docker.mjs";import{t as S}from"../_chunks/libs/is-inside-container.mjs";import"../_chunks/libs/ansi-regex.mjs";import{t as ke}from"../_chunks/libs/boxen.mjs";import"../_chunks/libs/ansi-align.mjs";import"../_chunks/libs/ansi-styles.mjs";import"../_chunks/libs/find-up-simple.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{t as Ne}from"../_chunks/libs/esm-env.mjs";import{n as Pe,t as Fe}from"../_chunks/libs/conf.mjs";import"../_chunks/libs/atomically.mjs";import{a as C,c as w,d as T,f as Ie,i as Le,l as E,n as D,o as Re,p as ze,r as O,s as k,t as Be,u as A}from"../_chunks/libs/@modelcontextprotocol/sdk.mjs";import"../_chunks/libs/ajv.mjs";import{t as Ve}from"../_chunks/libs/ky.mjs";import{n as He,t as Ue}from"../_chunks/libs/get-port.mjs";import{t as We}from"../_chunks/libs/vscode-languageserver.mjs";import{t as Ge}from"../_chunks/libs/@hono/node-server.mjs";import Ke from"node:module";import{isDeploymentElementModel as qe,isDeploymentNodeModel as Je,isDeploymentRelationModel as Ye,isElementModel as Xe,isLikeC4ViewModel as Ze,isRelationModel as Qe,modelConnection as $e}from"@likec4/core/model";import{invariant as j,nonexhaustive as et}from"@likec4/core";import{basename as tt,dirname as M,extname as nt,isAbsolute as rt,join as N,relative as P,resolve as F,sep as it}from"node:path";import{ifilter as at,invariant as ot,isSameHierarchy as st}from"@likec4/core/utils";import ct from"nano-spawn";import{tmpdir as lt}from"node:os";import{resolve as I}from"path";import{env as ut,isCI as dt,isDevelopment as ft,isTest as pt,nodeENV as mt}from"std-env";import{copyFile as ht,mkdir as L,mkdtemp as gt,readFile as _t,readdir as vt,realpath as yt,rm as bt,stat as xt,writeFile as R}from"node:fs/promises";import{copyFileSync as St,existsSync as z,readFileSync as Ct,readdirSync as wt,rmSync as Tt,statSync as Et}from"node:fs";import{argv as Dt,cwd as Ot,exit as kt,hrtime as At,stdout as jt}from"node:process";import Mt from"yargs";import{hideBin as Nt}from"yargs/helpers";import{fileURLToPath as Pt,pathToFileURL as Ft}from"node:url";import It from"@vitejs/plugin-react";import{viteSingleFile as Lt}from"vite-plugin-singlefile";import{build as Rt,createServer as zt,preview as Bt}from"vite";import{setTimeout as Vt}from"node:timers/promises";import{setTimeout as Ht}from"node:timers";var Ut=`likec4`,Wt=`1.55.0`;const B=p.getChild(`cli`);function V(e){let t=p.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(`${x.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(`${x.red(r.name+` `+r.message)}`,{error:r});return}t.error(x.red(e),{error:r});return}if(typeof e==`string`){t.error(x.red(e));return}t.error`${e}`},clearScreen:function(e){},hasErrorLogged:function(e){return!1},hasWarned:!1}}function Gt(e){let[t,n]=At(e),r=t*1e3+n/1e6;return{ms:r,pretty:me(r)}}function H(e){let t=At();return{stopAndLog(n=`done in `){n=x.green(`${n}${Gt(t).pretty}`),(e||B).info(n)}}}function U(e,t){console.log(ke(e,{padding:1,margin:1,dimBorder:!0,...t}))}const Kt=V(`vite`),qt=M(Pt(import.meta.url)),Jt={banner:`/* prettier-ignore-start */
3
3
  /* eslint-disable */
4
4
 
5
5
  /******************************************************************************
@@ -10,40 +10,40 @@ import{s as e}from"../_chunks/rolldown-runtime.mjs";import"../_chunks/libs/birpc
10
10
  `,footer:`
11
11
 
12
12
  /* prettier-ignore-end */
13
- `};function Tt(){let e=ye({cwd:Ct});if(!e)throw Error(`likec4 package folder not found`);return A(e)}function Et(){let e=[P(Tt(),`__app__`),P(Ct,`../__app__`),P(Ct,`../../__app__`),P(Ct,`../../dist/__app__`)],t=r(e,F);if(!t)throw d.error(`likec4 app root does not exist, tried:\n${e.join(`
14
- `)}`),Error(`likec4 app root does not exist`);return t}async function Dt(){let e=await qe(M(ze(),`.likec4-public-`));return await k(M(e,`likec4-views.js`),`// generated by likec4
15
- `),e}function Ot(e){return N(I(),e)}const kt=1e4;function At(){let e=Tt();return{"likec4/icons":`@likec4/icons`,"likec4/react":P(e,`react/index.mjs`),"likec4/model":P(e,`dist/model/index.mjs`),"likec4/vite-plugin/internal":P(e,`dist/vite-plugin/internal.mjs`)}}const jt=async({languageServices:e,likec4AssetsDir:t,...n})=>{let r=n.customLogger??St,i=Et();r.info(`${y.cyan(`likec4 app root`)} ${y.dim(Ot(i))}`);let a=n.outputDir??P(e.workspace,`dist`);r.info(y.cyan(`outDir`)+` `+y.dim(Ot(a)));let o=`/`;n.base&&(o=ne(n.base),!ie(o)&&o!==`./`&&(o=ae(o))),o!==`/`&&r.info(`${y.green(`app base url`)} ${y.dim(o)}`);let s=n.webcomponentPrefix??`likec4`,c=n.title??`LikeC4`,l=n.outputSingleFile??!1;return{isDev:!1,likec4AssetsDir:t,webcomponentPrefix:s,title:c,root:i,languageServices:e,clearScreen:!1,base:o,resolve:{conditions:[`production`],dedupe:[`react`,`react-dom`,`react/jsx-runtime`,`react/jsx-dev-runtime`,`react-dom/client`],alias:{...At(),"likec4/previews":t}},configFile:!1,mode:`production`,optimizeDeps:{include:[`react`,`react-dom`,`react/jsx-runtime`,`react/jsx-dev-runtime`,`react-dom/client`,`@likec4/core/types`,`@likec4/core/model`,`@likec4/core/styles`,`@likec4/core/utils`,`@likec4/core`,`likec4/vite-plugin/internal`],noDiscovery:!0},esbuild:{tsconfigRaw:{compilerOptions:{target:`ESNext`,jsx:`react-jsx`}}},define:{WEBCOMPONENT_PREFIX:JSON.stringify(s),PAGE_TITLE:JSON.stringify(c),__USE_HASH_HISTORY__:n?.useHashHistory===!0?`true`:`false`,"process.env.NODE_ENV":`"production"`},build:{outDir:a,emptyOutDir:!1,sourcemap:!1,cssMinify:!1,minify:!0,copyPublicDir:!0,chunkSizeWarningLimit:kt,assetsInlineLimit:1e5,rollupOptions:{treeshake:{preset:`recommended`},...!l&&{input:[P(i,`index.html`),P(i,`src`,`main.js`),P(i,`src`,`fonts.css`),P(i,`src`,`style.css`)],output:{manualChunks:e=>{if(!(e.endsWith(`.css`)||e.endsWith(`.html`)||e.includes(`likec4/icons`)||e.includes(`const.js`))){if(e.includes(`__app__`)){let t=e.match(/__app__\/src\/([\w]+)\.js/)?.[1];return t?t[1]:void 0}if(e.includes(`likec4`))return`likec4`;if(e.includes(`node_modules`))return`vendors`}}}}}},customLogger:r,plugins:[pt(),ge({languageServices:e.languageServices}),l?mt():void 0]}};async function Mt({languageServices:e,outDir:t,base:n,webcomponentPrefix:r=`likec4`,filename:i=`likec4-views.js`}){let a=B([`vite`,`webcomponent`]),o=Et();return a.info(y.cyan(`outDir`)+` `+y.dim(t)),{root:o,clearScreen:!1,base:n,configFile:!1,publicDir:!1,mode:`production`,resolve:{conditions:[`production`],alias:At(),dedupe:[`react`,`react-dom`,`react/jsx-runtime`,`react/jsx-dev-runtime`,`react-dom/client`]},define:{WEBCOMPONENT_PREFIX:JSON.stringify(r),"process.env.NODE_ENV":`"production"`},esbuild:{...wt,tsconfigRaw:{compilerOptions:{target:`ESNext`,jsx:`react-jsx`}}},build:{outDir:t,emptyOutDir:!1,sourcemap:!1,minify:!0,assetsInlineLimit:1024*1024,chunkSizeWarningLimit:kt,lib:{entry:`src/webcomponent.js`,fileName(e,t){return i},formats:[`iife`],name:`LikeC4Views`},rollupOptions:{treeshake:{preset:`recommended`},output:{format:`iife`,hoistTransitiveImports:!1,compact:!0}}},customLogger:a,plugins:[pt(),ge({languageServices:e.languageServices})]}}const Nt=[`favicon.ico`,`robots.txt`];async function Pt({buildWebcomponent:e=!0,webcomponentPrefix:t=`likec4`,title:n,languageServices:r,likec4AssetsDir:i,outputSingleFile:a,...o}){i??=await qe(M(ze(),`.likec4-assets-`));let s=await jt({...o,languageServices:r,likec4AssetsDir:i,webcomponentPrefix:t,title:n,outputSingleFile:a}),c=!F(s.build.outDir)||rt(s.build.outDir).length===0,l=await Dt();for(let e of Nt){let t=P(s.root,e);F(t)&&tt(t,P(l,e))}let u=r.languageServices.projects();if(u.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?s.customLogger.info(`${y.dim(`workspace:`)} ${y.green(`✓ all views layouted`)}`):s.customLogger.warn(`${y.dim(`workspace:`)} ${y.yellow(`✗ layouted ${t.length} of ${e.length} views`)}`),t.forEach(e=>{(e.hasLayoutDrift||e.drifts&&e.drifts.length>0)&&s.customLogger.warn(y.dim(`view`)+` `+y.red(e.id)+` `+y.yellow(`is out of date, layout drift detected`))});let n=u[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))||s.customLogger.warn(y.dim(`landingPage:`)+` `+y.yellow(`no views match the configured filter`))}}else for(let e of u){let t=await r.viewsService.computedViews(e.id);t.length===0?s.customLogger.warn(`${y.dim(`project:`)} ${e.id} ${y.yellow(`✗ no views found`)}`):s.customLogger.info(`${y.dim(`project:`)} ${e.id} ${y.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))||s.customLogger.warn(`${y.dim(`project:`)} ${e.id} ${y.yellow(`landingPage: no views match the configured filter`)}`)}}if(e&&!a&&await R(await Mt({webcomponentPrefix:t,languageServices:r,outDir:l,base:s.base})),await R({...s,customLogger:s.customLogger,publicDir:l,mode:`production`}),a){if(!c){s.customLogger.warn(y.yellow(`outDir was not empty, skipping cleanup`));return}for(let e of rt(P(s.build.outDir)).filter(e=>e!==`index.html`))it(P(s.build.outDir,e),{recursive:!0})}let d=P(s.build.outDir,`index.html`);F(d)&&tt(d,P(s.build.outDir,`404.html`))}function Ft(e){try{return!!Ae.createRequire(import.meta.url).resolve(e)}catch(e){return z.debug(_(e)),!1}}async function U(){if(Ft(`react`)&&Ft(`react-dom`)){z.debug(`react already installed`);return}z.warn(`react not installed`);let e=await xe();e||(z.error`Package manager not detected, please install dependencies manually: ${`react`} ${`react-dom`}`,process.exit(1));let t=be(e.agent,`add`,[`react`,`react-dom`]);t||(z.error`Please install dependencies manually: ${`react`} ${`react-dom`}`,process.exit(1));try{await Re(t.command,t.args,{stdio:`inherit`})}catch(e){z.debug(_(e)),z.error`Please install dependencies manually: ${`react`} ${`react-dom`}`,process.exit(1)}}async function It(){if(Ft(`playwright`)){z.debug(`playwright already installed`);return}z.warn(`playwright not installed`);let e=await xe();e||(z.error`Package manager not detected, please install dependencies manually: ${`playwright`}`,process.exit(1));let t=be(e.agent,`add`,[`playwright`]);t||(z.error`Please install dependencies manually: ${`playwright`}`,process.exit(1));try{await Re(t.command,t.args,{preferLocal:!0,stdio:`inherit`})}catch(e){z.debug(_(e)),z.error`Please install dependencies manually: ${`playwright`}`,process.exit(1)}}const W={type:`string`,desc:`<directory> with LikeC4 sources (default is current directory or 'LIKEC4_WORKSPACE' env)`,normalize:!0,default:Be.LIKEC4_WORKSPACE||`.`,coerce:P},G={alias:`use-dot-bin`,boolean:!0,type:`boolean`,desc:T()?`enabled in container, disable by --no-use-dot`:`use graphviz binaries ("dot" should be on PATH)`,default:T()},Lt={boolean:!0,type:`boolean`,desc:"use `@likec4/core` package in types",default:!1},Rt={boolean:!0,type:`boolean`,desc:`use hash history for navigation, e.g. "/#/view" instead of "/view"`},K={alias:[`o`,`output`],string:!0,desc:`output directory`,normalize:!0,nargs:1,coerce:P},zt={alias:`w`,string:!0,desc:`prefix for Webcomponents, e.g "c4" generates <c4-view ../>`,default:`likec4`,nargs:1},Bt={alias:`t`,string:!0,desc:`base title of the app pages (default is "LikeC4")`,default:`LikeC4`,nargs:1},Vt={alias:[`base-url`],string:!0,desc:`base url the app is being served from, e.g. "/" or "/pages/"`,nargs:1},Ht={boolean:!0,desc:`outputs a single self-contained HTML file with all required resources inlined`},Ut={alias:`l`,string:!0,...T()?{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},Wt={number:!0,desc:`port number for the dev server (default is 5173, or PORT environment variable)`,nargs:1},q={alias:`p`,string:!0,desc:`select LikeC4 project by name (e.g. "my-project") or by path`,nargs:1},Gt={hidden:!0,nargs:1,desc:`force log level`,choices:[`trace`,`debug`,`info`,`warning`,`error`],conflicts:[`verbose`]},Kt={boolean:!0,desc:`verbose logging`,conflicts:[`log-level`]},qt=Se?`trace`:`debug`,J={name:yt,version:bt},Jt=c(()=>new we({projectName:yt,clearInvalidConfig:!0})),Yt=1e3*60,Xt=Yt*60*24*7;function Y(){if(!Ve)try{let e=Jt(),t=e.get(`lastSupportUsMessage`);if(!t){e.set(`lastSupportUsMessage`,Date.now()-Xt+5*Yt);return}if(t+Xt>Date.now())return;e.set(`lastSupportUsMessage`,Date.now()),H([y.dim(`If you are working in a commercial environment`),y.dim(`consider supporting the project`),``,y.dim(`How to get more?`)+` `+y.underline(`https://likec4.dev/sponsor/`)].join(`
16
- `))}catch{}}function X(){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 r(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 e(){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:r.bind(null,!1),a:r.bind(null,!0),d:function r(){var i,a=this.e,o=0;function s(){for(;i=n.pop();)try{if(!i.a&&o===1)return o=0,n.push(i),Promise.resolve().then(s);if(i.d){var e=i.d.call(i.v);if(i.a)return o|=2,Promise.resolve(e).then(s,c)}else o|=1}catch(e){return c(e)}if(o===1)return a===t?Promise.resolve():Promise.reject(a);if(a!==t)throw a}function c(n){return a=a===t?n:new e(n,a),s()}return s()}}}const Zt=e=>e.command({command:`build [path]`,aliases:[`bundle`],describe:`Build a static website`,builder:e=>e.positional(`path`,W).option(`output`,{alias:`o`,type:`string`,desc:`output directory for production build`,normalize:!0,coerce:P}).option(`base`,Vt).option(`use-hash-history`,Rt).option(`use-dot`,G).option(`webcomponent-prefix`,zt).option(`title`,Bt).option(`output-single-file`,Ht).example(`${y.green(`$0 build -o ./build ./src`)}`,y.gray(`Search for likec4 files in 'src' and output static site to 'build'`)),handler:async e=>{try{var t=X();let n={useHashHistory:e[`use-hash-history`]??!1,useDotBin:e[`use-dot`],webcomponentPrefix:e[`webcomponent-prefix`],outputSingleFile:e[`output-single-file`]??!1};await U();let r=B(`c4:build`),i=t.a(await C(e.path,{graphviz:e[`use-dot`]?`binary`:`wasm`,watch:!1})),a=e.output??P(i.workspace,`dist`),o=P(a,`assets`);await Pt({base:e.base,useHashHistory:n.outputSingleFile||n.useHashHistory,customLogger:r,webcomponentPrefix:n.webcomponentPrefix,title:e.title,languageServices:i,likec4AssetsDir:o,outputDir:a,outputSingleFile:n.outputSingleFile}),Y()}catch(e){t.e=e}finally{await t.d()}}});var Qt=e(Ce(),1);const $t=`check-update`;async function en(){if(Ue||Ge===$t)return;let e=Jt(),t=e.get(`lastUpdateCheck`);if(!t){await tn(!1);return}let n=e.get(`latestVersion`);if(s(n)||s(t)||t+864e5<Date.now())try{Re(`likec4`,[`check-update`],{stdio:`ignore`,timeout:5e3,preferLocal:!0,detached:!0,env:{NODE_ENV:$t}}).catch(()=>{})}catch{}n&&(0,Qt.gt)(n,J.version)&&H([`Update available: `,y.dim(J.version),y.reset(` → `),y.green(n)].join(``))}async function tn(e=!0){try{let t=Jt();t.set({lastUpdateCheck:Date.now()});let n=await nn();Ie(n,`No version found in latest npm`),t.set({lastUpdateCheck:Date.now(),latestVersion:n}),(0,Qt.gt)(n,J.version)?H([`Update available: `,y.dim(J.version),y.reset(` → `),y.green(n)].join(``)):e&&H(y.dim(`Up to date: `)+` `+y.green(J.version))}catch(e){z.warning(_(e))}}async function nn(){return(await Te(`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 rn=e=>e.command({command:`check-update`,describe:`Check for updates`,handler:async()=>{await tn()}});function an(e,t){if(!t)return e.languageServices.projectsManager.ensureProjectId();let n=P(t);if(n===e.workspace)return e.languageServices.projectsManager.ensureProjectId();if(F(n)&&at(n).isDirectory()){z.debug`Project path exists: ${n}`;let t=b.file(n.endsWith(et)?n:n+et),r=e.languageServices.projects().find(e=>e.folder.fsPath===t.fsPath);if(r)return z.debug`Found project ${r.id} at path: ${n}`,r.id;z.debug`No project registered at path: ${n}`}return e.languageServices.projectsManager.ensureProjectId(t)}function Z(e,t){let n=an(e,t),r=e.languageServices.projectsManager.getProject(n);return e.languageServices.projectsManager.defaultProjectId=n,{projectId:n,projectFolder:r.folderUri.fsPath,config:r.config}}const Q=z.getChild(`generator`);async function on({name:e,path:t,useDotBin:n,project:r}){try{var i=X();let a=V(Q),o=i.a(await C(t,{graphviz:n?`binary`:`wasm`,watch:!1})),{projectId:s,config:c}=Z(o,r);r&&Q.info(`${y.dim(`project`)} ${y.green(s)}`);let l=c.generators?.[e];if(!l)throw Q.error(y.red(`generator ${e} does not exist in project config`)),Error(`generator ${e} does not exist in project config`);Q.info(`${y.dim(`generator`)} ${y.green(e)}`),await sn({likec4:o,model:await o.layoutedModel(s),generator:l,logger:Q.getChild(e)}),a.stopAndLog()}catch(e){i.e=e}finally{await i.d()}}async function sn({likec4:e,model:t,generator:n,logger:r}){let i=e.languageServices,a=new Set,o=i.project(t.project.id),s=t.project.id;r.debug(`${y.dim(`running for project:`)} ${y.green(o.id)}`),await Promise.resolve().then(()=>n({likec4model:t,ctx:{workspace:e.languageServices.workspaceUri,project:o,locate:e=>{let t=null;switch(!0){case Ne(e):t=i.locate({element:e.id,projectId:s});break;case Pe(e):t=i.locate({view:e.id,projectId:s});break;case je(e):t=i.locate({deployment:e.id,projectId:s});break;case Fe(e):case Me(e):t=i.locate({relation:e.id,projectId:s});break;default:Le(e)}if(!t)throw r.error(`Cannot locate ${e.id}`,{target:e}),Error(`Cannot locate ${e.id}`);let n=b.parse(t.uri);return{range:t.range,document:n,relativePath:x.relative(o.folder,n),folder:x.dirname(n).fsPath,filename:x.basename(n)}},write:async({path:e,content:t})=>{let n;n=Array.isArray(e)?P(o.folder.fsPath,...e):b.isUri(e)?e.fsPath:P(o.folder.fsPath,`${e}`);let i=A(n);a.has(i)||(F(i)||(r.debug(`${y.dim(`create directory`)} ${i}`),await D(i,{recursive:!0})),a.add(i)),r.debug(`${y.dim(`write`)} ${n}`),await k(n,t)},abort:e=>{throw r.error(e||`Generator aborted`),Error(e||`Generator aborted`)}}}))}async function cn(e,t,n){t??=P(e.workspace,`likec4.generated.ts`),j(t)!==`.ts`&&(t+=`.ts`),await D(A(t),{recursive:!0});let r=me([...await e.diagrams()]);await k(t,r),n.info(`${y.dim(`generated`)} ${N(process.cwd(),t)}`)}async function ln(e,t,n){await D(t,{recursive:!0}),n.info(`${y.dim(`format`)} ${y.green(`dot`)}`),n.info(`${y.dim(`outdir`)} ${t}`);let r=new Set,i=await e.computedModel(),a=l(i.$data.views),o=0;for(let s of a)try{let a=await e.viewsService.layouter.dot({view:s,styles:i.$styles}),c=`.`;s.sourcePath&&(c=A(s.sourcePath)),c=P(t,c),r.has(c)||(await D(c,{recursive:!0}),r.add(c));let l=P(c,s.id+`.dot`);await k(l,a),n.info(`${y.dim(`generated`)} ${N(process.cwd(),l)}`),o++}catch(e){z.error(`error while generating ${s.id}`,{error:e})}o>0&&n.info(`${y.dim(`total`)} ${o} files`)}async function un(e,t,n,r){await D(n,{recursive:!0}),r.info(`${y.dim(`format`)} ${y.green(t)}`),r.info(`${y.dim(`outdir`)} ${n}`);let i,a;switch(t){case`d2`:i=`.d2`,a=le;break;case`mermaid`:i=`.mmd`,a=pe;break;case`plantuml`:i=`.puml`,a=ue;break;default:Le(t)}let o=new Set,s=await e.layoutedModel(),c=0;for(let e of s.views()){let t=e.$view;try{let s=`.`;t.sourcePath&&(s=A(t.sourcePath)),s=P(n,s),o.has(s)||(await D(s,{recursive:!0}),o.add(s));let l=P(s,t.id+i);await k(l,a(e)),r.info(`${y.dim(`generated`)} ${N(process.cwd(),l)}`),c++}catch(e){r.error(`error while generating ${t.id}`,{error:e})}}c>0&&r.info(`${y.dim(`total`)} ${c} files`)}async function dn({path:e,useDotBin:t,...n}){let r=B(`c4:codegen`),i=V(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 cn(a,n.outfile,r);break;case`dot`:await ln(a,n.outdir??e,r);break;case`d2`:case`mermaid`:case`plantuml`:await un(a,n.format,n.outdir??e,r);break;default:Le(n)}i.stopAndLog()}const fn=A(L(import.meta.url));function pn(){try{return JSON.parse(nt(M(fn,`..`,`package.json`),`utf8`)).version??`0.1.0`}catch{return JSON.parse(nt(M(fn,`..`,`..`,`package.json`),`utf8`)).version??`0.1.0`}}const mn=pn(),hn=`leanix`,gn=`depends on`,_n={factSheetTypes:{system:`Application`,container:`ITComponent`,component:`ITComponent`,actor:`Provider`},relationTypes:{default:gn},metadataToFields:{title:`name`,description:`description`,technology:`technology`}};function vn(e){let t={factSheetTypes:{..._n.factSheetTypes},relationTypes:{..._n.relationTypes},metadataToFields:{..._n.metadataToFields}};return e?{factSheetTypes:{...t.factSheetTypes,...e.factSheetTypes},relationTypes:{...t.relationTypes,...e.relationTypes},metadataToFields:{...t.metadataToFields,...e.metadataToFields}}:t}function yn(e,t){return t.factSheetTypes[e]??t.factSheetTypes.default??`Application`}function bn(e,t){let n=e??`default`;return t.relationTypes[n]??t.relationTypes.default??gn}const xn={manifestVersion:`1.0`,bridgeVersion:mn,mappingProfile:`default`};function Sn(e){let t={};for(let n of e.elements())t[n.id]={canonicalId:n.id,external:{}};return t}function Cn(e){let t={};for(let n of e.views())t[n.id]={viewId:n.id,external:{}};return t}function wn(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 Tn(e,t={}){let n={...xn,...t,generatedAt:t.generatedAt??new Date().toISOString()};return{manifestVersion:n.manifestVersion,generatedAt:n.generatedAt,bridgeVersion:n.bridgeVersion,mappingProfile:n.mappingProfile,projectId:e.projectId,entities:Sn(e),views:Cn(e),relations:wn(e)}}function En(e,t){let n=[];for(let r of e.elements()){let e=yn(r.kind,t),i=r.getMetadata(),a=typeof i.description==`string`?i.description:void 0,o=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},...o!==void 0&&{technology:o},...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 Dn(e,t){let n=[];for(let r of e.relationships()){let e=r.title??r.kind;n.push({type:bn(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 On(e,t={}){let n=vn(t.mapping),r=t.generatedAt??new Date().toISOString(),i=t.mappingProfile??(t.mapping?`custom`:`default`);return{generatedAt:r,projectId:e.projectId,mappingProfile:i,factSheets:En(e,n),relations:Dn(e,n)}}function kn(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 An(e,t){if(e.projectId!==t.projectId||e.mappingProfile!==t.mappingProfile)throw Error(kn(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 jn=class extends Error{constructor(e,t,n){super(e),this.statusCode=t,this.graphqlErrors=n,this.name=`LeanixApiError`}};function Mn(e){return new Promise(t=>setTimeout(t,e))}var Nn=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 n=async()=>{let n=Date.now()-this.lastRequestTime;n<this.requestDelayMs&&await Mn(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 jn(`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 jn(`Invalid JSON response: ${r} ${i.status} ${i.statusText} - ${t}`,i.status)}if(!i.ok)throw new jn(a.errors?.[0]?.message??`HTTP ${i.status} ${i.statusText}`,i.status,a.errors);if(a.errors&&a.errors.length>0)throw new jn(a.errors.map(e=>e.message).join(`; `),i.status,a.errors);if(a.data===void 0)throw new jn(`GraphQL response had no data and no errors`);return a.data},r=this.rateLimitLock,i;this.rateLimitLock=new Promise(e=>{i=e}),await r;try{return await n()}finally{i()}}};async function Pn(e,t,n){let r=(await e.graphql(`
13
+ `};function Yt(){let e=Ae({cwd:qt});if(!e)throw Error(`likec4 package folder not found`);return M(e)}function Xt(){let e=[F(Yt(),`__app__`),F(qt,`../__app__`),F(qt,`../../__app__`),F(qt,`../../dist/__app__`)],t=r(e,z);if(!t)throw p.error(`likec4 app root does not exist, tried:\n${e.join(`
14
+ `)}`),Error(`likec4 app root does not exist`);return t}async function Zt(){let e=await gt(N(lt(),`.likec4-public-`));return await R(N(e,`likec4-views.js`),`// generated by likec4
15
+ `),e}function Qt(e){return P(Ot(),e)}const $t=1e4;function en(){let e=Yt();return{"likec4/icons":`@likec4/icons`,"likec4/react":F(e,`react/index.mjs`),"likec4/model":F(e,`dist/model/index.mjs`),"likec4/vite-plugin/internal":F(e,`dist/vite-plugin/internal.mjs`)}}const tn=async({languageServices:e,likec4AssetsDir:t,...n})=>{let r=n.customLogger??Kt,i=Xt();r.info(`${x.cyan(`likec4 app root`)} ${x.dim(Qt(i))}`);let a=n.outputDir??F(e.workspace,`dist`);r.info(x.cyan(`outDir`)+` `+x.dim(Qt(a)));let o=`/`;n.base&&(o=oe(n.base),!ce(o)&&o!==`./`&&(o=le(o))),o!==`/`&&r.info(`${x.green(`app base url`)} ${x.dim(o)}`);let s=n.webcomponentPrefix??`likec4`,c=n.title??`LikeC4`,l=n.outputSingleFile??!1;return{isDev:!1,likec4AssetsDir:t,webcomponentPrefix:s,title:c,root:i,languageServices:e,clearScreen:!1,base:o,resolve:{conditions:[`production`],dedupe:[`react`,`react-dom`,`react/jsx-runtime`,`react/jsx-dev-runtime`,`react-dom/client`],alias:{...en(),"likec4/previews":t}},configFile:!1,mode:`production`,optimizeDeps:{include:[`react`,`react-dom`,`react/jsx-runtime`,`react/jsx-dev-runtime`,`react-dom/client`,`@likec4/core/types`,`@likec4/core/model`,`@likec4/core/styles`,`@likec4/core/utils`,`@likec4/core`,`likec4/vite-plugin/internal`],noDiscovery:!0},esbuild:{tsconfigRaw:{compilerOptions:{target:`ESNext`,jsx:`react-jsx`}}},define:{WEBCOMPONENT_PREFIX:JSON.stringify(s),PAGE_TITLE:JSON.stringify(c),__USE_HASH_HISTORY__:n?.useHashHistory===!0?`true`:`false`,__DEFAULT_THEME__:JSON.stringify(n?.theme??`auto`),"process.env.NODE_ENV":`"production"`},build:{outDir:a,emptyOutDir:!1,sourcemap:!1,cssMinify:!1,minify:!0,copyPublicDir:!0,chunkSizeWarningLimit:$t,assetsInlineLimit:1e5,rollupOptions:{treeshake:{preset:`recommended`},...!l&&{input:[F(i,`index.html`),F(i,`src`,`main.js`),F(i,`src`,`fonts.css`),F(i,`src`,`style.css`)],output:{manualChunks:e=>{if(!(e.endsWith(`.css`)||e.endsWith(`.html`)||e.includes(`likec4/icons`)||e.includes(`const.js`))){if(e.includes(`__app__`)){let t=e.match(/__app__\/src\/([\w]+)\.js/)?.[1];return t?t[1]:void 0}if(e.includes(`likec4`))return`likec4`;if(e.includes(`node_modules`))return`vendors`}}}}}},customLogger:r,plugins:[It(),Ee({languageServices:e.languageServices}),l?Lt():void 0]}};async function nn({languageServices:e,outDir:t,base:n,webcomponentPrefix:r=`likec4`,filename:i=`likec4-views.js`}){let a=V([`vite`,`webcomponent`]),o=Xt();return a.info(x.cyan(`outDir`)+` `+x.dim(t)),{root:o,clearScreen:!1,base:n,configFile:!1,publicDir:!1,mode:`production`,resolve:{conditions:[`production`],alias:en(),dedupe:[`react`,`react-dom`,`react/jsx-runtime`,`react/jsx-dev-runtime`,`react-dom/client`]},define:{WEBCOMPONENT_PREFIX:JSON.stringify(r),"process.env.NODE_ENV":`"production"`},esbuild:{...Jt,tsconfigRaw:{compilerOptions:{target:`ESNext`,jsx:`react-jsx`}}},build:{outDir:t,emptyOutDir:!1,sourcemap:!1,minify:!0,assetsInlineLimit:1024*1024,chunkSizeWarningLimit:$t,lib:{entry:`src/webcomponent.js`,fileName(e,t){return i},formats:[`iife`],name:`LikeC4Views`},rollupOptions:{treeshake:{preset:`recommended`},output:{format:`iife`,hoistTransitiveImports:!1,compact:!0}}},customLogger:a,plugins:[It(),Ee({languageServices:e.languageServices})]}}const rn=[`favicon.ico`,`robots.txt`];async function an({buildWebcomponent:e=!0,webcomponentPrefix:t=`likec4`,title:n,languageServices:r,likec4AssetsDir:i,outputSingleFile:a,...o}){i??=await gt(N(lt(),`.likec4-assets-`));let s=await tn({...o,languageServices:r,likec4AssetsDir:i,webcomponentPrefix:t,title:n,outputSingleFile:a}),c=!z(s.build.outDir)||wt(s.build.outDir).length===0,l=await Zt();for(let e of rn){let t=F(s.root,e);z(t)&&St(t,F(l,e))}let u=r.languageServices.projects();if(u.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?s.customLogger.info(`${x.dim(`workspace:`)} ${x.green(`✓ all views layouted`)}`):s.customLogger.warn(`${x.dim(`workspace:`)} ${x.yellow(`✗ layouted ${t.length} of ${e.length} views`)}`),t.forEach(e=>{(e.hasLayoutDrift||e.drifts&&e.drifts.length>0)&&s.customLogger.warn(x.dim(`view`)+` `+x.red(e.id)+` `+x.yellow(`is out of date, layout drift detected`))});let n=u[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))||s.customLogger.warn(x.dim(`landingPage:`)+` `+x.yellow(`no views match the configured filter`))}}else for(let e of u){let t=await r.viewsService.computedViews(e.id);t.length===0?s.customLogger.warn(`${x.dim(`project:`)} ${e.id} ${x.yellow(`✗ no views found`)}`):s.customLogger.info(`${x.dim(`project:`)} ${e.id} ${x.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))||s.customLogger.warn(`${x.dim(`project:`)} ${e.id} ${x.yellow(`landingPage: no views match the configured filter`)}`)}}if(e&&!a&&await Rt(await nn({webcomponentPrefix:t,languageServices:r,outDir:l,base:s.base})),await Rt({...s,customLogger:s.customLogger,publicDir:l,mode:`production`}),a){if(!c){s.customLogger.warn(x.yellow(`outDir was not empty, skipping cleanup`));return}for(let e of wt(F(s.build.outDir)).filter(e=>e!==`index.html`))Tt(F(s.build.outDir,e),{recursive:!0})}let d=F(s.build.outDir,`index.html`);z(d)&&St(d,F(s.build.outDir,`404.html`))}function on(e){try{return!!Ke.createRequire(import.meta.url).resolve(e)}catch(e){return B.debug(h(e)),!1}}async function sn(){if(on(`react`)&&on(`react-dom`)){B.debug(`react already installed`);return}B.warn(`react not installed`);let e=await Me();e||(B.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||(B.error`Please install dependencies manually: ${`react`} ${`react-dom`}`,process.exit(1));try{await ct(t.command,t.args,{stdio:`inherit`})}catch(e){B.debug(h(e)),B.error`Please install dependencies manually: ${`react`} ${`react-dom`}`,process.exit(1)}}async function cn(){if(on(`playwright`)){B.debug(`playwright already installed`);return}B.warn(`playwright not installed`);let e=await Me();e||(B.error`Package manager not detected, please install dependencies manually: ${`playwright`}`,process.exit(1));let t=je(e.agent,`add`,[`playwright`]);t||(B.error`Please install dependencies manually: ${`playwright`}`,process.exit(1));try{await ct(t.command,t.args,{preferLocal:!0,stdio:`inherit`})}catch(e){B.debug(h(e)),B.error`Please install dependencies manually: ${`playwright`}`,process.exit(1)}}const W={type:`string`,desc:`<directory> with LikeC4 sources (default is current directory or 'LIKEC4_WORKSPACE' env)`,normalize:!0,default:ut.LIKEC4_WORKSPACE||`.`,coerce:F},G={alias:`use-dot-bin`,boolean:!0,type:`boolean`,desc:S()?`enabled in container, disable by --no-use-dot`:`use graphviz binaries ("dot" should be on PATH)`,default:S()},ln={boolean:!0,type:`boolean`,desc:"use `@likec4/core` package in types",default:!1},un={boolean:!0,type:`boolean`,desc:`use hash history for navigation, e.g. "/#/view" instead of "/view"`},K={alias:[`o`,`output`],string:!0,desc:`output directory`,normalize:!0,nargs:1,coerce:F},dn={alias:`w`,string:!0,desc:`prefix for Webcomponents, e.g "c4" generates <c4-view ../>`,default:`likec4`,nargs:1},fn={alias:`t`,string:!0,desc:`base title of the app pages (default is "LikeC4")`,default:`LikeC4`,nargs:1},pn={choices:[`light`,`dark`],desc:`default color scheme for the built website (default: auto, follows system preference)`,nargs:1},mn={alias:[`base-url`],string:!0,desc:`base url the app is being served from, e.g. "/" or "/pages/"`,nargs:1},hn={boolean:!0,desc:`outputs a single self-contained HTML file with all required resources inlined`},gn={alias:`l`,string:!0,...S()?{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},_n={number:!0,desc:`port number for the dev server (default is 5173, or PORT environment variable)`,nargs:1},q={alias:`p`,string:!0,desc:`select LikeC4 project by name (e.g. "my-project") or by path`,nargs:1},vn={hidden:!0,nargs:1,desc:`force log level`,choices:[`trace`,`debug`,`info`,`warning`,`error`],conflicts:[`verbose`]},yn={boolean:!0,desc:`verbose logging`,conflicts:[`log-level`]},bn=Ne?`trace`:`debug`,xn={name:Ut,version:Wt},Sn=c(()=>new Fe({projectName:Ut,clearInvalidConfig:!0})),Cn=1e3*60,wn=Cn*60*24*7;function J(){if(!dt)try{let e=Sn(),t=e.get(`lastSupportUsMessage`);if(!t){e.set(`lastSupportUsMessage`,Date.now()-wn+5*Cn);return}if(t+wn>Date.now())return;e.set(`lastSupportUsMessage`,Date.now()),U([x.dim(`If you are working in a commercial environment`),x.dim(`consider supporting the project`),``,x.dim(`How to get more?`)+` `+x.underline(`https://likec4.dev/sponsor/`)].join(`
16
+ `))}catch{}}function Y(){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 r(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 e(){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:r.bind(null,!1),a:r.bind(null,!0),d:function r(){var i,a=this.e,o=0;function s(){for(;i=n.pop();)try{if(!i.a&&o===1)return o=0,n.push(i),Promise.resolve().then(s);if(i.d){var e=i.d.call(i.v);if(i.a)return o|=2,Promise.resolve(e).then(s,c)}else o|=1}catch(e){return c(e)}if(o===1)return a===t?Promise.resolve():Promise.reject(a);if(a!==t)throw a}function c(n){return a=a===t?n:new e(n,a),s()}return s()}}}const Tn=e=>e.command({command:`build [path]`,aliases:[`bundle`],describe:`Build a static website`,builder:e=>e.positional(`path`,W).option(`output`,{alias:`o`,type:`string`,desc:`output directory for production build`,normalize:!0,coerce:F}).option(`base`,mn).option(`use-hash-history`,un).option(`use-dot`,G).option(`webcomponent-prefix`,dn).option(`title`,fn).option(`output-single-file`,hn).option(`theme`,pn).example(`${x.green(`$0 build -o ./build ./src`)}`,x.gray(`Search for likec4 files in 'src' and output static site to 'build'`)).example(`${x.green(`$0 build --theme dark -o ./build ./src`)}`,x.gray(`Build with dark color scheme as default`)),handler:async e=>{try{var t=Y();let n={useHashHistory:e[`use-hash-history`]??!1,useDotBin:e[`use-dot`],webcomponentPrefix:e[`webcomponent-prefix`],outputSingleFile:e[`output-single-file`]??!1};await sn();let r=V(`c4:build`),i=t.a(await v(e.path,{graphviz:e[`use-dot`]?`binary`:`wasm`,watch:!1})),a=e.output??F(i.workspace,`dist`),o=F(a,`assets`);await an({base:e.base,useHashHistory:n.outputSingleFile||n.useHashHistory,customLogger:r,webcomponentPrefix:n.webcomponentPrefix,title:e.title,theme:e.theme,languageServices:i,likec4AssetsDir:o,outputDir:a,outputSingleFile:n.outputSingleFile}),J()}catch(e){t.e=e}finally{await t.d()}}});var En=e(Pe(),1);const Dn=`check-update`;async function On(){if(dt||pt||mt===Dn)return;let e=Sn(),t=e.get(`lastUpdateCheck`);if(!t){await kn(!1);return}let n=e.get(`latestVersion`);if(s(n)||s(t)||t+864e5<Date.now())try{ct(`likec4`,[`check-update`],{stdio:`ignore`,timeout:5e3,preferLocal:!0,detached:!0,env:{NODE_ENV:Dn}}).catch(()=>{})}catch{}n&&(0,En.gt)(n,xn.version)&&U([`Update available: `,x.dim(xn.version),x.reset(` → `),x.green(n)].join(``))}async function kn(e=!0){try{let t=Sn();t.set({lastUpdateCheck:Date.now()});let n=await An();j(n,`No version found in latest npm`),t.set({lastUpdateCheck:Date.now(),latestVersion:n}),(0,En.gt)(n,xn.version)?U([`Update available: `,x.dim(xn.version),x.reset(` → `),x.green(n)].join(``)):e&&U(x.dim(`Up to date: `)+` `+x.green(xn.version))}catch(e){B.warning(h(e))}}async function An(){return(await Ve(`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 jn=e=>e.command({command:`check-update`,describe:`Check for updates`,handler:async()=>{await kn()}});function Mn(e,t){if(!t)return e.languageServices.projectsManager.ensureProjectId();let n=F(t);if(n===e.workspace)return e.languageServices.projectsManager.ensureProjectId();if(z(n)&&Et(n).isDirectory()){B.debug`Project path exists: ${n}`;let t=re.file(n.endsWith(it)?n:n+it),r=e.languageServices.projects().find(e=>e.folder.fsPath===t.fsPath);if(r)return B.debug`Found project ${r.id} at path: ${n}`,r.id;B.debug`No project registered at path: ${n}`}return e.languageServices.projectsManager.ensureProjectId(t)}function Nn(e,t){let n=Mn(e,t),r=e.languageServices.projectsManager.getProject(n);return e.languageServices.projectsManager.defaultProjectId=n,{projectId:n,projectFolder:r.folderUri.fsPath,config:r.config}}const Pn=B.getChild(`generator`);async function Fn({name:e,path:t,useDotBin:n,project:r}){try{var i=Y();let a=H(Pn),o=i.a(await v(t,{graphviz:n?`binary`:`wasm`,watch:!1})),{projectId:s,config:c}=Nn(o,r);r&&Pn.info(`${x.dim(`project`)} ${x.green(s)}`);let l=c.generators?.[e];if(!l)throw Pn.error(x.red(`generator ${e} does not exist in project config`)),Error(`generator ${e} does not exist in project config`);Pn.info(`${x.dim(`generator`)} ${x.green(e)}`),await In({likec4:o,model:await o.layoutedModel(s),generator:l,logger:Pn.getChild(e)}),a.stopAndLog()}catch(e){i.e=e}finally{await i.d()}}async function In({likec4:e,model:t,generator:n,logger:r}){let i=e.languageServices,a=new Set,o=i.project(t.project.id),s=t.project.id;r.debug(`${x.dim(`running for project:`)} ${x.green(o.id)}`),await Promise.resolve().then(()=>n({likec4model:t,ctx:{workspace:e.languageServices.workspaceUri,project:o,locate:e=>{let t=null;switch(!0){case Xe(e):t=i.locate({element:e.id,projectId:s});break;case Ze(e):t=i.locate({view:e.id,projectId:s});break;case qe(e):t=i.locate({deployment:e.id,projectId:s});break;case Qe(e):case Ye(e):t=i.locate({relation:e.id,projectId:s});break;default:et(e)}if(!t)throw r.error(`Cannot locate ${e.id}`,{target:e}),Error(`Cannot locate ${e.id}`);let n=re.parse(t.uri);return{range:t.range,document:n,relativePath:ie.relative(o.folder,n),folder:ie.dirname(n).fsPath,filename:ie.basename(n)}},write:async({path:e,content:t})=>{let n;n=Array.isArray(e)?F(o.folder.fsPath,...e):re.isUri(e)?e.fsPath:F(o.folder.fsPath,`${e}`);let i=M(n);a.has(i)||(z(i)||(r.debug(`${x.dim(`create directory`)} ${i}`),await L(i,{recursive:!0})),a.add(i)),r.debug(`${x.dim(`write`)} ${n}`),await R(n,t)},abort:e=>{throw r.error(e||`Generator aborted`),Error(e||`Generator aborted`)}}}))}async function Ln(e,t,n){t??=F(e.workspace,`likec4.generated.ts`),nt(t)!==`.ts`&&(t+=`.ts`),await L(M(t),{recursive:!0});let r=we([...await e.diagrams()]);await R(t,r),n.info(`${x.dim(`generated`)} ${P(process.cwd(),t)}`)}async function Rn(e,t,n){await L(t,{recursive:!0}),n.info(`${x.dim(`format`)} ${x.green(`dot`)}`),n.info(`${x.dim(`outdir`)} ${t}`);let r=new Set,i=await e.computedModel(),a=l(i.$data.views),o=0;for(let s of a)try{let a=await e.viewsService.layouter.dot({view:s,styles:i.$styles}),c=`.`;s.sourcePath&&(c=M(s.sourcePath)),c=F(t,c),r.has(c)||(await L(c,{recursive:!0}),r.add(c));let l=F(c,s.id+`.dot`);await R(l,a),n.info(`${x.dim(`generated`)} ${P(process.cwd(),l)}`),o++}catch(e){B.error(`error while generating ${s.id}`,{error:e})}o>0&&n.info(`${x.dim(`total`)} ${o} files`)}async function zn(e,t,n,r){await L(n,{recursive:!0}),r.info(`${x.dim(`format`)} ${x.green(t)}`),r.info(`${x.dim(`outdir`)} ${n}`);let i,a;switch(t){case`d2`:i=`.d2`,a=ye;break;case`mermaid`:i=`.mmd`,a=Ce;break;case`plantuml`:i=`.puml`,a=be;break;default:et(t)}let o=new Set,s=await e.layoutedModel(),c=0;for(let e of s.views()){let t=e.$view;try{let s=`.`;t.sourcePath&&(s=M(t.sourcePath)),s=F(n,s),o.has(s)||(await L(s,{recursive:!0}),o.add(s));let l=F(s,t.id+i);await R(l,a(e)),r.info(`${x.dim(`generated`)} ${P(process.cwd(),l)}`),c++}catch(e){r.error(`error while generating ${t.id}`,{error:e})}}c>0&&r.info(`${x.dim(`total`)} ${c} files`)}async function Bn({path:e,useDotBin:t,...n}){let r=V(`c4:codegen`),i=H(r),a=await v(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 Ln(a,n.outfile,r);break;case`dot`:await Rn(a,n.outdir??e,r);break;case`d2`:case`mermaid`:case`plantuml`:await zn(a,n.format,n.outdir??e,r);break;default:et(n)}i.stopAndLog()}const Vn=M(Pt(import.meta.url));function Hn(){try{let e=JSON.parse(Ct(N(Vn,`..`,`package.json`),`utf8`));if(e.version)return e.version}catch{}try{let e=JSON.parse(Ct(N(Vn,`..`,`..`,`package.json`),`utf8`));if(e.version)return e.version}catch{}return`0.1.0`}const Un=Hn(),Wn=`leanix`,Gn=`depends on`,Kn=new Set([`factSheetTypes`,`relationTypes`,`metadataToFields`]);function qn(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 Jn(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(!Kn.has(e))throw Error(`LeanIX mapping has unknown key "${e}". Allowed: factSheetTypes, relationTypes, metadataToFields`);if(t.factSheetTypes!==void 0&&!qn(t.factSheetTypes))throw Error(`LeanIX mapping "factSheetTypes" must be an object with string keys and string values`);if(t.relationTypes!==void 0&&!qn(t.relationTypes))throw Error(`LeanIX mapping "relationTypes" must be an object with string keys and string values`);if(t.metadataToFields!==void 0&&!qn(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:Gn},metadataToFields:{title:`name`,description:`description`,technology:`technology`}};function Xn(e){let t=Jn(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 Zn(e,t){return t.factSheetTypes[e]??t.factSheetTypes.default??`Application`}function Qn(e,t){let n=e??`default`;return t.relationTypes[n]??t.relationTypes.default??Gn}const $n={manifestVersion:`1.0`,bridgeVersion:Un,mappingProfile:`default`};function er(e){let t={};for(let n of e.elements())t[n.id]={canonicalId:n.id,external:{}};return t}function tr(e){let t={};for(let n of e.views())t[n.id]={viewId:n.id,external:{}};return t}function nr(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 rr(e,t={}){let n={...$n,...t,generatedAt:t.generatedAt??new Date().toISOString()};return{manifestVersion:n.manifestVersion,generatedAt:n.generatedAt,bridgeVersion:n.bridgeVersion,mappingProfile:n.mappingProfile,projectId:e.projectId,entities:er(e),views:tr(e),relations:nr(e)}}function ir(e,t){let n=[];for(let r of e.elements()){let e=Zn(r.kind,t),i=r.getMetadata(),a=typeof i.description==`string`?i.description:void 0,o=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},...o!==void 0&&{technology:o},...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 ar(e,t){let n=[];for(let r of e.relationships()){let e=r.title??r.kind;n.push({type:Qn(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 or(e,t={}){let n=Xn(t.mapping),r=t.generatedAt??new Date().toISOString(),i=t.mappingProfile??(t.mapping?`custom`:`default`);return{generatedAt:r,projectId:e.projectId,mappingProfile:i,factSheets:ir(e,n),relations:ar(e,n)}}function sr(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 cr(e,t){if(e.projectId!==t.projectId||e.mappingProfile!==t.mappingProfile)throw Error(sr(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 lr=class extends Error{constructor(e,t,n){super(e),this.statusCode=t,this.graphqlErrors=n,this.name=`LeanixApiError`}};function ur(e){return new Promise(t=>setTimeout(t,e))}var dr=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 n=async()=>{let n=Date.now()-this.lastRequestTime;n<this.requestDelayMs&&await ur(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 lr(`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 lr(`Invalid JSON response: ${r} ${i.status} ${i.statusText} - ${t}`,i.status)}if(!i.ok)throw new lr(a.errors?.[0]?.message??`HTTP ${i.status} ${i.statusText}`,i.status,a.errors);if(a.errors&&a.errors.length>0)throw new lr(a.errors.map(e=>e.message).join(`; `),i.status,a.errors);if(a.data===void 0)throw new lr(`GraphQL response had no data and no errors`);return a.data},r=this.rateLimitLock,i;this.rateLimitLock=new Promise(e=>{i=e}),await r;try{return await n()}finally{i()}}};async function fr(e,t,n){let r=(await e.graphql(`
17
17
  query FindFactSheet($name: String!, $type: String!) {
18
18
  allFactSheets(filter: { name: $name, factSheetType: $type }) {
19
19
  edges { node { id name type } }
20
20
  }
21
21
  }
22
- `,{name:t,type:n})).allFactSheets?.edges??[];if(r.length>1)throw Error(`Multiple fact sheets found for name="${t}" type="${n}". Ensure unique name+type in LeanIX or use likec4Id attribute for lookup.`);return r[0]?.node?.id??null}async function Fn(e,t,n){let r={facetFilters:[{facetKey:t,operator:`OR`,keys:[n]}]},i=(await e.graphql(`
22
+ `,{name:t,type:n})).allFactSheets?.edges??[];if(r.length>1)throw Error(`Multiple fact sheets found for name="${t}" type="${n}". Ensure unique name+type in LeanIX or use likec4Id attribute for lookup.`);return r[0]?.node?.id??null}async function pr(e,t,n){let r={facetFilters:[{facetKey:t,operator:`OR`,keys:[n]}]},i=(await e.graphql(`
23
23
  query FindFactSheetByAttribute($filter: FilterInput!) {
24
24
  allFactSheets(filter: $filter) {
25
25
  edges { node { id } }
26
26
  }
27
27
  }
28
- `,{filter:r})).allFactSheets?.edges??[];if(i.length>1)throw Error(`Multiple fact sheets found for attribute ${t}=${n}. Ensure unique likec4Id in LeanIX.`);return i[0]?.node?.id??null}async function In(e,t,n,r){let i=[{op:`replace`,path:`/factSheetAttributes/${n}`,value:r}];if(!(await e.graphql(`
28
+ `,{filter:r})).allFactSheets?.edges??[];if(i.length>1)throw Error(`Multiple fact sheets found for attribute ${t}=${n}. Ensure unique likec4Id in LeanIX.`);return i[0]?.node?.id??null}async function mr(e,t,n,r){let i=[{op:`replace`,path:`/factSheetAttributes/${n}`,value:r}];if(!(await e.graphql(`
29
29
  mutation UpdateFactSheet($id: ID!, $patches: [Patch]) {
30
30
  updateFactSheet(id: $id, patches: $patches) {
31
31
  factSheet { id }
32
32
  }
33
33
  }
34
- `,{id:t,patches:i})).updateFactSheet?.factSheet?.id)throw Error(`updateFactSheet did not return fact sheet (id=${t}, attribute=${n})`)}async function Ln(e,t,n){let r=[];t.description&&r.push({op:`replace`,path:`/description`,value:t.description}),n&&t.likec4Id&&r.push({op:`replace`,path:`/factSheetAttributes/${n}`,value:t.likec4Id});let i={input:{name:t.name,type:t.type},patches:r},a=(await e.graphql(`
34
+ `,{id:t,patches:i})).updateFactSheet?.factSheet?.id)throw Error(`updateFactSheet did not return fact sheet (id=${t}, attribute=${n})`)}async function hr(e,t,n){let r=[];t.description&&r.push({op:`replace`,path:`/description`,value:t.description}),n&&t.likec4Id&&r.push({op:`replace`,path:`/factSheetAttributes/${n}`,value:t.likec4Id});let i={input:{name:t.name,type:t.type},patches:r},a=(await e.graphql(`
35
35
  mutation CreateFactSheet($input: CreateFactSheetInput!, $patches: [Patch]) {
36
36
  createFactSheet(input: $input, patches: $patches) {
37
37
  factSheet { id name type rev }
38
38
  }
39
39
  }
40
- `,i)).createFactSheet?.factSheet?.id;if(!a)throw Error(`createFactSheet did not return id for ${String(t.name)}`);return a}async function Rn(e,t,n,r,i){let a=await e.graphql(`
40
+ `,i)).createFactSheet?.factSheet?.id;if(!a)throw Error(`createFactSheet did not return id for ${String(t.name)}`);return a}async function gr(e,t,n,r,i){let a=await e.graphql(`
41
41
  mutation CreateRelation($source: ID!, $target: ID!, $type: String!) {
42
42
  createRelation(source: $source, target: $target, type: $type) {
43
43
  relation { id }
44
44
  }
45
45
  }
46
- `,{source:t,target:n,type:r}),o=a.createRelation?.relation?.id;if(!o){let e=JSON.stringify(a,null,2);throw Error(`createRelation did not return relation id (sourceFactSheetId=${t}, targetFactSheetId=${n}, relationType=${r}). Response: ${e}`)}return o}function zn(e,t){let n=t?`update`:`create`;return{likec4Id:e.likec4Id,name:e.name,type:e.type,action:n,...t?{existingFactSheetId:t}:{}}}function Bn(e,t){return{factSheetsToCreate:e.filter(e=>e.action===`create`).length,factSheetsToUpdate:e.filter(e=>e.action===`update`).length,relationsToCreate:t.length}}function Vn(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 Hn(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,[hn]:{factSheetId:e,externalId:e}}})}return n}async function Un(e,t,n,r){if(!n)return null;if(r){let n=await Fn(e,r,t.likec4Id);if(n)return n;let i=await Pn(e,t.name,t.type);if(i&&t.likec4Id)try{await In(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 Pn(e,t.name,t.type)}async function Wn(e,t,n,r){let i=new Map,a=[],o=0,s=0;for(let c of t)try{let t=await Un(e,c,n,r);t&&s++,t||(t=await Ln(e,c,r),o++),t&&i.set(c.likec4Id,t)}catch(e){a.push(`Fact sheet ${c.likec4Id} (${String(c.name)}): ${Vn(e)}`)}return{likec4IdToFactSheetId:i,factSheetsCreated:o,factSheetsReused:s,errors:a}}async function Gn(e,t,n,r){let i=[],a=[],o=0;for(let s of t){let t=r.get(s.sourceFqn),c=r.get(s.targetFqn),l=s.external?.[hn];if(t&&c&&!l?.relationId){let r=n.find(e=>e.sourceLikec4Id===s.sourceFqn&&e.targetLikec4Id===s.targetFqn&&e.likec4RelationId===s.relationId);if(r)try{let n=await Rn(e,t,c,r.type,r.title);o++,i.push({...s,external:{...s.external,[hn]:{relationId:n,...s.external?.[hn]}}});continue}catch(e){a.push(`Relation ${s.compositeKey}: ${Vn(e)}`)}}i.push(s)}return{updatedRelations:i,relationsCreated:o,errors:a}}async function Kn(e,t,n={}){let r=n.idempotent??!0,i=n.likec4IdAttribute,a=n.generatedAt??new Date().toISOString(),o=[],s=[];for(let n of e.factSheets)try{let e=null;r&&(i?(e=await Fn(t,i,n.likec4Id),e||=await Pn(t,n.name,n.type)):e=await Pn(t,n.name,n.type)),s.push(zn(n,e))}catch(e){o.push(`Fact sheet ${n.likec4Id} (${String(n.name)}): ${Vn(e)}`),s.push(zn(n,null))}let c=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:Bn(s,c),factSheetPlans:s,relationPlans:c,errors:o}}async function qn(e,t,n,r={}){let i=r.idempotent??!0,a=r.likec4IdAttribute,o=await Wn(n,t.factSheets,i,a),s=Hn(e.entities,o.likec4IdToFactSheetId),c=await Gn(n,e.relations,t.relations,o.likec4IdToFactSheetId);return{manifest:{...e,entities:s,relations:c.updatedRelations},factSheetsCreated:o.factSheetsCreated,factSheetsReused:o.factSheetsReused,relationsCreated:c.relationsCreated,errors:[...o.errors,...c.errors]}}async function Jn(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 Yn(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 Zn(e,{...i==null?{}:{likec4IdAttribute:i},maxFactSheets:r});return{generatedAt:n,factSheets:a,relations:await Qn(e,a.map(e=>e.id))}}function Xn(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 Zn(e,t){let n=t.likec4IdAttribute,r=Math.min(100,t.maxFactSheets),i=[],a=null,o=!0,s=`
46
+ `,{source:t,target:n,type:r}),o=a.createRelation?.relation?.id;if(!o){let e=JSON.stringify(a,null,2);throw Error(`createRelation did not return relation id (sourceFactSheetId=${t}, targetFactSheetId=${n}, relationType=${r}). Response: ${e}`)}return o}function _r(e,t){let n=t?`update`:`create`;return{likec4Id:e.likec4Id,name:e.name,type:e.type,action:n,...t?{existingFactSheetId:t}:{}}}function vr(e,t){return{factSheetsToCreate:e.filter(e=>e.action===`create`).length,factSheetsToUpdate:e.filter(e=>e.action===`update`).length,relationsToCreate:t.length}}function yr(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 br(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,[Wn]:{factSheetId:e,externalId:e}}})}return n}async function xr(e,t,n,r){if(!n)return null;if(r){let n=await pr(e,r,t.likec4Id);if(n)return n;let i=await fr(e,t.name,t.type);if(i&&t.likec4Id)try{await mr(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 fr(e,t.name,t.type)}async function Sr(e,t,n,r){let i=new Map,a=[],o=0,s=0;for(let c of t)try{let t=await xr(e,c,n,r);t&&s++,t||(t=await hr(e,c,r),o++),t&&i.set(c.likec4Id,t)}catch(e){a.push(`Fact sheet ${c.likec4Id} (${String(c.name)}): ${yr(e)}`)}return{likec4IdToFactSheetId:i,factSheetsCreated:o,factSheetsReused:s,errors:a}}async function Cr(e,t,n,r){let i=[],a=[],o=0;for(let s of t){let t=r.get(s.sourceFqn),c=r.get(s.targetFqn),l=s.external?.[Wn];if(t&&c&&!l?.relationId){let r=n.find(e=>e.sourceLikec4Id===s.sourceFqn&&e.targetLikec4Id===s.targetFqn&&e.likec4RelationId===s.relationId);if(r)try{let n=await gr(e,t,c,r.type,r.title);o++,i.push({...s,external:{...s.external,[Wn]:{relationId:n,...s.external?.[Wn]}}});continue}catch(e){a.push(`Relation ${s.compositeKey}: ${yr(e)}`)}}i.push(s)}return{updatedRelations:i,relationsCreated:o,errors:a}}async function wr(e,t,n={}){let r=n.idempotent??!0,i=n.likec4IdAttribute,a=n.generatedAt??new Date().toISOString(),o=[],s=[];for(let n of e.factSheets)try{let e=null;r&&(i?(e=await pr(t,i,n.likec4Id),e||=await fr(t,n.name,n.type)):e=await fr(t,n.name,n.type)),s.push(_r(n,e))}catch(e){o.push(`Fact sheet ${n.likec4Id} (${String(n.name)}): ${yr(e)}`),s.push(_r(n,null))}let c=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:vr(s,c),factSheetPlans:s,relationPlans:c,errors:o}}async function Tr(e,t,n,r={}){let i=r.idempotent??!0,a=r.likec4IdAttribute,o=await Sr(n,t.factSheets,i,a),s=br(e.entities,o.likec4IdToFactSheetId),c=await Cr(n,e.relations,t.relations,o.likec4IdToFactSheetId);return{manifest:{...e,entities:s,relations:c.updatedRelations},factSheetsCreated:o.factSheetsCreated,factSheetsReused:o.factSheetsReused,relationsCreated:c.relationsCreated,errors:[...o.errors,...c.errors]}}async function Er(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 Dr(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 kr(e,{...i==null?{}:{likec4IdAttribute:i},maxFactSheets:r});return{generatedAt:n,factSheets:a,relations:await Ar(e,a.map(e=>e.id))}}function Or(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 kr(e,t){let n=t.likec4IdAttribute,r=Math.min(100,t.maxFactSheets),i=[],a=null,o=!0,s=`
47
47
  query AllFactSheets($first: Int!, $after: String, $filter: FilterInput) {
48
48
  allFactSheets(first: $first, after: $after, filter: $filter) {
49
49
  edges {
@@ -61,7 +61,7 @@ import{s as e}from"../_chunks/rolldown-runtime.mjs";import"../_chunks/libs/birpc
61
61
  }
62
62
  }
63
63
  }
64
- `,c=async t=>Jn(()=>e.graphql(s,{first:r,after:t,filter:{}}));for(;o&&i.length<t.maxFactSheets;){let e=await c(a),r=e.allFactSheets?.edges??[],s=e.allFactSheets?.pageInfo;for(let e of r){if(i.length>=t.maxFactSheets)break;let r=Xn(e.node,n);r&&i.push(r)}o=s?.hasNextPage===!0&&i.length<t.maxFactSheets,a=s?.endCursor??null}return i}async function Qn(e,t){if(t.length===0)return[];let n=[],r=new Set(t);async function i(t){let n=[],i=null,a=!0;for(;a;){let o=await Jn(()=>e.graphql(`
64
+ `,c=async t=>Er(()=>e.graphql(s,{first:r,after:t,filter:{}}));for(;o&&i.length<t.maxFactSheets;){let e=await c(a),r=e.allFactSheets?.edges??[],s=e.allFactSheets?.pageInfo;for(let e of r){if(i.length>=t.maxFactSheets)break;let r=Or(e.node,n);r&&i.push(r)}o=s?.hasNextPage===!0&&i.length<t.maxFactSheets,a=s?.endCursor??null}return i}async function Ar(e,t){if(t.length===0)return[];let n=[],r=new Set(t);async function i(t){let n=[],i=null,a=!0;for(;a;){let o=await Er(()=>e.graphql(`
65
65
  query FactSheetRelations($id: ID!, $first: Int, $after: String) {
66
66
  factSheet(id: $id) {
67
67
  id
@@ -77,27 +77,27 @@ import{s as e}from"../_chunks/rolldown-runtime.mjs";import"../_chunks/libs/birpc
77
77
  }
78
78
  }
79
79
  }
80
- `,{id:t,first:100,after:i})),s=o?.factSheet?.relations?.edges??[],c=o?.factSheet?.relations?.pageInfo;for(let e of s){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=c?.hasNextPage===!0,i=c?.endCursor??null}return n}for(let e=0;e<t.length;e+=10){let r=t.slice(e,e+10),a=await Promise.all(r.map(e=>i(e)));for(let e of a)n.push(...e)}return n}function $n(e,t,n,r){let i=e.external?.[hn],a=i?.factSheetId??i?.externalId;if(a==null)return null;let o=n.get(a);return!o||r.has(o.id)?null:(r.add(o.id),{canonicalId:t,factSheetId:o.id,name:o.name,type:o.type})}function er(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 tr(e,t,n,r,i,a,o,s){let c=`${t??e}${n??``}`,l=r.get(c)?.filter(e=>!i.has(e.id))??[];if(l.length===0)o.push({canonicalId:e,...t===void 0?{}:{name:t},...n===void 0?{}:{type:n}});else if(l.length===1){let t=l[0];a.push({canonicalId:e,factSheetId:t.id,name:t.name,type:t.type}),i.add(t.id)}else s.push({canonicalId:e,...t===void 0?{}:{name:t},...n===void 0?{}:{type:n},candidateFactSheetIds:l.map(e=>e.id)})}function nr(e,t,n={}){let r=n.generatedAt??new Date().toISOString(),i=n.dryRun,a=[],o=[],s=[],c=new Map(e.factSheets.map(e=>[e.id,e])),l=new Map,u=new Map;for(let t of e.factSheets){t.likec4Id&&l.set(t.likec4Id,t);let e=`${t.name}${t.type}`;u.has(e)||u.set(e,[]),u.get(e).push(t)}let d=i?new Map(i.factSheets.map(e=>[e.likec4Id,e])):null,f=new Set;for(let[e,n]of Object.entries(t.entities)){let t=$n(n,e,c,f);if(t){a.push(t);continue}let r=er(e,l,f);if(r){a.push(r);continue}let i=d?.get(e);tr(e,i?.name??void 0,i?.type??void 0,u,f,a,o,s)}let p=e.factSheets.filter(e=>!f.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:o,unmatchedInLeanix:p,ambiguous:s,summary:{matched:a.length,unmatchedInLikec4:o.length,unmatchedInLeanix:p.length,ambiguous:s.length}}}function $(e){return typeof e==`object`&&!!e}function rr(e){return $(e)?typeof e.canonicalId==`string`:!1}function ir(e){return $(e)?typeof e.viewId==`string`:!1}function ar(e){return $(e)?typeof e.relationId==`string`&&typeof e.sourceFqn==`string`&&typeof e.targetFqn==`string`&&typeof e.compositeKey==`string`:!1}function or(e){return $(e)?typeof e.id==`string`&&typeof e.name==`string`&&typeof e.type==`string`:!1}function sr(e){return $(e)?typeof e.sourceFactSheetId==`string`&&typeof e.targetFactSheetId==`string`&&typeof e.type==`string`:!1}function cr(e){if(!$(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(!rr(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(!ir(e))return!1;let r=e.relations;if(!Array.isArray(r))return!1;for(let e of r)if(!ar(e))return!1;return!0}function lr(e){if(!$(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(!or(t))return!1;if(!Array.isArray(e.relations))return!1;for(let t of e.relations)if(!sr(t))return!1;return!0}const ur=`No project or empty model`,dr=`LEANIX_API_TOKEN is required for likec4 sync leanix --apply`,fr=`default`,pr=`manifest.json`,mr=`leanix-dry-run.json`,hr=`report.json`;function gr(e){return{projectId:String(e.projectId),elements:()=>e.elements(),relationships:()=>e.relationships(),views:()=>e.views()}}function _r(e){let t=Tn(e,{mappingProfile:fr}),n=On(e,{mappingProfile:fr});return{manifest:t,dryRun:n,report:An(t,n)}}async function vr(e,t,n,r=process.cwd()){await D(e,{recursive:!0});let i=P(e,pr),a=P(e,mr),o=P(e,hr);await k(i,JSON.stringify(t.manifest,null,2)),await k(a,JSON.stringify(t.dryRun,null,2)),await k(o,JSON.stringify(t.report,null,2)),n.info(`${y.dim(`generated`)} ${N(r,i)}`),n.info(`${y.dim(`generated`)} ${N(r,a)}`),n.info(`${y.dim(`generated`)} ${N(r,o)}`)}const yr={manifest:pr,dryRun:mr,report:hr};async function br(e){let t=B(`c4:gen:leanix:dry-run`),n=V(t),{path:r,outdir:i,project:a,useDotBin:o}=e;try{try{var s=X();let e=s.a(await C(r,{graphviz:o?`binary`:`wasm`,watch:!1})),{projectId:n}=Z(e,a);a&&t.info(`${y.dim(`project`)} ${y.green(n)}`);let c=await e.layoutedModel(n);if(c===w.EMPTY)throw t.error(ur),Error(ur);await vr(i,_r(gr(c)),t)}catch(e){s.e=e}finally{await s.d()}}finally{n.stopAndLog()}}function xr(){let e=process.env.LEANIX_API_TOKEN?.trim();return e?new Nn({apiToken:e,baseUrl:process.env.LEANIX_BASE_URL?.trim()||`https://app.leanix.net`,requestDelayMs:200}):null}function Sr(){let e=xr();if(!e)throw Error(`LEANIX_API_TOKEN is required. Set it in the environment to call the LeanIX API.`);return e}async function Cr(e){let t=B(`c4:gen:leanix:inventory`),n=V(t),{outdir:r,likec4IdAttribute:i}=e;try{let e=Sr(),n={};typeof i==`string`&&i.trim()!==``&&(n.likec4IdAttribute=i.trim());let a=await Yn(e,n);await D(r,{recursive:!0});let o=P(r,`leanix-inventory-snapshot.json`);await k(o,JSON.stringify(a,null,2)),t.info(`${y.dim(`generated`)} ${N(process.cwd(),o)}`),t.info(`${y.dim(`snapshot`)} ${a.factSheets.length} fact sheets, ${a.relations.length} relations`)}finally{n.stopAndLog()}}const wr=`manifest.json`,Tr=`leanix-inventory-snapshot.json`;async function Er(e){let t=P(e,wr),n=P(e,Tr),[r,i]=await Promise.all([O(t,`utf-8`),O(n,`utf-8`)]),a=JSON.parse(r),o=JSON.parse(i);if(!cr(a))throw Error(`Invalid manifest format: missing manifestVersion, projectId, entities, relations, or views`);if(!lr(o))throw Error(`Invalid snapshot format: missing factSheets or relations arrays`);return{manifest:a,snapshot:o}}async function Dr(e,t,n){try{var r=X();let i=r.a(await C(e,{graphviz:n?`binary`:`wasm`,watch:!1})),{projectId:a}=Z(i,t),o=await i.layoutedModel(a);return o===w.EMPTY?void 0:_r(gr(o)).dryRun}catch(e){r.e=e}finally{await r.d()}}async function Or(e){let t=B(`c4:gen:leanix:reconcile`),n=V(t),{path:r,outdir:i,project:a,useDotBin:o}=e;try{let e,n;try{let t=await Er(i);e=t.manifest,n=t.snapshot}catch(e){let n=e instanceof Error?e.message:String(e);throw t.error(`Failed to read ${wr} or ${Tr} from ${i}: ${n}`),e}let s;try{s=await Dr(r,a,o)}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}`),s=void 0}let c=nr(n,e,{...s==null?{}:{dryRun:s}}),l=P(i,`reconciliation-report.json`);await k(l,JSON.stringify(c,null,2)),t.info(`${y.dim(`generated`)} ${N(process.cwd(),l)}`),t.info(`${y.dim(`reconcile`)} matched=${c.summary.matched} unmatchedLikec4=${c.summary.unmatchedInLikec4} unmatchedLeanix=${c.summary.unmatchedInLeanix} ambiguous=${c.summary.ambiguous}`)}finally{n.stopAndLog()}}async function kr({path:e,useDotBin:t,useCorePackage:n,outfile:r,project:i}){try{var a=X();let o=B(`c4:codegen`),s=V(o),c=a.a(await C(e,{graphviz:t?`binary`:`wasm`,watch:!1})),{projectId:l,projectFolder:u}=Z(c,i);i&&o.info(`${y.dim(`project`)} ${y.green(l)}`),o.info(`${y.dim(`format`)} ${y.green(`model`)}`);let d=await c.layoutedModel(l);for(let e of d.views())e.hasLayoutDrifts&&o.warn(y.yellow(`layout drift detected, view:`)+` `+y.red(e.id));let f=P(c.projectsManager.hasMultipleProjects()?u:c.workspace,`likec4-model.ts`);if(r&&(f=$e(r)?r:P(r),F(r)&&(await Ze(r)).isDirectory()))throw Error(`output file is a directory: ${r}`);let p=Qe(f);o.info(`${y.dim(`filename`)} ${p}`);let m=j(p).toLocaleLowerCase();if(![`.ts`,`.mts`,`.cts`].includes(m))throw o.error(`output file ${r} has extension "${m}"`),Error(`output file ${r} must be a .ts, .mts or .cts file`);let h=A(f);o.info(`${y.dim(`outdir`)} ${h}`),await D(h,{recursive:!0}),await k(f,se(d,{useCorePackage:n}),{encoding:`utf-8`}),s.stopAndLog(),H(oe(`
81
- ${y.dim(`Source generated:`)}
82
- ${N(I(),f)}
83
-
84
- ${y.dim(`How to use:`)}
85
- ${y.underline(`https://likec4.dev/tooling/code-generation/model/`)}
86
- `).trim(),{padding:1,borderColor:`green`,borderStyle:`round`})}catch(e){a.e=e}finally{await a.d()}}async function Ar({languageServices:e,outDir:t,filename:n=`likec4-react.mjs`}){let r=B([`vite`,`react`]),i=Et();return r.info(`${y.cyan(`likec4 app root`)} ${y.dim(Ot(i))}`),r.info(y.cyan(`outDir`)+` `+y.dim(Ot(t))),{customLogger:r,root:i,configFile:!1,clearScreen:!1,publicDir:!1,mode:`production`,resolve:{conditions:[`production`],alias:At()},esbuild:{banner:`'use client'
87
- `+wt.banner,footer:wt.footer,jsx:`transform`,jsxDev:!1,jsxSideEffects:!1,minifyIdentifiers:!1,minifySyntax:!1,minifyWhitespace:!1,tsconfigRaw:{compilerOptions:{target:`ES2022`,useDefineForClassFields:!0,verbatimModuleSyntax:!0,jsx:`react-jsx`}}},build:{outDir:t,emptyOutDir:!1,sourcemap:!1,minify:!1,copyPublicDir:!1,chunkSizeWarningLimit:kt,assetsInlineLimit:5e5,lib:{entry:`react/likec4.tsx`,fileName(e,t){return n},formats:[`es`]},rollupOptions:{output:{compact:!1,exports:`named`},external:[`likec4/react`,`likec4/model`,`react`,`react-dom`,`react/jsx-runtime`,`react/jsx-dev-runtime`,`react-dom/client`,/@likec4\/core.*/],onwarn(e,t){e.code!==`SOURCEMAP_ERROR`&&t(e)}}},plugins:[pt({}),ge({languageServices:e.languageServices})]}}async function jr({path:e,useDotBin:t,useCorePackage:n,outfile:r,project:i}){try{var a=X();await U();let o=B(`c4:codegen`),s=V(o),c=a.a(await C(e,{graphviz:t?`binary`:`wasm`,watch:!1})),{projectId:l,projectFolder:u}=Z(c,i);i&&o.info(`${y.dim(`project`)} ${y.green(l)}`),o.info(`${y.dim(`format`)} ${y.green(`react`)}`);let d=await c.diagrams(l);if(d.length===0)throw process.exitCode=1,Error(`no views found`);d.forEach(e=>{if(e.drifts&&e.drifts.length>0){o.info(y.yellow(`layout drift detected, view:`)+` `+y.red(e.id));return}if(e.hasLayoutDrift){o.warn(y.yellow(`drift detected, manual layout can not be applied, view:`)+` `+y.red(e.id));return}});let f=P(c.projectsManager.hasMultipleProjects()?u:c.workspace,`likec4-views.js`);if(r&&(f=$e(r)?r:P(r),F(r)&&(await Ze(r)).isDirectory()))throw Error(`output file is a directory: ${r}`);let p=A(f);o.info(`${y.dim(`outdir`)} ${p}`);let m=Qe(f);o.info(`${y.dim(`filename`)} ${m}`);let h=j(m).toLocaleLowerCase();if(![`.js`,`.mjs`,`.jsx`].includes(h))throw o.error(`output file ${r} has extension "${h}"`),Error(`output file ${r} must be a .js, .jsx or .mjs`);await R({...await Ar({languageServices:c,outDir:p,filename:m}),logLevel:`warn`});let g=await c.layoutedModel(l),_=P(p,Qe(f,h)+(h===`.mjs`?`.d.mts`:`.d.ts`));await k(_,fe(g,{useCorePackage:n})),s.stopAndLog(),H(oe(`
88
- ${y.dim(`Sources generated:`)}
89
- ${N(I(),f)}
90
- ${N(I(),_)}
91
-
92
- ${y.dim(`How to use:`)}
93
- ${y.underline(`https://likec4.dev/tooling/code-generation/react/`)}
94
- `),{padding:1,borderColor:`green`,borderStyle:`round`})}catch(e){a.e=e}finally{await a.d()}}async function Mr({project:e,path:t,useDotBin:n,webcomponentPrefix:r=`likec4`,outfile:i}){try{var o=X();await U();let s=B(`c4:codegen`),c=V(s),l=o.a(await C(t,{graphviz:n?`binary`:`wasm`,watch:!1})),{projectId:u,projectFolder:d}=Z(l,e);e&&s.info(`${y.dim(`project`)} ${y.green(u)}`),s.info(`${y.dim(`format`)} ${y.green(`webcomponent`)}`);let f=await l.diagrams(u);if(!a(f,1))throw s.warn(`no views found`),process.exitCode=1,Error(`no views found`);f.forEach(e=>{e.hasLayoutDrift&&s.warn(y.yellow(`drift detected, manual layout can not be applied, view:`)+` `+y.red(e.id))});let p=P(l.projectsManager.hasMultipleProjects()?d:l.workspace,`likec4-views.js`);if(i&&(p=$e(i)?i:P(i),F(i)&&(await Ze(i)).isDirectory()))throw Error(`output file is a directory: ${i}`);s.debug(`${y.dim(`outfilepath`)} ${p}`);let m=Qe(p);s.debug(`${y.dim(`filename`)} ${m}`);let h=j(m).toLocaleLowerCase();if(h!==`.js`&&h!==`.mjs`)throw s.warn(`output file ${i} has extension "${h}"`),Error(`output file ${i} must be a .js or .mjs`);let g=await Dt();s.debug(`${y.dim(`created temp public`)} ${g}`);let _=await Mt({languageServices:l,outDir:g,filename:m,webcomponentPrefix:r,base:`/`});s.debug(`${y.dim(`vite build webcomponent`)}`),await R({..._,logLevel:`warn`});let v=P(g,m);if(!F(v))throw Error(`output file not found: ${v}`);await D(A(p),{recursive:!0}),await Ke(v,p),s.info(`${y.dim(`generated`)} ${p}`),s.debug(`${y.dim(`remove temp public`)}`),await Xe(g,{recursive:!0,force:!0}),c.stopAndLog(),H(oe(`
95
- ${y.dim(`Webcomponents generated to:`)}
96
- ${N(I(),p)}
97
-
98
- ${y.dim(`Setup and usage instructions:`)}
99
- ${y.blue(`https://likec4.dev/tooling/code-generation/webcomponent/`)}
100
- `))}catch(e){o.e=e}finally{await o.d()}}const Nr=e=>e.command({command:`gen <command> [path]`,aliases:[`generate`,`codegen`],describe:`Generate various artifacts from LikeC4 sources`,builder:e=>e.positional(`path`,W).command(`react [path]`,`generate react component to render likec4 view`,e=>e.positional(`path`,W).option(`project`,q).option(`outfile`,{alias:[`o`,`output`],type:`string`,desc:`<file> path to output file (.jsx, .mjs or .js)`,normalize:!0,coerce:E}).option(`use-dot`,G).option(`use-core-package`,Lt),async e=>{await jr({project:e.project,useDotBin:e.useDotBin,path:e.path,outfile:e.outfile,useCorePackage:e.useCorePackage}),Y()}).command({command:`webcomponent [path]`,aliases:[`wc`,`webcomp`],describe:`generate js with webcomponents`,builder:e=>e.positional(`path`,W).option(`project`,q).option(`outfile`,{alias:[`o`,`output`],type:`string`,desc:`<file> path to output file (.mjs or .js)`,normalize:!0,coerce:E}).option(`webcomponent-prefix`,zt).option(`use-dot`,G),handler:async e=>{await Mr({project:e.project,useDotBin:e.useDotBin,path:e.path,outfile:e.outfile,webcomponentPrefix:e.webcomponentPrefix}),Y()}}).command({command:`model [path]`,aliases:[`ts`],describe:`generate LikeC4Model (.ts)`,builder:e=>e.positional(`path`,W).option(`project`,q).option(`outfile`,{alias:[`o`,`output`],type:`string`,desc:`<file> path to output file (.ts)`,normalize:!0,coerce:E}).option(`use-dot`,G).option(`use-core-package`,Lt),handler:async e=>{await kr({path:e.path,useDotBin:e.useDotBin,useCorePackage:e.useCorePackage,outfile:e.outfile,project:e.project}),Y()}}).command({command:`views-data [path]`,aliases:[`views`],describe:`{deprecated} use codegen model`,deprecated:!0,builder:e=>e.positional(`path`,W).option(`outfile`,{alias:[`o`,`output`],type:`string`,desc:`<file> output .ts file`,normalize:!0,coerce:E}).option(`use-dot`,G),handler:async e=>{await dn({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`,W).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`,W).option(`outdir`,{...K,desc:`<dir> output directory for manifest.json, leanix-dry-run.json, report.json`}).option(`project`,q).option(`use-dot`,G).example(`${y.green(`$0 gen leanix dry-run -o out/bridge`)}`,y.gray(`Write bridge artifacts to out/bridge`)),async e=>{await br({path:e.path,outdir:e.outdir??E(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`,{...K,default:E(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(`${y.green(`$0 gen leanix inventory -o out/bridge`)}`,y.gray(`Requires LEANIX_API_TOKEN`)),async e=>{await Cr({outdir:e.outdir??E(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`,W).option(`outdir`,{...K,default:E(process.cwd(),`out`,`bridge`),desc:`<dir> directory with manifest.json and leanix-inventory-snapshot.json`}).option(`project`,q).option(`use-dot`,G).example(`${y.green(`$0 gen leanix reconcile -o out/bridge`)}`,y.gray(`Reads manifest + snapshot from outdir; optional workspace for name+type matching`)),async e=>{await Or({path:e.path,outdir:e.outdir??E(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`,W).option(`outdir`,K).option(`use-dot`,G),handler:async e=>{await dn({format:`dot`,path:e.path,useDotBin:e.useDotBin,outdir:e.outdir}),Y()}}).command({command:`d2 [path]`,describe:`generate D2 files (.d2)`,builder:e=>e.positional(`path`,W).option(`outdir`,K).option(`use-dot`,G),handler:async e=>{await dn({format:`d2`,path:e.path,useDotBin:e.useDotBin,outdir:e.outdir}),Y()}}).command({command:`mermaid [path]`,aliases:[`mmd`],describe:`generate Mermaid files (.mmd)`,builder:e=>e.positional(`path`,W).option(`outdir`,K).option(`use-dot`,G),handler:async e=>{await dn({format:`mermaid`,useDotBin:e.useDotBin,path:e.path,outdir:e.outdir}),Y()}}).command({command:`plantuml [path]`,aliases:[`puml`],describe:`generate PlantUML files (.puml)`,builder:e=>e.positional(`path`,W).option(`outdir`,K).option(`use-dot`,G),handler:async e=>{await dn({format:`plantuml`,useDotBin:e.useDotBin,path:e.path,outdir:e.outdir}),Y()}}).command({command:`<custom> [path]`,describe:`run custom generator from likec4 config`,builder:e=>e.positional(`path`,W).option(`project`,q).option(`use-dot`,G),handler:async e=>{await on({name:`custom`,path:e.path,project:e.project,useDotBin:e.useDotBin})}}).epilog(`${y.bold(`Examples:`)}
80
+ `,{id:t,first:100,after:i})),s=o?.factSheet?.relations?.edges??[],c=o?.factSheet?.relations?.pageInfo;for(let e of s){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=c?.hasNextPage===!0,i=c?.endCursor??null}return n}for(let e=0;e<t.length;e+=10){let r=t.slice(e,e+10),a=await Promise.all(r.map(e=>i(e)));for(let e of a)n.push(...e)}return n}function jr(e,t,n,r){let i=e.external?.[Wn],a=i?.factSheetId??i?.externalId;if(a==null)return null;let o=n.get(a);return!o||r.has(o.id)?null:(r.add(o.id),{canonicalId:t,factSheetId:o.id,name:o.name,type:o.type})}function Mr(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 Nr(e,t,n,r,i,a,o,s){let c=`${t??e}${n??``}`,l=r.get(c)?.filter(e=>!i.has(e.id))??[];if(l.length===0)o.push({canonicalId:e,...t===void 0?{}:{name:t},...n===void 0?{}:{type:n}});else if(l.length===1){let t=l[0];a.push({canonicalId:e,factSheetId:t.id,name:t.name,type:t.type}),i.add(t.id)}else s.push({canonicalId:e,...t===void 0?{}:{name:t},...n===void 0?{}:{type:n},candidateFactSheetIds:l.map(e=>e.id)})}function Pr(e,t,n={}){let r=n.generatedAt??new Date().toISOString(),i=n.dryRun,a=[],o=[],s=[],c=new Map(e.factSheets.map(e=>[e.id,e])),l=new Map,u=new Map;for(let t of e.factSheets){t.likec4Id&&l.set(t.likec4Id,t);let e=`${t.name}${t.type}`;u.has(e)||u.set(e,[]),u.get(e).push(t)}let d=i?new Map(i.factSheets.map(e=>[e.likec4Id,e])):null,f=new Set;for(let[e,n]of Object.entries(t.entities)){let t=jr(n,e,c,f);if(t){a.push(t);continue}let r=Mr(e,l,f);if(r){a.push(r);continue}let i=d?.get(e);Nr(e,i?.name??void 0,i?.type??void 0,u,f,a,o,s)}let p=e.factSheets.filter(e=>!f.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:o,unmatchedInLeanix:p,ambiguous:s,summary:{matched:a.length,unmatchedInLikec4:o.length,unmatchedInLeanix:p.length,ambiguous:s.length}}}function Fr(e){return typeof e==`object`&&!!e}function Ir(e){return Fr(e)?typeof e.canonicalId==`string`:!1}function Lr(e){return Fr(e)?typeof e.viewId==`string`:!1}function Rr(e){return Fr(e)?typeof e.relationId==`string`&&typeof e.sourceFqn==`string`&&typeof e.targetFqn==`string`&&typeof e.compositeKey==`string`:!1}function zr(e){return Fr(e)?typeof e.id==`string`&&typeof e.name==`string`&&typeof e.type==`string`:!1}function Br(e){return Fr(e)?typeof e.sourceFactSheetId==`string`&&typeof e.targetFactSheetId==`string`&&typeof e.type==`string`:!1}function Vr(e){if(!Fr(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(!Ir(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(!Lr(e))return!1;let r=e.relations;if(!Array.isArray(r))return!1;for(let e of r)if(!Rr(e))return!1;return!0}function Hr(e){if(!Fr(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(!zr(t))return!1;if(!Array.isArray(e.relations))return!1;for(let t of e.relations)if(!Br(t))return!1;return!0}const Ur=`No project or empty model`,Wr=`LEANIX_API_TOKEN is required for likec4 sync leanix --apply`,Gr=`default`,Kr=`manifest.json`,qr=`leanix-dry-run.json`,Jr=`report.json`;function Yr(e){return{projectId:String(e.projectId),elements:()=>e.elements(),relationships:()=>e.relationships(),views:()=>e.views()}}function Xr(e){let t=rr(e,{mappingProfile:Gr}),n=or(e,{mappingProfile:Gr});return{manifest:t,dryRun:n,report:cr(t,n)}}async function Zr(e,t,n,r=process.cwd()){await L(e,{recursive:!0});let i=F(e,Kr),a=F(e,qr),o=F(e,Jr);await R(i,JSON.stringify(t.manifest,null,2)),await R(a,JSON.stringify(t.dryRun,null,2)),await R(o,JSON.stringify(t.report,null,2)),n.info(`${x.dim(`generated`)} ${P(r,i)}`),n.info(`${x.dim(`generated`)} ${P(r,a)}`),n.info(`${x.dim(`generated`)} ${P(r,o)}`)}const Qr={manifest:Kr,dryRun:qr,report:Jr};async function $r(e){let t=V(`c4:gen:leanix:dry-run`),n=H(t),{path:r,outdir:i,project:a,useDotBin:o}=e;try{try{var s=Y();let e=s.a(await v(r,{graphviz:o?`binary`:`wasm`,watch:!1})),{projectId:n}=Nn(e,a);a&&t.info(`${x.dim(`project`)} ${x.green(n)}`);let c=await e.layoutedModel(n);if(c===Oe.EMPTY)throw t.error(Ur),Error(Ur);await Zr(i,Xr(Yr(c)),t)}catch(e){s.e=e}finally{await s.d()}}finally{n.stopAndLog()}}function ei(){let e=process.env.LEANIX_API_TOKEN?.trim();return e?new dr({apiToken:e,baseUrl:process.env.LEANIX_BASE_URL?.trim()||`https://app.leanix.net`,requestDelayMs:200}):null}function ti(){let e=ei();if(!e)throw Error(`LEANIX_API_TOKEN is required. Set it in the environment to call the LeanIX API.`);return e}async function ni(e){let t=V(`c4:gen:leanix:inventory`),n=H(t),{outdir:r,likec4IdAttribute:i}=e;try{let e=ti(),n={};typeof i==`string`&&i.trim()!==``&&(n.likec4IdAttribute=i.trim());let a=await Dr(e,n);await L(r,{recursive:!0});let o=F(r,`leanix-inventory-snapshot.json`);await R(o,JSON.stringify(a,null,2)),t.info(`${x.dim(`generated`)} ${P(process.cwd(),o)}`),t.info(`${x.dim(`snapshot`)} ${a.factSheets.length} fact sheets, ${a.relations.length} relations`)}finally{n.stopAndLog()}}const ri=`manifest.json`,ii=`leanix-inventory-snapshot.json`;async function ai(e){let t=F(e,ri),n=F(e,ii),[r,i]=await Promise.all([_t(t,`utf-8`),_t(n,`utf-8`)]),a=JSON.parse(r),o=JSON.parse(i);if(!Vr(a))throw Error(`Invalid manifest format: missing manifestVersion, projectId, entities, relations, or views`);if(!Hr(o))throw Error(`Invalid snapshot format: missing factSheets or relations arrays`);return{manifest:a,snapshot:o}}async function oi(e,t,n){try{var r=Y();let i=r.a(await v(e,{graphviz:n?`binary`:`wasm`,watch:!1})),{projectId:a}=Nn(i,t),o=await i.layoutedModel(a);return o===Oe.EMPTY?void 0:Xr(Yr(o)).dryRun}catch(e){r.e=e}finally{await r.d()}}async function si(e){let t=V(`c4:gen:leanix:reconcile`),n=H(t),{path:r,outdir:i,project:a,useDotBin:o}=e;try{let e,n;try{let t=await ai(i);e=t.manifest,n=t.snapshot}catch(e){let n=e instanceof Error?e.message:String(e);throw t.error(`Failed to read ${ri} or ${ii} from ${i}: ${n}`),e}let s;try{s=await oi(r,a,o)}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}`),s=void 0}let c=Pr(n,e,{...s==null?{}:{dryRun:s}}),l=F(i,`reconciliation-report.json`);await R(l,JSON.stringify(c,null,2)),t.info(`${x.dim(`generated`)} ${P(process.cwd(),l)}`),t.info(`${x.dim(`reconcile`)} matched=${c.summary.matched} unmatchedLikec4=${c.summary.unmatchedInLikec4} unmatchedLeanix=${c.summary.unmatchedInLeanix} ambiguous=${c.summary.ambiguous}`)}finally{n.stopAndLog()}}async function ci({path:e,useDotBin:t,useCorePackage:n,outfile:r,project:i}){try{var a=Y();let o=V(`c4:codegen`),s=H(o),c=a.a(await v(e,{graphviz:t?`binary`:`wasm`,watch:!1})),{projectId:l,projectFolder:u}=Nn(c,i);i&&o.info(`${x.dim(`project`)} ${x.green(l)}`),o.info(`${x.dim(`format`)} ${x.green(`model`)}`);let d=await c.layoutedModel(l);for(let e of d.views())e.hasLayoutDrifts&&o.warn(x.yellow(`layout drift detected, view:`)+` `+x.red(e.id));let f=F(c.projectsManager.hasMultipleProjects()?u:c.workspace,`likec4-model.ts`);if(r&&(f=rt(r)?r:F(r),z(r)&&(await xt(r)).isDirectory()))throw Error(`output file is a directory: ${r}`);let p=tt(f);o.info(`${x.dim(`filename`)} ${p}`);let m=nt(p).toLocaleLowerCase();if(![`.ts`,`.mts`,`.cts`].includes(m))throw o.error(`output file ${r} has extension "${m}"`),Error(`output file ${r} must be a .ts, .mts or .cts file`);let h=M(f);o.info(`${x.dim(`outdir`)} ${h}`),await L(h,{recursive:!0}),await R(f,_e(d,{useCorePackage:n}),{encoding:`utf-8`}),s.stopAndLog(),U(ge(`
81
+ ${x.dim(`Source generated:`)}
82
+ ${P(Ot(),f)}
83
+
84
+ ${x.dim(`How to use:`)}
85
+ ${x.underline(`https://likec4.dev/tooling/code-generation/model/`)}
86
+ `).trim(),{padding:1,borderColor:`green`,borderStyle:`round`})}catch(e){a.e=e}finally{await a.d()}}async function li({languageServices:e,outDir:t,filename:n=`likec4-react.mjs`}){let r=V([`vite`,`react`]),i=Xt();return r.info(`${x.cyan(`likec4 app root`)} ${x.dim(Qt(i))}`),r.info(x.cyan(`outDir`)+` `+x.dim(Qt(t))),{customLogger:r,root:i,configFile:!1,clearScreen:!1,publicDir:!1,mode:`production`,resolve:{conditions:[`production`],alias:en()},esbuild:{banner:`'use client'
87
+ `+Jt.banner,footer:Jt.footer,jsx:`transform`,jsxDev:!1,jsxSideEffects:!1,minifyIdentifiers:!1,minifySyntax:!1,minifyWhitespace:!1,tsconfigRaw:{compilerOptions:{target:`ES2022`,useDefineForClassFields:!0,verbatimModuleSyntax:!0,jsx:`react-jsx`}}},build:{outDir:t,emptyOutDir:!1,sourcemap:!1,minify:!1,copyPublicDir:!1,chunkSizeWarningLimit:$t,assetsInlineLimit:5e5,lib:{entry:`react/likec4.tsx`,fileName(e,t){return n},formats:[`es`]},rollupOptions:{output:{compact:!1,exports:`named`},external:[`likec4/react`,`likec4/model`,`react`,`react-dom`,`react/jsx-runtime`,`react/jsx-dev-runtime`,`react-dom/client`,/@likec4\/core.*/],onwarn(e,t){e.code!==`SOURCEMAP_ERROR`&&t(e)}}},plugins:[It({}),Ee({languageServices:e.languageServices})]}}async function ui({path:e,useDotBin:t,useCorePackage:n,outfile:r,project:i}){try{var a=Y();await sn();let o=V(`c4:codegen`),s=H(o),c=a.a(await v(e,{graphviz:t?`binary`:`wasm`,watch:!1})),{projectId:l,projectFolder:u}=Nn(c,i);i&&o.info(`${x.dim(`project`)} ${x.green(l)}`),o.info(`${x.dim(`format`)} ${x.green(`react`)}`);let d=await c.diagrams(l);if(d.length===0)throw process.exitCode=1,Error(`no views found`);d.forEach(e=>{if(e.drifts&&e.drifts.length>0){o.info(x.yellow(`layout drift detected, view:`)+` `+x.red(e.id));return}if(e.hasLayoutDrift){o.warn(x.yellow(`drift detected, manual layout can not be applied, view:`)+` `+x.red(e.id));return}});let f=F(c.projectsManager.hasMultipleProjects()?u:c.workspace,`likec4-views.js`);if(r&&(f=rt(r)?r:F(r),z(r)&&(await xt(r)).isDirectory()))throw Error(`output file is a directory: ${r}`);let p=M(f);o.info(`${x.dim(`outdir`)} ${p}`);let m=tt(f);o.info(`${x.dim(`filename`)} ${m}`);let h=nt(m).toLocaleLowerCase();if(![`.js`,`.mjs`,`.jsx`].includes(h))throw o.error(`output file ${r} has extension "${h}"`),Error(`output file ${r} must be a .js, .jsx or .mjs`);await Rt({...await li({languageServices:c,outDir:p,filename:m}),logLevel:`warn`});let g=await c.layoutedModel(l),_=F(p,tt(f,h)+(h===`.mjs`?`.d.mts`:`.d.ts`));await R(_,Se(g,{useCorePackage:n})),s.stopAndLog(),U(ge(`
88
+ ${x.dim(`Sources generated:`)}
89
+ ${P(Ot(),f)}
90
+ ${P(Ot(),_)}
91
+
92
+ ${x.dim(`How to use:`)}
93
+ ${x.underline(`https://likec4.dev/tooling/code-generation/react/`)}
94
+ `),{padding:1,borderColor:`green`,borderStyle:`round`})}catch(e){a.e=e}finally{await a.d()}}async function di({project:e,path:t,useDotBin:n,webcomponentPrefix:r=`likec4`,outfile:i}){try{var o=Y();await sn();let s=V(`c4:codegen`),c=H(s),l=o.a(await v(t,{graphviz:n?`binary`:`wasm`,watch:!1})),{projectId:u,projectFolder:d}=Nn(l,e);e&&s.info(`${x.dim(`project`)} ${x.green(u)}`),s.info(`${x.dim(`format`)} ${x.green(`webcomponent`)}`);let f=await l.diagrams(u);if(!a(f,1))throw s.warn(`no views found`),process.exitCode=1,Error(`no views found`);f.forEach(e=>{e.hasLayoutDrift&&s.warn(x.yellow(`drift detected, manual layout can not be applied, view:`)+` `+x.red(e.id))});let p=F(l.projectsManager.hasMultipleProjects()?d:l.workspace,`likec4-views.js`);if(i&&(p=rt(i)?i:F(i),z(i)&&(await xt(i)).isDirectory()))throw Error(`output file is a directory: ${i}`);s.debug(`${x.dim(`outfilepath`)} ${p}`);let m=tt(p);s.debug(`${x.dim(`filename`)} ${m}`);let h=nt(m).toLocaleLowerCase();if(h!==`.js`&&h!==`.mjs`)throw s.warn(`output file ${i} has extension "${h}"`),Error(`output file ${i} must be a .js or .mjs`);let g=await Zt();s.debug(`${x.dim(`created temp public`)} ${g}`);let _=await nn({languageServices:l,outDir:g,filename:m,webcomponentPrefix:r,base:`/`});s.debug(`${x.dim(`vite build webcomponent`)}`),await Rt({..._,logLevel:`warn`});let y=F(g,m);if(!z(y))throw Error(`output file not found: ${y}`);await L(M(p),{recursive:!0}),await ht(y,p),s.info(`${x.dim(`generated`)} ${p}`),s.debug(`${x.dim(`remove temp public`)}`),await bt(g,{recursive:!0,force:!0}),c.stopAndLog(),U(ge(`
95
+ ${x.dim(`Webcomponents generated to:`)}
96
+ ${P(Ot(),p)}
97
+
98
+ ${x.dim(`Setup and usage instructions:`)}
99
+ ${x.blue(`https://likec4.dev/tooling/code-generation/webcomponent/`)}
100
+ `))}catch(e){o.e=e}finally{await o.d()}}const fi=e=>e.command({command:`gen <command> [path]`,aliases:[`generate`,`codegen`],describe:`Generate various artifacts from LikeC4 sources`,builder:e=>e.positional(`path`,W).command(`react [path]`,`generate react component to render likec4 view`,e=>e.positional(`path`,W).option(`project`,q).option(`outfile`,{alias:[`o`,`output`],type:`string`,desc:`<file> path to output file (.jsx, .mjs or .js)`,normalize:!0,coerce:I}).option(`use-dot`,G).option(`use-core-package`,ln),async e=>{await ui({project:e.project,useDotBin:e.useDotBin,path:e.path,outfile:e.outfile,useCorePackage:e.useCorePackage}),J()}).command({command:`webcomponent [path]`,aliases:[`wc`,`webcomp`],describe:`generate js with webcomponents`,builder:e=>e.positional(`path`,W).option(`project`,q).option(`outfile`,{alias:[`o`,`output`],type:`string`,desc:`<file> path to output file (.mjs or .js)`,normalize:!0,coerce:I}).option(`webcomponent-prefix`,dn).option(`use-dot`,G),handler:async e=>{await di({project:e.project,useDotBin:e.useDotBin,path:e.path,outfile:e.outfile,webcomponentPrefix:e.webcomponentPrefix}),J()}}).command({command:`model [path]`,aliases:[`ts`],describe:`generate LikeC4Model (.ts)`,builder:e=>e.positional(`path`,W).option(`project`,q).option(`outfile`,{alias:[`o`,`output`],type:`string`,desc:`<file> path to output file (.ts)`,normalize:!0,coerce:I}).option(`use-dot`,G).option(`use-core-package`,ln),handler:async e=>{await ci({path:e.path,useDotBin:e.useDotBin,useCorePackage:e.useCorePackage,outfile:e.outfile,project:e.project}),J()}}).command({command:`views-data [path]`,aliases:[`views`],describe:`{deprecated} use codegen model`,deprecated:!0,builder:e=>e.positional(`path`,W).option(`outfile`,{alias:[`o`,`output`],type:`string`,desc:`<file> output .ts file`,normalize:!0,coerce:I}).option(`use-dot`,G),handler:async e=>{await Bn({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`,W).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`,W).option(`outdir`,{...K,desc:`<dir> output directory for manifest.json, leanix-dry-run.json, report.json`}).option(`project`,q).option(`use-dot`,G).example(`${x.green(`$0 gen leanix dry-run -o out/bridge`)}`,x.gray(`Write bridge artifacts to out/bridge`)),async e=>{await $r({path:e.path,outdir:e.outdir??I(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`,{...K,default:I(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(`${x.green(`$0 gen leanix inventory -o out/bridge`)}`,x.gray(`Requires LEANIX_API_TOKEN`)),async e=>{await ni({outdir:e.outdir??I(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`,W).option(`outdir`,{...K,default:I(process.cwd(),`out`,`bridge`),desc:`<dir> directory with manifest.json and leanix-inventory-snapshot.json`}).option(`project`,q).option(`use-dot`,G).example(`${x.green(`$0 gen leanix reconcile -o out/bridge`)}`,x.gray(`Reads manifest + snapshot from outdir; optional workspace for name+type matching`)),async e=>{await si({path:e.path,outdir:e.outdir??I(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`,W).option(`outdir`,K).option(`use-dot`,G),handler:async e=>{await Bn({format:`dot`,path:e.path,useDotBin:e.useDotBin,outdir:e.outdir}),J()}}).command({command:`d2 [path]`,describe:`generate D2 files (.d2)`,builder:e=>e.positional(`path`,W).option(`outdir`,K).option(`use-dot`,G),handler:async e=>{await Bn({format:`d2`,path:e.path,useDotBin:e.useDotBin,outdir:e.outdir}),J()}}).command({command:`mermaid [path]`,aliases:[`mmd`],describe:`generate Mermaid files (.mmd)`,builder:e=>e.positional(`path`,W).option(`outdir`,K).option(`use-dot`,G),handler:async e=>{await Bn({format:`mermaid`,useDotBin:e.useDotBin,path:e.path,outdir:e.outdir}),J()}}).command({command:`plantuml [path]`,aliases:[`puml`],describe:`generate PlantUML files (.puml)`,builder:e=>e.positional(`path`,W).option(`outdir`,K).option(`use-dot`,G),handler:async e=>{await Bn({format:`plantuml`,useDotBin:e.useDotBin,path:e.path,outdir:e.outdir}),J()}}).command({command:`<custom> [path]`,describe:`run custom generator from likec4 config`,builder:e=>e.positional(`path`,W).option(`project`,q).option(`use-dot`,G),handler:async e=>{await Fn({name:`custom`,path:e.path,project:e.project,useDotBin:e.useDotBin})}}).epilog(`${x.bold(`Examples:`)}
101
101
  likec4 gen react -o dist/likec4-views.mjs ./src/likec4
102
102
  likec4 gen model -o likec4-model.ts
103
103
  likec4 gen leanix dry-run -o out/bridge
@@ -108,64 +108,1195 @@ import{s as e}from"../_chunks/rolldown-runtime.mjs";import"../_chunks/libs/birpc
108
108
  likec4 gen mmd --outdir assets/
109
109
  likec4 gen plantuml --outdir assets/
110
110
  likec4 gen dot -o out .
111
- `),handler:async e=>{await on({name:e.command,path:e.path,project:e.project,useDotBin:e.useDotBin})}}),Pr=new Set([`node_modules`,`.git`]);function Fr(e){return e.endsWith(`.c4`)||e.endsWith(`.likec4`)}function Ir(e,t=`
111
+ `),handler:async e=>{await Fn({name:e.command,path:e.path,project:e.project,useDotBin:e.useDotBin})}}),pi=new Set([`node_modules`,`.git`]);function mi(e){return e.endsWith(`.c4`)||e.endsWith(`.likec4`)}function hi(e,t=`
112
112
 
113
- `){return e.filter(e=>e.trim()!==``).join(t)}const Lr=`No project or empty model`,Rr=`No views could be exported`;function zr(){return`${y.bold(`Examples:`)}
114
- ${y.green(`$0 export drawio`)}
115
- ${y.gray(`Export each view to a separate .drawio file`)}
113
+ `){return e.filter(e=>e.trim()!==``).join(t)}const gi=`No project or empty model`,_i=`No views could be exported`;function vi(){return`${x.bold(`Examples:`)}
114
+ ${x.green(`$0 export drawio`)}
115
+ ${x.gray(`Export each view to a separate .drawio file`)}
116
116
 
117
- ${y.green(`$0 export drawio --all-in-one -o ./diagrams src/`)}
118
- ${y.gray(`Export all views as tabs in one .drawio file`)}
117
+ ${x.green(`$0 export drawio --all-in-one -o ./diagrams src/`)}
118
+ ${x.gray(`Export all views as tabs in one .drawio file`)}
119
119
 
120
- ${y.green(`$0 export drawio --roundtrip -o ./out`)}
121
- ${y.gray(`Re-apply layout/waypoints from comment blocks (e.g. after import from DrawIO)`)}
120
+ ${x.green(`$0 export drawio --roundtrip -o ./out`)}
121
+ ${x.gray(`Re-apply layout/waypoints from comment blocks (e.g. after import from DrawIO)`)}
122
122
 
123
- ${y.green(`$0 export drawio --uncompressed -o ./out`)}
124
- ${y.gray(`Export with raw XML (no compression) for draw.io desktop compatibility`)}
123
+ ${x.green(`$0 export drawio --uncompressed -o ./out`)}
124
+ ${x.gray(`Export with raw XML (no compression) for draw.io desktop compatibility`)}
125
125
 
126
- ${y.green(`$0 export drawio --profile leanix -o ./out`)}
127
- ${y.gray(`Export with bridge-managed metadata (likec4Id, likec4ViewId, etc.) for LeanIX interoperability`)}`}function Br(e){return e instanceof Error?e:Error(_(e))}function Vr(e,t,n){let r=Br(n);throw e.error(t,{error:r}),r}async function Hr(e,t){let n=[],r=new Set;async function i(e,a){if(a>=50)return;let o=await Ye(e).catch(()=>null);if(o==null||r.has(o))return;r.add(o);let s=await Je(e,{withFileTypes:!0}).catch(n=>(t?.debug&&t.debug(`${y.dim(`Roundtrip:`)} readdir failed`,{dir:e,err:n}),[]));for(let r of s){let o=M(e,r.name);switch(!0){case r.isDirectory():Pr.has(r.name)||await i(o,a+1);break;case r.isSymbolicLink():if((await Ze(o).catch(()=>null))?.isFile()&&Fr(r.name)){let e=await O(o,`utf-8`).catch(e=>(t?.debug&&t.debug(`${y.dim(`Roundtrip:`)} readFile failed`,{file:o,err:e}),``));e&&n.push(e)}break;case r.isFile()&&Fr(r.name):{let e=await O(o,`utf-8`).catch(e=>(t?.debug&&t.debug(`${y.dim(`Roundtrip:`)} readFile failed`,{file:o,err:e}),``));e&&n.push(e);break}}}}return await i(e,0),Ir(n)}async function Ur(e,t,n){if(t)return Hr(P(e),n)}function Wr(e,t,n){let r=e?{compressed:!1}:{compressed:!0};return t===`leanix`&&(r.profile=`leanix`,r.projectId=n),r}function Gr(e,t,n,r,i){return he(e.map(e=>String(e.$view.id)),t,Wr(n,r,i))}async function Kr(e){let{viewmodels:t,outdir:n,workspacePath:r,roundtrip:i,uncompressed:a,profile:o,projectId:s,logger:c}=e,l=de(t,Gr(t,await Ur(r,i,c),a,o,s)),u=P(n,_e);await k(u,l),c.info(`${y.dim(`generated`)} ${N(process.cwd(),u)} (${t.length} tab(s))`)}async function qr(e,t,n,r){let i=String(e.$view.id);try{let a=ce(e,t[i]),o=P(n,i+`.drawio`);return await D(A(o),{recursive:!0}),await k(o,a),r.info(`${y.dim(`generated`)} ${N(process.cwd(),o)}`),!0}catch(e){return r.error(`Failed to export view ${i}`,{error:Br(e)}),!1}}async function Jr(e){let{viewmodels:t,outdir:n,workspacePath:r,roundtrip:i,uncompressed:a,profile:o,projectId:s,logger:c}=e,l=Gr(t,await Ur(r,i,c),a,o,s),u=0;for(let e of t)await qr(e,l,n,c)&&u++;return{succeeded:u}}async function Yr(e,t){try{var n=X();let r=V(t),i=n.a(await Ee(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),o=await i.layoutedModel(a);if(o===w.EMPTY)throw t.error(Lr),Error(Lr);let s=[...o.views()];if(s.length===0)throw t.error(`No views to export`),Error(Rr);await D(e.outdir,{recursive:!0});let c=String(o.projectId),l={viewmodels:s,outdir:e.outdir,workspacePath:e.path,roundtrip:e.roundtrip,uncompressed:e.uncompressed,profile:e.profile,projectId:c,logger:t};if(e.allInOne)try{await Kr(l)}catch(e){Vr(t,`Failed to export DrawIO`,e)}else{let{succeeded:e}=await Jr(l);if(e===0)throw t.error(Rr),Error(Rr);t.info(`${y.dim(`total`)} ${e} DrawIO file(s)`)}r.stopAndLog(`✓ export drawio in `)}catch(e){n.e=e}finally{await n.d()}}function Xr(e){return e.command({command:`drawio [path]`,describe:`export view(s) to DrawIO (.drawio) for editing in draw.io`,builder:e=>e.positional(`path`,W).option(`outdir`,{alias:`o`,type:`string`,desc:`<dir> output directory for .drawio files`,normalize:!0,coerce:P}).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:q,"use-dot":G}).epilog(zr()),handler:async e=>{let t=B(`c4:export`);await Yr({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)}})}const Zr=`project not found`,Qr=`No projects found`;async function $r(e,t){try{var n=X();let r=V(t),i=n.a(await C(e.path,{graphviz:e.useDot?`binary`:`wasm`,watch:!1})),o=[...i.projectsManager.all];if(e.project){if(o=o.filter(t=>t===e.project),!a(o,1))throw t.error(`${Zr}: ${e.project}`),Error(`${Zr}: ${e.project}`)}else{if(!a(o,1))throw t.error(Qr),Error(Qr);t.info(`${y.dim(`workspace:`)} Found ${o.length} projects`)}let s=[];for(let n of o){let r;if(e.skipLayout?(t.info(`Generate model for project ${y.green(n)} ${y.dim(`(skip layout)`)}`),r=await i.computedModel(n)):(t.info(`Generating layouted model for project ${y.green(n)}`),r=await i.layoutedModel(n)),r===w.EMPTY){t.warn(y.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;j(c).toLowerCase()!==`.json`&&(c+=`.json`),await D(A(c),{recursive:!0});let l=s.length===1?s[0]:s,u=e.pretty?JSON.stringify(l,void 0,2):JSON.stringify(l);await k(c,u);let d=c.startsWith(e.path)?N(e.path,c):c;t.info(`${y.dim(`generated`)} ${d}`),r.stopAndLog(`✓ export in `)}catch(e){n.e=e}finally{await n.d()}}function ei(e){return e.command({command:`json [path]`,describe:`export model(s) to JSON`,builder:e=>e.positional(`path`,W).option(`outfile`,{alias:`o`,type:`string`,desc:`<file> output .json file`,default:`likec4.json`,normalize:!0,coerce:P}).options({project:q,"use-dot":G,"skip-layout":{type:`boolean`,desc:`skip layouting (only compute model)`},pretty:{type:`boolean`,desc:`indented JSON output`}}).epilog(`${y.bold(`Examples:`)}
128
- ${y.green(`$0 export json --skip-layout`)}
129
- ${y.gray(`Search for likec4 files in current directory and output JSON to likec4.json (no layout)`)}
126
+ ${x.green(`$0 export drawio --profile leanix -o ./out`)}
127
+ ${x.gray(`Export with bridge-managed metadata (likec4Id, likec4ViewId, etc.) for LeanIX interoperability`)}`}function yi(e){return e instanceof Error?e:Error(h(e))}function bi(e,t,n){let r=yi(n);throw e.error(t,{error:r}),r}async function xi(e,t){let n=[],r=new Set;async function i(e,a){if(a>=50)return;let o=await yt(e).catch(()=>null);if(o==null||r.has(o))return;r.add(o);let s=await vt(e,{withFileTypes:!0}).catch(n=>(t?.debug&&t.debug(`${x.dim(`Roundtrip:`)} readdir failed`,{dir:e,err:n}),[]));for(let r of s){let o=N(e,r.name);switch(!0){case r.isDirectory():pi.has(r.name)||await i(o,a+1);break;case r.isSymbolicLink():if((await xt(o).catch(()=>null))?.isFile()&&mi(r.name)){let e=await _t(o,`utf-8`).catch(e=>(t?.debug&&t.debug(`${x.dim(`Roundtrip:`)} readFile failed`,{file:o,err:e}),``));e&&n.push(e)}break;case r.isFile()&&mi(r.name):{let e=await _t(o,`utf-8`).catch(e=>(t?.debug&&t.debug(`${x.dim(`Roundtrip:`)} readFile failed`,{file:o,err:e}),``));e&&n.push(e);break}}}}return await i(e,0),hi(n)}async function Si(e,t,n){if(t)return xi(F(e),n)}function Ci(e,t,n){let r=e?{compressed:!1}:{compressed:!0};return t===`leanix`&&(r.profile=`leanix`,r.projectId=n),r}function wi(e,t,n,r,i){return Te(e.map(e=>String(e.$view.id)),t,Ci(n,r,i))}async function Ti(e){let{viewmodels:t,outdir:n,workspacePath:r,roundtrip:i,uncompressed:a,profile:o,projectId:s,logger:c}=e,l=xe(t,wi(t,await Si(r,i,c),a,o,s)),u=F(n,De);await R(u,l),c.info(`${x.dim(`generated`)} ${P(process.cwd(),u)} (${t.length} tab(s))`)}async function Ei(e,t,n,r){let i=String(e.$view.id);try{let a=ve(e,t[i]),o=F(n,i+`.drawio`);return await L(M(o),{recursive:!0}),await R(o,a),r.info(`${x.dim(`generated`)} ${P(process.cwd(),o)}`),!0}catch(e){return r.error(`Failed to export view ${i}`,{error:yi(e)}),!1}}async function Di(e){let{viewmodels:t,outdir:n,workspacePath:r,roundtrip:i,uncompressed:a,profile:o,projectId:s,logger:c}=e,l=wi(t,await Si(r,i,c),a,o,s),u=0;for(let e of t)await Ei(e,l,n,c)&&u++;return{succeeded:u}}async function Oi(e,t){try{var n=Y();let r=H(t),i=n.a(await v(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),o=await i.layoutedModel(a);if(o===Oe.EMPTY)throw t.error(gi),Error(gi);let s=[...o.views()];if(s.length===0)throw t.error(`No views to export`),Error(_i);await L(e.outdir,{recursive:!0});let c=String(o.projectId),l={viewmodels:s,outdir:e.outdir,workspacePath:e.path,roundtrip:e.roundtrip,uncompressed:e.uncompressed,profile:e.profile,projectId:c,logger:t};if(e.allInOne)try{await Ti(l)}catch(e){bi(t,`Failed to export DrawIO`,e)}else{let{succeeded:e}=await Di(l);if(e===0)throw t.error(_i),Error(_i);t.info(`${x.dim(`total`)} ${e} DrawIO file(s)`)}r.stopAndLog(`✓ export drawio in `)}catch(e){n.e=e}finally{await n.d()}}function ki(e){return e.command({command:`drawio [path]`,describe:`export view(s) to DrawIO (.drawio) for editing in draw.io`,builder:e=>e.positional(`path`,W).option(`outdir`,{alias:`o`,type:`string`,desc:`<dir> output directory for .drawio files`,normalize:!0,coerce:F}).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:q,"use-dot":G}).epilog(vi()),handler:async e=>{let t=V(`c4:export`);await Oi({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)}})}const Ai=`project not found`,ji=`No projects found`;async function Mi(e,t){try{var n=Y();let r=H(t),i=n.a(await v(e.path,{graphviz:e.useDot?`binary`:`wasm`,watch:!1})),o=[...i.projectsManager.all];if(e.project){if(o=o.filter(t=>t===e.project),!a(o,1))throw t.error(`${Ai}: ${e.project}`),Error(`${Ai}: ${e.project}`)}else{if(!a(o,1))throw t.error(ji),Error(ji);t.info(`${x.dim(`workspace:`)} Found ${o.length} projects`)}let s=[];for(let n of o){let r;if(e.skipLayout?(t.info(`Generate model for project ${x.green(n)} ${x.dim(`(skip layout)`)}`),r=await i.computedModel(n)):(t.info(`Generating layouted model for project ${x.green(n)}`),r=await i.layoutedModel(n)),r===Oe.EMPTY){t.warn(x.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;nt(c).toLowerCase()!==`.json`&&(c+=`.json`),await L(M(c),{recursive:!0});let l=s.length===1?s[0]:s,u=e.pretty?JSON.stringify(l,void 0,2):JSON.stringify(l);await R(c,u);let d=c.startsWith(e.path)?P(e.path,c):c;t.info(`${x.dim(`generated`)} ${d}`),r.stopAndLog(`✓ export in `)}catch(e){n.e=e}finally{await n.d()}}function Ni(e){return e.command({command:`json [path]`,describe:`export model(s) to JSON`,builder:e=>e.positional(`path`,W).option(`outfile`,{alias:`o`,type:`string`,desc:`<file> output .json file`,default:`likec4.json`,normalize:!0,coerce:F}).options({project:q,"use-dot":G,"skip-layout":{type:`boolean`,desc:`skip layouting (only compute model)`},pretty:{type:`boolean`,desc:`indented JSON output`}}).epilog(`${x.bold(`Examples:`)}
128
+ ${x.green(`$0 export json --skip-layout`)}
129
+ ${x.gray(`Search for likec4 files in current directory and output JSON to likec4.json (no layout)`)}
130
130
 
131
- ${y.green(`$0 export json --pretty -o ./generated/likec4.json src/likec4 `)}
132
- ${y.gray(`Search for likec4 files in src/likec4 and output JSON to generated/likec4.json`)}
133
- `),handler:async e=>{let t=B(`c4:export`);await $r({path:e.path,outfile:e.outfile,project:e.project,skipLayout:!!e.skipLayout,pretty:!!e.pretty,useDot:!!e[`use-dot`]},t),Y()}})}var ti=e(ee(),1);function ni(e){if(e.resolvedUrls)return i(e.resolvedUrls.network)??i(e.resolvedUrls.local)}function ri(e){if(!e.resolvedUrls)throw Error(`Vite server is not ready, no resolvedUrls`);H([y.green(`LikeC4 served at:`),``,y.dim(`Local: `)+e.resolvedUrls.local.join(`
134
- `+``.padEnd(9,` `)),e.resolvedUrls.network.length?y.dim(`Network: `)+e.resolvedUrls.network.join(`
131
+ ${x.green(`$0 export json --pretty -o ./generated/likec4.json src/likec4 `)}
132
+ ${x.gray(`Search for likec4 files in src/likec4 and output JSON to generated/likec4.json`)}
133
+ `),handler:async e=>{let t=V(`c4:export`);await Mi({path:e.path,outfile:e.outfile,project:e.project,skipLayout:!!e.skipLayout,pretty:!!e.pretty,useDot:!!e[`use-dot`]},t),J()}})}var Pi=e(he(),1);function Fi(e){if(e.resolvedUrls)return i(e.resolvedUrls.network)??i(e.resolvedUrls.local)}function Ii(e){if(!e.resolvedUrls)throw Error(`Vite server is not ready, no resolvedUrls`);U([x.green(`LikeC4 served at:`),``,x.dim(`Local: `)+e.resolvedUrls.local.join(`
134
+ `+``.padEnd(9,` `)),e.resolvedUrls.network.length?x.dim(`Network: `)+e.resolvedUrls.network.join(`
135
135
  `+``.padEnd(9,` `)):void 0].filter(e=>u(e)).join(`
136
- `))}async function ii({buildWebcomponent:e=!0,hmr:t=!0,webcomponentPrefix:n=`likec4`,title:r,languageServices:i,likec4AssetsDir:a,openBrowser:o,listen:s,port:c,...l}){a??=await qe(M(ze(),`.likec4-assets-`));let{isDev:u,...d}=await jt({...l,languageServices:i,likec4AssetsDir:a,webcomponentPrefix:n,title:r}),f=d.customLogger;c??=Be.PORT?parseInt(Be.PORT,10):void 0,c||=await Oe({port:[5173,5174,...De(61e3,61010),...De(62002,62010)]});let p=24678,m=await Dt(),h=s??(T()?`0.0.0.0`:`localhost`);t?(p=await Oe({port:De(24678,24690)}),f.info(`Enabling HMR: localhost:${p}`),T()&&f.info(y.yellow(`ensure port ${p} is published from container`))):f.info(`Disabling HMR`);let g=await ht({...d,define:t?{...d.define,"process.env.NODE_ENV":`"development"`}:d.define,mode:t?`development`:d.mode,publicDir:m,server:{host:h,allowedHosts:!0,port:c,hmr:t&&{overlay:!0,port:p},fs:{strict:!1},open:o??(!u&&!T())}});return e?(f.info(`Building webcomponent`),Mt({webcomponentPrefix:n,languageServices:i,outDir:m,base:d.base}).then(e=>R({...e,logLevel:`warn`})).catch(e=>{f.warn(_(e)),f.warn(`webcomponent build failed, ignoring error and continue`)})):f.info(`Skip webcomponent build`),await g.listen(),g}async function ai({browserContext:e,views:r,output:i,logger:a,timeout:o,maxAttempts:s,dynamicVariant:c,outputType:l,theme:u}){let d,f=r.map(e=>({view:e,attempt:1})),p=[],m;for(;m=f.shift();){let{view:r,attempt:h}=m,g=`export/${encodeURIComponent(r.id)}/`;try{if(h>1){d&&=(d.close({runBeforeUnload:!0}).catch(e=>a.error(`failed to close page: ${e}`)),void 0);let e=t(h*200,{min:200,max:1e3});a.info(y.cyan(g)+y.dim(` attempt ${h} of ${s} after ${e}ms`)),await _t(e)}else r.hasLayoutDrift&&a.warn(y.yellow(`Drift detected, manual layout can not be applied, view may be invalid: `)+y.red(r.id));let f=`.`;l===`relative`&&(f=r.sourcePath??`.`,f=f.includes(`/`)?f.slice(0,f.lastIndexOf(`/`)):`.`);let m=P(i,f,`${r.id}.png`);d??=await e.newPage();let _=r.bounds;c===`sequence`&&r._type===`dynamic`&&(_=r.sequenceLayout.bounds),await d.setViewportSize({width:_.width+40+20,height:_.height+40+20}),await d.goto(te(g,{padding:20,theme:u,dynamic:c})),a.info(y.cyan(g)+y.dim(` -> ${N(i,m)}`)),await d.waitForSelector(`.react-flow.initialized`),r.nodes.some(e=>n(e.icon)&&e.icon.toLowerCase().startsWith(`http`))&&await oi(d,o),await d.getByTestId(`export-page`).screenshot({animations:`disabled`,path:m,omitBackground:!0}),p.push({view:r,path:m})}catch(e){d?.close({runBeforeUnload:!0}).catch(e=>a.error(`failed to close page: ${e}`)),a.error(y.red(`failed `+g+`
137
- `+e)),h<s&&(f.push({view:r,attempt:h+1}),a.info(y.dim(`retry ${g}`))),d=void 0}}return p}async function oi(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 si({logger:e,serverUrl:t,theme:n=`light`,timeoutMs:r=15e3,views:i,output:a,outputType:o=`relative`,maxAttempts:s=3,chromiumSandbox:c=!1,sequence:l=!1}){e.info(`${y.dim(`output`)} ${a}`),e.info(`${y.dim(`base url`)} ${t}\n`);let{chromium:u}=await import(`playwright`),d=u.executablePath();e.info(y.cyan(`Start chromium`)+` `+y.dim(d));let f=await u.launch({chromiumSandbox:c,headless:!0});e.info(y.cyan(`Color scheme: `)+n+`
138
- `);let p=await f.newContext({deviceScaleFactor:2,colorScheme:n,baseURL:t,bypassCSP:!0,ignoreHTTPSErrors:!0,isMobile:!1});p.setDefaultNavigationTimeout(r),p.setDefaultTimeout(r);try{return await ai({browserContext:p,views:i,output:a,outputType:o,logger:e,maxAttempts:s,dynamicVariant:l?`sequence`:`diagram`,timeout:r,theme:n})}finally{e.info(y.cyan(`close chromium`)),await p.close(),await f.close()}}async function ci(e,t){try{var n=X();let{path:r,useDotBin:i,project:o,theme:s=`light`,output:c,outputType:l,serverUrl:u,ignore:d=!1,timeoutMs:f=15e3,maxAttempts:p=3,filter:m,sequence:h=!1,chromiumSandbox:g=!1}=e,_=n.a(await C(r,{graphviz:i?`binary`:`wasm`,watch:!1})),v=c??_.workspace,b,x=u,S=[..._.languageServices.projects()];if(o&&!S.some(e=>e.id===o))throw t.error(`project not found: ${o}`),Error(`project not found: ${o}`);try{if(!x&&(t.info(y.cyan(`start preview server`)),b=await ii({languageServices:_,buildWebcomponent:!1,openBrowser:!1,hmr:!1}),x=ni(b),!x))throw t.error(`Vite server is not ready, no resolvedUrls`),Error(`Vite server is not ready, no resolvedUrls`);for(let e of S){if(o&&e.id!==o)continue;S.length>1&&(t.info(y.dim(`---------`)),t.info(`${y.dim(`project:`)} ${e.id}`),t.info(`${y.dim(`folder:`)} ${e.folder.fsPath}`));let n=await _.diagrams(e.id);if(m&&a(m,1)&&a(n,1)){let e=(0,ti.default)(m);t.info(`${y.cyan(`filter`)} ${y.dim(JSON.stringify(m))}`),n=n.filter(n=>e(n.id)?(t.info(`${y.green(`include`)} ${n.id} ✅`),!0):(t.info(`${y.gray(`skip`)} ${y.dim(n.id)}`),!1))}if(!a(n,1)){t.warn(`no views found`);continue}let r=S.length>1?ne(re(x,`project`,e.id)):x,i=S.length>1?re(v,e.id):v,c=ct(),u=await si({logger:t,serverUrl:r,theme:s,timeoutMs:f,views:n,output:i,outputType:l,maxAttempts:p,sequence:h,chromiumSandbox:g}),{pretty:b}=xt(c);if(u.length>0&&t.info(y.green(`exported ${u.length} views in ${b}`)+`
139
- `),u.length!==n.length&&(d&&u.length>0?t.info(y.dim(`ignore`)+` `+y.red(`failed ${n.length-u.length} out of ${n.length} views`)):t.error(y.red(`failed ${n.length-u.length} out of ${n.length} views`))),u.length!==n.length&&(u.length===0||!d))throw Error(`Failed ${n.length-u.length} out of ${n.length} views`)}}finally{b&&(t.info(y.cyan(`stop server`)),await b.close().catch(e=>{t.error(e)}))}}catch(e){n.e=e}finally{await n.d()}}async function li(e){await ci(e,B(`c4:export`))}function ui(e){return e.command({command:`png [path]`,describe:`export views to PNG`,builder:e=>e.positional(`path`,W).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:P},project:q,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":G,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
140
- 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(`${y.bold(`Examples:`)}
141
- ${y.green(`$0 export png`)}
142
- ${y.gray(`Search for likec4 files in current directory and output PNG next to sources`)}
143
-
144
- ${y.green(`$0 export png --theme dark -o ./png src/likec4`)}
145
- ${y.gray(`Search for likec4 files in src/likec4 and output PNG with dark theme to png folder`)}
146
-
147
- ${y.green(`$0 export png -f "team1*" -f "team2*" --flat -o ./png src/likec4`)}
148
- ${y.gray(`Export views matching team1* or team2* only`)}
149
-
150
- ${y.green(`$0 export png -f "use-case*" --sequence src/likec4`)}
151
- ${y.gray(`Export views matching use-case* using sequence layout`)}
152
- `),handler:async e=>{Ie(e.timeout>=1,`timeout must be >= 1`),Ie(e[`max-attempts`]>=1,`max-attempts must be >= 1`),await U(),await It();let t=e.theme??(e.dark?`dark`:`light`);await li({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`]}),Y()}})}const di=e=>e.command({command:`export <format> [path]`,describe:`Export to images, JSON, or DrawIO`,builder:e=>o(e.usage(`${y.bold(`Usage:`)} $0 export <format> [path]`),ui,ei,Xr).updateStrings({"Commands:":y.bold(`Formats:`)}),handler:()=>void 0}),fi=e=>e.command({command:`format [path]`,aliases:[`fmt`],describe:`Format LikeC4 source files`,builder:e=>e.positional(`path`,W).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=>P(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=X();let n=B(`c4:format`),r=V(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 o=e.project?.filter(Boolean),s=e.files?.filter(Boolean).map(e=>ft(e).toString());if(n.debug(`workspace: ${e.path}`),o?.length){n.debug(`projects:`);for(let e of o)n.debug(` ${e}`)}if(s?.length){n.debug(`files:`);for(let e of s)n.debug(` ${L(e)}`)}let c;try{c=await a.format({...o?.length&&{projects:o},...s?.length&&{documentUris:s}})}catch(e){n.error(e instanceof Error?e.message:String(e)),process.exitCode=1;return}n.debug(`${c.size} document(s) to process`);let l=process.cwd(),u=e=>{let t=N(l,e);return t.startsWith(`..`)?e:t};if(s){let e=s.filter(e=>!c.has(e));for(let t of e)n.warn(`${y.yellow(`skipped`)} ${u(L(t))} (not found in workspace)`)}let d=0,f=0,p=[];for(let[e,t]of c){let r=L(e),a=u(r),o;try{o=await O(r,`utf-8`)}catch(e){n.error(`Failed to read ${a}: ${e}`),f++;continue}if(o===t){n.debug(`${y.dim(`unchanged`)} ${a}`);continue}if(d++,p.push(a),i)n.info(`${y.yellow(`needs formatting`)} ${a}`);else try{await k(r,t,`utf-8`),n.info(`${y.green(`formatted`)} ${a}`)}catch(e){n.error(`Failed to write ${a}: ${e}`),f++}}if(f>0){n.error(`${f} file(s) failed to process`),process.exitCode=1;return}if(i){if(d>0){n.error(`${d} of ${c.size} file(s) need formatting:\n${p.map(e=>` ${e}`).join(`
153
- `)}`),process.exitCode=1;return}n.info(y.green(`All ${c.size} file(s) are formatted`))}else d>0?n.info(`${y.green(String(d))} of ${c.size} file(s) formatted`):n.info(y.green(`All ${c.size} file(s) already formatted`));r.stopAndLog(`✓ format in `)}catch(e){t.e=e}finally{await t.d()}}});var pi=ke();function mi(e){return e.command({command:`lsp`,aliases:[],describe:`Start LSP server`,builder:e=>e.usage(`${y.bold(`Usage:`)} $0 lsp`).option(`log-level`,Gt).option(`verbose`,Kt).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`,G).showHidden().epilog(`${y.bold(`Examples:`)}
154
-
155
- ${y.green(`$0 lsp --stdio `)}
156
- ${y.gray(`Start LSP with stdio transport`)}
157
-
158
- ${y.green(`$0 lsp --node-ipc --watch --no-manual-layouts --no-color `)}
159
- ${y.gray(`Start LSP with node-ipc transport and watcher, disabled manual layouts and disabled color`)}
160
-
161
- `),handler:e=>{let t;if(e.nodeIpc||e.stdio||e.socket||e.pipe)t=(0,pi.createConnection)(pi.ProposedFeatures.all);else throw Error(`No transport specified`);h({lspConnection:t,useStdErr:e.stdio===!0,colors:y.isColorSupported,enableTelemetry:e.telemetry,logLevel:e.verbose?qt:e.logLevel}),m({connection:t,enableManualLayouts:e.manualLayouts,enableWatcher:e.watch,graphviz:e.useDot?`binary`:`wasm`,configureLogger:!1})}})}const hi=e=>e.command({command:`mcp [path]`,aliases:[],describe:`Start MCP server`,builder:e=>e.usage(`${y.bold(`Usage:`)} $0 mcp [path]`).positional(`path`,W).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`,G).option(`log-level`,Gt).option(`verbose`,Kt).showHidden().epilog(`${y.bold(`Examples:`)}
162
- ${y.green(`$0 mcp`)}
163
- ${y.gray(`Start MCP with default stdio transport`)}
164
- ${y.green(`$0 mcp --http ./src`)}
165
- ${y.gray(`Start MCP with streamable http transport on port 33335 at ./src folder`)}
166
- ${y.green(`$0 mcp -p 1234`)}
167
- ${y.gray(`Start MCP with streamable http transport on port 1234`)}
168
- `),handler:async e=>{e.http||e.port?(h({colors:y.isColorSupported,logLevel:e.verbose?qt:e.logLevel}),await gi(e.path,e.useDot,e.port)):(h({useStdErr:!0,logLevel:e.verbose?qt:e.logLevel}),await _i(e.path,e.useDot))}});async function gi(e,t,n=33335){await Ee(e,{mcp:{port:n},watch:!0,configureLogger:!1,graphviz:t?`binary`:`wasm`}),H([y.green(`LikeC4 MCP served at:`),`
136
+ `))}async function Li({buildWebcomponent:e=!0,hmr:t=!0,webcomponentPrefix:n=`likec4`,title:r,languageServices:i,likec4AssetsDir:a,openBrowser:o,listen:s,port:c,...l}){a??=await gt(N(lt(),`.likec4-assets-`));let{isDev:u,...d}=await tn({...l,languageServices:i,likec4AssetsDir:a,webcomponentPrefix:n,title:r}),f=d.customLogger;c??=ut.PORT?parseInt(ut.PORT,10):void 0,c||=await Ue({port:[5173,5174,...He(61e3,61010),...He(62002,62010)]});let p=24678,m=await Zt(),g=s??(S()?`0.0.0.0`:`localhost`);t?(p=await Ue({port:He(24678,24690)}),f.info(`Enabling HMR: localhost:${p}`),S()&&f.info(x.yellow(`ensure port ${p} is published from container`))):f.info(`Disabling HMR`);let _=await zt({...d,define:t?{...d.define,"process.env.NODE_ENV":`"development"`}:d.define,mode:t?`development`:d.mode,publicDir:m,server:{host:g,allowedHosts:!0,port:c,hmr:t&&{overlay:!0,port:p},fs:{strict:!1},open:o??(!u&&!S())}});return e?(f.info(`Building webcomponent`),nn({webcomponentPrefix:n,languageServices:i,outDir:m,base:d.base}).then(e=>Rt({...e,logLevel:`warn`})).catch(e=>{f.warn(h(e)),f.warn(`webcomponent build failed, ignoring error and continue`)})):f.info(`Skip webcomponent build`),await _.listen(),_}async function Ri({browserContext:e,views:r,output:i,logger:a,timeout:o,maxAttempts:s,dynamicVariant:c,outputType:l,theme:u}){let d,f=r.map(e=>({view:e,attempt:1})),p=[],m;for(;m=f.shift();){let{view:r,attempt:h}=m,g=`export/${encodeURIComponent(r.id)}/`;try{if(h>1){d&&=(d.close({runBeforeUnload:!0}).catch(e=>a.error(`failed to close page: ${e}`)),void 0);let e=t(h*200,{min:200,max:1e3});a.info(x.cyan(g)+x.dim(` attempt ${h} of ${s} after ${e}ms`)),await Vt(e)}else r.hasLayoutDrift&&a.warn(x.yellow(`Drift detected, manual layout can not be applied, view may be invalid: `)+x.red(r.id));let f=`.`;l===`relative`&&(f=r.sourcePath??`.`,f=f.includes(`/`)?f.slice(0,f.lastIndexOf(`/`)):`.`);let m=F(i,f,`${r.id}.png`);d??=await e.newPage();let _=r.bounds;c===`sequence`&&r._type===`dynamic`&&(_=r.sequenceLayout.bounds),await d.setViewportSize({width:_.width+40+20,height:_.height+40+20}),await d.goto(ae(g,{padding:20,theme:u,dynamic:c})),a.info(x.cyan(g)+x.dim(` -> ${P(i,m)}`)),await d.waitForSelector(`.react-flow.initialized`),r.nodes.some(e=>n(e.icon)&&e.icon.toLowerCase().startsWith(`http`))&&await zi(d,o),await d.getByTestId(`export-page`).screenshot({animations:`disabled`,path:m,omitBackground:!0}),p.push({view:r,path:m})}catch(e){d?.close({runBeforeUnload:!0}).catch(e=>a.error(`failed to close page: ${e}`)),a.error(x.red(`failed `+g+`
137
+ `+e)),h<s&&(f.push({view:r,attempt:h+1}),a.info(x.dim(`retry ${g}`))),d=void 0}}return p}async function zi(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 Bi({logger:e,serverUrl:t,theme:n=`light`,timeoutMs:r=15e3,views:i,output:a,outputType:o=`relative`,maxAttempts:s=3,chromiumSandbox:c=!1,sequence:l=!1}){e.info(`${x.dim(`output`)} ${a}`),e.info(`${x.dim(`base url`)} ${t}\n`);let{chromium:u}=await import(`playwright`),d=u.executablePath();e.info(x.cyan(`Start chromium`)+` `+x.dim(d));let f=await u.launch({chromiumSandbox:c,headless:!0});e.info(x.cyan(`Color scheme: `)+n+`
138
+ `);let p=await f.newContext({deviceScaleFactor:2,colorScheme:n,baseURL:t,bypassCSP:!0,ignoreHTTPSErrors:!0,isMobile:!1});p.setDefaultNavigationTimeout(r),p.setDefaultTimeout(r);try{return await Ri({browserContext:p,views:i,output:a,outputType:o,logger:e,maxAttempts:s,dynamicVariant:l?`sequence`:`diagram`,timeout:r,theme:n})}finally{e.info(x.cyan(`close chromium`)),await p.close(),await f.close()}}async function Vi(e,t){try{var n=Y();let{path:r,useDotBin:i,project:o,theme:s=`light`,output:c,outputType:l,serverUrl:u,ignore:d=!1,timeoutMs:f=15e3,maxAttempts:p=3,filter:m,sequence:h=!1,chromiumSandbox:g=!1}=e,_=n.a(await v(r,{graphviz:i?`binary`:`wasm`,watch:!1})),y=c??_.workspace,ee,b=u,te=[..._.languageServices.projects()];if(o&&!te.some(e=>e.id===o))throw t.error(`project not found: ${o}`),Error(`project not found: ${o}`);try{if(!b&&(t.info(x.cyan(`start preview server`)),ee=await Li({languageServices:_,buildWebcomponent:!1,openBrowser:!1,hmr:!1}),b=Fi(ee),!b))throw t.error(`Vite server is not ready, no resolvedUrls`),Error(`Vite server is not ready, no resolvedUrls`);for(let e of te){if(o&&e.id!==o)continue;te.length>1&&(t.info(x.dim(`---------`)),t.info(`${x.dim(`project:`)} ${e.id}`),t.info(`${x.dim(`folder:`)} ${e.folder.fsPath}`));let n=await _.diagrams(e.id);if(m&&a(m,1)&&a(n,1)){let e=(0,Pi.default)(m);t.info(`${x.cyan(`filter`)} ${x.dim(JSON.stringify(m))}`),n=n.filter(n=>e(n.id)?(t.info(`${x.green(`include`)} ${n.id} ✅`),!0):(t.info(`${x.gray(`skip`)} ${x.dim(n.id)}`),!1))}if(!a(n,1)){t.warn(`no views found`);continue}let r=te.length>1?oe(se(b,`project`,e.id)):b,i=te.length>1?se(y,e.id):y,c=At(),u=await Bi({logger:t,serverUrl:r,theme:s,timeoutMs:f,views:n,output:i,outputType:l,maxAttempts:p,sequence:h,chromiumSandbox:g}),{pretty:v}=Gt(c);if(u.length>0&&t.info(x.green(`exported ${u.length} views in ${v}`)+`
139
+ `),u.length!==n.length&&(d&&u.length>0?t.info(x.dim(`ignore`)+` `+x.red(`failed ${n.length-u.length} out of ${n.length} views`)):t.error(x.red(`failed ${n.length-u.length} out of ${n.length} views`))),u.length!==n.length&&(u.length===0||!d))throw Error(`Failed ${n.length-u.length} out of ${n.length} views`)}}finally{ee&&(t.info(x.cyan(`stop server`)),await ee.close().catch(e=>{t.error(e)}))}}catch(e){n.e=e}finally{await n.d()}}async function Hi(e){await Vi(e,V(`c4:export`))}function Ui(e){return e.command({command:`png [path]`,describe:`export views to PNG`,builder:e=>e.positional(`path`,W).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:F},project:q,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":G,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
140
+ 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(`${x.bold(`Examples:`)}
141
+ ${x.green(`$0 export png`)}
142
+ ${x.gray(`Search for likec4 files in current directory and output PNG next to sources`)}
143
+
144
+ ${x.green(`$0 export png --theme dark -o ./png src/likec4`)}
145
+ ${x.gray(`Search for likec4 files in src/likec4 and output PNG with dark theme to png folder`)}
146
+
147
+ ${x.green(`$0 export png -f "team1*" -f "team2*" --flat -o ./png src/likec4`)}
148
+ ${x.gray(`Export views matching team1* or team2* only`)}
149
+
150
+ ${x.green(`$0 export png -f "use-case*" --sequence src/likec4`)}
151
+ ${x.gray(`Export views matching use-case* using sequence layout`)}
152
+ `),handler:async e=>{j(e.timeout>=1,`timeout must be >= 1`),j(e[`max-attempts`]>=1,`max-attempts must be >= 1`),await sn(),await cn();let t=e.theme??(e.dark?`dark`:`light`);await Hi({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`]}),J()}})}const Wi=e=>e.command({command:`export <format> [path]`,describe:`Export to images, JSON, or DrawIO`,builder:e=>o(e.usage(`${x.bold(`Usage:`)} $0 export <format> [path]`),Ui,Ni,ki).updateStrings({"Commands:":x.bold(`Formats:`)}),handler:()=>void 0}),Gi=e=>e.command({command:`format [path]`,aliases:[`fmt`],describe:`Format LikeC4 source files`,builder:e=>e.positional(`path`,W).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=>F(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=Y();let n=V(`c4:format`),r=H(n),i=e.check,a;try{a=await v(e.path,{watch:!1})}catch(e){n.error(e instanceof Error?e.message:String(e)),process.exitCode=1;return}t.a(a);let o=e.project?.filter(Boolean),s=e.files?.filter(Boolean).map(e=>Ft(e).toString());if(n.debug(`workspace: ${e.path}`),o?.length){n.debug(`projects:`);for(let e of o)n.debug(` ${e}`)}if(s?.length){n.debug(`files:`);for(let e of s)n.debug(` ${Pt(e)}`)}let c;try{c=await a.format({...o?.length&&{projects:o},...s?.length&&{documentUris:s}})}catch(e){n.error(e instanceof Error?e.message:String(e)),process.exitCode=1;return}n.debug(`${c.size} document(s) to process`);let l=process.cwd(),u=e=>{let t=P(l,e);return t.startsWith(`..`)?e:t};if(s){let e=s.filter(e=>!c.has(e));for(let t of e)n.warn(`${x.yellow(`skipped`)} ${u(Pt(t))} (not found in workspace)`)}let d=0,f=0,p=[];for(let[e,t]of c){let r=Pt(e),a=u(r),o;try{o=await _t(r,`utf-8`)}catch(e){n.error(`Failed to read ${a}: ${e}`),f++;continue}if(o===t){n.debug(`${x.dim(`unchanged`)} ${a}`);continue}if(d++,p.push(a),i)n.info(`${x.yellow(`needs formatting`)} ${a}`);else try{await R(r,t,`utf-8`),n.info(`${x.green(`formatted`)} ${a}`)}catch(e){n.error(`Failed to write ${a}: ${e}`),f++}}if(f>0){n.error(`${f} file(s) failed to process`),process.exitCode=1;return}if(i){if(d>0){n.error(`${d} of ${c.size} file(s) need formatting:\n${p.map(e=>` ${e}`).join(`
153
+ `)}`),process.exitCode=1;return}n.info(x.green(`All ${c.size} file(s) are formatted`))}else d>0?n.info(`${x.green(String(d))} of ${c.size} file(s) formatted`):n.info(x.green(`All ${c.size} file(s) already formatted`));r.stopAndLog(`✓ format in `)}catch(e){t.e=e}finally{await t.d()}}}),Ki=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:g,description:`Filter icons by group`}),handler:e=>{let t=e.group?[e.group]:g;switch(!0){case e.format===`json`:{let e=Object.fromEntries(t.map(e=>[e,f[e]]));console.log(JSON.stringify(e,null,2));break}default:for(let e of t)for(let t of f[e])console.log(`${e}:${t}`)}}});var qi=We();function Ji(e){return e.command({command:`lsp`,aliases:[],describe:`Start LSP server`,builder:e=>e.usage(`${x.bold(`Usage:`)} $0 lsp`).option(`log-level`,vn).option(`verbose`,yn).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`,G).showHidden().epilog(`${x.bold(`Examples:`)}
154
+
155
+ ${x.green(`$0 lsp --stdio `)}
156
+ ${x.gray(`Start LSP with stdio transport`)}
157
+
158
+ ${x.green(`$0 lsp --node-ipc --watch --no-manual-layouts --no-color `)}
159
+ ${x.gray(`Start LSP with node-ipc transport and watcher, disabled manual layouts and disabled color`)}
160
+
161
+ `),handler:e=>{let t;if(e.nodeIpc||e.stdio||e.socket||e.pipe)t=(0,qi.createConnection)(qi.ProposedFeatures.all);else throw Error(`No transport specified`);y({lspConnection:t,useStdErr:e.stdio===!0,colors:x.isColorSupported,enableTelemetry:e.telemetry,logLevel:e.verbose?bn:e.logLevel}),ee({connection:t,enableManualLayouts:e.manualLayouts,enableWatcher:e.watch,graphviz:e.useDot?`binary`:`wasm`,configureLogger:!1})}})}const X=p.getChild(`mcp`);function Z(e,t){let{name:n,description:r,...i}=e;return e=>[n,{description:r?.trim()??``,...i},Yi(n,e,t)]}function Yi(e,t,n){let r=n.bind(null,t);return(async function t(n,i){X.debug(`Calling tool {name}, args: {args}`,{name:e,args:n});try{let e=await r.call(null,n,i);return typeof e==`string`?{content:[{type:`text`,text:e}]}:{content:[{type:`text`,text:JSON.stringify(e)}],structuredContent:e}}catch(t){return X.error(`Tool ${e} failed`,{err:t}),{content:[{type:`text`,text:h(t)}],isError:!0}}})}var Xi=`1.55.0`;const Zi=w({name:A().describe(`Project identifier`),title:A().optional().describe(`Human-readable project title`),contactPerson:A().optional().describe(`Maintainer contact information`),metadata:E(A(),Ie()).optional().describe(`Custom project metadata as key-value pairs`),extends:T([A(),D(A())]).optional().describe(`Style inheritance paths`),exclude:D(A()).optional().describe(`File exclusion patterns`),include:w({paths:D(A()).describe(`Include paths`),maxDepth:k().describe(`Maximum directory depth`),fileThreshold:k().describe(`File threshold`)}).optional().describe(`Include configuration`),manualLayouts:w({outDir:A().describe(`Output directory for manual layouts`)}).optional().describe(`Manual layouts configuration`),styles:w({hasTheme:O().describe(`Whether theme customization is defined`),hasDefaults:O().describe(`Whether default style values are defined`),hasCustomCss:O().describe(`Whether custom CSS is defined`)}).optional().describe(`Simplified styles configuration (boolean flags)`)});function Qi(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 $i=w({id:A().describe(`Element id (FQN)`),name:A().describe(`Element name`),kind:A().describe(`Element kind`),title:A(),tags:D(A()),metadata:E(T([A(),D(A())])),includedInViews:D(w({id:A().describe(`View id`),title:A().describe(`View title`),type:C([`element`,`deployment`,`dynamic`]).describe(`View type`)})).describe(`Views that include this element`)});function Q(e){return{id:e.id,name:e.name,kind:e.kind,title:e.title,tags:[...e.tags],metadata:e.getMetadata(),includedInViews:ra(e.views())}}function ea(e,t,n,r,i,a){j(e.findElement(t),`Element "${t}" not found`);let o=new Set,s={},c=0,l=!1,u=[{elementId:t,depth:0}];for(;u.length>0;){let{elementId:t,depth:d}=u.shift();if(d>i||o.has(t))continue;if(o.size>=a){l=!0;break}let f=e.findElement(t);if(!f)continue;o.add(t),c=Math.max(c,d);let p=(n===`incoming`?[...f.incoming(r)]:[...f.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});s[t]={...Q(f),neighbors:p,depth:d};for(let e of p)o.has(e.elementId)||u.push({elementId:e.elementId,depth:d+1})}for(let e of Object.values(s))e.neighbors=e.neighbors.filter(e=>e.elementId in s);return{target:t,totalNodes:o.size,maxDepth:c,truncated:l,nodes:s}}const ta=w({path:A().describe(`Path to the file`),range:w({start:w({line:k(),character:k()}),end:w({line:k(),character:k()})}).describe(`Range in the file`)}).nullable(),$=A().refine(e=>!0).optional().default(`default`).describe(`Project id (optional, will use "default" if not specified)`),na=D(w({id:A().describe(`View id`),title:A().describe(`View title`),type:C([`element`,`deployment`,`dynamic`]).describe(`View type`)})),ra=e=>[...e].map(e=>({id:e.id,title:e.titleOrId,type:e.$view._type})),ia=(e,t)=>n=>{try{let r=e.locate({projectId:t,...n});return r?{path:re.parse(r.uri).fsPath,range:r.range}:null}catch(e){return X.debug(`Failed to locate {params}`,{error:e,params:n}),null}},aa=$i.extend({description:A().nullable().describe(`Element description`),technology:A().nullable().describe(`Element technology`),shape:A().describe(`Rendered shape`),color:A().describe(`Rendered color`),children:D(A()).describe(`Direct child element ids`),incomingCount:k().describe(`Number of incoming relationships`),outgoingCount:k().describe(`Number of outgoing relationships`)}),oa=Z({name:`batch-read-elements`,description:`
162
+ Read details of multiple elements in a single call, reducing round-trips.
163
+ Returns a compact summary for each element including metadata, description, technology, shape, children, and relationship counts.
164
+
165
+ Request:
166
+ - ids: string[] — array of element ids (FQNs) to read (max 50)
167
+ - project: string (optional) project id. Defaults to "default" if omitted.
168
+
169
+ Response (JSON object):
170
+ - elements: Array of element details, each with:
171
+ - id: string — element id (FQN)
172
+ - name: string — element name
173
+ - kind: string — element kind
174
+ - title: string — human-readable title
175
+ - description: string|null — optional description
176
+ - technology: string|null — optional technology
177
+ - tags: string[] — assigned tags
178
+ - metadata: Record<string, string | string[]> — element metadata
179
+ - shape: string — rendered shape
180
+ - color: string — rendered color
181
+ - children: string[] — direct child element ids
182
+ - incomingCount: number — number of incoming relationships
183
+ - outgoingCount: number — number of outgoing relationships
184
+ - includedInViews: View[] — views that include this element
185
+ - notFound: string[] — ids that were not found in the project
186
+
187
+ View (object) fields:
188
+ - id: string — view identifier
189
+ - title: string — view title
190
+ - type: "element" | "deployment" | "dynamic"
191
+
192
+ Notes:
193
+ - Read-only, idempotent, no side effects.
194
+ - Safe to call repeatedly.
195
+ - Maximum 50 element ids per call.
196
+ - Elements not found are listed in notFound array (not an error).
197
+ - More efficient than multiple read-element calls when you need summary data for many elements.
198
+
199
+ Example response:
200
+ {
201
+ "elements": [
202
+ {
203
+ "id": "shop.frontend",
204
+ "name": "frontend",
205
+ "kind": "container",
206
+ "title": "Frontend",
207
+ "description": "User-facing web app",
208
+ "technology": "React",
209
+ "tags": ["public"],
210
+ "metadata": { "owner": "web-team" },
211
+ "shape": "browser",
212
+ "color": "#2F80ED",
213
+ "children": ["shop.frontend.auth"],
214
+ "incomingCount": 2,
215
+ "outgoingCount": 3,
216
+ "includedInViews": [
217
+ { "id": "system-overview", "title": "System Overview", "type": "element" }
218
+ ]
219
+ }
220
+ ],
221
+ "notFound": []
222
+ }
223
+ `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Batch read elements`},inputSchema:{ids:D(A()).min(1).max(50).describe(`Array of element ids (FQNs) to read (max 50)`),project:$},outputSchema:{elements:D(aa),notFound:D(A()).describe(`Element ids that were not found`)}},async(e,t)=>{j(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({...Q(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}}),sa=w({id:A(),kind:A(),title:A(),description:A().nullable(),technology:A().nullable(),shape:A(),color:A()}),ca=w({element1:sa,element2:sa,propertyDiffs:D(w({property:A().describe(`Property name`),element1Value:A().nullable().describe(`Value in element1`),element2Value:A().nullable().describe(`Value in element2`)})).describe(`Properties that differ between the two elements`),tags:w({onlyInElement1:D(A()).describe(`Tags present only in element1`),onlyInElement2:D(A()).describe(`Tags present only in element2`),common:D(A()).describe(`Tags present in both elements`)}),metadata:w({onlyInElement1:E(T([A(),D(A())])).describe(`Metadata keys only in element1`),onlyInElement2:E(T([A(),D(A())])).describe(`Metadata keys only in element2`),different:D(w({key:A(),element1Value:T([A(),D(A())]),element2Value:T([A(),D(A())])})).describe(`Metadata keys present in both but with different values`),common:E(T([A(),D(A())])).describe(`Metadata keys with identical values in both`)}),relationships:w({incomingOnlyElement1:k().describe(`Count of unique source elements sending to element1 only`),incomingOnlyElement2:k().describe(`Count of unique source elements sending to element2 only`),incomingShared:k().describe(`Count of unique source elements sending to both`),outgoingOnlyElement1:k().describe(`Count of unique target elements receiving from element1 only`),outgoingOnlyElement2:k().describe(`Count of unique target elements receiving from element2 only`),outgoingShared:k().describe(`Count of unique target elements receiving from both`)})}),la=Z({name:`element-diff`,description:`
224
+ Compare two elements side-by-side, showing differences in properties, tags, metadata, and relationships.
225
+
226
+ Request:
227
+ - element1Id: string — first element id (FQN)
228
+ - element2Id: string — second element id (FQN)
229
+ - project: string (optional) — project id. Defaults to "default" if omitted.
230
+
231
+ Response (JSON object):
232
+ - element1: object — snapshot of first element (id, kind, title, description, technology, shape, color)
233
+ - element2: object — snapshot of second element
234
+ - propertyDiffs: Array of { property, element1Value, element2Value } — properties that differ
235
+ - tags: object
236
+ - onlyInElement1: string[] — tags only in element1
237
+ - onlyInElement2: string[] — tags only in element2
238
+ - common: string[] — tags in both
239
+ - metadata: object
240
+ - onlyInElement1: Record — metadata keys only in element1
241
+ - onlyInElement2: Record — metadata keys only in element2
242
+ - different: Array of { key, element1Value, element2Value } — keys present in both but with different values
243
+ - common: Record — metadata keys with identical values in both
244
+ - relationships: object — relationship count comparison
245
+ - incomingOnlyElement1/incomingOnlyElement2/incomingShared
246
+ - outgoingOnlyElement1/outgoingOnlyElement2/outgoingShared
247
+
248
+ Notes:
249
+ - Read-only, idempotent, no side effects.
250
+ - Safe to call repeatedly.
251
+ - Both elements must exist in the same project.
252
+ - Useful for comparing similar nodes to understand why they have different configurations.
253
+
254
+ Example response:
255
+ {
256
+ "element1": { "id": "planner.nodeA", "kind": "cgf-node", "title": "nodeA", ... },
257
+ "element2": { "id": "planner.nodeB", "kind": "cgf-node", "title": "nodeB", ... },
258
+ "propertyDiffs": [
259
+ { "property": "title", "element1Value": "nodeA :dwNodeTypeA", "element2Value": "nodeB :dwNodeTypeB" }
260
+ ],
261
+ "tags": {
262
+ "onlyInElement1": ["target_asil_qm"],
263
+ "onlyInElement2": ["target_asil_asil_b"],
264
+ "common": ["is_in_dag", "process_camera_master"]
265
+ },
266
+ "metadata": {
267
+ "onlyInElement1": {},
268
+ "onlyInElement2": {},
269
+ "different": [
270
+ { "key": "target_asil", "element1Value": "QM", "element2Value": "ASIL-B" }
271
+ ],
272
+ "common": { "host": "machine0" }
273
+ },
274
+ "relationships": {
275
+ "incomingOnlyElement1": 2,
276
+ "incomingOnlyElement2": 1,
277
+ "incomingShared": 3,
278
+ "outgoingOnlyElement1": 0,
279
+ "outgoingOnlyElement2": 1,
280
+ "outgoingShared": 2
281
+ }
282
+ }
283
+ `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Compare two elements`},inputSchema:{element1Id:A().describe(`First element id (FQN)`),element2Id:A().describe(`Second element id (FQN)`),project:$},outputSchema:ca.shape},async(e,t)=>{let n=e.projectsManager.ensureProjectId(t.project),r=await e.computedModel(n),i=r.findElement(t.element1Id);j(i,`Element "${t.element1Id}" not found in project "${n}"`);let a=r.findElement(t.element2Id);j(a,`Element "${t.element2Id}" not found in project "${n}"`);let o=[],s=[{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 s){let t=e.get(i),n=e.get(a);t!==n&&o.push({property:e.name,element1Value:t,element2Value:n})}let c=new Set(i.tags),l=new Set(a.tags),u=[],d=[],f=[];for(let e of c)l.has(e)?u.push(e):d.push(e);for(let e of l)c.has(e)||f.push(e);let p=i.getMetadata(),m=a.getMetadata(),h=new Set([...Object.keys(p),...Object.keys(m)]),g={},_={},v=[],y={};for(let e of h){let t=p[e],n=m[e];t!==void 0&&n===void 0?g[e]=t:t===void 0&&n!==void 0?_[e]=n:t!==void 0&&n!==void 0&&(JSON.stringify(t)===JSON.stringify(n)?y[e]=t:v.push({key:e,element1Value:t,element2Value:n}))}let ee=new Set([...i.incoming()].map(e=>e.source.id)),b=new Set([...a.incoming()].map(e=>e.source.id)),te=new Set([...i.outgoing()].map(e=>e.target.id)),ne=new Set([...a.outgoing()].map(e=>e.target.id)),re=0,ie=0,x=0;for(let e of ee)b.has(e)?re++:ie++;for(let e of b)ee.has(e)||x++;let ae=0,oe=0,se=0;for(let e of te)ne.has(e)?ae++:oe++;for(let e of ne)te.has(e)||se++;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:o,tags:{onlyInElement1:d,onlyInElement2:f,common:u},metadata:{onlyInElement1:g,onlyInElement2:_,different:v,common:y},relationships:{incomingOnlyElement1:ie,incomingOnlyElement2:x,incomingShared:re,outgoingOnlyElement1:oe,outgoingOnlyElement2:se,outgoingShared:ae}}}),ua=Z({name:`find-relationship-paths`,description:`
284
+ Discover all paths (chains of relationships) between two elements, supporting multi-hop traversal.
285
+
286
+ Request:
287
+ - sourceId: string — source element FQN
288
+ - targetId: string — target element FQN
289
+ - maxDepth: number (optional, default: 3, max: 5) — maximum path length (number of hops)
290
+ - includeIndirect: boolean (optional, default: false) — include indirect (implied) relationships through nested elements
291
+ - project: string (optional) — project id. Defaults to "default" if omitted.
292
+
293
+ Algorithm:
294
+ - Uses breadth-first search (BFS) to find all paths
295
+ - Prevents cycles with visited set per path
296
+ - Paths are sorted by length (shortest first)
297
+ - Limited to 100 paths to avoid overwhelming responses
298
+
299
+ Response (JSON object):
300
+ - paths: Array of path objects, each with:
301
+ - length: number — number of hops in the path
302
+ - steps: Array<Step> — ordered sequence of relationships
303
+
304
+ Step (object) fields:
305
+ - source: string — source element FQN
306
+ - target: string — target element FQN
307
+ - relationship: object
308
+ - kind: string|null — relationship kind
309
+ - title: string|null — relationship title
310
+ - description: string|null — relationship description
311
+ - technology: string|null — relationship technology
312
+ - tags: string[] — relationship tags
313
+
314
+ Notes:
315
+ - Read-only, idempotent, no side effects.
316
+ - Safe to call repeatedly.
317
+ - Returns empty paths array if no paths exist.
318
+ - Rejects if source equals target.
319
+ - includeIndirect=false (default): only follows direct relationships on each element.
320
+ includeIndirect=true: also follows implied relationships through nested elements.
321
+ - maxDepth is capped at 5 to prevent excessive computation.
322
+ - Paths are discovered iteratively and sorted by length.
323
+
324
+ Example response:
325
+ {
326
+ "paths": [
327
+ {
328
+ "length": 1,
329
+ "steps": [
330
+ {
331
+ "source": "shop.frontend",
332
+ "target": "shop.backend",
333
+ "relationship": {
334
+ "kind": "uses",
335
+ "title": "Calls API",
336
+ "description": null,
337
+ "technology": "HTTPS",
338
+ "tags": []
339
+ }
340
+ }
341
+ ]
342
+ },
343
+ {
344
+ "length": 2,
345
+ "steps": [
346
+ {
347
+ "source": "shop.frontend",
348
+ "target": "shop.cache",
349
+ "relationship": {
350
+ "kind": "uses",
351
+ "title": "Reads from",
352
+ "description": null,
353
+ "technology": "Redis",
354
+ "tags": []
355
+ }
356
+ },
357
+ {
358
+ "source": "shop.cache",
359
+ "target": "shop.backend",
360
+ "relationship": {
361
+ "kind": "syncs-with",
362
+ "title": "Updates",
363
+ "description": null,
364
+ "technology": null,
365
+ "tags": []
366
+ }
367
+ }
368
+ ]
369
+ }
370
+ ]
371
+ }
372
+ `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Find relationship paths`},inputSchema:{sourceId:A().describe(`Source element FQN`),targetId:A().describe(`Target element FQN`),maxDepth:k().int().min(1).max(5).optional().default(3).describe(`Maximum path length (default: 3, max: 5)`),includeIndirect:O().optional().default(!1).describe(`Include indirect (implied) relationships through nested elements (default: false)`),project:$},outputSchema:{paths:D(w({length:k().describe(`Number of hops in the path`),steps:D(w({source:A().describe(`Source element FQN`),target:A().describe(`Target element FQN`),relationship:w({kind:A().nullable().describe(`Relationship kind`),title:A().nullable().describe(`Relationship title`),description:A().nullable().describe(`Relationship description`),technology:A().nullable().describe(`Relationship technology`),tags:D(A()).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);j(i,`Source element "${t.sourceId}" not found in project "${n}"`);let a=r.findElement(t.targetId);j(a,`Target element "${t.targetId}" not found in project "${n}"`),j(i.id!==a.id,`Source and target must be different elements`);let o=t.maxDepth,s=t.includeIndirect?`all`:`direct`,c=[{elementId:i.id,path:[],visited:new Set([i.id])}],l=[];for(;c.length>0&&l.length<100;){let e=c.shift();if(e.path.length>=o)continue;let t=r.findElement(e.elementId);if(t)for(let n of t.outgoing(s)){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(l.push({length:e.path.length+1,steps:[...e.path,t]}),l.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]}};c.push({elementId:t,path:[...e.path,r],visited:new Set([...e.visited,t])})}}return l.sort((e,t)=>e.length-t.length),{paths:l}}),da=w({id:A(),title:A(),kind:A()}),fa=w({type:C([`direct`,`indirect`]).describe(`Type of relationship, "direct" for direct relationships, "indirect" for relationships through nested elements`),source:da,target:da,kind:A().nullable().describe(`Relationship kind`),title:A().nullable().describe(`Relationship title`),description:A().nullable().describe(`Relationship description`),technology:A().nullable().describe(`Relationship technology`),tags:D(A()).describe(`Relationship tags`),includedInViews:na.describe(`Views that include this relationship`),sourceLocation:ta}),pa=Z({name:`find-relationships`,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Find relationships between two elements`},description:`
373
+ Find relationships between two LikeC4 elements within a project.
374
+
375
+ What it does:
376
+ - Finds both direct relationships (element1 ↔ element2) and indirect ones that arise via containment (e.g. via nested elements).
377
+ - Returns rich metadata for each relationship and where it appears in views.
378
+
379
+ Inputs:
380
+ - element1: string — Element ID (FQN)
381
+ - element2: string — Element ID (FQN)
382
+ - project: string (optional, defaults to "default") — Project id
383
+
384
+ Output:
385
+ - found: Relationship[]
386
+
387
+ Relationship (object) fields:
388
+ - type: "direct" | "indirect" — direct is between the specified endpoints; indirect is via nested elements
389
+ - source: Endpoint
390
+ - target: Endpoint
391
+ - kind: string|null — relationship kind from the model
392
+ - title: string|null — relationship title if provided
393
+ - description: string|null — relationship description text
394
+ - technology: string|null — relationship technology
395
+ - tags: string[] — relationship tags
396
+ - includedInViews: View[] — views where this relationship appears
397
+ - sourceLocation: { path: string, range: { start: { line: number, character: number }, end: { line: number, character: number } } } | null
398
+
399
+ Endpoint (object) fields:
400
+ - id: string — Element ID (FQN)
401
+ - title: string — element title
402
+ - kind: string — element kind
403
+
404
+ View (object) fields:
405
+ - id: string — view identifier
406
+ - title: string — view title
407
+ - type: "element" | "deployment" | "dynamic"
408
+
409
+ Notes:
410
+ - Read-only, idempotent; does not mutate the model. May trigger UI navigation in supporting clients.
411
+ - The order of results is not guaranteed.
412
+
413
+ Example:
414
+ Request:
415
+ {
416
+ "element1": "shop.frontend",
417
+ "element2": "shop.backend",
418
+ "project": "default"
419
+ }
420
+
421
+ Response:
422
+ {
423
+ "found": [
424
+ {
425
+ "type": "direct",
426
+ "source": { "id": "shop.frontend", "title": "Frontend", "kind": "component" },
427
+ "target": { "id": "shop.backend", "title": "Backend", "kind": "component" },
428
+ "kind": "sync",
429
+ "title": "Calls",
430
+ "description": "Frontend calls Backend",
431
+ "technology": "HTTP",
432
+ "tags": ["public"],
433
+ "includedInViews": [
434
+ { "id": "system-overview", "title": "System Overview", "type": "element" }
435
+ ],
436
+ "sourceLocation": {
437
+ "path": "/abs/path/project/model.c4",
438
+ "range": { "start": { "line": 12, "character": 0 }, "end": { "line": 14, "character": 0 } }
439
+ }
440
+ }
441
+ ]
442
+ }
443
+ `,inputSchema:{element1:A().describe(`Element ID (FQN)`),element2:A().describe(`Element ID (FQN)`),project:$},outputSchema:{found:D(fa)}},async(e,t)=>{let n=e.projectsManager.ensureProjectId(t.project);if(st(t.element1,t.element2))throw Error(`No relationships possible between parent-child`);let r=[],i=await e.computedModel(n),a=i.findElement(t.element1);ot(a,`Element "${t.element1}" not found in project "${n}"`);let o=i.findElement(t.element2);ot(o,`Element "${t.element2}" not found in project "${n}"`);let s=ia(e,n),c=$e.findConnection(a,o,`both`).flatMap(e=>[...e.relations]);for(let e of c){let t=e.source===a&&e.target===o||e.source===o&&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:ra(e.views()),sourceLocation:s({relation:e.id})})}return{found:r}}),ma=Z({name:`list-projects`,description:`
444
+ List LikeC4 projects discoverable in the current workspace.
445
+
446
+ Request:
447
+ - No input parameters.
448
+
449
+ Response (JSON object):
450
+ - projects: Project[]
451
+
452
+ Project (object) fields:
453
+ - id: string — stable project identifier
454
+ - title: string — human-readable project title
455
+ - folder: string — absolute path to the project root
456
+ - sources: string[] — absolute file paths of related documents
457
+
458
+ Notes:
459
+ - Read-only, idempotent, no side effects.
460
+ - Safe to call repeatedly.
461
+
462
+ Example response:
463
+ {
464
+ "projects": [
465
+ {
466
+ "id": "docs",
467
+ "title": "Documentation",
468
+ "folder": "/abs/path/to/workspace/docs",
469
+ "sources": [
470
+ "/abs/path/to/workspace/docs/model/contexts.likec4",
471
+ "/abs/path/to/workspace/docs/model/relations.likec4"
472
+ ]
473
+ }
474
+ ]
475
+ }
476
+ `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`List projects`},outputSchema:{projects:D(w({id:A(),title:A(),folder:A(),sources:D(A())}))}},async e=>({projects:e.projects().map(e=>({id:e.id,title:e.title,folder:e.folder.fsPath,sources:e.documents.map(e=>e.fsPath)}))})),ha=C([`exact`,`contains`,`exists`]),ga=Z({name:`query-by-metadata`,description:`
477
+ Search elements and deployment nodes by metadata key-value pairs with flexible matching modes.
478
+
479
+ Request:
480
+ - key: string — metadata key to filter by
481
+ - value: string (optional) — metadata value to match (ignored for 'exists' mode)
482
+ - matchMode: "exact" | "contains" | "exists" (optional, default: "exact")
483
+ - project: string (optional) — project id. Defaults to "default" if omitted.
484
+
485
+ Match Modes:
486
+ - exact: Value must match exactly (case-sensitive)
487
+ Example: key="owner", value="platform-team" matches only exact "platform-team"
488
+ - contains: Value contains the search string (case-insensitive)
489
+ Example: key="technology", value="aws" matches "AWS Lambda", "aws-s3", etc.
490
+ - exists: Element has the key (value parameter is ignored)
491
+ Example: key="owner" returns all elements with any "owner" metadata
492
+
493
+ Response (JSON object):
494
+ - results: Array of matching elements/deployment-nodes, each with:
495
+ - id: string — element/node id (FQN)
496
+ - name: string — element/node name
497
+ - kind: string — element/node kind
498
+ - title: string — human-readable title
499
+ - tags: string[] — assigned tags
500
+ - metadata: Record<string, string | string[]> — all element metadata
501
+ - matchedValue: string — the metadata value that matched (for reference)
502
+ - includedInViews: View[] — views that include this element
503
+
504
+ View (object) fields:
505
+ - id: string — view identifier
506
+ - title: string — view title
507
+ - type: "element" | "deployment" | "dynamic"
508
+
509
+ Notes:
510
+ - Read-only, idempotent, no side effects.
511
+ - Safe to call repeatedly.
512
+ - Handles both string and array metadata values.
513
+ - For array values, matches if any element in the array matches.
514
+ - Returns empty array if no matches found.
515
+ - Limited to 50 results to avoid overwhelming responses.
516
+ - Case-sensitive for exact mode, case-insensitive for contains mode.
517
+
518
+ Example response:
519
+ {
520
+ "results": [
521
+ {
522
+ "id": "shop.frontend",
523
+ "name": "frontend",
524
+ "kind": "container",
525
+ "title": "Frontend",
526
+ "tags": ["public"],
527
+ "metadata": {
528
+ "owner": "platform-team",
529
+ "tier": "critical"
530
+ },
531
+ "matchedValue": "platform-team",
532
+ "includedInViews": [
533
+ {
534
+ "id": "system-overview",
535
+ "title": "System Overview",
536
+ "type": "element"
537
+ }
538
+ ]
539
+ }
540
+ ]
541
+ }
542
+ `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Query by metadata`},inputSchema:{key:A().describe(`Metadata key to filter by`),value:A().optional().describe(`Metadata value to match (ignored for exists mode)`),matchMode:ha.optional().default(`exact`).describe(`Matching mode`),project:$},outputSchema:{results:D($i.extend({matchedValue:A().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=[],o=(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}},s=(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&&o(r,t.value,i)&&a.push({...Q(e),matchedValue:s(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&&o(r,t.value,i)&&a.push({...Q(e),matchedValue:s(r,t.value,i)})}}return{results:a}}),_a=Z({name:`query-by-tag-pattern`,description:`
543
+ Search elements by tag patterns using prefix or substring matching.
544
+ Useful for tag taxonomies with structured naming conventions (e.g., "schedule_*", "*_asil_*").
545
+
546
+ Request:
547
+ - pattern: string — tag pattern to match
548
+ - matchMode: "prefix" | "contains" | "suffix" (optional, default: "prefix")
549
+ - prefix: matches tags starting with the pattern (e.g., "target_asil" matches "target_asil_qm", "target_asil_asil_b")
550
+ - contains: matches tags containing the pattern anywhere (e.g., "asil" matches "target_asil_qm", "unit_asil_b")
551
+ - suffix: matches tags ending with the pattern (e.g., "_tbc" matches "target_asil_qm__tbc")
552
+ - project: string (optional) — project id. Defaults to "default" if omitted.
553
+
554
+ Response (JSON object):
555
+ - results: Array of matching elements, each with:
556
+ - id: string — element id (FQN)
557
+ - name: string — element name
558
+ - kind: string — element kind
559
+ - title: string — human-readable title
560
+ - tags: string[] — all assigned tags
561
+ - metadata: Record<string, string | string[]> — element metadata
562
+ - matchedTags: string[] — the specific tags that matched the pattern
563
+ - includedInViews: View[] — views that include this element
564
+ - truncated: boolean — true if results were truncated due to exceeding the 50-result limit
565
+ - matchedTagValues: string[] — all unique tag values that matched the pattern across all elements
566
+
567
+ View (object) fields:
568
+ - id: string — view identifier
569
+ - title: string — view title
570
+ - type: "element" | "deployment" | "dynamic"
571
+
572
+ Notes:
573
+ - Read-only, idempotent, no side effects.
574
+ - Safe to call repeatedly.
575
+ - Pattern matching is case-insensitive.
576
+ - Returns empty array if no matches found.
577
+ - Limited to 50 results.
578
+ - matchedTagValues provides a summary of all distinct matching tag values found.
579
+
580
+ Example response:
581
+ {
582
+ "results": [
583
+ {
584
+ "id": "top.planner.behaviorNode",
585
+ "name": "behaviorNode",
586
+ "kind": "cgf-node",
587
+ "title": "behaviorNode :dwBehaviorPlannerNode",
588
+ "tags": ["is_in_dag", "target_asil_qm", "process_camera_master"],
589
+ "metadata": {},
590
+ "matchedTags": ["target_asil_qm"],
591
+ "includedInViews": []
592
+ }
593
+ ],
594
+ "truncated": false,
595
+ "matchedTagValues": ["target_asil_qm", "target_asil_asil_b", "target_asil_qm__tbc"]
596
+ }
597
+ `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Query by tag pattern`},inputSchema:{pattern:A().min(1).describe(`Tag pattern to match`),matchMode:C([`prefix`,`contains`,`suffix`]).optional().default(`prefix`).describe(`Pattern matching mode (default: prefix)`),project:$},outputSchema:{results:D($i.extend({matchedTags:D(A()).describe(`Tags that matched the pattern`)})),truncated:O().describe(`True if results were truncated`),matchedTagValues:D(A()).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(),a=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)}},o=[],s=!1,c=new Set;for(let e of r.elements()){let t=[...e.tags].filter(a);if(t.length>0){if(t.forEach(e=>c.add(e)),o.length>=50){s=!0;continue}o.push({...Q(e),matchedTags:t})}}for(let e of r.deployment.elements()){if(!Je(e))continue;let t=[...e.tags].filter(a);if(t.length>0){if(t.forEach(e=>c.add(e)),o.length>=50){s=!0;continue}o.push({...Q(e),matchedTags:t})}}return{results:o,truncated:s,matchedTagValues:[...c].sort((e,t)=>e.localeCompare(t))}}),va=Z({name:`query-by-tags`,description:`
598
+ Advanced tag filtering with boolean logic (AND, OR, NOT).
599
+
600
+ Request:
601
+ - allOf: string[] (optional) — element must have ALL these tags (AND logic)
602
+ - anyOf: string[] (optional) — element must have ANY of these tags (OR logic)
603
+ - noneOf: string[] (optional) — element must have NONE of these tags (NOT logic)
604
+ - project: string (optional) — project id. Defaults to "default" if omitted.
605
+
606
+ Boolean Logic:
607
+ - All three conditions are combined with AND logic
608
+ - At least one condition must be specified
609
+ - Tags are case-sensitive
610
+
611
+ Example Queries:
612
+ - Public APIs: {"allOf": ["public", "api"]}
613
+ - Deprecated or legacy: {"anyOf": ["deprecated", "legacy"]}
614
+ - Public but not deprecated: {"allOf": ["public"], "noneOf": ["deprecated"]}
615
+ - Critical services not in migration: {"allOf": ["critical", "service"], "noneOf": ["migration", "deprecated"]}
616
+
617
+ Response (JSON object):
618
+ - results: Array of matching elements/deployment-nodes, each with:
619
+ - id: string — element/node id (FQN)
620
+ - name: string — element/node name
621
+ - kind: string — element/node kind
622
+ - title: string — human-readable title
623
+ - tags: string[] — assigned tags (for reference)
624
+ - metadata: Record<string, string | string[]> — element metadata
625
+ - includedInViews: View[] — views that include this element
626
+
627
+ View (object) fields:
628
+ - id: string — view identifier
629
+ - title: string — view title
630
+ - type: "element" | "deployment" | "dynamic"
631
+
632
+ Notes:
633
+ - Read-only, idempotent, no side effects.
634
+ - Safe to call repeatedly.
635
+ - Returns empty array if no matches found.
636
+ - Limited to 50 results to avoid overwhelming responses.
637
+ - Conflicting conditions (e.g., allOf and noneOf with same tag) will return no results.
638
+
639
+ Example response:
640
+ {
641
+ "results": [
642
+ {
643
+ "id": "shop.api",
644
+ "name": "api",
645
+ "kind": "container",
646
+ "title": "API Gateway",
647
+ "tags": ["public", "api", "critical"],
648
+ "metadata": {
649
+ "owner": "platform-team"
650
+ },
651
+ "includedInViews": [
652
+ {
653
+ "id": "system-overview",
654
+ "title": "System Overview",
655
+ "type": "element"
656
+ }
657
+ ]
658
+ }
659
+ ]
660
+ }
661
+ `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Query by tags`},inputSchema:{allOf:D(A()).optional().describe(`Element must have ALL these tags (AND)`),anyOf:D(A()).optional().describe(`Element must have ANY of these tags (OR)`),noneOf:D(A()).optional().describe(`Element must have NONE of these tags (NOT)`),project:$},outputSchema:{results:D($i),truncated:O().describe(`True if results were truncated due to exceeding the 50-result limit`)}},async(e,t)=>{j(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,o=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}o(e.tags)&&i.push(Q(e))}if(!a)for(let e of r.deployment.elements()){if(i.length>=50){a=!0;break}Je(e)&&o(e.tags)&&i.push(Q(e))}return{results:i,truncated:a}}),ya=C([`ancestors`,`descendants`,`siblings`,`children`,`parent`,`incomers`,`outgoers`]),ba=Z({name:`query-graph`,description:`
662
+ Query element hierarchy and relationships in the architecture graph.
663
+
664
+ Request:
665
+ - elementId: string — element id (FQN) to query
666
+ - queryType: "ancestors" | "descendants" | "siblings" | "children" | "parent" | "incomers" | "outgoers"
667
+ - includeIndirect: boolean (optional, default: true) — for incomers/outgoers, include indirect relationships (through nested elements)
668
+ - project: string (optional) — project id. Defaults to "default" if omitted.
669
+
670
+ Query Types:
671
+ - ancestors: Returns all parent elements up to the root (hierarchical)
672
+ Example: shop.frontend.auth.service returns [shop.frontend.auth, shop.frontend, shop]
673
+ - descendants: Returns all child elements recursively (hierarchical)
674
+ Example: shop.frontend returns all nested elements like shop.frontend.auth, shop.frontend.auth.service
675
+ - siblings: Returns elements at the same hierarchy level with the same parent
676
+ Example: shop.frontend returns [shop.backend, shop.database] if they're siblings
677
+ - children: Returns direct child elements only (not recursive)
678
+ Example: shop returns [shop.frontend, shop.backend] but not shop.frontend.auth
679
+ - parent: Returns the direct parent element
680
+ Example: shop.frontend.auth returns shop.frontend
681
+ - incomers: Returns elements that have outgoing relationships to this element (single hop, not recursive).
682
+ For recursive upstream traversal, use query-incomers-graph instead.
683
+ includeIndirect=true: Includes relationships to nested children
684
+ Example: Elements that depend on this element
685
+ - outgoers: Returns elements that receive incoming relationships from this element (single hop, not recursive).
686
+ For recursive downstream traversal, use query-outgoers-graph instead.
687
+ includeIndirect=true: Includes relationships from nested children
688
+ Example: Elements this element depends on
689
+
690
+ Response (JSON object):
691
+ - results: Array of elements (max 100), each with:
692
+ - id: string — element id (FQN)
693
+ - name: string — element name
694
+ - kind: string — element kind
695
+ - title: string — human-readable title
696
+ - tags: string[] — assigned tags
697
+ - metadata: Record<string, string> — element metadata
698
+ - includedInViews: View[] — views that include this element
699
+ - truncated: boolean — true if results were truncated due to exceeding maximum limit (100)
700
+
701
+ View (object) fields:
702
+ - id: string — view identifier
703
+ - title: string — view title
704
+ - type: "element" | "deployment" | "dynamic"
705
+
706
+ Notes:
707
+ - Read-only, idempotent, no side effects.
708
+ - Safe to call repeatedly.
709
+ - For parent query on root element, returns empty array.
710
+ - For hierarchical queries (ancestors, descendants, siblings, children), includeIndirect is ignored.
711
+
712
+ Example response:
713
+ {
714
+ "results": [
715
+ {
716
+ "id": "shop.frontend",
717
+ "name": "frontend",
718
+ "kind": "container",
719
+ "title": "Frontend",
720
+ "tags": ["public"],
721
+ "metadata": { "owner": "web-team" },
722
+ "includedInViews": [
723
+ {
724
+ "id": "system-overview",
725
+ "title": "System Overview",
726
+ "type": "element"
727
+ }
728
+ ]
729
+ }
730
+ ],
731
+ "truncated": false
732
+ }
733
+ `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Query element graph`},inputSchema:{elementId:A().describe(`Element id (FQN) to query`),queryType:ya.describe(`Type of graph query`),includeIndirect:O().optional().default(!0).describe(`For incomers/outgoers: include indirect relationships (default: true)`),project:$},outputSchema:{results:D($i),truncated:O().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);j(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(Q(e))}break;case`descendants`:for(let e of r.descendants()){if(i.length>=100){a=!0;break}i.push(Q(e))}break;case`siblings`:for(let e of r.siblings()){if(i.length>=100){a=!0;break}i.push(Q(e))}break;case`children`:for(let e of r.children()){if(i.length>=100){a=!0;break}i.push(Q(e))}break;case`parent`:{let e=r.parent;e&&i.push(Q(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(Q(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(Q(t))}break}}return{results:i,truncated:a}}),xa=w({elementId:A().describe(`ID of the incoming element`),relationshipLabel:A().optional().describe(`Label on the relationship`),technology:A().optional().describe(`Technology specified on the relationship`)}),Sa=Z({name:`query-incomers-graph`,description:`
734
+ Query the complete graph of all elements that provide input to the target element (recursive incomers/producers).
735
+
736
+ This tool performs a breadth-first traversal to discover all upstream dependencies - elements that directly or
737
+ indirectly provide input to the target element. It returns the complete subgraph in a single response,
738
+ making it much more efficient than repeated individual queries.
739
+
740
+ Request:
741
+ - elementId: string — target element id (FQN) to start from
742
+ - includeIndirect: boolean (optional, default: true) — include relationships through nested elements
743
+ - maxDepth: number (optional, default: 10, max: 50) — maximum traversal depth to prevent infinite recursion
744
+ - maxNodes: number (optional, default: 200, max: 2000) — maximum number of nodes to return
745
+ - project: string (optional) — project id. Defaults to "default" if omitted.
746
+
747
+ Response Structure:
748
+ {
749
+ "target": "element.id",
750
+ "totalNodes": number,
751
+ "maxDepth": number,
752
+ "truncated": boolean,
753
+ "nodes": {
754
+ "element.id": {
755
+ "id": "element.id",
756
+ "name": "name",
757
+ "kind": "kind",
758
+ "title": "title",
759
+ "tags": ["tag1", "tag2"],
760
+ "metadata": {},
761
+ "includedInViews": [...],
762
+ "incomers": [
763
+ {
764
+ "elementId": "id1",
765
+ "relationshipLabel": "uses",
766
+ "technology": "REST"
767
+ }
768
+ ],
769
+ "depth": number
770
+ }
771
+ }
772
+ }
773
+
774
+ Use Cases:
775
+ - Find all producers/dependencies for an element
776
+ - Trace data lineage upstream
777
+ - Identify root causes and dependencies
778
+ - Build complete dependency trees
779
+ - Answer "what feeds into this?" questions
780
+
781
+ Notes:
782
+ - Read-only, idempotent, no side effects
783
+ - Cycle detection prevents infinite loops
784
+ - Result size limited to maxNodes to prevent huge responses
785
+ - If truncated=true, increase maxNodes or reduce maxDepth to get more specific results
786
+
787
+ Example:
788
+ For a database element, this returns all services, APIs, and components that write to it,
789
+ plus all their dependencies, recursively up to maxDepth levels.
790
+ `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Query complete incomers graph`},inputSchema:{elementId:A().describe(`Target element id (FQN) to query incomers for`),includeIndirect:O().optional().default(!0).describe(`Include indirect relationships through nested elements (default: true)`),maxDepth:k().int().positive().max(50).optional().default(10).describe(`Maximum traversal depth (default: 10, max: 50)`),maxNodes:k().int().positive().max(2e3).optional().default(200).describe(`Maximum number of nodes to return (default: 200, max: 2000)`),project:$},outputSchema:{target:A().describe(`Target element id`),totalNodes:k().describe(`Total number of nodes in the graph`),maxDepth:k().describe(`Maximum depth reached`),truncated:O().describe(`True if result was truncated due to maxNodes limit`),nodes:E($i.extend({incomers:D(xa).describe(`Incoming relationships with details`),depth:k().describe(`Distance from target element (0 = target)`)}))}},async(e,t)=>{let n=e.projectsManager.ensureProjectId(t.project),r=await e.computedModel(n);j(r.findElement(t.elementId),`Element "${t.elementId}" not found in project "${n}"`);let i=t.includeIndirect?`all`:`direct`,a=ea(r,t.elementId,`incoming`,i,t.maxDepth,t.maxNodes),o={};for(let[e,t]of Object.entries(a.nodes)){let{neighbors:n,...r}=t;o[e]={...r,incomers:n}}return{target:a.target,totalNodes:a.totalNodes,maxDepth:a.maxDepth,truncated:a.truncated,nodes:o}}),Ca=w({elementId:A().describe(`ID of the outgoing element`),relationshipLabel:A().optional().describe(`Label on the relationship`),technology:A().optional().describe(`Technology specified on the relationship`)}),wa=Z({name:`query-outgoers-graph`,description:`
791
+ Query the complete graph of all elements that receive output from the target element (recursive outgoers/consumers).
792
+
793
+ This tool performs a breadth-first traversal to discover all downstream dependencies - elements that directly or
794
+ indirectly consume output from the target element. It returns the complete subgraph in a single response,
795
+ making it much more efficient than repeated individual queries.
796
+
797
+ Request:
798
+ - elementId: string — target element id (FQN) to start from
799
+ - includeIndirect: boolean (optional, default: true) — include relationships through nested elements
800
+ - maxDepth: number (optional, default: 10, max: 50) — maximum traversal depth to prevent infinite recursion
801
+ - maxNodes: number (optional, default: 200, max: 2000) — maximum number of nodes to return
802
+ - project: string (optional) — project id. Defaults to "default" if omitted.
803
+
804
+ Response Structure:
805
+ {
806
+ "target": "element.id",
807
+ "totalNodes": number,
808
+ "maxDepth": number,
809
+ "truncated": boolean,
810
+ "nodes": {
811
+ "element.id": {
812
+ "id": "element.id",
813
+ "name": "name",
814
+ "kind": "kind",
815
+ "title": "title",
816
+ "tags": ["tag1", "tag2"],
817
+ "metadata": {},
818
+ "includedInViews": [...],
819
+ "outgoers": [
820
+ {
821
+ "elementId": "id1",
822
+ "relationshipLabel": "sends data to",
823
+ "technology": "Kafka"
824
+ }
825
+ ],
826
+ "depth": number
827
+ }
828
+ }
829
+ }
830
+
831
+ Use Cases:
832
+ - Find all consumers/dependents of an element
833
+ - Trace data lineage downstream
834
+ - Assess impact of changes (blast radius)
835
+ - Build complete consumer trees
836
+ - Answer "what depends on this?" questions
837
+
838
+ Notes:
839
+ - Read-only, idempotent, no side effects
840
+ - Cycle detection prevents infinite loops
841
+ - Result size limited to maxNodes to prevent huge responses
842
+ - If truncated=true, increase maxNodes or reduce maxDepth to get more specific results
843
+
844
+ Example:
845
+ For an API service, this returns all clients, services, and systems that consume its output,
846
+ plus all their consumers, recursively up to maxDepth levels.
847
+ `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Query complete outgoers graph`},inputSchema:{elementId:A().describe(`Target element id (FQN) to query outgoers for`),includeIndirect:O().optional().default(!0).describe(`Include indirect relationships through nested elements (default: true)`),maxDepth:k().int().positive().max(50).optional().default(10).describe(`Maximum traversal depth (default: 10, max: 50)`),maxNodes:k().int().positive().max(2e3).optional().default(200).describe(`Maximum number of nodes to return (default: 200, max: 2000)`),project:$},outputSchema:{target:A().describe(`Target element id`),totalNodes:k().describe(`Total number of nodes in the graph`),maxDepth:k().describe(`Maximum depth reached`),truncated:O().describe(`True if result was truncated due to maxNodes limit`),nodes:E($i.extend({outgoers:D(Ca).describe(`Outgoing relationships with details`),depth:k().describe(`Distance from target element (0 = target)`)}))}},async(e,t)=>{let n=e.projectsManager.ensureProjectId(t.project),r=await e.computedModel(n);j(r.findElement(t.elementId),`Element "${t.elementId}" not found in project "${n}"`);let i=t.includeIndirect?`all`:`direct`,a=ea(r,t.elementId,`outgoing`,i,t.maxDepth,t.maxNodes),o={};for(let[e,t]of Object.entries(a.nodes)){let{neighbors:n,...r}=t;o[e]={...r,outgoers:n}}return{target:a.target,totalNodes:a.totalNodes,maxDepth:a.maxDepth,truncated:a.truncated,nodes:o}}),Ta=Z({name:`read-deployment`,description:`
848
+ Read details about a deployment node or a deployed instance in a LikeC4 project.
849
+
850
+ What it does:
851
+ - Returns metadata about a deployment entity (node or instance), including kind, tags, color/shape, children, which views include it, and its source location.
852
+
853
+ Inputs:
854
+ - id: string — Deployment id (FQN)
855
+ - project: string (optional, defaults to "default") — Project id
856
+
857
+ Output fields:
858
+ - type: "deployment-node" | "deployed-instance"
859
+ - id: string — Deployment id (FQN)
860
+ - kind: string — Deployment node kind, or element kind for deployed instances
861
+ - name: string — Name of the deployment entity
862
+ - title: string — Title of the deployment entity
863
+ - description: string|null — Description text
864
+ - technology: string|null — Technology info, if any
865
+ - tags: string[] — Tags assigned to this entity
866
+ - project: string — Project id
867
+ - metadata: Record<string, string>
868
+ - links: Array<{ title: string|null, url: string, relative: string|null }> — external links associated with this deployment entity
869
+ - shape: string — Rendered shape
870
+ - color: string — Rendered color
871
+ - children: string[] — Child deployment ids (empty for instances)
872
+ - includedInViews: View[] — Views that include this entity
873
+ - instanceof: { id: string, title: string, kind: string } | null — If type is "deployed-instance", the referenced element
874
+ - sourceLocation: { path: string, range: { start: { line: number, character: number }, end: { line: number, character: number } } } | null
875
+
876
+ View (object) fields:
877
+ - id: string — view identifier
878
+ - title: string — view title
879
+ - type: "element" | "deployment" | "dynamic"
880
+
881
+ Notes:
882
+ - Read-only, idempotent; does not mutate the model.
883
+
884
+ Example request:
885
+ { "id": "k8s.cluster.frontend", "project": "default" }
886
+
887
+ Example response (deployed instance):
888
+ {
889
+ "type": "deployed-instance",
890
+ "id": "k8s.cluster.frontend",
891
+ "kind": "k8s.pod",
892
+ "name": "frontend",
893
+ "title": "Frontend Pod",
894
+ "description": null,
895
+ "technology": "Kubernetes",
896
+ "tags": ["prod"],
897
+ "project": "default",
898
+ "metadata": {},
899
+ "links": [],
900
+ "shape": "rectangle",
901
+ "color": "#2F80ED",
902
+ "children": [],
903
+ "includedInViews": [
904
+ { "id": "runtime-overview", "title": "Runtime Overview", "type": "deployment" }
905
+ ],
906
+ "instanceof": { "id": "shop.frontend", "title": "Frontend", "kind": "component" },
907
+ "sourceLocation": {
908
+ "path": "/abs/path/project/model.c4",
909
+ "range": { "start": { "line": 10, "character": 0 }, "end": { "line": 25, "character": 0 } }
910
+ }
911
+ }
912
+ `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Read deployment entity`},inputSchema:{id:A().describe(`Deployment id (FQN)`),project:$},outputSchema:{type:C([`deployment-node`,`deployed-instance`]),id:A().describe(`Deployment id (FQN)`),kind:A().describe(`Deployment node kind, or element kind for deployed instances`),name:A(),title:A(),description:A().nullable(),technology:A().nullable(),tags:D(A()),project:A(),metadata:E(T([A(),D(A())])),links:D(w({title:A().nullable().describe(`Optional link title`),url:A().describe(`Link URL`),relative:A().nullable().describe(`Relative path (if URL is relative to workspace root)`)})).describe(`External links associated with this deployment entity`),shape:A(),color:A(),children:D(A()).describe(`Children of this deployment node (Array of Deployment ids)`),includedInViews:na.describe(`Views that include this deployment node`),instanceof:w({id:A().describe(`Element ID (FQN)`),title:A(),kind:A()}).nullable().describe(`If type is "deployed-instance", the referenced element`),sourceLocation:ta}},async(e,t)=>{let n=e.projectsManager.ensureProjectId(t.project),r=(await e.computedModel(n)).deployment.findElement(t.id);j(r,`Deployment entity "${t.id}" not found in project "${n}"`);let i=ia(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:ra(r.views()),instanceof:r.isInstance()?{id:r.element.id,title:r.element.title,kind:r.element.kind}:null,sourceLocation:i({deployment:r.id})}}),Ea=Z({name:`read-element`,description:`
913
+ Read detailed information about a LikeC4 element.
914
+
915
+ Request:
916
+ - id: string — element id (FQN)
917
+ - project: string (optional) — project id. Defaults to "default" if omitted.
918
+
919
+ Response (JSON object):
920
+ - id: string — element id (FQN)
921
+ - name: string — element name
922
+ - kind: string — element kind
923
+ - title: string — human-readable title
924
+ - description: string|null — optional description
925
+ - technology: string|null — optional technology
926
+ - tags: string[] — assigned tags
927
+ - project: string — project id this element belongs to
928
+ - metadata: Record<string, string> — element metadata
929
+ - links: Array<{ title: string|null, url: string, relative: string|null }> — external links associated with this element
930
+ - shape: string — rendered shape
931
+ - color: string — rendered color
932
+ - children: string[] — ids (FQNs) of direct child elements
933
+ - defaultView: string|null — default view name if set
934
+ - includedInViews: View[] — views that include this element
935
+ - relationships: object — relationships of this element (direct and indirect)
936
+ - incoming: Array<{ source: { id: string, title: string, kind: string }, kind: string|null, target: string, title: string|null, description: string|null, technology: string|null, tags: string[] }>
937
+ - outgoing: Array<{ source: string, target: { id: string, title: string, kind: string }, kind: string|null, title: string|null, description: string|null, technology: string|null, tags: string[] }>
938
+ - deployedInstances: string[] — deployed instance ids (Deployment FQNs)
939
+ - sourceLocation: { path: string, range: { start: { line: number, character: number }, end: { line: number, character: number } } } | null — source location if available
940
+
941
+ View (object) fields:
942
+ - id: string — view identifier
943
+ - title: string — view title
944
+ - type: "element" | "deployment" | "dynamic"
945
+
946
+ Notes:
947
+ - Read-only, idempotent, no side effects.
948
+ - Safe to call repeatedly.
949
+
950
+ Example response:
951
+ {
952
+ "id": "shop.frontend",
953
+ "name": "frontend",
954
+ "kind": "container",
955
+ "title": "Frontend",
956
+ "description": "User-facing web app",
957
+ "technology": "React",
958
+ "tags": ["public"],
959
+ "project": "default",
960
+ "metadata": { "owner": "web" },
961
+ "links": [
962
+ {
963
+ "title": "Documentation",
964
+ "url": "https://docs.example.com/frontend",
965
+ "relative": null
966
+ }
967
+ ],
968
+ "shape": "rounded-rectangle",
969
+ "color": "#2F80ED",
970
+ "children": ["shop.frontend.auth"],
971
+ "defaultView": "frontend-overview",
972
+ "includedInViews": [
973
+ {
974
+ "id": "frontend-overview",
975
+ "title": "Frontend Overview",
976
+ "type": "element"
977
+ }
978
+ ],
979
+ "relationships": {
980
+ "incoming": [
981
+ {
982
+ "source": { "id": "shop.api", "title": "API", "kind": "container" },
983
+ "kind": "uses",
984
+ "target": "shop.frontend",
985
+ "title": "Calls",
986
+ "description": null,
987
+ "technology": "HTTPS",
988
+ "tags": []
989
+ }
990
+ ],
991
+ "outgoing": []
992
+ },
993
+ "deployedInstances": ["k8s.cluster.frontend"],
994
+ "sourceLocation": {
995
+ "path": "/abs/path/project/model.c4",
996
+ "range": { "start": { "line": 10, "character": 0 }, "end": { "line": 25, "character": 0 } }
997
+ }
998
+ }
999
+ `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Read element`},inputSchema:{id:A().describe(`Element id (FQN)`),project:$},outputSchema:{id:A().describe(`Element id (FQN)`),kind:A().describe(`Element kind`),name:A().describe(`Element name`),title:A(),description:A().nullable(),technology:A().nullable(),tags:D(A()),project:A(),metadata:E(T([A(),D(A())])),links:D(w({title:A().nullable().describe(`Optional link title`),url:A().describe(`Link URL`),relative:A().nullable().describe(`Relative path (if URL is relative to workspace root)`)})).describe(`External links associated with this element`),shape:A(),color:A(),children:D(A()).describe(`Children of this element (Array of FQNs)`),defaultView:A().nullable().describe(`Name of the default view of this element`),includedInViews:na.describe(`Views that include this element`),relationships:w({incoming:D(w({source:w({id:A(),title:A(),kind:A()}).describe(`Source element of this relationship`),kind:A().nullable().describe(`Relationship kind`),target:A().describe(`Target element id (FQN), either this element or nested element, if relationship is indirect`),title:A().nullable().describe(`Relationship title`),description:A().nullable().describe(`Relationship description`),technology:A().nullable().describe(`Relationship technology`),tags:D(A()).describe(`Relationship tags`)})).describe(`Incoming relationships of this element (direct and indirect, incoming to nested elements)`),outgoing:D(w({source:A().describe(`Source element id (FQN), either this element or nested element, if relationship is indirect`),target:w({id:A(),title:A(),kind:A()}).describe(`Target element of this relationship`),kind:A().nullable().describe(`Relationship kind`),title:A().nullable().describe(`Relationship title`),description:A().nullable().describe(`Relationship description`),technology:A().nullable().describe(`Relationship technology`),tags:D(A()).describe(`Relationship tags`)})).describe(`Outgoing relationships of this element (direct and indirect, outgoing from nested elements)`)}).describe(`Relationships of this element`),deployedInstances:D(A()).describe(`Deployed instances of this element (Array of Deployment FQNs)`),sourceLocation:ta}},async(e,t)=>{let n=e.projectsManager.ensureProjectId(t.project),r=(await e.computedModel(n)).findElement(t.id);j(r,`Element "${t.id}" not found in project "${n}"`);let i=ia(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:ra(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})}}),Da=Z({name:`read-project-summary`,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Read project summary`},description:`
1000
+ Request:
1001
+ - project: string (optional) — project id. Defaults to "default" if omitted.
1002
+
1003
+ Response (JSON object):
1004
+ - title: string — human-readable project title
1005
+ - folder: string — absolute path to the project root
1006
+ - sources: string[] — absolute file paths of model documents
1007
+ - config: object — project configuration
1008
+ - name: string — project identifier
1009
+ - title?: string — human-readable title
1010
+ - contactPerson?: string — maintainer contact
1011
+ - metadata?: object — custom project metadata as key-value pairs
1012
+ - extends?: string | string[] — style inheritance paths
1013
+ - exclude?: string[] — file exclusion patterns
1014
+ - include?: object — include configuration (paths, maxDepth, fileThreshold)
1015
+ - manualLayouts?: object — manual layouts config (outDir)
1016
+ - styles?: object — simplified styles (hasTheme, hasDefaults, hasCustomCss)
1017
+ - specification: object
1018
+ - elementKinds: string[] — all element kinds
1019
+ - relationshipKinds: string[] — all relationship kinds
1020
+ - deploymentKinds: string[] — all deployment kinds
1021
+ - tags: string[] — all tags
1022
+ - metadataKeys: string[] — used metadata keys
1023
+ - elements: Element[] — list of elements
1024
+ - deployments: Deployment[] — list of deployment entities
1025
+ - views: View[] — list of views defined in the model
1026
+
1027
+ Element (object) fields:
1028
+ - id: string — element id (FQN)
1029
+ - kind: string — element kind
1030
+ - title: string — element title
1031
+ - tags: string[] — element tags
1032
+
1033
+ Deployment (object) fields:
1034
+ - type = "deployment-node": { id: string, kind: string, title: string, tags: string[] }
1035
+ - type = "deployed-instance": { id: string, title: string, tags: string[], referencedElementId: string }
1036
+
1037
+ View (object) fields:
1038
+ - id: string — view identifier
1039
+ - title: string — view title
1040
+ - type: "element" | "deployment" | "dynamic"
1041
+
1042
+ Notes:
1043
+ - Read-only, idempotent, no side effects.
1044
+ - Safe to call repeatedly.
1045
+
1046
+ Example response:
1047
+ {
1048
+ "title": "Cloud Boutique",
1049
+ "folder": "/abs/path/to/workspace/examples/cloud-system",
1050
+ "sources": [
1051
+ "/abs/path/to/workspace/examples/cloud-system/model.c4"
1052
+ ],
1053
+ "config": {
1054
+ "name": "cloud-boutique",
1055
+ "title": "Cloud Boutique",
1056
+ "contactPerson": "admin@example.com"
1057
+ },
1058
+ "specification": {
1059
+ "elementKinds": ["system", "container", "component"],
1060
+ "relationshipKinds": ["uses", "depends-on"],
1061
+ "deploymentKinds": ["node", "cluster"],
1062
+ "tags": ["public", "internal"],
1063
+ "metadataKeys": ["owner", "tier"]
1064
+ },
1065
+ "elements": [
1066
+ {
1067
+ "id": "shop.frontend",
1068
+ "kind": "component",
1069
+ "title": "Frontend",
1070
+ "tags": ["public"]
1071
+ }
1072
+ ],
1073
+ "deployments": [
1074
+ {
1075
+ "type": "deployment-node",
1076
+ "id": "k8s.shop.frontend",
1077
+ "kind": "cluster",
1078
+ "title": "Frontend",
1079
+ "tags": []
1080
+ }
1081
+ ],
1082
+ "views": [
1083
+ {
1084
+ "id": "system-overview",
1085
+ "title": "System Overview",
1086
+ "type": "element"
1087
+ }
1088
+ ]
1089
+ }
1090
+ `,inputSchema:{project:$},outputSchema:{title:A(),folder:A(),sources:D(A()),config:Zi.describe(`Project configuration`),specification:w({elementKinds:D(A()),relationshipKinds:D(A()),deploymentKinds:D(A()),tags:D(A()),metadataKeys:D(A())}),elements:D(w({id:A(),kind:A(),title:A(),tags:D(A())})).describe(`List of elements in the project`),deployments:D(Le(`type`,[w({type:Re(`deployment-node`),id:A().describe(`Node ID`),kind:A().describe(`Deployment node kind`),title:A().describe(`Node title`),tags:D(A())}),w({type:Re(`deployed-instance`),id:A().describe(`Node ID`),title:A().describe(`Node title`),tags:D(A()),referencedElementId:A().describe(`Element ID (FQN)`)})])).describe(`List of deployment nodes and deployed instances in the project`),views:D(w({id:A(),title:A(),type:C([`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:Qi(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}))}}),Oa=e=>e.hasElement()?e.element.id:e.hasDeployment()?e.deployment.id:null,ka=Le(`type`,[w({type:Re(`element`),id:A().describe(`Node ID`),elementId:A().describe(`Element ID (FQN)`),kind:A().describe(`Element kind`),title:A().describe(`Node title`),description:A().nullable(),technology:A().nullable(),children:D(A()).describe(`Children nodes, array of node IDs`),shape:A().describe(`Rendered shape`),color:A().describe(`Rendered color`),tags:D(A())}),w({type:Re(`deployment-node`),id:A().describe(`Node ID`),deploymentId:A().describe(`Deployment entity ID (FQN)`),kind:A().describe(`Deployment kind`),title:A().describe(`Node title`),description:A().nullable(),technology:A().nullable(),children:D(A()).describe(`Children nodes, array of node IDs`),shape:A().describe(`Rendered shape`),color:A().describe(`Rendered color`),tags:D(A())}),w({type:Re(`deployed-instance`),id:A().describe(`Node ID`),deploymentId:A().describe(`Deployment entity ID (FQN)`),title:A().describe(`Node title`),description:A().nullable(),technology:A().nullable(),referencedElement:w({id:A().describe(`Element ID (FQN)`),kind:A().describe(`Element kind`),title:A().describe(`Element title`)}),shape:A().describe(`Rendered shape`),color:A().describe(`Rendered color`),tags:D(A())})]),Aa=Z({name:`read-view`,description:`
1091
+ Read detailed information about a LikeC4 view.
1092
+
1093
+ Request:
1094
+ - viewId: string — view id (name)
1095
+ - project: string (optional) — project id. Defaults to "default" if omitted.
1096
+
1097
+ Response (JSON object):
1098
+ - id: string — view id
1099
+ - type: "element" | "deployment" | "dynamic" — view type
1100
+ - title: string — view title (falls back to id if not set)
1101
+ - description: string|null — optional description
1102
+ - tags: string[] — view tags
1103
+ - project: string — project id this view belongs to
1104
+ - nodes: Node[] — nodes included in the view
1105
+ - edges: Edge[] — relationships between nodes
1106
+ - sourceLocation: { path: string, range: { start: { line: number, character: number }, end: { line: number, character: number } } } | null — source location if available
1107
+
1108
+ Node (discriminated union by "type"):
1109
+ - type = "element": { id: string, elementId: string, kind: string, title: string, description: string|null, technology: string|null, children: string[], shape: string, color: string, tags: string[] }
1110
+ - type = "deployment-node": { id: string, deploymentId: string, kind: string, title: string, description: string|null, technology: string|null, children: string[], shape: string, color: string, tags: string[] }
1111
+ - type = "deployed-instance": { id: string, deploymentId: string, title: string, description: string|null, technology: string|null, referencedElement: { id: string, kind: string, title: string }, shape: string, color: string, tags: string[] }
1112
+
1113
+ Edge object:
1114
+ - { source: string, target: string, label: string|null, description: string|null, technology: string|null, tags: string[] }
1115
+
1116
+ Notes:
1117
+ - Read-only, idempotent, no side effects.
1118
+
1119
+ Example response:
1120
+ {
1121
+ "id": "system-overview",
1122
+ "type": "element",
1123
+ "title": "System Overview",
1124
+ "description": null,
1125
+ "tags": [],
1126
+ "project": "default",
1127
+ "nodes": [
1128
+ { "type": "logical", "id": "n1", "elementId": "shop.frontend", "kind": "container", "title": "Frontend", "description": null, "technology": "React", "children": [], "shape": "rounded-rectangle", "color": "#2F80ED", "tags": [] }
1129
+ ],
1130
+ "edges": [
1131
+ { "source": "n1", "target": "n2", "label": "calls", "description": null, "technology": "HTTPS", "tags": [] }
1132
+ ],
1133
+ "sourceLocation": {
1134
+ "path": "/abs/path/project/model.c4",
1135
+ "range": { "start": { "line": 10, "character": 0 }, "end": { "line": 30, "character": 0 } }
1136
+ }
1137
+ }
1138
+ `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Read view`},inputSchema:{viewId:A().describe(`View id (name)`),project:$},outputSchema:{id:A(),type:C([`element`,`deployment`,`dynamic`]).describe(`View type`),title:A(),description:A().nullable(),tags:D(A()),project:A(),nodes:D(ka),edges:D(w({source:A().describe(`Source node`),target:A().describe(`Target node`),label:A().nullable(),description:A().nullable(),technology:A().nullable(),tags:D(A())})).describe(`Edge represents relationship between nodes`),sourceLocation:ta}},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=ia(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=>Oa(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})}}),ja=D(Le(`type`,[w({type:Re(`element`),project:A().describe(`Project ID`),id:A().describe(`Element ID (FQN)`),name:A().describe(`Element name`),kind:A(),title:A(),technology:A().nullable(),shape:A(),includedInViews:na,metadata:E(T([A(),D(A())])),tags:D(A())}),w({type:Re(`deployment-node`),project:A().describe(`Project ID`),id:A().describe(`Deployment ID (FQN)`),name:A().describe(`Deployment name`),kind:A(),title:A(),technology:A().nullable(),shape:A(),includedInViews:na,metadata:E(T([A(),D(A())])),tags:D(A())})])),Ma=Z({name:`search-element`,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Search elements`},description:`
1139
+ Search LikeC4 elements and deployment nodes across all projects.
1140
+
1141
+ Query syntax (case-insensitive):
1142
+ - kind:<value> filters by kind
1143
+ - shape:<value> filters by shape
1144
+ - meta:<key> filters by having metadata with the given key
1145
+ - #<value> matches assigned tags
1146
+ - <value> matches id (FQN) or title
1147
+
1148
+ Request:
1149
+ - search: string — at least 2 characters
1150
+
1151
+ Response (JSON object):
1152
+ - total: number - total number of results
1153
+ - found: Result[] - returns top 20 results
1154
+
1155
+ Result (discriminated union by "type"):
1156
+ - type = "element": { id: string, name: string, kind: string, title: string, technology: string|null, shape: string, project: string, includedInViews: View[], tags: string[], metadata: Record<string, string> }
1157
+ - type = "deployment-node": { id: string, name: string, kind: string, title: string, technology: string|null, shape: string, project: string, includedInViews: View[], tags: string[], metadata: Record<string, string> }
1158
+
1159
+ View (object) fields:
1160
+ - id: string — view identifier
1161
+ - title: string — view title
1162
+ - type: "element" | "deployment" | "dynamic"
1163
+
1164
+ Notes:
1165
+ - Read-only, idempotent.
1166
+ - Use results as input to other tools (e.g., read-element, read-view).
1167
+
1168
+ Example response:
1169
+ {
1170
+ "total": 1,
1171
+ "found": [
1172
+ {
1173
+ "type": "logical",
1174
+ "project": "default",
1175
+ "id": "shop.frontend",
1176
+ "name": "frontend",
1177
+ "kind": "container",
1178
+ "title": "Frontend",
1179
+ "technology": "React",
1180
+ "shape": "rectangle",
1181
+ "includedInViews": [
1182
+ {
1183
+ "id": "system-overview",
1184
+ "title": "System Overview",
1185
+ "type": "element"
1186
+ }
1187
+ ],
1188
+ "tags": ["public"],
1189
+ "metadata": {}
1190
+ }
1191
+ ]
1192
+ }
1193
+ `,inputSchema:{search:A().min(2,`Search must be at least 2 characters long`)},outputSchema:{total:k(),found:ja}},async(e,t)=>{let n=e.projects(),r=[],i=t.search.toLowerCase(),a;i.startsWith(`kind:`)?(i=i.slice(5),X.debug(`search by kind: {search}`,{search:i}),a=e=>e.kind.toLowerCase()===i):i.startsWith(`shape:`)?(i=i.slice(6),X.debug(`search by shape: {search}`,{search:i}),a=e=>e.shape.toLowerCase()===i):i.startsWith(`meta:`)?(i=i.slice(5),X.debug(`search by metadata: {search}`,{search:i}),a=e=>!!e.getMetadata(i)):i.startsWith(`#`)?(i=i.slice(1),X.debug(`search by tag: {search}`,{search:i}),a=e=>e.tags.some(e=>e.toLowerCase().includes(i))):(X.debug(`search by id/title: {search}`,{search:i}),a=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 at(n.elements(),e=>!e.imported&&a(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:ra(e.views())});for(let e of at(n.deployment.nodes(),a))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:ra(e.views())})}catch(e){X.error(`Error searching in project ${t.id}:`,{error:e})}return{total:r.length,found:r.slice(0,20)}}),Na=w({id:A().describe(`Element id (FQN)`),name:A().describe(`Element name`),kind:A().describe(`Element kind`),title:A().describe(`Human-readable title`),depth:k().describe(`Depth relative to the root element (1 = direct child)`),tags:D(A()).describe(`Assigned tags`),metadata:E(T([A(),D(A())])).describe(`Element metadata`),childCount:k().describe(`Number of direct children`),incomingCount:k().describe(`Number of incoming relationships`),outgoingCount:k().describe(`Number of outgoing relationships`)}),Pa=Z({name:`subgraph-summary`,description:`
1194
+ Get a compact, table-friendly summary of all descendants of a parent element.
1195
+ Returns each descendant with its depth, metadata, tags, and relationship counts in a single call.
1196
+ Much more efficient than calling read-element for each descendant individually.
1197
+
1198
+ Request:
1199
+ - elementId: string — parent element id (FQN) whose descendants to summarize
1200
+ - maxDepth: number (optional, default: 10, max: 20) — maximum depth of descendants to include
1201
+ - metadataKeys: string[] (optional) — if provided, only include these metadata keys in the response (reduces response size)
1202
+ - project: string (optional) — project id. Defaults to "default" if omitted.
1203
+
1204
+ Response (JSON object):
1205
+ - root: object — the root element summary
1206
+ - id: string — element id
1207
+ - kind: string — element kind
1208
+ - title: string — element title
1209
+ - childCount: number — number of direct children
1210
+ - descendants: Array of descendant summaries, each with:
1211
+ - id: string — element id (FQN)
1212
+ - name: string — element name
1213
+ - kind: string — element kind
1214
+ - title: string — human-readable title
1215
+ - depth: number — depth relative to root (1 = direct child)
1216
+ - tags: string[] — assigned tags
1217
+ - metadata: Record<string, string | string[]> — element metadata (filtered by metadataKeys if provided)
1218
+ - childCount: number — number of direct children
1219
+ - incomingCount: number — number of incoming relationships
1220
+ - outgoingCount: number — number of outgoing relationships
1221
+ - totalDescendants: number — total number of descendants (may differ from array length if truncated)
1222
+ - truncated: boolean — true if results were truncated due to exceeding the 200-result limit
1223
+ - truncatedByDepth: boolean — true if deeper descendants exist beyond maxDepth
1224
+
1225
+ Notes:
1226
+ - Read-only, idempotent, no side effects.
1227
+ - Safe to call repeatedly.
1228
+ - Limited to 200 descendants in the response.
1229
+ - Use metadataKeys to reduce response size when you only need specific metadata.
1230
+ - Descendants are returned in breadth-first order (closest to root first).
1231
+ - depth=1 means direct child, depth=2 means grandchild, etc.
1232
+
1233
+ Example response:
1234
+ {
1235
+ "root": {
1236
+ "id": "top.planner",
1237
+ "kind": "subsystem",
1238
+ "title": "Planner Subsystem",
1239
+ "childCount": 5
1240
+ },
1241
+ "descendants": [
1242
+ {
1243
+ "id": "top.planner.nodeA",
1244
+ "name": "nodeA",
1245
+ "kind": "cgf-node",
1246
+ "title": "nodeA :dwNodeTypeA",
1247
+ "depth": 1,
1248
+ "tags": ["is_in_dag", "target_asil_qm"],
1249
+ "metadata": { "target_asil": "QM", "safety_info_unit_asil": "QM" },
1250
+ "childCount": 0,
1251
+ "incomingCount": 3,
1252
+ "outgoingCount": 2
1253
+ }
1254
+ ],
1255
+ "totalDescendants": 5,
1256
+ "truncated": false,
1257
+ "truncatedByDepth": false
1258
+ }
1259
+ `,annotations:{readOnlyHint:!0,idempotentHint:!0,title:`Subgraph summary`},inputSchema:{elementId:A().describe(`Parent element id (FQN) whose descendants to summarize`),maxDepth:k().int().min(1).max(20).optional().default(10).describe(`Maximum depth of descendants to include (default: 10, max: 20)`),metadataKeys:D(A()).optional().describe(`If provided, only include these metadata keys in the response`),project:$},outputSchema:{root:w({id:A(),kind:A(),title:A(),childCount:k()}),descendants:D(Na),totalDescendants:k().describe(`Total number of descendants found`),truncated:O().describe(`True if results were truncated due to exceeding the limit`),truncatedByDepth:O().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);j(r,`Element "${t.elementId}" not found in project "${n}"`);let i=t.maxDepth,a=t.metadataKeys,o=[],s=0,c=!1,l=!1,u=[],d=[...r.children()];for(let e of d)u.push({element:e,depth:1});for(;u.length>0;){let{element:e,depth:t}=u.shift();if(t>i){l=!0;continue}s++;let n=[...e.children()];if(o.length<200){let r=e.getMetadata(),i=a?Object.fromEntries(a.filter(e=>e in r).map(e=>[e,r[e]])):r;o.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 c=!0;for(let e of n)u.push({element:e,depth:t+1})}return{root:{id:r.id,kind:r.kind,title:r.title,childCount:d.length},descendants:o,totalDescendants:s,truncated:c,truncatedByDepth:l}});function Fa(e,t){let n=new Be({name:`LikeC4`,version:Xi},{instructions:`LikeC4 MCP – query and navigate LikeC4 models.
1260
+
1261
+ Conventions:
1262
+ - All tools are read-only and idempotent.
1263
+ - "project" is optional and defaults to "default".
1264
+
1265
+ Available tools:
1266
+ - list-projects — List all LikeC4 projects in the workspace.
1267
+ - read-project-summary — Project specification, configuration, all elements, deployment nodes and views. Input: { project? }.
1268
+ - search-element — Search elements and deployment nodes across all projects by id/title/kind/shape/tags/metadata. Input: { search }.
1269
+ - read-element — Full element details including relationships, includedInViews, deployedInstances, metadata and sourceLocation. Input: { id, project? }.
1270
+ - read-deployment — Details of a deployment node or deployed instance. Input: { id, project? }.
1271
+ - read-view — Full view details (nodes/edges) and sourceLocation. Input: { viewId, project? }.
1272
+ - find-relationships — Direct and indirect relationships between two elements in a project. Input: { element1, element2, project? }.
1273
+ - query-graph — Query element hierarchy (ancestors, descendants, siblings, children, parent) and relationships (incomers, outgoers). Input: { elementId, queryType, includeIndirect?, project? }.
1274
+ - query-incomers-graph — Get complete graph of all upstream dependencies/producers (recursive incomers). Much more efficient than repeated query-graph calls. Input: { elementId, includeIndirect?, maxDepth?, maxNodes?, project? }.
1275
+ - query-outgoers-graph — Get complete graph of all downstream consumers/dependents (recursive outgoers). Much more efficient than repeated query-graph calls. Input: { elementId, includeIndirect?, maxDepth?, maxNodes?, project? }.
1276
+ - query-by-metadata — Search elements by metadata key-value pairs with exact/contains/exists matching. Input: { key, value?, matchMode?, project? }.
1277
+ - query-by-tags — Advanced tag filtering with boolean logic (allOf, anyOf, noneOf). Input: { allOf?, anyOf?, noneOf?, project? }.
1278
+ - find-relationship-paths — Discover all paths (chains of relationships) between two elements with BFS traversal. Input: { sourceId, targetId, maxDepth?, includeIndirect?, project? }.
1279
+ - batch-read-elements — Read details of multiple elements in a single call, reducing round-trips. Input: { ids, project? }.
1280
+ - query-by-tag-pattern — Search elements by tag prefix/contains/suffix patterns. Input: { pattern, matchMode?, project? }.
1281
+ - element-diff — Compare two elements side-by-side showing differences in properties, tags, metadata, and relationships. Input: { element1Id, element2Id, project? }.
1282
+ - subgraph-summary — Compact summary of all descendants of a parent element with metadata, tags, and relationship counts. Input: { elementId, maxDepth?, metadataKeys?, project? }.
1283
+
1284
+ Instructions:
1285
+ - Identify the project first
1286
+ - Use "search-element" to find elements by id/title/kind/shape/tags/metadata and select the project
1287
+ - Use "read-project-summary" to find all elements and deployment nodes inside the project, what kinds, tags, metadata keys are available
1288
+ - Use "list-projects" to list all available projects
1289
+ - If response returns "sourceLocation", provide link to this location in the editor
1290
+
1291
+ Full documentation: https://likec4.dev/llms-full.txt
1292
+ `,enforceStrictCapabilities:!0,...t,capabilities:{tools:{},logging:{},...t?.capabilities}});return n.registerTool(...ma(e)),n.registerTool(...Da(e)),n.registerTool(...Ea(e)),n.registerTool(...Ta(e)),n.registerTool(...Aa(e)),n.registerTool(...Ma(e)),n.registerTool(...pa(e)),n.registerTool(...ba(e)),n.registerTool(...Sa(e)),n.registerTool(...wa(e)),n.registerTool(...ga(e)),n.registerTool(...va(e)),n.registerTool(...ua(e)),n.registerTool(...oa(e)),n.registerTool(..._a(e)),n.registerTool(...la(e)),n.registerTool(...Pa(e)),n.server.onerror=e=>{p.error(h(e))},n}var Ia=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||(X.info(`Starting MCP stdio server`),this._mcp=Fa(this.services),this.transport=new ze,await this._mcp.connect(this.transport),X.info(`LikeC4 MCP Server running on stdio`))}async stop(){if(this.transport)try{X.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 La(e){let t=new ue;t.use(`*`,fe({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 de({eventStore:new pe({})});return t.all(`/mcp`,async e=>(n.isConnected()||await n.connect(r),await r.handleRequest(e))),t.notFound(e=>(X.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)=>(X.error(h(e)),t.json({jsonrpc:`2.0`,error:{code:-32603,message:`Internal server error`},id:null},{status:500}))),t}async function Ra(e){let{factory:t,port:n}=e,r=await La(t);return new Promise((e,t)=>{let i=Ge({fetch:r.fetch,hostname:`0.0.0.0`,port:n}).prependOnceListener(`error`,t).prependOnceListener(`listening`,()=>{i.removeListener(`error`,t),e(i.unref())})})}var za=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()}X.info(`Starting MCP server on port {port}`,{port:e}),this._port=e,this.server=await Ra({factory:()=>Fa(this.services),port:e}),X.info(`MCP server ready at http://0.0.0.0:{port}/mcp`,{port:e})}stop(){let e=this.server;return e?(X.info(`Stopping MCP server`),this.server=void 0,new Promise(t=>{e.close(e=>{e?X.error(`Failed to stop MCP server`,{err:e}):X.info(`MCP server stopped`),t()})})):(X.info(`MCP server is not running, nothing to stop`),Promise.resolve())}};async function Ba(e){let t=ne(e,{workspacePath:`.`,mcp:`stdio`,graphviz:`wasm`,watch:!0,throwIfInvalid:!1,configureLogger:!0});t.configureLogger&&(y({useStdErr:t.mcp===`stdio`,colors:x.isColorSupported&&t.mcp!==`stdio`,logLevel:ft?`debug`:`info`}),process.on(`uncaughtException`,e=>{X.error(`uncaughtException`,{err:e})}),process.on(`unhandledRejection`,e=>{X.error(`unhandledRejection`,{err:e})}));let n=F(t.workspacePath);X.info`Loading LikeC4 from workspace: ${n}`;let r=await v(n,{graphviz:t.graphviz,manualLayouts:!0,configureLogger:!1,watch:t.watch,throwIfInvalid:t.throwIfInvalid}),i=r.languageServices;return{server:t.mcp===`stdio`?new Ia(i):new za(i,t.mcp.port),likec4:r}}async function Va(e){let t=await Ba(e);return await t.server.start(),t}const Ha=e=>e.command({command:`mcp [path]`,aliases:[],describe:`Start MCP server`,builder:e=>e.usage(`${x.bold(`Usage:`)} $0 mcp [path]`).positional(`path`,W).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`,G).option(`log-level`,vn).option(`verbose`,yn).showHidden().epilog(`${x.bold(`Examples:`)}
1293
+ ${x.green(`$0 mcp`)}
1294
+ ${x.gray(`Start MCP with default stdio transport`)}
1295
+ ${x.green(`$0 mcp --http ./src`)}
1296
+ ${x.gray(`Start MCP with streamable http transport on port 33335 at ./src folder`)}
1297
+ ${x.green(`$0 mcp -p 1234`)}
1298
+ ${x.gray(`Start MCP with streamable http transport on port 1234`)}
1299
+ `),handler:async e=>{e.http||e.port?(y({colors:x.isColorSupported,logLevel:e.verbose?bn:e.logLevel}),await Ua(e.path,e.useDot,e.port)):(y({useStdErr:!0,colors:!1,logLevel:e.verbose?bn:e.logLevel}),await Wa(e.path,e.useDot))}});async function Ua(e,t,n=33335){await Va({workspacePath:e,mcp:{port:n},watch:!0,configureLogger:!1,graphviz:t?`binary`:`wasm`}),U([x.green(`LikeC4 MCP served at:`),`
169
1300
  {
170
1301
  "mcpServers": {
171
1302
  "likec4": {
@@ -174,18 +1305,18 @@ ${y.green(`$0 mcp -p 1234`)}
174
1305
  }
175
1306
  }
176
1307
 
177
- ${y.dim(`Documentation:`)}
178
- ${y.underline(`https://likec4.dev/tooling/mcp/#using-extension`)}
1308
+ ${x.dim(`Documentation:`)}
1309
+ ${x.underline(`https://likec4.dev/tooling/mcp/#using-extension`)}
179
1310
  `].join(`
180
- `))}async function _i(e,t){await Ee(e,{mcp:`stdio`,watch:!0,configureLogger:!1,graphviz:t?`binary`:`wasm`})}async function vi(e){let t=await jt({...e,likec4AssetsDir:``,webcomponentPrefix:void 0}),n=await Oe({port:De(62001,62010)}),r=e?.open??!1;return await gt({...t,customLogger:t.customLogger,mode:`production`,preview:{host:e.listen??`127.0.0.1`,allowedHosts:!0,port:n,open:r}})}async function yi({path:e,output:t,base:n,listen:r}){ri(await vi({base:n,languageServices:await C(e,{watch:!1}),outputDir:t,open:!T(),listen:r}))}const bi=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
181
- 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`],E).default(`path`,E(`.`),`.`).default(`listen`,`127.0.0.1`,`localhost`),handler:async e=>{await yi(e)}});async function xi({path:e,useDotBin:t,webcomponentPrefix:n,title:r,useHashHistory:i,enableWebcomponent:a=!0,enableHMR:o=!0,base:s,listen:c,port:l}){o&&(process.env.NODE_ENV=`development`);let u=await ii({buildWebcomponent:a,hmr:o,base:s,webcomponentPrefix:n,title:r,languageServices:await C(e,{graphviz:t?`binary`:`wasm`,watch:o}),useHashHistory:i,likec4AssetsDir:await qe(M(ze(),`.likec4-assets-`)),listen:c,port:l});u.config.logger.clearScreen(`info`),ri(u),vt(Y,1e3).unref()}const Si=e=>e.command({command:`start [path]`,aliases:[`serve`,`dev`],describe:`Start local dev server to preview LikeC4 views`,builder:e=>e.positional(`path`,W).option(`base`,Vt).option(`webcomponent-prefix`,zt).option(`title`,Bt).option(`use-hash-history`,Rt).option(`use-dot`,G).option(`listen`,Ut).option(`port`,Wt).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 U(),await xi({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 Ci(e,t,n,r){let i=await Kn(t,n,{idempotent:!0}),a=P(e,`sync-plan.json`);if(await k(a,JSON.stringify(i,null,2)),r.info(`${y.dim(`generated`)} ${N(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 wi(e,t,n,r){let i=await qn(t.manifest,t.dryRun,n,{idempotent:!0}),a=P(e,yr.manifest);if(await k(a,JSON.stringify(i.manifest,null,2)),r.info(`${y.dim(`generated`)} ${N(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 Ti(e){let t=B(`c4:sync:leanix`),n=V(t),{path:r,outdir:i,project:a,useDotBin:o,dryRun:s,apply:c}=e;try{try{var l=X();if(s&&c)throw Error(`Choose either dryRun or apply, not both`);let e=l.a(await C(r,{graphviz:o?`binary`:`wasm`,watch:!1})),{projectId:n}=Z(e,a);a&&t.info(`${y.dim(`project`)} ${y.green(n)}`);let u=await e.layoutedModel(n);if(u===w.EMPTY)throw t.error(ur),Error(ur);let d=_r(gr(u));await vr(i,d,t);let f=xr();if((s||!c)&&(f?await Ci(i,d.dryRun,f,t):t.info(`${y.dim(`skip`)} sync-plan (set LEANIX_API_TOKEN to include plan)`)),c){if(!f)throw t.error(dr),Error(dr);await wi(i,d,f,t)}}catch(e){l.e=e}finally{await l.d()}}finally{n.stopAndLog()}}const Ei=P(process.cwd(),`out`,`bridge`);function Di(e){return typeof e!=`object`||!e||!Object.hasOwn(e,`target`)?!1:typeof Reflect.get(e,`target`)==`string`}function Oi(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`,W).option(`outdir`,{...K,default:Ei,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`,q).option(`use-dot`,G).example(`${y.green(`$0 sync leanix --dry-run -o out/bridge`)}`,y.gray(`Write bridge artifacts and optionally sync-plan when LEANIX_API_TOKEN is set`)).example(`${y.green(`$0 sync leanix --apply -o out/bridge`)}`,y.gray(`Write artifacts then run live sync; updates manifest with LeanIX IDs`)),handler:async e=>{if(!Di(e)||e.target!==`leanix`)return;let t=e.apply??!1,n=e.dryRun??!t;await Ti({path:e.path??`.`,outdir:e.outdir??Ei,project:e.project,useDotBin:e.useDotBin??!1,dryRun:n,apply:t})}})}const ki=e=>e.command({command:`validate [path]`,aliases:[],describe:`Validate syntax, semantics and layout drifts`,builder:e=>e.positional(`path`,W).options({project:q,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(`${y.bold(`Examples:`)}
182
- ${y.green(`$0 validate `)}
183
- ${y.gray(`Validate all in the current directory`)}
184
-
185
- ${y.green(`$0 validate --no-layout --json -f ./src/model.c4 -f ./src/deployment.c4 `)}
186
- ${y.gray([`Validate all`,`ignore layout drifts`,`report only errors from these files`,`output as JSON`].join(`, `))}
187
-
188
- ${y.green(`$0 validate --project my-project /some/where`)}
189
- ${y.gray(`Validate my-project in /some/where`)}
190
- `),handler:async e=>{try{var t=X();let n=B(`c4:validate`),r=V(n),i=e.json===!0,a=e.layout===!0,o=e.file?.map(e=>P(e))??null,s=t.a(await C(e.path,{watch:!1,printErrors:!i,throwIfInvalid:!1,configureLogger:i?`stderr`:!1})),c=s.getErrors().map(e=>({message:e.message,file:e.sourceFsPath,line:e.line,range:e.range})),l=[];if(a){n.debug(`running layout validation...`);try{let t=await s.diagrams(e.project);for(let n of t)n.drifts&&n.drifts.length>0&&l.push({message:`Layout drift detected on view '${n.id}'`,file:n.sourcePath?P(e.path,n.sourcePath):``,line:0,range:null})}catch(e){l.push({message:`Layout validation failed: ${e instanceof Error?e.message:String(e)}`,file:``,line:0,range:null})}}let u=[...c,...l],d=s.documentCount(),f=u.length,p=o?u.filter(e=>o.some(t=>e.file===t||e.file.endsWith(`/`+t)||e.file.endsWith(`\\`+t))):u,m=new Set(p.map(e=>e.file)),h=p.length===0;process.exitCode=h?0:1;let g={valid:h,errors:p,stats:{totalFiles:d,totalErrors:f,filteredFiles:o?m.size:d,filteredErrors:p.length}};if(i){console.log(JSON.stringify(g,null,2));return}for(let e of l)n.error(y.red(e.message)+(e.file?` at `+e.file:``));if(h)n.info(y.green(`✓ Valid`)+y.dim(` (${d} files)`));else{let e=o?`, ${p.length} in filtered files`:``;n.error(y.red(`✗ Invalid`)+y.dim(` (${d} files, ${f} errors${e})`))}r.stopAndLog(`validate `)}catch(e){t.e=e}finally{await t.d()}}});function Ai(e){let t=e??(He?`trace`:`info`);p({reset:!0,sinks:{console:g({formatter:y.isColorSupported?v():f()})},loggers:[{category:`likec4`,sinks:[`console`],lowestLevel:t}]})}async function ji(){!We&&!Ve&&!T()&&await en(),await o(ut(dt(ot)),Si,Zt,Nr,di,fi,bi,Oi,ki,hi,mi,rn,e=>e.command({command:`completion`,describe:`Generate completion script`,handler:()=>{e.showCompletionScript()}})).scriptName(`likec4`).usage(`Usage: $0 <command>`).version(bt).alias(`v`,`version`).alias(`h`,`help`).help(`help`).option(`log-level`,Gt).option(`verbose`,Kt).option(`color`,{boolean:!0,describe:[`force color output, or disable with --no-color`,`respects 'FORCE_COLOR' and 'NO_COLOR' env variables`].join(`
191
- `),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:":y.bold(`Globals:`),"Options:":y.bold(`Options:`),"Positionals:":y.bold(`Arguments:`),"Commands:":y.bold(`Commands:`),"Examples:":y.bold(`Examples:`)}).wrap(t(lt.columns-10,{min:60,max:180})).middleware(e=>{Ai(e.verbose?qt:e.logLevel)}).parseAsync()}function Mi(e,t){console.error(t==null?_(e):`${t} ${_(e)}`),st(1)}ji().catch(Mi),process.on(`unhandledRejection`,e=>{Mi(e,`Unhandled rejection:`)}),process.on(`uncaughtException`,e=>{console.error(e)});export{};
1311
+ `))}async function Wa(e,t){await Va({workspacePath:e,mcp:`stdio`,watch:!0,configureLogger:!1,graphviz:t?`binary`:`wasm`})}async function Ga(e){let t=await tn({...e,likec4AssetsDir:``,webcomponentPrefix:void 0}),n=await Ue({port:He(62001,62010)}),r=e?.open??!1;return await Bt({...t,customLogger:t.customLogger,mode:`production`,preview:{host:e.listen??`127.0.0.1`,allowedHosts:!0,port:n,open:r}})}async function Ka({path:e,output:t,base:n,listen:r}){Ii(await Ga({base:n,languageServices:await v(e,{watch:!1}),outputDir:t,open:!S(),listen:r}))}const qa=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
1312
+ 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`],I).default(`path`,I(`.`),`.`).default(`listen`,`127.0.0.1`,`localhost`),handler:async e=>{await Ka(e)}});async function Ja({path:e,useDotBin:t,webcomponentPrefix:n,title:r,useHashHistory:i,enableWebcomponent:a=!0,enableHMR:o=!0,base:s,listen:c,port:l}){o&&(process.env.NODE_ENV=`development`);let u=await Li({buildWebcomponent:a,hmr:o,base:s,webcomponentPrefix:n,title:r,languageServices:await v(e,{graphviz:t?`binary`:`wasm`,watch:o}),useHashHistory:i,likec4AssetsDir:await gt(N(lt(),`.likec4-assets-`)),listen:c,port:l});u.config.logger.clearScreen(`info`),Ii(u),Ht(J,1e3).unref()}const Ya=e=>e.command({command:`start [path]`,aliases:[`serve`,`dev`],describe:`Start local dev server to preview LikeC4 views`,builder:e=>e.positional(`path`,W).option(`base`,mn).option(`webcomponent-prefix`,dn).option(`title`,fn).option(`use-hash-history`,un).option(`use-dot`,G).option(`listen`,gn).option(`port`,_n).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 sn(),await Ja({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 Xa(e,t,n,r){let i=await wr(t,n,{idempotent:!0}),a=F(e,`sync-plan.json`);if(await R(a,JSON.stringify(i,null,2)),r.info(`${x.dim(`generated`)} ${P(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 Za(e,t,n,r){let i=await Tr(t.manifest,t.dryRun,n,{idempotent:!0}),a=F(e,Qr.manifest);if(await R(a,JSON.stringify(i.manifest,null,2)),r.info(`${x.dim(`generated`)} ${P(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 Qa(e){let t=V(`c4:sync:leanix`),n=H(t),{path:r,outdir:i,project:a,useDotBin:o,dryRun:s,apply:c}=e;try{try{var l=Y();if(s&&c)throw Error(`Choose either dryRun or apply, not both`);let e=l.a(await v(r,{graphviz:o?`binary`:`wasm`,watch:!1})),{projectId:n}=Nn(e,a);a&&t.info(`${x.dim(`project`)} ${x.green(n)}`);let u=await e.layoutedModel(n);if(u===Oe.EMPTY)throw t.error(Ur),Error(Ur);let d=Xr(Yr(u));await Zr(i,d,t);let f=ei();if((s||!c)&&(f?await Xa(i,d.dryRun,f,t):t.info(`${x.dim(`skip`)} sync-plan (set LEANIX_API_TOKEN to include plan)`)),c){if(!f)throw t.error(Wr),Error(Wr);await Za(i,d,f,t)}}catch(e){l.e=e}finally{await l.d()}}finally{n.stopAndLog()}}const $a=F(process.cwd(),`out`,`bridge`);function eo(e){return typeof e!=`object`||!e||!Object.hasOwn(e,`target`)?!1:typeof Reflect.get(e,`target`)==`string`}function to(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`,W).option(`outdir`,{...K,default:$a,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`,q).option(`use-dot`,G).example(`${x.green(`$0 sync leanix --dry-run -o out/bridge`)}`,x.gray(`Write bridge artifacts and optionally sync-plan when LEANIX_API_TOKEN is set`)).example(`${x.green(`$0 sync leanix --apply -o out/bridge`)}`,x.gray(`Write artifacts then run live sync; updates manifest with LeanIX IDs`)),handler:async e=>{if(!eo(e)||e.target!==`leanix`)return;let t=e.apply??!1,n=e.dryRun??!t;await Qa({path:e.path??`.`,outdir:e.outdir??$a,project:e.project,useDotBin:e.useDotBin??!1,dryRun:n,apply:t})}})}const no=e=>e.command({command:`validate [path]`,aliases:[],describe:`Validate syntax, semantics and layout drifts`,builder:e=>e.positional(`path`,W).options({project:q,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(`${x.bold(`Examples:`)}
1313
+ ${x.green(`$0 validate `)}
1314
+ ${x.gray(`Validate all in the current directory`)}
1315
+
1316
+ ${x.green(`$0 validate --no-layout --json -f ./src/model.c4 -f ./src/deployment.c4 `)}
1317
+ ${x.gray([`Validate all`,`ignore layout drifts`,`report only errors from these files`,`output as JSON`].join(`, `))}
1318
+
1319
+ ${x.green(`$0 validate --project my-project /some/where`)}
1320
+ ${x.gray(`Validate my-project in /some/where`)}
1321
+ `),handler:async e=>{try{var t=Y();let n=V(`c4:validate`),r=H(n),i=e.json===!0,a=e.layout===!0,o=e.file?.map(e=>F(e))??null,s=t.a(await v(e.path,{watch:!1,printErrors:!i,throwIfInvalid:!1,configureLogger:i?`stderr`:!1})),c=s.getErrors().map(e=>({message:e.message,file:e.sourceFsPath,line:e.line,range:e.range})),l=[];if(a){n.debug(`running layout validation...`);try{let t=await s.diagrams(e.project);for(let n of t)n.drifts&&n.drifts.length>0&&l.push({message:`Layout drift detected on view '${n.id}'`,file:n.sourcePath?F(e.path,n.sourcePath):``,line:0,range:null})}catch(e){l.push({message:`Layout validation failed: ${e instanceof Error?e.message:String(e)}`,file:``,line:0,range:null})}}let u=[...c,...l],d=s.documentCount(),f=u.length,p=o?u.filter(e=>o.some(t=>e.file===t||e.file.endsWith(`/`+t)||e.file.endsWith(`\\`+t))):u,m=new Set(p.map(e=>e.file)),h=p.length===0;process.exitCode=h?0:1;let g={valid:h,errors:p,stats:{totalFiles:d,totalErrors:f,filteredFiles:o?m.size:d,filteredErrors:p.length}};if(i){console.log(JSON.stringify(g,null,2));return}for(let e of l)n.error(x.red(e.message)+(e.file?` at `+e.file:``));if(h)n.info(x.green(`✓ Valid`)+x.dim(` (${d} files)`));else{let e=o?`, ${p.length} in filtered files`:``;n.error(x.red(`✗ Invalid`)+x.dim(` (${d} files, ${f} errors${e})`))}r.stopAndLog(`validate `)}catch(e){t.e=e}finally{await t.d()}}});function ro(e){let t=e??(ft?`trace`:`info`);b({reset:!0,sinks:{console:_({formatter:x.isColorSupported?te():m()})},loggers:[{category:`likec4`,sinks:[`console`],lowestLevel:t}]})}async function io(){!pt&&!dt&&!S()&&await On(),await o(Mt(Nt(Dt)),Ya,Tn,fi,Wi,Gi,qa,to,no,Ki,Ha,Ji,jn,e=>e.command({command:`completion`,describe:`Generate completion script`,handler:()=>{e.showCompletionScript()}})).scriptName(`likec4`).usage(`Usage: $0 <command>`).version(Wt).alias(`v`,`version`).alias(`h`,`help`).help(`help`).option(`log-level`,vn).option(`verbose`,yn).option(`color`,{boolean:!0,describe:[`force color output, or disable with --no-color`,`respects 'FORCE_COLOR' and 'NO_COLOR' env variables`].join(`
1322
+ `),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:":x.bold(`Globals:`),"Options:":x.bold(`Options:`),"Positionals:":x.bold(`Arguments:`),"Commands:":x.bold(`Commands:`),"Examples:":x.bold(`Examples:`)}).wrap(t(jt.columns-10,{min:60,max:180})).middleware(e=>{ro(e.verbose?bn:e.logLevel)}).parseAsync()}function ao(e,t){console.error(t==null?h(e):`${t} ${h(e)}`),kt(1)}io().catch(ao),process.on(`unhandledRejection`,e=>{ao(e,`Unhandled rejection:`)}),process.on(`uncaughtException`,e=>{console.error(e)});export{};