yamchart 0.10.1 → 0.10.3

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 (83) hide show
  1. package/dist/{advisor-5TJDNAY7.js → advisor-XTJQU7E4.js} +12 -12
  2. package/dist/{chunk-QUIDZO5G.js → chunk-2XJZJ6IA.js} +22 -6
  3. package/dist/chunk-2XJZJ6IA.js.map +1 -0
  4. package/dist/{chunk-UFDQ3C7Q.js → chunk-6ELSQNIH.js} +257 -257
  5. package/dist/chunk-6ELSQNIH.js.map +1 -0
  6. package/dist/{chunk-64CI3HSY.js → chunk-KDDO4UII.js} +70 -11
  7. package/dist/chunk-KDDO4UII.js.map +1 -0
  8. package/dist/{chunk-S2CH4HUZ.js → chunk-ODSPBOJW.js} +4 -4
  9. package/dist/chunk-OYBI433Z.js +1296 -0
  10. package/dist/chunk-OYBI433Z.js.map +1 -0
  11. package/dist/{chunk-ZBCQNWVN.js → chunk-PXFTWXSV.js} +5 -5
  12. package/dist/{chunk-5FHV22X2.js → chunk-XNMB25GT.js} +4 -4
  13. package/dist/{connection-utils-FEUWER5I.js → connection-utils-S7EFPTLY.js} +5 -5
  14. package/dist/{describe-MEP72B56.js → describe-TA2CTODC.js} +7 -7
  15. package/dist/{dev-H6SJZ5UA.js → dev-PHFYLJPJ.js} +2589 -1243
  16. package/dist/dev-PHFYLJPJ.js.map +1 -0
  17. package/dist/dev-supervisor-JXLVGEHP.js +43 -0
  18. package/dist/dev-supervisor-JXLVGEHP.js.map +1 -0
  19. package/dist/{dist-PPAD6KOM.js → dist-F6TVLP6C.js} +34 -4
  20. package/dist/{dist-XNCED7JW.js → dist-Q5ETETUU.js} +4 -4
  21. package/dist/{dist-5DQO6L2S.js → dist-YJOOH65Y.js} +9 -5
  22. package/dist/index.js +65 -42
  23. package/dist/index.js.map +1 -1
  24. package/dist/{init-SECXKD5G.js → init-TJJVKMEN.js} +24 -5
  25. package/dist/init-TJJVKMEN.js.map +1 -0
  26. package/dist/public/assets/DataView-V-E6oxy6.js +9 -0
  27. package/dist/public/assets/{EventManagement-BnmeJDQl.js → EventManagement-Do2xU5lV.js} +2 -2
  28. package/dist/public/assets/ExplorePage-Dg50mvGB.js +1 -0
  29. package/dist/public/assets/{LoginPage-CzaFkkjg.js → LoginPage-DmYGIXcu.js} +1 -1
  30. package/dist/public/assets/{PublicViewer-irjxqH6a.js → PublicViewer-CJTgc9OF.js} +1 -1
  31. package/dist/public/assets/{SetupWizard-ConWIcmy.js → SetupWizard-Bo-zmh43.js} +1 -1
  32. package/dist/public/assets/{ShareManagement-CP4wdwLR.js → ShareManagement-6Wp6b2Gp.js} +1 -1
  33. package/dist/public/assets/{SourceDetailView-DZS5518E.js → SourceDetailView-CTzSXhZc.js} +1 -1
  34. package/dist/public/assets/UserManagement-DQhB13T0.js +1 -0
  35. package/dist/public/assets/{index-jlfTO7f5.js → index-CY8xsfQH.js} +41 -41
  36. package/dist/public/assets/{index-C1X8RW4Z.css → index-Dkn-tJCT.css} +1 -1
  37. package/dist/public/assets/{index.es-CgnvEWi5.js → index.es-Bc3yys5L.js} +1 -1
  38. package/dist/public/assets/{jspdf.es.min-Cw5WefMt.js → jspdf.es.min-D94JEH-J.js} +3 -3
  39. package/dist/public/index.html +2 -2
  40. package/dist/{query-2H3YOPI2.js → query-AX4BOPMH.js} +5 -5
  41. package/dist/sample-4NUBJGIL.js +76 -0
  42. package/dist/sample-4NUBJGIL.js.map +1 -0
  43. package/dist/{search-IPE4ISFB.js → search-IBVVYN4I.js} +7 -7
  44. package/dist/{semantic-K3MYXXJI.js → semantic-33YIUMUV.js} +39 -4
  45. package/dist/semantic-33YIUMUV.js.map +1 -0
  46. package/dist/semantic-5WGVZ7HY.js +30 -0
  47. package/dist/{source-resolver-HZQLOODU.js → source-resolver-GYXIRIVK.js} +7 -7
  48. package/dist/source-resolver-GYXIRIVK.js.map +1 -0
  49. package/dist/{sync-warehouse-TUNULDUY.js → sync-warehouse-5NKENCOZ.js} +15 -11
  50. package/dist/sync-warehouse-5NKENCOZ.js.map +1 -0
  51. package/dist/{tables-K5NAN2WK.js → tables-QMZMYYV5.js} +7 -7
  52. package/dist/templates/default/docs/yamchart-reference.md +26 -0
  53. package/dist/{test-SRHVOXZB.js → test-6MCPGXJP.js} +19 -7
  54. package/dist/test-6MCPGXJP.js.map +1 -0
  55. package/package.json +2 -2
  56. package/dist/chunk-64CI3HSY.js.map +0 -1
  57. package/dist/chunk-QUIDZO5G.js.map +0 -1
  58. package/dist/chunk-UFDQ3C7Q.js.map +0 -1
  59. package/dist/chunk-ZIY22VO7.js +0 -1190
  60. package/dist/chunk-ZIY22VO7.js.map +0 -1
  61. package/dist/dev-H6SJZ5UA.js.map +0 -1
  62. package/dist/init-SECXKD5G.js.map +0 -1
  63. package/dist/public/assets/DataView-DUCz_96y.js +0 -9
  64. package/dist/public/assets/ExplorePage-kk4z9ldZ.js +0 -1
  65. package/dist/public/assets/UserManagement-AubGd9hl.js +0 -1
  66. package/dist/sample-ODUGGSFA.js +0 -42
  67. package/dist/sample-ODUGGSFA.js.map +0 -1
  68. package/dist/semantic-K3MYXXJI.js.map +0 -1
  69. package/dist/sync-warehouse-TUNULDUY.js.map +0 -1
  70. package/dist/test-SRHVOXZB.js.map +0 -1
  71. /package/dist/{advisor-5TJDNAY7.js.map → advisor-XTJQU7E4.js.map} +0 -0
  72. /package/dist/{chunk-S2CH4HUZ.js.map → chunk-ODSPBOJW.js.map} +0 -0
  73. /package/dist/{chunk-ZBCQNWVN.js.map → chunk-PXFTWXSV.js.map} +0 -0
  74. /package/dist/{chunk-5FHV22X2.js.map → chunk-XNMB25GT.js.map} +0 -0
  75. /package/dist/{connection-utils-FEUWER5I.js.map → connection-utils-S7EFPTLY.js.map} +0 -0
  76. /package/dist/{describe-MEP72B56.js.map → describe-TA2CTODC.js.map} +0 -0
  77. /package/dist/{dist-5DQO6L2S.js.map → dist-F6TVLP6C.js.map} +0 -0
  78. /package/dist/{dist-PPAD6KOM.js.map → dist-Q5ETETUU.js.map} +0 -0
  79. /package/dist/{dist-XNCED7JW.js.map → dist-YJOOH65Y.js.map} +0 -0
  80. /package/dist/{query-2H3YOPI2.js.map → query-AX4BOPMH.js.map} +0 -0
  81. /package/dist/{search-IPE4ISFB.js.map → search-IBVVYN4I.js.map} +0 -0
  82. /package/dist/{source-resolver-HZQLOODU.js.map → semantic-5WGVZ7HY.js.map} +0 -0
  83. /package/dist/{tables-K5NAN2WK.js.map → tables-QMZMYYV5.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/init.ts"],"sourcesContent":["import { mkdir, readFile, writeFile, access, readdir, copyFile } from 'fs/promises';\nimport { join, dirname, basename } from 'path';\nimport { fileURLToPath } from 'url';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nexport interface InitOptions {\n empty?: boolean;\n example?: boolean;\n force?: boolean;\n}\n\nexport interface InitResult {\n success: boolean;\n files: string[];\n error?: string;\n}\n\n/**\n * Check if a directory exists and is accessible.\n */\nasync function directoryExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Get the templates directory path.\n * Handles both development (src/commands) and production (dist/) contexts.\n */\nasync function getTemplatesDir(): Promise<string> {\n // In production (dist/), templates are at dist/templates\n const distTemplates = join(__dirname, 'templates');\n if (await directoryExists(distTemplates)) {\n return distTemplates;\n }\n\n // In development (src/commands), templates are at src/templates\n const srcTemplates = join(__dirname, '../templates');\n if (await directoryExists(srcTemplates)) {\n return srcTemplates;\n }\n\n throw new Error('Templates not found. Reinstall yamchart or check installation.');\n}\n\n/**\n * Get the examples directory path.\n * Handles both development and production contexts.\n */\nasync function getExamplesDir(): Promise<string> {\n // In production (dist/): dist -> cli -> apps -> yamchart -> examples\n const distExamples = join(__dirname, '../../../examples');\n if (await directoryExists(distExamples)) {\n return distExamples;\n }\n\n // In development (src/commands): src/commands -> src -> cli -> apps -> yamchart -> examples\n const srcExamples = join(__dirname, '../../../../examples');\n if (await directoryExists(srcExamples)) {\n return srcExamples;\n }\n\n throw new Error('Example assets not found. Reinstall yamchart or use default mode.');\n}\n\nexport async function initProject(projectDir: string, options: InitOptions): Promise<InitResult> {\n const projectName = basename(projectDir);\n const files: string[] = [];\n\n // Check if yamchart.yaml already exists\n const yamchartYamlPath = join(projectDir, 'yamchart.yaml');\n try {\n await access(yamchartYamlPath);\n if (!options.force) {\n return {\n success: false,\n files: [],\n error: `${yamchartYamlPath} already exists. Use --force to overwrite.`,\n };\n }\n } catch {\n // File doesn't exist, continue\n }\n\n // Create project directory and assets dir\n await mkdir(projectDir, { recursive: true });\n await mkdir(join(projectDir, 'assets'), { recursive: true });\n\n try {\n if (options.example) {\n // Copy example project\n const examplesDir = await getExamplesDir();\n await copyDirectory(examplesDir, projectDir, files, projectName);\n } else if (options.empty) {\n // Empty mode - only yamchart.yaml\n const templateDir = join(await getTemplatesDir(), 'empty');\n await copyTemplate(templateDir, projectDir, files, projectName);\n } else {\n // Default mode - minimal working project\n const templateDir = join(await getTemplatesDir(), 'default');\n await copyTemplate(templateDir, projectDir, files, projectName);\n }\n } catch (err) {\n return {\n success: false,\n files: [],\n error: err instanceof Error ? err.message : 'Failed to create project',\n };\n }\n\n // Ensure yamchart.local.yaml is gitignored\n const gitignorePath = join(projectDir, '.gitignore');\n const gitignoreEntry = 'yamchart.local.yaml';\n try {\n const existing = await readFile(gitignorePath, 'utf-8');\n if (!existing.includes('yamchart.local.yaml')) {\n await writeFile(gitignorePath, existing.trimEnd() + '\\n' + gitignoreEntry + '\\n', 'utf-8');\n }\n } catch {\n // No .gitignore exists, create one\n await writeFile(gitignorePath, gitignoreEntry + '\\n', 'utf-8');\n }\n if (!files.includes('.gitignore')) {\n files.push('.gitignore');\n }\n\n return { success: true, files };\n}\n\nasync function copyTemplate(\n templateDir: string,\n targetDir: string,\n files: string[],\n projectName: string,\n basePath: string = ''\n): Promise<void> {\n const entries = await readdir(templateDir, { withFileTypes: true });\n\n for (const entry of entries) {\n const srcPath = join(templateDir, entry.name);\n const destPath = join(targetDir, entry.name);\n const relativePath = basePath ? `${basePath}/${entry.name}` : entry.name;\n\n if (entry.isDirectory()) {\n await mkdir(destPath, { recursive: true });\n await copyTemplate(srcPath, destPath, files, projectName, relativePath);\n } else {\n let content = await readFile(srcPath, 'utf-8');\n content = content.replace(/\\{\\{name\\}\\}/g, projectName);\n await writeFile(destPath, content, 'utf-8');\n files.push(relativePath);\n }\n }\n}\n\nasync function copyDirectory(\n srcDir: string,\n destDir: string,\n files: string[],\n projectName: string,\n basePath: string = ''\n): Promise<void> {\n const entries = await readdir(srcDir, { withFileTypes: true });\n\n for (const entry of entries) {\n // Skip node_modules, lock files, and hidden files (except .claude)\n if (\n entry.name === 'node_modules' ||\n entry.name === 'pnpm-lock.yaml' ||\n entry.name === 'package-lock.json' ||\n entry.name === 'yarn.lock' ||\n entry.name === 'package.json' ||\n (entry.name.startsWith('.') && entry.name !== '.claude')\n ) {\n continue;\n }\n\n const srcPath = join(srcDir, entry.name);\n const destPath = join(destDir, entry.name);\n const relativePath = basePath ? `${basePath}/${entry.name}` : entry.name;\n\n if (entry.isDirectory()) {\n await mkdir(destPath, { recursive: true });\n await copyDirectory(srcPath, destPath, files, projectName, relativePath);\n } else {\n // For binary files (like .duckdb), copy directly\n if (entry.name.endsWith('.duckdb')) {\n await copyFile(srcPath, destPath);\n } else {\n // For text files, replace project name in yamchart.yaml\n let content = await readFile(srcPath, 'utf-8');\n if (entry.name === 'yamchart.yaml') {\n content = content.replace(/^name:\\s*\\S+/m, `name: ${projectName}`);\n }\n await writeFile(destPath, content, 'utf-8');\n }\n files.push(relativePath);\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,9 +0,0 @@
1
- import{v as S,j as e,Q as $,e as W}from"./index-jlfTO7f5.js";import{a as h}from"./echarts-DtOYsfLX.js";import{l as I}from"./data-3vtzSuAZ.js";function O({label:o,value:s}){return e.jsxs("div",{style:{display:"flex",flexDirection:"column"},children:[e.jsx("span",{style:{fontSize:"18px",fontWeight:600,color:"var(--yc-color-text)"},children:s}),e.jsx("span",{style:{fontSize:"12px",color:"var(--yc-color-text-secondary)"},children:o})]})}function M({source:o,onOpen:s}){return e.jsxs("div",{onClick:()=>s(o.name),style:{border:"1px solid var(--yc-color-border)",borderRadius:"8px",padding:"16px",background:"var(--yc-color-surface)",cursor:"pointer",display:"flex",flexDirection:"column",gap:"12px"},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between"},children:[e.jsx("span",{style:{fontSize:"15px",fontWeight:600,color:"var(--yc-color-text)"},children:o.name}),e.jsx("span",{style:{fontSize:"11px",fontWeight:500,padding:"2px 8px",borderRadius:"9999px",background:"var(--yc-color-bg)",color:"var(--yc-color-text-secondary)",border:"1px solid var(--yc-color-border)",letterSpacing:"0.04em"},children:o.type.toUpperCase()})]}),e.jsxs("div",{style:{display:"flex",gap:"24px"},children:[e.jsx(O,{label:"Tables",value:o.counts.tables}),e.jsx(O,{label:"Hunches",value:o.counts.pendingHunches}),e.jsx(O,{label:"Blindspots",value:o.counts.openBlindspots})]}),e.jsx("button",{onClick:t=>{t.stopPropagation(),s(o.name)},style:{alignSelf:"flex-start",fontSize:"13px",fontWeight:500,color:"var(--yc-color-primary)",background:"none",border:"none",padding:0,cursor:"pointer"},children:"Open →"})]})}function K(){const{data:o,isLoading:s,error:t}=S({queryKey:["sources"],queryFn:I}),n=c=>{window.location.hash=`/data/sources/${encodeURIComponent(c)}`};return e.jsxs("div",{className:"p-6 w-full",children:[e.jsx("h2",{className:"text-lg font-semibold mb-1",style:{color:"var(--yc-color-text)"},children:"Data Sources"}),e.jsx("p",{className:"text-sm mb-4",style:{color:"var(--yc-color-text-secondary)"},children:"Your connected data sources. Open one to browse its tables and add business context."}),t&&e.jsx("p",{className:"text-sm",style:{color:"var(--yc-color-danger)"},children:"Failed to load sources."}),s?e.jsx("p",{className:"text-sm",style:{color:"var(--yc-color-text-secondary)"},children:"Loading…"}):!o||o.length===0?e.jsxs("p",{className:"text-sm",style:{color:"var(--yc-color-text-secondary)"},children:["No connections configured. Add one in your project's ",e.jsx("code",{children:"connections/"})," directory."]}):e.jsx("div",{style:{display:"grid",gridTemplateColumns:"repeat(auto-fill, minmax(260px, 1fr))",gap:"16px"},children:o.map(c=>e.jsx(M,{source:c,onOpen:n},c.name))})]})}function J(o){const s=o.match(/event:\s*(\w+)\s*\ndata:\s*(\{[\s\S]*\})/);if(!s)return null;try{return{event:s[1],data:JSON.parse(s[2])}}catch{return null}}async function L(o,s="pending"){const t=new URLSearchParams({status:s,...o?{connection:o}:{}}),n=await fetch(`/api/hunches?${t}`);if(!n.ok)throw new Error("Failed to load hunches");return n.json()}async function U(o,s){return(await fetch(`/api/hunches/${o}/confirm`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s?{sql:s}:{})})).json()}async function V(o){return(await fetch(`/api/hunches/${o}/reject`,{method:"POST"})).json()}async function Q(o){return(await fetch(`/api/hunches/${o}/run`,{method:"POST"})).json()}async function G(o,s){const n=(await fetch("/api/learn",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({connection:o})})).body.getReader(),c=new TextDecoder;let d="";for(;;){const{done:p,value:a}=await n.read();if(p)break;d+=c.decode(a,{stream:!0});const l=d.split(`
2
-
3
- `);d=l.pop()??"";for(const y of l){const u=J(y+`
4
-
5
- `);u&&s(u)}}}async function R(o="open",s){const t=new URLSearchParams({status:o});return s&&t.set("connection",s),(await fetch(`/api/blindspots?${t}`)).json()}async function Y(o,s){return(await fetch(`/api/blindspots/${o}/answer`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({answer:s})})).json()}async function D(o){return(await fetch(`/api/blindspots/${o}/dismiss`,{method:"POST"})).json()}async function X(o,s){const n=(await fetch("/api/blindspots/scan",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({connection:o})})).body.getReader(),c=new TextDecoder;let d="";for(;;){const{done:p,value:a}=await n.read();if(p)break;d+=c.decode(a,{stream:!0});const l=d.split(`
6
-
7
- `);d=l.pop()??"";for(const y of l){const u=J(y+`
8
-
9
- `);u&&s(u)}}}const x=$(o=>({learning:!1,hunches:[],setLearning:s=>o({learning:s}),setPhase:s=>o({phase:s}),setHunches:s=>o({hunches:s}),removeHunch:s=>o(t=>({hunches:t.hunches.filter(n=>n.id!==s)}))}));function z({hunch:o,onConfirm:s,onReject:t,onRun:n,running:c}){const[d,p]=h.useState(o.sql);return e.jsxs("div",{className:"rounded-lg p-4 mb-3",style:{border:"1px solid var(--yc-color-border)",backgroundColor:"var(--yc-color-surface)"},children:[e.jsxs("div",{className:"flex items-start justify-between gap-2",children:[e.jsx("h3",{className:"font-medium",style:{color:"var(--yc-color-text)"},children:o.question}),o.confidence!=null&&e.jsxs("span",{className:"text-xs whitespace-nowrap",style:{color:"var(--yc-color-text-muted)"},children:[Math.round(o.confidence*100),"%"]})]}),o.rationale&&e.jsx("p",{className:"text-sm mt-1",style:{color:"var(--yc-color-text-secondary)"},children:o.rationale}),e.jsx("textarea",{className:"w-full font-mono text-sm mt-2 p-2 rounded",style:{backgroundColor:"var(--yc-color-input-bg)",border:"1px solid var(--yc-color-border)",color:"var(--yc-color-text)"},rows:3,value:d,onChange:a=>p(a.target.value),spellCheck:!1}),o.lastRunSample&&e.jsx("div",{className:"text-xs mt-2 overflow-auto max-h-40 rounded p-2",style:{backgroundColor:"var(--yc-color-input-bg)",color:"var(--yc-color-text-secondary)"},children:e.jsx("pre",{className:"font-mono",children:JSON.stringify(o.lastRunSample.rows.slice(0,5),null,2)})}),e.jsxs("div",{className:"flex gap-2 mt-3",children:[e.jsx("button",{onClick:()=>s(o.id,d),className:"px-3 py-1 rounded text-white text-sm hover:opacity-90",style:{backgroundColor:"var(--yc-color-primary)"},children:"Confirm"}),e.jsx("button",{onClick:()=>n(o.id,d),disabled:c,className:"px-3 py-1 rounded text-sm hover:opacity-80 disabled:opacity-50",style:{border:"1px solid var(--yc-color-border)",color:"var(--yc-color-text)"},children:c?"Running…":"Run"}),e.jsx("button",{onClick:()=>t(o.id),className:"px-3 py-1 rounded text-sm hover:opacity-80",style:{border:"1px solid var(--yc-color-border)",color:"var(--yc-color-text-secondary)"},children:"Reject"})]})]})}function Z({connection:o,onComplete:s}){const t=x(l=>l.learning),n=x(l=>l.phase),c=x(l=>l.setLearning),d=x(l=>l.setPhase),p=l=>l==="profiling"?"Profiling the source…":l==="generating"?"Generating hunches…":l==="error"?"Something went wrong.":"Learning…",a=async()=>{c(!0),d("profiling");try{await G(o,l=>{if(l.event==="status")d(l.data.phase);else if(l.event==="done"){const y=l.data.hunches??[];s==null||s(y)}else l.event==="error"&&d("error")})}catch{d("error")}finally{c(!1)}};return e.jsxs("div",{className:"rounded-lg p-5 mb-4 flex items-center justify-between gap-4",style:{border:"1px solid var(--yc-color-border)",backgroundColor:"var(--yc-color-surface)"},children:[e.jsxs("div",{children:[e.jsx("h3",{className:"font-medium",style:{color:"var(--yc-color-text)"},children:"Learn this source"}),e.jsxs("p",{className:"text-sm mt-1",style:{color:"var(--yc-color-text-secondary)"},children:["Profile ",e.jsx("span",{className:"font-mono",children:o})," and propose business questions you can confirm or edit."]}),t&&e.jsx("p",{className:"text-sm mt-2",style:{color:"var(--yc-color-primary)"},children:p(n)})]}),e.jsx("button",{onClick:a,disabled:t,className:"px-4 py-2 rounded text-white text-sm whitespace-nowrap hover:opacity-90 disabled:opacity-50",style:{backgroundColor:"var(--yc-color-primary)"},children:t?"Learning…":"Learn this source"})]})}function _({connection:o}={}){var r,g,A;const{data:s}=W(),t=((r=s==null?void 0:s.defaults)==null?void 0:r.connection)??((A=(g=s==null?void 0:s.connections)==null?void 0:g[0])==null?void 0:A.name)??"",n=o??t,[c,d]=h.useState("pending"),p=x(i=>i.hunches),a=x(i=>i.setHunches),l=x(i=>i.removeHunch),[y,u]=h.useState(null),{data:f,isLoading:P,error:H}=S({queryKey:["hunches",n,"pending"],queryFn:()=>L(n||void 0,"pending"),enabled:!!n&&c==="pending"}),{data:b,isLoading:T,error:q}=S({queryKey:["hunches",n,"confirmed"],queryFn:()=>L(n||void 0,"confirmed"),enabled:!!n&&c==="approved"});h.useEffect(()=>{f&&a(f)},[f,a]);const C=async(i,m)=>{l(i);try{await U(i,m)}catch{a(await L(n||void 0,"pending"))}},k=async i=>{l(i);try{await V(i)}catch{a(await L(n||void 0,"pending"))}},j=async i=>{u(i);try{const m=await Q(i);m.sample&&a(x.getState().hunches.map(N=>N.id===i?{...N,lastRunSample:m.sample}:N))}finally{u(null)}},B=i=>{const m=new Set(x.getState().hunches.map(F=>F.id)),N=i.filter(F=>!m.has(F.id));a([...N,...x.getState().hunches])},w=(i,m)=>e.jsx("button",{onClick:()=>d(i),style:{color:c===i?"var(--yc-color-primary)":"var(--yc-color-text-secondary)",borderBottom:c===i?"2px solid var(--yc-color-primary)":"2px solid transparent",paddingBottom:"6px",marginRight:"16px",background:"none",border:"none",cursor:"pointer",fontSize:"14px",fontWeight:c===i?600:400},children:m});return e.jsxs("div",{className:"p-6 max-w-3xl mx-auto w-full",children:[e.jsx("h2",{className:"text-lg font-semibold mb-1",style:{color:"var(--yc-color-text)"},children:"Hunches"}),e.jsx("p",{className:"text-sm mb-4",style:{color:"var(--yc-color-text-secondary)"},children:"Confirm, edit, run, or reject the questions learned from your source."}),e.jsxs("div",{style:{display:"flex",borderBottom:"1px solid var(--yc-color-border)",marginBottom:"16px"},children:[w("pending","Pending"),w("approved","Approved")]}),c==="pending"&&e.jsxs(e.Fragment,{children:[n?e.jsx(Z,{connection:n,onComplete:B}):e.jsx("p",{className:"text-sm",style:{color:"var(--yc-color-text-secondary)"},children:"No connection configured."}),H&&e.jsx("p",{className:"text-sm",style:{color:"var(--yc-color-danger)"},children:"Failed to load hunches."}),P?e.jsx("p",{className:"text-sm",style:{color:"var(--yc-color-text-secondary)"},children:"Loading…"}):p.length===0?e.jsx("p",{className:"text-sm",style:{color:"var(--yc-color-text-secondary)"},children:"No pending hunches. Learn this source to generate some."}):p.map(i=>e.jsx(z,{hunch:i,onConfirm:C,onReject:k,onRun:j,running:y===i.id},i.id))]}),c==="approved"&&e.jsxs(e.Fragment,{children:[q&&e.jsx("p",{className:"text-sm",style:{color:"var(--yc-color-danger)"},children:"Failed to load approved hunches."}),T?e.jsx("p",{className:"text-sm",style:{color:"var(--yc-color-text-secondary)"},children:"Loading…"}):!b||b.length===0?e.jsx("p",{className:"text-sm",style:{color:"var(--yc-color-text-secondary)"},children:"No approved hunches yet. Confirm some from the Pending tab."}):b.map(i=>e.jsx(z,{hunch:i,onConfirm:C,onReject:k,onRun:j,running:y===i.id},i.id))]})]})}const v=$(o=>({scanning:!1,blindspots:[],setScanning:s=>o({scanning:s}),setPhase:s=>o({phase:s}),setBlindspots:s=>o({blindspots:s}),removeBlindspot:s=>o(t=>({blindspots:t.blindspots.filter(n=>n.id!==s)}))}));function ee({blindspot:o,onAnswer:s,onDismiss:t,onAccept:n}){const[c,d]=h.useState(""),p=o.kind==="opportunity";return e.jsxs("div",{className:"rounded-lg p-4 mb-3",style:{border:"1px solid var(--yc-color-border)",backgroundColor:"var(--yc-color-surface)"},children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-xs px-2 py-0.5 rounded-full",style:{border:"1px solid var(--yc-color-border)",color:"var(--yc-color-text-secondary)"},children:p?"opportunity":"context"}),e.jsx("h3",{className:"font-medium",style:{color:"var(--yc-color-text)"},children:o.title})]}),e.jsx("p",{className:"text-sm mt-1",style:{color:"var(--yc-color-text-secondary)"},children:o.detail}),p&&o.suggestedModel&&e.jsxs("div",{className:"text-xs mt-2 p-2 rounded",style:{backgroundColor:"var(--yc-color-input-bg)"},children:[e.jsx("div",{className:"font-mono",style:{color:"var(--yc-color-text)"},children:o.suggestedModel.name}),e.jsx("div",{style:{color:"var(--yc-color-text-secondary)"},children:o.suggestedModel.description}),o.suggestedModel.columns.length>0&&e.jsxs("div",{className:"mt-1",style:{color:"var(--yc-color-text-secondary)"},children:["cols: ",o.suggestedModel.columns.map(a=>a.name).join(", ")]})]}),!p&&e.jsx("textarea",{className:"w-full text-sm mt-2 p-2 rounded",style:{backgroundColor:"var(--yc-color-input-bg)",border:"1px solid var(--yc-color-border)",color:"var(--yc-color-text)"},rows:2,placeholder:"Explain this in business terms…",value:c,onChange:a=>d(a.target.value)}),e.jsxs("div",{className:"flex gap-2 mt-3",children:[p?e.jsx("button",{onClick:()=>n(o.id),className:"px-3 py-1 rounded text-white text-sm hover:opacity-90",style:{backgroundColor:"var(--yc-color-primary)"},children:"Accept"}):e.jsx("button",{onClick:()=>s(o.id,c),className:"px-3 py-1 rounded text-white text-sm hover:opacity-90",style:{backgroundColor:"var(--yc-color-primary)"},children:"Save"}),e.jsx("button",{onClick:()=>t(o.id),className:"px-3 py-1 rounded text-sm hover:opacity-80",style:{border:"1px solid var(--yc-color-border)",color:"var(--yc-color-text-secondary)"},children:"Dismiss"})]})]})}function oe({connection:o}={}){var j,B,w;const{data:s}=W(),t=((j=s==null?void 0:s.defaults)==null?void 0:j.connection)??((w=(B=s==null?void 0:s.connections)==null?void 0:B[0])==null?void 0:w.name)??"",n=o??t,c=v(r=>r.blindspots),d=v(r=>r.setBlindspots),p=v(r=>r.removeBlindspot),a=v(r=>r.scanning),l=v(r=>r.phase),y=v(r=>r.setScanning),u=v(r=>r.setPhase),{data:f,isLoading:P,error:H}=S({queryKey:["blindspots",n,"open"],queryFn:()=>R("open",n||void 0),enabled:!!n});h.useEffect(()=>{f&&d(f)},[f,d]);const b=async(r,g)=>{if(g.trim()){p(r);try{await Y(r,g)}catch{d(await R("open",n||void 0))}}},T=async r=>{p(r);try{await D(r)}catch{d(await R("open",n||void 0))}},q=async r=>{p(r);try{await D(r),alert("Sent to the dbt advisor — coming soon")}catch{d(await R("open",n||void 0))}},C=async()=>{if(n){y(!0),u("scanning");try{await X(n,r=>{if(r.event==="status")u(r.data.phase);else if(r.event==="done"){const g=r.data.blindspots??[];d(g)}else r.event==="error"&&u("error")})}catch{u("error")}finally{y(!1)}}},k=r=>r==="scanning"?"Scanning the source…":r==="error"?"Something went wrong.":"Scanning…";return e.jsxs("div",{className:"p-6 max-w-3xl mx-auto w-full",children:[e.jsx("h2",{className:"text-lg font-semibold mb-1",style:{color:"var(--yc-color-text)"},children:"Blindspots"}),e.jsx("p",{className:"text-sm mb-4",style:{color:"var(--yc-color-text-secondary)"},children:"Where the system lacks business context, plus useful marts it thinks are missing."}),e.jsxs("div",{className:"rounded-lg p-5 mb-4 flex items-center justify-between gap-4",style:{border:"1px solid var(--yc-color-border)",backgroundColor:"var(--yc-color-surface)"},children:[e.jsxs("div",{children:[e.jsx("h3",{className:"font-medium",style:{color:"var(--yc-color-text)"},children:"Scan for blindspots"}),e.jsx("p",{className:"text-sm mt-1",style:{color:"var(--yc-color-text-secondary)"},children:n?e.jsxs(e.Fragment,{children:["Audit ",e.jsx("span",{className:"font-mono",children:n})," for ambiguities and missing marts."]}):"No connection configured."}),a&&e.jsx("p",{className:"text-sm mt-2",style:{color:"var(--yc-color-primary)"},children:k(l)})]}),e.jsx("button",{onClick:C,disabled:a||!n,className:"px-4 py-2 rounded text-white text-sm whitespace-nowrap hover:opacity-90 disabled:opacity-50",style:{backgroundColor:"var(--yc-color-primary)"},children:a?"Scanning…":"Scan for blindspots"})]}),H&&e.jsx("p",{className:"text-sm",style:{color:"var(--yc-color-danger)"},children:"Failed to load blindspots."}),P?e.jsx("p",{className:"text-sm",style:{color:"var(--yc-color-text-secondary)"},children:"Loading…"}):c.length===0?e.jsx("p",{className:"text-sm",style:{color:"var(--yc-color-text-secondary)"},children:"No open blindspots. Scan this source to find some."}):c.map(r=>e.jsx(ee,{blindspot:r,onAnswer:b,onDismiss:T,onAccept:q},r.id))]})}const se=[{id:"sources",label:"Data Sources"},{id:"hunches",label:"Hunches"},{id:"blindspots",label:"Blindspots"}];function E({value:o,onChange:s}){const{data:t}=S({queryKey:["sources"],queryFn:I});return e.jsxs("div",{style:{padding:"12px 24px 0",display:"flex",alignItems:"center",gap:"8px"},children:[e.jsx("label",{htmlFor:"source-selector",style:{fontSize:"13px",color:"var(--yc-color-text-secondary)",whiteSpace:"nowrap"},children:"Source:"}),e.jsxs("select",{id:"source-selector",value:o,onChange:n=>s(n.target.value),style:{fontSize:"13px",padding:"4px 8px",borderRadius:"6px",border:"1px solid var(--yc-color-border)",backgroundColor:"var(--yc-color-surface)",color:"var(--yc-color-text)",cursor:"pointer"},children:[e.jsx("option",{value:"",children:"All sources"}),t==null?void 0:t.map(n=>e.jsx("option",{value:n.name,children:n.name},n.name))]})]})}function ce({tab:o,onTabChange:s}){const[t,n]=h.useState(""),[c,d]=h.useState(""),p=(a,l)=>e.jsx("button",{onClick:()=>s(a),style:{color:o===a?"var(--yc-color-primary)":"var(--yc-color-text-secondary)",borderBottom:o===a?"2px solid var(--yc-color-primary)":"2px solid transparent",paddingBottom:"6px",marginRight:"16px",background:"none",border:"none",cursor:"pointer",fontSize:"14px",fontWeight:o===a?600:400},children:l},a);return e.jsxs("div",{className:"flex flex-col h-full w-full",children:[e.jsx("div",{style:{display:"flex",borderBottom:"1px solid var(--yc-color-border)",padding:"16px 24px 0"},children:se.map(a=>p(a.id,a.label))}),e.jsxs("div",{className:"flex-1 overflow-y-auto",children:[o==="sources"&&e.jsx(K,{}),o==="hunches"&&e.jsxs(e.Fragment,{children:[e.jsx(E,{value:t,onChange:n}),e.jsx(_,{connection:t||void 0})]}),o==="blindspots"&&e.jsxs(e.Fragment,{children:[e.jsx(E,{value:c,onChange:d}),e.jsx(oe,{connection:c||void 0})]})]})]})}export{ce as DataView};
@@ -1 +0,0 @@
1
- import{j as e,i as k,J as E,K as B,v as M,N as W,O as $,a as D}from"./index-jlfTO7f5.js";import{a}from"./echarts-DtOYsfLX.js";const T=["What data do I have?","Show me recent trends","What are the top items by revenue?","Compare this month to last month"];function P({summary:t,onPromptClick:i}){return e.jsxs("div",{className:"flex flex-col items-center justify-center h-full px-6 py-12 gap-8",children:[e.jsxs("div",{className:"text-center",children:[e.jsx("h1",{className:"text-2xl font-bold mb-2",style:{color:"var(--yc-color-text)"},children:"Data Explorer"}),e.jsx("p",{className:"text-sm",style:{color:"var(--yc-color-text-secondary)"},children:"Ask questions about your data in plain English"})]}),t&&(t.tableCount>0||t.modelCount>0)&&e.jsxs("div",{className:"rounded-xl px-5 py-4 w-full max-w-md flex flex-col gap-3",style:{background:"var(--yc-color-surface)",border:"1px solid var(--yc-color-border)"},children:[e.jsx("p",{className:"text-xs font-semibold uppercase tracking-wide",style:{color:"var(--yc-color-text-secondary)"},children:"Connected data"}),e.jsxs("div",{className:"flex gap-6",children:[t.tableCount>0&&e.jsxs("div",{children:[e.jsx("span",{className:"text-xl font-bold",style:{color:"var(--yc-color-text)"},children:t.tableCount}),e.jsx("span",{className:"text-xs ml-1",style:{color:"var(--yc-color-text-secondary)"},children:t.tableCount===1?"table":"tables"})]}),t.modelCount>0&&e.jsxs("div",{children:[e.jsx("span",{className:"text-xl font-bold",style:{color:"var(--yc-color-text)"},children:t.modelCount}),e.jsx("span",{className:"text-xs ml-1",style:{color:"var(--yc-color-text-secondary)"},children:t.modelCount===1?"model":"models"})]})]}),t.connections.length>0&&e.jsx("div",{className:"flex flex-wrap gap-1.5",children:t.connections.map(l=>e.jsx("span",{className:"text-xs px-2 py-0.5 rounded-full",style:{background:"var(--yc-color-bg)",color:"var(--yc-color-text-secondary)",border:"1px solid var(--yc-color-border)"},children:l.name},l.name))})]}),e.jsx("div",{className:"flex flex-wrap gap-2 justify-center max-w-lg",children:T.map(l=>e.jsx("button",{onClick:()=>i(l),className:"text-sm px-3 py-1.5 rounded-full transition-opacity hover:opacity-80",style:{background:"var(--yc-color-surface)",color:"var(--yc-color-text)",border:"1px solid var(--yc-color-border)"},children:l},l))})]})}function R({summary:t,onTableClick:i}){const[l,x]=a.useState(new Set),[n,h]=a.useState(new Set),v=s=>{x(o=>{const c=new Set(o);return c.has(s)?c.delete(s):c.add(s),c})},f=s=>{h(o=>{const c=new Set(o);return c.has(s)?c.delete(s):c.add(s),c})},y=((t==null?void 0:t.connections)??[]).map(s=>({connection:s.name,tables:((t==null?void 0:t.tables)??[]).filter(o=>o.connection===s.name)})),u=(t==null?void 0:t.models)??[];return e.jsxs("div",{className:"w-64 flex-shrink-0 flex flex-col h-full overflow-y-auto",style:{borderRight:"1px solid var(--yc-color-border)",background:"var(--yc-color-surface)"},children:[e.jsx("div",{className:"px-3 py-2 flex items-center",style:{borderBottom:"1px solid var(--yc-color-border)"},children:e.jsx("span",{className:"text-xs font-semibold uppercase tracking-wide",style:{color:"var(--yc-color-text-secondary)"},children:"Catalog"})}),e.jsxs("div",{className:"flex-1 overflow-y-auto py-2",children:[y.map(s=>e.jsxs("div",{children:[e.jsxs("button",{className:"w-full flex items-center gap-1.5 px-3 py-1.5 hover:opacity-80 text-left",onClick:()=>v(s.connection),children:[e.jsx(g,{expanded:l.has(s.connection)}),e.jsx(I,{}),e.jsx("span",{className:"text-xs font-medium truncate",style:{color:"var(--yc-color-text)"},children:s.connection}),e.jsx("span",{className:"ml-auto text-xs",style:{color:"var(--yc-color-text-secondary)"},children:s.tables.length})]}),l.has(s.connection)&&e.jsx("div",{children:s.tables.map(o=>{const c=`${s.connection}:${o.name}`,m=n.has(c);return e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center gap-1 pl-6 pr-2 py-1 group",children:[e.jsxs("button",{className:"flex items-center gap-1 flex-1 min-w-0 hover:opacity-80 text-left",onClick:()=>f(c),children:[e.jsx(g,{expanded:m}),e.jsx(A,{}),e.jsx("span",{className:"text-xs truncate",style:{color:"var(--yc-color-text)"},children:o.schema?`${o.schema}.${o.name}`:o.name})]}),e.jsx("button",{className:"opacity-0 group-hover:opacity-100 text-xs px-1.5 py-0.5 rounded transition-opacity flex-shrink-0",style:{background:"var(--yc-color-primary)",color:"#fff"},onClick:()=>i(o.schema?`${o.schema}.${o.name}`:o.name),title:`Ask about ${o.name}`,children:"Ask"})]}),m&&o.columns.length>0&&e.jsx("div",{className:"pl-12 pb-1",children:o.columns.map(d=>e.jsxs("div",{className:"flex items-center gap-1.5 py-0.5 pr-2",children:[e.jsx("span",{className:"text-xs truncate",style:{color:"var(--yc-color-text)"},children:d.name}),d.type&&e.jsx("span",{className:"text-xs ml-auto flex-shrink-0",style:{color:"var(--yc-color-text-secondary)"},children:d.type})]},d.name))})]},c)})})]},s.connection)),u.length>0&&e.jsxs("div",{className:"mt-2",children:[e.jsx("div",{className:"px-3 py-1.5",style:{borderTop:"1px solid var(--yc-color-border)"},children:e.jsx("span",{className:"text-xs font-semibold uppercase tracking-wide",style:{color:"var(--yc-color-text-secondary)"},children:"Models"})}),u.map(s=>e.jsxs("div",{className:"flex items-center gap-1.5 pl-3 pr-2 py-1.5 group",children:[e.jsx(O,{}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"text-xs truncate",style:{color:"var(--yc-color-text)"},children:s.name}),s.description&&e.jsx("p",{className:"text-xs truncate",style:{color:"var(--yc-color-text-secondary)"},children:s.description})]}),e.jsx("button",{className:"opacity-0 group-hover:opacity-100 text-xs px-1.5 py-0.5 rounded transition-opacity flex-shrink-0",style:{background:"var(--yc-color-primary)",color:"#fff"},onClick:()=>i(s.name),title:`Ask about ${s.name}`,children:"Ask"})]},s.name))]}),!t||y.length===0&&u.length===0?e.jsx("div",{className:"px-3 py-4 text-center",children:e.jsxs("p",{className:"text-xs",style:{color:"var(--yc-color-text-secondary)"},children:["No catalog data available. Run ",e.jsx("code",{className:"font-mono",children:"yamchart sync-warehouse"})," to populate."]})}):null]})]})}function g({expanded:t}){return e.jsx("svg",{width:"10",height:"10",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2.5",strokeLinecap:"round",strokeLinejoin:"round",style:{color:"var(--yc-color-text-secondary)",transform:t?"rotate(90deg)":"rotate(0deg)",transition:"transform 0.15s",flexShrink:0},children:e.jsx("polyline",{points:"9 18 15 12 9 6"})})}function I(){return e.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",style:{color:"var(--yc-color-text-secondary)",flexShrink:0},children:[e.jsx("ellipse",{cx:"12",cy:"5",rx:"9",ry:"3"}),e.jsx("path",{d:"M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"}),e.jsx("path",{d:"M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"})]})}function A(){return e.jsxs("svg",{width:"11",height:"11",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",style:{color:"var(--yc-color-text-secondary)",flexShrink:0},children:[e.jsx("rect",{x:"3",y:"3",width:"18",height:"18",rx:"2"}),e.jsx("path",{d:"M3 9h18M3 15h18M9 3v18"})]})}function O(){return e.jsxs("svg",{width:"11",height:"11",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",style:{color:"var(--yc-color-text-secondary)",flexShrink:0},children:[e.jsx("polyline",{points:"16 18 22 12 16 6"}),e.jsx("polyline",{points:"8 6 2 12 8 18"})]})}function q(){const t=k(n=>n.savedCharts),[i,l]=a.useState(!1),x=a.useRef(null);return a.useEffect(()=>{if(!i)return;function n(h){x.current&&!x.current.contains(h.target)&&l(!1)}return document.addEventListener("mousedown",n),()=>document.removeEventListener("mousedown",n)},[i]),t.length===0?null:e.jsxs("div",{className:"relative",ref:x,children:[e.jsxs("button",{onClick:()=>l(n=>!n),className:"flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-sm font-medium transition-opacity hover:opacity-80",style:{background:"var(--yc-color-surface)",border:"1px solid var(--yc-color-border)",color:"var(--yc-color-text)"},children:[e.jsxs("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[e.jsx("rect",{x:"3",y:"3",width:"7",height:"7"}),e.jsx("rect",{x:"14",y:"3",width:"7",height:"7"}),e.jsx("rect",{x:"14",y:"14",width:"7",height:"7"}),e.jsx("rect",{x:"3",y:"14",width:"7",height:"7"})]}),e.jsxs("span",{children:[t.length," saved ",t.length===1?"chart":"charts"]}),e.jsx("span",{className:"inline-flex items-center justify-center w-5 h-5 rounded-full text-xs font-bold text-white",style:{background:"var(--yc-color-primary)"},children:t.length})]}),i&&e.jsxs("div",{className:"absolute right-0 top-full mt-1 w-56 rounded-lg shadow-lg z-50 py-1",style:{background:"var(--yc-color-bg)",border:"1px solid var(--yc-color-border)"},children:[e.jsx("p",{className:"px-3 py-1.5 text-xs font-semibold uppercase tracking-wide",style:{color:"var(--yc-color-text-secondary)"},children:"Saved charts"}),t.map(n=>e.jsxs("div",{className:"flex items-center gap-2 px-3 py-2",children:[e.jsx("svg",{width:"12",height:"12",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",style:{color:"var(--yc-color-primary)",flexShrink:0},children:e.jsx("polyline",{points:"20 6 9 17 4 12"})}),e.jsx("span",{className:"text-sm truncate",style:{color:"var(--yc-color-text)"},children:n})]},n))]})]})}function V(){const t=E(),{messages:i,isStreaming:l,savedCharts:x,openPanel:n,setPanelMode:h,snapshotExploreHistory:v,clearConversation:f}=k(),[y,u]=a.useState(!0),[s,o]=a.useState(void 0),c=a.useRef(null);a.useEffect(()=>(h("explore"),n({type:"explore"}),()=>{h("panel")}),[h,n]),a.useEffect(()=>{var r;(r=c.current)==null||r.scrollIntoView({behavior:"smooth"})},[i]);const m=a.useCallback((r,p,S)=>{v(p),h("panel");const L=r==="chart"?"charts":"dashboards";window.location.hash=`/${L}/${encodeURIComponent(p)}${S?"?edit=true":""}`,n({type:r==="chart"?"chart":"dashboard",name:p})},[v,h,n]),{sendMessage:d}=B(m),{data:j}=M({queryKey:["catalog-summary"],queryFn:()=>D.getCatalogSummary(),staleTime:6e4,retry:!1}),b=a.useCallback(r=>{o(`Tell me about the ${r} table`)},[]),w=a.useCallback(r=>{d(r)},[d]),N=a.useCallback(r=>{d(r),o(void 0)},[d]),C=a.useCallback(()=>{const r=x.join(", ");d(`Build a dashboard using these charts: ${r}. Arrange them in a logical layout.`)},[x,d]);return t==="sm"?e.jsx("div",{className:"flex items-center justify-center h-screen px-6",style:{background:"var(--yc-color-bg)"},children:e.jsxs("div",{className:"text-center max-w-xs",children:[e.jsx("p",{className:"text-lg font-semibold mb-2",style:{color:"var(--yc-color-text)"},children:"Desktop required"}),e.jsx("p",{className:"text-sm",style:{color:"var(--yc-color-text-secondary)"},children:"Data Explorer is designed for larger screens. Please open it on a desktop or laptop."})]})}):e.jsxs("div",{className:"flex h-screen overflow-hidden",style:{background:"var(--yc-color-bg)"},children:[y&&e.jsx(R,{summary:j??null,onTableClick:b}),e.jsxs("div",{className:"flex-1 flex flex-col h-full min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2 px-4 py-2 flex-shrink-0",style:{borderBottom:"1px solid var(--yc-color-border)"},children:[e.jsxs("a",{href:"#/",className:"flex items-center gap-1.5 text-sm hover:opacity-80",style:{color:"var(--yc-color-text-secondary)"},onClick:r=>{r.preventDefault(),window.location.hash="/"},children:[e.jsx("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:e.jsx("polyline",{points:"15 18 9 12 15 6"})}),"Dashboards"]}),e.jsx("div",{className:"w-px h-4 mx-1",style:{background:"var(--yc-color-border)"}}),e.jsx("button",{className:"p-1.5 rounded hover:opacity-80",style:{color:"var(--yc-color-text-secondary)"},onClick:()=>u(r=>!r),title:y?"Hide catalog":"Show catalog",children:e.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[e.jsx("rect",{x:"3",y:"3",width:"18",height:"18",rx:"2"}),e.jsx("path",{d:"M9 3v18"})]})}),e.jsx("span",{className:"text-sm font-semibold",style:{color:"var(--yc-color-text)"},children:"Data Explorer"}),e.jsxs("div",{className:"ml-auto flex items-center gap-2",children:[e.jsx(q,{}),e.jsxs("button",{disabled:x.length===0||l,onClick:C,className:"flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-sm font-medium transition-opacity disabled:opacity-40",style:{background:"var(--yc-color-primary)",color:"#fff"},children:[e.jsxs("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[e.jsx("rect",{x:"3",y:"3",width:"7",height:"7"}),e.jsx("rect",{x:"14",y:"3",width:"7",height:"7"}),e.jsx("rect",{x:"14",y:"14",width:"7",height:"7"}),e.jsx("rect",{x:"3",y:"14",width:"7",height:"7"})]}),"Build Dashboard"]}),i.length>0&&e.jsx("button",{className:"p-1.5 rounded hover:opacity-80",style:{color:"var(--yc-color-text-secondary)"},onClick:f,title:"New conversation",children:e.jsxs("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[e.jsx("path",{d:"M12 20h9"}),e.jsx("path",{d:"M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"})]})})]})]}),e.jsx("div",{className:"flex-1 overflow-y-auto px-6 py-4 flex flex-col gap-3 min-h-0",children:i.length===0?e.jsx(P,{summary:j??null,onPromptClick:w}):e.jsxs(e.Fragment,{children:[i.map((r,p)=>e.jsx(W,{message:r,isStreaming:l&&p===i.length-1&&r.role==="assistant",onSendMessage:d},p)),e.jsx("div",{ref:c})]})}),e.jsx("div",{className:"px-6 py-3 flex-shrink-0",style:{borderTop:"1px solid var(--yc-color-border)"},children:e.jsx($,{onSend:N,placeholder:"Ask about your data...",disabled:l,initialValue:s})})]})]})}export{V as default};
@@ -1 +0,0 @@
1
- import{j as e,a as p,A as j}from"./index-jlfTO7f5.js";import{a as s}from"./echarts-DtOYsfLX.js";function P(){var A;const[i,N]=s.useState([]),[b,C]=s.useState(!0),[v,h]=s.useState(!1),[x,w]=s.useState(""),[l,g]=s.useState(null),[u,c]=s.useState([]),[m,y]=s.useState(!1),d=async()=>{try{const{users:t}=await p.authListUsers();N(t)}catch{w("Failed to load users")}finally{C(!1)}};s.useEffect(()=>{d()},[]);const a=async(t,r)=>{try{await p.authUpdateUser(t,{role:r}),await d()}catch(o){alert(o instanceof j?o.message:"Failed to update role")}},f=async(t,r)=>{if(confirm(`Delete user "${r}"? This cannot be undone.`))try{await p.authDeleteUser(t),await d()}catch(o){alert(o instanceof j?o.message:"Failed to delete user")}},U=t=>{if(l===t.id)g(null),c([]);else{g(t.id);const r=JSON.parse(t.attributes||"{}");c(Object.entries(r).map(([o,n])=>({key:o,value:n})))}},k=(t,r,o)=>{c(n=>n.map((S,M)=>M===t?{...S,[r]:o}:S))},E=()=>{c(t=>[...t,{key:"",value:""}])},L=t=>{c(r=>r.filter((o,n)=>n!==t))},D=async()=>{if(l){y(!0);try{const t={};for(const{key:r,value:o}of u){const n=r.trim();n&&(t[n]=o)}await p.authUpdateUser(l,{attributes:t}),await d(),c(Object.entries(t).map(([r,o])=>({key:r,value:o})))}catch(t){alert(t instanceof j?t.message:"Failed to save attributes")}finally{y(!1)}}};return b?e.jsx("div",{className:"p-6",style:{color:"var(--yc-color-text-secondary)"},children:"Loading users..."}):e.jsxs("div",{className:"p-6 max-w-4xl mx-auto",children:[e.jsxs("div",{className:"flex items-center justify-between mb-6",children:[e.jsx("h1",{className:"text-xl font-semibold",style:{color:"var(--yc-color-text)"},children:"User Management"}),e.jsx("button",{onClick:()=>h(!0),className:"px-4 py-2 bg-blue-600 text-white text-sm font-medium rounded-md hover:bg-blue-700",children:"Add User"})]}),x&&e.jsx("div",{className:"text-sm rounded-md px-4 py-3 mb-4",style:{backgroundColor:"color-mix(in srgb, var(--yc-color-danger) 10%, transparent)",border:"1px solid color-mix(in srgb, var(--yc-color-danger) 30%, transparent)",color:"var(--yc-color-danger)"},children:x}),e.jsx("div",{className:"rounded-lg overflow-hidden",style:{backgroundColor:"var(--yc-color-surface)",border:"1px solid var(--yc-color-border)"},children:e.jsxs("table",{className:"w-full yc-table",children:[e.jsx("thead",{className:"border-b",style:{backgroundColor:"var(--yc-color-input-bg)",borderColor:"var(--yc-color-border)",color:"var(--yc-color-text-secondary)"},children:e.jsxs("tr",{children:[e.jsx("th",{className:"px-3 py-3 text-right text-xs font-medium w-10",style:{color:"var(--yc-color-text-muted)"},children:"#"}),e.jsx("th",{className:"px-4 py-3 text-left text-xs font-medium uppercase",children:"Name"}),e.jsx("th",{className:"px-4 py-3 text-left text-xs font-medium uppercase",children:"Email"}),e.jsx("th",{className:"px-4 py-3 text-left text-xs font-medium uppercase",children:"Role"}),e.jsx("th",{className:"px-4 py-3 text-left text-xs font-medium uppercase",children:"Created"}),e.jsx("th",{className:"px-4 py-3 text-right text-xs font-medium uppercase",children:"Actions"})]})}),e.jsx("tbody",{className:"divide-y",style:{borderColor:"var(--yc-color-border)"},children:i.map((t,r)=>e.jsxs("tr",{className:"group",children:[e.jsx("td",{className:"px-3 py-3 text-right text-sm yc-row-num w-10",children:r+1}),e.jsx("td",{className:"px-4 py-3 text-sm",style:{color:"var(--yc-color-text)"},children:t.name}),e.jsx("td",{className:"px-4 py-3 text-sm",style:{color:"var(--yc-color-text-secondary)"},children:t.email}),e.jsx("td",{className:"px-4 py-3",children:e.jsxs("select",{value:t.role,onChange:o=>a(t.id,o.target.value),className:"text-sm border rounded px-2 py-1",style:{backgroundColor:"var(--yc-color-input-bg)",color:"var(--yc-color-text)",borderColor:"var(--yc-color-border)"},children:[e.jsx("option",{value:"admin",children:"Admin"}),e.jsx("option",{value:"editor",children:"Editor"}),e.jsx("option",{value:"viewer",children:"Viewer"})]})}),e.jsx("td",{className:"px-4 py-3 text-sm",style:{color:"var(--yc-color-text-secondary)"},children:new Date(t.created_at).toLocaleDateString()}),e.jsxs("td",{className:"px-4 py-3 text-right space-x-3",children:[e.jsx("button",{onClick:()=>U(t),className:"text-sm hover:opacity-80",style:{color:"var(--yc-color-primary)"},children:l===t.id?"Hide Attrs":"Attrs"}),e.jsx("button",{onClick:()=>f(t.id,t.name),className:"text-sm hover:opacity-80",style:{color:"var(--yc-color-danger)"},children:"Delete"})]})]},t.id))})]})}),l&&e.jsxs("div",{className:"mt-4 rounded-lg p-4",style:{backgroundColor:"var(--yc-color-surface)",border:"1px solid var(--yc-color-border)"},children:[e.jsxs("div",{className:"flex items-center justify-between mb-3",children:[e.jsxs("h3",{className:"text-sm font-medium",style:{color:"var(--yc-color-text-secondary)"},children:["Attributes for ",(A=i.find(t=>t.id===l))==null?void 0:A.name]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx("button",{onClick:E,className:"px-3 py-1 text-xs font-medium rounded hover:opacity-80",style:{color:"var(--yc-color-primary)",border:"1px solid color-mix(in srgb, var(--yc-color-primary) 50%, transparent)"},children:"Add Attribute"}),e.jsx("button",{onClick:D,disabled:m,className:"px-3 py-1 text-xs font-medium text-white bg-blue-600 rounded hover:bg-blue-700 disabled:opacity-50",children:m?"Saving...":"Save"})]})]}),u.length===0?e.jsx("p",{className:"text-sm",style:{color:"var(--yc-color-text-muted)"},children:'No attributes. Click "Add Attribute" to define key-value pairs for row-level security.'}):e.jsx("div",{className:"space-y-2",children:u.map((t,r)=>e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"text",placeholder:"Key (e.g. department)",value:t.key,onChange:o=>k(r,"key",o.target.value),className:"flex-1 px-3 py-1.5 text-sm border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500",style:{backgroundColor:"var(--yc-color-input-bg)",color:"var(--yc-color-text)",borderColor:"var(--yc-color-border)"}}),e.jsx("input",{type:"text",placeholder:"Value (e.g. Sales)",value:t.value,onChange:o=>k(r,"value",o.target.value),className:"flex-1 px-3 py-1.5 text-sm border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500",style:{backgroundColor:"var(--yc-color-input-bg)",color:"var(--yc-color-text)",borderColor:"var(--yc-color-border)"}}),e.jsx("button",{onClick:()=>L(r),className:"p-1.5 hover:opacity-80",style:{color:"var(--yc-color-text-muted)"},title:"Remove attribute",children:e.jsx("svg",{className:"w-4 h-4",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M6 18L18 6M6 6l12 12"})})})]},r))})]}),v&&e.jsx(R,{onClose:()=>h(!1),onCreated:d})]})}function R({onClose:i,onCreated:N}){const[b,C]=s.useState(""),[v,h]=s.useState(""),[x,w]=s.useState(""),[l,g]=s.useState("viewer"),[u,c]=s.useState(""),[m,y]=s.useState(!1),d=async a=>{a.preventDefault(),c(""),y(!0);try{await p.authCreateUser({email:b,name:v,password:x,role:l}),N(),i()}catch(f){c(f instanceof j?f.message:"Failed to create user")}finally{y(!1)}};return e.jsx("div",{className:"fixed inset-0 bg-black/50 flex items-center justify-center z-50",onClick:i,children:e.jsxs("div",{className:"rounded-lg shadow-lg p-6 w-full max-w-md",style:{backgroundColor:"var(--yc-color-surface)"},onClick:a=>a.stopPropagation(),children:[e.jsx("h2",{className:"text-lg font-semibold mb-4",style:{color:"var(--yc-color-text)"},children:"Add User"}),u&&e.jsx("div",{className:"text-sm rounded-md px-4 py-3 mb-4",style:{backgroundColor:"color-mix(in srgb, var(--yc-color-danger) 10%, transparent)",border:"1px solid color-mix(in srgb, var(--yc-color-danger) 30%, transparent)",color:"var(--yc-color-danger)"},children:u}),e.jsxs("form",{onSubmit:d,className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-sm font-medium mb-1",style:{color:"var(--yc-color-text-secondary)"},children:"Name"}),e.jsx("input",{type:"text",value:v,onChange:a=>h(a.target.value),required:!0,className:"w-full px-3 py-2 border rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500",style:{backgroundColor:"var(--yc-color-input-bg)",color:"var(--yc-color-text)",borderColor:"var(--yc-color-border)"}})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-sm font-medium mb-1",style:{color:"var(--yc-color-text-secondary)"},children:"Email"}),e.jsx("input",{type:"email",value:b,onChange:a=>C(a.target.value),required:!0,className:"w-full px-3 py-2 border rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500",style:{backgroundColor:"var(--yc-color-input-bg)",color:"var(--yc-color-text)",borderColor:"var(--yc-color-border)"}})]}),e.jsxs("div",{children:[e.jsxs("label",{className:"block text-sm font-medium mb-1",style:{color:"var(--yc-color-text-secondary)"},children:["Temporary Password ",e.jsx("span",{style:{color:"var(--yc-color-text-secondary)"},children:"(optional)"})]}),e.jsx("input",{type:"password",value:x,onChange:a=>w(a.target.value),minLength:8,placeholder:"Leave blank to invite via SSO",className:"w-full px-3 py-2 border rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500",style:{backgroundColor:"var(--yc-color-input-bg)",color:"var(--yc-color-text)",borderColor:"var(--yc-color-border)"}}),e.jsx("p",{className:"mt-1 text-xs",style:{color:"var(--yc-color-text-secondary)"},children:"Leave blank to invite an SSO user — they sign in with their provider, no password."})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-sm font-medium mb-1",style:{color:"var(--yc-color-text-secondary)"},children:"Role"}),e.jsxs("select",{value:l,onChange:a=>g(a.target.value),className:"w-full px-3 py-2 border rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500",style:{backgroundColor:"var(--yc-color-input-bg)",color:"var(--yc-color-text)",borderColor:"var(--yc-color-border)"},children:[e.jsx("option",{value:"viewer",children:"Viewer"}),e.jsx("option",{value:"editor",children:"Editor"}),e.jsx("option",{value:"admin",children:"Admin"})]})]}),e.jsxs("div",{className:"flex justify-end gap-3",children:[e.jsx("button",{type:"button",onClick:i,className:"px-4 py-2 text-sm hover:bg-black/5 rounded-md",style:{color:"var(--yc-color-text-secondary)"},children:"Cancel"}),e.jsx("button",{type:"submit",disabled:m,className:"px-4 py-2 text-sm bg-blue-600 text-white rounded-md hover:bg-blue-700 disabled:opacity-50",children:m?"Creating...":"Create User"})]})]})]})})}export{P as UserManagement};
@@ -1,42 +0,0 @@
1
- import { createRequire as __yamchartCreateRequire } from 'module'; if (!globalThis.require) globalThis.require = __yamchartCreateRequire(import.meta.url);
2
- import {
3
- resolveTableName
4
- } from "./chunk-VJC24RKT.js";
5
- import {
6
- createConnector,
7
- resolveConnection
8
- } from "./chunk-5FHV22X2.js";
9
- import "./chunk-QUIDZO5G.js";
10
- import "./chunk-UFDQ3C7Q.js";
11
- import "./chunk-ZIY22VO7.js";
12
- import "./chunk-7D4SUZUM.js";
13
-
14
- // src/commands/sample.ts
15
- import { performance } from "perf_hooks";
16
- async function sampleTable(projectDir, table, options) {
17
- const resolved = await resolveTableName(projectDir, table);
18
- const connection = await resolveConnection(projectDir, options.connection);
19
- const connector = createConnector(connection, projectDir);
20
- try {
21
- await connector.connect();
22
- const limit = options.limit ?? 5;
23
- const sql = `SELECT * FROM ${resolved.tableName} LIMIT ${limit}`;
24
- const startTime = performance.now();
25
- const result = await connector.execute(sql);
26
- const durationMs = performance.now() - startTime;
27
- return {
28
- ...result,
29
- durationMs,
30
- table: resolved.tableName,
31
- connectionName: connection.name,
32
- connectionType: connection.type,
33
- ...resolved.source === "catalog" ? { resolvedFrom: table } : {}
34
- };
35
- } finally {
36
- await connector.disconnect();
37
- }
38
- }
39
- export {
40
- sampleTable
41
- };
42
- //# sourceMappingURL=sample-ODUGGSFA.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/sample.ts"],"sourcesContent":["import { performance } from 'node:perf_hooks';\nimport type { QueryResult } from '@yamchart/query';\nimport { resolveConnection, createConnector } from './connection-utils.js';\nimport { resolveTableName } from './model-resolver.js';\n\nexport interface SampleOptions {\n connection?: string;\n json?: boolean;\n limit?: number;\n}\n\nexport interface SampleResult extends QueryResult {\n table: string;\n connectionName: string;\n connectionType: string;\n resolvedFrom?: string;\n}\n\n/**\n * Sample rows from a table or dbt model.\n *\n * Resolves dbt model names via catalog, then runs SELECT * with a LIMIT.\n */\nexport async function sampleTable(\n projectDir: string,\n table: string,\n options: SampleOptions,\n): Promise<SampleResult> {\n const resolved = await resolveTableName(projectDir, table);\n const connection = await resolveConnection(projectDir, options.connection);\n const connector = createConnector(connection, projectDir);\n\n try {\n await connector.connect();\n\n const limit = options.limit ?? 5;\n const sql = `SELECT * FROM ${resolved.tableName} LIMIT ${limit}`;\n const startTime = performance.now();\n const result = await connector.execute(sql);\n const durationMs = performance.now() - startTime;\n\n return {\n ...result,\n durationMs,\n table: resolved.tableName,\n connectionName: connection.name,\n connectionType: connection.type,\n ...(resolved.source === 'catalog' ? { resolvedFrom: table } : {}),\n };\n } finally {\n await connector.disconnect();\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAAA,SAAS,mBAAmB;AAuB5B,eAAsB,YACpB,YACA,OACA,SACuB;AACvB,QAAM,WAAW,MAAM,iBAAiB,YAAY,KAAK;AACzD,QAAM,aAAa,MAAM,kBAAkB,YAAY,QAAQ,UAAU;AACzE,QAAM,YAAY,gBAAgB,YAAY,UAAU;AAExD,MAAI;AACF,UAAM,UAAU,QAAQ;AAExB,UAAM,QAAQ,QAAQ,SAAS;AAC/B,UAAM,MAAM,iBAAiB,SAAS,SAAS,UAAU,KAAK;AAC9D,UAAM,YAAY,YAAY,IAAI;AAClC,UAAM,SAAS,MAAM,UAAU,QAAQ,GAAG;AAC1C,UAAM,aAAa,YAAY,IAAI,IAAI;AAEvC,WAAO;AAAA,MACL,GAAG;AAAA,MACH;AAAA,MACA,OAAO,SAAS;AAAA,MAChB,gBAAgB,WAAW;AAAA,MAC3B,gBAAgB,WAAW;AAAA,MAC3B,GAAI,SAAS,WAAW,YAAY,EAAE,cAAc,MAAM,IAAI,CAAC;AAAA,IACjE;AAAA,EACF,UAAE;AACA,UAAM,UAAU,WAAW;AAAA,EAC7B;AACF;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/semantic.ts"],"sourcesContent":["import { SemanticModelBuilder, SemanticQueryCompiler } from '@yamchart/query/semantic';\nimport type { SemanticFilter } from '@yamchart/schema';\n\ninterface CatalogJsonData {\n models: Array<{\n name: string;\n table?: string;\n description?: string;\n source?: string;\n path?: string;\n columns?: Array<{ name: string; data_type?: string; description?: string; hints?: string[] }>;\n }>;\n}\n\nexport interface SemanticEntitySummary {\n name: string;\n source_table: string;\n description?: string;\n measures: Array<{ name: string; type: string }>;\n dimensions: Array<{ name: string; type: string }>;\n}\n\nexport interface ListResult {\n entities: SemanticEntitySummary[];\n}\n\nexport interface QueryInput {\n entity: string;\n measures: string[];\n dimensions: string[];\n filters: Array<{ dimension: string; operator: string; value: string | number | boolean | Array<string | number> }>;\n order_by?: { field: string; direction: string };\n limit: number;\n}\n\nexport interface QueryResult {\n sql: string;\n entityName: string;\n}\n\nexport function listSemanticEntities(catalog: CatalogJsonData): ListResult {\n const builder = new SemanticModelBuilder();\n const model = builder.build({ catalog: { models: catalog.models } });\n\n return {\n entities: model.entities.map((e) => ({\n name: e.name,\n source_table: e.source_table,\n description: e.description,\n measures: e.measures.map((m) => ({ name: m.name, type: m.type })),\n dimensions: e.dimensions.map((d) => ({ name: d.name, type: d.type })),\n })),\n };\n}\n\nexport function querySemanticEntity(catalog: CatalogJsonData, input: QueryInput): QueryResult {\n const builder = new SemanticModelBuilder();\n const model = builder.build({ catalog: { models: catalog.models } });\n\n const compiler = new SemanticQueryCompiler();\n const sql = compiler.compile(model, {\n model: input.entity,\n measures: input.measures,\n dimensions: input.dimensions,\n filters: input.filters as SemanticFilter[],\n order_by: input.order_by ? { field: input.order_by.field, direction: input.order_by.direction as 'asc' | 'desc' } : undefined,\n limit: input.limit,\n });\n\n return { sql, entityName: input.entity };\n}\n"],"mappings":";;;;;;;;AAwCO,SAAS,qBAAqB,SAAsC;AACzE,QAAM,UAAU,IAAI,qBAAqB;AACzC,QAAM,QAAQ,QAAQ,MAAM,EAAE,SAAS,EAAE,QAAQ,QAAQ,OAAO,EAAE,CAAC;AAEnE,SAAO;AAAA,IACL,UAAU,MAAM,SAAS,IAAI,CAAC,OAAO;AAAA,MACnC,MAAM,EAAE;AAAA,MACR,cAAc,EAAE;AAAA,MAChB,aAAa,EAAE;AAAA,MACf,UAAU,EAAE,SAAS,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,EAAE,KAAK,EAAE;AAAA,MAChE,YAAY,EAAE,WAAW,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,EAAE,KAAK,EAAE;AAAA,IACtE,EAAE;AAAA,EACJ;AACF;AAEO,SAAS,oBAAoB,SAA0B,OAAgC;AAC5F,QAAM,UAAU,IAAI,qBAAqB;AACzC,QAAM,QAAQ,QAAQ,MAAM,EAAE,SAAS,EAAE,QAAQ,QAAQ,OAAO,EAAE,CAAC;AAEnE,QAAM,WAAW,IAAI,sBAAsB;AAC3C,QAAM,MAAM,SAAS,QAAQ,OAAO;AAAA,IAClC,OAAO,MAAM;AAAA,IACb,UAAU,MAAM;AAAA,IAChB,YAAY,MAAM;AAAA,IAClB,SAAS,MAAM;AAAA,IACf,UAAU,MAAM,WAAW,EAAE,OAAO,MAAM,SAAS,OAAO,WAAW,MAAM,SAAS,UAA4B,IAAI;AAAA,IACpH,OAAO,MAAM;AAAA,EACf,CAAC;AAED,SAAO,EAAE,KAAK,YAAY,MAAM,OAAO;AACzC;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/warehouse-sync.ts","../src/commands/sync-warehouse.ts"],"sourcesContent":["/**\n * Core warehouse sync logic.\n *\n * Pure functions for diffing, grouping, building models, and merging catalogs,\n * plus an async orchestrator (syncWarehouse) that does I/O.\n */\n\nimport { readFile, writeFile, mkdir } from 'fs/promises';\nimport { join } from 'path';\nimport type { Connector } from '@yamchart/query';\nimport type { NormalizedColumnWithTable, NormalizedTable } from './introspection.js';\nimport { getTablesQuery, getColumnsQuery, getDescribeQuery } from './introspection.js';\nimport type { CatalogModel, CatalogData } from '../dbt/catalog.js';\nimport { generateCatalogMd, generateCatalogJson, generateWarehouseSection } from '../dbt/catalog.js';\n\n// ---------------------------------------------------------------------------\n// Interfaces\n// ---------------------------------------------------------------------------\n\nexport interface SyncState {\n syncedAt: string;\n connection: string;\n schemas: string[];\n skipSamples: boolean;\n tables: Record<string, { columnCount: number; lastAltered?: string }>;\n}\n\nexport interface WarehouseTable {\n qualifiedName: string; // \"SCHEMA.TABLE\"\n schema: string;\n name: string;\n type: string; // \"TABLE\" | \"VIEW\"\n columnCount: number;\n}\n\nexport interface SyncDiff {\n newTables: string[];\n changedTables: string[];\n unchangedTables: string[];\n removedTables: string[];\n}\n\nexport interface SyncWarehouseResult {\n tablesTotal: number;\n tablesNew: number;\n tablesChanged: number;\n tablesUnchanged: number;\n tablesRemoved: number;\n errors: string[];\n durationMs: number;\n}\n\nexport interface SyncWarehouseOptions {\n schemas?: string[];\n database?: string;\n skipSamples?: boolean;\n full?: boolean;\n onProgress?: (table: string, index: number, total: number) => void;\n}\n\n// ---------------------------------------------------------------------------\n// Pure functions\n// ---------------------------------------------------------------------------\n\n/**\n * Group a flat column list into a Map keyed by \"SCHEMA.TABLE\".\n */\nexport function groupColumnsByTable(\n columns: NormalizedColumnWithTable[],\n): Map<string, NormalizedColumnWithTable[]> {\n const map = new Map<string, NormalizedColumnWithTable[]>();\n for (const col of columns) {\n const key = `${col.schema}.${col.table}`;\n const existing = map.get(key);\n if (existing) {\n existing.push(col);\n } else {\n map.set(key, [col]);\n }\n }\n return map;\n}\n\n/**\n * Compare current warehouse tables against previous sync state.\n * All tables are \"new\" when prev is null.\n * Detects changed by column count mismatch.\n * Detects removed tables (in prev but not in current).\n */\nexport function diffSyncState(\n current: WarehouseTable[],\n prev: SyncState | null,\n): SyncDiff {\n const newTables: string[] = [];\n const changedTables: string[] = [];\n const unchangedTables: string[] = [];\n const removedTables: string[] = [];\n\n if (!prev) {\n return {\n newTables: current.map((t) => t.qualifiedName),\n changedTables: [],\n unchangedTables: [],\n removedTables: [],\n };\n }\n\n const currentNames = new Set(current.map((t) => t.qualifiedName));\n\n for (const table of current) {\n const prevEntry = prev.tables[table.qualifiedName];\n if (!prevEntry) {\n newTables.push(table.qualifiedName);\n } else if (prevEntry.columnCount !== table.columnCount) {\n changedTables.push(table.qualifiedName);\n } else {\n unchangedTables.push(table.qualifiedName);\n }\n }\n\n // Detect removed tables\n for (const name of Object.keys(prev.tables)) {\n if (!currentNames.has(name)) {\n removedTables.push(name);\n }\n }\n\n return { newTables, changedTables, unchangedTables, removedTables };\n}\n\n/**\n * Build CatalogModel entries from warehouse metadata.\n */\nexport function buildWarehouseModels(\n tables: WarehouseTable[],\n columnMap: Map<string, NormalizedColumnWithTable[]>,\n samples: Record<string, Record<string, unknown>[]>,\n): CatalogModel[] {\n const now = new Date().toISOString();\n\n return tables.map((table) => {\n const cols = columnMap.get(table.qualifiedName) || [];\n const sampleRows = samples[table.qualifiedName];\n\n return {\n name: table.name,\n path: '',\n description: '',\n table: table.qualifiedName,\n tags: ['warehouse'],\n meta: {},\n columns: cols.map((c) => ({\n name: c.name,\n data_type: c.type,\n description: '',\n hints: [],\n })),\n yamchartModels: [],\n source: 'warehouse' as const,\n tableType: table.type as 'TABLE' | 'VIEW',\n ...(sampleRows ? { sampleRows } : {}),\n lastSynced: now,\n };\n });\n}\n\n/**\n * Merge warehouse models into an existing dbt catalog.\n *\n * 1. If no existing catalog, create new with warehouseModels.\n * 2. Remove stale warehouse entries from existing.\n * 3. For tables in both dbt and warehouse (matched by `table` field, case-insensitive):\n * - dbt entry wins (keep it)\n * - Backfill data_type from warehouse columns where missing\n * - Add any warehouse columns that don't exist in the dbt entry\n * 4. Append remaining warehouse-only models.\n * 5. Return updated CatalogData.\n */\nexport function mergeWithDbtCatalog(\n existingCatalog: CatalogData | null,\n warehouseModels: CatalogModel[],\n): CatalogData {\n if (!existingCatalog) {\n return {\n syncedAt: new Date().toISOString(),\n source: { type: 'warehouse' },\n stats: { modelsIncluded: warehouseModels.length, modelsExcluded: 0 },\n models: warehouseModels,\n };\n }\n\n // Build a lookup of warehouse models by normalized table name\n const warehouseByTable = new Map<string, CatalogModel>();\n for (const wm of warehouseModels) {\n if (wm.table) {\n warehouseByTable.set(wm.table.toUpperCase(), wm);\n }\n }\n\n // Track which warehouse models were consumed by dbt merge\n const consumedWarehouseTables = new Set<string>();\n\n // Process existing catalog: keep non-warehouse entries, merge dbt+warehouse matches\n const mergedModels: CatalogModel[] = [];\n\n for (const model of existingCatalog.models) {\n // Remove stale warehouse entries — they'll be replaced by current warehouseModels\n if (model.source === 'warehouse') {\n continue;\n }\n\n // Check if this dbt model matches a warehouse table\n const tableKey = (model.table || '').toUpperCase();\n const warehouseMatch = tableKey ? warehouseByTable.get(tableKey) : undefined;\n\n if (warehouseMatch) {\n // dbt entry wins — backfill data_type and add missing columns\n const warehouseColMap = new Map<string, { data_type?: string; description: string; hints: string[] }>();\n for (const wc of warehouseMatch.columns) {\n warehouseColMap.set(wc.name.toLowerCase(), wc);\n }\n\n // Backfill data_type on existing dbt columns\n const updatedColumns = model.columns.map((col) => {\n const wc = warehouseColMap.get(col.name.toLowerCase());\n if (wc && !col.data_type && wc.data_type) {\n return { ...col, data_type: wc.data_type };\n }\n return col;\n });\n\n // Add warehouse columns not present in dbt entry\n const existingColNames = new Set(model.columns.map((c) => c.name.toLowerCase()));\n for (const wc of warehouseMatch.columns) {\n if (!existingColNames.has(wc.name.toLowerCase())) {\n updatedColumns.push(wc);\n }\n }\n\n mergedModels.push({ ...model, columns: updatedColumns });\n consumedWarehouseTables.add(tableKey);\n } else {\n mergedModels.push(model);\n }\n }\n\n // Append warehouse-only models (not consumed by dbt merge)\n for (const wm of warehouseModels) {\n const tableKey = (wm.table || '').toUpperCase();\n if (!consumedWarehouseTables.has(tableKey)) {\n mergedModels.push(wm);\n }\n }\n\n return {\n ...existingCatalog,\n syncedAt: new Date().toISOString(),\n models: mergedModels,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Async orchestrator\n// ---------------------------------------------------------------------------\n\n/**\n * Main warehouse sync orchestrator.\n *\n * 1. Fetch tables and columns from the warehouse.\n * 2. Diff against previous sync state.\n * 3. Sample new/changed tables (unless skipSamples).\n * 4. Build warehouse CatalogModel entries.\n * 5. Merge with existing catalog, write files.\n */\nexport async function syncWarehouse(\n projectDir: string,\n connector: Connector,\n connectionType: string,\n connectionName: string,\n options?: SyncWarehouseOptions,\n): Promise<SyncWarehouseResult> {\n const start = performance.now();\n const errors: string[] = [];\n\n // 1. Fetch tables\n let normalizedTables: NormalizedTable[] = [];\n\n if (connectionType === 'bigquery') {\n // BigQuery INFORMATION_SCHEMA is dataset-scoped — the dataset must be baked\n // into the query, so we run one query per dataset rather than filtering\n // client-side.\n if (!options?.schemas || options.schemas.length === 0) {\n throw new Error(\n 'BigQuery sync requires a dataset. Pass --schema <dataset> (or set config.dataset).',\n );\n }\n for (const dataset of options.schemas) {\n const q = getTablesQuery(connectionType, { schema: dataset });\n const res = await connector.execute(q.sql);\n normalizedTables.push(...q.normalize(res.rows));\n }\n } else {\n const tablesQuery = getTablesQuery(connectionType, {\n database: options?.database,\n });\n const tablesResult = await connector.execute(tablesQuery.sql);\n normalizedTables = tablesQuery.normalize(tablesResult.rows);\n\n // Filter by schemas if specified\n if (options?.schemas && options.schemas.length > 0) {\n const schemaSet = new Set(options.schemas.map((s) => s.toUpperCase()));\n normalizedTables = normalizedTables.filter((t) => schemaSet.has(t.schema.toUpperCase()));\n }\n }\n\n // 2. Fetch columns\n let allColumns: NormalizedColumnWithTable[] = [];\n\n if (connectionType === 'sqlite') {\n // SQLite: describe each table individually\n for (const table of normalizedTables) {\n try {\n const describeQuery = getDescribeQuery('sqlite', table.name);\n const descResult = await connector.execute(describeQuery.sql);\n const cols = describeQuery.normalize(descResult.rows);\n for (const col of cols) {\n allColumns.push({\n schema: table.schema,\n table: table.name,\n name: col.name,\n type: col.type,\n nullable: col.nullable,\n });\n }\n } catch (err) {\n errors.push(`Failed to describe ${table.name}: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n } else if (connectionType === 'bigquery') {\n // Dataset-scoped, same as the tables query above.\n for (const dataset of options!.schemas!) {\n const q = getColumnsQuery(connectionType, { schema: dataset });\n const res = await connector.execute(q.sql);\n allColumns.push(...q.normalize(res.rows));\n }\n } else {\n const columnsQuery = getColumnsQuery(connectionType, {\n database: options?.database,\n });\n const columnsResult = await connector.execute(columnsQuery.sql);\n allColumns = columnsQuery.normalize(columnsResult.rows);\n\n // Filter columns by schemas if specified\n if (options?.schemas && options.schemas.length > 0) {\n const schemaSet = new Set(options.schemas.map((s) => s.toUpperCase()));\n allColumns = allColumns.filter((c) => schemaSet.has(c.schema.toUpperCase()));\n }\n }\n\n // Group columns by table\n const columnMap = groupColumnsByTable(allColumns);\n\n // Build WarehouseTable entries with column counts\n const warehouseTables: WarehouseTable[] = normalizedTables.map((t) => {\n const qualifiedName = t.schema ? `${t.schema}.${t.name}` : t.name;\n return {\n qualifiedName,\n schema: t.schema,\n name: t.name,\n type: t.type,\n columnCount: columnMap.get(qualifiedName)?.length || 0,\n };\n });\n\n // 3. Load previous sync state, compute diff\n let prevState: SyncState | null = null;\n if (!options?.full) {\n try {\n const raw = await readFile(join(projectDir, '.yamchart', 'warehouse-sync.json'), 'utf-8');\n prevState = JSON.parse(raw);\n } catch {\n /* no previous state */\n }\n }\n\n const diff = diffSyncState(warehouseTables, prevState);\n\n // 4. Sample new/changed tables (unless skipSamples)\n const samples: Record<string, Record<string, unknown>[]> = {};\n const tablesToSample = options?.skipSamples\n ? []\n : [...diff.newTables, ...diff.changedTables];\n\n for (let i = 0; i < tablesToSample.length; i++) {\n const tableName = tablesToSample[i]!;\n options?.onProgress?.(tableName, i + 1, tablesToSample.length);\n\n try {\n const sampleSql = `SELECT * FROM ${tableName} LIMIT 3`;\n const samplePromise = connector.execute(sampleSql);\n const timeoutPromise = new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error(`Timeout sampling ${tableName} (5s)`)), 5000),\n );\n const result = await Promise.race([samplePromise, timeoutPromise]);\n samples[tableName] = result.rows;\n } catch (err) {\n errors.push(`Failed to sample ${tableName}: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n // 5. For unchanged tables: carry forward sampleRows from existing catalog\n let existingCatalog: CatalogData | null = null;\n try {\n const raw = await readFile(join(projectDir, '.yamchart', 'catalog.json'), 'utf-8');\n existingCatalog = JSON.parse(raw);\n } catch {\n /* no existing catalog */\n }\n\n if (existingCatalog && !options?.skipSamples) {\n for (const tableName of diff.unchangedTables) {\n const existingModel = existingCatalog.models.find(\n (m) => m.table?.toUpperCase() === tableName.toUpperCase() && m.source === 'warehouse',\n );\n if (existingModel?.sampleRows) {\n samples[tableName] = existingModel.sampleRows;\n }\n }\n }\n\n // 6. Build warehouse CatalogModel entries\n const warehouseModels = buildWarehouseModels(warehouseTables, columnMap, samples);\n\n // 7. Merge with existing catalog, write files\n const merged = mergeWithDbtCatalog(existingCatalog, warehouseModels);\n\n await mkdir(join(projectDir, '.yamchart'), { recursive: true });\n await writeFile(join(projectDir, '.yamchart', 'catalog.json'), generateCatalogJson(merged));\n\n const catalogMd = generateCatalogMd(merged);\n const syncDate = new Date().toISOString().split('T')[0]!;\n const warehouseSection = generateWarehouseSection(merged.models, connectionName, syncDate);\n const fullMd = warehouseSection ? catalogMd + '\\n' + warehouseSection : catalogMd;\n await writeFile(join(projectDir, '.yamchart', 'catalog.md'), fullMd);\n\n // Write sync state\n const syncState: SyncState = {\n syncedAt: new Date().toISOString(),\n connection: connectionName,\n schemas: options?.schemas || [],\n skipSamples: options?.skipSamples || false,\n tables: Object.fromEntries(\n warehouseTables.map((t) => [t.qualifiedName, { columnCount: t.columnCount }]),\n ),\n };\n await writeFile(join(projectDir, '.yamchart', 'warehouse-sync.json'), JSON.stringify(syncState, null, 2));\n\n const durationMs = Math.round(performance.now() - start);\n\n return {\n tablesTotal: warehouseTables.length,\n tablesNew: diff.newTables.length,\n tablesChanged: diff.changedTables.length,\n tablesUnchanged: diff.unchangedTables.length,\n tablesRemoved: diff.removedTables.length,\n errors,\n durationMs,\n };\n}\n","/**\n * CLI handler for `yamchart sync-warehouse`.\n *\n * Thin wrapper: resolves connection, creates connector, delegates to syncWarehouse().\n */\n\nimport * as output from '../utils/output.js';\nimport { resolveConnection, createConnector } from './connection-utils.js';\nimport { syncWarehouse } from './warehouse-sync.js';\nimport { readFile } from 'fs/promises';\nimport { join } from 'path';\nimport type { SyncState } from './warehouse-sync.js';\n\nexport interface SyncWarehouseCliOptions {\n connection?: string;\n schema?: string; // comma-separated → split into array\n database?: string;\n skipSamples?: boolean;\n refresh?: boolean;\n full?: boolean;\n json?: boolean;\n}\n\nexport async function runSyncWarehouse(\n projectDir: string,\n options: SyncWarehouseCliOptions,\n): Promise<void> {\n // Handle --refresh: load saved connection/schemas from previous sync state\n let connectionOverride = options.connection;\n let schemasOverride = options.schema;\n\n if (options.refresh) {\n try {\n const raw = await readFile(join(projectDir, '.yamchart', 'warehouse-sync.json'), 'utf-8');\n const prevState: SyncState = JSON.parse(raw);\n connectionOverride = connectionOverride || prevState.connection;\n if (!schemasOverride && prevState.schemas.length > 0) {\n schemasOverride = prevState.schemas.join(',');\n }\n if (!options.json) {\n output.info(`Re-syncing from ${prevState.connection} (${prevState.schemas.join(', ') || 'all schemas'})`);\n }\n } catch {\n output.error('No previous sync state found. Run sync-warehouse without --refresh first.');\n process.exit(1);\n }\n }\n\n // Resolve connection\n const connection = await resolveConnection(projectDir, connectionOverride);\n const connector = createConnector(connection, projectDir);\n\n let schemas = schemasOverride\n ? schemasOverride.split(',').map((s) => s.trim())\n : undefined;\n\n // BigQuery INFORMATION_SCHEMA is dataset-scoped; fall back to the connection's\n // configured dataset when no --schema is provided.\n if ((!schemas || schemas.length === 0) && connection.type === 'bigquery') {\n const dataset = (connection.config as { dataset?: string }).dataset;\n if (dataset) {\n schemas = [dataset];\n }\n }\n\n const spin = options.json ? null : output.spinner(`Connecting to ${connection.name} ...`);\n\n try {\n await connector.connect();\n\n if (spin) {\n spin.text = 'Fetching table metadata...';\n }\n\n const result = await syncWarehouse(\n projectDir,\n connector,\n connection.type,\n connection.name,\n {\n schemas,\n database: options.database,\n skipSamples: options.skipSamples,\n full: options.full,\n onProgress: spin\n ? (table, index, total) => {\n spin.text = `Sampling tables... ${index}/${total} (${table})`;\n }\n : undefined,\n },\n );\n\n if (spin) {\n spin.stop();\n }\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n } else {\n const parts = [\n `${result.tablesNew} new`,\n `${result.tablesChanged} changed`,\n `${result.tablesUnchanged} unchanged`,\n ];\n if (result.tablesRemoved > 0) {\n parts.push(`${result.tablesRemoved} removed`);\n }\n output.success(\n `Synced ${result.tablesTotal} tables (${parts.join(', ')}) in ${(result.durationMs / 1000).toFixed(1)}s`,\n );\n output.detail('Written to .yamchart/catalog.json');\n\n if (result.errors.length > 0) {\n output.warning(`${result.errors.length} table(s) had sampling errors:`);\n for (const err of result.errors.slice(0, 5)) {\n output.detail(err);\n }\n if (result.errors.length > 5) {\n output.detail(`... and ${result.errors.length - 5} more`);\n }\n }\n }\n } finally {\n await connector.disconnect();\n }\n}\n"],"mappings":"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","names":["readFile","join"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/test.ts"],"sourcesContent":["import { readFile, readdir } from 'fs/promises';\nimport { join, extname } from 'path';\nimport {\n parseModelMetadata,\n runAll,\n renderTemplate,\n createTemplateContext,\n expandDatePreset,\n isDatePreset,\n resolveDynamicDefault,\n type TestSuiteResult,\n type TestModelInput,\n} from '@yamchart/query';\nimport type { ModelMetadata } from '@yamchart/schema';\nimport * as output from '../utils/output.js';\nimport { resolveConnection, createConnector } from './connection-utils.js';\n\nexport interface TestOptions {\n connection?: string;\n json?: boolean;\n}\n\nexport interface TestResult {\n success: boolean;\n suite: TestSuiteResult;\n connectionName: string;\n}\n\nexport async function testProject(\n projectDir: string,\n modelFilter: string | undefined,\n options: TestOptions,\n): Promise<TestResult> {\n const connection = await resolveConnection(projectDir, options.connection);\n const connector = createConnector(connection, projectDir);\n\n const modelsDir = join(projectDir, 'models');\n const allModels = await loadModels(modelsDir);\n\n let modelsToTest = allModels;\n if (modelFilter) {\n modelsToTest = allModels.filter((m) => m.name === modelFilter);\n if (modelsToTest.length === 0) {\n throw new Error(`Model \"${modelFilter}\" not found`);\n }\n }\n\n // Build refs map: model name -> model name (identity for standalone execution)\n const refs: Record<string, string> = {};\n for (const m of allModels) {\n refs[m.name] = m.name;\n }\n\n const testInputs: TestModelInput[] = [];\n for (const model of modelsToTest) {\n try {\n const compiledSql = compileWithDefaults(model.sql, model.metadata, refs);\n testInputs.push({ compiledSql, metadata: model.metadata });\n } catch {\n // If compilation fails, include raw SQL so the error is reported during test execution\n testInputs.push({ compiledSql: model.sql, metadata: model.metadata });\n }\n }\n\n try {\n await connector.connect();\n const suite = await runAll(testInputs, connector);\n return { success: suite.failed === 0, suite, connectionName: connection.name };\n } finally {\n await connector.disconnect();\n }\n}\n\nfunction compileWithDefaults(\n sql: string,\n metadata: ModelMetadata,\n refs: Record<string, string>,\n): string {\n const params: Record<string, unknown> = {};\n if (metadata.params) {\n for (const p of metadata.params) {\n if (p.default !== undefined) {\n params[p.name] = resolveDynamicDefault(p.default);\n }\n }\n }\n\n // Expand date presets into start_date/end_date\n if (typeof params.date_range === 'string' && isDatePreset(params.date_range)) {\n const range = expandDatePreset(params.date_range);\n if (range) {\n params.start_date = range.start_date;\n params.end_date = range.end_date;\n }\n }\n\n const context = createTemplateContext(params, refs);\n return renderTemplate(sql, context);\n}\n\ninterface LoadedModel {\n name: string;\n sql: string;\n metadata: ModelMetadata;\n}\n\nasync function loadModels(dir: string): Promise<LoadedModel[]> {\n const models: LoadedModel[] = [];\n\n let entries;\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch {\n return models;\n }\n\n for (const entry of entries) {\n const fullPath = join(dir, entry.name);\n if (entry.isDirectory()) {\n const subModels = await loadModels(fullPath);\n models.push(...subModels);\n } else if (extname(entry.name) === '.sql') {\n const content = await readFile(fullPath, 'utf-8');\n try {\n const parsed = parseModelMetadata(content);\n models.push({ name: parsed.name, sql: parsed.sql, metadata: parsed });\n } catch {\n // Skip unparseable models\n }\n }\n }\n\n return models;\n}\n\nexport function formatTestOutput(result: TestResult, connectionName: string): void {\n const { suite } = result;\n\n const testedModels = suite.models.filter(\n (m) => m.schemaCheck || m.assertions.length > 0 || m.error,\n );\n\n output.header(`Testing ${suite.models.length} model(s) against ${connectionName}...`);\n\n for (const model of suite.models) {\n const hasChecks = model.schemaCheck || model.assertions.length > 0 || model.error;\n if (!hasChecks) continue;\n\n console.log(` ${model.modelName}`);\n\n if (model.error) {\n output.error(` error: ${model.error}`);\n continue;\n }\n\n if (model.schemaCheck) {\n formatSchemaCheck(model.schemaCheck);\n }\n\n for (const assertion of model.assertions) {\n formatAssertion(assertion);\n }\n\n output.newline();\n }\n\n // Summary line\n const totalChecks = suite.passed + suite.failed;\n const summary = `${testedModels.length} model(s), ${totalChecks} check(s): ${suite.passed} passed, ${suite.failed} failed`;\n const skippedSuffix = suite.skipped > 0 ? ` (${suite.skipped} skipped)` : '';\n const durationSuffix = ` (${suite.durationMs.toFixed(0)}ms)`;\n\n if (suite.failed === 0) {\n output.success(`${summary}${skippedSuffix}${durationSuffix}`);\n } else {\n output.error(`${summary}${skippedSuffix}${durationSuffix}`);\n }\n}\n\nfunction formatSchemaCheck(check: NonNullable<TestSuiteResult['models'][0]['schemaCheck']>): void {\n if (check.passed) {\n output.success(` schema: returns expected columns (${check.expectedColumns.join(', ')})`);\n return;\n }\n\n const issues: string[] = [];\n if (check.missingColumns.length > 0) {\n issues.push(`missing: ${check.missingColumns.join(', ')}`);\n }\n for (const m of check.typeMismatches) {\n issues.push(`${m.column}: expected ${m.expected}, got ${m.actual}`);\n }\n output.error(` schema: ${issues.join('; ')}`);\n}\n\nfunction formatAssertion(assertion: TestSuiteResult['models'][0]['assertions'][0]): void {\n const label = extractAssertionLabel(assertion.sql);\n\n if (assertion.warning) {\n output.warning(` ${label}`);\n output.detail(` ${assertion.warning}`);\n }\n\n if (assertion.error) {\n output.error(` test: ${label} -- error`);\n output.detail(` ${assertion.error}`);\n } else if (assertion.passed) {\n output.success(` test: ${label}`);\n } else {\n output.error(` test: ${label} -- ${assertion.violationCount} failing row(s)`);\n if (assertion.sampleViolations) {\n for (const row of assertion.sampleViolations.slice(0, 3)) {\n output.detail(` ${JSON.stringify(row)}`);\n }\n }\n }\n}\n\nfunction extractAssertionLabel(sql: string): string {\n const whereMatch = sql.match(/WHERE\\s+(.+?)$/i);\n if (whereMatch?.[1]) {\n const clause = whereMatch[1].trim();\n return clause.length > 60 ? clause.slice(0, 57) + '...' : clause;\n }\n return sql.length > 60 ? sql.slice(0, 57) + '...' : sql;\n}\n"],"mappings":"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","names":[]}