@uncaughtdev/core 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/README.md +44 -3
  2. package/dist/chunk-2YXXFGBV.js +2 -0
  3. package/dist/chunk-2YXXFGBV.js.map +1 -0
  4. package/dist/chunk-3FCDO7OR.mjs +23 -0
  5. package/dist/chunk-3FCDO7OR.mjs.map +1 -0
  6. package/dist/chunk-A6GKDPT3.mjs +2 -0
  7. package/dist/chunk-A6GKDPT3.mjs.map +1 -0
  8. package/dist/chunk-BXMN7NW4.mjs +2 -0
  9. package/dist/chunk-BXMN7NW4.mjs.map +1 -0
  10. package/dist/chunk-HANXURHX.mjs +59 -0
  11. package/dist/chunk-HANXURHX.mjs.map +1 -0
  12. package/dist/chunk-MSUAXLMV.js +2 -0
  13. package/dist/chunk-MSUAXLMV.js.map +1 -0
  14. package/dist/chunk-VQXSHR3C.js +59 -0
  15. package/dist/chunk-VQXSHR3C.js.map +1 -0
  16. package/dist/chunk-WZBG5VLB.js +23 -0
  17. package/dist/chunk-WZBG5VLB.js.map +1 -0
  18. package/dist/index.d.mts +64 -3
  19. package/dist/index.d.ts +64 -3
  20. package/dist/index.js +7 -26
  21. package/dist/index.js.map +1 -1
  22. package/dist/index.mjs +7 -26
  23. package/dist/index.mjs.map +1 -1
  24. package/dist/local-api-handler-pages.js +1 -1
  25. package/dist/local-api-handler-pages.js.map +1 -1
  26. package/dist/local-api-handler-pages.mjs +1 -1
  27. package/dist/local-api-handler-pages.mjs.map +1 -1
  28. package/dist/local-api-handler.d.mts +1 -1
  29. package/dist/local-api-handler.d.ts +1 -1
  30. package/dist/local-api-handler.js +1 -1
  31. package/dist/local-api-handler.mjs +1 -1
  32. package/dist/local-viewer.js +432 -46
  33. package/dist/local-viewer.js.map +1 -1
  34. package/dist/local-viewer.mjs +432 -46
  35. package/dist/local-viewer.mjs.map +1 -1
  36. package/dist/mcp-server.d.mts +1 -0
  37. package/dist/mcp-server.d.ts +1 -0
  38. package/dist/mcp-server.js +22 -0
  39. package/dist/mcp-server.js.map +1 -0
  40. package/dist/mcp-server.mjs +22 -0
  41. package/dist/mcp-server.mjs.map +1 -0
  42. package/dist/sqlite-store-4FTNST7O.js +2 -0
  43. package/dist/sqlite-store-4FTNST7O.js.map +1 -0
  44. package/dist/sqlite-store-TEXDAAOM.mjs +2 -0
  45. package/dist/sqlite-store-TEXDAAOM.mjs.map +1 -0
  46. package/dist/{types-CjgYXVc_.d.mts → types-D1Fw4k-D.d.mts} +12 -1
  47. package/dist/{types-CjgYXVc_.d.ts → types-D1Fw4k-D.d.ts} +12 -1
  48. package/package.json +9 -2
  49. package/dist/chunk-FFHQ452Q.js +0 -2
  50. package/dist/chunk-FFHQ452Q.js.map +0 -1
  51. package/dist/chunk-JALIO2BZ.mjs +0 -2
  52. package/dist/chunk-JALIO2BZ.mjs.map +0 -1
@@ -1,96 +1,482 @@
1
1
  #!/usr/bin/env node
