@minimalcorp/tsunagi 0.1.38 → 0.1.39

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 (127) hide show
  1. package/.next/standalone/apps/web/.next/BUILD_ID +1 -1
  2. package/.next/standalone/apps/web/.next/build-manifest.json +5 -5
  3. package/.next/standalone/apps/web/.next/prerender-manifest.json +3 -3
  4. package/.next/standalone/apps/web/.next/server/app/_global-error/page/build-manifest.json +2 -2
  5. package/.next/standalone/apps/web/.next/server/app/_global-error.html +1 -1
  6. package/.next/standalone/apps/web/.next/server/app/_global-error.rsc +1 -1
  7. package/.next/standalone/apps/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  8. package/.next/standalone/apps/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  9. package/.next/standalone/apps/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  10. package/.next/standalone/apps/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  11. package/.next/standalone/apps/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  12. package/.next/standalone/apps/web/.next/server/app/_not-found/page/build-manifest.json +2 -2
  13. package/.next/standalone/apps/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  14. package/.next/standalone/apps/web/.next/server/app/_not-found.html +1 -1
  15. package/.next/standalone/apps/web/.next/server/app/_not-found.rsc +2 -2
  16. package/.next/standalone/apps/web/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  17. package/.next/standalone/apps/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  18. package/.next/standalone/apps/web/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  19. package/.next/standalone/apps/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  20. package/.next/standalone/apps/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  21. package/.next/standalone/apps/web/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  22. package/.next/standalone/apps/web/.next/server/app/index.html +1 -1
  23. package/.next/standalone/apps/web/.next/server/app/index.rsc +3 -3
  24. package/.next/standalone/apps/web/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  25. package/.next/standalone/apps/web/.next/server/app/index.segments/_full.segment.rsc +3 -3
  26. package/.next/standalone/apps/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
  27. package/.next/standalone/apps/web/.next/server/app/index.segments/_index.segment.rsc +2 -2
  28. package/.next/standalone/apps/web/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  29. package/.next/standalone/apps/web/.next/server/app/page/build-manifest.json +2 -2
  30. package/.next/standalone/apps/web/.next/server/app/page.js.nft.json +1 -1
  31. package/.next/standalone/apps/web/.next/server/app/page_client-reference-manifest.js +1 -1
  32. package/.next/standalone/apps/web/.next/server/app/settings/page/build-manifest.json +2 -2
  33. package/.next/standalone/apps/web/.next/server/app/settings/page.js.nft.json +1 -1
  34. package/.next/standalone/apps/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  35. package/.next/standalone/apps/web/.next/server/app/settings.html +1 -1
  36. package/.next/standalone/apps/web/.next/server/app/settings.rsc +3 -3
  37. package/.next/standalone/apps/web/.next/server/app/settings.segments/_full.segment.rsc +3 -3
  38. package/.next/standalone/apps/web/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  39. package/.next/standalone/apps/web/.next/server/app/settings.segments/_index.segment.rsc +2 -2
  40. package/.next/standalone/apps/web/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  41. package/.next/standalone/apps/web/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +2 -2
  42. package/.next/standalone/apps/web/.next/server/app/settings.segments/settings.segment.rsc +1 -1
  43. package/.next/standalone/apps/web/.next/server/app/tasks/[id]/page/build-manifest.json +2 -2
  44. package/.next/standalone/apps/web/.next/server/app/tasks/[id]/page.js.nft.json +1 -1
  45. package/.next/standalone/apps/web/.next/server/app/tasks/[id]/page_client-reference-manifest.js +1 -1
  46. package/.next/standalone/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0nhzci6._.js +4 -8
  47. package/.next/standalone/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0vi01rl._.js +4 -8
  48. package/.next/standalone/apps/web/.next/server/chunks/ssr/{[root-of-the-server]__04g~n~m._.js → [root-of-the-server]__0zf09ry._.js} +2 -2
  49. package/.next/standalone/apps/web/.next/server/chunks/ssr/_04l3mh~._.js +10 -0
  50. package/.next/standalone/apps/web/.next/server/chunks/ssr/_0bt-4.4._.js +3 -0
  51. package/.next/standalone/apps/web/.next/server/chunks/ssr/_0e3431w._.js +10 -0
  52. package/.next/standalone/apps/web/.next/server/chunks/ssr/_0g.cd6a._.js +1 -1
  53. package/.next/standalone/apps/web/.next/server/chunks/ssr/_0lirkqp._.js +10 -0
  54. package/.next/standalone/apps/web/.next/server/chunks/ssr/_0soxqr.._.js +3 -0
  55. package/.next/standalone/apps/web/.next/server/chunks/ssr/apps_web_src_app_settings_page_tsx_0i6itlb._.js +1 -1
  56. package/.next/standalone/apps/web/.next/server/chunks/ssr/apps_web_src_app_tasks_[id]_page_tsx_0jshsm2._.js +4 -5
  57. package/.next/standalone/apps/web/.next/server/chunks/ssr/{node_modules_0h0imx2._.js → node_modules_0_4__2k._.js} +1 -1
  58. package/.next/standalone/apps/web/.next/server/chunks/ssr/{node_modules_0pbr55t._.js → node_modules_0bqsyfk._.js} +1 -1
  59. package/.next/standalone/apps/web/.next/server/chunks/ssr/{node_modules_06vr-0a._.js → node_modules_0bzw~9d._.js} +1 -1
  60. package/.next/standalone/apps/web/.next/server/chunks/ssr/{node_modules_0k7u4.c._.js → node_modules_0fsewd2._.js} +1 -1
  61. package/.next/standalone/apps/web/.next/server/chunks/ssr/{node_modules_0c6z_cw._.js → node_modules_0l~40og._.js} +1 -1
  62. package/.next/standalone/apps/web/.next/server/chunks/ssr/{node_modules_0jo-w3s._.js → node_modules_0pk6e0.._.js} +1 -1
  63. package/.next/standalone/apps/web/.next/server/chunks/ssr/{node_modules_0zkg-x0._.js → node_modules_0smdx~2._.js} +1 -1
  64. package/.next/standalone/apps/web/.next/server/chunks/ssr/{node_modules_0fcqekz._.js → node_modules_0uej915._.js} +1 -1
  65. package/.next/standalone/apps/web/.next/server/middleware-build-manifest.js +5 -5
  66. package/.next/standalone/apps/web/.next/server/pages/404.html +1 -1
  67. package/.next/standalone/apps/web/.next/server/pages/500.html +1 -1
  68. package/.next/standalone/apps/web/.next/server/server-reference-manifest.js +1 -1
  69. package/.next/standalone/apps/web/.next/server/server-reference-manifest.json +1 -1
  70. package/.next/standalone/apps/web/.next/static/chunks/{0p.4ej_8gk7m7.js → 02.u6zk77a338.js} +10 -11
  71. package/.next/standalone/apps/web/.next/static/chunks/05n6~h_wwg.jj.js +5 -0
  72. package/.next/standalone/apps/web/.next/static/chunks/0_ygv4z~5c_9z.js +5 -0
  73. package/.next/standalone/apps/web/.next/static/chunks/0g5hoj5w-z.~6.js +1 -0
  74. package/.next/standalone/apps/web/.next/static/chunks/0nhcl~svhi_26.js +7 -0
  75. package/.next/standalone/apps/web/.next/static/chunks/0p4dfdgz~3qt3.js +5 -0
  76. package/.next/standalone/apps/web/.next/static/chunks/0p9~lk406udl5.css +4 -0
  77. package/.next/standalone/apps/web/.next/static/chunks/0q-u7bl7oa42n.js +1 -0
  78. package/.next/standalone/apps/web/.next/static/chunks/0q_j4~6_etj_q.js +7 -0
  79. package/.next/standalone/apps/web/.next/static/chunks/0zjymvayyxt-d.js +5 -0
  80. package/.next/standalone/apps/web/.next/static/chunks/{0lp.2eizum8y~.js → 11rs2-0jl1rzr.js} +1 -1
  81. package/.next/standalone/apps/web/.next/static/chunks/{15~pc9ql1ab38.js → 158q94mo2-6sx.js} +7 -7
  82. package/.next/standalone/apps/web/.next/static/chunks/167xa3jy_0g.u.js +1 -0
  83. package/.next/standalone/apps/web/.next/static/chunks/{turbopack-0079niub0zo4u.js → turbopack-07pr2uza0.4cp.js} +1 -1
  84. package/dist/server/basic-auth.js +9 -1
  85. package/dist/server/generated/prisma/internal/class.js +1 -1
  86. package/dist/server/index.js +20 -0
  87. package/dist/server/lib/claude-command.d.ts +6 -0
  88. package/dist/server/lib/claude-command.js +85 -0
  89. package/dist/server/lib/claude-config-guard.d.ts +12 -0
  90. package/dist/server/lib/claude-config-guard.js +49 -0
  91. package/dist/server/lib/lmstudio.d.ts +24 -0
  92. package/dist/server/lib/lmstudio.js +198 -0
  93. package/dist/server/lib/local-llm-env.d.ts +28 -0
  94. package/dist/server/lib/local-llm-env.js +91 -0
  95. package/dist/server/lib/local-llm.d.ts +56 -0
  96. package/dist/server/lib/local-llm.js +366 -0
  97. package/dist/server/lib/ollama-settings.d.ts +16 -10
  98. package/dist/server/lib/ollama-settings.js +104 -91
  99. package/dist/server/lib/searxng.d.ts +26 -0
  100. package/dist/server/lib/searxng.js +308 -0
  101. package/dist/server/routes/local-llm.d.ts +2 -0
  102. package/dist/server/routes/local-llm.js +192 -0
  103. package/dist/server/routes/mcp-web.d.ts +2 -0
  104. package/dist/server/routes/mcp-web.js +107 -0
  105. package/dist/server/routes/onboarding.js +4 -4
  106. package/dist/server/routes/settings.js +100 -26
  107. package/dist/server/routes/tasks.js +5 -1
  108. package/dist/server/routes/terminal.js +53 -11
  109. package/npm-shrinkwrap.json +5 -5
  110. package/package.json +1 -1
  111. package/prisma/schema.prisma +1 -1
  112. package/.next/standalone/apps/web/.next/server/chunks/ssr/_016-lxb._.js +0 -3
  113. package/.next/standalone/apps/web/.next/server/chunks/ssr/_0hh~0f6._.js +0 -3
  114. package/.next/standalone/apps/web/.next/server/chunks/ssr/_0r0xwce._.js +0 -6
  115. package/.next/standalone/apps/web/.next/server/chunks/ssr/_0sbp1da._.js +0 -6
  116. package/.next/standalone/apps/web/.next/server/chunks/ssr/_12c1w~~._.js +0 -6
  117. package/.next/standalone/apps/web/.next/static/chunks/0229rjr88pv9k.js +0 -1
  118. package/.next/standalone/apps/web/.next/static/chunks/04l9g6rg7~-d5.js +0 -1
  119. package/.next/standalone/apps/web/.next/static/chunks/0citvl2medd0s.js +0 -11
  120. package/.next/standalone/apps/web/.next/static/chunks/0e8u7rqrqfiiy.js +0 -1
  121. package/.next/standalone/apps/web/.next/static/chunks/0pg---_6a_4ls.css +0 -4
  122. package/.next/standalone/apps/web/.next/static/chunks/0uv~zl3--e3wo.js +0 -11
  123. package/.next/standalone/apps/web/.next/static/chunks/11rpr3..poyv8.js +0 -5
  124. package/.next/standalone/apps/web/.next/static/chunks/1200zkjn5n2w7.js +0 -1
  125. /package/.next/standalone/apps/web/.next/static/{TJDp2MIqJ14hotMmE5sIo → C1cjF-gU-snY_atxJbn1v}/_buildManifest.js +0 -0
  126. /package/.next/standalone/apps/web/.next/static/{TJDp2MIqJ14hotMmE5sIo → C1cjF-gU-snY_atxJbn1v}/_clientMiddlewareManifest.js +0 -0
  127. /package/.next/standalone/apps/web/.next/static/{TJDp2MIqJ14hotMmE5sIo → C1cjF-gU-snY_atxJbn1v}/_ssgManifest.js +0 -0
@@ -0,0 +1 @@
1
+ (globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,41241,19556,9752,20486,t=>{"use strict";var e=t.i(49915),a=(0,t.i(65485).default)(Object.keys,Object),s=Object.prototype.hasOwnProperty;let i=function(t){if(!(0,e.default)(t))return a(t);var i=[];for(var r in Object(t))s.call(t,r)&&"constructor"!=r&&i.push(r);return i};t.s(["default",0,i],19556);var r=t.i(47244),l=t.i(56176),n=(0,r.default)(l.default,"DataView"),c=t.i(44483),o=(0,r.default)(l.default,"Promise"),u=(0,r.default)(l.default,"Set");t.s(["default",0,u],9752);var d=(0,r.default)(l.default,"WeakMap"),h=t.i(35287),m=t.i(66762),k="[object Map]",p="[object Promise]",g="[object Set]",f="[object WeakMap]",j="[object DataView]",v=(0,m.default)(n),b=(0,m.default)(c.default),y=(0,m.default)(o),x=(0,m.default)(u),w=(0,m.default)(d),P=h.default;(n&&P(new n(new ArrayBuffer(1)))!=j||c.default&&P(new c.default)!=k||o&&P(o.resolve())!=p||u&&P(new u)!=g||d&&P(new d)!=f)&&(P=function(t){var e=(0,h.default)(t),a="[object Object]"==e?t.constructor:void 0,s=a?(0,m.default)(a):"";if(s)switch(s){case v:return j;case b:return k;case y:return p;case x:return g;case w:return f}return e});let q=P;t.s(["default",0,q],20486);var _=t.i(15300),z=t.i(44071),L=t.i(41338),$=t.i(3745),C=t.i(1645),F=Object.prototype.hasOwnProperty;t.s(["default",0,function(t){if(null==t)return!0;if((0,L.default)(t)&&((0,z.default)(t)||"string"==typeof t||"function"==typeof t.splice||(0,$.default)(t)||(0,C.default)(t)||(0,_.default)(t)))return!t.length;var a=q(t);if("[object Map]"==a||"[object Set]"==a)return!t.size;if((0,e.default)(t))return!i(t).length;for(var s in t)if(F.call(t,s))return!1;return!0}],41241)},44917,t=>{"use strict";var e=t.i(96977),a=t.i(71206);t.i(47716);var s=t.i(23685),i=(0,a.__name)(t=>{let{securityLevel:a}=(0,e.getConfig2)(),i=(0,s.select)("body");if("sandbox"===a){let e=(0,s.select)(`#i${t}`),a=e.node()?.contentDocument??document;i=(0,s.select)(a.body)}return i.select(`#${t}`)},"selectSvgElement");t.s(["selectSvgElement",0,i])},3262,t=>{"use strict";var e=t.i(31360),a=t.i(60884),s=t.i(29432),i=t.i(96977),r=t.i(71206),l={common:i.common_default,getConfig:i.getConfig,insertCluster:a.insertCluster,insertEdge:e.insertEdge,insertEdgeLabel:e.insertEdgeLabel,insertMarkers:e.markers_default,insertNode:a.insertNode,interpolateToCurve:s.interpolateToCurve,labelHelper:a.labelHelper,log:r.log,positionEdgeLabel:e.positionEdgeLabel},n={},c=(0,r.__name)(t=>{for(let e of t)n[e.name]=e},"registerLayoutLoaders");(0,r.__name)(()=>{c([{name:"dagre",loader:(0,r.__name)(async()=>await t.A(92568),"loader")},{name:"cose-bilkent",loader:(0,r.__name)(async()=>await t.A(62369),"loader")}])},"registerDefaultLayoutLoaders")();var o=(0,r.__name)(async(t,e)=>{if(!(t.layoutAlgorithm in n))throw Error(`Unknown layout algorithm: ${t.layoutAlgorithm}`);if(t.diagramId)for(let e of t.nodes){let a=e.domId||e.id;e.domId=`${t.diagramId}-${a}`}let a=n[t.layoutAlgorithm],s=await a.loader(),{theme:i,themeVariables:r}=t.config,{useGradient:c,gradientStart:o,gradientStop:u}=r,d=e.attr("id");if(e.append("defs").append("filter").attr("id",`${d}-drop-shadow`).attr("height","130%").attr("width","130%").append("feDropShadow").attr("dx","4").attr("dy","4").attr("stdDeviation",0).attr("flood-opacity","0.06").attr("flood-color",`${i?.includes("dark")?"#FFFFFF":"#000000"}`),e.append("defs").append("filter").attr("id",`${d}-drop-shadow-small`).attr("height","150%").attr("width","150%").append("feDropShadow").attr("dx","2").attr("dy","2").attr("stdDeviation",0).attr("flood-opacity","0.06").attr("flood-color",`${i?.includes("dark")?"#FFFFFF":"#000000"}`),c){let t=e.append("linearGradient").attr("id",e.attr("id")+"-gradient").attr("gradientUnits","objectBoundingBox").attr("x1","0%").attr("y1","0%").attr("x2","100%").attr("y2","0%");t.append("svg:stop").attr("offset","0%").attr("stop-color",o).attr("stop-opacity",1),t.append("svg:stop").attr("offset","100%").attr("stop-color",u).attr("stop-opacity",1)}return s.render(t,e,l,{algorithm:a.algorithm})},"render"),u=(0,r.__name)((t="",{fallback:e="dagre"}={})=>{if(t in n)return t;if(e in n)return r.log.warn(`Layout algorithm ${t} is not registered. Using ${e} as fallback.`),e;throw Error(`Both layout algorithms ${t} and ${e} are not registered.`)},"getRegisteredLayoutAlgorithm");t.s(["getRegisteredLayoutAlgorithm",0,u,"registerLayoutLoaders",0,c,"render",0,o])},50160,t=>{t.q("/_next/static/media/icon.0fkix7.hkmsz4.png")},16715,t=>{"use strict";let e=(0,t.i(75254).default)("refresh-cw",[["path",{d:"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",key:"v9h5vc"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}],["path",{d:"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",key:"3uifl3"}],["path",{d:"M8 16H3v5",key:"1cv678"}]]);t.s(["RefreshCw",0,e],16715)},7233,5352,t=>{"use strict";let e=(0,t.i(75254).default)("plus",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]);t.s(["Plus",0,e],7233);let a=[{bg:"bg-blue-100 dark:bg-blue-900/30",text:"text-blue-700 dark:text-blue-300"},{bg:"bg-emerald-100 dark:bg-emerald-900/30",text:"text-emerald-700 dark:text-emerald-300"},{bg:"bg-violet-100 dark:bg-violet-900/30",text:"text-violet-700 dark:text-violet-300"},{bg:"bg-amber-100 dark:bg-amber-900/30",text:"text-amber-700 dark:text-amber-300"},{bg:"bg-rose-100 dark:bg-rose-900/30",text:"text-rose-700 dark:text-rose-300"},{bg:"bg-cyan-100 dark:bg-cyan-900/30",text:"text-cyan-700 dark:text-cyan-300"},{bg:"bg-orange-100 dark:bg-orange-900/30",text:"text-orange-700 dark:text-orange-300"},{bg:"bg-teal-100 dark:bg-teal-900/30",text:"text-teal-700 dark:text-teal-300"},{bg:"bg-indigo-100 dark:bg-indigo-900/30",text:"text-indigo-700 dark:text-indigo-300"},{bg:"bg-pink-100 dark:bg-pink-900/30",text:"text-pink-700 dark:text-pink-300"},{bg:"bg-lime-100 dark:bg-lime-900/30",text:"text-lime-700 dark:text-lime-300"},{bg:"bg-fuchsia-100 dark:bg-fuchsia-900/30",text:"text-fuchsia-700 dark:text-fuchsia-300"}];t.s(["getRepoColor",0,function(t,e){let s=function(t){let e=5381;for(let a=0;a<t.length;a++)e=33*e^t.charCodeAt(a);return e>>>0}(`${t}/${e}`)%a.length;return a[s]}],5352)},55716,t=>{"use strict";let e=(0,t.i(75254).default)("git-branch",[["line",{x1:"6",x2:"6",y1:"3",y2:"15",key:"17qcm7"}],["circle",{cx:"18",cy:"6",r:"3",key:"1h7g24"}],["circle",{cx:"6",cy:"18",r:"3",key:"fqmcym"}],["path",{d:"M18 9a9 9 0 0 1-9 9",key:"n2h4wq"}]]);t.s(["GitBranch",0,e],55716)},39484,t=>{t.v(e=>Promise.all(["static/chunks/002jt~~cq5_aa.js"].map(e=>t.l(e))).then(()=>e(16400)))},92568,t=>{t.v(e=>Promise.all(["static/chunks/0bew-tpzkv4a6.js","static/chunks/0hc31lz26e0bj.js","static/chunks/156lsa3n_7-g1.js"].map(e=>t.l(e))).then(()=>e(68053)))},62369,t=>{t.v(e=>Promise.all(["static/chunks/0t-ecot2ot8jq.js","static/chunks/0s2ei~z99yg.7.js"].map(e=>t.l(e))).then(()=>e(97810)))},78997,t=>{t.v(e=>Promise.all(["static/chunks/0w4h2u4jedq4..js","static/chunks/0v8zy131j2_sl.js"].map(e=>t.l(e))).then(()=>e(77010)))},28146,t=>{t.v(e=>Promise.all(["static/chunks/179i-blt6kp34.js","static/chunks/004q74ucr0rud.js"].map(e=>t.l(e))).then(()=>e(26067)))},80472,t=>{t.v(e=>Promise.all(["static/chunks/0-whcx~709zzu.js"].map(e=>t.l(e))).then(()=>e(50032)))},83305,t=>{t.v(e=>Promise.all(["static/chunks/00h5q76-kypod.js","static/chunks/0f6mqg1npiv.t.js","static/chunks/0g7ov558axacn.js"].map(e=>t.l(e))).then(()=>e(8709)))},34606,t=>{t.v(e=>Promise.all(["static/chunks/0t-7~zw5_oj33.js","static/chunks/0t1nhjmm.2-8-.js"].map(e=>t.l(e))).then(()=>e(13976)))},23526,t=>{t.v(e=>Promise.all(["static/chunks/0zz1c.5ttlw75.js","static/chunks/0f6mqg1npiv.t.js","static/chunks/00h5q76-kypod.js"].map(e=>t.l(e))).then(()=>e(60498)))},3931,t=>{t.v(e=>Promise.all(["static/chunks/0egss2l0vp3iv.js","static/chunks/0f6mqg1npiv.t.js","static/chunks/00h5q76-kypod.js"].map(e=>t.l(e))).then(()=>e(79567)))},67051,t=>{t.v(e=>Promise.all(["static/chunks/0v~puv980n2mn.js"].map(e=>t.l(e))).then(()=>e(51778)))},36080,t=>{t.v(e=>Promise.all(["static/chunks/0_u58hj44ucg2.js","static/chunks/0coux02phyasu.js"].map(e=>t.l(e))).then(()=>e(79003)))},3156,t=>{t.v(e=>Promise.all(["static/chunks/0~fjlnit~fkey.js"].map(e=>t.l(e))).then(()=>e(91739)))},71209,t=>{t.v(e=>Promise.all(["static/chunks/0njmix7y_6miv.js","static/chunks/0z9df3ijvbr8h.js"].map(e=>t.l(e))).then(()=>e(94614)))},78922,t=>{t.v(e=>Promise.all(["static/chunks/0nt-wtu-~b7hv.js","static/chunks/0nwbvs~t8m~k6.js"].map(e=>t.l(e))).then(()=>e(99223)))},10404,t=>{t.v(e=>Promise.all(["static/chunks/0puq-xa16mucw.js","static/chunks/0nwbvs~t8m~k6.js"].map(e=>t.l(e))).then(()=>e(25730)))},81283,t=>{t.v(e=>Promise.all(["static/chunks/0bew-tpzkv4a6.js","static/chunks/104dsd7mk1jyt.js","static/chunks/0.fiftciismd2.js","static/chunks/0hc31lz26e0bj.js"].map(e=>t.l(e))).then(()=>e(24924)))},41605,t=>{t.v(e=>Promise.all(["static/chunks/0vj43fihkfmqz.js","static/chunks/0.fiftciismd2.js"].map(e=>t.l(e))).then(()=>e(32579)))},78877,t=>{t.v(e=>Promise.all(["static/chunks/0lmm~3cjla0c9.js"].map(e=>t.l(e))).then(()=>e(21392)))},27415,t=>{t.v(e=>Promise.all(["static/chunks/0rr4nl_auvf0b.js"].map(e=>t.l(e))).then(()=>e(92280)))},44319,t=>{t.v(e=>Promise.all(["static/chunks/0l_tj98f_5ot-.js"].map(e=>t.l(e))).then(()=>e(84201)))},31376,t=>{t.v(e=>Promise.all(["static/chunks/0-_x27yxy_uq_.js"].map(e=>t.l(e))).then(()=>e(3054)))},34215,t=>{t.v(e=>Promise.all(["static/chunks/0kx.ki.9u_0dy.js"].map(e=>t.l(e))).then(()=>e(30770)))},11980,t=>{t.v(e=>Promise.all(["static/chunks/0bb.y5mii27l0.js","static/chunks/0f6mqg1npiv.t.js","static/chunks/00h5q76-kypod.js"].map(e=>t.l(e))).then(()=>e(39342)))},70234,t=>{t.v(e=>Promise.all(["static/chunks/0g8qw208n3i89.js","static/chunks/0f6mqg1npiv.t.js","static/chunks/00h5q76-kypod.js"].map(e=>t.l(e))).then(()=>e(43020)))},44243,t=>{t.v(e=>Promise.all(["static/chunks/06x~dj4kp-z9f.js","static/chunks/11905-quym2vs.js","static/chunks/043yk9d-7bl43.js"].map(e=>t.l(e))).then(()=>e(15508)))},51365,t=>{t.v(e=>Promise.all(["static/chunks/0r4wgiv_kwiro.js","static/chunks/0f6mqg1npiv.t.js","static/chunks/00h5q76-kypod.js"].map(e=>t.l(e))).then(()=>e(78730)))},46201,t=>{t.v(e=>Promise.all(["static/chunks/1158vq~dpuyl-.js","static/chunks/00h5q76-kypod.js","static/chunks/0f6mqg1npiv.t.js","static/chunks/0s2ei~z99yg.7.js","static/chunks/0lr2ip~4h2o.z.js"].map(e=>t.l(e))).then(()=>e(38206)))},48926,t=>{t.v(e=>Promise.all(["static/chunks/0kl8vyx5367.j.js"].map(e=>t.l(e))).then(()=>e(90158)))},81291,t=>{t.v(e=>Promise.all(["static/chunks/17me7gnh4-..3.js"].map(e=>t.l(e))).then(()=>e(4447)))},31656,t=>{t.v(e=>Promise.all(["static/chunks/00h5q76-kypod.js","static/chunks/0f6mqg1npiv.t.js","static/chunks/0_7ef.hja3s4s.js"].map(e=>t.l(e))).then(()=>e(68025)))},22654,t=>{t.v(e=>Promise.all(["static/chunks/00h5q76-kypod.js","static/chunks/0f6mqg1npiv.t.js","static/chunks/0oryo.isv4jwb.js"].map(e=>t.l(e))).then(()=>e(67933)))}]);
@@ -1 +1 @@
1
- (globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,{otherChunks:["static/chunks/0apjd6p1xsnc3.js","static/chunks/02i7dfk78~t~2.js","static/chunks/0.76ju_ex-wmx.js","static/chunks/0lp.2eizum8y~.js"],runtimeModuleIds:[94553]}]),(()=>{let e;if(!Array.isArray(globalThis.TURBOPACK))return;let t="/_next/",r=function(){if(null!=self.TURBOPACK_ASSET_SUFFIX)return self.TURBOPACK_ASSET_SUFFIX;let e=document?.currentScript?.getAttribute?.("src")??"",t=e.indexOf("?");return t>=0?e.slice(t):""}(),n=["NEXT_DEPLOYMENT_ID","NEXT_CLIENT_ASSET_SUFFIX"];var o,i=((o=i||{})[o.Runtime=0]="Runtime",o[o.Parent=1]="Parent",o[o.Update=2]="Update",o);let l=new WeakMap;function s(e,t){this.m=e,this.e=t}let u=s.prototype,a=Object.prototype.hasOwnProperty,c="u">typeof Symbol&&Symbol.toStringTag;function f(e,t,r){a.call(e,t)||Object.defineProperty(e,t,r)}function p(e,t){let r=e[t];return r||(r=h(t),e[t]=r),r}function h(e){return{exports:{},error:void 0,id:e,namespaceObject:void 0}}function d(e,t){f(e,"__esModule",{value:!0}),c&&f(e,c,{value:"Module"});let r=0;for(;r<t.length;){let n=t[r++],o=t[r++];if("number"==typeof o)if(0===o)f(e,n,{value:t[r++],enumerable:!0,writable:!1});else throw Error(`unexpected tag: ${o}`);else"function"==typeof t[r]?f(e,n,{get:o,set:t[r++],enumerable:!0}):f(e,n,{get:o,enumerable:!0})}Object.seal(e)}function m(e,t){(null!=t?p(this.c,t):this.m).exports=e}u.s=function(e,t){let r,n;null!=t?n=(r=p(this.c,t)).exports:(r=this.m,n=this.e),r.namespaceObject=n,d(n,e)},u.j=function(e,t){var r,n;let o,i,s;null!=t?i=(o=p(this.c,t)).exports:(o=this.m,i=this.e);let u=(r=o,n=i,(s=l.get(r))||(l.set(r,s=[]),r.exports=r.namespaceObject=new Proxy(n,{get(e,t){if(a.call(e,t)||"default"===t||"__esModule"===t)return Reflect.get(e,t);for(let e of s){let r=Reflect.get(e,t);if(void 0!==r)return r}},ownKeys(e){let t=Reflect.ownKeys(e);for(let e of s)for(let r of Reflect.ownKeys(e))"default"===r||t.includes(r)||t.push(r);return t}})),s);"object"==typeof e&&null!==e&&u.push(e)},u.v=m,u.n=function(e,t){let r;(r=null!=t?p(this.c,t):this.m).exports=r.namespaceObject=e};let b=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,y=[null,b({}),b([]),b(b)];function g(e,t,r){let n=[],o=-1;for(let t=e;("object"==typeof t||"function"==typeof t)&&!y.includes(t);t=b(t))for(let r of Object.getOwnPropertyNames(t))n.push(r,function(e,t){return()=>e[t]}(e,r)),-1===o&&"default"===r&&(o=n.length-1);return r&&o>=0||(o>=0?n.splice(o,1,0,e):n.push("default",0,e)),d(t,n),t}function O(e){let t=B(e,this.m);if(t.namespaceObject)return t.namespaceObject;let r=t.exports;return t.namespaceObject=g(r,"function"==typeof r?function(...e){return r.apply(this,e)}:Object.create(null),r&&r.__esModule)}function w(e){let t=e.indexOf("#");-1!==t&&(e=e.substring(0,t));let r=e.indexOf("?");return -1!==r&&(e=e.substring(0,r)),e}function j(){let e,t;return{promise:new Promise((r,n)=>{t=n,e=r}),resolve:e,reject:t}}u.i=O,u.A=function(e){return this.r(e)(O.bind(this))},u.t="function"==typeof require?require:function(){throw Error("Unexpected use of runtime require")},u.r=function(e){return B(e,this.m).exports},u.f=function(e){function t(t){if(t=w(t),a.call(e,t))return e[t].module();let r=Error(`Cannot find module '${t}'`);throw r.code="MODULE_NOT_FOUND",r}return t.keys=()=>Object.keys(e),t.resolve=t=>{if(t=w(t),a.call(e,t))return e[t].id();let r=Error(`Cannot find module '${t}'`);throw r.code="MODULE_NOT_FOUND",r},t.import=async e=>await t(e),t};let k=Symbol("turbopack queues"),U=Symbol("turbopack exports"),C=Symbol("turbopack error");function P(e){e&&1!==e.status&&(e.status=1,e.forEach(e=>e.queueCount--),e.forEach(e=>e.queueCount--?e.queueCount++:e()))}u.a=function(e,t){let r=this.m,n=t?Object.assign([],{status:-1}):void 0,o=new Set,{resolve:i,reject:l,promise:s}=j(),u=Object.assign(s,{[U]:r.exports,[k]:e=>{n&&e(n),o.forEach(e),u.catch(()=>{})}}),a={get:()=>u,set(e){e!==u&&(u[U]=e)}};Object.defineProperty(r,"exports",a),Object.defineProperty(r,"namespaceObject",a),e(function(e){let t=e.map(e=>{if(null!==e&&"object"==typeof e){if(k in e)return e;if(null!=e&&"object"==typeof e&&"then"in e&&"function"==typeof e.then){let t=Object.assign([],{status:0}),r={[U]:{},[k]:e=>e(t)};return e.then(e=>{r[U]=e,P(t)},e=>{r[C]=e,P(t)}),r}}return{[U]:e,[k]:()=>{}}}),r=()=>t.map(e=>{if(e[C])throw e[C];return e[U]}),{promise:i,resolve:l}=j(),s=Object.assign(()=>l(r),{queueCount:0});function u(e){e!==n&&!o.has(e)&&(o.add(e),e&&0===e.status&&(s.queueCount++,e.push(s)))}return t.map(e=>e[k](u)),s.queueCount?i:r()},function(e){e?l(u[C]=e):i(u[U]),P(n)}),n&&-1===n.status&&(n.status=0)};let v=function(e){let t=new URL(e,"x:/"),r={};for(let e in t)r[e]=t[e];for(let t in r.href=e,r.pathname=e.replace(/[?#].*/,""),r.origin=r.protocol="",r.toString=r.toJSON=(...t)=>e,r)Object.defineProperty(this,t,{enumerable:!0,configurable:!0,value:r[t]})};function R(e,t){throw Error(`Invariant: ${t(e)}`)}v.prototype=URL.prototype,u.U=v,u.z=function(e){throw Error("dynamic usage of require is not supported")},u.g=globalThis;let S=s.prototype,$=new Map;u.M=$;let _=new Map,E=new Map;async function T(e,t,r){let n;if("string"==typeof r)return M(e,t,N(r));let o=r.included||[],i=o.map(e=>!!$.has(e)||_.get(e));if(i.length>0&&i.every(e=>e))return void await Promise.all(i);let l=r.moduleChunks||[],s=l.map(e=>E.get(e)).filter(e=>e);if(s.length>0){if(s.length===l.length)return void await Promise.all(s);let r=new Set;for(let e of l)E.has(e)||r.add(e);for(let n of r){let r=M(e,t,N(n));E.set(n,r),s.push(r)}n=Promise.all(s)}else{for(let o of(n=M(e,t,N(r.path)),l))E.has(o)||E.set(o,n)}for(let e of o)_.has(e)||_.set(e,n);await n}S.l=function(e){return T(i.Parent,this.m.id,e)};let x=Promise.resolve(void 0),A=new WeakMap;function M(t,r,n){let o=e.loadChunkCached(t,n),l=A.get(o);if(void 0===l){let e=A.set.bind(A,o,x);l=o.then(e).catch(e=>{let o;switch(t){case i.Runtime:o=`as a runtime dependency of chunk ${r}`;break;case i.Parent:o=`from module ${r}`;break;case i.Update:o="from an HMR update";break;default:R(t,e=>`Unknown source type: ${e}`)}let l=Error(`Failed to load chunk ${n} ${o}${e?`: ${e}`:""}`,e?{cause:e}:void 0);throw l.name="ChunkLoadError",l}),A.set(o,l)}return l}function N(e){return`${t}${e.split("/").map(e=>encodeURIComponent(e)).join("/")}${r}`}S.L=function(e){return M(i.Parent,this.m.id,e)},S.R=function(e){let t=this.r(e);return t?.default??t},S.P=function(e){return`/ROOT/${e??""}`},S.q=function(e,t){m.call(this,`${e}${r}`,t)},S.b=function(e,t,o,i){let l="SharedWorker"===e.name,s=[o.map(e=>N(e)).reverse(),r];for(let e of n)s.push(globalThis[e]);let u=new URL(N(t),location.origin),a=JSON.stringify(s);return l?u.searchParams.set("params",a):u.hash="#params="+encodeURIComponent(a),new e(u,i?{...i,type:void 0}:void 0)};let K=/\.js(?:\?[^#]*)?(?:#.*)?$/,q=/\.css(?:\?[^#]*)?(?:#.*)?$/;function L(e){return q.test(e)}u.w=function(t,r,n){return e.loadWebAssembly(i.Parent,this.m.id,t,r,n)},u.u=function(t,r){return e.loadWebAssemblyModule(i.Parent,this.m.id,t,r)};let I={};u.c=I;let B=(e,t)=>{let r=I[e];if(r){if(r.error)throw r.error;return r}return W(e,i.Parent,t.id)};function W(e,t,r){let n=$.get(e);if("function"!=typeof n)throw Error(function(e,t,r){let n;switch(t){case 0:n=`as a runtime entry of chunk ${r}`;break;case 1:n=`because it was required from module ${r}`;break;case 2:n="because of an HMR update";break;default:R(t,e=>`Unknown source type: ${e}`)}return`Module ${e} was instantiated ${n}, but the module factory is not available.`}(e,t,r));let o=h(e),i=o.exports;I[e]=o;let l=new s(o,i);try{n(l,o,i)}catch(e){throw o.error=e,e}return o.namespaceObject&&o.exports!==o.namespaceObject&&g(o.exports,o.namespaceObject),o}function F(t){let r,n=function(e){if("string"==typeof e)return e;if(e)return{src:e.getAttribute("src")};if("u">typeof TURBOPACK_NEXT_CHUNK_URLS)return{src:TURBOPACK_NEXT_CHUNK_URLS.pop()};throw Error("chunk path empty but not in a worker")}(t[0]);return 2===t.length?r=t[1]:(r=void 0,!function(e,t){let r=1;for(;r<e.length;){let n,o=r+1;for(;o<e.length&&"function"!=typeof e[o];)o++;if(o===e.length)throw Error("malformed chunk format, expected a factory function");let i=e[o];for(let i=r;i<o;i++){let r=e[i],o=t.get(r);if(o){n=o;break}}let l=n??i,s=!1;for(let n=r;n<o;n++){let r=e[n];t.has(r)||(s||(l===i&&Object.defineProperty(i,"name",{value:"module evaluation"}),s=!0),t.set(r,l))}r=o+1}}(t,$)),e.registerChunk(n,r)}let X=new Map;function D(e){let t=X.get(e);if(!t){let r,n;t={resolved:!1,loadingStarted:!1,promise:new Promise((e,t)=>{r=e,n=t}),resolve:()=>{t.resolved=!0,r()},reject:n},X.set(e,t)}return t}e={async registerChunk(e,r){let n=function(e){if("string"==typeof e)return e;let r=decodeURIComponent(e.src.replace(/[?#].*$/,""));return r.startsWith(t)?r.slice(t.length):r}(e);if(D("string"==typeof e?N(e):e.src).resolve(),null!=r){for(let e of r.otherChunks)D(N("string"==typeof e?e:e.path));if(await Promise.all(r.otherChunks.map(e=>T(i.Runtime,n,e))),r.runtimeModuleIds.length>0)for(let e of r.runtimeModuleIds)!function(e,t){let r=I[t];if(r){if(r.error)throw r.error;return}W(t,i.Runtime,e)}(n,e)}},loadChunkCached:(e,t)=>(function(e,t){let r=D(t);if(r.loadingStarted)return r.promise;if(e===i.Runtime)return r.loadingStarted=!0,L(t)&&r.resolve(),r.promise;if("function"==typeof importScripts)if(L(t));else if(K.test(t))self.TURBOPACK_NEXT_CHUNK_URLS.push(t),importScripts(t);else throw Error(`can't infer type of chunk from URL ${t} in worker`);else{let e=decodeURI(t);if(L(t))if(document.querySelectorAll(`link[rel=stylesheet][href="${t}"],link[rel=stylesheet][href^="${t}?"],link[rel=stylesheet][href="${e}"],link[rel=stylesheet][href^="${e}?"]`).length>0)r.resolve();else{let e=document.createElement("link");e.rel="stylesheet",e.href=t,e.onerror=()=>{r.reject()},e.onload=()=>{r.resolve()},document.head.appendChild(e)}else if(K.test(t)){let n=document.querySelectorAll(`script[src="${t}"],script[src^="${t}?"],script[src="${e}"],script[src^="${e}?"]`);if(n.length>0)for(let e of Array.from(n))e.addEventListener("error",()=>{r.reject()});else{let e=document.createElement("script");e.src=t,e.onerror=()=>{r.reject()},document.head.appendChild(e)}}else throw Error(`can't infer type of chunk from URL ${t}`)}return r.loadingStarted=!0,r.promise})(e,t),async loadWebAssembly(e,t,r,n,o){let i=fetch(N(r)),{instance:l}=await WebAssembly.instantiateStreaming(i,o);return l.exports},async loadWebAssemblyModule(e,t,r,n){let o=fetch(N(r));return await WebAssembly.compileStreaming(o)}};let H=globalThis.TURBOPACK;globalThis.TURBOPACK={push:F},H.forEach(F)})();
1
+ (globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,{otherChunks:["static/chunks/0apjd6p1xsnc3.js","static/chunks/02i7dfk78~t~2.js","static/chunks/0.76ju_ex-wmx.js","static/chunks/11rs2-0jl1rzr.js"],runtimeModuleIds:[94553]}]),(()=>{let e;if(!Array.isArray(globalThis.TURBOPACK))return;let t="/_next/",r=function(){if(null!=self.TURBOPACK_ASSET_SUFFIX)return self.TURBOPACK_ASSET_SUFFIX;let e=document?.currentScript?.getAttribute?.("src")??"",t=e.indexOf("?");return t>=0?e.slice(t):""}(),n=["NEXT_DEPLOYMENT_ID","NEXT_CLIENT_ASSET_SUFFIX"];var o,i=((o=i||{})[o.Runtime=0]="Runtime",o[o.Parent=1]="Parent",o[o.Update=2]="Update",o);let l=new WeakMap;function s(e,t){this.m=e,this.e=t}let u=s.prototype,a=Object.prototype.hasOwnProperty,c="u">typeof Symbol&&Symbol.toStringTag;function f(e,t,r){a.call(e,t)||Object.defineProperty(e,t,r)}function p(e,t){let r=e[t];return r||(r=h(t),e[t]=r),r}function h(e){return{exports:{},error:void 0,id:e,namespaceObject:void 0}}function d(e,t){f(e,"__esModule",{value:!0}),c&&f(e,c,{value:"Module"});let r=0;for(;r<t.length;){let n=t[r++],o=t[r++];if("number"==typeof o)if(0===o)f(e,n,{value:t[r++],enumerable:!0,writable:!1});else throw Error(`unexpected tag: ${o}`);else"function"==typeof t[r]?f(e,n,{get:o,set:t[r++],enumerable:!0}):f(e,n,{get:o,enumerable:!0})}Object.seal(e)}function m(e,t){(null!=t?p(this.c,t):this.m).exports=e}u.s=function(e,t){let r,n;null!=t?n=(r=p(this.c,t)).exports:(r=this.m,n=this.e),r.namespaceObject=n,d(n,e)},u.j=function(e,t){var r,n;let o,i,s;null!=t?i=(o=p(this.c,t)).exports:(o=this.m,i=this.e);let u=(r=o,n=i,(s=l.get(r))||(l.set(r,s=[]),r.exports=r.namespaceObject=new Proxy(n,{get(e,t){if(a.call(e,t)||"default"===t||"__esModule"===t)return Reflect.get(e,t);for(let e of s){let r=Reflect.get(e,t);if(void 0!==r)return r}},ownKeys(e){let t=Reflect.ownKeys(e);for(let e of s)for(let r of Reflect.ownKeys(e))"default"===r||t.includes(r)||t.push(r);return t}})),s);"object"==typeof e&&null!==e&&u.push(e)},u.v=m,u.n=function(e,t){let r;(r=null!=t?p(this.c,t):this.m).exports=r.namespaceObject=e};let b=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,y=[null,b({}),b([]),b(b)];function g(e,t,r){let n=[],o=-1;for(let t=e;("object"==typeof t||"function"==typeof t)&&!y.includes(t);t=b(t))for(let r of Object.getOwnPropertyNames(t))n.push(r,function(e,t){return()=>e[t]}(e,r)),-1===o&&"default"===r&&(o=n.length-1);return r&&o>=0||(o>=0?n.splice(o,1,0,e):n.push("default",0,e)),d(t,n),t}function O(e){let t=B(e,this.m);if(t.namespaceObject)return t.namespaceObject;let r=t.exports;return t.namespaceObject=g(r,"function"==typeof r?function(...e){return r.apply(this,e)}:Object.create(null),r&&r.__esModule)}function w(e){let t=e.indexOf("#");-1!==t&&(e=e.substring(0,t));let r=e.indexOf("?");return -1!==r&&(e=e.substring(0,r)),e}function j(){let e,t;return{promise:new Promise((r,n)=>{t=n,e=r}),resolve:e,reject:t}}u.i=O,u.A=function(e){return this.r(e)(O.bind(this))},u.t="function"==typeof require?require:function(){throw Error("Unexpected use of runtime require")},u.r=function(e){return B(e,this.m).exports},u.f=function(e){function t(t){if(t=w(t),a.call(e,t))return e[t].module();let r=Error(`Cannot find module '${t}'`);throw r.code="MODULE_NOT_FOUND",r}return t.keys=()=>Object.keys(e),t.resolve=t=>{if(t=w(t),a.call(e,t))return e[t].id();let r=Error(`Cannot find module '${t}'`);throw r.code="MODULE_NOT_FOUND",r},t.import=async e=>await t(e),t};let k=Symbol("turbopack queues"),U=Symbol("turbopack exports"),C=Symbol("turbopack error");function P(e){e&&1!==e.status&&(e.status=1,e.forEach(e=>e.queueCount--),e.forEach(e=>e.queueCount--?e.queueCount++:e()))}u.a=function(e,t){let r=this.m,n=t?Object.assign([],{status:-1}):void 0,o=new Set,{resolve:i,reject:l,promise:s}=j(),u=Object.assign(s,{[U]:r.exports,[k]:e=>{n&&e(n),o.forEach(e),u.catch(()=>{})}}),a={get:()=>u,set(e){e!==u&&(u[U]=e)}};Object.defineProperty(r,"exports",a),Object.defineProperty(r,"namespaceObject",a),e(function(e){let t=e.map(e=>{if(null!==e&&"object"==typeof e){if(k in e)return e;if(null!=e&&"object"==typeof e&&"then"in e&&"function"==typeof e.then){let t=Object.assign([],{status:0}),r={[U]:{},[k]:e=>e(t)};return e.then(e=>{r[U]=e,P(t)},e=>{r[C]=e,P(t)}),r}}return{[U]:e,[k]:()=>{}}}),r=()=>t.map(e=>{if(e[C])throw e[C];return e[U]}),{promise:i,resolve:l}=j(),s=Object.assign(()=>l(r),{queueCount:0});function u(e){e!==n&&!o.has(e)&&(o.add(e),e&&0===e.status&&(s.queueCount++,e.push(s)))}return t.map(e=>e[k](u)),s.queueCount?i:r()},function(e){e?l(u[C]=e):i(u[U]),P(n)}),n&&-1===n.status&&(n.status=0)};let v=function(e){let t=new URL(e,"x:/"),r={};for(let e in t)r[e]=t[e];for(let t in r.href=e,r.pathname=e.replace(/[?#].*/,""),r.origin=r.protocol="",r.toString=r.toJSON=(...t)=>e,r)Object.defineProperty(this,t,{enumerable:!0,configurable:!0,value:r[t]})};function R(e,t){throw Error(`Invariant: ${t(e)}`)}v.prototype=URL.prototype,u.U=v,u.z=function(e){throw Error("dynamic usage of require is not supported")},u.g=globalThis;let S=s.prototype,$=new Map;u.M=$;let _=new Map,E=new Map;async function T(e,t,r){let n;if("string"==typeof r)return M(e,t,N(r));let o=r.included||[],i=o.map(e=>!!$.has(e)||_.get(e));if(i.length>0&&i.every(e=>e))return void await Promise.all(i);let l=r.moduleChunks||[],s=l.map(e=>E.get(e)).filter(e=>e);if(s.length>0){if(s.length===l.length)return void await Promise.all(s);let r=new Set;for(let e of l)E.has(e)||r.add(e);for(let n of r){let r=M(e,t,N(n));E.set(n,r),s.push(r)}n=Promise.all(s)}else{for(let o of(n=M(e,t,N(r.path)),l))E.has(o)||E.set(o,n)}for(let e of o)_.has(e)||_.set(e,n);await n}S.l=function(e){return T(i.Parent,this.m.id,e)};let x=Promise.resolve(void 0),A=new WeakMap;function M(t,r,n){let o=e.loadChunkCached(t,n),l=A.get(o);if(void 0===l){let e=A.set.bind(A,o,x);l=o.then(e).catch(e=>{let o;switch(t){case i.Runtime:o=`as a runtime dependency of chunk ${r}`;break;case i.Parent:o=`from module ${r}`;break;case i.Update:o="from an HMR update";break;default:R(t,e=>`Unknown source type: ${e}`)}let l=Error(`Failed to load chunk ${n} ${o}${e?`: ${e}`:""}`,e?{cause:e}:void 0);throw l.name="ChunkLoadError",l}),A.set(o,l)}return l}function N(e){return`${t}${e.split("/").map(e=>encodeURIComponent(e)).join("/")}${r}`}S.L=function(e){return M(i.Parent,this.m.id,e)},S.R=function(e){let t=this.r(e);return t?.default??t},S.P=function(e){return`/ROOT/${e??""}`},S.q=function(e,t){m.call(this,`${e}${r}`,t)},S.b=function(e,t,o,i){let l="SharedWorker"===e.name,s=[o.map(e=>N(e)).reverse(),r];for(let e of n)s.push(globalThis[e]);let u=new URL(N(t),location.origin),a=JSON.stringify(s);return l?u.searchParams.set("params",a):u.hash="#params="+encodeURIComponent(a),new e(u,i?{...i,type:void 0}:void 0)};let K=/\.js(?:\?[^#]*)?(?:#.*)?$/,q=/\.css(?:\?[^#]*)?(?:#.*)?$/;function L(e){return q.test(e)}u.w=function(t,r,n){return e.loadWebAssembly(i.Parent,this.m.id,t,r,n)},u.u=function(t,r){return e.loadWebAssemblyModule(i.Parent,this.m.id,t,r)};let I={};u.c=I;let B=(e,t)=>{let r=I[e];if(r){if(r.error)throw r.error;return r}return W(e,i.Parent,t.id)};function W(e,t,r){let n=$.get(e);if("function"!=typeof n)throw Error(function(e,t,r){let n;switch(t){case 0:n=`as a runtime entry of chunk ${r}`;break;case 1:n=`because it was required from module ${r}`;break;case 2:n="because of an HMR update";break;default:R(t,e=>`Unknown source type: ${e}`)}return`Module ${e} was instantiated ${n}, but the module factory is not available.`}(e,t,r));let o=h(e),i=o.exports;I[e]=o;let l=new s(o,i);try{n(l,o,i)}catch(e){throw o.error=e,e}return o.namespaceObject&&o.exports!==o.namespaceObject&&g(o.exports,o.namespaceObject),o}function F(t){let r,n=function(e){if("string"==typeof e)return e;if(e)return{src:e.getAttribute("src")};if("u">typeof TURBOPACK_NEXT_CHUNK_URLS)return{src:TURBOPACK_NEXT_CHUNK_URLS.pop()};throw Error("chunk path empty but not in a worker")}(t[0]);return 2===t.length?r=t[1]:(r=void 0,!function(e,t){let r=1;for(;r<e.length;){let n,o=r+1;for(;o<e.length&&"function"!=typeof e[o];)o++;if(o===e.length)throw Error("malformed chunk format, expected a factory function");let i=e[o];for(let i=r;i<o;i++){let r=e[i],o=t.get(r);if(o){n=o;break}}let l=n??i,s=!1;for(let n=r;n<o;n++){let r=e[n];t.has(r)||(s||(l===i&&Object.defineProperty(i,"name",{value:"module evaluation"}),s=!0),t.set(r,l))}r=o+1}}(t,$)),e.registerChunk(n,r)}let X=new Map;function D(e){let t=X.get(e);if(!t){let r,n;t={resolved:!1,loadingStarted:!1,promise:new Promise((e,t)=>{r=e,n=t}),resolve:()=>{t.resolved=!0,r()},reject:n},X.set(e,t)}return t}e={async registerChunk(e,r){let n=function(e){if("string"==typeof e)return e;let r=decodeURIComponent(e.src.replace(/[?#].*$/,""));return r.startsWith(t)?r.slice(t.length):r}(e);if(D("string"==typeof e?N(e):e.src).resolve(),null!=r){for(let e of r.otherChunks)D(N("string"==typeof e?e:e.path));if(await Promise.all(r.otherChunks.map(e=>T(i.Runtime,n,e))),r.runtimeModuleIds.length>0)for(let e of r.runtimeModuleIds)!function(e,t){let r=I[t];if(r){if(r.error)throw r.error;return}W(t,i.Runtime,e)}(n,e)}},loadChunkCached:(e,t)=>(function(e,t){let r=D(t);if(r.loadingStarted)return r.promise;if(e===i.Runtime)return r.loadingStarted=!0,L(t)&&r.resolve(),r.promise;if("function"==typeof importScripts)if(L(t));else if(K.test(t))self.TURBOPACK_NEXT_CHUNK_URLS.push(t),importScripts(t);else throw Error(`can't infer type of chunk from URL ${t} in worker`);else{let e=decodeURI(t);if(L(t))if(document.querySelectorAll(`link[rel=stylesheet][href="${t}"],link[rel=stylesheet][href^="${t}?"],link[rel=stylesheet][href="${e}"],link[rel=stylesheet][href^="${e}?"]`).length>0)r.resolve();else{let e=document.createElement("link");e.rel="stylesheet",e.href=t,e.onerror=()=>{r.reject()},e.onload=()=>{r.resolve()},document.head.appendChild(e)}else if(K.test(t)){let n=document.querySelectorAll(`script[src="${t}"],script[src^="${t}?"],script[src="${e}"],script[src^="${e}?"]`);if(n.length>0)for(let e of Array.from(n))e.addEventListener("error",()=>{r.reject()});else{let e=document.createElement("script");e.src=t,e.onerror=()=>{r.reject()},document.head.appendChild(e)}}else throw Error(`can't infer type of chunk from URL ${t}`)}return r.loadingStarted=!0,r.promise})(e,t),async loadWebAssembly(e,t,r,n,o){let i=fetch(N(r)),{instance:l}=await WebAssembly.instantiateStreaming(i,o);return l.exports},async loadWebAssemblyModule(e,t,r,n){let o=fetch(N(r));return await WebAssembly.compileStreaming(o)}};let H=globalThis.TURBOPACK;globalThis.TURBOPACK={push:F},H.forEach(F)})();
@@ -15,7 +15,15 @@ import crypto from 'node:crypto';
15
15
  // localhost 経由で叩く。これを免除しないと Basic 認証有効時に 401 となり
16
16
  // Monaco Editor が開かない。外部ブラウザからの /complete は cf ヘッダが付くため
17
17
  // 引き続き認証必須。
18
- const LOCAL_EXEMPT_PREFIXES = ['/health', '/api/hooks', '/api/internal', '/api/mcp', '/api/editor'];
18
+ const LOCAL_EXEMPT_PREFIXES = [
19
+ '/health',
20
+ '/api/hooks',
21
+ '/api/internal',
22
+ '/api/mcp',
23
+ '/api/editor',
24
+ // ローカルLLMタブの Claude Code が接続する中継口
25
+ '/api/local-llm/proxy',
26
+ ];
19
27
  const LOOPBACK_ADDRESSES = new Set(['127.0.0.1', '::1', '::ffff:127.0.0.1']);
20
28
  export function createBasicAuth(env = process.env) {
21
29
  const user = env.TSUNAGI_BASIC_AUTH_USER;
@@ -15,7 +15,7 @@ const config = {
15
15
  "clientVersion": "7.6.0",
16
16
  "engineVersion": "75cbdc1eb7150937890ad5465d861175c6624711",
17
17
  "activeProvider": "sqlite",
18
- "inlineSchema": "generator client {\n provider = \"prisma-client\"\n output = \"../src/generated/prisma\"\n}\n\ndatasource db {\n provider = \"sqlite\"\n}\n\n// Repository\nmodel Repository {\n id String @id @default(uuid())\n owner String\n repo String\n cloneUrl String @map(\"clone_url\")\n order Int @default(0)\n createdAt DateTime @default(now()) @map(\"created_at\")\n\n tasks Task[]\n environmentVars EnvironmentVariable[]\n\n @@unique([owner, repo])\n @@map(\"repositories\")\n}\n\n// Task\nmodel Task {\n id String @id @default(uuid())\n title String\n description String\n status String // 'backlog' | 'planning' | 'coding' | 'reviewing' | 'done'\n owner String\n repo String\n branch String\n baseBranch String @map(\"base_branch\") // rebase/merge判定用のベースブランチ\n repoId String @map(\"repo_id\")\n worktreeStatus String @map(\"worktree_status\") // 'pending' | 'created' | 'error'\n\n // Pull Request情報\n pullRequestUrl String? @map(\"pull_request_url\")\n\n effort Int?\n order Int @default(0)\n deletedAt DateTime? @map(\"deleted_at\")\n createdAt DateTime @default(now()) @map(\"created_at\")\n updatedAt DateTime @updatedAt @map(\"updated_at\")\n\n repository Repository @relation(fields: [repoId], references: [id], onDelete: Cascade)\n tabs Tab[]\n\n @@index([owner, repo])\n @@index([status])\n @@index([deletedAt])\n @@map(\"tasks\")\n}\n\n// Tab\nmodel Tab {\n tabId String @id @map(\"tab_id\")\n taskId String @map(\"task_id\")\n order Int // タブ表示用の連番\n status String // 'idle' | 'running' | 'success' | 'error'\n mode String @default(\"claude\") // 'terminal' | 'claude' | 'ollama'(ollama: ローカルLLM(Ollama)で起動するclaude)\n createdAt DateTime @default(now()) @map(\"created_at\")\n startedAt DateTime @map(\"started_at\")\n completedAt DateTime? @map(\"completed_at\")\n todos String? @default(\"[]\") // JSON: Todo[]\n // 完了(success/error)したがタスク詳細で未確認であることを示す。詳細を開くとfalseになる\n unread Boolean @default(false)\n updatedAt DateTime @updatedAt @map(\"updated_at\")\n\n task Task @relation(fields: [taskId], references: [id], onDelete: Cascade)\n\n @@index([taskId])\n @@map(\"tabs\")\n}\n\n// EnvironmentVariable\nmodel EnvironmentVariable {\n id String @id @default(uuid())\n key String\n value String\n scope String // 'global' | 'owner' | 'repo' - 階層構造の優先順位制御\n owner String?\n repo String?\n enabled Boolean @default(true)\n createdAt DateTime @default(now()) @map(\"created_at\")\n updatedAt DateTime @updatedAt @map(\"updated_at\")\n\n repository Repository? @relation(fields: [owner, repo], references: [owner, repo], onDelete: Cascade)\n\n @@unique([key, scope, owner, repo])\n @@index([scope, owner, repo])\n @@map(\"environment_variables\")\n}\n\n// AppSetting - アプリ全体の設定(key単位でJSONを保存)\nmodel AppSetting {\n key String @id\n value String // JSON\n updatedAt DateTime @updatedAt @map(\"updated_at\")\n\n @@map(\"app_settings\")\n}\n",
18
+ "inlineSchema": "generator client {\n provider = \"prisma-client\"\n output = \"../src/generated/prisma\"\n}\n\ndatasource db {\n provider = \"sqlite\"\n}\n\n// Repository\nmodel Repository {\n id String @id @default(uuid())\n owner String\n repo String\n cloneUrl String @map(\"clone_url\")\n order Int @default(0)\n createdAt DateTime @default(now()) @map(\"created_at\")\n\n tasks Task[]\n environmentVars EnvironmentVariable[]\n\n @@unique([owner, repo])\n @@map(\"repositories\")\n}\n\n// Task\nmodel Task {\n id String @id @default(uuid())\n title String\n description String\n status String // 'backlog' | 'planning' | 'coding' | 'reviewing' | 'done'\n owner String\n repo String\n branch String\n baseBranch String @map(\"base_branch\") // rebase/merge判定用のベースブランチ\n repoId String @map(\"repo_id\")\n worktreeStatus String @map(\"worktree_status\") // 'pending' | 'created' | 'error'\n\n // Pull Request情報\n pullRequestUrl String? @map(\"pull_request_url\")\n\n effort Int?\n order Int @default(0)\n deletedAt DateTime? @map(\"deleted_at\")\n createdAt DateTime @default(now()) @map(\"created_at\")\n updatedAt DateTime @updatedAt @map(\"updated_at\")\n\n repository Repository @relation(fields: [repoId], references: [id], onDelete: Cascade)\n tabs Tab[]\n\n @@index([owner, repo])\n @@index([status])\n @@index([deletedAt])\n @@map(\"tasks\")\n}\n\n// Tab\nmodel Tab {\n tabId String @id @map(\"tab_id\")\n taskId String @map(\"task_id\")\n order Int // タブ表示用の連番\n status String // 'idle' | 'running' | 'success' | 'error'\n mode String @default(\"claude\") // 'terminal' | 'claude' | 'local'(local: ローカルLLMで起動するclaude。旧 'ollama' / 'lmstudio' も local 扱い)\n createdAt DateTime @default(now()) @map(\"created_at\")\n startedAt DateTime @map(\"started_at\")\n completedAt DateTime? @map(\"completed_at\")\n todos String? @default(\"[]\") // JSON: Todo[]\n // 完了(success/error)したがタスク詳細で未確認であることを示す。詳細を開くとfalseになる\n unread Boolean @default(false)\n updatedAt DateTime @updatedAt @map(\"updated_at\")\n\n task Task @relation(fields: [taskId], references: [id], onDelete: Cascade)\n\n @@index([taskId])\n @@map(\"tabs\")\n}\n\n// EnvironmentVariable\nmodel EnvironmentVariable {\n id String @id @default(uuid())\n key String\n value String\n scope String // 'global' | 'owner' | 'repo' - 階層構造の優先順位制御\n owner String?\n repo String?\n enabled Boolean @default(true)\n createdAt DateTime @default(now()) @map(\"created_at\")\n updatedAt DateTime @updatedAt @map(\"updated_at\")\n\n repository Repository? @relation(fields: [owner, repo], references: [owner, repo], onDelete: Cascade)\n\n @@unique([key, scope, owner, repo])\n @@index([scope, owner, repo])\n @@map(\"environment_variables\")\n}\n\n// AppSetting - アプリ全体の設定(key単位でJSONを保存)\nmodel AppSetting {\n key String @id\n value String // JSON\n updatedAt DateTime @updatedAt @map(\"updated_at\")\n\n @@map(\"app_settings\")\n}\n",
19
19
  "runtimeDataModel": {
20
20
  "models": {},
21
21
  "enums": {},
@@ -13,6 +13,11 @@ import { onboardingRoutes } from './routes/onboarding.js';
13
13
  import { internalRoutes } from './routes/internal.js';
14
14
  import { hooksRoutes } from './routes/hooks.js';
15
15
  import { mcpRoutes } from './routes/mcp.js';
16
+ import { mcpWebRoutes } from './routes/mcp-web.js';
17
+ import { localLlmRoutes } from './routes/local-llm.js';
18
+ import { unloadOnShutdown } from './lib/local-llm.js';
19
+ import { watchUserSettingsForLocalModel } from './lib/claude-config-guard.js';
20
+ import { LOCAL_MODEL_ALIAS } from './lib/local-llm-env.js';
16
21
  import { terminalRoutes } from './routes/terminal.js';
17
22
  import { editorRoutes } from './routes/editor.js';
18
23
  import { whisperRoutes } from './routes/whisper.js';
@@ -20,6 +25,7 @@ import { stopWhisperServerOnExit } from './lib/whisper-process.js';
20
25
  import { llmRoutes } from './routes/llm.js';
21
26
  import { settingsRoutes } from './routes/settings.js';
22
27
  import { stopLlmServerOnExit } from './lib/llm-process.js';
28
+ import { stopSearxngOnExit, syncSearxng } from './lib/searxng.js';
23
29
  import { createBasicAuth } from './basic-auth.js';
24
30
  // Fastify は単一の公開エンドポイント。Next.js は内部ポートで動かしプロキシする。
25
31
  // PORT ではなく TSUNAGI_SERVER_PORT を見る(apps/cli が注入する専用キー)。generic な PORT を
@@ -94,11 +100,13 @@ async function start() {
94
100
  await fastify.register(internalRoutes, { prefix: '/api' });
95
101
  await fastify.register(hooksRoutes, { prefix: '/api' });
96
102
  await fastify.register(mcpRoutes, { prefix: '/api' });
103
+ await fastify.register(mcpWebRoutes, { prefix: '/api' });
97
104
  await fastify.register(terminalRoutes, { prefix: '/api' });
98
105
  await fastify.register(editorRoutes, { prefix: '/api' });
99
106
  await fastify.register(whisperRoutes, { prefix: '/api' });
100
107
  await fastify.register(llmRoutes, { prefix: '/api' });
101
108
  await fastify.register(settingsRoutes, { prefix: '/api' });
109
+ await fastify.register(localLlmRoutes, { prefix: '/api' });
102
110
  // catch-all リバースプロキシ: /api・/socket.io・/health 以外を内部 Next.js へ転送。
103
111
  // - /api/* と /health は上で定義済みルートが wildcard より優先される。
104
112
  // - /socket.io は Socket.IO が HTTP サーバ層で先取りするためここには来ない。
@@ -147,10 +155,21 @@ async function start() {
147
155
  }
148
156
  await fastify.listen({ port: PORT, host: '0.0.0.0' });
149
157
  console.log(`Fastify server running on port ${PORT}`);
158
+ // ローカルLLM(Ollama / LM Studio)が有効ならローカル検索用の SearXNG を起動する。
159
+ // 完了は待たず、失敗しても状態として記録するだけで tsunagi の起動は妨げない
160
+ void syncSearxng();
161
+ // ローカルLLMタブの /model で中継口の名前が既定モデルに保存されたら取り除く
162
+ watchUserSettingsForLocalModel(LOCAL_MODEL_ALIAS);
150
163
  const shutdown = async (signal) => {
151
164
  console.log(`[server] Received ${signal}, shutting down...`);
152
165
  stopWhisperServerOnExit();
153
166
  stopLlmServerOnExit();
167
+ stopSearxngOnExit();
168
+ // 設定で有効なら、ローカルLLMのモデルをメモリから外す(バッテリー・メモリ節約)。
169
+ // 開発時の tsx watch はファイル変更のたびに SIGTERM で再起動するため、その場合は外さない
170
+ if (signal === 'SIGINT' || process.env.NODE_ENV === 'production') {
171
+ await unloadOnShutdown();
172
+ }
154
173
  await fastify.close();
155
174
  process.exit(0);
156
175
  };
@@ -160,6 +179,7 @@ async function start() {
160
179
  process.on('exit', () => {
161
180
  stopWhisperServerOnExit();
162
181
  stopLlmServerOnExit();
182
+ stopSearxngOnExit();
163
183
  });
164
184
  }
165
185
  start().catch((err) => {
@@ -0,0 +1,6 @@
1
+ import type { TabMode } from '@minimalcorp/tsunagi-shared';
2
+ /** ローカルLLMタブの Claude Code の接続先(tsunagi の中継口) */
3
+ export declare const LOCAL_LLM_PROXY_URL: string;
4
+ export declare function isLocalLlmMode(mode: TabMode | undefined): boolean;
5
+ /** タブの mode に応じた claude の起動コマンド(既存セッションがあれば resume) */
6
+ export declare function buildClaudeCommand(sessionId: string, mode: TabMode): Promise<string>;
@@ -0,0 +1,85 @@
1
+ import { LOCAL_MODEL_ALIAS } from './local-llm-env.js';
2
+ import { getLocalLlmSettings } from './local-llm.js';
3
+ // Fastify(API) の公開ポート。index.ts と同じ既定値・同じ環境変数を見る
4
+ const SERVER_PORT = Number(process.env.TSUNAGI_SERVER_PORT) || 2791;
5
+ const SERVER_URL = `http://localhost:${SERVER_PORT}`;
6
+ /** ローカルLLMタブの Claude Code の接続先(tsunagi の中継口) */
7
+ export const LOCAL_LLM_PROXY_URL = `${SERVER_URL}/api/local-llm/proxy`;
8
+ /** ローカル検索に切り替えたタブで、組み込み WebSearch の代わりに使うよう促す */
9
+ const LOCAL_WEB_SEARCH_PROMPT = 'The built-in WebSearch tool is unavailable in this session. ' +
10
+ 'When you need information from the web, first call mcp__tsunagi-web__web_search to find pages. ' +
11
+ 'Do not guess URLs: only use WebFetch on URLs returned by web_search or given by the user.';
12
+ export function isLocalLlmMode(mode) {
13
+ return mode === 'local' || mode === 'ollama' || mode === 'lmstudio';
14
+ }
15
+ function shellQuote(value) {
16
+ return `'${value.replace(/'/g, `'\\''`)}'`;
17
+ }
18
+ /**
19
+ * ローカルLLMタブの claude に付ける引数。
20
+ * - モデルは Settings でだけ切り替える: /model の一覧を中継口の名前1件にし、PreModelSwitch フックで
21
+ * それ以外への切り替えを拒否する(Enter での切り替えは ~/.claude/settings.json に保存され、
22
+ * 通常の Claude タブが壊れるため)
23
+ * - ANTHROPIC_BASE_URL を変えたセッションでは MCP の tool search が無効になり、全 MCP のツール定義が
24
+ * 毎回プロンプトに載る(prefill が遅くなり tool 選択の精度も落ちる)。そのため MCP を tsunagi の
25
+ * タスク管理と web_search だけに絞る
26
+ */
27
+ async function localLlmArgs() {
28
+ const { active, webSearch } = await getLocalLlmSettings();
29
+ // ollama.com による WebSearch の代行は、使用中のモデルが Ollama のときだけ使える
30
+ const localWebSearch = webSearch === 'local' || active?.provider !== 'ollama';
31
+ const settings = {
32
+ modelPicker: {
33
+ options: [
34
+ {
35
+ model: LOCAL_MODEL_ALIAS,
36
+ label: 'ローカルLLM',
37
+ description: 'tsunagi の Settings で選んだモデル(切り替えも Settings で行う)',
38
+ },
39
+ ],
40
+ replaceBuiltInOptions: true,
41
+ },
42
+ hooks: {
43
+ PreModelSwitch: [
44
+ {
45
+ hooks: [
46
+ {
47
+ type: 'http',
48
+ url: `${SERVER_URL}/api/hooks/local-llm/pre-model-switch`,
49
+ timeout: 10,
50
+ },
51
+ ],
52
+ },
53
+ ],
54
+ },
55
+ };
56
+ const mcpServers = {
57
+ tsunagi: { type: 'http', url: `${SERVER_URL}/api/mcp` },
58
+ };
59
+ if (localWebSearch) {
60
+ mcpServers['tsunagi-web'] = { type: 'http', url: `${SERVER_URL}/api/mcp/web` };
61
+ }
62
+ const args = [
63
+ // 会話記録には転送先の実モデル名が残り、再開時に Claude Code がそれを復元しうるため、
64
+ // 中継口の名前に固定する(--model は会話記録より優先され、settings.json にも保存されない)
65
+ '--model',
66
+ LOCAL_MODEL_ALIAS,
67
+ '--settings',
68
+ shellQuote(JSON.stringify(settings)),
69
+ '--strict-mcp-config',
70
+ '--mcp-config',
71
+ shellQuote(JSON.stringify({ mcpServers })),
72
+ ];
73
+ if (localWebSearch) {
74
+ args.push('--disallowedTools', 'WebSearch', '--append-system-prompt', shellQuote(LOCAL_WEB_SEARCH_PROMPT));
75
+ }
76
+ return args;
77
+ }
78
+ /** タブの mode に応じた claude の起動コマンド(既存セッションがあれば resume) */
79
+ export async function buildClaudeCommand(sessionId, mode) {
80
+ const args = ['--dangerously-skip-permissions'];
81
+ if (isLocalLlmMode(mode))
82
+ args.push(...(await localLlmArgs()));
83
+ const claude = `claude ${args.join(' ')}`;
84
+ return `${claude} --resume ${sessionId} 2>/dev/null || ${claude} --session-id ${sessionId}`;
85
+ }
@@ -7,3 +7,15 @@
7
7
  * を前提にした自動起動フローが止まる。claude 起動直前にこのフラグだけ補正する。
8
8
  */
9
9
  export declare function ensureClaudeOnboardingCompleted(): Promise<void>;
10
+ /**
11
+ * ローカルLLMタブで /model の一覧から「ローカルLLM」を Enter で選ぶと、Claude Code は同じモデルへの
12
+ * 切り替えとみなして PreModelSwitch フックを通さずに ~/.claude/settings.json の model に
13
+ * 中継口の名前(localModelAlias)を保存する。そのままだと通常の Claude タブがその名前で起動して
14
+ * 壊れるため取り除く。
15
+ */
16
+ export declare function removeLocalModelFromUserSettings(localModelAlias: string): Promise<void>;
17
+ /**
18
+ * ~/.claude/settings.json の変更を監視し、中継口の名前が保存されたらすぐ取り除く。
19
+ * Claude Code は tmp ファイル経由で置き換えることがあるため、ファイルではなくディレクトリを監視する。
20
+ */
21
+ export declare function watchUserSettingsForLocalModel(localModelAlias: string): void;
@@ -1,3 +1,4 @@
1
+ import { watch } from 'fs';
1
2
  import * as fs from 'fs/promises';
2
3
  import * as os from 'os';
3
4
  import * as path from 'path';
@@ -41,3 +42,51 @@ export async function ensureClaudeOnboardingCompleted() {
41
42
  await fs.rm(tmpPath, { force: true }).catch(() => { });
42
43
  }
43
44
  }
45
+ const USER_SETTINGS_DIR = path.join(os.homedir(), '.claude');
46
+ const USER_SETTINGS_FILE = 'settings.json';
47
+ /**
48
+ * ローカルLLMタブで /model の一覧から「ローカルLLM」を Enter で選ぶと、Claude Code は同じモデルへの
49
+ * 切り替えとみなして PreModelSwitch フックを通さずに ~/.claude/settings.json の model に
50
+ * 中継口の名前(localModelAlias)を保存する。そのままだと通常の Claude タブがその名前で起動して
51
+ * 壊れるため取り除く。
52
+ */
53
+ export async function removeLocalModelFromUserSettings(localModelAlias) {
54
+ const settingsPath = path.join(USER_SETTINGS_DIR, USER_SETTINGS_FILE);
55
+ let settings;
56
+ try {
57
+ settings = JSON.parse(await fs.readFile(settingsPath, 'utf-8'));
58
+ }
59
+ catch {
60
+ return;
61
+ }
62
+ if (settings.model !== localModelAlias)
63
+ return;
64
+ delete settings.model;
65
+ const tmpPath = `${settingsPath}.tsunagi-tmp-${process.pid}`;
66
+ try {
67
+ await fs.writeFile(tmpPath, `${JSON.stringify(settings, null, 2)}\n`, 'utf-8');
68
+ await fs.rename(tmpPath, settingsPath);
69
+ }
70
+ catch {
71
+ await fs.rm(tmpPath, { force: true }).catch(() => { });
72
+ }
73
+ }
74
+ /**
75
+ * ~/.claude/settings.json の変更を監視し、中継口の名前が保存されたらすぐ取り除く。
76
+ * Claude Code は tmp ファイル経由で置き換えることがあるため、ファイルではなくディレクトリを監視する。
77
+ */
78
+ export function watchUserSettingsForLocalModel(localModelAlias) {
79
+ let watcher;
80
+ try {
81
+ watcher = watch(USER_SETTINGS_DIR, (_event, filename) => {
82
+ if (filename === USER_SETTINGS_FILE)
83
+ void removeLocalModelFromUserSettings(localModelAlias);
84
+ });
85
+ }
86
+ catch {
87
+ // ~/.claude がまだない(claude 未実行)場合は監視しない。起動前の補正で対応する
88
+ return;
89
+ }
90
+ watcher.on('error', () => watcher.close());
91
+ watcher.unref();
92
+ }
@@ -0,0 +1,24 @@
1
+ import type { LmStudioEstimate, LmStudioSettings, LmStudioStatus, LocalLlmModel } from '@minimalcorp/tsunagi-shared';
2
+ export declare const LMSTUDIO_SETTING_KEY = "lmstudio";
3
+ export declare function defaultLmStudioSettings(): LmStudioSettings;
4
+ export declare function getLmStudioSettings(): Promise<LmStudioSettings>;
5
+ export declare function saveLmStudioSettings(settings: LmStudioSettings): Promise<LmStudioSettings>;
6
+ /** リクエストボディを検証して LmStudioSettings に正規化する。不正ならエラーメッセージを返す */
7
+ export declare function parseLmStudioSettings(body: unknown): {
8
+ settings: LmStudioSettings;
9
+ } | {
10
+ error: string;
11
+ };
12
+ /** LM Studio へのリクエストに付ける認証トークン(認証を有効にしていなければ値は検証されない) */
13
+ export declare function lmStudioAuthToken(settings: LmStudioSettings): string;
14
+ /** lms CLI を探す(設定値 → ~/.lmstudio/bin/lms → PATH)。見つからなければ null */
15
+ export declare function findLms(settings: LmStudioSettings): string | null;
16
+ export declare function getLmStudioStatus(settings: LmStudioSettings): Promise<LmStudioStatus>;
17
+ /** ダウンロード済みの LLM 一覧。サーバー停止中でも選べるよう lms ls にフォールバックする */
18
+ export declare function listLmStudioModels(settings: LmStudioSettings): Promise<LocalLlmModel[]>;
19
+ export declare function startLmStudioServer(settings: LmStudioSettings): Promise<void>;
20
+ export declare function stopLmStudioServer(settings: LmStudioSettings): Promise<void>;
21
+ /** 読み込みに必要なメモリの見積もり(lms load --estimate-only の出力を読む) */
22
+ export declare function estimateLmStudioLoad(settings: LmStudioSettings, model: string, contextTokens: number): Promise<LmStudioEstimate>;
23
+ export declare function unloadLmStudioModel(settings: LmStudioSettings, instanceId: string): Promise<void>;
24
+ export declare function loadLmStudioModel(settings: LmStudioSettings, model: string, contextTokens: number): Promise<void>;
@@ -0,0 +1,198 @@
1
+ import { execFile } from 'node:child_process';
2
+ import * as fs from 'node:fs';
3
+ import * as os from 'node:os';
4
+ import * as path from 'node:path';
5
+ import { normalizeBaseUrl, readAppSetting, writeAppSetting } from './local-llm-env.js';
6
+ export const LMSTUDIO_SETTING_KEY = 'lmstudio';
7
+ const DEFAULT_BASE_URL = process.env.TSUNAGI_LMSTUDIO_URL || 'http://localhost:1234';
8
+ /** LM Studio の初回起動時に置かれる lms CLI */
9
+ const DEFAULT_LMS_PATH = path.join(os.homedir(), '.lmstudio', 'bin', 'lms');
10
+ // モデルの読み込みは 20GB 級で数十秒かかる
11
+ const LOAD_TIMEOUT_MS = 10 * 60 * 1000;
12
+ export function defaultLmStudioSettings() {
13
+ return { enabled: false, baseUrl: DEFAULT_BASE_URL, apiToken: '', lmsPath: '' };
14
+ }
15
+ export async function getLmStudioSettings() {
16
+ const { enabled, baseUrl, apiToken, lmsPath } = await readAppSetting(LMSTUDIO_SETTING_KEY, defaultLmStudioSettings());
17
+ return { enabled, baseUrl, apiToken, lmsPath };
18
+ }
19
+ export async function saveLmStudioSettings(settings) {
20
+ return writeAppSetting(LMSTUDIO_SETTING_KEY, settings);
21
+ }
22
+ /** リクエストボディを検証して LmStudioSettings に正規化する。不正ならエラーメッセージを返す */
23
+ export function parseLmStudioSettings(body) {
24
+ if (typeof body !== 'object' || body === null)
25
+ return { error: 'Invalid body' };
26
+ const b = body;
27
+ if (typeof b.enabled !== 'boolean')
28
+ return { error: 'enabled must be boolean' };
29
+ const baseUrl = normalizeBaseUrl(b.baseUrl);
30
+ if (!baseUrl)
31
+ return { error: 'baseUrl must be a valid http(s) URL' };
32
+ for (const key of ['apiToken', 'lmsPath']) {
33
+ if (typeof b[key] !== 'string')
34
+ return { error: `${key} must be string` };
35
+ }
36
+ return {
37
+ settings: {
38
+ enabled: b.enabled,
39
+ baseUrl,
40
+ apiToken: b.apiToken.trim(),
41
+ lmsPath: b.lmsPath.trim(),
42
+ },
43
+ };
44
+ }
45
+ /** LM Studio へのリクエストに付ける認証トークン(認証を有効にしていなければ値は検証されない) */
46
+ export function lmStudioAuthToken(settings) {
47
+ return settings.apiToken || 'lmstudio';
48
+ }
49
+ function isExecutable(file) {
50
+ try {
51
+ fs.accessSync(file, fs.constants.X_OK);
52
+ return true;
53
+ }
54
+ catch {
55
+ return false;
56
+ }
57
+ }
58
+ /** lms CLI を探す(設定値 → ~/.lmstudio/bin/lms → PATH)。見つからなければ null */
59
+ export function findLms(settings) {
60
+ if (settings.lmsPath)
61
+ return isExecutable(settings.lmsPath) ? settings.lmsPath : null;
62
+ if (isExecutable(DEFAULT_LMS_PATH))
63
+ return DEFAULT_LMS_PATH;
64
+ for (const dir of (process.env.PATH ?? '').split(path.delimiter)) {
65
+ const candidate = path.join(dir, 'lms');
66
+ if (dir && isExecutable(candidate))
67
+ return candidate;
68
+ }
69
+ return null;
70
+ }
71
+ function runLms(settings, args, timeout = 60000) {
72
+ const lms = findLms(settings);
73
+ if (!lms) {
74
+ return Promise.reject(new Error('lms CLI が見つかりません。LM Studio を一度起動するか、lms のパスを設定してください'));
75
+ }
76
+ return new Promise((resolve, reject) => {
77
+ execFile(lms, args, { timeout, maxBuffer: 10 * 1024 * 1024 }, (error, stdout, stderr) => {
78
+ if (error) {
79
+ reject(new Error(`lms ${args.join(' ')} failed: ${stderr.trim() || error.message}`));
80
+ return;
81
+ }
82
+ resolve({ stdout, stderr });
83
+ });
84
+ });
85
+ }
86
+ function authHeaders(settings) {
87
+ return settings.apiToken ? { Authorization: `Bearer ${settings.apiToken}` } : {};
88
+ }
89
+ async function fetchRestModels(settings, timeout = 3000) {
90
+ const res = await fetch(`${settings.baseUrl}/api/v1/models`, {
91
+ headers: authHeaders(settings),
92
+ signal: AbortSignal.timeout(timeout),
93
+ });
94
+ if (!res.ok)
95
+ throw new Error(`LM Studio responded ${res.status}`);
96
+ return (await res.json()).models ?? [];
97
+ }
98
+ export async function getLmStudioStatus(settings) {
99
+ const lmsPath = findLms(settings);
100
+ try {
101
+ const models = await fetchRestModels(settings);
102
+ return {
103
+ lmsPath,
104
+ serverRunning: true,
105
+ loaded: models.flatMap((m) => (m.loaded_instances ?? []).map((i) => ({
106
+ key: m.key,
107
+ instanceId: i.id,
108
+ contextLength: i.config?.context_length ?? 0,
109
+ }))),
110
+ };
111
+ }
112
+ catch (error) {
113
+ return {
114
+ lmsPath,
115
+ serverRunning: false,
116
+ loaded: [],
117
+ error: error instanceof Error ? error.message : String(error),
118
+ };
119
+ }
120
+ }
121
+ /** ダウンロード済みの LLM 一覧。サーバー停止中でも選べるよう lms ls にフォールバックする */
122
+ export async function listLmStudioModels(settings) {
123
+ let models;
124
+ try {
125
+ models = (await fetchRestModels(settings))
126
+ .filter((m) => m.type === 'llm')
127
+ .map((m) => ({
128
+ provider: 'lmstudio',
129
+ model: m.key,
130
+ displayName: m.display_name ?? m.key,
131
+ format: m.format ?? '',
132
+ sizeBytes: m.size_bytes ?? 0,
133
+ maxContextLength: m.max_context_length ?? null,
134
+ }));
135
+ }
136
+ catch {
137
+ const { stdout } = await runLms(settings, ['ls', '--json', '--llm']);
138
+ const list = JSON.parse(stdout);
139
+ models = list.map((m) => ({
140
+ provider: 'lmstudio',
141
+ model: m.modelKey,
142
+ displayName: m.displayName ?? m.modelKey,
143
+ // lms ls は MLX を safetensors と表記する
144
+ format: m.format === 'safetensors' ? 'mlx' : (m.format ?? ''),
145
+ sizeBytes: m.sizeBytes ?? 0,
146
+ maxContextLength: m.maxContextLength ?? null,
147
+ }));
148
+ }
149
+ return models.sort((a, b) => a.model.localeCompare(b.model));
150
+ }
151
+ function portOf(baseUrl) {
152
+ const url = new URL(baseUrl);
153
+ return url.port || (url.protocol === 'https:' ? '443' : '80');
154
+ }
155
+ export async function startLmStudioServer(settings) {
156
+ await runLms(settings, ['server', 'start', '--port', portOf(settings.baseUrl)]);
157
+ }
158
+ export async function stopLmStudioServer(settings) {
159
+ await runLms(settings, ['server', 'stop']);
160
+ }
161
+ /** 読み込みに必要なメモリの見積もり(lms load --estimate-only の出力を読む) */
162
+ export async function estimateLmStudioLoad(settings, model, contextTokens) {
163
+ const { stdout } = await runLms(settings, [
164
+ 'load',
165
+ model,
166
+ '--context-length',
167
+ String(contextTokens),
168
+ '--estimate-only',
169
+ '--yes',
170
+ ]);
171
+ return {
172
+ totalMemory: stdout.match(/Estimated Total Memory:\s*(.+)/)?.[1]?.trim() ?? null,
173
+ verdict: stdout.match(/Estimate:\s*(.+)/)?.[1]?.trim() ?? null,
174
+ };
175
+ }
176
+ export async function unloadLmStudioModel(settings, instanceId) {
177
+ const res = await fetch(`${settings.baseUrl}/api/v1/models/unload`, {
178
+ method: 'POST',
179
+ headers: { 'Content-Type': 'application/json', ...authHeaders(settings) },
180
+ body: JSON.stringify({ instance_id: instanceId }),
181
+ signal: AbortSignal.timeout(60000),
182
+ });
183
+ if (!res.ok)
184
+ throw new Error(`LM Studio の unload に失敗しました (${res.status})`);
185
+ }
186
+ export async function loadLmStudioModel(settings, model, contextTokens) {
187
+ const res = await fetch(`${settings.baseUrl}/api/v1/models/load`, {
188
+ method: 'POST',
189
+ headers: { 'Content-Type': 'application/json', ...authHeaders(settings) },
190
+ body: JSON.stringify({ model, context_length: contextTokens }),
191
+ signal: AbortSignal.timeout(LOAD_TIMEOUT_MS),
192
+ });
193
+ if (!res.ok) {
194
+ const body = (await res.json().catch(() => ({})));
195
+ const message = typeof body.error === 'string' ? body.error : body.error?.message;
196
+ throw new Error(`LM Studio でモデルを読み込めません: ${message ?? res.status}`);
197
+ }
198
+ }
@@ -0,0 +1,28 @@
1
+ /** ローカルLLMタブでは Anthropic の認証情報を環境変数ごと取り除く(ANTHROPIC_AUTH_TOKEN と競合するため) */
2
+ export declare const LOCAL_LLM_UNSET_ENV_KEYS: string[];
3
+ /** AppSetting から JSON 設定を読む。未保存・破損時は既定値 */
4
+ export declare function readAppSetting<T extends object>(key: string, defaults: T): Promise<T>;
5
+ export declare function writeAppSetting<T>(key: string, settings: T): Promise<T>;
6
+ /** http(s) の URL を末尾スラッシュなしに正規化する。不正なら null */
7
+ export declare function normalizeBaseUrl(value: unknown): string | null;
8
+ export declare function parseContextTokens(value: unknown): number | null;
9
+ /** extraEnv を検証する。不正ならエラーメッセージ */
10
+ export declare function parseExtraEnv(value: unknown): {
11
+ env: Record<string, string>;
12
+ } | {
13
+ error: string;
14
+ };
15
+ /**
16
+ * ローカルLLMタブの Claude Code が名乗るモデル名。tsunagi の中継口が使用中のモデルに書き換えるため、
17
+ * タブを作った後にモデルを切り替えても既存タブがそのまま追従する。
18
+ */
19
+ export declare const LOCAL_MODEL_ALIAS = "tsunagi-local";
20
+ /**
21
+ * ローカルLLMタブの Claude Code を tsunagi の中継口に向けるための環境変数。
22
+ * DB の環境変数より後に適用し、同名キーを上書きする。
23
+ */
24
+ export declare function buildLocalLlmEnv(params: {
25
+ proxyUrl: string;
26
+ contextTokens: number;
27
+ extraEnv: Record<string, string>;
28
+ }): Record<string, string>;