2
- 'use strict';var c=require('fs/promises'),r=require('path'),child_process=require('child_process');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var c__namespace=/*#__PURE__*/_interopNamespace(c);var r__namespace=/*#__PURE__*/_interopNamespace(r);var N="\x1B[0m",y="\x1B[1m",h="\x1B[2m",b="\x1B[31m",x="\x1B[32m",m="\x1B[33m",f="\x1B[36m",j="\x1B[37m",w="\x1B[90m",A="\x1B[41m",M="\x1B[42m",O="\x1B[43m";function n(e,t){return `${e}${t}${N}`}function E(){return r__namespace.resolve(process.cwd(),".uncaught")}function F(){return r__namespace.join(E(),"issues.json")}async function D(){try{let e=await c__namespace.readFile(F(),"utf-8");return JSON.parse(e)}catch{return []}}async function T(e){let t=F(),o=t+".tmp";await c__namespace.writeFile(o,JSON.stringify(e,null,2),"utf-8"),await c__namespace.rename(o,t);}async function L(){let e=await D();if(e.length===0){console.log(n(h,`
2
+ 'use strict';var chunkVQXSHR3C_js=require('./chunk-VQXSHR3C.js');require('./chunk-2YXXFGBV.js');var l=require('fs/promises'),i=require('path'),L=require('http'),child_process=require('child_process');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var l__namespace=/*#__PURE__*/_interopNamespace(l);var i__namespace=/*#__PURE__*/_interopNamespace(i);var L__namespace=/*#__PURE__*/_interopNamespace(L);var O="\x1B[0m",$="\x1B[1m",h="\x1B[2m",k="\x1B[31m",x="\x1B[32m",v="\x1B[33m",b="\x1B[36m",I="\x1B[37m",w="\x1B[90m",N="\x1B[41m",z="\x1B[42m",B="\x1B[43m";function t(e,n){return `${e}${n}${O}`}function P(){return i__namespace.resolve(process.cwd(),".uncaught")}function M(){return i__namespace.join(P(),"issues.json")}function J(){return i__namespace.join(P(),"uncaught.db")}function E(){let e=chunkVQXSHR3C_js.a(J());return e.importFromFiles(P()),e}async function D(){try{let e=E(),n=e.getIssues();return e.close(),n}catch{try{let e=await l__namespace.readFile(M(),"utf-8");return JSON.parse(e)}catch{return []}}}async function G(e){let n=M(),o=n+".tmp";await l__namespace.writeFile(o,JSON.stringify(e,null,2),"utf-8"),await l__namespace.rename(o,n);try{let s=E();for(let a of e)s.upsertIssue(a);s.close();}catch{}}async function _(){let e=await D();if(e.length===0){console.log(t(h,`
3
3
  No issues found in .uncaught/
4
- `)),console.log(n(w,` Capture errors with initUncaught() to see them here.
5
- `));return}console.log(""),console.log(n(y," Uncaught Issues")),console.log(n(h," \u2500".repeat(35))),console.log("");let t=B("#","Status","Count","Error","Last Seen");console.log(n(h,` ${t}`)),console.log(n(h," "+"\u2500".repeat(90)));for(let o=0;o<e.length;o++){let s=e[o],i=String(o+1).padStart(3),a=V(s.status),p=String(s.count).padStart(5),u=I(s.title,45),d=I(s.errorType,15),g=Y(s.lastSeen),l=`${n(b,d)} ${n(j,u)}`;console.log(` ${n(f,i)} ${a} ${n(m,p)} ${l} ${n(w,g)}`);}console.log(""),console.log(n(h,` ${e.length} issue(s) total`)),console.log(n(w," Run: uncaught show <n> to view fix prompt, --open to open in editor")),console.log("");}async function _(e,t){let o=await D(),s=parseInt(e,10)-1;if(isNaN(s)||s<0||s>=o.length){console.error(n(b,`
6
- Invalid issue number: ${e}`)),console.error(n(w,` Valid range: 1-${o.length}
7
- `)),process.exitCode=1;return}let i=o[s],a=r__namespace.join(E(),"fix-prompts",i.fixPromptFile),p;try{p=await c__namespace.readFile(a,"utf-8");}catch{console.error(n(b,`
8
- Fix prompt file not found: ${a}
9
- `)),process.exitCode=1;return}if(t){let u=process.env.EDITOR||"code";console.log(n(h,` Opening ${a} in ${u}...`));try{child_process.spawn(u,[a],{detached:!0,stdio:"ignore"}).unref();}catch{let d=process.platform==="darwin"?"open":"xdg-open";try{child_process.spawn(d,[a],{detached:!0,stdio:"ignore"}).unref();}catch{console.error(n(b,` Could not open editor. File is at: ${a}`));}}return}console.log(""),console.log(n(y,` Fix Prompt for Issue #${s+1}`)),console.log(n(h,` Fingerprint: ${i.fingerprint}`)),console.log(n(h,` Count: ${i.count} | Users: ${i.affectedUsers.length}`)),console.log(n(h," \u2500".repeat(35))),console.log(""),console.log(p),console.log(""),console.log(n(w,` File: ${a}`)),console.log(n(w," Tip: run with --open to open in your editor")),console.log("");}async function W(){let e=E();try{await c__namespace.access(e);}catch{console.log(n(h,`
4
+ `)),console.log(t(w,` Capture errors with initUncaught() to see them here.
5
+ `));return}console.log(""),console.log(t($," Uncaught Issues")),console.log(t(h," \u2500".repeat(35))),console.log("");let n=K("#","Status","Count","Error","Last Seen");console.log(t(h,` ${n}`)),console.log(t(h," "+"\u2500".repeat(90)));for(let o=0;o<e.length;o++){let s=e[o],a=String(o+1).padStart(3),r=Q(s.status),u=String(s.count).padStart(5),d=F(s.title,45),g=F(s.errorType,15),f=X(s.lastSeen),c=`${t(k,g)} ${t(I,d)}`;console.log(` ${t(b,a)} ${r} ${t(v,u)} ${c} ${t(w,f)}`);}console.log(""),console.log(t(h,` ${e.length} issue(s) total`)),console.log(t(w," Run: uncaught show <n> to view fix prompt, --open to open in editor")),console.log(t(b," Run: npx @uncaughtdev/core dashboard \u2014 for a web UI")),console.log("");}async function V(e,n){let o=await D(),s=parseInt(e,10)-1;if(isNaN(s)||s<0||s>=o.length){console.error(t(k,`
6
+ Invalid issue number: ${e}`)),console.error(t(w,` Valid range: 1-${o.length}
7
+ `)),process.exitCode=1;return}let a=o[s],r=i__namespace.join(P(),"fix-prompts",a.fixPromptFile),u;try{u=await l__namespace.readFile(r,"utf-8");}catch{console.error(t(k,`
8
+ Fix prompt file not found: ${r}
9
+ `)),process.exitCode=1;return}if(n){let d=process.env.EDITOR||"code";console.log(t(h,` Opening ${r} in ${d}...`));try{child_process.spawn(d,[r],{detached:!0,stdio:"ignore"}).unref();}catch{let g=process.platform==="darwin"?"open":"xdg-open";try{child_process.spawn(g,[r],{detached:!0,stdio:"ignore"}).unref();}catch{console.error(t(k,` Could not open editor. File is at: ${r}`));}}return}console.log(""),console.log(t($,` Fix Prompt for Issue #${s+1}`)),console.log(t(h,` Fingerprint: ${a.fingerprint}`)),console.log(t(h,` Count: ${a.count} | Users: ${a.affectedUsers.length}`)),console.log(t(h," \u2500".repeat(35))),console.log(""),console.log(u),console.log(""),console.log(t(w,` File: ${r}`)),console.log(t(w," Tip: run with --open to open in your editor")),console.log("");}async function W(){let e=P();try{await l__namespace.access(e);}catch{console.log(t(h,`
10
10
  Nothing to clear \u2014 .uncaught/ does not exist.
11
- `));return}let t=await c__namespace.readdir(e);for(let o of t){let s=r__namespace.join(e,o);await c__namespace.rm(s,{recursive:true,force:true});}console.log(n(x,`
11
+ `));return}try{let o=E();o.deleteAllIssues(),o.close();}catch{}let n=await l__namespace.readdir(e);for(let o of n){let s=i__namespace.join(e,o);await l__namespace.rm(s,{recursive:true,force:true});}console.log(t(x,`
12
12
  Cleared all issues in .uncaught/
13
- `));}async function G(e){let t=await D(),o=parseInt(e,10)-1;if(isNaN(o)||o<0||o>=t.length){console.error(n(b,`
14
- Invalid issue number: ${e}`)),console.error(n(w,` Valid range: 1-${t.length}
15
- `)),process.exitCode=1;return}let s=t[o];if(s.status==="resolved"){console.log(n(m,`
13
+ `));}async function Y(e){let n=await D(),o=parseInt(e,10)-1;if(isNaN(o)||o<0||o>=n.length){console.error(t(k,`
14
+ Invalid issue number: ${e}`)),console.error(t(w,` Valid range: 1-${n.length}
15
+ `)),process.exitCode=1;return}let s=n[o];if(s.status==="resolved"){console.log(t(v,`
16
16
  Issue #${o+1} is already resolved.
17
- `));return}s.status="resolved",await T(t),console.log(n(x,`
18
- Issue #${o+1} marked as resolved.`)),console.log(n(h,` ${s.errorType}: ${I(s.title,60)}
19
- `));}function B(e,t,o,s,i){return `${e.padStart(3)} ${t.padEnd(10)} ${o.padStart(5)} ${s.padEnd(60)} ${i}`}function V(e){switch(e){case "open":return n(`${A}${j}${y}`," OPEN ");case "resolved":return n(`${M}${j}${y}`," DONE ");case "ignored":return n(`${O}${j}${y}`," SKIP ");default:return n(h,String(e).padEnd(6))}}function Y(e){try{let t=new Date(e).getTime(),s=Date.now()-t;if(s<0)return "just now";let i=Math.floor(s/1e3);if(i<60)return `${i}s ago`;let a=Math.floor(i/60);if(a<60)return `${a}m ago`;let p=Math.floor(a/60);if(p<24)return `${p}h ago`;let u=Math.floor(p/24);return u<30?`${u}d ago`:new Date(e).toLocaleDateString()}catch{return e}}function I(e,t){return e.length<=t?e:e.slice(0,t-3)+"..."}function R(){console.log(`
20
- ${n(y," uncaught")} \u2014 error monitoring for vibe coders
17
+ `));return}s.status="resolved",await G(n);try{let a=E();a.updateIssueStatus(s.fingerprint,"resolved"),a.close();}catch{}console.log(t(x,`
18
+ Issue #${o+1} marked as resolved.`)),console.log(t(h,` ${s.errorType}: ${F(s.title,60)}
19
+ `));}function K(e,n,o,s,a){return `${e.padStart(3)} ${n.padEnd(10)} ${o.padStart(5)} ${s.padEnd(60)} ${a}`}function Q(e){switch(e){case "open":return t(`${N}${I}${$}`," OPEN ");case "resolved":return t(`${z}${I}${$}`," DONE ");case "ignored":return t(`${B}${I}${$}`," SKIP ");default:return t(h,String(e).padEnd(6))}}function X(e){try{let n=new Date(e).getTime(),s=Date.now()-n;if(s<0)return "just now";let a=Math.floor(s/1e3);if(a<60)return `${a}s ago`;let r=Math.floor(a/60);if(r<60)return `${r}m ago`;let u=Math.floor(r/60);if(u<24)return `${u}h ago`;let d=Math.floor(u/24);return d<30?`${d}d ago`:new Date(e).toLocaleDateString()}catch{return e}}function F(e,n){return e.length<=n?e:e.slice(0,n-3)+"..."}function U(){console.log(`
20
+ ${t($," uncaught")} \u2014 error monitoring for vibe coders
21
21
 
22
- ${n(y," Setup:")}
23
- ${n(f,"npx uncaughtdev init")} Auto-detect framework, install, and patch \u2014 one command
22
+ ${t($," Setup:")}
23
+ ${t(b,"npx uncaughtdev init")} Auto-detect framework, install, and patch \u2014 one command
24
24
 
25
- ${n(y," Viewer:")}
25
+ ${t($," Viewer:")}
26
26
  npx uncaughtdev List all captured issues
27
27
  npx uncaughtdev list List all captured issues
28
28
  npx uncaughtdev show <n> Display fix prompt for issue #n
29
29
  npx uncaughtdev show <n> --open Open fix prompt in $EDITOR
30
30
  npx uncaughtdev resolve <n> Mark issue #n as resolved
31
31
  npx uncaughtdev clear Remove all captured issues
32
+ npx uncaughtdev dashboard Open web dashboard (--port 3300)
32
33
 
33
- ${n(y," Examples:")}
34
+ ${t($," Examples:")}
34
35
  npx uncaughtdev init Setup Uncaught in your project
35
36
  npx uncaughtdev show 1 Print fix prompt for issue #1
36
37
  npx uncaughtdev show 3 --open Open issue #3's prompt in editor
37
- `);}async function v(e){try{return await c__namespace.access(e),!0}catch{return false}}async function P(e){try{return (await c__namespace.stat(e)).isDirectory()}catch{return false}}function J(e,t){return new Promise(o=>{let s=child_process.spawn(e,t,{stdio:"inherit",shell:true});s.on("close",i=>o(i===0)),s.on("error",()=>o(false));})}async function K(){let e=process.cwd(),t={framework:"unknown",packageManager:"npm",hasSupabase:false,hasTypescript:false,rootDir:e};await v(r__namespace.join(e,"pnpm-lock.yaml"))?t.packageManager="pnpm":await v(r__namespace.join(e,"yarn.lock"))?t.packageManager="yarn":(await v(r__namespace.join(e,"bun.lockb"))||await v(r__namespace.join(e,"bun.lock")))&&(t.packageManager="bun");let o={};try{let i=await c__namespace.readFile(r__namespace.join(e,"package.json"),"utf-8");o=JSON.parse(i);}catch{return t}let s={...o.dependencies??{},...o.devDependencies??{}};return t.hasTypescript="typescript"in s||await v(r__namespace.join(e,"tsconfig.json")),t.hasSupabase="@supabase/supabase-js"in s,"next"in s?await P(r__namespace.join(e,"app"))||await P(r__namespace.join(e,"src","app"))?t.framework="nextjs-app":await P(r__namespace.join(e,"pages"))||await P(r__namespace.join(e,"src","pages"))?t.framework="nextjs-pages":t.framework="nextjs-app":"vite"in s&&("react"in s||"react-dom"in s)?t.framework="vite-react":"react-scripts"in s&&(t.framework="cra"),t}function H(e,t){switch(e){case "pnpm":return {cmd:"pnpm",args:["add",...t]};case "yarn":return {cmd:"yarn",args:["add",...t]};case "bun":return {cmd:"bun",args:["add",...t]};default:return {cmd:"npm",args:["install",...t]}}}function q(e){let t=-1,o=/^import\s/gm,s;for(;(s=o.exec(e))!==null;)t=s.index;return t}function z(e,t){let o=q(e);if(o>=0){let i=e.indexOf(`
38
- `,o)+1;return e.slice(0,i)+t+e.slice(i)}let s=e.indexOf(`
38
+ `);}async function y(e){try{return await l__namespace.access(e),!0}catch{return false}}async function S(e){try{return (await l__namespace.stat(e)).isDirectory()}catch{return false}}function Z(e,n){return new Promise(o=>{let s=child_process.spawn(e,n,{stdio:"inherit",shell:true});s.on("close",a=>o(a===0)),s.on("error",()=>o(false));})}async function q(){let e=process.cwd(),n={framework:"unknown",packageManager:"npm",hasSupabase:false,hasTypescript:false,rootDir:e};await y(i__namespace.join(e,"pnpm-lock.yaml"))?n.packageManager="pnpm":await y(i__namespace.join(e,"yarn.lock"))?n.packageManager="yarn":(await y(i__namespace.join(e,"bun.lockb"))||await y(i__namespace.join(e,"bun.lock")))&&(n.packageManager="bun");let o={};try{let a=await l__namespace.readFile(i__namespace.join(e,"package.json"),"utf-8");o=JSON.parse(a);}catch{return n}let s={...o.dependencies??{},...o.devDependencies??{}};return n.hasTypescript="typescript"in s||await y(i__namespace.join(e,"tsconfig.json")),n.hasSupabase="@supabase/supabase-js"in s,"next"in s?await S(i__namespace.join(e,"app"))||await S(i__namespace.join(e,"src","app"))?n.framework="nextjs-app":await S(i__namespace.join(e,"pages"))||await S(i__namespace.join(e,"src","pages"))?n.framework="nextjs-pages":n.framework="nextjs-app":"vite"in s&&("react"in s||"react-dom"in s)?n.framework="vite-react":"react-scripts"in s&&(n.framework="cra"),n}function ee(e,n){switch(e){case "pnpm":return {cmd:"pnpm",args:["add",...n]};case "yarn":return {cmd:"yarn",args:["add",...n]};case "bun":return {cmd:"bun",args:["add",...n]};default:return {cmd:"npm",args:["install",...n]}}}function te(e){let n=-1,o=/^import\s/gm,s;for(;(s=o.exec(e))!==null;)n=s.index;return n}function T(e,n){let o=te(e);if(o>=0){let a=e.indexOf(`
39
+ `,o)+1;return e.slice(0,a)+n+e.slice(a)}let s=e.indexOf(`
39
40
  `);return s>=0&&e.slice(0,s).includes("use client")?e.slice(0,s+1)+`
40
- `+t+e.slice(s+1):t+e}async function Q(){let e=process.cwd();console.log(""),console.log(n(y," \u{1F9EA} uncaught init")),console.log(n(h," \u2500".repeat(35))),console.log(""),console.log(n(f," \u25B8 Detecting framework..."));let t=await K();if(console.log(` ${n(x,{"nextjs-app":"Next.js (App Router)","nextjs-pages":"Next.js (Pages Router)","vite-react":"Vite + React",cra:"Create React App",unknown:"Unknown"}[t.framework])} \xB7 ${t.packageManager} \xB7 TS=${t.hasTypescript} \xB7 Supabase=${t.hasSupabase}`),console.log(""),t.framework==="unknown"){console.log(n(m," \u26A0 Could not detect framework. Supported: Next.js, Vite+React, CRA")),process.exitCode=1;return}console.log(n(f," \u25B8 Installing packages..."));let s=["@uncaughtdev/core","@uncaughtdev/react"];t.hasSupabase&&s.push("@uncaughtdev/supabase");let i=H(t.packageManager,s);console.log(n(w,` ${i.cmd} ${i.args.join(" ")}`)),await J(i.cmd,i.args)?(console.log(n(x," \u2713 Packages installed")),console.log("")):(console.log(n(m,`
41
- \u26A0 Install failed \u2014 packages may not be published yet.`)),console.log(n(w," Continuing with file patching. Install manually if needed.")),console.log(""));let p=t.hasTypescript?"tsx":"jsx",u=t.hasTypescript?"ts":"js",d=r__namespace.basename(e);if(t.framework==="nextjs-app"){let g=await P(r__namespace.join(e,"app"))?r__namespace.join(e,"app"):r__namespace.join(e,"src","app");console.log(n(f," \u25B8 Patching layout..."));let l=r__namespace.join(g,`layout.${p}`);await S(l,d,"layout"),console.log(n(f," \u25B8 Creating API route..."));let k=r__namespace.join(g,"api","uncaught","local");await c__namespace.mkdir(k,{recursive:true});let $=r__namespace.join(k,`route.${u}`);await v($)?console.log(n(m," \u2298 Already exists, skipping")):(await c__namespace.writeFile($,`export { POST } from '@uncaughtdev/core/local-api-handler';
42
- `),console.log(n(x,` \u2713 Created ${r__namespace.relative(e,$)}`))),console.log(n(f," \u25B8 Patching next.config...")),await U(e);}else if(t.framework==="nextjs-pages"){let g=await P(r__namespace.join(e,"pages"))?r__namespace.join(e,"pages"):r__namespace.join(e,"src","pages");console.log(n(f," \u25B8 Patching _app..."));let l=r__namespace.join(g,`_app.${p}`);await S(l,d,"pages-app"),console.log(n(f," \u25B8 Creating API route..."));let k=r__namespace.join(g,"api","uncaught");await c__namespace.mkdir(k,{recursive:true});let $=r__namespace.join(k,`local.${u}`);await v($)?console.log(n(m," \u2298 Already exists, skipping")):(await c__namespace.writeFile($,`export { default } from '@uncaughtdev/core/local-api-handler/pages';
43
- `),console.log(n(x,` \u2713 Created ${r__namespace.relative(e,$)}`))),console.log(n(f," \u25B8 Patching next.config...")),await U(e);}else if(t.framework==="vite-react"||t.framework==="cra"){let g=t.framework==="vite-react"?["src/main.tsx","src/main.jsx","main.tsx","main.jsx"]:["src/index.tsx","src/index.jsx"],l=null;for(let k of g){let $=r__namespace.join(e,k);if(await v($)){l=$;break}}l?(console.log(n(f," \u25B8 Patching entry file...")),await S(l,d,"entry")):console.log(n(m," \u26A0 Could not find entry file. Wrap your root with <UncaughtProvider> manually."));}t.hasSupabase&&(console.log(""),console.log(n(f," \u25B8 Supabase detected! Wrap your client:")),console.log(n(w," import { wrapSupabase } from '@uncaughtdev/supabase';")),console.log(n(w," const supabase = wrapSupabase(createClient(url, key));"))),console.log(""),console.log(n(x," \u2713 Done! Uncaught is now tracking errors.")),console.log(""),console.log(n(j," Start your dev server, trigger an error, then:")),console.log(n(f," npx uncaughtdev")),console.log("");}async function S(e,t,o){let s=process.cwd(),i=r__namespace.relative(s,e);if(!await v(e)){let l="";o==="layout"?l=`'use client';
41
+ `+n+e.slice(s+1):n+e}async function ne(){let e=process.cwd();console.log(""),console.log(t($," \u{1F9EA} uncaught init")),console.log(t(h," \u2500".repeat(35))),console.log(""),console.log(t(b," \u25B8 Detecting framework..."));let n=await q();if(console.log(` ${t(x,{"nextjs-app":"Next.js (App Router)","nextjs-pages":"Next.js (Pages Router)","vite-react":"Vite + React",cra:"Create React App",unknown:"Unknown"}[n.framework])} \xB7 ${n.packageManager} \xB7 TS=${n.hasTypescript} \xB7 Supabase=${n.hasSupabase}`),console.log(""),n.framework==="unknown"){console.log(t(v," \u26A0 Could not detect framework. Supported: Next.js, Vite+React, CRA")),process.exitCode=1;return}console.log(t(b," \u25B8 Installing packages..."));let s=["@uncaughtdev/core","@uncaughtdev/react"];n.hasSupabase&&s.push("@uncaughtdev/supabase");let a=ee(n.packageManager,s);console.log(t(w,` ${a.cmd} ${a.args.join(" ")}`)),await Z(a.cmd,a.args)?(console.log(t(x," \u2713 Packages installed")),console.log("")):(console.log(t(v,`
42
+ \u26A0 Install failed \u2014 packages may not be published yet.`)),console.log(t(w," Continuing with file patching. Install manually if needed.")),console.log(""));let u=n.hasTypescript?"tsx":"jsx",d=n.hasTypescript?"ts":"js",g=i__namespace.basename(e);if(n.framework==="nextjs-app"){let f=await S(i__namespace.join(e,"app"))?i__namespace.join(e,"app"):i__namespace.join(e,"src","app");console.log(t(b," \u25B8 Setting up providers..."));let c=i__namespace.join(f,`layout.${u}`);await oe(f,c,g,u),console.log(t(b," \u25B8 Creating API route..."));let m=i__namespace.join(f,"api","uncaught","local");await l__namespace.mkdir(m,{recursive:true});let p=i__namespace.join(m,`route.${d}`);await y(p)?console.log(t(v," \u2298 Already exists, skipping")):(await l__namespace.writeFile(p,`export { POST } from '@uncaughtdev/core/local-api-handler';
43
+ `),console.log(t(x,` \u2713 Created ${i__namespace.relative(e,p)}`))),console.log(t(b," \u25B8 Patching next.config...")),await A(e);}else if(n.framework==="nextjs-pages"){let f=await S(i__namespace.join(e,"pages"))?i__namespace.join(e,"pages"):i__namespace.join(e,"src","pages");console.log(t(b," \u25B8 Patching _app..."));let c=i__namespace.join(f,`_app.${u}`);await R(c,g,"pages-app"),console.log(t(b," \u25B8 Creating API route..."));let m=i__namespace.join(f,"api","uncaught");await l__namespace.mkdir(m,{recursive:true});let p=i__namespace.join(m,`local.${d}`);await y(p)?console.log(t(v," \u2298 Already exists, skipping")):(await l__namespace.writeFile(p,`export { default } from '@uncaughtdev/core/local-api-handler/pages';
44
+ `),console.log(t(x,` \u2713 Created ${i__namespace.relative(e,p)}`))),console.log(t(b," \u25B8 Patching next.config...")),await A(e);}else if(n.framework==="vite-react"||n.framework==="cra"){let f=n.framework==="vite-react"?["src/main.tsx","src/main.jsx","main.tsx","main.jsx"]:["src/index.tsx","src/index.jsx"],c=null;for(let m of f){let p=i__namespace.join(e,m);if(await y(p)){c=p;break}}c?(console.log(t(b," \u25B8 Patching entry file...")),await R(c,g,"entry")):console.log(t(v," \u26A0 Could not find entry file. Wrap your root with <UncaughtProvider> manually."));}n.hasSupabase&&(console.log(""),console.log(t(b," \u25B8 Supabase detected! Wrap your client:")),console.log(t(w," import { wrapSupabase } from '@uncaughtdev/supabase';")),console.log(t(w," const supabase = wrapSupabase(createClient(url, key));"))),console.log(""),console.log(t(x," \u2713 Done! Uncaught is now tracking errors.")),console.log(""),console.log(t(I," Start your dev server, trigger an error, then:")),console.log(t(b," npx uncaughtdev")),console.log("");}async function oe(e,n,o,s){let a=process.cwd(),r=i__namespace.join(e,`providers.${s}`),u=i__namespace.relative(a,r),d=i__namespace.relative(a,n);if(await y(r)){let m=await l__namespace.readFile(r,"utf-8");if(m.includes("UncaughtProvider")||m.includes("@uncaughtdev/react"))console.log(t(v,` \u2298 ${u} already has UncaughtProvider, skipping`));else {let p=m;!p.includes("'use client'")&&!p.includes('"use client"')&&(p=`'use client';
45
+
46
+ ${p}`),p=T(p,`import { UncaughtProvider } from '@uncaughtdev/react';
47
+ `),await l__namespace.writeFile(r,p),console.log(t(v,` \u26A0 ${u} exists \u2014 added import but you may need to manually wrap with <UncaughtProvider>.`));}}else {let m=`'use client';
44
48
 
45
49
  import { UncaughtProvider } from '@uncaughtdev/react';
46
50
 
51
+ export function Providers({ children }: { children: React.ReactNode }) {
52
+ return (
53
+ <UncaughtProvider projectKey="${o}" transport="local">
54
+ {children}
55
+ </UncaughtProvider>
56
+ );
57
+ }
58
+ `;await l__namespace.writeFile(r,m),console.log(t(x,` \u2713 Created ${u}`));}if(!await y(n)){await l__namespace.writeFile(n,`import { Providers } from './providers';
59
+
47
60
  export default function RootLayout({ children }: { children: React.ReactNode }) {
48
61
  return (
49
62
  <html lang="en">
50
63
  <body>
51
- <UncaughtProvider projectKey="${t}" transport="local">
52
- {children}
53
- </UncaughtProvider>
64
+ <Providers>{children}</Providers>
54
65
  </body>
55
66
  </html>
56
67
  );
57
68
  }
58
- `:o==="pages-app"&&(l=`import { UncaughtProvider } from '@uncaughtdev/react';
69
+ `),console.log(t(x,` \u2713 Created ${d}`));return}let g=await l__namespace.readFile(n,"utf-8");if(g.includes("UncaughtProvider")||g.includes("@uncaughtdev/react")||g.includes("./providers")){console.log(t(v,` \u2298 ${d} already has providers, skipping`));return}g=T(g,`import { Providers } from './providers';
70
+ `);let f=false,c=g.match(/(\n(\s*))\{children\}/);c&&(g=g.replace(`${c[1]}{children}`,`${c[1]}<Providers>{children}</Providers>`),f=true),f?(await l__namespace.writeFile(n,g),console.log(t(x,` \u2713 Patched ${d}`))):console.log(t(v,` \u26A0 Could not auto-patch ${d}. Import Providers from './providers' and wrap {children}.`));}async function R(e,n,o){let s=process.cwd(),a=i__namespace.relative(s,e);if(!await y(e)){let c="";o==="pages-app"&&(c=`import { UncaughtProvider } from '@uncaughtdev/react';
59
71
  import type { AppProps } from 'next/app';
60
72
 
61
73
  export default function App({ Component, pageProps }: AppProps) {
62
74
  return (
63
- <UncaughtProvider projectKey="${t}" transport="local">
75
+ <UncaughtProvider projectKey="${n}" transport="local">
64
76
  <Component {...pageProps} />
65
77
  </UncaughtProvider>
66
78
  );
67
79
  }
68
- `),await c__namespace.writeFile(e,l),console.log(n(x,` \u2713 Created ${i}`));return}let a=await c__namespace.readFile(e,"utf-8");if(a.includes("UncaughtProvider")||a.includes("@uncaughtdev/react")){console.log(n(m,` \u2298 ${i} already has UncaughtProvider, skipping`));return}o==="layout"&&!a.includes("'use client'")&&!a.includes('"use client"')&&(a=`'use client';
69
-
70
- ${a}`),a=z(a,`import { UncaughtProvider } from '@uncaughtdev/react';
71
- `);let u=`<UncaughtProvider projectKey="${t}" transport="${o==="entry"?"console":"local"}">`,d="</UncaughtProvider>",g=false;if(o==="layout"&&a.includes("{children}")){let l=a.match(/(\n(\s*))\{children\}/);if(l){l[2];a=a.replace(`${l[1]}{children}`,`${l[1]}${u}${l[1]} {children}${l[1]}${d}`);}else a=a.replace("{children}",`
72
- ${u}
73
- {children}
74
- ${d}
75
- `);g=true;}else if(o==="pages-app"){let l=a.match(/<Component\s[^>]*\/>/);l&&(a=a.replace(l[0],`${u}
76
- ${l[0]}
77
- ${d}`),g=true);}else if(o==="entry"){let l=a.match(/<App\s*\/>/);l&&(a=a.replace(l[0],`${u}
80
+ `),await l__namespace.writeFile(e,c),console.log(t(x,` \u2713 Created ${a}`));return}let r=await l__namespace.readFile(e,"utf-8");if(r.includes("UncaughtProvider")||r.includes("@uncaughtdev/react")){console.log(t(v,` \u2298 ${a} already has UncaughtProvider, skipping`));return}r=T(r,`import { UncaughtProvider } from '@uncaughtdev/react';
81
+ `);let d=`<UncaughtProvider projectKey="${n}" transport="${o==="entry"?"console":"local"}">`,g="</UncaughtProvider>",f=false;if(o==="pages-app"){let c=r.match(/<Component\s[^>]*\/>/);c&&(r=r.replace(c[0],`${d}
82
+ ${c[0]}
83
+ ${g}`),f=true);}else if(o==="entry"){let c=r.match(/<App\s*\/>/);c&&(r=r.replace(c[0],`${d}
78
84
  <App />
79
- ${d}`),g=true);}g?(await c__namespace.writeFile(e,a),console.log(n(x,` \u2713 Patched ${i}`))):(console.log(n(m,` \u26A0 Could not auto-patch ${i}. Wrap your root component with:`)),console.log(n(w,` <UncaughtProvider projectKey="${t}" transport="local">{children}</UncaughtProvider>`)));}async function U(e){let t=["next.config.ts","next.config.mjs","next.config.js"],o=null;for(let p of t){let u=r__namespace.join(e,p);if(await v(u)){o=u;break}}let s=`
85
+ ${g}`),f=true);}f?(await l__namespace.writeFile(e,r),console.log(t(x,` \u2713 Patched ${a}`))):(console.log(t(v,` \u26A0 Could not auto-patch ${a}. Wrap your root component with:`)),console.log(t(w,` <UncaughtProvider projectKey="${n}" transport="local">{children}</UncaughtProvider>`)));}async function A(e){let n=["next.config.ts","next.config.mjs","next.config.js"],o=null;for(let u of n){let d=i__namespace.join(e,u);if(await y(d)){o=d;break}}let s=`
80
86
  webpack: (config, { isServer }) => {
81
87
  if (!isServer) {
82
88
  config.resolve.fallback = { ...config.resolve.fallback, fs: false, path: false, child_process: false };
83
89
  }
84
90
  return config;
85
- },`;if(!o){o=r__namespace.join(e,"next.config.js"),await c__namespace.writeFile(o,`/** @type {import('next').NextConfig} */
91
+ },`;if(!o){o=i__namespace.join(e,"next.config.js"),await l__namespace.writeFile(o,`/** @type {import('next').NextConfig} */
86
92
  const nextConfig = {${s}
87
93
  };
88
94
  module.exports = nextConfig;
89
- `),console.log(n(x," \u2713 Created next.config.js"));return}let i=await c__namespace.readFile(o,"utf-8");if(i.includes("fs: false")){console.log(n(m," \u2298 Already has webpack fallback, skipping"));return}if(i.includes("webpack")){console.log(n(m," \u2298 Has custom webpack \u2014 add manually: config.resolve.fallback = { fs: false, path: false, child_process: false }"));return}let a=i.match(/(const\s+\w+\s*=\s*\{|module\.exports\s*=\s*\{|export\s+default\s*\{)/);if(a&&a.index!==void 0){let p=a.index+a[0].length;i=i.slice(0,p)+s+i.slice(p),await c__namespace.writeFile(o,i),console.log(n(x,` \u2713 Patched ${r__namespace.relative(e,o)}`));}else console.log(n(m," \u26A0 Could not auto-patch. Add webpack fallback for fs/path/child_process manually."));}async function X(){let e=process.argv.slice(2),t=e[0]??"list";switch(t){case "init":case "setup":await Q();break;case "list":case "ls":await L();break;case "show":case "view":{let o=e[1];if(!o){console.error(n(b,`
95
+ `),console.log(t(x," \u2713 Created next.config.js"));return}let a=await l__namespace.readFile(o,"utf-8");if(a.includes("fs: false")){console.log(t(v," \u2298 Already has webpack fallback, skipping"));return}if(a.includes("webpack")){console.log(t(v," \u2298 Has custom webpack \u2014 add manually: config.resolve.fallback = { fs: false, path: false, child_process: false }"));return}let r=a.match(/(const\s+\w+\s*=\s*\{|module\.exports\s*=\s*\{|export\s+default\s*\{)/);if(r&&r.index!==void 0){let u=r.index+r[0].length;a=a.slice(0,u)+s+a.slice(u),await l__namespace.writeFile(o,a),console.log(t(x,` \u2713 Patched ${i__namespace.relative(e,o)}`));}else console.log(t(v," \u26A0 Could not auto-patch. Add webpack fallback for fs/path/child_process manually."));}var se=`<!DOCTYPE html>
96
+ <html lang="en">
97
+ <head>
98
+ <meta charset="utf-8">
99
+ <meta name="viewport" content="width=device-width, initial-scale=1">
100
+ <title>Uncaught Dashboard</title>
101
+ <style>
102
+ * { margin: 0; padding: 0; box-sizing: border-box; }
103
+ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif; background: #0a0a0a; color: #e0e0e0; min-height: 100vh; }
104
+ a { color: #60a5fa; text-decoration: none; }
105
+ code { background: #1e1e2e; padding: 2px 6px; border-radius: 4px; font-size: 0.85em; }
106
+ pre { background: #1e1e2e; padding: 16px; border-radius: 8px; overflow-x: auto; font-size: 0.85em; line-height: 1.5; }
107
+ header { background: #111; border-bottom: 1px solid #222; padding: 16px 24px; display: flex; align-items: center; gap: 16px; }
108
+ header h1 { font-size: 1.2rem; font-weight: 600; }
109
+ header h1 span { color: #f87171; }
110
+ .stats { display: flex; gap: 24px; margin-left: auto; font-size: 0.85rem; color: #888; }
111
+ .stats .stat-val { color: #e0e0e0; font-weight: 600; }
112
+ .filters { display: flex; gap: 8px; padding: 16px 24px; border-bottom: 1px solid #1a1a1a; }
113
+ .filter-btn { background: #1a1a1a; border: 1px solid #333; color: #aaa; padding: 6px 16px; border-radius: 6px; cursor: pointer; font-size: 0.85rem; transition: all 0.15s; }
114
+ .filter-btn:hover { border-color: #555; color: #e0e0e0; }
115
+ .filter-btn.active { background: #1e3a5f; border-color: #60a5fa; color: #60a5fa; }
116
+ .container { max-width: 1200px; margin: 0 auto; padding: 0 24px; }
117
+ table { width: 100%; border-collapse: collapse; margin-top: 8px; }
118
+ th { text-align: left; padding: 12px 16px; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.05em; color: #666; border-bottom: 1px solid #222; }
119
+ td { padding: 12px 16px; border-bottom: 1px solid #1a1a1a; font-size: 0.9rem; vertical-align: top; }
120
+ tr { cursor: pointer; transition: background 0.1s; }
121
+ tr:hover { background: #141414; }
122
+ tr.selected { background: #1a1a2e; }
123
+ .badge { display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 0.75rem; font-weight: 600; text-transform: uppercase; }
124
+ .badge-open { background: #3b1111; color: #f87171; }
125
+ .badge-resolved { background: #0f2f1a; color: #4ade80; }
126
+ .badge-ignored { background: #2d2305; color: #facc15; }
127
+ .badge-release { background: #1e1e3e; color: #a78bfa; font-size: 0.7rem; margin-left: 6px; }
128
+ .badge-env { background: #1a2e1a; color: #86efac; font-size: 0.7rem; margin-left: 4px; }
129
+ .env-filter { background: #1a1a1a; border: 1px solid #333; color: #aaa; padding: 6px 12px; border-radius: 6px; font-size: 0.85rem; margin-left: 8px; }
130
+ .feedback-box { background: #1a1a2e; border: 1px solid #2e2e5c; border-radius: 8px; padding: 12px 16px; margin-top: 8px; font-style: italic; color: #c4b5fd; }
131
+ .count { background: #1e1e2e; padding: 2px 8px; border-radius: 10px; font-size: 0.8rem; font-weight: 600; }
132
+ .error-type { color: #f87171; font-weight: 500; font-size: 0.8rem; }
133
+ .error-title { color: #e0e0e0; }
134
+ .time-ago { color: #666; font-size: 0.8rem; }
135
+ .empty { text-align: center; padding: 80px 24px; color: #555; }
136
+ .empty h2 { font-size: 1.2rem; margin-bottom: 8px; color: #666; }
137
+
138
+ /* Detail panel */
139
+ .detail-overlay { display: none; position: fixed; top: 0; right: 0; bottom: 0; width: 55%; background: #111; border-left: 1px solid #222; overflow-y: auto; z-index: 100; box-shadow: -4px 0 24px rgba(0,0,0,0.5); }
140
+ .detail-overlay.open { display: block; }
141
+ .detail-header { padding: 20px 24px; border-bottom: 1px solid #222; display: flex; align-items: center; gap: 12px; }
142
+ .detail-header h2 { font-size: 1rem; flex: 1; }
143
+ .close-btn { background: none; border: 1px solid #333; color: #aaa; padding: 4px 12px; border-radius: 4px; cursor: pointer; font-size: 0.85rem; }
144
+ .close-btn:hover { border-color: #666; color: #fff; }
145
+ .detail-body { padding: 24px; }
146
+ .detail-section { margin-bottom: 24px; }
147
+ .detail-section h3 { font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.05em; color: #666; margin-bottom: 8px; }
148
+ .detail-meta { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; }
149
+ .meta-item { background: #1a1a1a; padding: 12px; border-radius: 6px; }
150
+ .meta-label { font-size: 0.7rem; text-transform: uppercase; color: #666; margin-bottom: 4px; }
151
+ .meta-value { font-size: 0.9rem; }
152
+ .breadcrumbs { list-style: none; }
153
+ .breadcrumbs li { padding: 6px 0; border-bottom: 1px solid #1a1a1a; font-size: 0.85rem; display: flex; gap: 8px; }
154
+ .bc-time { color: #666; font-family: monospace; font-size: 0.8rem; min-width: 60px; }
155
+ .bc-type { color: #60a5fa; font-size: 0.75rem; font-weight: 600; min-width: 70px; }
156
+ .action-bar { display: flex; gap: 8px; padding: 16px 24px; border-top: 1px solid #222; position: sticky; bottom: 0; background: #111; }
157
+ .action-btn { padding: 8px 16px; border-radius: 6px; border: 1px solid #333; cursor: pointer; font-size: 0.85rem; transition: all 0.15s; }
158
+ .btn-resolve { background: #0f2f1a; color: #4ade80; border-color: #1a5c2e; }
159
+ .btn-resolve:hover { background: #1a5c2e; }
160
+ .btn-ignore { background: #2d2305; color: #facc15; border-color: #5c4a0a; }
161
+ .btn-ignore:hover { background: #5c4a0a; }
162
+ .btn-copy { background: #1a1a2e; color: #818cf8; border-color: #2e2e5c; }
163
+ .btn-copy:hover { background: #2e2e5c; }
164
+ .btn-open { background: #1e3a5f; color: #60a5fa; border-color: #2563eb; }
165
+ .btn-open:hover { background: #2563eb; }
166
+
167
+ /* Fix prompt box */
168
+ .prompt-box { position: relative; background: #0d0d0d; border: 1px solid #222; border-radius: 8px; margin-bottom: 24px; }
169
+ .prompt-header { display: flex; align-items: center; justify-content: space-between; padding: 10px 16px; border-bottom: 1px solid #222; }
170
+ .prompt-header h3 { font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.05em; color: #666; margin: 0; }
171
+ .prompt-copy-btn { background: #1a1a2e; border: 1px solid #2e2e5c; color: #818cf8; padding: 4px 12px; border-radius: 4px; cursor: pointer; font-size: 0.75rem; display: flex; align-items: center; gap: 4px; transition: all 0.15s; }
172
+ .prompt-copy-btn:hover { background: #2e2e5c; }
173
+ .prompt-copy-btn svg { width: 14px; height: 14px; }
174
+ .prompt-content { padding: 16px; max-height: 300px; overflow-y: auto; font-size: 0.85rem; line-height: 1.5; white-space: pre-wrap; font-family: 'SF Mono', 'Fira Code', monospace; color: #ccc; }
175
+
176
+ /* Fix prompt markdown (expanded view) */
177
+ .fix-prompt { background: #0d0d0d; border: 1px solid #222; border-radius: 8px; padding: 20px; line-height: 1.6; }
178
+ .fix-prompt h1, .fix-prompt h2, .fix-prompt h3 { color: #e0e0e0; margin: 16px 0 8px; }
179
+ .fix-prompt h1 { font-size: 1.2rem; }
180
+ .fix-prompt h2 { font-size: 1rem; border-bottom: 1px solid #222; padding-bottom: 6px; }
181
+ .fix-prompt h3 { font-size: 0.9rem; }
182
+ .fix-prompt ul, .fix-prompt ol { padding-left: 20px; margin: 8px 0; }
183
+ .fix-prompt li { margin: 4px 0; }
184
+ .fix-prompt strong { color: #f0f0f0; }
185
+ .fix-prompt p { margin: 8px 0; }
186
+ </style>
187
+ </head>
188
+ <body>
189
+ <header>
190
+ <h1><span>uncaught</span> dashboard</h1>
191
+ <div class="stats" id="stats"></div>
192
+ </header>
193
+ <div class="filters" id="filters">
194
+ <button class="filter-btn active" data-filter="all">All</button>
195
+ <button class="filter-btn" data-filter="open">Open</button>
196
+ <button class="filter-btn" data-filter="resolved">Resolved</button>
197
+ <button class="filter-btn" data-filter="ignored">Ignored</button>
198
+ <select class="env-filter" id="env-filter">
199
+ <option value="">All Environments</option>
200
+ </select>
201
+ </div>
202
+ <div class="container">
203
+ <table>
204
+ <thead>
205
+ <tr><th>#</th><th>Status</th><th>Error</th><th>Release</th><th>Count</th><th>Users</th><th>Last Seen</th></tr>
206
+ </thead>
207
+ <tbody id="issues-body"></tbody>
208
+ </table>
209
+ <div class="empty" id="empty" style="display:none;">
210
+ <h2>No issues found</h2>
211
+ <p>Trigger some errors in your app and they will appear here.</p>
212
+ </div>
213
+ </div>
214
+ <div class="detail-overlay" id="detail">
215
+ <div class="detail-header">
216
+ <h2 id="detail-title"></h2>
217
+ <button class="close-btn" id="close-detail">Close</button>
218
+ </div>
219
+ <div class="detail-body" id="detail-body"></div>
220
+ <div class="action-bar" id="action-bar"></div>
221
+ </div>
222
+ <script>
223
+ let allIssues = [];
224
+ let currentFilter = 'all';
225
+ let currentEnv = '';
226
+ let selectedFp = null;
227
+
228
+ async function fetchIssues() {
229
+ try {
230
+ var params = [];
231
+ if (currentFilter !== 'all') params.push('status=' + currentFilter);
232
+ if (currentEnv) params.push('environment=' + encodeURIComponent(currentEnv));
233
+ var url = '/api/issues' + (params.length ? '?' + params.join('&') : '');
234
+ const res = await fetch(url);
235
+ allIssues = await res.json();
236
+ renderIssues();
237
+ fetchStats();
238
+ updateEnvFilter();
239
+ } catch(e) { console.error('Failed to fetch issues', e); }
240
+ }
241
+
242
+ function updateEnvFilter() {
243
+ var sel = document.getElementById('env-filter');
244
+ var envs = new Set();
245
+ allIssues.forEach(function(i) { if (i.environment) envs.add(i.environment); });
246
+ var opts = '<option value="">All Environments</option>';
247
+ envs.forEach(function(e) { opts += '<option value="' + escHtml(e) + '"' + (e === currentEnv ? ' selected' : '') + '>' + escHtml(e) + '</option>'; });
248
+ sel.innerHTML = opts;
249
+ }
250
+
251
+ async function fetchStats() {
252
+ try {
253
+ const res = await fetch('/api/stats');
254
+ const s = await res.json();
255
+ document.getElementById('stats').innerHTML =
256
+ '<div><span class="stat-val">' + s.total + '</span> issues</div>' +
257
+ '<div><span class="stat-val">' + s.open + '</span> open</div>' +
258
+ '<div><span class="stat-val">' + s.totalEvents + '</span> events</div>';
259
+ } catch(e) {}
260
+ }
261
+
262
+ function timeAgo(iso) {
263
+ const ms = Date.now() - new Date(iso).getTime();
264
+ if (ms < 0) return 'just now';
265
+ const s = Math.floor(ms/1000);
266
+ if (s < 60) return s + 's ago';
267
+ const m = Math.floor(s/60);
268
+ if (m < 60) return m + 'm ago';
269
+ const h = Math.floor(m/60);
270
+ if (h < 24) return h + 'h ago';
271
+ const d = Math.floor(h/24);
272
+ if (d < 30) return d + 'd ago';
273
+ return new Date(iso).toLocaleDateString();
274
+ }
275
+
276
+ function escHtml(s) { const d = document.createElement('div'); d.textContent = s; return d.innerHTML; }
277
+
278
+ function renderIssues() {
279
+ const body = document.getElementById('issues-body');
280
+ const empty = document.getElementById('empty');
281
+ if (allIssues.length === 0) { body.innerHTML = ''; empty.style.display = 'block'; return; }
282
+ empty.style.display = 'none';
283
+ body.innerHTML = allIssues.map(function(issue, i) {
284
+ const cls = issue.status === 'open' ? 'badge-open' : issue.status === 'resolved' ? 'badge-resolved' : 'badge-ignored';
285
+ var relBadge = issue.release ? '<span class="badge badge-release">' + escHtml(issue.release) + '</span>' : '<span style="color:#555">\u2014</span>';
286
+ var envBadge = issue.environment ? '<span class="badge badge-env">' + escHtml(issue.environment) + '</span>' : '';
287
+ return '<tr data-fp="' + issue.fingerprint + '" class="' + (issue.fingerprint === selectedFp ? 'selected' : '') + '">' +
288
+ '<td>' + (i+1) + '</td>' +
289
+ '<td><span class="badge ' + cls + '">' + issue.status + '</span>' + envBadge + '</td>' +
290
+ '<td><span class="error-type">' + escHtml(issue.errorType) + '</span> <span class="error-title">' + escHtml(issue.title.length > 60 ? issue.title.slice(0,57) + '...' : issue.title) + '</span></td>' +
291
+ '<td>' + relBadge + '</td>' +
292
+ '<td><span class="count">' + issue.count + '</span></td>' +
293
+ '<td>' + issue.affectedUsers.length + '</td>' +
294
+ '<td class="time-ago">' + timeAgo(issue.lastSeen) + '</td>' +
295
+ '</tr>';
296
+ }).join('');
297
+ }
298
+
299
+ function renderMd(md) {
300
+ return md
301
+ .replace(/^### (.+)$/gm, '<h3>$1</h3>')
302
+ .replace(/^## (.+)$/gm, '<h2>$1</h2>')
303
+ .replace(/^# (.+)$/gm, '<h1>$1</h1>')
304
+ .replace(/\\*\\*(.+?)\\*\\*/g, '<strong>$1</strong>')
305
+ .replace(/\`\`\`[\\s\\S]*?\`\`\`/g, function(m) {
306
+ var code = m.replace(/\`\`\`\\w*\\n?/g, '').replace(/\`\`\`$/g, '');
307
+ return '<pre><code>' + escHtml(code) + '</code></pre>';
308
+ })
309
+ .replace(/\`([^\`]+)\`/g, '<code>$1</code>')
310
+ .replace(/^- \\*\\*(.+?)\\*\\* ?\u2014 ?(.+)$/gm, '<li><strong>$1</strong> \u2014 $2</li>')
311
+ .replace(/^- (.+)$/gm, '<li>$1</li>')
312
+ .replace(/^(\\d+)\\. (.+)$/gm, '<li>$2</li>')
313
+ .replace(/(<li>.*<\\/li>)/s, '<ul>$1</ul>')
314
+ .replace(/\\n\\n/g, '</p><p>')
315
+ .replace(/\\n/g, '<br>');
316
+ }
317
+
318
+ async function showDetail(fp) {
319
+ selectedFp = fp;
320
+ renderIssues();
321
+ try {
322
+ const res = await fetch('/api/issues/' + fp);
323
+ const data = await res.json();
324
+ const issue = data.issue;
325
+ const event = data.event;
326
+
327
+ document.getElementById('detail-title').textContent = issue.errorType + ': ' + issue.title;
328
+
329
+ let html = '';
330
+
331
+ if (event) {
332
+ // Fix prompt \u2014 first, compact box with copy icon
333
+ if (event.fixPrompt) {
334
+ html += '<div class="prompt-box">';
335
+ html += '<div class="prompt-header"><h3>Fix Prompt</h3>';
336
+ html += '<button class="prompt-copy-btn" onclick="copyPrompt()">';
337
+ html += '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>';
338
+ html += '<span id="copy-label">Copy</span></button></div>';
339
+ html += '<div class="prompt-content">' + escHtml(event.fixPrompt) + '</div>';
340
+ html += '</div>';
341
+ }
342
+ }
343
+
344
+ // Meta
345
+ html += '<div class="detail-section"><h3>Details</h3><div class="detail-meta">';
346
+ html += '<div class="meta-item"><div class="meta-label">Fingerprint</div><div class="meta-value"><code>' + issue.fingerprint + '</code></div></div>';
347
+ html += '<div class="meta-item"><div class="meta-label">Occurrences</div><div class="meta-value">' + issue.count + '</div></div>';
348
+ html += '<div class="meta-item"><div class="meta-label">Users Affected</div><div class="meta-value">' + issue.affectedUsers.length + '</div></div>';
349
+ html += '<div class="meta-item"><div class="meta-label">First Seen</div><div class="meta-value">' + timeAgo(issue.firstSeen) + '</div></div>';
350
+ html += '<div class="meta-item"><div class="meta-label">Last Seen</div><div class="meta-value">' + timeAgo(issue.lastSeen) + '</div></div>';
351
+ html += '<div class="meta-item"><div class="meta-label">Status</div><div class="meta-value"><span class="badge badge-' + issue.status + '">' + issue.status + '</span></div></div>';
352
+ if (issue.release) html += '<div class="meta-item"><div class="meta-label">Release</div><div class="meta-value"><span class="badge badge-release">' + escHtml(issue.release) + '</span></div></div>';
353
+ if (issue.environment) html += '<div class="meta-item"><div class="meta-label">Environment</div><div class="meta-value"><span class="badge badge-env">' + escHtml(issue.environment) + '</span></div></div>';
354
+ html += '</div></div>';
355
+
356
+ if (event) {
357
+ // User feedback
358
+ if (event.userFeedback) {
359
+ html += '<div class="detail-section"><h3>User Feedback</h3><div class="feedback-box">"' + escHtml(event.userFeedback) + '"</div></div>';
360
+ }
361
+
362
+ // Stack trace (prefer resolved)
363
+ var stackLabel = 'Stack Trace';
364
+ var stackContent = '';
365
+ if (event.error && event.error.resolvedStack) {
366
+ stackLabel = 'Stack Trace (Source Mapped)';
367
+ stackContent = event.error.resolvedStack;
368
+ } else if (event.error && event.error.stack) {
369
+ stackContent = event.error.stack;
370
+ }
371
+ if (stackContent) {
372
+ html += '<div class="detail-section"><h3>' + stackLabel + '</h3><pre><code>' + escHtml(stackContent) + '</code></pre></div>';
373
+ }
374
+
375
+ // Environment
376
+ if (event.environment) {
377
+ const env = event.environment;
378
+ html += '<div class="detail-section"><h3>Environment</h3><div class="detail-meta">';
379
+ if (env.deploy) html += '<div class="meta-item"><div class="meta-label">Deploy Env</div><div class="meta-value">' + escHtml(env.deploy) + '</div></div>';
380
+ if (env.browser) html += '<div class="meta-item"><div class="meta-label">Browser</div><div class="meta-value">' + escHtml(env.browser + (env.browserVersion ? ' ' + env.browserVersion : '')) + '</div></div>';
381
+ if (env.os) html += '<div class="meta-item"><div class="meta-label">OS</div><div class="meta-value">' + escHtml(env.os) + '</div></div>';
382
+ if (env.runtime) html += '<div class="meta-item"><div class="meta-label">Runtime</div><div class="meta-value">' + escHtml(env.runtime) + '</div></div>';
383
+ if (env.url) html += '<div class="meta-item"><div class="meta-label">URL</div><div class="meta-value">' + escHtml(env.url) + '</div></div>';
384
+ if (env.deviceType) html += '<div class="meta-item"><div class="meta-label">Device</div><div class="meta-value">' + escHtml(env.deviceType) + '</div></div>';
385
+ html += '</div></div>';
386
+ }
387
+
388
+ // Breadcrumbs
389
+ if (event.breadcrumbs && event.breadcrumbs.length > 0) {
390
+ html += '<div class="detail-section"><h3>Breadcrumbs</h3><ul class="breadcrumbs">';
391
+ event.breadcrumbs.forEach(function(bc) {
392
+ var t = bc.timestamp ? new Date(bc.timestamp).toLocaleTimeString() : '';
393
+ html += '<li><span class="bc-time">' + t + '</span><span class="bc-type">[' + escHtml(bc.type) + ']</span><span>' + escHtml(bc.message) + '</span></li>';
394
+ });
395
+ html += '</ul></div>';
396
+ }
397
+ }
398
+
399
+ document.getElementById('detail-body').innerHTML = html;
400
+
401
+ // Action bar
402
+ let actions = '';
403
+ if (issue.status !== 'resolved') actions += '<button class="action-btn btn-resolve" onclick="updateStatus(\\'' + fp + '\\', \\'resolved\\')">Mark Resolved</button>';
404
+ if (issue.status !== 'ignored') actions += '<button class="action-btn btn-ignore" onclick="updateStatus(\\'' + fp + '\\', \\'ignored\\')">Mark Ignored</button>';
405
+ if (issue.status !== 'open') actions += '<button class="action-btn btn-open" onclick="updateStatus(\\'' + fp + '\\', \\'open\\')">Reopen</button>';
406
+ document.getElementById('action-bar').innerHTML = actions;
407
+
408
+ document.getElementById('detail').classList.add('open');
409
+ window._currentFixPrompt = event ? event.fixPrompt : '';
410
+ } catch(e) { console.error('Failed to load detail', e); }
411
+ }
412
+
413
+ async function updateStatus(fp, status) {
414
+ try {
415
+ await fetch('/api/issues/' + fp, { method: 'PATCH', headers: {'Content-Type':'application/json'}, body: JSON.stringify({status:status}) });
416
+ fetchIssues();
417
+ showDetail(fp);
418
+ } catch(e) { console.error('Failed to update', e); }
419
+ }
420
+
421
+ function copyPrompt() {
422
+ if (window._currentFixPrompt) {
423
+ navigator.clipboard.writeText(window._currentFixPrompt).then(function() {
424
+ var label = document.getElementById('copy-label');
425
+ if (label) { label.textContent = 'Copied!'; setTimeout(function(){ label.textContent = 'Copy'; }, 2000); }
426
+ });
427
+ }
428
+ }
429
+
430
+ // Event delegation
431
+ document.getElementById('issues-body').addEventListener('click', function(e) {
432
+ var tr = e.target.closest('tr');
433
+ if (tr && tr.dataset.fp) showDetail(tr.dataset.fp);
434
+ });
435
+
436
+ document.getElementById('close-detail').addEventListener('click', function() {
437
+ document.getElementById('detail').classList.remove('open');
438
+ selectedFp = null;
439
+ renderIssues();
440
+ });
441
+
442
+ document.getElementById('filters').addEventListener('click', function(e) {
443
+ var btn = e.target.closest('.filter-btn');
444
+ if (!btn) return;
445
+ document.querySelectorAll('.filter-btn').forEach(function(b){ b.classList.remove('active'); });
446
+ btn.classList.add('active');
447
+ currentFilter = btn.dataset.filter;
448
+ fetchIssues();
449
+ });
450
+
451
+ document.getElementById('env-filter').addEventListener('change', function(e) {
452
+ currentEnv = e.target.value;
453
+ fetchIssues();
454
+ });
455
+
456
+ // Close on Escape
457
+ document.addEventListener('keydown', function(e) {
458
+ if (e.key === 'Escape') {
459
+ document.getElementById('detail').classList.remove('open');
460
+ selectedFp = null;
461
+ renderIssues();
462
+ }
463
+ });
464
+
465
+ // Initial load + auto-refresh
466
+ fetchIssues();
467
+ setInterval(fetchIssues, 5000);
468
+ </script>
469
+ </body>
470
+ </html>`;async function ae(e){let n=P();await l__namespace.mkdir(n,{recursive:true});let o;try{o=E();}catch(a){console.error(t(k,`
471
+ Failed to open database:`),a),process.exitCode=1;return}let s=L__namespace.createServer(async(a,r)=>{let u=new URL(a.url,`http://localhost:${e}`),d=u.pathname;if(r.setHeader("Access-Control-Allow-Origin","*"),r.setHeader("Access-Control-Allow-Methods","GET, PATCH, DELETE, OPTIONS"),r.setHeader("Access-Control-Allow-Headers","Content-Type"),a.method==="OPTIONS"){r.writeHead(204),r.end();return}if(d==="/"||d==="/index.html"){r.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),r.end(se);return}try{if(d==="/api/issues"&&a.method==="GET"){let c=u.searchParams.get("status"),m=u.searchParams.get("environment")||void 0,p={};c&&(p.status=c),m&&(p.environment=m);let j=Object.keys(p).length>0?o.getIssues(p):o.getIssues();r.writeHead(200,{"Content-Type":"application/json"}),r.end(JSON.stringify(j));return}if(d==="/api/stats"&&a.method==="GET"){let c=o.getStats();r.writeHead(200,{"Content-Type":"application/json"}),r.end(JSON.stringify(c));return}let g=d.match(/^\/api\/issues\/([a-f0-9]+)$/),f=d.match(/^\/api\/issues\/([a-f0-9]+)\/events$/);if(f&&a.method==="GET"){let c=f[1],m=parseInt(u.searchParams.get("limit")??"20",10),p=parseInt(u.searchParams.get("offset")??"0",10),j=o.getEvents(c,{limit:m,offset:p});r.writeHead(200,{"Content-Type":"application/json"}),r.end(JSON.stringify(j));return}if(g&&a.method==="GET"){let c=g[1],m=o.getIssue(c);if(!m){r.writeHead(404,{"Content-Type":"application/json"}),r.end(JSON.stringify({error:"Issue not found"}));return}let p=o.getLatestEvent(c);r.writeHead(200,{"Content-Type":"application/json"}),r.end(JSON.stringify({issue:m,event:p??null}));return}if(g&&a.method==="PATCH"){let c=g[1],m=await re(a),{status:p}=JSON.parse(m);o.updateIssueStatus(c,p),r.writeHead(200,{"Content-Type":"application/json"}),r.end(JSON.stringify({ok:!0}));return}if(d==="/api/issues"&&a.method==="DELETE"){o.deleteAllIssues(),r.writeHead(200,{"Content-Type":"application/json"}),r.end(JSON.stringify({ok:!0}));return}}catch(g){r.writeHead(500,{"Content-Type":"application/json"}),r.end(JSON.stringify({error:String(g)}));return}r.writeHead(404),r.end("Not found");});s.on("error",a=>{a.code==="EADDRINUSE"?(console.error(t(k,`
472
+ Port ${e} is already in use. Try: npx @uncaughtdev/core dashboard --port ${e+1}
473
+ `)),process.exitCode=1):(console.error(t(k,`
474
+ Server error:`),a),process.exitCode=1);}),s.listen(e,()=>{console.log(""),console.log(t($," uncaught dashboard")),console.log(t(h," \u2500".repeat(35))),console.log(""),console.log(` ${t(x,"\u25CF")} Running at ${t(b,`http://localhost:${e}`)}`),console.log(""),console.log(t(h," Press Ctrl+C to stop")),console.log("");let a=process.platform==="darwin"?"open":process.platform==="win32"?"start":"xdg-open";try{child_process.spawn(a,[`http://localhost:${e}`],{detached:!0,stdio:"ignore"}).unref();}catch{}}),process.on("SIGINT",()=>{console.log(t(h,`
475
+ Shutting down...`)),o.close(),s.close(),process.exit(0);});}function re(e){return new Promise((n,o)=>{let s="";e.on("data",a=>{s+=a;}),e.on("end",()=>n(s)),e.on("error",o);})}async function ie(){let e=process.argv.slice(2),n=e[0]??"list";switch(n){case "init":case "setup":await ne();break;case "list":case "ls":await _();break;case "show":case "view":{let o=e[1];if(!o){console.error(t(k,`
90
476
  Missing issue number. Usage: uncaught show <n>
91
- `)),process.exitCode=1;return}let s=e.includes("--open")||e.includes("-o");await _(o,s);break}case "resolve":{let o=e[1];if(!o){console.error(n(b,`
477
+ `)),process.exitCode=1;return}let s=e.includes("--open")||e.includes("-o");await V(o,s);break}case "resolve":{let o=e[1];if(!o){console.error(t(k,`
92
478
  Missing issue number. Usage: uncaught resolve <n>
93
- `)),process.exitCode=1;return}await G(o);break}case "clear":case "clean":await W();break;case "help":case "--help":case "-h":R();break;default:console.error(n(b,`
94
- Unknown command: ${t}`)),R(),process.exitCode=1;break}}X().catch(e=>{console.error(n(b,`
479
+ `)),process.exitCode=1;return}await Y(o);break}case "clear":case "clean":await W();break;case "dashboard":case "dash":case "ui":{let o=e.indexOf("--port"),s=o>=0&&parseInt(e[o+1],10)||3300;await ae(s);break}case "help":case "--help":case "-h":U();break;default:console.error(t(k,`
480
+ Unknown command: ${n}`)),U(),process.exitCode=1;break}}ie().catch(e=>{console.error(t(k,`
95
481
  Unexpected error:`),e),process.exitCode=1;});//# sourceMappingURL=local-viewer.js.map
96
482
  //# sourceMappingURL=local-viewer.js.map